diff --git a/0001-nfs-idmap-fix-infinite-loop.patch b/0001-nfs-idmap-fix-infinite-loop.patch new file mode 100644 index 0000000..85ffeff --- /dev/null +++ b/0001-nfs-idmap-fix-infinite-loop.patch @@ -0,0 +1,43 @@ +From 207813a4dffb033dde6e3f4c08946864dcf6064a Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 18 Dec 2015 13:16:29 +0100 +Subject: [PATCH 01/49] nfs idmap: fix infinite loop +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Resolves: +https://fedorahosted.org/sssd/ticket/2909 + +Reviewed-by: Lukáš Slebodník +Reviewed-by: Noam Meltzer +(cherry picked from commit 2a256e4e4b64891fe846e933589506daa68aa13e) +--- + src/sss_client/nfs/sss_nfs_client.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/sss_client/nfs/sss_nfs_client.c b/src/sss_client/nfs/sss_nfs_client.c +index 64cb67a8b75ec04c1d6fa03905f5427bbe6c1e82..8fd993005606a52217dc306f1816c3f88a283aa0 100644 +--- a/src/sss_client/nfs/sss_nfs_client.c ++++ b/src/sss_client/nfs/sss_nfs_client.c +@@ -157,7 +157,7 @@ static int get_user_from_mc(char *name, size_t len, uid_t uid) + goto done; + } + buf = p; +- rc = sss_nss_mc_getpwuid(uid, &pwd, buf, BUF_LEN); ++ rc = sss_nss_mc_getpwuid(uid, &pwd, buf, buflen); + } while (rc == ERANGE); + + if (rc == 0) { +@@ -198,7 +198,7 @@ static int get_group_from_mc(char *name, size_t len, id_t gid) + goto done; + } + buf = p; +- rc = sss_nss_mc_getgrgid(gid, &grp, buf, BUF_LEN); ++ rc = sss_nss_mc_getgrgid(gid, &grp, buf, buflen); + } while (rc == ERANGE); + + if (rc == 0) { +-- +2.5.0 + diff --git a/0002-Use-right-domain-for-user-lookups.patch b/0002-Use-right-domain-for-user-lookups.patch new file mode 100644 index 0000000..60172a9 --- /dev/null +++ b/0002-Use-right-domain-for-user-lookups.patch @@ -0,0 +1,32 @@ +From 86c589c8e334e24dfdea910c85da14ebd77972ac Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 14 Dec 2015 17:16:13 +0100 +Subject: [PATCH 02/49] Use right domain for user lookups +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related to https://fedorahosted.org/sssd/ticket/2910 + +Reviewed-by: Pavel Březina +(cherry picked from commit cc1370dab6de99e50ac41126b500382f0aaa73ae) +--- + src/providers/ldap/sdap_async_groups.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c +index c2a618d40cef14e64c899f3982153ab0bcde8358..b154bd079577c49883acbd36a557f6ba56ed017e 100644 +--- a/src/providers/ldap/sdap_async_groups.c ++++ b/src/providers/ldap/sdap_async_groups.c +@@ -2474,7 +2474,7 @@ static errno_t sdap_nested_group_populate_users(TALLOC_CTX *mem_ctx, + ret = ENOMEM; + goto done; + } +- ret = sysdb_search_users(tmp_ctx, domain, filter, ++ ret = sysdb_search_users(tmp_ctx, user_dom, filter, + search_attrs, &count, &msgs); + talloc_zfree(filter); + talloc_zfree(clean_orig_dn); +-- +2.5.0 + diff --git a/0003-sdap_save_grpmem-determine-domain-by-SID-if-possible.patch b/0003-sdap_save_grpmem-determine-domain-by-SID-if-possible.patch new file mode 100644 index 0000000..8ed828b --- /dev/null +++ b/0003-sdap_save_grpmem-determine-domain-by-SID-if-possible.patch @@ -0,0 +1,114 @@ +From 1a3304eb0fdeec439c9e9fb64f7b5069c7ac6620 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 15 Dec 2015 17:20:18 +0100 +Subject: [PATCH 03/49] sdap_save_grpmem: determine domain by SID if possible +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Resolves https://fedorahosted.org/sssd/ticket/2910 + +Reviewed-by: Pavel Březina +(cherry picked from commit 0c1fe8a15cced95e8451ad4c9260c5e4ecca45f1) +--- + src/providers/ldap/sdap_async_groups.c | 48 +++++++++++++++++++++++++--------- + 1 file changed, 35 insertions(+), 13 deletions(-) + +diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c +index b154bd079577c49883acbd36a557f6ba56ed017e..24c9f4d39fecfa9806e4dbe23c2395d201bbf9a0 100644 +--- a/src/providers/ldap/sdap_async_groups.c ++++ b/src/providers/ldap/sdap_async_groups.c +@@ -874,6 +874,7 @@ static int sdap_save_grpmem(TALLOC_CTX *memctx, + const char *group_name; + char **userdns = NULL; + size_t nuserdns = 0; ++ struct sss_domain_info *group_dom = NULL; + int ret; + + if (dom->ignore_group_members) { +@@ -884,7 +885,34 @@ static int sdap_save_grpmem(TALLOC_CTX *memctx, + return EOK; + } + +- ret = sdap_get_group_primary_name(memctx, opts, attrs, dom, &group_name); ++ ret = sysdb_attrs_get_string(attrs, SYSDB_SID_STR, &group_sid); ++ if (ret != EOK) { ++ /* Try harder. */ ++ ret = sdap_attrs_get_sid_str(memctx, opts->idmap_ctx, attrs, ++ opts->group_map[SDAP_AT_GROUP_OBJECTSID].sys_name, ++ discard_const(&group_sid)); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_TRACE_FUNC, "Failed to get group sid\n"); ++ group_sid = NULL; ++ } ++ } ++ ++ if (group_sid != NULL) { ++ group_dom = sss_get_domain_by_sid_ldap_fallback(get_domains_head(dom), ++ group_sid); ++ if (group_dom == NULL) { ++ DEBUG(SSSDBG_TRACE_FUNC, "SID [%s] does not belong to any known " ++ "domain, using [%s].\n", group_sid, ++ dom->name); ++ } ++ } ++ ++ if (group_dom == NULL) { ++ group_dom = dom; ++ } ++ ++ ret = sdap_get_group_primary_name(memctx, opts, attrs, group_dom, ++ &group_name); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to get group name\n"); + goto fail; +@@ -895,7 +923,7 @@ static int sdap_save_grpmem(TALLOC_CTX *memctx, + * are reported with tokenGroups, too + */ + if (opts->schema_type == SDAP_SCHEMA_AD) { +- ret = sdap_dn_by_primary_gid(memctx, attrs, dom, opts, ++ ret = sdap_dn_by_primary_gid(memctx, attrs, group_dom, opts, + &userdns, &nuserdns); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, +@@ -910,15 +938,9 @@ static int sdap_save_grpmem(TALLOC_CTX *memctx, + * https://fedorahosted.org/sssd/ticket/2522 + */ + if (opts->schema_type == SDAP_SCHEMA_IPA_V1) { +- ret = sysdb_attrs_get_string(attrs, SYSDB_SID_STR, &group_sid); +- if (ret != EOK) { +- DEBUG(SSSDBG_TRACE_FUNC, "Failed to get group sid\n"); +- group_sid = NULL; +- } +- + if (group_sid != NULL) { +- ret = retain_extern_members(memctx, dom, group_name, group_sid, +- &userdns, &nuserdns); ++ ret = retain_extern_members(memctx, group_dom, group_name, ++ group_sid, &userdns, &nuserdns); + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_INTERNAL, + "retain_extern_members failed: %d:[%s].\n", +@@ -949,7 +971,7 @@ static int sdap_save_grpmem(TALLOC_CTX *memctx, + goto fail; + } + +- ret = sdap_fill_memberships(opts, group_attrs, ctx, dom, ghosts, ++ ret = sdap_fill_memberships(opts, group_attrs, ctx, group_dom, ghosts, + el->values, el->num_values, + userdns, nuserdns); + if (ret) { +@@ -960,8 +982,8 @@ static int sdap_save_grpmem(TALLOC_CTX *memctx, + } + } + +- ret = sysdb_store_group(dom, group_name, 0, group_attrs, +- dom->group_timeout, now); ++ ret = sysdb_store_group(group_dom, group_name, 0, group_attrs, ++ group_dom->group_timeout, now); + if (ret) { + DEBUG(SSSDBG_MINOR_FAILURE, "sysdb_store_group failed: [%d][%s].\n", + ret, strerror(ret)); +-- +2.5.0 + diff --git a/0004-ipa_s2n_save_objects-use-configured-user-and-group-t.patch b/0004-ipa_s2n_save_objects-use-configured-user-and-group-t.patch new file mode 100644 index 0000000..cf6afee --- /dev/null +++ b/0004-ipa_s2n_save_objects-use-configured-user-and-group-t.patch @@ -0,0 +1,69 @@ +From ac80cf29e6f04550f35172345bec0577340b3c47 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 5 Jan 2016 13:46:55 +0100 +Subject: [PATCH 04/49] ipa_s2n_save_objects(): use configured user and group + timeout +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Resolves https://fedorahosted.org/sssd/ticket/2899 + +Reviewed-by: Lukáš Slebodník +(cherry picked from commit acce97e8d97e81a9e660d46c4e3c00bcb423c035) +--- + src/providers/ipa/ipa_s2n_exop.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index bcd11749fbde4cae2a47b9b2182138ae04f2d6bc..d101a437dfaf2829013f9e3e3705a7161c654d78 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -1743,7 +1743,6 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + { + int ret; + time_t now; +- uint64_t timeout = 10*60*60; /* FIXME: find a better timeout ! */ + struct sss_nss_homedir_ctx homedir_ctx; + char *name = NULL; + char *realm; +@@ -1947,7 +1946,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + * SYSDB_INITGR_EXPIRE will be set.*/ + ret = sysdb_attrs_add_time_t(attrs->sysdb_attrs, + SYSDB_INITGR_EXPIRE, +- time(NULL) + timeout); ++ time(NULL) + dom->user_timeout); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "sysdb_attrs_add_time_t failed.\n"); +@@ -2006,7 +2005,7 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + gid, attrs->a.user.pw_gecos, + attrs->a.user.pw_dir, attrs->a.user.pw_shell, + NULL, attrs->sysdb_attrs, NULL, +- timeout, now); ++ dom->user_timeout, now); + 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 +@@ -2034,7 +2033,7 @@ 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); ++ dom->user_timeout, now); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "sysdb_store_user failed for MPG user [%d]: %s\n", +@@ -2174,7 +2173,8 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + } + + ret = sysdb_store_group(dom, name, attrs->a.group.gr_gid, +- attrs->sysdb_attrs, timeout, now); ++ attrs->sysdb_attrs, dom->group_timeout, ++ now); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sysdb_store_group failed.\n"); + goto done; +-- +2.5.0 + diff --git a/0005-SPEC-Change-package-ownership-of-pubconfpath-krb5.in.patch b/0005-SPEC-Change-package-ownership-of-pubconfpath-krb5.in.patch new file mode 100644 index 0000000..3b6a9ef --- /dev/null +++ b/0005-SPEC-Change-package-ownership-of-pubconfpath-krb5.in.patch @@ -0,0 +1,44 @@ +From 81dfc2be7f2ea92e5fe9749f1b5b64b6c7b12f21 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Wed, 6 Jan 2016 18:09:16 +0100 +Subject: [PATCH 05/49] SPEC: Change package ownership of + %{pubconfpath}/krb5.include.d + +krb5 domain mapping files are stored to the directory +%{pubconfpath}/krb5.include.d. It can be stored by ipa or ad provider. +However this directory was owned by sub-package sssd-ipa. And ad provider +can be installed without this package. Therefore %{pubconfpath}/krb5.include.d +should be owned by common dependency. + +The owner of this directory was also fixed to sssd. +It's already done by make install. It was changed only in spec file. + +Reviewed-by: Jakub Hrozek +(cherry picked from commit b978d3e423c18d5697e6c1398c07e444e6f98e3f) +--- + contrib/sssd.spec.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in +index 710ba92209d4a4d6e45b63bf7bf693fd5ec5f490..9855e11a8bb0ff3f50ceeae98f383c514011cc90 100644 +--- a/contrib/sssd.spec.in ++++ b/contrib/sssd.spec.in +@@ -765,6 +765,7 @@ rm -rf $RPM_BUILD_ROOT + %files krb5-common + %defattr(-,root,root,-) + %doc COPYING ++%attr(755,sssd,sssd) %dir %{pubconfpath}/krb5.include.d + %attr(4750,root,sssd) %{_libexecdir}/%{servicename}/ldap_child + %attr(4750,root,sssd) %{_libexecdir}/%{servicename}/krb5_child + +@@ -782,7 +783,6 @@ rm -rf $RPM_BUILD_ROOT + %files ipa -f sssd_ipa.lang + %defattr(-,root,root,-) + %doc COPYING +-%attr(755,root,root) %dir %{pubconfpath}/krb5.include.d + %attr(700,sssd,sssd) %dir %{keytabdir} + %{_libdir}/%{name}/libsss_ipa.so + %attr(4750,root,sssd) %{_libexecdir}/%{servicename}/selinux_child +-- +2.5.0 + diff --git a/0006-AD-SRV-prefer-site-local-DCs-in-LDAP-ping.patch b/0006-AD-SRV-prefer-site-local-DCs-in-LDAP-ping.patch new file mode 100644 index 0000000..097ff02 --- /dev/null +++ b/0006-AD-SRV-prefer-site-local-DCs-in-LDAP-ping.patch @@ -0,0 +1,89 @@ +From cce018a29027fe531de9191cdc905ab201deb133 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 5 Jan 2016 13:20:14 +0100 +Subject: [PATCH 06/49] AD SRV: prefer site-local DCs in LDAP ping + +Resolves: +https://fedorahosted.org/sssd/ticket/2765 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit a1c6869c67fcf4971ac843315b97bf46893ca92d) +--- + src/providers/ad/ad_srv.c | 40 ++++++++++++++++++++++++++++++---------- + 1 file changed, 30 insertions(+), 10 deletions(-) + +diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c +index 123aac6a4a73a60b5d597d9b34eb5fbd7865f8d3..e719272520cee11739431a686a6cf09aaf76947e 100644 +--- a/src/providers/ad/ad_srv.c ++++ b/src/providers/ad/ad_srv.c +@@ -118,7 +118,8 @@ static void ad_get_dc_servers_done(struct tevent_req *subreq); + static struct tevent_req *ad_get_dc_servers_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct resolv_ctx *resolv_ctx, +- const char *domain) ++ const char *discovery_domain, ++ const char *site) + { + struct ad_get_dc_servers_state *state = NULL; + struct tevent_req *req = NULL; +@@ -133,21 +134,39 @@ static struct tevent_req *ad_get_dc_servers_send(TALLOC_CTX *mem_ctx, + return NULL; + } + +- domains = talloc_zero_array(state, const char *, 2); ++ domains = talloc_zero_array(state, const char *, 3); + if (domains == NULL) { + ret = ENOMEM; + goto immediately; + } + +- domains[0] = talloc_strdup(domains, domain); +- if (domains[0] == NULL) { +- ret = ENOMEM; +- goto immediately; ++ if (site == NULL) { ++ DEBUG(SSSDBG_TRACE_FUNC, "Looking up domain controllers in domain " ++ "%s\n", discovery_domain); ++ ++ domains[0] = talloc_strdup(domains, discovery_domain); ++ if (domains[0] == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ } else { ++ DEBUG(SSSDBG_TRACE_FUNC, "Looking up domain controllers in domain " ++ "%s and site %s\n", discovery_domain, site); ++ ++ domains[0] = talloc_asprintf(state, AD_SITE_DOMAIN_FMT, ++ site, discovery_domain); ++ if (domains[0] == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ domains[1] = talloc_strdup(domains, discovery_domain); ++ if (domains[1] == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } + } + +- DEBUG(SSSDBG_TRACE_FUNC, "Looking up domain controllers in domain %s\n", +- domain); +- + subreq = fo_discover_srv_send(state, ev, resolv_ctx, + "ldap", FO_PROTO_TCP, domains); + if (subreq == NULL) { +@@ -692,7 +711,8 @@ struct tevent_req *ad_srv_plugin_send(TALLOC_CTX *mem_ctx, + DEBUG(SSSDBG_TRACE_FUNC, "About to find domain controllers\n"); + + subreq = ad_get_dc_servers_send(state, ev, ctx->be_res->resolv, +- state->discovery_domain); ++ state->discovery_domain, ++ state->ctx->ad_site_override); + if (subreq == NULL) { + ret = ENOMEM; + goto immediately; +-- +2.5.0 + diff --git a/0007-ldap-remove-originalMeberOf-if-there-is-no-memberOf.patch b/0007-ldap-remove-originalMeberOf-if-there-is-no-memberOf.patch new file mode 100644 index 0000000..35db1ec --- /dev/null +++ b/0007-ldap-remove-originalMeberOf-if-there-is-no-memberOf.patch @@ -0,0 +1,86 @@ +From a83b56cc7cf9b74299475727ff41f61f42002f4a Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 21 Dec 2015 15:51:09 +0100 +Subject: [PATCH 07/49] ldap: remove originalMeberOf if there is no memberOf + +Since originalMemerberOf is not mapped directly to an original attribute +and is handled specially it is not automatically removed if there is no +memberOf in the original object anymore. This patch put +originalMemerberOf on the list of attribute which should be removed in +that case. + +Resolves https://fedorahosted.org/sssd/ticket/2917 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 9a2f018c0f68a3ada4cea4128a861a7f85893f22) +--- + src/providers/ipa/ipa_s2n_exop.c | 12 +++++++++++- + src/providers/ldap/ldap_common.c | 8 +++++++- + 2 files changed, 18 insertions(+), 2 deletions(-) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index d101a437dfaf2829013f9e3e3705a7161c654d78..1d233cd52c18b4b6ed753bd92d186ac02ed2cb80 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -1764,6 +1764,8 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + struct sysdb_attrs *gid_override_attrs = NULL; + char ** exop_grouplist; + struct ldb_message *msg; ++ struct ldb_message_element *el = NULL; ++ const char *missing[] = {NULL, NULL}; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { +@@ -1993,6 +1995,12 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + } + } + ++ ret = sysdb_attrs_get_el_ext(attrs->sysdb_attrs, ++ SYSDB_ORIG_MEMBEROF, false, &el); ++ if (ret == ENOENT) { ++ missing[0] = SYSDB_ORIG_MEMBEROF; ++ } ++ + ret = sysdb_transaction_start(dom->sysdb); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); +@@ -2004,7 +2012,9 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + 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, ++ NULL, attrs->sysdb_attrs, ++ missing[0] == NULL ? NULL ++ : discard_const(missing), + dom->user_timeout, now); + if (ret == EEXIST && dom->mpg == true) { + /* This handles the case where getgrgid() was called for +diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c +index aa4c6cb851a5735e051ef2c024ca0171a4f61148..df4d52bc7426033852899c49bc0fa7a0f1aa9ed6 100644 +--- a/src/providers/ldap/ldap_common.c ++++ b/src/providers/ldap/ldap_common.c +@@ -780,7 +780,7 @@ errno_t list_missing_attrs(TALLOC_CTX *mem_ctx, + /* Allocate the maximum possible values for missing_attrs, to + * be on the safe side + */ +- missing = talloc_array(tmp_ctx, char *, attr_count); ++ missing = talloc_array(tmp_ctx, char *, attr_count + 2); + if (!missing) { + ret = ENOMEM; + goto done; +@@ -831,6 +831,12 @@ errno_t list_missing_attrs(TALLOC_CTX *mem_ctx, + /* Attribute could not be found. Add to the missing list */ + missing[k] = talloc_steal(missing, sysdb_name); + k++; ++ ++ /* Remove originalMemberOf as well if MemberOf is missing */ ++ if (strcmp(sysdb_name, SYSDB_MEMBEROF) == 0) { ++ missing[k] = talloc_strdup(missing, SYSDB_ORIG_MEMBEROF); ++ k++; ++ } + } + } + +-- +2.5.0 + diff --git a/0008-KRB5-Adding-DNS-SRV-lookup-for-krb5-provider.patch b/0008-KRB5-Adding-DNS-SRV-lookup-for-krb5-provider.patch new file mode 100644 index 0000000..9cdff5e --- /dev/null +++ b/0008-KRB5-Adding-DNS-SRV-lookup-for-krb5-provider.patch @@ -0,0 +1,37 @@ +From d0bd229965c51af3dfe79d21a5fcd25cc1903b0c Mon Sep 17 00:00:00 2001 +From: Petr Cech +Date: Mon, 11 Jan 2016 06:18:33 -0500 +Subject: [PATCH 08/49] KRB5: Adding DNS SRV lookup for krb5 provider + +This patch add DNS SRV lookup for krb5 provider. + +Resolves: +https://fedorahosted.org/sssd/ticket/2888 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 684191e61d891b1c34f3742a40d5a2ed6a1192dd) +--- + src/providers/krb5/krb5_init.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/providers/krb5/krb5_init.c b/src/providers/krb5/krb5_init.c +index f1c63107642fba8441ff563bd9ecd7eff233d65c..4f36d905b1d5e89466998fba946f9f6f6915f51d 100644 +--- a/src/providers/krb5/krb5_init.c ++++ b/src/providers/krb5/krb5_init.c +@@ -169,6 +169,13 @@ int sssm_krb5_auth_init(struct be_ctx *bectx, + } + talloc_set_destructor((TALLOC_CTX *) ctx, krb5_ctx_re_destructor); + ++ ret = be_fo_set_dns_srv_lookup_plugin(bectx, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set SRV lookup plugin " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ goto fail; ++ } ++ + *ops = &krb5_auth_ops; + *pvt_auth_data = ctx; + return EOK; +-- +2.5.0 + diff --git a/0009-SDAP-do-not-fail-if-refs-are-found-but-not-processed.patch b/0009-SDAP-do-not-fail-if-refs-are-found-but-not-processed.patch new file mode 100644 index 0000000..ae08f7f --- /dev/null +++ b/0009-SDAP-do-not-fail-if-refs-are-found-but-not-processed.patch @@ -0,0 +1,49 @@ +From b516864d5216fa6cf7238c3ea777f060cde383ff Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 13 Jan 2016 13:15:09 +0100 +Subject: [PATCH 09/49] SDAP: do not fail if refs are found but not processed + +It is possible to end up with not-processed referrals when +using AD provider and ldap_referrals=true. + +Resolves: +https://fedorahosted.org/sssd/ticket/2906 + +Reviewed-by: Stephen Gallagher +(cherry picked from commit 468495d91d536603a1c485424275b6dcf2bb83de) +--- + src/providers/ldap/sdap_async.c | 11 +---------- + 1 file changed, 1 insertion(+), 10 deletions(-) + +diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c +index 668bd7b465bbfefad13ab0b7061cd16a05dfbef1..5260aafebf7570291876b2433dbcf44ffb5b0011 100644 +--- a/src/providers/ldap/sdap_async.c ++++ b/src/providers/ldap/sdap_async.c +@@ -1653,16 +1653,6 @@ static void generic_ext_search_handler(struct tevent_req *subreq, + } + + if (ref_count > 0) { +- if (dp_opt_get_bool(opts->basic, SDAP_REFERRALS)) { +- /* We got back referrals here, but they should have +- * been processed internally by openldap libs. +- * This should never happen. +- */ +- talloc_free(refs); +- tevent_req_error(req, EINVAL); +- return; +- } +- + /* We will ignore referrals in the generic handler */ + DEBUG(SSSDBG_TRACE_ALL, + "Request included referrals which were ignored.\n"); +@@ -1674,6 +1664,7 @@ static void generic_ext_search_handler(struct tevent_req *subreq, + } + } + ++ talloc_free(refs); + tevent_req_done(req); + } + +-- +2.5.0 + diff --git a/0010-sudo-remove-unused-param-name-in-sdap_sudo_get_usn.patch b/0010-sudo-remove-unused-param-name-in-sdap_sudo_get_usn.patch new file mode 100644 index 0000000..943db88 --- /dev/null +++ b/0010-sudo-remove-unused-param-name-in-sdap_sudo_get_usn.patch @@ -0,0 +1,35 @@ +From 70828dd44d1c35a9084d39f8420e1b984fb2fcaa Mon Sep 17 00:00:00 2001 +From: Pavel Reichl +Date: Mon, 2 Nov 2015 14:59:49 +0100 +Subject: [PATCH 10/49] sudo: remove unused param name in sdap_sudo_get_usn() + +Reviewed-by: Petr Cech +(cherry picked from commit e307c269fe1dc94a1771b459c5925e449ba7668b) +--- + src/providers/ldap/sdap_sudo_cache.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/providers/ldap/sdap_sudo_cache.c b/src/providers/ldap/sdap_sudo_cache.c +index 27203c227064bdcd918cda67bb93a5d62b42e4bd..56e84ce8f26338ea5856eb5c76627641eee93df1 100644 +--- a/src/providers/ldap/sdap_sudo_cache.c ++++ b/src/providers/ldap/sdap_sudo_cache.c +@@ -28,7 +28,6 @@ + static errno_t sdap_sudo_get_usn(TALLOC_CTX *mem_ctx, + struct sysdb_attrs *attrs, + struct sdap_attr_map *map, +- const char *name, + char **_usn) + { + const char *usn; +@@ -86,7 +85,7 @@ sdap_save_native_sudorule(TALLOC_CTX *mem_ctx, + return ret; + } + +- ret = sdap_sudo_get_usn(mem_ctx, attrs, map, rule_name, _usn); ++ ret = sdap_sudo_get_usn(mem_ctx, attrs, map, _usn); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, "Could not read USN from %s\n", rule_name); + *_usn = NULL; +-- +2.5.0 + diff --git a/0011-sudo-remove-unused-param.-in-ldap_get_sudo_options.patch b/0011-sudo-remove-unused-param.-in-ldap_get_sudo_options.patch new file mode 100644 index 0000000..8bf5315 --- /dev/null +++ b/0011-sudo-remove-unused-param.-in-ldap_get_sudo_options.patch @@ -0,0 +1,62 @@ +From d58ae3b51f2f87e7ff1024ae25cb996ce91cae55 Mon Sep 17 00:00:00 2001 +From: Pavel Reichl +Date: Sun, 11 Oct 2015 22:33:08 +0200 +Subject: [PATCH 11/49] sudo: remove unused param. in ldap_get_sudo_options +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Remove unused talloc memory context. + +Reviewed-by: Lukáš Slebodník +(cherry picked from commit 8835ecb2ff5126629993a6b6d3fb0bb7baa3b765) +--- + src/providers/ldap/ldap_common.h | 3 +-- + src/providers/ldap/ldap_options.c | 3 +-- + src/providers/ldap/sdap_sudo.c | 2 +- + 3 files changed, 3 insertions(+), 5 deletions(-) + +diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h +index f552520a0503908f82b845f8e813cf67306ec954..ae45fb71b5cf7edab618a829057357bea2d6844b 100644 +--- a/src/providers/ldap/ldap_common.h ++++ b/src/providers/ldap/ldap_common.h +@@ -167,8 +167,7 @@ int ldap_get_options(TALLOC_CTX *memctx, + const char *conf_path, + struct sdap_options **_opts); + +-int ldap_get_sudo_options(TALLOC_CTX *memctx, +- struct confdb_ctx *cdb, ++int ldap_get_sudo_options(struct confdb_ctx *cdb, + const char *conf_path, + struct sdap_options *opts, + bool *use_host_filter, +diff --git a/src/providers/ldap/ldap_options.c b/src/providers/ldap/ldap_options.c +index 7ad6071508d0abbb33984c697b833cf12f9e4df9..cf49e41abbea78c1b1fd79e2e0713fba279971be 100644 +--- a/src/providers/ldap/ldap_options.c ++++ b/src/providers/ldap/ldap_options.c +@@ -343,8 +343,7 @@ done: + return ret; + } + +-int ldap_get_sudo_options(TALLOC_CTX *memctx, +- struct confdb_ctx *cdb, ++int ldap_get_sudo_options(struct confdb_ctx *cdb, + const char *conf_path, + struct sdap_options *opts, + bool *use_host_filter, +diff --git a/src/providers/ldap/sdap_sudo.c b/src/providers/ldap/sdap_sudo.c +index 24642344491dfb93f039bde6a0bfe8fd3e24a80d..550784842c6e6162d153785940c1e37a51b5dc1f 100644 +--- a/src/providers/ldap/sdap_sudo.c ++++ b/src/providers/ldap/sdap_sudo.c +@@ -76,7 +76,7 @@ int sdap_sudo_init(struct be_ctx *be_ctx, + * so we don't have current usn values available */ + sudo_ctx->full_refresh_done = false; + +- ret = ldap_get_sudo_options(id_ctx, be_ctx->cdb, ++ ret = ldap_get_sudo_options(be_ctx->cdb, + be_ctx->conf_path, id_ctx->opts, + &sudo_ctx->use_host_filter, + &sudo_ctx->include_regexp, +-- +2.5.0 + diff --git a/0012-SDAP-Add-request-that-iterates-over-all-search-bases.patch b/0012-SDAP-Add-request-that-iterates-over-all-search-bases.patch new file mode 100644 index 0000000..828f020 --- /dev/null +++ b/0012-SDAP-Add-request-that-iterates-over-all-search-bases.patch @@ -0,0 +1,383 @@ +From a9845c875e430e00cfb49a39b09c8595ff8e3416 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 1 Dec 2015 13:08:36 +0100 +Subject: [PATCH 12/49] SDAP: Add request that iterates over all search bases + +We often need to iterate over many search bases but we always use +mostly copy&paste iterator. This will reduce code duplication and +simplify code flow. + +Reviewed-by: Sumit Bose +(cherry picked from commit d0599eaa9369fd867953e3c58b8d7bb445525ff5) +--- + Makefile.am | 2 + + src/providers/ldap/ldap_common.h | 9 +- + src/providers/ldap/sdap.c | 2 +- + src/providers/ldap/sdap_ops.c | 232 +++++++++++++++++++++++++++++++++++++++ + src/providers/ldap/sdap_ops.h | 44 ++++++++ + src/providers/ldap/sdap_utils.c | 6 +- + 6 files changed, 288 insertions(+), 7 deletions(-) + create mode 100644 src/providers/ldap/sdap_ops.c + create mode 100644 src/providers/ldap/sdap_ops.h + +diff --git a/Makefile.am b/Makefile.am +index 1937dcbebc4f29c4ffe72eeeb67cdb5344a8e7d1..095b1cfd62f49d266df278e1736d48ed5ef4fa7a 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -628,6 +628,7 @@ dist_noinst_HEADERS = \ + src/providers/ldap/sdap_users.h \ + src/providers/ldap/sdap_dyndns.h \ + src/providers/ldap/sdap_async_enum.h \ ++ src/providers/ldap/sdap_ops.h \ + src/providers/ipa/ipa_common.h \ + src/providers/ipa/ipa_config.h \ + src/providers/ipa/ipa_access.h \ +@@ -2836,6 +2837,7 @@ libsss_ldap_common_la_SOURCES = \ + src/providers/ldap/sdap_refresh.c \ + src/providers/ldap/sdap_utils.c \ + src/providers/ldap/sdap_domain.c \ ++ src/providers/ldap/sdap_ops.c \ + src/providers/ldap/sdap.c \ + src/util/user_info_msg.c \ + src/util/sss_ldap.c \ +diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h +index ae45fb71b5cf7edab618a829057357bea2d6844b..66434dd0e8bc82649fecd67b1394cb6b102a7d49 100644 +--- a/src/providers/ldap/ldap_common.h ++++ b/src/providers/ldap/ldap_common.h +@@ -264,9 +264,12 @@ errno_t list_missing_attrs(TALLOC_CTX *mem_ctx, + + bool sdap_is_secure_uri(const char *uri); + +-char *sdap_get_id_specific_filter(TALLOC_CTX *mem_ctx, +- const char *base_filter, +- const char *extra_filter); ++char *sdap_combine_filters(TALLOC_CTX *mem_ctx, ++ const char *base_filter, ++ const char *extra_filter); ++ ++#define sdap_get_id_specific_filter(mem_ctx, base_filter, extra_filter) \ ++ sdap_combine_filters((mem_ctx), (base_filter), (extra_filter)) + + char *sdap_get_access_filter(TALLOC_CTX *mem_ctx, + const char *base_filter); +diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c +index fcdc4028efe97bba13f265a8cfd7c75fa6b7a07c..f9b9ff7e6913c406547f36d341300b936e121693 100644 +--- a/src/providers/ldap/sdap.c ++++ b/src/providers/ldap/sdap.c +@@ -312,7 +312,7 @@ int sdap_get_map(TALLOC_CTX *memctx, + char *name; + int i, ret; + +- map = talloc_array(memctx, struct sdap_attr_map, num_entries); ++ map = talloc_zero_array(memctx, struct sdap_attr_map, num_entries + 1); + if (!map) { + return ENOMEM; + } +diff --git a/src/providers/ldap/sdap_ops.c b/src/providers/ldap/sdap_ops.c +new file mode 100644 +index 0000000000000000000000000000000000000000..b2f2c35d0bf49682f522993390cfec2f451bf366 +--- /dev/null ++++ b/src/providers/ldap/sdap_ops.c +@@ -0,0 +1,232 @@ ++/* ++ Authors: ++ Pavel Březina ++ ++ Copyright (C) 2015 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#include ++#include ++ ++#include "util/util.h" ++#include "providers/ldap/sdap.h" ++#include "providers/ldap/sdap_async.h" ++#include "providers/ldap/ldap_common.h" ++ ++struct sdap_search_bases_state { ++ struct tevent_context *ev; ++ struct sdap_options *opts; ++ struct sdap_handle *sh; ++ const char *filter; ++ const char **attrs; ++ struct sdap_attr_map *map; ++ int map_num_attrs; ++ int timeout; ++ bool allow_paging; ++ ++ size_t base_iter; ++ struct sdap_search_base *cur_base; ++ struct sdap_search_base **bases; ++ ++ size_t reply_count; ++ struct sysdb_attrs **reply; ++}; ++ ++static errno_t sdap_search_bases_next_base(struct tevent_req *req); ++static void sdap_search_bases_done(struct tevent_req *subreq); ++ ++struct tevent_req *sdap_search_bases_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct sdap_options *opts, ++ struct sdap_handle *sh, ++ struct sdap_search_base **bases, ++ struct sdap_attr_map *map, ++ bool allow_paging, ++ int timeout, ++ const char *filter, ++ const char **attrs) ++{ ++ struct tevent_req *req; ++ struct sdap_search_bases_state *state; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct sdap_search_bases_state); ++ if (req == NULL) { ++ return NULL; ++ } ++ ++ if (bases == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "No search base specified!\n"); ++ ret = ERR_INTERNAL; ++ goto immediately; ++ } ++ ++ if (map == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "No attribute map specified!\n"); ++ ret = ERR_INTERNAL; ++ goto immediately; ++ } ++ ++ state->ev = ev; ++ state->opts = opts; ++ state->sh = sh; ++ state->bases = bases; ++ state->map = map; ++ state->filter = filter; ++ state->attrs = attrs; ++ state->allow_paging = allow_paging; ++ ++ state->timeout = timeout == 0 ++ ? dp_opt_get_int(opts->basic, SDAP_SEARCH_TIMEOUT) ++ : timeout; ++ ++ for (state->map_num_attrs = 0; ++ state->map[state->map_num_attrs].opt_name != NULL; ++ state->map_num_attrs++) { ++ /* no op */; ++ } ++ ++ if (state->attrs == NULL) { ++ ret = build_attrs_from_map(state, state->map, state->map_num_attrs, ++ NULL, &state->attrs, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to build attrs from map " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ goto immediately; ++ } ++ } ++ ++ state->base_iter = 0; ++ ret = sdap_search_bases_next_base(req); ++ if (ret == EAGAIN) { ++ /* asynchronous processing */ ++ return req; ++ } ++ ++immediately: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ ++ return req; ++} ++ ++static errno_t sdap_search_bases_next_base(struct tevent_req *req) ++{ ++ struct sdap_search_bases_state *state; ++ struct tevent_req *subreq; ++ char *filter; ++ ++ state = tevent_req_data(req, struct sdap_search_bases_state); ++ state->cur_base = state->bases[state->base_iter]; ++ if (state->cur_base == NULL) { ++ return EOK; ++ } ++ ++ /* Combine lookup and search base filters. */ ++ filter = sdap_combine_filters(state, state->filter, ++ state->cur_base->filter); ++ if (filter == NULL) { ++ return ENOMEM; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Issuing LDAP lookup with base [%s]\n", ++ state->cur_base->basedn); ++ ++ subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh, ++ state->cur_base->basedn, ++ state->cur_base->scope, filter, ++ state->attrs, state->map, ++ state->map_num_attrs, state->timeout, ++ state->allow_paging); ++ if (subreq == NULL) { ++ return ENOMEM; ++ } ++ ++ tevent_req_set_callback(subreq, sdap_search_bases_done, req); ++ ++ state->base_iter++; ++ return EAGAIN; ++} ++ ++static void sdap_search_bases_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req; ++ struct sdap_search_bases_state *state; ++ struct sysdb_attrs **attrs; ++ size_t count; ++ size_t i; ++ int ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct sdap_search_bases_state); ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Receiving data from base [%s]\n", ++ state->cur_base->basedn); ++ ++ ret = sdap_get_generic_recv(subreq, state, &count, &attrs); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ /* Add rules to result. */ ++ if (count > 0) { ++ state->reply = talloc_realloc(state, state->reply, struct sysdb_attrs *, ++ state->reply_count + count); ++ if (state->reply == NULL) { ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ ++ for (i = 0; i < count; i++) { ++ state->reply[state->reply_count + i] = talloc_steal(state->reply, ++ attrs[i]); ++ } ++ ++ state->reply_count += count; ++ } ++ ++ /* Try next search base. */ ++ ret = sdap_search_bases_next_base(req); ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else if (ret != EAGAIN) { ++ tevent_req_error(req, ret); ++ } ++ ++ return; ++} ++ ++int sdap_search_bases_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ size_t *reply_count, ++ struct sysdb_attrs ***reply) ++{ ++ struct sdap_search_bases_state *state = ++ tevent_req_data(req, struct sdap_search_bases_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ *reply_count = state->reply_count; ++ *reply = talloc_steal(mem_ctx, state->reply); ++ ++ return EOK; ++} +diff --git a/src/providers/ldap/sdap_ops.h b/src/providers/ldap/sdap_ops.h +new file mode 100644 +index 0000000000000000000000000000000000000000..bc53ff8701c26ca00d5c07b441b170d615bda2ee +--- /dev/null ++++ b/src/providers/ldap/sdap_ops.h +@@ -0,0 +1,44 @@ ++/* ++ Authors: ++ Pavel Březina ++ ++ Copyright (C) 2015 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#ifndef _SDAP_OPS_H_ ++#define _SDAP_OPS_H_ ++ ++#include ++#include ++#include "providers/ldap/ldap_common.h" ++ ++struct tevent_req *sdap_search_bases_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct sdap_options *opts, ++ struct sdap_handle *sh, ++ struct sdap_search_base **bases, ++ struct sdap_attr_map *map, ++ bool allow_paging, ++ int timeout, ++ const char *filter, ++ const char **attrs); ++ ++int sdap_search_bases_recv(struct tevent_req *req, ++ TALLOC_CTX *mem_ctx, ++ size_t *reply_count, ++ struct sysdb_attrs ***reply); ++ ++#endif /* _SDAP_OPS_H_ */ +diff --git a/src/providers/ldap/sdap_utils.c b/src/providers/ldap/sdap_utils.c +index 9da46ea70bf80e7f4d12fdfc7d1c97e99de8d000..7a96f81a1db2644b698e5a5baaed19366a305c6b 100644 +--- a/src/providers/ldap/sdap_utils.c ++++ b/src/providers/ldap/sdap_utils.c +@@ -149,9 +149,9 @@ errno_t deref_string_to_val(const char *str, int *val) + return EOK; + } + +-char *sdap_get_id_specific_filter(TALLOC_CTX *mem_ctx, +- const char *base_filter, +- const char *extra_filter) ++char *sdap_combine_filters(TALLOC_CTX *mem_ctx, ++ const char *base_filter, ++ const char *extra_filter) + { + char *filter = NULL; + +-- +2.5.0 + diff --git a/0013-SDAP-rename-sdap_get_id_specific_filter.patch b/0013-SDAP-rename-sdap_get_id_specific_filter.patch new file mode 100644 index 0000000..8877b48 --- /dev/null +++ b/0013-SDAP-rename-sdap_get_id_specific_filter.patch @@ -0,0 +1,369 @@ +From ca05bdf79d3ef60b0747db10b0ba0be48163841d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 1 Dec 2015 15:27:41 +0100 +Subject: [PATCH 13/49] SDAP: rename sdap_get_id_specific_filter + +More generic name is used now since it is not used only for id +filters. Probably all references will be deleted when the code +uses sdap_search_in_bases istead of custom search base iterators. + +Reviewed-by: Sumit Bose +(cherry picked from commit 92ec40e6aa25f75903ffdb166a8ec56b67bfd77d) +--- + src/providers/ipa/ipa_hbac_rules.c | 5 ++--- + src/providers/ipa/ipa_hbac_services.c | 10 ++++------ + src/providers/ipa/ipa_hosts.c | 8 ++++---- + src/providers/ipa/ipa_netgroups.c | 2 +- + src/providers/ipa/ipa_selinux_maps.c | 4 ++-- + src/providers/ipa/ipa_subdomains.c | 4 ++-- + src/providers/ldap/ldap_common.h | 3 --- + src/providers/ldap/sdap_async_autofs.c | 6 ++---- + src/providers/ldap/sdap_async_groups.c | 3 +-- + src/providers/ldap/sdap_async_groups_ad.c | 3 +-- + src/providers/ldap/sdap_async_initgroups.c | 22 ++++++++-------------- + src/providers/ldap/sdap_async_initgroups_ad.c | 3 +-- + src/providers/ldap/sdap_async_nested_groups.c | 6 ++---- + src/providers/ldap/sdap_async_netgroups.c | 3 +-- + src/providers/ldap/sdap_async_services.c | 3 +-- + src/providers/ldap/sdap_async_sudo.c | 4 ++-- + src/providers/ldap/sdap_async_users.c | 3 +-- + 17 files changed, 35 insertions(+), 57 deletions(-) + +diff --git a/src/providers/ipa/ipa_hbac_rules.c b/src/providers/ipa/ipa_hbac_rules.c +index ffef6dc4ce4229f2063d1b00308892bd3765f398..1a812a383d49386ad9e02b2a84f759f399b20c75 100644 +--- a/src/providers/ipa/ipa_hbac_rules.c ++++ b/src/providers/ipa/ipa_hbac_rules.c +@@ -206,9 +206,8 @@ ipa_hbac_rule_info_next(struct tevent_req *req, + } + + talloc_zfree(state->cur_filter); +- state->cur_filter = sdap_get_id_specific_filter(state, +- state->rules_filter, +- base->filter); ++ state->cur_filter = sdap_combine_filters(state, state->rules_filter, ++ base->filter); + if (state->cur_filter == NULL) { + return ENOMEM; + } +diff --git a/src/providers/ipa/ipa_hbac_services.c b/src/providers/ipa/ipa_hbac_services.c +index 35ee003effb5ac933843cbc3bd662f81a58246ad..cf8ce84bf54f2d22bd5cd19d88e647889742a41e 100644 +--- a/src/providers/ipa/ipa_hbac_services.c ++++ b/src/providers/ipa/ipa_hbac_services.c +@@ -137,9 +137,8 @@ static errno_t ipa_hbac_service_info_next(struct tevent_req *req, + } + + talloc_zfree(state->cur_filter); +- state->cur_filter = sdap_get_id_specific_filter(state, +- state->service_filter, +- base->filter); ++ state->cur_filter = sdap_combine_filters(state, state->service_filter, ++ base->filter); + if (state->cur_filter == NULL) { + return ENOMEM; + } +@@ -251,9 +250,8 @@ ipa_hbac_servicegroup_info_next(struct tevent_req *req, + } + + talloc_zfree(state->cur_filter); +- state->cur_filter = sdap_get_id_specific_filter(state, +- state->service_filter, +- base->filter); ++ state->cur_filter = sdap_combine_filters(state, state->service_filter, ++ base->filter); + if (state->cur_filter == NULL) { + return ENOMEM; + } +diff --git a/src/providers/ipa/ipa_hosts.c b/src/providers/ipa/ipa_hosts.c +index 64f80f082cdda57949e1b01efe46d6f76faa1734..5966e3c74778433fbfc04c053547dc5e358f710a 100644 +--- a/src/providers/ipa/ipa_hosts.c ++++ b/src/providers/ipa/ipa_hosts.c +@@ -154,8 +154,8 @@ static errno_t ipa_host_info_next(struct tevent_req *req, + } + + talloc_zfree(state->cur_filter); +- state->cur_filter = sdap_get_id_specific_filter(state, state->host_filter, +- base->filter); ++ state->cur_filter = sdap_combine_filters(state, state->host_filter, ++ base->filter); + if (state->cur_filter == NULL) { + return ENOMEM; + } +@@ -292,8 +292,8 @@ static errno_t ipa_hostgroup_info_next(struct tevent_req *req, + } + + talloc_zfree(state->cur_filter); +- state->cur_filter = sdap_get_id_specific_filter(state, state->host_filter, +- base->filter); ++ state->cur_filter = sdap_combine_filters(state, state->host_filter, ++ base->filter); + if (state->cur_filter == NULL) { + return ENOMEM; + } +diff --git a/src/providers/ipa/ipa_netgroups.c b/src/providers/ipa/ipa_netgroups.c +index 6f004e034a77de1049c2e127e82ce49d3e7400f3..a19e5e03d7025cbd9eed12261f586a4eae22b4a3 100644 +--- a/src/providers/ipa/ipa_netgroups.c ++++ b/src/providers/ipa/ipa_netgroups.c +@@ -254,7 +254,7 @@ static errno_t ipa_netgr_next_base(struct tevent_req *req) + netgr_bases = state->ipa_opts->id->sdom->netgroup_search_bases; + + talloc_zfree(state->filter); +- state->filter = sdap_get_id_specific_filter( ++ state->filter = sdap_combine_filters( + state, + state->base_filter, + netgr_bases[state->netgr_base_iter]->filter); +diff --git a/src/providers/ipa/ipa_selinux_maps.c b/src/providers/ipa/ipa_selinux_maps.c +index 315cc7de40d8262619c86bb897bb16da45ea66c2..9abac4d00a3d1ebf599a0c47c2e8c7f374e20a58 100644 +--- a/src/providers/ipa/ipa_selinux_maps.c ++++ b/src/providers/ipa/ipa_selinux_maps.c +@@ -121,8 +121,8 @@ ipa_selinux_get_maps_next(struct tevent_req *req, + } + + talloc_zfree(state->cur_filter); +- state->cur_filter = sdap_get_id_specific_filter(state, state->maps_filter, +- base->filter); ++ state->cur_filter = sdap_combine_filters(state, state->maps_filter, ++ base->filter); + if (state->cur_filter == NULL) { + return ENOMEM; + } +diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c +index 70a2933757688d0cc758a56d20649bf5e7f43436..cd78506ffc59c392da4e834c764c9ca82dbc89b0 100644 +--- a/src/providers/ipa/ipa_subdomains.c ++++ b/src/providers/ipa/ipa_subdomains.c +@@ -726,8 +726,8 @@ ipa_subdomains_handler_get(struct ipa_subdomains_req_ctx *ctx, + } + + talloc_free(ctx->current_filter); +- ctx->current_filter = sdap_get_id_specific_filter(ctx, params->filter, +- base->filter); ++ ctx->current_filter = sdap_combine_filters(ctx, params->filter, ++ base->filter); + if (ctx->current_filter == NULL) { + return ENOMEM; + } +diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h +index 66434dd0e8bc82649fecd67b1394cb6b102a7d49..e5fee51e742a69d8876f2829f75b2af5f020ef6f 100644 +--- a/src/providers/ldap/ldap_common.h ++++ b/src/providers/ldap/ldap_common.h +@@ -268,9 +268,6 @@ char *sdap_combine_filters(TALLOC_CTX *mem_ctx, + const char *base_filter, + const char *extra_filter); + +-#define sdap_get_id_specific_filter(mem_ctx, base_filter, extra_filter) \ +- sdap_combine_filters((mem_ctx), (base_filter), (extra_filter)) +- + char *sdap_get_access_filter(TALLOC_CTX *mem_ctx, + const char *base_filter); + +diff --git a/src/providers/ldap/sdap_async_autofs.c b/src/providers/ldap/sdap_async_autofs.c +index 1db8d2067a691ac93844d97dd2d53422b1ca3ad2..85cc8928139196ba25caef2e3fc46b004c85f073 100644 +--- a/src/providers/ldap/sdap_async_autofs.c ++++ b/src/providers/ldap/sdap_async_autofs.c +@@ -313,8 +313,7 @@ automntmaps_process_members_next_base(struct tevent_req *req) + tevent_req_data(req, struct automntmaps_process_members_state); + + talloc_zfree(state->filter); +- state->filter = sdap_get_id_specific_filter(state, +- state->base_filter, ++ state->filter = sdap_combine_filters(state, state->base_filter, + state->search_bases[state->base_iter]->filter); + if (!state->filter) { + return ENOMEM; +@@ -493,8 +492,7 @@ sdap_get_automntmap_next_base(struct tevent_req *req) + state = tevent_req_data(req, struct sdap_get_automntmap_state); + + talloc_zfree(state->filter); +- state->filter = sdap_get_id_specific_filter(state, +- state->base_filter, ++ state->filter = sdap_combine_filters(state, state->base_filter, + state->search_bases[state->base_iter]->filter); + if (!state->filter) { + return ENOMEM; +diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c +index 24c9f4d39fecfa9806e4dbe23c2395d201bbf9a0..31e0b86a94f1c3969c8fcafe463c591423a835f0 100644 +--- a/src/providers/ldap/sdap_async_groups.c ++++ b/src/providers/ldap/sdap_async_groups.c +@@ -1891,8 +1891,7 @@ static errno_t sdap_get_groups_next_base(struct tevent_req *req) + state = tevent_req_data(req, struct sdap_get_groups_state); + + talloc_zfree(state->filter); +- state->filter = sdap_get_id_specific_filter(state, +- state->base_filter, ++ state->filter = sdap_combine_filters(state, state->base_filter, + state->search_bases[state->base_iter]->filter); + if (!state->filter) { + return ENOMEM; +diff --git a/src/providers/ldap/sdap_async_groups_ad.c b/src/providers/ldap/sdap_async_groups_ad.c +index 8db587c96d569fc691486b252ff8f2c7d96e29c2..3f842b26dacd5a58b8254125287b98633cf29ae8 100644 +--- a/src/providers/ldap/sdap_async_groups_ad.c ++++ b/src/providers/ldap/sdap_async_groups_ad.c +@@ -141,8 +141,7 @@ sdap_get_ad_match_rule_members_next_base(struct tevent_req *req) + state = tevent_req_data(req, struct sdap_ad_match_rule_state); + + talloc_zfree(state->filter); +- state->filter = sdap_get_id_specific_filter(state, +- state->base_filter, ++ state->filter = sdap_combine_filters(state, state->base_filter, + state->search_bases[state->base_iter]->filter); + if (!state->filter) { + return ENOMEM; +diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c +index f451c4630cd5a8a7edb9f38c1e090a9a833c9cb5..1e5f5ab49896b234bec0c7a2c1429f30d90ae32a 100644 +--- a/src/providers/ldap/sdap_async_initgroups.c ++++ b/src/providers/ldap/sdap_async_initgroups.c +@@ -493,9 +493,8 @@ static errno_t sdap_initgr_rfc2307_next_base(struct tevent_req *req) + + talloc_zfree(state->filter); + +- state->filter = sdap_get_id_specific_filter( +- state, state->base_filter, +- state->search_bases[state->base_iter]->filter); ++ state->filter = sdap_combine_filters( state, state->base_filter, ++ state->search_bases[state->base_iter]->filter); + if (!state->filter) { + return ENOMEM; + } +@@ -1667,10 +1666,8 @@ static errno_t sdap_initgr_rfc2307bis_next_base(struct tevent_req *req) + state = tevent_req_data(req, struct sdap_initgr_rfc2307bis_state); + + talloc_zfree(state->filter); +- state->filter = sdap_get_id_specific_filter( +- state, +- state->base_filter, +- state->search_bases[state->base_iter]->filter); ++ state->filter = sdap_combine_filters(state, state->base_filter, ++ state->search_bases[state->base_iter]->filter); + if (!state->filter) { + return ENOMEM; + } +@@ -2430,9 +2427,8 @@ static errno_t rfc2307bis_nested_groups_next_base(struct tevent_req *req) + state = tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx); + + talloc_zfree(state->filter); +- state->filter = sdap_get_id_specific_filter( +- state, state->base_filter, +- state->search_bases[state->base_iter]->filter); ++ state->filter = sdap_combine_filters(state, state->base_filter, ++ state->search_bases[state->base_iter]->filter); + if (!state->filter) { + return ENOMEM; + } +@@ -2798,10 +2794,8 @@ static errno_t sdap_get_initgr_next_base(struct tevent_req *req) + state = tevent_req_data(req, struct sdap_get_initgr_state); + + talloc_zfree(state->filter); +- state->filter = sdap_get_id_specific_filter( +- state, +- state->user_base_filter, +- state->user_search_bases[state->user_base_iter]->filter); ++ state->filter = sdap_combine_filters(state, state->user_base_filter, ++ state->user_search_bases[state->user_base_iter]->filter); + if (!state->filter) { + return ENOMEM; + } +diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c +index e210db978c6b1cc9beea99f25cc58bec2670f66d..76b14a55b2619b22928e13f5513a7ef33cafbe5f 100644 +--- a/src/providers/ldap/sdap_async_initgroups_ad.c ++++ b/src/providers/ldap/sdap_async_initgroups_ad.c +@@ -170,8 +170,7 @@ sdap_get_ad_match_rule_initgroups_next_base(struct tevent_req *req) + state = tevent_req_data(req, struct sdap_ad_match_rule_initgr_state); + + talloc_zfree(state->filter); +- state->filter = sdap_get_id_specific_filter(state, +- state->base_filter, ++ state->filter = sdap_combine_filters(state, state->base_filter, + state->search_bases[state->base_iter]->filter); + if (!state->filter) { + return ENOMEM; +diff --git a/src/providers/ldap/sdap_async_nested_groups.c b/src/providers/ldap/sdap_async_nested_groups.c +index 08e199869ad16c3b19d998a2a28eae9a0dd0a371..af25430eacd4de7ea2e2872b0d9e34c8515c22db 100644 +--- a/src/providers/ldap/sdap_async_nested_groups.c ++++ b/src/providers/ldap/sdap_async_nested_groups.c +@@ -1589,8 +1589,7 @@ sdap_nested_group_lookup_user_send(TALLOC_CTX *mem_ctx, + } + + /* use search base filter if needed */ +- filter = sdap_get_id_specific_filter(state, base_filter, +- member->user_filter); ++ filter = sdap_combine_filters(state, base_filter, member->user_filter); + if (filter == NULL) { + ret = ENOMEM; + goto immediately; +@@ -1733,8 +1732,7 @@ sdap_nested_group_lookup_group_send(TALLOC_CTX *mem_ctx, + } + + /* use search base filter if needed */ +- filter = sdap_get_id_specific_filter(state, base_filter, +- member->group_filter); ++ filter = sdap_combine_filters(state, base_filter, member->group_filter); + if (filter == NULL) { + ret = ENOMEM; + goto immediately; +diff --git a/src/providers/ldap/sdap_async_netgroups.c b/src/providers/ldap/sdap_async_netgroups.c +index e50f2508707fbd43374d5afef7360274afb18fa6..ae8e56b3cd5ed127c0293c1d6702de952cc646a7 100644 +--- a/src/providers/ldap/sdap_async_netgroups.c ++++ b/src/providers/ldap/sdap_async_netgroups.c +@@ -624,8 +624,7 @@ static errno_t sdap_get_netgroups_next_base(struct tevent_req *req) + state = tevent_req_data(req, struct sdap_get_netgroups_state); + + talloc_zfree(state->filter); +- state->filter = sdap_get_id_specific_filter(state, +- state->base_filter, ++ state->filter = sdap_combine_filters(state, state->base_filter, + state->search_bases[state->base_iter]->filter); + if (!state->filter) { + return ENOMEM; +diff --git a/src/providers/ldap/sdap_async_services.c b/src/providers/ldap/sdap_async_services.c +index 54f3ffb7440df8808f2dfb4806314b9c795f7acc..72758f2469561bc14d2ae21507e96857bbe48737 100644 +--- a/src/providers/ldap/sdap_async_services.c ++++ b/src/providers/ldap/sdap_async_services.c +@@ -129,8 +129,7 @@ sdap_get_services_next_base(struct tevent_req *req) + state = tevent_req_data(req, struct sdap_get_services_state); + + talloc_zfree(state->filter); +- state->filter = sdap_get_id_specific_filter(state, +- state->base_filter, ++ state->filter = sdap_combine_filters(state, state->base_filter, + state->search_bases[state->base_iter]->filter); + if (!state->filter) { + return ENOMEM; +diff --git a/src/providers/ldap/sdap_async_sudo.c b/src/providers/ldap/sdap_async_sudo.c +index fd9aecba98838ba01453cc4eed827c9e5a2fa9e2..421b5712a80de990be83729e9c40c06c175a77fc 100644 +--- a/src/providers/ldap/sdap_async_sudo.c ++++ b/src/providers/ldap/sdap_async_sudo.c +@@ -125,7 +125,7 @@ static errno_t sdap_sudo_load_sudoers_next_base(struct tevent_req *req) + } + + /* Combine lookup and search base filters. */ +- filter = sdap_get_id_specific_filter(state, state->filter, base->filter); ++ filter = sdap_combine_filters(state, state->filter, base->filter); + if (filter == NULL) { + return ENOMEM; + } +@@ -467,7 +467,7 @@ static char *sdap_sudo_get_filter(TALLOC_CTX *mem_ctx, + goto done; + } + +- filter = sdap_get_id_specific_filter(tmp_ctx, rule_filter, host_filter); ++ filter = sdap_combine_filters(tmp_ctx, rule_filter, host_filter); + if (filter == NULL) { + goto done; + } +diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c +index 865439cadeb4f9f9452b1549663691c29e52f27b..25dd40dfff08d08f25856bd1f00dfd3bb5eeb3d5 100644 +--- a/src/providers/ldap/sdap_async_users.c ++++ b/src/providers/ldap/sdap_async_users.c +@@ -682,8 +682,7 @@ static errno_t sdap_search_user_next_base(struct tevent_req *req) + state = tevent_req_data(req, struct sdap_search_user_state); + + talloc_zfree(state->filter); +- state->filter = sdap_get_id_specific_filter(state, +- state->base_filter, ++ state->filter = sdap_combine_filters(state, state->base_filter, + state->search_bases[state->base_iter]->filter); + if (state->filter == NULL) { + return ENOMEM; +-- +2.5.0 + diff --git a/0014-SDAP-support-empty-filters-in-sdap_combine_filters.patch b/0014-SDAP-support-empty-filters-in-sdap_combine_filters.patch new file mode 100644 index 0000000..7ccb25a --- /dev/null +++ b/0014-SDAP-support-empty-filters-in-sdap_combine_filters.patch @@ -0,0 +1,37 @@ +From d3a3e06085cd25ce09f122ff04917d09743752a8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 18 Dec 2015 14:23:56 +0100 +Subject: [PATCH 14/49] SDAP: support empty filters in sdap_combine_filters() + +Reviewed-by: Sumit Bose +(cherry picked from commit 1d3f5fc2802c218916e6d6bc98eeaed79c66bafe) +--- + src/providers/ldap/sdap_utils.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/providers/ldap/sdap_utils.c b/src/providers/ldap/sdap_utils.c +index 7a96f81a1db2644b698e5a5baaed19366a305c6b..47921b8768b9c4c4b2d40a5eb28e28bf48238210 100644 +--- a/src/providers/ldap/sdap_utils.c ++++ b/src/providers/ldap/sdap_utils.c +@@ -155,8 +155,10 @@ char *sdap_combine_filters(TALLOC_CTX *mem_ctx, + { + char *filter = NULL; + +- if (!extra_filter) { ++ if (extra_filter == NULL || extra_filter[0] == '\0') { + return talloc_strdup(mem_ctx, base_filter); ++ } else if (base_filter == NULL || base_filter[0] == '\0') { ++ return talloc_strdup(mem_ctx, extra_filter); + } + + if (extra_filter[0] == '(') { +@@ -166,5 +168,6 @@ char *sdap_combine_filters(TALLOC_CTX *mem_ctx, + filter = talloc_asprintf(mem_ctx, "(&%s(%s))", + base_filter, extra_filter); + } ++ + return filter; /* NULL or not */ + } +-- +2.5.0 + diff --git a/0015-SUDO-use-sdap_search_bases-instead-custom-sb-iterato.patch b/0015-SUDO-use-sdap_search_bases-instead-custom-sb-iterato.patch new file mode 100644 index 0000000..f1e7c53 --- /dev/null +++ b/0015-SUDO-use-sdap_search_bases-instead-custom-sb-iterato.patch @@ -0,0 +1,216 @@ +From 1acd58fd1a2bb992ea3f4546433eb3ea69772801 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 16 Dec 2015 13:49:02 +0100 +Subject: [PATCH 15/49] SUDO: use sdap_search_bases instead custom sb iterator + +Removes code duplication. + +Reviewed-by: Sumit Bose +(cherry picked from commit e9ae5cd285dcc8fa232e16f9c7a29f18537272f2) +--- + src/providers/ldap/sdap_async_sudo.c | 133 +++++++---------------------------- + 1 file changed, 26 insertions(+), 107 deletions(-) + +diff --git a/src/providers/ldap/sdap_async_sudo.c b/src/providers/ldap/sdap_async_sudo.c +index 421b5712a80de990be83729e9c40c06c175a77fc..d7780d38405a2705e25a9c983aca2736548a624e 100644 +--- a/src/providers/ldap/sdap_async_sudo.c ++++ b/src/providers/ldap/sdap_async_sudo.c +@@ -29,27 +29,16 @@ + #include "providers/dp_backend.h" + #include "providers/ldap/ldap_common.h" + #include "providers/ldap/sdap.h" +-#include "providers/ldap/sdap_async.h" ++#include "providers/ldap/sdap_ops.h" + #include "providers/ldap/sdap_sudo.h" + #include "providers/ldap/sdap_sudo_cache.h" + #include "db/sysdb_sudo.h" + + struct sdap_sudo_load_sudoers_state { +- struct tevent_context *ev; +- struct sdap_options *opts; +- struct sdap_handle *sh; +- +- int timeout; +- const char **attrs; +- const char *filter; +- size_t base_iter; +- struct sdap_search_base **search_bases; +- + struct sysdb_attrs **rules; + size_t num_rules; + }; + +-static errno_t sdap_sudo_load_sudoers_next_base(struct tevent_req *req); + static void sdap_sudo_load_sudoers_done(struct tevent_req *subreq); + + static struct tevent_req * +@@ -60,7 +49,9 @@ sdap_sudo_load_sudoers_send(TALLOC_CTX *mem_ctx, + const char *ldap_filter) + { + struct tevent_req *req; ++ struct tevent_req *subreq; + struct sdap_sudo_load_sudoers_state *state; ++ struct sdap_search_base **sb; + int ret; + + req = tevent_req_create(mem_ctx, &state, +@@ -69,133 +60,61 @@ sdap_sudo_load_sudoers_send(TALLOC_CTX *mem_ctx, + return NULL; + } + +- state->ev = ev; +- state->opts = opts; +- state->sh = sh; +- state->base_iter = 0; +- state->search_bases = opts->sdom->sudo_search_bases; +- state->filter = ldap_filter; +- state->timeout = dp_opt_get_int(opts->basic, SDAP_SEARCH_TIMEOUT); + state->rules = NULL; + state->num_rules = 0; + +- if (state->search_bases == NULL) { ++ sb = opts->sdom->sudo_search_bases; ++ if (sb == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + "SUDOERS lookup request without a search base\n"); + ret = EINVAL; + goto immediately; + } + +- /* create attrs from map */ +- ret = build_attrs_from_map(state, opts->sudorule_map, SDAP_OPTS_SUDO, +- NULL, &state->attrs, NULL); +- if (ret != EOK) { +- goto immediately; +- } ++ DEBUG(SSSDBG_TRACE_FUNC, "About to fetch sudo rules\n"); + +- /* begin search */ +- ret = sdap_sudo_load_sudoers_next_base(req); +- if (ret == EAGAIN) { +- /* asynchronous processing */ +- return req; +- } +- +-immediately: +- if (ret == EOK) { +- tevent_req_done(req); +- } else { +- tevent_req_error(req, ret); +- } +- tevent_req_post(req, ev); +- +- return req; +-} +- +-static errno_t sdap_sudo_load_sudoers_next_base(struct tevent_req *req) +-{ +- struct sdap_sudo_load_sudoers_state *state; +- struct sdap_search_base *base; +- struct tevent_req *subreq; +- char *filter; +- +- state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state); +- base = state->search_bases[state->base_iter]; +- if (base == NULL) { +- return EOK; +- } +- +- /* Combine lookup and search base filters. */ +- filter = sdap_combine_filters(state, state->filter, base->filter); +- if (filter == NULL) { +- return ENOMEM; +- } +- +- DEBUG(SSSDBG_TRACE_FUNC, "Searching for sudo rules with base [%s]\n", +- base->basedn); +- +- subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh, +- base->basedn, base->scope, filter, +- state->attrs, state->opts->sudorule_map, +- SDAP_OPTS_SUDO, state->timeout, true); ++ subreq = sdap_search_bases_send(state, ev, opts, sh, sb, ++ opts->sudorule_map, true, 0, ++ ldap_filter, NULL); + if (subreq == NULL) { +- return ENOMEM; ++ ret = ENOMEM; ++ goto immediately; + } + + tevent_req_set_callback(subreq, sdap_sudo_load_sudoers_done, req); + +- state->base_iter++; +- return EAGAIN; ++ ret = EOK; ++ ++immediately: ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ } ++ ++ return req; + } + + static void sdap_sudo_load_sudoers_done(struct tevent_req *subreq) + { + struct tevent_req *req; + struct sdap_sudo_load_sudoers_state *state; +- struct sdap_search_base *search_base; +- struct sysdb_attrs **attrs = NULL; +- size_t count; +- int ret; +- size_t i; ++ errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state); +- search_base = state->search_bases[state->base_iter - 1]; + +- DEBUG(SSSDBG_TRACE_FUNC, "Receiving sudo rules with base [%s]\n", +- search_base->basedn); +- +- ret = sdap_get_generic_recv(subreq, state, &count, &attrs); ++ ret = sdap_search_bases_recv(subreq, state, &state->num_rules, ++ &state->rules); + talloc_zfree(subreq); + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + +- /* Add rules to result. */ +- if (count > 0) { +- state->rules = talloc_realloc(state, state->rules, +- struct sysdb_attrs *, +- state->num_rules + count); +- if (state->rules == NULL) { +- tevent_req_error(req, ENOMEM); +- return; +- } ++ DEBUG(SSSDBG_IMPORTANT_INFO, "Received %zu sudo rules\n", ++ state->num_rules); + +- for (i = 0; i < count; i++) { +- state->rules[state->num_rules + i] = talloc_steal(state->rules, +- attrs[i]); +- } +- +- state->num_rules += count; +- } +- +- /* Try next search base. */ +- ret = sdap_sudo_load_sudoers_next_base(req); +- if (ret == EOK) { +- tevent_req_done(req); +- } else if (ret != EAGAIN) { +- tevent_req_error(req, ret); +- } ++ tevent_req_done(req); + + return; + } +-- +2.5.0 + diff --git a/0016-SUDO-make-sudo-sysdb-interface-more-reusable.patch b/0016-SUDO-make-sudo-sysdb-interface-more-reusable.patch new file mode 100644 index 0000000..d27b647 --- /dev/null +++ b/0016-SUDO-make-sudo-sysdb-interface-more-reusable.patch @@ -0,0 +1,988 @@ +From 154d886c35318cabfb174e6791d3361ce760cdcd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 16 Dec 2015 14:42:04 +0100 +Subject: [PATCH 16/49] SUDO: make sudo sysdb interface more reusable + +Reviewed-by: Sumit Bose +(cherry picked from commit 68abbe716bed7c8d6790d9bec168ef44469306a1) +--- + Makefile.am | 2 - + src/db/sysdb.c | 98 ++++++++++++ + src/db/sysdb.h | 7 + + src/db/sysdb_sudo.c | 286 +++++++++++++++++++++++++++-------- + src/db/sysdb_sudo.h | 17 +-- + src/providers/ldap/sdap_async_sudo.c | 121 ++------------- + src/providers/ldap/sdap_sudo.c | 1 - + src/providers/ldap/sdap_sudo_cache.c | 183 ---------------------- + src/providers/ldap/sdap_sudo_cache.h | 37 ----- + 9 files changed, 354 insertions(+), 398 deletions(-) + delete mode 100644 src/providers/ldap/sdap_sudo_cache.c + delete mode 100644 src/providers/ldap/sdap_sudo_cache.h + +diff --git a/Makefile.am b/Makefile.am +index 095b1cfd62f49d266df278e1736d48ed5ef4fa7a..29dd73edf3e6770e4280945f69c9d266f3d8c4c4 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -618,7 +618,6 @@ dist_noinst_HEADERS = \ + src/providers/ldap/sdap_access.h \ + src/providers/ldap/sdap_async.h \ + src/providers/ldap/sdap_async_private.h \ +- src/providers/ldap/sdap_sudo_cache.h \ + src/providers/ldap/sdap_sudo.h \ + src/providers/ldap/sdap_autofs.h \ + src/providers/ldap/sdap_id_op.h \ +@@ -2859,7 +2858,6 @@ libsss_ldap_common_la_LDFLAGS = \ + + if BUILD_SUDO + libsss_ldap_common_la_SOURCES += \ +- src/providers/ldap/sdap_sudo_cache.c \ + src/providers/ldap/sdap_async_sudo.c \ + src/providers/ldap/sdap_async_sudo_hostinfo.c \ + src/providers/ldap/sdap_sudo_refresh.c \ +diff --git a/src/db/sysdb.c b/src/db/sysdb.c +index a71364d7c4b600eafd10fafa6641eac7b2292764..d4366a3c76f114bf113567754a1e0417afe664e3 100644 +--- a/src/db/sysdb.c ++++ b/src/db/sysdb.c +@@ -2013,3 +2013,101 @@ errno_t sysdb_msg2attrs(TALLOC_CTX *mem_ctx, size_t count, + + return EOK; + } ++ ++int sysdb_compare_usn(const char *a, const char *b) ++{ ++ size_t len_a; ++ size_t len_b; ++ ++ if (a == NULL) { ++ return -1; ++ } ++ ++ if (b == NULL) { ++ return 1; ++ } ++ ++ len_a = strlen(a); ++ len_b = strlen(b); ++ ++ /* trim leading zeros */ ++ while (len_a > 0 && *a == '0') { ++ a++; ++ len_a--; ++ } ++ ++ while (len_b > 0 && *b == '0') { ++ b++; ++ len_b--; ++ } ++ ++ /* less digits means lower number */ ++ if (len_a < len_b) { ++ return -1; ++ } ++ ++ /* more digits means bigger number */ ++ if (len_a > len_b) { ++ return 1; ++ } ++ ++ /* now we can compare digits since alphabetical order is the same ++ * as numeric order */ ++ return strcmp(a, b); ++} ++ ++errno_t sysdb_get_highest_usn(TALLOC_CTX *mem_ctx, ++ struct sysdb_attrs **attrs, ++ size_t num_attrs, ++ char **_usn) ++{ ++ const char *highest = NULL; ++ const char *current = NULL; ++ char *usn; ++ errno_t ret; ++ size_t i; ++ ++ if (num_attrs == 0 || attrs == NULL) { ++ goto done; ++ } ++ ++ for (i = 0; i < num_attrs; i++) { ++ ret = sysdb_attrs_get_string(attrs[i], SYSDB_USN, ¤t); ++ if (ret == ENOENT) { ++ /* USN value is not present, assuming zero. */ ++ current = "0"; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Failed to retrieve USN value " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ ++ return ret; ++ } ++ ++ if (current == NULL) { ++ continue; ++ } ++ ++ if (highest == NULL) { ++ highest = current; ++ continue; ++ } ++ ++ if (sysdb_compare_usn(current, highest) > 0 ) { ++ highest = current; ++ } ++ } ++ ++done: ++ if (highest == NULL) { ++ usn = talloc_strdup(mem_ctx, "0"); ++ } else { ++ usn = talloc_strdup(mem_ctx, highest); ++ } ++ ++ if (usn == NULL) { ++ return ENOMEM; ++ } ++ ++ *_usn = usn; ++ return EOK; ++} +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index ad1bf75b7437730af4a56d97e8f9868073e678aa..2e797fd7fa39163c2ab6a10e51228e0f1af3f9e3 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -386,6 +386,13 @@ errno_t sysdb_msg2attrs(TALLOC_CTX *mem_ctx, size_t count, + struct ldb_message **msgs, + struct sysdb_attrs ***attrs); + ++int sysdb_compare_usn(const char *a, const char *b); ++ ++errno_t sysdb_get_highest_usn(TALLOC_CTX *mem_ctx, ++ struct sysdb_attrs **attrs, ++ size_t num_attrs, ++ char **_usn); ++ + /* convert an ldb error into an errno error */ + int sysdb_error_to_errno(int ldberr); + +diff --git a/src/db/sysdb_sudo.c b/src/db/sysdb_sudo.c +index 784ac8af3ae5cb08f30eb9631c7ffa4aa92bde23..76116abacb20219f0c1dcdde755e8268e10fd293 100644 +--- a/src/db/sysdb_sudo.c ++++ b/src/db/sysdb_sudo.c +@@ -27,6 +27,8 @@ + #include "db/sysdb_private.h" + #include "db/sysdb_sudo.h" + ++#define SUDO_ALL_FILTER "(" SYSDB_OBJECTCLASS "=" SYSDB_SUDO_CACHE_OC ")" ++ + #define NULL_CHECK(val, rval, label) do { \ + if (!val) { \ + rval = ENOMEM; \ +@@ -427,41 +429,6 @@ done: + return ret; + } + +-errno_t +-sysdb_save_sudorule(struct sss_domain_info *domain, +- const char *rule_name, +- struct sysdb_attrs *attrs) +-{ +- errno_t ret; +- +- DEBUG(SSSDBG_TRACE_FUNC, "Adding sudo rule %s\n", rule_name); +- +- ret = sysdb_attrs_add_string(attrs, SYSDB_OBJECTCLASS, +- SYSDB_SUDO_CACHE_OC); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "Could not set rule object class [%d]: %s\n", +- ret, strerror(ret)); +- return ret; +- } +- +- ret = sysdb_attrs_add_string(attrs, SYSDB_NAME, rule_name); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "Could not set name attribute [%d]: %s\n", +- ret, strerror(ret)); +- return ret; +- } +- +- ret = sysdb_store_custom(domain, rule_name, +- SUDORULE_SUBDIR, attrs); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "sysdb_store_custom failed [%d]: %s\n", +- ret, strerror(ret)); +- return ret; +- } +- +- return EOK; +-} +- + static errno_t sysdb_sudo_set_refresh_time(struct sss_domain_info *domain, + const char *attr_name, + time_t value) +@@ -615,6 +582,26 @@ errno_t sysdb_sudo_get_last_full_refresh(struct sss_domain_info *domain, + + /* ==================== Purge functions ==================== */ + ++static const char * ++sysdb_sudo_get_rule_name(struct sysdb_attrs *rule) ++{ ++ const char *name; ++ errno_t ret; ++ ++ ret = sysdb_attrs_get_string(rule, SYSDB_SUDO_CACHE_AT_CN, &name); ++ if (ret == ERANGE) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Warning: found rule that contains none " ++ "or multiple CN values. It will be skipped.\n"); ++ return NULL; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to obtain rule name [%d]: %s\n", ++ ret, strerror(ret)); ++ return NULL; ++ } ++ ++ return name; ++} ++ + static errno_t sysdb_sudo_purge_all(struct sss_domain_info *domain) + { + struct ldb_dn *base_dn = NULL; +@@ -627,6 +614,8 @@ static errno_t sysdb_sudo_purge_all(struct sss_domain_info *domain) + base_dn = sysdb_custom_subtree_dn(tmp_ctx, domain, SUDORULE_SUBDIR); + NULL_CHECK(base_dn, ret, done); + ++ DEBUG(SSSDBG_TRACE_FUNC, "Deleting all cached sudo rules\n"); ++ + ret = sysdb_delete_recursive(domain->sysdb, base_dn, true); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sysdb_delete_recursive failed.\n"); +@@ -639,42 +628,74 @@ done: + return ret; + } + +-errno_t sysdb_sudo_purge_byname(struct sss_domain_info *domain, +- const char *name) ++static errno_t ++sysdb_sudo_purge_byname(struct sss_domain_info *domain, ++ const char *name) + { + DEBUG(SSSDBG_TRACE_INTERNAL, "Deleting sudo rule %s\n", name); + return sysdb_delete_custom(domain, name, SUDORULE_SUBDIR); + } + +-errno_t sysdb_sudo_purge_byfilter(struct sss_domain_info *domain, +- const char *filter) ++static errno_t ++sysdb_sudo_purge_byrules(struct sss_domain_info *dom, ++ struct sysdb_attrs **rules, ++ size_t num_rules) ++{ ++ const char *name; ++ errno_t ret; ++ size_t i; ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "About to remove rules from sudo cache\n"); ++ ++ if (num_rules == 0 || rules == NULL) { ++ return EOK; ++ } ++ ++ for (i = 0; i < num_rules; i++) { ++ name = sysdb_sudo_get_rule_name(rules[i]); ++ if (name == NULL) { ++ continue; ++ } ++ ++ ret = sysdb_sudo_purge_byname(dom, name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Failed to delete rule " ++ "%s [%d]: %s\n", name, ret, sss_strerror(ret)); ++ continue; ++ } ++ } ++ ++ return EOK; ++} ++ ++static errno_t ++sysdb_sudo_purge_byfilter(struct sss_domain_info *domain, ++ const char *filter) + { + TALLOC_CTX *tmp_ctx; +- size_t count; ++ struct sysdb_attrs **rules; + struct ldb_message **msgs; +- const char *name; +- int i; ++ size_t count; + errno_t ret; +- errno_t sret; +- bool in_transaction = false; + const char *attrs[] = { SYSDB_OBJECTCLASS, + SYSDB_NAME, + SYSDB_SUDO_CACHE_AT_CN, + NULL }; + +- /* just purge all if there's no filter */ +- if (!filter) { ++ if (filter == NULL || strcmp(filter, SUDO_ALL_FILTER) == 0) { + return sysdb_sudo_purge_all(domain); + } + + tmp_ctx = talloc_new(NULL); +- NULL_CHECK(tmp_ctx, ret, done); ++ if (tmp_ctx == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } + +- /* match entries based on the filter and remove them one by one */ + ret = sysdb_search_custom(tmp_ctx, domain, filter, + SUDORULE_SUBDIR, attrs, + &count, &msgs); +- if (ret == ENOENT) { ++ if (ret == ENOENT || count == 0) { + DEBUG(SSSDBG_TRACE_FUNC, "No rules matched\n"); + ret = EOK; + goto done; +@@ -683,24 +704,165 @@ errno_t sysdb_sudo_purge_byfilter(struct sss_domain_info *domain, + goto done; + } + ++ ret = sysdb_msg2attrs(tmp_ctx, count, msgs, &rules); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to convert ldb message to " ++ "sysdb attrs [%d]: %s\n", ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = sysdb_sudo_purge_byrules(domain, rules, count); ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++errno_t sysdb_sudo_purge(struct sss_domain_info *domain, ++ const char *delete_filter, ++ struct sysdb_attrs **rules, ++ size_t num_rules) ++{ ++ bool in_transaction = false; ++ errno_t sret; ++ errno_t ret; ++ + ret = sysdb_transaction_start(domain->sysdb); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); ++ return ret; ++ } ++ in_transaction = true; ++ ++ if (delete_filter) { ++ ret = sysdb_sudo_purge_byfilter(domain, delete_filter); ++ } else { ++ ret = sysdb_sudo_purge_byrules(domain, rules, num_rules); ++ } ++ ++ if (ret != EOK) { + goto done; + } ++ ++ ret = sysdb_transaction_commit(domain->sysdb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n"); ++ goto done; ++ } ++ in_transaction = false; ++ ++done: ++ if (in_transaction) { ++ sret = sysdb_transaction_cancel(domain->sysdb); ++ if (sret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n"); ++ } ++ } ++ ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to purge sudo cache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ } ++ ++ return ret; ++} ++ ++static errno_t ++sysdb_sudo_add_sss_attrs(struct sysdb_attrs *rule, ++ const char *name, ++ int cache_timeout, ++ time_t now) ++{ ++ time_t expire; ++ errno_t ret; ++ ++ ret = sysdb_attrs_add_string(rule, SYSDB_OBJECTCLASS, SYSDB_SUDO_CACHE_OC); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to add %s attribute [%d]: %s\n", ++ SYSDB_OBJECTCLASS, ret, strerror(ret)); ++ return ret; ++ } ++ ++ ret = sysdb_attrs_add_string(rule, SYSDB_NAME, name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to add %s attribute [%d]: %s\n", ++ SYSDB_OBJECTCLASS, ret, strerror(ret)); ++ return ret; ++ } ++ ++ expire = cache_timeout > 0 ? now + cache_timeout : 0; ++ ret = sysdb_attrs_add_time_t(rule, SYSDB_CACHE_EXPIRE, expire); ++ if (ret) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to add %s attribute [%d]: %s\n", ++ SYSDB_CACHE_EXPIRE, ret, strerror(ret)); ++ return ret; ++ } ++ ++ return EOK; ++} ++ ++static errno_t ++sysdb_sudo_store_rule(struct sss_domain_info *domain, ++ struct sysdb_attrs *rule, ++ int cache_timeout, ++ time_t now) ++{ ++ const char *name; ++ errno_t ret; ++ ++ name = sysdb_sudo_get_rule_name(rule); ++ if (name == NULL) { ++ return EINVAL; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Adding sudo rule %s\n", name); ++ ++ ret = sysdb_sudo_add_sss_attrs(rule, name, cache_timeout, now); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ ret = sysdb_store_custom(domain, name, SUDORULE_SUBDIR, rule); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to store rule %s [%d]: %s\n", ++ name, ret, strerror(ret)); ++ return ret; ++ } ++ ++ return EOK; ++} ++ ++errno_t ++sysdb_sudo_store(struct sss_domain_info *domain, ++ struct sysdb_attrs **rules, ++ size_t num_rules) ++{ ++ bool in_transaction = false; ++ errno_t sret; ++ errno_t ret; ++ time_t now; ++ size_t i; ++ ++ if (num_rules == 0 || rules == NULL) { ++ return EOK; ++ } ++ ++ ret = sysdb_transaction_start(domain->sysdb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); ++ return ret; ++ } + in_transaction = true; + +- for (i = 0; i < count; i++) { +- name = ldb_msg_find_attr_as_string(msgs[i], SYSDB_NAME, NULL); +- if (name == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "A rule without a name?\n"); +- /* skip this one but still delete other entries */ ++ now = time(NULL); ++ for (i = 0; i < num_rules; i++) { ++ ret = sysdb_sudo_store_rule(domain, rules[i], ++ domain->sudo_timeout, now); ++ if (ret == EINVAL) { ++ /* Multiple CNs are error on server side, we can just ignore this ++ * rule and save the others. Loud debug message is in logs. */ + continue; +- } +- +- ret = sysdb_sudo_purge_byname(domain, name); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "Could not delete rule %s\n", name); ++ } else if (ret != EOK) { + goto done; + } + } +@@ -720,6 +882,10 @@ done: + } + } + +- talloc_free(tmp_ctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to store sudo rules [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ } ++ + return ret; + } +diff --git a/src/db/sysdb_sudo.h b/src/db/sysdb_sudo.h +index fc896c385c6fa71e735b3db763ccee4a0354d007..6dd9ea7bb8ec947f5beceb89fd27bde156c27c36 100644 +--- a/src/db/sysdb_sudo.h ++++ b/src/db/sysdb_sudo.h +@@ -78,20 +78,19 @@ sysdb_get_sudo_user_info(TALLOC_CTX *mem_ctx, + const char *username, uid_t *_uid, + char ***groupnames); + +-errno_t +-sysdb_save_sudorule(struct sss_domain_info *domain, +- const char *rule_name, +- struct sysdb_attrs *attrs); +- + errno_t sysdb_sudo_set_last_full_refresh(struct sss_domain_info *domain, + time_t value); + errno_t sysdb_sudo_get_last_full_refresh(struct sss_domain_info *domain, + time_t *value); + +-errno_t sysdb_sudo_purge_byname(struct sss_domain_info *domain, +- const char *name); ++errno_t sysdb_sudo_purge(struct sss_domain_info *domain, ++ const char *delete_filter, ++ struct sysdb_attrs **rules, ++ size_t num_rules); + +-errno_t sysdb_sudo_purge_byfilter(struct sss_domain_info *domain, +- const char *filter); ++errno_t ++sysdb_sudo_store(struct sss_domain_info *domain, ++ struct sysdb_attrs **rules, ++ size_t num_rules); + + #endif /* _SYSDB_SUDO_H_ */ +diff --git a/src/providers/ldap/sdap_async_sudo.c b/src/providers/ldap/sdap_async_sudo.c +index d7780d38405a2705e25a9c983aca2736548a624e..2fcfa4aec5d4d53f26d40395e99bdce1b41710d4 100644 +--- a/src/providers/ldap/sdap_async_sudo.c ++++ b/src/providers/ldap/sdap_async_sudo.c +@@ -31,7 +31,6 @@ + #include "providers/ldap/sdap.h" + #include "providers/ldap/sdap_ops.h" + #include "providers/ldap/sdap_sudo.h" +-#include "providers/ldap/sdap_sudo_cache.h" + #include "db/sysdb_sudo.h" + + struct sdap_sudo_load_sudoers_state { +@@ -136,89 +135,6 @@ static int sdap_sudo_load_sudoers_recv(struct tevent_req *req, + return EOK; + } + +-static int sdap_sudo_purge_sudoers(struct sss_domain_info *dom, +- const char *filter, +- struct sdap_attr_map *map, +- size_t rules_count, +- struct sysdb_attrs **rules) +-{ +- const char *name; +- size_t i; +- errno_t ret; +- +- if (filter == NULL) { +- /* removes downloaded rules from the cache */ +- if (rules_count == 0 || rules == NULL) { +- return EOK; +- } +- +- for (i = 0; i < rules_count; i++) { +- ret = sysdb_attrs_get_string(rules[i], +- map[SDAP_AT_SUDO_NAME].sys_name, +- &name); +- if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, +- "Failed to retrieve rule name: [%s]\n", strerror(ret)); +- continue; +- } +- +- ret = sysdb_sudo_purge_byname(dom, name); +- if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, +- "Failed to delete rule %s: [%s]\n", +- name, strerror(ret)); +- continue; +- } +- } +- +- ret = EOK; +- } else { +- /* purge cache by provided filter */ +- ret = sysdb_sudo_purge_byfilter(dom, filter); +- if (ret != EOK) { +- goto done; +- } +- } +- +-done: +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "failed to purge sudo rules [%d]: %s\n", +- ret, strerror(ret)); +- } +- +- return ret; +-} +- +-static int sdap_sudo_store_sudoers(TALLOC_CTX *mem_ctx, +- struct sss_domain_info *domain, +- struct sdap_options *opts, +- size_t rules_count, +- struct sysdb_attrs **rules, +- int cache_timeout, +- time_t now, +- char **_usn) +-{ +- errno_t ret; +- +- /* Empty sudoers? Done. */ +- if (rules_count == 0 || rules == NULL) { +- *_usn = NULL; +- return EOK; +- } +- +- ret = sdap_save_native_sudorule_list(mem_ctx, domain, +- opts->sudorule_map, rules, +- rules_count, cache_timeout, now, +- _usn); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "failed to save sudo rules [%d]: %s\n", +- ret, strerror(ret)); +- return ret; +- } +- +- return EOK; +-} +- + static void sdap_sudo_set_usn(struct sdap_server_opts *srv_opts, char *usn) + { + unsigned int usn_number; +@@ -230,23 +146,14 @@ static void sdap_sudo_set_usn(struct sdap_server_opts *srv_opts, char *usn) + } + + if (usn == NULL) { +- /* If the USN value is unknown and we don't have max_sudo_value set +- * (possibly first full refresh which did not find any rule) we will +- * set zero so smart refresh can pick up. */ +- if (srv_opts->max_sudo_value == NULL) { +- srv_opts->max_sudo_value = talloc_strdup(srv_opts, "0"); +- if (srv_opts->max_sudo_value == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n"); +- } +- return; +- } +- +- DEBUG(SSSDBG_TRACE_FUNC, "Empty USN, ignoring\n"); ++ DEBUG(SSSDBG_TRACE_FUNC, "Bug: usn is NULL\n"); + return; + } + +- talloc_zfree(srv_opts->max_sudo_value); +- srv_opts->max_sudo_value = talloc_steal(srv_opts, usn); ++ if (sysdb_compare_usn(usn, srv_opts->max_sudo_value) > 0) { ++ talloc_zfree(srv_opts->max_sudo_value); ++ srv_opts->max_sudo_value = talloc_steal(srv_opts, usn); ++ } + + usn_number = strtoul(usn, &endptr, 10); + if ((endptr == NULL || (*endptr == '\0' && endptr != usn)) +@@ -625,7 +532,6 @@ static void sdap_sudo_refresh_done(struct tevent_req *subreq) + int ret; + errno_t sret; + bool in_transaction = false; +- time_t now; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_sudo_refresh_state); +@@ -654,17 +560,14 @@ static void sdap_sudo_refresh_done(struct tevent_req *subreq) + in_transaction = true; + + /* purge cache */ +- ret = sdap_sudo_purge_sudoers(state->domain, state->delete_filter, +- state->opts->sudorule_map, rules_count, rules); ++ ret = sysdb_sudo_purge(state->domain, state->delete_filter, ++ rules, rules_count); + if (ret != EOK) { + goto done; + } + + /* store rules */ +- now = time(NULL); +- ret = sdap_sudo_store_sudoers(state, state->domain, +- state->opts, rules_count, rules, +- state->domain->sudo_timeout, now, &usn); ++ ret = sysdb_sudo_store(state->domain, rules, rules_count); + if (ret != EOK) { + goto done; + } +@@ -680,7 +583,13 @@ static void sdap_sudo_refresh_done(struct tevent_req *subreq) + DEBUG(SSSDBG_TRACE_FUNC, "Sudoers is successfuly stored in cache\n"); + + /* remember new usn */ +- sdap_sudo_set_usn(state->srv_opts, usn); ++ ret = sysdb_get_highest_usn(state, rules, rules_count, &usn); ++ if (ret == EOK) { ++ sdap_sudo_set_usn(state->srv_opts, usn); ++ } else { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Unable to get highest USN [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ } + + ret = EOK; + state->num_rules = rules_count; +diff --git a/src/providers/ldap/sdap_sudo.c b/src/providers/ldap/sdap_sudo.c +index 550784842c6e6162d153785940c1e37a51b5dc1f..10067e9ba779b5224bf21dd7a705c45e7f4e0f99 100644 +--- a/src/providers/ldap/sdap_sudo.c ++++ b/src/providers/ldap/sdap_sudo.c +@@ -27,7 +27,6 @@ + #include "providers/ldap/sdap.h" + #include "providers/ldap/sdap_async.h" + #include "providers/ldap/sdap_sudo.h" +-#include "providers/ldap/sdap_sudo_cache.h" + #include "db/sysdb_sudo.h" + + static void sdap_sudo_handler(struct be_req *breq); +diff --git a/src/providers/ldap/sdap_sudo_cache.c b/src/providers/ldap/sdap_sudo_cache.c +deleted file mode 100644 +index 56e84ce8f26338ea5856eb5c76627641eee93df1..0000000000000000000000000000000000000000 +--- a/src/providers/ldap/sdap_sudo_cache.c ++++ /dev/null +@@ -1,183 +0,0 @@ +-/* +- Authors: +- Jakub Hrozek +- +- Copyright (C) 2011 Red Hat +- +- This program is free software; you can redistribute it and/or modify +- it under the terms of the GNU General Public License as published by +- the Free Software Foundation; either version 3 of the License, or +- (at your option) any later version. +- +- This program is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- GNU General Public License for more details. +- +- You should have received a copy of the GNU General Public License +- along with this program. If not, see . +-*/ +- +-#include +- +-#include "db/sysdb.h" +-#include "db/sysdb_sudo.h" +-#include "providers/ldap/sdap_sudo_cache.h" +- +-/* ========== Functions specific for the native sudo LDAP schema ========== */ +-static errno_t sdap_sudo_get_usn(TALLOC_CTX *mem_ctx, +- struct sysdb_attrs *attrs, +- struct sdap_attr_map *map, +- char **_usn) +-{ +- const char *usn; +- errno_t ret; +- +- if (_usn == NULL) { +- return EINVAL; +- } +- +- ret = sysdb_attrs_get_string(attrs, map[SDAP_AT_SUDO_USN].sys_name, &usn); +- if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, +- "Failed to retrieve USN value: [%s]\n", strerror(ret)); +- +- return ret; +- } +- +- *_usn = talloc_strdup(mem_ctx, usn); +- if (*_usn == NULL) { +- return ENOMEM; +- } +- +- return EOK; +-} +- +-static errno_t +-sdap_save_native_sudorule(TALLOC_CTX *mem_ctx, +- struct sss_domain_info *domain, +- struct sdap_attr_map *map, +- struct sysdb_attrs *attrs, +- int cache_timeout, +- time_t now, +- char **_usn) +-{ +- errno_t ret; +- const char *rule_name; +- +- ret = sysdb_attrs_get_string(attrs, map[SDAP_AT_SUDO_NAME].sys_name, +- &rule_name); +- if (ret == ERANGE) { +- DEBUG(SSSDBG_OP_FAILURE, "Warning: found rule that contains none " +- "or multiple CN values. It will be skipped.\n"); +- return ret; +- } else if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "Could not get rule name [%d]: %s\n", +- ret, strerror(ret)); +- return ret; +- } +- +- ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE, +- (cache_timeout ? (now + cache_timeout) : 0)); +- if (ret) { +- DEBUG(SSSDBG_OP_FAILURE, "Could not set sysdb cache expire [%d]: %s\n", +- ret, strerror(ret)); +- return ret; +- } +- +- ret = sdap_sudo_get_usn(mem_ctx, attrs, map, _usn); +- if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, "Could not read USN from %s\n", rule_name); +- *_usn = NULL; +- /* but we will store the rule anyway */ +- } +- +- ret = sysdb_save_sudorule(domain, rule_name, attrs); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "Could not save sudorule %s\n", rule_name); +- return ret; +- } +- +- return ret; +-} +- +-errno_t +-sdap_save_native_sudorule_list(TALLOC_CTX *mem_ctx, +- struct sss_domain_info *domain, +- struct sdap_attr_map *map, +- struct sysdb_attrs **replies, +- size_t replies_count, +- int cache_timeout, +- time_t now, +- char **_usn) +-{ +- TALLOC_CTX *tmp_ctx = NULL; +- char *higher_usn = NULL; +- char *usn_value = NULL; +- errno_t ret, tret; +- bool in_transaction = false; +- size_t i; +- +- tmp_ctx = talloc_new(NULL); +- if (tmp_ctx == NULL) { +- DEBUG(SSSDBG_FATAL_FAILURE, "talloc_new() failed\n"); +- return ENOMEM; +- } +- +- ret = sysdb_transaction_start(domain->sysdb); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Could not start transaction\n"); +- goto fail; +- } +- in_transaction = true; +- +- for (i=0; i < replies_count; i++) { +- usn_value = NULL; +- ret = sdap_save_native_sudorule(tmp_ctx, domain, map, replies[i], +- cache_timeout, now, &usn_value); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to save sudo rule, " +- "will continue with next...\n"); +- continue; +- } +- +- /* find highest usn */ +- if (usn_value) { +- if (higher_usn) { +- if ((strlen(usn_value) > strlen(higher_usn)) || +- (strcmp(usn_value, higher_usn) > 0)) { +- talloc_zfree(higher_usn); +- higher_usn = usn_value; +- } else { +- talloc_zfree(usn_value); +- } +- } else { +- higher_usn = usn_value; +- } +- } +- } +- +- ret = sysdb_transaction_commit(domain->sysdb); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n"); +- goto fail; +- } +- in_transaction = false; +- +- if (higher_usn != NULL) { +- *_usn = talloc_steal(mem_ctx, higher_usn); +- } +- +- ret = EOK; +-fail: +- if (in_transaction) { +- tret = sysdb_transaction_cancel(domain->sysdb); +- if (tret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n"); +- } +- } +- +- talloc_free(tmp_ctx); +- +- return ret; +-} +diff --git a/src/providers/ldap/sdap_sudo_cache.h b/src/providers/ldap/sdap_sudo_cache.h +deleted file mode 100644 +index 5a756bf313831267cf34676b392973a1a8e740ec..0000000000000000000000000000000000000000 +--- a/src/providers/ldap/sdap_sudo_cache.h ++++ /dev/null +@@ -1,37 +0,0 @@ +-/* +- Authors: +- Jakub Hrozek +- +- Copyright (C) 2011 Red Hat +- +- This program is free software; you can redistribute it and/or modify +- it under the terms of the GNU General Public License as published by +- the Free Software Foundation; either version 3 of the License, or +- (at your option) any later version. +- +- This program is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- GNU General Public License for more details. +- +- You should have received a copy of the GNU General Public License +- along with this program. If not, see . +-*/ +- +-#ifndef _SDAP_SUDO_CACHE_H_ +-#define _SDAP_SUDO_CACHE_H_ +- +-#include "src/providers/ldap/sdap.h" +- +-/* Cache functions specific for the native sudo LDAP schema */ +-errno_t +-sdap_save_native_sudorule_list(TALLOC_CTX *mem_ctx, +- struct sss_domain_info *domain, +- struct sdap_attr_map *map, +- struct sysdb_attrs **replies, +- size_t replies_count, +- int cache_timeout, +- time_t now, +- char **_usn); +- +-#endif /* _SDAP_SUDO_CACHE_H_ */ +-- +2.5.0 + diff --git a/0017-SUDO-move-code-shared-between-ldap-and-ipa-to-separa.patch b/0017-SUDO-move-code-shared-between-ldap-and-ipa-to-separa.patch new file mode 100644 index 0000000..27cd670 --- /dev/null +++ b/0017-SUDO-move-code-shared-between-ldap-and-ipa-to-separa.patch @@ -0,0 +1,394 @@ +From 95653f8aa03f44fff011ac1c04c1dac8b460687c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 17 Dec 2015 13:24:39 +0100 +Subject: [PATCH 17/49] SUDO: move code shared between ldap and ipa to separate + module + +Reviewed-by: Sumit Bose +(cherry picked from commit 85feb8d77a2c832787880944e02104846c4d5376) +--- + Makefile.am | 2 + + src/providers/ldap/sdap_async_sudo.c | 31 +------ + src/providers/ldap/sdap_sudo_refresh.c | 87 ++----------------- + src/providers/ldap/sdap_sudo_shared.c | 149 +++++++++++++++++++++++++++++++++ + src/providers/ldap/sdap_sudo_shared.h | 40 +++++++++ + 5 files changed, 199 insertions(+), 110 deletions(-) + create mode 100644 src/providers/ldap/sdap_sudo_shared.c + create mode 100644 src/providers/ldap/sdap_sudo_shared.h + +diff --git a/Makefile.am b/Makefile.am +index 29dd73edf3e6770e4280945f69c9d266f3d8c4c4..8b57640cacd0e1f30f3d1270a92521c55ba0e026 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -619,6 +619,7 @@ dist_noinst_HEADERS = \ + src/providers/ldap/sdap_async.h \ + src/providers/ldap/sdap_async_private.h \ + src/providers/ldap/sdap_sudo.h \ ++ src/providers/ldap/sdap_sudo_shared.h \ + src/providers/ldap/sdap_autofs.h \ + src/providers/ldap/sdap_id_op.h \ + src/providers/ldap/ldap_opts.h \ +@@ -2861,6 +2862,7 @@ libsss_ldap_common_la_SOURCES += \ + src/providers/ldap/sdap_async_sudo.c \ + src/providers/ldap/sdap_async_sudo_hostinfo.c \ + src/providers/ldap/sdap_sudo_refresh.c \ ++ src/providers/ldap/sdap_sudo_shared.c \ + src/providers/ldap/sdap_sudo.c + endif + +diff --git a/src/providers/ldap/sdap_async_sudo.c b/src/providers/ldap/sdap_async_sudo.c +index 2fcfa4aec5d4d53f26d40395e99bdce1b41710d4..d26d00f47a5c1fa02705a09c1d3ce02a4d5788a8 100644 +--- a/src/providers/ldap/sdap_async_sudo.c ++++ b/src/providers/ldap/sdap_async_sudo.c +@@ -31,6 +31,7 @@ + #include "providers/ldap/sdap.h" + #include "providers/ldap/sdap_ops.h" + #include "providers/ldap/sdap_sudo.h" ++#include "providers/ldap/sdap_sudo_shared.h" + #include "db/sysdb_sudo.h" + + struct sdap_sudo_load_sudoers_state { +@@ -135,36 +136,6 @@ static int sdap_sudo_load_sudoers_recv(struct tevent_req *req, + return EOK; + } + +-static void sdap_sudo_set_usn(struct sdap_server_opts *srv_opts, char *usn) +-{ +- unsigned int usn_number; +- char *endptr = NULL; +- +- if (srv_opts == NULL) { +- DEBUG(SSSDBG_TRACE_FUNC, "Bug: srv_opts is NULL\n"); +- return; +- } +- +- if (usn == NULL) { +- DEBUG(SSSDBG_TRACE_FUNC, "Bug: usn is NULL\n"); +- return; +- } +- +- if (sysdb_compare_usn(usn, srv_opts->max_sudo_value) > 0) { +- talloc_zfree(srv_opts->max_sudo_value); +- srv_opts->max_sudo_value = talloc_steal(srv_opts, usn); +- } +- +- usn_number = strtoul(usn, &endptr, 10); +- if ((endptr == NULL || (*endptr == '\0' && endptr != usn)) +- && (usn_number > srv_opts->last_usn)) { +- srv_opts->last_usn = usn_number; +- } +- +- DEBUG(SSSDBG_FUNC_DATA, "SUDO higher USN value: [%s]\n", +- srv_opts->max_sudo_value); +-} +- + static char *sdap_sudo_build_host_filter(TALLOC_CTX *mem_ctx, + struct sdap_attr_map *map, + char **hostnames, +diff --git a/src/providers/ldap/sdap_sudo_refresh.c b/src/providers/ldap/sdap_sudo_refresh.c +index e3df8f1c5071518af1d1f10cf0e3a19301f78640..5697818ce71240468d2bcaa8af7994ca6b8ea3ef 100644 +--- a/src/providers/ldap/sdap_sudo_refresh.c ++++ b/src/providers/ldap/sdap_sudo_refresh.c +@@ -25,6 +25,7 @@ + #include "util/util.h" + #include "providers/dp_ptask.h" + #include "providers/ldap/sdap_sudo.h" ++#include "providers/ldap/sdap_sudo_shared.h" + #include "db/sysdb_sudo.h" + + struct sdap_sudo_full_refresh_state { +@@ -469,84 +470,10 @@ sdap_sudo_ptask_smart_refresh_recv(struct tevent_req *req) + errno_t + sdap_sudo_ptask_setup(struct be_ctx *be_ctx, struct sdap_sudo_ctx *sudo_ctx) + { +- struct dp_option *opts = sudo_ctx->id_ctx->opts->basic; +- time_t smart; +- time_t full; +- time_t delay; +- time_t last_refresh; +- errno_t ret; +- +- smart = dp_opt_get_int(opts, SDAP_SUDO_SMART_REFRESH_INTERVAL); +- full = dp_opt_get_int(opts, SDAP_SUDO_FULL_REFRESH_INTERVAL); +- +- if (smart == 0 && full == 0) { +- /* We don't allow both types to be disabled. At least smart refresh +- * needs to be enabled. In this case smart refresh will catch up new +- * and modified rules and deleted rules are caught when expired. */ +- smart = opts[SDAP_SUDO_SMART_REFRESH_INTERVAL].def_val.number; +- +- DEBUG(SSSDBG_CONF_SETTINGS, "At least smart refresh needs to be " +- "enabled. Setting smart refresh interval to default value " +- "(%ld) seconds.\n", smart); +- } else if (full <= smart) { +- /* In this case it does not make any sense to run smart refresh. */ +- smart = 0; +- +- DEBUG(SSSDBG_CONF_SETTINGS, "Smart refresh interval has to be lower " +- "than full refresh interval. Periodical smart refresh will be " +- "disabled.\n"); +- } +- +- ret = sysdb_sudo_get_last_full_refresh(be_ctx->domain, &last_refresh); +- if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, "Unable to obtain time of last full " +- "refresh. Assuming none was performed so far.\n"); +- last_refresh = 0; +- } +- +- if (last_refresh == 0) { +- /* If this is the first startup, we need to kick off an refresh +- * immediately, to close a window where clients requesting sudo +- * information won't get an immediate reply with no entries */ +- delay = 0; +- } else { +- /* At least one update has previously run, so clients will get cached +- * data. We will delay the refresh so we don't slow down the startup +- * process if this is happening during system boot. */ +- delay = 10; +- } +- +- /* Full refresh. +- * +- * Disable when offline and run immediately when SSSD goes back online. +- * Since we have periodical online check we don't have to run this task +- * when offline. */ +- ret = be_ptask_create(be_ctx, be_ctx, full, delay, 0, 0, full, +- BE_PTASK_OFFLINE_DISABLE, 0, +- sdap_sudo_ptask_full_refresh_send, +- sdap_sudo_ptask_full_refresh_recv, +- sudo_ctx, "SUDO Full Refresh", NULL); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup full refresh ptask " +- "[%d]: %s\n", ret, sss_strerror(ret)); +- return ret; +- } +- +- /* Smart refresh. +- * +- * Disable when offline and reschedule normally when SSSD goes back online. +- * Since we have periodical online check we don't have to run this task +- * when offline. */ +- ret = be_ptask_create(be_ctx, be_ctx, smart, delay + smart, smart, 0, smart, +- BE_PTASK_OFFLINE_DISABLE, 0, +- sdap_sudo_ptask_smart_refresh_send, +- sdap_sudo_ptask_smart_refresh_recv, +- sudo_ctx, "SUDO Smart Refresh", NULL); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup smart refresh ptask " +- "[%d]: %s\n", ret, sss_strerror(ret)); +- return ret; +- } +- +- return EOK; ++ return sdap_sudo_ptask_setup_generic(be_ctx, sudo_ctx->id_ctx->opts->basic, ++ sdap_sudo_ptask_full_refresh_send, ++ sdap_sudo_ptask_full_refresh_recv, ++ sdap_sudo_ptask_smart_refresh_send, ++ sdap_sudo_ptask_smart_refresh_recv, ++ sudo_ctx); + } +diff --git a/src/providers/ldap/sdap_sudo_shared.c b/src/providers/ldap/sdap_sudo_shared.c +new file mode 100644 +index 0000000000000000000000000000000000000000..86a6acf4758a1d5952f28cf1847a425d1b3b40ec +--- /dev/null ++++ b/src/providers/ldap/sdap_sudo_shared.c +@@ -0,0 +1,149 @@ ++/* ++ Authors: ++ Pavel Březina ++ ++ Copyright (C) 2015 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#include ++#include ++#include ++ ++#include "util/util.h" ++#include "providers/dp_ptask.h" ++#include "providers/ldap/sdap.h" ++#include "providers/ldap/sdap_sudo_shared.h" ++#include "db/sysdb_sudo.h" ++ ++errno_t ++sdap_sudo_ptask_setup_generic(struct be_ctx *be_ctx, ++ struct dp_option *opts, ++ be_ptask_send_t full_send_fn, ++ be_ptask_recv_t full_recv_fn, ++ be_ptask_send_t smart_send_fn, ++ be_ptask_recv_t smart_recv_fn, ++ void *pvt) ++{ ++ time_t smart; ++ time_t full; ++ time_t delay; ++ time_t last_refresh; ++ errno_t ret; ++ ++ smart = dp_opt_get_int(opts, SDAP_SUDO_SMART_REFRESH_INTERVAL); ++ full = dp_opt_get_int(opts, SDAP_SUDO_FULL_REFRESH_INTERVAL); ++ ++ if (smart == 0 && full == 0) { ++ /* We don't allow both types to be disabled. At least smart refresh ++ * needs to be enabled. In this case smart refresh will catch up new ++ * and modified rules and deleted rules are caught when expired. */ ++ smart = opts[SDAP_SUDO_SMART_REFRESH_INTERVAL].def_val.number; ++ ++ DEBUG(SSSDBG_CONF_SETTINGS, "At least smart refresh needs to be " ++ "enabled. Setting smart refresh interval to default value " ++ "(%ld) seconds.\n", smart); ++ } else if (full <= smart) { ++ /* In this case it does not make any sense to run smart refresh. */ ++ smart = 0; ++ ++ DEBUG(SSSDBG_CONF_SETTINGS, "Smart refresh interval has to be lower " ++ "than full refresh interval. Periodical smart refresh will be " ++ "disabled.\n"); ++ } ++ ++ ret = sysdb_sudo_get_last_full_refresh(be_ctx->domain, &last_refresh); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Unable to obtain time of last full " ++ "refresh. Assuming none was performed so far.\n"); ++ last_refresh = 0; ++ } ++ ++ if (last_refresh == 0) { ++ /* If this is the first startup, we need to kick off an refresh ++ * immediately, to close a window where clients requesting sudo ++ * information won't get an immediate reply with no entries */ ++ delay = 0; ++ } else { ++ /* At least one update has previously run, so clients will get cached ++ * data. We will delay the refresh so we don't slow down the startup ++ * process if this is happening during system boot. */ ++ delay = 10; ++ } ++ ++ /* Full refresh. ++ * ++ * Disable when offline and run immediately when SSSD goes back online. ++ * Since we have periodical online check we don't have to run this task ++ * when offline. */ ++ ret = be_ptask_create(be_ctx, be_ctx, full, delay, 0, 0, full, ++ BE_PTASK_OFFLINE_DISABLE, 0, ++ full_send_fn, full_recv_fn, pvt, ++ "SUDO Full Refresh", NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup full refresh ptask " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ return ret; ++ } ++ ++ /* Smart refresh. ++ * ++ * Disable when offline and reschedule normally when SSSD goes back online. ++ * Since we have periodical online check we don't have to run this task ++ * when offline. */ ++ ret = be_ptask_create(be_ctx, be_ctx, smart, delay + smart, smart, 0, smart, ++ BE_PTASK_OFFLINE_DISABLE, 0, ++ smart_send_fn, smart_recv_fn, pvt, ++ "SUDO Smart Refresh", NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup smart refresh ptask " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ return ret; ++ } ++ ++ return EOK; ++} ++ ++void ++sdap_sudo_set_usn(struct sdap_server_opts *srv_opts, ++ char *usn) ++{ ++ unsigned int usn_number; ++ char *endptr = NULL; ++ ++ if (srv_opts == NULL) { ++ DEBUG(SSSDBG_TRACE_FUNC, "Bug: srv_opts is NULL\n"); ++ return; ++ } ++ ++ if (usn == NULL) { ++ DEBUG(SSSDBG_TRACE_FUNC, "Bug: usn is NULL\n"); ++ return; ++ } ++ ++ if (sysdb_compare_usn(usn, srv_opts->max_sudo_value) > 0) { ++ talloc_zfree(srv_opts->max_sudo_value); ++ srv_opts->max_sudo_value = talloc_steal(srv_opts, usn); ++ } ++ ++ usn_number = strtoul(usn, &endptr, 10); ++ if ((endptr == NULL || (*endptr == '\0' && endptr != usn)) ++ && (usn_number > srv_opts->last_usn)) { ++ srv_opts->last_usn = usn_number; ++ } ++ ++ DEBUG(SSSDBG_FUNC_DATA, "SUDO higher USN value: [%s]\n", ++ srv_opts->max_sudo_value); ++} +diff --git a/src/providers/ldap/sdap_sudo_shared.h b/src/providers/ldap/sdap_sudo_shared.h +new file mode 100644 +index 0000000000000000000000000000000000000000..bbc6927250cf8a9b4a92eb15bad6c718c76e2f70 +--- /dev/null ++++ b/src/providers/ldap/sdap_sudo_shared.h +@@ -0,0 +1,40 @@ ++/* ++ Authors: ++ Pavel Březina ++ ++ Copyright (C) 2015 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#ifndef _SDAP_SUDO_SHARED_H_ ++#define _SDAP_SUDO_SHARED_H_ ++ ++#include "providers/dp_backend.h" ++#include "providers/dp_ptask.h" ++ ++errno_t ++sdap_sudo_ptask_setup_generic(struct be_ctx *be_ctx, ++ struct dp_option *opts, ++ be_ptask_send_t full_send_fn, ++ be_ptask_recv_t full_recv_fn, ++ be_ptask_send_t smart_send_fn, ++ be_ptask_recv_t smart_recv_fn, ++ void *pvt); ++ ++void ++sdap_sudo_set_usn(struct sdap_server_opts *srv_opts, ++ char *usn); ++ ++#endif /* _SDAP_SUDO_SHARED_H_ */ +-- +2.5.0 + diff --git a/0018-SUDO-allow-to-disable-ptask.patch b/0018-SUDO-allow-to-disable-ptask.patch new file mode 100644 index 0000000..682e08f --- /dev/null +++ b/0018-SUDO-allow-to-disable-ptask.patch @@ -0,0 +1,68 @@ +From ccf6c568a0bb4a3660297653d96c7fb311b6665f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 18 Dec 2015 11:50:09 +0100 +Subject: [PATCH 18/49] SUDO: allow to disable ptask + +Reviewed-by: Sumit Bose +(cherry picked from commit e085a79acfcd5331b6f99748e21765579a9a99f2) +--- + src/providers/ldap/sdap_sudo_shared.c | 36 +++++++++++++++++++---------------- + 1 file changed, 20 insertions(+), 16 deletions(-) + +diff --git a/src/providers/ldap/sdap_sudo_shared.c b/src/providers/ldap/sdap_sudo_shared.c +index 86a6acf4758a1d5952f28cf1847a425d1b3b40ec..b31d5d27f61b73e71ab8ad0341415ee00e2295cf 100644 +--- a/src/providers/ldap/sdap_sudo_shared.c ++++ b/src/providers/ldap/sdap_sudo_shared.c +@@ -88,14 +88,16 @@ sdap_sudo_ptask_setup_generic(struct be_ctx *be_ctx, + * Disable when offline and run immediately when SSSD goes back online. + * Since we have periodical online check we don't have to run this task + * when offline. */ +- ret = be_ptask_create(be_ctx, be_ctx, full, delay, 0, 0, full, +- BE_PTASK_OFFLINE_DISABLE, 0, +- full_send_fn, full_recv_fn, pvt, +- "SUDO Full Refresh", NULL); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup full refresh ptask " +- "[%d]: %s\n", ret, sss_strerror(ret)); +- return ret; ++ if (full > 0) { ++ ret = be_ptask_create(be_ctx, be_ctx, full, delay, 0, 0, full, ++ BE_PTASK_OFFLINE_DISABLE, 0, ++ full_send_fn, full_recv_fn, pvt, ++ "SUDO Full Refresh", NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup full refresh ptask " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ return ret; ++ } + } + + /* Smart refresh. +@@ -103,14 +105,16 @@ sdap_sudo_ptask_setup_generic(struct be_ctx *be_ctx, + * Disable when offline and reschedule normally when SSSD goes back online. + * Since we have periodical online check we don't have to run this task + * when offline. */ +- ret = be_ptask_create(be_ctx, be_ctx, smart, delay + smart, smart, 0, smart, +- BE_PTASK_OFFLINE_DISABLE, 0, +- smart_send_fn, smart_recv_fn, pvt, +- "SUDO Smart Refresh", NULL); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup smart refresh ptask " +- "[%d]: %s\n", ret, sss_strerror(ret)); +- return ret; ++ if (smart > 0) { ++ ret = be_ptask_create(be_ctx, be_ctx, smart, delay + smart, smart, 0, ++ smart, BE_PTASK_OFFLINE_DISABLE, 0, ++ smart_send_fn, smart_recv_fn, pvt, ++ "SUDO Smart Refresh", NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup smart refresh ptask " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ return ret; ++ } + } + + return EOK; +-- +2.5.0 + diff --git a/0019-SUDO-fail-on-failed-request-that-cannot-be-retry.patch b/0019-SUDO-fail-on-failed-request-that-cannot-be-retry.patch new file mode 100644 index 0000000..7f8efe8 --- /dev/null +++ b/0019-SUDO-fail-on-failed-request-that-cannot-be-retry.patch @@ -0,0 +1,28 @@ +From 3571ecfed9d76240324f881c7d1faaf62fa2798c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 18 Dec 2015 12:45:53 +0100 +Subject: [PATCH 19/49] SUDO: fail on failed request that cannot be retry + +Reviewed-by: Sumit Bose +(cherry picked from commit cad751beaa12e34e15565bc413442b1e80ac0c29) +--- + src/providers/ldap/sdap_async_sudo.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/providers/ldap/sdap_async_sudo.c b/src/providers/ldap/sdap_async_sudo.c +index d26d00f47a5c1fa02705a09c1d3ce02a4d5788a8..e3f3da186181a5f3ffbe818073cdbdca1112857a 100644 +--- a/src/providers/ldap/sdap_async_sudo.c ++++ b/src/providers/ldap/sdap_async_sudo.c +@@ -518,6 +518,9 @@ static void sdap_sudo_refresh_done(struct tevent_req *subreq) + tevent_req_error(req, ret); + } + return; ++ } else if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Received %zu rules\n", rules_count); +-- +2.5.0 + diff --git a/0020-IPA-add-ipa_get_rdn-and-ipa_check_rdn.patch b/0020-IPA-add-ipa_get_rdn-and-ipa_check_rdn.patch new file mode 100644 index 0000000..8287d1a --- /dev/null +++ b/0020-IPA-add-ipa_get_rdn-and-ipa_check_rdn.patch @@ -0,0 +1,510 @@ +From 51e5796950c7e429838d7283441af63171339657 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 10 Dec 2015 14:08:52 +0100 +Subject: [PATCH 20/49] IPA: add ipa_get_rdn and ipa_check_rdn + +To exploit knowledge of IPA LDAP hierarchy. + +Reviewed-by: Sumit Bose +(cherry picked from commit b407fe0474a674bb42f0f42ab47c7f530a07a367) +--- + Makefile.am | 22 ++++ + src/providers/ipa/ipa_dn.c | 145 ++++++++++++++++++++++++++ + src/providers/ipa/ipa_dn.h | 43 ++++++++ + src/tests/cmocka/test_ipa_dn.c | 228 +++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 438 insertions(+) + create mode 100644 src/providers/ipa/ipa_dn.c + create mode 100644 src/providers/ipa/ipa_dn.h + create mode 100644 src/tests/cmocka/test_ipa_dn.c + +diff --git a/Makefile.am b/Makefile.am +index 8b57640cacd0e1f30f3d1270a92521c55ba0e026..6efb5ea7f81642292b39a44e7e2029a2757e47ea 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -245,6 +245,7 @@ if HAVE_CMOCKA + test_cert_utils \ + test_ldap_id_cleanup \ + test_data_provider_be \ ++ test_ipa_dn \ + $(NULL) + + if HAVE_LIBRESOLV +@@ -642,6 +643,7 @@ dist_noinst_HEADERS = \ + src/providers/ipa/ipa_hostid.h \ + src/providers/ipa/ipa_opts.h \ + src/providers/ipa/ipa_srv.h \ ++ src/providers/ipa/ipa_dn.h \ + src/providers/ad/ad_srv.h \ + src/providers/proxy/proxy.h \ + src/tools/tools_util.h \ +@@ -2631,6 +2633,25 @@ test_data_provider_be_LDADD = \ + libdlopen_test_providers.la \ + $(NULL) + ++test_ipa_dn_SOURCES = \ ++ src/providers/ipa/ipa_dn.c \ ++ src/tests/cmocka/test_ipa_dn.c \ ++ $(NULL) ++test_ipa_dn_CFLAGS = \ ++ $(AM_CFLAGS) \ ++ -DUNIT_TESTING \ ++ $(NULL) ++test_ipa_dn_LDFLAGS = \ ++ -Wl,-wrap,_tevent_add_timer \ ++ $(NULL) ++test_ipa_dn_LDADD = \ ++ $(CMOCKA_LIBS) \ ++ $(SSSD_LIBS) \ ++ $(SSSD_INTERNAL_LTLIBS) \ ++ $(LIBADD_DL) \ ++ libsss_test_common.la \ ++ $(NULL) ++ + endif # HAVE_CMOCKA + + noinst_PROGRAMS = pam_test_client +@@ -2983,6 +3004,7 @@ libsss_ipa_la_SOURCES = \ + src/providers/ipa/ipa_selinux_maps.c \ + src/providers/ipa/ipa_srv.c \ + src/providers/ipa/ipa_idmap.c \ ++ src/providers/ipa/ipa_dn.c \ + src/providers/ad/ad_opts.c \ + src/providers/ad/ad_common.c \ + src/providers/ad/ad_common.h \ +diff --git a/src/providers/ipa/ipa_dn.c b/src/providers/ipa/ipa_dn.c +new file mode 100644 +index 0000000000000000000000000000000000000000..c58e014f8c83d39f2c558449702a02dc6fdb0713 +--- /dev/null ++++ b/src/providers/ipa/ipa_dn.c +@@ -0,0 +1,145 @@ ++/* ++ Authors: ++ Pavel Březina ++ ++ Copyright (C) 2015 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#include ++#include ++#include "db/sysdb.h" ++#include "providers/ipa/ipa_dn.h" ++ ++static bool check_dn(struct ldb_dn *dn, ++ const char *rdn_attr, ++ va_list in_ap) ++{ ++ const struct ldb_val *ldbval; ++ const char *strval; ++ const char *ldbattr; ++ const char *attr; ++ const char *val; ++ va_list ap; ++ int num_comp; ++ int comp; ++ ++ /* check RDN attribute */ ++ ldbattr = ldb_dn_get_rdn_name(dn); ++ if (ldbattr == NULL || strcasecmp(ldbattr, rdn_attr) != 0) { ++ return false; ++ } ++ ++ /* Check DN components. First we check if all attr=value pairs match input. ++ * Then we check that the next attribute is a domain component. ++ */ ++ ++ comp = 1; ++ num_comp = ldb_dn_get_comp_num(dn); ++ ++ va_copy(ap, in_ap); ++ while ((attr = va_arg(ap, const char *)) != NULL) { ++ val = va_arg(ap, const char *); ++ if (val == NULL) { ++ goto vafail; ++ } ++ ++ if (comp > num_comp) { ++ goto vafail; ++ } ++ ++ ldbattr = ldb_dn_get_component_name(dn, comp); ++ if (ldbattr == NULL || strcasecmp(ldbattr, attr) != 0) { ++ goto vafail; ++ } ++ ++ ldbval = ldb_dn_get_component_val(dn, comp); ++ if (ldbval == NULL) { ++ goto vafail; ++ } ++ ++ strval = (const char *)ldbval->data; ++ if (strval == NULL || strncasecmp(strval, val, ldbval->length) != 0) { ++ goto vafail; ++ } ++ ++ comp++; ++ } ++ va_end(ap); ++ ++ ldbattr = ldb_dn_get_component_name(dn, comp); ++ if (ldbattr == NULL || strcmp(ldbattr, "dc") != 0) { ++ return false; ++ } ++ ++ return true; ++ ++vafail: ++ va_end(ap); ++ return false; ++} ++ ++errno_t _ipa_get_rdn(TALLOC_CTX *mem_ctx, ++ struct sysdb_ctx *sysdb, ++ const char *obj_dn, ++ char **_rdn_val, ++ const char *rdn_attr, ++ ...) ++{ ++ const struct ldb_val *val; ++ struct ldb_dn *dn; ++ errno_t ret; ++ bool bret; ++ va_list ap; ++ char *rdn; ++ ++ dn = ldb_dn_new(mem_ctx, sysdb_ctx_get_ldb(sysdb), obj_dn); ++ if (dn == NULL) { ++ return ENOMEM; ++ } ++ ++ va_start(ap, rdn_attr); ++ bret = check_dn(dn, rdn_attr, ap); ++ va_end(ap); ++ if (bret == false) { ++ ret = ENOENT; ++ goto done; ++ } ++ ++ if (_rdn_val == NULL) { ++ ret = EOK; ++ goto done; ++ } ++ ++ val = ldb_dn_get_rdn_val(dn); ++ if (val == NULL || val->data == NULL) { ++ ret = EINVAL; ++ goto done; ++ } ++ ++ rdn = talloc_strndup(mem_ctx, (const char*)val->data, val->length); ++ if (rdn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ *_rdn_val = rdn; ++ ++ ret = EOK; ++ ++done: ++ talloc_free(dn); ++ return ret; ++} +diff --git a/src/providers/ipa/ipa_dn.h b/src/providers/ipa/ipa_dn.h +new file mode 100644 +index 0000000000000000000000000000000000000000..f889c3ee6548c6d4cf719441bbe2f0c7caa1a579 +--- /dev/null ++++ b/src/providers/ipa/ipa_dn.h +@@ -0,0 +1,43 @@ ++/* ++ Authors: ++ Pavel Březina ++ ++ Copyright (C) 2015 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#ifndef IPA_DN_H_ ++#define IPA_DN_H_ ++ ++#include ++#include "db/sysdb.h" ++ ++errno_t _ipa_get_rdn(TALLOC_CTX *mem_ctx, ++ struct sysdb_ctx *sysdb, ++ const char *obj_dn, ++ char **_rdn_val, ++ const char *rdn_attr, ++ ...); ++ ++#define ipa_get_rdn(mem_ctx, sysdb, dn, _rdn_val, rdn_attr, ...) \ ++ _ipa_get_rdn(mem_ctx, sysdb, dn, _rdn_val, rdn_attr, ##__VA_ARGS__, NULL) ++ ++#define ipa_check_rdn(sysdb, dn, rdn_attr, ...) \ ++ _ipa_get_rdn(NULL, sysdb, dn, NULL, rdn_attr, ##__VA_ARGS__, NULL) ++ ++#define ipa_check_rdn_bool(sysdb, dn, rdn_attr, ...) \ ++ ((bool)(ipa_check_rdn(sysdb, dn, rdn_attr, ##__VA_ARGS__) == EOK)) ++ ++#endif /* IPA_DN_H_ */ +diff --git a/src/tests/cmocka/test_ipa_dn.c b/src/tests/cmocka/test_ipa_dn.c +new file mode 100644 +index 0000000000000000000000000000000000000000..a6e26ec31ff25519ad895ef934dac0e3a3dd83ae +--- /dev/null ++++ b/src/tests/cmocka/test_ipa_dn.c +@@ -0,0 +1,228 @@ ++/* ++ Authors: ++ Pavel Březina ++ ++ Copyright (C) 2015 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#include ++#include ++#include ++ ++#include "tests/cmocka/common_mock.h" ++#include "providers/ipa/ipa_dn.h" ++ ++#define TESTS_PATH "tp_" BASE_FILE_STEM ++#define TEST_CONF_DB "test_ipa_dn_conf.ldb" ++#define TEST_DOM_NAME "ipa_dn_test" ++#define TEST_ID_PROVIDER "ipa" ++ ++struct ipa_dn_test_ctx { ++ struct sss_test_ctx *tctx; ++ struct sysdb_ctx *sysdb; ++}; ++ ++static int ipa_dn_test_setup(void **state) ++{ ++ struct ipa_dn_test_ctx *test_ctx = NULL; ++ ++ test_ctx = talloc_zero(NULL, struct ipa_dn_test_ctx); ++ assert_non_null(test_ctx); ++ *state = test_ctx; ++ ++ /* initialize domain */ ++ test_ctx->tctx = create_dom_test_ctx(test_ctx, TESTS_PATH, TEST_CONF_DB, ++ TEST_DOM_NAME, ++ TEST_ID_PROVIDER, NULL); ++ assert_non_null(test_ctx->tctx); ++ ++ test_ctx->sysdb = test_ctx->tctx->sysdb; ++ ++ return 0; ++} ++ ++static int ipa_dn_test_teardown(void **state) ++{ ++ talloc_zfree(*state); ++ return 0; ++} ++ ++static void ipa_check_rdn_test(void **state) ++{ ++ struct ipa_dn_test_ctx *test_ctx = NULL; ++ errno_t ret; ++ ++ test_ctx = talloc_get_type_abort(*state, struct ipa_dn_test_ctx); ++ ++ ret = ipa_check_rdn(test_ctx->sysdb, "cn=rdn,dc=example,dc=com", "cn"); ++ assert_int_equal(ret, EOK); ++ ++ ret = ipa_check_rdn(test_ctx->sysdb, "cn=rdn,attr1=value1,dc=example,dc=com", "cn", "attr1", "value1"); ++ assert_int_equal(ret, EOK); ++ ++ ret = ipa_check_rdn(test_ctx->sysdb, "cn=rdn,attr1=value1,attr2=value2,dc=example,dc=com", "cn", "attr1", "value1", "attr2", "value2"); ++ assert_int_equal(ret, EOK); ++ ++ ret = ipa_check_rdn(test_ctx->sysdb, "cn=rdn,dc=example,dc=com", "nope"); ++ assert_int_equal(ret, ENOENT); ++ ++ ret = ipa_check_rdn(test_ctx->sysdb, "cn=rdn,attr1=value1,dc=example,dc=com", "cn", "nope", "value1"); ++ assert_int_equal(ret, ENOENT); ++ ++ ret = ipa_check_rdn(test_ctx->sysdb, "cn=rdn,attr1=value1,attr2=value2,dc=example,dc=com", "cn", "attr1", "nope"); ++ assert_int_equal(ret, ENOENT); ++ ++ ret = ipa_check_rdn(test_ctx->sysdb, "cn=rdn,attr1=value1,dc=example,dc=com", "cn", "attr1"); ++ assert_int_equal(ret, ENOENT); ++ ++ ret = ipa_check_rdn(test_ctx->sysdb, "cn=rdn,attr1=value1", "cn", "attr1", "value1"); ++ assert_int_equal(ret, ENOENT); ++} ++ ++static void ipa_check_rdn_bool_test(void **state) ++{ ++ struct ipa_dn_test_ctx *test_ctx = NULL; ++ bool bret; ++ ++ test_ctx = talloc_get_type_abort(*state, struct ipa_dn_test_ctx); ++ ++ bret = ipa_check_rdn_bool(test_ctx->sysdb, "cn=rdn,dc=example,dc=com", "cn"); ++ assert_true(bret); ++ ++ bret = ipa_check_rdn_bool(test_ctx->sysdb, "cn=rdn,attr1=value1,dc=example,dc=com", "cn", "attr1", "value1"); ++ assert_true(bret); ++ ++ bret = ipa_check_rdn_bool(test_ctx->sysdb, "cn=rdn,attr1=value1,attr2=value2,dc=example,dc=com", "cn", "attr1", "value1", "attr2", "value2"); ++ assert_true(bret); ++ ++ bret = ipa_check_rdn_bool(test_ctx->sysdb, "cn=rdn,dc=example,dc=com", "nope"); ++ assert_false(bret); ++ ++ bret = ipa_check_rdn_bool(test_ctx->sysdb, "cn=rdn,attr1=value1,dc=example,dc=com", "cn", "nope", "value1"); ++ assert_false(bret); ++ ++ bret = ipa_check_rdn_bool(test_ctx->sysdb, "cn=rdn,attr1=value1,attr2=value2,dc=example,dc=com", "cn", "attr1", "nope"); ++ assert_false(bret); ++ ++ bret = ipa_check_rdn_bool(test_ctx->sysdb, "cn=rdn,attr1=value1,dc=example,dc=com", "cn", "attr1"); ++ assert_false(bret); ++ ++ bret = ipa_check_rdn_bool(test_ctx->sysdb, "cn=rdn,attr1=value1", "cn", "attr1", "value1"); ++ assert_false(bret); ++} ++ ++static void ipa_get_rdn_test(void **state) ++{ ++ struct ipa_dn_test_ctx *test_ctx = NULL; ++ const char *exprdn = "rdn"; ++ char *rdn = NULL; ++ errno_t ret; ++ ++ test_ctx = talloc_get_type_abort(*state, struct ipa_dn_test_ctx); ++ ++ ret = ipa_get_rdn(test_ctx, test_ctx->sysdb, "cn=rdn,dc=example,dc=com", &rdn, "cn"); ++ assert_int_equal(ret, EOK); ++ assert_non_null(rdn); ++ assert_string_equal(exprdn, rdn); ++ ++ ret = ipa_get_rdn(test_ctx, test_ctx->sysdb, "cn=rdn,attr1=value1,dc=example,dc=com", &rdn, "cn", "attr1", "value1"); ++ assert_int_equal(ret, EOK); ++ assert_non_null(rdn); ++ assert_string_equal(exprdn, rdn); ++ ++ ret = ipa_get_rdn(test_ctx, test_ctx->sysdb, "cn=rdn,attr1=value1,attr2=value2,dc=example,dc=com", &rdn, "cn", "attr1", "value1", "attr2", "value2"); ++ assert_int_equal(ret, EOK); ++ assert_non_null(rdn); ++ assert_string_equal(exprdn, rdn); ++ ++ rdn = NULL; ++ ++ ret = ipa_get_rdn(test_ctx, test_ctx->sysdb, "cn=rdn,dc=example,dc=com", &rdn, "nope"); ++ assert_int_equal(ret, ENOENT); ++ assert_null(rdn); ++ ++ ret = ipa_get_rdn(test_ctx, test_ctx->sysdb, "cn=rdn,attr1=value1,dc=example,dc=com", &rdn, "cn", "nope", "value1"); ++ assert_int_equal(ret, ENOENT); ++ assert_null(rdn); ++ ++ ret = ipa_get_rdn(test_ctx, test_ctx->sysdb, "cn=rdn,attr1=value1,attr2=value2,dc=example,dc=com", &rdn, "cn", "attr1", "nope"); ++ assert_int_equal(ret, ENOENT); ++ assert_null(rdn); ++ ++ ret = ipa_get_rdn(test_ctx, test_ctx->sysdb, "cn=rdn,attr1=value1,dc=example,dc=com", &rdn, "cn", "attr1"); ++ assert_int_equal(ret, ENOENT); ++ assert_null(rdn); ++ ++ ret = ipa_get_rdn(test_ctx, test_ctx->sysdb, "cn=rdn,attr1=value1", &rdn, "cn", "attr1", "value1"); ++ assert_int_equal(ret, ENOENT); ++ assert_null(rdn); ++} ++ ++int main(int argc, const char *argv[]) ++{ ++ int rv; ++ int no_cleanup = 0; ++ poptContext pc; ++ int opt; ++ struct poptOption long_options[] = { ++ POPT_AUTOHELP ++ SSSD_DEBUG_OPTS ++ {"no-cleanup", 'n', POPT_ARG_NONE, &no_cleanup, 0, ++ _("Do not delete the test database after a test run"), NULL }, ++ POPT_TABLEEND ++ }; ++ ++ const struct CMUnitTest tests[] = { ++ cmocka_unit_test_setup_teardown(ipa_check_rdn_test, ++ ipa_dn_test_setup, ++ ipa_dn_test_teardown), ++ cmocka_unit_test_setup_teardown(ipa_check_rdn_bool_test, ++ ipa_dn_test_setup, ++ ipa_dn_test_teardown), ++ cmocka_unit_test_setup_teardown(ipa_get_rdn_test, ++ ipa_dn_test_setup, ++ ipa_dn_test_teardown) ++ }; ++ ++ /* Set debug level to invalid value so we can deside if -d 0 was used. */ ++ debug_level = SSSDBG_INVALID; ++ ++ pc = poptGetContext(argv[0], argc, argv, long_options, 0); ++ while((opt = poptGetNextOpt(pc)) != -1) { ++ switch(opt) { ++ default: ++ fprintf(stderr, "\nInvalid option %s: %s\n\n", ++ poptBadOption(pc, 0), poptStrerror(opt)); ++ poptPrintUsage(pc, stderr, 0); ++ return 1; ++ } ++ } ++ poptFreeContext(pc); ++ ++ DEBUG_CLI_INIT(debug_level); ++ ++ /* Even though normally the tests should clean up after themselves ++ * they might not after a failed run. Remove the old db to be sure */ ++ tests_set_cwd(); ++ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME); ++ test_dom_suite_setup(TESTS_PATH); ++ ++ rv = cmocka_run_group_tests(tests, NULL, NULL); ++ if (rv == 0 && !no_cleanup) { ++ test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME); ++ } ++ return rv; ++} +-- +2.5.0 + diff --git a/0021-SDAP-use-ipa_get_rdn-in-nested-groups.patch b/0021-SDAP-use-ipa_get_rdn-in-nested-groups.patch new file mode 100644 index 0000000..83c1c09 --- /dev/null +++ b/0021-SDAP-use-ipa_get_rdn-in-nested-groups.patch @@ -0,0 +1,152 @@ +From 0e69b0fca08a1e35eb50232bfaa10094101ea801 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 10 Dec 2015 15:10:37 +0100 +Subject: [PATCH 21/49] SDAP: use ipa_get_rdn() in nested groups + +Reviewed-by: Sumit Bose +(cherry picked from commit a6dd4a6c55773e81490dcafd61d4b9782705e9bf) +--- + Makefile.am | 2 + + src/providers/ldap/sdap_async_nested_groups.c | 80 +++------------------------ + 2 files changed, 11 insertions(+), 71 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index 6efb5ea7f81642292b39a44e7e2029a2757e47ea..59632f59f26f6d113de3398856e2ef0015d4ad16 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2092,6 +2092,7 @@ nestedgroups_tests_SOURCES = \ + src/tests/cmocka/common_mock_be.c \ + src/providers/ldap/sdap_async_nested_groups.c \ + src/providers/ldap/sdap_ad_groups.c \ ++ src/providers/ipa/ipa_dn.c \ + $(NULL) + nestedgroups_tests_CFLAGS = \ + $(AM_CFLAGS) \ +@@ -2860,6 +2861,7 @@ libsss_ldap_common_la_SOURCES = \ + src/providers/ldap/sdap_domain.c \ + src/providers/ldap/sdap_ops.c \ + src/providers/ldap/sdap.c \ ++ src/providers/ipa/ipa_dn.c \ + src/util/user_info_msg.c \ + src/util/sss_ldap.c \ + $(NULL) +diff --git a/src/providers/ldap/sdap_async_nested_groups.c b/src/providers/ldap/sdap_async_nested_groups.c +index af25430eacd4de7ea2e2872b0d9e34c8515c22db..9d715225243d8672850563473bd3938d4cc5db6b 100644 +--- a/src/providers/ldap/sdap_async_nested_groups.c ++++ b/src/providers/ldap/sdap_async_nested_groups.c +@@ -35,6 +35,7 @@ + #include "providers/ldap/sdap_async.h" + #include "providers/ldap/sdap_async_private.h" + #include "providers/ldap/sdap_idmap.h" ++#include "providers/ipa/ipa_dn.h" + + #define sdap_nested_group_sysdb_search_users(domain, filter) \ + sdap_nested_group_sysdb_search((domain), (filter), true) +@@ -1417,96 +1418,33 @@ static errno_t sdap_nested_group_single_recv(struct tevent_req *req) + return EOK; + } + +-/* This should be a function pointer set from the IPA provider */ + static errno_t sdap_nested_group_get_ipa_user(TALLOC_CTX *mem_ctx, + const char *user_dn, + struct sysdb_ctx *sysdb, + struct sysdb_attrs **_user) + { +- errno_t ret; +- struct sysdb_attrs *user = NULL; +- char *name; +- struct ldb_dn *dn = NULL; +- const char *rdn_name; +- const char *users_comp_name; +- const char *acct_comp_name; +- const struct ldb_val *rdn_val; +- const struct ldb_val *users_comp_val; +- const struct ldb_val *acct_comp_val; + TALLOC_CTX *tmp_ctx; ++ struct sysdb_attrs *user; ++ char *name; ++ errno_t ret; + + tmp_ctx = talloc_new(NULL); +- if (!tmp_ctx) return ENOMEM; +- +- /* return username if dn is in form: +- * uid=username,cn=users,cn=accounts,dc=example,dc=com */ +- +- dn = ldb_dn_new(tmp_ctx, sysdb_ctx_get_ldb(sysdb), user_dn); +- if (dn == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- /* rdn, users, accounts and least one domain component */ +- if (ldb_dn_get_comp_num(dn) < 4) { +- ret = ENOENT; +- goto done; +- } +- +- rdn_name = ldb_dn_get_rdn_name(dn); +- if (rdn_name == NULL) { +- ret = EINVAL; +- goto done; +- } +- +- /* rdn must be 'uid' */ +- if (strcasecmp("uid", rdn_name) != 0) { +- ret = ENOENT; +- goto done; +- } +- +- /* second component must be 'cn=users' */ +- users_comp_name = ldb_dn_get_component_name(dn, 1); +- if (strcasecmp("cn", users_comp_name) != 0) { +- ret = ENOENT; +- goto done; +- } +- +- users_comp_val = ldb_dn_get_component_val(dn, 1); +- if (strncasecmp("users", (const char *) users_comp_val->data, +- users_comp_val->length) != 0) { +- ret = ENOENT; +- goto done; +- } +- +- /* third component must be 'cn=accounts' */ +- acct_comp_name = ldb_dn_get_component_name(dn, 2); +- if (strcasecmp("cn", acct_comp_name) != 0) { +- ret = ENOENT; +- goto done; ++ if (tmp_ctx == NULL) { ++ return ENOMEM; + } + +- acct_comp_val = ldb_dn_get_component_val(dn, 2); +- if (strncasecmp("accounts", (const char *) acct_comp_val->data, +- acct_comp_val->length) != 0) { +- ret = ENOENT; ++ ret = ipa_get_rdn(tmp_ctx, sysdb, user_dn, &name, "uid", ++ "cn", "users", "cn", "accounts"); ++ if (ret != EOK) { + goto done; + } + +- /* value of rdn is username */ + user = sysdb_new_attrs(tmp_ctx); + if (user == NULL) { + ret = ENOMEM; + goto done; + } + +- rdn_val = ldb_dn_get_rdn_val(dn); +- name = talloc_strndup(user, (const char *)rdn_val->data, rdn_val->length); +- if (name == NULL) { +- ret = ENOMEM; +- goto done; +- } +- + ret = sysdb_attrs_add_string(user, SYSDB_NAME, name); + if (ret != EOK) { + goto done; +-- +2.5.0 + diff --git a/0022-IPA-SUDO-choose-between-IPA-and-LDAP-schema.patch b/0022-IPA-SUDO-choose-between-IPA-and-LDAP-schema.patch new file mode 100644 index 0000000..cf74a91 --- /dev/null +++ b/0022-IPA-SUDO-choose-between-IPA-and-LDAP-schema.patch @@ -0,0 +1,208 @@ +From 420700d4afe7ca56a8cb707cc81d0494e9296a34 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 25 Nov 2015 12:32:25 +0100 +Subject: [PATCH 22/49] IPA SUDO: choose between IPA and LDAP schema + +This patch implement logic to choose between IPA and LDAP schema. From +this point the sudo support in IPA is removed if sudo search base is +not set specifically, it will be brought back in furter patches. + +Resolves: +https://fedorahosted.org/sssd/ticket/1108 + +Reviewed-by: Sumit Bose +(cherry picked from commit 0f04241fc90f134af0272eb0999e75fb6749b595) +--- + src/providers/ipa/ipa_common.c | 38 --------------- + src/providers/ipa/ipa_sudo.c | 108 +++++++++++++++++++++++++++++++++-------- + 2 files changed, 88 insertions(+), 58 deletions(-) + +diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c +index 2940a42cc8d1eeb0dc18289bbe14d0effcc2be91..90be427518b55a22e307249fbd628017ae4600a3 100644 +--- a/src/providers/ipa/ipa_common.c ++++ b/src/providers/ipa/ipa_common.c +@@ -311,44 +311,6 @@ int ipa_get_id_options(struct ipa_options *ipa_opts, + if (ret != EOK) goto done; + + if (NULL == dp_opt_get_string(ipa_opts->id->basic, +- SDAP_SUDO_SEARCH_BASE)) { +-#if 0 +- ret = dp_opt_set_string(ipa_opts->id->basic, SDAP_SUDO_SEARCH_BASE, +- dp_opt_get_string(ipa_opts->id->basic, +- SDAP_SEARCH_BASE)); +- if (ret != EOK) { +- goto done; +- } +-#else +- /* We don't yet have support for the representation +- * of sudo in IPA. For now, we need to point at the +- * compat tree +- */ +- value = talloc_asprintf(tmpctx, "ou=SUDOers,%s", basedn); +- if (!value) { +- ret = ENOMEM; +- goto done; +- } +- +- ret = dp_opt_set_string(ipa_opts->id->basic, +- SDAP_SUDO_SEARCH_BASE, +- value); +- if (ret != EOK) { +- goto done; +- } +-#endif +- +- DEBUG(SSSDBG_TRACE_FUNC, "Option %s set to %s\n", +- ipa_opts->id->basic[SDAP_SUDO_SEARCH_BASE].opt_name, +- dp_opt_get_string(ipa_opts->id->basic, +- SDAP_SUDO_SEARCH_BASE)); +- } +- ret = sdap_parse_search_base(ipa_opts->id, ipa_opts->id->basic, +- SDAP_SUDO_SEARCH_BASE, +- &ipa_opts->id->sdom->sudo_search_bases); +- if (ret != EOK) goto done; +- +- if (NULL == dp_opt_get_string(ipa_opts->id->basic, + SDAP_NETGROUP_SEARCH_BASE)) { + value = talloc_asprintf(tmpctx, "cn=ng,cn=alt,%s", basedn); + if (!value) { +diff --git a/src/providers/ipa/ipa_sudo.c b/src/providers/ipa/ipa_sudo.c +index 4863aa55904c47ff7d19e3fdb364c06bad5f5678..3d159b3ac0f4ce8f423454506f66f23009eb463f 100644 +--- a/src/providers/ipa/ipa_sudo.c ++++ b/src/providers/ipa/ipa_sudo.c +@@ -1,12 +1,8 @@ + /* +- SSSD +- +- IPA Provider Initialization functions +- + Authors: +- Lukas Slebodnik ++ Pavel Březina + +- Copyright (C) 2013 Red Hat ++ Copyright (C) 2015 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by +@@ -25,31 +21,103 @@ + #include "providers/ipa/ipa_common.h" + #include "providers/ldap/sdap_sudo.h" + ++enum sudo_schema { ++ SUDO_SCHEMA_IPA, ++ SUDO_SCHEMA_LDAP ++}; ++ ++static errno_t ++ipa_sudo_choose_schema(struct dp_option *ipa_opts, ++ struct dp_option *sdap_opts, ++ enum sudo_schema *_schema) ++{ ++ TALLOC_CTX *tmp_ctx; ++ char *ipa_search_base; ++ char *search_base; ++ char *basedn; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); ++ return ENOMEM; ++ } ++ ++ ret = domain_to_basedn(tmp_ctx, dp_opt_get_string(ipa_opts, ++ IPA_KRB5_REALM), &basedn); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to obtain basedn\n"); ++ goto done; ++ } ++ ++ ipa_search_base = talloc_asprintf(tmp_ctx, "cn=sudo,%s", basedn); ++ if (ipa_search_base == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ search_base = dp_opt_get_string(sdap_opts, SDAP_SUDO_SEARCH_BASE); ++ if (search_base == NULL) { ++ ret = dp_opt_set_string(sdap_opts, SDAP_SUDO_SEARCH_BASE, ++ ipa_search_base); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Option %s set to %s\n", ++ sdap_opts[SDAP_SUDO_SEARCH_BASE].opt_name, ipa_search_base); ++ ++ search_base = ipa_search_base; ++ } ++ ++ /* Use IPA schema only if search base is cn=sudo,$dc. */ ++ if (strcmp(ipa_search_base, search_base) == 0) { ++ *_schema = SUDO_SCHEMA_IPA; ++ } else { ++ *_schema = SUDO_SCHEMA_LDAP; ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ + int ipa_sudo_init(struct be_ctx *be_ctx, + struct ipa_id_ctx *id_ctx, + struct bet_ops **ops, + void **pvt_data) + { +- int ret; +- struct ipa_options *ipa_options; +- struct sdap_options *ldap_options; ++ enum sudo_schema schema; ++ errno_t ret; + +- DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing sudo IPA back end\n"); ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing IPA sudo back end\n"); + +- /* +- * SDAP_SUDO_SEARCH_BASE has already been initialized in +- * function ipa_get_id_options +- */ +- ret = sdap_sudo_init(be_ctx, id_ctx->sdap_id_ctx, ops, pvt_data); ++ ret = ipa_sudo_choose_schema(id_ctx->ipa_options->basic, ++ id_ctx->ipa_options->id->basic, ++ &schema); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize LDAP SUDO [%d]: %s\n", +- ret, strerror(ret)); ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to choose sudo schema [%d]: %s\n", ++ ret, sss_strerror(ret)); + return ret; + } + +- ipa_options = id_ctx->ipa_options; +- ldap_options = id_ctx->sdap_id_ctx->opts; ++ switch (schema) { ++ case SUDO_SCHEMA_IPA: ++ DEBUG(SSSDBG_TRACE_FUNC, "Using IPA schema for sudo\n"); ++ break; ++ case SUDO_SCHEMA_LDAP: ++ DEBUG(SSSDBG_TRACE_FUNC, "Using LDAP schema for sudo\n"); ++ ret = sdap_sudo_init(be_ctx, id_ctx->sdap_id_ctx, ops, pvt_data); ++ break; ++ } ++ ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize sudo provider" ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ return ret; ++ } + +- ipa_options->id->sudorule_map = ldap_options->sudorule_map; + return EOK; + } +-- +2.5.0 + diff --git a/0023-IPA-SUDO-Add-ipasudorule-mapping.patch b/0023-IPA-SUDO-Add-ipasudorule-mapping.patch new file mode 100644 index 0000000..3716586 --- /dev/null +++ b/0023-IPA-SUDO-Add-ipasudorule-mapping.patch @@ -0,0 +1,169 @@ +From 3ab86013f8041070c866135b8b2c61ad8f3da40c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 1 Dec 2015 13:10:16 +0100 +Subject: [PATCH 23/49] IPA SUDO: Add ipasudorule mapping + +Reviewed-by: Sumit Bose +(cherry picked from commit a2057618f30a3c64bdffb35a2ef3c2ba148c8a03) +--- + src/config/etc/sssd.api.d/sssd-ipa.conf | 20 ++++++++++++++++++++ + src/db/sysdb_sudo.h | 20 ++++++++++++++++++++ + src/providers/ipa/ipa_common.h | 25 +++++++++++++++++++++++++ + src/providers/ipa/ipa_opts.c | 24 ++++++++++++++++++++++++ + src/providers/ipa/ipa_opts.h | 2 ++ + src/providers/ipa/ipa_sudo.c | 1 + + 6 files changed, 92 insertions(+) + +diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf +index ab712fe55cdac6d247a085aeca5cc82d65966623..0e4e8c00b0fb1fcf9ee9ee82790c28f6c14d26d0 100644 +--- a/src/config/etc/sssd.api.d/sssd-ipa.conf ++++ b/src/config/etc/sssd.api.d/sssd-ipa.conf +@@ -234,3 +234,23 @@ ldap_sudorule_runasgroup = str, None, false + ldap_sudorule_notbefore = str, None, false + ldap_sudorule_notafter = str, None, false + ldap_sudorule_order = str, None, false ++ipa_sudorule_object_class = str, None, false ++ipa_sudorule_name = str, None, false ++ipa_sudorule_uuid = str, None, false ++ipa_sudorule_enabled_flag = str, None, false ++ipa_sudorule_option = str, None, false ++ipa_sudorule_runasgroup = str, None, false ++ipa_sudorule_runasgroup = str, None, false ++ipa_sudorule_allowcmd = str, None, false ++ipa_sudorule_denycmd = str, None, false ++ipa_sudorule_host = str, None, false ++ipa_sudorule_user = str, None, false ++ipa_sudorule_notafter = str, None, false ++ipa_sudorule_notbefore = str, None, false ++ipa_sudorule_sudoorder = str, None, false ++ipa_sudorule_cmdcategory = str, None, false ++ipa_sudorule_hostcategory = str, None, false ++ipa_sudorule_usercategory = str, None, false ++ipa_sudorule_runasusercategory = str, None, false ++ipa_sudorule_runasgroupcategory = str, None, false ++ipa_sudorule_entry_usn = str, None, false +diff --git a/src/db/sysdb_sudo.h b/src/db/sysdb_sudo.h +index 6dd9ea7bb8ec947f5beceb89fd27bde156c27c36..cb4bcc236933d60adaba1c6ffcc52fc73f5df064 100644 +--- a/src/db/sysdb_sudo.h ++++ b/src/db/sysdb_sudo.h +@@ -46,6 +46,26 @@ + #define SYSDB_SUDO_CACHE_AT_NOTAFTER "sudoNotAfter" + #define SYSDB_SUDO_CACHE_AT_ORDER "sudoOrder" + ++/* sysdb ipa attributes */ ++#define SYSDB_IPA_SUDORULE_OC "ipasudorule" ++#define SYSDB_IPA_SUDORULE_ENABLED "ipaEnabledFlag" ++#define SYSDB_IPA_SUDORULE_OPTION "ipaSudoOpt" ++#define SYSDB_IPA_SUDORULE_RUNASUSER "ipaSudoRunAs" ++#define SYSDB_IPA_SUDORULE_RUNASGROUP "ipaSudoRunAsGroup" ++#define SYSDB_IPA_SUDORULE_ORIGCMD "originalMemberCommand" ++#define SYSDB_IPA_SUDORULE_ALLOWCMD "memberAllowCmd" ++#define SYSDB_IPA_SUDORULE_DENYCMD "memberDenyCmd" ++#define SYSDB_IPA_SUDORULE_HOST "memberHost" ++#define SYSDB_IPA_SUDORULE_USER "memberUser" ++#define SYSDB_IPA_SUDORULE_NOTAFTER "sudoNotAfter" ++#define SYSDB_IPA_SUDORULE_NOTBEFORE "sudoNotBefore" ++#define SYSDB_IPA_SUDORULE_SUDOORDER "sudoOrder" ++#define SYSDB_IPA_SUDORULE_CMDCATEGORY "cmdCategory" ++#define SYSDB_IPA_SUDORULE_HOSTCATEGORY "hostCategory" ++#define SYSDB_IPA_SUDORULE_USERCATEGORY "userCategory" ++#define SYSDB_IPA_SUDORULE_RUNASUSERCATEGORY "ipaSudoRunAsUserCategory" ++#define SYSDB_IPA_SUDORULE_RUNASGROUPCATEGORY "ipaSudoRunAsGroupCategory" ++ + /* When constructing a sysdb filter, OR these values to include.. */ + #define SYSDB_SUDO_FILTER_NONE 0x00 /* no additional filter */ + #define SYSDB_SUDO_FILTER_USERNAME 0x01 /* username */ +diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h +index fb36c702bee2e21860d64e2030f6a0c2b85f564e..d5527aeeda27a4684bc51e2d5bc420f9c3165a86 100644 +--- a/src/providers/ipa/ipa_common.h ++++ b/src/providers/ipa/ipa_common.h +@@ -133,6 +133,31 @@ enum ipa_override_attrs { + IPA_OPTS_OVERRIDE + }; + ++enum ipa_sudorule_attrs { ++ IPA_OC_SUDORULE = 0, ++ IPA_AT_SUDORULE_NAME, ++ IPA_AT_SUDORULE_UUID, ++ IPA_AT_SUDORULE_ENABLED, ++ IPA_AT_SUDORULE_OPTION, ++ IPA_AT_SUDORULE_RUNASUSER, ++ IPA_AT_SUDORULE_RUNASGROUP, ++ IPA_AT_SUDORULE_ALLOWCMD, ++ IPA_AT_SUDORULE_DENYCMD, ++ IPA_AT_SUDORULE_HOST, ++ IPA_AT_SUDORULE_USER, ++ IPA_AT_SUDORULE_NOTAFTER, ++ IPA_AT_SUDORULE_NOTBEFORE, ++ IPA_AT_SUDORULE_SUDOORDER, ++ IPA_AT_SUDORULE_CMDCATEGORY, ++ IPA_AT_SUDORULE_HOSTCATEGORY, ++ IPA_AT_SUDORULE_USERCATEGORY, ++ IPA_AT_SUDORULE_RUNASUSERCATEGORY, ++ IPA_AT_SUDORULE_RUNASGROUPCATEGORY, ++ IPA_AT_SUDORULE_ENTRYUSN, ++ ++ IPA_OPTS_SUDORULE ++}; ++ + struct ipa_auth_ctx { + struct krb5_ctx *krb5_auth_ctx; + struct sdap_id_ctx *sdap_id_ctx; +diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c +index bc983ec32d63c37b6fdf06d6009df9084f82d4bf..25e9a009a142580e40e3bc2034d7b310ff8ae9c5 100644 +--- a/src/providers/ipa/ipa_opts.c ++++ b/src/providers/ipa/ipa_opts.c +@@ -335,3 +335,27 @@ struct sdap_attr_map ipa_autofs_entry_map[] = { + { "ldap_autofs_entry_value", "automountInformation", SYSDB_AUTOFS_ENTRY_VALUE, NULL }, + SDAP_ATTR_MAP_TERMINATOR + }; ++ ++struct sdap_attr_map ipa_sudorule_map[] = { ++ { "ipa_sudorule_object_class", "ipasudorule", SYSDB_IPA_SUDORULE_OC, NULL }, ++ { "ipa_sudorule_name", "cn", SYSDB_NAME, NULL }, ++ { "ipa_sudorule_uuid", "ipaUniqueID", SYSDB_UUID, NULL }, ++ { "ipa_sudorule_enabled_flag", "ipaEnabledFlag", SYSDB_IPA_SUDORULE_ENABLED, NULL }, ++ { "ipa_sudorule_option", "ipaSudoOpt", SYSDB_IPA_SUDORULE_OPTION, NULL }, ++ { "ipa_sudorule_runasuser", "ipaSudoRunAs", SYSDB_IPA_SUDORULE_RUNASUSER, NULL }, ++ { "ipa_sudorule_runasgroup", "ipaSudoRunAsGroup", SYSDB_IPA_SUDORULE_RUNASGROUP, NULL }, ++ { "ipa_sudorule_allowcmd", "memberAllowCmd", SYSDB_IPA_SUDORULE_ALLOWCMD, NULL }, ++ { "ipa_sudorule_denycmd", "memberDenyCmd", SYSDB_IPA_SUDORULE_DENYCMD, NULL }, ++ { "ipa_sudorule_host", "memberHost", SYSDB_IPA_SUDORULE_HOST, NULL }, ++ { "ipa_sudorule_user", "memberUser", SYSDB_IPA_SUDORULE_USER, NULL }, ++ { "ipa_sudorule_notafter", "sudoNotAfter", SYSDB_IPA_SUDORULE_NOTAFTER, NULL }, ++ { "ipa_sudorule_notbefore", "sudoNotBefore", SYSDB_IPA_SUDORULE_NOTBEFORE, NULL }, ++ { "ipa_sudorule_sudoorder", "sudoOrder", SYSDB_IPA_SUDORULE_SUDOORDER, NULL }, ++ { "ipa_sudorule_cmdcategory", "cmdCategory", SYSDB_IPA_SUDORULE_CMDCATEGORY, NULL }, ++ { "ipa_sudorule_hostcategory", "hostCategory", SYSDB_IPA_SUDORULE_HOSTCATEGORY, NULL }, ++ { "ipa_sudorule_usercategory", "userCategory", SYSDB_IPA_SUDORULE_USERCATEGORY, NULL }, ++ { "ipa_sudorule_runasusercategory", "ipaSudoRunAsUserCategory", SYSDB_IPA_SUDORULE_RUNASUSERCATEGORY, NULL }, ++ { "ipa_sudorule_runasgroupcategory", "ipaSudoRunAsGroupCategory", SYSDB_IPA_SUDORULE_RUNASGROUPCATEGORY, NULL }, ++ { "ipa_sudorule_entry_usn", "entryUSN", SYSDB_USN, NULL }, ++ SDAP_ATTR_MAP_TERMINATOR ++}; +diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h +index af12e63d80696d8341a963368e7d3a3694f16812..6d9e52f73ae1b5625c31d73adc67a76f018c3898 100644 +--- a/src/providers/ipa/ipa_opts.h ++++ b/src/providers/ipa/ipa_opts.h +@@ -58,4 +58,6 @@ extern struct sdap_attr_map ipa_autofs_mobject_map[]; + + extern struct sdap_attr_map ipa_autofs_entry_map[]; + ++extern struct sdap_attr_map ipa_sudorule_map[]; ++ + #endif /* IPA_OPTS_H_ */ +diff --git a/src/providers/ipa/ipa_sudo.c b/src/providers/ipa/ipa_sudo.c +index 3d159b3ac0f4ce8f423454506f66f23009eb463f..529fb5f0736a883654b60d43d9dcf248af5c8c21 100644 +--- a/src/providers/ipa/ipa_sudo.c ++++ b/src/providers/ipa/ipa_sudo.c +@@ -20,6 +20,7 @@ + + #include "providers/ipa/ipa_common.h" + #include "providers/ldap/sdap_sudo.h" ++#include "db/sysdb_sudo.h" + + enum sudo_schema { + SUDO_SCHEMA_IPA, +-- +2.5.0 + diff --git a/0024-IPA-SUDO-Add-ipasudocmdgrp-mapping.patch b/0024-IPA-SUDO-Add-ipasudocmdgrp-mapping.patch new file mode 100644 index 0000000..0a63cac --- /dev/null +++ b/0024-IPA-SUDO-Add-ipasudocmdgrp-mapping.patch @@ -0,0 +1,93 @@ +From 71f41c651bd5a0ff966cfef662abefb8588948ff Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 2 Dec 2015 14:48:18 +0100 +Subject: [PATCH 24/49] IPA SUDO: Add ipasudocmdgrp mapping + +Reviewed-by: Sumit Bose +(cherry picked from commit ed8650be18af26b7bf389e1246f7e8cdb363f829) +--- + src/config/etc/sssd.api.d/sssd-ipa.conf | 5 +++++ + src/db/sysdb_sudo.h | 2 ++ + src/providers/ipa/ipa_common.h | 10 ++++++++++ + src/providers/ipa/ipa_opts.c | 9 +++++++++ + src/providers/ipa/ipa_opts.h | 2 ++ + 5 files changed, 28 insertions(+) + +diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf +index 0e4e8c00b0fb1fcf9ee9ee82790c28f6c14d26d0..f46545491439824f2ac3d65d4bbbad7d0b70a42b 100644 +--- a/src/config/etc/sssd.api.d/sssd-ipa.conf ++++ b/src/config/etc/sssd.api.d/sssd-ipa.conf +@@ -254,3 +254,8 @@ ipa_sudorule_usercategory = str, None, false + ipa_sudorule_runasusercategory = str, None, false + ipa_sudorule_runasgroupcategory = str, None, false + ipa_sudorule_entry_usn = str, None, false ++ipa_sudocmdgroup_object_class = str, None, false ++ipa_sudocmdgroup_uuid = str, None, false ++ipa_sudocmdgroup_name = str, None, false ++ipa_sudocmdgroup_member = str, None, false ++ipa_sudocmdgroup_entry_usn = str, None, false +diff --git a/src/db/sysdb_sudo.h b/src/db/sysdb_sudo.h +index cb4bcc236933d60adaba1c6ffcc52fc73f5df064..658d0237a16b5d1687bd0bf2ac60d24c91e1b03b 100644 +--- a/src/db/sysdb_sudo.h ++++ b/src/db/sysdb_sudo.h +@@ -66,6 +66,8 @@ + #define SYSDB_IPA_SUDORULE_RUNASUSERCATEGORY "ipaSudoRunAsUserCategory" + #define SYSDB_IPA_SUDORULE_RUNASGROUPCATEGORY "ipaSudoRunAsGroupCategory" + ++#define SYSDB_IPA_SUDOCMDGROUP_OC "ipasudocmdgrp" ++ + /* When constructing a sysdb filter, OR these values to include.. */ + #define SYSDB_SUDO_FILTER_NONE 0x00 /* no additional filter */ + #define SYSDB_SUDO_FILTER_USERNAME 0x01 /* username */ +diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h +index d5527aeeda27a4684bc51e2d5bc420f9c3165a86..57d93dd643e27d08802009dbcb8056c05edf76ab 100644 +--- a/src/providers/ipa/ipa_common.h ++++ b/src/providers/ipa/ipa_common.h +@@ -158,6 +158,16 @@ enum ipa_sudorule_attrs { + IPA_OPTS_SUDORULE + }; + ++enum ipa_sudocmdgroup_attrs { ++ IPA_OC_SUDOCMDGROUP = 0, ++ IPA_AT_SUDOCMDGROUP_UUID, ++ IPA_AT_SUDOCMDGROUP_NAME, ++ IPA_AT_SUDOCMDGROUP_MEMBER, ++ IPA_AT_SUDOCMDGROUP_ENTRYUSN, ++ ++ IPA_OPTS_SUDOCMDGROUP ++}; ++ + struct ipa_auth_ctx { + struct krb5_ctx *krb5_auth_ctx; + struct sdap_id_ctx *sdap_id_ctx; +diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c +index 25e9a009a142580e40e3bc2034d7b310ff8ae9c5..3493984f5db5b0d3ae474858510af61478e4561f 100644 +--- a/src/providers/ipa/ipa_opts.c ++++ b/src/providers/ipa/ipa_opts.c +@@ -359,3 +359,12 @@ struct sdap_attr_map ipa_sudorule_map[] = { + { "ipa_sudorule_entry_usn", "entryUSN", SYSDB_USN, NULL }, + SDAP_ATTR_MAP_TERMINATOR + }; ++ ++struct sdap_attr_map ipa_sudocmdgroup_map[] = { ++ { "ipa_sudocmdgroup_object_class", "ipasudocmdgrp", SYSDB_IPA_SUDOCMDGROUP_OC, NULL }, ++ { "ipa_sudocmdgroup_uuid", "ipaUniqueID", SYSDB_UUID, NULL }, ++ { "ipa_sudocmdgroup_name", "cn", SYSDB_NAME, NULL }, ++ { "ipa_sudocmdgroup_member", "member", SYSDB_MEMBER, NULL }, ++ { "ipa_sudocmdgroup_entry_usn", "entryUSN", SYSDB_USN, NULL }, ++ SDAP_ATTR_MAP_TERMINATOR ++}; +diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h +index 6d9e52f73ae1b5625c31d73adc67a76f018c3898..89acea1608743a65c85b1b1c955e4215576fc48b 100644 +--- a/src/providers/ipa/ipa_opts.h ++++ b/src/providers/ipa/ipa_opts.h +@@ -60,4 +60,6 @@ extern struct sdap_attr_map ipa_autofs_entry_map[]; + + extern struct sdap_attr_map ipa_sudorule_map[]; + ++extern struct sdap_attr_map ipa_sudocmdgroup_map[]; ++ + #endif /* IPA_OPTS_H_ */ +-- +2.5.0 + diff --git a/0025-IPA-SUDO-Add-ipasudocmd-mapping.patch b/0025-IPA-SUDO-Add-ipasudocmd-mapping.patch new file mode 100644 index 0000000..b053eb2 --- /dev/null +++ b/0025-IPA-SUDO-Add-ipasudocmd-mapping.patch @@ -0,0 +1,91 @@ +From 0afa6acd1ff34c749f4442233f8e2c6cd8337678 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 2 Dec 2015 15:02:39 +0100 +Subject: [PATCH 25/49] IPA SUDO: Add ipasudocmd mapping + +Reviewed-by: Sumit Bose +(cherry picked from commit cc7766c8456653ab5d7dedbf432cb1711a905804) +--- + src/config/etc/sssd.api.d/sssd-ipa.conf | 4 ++++ + src/db/sysdb_sudo.h | 3 +++ + src/providers/ipa/ipa_common.h | 9 +++++++++ + src/providers/ipa/ipa_opts.c | 8 ++++++++ + src/providers/ipa/ipa_opts.h | 2 ++ + 5 files changed, 26 insertions(+) + +diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf +index f46545491439824f2ac3d65d4bbbad7d0b70a42b..2784a01e7a012f642377ae9c89d1ed03be88c7ae 100644 +--- a/src/config/etc/sssd.api.d/sssd-ipa.conf ++++ b/src/config/etc/sssd.api.d/sssd-ipa.conf +@@ -259,3 +259,7 @@ ipa_sudocmdgroup_uuid = str, None, false + ipa_sudocmdgroup_name = str, None, false + ipa_sudocmdgroup_member = str, None, false + ipa_sudocmdgroup_entry_usn = str, None, false ++ipa_sudocmd_object_class = str, None, false ++ipa_sudocmd_uuid = str, None, false ++ipa_sudocmd_sudoCmd = str, None, false ++ipa_sudocmd_memberof = str, None, false +diff --git a/src/db/sysdb_sudo.h b/src/db/sysdb_sudo.h +index 658d0237a16b5d1687bd0bf2ac60d24c91e1b03b..8635e78041687f386ec15d45e5d1d3f1f0551e3d 100644 +--- a/src/db/sysdb_sudo.h ++++ b/src/db/sysdb_sudo.h +@@ -68,6 +68,9 @@ + + #define SYSDB_IPA_SUDOCMDGROUP_OC "ipasudocmdgrp" + ++#define SYSDB_IPA_SUDOCMD_OC "ipasudocmd" ++#define SYSDB_IPA_SUDOCMD_SUDOCMD "sudoCmd" ++ + /* When constructing a sysdb filter, OR these values to include.. */ + #define SYSDB_SUDO_FILTER_NONE 0x00 /* no additional filter */ + #define SYSDB_SUDO_FILTER_USERNAME 0x01 /* username */ +diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h +index 57d93dd643e27d08802009dbcb8056c05edf76ab..8cb2058fef98fc8eef0d769a6f62882d1da7ae53 100644 +--- a/src/providers/ipa/ipa_common.h ++++ b/src/providers/ipa/ipa_common.h +@@ -168,6 +168,15 @@ enum ipa_sudocmdgroup_attrs { + IPA_OPTS_SUDOCMDGROUP + }; + ++enum ipa_sudocmd_attrs { ++ IPA_OC_SUDOCMD = 0, ++ IPA_AT_SUDOCMD_UUID, ++ IPA_AT_SUDOCMD_CMD, ++ IPA_AT_SUDOCMD_MEMBEROF, ++ ++ IPA_OPTS_SUDOCMD ++}; ++ + struct ipa_auth_ctx { + struct krb5_ctx *krb5_auth_ctx; + struct sdap_id_ctx *sdap_id_ctx; +diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c +index 3493984f5db5b0d3ae474858510af61478e4561f..725e512352ff40cb4de6daba88efa3b8dfefdc62 100644 +--- a/src/providers/ipa/ipa_opts.c ++++ b/src/providers/ipa/ipa_opts.c +@@ -368,3 +368,11 @@ struct sdap_attr_map ipa_sudocmdgroup_map[] = { + { "ipa_sudocmdgroup_entry_usn", "entryUSN", SYSDB_USN, NULL }, + SDAP_ATTR_MAP_TERMINATOR + }; ++ ++struct sdap_attr_map ipa_sudocmd_map[] = { ++ { "ipa_sudocmd_object_class", "ipasudocmd", SYSDB_IPA_SUDOCMD_OC, NULL }, ++ { "ipa_sudocmd_uuid", "ipaUniqueID", SYSDB_UUID, NULL }, ++ { "ipa_sudocmd_sudoCmd", "sudoCmd", SYSDB_IPA_SUDOCMD_SUDOCMD, NULL }, ++ { "ipa_sudocmd_memberof", "memberOf", SYSDB_MEMBEROF, NULL }, ++ SDAP_ATTR_MAP_TERMINATOR ++}; +diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h +index 89acea1608743a65c85b1b1c955e4215576fc48b..68326b8649a268232394a8fe970d932feb01d46e 100644 +--- a/src/providers/ipa/ipa_opts.h ++++ b/src/providers/ipa/ipa_opts.h +@@ -62,4 +62,6 @@ extern struct sdap_attr_map ipa_sudorule_map[]; + + extern struct sdap_attr_map ipa_sudocmdgroup_map[]; + ++extern struct sdap_attr_map ipa_sudocmd_map[]; ++ + #endif /* IPA_OPTS_H_ */ +-- +2.5.0 + diff --git a/0026-IPA-SUDO-Implement-sudo-handler.patch b/0026-IPA-SUDO-Implement-sudo-handler.patch new file mode 100644 index 0000000..e7f9a9f --- /dev/null +++ b/0026-IPA-SUDO-Implement-sudo-handler.patch @@ -0,0 +1,191 @@ +From 17f35039230235f94c58a01ebd037a2634769b0c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 25 Nov 2015 13:14:57 +0100 +Subject: [PATCH 26/49] IPA SUDO: Implement sudo handler + +Resolves: +https://fedorahosted.org/sssd/ticket/XXXX + +Reviewed-by: Sumit Bose +(cherry picked from commit 4ddd5591c50e27dffa55f03fbce0dcc85cd50a8b) +--- + Makefile.am | 1 + + src/providers/ipa/ipa_sudo.c | 82 ++++++++++++++++++++++++++++++++++++++++++++ + src/providers/ipa/ipa_sudo.h | 38 ++++++++++++++++++++ + 3 files changed, 121 insertions(+) + create mode 100644 src/providers/ipa/ipa_sudo.h + +diff --git a/Makefile.am b/Makefile.am +index 59632f59f26f6d113de3398856e2ef0015d4ad16..69905a9112114932e918adff94d0c285c09ed231 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -644,6 +644,7 @@ dist_noinst_HEADERS = \ + src/providers/ipa/ipa_opts.h \ + src/providers/ipa/ipa_srv.h \ + src/providers/ipa/ipa_dn.h \ ++ src/providers/ipa/ipa_sudo.h \ + src/providers/ad/ad_srv.h \ + src/providers/proxy/proxy.h \ + src/tools/tools_util.h \ +diff --git a/src/providers/ipa/ipa_sudo.c b/src/providers/ipa/ipa_sudo.c +index 529fb5f0736a883654b60d43d9dcf248af5c8c21..e1b0c828806104336f3df9724484a4411b7fef30 100644 +--- a/src/providers/ipa/ipa_sudo.c ++++ b/src/providers/ipa/ipa_sudo.c +@@ -18,10 +18,19 @@ + along with this program. If not, see . + */ + ++#include "providers/ipa/ipa_opts.h" + #include "providers/ipa/ipa_common.h" + #include "providers/ldap/sdap_sudo.h" ++#include "providers/ipa/ipa_sudo.h" + #include "db/sysdb_sudo.h" + ++static void ipa_sudo_handler(struct be_req *breq); ++ ++struct bet_ops ipa_sudo_ops = { ++ .handler = ipa_sudo_handler, ++ .finalize = NULL, ++}; ++ + enum sudo_schema { + SUDO_SCHEMA_IPA, + SUDO_SCHEMA_LDAP +@@ -85,6 +94,72 @@ done: + return ret; + } + ++static int ++ipa_sudo_init_ipa_schema(struct be_ctx *be_ctx, ++ struct ipa_id_ctx *id_ctx, ++ struct bet_ops **ops, ++ void **pvt_data) ++{ ++ struct ipa_sudo_ctx *sudo_ctx; ++ errno_t ret; ++ ++ sudo_ctx = talloc_zero(be_ctx, struct ipa_sudo_ctx); ++ if (sudo_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ sudo_ctx->id_ctx = id_ctx->sdap_id_ctx; ++ sudo_ctx->ipa_opts = id_ctx->ipa_options; ++ sudo_ctx->sdap_opts = id_ctx->sdap_id_ctx->opts; ++ ++ ret = sdap_get_map(sudo_ctx, be_ctx->cdb, be_ctx->conf_path, ++ ipa_sudorule_map, IPA_OPTS_SUDORULE, ++ &sudo_ctx->sudorule_map); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse attribute map " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = sdap_get_map(sudo_ctx, be_ctx->cdb, be_ctx->conf_path, ++ ipa_sudocmdgroup_map, IPA_OPTS_SUDOCMDGROUP, ++ &sudo_ctx->sudocmdgroup_map); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse attribute map " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = sdap_get_map(sudo_ctx, be_ctx->cdb, be_ctx->conf_path, ++ ipa_sudocmd_map, IPA_OPTS_SUDOCMD, ++ &sudo_ctx->sudocmd_map); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse attribute map " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = sdap_parse_search_base(sudo_ctx, sudo_ctx->sdap_opts->basic, ++ SDAP_SUDO_SEARCH_BASE, ++ &sudo_ctx->sudo_sb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Could not parse sudo search base\n"); ++ return ret; ++ } ++ ++ *ops = &ipa_sudo_ops; ++ *pvt_data = sudo_ctx; ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ talloc_free(sudo_ctx); ++ } ++ ++ return ret; ++} ++ + int ipa_sudo_init(struct be_ctx *be_ctx, + struct ipa_id_ctx *id_ctx, + struct bet_ops **ops, +@@ -107,6 +182,7 @@ int ipa_sudo_init(struct be_ctx *be_ctx, + switch (schema) { + case SUDO_SCHEMA_IPA: + DEBUG(SSSDBG_TRACE_FUNC, "Using IPA schema for sudo\n"); ++ ret = ipa_sudo_init_ipa_schema(be_ctx, id_ctx, ops, pvt_data); + break; + case SUDO_SCHEMA_LDAP: + DEBUG(SSSDBG_TRACE_FUNC, "Using LDAP schema for sudo\n"); +@@ -122,3 +198,9 @@ int ipa_sudo_init(struct be_ctx *be_ctx, + + return EOK; + } ++ ++static void ++ipa_sudo_handler(struct be_req *be_req) ++{ ++ sdap_handler_done(be_req, DP_ERR_FATAL, ERR_INTERNAL, "Not implemented yet."); ++} +diff --git a/src/providers/ipa/ipa_sudo.h b/src/providers/ipa/ipa_sudo.h +new file mode 100644 +index 0000000000000000000000000000000000000000..21251ed3dabfaebdc324c8d06ba8f1a0b82951b1 +--- /dev/null ++++ b/src/providers/ipa/ipa_sudo.h +@@ -0,0 +1,38 @@ ++/* ++ Authors: ++ Pavel Březina ++ ++ Copyright (C) 2015 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#ifndef _IPA_SUDO_H_ ++#define _IPA_SUDO_H_ ++ ++#include "providers/ipa/ipa_common.h" ++ ++struct ipa_sudo_ctx { ++ struct sdap_id_ctx *id_ctx; ++ struct ipa_options *ipa_opts; ++ struct sdap_options *sdap_opts; ++ ++ /* sudo */ ++ struct sdap_attr_map *sudocmdgroup_map; ++ struct sdap_attr_map *sudorule_map; ++ struct sdap_attr_map *sudocmd_map; ++ struct sdap_search_base **sudo_sb; ++}; ++ ++#endif /* _IPA_SUDO_H_ */ +-- +2.5.0 + diff --git a/0027-IPA-SUDO-Implement-full-refresh.patch b/0027-IPA-SUDO-Implement-full-refresh.patch new file mode 100644 index 0000000..9d2b8cc --- /dev/null +++ b/0027-IPA-SUDO-Implement-full-refresh.patch @@ -0,0 +1,2372 @@ +From b55cdd3a298b5edd5ddc26beebfa6379843ebe21 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 11 Dec 2015 15:00:40 +0100 +Subject: [PATCH 27/49] IPA SUDO: Implement full refresh + +Reviewed-by: Sumit Bose +(cherry picked from commit a641a13889d617aca6bd998025e9087e822ff7f0) +--- + Makefile.am | 5 +- + src/providers/ipa/ipa_sudo.c | 75 +- + src/providers/ipa/ipa_sudo.h | 75 ++ + src/providers/ipa/ipa_sudo_async.c | 779 +++++++++++++++++++++ + src/providers/ipa/ipa_sudo_conversion.c | 1158 +++++++++++++++++++++++++++++++ + src/providers/ipa/ipa_sudo_refresh.c | 195 ++++++ + 6 files changed, 2285 insertions(+), 2 deletions(-) + create mode 100644 src/providers/ipa/ipa_sudo_async.c + create mode 100644 src/providers/ipa/ipa_sudo_conversion.c + create mode 100644 src/providers/ipa/ipa_sudo_refresh.c + +diff --git a/Makefile.am b/Makefile.am +index 69905a9112114932e918adff94d0c285c09ed231..1c0b1aada9804b2ef35a09cf1b7bf5e9c65ee4e5 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3044,7 +3044,10 @@ endif + + if BUILD_SUDO + libsss_ipa_la_SOURCES += \ +- src/providers/ipa/ipa_sudo.c ++ src/providers/ipa/ipa_sudo.c \ ++ src/providers/ipa/ipa_sudo_refresh.c \ ++ src/providers/ipa/ipa_sudo_conversion.c \ ++ src/providers/ipa/ipa_sudo_async.c + endif + + if BUILD_SSH +diff --git a/src/providers/ipa/ipa_sudo.c b/src/providers/ipa/ipa_sudo.c +index e1b0c828806104336f3df9724484a4411b7fef30..3e73bd30fa86f394b3ef822d59c7b0e539c92ca2 100644 +--- a/src/providers/ipa/ipa_sudo.c ++++ b/src/providers/ipa/ipa_sudo.c +@@ -147,6 +147,13 @@ ipa_sudo_init_ipa_schema(struct be_ctx *be_ctx, + return ret; + } + ++ ret = ipa_sudo_ptask_setup(be_ctx, sudo_ctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to setup periodic tasks " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ goto done; ++ } ++ + *ops = &ipa_sudo_ops; + *pvt_data = sudo_ctx; + +@@ -200,7 +207,73 @@ int ipa_sudo_init(struct be_ctx *be_ctx, + } + + static void ++ipa_sudo_reply(struct tevent_req *req) ++{ ++ struct be_sudo_req *sudo_req; ++ struct be_req *be_req; ++ int dp_error; ++ int ret; ++ ++ be_req = tevent_req_callback_data(req, struct be_req); ++ sudo_req = talloc_get_type(be_req_get_data(be_req), struct be_sudo_req); ++ ++ switch (sudo_req->type) { ++ case BE_REQ_SUDO_FULL: ++ ret = ipa_sudo_full_refresh_recv(req, &dp_error); ++ break; ++ default: ++ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request type: %d\n", ++ sudo_req->type); ++ dp_error = DP_ERR_FATAL; ++ ret = ERR_INTERNAL; ++ break; ++ } ++ ++ talloc_zfree(req); ++ sdap_handler_done(be_req, dp_error, ret, sss_strerror(ret)); ++} ++ ++static void + ipa_sudo_handler(struct be_req *be_req) + { +- sdap_handler_done(be_req, DP_ERR_FATAL, ERR_INTERNAL, "Not implemented yet."); ++ struct be_ctx *be_ctx = be_req_get_be_ctx(be_req); ++ struct ipa_sudo_ctx *sudo_ctx; ++ struct be_sudo_req *sudo_req; ++ struct tevent_req *req; ++ int ret; ++ ++ if (be_is_offline(be_ctx)) { ++ sdap_handler_done(be_req, DP_ERR_OFFLINE, EAGAIN, "Offline"); ++ return; ++ } ++ ++ sudo_ctx = talloc_get_type(be_ctx->bet_info[BET_SUDO].pvt_bet_data, ++ struct ipa_sudo_ctx); ++ ++ sudo_req = talloc_get_type(be_req_get_data(be_req), struct be_sudo_req); ++ ++ switch (sudo_req->type) { ++ case BE_REQ_SUDO_FULL: ++ req = ipa_sudo_full_refresh_send(be_req, be_ctx->ev, sudo_ctx); ++ break; ++ default: ++ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request type: %d\n", ++ sudo_req->type); ++ ret = EINVAL; ++ goto fail; ++ } ++ ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to send request: %d\n", ++ sudo_req->type); ++ ret = ENOMEM; ++ goto fail; ++ } ++ ++ tevent_req_set_callback(req, ipa_sudo_reply, be_req); ++ ++ return; ++ ++fail: ++ sdap_handler_done(be_req, DP_ERR_FATAL, ret, NULL); + } +diff --git a/src/providers/ipa/ipa_sudo.h b/src/providers/ipa/ipa_sudo.h +index 21251ed3dabfaebdc324c8d06ba8f1a0b82951b1..1ef50a7f352182bdc6607b2fd8ee3d72ccab391d 100644 +--- a/src/providers/ipa/ipa_sudo.h ++++ b/src/providers/ipa/ipa_sudo.h +@@ -28,6 +28,9 @@ struct ipa_sudo_ctx { + struct ipa_options *ipa_opts; + struct sdap_options *sdap_opts; + ++ bool full_refresh_done; ++ bool full_refresh_in_progress; ++ + /* sudo */ + struct sdap_attr_map *sudocmdgroup_map; + struct sdap_attr_map *sudorule_map; +@@ -35,4 +38,76 @@ struct ipa_sudo_ctx { + struct sdap_search_base **sudo_sb; + }; + ++errno_t ++ipa_sudo_ptask_setup(struct be_ctx *be_ctx, struct ipa_sudo_ctx *sudo_ctx); ++ ++struct tevent_req * ++ipa_sudo_full_refresh_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct ipa_sudo_ctx *sudo_ctx); ++ ++int ++ipa_sudo_full_refresh_recv(struct tevent_req *req, ++ int *dp_error); ++ ++struct tevent_req * ++ipa_sudo_refresh_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct ipa_sudo_ctx *sudo_ctx, ++ const char *search_filter, ++ const char *delete_filter); ++ ++errno_t ++ipa_sudo_refresh_recv(struct tevent_req *req, ++ int *dp_error, ++ size_t *_num_rules); ++ ++struct ipa_sudo_conv; ++ ++struct ipa_sudo_conv * ++ipa_sudo_conv_init(TALLOC_CTX *mem_ctx, ++ struct sysdb_ctx *sysdb, ++ struct sdap_attr_map *map_rule, ++ struct sdap_attr_map *map_cmdgroup, ++ struct sdap_attr_map *map_cmd, ++ struct sdap_attr_map *map_user, ++ struct sdap_attr_map *map_group, ++ struct sdap_attr_map *map_host, ++ struct sdap_attr_map *map_hostgroup); ++ ++errno_t ++ipa_sudo_conv_rules(struct ipa_sudo_conv *conv, ++ struct sysdb_attrs **rules, ++ size_t num_rules); ++ ++errno_t ++ipa_sudo_conv_cmdgroups(struct ipa_sudo_conv *conv, ++ struct sysdb_attrs **cmdgroups, ++ size_t num_cmdgroups); ++ ++errno_t ++ipa_sudo_conv_cmds(struct ipa_sudo_conv *conv, ++ struct sysdb_attrs **cmds, ++ size_t num_cmds); ++ ++bool ++ipa_sudo_conv_has_cmdgroups(struct ipa_sudo_conv *conv); ++ ++bool ++ipa_sudo_conv_has_cmds(struct ipa_sudo_conv *conv); ++ ++char * ++ipa_sudo_conv_cmdgroup_filter(TALLOC_CTX *mem_ctx, ++ struct ipa_sudo_conv *conv); ++ ++char * ++ipa_sudo_conv_cmd_filter(TALLOC_CTX *mem_ctx, ++ struct ipa_sudo_conv *conv); ++ ++errno_t ++ipa_sudo_conv_result(TALLOC_CTX *mem_ctx, ++ struct ipa_sudo_conv *conv, ++ struct sysdb_attrs ***_rules, ++ size_t *_num_rules); ++ + #endif /* _IPA_SUDO_H_ */ +diff --git a/src/providers/ipa/ipa_sudo_async.c b/src/providers/ipa/ipa_sudo_async.c +new file mode 100644 +index 0000000000000000000000000000000000000000..9ddda1b41a0b3c6ceb33e6d665749948ae835a97 +--- /dev/null ++++ b/src/providers/ipa/ipa_sudo_async.c +@@ -0,0 +1,779 @@ ++/* ++ Authors: ++ Pavel Březina ++ ++ Copyright (C) 2015 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#include ++#include ++#include ++ ++#include "providers/ldap/sdap_ops.h" ++#include "providers/ipa/ipa_common.h" ++#include "providers/ipa/ipa_hosts.h" ++#include "providers/ipa/ipa_sudo.h" ++#include "providers/ipa/ipa_dn.h" ++#include "db/sysdb.h" ++#include "db/sysdb_sudo.h" ++ ++struct ipa_hostinfo { ++ size_t num_hosts; ++ size_t num_hostgroups; ++ struct sysdb_attrs **hosts; ++ struct sysdb_attrs **hostgroups; ++}; ++ ++static char * ++ipa_sudo_filter_append_origdn(char *filter, ++ struct sysdb_attrs *attrs, ++ const char *attr_name) ++{ ++ const char *origdn; ++ char *sanitizeddn; ++ errno_t ret; ++ ++ ret = sysdb_attrs_get_string(attrs, SYSDB_ORIG_DN, &origdn); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get original DN " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ return NULL; ++ } ++ ++ ret = sss_filter_sanitize(NULL, origdn, &sanitizeddn); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to sanitize DN " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ return NULL; ++ } ++ ++ filter = talloc_asprintf_append(filter, "(%s=%s)", attr_name, sanitizeddn); ++ talloc_free(sanitizeddn); ++ if (filter == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf_append() failed\n"); ++ } ++ ++ return filter; ++} ++ ++/** ++ * (|(hostCategory=ALL)(memberHost=$DN(fqdn))(memberHost=$DN(hostgroup))...) ++ */ ++static char * ++ipa_sudo_host_filter(TALLOC_CTX *mem_ctx, ++ struct ipa_hostinfo *host, ++ struct sdap_attr_map *map) ++{ ++ TALLOC_CTX *tmp_ctx; ++ char *filter; ++ size_t i; ++ ++ /* If realloc fails we will free all data through tmp_ctx. */ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return NULL; ++ } ++ ++ filter = talloc_asprintf(tmp_ctx, "(!(%s=*))", ++ map[IPA_AT_SUDORULE_HOST].name); ++ if (filter == NULL) { ++ goto fail; ++ } ++ ++ /* Append hostCategory=ALL */ ++ filter = talloc_asprintf_append(filter, "(%s=ALL)", ++ map[IPA_AT_SUDORULE_HOSTCATEGORY].name); ++ if (filter == NULL) { ++ goto fail; ++ } ++ ++ /* Append client machine */ ++ for (i = 0; i < host->num_hosts; i++) { ++ filter = ipa_sudo_filter_append_origdn(filter, host->hosts[i], ++ map[IPA_AT_SUDORULE_HOST].name); ++ if (filter == NULL) { ++ goto fail; ++ } ++ } ++ ++ /* Append hostgroups */ ++ for (i = 0; i < host->num_hostgroups; i++) { ++ filter = ipa_sudo_filter_append_origdn(filter, host->hostgroups[i], ++ map[IPA_AT_SUDORULE_HOST].name); ++ if (filter == NULL) { ++ goto fail; ++ } ++ } ++ ++ /* OR filters */ ++ filter = talloc_asprintf(tmp_ctx, "(|%s)", filter); ++ if (filter == NULL) { ++ goto fail; ++ } ++ ++ talloc_steal(mem_ctx, filter); ++ talloc_free(tmp_ctx); ++ return filter; ++ ++fail: ++ talloc_free(tmp_ctx); ++ return NULL; ++} ++ ++struct ipa_sudo_fetch_state { ++ struct tevent_context *ev; ++ struct sysdb_ctx *sysdb; ++ struct ipa_sudo_ctx *sudo_ctx; ++ struct sdap_options *sdap_opts; ++ struct ipa_hostinfo *host; ++ struct sdap_handle *sh; ++ ++ struct sdap_attr_map *map_cmdgroup; ++ struct sdap_attr_map *map_rule; ++ struct sdap_attr_map *map_cmd; ++ struct sdap_search_base **sudo_sb; ++ ++ struct ipa_sudo_conv *conv; ++ struct sysdb_attrs **rules; ++ size_t num_rules; ++}; ++ ++static errno_t ipa_sudo_fetch_rules(struct tevent_req *req); ++static void ipa_sudo_fetch_rules_done(struct tevent_req *subreq); ++static errno_t ipa_sudo_fetch_cmdgroups(struct tevent_req *req); ++static void ipa_sudo_fetch_cmdgroups_done(struct tevent_req *subreq); ++static errno_t ipa_sudo_fetch_cmds(struct tevent_req *req); ++static void ipa_sudo_fetch_cmds_done(struct tevent_req *subreq); ++static void ipa_sudo_fetch_done(struct tevent_req *req); ++ ++static struct tevent_req * ++ipa_sudo_fetch_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct sysdb_ctx *sysdb, ++ struct ipa_sudo_ctx *sudo_ctx, ++ struct ipa_hostinfo *host, ++ struct sdap_attr_map *map_user, ++ struct sdap_attr_map *map_group, ++ struct sdap_attr_map *map_host, ++ struct sdap_attr_map *map_hostgroup, ++ struct sdap_handle *sh) ++{ ++ struct ipa_sudo_fetch_state *state = NULL; ++ struct tevent_req *req = NULL; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct ipa_sudo_fetch_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n")); ++ return NULL; ++ } ++ ++ state->ev = ev; ++ state->sysdb = sysdb; ++ state->sudo_ctx = sudo_ctx; ++ state->sdap_opts = sudo_ctx->sdap_opts; ++ state->host = host; ++ state->sh = sh; ++ ++ state->map_cmdgroup = sudo_ctx->sudocmdgroup_map; ++ state->map_rule = sudo_ctx->sudorule_map; ++ state->map_cmd = sudo_ctx->sudocmd_map; ++ state->sudo_sb = sudo_ctx->sudo_sb; ++ ++ state->conv = ipa_sudo_conv_init(state, sysdb, state->map_rule, ++ state->map_cmdgroup, state->map_cmd, ++ map_user, map_group, map_host, ++ map_hostgroup); ++ if (state->conv == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ ret = ipa_sudo_fetch_rules(req); ++ if (ret != EAGAIN) { ++ goto immediately; ++ } ++ ++ return req; ++ ++immediately: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, state->ev); ++ ++ return req; ++} ++ ++static errno_t ++ipa_sudo_fetch_rules(struct tevent_req *req) ++{ ++ struct ipa_sudo_fetch_state *state; ++ struct tevent_req *subreq; ++ struct sdap_attr_map *map; ++ char *host_filter; ++ char *filter; ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "About to fetch sudo rules\n"); ++ ++ state = tevent_req_data(req, struct ipa_sudo_fetch_state); ++ map = state->map_rule; ++ ++ host_filter = ipa_sudo_host_filter(state, state->host, map); ++ if (host_filter == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build host filter\n"); ++ return ENOMEM; ++ } ++ ++ filter = talloc_asprintf(state, "(&(objectClass=%s)(%s=TRUE)%s)", ++ map[IPA_OC_SUDORULE].name, ++ map[IPA_AT_SUDORULE_ENABLED].name, ++ host_filter); ++ talloc_zfree(host_filter); ++ if (filter == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build filter\n"); ++ return ENOMEM; ++ } ++ ++ subreq = sdap_search_bases_send(state, state->ev, state->sdap_opts, ++ state->sh, state->sudo_sb, map, true, 0, ++ filter, NULL); ++ if (subreq == NULL) { ++ return ENOMEM; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_sudo_fetch_rules_done, req); ++ return EAGAIN; ++} ++ ++static void ++ipa_sudo_fetch_rules_done(struct tevent_req *subreq) ++{ ++ struct ipa_sudo_fetch_state *state = NULL; ++ struct tevent_req *req = NULL; ++ struct sysdb_attrs **attrs; ++ size_t num_attrs; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_sudo_fetch_state); ++ ++ ret = sdap_search_bases_recv(subreq, state, &num_attrs, &attrs); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_IMPORTANT_INFO, "Received %zu sudo rules\n", num_attrs); ++ ++ ret = ipa_sudo_conv_rules(state->conv, attrs, num_attrs); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed when converting rules " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = ipa_sudo_fetch_cmdgroups(req); ++ ++done: ++ if (ret == EOK) { ++ ipa_sudo_fetch_done(req); ++ } else if (ret != EAGAIN) { ++ tevent_req_error(req, ret); ++ } ++ ++ return; ++} ++ ++static errno_t ++ipa_sudo_fetch_cmdgroups(struct tevent_req *req) ++{ ++ struct ipa_sudo_fetch_state *state; ++ struct tevent_req *subreq; ++ char *filter; ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "About to fetch sudo command groups\n"); ++ ++ state = tevent_req_data(req, struct ipa_sudo_fetch_state); ++ ++ if (ipa_sudo_conv_has_cmdgroups(state->conv)) { ++ DEBUG(SSSDBG_TRACE_FUNC, "No command groups needs to be downloaded\n"); ++ return ipa_sudo_fetch_cmds(req); ++ } ++ ++ filter = ipa_sudo_conv_cmdgroup_filter(state, state->conv); ++ if (filter == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build filter\n"); ++ return ENOMEM; ++ } ++ ++ subreq = sdap_search_bases_send(state, state->ev, state->sdap_opts, ++ state->sh, state->sudo_sb, ++ state->map_cmdgroup, true, 0, ++ filter, NULL); ++ if (subreq == NULL) { ++ return ENOMEM; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_sudo_fetch_cmdgroups_done, req); ++ return EAGAIN; ++} ++ ++static void ++ipa_sudo_fetch_cmdgroups_done(struct tevent_req *subreq) ++{ ++ struct ipa_sudo_fetch_state *state = NULL; ++ struct tevent_req *req = NULL; ++ struct sysdb_attrs **attrs; ++ size_t num_attrs; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_sudo_fetch_state); ++ ++ ret = sdap_search_bases_recv(subreq, state, &num_attrs, &attrs); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_IMPORTANT_INFO, "Received %zu sudo command groups\n", ++ num_attrs); ++ ++ ret = ipa_sudo_conv_cmdgroups(state->conv, attrs, num_attrs); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed when converting command groups " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = ipa_sudo_fetch_cmds(req); ++ ++done: ++ if (ret == EOK) { ++ ipa_sudo_fetch_done(req); ++ } else if (ret != EAGAIN) { ++ tevent_req_error(req, ret); ++ } ++ ++ return; ++} ++ ++static errno_t ++ipa_sudo_fetch_cmds(struct tevent_req *req) ++{ ++ struct ipa_sudo_fetch_state *state; ++ struct tevent_req *subreq; ++ char *filter; ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "About to fetch sudo commands\n"); ++ ++ state = tevent_req_data(req, struct ipa_sudo_fetch_state); ++ ++ if (ipa_sudo_conv_has_cmds(state->conv)) { ++ DEBUG(SSSDBG_TRACE_FUNC, "No commands needs to be downloaded\n"); ++ return EOK; ++ } ++ ++ filter = ipa_sudo_conv_cmd_filter(state, state->conv); ++ if (filter == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build filter\n"); ++ return ENOMEM; ++ } ++ ++ subreq = sdap_search_bases_send(state, state->ev, state->sdap_opts, ++ state->sh, state->sudo_sb, ++ state->map_cmd, true, 0, ++ filter, NULL); ++ if (subreq == NULL) { ++ return ENOMEM; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_sudo_fetch_cmds_done, req); ++ return EAGAIN; ++} ++ ++static void ++ipa_sudo_fetch_cmds_done(struct tevent_req *subreq) ++{ ++ struct ipa_sudo_fetch_state *state = NULL; ++ struct tevent_req *req = NULL; ++ struct sysdb_attrs **attrs; ++ size_t num_attrs; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_sudo_fetch_state); ++ ++ ret = sdap_search_bases_recv(subreq, state, &num_attrs, &attrs); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_IMPORTANT_INFO, "Received %zu sudo commands\n", num_attrs); ++ ++ ret = ipa_sudo_conv_cmds(state->conv, attrs, num_attrs); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed when converting commands " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++done: ++ if (ret == EOK) { ++ ipa_sudo_fetch_done(req); ++ } else if (ret != EAGAIN) { ++ tevent_req_error(req, ret); ++ } ++ ++ return; ++} ++ ++static void ++ipa_sudo_fetch_done(struct tevent_req *req) ++{ ++ struct ipa_sudo_fetch_state *state = NULL; ++ errno_t ret; ++ ++ state = tevent_req_data(req, struct ipa_sudo_fetch_state); ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "About to convert rules\n"); ++ ++ ret = ipa_sudo_conv_result(state, state->conv, ++ &state->rules, &state->num_rules); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to convert rules [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++static errno_t ++ipa_sudo_fetch_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ struct sysdb_attrs ***_rules, ++ size_t *_num_rules) ++{ ++ struct ipa_sudo_fetch_state *state = NULL; ++ state = tevent_req_data(req, struct ipa_sudo_fetch_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ *_rules = talloc_steal(mem_ctx, state->rules); ++ *_num_rules = state->num_rules; ++ ++ return EOK; ++} ++ ++ ++struct ipa_sudo_refresh_state { ++ struct tevent_context *ev; ++ struct sysdb_ctx *sysdb; ++ struct sss_domain_info *domain; ++ struct ipa_sudo_ctx *sudo_ctx; ++ struct ipa_options *ipa_opts; ++ struct sdap_options *sdap_opts; ++ const char *search_filter; ++ const char *delete_filter; ++ ++ struct sdap_id_op *sdap_op; ++ struct sdap_handle *sh; ++ int dp_error; ++ ++ struct sysdb_attrs **rules; ++ size_t num_rules; ++}; ++ ++static errno_t ipa_sudo_refresh_retry(struct tevent_req *req); ++static void ipa_sudo_refresh_connect_done(struct tevent_req *subreq); ++static void ipa_sudo_refresh_host_done(struct tevent_req *subreq); ++static void ipa_sudo_refresh_done(struct tevent_req *subreq); ++ ++struct tevent_req * ++ipa_sudo_refresh_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct ipa_sudo_ctx *sudo_ctx, ++ const char *search_filter, ++ const char *delete_filter) ++{ ++ struct ipa_sudo_refresh_state *state; ++ struct tevent_req *req; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct ipa_sudo_refresh_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n")); ++ return NULL; ++ } ++ ++ state->ev = ev; ++ state->sysdb = sudo_ctx->id_ctx->be->domain->sysdb; ++ state->domain = sudo_ctx->id_ctx->be->domain; ++ state->sudo_ctx = sudo_ctx; ++ state->ipa_opts = sudo_ctx->ipa_opts; ++ state->sdap_opts = sudo_ctx->sdap_opts; ++ state->dp_error = DP_ERR_FATAL; ++ ++ state->sdap_op = sdap_id_op_create(state, ++ sudo_ctx->id_ctx->conn->conn_cache); ++ if (!state->sdap_op) { ++ DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create() failed\n"); ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ state->search_filter = talloc_strdup(state, search_filter); ++ if (search_filter != NULL && state->search_filter == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ state->delete_filter = talloc_strdup(state, delete_filter); ++ if (delete_filter != NULL && state->delete_filter == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ ret = ipa_sudo_refresh_retry(req); ++ if (ret == EAGAIN) { ++ /* asynchronous processing */ ++ return req; ++ } ++ ++immediately: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, state->ev); ++ ++ return req; ++} ++ ++static errno_t ++ipa_sudo_refresh_retry(struct tevent_req *req) ++{ ++ struct ipa_sudo_refresh_state *state; ++ struct tevent_req *subreq; ++ int ret; ++ ++ state = tevent_req_data(req, struct ipa_sudo_refresh_state); ++ ++ subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret); ++ if (subreq == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "sdap_id_op_connect_send() failed: " ++ "%d(%s)\n", ret, strerror(ret)); ++ return ret; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_sudo_refresh_connect_done, req); ++ ++ return EAGAIN; ++} ++ ++static void ++ipa_sudo_refresh_connect_done(struct tevent_req *subreq) ++{ ++ struct ipa_sudo_refresh_state *state; ++ const char *hostname; ++ struct tevent_req *req; ++ int dp_error; ++ int ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_sudo_refresh_state); ++ ++ ret = sdap_id_op_connect_recv(subreq, &dp_error); ++ talloc_zfree(subreq); ++ ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "SUDO LDAP connection failed " ++ "[%d]: %s\n", ret, strerror(ret)); ++ state->dp_error = dp_error; ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ state->sh = sdap_id_op_handle(state->sdap_op); ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "SUDO LDAP connection successful\n"); ++ DEBUG(SSSDBG_TRACE_FUNC, "About to fetch host information\n"); ++ ++ /* Obtain host information. */ ++ hostname = dp_opt_get_string(state->ipa_opts->basic, IPA_HOSTNAME); ++ ++ subreq = ipa_host_info_send(state, state->ev, ++ state->sh, state->sdap_opts, hostname, ++ state->ipa_opts->host_map, ++ state->ipa_opts->hostgroup_map, ++ state->ipa_opts->host_search_bases); ++ if (subreq == NULL) { ++ state->dp_error = DP_ERR_FATAL; ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_sudo_refresh_host_done, req); ++} ++ ++static void ++ipa_sudo_refresh_host_done(struct tevent_req *subreq) ++{ ++ struct ipa_sudo_refresh_state *state; ++ struct ipa_hostinfo *host; ++ struct tevent_req *req; ++ int ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_sudo_refresh_state); ++ ++ host = talloc_zero(state, struct ipa_hostinfo); ++ if (host == NULL) { ++ state->dp_error = DP_ERR_FATAL; ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ ++ ret = ipa_host_info_recv(subreq, host, &host->num_hosts, &host->hosts, ++ &host->num_hostgroups, &host->hostgroups); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve host information " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ state->dp_error = DP_ERR_FATAL; ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ subreq = ipa_sudo_fetch_send(state, state->ev, state->sysdb, ++ state->sudo_ctx, host, ++ state->sdap_opts->user_map, ++ state->sdap_opts->group_map, ++ state->ipa_opts->host_map, ++ state->ipa_opts->hostgroup_map, state->sh); ++ if (subreq == NULL) { ++ state->dp_error = DP_ERR_FATAL; ++ tevent_req_error(req, ENOMEM); ++ return; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_sudo_refresh_done, req); ++} ++ ++static void ++ipa_sudo_refresh_done(struct tevent_req *subreq) ++{ ++ struct ipa_sudo_refresh_state *state; ++ struct tevent_req *req; ++ bool in_transaction = false; ++ errno_t sret; ++ int ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_sudo_refresh_state); ++ ++ ret = ipa_sudo_fetch_recv(state, subreq, &state->rules, &state->num_rules); ++ talloc_zfree(subreq); ++ ++ ret = sdap_id_op_done(state->sdap_op, ret, &state->dp_error); ++ if (state->dp_error == DP_ERR_OK && ret != EOK) { ++ /* retry */ ++ ret = ipa_sudo_refresh_retry(req); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ } ++ return; ++ } else if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ ret = sysdb_transaction_start(state->sysdb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); ++ goto done; ++ } ++ in_transaction = true; ++ ++ ret = sysdb_sudo_purge(state->domain, state->delete_filter, ++ state->rules, state->num_rules); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = sysdb_sudo_store(state->domain, state->rules, state->num_rules); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = sysdb_transaction_commit(state->sysdb); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n"); ++ goto done; ++ } ++ in_transaction = false; ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Sudo rules are successfully stored in cache\n"); ++ ++done: ++ if (in_transaction) { ++ sret = sysdb_transaction_cancel(state->sysdb); ++ if (sret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n"); ++ } ++ } ++ ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++errno_t ++ipa_sudo_refresh_recv(struct tevent_req *req, ++ int *dp_error, ++ size_t *_num_rules) ++{ ++ struct ipa_sudo_refresh_state *state = NULL; ++ state = tevent_req_data(req, struct ipa_sudo_refresh_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ *dp_error = state->dp_error; ++ ++ if (_num_rules != NULL) { ++ *_num_rules = state->num_rules; ++ } ++ ++ return EOK; ++} +diff --git a/src/providers/ipa/ipa_sudo_conversion.c b/src/providers/ipa/ipa_sudo_conversion.c +new file mode 100644 +index 0000000000000000000000000000000000000000..2f28f837e62b42406ddda25b3f63832c1abb950d +--- /dev/null ++++ b/src/providers/ipa/ipa_sudo_conversion.c +@@ -0,0 +1,1158 @@ ++/* ++ Authors: ++ Pavel Březina ++ ++ Copyright (C) 2015 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#include ++#include ++#include ++ ++#include "providers/ldap/sdap.h" ++#include "providers/ipa/ipa_common.h" ++#include "providers/ipa/ipa_dn.h" ++#include "db/sysdb_sudo.h" ++#include "db/sysdb.h" ++#include "util/util.h" ++ ++#define SUDO_DN_CMDGROUPS "sudocmdgroups" ++#define SUDO_DN_CMDS "sudocmds" ++#define SUDO_DN_CONTAINER "sudo" ++#define SUDO_DN_CN "cn" ++ ++#define MATCHDN(cat) SUDO_DN_CN, (cat), SUDO_DN_CN, SUDO_DN_CONTAINER ++#define MATCHDN_CMDGROUPS MATCHDN(SUDO_DN_CMDGROUPS) ++#define MATCHDN_CMDS MATCHDN(SUDO_DN_CMDS) ++ ++#define MATCHRDN_CMDGROUPS(map) (map)[IPA_AT_SUDOCMDGROUP_NAME].name, MATCHDN_CMDGROUPS ++#define MATCHRDN_CMDS(map) (map)[IPA_AT_SUDOCMD_UUID].name, MATCHDN_CMDS ++ ++#define MATCHRDN_USER(map) (map)[SDAP_AT_USER_NAME].name, "cn", "users", "cn", "accounts" ++#define MATCHRDN_GROUP(map) (map)[SDAP_AT_GROUP_NAME].name, "cn", "groups", "cn", "accounts" ++#define MATCHRDN_HOST(map) (map)[IPA_AT_HOST_FQDN].name, "cn", "computers", "cn", "accounts" ++#define MATCHRDN_HOSTGROUP(map) (map)[IPA_AT_HOSTGROUP_NAME].name, "cn", "hostgroups", "cn", "accounts" ++ ++struct ipa_sudo_conv { ++ struct sysdb_ctx *sysdb; ++ ++ struct sdap_attr_map *map_rule; ++ struct sdap_attr_map *map_cmdgroup; ++ struct sdap_attr_map *map_cmd; ++ struct sdap_attr_map *map_user; ++ struct sdap_attr_map *map_group; ++ struct sdap_attr_map *map_host; ++ struct sdap_attr_map *map_hostgroup; ++ ++ hash_table_t *rules; ++ hash_table_t *cmdgroups; ++ hash_table_t *cmds; ++}; ++ ++struct ipa_sudo_dn_list { ++ struct ipa_sudo_dn_list *prev, *next; ++ const char *dn; ++}; ++ ++struct ipa_sudo_rulemember { ++ struct ipa_sudo_dn_list *cmdgroups; ++ struct ipa_sudo_dn_list *cmds; ++}; ++ ++struct ipa_sudo_rule { ++ struct sysdb_attrs *attrs; ++ struct ipa_sudo_rulemember allow; ++ struct ipa_sudo_rulemember deny; ++}; ++ ++struct ipa_sudo_cmdgroup { ++ struct ipa_sudo_dn_list *cmds; ++ const char **expanded; ++}; ++ ++static size_t ++ipa_sudo_dn_list_count(struct ipa_sudo_dn_list *list) ++{ ++ struct ipa_sudo_dn_list *item; ++ size_t i; ++ ++ for (i = 0, item = list; item != NULL; item = item->next, i++) { ++ /* no op */ ++ } ++ ++ return i; ++} ++ ++static errno_t ++ipa_sudo_conv_store(hash_table_t *table, ++ const char *key, ++ void *value) ++{ ++ hash_key_t hkey; ++ hash_value_t hvalue; ++ int hret; ++ ++ if (table == NULL || key == NULL) { ++ return EINVAL; ++ } ++ ++ hkey.type = HASH_KEY_STRING; ++ hkey.str = discard_const(key); ++ ++ /* If value is NULL we don't want to override existing entry. */ ++ if (value == NULL && hash_has_key(table, &hkey)) { ++ return EEXIST; ++ } ++ ++ hvalue.type = HASH_VALUE_PTR; ++ hvalue.ptr = value; ++ ++ hret = hash_enter(table, &hkey, &hvalue); ++ if (hret != HASH_SUCCESS) { ++ return EIO; ++ } ++ ++ if (value != NULL) { ++ talloc_steal(table, value); ++ } ++ ++ return EOK; ++} ++ ++static void * ++ipa_sudo_conv_lookup(hash_table_t *table, ++ const char *key) ++{ ++ hash_key_t hkey; ++ hash_value_t hvalue; ++ int hret; ++ ++ hkey.type = HASH_KEY_STRING; ++ hkey.str = discard_const(key); ++ ++ hret = hash_lookup(table, &hkey, &hvalue); ++ if (hret == HASH_ERROR_KEY_NOT_FOUND) { ++ DEBUG(SSSDBG_OP_FAILURE, "Key not found %s\n", key); ++ return NULL; ++ } else if (hret != HASH_SUCCESS) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup value [%d]\n", hret); ++ return NULL; ++ } ++ ++ return hvalue.ptr; ++} ++ ++static errno_t ++store_rulemember(TALLOC_CTX *mem_ctx, ++ struct ipa_sudo_dn_list **list, ++ hash_table_t *table, ++ const char *dn) ++{ ++ struct ipa_sudo_dn_list *item; ++ errno_t ret; ++ ++ item = talloc_zero(mem_ctx, struct ipa_sudo_dn_list); ++ if (item == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = ipa_sudo_conv_store(table, dn, NULL); ++ if (ret != EOK && ret != EEXIST) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to store DN %s [%d]: %s\n", ++ dn, ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ item->dn = talloc_steal(item, dn); ++ DLIST_ADD(*list, item); ++ ++done: ++ if (ret != EOK && ret != EEXIST) { ++ talloc_free(item); ++ } ++ ++ return ret; ++} ++ ++static errno_t ++process_rulemember(TALLOC_CTX *mem_ctx, ++ struct ipa_sudo_conv *conv, ++ struct ipa_sudo_rulemember *rulemember, ++ struct sysdb_attrs *rule, ++ const char *attr) ++{ ++ TALLOC_CTX *tmp_ctx; ++ const char **members; ++ errno_t ret; ++ int i; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = sysdb_attrs_get_string_array(rule, attr, tmp_ctx, &members); ++ if (ret == ENOENT) { ++ ret = EOK; ++ goto done; ++ } else if (ret != EOK) { ++ goto done; ++ } ++ ++ for (i = 0; members[i] != NULL; i++) { ++ if (ipa_check_rdn_bool(conv->sysdb, members[i], ++ MATCHRDN_CMDGROUPS(conv->map_cmdgroup))) { ++ ret = store_rulemember(mem_ctx, &rulemember->cmdgroups, ++ conv->cmdgroups, members[i]); ++ if (ret == EOK) { ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Found sudo command group %s\n", ++ members[i]); ++ } else if (ret != EEXIST) { ++ goto done; ++ } ++ } else if (ipa_check_rdn_bool(conv->sysdb, members[i], ++ MATCHRDN_CMDS(conv->map_cmd))) { ++ ret = store_rulemember(mem_ctx, &rulemember->cmds, ++ conv->cmds, members[i]); ++ if (ret == EOK) { ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Found sudo command group %s\n", ++ members[i]); ++ } else if (ret != EEXIST) { ++ goto done; ++ } ++ } else { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Invalid member DN %s, skipping...\n", ++ members[i]); ++ continue; ++ } ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++static errno_t ++process_allowcmd(struct ipa_sudo_conv *conv, ++ struct ipa_sudo_rule *rule) ++{ ++ return process_rulemember(rule, conv, &rule->allow, rule->attrs, ++ SYSDB_IPA_SUDORULE_ALLOWCMD); ++} ++ ++static errno_t ++process_denycmd(struct ipa_sudo_conv *conv, ++ struct ipa_sudo_rule *rule) ++{ ++ return process_rulemember(rule, conv, &rule->deny, rule->attrs, ++ SYSDB_IPA_SUDORULE_DENYCMD); ++} ++ ++static errno_t ++process_cmdgroupmember(struct ipa_sudo_conv *conv, ++ struct ipa_sudo_cmdgroup *cmdgroup, ++ struct sysdb_attrs *attrs) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct ipa_sudo_dn_list *item; ++ const char **members; ++ errno_t ret; ++ int i; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = sysdb_attrs_get_string_array(attrs, SYSDB_MEMBER, tmp_ctx, &members); ++ if (ret == ENOENT) { ++ ret = EOK; ++ goto done; ++ } else if (ret != EOK) { ++ goto done; ++ } ++ ++ for (i = 0; members[i] != NULL; i++) { ++ ret = ipa_sudo_conv_store(conv->cmds, members[i], NULL); ++ if (ret == EOK) { ++ DEBUG(SSSDBG_TRACE_INTERNAL, "Found sudo command %s\n", ++ members[i]); ++ } else if (ret != EEXIST) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to store DN [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ item = talloc_zero(tmp_ctx, struct ipa_sudo_dn_list); ++ if (item == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ item->dn = talloc_steal(item, members[i]); ++ DLIST_ADD(cmdgroup->cmds, item); ++ talloc_steal(cmdgroup, item); ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++struct ipa_sudo_conv * ++ipa_sudo_conv_init(TALLOC_CTX *mem_ctx, ++ struct sysdb_ctx *sysdb, ++ struct sdap_attr_map *map_rule, ++ struct sdap_attr_map *map_cmdgroup, ++ struct sdap_attr_map *map_cmd, ++ struct sdap_attr_map *map_user, ++ struct sdap_attr_map *map_group, ++ struct sdap_attr_map *map_host, ++ struct sdap_attr_map *map_hostgroup) ++{ ++ struct ipa_sudo_conv *conv; ++ errno_t ret; ++ ++ conv = talloc_zero(mem_ctx, struct ipa_sudo_conv); ++ if (conv == NULL) { ++ return NULL; ++ } ++ ++ conv->sysdb = sysdb; ++ conv->map_rule = map_rule; ++ conv->map_cmdgroup = map_cmdgroup; ++ conv->map_cmd = map_cmd; ++ conv->map_user = map_user; ++ conv->map_group = map_group; ++ conv->map_host = map_host; ++ conv->map_hostgroup = map_hostgroup; ++ ++ ret = sss_hash_create(conv, 20, &conv->rules); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create hash table [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = sss_hash_create(conv, 20, &conv->cmdgroups); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create hash table [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = sss_hash_create(conv, 20, &conv->cmds); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create hash table [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++done: ++ if (ret != EOK) { ++ talloc_free(conv); ++ return NULL; ++ } ++ ++ return conv; ++} ++ ++errno_t ++ipa_sudo_conv_rules(struct ipa_sudo_conv *conv, ++ struct sysdb_attrs **rules, ++ size_t num_rules) ++{ ++ struct ipa_sudo_rule *rule = NULL; ++ const char *key; ++ errno_t ret; ++ size_t i; ++ ++ if (num_rules == 0) { ++ /* We're done here. */ ++ return EOK; ++ } ++ ++ for (i = 0; i < num_rules; i++) { ++ ret = sysdb_attrs_get_string(rules[i], SYSDB_NAME, &key); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Failed to get rule name, skipping " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ continue; ++ } ++ ++ rule = talloc_zero(conv->rules, struct ipa_sudo_rule); ++ if (rule == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ rule->attrs = rules[i]; ++ ++ ret = process_allowcmd(conv, rule); ++ if (ret != EOK && ret != EEXIST) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to process memberAllowCmd " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ return ret; ++ } ++ ++ ret = process_denycmd(conv, rule); ++ if (ret != EOK && ret != EEXIST) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to process memberDenyCmd " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ return ret; ++ } ++ ++ ret = ipa_sudo_conv_store(conv->rules, key, rule); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to store rule into table " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ talloc_steal(rule, rule->attrs); ++ rule = NULL; ++ } ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ talloc_free(rule); ++ } ++ ++ return ret; ++} ++ ++errno_t ++ipa_sudo_conv_cmdgroups(struct ipa_sudo_conv *conv, ++ struct sysdb_attrs **cmdgroups, ++ size_t num_cmdgroups) ++{ ++ struct ipa_sudo_cmdgroup *cmdgroup = NULL; ++ const char *key; ++ errno_t ret; ++ size_t i; ++ ++ if (num_cmdgroups == 0) { ++ /* We're done here. */ ++ return EOK; ++ } ++ ++ for (i = 0; i < num_cmdgroups; i++) { ++ ret = sysdb_attrs_get_string(cmdgroups[i], SYSDB_ORIG_DN, &key); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Failed to get command group DN, " ++ "skipping [%d]: %s\n", ret, sss_strerror(ret)); ++ continue; ++ } ++ ++ cmdgroup = talloc_zero(conv->cmdgroups, struct ipa_sudo_cmdgroup); ++ if (cmdgroup == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = process_cmdgroupmember(conv, cmdgroup, cmdgroups[i]); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to process member " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ return ret; ++ } ++ ++ ret = ipa_sudo_conv_store(conv->cmdgroups, key, cmdgroup); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to store command group into " ++ "table [%d]: %s\n", ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ cmdgroup = NULL; ++ } ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ talloc_free(cmdgroup); ++ } ++ ++ return ret; ++} ++ ++errno_t ++ipa_sudo_conv_cmds(struct ipa_sudo_conv *conv, ++ struct sysdb_attrs **cmds, ++ size_t num_cmds) ++{ ++ const char *key; ++ const char *cmd; ++ errno_t ret; ++ size_t i; ++ ++ if (num_cmds == 0) { ++ /* We're done here. */ ++ return EOK; ++ } ++ ++ for (i = 0; i < num_cmds; i++) { ++ ret = sysdb_attrs_get_string(cmds[i], SYSDB_ORIG_DN, &key); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Failed to get command DN, skipping " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ continue; ++ } ++ ++ ret = sysdb_attrs_get_string(cmds[i], SYSDB_IPA_SUDOCMD_SUDOCMD, &cmd); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Failed to get command, skipping " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ continue; ++ } ++ ++ ret = ipa_sudo_conv_store(conv->cmds, key, discard_const(cmd)); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to store command into table " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ goto done; ++ } ++ } ++ ++ ret = EOK; ++ ++done: ++ return ret; ++} ++ ++bool ++ipa_sudo_conv_has_cmdgroups(struct ipa_sudo_conv *conv) ++{ ++ return hash_count(conv->cmdgroups) == 0; ++} ++ ++bool ++ipa_sudo_conv_has_cmds(struct ipa_sudo_conv *conv) ++{ ++ return hash_count(conv->cmds) == 0; ++} ++ ++static char * ++build_filter(TALLOC_CTX *mem_ctx, ++ struct sysdb_ctx *sysdb, ++ hash_table_t *table, ++ const char *class, ++ const char *rdn_attr, ++ const char *category) ++{ ++ TALLOC_CTX *tmp_ctx; ++ hash_key_t *keys; ++ unsigned long int count; ++ unsigned long int i; ++ char *filter; ++ char *rdn_val; ++ char *safe_rdn; ++ errno_t ret; ++ int hret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return NULL; ++ } ++ ++ hret = hash_keys(table, &count, &keys); ++ if (hret != HASH_SUCCESS) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ talloc_steal(tmp_ctx, keys); ++ ++ filter = talloc_strdup(tmp_ctx, ""); ++ if (filter == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ for (i = 0; i < count; i++) { ++ ret = ipa_get_rdn(tmp_ctx, sysdb, keys[i].str, &rdn_val, ++ rdn_attr, MATCHDN(category)); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get member %s [%d]: %s\n", ++ keys[i].str, ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = sss_filter_sanitize(tmp_ctx, rdn_val, &safe_rdn); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to sanitize DN " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ filter = talloc_asprintf_append(filter, "(%s=%s)", rdn_attr, safe_rdn); ++ if (filter == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ filter = talloc_asprintf(filter, "(&(objectClass=%s)(|%s))", ++ class, filter); ++ if (filter == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ talloc_steal(mem_ctx, filter); ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ ++ if (ret != EOK) { ++ return NULL; ++ } ++ ++ return filter; ++} ++ ++char * ++ipa_sudo_conv_cmdgroup_filter(TALLOC_CTX *mem_ctx, ++ struct ipa_sudo_conv *conv) ++{ ++ const char *rdn_attr = conv->map_cmdgroup[IPA_AT_SUDOCMDGROUP_NAME].name; ++ const char *class = conv->map_cmdgroup[IPA_OC_SUDOCMDGROUP].name; ++ ++ return build_filter(mem_ctx, conv->sysdb, conv->cmdgroups, class, ++ rdn_attr, SUDO_DN_CMDGROUPS); ++} ++ ++char * ++ipa_sudo_conv_cmd_filter(TALLOC_CTX *mem_ctx, ++ struct ipa_sudo_conv *conv) ++{ ++ const char *rdn_attr = conv->map_cmd[IPA_AT_SUDOCMD_UUID].name; ++ const char *class = conv->map_cmd[IPA_OC_SUDOCMD].name; ++ ++ return build_filter(mem_ctx, conv->sysdb, conv->cmds, class, ++ rdn_attr, SUDO_DN_CMDS); ++} ++ ++struct ipa_sudo_conv_result_ctx { ++ struct ipa_sudo_conv *conv; ++ struct sysdb_attrs **rules; ++ size_t num_rules; ++ errno_t ret; ++}; ++ ++static const char * ++convert_host(TALLOC_CTX *mem_ctx, ++ struct ipa_sudo_conv *conv, ++ const char *value) ++{ ++ char *rdn; ++ const char *group; ++ errno_t ret; ++ ++ ret = ipa_get_rdn(mem_ctx, conv->sysdb, value, &rdn, ++ MATCHRDN_HOST(conv->map_host)); ++ if (ret == EOK) { ++ return rdn; ++ } else if (ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, "ipa_get_rdn() failed on value %s [%d]: %s\n", ++ value, ret, sss_strerror(ret)); ++ return NULL; ++ } ++ ++ ret = ipa_get_rdn(mem_ctx, conv->sysdb, value, &rdn, ++ MATCHRDN_HOSTGROUP(conv->map_hostgroup)); ++ if (ret == ENOENT) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected DN %s\n", value); ++ return NULL; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "ipa_get_rdn() failed on value %s [%d]: %s\n", ++ value, ret, sss_strerror(ret)); ++ return NULL; ++ } ++ ++ group = talloc_asprintf(mem_ctx, "+%s", rdn); ++ talloc_free(rdn); ++ ++ return group; ++} ++ ++static const char * ++convert_user(TALLOC_CTX *mem_ctx, ++ struct ipa_sudo_conv *conv, ++ const char *value) ++{ ++ char *rdn; ++ const char *group; ++ errno_t ret; ++ ++ ret = ipa_get_rdn(mem_ctx, conv->sysdb, value, &rdn, ++ MATCHRDN_USER(conv->map_user)); ++ if (ret == EOK) { ++ return rdn; ++ } else if (ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, "ipa_get_rdn() failed on value %s [%d]: %s\n", ++ value, ret, sss_strerror(ret)); ++ return NULL; ++ } ++ ++ ret = ipa_get_rdn(mem_ctx, conv->sysdb, value, &rdn, ++ MATCHRDN_GROUP(conv->map_group)); ++ if (ret == ENOENT) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected DN %s\n", value); ++ return NULL; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "ipa_get_rdn() failed on value %s [%d]: %s\n", ++ value, ret, sss_strerror(ret)); ++ return NULL; ++ } ++ ++ group = talloc_asprintf(mem_ctx, "%%%s", rdn); ++ talloc_free(rdn); ++ ++ return group; ++} ++ ++static const char * ++convert_group(TALLOC_CTX *mem_ctx, ++ struct ipa_sudo_conv *conv, ++ const char *value) ++{ ++ char *rdn; ++ errno_t ret; ++ ++ ret = ipa_get_rdn(mem_ctx, conv->sysdb, value, &rdn, ++ MATCHRDN_GROUP(conv->map_group)); ++ if (ret == ENOENT) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected DN %s\n", value); ++ return NULL; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "ipa_get_rdn() failed on value %s [%d]: %s\n", ++ value, ret, sss_strerror(ret)); ++ return NULL; ++ } ++ ++ return rdn; ++} ++ ++static const char * ++convert_cat(TALLOC_CTX *mem_ctx, ++ struct ipa_sudo_conv *conv, ++ const char *value) ++{ ++ if (strcmp(value, "all") == 0) { ++ return talloc_strdup(mem_ctx, "ALL"); ++ } ++ ++ return value; ++} ++ ++static errno_t ++convert_attributes(struct ipa_sudo_conv *conv, ++ struct ipa_sudo_rule *rule, ++ struct sysdb_attrs *attrs) ++{ ++ TALLOC_CTX *tmp_ctx; ++ const char **values; ++ const char *value; ++ errno_t ret; ++ int i, j; ++ static struct { ++ const char *ipa; ++ const char *sudo; ++ const char *(*conv_fn)(TALLOC_CTX *mem_ctx, ++ struct ipa_sudo_conv *conv, ++ const char *value); ++ } table[] = {{SYSDB_NAME, SYSDB_SUDO_CACHE_AT_CN , NULL}, ++ {SYSDB_IPA_SUDORULE_HOST, SYSDB_SUDO_CACHE_AT_HOST , convert_host}, ++ {SYSDB_IPA_SUDORULE_USER, SYSDB_SUDO_CACHE_AT_USER , convert_user}, ++ {SYSDB_IPA_SUDORULE_RUNASUSER, SYSDB_SUDO_CACHE_AT_RUNASUSER , convert_user}, ++ {SYSDB_IPA_SUDORULE_RUNASGROUP, SYSDB_SUDO_CACHE_AT_RUNASGROUP , convert_group}, ++ {SYSDB_IPA_SUDORULE_OPTION, SYSDB_SUDO_CACHE_AT_OPTION , NULL}, ++ {SYSDB_IPA_SUDORULE_NOTAFTER, SYSDB_SUDO_CACHE_AT_NOTAFTER , NULL}, ++ {SYSDB_IPA_SUDORULE_NOTBEFORE, SYSDB_SUDO_CACHE_AT_NOTBEFORE , NULL}, ++ {SYSDB_IPA_SUDORULE_SUDOORDER, SYSDB_SUDO_CACHE_AT_ORDER , NULL}, ++ {SYSDB_IPA_SUDORULE_CMDCATEGORY, SYSDB_SUDO_CACHE_AT_COMMAND , convert_cat}, ++ {SYSDB_IPA_SUDORULE_HOSTCATEGORY, SYSDB_SUDO_CACHE_AT_HOST , convert_cat}, ++ {SYSDB_IPA_SUDORULE_USERCATEGORY, SYSDB_SUDO_CACHE_AT_USER , convert_cat}, ++ {SYSDB_IPA_SUDORULE_RUNASUSERCATEGORY, SYSDB_SUDO_CACHE_AT_RUNASUSER , convert_cat}, ++ {SYSDB_IPA_SUDORULE_RUNASGROUPCATEGORY, SYSDB_SUDO_CACHE_AT_RUNASGROUP , convert_cat}, ++ {SYSDB_IPA_SUDORULE_ALLOWCMD, SYSDB_IPA_SUDORULE_ORIGCMD , NULL}, ++ {SYSDB_IPA_SUDORULE_DENYCMD, SYSDB_IPA_SUDORULE_ORIGCMD , NULL}, ++ {NULL, NULL, NULL}}; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ for (i = 0; table[i].ipa != NULL; i++) { ++ ret = sysdb_attrs_get_string_array(rule->attrs, table[i].ipa, ++ tmp_ctx, &values); ++ if (ret == ENOENT) { ++ continue; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to read attribute " ++ "%s [%d]: %s\n", table[i].ipa, ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ for (j = 0; values[j] != NULL; j++) { ++ if (table[i].conv_fn != NULL) { ++ value = table[i].conv_fn(tmp_ctx, conv, values[j]); ++ if (value == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } else { ++ value = values[j]; ++ } ++ ++ ret = sysdb_attrs_add_string_safe(attrs, table[i].sudo, value); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add attribute " ++ "%s [%d]: %s\n", table[i].sudo, ret, sss_strerror(ret)); ++ goto done; ++ } ++ } ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++static const char ** ++combine_cmdgroups(TALLOC_CTX *mem_ctx, ++ struct ipa_sudo_conv *conv, ++ struct ipa_sudo_dn_list *list) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct ipa_sudo_cmdgroup *cmdgroup; ++ struct ipa_sudo_dn_list *listitem; ++ const char **values = NULL; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return NULL; ++ } ++ ++ values = talloc_zero_array(tmp_ctx, const char *, 1); ++ if (values == NULL) { ++ talloc_free(tmp_ctx); ++ return NULL; ++ } ++ ++ DLIST_FOR_EACH(listitem, list) { ++ cmdgroup = ipa_sudo_conv_lookup(conv->cmdgroups, listitem->dn); ++ ++ ret = add_strings_lists(mem_ctx, values, cmdgroup->expanded, ++ false, discard_const(&values)); ++ if (ret != EOK) { ++ talloc_free(tmp_ctx); ++ return NULL; ++ } ++ } ++ ++ talloc_steal(mem_ctx, values); ++ talloc_free(tmp_ctx); ++ ++ return values; ++} ++ ++static const char ** ++combine_cmds(TALLOC_CTX *mem_ctx, ++ struct ipa_sudo_conv *conv, ++ struct ipa_sudo_dn_list *list) ++{ ++ struct ipa_sudo_dn_list *listitem; ++ const char **values; ++ const char *command; ++ size_t count; ++ size_t i; ++ ++ count = ipa_sudo_dn_list_count(list); ++ ++ values = talloc_zero_array(mem_ctx, const char *, count + 1); ++ if (values == NULL) { ++ return NULL; ++ } ++ ++ i = 0; ++ DLIST_FOR_EACH(listitem, list) { ++ command = ipa_sudo_conv_lookup(conv->cmds, listitem->dn); ++ if (command == NULL) { ++ continue; ++ } ++ ++ values[i] = command; ++ i++; ++ } ++ ++ return values; ++} ++ ++static errno_t ++build_sudocommand(struct ipa_sudo_conv *conv, ++ struct ipa_sudo_rulemember *mlist, ++ struct sysdb_attrs *attrs, ++ char prefix) ++{ ++ TALLOC_CTX *tmp_ctx; ++ const char **cmds[2]; ++ const char *command; ++ errno_t ret; ++ int i, j; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ cmds[0] = combine_cmdgroups(tmp_ctx, conv, mlist->cmdgroups); ++ if (cmds[0] == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ cmds[1] = combine_cmds(tmp_ctx, conv, mlist->cmds); ++ if (cmds[1] == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ for (i = 0; i < 2; i++) { ++ for (j = 0; cmds[i][j] != NULL; j++) { ++ if (prefix == '\0') { ++ command = cmds[i][j]; ++ } else { ++ command = talloc_asprintf(tmp_ctx, "%c%s", prefix, cmds[i][j]); ++ if (command == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ ret = sysdb_attrs_add_string_safe(attrs, ++ SYSDB_SUDO_CACHE_AT_COMMAND, command); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add attribute " ++ "%s [%d]: %s\n", SYSDB_SUDO_CACHE_AT_COMMAND, ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ } ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++static errno_t ++convert_sudocommand(struct ipa_sudo_conv *conv, ++ struct ipa_sudo_rule *rule, ++ struct sysdb_attrs *attrs) ++{ ++ TALLOC_CTX *tmp_ctx; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = build_sudocommand(conv, &rule->allow, attrs, '\0'); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build allow commands " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = build_sudocommand(conv, &rule->deny, attrs, '!'); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build deny commands " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++static bool ++rules_iterator(hash_entry_t *item, ++ void *user_data) ++{ ++ struct ipa_sudo_conv_result_ctx *ctx = user_data; ++ struct ipa_sudo_rule *rule = item->value.ptr; ++ struct sysdb_attrs *attrs; ++ ++ if (ctx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: ctx is NULL\n"); ++ return false; ++ } ++ ++ if (rule == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: rule is NULL\n"); ++ ctx->ret = ERR_INTERNAL; ++ return false; ++ } ++ ++ attrs = sysdb_new_attrs(ctx->rules); ++ if (attrs == NULL) { ++ ctx->ret = ENOMEM; ++ return false; ++ } ++ ++ ctx->ret = convert_attributes(ctx->conv, rule, attrs); ++ if (ctx->ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to convert attributes [%d]: %s\n", ++ ctx->ret, sss_strerror(ctx->ret)); ++ talloc_free(attrs); ++ return false; ++ } ++ ++ ctx->ret = convert_sudocommand(ctx->conv, rule, attrs); ++ if (ctx->ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to build sudoCommand [%d]: %s\n", ++ ctx->ret, sss_strerror(ctx->ret)); ++ talloc_free(attrs); ++ return false; ++ } ++ ++ ctx->rules[ctx->num_rules] = attrs; ++ ctx->num_rules++; ++ ++ return true; ++} ++ ++static bool ++cmdgroups_iterator(hash_entry_t *item, ++ void *user_data) ++{ ++ struct ipa_sudo_conv_result_ctx *ctx = user_data; ++ struct ipa_sudo_cmdgroup *cmdgroup = item->value.ptr; ++ const char **values; ++ ++ if (ctx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: ctx is NULL\n"); ++ return false; ++ } ++ ++ if (cmdgroup == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: rule is NULL\n"); ++ ctx->ret = ERR_INTERNAL; ++ return false; ++ } ++ ++ values = combine_cmds(cmdgroup, ctx->conv, cmdgroup->cmds); ++ if (values == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to expand commands\n"); ++ ctx->ret = ENOMEM; ++ return false; ++ } ++ ++ cmdgroup->expanded = values; ++ ctx->ret = EOK; ++ ++ return true; ++} ++ ++errno_t ++ipa_sudo_conv_result(TALLOC_CTX *mem_ctx, ++ struct ipa_sudo_conv *conv, ++ struct sysdb_attrs ***_rules, ++ size_t *_num_rules) ++{ ++ struct ipa_sudo_conv_result_ctx ctx; ++ struct sysdb_attrs **rules; ++ unsigned long num_rules; ++ int hret; ++ ++ num_rules = hash_count(conv->rules); ++ if (num_rules == 0) { ++ *_rules = NULL; ++ *_num_rules = 0; ++ return EOK; ++ } ++ ++ ctx.conv = conv; ++ ctx.rules = NULL; ++ ctx.num_rules = 0; ++ ++ /* If there are no cmdgroups the iterator is not called and ctx.ret is ++ * uninitialized. Since it is ok that there are no cmdgroups initializing ++ * ctx.ret to EOK. */ ++ ctx.ret = EOK; ++ ++ /* Expand commands in command groups. */ ++ hret = hash_iterate(conv->cmdgroups, cmdgroups_iterator, &ctx); ++ if (hret != HASH_SUCCESS) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to iterate over command groups " ++ "[%d]\n", hret); ++ return EIO; ++ } ++ ++ if (ctx.ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to expand command grousp " ++ "[%d]: %s\n", ctx.ret, sss_strerror(ctx.ret)); ++ return ctx.ret; ++ } ++ ++ /* Convert rules. */ ++ rules = talloc_zero_array(mem_ctx, struct sysdb_attrs *, num_rules); ++ if (rules == NULL) { ++ return ENOMEM; ++ } ++ ++ ctx.rules = rules; ++ ctx.num_rules = 0; ++ ++ hret = hash_iterate(conv->rules, rules_iterator, &ctx); ++ if (hret != HASH_SUCCESS) { ++ DEBUG(SSSDBG_OP_FAILURE, "Unable to iterate over rules [%d]\n", hret); ++ return EIO; ++ } ++ ++ if (ctx.ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to convert rules [%d]: %s\n", ++ ctx.ret, sss_strerror(ctx.ret)); ++ talloc_free(rules); ++ return ctx.ret; ++ } ++ ++ *_rules = ctx.rules; ++ *_num_rules = ctx.num_rules; ++ ++ return EOK; ++} +diff --git a/src/providers/ipa/ipa_sudo_refresh.c b/src/providers/ipa/ipa_sudo_refresh.c +new file mode 100644 +index 0000000000000000000000000000000000000000..6fb8f66af607440ddcbb266c0b049ed99bf235b9 +--- /dev/null ++++ b/src/providers/ipa/ipa_sudo_refresh.c +@@ -0,0 +1,195 @@ ++/* ++ Authors: ++ Pavel Březina ++ ++ Copyright (C) 2015 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#include ++#include ++#include ++ ++#include "util/util.h" ++#include "providers/dp_ptask.h" ++#include "providers/ipa/ipa_sudo.h" ++#include "providers/ldap/sdap_sudo_shared.h" ++#include "db/sysdb_sudo.h" ++ ++struct ipa_sudo_full_refresh_state { ++ struct ipa_sudo_ctx *sudo_ctx; ++ struct sss_domain_info *domain; ++ int dp_error; ++}; ++ ++static void ipa_sudo_full_refresh_done(struct tevent_req *subreq); ++ ++struct tevent_req * ++ipa_sudo_full_refresh_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct ipa_sudo_ctx *sudo_ctx) ++{ ++ struct ipa_sudo_full_refresh_state *state; ++ struct tevent_req *subreq; ++ struct tevent_req *req; ++ char *delete_filter; ++ int ret; ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct ipa_sudo_full_refresh_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); ++ return NULL; ++ } ++ ++ sudo_ctx->full_refresh_in_progress = true; ++ ++ state->domain = sudo_ctx->id_ctx->be->domain; ++ state->sudo_ctx = sudo_ctx; ++ ++ /* Remove all rules from cache */ ++ delete_filter = talloc_asprintf(state, "(%s=%s)", SYSDB_OBJECTCLASS, ++ SYSDB_SUDO_CACHE_OC); ++ if (delete_filter == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Issuing a full refresh of sudo rules\n"); ++ ++ subreq = ipa_sudo_refresh_send(state, ev, sudo_ctx, NULL, delete_filter); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_sudo_full_refresh_done, req); ++ ++ return req; ++ ++immediately: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ ++ return req; ++} ++ ++static void ++ipa_sudo_full_refresh_done(struct tevent_req *subreq) ++{ ++ struct ipa_sudo_full_refresh_state *state; ++ struct tevent_req *req; ++ int ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_sudo_full_refresh_state); ++ ++ ret = ipa_sudo_refresh_recv(subreq, &state->dp_error, NULL); ++ talloc_zfree(subreq); ++ if (ret != EOK || state->dp_error != DP_ERR_OK) { ++ goto done; ++ } ++ ++ state->sudo_ctx->full_refresh_done = true; ++ ++ ret = sysdb_sudo_set_last_full_refresh(state->domain, time(NULL)); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Unable to save time of " ++ "a successful full refresh\n"); ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Successful full refresh of sudo rules\n"); ++ ++done: ++ state->sudo_ctx->full_refresh_in_progress = false; ++ ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++int ++ipa_sudo_full_refresh_recv(struct tevent_req *req, ++ int *dp_error) ++{ ++ struct ipa_sudo_full_refresh_state *state; ++ state = tevent_req_data(req, struct ipa_sudo_full_refresh_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ *dp_error = state->dp_error; ++ ++ return EOK; ++} ++ ++static struct tevent_req * ++ipa_sudo_ptask_full_refresh_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct be_ctx *be_ctx, ++ struct be_ptask *be_ptask, ++ void *pvt) ++{ ++ struct ipa_sudo_ctx *sudo_ctx; ++ sudo_ctx = talloc_get_type(pvt, struct ipa_sudo_ctx); ++ ++ return ipa_sudo_full_refresh_send(mem_ctx, be_ctx->ev, sudo_ctx); ++} ++ ++static errno_t ++ipa_sudo_ptask_full_refresh_recv(struct tevent_req *req) ++{ ++ int dp_error; ++ ++ return ipa_sudo_full_refresh_recv(req, &dp_error); ++} ++ ++static struct tevent_req * ++ipa_sudo_ptask_smart_refresh_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct be_ctx *be_ctx, ++ struct be_ptask *be_ptask, ++ void *pvt) ++{ ++ struct ipa_sudo_ctx *sudo_ctx; ++ sudo_ctx = talloc_get_type(pvt, struct ipa_sudo_ctx); ++ ++ return ipa_sudo_full_refresh_send(mem_ctx, be_ctx->ev, sudo_ctx); ++} ++ ++static errno_t ++ipa_sudo_ptask_smart_refresh_recv(struct tevent_req *req) ++{ ++ int dp_error; ++ ++ return ipa_sudo_full_refresh_recv(req, &dp_error); ++} ++ ++errno_t ++ipa_sudo_ptask_setup(struct be_ctx *be_ctx, struct ipa_sudo_ctx *sudo_ctx) ++{ ++ return sdap_sudo_ptask_setup_generic(be_ctx, sudo_ctx->id_ctx->opts->basic, ++ ipa_sudo_ptask_full_refresh_send, ++ ipa_sudo_ptask_full_refresh_recv, ++ ipa_sudo_ptask_smart_refresh_send, ++ ipa_sudo_ptask_smart_refresh_recv, ++ sudo_ctx); ++} +-- +2.5.0 + diff --git a/0028-IPA-SUDO-Implement-rules-refresh.patch b/0028-IPA-SUDO-Implement-rules-refresh.patch new file mode 100644 index 0000000..8698284 --- /dev/null +++ b/0028-IPA-SUDO-Implement-rules-refresh.patch @@ -0,0 +1,315 @@ +From 1f278025259661dbbec6d9d9cca4f4b8ba6decca Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 17 Dec 2015 14:00:21 +0100 +Subject: [PATCH 28/49] IPA SUDO: Implement rules refresh + +Reviewed-by: Sumit Bose +(cherry picked from commit 9630a4614ba4d5f68e967d4e108893550a996f30) +--- + src/providers/ipa/ipa_sudo.c | 11 +++ + src/providers/ipa/ipa_sudo.h | 11 +++ + src/providers/ipa/ipa_sudo_async.c | 12 ++- + src/providers/ipa/ipa_sudo_conversion.c | 2 +- + src/providers/ipa/ipa_sudo_refresh.c | 155 ++++++++++++++++++++++++++++++++ + 5 files changed, 186 insertions(+), 5 deletions(-) + +diff --git a/src/providers/ipa/ipa_sudo.c b/src/providers/ipa/ipa_sudo.c +index 3e73bd30fa86f394b3ef822d59c7b0e539c92ca2..b4633858f8b1eda870dd1014f998bd7215d0bdbf 100644 +--- a/src/providers/ipa/ipa_sudo.c ++++ b/src/providers/ipa/ipa_sudo.c +@@ -211,6 +211,7 @@ ipa_sudo_reply(struct tevent_req *req) + { + struct be_sudo_req *sudo_req; + struct be_req *be_req; ++ bool deleted; + int dp_error; + int ret; + +@@ -221,6 +222,12 @@ ipa_sudo_reply(struct tevent_req *req) + case BE_REQ_SUDO_FULL: + ret = ipa_sudo_full_refresh_recv(req, &dp_error); + break; ++ case BE_REQ_SUDO_RULES: ++ ret = ipa_sudo_rules_refresh_recv(req, &dp_error, &deleted); ++ if (ret == EOK && deleted == true) { ++ ret = ENOENT; ++ } ++ break; + default: + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request type: %d\n", + sudo_req->type); +@@ -256,6 +263,10 @@ ipa_sudo_handler(struct be_req *be_req) + case BE_REQ_SUDO_FULL: + req = ipa_sudo_full_refresh_send(be_req, be_ctx->ev, sudo_ctx); + break; ++ case BE_REQ_SUDO_RULES: ++ req = ipa_sudo_rules_refresh_send(be_req, be_ctx->ev, sudo_ctx, ++ sudo_req->rules); ++ break; + default: + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request type: %d\n", + sudo_req->type); +diff --git a/src/providers/ipa/ipa_sudo.h b/src/providers/ipa/ipa_sudo.h +index 1ef50a7f352182bdc6607b2fd8ee3d72ccab391d..9dd72948732f4b6e19f4a6546128c5319cd97bda 100644 +--- a/src/providers/ipa/ipa_sudo.h ++++ b/src/providers/ipa/ipa_sudo.h +@@ -50,6 +50,11 @@ int + ipa_sudo_full_refresh_recv(struct tevent_req *req, + int *dp_error); + ++int ++ipa_sudo_rules_refresh_recv(struct tevent_req *req, ++ int *dp_error, ++ bool *deleted); ++ + struct tevent_req * + ipa_sudo_refresh_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, +@@ -57,6 +62,12 @@ ipa_sudo_refresh_send(TALLOC_CTX *mem_ctx, + const char *search_filter, + const char *delete_filter); + ++struct tevent_req * ++ipa_sudo_rules_refresh_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct ipa_sudo_ctx *sudo_ctx, ++ char **rules); ++ + errno_t + ipa_sudo_refresh_recv(struct tevent_req *req, + int *dp_error, +diff --git a/src/providers/ipa/ipa_sudo_async.c b/src/providers/ipa/ipa_sudo_async.c +index 9ddda1b41a0b3c6ceb33e6d665749948ae835a97..cea85cdbfc21598164557b70a7055fd4b786ba8a 100644 +--- a/src/providers/ipa/ipa_sudo_async.c ++++ b/src/providers/ipa/ipa_sudo_async.c +@@ -140,6 +140,7 @@ struct ipa_sudo_fetch_state { + struct sdap_options *sdap_opts; + struct ipa_hostinfo *host; + struct sdap_handle *sh; ++ const char *search_filter; + + struct sdap_attr_map *map_cmdgroup; + struct sdap_attr_map *map_rule; +@@ -169,7 +170,8 @@ ipa_sudo_fetch_send(TALLOC_CTX *mem_ctx, + struct sdap_attr_map *map_group, + struct sdap_attr_map *map_host, + struct sdap_attr_map *map_hostgroup, +- struct sdap_handle *sh) ++ struct sdap_handle *sh, ++ const char *search_filter) + { + struct ipa_sudo_fetch_state *state = NULL; + struct tevent_req *req = NULL; +@@ -188,6 +190,7 @@ ipa_sudo_fetch_send(TALLOC_CTX *mem_ctx, + state->sdap_opts = sudo_ctx->sdap_opts; + state->host = host; + state->sh = sh; ++ state->search_filter = search_filter == NULL ? "" : search_filter; + + state->map_cmdgroup = sudo_ctx->sudocmdgroup_map; + state->map_rule = sudo_ctx->sudorule_map; +@@ -241,10 +244,10 @@ ipa_sudo_fetch_rules(struct tevent_req *req) + return ENOMEM; + } + +- filter = talloc_asprintf(state, "(&(objectClass=%s)(%s=TRUE)%s)", ++ filter = talloc_asprintf(state, "(&(objectClass=%s)(%s=TRUE)%s%s)", + map[IPA_OC_SUDORULE].name, + map[IPA_AT_SUDORULE_ENABLED].name, +- host_filter); ++ host_filter, state->search_filter); + talloc_zfree(host_filter); + if (filter == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build filter\n"); +@@ -678,7 +681,8 @@ ipa_sudo_refresh_host_done(struct tevent_req *subreq) + state->sdap_opts->user_map, + state->sdap_opts->group_map, + state->ipa_opts->host_map, +- state->ipa_opts->hostgroup_map, state->sh); ++ state->ipa_opts->hostgroup_map, state->sh, ++ state->search_filter); + if (subreq == NULL) { + state->dp_error = DP_ERR_FATAL; + tevent_req_error(req, ENOMEM); +diff --git a/src/providers/ipa/ipa_sudo_conversion.c b/src/providers/ipa/ipa_sudo_conversion.c +index 2f28f837e62b42406ddda25b3f63832c1abb950d..195e40f248e15756a224335208276f6f7a646cd0 100644 +--- a/src/providers/ipa/ipa_sudo_conversion.c ++++ b/src/providers/ipa/ipa_sudo_conversion.c +@@ -1124,7 +1124,7 @@ ipa_sudo_conv_result(TALLOC_CTX *mem_ctx, + } + + if (ctx.ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Unable to expand command grousp " ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to expand command groups " + "[%d]: %s\n", ctx.ret, sss_strerror(ctx.ret)); + return ctx.ret; + } +diff --git a/src/providers/ipa/ipa_sudo_refresh.c b/src/providers/ipa/ipa_sudo_refresh.c +index 6fb8f66af607440ddcbb266c0b049ed99bf235b9..f1b99c0de96dd2226eb3181ce44e54c019139c6e 100644 +--- a/src/providers/ipa/ipa_sudo_refresh.c ++++ b/src/providers/ipa/ipa_sudo_refresh.c +@@ -141,6 +141,161 @@ ipa_sudo_full_refresh_recv(struct tevent_req *req, + return EOK; + } + ++struct ipa_sudo_rules_refresh_state { ++ size_t num_rules; ++ int dp_error; ++ bool deleted; ++}; ++ ++static void ipa_sudo_rules_refresh_done(struct tevent_req *subreq); ++ ++struct tevent_req * ++ipa_sudo_rules_refresh_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct ipa_sudo_ctx *sudo_ctx, ++ char **rules) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct ipa_sudo_rules_refresh_state *state; ++ struct tevent_req *subreq; ++ struct tevent_req *req; ++ char *search_filter; ++ char *delete_filter; ++ char *safe_rule; ++ errno_t ret; ++ int i; ++ ++ req = tevent_req_create(mem_ctx, &state, struct ipa_sudo_rules_refresh_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); ++ return NULL; ++ } ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ if (rules == NULL || rules[0] == NULL) { ++ state->dp_error = DP_ERR_OK; ++ state->num_rules = 0; ++ state->deleted = false; ++ ret = EOK; ++ goto immediately; ++ } ++ ++ search_filter = talloc_zero(tmp_ctx, char); /* assign to tmp_ctx */ ++ delete_filter = talloc_zero(tmp_ctx, char); /* assign to tmp_ctx */ ++ ++ /* Download only selected rules from LDAP. */ ++ /* Remove all selected rules from cache. */ ++ for (i = 0; rules[i] != NULL; i++) { ++ ret = sss_filter_sanitize(tmp_ctx, rules[i], &safe_rule); ++ if (ret != EOK) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ search_filter = talloc_asprintf_append_buffer(search_filter, "(%s=%s)", ++ sudo_ctx->sudorule_map[IPA_AT_SUDORULE_NAME].name, ++ safe_rule); ++ if (search_filter == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ delete_filter = talloc_asprintf_append_buffer(delete_filter, "(%s=%s)", ++ SYSDB_NAME, safe_rule); ++ if (delete_filter == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ } ++ ++ state->num_rules = i; ++ ++ search_filter = talloc_asprintf(tmp_ctx, "(|%s)", search_filter); ++ if (search_filter == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ delete_filter = talloc_asprintf(tmp_ctx, "(&(%s=%s)(|%s))", ++ SYSDB_OBJECTCLASS, SYSDB_SUDO_CACHE_OC, ++ delete_filter); ++ if (delete_filter == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ subreq = ipa_sudo_refresh_send(req, ev, sudo_ctx, search_filter, ++ delete_filter); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_sudo_rules_refresh_done, req); ++ ++ ret = EOK; ++ ++immediately: ++ talloc_free(tmp_ctx); ++ ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ } ++ ++ return req; ++} ++ ++static void ++ipa_sudo_rules_refresh_done(struct tevent_req *subreq) ++{ ++ struct ipa_sudo_rules_refresh_state *state; ++ struct tevent_req *req = NULL; ++ size_t downloaded_rules_num; ++ int ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_sudo_rules_refresh_state); ++ ++ ret = ipa_sudo_refresh_recv(subreq, &state->dp_error, &downloaded_rules_num); ++ talloc_zfree(subreq); ++ if (ret != EOK || state->dp_error != DP_ERR_OK) { ++ goto done; ++ } ++ ++ state->deleted = downloaded_rules_num != state->num_rules ? true : false; ++ ++done: ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++int ++ipa_sudo_rules_refresh_recv(struct tevent_req *req, ++ int *dp_error, ++ bool *deleted) ++{ ++ struct ipa_sudo_rules_refresh_state *state; ++ state = tevent_req_data(req, struct ipa_sudo_rules_refresh_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ *dp_error = state->dp_error; ++ *deleted = state->deleted; ++ ++ return EOK; ++} ++ + static struct tevent_req * + ipa_sudo_ptask_full_refresh_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, +-- +2.5.0 + diff --git a/0029-IPA-SUDO-Remember-USN.patch b/0029-IPA-SUDO-Remember-USN.patch new file mode 100644 index 0000000..b24ea12 --- /dev/null +++ b/0029-IPA-SUDO-Remember-USN.patch @@ -0,0 +1,138 @@ +From 318bdcab400cbe714115e945d016c81037eef18c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 18 Dec 2015 12:34:21 +0100 +Subject: [PATCH 29/49] IPA SUDO: Remember USN + +Reviewed-by: Sumit Bose +(cherry picked from commit d06cc0974e59cd6cf1da45cc8c60d6e822b731c2) +--- + src/providers/ipa/ipa_sudo_async.c | 50 ++++++++++++++++++++++++++++++++++++-- + 1 file changed, 48 insertions(+), 2 deletions(-) + +diff --git a/src/providers/ipa/ipa_sudo_async.c b/src/providers/ipa/ipa_sudo_async.c +index cea85cdbfc21598164557b70a7055fd4b786ba8a..d52b97da17337b224c4be4b4fb65b0a99000e4b6 100644 +--- a/src/providers/ipa/ipa_sudo_async.c ++++ b/src/providers/ipa/ipa_sudo_async.c +@@ -23,6 +23,7 @@ + #include + + #include "providers/ldap/sdap_ops.h" ++#include "providers/ldap/sdap_sudo_shared.h" + #include "providers/ipa/ipa_common.h" + #include "providers/ipa/ipa_hosts.h" + #include "providers/ipa/ipa_sudo.h" +@@ -133,6 +134,32 @@ fail: + return NULL; + } + ++static errno_t ++ipa_sudo_highest_usn(TALLOC_CTX *mem_ctx, ++ struct sysdb_attrs **attrs, ++ size_t num_attrs, ++ char **current_usn) ++{ ++ errno_t ret; ++ char *usn; ++ ++ ret = sysdb_get_highest_usn(mem_ctx, attrs, num_attrs, &usn); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Unable to get highest USN [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ return ret; ++ } ++ ++ if (sysdb_compare_usn(usn, *current_usn) > 0) { ++ talloc_free(*current_usn); ++ *current_usn = usn; ++ return EOK; ++ } ++ ++ talloc_free(usn); ++ return EOK; ++} ++ + struct ipa_sudo_fetch_state { + struct tevent_context *ev; + struct sysdb_ctx *sysdb; +@@ -150,6 +177,7 @@ struct ipa_sudo_fetch_state { + struct ipa_sudo_conv *conv; + struct sysdb_attrs **rules; + size_t num_rules; ++ char *usn; + }; + + static errno_t ipa_sudo_fetch_rules(struct tevent_req *req); +@@ -292,6 +320,11 @@ ipa_sudo_fetch_rules_done(struct tevent_req *subreq) + goto done; + } + ++ ret = ipa_sudo_highest_usn(state, attrs, num_attrs, &state->usn); ++ if (ret != EOK) { ++ goto done; ++ } ++ + ret = ipa_sudo_fetch_cmdgroups(req); + + done: +@@ -366,6 +399,11 @@ ipa_sudo_fetch_cmdgroups_done(struct tevent_req *subreq) + goto done; + } + ++ ret = ipa_sudo_highest_usn(state, attrs, num_attrs, &state->usn); ++ if (ret != EOK) { ++ goto done; ++ } ++ + ret = ipa_sudo_fetch_cmds(req); + + done: +@@ -482,7 +520,8 @@ static errno_t + ipa_sudo_fetch_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct sysdb_attrs ***_rules, +- size_t *_num_rules) ++ size_t *_num_rules, ++ char **_usn) + { + struct ipa_sudo_fetch_state *state = NULL; + state = tevent_req_data(req, struct ipa_sudo_fetch_state); +@@ -491,6 +530,7 @@ ipa_sudo_fetch_recv(TALLOC_CTX *mem_ctx, + + *_rules = talloc_steal(mem_ctx, state->rules); + *_num_rules = state->num_rules; ++ *_usn = talloc_steal(mem_ctx, state->usn); + + return EOK; + } +@@ -697,6 +737,7 @@ ipa_sudo_refresh_done(struct tevent_req *subreq) + { + struct ipa_sudo_refresh_state *state; + struct tevent_req *req; ++ char *usn = NULL; + bool in_transaction = false; + errno_t sret; + int ret; +@@ -704,7 +745,8 @@ ipa_sudo_refresh_done(struct tevent_req *subreq) + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct ipa_sudo_refresh_state); + +- ret = ipa_sudo_fetch_recv(state, subreq, &state->rules, &state->num_rules); ++ ret = ipa_sudo_fetch_recv(state, subreq, &state->rules, ++ &state->num_rules, &usn); + talloc_zfree(subreq); + + ret = sdap_id_op_done(state->sdap_op, ret, &state->dp_error); +@@ -745,6 +787,10 @@ ipa_sudo_refresh_done(struct tevent_req *subreq) + } + in_transaction = false; + ++ if (usn != NULL) { ++ sdap_sudo_set_usn(state->sudo_ctx->id_ctx->srv_opts, usn); ++ } ++ + DEBUG(SSSDBG_TRACE_FUNC, "Sudo rules are successfully stored in cache\n"); + + done: +-- +2.5.0 + diff --git a/0030-SDAP-Add-sdap_or_filters.patch b/0030-SDAP-Add-sdap_or_filters.patch new file mode 100644 index 0000000..c38f70a --- /dev/null +++ b/0030-SDAP-Add-sdap_or_filters.patch @@ -0,0 +1,80 @@ +From da594641c3bb8718808205c20f0a4e8f96e80d71 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 5 Jan 2016 11:17:38 +0100 +Subject: [PATCH 30/49] SDAP: Add sdap_or_filters + +Reviewed-by: Sumit Bose +(cherry picked from commit ad5a48c4947183fda49308259e3411d17a8b0a13) +--- + src/providers/ldap/ldap_common.h | 4 ++++ + src/providers/ldap/sdap_utils.c | 30 +++++++++++++++++++++++------- + 2 files changed, 27 insertions(+), 7 deletions(-) + +diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h +index e5fee51e742a69d8876f2829f75b2af5f020ef6f..bdd02d8221850b8baef746cc1f28a7c8f8569924 100644 +--- a/src/providers/ldap/ldap_common.h ++++ b/src/providers/ldap/ldap_common.h +@@ -264,6 +264,10 @@ errno_t list_missing_attrs(TALLOC_CTX *mem_ctx, + + bool sdap_is_secure_uri(const char *uri); + ++char *sdap_or_filters(TALLOC_CTX *mem_ctx, ++ const char *base_filter, ++ const char *extra_filter); ++ + char *sdap_combine_filters(TALLOC_CTX *mem_ctx, + const char *base_filter, + const char *extra_filter); +diff --git a/src/providers/ldap/sdap_utils.c b/src/providers/ldap/sdap_utils.c +index 47921b8768b9c4c4b2d40a5eb28e28bf48238210..347206c21286ea1a491a7b9447a179694ded9b9b 100644 +--- a/src/providers/ldap/sdap_utils.c ++++ b/src/providers/ldap/sdap_utils.c +@@ -149,9 +149,11 @@ errno_t deref_string_to_val(const char *str, int *val) + return EOK; + } + +-char *sdap_combine_filters(TALLOC_CTX *mem_ctx, +- const char *base_filter, +- const char *extra_filter) ++static char * ++sdap_combine_filters_ex(TALLOC_CTX *mem_ctx, ++ char operator, ++ const char *base_filter, ++ const char *extra_filter) + { + char *filter = NULL; + +@@ -162,12 +164,26 @@ char *sdap_combine_filters(TALLOC_CTX *mem_ctx, + } + + if (extra_filter[0] == '(') { +- filter = talloc_asprintf(mem_ctx, "(&%s%s)", +- base_filter, extra_filter); ++ filter = talloc_asprintf(mem_ctx, "(%c%s%s)", ++ operator, base_filter, extra_filter); + } else { +- filter = talloc_asprintf(mem_ctx, "(&%s(%s))", +- base_filter, extra_filter); ++ filter = talloc_asprintf(mem_ctx, "(%c%s(%s))", ++ operator, base_filter, extra_filter); + } + + return filter; /* NULL or not */ + } ++ ++char *sdap_or_filters(TALLOC_CTX *mem_ctx, ++ const char *base_filter, ++ const char *extra_filter) ++{ ++ return sdap_combine_filters_ex(mem_ctx, '|', base_filter, extra_filter); ++} ++ ++char *sdap_combine_filters(TALLOC_CTX *mem_ctx, ++ const char *base_filter, ++ const char *extra_filter) ++{ ++ return sdap_combine_filters_ex(mem_ctx, '&', base_filter, extra_filter); ++} +-- +2.5.0 + diff --git a/0031-IPA-SUDO-Implement-smart-refresh.patch b/0031-IPA-SUDO-Implement-smart-refresh.patch new file mode 100644 index 0000000..74d9ae9 --- /dev/null +++ b/0031-IPA-SUDO-Implement-smart-refresh.patch @@ -0,0 +1,610 @@ +From 5edf5c55bb259ac29454493d06097c5fab8a2199 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 18 Dec 2015 13:05:41 +0100 +Subject: [PATCH 31/49] IPA SUDO: Implement smart refresh + +Reviewed-by: Sumit Bose +(cherry picked from commit cc7f9b639144183eb4f8bd86e5bed077da7d4e35) +--- + src/providers/ipa/ipa_sudo.h | 1 + + src/providers/ipa/ipa_sudo_async.c | 312 ++++++++++++++++++++++++++++++++++- + src/providers/ipa/ipa_sudo_refresh.c | 132 ++++++++++++++- + 3 files changed, 438 insertions(+), 7 deletions(-) + +diff --git a/src/providers/ipa/ipa_sudo.h b/src/providers/ipa/ipa_sudo.h +index 9dd72948732f4b6e19f4a6546128c5319cd97bda..81ada14e46550fab815a7df262abd0b5fa11afd7 100644 +--- a/src/providers/ipa/ipa_sudo.h ++++ b/src/providers/ipa/ipa_sudo.h +@@ -59,6 +59,7 @@ struct tevent_req * + ipa_sudo_refresh_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ipa_sudo_ctx *sudo_ctx, ++ const char *cmdgroups_filter, + const char *search_filter, + const char *delete_filter); + +diff --git a/src/providers/ipa/ipa_sudo_async.c b/src/providers/ipa/ipa_sudo_async.c +index d52b97da17337b224c4be4b4fb65b0a99000e4b6..79e69ce962fd5cc2df0e9aac10a5469ffd73c6be 100644 +--- a/src/providers/ipa/ipa_sudo_async.c ++++ b/src/providers/ipa/ipa_sudo_async.c +@@ -160,14 +160,217 @@ ipa_sudo_highest_usn(TALLOC_CTX *mem_ctx, + return EOK; + } + ++static errno_t ++ipa_sudo_assoc_rules_filter(TALLOC_CTX *mem_ctx, ++ struct sysdb_attrs **cmdgroups, ++ size_t num_cmdgroups, ++ char **_filter) ++{ ++ TALLOC_CTX *tmp_ctx; ++ const char *origdn; ++ char *sanitized; ++ char *filter; ++ errno_t ret; ++ size_t i; ++ ++ if (num_cmdgroups == 0) { ++ return ENOENT; ++ } ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ filter = talloc_strdup(tmp_ctx, ""); ++ if (filter == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ for (i = 0; i < num_cmdgroups; i++) { ++ ret = sysdb_attrs_get_string(cmdgroups[i], SYSDB_ORIG_DN, &origdn); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get original dn [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ ret = ERR_INTERNAL; ++ goto done; ++ } ++ ++ ret = sss_filter_sanitize(tmp_ctx, origdn, &sanitized); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ filter = talloc_asprintf_append(filter, "(%s=%s)", ++ SYSDB_IPA_SUDORULE_ORIGCMD, sanitized); ++ if (filter == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ filter = talloc_asprintf(tmp_ctx, "(&(objectClass=%s)(|%s)))", ++ SYSDB_SUDO_CACHE_OC, filter); ++ if (filter == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ *_filter = talloc_steal(mem_ctx, filter); ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++static errno_t ++ipa_sudo_assoc_rules(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain, ++ struct sysdb_attrs **cmdgroups, ++ size_t num_cmdgroups, ++ struct sysdb_attrs ***_rules, ++ size_t *_num_rules) ++{ ++ TALLOC_CTX *tmp_ctx; ++ const char *attrs[] = {SYSDB_NAME, NULL}; ++ struct sysdb_attrs **rules; ++ struct ldb_message **msgs; ++ size_t num_rules; ++ char *filter; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = ipa_sudo_assoc_rules_filter(tmp_ctx, cmdgroups, ++ num_cmdgroups, &filter); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = sysdb_search_custom(tmp_ctx, domain, filter, ++ SUDORULE_SUBDIR, attrs, ++ &num_rules, &msgs); ++ if (ret == ENOENT) { ++ *_rules = NULL; ++ *_num_rules = 0; ++ ret = EOK; ++ goto done; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Error looking up sudo rules [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = sysdb_msg2attrs(tmp_ctx, num_rules, msgs, &rules); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not convert ldb message to " ++ "sysdb_attrs [%d]: %s\n", ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ *_rules = talloc_steal(mem_ctx, rules); ++ *_num_rules = num_rules; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++static errno_t ++ipa_sudo_filter_rules_bycmdgroups(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *domain, ++ struct sysdb_attrs **cmdgroups, ++ size_t num_cmdgroups, ++ struct sdap_attr_map *map_rule, ++ char **_filter) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct sysdb_attrs **rules; ++ size_t num_rules; ++ const char *name; ++ char *sanitized; ++ char *filter; ++ errno_t ret; ++ size_t i; ++ ++ if (num_cmdgroups == 0) { ++ *_filter = NULL; ++ return EOK; ++ } ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ ret = ipa_sudo_assoc_rules(tmp_ctx, domain, cmdgroups, num_cmdgroups, ++ &rules, &num_rules); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ if (num_rules == 0) { ++ *_filter = NULL; ++ ret = EOK; ++ goto done; ++ } ++ ++ filter = talloc_strdup(tmp_ctx, ""); ++ if (filter == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ for (i = 0; i < num_rules; i++) { ++ ret = sysdb_attrs_get_string(rules[i], SYSDB_NAME, &name); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get name [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = sss_filter_sanitize(tmp_ctx, name, &sanitized); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ filter = talloc_asprintf_append(filter, "(%s=%s)", ++ map_rule[IPA_AT_SUDORULE_NAME].name, sanitized); ++ if (filter == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ filter = talloc_asprintf(tmp_ctx, "(|%s)", filter); ++ if (filter == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ *_filter = talloc_steal(mem_ctx, filter); ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ + struct ipa_sudo_fetch_state { + struct tevent_context *ev; + struct sysdb_ctx *sysdb; ++ struct sss_domain_info *domain; + struct ipa_sudo_ctx *sudo_ctx; + struct sdap_options *sdap_opts; + struct ipa_hostinfo *host; + struct sdap_handle *sh; + const char *search_filter; ++ const char *cmdgroups_filter; + + struct sdap_attr_map *map_cmdgroup; + struct sdap_attr_map *map_rule; +@@ -180,6 +383,8 @@ struct ipa_sudo_fetch_state { + char *usn; + }; + ++static errno_t ipa_sudo_fetch_addtl_cmdgroups(struct tevent_req *req); ++static void ipa_sudo_fetch_addtl_cmdgroups_done(struct tevent_req *subreq); + static errno_t ipa_sudo_fetch_rules(struct tevent_req *req); + static void ipa_sudo_fetch_rules_done(struct tevent_req *subreq); + static errno_t ipa_sudo_fetch_cmdgroups(struct tevent_req *req); +@@ -191,6 +396,7 @@ static void ipa_sudo_fetch_done(struct tevent_req *req); + static struct tevent_req * + ipa_sudo_fetch_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, ++ struct sss_domain_info *domain, + struct sysdb_ctx *sysdb, + struct ipa_sudo_ctx *sudo_ctx, + struct ipa_hostinfo *host, +@@ -199,6 +405,7 @@ ipa_sudo_fetch_send(TALLOC_CTX *mem_ctx, + struct sdap_attr_map *map_host, + struct sdap_attr_map *map_hostgroup, + struct sdap_handle *sh, ++ const char *cmdgroups_filter, + const char *search_filter) + { + struct ipa_sudo_fetch_state *state = NULL; +@@ -214,11 +421,13 @@ ipa_sudo_fetch_send(TALLOC_CTX *mem_ctx, + + state->ev = ev; + state->sysdb = sysdb; ++ state->domain = domain; + state->sudo_ctx = sudo_ctx; + state->sdap_opts = sudo_ctx->sdap_opts; + state->host = host; + state->sh = sh; + state->search_filter = search_filter == NULL ? "" : search_filter; ++ state->cmdgroups_filter = cmdgroups_filter; + + state->map_cmdgroup = sudo_ctx->sudocmdgroup_map; + state->map_rule = sudo_ctx->sudorule_map; +@@ -234,7 +443,15 @@ ipa_sudo_fetch_send(TALLOC_CTX *mem_ctx, + goto immediately; + } + +- ret = ipa_sudo_fetch_rules(req); ++ if (state->cmdgroups_filter != NULL) { ++ /* We need to fetch additional cmdgroups that may not be revealed ++ * during normal search. Such as when using entryUSN filter in smart ++ * refresh, some command groups may have change but none rule was ++ * modified but we need to fetch associated rules anyway. */ ++ ret = ipa_sudo_fetch_addtl_cmdgroups(req); ++ } else { ++ ret = ipa_sudo_fetch_rules(req); ++ } + if (ret != EAGAIN) { + goto immediately; + } +@@ -253,6 +470,87 @@ immediately: + } + + static errno_t ++ipa_sudo_fetch_addtl_cmdgroups(struct tevent_req *req) ++{ ++ struct ipa_sudo_fetch_state *state; ++ struct tevent_req *subreq; ++ struct sdap_attr_map *map; ++ char *filter; ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "About to fetch additional command groups\n"); ++ ++ state = tevent_req_data(req, struct ipa_sudo_fetch_state); ++ map = state->map_cmdgroup; ++ ++ filter = talloc_asprintf(state, "(&(objectClass=%s)%s)", ++ map[IPA_OC_SUDOCMDGROUP].name, ++ state->cmdgroups_filter); ++ if (filter == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to build filter\n"); ++ return ENOMEM; ++ } ++ ++ subreq = sdap_search_bases_send(state, state->ev, state->sdap_opts, ++ state->sh, state->sudo_sb, map, true, 0, ++ filter, NULL); ++ if (subreq == NULL) { ++ return ENOMEM; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_sudo_fetch_addtl_cmdgroups_done, req); ++ return EAGAIN; ++} ++ ++static void ++ipa_sudo_fetch_addtl_cmdgroups_done(struct tevent_req *subreq) ++{ ++ struct ipa_sudo_fetch_state *state = NULL; ++ struct tevent_req *req = NULL; ++ struct sysdb_attrs **attrs; ++ size_t num_attrs; ++ char *filter; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_sudo_fetch_state); ++ ++ ret = sdap_search_bases_recv(subreq, state, &num_attrs, &attrs); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_IMPORTANT_INFO, "Received %zu additional command groups\n", ++ num_attrs); ++ ++ ret = ipa_sudo_filter_rules_bycmdgroups(state, state->domain, attrs, ++ num_attrs, state->map_rule, ++ &filter); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to construct rules filter " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ state->search_filter = sdap_or_filters(state, state->search_filter, filter); ++ if (state->search_filter == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = ipa_sudo_fetch_rules(req); ++ ++done: ++ if (ret == EOK) { ++ ipa_sudo_fetch_done(req); ++ } else if (ret != EAGAIN) { ++ tevent_req_error(req, ret); ++ } ++ ++ return; ++} ++ ++static errno_t + ipa_sudo_fetch_rules(struct tevent_req *req) + { + struct ipa_sudo_fetch_state *state; +@@ -543,6 +841,7 @@ struct ipa_sudo_refresh_state { + struct ipa_sudo_ctx *sudo_ctx; + struct ipa_options *ipa_opts; + struct sdap_options *sdap_opts; ++ const char *cmdgroups_filter; + const char *search_filter; + const char *delete_filter; + +@@ -563,6 +862,7 @@ struct tevent_req * + ipa_sudo_refresh_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ipa_sudo_ctx *sudo_ctx, ++ const char *cmdgroups_filter, + const char *search_filter, + const char *delete_filter) + { +@@ -592,6 +892,12 @@ ipa_sudo_refresh_send(TALLOC_CTX *mem_ctx, + goto immediately; + } + ++ state->cmdgroups_filter = talloc_strdup(state, cmdgroups_filter); ++ if (cmdgroups_filter != NULL && state->cmdgroups_filter == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ + state->search_filter = talloc_strdup(state, search_filter); + if (search_filter != NULL && state->search_filter == NULL) { + ret = ENOMEM; +@@ -716,13 +1022,13 @@ ipa_sudo_refresh_host_done(struct tevent_req *subreq) + return; + } + +- subreq = ipa_sudo_fetch_send(state, state->ev, state->sysdb, ++ subreq = ipa_sudo_fetch_send(state, state->ev, state->domain, state->sysdb, + state->sudo_ctx, host, + state->sdap_opts->user_map, + state->sdap_opts->group_map, + state->ipa_opts->host_map, + state->ipa_opts->hostgroup_map, state->sh, +- state->search_filter); ++ state->cmdgroups_filter, state->search_filter); + if (subreq == NULL) { + state->dp_error = DP_ERR_FATAL; + tevent_req_error(req, ENOMEM); +diff --git a/src/providers/ipa/ipa_sudo_refresh.c b/src/providers/ipa/ipa_sudo_refresh.c +index f1b99c0de96dd2226eb3181ce44e54c019139c6e..bdde4a0026f224898a4987476f49122ea92a6052 100644 +--- a/src/providers/ipa/ipa_sudo_refresh.c ++++ b/src/providers/ipa/ipa_sudo_refresh.c +@@ -69,7 +69,8 @@ ipa_sudo_full_refresh_send(TALLOC_CTX *mem_ctx, + + DEBUG(SSSDBG_TRACE_FUNC, "Issuing a full refresh of sudo rules\n"); + +- subreq = ipa_sudo_refresh_send(state, ev, sudo_ctx, NULL, delete_filter); ++ subreq = ipa_sudo_refresh_send(state, ev, sudo_ctx, ++ NULL, NULL, delete_filter); + if (subreq == NULL) { + ret = ENOMEM; + goto immediately; +@@ -141,6 +142,129 @@ ipa_sudo_full_refresh_recv(struct tevent_req *req, + return EOK; + } + ++struct ipa_sudo_smart_refresh_state { ++ int dp_error; ++}; ++ ++static void ipa_sudo_smart_refresh_done(struct tevent_req *subreq); ++ ++static struct tevent_req * ++ipa_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct ipa_sudo_ctx *sudo_ctx) ++{ ++ struct sdap_server_opts *srv_opts = sudo_ctx->id_ctx->srv_opts; ++ struct ipa_sudo_smart_refresh_state *state; ++ struct tevent_req *subreq; ++ struct tevent_req *req; ++ char *cmdgroups_filter; ++ char *search_filter; ++ const char *usn; ++ errno_t ret; ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct ipa_sudo_smart_refresh_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); ++ return NULL; ++ } ++ ++ if (!sudo_ctx->full_refresh_done ++ || srv_opts == NULL || srv_opts->max_sudo_value == NULL) { ++ /* Perform full refresh first */ ++ DEBUG(SSSDBG_TRACE_FUNC, "USN value is unknown, " ++ "waiting for full refresh!\n"); ++ ret = EINVAL; ++ goto immediately; ++ } ++ ++ /* Download all rules from LDAP that are newer than usn */ ++ usn = srv_opts->max_sudo_value; ++ ++ cmdgroups_filter = talloc_asprintf(state, ++ "(&(%s>=%s)(!(%s=%s)))", ++ sudo_ctx->sudocmdgroup_map[IPA_AT_SUDOCMDGROUP_ENTRYUSN].name, usn, ++ sudo_ctx->sudocmdgroup_map[IPA_AT_SUDOCMDGROUP_ENTRYUSN].name, usn); ++ if (cmdgroups_filter == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ search_filter = talloc_asprintf(state, ++ "(&(%s>=%s)(!(%s=%s)))", ++ sudo_ctx->sudorule_map[IPA_AT_SUDORULE_ENTRYUSN].name, usn, ++ sudo_ctx->sudorule_map[IPA_AT_SUDORULE_ENTRYUSN].name, usn); ++ if (search_filter == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ /* Do not remove any rules that are already in the sysdb. */ ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Issuing a smart refresh of sudo rules " ++ "(USN > %s)\n", usn); ++ ++ subreq = ipa_sudo_refresh_send(state, ev, sudo_ctx, cmdgroups_filter, ++ search_filter, NULL); ++ if (subreq == NULL) { ++ ret = ENOMEM; ++ goto immediately; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_sudo_smart_refresh_done, req); ++ ++ return req; ++ ++immediately: ++ if (ret == EOK) { ++ tevent_req_done(req); ++ } else { ++ tevent_req_error(req, ret); ++ } ++ tevent_req_post(req, ev); ++ ++ return req; ++} ++ ++static void ipa_sudo_smart_refresh_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = NULL; ++ struct ipa_sudo_smart_refresh_state *state = NULL; ++ int ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ state = tevent_req_data(req, struct ipa_sudo_smart_refresh_state); ++ ++ ret = ipa_sudo_refresh_recv(subreq, &state->dp_error, NULL); ++ talloc_zfree(subreq); ++ if (ret != EOK || state->dp_error != DP_ERR_OK) { ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Successful smart refresh of sudo rules\n"); ++ ++done: ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++} ++ ++int ipa_sudo_smart_refresh_recv(struct tevent_req *req, ++ int *dp_error) ++{ ++ struct ipa_sudo_smart_refresh_state *state = NULL; ++ state = tevent_req_data(req, struct ipa_sudo_smart_refresh_state); ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ *dp_error = state->dp_error; ++ ++ return EOK; ++} ++ + struct ipa_sudo_rules_refresh_state { + size_t num_rules; + int dp_error; +@@ -230,7 +354,7 @@ ipa_sudo_rules_refresh_send(TALLOC_CTX *mem_ctx, + goto immediately; + } + +- subreq = ipa_sudo_refresh_send(req, ev, sudo_ctx, search_filter, ++ subreq = ipa_sudo_refresh_send(req, ev, sudo_ctx, NULL, search_filter, + delete_filter); + if (subreq == NULL) { + ret = ENOMEM; +@@ -327,7 +451,7 @@ ipa_sudo_ptask_smart_refresh_send(TALLOC_CTX *mem_ctx, + struct ipa_sudo_ctx *sudo_ctx; + sudo_ctx = talloc_get_type(pvt, struct ipa_sudo_ctx); + +- return ipa_sudo_full_refresh_send(mem_ctx, be_ctx->ev, sudo_ctx); ++ return ipa_sudo_smart_refresh_send(mem_ctx, be_ctx->ev, sudo_ctx); + } + + static errno_t +@@ -335,7 +459,7 @@ ipa_sudo_ptask_smart_refresh_recv(struct tevent_req *req) + { + int dp_error; + +- return ipa_sudo_full_refresh_recv(req, &dp_error); ++ return ipa_sudo_smart_refresh_recv(req, &dp_error); + } + + errno_t +-- +2.5.0 + diff --git a/0032-SUDO-sdap_sudo_set_usn-do-not-steal-usn.patch b/0032-SUDO-sdap_sudo_set_usn-do-not-steal-usn.patch new file mode 100644 index 0000000..af36474 --- /dev/null +++ b/0032-SUDO-sdap_sudo_set_usn-do-not-steal-usn.patch @@ -0,0 +1,62 @@ +From effe11c0b2a5e77e1b6085d695339fc449e2481f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 12 Jan 2016 12:02:40 +0100 +Subject: [PATCH 32/49] SUDO: sdap_sudo_set_usn() do not steal usn + +This is less error prone. + +Reviewed-by: Sumit Bose +(cherry picked from commit 3ff3bb43ae6509905bbf7fa6540c44cdbbd0f738) +--- + src/providers/ldap/sdap_sudo_shared.c | 11 +++++++++-- + src/providers/ldap/sdap_sudo_shared.h | 2 +- + 2 files changed, 10 insertions(+), 3 deletions(-) + +diff --git a/src/providers/ldap/sdap_sudo_shared.c b/src/providers/ldap/sdap_sudo_shared.c +index b31d5d27f61b73e71ab8ad0341415ee00e2295cf..0885054e4d0e886671f7057e44d0e66e3f5ccaad 100644 +--- a/src/providers/ldap/sdap_sudo_shared.c ++++ b/src/providers/ldap/sdap_sudo_shared.c +@@ -122,10 +122,11 @@ sdap_sudo_ptask_setup_generic(struct be_ctx *be_ctx, + + void + sdap_sudo_set_usn(struct sdap_server_opts *srv_opts, +- char *usn) ++ const char *usn) + { + unsigned int usn_number; + char *endptr = NULL; ++ char *newusn; + + if (srv_opts == NULL) { + DEBUG(SSSDBG_TRACE_FUNC, "Bug: srv_opts is NULL\n"); +@@ -138,8 +139,14 @@ sdap_sudo_set_usn(struct sdap_server_opts *srv_opts, + } + + if (sysdb_compare_usn(usn, srv_opts->max_sudo_value) > 0) { ++ newusn = talloc_strdup(srv_opts, usn); ++ if (newusn == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n"); ++ return; ++ } ++ + talloc_zfree(srv_opts->max_sudo_value); +- srv_opts->max_sudo_value = talloc_steal(srv_opts, usn); ++ srv_opts->max_sudo_value = newusn; + } + + usn_number = strtoul(usn, &endptr, 10); +diff --git a/src/providers/ldap/sdap_sudo_shared.h b/src/providers/ldap/sdap_sudo_shared.h +index bbc6927250cf8a9b4a92eb15bad6c718c76e2f70..76858d431d0a8f2513f71321d39822da921bf9f8 100644 +--- a/src/providers/ldap/sdap_sudo_shared.h ++++ b/src/providers/ldap/sdap_sudo_shared.h +@@ -35,6 +35,6 @@ sdap_sudo_ptask_setup_generic(struct be_ctx *be_ctx, + + void + sdap_sudo_set_usn(struct sdap_server_opts *srv_opts, +- char *usn); ++ const char *usn); + + #endif /* _SDAP_SUDO_SHARED_H_ */ +-- +2.5.0 + diff --git a/0033-SUDO-remove-full_refresh_in_progress.patch b/0033-SUDO-remove-full_refresh_in_progress.patch new file mode 100644 index 0000000..b293f42 --- /dev/null +++ b/0033-SUDO-remove-full_refresh_in_progress.patch @@ -0,0 +1,87 @@ +From df870fbd4c2d9fa573338714ff1511475e74e785 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 12 Jan 2016 12:12:17 +0100 +Subject: [PATCH 33/49] SUDO: remove full_refresh_in_progress + +When we switched to be_ptask this variable has become obsolete. + +Reviewed-by: Sumit Bose +(cherry picked from commit 43bbf5b158ec3152806791ca49ae224ee978de24) +--- + src/providers/ipa/ipa_sudo.h | 1 - + src/providers/ipa/ipa_sudo_refresh.c | 4 ---- + src/providers/ldap/sdap_sudo.h | 1 - + src/providers/ldap/sdap_sudo_refresh.c | 4 ---- + 4 files changed, 10 deletions(-) + +diff --git a/src/providers/ipa/ipa_sudo.h b/src/providers/ipa/ipa_sudo.h +index 81ada14e46550fab815a7df262abd0b5fa11afd7..3c346c837be6ee4848d4786ac01f36bc80698d3f 100644 +--- a/src/providers/ipa/ipa_sudo.h ++++ b/src/providers/ipa/ipa_sudo.h +@@ -29,7 +29,6 @@ struct ipa_sudo_ctx { + struct sdap_options *sdap_opts; + + bool full_refresh_done; +- bool full_refresh_in_progress; + + /* sudo */ + struct sdap_attr_map *sudocmdgroup_map; +diff --git a/src/providers/ipa/ipa_sudo_refresh.c b/src/providers/ipa/ipa_sudo_refresh.c +index bdde4a0026f224898a4987476f49122ea92a6052..c8fb7d9216edc0568ee906c368fcff5ff1596022 100644 +--- a/src/providers/ipa/ipa_sudo_refresh.c ++++ b/src/providers/ipa/ipa_sudo_refresh.c +@@ -54,8 +54,6 @@ ipa_sudo_full_refresh_send(TALLOC_CTX *mem_ctx, + return NULL; + } + +- sudo_ctx->full_refresh_in_progress = true; +- + state->domain = sudo_ctx->id_ctx->be->domain; + state->sudo_ctx = sudo_ctx; + +@@ -118,8 +116,6 @@ ipa_sudo_full_refresh_done(struct tevent_req *subreq) + DEBUG(SSSDBG_TRACE_FUNC, "Successful full refresh of sudo rules\n"); + + done: +- state->sudo_ctx->full_refresh_in_progress = false; +- + if (ret != EOK) { + tevent_req_error(req, ret); + return; +diff --git a/src/providers/ldap/sdap_sudo.h b/src/providers/ldap/sdap_sudo.h +index d2fa9bec41a07bbae2aaf1739df67a20ea6a578a..060f9fe36d3f6fda6d041e2f1c9a0781d914265d 100644 +--- a/src/providers/ldap/sdap_sudo.h ++++ b/src/providers/ldap/sdap_sudo.h +@@ -34,7 +34,6 @@ struct sdap_sudo_ctx { + bool use_host_filter; + + bool full_refresh_done; +- bool full_refresh_in_progress; + + bool run_hostinfo; + }; +diff --git a/src/providers/ldap/sdap_sudo_refresh.c b/src/providers/ldap/sdap_sudo_refresh.c +index 5697818ce71240468d2bcaa8af7994ca6b8ea3ef..f1fb6a924c93ec5c71a890d4e03aaac3e9709d73 100644 +--- a/src/providers/ldap/sdap_sudo_refresh.c ++++ b/src/providers/ldap/sdap_sudo_refresh.c +@@ -55,8 +55,6 @@ struct tevent_req *sdap_sudo_full_refresh_send(TALLOC_CTX *mem_ctx, + return NULL; + } + +- sudo_ctx->full_refresh_in_progress = true; +- + state->sudo_ctx = sudo_ctx; + state->id_ctx = id_ctx; + state->sysdb = id_ctx->be->domain->sysdb; +@@ -132,8 +130,6 @@ static void sdap_sudo_full_refresh_done(struct tevent_req *subreq) + DEBUG(SSSDBG_TRACE_FUNC, "Successful full refresh of sudo rules\n"); + + done: +- state->sudo_ctx->full_refresh_in_progress = false; +- + if (ret != EOK) { + tevent_req_error(req, ret); + return; +-- +2.5.0 + diff --git a/0034-SUDO-assume-zero-if-usn-is-unknown.patch b/0034-SUDO-assume-zero-if-usn-is-unknown.patch new file mode 100644 index 0000000..ee4caee --- /dev/null +++ b/0034-SUDO-assume-zero-if-usn-is-unknown.patch @@ -0,0 +1,127 @@ +From bd0561dd88307853b1901d2ba4036ec0c862f6d9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 12 Jan 2016 12:15:03 +0100 +Subject: [PATCH 34/49] SUDO: assume zero if usn is unknown + +When we switched to be_ptaks full_refresh_done has become obsolete since +timing is handled in a better way. In case of unknown USN we assume zero +which allows us to disable full refresh completely in configuration. + +Reviewed-by: Sumit Bose +(cherry picked from commit 8bd44a13de231d025882810c720dd07ca4ee564d) +--- + src/providers/ipa/ipa_sudo.h | 2 -- + src/providers/ipa/ipa_sudo_refresh.c | 18 ++++++------------ + src/providers/ldap/sdap_sudo.c | 4 ---- + src/providers/ldap/sdap_sudo_refresh.c | 19 +++++++------------ + 4 files changed, 13 insertions(+), 30 deletions(-) + +diff --git a/src/providers/ipa/ipa_sudo.h b/src/providers/ipa/ipa_sudo.h +index 3c346c837be6ee4848d4786ac01f36bc80698d3f..8b866001931ff0550157861dfbc4a99d7bb8319f 100644 +--- a/src/providers/ipa/ipa_sudo.h ++++ b/src/providers/ipa/ipa_sudo.h +@@ -28,8 +28,6 @@ struct ipa_sudo_ctx { + struct ipa_options *ipa_opts; + struct sdap_options *sdap_opts; + +- bool full_refresh_done; +- + /* sudo */ + struct sdap_attr_map *sudocmdgroup_map; + struct sdap_attr_map *sudorule_map; +diff --git a/src/providers/ipa/ipa_sudo_refresh.c b/src/providers/ipa/ipa_sudo_refresh.c +index c8fb7d9216edc0568ee906c368fcff5ff1596022..5934a8f1181250890ca57ac8d83e47ffdc445ea4 100644 +--- a/src/providers/ipa/ipa_sudo_refresh.c ++++ b/src/providers/ipa/ipa_sudo_refresh.c +@@ -105,8 +105,6 @@ ipa_sudo_full_refresh_done(struct tevent_req *subreq) + goto done; + } + +- state->sudo_ctx->full_refresh_done = true; +- + ret = sysdb_sudo_set_last_full_refresh(state->domain, time(NULL)); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, "Unable to save time of " +@@ -165,17 +163,13 @@ ipa_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx, + return NULL; + } + +- if (!sudo_ctx->full_refresh_done +- || srv_opts == NULL || srv_opts->max_sudo_value == NULL) { +- /* Perform full refresh first */ +- DEBUG(SSSDBG_TRACE_FUNC, "USN value is unknown, " +- "waiting for full refresh!\n"); +- ret = EINVAL; +- goto immediately; +- } +- + /* Download all rules from LDAP that are newer than usn */ +- usn = srv_opts->max_sudo_value; ++ if (srv_opts == NULL || srv_opts->max_sudo_value == NULL) { ++ DEBUG(SSSDBG_TRACE_FUNC, "USN value is unknown, ssuming zero.\n"); ++ usn = "0"; ++ } else { ++ usn = srv_opts->max_sudo_value; ++ } + + cmdgroups_filter = talloc_asprintf(state, + "(&(%s>=%s)(!(%s=%s)))", +diff --git a/src/providers/ldap/sdap_sudo.c b/src/providers/ldap/sdap_sudo.c +index 10067e9ba779b5224bf21dd7a705c45e7f4e0f99..e653c46363253789e60146fbfc067cb93d4ab7f1 100644 +--- a/src/providers/ldap/sdap_sudo.c ++++ b/src/providers/ldap/sdap_sudo.c +@@ -71,10 +71,6 @@ int sdap_sudo_init(struct be_ctx *be_ctx, + *ops = &sdap_sudo_ops; + *pvt_data = sudo_ctx; + +- /* we didn't do any full refresh now, +- * so we don't have current usn values available */ +- sudo_ctx->full_refresh_done = false; +- + ret = ldap_get_sudo_options(be_ctx->cdb, + be_ctx->conf_path, id_ctx->opts, + &sudo_ctx->use_host_filter, +diff --git a/src/providers/ldap/sdap_sudo_refresh.c b/src/providers/ldap/sdap_sudo_refresh.c +index f1fb6a924c93ec5c71a890d4e03aaac3e9709d73..61f24efa11da05d75bc31ea4ea3b150b2f9857f8 100644 +--- a/src/providers/ldap/sdap_sudo_refresh.c ++++ b/src/providers/ldap/sdap_sudo_refresh.c +@@ -115,8 +115,6 @@ static void sdap_sudo_full_refresh_done(struct tevent_req *subreq) + goto done; + } + +- state->sudo_ctx->full_refresh_done = true; +- + /* save the time in the sysdb */ + ret = sysdb_sudo_set_last_full_refresh(state->domain, time(NULL)); + if (ret != EOK) { +@@ -178,20 +176,17 @@ struct tevent_req *sdap_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx, + return NULL; + } + +- if (!sudo_ctx->full_refresh_done +- || srv_opts == NULL || srv_opts->max_sudo_value == NULL) { +- /* Perform full refresh first */ +- DEBUG(SSSDBG_TRACE_FUNC, "USN value is unknown, " +- "waiting for full refresh!\n"); +- ret = EINVAL; +- goto immediately; +- } +- + state->id_ctx = id_ctx; + state->sysdb = id_ctx->be->domain->sysdb; + + /* Download all rules from LDAP that are newer than usn */ +- usn = srv_opts->max_sudo_value; ++ if (srv_opts == NULL || srv_opts->max_sudo_value == NULL) { ++ DEBUG(SSSDBG_TRACE_FUNC, "USN value is unknown, ssuming zero.\n"); ++ usn = "0"; ++ } else { ++ usn = srv_opts->max_sudo_value; ++ } ++ + search_filter = talloc_asprintf(state, + "(&(objectclass=%s)(%s>=%s)(!(%s=%s)))", + map[SDAP_OC_SUDORULE].name, +-- +2.5.0 + diff --git a/0035-SUDO-allow-disabling-full-refresh.patch b/0035-SUDO-allow-disabling-full-refresh.patch new file mode 100644 index 0000000..698c062 --- /dev/null +++ b/0035-SUDO-allow-disabling-full-refresh.patch @@ -0,0 +1,31 @@ +From 83f57d9810a34780949ac9f0c4dc9c6f8a069127 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 12 Jan 2016 11:45:22 +0100 +Subject: [PATCH 35/49] SUDO: allow disabling full refresh + +This condition always disabled smart refresh when full refresh +interval was set to zero and thus disabling periodic refresh +functionality completelely. + +Reviewed-by: Sumit Bose +(cherry picked from commit 8da71a9d5eebe7690b66fde8bfad195d5e3cc629) +--- + src/providers/ldap/sdap_sudo_shared.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/providers/ldap/sdap_sudo_shared.c b/src/providers/ldap/sdap_sudo_shared.c +index 0885054e4d0e886671f7057e44d0e66e3f5ccaad..9e9574b7c641f52bd54989172ad7b6ccfd04b13f 100644 +--- a/src/providers/ldap/sdap_sudo_shared.c ++++ b/src/providers/ldap/sdap_sudo_shared.c +@@ -55,7 +55,7 @@ sdap_sudo_ptask_setup_generic(struct be_ctx *be_ctx, + DEBUG(SSSDBG_CONF_SETTINGS, "At least smart refresh needs to be " + "enabled. Setting smart refresh interval to default value " + "(%ld) seconds.\n", smart); +- } else if (full <= smart) { ++ } else if (full > 0 && full <= smart) { + /* In this case it does not make any sense to run smart refresh. */ + smart = 0; + +-- +2.5.0 + diff --git a/0036-SUDO-remember-usn-as-number-instead-of-string.patch b/0036-SUDO-remember-usn-as-number-instead-of-string.patch new file mode 100644 index 0000000..52ccc07 --- /dev/null +++ b/0036-SUDO-remember-usn-as-number-instead-of-string.patch @@ -0,0 +1,178 @@ +From 0d13927fc7b2daec06cdff379715318e1dc2e05b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 14 Jan 2016 12:23:37 +0100 +Subject: [PATCH 36/49] SUDO: remember usn as number instead of string + +Reviewed-by: Sumit Bose +(cherry picked from commit f58ffb26aeaae0642a149643672fa59ec01a3a36) +--- + src/providers/ipa/ipa_sudo_refresh.c | 14 +++++++------- + src/providers/ldap/sdap.h | 2 +- + src/providers/ldap/sdap_sudo_refresh.c | 12 ++++++------ + src/providers/ldap/sdap_sudo_shared.c | 35 ++++++++++++++++++---------------- + 4 files changed, 33 insertions(+), 30 deletions(-) + +diff --git a/src/providers/ipa/ipa_sudo_refresh.c b/src/providers/ipa/ipa_sudo_refresh.c +index 5934a8f1181250890ca57ac8d83e47ffdc445ea4..42137679c4bd2209b98d1d5223fd3ac71dc16b16 100644 +--- a/src/providers/ipa/ipa_sudo_refresh.c ++++ b/src/providers/ipa/ipa_sudo_refresh.c +@@ -153,7 +153,7 @@ ipa_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx, + struct tevent_req *req; + char *cmdgroups_filter; + char *search_filter; +- const char *usn; ++ unsigned long usn; + errno_t ret; + + req = tevent_req_create(mem_ctx, &state, +@@ -164,15 +164,15 @@ ipa_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx, + } + + /* Download all rules from LDAP that are newer than usn */ +- if (srv_opts == NULL || srv_opts->max_sudo_value == NULL) { +- DEBUG(SSSDBG_TRACE_FUNC, "USN value is unknown, ssuming zero.\n"); +- usn = "0"; ++ if (srv_opts == NULL || srv_opts->max_sudo_value == 0) { ++ DEBUG(SSSDBG_TRACE_FUNC, "USN value is unknown, assuming zero.\n"); ++ usn = 0; + } else { + usn = srv_opts->max_sudo_value; + } + + cmdgroups_filter = talloc_asprintf(state, +- "(&(%s>=%s)(!(%s=%s)))", ++ "(&(%s>=%lu)(!(%s=%lu)))", + sudo_ctx->sudocmdgroup_map[IPA_AT_SUDOCMDGROUP_ENTRYUSN].name, usn, + sudo_ctx->sudocmdgroup_map[IPA_AT_SUDOCMDGROUP_ENTRYUSN].name, usn); + if (cmdgroups_filter == NULL) { +@@ -181,7 +181,7 @@ ipa_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx, + } + + search_filter = talloc_asprintf(state, +- "(&(%s>=%s)(!(%s=%s)))", ++ "(&(%s>=%lu)(!(%s=%lu)))", + sudo_ctx->sudorule_map[IPA_AT_SUDORULE_ENTRYUSN].name, usn, + sudo_ctx->sudorule_map[IPA_AT_SUDORULE_ENTRYUSN].name, usn); + if (search_filter == NULL) { +@@ -192,7 +192,7 @@ ipa_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx, + /* Do not remove any rules that are already in the sysdb. */ + + DEBUG(SSSDBG_TRACE_FUNC, "Issuing a smart refresh of sudo rules " +- "(USN > %s)\n", usn); ++ "(USN > %lu)\n", usn); + + subreq = ipa_sudo_refresh_send(state, ev, sudo_ctx, cmdgroups_filter, + search_filter, NULL); +diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h +index edfbf229b4c4396592020de931eba5f83a8f06ed..d7a299220414f2cf9d80de9921b6a5ec49e5793b 100644 +--- a/src/providers/ldap/sdap.h ++++ b/src/providers/ldap/sdap.h +@@ -460,7 +460,7 @@ struct sdap_server_opts { + char *max_user_value; + char *max_group_value; + char *max_service_value; +- char *max_sudo_value; ++ unsigned long max_sudo_value; + bool posix_checked; + }; + +diff --git a/src/providers/ldap/sdap_sudo_refresh.c b/src/providers/ldap/sdap_sudo_refresh.c +index 61f24efa11da05d75bc31ea4ea3b150b2f9857f8..ff00fd037430f9a7ce62624184faa53288e581e4 100644 +--- a/src/providers/ldap/sdap_sudo_refresh.c ++++ b/src/providers/ldap/sdap_sudo_refresh.c +@@ -167,7 +167,7 @@ struct tevent_req *sdap_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx, + struct sdap_server_opts *srv_opts = id_ctx->srv_opts; + struct sdap_sudo_smart_refresh_state *state = NULL; + char *search_filter = NULL; +- const char *usn; ++ unsigned long usn; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_smart_refresh_state); +@@ -180,15 +180,15 @@ struct tevent_req *sdap_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx, + state->sysdb = id_ctx->be->domain->sysdb; + + /* Download all rules from LDAP that are newer than usn */ +- if (srv_opts == NULL || srv_opts->max_sudo_value == NULL) { +- DEBUG(SSSDBG_TRACE_FUNC, "USN value is unknown, ssuming zero.\n"); +- usn = "0"; ++ if (srv_opts == NULL || srv_opts->max_sudo_value == 0) { ++ DEBUG(SSSDBG_TRACE_FUNC, "USN value is unknown, assuming zero.\n"); ++ usn = 0; + } else { + usn = srv_opts->max_sudo_value; + } + + search_filter = talloc_asprintf(state, +- "(&(objectclass=%s)(%s>=%s)(!(%s=%s)))", ++ "(&(objectclass=%s)(%s>=%lu)(!(%s=%lu)))", + map[SDAP_OC_SUDORULE].name, + map[SDAP_AT_SUDO_USN].name, usn, + map[SDAP_AT_SUDO_USN].name, usn); +@@ -201,7 +201,7 @@ struct tevent_req *sdap_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx, + * sysdb_filter = NULL; */ + + DEBUG(SSSDBG_TRACE_FUNC, "Issuing a smart refresh of sudo rules " +- "(USN > %s)\n", usn); ++ "(USN > %lu)\n", usn); + + subreq = sdap_sudo_refresh_send(state, sudo_ctx, search_filter, NULL); + if (subreq == NULL) { +diff --git a/src/providers/ldap/sdap_sudo_shared.c b/src/providers/ldap/sdap_sudo_shared.c +index 9e9574b7c641f52bd54989172ad7b6ccfd04b13f..72f55e14baa8f8cf896205fb20f14d5f446cfb0a 100644 +--- a/src/providers/ldap/sdap_sudo_shared.c ++++ b/src/providers/ldap/sdap_sudo_shared.c +@@ -126,7 +126,7 @@ sdap_sudo_set_usn(struct sdap_server_opts *srv_opts, + { + unsigned int usn_number; + char *endptr = NULL; +- char *newusn; ++ errno_t ret; + + if (srv_opts == NULL) { + DEBUG(SSSDBG_TRACE_FUNC, "Bug: srv_opts is NULL\n"); +@@ -138,23 +138,26 @@ sdap_sudo_set_usn(struct sdap_server_opts *srv_opts, + return; + } + +- if (sysdb_compare_usn(usn, srv_opts->max_sudo_value) > 0) { +- newusn = talloc_strdup(srv_opts, usn); +- if (newusn == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n"); +- return; +- } +- +- talloc_zfree(srv_opts->max_sudo_value); +- srv_opts->max_sudo_value = newusn; +- } +- ++ errno = 0; + usn_number = strtoul(usn, &endptr, 10); +- if ((endptr == NULL || (*endptr == '\0' && endptr != usn)) +- && (usn_number > srv_opts->last_usn)) { +- srv_opts->last_usn = usn_number; ++ if (endptr != NULL && *endptr != '\0') { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Unable to convert USN %s\n", usn); ++ return; ++ } else if (errno != 0) { ++ ret = errno; ++ DEBUG(SSSDBG_MINOR_FAILURE, "Unable to convert USN %s [%d]: %s\n", ++ usn, ret, sss_strerror(ret)); ++ return; + } + +- DEBUG(SSSDBG_FUNC_DATA, "SUDO higher USN value: [%s]\n", ++ if (usn_number > srv_opts->max_sudo_value) { ++ srv_opts->max_sudo_value = usn_number; ++ } ++ ++ if (usn_number > srv_opts->last_usn) { ++ srv_opts->last_usn = usn_number; ++ } ++ ++ DEBUG(SSSDBG_FUNC_DATA, "SUDO higher USN value: [%lu]\n", + srv_opts->max_sudo_value); + } +-- +2.5.0 + diff --git a/0037-SUDO-simplify-usn-filter.patch b/0037-SUDO-simplify-usn-filter.patch new file mode 100644 index 0000000..d404218 --- /dev/null +++ b/0037-SUDO-simplify-usn-filter.patch @@ -0,0 +1,66 @@ +From 7971fa6c5b1b2c12b3e42aad158429665189a300 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 14 Jan 2016 13:12:14 +0100 +Subject: [PATCH 37/49] SUDO: simplify usn filter + +usn >= current && usn != currect is equivalent to usn >= current + 1 + +Reviewed-by: Sumit Bose +(cherry picked from commit 1476d5348fcf387e7481d833becbd993d91f8019) +--- + src/providers/ipa/ipa_sudo_refresh.c | 10 +++------- + src/providers/ldap/sdap_sudo_refresh.c | 6 ++---- + 2 files changed, 5 insertions(+), 11 deletions(-) + +diff --git a/src/providers/ipa/ipa_sudo_refresh.c b/src/providers/ipa/ipa_sudo_refresh.c +index 42137679c4bd2209b98d1d5223fd3ac71dc16b16..7871802ef7462ce98f6ff43bc33da57ff123ff6f 100644 +--- a/src/providers/ipa/ipa_sudo_refresh.c ++++ b/src/providers/ipa/ipa_sudo_refresh.c +@@ -168,21 +168,17 @@ ipa_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx, + DEBUG(SSSDBG_TRACE_FUNC, "USN value is unknown, assuming zero.\n"); + usn = 0; + } else { +- usn = srv_opts->max_sudo_value; ++ usn = srv_opts->max_sudo_value + 1; + } + +- cmdgroups_filter = talloc_asprintf(state, +- "(&(%s>=%lu)(!(%s=%lu)))", +- sudo_ctx->sudocmdgroup_map[IPA_AT_SUDOCMDGROUP_ENTRYUSN].name, usn, ++ cmdgroups_filter = talloc_asprintf(state, "(%s>=%lu)", + sudo_ctx->sudocmdgroup_map[IPA_AT_SUDOCMDGROUP_ENTRYUSN].name, usn); + if (cmdgroups_filter == NULL) { + ret = ENOMEM; + goto immediately; + } + +- search_filter = talloc_asprintf(state, +- "(&(%s>=%lu)(!(%s=%lu)))", +- sudo_ctx->sudorule_map[IPA_AT_SUDORULE_ENTRYUSN].name, usn, ++ search_filter = talloc_asprintf(state, "(%s>=%lu)", + sudo_ctx->sudorule_map[IPA_AT_SUDORULE_ENTRYUSN].name, usn); + if (search_filter == NULL) { + ret = ENOMEM; +diff --git a/src/providers/ldap/sdap_sudo_refresh.c b/src/providers/ldap/sdap_sudo_refresh.c +index ff00fd037430f9a7ce62624184faa53288e581e4..5ba858019e0bda91a9e0919ed2b0345d9faf085e 100644 +--- a/src/providers/ldap/sdap_sudo_refresh.c ++++ b/src/providers/ldap/sdap_sudo_refresh.c +@@ -184,13 +184,11 @@ struct tevent_req *sdap_sudo_smart_refresh_send(TALLOC_CTX *mem_ctx, + DEBUG(SSSDBG_TRACE_FUNC, "USN value is unknown, assuming zero.\n"); + usn = 0; + } else { +- usn = srv_opts->max_sudo_value; ++ usn = srv_opts->max_sudo_value + 1; + } + +- search_filter = talloc_asprintf(state, +- "(&(objectclass=%s)(%s>=%lu)(!(%s=%lu)))", ++ search_filter = talloc_asprintf(state, "(&(objectclass=%s)(%s>=%lu))", + map[SDAP_OC_SUDORULE].name, +- map[SDAP_AT_SUDO_USN].name, usn, + map[SDAP_AT_SUDO_USN].name, usn); + if (search_filter == NULL) { + ret = ENOMEM; +-- +2.5.0 + diff --git a/0038-IPA-SUDO-Add-support-for-ipaSudoRunAsExt-attributes.patch b/0038-IPA-SUDO-Add-support-for-ipaSudoRunAsExt-attributes.patch new file mode 100644 index 0000000..3969112 --- /dev/null +++ b/0038-IPA-SUDO-Add-support-for-ipaSudoRunAsExt-attributes.patch @@ -0,0 +1,103 @@ +From d652bd9483243485ce86617fc070773f684c113b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Mon, 18 Jan 2016 12:15:47 +0100 +Subject: [PATCH 38/49] IPA SUDO: Add support for ipaSudoRunAsExt* attributes + +Reviewed-by: Sumit Bose +(cherry picked from commit a7d2b4f157194c14bc4a40c74f6416b82befa460) +--- + src/config/etc/sssd.api.d/sssd-ipa.conf | 3 +++ + src/db/sysdb_sudo.h | 3 +++ + src/providers/ipa/ipa_common.h | 3 +++ + src/providers/ipa/ipa_opts.c | 3 +++ + src/providers/ipa/ipa_sudo_conversion.c | 11 +++++++++++ + 5 files changed, 23 insertions(+) + +diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf +index 2784a01e7a012f642377ae9c89d1ed03be88c7ae..13715ec34666f2dbc66df037565b495b9df42511 100644 +--- a/src/config/etc/sssd.api.d/sssd-ipa.conf ++++ b/src/config/etc/sssd.api.d/sssd-ipa.conf +@@ -253,6 +253,9 @@ ipa_sudorule_hostcategory = str, None, false + ipa_sudorule_usercategory = str, None, false + ipa_sudorule_runasusercategory = str, None, false + ipa_sudorule_runasgroupcategory = str, None, false ++ipa_sudorule_runasextuser = str, None, false ++ipa_sudorule_runasextgroup = str, None, false ++ipa_sudorule_runasextusergroup = str, None, false + ipa_sudorule_entry_usn = str, None, false + ipa_sudocmdgroup_object_class = str, None, false + ipa_sudocmdgroup_uuid = str, None, false +diff --git a/src/db/sysdb_sudo.h b/src/db/sysdb_sudo.h +index 8635e78041687f386ec15d45e5d1d3f1f0551e3d..ba90a68512c6c29134ab2f746220db9533a93dda 100644 +--- a/src/db/sysdb_sudo.h ++++ b/src/db/sysdb_sudo.h +@@ -65,6 +65,9 @@ + #define SYSDB_IPA_SUDORULE_USERCATEGORY "userCategory" + #define SYSDB_IPA_SUDORULE_RUNASUSERCATEGORY "ipaSudoRunAsUserCategory" + #define SYSDB_IPA_SUDORULE_RUNASGROUPCATEGORY "ipaSudoRunAsGroupCategory" ++#define SYSDB_IPA_SUDORULE_RUNASEXTUSER "ipaSudoRunAsExtUser" ++#define SYSDB_IPA_SUDORULE_RUNASEXTGROUP "ipaSudoRunAsExtGroup" ++#define SYSDB_IPA_SUDORULE_RUNASEXTUSERGROUP "ipaSudoRunAsExtUserGroup" + + #define SYSDB_IPA_SUDOCMDGROUP_OC "ipasudocmdgrp" + +diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h +index 8cb2058fef98fc8eef0d769a6f62882d1da7ae53..24898ee3809b0bcb682321ba4cfa500acd7c795b 100644 +--- a/src/providers/ipa/ipa_common.h ++++ b/src/providers/ipa/ipa_common.h +@@ -153,6 +153,9 @@ enum ipa_sudorule_attrs { + IPA_AT_SUDORULE_USERCATEGORY, + IPA_AT_SUDORULE_RUNASUSERCATEGORY, + IPA_AT_SUDORULE_RUNASGROUPCATEGORY, ++ IPA_AT_SUDORULE_RUNASEXTUSER, ++ IPA_AT_SUDORULE_RUNASEXTGROUP, ++ IPA_AT_SUDORULE_RUNASEXTUSERGROUP, + IPA_AT_SUDORULE_ENTRYUSN, + + IPA_OPTS_SUDORULE +diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c +index 725e512352ff40cb4de6daba88efa3b8dfefdc62..cda10f89a60264ffd998da73ebadd09dff35ed79 100644 +--- a/src/providers/ipa/ipa_opts.c ++++ b/src/providers/ipa/ipa_opts.c +@@ -356,6 +356,9 @@ struct sdap_attr_map ipa_sudorule_map[] = { + { "ipa_sudorule_usercategory", "userCategory", SYSDB_IPA_SUDORULE_USERCATEGORY, NULL }, + { "ipa_sudorule_runasusercategory", "ipaSudoRunAsUserCategory", SYSDB_IPA_SUDORULE_RUNASUSERCATEGORY, NULL }, + { "ipa_sudorule_runasgroupcategory", "ipaSudoRunAsGroupCategory", SYSDB_IPA_SUDORULE_RUNASGROUPCATEGORY, NULL }, ++ { "ipa_sudorule_runasextuser", "ipaSudoRunAsExtUser", SYSDB_IPA_SUDORULE_RUNASEXTUSER, NULL }, ++ { "ipa_sudorule_runasextgroup", "ipaSudoRunAsExtGroup", SYSDB_IPA_SUDORULE_RUNASEXTGROUP, NULL }, ++ { "ipa_sudorule_runasextusergroup", "ipaSudoRunAsExtUserGroup", SYSDB_IPA_SUDORULE_RUNASEXTUSERGROUP, NULL }, + { "ipa_sudorule_entry_usn", "entryUSN", SYSDB_USN, NULL }, + SDAP_ATTR_MAP_TERMINATOR + }; +diff --git a/src/providers/ipa/ipa_sudo_conversion.c b/src/providers/ipa/ipa_sudo_conversion.c +index 195e40f248e15756a224335208276f6f7a646cd0..02d7ebd5dd819f54b6d97b2251eca294d95a224b 100644 +--- a/src/providers/ipa/ipa_sudo_conversion.c ++++ b/src/providers/ipa/ipa_sudo_conversion.c +@@ -757,6 +757,14 @@ convert_group(TALLOC_CTX *mem_ctx, + } + + static const char * ++convert_runasextusergroup(TALLOC_CTX *mem_ctx, ++ struct ipa_sudo_conv *conv, ++ const char *value) ++{ ++ return talloc_asprintf(mem_ctx, "%%%s", value); ++} ++ ++static const char * + convert_cat(TALLOC_CTX *mem_ctx, + struct ipa_sudo_conv *conv, + const char *value) +@@ -798,6 +806,9 @@ convert_attributes(struct ipa_sudo_conv *conv, + {SYSDB_IPA_SUDORULE_USERCATEGORY, SYSDB_SUDO_CACHE_AT_USER , convert_cat}, + {SYSDB_IPA_SUDORULE_RUNASUSERCATEGORY, SYSDB_SUDO_CACHE_AT_RUNASUSER , convert_cat}, + {SYSDB_IPA_SUDORULE_RUNASGROUPCATEGORY, SYSDB_SUDO_CACHE_AT_RUNASGROUP , convert_cat}, ++ {SYSDB_IPA_SUDORULE_RUNASEXTUSER, SYSDB_SUDO_CACHE_AT_RUNASUSER , NULL}, ++ {SYSDB_IPA_SUDORULE_RUNASEXTGROUP, SYSDB_SUDO_CACHE_AT_RUNASGROUP , NULL}, ++ {SYSDB_IPA_SUDORULE_RUNASEXTUSERGROUP, SYSDB_SUDO_CACHE_AT_RUNASUSER , convert_runasextusergroup}, + {SYSDB_IPA_SUDORULE_ALLOWCMD, SYSDB_IPA_SUDORULE_ORIGCMD , NULL}, + {SYSDB_IPA_SUDORULE_DENYCMD, SYSDB_IPA_SUDORULE_ORIGCMD , NULL}, + {NULL, NULL, NULL}}; +-- +2.5.0 + diff --git a/0039-UTIL-allow-to-skip-default-options-for-child-process.patch b/0039-UTIL-allow-to-skip-default-options-for-child-process.patch new file mode 100644 index 0000000..25345d7 --- /dev/null +++ b/0039-UTIL-allow-to-skip-default-options-for-child-process.patch @@ -0,0 +1,240 @@ +From d0daca3614cd739cda955d8fdbd75b5718420276 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 14 Jan 2016 13:33:53 +0100 +Subject: [PATCH 39/49] UTIL: allow to skip default options for child processes + +Currently the SSSD default options like e.g. --debug-level are added +unconditionally to the command line options of a child process when +started with the child helper functions. + +If a binary from a different source should be started as a child by SSSD +those options might not be known or used differently. This patch adds an +option to exec_child_ex() which allows to skip the default options and +only add specific options. + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 9dcc7dbf04466cd8cd90aa0bb8acbebef9aca832) +--- + src/providers/ad/ad_gpo.c | 2 +- + src/providers/krb5/krb5_child_handler.c | 2 +- + src/responder/pam/pamsrv_p11.c | 2 +- + src/tests/cmocka/test_child_common.c | 4 +- + src/util/child_common.c | 73 ++++++++++++++++++--------------- + src/util/child_common.h | 2 +- + 6 files changed, 47 insertions(+), 38 deletions(-) + +diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c +index d63e52e2798753262b13361788d40b8743640c84..00f4457ddfa35b8917d7babc6666fdc129fb63ae 100644 +--- a/src/providers/ad/ad_gpo.c ++++ b/src/providers/ad/ad_gpo.c +@@ -4139,7 +4139,7 @@ gpo_fork_child(struct tevent_req *req) + if (pid == 0) { /* child */ + err = exec_child_ex(state, + pipefd_to_child, pipefd_from_child, +- GPO_CHILD, gpo_child_debug_fd, NULL, ++ GPO_CHILD, gpo_child_debug_fd, NULL, false, + STDIN_FILENO, AD_GPO_CHILD_OUT_FILENO); + DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec gpo_child: [%d][%s].\n", + err, strerror(err)); +diff --git a/src/providers/krb5/krb5_child_handler.c b/src/providers/krb5/krb5_child_handler.c +index fa1055eb7fc7e9aa6fabef1c1759c272b217a395..167a2b2ad09b67908cdce8051d8a37e557c91545 100644 +--- a/src/providers/krb5/krb5_child_handler.c ++++ b/src/providers/krb5/krb5_child_handler.c +@@ -312,7 +312,7 @@ static errno_t fork_child(struct tevent_req *req) + err = exec_child_ex(state, + pipefd_to_child, pipefd_from_child, + KRB5_CHILD, state->kr->krb5_ctx->child_debug_fd, +- k5c_extra_args, STDIN_FILENO, STDOUT_FILENO); ++ k5c_extra_args, false, STDIN_FILENO, STDOUT_FILENO); + if (err != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec KRB5 child: [%d][%s].\n", + err, strerror(err)); +diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c +index 58310a2530287fc6d08a7195c8e879f96dcc5403..ea428a6a3dd41b1770b69ff0301ed98c1c08c01d 100644 +--- a/src/responder/pam/pamsrv_p11.c ++++ b/src/responder/pam/pamsrv_p11.c +@@ -322,7 +322,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + child_pid = fork(); + if (child_pid == 0) { /* child */ + ret = exec_child_ex(state, pipefd_to_child, pipefd_from_child, +- P11_CHILD_PATH, child_debug_fd, extra_args, ++ P11_CHILD_PATH, child_debug_fd, extra_args, false, + STDIN_FILENO, STDOUT_FILENO); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec p11 child: [%d][%s].\n", +diff --git a/src/tests/cmocka/test_child_common.c b/src/tests/cmocka/test_child_common.c +index bf500fa5a1f2b2fe79833e23a53cdf0b06b81260..9ed9c1ae42dd93cef833b738c29259a18e791339 100644 +--- a/src/tests/cmocka/test_child_common.c ++++ b/src/tests/cmocka/test_child_common.c +@@ -139,7 +139,7 @@ void test_exec_child_extra_args(void **state) + ret = exec_child_ex(child_tctx, + child_tctx->pipefd_to_child, + child_tctx->pipefd_from_child, +- CHILD_DIR"/"TEST_BIN, 2, extra_args, ++ CHILD_DIR"/"TEST_BIN, 2, extra_args, false, + STDIN_FILENO, STDOUT_FILENO); + assert_int_equal(ret, EOK); + } else { +@@ -287,7 +287,7 @@ void test_exec_child_echo(void **state) + ret = exec_child_ex(child_tctx, + child_tctx->pipefd_to_child, + child_tctx->pipefd_from_child, +- CHILD_DIR"/"TEST_BIN, 2, NULL, ++ CHILD_DIR"/"TEST_BIN, 2, NULL, false, + STDIN_FILENO, 3); + assert_int_equal(ret, EOK); + } +diff --git a/src/util/child_common.c b/src/util/child_common.c +index a6131cd20e7cfff5e5d58806aa2c178327eb9baa..60466c146b5bd9147e9425736072f1ea6ed73663 100644 +--- a/src/util/child_common.c ++++ b/src/util/child_common.c +@@ -612,6 +612,7 @@ static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx, + int child_debug_fd, + const char *binary, + const char *extra_argv[], ++ bool extra_args_only, + char ***_argv) + { + /* +@@ -619,18 +620,24 @@ static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx, + * debug_microseconds and NULL + */ + uint_t argc = 5; +- char ** argv; ++ char ** argv = NULL; + errno_t ret = EINVAL; + size_t i; + ++ if (extra_args_only) { ++ argc = 2; /* program name and NULL */ ++ } ++ + /* Save the current state in case an interrupt changes it */ + bool child_debug_to_file = debug_to_file; + bool child_debug_timestamps = debug_timestamps; + bool child_debug_microseconds = debug_microseconds; + bool child_debug_stderr = debug_to_stderr; + +- if (child_debug_to_file) argc++; +- if (child_debug_stderr) argc++; ++ if (!extra_args_only) { ++ if (child_debug_to_file) argc++; ++ if (child_debug_stderr) argc++; ++ } + + if (extra_argv) { + for (i = 0; extra_argv[i]; i++) argc++; +@@ -659,42 +666,44 @@ static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx, + } + } + +- argv[--argc] = talloc_asprintf(argv, "--debug-level=%#.4x", +- debug_level); +- if (argv[argc] == NULL) { +- ret = ENOMEM; +- goto fail; +- } +- +- if (child_debug_stderr) { +- argv[--argc] = talloc_strdup(argv, "--debug-to-stderr"); ++ if (!extra_args_only) { ++ argv[--argc] = talloc_asprintf(argv, "--debug-level=%#.4x", ++ debug_level); + if (argv[argc] == NULL) { + ret = ENOMEM; + goto fail; + } +- } + +- if (child_debug_to_file) { +- argv[--argc] = talloc_asprintf(argv, "--debug-fd=%d", +- child_debug_fd); ++ if (child_debug_stderr) { ++ argv[--argc] = talloc_strdup(argv, "--debug-to-stderr"); ++ if (argv[argc] == NULL) { ++ ret = ENOMEM; ++ goto fail; ++ } ++ } ++ ++ if (child_debug_to_file) { ++ argv[--argc] = talloc_asprintf(argv, "--debug-fd=%d", ++ child_debug_fd); ++ if (argv[argc] == NULL) { ++ ret = ENOMEM; ++ goto fail; ++ } ++ } ++ ++ argv[--argc] = talloc_asprintf(argv, "--debug-timestamps=%d", ++ child_debug_timestamps); + if (argv[argc] == NULL) { + ret = ENOMEM; + goto fail; + } +- } + +- argv[--argc] = talloc_asprintf(argv, "--debug-timestamps=%d", +- child_debug_timestamps); +- if (argv[argc] == NULL) { +- ret = ENOMEM; +- goto fail; +- } +- +- argv[--argc] = talloc_asprintf(argv, "--debug-microseconds=%d", +- child_debug_microseconds); +- if (argv[argc] == NULL) { +- ret = ENOMEM; +- goto fail; ++ argv[--argc] = talloc_asprintf(argv, "--debug-microseconds=%d", ++ child_debug_microseconds); ++ if (argv[argc] == NULL) { ++ ret = ENOMEM; ++ goto fail; ++ } + } + + argv[--argc] = talloc_strdup(argv, binary); +@@ -720,7 +729,7 @@ fail: + errno_t exec_child_ex(TALLOC_CTX *mem_ctx, + int *pipefd_to_child, int *pipefd_from_child, + const char *binary, int debug_fd, +- const char *extra_argv[], ++ const char *extra_argv[], bool extra_args_only, + int child_in_fd, int child_out_fd) + { + int ret; +@@ -746,7 +755,7 @@ errno_t exec_child_ex(TALLOC_CTX *mem_ctx, + } + + ret = prepare_child_argv(mem_ctx, debug_fd, +- binary, extra_argv, ++ binary, extra_argv, extra_args_only, + &argv); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "prepare_child_argv.\n"); +@@ -764,7 +773,7 @@ errno_t exec_child(TALLOC_CTX *mem_ctx, + const char *binary, int debug_fd) + { + return exec_child_ex(mem_ctx, pipefd_to_child, pipefd_from_child, +- binary, debug_fd, NULL, ++ binary, debug_fd, NULL, false, + STDIN_FILENO, STDOUT_FILENO); + } + +diff --git a/src/util/child_common.h b/src/util/child_common.h +index b93991832b7389177f9da05e694ab729ef50cdc7..0111f2cdb26af8543d68e6a6661d656d1c9c45ac 100644 +--- a/src/util/child_common.h ++++ b/src/util/child_common.h +@@ -104,7 +104,7 @@ void fd_nonblocking(int fd); + errno_t exec_child_ex(TALLOC_CTX *mem_ctx, + int *pipefd_to_child, int *pipefd_from_child, + const char *binary, int debug_fd, +- const char *extra_argv[], ++ const char *extra_argv[], bool extra_args_only, + int child_in_fd, int child_out_fd); + + /* Same as exec_child_ex() except child_in_fd is set to STDIN_FILENO and +-- +2.5.0 + diff --git a/0040-DP_TASK-add-be_ptask_get_timeout.patch b/0040-DP_TASK-add-be_ptask_get_timeout.patch new file mode 100644 index 0000000..f186644 --- /dev/null +++ b/0040-DP_TASK-add-be_ptask_get_timeout.patch @@ -0,0 +1,90 @@ +From 6ce7de495012c3b4ec28696466938a784e3a4708 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 18 Jan 2016 13:20:16 +0100 +Subject: [PATCH 40/49] DP_TASK: add be_ptask_get_timeout() + +Reviewed-by: Jakub Hrozek +(cherry picked from commit e89c2cb5ec77d57ed93952dae08df51738834faf) +--- + src/providers/dp_ptask.c | 5 +++++ + src/providers/dp_ptask.h | 1 + + src/tests/cmocka/test_be_ptask.c | 22 ++++++++++++++++++++++ + 3 files changed, 28 insertions(+) + +diff --git a/src/providers/dp_ptask.c b/src/providers/dp_ptask.c +index 51800ab57b5649380c0603f1d602dfa81d1f5919..3ebb134be4a991498ac5692883dd1a42416efcfe 100644 +--- a/src/providers/dp_ptask.c ++++ b/src/providers/dp_ptask.c +@@ -384,6 +384,11 @@ time_t be_ptask_get_period(struct be_ptask *task) + return task->period; + } + ++time_t be_ptask_get_timeout(struct be_ptask *task) ++{ ++ return task->timeout; ++} ++ + struct be_ptask_sync_ctx { + be_ptask_sync_t fn; + void *pvt; +diff --git a/src/providers/dp_ptask.h b/src/providers/dp_ptask.h +index 1b931010bb206285f3ca635f7b0c2399c3050951..3b97553619f5ac2d4292ba61e3de3c7408af812c 100644 +--- a/src/providers/dp_ptask.h ++++ b/src/providers/dp_ptask.h +@@ -126,5 +126,6 @@ void be_ptask_disable(struct be_ptask *task); + void be_ptask_destroy(struct be_ptask **task); + + time_t be_ptask_get_period(struct be_ptask *task); ++time_t be_ptask_get_timeout(struct be_ptask *task); + + #endif /* _DP_PTASK_H_ */ +diff --git a/src/tests/cmocka/test_be_ptask.c b/src/tests/cmocka/test_be_ptask.c +index a0daaf967a6f1ea991ff30445488ffadff51f821..cbf61e81dd00d98cb27f87e31a0c4718f6b9a0b4 100644 +--- a/src/tests/cmocka/test_be_ptask.c ++++ b/src/tests/cmocka/test_be_ptask.c +@@ -33,6 +33,7 @@ + + #define DELAY 2 + #define PERIOD 1 ++#define TIMEOUT 123 + + #define new_test(test) \ + cmocka_unit_test_setup_teardown(test_ ## test, test_setup, test_teardown) +@@ -795,6 +796,26 @@ void test_be_ptask_get_period(void **state) + assert_null(ptask); + } + ++void test_be_ptask_get_timeout(void **state) ++{ ++ struct test_ctx *test_ctx = (struct test_ctx *)(*state); ++ struct be_ptask *ptask = NULL; ++ time_t out_timeout; ++ errno_t ret; ++ ++ ret = be_ptask_create(test_ctx, test_ctx->be_ctx, PERIOD, 0, 0, 0, TIMEOUT, ++ BE_PTASK_OFFLINE_SKIP, 0, test_be_ptask_send, ++ test_be_ptask_recv, test_ctx, "Test ptask", &ptask); ++ assert_int_equal(ret, ERR_OK); ++ assert_non_null(ptask); ++ ++ out_timeout = be_ptask_get_timeout(ptask); ++ assert_true(TIMEOUT == out_timeout); ++ ++ be_ptask_destroy(&ptask); ++ assert_null(ptask); ++} ++ + void test_be_ptask_create_sync(void **state) + { + struct test_ctx *test_ctx = (struct test_ctx *)(*state); +@@ -970,6 +991,7 @@ int main(int argc, const char *argv[]) + new_test(be_ptask_reschedule_timeout), + new_test(be_ptask_reschedule_backoff), + new_test(be_ptask_get_period), ++ new_test(be_ptask_get_timeout), + new_test(be_ptask_create_sync), + new_test(be_ptask_sync_reschedule_ok), + new_test(be_ptask_sync_reschedule_error), +-- +2.5.0 + diff --git a/0041-AD-add-task-to-renew-the-machine-account-password-if.patch b/0041-AD-add-task-to-renew-the-machine-account-password-if.patch new file mode 100644 index 0000000..fabd19a --- /dev/null +++ b/0041-AD-add-task-to-renew-the-machine-account-password-if.patch @@ -0,0 +1,575 @@ +From 70a669646ed841048346b451741e972a0ada703d Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 12 Jan 2016 11:05:02 +0100 +Subject: [PATCH 41/49] AD: add task to renew the machine account password if + needed + +AD expects its clients to renew the machine account password on a +regular basis, be default every 30 days. Even if a client does not renew +the password it might not cause issues because AD does not enforce the +renewal. But the password age might be used to identify unused machine +accounts in large environments which might get disabled or deleted +automatically. + +With this patch SSSD calls an external program to check the age of the +machine account password and renew it if needed. Currently 'adcli' is +used as external program which is able to renew the password since +version 0.8.0. + +Resolves https://fedorahosted.org/sssd/ticket/1041 + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 5f7cd30c865046a7ea69944f7e07c85b4c43465a) +--- + Makefile.am | 1 + + src/config/SSSDConfig/__init__.py.in | 2 + + src/config/etc/sssd.api.d/sssd-ad.conf | 2 + + src/man/sssd-ad.5.xml | 33 +++ + src/providers/ad/ad_common.h | 5 + + src/providers/ad/ad_init.c | 7 + + src/providers/ad/ad_machine_pw_renewal.c | 372 +++++++++++++++++++++++++++++++ + src/providers/ad/ad_opts.c | 2 + + src/util/util_errors.c | 1 + + src/util/util_errors.h | 1 + + 10 files changed, 426 insertions(+) + create mode 100644 src/providers/ad/ad_machine_pw_renewal.c + +diff --git a/Makefile.am b/Makefile.am +index 1c0b1aada9804b2ef35a09cf1b7bf5e9c65ee4e5..a9099c07fcfe54a88bd56129364dde5262e901ed 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -3061,6 +3061,7 @@ libsss_ad_la_SOURCES = \ + src/providers/ad/ad_common.h \ + src/providers/ad/ad_init.c \ + src/providers/ad/ad_dyndns.c \ ++ src/providers/ad/ad_machine_pw_renewal.c \ + src/providers/ad/ad_id.c \ + src/providers/ad/ad_id.h \ + src/providers/ad/ad_access.c \ +diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in +index 2cb857013fe4bddfd2e79e589d3ba9721dc3ca4f..b4a6fcb0d37469e1dda85eda95fd80825697902c 100644 +--- a/src/config/SSSDConfig/__init__.py.in ++++ b/src/config/SSSDConfig/__init__.py.in +@@ -199,6 +199,8 @@ option_strings = { + 'ad_gpo_map_deny' : _('PAM service names for which GPO-based access is always denied'), + 'ad_gpo_default_right' : _('Default logon right (or permit/deny) to use for unmapped PAM service names'), + 'ad_site' : _('a particular site to be used by the client'), ++ 'ad_maximum_machine_account_password_age' : _('Maximum age in days before the machine account password should be renewed'), ++ 'ad_machine_account_password_renewal_opts' : _('Option for tuing the machine account renewal task'), + + # [provider/krb5] + 'krb5_kdcip' : _('Kerberos server address'), +diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf +index 5eb546caac913b839112a70bd81dbde2c7ff2d9f..0ea73d14112d1c7cf7a6d4cbda0d2b2e53a3a7be 100644 +--- a/src/config/etc/sssd.api.d/sssd-ad.conf ++++ b/src/config/etc/sssd.api.d/sssd-ad.conf +@@ -17,6 +17,8 @@ ad_gpo_map_permit = str, None, false + ad_gpo_map_deny = str, None, false + ad_gpo_default_right = str, None, false + ad_site = str, None, false ++ad_maximum_machine_account_password_age = int, None, false ++ad_machine_account_password_renewal_opts = str, None, false + ldap_uri = str, None, false + ldap_backup_uri = str, None, false + ldap_search_base = str, None, false +diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml +index 173fb93009f66c2c83ab87ff5ca900fc10cbf5e8..4280eac5f4594b26d158a0ea58622f9fe7beb53e 100644 +--- a/src/man/sssd-ad.5.xml ++++ b/src/man/sssd-ad.5.xml +@@ -719,6 +719,39 @@ ad_gpo_map_deny = +my_pam_service + + + ++ ad_maximum_machine_account_password_age (integer) ++ ++ ++ SSSD will check once a day if the machine account ++ password is older than the given age in days and try ++ to renew it. A value of 0 will disable the renewal ++ attempt. ++ ++ ++ Default: 30 days ++ ++ ++ ++ ++ ++ ad_machine_account_password_renewal_opts (string) ++ ++ ++ This option should only be used to test the machine ++ account renewal task. The option expect 2 integers ++ seperated by a colon (':'). The first integer ++ defines the interval in seconds how often the task ++ is run. The second specifies the inital timeout in ++ seconds before the task is run for the first time ++ after startup. ++ ++ ++ Default: 86400:750 (24h and 15m) ++ ++ ++ ++ ++ + dyndns_update (boolean) + + +diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h +index 2dd4175487cd36215dad1aaa9111e316a1fc3a0a..5bb2e52d402e4279fdc60d4ab58afd2292358487 100644 +--- a/src/providers/ad/ad_common.h ++++ b/src/providers/ad/ad_common.h +@@ -62,6 +62,8 @@ enum ad_basic_opt { + AD_GPO_DEFAULT_RIGHT, + AD_SITE, + AD_KRB5_CONFD_PATH, ++ AD_MAXIMUM_MACHINE_ACCOUNT_PASSWORD_AGE, ++ AD_MACHINE_ACCOUNT_PASSWORD_RENEWAL_OPTS, + + AD_OPTS_BASIC /* opts counter */ + }; +@@ -180,4 +182,7 @@ int ad_autofs_init(struct be_ctx *be_ctx, + struct bet_ops **ops, + void **pvt_data); + ++errno_t ad_machine_account_password_renewal_init(struct be_ctx *be_ctx, ++ struct ad_options *ad_opts); ++ + #endif /* AD_COMMON_H_ */ +diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c +index 72ce5536b0f0f69a530bda0ffc41ae93180c1a94..e40fb6f1d0eabae45581969f1ff73c8cf302fb4c 100644 +--- a/src/providers/ad/ad_init.c ++++ b/src/providers/ad/ad_init.c +@@ -308,6 +308,13 @@ sssm_ad_id_init(struct be_ctx *bectx, + "will not work [%d]: %s\n", ret, strerror(ret)); + } + ++ ret = ad_machine_account_password_renewal_init(bectx, ad_options); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot setup task for machine account " ++ "password renewal.\n"); ++ goto done; ++ } ++ + *ops = &ad_id_ops; + *pvt_data = ad_ctx; + +diff --git a/src/providers/ad/ad_machine_pw_renewal.c b/src/providers/ad/ad_machine_pw_renewal.c +new file mode 100644 +index 0000000000000000000000000000000000000000..e42c700e7aa3cf9a45acee025e36899b36642dad +--- /dev/null ++++ b/src/providers/ad/ad_machine_pw_renewal.c +@@ -0,0 +1,372 @@ ++/* ++ SSSD ++ ++ Authors: ++ Sumit Bose ++ ++ Copyright (C) 2016 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++ ++#include "util/util.h" ++#include "util/strtonum.h" ++#include "providers/dp_ptask.h" ++#include "providers/ad/ad_common.h" ++ ++#ifndef RENEWAL_PROG_PATH ++#define RENEWAL_PROG_PATH "/usr/sbin/adcli" ++#endif ++ ++struct renewal_data { ++ char *prog_path; ++ const char **extra_args; ++}; ++ ++static errno_t get_adcli_extra_args(const char *ad_domain, ++ const char *ad_hostname, ++ const char *ad_keytab, ++ size_t pw_lifetime_in_days, ++ size_t period, ++ size_t initial_delay, ++ struct renewal_data *renewal_data) ++{ ++ const char **args; ++ size_t c = 0; ++ ++ if (ad_domain == NULL || ad_hostname == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Missing AD domain or hostname.\n"); ++ return EINVAL; ++ } ++ ++ renewal_data->prog_path = talloc_strdup(renewal_data, RENEWAL_PROG_PATH); ++ if (renewal_data->prog_path == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ++ return ENOMEM; ++ } ++ ++ args = talloc_array(renewal_data, const char *, 7); ++ if (args == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n"); ++ return ENOMEM; ++ } ++ ++ /* extra_args are added in revers order */ ++ args[c++] = talloc_asprintf(args, "--computer-password-lifetime=%zu", ++ pw_lifetime_in_days); ++ args[c++] = talloc_asprintf(args, "--host-fqdn=%s", ad_hostname); ++ if (ad_keytab != NULL) { ++ args[c++] = talloc_asprintf(args, "--host-keytab=%s", ad_keytab); ++ } ++ args[c++] = talloc_asprintf(args, "--domain=%s", ad_domain); ++ if (DEBUG_IS_SET(SSSDBG_TRACE_LIBS)) { ++ args[c++] = talloc_strdup(args, "--verbose"); ++ } ++ args[c++] = talloc_strdup(args, "update"); ++ args[c] = NULL; ++ ++ do { ++ if (args[--c] == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "talloc failed while copying arguments.\n"); ++ talloc_free(args); ++ return ENOMEM; ++ } ++ } while (c != 0); ++ ++ renewal_data->extra_args = args; ++ ++ return EOK; ++} ++ ++struct renewal_state { ++ int child_status; ++ struct sss_child_ctx_old *child_ctx; ++ struct tevent_timer *timeout_handler; ++ struct tevent_context *ev; ++ ++ int write_to_child_fd; ++ int read_from_child_fd; ++}; ++ ++static void ad_machine_account_password_renewal_done(struct tevent_req *subreq); ++static void ++ad_machine_account_password_renewal_timeout(struct tevent_context *ev, ++ struct tevent_timer *te, ++ struct timeval tv, void *pvt); ++ ++static struct tevent_req * ++ad_machine_account_password_renewal_send(TALLOC_CTX *mem_ctx, ++ struct tevent_context *ev, ++ struct be_ctx *be_ctx, ++ struct be_ptask *be_ptask, ++ void *pvt) ++{ ++ struct renewal_data *renewal_data; ++ struct renewal_state *state; ++ struct tevent_req *req; ++ struct tevent_req *subreq; ++ pid_t child_pid; ++ struct timeval tv; ++ int pipefd_to_child[2]; ++ int pipefd_from_child[2]; ++ int ret; ++ ++ req = tevent_req_create(mem_ctx, &state, struct renewal_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "tevent_req_create failed.\n"); ++ return NULL; ++ } ++ ++ renewal_data = talloc_get_type(pvt, struct renewal_data); ++ ++ state->ev = ev; ++ state->child_status = EFAULT; ++ state->read_from_child_fd = -1; ++ state->write_to_child_fd = -1; ++ ++ ret = pipe(pipefd_from_child); ++ if (ret == -1) { ++ ret = errno; ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "pipe failed [%d][%s].\n", ret, strerror(ret)); ++ goto done; ++ } ++ ret = pipe(pipefd_to_child); ++ if (ret == -1) { ++ ret = errno; ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "pipe failed [%d][%s].\n", ret, strerror(ret)); ++ goto done; ++ } ++ ++ child_pid = fork(); ++ if (child_pid == 0) { /* child */ ++ ret = exec_child_ex(state, pipefd_to_child, pipefd_from_child, ++ renewal_data->prog_path, -1, ++ renewal_data->extra_args, true, ++ STDIN_FILENO, STDERR_FILENO); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec renewal child: [%d][%s].\n", ++ ret, strerror(ret)); ++ goto done; ++ } ++ } else if (child_pid > 0) { /* parent */ ++ ++ state->read_from_child_fd = pipefd_from_child[0]; ++ close(pipefd_from_child[1]); ++ sss_fd_nonblocking(state->read_from_child_fd); ++ ++ state->write_to_child_fd = pipefd_to_child[1]; ++ close(pipefd_to_child[0]); ++ sss_fd_nonblocking(state->write_to_child_fd); ++ ++ /* Set up SIGCHLD handler */ ++ ret = child_handler_setup(ev, child_pid, NULL, NULL, &state->child_ctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Could not set up child handlers [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ ret = ERR_RENEWAL_CHILD; ++ goto done; ++ } ++ ++ /* Set up timeout handler */ ++ tv = tevent_timeval_current_ofs(be_ptask_get_timeout(be_ptask), 0); ++ state->timeout_handler = tevent_add_timer(ev, req, tv, ++ ad_machine_account_password_renewal_timeout, ++ req); ++ if(state->timeout_handler == NULL) { ++ ret = ERR_RENEWAL_CHILD; ++ goto done; ++ } ++ ++ subreq = read_pipe_send(state, ev, state->read_from_child_fd); ++ if (subreq == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "read_pipe_send failed.\n"); ++ ret = ERR_RENEWAL_CHILD; ++ goto done; ++ } ++ tevent_req_set_callback(subreq, ++ ad_machine_account_password_renewal_done, req); ++ ++ /* Now either wait for the timeout to fire or the child ++ * to finish ++ */ ++ } else { /* error */ ++ ret = errno; ++ DEBUG(SSSDBG_CRIT_FAILURE, "fork failed [%d][%s].\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ tevent_req_post(req, ev); ++ } ++ return req; ++} ++ ++static void ad_machine_account_password_renewal_done(struct tevent_req *subreq) ++{ ++ uint8_t *buf; ++ ssize_t buf_len; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct renewal_state *state = tevent_req_data(req, struct renewal_state); ++ int ret; ++ ++ talloc_zfree(state->timeout_handler); ++ ++ ret = read_pipe_recv(subreq, state, &buf, &buf_len); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_LIBS, "--- adcli output start---\n" ++ "%.*s" ++ "---adcli output end---\n", ++ (int) buf_len, buf); ++ ++ close(state->read_from_child_fd); ++ state->read_from_child_fd = -1; ++ ++ ++ tevent_req_done(req); ++ return; ++} ++ ++static void ++ad_machine_account_password_renewal_timeout(struct tevent_context *ev, ++ struct tevent_timer *te, ++ struct timeval tv, void *pvt) ++{ ++ struct tevent_req *req = talloc_get_type(pvt, struct tevent_req); ++ struct renewal_state *state = tevent_req_data(req, struct renewal_state); ++ ++ DEBUG(SSSDBG_CRIT_FAILURE, "Timeout reached for AD renewal child.\n"); ++ child_handler_destroy(state->child_ctx); ++ state->child_ctx = NULL; ++ state->child_status = ETIMEDOUT; ++ tevent_req_error(req, ERR_RENEWAL_CHILD); ++} ++ ++static errno_t ++ad_machine_account_password_renewal_recv(struct tevent_req *req) ++{ ++ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ return EOK; ++} ++ ++errno_t ad_machine_account_password_renewal_init(struct be_ctx *be_ctx, ++ struct ad_options *ad_opts) ++{ ++ int ret; ++ struct renewal_data *renewal_data; ++ int lifetime; ++ size_t period; ++ size_t initial_delay; ++ const char *dummy; ++ char **opt_list; ++ int opt_list_size; ++ char *endptr; ++ ++ lifetime = dp_opt_get_int(ad_opts->basic, ++ AD_MAXIMUM_MACHINE_ACCOUNT_PASSWORD_AGE); ++ ++ if (lifetime == 0) { ++ DEBUG(SSSDBG_CONF_SETTINGS, "Automatic machine account renewal disabled.\n"); ++ return EOK; ++ } ++ ++ if (lifetime < 0) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Illegal value [%d] for password lifetime.\n", lifetime); ++ return EINVAL; ++ } ++ ++ renewal_data = talloc(be_ctx, struct renewal_data); ++ if (renewal_data == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc failed.\n"); ++ return ENOMEM; ++ } ++ ++ dummy = dp_opt_get_cstring(ad_opts->basic, ++ AD_MACHINE_ACCOUNT_PASSWORD_RENEWAL_OPTS); ++ ret = split_on_separator(renewal_data, dummy, ':', true, false, ++ &opt_list, &opt_list_size); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "split_on_separator failed.\n"); ++ goto done; ++ } ++ ++ if (opt_list_size != 2) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Wrong number of renewal options.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ errno = 0; ++ period = strtouint32(opt_list[0], &endptr, 10); ++ if (errno != 0 || *endptr != '\0' || opt_list[0] == endptr) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse first renewal option.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ errno = 0; ++ initial_delay = strtouint32(opt_list[1], &endptr, 10); ++ if (errno != 0 || *endptr != '\0' || opt_list[0] == endptr) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse second renewal option.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ ret = get_adcli_extra_args(dp_opt_get_cstring(ad_opts->basic, AD_DOMAIN), ++ dp_opt_get_cstring(ad_opts->basic, AD_HOSTNAME), ++ dp_opt_get_cstring(ad_opts->id_ctx->sdap_id_ctx->opts->basic, ++ SDAP_KRB5_KEYTAB), ++ lifetime, period, initial_delay, renewal_data); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "get_adcli_extra_args failed.\n"); ++ goto done; ++ } ++ ++ ret = be_ptask_create(be_ctx, be_ctx, period, initial_delay, 0, 0, 60, ++ BE_PTASK_OFFLINE_DISABLE, 0, ++ ad_machine_account_password_renewal_send, ++ ad_machine_account_password_renewal_recv, ++ renewal_data, ++ "AD machine account password renewal", NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "be_ptask_create failed.\n"); ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ if (ret != EOK) { ++ talloc_free(renewal_data); ++ } ++ ++ return ret; ++} +diff --git a/src/providers/ad/ad_opts.c b/src/providers/ad/ad_opts.c +index 4ea96637ca7264c76109ed8c2f7b5e8a94f73bfe..8b2841eadc0236b51f8c9c2c02b7c98837fbe416 100644 +--- a/src/providers/ad/ad_opts.c ++++ b/src/providers/ad/ad_opts.c +@@ -48,6 +48,8 @@ struct dp_option ad_basic_opts[] = { + { "ad_gpo_default_right", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "ad_site", DP_OPT_STRING, NULL_STRING, NULL_STRING }, + { "krb5_confd_path", DP_OPT_STRING, { KRB5_MAPPING_DIR }, NULL_STRING }, ++ { "ad_maximum_machine_account_password_age", DP_OPT_NUMBER, { .number = 30 }, NULL_NUMBER }, ++ { "ad_machine_account_password_renewal_opts", DP_OPT_STRING, { "86400:750" }, NULL_STRING }, + DP_OPTION_TERMINATOR + }; + +diff --git a/src/util/util_errors.c b/src/util/util_errors.c +index ed19346d9b588a711367af4c891b1298cd4f067e..1d684d387b90b8db37609d5bc022e06fcac708f9 100644 +--- a/src/util/util_errors.c ++++ b/src/util/util_errors.c +@@ -82,6 +82,7 @@ struct err_string error_to_str[] = { + { "Address family not supported" }, /* ERR_ADDR_FAMILY_NOT_SUPPORTED */ + { "Message sender is the bus" }, /* ERR_SBUS_SENDER_BUS */ + { "Subdomain is inactive" }, /* ERR_SUBDOM_INACTIVE */ ++ { "AD renewal child failed" }, /* ERR_RENEWAL_CHILD */ + { "ERR_LAST" } /* ERR_LAST */ + }; + +diff --git a/src/util/util_errors.h b/src/util/util_errors.h +index c1d081912a382d645c27809a3ac336ff90047cdf..5c02fdd8b4c6e0c59f7fd6f66a3fc8a8e48dc607 100644 +--- a/src/util/util_errors.h ++++ b/src/util/util_errors.h +@@ -104,6 +104,7 @@ enum sssd_errors { + ERR_ADDR_FAMILY_NOT_SUPPORTED, + ERR_SBUS_SENDER_BUS, + ERR_SUBDOM_INACTIVE, ++ ERR_RENEWAL_CHILD, + ERR_LAST /* ALWAYS LAST */ + }; + +-- +2.5.0 + diff --git a/0042-FO-add-fo_get_active_server.patch b/0042-FO-add-fo_get_active_server.patch new file mode 100644 index 0000000..7bbb4ad --- /dev/null +++ b/0042-FO-add-fo_get_active_server.patch @@ -0,0 +1,95 @@ +From 7012e1c6d5571eb75015b679dbadcd14c68d4f58 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 19 Jan 2016 15:04:04 +0100 +Subject: [PATCH 42/49] FO: add fo_get_active_server() + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 5a7f17aedad34a8618765bc33342c109a6958ab5) +--- + src/providers/fail_over.c | 5 +++++ + src/providers/fail_over.h | 2 ++ + src/tests/fail_over-tests.c | 11 +++++++++++ + 3 files changed, 18 insertions(+) + +diff --git a/src/providers/fail_over.c b/src/providers/fail_over.c +index b076687ac6e571f7e27402fd11ac60183ea46951..b51a6c99ce031a1566f5d021fcf41843891a2d1c 100644 +--- a/src/providers/fail_over.c ++++ b/src/providers/fail_over.c +@@ -1457,6 +1457,11 @@ fo_set_port_status(struct fo_server *server, enum port_status status) + } + } + ++struct fo_server *fo_get_active_server(struct fo_service *service) ++{ ++ return service->active_server; ++} ++ + void fo_try_next_server(struct fo_service *service) + { + struct fo_server *server; +diff --git a/src/providers/fail_over.h b/src/providers/fail_over.h +index e49c6414a14eb6ca2cad333f8efbb58576811345..b8272a0a16015ff6b5d287b775c33a77e23eba67 100644 +--- a/src/providers/fail_over.h ++++ b/src/providers/fail_over.h +@@ -200,6 +200,8 @@ void fo_reset_services(struct fo_ctx *fo_ctx); + + void fo_reset_servers(struct fo_service *svc); + ++struct fo_server *fo_get_active_server(struct fo_service *service); ++ + bool fo_svc_has_server(struct fo_service *service, struct fo_server *server); + + /* +diff --git a/src/tests/fail_over-tests.c b/src/tests/fail_over-tests.c +index b21ead38229be5d55df2de10bec3dd00a8566d71..c9bac68711cfcf624064b5881f5226d4f8449e39 100644 +--- a/src/tests/fail_over-tests.c ++++ b/src/tests/fail_over-tests.c +@@ -50,6 +50,7 @@ struct test_ctx { + struct task { + struct test_ctx *test_ctx; + const char *location; ++ struct fo_service *service; + int recv; + int port; + int new_server_status; +@@ -147,6 +148,7 @@ test_resolve_service_callback(struct tevent_req *req) + int port; + struct task *task; + struct fo_server *server = NULL; ++ struct fo_server *active_server = NULL; + struct resolv_hostent *he; + int i; + +@@ -181,6 +183,13 @@ test_resolve_service_callback(struct tevent_req *req) + } + } + ++ if (task->new_port_status == PORT_WORKING ++ && task->new_server_status == SERVER_WORKING) { ++ active_server = fo_get_active_server(task->service); ++ fail_if(active_server == NULL, "Missing active server"); ++ fail_if(server != active_server, "Current server is not active server"); ++ } ++ + } + + #define get_request(a, b, c, d, e, f) \ +@@ -203,6 +212,7 @@ _get_request(struct test_ctx *test_ctx, struct fo_service *service, + task->new_port_status = new_port_status; + task->new_server_status = new_server_status; + task->location = location; ++ task->service = service; + test_ctx->tasks++; + + req = fo_resolve_service_send(test_ctx, test_ctx->ev, +@@ -242,6 +252,7 @@ START_TEST(test_fo_resolve_service) + + /* Make requests. */ + get_request(ctx, service[0], EOK, 20, PORT_WORKING, -1); ++ get_request(ctx, service[0], EOK, 20, PORT_WORKING, SERVER_WORKING); + get_request(ctx, service[0], EOK, 20, -1, SERVER_NOT_WORKING); + get_request(ctx, service[0], EOK, 80, PORT_WORKING, -1); + get_request(ctx, service[0], EOK, 80, PORT_NOT_WORKING, -1); +-- +2.5.0 + diff --git a/0043-FO-add-be_fo_get_active_server_name.patch b/0043-FO-add-be_fo_get_active_server_name.patch new file mode 100644 index 0000000..253d2cc --- /dev/null +++ b/0043-FO-add-be_fo_get_active_server_name.patch @@ -0,0 +1,57 @@ +From ba178abc4f4ddeb0faf65cb779b15e6a95f113fc Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 19 Jan 2016 15:05:03 +0100 +Subject: [PATCH 43/49] FO: add be_fo_get_active_server_name() + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 7fdec78178440855058be8ca1011e0b1aa45de31) +--- + src/providers/data_provider_fo.c | 17 +++++++++++++++++ + src/providers/dp_backend.h | 3 +++ + 2 files changed, 20 insertions(+) + +diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c +index cd57340a0ba0ac7e474dc502bf1f1b4de0e1f778..d1d8c4c5c94811ce73b550dc99166d3c913b95aa 100644 +--- a/src/providers/data_provider_fo.c ++++ b/src/providers/data_provider_fo.c +@@ -723,6 +723,23 @@ void be_fo_try_next_server(struct be_ctx *ctx, const char *service_name) + } + } + ++const char *be_fo_get_active_server_name(struct be_ctx *ctx, ++ const char *service_name) ++{ ++ struct be_svc_data *svc; ++ struct fo_server *server; ++ ++ svc = be_fo_find_svc_data(ctx, service_name); ++ if (svc != NULL) { ++ server = fo_get_active_server(svc->fo_service); ++ if (server != NULL) { ++ return fo_get_server_name(server); ++ } ++ } ++ ++ return NULL; ++} ++ + int be_fo_run_callbacks_at_next_request(struct be_ctx *ctx, + const char *service_name) + { +diff --git a/src/providers/dp_backend.h b/src/providers/dp_backend.h +index 0ced851be8468ce21a9d283e26461fc47194557e..ffeeca4a6bad976ae8922bc4964b839242290259 100644 +--- a/src/providers/dp_backend.h ++++ b/src/providers/dp_backend.h +@@ -285,6 +285,9 @@ int be_fo_run_callbacks_at_next_request(struct be_ctx *ctx, + void reset_fo(struct be_ctx *be_ctx); + void be_fo_reset_svc(struct be_ctx *be_ctx, const char *svc_name); + ++const char *be_fo_get_active_server_name(struct be_ctx *ctx, ++ const char *service_name); ++ + errno_t be_res_init(struct be_ctx *ctx); + + /* be_req helpers */ +-- +2.5.0 + diff --git a/0044-AD-try-to-use-current-server-in-the-renewal-task.patch b/0044-AD-try-to-use-current-server-in-the-renewal-task.patch new file mode 100644 index 0000000..c14f283 --- /dev/null +++ b/0044-AD-try-to-use-current-server-in-the-renewal-task.patch @@ -0,0 +1,92 @@ +From 3e1fe540aa11d653dff45c00f2845c5394706c1b Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 19 Jan 2016 15:05:36 +0100 +Subject: [PATCH 44/49] AD: try to use current server in the renewal task + +Reviewed-by: Jakub Hrozek +(cherry picked from commit 8167761a1e1d7575d49babcea45937fc9cd45fdc) +--- + src/providers/ad/ad_machine_pw_renewal.c | 26 +++++++++++++++++++++++--- + 1 file changed, 23 insertions(+), 3 deletions(-) + +diff --git a/src/providers/ad/ad_machine_pw_renewal.c b/src/providers/ad/ad_machine_pw_renewal.c +index e42c700e7aa3cf9a45acee025e36899b36642dad..7997fbb0cdaa9490cd4e5c794c9d98e3b892673e 100644 +--- a/src/providers/ad/ad_machine_pw_renewal.c ++++ b/src/providers/ad/ad_machine_pw_renewal.c +@@ -31,6 +31,7 @@ + #endif + + struct renewal_data { ++ struct be_ctx *be_ctx; + char *prog_path; + const char **extra_args; + }; +@@ -57,13 +58,16 @@ static errno_t get_adcli_extra_args(const char *ad_domain, + return ENOMEM; + } + +- args = talloc_array(renewal_data, const char *, 7); ++ args = talloc_array(renewal_data, const char *, 8); + if (args == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n"); + return ENOMEM; + } + + /* extra_args are added in revers order */ ++ /* first add NULL as a placeholder for the server name which is determined ++ * at runtime */ ++ args[c++] = NULL; + args[c++] = talloc_asprintf(args, "--computer-password-lifetime=%zu", + pw_lifetime_in_days); + args[c++] = talloc_asprintf(args, "--host-fqdn=%s", ad_hostname); +@@ -84,7 +88,7 @@ static errno_t get_adcli_extra_args(const char *ad_domain, + talloc_free(args); + return ENOMEM; + } +- } while (c != 0); ++ } while (c != 1); /* is is expected that the first element is NULL */ + + renewal_data->extra_args = args; + +@@ -123,6 +127,8 @@ ad_machine_account_password_renewal_send(TALLOC_CTX *mem_ctx, + int pipefd_to_child[2]; + int pipefd_from_child[2]; + int ret; ++ const char **extra_args; ++ const char *server_name; + + req = tevent_req_create(mem_ctx, &state, struct renewal_state); + if (req == NULL) { +@@ -137,6 +143,20 @@ ad_machine_account_password_renewal_send(TALLOC_CTX *mem_ctx, + state->read_from_child_fd = -1; + state->write_to_child_fd = -1; + ++ server_name = be_fo_get_active_server_name(be_ctx, AD_SERVICE_NAME); ++ talloc_zfree(renewal_data->extra_args[0]); ++ if (server_name != NULL) { ++ renewal_data->extra_args[0] = talloc_asprintf(renewal_data->extra_args, ++ "--domain-controller=%s", ++ server_name); ++ /* if talloc_asprintf() fails we let adcli try to find a server */ ++ } ++ ++ extra_args = renewal_data->extra_args; ++ if (extra_args[0] == NULL) { ++ extra_args = &renewal_data->extra_args[1]; ++ } ++ + ret = pipe(pipefd_from_child); + if (ret == -1) { + ret = errno; +@@ -156,7 +176,7 @@ ad_machine_account_password_renewal_send(TALLOC_CTX *mem_ctx, + if (child_pid == 0) { /* child */ + ret = exec_child_ex(state, pipefd_to_child, pipefd_from_child, + renewal_data->prog_path, -1, +- renewal_data->extra_args, true, ++ extra_args, true, + STDIN_FILENO, STDERR_FILENO); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec renewal child: [%d][%s].\n", +-- +2.5.0 + diff --git a/sssd.spec b/sssd.spec index 10a53eb..8119eb0 100644 --- a/sssd.spec +++ b/sssd.spec @@ -24,7 +24,7 @@ Name: sssd Version: 1.13.3 -Release: 1%{?dist} +Release: 2%{?dist} Group: Applications/System Summary: System Security Services Daemon License: GPLv3+ @@ -33,6 +33,50 @@ Source0: https://fedorahosted.org/released/sssd/%{name}-%{version}.tar.gz BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) ### Patches ### +Patch0001: 0001-nfs-idmap-fix-infinite-loop.patch +Patch0002: 0002-Use-right-domain-for-user-lookups.patch +Patch0003: 0003-sdap_save_grpmem-determine-domain-by-SID-if-possible.patch +Patch0004: 0004-ipa_s2n_save_objects-use-configured-user-and-group-t.patch +Patch0005: 0005-SPEC-Change-package-ownership-of-pubconfpath-krb5.in.patch +Patch0006: 0006-AD-SRV-prefer-site-local-DCs-in-LDAP-ping.patch +Patch0007: 0007-ldap-remove-originalMeberOf-if-there-is-no-memberOf.patch +Patch0008: 0008-KRB5-Adding-DNS-SRV-lookup-for-krb5-provider.patch +Patch0009: 0009-SDAP-do-not-fail-if-refs-are-found-but-not-processed.patch +Patch0010: 0010-sudo-remove-unused-param-name-in-sdap_sudo_get_usn.patch +Patch0011: 0011-sudo-remove-unused-param.-in-ldap_get_sudo_options.patch +Patch0012: 0012-SDAP-Add-request-that-iterates-over-all-search-bases.patch +Patch0013: 0013-SDAP-rename-sdap_get_id_specific_filter.patch +Patch0014: 0014-SDAP-support-empty-filters-in-sdap_combine_filters.patch +Patch0015: 0015-SUDO-use-sdap_search_bases-instead-custom-sb-iterato.patch +Patch0016: 0016-SUDO-make-sudo-sysdb-interface-more-reusable.patch +Patch0017: 0017-SUDO-move-code-shared-between-ldap-and-ipa-to-separa.patch +Patch0018: 0018-SUDO-allow-to-disable-ptask.patch +Patch0019: 0019-SUDO-fail-on-failed-request-that-cannot-be-retry.patch +Patch0020: 0020-IPA-add-ipa_get_rdn-and-ipa_check_rdn.patch +Patch0021: 0021-SDAP-use-ipa_get_rdn-in-nested-groups.patch +Patch0022: 0022-IPA-SUDO-choose-between-IPA-and-LDAP-schema.patch +Patch0023: 0023-IPA-SUDO-Add-ipasudorule-mapping.patch +Patch0024: 0024-IPA-SUDO-Add-ipasudocmdgrp-mapping.patch +Patch0025: 0025-IPA-SUDO-Add-ipasudocmd-mapping.patch +Patch0026: 0026-IPA-SUDO-Implement-sudo-handler.patch +Patch0027: 0027-IPA-SUDO-Implement-full-refresh.patch +Patch0028: 0028-IPA-SUDO-Implement-rules-refresh.patch +Patch0029: 0029-IPA-SUDO-Remember-USN.patch +Patch0030: 0030-SDAP-Add-sdap_or_filters.patch +Patch0031: 0031-IPA-SUDO-Implement-smart-refresh.patch +Patch0032: 0032-SUDO-sdap_sudo_set_usn-do-not-steal-usn.patch +Patch0033: 0033-SUDO-remove-full_refresh_in_progress.patch +Patch0034: 0034-SUDO-assume-zero-if-usn-is-unknown.patch +Patch0035: 0035-SUDO-allow-disabling-full-refresh.patch +Patch0036: 0036-SUDO-remember-usn-as-number-instead-of-string.patch +Patch0037: 0037-SUDO-simplify-usn-filter.patch +Patch0038: 0038-IPA-SUDO-Add-support-for-ipaSudoRunAsExt-attributes.patch +Patch0039: 0039-UTIL-allow-to-skip-default-options-for-child-process.patch +Patch0040: 0040-DP_TASK-add-be_ptask_get_timeout.patch +Patch0041: 0041-AD-add-task-to-renew-the-machine-account-password-if.patch +Patch0042: 0042-FO-add-fo_get_active_server.patch +Patch0043: 0043-FO-add-be_fo_get_active_server_name.patch +Patch0044: 0044-AD-try-to-use-current-server-in-the-renewal-task.patch Patch0100: 0100-FO-Don-t-free-rc-allocated-structure.patch Patch0101: 0101-tests-Reduce-failover-code-duplication.patch Patch0102: 0102-FO-Use-refcount-to-keep-track-of-servers-returned-to.patch @@ -1019,6 +1063,9 @@ fi %{_libdir}/%{name}/modules/libwbclient.so %changelog +* Tue Jan 19 2016 Lukas Slebodnik - 1.13.3-2 +- Resolves: rhbz#1256849 - SUDO: Support the IPA schema + * Wed Dec 16 2015 Lukas Slebodnik - 1.13.3-1 - New upstream release 1.13.3 - https://fedorahosted.org/sssd/wiki/Releases/Notes-1.13.3