diff --git a/SOURCES/0001-SYSDB-Skip-malformed-netgroup-attribute.patch b/SOURCES/0001-SYSDB-Skip-malformed-netgroup-attribute.patch new file mode 100644 index 0000000..a240448 --- /dev/null +++ b/SOURCES/0001-SYSDB-Skip-malformed-netgroup-attribute.patch @@ -0,0 +1,36 @@ +From d0eeff900d721a0e147b3513d075dbb64b002dc1 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Tue, 12 Nov 2013 14:39:27 +0100 +Subject: [PATCH 1/6] SYSDB: Skip malformed netgroup attribute. + +It was not easy find out why netgroup could not be covert into result entries. +Problem was that nisNetgroupTriple contained unexpected string "(,user01)" +This patch will ignore only malformed attribute and processing of netgroup +will not fail. + +Resolves: +https://fedorahosted.org/sssd/ticket/2137 +--- + src/db/sysdb_search.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c +index 8dfaf1f2ada22db5e70ebe18bee1ee299e4767dd..d15fc73ce2272bff53650ae9dd0dbdad99a849e6 100644 +--- a/src/db/sysdb_search.c ++++ b/src/db/sysdb_search.c +@@ -728,7 +728,11 @@ errno_t sysdb_netgr_to_entries(TALLOC_CTX *mem_ctx, + &tmp_entry[c]->value.triple.username, + &tmp_entry[c]->value.triple.domainname); + if (ret != EOK) { +- goto done; ++ DEBUG(SSSDBG_IMPORTANT_INFO, ++ ("Cannot split netgroup triple [%s], " ++ "this attribute will be skipped \n", ++ triple_str)); ++ continue; + } + + c++; +-- +1.8.4.2 + diff --git a/SOURCES/0002-monitor-Specific-error-message-for-missing-sssd.conf.patch b/SOURCES/0002-monitor-Specific-error-message-for-missing-sssd.conf.patch new file mode 100644 index 0000000..ea4a22b --- /dev/null +++ b/SOURCES/0002-monitor-Specific-error-message-for-missing-sssd.conf.patch @@ -0,0 +1,90 @@ +From 08134dde5a6c8b23cf40ec8f0020cd553af2667e Mon Sep 17 00:00:00 2001 +From: Pavel Reichl +Date: Tue, 19 Nov 2013 11:24:31 +0000 +Subject: [PATCH 2/6] monitor: Specific error message for missing sssd.conf + +Specific error message is logged for missing sssd.conf file. New sssd specific +error value is introduced for this case. + +Resolves: +https://fedorahosted.org/sssd/ticket/2156 +--- + src/confdb/confdb_setup.c | 9 +++++++-- + src/monitor/monitor.c | 8 +++++++- + src/util/util_errors.c | 1 + + src/util/util_errors.h | 1 + + 4 files changed, 16 insertions(+), 3 deletions(-) + +diff --git a/src/confdb/confdb_setup.c b/src/confdb/confdb_setup.c +index b13553eaa560bb83ecf7a53b32ab116f38f7f480..2a34e4f7a3e5f9aa37760036520f5274e9289b70 100644 +--- a/src/confdb/confdb_setup.c ++++ b/src/confdb/confdb_setup.c +@@ -155,8 +155,13 @@ int confdb_init_db(const char *config_file, struct confdb_ctx *cdb) + /* Open config file */ + ret = sss_ini_config_file_open(init_data, config_file); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to open configuration file.\n")); +- ret = EIO; ++ DEBUG(SSSDBG_TRACE_FUNC, ++ ("sss_ini_config_file_open failed: %s [%d]\n", strerror(ret), ++ ret)); ++ if (ret == ENOENT) { ++ /* sss specific error denoting missing configuration file */ ++ ret = ERR_MISSING_CONF; ++ } + goto done; + } + +diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c +index 3d8ba26285b6a8fc60ccb695f8b10ae1714ac918..09f530d2643b45fc31fb4dbe3cb69f2abc5510af 100644 +--- a/src/monitor/monitor.c ++++ b/src/monitor/monitor.c +@@ -1614,7 +1614,7 @@ static errno_t load_configuration(TALLOC_CTX *mem_ctx, + ret = confdb_init_db(config_file, ctx->cdb); + if (ret != EOK) { + DEBUG(0, ("ConfDB initialization has failed [%s]\n", +- strerror(ret))); ++ sss_strerror(ret))); + goto done; + } + +@@ -2789,6 +2789,12 @@ int main(int argc, const char *argv[]) + ret = load_configuration(tmp_ctx, config_file, &monitor); + if (ret != EOK) { + switch (ret) { ++ case ERR_MISSING_CONF: ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ ("Configuration file: %s does not exist.\n", config_file)); ++ sss_log(SSS_LOG_ALERT, ++ "Configuration file: %s does not exist.\n", config_file); ++ break; + case EPERM: + case EACCES: + DEBUG(SSSDBG_CRIT_FAILURE, +diff --git a/src/util/util_errors.c b/src/util/util_errors.c +index b3d10f97b0567ca21ca08a3f2d326ea401c28aff..114c8b04fd354b166d14e526a3bab6a6c0c05951 100644 +--- a/src/util/util_errors.c ++++ b/src/util/util_errors.c +@@ -50,6 +50,7 @@ struct err_string error_to_str[] = { + { "Dynamic DNS update not possible while offline" }, /* ERR_DYNDNS_OFFLINE */ + { "Entry not found" }, /* ERR_NOT_FOUND */ + { "Domain not found" }, /* ERR_DOMAIN_NOT_FOUND */ ++ { "Missing configuration file" }, /* ERR_MISSING_CONF */ + }; + + +diff --git a/src/util/util_errors.h b/src/util/util_errors.h +index 685607c5bb1b4e7c37152c876518a2b1c69c18d6..bca45f392b0357c3f1c848768358cb1d47514715 100644 +--- a/src/util/util_errors.h ++++ b/src/util/util_errors.h +@@ -72,6 +72,7 @@ enum sssd_errors { + ERR_DYNDNS_OFFLINE, + ERR_NOT_FOUND, + ERR_DOMAIN_NOT_FOUND, ++ ERR_MISSING_CONF, + ERR_LAST /* ALWAYS LAST */ + }; + +-- +1.8.4.2 + diff --git a/SOURCES/0003-AD-Fix-a-typo-in-the-man-page.patch b/SOURCES/0003-AD-Fix-a-typo-in-the-man-page.patch new file mode 100644 index 0000000..9baeeb9 --- /dev/null +++ b/SOURCES/0003-AD-Fix-a-typo-in-the-man-page.patch @@ -0,0 +1,26 @@ +From ebb9c8acfb2423a2474cbbc52794d41975478dcf Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 18 Nov 2013 11:05:04 +0100 +Subject: [PATCH 3/6] AD: Fix a typo in the man page + +https://fedorahosted.org/sssd/ticket/2154 +--- + src/man/sssd-ad.5.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml +index 3dcf2c7390e89cacec202f49c559eccf03800450..e31f87a96a14907c64166e53da443ad735c6e85e 100644 +--- a/src/man/sssd-ad.5.xml ++++ b/src/man/sssd-ad.5.xml +@@ -175,7 +175,7 @@ ldap_id_mapping = False + This option specifies LDAP access control + filter that the user must match in order + to be allowed access. Please note that the +- access_filter option must be ++ access_provider option must be + explicitly set to ad in order + for this option to have an effect. + +-- +1.8.4.2 + diff --git a/SOURCES/0004-LDAP-Initialize-user-count-for-AD-matching-rule.patch b/SOURCES/0004-LDAP-Initialize-user-count-for-AD-matching-rule.patch new file mode 100644 index 0000000..10ffd1a --- /dev/null +++ b/SOURCES/0004-LDAP-Initialize-user-count-for-AD-matching-rule.patch @@ -0,0 +1,29 @@ +From 44d60762a2ffe45b2dadf05634eefb2af2e3ce14 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 18 Nov 2013 16:38:34 +0100 +Subject: [PATCH 4/6] LDAP: Initialize user count for AD matching rule + +https://fedorahosted.org/sssd/ticket/2157 + +If AD matching rule was selected, but the group was empty, the SSSD +accessed random data. Initializing count to zero prevents that. +--- + src/providers/ldap/sdap_async_groups.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c +index 7a8f3e2a5c83c5b320497a76c363a90620315dcf..9f7e3e55d0234e9aa7b9e59456044587bcad88ef 100644 +--- a/src/providers/ldap/sdap_async_groups.c ++++ b/src/providers/ldap/sdap_async_groups.c +@@ -1828,7 +1828,7 @@ static void sdap_ad_match_rule_members_process(struct tevent_req *subreq) + struct sysdb_attrs *group = state->groups[0]; + struct ldb_message_element *member_el; + struct ldb_message_element *orig_dn_el; +- size_t count; ++ size_t count = 0; + size_t i; + hash_table_t *ghosts; + +-- +1.8.4.2 + diff --git a/SOURCES/0005-SSSD-Improved-domain-detection.patch b/SOURCES/0005-SSSD-Improved-domain-detection.patch new file mode 100644 index 0000000..7ae4898 --- /dev/null +++ b/SOURCES/0005-SSSD-Improved-domain-detection.patch @@ -0,0 +1,165 @@ +From 3cf1217a277d1103a8956e33fc0a8464227e2dd2 Mon Sep 17 00:00:00 2001 +From: Pavel Reichl +Date: Thu, 14 Nov 2013 21:34:51 +0000 +Subject: [PATCH 5/6] SSSD: Improved domain detection + +A bit more elegant way of detection of what domain the group member belongs to + +Resolves: +https://fedorahosted.org/sssd/ticket/2132 +--- + src/providers/ldap/ldap_common.c | 39 ++++++++++++++++++++++++++++----------- + src/util/sss_ldap.c | 28 +++++++++++++++++++++++----- + src/util/sss_ldap.h | 6 ++++++ + 3 files changed, 57 insertions(+), 16 deletions(-) + +diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c +index facf102edc792c75a563a276f3ea9f3acc3052b4..35ea81360b4ec61eca6b952cd86fc93a6eda17dc 100644 +--- a/src/providers/ldap/ldap_common.c ++++ b/src/providers/ldap/ldap_common.c +@@ -68,23 +68,40 @@ sdap_domain_get_by_dn(struct sdap_options *opts, + const char *dn) + { + struct sdap_domain *sditer = NULL; +- char *dc = NULL; ++ struct sdap_domain *sdmatch = NULL; ++ TALLOC_CTX *tmp_ctx = NULL; ++ int match_len; ++ int best_match_len = 0; + +- dc = strstr(dn, "dc="); +- if (dc == NULL) { +- dc = strstr(dn, "DC="); +- if (dc == NULL) { +- return NULL; +- } ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return NULL; + } + + DLIST_FOR_EACH(sditer, opts->sdom) { +- if (strcasecmp(sditer->basedn, dc) == 0) { +- return sditer; ++ if (sss_ldap_dn_in_search_bases_len(tmp_ctx, dn, sditer->search_bases, ++ NULL, &match_len) ++ || sss_ldap_dn_in_search_bases_len(tmp_ctx, dn, ++ sditer->user_search_bases, NULL, &match_len) ++ || sss_ldap_dn_in_search_bases_len(tmp_ctx, dn, ++ sditer->group_search_bases, NULL, &match_len) ++ || sss_ldap_dn_in_search_bases_len(tmp_ctx, dn, ++ sditer->netgroup_search_bases, NULL, &match_len) ++ || sss_ldap_dn_in_search_bases_len(tmp_ctx, dn, ++ sditer->sudo_search_bases, NULL, &match_len) ++ || sss_ldap_dn_in_search_bases_len(tmp_ctx, dn, ++ sditer->service_search_bases, NULL, &match_len) ++ || sss_ldap_dn_in_search_bases_len(tmp_ctx, dn, ++ sditer->autofs_search_bases, NULL, &match_len)) { ++ if (best_match_len < match_len) { ++ /*this is a longer match*/ ++ best_match_len = match_len; ++ sdmatch = sditer; ++ } + } + } +- +- return NULL; ++ talloc_free(tmp_ctx); ++ return sdmatch; + } + + errno_t +diff --git a/src/util/sss_ldap.c b/src/util/sss_ldap.c +index 6d7b0907ca2fa48d9cff5257ab6bbba0ae7dd5c6..e1a05e8f60afb692ac95c99a443febac72a31187 100644 +--- a/src/util/sss_ldap.c ++++ b/src/util/sss_ldap.c +@@ -470,10 +470,13 @@ int sss_ldap_init_recv(struct tevent_req *req, LDAP **ldap, int *sd) + * _filter will contain combined filters from all possible search bases + * or NULL if it should be empty + */ +-bool sss_ldap_dn_in_search_bases(TALLOC_CTX *mem_ctx, +- const char *dn, +- struct sdap_search_base **search_bases, +- char **_filter) ++ ++ ++bool sss_ldap_dn_in_search_bases_len(TALLOC_CTX *mem_ctx, ++ const char *dn, ++ struct sdap_search_base **search_bases, ++ char **_filter, ++ int *_match_len) + { + struct sdap_search_base *base; + int basedn_len, dn_len; +@@ -484,6 +487,7 @@ bool sss_ldap_dn_in_search_bases(TALLOC_CTX *mem_ctx, + bool backslash_found = false; + char *filter = NULL; + bool ret = false; ++ int match_len; + + if (dn == NULL) { + DEBUG(SSSDBG_FUNC_DATA, ("dn is NULL\n")); +@@ -511,6 +515,7 @@ bool sss_ldap_dn_in_search_bases(TALLOC_CTX *mem_ctx, + if (!base_confirmed) { + continue; + } ++ match_len = basedn_len; + + switch (base->scope) { + case LDAP_SCOPE_BASE: +@@ -558,6 +563,9 @@ bool sss_ldap_dn_in_search_bases(TALLOC_CTX *mem_ctx, + * Append filter otherwise. + */ + ret = true; ++ if (_match_len) { ++ *_match_len = match_len; ++ } + + if (base->filter == NULL || _filter == NULL) { + goto done; +@@ -575,7 +583,8 @@ bool sss_ldap_dn_in_search_bases(TALLOC_CTX *mem_ctx, + if (filter != NULL) { + *_filter = talloc_asprintf(mem_ctx, "(|%s)", filter); + if (*_filter == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_asprintf_append() failed\n")); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ ("talloc_asprintf_append() failed\n")); + ret = false; + goto done; + } +@@ -589,6 +598,15 @@ done: + return ret; + } + ++bool sss_ldap_dn_in_search_bases(TALLOC_CTX *mem_ctx, ++ const char *dn, ++ struct sdap_search_base **search_bases, ++ char **_filter) ++{ ++ return sss_ldap_dn_in_search_bases_len(mem_ctx, dn, search_bases, _filter, ++ NULL); ++} ++ + char *sss_ldap_encode_ndr_uint32(TALLOC_CTX *mem_ctx, uint32_t flags) + { + char hex[9]; /* 4 bytes in hex + terminating zero */ +diff --git a/src/util/sss_ldap.h b/src/util/sss_ldap.h +index e5c30eb2115d422ef5a52cc5cd75c85be8fbe2d7..f298b2fbb30cf1532f8e94504ffb83ef73880b81 100644 +--- a/src/util/sss_ldap.h ++++ b/src/util/sss_ldap.h +@@ -74,6 +74,12 @@ bool sss_ldap_dn_in_search_bases(TALLOC_CTX *mem_ctx, + struct sdap_search_base **search_bases, + char **_filter); + ++bool sss_ldap_dn_in_search_bases_len(TALLOC_CTX *mem_ctx, ++ const char *dn, ++ struct sdap_search_base **search_bases, ++ char **_filter, ++ int *_match_len); ++ + char *sss_ldap_encode_ndr_uint32(TALLOC_CTX *mem_ctx, uint32_t flags); + + #endif /* __SSS_LDAP_H__ */ +-- +1.8.4.2 + diff --git a/SOURCES/0006-SSSD-Unit-test-sss_ldap_dn_in_search_bases.patch b/SOURCES/0006-SSSD-Unit-test-sss_ldap_dn_in_search_bases.patch new file mode 100644 index 0000000..e0555b3 --- /dev/null +++ b/SOURCES/0006-SSSD-Unit-test-sss_ldap_dn_in_search_bases.patch @@ -0,0 +1,260 @@ +From 94c85df2d7ded82f2939d8fe29821e4c78ff000d Mon Sep 17 00:00:00 2001 +From: Pavel Reichl +Date: Thu, 14 Nov 2013 21:52:26 +0000 +Subject: [PATCH 6/6] SSSD: Unit test - sss_ldap_dn_in_search_bases + +Unit test testing detection of the right domain when processing group with members from several domains + +Resolves: +https://fedorahosted.org/sssd/ticket/2132 +--- + Makefile.am | 27 ++++- + src/tests/cmocka/test_search_bases.c | 191 +++++++++++++++++++++++++++++++++++ + 2 files changed, 217 insertions(+), 1 deletion(-) + create mode 100644 src/tests/cmocka/test_search_bases.c + +diff --git a/Makefile.am b/Makefile.am +index 2ba1ec0fd94e3292f05de0139d607b3626b5c6f7..583ccdb499306268640bfb894f673c42945e19ff 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -151,7 +151,8 @@ if HAVE_CMOCKA + fqnames-tests \ + test_sss_idmap \ + test_utils \ +- ad_access_filter_tests ++ ad_access_filter_tests \ ++ test_search_bases + endif + + check_PROGRAMS = \ +@@ -1367,6 +1368,30 @@ test_utils_LDADD = \ + $(SSSD_INTERNAL_LTLIBS) \ + libsss_test_common.la + ++test_search_bases_SOURCES = \ ++ $(sssd_be_SOURCES) \ ++ src/util/sss_ldap.c \ ++ src/util/sss_krb5.c \ ++ src/util/find_uid.c \ ++ src/util/user_info_msg.c \ ++ src/tests/cmocka/test_search_bases.c ++test_search_bases_CFLAGS = \ ++ $(AM_CFLAGS) \ ++ -DUNIT_TESTING ++test_search_bases_LDADD = \ ++ $(PAM_LIBS) \ ++ $(CMOCKA_LIBS) \ ++ $(POPT_LIBS) \ ++ $(SSSD_LIBS) \ ++ $(CARES_LIBS) \ ++ $(KRB5_LIBS) \ ++ $(SSSD_INTERNAL_LTLIBS) \ ++ $(SYSTEMD_LOGIN_LIBS) \ ++ libsss_ldap_common.la \ ++ libsss_idmap.la \ ++ libsss_krb5_common.la \ ++ libsss_test_common.la ++ + ad_access_filter_tests_SOURCES = \ + $(sssd_be_SOURCES) \ + src/util/sss_ldap.c \ +diff --git a/src/tests/cmocka/test_search_bases.c b/src/tests/cmocka/test_search_bases.c +new file mode 100644 +index 0000000000000000000000000000000000000000..e03ef3662685d92335bce4a7023e1ac7e64432c8 +--- /dev/null ++++ b/src/tests/cmocka/test_search_bases.c +@@ -0,0 +1,191 @@ ++/* ++ Authors: ++ Pavel Reichl ++ ++ Copyright (C) 2013 Red Hat ++ ++ SSSD tests - Search bases ++ ++ 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 ++#include ++ ++#include "util/find_uid.h" ++#include "util/sss_ldap.h" ++#include "tests/common.h" ++#include "providers/ldap/ldap_common.h" ++#include "providers/ldap/sdap.h" ++#include "dhash.h" ++#include "tests/common_check.h" ++ ++enum sss_test_get_by_dn { ++ DN_NOT_IN_DOMS, /* dn is not in any domain */ ++ DN_IN_DOM1, /* dn is in the domain based on dns */ ++ DN_IN_DOM2, /* dn is in the domain based on dns2 */ ++}; ++ ++static struct sdap_search_base** generate_bases(TALLOC_CTX *mem_ctx, ++ const char** dns, size_t n) ++{ ++ struct sdap_search_base **search_bases; ++ errno_t err; ++ int i; ++ ++ search_bases = talloc_array(mem_ctx, struct sdap_search_base *, n + 1); ++ assert_non_null(search_bases); ++ ++ for (i=0; i < n; ++i) { ++ err = sdap_create_search_base(mem_ctx, dns[i], LDAP_SCOPE_SUBTREE, ++ NULL, &search_bases[i]); ++ if (err != EOK) { ++ fprintf(stderr, "Failed to create search base\n"); ++ } ++ assert_int_equal(err, EOK); ++ } ++ search_bases[n] = NULL; ++ return search_bases; ++} ++ ++static bool do_test_search_bases(const char* dn, const char** dns, size_t n) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct sdap_search_base **search_bases; ++ bool ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ assert_non_null(tmp_ctx); ++ ++ search_bases = generate_bases(tmp_ctx, dns, n); ++ check_leaks_push(tmp_ctx); ++ ret = sss_ldap_dn_in_search_bases(tmp_ctx, dn, search_bases, NULL); ++ assert_true(check_leaks_pop(tmp_ctx) == true); ++ ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++void test_search_bases_fail(void **state) ++{ ++ const char *dn = "cn=user, dc=sub, dc=ad, dc=pb"; ++ const char *dns[] = {"dc=example, dc=com", "dc=subdom, dc=ad, dc=pb"}; ++ bool ret; ++ ++ ret = do_test_search_bases(dn, dns, 2); ++ assert_false(ret); ++} ++ ++void test_search_bases_success(void **state) ++{ ++ const char *dn = "cn=user, dc=sub, dc=ad, dc=pb"; ++ const char *dns[] = {"", "dc=ad, dc=pb", "dc=sub, dc=ad, dc=pb"}; ++ bool ret; ++ ++ ret = do_test_search_bases(dn, dns, 3); ++ assert_true(ret); ++} ++ ++static void do_test_get_by_dn(const char *dn, const char **dns, size_t n, ++ const char **dns2, size_t n2, int expected_result) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct sdap_options *opts; ++ struct sdap_domain *sdom; ++ struct sdap_domain *sdom2; ++ struct sdap_domain *res_sdom; ++ struct sdap_search_base **search_bases; ++ struct sdap_search_base **search_bases2; ++ tmp_ctx = talloc_new(NULL); ++ assert_non_null(tmp_ctx); ++ ++ search_bases = generate_bases(tmp_ctx, dns, n); ++ search_bases2 = generate_bases(tmp_ctx, dns2, n2); ++ sdom = talloc_zero(tmp_ctx, struct sdap_domain); ++ assert_non_null(sdom); ++ sdom2 = talloc_zero(tmp_ctx, struct sdap_domain); ++ assert_non_null(sdom2); ++ ++ sdom->search_bases = search_bases; ++ sdom->next = sdom2; ++ sdom->prev = NULL; ++ sdom2->search_bases = search_bases2; ++ sdom2->next = NULL; ++ sdom2->prev = sdom; ++ ++ opts = talloc(tmp_ctx, struct sdap_options); ++ assert_non_null(opts); ++ opts->sdom = sdom; ++ res_sdom = sdap_domain_get_by_dn(opts, dn); ++ ++ switch (expected_result) { ++ case DN_NOT_IN_DOMS: ++ assert_null(res_sdom); ++ break; ++ case DN_IN_DOM1: ++ assert_true(res_sdom == sdom); ++ break; ++ case DN_IN_DOM2: ++ assert_true(res_sdom == sdom2); ++ break; ++ } ++ ++ talloc_free(tmp_ctx); ++} ++ ++void test_get_by_dn(void **state) ++{ ++ const char *dn = "cn=user, dc=sub, dc=ad, dc=pb"; ++ const char *dns[] = {"dc=ad, dc=pb"}; ++ const char *dns2[] = {"dc=sub, dc=ad, dc=pb"}; ++ ++ do_test_get_by_dn(dn, dns, 1, dns2, 1, DN_IN_DOM2); ++} ++ ++void test_get_by_dn2(void **state) ++{ ++ const char *dn = "cn=user, dc=ad, dc=com"; ++ const char *dns[] = {"dc=ad, dc=com"}; ++ const char *dns2[] = {"dc=sub, dc=ad, dc=pb"}; ++ ++ do_test_get_by_dn(dn, dns, 1, dns2, 1, DN_IN_DOM1); ++} ++ ++void test_get_by_dn_fail(void **state) ++{ ++ const char *dn = "cn=user, dc=sub, dc=example, dc=com"; ++ const char *dns[] = {"dc=ad, dc=pb"}; ++ const char *dns2[] = {"dc=sub, dc=ad, dc=pb"}; ++ ++ do_test_get_by_dn(dn, dns, 1, dns2, 1, DN_NOT_IN_DOMS); ++} ++ ++int main(void) ++{ ++ const UnitTest tests[] = { ++ unit_test(test_search_bases_fail), ++ unit_test(test_search_bases_success), ++ unit_test(test_get_by_dn_fail), ++ unit_test(test_get_by_dn), ++ unit_test(test_get_by_dn2) ++ }; ++ ++ return run_tests(tests); ++} +-- +1.8.4.2 + diff --git a/SOURCES/0007-do-not-use-default_domain_suffix-with-autofs.patch b/SOURCES/0007-do-not-use-default_domain_suffix-with-autofs.patch new file mode 100644 index 0000000..d10d47d --- /dev/null +++ b/SOURCES/0007-do-not-use-default_domain_suffix-with-autofs.patch @@ -0,0 +1,25 @@ +From b7c339c616e88c0e8db5c5a653dacdedf19a147a Mon Sep 17 00:00:00 2001 +From: Aron Parsons +Date: Wed, 6 Nov 2013 15:18:54 +0000 +Subject: [PATCH 7/7] do not use default_domain_suffix with autofs + +--- + src/responder/autofs/autofssrv_cmd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/responder/autofs/autofssrv_cmd.c b/src/responder/autofs/autofssrv_cmd.c +index e9168ea8f85cbaf9e934b44838d17360024a2bc1..4c5bda01d4abd967e8cd8260904f34546b898d99 100644 +--- a/src/responder/autofs/autofssrv_cmd.c ++++ b/src/responder/autofs/autofssrv_cmd.c +@@ -435,7 +435,7 @@ setautomntent_send(TALLOC_CTX *mem_ctx, + state->dctx = dctx; + + ret = sss_parse_name_for_domains(state, client->rctx->domains, +- client->rctx->default_domain, rawname, ++ NULL, rawname, + &domname, &state->mapname); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, +-- +1.8.4.2 + diff --git a/SOURCES/0008-SYSDB-Sanitize-filter-before-sysdb_search_groups.patch b/SOURCES/0008-SYSDB-Sanitize-filter-before-sysdb_search_groups.patch new file mode 100644 index 0000000..c51c590 --- /dev/null +++ b/SOURCES/0008-SYSDB-Sanitize-filter-before-sysdb_search_groups.patch @@ -0,0 +1,63 @@ +From bd24c6f485ac1421053167eabd6e5e963829403b Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Mon, 25 Nov 2013 13:43:30 +0100 +Subject: [PATCH 8/9] SYSDB: Sanitize filter before sysdb_search_groups + +sysdb_delete_user fails with EIO if user does not exist and contains +backslashes. +ldb could not parse filter (&(objectclass=group)(ghost=usr\\\\001)), +because ghost value was not sanitized + +Resolves: +https://fedorahosted.org/sssd/ticket/2163 +--- + src/db/sysdb_ops.c | 9 ++++++++- + src/tests/sysdb-tests.c | 5 +++++ + 2 files changed, 13 insertions(+), 1 deletion(-) + +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index 094c27b7f478e0a53a3b6666c727e86eb36a249e..eb88cd256d0c2e45e1528e8a867e42354215cc7f 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -2539,6 +2539,7 @@ int sysdb_delete_user(struct sysdb_ctx *sysdb, + struct ldb_message *msg; + int ret; + int i; ++ char *sanitized_name; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) { +@@ -2578,7 +2579,13 @@ int sysdb_delete_user(struct sysdb_ctx *sysdb, + } + } else if (ret == ENOENT && name != NULL) { + /* Perhaps a ghost user? */ +- filter = talloc_asprintf(tmp_ctx, "(%s=%s)", SYSDB_GHOST, name); ++ ret = sss_filter_sanitize(tmp_ctx, name, &sanitized_name); ++ if (ret != EOK) { ++ goto fail; ++ } ++ ++ filter = talloc_asprintf(tmp_ctx, "(%s=%s)", ++ SYSDB_GHOST, sanitized_name); + if (filter == NULL) { + ret = ENOMEM; + goto fail; +diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c +index 1c28526e06df012b8749e1540e70a27948c17ab2..bf964fd76d33bbceac6c1846db7a5011db1375f5 100644 +--- a/src/tests/sysdb-tests.c ++++ b/src/tests/sysdb-tests.c +@@ -3998,6 +3998,11 @@ START_TEST(test_odd_characters) + fail_unless(ret == EOK, "sysdb_delete_user error [%d][%s]", + ret, strerror(ret)); + ++ /* Delete non existing User */ ++ ret = sysdb_delete_user(test_ctx->sysdb, test_ctx->domain, ++ odd_username, 10000); ++ fail_unless(ret == ENOENT, "sysdb_delete_user error [%d][%s]", ++ ret, strerror(ret)); + + /* Delete Group */ + ret = sysdb_delete_group(test_ctx->sysdb, test_ctx->domain, +-- +1.8.4.2 + diff --git a/SOURCES/0009-SYSDB-Sanitize-filter-before-removing-ghost-attrs.patch b/SOURCES/0009-SYSDB-Sanitize-filter-before-removing-ghost-attrs.patch new file mode 100644 index 0000000..ac80bac --- /dev/null +++ b/SOURCES/0009-SYSDB-Sanitize-filter-before-removing-ghost-attrs.patch @@ -0,0 +1,85 @@ +From 0a509d518dd5d17e32e3a4c34b319a38210ba17b Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Mon, 25 Nov 2013 16:01:59 +0100 +Subject: [PATCH 9/9] SYSDB: Sanitize filter before removing ghost attrs + +sysdb_add_user fails with EIO if enumeration is disabled and user contains +backslashes. +We try to remove ghost attributes from groups with disabled enumeration, +but unsanitized filter is used to find ghost attributes +"(|(ghost=usr\\\\002)" and ldb cannot parse this filter. + +Resolves: +https://fedorahosted.org/sssd/ticket/2163 +--- + src/db/sysdb_ops.c | 9 ++++++++- + src/tests/sysdb-tests.c | 19 +++++++++++++++++++ + 2 files changed, 27 insertions(+), 1 deletion(-) + +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index eb88cd256d0c2e45e1528e8a867e42354215cc7f..890bf1eb3cc5fc0b6eb6f7a145aee6d87945cd8d 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -1091,6 +1091,7 @@ sysdb_remove_ghostattr_from_groups(struct sysdb_ctx *sysdb, + struct ldb_dn *tmpdn; + const char *group_attrs[] = {SYSDB_NAME, SYSDB_GHOST, SYSDB_ORIG_MEMBER, NULL}; + const char *userdn; ++ char *sanitized_name; + char *filter; + errno_t ret = EOK; + size_t group_count = 0; +@@ -1101,7 +1102,13 @@ sysdb_remove_ghostattr_from_groups(struct sysdb_ctx *sysdb, + return ENOENT; + } + +- filter = talloc_asprintf(tmp_ctx, "(|(%s=%s)", SYSDB_GHOST, name); ++ ret = sss_filter_sanitize(tmp_ctx, name, &sanitized_name); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ filter = talloc_asprintf(tmp_ctx, "(|(%s=%s)", ++ SYSDB_GHOST, sanitized_name); + if (!filter) { + ret = ENOMEM; + goto done; +diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c +index bf964fd76d33bbceac6c1846db7a5011db1375f5..ddbf6f28fd5024945fedcb3c6e2122948c4f1459 100644 +--- a/src/tests/sysdb-tests.c ++++ b/src/tests/sysdb-tests.c +@@ -3900,6 +3900,8 @@ START_TEST(test_odd_characters) + struct ldb_message *msg; + const struct ldb_val *val; + const char odd_username[] = "*(odd)\\user,name"; ++ const char odd_username_orig_dn[] = ++ "\\2a\\28odd\\29\\5cuser,name,cn=users,dc=example,dc=com"; + const char odd_groupname[] = "*(odd\\*)\\group,name"; + const char odd_netgroupname[] = "*(odd\\*)\\netgroup,name"; + const char *received_user; +@@ -4010,6 +4012,23 @@ START_TEST(test_odd_characters) + fail_unless(ret == EOK, "sysdb_delete_group error [%d][%s]", + ret, strerror(ret)); + ++ /* Add */ ++ ret = sysdb_add_user(test_ctx->sysdb, ++ test_ctx->domain, ++ odd_username, ++ 10000, 0, ++ "","","", ++ odd_username_orig_dn, ++ NULL, 5400, 0); ++ fail_unless(ret == EOK, "sysdb_add_user error [%d][%s]", ++ ret, strerror(ret)); ++ ++ /* Delete User */ ++ ret = sysdb_delete_user(test_ctx->sysdb, test_ctx->domain, ++ odd_username, 10000); ++ fail_unless(ret == EOK, "sysdb_delete_user error [%d][%s]", ++ ret, strerror(ret)); ++ + /* ===== Netgroups ===== */ + /* Add */ + ret = sysdb_add_netgroup(test_ctx->sysdb, test_ctx->domain, +-- +1.8.4.2 + diff --git a/SOURCES/0010-LDAP-Split-out-a-request-to-search-for-a-user-w-o-sa.patch b/SOURCES/0010-LDAP-Split-out-a-request-to-search-for-a-user-w-o-sa.patch new file mode 100644 index 0000000..3d4f47b --- /dev/null +++ b/SOURCES/0010-LDAP-Split-out-a-request-to-search-for-a-user-w-o-sa.patch @@ -0,0 +1,301 @@ +From 26f41ed62ab74d628764702a1522cedd22b55599 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 1 Oct 2013 17:44:07 +0200 +Subject: [PATCH 10/11] LDAP: Split out a request to search for a user w/o + saving + +Related: +https://fedorahosted.org/sssd/ticket/2077 + +Certain situations require that a user entry is downloaded for further +inpection, but not saved to the sysdb right away. This patch splits the +previously monolithic request into one that just downloads the data and +one that uses the new one to download and save the user. +--- + src/providers/ldap/sdap_async.h | 16 ++++ + src/providers/ldap/sdap_async_users.c | 162 +++++++++++++++++++++++++++------- + 2 files changed, 146 insertions(+), 32 deletions(-) + +diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h +index c8031c9a9d527a6d808f1ddce096de23850ebfd6..dbf572cdc82b100ba9c26b4853f05db1ba5fa4ed 100644 +--- a/src/providers/ldap/sdap_async.h ++++ b/src/providers/ldap/sdap_async.h +@@ -58,6 +58,22 @@ errno_t sdap_connect_host_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct sdap_handle **_sh); + ++/* Search users in LDAP, return them as attrs */ ++struct tevent_req *sdap_search_user_send(TALLOC_CTX *memctx, ++ struct tevent_context *ev, ++ struct sss_domain_info *dom, ++ struct sdap_options *opts, ++ struct sdap_search_base **search_bases, ++ struct sdap_handle *sh, ++ const char **attrs, ++ const char *filter, ++ int timeout, ++ bool enumeration); ++int sdap_search_user_recv(TALLOC_CTX *memctx, struct tevent_req *req, ++ char **higher_usn, struct sysdb_attrs ***users, ++ size_t *count); ++ ++/* Search users in LDAP using the request above, save them to cache */ + struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx, + struct tevent_context *ev, + struct sss_domain_info *dom, +diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c +index 9cfe217482580d4a11ad4ace2f688f42ca55d7b3..7f0b2eea0b5ee909bcf148236c7fc43863fe8c13 100644 +--- a/src/providers/ldap/sdap_async_users.c ++++ b/src/providers/ldap/sdap_async_users.c +@@ -579,15 +579,15 @@ done: + + /* ==Search-Users-with-filter============================================= */ + +-struct sdap_get_users_state { ++struct sdap_search_user_state { + struct tevent_context *ev; + struct sdap_options *opts; + struct sdap_handle *sh; + struct sss_domain_info *dom; +- struct sysdb_ctx *sysdb; ++ + const char **attrs; + const char *base_filter; +- char *filter; ++ const char *filter; + int timeout; + bool enumeration; + +@@ -599,33 +599,31 @@ struct sdap_get_users_state { + struct sdap_search_base **search_bases; + }; + +-static errno_t sdap_get_users_next_base(struct tevent_req *req); +-static void sdap_get_users_process(struct tevent_req *subreq); ++static errno_t sdap_search_user_next_base(struct tevent_req *req); ++static void sdap_search_user_process(struct tevent_req *subreq); + +-struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx, +- struct tevent_context *ev, +- struct sss_domain_info *dom, +- struct sysdb_ctx *sysdb, +- struct sdap_options *opts, +- struct sdap_search_base **search_bases, +- struct sdap_handle *sh, +- const char **attrs, +- const char *filter, +- int timeout, +- bool enumeration) ++struct tevent_req *sdap_search_user_send(TALLOC_CTX *memctx, ++ struct tevent_context *ev, ++ struct sss_domain_info *dom, ++ struct sdap_options *opts, ++ struct sdap_search_base **search_bases, ++ struct sdap_handle *sh, ++ const char **attrs, ++ const char *filter, ++ int timeout, ++ bool enumeration) + { + errno_t ret; + struct tevent_req *req; +- struct sdap_get_users_state *state; ++ struct sdap_search_user_state *state; + +- req = tevent_req_create(memctx, &state, struct sdap_get_users_state); +- if (!req) return NULL; ++ req = tevent_req_create(memctx, &state, struct sdap_search_user_state); ++ if (req == NULL) return NULL; + + state->ev = ev; + state->opts = opts; + state->dom = dom; + state->sh = sh; +- state->sysdb = sysdb; + state->attrs = attrs; + state->higher_usn = NULL; + state->users = NULL; +@@ -643,7 +641,7 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx, + goto done; + } + +- ret = sdap_get_users_next_base(req); ++ ret = sdap_search_user_next_base(req); + + done: + if (ret != EOK) { +@@ -654,18 +652,18 @@ done: + return req; + } + +-static errno_t sdap_get_users_next_base(struct tevent_req *req) ++static errno_t sdap_search_user_next_base(struct tevent_req *req) + { + struct tevent_req *subreq; +- struct sdap_get_users_state *state; ++ struct sdap_search_user_state *state; + +- state = tevent_req_data(req, struct sdap_get_users_state); ++ state = tevent_req_data(req, struct sdap_search_user_state); + + talloc_zfree(state->filter); + state->filter = sdap_get_id_specific_filter(state, + state->base_filter, + state->search_bases[state->base_iter]->filter); +- if (!state->filter) { ++ if (state->filter == NULL) { + return ENOMEM; + } + +@@ -681,20 +679,20 @@ static errno_t sdap_get_users_next_base(struct tevent_req *req) + state->opts->user_map, SDAP_OPTS_USER, + state->timeout, + state->enumeration); /* If we're enumerating, we need paging */ +- if (!subreq) { ++ if (subreq == NULL) { + return ENOMEM; + } +- tevent_req_set_callback(subreq, sdap_get_users_process, req); ++ tevent_req_set_callback(subreq, sdap_search_user_process, req); + + return EOK; + } + +-static void sdap_get_users_process(struct tevent_req *subreq) ++static void sdap_search_user_process(struct tevent_req *subreq) + { + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); +- struct sdap_get_users_state *state = tevent_req_data(req, +- struct sdap_get_users_state); ++ struct sdap_search_user_state *state = tevent_req_data(req, ++ struct sdap_search_user_state); + int ret; + size_t count, i; + struct sysdb_attrs **users; +@@ -744,7 +742,7 @@ static void sdap_get_users_process(struct tevent_req *subreq) + state->base_iter++; + if (state->search_bases[state->base_iter]) { + /* There are more search bases to try */ +- ret = sdap_get_users_next_base(req); ++ ret = sdap_search_user_next_base(req); + if (ret != EOK) { + tevent_req_error(req, ret); + } +@@ -760,12 +758,112 @@ static void sdap_get_users_process(struct tevent_req *subreq) + return; + } + ++ DEBUG(SSSDBG_TRACE_ALL, ("Retrieved total %zu users\n", state->count)); ++ tevent_req_done(req); ++} ++ ++ ++int sdap_search_user_recv(TALLOC_CTX *memctx, struct tevent_req *req, ++ char **higher_usn, struct sysdb_attrs ***users, ++ size_t *count) ++{ ++ struct sdap_search_user_state *state = tevent_req_data(req, ++ struct sdap_search_user_state); ++ ++ if (higher_usn) { ++ *higher_usn = talloc_steal(memctx, state->higher_usn); ++ } ++ ++ if (users) { ++ *users = talloc_steal(memctx, state->users); ++ } ++ ++ if (count) { ++ *count = state->count; ++ } ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ return EOK; ++} ++ ++/* ==Search-And-Save-Users-with-filter============================================= */ ++struct sdap_get_users_state { ++ struct sysdb_ctx *sysdb; ++ struct sdap_options *opts; ++ struct sss_domain_info *dom; ++ ++ char *higher_usn; ++ struct sysdb_attrs **users; ++ size_t count; ++}; ++ ++static void sdap_get_users_done(struct tevent_req *subreq); ++ ++struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx, ++ struct tevent_context *ev, ++ struct sss_domain_info *dom, ++ struct sysdb_ctx *sysdb, ++ struct sdap_options *opts, ++ struct sdap_search_base **search_bases, ++ struct sdap_handle *sh, ++ const char **attrs, ++ const char *filter, ++ int timeout, ++ bool enumeration) ++{ ++ errno_t ret; ++ struct tevent_req *req; ++ struct tevent_req *subreq; ++ struct sdap_get_users_state *state; ++ ++ req = tevent_req_create(memctx, &state, struct sdap_get_users_state); ++ if (!req) return NULL; ++ ++ state->sysdb = sysdb; ++ state->opts = opts; ++ state->dom = dom; ++ ++ subreq = sdap_search_user_send(state, ev, dom, opts, search_bases, ++ sh, attrs, filter, timeout, enumeration); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ tevent_req_set_callback(subreq, sdap_get_users_done, req); ++ ++ ret = EOK; ++done: ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ } ++ ++ return req; ++} ++ ++static void sdap_get_users_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct sdap_get_users_state *state = tevent_req_data(req, ++ struct sdap_get_users_state); ++ int ret; ++ ++ ret = sdap_search_user_recv(state, subreq, &state->higher_usn, ++ &state->users, &state->count); ++ if (ret) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Failed to retrieve users\n")); ++ tevent_req_error(req, ret); ++ return; ++ } ++ + ret = sdap_save_users(state, state->sysdb, + state->dom, state->opts, + state->users, state->count, + &state->higher_usn); + if (ret) { +- DEBUG(2, ("Failed to store users.\n")); ++ DEBUG(SSSDBG_OP_FAILURE, ("Failed to store users.\n")); + tevent_req_error(req, ret); + return; + } +-- +1.8.4.2 + diff --git a/SOURCES/0011-LDAP-Search-for-original-DN-during-auth-if-it-s-miss.patch b/SOURCES/0011-LDAP-Search-for-original-DN-during-auth-if-it-s-miss.patch new file mode 100644 index 0000000..11481f6 --- /dev/null +++ b/SOURCES/0011-LDAP-Search-for-original-DN-during-auth-if-it-s-miss.patch @@ -0,0 +1,269 @@ +From 8285fdca515e103eed41625a444de6fe72c5daa7 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 1 Oct 2013 17:44:55 +0200 +Subject: [PATCH 11/11] LDAP: Search for original DN during auth if it's + missing + +Resolves: https://fedorahosted.org/sssd/ticket/2077 + +If during the LDAP authentication we find out that the originalDN to +bind as is missing (because the ID module is not LDAP based), we can try +to look up the user from LDAP without saving him just in order to +receive the originalDN. +--- + src/providers/ldap/ldap_auth.c | 210 +++++++++++++++++++++++++++++++++++++---- + 1 file changed, 194 insertions(+), 16 deletions(-) + +diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c +index f9bab4b2b72a061c88fbf18d3f8401b673f79619..ddaeb09c8ae06812855a1daec2fc3399eb4be361 100644 +--- a/src/providers/ldap/ldap_auth.c ++++ b/src/providers/ldap/ldap_auth.c +@@ -343,6 +343,146 @@ shadow_fail: + } + + /* ==Get-User-DN========================================================== */ ++struct get_user_dn_state { ++ const char *username; ++ ++ char *orig_dn; ++}; ++ ++static void get_user_dn_done(struct tevent_req *subreq); ++ ++static struct tevent_req *get_user_dn_send(TALLOC_CTX *memctx, ++ struct tevent_context *ev, ++ struct sss_domain_info *domain, ++ struct sdap_handle *sh, ++ struct sdap_options *opts, ++ const char *username) ++{ ++ struct tevent_req *req; ++ struct tevent_req *subreq; ++ struct get_user_dn_state *state; ++ char *clean_name; ++ char *filter; ++ const char **attrs; ++ errno_t ret; ++ ++ req = tevent_req_create(memctx, &state, struct get_user_dn_state); ++ if (!req) return NULL; ++ ++ state->username = username; ++ ++ ret = sss_filter_sanitize(state, username, &clean_name); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))", ++ opts->user_map[SDAP_AT_USER_NAME].name, ++ clean_name, ++ opts->user_map[SDAP_OC_USER].name); ++ talloc_zfree(clean_name); ++ if (filter == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Failed to build the base filter\n")); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ /* We're mostly interested in the DN anyway */ ++ attrs = talloc_array(state, const char *, 3); ++ if (attrs == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ attrs[0] = "objectclass"; ++ attrs[1] = opts->user_map[SDAP_AT_USER_NAME].name; ++ attrs[2] = NULL; ++ ++ subreq = sdap_search_user_send(state, ev, domain, opts, ++ opts->sdom->user_search_bases, ++ sh, attrs, filter, ++ dp_opt_get_int(opts->basic, ++ SDAP_SEARCH_TIMEOUT), ++ false); ++ if (!subreq) { ++ ret = ENOMEM; ++ goto done; ++ } ++ tevent_req_set_callback(subreq, get_user_dn_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 get_user_dn_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct get_user_dn_state *state = tevent_req_data(req, ++ struct get_user_dn_state); ++ struct ldb_message_element *el; ++ struct sysdb_attrs **users; ++ size_t count; ++ ++ ret = sdap_search_user_recv(state, subreq, NULL, &users, &count); ++ talloc_zfree(subreq); ++ if (ret && ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Failed to retrieve users\n")); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (count == 0) { ++ DEBUG(SSSDBG_OP_FAILURE, ("No such user\n")); ++ tevent_req_error(req, ENOMEM); ++ return; ++ } else if (count > 1) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Multiple users matched\n")); ++ tevent_req_error(req, EIO); ++ return; ++ } ++ ++ /* exactly one user. Get the originalDN */ ++ ret = sysdb_attrs_get_el_ext(users[0], SYSDB_ORIG_DN, false, &el); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("originalDN is not available for [%s].\n", state->username)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ state->orig_dn = talloc_strdup(state, (const char *) el->values[0].data); ++ if (state->orig_dn == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, ("Found originalDN [%s] for [%s]\n", ++ state->orig_dn, state->username)); ++ tevent_req_done(req); ++} ++ ++static int get_user_dn_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req, ++ char **orig_dn) ++{ ++ struct get_user_dn_state *state = tevent_req_data(req, ++ struct get_user_dn_state); ++ ++ if (orig_dn) { ++ *orig_dn = talloc_move(mem_ctx, &state->orig_dn); ++ } ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ return EOK; ++} + + static int get_user_dn(TALLOC_CTX *memctx, + struct sysdb_ctx *sysdb, +@@ -391,25 +531,20 @@ static int get_user_dn(TALLOC_CTX *memctx, + + switch (res->count) { + case 0: +- /* FIXME: not in cache, needs a true search */ +- ret = ENOENT; ++ /* No such user entry? Look it up */ ++ ret = EAGAIN; + break; + + case 1: + dn = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_ORIG_DN, NULL); +- if (dn) { +- dn = talloc_strdup(tmpctx, dn); +- } else { +- /* TODO: try to search ldap server ? */ +- +- /* FIXME: remove once we store originalDN on every call +- * NOTE: this is wrong, works only with some DITs */ +- dn = talloc_asprintf(tmpctx, "%s=%s,%s", +- opts->user_map[SDAP_AT_USER_NAME].name, +- username, +- dp_opt_get_string(opts->basic, +- SDAP_USER_SEARCH_BASE)); ++ if (dn == NULL) { ++ /* The user entry has no original DN. This is the case when the ID ++ * provider is not LDAP-based (proxy perhaps) */ ++ ret = EAGAIN; ++ break; + } ++ ++ dn = talloc_strdup(tmpctx, dn); + if (!dn) { + ret = ENOMEM; + break; +@@ -466,6 +601,8 @@ struct auth_state { + }; + + static struct tevent_req *auth_get_server(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); +@@ -610,11 +747,52 @@ static void auth_connect_done(struct tevent_req *subreq) + ret = get_user_dn(state, state->ctx->be->domain->sysdb, state->ctx->be->domain, + state->ctx->opts, state->username, &state->dn, + &state->pw_expire_type, &state->pw_expire_data); +- if (ret) { +- tevent_req_error(req, ret); ++ if (ret == EOK) { ++ /* All required user data was pre-cached during an identity lookup. ++ * We can proceed with the bind */ ++ auth_do_bind(req); ++ return; ++ } else if (ret == EAGAIN) { ++ /* The cached user entry was missing the bind DN. Need to look ++ * it up based on user name in order to perform the bind */ ++ subreq = get_user_dn_send(req, state->ev, state->ctx->be->domain, ++ state->sh, state->ctx->opts, state->username); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, auth_get_dn_done, req); ++ return; ++ } ++ ++ tevent_req_error(req, ret); ++ return; ++} ++ ++static void auth_get_dn_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); ++ errno_t ret; ++ ++ ret = get_user_dn_recv(state, subreq, &state->dn); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ tevent_req_error(req, ERR_ACCOUNT_UNKNOWN); + return; + } + ++ /* The DN was found with an LDAP lookup ++ * We can proceed with the bind */ ++ return auth_do_bind(req); ++} ++ ++static void auth_do_bind(struct tevent_req *req) ++{ ++ struct auth_state *state = tevent_req_data(req, struct auth_state); ++ struct tevent_req *subreq; ++ + subreq = sdap_auth_send(state, state->ev, state->sh, + NULL, NULL, state->dn, + state->authtok); +-- +1.8.4.2 + diff --git a/SOURCES/0012-LDAP-Prevent-from-using-uninitialized-sdap_options.patch b/SOURCES/0012-LDAP-Prevent-from-using-uninitialized-sdap_options.patch new file mode 100644 index 0000000..7c99b36 --- /dev/null +++ b/SOURCES/0012-LDAP-Prevent-from-using-uninitialized-sdap_options.patch @@ -0,0 +1,30 @@ +From 5eea6f1e7a43bdd63a1530fb9c68ef292f431f4f Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Wed, 13 Nov 2013 08:32:23 +0100 +Subject: [PATCH 12/12] LDAP: Prevent from using uninitialized sdap_options + +ldap_get_options can fail in time of ldap back end initialisation +and then sssd try to release uninitialised sdap_options. + +Resolves: +https://fedorahosted.org/sssd/ticket/2147 +--- + src/providers/ldap/ldap_init.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c +index 17874b1325d3e5bf2eded62c6f022364b84a5c2a..15615b2891f2e3104c11e8610c081adcd1d1ee8e 100644 +--- a/src/providers/ldap/ldap_init.c ++++ b/src/providers/ldap/ldap_init.c +@@ -94,7 +94,7 @@ int sssm_ldap_id_init(struct be_ctx *bectx, + const char *dns_service_name; + const char *sasl_mech; + struct sdap_service *sdap_service; +- struct sdap_options *opts; ++ struct sdap_options *opts = NULL; + int ret; + + /* If we're already set up, just return that */ +-- +1.8.4.2 + diff --git a/SOURCES/0013-SUBDOMAINS-Reuse-cached-results-if-DP-is-offline.patch b/SOURCES/0013-SUBDOMAINS-Reuse-cached-results-if-DP-is-offline.patch new file mode 100644 index 0000000..bc5a348 --- /dev/null +++ b/SOURCES/0013-SUBDOMAINS-Reuse-cached-results-if-DP-is-offline.patch @@ -0,0 +1,63 @@ +From 8751aace6de14f3782765a89555b65e991f340a0 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 3 Dec 2013 15:25:25 +0100 +Subject: [PATCH 13/15] SUBDOMAINS: Reuse cached results if DP is offline + +If Data Provider was unable to refresh the subdomain list, the +sss_domain_info->subdomains list was NULL. Which meant that no DP +request matched any known domain and hence offline authentication was +not working correctly. + +Resolves: +https://fedorahosted.org/sssd/ticket/2168 +--- + src/providers/ad/ad_subdomains.c | 7 +++++++ + src/providers/ipa/ipa_subdomains.c | 8 ++++++-- + 2 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index 9911dfe0f4fda6749fa6dd3f15b1c04a36964ca4..18414523096ba0e53261415551eea57b4b2758b2 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -650,5 +650,12 @@ int ad_subdom_init(struct be_ctx *be_ctx, + return EFAULT; + } + ++ ret = sysdb_update_subdomains(be_ctx->domain); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Could not load the list of subdomains. " ++ "Users from trusted domains might not be resolved correctly\n")); ++ /* Ignore this error and try to discover the subdomains later */ ++ } ++ + return EOK; + } +diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c +index 4f7627eddb9c54d68e45be876157057f3c30b422..416e21913be8e991c9f496ff2b54f238b602f304 100644 +--- a/src/providers/ipa/ipa_subdomains.c ++++ b/src/providers/ipa/ipa_subdomains.c +@@ -809,8 +809,6 @@ static void ipa_subdomains_get_conn_done(struct tevent_req *req) + DEBUG(SSSDBG_MINOR_FAILURE, + ("No IPA server is available, cannot get the " + "subdomain list while offline\n")); +- +-/* FIXME: return saved results ?? */ + } else { + DEBUG(SSSDBG_OP_FAILURE, + ("Failed to connect to IPA server: [%d](%s)\n", +@@ -1291,6 +1289,12 @@ int ipa_subdom_init(struct be_ctx *be_ctx, + DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to add subdom offline callback")); + } + ++ ret = sysdb_update_subdomains(be_ctx->domain); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Could not load the list of subdomains. " ++ "Users from trusted domains might not be resolved correctly\n")); ++ } ++ + return EOK; + } + +-- +1.8.4.2 + diff --git a/SOURCES/0014-failover-check-dns_domain-if-primary-servers-lookup-.patch b/SOURCES/0014-failover-check-dns_domain-if-primary-servers-lookup-.patch new file mode 100644 index 0000000..3da0806 --- /dev/null +++ b/SOURCES/0014-failover-check-dns_domain-if-primary-servers-lookup-.patch @@ -0,0 +1,42 @@ +From 0926cec5b98218131ac822e1684f9bce7aa0072c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 5 Dec 2013 13:19:16 +0100 +Subject: [PATCH 14/15] failover: check dns_domain if primary servers lookup + failed + +If primary servers lookup failed, dns_domain is not set. + +Resolves: +https://fedorahosted.org/sssd/ticket/2173 +--- + src/providers/fail_over_srv.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/src/providers/fail_over_srv.c b/src/providers/fail_over_srv.c +index 543516ef19e288556e39e61b400a628c94e2817b..c27416899e30b3cf8b3c0496adb08089f4b2c11d 100644 +--- a/src/providers/fail_over_srv.c ++++ b/src/providers/fail_over_srv.c +@@ -302,13 +302,17 @@ static void fo_discover_servers_primary_done(struct tevent_req *subreq) + } + + if (state->backup_domain == NULL) { ++ /* if there is no backup domain, we are done */ + DEBUG(SSSDBG_TRACE_FUNC, ("No backup domain specified\n")); + goto done; + } + +- if (strcasecmp(state->dns_domain, state->backup_domain) == 0) { +- /* primary domain was unreachable, we will use servers from backup +- * domain as primary */ ++ if (state->dns_domain != NULL ++ && strcasecmp(state->dns_domain, state->backup_domain) == 0) { ++ /* If there was no error and dns_domain is the same as backup domain, ++ * it means that we were unable to resolve SRV in primary domain, but ++ * SRV from backup domain was resolved and those servers are considered ++ * to be primary. We are done. */ + state->backup_servers = NULL; + state->num_backup_servers = 0; + +-- +1.8.4.2 + diff --git a/SOURCES/0015-NSS-Set-packet-length-for-initgroups.patch b/SOURCES/0015-NSS-Set-packet-length-for-initgroups.patch new file mode 100644 index 0000000..b122626 --- /dev/null +++ b/SOURCES/0015-NSS-Set-packet-length-for-initgroups.patch @@ -0,0 +1,37 @@ +From 644f0b89c61b8a912514df550633f179c654240a Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Tue, 5 Nov 2013 17:58:36 +0100 +Subject: [PATCH 15/15] NSS: Set packet length for initgroups + +Some groups could be skipped, but packet length was not trimmed. +This is a reason why valgrind reported access to uninitialised bytes. +Actually, it isn't a problem, because the first uint32 in body is number of +sended gids. + +Resolves: +https://fedorahosted.org/sssd/ticket/2138 +--- + src/responder/nss/nsssrv_cmd.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c +index ada2b64df88d6a03a5c36a76076da447faa573c9..07f31188074bf45664969fb33388edb475e53b96 100644 +--- a/src/responder/nss/nsssrv_cmd.c ++++ b/src/responder/nss/nsssrv_cmd.c +@@ -3558,6 +3558,13 @@ static int fill_initgr(struct sss_packet *packet, struct ldb_result *res) + + ((uint32_t *)body)[0] = num-skipped; /* num results */ + ((uint32_t *)body)[1] = 0; /* reserved */ ++ blen = (2 + bindex) * sizeof(uint32_t); ++ ret = sss_packet_set_size(packet, blen); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("Could not set packet size to value:%zu\n", blen)); ++ return ret; ++ } + + return EOK; + } +-- +1.8.4.2 + diff --git a/SOURCES/0016-NSS-Fix-memory-leak-in-sss_setnetgrent.patch b/SOURCES/0016-NSS-Fix-memory-leak-in-sss_setnetgrent.patch new file mode 100644 index 0000000..698ba3e --- /dev/null +++ b/SOURCES/0016-NSS-Fix-memory-leak-in-sss_setnetgrent.patch @@ -0,0 +1,33 @@ +From 81aa563090c33bafbf22f1cde586b77ed526c25f Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Wed, 27 Nov 2013 10:22:59 +0100 +Subject: [PATCH 16/17] NSS: Fix memory leak in sss_setnetgrent + +struct nss_cmd_ctx was not released in function nss_cmd_setnetgrent_done +and it wasn't used in the other function, because getnetgrent creates its own +nss_cmd_ctx context. struct nss_cmd_ctx was released after closing client +because it was allocated under client context. Memory leak is apparent with +long living clients. + +Resolves: +https://fedorahosted.org/sssd/ticket/2170 +--- + src/responder/nss/nsssrv_netgroup.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/responder/nss/nsssrv_netgroup.c b/src/responder/nss/nsssrv_netgroup.c +index a1c41968db0becbc42a1c501b666d9aec5241b5f..18e8579372fa39a1b3a60076948bc12bc008fb80 100644 +--- a/src/responder/nss/nsssrv_netgroup.c ++++ b/src/responder/nss/nsssrv_netgroup.c +@@ -687,7 +687,7 @@ static void nss_cmd_setnetgrent_done(struct tevent_req *req) + ((uint32_t *)body)[1] = 0; /* reserved */ + } + +- sss_cmd_done(cmdctx->cctx, NULL); ++ sss_cmd_done(cmdctx->cctx, cmdctx); + return; + } + +-- +1.8.4.2 + diff --git a/SOURCES/0017-AD-use-LDAP-for-group-lookups.patch b/SOURCES/0017-AD-use-LDAP-for-group-lookups.patch new file mode 100644 index 0000000..be1d3cf --- /dev/null +++ b/SOURCES/0017-AD-use-LDAP-for-group-lookups.patch @@ -0,0 +1,253 @@ +From 0324d31d0479e5de0d3aac05bf5fb922d84f84c4 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 9 Dec 2013 11:45:28 +0100 +Subject: [PATCH 17/17] AD: use LDAP for group lookups + +The group memberships cannot be reliable retrieved from the Global +Catalog. By default the memberOf attribute is not replicated to the GC +at all and the member attribute is copied from the local LDAP instance +to the GC running on the same host, but is only replicated to other GC +instances for groups with universal scope. Additionally the tokenGroups +attribute contains invalid SIDs when used with the GC for users from a +different domains than the GC belongs to. + +As a result the requests which tries to resolve group-memberships of a +AD user have to go to a LDAP server from the domain of the user. + +Fixes https://fedorahosted.org/sssd/ticket/2161 and +https://fedorahosted.org/sssd/ticket/2148 as a side-effect. +--- + src/providers/ad/ad_id.c | 20 +++++- + src/providers/ad/ad_subdomains.c | 133 ++++++++++++++++++++++++++++++++++++++- + src/providers/ldap/sdap.h | 2 + + 3 files changed, 152 insertions(+), 3 deletions(-) + +diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c +index 87b69c66892ebfa48a1067c63006f3e3bd2e7444..dadb50da92cac87d3162bddb44395dad7d2abbc4 100644 +--- a/src/providers/ad/ad_id.c ++++ b/src/providers/ad/ad_id.c +@@ -188,6 +188,8 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx, + struct sss_domain_info *dom, struct be_acct_req *ar) + { + struct sdap_id_conn_ctx **clist; ++ struct sdap_domain *sdom; ++ struct ad_id_ctx *subdom_id_ctx; + + /* LDAP, GC, sentinel */ + clist = talloc_zero_array(breq, struct sdap_id_conn_ctx *, 3); +@@ -197,8 +199,6 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx, + case BE_REQ_USER: /* user */ + case BE_REQ_BY_SECID: /* by SID */ + case BE_REQ_USER_AND_GROUP: /* get SID */ +- case BE_REQ_GROUP: /* group */ +- case BE_REQ_INITGROUPS: /* init groups for user */ + /* Always try GC first */ + clist[0] = ad_ctx->gc_ctx; + if (IS_SUBDOMAIN(dom) == true) { +@@ -216,6 +216,22 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx, + clist[1] = ad_ctx->ldap_ctx; + break; + ++ case BE_REQ_GROUP: /* group */ ++ case BE_REQ_INITGROUPS: /* init groups for user */ ++ if (IS_SUBDOMAIN(dom)) { ++ sdom = sdap_domain_get(ad_ctx->sdap_id_ctx->opts, dom); ++ if (sdom == NULL || sdom->pvt == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("No ID ctx available for [%s].\n", ++ dom->name)); ++ return NULL; ++ } ++ subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx); ++ clist[0] = subdom_id_ctx->ldap_ctx; ++ } else { ++ clist[0] = ad_ctx->ldap_ctx; ++ } ++ break; ++ + default: + clist[0] = ad_ctx->ldap_ctx; + break; +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index 18414523096ba0e53261415551eea57b4b2758b2..28c5eafb395b70e8f3630a43b67c61810683fe7c 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -25,6 +25,7 @@ + #include "providers/ldap/sdap_async.h" + #include "providers/ad/ad_subdomains.h" + #include "providers/ad/ad_domain_info.h" ++#include "providers/ad/ad_srv.h" + #include "providers/ldap/sdap_idmap.h" + #include "util/util_sss_idmap.h" + #include +@@ -68,6 +69,7 @@ struct ad_subdomains_ctx { + + time_t last_refreshed; + struct tevent_timer *timer_event; ++ struct ad_id_ctx *ad_id_ctx; + }; + + struct ad_subdomains_req_ctx { +@@ -86,10 +88,138 @@ struct ad_subdomains_req_ctx { + }; + + static errno_t ++ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, ++ struct ad_id_ctx *id_ctx, ++ struct sss_domain_info *subdom, ++ struct ad_id_ctx **_subdom_id_ctx) ++{ ++ struct ad_options *ad_options; ++ struct ad_id_ctx *ad_id_ctx; ++ const char *gc_service_name; ++ struct ad_srv_plugin_ctx *srv_ctx; ++ char *ad_domain; ++ struct sdap_domain *sdom; ++ errno_t ret; ++ const char *realm; ++ const char *hostname; ++ ++ realm = dp_opt_get_cstring(id_ctx->ad_options->basic, AD_KRB5_REALM); ++ hostname = dp_opt_get_cstring(id_ctx->ad_options->basic, AD_HOSTNAME); ++ if (realm == NULL || hostname == NULL) { ++ DEBUG(SSSDBG_CONF_SETTINGS, ("Missing realm or hostname.\n")); ++ return EINVAL; ++ } ++ ++ ad_options = ad_create_default_options(id_ctx, realm, hostname); ++ if (ad_options == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Cannot initialize AD options\n")); ++ talloc_free(ad_options); ++ return ENOMEM; ++ } ++ ++ ad_domain = subdom->name; ++ ++ ret = dp_opt_set_string(ad_options->basic, AD_DOMAIN, ad_domain); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Cannot set AD domain\n")); ++ talloc_free(ad_options); ++ return ret; ++ } ++ ++ gc_service_name = talloc_asprintf(ad_options, "%s%s", "gc_", subdom->name); ++ if (gc_service_name == NULL) { ++ talloc_free(ad_options); ++ return ENOMEM; ++ } ++ ++ ret = ad_failover_init(ad_options, be_ctx, NULL, NULL, realm, ++ subdom->name, gc_service_name, ++ subdom->name, &ad_options->service); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Cannot initialize AD failover\n")); ++ talloc_free(ad_options); ++ return ret; ++ } ++ ++ ad_id_ctx = ad_id_ctx_init(ad_options, be_ctx); ++ if (ad_id_ctx == NULL) { ++ talloc_free(ad_options); ++ return ENOMEM; ++ } ++ ad_id_ctx->sdap_id_ctx->opts = ad_options->id; ++ ad_options->id_ctx = ad_id_ctx; ++ ++ /* use AD plugin */ ++ srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx->be_res, ++ default_host_dbs, ++ ad_id_ctx->ad_options->id, ++ hostname, ++ ad_domain); ++ if (srv_ctx == NULL) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ("Out of memory?\n")); ++ return ENOMEM; ++ } ++ be_fo_set_srv_lookup_plugin(be_ctx, ad_srv_plugin_send, ++ ad_srv_plugin_recv, srv_ctx, "AD"); ++ ++ ret = sdap_domain_subdom_add(ad_id_ctx->sdap_id_ctx, ++ ad_id_ctx->sdap_id_ctx->opts->sdom, ++ subdom->parent); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Cannot initialize sdap domain\n")); ++ talloc_free(ad_options); ++ return ret; ++ } ++ ++ sdom = sdap_domain_get(ad_id_ctx->sdap_id_ctx->opts, subdom); ++ if (sdom == NULL) { ++ return EFAULT; ++ } ++ ++ ret = sdap_id_setup_tasks(ad_id_ctx->sdap_id_ctx, ++ ad_id_ctx->ldap_ctx, sdom, ++ ldap_enumeration_send, ++ ldap_enumeration_recv); ++ if (ret != EOK) { ++ talloc_free(ad_options); ++ return ret; ++ } ++ ++ /* Set up the ID mapping object */ ++ ad_id_ctx->sdap_id_ctx->opts->idmap_ctx = ++ id_ctx->sdap_id_ctx->opts->idmap_ctx; ++ ++ *_subdom_id_ctx = ad_id_ctx; ++ return EOK; ++} ++ ++static errno_t + ads_store_sdap_subdom(struct ad_subdomains_ctx *ctx, + struct sss_domain_info *parent) + { +- return sdap_domain_subdom_add(ctx->sdap_id_ctx, ctx->sdom, parent); ++ int ret; ++ struct sdap_domain *sditer; ++ struct ad_id_ctx *subdom_id_ctx; ++ ++ ret = sdap_domain_subdom_add(ctx->sdap_id_ctx, ctx->sdom, parent); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("sdap_domain_subdom_add failed.\n")); ++ return ret; ++ } ++ ++ 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, ++ sditer->dom, &subdom_id_ctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("ad_subdom_ad_ctx_new failed.\n")); ++ } else { ++ sditer->pvt = subdom_id_ctx; ++ } ++ } ++ } ++ ++ return EOK; + } + + static errno_t +@@ -630,6 +760,7 @@ int ad_subdom_init(struct be_ctx *be_ctx, + DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n")); + return ENOMEM; + } ++ ctx->ad_id_ctx = id_ctx; + *ops = &ad_subdomains_ops; + *pvt_data = ctx; + +diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h +index c53471b9bd6d9b18f37a8bf4089c8700d4a1163d..fa641730bb78b6a96c0b9640af7612b876f56533 100644 +--- a/src/providers/ldap/sdap.h ++++ b/src/providers/ldap/sdap.h +@@ -394,6 +394,8 @@ struct sdap_domain { + struct timeval last_enum; + /* cleanup loop timer */ + struct timeval last_purge; ++ ++ void *pvt; + }; + + struct sdap_options { +-- +1.8.4.2 + diff --git a/SOURCES/0018-idmap-add-API-to-free-allocated-SIDs.patch b/SOURCES/0018-idmap-add-API-to-free-allocated-SIDs.patch new file mode 100644 index 0000000..02df2e8 --- /dev/null +++ b/SOURCES/0018-idmap-add-API-to-free-allocated-SIDs.patch @@ -0,0 +1,119 @@ +From 16c8b0e7a0ac40b078f98c9f8025d39a59dca9bb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 1 Nov 2013 12:23:23 +0100 +Subject: [PATCH 18/31] idmap: add API to free allocated SIDs + +--- + src/lib/idmap/sss_idmap.c | 36 +++++++++++++++++++++++++++++++++++ + src/lib/idmap/sss_idmap.h | 48 +++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 84 insertions(+) + +diff --git a/src/lib/idmap/sss_idmap.c b/src/lib/idmap/sss_idmap.c +index 9278e10d2bee37b741a87cd84d666d8a5b7bb671..3f1e7a58f390a3c10999251e2155ef513ba69bd7 100644 +--- a/src/lib/idmap/sss_idmap.c ++++ b/src/lib/idmap/sss_idmap.c +@@ -246,6 +246,42 @@ enum idmap_error_code sss_idmap_free(struct sss_idmap_ctx *ctx) + return IDMAP_SUCCESS; + } + ++static enum idmap_error_code sss_idmap_free_ptr(struct sss_idmap_ctx *ctx, ++ void *ptr) ++{ ++ CHECK_IDMAP_CTX(ctx, IDMAP_CONTEXT_INVALID); ++ ++ if (ptr != NULL) { ++ ctx->free_func(ptr, ctx->alloc_pvt); ++ } ++ ++ return IDMAP_SUCCESS; ++} ++ ++enum idmap_error_code sss_idmap_free_sid(struct sss_idmap_ctx *ctx, ++ char *sid) ++{ ++ return sss_idmap_free_ptr(ctx, sid); ++} ++ ++enum idmap_error_code sss_idmap_free_dom_sid(struct sss_idmap_ctx *ctx, ++ struct sss_dom_sid *dom_sid) ++{ ++ return sss_idmap_free_ptr(ctx, dom_sid); ++} ++ ++enum idmap_error_code sss_idmap_free_smb_sid(struct sss_idmap_ctx *ctx, ++ struct dom_sid *smb_sid) ++{ ++ return sss_idmap_free_ptr(ctx, smb_sid); ++} ++ ++enum idmap_error_code sss_idmap_free_bin_sid(struct sss_idmap_ctx *ctx, ++ uint8_t *bin_sid) ++{ ++ return sss_idmap_free_ptr(ctx, bin_sid); ++} ++ + enum idmap_error_code sss_idmap_calculate_range(struct sss_idmap_ctx *ctx, + const char *dom_sid, + id_t *slice_num, +diff --git a/src/lib/idmap/sss_idmap.h b/src/lib/idmap/sss_idmap.h +index 4101fb9a5e0982c6ba0560decd299a0ed9e722b6..1e1c9a5cfe490301d0e633db808589f1bc0ef857 100644 +--- a/src/lib/idmap/sss_idmap.h ++++ b/src/lib/idmap/sss_idmap.h +@@ -504,6 +504,54 @@ enum idmap_error_code sss_idmap_unix_to_bin_sid(struct sss_idmap_ctx *ctx, + enum idmap_error_code sss_idmap_free(struct sss_idmap_ctx *ctx); + + /** ++ * @brief Free mapped SID. ++ * ++ * @param[in] ctx Idmap context ++ * @param[in] sid SID to be freed. ++ * ++ * @return ++ * - #IDMAP_CONTEXT_INVALID: Provided context is invalid ++ */ ++enum idmap_error_code sss_idmap_free_sid(struct sss_idmap_ctx *ctx, ++ char *sid); ++ ++/** ++ * @brief Free mapped domain SID. ++ * ++ * @param[in] ctx Idmap context ++ * @param[in] dom_sid Domain SID to be freed. ++ * ++ * @return ++ * - #IDMAP_CONTEXT_INVALID: Provided context is invalid ++ */ ++enum idmap_error_code sss_idmap_free_dom_sid(struct sss_idmap_ctx *ctx, ++ struct sss_dom_sid *dom_sid); ++ ++/** ++ * @brief Free mapped Samba SID. ++ * ++ * @param[in] ctx Idmap context ++ * @param[in] smb_sid Samba SID to be freed. ++ * ++ * @return ++ * - #IDMAP_CONTEXT_INVALID: Provided context is invalid ++ */ ++enum idmap_error_code sss_idmap_free_smb_sid(struct sss_idmap_ctx *ctx, ++ struct dom_sid *smb_sid); ++ ++/** ++ * @brief Free mapped binary SID. ++ * ++ * @param[in] ctx Idmap context ++ * @param[in] smb_sid Binary SID to be freed. ++ * ++ * @return ++ * - #IDMAP_CONTEXT_INVALID: Provided context is invalid ++ */ ++enum idmap_error_code sss_idmap_free_bin_sid(struct sss_idmap_ctx *ctx, ++ uint8_t *bin_sid); ++ ++/** + * @brief Translate error code to a string + * + * @param[in] err Idmap error code +-- +1.8.4.2 + diff --git a/SOURCES/0019-free-idmapped-SIDs-correctly.patch b/SOURCES/0019-free-idmapped-SIDs-correctly.patch new file mode 100644 index 0000000..241ae14 --- /dev/null +++ b/SOURCES/0019-free-idmapped-SIDs-correctly.patch @@ -0,0 +1,205 @@ +From 9fad27b40eff82bcdffa61cafcc54e2d7750faee Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 1 Nov 2013 12:27:59 +0100 +Subject: [PATCH 19/31] free idmapped SIDs correctly + +Resolves: +https://fedorahosted.org/sssd/ticket/2133 +--- + src/providers/ad/ad_id.c | 3 +-- + src/providers/ad/ad_subdomains.c | 2 ++ + src/providers/ldap/ldap_id.c | 4 ++-- + src/providers/ldap/sdap_async_initgroups_ad.c | 2 ++ + src/responder/pac/pacsrv_cmd.c | 2 ++ + src/responder/pac/pacsrv_utils.c | 4 ++-- + src/tests/cmocka/test_sss_idmap.c | 2 ++ + src/tests/sss_idmap-tests.c | 14 +++++++------- + 8 files changed, 20 insertions(+), 13 deletions(-) + +diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c +index dadb50da92cac87d3162bddb44395dad7d2abbc4..19bc65825be21c6419db1e92db642be0a14b97a8 100644 +--- a/src/providers/ad/ad_id.c ++++ b/src/providers/ad/ad_id.c +@@ -307,8 +307,7 @@ static errno_t ad_account_can_shortcut(struct be_ctx *be_ctx, + + done: + if (sid != NULL) { +- /* FIXME: use library function when #2133 is fixed */ +- talloc_free(sid); ++ sss_idmap_free_sid(idmap_ctx->map, sid); + } + + if (ret == EOK) { +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index 28c5eafb395b70e8f3630a43b67c61810683fe7c..dd692fb699ddf14bcf8f9926383e82da77c494e0 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -302,7 +302,9 @@ ad_subdom_store(struct ad_subdomains_ctx *ctx, + + ret = EOK; + done: ++ sss_idmap_free_sid(ctx->sdap_id_ctx->opts->idmap_ctx->map, sid_str); + talloc_free(tmp_ctx); ++ + return ret; + } + +diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c +index fad1585331b7f0240770d2dc5a2e89788d2ad4da..793bc99ebcec883be7db3fc9dd56fa511d8ba3bb 100644 +--- a/src/providers/ldap/ldap_id.c ++++ b/src/providers/ldap/ldap_id.c +@@ -139,7 +139,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, + + attr_name = ctx->opts->user_map[SDAP_AT_USER_OBJECTSID].name; + ret = sss_filter_sanitize(state, sid, &clean_name); +- talloc_zfree(sid); ++ sss_idmap_free_sid(ctx->opts->idmap_ctx->map, sid); + if (ret != EOK) { + goto fail; + } +@@ -509,7 +509,7 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx, + + attr_name = ctx->opts->group_map[SDAP_AT_GROUP_OBJECTSID].name; + ret = sss_filter_sanitize(state, sid, &clean_name); +- talloc_zfree(sid); ++ sss_idmap_free_sid(ctx->opts->idmap_ctx->map, sid); + if (ret != EOK) { + goto fail; + } +diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c +index a0841a799bdbb1ad4de856d1715c88588b3b4da9..aa72c8876ba93eefc6230537801c50ab04e591ce 100644 +--- a/src/providers/ldap/sdap_async_initgroups_ad.c ++++ b/src/providers/ldap/sdap_async_initgroups_ad.c +@@ -594,6 +594,8 @@ sdap_get_ad_tokengroups_initgroups_lookup_done(struct tevent_req *subreq) + in_transaction = false; + + done: ++ sss_idmap_free_sid(state->opts->idmap_ctx->map, sid_str); ++ + if (in_transaction) { + sret = sysdb_transaction_cancel(state->sysdb); + DEBUG(SSSDBG_FATAL_FAILURE, +diff --git a/src/responder/pac/pacsrv_cmd.c b/src/responder/pac/pacsrv_cmd.c +index f6e8abaf580a43417f3ea09929feccf19e5b0f29..144f5f5847e7ead490d59bae0e2fe49722eb9b69 100644 +--- a/src/responder/pac/pacsrv_cmd.c ++++ b/src/responder/pac/pacsrv_cmd.c +@@ -161,6 +161,8 @@ static errno_t pac_add_pac_user(struct cli_ctx *cctx) + goto done; + } + ++ talloc_steal(pr_ctx, pr_ctx->user_dom_sid_str); ++ + ret = responder_get_domain_by_id(cctx->rctx, pr_ctx->user_dom_sid_str, + &pr_ctx->dom); + if (ret == EAGAIN || ret == ENOENT) { +diff --git a/src/responder/pac/pacsrv_utils.c b/src/responder/pac/pacsrv_utils.c +index 05b53edee2ada79abf8bd04a6032314b68541d8e..30055a1345b7d943e6adf822438263c92e53b51a 100644 +--- a/src/responder/pac/pacsrv_utils.c ++++ b/src/responder/pac/pacsrv_utils.c +@@ -264,14 +264,14 @@ errno_t get_sids_from_pac(TALLOC_CTX *mem_ctx, + goto done; + } + +- talloc_zfree(sid_str); ++ sss_idmap_free_sid(pac_ctx->idmap_ctx, sid_str); + } + + ret = EOK; + + done: + talloc_free(sid_str); +- talloc_free(user_dom_sid_str); ++ sss_idmap_free_sid(pac_ctx->idmap_ctx, user_dom_sid_str); + + if (ret == EOK) { + *_sid_table = sid_table; +diff --git a/src/tests/cmocka/test_sss_idmap.c b/src/tests/cmocka/test_sss_idmap.c +index 53ed35a97863f8f52b82bec64d6dfb192891b0fe..019b4618ef0e14e87cb86d64989e8f5ca9dfdfd8 100644 +--- a/src/tests/cmocka/test_sss_idmap.c ++++ b/src/tests/cmocka/test_sss_idmap.c +@@ -251,6 +251,7 @@ void test_map_id(void **state) + err = sss_idmap_unix_to_sid(test_ctx->idmap_ctx, id, &sid); + assert_int_equal(err, IDMAP_SUCCESS); + assert_string_equal(sid, TEST_DOM_SID"-0"); ++ sss_idmap_free_sid(test_ctx->idmap_ctx, sid); + + err = sss_idmap_sid_to_unix(test_ctx->idmap_ctx, + TEST_DOM_SID"-"TEST_OFFSET_STR, &id); +@@ -260,6 +261,7 @@ void test_map_id(void **state) + err = sss_idmap_unix_to_sid(test_ctx->idmap_ctx, id, &sid); + assert_int_equal(err, IDMAP_SUCCESS); + assert_string_equal(sid, TEST_DOM_SID"-"TEST_OFFSET_STR); ++ sss_idmap_free_sid(test_ctx->idmap_ctx, sid); + } + + void test_map_id_external(void **state) +diff --git a/src/tests/sss_idmap-tests.c b/src/tests/sss_idmap-tests.c +index 65e61351ddcf52deffe9c8abf38497cd9183c448..b2de0e70f794414587080587af1fd4a06d5ae854 100644 +--- a/src/tests/sss_idmap-tests.c ++++ b/src/tests/sss_idmap-tests.c +@@ -280,7 +280,7 @@ START_TEST(idmap_test_uid2sid) + "sss_idmap_unix_to_sid returned wrong SID, " + "expected [%s], got [%s].", "S-1-5-21-1-2-3-1000", sid); + +- talloc_free(sid); ++ sss_idmap_free_sid(idmap_ctx, sid); + } + END_TEST + +@@ -304,7 +304,7 @@ START_TEST(idmap_test_uid2dom_sid) + "sss_idmap_unix_to_dom_sid returned wrong SID, " + "expected [%s], got [%s].", "S-1-5-21-1-2-3-1000", sid); + +- talloc_free(sid); ++ sss_idmap_free_sid(idmap_ctx, sid); + talloc_free(dom_sid); + } + END_TEST +@@ -330,7 +330,7 @@ START_TEST(idmap_test_uid2bin_sid) + "sss_idmap_unix_to_bin_sid returned wrong SID, " + "expected [%s], got [%s].", "S-1-5-21-1-2-3-1000", sid); + +- talloc_free(sid); ++ sss_idmap_free_sid(idmap_ctx, sid); + talloc_free(bin_sid); + } + END_TEST +@@ -385,7 +385,7 @@ START_TEST(idmap_test_sid2dom_sid) + "SID strings do not match."); + + talloc_free(dom_sid); +- talloc_free(new_sid); ++ sss_idmap_free_sid(idmap_ctx, new_sid); + } + END_TEST + +@@ -418,7 +418,7 @@ START_TEST(idmap_test_large_and_too_large_sid) + "did not return IDMAP_SID_INVALID"); + + talloc_free(dom_sid); +- talloc_free(new_sid); ++ sss_idmap_free_sid(idmap_ctx, new_sid); + } + END_TEST + +@@ -454,7 +454,7 @@ START_TEST(idmap_test_bin_sid2sid) + "expected [%s], get [%s]", + test_sid, sid); + +- talloc_free(sid); ++ sss_idmap_free_sid(idmap_ctx, sid); + } + END_TEST + +@@ -528,7 +528,7 @@ START_TEST(idmap_test_smb_sid2sid) + "expected [%s], get [%s]", + test_sid, sid); + +- talloc_free(sid); ++ sss_idmap_free_sid(idmap_ctx, sid); + } + END_TEST + +-- +1.8.4.2 + diff --git a/SOURCES/0020-free-idmapped-dom-SIDs-correctly.patch b/SOURCES/0020-free-idmapped-dom-SIDs-correctly.patch new file mode 100644 index 0000000..8632643 --- /dev/null +++ b/SOURCES/0020-free-idmapped-dom-SIDs-correctly.patch @@ -0,0 +1,72 @@ +From 8894f5214c20e530c15a7481ed0b84e533cef519 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 1 Nov 2013 13:17:17 +0100 +Subject: [PATCH 20/31] free idmapped dom SIDs correctly + +Resolves: +https://fedorahosted.org/sssd/ticket/2133 +--- + src/tests/sss_idmap-tests.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/src/tests/sss_idmap-tests.c b/src/tests/sss_idmap-tests.c +index b2de0e70f794414587080587af1fd4a06d5ae854..c43e326b1f49ac74c387c76e58f2f32efdce40ff 100644 +--- a/src/tests/sss_idmap-tests.c ++++ b/src/tests/sss_idmap-tests.c +@@ -261,7 +261,7 @@ START_TEST(idmap_test_dom_sid2uid) + "sss_idmap_dom_sid_to_unix returned wrong id, " + "got [%d], expected [%d].", id, 1000 + IDMAP_RANGE_MIN); + +- talloc_free(dom_sid); ++ sss_idmap_free_dom_sid(idmap_ctx, dom_sid); + } + END_TEST + +@@ -305,7 +305,7 @@ START_TEST(idmap_test_uid2dom_sid) + "expected [%s], got [%s].", "S-1-5-21-1-2-3-1000", sid); + + sss_idmap_free_sid(idmap_ctx, sid); +- talloc_free(dom_sid); ++ sss_idmap_free_dom_sid(idmap_ctx, dom_sid); + } + END_TEST + +@@ -358,7 +358,7 @@ START_TEST(idmap_test_bin_sid2dom_sid) + fail_unless(memcmp(test_bin_sid, new_bin_sid, test_bin_sid_length) == 0, + "Binary SIDs do not match."); + +- talloc_free(dom_sid); ++ sss_idmap_free_dom_sid(idmap_ctx, dom_sid); + talloc_free(new_bin_sid); + } + END_TEST +@@ -384,7 +384,7 @@ START_TEST(idmap_test_sid2dom_sid) + fail_unless(strcmp("S-1-5-21-1-2-3-1000", new_sid) == 0, + "SID strings do not match."); + +- talloc_free(dom_sid); ++ sss_idmap_free_dom_sid(idmap_ctx, dom_sid); + sss_idmap_free_sid(idmap_ctx, new_sid); + } + END_TEST +@@ -417,7 +417,7 @@ START_TEST(idmap_test_large_and_too_large_sid) + "Trying to convert a SID with a too large component " + "did not return IDMAP_SID_INVALID"); + +- talloc_free(dom_sid); ++ sss_idmap_free_dom_sid(idmap_ctx, dom_sid); + sss_idmap_free_sid(idmap_ctx, new_sid); + } + END_TEST +@@ -475,7 +475,7 @@ START_TEST(idmap_test_smb_sid2dom_sid) + fail_unless(memcmp(&test_smb_sid, new_smb_sid, sizeof(struct dom_sid)) == 0, + "Samba dom_sid-s do not match."); + +- talloc_free(dom_sid); ++ sss_idmap_free_dom_sid(idmap_ctx, dom_sid); + talloc_free(new_smb_sid); + } + END_TEST +-- +1.8.4.2 + diff --git a/SOURCES/0021-free-idmapped-smb-SIDs-correctly.patch b/SOURCES/0021-free-idmapped-smb-SIDs-correctly.patch new file mode 100644 index 0000000..5566418 --- /dev/null +++ b/SOURCES/0021-free-idmapped-smb-SIDs-correctly.patch @@ -0,0 +1,45 @@ +From 6b44bc4465b954183f8a52fbb05da6b63b17f0d1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Mon, 4 Nov 2013 11:59:28 +0100 +Subject: [PATCH 21/31] free idmapped smb SIDs correctly + +Resolves: +https://fedorahosted.org/sssd/ticket/2133 +--- + src/tests/sss_idmap-tests.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/tests/sss_idmap-tests.c b/src/tests/sss_idmap-tests.c +index c43e326b1f49ac74c387c76e58f2f32efdce40ff..888be82248045058093d6943ef73742d8812eac3 100644 +--- a/src/tests/sss_idmap-tests.c ++++ b/src/tests/sss_idmap-tests.c +@@ -476,7 +476,7 @@ START_TEST(idmap_test_smb_sid2dom_sid) + "Samba dom_sid-s do not match."); + + sss_idmap_free_dom_sid(idmap_ctx, dom_sid); +- talloc_free(new_smb_sid); ++ sss_idmap_free_smb_sid(idmap_ctx, new_smb_sid); + } + END_TEST + +@@ -512,7 +512,7 @@ START_TEST(idmap_test_bin_sid2smb_sid) + fail_unless(memcmp(&test_smb_sid, smb_sid, sizeof(struct dom_sid)) == 0, + "Samba dom_sid structs do not match."); + +- talloc_free(smb_sid); ++ sss_idmap_free_smb_sid(idmap_ctx, smb_sid); + } + END_TEST + +@@ -543,7 +543,7 @@ START_TEST(idmap_test_sid2smb_sid) + fail_unless(memcmp(&test_smb_sid, smb_sid, sizeof(struct dom_sid)) == 0, + "Samba dom_sid structs do not match."); + +- talloc_free(smb_sid); ++ sss_idmap_free_smb_sid(idmap_ctx, smb_sid); + } + END_TEST + +-- +1.8.4.2 + diff --git a/SOURCES/0022-free-idmapped-binary-SIDs-correctly.patch b/SOURCES/0022-free-idmapped-binary-SIDs-correctly.patch new file mode 100644 index 0000000..6ad0fd2 --- /dev/null +++ b/SOURCES/0022-free-idmapped-binary-SIDs-correctly.patch @@ -0,0 +1,77 @@ +From ccb2fe6ee1397b3c3d413d6c546cb88701958de3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 7 Nov 2013 11:09:48 +0100 +Subject: [PATCH 22/31] free idmapped binary SIDs correctly + +Resolves: +https://fedorahosted.org/sssd/ticket/2133 +--- + src/responder/nss/nsssrv_cmd.c | 2 +- + src/tests/sss_idmap-tests.c | 10 +++++----- + 2 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c +index 07f31188074bf45664969fb33388edb475e53b96..550017c0e4385a7147ed5ef83da2c37cb97c8092 100644 +--- a/src/responder/nss/nsssrv_cmd.c ++++ b/src/responder/nss/nsssrv_cmd.c +@@ -4341,7 +4341,7 @@ static int nss_cmd_getbysid(enum sss_cli_command cmd, struct cli_ctx *cctx) + /* If the body isn't a SID, fail */ + err = sss_idmap_sid_to_bin_sid(nctx->idmap_ctx, sid_str, + &bin_sid, &bin_sid_length); +- talloc_free(bin_sid); ++ sss_idmap_free_bin_sid(nctx->idmap_ctx, bin_sid); + if (err != IDMAP_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, ("sss_idmap_sid_to_bin_sid failed for [%s].\n", + body)); +diff --git a/src/tests/sss_idmap-tests.c b/src/tests/sss_idmap-tests.c +index 888be82248045058093d6943ef73742d8812eac3..f5ec68383679bfc685467bd625c86b8d6f474d48 100644 +--- a/src/tests/sss_idmap-tests.c ++++ b/src/tests/sss_idmap-tests.c +@@ -242,7 +242,7 @@ START_TEST(idmap_test_bin_sid2uid) + "sss_idmap_bin_sid_to_unix returned wrong id, " + "got [%d], expected [%d].", id, 1000 + IDMAP_RANGE_MIN); + +- talloc_free(bin_sid); ++ sss_idmap_free_bin_sid(idmap_ctx, bin_sid); + } + END_TEST + +@@ -331,7 +331,7 @@ START_TEST(idmap_test_uid2bin_sid) + "expected [%s], got [%s].", "S-1-5-21-1-2-3-1000", sid); + + sss_idmap_free_sid(idmap_ctx, sid); +- talloc_free(bin_sid); ++ sss_idmap_free_bin_sid(idmap_ctx, bin_sid); + } + END_TEST + +@@ -359,7 +359,7 @@ START_TEST(idmap_test_bin_sid2dom_sid) + "Binary SIDs do not match."); + + sss_idmap_free_dom_sid(idmap_ctx, dom_sid); +- talloc_free(new_bin_sid); ++ sss_idmap_free_bin_sid(idmap_ctx, new_bin_sid); + } + END_TEST + +@@ -437,7 +437,7 @@ START_TEST(idmap_test_sid2bin_sid) + fail_unless(memcmp(bin_sid, test_bin_sid, test_bin_sid_length) == 0, + "Binary SIDs do not match"); + +- talloc_free(bin_sid); ++ sss_idmap_free_bin_sid(idmap_ctx, bin_sid); + } + END_TEST + +@@ -496,7 +496,7 @@ START_TEST(idmap_test_smb_sid2bin_sid) + fail_unless(memcmp(bin_sid, test_bin_sid, test_bin_sid_length) == 0, + "Binary SIDs do not match."); + +- talloc_free(bin_sid); ++ sss_idmap_free_bin_sid(idmap_ctx, bin_sid); + } + END_TEST + +-- +1.8.4.2 + diff --git a/SOURCES/0023-Initialize-sid_str-to-NULL-to-avoid-freeing-random-d.patch b/SOURCES/0023-Initialize-sid_str-to-NULL-to-avoid-freeing-random-d.patch new file mode 100644 index 0000000..4839823 --- /dev/null +++ b/SOURCES/0023-Initialize-sid_str-to-NULL-to-avoid-freeing-random-d.patch @@ -0,0 +1,41 @@ +From 456d952eecf2f068feafd2fff8bec8df84eba8ca Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Thu, 7 Nov 2013 12:00:43 +0100 +Subject: [PATCH 23/31] Initialize sid_str to NULL to avoid freeing random data + +If any function before failed, sss_idmap_free_sid() might have been +called with random data. +--- + src/providers/ad/ad_subdomains.c | 2 +- + src/providers/ldap/sdap_async_initgroups_ad.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index dd692fb699ddf14bcf8f9926383e82da77c494e0..100fb13e99f7bf4b3946b1f5c5f9c626674bfb46 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -234,7 +234,7 @@ ad_subdom_store(struct ad_subdomains_ctx *ctx, + errno_t ret; + enum idmap_error_code err; + struct ldb_message_element *el; +- char *sid_str; ++ char *sid_str = NULL; + uint32_t trust_type; + bool mpg; + +diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c +index aa72c8876ba93eefc6230537801c50ab04e591ce..e58d93fb2da36febd6074381882192ba9e204e86 100644 +--- a/src/providers/ldap/sdap_async_initgroups_ad.c ++++ b/src/providers/ldap/sdap_async_initgroups_ad.c +@@ -361,7 +361,7 @@ sdap_get_ad_tokengroups_initgroups_lookup_done(struct tevent_req *subreq) + size_t user_count, group_count, i; + TALLOC_CTX *tmp_ctx; + bool in_transaction = false; +- char *sid_str; ++ char *sid_str = NULL; + gid_t gid; + time_t now; + struct sss_domain_info *group_domain; +-- +1.8.4.2 + diff --git a/SOURCES/0024-ad-refactor-tokengroups-initgroups.patch b/SOURCES/0024-ad-refactor-tokengroups-initgroups.patch new file mode 100644 index 0000000..cd4ad74 --- /dev/null +++ b/SOURCES/0024-ad-refactor-tokengroups-initgroups.patch @@ -0,0 +1,749 @@ +From 8b581624e18d6f232d3174ed112d032bb6deffba Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 12 Nov 2013 13:52:40 +0100 +Subject: [PATCH 24/31] ad: refactor tokengroups initgroups + +sdap_get_ad_tokengroups_initgroups is split into more parts so +it can be reused later. +--- + src/providers/ldap/sdap_async.h | 20 +- + src/providers/ldap/sdap_async_initgroups.c | 16 +- + src/providers/ldap/sdap_async_initgroups_ad.c | 552 ++++++++++++++++---------- + 3 files changed, 357 insertions(+), 231 deletions(-) + +diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h +index dbf572cdc82b100ba9c26b4853f05db1ba5fa4ed..67623454e675f648259c089acca59258f386ecdb 100644 +--- a/src/providers/ldap/sdap_async.h ++++ b/src/providers/ldap/sdap_async.h +@@ -294,17 +294,17 @@ sdap_get_ad_match_rule_initgroups_recv(struct tevent_req *req); + + + struct tevent_req * +-sdap_get_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx, +- struct tevent_context *ev, +- struct sdap_options *opts, +- struct sysdb_ctx *sysdb, +- struct sss_domain_info *domain, +- struct sdap_handle *sh, +- const char *name, +- const char *orig_dn, +- int timeout); ++sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct sdap_options *opts, ++ struct sysdb_ctx *sysdb, ++ struct sss_domain_info *domain, ++ struct sdap_handle *sh, ++ const char *name, ++ const char *orig_dn, ++ int timeout); + + errno_t +-sdap_get_ad_tokengroups_initgroups_recv(struct tevent_req *req); ++sdap_ad_tokengroups_initgroups_recv(struct tevent_req *req); + + #endif /* _SDAP_ASYNC_H_ */ +diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c +index c16d484950e06c8474cc38db45b978b624473056..7d5cd2e7cbd86e2eb9774dfee1b8e31edec57b88 100644 +--- a/src/providers/ldap/sdap_async_initgroups.c ++++ b/src/providers/ldap/sdap_async_initgroups.c +@@ -2857,13 +2857,13 @@ static void sdap_get_initgr_user(struct tevent_req *subreq) + /* Take advantage of AD's tokenGroups mechanism to look up all + * parent groups in a single request. + */ +- subreq = sdap_get_ad_tokengroups_initgroups_send(state, state->ev, +- state->opts, +- state->sysdb, +- state->dom, +- state->sh, +- cname, orig_dn, +- state->timeout); ++ subreq = sdap_ad_tokengroups_initgroups_send(state, state->ev, ++ state->opts, ++ state->sysdb, ++ state->dom, ++ state->sh, ++ cname, orig_dn, ++ state->timeout); + } else if (state->opts->support_matching_rule + && dp_opt_get_bool(state->opts->basic, + SDAP_AD_MATCHING_RULE_INITGROUPS)) { +@@ -2952,7 +2952,7 @@ static void sdap_get_initgr_done(struct tevent_req *subreq) + case SDAP_SCHEMA_AD: + if (state->use_id_mapping + && state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2008) { +- ret = sdap_get_ad_tokengroups_initgroups_recv(subreq); ++ ret = sdap_ad_tokengroups_initgroups_recv(subreq); + } + else if (state->opts->support_matching_rule + && dp_opt_get_bool(state->opts->basic, +diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c +index e58d93fb2da36febd6074381882192ba9e204e86..7ba155338a358681c1bd201bee1c75f67afb4650 100644 +--- a/src/providers/ldap/sdap_async_initgroups_ad.c ++++ b/src/providers/ldap/sdap_async_initgroups_ad.c +@@ -298,96 +298,87 @@ sdap_get_ad_match_rule_initgroups_recv(struct tevent_req *req) + return EOK; + } + +-struct sdap_ad_tokengroups_initgr_state { ++struct sdap_get_ad_tokengroups_state { + struct tevent_context *ev; +- struct sdap_options *opts; +- struct sysdb_ctx *sysdb; +- struct sss_domain_info *domain; +- struct sdap_handle *sh; ++ struct sss_idmap_ctx *idmap_ctx; + const char *username; ++ ++ char **sids; ++ size_t num_sids; + }; + +-static void +-sdap_get_ad_tokengroups_initgroups_lookup_done(struct tevent_req *req); ++static void sdap_get_ad_tokengroups_done(struct tevent_req *subreq); + +-struct tevent_req * +-sdap_get_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx, +- struct tevent_context *ev, +- struct sdap_options *opts, +- struct sysdb_ctx *sysdb, +- struct sss_domain_info *domain, +- struct sdap_handle *sh, +- const char *name, +- const char *orig_dn, +- int timeout) ++static struct tevent_req * ++sdap_get_ad_tokengroups_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct sdap_options *opts, ++ struct sdap_handle *sh, ++ const char *name, ++ const char *orig_dn, ++ int timeout) + { +- struct tevent_req *req; +- struct tevent_req *subreq; +- struct sdap_ad_tokengroups_initgr_state *state; ++ struct sdap_get_ad_tokengroups_state *state = NULL; ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; + const char *attrs[] = {AD_TOKENGROUPS_ATTR, NULL}; ++ errno_t ret; + + req = tevent_req_create(mem_ctx, &state, +- struct sdap_ad_tokengroups_initgr_state); +- if (!req) return NULL; ++ struct sdap_get_ad_tokengroups_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n")); ++ return NULL; ++ } + ++ state->idmap_ctx = opts->idmap_ctx->map; + state->ev = ev; +- state->opts = opts; +- state->sysdb = sysdb; +- state->domain = domain; +- state->sh = sh; +- state->username = name; ++ state->username = talloc_strdup(state, name); ++ if (state->username == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ subreq = sdap_get_generic_send(state, state->ev, opts, sh, orig_dn, ++ LDAP_SCOPE_BASE, NULL, attrs, ++ NULL, 0, timeout, false); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ tevent_req_set_callback(subreq, sdap_get_ad_tokengroups_done, req); ++ ++ return req; + +- subreq = sdap_get_generic_send( +- state, state->ev, state->opts, state->sh, +- orig_dn, LDAP_SCOPE_BASE, NULL, attrs, +- NULL, 0, timeout, false); +- if (!subreq) { +- tevent_req_error(req, ENOMEM); +- tevent_req_post(req, ev); +- return req; ++immediately: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); + } ++ tevent_req_post(req, ev); + +- tevent_req_set_callback(subreq, +- sdap_get_ad_tokengroups_initgroups_lookup_done, +- req); + return req; + } + +-static void +-sdap_get_ad_tokengroups_initgroups_lookup_done(struct tevent_req *subreq) ++static void sdap_get_ad_tokengroups_done(struct tevent_req *subreq) + { +- errno_t ret, sret; ++ TALLOC_CTX *tmp_ctx = NULL; ++ struct sdap_get_ad_tokengroups_state *state = NULL; ++ struct tevent_req *req = NULL; ++ struct sysdb_attrs **users = NULL; ++ struct ldb_message_element *el = NULL; + enum idmap_error_code err; +- size_t user_count, group_count, i; +- TALLOC_CTX *tmp_ctx; +- bool in_transaction = false; + char *sid_str = NULL; +- gid_t gid; +- time_t now; +- struct sss_domain_info *group_domain; +- struct sysdb_attrs **users; +- struct ldb_message_element *el; +- struct ldb_message *msg; +- struct ldb_dn *group_ldb_dn; +- const char *group_str_dn; +- char **ldap_grouplist; +- char **sysdb_grouplist; +- char **add_groups; +- char **del_groups; +- const char *attrs[] = { SYSDB_NAME, NULL }; +- const char *group_name; +- struct tevent_req *req = +- tevent_req_callback_data(subreq, struct tevent_req); +- struct sdap_ad_tokengroups_initgr_state *state = +- tevent_req_data(req, struct sdap_ad_tokengroups_initgr_state); ++ size_t num_users; ++ size_t i; ++ errno_t ret; + +- tmp_ctx = talloc_new(NULL); +- if (!tmp_ctx) { +- ret = ENOMEM; +- goto done; +- } ++ 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, &user_count, &users); ++ ret = sdap_get_generic_recv(subreq, tmp_ctx, &num_users, &users); + talloc_zfree(subreq); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, +@@ -395,226 +386,361 @@ sdap_get_ad_tokengroups_initgroups_lookup_done(struct tevent_req *subreq) + goto done; + } + +- if (user_count != 1) { ++ if (num_users != 1) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("More than one result on a base search!\n")); + ret = EINVAL; + goto done; + } + +- /* Get the list of group SIDs */ +- ret = sysdb_attrs_get_el_ext(users[0], AD_TOKENGROUPS_ATTR, +- false, &el); +- if (ret != EOK) { +- if (ret == ENOENT) { +- DEBUG(SSSDBG_TRACE_LIBS, +- ("No tokenGroups entries for [%s]\n", +- state->username)); +- /* No groups in LDAP. We need to ensure that the +- * sysdb matches. +- */ +- el = talloc_zero(tmp_ctx, struct ldb_message_element); +- if (!el) { +- ret = ENOMEM; +- goto done; +- } +- el->num_values = 0; ++ /* get the list of sids from tokengroups */ ++ ret = sysdb_attrs_get_el_ext(users[0], AD_TOKENGROUPS_ATTR, false, &el); ++ if (ret == ENOENT) { ++ DEBUG(SSSDBG_TRACE_LIBS, ("No tokenGroups entries for [%s]\n", ++ state->username)); + +- /* This will skip the group-processing loop below +- * and proceed to removing any sysdb groups. +- */ +- } else { +- DEBUG(SSSDBG_MINOR_FAILURE, +- ("Could not read tokenGroups attribute: [%s]\n", +- strerror(ret))); +- goto done; +- } ++ state->sids = NULL; ++ state->num_sids = 0; ++ ret = EOK; ++ goto done; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Could not read tokenGroups attribute: " ++ "[%s]\n", strerror(ret))); ++ goto done; + } + +- /* Process the groups */ +- now = time(NULL); +- +- ret = sysdb_transaction_start(state->sysdb); +- if (ret != EOK) goto done; +- in_transaction = true; +- +- ldap_grouplist = talloc_array(tmp_ctx, char *, el->num_values + 1); +- if (!ldap_grouplist) { ++ state->num_sids = 0; ++ state->sids = talloc_zero_array(state, char*, el->num_values); ++ if (state->sids == NULL) { + ret = ENOMEM; + goto done; + } +- group_count = 0; + ++ /* convert binary sid to string */ + for (i = 0; i < el->num_values; i++) { +- /* Get the SID and convert it to a GID */ +- +- err = sss_idmap_bin_sid_to_sid(state->opts->idmap_ctx->map, +- el->values[i].data, +- el->values[i].length, +- &sid_str); ++ err = sss_idmap_bin_sid_to_sid(state->idmap_ctx, el->values[i].data, ++ el->values[i].length, &sid_str); + if (err != IDMAP_SUCCESS) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Could not convert binary SID to string: [%s]. Skipping\n", + idmap_error_string(err))); + continue; + } +- DEBUG(SSSDBG_TRACE_LIBS, +- ("Processing membership SID [%s]\n", +- sid_str)); +- ret = sdap_idmap_sid_to_unix(state->opts->idmap_ctx, sid_str, +- &gid); ++ ++ state->sids[i] = talloc_move(state->sids, &sid_str); ++ state->num_sids++; ++ } ++ ++ /* shrink array to final number of elements */ ++ state->sids = talloc_realloc(state, state->sids, char*, state->num_sids); ++ if (state->sids == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++static errno_t sdap_get_ad_tokengroups_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ size_t *_num_sids, ++ char ***_sids) ++{ ++ struct sdap_get_ad_tokengroups_state *state = NULL; ++ state = tevent_req_data(req, struct sdap_get_ad_tokengroups_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ if (_num_sids != NULL) { ++ *_num_sids = state->num_sids; ++ } ++ ++ if (_sids != NULL) { ++ *_sids = talloc_steal(mem_ctx, state->sids); ++ } ++ ++ return EOK; ++} ++ ++static errno_t ++sdap_ad_tokengroups_update_members(TALLOC_CTX *mem_ctx, ++ const char *username, ++ struct sysdb_ctx *sysdb, ++ struct sss_domain_info *domain, ++ char **ldap_groups) ++{ ++ TALLOC_CTX *tmp_ctx = NULL; ++ char **sysdb_groups = NULL; ++ char **add_groups = NULL; ++ char **del_groups = NULL; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); ++ return ENOMEM; ++ } ++ ++ /* Get the current sysdb group list for this user so we can update it. */ ++ ret = get_sysdb_grouplist_dn(tmp_ctx, sysdb, domain, ++ username, &sysdb_groups); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Could not get the list of groups for " ++ "[%s] in the sysdb: [%s]\n", username, strerror(ret))); ++ goto done; ++ } ++ ++ /* Find the differences between the sysdb and LDAP lists. ++ * Groups in the sysdb only must be removed. */ ++ ret = diff_string_lists(tmp_ctx, ldap_groups, sysdb_groups, ++ &add_groups, &del_groups, NULL); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_LIBS, ("Updating memberships for [%s]\n", username)); ++ ++ ret = sysdb_update_members_dn(domain->sysdb, domain, username, ++ SYSDB_MEMBER_USER, ++ (const char *const *) add_groups, ++ (const char *const *) del_groups); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Membership update failed [%d]: %s\n", ++ ret, strerror(ret))); ++ goto done; ++ } ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++struct sdap_ad_tokengroups_initgroups_state { ++ struct sdap_idmap_ctx *idmap_ctx; ++ struct sysdb_ctx *sysdb; ++ struct sss_domain_info *domain; ++ const char *username; ++}; ++ ++static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq); ++ ++struct tevent_req * ++sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct sdap_options *opts, ++ struct sysdb_ctx *sysdb, ++ struct sss_domain_info *domain, ++ struct sdap_handle *sh, ++ const char *name, ++ const char *orig_dn, ++ int timeout) ++{ ++ struct sdap_ad_tokengroups_initgroups_state *state = NULL; ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct sdap_ad_tokengroups_initgroups_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n")); ++ return NULL; ++ } ++ ++ state->idmap_ctx = opts->idmap_ctx; ++ state->sysdb = sysdb; ++ state->domain = domain; ++ state->username = talloc_strdup(state, name); ++ if (state->username == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ subreq = sdap_get_ad_tokengroups_send(state, ev, opts, sh, name, orig_dn, ++ timeout); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgroups_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 sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq) ++{ ++ TALLOC_CTX *tmp_ctx = NULL; ++ struct sdap_ad_tokengroups_initgroups_state *state = NULL; ++ struct tevent_req *req = NULL; ++ struct sss_domain_info *domain = NULL; ++ struct ldb_message *msg = NULL; ++ const char *attrs[] = {SYSDB_NAME, NULL}; ++ const char *name = NULL; ++ const char *sid = NULL; ++ char **sids = NULL; ++ size_t num_sids; ++ size_t i; ++ time_t now; ++ gid_t gid; ++ char **groups = NULL; ++ size_t num_groups; ++ errno_t ret, sret; ++ bool in_transaction; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct sdap_ad_tokengroups_initgroups_state); ++ ++ ret = sdap_get_ad_tokengroups_recv(state, subreq, &num_sids, &sids); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to acquire tokengroups [%d]: %s\n", ++ ret, strerror(ret))); ++ goto done; ++ } ++ ++ num_groups = 0; ++ groups = talloc_zero_array(tmp_ctx, char*, num_sids + 1); ++ if (groups == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ now = time(NULL); ++ ret = sysdb_transaction_start(state->sysdb); ++ if (ret != EOK) { ++ goto done; ++ } ++ in_transaction = true; ++ ++ for (i = 0; i < num_sids; i++) { ++ sid = sids[i]; ++ DEBUG(SSSDBG_TRACE_LIBS, ("Processing membership SID [%s]\n", sid)); ++ ++ ret = sdap_idmap_sid_to_unix(state->idmap_ctx, sid, &gid); + if (ret == ENOTSUP) { + DEBUG(SSSDBG_TRACE_FUNC, ("Skipping built-in object.\n")); + ret = EOK; + continue; + } else if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, +- ("Could not convert SID to GID: [%s]. Skipping\n", +- strerror(ret))); ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Could not convert SID to GID: [%s]. " ++ "Skipping\n", strerror(ret))); + continue; + } + +- group_domain = find_subdomain_by_sid(get_domains_head(state->domain), +- sid_str); +- if (group_domain == NULL) { +- DEBUG(SSSDBG_MINOR_FAILURE, ("Domain not found for SID %s\n", +- sid_str)); ++ domain = find_subdomain_by_sid(get_domains_head(state->domain), sid); ++ if (domain == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Domain not found for SID %s\n", sid)); + continue; + } + +- DEBUG(SSSDBG_TRACE_LIBS, +- ("Processing membership GID [%"SPRIgid"]\n", gid)); ++ DEBUG(SSSDBG_TRACE_LIBS, ("SID [%s] maps to GID [%"SPRIgid"]\n", ++ sid, gid)); + + /* Check whether this GID already exists in the sysdb */ +- ret = sysdb_search_group_by_gid(tmp_ctx, group_domain->sysdb, +- group_domain, gid, attrs, &msg); ++ ret = sysdb_search_group_by_gid(tmp_ctx, domain->sysdb, domain, ++ gid, attrs, &msg); + if (ret == EOK) { +- group_name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); +- if (!group_name) { ++ name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); ++ if (name == NULL) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Could not retrieve group name from sysdb\n")); + ret = EINVAL; + goto done; + } + } else if (ret == ENOENT) { +- /* This is a new group. For now, we will store it +- * under the name of its SID. When a direct lookup of +- * the group or its GID occurs, it will replace this +- * temporary entry. +- */ +- +- group_name = sid_str; +- ret = sysdb_add_incomplete_group(group_domain->sysdb, +- group_domain, +- group_name, gid, +- NULL, sid_str, false, now); ++ /* This is a new group. For now, we will store it under the name ++ * of its SID. When a direct lookup of the group or its GID occurs, ++ * it will replace this temporary entry. */ ++ name = sid; ++ ret = sysdb_add_incomplete_group(domain->sysdb, domain, name, gid, ++ NULL, sid, false, now); + if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, +- ("Could not create incomplete group: [%s]\n", +- strerror(ret))); ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Could not create incomplete " ++ "group: [%s]\n", strerror(ret))); + goto done; + } + } else { + /* Unexpected error */ +- DEBUG(SSSDBG_MINOR_FAILURE, +- ("Could not look up group in sysdb: [%s]\n", +- strerror(ret))); ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Could not look up group in sysdb: " ++ "[%s]\n", strerror(ret))); + goto done; + } + +- group_ldb_dn = sysdb_group_dn(group_domain->sysdb, tmp_ctx, +- group_domain, group_name); +- if (group_ldb_dn == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, ("sysdb_group_dn() failed\n")); ++ groups[num_groups] = sysdb_group_strdn(tmp_ctx, domain->name, name); ++ if (groups[num_groups] == NULL) { + ret = ENOMEM; + goto done; + } +- +- group_str_dn = ldb_dn_get_linearized(group_ldb_dn); +- if (group_str_dn == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, ("ldb_dn_get_linearized() failed\n")); +- ret = EINVAL; +- goto done; +- } +- +- ldap_grouplist[group_count] = +- talloc_strdup(ldap_grouplist, group_str_dn); +- if (!ldap_grouplist[group_count]) { +- ret = ENOMEM; +- goto done; +- } +- +- talloc_zfree(group_ldb_dn); /* also frees group_str_dn */ +- group_str_dn = NULL; +- +- group_count++; +- } +- ldap_grouplist[group_count] = NULL; +- +- /* Get the current sysdb group list for this user +- * so we can update it. +- */ +- ret = get_sysdb_grouplist_dn(state, state->sysdb, state->domain, +- state->username, &sysdb_grouplist); +- if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, +- ("Could not get the list of groups for [%s] in the sysdb: " +- "[%s]\n", +- state->username, strerror(ret))); +- goto done; ++ num_groups++; + } + +- /* Find the differences between the sysdb and LDAP lists +- * Groups in the sysdb only must be removed. +- */ +- ret = diff_string_lists(tmp_ctx, ldap_grouplist, sysdb_grouplist, +- &add_groups, &del_groups, NULL); +- if (ret != EOK) goto done; ++ groups[num_groups] = NULL; + +- DEBUG(SSSDBG_TRACE_LIBS, +- ("Updating memberships for [%s]\n", state->username)); +- ret = sysdb_update_members_dn(state->sysdb, state->domain, +- state->username, SYSDB_MEMBER_USER, +- (const char *const *) add_groups, +- (const char *const *) del_groups); ++ ret = sdap_ad_tokengroups_update_members(state, state->username, ++ state->sysdb, state->domain, ++ groups); + if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, +- ("Membership update failed [%d]: %s\n", +- ret, strerror(ret))); ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Membership update failed [%d]: %s\n", ++ ret, strerror(ret))); + goto done; + } + + ret = sysdb_transaction_commit(state->sysdb); + if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- ("Could not commit transaction! [%s]\n", +- strerror(ret))); ++ DEBUG(SSSDBG_CRIT_FAILURE, ("Could not commit transaction! [%s]\n", ++ strerror(ret))); + goto done; + } + in_transaction = false; + + done: +- sss_idmap_free_sid(state->opts->idmap_ctx->map, sid_str); ++ talloc_free(tmp_ctx); + + if (in_transaction) { + sret = sysdb_transaction_cancel(state->sysdb); +- DEBUG(SSSDBG_FATAL_FAILURE, +- ("Could not cancel transaction! [%s]\n", +- strerror(sret))); ++ DEBUG(SSSDBG_FATAL_FAILURE, ("Could not cancel transaction! [%s]\n", ++ strerror(sret))); + } + +- if (ret == EOK) { +- tevent_req_done(req); +- } else { ++ if (ret != EOK) { + tevent_req_error(req, ret); ++ return; + } +- talloc_free(tmp_ctx); +- return; ++ ++ tevent_req_done(req); + } + +-errno_t +-sdap_get_ad_tokengroups_initgroups_recv(struct tevent_req *req) ++errno_t sdap_ad_tokengroups_initgroups_recv(struct tevent_req *req) + { + TEVENT_REQ_RETURN_ON_ERROR(req); ++ + return EOK; + } +-- +1.8.4.2 + diff --git a/SOURCES/0025-ad-use-tokengroups-even-when-id-mapping-is-disabled.patch b/SOURCES/0025-ad-use-tokengroups-even-when-id-mapping-is-disabled.patch new file mode 100644 index 0000000..50f54c9 --- /dev/null +++ b/SOURCES/0025-ad-use-tokengroups-even-when-id-mapping-is-disabled.patch @@ -0,0 +1,677 @@ +From 6385798f807d370fe6685653e337f65bf59f21bc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 12 Nov 2013 13:51:34 +0100 +Subject: [PATCH 25/31] ad: use tokengroups even when id mapping is disabled + +https://fedorahosted.org/sssd/ticket/1568 +--- + src/providers/ldap/sdap_async.h | 4 +- + src/providers/ldap/sdap_async_initgroups.c | 10 +- + src/providers/ldap/sdap_async_initgroups_ad.c | 537 +++++++++++++++++++++++++- + 3 files changed, 525 insertions(+), 26 deletions(-) + +diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h +index 67623454e675f648259c089acca59258f386ecdb..f47437553a2d35dac90d86209848e840a237c3fb 100644 +--- a/src/providers/ldap/sdap_async.h ++++ b/src/providers/ldap/sdap_async.h +@@ -296,13 +296,15 @@ sdap_get_ad_match_rule_initgroups_recv(struct tevent_req *req); + struct tevent_req * + sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, ++ struct sdap_id_ctx *id_ctx, + struct sdap_options *opts, + struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + struct sdap_handle *sh, + const char *name, + const char *orig_dn, +- int timeout); ++ int timeout, ++ bool use_id_mapping); + + errno_t + sdap_ad_tokengroups_initgroups_recv(struct tevent_req *req); +diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c +index 7d5cd2e7cbd86e2eb9774dfee1b8e31edec57b88..1b865af0a113222b3c9c11e9401718abad577fd7 100644 +--- a/src/providers/ldap/sdap_async_initgroups.c ++++ b/src/providers/ldap/sdap_async_initgroups.c +@@ -2852,18 +2852,19 @@ static void sdap_get_initgr_user(struct tevent_req *subreq) + return; + } + +- if (state->use_id_mapping +- && state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2008) { ++ if (state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2008) { + /* Take advantage of AD's tokenGroups mechanism to look up all + * parent groups in a single request. + */ + subreq = sdap_ad_tokengroups_initgroups_send(state, state->ev, ++ state->id_ctx, + state->opts, + state->sysdb, + state->dom, + state->sh, + cname, orig_dn, +- state->timeout); ++ state->timeout, ++ state->use_id_mapping); + } else if (state->opts->support_matching_rule + && dp_opt_get_bool(state->opts->basic, + SDAP_AD_MATCHING_RULE_INITGROUPS)) { +@@ -2950,8 +2951,7 @@ static void sdap_get_initgr_done(struct tevent_req *subreq) + + case SDAP_SCHEMA_RFC2307BIS: + case SDAP_SCHEMA_AD: +- if (state->use_id_mapping +- && state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2008) { ++ if (state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2008) { + ret = sdap_ad_tokengroups_initgroups_recv(subreq); + } + else if (state->opts->support_matching_rule +diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c +index 7ba155338a358681c1bd201bee1c75f67afb4650..8e0506831cb189415b62efaa378d3dc7ec350cde 100644 +--- a/src/providers/ldap/sdap_async_initgroups_ad.c ++++ b/src/providers/ldap/sdap_async_initgroups_ad.c +@@ -525,33 +525,180 @@ done: + return ret; + } + +-struct sdap_ad_tokengroups_initgroups_state { ++struct sdap_ad_resolve_sids_state { ++ struct tevent_context *ev; ++ struct sdap_id_ctx *id_ctx; ++ struct sdap_options *opts; ++ struct sss_domain_info *domain; ++ char **sids; ++ ++ const char *current_sid; ++ int index; ++}; ++ ++static errno_t sdap_ad_resolve_sids_step(struct tevent_req *req); ++static void sdap_ad_resolve_sids_done(struct tevent_req *subreq); ++ ++static struct tevent_req * ++sdap_ad_resolve_sids_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct sdap_id_ctx *id_ctx, ++ struct sdap_options *opts, ++ struct sss_domain_info *domain, ++ char **sids) ++{ ++ struct sdap_ad_resolve_sids_state *state = NULL; ++ struct tevent_req *req = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct sdap_ad_resolve_sids_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n")); ++ return NULL; ++ } ++ ++ state->ev = ev; ++ state->id_ctx = id_ctx; ++ state->opts = opts; ++ state->domain = get_domains_head(domain); ++ state->sids = sids; ++ state->index = 0; ++ ++ if (state->sids == NULL) { ++ ret = EOK; ++ goto immediately; ++ } ++ ++ ret = sdap_ad_resolve_sids_step(req); ++ if (ret != EAGAIN) { ++ goto immediately; ++ } ++ ++ return req; ++ ++immediately: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ ++ return req; ++} ++ ++static errno_t sdap_ad_resolve_sids_step(struct tevent_req *req) ++{ ++ struct sdap_ad_resolve_sids_state *state = NULL; ++ struct tevent_req *subreq = NULL; ++ struct sdap_domain *sdap_domain = NULL; ++ struct sss_domain_info *domain = NULL; ++ ++ state = tevent_req_data(req, struct sdap_ad_resolve_sids_state); ++ ++ do { ++ state->current_sid = state->sids[state->index]; ++ if (state->current_sid == NULL) { ++ return EOK; ++ } ++ state->index++; ++ ++ domain = find_subdomain_by_sid(state->domain, state->current_sid); ++ if (domain == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("SID %s does not belong to any known " ++ "domain\n", state->current_sid)); ++ } ++ } while (domain == NULL); ++ ++ sdap_domain = sdap_domain_get(state->opts, domain); ++ if (sdap_domain == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("SDAP domain does not exist?\n")); ++ return ERR_INTERNAL; ++ } ++ ++ subreq = groups_get_send(state, state->ev, state->id_ctx, sdap_domain, ++ state->id_ctx->conn, state->current_sid, ++ BE_FILTER_SECID, BE_ATTR_CORE, false); ++ if (subreq == NULL) { ++ return ENOMEM; ++ } ++ ++ tevent_req_set_callback(subreq, sdap_ad_resolve_sids_done, req); ++ ++ return EAGAIN; ++} ++ ++static void sdap_ad_resolve_sids_done(struct tevent_req *subreq) ++{ ++ struct sdap_ad_resolve_sids_state *state = NULL; ++ struct tevent_req *req = NULL; ++ int dp_error; ++ int sdap_error; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct sdap_ad_resolve_sids_state); ++ ++ ret = groups_get_recv(subreq, &dp_error, &sdap_error); ++ talloc_zfree(subreq); ++ if (ret != EOK || sdap_error != EOK || dp_error != DP_ERR_OK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to resolve SID %s [dp_error: %d, " ++ "sdap_error: %d, ret: %d]: %s\n", state->current_sid, dp_error, ++ sdap_error, ret, strerror(ret))); ++ goto done; ++ } ++ ++ ret = sdap_ad_resolve_sids_step(req); ++ if (ret == EAGAIN) { ++ /* continue with next SID */ ++ return; ++ } ++ ++done: ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++static errno_t sdap_ad_resolve_sids_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ return EOK; ++} ++ ++ ++struct sdap_ad_tokengroups_initgr_mapping_state { + struct sdap_idmap_ctx *idmap_ctx; + struct sysdb_ctx *sysdb; + struct sss_domain_info *domain; + const char *username; + }; + +-static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq); ++static void sdap_ad_tokengroups_initgr_mapping_done(struct tevent_req *subreq); + +-struct tevent_req * +-sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx, +- struct tevent_context *ev, +- struct sdap_options *opts, +- struct sysdb_ctx *sysdb, +- struct sss_domain_info *domain, +- struct sdap_handle *sh, +- const char *name, +- const char *orig_dn, +- int timeout) ++static struct tevent_req * ++sdap_ad_tokengroups_initgr_mapping_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct sdap_options *opts, ++ struct sysdb_ctx *sysdb, ++ struct sss_domain_info *domain, ++ struct sdap_handle *sh, ++ const char *name, ++ const char *orig_dn, ++ int timeout) + { +- struct sdap_ad_tokengroups_initgroups_state *state = NULL; ++ struct sdap_ad_tokengroups_initgr_mapping_state *state = NULL; + struct tevent_req *req = NULL; + struct tevent_req *subreq = NULL; + errno_t ret; + + req = tevent_req_create(mem_ctx, &state, +- struct sdap_ad_tokengroups_initgroups_state); ++ struct sdap_ad_tokengroups_initgr_mapping_state); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n")); + return NULL; +@@ -573,7 +720,8 @@ sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx, + goto immediately; + } + +- tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgroups_done, req); ++ tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgr_mapping_done, ++ req); + + return req; + +@@ -588,10 +736,10 @@ immediately: + return req; + } + +-static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq) ++static void sdap_ad_tokengroups_initgr_mapping_done(struct tevent_req *subreq) + { + TALLOC_CTX *tmp_ctx = NULL; +- struct sdap_ad_tokengroups_initgroups_state *state = NULL; ++ struct sdap_ad_tokengroups_initgr_mapping_state *state = NULL; + struct tevent_req *req = NULL; + struct sss_domain_info *domain = NULL; + struct ldb_message *msg = NULL; +@@ -599,14 +747,14 @@ static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq) + const char *name = NULL; + const char *sid = NULL; + char **sids = NULL; +- size_t num_sids; ++ size_t num_sids = 0; + size_t i; + time_t now; + gid_t gid; + char **groups = NULL; + size_t num_groups; + errno_t ret, sret; +- bool in_transaction; ++ bool in_transaction = false; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { +@@ -616,7 +764,7 @@ static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq) + } + + req = tevent_req_callback_data(subreq, struct tevent_req); +- state = tevent_req_data(req, struct sdap_ad_tokengroups_initgroups_state); ++ state = tevent_req_data(req, struct sdap_ad_tokengroups_initgr_mapping_state); + + ret = sdap_get_ad_tokengroups_recv(state, subreq, &num_sids, &sids); + talloc_zfree(subreq); +@@ -738,6 +886,355 @@ done: + tevent_req_done(req); + } + ++static int sdap_ad_tokengroups_initgr_mapping_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ return EOK; ++} ++ ++struct sdap_ad_tokengroups_initgr_posix_state { ++ struct tevent_context *ev; ++ struct sdap_id_ctx *id_ctx; ++ struct sdap_options *opts; ++ struct sysdb_ctx *sysdb; ++ struct sss_domain_info *domain; ++ const char *username; ++}; ++ ++static void ++sdap_ad_tokengroups_initgr_posix_tg_done(struct tevent_req *subreq); ++ ++static void ++sdap_ad_tokengroups_initgr_posix_sids_done(struct tevent_req *subreq); ++ ++static struct tevent_req * ++sdap_ad_tokengroups_initgr_posix_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct sdap_id_ctx *id_ctx, ++ struct sdap_options *opts, ++ struct sysdb_ctx *sysdb, ++ struct sss_domain_info *domain, ++ struct sdap_handle *sh, ++ const char *name, ++ const char *orig_dn, ++ int timeout) ++{ ++ struct sdap_ad_tokengroups_initgr_posix_state *state = NULL; ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct sdap_ad_tokengroups_initgr_posix_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n")); ++ return NULL; ++ } ++ ++ state->ev = ev; ++ state->id_ctx = id_ctx; ++ state->opts = opts; ++ state->sysdb = sysdb; ++ state->domain = domain; ++ state->username = talloc_strdup(state, name); ++ if (state->username == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ subreq = sdap_get_ad_tokengroups_send(state, ev, opts, sh, name, orig_dn, ++ timeout); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgr_posix_tg_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 ++sdap_ad_tokengroups_initgr_posix_tg_done(struct tevent_req *subreq) ++{ ++ TALLOC_CTX *tmp_ctx = NULL; ++ struct sdap_ad_tokengroups_initgr_posix_state *state = NULL; ++ struct tevent_req *req = NULL; ++ struct sss_domain_info *domain = NULL; ++ struct ldb_message *msg = NULL; ++ const char *attrs[] = {SYSDB_NAME, SYSDB_POSIX, NULL}; ++ const char *is_posix = NULL; ++ const char *name = NULL; ++ char *sid = NULL; ++ char **sids = NULL; ++ size_t num_sids = 0; ++ char **valid_groups = NULL; ++ size_t num_valid_groups; ++ char **missing_sids = NULL; ++ size_t num_missing_sids; ++ size_t i; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, ++ struct sdap_ad_tokengroups_initgr_posix_state); ++ ++ ret = sdap_get_ad_tokengroups_recv(state, subreq, &num_sids, &sids); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to acquire tokengroups [%d]: %s\n", ++ ret, strerror(ret))); ++ goto done; ++ } ++ ++ num_valid_groups = 0; ++ valid_groups = talloc_zero_array(tmp_ctx, char*, num_sids + 1); ++ if (valid_groups == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ num_missing_sids = 0; ++ missing_sids = talloc_zero_array(tmp_ctx, char*, num_sids + 1); ++ if (missing_sids == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ /* For each SID check if it is already present in the cache. If yes, we ++ * will get name of the group and update the membership. Otherwise we need ++ * to remember the SID and download missing groups one by one. */ ++ for (i = 0; i < num_sids; i++) { ++ sid = sids[i]; ++ DEBUG(SSSDBG_TRACE_LIBS, ("Processing membership SID [%s]\n", sid)); ++ ++ domain = find_subdomain_by_sid(get_domains_head(state->domain), sid); ++ if (domain == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Domain not found for SID %s\n", sid)); ++ continue; ++ } ++ ++ ret = sysdb_search_group_by_sid_str(tmp_ctx, domain->sysdb, domain, ++ sid, attrs, &msg); ++ if (ret == EOK) { ++ is_posix = ldb_msg_find_attr_as_string(msg, SYSDB_POSIX, NULL); ++ if (is_posix != NULL && strcmp(is_posix, "FALSE") == 0) { ++ /* skip non-posix group */ ++ continue; ++ } ++ ++ /* we will update membership of this group */ ++ name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); ++ if (name == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ ("Could not retrieve group name from sysdb\n")); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ valid_groups[num_valid_groups] = sysdb_group_strdn(tmp_ctx, ++ domain->name, ++ name); ++ if (valid_groups[num_valid_groups] == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ num_valid_groups++; ++ } else if (ret == ENOENT) { ++ /* we need to download this group */ ++ missing_sids[num_missing_sids] = talloc_steal(missing_sids, sid); ++ num_missing_sids++; ++ ++ DEBUG(SSSDBG_TRACE_FUNC, ("Missing SID %s will be downloaded\n", ++ sid)); ++ } else { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Could not look up group in sysdb: " ++ "[%s]\n", strerror(ret))); ++ goto done; ++ } ++ } ++ ++ valid_groups[num_valid_groups] = NULL; ++ missing_sids[num_missing_sids] = NULL; ++ ++ /* update membership of existing groups */ ++ ret = sdap_ad_tokengroups_update_members(state, state->username, ++ state->sysdb, state->domain, ++ valid_groups); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Membership update failed [%d]: %s\n", ++ ret, strerror(ret))); ++ goto done; ++ } ++ ++ /* download missing SIDs */ ++ missing_sids = talloc_steal(state, missing_sids); ++ subreq = sdap_ad_resolve_sids_send(state, state->ev, state->id_ctx, ++ state->opts, state->domain, ++ missing_sids); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgr_posix_sids_done, ++ req); ++ ++ return; ++ ++done: ++ talloc_free(tmp_ctx); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++static void ++sdap_ad_tokengroups_initgr_posix_sids_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = NULL; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ ++ ret = sdap_ad_resolve_sids_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to resolve missing SIDs " ++ "[%d]: %s\n", ret, strerror(ret))); ++ goto done; ++ } ++ ++done: ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++static errno_t sdap_ad_tokengroups_initgr_posix_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ return EOK; ++} ++ ++struct sdap_ad_tokengroups_initgroups_state { ++ bool use_id_mapping; ++}; ++ ++static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq); ++ ++struct tevent_req * ++sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct sdap_id_ctx *id_ctx, ++ struct sdap_options *opts, ++ struct sysdb_ctx *sysdb, ++ struct sss_domain_info *domain, ++ struct sdap_handle *sh, ++ const char *name, ++ const char *orig_dn, ++ int timeout, ++ bool use_id_mapping) ++{ ++ struct sdap_ad_tokengroups_initgroups_state *state = NULL; ++ struct tevent_req *req = NULL; ++ struct tevent_req *subreq = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct sdap_ad_tokengroups_initgroups_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n")); ++ return NULL; ++ } ++ ++ state->use_id_mapping = use_id_mapping; ++ ++ if (state->use_id_mapping) { ++ subreq = sdap_ad_tokengroups_initgr_mapping_send(state, ev, opts, ++ sysdb, domain, sh, ++ name, orig_dn, ++ timeout); ++ } else { ++ subreq = sdap_ad_tokengroups_initgr_posix_send(state, ev, id_ctx, opts, ++ sysdb, domain, sh, ++ name, orig_dn, ++ timeout); ++ } ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgroups_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 sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq) ++{ ++ struct sdap_ad_tokengroups_initgroups_state *state = NULL; ++ struct tevent_req *req = NULL; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct sdap_ad_tokengroups_initgroups_state); ++ ++ if (state->use_id_mapping) { ++ ret = sdap_ad_tokengroups_initgr_mapping_recv(subreq); ++ } else { ++ ret = sdap_ad_tokengroups_initgr_posix_recv(subreq); ++ } ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++done: ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ + errno_t sdap_ad_tokengroups_initgroups_recv(struct tevent_req *req) + { + TEVENT_REQ_RETURN_ON_ERROR(req); +-- +1.8.4.2 + diff --git a/SOURCES/0026-AD-filter-domain-local-groups-for-trusted-sub-domain.patch b/SOURCES/0026-AD-filter-domain-local-groups-for-trusted-sub-domain.patch new file mode 100644 index 0000000..a0be4bd --- /dev/null +++ b/SOURCES/0026-AD-filter-domain-local-groups-for-trusted-sub-domain.patch @@ -0,0 +1,309 @@ +From 8d55e0fffd29184d44cb49eaab2ca3a4226e0123 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 10 Dec 2013 10:14:28 +0100 +Subject: [PATCH 26/31] AD: filter domain local groups for trusted/sub domains + +In Active Directory groups with a domain local scope should only be used +inside of the specific domain. Since SSSD read the group memberships +from LDAP server of the user's domain the domain local groups are +included in the LDAP result. Those groups should be filtered out if the +domain is a sub/trusted domain, i.e. is not the domain the client +running SSSD is joined to. + +The groups will still be in the cache but marked as non-POSIX groups and +no GID will be assigned. + +Fixes https://fedorahosted.org/sssd/ticket/2178 +--- + src/providers/ldap/sdap.h | 8 ++ + src/providers/ldap/sdap_async_groups.c | 160 ++++++++++++++++---------- + src/providers/ldap/sdap_async_initgroups_ad.c | 6 +- + src/providers/ldap/sdap_async_nested_groups.c | 28 ++++- + 4 files changed, 138 insertions(+), 64 deletions(-) + +diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h +index fa641730bb78b6a96c0b9640af7612b876f56533..a7ea94eb810a96b61862bd8cc6fcd800c3e8e0cb 100644 +--- a/src/providers/ldap/sdap.h ++++ b/src/providers/ldap/sdap.h +@@ -137,6 +137,14 @@ struct sdap_ppolicy_data { + #define SDAP_AD_USN "uSNChanged" + #define SDAP_AD_LAST_USN "highestCommittedUSN" + ++#define SDAP_AD_GROUP_TYPE_BUILTIN 0x00000001 ++#define SDAP_AD_GROUP_TYPE_GLOBAL 0x00000002 ++#define SDAP_AD_GROUP_TYPE_DOMAIN_LOCAL 0x00000004 ++#define SDAP_AD_GROUP_TYPE_UNIVERSAL 0x00000008 ++#define SDAP_AD_GROUP_TYPE_APP_BASIC 0x00000010 ++#define SDAP_AD_GROUP_TYPE_APP_QUERY 0x00000020 ++#define SDAP_AD_GROUP_TYPE_SECURITY 0x80000000 ++ + enum sdap_basic_opt { + SDAP_URI = 0, + SDAP_BACKUP_URI, +diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c +index 9f7e3e55d0234e9aa7b9e59456044587bcad88ef..33648c5da367c908d085a71a9a9017cb294bb300 100644 +--- a/src/providers/ldap/sdap_async_groups.c ++++ b/src/providers/ldap/sdap_async_groups.c +@@ -451,6 +451,7 @@ static int sdap_save_group(TALLOC_CTX *memctx, + bool posix_group; + bool use_id_mapping; + char *sid_str; ++ int32_t ad_group_type; + + tmpctx = talloc_new(NULL); + if (!tmpctx) { +@@ -503,74 +504,113 @@ static int sdap_save_group(TALLOC_CTX *memctx, + } + DEBUG(SSSDBG_TRACE_FUNC, ("Processing group %s\n", group_name)); + +- use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(opts->idmap_ctx, +- dom->name, +- sid_str); +- if (use_id_mapping) { +- posix_group = true; +- +- if (sid_str == NULL) { +- DEBUG(SSSDBG_MINOR_FAILURE, ("SID not available, cannot map a " \ +- "unix ID to group [%s].\n", group_name)); +- ret = ENOENT; ++ posix_group = true; ++ if (opts->schema_type == SDAP_SCHEMA_AD) { ++ ret = sysdb_attrs_get_int32_t(attrs, SYSDB_GROUP_TYPE, &ad_group_type); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_int32_t failed.\n")); + goto done; + } + +- DEBUG(SSSDBG_TRACE_LIBS, +- ("Mapping group [%s] objectSID [%s] to unix ID\n", +- group_name, sid_str)); +- +- /* Convert the SID into a UNIX group ID */ +- ret = sdap_idmap_sid_to_unix(opts->idmap_ctx, sid_str, &gid); +- if (ret == ENOTSUP) { +- /* ENOTSUP is returned if built-in SID was provided +- * => do not store the group, but return EOK */ +- DEBUG(SSSDBG_TRACE_FUNC, ("Skipping built-in object.\n")); +- ret = EOK; +- goto done; +- } else if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, +- ("Could not convert SID string: [%s]\n", +- strerror(ret))); +- goto done; ++ DEBUG(SSSDBG_TRACE_ALL, ("AD group [%s] has type flags %#x.", ++ group_name, ad_group_type)); ++ /* Only security groups from AD are considered for POSIX groups. ++ * Additionally only global and universal group are taken to account ++ * for trusted domains. */ ++ if (!(ad_group_type & SDAP_AD_GROUP_TYPE_SECURITY) ++ || (IS_SUBDOMAIN(dom) ++ && (!((ad_group_type & SDAP_AD_GROUP_TYPE_GLOBAL) ++ || (ad_group_type & SDAP_AD_GROUP_TYPE_UNIVERSAL))))) { ++ posix_group = false; ++ gid = 0; ++ DEBUG(SSSDBG_TRACE_FUNC, ("Filtering AD group [%s].\n", ++ group_name)); ++ ret = sysdb_attrs_add_uint32(group_attrs, ++ opts->group_map[SDAP_AT_GROUP_GID].sys_name, 0); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ ("Failed to add a GID to non-posix group!\n")); ++ return ret; ++ } ++ ret = sysdb_attrs_add_bool(group_attrs, SYSDB_POSIX, false); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("Error: Failed to mark group as non-posix!\n")); ++ return ret; ++ } + } ++ } + +- /* Store the GID in the ldap_attrs so it doesn't get +- * treated as a missing attribute from LDAP and removed. +- */ +- ret = sdap_replace_id(attrs, SYSDB_GIDNUM, gid); +- if (ret) { +- DEBUG(SSSDBG_OP_FAILURE, ("Cannot set the id-mapped GID\n")); +- goto done; +- } +- } else { +- ret = sysdb_attrs_get_bool(attrs, SYSDB_POSIX, &posix_group); +- if (ret == ENOENT) { ++ if (posix_group) { ++ use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(opts->idmap_ctx, ++ dom->name, ++ sid_str); ++ if (use_id_mapping) { + posix_group = true; +- } else if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, +- ("Error reading posix attribute: [%s]\n", +- strerror(ret))); +- goto done; +- } + +- DEBUG(8, ("This is%s a posix group\n", (posix_group)?"":" not")); +- ret = sysdb_attrs_add_bool(group_attrs, SYSDB_POSIX, posix_group); +- if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, +- ("Error setting posix attribute: [%s]\n", +- strerror(ret))); +- goto done; +- } ++ if (sid_str == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("SID not available, cannot map a " \ ++ "unix ID to group [%s].\n", group_name)); ++ ret = ENOENT; ++ goto done; ++ } + +- ret = sysdb_attrs_get_uint32_t(attrs, +- opts->group_map[SDAP_AT_GROUP_GID].sys_name, +- &gid); +- if (ret != EOK) { +- DEBUG(1, ("no gid provided for [%s] in domain [%s].\n", +- group_name, dom->name)); +- ret = EINVAL; +- goto done; ++ DEBUG(SSSDBG_TRACE_LIBS, ++ ("Mapping group [%s] objectSID [%s] to unix ID\n", ++ group_name, sid_str)); ++ ++ /* Convert the SID into a UNIX group ID */ ++ ret = sdap_idmap_sid_to_unix(opts->idmap_ctx, sid_str, &gid); ++ if (ret == ENOTSUP) { ++ /* ENOTSUP is returned if built-in SID was provided ++ * => do not store the group, but return EOK */ ++ DEBUG(SSSDBG_TRACE_FUNC, ("Skipping built-in object.\n")); ++ ret = EOK; ++ goto done; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ ("Could not convert SID string: [%s]\n", ++ strerror(ret))); ++ goto done; ++ } ++ ++ /* Store the GID in the ldap_attrs so it doesn't get ++ * treated as a missing attribute from LDAP and removed. ++ */ ++ ret = sdap_replace_id(attrs, SYSDB_GIDNUM, gid); ++ if (ret) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Cannot set the id-mapped GID\n")); ++ goto done; ++ } ++ } else { ++ ret = sysdb_attrs_get_bool(attrs, SYSDB_POSIX, &posix_group); ++ if (ret == ENOENT) { ++ posix_group = true; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ ("Error reading posix attribute: [%s]\n", ++ strerror(ret))); ++ goto done; ++ } ++ ++ DEBUG(8, ("This is%s a posix group\n", (posix_group)?"":" not")); ++ ret = sysdb_attrs_add_bool(group_attrs, SYSDB_POSIX, posix_group); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ ("Error setting posix attribute: [%s]\n", ++ strerror(ret))); ++ goto done; ++ } ++ ++ ret = sysdb_attrs_get_uint32_t(attrs, ++ opts->group_map[SDAP_AT_GROUP_GID].sys_name, ++ &gid); ++ if (ret != EOK) { ++ DEBUG(1, ("no gid provided for [%s] in domain [%s].\n", ++ group_name, dom->name)); ++ ret = EINVAL; ++ goto done; ++ } + } + } + +diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c +index 8e0506831cb189415b62efaa378d3dc7ec350cde..f1bf77e8614c30b214118140e380c23c40c1195b 100644 +--- a/src/providers/ldap/sdap_async_initgroups_ad.c ++++ b/src/providers/ldap/sdap_async_initgroups_ad.c +@@ -1145,6 +1145,7 @@ static errno_t sdap_ad_tokengroups_initgr_posix_recv(struct tevent_req *req) + + struct sdap_ad_tokengroups_initgroups_state { + bool use_id_mapping; ++ struct sss_domain_info *domain; + }; + + static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq); +@@ -1175,8 +1176,9 @@ sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx, + } + + state->use_id_mapping = use_id_mapping; ++ state->domain = domain; + +- if (state->use_id_mapping) { ++ if (state->use_id_mapping && !IS_SUBDOMAIN(state->domain)) { + subreq = sdap_ad_tokengroups_initgr_mapping_send(state, ev, opts, + sysdb, domain, sh, + name, orig_dn, +@@ -1216,7 +1218,7 @@ static void sdap_ad_tokengroups_initgroups_done(struct tevent_req *subreq) + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_ad_tokengroups_initgroups_state); + +- if (state->use_id_mapping) { ++ if (state->use_id_mapping && !IS_SUBDOMAIN(state->domain)) { + ret = sdap_ad_tokengroups_initgr_mapping_recv(subreq); + } else { + ret = sdap_ad_tokengroups_initgr_posix_recv(subreq); +diff --git a/src/providers/ldap/sdap_async_nested_groups.c b/src/providers/ldap/sdap_async_nested_groups.c +index c107b700b84b8c178051fd4505f3947be8373de2..f58564aec0628c827672950f767401ee32051b59 100644 +--- a/src/providers/ldap/sdap_async_nested_groups.c ++++ b/src/providers/ldap/sdap_async_nested_groups.c +@@ -239,15 +239,39 @@ sdap_nested_group_hash_group(struct sdap_nested_group_ctx *group_ctx, + struct sdap_attr_map *map = group_ctx->opts->group_map; + gid_t gid; + errno_t ret; ++ int32_t ad_group_type; ++ bool posix_group = true; ++ ++ if (group_ctx->opts->schema_type == SDAP_SCHEMA_AD) { ++ ret = sysdb_attrs_get_int32_t(group, SYSDB_GROUP_TYPE, &ad_group_type); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_int32_t failed.\n")); ++ return ret; ++ } ++ ++ DEBUG(SSSDBG_TRACE_ALL, ("AD group has type flags %#x.\n", ++ ad_group_type)); ++ /* Only security groups from AD are considered for POSIX groups. ++ * Additionally only global and universal group are taken to account ++ * for trusted domains. */ ++ if (!(ad_group_type & SDAP_AD_GROUP_TYPE_SECURITY) ++ || (IS_SUBDOMAIN(group_ctx->domain) ++ && (!((ad_group_type & SDAP_AD_GROUP_TYPE_GLOBAL) ++ || (ad_group_type & SDAP_AD_GROUP_TYPE_UNIVERSAL))))) { ++ posix_group = false; ++ gid = 0; ++ DEBUG(SSSDBG_TRACE_FUNC, ("Filtering AD group.\n")); ++ } ++ } + + ret = sysdb_attrs_get_uint32_t(group, map[SDAP_AT_GROUP_GID].sys_name, + &gid); +- if (ret == ENOENT || (ret == EOK && gid == 0)) { ++ if (ret == ENOENT || (ret == EOK && gid == 0) || !posix_group) { + DEBUG(SSSDBG_TRACE_ALL, + ("The group's gid was %s\n", ret == ENOENT ? "missing" : "zero")); + DEBUG(SSSDBG_TRACE_INTERNAL, + ("Marking group as non-posix and setting GID=0!\n")); +- if (ret == ENOENT) { ++ if (ret == ENOENT || !posix_group) { + ret = sysdb_attrs_add_uint32(group, + map[SDAP_AT_GROUP_GID].sys_name, 0); + if (ret != EOK) { +-- +1.8.4.2 + diff --git a/SOURCES/0027-AD-cross-domain-membership-fix.patch b/SOURCES/0027-AD-cross-domain-membership-fix.patch new file mode 100644 index 0000000..5f273b4 --- /dev/null +++ b/SOURCES/0027-AD-cross-domain-membership-fix.patch @@ -0,0 +1,639 @@ +From 402af69c0bb7ea8b84e36f3567de6086042cb152 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 18 Dec 2013 13:47:31 +0100 +Subject: [PATCH 27/31] AD: cross-domain membership fix + +A recent patch directed all call related to group membership lookups to +the AD LDAP port to fix an issue related to missing group memberships in +the Global Catalog. As a side-effect it broke cross-domain +group-memberships because those cannot be resolved by the connection to +the LDAP port. + +The patch tires to fix this by restoring the original behaviour in the +top-level lookup calls in the AD provider and switching to the LDAP port +only for the LDAP request which is expected to return the full group +membership. + +Additionally this patch contains a related fix for the tokenGroups with +Posix attributes patch. The original connection, typically a Global +Catalog connection in the AD case is passed down the stack so that the +group lookup after the tokenGroups request can run over the same +connection. +--- + src/providers/ad/ad_id.c | 19 +-- + src/providers/ad/ad_init.c | 2 + + src/providers/ldap/sdap_async.h | 1 + + src/providers/ldap/sdap_async_groups.c | 62 +++++++- + src/providers/ldap/sdap_async_initgroups.c | 50 ++++++- + src/providers/ldap/sdap_async_initgroups_ad.c | 197 ++++++++++++++++++++++---- + 6 files changed, 281 insertions(+), 50 deletions(-) + +diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c +index 19bc65825be21c6419db1e92db642be0a14b97a8..cf71b172dd7c241a9280a7ea72ef2518f66a7435 100644 +--- a/src/providers/ad/ad_id.c ++++ b/src/providers/ad/ad_id.c +@@ -199,6 +199,8 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx, + case BE_REQ_USER: /* user */ + case BE_REQ_BY_SECID: /* by SID */ + case BE_REQ_USER_AND_GROUP: /* get SID */ ++ case BE_REQ_GROUP: /* group */ ++ case BE_REQ_INITGROUPS: /* init groups for user */ + /* Always try GC first */ + clist[0] = ad_ctx->gc_ctx; + if (IS_SUBDOMAIN(dom) == true) { +@@ -215,23 +217,6 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx, + */ + clist[1] = ad_ctx->ldap_ctx; + break; +- +- case BE_REQ_GROUP: /* group */ +- case BE_REQ_INITGROUPS: /* init groups for user */ +- if (IS_SUBDOMAIN(dom)) { +- sdom = sdap_domain_get(ad_ctx->sdap_id_ctx->opts, dom); +- if (sdom == NULL || sdom->pvt == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, ("No ID ctx available for [%s].\n", +- dom->name)); +- return NULL; +- } +- subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx); +- clist[0] = subdom_id_ctx->ldap_ctx; +- } else { +- clist[0] = ad_ctx->ldap_ctx; +- } +- break; +- + default: + clist[0] = ad_ctx->ldap_ctx; + break; +diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c +index d06efbd082bd6bba74fb6616c7dd722c99244988..332bfda3801db3824ce1896d37e65e2c3a6b8b8b 100644 +--- a/src/providers/ad/ad_init.c ++++ b/src/providers/ad/ad_init.c +@@ -214,6 +214,8 @@ sssm_ad_id_init(struct be_ctx *bectx, + goto done; + } + ++ ad_ctx->sdap_id_ctx->opts->sdom->pvt = ad_ctx; ++ + /* Set up the ID mapping object */ + ret = sdap_idmap_init(ad_ctx->sdap_id_ctx, ad_ctx->sdap_id_ctx, + &ad_ctx->sdap_id_ctx->opts->idmap_ctx); +diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h +index f47437553a2d35dac90d86209848e840a237c3fb..33e8708ab7e80ab4280df300fdc300d4ecd18305 100644 +--- a/src/providers/ldap/sdap_async.h ++++ b/src/providers/ldap/sdap_async.h +@@ -297,6 +297,7 @@ struct tevent_req * + sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sdap_id_ctx *id_ctx, ++ struct sdap_id_conn_ctx *conn, + struct sdap_options *opts, + struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, +diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c +index 33648c5da367c908d085a71a9a9017cb294bb300..9eece9a6e4baaf302a28b57a63dae45a0741136c 100644 +--- a/src/providers/ldap/sdap_async_groups.c ++++ b/src/providers/ldap/sdap_async_groups.c +@@ -26,6 +26,7 @@ + #include "providers/ldap/sdap_async_private.h" + #include "providers/ldap/ldap_common.h" + #include "providers/ldap/sdap_idmap.h" ++#include "providers/ad/ad_common.h" + + /* ==Group-Parsing Routines=============================================== */ + +@@ -1540,9 +1541,13 @@ struct sdap_get_groups_state { + + size_t base_iter; + struct sdap_search_base **search_bases; ++ ++ struct sdap_handle *ldap_sh; ++ struct sdap_id_op *op; + }; + + static errno_t sdap_get_groups_next_base(struct tevent_req *req); ++static void sdap_get_groups_ldap_connect_done(struct tevent_req *subreq); + static void sdap_get_groups_process(struct tevent_req *subreq); + static void sdap_get_groups_done(struct tevent_req *subreq); + +@@ -1558,7 +1563,9 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx, + { + errno_t ret; + struct tevent_req *req; ++ struct tevent_req *subreq; + struct sdap_get_groups_state *state; ++ struct ad_id_ctx *subdom_id_ctx; + + req = tevent_req_create(memctx, &state, struct sdap_get_groups_state); + if (!req) return NULL; +@@ -1586,6 +1593,30 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx, + goto done; + } + ++ /* With AD by default the Global Catalog is used for lookup. But the GC ++ * group object might not have full group membership data. To make sure we ++ * connect to an LDAP server of the group's domain. */ ++ if (state->opts->schema_type == SDAP_SCHEMA_AD && sdom->pvt != NULL) { ++ subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx); ++ state->op = sdap_id_op_create(state, subdom_id_ctx->ldap_ctx->conn_cache); ++ if (!state->op) { ++ DEBUG(2, ("sdap_id_op_create failed\n")); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ subreq = sdap_id_op_connect_send(state->op, state, &ret); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ tevent_req_set_callback(subreq, ++ sdap_get_groups_ldap_connect_done, ++ req); ++ return req; ++ } ++ + ret = sdap_get_groups_next_base(req); + + done: +@@ -1597,6 +1628,34 @@ done: + return req; + } + ++static void sdap_get_groups_ldap_connect_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req; ++ struct sdap_get_groups_state *state; ++ int ret; ++ int dp_error; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct sdap_get_groups_state); ++ ++ ret = sdap_id_op_connect_recv(subreq, &dp_error); ++ talloc_zfree(subreq); ++ ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ state->ldap_sh = sdap_id_op_handle(state->op); ++ ++ ret = sdap_get_groups_next_base(req); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ } ++ ++ return; ++} ++ + static errno_t sdap_get_groups_next_base(struct tevent_req *req) + { + struct tevent_req *subreq; +@@ -1617,7 +1676,8 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req) + state->search_bases[state->base_iter]->basedn)); + + subreq = sdap_get_generic_send( +- state, state->ev, state->opts, state->sh, ++ state, state->ev, state->opts, ++ state->ldap_sh != NULL ? state->ldap_sh : state->sh, + state->search_bases[state->base_iter]->basedn, + state->search_bases[state->base_iter]->scope, + state->filter, state->attrs, +diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c +index 1b865af0a113222b3c9c11e9401718abad577fd7..aba7ba42dade8923ae91f5bc8962e03d038c15a1 100644 +--- a/src/providers/ldap/sdap_async_initgroups.c ++++ b/src/providers/ldap/sdap_async_initgroups.c +@@ -2749,6 +2749,10 @@ static void sdap_get_initgr_user(struct tevent_req *subreq) + const char *orig_dn; + const char *cname; + bool in_transaction = false; ++ char *expected_basedn; ++ size_t expected_basedn_len; ++ size_t dn_len; ++ size_t c = 0; + + DEBUG(9, ("Receiving info for the user\n")); + +@@ -2788,11 +2792,50 @@ static void sdap_get_initgr_user(struct tevent_req *subreq) + } else if (count != 1) { + DEBUG(SSSDBG_OP_FAILURE, + ("Expected one user entry and got %zu\n", count)); +- tevent_req_error(req, EINVAL); +- return; ++ ++ ret = domain_to_basedn(state, state->dom->name, &expected_basedn); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("domain_to_basedn failed.\n")); ++ tevent_req_error(req, ret); ++ return; ++ } ++ expected_basedn = talloc_asprintf(state, "%s%s", ++ "cn=users,", expected_basedn); ++ if (expected_basedn == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ("talloc_append failed.\n")); ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_ALL, ("Expected BaseDN is [%s].\n", expected_basedn)); ++ expected_basedn_len = strlen(expected_basedn); ++ ++ for (c = 0; c < count; c++) { ++ ret = sysdb_attrs_get_string(usr_attrs[c], SYSDB_ORIG_DN, &orig_dn); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n")); ++ tevent_req_error(req, ret); ++ return; ++ } ++ dn_len = strlen(orig_dn); ++ ++ if (dn_len > expected_basedn_len ++ && strcasecmp(orig_dn + (dn_len - expected_basedn_len), ++ expected_basedn) == 0) { ++ DEBUG(SSSDBG_TRACE_ALL, ++ ("Found matching dn [%s].\n", orig_dn)); ++ break; ++ } ++ } ++ ++ if (c == count) { ++ DEBUG(SSSDBG_OP_FAILURE, ("No matching DN found.\n")); ++ tevent_req_error(req, EINVAL); ++ return; ++ } + } + +- state->orig_user = usr_attrs[0]; ++ state->orig_user = usr_attrs[c]; + + ret = sysdb_transaction_start(state->sysdb); + if (ret) { +@@ -2858,6 +2901,7 @@ static void sdap_get_initgr_user(struct tevent_req *subreq) + */ + subreq = sdap_ad_tokengroups_initgroups_send(state, state->ev, + state->id_ctx, ++ state->conn, + state->opts, + state->sysdb, + state->dom, +diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c +index f1bf77e8614c30b214118140e380c23c40c1195b..8f8f0a4cc635818dcc7f75f9da603ce2f55c820f 100644 +--- a/src/providers/ldap/sdap_async_initgroups_ad.c ++++ b/src/providers/ldap/sdap_async_initgroups_ad.c +@@ -25,6 +25,7 @@ + #include "providers/ldap/ldap_common.h" + #include "providers/ldap/sdap_async_private.h" + #include "providers/ldap/sdap_idmap.h" ++#include "providers/ad/ad_common.h" + #include "lib/idmap/sss_idmap.h" + + struct sdap_ad_match_rule_initgr_state { +@@ -528,6 +529,7 @@ done: + struct sdap_ad_resolve_sids_state { + struct tevent_context *ev; + struct sdap_id_ctx *id_ctx; ++ struct sdap_id_conn_ctx *conn; + struct sdap_options *opts; + struct sss_domain_info *domain; + char **sids; +@@ -543,6 +545,7 @@ static struct tevent_req * + sdap_ad_resolve_sids_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sdap_id_ctx *id_ctx, ++ struct sdap_id_conn_ctx *conn, + struct sdap_options *opts, + struct sss_domain_info *domain, + char **sids) +@@ -560,6 +563,7 @@ sdap_ad_resolve_sids_send(TALLOC_CTX *mem_ctx, + + state->ev = ev; + state->id_ctx = id_ctx; ++ state->conn = conn; + state->opts = opts; + state->domain = get_domains_head(domain); + state->sids = sids; +@@ -618,7 +622,7 @@ static errno_t sdap_ad_resolve_sids_step(struct tevent_req *req) + } + + subreq = groups_get_send(state, state->ev, state->id_ctx, sdap_domain, +- state->id_ctx->conn, state->current_sid, ++ state->conn, state->current_sid, + BE_FILTER_SECID, BE_ATTR_CORE, false); + if (subreq == NULL) { + return ENOMEM; +@@ -673,12 +677,21 @@ static errno_t sdap_ad_resolve_sids_recv(struct tevent_req *req) + + + struct sdap_ad_tokengroups_initgr_mapping_state { ++ struct tevent_context *ev; ++ struct sdap_options *opts; ++ struct sdap_handle *sh; + struct sdap_idmap_ctx *idmap_ctx; + struct sysdb_ctx *sysdb; + struct sss_domain_info *domain; ++ const char *orig_dn; ++ int timeout; + const char *username; ++ ++ struct sdap_id_op *op; + }; + ++static void ++sdap_ad_tokengroups_initgr_mapping_connect_done(struct tevent_req *subreq); + static void sdap_ad_tokengroups_initgr_mapping_done(struct tevent_req *subreq); + + static struct tevent_req * +@@ -695,6 +708,8 @@ sdap_ad_tokengroups_initgr_mapping_send(TALLOC_CTX *mem_ctx, + struct sdap_ad_tokengroups_initgr_mapping_state *state = NULL; + struct tevent_req *req = NULL; + struct tevent_req *subreq = NULL; ++ struct sdap_domain *sdom; ++ struct ad_id_ctx *subdom_id_ctx; + errno_t ret; + + req = tevent_req_create(mem_ctx, &state, +@@ -704,36 +719,92 @@ sdap_ad_tokengroups_initgr_mapping_send(TALLOC_CTX *mem_ctx, + return NULL; + } + ++ state->ev = ev; ++ state->opts = opts; ++ state->sh = sh; + state->idmap_ctx = opts->idmap_ctx; + state->sysdb = sysdb; + state->domain = domain; ++ state->timeout = timeout; ++ state->orig_dn = orig_dn; + state->username = talloc_strdup(state, name); + if (state->username == NULL) { + ret = ENOMEM; + goto immediately; + } + +- subreq = sdap_get_ad_tokengroups_send(state, ev, opts, sh, name, orig_dn, +- timeout); ++ sdom = sdap_domain_get(opts, domain); ++ if (sdom == NULL || sdom->pvt == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("No ID ctx available for [%s].\n", ++ domain->name)); ++ ret = EINVAL; ++ goto immediately; ++ } ++ subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx); ++ state->op = sdap_id_op_create(state, subdom_id_ctx->ldap_ctx->conn_cache); ++ if (!state->op) { ++ DEBUG(2, ("sdap_id_op_create failed\n")); ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ subreq = sdap_id_op_connect_send(state->op, state, &ret); + if (subreq == NULL) { + ret = ENOMEM; + goto immediately; + } + ++ tevent_req_set_callback(subreq, ++ sdap_ad_tokengroups_initgr_mapping_connect_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 ++sdap_ad_tokengroups_initgr_mapping_connect_done(struct tevent_req *subreq) ++{ ++ struct sdap_ad_tokengroups_initgr_mapping_state *state = NULL; ++ struct tevent_req *req = NULL; ++ int ret; ++ int dp_error = DP_ERR_FATAL; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, ++ struct sdap_ad_tokengroups_initgr_mapping_state); ++ ++ ++ ret = sdap_id_op_connect_recv(subreq, &dp_error); ++ talloc_zfree(subreq); ++ ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ subreq = sdap_get_ad_tokengroups_send(state, state->ev, state->opts, ++ sdap_id_op_handle(state->op), ++ state->username, ++ state->orig_dn, state->timeout); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ + tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgr_mapping_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; ++ return; + } + + static void sdap_ad_tokengroups_initgr_mapping_done(struct tevent_req *subreq) +@@ -896,22 +967,31 @@ static int sdap_ad_tokengroups_initgr_mapping_recv(struct tevent_req *req) + struct sdap_ad_tokengroups_initgr_posix_state { + struct tevent_context *ev; + struct sdap_id_ctx *id_ctx; ++ struct sdap_id_conn_ctx *conn; + struct sdap_options *opts; ++ struct sdap_handle *sh; + struct sysdb_ctx *sysdb; + struct sss_domain_info *domain; ++ const char *orig_dn; ++ int timeout; + const char *username; ++ ++ struct sdap_id_op *op; + }; + + static void + sdap_ad_tokengroups_initgr_posix_tg_done(struct tevent_req *subreq); + + static void ++sdap_ad_tokengroups_initgr_posix_sids_connect_done(struct tevent_req *subreq); ++static void + sdap_ad_tokengroups_initgr_posix_sids_done(struct tevent_req *subreq); + + static struct tevent_req * + sdap_ad_tokengroups_initgr_posix_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sdap_id_ctx *id_ctx, ++ struct sdap_id_conn_ctx *conn, + struct sdap_options *opts, + struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, +@@ -923,6 +1003,8 @@ sdap_ad_tokengroups_initgr_posix_send(TALLOC_CTX *mem_ctx, + struct sdap_ad_tokengroups_initgr_posix_state *state = NULL; + struct tevent_req *req = NULL; + struct tevent_req *subreq = NULL; ++ struct sdap_domain *sdom; ++ struct ad_id_ctx *subdom_id_ctx; + errno_t ret; + + req = tevent_req_create(mem_ctx, &state, +@@ -934,36 +1016,91 @@ sdap_ad_tokengroups_initgr_posix_send(TALLOC_CTX *mem_ctx, + + state->ev = ev; + state->id_ctx = id_ctx; ++ state->conn = conn; + state->opts = opts; ++ state->sh = sh; + state->sysdb = sysdb; + state->domain = domain; ++ state->orig_dn = orig_dn; ++ state->timeout = timeout; + state->username = talloc_strdup(state, name); + if (state->username == NULL) { + ret = ENOMEM; + goto immediately; + } + +- subreq = sdap_get_ad_tokengroups_send(state, ev, opts, sh, name, orig_dn, +- timeout); ++ sdom = sdap_domain_get(opts, domain); ++ if (sdom == NULL || sdom->pvt == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("No ID ctx available for [%s].\n", ++ domain->name)); ++ ret = EINVAL; ++ goto immediately; ++ } ++ subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx); ++ state->op = sdap_id_op_create(state, subdom_id_ctx->ldap_ctx->conn_cache); ++ if (!state->op) { ++ DEBUG(2, ("sdap_id_op_create failed\n")); ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ subreq = sdap_id_op_connect_send(state->op, state, &ret); + if (subreq == NULL) { + ret = ENOMEM; + goto immediately; + } + ++ tevent_req_set_callback(subreq, ++ sdap_ad_tokengroups_initgr_posix_sids_connect_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 ++sdap_ad_tokengroups_initgr_posix_sids_connect_done(struct tevent_req *subreq) ++{ ++ struct sdap_ad_tokengroups_initgr_posix_state *state = NULL; ++ struct tevent_req *req = NULL; ++ int ret; ++ int dp_error = DP_ERR_FATAL; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, ++ struct sdap_ad_tokengroups_initgr_posix_state); ++ ++ ++ ret = sdap_id_op_connect_recv(subreq, &dp_error); ++ talloc_zfree(subreq); ++ ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ subreq = sdap_get_ad_tokengroups_send(state, state->ev, state->opts, ++ sdap_id_op_handle(state->op), ++ state->username, state->orig_dn, ++ state->timeout); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ + tevent_req_set_callback(subreq, sdap_ad_tokengroups_initgr_posix_tg_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; ++ return; + } + + static void +@@ -1089,6 +1226,7 @@ sdap_ad_tokengroups_initgr_posix_tg_done(struct tevent_req *subreq) + /* download missing SIDs */ + missing_sids = talloc_steal(state, missing_sids); + subreq = sdap_ad_resolve_sids_send(state, state->ev, state->id_ctx, ++ state->conn, + state->opts, state->domain, + missing_sids); + if (subreq == NULL) { +@@ -1154,6 +1292,7 @@ struct tevent_req * + sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sdap_id_ctx *id_ctx, ++ struct sdap_id_conn_ctx *conn, + struct sdap_options *opts, + struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, +@@ -1184,8 +1323,8 @@ sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx, + name, orig_dn, + timeout); + } else { +- subreq = sdap_ad_tokengroups_initgr_posix_send(state, ev, id_ctx, opts, +- sysdb, domain, sh, ++ subreq = sdap_ad_tokengroups_initgr_posix_send(state, ev, id_ctx, conn, ++ opts, sysdb, domain, sh, + name, orig_dn, + timeout); + } +-- +1.8.4.2 + diff --git a/SOURCES/0028-AD-Add-a-utility-function-to-create-list-of-connecti.patch b/SOURCES/0028-AD-Add-a-utility-function-to-create-list-of-connecti.patch new file mode 100644 index 0000000..3083367 --- /dev/null +++ b/SOURCES/0028-AD-Add-a-utility-function-to-create-list-of-connecti.patch @@ -0,0 +1,497 @@ +From 1dced7370e55be16154bbb649606f928765819d0 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 3 Dec 2013 20:45:44 +0100 +Subject: [PATCH 28/31] AD: Add a utility function to create list of + connections + +ad_id.c and ad_access.c used the same block of code. With the upcoming +option to disable GC lookups, we should unify the code in a function to +avoid breaking one of the code paths. + +The same applies for the LDAP connection to the trusted AD DC. + +Includes a unit test. +--- + Makefile.am | 28 +++++ + src/providers/ad/ad_access.c | 16 +-- + src/providers/ad/ad_access.h | 4 +- + src/providers/ad/ad_common.c | 52 +++++++++ + src/providers/ad/ad_common.h | 7 ++ + src/providers/ad/ad_id.c | 29 ++--- + src/providers/ad/ad_init.c | 3 +- + src/tests/cmocka/test_ad_common.c | 221 ++++++++++++++++++++++++++++++++++++++ + 8 files changed, 319 insertions(+), 41 deletions(-) + create mode 100644 src/tests/cmocka/test_ad_common.c + +diff --git a/Makefile.am b/Makefile.am +index 583ccdb499306268640bfb894f673c42945e19ff..da407038089f3c010dea139735db9e0e2f000943 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -152,6 +152,7 @@ if HAVE_CMOCKA + test_sss_idmap \ + test_utils \ + ad_access_filter_tests \ ++ ad_common_tests \ + test_search_bases + endif + +@@ -1398,6 +1399,7 @@ ad_access_filter_tests_SOURCES = \ + src/util/sss_krb5.c \ + src/util/find_uid.c \ + src/util/user_info_msg.c \ ++ src/providers/ad/ad_common.c \ + src/tests/cmocka/test_ad_access_filter.c + ad_access_filter_tests_CFLAGS = \ + $(AM_CFLAGS) \ +@@ -1416,6 +1418,32 @@ ad_access_filter_tests_LDADD = \ + libsss_krb5_common.la \ + libsss_test_common.la + ++ad_common_tests_SOURCES = \ ++ $(sssd_be_SOURCES) \ ++ src/util/sss_ldap.c \ ++ src/util/sss_krb5.c \ ++ src/util/find_uid.c \ ++ src/util/user_info_msg.c \ ++ src/tests/cmocka/test_ad_common.c ++ad_common_tests_CFLAGS = \ ++ $(AM_CFLAGS) \ ++ $(SYSTEMD_LOGIN_CFLAGS) \ ++ -DUNIT_TESTING ++ad_common_tests_LDFLAGS = \ ++ -Wl,-wrap,sdap_set_sasl_options ++ad_common_tests_LDADD = \ ++ $(PAM_LIBS) \ ++ $(CMOCKA_LIBS) \ ++ $(SSSD_LIBS) \ ++ $(CARES_LIBS) \ ++ $(KRB5_LIBS) \ ++ $(SSSD_INTERNAL_LTLIBS) \ ++ $(SYSTEMD_LOGIN_LIBS) \ ++ libsss_ldap_common.la \ ++ libsss_idmap.la \ ++ libsss_krb5_common.la \ ++ libsss_test_common.la ++ + endif + + noinst_PROGRAMS = pam_test_client +diff --git a/src/providers/ad/ad_access.c b/src/providers/ad/ad_access.c +index 6995172db304810899e538b37572e4ba953db3e7..68a292abc88daa2f10f6797db50cc75335e80483 100644 +--- a/src/providers/ad/ad_access.c ++++ b/src/providers/ad/ad_access.c +@@ -274,26 +274,12 @@ ad_access_send(TALLOC_CTX *mem_ctx, + goto done; + } + +- state->clist = talloc_zero_array(state, struct sdap_id_conn_ctx *, 3); ++ state->clist = ad_gc_conn_list(state, ctx->ad_id_ctx, domain); + if (state->clist == NULL) { + ret = ENOMEM; + goto done; + } + +- /* Always try GC first */ +- ctx->gc_ctx->ignore_mark_offline = false; +- state->clist[0] = ctx->gc_ctx; +- if (IS_SUBDOMAIN(domain) == false) { +- /* fall back to ldap if gc is not available */ +- state->clist[0]->ignore_mark_offline = true; +- +- /* With root domain users we have the option to +- * fall back to LDAP in case ie POSIX attributes +- * are used but not replicated to GC +- */ +- state->clist[1] = ctx->ldap_ctx; +- } +- + ret = ad_access_step(req, state->clist[state->cindex]); + if (ret != EOK) { + goto done; +diff --git a/src/providers/ad/ad_access.h b/src/providers/ad/ad_access.h +index ca5e69729c574be53b7da04df0ff89446da04c58..3bd19ccc508b43f7103c7041dcc8573a00235097 100644 +--- a/src/providers/ad/ad_access.h ++++ b/src/providers/ad/ad_access.h +@@ -26,9 +26,7 @@ + struct ad_access_ctx { + struct dp_option *ad_options; + struct sdap_access_ctx *sdap_access_ctx; +- +- struct sdap_id_conn_ctx *ldap_ctx; +- struct sdap_id_conn_ctx *gc_ctx; ++ struct ad_id_ctx *ad_id_ctx; + }; + + void +diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c +index f679c11ad18078b454b778ef30e40cca716412cb..af0ec839964233c7642205f4489e5b6462509848 100644 +--- a/src/providers/ad/ad_common.c ++++ b/src/providers/ad/ad_common.c +@@ -1096,3 +1096,55 @@ ad_id_ctx_init(struct ad_options *ad_opts, struct be_ctx *bectx) + + return ad_ctx; + } ++ ++struct sdap_id_conn_ctx * ++ad_get_dom_ldap_conn(struct ad_id_ctx *ad_ctx, struct sss_domain_info *dom) ++{ ++ struct sdap_id_conn_ctx *conn; ++ struct sdap_domain *sdom; ++ struct ad_id_ctx *subdom_id_ctx; ++ ++ if (IS_SUBDOMAIN(dom)) { ++ sdom = sdap_domain_get(ad_ctx->sdap_id_ctx->opts, dom); ++ if (sdom == NULL || sdom->pvt == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("No ID ctx available for [%s].\n", ++ dom->name)); ++ return NULL; ++ } ++ subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx); ++ conn = subdom_id_ctx->ldap_ctx; ++ } else { ++ conn = ad_ctx->ldap_ctx; ++ } ++ ++ return conn; ++} ++ ++struct sdap_id_conn_ctx ** ++ad_gc_conn_list(TALLOC_CTX *mem_ctx, struct ad_id_ctx *ad_ctx, ++ struct sss_domain_info *dom) ++{ ++ struct sdap_id_conn_ctx **clist; ++ ++ clist = talloc_zero_array(mem_ctx, struct sdap_id_conn_ctx *, 3); ++ if (clist == NULL) return NULL; ++ ++ /* Always try GC first */ ++ clist[0] = ad_ctx->gc_ctx; ++ if (IS_SUBDOMAIN(dom) == true) { ++ clist[0]->ignore_mark_offline = false; ++ /* Subdomain users are only present in GC. */ ++ return clist; ++ } ++ ++ /* fall back to ldap if gc is not available */ ++ clist[0]->ignore_mark_offline = true; ++ ++ /* With root domain users we have the option to ++ * fall back to LDAP in case ie POSIX attributes ++ * are used but not replicated to GC ++ */ ++ clist[1] = ad_ctx->ldap_ctx; ++ ++ return clist; ++} +diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h +index b8b73c042b8a5433f720c89c04447c07cd3eac43..ed5b8584dc5327a24e60985486c6155604271fd2 100644 +--- a/src/providers/ad/ad_common.h ++++ b/src/providers/ad/ad_common.h +@@ -115,6 +115,13 @@ ad_get_dyndns_options(struct be_ctx *be_ctx, + struct ad_id_ctx * + ad_id_ctx_init(struct ad_options *ad_opts, struct be_ctx *bectx); + ++struct sdap_id_conn_ctx ** ++ad_gc_conn_list(TALLOC_CTX *mem_ctx, struct ad_id_ctx *ad_ctx, ++ struct sss_domain_info *dom); ++ ++struct sdap_id_conn_ctx * ++ad_get_dom_ldap_conn(struct ad_id_ctx *ad_ctx, struct sss_domain_info *dom); ++ + /* AD dynamic DNS updates */ + errno_t ad_dyndns_init(struct be_ctx *be_ctx, + struct ad_options *ctx); +diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c +index cf71b172dd7c241a9280a7ea72ef2518f66a7435..e47c41863a14eed695907548d64f4559fbae629d 100644 +--- a/src/providers/ad/ad_id.c ++++ b/src/providers/ad/ad_id.c +@@ -188,12 +188,6 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx, + struct sss_domain_info *dom, struct be_acct_req *ar) + { + struct sdap_id_conn_ctx **clist; +- struct sdap_domain *sdom; +- struct ad_id_ctx *subdom_id_ctx; +- +- /* LDAP, GC, sentinel */ +- clist = talloc_zero_array(breq, struct sdap_id_conn_ctx *, 3); +- if (clist == NULL) return NULL; + + switch (ar->entry_type & BE_REQ_TYPE_MASK) { + case BE_REQ_USER: /* user */ +@@ -201,24 +195,17 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx, + case BE_REQ_USER_AND_GROUP: /* get SID */ + case BE_REQ_GROUP: /* group */ + case BE_REQ_INITGROUPS: /* init groups for user */ +- /* Always try GC first */ +- clist[0] = ad_ctx->gc_ctx; +- if (IS_SUBDOMAIN(dom) == true) { +- clist[0]->ignore_mark_offline = false; +- /* Subdomain users are only present in GC. */ +- break; +- } +- /* fall back to ldap if gc is not available */ +- clist[0]->ignore_mark_offline = true; +- +- /* With root domain users we have the option to +- * fall back to LDAP in case ie POSIX attributes +- * are used but not replicated to GC +- */ +- clist[1] = ad_ctx->ldap_ctx; ++ clist = ad_gc_conn_list(breq, ad_ctx, dom); ++ if (clist == NULL) return NULL; + break; ++ + default: ++ /* Requests for other object should only contact LDAP by default */ ++ clist = talloc_zero_array(breq, struct sdap_id_conn_ctx *, 2); ++ if (clist == NULL) return NULL; ++ + clist[0] = ad_ctx->ldap_ctx; ++ clist[1] = NULL; + break; + } + +diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c +index 332bfda3801db3824ce1896d37e65e2c3a6b8b8b..ed69a7d9889bac1281b5ff7c7b0f290ab09173fb 100644 +--- a/src/providers/ad/ad_init.c ++++ b/src/providers/ad/ad_init.c +@@ -377,8 +377,7 @@ sssm_ad_access_init(struct be_ctx *bectx, + if (ret != EOK) { + goto fail; + } +- access_ctx->ldap_ctx = ad_id_ctx->ldap_ctx; +- access_ctx->gc_ctx = ad_id_ctx->gc_ctx; ++ access_ctx->ad_id_ctx = ad_id_ctx; + + ret = dp_copy_options(access_ctx, ad_options->basic, AD_OPTS_BASIC, + &access_ctx->ad_options); +diff --git a/src/tests/cmocka/test_ad_common.c b/src/tests/cmocka/test_ad_common.c +new file mode 100644 +index 0000000000000000000000000000000000000000..648b68f2dc05947b1fbb4c680ec63d3c2c6275b3 +--- /dev/null ++++ b/src/tests/cmocka/test_ad_common.c +@@ -0,0 +1,221 @@ ++/* ++ Authors: ++ Jakub Hrozek ++ ++ Copyright (C) 2013 Red Hat ++ ++ SSSD tests: AD access control filter tests ++ ++ 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 ++#include ++ ++/* In order to access opaque types */ ++#include "providers/ad/ad_common.c" ++ ++#include "tests/cmocka/common_mock.h" ++ ++#define DOMNAME "domname" ++#define SUBDOMNAME "sub."DOMNAME ++#define REALMNAME DOMNAME ++#define HOST_NAME "ad."REALMNAME ++ ++struct ad_common_test_ctx { ++ struct ad_id_ctx *ad_ctx; ++ struct ad_id_ctx *subdom_ad_ctx; ++ ++ struct sss_domain_info *dom; ++ struct sss_domain_info *subdom; ++}; ++ ++static void ++ad_common_test_setup(void **state) ++{ ++ struct ad_common_test_ctx *test_ctx; ++ errno_t ret; ++ struct sdap_domain *sdom; ++ struct ad_id_ctx *ad_ctx; ++ struct ad_id_ctx *subdom_ad_ctx; ++ struct sdap_id_conn_ctx *subdom_ldap_ctx; ++ ++ assert_true(leak_check_setup()); ++ check_leaks_push(global_talloc_context); ++ ++ test_ctx = talloc_zero(global_talloc_context, struct ad_common_test_ctx); ++ assert_non_null(test_ctx); ++ ++ test_ctx->dom = talloc_zero(test_ctx, struct sss_domain_info); ++ assert_non_null(test_ctx->dom); ++ test_ctx->dom->name = discard_const(DOMNAME); ++ ++ test_ctx->subdom = talloc_zero(test_ctx, struct sss_domain_info); ++ assert_non_null(test_ctx->subdom); ++ test_ctx->subdom->name = discard_const(SUBDOMNAME); ++ test_ctx->subdom->parent = test_ctx->dom; ++ ++ ad_ctx = talloc_zero(test_ctx, struct ad_id_ctx); ++ assert_non_null(ad_ctx); ++ ++ ad_ctx->ad_options = ad_create_default_options(ad_ctx, ++ REALMNAME, HOST_NAME); ++ assert_non_null(ad_ctx->ad_options); ++ ++ ad_ctx->gc_ctx = talloc_zero(ad_ctx, struct sdap_id_conn_ctx); ++ assert_non_null(ad_ctx->gc_ctx); ++ ++ ad_ctx->ldap_ctx = talloc_zero(ad_ctx, struct sdap_id_conn_ctx); ++ assert_non_null(ad_ctx->ldap_ctx); ++ ++ ad_ctx->sdap_id_ctx = talloc_zero(ad_ctx, struct sdap_id_ctx); ++ assert_non_null(ad_ctx->sdap_id_ctx); ++ ++ ad_ctx->sdap_id_ctx->opts = talloc_zero(ad_ctx->sdap_id_ctx, ++ struct sdap_options); ++ assert_non_null(ad_ctx->sdap_id_ctx->opts); ++ ++ ret = sdap_domain_add(ad_ctx->sdap_id_ctx->opts, test_ctx->dom, &sdom); ++ assert_int_equal(ret, EOK); ++ ++ subdom_ad_ctx = talloc_zero(test_ctx, struct ad_id_ctx); ++ assert_non_null(subdom_ad_ctx); ++ ++ subdom_ldap_ctx = talloc_zero(subdom_ad_ctx, struct sdap_id_conn_ctx); ++ assert_non_null(subdom_ldap_ctx); ++ subdom_ad_ctx->ldap_ctx = subdom_ldap_ctx; ++ ++ ret = sdap_domain_add(ad_ctx->sdap_id_ctx->opts, test_ctx->subdom, &sdom); ++ assert_int_equal(ret, EOK); ++ sdom->pvt = subdom_ad_ctx; ++ ++ test_ctx->ad_ctx = ad_ctx; ++ test_ctx->subdom_ad_ctx = subdom_ad_ctx; ++ ++ check_leaks_push(test_ctx); ++ *state = test_ctx; ++} ++ ++static void ++ad_common_test_teardown(void **state) ++{ ++ struct ad_common_test_ctx *test_ctx = talloc_get_type(*state, ++ struct ad_common_test_ctx); ++ assert_non_null(test_ctx); ++ ++ assert_true(check_leaks_pop(test_ctx) == true); ++ talloc_free(test_ctx); ++ assert_true(check_leaks_pop(global_talloc_context) == true); ++ assert_true(leak_check_teardown()); ++} ++ ++errno_t ++__wrap_sdap_set_sasl_options(struct sdap_options *id_opts, ++ char *default_primary, ++ char *default_realm, ++ const char *keytab_path) ++{ ++ /* Pretend SASL is fine */ ++ return EOK; ++} ++ ++void test_ldap_conn_list(void **state) ++{ ++ struct sdap_id_conn_ctx *conn; ++ ++ struct ad_common_test_ctx *test_ctx = talloc_get_type(*state, ++ struct ad_common_test_ctx); ++ assert_non_null(test_ctx); ++ ++ conn = ad_get_dom_ldap_conn(test_ctx->ad_ctx, test_ctx->dom); ++ assert_true(conn == test_ctx->ad_ctx->ldap_ctx); ++ ++ conn = ad_get_dom_ldap_conn(test_ctx->ad_ctx, test_ctx->subdom); ++ assert_true(conn == test_ctx->subdom_ad_ctx->ldap_ctx); ++} ++ ++void test_conn_list(void **state) ++{ ++ struct sdap_id_conn_ctx **conn_list; ++ ++ struct ad_common_test_ctx *test_ctx = talloc_get_type(*state, ++ struct ad_common_test_ctx); ++ assert_non_null(test_ctx); ++ ++ conn_list = ad_gc_conn_list(test_ctx, test_ctx->ad_ctx, test_ctx->dom); ++ assert_non_null(conn_list); ++ ++ assert_true(conn_list[0] == test_ctx->ad_ctx->gc_ctx); ++ /* If there is a fallback, we should ignore the offline mode */ ++ assert_true(conn_list[0]->ignore_mark_offline); ++ assert_true(conn_list[1] == test_ctx->ad_ctx->ldap_ctx); ++ assert_false(conn_list[1]->ignore_mark_offline); ++ assert_null(conn_list[2]); ++ talloc_free(conn_list); ++ ++ conn_list = ad_gc_conn_list(test_ctx, test_ctx->ad_ctx, test_ctx->subdom); ++ assert_non_null(conn_list); ++ ++ assert_true(conn_list[0] == test_ctx->ad_ctx->gc_ctx); ++ assert_false(conn_list[0]->ignore_mark_offline); ++ assert_null(conn_list[1]); ++ talloc_free(conn_list); ++} ++ ++int main(int argc, const char *argv[]) ++{ ++ poptContext pc; ++ int opt; ++ struct poptOption long_options[] = { ++ POPT_AUTOHELP ++ SSSD_DEBUG_OPTS ++ POPT_TABLEEND ++ }; ++ ++ const UnitTest tests[] = { ++ unit_test_setup_teardown(test_ldap_conn_list, ++ ad_common_test_setup, ++ ad_common_test_teardown), ++ unit_test_setup_teardown(test_conn_list, ++ ad_common_test_setup, ++ ad_common_test_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_INIT(debug_level); ++ ++ tests_set_cwd(); ++ ++ return run_tests(tests); ++} +-- +1.8.4.2 + diff --git a/SOURCES/0029-AD-Add-a-new-option-to-turn-off-GC-lookups.patch b/SOURCES/0029-AD-Add-a-new-option-to-turn-off-GC-lookups.patch new file mode 100644 index 0000000..03ff29d --- /dev/null +++ b/SOURCES/0029-AD-Add-a-new-option-to-turn-off-GC-lookups.patch @@ -0,0 +1,175 @@ +From 168396cd93b3f0e42b4842f520f2bcece91274c6 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Fri, 29 Nov 2013 11:39:09 +0100 +Subject: [PATCH 29/31] AD: Add a new option to turn off GC lookups + +SSSD now defaults to using GC by default. For some environments, for +instance those that don't or can't replicate the POSIX attributes to +Global Catalog, this might not be desirable. + +This patch introduces a new option ad_enable_gc, that is enabled by +default. Setting this option to false makes the SSSD contact only the +LDAP port of AD DCs. +--- + src/config/etc/sssd.api.d/sssd-ad.conf | 1 + + src/man/sssd-ad.5.xml | 17 +++++++++++++++++ + src/providers/ad/ad_common.c | 31 ++++++++++++++++++------------- + src/providers/ad/ad_common.h | 1 + + src/providers/ad/ad_opts.h | 1 + + src/tests/cmocka/test_ad_common.c | 20 ++++++++++++++++++++ + 6 files changed, 58 insertions(+), 13 deletions(-) + +diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf +index 9f606f6c4da65d4bfb20a97ee27801dac9307868..00e8968d2b6dab33a39005f11a497cb3e2185302 100644 +--- a/src/config/etc/sssd.api.d/sssd-ad.conf ++++ b/src/config/etc/sssd.api.d/sssd-ad.conf +@@ -5,6 +5,7 @@ ad_backup_server = str, None, false + ad_hostname = str, None, false + ad_enable_dns_sites = bool, None, false + ad_access_filter = str, None, false ++ad_enable_gc = bool, None, false + ldap_uri = str, None, false + ldap_backup_uri = str, None, false + ldap_search_base = str, None, false +diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml +index e31f87a96a14907c64166e53da443ad735c6e85e..38cc31278cf87c98ca9e53cf91fda7b141bff78d 100644 +--- a/src/man/sssd-ad.5.xml ++++ b/src/man/sssd-ad.5.xml +@@ -228,6 +228,23 @@ FOREST:EXAMPLE.COM:(memberOf=cn=admins,ou=groups,dc=example,dc=com) + + + ++ ad_enable_gc (boolean) ++ ++ ++ By default, the SSSD connects to the Global ++ Catalog first to retrieve users and uses the ++ LDAP port to retrieve group memberships or ++ as a fallback. Disabling this option makes ++ the SSSD only connect to the LDAP port of the ++ current AD server. ++ ++ ++ Default: true ++ ++ ++ ++ ++ + dyndns_update (boolean) + + +diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c +index af0ec839964233c7642205f4489e5b6462509848..a5ea4f587f30575a5903d8ae1a459f53512c011f 100644 +--- a/src/providers/ad/ad_common.c ++++ b/src/providers/ad/ad_common.c +@@ -1125,26 +1125,31 @@ ad_gc_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(mem_ctx, struct sdap_id_conn_ctx *, 3); + if (clist == NULL) return NULL; + + /* Always try GC first */ +- clist[0] = ad_ctx->gc_ctx; +- if (IS_SUBDOMAIN(dom) == true) { +- clist[0]->ignore_mark_offline = false; +- /* Subdomain users are only present in GC. */ +- return clist; ++ if (dp_opt_get_bool(ad_ctx->ad_options->basic, AD_ENABLE_GC)) { ++ clist[cindex] = ad_ctx->gc_ctx; ++ if (IS_SUBDOMAIN(dom) == true) { ++ clist[cindex]->ignore_mark_offline = false; ++ /* Subdomain users are only present in GC. */ ++ return clist; ++ } ++ /* fall back to ldap if gc is not available */ ++ clist[cindex]->ignore_mark_offline = true; ++ cindex++; + } + +- /* fall back to ldap if gc is not available */ +- clist[0]->ignore_mark_offline = true; +- +- /* With root domain users we have the option to +- * fall back to LDAP in case ie POSIX attributes +- * are used but not replicated to GC +- */ +- clist[1] = ad_ctx->ldap_ctx; ++ if (IS_SUBDOMAIN(dom) == false) { ++ /* With root domain users we have the option to ++ * fall back to LDAP in case ie POSIX attributes ++ * are used but not replicated to GC ++ */ ++ clist[cindex] = ad_ctx->ldap_ctx; ++ } + + return clist; + } +diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h +index ed5b8584dc5327a24e60985486c6155604271fd2..d370cef69124c127f41d7c4cbaa25713363e7752 100644 +--- a/src/providers/ad/ad_common.h ++++ b/src/providers/ad/ad_common.h +@@ -42,6 +42,7 @@ enum ad_basic_opt { + AD_KRB5_REALM, + AD_ENABLE_DNS_SITES, + AD_ACCESS_FILTER, ++ AD_ENABLE_GC, + + AD_OPTS_BASIC /* opts counter */ + }; +diff --git a/src/providers/ad/ad_opts.h b/src/providers/ad/ad_opts.h +index 8022a16274a04389b7a64b491ec28a0c3c55aaef..5b7b1c89f5f45d7cc744a955e6378390948a99fd 100644 +--- a/src/providers/ad/ad_opts.h ++++ b/src/providers/ad/ad_opts.h +@@ -36,6 +36,7 @@ struct dp_option ad_basic_opts[] = { + { "krb5_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING}, + { "ad_enable_dns_sites", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE }, + { "ad_access_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING}, ++ { "ad_enable_gc", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE }, + DP_OPTION_TERMINATOR + }; + +diff --git a/src/tests/cmocka/test_ad_common.c b/src/tests/cmocka/test_ad_common.c +index 648b68f2dc05947b1fbb4c680ec63d3c2c6275b3..07502b82d43d730562c60125b639d8e7d1034458 100644 +--- a/src/tests/cmocka/test_ad_common.c ++++ b/src/tests/cmocka/test_ad_common.c +@@ -159,6 +159,8 @@ void test_conn_list(void **state) + struct ad_common_test_ctx); + assert_non_null(test_ctx); + ++ assert_true(dp_opt_get_bool(test_ctx->ad_ctx->ad_options->basic, ++ AD_ENABLE_GC)); + conn_list = ad_gc_conn_list(test_ctx, test_ctx->ad_ctx, test_ctx->dom); + assert_non_null(conn_list); + +@@ -177,6 +179,24 @@ void test_conn_list(void **state) + assert_false(conn_list[0]->ignore_mark_offline); + assert_null(conn_list[1]); + talloc_free(conn_list); ++ ++ dp_opt_set_bool(test_ctx->ad_ctx->ad_options->basic, AD_ENABLE_GC, false); ++ assert_false(dp_opt_get_bool(test_ctx->ad_ctx->ad_options->basic, ++ AD_ENABLE_GC)); ++ ++ conn_list = ad_gc_conn_list(test_ctx, test_ctx->ad_ctx, test_ctx->dom); ++ assert_non_null(conn_list); ++ ++ assert_true(conn_list[0] == test_ctx->ad_ctx->ldap_ctx); ++ assert_false(conn_list[0]->ignore_mark_offline); ++ assert_null(conn_list[1]); ++ talloc_free(conn_list); ++ ++ conn_list = ad_gc_conn_list(test_ctx, test_ctx->ad_ctx, test_ctx->subdom); ++ assert_non_null(conn_list); ++ ++ assert_null(conn_list[0]); ++ talloc_free(conn_list); + } + + int main(int argc, const char *argv[]) +-- +1.8.4.2 + diff --git a/SOURCES/0030-AD-Enable-fallback-to-LDAP-of-trusted-domain.patch b/SOURCES/0030-AD-Enable-fallback-to-LDAP-of-trusted-domain.patch new file mode 100644 index 0000000..7190d1f --- /dev/null +++ b/SOURCES/0030-AD-Enable-fallback-to-LDAP-of-trusted-domain.patch @@ -0,0 +1,69 @@ +From dfebe8a952561e51fe1d603886ba4e979b29d889 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Fri, 13 Dec 2013 20:11:11 +0100 +Subject: [PATCH 30/31] AD: Enable fallback to LDAP of trusted domain + +Since we have the LDAP port of a trusted AD GC always available now, we +can always perform a fallback. +--- + src/providers/ad/ad_common.c | 14 +------------- + src/tests/cmocka/test_ad_common.c | 7 ++++--- + 2 files changed, 5 insertions(+), 16 deletions(-) + +diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c +index a5ea4f587f30575a5903d8ae1a459f53512c011f..99fa4c07af2a79bb3ca195214ddb0dbd60c61620 100644 +--- a/src/providers/ad/ad_common.c ++++ b/src/providers/ad/ad_common.c +@@ -1133,23 +1133,11 @@ ad_gc_conn_list(TALLOC_CTX *mem_ctx, struct ad_id_ctx *ad_ctx, + /* Always try GC first */ + if (dp_opt_get_bool(ad_ctx->ad_options->basic, AD_ENABLE_GC)) { + clist[cindex] = ad_ctx->gc_ctx; +- if (IS_SUBDOMAIN(dom) == true) { +- clist[cindex]->ignore_mark_offline = false; +- /* Subdomain users are only present in GC. */ +- return clist; +- } +- /* fall back to ldap if gc is not available */ + clist[cindex]->ignore_mark_offline = true; + cindex++; + } + +- if (IS_SUBDOMAIN(dom) == false) { +- /* With root domain users we have the option to +- * fall back to LDAP in case ie POSIX attributes +- * are used but not replicated to GC +- */ +- clist[cindex] = ad_ctx->ldap_ctx; +- } ++ clist[cindex] = ad_get_dom_ldap_conn(ad_ctx, dom); + + return clist; + } +diff --git a/src/tests/cmocka/test_ad_common.c b/src/tests/cmocka/test_ad_common.c +index 07502b82d43d730562c60125b639d8e7d1034458..bbd56b1b9b78cb78cb24726522822ad2f7ae9980 100644 +--- a/src/tests/cmocka/test_ad_common.c ++++ b/src/tests/cmocka/test_ad_common.c +@@ -176,8 +176,9 @@ void test_conn_list(void **state) + assert_non_null(conn_list); + + assert_true(conn_list[0] == test_ctx->ad_ctx->gc_ctx); +- assert_false(conn_list[0]->ignore_mark_offline); +- assert_null(conn_list[1]); ++ assert_true(conn_list[0]->ignore_mark_offline); ++ assert_true(conn_list[1] == test_ctx->subdom_ad_ctx->ldap_ctx); ++ assert_false(conn_list[1]->ignore_mark_offline); + talloc_free(conn_list); + + dp_opt_set_bool(test_ctx->ad_ctx->ad_options->basic, AD_ENABLE_GC, false); +@@ -195,7 +196,7 @@ void test_conn_list(void **state) + conn_list = ad_gc_conn_list(test_ctx, test_ctx->ad_ctx, test_ctx->subdom); + assert_non_null(conn_list); + +- assert_null(conn_list[0]); ++ assert_true(conn_list[0] == test_ctx->subdom_ad_ctx->ldap_ctx); + talloc_free(conn_list); + } + +-- +1.8.4.2 + diff --git a/SOURCES/0031-Bump-sss_idmap-version-to-3-0-3.patch b/SOURCES/0031-Bump-sss_idmap-version-to-3-0-3.patch new file mode 100644 index 0000000..57a1353 --- /dev/null +++ b/SOURCES/0031-Bump-sss_idmap-version-to-3-0-3.patch @@ -0,0 +1,26 @@ +From eb03d9c884e6d69af31d079a3bcb572de1a5838b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Mon, 4 Nov 2013 11:59:49 +0100 +Subject: [PATCH 31/31] Bump sss_idmap version to 3:0:3 + +New functions were added. +--- + Makefile.am | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile.am b/Makefile.am +index da407038089f3c010dea139735db9e0e2f000943..16648f9aa2275b60ec84a95ff8a26b1225b97918 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -612,7 +612,7 @@ libsss_idmap_la_SOURCES = \ + src/lib/idmap/sss_idmap_conv.c \ + src/util/murmurhash3.c + libsss_idmap_la_LDFLAGS = \ +- -version-info 2:0:2 ++ -version-info 3:0:3 + + dist_pkgconfig_DATA += src/sss_client/idmap/sss_nss_idmap.pc + libsss_nss_idmap_la_SOURCES = \ +-- +1.8.4.2 + diff --git a/SOURCES/0032-AD-Refresh-subdomain-data-structures-on-startup.patch b/SOURCES/0032-AD-Refresh-subdomain-data-structures-on-startup.patch new file mode 100644 index 0000000..ff6078a --- /dev/null +++ b/SOURCES/0032-AD-Refresh-subdomain-data-structures-on-startup.patch @@ -0,0 +1,98 @@ +From 1213f1a45e222b3c1b304262c51900d8ab2a886a Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Fri, 13 Dec 2013 19:11:47 +0100 +Subject: [PATCH 32/34] AD: Refresh subdomain data structures on startup + +Previously, if no changes were done to the list of subdomains, the SSSD +didn't update its list of sdap_domain mappings for the new subdomain. +This resulted in errors as no id_ctx was present for the subdomain +during lookup. + +This patch moves the block of code performed during update to a function +of its own and calls it during provider initialization as well. +--- + src/providers/ad/ad_subdomains.c | 49 ++++++++++++++++++++++++++-------------- + 1 file changed, 32 insertions(+), 17 deletions(-) + +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index 100fb13e99f7bf4b3946b1f5c5f9c626674bfb46..e438a688c364084a3f2bbca338a39d61aa86b5d6 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -414,6 +414,31 @@ done: + return ret; + } + ++static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *ctx) ++{ ++ errno_t ret; ++ ++ ret = sysdb_update_subdomains(ctx->be_ctx->domain); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("sysdb_update_subdomains failed.\n")); ++ return ret; ++ } ++ ++ ret = sss_write_domain_mappings(ctx->be_ctx->domain, false); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("sss_krb5_write_mappings failed.\n")); ++ /* Just continue */ ++ } ++ ++ ret = ads_store_sdap_subdom(ctx, ctx->be_ctx->domain); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("ads_store_sdap_subdom failed.\n")); ++ return ret; ++ } ++ ++ return EOK; ++} ++ + static void ad_subdomains_get_conn_done(struct tevent_req *req); + static void ad_subdomains_master_dom_done(struct tevent_req *req); + static errno_t ad_subdomains_get_slave(struct ad_subdomains_req_ctx *ctx); +@@ -619,25 +644,15 @@ static void ad_subdomains_get_slave_domain_done(struct tevent_req *req) + goto done; + } + ++ DEBUG(SSSDBG_TRACE_LIBS, ("There are %schanges\n", ++ refresh_has_changes ? "" : "no ")); ++ + if (refresh_has_changes) { +- ret = sysdb_update_subdomains(ctx->sd_ctx->be_ctx->domain); ++ ret = ad_subdom_reinit(ctx->sd_ctx); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, ("sysdb_update_subdomains failed.\n")); ++ DEBUG(SSSDBG_OP_FAILURE, ("Could not reinitialize subdomains\n")); + goto done; + } +- +- ret = ads_store_sdap_subdom(ctx->sd_ctx, ctx->sd_ctx->be_ctx->domain); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, ("ads_store_sdap_subdom failed.\n")); +- goto done; +- } +- +- ret = sss_write_domain_mappings(ctx->sd_ctx->be_ctx->domain, false); +- if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, +- ("sss_krb5_write_mappings failed.\n")); +- /* Just continue */ +- } + } + + ret = EOK; +@@ -783,9 +798,9 @@ int ad_subdom_init(struct be_ctx *be_ctx, + return EFAULT; + } + +- ret = sysdb_update_subdomains(be_ctx->domain); ++ ret = ad_subdom_reinit(ctx); + if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, ("Could not load the list of subdomains. " ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Could not reinitialize subdomains. " + "Users from trusted domains might not be resolved correctly\n")); + /* Ignore this error and try to discover the subdomains later */ + } +-- +1.8.4.2 + diff --git a/SOURCES/0033-IPA-Refresh-subdomain-data-structures-on-startup.patch b/SOURCES/0033-IPA-Refresh-subdomain-data-structures-on-startup.patch new file mode 100644 index 0000000..2d070bf --- /dev/null +++ b/SOURCES/0033-IPA-Refresh-subdomain-data-structures-on-startup.patch @@ -0,0 +1,93 @@ +From 3a1056929310cf304449baf3feed94bc8fe46383 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 17 Dec 2013 17:22:45 +0100 +Subject: [PATCH 33/34] IPA: Refresh subdomain data structures on startup + +Write domain-mappings at startup and initialize internal data structures +on provider startup, not only during updates. +--- + src/providers/ipa/ipa_subdomains.c | 51 ++++++++++++++++++++++++-------------- + 1 file changed, 32 insertions(+), 19 deletions(-) + +diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c +index 416e21913be8e991c9f496ff2b54f238b602f304..56fd4f99654aa07f822c49d6d39526765785f0de 100644 +--- a/src/providers/ipa/ipa_subdomains.c ++++ b/src/providers/ipa/ipa_subdomains.c +@@ -267,6 +267,35 @@ ipa_ad_subdom_refresh(struct be_ctx *be_ctx, + return EOK; + } + ++static errno_t ++ipa_subdom_reinit(struct ipa_subdomains_ctx *ctx) ++{ ++ errno_t ret; ++ ++ ret = sysdb_update_subdomains(ctx->be_ctx->domain); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("sysdb_update_subdomains failed.\n")); ++ return ret; ++ } ++ ++ ret = ipa_ad_subdom_refresh(ctx->be_ctx, ctx->id_ctx, ctx->be_ctx->domain); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("ipa_ad_subdom_refresh failed.\n")); ++ return ret; ++ } ++ ++ ret = sss_write_domain_mappings(ctx->be_ctx->domain, ++ dp_opt_get_bool(ctx->id_ctx->ipa_options->basic, ++ IPA_SERVER_MODE)); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ ("sss_krb5_write_mappings failed.\n")); ++ /* Just continue */ ++ } ++ ++ return EOK; ++} ++ + static void + ipa_ad_subdom_remove(struct ipa_subdomains_ctx *ctx, + struct sss_domain_info *subdom) +@@ -921,27 +950,11 @@ static void ipa_subdomains_handler_done(struct tevent_req *req) + } + + if (refresh_has_changes) { +- ret = sysdb_update_subdomains(domain); ++ ret = ipa_subdom_reinit(ctx->sd_ctx); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, ("sysdb_update_subdomains failed.\n")); ++ DEBUG(SSSDBG_OP_FAILURE, ("Could not reinitialize subdomains\n")); + goto done; + } +- +- ret = ipa_ad_subdom_refresh(ctx->sd_ctx->be_ctx, ctx->sd_ctx->id_ctx, +- domain); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, ("ipa_ad_subdom_refresh failed.\n")); +- goto done; +- } +- +- ret = sss_write_domain_mappings(domain, +- dp_opt_get_bool(ctx->sd_ctx->id_ctx->ipa_options->basic, +- IPA_SERVER_MODE)); +- if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, +- ("sss_krb5_write_mappings failed.\n")); +- /* Just continue */ +- } + } + + ret = sysdb_master_domain_update(domain); +@@ -1289,7 +1302,7 @@ int ipa_subdom_init(struct be_ctx *be_ctx, + DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to add subdom offline callback")); + } + +- ret = sysdb_update_subdomains(be_ctx->domain); ++ ret = ipa_subdom_reinit(ctx); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, ("Could not load the list of subdomains. " + "Users from trusted domains might not be resolved correctly\n")); +-- +1.8.4.2 + diff --git a/SOURCES/0034-IPA-Call-ipa_ad_subdom_refresh-when-server-mode-is-i.patch b/SOURCES/0034-IPA-Call-ipa_ad_subdom_refresh-when-server-mode-is-i.patch new file mode 100644 index 0000000..d3f683f --- /dev/null +++ b/SOURCES/0034-IPA-Call-ipa_ad_subdom_refresh-when-server-mode-is-i.patch @@ -0,0 +1,67 @@ +From 414d36bc08bf3ddb8c742f4548711cc0b448bb85 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 18 Dec 2013 18:14:46 +0100 +Subject: [PATCH 34/34] IPA: Call ipa_ad_subdom_refresh when server mode is + initialized + +ipa_ad_subdom_refresh was called before IPA server context was +initialized. On IPA server, this caused the code to dereference a NULL +pointer and crash. +--- + src/providers/ipa/ipa_subdomains.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c +index 56fd4f99654aa07f822c49d6d39526765785f0de..2d28d7cd0538b204eb2818e71e029dec19456a1c 100644 +--- a/src/providers/ipa/ipa_subdomains.c ++++ b/src/providers/ipa/ipa_subdomains.c +@@ -278,12 +278,6 @@ ipa_subdom_reinit(struct ipa_subdomains_ctx *ctx) + return ret; + } + +- ret = ipa_ad_subdom_refresh(ctx->be_ctx, ctx->id_ctx, ctx->be_ctx->domain); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, ("ipa_ad_subdom_refresh failed.\n")); +- return ret; +- } +- + ret = sss_write_domain_mappings(ctx->be_ctx->domain, + dp_opt_get_bool(ctx->id_ctx->ipa_options->basic, + IPA_SERVER_MODE)); +@@ -955,6 +949,13 @@ static void ipa_subdomains_handler_done(struct tevent_req *req) + DEBUG(SSSDBG_OP_FAILURE, ("Could not reinitialize subdomains\n")); + goto done; + } ++ ++ ret = ipa_ad_subdom_refresh(ctx->sd_ctx->be_ctx, ctx->sd_ctx->id_ctx, ++ domain); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("ipa_ad_subdom_refresh failed.\n")); ++ goto done; ++ } + } + + ret = sysdb_master_domain_update(domain); +@@ -1316,6 +1317,7 @@ int ipa_ad_subdom_init(struct be_ctx *be_ctx, + { + char *realm; + char *hostname; ++ errno_t ret; + + if (dp_opt_get_bool(id_ctx->ipa_options->basic, + IPA_SERVER_MODE) == false) { +@@ -1360,5 +1362,11 @@ int ipa_ad_subdom_init(struct be_ctx *be_ctx, + id_ctx->server_mode->trusts = NULL; + id_ctx->server_mode->ext_groups = NULL; + ++ ret = ipa_ad_subdom_refresh(be_ctx, id_ctx, be_ctx->domain); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("ipa_ad_subdom_refresh failed.\n")); ++ return ret; ++ } ++ + return EOK; + } +-- +1.8.4.2 + diff --git a/SOURCES/0035-sss_cache-initialize-names-member-of-sss_domain_info.patch b/SOURCES/0035-sss_cache-initialize-names-member-of-sss_domain_info.patch new file mode 100644 index 0000000..825f38f --- /dev/null +++ b/SOURCES/0035-sss_cache-initialize-names-member-of-sss_domain_info.patch @@ -0,0 +1,80 @@ +From ca3dda947538ca1c16386d4c3f86f97eee7d0abc Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 25 Nov 2013 17:54:06 +0100 +Subject: [PATCH 35/41] sss_cache: initialize names member of sss_domain_info + +sss_tc_fqname() called by sss_get_domain_name() requires that the names +member of the sss_domain_info struct is set to work properly. If the +names struct is properly initialized in sss_domain_info the separate one +in the tool context is not needed anymore. + +Related to https://fedorahosted.org/sssd/ticket/1741 +--- + src/tools/sss_cache.c | 23 ++++++++++------------- + 1 file changed, 10 insertions(+), 13 deletions(-) + +diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c +index fa2e29de8bf8a035dd725aa3190af1c2a2091e05..3b6e62393f6cf0f6ccc94aea8cf19bf3aedc444f 100644 +--- a/src/tools/sss_cache.c ++++ b/src/tools/sss_cache.c +@@ -63,7 +63,6 @@ static errno_t search_autofsmaps(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, + struct cache_tool_ctx { + struct confdb_ctx *confdb; + struct sss_domain_info *domains; +- struct sss_names_ctx *nctx; + + char *user_filter; + char *group_filter; +@@ -209,7 +208,7 @@ static errno_t update_filter(struct cache_tool_ctx *tctx, + return ENOMEM; + } + +- ret = sss_parse_name(tmp_ctx, tctx->nctx, name, ++ ret = sss_parse_name(tmp_ctx, dinfo->names, name, + &parsed_domain, &parsed_name); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("sss_parse_name failed\n")); +@@ -280,17 +279,6 @@ static errno_t update_all_filters(struct cache_tool_ctx *tctx, + { + errno_t ret; + +- if (IS_SUBDOMAIN(dinfo)) { +- ret = sss_names_init(tctx, tctx->confdb, dinfo->parent->name, +- &tctx->nctx); +- } else { +- ret = sss_names_init(tctx, tctx->confdb, dinfo->name, &tctx->nctx); +- } +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, ("sss_names_init() failed\n")); +- return ret; +- } +- + /* Update user filter */ + ret = update_filter(tctx, dinfo, tctx->user_name, + tctx->update_user_filter, "(%s=%s)", false, +@@ -467,6 +455,7 @@ errno_t init_domains(struct cache_tool_ctx *ctx, const char *domain) + { + char *confdb_path; + int ret; ++ struct sss_domain_info *dinfo; + + confdb_path = talloc_asprintf(ctx, "%s/%s", DB_PATH, CONFDB_FILE); + if (confdb_path == NULL) { +@@ -505,6 +494,14 @@ errno_t init_domains(struct cache_tool_ctx *ctx, const char *domain) + } + } + ++ for (dinfo = ctx->domains; dinfo; dinfo = get_next_domain(dinfo, false)) { ++ ret = sss_names_init(ctx, ctx->confdb, dinfo->name, &dinfo->names); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("sss_names_init() failed\n")); ++ return ret; ++ } ++ } ++ + return EOK; + } + +-- +1.8.4.2 + diff --git a/SOURCES/0036-sss_cache-fix-case-sensitivity-issue.patch b/SOURCES/0036-sss_cache-fix-case-sensitivity-issue.patch new file mode 100644 index 0000000..b9ca7c5 --- /dev/null +++ b/SOURCES/0036-sss_cache-fix-case-sensitivity-issue.patch @@ -0,0 +1,112 @@ +From 2db8726f09800d64231f403198742d22a04a8d8b Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 26 Nov 2013 10:27:50 +0100 +Subject: [PATCH 36/41] sss_cache: fix case-sensitivity issue + +For case-insensitive domains the lower-case name for case-insensitive +searches is stored in SYSDB_NAME_ALIAS. + +Related to https://fedorahosted.org/sssd/ticket/1741 +--- + src/tools/sss_cache.c | 63 +++++++++++++++++++++++++++++---------------------- + 1 file changed, 36 insertions(+), 27 deletions(-) + +diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c +index 3b6e62393f6cf0f6ccc94aea8cf19bf3aedc444f..56dc47afdcb92b71dc1ef71d7f26fdf276a1c45f 100644 +--- a/src/tools/sss_cache.c ++++ b/src/tools/sss_cache.c +@@ -196,6 +196,8 @@ static errno_t update_filter(struct cache_tool_ctx *tctx, + TALLOC_CTX *tmp_ctx = NULL; + char *use_name = NULL; + char *filter; ++ char *sanitized; ++ char *lc_sanitized; + + if (!name || !update) { + /* Nothing to do */ +@@ -215,6 +217,14 @@ static errno_t update_filter(struct cache_tool_ctx *tctx, + goto done; + } + ++ if (parsed_domain != NULL && strcasecmp(dinfo->name, parsed_domain) != 0) { ++ /* We were able to parse the domain from given fqdn, but it ++ * does not match with currently processed domain. */ ++ filter = NULL; ++ ret = EOK; ++ goto done; ++ } ++ + if (!dinfo->case_sensitive && !force_case_sensitivity) { + use_name = sss_tc_utf8_str_tolower(tmp_ctx, parsed_name); + if (!use_name) { +@@ -232,41 +242,40 @@ static errno_t update_filter(struct cache_tool_ctx *tctx, + ret = ENOMEM; + goto done; + } ++ } + +- if (!strcasecmp(dinfo->name, parsed_domain)) { +- if (fmt) { +- filter = talloc_asprintf(tmp_ctx, fmt, +- SYSDB_NAME, use_name); +- } else { +- filter = talloc_strdup(tmp_ctx, use_name); +- } +- if (filter == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory\n")); +- ret = ENOMEM; +- goto done; +- } ++ ret = sss_filter_sanitize_for_dom(tmp_ctx, use_name, dinfo, ++ &sanitized, &lc_sanitized); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to sanitize the given name.\n")); ++ goto done; ++ } ++ ++ if (fmt) { ++ if (!dinfo->case_sensitive && !force_case_sensitivity) { ++ filter = talloc_asprintf(tmp_ctx, "(|(%s=%s)(%s=%s))", ++ SYSDB_NAME_ALIAS, lc_sanitized, ++ SYSDB_NAME_ALIAS, sanitized); + } else { +- /* We were able to parse the domain from given fqdn, but it +- * does not match with currently processed domain. */ +- filter = NULL; ++ filter = talloc_asprintf(tmp_ctx, fmt, SYSDB_NAME, sanitized); + } + } else { +- if (fmt) { +- filter = talloc_asprintf(tmp_ctx, fmt, SYSDB_NAME, name); +- } else { +- filter = talloc_strdup(tmp_ctx, name); +- } +- if (filter == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory\n")); +- ret = ENOMEM; +- goto done; +- } ++ filter = talloc_strdup(tmp_ctx, sanitized); ++ } ++ if (filter == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory\n")); ++ ret = ENOMEM; ++ goto done; + } + +- talloc_free(*_filter); +- *_filter = talloc_steal(tctx, filter); + ret = EOK; ++ + done: ++ if (ret == EOK) { ++ talloc_free(*_filter); ++ *_filter = talloc_steal(tctx, filter); ++ } ++ + talloc_free(tmp_ctx); + return ret; + +-- +1.8.4.2 + diff --git a/SOURCES/0037-Add-sysdb_attrs_add_lc_name_alias.patch b/SOURCES/0037-Add-sysdb_attrs_add_lc_name_alias.patch new file mode 100644 index 0000000..96db4f3 --- /dev/null +++ b/SOURCES/0037-Add-sysdb_attrs_add_lc_name_alias.patch @@ -0,0 +1,107 @@ +From b1f74ee745aa84f53fe330d55fafb9810012f875 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 28 Nov 2013 11:28:39 +0100 +Subject: [PATCH 37/41] Add sysdb_attrs_add_lc_name_alias + +--- + src/db/sysdb.c | 22 ++++++++++++++++++++++ + src/db/sysdb.h | 2 ++ + src/tests/sysdb-tests.c | 29 +++++++++++++++++++++++++++++ + 3 files changed, 53 insertions(+) + +diff --git a/src/db/sysdb.c b/src/db/sysdb.c +index da5dbe84c2415025a188544f4b4c944888f07888..2a4be58008fc1164765db26aaba3886071448d30 100644 +--- a/src/db/sysdb.c ++++ b/src/db/sysdb.c +@@ -618,6 +618,28 @@ int sysdb_attrs_add_time_t(struct sysdb_attrs *attrs, + return ret; + } + ++int sysdb_attrs_add_lc_name_alias(struct sysdb_attrs *attrs, ++ const char *value) ++{ ++ char *lc_str; ++ int ret; ++ ++ if (attrs == NULL || value == NULL) { ++ return EINVAL; ++ } ++ ++ lc_str = sss_tc_utf8_str_tolower(attrs, value); ++ if (lc_str == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Cannot convert name to lowercase\n")); ++ return ENOMEM; ++ } ++ ++ ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lc_str); ++ talloc_free(lc_str); ++ ++ return ret; ++} ++ + int sysdb_attrs_copy_values(struct sysdb_attrs *src, + struct sysdb_attrs *dst, + const char *name) +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index 4d5ef0b4794a85aa7fbc8f261d42eddd1043284e..f3358d642efd1c13203061c43e455a5c26c72740 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -274,6 +274,8 @@ int sysdb_attrs_add_uint32(struct sysdb_attrs *attrs, + const char *name, uint32_t value); + int sysdb_attrs_add_time_t(struct sysdb_attrs *attrs, + const char *name, time_t value); ++int sysdb_attrs_add_lc_name_alias(struct sysdb_attrs *attrs, ++ const char *value); + int sysdb_attrs_copy_values(struct sysdb_attrs *src, + struct sysdb_attrs *dst, + const char *name); +diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c +index ddbf6f28fd5024945fedcb3c6e2122948c4f1459..63ffac82e15849e5f6534462ce7c58b183412acc 100644 +--- a/src/tests/sysdb-tests.c ++++ b/src/tests/sysdb-tests.c +@@ -4422,6 +4422,33 @@ START_TEST(test_sysdb_svc_remove_alias) + } + END_TEST + ++#define LC_NAME_ALIAS_TEST_VAL "TeSt VaLuE" ++#define LC_NAME_ALIAS_CHECK_VAL "test value" ++START_TEST(test_sysdb_attrs_add_lc_name_alias) ++{ ++ int ret; ++ struct sysdb_attrs *attrs; ++ const char *str; ++ ++ ret = sysdb_attrs_add_lc_name_alias(NULL, NULL); ++ fail_unless(ret == EINVAL, "EINVAL not returned for NULL input"); ++ ++ attrs = sysdb_new_attrs(NULL); ++ fail_unless(attrs != NULL, "sysdb_new_attrs failed"); ++ ++ ret = sysdb_attrs_add_lc_name_alias(attrs, LC_NAME_ALIAS_TEST_VAL); ++ fail_unless(ret == EOK, "sysdb_attrs_add_lc_name_alias failed"); ++ ++ ret = sysdb_attrs_get_string(attrs, SYSDB_NAME_ALIAS, &str); ++ fail_unless(ret == EOK, "sysdb_attrs_get_string failed"); ++ fail_unless(strcmp(str, LC_NAME_ALIAS_CHECK_VAL) == 0, ++ "Unexpected value, expected [%s], got [%s]", ++ LC_NAME_ALIAS_CHECK_VAL, str); ++ ++ talloc_free(attrs); ++} ++END_TEST ++ + START_TEST(test_sysdb_has_enumerated) + { + errno_t ret; +@@ -5188,6 +5215,8 @@ Suite *create_sysdb_suite(void) + tcase_add_test(tc_sysdb, test_sysdb_store_services); + tcase_add_test(tc_sysdb, test_sysdb_svc_remove_alias); + ++ tcase_add_test(tc_sysdb, test_sysdb_attrs_add_lc_name_alias); ++ + /* Add all test cases to the test suite */ + suite_add_tcase(s, tc_sysdb); + +-- +1.8.4.2 + diff --git a/SOURCES/0038-Use-sysdb_attrs_add_lc_name_alias-to-add-case-insens.patch b/SOURCES/0038-Use-sysdb_attrs_add_lc_name_alias-to-add-case-insens.patch new file mode 100644 index 0000000..0679bf7 --- /dev/null +++ b/SOURCES/0038-Use-sysdb_attrs_add_lc_name_alias-to-add-case-insens.patch @@ -0,0 +1,195 @@ +From e90d014c1ce95a30f4be2383a4b4f47ad21c5601 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 28 Nov 2013 12:31:24 +0100 +Subject: [PATCH 38/41] Use sysdb_attrs_add_lc_name_alias to add + case-insensitive alias + +--- + src/providers/ipa/ipa_s2n_exop.c | 27 ++++++--------------------- + src/providers/ldap/sdap_async.c | 21 ++++++++++++++++----- + src/providers/proxy/proxy_id.c | 20 ++------------------ + src/providers/proxy/proxy_netgroup.c | 10 +--------- + src/responder/pac/pacsrv_utils.c | 4 ++-- + 5 files changed, 27 insertions(+), 55 deletions(-) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index d8506aaae2582f496033212e5abeef753244c21a..8bad16d42facac3a585a4fdf579c3d2bb913dd71 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -651,7 +651,6 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq) + struct sysdb_attrs *user_attrs = NULL; + struct sysdb_attrs *group_attrs = NULL; + char *name; +- char *lc_name; + char *realm; + char *upn; + struct berval *bv_req = NULL; +@@ -767,16 +766,10 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq) + goto done; + } + +- lc_name = sss_tc_utf8_str_tolower(user_attrs, name); +- if (lc_name == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot convert name to lowercase\n")); +- ret = ENOMEM; +- goto done; +- } +- +- ret = sysdb_attrs_add_string(user_attrs, SYSDB_NAME_ALIAS, lc_name); ++ ret = sysdb_attrs_add_lc_name_alias(user_attrs, name); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_add_string failed.\n")); ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("sysdb_attrs_add_lc_name_alias failed.\n")); + goto done; + } + +@@ -852,18 +845,10 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq) + goto done; + } + +- lc_name = sss_tc_utf8_str_tolower(group_attrs, name); +- if (lc_name == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- ("Cannot convert name to lowercase\n")); +- ret = ENOMEM; +- goto done; +- } +- +- ret = sysdb_attrs_add_string(group_attrs, SYSDB_NAME_ALIAS, +- lc_name); ++ ret = sysdb_attrs_add_lc_name_alias(group_attrs, name); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_add_string failed.\n")); ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("sysdb_attrs_add_lc_name_alias failed.\n")); + goto done; + } + +diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c +index f5cc962b34c8ef5e8c8dc9cf90b77d782b389032..e905d2dd6d539baadcd29aa0869ca04e845947e2 100644 +--- a/src/providers/ldap/sdap_async.c ++++ b/src/providers/ldap/sdap_async.c +@@ -2318,12 +2318,23 @@ sdap_save_all_names(const char *name, + goto done; + } + +- ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, domname); +- if (ret) { +- DEBUG(SSSDBG_OP_FAILURE, ("Failed to add alias [%s] into the " +- "attribute list\n", aliases[i])); +- goto done; ++ if (lowercase) { ++ ret = sysdb_attrs_add_lc_name_alias(attrs, domname); ++ if (ret) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Failed to add lower-cased version " ++ "of alias [%s] into the " ++ "attribute list\n", aliases[i])); ++ goto done; ++ } ++ } else { ++ ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, domname); ++ if (ret) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Failed to add alias [%s] into the " ++ "attribute list\n", aliases[i])); ++ goto done; ++ } + } ++ + } + + ret = EOK; +diff --git a/src/providers/proxy/proxy_id.c b/src/providers/proxy/proxy_id.c +index 963aad2d0676a665d69be2ea2996ad49cb2bacc6..2c01aad5ae86e11d22383d6b618073ef8e9d6dbb 100644 +--- a/src/providers/proxy/proxy_id.c ++++ b/src/providers/proxy/proxy_id.c +@@ -223,7 +223,6 @@ static int save_user(struct sysdb_ctx *sysdb, struct sss_domain_info *domain, + { + const char *shell; + const char *gecos; +- char *lower; + struct sysdb_attrs *attrs = NULL; + errno_t ret; + const char *cased_alias; +@@ -249,14 +248,7 @@ static int save_user(struct sysdb_ctx *sysdb, struct sss_domain_info *domain, + } + + if (lowercase) { +- lower = sss_tc_utf8_str_tolower(attrs, pwd->pw_name); +- if (!lower) { +- DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot convert name to lowercase\n")); +- talloc_zfree(attrs); +- return ENOMEM; +- } +- +- ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lower); ++ ret = sysdb_attrs_add_lc_name_alias(attrs, pwd->pw_name); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not add name alias\n")); + talloc_zfree(attrs); +@@ -540,7 +532,6 @@ static int save_group(struct sysdb_ctx *sysdb, struct sss_domain_info *dom, + { + errno_t ret, sret; + struct sysdb_attrs *attrs = NULL; +- char *lower; + const char *cased_alias; + TALLOC_CTX *tmp_ctx; + time_t now = time(NULL); +@@ -595,14 +586,7 @@ static int save_group(struct sysdb_ctx *sysdb, struct sss_domain_info *dom, + } + + if (dom->case_sensitive == false) { +- lower = sss_tc_utf8_str_tolower(attrs, grp->gr_name); +- if (!lower) { +- DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot convert name to lowercase\n")); +- ret = ENOMEM; +- goto done; +- } +- +- ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lower); ++ ret = sysdb_attrs_add_lc_name_alias(attrs, grp->gr_name); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not add name alias\n")); + ret = ENOMEM; +diff --git a/src/providers/proxy/proxy_netgroup.c b/src/providers/proxy/proxy_netgroup.c +index 04a0b18d7079aa15d04562ee5c785caed4456fb5..bb0bc171b8c3688a92c14f711669f752653a39f0 100644 +--- a/src/providers/proxy/proxy_netgroup.c ++++ b/src/providers/proxy/proxy_netgroup.c +@@ -74,17 +74,9 @@ static errno_t save_netgroup(struct sysdb_ctx *sysdb, + uint64_t cache_timeout) + { + errno_t ret; +- char *lower; + + if (lowercase) { +- lower = sss_tc_utf8_str_tolower(NULL, name); +- if (!lower) { +- DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot convert name to lowercase\n")); +- return ENOMEM; +- } +- +- ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lower); +- talloc_free(lower); ++ ret = sysdb_attrs_add_lc_name_alias(attrs, name); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not add name alias\n")); + return ret; +diff --git a/src/responder/pac/pacsrv_utils.c b/src/responder/pac/pacsrv_utils.c +index 30055a1345b7d943e6adf822438263c92e53b51a..6a6ea2e357483c68533c501b93c16383ee644048 100644 +--- a/src/responder/pac/pacsrv_utils.c ++++ b/src/responder/pac/pacsrv_utils.c +@@ -483,9 +483,9 @@ errno_t get_pwd_from_pac(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, pwd->pw_name); ++ ret = sysdb_attrs_add_lc_name_alias(attrs, pwd->pw_name); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_add_string failed.\n")); ++ DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_add_lc_name_alias failed.\n")); + goto done; + } + +-- +1.8.4.2 + diff --git a/SOURCES/0039-Use-lower-case-name-for-case-insensitive-searches.patch b/SOURCES/0039-Use-lower-case-name-for-case-insensitive-searches.patch new file mode 100644 index 0000000..ac7d540 --- /dev/null +++ b/SOURCES/0039-Use-lower-case-name-for-case-insensitive-searches.patch @@ -0,0 +1,356 @@ +From b0af402f8201d28922892b18792474f4ec546f36 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 13 Dec 2013 11:44:59 +0100 +Subject: [PATCH 39/41] Use lower-case name for case-insensitive searches + +The patch makes sure that a completely lower-cased version of a fully +qualified name is used for case insensitive searches. Currently there +are code paths where the domain name was used as configured and was not +lower-cased. + +To make sure this patch does not break with old entries in the cache or +case sensitive domains a third template was added to the related filters +templates which is either filled with a completely lower-cased version or +with the old version. The other two template values are unchanged. +--- + src/db/sysdb.h | 10 +++++----- + src/db/sysdb_ops.c | 8 +++++--- + src/db/sysdb_search.c | 30 ++++++++++++++++++++-------- + src/responder/pam/pam_LOCAL_domain.c | 4 ++-- + src/tests/cmocka/test_utils.c | 38 ++++++++++++++++++++++++++++++++++++ + src/util/sss_tc_utf8.c | 30 ++++++++++++++++++++++++++++ + src/util/util.h | 6 ++++++ + 7 files changed, 108 insertions(+), 18 deletions(-) + +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index f3358d642efd1c13203061c43e455a5c26c72740..f1ed8158ccff70f85940d63f247e23451c22c30f 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -144,23 +144,23 @@ + #define SYSDB_NC "objectclass="SYSDB_NETGROUP_CLASS + #define SYSDB_MPGC "|("SYSDB_UC")("SYSDB_GC")" + +-#define SYSDB_PWNAM_FILTER "(&("SYSDB_UC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))" ++#define SYSDB_PWNAM_FILTER "(&("SYSDB_UC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))" + #define SYSDB_PWUID_FILTER "(&("SYSDB_UC")("SYSDB_UIDNUM"=%lu))" + #define SYSDB_PWSID_FILTER "(&("SYSDB_UC")("SYSDB_SID_STR"=%s))" + #define SYSDB_PWENT_FILTER "("SYSDB_UC")" + +-#define SYSDB_GRNAM_FILTER "(&("SYSDB_GC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))" ++#define SYSDB_GRNAM_FILTER "(&("SYSDB_GC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))" + #define SYSDB_GRGID_FILTER "(&("SYSDB_GC")("SYSDB_GIDNUM"=%lu))" + #define SYSDB_GRSID_FILTER "(&("SYSDB_GC")("SYSDB_SID_STR"=%s))" + #define SYSDB_GRENT_FILTER "("SYSDB_GC")" +-#define SYSDB_GRNAM_MPG_FILTER "(&("SYSDB_MPGC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))" ++#define SYSDB_GRNAM_MPG_FILTER "(&("SYSDB_MPGC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))" + #define SYSDB_GRGID_MPG_FILTER "(&("SYSDB_MPGC")("SYSDB_GIDNUM"=%lu))" + #define SYSDB_GRENT_MPG_FILTER "("SYSDB_MPGC")" + + #define SYSDB_INITGR_FILTER "(&("SYSDB_GC")("SYSDB_GIDNUM"=*))" + +-#define SYSDB_NETGR_FILTER "(&("SYSDB_NC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))" +-#define SYSDB_NETGR_TRIPLES_FILTER "(|("SYSDB_NAME"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_MEMBEROF"=%s))" ++#define SYSDB_NETGR_FILTER "(&("SYSDB_NC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))" ++#define SYSDB_NETGR_TRIPLES_FILTER "(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_MEMBEROF"=%s))" + + #define SYSDB_SID_FILTER "(&(|("SYSDB_UC")("SYSDB_GC"))("SYSDB_SID_STR"=%s))" + +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index 890bf1eb3cc5fc0b6eb6f7a145aee6d87945cd8d..a5dfd443c84b87609881f9042b3e82958c3b0e5f 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -305,6 +305,7 @@ int sysdb_search_user_by_name(TALLOC_CTX *mem_ctx, + struct ldb_dn *basedn; + size_t msgs_count = 0; + char *sanitized_name; ++ char *lc_sanitized_name; + char *filter; + int ret; + +@@ -320,13 +321,14 @@ int sysdb_search_user_by_name(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = sss_filter_sanitize(tmp_ctx, name, &sanitized_name); ++ ret = sss_filter_sanitize_for_dom(tmp_ctx, name, domain, &sanitized_name, ++ &lc_sanitized_name); + if (ret != EOK) { + goto done; + } + +- filter = talloc_asprintf(tmp_ctx, SYSDB_PWNAM_FILTER, sanitized_name, +- sanitized_name); ++ filter = talloc_asprintf(tmp_ctx, SYSDB_PWNAM_FILTER, lc_sanitized_name, ++ sanitized_name, sanitized_name); + if (!filter) { + ret = ENOMEM; + goto done; +diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c +index d15fc73ce2272bff53650ae9dd0dbdad99a849e6..308710a2c780b9a709930b7d8a16a0c07471aff7 100644 +--- a/src/db/sysdb_search.c ++++ b/src/db/sysdb_search.c +@@ -38,6 +38,7 @@ int sysdb_getpwnam(TALLOC_CTX *mem_ctx, + struct ldb_dn *base_dn; + struct ldb_result *res; + char *sanitized_name; ++ char *lc_sanitized_name; + const char *src_name; + int ret; + +@@ -61,13 +62,15 @@ int sysdb_getpwnam(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = sss_filter_sanitize(tmp_ctx, src_name, &sanitized_name); ++ ret = sss_filter_sanitize_for_dom(tmp_ctx, src_name, domain, ++ &sanitized_name, &lc_sanitized_name); + if (ret != EOK) { + goto done; + } + + ret = ldb_search(sysdb->ldb, tmp_ctx, &res, base_dn, + LDB_SCOPE_SUBTREE, attrs, SYSDB_PWNAM_FILTER, ++ lc_sanitized_name, + sanitized_name, sanitized_name); + if (ret) { + ret = sysdb_error_to_errno(ret); +@@ -214,6 +217,7 @@ int sysdb_getgrnam(TALLOC_CTX *mem_ctx, + struct ldb_dn *base_dn; + struct ldb_result *res; + const char *src_name; ++ char *lc_sanitized_name; + int ret; + + tmp_ctx = talloc_new(NULL); +@@ -243,14 +247,15 @@ int sysdb_getgrnam(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = sss_filter_sanitize(tmp_ctx, src_name, &sanitized_name); ++ ret = sss_filter_sanitize_for_dom(tmp_ctx, src_name, domain, ++ &sanitized_name, &lc_sanitized_name); + if (ret != EOK) { + goto done; + } + + ret = ldb_search(sysdb->ldb, tmp_ctx, &res, base_dn, + LDB_SCOPE_SUBTREE, attrs, fmt_filter, +- sanitized_name, sanitized_name); ++ lc_sanitized_name, sanitized_name, sanitized_name); + if (ret) { + ret = sysdb_error_to_errno(ret); + goto done; +@@ -481,6 +486,7 @@ int sysdb_get_user_attr(TALLOC_CTX *mem_ctx, + struct ldb_dn *base_dn; + struct ldb_result *res; + char *sanitized_name; ++ char *lc_sanitized_name; + int ret; + + tmp_ctx = talloc_new(NULL); +@@ -495,14 +501,15 @@ int sysdb_get_user_attr(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = sss_filter_sanitize(tmp_ctx, name, &sanitized_name); ++ ret = sss_filter_sanitize_for_dom(tmp_ctx, name, domain, &sanitized_name, ++ &lc_sanitized_name); + if (ret != EOK) { + goto done; + } + + ret = ldb_search(sysdb->ldb, tmp_ctx, &res, base_dn, + LDB_SCOPE_SUBTREE, attributes, +- SYSDB_PWNAM_FILTER, sanitized_name, ++ SYSDB_PWNAM_FILTER, lc_sanitized_name, sanitized_name, + sanitized_name); + if (ret) { + ret = sysdb_error_to_errno(ret); +@@ -785,6 +792,7 @@ errno_t sysdb_getnetgr(TALLOC_CTX *mem_ctx, + struct ldb_dn *base_dn; + struct ldb_result *result; + char *sanitized_netgroup; ++ char *lc_sanitized_netgroup; + char *netgroup_dn; + int lret; + errno_t ret; +@@ -802,7 +810,9 @@ errno_t sysdb_getnetgr(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = sss_filter_sanitize(tmp_ctx, netgroup, &sanitized_netgroup); ++ ret = sss_filter_sanitize_for_dom(tmp_ctx, netgroup, domain, ++ &sanitized_netgroup, ++ &lc_sanitized_netgroup); + if (ret != EOK) { + goto done; + } +@@ -816,7 +826,7 @@ errno_t sysdb_getnetgr(TALLOC_CTX *mem_ctx, + + lret = ldb_search(sysdb->ldb, tmp_ctx, &result, base_dn, + LDB_SCOPE_SUBTREE, attrs, +- SYSDB_NETGR_TRIPLES_FILTER, ++ SYSDB_NETGR_TRIPLES_FILTER, lc_sanitized_netgroup, + sanitized_netgroup, sanitized_netgroup, + netgroup_dn); + ret = sysdb_error_to_errno(lret); +@@ -843,6 +853,7 @@ int sysdb_get_netgroup_attr(TALLOC_CTX *mem_ctx, + struct ldb_dn *base_dn; + struct ldb_result *result; + char *sanitized_netgroup; ++ char *lc_sanitized_netgroup; + int ret; + + tmp_ctx = talloc_new(NULL); +@@ -857,7 +868,9 @@ int sysdb_get_netgroup_attr(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = sss_filter_sanitize(tmp_ctx, netgrname, &sanitized_netgroup); ++ ret = sss_filter_sanitize_for_dom(tmp_ctx, netgrname, domain, ++ &sanitized_netgroup, ++ &lc_sanitized_netgroup); + if (ret != EOK) { + goto done; + } +@@ -865,6 +878,7 @@ int sysdb_get_netgroup_attr(TALLOC_CTX *mem_ctx, + ret = ldb_search(sysdb->ldb, tmp_ctx, &result, base_dn, + LDB_SCOPE_SUBTREE, attributes, + SYSDB_NETGR_FILTER, ++ lc_sanitized_netgroup, + sanitized_netgroup, + sanitized_netgroup); + if (ret) { +diff --git a/src/responder/pam/pam_LOCAL_domain.c b/src/responder/pam/pam_LOCAL_domain.c +index e7776cba3b74a86ef63dad30f08b4436a59a89be..49ddbcda39468e6a4f2065d97df309ce881b6aa4 100644 +--- a/src/responder/pam/pam_LOCAL_domain.c ++++ b/src/responder/pam/pam_LOCAL_domain.c +@@ -258,12 +258,12 @@ int LOCAL_pam_handler(struct pam_auth_req *preq) + + if (res->count < 1) { + DEBUG(4, ("No user found with filter ["SYSDB_PWNAM_FILTER"]\n", +- pd->user, pd->user)); ++ pd->user, pd->user, pd->user)); + pd->pam_status = PAM_USER_UNKNOWN; + goto done; + } else if (res->count > 1) { + DEBUG(4, ("More than one object found with filter ["SYSDB_PWNAM_FILTER"]\n", +- pd->user, pd->user)); ++ pd->user, pd->user, pd->user)); + lreq->error = EFAULT; + goto done; + } +diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c +index 1be59ab69cfa632010c5e1700dc79f59b6f48fde..61e8e9f07ca2f6772b12fe602acb3d2872b39c10 100644 +--- a/src/tests/cmocka/test_utils.c ++++ b/src/tests/cmocka/test_utils.c +@@ -177,6 +177,41 @@ void test_find_subdomain_by_sid_missing_sid(void **state) + } + } + ++#define TEST_SANITIZE_INPUT "TestUser@Test.Domain" ++#define TEST_SANITIZE_LC_INPUT "testuser@test.domain" ++ ++void test_sss_filter_sanitize_for_dom(void **state) ++{ ++ struct dom_list_test_ctx *test_ctx; ++ int ret; ++ char *sanitized; ++ char *lc_sanitized; ++ struct sss_domain_info *dom; ++ ++ test_ctx = talloc_get_type(*state, struct dom_list_test_ctx); ++ dom = test_ctx->dom_list; ++ ++ dom->case_sensitive = true; ++ ++ ret = sss_filter_sanitize_for_dom(test_ctx, TEST_SANITIZE_INPUT, dom, ++ &sanitized, &lc_sanitized); ++ assert_int_equal(ret, EOK); ++ assert_string_equal(sanitized, TEST_SANITIZE_INPUT); ++ assert_string_equal(lc_sanitized, TEST_SANITIZE_INPUT); ++ talloc_free(sanitized); ++ talloc_free(lc_sanitized); ++ ++ dom->case_sensitive = false; ++ ++ ret = sss_filter_sanitize_for_dom(test_ctx, TEST_SANITIZE_INPUT, dom, ++ &sanitized, &lc_sanitized); ++ assert_int_equal(ret, EOK); ++ assert_string_equal(sanitized, TEST_SANITIZE_INPUT); ++ assert_string_equal(lc_sanitized, TEST_SANITIZE_LC_INPUT); ++ talloc_free(sanitized); ++ talloc_free(lc_sanitized); ++} ++ + int main(int argc, const char *argv[]) + { + poptContext pc; +@@ -194,6 +229,9 @@ int main(int argc, const char *argv[]) + setup_dom_list, teardown_dom_list), + unit_test_setup_teardown(test_find_subdomain_by_sid_missing_sid, + setup_dom_list, teardown_dom_list), ++ ++ unit_test_setup_teardown(test_sss_filter_sanitize_for_dom, ++ setup_dom_list, teardown_dom_list), + }; + + /* Set debug level to invalid value so we can deside if -d 0 was used. */ +diff --git a/src/util/sss_tc_utf8.c b/src/util/sss_tc_utf8.c +index 6a976211f7b77d329ba3261577c43466406f3da9..e1426a44f3518783dca4f22cd6016cdde92d0f56 100644 +--- a/src/util/sss_tc_utf8.c ++++ b/src/util/sss_tc_utf8.c +@@ -55,3 +55,33 @@ sss_tc_utf8_tolower(TALLOC_CTX *mem_ctx, const uint8_t *s, size_t len, size_t *_ + return ret; + } + ++errno_t sss_filter_sanitize_for_dom(TALLOC_CTX *mem_ctx, ++ const char *input, ++ struct sss_domain_info *dom, ++ char **sanitized, ++ char **lc_sanitized) ++{ ++ int ret; ++ ++ ret = sss_filter_sanitize(mem_ctx, input, sanitized); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("sss_filter_sanitize failed.\n")); ++ return ret; ++ } ++ ++ if (dom->case_sensitive) { ++ *lc_sanitized = talloc_strdup(mem_ctx, *sanitized); ++ } else { ++ *lc_sanitized = sss_tc_utf8_str_tolower(mem_ctx, *sanitized); ++ } ++ ++ if (*lc_sanitized == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ("%s failed.\n", ++ dom->case_sensitive ? ++ "talloc_strdup" : ++ "sss_tc_utf8_str_tolower")); ++ return ENOMEM; ++ } ++ ++ return EOK; ++} +diff --git a/src/util/util.h b/src/util/util.h +index 058c1c27986f9749a18dd4c92ddb9428349a1dac..3334476ab83a137d957765fe2c9afba4ad0d014c 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -484,6 +484,12 @@ errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx, + const char *input, + char **sanitized); + ++errno_t sss_filter_sanitize_for_dom(TALLOC_CTX *mem_ctx, ++ const char *input, ++ struct sss_domain_info *dom, ++ char **sanitized, ++ char **lc_sanitized); ++ + char * + sss_escape_ip_address(TALLOC_CTX *mem_ctx, int family, const char *addr); + +-- +1.8.4.2 + diff --git a/SOURCES/0040-Add-new-option-ldap_group_type.patch b/SOURCES/0040-Add-new-option-ldap_group_type.patch new file mode 100644 index 0000000..0f0f27f --- /dev/null +++ b/SOURCES/0040-Add-new-option-ldap_group_type.patch @@ -0,0 +1,177 @@ +From fd56e9302454869c636c2e40322eec52391b4c4f Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 9 Dec 2013 12:17:43 +0100 +Subject: [PATCH 40/41] Add new option ldap_group_type + +--- + src/config/SSSDConfig/__init__.py.in | 1 + + src/config/etc/sssd.api.d/sssd-ad.conf | 1 + + src/config/etc/sssd.api.d/sssd-ipa.conf | 1 + + src/config/etc/sssd.api.d/sssd-ldap.conf | 1 + + src/db/sysdb.h | 1 + + src/man/sssd-ldap.5.xml | 21 +++++++++++++++++++++ + src/providers/ad/ad_opts.h | 1 + + src/providers/ipa/ipa_opts.h | 1 + + src/providers/ldap/ldap_opts.h | 3 +++ + src/providers/ldap/sdap.h | 1 + + 10 files changed, 32 insertions(+) + +diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in +index af5903c65e05411d5773f1f9b1f742fdb832433c..8563a91e7afe680edfa0b9dd951ac7ab5a0fd3b0 100644 +--- a/src/config/SSSDConfig/__init__.py.in ++++ b/src/config/SSSDConfig/__init__.py.in +@@ -284,6 +284,7 @@ option_strings = { + 'ldap_group_uuid' : _('Group UUID attribute'), + 'ldap_group_objectsid' : _("objectSID attribute"), + 'ldap_group_modify_timestamp' : _('Modification time attribute for groups'), ++ 'ldap_group_type' : _('Type of the group and other flags'), + #replaced by ldap_entry_usn# 'ldap_group_entry_usn' : _('entryUSN attribute'), + 'ldap_group_nesting_level' : _('Maximum nesting level SSSd will follow'), + +diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf +index 00e8968d2b6dab33a39005f11a497cb3e2185302..6b136f2ec88614092cf1ceb4e2cea79db064d468 100644 +--- a/src/config/etc/sssd.api.d/sssd-ad.conf ++++ b/src/config/etc/sssd.api.d/sssd-ad.conf +@@ -91,6 +91,7 @@ ldap_group_uuid = str, None, false + ldap_group_objectsid = str, None, false + ldap_group_modify_timestamp = str, None, false + ldap_group_entry_usn = str, None, false ++ldap_group_type = int, None, false + ldap_force_upper_case_realm = bool, None, false + ldap_group_nesting_level = int, None, false + ldap_netgroup_search_base = str, None, false +diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf +index bc14fbe3d4153bd7a7ca4ffe0351edf0b8c02ee4..a94b5f09b073c050bff597d66c8164e4f38a9bfe 100644 +--- a/src/config/etc/sssd.api.d/sssd-ipa.conf ++++ b/src/config/etc/sssd.api.d/sssd-ipa.conf +@@ -98,6 +98,7 @@ ldap_group_uuid = str, None, false + ldap_group_objectsid = str, None, false + ldap_group_modify_timestamp = str, None, false + ldap_group_entry_usn = str, None, false ++ldap_group_type = int, None, false + ldap_force_upper_case_realm = bool, None, false + ldap_group_nesting_level = int, None, false + ldap_netgroup_search_base = str, None, false +diff --git a/src/config/etc/sssd.api.d/sssd-ldap.conf b/src/config/etc/sssd.api.d/sssd-ldap.conf +index eb239664c49e9d516468c184dfeac190ecf8ddd8..4f5a06800d4ba4dacea08285b9db3abdc44df8f3 100644 +--- a/src/config/etc/sssd.api.d/sssd-ldap.conf ++++ b/src/config/etc/sssd.api.d/sssd-ldap.conf +@@ -93,6 +93,7 @@ ldap_group_uuid = str, None, false + ldap_group_objectsid = str, None, false + ldap_group_modify_timestamp = str, None, false + ldap_group_entry_usn = str, None, false ++ldap_group_type = int, None, false + ldap_group_nesting_level = int, None, false + ldap_force_upper_case_realm = bool, None, false + ldap_netgroup_search_base = str, None, false +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index f1ed8158ccff70f85940d63f247e23451c22c30f..9bcd7be0960fcfa390fb9150594ea84880a14eea 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -76,6 +76,7 @@ + #define SYSDB_POSIX "isPosix" + #define SYSDB_USER_CATEGORY "userCategory" + #define SYSDB_HOST_CATEGORY "hostCategory" ++#define SYSDB_GROUP_TYPE "groupType" + + #define SYSDB_GECOS "gecos" + #define SYSDB_LAST_LOGIN "lastLogin" +diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml +index efe22c9d22adccb244fe99603a74eb93dbddea7f..cc58544c38e8ffa779f0a1b22a69caaf3f193ce1 100644 +--- a/src/man/sssd-ldap.5.xml ++++ b/src/man/sssd-ldap.5.xml +@@ -849,6 +849,27 @@ + + + ++ ldap_group_type (integer) ++ ++ ++ The LDAP attribute that contains an integer value ++ indicating the type of the group and maybe other ++ flags. ++ ++ ++ This attribute is currently only used by the AD ++ provider to determine if a group is a domain local ++ groups and has to be filtered out for trusted ++ domains. ++ ++ ++ Default: groupType in the AD provider, othewise not ++ set ++ ++ ++ ++ ++ + ldap_group_nesting_level (integer) + + +diff --git a/src/providers/ad/ad_opts.h b/src/providers/ad/ad_opts.h +index 5b7b1c89f5f45d7cc744a955e6378390948a99fd..0deeec99a9c1944301b80d1f25713b5d0504e88c 100644 +--- a/src/providers/ad/ad_opts.h ++++ b/src/providers/ad/ad_opts.h +@@ -209,6 +209,7 @@ struct sdap_attr_map ad_2008r2_group_map[] = { + { "ldap_group_objectsid", "objectSID", SYSDB_SID, NULL }, + { "ldap_group_modify_timestamp", "whenChanged", SYSDB_ORIG_MODSTAMP, NULL }, + { "ldap_group_entry_usn", SDAP_AD_USN, SYSDB_USN, NULL }, ++ { "ldap_group_type", "groupType", SYSDB_GROUP_TYPE, NULL }, + SDAP_ATTR_MAP_TERMINATOR + }; + +diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h +index 5ec36c550b166e07a9ed2f2c31474c55d0ecdaee..27dc3e2f977383836c18cb824abceb03c9e9056c 100644 +--- a/src/providers/ipa/ipa_opts.h ++++ b/src/providers/ipa/ipa_opts.h +@@ -209,6 +209,7 @@ struct sdap_attr_map ipa_group_map[] = { + { "ldap_group_objectsid", "ipaNTSecurityIdentifier", SYSDB_SID_STR, NULL }, + { "ldap_group_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL }, + { "ldap_group_entry_usn", NULL, SYSDB_USN, NULL }, ++ { "ldap_group_type", NULL, SYSDB_GROUP_TYPE, NULL }, + SDAP_ATTR_MAP_TERMINATOR + }; + +diff --git a/src/providers/ldap/ldap_opts.h b/src/providers/ldap/ldap_opts.h +index a6c821f3ac3ad951a3b45168b298b96fefb96b60..9593dfd30a81db60b7358c66975871507340aa4b 100644 +--- a/src/providers/ldap/ldap_opts.h ++++ b/src/providers/ldap/ldap_opts.h +@@ -187,6 +187,7 @@ struct sdap_attr_map rfc2307_group_map[] = { + { "ldap_group_objectsid", NULL, SYSDB_SID, NULL }, + { "ldap_group_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL }, + { "ldap_group_entry_usn", NULL, SYSDB_USN, NULL }, ++ { "ldap_group_type", NULL, SYSDB_GROUP_TYPE, NULL }, + SDAP_ATTR_MAP_TERMINATOR + }; + +@@ -241,6 +242,7 @@ struct sdap_attr_map rfc2307bis_group_map[] = { + { "ldap_group_objectsid", NULL, SYSDB_SID, NULL }, + { "ldap_group_modify_timestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL }, + { "ldap_group_entry_usn", NULL, SYSDB_USN, NULL }, ++ { "ldap_group_type", NULL, SYSDB_GROUP_TYPE, NULL }, + SDAP_ATTR_MAP_TERMINATOR + }; + +@@ -293,6 +295,7 @@ struct sdap_attr_map gen_ad2008r2_group_map[] = { + { "ldap_group_objectsid", "objectSID", SYSDB_SID, NULL }, + { "ldap_group_modify_timestamp", "whenChanged", SYSDB_ORIG_MODSTAMP, NULL }, + { "ldap_group_entry_usn", SDAP_AD_USN, SYSDB_USN, NULL }, ++ { "ldap_group_type", NULL, SYSDB_GROUP_TYPE, NULL }, + SDAP_ATTR_MAP_TERMINATOR + }; + +diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h +index a7ea94eb810a96b61862bd8cc6fcd800c3e8e0cb..d408be0a65cdd840d8379b7af4c0ab1e67ed3f5c 100644 +--- a/src/providers/ldap/sdap.h ++++ b/src/providers/ldap/sdap.h +@@ -296,6 +296,7 @@ enum sdap_group_attrs { + SDAP_AT_GROUP_OBJECTSID, + SDAP_AT_GROUP_MODSTAMP, + SDAP_AT_GROUP_USN, ++ SDAP_AT_GROUP_TYPE, + + SDAP_OPTS_GROUP /* attrs counter */ + }; +-- +1.8.4.2 + diff --git a/SOURCES/0041-Add-sysdb_attrs_get_int32_t.patch b/SOURCES/0041-Add-sysdb_attrs_get_int32_t.patch new file mode 100644 index 0000000..04d3a63 --- /dev/null +++ b/SOURCES/0041-Add-sysdb_attrs_get_int32_t.patch @@ -0,0 +1,63 @@ +From 91c41b25f3d2e5a6074d1dd73c3355f9159d2cae Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 10 Dec 2013 10:14:02 +0100 +Subject: [PATCH 41/41] Add sysdb_attrs_get_int32_t + +--- + src/db/sysdb.c | 26 ++++++++++++++++++++++++++ + src/db/sysdb.h | 2 ++ + 2 files changed, 28 insertions(+) + +diff --git a/src/db/sysdb.c b/src/db/sysdb.c +index 2a4be58008fc1164765db26aaba3886071448d30..0e07ed60858298a1ac85d06146ccb98c5899a705 100644 +--- a/src/db/sysdb.c ++++ b/src/db/sysdb.c +@@ -366,6 +366,32 @@ int sysdb_attrs_get_string(struct sysdb_attrs *attrs, const char *name, + return EOK; + } + ++int sysdb_attrs_get_int32_t(struct sysdb_attrs *attrs, const char *name, ++ int32_t *value) ++{ ++ struct ldb_message_element *el; ++ int ret; ++ char *endptr; ++ int32_t val; ++ ++ ret = sysdb_attrs_get_el_ext(attrs, name, false, &el); ++ if (ret) { ++ return ret; ++ } ++ ++ if (el->num_values != 1) { ++ return ERANGE; ++ } ++ ++ errno = 0; ++ val = strtoint32((const char *) el->values[0].data, &endptr, 10); ++ if (errno != 0) return errno; ++ if (*endptr) return EINVAL; ++ ++ *value = val; ++ return EOK; ++} ++ + int sysdb_attrs_get_uint32_t(struct sysdb_attrs *attrs, const char *name, + uint32_t *value) + { +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index 9bcd7be0960fcfa390fb9150594ea84880a14eea..255a135f0cad788e4c952b86fe24ca10f5e63732 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -294,6 +294,8 @@ errno_t sysdb_attrs_get_bool(struct sysdb_attrs *attrs, const char *name, + bool *value); + int sysdb_attrs_get_uint16_t(struct sysdb_attrs *attrs, const char *name, + uint16_t *value); ++int sysdb_attrs_get_int32_t(struct sysdb_attrs *attrs, const char *name, ++ int32_t *value); + int sysdb_attrs_get_uint32_t(struct sysdb_attrs *attrs, const char *name, + uint32_t *value); + +-- +1.8.4.2 + diff --git a/SOURCES/0042-IPA-fix-for-recent-AD-group-membership-changes.patch b/SOURCES/0042-IPA-fix-for-recent-AD-group-membership-changes.patch new file mode 100644 index 0000000..fa294ce --- /dev/null +++ b/SOURCES/0042-IPA-fix-for-recent-AD-group-membership-changes.patch @@ -0,0 +1,24 @@ +From 32388a70e254021473cca2caf8fcc77fdf7e7635 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 7 Jan 2014 13:04:58 +0100 +Subject: [PATCH 42/43] IPA: fix for recent AD group membership changes + +--- + src/providers/ipa/ipa_subdomains.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c +index 2d28d7cd0538b204eb2818e71e029dec19456a1c..9efbd725f1102d34af2107801286bca1c6412c19 100644 +--- a/src/providers/ipa/ipa_subdomains.c ++++ b/src/providers/ipa/ipa_subdomains.c +@@ -192,6 +192,8 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx, + return ret; + } + ++ sdom->pvt = ad_id_ctx; ++ + /* Set up the ID mapping object */ + ad_id_ctx->sdap_id_ctx->opts->idmap_ctx = + id_ctx->sdap_id_ctx->opts->idmap_ctx; +-- +1.8.4.2 diff --git a/SOURCES/0043-LDAP-Fix-typo-and-use-the-right-attribute-map.patch b/SOURCES/0043-LDAP-Fix-typo-and-use-the-right-attribute-map.patch new file mode 100644 index 0000000..1f5f205 --- /dev/null +++ b/SOURCES/0043-LDAP-Fix-typo-and-use-the-right-attribute-map.patch @@ -0,0 +1,29 @@ +From 147af349a5642f85689cbfe68136f0e01706330e Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 8 Jan 2014 08:11:46 +0100 +Subject: [PATCH 43/43] LDAP: Fix typo and use the right attribute map + +https://fedorahosted.org/sssd/ticket/2191 + +There was a copy-n-paste bug in the code that resulted in using a wrong +attribute map. This could lead to the primary name not being selected +correctly. +--- + src/providers/ldap/sdap.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c +index 078326ad3614ed2cd41659ea279642a46a0e24e1..ddcf199b61311b69fde54c3ee25f2338ceb05576 100644 +--- a/src/providers/ldap/sdap.c ++++ b/src/providers/ldap/sdap.c +@@ -1246,7 +1246,7 @@ errno_t sdap_get_user_primary_name(TALLOC_CTX *memctx, + const char **_user_name) + { + return sdap_get_primary_name(memctx, +- opts->group_map[SDAP_AT_USER_NAME].name, ++ opts->user_map[SDAP_AT_USER_NAME].name, + attrs, dom, _user_name); + } + +-- +1.8.4.2 diff --git a/SOURCES/0044-pac-fix-double-free.patch b/SOURCES/0044-pac-fix-double-free.patch new file mode 100644 index 0000000..afc6cf0 --- /dev/null +++ b/SOURCES/0044-pac-fix-double-free.patch @@ -0,0 +1,69 @@ +From 47bc6c387ab1d3f835167c528bb57f688080af1a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Mon, 11 Nov 2013 12:47:53 +0100 +Subject: [PATCH 44/47] pac: fix double free + +--- + src/responder/pac/pacsrv_utils.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +diff --git a/src/responder/pac/pacsrv_utils.c b/src/responder/pac/pacsrv_utils.c +index 6a6ea2e357483c68533c501b93c16383ee644048..a82320fcae3b0494e7b6b322428e3a17ed729b4a 100644 +--- a/src/responder/pac/pacsrv_utils.c ++++ b/src/responder/pac/pacsrv_utils.c +@@ -74,6 +74,7 @@ errno_t get_sids_from_pac(TALLOC_CTX *mem_ctx, + struct sss_domain_info *user_dom; + struct sss_domain_info *group_dom; + char *sid_str = NULL; ++ char *msid_str = NULL; + char *user_dom_sid_str = NULL; + size_t user_dom_sid_str_len; + enum idmap_error_code err; +@@ -231,24 +232,22 @@ errno_t get_sids_from_pac(TALLOC_CTX *mem_ctx, + + } + +- talloc_zfree(sid_str); +- + for(s = 0; s < info3->sidcount; s++) { + err = sss_idmap_smb_sid_to_sid(pac_ctx->idmap_ctx, info3->sids[s].sid, +- &sid_str); ++ &msid_str); + if (err != IDMAP_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, ("sss_idmap_smb_sid_to_sid failed.\n")); + ret = EFAULT; + goto done; + } + +- key.str = sid_str; ++ key.str = msid_str; + value.ul = 0; + +- ret = responder_get_domain_by_id(pac_ctx->rctx, sid_str, &group_dom); ++ ret = responder_get_domain_by_id(pac_ctx->rctx, msid_str, &group_dom); + if (ret == EOK) { + ret = sysdb_search_object_by_sid(mem_ctx, group_dom->sysdb, +- group_dom, sid_str, NULL, &msg); ++ group_dom, msid_str, NULL, &msg); + if (ret == EOK && msg->count == 1 ) { + value.ul = ldb_msg_find_attr_as_uint64(msg->msgs[0], + SYSDB_GIDNUM, 0); +@@ -257,14 +256,13 @@ errno_t get_sids_from_pac(TALLOC_CTX *mem_ctx, + } + + ret = hash_enter(sid_table, &key, &value); ++ sss_idmap_free_sid(pac_ctx->idmap_ctx, msid_str); + if (ret != HASH_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, ("hash_enter failed [%d][%s].\n", + ret, hash_error_string(ret))); + ret = EIO; + goto done; + } +- +- sss_idmap_free_sid(pac_ctx->idmap_ctx, sid_str); + } + + ret = EOK; +-- +1.8.4.2 + diff --git a/SOURCES/0045-pac-fix-potential-memory-leaks.patch b/SOURCES/0045-pac-fix-potential-memory-leaks.patch new file mode 100644 index 0000000..3658ae5 --- /dev/null +++ b/SOURCES/0045-pac-fix-potential-memory-leaks.patch @@ -0,0 +1,65 @@ +From 7e60e5991e97443044ae9c097131c84e9538cc42 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 12 Nov 2013 13:41:49 +0100 +Subject: [PATCH 45/47] pac: fix potential memory leaks + +--- + src/responder/pac/pacsrv_utils.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/src/responder/pac/pacsrv_utils.c b/src/responder/pac/pacsrv_utils.c +index a82320fcae3b0494e7b6b322428e3a17ed729b4a..53edcc286119aa4a315285827da96e5d157afec9 100644 +--- a/src/responder/pac/pacsrv_utils.c ++++ b/src/responder/pac/pacsrv_utils.c +@@ -82,7 +82,7 @@ errno_t get_sids_from_pac(TALLOC_CTX *mem_ctx, + hash_key_t key; + hash_value_t value; + char *rid_start; +- struct ldb_result *msg; ++ struct ldb_result *msg = NULL; + char *user_sid_str = NULL; + char *primary_group_sid_str = NULL; + +@@ -154,8 +154,8 @@ errno_t get_sids_from_pac(TALLOC_CTX *mem_ctx, + sid_str, NULL, &msg); + if (ret == EOK && msg->count == 1) { + value.ul = ldb_msg_find_attr_as_uint64(msg->msgs[0], SYSDB_UIDNUM, 0); +- talloc_free(msg); + } ++ talloc_zfree(msg); + + ret = hash_enter(sid_table, &key, &value); + if (ret != HASH_SUCCESS) { +@@ -189,8 +189,8 @@ errno_t get_sids_from_pac(TALLOC_CTX *mem_ctx, + sid_str, NULL, &msg); + if (ret == EOK && msg->count == 1) { + value.ul = ldb_msg_find_attr_as_uint64(msg->msgs[0], SYSDB_GIDNUM, 0); +- talloc_free(msg); + } ++ talloc_zfree(msg); + + ret = hash_enter(sid_table, &key, &value); + if (ret != HASH_SUCCESS) { +@@ -219,8 +219,8 @@ errno_t get_sids_from_pac(TALLOC_CTX *mem_ctx, + if (ret == EOK && msg->count == 1) { + value.ul = ldb_msg_find_attr_as_uint64(msg->msgs[0], + SYSDB_GIDNUM, 0); +- talloc_free(msg); + } ++ talloc_zfree(msg); + + ret = hash_enter(sid_table, &key, &value); + if (ret != HASH_SUCCESS) { +@@ -251,8 +251,8 @@ errno_t get_sids_from_pac(TALLOC_CTX *mem_ctx, + if (ret == EOK && msg->count == 1 ) { + value.ul = ldb_msg_find_attr_as_uint64(msg->msgs[0], + SYSDB_GIDNUM, 0); +- talloc_free(msg); + } ++ talloc_zfree(msg); + } + + ret = hash_enter(sid_table, &key, &value); +-- +1.8.4.2 + diff --git a/SOURCES/0046-responder-Set-forest-attribute-in-AD-domains.patch b/SOURCES/0046-responder-Set-forest-attribute-in-AD-domains.patch new file mode 100644 index 0000000..54068b1 --- /dev/null +++ b/SOURCES/0046-responder-Set-forest-attribute-in-AD-domains.patch @@ -0,0 +1,321 @@ +From 6ac0feca0cdc66fc8d8a612e25d37a49d27c0233 Mon Sep 17 00:00:00 2001 +From: Pavel Reichl +Date: Tue, 17 Dec 2013 17:32:04 +0000 +Subject: [PATCH 46/47] responder: Set forest attribute in AD domains + +Resolves: +https://fedorahosted.org/sssd/ticket/2160 +--- + src/db/sysdb.h | 3 ++- + src/db/sysdb_subdomains.c | 35 ++++++++++++++++++++++++++++- + src/providers/ad/ad_domain_info.c | 46 +++++++++++++++++++++++++++++++------- + src/providers/ad/ad_domain_info.h | 3 ++- + src/providers/ad/ad_id.c | 5 +++-- + src/providers/ad/ad_subdomains.c | 9 +++++--- + src/providers/ipa/ipa_subdomains.c | 2 +- + src/providers/ldap/sdap_access.c | 2 +- + 8 files changed, 87 insertions(+), 18 deletions(-) + +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index 255a135f0cad788e4c952b86fe24ca10f5e63732..9677294b22e47f5169d7631673beec2dbc6117ad 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -388,7 +388,8 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain); + errno_t sysdb_master_domain_update(struct sss_domain_info *domain); + + errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain, +- const char *flat, const char *id); ++ const char *flat, const char *id, ++ const char* forest); + + errno_t sysdb_subdomain_delete(struct sysdb_ctx *sysdb, const char *name); + +diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c +index 43c75799cdc2856916b2dc95c3a544ef99b56081..9c2926c00b0cc08cb8e317ae838e26c82506ee37 100644 +--- a/src/db/sysdb_subdomains.c ++++ b/src/db/sysdb_subdomains.c +@@ -208,6 +208,7 @@ errno_t sysdb_master_domain_update(struct sss_domain_info *domain) + SYSDB_SUBDOMAIN_REALM, + SYSDB_SUBDOMAIN_FLAT, + SYSDB_SUBDOMAIN_ID, ++ SYSDB_SUBDOMAIN_FOREST, + NULL}; + + tmp_ctx = talloc_new(NULL); +@@ -278,13 +279,27 @@ errno_t sysdb_master_domain_update(struct sss_domain_info *domain) + } + } + ++ tmp_str = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SUBDOMAIN_FOREST, ++ NULL); ++ if (tmp_str != NULL && ++ (domain->forest == NULL || ++ strcasecmp(tmp_str, domain->forest) != 0)) { ++ talloc_free(domain->forest); ++ domain->forest = talloc_strdup(domain, tmp_str); ++ if (domain->forest == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ + done: + talloc_free(tmp_ctx); + return ret; + } + + errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain, +- const char *flat, const char *id) ++ const char *flat, const char *id, ++ const char* forest) + { + TALLOC_CTX *tmp_ctx; + struct ldb_message *msg; +@@ -345,6 +360,24 @@ errno_t sysdb_master_domain_add_info(struct sss_domain_info *domain, + do_update = true; + } + ++ if (forest != NULL && (domain->forest == NULL || ++ strcmp(domain->forest, forest) != 0)) { ++ ret = ldb_msg_add_empty(msg, SYSDB_SUBDOMAIN_FOREST, ++ LDB_FLAG_MOD_REPLACE, NULL); ++ if (ret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ ret = ldb_msg_add_string(msg, SYSDB_SUBDOMAIN_FOREST, forest); ++ if (ret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ do_update = true; ++ } ++ + if (do_update == false) { + ret = EOK; + goto done; +diff --git a/src/providers/ad/ad_domain_info.c b/src/providers/ad/ad_domain_info.c +index eff2034d12261510ed7535dee7098a6e68f1f2c2..5475c5bc7ec74e81080566c6fbd6919c54a60f40 100644 +--- a/src/providers/ad/ad_domain_info.c ++++ b/src/providers/ad/ad_domain_info.c +@@ -41,9 +41,9 @@ + #define MASTER_DOMAIN_SID_FILTER "objectclass=domain" + + static errno_t +-netlogon_get_flat_name(TALLOC_CTX *mem_ctx, +- struct sysdb_attrs *reply, +- char **_flat_name) ++netlogon_get_domain_info(TALLOC_CTX *mem_ctx, ++ struct sysdb_attrs *reply, ++ char **_flat_name, char **_forest) + { + errno_t ret; + struct ldb_message_element *el; +@@ -52,6 +52,7 @@ netlogon_get_flat_name(TALLOC_CTX *mem_ctx, + enum ndr_err_code ndr_err; + struct netlogon_samlogon_response response; + const char *flat_name; ++ const char *forest; + + ret = sysdb_attrs_get_el(reply, AD_AT_NETLOGON, &el); + if (ret != EOK) { +@@ -92,11 +93,13 @@ netlogon_get_flat_name(TALLOC_CTX *mem_ctx, + goto done; + } + ++ /* get flat name */ + if (response.data.nt5_ex.domain_name != NULL && + *response.data.nt5_ex.domain_name != '\0') { + flat_name = response.data.nt5_ex.domain_name; + } else { +- DEBUG(SSSDBG_MINOR_FAILURE, ("No netlogon data available\n")); ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ ("No netlogon domain name data available\n")); + ret = ENOENT; + goto done; + } +@@ -107,6 +110,24 @@ netlogon_get_flat_name(TALLOC_CTX *mem_ctx, + ret = ENOMEM; + goto done; + } ++ ++ /* get forest */ ++ if (response.data.nt5_ex.forest != NULL && ++ *response.data.nt5_ex.forest != '\0') { ++ forest = response.data.nt5_ex.forest; ++ } else { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("No netlogon forest data available\n")); ++ ret = ENOENT; ++ goto done; ++ } ++ ++ *_forest = talloc_strdup(mem_ctx, forest); ++ if (*_forest == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n")); ++ ret = ENOMEM; ++ goto done; ++ } ++ + ret = EOK; + done: + talloc_free(ndr_pull); +@@ -124,6 +145,7 @@ struct ad_master_domain_state { + int base_iter; + + char *flat; ++ char *forest; + char *sid; + }; + +@@ -338,14 +360,17 @@ ad_master_domain_netlogon_done(struct tevent_req *subreq) + + /* Exactly one flat name. Carry on */ + +- ret = netlogon_get_flat_name(state, reply[0], &state->flat); ++ ret = netlogon_get_domain_info(state, reply[0], &state->flat, ++ &state->forest); + if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, ("Could not get the flat name\n")); ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ ("Could not get the flat name or forest\n")); + /* Not fatal. Just quit. */ + goto done; + } +- + DEBUG(SSSDBG_TRACE_FUNC, ("Found flat name [%s].\n", state->flat)); ++ DEBUG(SSSDBG_TRACE_FUNC, ("Found forest [%s].\n", state->forest)); ++ + done: + tevent_req_done(req); + return; +@@ -355,7 +380,8 @@ errno_t + ad_master_domain_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + char **_flat, +- char **_id) ++ char **_id, ++ char **_forest) + { + struct ad_master_domain_state *state = tevent_req_data(req, + struct ad_master_domain_state); +@@ -366,6 +392,10 @@ ad_master_domain_recv(struct tevent_req *req, + *_flat = talloc_steal(mem_ctx, state->flat); + } + ++ if (_forest) { ++ *_forest = talloc_steal(mem_ctx, state->forest); ++ } ++ + if (_id) { + *_id = talloc_steal(mem_ctx, state->sid); + } +diff --git a/src/providers/ad/ad_domain_info.h b/src/providers/ad/ad_domain_info.h +index d21706396034509a498391e666e03a8e2eda8e08..d3a6416cebd07b524aceedcb63a18c4467e3dc4e 100644 +--- a/src/providers/ad/ad_domain_info.h ++++ b/src/providers/ad/ad_domain_info.h +@@ -36,6 +36,7 @@ errno_t + ad_master_domain_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + char **_flat, +- char **_id); ++ char **_id, ++ char **_forest); + + #endif /* _AD_MASTER_DOMAIN_H_ */ +diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c +index e47c41863a14eed695907548d64f4559fbae629d..44bfa00986b6c0ebfa65dd7b83dd45eb64b87946 100644 +--- a/src/providers/ad/ad_id.c ++++ b/src/providers/ad/ad_id.c +@@ -519,9 +519,10 @@ ad_enumeration_master_done(struct tevent_req *subreq) + struct ad_enumeration_state); + char *flat_name; + char *master_sid; ++ char *forest; + + ret = ad_master_domain_recv(subreq, state, +- &flat_name, &master_sid); ++ &flat_name, &master_sid, &forest); + talloc_zfree(subreq); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Cannot retrieve master domain info\n")); +@@ -530,7 +531,7 @@ ad_enumeration_master_done(struct tevent_req *subreq) + } + + ret = sysdb_master_domain_add_info(state->sdom->dom, +- flat_name, master_sid); ++ flat_name, master_sid, forest); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Cannot save master domain info\n")); + tevent_req_error(req, ret); +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index e438a688c364084a3f2bbca338a39d61aa86b5d6..62c3e16d0d3323a32848b4fbf54d2a151c16f64c 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -85,6 +85,7 @@ struct ad_subdomains_req_ctx { + + char *master_sid; + char *flat_name; ++ char *forest; + }; + + static errno_t +@@ -294,7 +295,7 @@ ad_subdom_store(struct ad_subdomains_ctx *ctx, + + /* AD subdomains are currently all mpg and do not enumerate */ + ret = sysdb_subdomain_store(domain->sysdb, name, realm, flat, sid_str, +- mpg, false, NULL); ++ mpg, false, domain->forest); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("sysdb_subdomain_store failed.\n")); + goto done; +@@ -539,7 +540,8 @@ static void ad_subdomains_master_dom_done(struct tevent_req *req) + ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx); + + ret = ad_master_domain_recv(req, ctx, +- &ctx->flat_name, &ctx->master_sid); ++ &ctx->flat_name, &ctx->master_sid, ++ &ctx->forest); + talloc_zfree(req); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Cannot retrieve master domain info\n")); +@@ -547,7 +549,8 @@ static void ad_subdomains_master_dom_done(struct tevent_req *req) + } + + ret = sysdb_master_domain_add_info(ctx->sd_ctx->be_ctx->domain, +- ctx->flat_name, ctx->master_sid); ++ ctx->flat_name, ctx->master_sid, ++ ctx->forest); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Cannot save master domain info\n")); + goto done; +diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c +index 9efbd725f1102d34af2107801286bca1c6412c19..d9c204451f1b734ee98ce4c48f3f139731e47dec 100644 +--- a/src/providers/ipa/ipa_subdomains.c ++++ b/src/providers/ipa/ipa_subdomains.c +@@ -1076,7 +1076,7 @@ static void ipa_subdomains_handler_master_done(struct tevent_req *req) + } + + ret = sysdb_master_domain_add_info(ctx->sd_ctx->be_ctx->domain, +- flat, id); ++ flat, id, NULL); + } else { + ctx->search_base_iter++; + ret = ipa_subdomains_handler_get(ctx, IPA_SUBDOMAINS_MASTER); +diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c +index 6b387271a229668ddfa5d67143a585e667a16ddd..f0df24e7f3a855304b0cfd9d075ac67334f9bb1a 100644 +--- a/src/providers/ldap/sdap_access.c ++++ b/src/providers/ldap/sdap_access.c +@@ -214,7 +214,7 @@ static void sdap_access_filter_done(struct tevent_req *subreq) + ret = sdap_access_filter_recv(subreq); + talloc_zfree(subreq); + if (ret != EOK) { +- DEBUG(1, ("Error retrieving access check result.\n")); ++ DEBUG(SSSDBG_CRIT_FAILURE, ("Error retrieving access check result.\n")); + tevent_req_error(req, ret); + return; + } +-- +1.8.4.2 + diff --git a/SOURCES/0047-LDAP-Add-a-new-error-code-for-malformed-access-contr.patch b/SOURCES/0047-LDAP-Add-a-new-error-code-for-malformed-access-contr.patch new file mode 100644 index 0000000..706968d --- /dev/null +++ b/SOURCES/0047-LDAP-Add-a-new-error-code-for-malformed-access-contr.patch @@ -0,0 +1,146 @@ +From 91ab35daf713e146dfae53a67f6b86b424c897d5 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 8 Jan 2014 17:12:17 +0100 +Subject: [PATCH 47/47] LDAP: Add a new error code for malformed access control + filter + +https://fedorahosted.org/sssd/ticket/2164 + +The patch adds a new error code and special cases the new code so that +access is denied and a nicer log message is shown. +--- + src/providers/ldap/sdap_access.c | 8 +++++++- + src/providers/ldap/sdap_async.c | 12 ++++++------ + src/providers/ldap/sdap_async_groups_ad.c | 2 +- + src/providers/ldap/sdap_async_initgroups_ad.c | 4 ++-- + src/util/util_errors.c | 1 + + src/util/util_errors.h | 1 + + 6 files changed, 18 insertions(+), 10 deletions(-) + +diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c +index f0df24e7f3a855304b0cfd9d075ac67334f9bb1a..29e83eb43cf78107e2075e1aa95211abac6d2df1 100644 +--- a/src/providers/ldap/sdap_access.c ++++ b/src/providers/ldap/sdap_access.c +@@ -855,9 +855,15 @@ static void sdap_access_filter_get_access_done(struct tevent_req *subreq) + } + } else if (dp_error == DP_ERR_OFFLINE) { + ret = sdap_access_filter_decide_offline(req); ++ } else if (ret == ERR_INVALID_FILTER) { ++ sss_log(SSS_LOG_ERR, ++ "Malformed access control filter [%s]\n", state->filter); ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ ("Malformed access control filter [%s]\n", state->filter)); ++ ret = ERR_ACCESS_DENIED; + } else { + DEBUG(1, ("sdap_get_generic_send() returned error [%d][%s]\n", +- ret, strerror(ret))); ++ ret, sss_strerror(ret))); + } + + goto done; +diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c +index e905d2dd6d539baadcd29aa0869ca04e845947e2..367007bde0011ed4de283b2a50b22538830a5275 100644 +--- a/src/providers/ldap/sdap_async.c ++++ b/src/providers/ldap/sdap_async.c +@@ -1306,9 +1306,9 @@ static errno_t sdap_get_generic_ext_step(struct tevent_req *req) + sss_log(SSS_LOG_ERR, "LDAP connection error, %s", + sss_ldap_err2string(lret)); + } +- } +- +- else { ++ } else if (lret == LDAP_FILTER_ERROR) { ++ ret = ERR_INVALID_FILTER; ++ } else { + ret = EIO; + } + goto done; +@@ -1570,7 +1570,7 @@ static void sdap_get_generic_done(struct tevent_req *subreq) + talloc_zfree(subreq); + if (ret) { + DEBUG(4, ("sdap_get_generic_ext_recv failed [%d]: %s\n", +- ret, strerror(ret))); ++ ret, sss_strerror(ret))); + tevent_req_error(req, ret); + return; + } +@@ -1790,7 +1790,7 @@ static void sdap_x_deref_search_done(struct tevent_req *subreq) + talloc_zfree(subreq); + if (ret) { + DEBUG(4, ("sdap_get_generic_ext_recv failed [%d]: %s\n", +- ret, strerror(ret))); ++ ret, sss_strerror(ret))); + tevent_req_error(req, ret); + return; + } +@@ -2049,7 +2049,7 @@ static void sdap_asq_search_done(struct tevent_req *subreq) + talloc_zfree(subreq); + if (ret) { + DEBUG(4, ("sdap_get_generic_ext_recv failed [%d]: %s\n", +- ret, strerror(ret))); ++ ret, sss_strerror(ret))); + tevent_req_error(req, ret); + return; + } +diff --git a/src/providers/ldap/sdap_async_groups_ad.c b/src/providers/ldap/sdap_async_groups_ad.c +index 9b61c697d5789c3ec3467ec52a7171f6a640ce9e..6a8a4fd139657040ff83cad10ba35a0dde4a0122 100644 +--- a/src/providers/ldap/sdap_async_groups_ad.c ++++ b/src/providers/ldap/sdap_async_groups_ad.c +@@ -183,7 +183,7 @@ sdap_get_ad_match_rule_members_step(struct tevent_req *subreq) + talloc_zfree(subreq); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, +- ("LDAP search failed: [%s]\n", strerror(ret))); ++ ("LDAP search failed: [%s]\n", sss_strerror(ret))); + tevent_req_error(req, ret); + return; + } +diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c +index 8f8f0a4cc635818dcc7f75f9da603ce2f55c820f..724f308da68daf05e2dc4cc6c64cac347ab8a0ca 100644 +--- a/src/providers/ldap/sdap_async_initgroups_ad.c ++++ b/src/providers/ldap/sdap_async_initgroups_ad.c +@@ -208,7 +208,7 @@ sdap_get_ad_match_rule_initgroups_step(struct tevent_req *subreq) + talloc_zfree(subreq); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, +- ("LDAP search failed: [%s]\n", strerror(ret))); ++ ("LDAP search failed: [%s]\n", sss_strerror(ret))); + goto error; + } + +@@ -383,7 +383,7 @@ static void sdap_get_ad_tokengroups_done(struct tevent_req *subreq) + talloc_zfree(subreq); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, +- ("LDAP search failed: [%s]\n", strerror(ret))); ++ ("LDAP search failed: [%s]\n", sss_strerror(ret))); + goto done; + } + +diff --git a/src/util/util_errors.c b/src/util/util_errors.c +index 114c8b04fd354b166d14e526a3bab6a6c0c05951..633257e8da0ef039e555a07ad8b51125114ca01c 100644 +--- a/src/util/util_errors.c ++++ b/src/util/util_errors.c +@@ -51,6 +51,7 @@ struct err_string error_to_str[] = { + { "Entry not found" }, /* ERR_NOT_FOUND */ + { "Domain not found" }, /* ERR_DOMAIN_NOT_FOUND */ + { "Missing configuration file" }, /* ERR_MISSING_CONF */ ++ { "Malformed search filter" }, /* ERR_INVALID_FILTER, */ + }; + + +diff --git a/src/util/util_errors.h b/src/util/util_errors.h +index bca45f392b0357c3f1c848768358cb1d47514715..1332085031dbe6935cbdc94543fa14b09fe81028 100644 +--- a/src/util/util_errors.h ++++ b/src/util/util_errors.h +@@ -73,6 +73,7 @@ enum sssd_errors { + ERR_NOT_FOUND, + ERR_DOMAIN_NOT_FOUND, + ERR_MISSING_CONF, ++ ERR_INVALID_FILTER, + ERR_LAST /* ALWAYS LAST */ + }; + +-- +1.8.4.2 + diff --git a/SOURCES/0048-FAST-when-parsing-krb5_child-response-make-sure-to-n.patch b/SOURCES/0048-FAST-when-parsing-krb5_child-response-make-sure-to-n.patch new file mode 100644 index 0000000..0b1fb22 --- /dev/null +++ b/SOURCES/0048-FAST-when-parsing-krb5_child-response-make-sure-to-n.patch @@ -0,0 +1,46 @@ +From 103f7efda7b84e7c791af2ebc2255e61e826fd75 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Tue, 24 Dec 2013 13:01:46 +0200 +Subject: [PATCH 48/48] FAST: when parsing krb5_child response, make sure to + not miss OTP message if it was last one + +The last message in the stream might be with empty payload which means we get +only message type and message length (0) returned, i.e. 8 bytes left remaining +in the stream after processing preceding message. This makes our calculation at +the end of a message processing loop incorrect -- p+2*sizeof(int32_t) can be +equal to len, after all. + +Fixes FAST processing for FreeIPA native OTP case: +https://fedorahosted.org/sssd/ticket/2186 +--- + src/providers/krb5/krb5_child_handler.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c +index 92dec0d2afb1627b61c3dd1037e91546a7ee08d6..d6c1dc1f9707444a82e433a375839cadf73f1259 100644 +--- a/src/providers/krb5/krb5_child_handler.c ++++ b/src/providers/krb5/krb5_child_handler.c +@@ -548,8 +548,9 @@ parse_krb5_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, ssize_t len, + * CCACHE_ENV_NAME"=". pref_len also counts the trailing '=' because + * sizeof() counts the trailing '\0' of a string. */ + pref_len = sizeof(CCACHE_ENV_NAME); +- if (msg_len > pref_len && +- strncmp((const char *) &buf[p], CCACHE_ENV_NAME"=", pref_len) == 0) { ++ if ((msg_type == SSS_PAM_ENV_ITEM) && ++ (msg_len > pref_len) && ++ (strncmp((const char *) &buf[p], CCACHE_ENV_NAME"=", pref_len) == 0)) { + ccname = (char *) &buf[p+pref_len]; + ccname_len = msg_len-pref_len; + } +@@ -600,7 +601,7 @@ parse_krb5_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, ssize_t len, + + p += msg_len; + +- if ((p < len) && (p + 2*sizeof(int32_t) >= len)) { ++ if ((p < len) && (p + 2*sizeof(int32_t) > len)) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("The remainder of the message is too short.\n")); + return EINVAL; +-- +1.8.4.2 + diff --git a/SOURCES/0049-UTIL-Inherit-parent-domain-s-default_shell.patch b/SOURCES/0049-UTIL-Inherit-parent-domain-s-default_shell.patch new file mode 100644 index 0000000..5d3c101 --- /dev/null +++ b/SOURCES/0049-UTIL-Inherit-parent-domain-s-default_shell.patch @@ -0,0 +1,33 @@ +From 14bafb02c396396e04412a4981b98ae75534294a Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 14 Jan 2014 10:55:39 +0100 +Subject: [PATCH 49/53] UTIL: Inherit parent domain's default_shell + +Some override parameters were not inherited when creating subdomains. +Especially with AD trusts, this gave strange results. +--- + src/util/domain_info_utils.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c +index 61efc0b40dcd8969b635781549feab3eee79299e..98678f97b95d271a0d2e18daadae7f3f9a79f89e 100644 +--- a/src/util/domain_info_utils.c ++++ b/src/util/domain_info_utils.c +@@ -271,10 +271,13 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, + dom->group_timeout = parent->group_timeout; + dom->netgroup_timeout = parent->netgroup_timeout; + dom->service_timeout = parent->service_timeout; +- dom->override_homedir = parent->override_homedir; + dom->names = parent->names; + ++ dom->override_homedir = parent->override_homedir; ++ dom->fallback_homedir = parent->fallback_homedir; + dom->subdomain_homedir = parent->subdomain_homedir; ++ dom->override_shell = parent->override_shell; ++ dom->default_shell = parent->default_shell; + + if (parent->sysdb == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("Missing sysdb context in parent domain.\n")); +-- +1.8.4.2 + diff --git a/SOURCES/0050-NSS-Use-plain-user-name-when-expanding-homedir.patch b/SOURCES/0050-NSS-Use-plain-user-name-when-expanding-homedir.patch new file mode 100644 index 0000000..7fddcbd --- /dev/null +++ b/SOURCES/0050-NSS-Use-plain-user-name-when-expanding-homedir.patch @@ -0,0 +1,42 @@ +From 90e871a816440af34f095d3b1003476a0978a348 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 14 Jan 2014 11:10:25 +0100 +Subject: [PATCH 50/53] NSS: Use plain user name when expanding homedir + +--- + src/responder/nss/nsssrv_cmd.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c +index 550017c0e4385a7147ed5ef83da2c37cb97c8092..c59078b545842561a7e5f62e9a99da6057b23660 100644 +--- a/src/responder/nss/nsssrv_cmd.c ++++ b/src/responder/nss/nsssrv_cmd.c +@@ -172,13 +172,24 @@ static const char *get_homedir_override(TALLOC_CTX *mem_ctx, + struct ldb_message *msg, + struct nss_ctx *nctx, + struct sss_domain_info *dom, +- const char *name, ++ const char *orig_name, + uint32_t uid) + { + const char *homedir; ++ char *name; ++ char *domname; ++ errno_t ret; + + homedir = ldb_msg_find_attr_as_string(msg, SYSDB_HOMEDIR, NULL); + ++ /* Subdomain users store FQDN in their name attribute */ ++ ret = sss_parse_name(mem_ctx, dom->names, orig_name, &domname, &name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Could not parse [%s] into " ++ "name-value components.\n", orig_name)); ++ return NULL; ++ } ++ + /* Check whether we are unconditionally overriding the server + * for home directory locations. + */ +-- +1.8.4.2 + diff --git a/SOURCES/0051-simple-access-match-objects-using-flat-name.patch b/SOURCES/0051-simple-access-match-objects-using-flat-name.patch new file mode 100644 index 0000000..cf15b3e --- /dev/null +++ b/SOURCES/0051-simple-access-match-objects-using-flat-name.patch @@ -0,0 +1,31 @@ +From 9df26b2f56d249ce69f7fd7d5c40b55dfe119e93 Mon Sep 17 00:00:00 2001 +From: Pavel Reichl +Date: Wed, 8 Jan 2014 15:46:57 +0000 +Subject: [PATCH 51/53] simple access: match objects using flat name + +Use flat name to recognise users and groups belonging to main sssd domain. + +Resolves: +https://fedorahosted.org/sssd/ticket/2189 +--- + src/providers/simple/simple_access.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/providers/simple/simple_access.c b/src/providers/simple/simple_access.c +index 46b045e531dfc5fcdff4fc4f5370734aca1e377c..f2bfe755039fd7a370749fd3ce94a47c62c216bc 100644 +--- a/src/providers/simple/simple_access.c ++++ b/src/providers/simple/simple_access.c +@@ -140,7 +140,9 @@ static errno_t simple_access_parse_names(TALLOC_CTX *mem_ctx, + goto done; + } + +- if (domain == NULL || strcasecmp(domain, be_ctx->domain->name) == 0) { ++ if (domain == NULL || strcasecmp(domain, be_ctx->domain->name) == 0 || ++ (be_ctx->domain->flat_name != NULL && ++ strcasecmp(domain, be_ctx->domain->flat_name) == 0)) { + /* This object belongs to main SSSD domain. Those users and groups + * are stored without domain part, so we will strip it off. + * */ +-- +1.8.4.2 + diff --git a/SOURCES/0052-simple-access-refresh-master-domain-info.patch b/SOURCES/0052-simple-access-refresh-master-domain-info.patch new file mode 100644 index 0000000..4069e20 --- /dev/null +++ b/SOURCES/0052-simple-access-refresh-master-domain-info.patch @@ -0,0 +1,219 @@ +From b6c53b49cde8188bf2f8b493b275118472c4482e Mon Sep 17 00:00:00 2001 +From: Pavel Reichl +Date: Wed, 8 Jan 2014 16:03:08 +0000 +Subject: [PATCH 52/53] simple access: refresh master domain info + +To correctly decide if an object is a member of the main sssd domain, a flat name +is needed. However, the information may not be available when the module is +inited so it may be necessary to refresh this data later while processing a +request. + +Resolves: +https://fedorahosted.org/sssd/ticket/2189 +--- + src/providers/simple/simple_access.c | 135 +++++++++++++++++++++++------------ + src/providers/simple/simple_access.h | 2 + + 2 files changed, 92 insertions(+), 45 deletions(-) + +diff --git a/src/providers/simple/simple_access.c b/src/providers/simple/simple_access.c +index f2bfe755039fd7a370749fd3ce94a47c62c216bc..eab62a826b4749aa5e5dab4a8e491fc2263be4fb 100644 +--- a/src/providers/simple/simple_access.c ++++ b/src/providers/simple/simple_access.c +@@ -32,7 +32,76 @@ + #define CONFDB_SIMPLE_ALLOW_GROUPS "simple_allow_groups" + #define CONFDB_SIMPLE_DENY_GROUPS "simple_deny_groups" + ++#define TIMEOUT_OF_REFRESH_FILTER_LISTS 5 ++ + static void simple_access_check(struct tevent_req *req); ++static errno_t simple_access_parse_names(TALLOC_CTX *mem_ctx, ++ struct be_ctx *be_ctx, ++ char **list, ++ char ***_out); ++ ++static int simple_access_obtain_filter_lists(struct simple_ctx *ctx) ++{ ++ struct be_ctx *bectx = ctx->be_ctx; ++ int ret; ++ int i; ++ struct { ++ const char *name; ++ const char *option; ++ char **orig_list; ++ char ***ctx_list; ++ } lists[] = {{"Allow users", CONFDB_SIMPLE_ALLOW_USERS, NULL, NULL}, ++ {"Deny users", CONFDB_SIMPLE_DENY_USERS, NULL, NULL}, ++ {"Allow groups", CONFDB_SIMPLE_ALLOW_GROUPS, NULL, NULL}, ++ {"Deny groups", CONFDB_SIMPLE_DENY_GROUPS, NULL, NULL}, ++ {NULL, NULL, NULL, NULL}}; ++ ++ lists[0].ctx_list = &ctx->allow_users; ++ lists[1].ctx_list = &ctx->deny_users; ++ lists[2].ctx_list = &ctx->allow_groups; ++ lists[3].ctx_list = &ctx->deny_groups; ++ ++ ret = sysdb_master_domain_update(bectx->domain); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FUNC_DATA, ("Update of master domain failed [%d]: %s.\n", ++ ret, sss_strerror(ret))); ++ goto failed; ++ } ++ ++ for (i = 0; lists[i].name != NULL; i++) { ++ ret = confdb_get_string_as_list(bectx->cdb, ctx, bectx->conf_path, ++ lists[i].option, &lists[i].orig_list); ++ if (ret == ENOENT) { ++ DEBUG(SSSDBG_FUNC_DATA, ("%s list is empty.\n", lists[i].name)); ++ *lists[i].ctx_list = NULL; ++ continue; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("confdb_get_string_as_list failed.\n")); ++ goto failed; ++ } ++ ++ ret = simple_access_parse_names(ctx, bectx, lists[i].orig_list, ++ lists[i].ctx_list); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to parse %s list [%d]: %s\n", ++ lists[i].name, ret, sss_strerror(ret))); ++ goto failed; ++ } ++ } ++ ++ if (!ctx->allow_users && ++ !ctx->allow_groups && ++ !ctx->deny_users && ++ !ctx->deny_groups) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("No rules supplied for simple access provider. " ++ "Access will be granted for all users.\n")); ++ } ++ return EOK; ++ ++failed: ++ return ret; ++} + + void simple_access_handler(struct be_req *be_req) + { +@@ -40,13 +109,16 @@ void simple_access_handler(struct be_req *be_req) + struct pam_data *pd; + struct tevent_req *req; + struct simple_ctx *ctx; ++ int ret; ++ time_t now; + + pd = talloc_get_type(be_req_get_data(be_req), struct pam_data); + + pd->pam_status = PAM_SYSTEM_ERR; + + if (pd->cmd != SSS_PAM_ACCT_MGMT) { +- DEBUG(4, ("simple access does not handles pam task %d.\n", pd->cmd)); ++ DEBUG(SSSDBG_CONF_SETTINGS, ++ ("simple access does not handle pam task %d.\n", pd->cmd)); + pd->pam_status = PAM_MODULE_UNKNOWN; + goto done; + } +@@ -54,6 +126,18 @@ void simple_access_handler(struct be_req *be_req) + ctx = talloc_get_type(be_ctx->bet_info[BET_ACCESS].pvt_bet_data, + struct simple_ctx); + ++ ++ now = time(NULL); ++ if ((now - ctx->last_refresh_of_filter_lists) ++ > TIMEOUT_OF_REFRESH_FILTER_LISTS) { ++ ++ ret = simple_access_obtain_filter_lists(ctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to refresh filter lists\n")); ++ } ++ ctx->last_refresh_of_filter_lists = now; ++ } ++ + req = simple_access_check_send(be_req, be_ctx->ev, ctx, pd->user); + if (!req) { + pd->pam_status = PAM_SYSTEM_ERR; +@@ -176,18 +260,6 @@ int sssm_simple_access_init(struct be_ctx *bectx, struct bet_ops **ops, + { + int ret = EINVAL; + struct simple_ctx *ctx; +- int i; +- struct { +- const char *name; +- const char *option; +- char **orig_list; +- char ***ctx_list; +- } lists[] = {{"Allow users", CONFDB_SIMPLE_ALLOW_USERS, NULL, NULL}, +- {"Deny users", CONFDB_SIMPLE_DENY_USERS, NULL, NULL}, +- {"Allow groups", CONFDB_SIMPLE_ALLOW_GROUPS, NULL, NULL}, +- {"Deny groups", CONFDB_SIMPLE_DENY_GROUPS, NULL, NULL}, +- {NULL, NULL, NULL, NULL}}; +- + ctx = talloc_zero(bectx, struct simple_ctx); + if (ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_zero failed.\n")); +@@ -196,39 +268,11 @@ int sssm_simple_access_init(struct be_ctx *bectx, struct bet_ops **ops, + + ctx->domain = bectx->domain; + ctx->be_ctx = bectx; ++ ctx->last_refresh_of_filter_lists = 0; + +- lists[0].ctx_list = &ctx->allow_users; +- lists[1].ctx_list = &ctx->deny_users; +- lists[2].ctx_list = &ctx->allow_groups; +- lists[3].ctx_list = &ctx->deny_groups; +- +- for (i = 0; lists[i].name != NULL; i++) { +- ret = confdb_get_string_as_list(bectx->cdb, ctx, bectx->conf_path, +- lists[i].option, &lists[i].orig_list); +- if (ret == ENOENT) { +- DEBUG(SSSDBG_FUNC_DATA, ("%s list is empty.\n", lists[i].name)); +- *lists[i].ctx_list = NULL; +- continue; +- } else if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, ("confdb_get_string_as_list failed.\n")); +- goto failed; +- } +- +- ret = simple_access_parse_names(ctx, bectx, lists[i].orig_list, +- lists[i].ctx_list); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to parse %s list [%d]: %s\n", +- lists[i].name, ret, sss_strerror(ret))); +- goto failed; +- } +- } +- +- if (!ctx->allow_users && +- !ctx->allow_groups && +- !ctx->deny_users && +- !ctx->deny_groups) { +- DEBUG(SSSDBG_OP_FAILURE, ("No rules supplied for simple access provider. " +- "Access will be granted for all users.\n")); ++ ret = simple_access_obtain_filter_lists(ctx); ++ if (ret != EOK) { ++ goto failed; + } + + *ops = &simple_access_ops; +@@ -240,3 +284,4 @@ failed: + talloc_free(ctx); + return ret; + } ++ +diff --git a/src/providers/simple/simple_access.h b/src/providers/simple/simple_access.h +index 15dfaceb2d9a6670d3559e4a945c2c7a633fad44..a618b2e2ec16a2f32bad7ceb1f5adb7523199316 100644 +--- a/src/providers/simple/simple_access.h ++++ b/src/providers/simple/simple_access.h +@@ -32,6 +32,8 @@ struct simple_ctx { + char **deny_users; + char **allow_groups; + char **deny_groups; ++ ++ time_t last_refresh_of_filter_lists; + }; + + struct tevent_req *simple_access_check_send(TALLOC_CTX *mem_ctx, +-- +1.8.4.2 + diff --git a/SOURCES/0053-NSS-add-support-for-subdomain_homedir.patch b/SOURCES/0053-NSS-add-support-for-subdomain_homedir.patch new file mode 100644 index 0000000..c5b5068 --- /dev/null +++ b/SOURCES/0053-NSS-add-support-for-subdomain_homedir.patch @@ -0,0 +1,33 @@ +From 7bc2cfa445142254276d712a0ff6622eaf670253 Mon Sep 17 00:00:00 2001 +From: Pavel Reichl +Date: Wed, 15 Jan 2014 15:52:35 +0000 +Subject: [PATCH 53/53] NSS: add support for subdomain_homedir + +Resolves: +https://fedorahosted.org/sssd/ticket/2169 +--- + src/responder/nss/nsssrv_cmd.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c +index c59078b545842561a7e5f62e9a99da6057b23660..9ac3680de4d6ff12fe0c77a3963f84934e385276 100644 +--- a/src/responder/nss/nsssrv_cmd.c ++++ b/src/responder/nss/nsssrv_cmd.c +@@ -201,6 +201,14 @@ static const char *get_homedir_override(TALLOC_CTX *mem_ctx, + name, uid, homedir, dom->name, NULL); + } + ++ /* Override home directory location for subdomains. ++ * This option can be overriden by override_homedir. ++ */ ++ if (IS_SUBDOMAIN(dom) && dom->subdomain_homedir) { ++ return expand_homedir_template(mem_ctx, dom->subdomain_homedir, ++ name, uid, homedir, dom->name, NULL); ++ } ++ + if (!homedir || *homedir == '\0') { + /* In the case of a NULL or empty homedir, check to see if + * we have a fallback homedir to use. +-- +1.8.4.2 + diff --git a/SOURCES/0054-AD-Return-right-error-code-from-netlogon_get_flat_na.patch b/SOURCES/0054-AD-Return-right-error-code-from-netlogon_get_flat_na.patch new file mode 100644 index 0000000..afca73b --- /dev/null +++ b/SOURCES/0054-AD-Return-right-error-code-from-netlogon_get_flat_na.patch @@ -0,0 +1,29 @@ +From e47d40005610c3f6e14d4a656fda2e8cadde4844 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Thu, 16 Jan 2014 16:42:50 +0100 +Subject: [PATCH 54/57] AD: Return right error code from netlogon_get_flat_name + +EOK was returned in done section of netlogon_get_flat_name, +even if error code was set in variable ret. + +This patch fixes also warnings from scan-build. +--- + src/providers/ad/ad_domain_info.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/providers/ad/ad_domain_info.c b/src/providers/ad/ad_domain_info.c +index 5475c5bc7ec74e81080566c6fbd6919c54a60f40..28d24b1613040ab1e85cd1504c5469aa60bc08c5 100644 +--- a/src/providers/ad/ad_domain_info.c ++++ b/src/providers/ad/ad_domain_info.c +@@ -131,7 +131,7 @@ netlogon_get_domain_info(TALLOC_CTX *mem_ctx, + ret = EOK; + done: + talloc_free(ndr_pull); +- return EOK; ++ return ret; + } + + struct ad_master_domain_state { +-- +1.8.4.2 + diff --git a/SOURCES/0055-AD-Don-t-fail-the-request-if-ad_account_can_shortcut.patch b/SOURCES/0055-AD-Don-t-fail-the-request-if-ad_account_can_shortcut.patch new file mode 100644 index 0000000..31bc56b --- /dev/null +++ b/SOURCES/0055-AD-Don-t-fail-the-request-if-ad_account_can_shortcut.patch @@ -0,0 +1,28 @@ +From 380c18bfccd25961cf56c9f61b1ac8641a2022b1 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Thu, 16 Jan 2014 20:49:15 +0100 +Subject: [PATCH 55/57] AD: Don't fail the request if ad_account_can_shortcut + fails + +--- + src/providers/ad/ad_id.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c +index 44bfa00986b6c0ebfa65dd7b83dd45eb64b87946..ada47753fb337641df582a5a59affe8124fc2035 100644 +--- a/src/providers/ad/ad_id.c ++++ b/src/providers/ad/ad_id.c +@@ -320,7 +320,9 @@ ad_account_info_handler(struct be_req *be_req) + ar->filter_type, ar->filter_value, + ar->domain, &shortcut); + if (ret != EOK) { +- goto fail; ++ DEBUG(SSSDBG_TRACE_FUNC, ++ ("Cannot determine the right domain: %s\n", sss_strerror(ret))); ++ shortcut = false; + } + + if (shortcut) { +-- +1.8.4.2 + diff --git a/SOURCES/0056-MAN-Fix-a-typo.patch b/SOURCES/0056-MAN-Fix-a-typo.patch new file mode 100644 index 0000000..4d8b827 --- /dev/null +++ b/SOURCES/0056-MAN-Fix-a-typo.patch @@ -0,0 +1,25 @@ +From c5b312ebf55befc4d37f9a279340b55e65475cd3 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 20 Jan 2014 17:04:28 +0100 +Subject: [PATCH 56/57] MAN: Fix a typo + +--- + 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 43c06955d0182afe5a3c7d703f7c08b7cd09f503..b879bdf63c40e80efa21644bd9ba9d2d3477af06 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -489,7 +489,7 @@ + + example: + +-override_homedir = /home/%u ++fallback_homedir = /home/%u + + + +-- +1.8.4.2 + diff --git a/SOURCES/0057-LDAP-Fix-error-check.patch b/SOURCES/0057-LDAP-Fix-error-check.patch new file mode 100644 index 0000000..fd1664f --- /dev/null +++ b/SOURCES/0057-LDAP-Fix-error-check.patch @@ -0,0 +1,28 @@ +From fe7f5b1a3a965d1667ba1552a2b1165788f3bd2e Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Fri, 17 Jan 2014 10:49:27 +0100 +Subject: [PATCH 57/57] LDAP: Fix error check + +https://fedorahosted.org/sssd/ticket/2199 +--- + src/providers/ldap/ldap_common.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c +index 35ea81360b4ec61eca6b952cd86fc93a6eda17dc..4c94937aad9e25bd1cd0b6d573da2982b0f1be05 100644 +--- a/src/providers/ldap/ldap_common.c ++++ b/src/providers/ldap/ldap_common.c +@@ -831,8 +831,8 @@ errno_t common_parse_search_base(TALLOC_CTX *mem_ctx, + ret = sdap_create_search_base(search_bases, unparsed_base, + LDAP_SCOPE_SUBTREE, old_filter, + &search_bases[0]); +- if (!search_bases[0]) { +- ret = ENOMEM; ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Cannot create new sdap search base\n")); + goto done; + } + +-- +1.8.4.2 + diff --git a/SOURCES/0058-LDAP-Don-t-fail-if-subdomain-cannot-be-found-by-sid.patch b/SOURCES/0058-LDAP-Don-t-fail-if-subdomain-cannot-be-found-by-sid.patch new file mode 100644 index 0000000..c0ab7e0 --- /dev/null +++ b/SOURCES/0058-LDAP-Don-t-fail-if-subdomain-cannot-be-found-by-sid.patch @@ -0,0 +1,47 @@ +From 8509e1fe368b62225b7cf39eb1eec6cac7bf38b3 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Fri, 13 Dec 2013 18:20:08 +0100 +Subject: [PATCH 58/60] LDAP: Don't fail if subdomain cannot be found by sid + +Domain needn't contain sid if id_provider is ldap. +With enabled id mapping, user couldn't be stored, because domain +couldn't be found by sid. + +Resolves: +https://fedorahosted.org/sssd/ticket/2172 +--- + src/providers/ldap/sdap_async_users.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c +index 7f0b2eea0b5ee909bcf148236c7fc43863fe8c13..65c456c8fffb57cbf9e977a49388dbe250d1412a 100644 +--- a/src/providers/ldap/sdap_async_users.c ++++ b/src/providers/ldap/sdap_async_users.c +@@ -124,6 +124,7 @@ int sdap_save_user(TALLOC_CTX *memctx, + bool use_id_mapping; + char *sid_str; + char *dom_sid_str = NULL; ++ struct sss_domain_info *subdomain; + + DEBUG(SSSDBG_TRACE_FUNC, ("Save user\n")); + +@@ -163,11 +164,12 @@ int sdap_save_user(TALLOC_CTX *memctx, + /* If this object has a SID available, we will determine the correct + * domain by its SID. */ + if (sid_str != NULL) { +- dom = find_subdomain_by_sid(get_domains_head(dom), sid_str); +- if (dom == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, ("SID %s does not belong to any known " ++ subdomain = find_subdomain_by_sid(get_domains_head(dom), sid_str); ++ if (subdomain) { ++ dom = subdomain; ++ } else { ++ DEBUG(SSSDBG_TRACE_FUNC, ("SID %s does not belong to any known " + "domain\n", sid_str)); +- return ERR_DOMAIN_NOT_FOUND; + } + } + +-- +1.8.4.2 + diff --git a/SOURCES/0059-LDAP-update-id-mapping-detection-for-ldap-provider.patch b/SOURCES/0059-LDAP-update-id-mapping-detection-for-ldap-provider.patch new file mode 100644 index 0000000..f1573d8 --- /dev/null +++ b/SOURCES/0059-LDAP-update-id-mapping-detection-for-ldap-provider.patch @@ -0,0 +1,33 @@ +From adff1d0ac15ef7fd58cf2bc79af60f38c807126c Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Wed, 15 Jan 2014 14:55:10 +0100 +Subject: [PATCH 59/60] LDAP: update id mapping detection for ldap provider + +For id_provider ldap, it is only necessary to enable option ldap_id_mapping. +It is an regression introduced in the commit d3e1d88ce7de3216a862b + +Resolves: +https://fedorahosted.org/sssd/ticket/2172 +--- + src/providers/ldap/sdap_idmap.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/providers/ldap/sdap_idmap.c b/src/providers/ldap/sdap_idmap.c +index 249201def04131e01722479026b851e47e2283b5..b6455b81fbdedffc92bbaf8bdfbc12c1615a22f5 100644 +--- a/src/providers/ldap/sdap_idmap.c ++++ b/src/providers/ldap/sdap_idmap.c +@@ -522,6 +522,11 @@ bool sdap_idmap_domain_has_algorithmic_mapping(struct sdap_idmap_ctx *ctx, + int ret; + TALLOC_CTX *tmp_ctx = NULL; + ++ if (dp_opt_get_bool(ctx->id_ctx->opts->basic, SDAP_ID_MAPPING) ++ && 0 == strcmp("ldap", ctx->id_ctx->be->bet_info[BET_ID].mod_name)) { ++ return true; ++ } ++ + err = sss_idmap_domain_has_algorithmic_mapping(ctx->map, dom_sid, + &has_algorithmic_mapping); + if (err == IDMAP_SUCCESS) { +-- +1.8.4.2 + diff --git a/SOURCES/0060-sdap_idamp-Fall-back-to-another-method-if-sid-is-wro.patch b/SOURCES/0060-sdap_idamp-Fall-back-to-another-method-if-sid-is-wro.patch new file mode 100644 index 0000000..ccfa04f --- /dev/null +++ b/SOURCES/0060-sdap_idamp-Fall-back-to-another-method-if-sid-is-wro.patch @@ -0,0 +1,42 @@ +From 993aaa15cf4b128951fc9bd4a574e7ac5895d942 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Fri, 13 Dec 2013 15:33:23 +0100 +Subject: [PATCH 60/60] sdap_idamp: Fall back to another method if sid is wrong + +sss_idmap_domain_has_algorithmic_mapping can return also +IDMAP_SID_INVALID, but it does not mean that idmaping is +unavailable. We should fall back to another method of detection +(sss_idmap_domain_by_name_has_algorithmic_mapping) +and do not return false immediately. + +Resolves: +https://fedorahosted.org/sssd/ticket/2172 +--- + src/providers/ldap/sdap_idmap.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/src/providers/ldap/sdap_idmap.c b/src/providers/ldap/sdap_idmap.c +index b6455b81fbdedffc92bbaf8bdfbc12c1615a22f5..57c448fffa1b13699bd8042d33ac729bddb02ca8 100644 +--- a/src/providers/ldap/sdap_idmap.c ++++ b/src/providers/ldap/sdap_idmap.c +@@ -529,9 +529,15 @@ bool sdap_idmap_domain_has_algorithmic_mapping(struct sdap_idmap_ctx *ctx, + + err = sss_idmap_domain_has_algorithmic_mapping(ctx->map, dom_sid, + &has_algorithmic_mapping); +- if (err == IDMAP_SUCCESS) { ++ switch (err){ ++ case IDMAP_SUCCESS: + return has_algorithmic_mapping; +- } else if (err != IDMAP_SID_UNKNOWN && err != IDMAP_NO_DOMAIN) { ++ case IDMAP_SID_INVALID: /* FALLTHROUGH */ ++ case IDMAP_SID_UNKNOWN: /* FALLTHROUGH */ ++ case IDMAP_NO_DOMAIN: /* FALLTHROUGH */ ++ /* continue with idmap_domain_by_name */ ++ break; ++ default: + return false; + } + +-- +1.8.4.2 + diff --git a/SOURCES/0061-krb5-hint-to-increase-krb5_auth_timeout.patch b/SOURCES/0061-krb5-hint-to-increase-krb5_auth_timeout.patch new file mode 100644 index 0000000..14fbea6 --- /dev/null +++ b/SOURCES/0061-krb5-hint-to-increase-krb5_auth_timeout.patch @@ -0,0 +1,30 @@ +From 4777e706ed485ea61ebb0006c00a3d85440ffe70 Mon Sep 17 00:00:00 2001 +From: Pavel Reichl +Date: Tue, 21 Jan 2014 12:14:01 +0000 +Subject: [PATCH 61/62] krb5: hint to increase krb5_auth_timeout + +Resolves: +https://fedorahosted.org/sssd/ticket/2202 +--- + src/providers/krb5/krb5_child_handler.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c +index d6c1dc1f9707444a82e433a375839cadf73f1259..a0e8f610bbb27a25afa6171763a128dc7b8ea04d 100644 +--- a/src/providers/krb5/krb5_child_handler.c ++++ b/src/providers/krb5/krb5_child_handler.c +@@ -254,7 +254,10 @@ static void krb5_child_timeout(struct tevent_context *ev, + return; + } + +- DEBUG(9, ("timeout for child [%d] reached.\n", state->child_pid)); ++ DEBUG(SSSDBG_IMPORTANT_INFO, ++ ("Timeout for child [%d] reached. In case KDC is distant or network " ++ "is slow you may consider increasing value of krb5_auth_timeout.\n", ++ state->child_pid)); + + ret = kill(state->child_pid, SIGKILL); + if (ret == -1) { +-- +1.8.4.2 + diff --git a/SOURCES/0062-LDAP-Don-t-abort-request-if-no-id-mapping-domain-mat.patch b/SOURCES/0062-LDAP-Don-t-abort-request-if-no-id-mapping-domain-mat.patch new file mode 100644 index 0000000..1957040 --- /dev/null +++ b/SOURCES/0062-LDAP-Don-t-abort-request-if-no-id-mapping-domain-mat.patch @@ -0,0 +1,111 @@ +From 2ea997d55fb7b18bbf153d5fa625b688285dfdb9 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Fri, 24 Jan 2014 10:02:23 +0100 +Subject: [PATCH 62/62] LDAP: Don't abort request if no id mapping domain + matches + +If an ID was requested from the back end, but no ID mapping domain +matched, the request ended with a scary error message. It's better to +treat the request as if no such ID was found in the domain + +Related: +https://fedorahosted.org/sssd/ticket/2200 +--- + src/providers/ad/ad_id.c | 2 +- + src/providers/ldap/ldap_id.c | 44 +++++++++++++++++++++++++++++++++++++++----- + 2 files changed, 40 insertions(+), 6 deletions(-) + +diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c +index ada47753fb337641df582a5a59affe8124fc2035..e74653b734010712ff0562ce1bcbad2b03aba27e 100644 +--- a/src/providers/ad/ad_id.c ++++ b/src/providers/ad/ad_id.c +@@ -386,7 +386,7 @@ ad_account_info_complete(struct tevent_req *req) + error_text = NULL; + } else { + DEBUG(SSSDBG_FATAL_FAILURE, +- ("Bug: dp_error is OK on failed request")); ++ ("Bug: dp_error is OK on failed request\n")); + dp_error = DP_ERR_FATAL; + error_text = req_error_text; + } +diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c +index 793bc99ebcec883be7db3fc9dd56fa511d8ba3bb..e36c1f697c18e865a47d991dad103fc440456118 100644 +--- a/src/providers/ldap/ldap_id.c ++++ b/src/providers/ldap/ldap_id.c +@@ -129,7 +129,20 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, + /* Convert the UID to its objectSID */ + err = sss_idmap_unix_to_sid(ctx->opts->idmap_ctx->map, + uid, &sid); +- if (err != IDMAP_SUCCESS) { ++ if (err == IDMAP_NO_DOMAIN) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ ("[%s] did not match any configured ID mapping domain\n", ++ name)); ++ ++ ret = sysdb_delete_user(state->sysdb, ++ state->domain, NULL, uid); ++ if (ret == ENOENT) { ++ /* Ignore errors to remove users that were not cached previously */ ++ ret = EOK; ++ } ++ ++ goto fail; ++ } else if (err != IDMAP_SUCCESS) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Mapping ID [%s] to SID failed: [%s]\n", + name, idmap_error_string(err))); +@@ -213,7 +226,11 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, + return req; + + fail: +- tevent_req_error(req, ret); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ } else { ++ tevent_req_done(req); ++ } + tevent_req_post(req, ev); + return req; + } +@@ -496,10 +513,23 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx, + goto fail; + } + +- /* Convert the UID to its objectSID */ ++ /* Convert the GID to its objectSID */ + err = sss_idmap_unix_to_sid(ctx->opts->idmap_ctx->map, + gid, &sid); +- if (err != IDMAP_SUCCESS) { ++ if (err == IDMAP_NO_DOMAIN) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ ("[%s] did not match any configured ID mapping domain\n", ++ name)); ++ ++ ret = sysdb_delete_group(state->sysdb, ++ state->domain, NULL, gid); ++ if (ret == ENOENT) { ++ /* Ignore errors to remove users that were not cached previously */ ++ ret = EOK; ++ } ++ ++ goto fail; ++ } else if (err != IDMAP_SUCCESS) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Mapping ID [%s] to SID failed: [%s]\n", + name, idmap_error_string(err))); +@@ -587,7 +617,11 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx, + return req; + + fail: +- tevent_req_error(req, ret); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ } else { ++ tevent_req_done(req); ++ } + tevent_req_post(req, ev); + return req; + } +-- +1.8.4.2 + diff --git a/SOURCES/0063-sudo-memset-tm-when-converting-time-attributes.patch b/SOURCES/0063-sudo-memset-tm-when-converting-time-attributes.patch new file mode 100644 index 0000000..f53462a --- /dev/null +++ b/SOURCES/0063-sudo-memset-tm-when-converting-time-attributes.patch @@ -0,0 +1,34 @@ +From 89eca8339610956f8d95d701dc02d3f8256e2770 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 29 Jan 2014 12:56:08 +0100 +Subject: [PATCH 63/71] sudo: memset tm when converting time attributes + +strptime() which is used to parse LDAP time value does not initialize +all fields of tm structure (especially tm_isdst). This results in +random behavior - when the tm is converted into timestamp via mktime(), +the result depends on current value of tm_isdst. + +Resolves: +https://fedorahosted.org/sssd/ticket/2213 + +b +--- + src/db/sysdb_sudo.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/db/sysdb_sudo.c b/src/db/sysdb_sudo.c +index 4e98b5b35f3968a1db68c32812eac71670578b60..ceaecbd2666cfb84422bd72b3109da9c4aa0f0f3 100644 +--- a/src/db/sysdb_sudo.c ++++ b/src/db/sysdb_sudo.c +@@ -56,6 +56,8 @@ static errno_t sysdb_sudo_convert_time(const char *str, time_t *unix_time) + NULL}; + + for (format = formats; *format != NULL; format++) { ++ /* strptime() may leave some fields uninitialized */ ++ memset(&tm, 0, sizeof(struct tm)); + tret = strptime(str, *format, &tm); + if (tret != NULL && *tret == '\0') { + *unix_time = mktime(&tm); +-- +1.8.4.2 + diff --git a/SOURCES/0064-AD-Don-t-mark-domain-as-enumerated-twice.patch b/SOURCES/0064-AD-Don-t-mark-domain-as-enumerated-twice.patch new file mode 100644 index 0000000..0e318c1 --- /dev/null +++ b/SOURCES/0064-AD-Don-t-mark-domain-as-enumerated-twice.patch @@ -0,0 +1,38 @@ +From 392058122b5993a195436c2d5d9833e5e1dd0198 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 16 Dec 2013 03:36:19 +0100 +Subject: [PATCH 64/71] AD: Don't mark domain as enumerated twice + +The domain was already marked as enumerated using sysdb_set_enumerated +in the enumeration request itself. +--- + src/providers/ad/ad_id.c | 13 ------------- + 1 file changed, 13 deletions(-) + +diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c +index e74653b734010712ff0562ce1bcbad2b03aba27e..85edcf6d604f705f5645f77689c2b4c7471b5edd 100644 +--- a/src/providers/ad/ad_id.c ++++ b/src/providers/ad/ad_id.c +@@ -571,19 +571,6 @@ ad_enumeration_done(struct tevent_req *subreq) + return; + } + +- /* Ok, we've completed an enumeration. Save this to the +- * sysdb so we can postpone starting up the enumeration +- * process on the next SSSD service restart (to avoid +- * slowing down system boot-up +- */ +- ret = sysdb_set_enumerated(state->sdom->dom->sysdb, +- state->sdom->dom, true); +- if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, +- ("Could not mark domain as having enumerated.\n")); +- /* This error is non-fatal, so continue */ +- } +- + tevent_req_done(req); + } + +-- +1.8.4.2 + diff --git a/SOURCES/0065-AD-Store-info-on-whether-a-subdomain-is-set-to-enume.patch b/SOURCES/0065-AD-Store-info-on-whether-a-subdomain-is-set-to-enume.patch new file mode 100644 index 0000000..284d0d1 --- /dev/null +++ b/SOURCES/0065-AD-Store-info-on-whether-a-subdomain-is-set-to-enume.patch @@ -0,0 +1,97 @@ +From c6808be838567870a251d79baad1080910f6ec4c Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 10 Dec 2013 17:33:35 +0100 +Subject: [PATCH 65/71] AD: Store info on whether a subdomain is set to + enumerate + +Depending on the state of the subdomain_enumerate variable, the newly +created subdomain object is created with the right value of "enumerate" +attribute in the sysdb. +--- + src/providers/ad/ad_subdomains.c | 38 +++++++++++++++++++++++++++++++++----- + 1 file changed, 33 insertions(+), 5 deletions(-) + +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index 62c3e16d0d3323a32848b4fbf54d2a151c16f64c..348561a85524c203293c713d3f31552a99d74a43 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -223,10 +223,28 @@ ads_store_sdap_subdom(struct ad_subdomains_ctx *ctx, + return EOK; + } + ++static errno_t ad_subdom_enumerates(struct sss_domain_info *parent, ++ struct sysdb_attrs *attrs, ++ bool *_enumerates) ++{ ++ errno_t ret; ++ const char *name; ++ ++ 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 ret; ++ } ++ ++ *_enumerates = subdomain_enumerates(parent, name); ++ return EOK; ++} ++ + static errno_t + ad_subdom_store(struct ad_subdomains_ctx *ctx, + struct sss_domain_info *domain, +- struct sysdb_attrs *subdom_attrs) ++ struct sysdb_attrs *subdom_attrs, ++ bool enumerate) + { + TALLOC_CTX *tmp_ctx; + const char *name; +@@ -293,9 +311,8 @@ ad_subdom_store(struct ad_subdomains_ctx *ctx, + name, + sid_str); + +- /* AD subdomains are currently all mpg and do not enumerate */ + ret = sysdb_subdomain_store(domain->sysdb, name, realm, flat, sid_str, +- mpg, false, domain->forest); ++ mpg, enumerate, domain->forest); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("sysdb_subdomain_store failed.\n")); + goto done; +@@ -319,6 +336,7 @@ static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx, + const char *value; + int c, h; + int ret; ++ bool enumerate; + + domain = ctx->be_ctx->domain; + memset(handled, 0, sizeof(bool) * count); +@@ -367,7 +385,12 @@ static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx, + talloc_zfree(sdom); + } else { + /* ok let's try to update it */ +- ret = ad_subdom_store(ctx, domain, reply[c]); ++ ret = ad_subdom_enumerates(domain, reply[c], &enumerate); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = ad_subdom_store(ctx, domain, reply[c], enumerate); + if (ret) { + /* Nothing we can do about the error. Let's at least try + * to reuse the existing domains +@@ -396,7 +419,12 @@ static errno_t ad_subdomains_refresh(struct ad_subdomains_ctx *ctx, + /* Nothing we can do about the error. Let's at least try + * to reuse the existing domains. + */ +- ret = ad_subdom_store(ctx, domain, reply[c]); ++ ret = ad_subdom_enumerates(domain, reply[c], &enumerate); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = ad_subdom_store(ctx, domain, reply[c], enumerate); + if (ret) { + DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to parse subdom data, " + "will try to use cached subdomain\n")); +-- +1.8.4.2 + diff --git a/SOURCES/0066-LDAP-Pass-a-private-context-to-enumeration-ptask-ins.patch b/SOURCES/0066-LDAP-Pass-a-private-context-to-enumeration-ptask-ins.patch new file mode 100644 index 0000000..bba823a --- /dev/null +++ b/SOURCES/0066-LDAP-Pass-a-private-context-to-enumeration-ptask-ins.patch @@ -0,0 +1,284 @@ +From 1a5d7f670d94cb5c2b4a727e1e4cb3f1debadaa7 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 10 Dec 2013 21:49:45 +0100 +Subject: [PATCH 66/71] LDAP: Pass a private context to enumeration ptask + instead of hardcoded connection + +Previously, the sdap-domain enumeration request used a single connection context to +download all the data. Now we'd like to use different connections to +download different objects, so the ID context is passed in and the +request itself decides which connection to use for the sdap-domain +enumeration. +--- + src/providers/ad/ad_id.c | 12 ++++++++---- + src/providers/ad/ad_init.c | 7 ++++--- + src/providers/ad/ad_subdomains.c | 8 +++++--- + src/providers/ipa/ipa_subdomains.c | 8 +++++--- + src/providers/ldap/ldap_common.c | 15 +++++++++------ + src/providers/ldap/ldap_common.h | 17 +++++++++-------- + src/providers/ldap/ldap_id_enum.c | 21 ++++++++++++--------- + 7 files changed, 52 insertions(+), 36 deletions(-) + +diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c +index 85edcf6d604f705f5645f77689c2b4c7471b5edd..99383c13bdadfe9eb2af9f9323ca19a9759d4620 100644 +--- a/src/providers/ad/ad_id.c ++++ b/src/providers/ad/ad_id.c +@@ -414,6 +414,7 @@ ad_check_online(struct be_req *be_req) + } + + struct ad_enumeration_state { ++ struct ad_id_ctx *id_ctx; + struct ldap_enum_ctx *ectx; + struct sdap_id_op *sdap_op; + struct tevent_context *ev; +@@ -443,6 +444,7 @@ ad_enumeration_send(TALLOC_CTX *mem_ctx, + + ectx = talloc_get_type(pvt, struct ldap_enum_ctx); + if (ectx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot retrieve ldap_enum_ctx!\n")); + ret = EFAULT; + goto fail; + } +@@ -450,8 +452,10 @@ ad_enumeration_send(TALLOC_CTX *mem_ctx, + state->ectx = ectx; + state->ev = ev; + state->sdom = ectx->sdom; ++ state->id_ctx = talloc_get_type(ectx->pvt, struct ad_id_ctx); + +- state->sdap_op = sdap_id_op_create(state, ectx->conn->conn_cache); ++ state->sdap_op = sdap_id_op_create(state, ++ state->id_ctx->ldap_ctx->conn_cache); + if (state->sdap_op == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("sdap_id_op_create failed.\n")); + ret = ENOMEM; +@@ -500,7 +504,7 @@ ad_enumeration_conn_done(struct tevent_req *subreq) + } + + subreq = ad_master_domain_send(state, state->ev, +- state->ectx->conn, ++ state->id_ctx->ldap_ctx, + state->sdap_op, + state->sdom->dom->name); + if (subreq == NULL) { +@@ -540,8 +544,8 @@ ad_enumeration_master_done(struct tevent_req *subreq) + return; + } + +- subreq = sdap_dom_enum_send(state, state->ev, state->ectx->ctx, +- state->sdom, state->ectx->conn); ++ subreq = sdap_dom_enum_send(state, state->ev, state->id_ctx->sdap_id_ctx, ++ state->sdom, state->id_ctx->ldap_ctx); + if (subreq == NULL) { + /* The ptask API will reschedule the enumeration on its own on + * failure */ +diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c +index ed69a7d9889bac1281b5ff7c7b0f290ab09173fb..eff6d990d131e3aba124d252d001dd39e78b45cf 100644 +--- a/src/providers/ad/ad_init.c ++++ b/src/providers/ad/ad_init.c +@@ -205,11 +205,12 @@ sssm_ad_id_init(struct be_ctx *bectx, + goto done; + } + +- ret = sdap_id_setup_tasks(ad_ctx->sdap_id_ctx, +- ad_ctx->sdap_id_ctx->conn, ++ ret = sdap_id_setup_tasks(bectx, ++ ad_ctx->sdap_id_ctx, + ad_ctx->sdap_id_ctx->opts->sdom, + ad_enumeration_send, +- ad_enumeration_recv); ++ ad_enumeration_recv, ++ ad_ctx); + if (ret != EOK) { + goto done; + } +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index 348561a85524c203293c713d3f31552a99d74a43..e7871cc32407893948fe1b2803258d68c70889c1 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -177,10 +177,12 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, + return EFAULT; + } + +- ret = sdap_id_setup_tasks(ad_id_ctx->sdap_id_ctx, +- ad_id_ctx->ldap_ctx, sdom, ++ ret = sdap_id_setup_tasks(be_ctx, ++ ad_id_ctx->sdap_id_ctx, ++ sdom, + ldap_enumeration_send, +- ldap_enumeration_recv); ++ ldap_enumeration_recv, ++ ad_id_ctx->sdap_id_ctx); + if (ret != EOK) { + talloc_free(ad_options); + return ret; +diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c +index d9c204451f1b734ee98ce4c48f3f139731e47dec..88b6ba52538be83417e98c9a5dd033bea87ebe4b 100644 +--- a/src/providers/ipa/ipa_subdomains.c ++++ b/src/providers/ipa/ipa_subdomains.c +@@ -183,10 +183,12 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx, + return EFAULT; + } + +- ret = sdap_id_setup_tasks(ad_id_ctx->sdap_id_ctx, +- ad_id_ctx->ldap_ctx, sdom, ++ ret = sdap_id_setup_tasks(be_ctx, ++ ad_id_ctx->sdap_id_ctx, ++ sdom, + ldap_enumeration_send, +- ldap_enumeration_recv); ++ ldap_enumeration_recv, ++ ad_id_ctx->sdap_id_ctx); + if (ret != EOK) { + talloc_free(ad_options); + return ret; +diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c +index 4c94937aad9e25bd1cd0b6d573da2982b0f1be05..e799c783c118309409faca0294eadc4736d15108 100644 +--- a/src/providers/ldap/ldap_common.c ++++ b/src/providers/ldap/ldap_common.c +@@ -974,16 +974,18 @@ void sdap_mark_offline(struct sdap_id_ctx *ctx) + + int ldap_id_setup_tasks(struct sdap_id_ctx *ctx) + { +- return sdap_id_setup_tasks(ctx, ctx->conn, ctx->opts->sdom, ++ return sdap_id_setup_tasks(ctx->be, ctx, ctx->opts->sdom, + ldap_enumeration_send, +- ldap_enumeration_recv); ++ ldap_enumeration_recv, ++ ctx); + } + +-int sdap_id_setup_tasks(struct sdap_id_ctx *ctx, +- struct sdap_id_conn_ctx *conn, ++int sdap_id_setup_tasks(struct be_ctx *be_ctx, ++ struct sdap_id_ctx *ctx, + struct sdap_domain *sdom, + be_ptask_send_t send_fn, +- be_ptask_recv_t recv_fn) ++ be_ptask_recv_t recv_fn, ++ void *pvt) + { + int ret; + +@@ -991,7 +993,8 @@ int sdap_id_setup_tasks(struct sdap_id_ctx *ctx, + if (sdom->dom->enumerate) { + DEBUG(SSSDBG_TRACE_FUNC, ("Setting up enumeration for %s\n", + sdom->dom->name)); +- ret = ldap_setup_enumeration(ctx, conn, sdom, send_fn, recv_fn); ++ ret = ldap_setup_enumeration(be_ctx, ctx->opts, sdom, ++ send_fn, recv_fn, pvt); + } else { + /* the enumeration task, runs the cleanup process by itself, + * but if enumeration is not running we need to schedule it */ +diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h +index b3bd950e1dca6df0f5668397d5e5a0796e519862..889d5b118861e4ea3f51ab8a8ea5c5947e2560b9 100644 +--- a/src/providers/ldap/ldap_common.h ++++ b/src/providers/ldap/ldap_common.h +@@ -95,11 +95,12 @@ void sdap_handle_account_info(struct be_req *breq, struct sdap_id_ctx *ctx, + + /* Set up enumeration and/or cleanup */ + int ldap_id_setup_tasks(struct sdap_id_ctx *ctx); +-int sdap_id_setup_tasks(struct sdap_id_ctx *ctx, +- struct sdap_id_conn_ctx *conn, ++int sdap_id_setup_tasks(struct be_ctx *be_ctx, ++ struct sdap_id_ctx *ctx, + struct sdap_domain *sdom, + be_ptask_send_t send_fn, +- be_ptask_recv_t recv_fn); ++ be_ptask_recv_t recv_fn, ++ void *pvt); + + struct tevent_req * + sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx, +@@ -177,16 +178,16 @@ int ldap_get_autofs_options(TALLOC_CTX *memctx, + * structure that contains the request data + */ + struct ldap_enum_ctx { +- struct sdap_id_ctx *ctx; + struct sdap_domain *sdom; +- struct sdap_id_conn_ctx *conn; ++ void *pvt; + }; + +-errno_t ldap_setup_enumeration(struct sdap_id_ctx *ctx, +- struct sdap_id_conn_ctx *conn, ++errno_t ldap_setup_enumeration(struct be_ctx *be_ctx, ++ struct sdap_options *opts, + struct sdap_domain *sdom, + be_ptask_send_t send_fn, +- be_ptask_recv_t recv_fn); ++ be_ptask_recv_t recv_fn, ++ void *pvt); + struct tevent_req * + ldap_enumeration_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, +diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c +index 8cccaa916a24beb10fe692d9a0e09f5f47ceb6f7..c791496a6143b23118bf17a58f738fb0bfb5f95a 100644 +--- a/src/providers/ldap/ldap_id_enum.c ++++ b/src/providers/ldap/ldap_id_enum.c +@@ -27,11 +27,12 @@ + #include "providers/ldap/ldap_common.h" + #include "providers/ldap/sdap_async_enum.h" + +-errno_t ldap_setup_enumeration(struct sdap_id_ctx *ctx, +- struct sdap_id_conn_ctx *conn, ++errno_t ldap_setup_enumeration(struct be_ctx *be_ctx, ++ struct sdap_options *opts, + struct sdap_domain *sdom, + be_ptask_send_t send_fn, +- be_ptask_recv_t recv_fn) ++ be_ptask_recv_t recv_fn, ++ void *pvt) + { + errno_t ret; + time_t first_delay; +@@ -60,17 +61,16 @@ errno_t ldap_setup_enumeration(struct sdap_id_ctx *ctx, + first_delay = 0; + } + +- period = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT); ++ period = dp_opt_get_int(opts->basic, SDAP_ENUM_REFRESH_TIMEOUT); + + ectx = talloc(sdom, struct ldap_enum_ctx); + if (ectx == NULL) { + return ENOMEM; + } +- ectx->ctx = ctx; + ectx->sdom = sdom; +- ectx->conn = conn; ++ ectx->pvt = pvt; + +- ret = be_ptask_create(sdom, ctx->be, ++ ret = be_ptask_create(sdom, be_ctx, + period, /* period */ + first_delay, /* first_delay */ + 5, /* enabled delay */ +@@ -91,6 +91,7 @@ errno_t ldap_setup_enumeration(struct sdap_id_ctx *ctx, + + struct ldap_enumeration_state { + struct ldap_enum_ctx *ectx; ++ struct sdap_id_ctx *id_ctx; + struct sss_domain_info *dom; + }; + +@@ -118,14 +119,16 @@ ldap_enumeration_send(TALLOC_CTX *mem_ctx, + + ectx = talloc_get_type(pvt, struct ldap_enum_ctx); + if (ectx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot retrieve ldap_enum_ctx!\n")); + ret = EFAULT; + goto fail; + } + state->ectx = ectx; + state->dom = ectx->sdom->dom; ++ state->id_ctx = talloc_get_type_abort(ectx->pvt, struct sdap_id_ctx); + +- subreq = sdap_dom_enum_send(ectx, ev, ectx->ctx, ectx->sdom, +- ectx->conn); ++ subreq = sdap_dom_enum_send(ectx, ev, state->id_ctx, ectx->sdom, ++ state->id_ctx->conn); + if (subreq == NULL) { + /* The ptask API will reschedule the enumeration on its own on + * failure */ +-- +1.8.4.2 + diff --git a/SOURCES/0067-LDAP-Add-enum-request-with-custom-connection.patch b/SOURCES/0067-LDAP-Add-enum-request-with-custom-connection.patch new file mode 100644 index 0000000..04b5e24 --- /dev/null +++ b/SOURCES/0067-LDAP-Add-enum-request-with-custom-connection.patch @@ -0,0 +1,482 @@ +From 431198674303beea2a6a25af6d3fa4e852995b26 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 16 Dec 2013 02:41:53 +0100 +Subject: [PATCH 67/71] LDAP: Add enum request with custom connection + +This commit changes the enumerate-sdap-domain request to accept a +connection context per object that can be enumerated. Internally in the +request, an sdap_id_op is also created per enumerated object type. + +This change will allow i.e. users to be enumerated using GC connection, +while keeping the LDAP connection for groups and services. +--- + src/providers/ldap/sdap_async_enum.c | 309 +++++++++++++++++++++-------------- + src/providers/ldap/sdap_async_enum.h | 11 ++ + 2 files changed, 193 insertions(+), 127 deletions(-) + +diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c +index 8487f9a13b279bc71f633590bbab163945fc8f7c..cbc56be20526e6c2323f9fd1b49038dd4bf13fe5 100644 +--- a/src/providers/ldap/sdap_async_enum.c ++++ b/src/providers/ldap/sdap_async_enum.c +@@ -47,49 +47,56 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx, + bool purge); + static errno_t enum_groups_recv(struct tevent_req *req); + +-/* ==Enumeration-Request==================================================== */ +-struct sdap_dom_enum_state { ++/* ==Enumeration-Request-with-connections=================================== */ ++struct sdap_dom_enum_ex_state { + struct tevent_context *ev; + struct sdap_id_ctx *ctx; + struct sdap_domain *sdom; +- struct sdap_id_conn_ctx *conn; +- struct sdap_id_op *op; ++ ++ struct sdap_id_conn_ctx *user_conn; ++ struct sdap_id_conn_ctx *group_conn; ++ struct sdap_id_conn_ctx *svc_conn; ++ struct sdap_id_op *user_op; ++ struct sdap_id_op *group_op; ++ struct sdap_id_op *svc_op; + + bool purge; + }; + +-static errno_t sdap_dom_enum_retry(struct tevent_req *req); +-static void sdap_dom_enum_conn_done(struct tevent_req *subreq); +-static void sdap_dom_enum_users_done(struct tevent_req *subreq); +-static void sdap_dom_enum_groups_done(struct tevent_req *subreq); +-static void sdap_dom_enum_services_done(struct tevent_req *subreq); ++static errno_t sdap_dom_enum_ex_retry(struct tevent_req *req, ++ struct sdap_id_op *op, ++ tevent_req_fn tcb); ++static bool sdap_dom_enum_ex_connected(struct tevent_req *subreq); ++static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq); ++static void sdap_dom_enum_ex_users_done(struct tevent_req *subreq); ++static void sdap_dom_enum_ex_get_groups(struct tevent_req *subreq); ++static void sdap_dom_enum_ex_groups_done(struct tevent_req *subreq); ++static void sdap_dom_enum_ex_get_svcs(struct tevent_req *subreq); ++static void sdap_dom_enum_ex_svcs_done(struct tevent_req *subreq); + + struct tevent_req * +-sdap_dom_enum_send(TALLOC_CTX *memctx, +- struct tevent_context *ev, +- struct sdap_id_ctx *ctx, +- struct sdap_domain *sdom, +- struct sdap_id_conn_ctx *conn) ++sdap_dom_enum_ex_send(TALLOC_CTX *memctx, ++ struct tevent_context *ev, ++ struct sdap_id_ctx *ctx, ++ struct sdap_domain *sdom, ++ struct sdap_id_conn_ctx *user_conn, ++ struct sdap_id_conn_ctx *group_conn, ++ struct sdap_id_conn_ctx *svc_conn) + { + struct tevent_req *req; +- struct sdap_dom_enum_state *state; ++ struct sdap_dom_enum_ex_state *state; + int t; + errno_t ret; + +- req = tevent_req_create(ctx, &state, struct sdap_dom_enum_state); +- if (!req) return NULL; ++ req = tevent_req_create(ctx, &state, struct sdap_dom_enum_ex_state); ++ if (req == NULL) return NULL; + + state->ev = ev; + state->ctx = ctx; + state->sdom = sdom; +- state->conn = conn; +- state->op = sdap_id_op_create(state, state->ctx->conn->conn_cache); +- if (!state->op) { +- DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create failed\n")); +- ret = EIO; +- goto fail; +- } +- ++ state->user_conn = user_conn; ++ state->group_conn = group_conn; ++ state->svc_conn = svc_conn; + sdom->last_enum = tevent_timeval_current(); + + t = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT); +@@ -97,9 +104,17 @@ sdap_dom_enum_send(TALLOC_CTX *memctx, + state->purge = true; + } + +- ret = sdap_dom_enum_retry(req); ++ state->user_op = sdap_id_op_create(state, user_conn->conn_cache); ++ if (state->user_op == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create failed for users\n")); ++ ret = EIO; ++ goto fail; ++ } ++ ++ ret = sdap_dom_enum_ex_retry(req, state->user_op, ++ sdap_dom_enum_ex_get_users); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, ("ldap_id_enumerate_retry failed\n")); ++ DEBUG(SSSDBG_OP_FAILURE, ("sdap_dom_enum_ex_retry failed\n")); + goto fail; + } + +@@ -111,31 +126,32 @@ fail: + return req; + } + +-static errno_t sdap_dom_enum_retry(struct tevent_req *req) ++static errno_t sdap_dom_enum_ex_retry(struct tevent_req *req, ++ struct sdap_id_op *op, ++ tevent_req_fn tcb) + { +- struct sdap_dom_enum_state *state = tevent_req_data(req, +- struct sdap_dom_enum_state); ++ struct sdap_dom_enum_ex_state *state = tevent_req_data(req, ++ struct sdap_dom_enum_ex_state); + struct tevent_req *subreq; + errno_t ret; + +- subreq = sdap_id_op_connect_send(state->op, state, &ret); ++ subreq = sdap_id_op_connect_send(op, state, &ret); + if (subreq == NULL) { + DEBUG(SSSDBG_OP_FAILURE, + ("sdap_id_op_connect_send failed: %d\n", ret)); + return ret; + } + +- tevent_req_set_callback(subreq, sdap_dom_enum_conn_done, req); ++ tevent_req_set_callback(subreq, tcb, req); + return EOK; + } + +-static void sdap_dom_enum_conn_done(struct tevent_req *subreq) ++static bool sdap_dom_enum_ex_connected(struct tevent_req *subreq) + { ++ errno_t ret; ++ int dp_error; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); +- struct sdap_dom_enum_state *state = tevent_req_data(req, +- struct sdap_dom_enum_state); +- int ret, dp_error; + + ret = sdap_id_op_connect_recv(subreq, &dp_error); + talloc_zfree(subreq); +@@ -150,150 +166,173 @@ static void sdap_dom_enum_conn_done(struct tevent_req *subreq) + "LDAP server: (%d)[%s]\n", ret, strerror(ret))); + tevent_req_error(req, ret); + } ++ return false; ++ } ++ ++ return true; ++} ++ ++static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct sdap_dom_enum_ex_state *state = tevent_req_data(req, ++ struct sdap_dom_enum_ex_state); ++ ++ if (sdap_dom_enum_ex_connected(subreq) == false) { + return; + } + + subreq = enum_users_send(state, state->ev, + state->ctx, state->sdom, +- state->op, state->purge); ++ state->user_op, state->purge); + if (subreq == NULL) { + tevent_req_error(req, ENOMEM); + return; + } +- tevent_req_set_callback(subreq, sdap_dom_enum_users_done, req); ++ tevent_req_set_callback(subreq, sdap_dom_enum_ex_users_done, req); + } + +-static void sdap_dom_enum_users_done(struct tevent_req *subreq) ++static void sdap_dom_enum_ex_users_done(struct tevent_req *subreq) + { + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); +- struct sdap_dom_enum_state *state = tevent_req_data(req, +- struct sdap_dom_enum_state); +- uint64_t err = 0; +- int ret, dp_error = DP_ERR_FATAL; ++ struct sdap_dom_enum_ex_state *state = tevent_req_data(req, ++ struct sdap_dom_enum_ex_state); ++ errno_t ret; ++ int dp_error; + +- err = enum_users_recv(subreq); ++ ret = enum_users_recv(subreq); + talloc_zfree(subreq); +- if (err != EOK && err != ENOENT) { +- /* We call sdap_id_op_done only on error +- * as the connection is reused by groups enumeration */ +- ret = sdap_id_op_done(state->op, (int)err, &dp_error); +- if (dp_error == DP_ERR_OK) { +- /* retry */ +- ret = sdap_dom_enum_retry(req); +- if (ret == EOK) { +- return; +- } +- +- dp_error = DP_ERR_FATAL; +- } +- +- if (dp_error == DP_ERR_OFFLINE) { +- tevent_req_done(req); +- } else { +- DEBUG(SSSDBG_OP_FAILURE, +- ("User enumeration failed with: (%d)[%s]\n", +- ret, strerror(ret))); ++ ret = sdap_id_op_done(state->user_op, ret, &dp_error); ++ if (dp_error == DP_ERR_OK && ret != EOK) { ++ /* retry */ ++ ret = sdap_dom_enum_ex_retry(req, state->user_op, ++ sdap_dom_enum_ex_get_users); ++ if (ret != EOK) { + tevent_req_error(req, ret); ++ return; + } + return; + } + ++ state->group_op = sdap_id_op_create(state, state->group_conn->conn_cache); ++ if (state->group_op == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create failed for groups\n")); ++ tevent_req_error(req, EIO); ++ return; ++ } ++ ++ ret = sdap_dom_enum_ex_retry(req, state->group_op, ++ sdap_dom_enum_ex_get_groups); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ /* Continues to sdap_dom_enum_ex_get_groups */ ++} ++ ++static void sdap_dom_enum_ex_get_groups(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct sdap_dom_enum_ex_state *state = tevent_req_data(req, ++ struct sdap_dom_enum_ex_state); ++ ++ if (sdap_dom_enum_ex_connected(subreq) == false) { ++ return; ++ } ++ + subreq = enum_groups_send(state, state->ev, state->ctx, + state->sdom, +- state->op, state->purge); ++ state->group_op, state->purge); + if (subreq == NULL) { + tevent_req_error(req, ENOMEM); + return; + } +- tevent_req_set_callback(subreq, sdap_dom_enum_groups_done, req); ++ tevent_req_set_callback(subreq, sdap_dom_enum_ex_groups_done, req); + } + +-static void sdap_dom_enum_groups_done(struct tevent_req *subreq) ++static void sdap_dom_enum_ex_groups_done(struct tevent_req *subreq) + { + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); +- struct sdap_dom_enum_state *state = tevent_req_data(req, +- struct sdap_dom_enum_state); +- uint64_t err = 0; +- int ret, dp_error = DP_ERR_FATAL; ++ struct sdap_dom_enum_ex_state *state = tevent_req_data(req, ++ struct sdap_dom_enum_ex_state); ++ int ret; ++ int dp_error; + +- err = enum_groups_recv(subreq); ++ ret = enum_groups_recv(subreq); + talloc_zfree(subreq); +- if (err != EOK && err != ENOENT) { +- /* We call sdap_id_op_done only on error +- * as the connection is reused by services enumeration */ +- ret = sdap_id_op_done(state->op, (int)err, &dp_error); +- if (dp_error == DP_ERR_OK && ret != EOK) { +- /* retry */ +- ret = sdap_dom_enum_retry(req); +- if (ret == EOK) { +- return; +- } +- +- dp_error = DP_ERR_FATAL; +- } +- ++ ret = sdap_id_op_done(state->group_op, ret, &dp_error); ++ if (dp_error == DP_ERR_OK && ret != EOK) { ++ /* retry */ ++ ret = sdap_dom_enum_ex_retry(req, state->group_op, ++ sdap_dom_enum_ex_get_groups); + if (ret != EOK) { +- if (dp_error == DP_ERR_OFFLINE) { +- tevent_req_done(req); +- } else { +- DEBUG(SSSDBG_OP_FAILURE, +- ("Group enumeration failed with: (%d)[%s]\n", +- ret, strerror(ret))); +- tevent_req_error(req, ret); +- } +- ++ tevent_req_error(req, ret); + return; + } ++ return; ++ } ++ ++ ++ state->svc_op = sdap_id_op_create(state, state->svc_conn->conn_cache); ++ if (state->svc_op == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create failed for svcs\n")); ++ tevent_req_error(req, EIO); ++ return; ++ } ++ ++ ret = sdap_dom_enum_ex_retry(req, state->svc_op, ++ sdap_dom_enum_ex_get_svcs); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++} ++ ++static void sdap_dom_enum_ex_get_svcs(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct sdap_dom_enum_ex_state *state = tevent_req_data(req, ++ struct sdap_dom_enum_ex_state); ++ ++ if (sdap_dom_enum_ex_connected(subreq) == false) { ++ return; + } + + subreq = enum_services_send(state, state->ev, state->ctx, +- state->op, state->purge); ++ state->svc_op, state->purge); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } +- tevent_req_set_callback(subreq, sdap_dom_enum_services_done, req); ++ tevent_req_set_callback(subreq, sdap_dom_enum_ex_svcs_done, req); + } + +-static void sdap_dom_enum_services_done(struct tevent_req *subreq) ++static void sdap_dom_enum_ex_svcs_done(struct tevent_req *subreq) + { +- errno_t ret; +- int dp_error = DP_ERR_FATAL; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); +- struct sdap_dom_enum_state *state = tevent_req_data(req, +- struct sdap_dom_enum_state); ++ struct sdap_dom_enum_ex_state *state = tevent_req_data(req, ++ struct sdap_dom_enum_ex_state); ++ int ret; ++ int dp_error; + + ret = enum_services_recv(subreq); + talloc_zfree(subreq); +- if (ret == ENOENT) ret = EOK; +- +- /* All enumerations are complete, so conclude the +- * id_op +- */ +- ret = sdap_id_op_done(state->op, ret, &dp_error); ++ ret = sdap_id_op_done(state->svc_op, ret, &dp_error); + if (dp_error == DP_ERR_OK && ret != EOK) { + /* retry */ +- ret = sdap_dom_enum_retry(req); +- if (ret == EOK) { +- return; +- } +- +- dp_error = DP_ERR_FATAL; +- } +- +- if (ret != EOK) { +- if (dp_error == DP_ERR_OFFLINE) { +- tevent_req_done(req); +- } else { +- DEBUG(SSSDBG_MINOR_FAILURE, +- ("Service enumeration failed with: (%d)[%s]\n", +- ret, strerror(ret))); ++ ret = sdap_dom_enum_ex_retry(req, state->user_op, ++ sdap_dom_enum_ex_get_svcs); ++ if (ret != EOK) { + tevent_req_error(req, ret); ++ return; + } +- + return; + } + +@@ -323,11 +362,27 @@ static void sdap_dom_enum_services_done(struct tevent_req *subreq) + tevent_req_done(req); + } + ++errno_t sdap_dom_enum_ex_recv(struct tevent_req *req) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ return EOK; ++} ++ ++/* ==Enumeration-Request==================================================== */ ++struct tevent_req * ++sdap_dom_enum_send(TALLOC_CTX *memctx, ++ struct tevent_context *ev, ++ struct sdap_id_ctx *ctx, ++ struct sdap_domain *sdom, ++ struct sdap_id_conn_ctx *conn) ++{ ++ return sdap_dom_enum_ex_send(memctx, ev, ctx, sdom, conn, conn, conn); ++} ++ + errno_t sdap_dom_enum_recv(struct tevent_req *req) + { +- TEVENT_REQ_RETURN_ON_ERROR(req); +- +- return EOK; ++ return sdap_dom_enum_ex_recv(req); + } + + /* ==User-Enumeration===================================================== */ +diff --git a/src/providers/ldap/sdap_async_enum.h b/src/providers/ldap/sdap_async_enum.h +index 04ec8c6dcbec4bcce0de67b9e10acc857c9e9416..2da38f988913fa0d6f252697925e50e05eb794a6 100644 +--- a/src/providers/ldap/sdap_async_enum.h ++++ b/src/providers/ldap/sdap_async_enum.h +@@ -27,6 +27,17 @@ + #define _SDAP_ASYNC_ENUM_H_ + + struct tevent_req * ++sdap_dom_enum_ex_send(TALLOC_CTX *memctx, ++ struct tevent_context *ev, ++ struct sdap_id_ctx *ctx, ++ struct sdap_domain *sdom, ++ struct sdap_id_conn_ctx *user_conn, ++ struct sdap_id_conn_ctx *group_conn, ++ struct sdap_id_conn_ctx *svc_conn); ++ ++errno_t sdap_dom_enum_ex_recv(struct tevent_req *req); ++ ++struct tevent_req * + sdap_dom_enum_send(TALLOC_CTX *memctx, + struct tevent_context *ev, + struct sdap_id_ctx *ctx, +-- +1.8.4.2 + diff --git a/SOURCES/0068-AD-Enumerate-users-from-GC-other-entities-from-LDAP.patch b/SOURCES/0068-AD-Enumerate-users-from-GC-other-entities-from-LDAP.patch new file mode 100644 index 0000000..b8b61b9 --- /dev/null +++ b/SOURCES/0068-AD-Enumerate-users-from-GC-other-entities-from-LDAP.patch @@ -0,0 +1,57 @@ +From 1a077f0af935497b972a763a7027924a65476b01 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 28 Jan 2014 13:59:44 +0100 +Subject: [PATCH 68/71] AD: Enumerate users from GC, other entities from LDAP + +--- + src/providers/ad/ad_id.c | 20 +++++++++++++++++--- + 1 file changed, 17 insertions(+), 3 deletions(-) + +diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c +index 99383c13bdadfe9eb2af9f9323ca19a9759d4620..a47aa4f75ab348b0f4597fea264d770b5abe3184 100644 +--- a/src/providers/ad/ad_id.c ++++ b/src/providers/ad/ad_id.c +@@ -526,6 +526,7 @@ ad_enumeration_master_done(struct tevent_req *subreq) + char *flat_name; + char *master_sid; + char *forest; ++ struct sdap_id_conn_ctx *user_conn; + + ret = ad_master_domain_recv(subreq, state, + &flat_name, &master_sid, &forest); +@@ -544,8 +545,21 @@ ad_enumeration_master_done(struct tevent_req *subreq) + return; + } + +- subreq = sdap_dom_enum_send(state, state->ev, state->id_ctx->sdap_id_ctx, +- state->sdom, state->id_ctx->ldap_ctx); ++ if (dp_opt_get_bool(state->id_ctx->ad_options->basic, AD_ENABLE_GC)) { ++ user_conn = state->id_ctx->gc_ctx; ++ } else { ++ user_conn = state->id_ctx->ldap_ctx; ++ } ++ ++ /* Groups are searched for in LDAP, users in GC. Services (if present, ++ * which is unlikely in AD) from LDAP as well ++ */ ++ subreq = sdap_dom_enum_ex_send(state, state->ev, ++ state->id_ctx->sdap_id_ctx, ++ state->sdom, ++ user_conn, /* Users */ ++ state->id_ctx->ldap_ctx, /* Groups */ ++ state->id_ctx->ldap_ctx); /* Services */ + if (subreq == NULL) { + /* The ptask API will reschedule the enumeration on its own on + * failure */ +@@ -566,7 +580,7 @@ ad_enumeration_done(struct tevent_req *subreq) + struct ad_enumeration_state *state = tevent_req_data(req, + struct ad_enumeration_state); + +- ret = sdap_dom_enum_recv(subreq); ++ ret = sdap_dom_enum_ex_recv(subreq); + talloc_zfree(subreq); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, +-- +1.8.4.2 + diff --git a/SOURCES/0069-LDAP-Don-t-clobber-original_member-during-enumeratio.patch b/SOURCES/0069-LDAP-Don-t-clobber-original_member-during-enumeratio.patch new file mode 100644 index 0000000..7523a4a --- /dev/null +++ b/SOURCES/0069-LDAP-Don-t-clobber-original_member-during-enumeratio.patch @@ -0,0 +1,79 @@ +From 37722379349e257e2e77583e515ceafa3eee804c Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 21 Jan 2014 23:40:17 +0100 +Subject: [PATCH 69/71] LDAP: Don't clobber original_member during enumeration + +--- + src/providers/ldap/sdap_async_groups.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c +index 9eece9a6e4baaf302a28b57a63dae45a0741136c..4ed7d4ab9c0c932da49b244f061329a334719159 100644 +--- a/src/providers/ldap/sdap_async_groups.c ++++ b/src/providers/ldap/sdap_async_groups.c +@@ -807,6 +807,7 @@ static int sdap_save_groups(TALLOC_CTX *memctx, + int num_groups, + bool populate_members, + hash_table_t *ghosts, ++ bool save_orig_member, + char **_usn_value) + { + TALLOC_CTX *tmpctx; +@@ -864,9 +865,9 @@ static int sdap_save_groups(TALLOC_CTX *memctx, + usn_value = NULL; + + /* if 2 pass savemembers = false */ +- ret = sdap_save_group(tmpctx, sysdb, +- opts, dom, groups[i], +- populate_members, has_nesting, ++ ret = sdap_save_group(tmpctx, sysdb, opts, dom, groups[i], ++ populate_members, ++ has_nesting && save_orig_member, + ghosts, &usn_value, now); + + /* Do not fail completely on errors. +@@ -1835,7 +1836,7 @@ static void sdap_get_groups_process(struct tevent_req *subreq) + "to allow unrolling of nested groups.\n")); + ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts, + state->groups, state->count, false, +- NULL, NULL); ++ NULL, true, NULL); + if (ret) { + DEBUG(2, ("Failed to store groups.\n")); + tevent_req_error(req, ret); +@@ -1887,10 +1888,14 @@ static void sdap_get_groups_done(struct tevent_req *subreq) + + /* If ignore_group_members is set for the domain, don't update + * group memberships in the cache. ++ * ++ * If enumeration is on, don't overwrite orig_members as they've been ++ * saved earlier. + */ + ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts, + state->groups, state->count, + !state->dom->ignore_group_members, NULL, ++ !state->enumeration, + &state->higher_usn); + if (ret) { + DEBUG(2, ("Failed to store groups.\n")); +@@ -2014,7 +2019,7 @@ static void sdap_ad_match_rule_members_process(struct tevent_req *subreq) + /* Now save the group, users and ghosts to the cache */ + ret = sdap_save_groups(tmp_ctx, state->sysdb, state->dom, + state->opts, state->groups, 1, +- false, ghosts, NULL); ++ false, ghosts, true, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Could not save group to the cache: [%s]\n", +@@ -2090,7 +2095,7 @@ static void sdap_nested_done(struct tevent_req *subreq) + } + + ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts, +- groups, group_count, false, ghosts, ++ groups, group_count, false, ghosts, true, + &state->higher_usn); + if (ret != EOK) { + goto fail; +-- +1.8.4.2 + diff --git a/SOURCES/0070-DB-Add-sss_ldb_el_to_string_list.patch b/SOURCES/0070-DB-Add-sss_ldb_el_to_string_list.patch new file mode 100644 index 0000000..8b9b419 --- /dev/null +++ b/SOURCES/0070-DB-Add-sss_ldb_el_to_string_list.patch @@ -0,0 +1,160 @@ +From 329165182d0decee35f3837c1d2ad899f99e9950 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 28 Jan 2014 14:51:58 +0100 +Subject: [PATCH 70/71] DB: Add sss_ldb_el_to_string_list + +--- + src/db/sysdb.c | 41 ++++++++++++++++++++++++++--------------- + src/db/sysdb.h | 2 ++ + src/tests/sysdb-tests.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 77 insertions(+), 15 deletions(-) + +diff --git a/src/db/sysdb.c b/src/db/sysdb.c +index 0e07ed60858298a1ac85d06146ccb98c5899a705..592cadc1a322ee8504c407a508e34e7eb9465a15 100644 +--- a/src/db/sysdb.c ++++ b/src/db/sysdb.c +@@ -466,35 +466,46 @@ errno_t sysdb_attrs_get_bool(struct sysdb_attrs *attrs, const char *name, + return EOK; + } + +-int sysdb_attrs_get_string_array(struct sysdb_attrs *attrs, const char *name, +- TALLOC_CTX *mem_ctx, const char ***string) ++const char **sss_ldb_el_to_string_list(TALLOC_CTX *mem_ctx, ++ struct ldb_message_element *el) + { +- struct ldb_message_element *el; +- int ret; + unsigned int u; + const char **a; + +- ret = sysdb_attrs_get_el_ext(attrs, name, false, &el); +- if (ret) { +- return ret; +- } +- +- a = talloc_array(mem_ctx, const char *, el->num_values + 1); ++ a = talloc_zero_array(mem_ctx, const char *, el->num_values + 1); + if (a == NULL) { +- return ENOMEM; ++ return NULL; + } + +- memset(a, 0, sizeof(const char *) * (el->num_values + 1)); +- +- for(u = 0; u < el->num_values; u++) { ++ for (u = 0; u < el->num_values; u++) { + a[u] = talloc_strndup(a, (const char *)el->values[u].data, + el->values[u].length); + if (a[u] == NULL) { + talloc_free(a); +- return ENOMEM; ++ return NULL; + } + } + ++ return a; ++} ++ ++int sysdb_attrs_get_string_array(struct sysdb_attrs *attrs, const char *name, ++ TALLOC_CTX *mem_ctx, const char ***string) ++{ ++ struct ldb_message_element *el; ++ int ret; ++ const char **a; ++ ++ ret = sysdb_attrs_get_el_ext(attrs, name, false, &el); ++ if (ret) { ++ return ret; ++ } ++ ++ a = sss_ldb_el_to_string_list(mem_ctx, el); ++ if (a == NULL) { ++ return ENOMEM; ++ } ++ + *string = a; + return EOK; + } +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index 9677294b22e47f5169d7631673beec2dbc6117ad..5bd2c50ebff1ca1f4bb11d12e40512d8f460acbb 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -288,6 +288,8 @@ int sysdb_attrs_steal_string(struct sysdb_attrs *attrs, + const char *name, char *str); + int sysdb_attrs_get_string(struct sysdb_attrs *attrs, const char *name, + const char **string); ++const char **sss_ldb_el_to_string_list(TALLOC_CTX *mem_ctx, ++ struct ldb_message_element *el); + int sysdb_attrs_get_string_array(struct sysdb_attrs *attrs, const char *name, + TALLOC_CTX *mem_ctx, const char ***string); + errno_t sysdb_attrs_get_bool(struct sysdb_attrs *attrs, const char *name, +diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c +index 63ffac82e15849e5f6534462ce7c58b183412acc..69b09c7d4580595854330062e0f549eab1f8cf22 100644 +--- a/src/tests/sysdb-tests.c ++++ b/src/tests/sysdb-tests.c +@@ -4449,6 +4449,52 @@ START_TEST(test_sysdb_attrs_add_lc_name_alias) + } + END_TEST + ++START_TEST(test_sysdb_attrs_get_string_array) ++{ ++ int ret; ++ struct sysdb_attrs *attrs; ++ const char **list; ++ const char *attrname = "test_attr"; ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_message_element *el = NULL; ++ ++ tmp_ctx = talloc_new(NULL); ++ fail_unless(tmp_ctx != NULL, "talloc_new failed"); ++ ++ attrs = sysdb_new_attrs(NULL); ++ fail_unless(attrs != NULL, "sysdb_new_attrs failed"); ++ ++ ret = sysdb_attrs_add_string(attrs, attrname, "val1"); ++ fail_unless(ret == EOK, "sysdb_attrs_add_string failed"); ++ ret = sysdb_attrs_add_string(attrs, attrname, "val2"); ++ fail_unless(ret == EOK, "sysdb_attrs_add_string failed"); ++ ++ ret = sysdb_attrs_get_el_ext(attrs, attrname, false, &el); ++ fail_unless(ret == EOK, "sysdb_attrs_get_el_ext failed"); ++ ++ list = sss_ldb_el_to_string_list(tmp_ctx, el); ++ fail_if(list == NULL, ("sss_ldb_el_to_string_list failed\n")); ++ ++ ck_assert_str_eq(list[0], "val1"); ++ ck_assert_str_eq(list[1], "val2"); ++ fail_unless(list[2] == NULL, "Expected terminated list"); ++ ++ talloc_free(list); ++ ++ ret = sysdb_attrs_get_string_array(attrs, attrname, tmp_ctx, &list); ++ fail_unless(ret == EOK, "sysdb_attrs_get_string_array failed"); ++ ++ /* This test relies on values keeping the same order. It is the case ++ * with LDB, but if we ever switch from LDB, we need to amend the test ++ */ ++ ck_assert_str_eq(list[0], "val1"); ++ ck_assert_str_eq(list[1], "val2"); ++ fail_unless(list[2] == NULL, "Expected terminated list"); ++ ++ talloc_free(tmp_ctx); ++} ++END_TEST ++ + START_TEST(test_sysdb_has_enumerated) + { + errno_t ret; +@@ -5217,6 +5263,9 @@ Suite *create_sysdb_suite(void) + + tcase_add_test(tc_sysdb, test_sysdb_attrs_add_lc_name_alias); + ++/* ===== UTIL TESTS ===== */ ++ tcase_add_test(tc_sysdb, test_sysdb_attrs_get_string_array); ++ + /* Add all test cases to the test suite */ + suite_add_tcase(s, tc_sysdb); + +-- +1.8.4.2 + diff --git a/SOURCES/0071-AD-Establish-cross-domain-memberships-after-enumerat.patch b/SOURCES/0071-AD-Establish-cross-domain-memberships-after-enumerat.patch new file mode 100644 index 0000000..fc32870 --- /dev/null +++ b/SOURCES/0071-AD-Establish-cross-domain-memberships-after-enumerat.patch @@ -0,0 +1,508 @@ +From 8c714cbf1d0ce2cbddc4222ade51e1f93f36dbe8 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 22 Jan 2014 15:21:24 +0100 +Subject: [PATCH 71/71] AD: Establish cross-domain memberships after + enumeration finishes + +Because domain enumeration currently works for each domain separately, +the code has to establish cross-domain memberships after all domains are +enumerated. The code works as follows: + + 1) check if any *sub*domains were enumerated. If not, do nothing + 2) if any of the groups saved had more original members than + sysdb members, check if members of these groups can be linked now + that all users and groups are saved using the orig_member + attribute of the group matched against originalDN member of the + user. + +Related: +https://fedorahosted.org/sssd/ticket/2142 +--- + src/providers/ad/ad_id.c | 390 +++++++++++++++++++++++++++++++++++++-- + src/providers/ad/ad_subdomains.c | 11 -- + 2 files changed, 379 insertions(+), 22 deletions(-) + +diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c +index a47aa4f75ab348b0f4597fea264d770b5abe3184..e3302c15774ab1c24b16cefc274313e447b31e5c 100644 +--- a/src/providers/ad/ad_id.c ++++ b/src/providers/ad/ad_id.c +@@ -420,10 +420,13 @@ struct ad_enumeration_state { + struct tevent_context *ev; + + struct sdap_domain *sdom; ++ struct sdap_domain *sditer; + }; + + static void ad_enumeration_conn_done(struct tevent_req *subreq); + static void ad_enumeration_master_done(struct tevent_req *subreq); ++static errno_t ad_enum_sdom(struct tevent_req *req, struct sdap_domain *sd, ++ struct ad_id_ctx *id_ctx); + static void ad_enumeration_done(struct tevent_req *subreq); + + struct tevent_req * +@@ -452,6 +455,7 @@ ad_enumeration_send(TALLOC_CTX *mem_ctx, + state->ectx = ectx; + state->ev = ev; + state->sdom = ectx->sdom; ++ state->sditer = state->sdom; + state->id_ctx = talloc_get_type(ectx->pvt, struct ad_id_ctx); + + state->sdap_op = sdap_id_op_create(state, +@@ -526,7 +530,6 @@ ad_enumeration_master_done(struct tevent_req *subreq) + char *flat_name; + char *master_sid; + char *forest; +- struct sdap_id_conn_ctx *user_conn; + + ret = ad_master_domain_recv(subreq, state, + &flat_name, &master_sid, &forest); +@@ -545,32 +548,57 @@ ad_enumeration_master_done(struct tevent_req *subreq) + return; + } + +- if (dp_opt_get_bool(state->id_ctx->ad_options->basic, AD_ENABLE_GC)) { +- user_conn = state->id_ctx->gc_ctx; ++ ret = ad_enum_sdom(req, state->sdom, state->id_ctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("Could not enumerate domain %s\n", state->sdom->dom->name)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ /* Execution will resume in ad_enumeration_done */ ++} ++ ++static errno_t ++ad_enum_sdom(struct tevent_req *req, ++ struct sdap_domain *sd, ++ struct ad_id_ctx *id_ctx) ++{ ++ struct sdap_id_conn_ctx *user_conn; ++ struct tevent_req *subreq; ++ struct ad_enumeration_state *state = tevent_req_data(req, ++ struct ad_enumeration_state); ++ ++ if (dp_opt_get_bool(id_ctx->ad_options->basic, AD_ENABLE_GC)) { ++ user_conn = id_ctx->gc_ctx; + } else { +- user_conn = state->id_ctx->ldap_ctx; ++ user_conn = id_ctx->ldap_ctx; + } + + /* Groups are searched for in LDAP, users in GC. Services (if present, + * which is unlikely in AD) from LDAP as well + */ + subreq = sdap_dom_enum_ex_send(state, state->ev, +- state->id_ctx->sdap_id_ctx, +- state->sdom, +- user_conn, /* Users */ +- state->id_ctx->ldap_ctx, /* Groups */ +- state->id_ctx->ldap_ctx); /* Services */ ++ id_ctx->sdap_id_ctx, ++ sd, ++ user_conn, /* Users */ ++ id_ctx->ldap_ctx, /* Groups */ ++ id_ctx->ldap_ctx); /* Services */ + if (subreq == NULL) { + /* The ptask API will reschedule the enumeration on its own on + * failure */ + DEBUG(SSSDBG_OP_FAILURE, + ("Failed to schedule enumeration, retrying later!\n")); +- tevent_req_error(req, ENOMEM); +- return; ++ return ENOMEM; + } + tevent_req_set_callback(subreq, ad_enumeration_done, req); ++ ++ return EOK; + } + ++static errno_t ad_enum_cross_dom_members(struct sdap_options *opts, ++ struct sss_domain_info *dom); ++ + static void + ad_enumeration_done(struct tevent_req *subreq) + { +@@ -579,6 +607,7 @@ ad_enumeration_done(struct tevent_req *subreq) + struct tevent_req); + struct ad_enumeration_state *state = tevent_req_data(req, + struct ad_enumeration_state); ++ struct ad_id_ctx *subdom_id_ctx; + + ret = sdap_dom_enum_ex_recv(subreq); + talloc_zfree(subreq); +@@ -589,9 +618,348 @@ ad_enumeration_done(struct tevent_req *subreq) + return; + } + ++ state->sditer = state->sditer->next; ++ if (state->sditer != NULL) { ++ subdom_id_ctx = talloc_get_type(state->sdom->pvt, struct ad_id_ctx); ++ if (subdom_id_ctx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot retrieve subdomain ad_id_ctx!\n")); ++ tevent_req_error(req, EFAULT); ++ return; ++ } ++ ++ ret = ad_enum_sdom(req, state->sditer, state->sditer->pvt); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Could not enumerate domain %s\n", ++ state->sditer->dom->name)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ /* Execution will resume in ad_enumeration_done */ ++ return; ++ } ++ ++ /* No more subdomains to enumerate. Check if we need to fixup ++ * cross-domain membership ++ */ ++ if (state->sditer != state->sdom) { ++ /* We did enumerate at least one subdomain. Walk the subdomains ++ * and fixup members for each of them ++ */ ++ for (state->sditer = state->sdom; ++ state->sditer; ++ state->sditer = state->sditer->next) { ++ ret = ad_enum_cross_dom_members(state->id_ctx->ad_options->id, ++ state->sditer->dom); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Could not check cross-domain " ++ "memberships for %s, group memberships might be " ++ "incomplete!\n", state->sdom->dom->name)); ++ continue; ++ } ++ } ++ } ++ + tevent_req_done(req); + } + ++static errno_t ad_group_extra_members(TALLOC_CTX *mem_ctx, ++ const struct ldb_message *group, ++ struct sss_domain_info *dom, ++ char ***_group_only); ++static errno_t ad_group_add_member(struct sdap_options *opts, ++ struct sss_domain_info *group_domain, ++ struct ldb_dn *group_dn, ++ const char *member); ++ ++static errno_t ++ad_enum_cross_dom_members(struct sdap_options *opts, ++ struct sss_domain_info *dom) ++{ ++ errno_t ret; ++ errno_t sret; ++ char *filter; ++ TALLOC_CTX *tmp_ctx; ++ const char *attrs[] = { ++ SYSDB_NAME, ++ SYSDB_MEMBER, ++ SYSDB_ORIG_MEMBER, ++ NULL ++ }; ++ size_t count, i, mi; ++ struct ldb_message **msgs; ++ bool in_transaction = false; ++ char **group_only; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) return ENOMEM; ++ ++ ret = sysdb_transaction_start(dom->sysdb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n")); ++ goto done; ++ } ++ in_transaction = true; ++ ++ filter = talloc_asprintf(tmp_ctx, "(%s=*)", SYSDB_NAME); ++ if (filter == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_search_groups(tmp_ctx, dom->sysdb, dom, ++ filter, attrs, &count, &msgs); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ for (i = 0; i < count; i++) { ++ ret = ad_group_extra_members(tmp_ctx, msgs[i], dom, &group_only); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Failed to check extra members\n")); ++ } else if (group_only == NULL) { ++ DEBUG(SSSDBG_TRACE_INTERNAL, ("No extra members\n")); ++ continue; ++ } ++ ++ /* Group has extra members */ ++ for (mi = 0; group_only[mi]; mi++) { ++ ret = ad_group_add_member(opts, dom, msgs[i]->dn, group_only[mi]); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to add [%s]: %s\n", ++ group_only[mi], strerror(ret))); ++ continue; ++ } ++ } ++ ++ talloc_zfree(group_only); ++ } ++ ++ ret = sysdb_transaction_commit(dom->sysdb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to commit transaction\n")); ++ goto done; ++ } ++ in_transaction = false; ++ ++ ret = EOK; ++done: ++ if (in_transaction) { ++ sret = sysdb_transaction_cancel(dom->sysdb); ++ if (sret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("Could not cancel transaction\n")); ++ } ++ } ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++static errno_t ++ad_group_stored_orig_members(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom, ++ struct ldb_dn *dn, char ***_odn_list); ++ ++static errno_t ++ad_group_extra_members(TALLOC_CTX *mem_ctx, const struct ldb_message *group, ++ struct sss_domain_info *dom, char ***_group_only) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_message_element *m, *om; ++ const char *name; ++ errno_t ret; ++ char **sysdb_odn_list; ++ const char **group_odn_list; ++ char **group_only = NULL; ++ ++ if (_group_only == NULL) return EINVAL; ++ *_group_only = NULL; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) return ENOMEM; ++ ++ om = ldb_msg_find_element(group, SYSDB_ORIG_MEMBER); ++ m = ldb_msg_find_element(group, SYSDB_MEMBER); ++ name = ldb_msg_find_attr_as_string(group, SYSDB_NAME, NULL); ++ if (name == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ("A group with no name!\n")); ++ ret = EFAULT; ++ goto done; ++ } ++ ++ if (om == NULL || om->num_values == 0) { ++ DEBUG(SSSDBG_TRACE_FUNC, ("Group %s has no original members\n", name)); ++ ret = EOK; ++ goto done; ++ } ++ ++ if (m == NULL || (m->num_values < om->num_values)) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ ("Group %s has %d members but %d original members\n", ++ name, m ? m->num_values : 0, om->num_values)); ++ ++ /* Get the list of originalDN attributes that are already ++ * linked to the group ++ */ ++ ret = ad_group_stored_orig_members(tmp_ctx, dom, group->dn, ++ &sysdb_odn_list); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("Could not retrieve list of original members for %s\n", ++ name)); ++ goto done; ++ } ++ ++ /* Get the list of original DN attributes the group had in AD */ ++ group_odn_list = sss_ldb_el_to_string_list(tmp_ctx, om); ++ if (group_odn_list == NULL) { ++ ret = EFAULT; ++ goto done; ++ } ++ ++ /* Compare the two lists */ ++ ret = diff_string_lists(tmp_ctx, discard_const(group_odn_list), ++ sysdb_odn_list, &group_only, NULL, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("Could not compare lists of members for %s\n", name)); ++ goto done; ++ } ++ } ++ ++ ret = EOK; ++ *_group_only = talloc_steal(mem_ctx, group_only); ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++static errno_t ++ad_group_stored_orig_members(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom, ++ struct ldb_dn *dn, char ***_odn_list) ++{ ++ errno_t ret; ++ TALLOC_CTX *tmp_ctx; ++ size_t m_count, i; ++ struct ldb_message **members; ++ const char *attrs[] = { ++ SYSDB_NAME, ++ SYSDB_ORIG_DN, ++ NULL ++ }; ++ char **odn_list; ++ const char *odn; ++ size_t oi; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) return ENOMEM; ++ ++ /* Get all entries member element points to */ ++ ret = sysdb_asq_search(tmp_ctx, dom->sysdb, dn, NULL, SYSDB_MEMBER, ++ attrs, &m_count, &members); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ odn_list = talloc_zero_array(tmp_ctx, char *, m_count + 1); ++ if (odn_list == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ /* Get a list of their original DNs */ ++ oi = 0; ++ for (i = 0; i < m_count; i++) { ++ odn = ldb_msg_find_attr_as_string(members[i], SYSDB_ORIG_DN, NULL); ++ if (odn == NULL) { ++ continue; ++ } ++ ++ odn_list[oi] = talloc_strdup(odn_list, odn); ++ if (odn_list[oi] == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ oi++; ++ DEBUG(SSSDBG_TRACE_INTERNAL, ("Member %s already in sysdb\n", odn)); ++ } ++ ++ ret = EOK; ++ *_odn_list = talloc_steal(mem_ctx, odn_list); ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++static errno_t ++ad_group_add_member(struct sdap_options *opts, ++ struct sss_domain_info *group_domain, ++ struct ldb_dn *group_dn, ++ const char *member) ++{ ++ struct sdap_domain *sd; ++ struct ldb_dn *base_dn; ++ TALLOC_CTX *tmp_ctx; ++ errno_t ret; ++ const char *mem_filter; ++ size_t msgs_count; ++ struct ldb_message **msgs; ++ ++ /* This member would be from a different domain */ ++ sd = sdap_domain_get_by_dn(opts, member); ++ if (sd == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("No matching domain for %s\n", member)); ++ return ENOENT; ++ } ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) return ENOMEM; ++ ++ mem_filter = talloc_asprintf(tmp_ctx, "(%s=%s)", ++ SYSDB_ORIG_DN, member); ++ if (mem_filter == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ base_dn = sysdb_domain_dn(sd->dom->sysdb, tmp_ctx, sd->dom); ++ if (base_dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_search_entry(tmp_ctx, sd->dom->sysdb, base_dn, ++ LDB_SCOPE_SUBTREE, mem_filter, NULL, ++ &msgs_count, &msgs); ++ if (ret == ENOENT) { ++ DEBUG(SSSDBG_TRACE_FUNC, ("No member [%s] in sysdb\n", member)); ++ ret = EOK; ++ goto done; ++ } else if (ret != EOK) { ++ goto done; ++ } ++ DEBUG(SSSDBG_TRACE_INTERNAL, ("[%s] found in sysdb\n", member)); ++ ++ if (msgs_count != 1) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ ("Search by orig DN returned %zd results!\n", msgs_count)); ++ ret = EFAULT; ++ goto done; ++ } ++ ++ ret = sysdb_mod_group_member(group_domain->sysdb, msgs[0]->dn, ++ group_dn, SYSDB_MOD_ADD); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Could not add [%s] as a member of [%s]\n", ++ ldb_dn_get_linearized(msgs[0]->dn), ++ ldb_dn_get_linearized(group_dn))); ++ goto done; ++ } ++ ++ ret = EOK; ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ + errno_t + ad_enumeration_recv(struct tevent_req *req) + { +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index e7871cc32407893948fe1b2803258d68c70889c1..0d9652b5c615add47958cfdc61eba862a332ae4d 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -177,17 +177,6 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, + return EFAULT; + } + +- ret = sdap_id_setup_tasks(be_ctx, +- ad_id_ctx->sdap_id_ctx, +- sdom, +- ldap_enumeration_send, +- ldap_enumeration_recv, +- ad_id_ctx->sdap_id_ctx); +- if (ret != EOK) { +- talloc_free(ad_options); +- return ret; +- } +- + /* Set up the ID mapping object */ + ad_id_ctx->sdap_id_ctx->opts->idmap_ctx = + id_ctx->sdap_id_ctx->opts->idmap_ctx; +-- +1.8.4.2 + diff --git a/SOURCES/0072-AD-SRV-use-right-domain-name-for-CLDAP-ping.patch b/SOURCES/0072-AD-SRV-use-right-domain-name-for-CLDAP-ping.patch new file mode 100644 index 0000000..b3f1d9c --- /dev/null +++ b/SOURCES/0072-AD-SRV-use-right-domain-name-for-CLDAP-ping.patch @@ -0,0 +1,28 @@ +From 9118f124fad5fe15c5beb910db08794d9b3d2685 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 24 Jan 2014 16:52:22 +0100 +Subject: [PATCH 72/73] AD SRV: use right domain name for CLDAP ping + +Currently always the name of the configured domain was passed to the +CLDAP request. This will fail if the CLDAP request is send to a DC form +a different domain. +--- + src/providers/ad/ad_srv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c +index a238c192e495c3ff6330123d8e53d7d480e88e1b..99502e431e7b8b053e6ec58780abfd10859937be 100644 +--- a/src/providers/ad/ad_srv.c ++++ b/src/providers/ad/ad_srv.c +@@ -723,7 +723,7 @@ static void ad_srv_plugin_dcs_done(struct tevent_req *subreq) + state->ctx->be_res, + state->ctx->host_dbs, + state->ctx->opts, +- state->ctx->ad_domain, ++ state->discovery_domain, + dcs, num_dcs); + if (subreq == NULL) { + ret = ENOMEM; +-- +1.8.4.2 + diff --git a/SOURCES/0073-MAN-clarify-which-shell-option-takes-precedence.patch b/SOURCES/0073-MAN-clarify-which-shell-option-takes-precedence.patch new file mode 100644 index 0000000..e6fd18e --- /dev/null +++ b/SOURCES/0073-MAN-clarify-which-shell-option-takes-precedence.patch @@ -0,0 +1,43 @@ +From 045b0cbf342d50ce07fc768fbce63b9bd0309215 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 29 Jan 2014 13:24:15 +0100 +Subject: [PATCH 73/73] MAN: clarify which shell option takes precedence + +--- + src/man/sssd.conf.5.xml | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index b879bdf63c40e80efa21644bd9ba9d2d3477af06..84770f6b28876278a0ddd6d8a8a8f9a8e0d3146f 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -503,8 +503,9 @@ fallback_homedir = /home/%u + + + Override the login shell for all users. This +- option can be specified globally in the [nss] +- section or per-domain. ++ option supersedes any other shell options if ++ it takes effect and can be set either in the ++ [nss] section or per-domain. + + + Default: not set (SSSD will use the value +@@ -568,10 +569,10 @@ fallback_homedir = /home/%u + default_shell + + +- The default shell to use if the provider does not +- return one during lookup. This option supersedes +- any other shell options if it takes effect and can +- be set either in the [nss] section or per-domain. ++ The default shell to use if the provider does ++ not return one during lookup. This option can ++ be specified globally in the [nss] section ++ or per-domain. + + + Default: not set (Return NULL if no shell is +-- +1.8.4.2 + diff --git a/SOURCES/0074-LDAP-store-group-if-subdomain-cannot-be-found-by-sid.patch b/SOURCES/0074-LDAP-store-group-if-subdomain-cannot-be-found-by-sid.patch new file mode 100644 index 0000000..1caa79e --- /dev/null +++ b/SOURCES/0074-LDAP-store-group-if-subdomain-cannot-be-found-by-sid.patch @@ -0,0 +1,47 @@ +From 53554c55a75477b0ea719b845ff1660ac1a2ec82 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Fri, 24 Jan 2014 17:03:27 +0100 +Subject: [PATCH 74/75] LDAP: store group if subdomain cannot be found by sid + +Domain needn't contain sid if id_provider is ldap. +With enabled id mapping, group couldn't be stored, because domain +couldn't be found by sid. + +Resolves: +https://fedorahosted.org/sssd/ticket/2172 +--- + src/providers/ldap/sdap_async_groups.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c +index 4ed7d4ab9c0c932da49b244f061329a334719159..ab3691f80aaecca988dcbf0877491a37af3ae49b 100644 +--- a/src/providers/ldap/sdap_async_groups.c ++++ b/src/providers/ldap/sdap_async_groups.c +@@ -452,6 +452,7 @@ static int sdap_save_group(TALLOC_CTX *memctx, + bool posix_group; + bool use_id_mapping; + char *sid_str; ++ struct sss_domain_info *subdomain; + int32_t ad_group_type; + + tmpctx = talloc_new(NULL); +@@ -490,11 +491,12 @@ static int sdap_save_group(TALLOC_CTX *memctx, + /* If this object has a SID available, we will determine the correct + * domain by its SID. */ + if (sid_str != NULL) { +- dom = find_subdomain_by_sid(get_domains_head(dom), sid_str); +- if (dom == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, ("SID %s does not belong to any known " ++ subdomain = find_subdomain_by_sid(get_domains_head(dom), sid_str); ++ if (subdomain) { ++ dom = subdomain; ++ } else { ++ DEBUG(SSSDBG_TRACE_FUNC, ("SID %s does not belong to any known " + "domain\n", sid_str)); +- return ERR_DOMAIN_NOT_FOUND; + } + } + +-- +1.8.4.2 + diff --git a/SOURCES/0075-LDAP-require-attribute-groupType-for-AD-groups.patch b/SOURCES/0075-LDAP-require-attribute-groupType-for-AD-groups.patch new file mode 100644 index 0000000..ea1b78c --- /dev/null +++ b/SOURCES/0075-LDAP-require-attribute-groupType-for-AD-groups.patch @@ -0,0 +1,31 @@ +From 42817081e7afe5b67d4151c5ac87b0a48da31a1b Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Wed, 29 Jan 2014 14:58:53 +0100 +Subject: [PATCH 75/75] LDAP: require attribute groupType for AD groups + +Commit 8280c5213094 introduced filtering local groups for trusted/sub domains, +but attribute groupType was not available with configuration id_provide ldap +and ldap_schema ad. + +Resolves: +https://fedorahosted.org/sssd/ticket/2172 +--- + src/providers/ldap/ldap_opts.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/providers/ldap/ldap_opts.h b/src/providers/ldap/ldap_opts.h +index 9593dfd30a81db60b7358c66975871507340aa4b..d07051c51aef860943ee8bd4953e8f3d0660a656 100644 +--- a/src/providers/ldap/ldap_opts.h ++++ b/src/providers/ldap/ldap_opts.h +@@ -295,7 +295,7 @@ struct sdap_attr_map gen_ad2008r2_group_map[] = { + { "ldap_group_objectsid", "objectSID", SYSDB_SID, NULL }, + { "ldap_group_modify_timestamp", "whenChanged", SYSDB_ORIG_MODSTAMP, NULL }, + { "ldap_group_entry_usn", SDAP_AD_USN, SYSDB_USN, NULL }, +- { "ldap_group_type", NULL, SYSDB_GROUP_TYPE, NULL }, ++ { "ldap_group_type", "groupType", SYSDB_GROUP_TYPE, NULL }, + SDAP_ATTR_MAP_TERMINATOR + }; + +-- +1.8.4.2 + diff --git a/SOURCES/0076-MONITOR-Incorrect-permissions-on-sssd.conf.patch b/SOURCES/0076-MONITOR-Incorrect-permissions-on-sssd.conf.patch new file mode 100644 index 0000000..381c18e --- /dev/null +++ b/SOURCES/0076-MONITOR-Incorrect-permissions-on-sssd.conf.patch @@ -0,0 +1,46 @@ +From 3af4a383964cf391e0277bd8a272156a1805e357 Mon Sep 17 00:00:00 2001 +From: Pavel Reichl +Date: Wed, 5 Feb 2014 17:32:20 +0000 +Subject: [PATCH 76/80] MONITOR: Incorrect permissions on sssd.conf + +Print user friendly warning when permissions on sssd.conf are incorrect and +provide hint. + +Resolves: +https://fedorahosted.org/sssd/ticket/2208 + +Reviewed-by: Stephen Gallagher +(cherry picked from commit b3cc9b98966fa2d90172348c334b3b70c5261ab3) +--- + src/monitor/monitor.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c +index 09f530d2643b45fc31fb4dbe3cb69f2abc5510af..72a8b7c4a376dd9b68349b959cb869b9da059d38 100644 +--- a/src/monitor/monitor.c ++++ b/src/monitor/monitor.c +@@ -84,6 +84,11 @@ + */ + #define KRB5_RCACHE_DIR_DISABLE "__LIBKRB5_DEFAULTS__" + ++/* Warning messages */ ++#define CONF_FILE_PERM_ERROR_MSG "Cannot read config file %s. Please check "\ ++ "if permissions are 0600 and the file is "\ ++ "owned by root.root." ++ + int cmdline_debug_level; + int cmdline_debug_timestamps; + int cmdline_debug_microseconds; +@@ -2798,7 +2803,8 @@ int main(int argc, const char *argv[]) + case EPERM: + case EACCES: + DEBUG(SSSDBG_CRIT_FAILURE, +- ("Insufficient permissions to read configuration file.\n")); ++ (CONF_FILE_PERM_ERROR_MSG, config_file)); ++ sss_log(SSS_LOG_ALERT, CONF_FILE_PERM_ERROR_MSG, config_file); + break; + default: + DEBUG(SSSDBG_CRIT_FAILURE, +-- +1.8.5.3 + diff --git a/SOURCES/0077-Revert-NSS-add-support-for-subdomain_homedir.patch b/SOURCES/0077-Revert-NSS-add-support-for-subdomain_homedir.patch new file mode 100644 index 0000000..3f14be6 --- /dev/null +++ b/SOURCES/0077-Revert-NSS-add-support-for-subdomain_homedir.patch @@ -0,0 +1,34 @@ +From e7987aced2a2052d3cbff185f6e53708b552995b Mon Sep 17 00:00:00 2001 +From: Pavel Reichl +Date: Tue, 21 Jan 2014 15:06:37 +0000 +Subject: [PATCH 77/80] Revert "NSS: add support for subdomain_homedir" + +This reverts commit 1dc7694a1cbc62b0d7e23cc1369579e5ce0071e8. + +Reviewed-by: Jakub Hrozek +--- + src/responder/nss/nsssrv_cmd.c | 8 -------- + 1 file changed, 8 deletions(-) + +diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c +index 9ac3680de4d6ff12fe0c77a3963f84934e385276..c59078b545842561a7e5f62e9a99da6057b23660 100644 +--- a/src/responder/nss/nsssrv_cmd.c ++++ b/src/responder/nss/nsssrv_cmd.c +@@ -201,14 +201,6 @@ static const char *get_homedir_override(TALLOC_CTX *mem_ctx, + name, uid, homedir, dom->name, NULL); + } + +- /* Override home directory location for subdomains. +- * This option can be overriden by override_homedir. +- */ +- if (IS_SUBDOMAIN(dom) && dom->subdomain_homedir) { +- return expand_homedir_template(mem_ctx, dom->subdomain_homedir, +- name, uid, homedir, dom->name, NULL); +- } +- + if (!homedir || *homedir == '\0') { + /* In the case of a NULL or empty homedir, check to see if + * we have a fallback homedir to use. +-- +1.8.5.3 + diff --git a/SOURCES/0078-AD-support-for-subdomain_homedir.patch b/SOURCES/0078-AD-support-for-subdomain_homedir.patch new file mode 100644 index 0000000..ac57314 --- /dev/null +++ b/SOURCES/0078-AD-support-for-subdomain_homedir.patch @@ -0,0 +1,233 @@ +From 0b813ab764fd0b255e342765b79533e1869cd06e Mon Sep 17 00:00:00 2001 +From: Pavel Reichl +Date: Wed, 22 Jan 2014 16:47:22 +0000 +Subject: [PATCH 78/80] AD: support for subdomain_homedir + +Homedir is defaultly set accordingly to subdomain_homedir for users from AD. + +Resolves: +https://fedorahosted.org/sssd/ticket/2169 + +Reviewed-by: Jakub Hrozek +--- + src/providers/ipa/ipa_subdomains_id.c | 190 ++++++++++++++++++++++++++++++++++ + 1 file changed, 190 insertions(+) + +diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c +index c29a2a3047af105966b636422105abd15e8a3992..fb1ad896885866dd9c34f9db960e09d92763f86d 100644 +--- a/src/providers/ipa/ipa_subdomains_id.c ++++ b/src/providers/ipa/ipa_subdomains_id.c +@@ -25,6 +25,7 @@ + #include + + #include "util/util.h" ++#include "util/sss_nss.h" + #include "util/strtonum.h" + #include "db/sysdb.h" + #include "providers/ldap/ldap_common.h" +@@ -350,6 +351,185 @@ ipa_get_ad_id_ctx(struct ipa_id_ctx *ipa_ctx, + return (iter) ? iter->ad_id_ctx : NULL; + } + ++static errno_t ++get_subdomain_homedir_of_user(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom, ++ const char *fqname, uint32_t uid, ++ const char **_homedir) ++{ ++ errno_t ret; ++ char *name; ++ const char *homedir; ++ TALLOC_CTX *tmp_ctx; ++ ++ tmp_ctx = talloc_new(mem_ctx); ++ if (tmp_ctx == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sss_parse_name(tmp_ctx, dom->names, fqname, NULL, &name); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ homedir = expand_homedir_template(tmp_ctx, dom->subdomain_homedir, name, ++ uid, NULL, dom->name, dom->flat_name); ++ ++ if (homedir == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ("expand_homedir_template failed\n")); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ if (_homedir == NULL) { ++ ret = EINVAL; ++ goto done; ++ } ++ *_homedir = talloc_steal(mem_ctx, homedir); ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++static errno_t ++store_homedir_of_user(struct sss_domain_info *domain, ++ const char *fqname, const char *homedir) ++{ ++ errno_t ret; ++ errno_t sret; ++ TALLOC_CTX *tmp_ctx; ++ bool in_transaction = false; ++ struct sysdb_attrs *attrs; ++ struct sysdb_ctx *sysdb = domain->sysdb; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ attrs = sysdb_new_attrs(tmp_ctx); ++ if (attrs == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_attrs_add_string(attrs, SYSDB_HOMEDIR, homedir); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Error setting homedir: [%s]\n", ++ strerror(ret))); ++ goto done; ++ } ++ ++ ret = sysdb_transaction_start(sysdb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n")); ++ goto done; ++ } ++ ++ in_transaction = true; ++ ++ ret = sysdb_set_user_attr(sysdb, domain, fqname, attrs, SYSDB_MOD_REP); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ ("Failed to update homedir information!\n")); ++ goto done; ++ } ++ ++ ret = sysdb_transaction_commit(sysdb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ ("Cannot commit sysdb transaction [%d]: %s.\n", ++ ret, strerror(ret))); ++ 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(tmp_ctx); ++ return ret; ++} ++ ++static errno_t ++apply_subdomain_homedir(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom, ++ int filter_type, const char *filter_value) ++{ ++ errno_t ret; ++ uint32_t uid; ++ const char *fqname; ++ const char *homedir = NULL; ++ struct ldb_result *res; ++ ++ if (filter_type == BE_FILTER_NAME) { ++ ret = sysdb_getpwnam(mem_ctx, dom->sysdb, dom, filter_value, &res); ++ } else if (filter_type == BE_FILTER_IDNUM) { ++ errno = 0; ++ uid = strtouint32(filter_value, NULL, 10); ++ if (errno != 0) { ++ ret = errno; ++ goto done; ++ } ++ ret = sysdb_getpwuid(mem_ctx, dom->sysdb, dom, uid, &res); ++ } else { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("Unsupported filter type: [%d].\n", filter_type)); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("Failed to make request to our cache: [%d]: [%s]\n", ++ ret, sss_strerror(ret))); ++ goto done; ++ } ++ ++ if (res->count == 0) { ++ ret = ENOENT; ++ goto done; ++ } ++ ++ /* ++ * Homedir is always overriden by subdomain_homedir even if it was ++ * explicitly set by user. ++ */ ++ fqname = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL); ++ uid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_UIDNUM, 0); ++ if (uid == 0) { ++ DEBUG(SSSDBG_OP_FAILURE, ("UID for user [%s] is not known.\n", ++ filter_value)); ++ ret = ENOENT; ++ goto done; ++ } ++ ++ ret = get_subdomain_homedir_of_user(mem_ctx, dom, fqname, uid, &homedir); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("get_subdomain_homedir_of_user failed: [%d]: [%s]\n", ++ ret, sss_strerror(ret))); ++ goto done; ++ } ++ ++ ret = store_homedir_of_user(dom, fqname, homedir); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("store_homedir_of_user failed: [%d]: [%s]\n", ++ ret, sss_strerror(ret))); ++ goto done; ++ } ++ ++done: ++ return ret; ++} ++ + static void + ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq) + { +@@ -367,6 +547,16 @@ ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq) + return; + } + ++ ret = apply_subdomain_homedir(state, state->user_dom, ++ state->ar->filter_type, ++ state->ar->filter_value); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("apply_subdomain_homedir failed: [%d]: [%s].\n", ++ ret, sss_strerror(ret))); ++ goto fail; ++ } ++ + if ((state->ar->entry_type & BE_REQ_TYPE_MASK) != BE_REQ_INITGROUPS) { + tevent_req_done(req); + return; +-- +1.8.5.3 + diff --git a/SOURCES/0079-MAN-update-of-subdomain_homedir-usage.patch b/SOURCES/0079-MAN-update-of-subdomain_homedir-usage.patch new file mode 100644 index 0000000..d14bd16 --- /dev/null +++ b/SOURCES/0079-MAN-update-of-subdomain_homedir-usage.patch @@ -0,0 +1,30 @@ +From 75b31af85b662912d9deb0c6a8f14728f20e5d2d Mon Sep 17 00:00:00 2001 +From: Pavel Reichl +Date: Wed, 29 Jan 2014 16:55:30 +0000 +Subject: [PATCH 79/80] MAN: update of subdomain_homedir usage + +Resolves: +https://fedorahosted.org/sssd/ticket/2169 + +Reviewed-by: Jakub Hrozek +--- + src/man/sssd.conf.5.xml | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index 84770f6b28876278a0ddd6d8a8a8f9a8e0d3146f..5d861c73cfeb41920619d95e5c1e5c1975dcc45b 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -1771,7 +1771,8 @@ fallback_homedir = /home/%u + + + Use this homedir as default value for all subdomains +- within this domain. See override_homedir ++ within this domain in IPA AD trust. ++ See override_homedir + for info about possible values. In addition to those, the + expansion below can only be used with + subdomain_homedir. +-- +1.8.5.3 + diff --git a/SOURCES/0080-utils-handling-NULL-params-in-sss_parse_name.patch b/SOURCES/0080-utils-handling-NULL-params-in-sss_parse_name.patch new file mode 100644 index 0000000..b8ff0cd --- /dev/null +++ b/SOURCES/0080-utils-handling-NULL-params-in-sss_parse_name.patch @@ -0,0 +1,98 @@ +From 6ab5595ec7360bd4cc4c0494a1e0afedda701961 Mon Sep 17 00:00:00 2001 +From: Pavel Reichl +Date: Sun, 26 Jan 2014 12:39:43 +0000 +Subject: [PATCH 80/80] utils: handling NULL params in sss_parse_name + +Reviewed-by: Jakub Hrozek +--- + src/util/usertools.c | 50 +++++++++++++++++++++++++++----------------------- + src/util/util.h | 2 +- + 2 files changed, 28 insertions(+), 24 deletions(-) + +diff --git a/src/util/usertools.c b/src/util/usertools.c +index 9edae41e0f216f9f0d1660e473f3aa1bf7160b06..fab0a261e82b8c4d8071ced1dac99b8e3b987b00 100644 +--- a/src/util/usertools.c ++++ b/src/util/usertools.c +@@ -322,7 +322,7 @@ done: + + int sss_parse_name(TALLOC_CTX *memctx, + struct sss_names_ctx *snctx, +- const char *orig, char **domain, char **name) ++ const char *orig, char **_domain, char **_name) + { + pcre *re = snctx->re; + const char *result; +@@ -346,31 +346,35 @@ int sss_parse_name(TALLOC_CTX *memctx, + + strnum = ret; + +- result = NULL; +- ret = pcre_get_named_substring(re, orig, ovec, strnum, "name", &result); +- if (ret < 0 || !result) { +- DEBUG(2, ("Name not found!\n")); +- return EINVAL; ++ if (_name != NULL) { ++ result = NULL; ++ ret = pcre_get_named_substring(re, orig, ovec, strnum, "name", &result); ++ if (ret < 0 || !result) { ++ DEBUG(2, ("Name not found!\n")); ++ return EINVAL; ++ } ++ *_name = talloc_strdup(memctx, result); ++ pcre_free_substring(result); ++ if (!*_name) return ENOMEM; + } +- *name = talloc_strdup(memctx, result); +- pcre_free_substring(result); +- if (!*name) return ENOMEM; + +- +- result = NULL; +- ret = pcre_get_named_substring(re, orig, ovec, strnum, "domain", &result); +- if (ret < 0 || !result) { +- DEBUG(4, ("Domain not provided!\n")); +- *domain = NULL; +- } else { +- /* ignore "" string */ +- if (*result) { +- *domain = talloc_strdup(memctx, result); +- pcre_free_substring(result); +- if (!*domain) return ENOMEM; ++ if (_domain != NULL) { ++ result = NULL; ++ ret = pcre_get_named_substring(re, orig, ovec, strnum, "domain", ++ &result); ++ if (ret < 0 || !result) { ++ DEBUG(4, ("Domain not provided!\n")); ++ *_domain = NULL; + } else { +- pcre_free_substring(result); +- *domain = NULL; ++ /* ignore "" string */ ++ if (*result) { ++ *_domain = talloc_strdup(memctx, result); ++ pcre_free_substring(result); ++ if (!*_domain) return ENOMEM; ++ } else { ++ pcre_free_substring(result); ++ *_domain = NULL; ++ } + } + } + +diff --git a/src/util/util.h b/src/util/util.h +index 3334476ab83a137d957765fe2c9afba4ad0d014c..7b185bcb4287a4afc5bf67b40164cf69b9beeb19 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -349,7 +349,7 @@ int sss_names_init(TALLOC_CTX *mem_ctx, + + int sss_parse_name(TALLOC_CTX *memctx, + struct sss_names_ctx *snctx, +- const char *orig, char **domain, char **name); ++ const char *orig, char **_domain, char **_name); + + char * + sss_get_cased_name(TALLOC_CTX *mem_ctx, const char *orig_name, +-- +1.8.5.3 + diff --git a/SOURCES/0081-LDAP-Detect-the-presence-of-POSIX-attributes.patch b/SOURCES/0081-LDAP-Detect-the-presence-of-POSIX-attributes.patch new file mode 100644 index 0000000..6c4671b --- /dev/null +++ b/SOURCES/0081-LDAP-Detect-the-presence-of-POSIX-attributes.patch @@ -0,0 +1,834 @@ +From 3b0d429051648a1545de528ec760c4823088a1d9 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 16 Dec 2013 18:36:12 +0100 +Subject: [PATCH 81/84] LDAP: Detect the presence of POSIX attributes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When the schema is set to AD and ID mapping is not used, there is a one-time +check ran when searching for users to detect the presence of POSIX +attributes in LDAP. If this check fails, the search fails as if no entry +was found and returns a special error code. + +The sdap_server_opts structure is filled every time a client connects to +a server so the posix check boolean is reset to false again on connecting +to the server. + +It might be better to move the check to where the rootDSE is retrieved, +but the check depends on several features that are not known to the code +that retrieves the rootDSE (or the connection code for example) such as what +the attribute mappings are or the authentication method that should be used. + +Reviewed-by: Sumit Bose +Reviewed-by: Pavel Březina +(cherry picked from commit e81deec535d11912b87954c81a1edd768c1386c9) +--- + src/providers/ad/ad_id.c | 50 ++++++++- + src/providers/ad/ad_id.h | 1 + + src/providers/ipa/ipa_subdomains_id.c | 2 +- + src/providers/ldap/ldap_id.c | 158 +++++++++++++++++++++++++-- + src/providers/ldap/sdap.h | 1 + + src/providers/ldap/sdap_async.c | 200 ++++++++++++++++++++++++++++++++++ + src/providers/ldap/sdap_async.h | 9 ++ + src/providers/ldap/sdap_async_enum.c | 96 +++++++++++++++- + src/util/util_errors.c | 1 + + src/util/util_errors.h | 1 + + 10 files changed, 504 insertions(+), 15 deletions(-) + +diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c +index e3302c15774ab1c24b16cefc274313e447b31e5c..bfae86284355b6c13547aac55b7273133bde851d 100644 +--- a/src/providers/ad/ad_id.c ++++ b/src/providers/ad/ad_id.c +@@ -27,6 +27,28 @@ + #include "providers/ldap/sdap_async_enum.h" + #include "providers/ldap/sdap_idmap.h" + ++static void ++disable_gc(struct ad_options *ad_options) ++{ ++ errno_t ret; ++ ++ if (dp_opt_get_bool(ad_options->basic, AD_ENABLE_GC) == false) { ++ return; ++ } ++ ++ DEBUG(SSSDBG_IMPORTANT_INFO, ("POSIX attributes were requested " ++ "but are not present on the server side. Global Catalog " ++ "lookups will be disabled\n")); ++ ++ ret = dp_opt_set_bool(ad_options->basic, ++ AD_ENABLE_GC, false); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ ("Could not turn off GC support\n")); ++ /* Not fatal */ ++ } ++} ++ + struct ad_handle_acct_info_state { + struct be_req *breq; + struct be_acct_req *ar; +@@ -34,6 +56,7 @@ struct ad_handle_acct_info_state { + struct sdap_id_conn_ctx **conn; + struct sdap_domain *sdom; + size_t cindex; ++ struct ad_options *ad_options; + + int dp_error; + const char *err; +@@ -47,6 +70,7 @@ ad_handle_acct_info_send(TALLOC_CTX *mem_ctx, + struct be_req *breq, + struct be_acct_req *ar, + struct sdap_id_ctx *ctx, ++ struct ad_options *ad_options, + struct sdap_domain *sdom, + struct sdap_id_conn_ctx **conn) + { +@@ -64,6 +88,7 @@ ad_handle_acct_info_send(TALLOC_CTX *mem_ctx, + state->ctx = ctx; + state->sdom = sdom; + state->conn = conn; ++ state->ad_options = ad_options; + state->cindex = 0; + + ret = ad_handle_acct_info_step(req); +@@ -137,12 +162,14 @@ ad_handle_acct_info_done(struct tevent_req *subreq) + if (sdap_err == EOK) { + tevent_req_done(req); + return; ++ } else if (sdap_err == ERR_NO_POSIX) { ++ disable_gc(state->ad_options); + } else if (sdap_err != ENOENT) { + tevent_req_error(req, EIO); + return; + } + +- /* Ret is only ENOENT now. Try the next connection */ ++ /* Ret is only ENOENT or ERR_NO_POSIX now. Try the next connection */ + state->cindex++; + ret = ad_handle_acct_info_step(req); + if (ret != EAGAIN) { +@@ -356,7 +383,7 @@ ad_account_info_handler(struct be_req *be_req) + } + + req = ad_handle_acct_info_send(be_req, be_req, ar, sdap_id_ctx, +- sdom, clist); ++ ad_ctx->ad_options, sdom, clist); + if (req == NULL) { + ret = ENOMEM; + goto fail; +@@ -611,9 +638,24 @@ ad_enumeration_done(struct tevent_req *subreq) + + ret = sdap_dom_enum_ex_recv(subreq); + talloc_zfree(subreq); +- if (ret != EOK) { ++ if (ret == ERR_NO_POSIX) { ++ /* Retry enumerating the same domain again, this time w/o ++ * connecting to GC ++ */ ++ disable_gc(state->id_ctx->ad_options); ++ ret = ad_enum_sdom(req, state->sditer, state->id_ctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("Could not retry domain %s\n", state->sditer->dom->name)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ /* Execution will resume in ad_enumeration_done */ ++ return; ++ } else if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, +- ("Could not enumerate domain %s\n", state->sdom->dom->name)); ++ ("Could not enumerate domain %s\n", state->sditer->dom->name)); + tevent_req_error(req, ret); + return; + } +diff --git a/src/providers/ad/ad_id.h b/src/providers/ad/ad_id.h +index 74b85645c2d6458617a4064fe3fb3f99696c3741..9eb0ac3754be2fd687ed2257b91854f5fceb82a2 100644 +--- a/src/providers/ad/ad_id.h ++++ b/src/providers/ad/ad_id.h +@@ -31,6 +31,7 @@ ad_handle_acct_info_send(TALLOC_CTX *mem_ctx, + struct be_req *breq, + struct be_acct_req *ar, + struct sdap_id_ctx *ctx, ++ struct ad_options *ad_options, + struct sdap_domain *sdom, + struct sdap_id_conn_ctx **conn); + errno_t +diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c +index fb1ad896885866dd9c34f9db960e09d92763f86d..b61c6a5f4d7605f0cdfa182bbc933d35c4613a79 100644 +--- a/src/providers/ipa/ipa_subdomains_id.c ++++ b/src/providers/ipa/ipa_subdomains_id.c +@@ -323,7 +323,7 @@ ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx, + } + + subreq = ad_handle_acct_info_send(req, be_req, ar, sdap_id_ctx, +- sdom, clist); ++ ad_id_ctx->ad_options, sdom, clist); + if (subreq == NULL) { + ret = ENOMEM; + goto fail; +diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c +index e36c1f697c18e865a47d991dad103fc440456118..b948ba9f358af994bdbbb99a468f7dbe66e65c1d 100644 +--- a/src/providers/ldap/ldap_id.c ++++ b/src/providers/ldap/ldap_id.c +@@ -50,6 +50,7 @@ struct users_get_state { + + char *filter; + const char **attrs; ++ bool use_id_mapping; + + int dp_error; + int sdap_ret; +@@ -58,6 +59,8 @@ struct users_get_state { + + static int users_get_retry(struct tevent_req *req); + static void users_get_connect_done(struct tevent_req *subreq); ++static void users_get_posix_check_done(struct tevent_req *subreq); ++static void users_get_search(struct tevent_req *req); + static void users_get_done(struct tevent_req *subreq); + + struct tevent_req *users_get_send(TALLOC_CTX *memctx, +@@ -79,7 +82,6 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, + uid_t uid; + enum idmap_error_code err; + char *sid; +- bool use_id_mapping; + + req = tevent_req_create(memctx, &state, struct users_get_state); + if (!req) return NULL; +@@ -103,7 +105,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, + state->name = name; + state->filter_type = filter_type; + +- use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping( ++ state->use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping( + ctx->opts->idmap_ctx, + sdom->dom->name, + sdom->dom->domain_id); +@@ -116,7 +118,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, + } + break; + case BE_FILTER_IDNUM: +- if (use_id_mapping) { ++ if (state->use_id_mapping) { + /* If we're ID-mapping, we need to use the objectSID + * in the search filter. + */ +@@ -184,7 +186,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx, + goto fail; + } + +- if (use_id_mapping || filter_type == BE_FILTER_SECID) { ++ 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. +@@ -269,6 +271,75 @@ static void users_get_connect_done(struct tevent_req *subreq) + 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->use_id_mapping == false && ++ state->ctx->opts->schema_type == SDAP_SCHEMA_AD && ++ state->ctx->srv_opts && ++ state->ctx->srv_opts->posix_checked == false) { ++ 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) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, users_get_posix_check_done, req); ++ return; ++ } ++ ++ users_get_search(req); ++} ++ ++static void users_get_posix_check_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ bool has_posix; ++ int dp_error; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct users_get_state *state = tevent_req_data(req, ++ struct users_get_state); ++ ++ ret = sdap_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 user search ++ */ ++ ret = sdap_id_op_done(state->op, ret, &dp_error); ++ if (dp_error == DP_ERR_OK && ret != EOK) { ++ /* retry */ ++ ret = users_get_retry(req); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ } ++ return; ++ } ++ } ++ ++ state->ctx->srv_opts->posix_checked = true; ++ ++ /* If the check ran to completion, we know for certain about the attributes ++ */ ++ if (has_posix == false) { ++ state->sdap_ret = ERR_NO_POSIX; ++ tevent_req_done(req); ++ return; ++ } ++ ++ users_get_search(req); ++} ++ ++static void users_get_search(struct tevent_req *req) ++{ ++ struct users_get_state *state = tevent_req_data(req, ++ struct users_get_state); ++ struct tevent_req *subreq; ++ + subreq = sdap_get_users_send(state, state->ev, + state->domain, state->sysdb, + state->ctx->opts, +@@ -434,6 +505,7 @@ struct groups_get_state { + + char *filter; + const char **attrs; ++ bool use_id_mapping; + + int dp_error; + int sdap_ret; +@@ -442,6 +514,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_search(struct tevent_req *req); + static void groups_get_done(struct tevent_req *subreq); + + struct tevent_req *groups_get_send(TALLOC_CTX *memctx, +@@ -463,7 +537,6 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx, + gid_t gid; + enum idmap_error_code err; + char *sid; +- bool use_id_mapping; + const char *member_filter[2]; + + req = tevent_req_create(memctx, &state, struct groups_get_state); +@@ -488,7 +561,7 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx, + state->name = name; + state->filter_type = filter_type; + +- use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping( ++ state->use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping( + ctx->opts->idmap_ctx, + sdom->dom->name, + sdom->dom->domain_id); +@@ -503,7 +576,7 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx, + } + break; + case BE_FILTER_IDNUM: +- if (use_id_mapping) { ++ if (state->use_id_mapping) { + /* If we're ID-mapping, we need to use the objectSID + * in the search filter. + */ +@@ -571,7 +644,7 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx, + goto fail; + } + +- if (use_id_mapping || filter_type == BE_FILTER_SECID) { ++ 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 + */ +@@ -660,6 +733,75 @@ static void groups_get_connect_done(struct tevent_req *subreq) + 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->use_id_mapping == false && ++ state->ctx->opts->schema_type == SDAP_SCHEMA_AD && ++ state->ctx->srv_opts && ++ state->ctx->srv_opts->posix_checked == false) { ++ 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) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, groups_get_posix_check_done, req); ++ return; ++ } ++ ++ groups_get_search(req); ++} ++ ++static void groups_get_posix_check_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ bool has_posix; ++ int dp_error; ++ 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 = sdap_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 group search ++ */ ++ ret = sdap_id_op_done(state->op, ret, &dp_error); ++ if (dp_error == DP_ERR_OK && ret != EOK) { ++ /* retry */ ++ ret = groups_get_retry(req); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ } ++ return; ++ } ++ } ++ ++ state->ctx->srv_opts->posix_checked = true; ++ ++ /* If the check ran to completion, we know for certain about the attributes ++ */ ++ if (has_posix == false) { ++ state->sdap_ret = ERR_NO_POSIX; ++ tevent_req_done(req); ++ return; ++ } ++ ++ groups_get_search(req); ++} ++ ++static void groups_get_search(struct tevent_req *req) ++{ ++ struct groups_get_state *state = tevent_req_data(req, ++ struct groups_get_state); ++ struct tevent_req *subreq; ++ + subreq = sdap_get_groups_send(state, state->ev, + state->sdom, + state->ctx->opts, +diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h +index d408be0a65cdd840d8379b7af4c0ab1e67ed3f5c..f3f13e9c72b368af0c14e2d830a89a41e8cf77e4 100644 +--- a/src/providers/ldap/sdap.h ++++ b/src/providers/ldap/sdap.h +@@ -446,6 +446,7 @@ struct sdap_server_opts { + char *max_group_value; + char *max_service_value; + char *max_sudo_value; ++ bool posix_checked; + }; + + struct sdap_id_ctx; +diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c +index 367007bde0011ed4de283b2a50b22538830a5275..1022a093f06ec7e9a50b13160fc9a4660a255e92 100644 +--- a/src/providers/ldap/sdap_async.c ++++ b/src/providers/ldap/sdap_async.c +@@ -21,6 +21,7 @@ + + #include + #include "util/util.h" ++#include "util/strtonum.h" + #include "providers/ldap/sdap_async_private.h" + + #define REALM_SEPARATOR '@' +@@ -2083,6 +2084,205 @@ int sdap_asq_search_recv(struct tevent_req *req, + return EOK; + } + ++/* ==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, ++ void *pvt); ++ ++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; ++}; ++ ++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 sdap_posix_check_state *state; ++ errno_t ret; ++ ++ req = tevent_req_create(memctx, &state, struct sdap_posix_check_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ 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); ++ if (state->attrs == NULL) { ++ ret = ENOMEM; ++ goto fail; ++ } ++ state->attrs[0] = "objectclass"; ++ state->attrs[1] = opts->user_map[SDAP_AT_USER_UID].name; ++ state->attrs[2] = opts->group_map[SDAP_AT_GROUP_GID].name; ++ state->attrs[3] = NULL; ++ ++ state->filter = talloc_asprintf(state, "(|(%s=*)(%s=*))", ++ opts->user_map[SDAP_AT_USER_UID].name, ++ opts->group_map[SDAP_AT_GROUP_GID].name); ++ if (state->filter == NULL) { ++ ret = ENOMEM; ++ 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, false, ++ NULL, NULL, 1, state->timeout, ++ false, sdap_posix_check_parse, ++ state); ++ if (subreq == NULL) { ++ return ENOMEM; ++ } ++ tevent_req_set_callback(subreq, sdap_posix_check_done, req); ++ ++ return EOK; ++} ++ ++static errno_t sdap_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); ++ char *dn; ++ char *endptr; ++ ++ dn = ldap_get_dn(sh->ldap, msg->msg); ++ if (dn == NULL) { ++ DEBUG(SSSDBG_TRACE_LIBS, ++ ("Search did not find any entry with POSIX attributes\n")); ++ goto done; ++ } ++ DEBUG(SSSDBG_TRACE_LIBS, ("Found [%s] with POSIX attributes\n", dn)); ++ ldap_memfree(dn); ++ ++ vals = ldap_get_values_len(sh->ldap, msg->msg, ++ state->opts->user_map[SDAP_AT_USER_UID].name); ++ if (vals == NULL) { ++ vals = ldap_get_values_len(sh->ldap, msg->msg, ++ state->opts->group_map[SDAP_AT_GROUP_GID].name); ++ if (vals == NULL) { ++ DEBUG(SSSDBG_TRACE_LIBS, ("Entry does not have POSIX attrs?\n")); ++ goto done; ++ } ++ } ++ ++ if (vals[0] == NULL) { ++ DEBUG(SSSDBG_TRACE_LIBS, ("No value for POSIX attr\n")); ++ goto done; ++ } ++ ++ errno = 0; ++ strtouint32(vals[0]->bv_val, &endptr, 10); ++ if (errno || *endptr || (vals[0]->bv_val == endptr)) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("POSIX attribute is not a number: %s\n", vals[0]->bv_val)); ++ goto done; ++ } ++ ++ state->has_posix = true; ++done: ++ ldap_value_free_len(vals); ++ return EOK; ++} ++ ++static void sdap_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); ++ errno_t ret; ++ ++ ret = sdap_get_generic_ext_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("sdap_get_generic_ext_recv failed [%d]: %s\n", ++ ret, strerror(ret))); ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ /* Positive hit is definitve, no need to search other bases */ ++ if (state->has_posix == true) { ++ DEBUG(SSSDBG_FUNC_DATA, ("Server has POSIX attributes\n")); ++ tevent_req_done(req); ++ 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); ++} ++ ++int sdap_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); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ *_has_posix = state->has_posix; ++ return EOK; ++} ++ + /* ==Generic Deref Search============================================ */ + enum sdap_deref_type { + SDAP_DEREF_OPENLDAP, +diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h +index 33e8708ab7e80ab4280df300fdc300d4ecd18305..593404af3c460f8d956b0832b8f7e398b331729b 100644 +--- a/src/providers/ldap/sdap_async.h ++++ b/src/providers/ldap/sdap_async.h +@@ -210,6 +210,15 @@ int sdap_deref_search_recv(struct tevent_req *req, + size_t *reply_count, + struct sdap_deref_attrs ***reply); + ++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, ++ bool *_has_posix); ++ + errno_t + sdap_attrs_add_ldap_attr(struct sysdb_attrs *ldap_attrs, + const char *attr_name, +diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c +index cbc56be20526e6c2323f9fd1b49038dd4bf13fe5..0c20afa9d7a1b0198bb71cffdafcb14763c1dafb 100644 +--- a/src/providers/ldap/sdap_async_enum.c ++++ b/src/providers/ldap/sdap_async_enum.c +@@ -68,6 +68,8 @@ static errno_t sdap_dom_enum_ex_retry(struct tevent_req *req, + tevent_req_fn tcb); + static bool sdap_dom_enum_ex_connected(struct tevent_req *subreq); + static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq); ++static void sdap_dom_enum_ex_posix_check_done(struct tevent_req *subreq); ++static errno_t sdap_dom_enum_search_users(struct tevent_req *req); + static void sdap_dom_enum_ex_users_done(struct tevent_req *subreq); + static void sdap_dom_enum_ex_get_groups(struct tevent_req *subreq); + static void sdap_dom_enum_ex_groups_done(struct tevent_req *subreq); +@@ -178,19 +180,109 @@ static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq) + struct tevent_req); + struct sdap_dom_enum_ex_state *state = tevent_req_data(req, + struct sdap_dom_enum_ex_state); ++ bool use_id_mapping; ++ errno_t ret; + + if (sdap_dom_enum_ex_connected(subreq) == false) { + return; + } + ++ use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping( ++ state->ctx->opts->idmap_ctx, ++ state->sdom->dom->name, ++ state->sdom->dom->domain_id); ++ ++ /* 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) { ++ 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) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ tevent_req_set_callback(subreq, ++ sdap_dom_enum_ex_posix_check_done, req); ++ return; ++ } ++ ++ ++ ret = sdap_dom_enum_search_users(req); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ /* Execution resumes in sdap_dom_enum_ex_users_done */ ++} ++ ++static void sdap_dom_enum_ex_posix_check_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ bool has_posix; ++ int dp_error; ++ ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ 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); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ /* We can only finish the id_op on error as the connection ++ * is re-used by the user search ++ */ ++ ret = sdap_id_op_done(state->user_op, ret, &dp_error); ++ if (dp_error == DP_ERR_OK && ret != EOK) { ++ /* retry */ ++ ret = sdap_dom_enum_ex_retry(req, state->user_op, ++ sdap_dom_enum_ex_get_users); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ } ++ return; ++ } ++ } ++ ++ state->ctx->srv_opts->posix_checked = true; ++ ++ /* If the check ran to completion, we know for certain about the attributes ++ */ ++ if (has_posix == false) { ++ tevent_req_error(req, ERR_NO_POSIX); ++ return; ++ } ++ ++ ++ ret = sdap_dom_enum_search_users(req); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ /* Execution resumes in sdap_dom_enum_ex_users_done */ ++} ++ ++static errno_t sdap_dom_enum_search_users(struct tevent_req *req) ++{ ++ struct sdap_dom_enum_ex_state *state = tevent_req_data(req, ++ struct sdap_dom_enum_ex_state); ++ struct tevent_req *subreq; ++ + subreq = enum_users_send(state, state->ev, + state->ctx, state->sdom, + state->user_op, state->purge); + if (subreq == NULL) { +- tevent_req_error(req, ENOMEM); +- return; ++ return ENOMEM; + } + tevent_req_set_callback(subreq, sdap_dom_enum_ex_users_done, req); ++ return EOK; + } + + static void sdap_dom_enum_ex_users_done(struct tevent_req *subreq) +diff --git a/src/util/util_errors.c b/src/util/util_errors.c +index 633257e8da0ef039e555a07ad8b51125114ca01c..c9b507557da07555c719bb0dd18145e6799a53eb 100644 +--- a/src/util/util_errors.c ++++ b/src/util/util_errors.c +@@ -52,6 +52,7 @@ struct err_string error_to_str[] = { + { "Domain not found" }, /* ERR_DOMAIN_NOT_FOUND */ + { "Missing configuration file" }, /* ERR_MISSING_CONF */ + { "Malformed search filter" }, /* ERR_INVALID_FILTER, */ ++ { "No POSIX attributes detected" }, /* ERR_NO_POSIX */ + }; + + +diff --git a/src/util/util_errors.h b/src/util/util_errors.h +index 1332085031dbe6935cbdc94543fa14b09fe81028..3dd94af1f304d65e22515c859c6f69a021fa7e92 100644 +--- a/src/util/util_errors.h ++++ b/src/util/util_errors.h +@@ -74,6 +74,7 @@ enum sssd_errors { + ERR_DOMAIN_NOT_FOUND, + ERR_MISSING_CONF, + ERR_INVALID_FILTER, ++ ERR_NO_POSIX, + ERR_LAST /* ALWAYS LAST */ + }; + +-- +1.8.5.3 + diff --git a/SOURCES/0082-AD-Only-download-domains-that-are-set-to-enumerate.patch b/SOURCES/0082-AD-Only-download-domains-that-are-set-to-enumerate.patch new file mode 100644 index 0000000..b9b8cc0 --- /dev/null +++ b/SOURCES/0082-AD-Only-download-domains-that-are-set-to-enumerate.patch @@ -0,0 +1,34 @@ +From 94f1e5966733e1b327a9eba37781379c5d90f8a3 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 5 Feb 2014 16:39:47 +0100 +Subject: [PATCH 82/84] AD: Only download domains that are set to enumerate +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Pavel Březina +(cherry picked from commit 957c55df7a7086166fb3c14cead6a0dab8f574c1) +--- + src/providers/ad/ad_id.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c +index bfae86284355b6c13547aac55b7273133bde851d..2d3c11bb838f1418c006f9d79d8552cec1443e66 100644 +--- a/src/providers/ad/ad_id.c ++++ b/src/providers/ad/ad_id.c +@@ -660,7 +660,11 @@ ad_enumeration_done(struct tevent_req *subreq) + return; + } + +- state->sditer = state->sditer->next; ++ do { ++ state->sditer = state->sditer->next; ++ } while (state->sditer && ++ state->sditer->dom->enumerate == false); ++ + if (state->sditer != NULL) { + subdom_id_ctx = talloc_get_type(state->sdom->pvt, struct ad_id_ctx); + if (subdom_id_ctx == NULL) { +-- +1.8.5.3 + diff --git a/SOURCES/0083-AD-Remove-dead-code.patch b/SOURCES/0083-AD-Remove-dead-code.patch new file mode 100644 index 0000000..178d308 --- /dev/null +++ b/SOURCES/0083-AD-Remove-dead-code.patch @@ -0,0 +1,43 @@ +From 7f9da1ed660e45e276778187260ddbbf411c761e Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 5 Feb 2014 16:40:41 +0100 +Subject: [PATCH 83/84] AD: Remove dead code +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Pavel Březina +(cherry picked from commit d3436880c0ec1a7776698c739d4a3edc9a6ac57c) +--- + src/providers/ad/ad_id.c | 8 -------- + 1 file changed, 8 deletions(-) + +diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c +index 2d3c11bb838f1418c006f9d79d8552cec1443e66..87af656b364344a8ef27a444e5dfcf8848939110 100644 +--- a/src/providers/ad/ad_id.c ++++ b/src/providers/ad/ad_id.c +@@ -634,7 +634,6 @@ ad_enumeration_done(struct tevent_req *subreq) + struct tevent_req); + struct ad_enumeration_state *state = tevent_req_data(req, + struct ad_enumeration_state); +- struct ad_id_ctx *subdom_id_ctx; + + ret = sdap_dom_enum_ex_recv(subreq); + talloc_zfree(subreq); +@@ -666,13 +665,6 @@ ad_enumeration_done(struct tevent_req *subreq) + state->sditer->dom->enumerate == false); + + if (state->sditer != NULL) { +- subdom_id_ctx = talloc_get_type(state->sdom->pvt, struct ad_id_ctx); +- if (subdom_id_ctx == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot retrieve subdomain ad_id_ctx!\n")); +- tevent_req_error(req, EFAULT); +- return; +- } +- + ret = ad_enum_sdom(req, state->sditer, state->sditer->pvt); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not enumerate domain %s\n", +-- +1.8.5.3 + diff --git a/SOURCES/0084-LDAP-Handle-errors-from-sdap_id_op-properly-in-enum-.patch b/SOURCES/0084-LDAP-Handle-errors-from-sdap_id_op-properly-in-enum-.patch new file mode 100644 index 0000000..88049e5 --- /dev/null +++ b/SOURCES/0084-LDAP-Handle-errors-from-sdap_id_op-properly-in-enum-.patch @@ -0,0 +1,99 @@ +From 97616c8e1ab41c72c509a31626fafcfb07241a46 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 11 Feb 2014 12:23:51 +0100 +Subject: [PATCH 84/84] LDAP: Handle errors from sdap_id_op properly in enum + code +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Pavel Březina +(cherry picked from commit 93dabb2fe0a798f22bb802b9c6521ab9e6a4ac36) +--- + src/providers/ldap/sdap_async_enum.c | 42 +++++++++++++++++++++++++++++++++++- + 1 file changed, 41 insertions(+), 1 deletion(-) + +diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c +index 0c20afa9d7a1b0198bb71cffdafcb14763c1dafb..0431d03c38098080847035d522ab5f1f494b8bfe 100644 +--- a/src/providers/ldap/sdap_async_enum.c ++++ b/src/providers/ldap/sdap_async_enum.c +@@ -235,7 +235,7 @@ static void sdap_dom_enum_ex_posix_check_done(struct tevent_req *subreq) + + ret = sdap_posix_check_recv(subreq, &has_posix); + talloc_zfree(subreq); +- if (ret != EOK) { ++ if (ret != EOK && ret != ERR_NO_POSIX) { + /* We can only finish the id_op on error as the connection + * is re-used by the user search + */ +@@ -248,6 +248,16 @@ static void sdap_dom_enum_ex_posix_check_done(struct tevent_req *subreq) + tevent_req_error(req, ret); + } + return; ++ } else if (dp_error == DP_ERR_OFFLINE) { ++ DEBUG(SSSDBG_TRACE_FUNC, ("Backend is offline, retrying later\n")); ++ tevent_req_done(req); ++ return; ++ } else { ++ /* Non-recoverable error */ ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("POSIX check failed: %d: %s\n", ret, sss_strerror(ret))); ++ tevent_req_error(req, ret); ++ return; + } + } + +@@ -306,6 +316,16 @@ static void sdap_dom_enum_ex_users_done(struct tevent_req *subreq) + return; + } + return; ++ } else if (dp_error == DP_ERR_OFFLINE) { ++ DEBUG(SSSDBG_TRACE_FUNC, ("Backend is offline, retrying later\n")); ++ tevent_req_done(req); ++ return; ++ } else if (ret != EOK && ret != ENOENT) { ++ /* Non-recoverable error */ ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("User enumeration failed: %d: %s\n", ret, sss_strerror(ret))); ++ tevent_req_error(req, ret); ++ return; + } + + state->group_op = sdap_id_op_create(state, state->group_conn->conn_cache); +@@ -367,6 +387,16 @@ static void sdap_dom_enum_ex_groups_done(struct tevent_req *subreq) + return; + } + return; ++ } else if (dp_error == DP_ERR_OFFLINE) { ++ DEBUG(SSSDBG_TRACE_FUNC, ("Backend is offline, retrying later\n")); ++ tevent_req_done(req); ++ return; ++ } else if (ret != EOK && ret != ENOENT) { ++ /* Non-recoverable error */ ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("Group enumeration failed: %d: %s\n", ret, sss_strerror(ret))); ++ tevent_req_error(req, ret); ++ return; + } + + +@@ -426,6 +456,16 @@ static void sdap_dom_enum_ex_svcs_done(struct tevent_req *subreq) + return; + } + return; ++ } else if (dp_error == DP_ERR_OFFLINE) { ++ DEBUG(SSSDBG_TRACE_FUNC, ("Backend is offline, retrying later\n")); ++ tevent_req_done(req); ++ return; ++ } else if (ret != EOK && ret != ENOENT) { ++ /* Non-recoverable error */ ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("Service enumeration failed: %d: %s\n", ret, sss_strerror(ret))); ++ tevent_req_error(req, ret); ++ return; + } + + /* Ok, we've completed an enumeration. Save this to the +-- +1.8.5.3 + diff --git a/SOURCES/0085-SSS_CACHE-Reset-the-initgroups-attribute-when-resett.patch b/SOURCES/0085-SSS_CACHE-Reset-the-initgroups-attribute-when-resett.patch new file mode 100644 index 0000000..684c1e6 --- /dev/null +++ b/SOURCES/0085-SSS_CACHE-Reset-the-initgroups-attribute-when-resett.patch @@ -0,0 +1,35 @@ +From a5910c05a1013c9a050f6df3d4c6884e894bf2d9 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 11 Feb 2014 22:51:48 +0100 +Subject: [PATCH 85/88] SSS_CACHE: Reset the initgroups attribute when + resetting users +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +(cherry picked from commit 30ee051025753b63ceb19d3b83c44019a19554a1) +Reviewed-by: Lukáš Slebodník +--- + src/tools/sss_cache.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c +index 56dc47afdcb92b71dc1ef71d7f26fdf276a1c45f..59b36db3e25333f4ca5da241b607edda226b929f 100644 +--- a/src/tools/sss_cache.c ++++ b/src/tools/sss_cache.c +@@ -424,6 +424,12 @@ static errno_t invalidate_entry(TALLOC_CTX *ctx, struct sysdb_ctx *sysdb, + if (ret == EOK) { + switch (entry_type) { + case TYPE_USER: ++ /* For users, we also need to reset the initgroups ++ * cache expiry */ ++ ret = sysdb_attrs_add_time_t(sys_attrs, ++ SYSDB_INITGR_EXPIRE, 1); ++ if (ret != EOK) return ret; ++ + ret = sysdb_set_user_attr(sysdb, domain, name, sys_attrs, + SYSDB_MOD_REP); + break; +-- +1.8.5.3 + diff --git a/SOURCES/0086-IPA-Default-to-krb5_use_fast-try.patch b/SOURCES/0086-IPA-Default-to-krb5_use_fast-try.patch new file mode 100644 index 0000000..724e723 --- /dev/null +++ b/SOURCES/0086-IPA-Default-to-krb5_use_fast-try.patch @@ -0,0 +1,70 @@ +From 529c7ade2f7f633fdb80e2f5b2055afd5a017d2f Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 11 Feb 2014 15:36:04 +0100 +Subject: [PATCH 86/88] IPA: Default to krb5_use_fast=try +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Pavel Březina +Reviewed-by: Nathaniel McCallum +Reviewed-by: Alexander Bokovoy +--- + src/providers/ipa/ipa_common.c | 27 +++++++++++++++++++++++++++ + src/providers/ipa/ipa_opts.h | 2 +- + 2 files changed, 28 insertions(+), 1 deletion(-) + +diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c +index 671374098afa1f2e00fc9cf1788ba4383b600a1b..e0abd169302406a555728589185b67e0fbbcfe94 100644 +--- a/src/providers/ipa/ipa_common.c ++++ b/src/providers/ipa/ipa_common.c +@@ -664,6 +664,33 @@ int ipa_get_auth_options(struct ipa_options *ipa_opts, + dp_opt_get_string(ipa_opts->auth, KRB5_REALM))); + } + ++ /* If krb5_fast_principal was not set explicitly, default to ++ * host/$client_hostname ++ */ ++ value = dp_opt_get_string(ipa_opts->auth, KRB5_FAST_PRINCIPAL); ++ if (value == NULL) { ++ value = talloc_asprintf(ipa_opts->auth, "host/%s", ++ dp_opt_get_string(ipa_opts->basic, ++ IPA_HOSTNAME)); ++ if (value == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot set %s!\n", ++ ipa_opts->auth[KRB5_FAST_PRINCIPAL].opt_name)); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = dp_opt_set_string(ipa_opts->auth, KRB5_FAST_PRINCIPAL, ++ value); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot set %s!\n", ++ ipa_opts->auth[KRB5_FAST_PRINCIPAL].opt_name)); ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_CONF_SETTINGS, ("Option %s set to %s\n", ++ ipa_opts->auth[KRB5_FAST_PRINCIPAL].opt_name, value)); ++ } ++ + /* Set flag that controls whether we want to write the + * kdcinfo files at all + */ +diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h +index 27dc3e2f977383836c18cb824abceb03c9e9056c..c46d421ad0bfb9272cbdadbfeea5ebcf65a7deb1 100644 +--- a/src/providers/ipa/ipa_opts.h ++++ b/src/providers/ipa/ipa_opts.h +@@ -274,7 +274,7 @@ struct dp_option ipa_def_krb5_opts[] = { + { "krb5_renewable_lifetime", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "krb5_lifetime", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "krb5_renew_interval", DP_OPT_STRING, NULL_STRING, NULL_STRING }, +- { "krb5_use_fast", DP_OPT_STRING, NULL_STRING, NULL_STRING }, ++ { "krb5_use_fast", DP_OPT_STRING, { "try" }, NULL_STRING }, + { "krb5_fast_principal", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "krb5_canonicalize", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE }, + { "krb5_use_enterprise_principal", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, +-- +1.8.5.3 + diff --git a/SOURCES/0087-IPA-default-krb5_fast_principal-to-host-client-realm.patch b/SOURCES/0087-IPA-default-krb5_fast_principal-to-host-client-realm.patch new file mode 100644 index 0000000..ca8a886 --- /dev/null +++ b/SOURCES/0087-IPA-default-krb5_fast_principal-to-host-client-realm.patch @@ -0,0 +1,41 @@ +From 920e81404bc37e57f2d7613ca9031e2337c1edd0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 14 Feb 2014 11:45:50 +0100 +Subject: [PATCH 87/88] IPA: default krb5_fast_principal to host/$client@$realm + +If krb5_fast_principal is not set in sssd.conf it was set to host/$client, +KRB5 default realm was used which doesn't have to be the same as realm +used for IPA, thus authentication failed when using FAST. + +Reviewed-by: Alexander Bokovoy +(cherry picked from commit e325cabe762fad7d696e014a7fdbb47a5cb8174a) +--- + src/providers/ipa/ipa_common.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c +index e0abd169302406a555728589185b67e0fbbcfe94..d4db1549b3657268381d0e425615c1b389fed23e 100644 +--- a/src/providers/ipa/ipa_common.c ++++ b/src/providers/ipa/ipa_common.c +@@ -665,13 +665,15 @@ int ipa_get_auth_options(struct ipa_options *ipa_opts, + } + + /* If krb5_fast_principal was not set explicitly, default to +- * host/$client_hostname ++ * host/$client_hostname@REALM + */ + value = dp_opt_get_string(ipa_opts->auth, KRB5_FAST_PRINCIPAL); + if (value == NULL) { +- value = talloc_asprintf(ipa_opts->auth, "host/%s", ++ value = talloc_asprintf(ipa_opts->auth, "host/%s@%s", + dp_opt_get_string(ipa_opts->basic, +- IPA_HOSTNAME)); ++ IPA_HOSTNAME), ++ dp_opt_get_string(ipa_opts->auth, ++ KRB5_REALM)); + if (value == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot set %s!\n", + ipa_opts->auth[KRB5_FAST_PRINCIPAL].opt_name)); +-- +1.8.5.3 + diff --git a/SOURCES/0088-MAN-Clarify-the-new-krb5_use_fast-IPA-default.patch b/SOURCES/0088-MAN-Clarify-the-new-krb5_use_fast-IPA-default.patch new file mode 100644 index 0000000..a985a8c --- /dev/null +++ b/SOURCES/0088-MAN-Clarify-the-new-krb5_use_fast-IPA-default.patch @@ -0,0 +1,71 @@ +From 4d5cbad45245016747aa34f2271f2fe5214cf34a Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 17 Feb 2014 17:30:52 +0100 +Subject: [PATCH 88/88] MAN: Clarify the new krb5_use_fast IPA default + +--- + src/man/sssd-ipa.5.xml | 34 ++++++++++++++++++++++++++++++++++ + src/man/sssd-krb5.5.xml | 2 +- + 2 files changed, 35 insertions(+), 1 deletion(-) + +diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml +index 28ac252abbeb508d62ca1a94f2440afc6b5b5c88..7ab59dc20cc43c7ed86c0e1a988a30813b9fe673 100644 +--- a/src/man/sssd-ipa.5.xml ++++ b/src/man/sssd-ipa.5.xml +@@ -399,6 +399,40 @@ + + + ++ krb5_use_fast (string) ++ ++ ++ Enables flexible authentication secure tunneling ++ (FAST) for Kerberos pre-authentication. The ++ following options are supported: ++ ++ ++ never use FAST. ++ ++ ++ try to use FAST. If the server ++ does not support FAST, continue the ++ authentication without it. This is ++ equivalent to not setting this option at all. ++ ++ ++ demand to use FAST. The ++ authentication fails if the server does not ++ require fast. ++ ++ ++ Default: try ++ ++ ++ NOTE: SSSD supports FAST only with ++ MIT Kerberos version 1.8 and later. If SSSD is used ++ with an older version of MIT Kerberos, using this ++ option is a configuration error. ++ ++ ++ ++ ++ + ipa_hbac_refresh (integer) + + +diff --git a/src/man/sssd-krb5.5.xml b/src/man/sssd-krb5.5.xml +index 384d506616408c3f45f5b85621a8101ef4faa3e8..602c07e9c2e2b9c231c596d50be94b7d220c3257 100644 +--- a/src/man/sssd-krb5.5.xml ++++ b/src/man/sssd-krb5.5.xml +@@ -502,7 +502,7 @@ + + + +- Default: false (AD provide: true) ++ Default: false (AD provider: true) + + + +-- +1.8.5.3 + diff --git a/SOURCES/0089-IPA-Don-t-call-tevent_req_post-outside-_send.patch b/SOURCES/0089-IPA-Don-t-call-tevent_req_post-outside-_send.patch new file mode 100644 index 0000000..ac3ca2d --- /dev/null +++ b/SOURCES/0089-IPA-Don-t-call-tevent_req_post-outside-_send.patch @@ -0,0 +1,29 @@ +From 4b1c7fee8fd597660e77436fd205802e353b2e97 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 19 Feb 2014 15:00:15 +0100 +Subject: [PATCH 89/90] IPA: Don't call tevent_req_post outside _send +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Pavel Březina +(cherry picked from commit 6d4574a8dd1a9cafbb15631e7d01bdf6e67f821b) +--- + src/providers/ipa/ipa_subdomains_id.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c +index b61c6a5f4d7605f0cdfa182bbc933d35c4613a79..c15bdaa703835ab07a9b3b21d1304220a01eac10 100644 +--- a/src/providers/ipa/ipa_subdomains_id.c ++++ b/src/providers/ipa/ipa_subdomains_id.c +@@ -580,7 +580,6 @@ ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq) + fail: + state->dp_error = DP_ERR_FATAL; + tevent_req_error(req, ret); +- tevent_req_post(req, state->ev); + return; + } + +-- +1.8.5.3 + diff --git a/SOURCES/0090-IPA-Don-t-fail-if-apply_subdomain_homedir-returns-EN.patch b/SOURCES/0090-IPA-Don-t-fail-if-apply_subdomain_homedir-returns-EN.patch new file mode 100644 index 0000000..c09b52e --- /dev/null +++ b/SOURCES/0090-IPA-Don-t-fail-if-apply_subdomain_homedir-returns-EN.patch @@ -0,0 +1,28 @@ +From da729f6765e11fec980fbb9ec1291e2a7ef533fe Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 19 Feb 2014 15:34:34 +0100 +Subject: [PATCH 90/90] IPA: Don't fail if apply_subdomain_homedir returns + ENOENT + +Reviewed-by: Pavel Reichl +(cherry picked from commit 26786da26706aeedbda4caea0383c143ed4e59dc) +--- + 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 c15bdaa703835ab07a9b3b21d1304220a01eac10..637dd61f9f272eb4ac4ecb8368d2210801bb0373 100644 +--- a/src/providers/ipa/ipa_subdomains_id.c ++++ b/src/providers/ipa/ipa_subdomains_id.c +@@ -550,7 +550,7 @@ ipa_get_ad_acct_ad_part_done(struct tevent_req *subreq) + ret = apply_subdomain_homedir(state, state->user_dom, + state->ar->filter_type, + state->ar->filter_value); +- if (ret != EOK) { ++ if (ret != EOK && ret != ENOENT) { + DEBUG(SSSDBG_OP_FAILURE, + ("apply_subdomain_homedir failed: [%d]: [%s].\n", + ret, sss_strerror(ret))); +-- +1.8.5.3 + diff --git a/SOURCES/0091-LDAP-Setup-periodic-task-only-once.patch b/SOURCES/0091-LDAP-Setup-periodic-task-only-once.patch new file mode 100644 index 0000000..00b4633 --- /dev/null +++ b/SOURCES/0091-LDAP-Setup-periodic-task-only-once.patch @@ -0,0 +1,132 @@ +From f7a7a583c475eb22a6d762e74c67ffcfa7ba32d0 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Wed, 12 Feb 2014 14:33:49 +0100 +Subject: [PATCH 91/92] LDAP: Setup periodic task only once. + +If id provider is {ipa, ad} periodic task will be stared in sssm_{ipa,ad}_init +If you enable enumeration and use different providers for id and sudo(autofs) +then another periodic task will be scheduled. +This can cause weird behaviour (e.g. missing members of group) + +Perodic tasks will be started only by id_provider. + +Resolves: +https://fedorahosted.org/sssd/ticket/2153 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 057cb583f02bf47678c393cb8f1f74861c2b960b) +--- + src/providers/ldap/ldap_init.c | 54 ++++++++++++++++++++++++++++++++---------- + 1 file changed, 41 insertions(+), 13 deletions(-) + +diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c +index 15615b2891f2e3104c11e8610c081adcd1d1ee8e..cf4ab5598e2b6eb00c188edabb61e22605e7dc82 100644 +--- a/src/providers/ldap/ldap_init.c ++++ b/src/providers/ldap/ldap_init.c +@@ -84,9 +84,9 @@ errno_t check_order_list_for_duplicates(char **list, + return EOK; + } + +-int sssm_ldap_id_init(struct be_ctx *bectx, +- struct bet_ops **ops, +- void **pvt_data) ++static int ldap_id_init_internal(struct be_ctx *bectx, ++ struct bet_ops **ops, ++ void **pvt_data) + { + struct sdap_id_ctx *ctx = NULL; + const char *urls; +@@ -160,11 +160,6 @@ int sssm_ldap_id_init(struct be_ctx *bectx, + ret = sdap_idmap_init(ctx, ctx, &ctx->opts->idmap_ctx); + if (ret != EOK) goto done; + +- ret = ldap_id_setup_tasks(ctx); +- if (ret != EOK) { +- goto done; +- } +- + ret = sdap_setup_child(); + if (ret != EOK) { + DEBUG(1, ("setup_child failed [%d][%s].\n", +@@ -202,6 +197,39 @@ done: + return ret; + } + ++int sssm_ldap_id_init(struct be_ctx *bectx, ++ struct bet_ops **ops, ++ void **pvt_data) ++{ ++ int ret; ++ struct sdap_id_ctx *ctx = NULL; ++ ++ ret = ldap_id_init_internal(bectx, ops, (void **) &ctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ ("ldap_id_init_internal failed [%d][%s].\n", ++ ret, strerror(ret))); ++ goto done; ++ } ++ ++ ret = ldap_id_setup_tasks(ctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ ("sdap_id_setup_tasks failed [%d][%s].\n", ++ ret, strerror(ret))); ++ goto done; ++ } ++ ++ *pvt_data = ctx; ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ talloc_free(ctx); ++ } ++ return ret; ++} ++ + int sssm_ldap_auth_init(struct be_ctx *bectx, + struct bet_ops **ops, + void **pvt_data) +@@ -211,7 +239,7 @@ int sssm_ldap_auth_init(struct be_ctx *bectx, + struct sdap_auth_ctx *ctx; + int ret; + +- ret = sssm_ldap_id_init(bectx, ops, &data); ++ ret = ldap_id_init_internal(bectx, ops, &data); + if (ret == EOK) { + id_ctx = talloc_get_type(data, struct sdap_id_ctx); + +@@ -302,9 +330,9 @@ int sssm_ldap_access_init(struct be_ctx *bectx, + goto done; + } + +- ret = sssm_ldap_id_init(bectx, ops, (void **)&access_ctx->id_ctx); ++ ret = ldap_id_init_internal(bectx, ops, (void **)&access_ctx->id_ctx); + if (ret != EOK) { +- DEBUG(1, ("sssm_ldap_id_init failed.\n")); ++ DEBUG(SSSDBG_CRIT_FAILURE, ("ldap_id_init_internal failed.\n")); + goto done; + } + +@@ -417,7 +445,7 @@ int sssm_ldap_sudo_init(struct be_ctx *be_ctx, + void *data; + int ret; + +- ret = sssm_ldap_id_init(be_ctx, ops, &data); ++ ret = ldap_id_init_internal(be_ctx, ops, &data); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot init LDAP ID provider [%d]: %s\n", + ret, strerror(ret))); +@@ -447,7 +475,7 @@ int sssm_ldap_autofs_init(struct be_ctx *be_ctx, + void *data; + int ret; + +- ret = sssm_ldap_id_init(be_ctx, ops, &data); ++ ret = ldap_id_init_internal(be_ctx, ops, &data); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot init LDAP ID provider [%d]: %s\n", + ret, strerror(ret))); +-- +1.8.5.3 + diff --git a/SOURCES/0092-UTIL-Sanitize-whitespaces.patch b/SOURCES/0092-UTIL-Sanitize-whitespaces.patch new file mode 100644 index 0000000..09cdfa0 --- /dev/null +++ b/SOURCES/0092-UTIL-Sanitize-whitespaces.patch @@ -0,0 +1,43 @@ +From 1c4109bf7f16016cf0b53cd73e7b80e0d87be660 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Mon, 24 Feb 2014 11:37:52 +0100 +Subject: [PATCH 92/92] UTIL: Sanitize whitespaces. + +Original patches submitted by: mpesari(Thanks!!) + +It can cause problems if user will hit spaces before entering username. +(e.g in gdm). Spaces are ignored by LDAP; it's better to escape them. + +Resolves: +https://fedorahosted.org/sssd/ticket/1955 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 2b8208b45feb2aab64d560d3e12e01e7b6d00d39) +--- + src/util/util.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/src/util/util.c b/src/util/util.c +index fb3bed146e2c634375a1133ef512673dee16718a..1ec5c2a9474b0cd2d19a50b495e218d1da7da6c8 100644 +--- a/src/util/util.c ++++ b/src/util/util.c +@@ -537,6 +537,16 @@ errno_t sss_filter_sanitize(TALLOC_CTX *mem_ctx, + + while (input[i]) { + switch(input[i]) { ++ case '\t': ++ output[j++] = '\\'; ++ output[j++] = '0'; ++ output[j++] = '9'; ++ break; ++ case ' ': ++ output[j++] = '\\'; ++ output[j++] = '2'; ++ output[j++] = '0'; ++ break; + case '*': + output[j++] = '\\'; + output[j++] = '2'; +-- +1.8.5.3 + diff --git a/SOURCES/0093-IDMAP-add-sss_idmap_check_collision-_ex.patch b/SOURCES/0093-IDMAP-add-sss_idmap_check_collision-_ex.patch new file mode 100644 index 0000000..fe6caa9 --- /dev/null +++ b/SOURCES/0093-IDMAP-add-sss_idmap_check_collision-_ex.patch @@ -0,0 +1,362 @@ +From 4206e5dbe37277a4002010e85438fe376b5b1812 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 3 Feb 2014 13:30:35 +0100 +Subject: [PATCH 93/97] IDMAP: add sss_idmap_check_collision(_ex) + +--- + src/lib/idmap/sss_idmap.c | 129 ++++++++++++++++++++++++++------------ + src/lib/idmap/sss_idmap.h | 65 +++++++++++++++++++ + src/tests/cmocka/test_sss_idmap.c | 93 +++++++++++++++++++++++++++ + 3 files changed, 247 insertions(+), 40 deletions(-) + +diff --git a/src/lib/idmap/sss_idmap.c b/src/lib/idmap/sss_idmap.c +index 3f1e7a58f390a3c10999251e2155ef513ba69bd7..4c453120539a549807e9b6bb4db2dc396c1b3152 100644 +--- a/src/lib/idmap/sss_idmap.c ++++ b/src/lib/idmap/sss_idmap.c +@@ -380,55 +380,104 @@ enum idmap_error_code sss_idmap_calculate_range(struct sss_idmap_ctx *ctx, + return IDMAP_SUCCESS; + } + ++enum idmap_error_code sss_idmap_check_collision_ex(const char *o_name, ++ const char *o_sid, ++ struct sss_idmap_range *o_range, ++ uint32_t o_first_rid, ++ const char *o_range_id, ++ bool o_external_mapping, ++ const char *n_name, ++ const char *n_sid, ++ struct sss_idmap_range *n_range, ++ uint32_t n_first_rid, ++ const char *n_range_id, ++ bool n_external_mapping) ++{ ++ bool names_equal; ++ bool sids_equal; ++ ++ /* TODO: if both ranges have the same ID check if an update is ++ * needed. */ ++ ++ /* Check if ID ranges overlap. ++ * ID ranges with external mapping may overlap. */ ++ if ((!n_external_mapping && !o_external_mapping) ++ && ((n_range->min >= o_range->min ++ && n_range->min <= o_range->max) ++ || (n_range->max >= o_range->min ++ && n_range->max <= o_range->max))) { ++ return IDMAP_COLLISION; ++ } ++ ++ names_equal = (strcasecmp(n_name, o_name) == 0); ++ sids_equal = ((n_sid == NULL && o_sid == NULL) ++ || (n_sid != NULL && o_sid != NULL ++ && strcasecmp(n_sid, o_sid) == 0)); ++ ++ /* check if domain name and SID are consistent */ ++ if ((names_equal && !sids_equal) || (!names_equal && sids_equal)) { ++ return IDMAP_COLLISION; ++ } ++ ++ /* check if external_mapping is consistent */ ++ if (names_equal && sids_equal ++ && n_external_mapping != o_external_mapping) { ++ return IDMAP_COLLISION; ++ } ++ ++ /* check if RID ranges overlap */ ++ if (names_equal && sids_equal ++ && n_external_mapping == false ++ && n_first_rid >= o_first_rid ++ && n_first_rid <= o_first_rid + (o_range->max - o_range->min)) { ++ return IDMAP_COLLISION; ++ } ++ ++ return IDMAP_SUCCESS; ++} ++ ++enum idmap_error_code sss_idmap_check_collision(struct sss_idmap_ctx *ctx, ++ char *n_name, char *n_sid, ++ struct sss_idmap_range *n_range, ++ uint32_t n_first_rid, ++ char *n_range_id, ++ bool n_external_mapping) ++{ ++ struct idmap_domain_info *dom; ++ enum idmap_error_code err; ++ ++ for (dom = ctx->idmap_domain_info; dom != NULL; dom = dom->next) { ++ err = sss_idmap_check_collision_ex(dom->name, dom->sid, dom->range, ++ dom->first_rid, dom->range_id, ++ dom->external_mapping, ++ n_name, n_sid, n_range, n_first_rid, ++ n_range_id, n_external_mapping); ++ if (err != IDMAP_SUCCESS) { ++ return err; ++ } ++ } ++ return IDMAP_SUCCESS; ++} ++ + static enum idmap_error_code dom_check_collision( + struct idmap_domain_info *dom_list, + struct idmap_domain_info *new_dom) + { + struct idmap_domain_info *dom; +- bool names_equal; +- bool sids_equal; ++ enum idmap_error_code err; + + for (dom = dom_list; dom != NULL; dom = dom->next) { +- +- /* TODO: if both ranges have the same ID check if an update is +- * needed. */ +- +- /* Check if ID ranges overlap. +- * ID ranges with external mapping may overlap. */ +- if ((!new_dom->external_mapping && !dom->external_mapping) +- && ((new_dom->range->min >= dom->range->min +- && new_dom->range->min <= dom->range->max) +- || (new_dom->range->max >= dom->range->min +- && new_dom->range->max <= dom->range->max))) { +- return IDMAP_COLLISION; +- } +- +- names_equal = (strcasecmp(new_dom->name, dom->name) == 0); +- sids_equal = ((new_dom->sid == NULL && dom->sid == NULL) +- || (new_dom->sid != NULL && dom->sid != NULL +- && strcasecmp(new_dom->sid, dom->sid) == 0)); +- +- /* check if domain name and SID are consistent */ +- if ((names_equal && !sids_equal) || (!names_equal && sids_equal)) { +- return IDMAP_COLLISION; +- } +- +- /* check if external_mapping is consistent */ +- if (names_equal && sids_equal +- && new_dom->external_mapping != dom->external_mapping) { +- return IDMAP_COLLISION; +- } +- +- /* check if RID ranges overlap */ +- if (names_equal && sids_equal +- && new_dom->external_mapping == false +- && new_dom->first_rid >= dom->first_rid +- && new_dom->first_rid <= +- dom->first_rid + (dom->range->max - dom->range->min)) { +- return IDMAP_COLLISION; ++ err = sss_idmap_check_collision_ex(dom->name, dom->sid, dom->range, ++ dom->first_rid, dom->range_id, ++ dom->external_mapping, ++ new_dom->name, new_dom->sid, ++ new_dom->range, new_dom->first_rid, ++ new_dom->range_id, ++ new_dom->external_mapping); ++ if (err != IDMAP_SUCCESS) { ++ return err; + } + } +- + return IDMAP_SUCCESS; + } + +diff --git a/src/lib/idmap/sss_idmap.h b/src/lib/idmap/sss_idmap.h +index 1e1c9a5cfe490301d0e633db808589f1bc0ef857..ccc63f7f760b877cdb17696325731f8e540b2736 100644 +--- a/src/lib/idmap/sss_idmap.h ++++ b/src/lib/idmap/sss_idmap.h +@@ -289,6 +289,71 @@ enum idmap_error_code sss_idmap_add_domain_ex(struct sss_idmap_ctx *ctx, + const char *range_id, + uint32_t rid, + bool external_mapping); ++ ++/** ++ * @brief Check if a new range would collide with any existing one ++ * ++ * @param[in] ctx Idmap context ++ * @param[in] n_name Zero-terminated string with the domain name the new ++ * range should belong to ++ * @param[in] n_sid Zero-terminated string representation of the domain ++ * SID (S-1-15-.....) the new range sould belong to ++ * @param[in] n_range The new id range ++ * @param[in] n_range_id unique identifier of the new range, it is needed ++ * to allow updates at runtime, may be NULL ++ * @param[in] n_first_rid The RID that should be mapped to the first ID of the ++ * new range. ++ * @param[in] n_external_mapping Mapping type of the new range ++ * ++ * @return ++ * - #IDMAP_COLLISION: New range collides with existing one ++ */ ++enum idmap_error_code sss_idmap_check_collision(struct sss_idmap_ctx *ctx, ++ char *n_name, char *n_sid, ++ struct sss_idmap_range *n_range, ++ uint32_t n_first_rid, ++ char *n_range_id, ++ bool n_external_mapping); ++ ++/** ++ * @brief Check if two ranges would collide ++ * ++ * @param[in] o_name Zero-terminated string with the domain name the ++ * first range should belong to ++ * @param[in] o_sid Zero-terminated string representation of the domain ++ * SID (S-1-15-.....) the first range sould belong to ++ * @param[in] o_range The first id range ++ * @param[in] o_range_id unique identifier of the first range, it is needed ++ * to allow updates at runtime, may be NULL ++ * @param[in] o_first_rid The RID that should be mapped to the first ID of the ++ * first range. ++ * @param[in] o_external_mapping Mapping type of the first range ++ * @param[in] n_name Zero-terminated string with the domain name the ++ * second range should belong to ++ * @param[in] n_sid Zero-terminated string representation of the domain ++ * SID (S-1-15-.....) the second range sould belong to ++ * @param[in] n_range The second id range ++ * @param[in] n_range_id unique identifier of the second range, it is needed ++ * to allow updates at runtime, may be NULL ++ * @param[in] n_first_rid The RID that should be mapped to the first ID of the ++ * second range. ++ * @param[in] n_external_mapping Mapping type of the second range ++ * ++ * @return ++ * - #IDMAP_COLLISION: New range collides with existing one ++ */ ++enum idmap_error_code sss_idmap_check_collision_ex(const char *o_name, ++ const char *o_sid, ++ struct sss_idmap_range *o_range, ++ uint32_t o_first_rid, ++ const char *o_range_id, ++ bool o_external_mapping, ++ const char *n_name, ++ const char *n_sid, ++ struct sss_idmap_range *n_range, ++ uint32_t n_first_rid, ++ const char *n_range_id, ++ bool n_external_mapping); + /** + * @brief Translate SID to a unix UID or GID + * +diff --git a/src/tests/cmocka/test_sss_idmap.c b/src/tests/cmocka/test_sss_idmap.c +index 019b4618ef0e14e87cb86d64989e8f5ca9dfdfd8..ff933216416b61618bf764d8c2554b273706c787 100644 +--- a/src/tests/cmocka/test_sss_idmap.c ++++ b/src/tests/cmocka/test_sss_idmap.c +@@ -30,11 +30,15 @@ + #define TEST_RANGE_MAX 399999 + #define TEST_DOM_NAME "test.dom" + #define TEST_DOM_SID "S-1-5-21-123-456-789" ++#define TEST_FIRST_RID 0 ++#define TEST_EXT_MAPPING true + + #define TEST_2_RANGE_MIN 600000 + #define TEST_2_RANGE_MAX 799999 + #define TEST_2_DOM_NAME "test2.dom" + #define TEST_2_DOM_SID "S-1-5-21-987-654-321" ++#define TEST_2_FIRST_RID 1000000 ++#define TEST_2_EXT_MAPPING true + + #define TEST_OFFSET 1000000 + #define TEST_OFFSET_STR "1000000" +@@ -408,6 +412,94 @@ void test_has_algorithmic_by_name(void **state) + assert_false(use_id_mapping); + } + ++void test_sss_idmap_check_collision_ex(void **state) ++{ ++ enum idmap_error_code err; ++ struct sss_idmap_range r1 = {TEST_RANGE_MIN, TEST_RANGE_MAX}; ++ struct sss_idmap_range r2 = {TEST_2_RANGE_MIN, TEST_2_RANGE_MAX}; ++ ++ err = sss_idmap_check_collision_ex(TEST_DOM_NAME, TEST_DOM_SID, &r1, ++ TEST_FIRST_RID, NULL, ++ TEST_EXT_MAPPING, ++ TEST_2_DOM_NAME, TEST_2_DOM_SID, &r2, ++ TEST_2_FIRST_RID, NULL, ++ TEST_2_EXT_MAPPING); ++ assert_int_equal(err, IDMAP_SUCCESS); ++ ++ /* Same name, different SID */ ++ err = sss_idmap_check_collision_ex(TEST_DOM_NAME, TEST_DOM_SID, &r1, ++ TEST_FIRST_RID, NULL, ++ TEST_EXT_MAPPING, ++ TEST_DOM_NAME, TEST_2_DOM_SID, &r2, ++ TEST_2_FIRST_RID, NULL, ++ TEST_2_EXT_MAPPING); ++ assert_int_equal(err, IDMAP_COLLISION); ++ ++ /* Same SID, different name */ ++ err = sss_idmap_check_collision_ex(TEST_DOM_NAME, TEST_DOM_SID, &r1, ++ TEST_FIRST_RID, NULL, ++ TEST_EXT_MAPPING, ++ TEST_2_DOM_NAME, TEST_DOM_SID, &r2, ++ TEST_2_FIRST_RID, NULL, ++ TEST_2_EXT_MAPPING); ++ assert_int_equal(err, IDMAP_COLLISION); ++ ++ /* Same SID and name, no overlaps */ ++ err = sss_idmap_check_collision_ex(TEST_DOM_NAME, TEST_DOM_SID, &r1, ++ TEST_FIRST_RID, NULL, ++ TEST_EXT_MAPPING, ++ TEST_DOM_NAME, TEST_DOM_SID, &r2, ++ TEST_2_FIRST_RID, NULL, ++ TEST_2_EXT_MAPPING); ++ assert_int_equal(err, IDMAP_SUCCESS); ++ ++ /* Same SID and name, different mappings */ ++ err = sss_idmap_check_collision_ex(TEST_DOM_NAME, TEST_DOM_SID, &r1, ++ TEST_FIRST_RID, NULL, ++ TEST_EXT_MAPPING, ++ TEST_DOM_NAME, TEST_DOM_SID, &r2, ++ TEST_2_FIRST_RID, NULL, ++ !TEST_EXT_MAPPING); ++ assert_int_equal(err, IDMAP_COLLISION); ++ ++ /* Same SID and name, Overlapping RID range */ ++ err = sss_idmap_check_collision_ex(TEST_DOM_NAME, TEST_DOM_SID, &r1, ++ TEST_FIRST_RID, NULL, ++ false, ++ TEST_DOM_NAME, TEST_DOM_SID, &r2, ++ TEST_FIRST_RID, NULL, ++ false); ++ assert_int_equal(err, IDMAP_COLLISION); ++ ++ /* Different SID and name, Overlapping RID range */ ++ err = sss_idmap_check_collision_ex(TEST_DOM_NAME, TEST_DOM_SID, &r1, ++ TEST_FIRST_RID, NULL, ++ false, ++ TEST_2_DOM_NAME, TEST_2_DOM_SID, &r2, ++ TEST_FIRST_RID, NULL, ++ false); ++ assert_int_equal(err, IDMAP_SUCCESS); ++ ++ ++ /* Overlapping ranges with no external mapping */ ++ err = sss_idmap_check_collision_ex(TEST_DOM_NAME, TEST_DOM_SID, &r1, ++ TEST_FIRST_RID, NULL, ++ false, ++ TEST_2_DOM_NAME, TEST_2_DOM_SID, &r1, ++ TEST_2_FIRST_RID, NULL, ++ false); ++ assert_int_equal(err, IDMAP_COLLISION); ++ ++ /* Overlapping ranges with external mapping */ ++ err = sss_idmap_check_collision_ex(TEST_DOM_NAME, TEST_DOM_SID, &r1, ++ TEST_FIRST_RID, NULL, ++ true, ++ TEST_2_DOM_NAME, TEST_2_DOM_SID, &r1, ++ TEST_2_FIRST_RID, NULL, ++ true); ++ assert_int_equal(err, IDMAP_SUCCESS); ++} ++ + int main(int argc, const char *argv[]) + { + poptContext pc; +@@ -439,6 +531,7 @@ int main(int argc, const char *argv[]) + unit_test_setup_teardown(test_has_algorithmic_by_name, + test_sss_idmap_setup_with_both, + test_sss_idmap_teardown), ++ unit_test(test_sss_idmap_check_collision_ex), + }; + + /* Set debug level to invalid value so we can deside if -d 0 was used. */ +-- +1.8.5.3 + diff --git a/SOURCES/0094-IPA-refactor-idmap-code-and-add-test.patch b/SOURCES/0094-IPA-refactor-idmap-code-and-add-test.patch new file mode 100644 index 0000000..c648a76 --- /dev/null +++ b/SOURCES/0094-IPA-refactor-idmap-code-and-add-test.patch @@ -0,0 +1,630 @@ +From 5ec1d31f32583761c05691c951576b6213037393 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 7 Feb 2014 15:54:30 +0100 +Subject: [PATCH 94/97] IPA: refactor idmap code and add test + +--- + Makefile.am | 15 +++ + src/providers/ipa/ipa_common.h | 10 ++ + src/providers/ipa/ipa_idmap.c | 248 +++++++++++++++---------------------- + src/tests/cmocka/test_ipa_idmap.c | 249 ++++++++++++++++++++++++++++++++++++++ + 4 files changed, 374 insertions(+), 148 deletions(-) + create mode 100644 src/tests/cmocka/test_ipa_idmap.c + +diff --git a/Makefile.am b/Makefile.am +index 16648f9aa2275b60ec84a95ff8a26b1225b97918..2e1a1e6bacfb79e4ef7068a22a64c21d23858cb9 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -150,6 +150,7 @@ if HAVE_CMOCKA + dyndns-tests \ + fqnames-tests \ + test_sss_idmap \ ++ test_ipa_idmap \ + test_utils \ + ad_access_filter_tests \ + ad_common_tests \ +@@ -1359,6 +1360,20 @@ test_sss_idmap_LDADD = \ + $(SSSD_INTERNAL_LTLIBS) \ + libsss_test_common.la + ++test_ipa_idmap_SOURCES = \ ++ src/tests/cmocka/test_ipa_idmap.c \ ++ src/providers/ipa/ipa_idmap.c ++test_ipa_idmap_CFLAGS = \ ++ $(AM_CFLAGS) ++test_ipa_idmap_LDFLAGS = \ ++ -Wl,-wrap,sysdb_get_ranges ++test_ipa_idmap_LDADD = \ ++ $(CMOCKA_LIBS) \ ++ $(POPT_LIBS) \ ++ libsss_idmap.la \ ++ $(SSSD_INTERNAL_LTLIBS) \ ++ libsss_test_common.la ++ + test_utils_SOURCES = \ + src/tests/cmocka/test_utils.c + test_utils_CFLAGS = \ +diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h +index 02f0baf55f0d226eeb8956076b9bbcce285d4a94..0b8a17c532b7b0081dc749dcef1e6c0e684a7ed2 100644 +--- a/src/providers/ipa/ipa_common.h ++++ b/src/providers/ipa/ipa_common.h +@@ -195,6 +195,16 @@ int ipa_sudo_init(struct be_ctx *be_ctx, + struct bet_ops **ops, + void **pvt_data); + ++errno_t get_idmap_data_from_range(struct range_info *r, char *domain_name, ++ char **_name, char **_sid, uint32_t *_rid, ++ struct sss_idmap_range *_range, ++ bool *_external_mapping); ++ ++errno_t ipa_idmap_get_ranges_from_sysdb(struct sdap_idmap_ctx *idmap_ctx, ++ const char *dom_name, ++ const char *dom_sid_str, ++ bool allow_collisions); ++ + errno_t ipa_idmap_init(TALLOC_CTX *mem_ctx, + struct sdap_id_ctx *id_ctx, + struct sdap_idmap_ctx **_idmap_ctx); +diff --git a/src/providers/ipa/ipa_idmap.c b/src/providers/ipa/ipa_idmap.c +index eaca0ed3c3ce2622fbf80dff13d22e2e521f54fe..a65086af4cb4bec7ab85774f3ca1a3555056cee0 100644 +--- a/src/providers/ipa/ipa_idmap.c ++++ b/src/providers/ipa/ipa_idmap.c +@@ -156,9 +156,68 @@ done: + return ret; + } + +-errno_t ipa_idmap_find_new_domain(struct sdap_idmap_ctx *idmap_ctx, +- const char *dom_name, +- const char *dom_sid_str) ++errno_t get_idmap_data_from_range(struct range_info *r, char *domain_name, ++ char **_name, char **_sid, uint32_t *_rid, ++ struct sss_idmap_range *_range, ++ bool *_external_mapping) ++{ ++ if (r->range_type == NULL) { ++ /* Older IPA servers might not have the range_type attribute, but ++ * only support local ranges and trusts with algorithmic mapping. */ ++ ++ if (r->trusted_dom_sid == NULL && r->secondary_base_rid != 0) { ++ /* local IPA domain */ ++ *_rid = 0; ++ *_external_mapping = true; ++ *_name = domain_name; ++ *_sid = NULL; ++ } else if (r->trusted_dom_sid != NULL ++ && r->secondary_base_rid == 0) { ++ /* trusted domain */ ++ *_rid = r->base_rid; ++ *_external_mapping = false; ++ *_name = r->trusted_dom_sid; ++ *_sid = r->trusted_dom_sid; ++ } else { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Cannot determine range type, " \ ++ "for id range [%s].\n", ++ r->name)); ++ return EINVAL; ++ } ++ } else { ++ if (strcmp(r->range_type, IPA_RANGE_LOCAL) == 0) { ++ *_rid = 0; ++ *_external_mapping = true; ++ *_name = domain_name; ++ *_sid = NULL; ++ } else if (strcmp(r->range_type, IPA_RANGE_AD_TRUST_POSIX) == 0) { ++ *_rid = 0; ++ *_external_mapping = true; ++ *_name = r->trusted_dom_sid; ++ *_sid = r->trusted_dom_sid; ++ } else if (strcmp(r->range_type, IPA_RANGE_AD_TRUST) == 0) { ++ *_rid = r->base_rid; ++ *_external_mapping = false; ++ *_name = r->trusted_dom_sid; ++ *_sid = r->trusted_dom_sid; ++ } else { ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Range type [%s] of id range " \ ++ "[%s] not supported.\n", \ ++ r->range_type, r->name)); ++ return EINVAL; ++ } ++ } ++ ++ _range->min = r->base_id; ++ _range->max = r->base_id + r->id_range_size -1; ++ ++ return EOK; ++} ++ ++errno_t ipa_idmap_get_ranges_from_sysdb(struct sdap_idmap_ctx *idmap_ctx, ++ const char *dom_name, ++ const char *dom_sid_str, ++ bool allow_collisions) + { + int ret; + size_t range_count; +@@ -166,7 +225,6 @@ errno_t ipa_idmap_find_new_domain(struct sdap_idmap_ctx *idmap_ctx, + TALLOC_CTX *tmp_ctx; + size_t c; + enum idmap_error_code err; +- struct range_info *r; + struct sss_idmap_range range; + uint32_t rid; + bool external_mapping; +@@ -187,74 +245,39 @@ errno_t ipa_idmap_find_new_domain(struct sdap_idmap_ctx *idmap_ctx, + } + + for (c = 0; c < range_count; c++) { +- r = range_list[c]; +- +- if (r->range_type == NULL) { +- /* Older IPA servers might not have the range_type attribute, but +- * only support local ranges and trusts with algorithmic mapping. */ +- +- if (r->trusted_dom_sid == NULL && r->secondary_base_rid != 0) { +- /* local IPA domain */ +- rid = 0; +- external_mapping = true; +- name = idmap_ctx->id_ctx->be->domain->name; +- sid = NULL; +- } else if (r->trusted_dom_sid != NULL +- && r->secondary_base_rid == 0) { +- /* trusted domain */ +- rid = r->base_rid; +- external_mapping = false; +- name = r->trusted_dom_sid; +- sid = r->trusted_dom_sid; +- } else { +- DEBUG(SSSDBG_MINOR_FAILURE, ("Cannot determine range type, " \ +- "skipping id ange [%s].\n", +- r->name)); +- continue; +- } +- } else { +- if (strcmp(r->range_type, IPA_RANGE_LOCAL) == 0) { +- rid = 0; +- external_mapping = true; +- name = idmap_ctx->id_ctx->be->domain->name; +- sid = NULL; +- } else if (strcmp(r->range_type, IPA_RANGE_AD_TRUST_POSIX) == 0) { +- rid = 0; +- external_mapping = true; +- name = r->trusted_dom_sid; +- sid = r->trusted_dom_sid; +- } else if (strcmp(r->range_type, IPA_RANGE_AD_TRUST) == 0) { +- rid = r->base_rid; +- external_mapping = false; +- name = r->trusted_dom_sid; +- sid = r->trusted_dom_sid; +- } else { +- DEBUG(SSSDBG_MINOR_FAILURE, ("Range type [%s] not supported, " \ +- "skipping id range [%s].\n", +- r->range_type, r->name)); +- continue; +- } ++ ret = get_idmap_data_from_range(range_list[c], ++ idmap_ctx->id_ctx->be->domain->name, ++ &name, &sid, &rid, &range, ++ &external_mapping); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("get_idmap_data_from_range failed for " \ ++ "id range [%s], skipping.\n", ++ range_list[c]->name)); ++ continue; + } + +- range.min = r->base_id; +- range.max = r->base_id + r->id_range_size -1; + err = sss_idmap_add_domain_ex(idmap_ctx->map, name, sid, &range, +- r->name, rid, external_mapping); +- if (err != IDMAP_SUCCESS && err != IDMAP_COLLISION) { +- DEBUG(SSSDBG_CRIT_FAILURE, ("Could not add range [%s] to ID map\n", +- r->name)); +- ret = EIO; ++ range_list[c]->name, rid, ++ external_mapping); ++ if (err != IDMAP_SUCCESS) { ++ if (!allow_collisions || err != IDMAP_COLLISION) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("Could not add range [%s] to ID map\n", ++ range_list[c]->name)); ++ ret = EIO; ++ goto done; ++ } ++ } ++ } ++ ++ if (dom_name != NULL || dom_sid_str != NULL) { ++ ret = ipa_idmap_check_posix_child(idmap_ctx, dom_name, dom_sid_str, ++ range_count, range_list); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("ipa_idmap_check_posix_child failed.\n")); + goto done; + } + } + +- ret = ipa_idmap_check_posix_child(idmap_ctx, dom_name, dom_sid_str, +- range_count, range_list); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, ("ipa_idmap_check_posix_child failed.\n")); +- goto done; +- } +- + ret = EOK; + + done: +@@ -263,6 +286,14 @@ done: + return ret; + } + ++errno_t ipa_idmap_find_new_domain(struct sdap_idmap_ctx *idmap_ctx, ++ const char *dom_name, ++ const char *dom_sid_str) ++{ ++ return ipa_idmap_get_ranges_from_sysdb(idmap_ctx, dom_name, dom_sid_str, ++ true); ++} ++ + errno_t ipa_idmap_init(TALLOC_CTX *mem_ctx, + struct sdap_id_ctx *id_ctx, + struct sdap_idmap_ctx **_idmap_ctx) +@@ -270,17 +301,7 @@ errno_t ipa_idmap_init(TALLOC_CTX *mem_ctx, + errno_t ret; + TALLOC_CTX *tmp_ctx; + enum idmap_error_code err; +- size_t c; + struct sdap_idmap_ctx *idmap_ctx = NULL; +- struct sysdb_ctx *sysdb = id_ctx->be->domain->sysdb; +- size_t range_count; +- struct range_info **range_list; +- struct range_info *r; +- struct sss_idmap_range range; +- uint32_t rid; +- bool external_mapping; +- char *name; +- char *sid; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) return ENOMEM; +@@ -309,82 +330,13 @@ errno_t ipa_idmap_init(TALLOC_CTX *mem_ctx, + goto done; + } + +- +- /* Read in any existing mappings from the cache */ +- ret = sysdb_get_ranges(tmp_ctx, sysdb, &range_count, &range_list); +- if (ret != EOK && ret != ENOENT) { +- DEBUG(SSSDBG_FATAL_FAILURE, +- ("Could not read ranges from the cache: [%s]\n", +- strerror(ret))); ++ ret = ipa_idmap_get_ranges_from_sysdb(idmap_ctx, NULL, NULL, false); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("ipa_idmap_get_ranges_from_sysdb failed.\n")); + goto done; + } + +- DEBUG(SSSDBG_CONF_SETTINGS, +- ("Initializing [%zu] domains for ID-mapping\n", range_count)); +- +- for (c = 0; c < range_count; c++) { +- +- r = range_list[c]; +- +- if (r->range_type == NULL) { +- /* Older IPA servers might not have the range_type attribute, but +- * only support local ranges and trusts with algorithmic mapping. */ +- +- if (r->trusted_dom_sid == NULL && r->secondary_base_rid != 0) { +- /* local IPA domain */ +- rid = 0; +- external_mapping = true; +- sid = NULL; +- name = id_ctx->be->domain->name; +- } else if (r->trusted_dom_sid != NULL +- && r->secondary_base_rid == 0) { +- /* trusted domain */ +- rid = r->base_rid; +- external_mapping = false; +- sid = r->trusted_dom_sid; +- name = sid; +- } else { +- DEBUG(SSSDBG_MINOR_FAILURE, ("Cannot determine range type, " \ +- "skipping id ange [%s].\n", +- r->name)); +- continue; +- } +- } else { +- if (strcmp(r->range_type, IPA_RANGE_LOCAL) == 0) { +- rid = 0; +- external_mapping = true; +- sid = NULL; +- name = id_ctx->be->domain->name; +- } else if (strcmp(r->range_type, IPA_RANGE_AD_TRUST_POSIX) == 0) { +- rid = 0; +- external_mapping = true; +- sid = r->trusted_dom_sid; +- name = sid; +- } else if (strcmp(r->range_type, IPA_RANGE_AD_TRUST) == 0) { +- rid = r->base_rid; +- external_mapping = false; +- sid = r->trusted_dom_sid; +- name = sid; +- } else { +- DEBUG(SSSDBG_MINOR_FAILURE, ("Range type [%s] not supported, " \ +- "skipping id range [%s].\n", +- r->range_type, r->name)); +- continue; +- } +- } +- +- range.min = r->base_id; +- range.max = r->base_id + r->id_range_size -1; +- err = sss_idmap_add_domain_ex(idmap_ctx->map, name, sid, &range, +- r->name, rid, external_mapping); +- if (err != IDMAP_SUCCESS) { +- DEBUG(SSSDBG_CRIT_FAILURE, ("Could not add range [%s] to ID map\n", +- r->name)); +- ret = EIO; +- goto done; +- } +- } +- + *_idmap_ctx = talloc_steal(mem_ctx, idmap_ctx); + ret = EOK; + +diff --git a/src/tests/cmocka/test_ipa_idmap.c b/src/tests/cmocka/test_ipa_idmap.c +new file mode 100644 +index 0000000000000000000000000000000000000000..2fb2cde2f9a7f1172fb69b268d19b559ff9d2f32 +--- /dev/null ++++ b/src/tests/cmocka/test_ipa_idmap.c +@@ -0,0 +1,249 @@ ++/* ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) 2014 Red Hat ++ ++ SSSD tests: Unit tests for id-mapping in the IPA provider ++ ++ 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 "tests/cmocka/common_mock.h" ++#include "lib/idmap/sss_idmap.h" ++#include "providers/ipa/ipa_common.h" ++#include "providers/ldap/sdap_idmap.h" ++ ++#define RANGE_NAME discard_const("range1") ++#define DOMAIN_SID discard_const("S-1-5-21-2-3-4") ++#define DOMAIN_NAME discard_const("dom.test") ++#define BASE_RID 111 ++#define SECONDARY_BASE_RID 11223344 ++#define BASE_ID 123456 ++#define RANGE_SIZE 222222 ++#define RANGE_MAX (BASE_ID + RANGE_SIZE - 1) ++ ++void test_get_idmap_data_from_range(void **state) ++{ ++ char *dom_name; ++ char *sid; ++ uint32_t rid; ++ struct sss_idmap_range range; ++ bool external_mapping; ++ size_t c; ++ errno_t ret; ++ ++ struct test_data { ++ struct range_info r; ++ errno_t exp_ret; ++ char *exp_dom_name; ++ char *exp_sid; ++ uint32_t exp_rid; ++ struct sss_idmap_range exp_range; ++ bool exp_external_mapping; ++ } d[] = { ++ /* working IPA_RANGE_LOCAL range */ ++ {{RANGE_NAME, BASE_ID, RANGE_SIZE, BASE_RID, SECONDARY_BASE_RID, ++ NULL, discard_const(IPA_RANGE_LOCAL)}, ++ EOK, DOMAIN_NAME, NULL, 0, {BASE_ID, RANGE_MAX}, true}, ++ /* working old-style IPA_RANGE_LOCAL range without range type */ ++ {{RANGE_NAME, BASE_ID, RANGE_SIZE, BASE_RID, SECONDARY_BASE_RID, ++ NULL, NULL}, ++ EOK, DOMAIN_NAME, NULL, 0, {BASE_ID, RANGE_MAX}, true}, ++ /* old-style IPA_RANGE_LOCAL without SID and secondary base rid */ ++ {{RANGE_NAME, BASE_ID, RANGE_SIZE, BASE_RID, 0, NULL, NULL}, ++ EINVAL, NULL, NULL, 0, {0, 0}, false}, ++ /* old-style range with SID and secondary base rid */ ++ {{RANGE_NAME, BASE_ID, RANGE_SIZE, BASE_RID, SECONDARY_BASE_RID, ++ DOMAIN_SID, NULL}, ++ EINVAL, NULL, NULL, 0, {0, 0}, false}, ++ /* working IPA_RANGE_AD_TRUST range */ ++ {{RANGE_NAME, BASE_ID, RANGE_SIZE, BASE_RID, 0, DOMAIN_SID, ++ discard_const(IPA_RANGE_AD_TRUST)}, ++ EOK, DOMAIN_SID, DOMAIN_SID, BASE_RID, {BASE_ID, RANGE_MAX}, false}, ++ /* working old-style IPA_RANGE_AD_TRUST range without range type */ ++ {{RANGE_NAME, BASE_ID, RANGE_SIZE, BASE_RID, 0, DOMAIN_SID, NULL}, ++ EOK, DOMAIN_SID, DOMAIN_SID, BASE_RID, {BASE_ID, RANGE_MAX}, false}, ++ /* working IPA_RANGE_AD_TRUST_POSIX range */ ++ {{RANGE_NAME, BASE_ID, RANGE_SIZE, BASE_RID, 0, DOMAIN_SID, ++ discard_const(IPA_RANGE_AD_TRUST_POSIX)}, ++ EOK, DOMAIN_SID, DOMAIN_SID, 0, {BASE_ID, RANGE_MAX}, true}, ++ {{0}, 0, NULL, NULL, 0, {0, 0}, false} ++ }; ++ ++ for (c = 0; d[c].exp_dom_name != NULL; c++) { ++ ret = get_idmap_data_from_range(&d[c].r, DOMAIN_NAME, &dom_name, &sid, ++ &rid, &range, &external_mapping); ++ assert_int_equal(ret, d[c].exp_ret); ++ assert_string_equal(dom_name, d[c].exp_dom_name); ++ if (d[c].exp_sid == NULL) { ++ assert_null(sid); ++ } else { ++ assert_string_equal(sid, d[c].exp_sid); ++ } ++ assert_int_equal(rid, d[c].exp_rid); ++ assert_int_equal(range.min, d[c].exp_range.min); ++ assert_int_equal(range.max, d[c].exp_range.max); ++ assert_true(external_mapping == d[c].exp_external_mapping); ++ } ++} ++ ++errno_t __wrap_sysdb_get_ranges(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, ++ size_t *range_count, ++ struct range_info ***range_list) ++{ ++ ++ *range_count = sss_mock_type(size_t); ++ *range_list = talloc_steal(mem_ctx, ++ sss_mock_ptr_type(struct range_info **)); ++ return EOK; ++} ++ ++struct test_ctx { ++ struct sdap_idmap_ctx *idmap_ctx; ++ struct sdap_id_ctx *sdap_id_ctx; ++}; ++ ++static struct range_info **get_range_list(TALLOC_CTX *mem_ctx) ++{ ++ struct range_info **range_list; ++ ++ range_list = talloc_array(mem_ctx, struct range_info *, 2); ++ assert_non_null(range_list); ++ ++ range_list[0] = talloc_zero(range_list, struct range_info); ++ assert_non_null(range_list[0]); ++ ++ range_list[0]->name = talloc_strdup(range_list[0], RANGE_NAME); ++ assert_non_null( range_list[0]->name); ++ range_list[0]->base_id = BASE_ID; ++ range_list[0]->id_range_size = RANGE_SIZE; ++ range_list[0]->base_rid = BASE_RID; ++ range_list[0]->secondary_base_rid = 0; ++ range_list[0]->trusted_dom_sid = talloc_strdup(range_list[0], DOMAIN_SID); ++ assert_non_null(range_list[0]->trusted_dom_sid); ++ range_list[0]->range_type = talloc_strdup(range_list[0], ++ IPA_RANGE_AD_TRUST); ++ assert_non_null(range_list[0]->range_type); ++ ++ return range_list; ++} ++ ++void setup_idmap_ctx(void **state) ++{ ++ int ret; ++ struct test_ctx *test_ctx; ++ ++ assert_true(leak_check_setup()); ++ ++ test_ctx = talloc_zero(global_talloc_context, struct test_ctx); ++ assert_non_null(test_ctx); ++ ++ test_ctx->sdap_id_ctx = talloc_zero(test_ctx, ++ struct sdap_id_ctx); ++ assert_non_null(test_ctx->sdap_id_ctx); ++ ++ test_ctx->sdap_id_ctx->be = talloc_zero(test_ctx->sdap_id_ctx, ++ struct be_ctx); ++ assert_non_null(test_ctx->sdap_id_ctx->be); ++ ++ test_ctx->sdap_id_ctx->be->domain = talloc_zero(test_ctx->sdap_id_ctx->be, ++ struct sss_domain_info); ++ assert_non_null(test_ctx->sdap_id_ctx->be->domain); ++ ++ test_ctx->sdap_id_ctx->be->domain->name = ++ talloc_strdup(test_ctx->sdap_id_ctx->be->domain, DOMAIN_NAME); ++ assert_non_null(test_ctx->sdap_id_ctx->be->domain->name); ++ ++ will_return(__wrap_sysdb_get_ranges, 1); ++ will_return(__wrap_sysdb_get_ranges, get_range_list(global_talloc_context)); ++ ++ ret = ipa_idmap_init(test_ctx, test_ctx->sdap_id_ctx, ++ &test_ctx->idmap_ctx); ++ assert_int_equal(ret, EOK); ++ ++ check_leaks_push(test_ctx); ++ *state = test_ctx; ++} ++ ++void teardown_idmap_ctx(void **state) ++{ ++ struct test_ctx *test_ctx = talloc_get_type(*state, struct test_ctx); ++ ++ assert_non_null(test_ctx); ++ ++ assert_true(check_leaks_pop(test_ctx) == true); ++ ++ talloc_free(test_ctx); ++ assert_true(leak_check_teardown()); ++} ++ ++void test_ipa_idmap_get_ranges_from_sysdb(void **state) ++{ ++ int ret; ++ struct test_ctx *test_ctx = talloc_get_type(*state, struct test_ctx); ++ assert_non_null(test_ctx); ++ ++ will_return(__wrap_sysdb_get_ranges, 1); ++ will_return(__wrap_sysdb_get_ranges, get_range_list(test_ctx->idmap_ctx)); ++ ret = ipa_idmap_get_ranges_from_sysdb(test_ctx->idmap_ctx, ++ DOMAIN_NAME, DOMAIN_SID, true); ++ assert_int_equal(ret, EOK); ++ ++ will_return(__wrap_sysdb_get_ranges, 1); ++ will_return(__wrap_sysdb_get_ranges, get_range_list(global_talloc_context)); ++ ret = ipa_idmap_get_ranges_from_sysdb(test_ctx->idmap_ctx, ++ DOMAIN_NAME, DOMAIN_SID, false); ++ assert_int_equal(ret, EIO); ++} ++ ++int main(int argc, const char *argv[]) ++{ ++ poptContext pc; ++ int opt; ++ struct poptOption long_options[] = { ++ POPT_AUTOHELP ++ SSSD_DEBUG_OPTS ++ POPT_TABLEEND ++ }; ++ ++ const UnitTest tests[] = { ++ unit_test(test_get_idmap_data_from_range), ++ unit_test_setup_teardown(test_ipa_idmap_get_ranges_from_sysdb, ++ setup_idmap_ctx, teardown_idmap_ctx), ++ }; ++ ++ /* 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_INIT(debug_level); ++ ++ tests_set_cwd(); ++ ++ return run_tests(tests); ++} +-- +1.8.5.3 + diff --git a/SOURCES/0095-IPA-check-ranges-for-collisions-before-saving-them.patch b/SOURCES/0095-IPA-check-ranges-for-collisions-before-saving-them.patch new file mode 100644 index 0000000..b083bfd --- /dev/null +++ b/SOURCES/0095-IPA-check-ranges-for-collisions-before-saving-them.patch @@ -0,0 +1,193 @@ +From 841fef45aef0a1424d4afbf3ea2bb40566155af9 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 7 Feb 2014 18:17:09 +0100 +Subject: [PATCH 95/97] IPA: check ranges for collisions before saving them + +Fixes https://fedorahosted.org/sssd/ticket/2253 +--- + src/providers/ipa/ipa_subdomains.c | 83 +++++++++++++++++++++++++++++--------- + 1 file changed, 63 insertions(+), 20 deletions(-) + +diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c +index 88b6ba52538be83417e98c9a5dd033bea87ebe4b..07ae03b6ab0325b011a26f36f4fdc9a5766b8445 100644 +--- a/src/providers/ipa/ipa_subdomains.c ++++ b/src/providers/ipa/ipa_subdomains.c +@@ -351,14 +351,28 @@ const char *get_flat_name_from_subdomain_name(struct be_ctx *be_ctx, + } + + static errno_t ipa_ranges_parse_results(TALLOC_CTX *mem_ctx, ++ char *domain_name, + size_t count, + struct sysdb_attrs **reply, + struct range_info ***_range_list) + { + struct range_info **range_list = NULL; ++ struct range_info *r; + const char *value; + size_t c; ++ size_t d; + int ret; ++ enum idmap_error_code err; ++ char *name1; ++ char *name2; ++ char *sid1; ++ char *sid2; ++ uint32_t rid1; ++ uint32_t rid2; ++ struct sss_idmap_range range1; ++ struct sss_idmap_range range2; ++ bool mapping1; ++ bool mapping2; + + range_list = talloc_array(mem_ctx, struct range_info *, count + 1); + if (range_list == NULL) { +@@ -367,8 +381,8 @@ static errno_t ipa_ranges_parse_results(TALLOC_CTX *mem_ctx, + } + + for (c = 0; c < count; c++) { +- range_list[c] = talloc_zero(range_list, struct range_info); +- if (range_list[c] == NULL) { ++ r = talloc_zero(range_list, struct range_info); ++ if (r == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("talloc_zero failed.\n")); + ret = ENOMEM; + goto done; +@@ -379,8 +393,8 @@ static errno_t ipa_ranges_parse_results(TALLOC_CTX *mem_ctx, + DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n")); + goto done; + } +- range_list[c]->name = talloc_strdup(range_list[c], value); +- if (range_list[c]->name == NULL) { ++ r->name = talloc_strdup(r, value); ++ if (r->name == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n")); + ret = ENOMEM; + goto done; +@@ -388,9 +402,8 @@ static errno_t ipa_ranges_parse_results(TALLOC_CTX *mem_ctx, + + ret = sysdb_attrs_get_string(reply[c], IPA_TRUSTED_DOMAIN_SID, &value); + if (ret == EOK) { +- range_list[c]->trusted_dom_sid = talloc_strdup(range_list[c], +- value); +- if (range_list[c]->trusted_dom_sid == NULL) { ++ r->trusted_dom_sid = talloc_strdup(r, value); ++ if (r->trusted_dom_sid == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n")); + ret = ENOMEM; + goto done; +@@ -401,28 +414,28 @@ static errno_t ipa_ranges_parse_results(TALLOC_CTX *mem_ctx, + } + + ret = sysdb_attrs_get_uint32_t(reply[c], IPA_BASE_ID, +- &range_list[c]->base_id); ++ &r->base_id); + if (ret != EOK && ret != ENOENT) { + DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n")); + goto done; + } + + ret = sysdb_attrs_get_uint32_t(reply[c], IPA_ID_RANGE_SIZE, +- &range_list[c]->id_range_size); ++ &r->id_range_size); + if (ret != EOK && ret != ENOENT) { + DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n")); + goto done; + } + + ret = sysdb_attrs_get_uint32_t(reply[c], IPA_BASE_RID, +- &range_list[c]->base_rid); ++ &r->base_rid); + if (ret != EOK && ret != ENOENT) { + DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n")); + goto done; + } + + ret = sysdb_attrs_get_uint32_t(reply[c], IPA_SECONDARY_BASE_RID, +- &range_list[c]->secondary_base_rid); ++ &r->secondary_base_rid); + if (ret != EOK && ret != ENOENT) { + DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n")); + goto done; +@@ -430,8 +443,8 @@ static errno_t ipa_ranges_parse_results(TALLOC_CTX *mem_ctx, + + ret = sysdb_attrs_get_string(reply[c], IPA_RANGE_TYPE, &value); + if (ret == EOK) { +- range_list[c]->range_type = talloc_strdup(range_list[c], value); +- if (range_list[c]->range_type == NULL) { ++ r->range_type = talloc_strdup(r, value); ++ if (r->range_type == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n")); + ret = ENOMEM; + goto done; +@@ -439,23 +452,52 @@ static errno_t ipa_ranges_parse_results(TALLOC_CTX *mem_ctx, + } else if (ret == ENOENT) { + /* Older IPA servers might not have the range_type attribute, but + * only support local ranges and trusts with algorithmic mapping. */ +- if (range_list[c]->trusted_dom_sid == NULL) { +- range_list[c]->range_type = talloc_strdup(range_list[c], +- IPA_RANGE_LOCAL); ++ if (r->trusted_dom_sid == NULL) { ++ r->range_type = talloc_strdup(r, IPA_RANGE_LOCAL); + } else { +- range_list[c]->range_type = talloc_strdup(range_list[c], +- IPA_RANGE_AD_TRUST); ++ r->range_type = talloc_strdup(r, IPA_RANGE_AD_TRUST); + } + } else { + DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n")); + goto done; + } +- if (range_list[c]->range_type == NULL) { ++ if (r->range_type == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("talloc_strdup failed.\n")); + ret = ENOMEM; + goto done; + } ++ ++ ret = get_idmap_data_from_range(r, domain_name, &name1, &sid1, &rid1, ++ &range1, &mapping1); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("get_idmap_data_from_range failed.\n")); ++ goto done; ++ } ++ for (d = 0; d < c; d++) { ++ ret = get_idmap_data_from_range(range_list[d], domain_name, &name2, ++ &sid2, &rid2, &range2, &mapping2); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("get_idmap_data_from_range failed.\n")); ++ goto done; ++ } ++ ++ err = sss_idmap_check_collision_ex(name1, sid1, &range1, rid1, ++ r->name, mapping1, ++ name2, sid2, &range2, rid2, ++ range_list[d]->name, mapping2); ++ if (err != IDMAP_SUCCESS) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ ("Collision of ranges [%s] and [%s] detected.\n", ++ r->name, range_list[d]->name)); ++ ret = EINVAL; ++ goto done; ++ } ++ } ++ ++ range_list[c] = r; + } ++ + range_list[c] = NULL; + + *_range_list = range_list; +@@ -1013,7 +1055,8 @@ static void ipa_subdomains_handler_ranges_done(struct tevent_req *req) + goto done; + } + +- ret = ipa_ranges_parse_results(ctx, reply_count, reply, &range_list); ++ ret = ipa_ranges_parse_results(ctx, domain->name, ++ reply_count, reply, &range_list); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + ("ipa_ranges_parse_results request failed.\n")); +-- +1.8.5.3 + diff --git a/SOURCES/0096-OPTS-Allow-using-defaults-for-blobs.patch b/SOURCES/0096-OPTS-Allow-using-defaults-for-blobs.patch new file mode 100644 index 0000000..ac6b578 --- /dev/null +++ b/SOURCES/0096-OPTS-Allow-using-defaults-for-blobs.patch @@ -0,0 +1,31 @@ +From 2f08218f0eb6e069c94401ac439d5d7f5b032564 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 24 Feb 2014 15:42:15 +0100 +Subject: [PATCH 96/97] OPTS: Allow using defaults for blobs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Pavel Březina +(cherry picked from commit ddd21d5dc3c89712d9286d1f66f4b2af73651cf2) +--- + src/providers/data_provider_opts.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/providers/data_provider_opts.c b/src/providers/data_provider_opts.c +index 0edadecc12d2e354c590df9d3ed011cb4e44eee0..5a2e3b74da7d4af4326a56a9cd47b7826e4b78e3 100644 +--- a/src/providers/data_provider_opts.c ++++ b/src/providers/data_provider_opts.c +@@ -78,6 +78,9 @@ int dp_get_options(TALLOC_CTX *memctx, + if (tmp) { + opts[i].val.blob.data = (uint8_t *)tmp; + opts[i].val.blob.length = strlen(tmp); ++ } else if (opts[i].def_val.blob.data != NULL) { ++ opts[i].val.blob.data = opts[i].def_val.blob.data; ++ opts[i].val.blob.length = opts[i].def_val.blob.length; + } else { + opts[i].val.blob.data = NULL; + opts[i].val.blob.length = 0; +-- +1.8.5.3 + diff --git a/SOURCES/0097-DP-Provide-separate-dp_copy_defaults-function.patch b/SOURCES/0097-DP-Provide-separate-dp_copy_defaults-function.patch new file mode 100644 index 0000000..4ef2599 --- /dev/null +++ b/SOURCES/0097-DP-Provide-separate-dp_copy_defaults-function.patch @@ -0,0 +1,637 @@ +From cb5090d6da0e0b378b095b151af70fa21cd62e9e Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 24 Feb 2014 15:42:51 +0100 +Subject: [PATCH 97/97] DP: Provide separate dp_copy_defaults function +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +https://fedorahosted.org/sssd/ticket/2257 + +Reviewed-by: Pavel Březina +(cherry picked from commit 90afedb00608547ae1f32aa7aafd552c4b306909) +--- + Makefile.am | 12 ++ + src/providers/ad/ad_common.c | 16 +- + src/providers/data_provider.h | 5 + + src/providers/data_provider_opts.c | 42 ++-- + src/tests/cmocka/test_dp_opts.c | 421 +++++++++++++++++++++++++++++++++++++ + src/tests/ipa_ldap_opt-tests.c | 2 +- + 6 files changed, 476 insertions(+), 22 deletions(-) + create mode 100644 src/tests/cmocka/test_dp_opts.c + +diff --git a/Makefile.am b/Makefile.am +index 2e1a1e6bacfb79e4ef7068a22a64c21d23858cb9..9025ec6a5bfa16408278506fdd573666b4b6dbe5 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -154,6 +154,7 @@ if HAVE_CMOCKA + test_utils \ + ad_access_filter_tests \ + ad_common_tests \ ++ dp_opt_tests \ + test_search_bases + endif + +@@ -1459,6 +1460,17 @@ ad_common_tests_LDADD = \ + libsss_krb5_common.la \ + libsss_test_common.la + ++dp_opt_tests_SOURCES = \ ++ src/providers/data_provider_opts.c \ ++ src/tests/cmocka/test_dp_opts.c ++dp_opt_tests_CFLAGS = \ ++ $(AM_CFLAGS) ++dp_opt_tests_LDADD = \ ++ $(CMOCKA_LIBS) \ ++ $(TALLOC_LIBS) \ ++ $(SSSD_INTERNAL_LTLIBS) \ ++ libsss_test_common.la ++ + endif + + noinst_PROGRAMS = pam_test_client +diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c +index 99fa4c07af2a79bb3ca195214ddb0dbd60c61620..605de49f7f7ae910cbc78e38f888600ba78a0c4f 100644 +--- a/src/providers/ad/ad_common.c ++++ b/src/providers/ad/ad_common.c +@@ -44,10 +44,10 @@ ad_create_default_sdap_options(TALLOC_CTX *mem_ctx) + return NULL; + } + +- ret = dp_copy_options(id_opts, +- ad_def_ldap_opts, +- SDAP_OPTS_BASIC, +- &id_opts->basic); ++ ret = dp_copy_defaults(id_opts, ++ ad_def_ldap_opts, ++ SDAP_OPTS_BASIC, ++ &id_opts->basic); + if (ret != EOK) { + goto fail; + } +@@ -117,10 +117,10 @@ ad_create_default_options(TALLOC_CTX *mem_ctx, + ad_options = talloc_zero(mem_ctx, struct ad_options); + if (ad_options == NULL) return NULL; + +- ret = dp_copy_options(ad_options, +- ad_basic_opts, +- AD_OPTS_BASIC, +- &ad_options->basic); ++ ret = dp_copy_defaults(ad_options, ++ ad_basic_opts, ++ AD_OPTS_BASIC, ++ &ad_options->basic); + if (ret != EOK) { + talloc_free(ad_options); + return NULL; +diff --git a/src/providers/data_provider.h b/src/providers/data_provider.h +index d086d5d2f368578c6a44a2c3b33738c894feba95..d86ff58e65c7ae35f7269fdd10ed78f529ed8d8c 100644 +--- a/src/providers/data_provider.h ++++ b/src/providers/data_provider.h +@@ -295,6 +295,11 @@ int dp_copy_options(TALLOC_CTX *memctx, + int num_opts, + struct dp_option **_opts); + ++int dp_copy_defaults(TALLOC_CTX *memctx, ++ struct dp_option *src_opts, ++ int num_opts, ++ struct dp_option **_opts); ++ + const char *_dp_opt_get_cstring(struct dp_option *opts, + int id, const char *location); + char *_dp_opt_get_string(struct dp_option *opts, +diff --git a/src/providers/data_provider_opts.c b/src/providers/data_provider_opts.c +index 5a2e3b74da7d4af4326a56a9cd47b7826e4b78e3..0cc48e46e8bbba487aea15b4ad1044e8ddc0482a 100644 +--- a/src/providers/data_provider_opts.c ++++ b/src/providers/data_provider_opts.c +@@ -131,11 +131,11 @@ done: + } + + /* =Basic-Option-Helpers================================================== */ +- +-int dp_copy_options(TALLOC_CTX *memctx, +- struct dp_option *src_opts, +- int num_opts, +- struct dp_option **_opts) ++static int dp_copy_options_ex(TALLOC_CTX *memctx, ++ bool copy_values, ++ struct dp_option *src_opts, ++ int num_opts, ++ struct dp_option **_opts) + { + struct dp_option *opts; + int i, ret = EOK; +@@ -151,9 +151,9 @@ int dp_copy_options(TALLOC_CTX *memctx, + + switch (src_opts[i].type) { + case DP_OPT_STRING: +- if (src_opts[i].val.string) { ++ if (copy_values) { + ret = dp_opt_set_string(opts, i, src_opts[i].val.string); +- } else if (src_opts[i].def_val.string) { ++ } else { + ret = dp_opt_set_string(opts, i, src_opts[i].def_val.string); + } + if (ret != EOK) { +@@ -169,9 +169,9 @@ int dp_copy_options(TALLOC_CTX *memctx, + break; + + case DP_OPT_BLOB: +- if (src_opts[i].val.blob.data) { ++ if (copy_values) { + ret = dp_opt_set_blob(opts, i, src_opts[i].val.blob); +- } else if (src_opts[i].def_val.blob.data) { ++ } else { + ret = dp_opt_set_blob(opts, i, src_opts[i].def_val.blob); + } + if (ret != EOK) { +@@ -185,9 +185,9 @@ int dp_copy_options(TALLOC_CTX *memctx, + break; + + case DP_OPT_NUMBER: +- if (src_opts[i].val.number) { ++ if (copy_values) { + ret = dp_opt_set_int(opts, i, src_opts[i].val.number); +- } else if (src_opts[i].def_val.number) { ++ } else { + ret = dp_opt_set_int(opts, i, src_opts[i].def_val.number); + } + if (ret != EOK) { +@@ -201,9 +201,9 @@ int dp_copy_options(TALLOC_CTX *memctx, + break; + + case DP_OPT_BOOL: +- if (src_opts[i].val.boolean) { ++ if (copy_values) { + ret = dp_opt_set_bool(opts, i, src_opts[i].val.boolean); +- } else if (src_opts[i].def_val.boolean) { ++ } else { + ret = dp_opt_set_bool(opts, i, src_opts[i].def_val.boolean); + } + if (ret != EOK) { +@@ -225,6 +225,22 @@ done: + return ret; + } + ++int dp_copy_options(TALLOC_CTX *memctx, ++ struct dp_option *src_opts, ++ int num_opts, ++ struct dp_option **_opts) ++{ ++ return dp_copy_options_ex(memctx, true, src_opts, num_opts, _opts); ++} ++ ++int dp_copy_defaults(TALLOC_CTX *memctx, ++ struct dp_option *src_opts, ++ int num_opts, ++ struct dp_option **_opts) ++{ ++ return dp_copy_options_ex(memctx, false, src_opts, num_opts, _opts); ++} ++ + static const char *dp_opt_type_to_string(enum dp_opt_type type) + { + switch (type) { +diff --git a/src/tests/cmocka/test_dp_opts.c b/src/tests/cmocka/test_dp_opts.c +new file mode 100644 +index 0000000000000000000000000000000000000000..07998b4034fb33195c99340e5544596925ecf145 +--- /dev/null ++++ b/src/tests/cmocka/test_dp_opts.c +@@ -0,0 +1,421 @@ ++/* ++ Authors: ++ Jakub Hrozek ++ ++ Copyright (C) 2014 Red Hat ++ ++ SSSD tests: Data Provider Option Tests ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#include ++ ++#include "providers/data_provider.h" ++ ++#include "tests/cmocka/common_mock.h" ++ ++#define STRING_DEFAULT "stringval" ++#define BLOB_DEFAULT "blobval" ++#define INT_DEFAULT 123 ++ ++#define TESTS_PATH "tests_opts" ++#define TEST_CONF_DB "test_opt_conf.ldb" ++#define TEST_SYSDB_FILE "cache_opt_test.ldb" ++#define TEST_DOM_NAME "opt_test" ++#define TEST_ID_PROVIDER "ldap" ++ ++enum test_opts { ++ OPT_STRING_NODEFAULT, ++ OPT_STRING_DEFAULT, ++ OPT_BLOB_NODEFAULT, ++ OPT_BLOB_DEFAULT, ++ OPT_INT_NODEFAULT, ++ OPT_INT_DEFAULT, ++ OPT_BOOL_TRUE, ++ OPT_BOOL_FALSE, ++ ++ OPT_NUM_OPTS ++}; ++ ++struct dp_option test_def_opts[] = { ++ { "string_nodefault", DP_OPT_STRING, NULL_STRING, NULL_STRING }, ++ { "string_default", DP_OPT_STRING, { STRING_DEFAULT }, NULL_STRING}, ++ { "blob_nodefault", DP_OPT_BLOB, NULL_BLOB, NULL_BLOB }, ++ { "blob_default", DP_OPT_BLOB, ++ { .blob = { discard_const(BLOB_DEFAULT), ++ sizeof(BLOB_DEFAULT) - 1 } }, ++ NULL_BLOB }, ++ { "int_nodefault", DP_OPT_NUMBER, NULL_NUMBER, NULL_NUMBER }, ++ { "int_default", DP_OPT_NUMBER, { .number = INT_DEFAULT }, NULL_NUMBER }, ++ { "bool_true", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE }, ++ { "bool_false", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }, ++ DP_OPTION_TERMINATOR ++}; ++ ++static void assert_defaults(struct dp_option *opts) ++{ ++ char *s; ++ struct dp_opt_blob b; ++ int i; ++ bool bo; ++ ++ s = dp_opt_get_string(opts, OPT_STRING_NODEFAULT); ++ assert_null(s); ++ ++ s = dp_opt_get_string(opts, OPT_STRING_DEFAULT); ++ assert_non_null(s); ++ assert_string_equal(s, STRING_DEFAULT); ++ ++ b = dp_opt_get_blob(opts, OPT_BLOB_NODEFAULT); ++ assert_null(b.data); ++ assert_int_equal(b.length, 0); ++ ++ b = dp_opt_get_blob(opts, OPT_BLOB_DEFAULT); ++ assert_non_null(b.data); ++ assert_int_equal(b.length, strlen(BLOB_DEFAULT)); ++ assert_memory_equal(b.data, BLOB_DEFAULT, strlen(BLOB_DEFAULT)); ++ ++ i = dp_opt_get_int(opts, OPT_INT_NODEFAULT); ++ assert_int_equal(i, 0); ++ ++ i = dp_opt_get_int(opts, OPT_INT_DEFAULT); ++ assert_int_equal(i, INT_DEFAULT); ++ ++ bo = dp_opt_get_bool(opts, OPT_BOOL_TRUE); ++ assert_true(bo == true); ++ ++ bo = dp_opt_get_bool(opts, OPT_BOOL_FALSE); ++ assert_true(bo == false); ++} ++ ++void opt_test_copy_default(void **state) ++{ ++ int ret; ++ TALLOC_CTX *mem_ctx; ++ struct dp_option *opts; ++ struct dp_opt_blob b; ++ ++ mem_ctx = talloc_new(global_talloc_context); ++ assert_non_null(mem_ctx); ++ ++ ret = dp_copy_defaults(mem_ctx, test_def_opts, OPT_NUM_OPTS, &opts); ++ assert_int_equal(ret, EOK); ++ assert_defaults(opts); ++ ++ /* Test that copy_defaults would still copy defaults even if we ++ * change the values ++ */ ++ ret = dp_opt_set_string(opts, OPT_STRING_NODEFAULT, "str1"); ++ assert_int_equal(ret, EOK); ++ ret = dp_opt_set_string(opts, OPT_STRING_DEFAULT, "str2"); ++ assert_int_equal(ret, EOK); ++ ++ b.data = discard_const_p(uint8_t, "blob1"); ++ b.length = strlen("blob1"); ++ ret = dp_opt_set_blob(opts, OPT_BLOB_NODEFAULT, b); ++ assert_int_equal(ret, EOK); ++ ++ ret = dp_opt_set_blob(opts, OPT_BLOB_DEFAULT, b); ++ b.data = discard_const_p(uint8_t, "blob2"); ++ b.length = strlen("blob2"); ++ assert_int_equal(ret, EOK); ++ ++ ret = dp_opt_set_int(opts, OPT_INT_NODEFAULT, 456); ++ assert_int_equal(ret, EOK); ++ ret = dp_opt_set_int(opts, OPT_INT_DEFAULT, 789); ++ assert_int_equal(ret, EOK); ++ ++ ret = dp_opt_set_bool(opts, OPT_BOOL_TRUE, false); ++ assert_int_equal(ret, EOK); ++ ret = dp_opt_set_bool(opts, OPT_BOOL_FALSE, true); ++ assert_int_equal(ret, EOK); ++ ++ talloc_free(opts); ++ ret = dp_copy_defaults(mem_ctx, test_def_opts, OPT_NUM_OPTS, &opts); ++ assert_int_equal(ret, EOK); ++ assert_defaults(opts); ++} ++ ++void opt_test_copy_options(void **state) ++{ ++ int ret; ++ TALLOC_CTX *mem_ctx; ++ struct dp_option *opts; ++ char *s; ++ struct dp_opt_blob b; ++ int i; ++ bool bo; ++ ++ mem_ctx = talloc_new(global_talloc_context); ++ assert_non_null(mem_ctx); ++ ++ ret = dp_copy_options(mem_ctx, test_def_opts, OPT_NUM_OPTS, &opts); ++ assert_int_equal(ret, EOK); ++ assert_int_equal(ret, EOK); ++ ++ ret = dp_opt_set_string(opts, OPT_STRING_NODEFAULT, "str1"); ++ assert_int_equal(ret, EOK); ++ ++ b.data = discard_const_p(uint8_t, "blob1"); ++ b.length = strlen("blob1"); ++ ret = dp_opt_set_blob(opts, OPT_BLOB_NODEFAULT, b); ++ assert_int_equal(ret, EOK); ++ ++ ret = dp_opt_set_int(opts, OPT_INT_NODEFAULT, 456); ++ assert_int_equal(ret, EOK); ++ ++ ret = dp_opt_set_bool(opts, OPT_BOOL_TRUE, false); ++ assert_int_equal(ret, EOK); ++ ++ /* Test that options set to an explicit value retain ++ * the value and even options with default value ++ * do not return the default unless explicitly set ++ */ ++ s = dp_opt_get_string(opts, OPT_STRING_NODEFAULT); ++ assert_string_equal(s, "str1"); ++ s = dp_opt_get_string(opts, OPT_STRING_DEFAULT); ++ assert_null(s); ++ ++ b = dp_opt_get_blob(opts, OPT_BLOB_NODEFAULT); ++ assert_non_null(b.data); ++ assert_int_equal(b.length, strlen("blob1")); ++ assert_memory_equal(b.data, "blob1", strlen("blob1")); ++ b = dp_opt_get_blob(opts, OPT_BLOB_DEFAULT); ++ assert_null(b.data); ++ assert_int_equal(b.length, 0); ++ ++ i = dp_opt_get_int(opts, OPT_INT_NODEFAULT); ++ assert_int_equal(i, 456); ++ i = dp_opt_get_int(opts, OPT_INT_DEFAULT); ++ assert_int_equal(i, 0); ++ ++ bo = dp_opt_get_bool(opts, OPT_BOOL_TRUE); ++ assert_false(bo == true); ++} ++ ++void opt_test_get(void **state) ++{ ++ int ret; ++ struct sss_test_ctx *tctx; ++ struct dp_option *opts; ++ char *dompath; ++ struct sss_test_conf_param params[] = { ++ { "string_nodefault", "stringval2" }, ++ { "blob_nodefault", "blobval2" }, ++ { "int_nodefault", "456" }, ++ { "bool_true", "false" }, ++ { NULL, NULL }, /* Sentinel */ ++ }; ++ char *s; ++ struct dp_opt_blob b; ++ int i; ++ bool bo; ++ ++ tctx = create_dom_test_ctx(global_talloc_context, TESTS_PATH, TEST_CONF_DB, ++ TEST_SYSDB_FILE, TEST_DOM_NAME, ++ TEST_ID_PROVIDER, params); ++ assert_non_null(tctx); ++ ++ dompath = talloc_asprintf(tctx, "config/domain/%s", TEST_DOM_NAME); ++ assert_non_null(dompath); ++ ++ ret = dp_get_options(global_talloc_context, tctx->confdb, dompath, ++ test_def_opts, OPT_NUM_OPTS, &opts); ++ assert_int_equal(ret, EOK); ++ ++ /* Options that were not specified explicitly should only have the default ++ * value, those that have been specified explicitly should carry that ++ * value ++ */ ++ s = dp_opt_get_string(opts, OPT_STRING_NODEFAULT); ++ assert_non_null(s); ++ assert_string_equal(s, "stringval2"); ++ ++ s = dp_opt_get_string(opts, OPT_STRING_DEFAULT); ++ assert_non_null(s); ++ assert_string_equal(s, STRING_DEFAULT); ++ ++ b = dp_opt_get_blob(opts, OPT_BLOB_NODEFAULT); ++ assert_non_null(b.data); ++ assert_int_equal(b.length, strlen("blobval2")); ++ assert_memory_equal(b.data, "blobval2", strlen("blobval2")); ++ ++ b = dp_opt_get_blob(opts, OPT_BLOB_DEFAULT); ++ assert_non_null(b.data); ++ assert_int_equal(b.length, strlen(BLOB_DEFAULT)); ++ assert_memory_equal(b.data, BLOB_DEFAULT, strlen(BLOB_DEFAULT)); ++ ++ i = dp_opt_get_int(opts, OPT_INT_NODEFAULT); ++ assert_int_equal(i, 456); ++ ++ i = dp_opt_get_int(opts, OPT_INT_DEFAULT); ++ assert_int_equal(i, INT_DEFAULT); ++ ++ bo = dp_opt_get_bool(opts, OPT_BOOL_TRUE); ++ assert_true(bo == false); ++ ++ bo = dp_opt_get_bool(opts, OPT_BOOL_FALSE); ++ assert_true(bo == false); ++} ++ ++void opt_test_getset_setup(void **state) ++{ ++ int ret; ++ struct dp_option *opts; ++ ++ ret = dp_copy_defaults(global_talloc_context, ++ test_def_opts, OPT_NUM_OPTS, &opts); ++ assert_int_equal(ret, EOK); ++ assert_defaults(opts); ++ ++ *state = opts; ++} ++ ++void opt_test_getset_teardown(void **state) ++{ ++ struct dp_option *opts = talloc_get_type(*state, struct dp_option); ++ talloc_free(opts); ++} ++ ++void opt_test_getset_string(void **state) ++{ ++ struct dp_option *opts = talloc_get_type(*state, struct dp_option); ++ int ret; ++ char *s; ++ ++ s = dp_opt_get_string(opts, OPT_STRING_NODEFAULT); ++ assert_null(s); ++ ++ ret = dp_opt_set_string(opts, OPT_STRING_NODEFAULT, "str1"); ++ assert_int_equal(ret, EOK); ++ ++ s = dp_opt_get_string(opts, OPT_STRING_NODEFAULT); ++ assert_non_null(s); ++ assert_string_equal(s, "str1"); ++} ++ ++void opt_test_getset_blob(void **state) ++{ ++ struct dp_option *opts = talloc_get_type(*state, struct dp_option); ++ int ret; ++ struct dp_opt_blob b; ++ ++ b = dp_opt_get_blob(opts, OPT_BLOB_NODEFAULT); ++ assert_null(b.data); ++ assert_int_equal(b.length, 0); ++ ++ b.data = discard_const_p(uint8_t, "blob2"); ++ b.length = strlen("blob2"); ++ ret = dp_opt_set_blob(opts, OPT_BLOB_NODEFAULT, b); ++ assert_int_equal(ret, EOK); ++ ++ b = dp_opt_get_blob(opts, OPT_BLOB_NODEFAULT); ++ assert_non_null(b.data); ++ assert_int_equal(b.length, strlen("blob2")); ++ assert_memory_equal(b.data, "blob2", strlen("blob2")); ++} ++ ++void opt_test_getset_int(void **state) ++{ ++ struct dp_option *opts = talloc_get_type(*state, struct dp_option); ++ int ret; ++ int i; ++ ++ i = dp_opt_get_int(opts, OPT_INT_NODEFAULT); ++ assert_int_equal(i, 0); ++ ++ ret = dp_opt_set_int(opts, OPT_INT_NODEFAULT, 456); ++ assert_int_equal(ret, EOK); ++ ++ i = dp_opt_get_int(opts, OPT_INT_NODEFAULT); ++ assert_int_equal(i, 456); ++} ++ ++void opt_test_getset_bool(void **state) ++{ ++ struct dp_option *opts = talloc_get_type(*state, struct dp_option); ++ int ret; ++ bool b; ++ ++ b = dp_opt_get_bool(opts, OPT_BOOL_TRUE); ++ assert_true(b == true); ++ ++ ret = dp_opt_set_bool(opts, OPT_BOOL_TRUE, false); ++ assert_int_equal(ret, EOK); ++ ++ b = dp_opt_get_bool(opts, OPT_BOOL_TRUE); ++ assert_false(b == true); ++} ++ ++int main(int argc, const char *argv[]) ++{ ++ int no_cleanup = 0; ++ poptContext pc; ++ int opt; ++ int ret; ++ 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 UnitTest tests[] = { ++ unit_test_setup_teardown(opt_test_getset_string, ++ opt_test_getset_setup, ++ opt_test_getset_teardown), ++ unit_test_setup_teardown(opt_test_getset_int, ++ opt_test_getset_setup, ++ opt_test_getset_teardown), ++ unit_test_setup_teardown(opt_test_getset_bool, ++ opt_test_getset_setup, ++ opt_test_getset_teardown), ++ unit_test_setup_teardown(opt_test_getset_blob, ++ opt_test_getset_setup, ++ opt_test_getset_teardown), ++ unit_test(opt_test_copy_default), ++ unit_test(opt_test_copy_options), ++ unit_test(opt_test_get) ++ }; ++ ++ /* 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_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(); ++ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_SYSDB_FILE); ++ test_dom_suite_setup(TESTS_PATH); ++ ++ ret = run_tests(tests); ++ if (ret == 0 && !no_cleanup) { ++ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_SYSDB_FILE); ++ } ++ return ret; ++} +diff --git a/src/tests/ipa_ldap_opt-tests.c b/src/tests/ipa_ldap_opt-tests.c +index 40afa5cba87d89bc6fa7345302991fe766b43314..25a094082dc369092f10ad823d98909027dd9a7e 100644 +--- a/src/tests/ipa_ldap_opt-tests.c ++++ b/src/tests/ipa_ldap_opt-tests.c +@@ -170,7 +170,7 @@ START_TEST(test_copy_opts) + tmp_ctx = talloc_new(NULL); + fail_unless(tmp_ctx != NULL, "talloc_new failed"); + +- ret = dp_copy_options(tmp_ctx, ad_def_ldap_opts, SDAP_OPTS_BASIC, &opts); ++ ret = dp_copy_defaults(tmp_ctx, ad_def_ldap_opts, SDAP_OPTS_BASIC, &opts); + fail_unless(ret == EOK, "[%s]", strerror(ret)); + + for (int i=0; i < SDAP_OPTS_BASIC; i++) { +-- +1.8.5.3 + diff --git a/SOURCES/0098-MAN-Clarify-the-ldap_access_filter-option-further.patch b/SOURCES/0098-MAN-Clarify-the-ldap_access_filter-option-further.patch new file mode 100644 index 0000000..d98e726 --- /dev/null +++ b/SOURCES/0098-MAN-Clarify-the-ldap_access_filter-option-further.patch @@ -0,0 +1,49 @@ +From af16267fc9d681fc4230fa82a9fe86de9491c8fd Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 24 Feb 2014 19:42:23 +0100 +Subject: [PATCH 98/99] MAN: Clarify the ldap_access_filter option further + +https://fedorahosted.org/sssd/ticket/2235 + +The memberof example was misleading and was making aministrators think +that the ldap_access_filter can resolve nested group memberships. + +Reviewed-by: Sumit Bose +Reviewed-by: Stephen Gallagher +(cherry picked from commit 604d46e028ab62f83060fb88bdd3319a31aca2d1) +--- + src/man/sssd-ldap.5.xml | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml +index cc58544c38e8ffa779f0a1b22a69caaf3f193ce1..b271a2b7fa8b19ac3e4475bd8ca634b0414f5ea4 100644 +--- a/src/man/sssd-ldap.5.xml ++++ b/src/man/sssd-ldap.5.xml +@@ -1775,19 +1775,20 @@ + and this option is not set, it will result in all + users being denied access. + Use access_provider = permit to change this default +- behavior. ++ behavior. Please note that this filter is applied on ++ the LDAP user entry only. + + + Example: + + + access_provider = ldap +-ldap_access_filter = memberOf=cn=allowedusers,ou=Groups,dc=example,dc=com ++ldap_access_filter = (employeeType=admin) + + + This example means that access to this host is +- restricted to members of the "allowedusers" group +- in ldap. ++ restricted to users whose employeeType ++ attribute is set to "admin". + + + Offline caching for this feature is limited to +-- +1.8.5.3 + diff --git a/SOURCES/0099-MAN-Clarify-that-changing-ID-mapping-options-might-r.patch b/SOURCES/0099-MAN-Clarify-that-changing-ID-mapping-options-might-r.patch new file mode 100644 index 0000000..d560ead --- /dev/null +++ b/SOURCES/0099-MAN-Clarify-that-changing-ID-mapping-options-might-r.patch @@ -0,0 +1,75 @@ +From 59995f35b7dd6ec552be1081b0120f2344e3ded3 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 25 Feb 2014 17:09:00 +0100 +Subject: [PATCH 99/99] MAN: Clarify that changing ID mapping options might + require purging the cache + +https://fedorahosted.org/sssd/ticket/2252 + +Currently SSSD chokes when IDs of users change, we don't support ID +changes yet. Because some users were confused about the failures, this +patch adds additional clarification. + +Reviewed-by: Sumit Bose +Reviewed-by: Stephen Gallagher +(cherry picked from commit 3dfa09a826e5f63b4948462c2452937fc329834d) +--- + src/man/include/ldap_id_mapping.xml | 42 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 42 insertions(+) + +diff --git a/src/man/include/ldap_id_mapping.xml b/src/man/include/ldap_id_mapping.xml +index 71ff248f1f24242b911f615fd6afeb0382dfa5a1..7f5dbd30be67745b26dbced341762705d6e09f14 100644 +--- a/src/man/include/ldap_id_mapping.xml ++++ b/src/man/include/ldap_id_mapping.xml +@@ -12,6 +12,48 @@ + need to use manually-assigned values, ALL values must be + manually-assigned. + ++ ++ Please note that changing the ID mapping related configuration ++ options will cause user and group IDs to change. At the moment, ++ SSSD does not support changing IDs, so the SSSD database must ++ be removed. Because cached passwords are also stored in the ++ database, removing the database should only be performed while ++ the authentication servers are reachable, otherwise users might ++ get locked out. In order to cache the password, an authentication ++ must be performed. It is not sufficient to use ++ ++ sss_cache ++ 8 ++ ++ to remove the database, rather the process ++ consists of: ++ ++ ++ ++ Making sure the remote servers are reachable ++ ++ ++ ++ ++ Stopping the SSSD service ++ ++ ++ ++ ++ Removing the database ++ ++ ++ ++ ++ Starting the SSSD service ++ ++ ++ ++ Moreover, as the change of IDs might necessitate the adjustment ++ of other system properties such as file and directory ownership, ++ it's advisable to plan ahead and test the ID mapping configuration ++ thoroughly. ++ + + + Mapping Algorithm +-- +1.8.5.3 + diff --git a/SOURCES/0100-DOC-Fix-names-of-arguments-in-doxygen-comments.patch b/SOURCES/0100-DOC-Fix-names-of-arguments-in-doxygen-comments.patch new file mode 100644 index 0000000..5138aea --- /dev/null +++ b/SOURCES/0100-DOC-Fix-names-of-arguments-in-doxygen-comments.patch @@ -0,0 +1,76 @@ +From 02e3c4dad405464c2f0cec97203a98e5fb251273 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Thu, 13 Feb 2014 17:46:29 +0100 +Subject: [PATCH 100/101] DOC: Fix names of arguments in doxygen comments +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Pavel Březina +(cherry picked from commit 3b35ff47651e4893ce537a273466766b962362da) +--- + src/lib/idmap/sss_idmap.h | 2 +- + src/sss_client/idmap/sss_nss_idmap.h | 6 +++--- + src/util/util.h | 2 +- + 3 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/src/lib/idmap/sss_idmap.h b/src/lib/idmap/sss_idmap.h +index ccc63f7f760b877cdb17696325731f8e540b2736..0797083293f7e010962828ddcd72709b290859b9 100644 +--- a/src/lib/idmap/sss_idmap.h ++++ b/src/lib/idmap/sss_idmap.h +@@ -608,7 +608,7 @@ enum idmap_error_code sss_idmap_free_smb_sid(struct sss_idmap_ctx *ctx, + * @brief Free mapped binary SID. + * + * @param[in] ctx Idmap context +- * @param[in] smb_sid Binary SID to be freed. ++ * @param[in] bin_sid Binary SID to be freed. + * + * @return + * - #IDMAP_CONTEXT_INVALID: Provided context is invalid +diff --git a/src/sss_client/idmap/sss_nss_idmap.h b/src/sss_client/idmap/sss_nss_idmap.h +index be5c506e27f0e418022cff78b48ca3a37aacd5af..79dacfbdb1708569507742fbd8579cf7aaa06d9b 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.h ++++ b/src/sss_client/idmap/sss_nss_idmap.h +@@ -43,7 +43,7 @@ enum sss_id_type { + * @param[in] fq_name Fully qualified name of a user or a group + * @param[out] sid String representation of the SID of the requested user + * or group, must be freed by the caller +- * @param[out] id_type Type of the object related to the given name ++ * @param[out] type Type of the object related to the given name + * + * @return + * - 0 (EOK): success, sid contains the requested SID +@@ -63,7 +63,7 @@ int sss_nss_getsidbyname(const char *fq_name, char **sid, + * @param[in] id POSIX UID or GID + * @param[out] sid String representation of the SID of the requested user + * or group, must be freed by the caller +- * @param[out] id_type Type of the object related to the given ID ++ * @param[out] type Type of the object related to the given ID + * + * @return + * - see #sss_nss_getsidbyname +@@ -76,7 +76,7 @@ int sss_nss_getsidbyid(uint32_t id, char **sid, enum sss_id_type *type); + * @param[in] sid String representation of the SID + * @param[out] fq_name Fully qualified name of a user or a group, + * must be freed by the caller +- * @param[out] id_type Type of the object related to the SID ++ * @param[out] type Type of the object related to the SID + * + * @return + * - see #sss_nss_getsidbyname +diff --git a/src/util/util.h b/src/util/util.h +index 7b185bcb4287a4afc5bf67b40164cf69b9beeb19..89684e84a5be6c26fe08e5d3ab3d20d3a0e199b1 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -513,7 +513,7 @@ bool string_in_list(const char *string, char **list, bool case_sensitive); + * prevents the compiler from optimizing out + * + * @param data The address of buffer to wipe +- * @param s Size of the buffer ++ * @param size Size of the buffer + */ + void safezero(void *data, size_t size); + +-- +1.8.5.3 + diff --git a/SOURCES/0101-libsss_idmap-bump-version-info.patch b/SOURCES/0101-libsss_idmap-bump-version-info.patch new file mode 100644 index 0000000..d40eb17 --- /dev/null +++ b/SOURCES/0101-libsss_idmap-bump-version-info.patch @@ -0,0 +1,31 @@ +From e5792a6be9c3c75c7ec47af873309668f1943ae2 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 26 Feb 2014 20:50:19 +0100 +Subject: [PATCH 101/101] libsss_idmap: bump version-info +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Jakub Hrozek +Reviewed-by: Lukáš Slebodník +(cherry picked from commit 034ffb3c69cd04f03b36b89766c47a7c9bd9b831) +--- + Makefile.am | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile.am b/Makefile.am +index 9025ec6a5bfa16408278506fdd573666b4b6dbe5..879054c2fb96f937fbd58ca0757d703cdea218d8 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -614,7 +614,7 @@ libsss_idmap_la_SOURCES = \ + src/lib/idmap/sss_idmap_conv.c \ + src/util/murmurhash3.c + libsss_idmap_la_LDFLAGS = \ +- -version-info 3:0:3 ++ -version-info 4:0:4 + + dist_pkgconfig_DATA += src/sss_client/idmap/sss_nss_idmap.pc + libsss_nss_idmap_la_SOURCES = \ +-- +1.8.5.3 + diff --git a/SOURCES/0102-config-API-add-missing-subdomain-target-to-AD-provid.patch b/SOURCES/0102-config-API-add-missing-subdomain-target-to-AD-provid.patch new file mode 100644 index 0000000..3c91933 --- /dev/null +++ b/SOURCES/0102-config-API-add-missing-subdomain-target-to-AD-provid.patch @@ -0,0 +1,33 @@ +From 565ae8c3bec0dd3f1cb618b3766a907b820625ca Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 28 Feb 2014 10:04:08 +0100 +Subject: [PATCH 102/104] config API: add missing subdomain target to AD + provider test +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Jakub Hrozek +Reviewed-by: Lukáš Slebodník +Reviewed-by: Pavel Březina +(cherry picked from commit b564424a77c7c3b361c944e0623023d0cfea2c9f) +--- + src/config/SSSDConfigTest.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py +index b6c1d74aa42917fde1222f90f99cb343c80d921a..e6cf663ec86396a3d50dcbc14d4cf4d1157b0d5d 100755 +--- a/src/config/SSSDConfigTest.py ++++ b/src/config/SSSDConfigTest.py +@@ -730,7 +730,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): + control_provider_dict = { + 'ipa': ['id', 'auth', 'access', 'chpass', 'sudo', 'autofs', + 'session', 'hostid', 'subdomains'], +- 'ad': ['id', 'auth', 'access', 'chpass'], ++ 'ad': ['id', 'auth', 'access', 'chpass', 'subdomains'], + 'local': ['id', 'auth', 'chpass'], + 'ldap': ['id', 'auth', 'access', 'chpass', 'sudo', 'autofs'], + 'krb5': ['auth', 'access', 'chpass'], +-- +1.8.5.3 + diff --git a/SOURCES/0103-SUDO-AD-provider.patch b/SOURCES/0103-SUDO-AD-provider.patch new file mode 100644 index 0000000..a456185 --- /dev/null +++ b/SOURCES/0103-SUDO-AD-provider.patch @@ -0,0 +1,244 @@ +From a15ab6146ebba795e3b58d5f32cf7a1d8653c082 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 28 Feb 2014 10:05:34 +0100 +Subject: [PATCH 103/104] SUDO: AD provider +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch adds the sudo target to the AD provider. The main reason is +to cover different default settings in the LDAP and AD provider. E.g. +the default for ldap_id_mapping is True in the AD provider and False +in the LDAP provider. If ldap_id_mapping was not set explicitly in the +config file both components worked with different setting. + +Fixes https://fedorahosted.org/sssd/ticket/2256 + +Reviewed-by: Jakub Hrozek +Reviewed-by: Lukáš Slebodník +Reviewed-by: Pavel Březina +(cherry picked from commit 61804568ce5ede3b1a699cda17c033dd6c23f0e3) +--- + Makefile.am | 5 ++++ + src/config/SSSDConfigTest.py | 2 +- + src/config/etc/sssd.api.d/sssd-ad.conf | 21 ++++++++++++++ + src/man/sssd-ad.5.xml | 6 ++-- + src/man/sssd.conf.5.xml | 15 ++++++++-- + src/providers/ad/ad_common.h | 4 +++ + src/providers/ad/ad_init.c | 25 +++++++++++++++++ + src/providers/ad/ad_sudo.c | 51 ++++++++++++++++++++++++++++++++++ + 8 files changed, 122 insertions(+), 7 deletions(-) + create mode 100644 src/providers/ad/ad_sudo.c + +diff --git a/Makefile.am b/Makefile.am +index 879054c2fb96f937fbd58ca0757d703cdea218d8..b37c04067d34569ad357327b7d463cc5b052f065 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1803,6 +1803,11 @@ libsss_ad_la_SOURCES = \ + src/util/sss_krb5.c \ + src/util/sss_ldap.c + ++if BUILD_SUDO ++libsss_ad_la_SOURCES += \ ++ src/providers/ad/ad_sudo.c ++endif ++ + libsss_ad_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(LDAP_CFLAGS) \ +diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py +index e6cf663ec86396a3d50dcbc14d4cf4d1157b0d5d..98b2fee63d519201047b0c576295863d59b0a37a 100755 +--- a/src/config/SSSDConfigTest.py ++++ b/src/config/SSSDConfigTest.py +@@ -730,7 +730,7 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): + control_provider_dict = { + 'ipa': ['id', 'auth', 'access', 'chpass', 'sudo', 'autofs', + 'session', 'hostid', 'subdomains'], +- 'ad': ['id', 'auth', 'access', 'chpass', 'subdomains'], ++ 'ad': ['id', 'auth', 'access', 'chpass', 'sudo', 'subdomains'], + 'local': ['id', 'auth', 'chpass'], + 'ldap': ['id', 'auth', 'access', 'chpass', 'sudo', 'autofs'], + 'krb5': ['auth', 'access', 'chpass'], +diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf +index 6b136f2ec88614092cf1ceb4e2cea79db064d468..aa20ca0bb5b70818525d61a1480a6b56bd8c4e48 100644 +--- a/src/config/etc/sssd.api.d/sssd-ad.conf ++++ b/src/config/etc/sssd.api.d/sssd-ad.conf +@@ -132,3 +132,24 @@ krb5_kpasswd = str, None, false + krb5_backup_kpasswd = str, None, false + + [provider/ad/subdomains] ++ ++[provider/ad/sudo] ++ldap_sudo_search_base = str, None, false ++ldap_sudo_full_refresh_interval = int, None, false ++ldap_sudo_smart_refresh_interval = int, None, false ++ldap_sudo_use_host_filter = bool, None, false ++ldap_sudo_hostnames = str, None, false ++ldap_sudo_ip = str, None, false ++ldap_sudo_include_netgroups = bool, None, false ++ldap_sudo_include_regexp = bool, None, false ++ldap_sudorule_object_class = str, None, false ++ldap_sudorule_name = str, None, false ++ldap_sudorule_command = str, None, false ++ldap_sudorule_host = str, None, false ++ldap_sudorule_user = str, None, false ++ldap_sudorule_option = str, None, false ++ldap_sudorule_runasuser = str, None, false ++ldap_sudorule_runasgroup = str, None, false ++ldap_sudorule_notbefore = str, None, false ++ldap_sudorule_notafter = str, None, false ++ldap_sudorule_order = str, None, false +diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml +index 38cc31278cf87c98ca9e53cf91fda7b141bff78d..8cd94d4aeaf553ecb54e0e4c866be5fb7a44fa8e 100644 +--- a/src/man/sssd-ad.5.xml ++++ b/src/man/sssd-ad.5.xml +@@ -60,9 +60,9 @@ + + + However, it is neither necessary nor recommended to set these +- options. The AD provider can also be used as an access and chpass +- provider. No configuration of the access provider is required on +- the client side. ++ options. The AD provider can also be used as an access, chpass and ++ sudo provider. No configuration of the access provider is required ++ on the client side. + + + By default, the AD provider will map UID and GID values from the +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index 5d861c73cfeb41920619d95e5c1e5c1975dcc45b..29b08d53d2568f2fce47b37ea0b88c9dc233c12e 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -1450,14 +1450,23 @@ fallback_homedir = /home/%u + + sssd-ldap + 5 +- for more information on configuring LDAP. ++ for more information on configuring ++ LDAP. ++ ++ ++ ipa the same as ldap ++ but with IPA default settings. ++ ++ ++ ad the same as ldap ++ but with AD default settings. + + + none disables SUDO explicitly. + + +- Default: The value of id_provider is used if it +- is set. ++ Default: The value of id_provider is ++ used if it is set. + + + +diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h +index d370cef69124c127f41d7c4cbaa25713363e7752..bc11e54b0c4903c876f23bfea3ef573f06ba8c69 100644 +--- a/src/providers/ad/ad_common.h ++++ b/src/providers/ad/ad_common.h +@@ -128,4 +128,8 @@ errno_t ad_dyndns_init(struct be_ctx *be_ctx, + struct ad_options *ctx); + void ad_dyndns_timer(void *pvt); + ++int ad_sudo_init(struct be_ctx *be_ctx, ++ struct ad_id_ctx *id_ctx, ++ struct bet_ops **ops, ++ void **pvt_data); + #endif /* AD_COMMON_H_ */ +diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c +index eff6d990d131e3aba124d252d001dd39e78b45cf..500d807e9c44e92089d31c81f3b22c9606c476e5 100644 +--- a/src/providers/ad/ad_init.c ++++ b/src/providers/ad/ad_init.c +@@ -467,3 +467,28 @@ int sssm_ad_subdomains_init(struct be_ctx *bectx, + + return EOK; + } ++ ++ ++int sssm_ad_sudo_init(struct be_ctx *bectx, ++ struct bet_ops **ops, ++ void **pvt_data) ++{ ++#ifdef BUILD_SUDO ++ struct ad_id_ctx *id_ctx; ++ int ret; ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, ("Initializing AD sudo handler\n")); ++ ++ ret = sssm_ad_id_init(bectx, ops, (void **) &id_ctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("sssm_ad_id_init failed.\n")); ++ return ret; ++ } ++ ++ return ad_sudo_init(bectx, id_ctx, ops, pvt_data); ++#else ++ DEBUG(SSSDBG_MINOR_FAILURE, ("Sudo init handler called but SSSD is " ++ "built without sudo support, ignoring\n")); ++ return EOK; ++#endif ++} +diff --git a/src/providers/ad/ad_sudo.c b/src/providers/ad/ad_sudo.c +new file mode 100644 +index 0000000000000000000000000000000000000000..b85c95c5c2f44e116a75bc24e073c067806621dd +--- /dev/null ++++ b/src/providers/ad/ad_sudo.c +@@ -0,0 +1,51 @@ ++/* ++ SSSD ++ ++ AD SUDO Provider Initialization functions ++ ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) 2014 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#include "providers/ad/ad_common.h" ++#include "providers/ldap/sdap_sudo.h" ++ ++int ad_sudo_init(struct be_ctx *be_ctx, ++ struct ad_id_ctx *id_ctx, ++ struct bet_ops **ops, ++ void **pvt_data) ++{ ++ int ret; ++ struct ad_options *ad_options; ++ struct sdap_options *ldap_options; ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, ("Initializing sudo AD back end\n")); ++ ++ ret = sdap_sudo_init(be_ctx, id_ctx->sdap_id_ctx, ops, pvt_data); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Cannot initialize LDAP SUDO [%d]: %s\n", ++ ret, strerror(ret))); ++ return ret; ++ } ++ ++ ad_options = id_ctx->ad_options; ++ ldap_options = id_ctx->sdap_id_ctx->opts; ++ ++ ad_options->id->sudorule_map = ldap_options->sudorule_map; ++ return EOK; ++} +-- +1.8.5.3 + diff --git a/SOURCES/0104-ipa-server-mode-use-lower-case-user-name-for-home-di.patch b/SOURCES/0104-ipa-server-mode-use-lower-case-user-name-for-home-di.patch new file mode 100644 index 0000000..4071e9b --- /dev/null +++ b/SOURCES/0104-ipa-server-mode-use-lower-case-user-name-for-home-di.patch @@ -0,0 +1,51 @@ +From 3b8640e8ef5cbcf934cdd6f42e9f6d956ca47395 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 3 Mar 2014 12:40:43 +0100 +Subject: [PATCH 104/104] ipa-server-mode: use lower-case user name for home + dir + +In older IPA server versions where the AD users where looked up by +winbind the user name component of the home directory path was always +lower case. This still holds for IPA clients as well. To avoid +regression this patch makes the user name component lower case as well. + +Fixes https://fedorahosted.org/sssd/ticket/2263 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 48b1db73639135dd4a15ee153f958c912836c621) +--- + src/providers/ipa/ipa_subdomains_id.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c +index 637dd61f9f272eb4ac4ecb8368d2210801bb0373..00993c496c1d100b37a780828c81492c2fac6157 100644 +--- a/src/providers/ipa/ipa_subdomains_id.c ++++ b/src/providers/ipa/ipa_subdomains_id.c +@@ -358,6 +358,7 @@ get_subdomain_homedir_of_user(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom, + { + errno_t ret; + char *name; ++ char *lc_name; + const char *homedir; + TALLOC_CTX *tmp_ctx; + +@@ -372,7 +373,15 @@ get_subdomain_homedir_of_user(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom, + goto done; + } + +- homedir = expand_homedir_template(tmp_ctx, dom->subdomain_homedir, name, ++ /* To be compatible with the old winbind based user lookups and IPA ++ * clients the user name in the home directory path will be lower-case. */ ++ lc_name = sss_tc_utf8_str_tolower(tmp_ctx, name); ++ if (lc_name == NULL) { ++ ret =ENOMEM; ++ goto done; ++ } ++ ++ homedir = expand_homedir_template(tmp_ctx, dom->subdomain_homedir, lc_name, + uid, NULL, dom->name, dom->flat_name); + + if (homedir == NULL) { +-- +1.8.5.3 + diff --git a/SOURCES/0105-IPA-Do-not-save-intermediate-data-to-sysdb.patch b/SOURCES/0105-IPA-Do-not-save-intermediate-data-to-sysdb.patch new file mode 100644 index 0000000..ba7de59 --- /dev/null +++ b/SOURCES/0105-IPA-Do-not-save-intermediate-data-to-sysdb.patch @@ -0,0 +1,101 @@ +From 4fc9c7b11aa64a151d19b908ca07d8b16b6657ff Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 4 Mar 2014 13:48:36 +0100 +Subject: [PATCH 105/105] IPA: Do not save intermediate data to sysdb + +https://fedorahosted.org/sssd/ticket/2264 + +Reviewed-by: Sumit Bose +--- + src/providers/ipa/ipa_selinux.c | 68 ++++++++++++++++++++--------------------- + 1 file changed, 34 insertions(+), 34 deletions(-) + +diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c +index c227db937a84228c0f3945dbe11ba904c7ad9744..2209ca188654d8c79ee402ba71beeadab2904093 100644 +--- a/src/providers/ipa/ipa_selinux.c ++++ b/src/providers/ipa/ipa_selinux.c +@@ -251,6 +251,40 @@ static void ipa_selinux_handler_done(struct tevent_req *req) + goto fail; + } + ++ ret = sysdb_transaction_start(sysdb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n")); ++ goto fail; ++ } ++ in_transaction = true; ++ ++ ret = sysdb_delete_usermaps(op_ctx->domain->sysdb, op_ctx->domain); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ ("Cannot delete existing maps from sysdb\n")); ++ goto fail; ++ } ++ ++ ret = sysdb_store_selinux_config(sysdb, op_ctx->domain, ++ default_user, map_order); ++ if (ret != EOK) { ++ goto fail; ++ } ++ ++ if (map_count > 0 && maps != NULL) { ++ ret = ipa_save_user_maps(sysdb, op_ctx->domain, map_count, maps); ++ if (ret != EOK) { ++ goto fail; ++ } ++ } ++ ++ ret = sysdb_transaction_commit(sysdb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Could not commit transaction\n")); ++ goto fail; ++ } ++ in_transaction = false; ++ + /* Process the maps and return list of best matches (maps with + * highest priority). The input maps are also parent memory + * context for the output list of best matches. The best match +@@ -279,40 +313,6 @@ static void ipa_selinux_handler_done(struct tevent_req *req) + goto fail; + } + +- ret = sysdb_transaction_start(sysdb); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n")); +- goto fail; +- } +- in_transaction = true; +- +- ret = sysdb_delete_usermaps(op_ctx->domain->sysdb, op_ctx->domain); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- ("Cannot delete existing maps from sysdb\n")); +- goto fail; +- } +- +- ret = sysdb_store_selinux_config(sysdb, op_ctx->domain, +- default_user, map_order); +- if (ret != EOK) { +- goto fail; +- } +- +- if (map_count > 0 && maps != NULL) { +- ret = ipa_save_user_maps(sysdb, op_ctx->domain, map_count, maps); +- if (ret != EOK) { +- goto fail; +- } +- } +- +- ret = sysdb_transaction_commit(sysdb); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, ("Could not commit transaction\n")); +- goto fail; +- } +- in_transaction = false; +- + /* If we got here in online mode, set last_update to current time */ + if (!be_is_offline(be_ctx)) { + op_ctx->selinux_ctx->last_update = time(NULL); +-- +1.8.5.3 + diff --git a/SOURCES/0106-Fix-krb5-changepw-when-FAST-only-preauth-methods-are.patch b/SOURCES/0106-Fix-krb5-changepw-when-FAST-only-preauth-methods-are.patch new file mode 100644 index 0000000..5c7b4a8 --- /dev/null +++ b/SOURCES/0106-Fix-krb5-changepw-when-FAST-only-preauth-methods-are.patch @@ -0,0 +1,127 @@ +From bbe47ea8ebe6373d0b05181eb27bb65432a9cc97 Mon Sep 17 00:00:00 2001 +From: Nathaniel McCallum +Date: Fri, 7 Mar 2014 12:21:11 -0500 +Subject: [PATCH 106/107] Fix krb5 changepw when FAST-only preauth methods are + used (like OTP) + +Before this patch, a different set of options was used when calling +krb5_get_init_creds_password() for the changepw principal. Because +this set of options did not contain the same FAST settings as the +options for normal requests, all authentication would fail when the +password of a FAST-only account would expire. + +The two sets approach was cargo-cult from kinit where multiple +requests could be issued using the same options set. However, in the +case of krb5_child, only one request (or occasionally a well-defined +second request) will be issued. Two option sets are therefore not +required. + +To fix this problem we removed the second option set used for changepw +requests. All requests now use a single option set which is modified, +if needed, for well-defined subsequent requests. + +Reviewed-by: Jakub Hrozek +Reviewed-by: Sumit Bose +--- + src/providers/krb5/krb5_child.c | 40 ++++++---------------------------------- + 1 file changed, 6 insertions(+), 34 deletions(-) + +diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c +index aa29de0cb4e14ea4804ba660b4b8e9b64e9e340e..461a27464f4fea09d4ca430b53aff072b29de141 100644 +--- a/src/providers/krb5/krb5_child.c ++++ b/src/providers/krb5/krb5_child.c +@@ -65,27 +65,14 @@ struct krb5_req { + static krb5_context krb5_error_ctx; + #define KRB5_CHILD_DEBUG(level, error) KRB5_DEBUG(level, krb5_error_ctx, error) + +-static krb5_error_code get_changepw_options(krb5_context ctx, +- krb5_get_init_creds_opt **_options) ++static void set_changepw_options(krb5_context ctx, ++ krb5_get_init_creds_opt *options) + { +- krb5_get_init_creds_opt *options; +- krb5_error_code kerr; +- +- kerr = sss_krb5_get_init_creds_opt_alloc(ctx, &options); +- if (kerr != 0) { +- KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); +- return kerr; +- } +- + sss_krb5_get_init_creds_opt_set_canonicalize(options, 0); + krb5_get_init_creds_opt_set_forwardable(options, 0); + krb5_get_init_creds_opt_set_proxiable(options, 0); + krb5_get_init_creds_opt_set_renew_life(options, 0); + krb5_get_init_creds_opt_set_tkt_life(options, 5*60); +- +- *_options = options; +- +- return 0; + } + + static errno_t sss_send_pac(krb5_authdata **pac_authdata) +@@ -1023,7 +1010,6 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim) + krb5_prompter_fct prompter = NULL; + const char *realm_name; + int realm_length; +- krb5_get_init_creds_opt *chagepw_options; + size_t msg_len; + uint8_t *msg; + +@@ -1041,12 +1027,7 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim) + prompter = sss_krb5_prompter; + } + +- kerr = get_changepw_options(kr->ctx, &chagepw_options); +- if (kerr != 0) { +- DEBUG(SSSDBG_OP_FAILURE, ("get_changepw_options failed.\n")); +- return kerr; +- } +- ++ set_changepw_options(kr->ctx, kr->options); + sss_krb5_princ_realm(kr->ctx, kr->princ, &realm_name, &realm_length); + + DEBUG(SSSDBG_TRACE_FUNC, +@@ -1055,8 +1036,7 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim) + discard_const(password), + prompter, kr, 0, + SSSD_KRB5_CHANGEPW_PRINCIPAL, +- chagepw_options); +- sss_krb5_get_init_creds_opt_free(kr->ctx, chagepw_options); ++ kr->options); + if (kerr != 0) { + ret = pack_user_info_chpass_error(kr->pd, "Old password not accepted.", + &msg_len, &msg); +@@ -1164,7 +1144,6 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim) + + static errno_t tgt_req_child(struct krb5_req *kr) + { +- krb5_get_init_creds_opt *chagepw_options; + const char *password = NULL; + krb5_error_code kerr; + int ret; +@@ -1210,19 +1189,12 @@ static errno_t tgt_req_child(struct krb5_req *kr) + DEBUG(1, ("Failed to unset expire callback, continue ...\n")); + } + +- kerr = get_changepw_options(kr->ctx, &chagepw_options); +- if (kerr != 0) { +- DEBUG(SSSDBG_OP_FAILURE, ("get_changepw_options failed.\n")); +- return kerr; +- } +- ++ set_changepw_options(kr->ctx, kr->options); + kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ, + discard_const(password), + sss_krb5_prompter, kr, 0, + SSSD_KRB5_CHANGEPW_PRINCIPAL, +- chagepw_options); +- +- sss_krb5_get_init_creds_opt_free(kr->ctx, chagepw_options); ++ kr->options); + + krb5_free_cred_contents(kr->ctx, kr->creds); + if (kerr == 0) { +-- +1.8.5.3 + diff --git a/SOURCES/0107-IPA-Use-GC-for-AD-initgroup-requests.patch b/SOURCES/0107-IPA-Use-GC-for-AD-initgroup-requests.patch new file mode 100644 index 0000000..f795e50 --- /dev/null +++ b/SOURCES/0107-IPA-Use-GC-for-AD-initgroup-requests.patch @@ -0,0 +1,46 @@ +From d34211137c7e70563b073b83d773ae18688efbbc Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 6 Mar 2014 15:37:57 +0100 +Subject: [PATCH 107/107] IPA: Use GC for AD initgroup requests + +Reviewed-by: Jakub Hrozek +--- + src/providers/ipa/ipa_subdomains_id.c | 21 +++++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c +index 00993c496c1d100b37a780828c81492c2fac6157..978ccc261d7525662e835b867044b6a5238a29df 100644 +--- a/src/providers/ipa/ipa_subdomains_id.c ++++ b/src/providers/ipa/ipa_subdomains_id.c +@@ -307,13 +307,22 @@ ipa_get_ad_acct_send(TALLOC_CTX *mem_ctx, + /* Currently only LDAP port for AD is used because POSIX + * attributes are not replicated to GC by default + */ +- clist = talloc_zero_array(req, struct sdap_id_conn_ctx *, 2); +- if (clist == NULL) { +- ret = ENOMEM; +- goto fail; ++ ++ if ((state->ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_INITGROUPS) { ++ clist = ad_gc_conn_list(req, ad_id_ctx, state->user_dom); ++ if (clist == NULL) { ++ ret = ENOMEM; ++ goto fail; ++ } ++ } else { ++ clist = talloc_zero_array(req, struct sdap_id_conn_ctx *, 2); ++ if (clist == NULL) { ++ ret = ENOMEM; ++ goto fail; ++ } ++ clist[0] = ad_id_ctx->ldap_ctx; ++ clist[1] = NULL; + } +- clist[0] = ad_id_ctx->ldap_ctx; +- clist[1] = NULL; + + /* Now we already need ad_id_ctx in particular sdap_id_conn_ctx */ + sdom = sdap_domain_get(sdap_id_ctx->opts, state->user_dom); +-- +1.8.5.3 + diff --git a/SOURCES/0108-AD-Only-connect-to-GC-for-subdomain-users.patch b/SOURCES/0108-AD-Only-connect-to-GC-for-subdomain-users.patch new file mode 100644 index 0000000..26f9aea --- /dev/null +++ b/SOURCES/0108-AD-Only-connect-to-GC-for-subdomain-users.patch @@ -0,0 +1,57 @@ +From e62c422753537d8e2b98e979553626850b7b7600 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 5 Mar 2014 11:50:54 +0100 +Subject: [PATCH 108/110] AD: Only connect to GC for subdomain users +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +https://fedorahosted.org/sssd/ticket/2251 + +By connecting to GC for users from both trusted domains and parent +domain, we lose the ability to download the shell and homedir if these +are used with ID mapping. + +This patch changes the user lookups only. Changing the logic for all +lookups would break cross-domain group memberships, for example. + +Reviewed-by: Pavel Březina +(cherry picked from commit bb8a08118db0916bf8252a9481c16271ec20acd3) +--- + src/providers/ad/ad_id.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c +index 87af656b364344a8ef27a444e5dfcf8848939110..a35823b4b77d42fc583a61653a175f0ee4d22ac4 100644 +--- a/src/providers/ad/ad_id.c ++++ b/src/providers/ad/ad_id.c +@@ -215,9 +215,26 @@ get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx, + struct sss_domain_info *dom, struct be_acct_req *ar) + { + struct sdap_id_conn_ctx **clist; ++ int cindex = 0; + + switch (ar->entry_type & BE_REQ_TYPE_MASK) { + case BE_REQ_USER: /* user */ ++ clist = talloc_zero_array(ad_ctx, struct sdap_id_conn_ctx *, 3); ++ if (clist == NULL) return NULL; ++ ++ /* Try GC first for users from trusted domains */ ++ if (dp_opt_get_bool(ad_ctx->ad_options->basic, AD_ENABLE_GC) ++ && IS_SUBDOMAIN(dom)) { ++ clist[cindex] = ad_ctx->gc_ctx; ++ clist[cindex]->ignore_mark_offline = true; ++ cindex++; ++ } ++ ++ /* Users from primary domain can be just downloaded from LDAP. ++ * The domain's LDAP connection also works as a fallback ++ */ ++ clist[cindex] = ad_get_dom_ldap_conn(ad_ctx, dom); ++ break; + case BE_REQ_BY_SECID: /* by SID */ + case BE_REQ_USER_AND_GROUP: /* get SID */ + case BE_REQ_GROUP: /* group */ +-- +1.8.5.3 + diff --git a/SOURCES/0109-MAN-Clarify-the-GC-support-a-bit.patch b/SOURCES/0109-MAN-Clarify-the-GC-support-a-bit.patch new file mode 100644 index 0000000..8269e74 --- /dev/null +++ b/SOURCES/0109-MAN-Clarify-the-GC-support-a-bit.patch @@ -0,0 +1,51 @@ +From b9336c0c96d409ecd7371a55fbfcf5691814efec Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 5 Mar 2014 12:13:48 +0100 +Subject: [PATCH 109/110] MAN: Clarify the GC support a bit +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It should be noted that disabling GC does *not* disable lookups from +trusted domains. Disabling GC might be a a good way for admins who wish +to use POSIX attributes in trusted domains and the man page should hint +this option. + +Reviewed-by: Pavel Březina +(cherry picked from commit fdaaf2525e333af04ee9b48429b6766b5fd6cab6) +--- + src/man/sssd-ad.5.xml | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml +index 8cd94d4aeaf553ecb54e0e4c866be5fb7a44fa8e..0554317f533f2309d9fad60dfe5543f8546a6bbc 100644 +--- a/src/man/sssd-ad.5.xml ++++ b/src/man/sssd-ad.5.xml +@@ -232,11 +232,19 @@ FOREST:EXAMPLE.COM:(memberOf=cn=admins,ou=groups,dc=example,dc=com) + + + By default, the SSSD connects to the Global +- Catalog first to retrieve users and uses the +- LDAP port to retrieve group memberships or +- as a fallback. Disabling this option makes +- the SSSD only connect to the LDAP port of the +- current AD server. ++ Catalog first to retrieve users from trusted ++ domains and uses the LDAP port to retrieve ++ group memberships or as a fallback. Disabling ++ this option makes the SSSD only connect to ++ the LDAP port of the current AD server. ++ ++ ++ Please note that disabling Global Catalog support ++ does not disable retrieving users from trusted ++ domains. The SSSD would connect to the LDAP port ++ of trusted domains instead. However, Global ++ Catalog must be used in order to resolve ++ cross-domain group memberships. + + + Default: true +-- +1.8.5.3 + diff --git a/SOURCES/0110-IPA-Use-the-correct-domain-when-processing-SELinux-r.patch b/SOURCES/0110-IPA-Use-the-correct-domain-when-processing-SELinux-r.patch new file mode 100644 index 0000000..a5644b8 --- /dev/null +++ b/SOURCES/0110-IPA-Use-the-correct-domain-when-processing-SELinux-r.patch @@ -0,0 +1,121 @@ +From 83eedf41e97e3fae59d92c0331cb3d1dc62a9010 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 5 Mar 2014 16:35:00 +0100 +Subject: [PATCH 110/110] IPA: Use the correct domain when processing SELinux + rules +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We blindly used the user's domain for everything. That wrong in case the +user comes from a subdomain. We should use the IPA domain for accessing +the SELinux rules and host data and the user domain only for the user. + +https://fedorahosted.org/sssd/ticket/2270 + +Reviewed-by: Pavel Březina +(cherry picked from commit 36f606d6743e77721bedeed0907f1be7a19fa4f4) +--- + src/providers/ipa/ipa_selinux.c | 26 ++++++++++++++++---------- + 1 file changed, 16 insertions(+), 10 deletions(-) + +diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c +index 2209ca188654d8c79ee402ba71beeadab2904093..4ec5a64159de139f9ba5b30bf1f1a56baf32a52f 100644 +--- a/src/providers/ipa/ipa_selinux.c ++++ b/src/providers/ipa/ipa_selinux.c +@@ -57,7 +57,8 @@ static errno_t ipa_get_selinux_recv(struct tevent_req *req, + + static struct ipa_selinux_op_ctx * + ipa_selinux_create_op_ctx(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, +- struct sss_domain_info *domain, ++ struct sss_domain_info *ipa_domain, ++ struct sss_domain_info *user_domain, + struct be_req *be_req, const char *username, + const char *hostname, + struct ipa_selinux_ctx *selinux_ctx); +@@ -80,7 +81,8 @@ static errno_t ipa_selinux_process_maps(TALLOC_CTX *mem_ctx, + + struct ipa_selinux_op_ctx { + struct be_req *be_req; +- struct sss_domain_info *domain; ++ struct sss_domain_info *user_domain; ++ struct sss_domain_info *ipa_domain; + struct ipa_selinux_ctx *selinux_ctx; + + struct sysdb_attrs *user; +@@ -131,6 +133,7 @@ void ipa_selinux_handler(struct be_req *be_req) + } + + op_ctx = ipa_selinux_create_op_ctx(be_req, user_domain->sysdb, ++ be_ctx->domain, + user_domain, + be_req, pd->user, hostname, + selinux_ctx); +@@ -155,7 +158,8 @@ fail: + + static struct ipa_selinux_op_ctx * + ipa_selinux_create_op_ctx(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, +- struct sss_domain_info *domain, ++ struct sss_domain_info *ipa_domain, ++ struct sss_domain_info *user_domain, + struct be_req *be_req, const char *username, + const char *hostname, + struct ipa_selinux_ctx *selinux_ctx) +@@ -175,15 +179,16 @@ ipa_selinux_create_op_ctx(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, + return NULL; + } + op_ctx->be_req = be_req; +- op_ctx->domain = domain; ++ op_ctx->ipa_domain = ipa_domain; ++ op_ctx->user_domain = user_domain; + op_ctx->selinux_ctx = selinux_ctx; + +- ret = sss_selinux_extract_user(op_ctx, sysdb, domain, username, &op_ctx->user); ++ ret = sss_selinux_extract_user(op_ctx, sysdb, user_domain, username, &op_ctx->user); + if (ret != EOK) { + goto fail; + } + +- host_dn = sysdb_custom_dn(sysdb, op_ctx, domain, hostname, HBAC_HOSTS_SUBDIR); ++ host_dn = sysdb_custom_dn(sysdb, op_ctx, ipa_domain, hostname, HBAC_HOSTS_SUBDIR); + if (host_dn == NULL) { + goto fail; + } +@@ -229,7 +234,7 @@ static void ipa_selinux_handler_done(struct tevent_req *req) + struct ipa_selinux_op_ctx *op_ctx = tevent_req_callback_data(req, struct ipa_selinux_op_ctx); + struct be_req *breq = op_ctx->be_req; + struct be_ctx *be_ctx = be_req_get_be_ctx(breq); +- struct sysdb_ctx *sysdb = op_ctx->domain->sysdb; ++ struct sysdb_ctx *sysdb = op_ctx->ipa_domain->sysdb; + errno_t ret, sret; + size_t map_count = 0; + struct sysdb_attrs **maps = NULL; +@@ -258,21 +263,22 @@ static void ipa_selinux_handler_done(struct tevent_req *req) + } + in_transaction = true; + +- ret = sysdb_delete_usermaps(op_ctx->domain->sysdb, op_ctx->domain); ++ ret = sysdb_delete_usermaps(op_ctx->ipa_domain->sysdb, op_ctx->ipa_domain); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Cannot delete existing maps from sysdb\n")); + goto fail; + } + +- ret = sysdb_store_selinux_config(sysdb, op_ctx->domain, ++ ret = sysdb_store_selinux_config(op_ctx->ipa_domain->sysdb, ++ op_ctx->ipa_domain, + default_user, map_order); + if (ret != EOK) { + goto fail; + } + + if (map_count > 0 && maps != NULL) { +- ret = ipa_save_user_maps(sysdb, op_ctx->domain, map_count, maps); ++ ret = ipa_save_user_maps(sysdb, op_ctx->ipa_domain, map_count, maps); + if (ret != EOK) { + goto fail; + } +-- +1.8.5.3 + diff --git a/SOURCES/0111-IPA-KRB5-handle-KRB5_PROG_ETYPE_NOSUPP-during-IPA-pa.patch b/SOURCES/0111-IPA-KRB5-handle-KRB5_PROG_ETYPE_NOSUPP-during-IPA-pa.patch new file mode 100644 index 0000000..edef6ea --- /dev/null +++ b/SOURCES/0111-IPA-KRB5-handle-KRB5_PROG_ETYPE_NOSUPP-during-IPA-pa.patch @@ -0,0 +1,32 @@ +From f8a49b3bff8d3969824fc7ba4e90d229f0c4edea Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 11 Mar 2014 13:16:14 +0100 +Subject: [PATCH 111/111] IPA/KRB5: handle KRB5_PROG_ETYPE_NOSUPP during IPA + password migration + +Fixes https://fedorahosted.org/sssd/ticket/2279 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 63bf0b7697d5a51b5338070d0e2652d49a4728ce) +--- + src/providers/krb5/krb5_child.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c +index 461a27464f4fea09d4ca430b53aff072b29de141..af303e6c8c507c7cef108027c49cc4adb74162e7 100644 +--- a/src/providers/krb5/krb5_child.c ++++ b/src/providers/krb5/krb5_child.c +@@ -986,6 +986,10 @@ static errno_t map_krb5_error(krb5_error_code kerr) + case KRB5KRB_AP_ERR_BAD_INTEGRITY: + return ERR_AUTH_FAILED; + ++ /* ERR_CREDS_INVALID is used to indicate to the IPA provider that trying ++ * password migration would make sense. All Kerberos error codes which can ++ * be seen while migrating LDAP users to IPA should be added here. */ ++ case KRB5_PROG_ETYPE_NOSUPP: + case KRB5_PREAUTH_FAILED: + case KRB5KDC_ERR_PREAUTH_FAILED: + return ERR_CREDS_INVALID; +-- +1.8.5.3 + diff --git a/SOURCES/0112-AD-Continue-if-sssd-failes-to-check-extra-members.patch b/SOURCES/0112-AD-Continue-if-sssd-failes-to-check-extra-members.patch new file mode 100644 index 0000000..25f4e5c --- /dev/null +++ b/SOURCES/0112-AD-Continue-if-sssd-failes-to-check-extra-members.patch @@ -0,0 +1,35 @@ +From 2ac5fed1ea4e9f56a18d0cc3b445855cdc6757c2 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Wed, 12 Mar 2014 17:38:22 +0100 +Subject: [PATCH 112/113] AD: Continue if sssd failes to check extra members + +Reported by scan-build + + for (mi = 0; group_only[mi]; mi++) { + ^~~~~~~~~~ +warning: Array access (from variable 'group_only') results in a null pointer +dereference + +It can happend if function ad_group_extra_members fails (ret != EOK) + +Reviewed-by: Simo Sorce +(cherry picked from commit bad65473c4c28ecbf2b6bd374a7ae2d634d57d8d) +--- + src/providers/ad/ad_id.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c +index a35823b4b77d42fc583a61653a175f0ee4d22ac4..01d18d7ae4bee82d8b75c7103c0f07635c6e08cc 100644 +--- a/src/providers/ad/ad_id.c ++++ b/src/providers/ad/ad_id.c +@@ -772,6 +772,7 @@ ad_enum_cross_dom_members(struct sdap_options *opts, + ret = ad_group_extra_members(tmp_ctx, msgs[i], dom, &group_only); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Failed to check extra members\n")); ++ continue; + } else if (group_only == NULL) { + DEBUG(SSSDBG_TRACE_INTERNAL, ("No extra members\n")); + continue; +-- +1.8.5.3 + diff --git a/SOURCES/0113-IPA-Write-SELinux-usernames-in-the-right-case.patch b/SOURCES/0113-IPA-Write-SELinux-usernames-in-the-right-case.patch new file mode 100644 index 0000000..c09551c --- /dev/null +++ b/SOURCES/0113-IPA-Write-SELinux-usernames-in-the-right-case.patch @@ -0,0 +1,103 @@ +From 12fa74c860993f154d1eb1585b4a735ca3684565 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 12 Mar 2014 15:19:02 +0100 +Subject: [PATCH 113/113] IPA: Write SELinux usernames in the right case +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +https://fedorahosted.org/sssd/ticket/2282 + +Reviewed-by: Michal Židek +--- + src/providers/ipa/ipa_selinux.c | 26 +++++++++++++++++++++----- + 1 file changed, 21 insertions(+), 5 deletions(-) + +diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c +index 4ec5a64159de139f9ba5b30bf1f1a56baf32a52f..7f59161918a04ff8c994a0ce0fe55924ff09eda7 100644 +--- a/src/providers/ipa/ipa_selinux.c ++++ b/src/providers/ipa/ipa_selinux.c +@@ -225,6 +225,7 @@ static errno_t create_order_array(TALLOC_CTX *mem_ctx, const char *map_order, + char ***_order_array, size_t *_order_count); + static errno_t choose_best_seuser(struct sysdb_attrs **usermaps, + struct pam_data *pd, ++ struct sss_domain_info *user_domain, + char **order_array, int order_count, + const char *default_user); + +@@ -311,8 +312,8 @@ static void ipa_selinux_handler_done(struct tevent_req *req) + goto fail; + } + +- ret = choose_best_seuser(best_match_maps, pd, order_array, order_count, +- default_user); ++ ret = choose_best_seuser(best_match_maps, pd, op_ctx->user_domain, ++ order_array, order_count, default_user); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Failed to evaluate ordered SELinux users array.\n")); +@@ -601,13 +602,16 @@ done: + return ret; + } + +-static errno_t write_selinux_login_file(const char *username, char *string); ++static errno_t write_selinux_login_file(const char *orig_name, ++ struct sss_domain_info *dom, ++ char *string); + static errno_t remove_selinux_login_file(const char *username); + + /* Choose best selinux user based on given order and write + * the user to selinux login file. */ + static errno_t choose_best_seuser(struct sysdb_attrs **usermaps, + struct pam_data *pd, ++ struct sss_domain_info *user_domain, + char **order_array, int order_count, + const char *default_user) + { +@@ -662,7 +666,7 @@ static errno_t choose_best_seuser(struct sysdb_attrs **usermaps, + } + } + +- ret = write_selinux_login_file(pd->user, file_content); ++ ret = write_selinux_login_file(pd->user, user_domain, file_content); + done: + if (!file_content) { + err = remove_selinux_login_file(pd->user); +@@ -673,7 +677,9 @@ done: + return ret; + } + +-static errno_t write_selinux_login_file(const char *username, char *string) ++static errno_t write_selinux_login_file(const char *orig_name, ++ struct sss_domain_info *dom, ++ char *string) + { + char *path = NULL; + char *tmp_path = NULL; +@@ -685,6 +691,7 @@ static errno_t write_selinux_login_file(const char *username, char *string) + char *full_string = NULL; + int enforce; + errno_t ret = EOK; ++ const char *username; + + len = strlen(string); + if (len == 0) { +@@ -697,6 +704,15 @@ static errno_t write_selinux_login_file(const char *username, char *string) + return ENOMEM; + } + ++ /* pam_selinux needs the username in the same format getpwnam() would ++ * return it ++ */ ++ username = sss_get_cased_name(tmp_ctx, orig_name, dom->case_sensitive); ++ if (username == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ + path = selogin_path(tmp_ctx, username); + if (path == NULL) { + ret = ENOMEM; +-- +1.8.5.3 + diff --git a/SOURCES/0114-krb5_child-remove-unused-option-lifetime_str-from-k5.patch b/SOURCES/0114-krb5_child-remove-unused-option-lifetime_str-from-k5.patch new file mode 100644 index 0000000..4aeb7a6 --- /dev/null +++ b/SOURCES/0114-krb5_child-remove-unused-option-lifetime_str-from-k5.patch @@ -0,0 +1,49 @@ +From 4069c662c32836f8ebba7f091c44f9db2a1ef62e Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 20 Mar 2014 18:39:48 +0100 +Subject: [PATCH 114/117] krb5_child: remove unused option lifetime_str from + k5c_setup_fast() + +Reviewed-by: Jakub Hrozek +--- + src/providers/krb5/krb5_child.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c +index af303e6c8c507c7cef108027c49cc4adb74162e7..7f07efc161d0242e64bd67e13dec9a3faa9f2e30 100644 +--- a/src/providers/krb5/krb5_child.c ++++ b/src/providers/krb5/krb5_child.c +@@ -1666,7 +1666,7 @@ static errno_t k5c_recv_data(struct krb5_req *kr, int fd, uint32_t *offline) + return ret; + } + +-static int k5c_setup_fast(struct krb5_req *kr, char *lifetime_str, bool demand) ++static int k5c_setup_fast(struct krb5_req *kr, bool demand) + { + krb5_principal fast_princ_struct; + krb5_data *realm_data; +@@ -1675,9 +1675,6 @@ static int k5c_setup_fast(struct krb5_req *kr, char *lifetime_str, bool demand) + krb5_error_code kerr; + char *tmp_str; + +- DEBUG(SSSDBG_CONF_SETTINGS, ("%s is set to [%s]\n", +- SSSD_KRB5_LIFETIME, lifetime_str)); +- + tmp_str = getenv(SSSD_KRB5_FAST_PRINCIPAL); + if (tmp_str) { + DEBUG(SSSDBG_CONF_SETTINGS, ("%s is set to [%s]\n", +@@ -1869,9 +1866,9 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline) + if (use_fast_str == NULL || strcasecmp(use_fast_str, "never") == 0) { + DEBUG(SSSDBG_CONF_SETTINGS, ("Not using FAST.\n")); + } else if (strcasecmp(use_fast_str, "try") == 0) { +- kerr = k5c_setup_fast(kr, lifetime_str, false); ++ kerr = k5c_setup_fast(kr, false); + } else if (strcasecmp(use_fast_str, "demand") == 0) { +- kerr = k5c_setup_fast(kr, lifetime_str, true); ++ kerr = k5c_setup_fast(kr, true); + } else { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Unsupported value [%s] for krb5_use_fast.\n", +-- +1.8.5.3 + diff --git a/SOURCES/0115-krb5-child-extract-lifetime-settings-into-set_lifeti.patch b/SOURCES/0115-krb5-child-extract-lifetime-settings-into-set_lifeti.patch new file mode 100644 index 0000000..c9502fa --- /dev/null +++ b/SOURCES/0115-krb5-child-extract-lifetime-settings-into-set_lifeti.patch @@ -0,0 +1,133 @@ +From b86041a3760faa9273f1df879e8bfa38fbbb84aa Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 21 Mar 2014 12:14:11 +0100 +Subject: [PATCH 115/117] krb5-child: extract lifetime settings into + set_lifetime_options() + +Additionally the lifetime option flags are unset if there are no +explicit settings to make sure the defaults from krb5.conf are used even +if other values were set manually in between. + +Reviewed-by: Jakub Hrozek +--- + src/providers/krb5/krb5_child.c | 89 +++++++++++++++++++++++++---------------- + 1 file changed, 55 insertions(+), 34 deletions(-) + +diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c +index 7f07efc161d0242e64bd67e13dec9a3faa9f2e30..7ea111e108e189c6839feec0f1108175c0291605 100644 +--- a/src/providers/krb5/krb5_child.c ++++ b/src/providers/krb5/krb5_child.c +@@ -65,6 +65,57 @@ struct krb5_req { + static krb5_context krb5_error_ctx; + #define KRB5_CHILD_DEBUG(level, error) KRB5_DEBUG(level, krb5_error_ctx, error) + ++static krb5_error_code set_lifetime_options(krb5_get_init_creds_opt *options) ++{ ++ char *lifetime_str; ++ krb5_error_code kerr; ++ krb5_deltat lifetime; ++ ++ lifetime_str = getenv(SSSD_KRB5_RENEWABLE_LIFETIME); ++ if (lifetime_str == NULL) { ++ DEBUG(SSSDBG_CONF_SETTINGS, ("Cannot read [%s] from environment.\n", ++ SSSD_KRB5_RENEWABLE_LIFETIME)); ++ ++ /* Unset option flag to make sure defaults from krb5.conf are used. */ ++ options->flags &= ~(KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE); ++ } else { ++ kerr = krb5_string_to_deltat(lifetime_str, &lifetime); ++ if (kerr != 0) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ ("krb5_string_to_deltat failed for [%s].\n", ++ lifetime_str)); ++ KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); ++ return kerr; ++ } ++ DEBUG(SSSDBG_CONF_SETTINGS, ("%s is set to [%s]\n", ++ SSSD_KRB5_RENEWABLE_LIFETIME, lifetime_str)); ++ krb5_get_init_creds_opt_set_renew_life(options, lifetime); ++ } ++ ++ lifetime_str = getenv(SSSD_KRB5_LIFETIME); ++ if (lifetime_str == NULL) { ++ DEBUG(SSSDBG_CONF_SETTINGS, ("Cannot read [%s] from environment.\n", ++ SSSD_KRB5_LIFETIME)); ++ ++ /* Unset option flag to make sure defaults from krb5.conf are used. */ ++ options->flags &= ~(KRB5_GET_INIT_CREDS_OPT_TKT_LIFE); ++ } else { ++ kerr = krb5_string_to_deltat(lifetime_str, &lifetime); ++ if (kerr != 0) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ ("krb5_string_to_deltat failed for [%s].\n", ++ lifetime_str)); ++ KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); ++ return kerr; ++ } ++ DEBUG(SSSDBG_CONF_SETTINGS, ++ ("%s is set to [%s]\n", SSSD_KRB5_LIFETIME, lifetime_str)); ++ krb5_get_init_creds_opt_set_tkt_life(options, lifetime); ++ } ++ ++ return 0; ++} ++ + static void set_changepw_options(krb5_context ctx, + krb5_get_init_creds_opt *options) + { +@@ -1744,9 +1795,7 @@ static int k5c_setup_fast(struct krb5_req *kr, bool demand) + static int k5c_setup(struct krb5_req *kr, uint32_t offline) + { + krb5_error_code kerr; +- char *lifetime_str; + char *use_fast_str; +- krb5_deltat lifetime; + int parse_flags; + + kr->realm = getenv(SSSD_KRB5_REALM); +@@ -1825,38 +1874,10 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline) + krb5_get_init_creds_opt_set_change_password_prompt(kr->options, 0); + #endif + +- lifetime_str = getenv(SSSD_KRB5_RENEWABLE_LIFETIME); +- if (lifetime_str == NULL) { +- DEBUG(SSSDBG_CONF_SETTINGS, ("Cannot read [%s] from environment.\n", +- SSSD_KRB5_RENEWABLE_LIFETIME)); +- } else { +- kerr = krb5_string_to_deltat(lifetime_str, &lifetime); +- if (kerr != 0) { +- DEBUG(1, ("krb5_string_to_deltat failed for [%s].\n", +- lifetime_str)); +- KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); +- return kerr; +- } +- DEBUG(SSSDBG_CONF_SETTINGS, ("%s is set to [%s]\n", +- SSSD_KRB5_RENEWABLE_LIFETIME, lifetime_str)); +- krb5_get_init_creds_opt_set_renew_life(kr->options, lifetime); +- } +- +- lifetime_str = getenv(SSSD_KRB5_LIFETIME); +- if (lifetime_str == NULL) { +- DEBUG(SSSDBG_CONF_SETTINGS, ("Cannot read [%s] from environment.\n", +- SSSD_KRB5_LIFETIME)); +- } else { +- kerr = krb5_string_to_deltat(lifetime_str, &lifetime); +- if (kerr != 0) { +- DEBUG(1, ("krb5_string_to_deltat failed for [%s].\n", +- lifetime_str)); +- KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr); +- return kerr; +- } +- DEBUG(SSSDBG_CONF_SETTINGS, +- ("%s is set to [%s]\n", SSSD_KRB5_LIFETIME, lifetime_str)); +- krb5_get_init_creds_opt_set_tkt_life(kr->options, lifetime); ++ kerr = set_lifetime_options(kr->options); ++ if (kerr != 0) { ++ DEBUG(SSSDBG_OP_FAILURE, ("set_lifetime_options failed.\n")); ++ return kerr; + } + + if (!offline) { +-- +1.8.5.3 + diff --git a/SOURCES/0116-krb5_client-rename-krb5_set_canonicalize-to-set_cano.patch b/SOURCES/0116-krb5_client-rename-krb5_set_canonicalize-to-set_cano.patch new file mode 100644 index 0000000..96a23b3 --- /dev/null +++ b/SOURCES/0116-krb5_client-rename-krb5_set_canonicalize-to-set_cano.patch @@ -0,0 +1,78 @@ +From 7dbdbb87a5660128b0bbac011c3684e13380f162 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 21 Mar 2014 16:15:39 +0100 +Subject: [PATCH 116/117] krb5_client: rename krb5_set_canonicalize() to + set_canonicalize_option() + +Reviewed-by: Jakub Hrozek +--- + src/providers/krb5/krb5_child.c | 32 ++++++++++++++++---------------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c +index 7ea111e108e189c6839feec0f1108175c0291605..674dad7387c6874209ee5e491cefc18eba4a6da5 100644 +--- a/src/providers/krb5/krb5_child.c ++++ b/src/providers/krb5/krb5_child.c +@@ -116,6 +116,20 @@ static krb5_error_code set_lifetime_options(krb5_get_init_creds_opt *options) + return 0; + } + ++static void set_canonicalize_option(krb5_get_init_creds_opt *opts) ++{ ++ int canonicalize = 0; ++ char *tmp_str; ++ ++ tmp_str = getenv(SSSD_KRB5_CANONICALIZE); ++ if (tmp_str != NULL && strcasecmp(tmp_str, "true") == 0) { ++ canonicalize = 1; ++ } ++ DEBUG(SSSDBG_CONF_SETTINGS, ("%s is set to [%s]\n", ++ SSSD_KRB5_CANONICALIZE, tmp_str ? tmp_str : "not set")); ++ sss_krb5_get_init_creds_opt_set_canonicalize(opts, canonicalize); ++} ++ + static void set_changepw_options(krb5_context ctx, + krb5_get_init_creds_opt *options) + { +@@ -875,20 +889,6 @@ done: + + } + +-static void krb5_set_canonicalize(krb5_get_init_creds_opt *opts) +-{ +- int canonicalize = 0; +- char *tmp_str; +- +- tmp_str = getenv(SSSD_KRB5_CANONICALIZE); +- if (tmp_str != NULL && strcasecmp(tmp_str, "true") == 0) { +- canonicalize = 1; +- } +- DEBUG(SSSDBG_CONF_SETTINGS, ("%s is set to [%s]\n", +- SSSD_KRB5_CANONICALIZE, tmp_str ? tmp_str : "not set")); +- sss_krb5_get_init_creds_opt_set_canonicalize(opts, canonicalize); +-} +- + static krb5_error_code get_and_save_tgt_with_keytab(krb5_context ctx, + krb5_principal princ, + krb5_keytab keytab, +@@ -904,7 +904,7 @@ static krb5_error_code get_and_save_tgt_with_keytab(krb5_context ctx, + krb5_get_init_creds_opt_set_address_list(&options, NULL); + krb5_get_init_creds_opt_set_forwardable(&options, 0); + krb5_get_init_creds_opt_set_proxiable(&options, 0); +- krb5_set_canonicalize(&options); ++ set_canonicalize_option(&options); + + kerr = krb5_get_init_creds_keytab(ctx, &creds, princ, keytab, 0, NULL, + &options); +@@ -1881,7 +1881,7 @@ static int k5c_setup(struct krb5_req *kr, uint32_t offline) + } + + if (!offline) { +- krb5_set_canonicalize(kr->options); ++ set_canonicalize_option(kr->options); + + use_fast_str = getenv(SSSD_KRB5_USE_FAST); + if (use_fast_str == NULL || strcasecmp(use_fast_str, "never") == 0) { +-- +1.8.5.3 + diff --git a/SOURCES/0117-krb5-child-add-revert_changepw_options.patch b/SOURCES/0117-krb5-child-add-revert_changepw_options.patch new file mode 100644 index 0000000..10478f3 --- /dev/null +++ b/SOURCES/0117-krb5-child-add-revert_changepw_options.patch @@ -0,0 +1,59 @@ +From 62b3828dae4445e30d948cf858e0ecbe120eaf36 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 21 Mar 2014 16:16:23 +0100 +Subject: [PATCH 117/117] krb5-child: add revert_changepw_options() + +After changing the Kerberos password krb5-child will try to get a fresh +TGT with the new password. This patch tries to make sure the right gic +options are used. + +Resolves: https://fedorahosted.org/sssd/ticket/2289 + +Reviewed-by: Jakub Hrozek +--- + src/providers/krb5/krb5_child.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c +index 674dad7387c6874209ee5e491cefc18eba4a6da5..97c5a590ad78080613325b5a397ac965905932fd 100644 +--- a/src/providers/krb5/krb5_child.c ++++ b/src/providers/krb5/krb5_child.c +@@ -140,6 +140,24 @@ static void set_changepw_options(krb5_context ctx, + krb5_get_init_creds_opt_set_tkt_life(options, 5*60); + } + ++static void revert_changepw_options(krb5_get_init_creds_opt *options) ++{ ++ krb5_error_code kerr; ++ ++ set_canonicalize_option(options); ++ ++ /* Currently we do not set forwardable and proxiable explicitly, the flags ++ * must be removed so that libkrb5 can take the defaults from krb5.conf */ ++ options->flags &= ~(KRB5_GET_INIT_CREDS_OPT_FORWARDABLE); ++ options->flags &= ~(KRB5_GET_INIT_CREDS_OPT_PROXIABLE); ++ ++ kerr = set_lifetime_options(options); ++ if (kerr != 0) { ++ DEBUG(SSSDBG_OP_FAILURE, ("set_lifetime_options failed.\n")); ++ } ++} ++ ++ + static errno_t sss_send_pac(krb5_authdata **pac_authdata) + { + struct sss_cli_req_data sss_data; +@@ -1187,6 +1205,10 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim) + + krb5_free_cred_contents(kr->ctx, kr->creds); + ++ /* We changed some of the gic options for the password change, now we have ++ * to change them back to get a fresh TGT. */ ++ revert_changepw_options(kr->options); ++ + kerr = get_and_save_tgt(kr, newpassword); + + sss_authtok_set_empty(kr->pd->newauthtok); +-- +1.8.5.3 + diff --git a/SOURCES/0118-KRB5-Do-not-attempt-to-get-a-TGT-after-a-password-ch.patch b/SOURCES/0118-KRB5-Do-not-attempt-to-get-a-TGT-after-a-password-ch.patch new file mode 100644 index 0000000..700c581 --- /dev/null +++ b/SOURCES/0118-KRB5-Do-not-attempt-to-get-a-TGT-after-a-password-ch.patch @@ -0,0 +1,164 @@ +From a9278ff6f7b387c529c3b57251974403c5990d44 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 18 Mar 2014 16:48:11 +0100 +Subject: [PATCH] KRB5: Do not attempt to get a TGT after a password change + using OTP + +https://fedorahosted.org/sssd/ticket/2271 + +The current krb5_child code attempts to get a TGT for the convenience of +the user using the new password after a password change operation. +However, an OTP should never be used twice, which means we can't perform +the kinit operation after chpass is finished. Instead, we only print a +PAM information instructing the user to log out and back in manually. +--- + src/providers/krb5/krb5_auth.c | 21 ++++++++++++++++++--- + src/providers/krb5/krb5_child.c | 12 ++++++++++++ + src/sss_client/pam_sss.c | 19 +++++++++++++++++++ + src/sss_client/sss_cli.h | 3 +++ + 4 files changed, 52 insertions(+), 3 deletions(-) + +diff --git a/src/providers/krb5/krb5_auth.c b/src/providers/krb5/krb5_auth.c +index ce461f5adefc6e42fdc69726ff71d23526375c0c..48c0746efc3d136a1f13e8982384d503d8d20723 100644 +--- a/src/providers/krb5/krb5_auth.c ++++ b/src/providers/krb5/krb5_auth.c +@@ -815,6 +815,7 @@ static void krb5_auth_done(struct tevent_req *subreq) + char *renew_interval_str; + time_t renew_interval_time = 0; + bool use_enterprise_principal; ++ uint32_t user_info_type; + + ret = handle_child_recv(subreq, pd, &buf, &len); + talloc_zfree(subreq); +@@ -1062,9 +1063,23 @@ static void krb5_auth_done(struct tevent_req *subreq) + + ret = sss_krb5_check_ccache_princ(kr->uid, kr->gid, kr->ccname, kr->upn); + if (ret) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- ("No ccache for %s in %s?\n", kr->upn, kr->ccname)); +- goto done; ++ if (res->otp == true && pd->cmd == SSS_PAM_CHAUTHTOK) { ++ DEBUG(SSSDBG_IMPORTANT_INFO, ++ ("Password change succeeded but currently " ++ "post-chpass kinit is not implemented\n")); ++ ++ user_info_type = SSS_PAM_USER_INFO_OTP_CHPASS; ++ ret = pam_add_response(pd, SSS_PAM_USER_INFO, sizeof(uint32_t), ++ (const uint8_t *) &user_info_type); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("pam_add_response failed.\n")); ++ /* Not fatal */ ++ } ++ } else { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ ("No ccache for %s in %s?\n", kr->upn, kr->ccname)); ++ goto done; ++ } + } + + if (kr->old_ccname) { +diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c +index d000d70167936b09bbaa39ec7a665089572d9aaa..3ee49e4678078d15dab98eeddf56d36f87955dcf 100644 +--- a/src/providers/krb5/krb5_child.c ++++ b/src/providers/krb5/krb5_child.c +@@ -45,6 +45,7 @@ struct krb5_req { + krb5_principal princ; + char* name; + krb5_creds *creds; ++ bool otp; + krb5_get_init_creds_opt *options; + + struct pam_data *pd; +@@ -370,6 +371,8 @@ static krb5_error_code answer_otp(krb5_context ctx, + goto done; + } + ++ kr->otp = true; ++ + /* Validate our assumptions about the contents of authtok. */ + ret = sss_authtok_get_password(kr->pd->authtok, &pwd, &len); + if (ret != EOK) +@@ -694,6 +697,8 @@ static errno_t k5c_send_data(struct krb5_req *kr, int fd, errno_t error) + size_t len; + int ret; + ++ DEBUG(SSSDBG_FUNC_DATA, ("Received error code %d\n", error)); ++ + ret = pack_response_packet(kr, error, kr->pd->resp_list, &buf, &len); + if (ret != EOK) { + DEBUG(1, ("pack_response_packet failed.\n")); +@@ -1110,6 +1115,8 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim) + prompter, kr, 0, + SSSD_KRB5_CHANGEPW_PRINCIPAL, + kr->options); ++ DEBUG(SSSDBG_TRACE_INTERNAL, ++ ("chpass is%s using OTP\n", kr->otp ? "" : " not")); + if (kerr != 0) { + ret = pack_user_info_chpass_error(kr->pd, "Old password not accepted.", + &msg_len, &msg); +@@ -1205,6 +1212,11 @@ static errno_t changepw_child(struct krb5_req *kr, bool prelim) + + krb5_free_cred_contents(kr->ctx, kr->creds); + ++ if (kr->otp == true) { ++ sss_authtok_set_empty(kr->pd->newauthtok); ++ return map_krb5_error(kerr); ++ } ++ + /* We changed some of the gic options for the password change, now we have + * to change them back to get a fresh TGT. */ + revert_changepw_options(kr->options); +diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c +index 4ff38f299bec75a49c8aace06eecab5735ca9443..e629fc19bd705ac35c2fa1ea4946f40c5eb49079 100644 +--- a/src/sss_client/pam_sss.c ++++ b/src/sss_client/pam_sss.c +@@ -771,6 +771,22 @@ static int user_info_offline_chpass(pam_handle_t *pamh) + return PAM_SUCCESS; + } + ++static int user_info_otp_chpass(pam_handle_t *pamh) ++{ ++ int ret; ++ ++ ret = do_pam_conversation(pamh, PAM_TEXT_INFO, ++ _("After changing the OTP password, you need to " ++ "log out and back in order to acquire a ticket"), ++ NULL, NULL); ++ if (ret != PAM_SUCCESS) { ++ D(("do_pam_conversation failed.")); ++ return PAM_SYSTEM_ERR; ++ } ++ ++ return PAM_SUCCESS; ++} ++ + static int user_info_chpass_error(pam_handle_t *pamh, size_t buflen, + uint8_t *buf) + { +@@ -856,6 +872,9 @@ static int eval_user_info_response(pam_handle_t *pamh, size_t buflen, + case SSS_PAM_USER_INFO_OFFLINE_CHPASS: + ret = user_info_offline_chpass(pamh); + break; ++ case SSS_PAM_USER_INFO_OTP_CHPASS: ++ ret = user_info_otp_chpass(pamh); ++ break; + case SSS_PAM_USER_INFO_CHPASS_ERROR: + ret = user_info_chpass_error(pamh, buflen, buf); + break; +diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h +index 285a2979addb0c0677527b76b3b6755f2f173815..16a08e1869bb81ede2c1db87f1fb6d0a51087847 100644 +--- a/src/sss_client/sss_cli.h ++++ b/src/sss_client/sss_cli.h +@@ -451,6 +451,9 @@ enum user_info_type { + * possible to change the password while + * the system is offline. This message + * is generated by the PAM responder. */ ++ SSS_PAM_USER_INFO_OTP_CHPASS, /**< Tell the user that he needs to kinit ++ * or login and logout to get a TGT after ++ * an OTP password change */ + SSS_PAM_USER_INFO_CHPASS_ERROR, /**< Tell the user that a password change + * failed and optionally give a reason. + * @param Size of the message as unsigned +-- +1.8.5.3 + diff --git a/SOURCES/0119-IPA-Use-function-sysdb_attrs_get_el-in-safe-way.patch b/SOURCES/0119-IPA-Use-function-sysdb_attrs_get_el-in-safe-way.patch new file mode 100644 index 0000000..2aa64b7 --- /dev/null +++ b/SOURCES/0119-IPA-Use-function-sysdb_attrs_get_el-in-safe-way.patch @@ -0,0 +1,76 @@ +From a9385ea99d15976c5e7585059945f6964f85339c Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Tue, 25 Mar 2014 17:57:32 +0100 +Subject: [PATCH] IPA: Use function sysdb_attrs_get_el in safe way + +Function sysdb_attrs_get_el can enlarge array of ldb_message_element in "struct +sysdb_attrs" if attribute is not among available attributes. Array will be +enlarged with function talloc_realloc but realloc can move array to another +place in memory therefore ldb_message_element should not be used after next +call of function sysdb_attrs_get_el + + sysdb_attrs_get_el(netgroup, SYSDB_ORIG_MEMBER_USER, &user_found); + sysdb_attrs_get_el(netgroup, SYSDB_ORIG_MEMBER_HOST, &host_found); +With netgroups, it is common to omit user or host from netgroup triple. +There is very high probability that realloc will be called. it is possible +pointer user_found can refer to the old area after the second call of function +sysdb_attrs_get_el. + +Resolves: +https://fedorahosted.org/sssd/ticket/2284 +--- + src/providers/ipa/ipa_netgroups.c | 17 +++++++---------- + 1 file changed, 7 insertions(+), 10 deletions(-) + +diff --git a/src/providers/ipa/ipa_netgroups.c b/src/providers/ipa/ipa_netgroups.c +index 49a4ba9ab60a05b31241916cf0a7669c785764d4..9cc374bc17eb53accaf607736a19555e17ebf4e1 100644 +--- a/src/providers/ipa/ipa_netgroups.c ++++ b/src/providers/ipa/ipa_netgroups.c +@@ -297,9 +297,7 @@ static void ipa_get_netgroups_process(struct tevent_req *subreq) + struct ipa_get_netgroups_state *state = tevent_req_data(req, + struct ipa_get_netgroups_state); + int i, ret; +- struct ldb_message_element *ng_found; +- struct ldb_message_element *host_found; +- struct ldb_message_element *user_found; ++ struct ldb_message_element *el; + struct sdap_search_base **netgr_bases; + struct sysdb_attrs **netgroups; + size_t netgroups_count; +@@ -345,16 +343,19 @@ static void ipa_get_netgroups_process(struct tevent_req *subreq) + + for (i = 0; i < netgroups_count; i++) { + ret = sysdb_attrs_get_el(netgroups[i], SYSDB_ORIG_NETGROUP_MEMBER, +- &ng_found); ++ &el); + if (ret != EOK) goto done; ++ if (el->num_values) state->entities_found |= ENTITY_NG; + + ret = sysdb_attrs_get_el(netgroups[i], SYSDB_ORIG_MEMBER_USER, +- &user_found); ++ &el); + if (ret != EOK) goto done; ++ if (el->num_values) state->entities_found |= ENTITY_USER; + + ret = sysdb_attrs_get_el(netgroups[i], SYSDB_ORIG_MEMBER_HOST, +- &host_found); ++ &el); + if (ret != EOK) goto done; ++ if (el->num_values) state->entities_found |= ENTITY_HOST; + + ret = sysdb_attrs_get_string(netgroups[i], SYSDB_ORIG_DN, &orig_dn); + if (ret != EOK) { +@@ -371,10 +372,6 @@ static void ipa_get_netgroups_process(struct tevent_req *subreq) + goto done; + } + +- if (ng_found->num_values) state->entities_found |= ENTITY_NG; +- if (user_found->num_values) state->entities_found |= ENTITY_USER; +- if (host_found->num_values) state->entities_found |= ENTITY_HOST; +- + if (state->entities_found == 0) { + continue; + } +-- +1.8.5.3 + diff --git a/SOURCES/0120-AD-connect-to-forest-root-when-downloading-the-list-.patch b/SOURCES/0120-AD-connect-to-forest-root-when-downloading-the-list-.patch new file mode 100644 index 0000000..de10d29 --- /dev/null +++ b/SOURCES/0120-AD-connect-to-forest-root-when-downloading-the-list-.patch @@ -0,0 +1,478 @@ +From d97ff9abd276e9216e5868be37c3762d208b36c0 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 1 Apr 2014 13:51:49 -0400 +Subject: [PATCH 120/120] AD: connect to forest root when downloading the list + of subdomains + +https://fedorahosted.org/sssd/ticket/2285 + +Only the forest root has the knowledge about all the domains in the forest, +the forest leaves only see themselves and the forest root. + +This patch switches to connecting to the forest root for downloading the +trusted domains instead of the server we are connected to. +--- + src/providers/ad/ad_subdomains.c | 372 ++++++++++++++++++++++++++++++++++++++- + 1 file changed, 363 insertions(+), 9 deletions(-) + +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index 0d9652b5c615add47958cfdc61eba862a332ae4d..3c841788d5d88069d79a9438b72f57c8c2e0ffda 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -54,7 +54,9 @@ + * the same forest. See http://msdn.microsoft.com/en-us/library/cc223786.aspx + * for more information. + */ +-#define SLAVE_DOMAIN_FILTER "(&(objectclass=trustedDomain)(trustType=2)(!(msDS-TrustForestTrustInfo=*)))" ++#define SLAVE_DOMAIN_FILTER_BASE "(objectclass=trustedDomain)(trustType=2)(!(msDS-TrustForestTrustInfo=*))" ++#define SLAVE_DOMAIN_FILTER "(&"SLAVE_DOMAIN_FILTER_BASE")" ++#define FOREST_ROOT_FILTER_FMT "(&"SLAVE_DOMAIN_FILTER_BASE"(cn=%s))" + + /* do not refresh more often than every 5 seconds for now */ + #define AD_SUBDOMAIN_REFRESH_LIMIT 5 +@@ -80,6 +82,11 @@ struct ad_subdomains_req_ctx { + char *current_filter; + size_t base_iter; + ++ struct ad_id_ctx *root_id_ctx; ++ struct sdap_id_op *root_op; ++ size_t root_base_iter; ++ struct sysdb_attrs *root_domain; ++ + size_t reply_count; + struct sysdb_attrs **reply; + +@@ -461,6 +468,7 @@ static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *ctx) + + static void ad_subdomains_get_conn_done(struct tevent_req *req); + static void ad_subdomains_master_dom_done(struct tevent_req *req); ++static errno_t ad_subdomains_get_root(struct ad_subdomains_req_ctx *ctx); + static errno_t ad_subdomains_get_slave(struct ad_subdomains_req_ctx *ctx); + + static void ad_subdomains_retrieve(struct ad_subdomains_ctx *ctx, +@@ -481,6 +489,10 @@ static void ad_subdomains_retrieve(struct ad_subdomains_ctx *ctx, + req_ctx->sd_ctx = ctx; + req_ctx->current_filter = NULL; + req_ctx->base_iter = 0; ++ req_ctx->root_base_iter = 0; ++ req_ctx->root_id_ctx = NULL; ++ req_ctx->root_op = NULL; ++ req_ctx->root_domain = NULL; + req_ctx->reply_count = 0; + req_ctx->reply = NULL; + +@@ -575,7 +587,20 @@ static void ad_subdomains_master_dom_done(struct tevent_req *req) + goto done; + } + +- ret = ad_subdomains_get_slave(ctx); ++ if (strcasecmp(ctx->sd_ctx->be_ctx->domain->name, ctx->forest) != 0) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ ("SSSD needs to look up the forest root domain\n")); ++ ret = ad_subdomains_get_root(ctx); ++ } else { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ ("Connected to forest root, looking up child domains..\n")); ++ ++ ctx->root_op = ctx->sdap_op; ++ ctx->root_id_ctx = ctx->sd_ctx->ad_id_ctx; ++ ++ ret = ad_subdomains_get_slave(ctx); ++ } ++ + if (ret == EAGAIN) { + return; + } else if (ret != EOK) { +@@ -586,6 +611,244 @@ done: + be_req_terminate(ctx->be_req, DP_ERR_FATAL, ret, NULL); + } + ++static void ad_subdomains_get_root_domain_done(struct tevent_req *req); ++ ++static errno_t ad_subdomains_get_root(struct ad_subdomains_req_ctx *ctx) ++{ ++ struct tevent_req *req; ++ struct sdap_search_base *base; ++ struct sdap_id_ctx *sdap_id_ctx; ++ char *filter; ++ const char *forest_root_attrs[] = { AD_AT_FLATNAME, AD_AT_TRUST_PARTNER, ++ AD_AT_SID, AD_AT_TRUST_TYPE, ++ AD_AT_TRUST_ATTRS, NULL }; ++ ++ sdap_id_ctx = ctx->sd_ctx->sdap_id_ctx; ++ base = sdap_id_ctx->opts->sdom->search_bases[ctx->root_base_iter]; ++ if (base == NULL) { ++ return EOK; ++ } ++ ++ filter = talloc_asprintf(ctx, FOREST_ROOT_FILTER_FMT, ctx->forest); ++ if (filter == NULL) { ++ return ENOMEM; ++ } ++ ++ req = sdap_get_generic_send(ctx, ctx->sd_ctx->be_ctx->ev, ++ sdap_id_ctx->opts, ++ sdap_id_op_handle(ctx->sdap_op), ++ base->basedn, LDAP_SCOPE_SUBTREE, ++ filter, forest_root_attrs, ++ NULL, 0, ++ dp_opt_get_int(sdap_id_ctx->opts->basic, ++ SDAP_SEARCH_TIMEOUT), ++ false); ++ ++ if (req == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ("sdap_get_generic_send failed.\n")); ++ return ENOMEM; ++ } ++ ++ tevent_req_set_callback(req, ad_subdomains_get_root_domain_done, ctx); ++ return EAGAIN; ++} ++ ++static struct ad_id_ctx *ads_get_root_id_ctx(struct ad_subdomains_req_ctx *ctx); ++static void ad_subdomains_root_conn_done(struct tevent_req *req); ++ ++static void ad_subdomains_get_root_domain_done(struct tevent_req *req) ++{ ++ int ret; ++ size_t reply_count; ++ struct sysdb_attrs **reply = NULL; ++ struct ad_subdomains_req_ctx *ctx; ++ int dp_error = DP_ERR_FATAL; ++ bool has_changes; ++ ++ ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx); ++ ++ ret = sdap_get_generic_recv(req, ctx, &reply_count, &reply); ++ talloc_zfree(req); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("sdap_get_generic_send request failed.\n")); ++ goto fail; ++ } ++ ++ if (reply_count == 0) { ++ /* If no root domain was found in the default search base, try the ++ * next one, if available ++ */ ++ ctx->root_base_iter++; ++ ret = ad_subdomains_get_root(ctx); ++ if (ret == EAGAIN) { ++ return; ++ } ++ ++ goto fail; ++ } else if (reply_count > 1) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ ("Multiple results for root domain search, " ++ "domain list might be incomplete!\n")); ++ ++ ctx->root_op = ctx->sdap_op; ++ ctx->root_id_ctx = ctx->sd_ctx->ad_id_ctx; ++ ++ ret = ad_subdomains_get_slave(ctx); ++ if (ret == EAGAIN) { ++ return; ++ } ++ ++ goto fail; ++ } ++ /* Exactly one result, good. */ ++ ++ /* We won't use the operation to the local LDAP anymore, but ++ * read from the forest root ++ */ ++ ret = sdap_id_op_done(ctx->sdap_op, ret, &dp_error); ++ if (ret != EOK) { ++ if (dp_error == DP_ERR_OFFLINE) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ ("No AD server is available, cannot get the " ++ "subdomain list while offline\n")); ++ } else { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("Failed to search the AD server: [%d](%s)\n", ++ ret, strerror(ret))); ++ } ++ goto fail; ++ } ++ ++ ret = ad_subdomains_refresh(ctx->sd_ctx, 1, reply, &has_changes); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("ad_subdomains_refresh failed.\n")); ++ goto fail; ++ } ++ ++ if (has_changes) { ++ ret = ad_subdom_reinit(ctx->sd_ctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Could not reinitialize subdomains\n")); ++ goto fail; ++ } ++ } ++ ++ ctx->root_domain = reply[0]; ++ ctx->root_id_ctx = ads_get_root_id_ctx(ctx); ++ if (ctx->root_id_ctx == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("Cannot create id ctx for the root domain\n")); ++ ret = EFAULT; ++ goto fail; ++ } ++ ++ ctx->root_op = sdap_id_op_create(ctx, ++ ctx->root_id_ctx->ldap_ctx->conn_cache); ++ if (ctx->root_op == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ("sdap_id_op_create failed.\n")); ++ ret = ENOMEM; ++ goto fail; ++ } ++ ++ req = sdap_id_op_connect_send(ctx->root_op, ctx, &ret); ++ if (req == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ("sdap_id_op_connect_send failed: %d(%s).\n", ++ ret, strerror(ret))); ++ goto fail; ++ } ++ ++ tevent_req_set_callback(req, ad_subdomains_root_conn_done, ctx); ++ return; ++ ++fail: ++ if (ret == EOK) { ++ ctx->sd_ctx->last_refreshed = time(NULL); ++ dp_error = DP_ERR_OK; ++ } ++ be_req_terminate(ctx->be_req, dp_error, ret, NULL); ++} ++ ++static struct ad_id_ctx *ads_get_root_id_ctx(struct ad_subdomains_req_ctx *ctx) ++{ ++ errno_t ret; ++ const char *name; ++ struct sss_domain_info *root; ++ struct sdap_domain *sdom; ++ struct ad_id_ctx *root_id_ctx; ++ ++ ret = sysdb_attrs_get_string(ctx->root_domain, 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 */ ++ root = find_subdomain_by_name(ctx->sd_ctx->be_ctx->domain, ++ name, false); ++ if (root == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Could not find the root domain\n")); ++ return NULL; ++ } ++ ++ sdom = sdap_domain_get(ctx->sd_ctx->ad_id_ctx->sdap_id_ctx->opts, root); ++ if (sdom == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("Cannot get the sdom for %s!\n", root->name)); ++ return NULL; ++ } ++ ++ if (sdom->pvt == NULL) { ++ ret = ad_subdom_ad_ctx_new(ctx->sd_ctx->be_ctx, ++ ctx->sd_ctx->ad_id_ctx, ++ root, ++ &root_id_ctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("ad_subdom_ad_ctx_new failed.\n")); ++ return NULL; ++ } ++ sdom->pvt = root_id_ctx; ++ } else { ++ root_id_ctx = sdom->pvt; ++ } ++ ++ return root_id_ctx; ++} ++ ++static void ad_subdomains_root_conn_done(struct tevent_req *req) ++{ ++ int ret; ++ int dp_error = DP_ERR_FATAL; ++ struct ad_subdomains_req_ctx *ctx; ++ ++ ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx); ++ ++ ret = sdap_id_op_connect_recv(req, &dp_error); ++ talloc_zfree(req); ++ if (ret) { ++ if (dp_error == DP_ERR_OFFLINE) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ ("No AD server is available, cannot get the " ++ "subdomain list while offline\n")); ++ } else { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("Failed to connect to AD server: [%d](%s)\n", ++ ret, strerror(ret))); ++ } ++ ++ goto fail; ++ } ++ ++ ret = ad_subdomains_get_slave(ctx); ++ if (ret == EAGAIN) { ++ return; ++ } else if (ret != EOK) { ++ goto fail; ++ } ++ ++fail: ++ be_req_terminate(ctx->be_req, dp_error, ret, NULL); ++} ++ + static void ad_subdomains_get_slave_domain_done(struct tevent_req *req); + + static errno_t ad_subdomains_get_slave(struct ad_subdomains_req_ctx *ctx) +@@ -596,18 +859,18 @@ static errno_t ad_subdomains_get_slave(struct ad_subdomains_req_ctx *ctx) + AD_AT_SID, AD_AT_TRUST_TYPE, + AD_AT_TRUST_ATTRS, NULL }; + +- base = ctx->sd_ctx->sdap_id_ctx->opts->sdom->search_bases[ctx->base_iter]; ++ base = ctx->root_id_ctx->sdap_id_ctx->opts->sdom->search_bases[ctx->base_iter]; + if (base == NULL) { + return EOK; + } + + req = sdap_get_generic_send(ctx, ctx->sd_ctx->be_ctx->ev, +- ctx->sd_ctx->sdap_id_ctx->opts, +- sdap_id_op_handle(ctx->sdap_op), ++ ctx->root_id_ctx->sdap_id_ctx->opts, ++ sdap_id_op_handle(ctx->root_op), + base->basedn, LDAP_SCOPE_SUBTREE, + SLAVE_DOMAIN_FILTER, slave_dom_attrs, + NULL, 0, +- dp_opt_get_int(ctx->sd_ctx->sdap_id_ctx->opts->basic, ++ dp_opt_get_int(ctx->root_id_ctx->sdap_id_ctx->opts->basic, + SDAP_SEARCH_TIMEOUT), + false); + +@@ -620,6 +883,68 @@ static errno_t ad_subdomains_get_slave(struct ad_subdomains_req_ctx *ctx) + return EAGAIN; + } + ++static errno_t ad_subdomains_process(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain, ++ size_t nsd, struct sysdb_attrs **sd, ++ struct sysdb_attrs *root, ++ size_t *_nsd_out, ++ struct sysdb_attrs ***_sd_out) ++{ ++ size_t i, sdi; ++ struct sysdb_attrs **sd_out; ++ const char *sd_name; ++ errno_t ret; ++ ++ if (root == NULL) { ++ /* We are connected directly to the root domain. The 'sd' ++ * list is complete and we can just use it ++ */ ++ *_nsd_out = nsd; ++ *_sd_out = sd; ++ return EOK; ++ } ++ ++ /* If we searched for root separately, we must: ++ * a) treat the root domain as a subdomain ++ * b) filter the subdomain we are connected to from the subdomain ++ * list, from our point of view, it's the master domain ++ */ ++ sd_out = talloc_zero_array(mem_ctx, struct sysdb_attrs *, nsd+1); ++ if (sd_out == NULL) { ++ return ENOMEM; ++ } ++ ++ sdi = 0; ++ for (i = 0; i < nsd; i++) { ++ ret = sysdb_attrs_get_string(sd[i], AD_AT_TRUST_PARTNER, &sd_name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("sysdb_attrs_get_string failed.\n")); ++ goto fail; ++ } ++ ++ if (strcasecmp(sd_name, domain->name) == 0) { ++ DEBUG(SSSDBG_TRACE_INTERNAL, ++ ("Not including primary domain %s in the subdomain list\n", ++ domain->name)); ++ continue; ++ } ++ ++ sd_out[sdi] = talloc_steal(sd_out, sd[i]); ++ sdi++; ++ } ++ ++ /* Now include the root */ ++ sd_out[sdi] = talloc_steal(sd_out, root); ++ ++ *_nsd_out = sdi+1; ++ *_sd_out = sd_out; ++ return EOK; ++ ++fail: ++ talloc_free(sd_out); ++ return ret; ++} ++ + static void ad_subdomains_get_slave_domain_done(struct tevent_req *req) + { + int ret; +@@ -628,6 +953,8 @@ static void ad_subdomains_get_slave_domain_done(struct tevent_req *req) + struct ad_subdomains_req_ctx *ctx; + int dp_error = DP_ERR_FATAL; + bool refresh_has_changes = false; ++ size_t nsubdoms; ++ struct sysdb_attrs **subdoms; + + ctx = tevent_req_callback_data(req, struct ad_subdomains_req_ctx); + +@@ -653,13 +980,40 @@ static void ad_subdomains_get_slave_domain_done(struct tevent_req *req) + ctx->base_iter++; + ret = ad_subdomains_get_slave(ctx); + if (ret == EAGAIN) { ++ /* Search in progress */ ++ return; ++ } ++ ++ ret = sdap_id_op_done(ctx->root_op, ret, &dp_error); ++ if (ret != EOK) { ++ if (dp_error == DP_ERR_OFFLINE) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ ("No AD server is available, cannot get the " ++ "subdomain list while offline\n")); ++ } else { ++ DEBUG(SSSDBG_OP_FAILURE, ++ ("Failed to search the AD server: [%d](%s)\n", ++ ret, strerror(ret))); ++ } ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ /* Based on whether we are connected to the forest root or not, we might ++ * need to exclude the subdomain we are connected to from the list of ++ * subdomains ++ */ ++ ret = ad_subdomains_process(ctx, ctx->sd_ctx->be_ctx->domain, ++ ctx->reply_count, ctx->reply, ++ ctx->root_domain, &nsubdoms, &subdoms); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ("Cannot process subdomain list\n")); ++ tevent_req_error(req, ret); + return; +- } else if (ret != EOK) { +- goto done; + } + + /* Got all the subdomains, let's process them */ +- ret = ad_subdomains_refresh(ctx->sd_ctx, ctx->reply_count, ctx->reply, ++ ret = ad_subdomains_refresh(ctx->sd_ctx, nsubdoms, subdoms, + &refresh_has_changes); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Failed to refresh subdomains.\n")); +-- +1.9.0 + diff --git a/SOURCES/0121-IPA-Fix-SELinux-mapping-order-memory-hierarchy.patch b/SOURCES/0121-IPA-Fix-SELinux-mapping-order-memory-hierarchy.patch new file mode 100644 index 0000000..e48bd0e --- /dev/null +++ b/SOURCES/0121-IPA-Fix-SELinux-mapping-order-memory-hierarchy.patch @@ -0,0 +1,64 @@ +From 1a088724c4d70edfbecab4252c1644100374f0f0 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 2 Apr 2014 22:11:59 +0200 +Subject: [PATCH 121/121] IPA: Fix SELinux mapping order memory hierarchy + +https://fedorahosted.org/sssd/ticket/2300 + +The list of SELinux mapping orders was allocated on tmp_ctx and parsed +into an array. The array itself was correctly allocated on mem_ctx but +its contents remained on tmp_ctx, leading to a use-after-free error. +This patch fixes the memory hierarchy so that both the array and its +contents are allocated on mem_ctx. + +(cherry picked from commit 355b8a655cfcc4e783077d12f76b55da1d23fb87) + +Reviewed-by: Sumit Bose +--- + src/providers/ipa/ipa_selinux.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c +index 7f59161918a04ff8c994a0ce0fe55924ff09eda7..b7cbe445f1ecbfffaa84bb049aaf45ba4ecb1a35 100644 +--- a/src/providers/ipa/ipa_selinux.c ++++ b/src/providers/ipa/ipa_selinux.c +@@ -557,21 +557,15 @@ static errno_t create_order_array(TALLOC_CTX *mem_ctx, const char *map_order, + goto done; + } + +- order = talloc_strdup(tmp_ctx, map_order); +- if (order == NULL) { +- ret = ENOMEM; +- goto done; +- } +- len = strlen(order); +- + /* The "order" string contains one or more SELinux user records + * separated by $. Now we need to create an array of string from + * this one string. First find out how many elements in the array + * will be. This way only one alloc will be necessary for the array + */ + order_count = 1; ++ len = strlen(map_order); + for (i = 0; i < len; i++) { +- if (order[i] == '$') order_count++; ++ if (map_order[i] == '$') order_count++; + } + + order_array = talloc_array(tmp_ctx, char *, order_count); +@@ -580,6 +574,12 @@ static errno_t create_order_array(TALLOC_CTX *mem_ctx, const char *map_order, + goto done; + } + ++ order = talloc_strdup(order_array, map_order); ++ if (order == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ + /* Now fill the array with pointers to the original string. Also + * use binary zeros to make multiple string out of the one. + */ +-- +1.9.0 + diff --git a/SPECS/sssd.spec b/SPECS/sssd.spec index 93d9fdc..c35d49c 100644 --- a/SPECS/sssd.spec +++ b/SPECS/sssd.spec @@ -8,7 +8,7 @@ Name: sssd Version: 1.11.2 -Release: 1%{?dist} +Release: 65%{?dist} Group: Applications/System Summary: System Security Services Daemon License: GPLv3+ @@ -17,6 +17,128 @@ Source0: https://fedorahosted.org/released/sssd/%{name}-%{version}.tar.gz BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) ### Patches ### +Patch0001: 0001-SYSDB-Skip-malformed-netgroup-attribute.patch +Patch0002: 0002-monitor-Specific-error-message-for-missing-sssd.conf.patch +Patch0003: 0003-AD-Fix-a-typo-in-the-man-page.patch +Patch0004: 0004-LDAP-Initialize-user-count-for-AD-matching-rule.patch +Patch0005: 0005-SSSD-Improved-domain-detection.patch +Patch0006: 0006-SSSD-Unit-test-sss_ldap_dn_in_search_bases.patch +Patch0007: 0007-do-not-use-default_domain_suffix-with-autofs.patch +Patch0008: 0008-SYSDB-Sanitize-filter-before-sysdb_search_groups.patch +Patch0009: 0009-SYSDB-Sanitize-filter-before-removing-ghost-attrs.patch +Patch0010: 0010-LDAP-Split-out-a-request-to-search-for-a-user-w-o-sa.patch +Patch0011: 0011-LDAP-Search-for-original-DN-during-auth-if-it-s-miss.patch +Patch0012: 0012-LDAP-Prevent-from-using-uninitialized-sdap_options.patch +Patch0013: 0013-SUBDOMAINS-Reuse-cached-results-if-DP-is-offline.patch +Patch0014: 0014-failover-check-dns_domain-if-primary-servers-lookup-.patch +Patch0015: 0015-NSS-Set-packet-length-for-initgroups.patch +Patch0016: 0016-NSS-Fix-memory-leak-in-sss_setnetgrent.patch +Patch0017: 0017-AD-use-LDAP-for-group-lookups.patch +Patch0018: 0018-idmap-add-API-to-free-allocated-SIDs.patch +Patch0019: 0019-free-idmapped-SIDs-correctly.patch +Patch0020: 0020-free-idmapped-dom-SIDs-correctly.patch +Patch0021: 0021-free-idmapped-smb-SIDs-correctly.patch +Patch0022: 0022-free-idmapped-binary-SIDs-correctly.patch +Patch0023: 0023-Initialize-sid_str-to-NULL-to-avoid-freeing-random-d.patch +Patch0024: 0024-ad-refactor-tokengroups-initgroups.patch +Patch0025: 0025-ad-use-tokengroups-even-when-id-mapping-is-disabled.patch +Patch0026: 0026-AD-filter-domain-local-groups-for-trusted-sub-domain.patch +Patch0027: 0027-AD-cross-domain-membership-fix.patch +Patch0028: 0028-AD-Add-a-utility-function-to-create-list-of-connecti.patch +Patch0029: 0029-AD-Add-a-new-option-to-turn-off-GC-lookups.patch +Patch0030: 0030-AD-Enable-fallback-to-LDAP-of-trusted-domain.patch +Patch0031: 0031-Bump-sss_idmap-version-to-3-0-3.patch +Patch0032: 0032-AD-Refresh-subdomain-data-structures-on-startup.patch +Patch0033: 0033-IPA-Refresh-subdomain-data-structures-on-startup.patch +Patch0034: 0034-IPA-Call-ipa_ad_subdom_refresh-when-server-mode-is-i.patch +Patch0035: 0035-sss_cache-initialize-names-member-of-sss_domain_info.patch +Patch0036: 0036-sss_cache-fix-case-sensitivity-issue.patch +Patch0037: 0037-Add-sysdb_attrs_add_lc_name_alias.patch +Patch0038: 0038-Use-sysdb_attrs_add_lc_name_alias-to-add-case-insens.patch +Patch0039: 0039-Use-lower-case-name-for-case-insensitive-searches.patch +Patch0040: 0040-Add-new-option-ldap_group_type.patch +Patch0041: 0041-Add-sysdb_attrs_get_int32_t.patch +Patch0042: 0042-IPA-fix-for-recent-AD-group-membership-changes.patch +Patch0043: 0043-LDAP-Fix-typo-and-use-the-right-attribute-map.patch +Patch0044: 0044-pac-fix-double-free.patch +Patch0045: 0045-pac-fix-potential-memory-leaks.patch +Patch0046: 0046-responder-Set-forest-attribute-in-AD-domains.patch +Patch0047: 0047-LDAP-Add-a-new-error-code-for-malformed-access-contr.patch +Patch0048: 0048-FAST-when-parsing-krb5_child-response-make-sure-to-n.patch +Patch0049: 0049-UTIL-Inherit-parent-domain-s-default_shell.patch +Patch0050: 0050-NSS-Use-plain-user-name-when-expanding-homedir.patch +Patch0051: 0051-simple-access-match-objects-using-flat-name.patch +Patch0052: 0052-simple-access-refresh-master-domain-info.patch +Patch0053: 0053-NSS-add-support-for-subdomain_homedir.patch +Patch0054: 0054-AD-Return-right-error-code-from-netlogon_get_flat_na.patch +Patch0055: 0055-AD-Don-t-fail-the-request-if-ad_account_can_shortcut.patch +Patch0056: 0056-MAN-Fix-a-typo.patch +Patch0057: 0057-LDAP-Fix-error-check.patch +Patch0058: 0058-LDAP-Don-t-fail-if-subdomain-cannot-be-found-by-sid.patch +Patch0059: 0059-LDAP-update-id-mapping-detection-for-ldap-provider.patch +Patch0060: 0060-sdap_idamp-Fall-back-to-another-method-if-sid-is-wro.patch +Patch0061: 0061-krb5-hint-to-increase-krb5_auth_timeout.patch +Patch0062: 0062-LDAP-Don-t-abort-request-if-no-id-mapping-domain-mat.patch +Patch0063: 0063-sudo-memset-tm-when-converting-time-attributes.patch +Patch0064: 0064-AD-Don-t-mark-domain-as-enumerated-twice.patch +Patch0065: 0065-AD-Store-info-on-whether-a-subdomain-is-set-to-enume.patch +Patch0066: 0066-LDAP-Pass-a-private-context-to-enumeration-ptask-ins.patch +Patch0067: 0067-LDAP-Add-enum-request-with-custom-connection.patch +Patch0068: 0068-AD-Enumerate-users-from-GC-other-entities-from-LDAP.patch +Patch0069: 0069-LDAP-Don-t-clobber-original_member-during-enumeratio.patch +Patch0070: 0070-DB-Add-sss_ldb_el_to_string_list.patch +Patch0071: 0071-AD-Establish-cross-domain-memberships-after-enumerat.patch +Patch0072: 0072-AD-SRV-use-right-domain-name-for-CLDAP-ping.patch +Patch0073: 0073-MAN-clarify-which-shell-option-takes-precedence.patch +Patch0074: 0074-LDAP-store-group-if-subdomain-cannot-be-found-by-sid.patch +Patch0075: 0075-LDAP-require-attribute-groupType-for-AD-groups.patch +Patch0076: 0076-MONITOR-Incorrect-permissions-on-sssd.conf.patch +Patch0077: 0077-Revert-NSS-add-support-for-subdomain_homedir.patch +Patch0078: 0078-AD-support-for-subdomain_homedir.patch +Patch0079: 0079-MAN-update-of-subdomain_homedir-usage.patch +Patch0080: 0080-utils-handling-NULL-params-in-sss_parse_name.patch +Patch0081: 0081-LDAP-Detect-the-presence-of-POSIX-attributes.patch +Patch0082: 0082-AD-Only-download-domains-that-are-set-to-enumerate.patch +Patch0083: 0083-AD-Remove-dead-code.patch +Patch0084: 0084-LDAP-Handle-errors-from-sdap_id_op-properly-in-enum-.patch +Patch0085: 0085-SSS_CACHE-Reset-the-initgroups-attribute-when-resett.patch +Patch0086: 0086-IPA-Default-to-krb5_use_fast-try.patch +Patch0087: 0087-IPA-default-krb5_fast_principal-to-host-client-realm.patch +Patch0088: 0088-MAN-Clarify-the-new-krb5_use_fast-IPA-default.patch +Patch0089: 0089-IPA-Don-t-call-tevent_req_post-outside-_send.patch +Patch0090: 0090-IPA-Don-t-fail-if-apply_subdomain_homedir-returns-EN.patch +Patch0091: 0091-LDAP-Setup-periodic-task-only-once.patch +Patch0092: 0092-UTIL-Sanitize-whitespaces.patch +Patch0093: 0093-IDMAP-add-sss_idmap_check_collision-_ex.patch +Patch0094: 0094-IPA-refactor-idmap-code-and-add-test.patch +Patch0095: 0095-IPA-check-ranges-for-collisions-before-saving-them.patch +Patch0096: 0096-OPTS-Allow-using-defaults-for-blobs.patch +Patch0097: 0097-DP-Provide-separate-dp_copy_defaults-function.patch +Patch0098: 0098-MAN-Clarify-the-ldap_access_filter-option-further.patch +Patch0099: 0099-MAN-Clarify-that-changing-ID-mapping-options-might-r.patch +Patch0100: 0100-DOC-Fix-names-of-arguments-in-doxygen-comments.patch +Patch0101: 0101-libsss_idmap-bump-version-info.patch +Patch0102: 0102-config-API-add-missing-subdomain-target-to-AD-provid.patch +Patch0103: 0103-SUDO-AD-provider.patch +Patch0104: 0104-ipa-server-mode-use-lower-case-user-name-for-home-di.patch +Patch0105: 0105-IPA-Do-not-save-intermediate-data-to-sysdb.patch +Patch0106: 0106-Fix-krb5-changepw-when-FAST-only-preauth-methods-are.patch +Patch0107: 0107-IPA-Use-GC-for-AD-initgroup-requests.patch +Patch0108: 0108-AD-Only-connect-to-GC-for-subdomain-users.patch +Patch0109: 0109-MAN-Clarify-the-GC-support-a-bit.patch +Patch0110: 0110-IPA-Use-the-correct-domain-when-processing-SELinux-r.patch +Patch0111: 0111-IPA-KRB5-handle-KRB5_PROG_ETYPE_NOSUPP-during-IPA-pa.patch +Patch0112: 0112-AD-Continue-if-sssd-failes-to-check-extra-members.patch +Patch0113: 0113-IPA-Write-SELinux-usernames-in-the-right-case.patch +Patch0114: 0114-krb5_child-remove-unused-option-lifetime_str-from-k5.patch +Patch0115: 0115-krb5-child-extract-lifetime-settings-into-set_lifeti.patch +Patch0116: 0116-krb5_client-rename-krb5_set_canonicalize-to-set_cano.patch +Patch0117: 0117-krb5-child-add-revert_changepw_options.patch +Patch0118: 0118-KRB5-Do-not-attempt-to-get-a-TGT-after-a-password-ch.patch +Patch0119: 0119-IPA-Use-function-sysdb_attrs_get_el-in-safe-way.patch +Patch0120: 0120-AD-connect-to-forest-root-when-downloading-the-list-.patch +Patch0121: 0121-IPA-Fix-SELinux-mapping-order-memory-hierarchy.patch + ### Dependencies ### Requires: sssd-common = %{version}-%{release} @@ -74,7 +196,7 @@ BuildRequires: pkgconfig BuildRequires: glib2-devel BuildRequires: diffstat BuildRequires: findutils -BuildRequires: samba4-devel >= samba4-4.0.0-59beta2 +BuildRequires: samba4-devel >= 4.0.0-59beta2 BuildRequires: selinux-policy-targeted %description @@ -699,6 +821,269 @@ fi %postun -n libsss_idmap -p /sbin/ldconfig %changelog +* Wed Apr 02 2014 Jakub Hrozek - 1.11.2-65 +- Resolves: rhbz#1082191 - RHEL7 IPA selinuxusermap hbac rule not always + matching + +* Wed Apr 02 2014 Jakub Hrozek - 1.11.2-64 +- Resolves: rhbz#1077328 - other subdomains are unavailable when joined + to a subdomain in the ad forest + +* Wed Mar 26 2014 Sumit Bose - 1.11.2-63 +- Resolves: rhbz#1078877 - Valgrind: Invalid read of int while processing + netgroup + +* Wed Mar 26 2014 Sumit Bose - 1.11.2-62 +- Resolves: rhbz#1075092 - Password change w/ OTP generates error on success + +* Fri Mar 21 2014 Jakub Hrozek - 1.11.2-61 +- Resolves: rhbz#1078840 - Error during password change + +* Thu Mar 13 2014 Jakub Hrozek - 1.11.2-60 +- Resolves: rhbz#1075663 - SSSD should create the SELinux mapping file + with format expected by pam_selinux + +* Wed Mar 12 2014 Jakub Hrozek - 1.11.2-59 +- Related: rhbz#1075621 - Add another Kerberos error code to trigger IPA + password migration + +* Tue Mar 11 2014 Jakub Hrozek - 1.11.2-58 +- Related: rhbz#1073635 - IPA SELinux code looks for the host in the wrong + sysdb subdir when a trusted user logs in + +* Tue Mar 11 2014 Jakub Hrozek - 1.11.2-57 +- Related: rhbz#1066096 - not retrieving homedirs of AD users with + posix attributes + +* Mon Mar 10 2014 Jakub Hrozek - 1.11.2-56 +- Related: rhbz#1072995 - AD group inconsistency when using AD provider + in sssd-1.11-40 + +* Mon Mar 10 2014 Jakub Hrozek - 1.11.2-55 +- Resolves: rhbz#1073631 - sssd fails to handle expired passwords + when OTP is used + +* Tue Mar 04 2014 Jakub Hrozek - 1.11.2-54 +- Resolves: rhbz#1072067 - SSSD Does not cache SELinux map from FreeIPA + correctly + +* Tue Mar 04 2014 Jakub Hrozek - 1.11.2-53 +- Resolves: rhbz#1071903 - ipa-server-mode: Use lower-case user name + component in home dir path + +* Tue Mar 04 2014 Jakub Hrozek - 1.11.2-52 +- Resolves: rhbz#1068725 - Evaluate usage of sudo LDAP provider together + with the AD provider + +* Wed Feb 26 2014 Jakub Hrozek - 1.11.2-51 +- Fix idmap documentation +- Bump idmap version info +- Related: rhbz#1067361 - Check IPA idranges before saving them to the cache + +* Wed Feb 26 2014 Jakub Hrozek - 1.11.2-50 +- Pull some follow up man page fixes from upstream +- Related: rhbz#1060389 - Document that `sssd` cache needs to be cleared + manually, if ID mapping configuration changes +- Related: rhbz#1064908 - MAN: Remove misleading memberof example from + ldap_access_filter example + +* Wed Feb 26 2014 Jakub Hrozek - 1.11.2-49 +- Resolves: rhbz#1060389 - Document that `sssd` cache needs to be cleared + manually, if ID mapping configuration changes + +* Wed Feb 26 2014 Jakub Hrozek - 1.11.2-48 +- Resolves: rhbz#1064908 - MAN: Remove misleading memberof example from + ldap_access_filter example + +* Wed Feb 26 2014 Jakub Hrozek - 1.11.2-47 +- Resolves: rhbz#1068723 - Setting int option to 0 yields the default value + +* Wed Feb 26 2014 Jakub Hrozek - 1.11.2-46 +- Resolves: rhbz#1067361 - Check IPA idranges before saving them to the cache + +* Wed Feb 26 2014 Jakub Hrozek - 1.11.2-45 +- Resolves: rhbz#1067476 - SSSD pam module accepts usernames with leading + spaces + +* Wed Feb 26 2014 Jakub Hrozek - 1.11.2-44 +- Resolves: rhbz#1033069 - Configuring two different provider types might + start two parallel enumeration tasks + +* Mon Feb 17 2014 Jakub Hrozek - 1.11.2-43 +- Resolves: rhbz#1068640 - 'IPA: Don't call tevent_req_post outside _send' + should be added to RHEL7 + +* Mon Feb 17 2014 Jakub Hrozek - 1.11.2-42 +- Resolves: rhbz#1063977 - SSSD needs to enable FAST by default + +* Mon Feb 17 2014 Jakub Hrozek - 1.11.2-41 +- Resolves: rhbz#1064582 - sss_cache does not reset the SYSDB_INITGR_EXPIRE + attribute when expiring users + +* Wed Feb 12 2014 Jakub Hrozek - 1.11.2-40 +- Resolves: rhbz#1033081 - Implement heuristics to detect if POSIX attributes + have been replicated to the Global Catalog or not + +* Wed Feb 12 2014 Jakub Hrozek - 1.11.2-39 +- Resolves: rhbz#872177 - [RFE] subdomain homedir template should be + configurable/use flatname by default + +* Wed Feb 12 2014 Jakub Hrozek - 1.11.2-38 +- Resolves: rhbz#1059753 - Warn with a user-friendly error message when + permissions on sssd.conf are incorrect + +* Wed Jan 29 2014 Jakub Hrozek - 1.11.2-37 +- Resolves: rhbz#1037653 - Enabling ldap_id_mapping doesn't exclude + uidNumber in filter + +* Wed Jan 29 2014 Jakub Hrozek - 1.11.2-36 +- Resolves: rhbz#1059253 - Man page states default_shell option supersedes + other shell options but in fact override_shell does. +- Use the right domain for AD site resolution +- Related: rhbz#743503 - [RFE] sssd should support DNS sites + +* Wed Jan 29 2014 Jakub Hrozek - 1.11.2-35 +- Resolves: rhbz#1028039 - AD Enumeration reads data from LDAP while + regular lookups connect to GC + +* Wed Jan 29 2014 Jakub Hrozek - 1.11.2-34 +- Resolves: rhbz#877438 - sudoNotBefore/sudoNotAfter not supported by sssd + sudoers plugin + +* Fri Jan 24 2014 Daniel Mach - 1.11.2-33 +- Mass rebuild 2014-01-24 + +* Fri Jan 24 2014 Jakub Hrozek - 1.11.2-32 +- Resolves: rhbz#1054639 - sssd_be aborts a request if it doesn't match + any configured idmap domain + +* Fri Jan 24 2014 Jakub Hrozek - 1.11.2-31 +- Resolves: rhbz#1054899 - explicitly suggest krb5_auth_timeout in a loud + DEBUG message in case Kerberos authentication + times out + +* Wed Jan 22 2014 Jakub Hrozek - 1.11.2-30 +- Resolves: rhbz#1037653 - Enabling ldap_id_mapping doesn't exclude + uidNumber in filter + +* Mon Jan 20 2014 Jakub Hrozek - 1.11.2-29 +- Resolves: rhbz#1051360 - [FJ7.0 Bug]: [REG] sssd_be crashes when + ldap_search_base cannot be parsed. +- Fix a typo in the man page +- Related: rhbz#1034920 - RHEL7 sssd not setting IPA AD trusted user homedir + +* Mon Jan 20 2014 Jakub Hrozek - 1.11.2-28 +- Resolves: rhbz#1054639 - sssd_be aborts a request if it doesn't match + any configured idmap domain +- Fix return value when searching for AD domain flat names +- Resolves: rhbz#1048102 - Access denied for users from gc domain when + using format DOMAIN\user + +* Wed Jan 15 2014 Jakub Hrozek - 1.11.2-27 +- Resolves: rhbz#1034920 - RHEL7 sssd not setting IPA AD trusted user homedir + +* Wed Jan 15 2014 Jakub Hrozek - 1.11.2-26 +- Resolves: rhbz#1048102 - Access denied for users from gc domain when + using format DOMAIN\user + +* Wed Jan 15 2014 Jakub Hrozek - 1.11.2-25 +- Resolves: rhbz#1053106 - sssd ad trusted sub domain do not inherit + fallbacks and overrides settings + +* Thu Jan 09 2014 Jakub Hrozek - 1.11.2-24 +- Resolves: rhbz#1051016 - FAST does not work in SSSD 1.11.2 in Fedora 20 + +* Thu Jan 09 2014 Jakub Hrozek - 1.11.2-23 +- Resolves: rhbz#1033133 - "System Error" when invalid ad_access_filter + is used + +* Thu Jan 09 2014 Jakub Hrozek - 1.11.2-22 +- Resolves: rhbz#1032983 - sssd_be crashes when ad_access_filter uses + FOREST keyword. +- Fix two memory leaks in the PAC responder (Related: rhbz#991065) + +* Wed Jan 08 2014 Jakub Hrozek - 1.11.2-21 +- Resolves: rhbz#1048184 - Group lookup does not return member with multiple + names after user lookup + +* Wed Jan 08 2014 Jakub Hrozek - 1.11.2-20 +- Resolves: rhbz#1049533 - Group membership lookup issue + +* Fri Dec 27 2013 Daniel Mach - 1.11.2-19 +- Mass rebuild 2013-12-27 + +* Thu Dec 19 2013 Jakub Hrozek - 1.11.2-18 +- Resolves: rhbz#894068 - sss_cache doesn't support subdomains + +* Thu Dec 19 2013 Jakub Hrozek - 1.11.2-17 +- Re-initialize subdomains after provider startup +- Related: rhbz#1038637 - If SSSD starts offline, subdomains list is + never read + +* Thu Dec 19 2013 Jakub Hrozek - 1.11.2-16 +- The AD provider is able to resolve group memberships for groups with + Global and Universal scope +- Related: rhbz#1033096 - tokenGroups do not work reliable with Global + Catalog + +* Wed Dec 18 2013 Jakub Hrozek - 1.11.2-15 +- Resolves: rhbz#1033096 - tokenGroups do not work reliable with Global + Catalog +- Resolves: rhbz#1030483 - Individual group search returned multiple + results in GC lookups + +* Wed Dec 18 2013 Jakub Hrozek - 1.11.2-14 +- Resolves: rhbz#1040969 - sssd_nss grows memory footprint when netgroups + are requested + +* Thu Dec 12 2013 Jakub Hrozek - 1.11.2-13 +- Resolves: rhbz#1023409 - Valgrind sssd "Syscall param + socketcall.sendto(msg) points to uninitialised + byte(s)" + +* Thu Dec 12 2013 Jakub Hrozek - 1.11.2-12 +- Resolves: rhbz#1037936 - sssd_be crashes occasionally + +* Thu Dec 12 2013 Jakub Hrozek - 1.11.2-11 +- Resolves: rhbz#1038637 - If SSSD starts offline, subdomains list is + never read + +* Mon Dec 2 2013 Jakub Hrozek - 1.11.2-10 +- Resolves: rhbz#1029631 - sssd_be crashes on manually adding a cleartext + password to ldap_default_authtok + +* Mon Dec 2 2013 Jakub Hrozek - 1.11.2-9 +- Resolves: rhbz#1036758 - SSSD: Allow for custom attributes in RDN when + using id_provider = proxy + +* Mon Dec 2 2013 Jakub Hrozek - 1.11.2-8 +- Resolves: rhbz#1034050 - Errors in domain log when saving user to sysdb + +* Mon Dec 2 2013 Jakub Hrozek - 1.11.2-7 +- Resolves: rhbz#1036157 - sssd can't retrieve auto.master when using the + "default_domain_suffix" option in + +* Mon Dec 2 2013 Jakub Hrozek - 1.11.2-6 +- Resolves: rhbz#1028057 - Improve detection of the right domain when + processing group with members from several domains + +* Mon Dec 2 2013 Jakub Hrozek - 1.11.2-5 +- Resolves: rhbz#1033084 - sssd_be segfaults if empty grop is resolved + using ad_matching_rule + +* Mon Dec 2 2013 Jakub Hrozek - 1.11.2-4 +- Resolves: rhbz#1031562 - Incorrect mention of access_filter in sssd-ad + manpage + +* Mon Dec 2 2013 Jakub Hrozek - 1.11.2-3 +- Resolves: rhbz#991549 - sssd fails to retrieve netgroups with multiple + CN attributes + +* Mon Dec 2 2013 Jakub Hrozek - 1.11.2-2 +- Skip netgroups that don't provide well-formed triplets +- Related: rhbz#991549 - sssd fails to retrieve netgroups with multiple + CN attributes + * Wed Oct 30 2013 Jakub Hrozek - 1.11.2-1 - New upstream release 1.11.2 - Remove upstreamed patches