Backport upstream patches required by FreeIPA 4.2.1

This commit is contained in:
Lukas Slebodnik 2015-09-07 18:37:40 +02:00
parent cc1ba0d674
commit cc6c9ff159
13 changed files with 1748 additions and 1 deletions

View File

@ -0,0 +1,98 @@
From a74f42e33fd62be175c30574242a214cdce14b06 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <preichl@redhat.com>
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

View File

@ -0,0 +1,194 @@
From 7a7696e489087f3e02f7d484766dc55112fe7803 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <preichl@redhat.com>
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
<listitem>
<para>
Optional. Applicable only when dyndns_update
- is true. Choose the interface whose IP address
- should be used for dynamic DNS updates.
- </para>
- <para>
- 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.
</para>
<para>
Default: Use the IP address of the AD LDAP connection
</para>
+ <para>
+ Example: dyndns_iface = em1, vnet1, vnet2
+ </para>
</listitem>
</varlistentry>
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 @@
<listitem>
<para>
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.
</para>
<para>
- NOTE: This option currently supports only one interface.
+ NOTE: This option currently supports multiple interfaces.
</para>
<para>
NOTE: While it is still possible to use the old
@@ -181,6 +182,9 @@
<para>
Default: Use the IP address of the IPA LDAP connection
</para>
+ <para>
+ Example: dyndns_iface = em1, vnet1, vnet2
+ </para>
</listitem>
</varlistentry>
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

View File

@ -0,0 +1,107 @@
From ef7a48d5acc481a207ac2821fc43651641f1b298 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <preichl@redhat.com>
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 <quote>*</quote> implies that
+ IPs from all interfaces should be used.
</para>
<para>
- 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
</para>
<para>
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.
- </para>
- <para>
- NOTE: This option currently supports multiple interfaces.
+ updates. Special value <quote>*</quote> implies that
+ IPs from all interfaces should be used.
</para>
<para>
NOTE: While it is still possible to use the old
@@ -180,7 +178,8 @@
in their config file.
</para>
<para>
- 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
</para>
<para>
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

View File

@ -0,0 +1,130 @@
From cef454da178e7e7f097fade886f4d06ba6aa0f4f Mon Sep 17 00:00:00 2001
From: Pavel Reichl <preichl@redhat.com>
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

View File

@ -0,0 +1,88 @@
From 2322de0bd2fdc6b2ca64969df35662ab962620a4 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
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 <sbose@redhat.com>
---
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

View File

@ -0,0 +1,27 @@
From f2fd03807a6a7d92b706f0964bd1bcf172766cd6 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Wed, 22 Jul 2015 15:17:57 +0200
Subject: [PATCH 08/14] IPA: Better debugging
Reviewed-by: Alexander Bokovoy <abokovoy@redhat.com>
---
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

View File

@ -0,0 +1,50 @@
From b5e5c04b5af74537c95213a72d4c916b50c05588 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
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 <abokovoy@redhat.com>
---
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

View File

@ -0,0 +1,116 @@
From 629fba06bc02e6ff4b25680532d298552fa55b22 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
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 <abokovoy@redhat.com>
---
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

View File

@ -0,0 +1,47 @@
From 4c4bc726cfc0207681c00fc386e3707d47bfe3a4 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
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 <pbrezina@redhat.com>
---
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

View File

@ -0,0 +1,50 @@
From 4c8af4a9bd8b0cdfa6820b3a39ae958869957dcb Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
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 <pbrezina@redhat.com>
---
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.
</para>
<para>
- Default: no set in the general case, userCertificate
+ Default: no set in the general case, userCertificate;binary
for IPA
</para>
</listitem>
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

View File

@ -0,0 +1,377 @@
From e3f5577a446e1f6f37c1dfd2c7d6c95f5c4551ab Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
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 <pbrezina@redhat.com>
---
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

View File

@ -0,0 +1,447 @@
From b2d318b91bb9d6ea1bef827031b980b8d6ec7b44 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
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 <pbrezina@redhat.com>
---
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

View File

@ -29,7 +29,7 @@
Name: sssd Name: sssd
Version: 1.13.0 Version: 1.13.0
Release: 4%{?dist} Release: 5%{?dist}
Group: Applications/System Group: Applications/System
Summary: System Security Services Daemon Summary: System Security Services Daemon
License: GPLv3+ License: GPLv3+
@ -40,6 +40,18 @@ BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
### Patches ### ### Patches ###
Patch0001: 0001-SSSDConfig-return-list-for-list_active_domains.patch Patch0001: 0001-SSSDConfig-return-list-for-list_active_domains.patch
Patch0002: 0002-KRB5-Return-right-data-provider-error-code.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 ### ### Dependencies ###
Requires: sssd-common = %{version}-%{release} Requires: sssd-common = %{version}-%{release}
@ -1012,10 +1024,14 @@ fi
%{_libdir}/%{name}/modules/libwbclient.so %{_libdir}/%{name}/modules/libwbclient.so
%changelog %changelog
* Mon Sep 07 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.0-5
- Backport upstream patches required by FreeIPA 4.2.1
* Tue Jul 21 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.0-4 * Tue Jul 21 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.0-4
- Fix ipa-migration bug - Fix ipa-migration bug
- Resolves: upstream #2719 - IPA: returned unknown dp error code with disabled - Resolves: upstream #2719 - IPA: returned unknown dp error code with disabled
migration mode migration mode
* Wed Jul 08 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.0-3 * Wed Jul 08 2015 Lukas Slebodnik <lslebodn@redhat.com> - 1.13.0-3
- New upstream release 1.13.0 - New upstream release 1.13.0
- https://fedorahosted.org/sssd/wiki/Releases/Notes-1.13.0 - https://fedorahosted.org/sssd/wiki/Releases/Notes-1.13.0