diff --git a/0003-DYNDNS-sss_iface_addr_list_get-return-ENOENT.patch b/0003-DYNDNS-sss_iface_addr_list_get-return-ENOENT.patch new file mode 100644 index 0000000..09108ec --- /dev/null +++ b/0003-DYNDNS-sss_iface_addr_list_get-return-ENOENT.patch @@ -0,0 +1,98 @@ +From a74f42e33fd62be175c30574242a214cdce14b06 Mon Sep 17 00:00:00 2001 +From: Pavel Reichl +Date: Wed, 8 Jul 2015 09:01:24 -0400 +Subject: [PATCH 03/14] DYNDNS: sss_iface_addr_list_get return ENOENT + +If none of eligible interfaces matches ifname then ENOENT is returned. + +Resolves: +https://fedorahosted.org/sssd/ticket/2549 +--- + src/providers/dp_dyndns.c | 13 +++++++++++-- + src/providers/ldap/sdap_dyndns.c | 6 +++++- + src/tests/cmocka/test_dyndns.c | 20 ++++++++++++++++++++ + 3 files changed, 36 insertions(+), 3 deletions(-) + +diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c +index 1cac3d0fae2454cea823ed640a4325f27580353f..2ac43a108ff6197d9e2662198a6da976ca348e76 100644 +--- a/src/providers/dp_dyndns.c ++++ b/src/providers/dp_dyndns.c +@@ -222,8 +222,17 @@ sss_iface_addr_list_get(TALLOC_CTX *mem_ctx, const char *ifname, + } + } + +- ret = EOK; +- *_addrlist = addrlist; ++ if (addrlist != NULL) { ++ /* OK, some result was found */ ++ ret = EOK; ++ *_addrlist = addrlist; ++ } else { ++ /* No result was found */ ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "No IPs usable for DNS was found for interface: %s.\n", ifname); ++ ret = ENOENT; ++ } ++ + done: + freeifaddrs(ifaces); + return ret; +diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c +index 0d9c9205792062378aa25aad6ac706058001433a..e99a4f6687035928f6775c38b9df6b2a06d38f38 100644 +--- a/src/providers/ldap/sdap_dyndns.c ++++ b/src/providers/ldap/sdap_dyndns.c +@@ -502,8 +502,12 @@ sdap_dyndns_get_addrs_send(TALLOC_CTX *mem_ctx, + if (iface) { + ret = sss_iface_addr_list_get(state, iface, &state->addresses); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, ++ DEBUG(ret == ENOENT ? SSSDBG_MINOR_FAILURE : SSSDBG_OP_FAILURE, + "Cannot get list of addresses from interface %s\n", iface); ++ /* non critical failure */ ++ if (ret == ENOENT) { ++ ret = EOK; ++ } + } + /* We're done. Just fake an async request completion */ + goto done; +diff --git a/src/tests/cmocka/test_dyndns.c b/src/tests/cmocka/test_dyndns.c +index 689e333d4e68c4a2582894d06b8b7b20c76b9be8..3214e90c063ea9a4cf6f6bc6507bf4e37b7d23a4 100644 +--- a/src/tests/cmocka/test_dyndns.c ++++ b/src/tests/cmocka/test_dyndns.c +@@ -247,6 +247,23 @@ void dyndns_test_get_multi_ifaddr(void **state) + assert_true(check_leaks_pop(dyndns_test_ctx) == true); + } + ++void dyndns_test_get_ifaddr_enoent(void **state) ++{ ++ errno_t ret; ++ struct sss_iface_addr *addrlist = NULL; ++ ++ check_leaks_push(dyndns_test_ctx); ++ will_return_getifaddrs("eth0", "192.168.0.1"); ++ will_return_getifaddrs("eth1", "192.168.0.2"); ++ will_return_getifaddrs(NULL, NULL); /* sentinel */ ++ ret = sss_iface_addr_list_get(dyndns_test_ctx, "non_existing_interface", ++ &addrlist); ++ assert_int_equal(ret, ENOENT); ++ talloc_free(addrlist); ++ ++ assert_true(check_leaks_pop(dyndns_test_ctx) == true); ++} ++ + void dyndns_test_ok(void **state) + { + struct tevent_req *req; +@@ -460,6 +477,9 @@ int main(int argc, const char *argv[]) + cmocka_unit_test_setup_teardown(dyndns_test_get_multi_ifaddr, + dyndns_test_simple_setup, + dyndns_test_teardown), ++ cmocka_unit_test_setup_teardown(dyndns_test_get_ifaddr_enoent, ++ dyndns_test_simple_setup, ++ dyndns_test_teardown), + + /* Dynamic DNS update unit tests*/ + cmocka_unit_test_setup_teardown(dyndns_test_ok, +-- +2.5.0 + diff --git a/0004-DYNDNS-support-mult.-interfaces-for-dyndns_iface-opt.patch b/0004-DYNDNS-support-mult.-interfaces-for-dyndns_iface-opt.patch new file mode 100644 index 0000000..41b26f0 --- /dev/null +++ b/0004-DYNDNS-support-mult.-interfaces-for-dyndns_iface-opt.patch @@ -0,0 +1,194 @@ +From 7a7696e489087f3e02f7d484766dc55112fe7803 Mon Sep 17 00:00:00 2001 +From: Pavel Reichl +Date: Wed, 8 Jul 2015 09:08:03 -0400 +Subject: [PATCH 04/14] DYNDNS: support mult. interfaces for dyndns_iface opt + +Resolves: +https://fedorahosted.org/sssd/ticket/2549 +--- + src/man/sssd-ad.5.xml | 11 +++--- + src/man/sssd-ipa.5.xml | 10 ++++-- + src/providers/dp_dyndns.c | 6 ++++ + src/providers/dp_dyndns.h | 4 +++ + src/providers/ldap/sdap_dyndns.c | 72 +++++++++++++++++++++++++++++++++++----- + 5 files changed, 87 insertions(+), 16 deletions(-) + +diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml +index 938a443e027b9bf83c75c240a7d6b2a0876b92c8..ff43ea37066514a87934d07b141e680416dcc05b 100644 +--- a/src/man/sssd-ad.5.xml ++++ b/src/man/sssd-ad.5.xml +@@ -754,15 +754,16 @@ ad_gpo_map_deny = +my_pam_service + + + Optional. Applicable only when dyndns_update +- is true. Choose the interface whose IP address +- should be used for dynamic DNS updates. +- +- +- NOTE: This option currently supports only one interface. ++ is true. Choose the interface or a list of interfaces ++ whose IP addresses should be used for dynamic DNS ++ updates. + + + Default: Use the IP address of the AD LDAP connection + ++ ++ Example: dyndns_iface = em1, vnet1, vnet2 ++ + + + +diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml +index 0716b6235f93965170983856b930799bfded6258..d450c2fadbb1713096ff766bf536702195cfd137 100644 +--- a/src/man/sssd-ipa.5.xml ++++ b/src/man/sssd-ipa.5.xml +@@ -166,11 +166,12 @@ + + + Optional. Applicable only when dyndns_update +- is true. Choose the interface whose IP address +- should be used for dynamic DNS updates. ++ is true. Choose the interface or a list of interfaces ++ whose IP addresses should be used for dynamic DNS ++ updates. + + +- NOTE: This option currently supports only one interface. ++ NOTE: This option currently supports multiple interfaces. + + + NOTE: While it is still possible to use the old +@@ -181,6 +182,9 @@ + + Default: Use the IP address of the IPA LDAP connection + ++ ++ Example: dyndns_iface = em1, vnet1, vnet2 ++ + + + +diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c +index 2ac43a108ff6197d9e2662198a6da976ca348e76..76562840ef1d427629e41617b871caaedab779d4 100644 +--- a/src/providers/dp_dyndns.c ++++ b/src/providers/dp_dyndns.c +@@ -49,6 +49,12 @@ struct sss_iface_addr { + struct sockaddr_storage *addr; + }; + ++void sss_iface_addr_concatenate(struct sss_iface_addr **list, ++ struct sss_iface_addr *list2) ++{ ++ DLIST_CONCATENATE((*list), list2, struct sss_iface_addr*); ++} ++ + struct sss_iface_addr * + sss_iface_addr_add(TALLOC_CTX *mem_ctx, struct sss_iface_addr **list, + struct sockaddr_storage *ss) +diff --git a/src/providers/dp_dyndns.h b/src/providers/dp_dyndns.h +index 23b833dace58a0ecbb1e2e21963a55186f1d06a8..deba112538ad22cd7f59be07934778ee9d4361e7 100644 +--- a/src/providers/dp_dyndns.h ++++ b/src/providers/dp_dyndns.h +@@ -128,4 +128,8 @@ nsupdate_get_addrs_recv(struct tevent_req *req, + struct sss_iface_addr **_addrlist, + size_t *_count); + ++void ++sss_iface_addr_concatenate(struct sss_iface_addr **list, ++ struct sss_iface_addr *list2); ++ + #endif /* DP_DYNDNS_H_ */ +diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c +index e99a4f6687035928f6775c38b9df6b2a06d38f38..f5929cff3db6f724efcedeb963e3a12d04f6e1d3 100644 +--- a/src/providers/ldap/sdap_dyndns.c ++++ b/src/providers/ldap/sdap_dyndns.c +@@ -482,6 +482,65 @@ static void sdap_dyndns_get_addrs_done(struct tevent_req *subreq); + static errno_t sdap_dyndns_add_ldap_conn(struct sdap_dyndns_get_addrs_state *state, + struct sdap_handle *sh); + ++static errno_t get_ifaces_addrs(TALLOC_CTX *mem_ctx, ++ const char *iface, ++ struct sss_iface_addr **_result) ++{ ++ struct sss_iface_addr *result_addrs = NULL; ++ struct sss_iface_addr *intf_addrs; ++ TALLOC_CTX *tmp_ctx; ++ char **list_of_intfs; ++ int num_of_intfs; ++ errno_t ret; ++ int i; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = split_on_separator(tmp_ctx, iface, ',', true, true, &list_of_intfs, ++ &num_of_intfs); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Parsing names of interfaces failed - %d:[%s].\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ for (i = 0; i < num_of_intfs; i++) { ++ ret = sss_iface_addr_list_get(tmp_ctx, list_of_intfs[i], &intf_addrs); ++ if (ret == EOK) { ++ if (result_addrs != NULL) { ++ /* If there is already an existing list, head of this existing ++ * list will be considered as parent talloc context for the ++ * new list. ++ */ ++ talloc_steal(result_addrs, intf_addrs); ++ } ++ sss_iface_addr_concatenate(&result_addrs, intf_addrs); ++ } else if (ret == ENOENT) { ++ /* non-critical failure */ ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Cannot get interface %s or there are no addresses " ++ "bind to it.\n", list_of_intfs[i]); ++ } else { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot get list of addresses from interface %s - %d:[%s]\n", ++ list_of_intfs[i], ret, sss_strerror(ret)); ++ goto done; ++ } ++ } ++ ++ ret = EOK; ++ *_result = talloc_steal(mem_ctx, result_addrs); ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ + static struct tevent_req * + sdap_dyndns_get_addrs_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, +@@ -500,14 +559,11 @@ sdap_dyndns_get_addrs_send(TALLOC_CTX *mem_ctx, + } + + if (iface) { +- ret = sss_iface_addr_list_get(state, iface, &state->addresses); +- if (ret != EOK) { +- DEBUG(ret == ENOENT ? SSSDBG_MINOR_FAILURE : SSSDBG_OP_FAILURE, +- "Cannot get list of addresses from interface %s\n", iface); +- /* non critical failure */ +- if (ret == ENOENT) { +- ret = EOK; +- } ++ ret = get_ifaces_addrs(state, iface, &state->addresses); ++ if (ret != EOK || state->addresses == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "get_ifaces_addrs() failed: %d:[%s]\n", ++ ret, sss_strerror(ret)); + } + /* We're done. Just fake an async request completion */ + goto done; +-- +2.5.0 + diff --git a/0005-DYNDNS-special-value-for-dyndns_iface-option.patch b/0005-DYNDNS-special-value-for-dyndns_iface-option.patch new file mode 100644 index 0000000..299df25 --- /dev/null +++ b/0005-DYNDNS-special-value-for-dyndns_iface-option.patch @@ -0,0 +1,107 @@ +From ef7a48d5acc481a207ac2821fc43651641f1b298 Mon Sep 17 00:00:00 2001 +From: Pavel Reichl +Date: Tue, 14 Jul 2015 04:21:34 -0400 +Subject: [PATCH 05/14] DYNDNS: special value '*' for dyndns_iface option + +Option dyndns_iface has now special value '*' which implies that IPs +from add interfaces should be sent during DDNS update. +--- + src/man/sssd-ad.5.xml | 6 ++++-- + src/man/sssd-ipa.5.xml | 9 ++++----- + src/providers/dp_dyndns.c | 20 ++++++++++++++++---- + 3 files changed, 24 insertions(+), 11 deletions(-) + +diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml +index ff43ea37066514a87934d07b141e680416dcc05b..3cbc10520098372d984d00425d03832d002d6672 100644 +--- a/src/man/sssd-ad.5.xml ++++ b/src/man/sssd-ad.5.xml +@@ -756,10 +756,12 @@ ad_gpo_map_deny = +my_pam_service + Optional. Applicable only when dyndns_update + is true. Choose the interface or a list of interfaces + whose IP addresses should be used for dynamic DNS +- updates. ++ updates. Special value * implies that ++ IPs from all interfaces should be used. + + +- Default: Use the IP address of the AD LDAP connection ++ Default: Use the IP addresses of the interface which ++ is used for AD LDAP connection + + + Example: dyndns_iface = em1, vnet1, vnet2 +diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml +index d450c2fadbb1713096ff766bf536702195cfd137..2e985991fde10827aff0e7c8e67f29a009683450 100644 +--- a/src/man/sssd-ipa.5.xml ++++ b/src/man/sssd-ipa.5.xml +@@ -168,10 +168,8 @@ + Optional. Applicable only when dyndns_update + is true. Choose the interface or a list of interfaces + whose IP addresses should be used for dynamic DNS +- updates. +- +- +- NOTE: This option currently supports multiple interfaces. ++ updates. Special value * implies that ++ IPs from all interfaces should be used. + + + NOTE: While it is still possible to use the old +@@ -180,7 +178,8 @@ + in their config file. + + +- Default: Use the IP address of the IPA LDAP connection ++ Default: Use the IP addresses of the interface which ++ is used for IPA LDAP connection + + + Example: dyndns_iface = em1, vnet1, vnet2 +diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c +index 76562840ef1d427629e41617b871caaedab779d4..03389acfba13e566540ca8b0570c0d009173575f 100644 +--- a/src/providers/dp_dyndns.c ++++ b/src/providers/dp_dyndns.c +@@ -42,6 +42,9 @@ + #define DYNDNS_TIMEOUT 15 + #endif /* DYNDNS_TIMEOUT */ + ++/* MASK represents special value for matching all interfaces */ ++#define MASK "*" ++ + struct sss_iface_addr { + struct sss_iface_addr *next; + struct sss_iface_addr *prev; +@@ -171,6 +174,16 @@ ok_for_dns(struct sockaddr *sa) + return true; + } + ++static bool supported_address_family(sa_family_t sa_family) ++{ ++ return sa_family == AF_INET || sa_family == AF_INET6; ++} ++ ++static bool matching_name(const char *ifname, const char *ifname2) ++{ ++ return (strcmp(MASK, ifname) == 0) || (strcasecmp(ifname, ifname2) == 0); ++} ++ + /* Collect IP addresses associated with an interface */ + errno_t + sss_iface_addr_list_get(TALLOC_CTX *mem_ctx, const char *ifname, +@@ -200,10 +213,9 @@ sss_iface_addr_list_get(TALLOC_CTX *mem_ctx, const char *ifname, + if (!ifa->ifa_addr) continue; + + /* Add IP addresses to the list */ +- if ((ifa->ifa_addr->sa_family == AF_INET || +- ifa->ifa_addr->sa_family == AF_INET6) && +- strcasecmp(ifa->ifa_name, ifname) == 0 && +- ok_for_dns(ifa->ifa_addr)) { ++ if (supported_address_family(ifa->ifa_addr->sa_family) ++ && matching_name(ifname, ifa->ifa_name) ++ && ok_for_dns(ifa->ifa_addr)) { + + /* Add this address to the IP address list */ + address = talloc_zero(mem_ctx, struct sss_iface_addr); +-- +2.5.0 + diff --git a/0006-TESTS-dyndns-tests-support-AAAA-addresses.patch b/0006-TESTS-dyndns-tests-support-AAAA-addresses.patch new file mode 100644 index 0000000..3191d5c --- /dev/null +++ b/0006-TESTS-dyndns-tests-support-AAAA-addresses.patch @@ -0,0 +1,130 @@ +From cef454da178e7e7f097fade886f4d06ba6aa0f4f Mon Sep 17 00:00:00 2001 +From: Pavel Reichl +Date: Wed, 15 Jul 2015 10:58:38 -0400 +Subject: [PATCH 06/14] TESTS: dyndns tests support AAAA addresses + +Resolves: +https://fedorahosted.org/sssd/ticket/2558 +--- + src/tests/cmocka/test_dyndns.c | 51 +++++++++++++++++++++++++++++++----------- + 1 file changed, 38 insertions(+), 13 deletions(-) + +diff --git a/src/tests/cmocka/test_dyndns.c b/src/tests/cmocka/test_dyndns.c +index 3214e90c063ea9a4cf6f6bc6507bf4e37b7d23a4..e9d42cea37472b38ae2eb900368f2ce3f409fefc 100644 +--- a/src/tests/cmocka/test_dyndns.c ++++ b/src/tests/cmocka/test_dyndns.c +@@ -97,7 +97,9 @@ int __wrap_getifaddrs(struct ifaddrs **_ifap) + struct ifaddrs *ifap_head = NULL; + char *name; + char *straddr; ++ int ad_family; + struct sockaddr_in *sa; ++ void *dst; + + while ((name = sss_mock_ptr_type(char *)) != NULL) { + straddr = sss_mock_ptr_type(char *); +@@ -105,6 +107,7 @@ int __wrap_getifaddrs(struct ifaddrs **_ifap) + errno = EINVAL; + goto fail; + } ++ ad_family = sss_mock_type(int); + + ifap = talloc_zero(global_mock_context, struct ifaddrs); + if (ifap == NULL) { +@@ -127,15 +130,33 @@ int __wrap_getifaddrs(struct ifaddrs **_ifap) + + /* Do not alocate directly on ifap->ifa_addr to + * avoid alignment warnings */ +- sa = talloc(ifap, struct sockaddr_in); ++ if (ad_family == AF_INET) { ++ sa = talloc(ifap, struct sockaddr_in); ++ } else if (ad_family == AF_INET6) { ++ sa = (struct sockaddr_in *) talloc(ifap, struct sockaddr_in6); ++ } else { ++ errno = EINVAL; ++ goto fail; ++ } ++ + if (sa == NULL) { + errno = ENOMEM; + goto fail; + } +- sa->sin_family = AF_INET; ++ ++ sa->sin_family = ad_family; ++ ++ if (ad_family == AF_INET) { ++ dst = &sa->sin_addr; ++ } else if (ad_family == AF_INET6) { ++ dst = &((struct sockaddr_in6 *)sa)->sin6_addr; ++ } else { ++ errno = EINVAL; ++ goto fail; ++ } + + /* convert straddr into ifa_addr */ +- if (inet_pton(AF_INET, straddr, &sa->sin_addr) != 1) { ++ if (inet_pton(ad_family, straddr, dst) != 1) { + goto fail; + } + +@@ -167,12 +188,16 @@ static void dyndns_test_done(struct tevent_req *req) + ctx->tctx->done = true; + } + +-void will_return_getifaddrs(const char *ifname, const char *straddr) ++void will_return_getifaddrs(const char *ifname, const char *straddr, ++ int af_family) + { + will_return(__wrap_getifaddrs, ifname); + if (ifname) { + will_return(__wrap_getifaddrs, straddr); + } ++ if (straddr) { ++ will_return(__wrap_getifaddrs, af_family); ++ } + } + + void dyndns_test_get_ifaddr(void **state) +@@ -182,9 +207,9 @@ void dyndns_test_get_ifaddr(void **state) + char straddr[128]; + + check_leaks_push(dyndns_test_ctx); +- will_return_getifaddrs("eth0", "192.168.0.1"); +- will_return_getifaddrs("eth1", "192.168.0.2"); +- will_return_getifaddrs(NULL, NULL); /* sentinel */ ++ will_return_getifaddrs("eth0", "192.168.0.1", AF_INET); ++ will_return_getifaddrs("eth1", "192.168.0.2", AF_INET); ++ will_return_getifaddrs(NULL, NULL, 0); /* sentinel */ + ret = sss_iface_addr_list_get(dyndns_test_ctx, "eth0", &addrlist); + assert_int_equal(ret, EOK); + +@@ -212,9 +237,9 @@ void dyndns_test_get_multi_ifaddr(void **state) + char straddr[128]; + + check_leaks_push(dyndns_test_ctx); +- will_return_getifaddrs("eth0", "192.168.0.2"); +- will_return_getifaddrs("eth0", "192.168.0.1"); +- will_return_getifaddrs(NULL, NULL); /* sentinel */ ++ will_return_getifaddrs("eth0", "192.168.0.2", AF_INET); ++ will_return_getifaddrs("eth0", "192.168.0.1", AF_INET); ++ will_return_getifaddrs(NULL, NULL, 0); /* sentinel */ + ret = sss_iface_addr_list_get(dyndns_test_ctx, "eth0", &addrlist); + assert_int_equal(ret, EOK); + +@@ -253,9 +278,9 @@ void dyndns_test_get_ifaddr_enoent(void **state) + struct sss_iface_addr *addrlist = NULL; + + check_leaks_push(dyndns_test_ctx); +- will_return_getifaddrs("eth0", "192.168.0.1"); +- will_return_getifaddrs("eth1", "192.168.0.2"); +- will_return_getifaddrs(NULL, NULL); /* sentinel */ ++ will_return_getifaddrs("eth0", "192.168.0.1", AF_INET); ++ will_return_getifaddrs("eth1", "192.168.0.2", AF_INET); ++ will_return_getifaddrs(NULL, NULL, 0); /* sentinel */ + ret = sss_iface_addr_list_get(dyndns_test_ctx, "non_existing_interface", + &addrlist); + assert_int_equal(ret, ENOENT); +-- +2.5.0 + diff --git a/0007-IPA-Remove-MPG-groups-if-getgrgid-was-called-before-.patch b/0007-IPA-Remove-MPG-groups-if-getgrgid-was-called-before-.patch new file mode 100644 index 0000000..b90bde2 --- /dev/null +++ b/0007-IPA-Remove-MPG-groups-if-getgrgid-was-called-before-.patch @@ -0,0 +1,88 @@ +From 2322de0bd2fdc6b2ca64969df35662ab962620a4 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 21 Jul 2015 11:44:03 +0200 +Subject: [PATCH 07/14] IPA: Remove MPG groups if getgrgid was called before + getpw() + +https://fedorahosted.org/sssd/ticket/2724 + +This bug only affects IPA clients that are connected to IPA servers with +AD trust and ID mapping in effect. + +If an IPA client calls getgrgid() for an ID that matches a user, the +user's private group would be returned and stored as a group entry. + +Subsequent queries for that user would fail, because MPG domains impose +uniqueness restriction for both the ID and name space across groups and +users. + +To work around that, we remove the UPG groups in MPG domains during a +group lookup. + +Reviewed-by: Sumit Bose +--- + src/providers/ipa/ipa_s2n_exop.c | 41 ++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 39 insertions(+), 2 deletions(-) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index 812a4bbd707faf5c184594b562c148d1e704fd58..1e6368dc7ef1a6f60b541409f7f6740d602f0d43 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -1764,6 +1764,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + int tret; + struct sysdb_attrs *gid_override_attrs = NULL; + char ** exop_grouplist; ++ struct ldb_message *msg; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { +@@ -2005,8 +2006,44 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + attrs->a.user.pw_dir, attrs->a.user.pw_shell, + NULL, attrs->sysdb_attrs, NULL, + timeout, now); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "sysdb_store_user failed.\n"); ++ if (ret == EEXIST && dom->mpg == true) { ++ /* This handles the case where getgrgid() was called for ++ * this user, so a group was created in the cache ++ */ ++ ret = sysdb_search_group_by_name(tmp_ctx, dom, name, NULL, &msg); ++ if (ret != EOK) { ++ /* Fail even on ENOENT, the group must be around */ ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Could not delete MPG group [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = sysdb_delete_group(dom, NULL, attrs->a.user.pw_uid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sysdb_delete_group failed for MPG group [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = sysdb_store_user(dom, name, NULL, ++ attrs->a.user.pw_uid, ++ gid, attrs->a.user.pw_gecos, ++ attrs->a.user.pw_dir, ++ attrs->a.user.pw_shell, ++ NULL, attrs->sysdb_attrs, NULL, ++ timeout, now); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sysdb_store_user failed for MPG user [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sysdb_store_user failed [%d]: %s\n", ++ ret, sss_strerror(ret)); + goto done; + } + +-- +2.5.0 + diff --git a/0008-IPA-Better-debugging.patch b/0008-IPA-Better-debugging.patch new file mode 100644 index 0000000..9d1200c --- /dev/null +++ b/0008-IPA-Better-debugging.patch @@ -0,0 +1,27 @@ +From f2fd03807a6a7d92b706f0964bd1bcf172766cd6 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 22 Jul 2015 15:17:57 +0200 +Subject: [PATCH 08/14] IPA: Better debugging + +Reviewed-by: Alexander Bokovoy +--- + src/providers/ipa/ipa_subdomains_server.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c +index cd8c6301c4e4fbbf194ca98ce7a7bfe6215b381c..a9e2c1f700ef47716be868bad68590b8d5d0d42a 100644 +--- a/src/providers/ipa/ipa_subdomains_server.c ++++ b/src/providers/ipa/ipa_subdomains_server.c +@@ -623,6 +623,9 @@ ipa_server_trust_add_send(TALLOC_CTX *mem_ctx, + + immediate: + if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Could not add trusted subdomain %s from forest %s\n", ++ subdom->name, state->forest); + tevent_req_error(req, ret); + } else { + tevent_req_done(req); +-- +2.5.0 + diff --git a/0009-UTIL-Lower-debug-level-in-perform_checks.patch b/0009-UTIL-Lower-debug-level-in-perform_checks.patch new file mode 100644 index 0000000..766f7bb --- /dev/null +++ b/0009-UTIL-Lower-debug-level-in-perform_checks.patch @@ -0,0 +1,50 @@ +From b5e5c04b5af74537c95213a72d4c916b50c05588 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 22 Jul 2015 16:29:09 +0200 +Subject: [PATCH 09/14] UTIL: Lower debug level in perform_checks() + +Failures in perform_checks() don't have to be fatal, therefore the debug +messages shouldn't be either. + +Reviewed-by: Alexander Bokovoy +--- + src/util/check_and_open.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/util/check_and_open.c b/src/util/check_and_open.c +index 59b90bf4b96731e385fcf92ed8bc251cb94abfda..b40ae2003e3de22ce9e4ca07cecc68e18a7abab4 100644 +--- a/src/util/check_and_open.c ++++ b/src/util/check_and_open.c +@@ -99,12 +99,12 @@ static errno_t perform_checks(struct stat *stat_buf, + } + + if ((mode & S_IFMT) != (st_mode & S_IFMT)) { +- DEBUG(SSSDBG_CRIT_FAILURE, "File is not the right type.\n"); ++ DEBUG(SSSDBG_TRACE_LIBS, "File is not the right type.\n"); + return EINVAL; + } + + if ((st_mode & ALLPERMS) != (mode & ALLPERMS)) { +- DEBUG(SSSDBG_CRIT_FAILURE, ++ DEBUG(SSSDBG_TRACE_LIBS, + "File has the wrong (bit masked) mode [%.7o], " + "expected [%.7o].\n", + (st_mode & ALLPERMS), (mode & ALLPERMS)); +@@ -112,12 +112,12 @@ static errno_t perform_checks(struct stat *stat_buf, + } + + if (uid != (uid_t)(-1) && stat_buf->st_uid != uid) { +- DEBUG(SSSDBG_CRIT_FAILURE, "File must be owned by uid [%d].\n", uid); ++ DEBUG(SSSDBG_TRACE_LIBS, "File must be owned by uid [%d].\n", uid); + return EINVAL; + } + + if (gid != (gid_t)(-1) && stat_buf->st_gid != gid) { +- DEBUG(SSSDBG_CRIT_FAILURE, "File must be owned by gid [%d].\n", gid); ++ DEBUG(SSSDBG_TRACE_LIBS, "File must be owned by gid [%d].\n", gid); + return EINVAL; + } + +-- +2.5.0 + diff --git a/0010-IPA-Handle-sssd-owned-keytabs-when-running-as-root.patch b/0010-IPA-Handle-sssd-owned-keytabs-when-running-as-root.patch new file mode 100644 index 0000000..be12309 --- /dev/null +++ b/0010-IPA-Handle-sssd-owned-keytabs-when-running-as-root.patch @@ -0,0 +1,116 @@ +From 629fba06bc02e6ff4b25680532d298552fa55b22 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 22 Jul 2015 17:20:11 +0200 +Subject: [PATCH 10/14] IPA: Handle sssd-owned keytabs when running as root + +https://fedorahosted.org/sssd/ticket/2718 + +This patch handles the case where the keytab is created with sssd:sssd +ownership (perhaps by the IPA oddjob script) but SSSD runs as root, +which is the default in many distributions. + +Reviewed-by: Alexander Bokovoy +--- + src/providers/ipa/ipa_subdomains.h | 3 ++ + src/providers/ipa/ipa_subdomains_server.c | 46 +++++++++++++++++++++++++------ + 2 files changed, 41 insertions(+), 8 deletions(-) + +diff --git a/src/providers/ipa/ipa_subdomains.h b/src/providers/ipa/ipa_subdomains.h +index 5bc63a173a1a8967eb5de30a2da84a81377d3900..2302c5f03e80de2ea1efad424769e777cd6dd8d5 100644 +--- a/src/providers/ipa/ipa_subdomains.h ++++ b/src/providers/ipa/ipa_subdomains.h +@@ -94,6 +94,9 @@ struct ipa_server_mode_ctx { + + struct ipa_ad_server_ctx *trusts; + struct ipa_ext_groups *ext_groups; ++ ++ uid_t kt_owner_uid; ++ uid_t kt_owner_gid; + }; + + int ipa_ad_subdom_init(struct be_ctx *be_ctx, +diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c +index a9e2c1f700ef47716be868bad68590b8d5d0d42a..4bfea61e6dd0a02f6b723a39f7ba236c914009b0 100644 +--- a/src/providers/ipa/ipa_subdomains_server.c ++++ b/src/providers/ipa/ipa_subdomains_server.c +@@ -520,16 +520,28 @@ static errno_t ipa_getkeytab_recv(struct tevent_req *req, int *child_status) + return EOK; + } + +-static errno_t ipa_check_keytab(const char *keytab) ++static errno_t ipa_check_keytab(const char *keytab, ++ uid_t kt_owner_uid, ++ gid_t kt_owner_gid) + { + errno_t ret; + + ret = check_file(keytab, getuid(), getgid(), S_IFREG|0600, 0, NULL, false); +- if (ret != EOK) { +- if (ret != ENOENT) { +- DEBUG(SSSDBG_OP_FAILURE, "Failed to check for %s\n", keytab); +- } else { +- DEBUG(SSSDBG_TRACE_FUNC, "Keytab %s is not present\n", keytab); ++ if (ret == ENOENT) { ++ DEBUG(SSSDBG_TRACE_FUNC, "Keytab %s is not present\n", keytab); ++ goto done; ++ } else if (ret != EOK) { ++ if (kt_owner_uid) { ++ ret = check_file(keytab, kt_owner_uid, kt_owner_gid, ++ S_IFREG|0600, 0, NULL, false); ++ } ++ ++ if (ret != EOK) { ++ if (ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to check for %s\n", keytab); ++ } else { ++ DEBUG(SSSDBG_TRACE_FUNC, "Keytab %s is not present\n", keytab); ++ } + } + goto done; + } +@@ -648,7 +660,9 @@ static errno_t ipa_server_trust_add_1way(struct tevent_req *req) + return EIO; + } + +- ret = ipa_check_keytab(state->keytab); ++ ret = ipa_check_keytab(state->keytab, ++ state->id_ctx->server_mode->kt_owner_uid, ++ state->id_ctx->server_mode->kt_owner_gid); + if (ret == EOK) { + DEBUG(SSSDBG_TRACE_FUNC, + "Keytab already present, can add the trust\n"); +@@ -704,7 +718,9 @@ static void ipa_server_trust_1way_kt_done(struct tevent_req *subreq) + DEBUG(SSSDBG_TRACE_FUNC, + "Keytab successfully retrieved to %s\n", state->keytab); + +- ret = ipa_check_keytab(state->keytab); ++ ret = ipa_check_keytab(state->keytab, ++ state->id_ctx->server_mode->kt_owner_uid, ++ state->id_ctx->server_mode->kt_owner_gid); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "ipa_check_keytab failed: %d\n", ret); + tevent_req_error(req, ret); +@@ -1029,6 +1045,20 @@ int ipa_ad_subdom_init(struct be_ctx *be_ctx, + id_ctx->server_mode->hostname = hostname; + id_ctx->server_mode->trusts = NULL; + id_ctx->server_mode->ext_groups = NULL; ++ id_ctx->server_mode->kt_owner_uid = 0; ++ id_ctx->server_mode->kt_owner_gid = 0; ++ ++ if (getuid() == 0) { ++ /* We need to handle keytabs created by IPA oddjob script gracefully ++ * even if we're running as root and IPA creates them as the SSSD user ++ */ ++ ret = sss_user_by_name_or_uid(SSSD_USER, ++ &id_ctx->server_mode->kt_owner_uid, ++ &id_ctx->server_mode->kt_owner_gid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Failed to get ID of %s\n", SSSD_USER); ++ } ++ } + + ret = ipa_ad_subdom_reinit(be_ctx, be_ctx->ev, + be_ctx, id_ctx, be_ctx->domain); +-- +2.5.0 + diff --git a/0011-LDAP-use-ldb_binary_encode-when-printing-attribute-v.patch b/0011-LDAP-use-ldb_binary_encode-when-printing-attribute-v.patch new file mode 100644 index 0000000..eb7c7d6 --- /dev/null +++ b/0011-LDAP-use-ldb_binary_encode-when-printing-attribute-v.patch @@ -0,0 +1,47 @@ +From 4c4bc726cfc0207681c00fc386e3707d47bfe3a4 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 10 Aug 2015 12:40:30 +0200 +Subject: [PATCH 11/14] LDAP: use ldb_binary_encode when printing attribute + values +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Pavel Březina +--- + src/providers/ldap/sdap_utils.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/src/providers/ldap/sdap_utils.c b/src/providers/ldap/sdap_utils.c +index f5ce8ee54f60a6c4c4cdbd5e50b20d973c175e83..9da46ea70bf80e7f4d12fdfc7d1c97e99de8d000 100644 +--- a/src/providers/ldap/sdap_utils.c ++++ b/src/providers/ldap/sdap_utils.c +@@ -35,6 +35,7 @@ sdap_attrs_add_ldap_attr(struct sysdb_attrs *ldap_attrs, + const char *objname = name ?: "object"; + const char *desc = attr_desc ?: attr_name; + unsigned int num_values, i; ++ char *printable; + + ret = sysdb_attrs_get_el(ldap_attrs, attr_name, &el); + if (ret) { +@@ -50,8 +51,16 @@ sdap_attrs_add_ldap_attr(struct sysdb_attrs *ldap_attrs, + } else { + num_values = multivalued ? el->num_values : 1; + for (i = 0; i < num_values; i++) { ++ printable = ldb_binary_encode(ldap_attrs, el->values[i]); ++ if (printable == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "ldb_binary_encode failed..\n"); ++ continue; ++ } ++ + DEBUG(SSSDBG_TRACE_INTERNAL, "Adding %s [%s] to attributes " +- "of [%s].\n", desc, el->values[i].data, objname); ++ "of [%s].\n", desc, printable, objname); ++ ++ talloc_zfree(printable); + + ret = sysdb_attrs_add_mem(attrs, attr_name, el->values[i].data, + el->values[i].length); +-- +2.5.0 + diff --git a/0012-IPA-Change-the-default-of-ldap_user_certificate-to-u.patch b/0012-IPA-Change-the-default-of-ldap_user_certificate-to-u.patch new file mode 100644 index 0000000..b38eac2 --- /dev/null +++ b/0012-IPA-Change-the-default-of-ldap_user_certificate-to-u.patch @@ -0,0 +1,50 @@ +From 4c8af4a9bd8b0cdfa6820b3a39ae958869957dcb Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 10 Aug 2015 12:40:39 +0200 +Subject: [PATCH 12/14] IPA: Change the default of ldap_user_certificate to + userCertificate;binary +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is safe from ldb point of view, because ldb gurantees the data is +NULL-terminated. We must be careful before we save the data, though. + +Resolves: +https://fedorahosted.org/sssd/ticket/2742 + +Reviewed-by: Pavel Březina +--- + src/man/sssd-ldap.5.xml | 2 +- + src/providers/ipa/ipa_opts.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml +index f14090843fd32141ad4f491b69868aa7b2412301..0239f656e4fab7d8d85a922fdd0978acd80a236b 100644 +--- a/src/man/sssd-ldap.5.xml ++++ b/src/man/sssd-ldap.5.xml +@@ -821,7 +821,7 @@ + certificate of the user. + + +- Default: no set in the general case, userCertificate ++ Default: no set in the general case, userCertificate;binary + for IPA + + +diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h +index 253c0715355536cc181c57beed5326a77e87e464..2f92ad765a1ca53611ed82e5e749c39d6f20a150 100644 +--- a/src/providers/ipa/ipa_opts.h ++++ b/src/providers/ipa/ipa_opts.h +@@ -203,7 +203,7 @@ struct sdap_attr_map ipa_user_map[] = { + { "ldap_user_nds_login_allowed_time_map", "loginAllowedTimeMap", SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL }, + { "ldap_user_ssh_public_key", "ipaSshPubKey", SYSDB_SSH_PUBKEY, NULL }, + { "ldap_user_auth_type", "ipaUserAuthType", SYSDB_AUTH_TYPE, NULL }, +- { "ldap_user_certificate", "userCertificate", SYSDB_USER_CERT, NULL }, ++ { "ldap_user_certificate", "userCertificate;binary", SYSDB_USER_CERT, NULL }, + SDAP_ATTR_MAP_TERMINATOR + }; + +-- +2.5.0 + diff --git a/0013-UTIL-Provide-a-common-interface-to-safely-create-tem.patch b/0013-UTIL-Provide-a-common-interface-to-safely-create-tem.patch new file mode 100644 index 0000000..4e3cb2d --- /dev/null +++ b/0013-UTIL-Provide-a-common-interface-to-safely-create-tem.patch @@ -0,0 +1,377 @@ +From e3f5577a446e1f6f37c1dfd2c7d6c95f5c4551ab Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Wed, 12 Aug 2015 12:41:44 +0200 +Subject: [PATCH 13/14] UTIL: Provide a common interface to safely create + temporary files +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Pavel Březina +--- + src/tests/cmocka/test_utils.c | 175 ++++++++++++++++++++++++++++++++++++++++++ + src/util/util.c | 127 ++++++++++++++++++++++++++++++ + src/util/util.h | 21 +++++ + 3 files changed, 323 insertions(+) + +diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c +index d3d00feda0bdd4048519f90ba48ae9d1042a95a1..c7ebe0997ec00197e8852bedbcf26ef1f6394fc3 100644 +--- a/src/tests/cmocka/test_utils.c ++++ b/src/tests/cmocka/test_utils.c +@@ -1212,6 +1212,168 @@ void test_fix_domain_in_name_list(void **state) + talloc_free(dom); + } + ++struct unique_file_test_ctx { ++ char *filename; ++}; ++ ++static int unique_file_test_setup(void **state) ++{ ++ struct unique_file_test_ctx *test_ctx; ++ ++ assert_true(leak_check_setup()); ++ check_leaks_push(global_talloc_context); ++ ++ test_ctx = talloc_zero(global_talloc_context, struct unique_file_test_ctx); ++ assert_non_null(test_ctx); ++ ++ test_ctx->filename = talloc_strdup(test_ctx, "test_unique_file_XXXXXX"); ++ assert_non_null(test_ctx); ++ ++ *state = test_ctx; ++ return 0; ++} ++ ++static int unique_file_test_teardown(void **state) ++{ ++ struct unique_file_test_ctx *test_ctx; ++ errno_t ret; ++ ++ test_ctx = talloc_get_type(*state, struct unique_file_test_ctx); ++ ++ errno = 0; ++ ret = unlink(test_ctx->filename); ++ if (ret != 0 && errno != ENOENT) { ++ fail(); ++ } ++ ++ talloc_free(test_ctx); ++ assert_true(check_leaks_pop(global_talloc_context) == true); ++ assert_true(leak_check_teardown()); ++ return 0; ++} ++ ++static void assert_destructor(TALLOC_CTX *owner, ++ struct unique_file_test_ctx *test_ctx) ++{ ++ int fd; ++ errno_t ret; ++ char *check_filename; ++ ++ /* Test that the destructor works */ ++ if (owner == NULL) { ++ return; ++ } ++ ++ check_filename = talloc_strdup(test_ctx, test_ctx->filename); ++ assert_non_null(check_filename); ++ ++ talloc_free(owner); ++ ++ ret = check_and_open_readonly(test_ctx->filename, &fd, ++ geteuid(), getegid(), ++ (S_IRUSR | S_IWUSR | S_IFREG), 0); ++ close(fd); ++ assert_int_not_equal(ret, EOK); ++} ++ ++static void sss_unique_file_test(struct unique_file_test_ctx *test_ctx, ++ bool test_destructor) ++{ ++ int fd; ++ errno_t ret; ++ struct stat sb; ++ TALLOC_CTX *owner = NULL; ++ ++ if (test_destructor) { ++ owner = talloc_new(test_ctx); ++ assert_non_null(owner); ++ } ++ ++ fd = sss_unique_file(owner, test_ctx->filename, &ret); ++ assert_int_not_equal(fd, -1); ++ assert_int_equal(ret, EOK); ++ ++ ret = check_fd(fd, geteuid(), getegid(), ++ (S_IRUSR | S_IWUSR | S_IFREG), 0, &sb); ++ close(fd); ++ assert_int_equal(ret, EOK); ++ ++ assert_destructor(owner, test_ctx); ++} ++ ++static void test_sss_unique_file(void **state) ++{ ++ struct unique_file_test_ctx *test_ctx; ++ test_ctx = talloc_get_type(*state, struct unique_file_test_ctx); ++ sss_unique_file_test(test_ctx, false); ++} ++ ++static void test_sss_unique_file_destruct(void **state) ++{ ++ struct unique_file_test_ctx *test_ctx; ++ test_ctx = talloc_get_type(*state, struct unique_file_test_ctx); ++ sss_unique_file_test(test_ctx, true); ++} ++ ++static void test_sss_unique_file_neg(void **state) ++{ ++ int fd; ++ errno_t ret; ++ ++ fd = sss_unique_file(NULL, discard_const("badpattern"), &ret); ++ assert_int_equal(fd, -1); ++ assert_int_equal(ret, EINVAL); ++} ++ ++static void sss_unique_filename_test(struct unique_file_test_ctx *test_ctx, ++ bool test_destructor) ++{ ++ int fd; ++ errno_t ret; ++ char *tmp_filename; ++ TALLOC_CTX *owner = NULL; ++ ++ tmp_filename = talloc_strdup(test_ctx, test_ctx->filename); ++ assert_non_null(tmp_filename); ++ ++ if (test_destructor) { ++ owner = talloc_new(test_ctx); ++ assert_non_null(owner); ++ } ++ ++ ret = sss_unique_filename(owner, test_ctx->filename); ++ assert_int_equal(ret, EOK); ++ ++ assert_int_equal(strncmp(test_ctx->filename, ++ tmp_filename, ++ strlen(tmp_filename) - sizeof("XXXXXX")), ++ 0); ++ ++ ret = check_and_open_readonly(test_ctx->filename, &fd, ++ geteuid(), getegid(), ++ (S_IRUSR | S_IWUSR | S_IFREG), 0); ++ close(fd); ++ assert_int_equal(ret, EOK); ++ ++ assert_destructor(owner, test_ctx); ++} ++ ++static void test_sss_unique_filename(void **state) ++{ ++ struct unique_file_test_ctx *test_ctx; ++ ++ test_ctx = talloc_get_type(*state, struct unique_file_test_ctx); ++ sss_unique_filename_test(test_ctx, false); ++} ++ ++static void test_sss_unique_filename_destruct(void **state) ++{ ++ struct unique_file_test_ctx *test_ctx; ++ ++ test_ctx = talloc_get_type(*state, struct unique_file_test_ctx); ++ sss_unique_filename_test(test_ctx, true); ++} ++ + int main(int argc, const char *argv[]) + { + poptContext pc; +@@ -1275,6 +1437,19 @@ int main(int argc, const char *argv[]) + cmocka_unit_test_setup_teardown(test_fix_domain_in_name_list, + confdb_test_setup, + confdb_test_teardown), ++ cmocka_unit_test_setup_teardown(test_sss_unique_file, ++ unique_file_test_setup, ++ unique_file_test_teardown), ++ cmocka_unit_test_setup_teardown(test_sss_unique_file_destruct, ++ unique_file_test_setup, ++ unique_file_test_teardown), ++ cmocka_unit_test(test_sss_unique_file_neg), ++ cmocka_unit_test_setup_teardown(test_sss_unique_filename, ++ unique_file_test_setup, ++ unique_file_test_teardown), ++ cmocka_unit_test_setup_teardown(test_sss_unique_filename_destruct, ++ unique_file_test_setup, ++ unique_file_test_teardown), + }; + + /* Set debug level to invalid value so we can deside if -d 0 was used. */ +diff --git a/src/util/util.c b/src/util/util.c +index cfd26a58b31048996e9669163b821282b219b2de..61e5efedce45ba4a70d57ce19406eafe8373692c 100644 +--- a/src/util/util.c ++++ b/src/util/util.c +@@ -957,3 +957,130 @@ errno_t sss_utc_to_time_t(const char *str, const char *format, time_t *_unix_tim + *_unix_time = ut; + return EOK; + } ++ ++struct tmpfile_watch { ++ const char *filename; ++}; ++ ++static int unlink_dbg(const char *filename) ++{ ++ errno_t ret; ++ ++ ret = unlink(filename); ++ if (ret != 0) { ++ if (errno == 2) { ++ DEBUG(SSSDBG_TRACE_INTERNAL, ++ "File already removed: [%s]\n", filename); ++ return 0; ++ } else { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot remove temporary file [%s]\n", filename); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++static int unique_filename_destructor(void *memptr) ++{ ++ struct tmpfile_watch *tw = talloc_get_type(memptr, struct tmpfile_watch); ++ ++ if (tw == NULL || tw->filename == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Wrong private pointer\n"); ++ return -1; ++ } ++ ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Unlinking [%s]\n", tw->filename); ++ ++ return unlink_dbg(tw->filename); ++} ++ ++static struct tmpfile_watch *tmpfile_watch_set(TALLOC_CTX *owner, ++ const char *filename) ++{ ++ struct tmpfile_watch *tw = NULL; ++ ++ tw = talloc_zero(owner, struct tmpfile_watch); ++ if (tw == NULL) { ++ return NULL; ++ } ++ ++ tw->filename = talloc_strdup(tw, filename); ++ if (tw->filename == NULL) { ++ talloc_free(tw); ++ return NULL; ++ } ++ ++ talloc_set_destructor((TALLOC_CTX *) tw, ++ unique_filename_destructor); ++ return tw; ++} ++ ++int sss_unique_file_ex(TALLOC_CTX *owner, ++ char *path_tmpl, ++ mode_t file_umask, ++ errno_t *_err) ++{ ++ size_t tmpl_len; ++ errno_t ret; ++ int fd = -1; ++ mode_t old_umask; ++ struct tmpfile_watch *tw = NULL; ++ ++ tmpl_len = strlen(path_tmpl); ++ if (tmpl_len < 6 || strcmp(path_tmpl + (tmpl_len - 6), "XXXXXX") != 0) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Template too short or doesn't end with XXXXXX!\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ old_umask = umask(file_umask); ++ fd = mkstemp(path_tmpl); ++ umask(old_umask); ++ if (fd == -1) { ++ ret = errno; ++ DEBUG(SSSDBG_OP_FAILURE, ++ "mkstemp(\"%s\") failed [%d]: %s!\n", ++ path_tmpl, ret, strerror(ret)); ++ goto done; ++ } ++ ++ if (owner != NULL) { ++ tw = tmpfile_watch_set(owner, path_tmpl); ++ if (tw == NULL) { ++ unlink_dbg(path_tmpl); ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ ret = EOK; ++done: ++ if (_err) { ++ *_err = ret; ++ } ++ return fd; ++} ++ ++int sss_unique_file(TALLOC_CTX *owner, ++ char *path_tmpl, ++ errno_t *_err) ++{ ++ return sss_unique_file_ex(owner, path_tmpl, 077, _err); ++} ++ ++errno_t sss_unique_filename(TALLOC_CTX *owner, char *path_tmpl) ++{ ++ int fd; ++ errno_t ret; ++ ++ fd = sss_unique_file(owner, path_tmpl, &ret); ++ /* We only care about a unique file name */ ++ if (fd >= 0) { ++ close(fd); ++ } ++ ++ return ret; ++} +diff --git a/src/util/util.h b/src/util/util.h +index 3d90cf0d1024b93016987a4d3e8a515359fd974d..ecbed1c9843b16ba6cf31927c6fd3db8c72aefde 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -653,4 +653,25 @@ int get_seuser(TALLOC_CTX *mem_ctx, const char *login_name, + /* convert time from generalized form to unix time */ + errno_t sss_utc_to_time_t(const char *str, const char *format, time_t *unix_time); + ++/* Creates a unique file using mkstemp with provided umask. The template ++ * must end with XXXXXX. Returns the fd, sets _err to an errno value on error. ++ * ++ * Prefer using sss_unique_file() as it uses a secure umask internally. ++ */ ++int sss_unique_file_ex(TALLOC_CTX *mem_ctx, ++ char *path_tmpl, ++ mode_t file_umask, ++ errno_t *_err); ++int sss_unique_file(TALLOC_CTX *owner, ++ char *path_tmpl, ++ errno_t *_err); ++ ++/* Creates a unique filename using mkstemp with secure umask. The template ++ * must end with XXXXXX ++ * ++ * path_tmpl must be a talloc context. Destructor would be set on the filename ++ * so that it's guaranteed the file is removed. ++ */ ++int sss_unique_filename(TALLOC_CTX *owner, char *path_tmpl); ++ + #endif /* __SSSD_UTIL_H__ */ +-- +2.5.0 + diff --git a/0014-IPA-Always-re-fetch-the-keytab-from-the-IPA-server.patch b/0014-IPA-Always-re-fetch-the-keytab-from-the-IPA-server.patch new file mode 100644 index 0000000..22026d5 --- /dev/null +++ b/0014-IPA-Always-re-fetch-the-keytab-from-the-IPA-server.patch @@ -0,0 +1,447 @@ +From b2d318b91bb9d6ea1bef827031b980b8d6ec7b44 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Fri, 24 Jul 2015 13:13:08 +0200 +Subject: [PATCH 14/14] IPA: Always re-fetch the keytab from the IPA server +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Even if a keytab for one-way trust exists, re-fetch the keytab again and +try to use it. Fall back to the previous one if it exists. + +This is in order to allow the admin to re-establish the trust keytabs +with a simple sssd restart. + +Reviewed-by: Pavel Březina +--- + Makefile.am | 2 + + src/providers/ipa/ipa_subdomains.c | 4 +- + src/providers/ipa/ipa_subdomains_server.c | 83 +++++++++---- + src/tests/cmocka/test_ipa_subdomains_server.c | 166 ++++++++++++++++++++++++-- + 4 files changed, 221 insertions(+), 34 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index b8cbc6df23ded1edb945a709b6dbe1c44eb54017..4e58b4f419607272f35363875054320af0899dcf 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2501,6 +2501,8 @@ test_ipa_subdom_server_LDFLAGS = \ + -Wl,-wrap,krb5_kt_default \ + -Wl,-wrap,execle \ + -Wl,-wrap,execve \ ++ -Wl,-wrap,rename \ ++ -Wl,-wrap,sss_unique_filename \ + $(NULL) + test_ipa_subdom_server_LDADD = \ + $(PAM_LIBS) \ +diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c +index cf72784473747c67d44a5d887faf867cfe62ce2b..c688ddb9bb9b643e0695c1901a4ca467f71853da 100644 +--- a/src/providers/ipa/ipa_subdomains.c ++++ b/src/providers/ipa/ipa_subdomains.c +@@ -264,7 +264,7 @@ static errno_t ipa_ranges_parse_results(TALLOC_CTX *mem_ctx, + 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")); ++ DEBUG(SSSDBG_OP_FAILURE, "get_idmap_data_from_range failed.\n"); + goto done; + } + for (d = 0; d < c; d++) { +@@ -272,7 +272,7 @@ static errno_t ipa_ranges_parse_results(TALLOC_CTX *mem_ctx, + &sid2, &rid2, &range2, &mapping2); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, +- ("get_idmap_data_from_range failed.\n")); ++ "get_idmap_data_from_range failed.\n"); + goto done; + } + +diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c +index 4bfea61e6dd0a02f6b723a39f7ba236c914009b0..dfecab1bc362b5772379bae6d51f9cef8443f225 100644 +--- a/src/providers/ipa/ipa_subdomains_server.c ++++ b/src/providers/ipa/ipa_subdomains_server.c +@@ -445,6 +445,17 @@ static void ipa_getkeytab_exec(const char *ccache, + exit(1); + } + ++ /* ipa-getkeytab cannot add keys to an empty file, let's unlink it and only ++ * use the filename */ ++ ret = unlink(keytab_path); ++ if (ret == -1) { ++ ret = errno; ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to unlink the temporary ccname [%d][%s]\n", ++ ret, sss_strerror(ret)); ++ exit(1); ++ } ++ + errno = 0; + ret = execle(IPA_GETKEYTAB_PATH, IPA_GETKEYTAB_PATH, + "-r", "-s", server, "-p", principal, "-k", keytab_path, NULL, +@@ -561,6 +572,7 @@ struct ipa_server_trust_add_state { + uint32_t direction; + const char *forest; + const char *keytab; ++ char *new_keytab; + const char *principal; + const char *forest_realm; + const char *ccache; +@@ -660,21 +672,20 @@ static errno_t ipa_server_trust_add_1way(struct tevent_req *req) + return EIO; + } + +- ret = ipa_check_keytab(state->keytab, +- state->id_ctx->server_mode->kt_owner_uid, +- state->id_ctx->server_mode->kt_owner_gid); +- if (ret == EOK) { +- DEBUG(SSSDBG_TRACE_FUNC, +- "Keytab already present, can add the trust\n"); +- return EOK; +- } else if (ret != ENOENT) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Failed to check for keytab: %d\n", ret); ++ state->new_keytab = talloc_asprintf(state, "%sXXXXXX", state->keytab); ++ if (state->new_keytab == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot set up ipa_get_keytab\n"); ++ return ENOMEM; ++ } ++ ++ ret = sss_unique_filename(state, state->new_keytab); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create temporary keytab name\n"); + return ret; + } + + DEBUG(SSSDBG_TRACE_FUNC, +- "No keytab for %s\n", state->subdom->name); ++ "Will re-fetch keytab for %s\n", state->subdom->name); + + hostname = dp_opt_get_string(state->id_ctx->ipa_options->basic, + IPA_HOSTNAME); +@@ -691,7 +702,7 @@ static errno_t ipa_server_trust_add_1way(struct tevent_req *req) + state->ccache, + hostname, + state->principal, +- state->keytab); ++ state->new_keytab); + if (subreq == NULL) { + return ENOMEM; + } +@@ -710,23 +721,49 @@ static void ipa_server_trust_1way_kt_done(struct tevent_req *subreq) + ret = ipa_getkeytab_recv(subreq, NULL); + talloc_zfree(subreq); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "ipa_getkeytab_recv failed: %d\n", ret); +- tevent_req_error(req, ret); +- return; ++ /* Do not fail here, but try to check and use the previous keytab, ++ * if any */ ++ DEBUG(SSSDBG_MINOR_FAILURE, "ipa_getkeytab_recv failed: %d\n", ret); ++ } else { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Keytab successfully retrieved to %s\n", state->new_keytab); + } + +- DEBUG(SSSDBG_TRACE_FUNC, +- "Keytab successfully retrieved to %s\n", state->keytab); +- +- ret = ipa_check_keytab(state->keytab, ++ ret = ipa_check_keytab(state->new_keytab, + state->id_ctx->server_mode->kt_owner_uid, + state->id_ctx->server_mode->kt_owner_gid); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "ipa_check_keytab failed: %d\n", ret); +- tevent_req_error(req, ret); +- return; ++ if (ret == EOK) { ++ ret = rename(state->new_keytab, state->keytab); ++ if (ret == -1) { ++ ret = errno; ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "rename failed [%d][%s].\n", ret, strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Keytab renamed to %s\n", state->keytab); ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Trying to recover and use the previous keytab, if available\n"); ++ ret = ipa_check_keytab(state->keytab, ++ state->id_ctx->server_mode->kt_owner_uid, ++ state->id_ctx->server_mode->kt_owner_gid); ++ if (ret == EOK) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "The previous keytab %s contains the expected principal\n", ++ state->keytab); ++ } else { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot use the old keytab: %d\n", ret); ++ /* Nothing we can do now */ ++ tevent_req_error(req, ret); ++ return; ++ } + } + ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Keytab %s contains the expected principals\n", state->new_keytab); ++ + ret = ipa_server_trust_add_step(req); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, +diff --git a/src/tests/cmocka/test_ipa_subdomains_server.c b/src/tests/cmocka/test_ipa_subdomains_server.c +index a4cb8c2b7538dc84b74e0227205b73780844b652..fb9bd80e299c05fa230599d442fa361ae757dcd3 100644 +--- a/src/tests/cmocka/test_ipa_subdomains_server.c ++++ b/src/tests/cmocka/test_ipa_subdomains_server.c +@@ -66,33 +66,79 @@ + #define ONEWAY_PRINC DOM_FLAT"$" + #define ONEWAY_AUTHID ONEWAY_PRINC"@"SUBDOM_REALM + ++static bool global_rename_called; ++ + krb5_error_code __wrap_krb5_kt_default(krb5_context context, krb5_keytab *id) + { + return krb5_kt_resolve(context, KEYTAB_PATH, id); + } + +-static void create_dummy_keytab(void) ++static void create_dummy_keytab(const char *dummy_kt) + { + errno_t ret; + +- assert_non_null(ONEWAY_KEYTAB); ++ assert_non_null(dummy_kt); + mock_keytab_with_contents(global_talloc_context, +- ONEWAY_KEYTAB, ONEWAY_AUTHID); ++ dummy_kt, ONEWAY_AUTHID); + +- ret = access(ONEWAY_KEYTAB, R_OK); ++ ret = access(dummy_kt, R_OK); + assert_int_equal(ret, 0); + } + ++static int wrap_exec(void) ++{ ++ const char *test_kt; ++ const char *fail_creating_kt; ++ ++ test_kt = getenv("TEST_KT_ENV"); ++ if (test_kt == NULL) { ++ _exit(1); ++ } ++ unsetenv("TEST_KT_ENV"); ++ ++ fail_creating_kt = getenv("KT_CREATE_FAIL"); ++ if (fail_creating_kt != NULL) { ++ _exit(1); ++ } ++ ++ create_dummy_keytab(test_kt); ++ _exit(0); ++ ++ return 1; /* Should not happen */ ++} ++ + int __wrap_execle(const char *path, const char *arg, ...) + { +- create_dummy_keytab(); +- _exit(0); ++ return wrap_exec(); + } + + int __wrap_execve(const char *path, const char *arg, ...) + { +- create_dummy_keytab(); +- _exit(0); ++ return wrap_exec(); ++} ++ ++errno_t __real_sss_unique_filename(TALLOC_CTX *owner, char *path_tmpl); ++ ++errno_t __wrap_sss_unique_filename(TALLOC_CTX *owner, char *path_tmpl) ++{ ++ int ret; ++ int sret; ++ ++ ret = __real_sss_unique_filename(owner, path_tmpl); ++ if (ret == EOK) { ++ ++ sret = setenv("TEST_KT_ENV", path_tmpl, 1); ++ assert_int_equal(sret, 0); ++ } ++ return ret; ++} ++ ++int __real_rename(const char *old, const char *new); ++ ++int __wrap_rename(const char *old, const char *new) ++{ ++ global_rename_called = true; ++ return __real_rename(old, new); + } + + struct trust_test_ctx { +@@ -100,6 +146,7 @@ struct trust_test_ctx { + struct be_ctx *be_ctx; + + struct ipa_id_ctx *ipa_ctx; ++ bool expect_rename; + }; + + static struct ipa_id_ctx *mock_ipa_ctx(TALLOC_CTX *mem_ctx, +@@ -244,6 +291,8 @@ static int test_ipa_server_create_trusts_setup(void **state) + + mock_keytab_with_contents(test_ctx, KEYTAB_PATH, KEYTAB_TEST_PRINC); + ++ global_rename_called = false; ++ + *state = test_ctx; + return 0; + } +@@ -260,6 +309,11 @@ static int test_ipa_server_create_trusts_teardown(void **state) + unlink(ONEWAY_KEYTAB); + /* Ignore failures */ + ++ /* If a test needs this variable, it should be set again in ++ * each test ++ */ ++ unsetenv("KT_CREATE_FAIL"); ++ + talloc_free(test_ctx); + return 0; + } +@@ -612,6 +666,8 @@ static void test_ipa_server_create_oneway(void **state) + + assert_null(test_ctx->ipa_ctx->server_mode->trusts); + ++ test_ctx->expect_rename = true; ++ + req = ipa_server_create_trusts_send(test_ctx, + test_ctx->tctx->ev, + test_ctx->be_ctx, +@@ -635,6 +691,8 @@ static void test_ipa_server_create_trusts_oneway(struct tevent_req *req) + talloc_zfree(req); + assert_int_equal(ret, EOK); + ++ assert_true(test_ctx->expect_rename == global_rename_called); ++ + ret = access(ONEWAY_KEYTAB, R_OK); + assert_int_equal(ret, 0); + +@@ -674,10 +732,46 @@ static void test_ipa_server_create_oneway_kt_exists(void **state) + + add_test_1way_subdomains(test_ctx); + +- create_dummy_keytab(); ++ create_dummy_keytab(ONEWAY_KEYTAB); + ret = access(ONEWAY_KEYTAB, R_OK); + assert_int_equal(ret, 0); + ++ test_ctx->expect_rename = true; ++ ++ assert_null(test_ctx->ipa_ctx->server_mode->trusts); ++ ++ req = ipa_server_create_trusts_send(test_ctx, ++ test_ctx->tctx->ev, ++ test_ctx->be_ctx, ++ test_ctx->ipa_ctx, ++ test_ctx->be_ctx->domain); ++ assert_non_null(req); ++ ++ tevent_req_set_callback(req, test_ipa_server_create_trusts_oneway, test_ctx); ++ ++ ret = test_ev_loop(test_ctx->tctx); ++ assert_int_equal(ret, ERR_OK); ++} ++ ++/* Test scenario where a keytab already exists, but refresh fails. In this case, ++ * sssd should attempt to reuse the previous keytab ++ */ ++static void test_ipa_server_create_oneway_kt_refresh_fallback(void **state) ++{ ++ struct trust_test_ctx *test_ctx = ++ talloc_get_type(*state, struct trust_test_ctx); ++ struct tevent_req *req; ++ errno_t ret; ++ ++ add_test_1way_subdomains(test_ctx); ++ ++ create_dummy_keytab(ONEWAY_KEYTAB); ++ ret = access(ONEWAY_KEYTAB, R_OK); ++ assert_int_equal(ret, 0); ++ ++ setenv("KT_CREATE_FAIL", "1", 1); ++ test_ctx->expect_rename = false; ++ + assert_null(test_ctx->ipa_ctx->server_mode->trusts); + + req = ipa_server_create_trusts_send(test_ctx, +@@ -693,6 +787,54 @@ static void test_ipa_server_create_oneway_kt_exists(void **state) + assert_int_equal(ret, ERR_OK); + } + ++/* Tests case where there's no keytab and retrieving fails. Just fail the ++ * request in that case ++ */ ++static void test_ipa_server_create_trusts_oneway_fail(struct tevent_req *req); ++ ++static void test_ipa_server_create_oneway_kt_refresh_fail(void **state) ++{ ++ struct trust_test_ctx *test_ctx = ++ talloc_get_type(*state, struct trust_test_ctx); ++ struct tevent_req *req; ++ errno_t ret; ++ ++ add_test_1way_subdomains(test_ctx); ++ ++ setenv("KT_CREATE_FAIL", "1", 1); ++ test_ctx->expect_rename = false; ++ ++ assert_null(test_ctx->ipa_ctx->server_mode->trusts); ++ ++ req = ipa_server_create_trusts_send(test_ctx, ++ test_ctx->tctx->ev, ++ test_ctx->be_ctx, ++ test_ctx->ipa_ctx, ++ test_ctx->be_ctx->domain); ++ assert_non_null(req); ++ ++ tevent_req_set_callback(req, ++ test_ipa_server_create_trusts_oneway_fail, ++ test_ctx); ++ ++ ret = test_ev_loop(test_ctx->tctx); ++ assert_int_equal(ret, ERR_OK); ++} ++ ++static void test_ipa_server_create_trusts_oneway_fail(struct tevent_req *req) ++{ ++ struct trust_test_ctx *test_ctx = \ ++ tevent_req_callback_data(req, struct trust_test_ctx); ++ errno_t ret; ++ ++ ret = ipa_server_create_trusts_recv(req); ++ assert_int_not_equal(ret, EOK); ++ ++ assert_true(test_ctx->expect_rename == global_rename_called); ++ ++ test_ev_done(test_ctx->tctx, EOK); ++} ++ + static void test_ipa_server_trust_oneway_init(void **state) + { + struct trust_test_ctx *test_ctx = +@@ -749,6 +891,12 @@ int main(int argc, const char *argv[]) + cmocka_unit_test_setup_teardown(test_ipa_server_create_oneway_kt_exists, + test_ipa_server_create_trusts_setup, + test_ipa_server_create_trusts_teardown), ++ cmocka_unit_test_setup_teardown(test_ipa_server_create_oneway_kt_refresh_fallback, ++ test_ipa_server_create_trusts_setup, ++ test_ipa_server_create_trusts_teardown), ++ cmocka_unit_test_setup_teardown(test_ipa_server_create_oneway_kt_refresh_fail, ++ test_ipa_server_create_trusts_setup, ++ test_ipa_server_create_trusts_teardown), + cmocka_unit_test_setup_teardown(test_ipa_server_trust_oneway_init, + test_ipa_server_create_trusts_setup, + test_ipa_server_create_trusts_teardown), +-- +2.5.0 + diff --git a/sssd.spec b/sssd.spec index fab2936..262f564 100644 --- a/sssd.spec +++ b/sssd.spec @@ -29,7 +29,7 @@ Name: sssd Version: 1.13.0 -Release: 4%{?dist} +Release: 5%{?dist} Group: Applications/System Summary: System Security Services Daemon License: GPLv3+ @@ -40,6 +40,18 @@ BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) ### Patches ### Patch0001: 0001-SSSDConfig-return-list-for-list_active_domains.patch Patch0002: 0002-KRB5-Return-right-data-provider-error-code.patch +Patch0003: 0003-DYNDNS-sss_iface_addr_list_get-return-ENOENT.patch +Patch0004: 0004-DYNDNS-support-mult.-interfaces-for-dyndns_iface-opt.patch +Patch0005: 0005-DYNDNS-special-value-for-dyndns_iface-option.patch +Patch0006: 0006-TESTS-dyndns-tests-support-AAAA-addresses.patch +Patch0007: 0007-IPA-Remove-MPG-groups-if-getgrgid-was-called-before-.patch +Patch0008: 0008-IPA-Better-debugging.patch +Patch0009: 0009-UTIL-Lower-debug-level-in-perform_checks.patch +Patch0010: 0010-IPA-Handle-sssd-owned-keytabs-when-running-as-root.patch +Patch0011: 0011-LDAP-use-ldb_binary_encode-when-printing-attribute-v.patch +Patch0012: 0012-IPA-Change-the-default-of-ldap_user_certificate-to-u.patch +Patch0013: 0013-UTIL-Provide-a-common-interface-to-safely-create-tem.patch +Patch0014: 0014-IPA-Always-re-fetch-the-keytab-from-the-IPA-server.patch ### Dependencies ### Requires: sssd-common = %{version}-%{release} @@ -1012,10 +1024,14 @@ fi %{_libdir}/%{name}/modules/libwbclient.so %changelog +* Mon Sep 07 2015 Lukas Slebodnik - 1.13.0-5 +- Backport upstream patches required by FreeIPA 4.2.1 + * Tue Jul 21 2015 Lukas Slebodnik - 1.13.0-4 - Fix ipa-migration bug - Resolves: upstream #2719 - IPA: returned unknown dp error code with disabled migration mode + * Wed Jul 08 2015 Lukas Slebodnik - 1.13.0-3 - New upstream release 1.13.0 - https://fedorahosted.org/sssd/wiki/Releases/Notes-1.13.0