From 2dd8451396f36c4aeca498637fadf69428fe6d6e Mon Sep 17 00:00:00 2001 From: Fabiano Fidêncio Date: Apr 27 2018 20:12:12 +0000 Subject: Resolves: upstream#2653 - Group renaming issue when "id_provider = ldap" is set. Signed-off-by: Fabiano Fidêncio --- diff --git a/0037-NSS-Add-InvalidateGroupById-handler.patch b/0037-NSS-Add-InvalidateGroupById-handler.patch new file mode 100644 index 0000000..7cb604e --- /dev/null +++ b/0037-NSS-Add-InvalidateGroupById-handler.patch @@ -0,0 +1,177 @@ +From d1f38315fa7f8c9d3392af0feb32afc56a0f6c4e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Fri, 16 Feb 2018 13:55:53 +0100 +Subject: [PATCH] NSS: Add InvalidateGroupById handler +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There are some situations where, from the backend, the NSS responder +will have to be notified to invalidate a group. + +In order to achieve this in a clean way, let's add the +InvalidateGroupById handler and make use of it later in this very same +series. + +Related: +https://pagure.io/SSSD/sssd/issue/2653 + +Signed-off-by: Fabiano Fidêncio +Reviewed-by: Jakub Hrozek +(cherry picked from commit 851d31264c826d7e1bca38bb6d49e66b446707e7) +--- + src/responder/nss/nss_iface.c | 16 ++++++++++++++ + src/responder/nss/nss_iface.xml | 3 +++ + src/responder/nss/nss_iface_generated.c | 38 +++++++++++++++++++++++++++++++++ + src/responder/nss/nss_iface_generated.h | 5 +++++ + 4 files changed, 62 insertions(+) + +diff --git a/src/responder/nss/nss_iface.c b/src/responder/nss/nss_iface.c +index 415af9550..805e4fcdf 100644 +--- a/src/responder/nss/nss_iface.c ++++ b/src/responder/nss/nss_iface.c +@@ -199,12 +199,28 @@ int nss_memorycache_update_initgroups(struct sbus_request *sbus_req, + return iface_nss_memorycache_UpdateInitgroups_finish(sbus_req); + } + ++int nss_memorycache_invalidate_group_by_id(struct sbus_request *sbus_req, ++ void *data, ++ gid_t gid) ++{ ++ struct resp_ctx *rctx = talloc_get_type(data, struct resp_ctx); ++ struct nss_ctx *nctx = talloc_get_type(rctx->pvt_ctx, struct nss_ctx); ++ ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "Invalidating group %"PRIu32" from memory cache\n", gid); ++ ++ sss_mmap_cache_gr_invalidate_gid(nctx->grp_mc_ctx, gid); ++ ++ return iface_nss_memorycache_InvalidateGroupById_finish(sbus_req); ++} ++ + struct iface_nss_memorycache iface_nss_memorycache = { + { &iface_nss_memorycache_meta, 0 }, + .UpdateInitgroups = nss_memorycache_update_initgroups, + .InvalidateAllUsers = nss_memorycache_invalidate_users, + .InvalidateAllGroups = nss_memorycache_invalidate_groups, + .InvalidateAllInitgroups = nss_memorycache_invalidate_initgroups, ++ .InvalidateGroupById = nss_memorycache_invalidate_group_by_id, + }; + + static struct sbus_iface_map iface_map[] = { +diff --git a/src/responder/nss/nss_iface.xml b/src/responder/nss/nss_iface.xml +index 27aae0197..4d8cf14f9 100644 +--- a/src/responder/nss/nss_iface.xml ++++ b/src/responder/nss/nss_iface.xml +@@ -14,5 +14,8 @@ + + + ++ ++ ++ + + +diff --git a/src/responder/nss/nss_iface_generated.c b/src/responder/nss/nss_iface_generated.c +index 4a8b704da..8d5a4584b 100644 +--- a/src/responder/nss/nss_iface_generated.c ++++ b/src/responder/nss/nss_iface_generated.c +@@ -12,6 +12,9 @@ + /* invokes a handler with a 'ssau' DBus signature */ + static int invoke_ssau_method(struct sbus_request *dbus_req, void *function_ptr); + ++/* invokes a handler with a 'u' DBus signature */ ++static int invoke_u_method(struct sbus_request *dbus_req, void *function_ptr); ++ + /* arguments for org.freedesktop.sssd.nss.MemoryCache.UpdateInitgroups */ + const struct sbus_arg_meta iface_nss_memorycache_UpdateInitgroups__in[] = { + { "user", "s" }, +@@ -44,6 +47,18 @@ int iface_nss_memorycache_InvalidateAllInitgroups_finish(struct sbus_request *re + DBUS_TYPE_INVALID); + } + ++/* arguments for org.freedesktop.sssd.nss.MemoryCache.InvalidateGroupById */ ++const struct sbus_arg_meta iface_nss_memorycache_InvalidateGroupById__in[] = { ++ { "gid", "u" }, ++ { NULL, } ++}; ++ ++int iface_nss_memorycache_InvalidateGroupById_finish(struct sbus_request *req) ++{ ++ return sbus_request_return_and_finish(req, ++ DBUS_TYPE_INVALID); ++} ++ + /* methods for org.freedesktop.sssd.nss.MemoryCache */ + const struct sbus_method_meta iface_nss_memorycache__methods[] = { + { +@@ -74,6 +89,13 @@ const struct sbus_method_meta iface_nss_memorycache__methods[] = { + offsetof(struct iface_nss_memorycache, InvalidateAllInitgroups), + NULL, /* no invoker */ + }, ++ { ++ "InvalidateGroupById", /* name */ ++ iface_nss_memorycache_InvalidateGroupById__in, ++ NULL, /* no out_args */ ++ offsetof(struct iface_nss_memorycache, InvalidateGroupById), ++ invoke_u_method, ++ }, + { NULL, } + }; + +@@ -86,6 +108,22 @@ const struct sbus_interface_meta iface_nss_memorycache_meta = { + sbus_invoke_get_all, /* GetAll invoker */ + }; + ++/* invokes a handler with a 'u' DBus signature */ ++static int invoke_u_method(struct sbus_request *dbus_req, void *function_ptr) ++{ ++ uint32_t arg_0; ++ int (*handler)(struct sbus_request *, void *, uint32_t) = function_ptr; ++ ++ if (!sbus_request_parse_or_finish(dbus_req, ++ DBUS_TYPE_UINT32, &arg_0, ++ DBUS_TYPE_INVALID)) { ++ return EOK; /* request handled */ ++ } ++ ++ return (handler)(dbus_req, dbus_req->intf->handler_data, ++ arg_0); ++} ++ + /* invokes a handler with a 'ssau' DBus signature */ + static int invoke_ssau_method(struct sbus_request *dbus_req, void *function_ptr) + { +diff --git a/src/responder/nss/nss_iface_generated.h b/src/responder/nss/nss_iface_generated.h +index 11fac7916..27a6d0853 100644 +--- a/src/responder/nss/nss_iface_generated.h ++++ b/src/responder/nss/nss_iface_generated.h +@@ -18,6 +18,7 @@ + #define IFACE_NSS_MEMORYCACHE_INVALIDATEALLUSERS "InvalidateAllUsers" + #define IFACE_NSS_MEMORYCACHE_INVALIDATEALLGROUPS "InvalidateAllGroups" + #define IFACE_NSS_MEMORYCACHE_INVALIDATEALLINITGROUPS "InvalidateAllInitgroups" ++#define IFACE_NSS_MEMORYCACHE_INVALIDATEGROUPBYID "InvalidateGroupById" + + /* ------------------------------------------------------------------------ + * DBus handlers +@@ -44,6 +45,7 @@ struct iface_nss_memorycache { + int (*InvalidateAllUsers)(struct sbus_request *req, void *data); + int (*InvalidateAllGroups)(struct sbus_request *req, void *data); + int (*InvalidateAllInitgroups)(struct sbus_request *req, void *data); ++ int (*InvalidateGroupById)(struct sbus_request *req, void *data, uint32_t arg_gid); + }; + + /* finish function for UpdateInitgroups */ +@@ -58,6 +60,9 @@ int iface_nss_memorycache_InvalidateAllGroups_finish(struct sbus_request *req); + /* finish function for InvalidateAllInitgroups */ + int iface_nss_memorycache_InvalidateAllInitgroups_finish(struct sbus_request *req); + ++/* finish function for InvalidateGroupById */ ++int iface_nss_memorycache_InvalidateGroupById_finish(struct sbus_request *req); ++ + /* ------------------------------------------------------------------------ + * DBus Interface Metadata + * +-- +2.14.3 + diff --git a/0038-DP-Add-dp_sbus_invalidate_group_memcache.patch b/0038-DP-Add-dp_sbus_invalidate_group_memcache.patch new file mode 100644 index 0000000..7f738c6 --- /dev/null +++ b/0038-DP-Add-dp_sbus_invalidate_group_memcache.patch @@ -0,0 +1,91 @@ +From efaabeae96f76036bbe06122f7fbf70a66d26c56 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 19 Feb 2018 08:42:10 +0100 +Subject: [PATCH] DP: Add dp_sbus_invalidate_group_memcache() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This function will be called from the data provider to the NSS +responder, which will invalidate a group in the memcache. + +Related: +https://pagure.io/SSSD/sssd/issue/2653 + +Signed-off-by: Fabiano Fidêncio +Reviewed-by: Jakub Hrozek +(cherry picked from commit 709c42f0cabc96d0e0edf72753a0967593206ff4) +--- + src/providers/data_provider/dp.h | 2 ++ + src/providers/data_provider/dp_resp_client.c | 45 ++++++++++++++++++++++++++++ + 2 files changed, 47 insertions(+) + +diff --git a/src/providers/data_provider/dp.h b/src/providers/data_provider/dp.h +index ceb49da53..e8b2f9c8f 100644 +--- a/src/providers/data_provider/dp.h ++++ b/src/providers/data_provider/dp.h +@@ -179,6 +179,8 @@ void dp_sbus_reset_groups_ncache(struct data_provider *provider, + void dp_sbus_reset_users_memcache(struct data_provider *provider); + void dp_sbus_reset_groups_memcache(struct data_provider *provider); + void dp_sbus_reset_initgr_memcache(struct data_provider *provider); ++void dp_sbus_invalidate_group_memcache(struct data_provider *provider, ++ gid_t gid); + + /* + * A dummy handler for DPM_ACCT_DOMAIN_HANDLER. +diff --git a/src/providers/data_provider/dp_resp_client.c b/src/providers/data_provider/dp_resp_client.c +index 5735188a6..a61f7c59d 100644 +--- a/src/providers/data_provider/dp_resp_client.c ++++ b/src/providers/data_provider/dp_resp_client.c +@@ -189,3 +189,48 @@ void dp_sbus_reset_initgr_memcache(struct data_provider *provider) + return dp_sbus_reset_memcache(provider, + IFACE_NSS_MEMORYCACHE_INVALIDATEALLINITGROUPS); + } ++ ++void dp_sbus_invalidate_group_memcache(struct data_provider *provider, ++ gid_t gid) ++{ ++ struct dp_client *dp_cli; ++ DBusMessage *msg; ++ dbus_bool_t dbret; ++ ++ if (provider == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "No provider pointer\n"); ++ return; ++ } ++ ++ dp_cli = provider->clients[DPC_NSS]; ++ if (dp_cli == NULL) { ++ return; ++ } ++ ++ msg = dbus_message_new_method_call(NULL, ++ NSS_MEMORYCACHE_PATH, ++ IFACE_NSS_MEMORYCACHE, ++ IFACE_NSS_MEMORYCACHE_INVALIDATEGROUPBYID); ++ if (msg == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n"); ++ return; ++ } ++ ++ dbret = dbus_message_append_args(msg, ++ DBUS_TYPE_UINT32, &gid, ++ DBUS_TYPE_INVALID); ++ if (!dbret) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n"); ++ dbus_message_unref(msg); ++ return; ++ } ++ ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "Ordering NSS responder to invalidate the group %"PRIu32" \n", ++ gid); ++ ++ sbus_conn_send_reply(dp_client_conn(dp_cli), msg); ++ dbus_message_unref(msg); ++ ++ return; ++} +-- +2.14.3 + diff --git a/0039-ERRORS-Add-ERR_GID_DUPLICATED.patch b/0039-ERRORS-Add-ERR_GID_DUPLICATED.patch new file mode 100644 index 0000000..8dbcc78 --- /dev/null +++ b/0039-ERRORS-Add-ERR_GID_DUPLICATED.patch @@ -0,0 +1,49 @@ +From 454f493664bf117c27634e6efe33ebe7d5a85c56 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 19 Feb 2018 08:29:36 +0100 +Subject: [PATCH] ERRORS: Add ERR_GID_DUPLICATED +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This new error will be returned from sysdb_add_incomplete_group() +when renaming a group which will case gid collision. + +Related: +https://pagure.io/SSSD/sssd/issue/2653 + +Signed-off-by: Fabiano Fidêncio +Reviewed-by: Jakub Hrozek +(cherry picked from commit ccd349f0274217e1f0cc118e3a6045e2235ce420) +--- + src/util/util_errors.c | 1 + + src/util/util_errors.h | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/src/util/util_errors.c b/src/util/util_errors.c +index 39ce3d7dc..e2bb2a014 100644 +--- a/src/util/util_errors.c ++++ b/src/util/util_errors.c +@@ -118,6 +118,7 @@ struct err_string error_to_str[] = { + { "GetAccountDomain() not supported" }, /* ERR_GET_ACCT_DOM_NOT_SUPPORTED */ + { "The last GetAccountDomain() result is still valid" }, /* ERR_GET_ACCT_DOM_CACHED */ + { "ID is outside the allowed range" }, /* ERR_ID_OUTSIDE_RANGE */ ++ { "Group ID is duplicated" }, /* ERR_GID_DUPLICATED */ + { "ERR_LAST" } /* ERR_LAST */ + }; + +diff --git a/src/util/util_errors.h b/src/util/util_errors.h +index ad4dad5f8..49501727d 100644 +--- a/src/util/util_errors.h ++++ b/src/util/util_errors.h +@@ -140,6 +140,7 @@ enum sssd_errors { + ERR_GET_ACCT_DOM_NOT_SUPPORTED, + ERR_GET_ACCT_DOM_CACHED, + ERR_ID_OUTSIDE_RANGE, ++ ERR_GID_DUPLICATED, + ERR_LAST /* ALWAYS LAST */ + }; + +-- +2.14.3 + diff --git a/0040-LDAP-Augment-the-sdap_opts-structure-with-a-data-pro.patch b/0040-LDAP-Augment-the-sdap_opts-structure-with-a-data-pro.patch new file mode 100644 index 0000000..d2df4bf --- /dev/null +++ b/0040-LDAP-Augment-the-sdap_opts-structure-with-a-data-pro.patch @@ -0,0 +1,380 @@ +From f60c77df9b7162f46d8639f940d5df31f64f5815 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 9 Apr 2018 12:36:45 +0200 +Subject: [PATCH] LDAP: Augment the sdap_opts structure with a data provider + pointer +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In order to be able to use the Data Provider methods from the SDAP code +to e.g. invalidate memcache when needed, add a new field to the +sdap_options structure with the data_provider structure pointer. + +Fill the pointer value for all LDAP-based providers. + +Related: +https://pagure.io/SSSD/sssd/issue/2653 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit d2633d922eeed68f92be4248b9172b928c189920) +--- + src/providers/ad/ad_common.c | 18 +++++++++++++----- + src/providers/ad/ad_common.h | 4 ++++ + src/providers/ad/ad_init.c | 5 ++++- + src/providers/ad/ad_subdomains.c | 8 ++++++-- + src/providers/ipa/ipa_common.c | 2 ++ + src/providers/ipa/ipa_common.h | 1 + + src/providers/ipa/ipa_init.c | 5 ++++- + src/providers/ipa/ipa_subdomains_server.c | 2 ++ + src/providers/ldap/ldap_common.h | 1 + + src/providers/ldap/ldap_init.c | 3 ++- + src/providers/ldap/ldap_options.c | 2 ++ + src/providers/ldap/sdap.h | 1 + + src/tests/cmocka/common_mock_sdap.c | 2 +- + src/tests/cmocka/test_ad_common.c | 3 +++ + 14 files changed, 46 insertions(+), 11 deletions(-) + +diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c +index 2a1647173..d92c68e6f 100644 +--- a/src/providers/ad/ad_common.c ++++ b/src/providers/ad/ad_common.c +@@ -35,7 +35,8 @@ static errno_t ad_set_sdap_options(struct ad_options *ad_opts, + struct sdap_options *id_opts); + + static struct sdap_options * +-ad_create_default_sdap_options(TALLOC_CTX *mem_ctx) ++ad_create_default_sdap_options(TALLOC_CTX *mem_ctx, ++ struct data_provider *dp) + { + struct sdap_options *id_opts; + errno_t ret; +@@ -44,6 +45,7 @@ ad_create_default_sdap_options(TALLOC_CTX *mem_ctx) + if (!id_opts) { + return NULL; + } ++ id_opts->dp = dp; + + ret = dp_copy_defaults(id_opts, + ad_def_ldap_opts, +@@ -112,6 +114,7 @@ static errno_t + ad_create_sdap_options(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, + const char *conf_path, ++ struct data_provider *dp, + struct sdap_options **_id_opts) + { + struct sdap_options *id_opts; +@@ -119,7 +122,7 @@ ad_create_sdap_options(TALLOC_CTX *mem_ctx, + + if (cdb == NULL || conf_path == NULL) { + /* Fallback to defaults if there is no confdb */ +- id_opts = ad_create_default_sdap_options(mem_ctx); ++ id_opts = ad_create_default_sdap_options(mem_ctx, dp); + if (id_opts == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Failed to initialize default sdap options\n"); +@@ -220,6 +223,7 @@ struct ad_options * + ad_create_options(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, + const char *conf_path, ++ struct data_provider *dp, + struct sss_domain_info *subdom) + { + struct ad_options *ad_options; +@@ -252,6 +256,7 @@ ad_create_options(TALLOC_CTX *mem_ctx, + ret = ad_create_sdap_options(ad_options, + cdb, + conf_path, ++ dp, + &ad_options->id); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD LDAP options\n"); +@@ -304,6 +309,7 @@ struct ad_options * + ad_create_2way_trust_options(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, + const char *conf_path, ++ struct data_provider *dp, + const char *realm, + struct sss_domain_info *subdom, + const char *hostname, +@@ -315,7 +321,7 @@ ad_create_2way_trust_options(TALLOC_CTX *mem_ctx, + DEBUG(SSSDBG_TRACE_FUNC, "2way trust is defined to domain '%s'\n", + subdom->name); + +- ad_options = ad_create_options(mem_ctx, cdb, conf_path, subdom); ++ ad_options = ad_create_options(mem_ctx, cdb, conf_path, dp, subdom); + if (ad_options == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "ad_create_options failed\n"); + return NULL; +@@ -343,6 +349,7 @@ struct ad_options * + ad_create_1way_trust_options(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, + const char *subdom_conf_path, ++ struct data_provider *dp, + struct sss_domain_info *subdom, + const char *hostname, + const char *keytab, +@@ -355,7 +362,7 @@ ad_create_1way_trust_options(TALLOC_CTX *mem_ctx, + DEBUG(SSSDBG_TRACE_FUNC, "1way trust is defined to domain '%s'\n", + subdom->name); + +- ad_options = ad_create_options(mem_ctx, cdb, subdom_conf_path, subdom); ++ ad_options = ad_create_options(mem_ctx, cdb, subdom_conf_path, dp, subdom); + if (ad_options == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "ad_create_options failed\n"); + return NULL; +@@ -1056,12 +1063,13 @@ errno_t + ad_get_id_options(struct ad_options *ad_opts, + struct confdb_ctx *cdb, + const char *conf_path, ++ struct data_provider *dp, + struct sdap_options **_opts) + { + struct sdap_options *id_opts; + errno_t ret; + +- ret = ad_create_sdap_options(ad_opts, cdb, conf_path, &id_opts); ++ ret = ad_create_sdap_options(ad_opts, cdb, conf_path, dp, &id_opts); + if (ret != EOK) { + return ENOMEM; + } +diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h +index 931aafc6c..6eb2ba7e9 100644 +--- a/src/providers/ad/ad_common.h ++++ b/src/providers/ad/ad_common.h +@@ -112,11 +112,13 @@ ad_get_common_options(TALLOC_CTX *mem_ctx, + struct ad_options *ad_create_options(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, + const char *conf_path, ++ struct data_provider *dp, + struct sss_domain_info *subdom); + + struct ad_options *ad_create_2way_trust_options(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, + const char *conf_path, ++ struct data_provider *dp, + const char *realm, + struct sss_domain_info *subdom, + const char *hostname, +@@ -125,6 +127,7 @@ struct ad_options *ad_create_2way_trust_options(TALLOC_CTX *mem_ctx, + struct ad_options *ad_create_1way_trust_options(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, + const char *conf_path, ++ struct data_provider *dp, + struct sss_domain_info *subdom, + const char *hostname, + const char *keytab, +@@ -147,6 +150,7 @@ errno_t + ad_get_id_options(struct ad_options *ad_opts, + struct confdb_ctx *cdb, + const char *conf_path, ++ struct data_provider *dp, + struct sdap_options **_opts); + errno_t + ad_get_autofs_options(struct ad_options *ad_opts, +diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c +index 8c485a7c2..b19624782 100644 +--- a/src/providers/ad/ad_init.c ++++ b/src/providers/ad/ad_init.c +@@ -453,7 +453,10 @@ errno_t sssm_ad_init(TALLOC_CTX *mem_ctx, + + init_ctx->options->id_ctx = init_ctx->id_ctx; + +- ret = ad_get_id_options(init_ctx->options, be_ctx->cdb, be_ctx->conf_path, ++ ret = ad_get_id_options(init_ctx->options, ++ be_ctx->cdb, ++ be_ctx->conf_path, ++ be_ctx->provider, + &init_ctx->id_ctx->sdap_id_ctx->opts); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to init AD id options\n"); +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index bd94ba8ea..74b9f0751 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -265,8 +265,12 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, + return ENOMEM; + } + +- ad_options = ad_create_2way_trust_options(id_ctx, be_ctx->cdb, +- subdom_conf_path, realm, subdom, ++ ad_options = ad_create_2way_trust_options(id_ctx, ++ be_ctx->cdb, ++ subdom_conf_path, ++ be_ctx->provider, ++ realm, ++ subdom, + hostname, keytab); + talloc_free(subdom_conf_path); + if (ad_options == NULL) { +diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c +index 2b81d7f3f..87ed96767 100644 +--- a/src/providers/ipa/ipa_common.c ++++ b/src/providers/ipa/ipa_common.c +@@ -171,6 +171,7 @@ static errno_t ipa_parse_search_base(TALLOC_CTX *mem_ctx, + int ipa_get_id_options(struct ipa_options *ipa_opts, + struct confdb_ctx *cdb, + const char *conf_path, ++ struct data_provider *dp, + struct sdap_options **_opts) + { + TALLOC_CTX *tmpctx; +@@ -190,6 +191,7 @@ int ipa_get_id_options(struct ipa_options *ipa_opts, + ret = ENOMEM; + goto done; + } ++ ipa_opts->id->dp = dp; + + ret = sdap_domain_add(ipa_opts->id, + ipa_opts->id_ctx->sdap_id_ctx->be->domain, +diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h +index 3a1259ccd..725e0e937 100644 +--- a/src/providers/ipa/ipa_common.h ++++ b/src/providers/ipa/ipa_common.h +@@ -235,6 +235,7 @@ int ipa_get_options(TALLOC_CTX *memctx, + int ipa_get_id_options(struct ipa_options *ipa_opts, + struct confdb_ctx *cdb, + const char *conf_path, ++ struct data_provider *dp, + struct sdap_options **_opts); + + int ipa_get_auth_options(struct ipa_options *ipa_opts, +diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c +index cd2227896..931145985 100644 +--- a/src/providers/ipa/ipa_init.c ++++ b/src/providers/ipa/ipa_init.c +@@ -161,7 +161,10 @@ static errno_t ipa_init_id_ctx(TALLOC_CTX *mem_ctx, + ipa_id_ctx->sdap_id_ctx = sdap_id_ctx; + ipa_options->id_ctx = ipa_id_ctx; + +- ret = ipa_get_id_options(ipa_options, be_ctx->cdb, be_ctx->conf_path, ++ ret = ipa_get_id_options(ipa_options, ++ be_ctx->cdb, ++ be_ctx->conf_path, ++ be_ctx->provider, + &sdap_id_ctx->opts); + if (ret != EOK) { + goto done; +diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c +index d670a156b..1e53e7a95 100644 +--- a/src/providers/ipa/ipa_subdomains_server.c ++++ b/src/providers/ipa/ipa_subdomains_server.c +@@ -148,6 +148,7 @@ ipa_create_1way_trust_ctx(struct ipa_id_ctx *id_ctx, + ad_options = ad_create_1way_trust_options(id_ctx, + be_ctx->cdb, + subdom_conf_path, ++ be_ctx->provider, + subdom, + id_ctx->server_mode->hostname, + keytab, +@@ -186,6 +187,7 @@ static struct ad_options *ipa_ad_options_new(struct be_ctx *be_ctx, + ad_options = ad_create_2way_trust_options(id_ctx, + be_ctx->cdb, + subdom_conf_path, ++ be_ctx->provider, + id_ctx->server_mode->realm, + subdom, + id_ctx->server_mode->hostname, +diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h +index 44dbc3fb0..548f0f985 100644 +--- a/src/providers/ldap/ldap_common.h ++++ b/src/providers/ldap/ldap_common.h +@@ -193,6 +193,7 @@ int ldap_get_options(TALLOC_CTX *memctx, + struct sss_domain_info *dom, + struct confdb_ctx *cdb, + const char *conf_path, ++ struct data_provider *dp, + struct sdap_options **_opts); + + int ldap_get_sudo_options(struct confdb_ctx *cdb, +diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c +index 83075b5d3..44b3e9ab3 100644 +--- a/src/providers/ldap/ldap_init.c ++++ b/src/providers/ldap/ldap_init.c +@@ -458,7 +458,8 @@ errno_t sssm_ldap_init(TALLOC_CTX *mem_ctx, + + /* Always initialize options since it is needed everywhere. */ + ret = ldap_get_options(init_ctx, be_ctx->domain, be_ctx->cdb, +- be_ctx->conf_path, &init_ctx->options); ++ be_ctx->conf_path, be_ctx->provider, ++ &init_ctx->options); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize LDAP options " + "[%d]: %s\n", ret, sss_strerror(ret)); +diff --git a/src/providers/ldap/ldap_options.c b/src/providers/ldap/ldap_options.c +index ccc1a2c5b..0b79715d2 100644 +--- a/src/providers/ldap/ldap_options.c ++++ b/src/providers/ldap/ldap_options.c +@@ -27,6 +27,7 @@ int ldap_get_options(TALLOC_CTX *memctx, + struct sss_domain_info *dom, + struct confdb_ctx *cdb, + const char *conf_path, ++ struct data_provider *dp, + struct sdap_options **_opts) + { + struct sdap_attr_map *default_attr_map; +@@ -57,6 +58,7 @@ int ldap_get_options(TALLOC_CTX *memctx, + + opts = talloc_zero(memctx, struct sdap_options); + if (!opts) return ENOMEM; ++ opts->dp = dp; + + ret = sdap_domain_add(opts, dom, NULL); + if (ret != EOK) { +diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h +index ecf9c4d2e..e892c4071 100644 +--- a/src/providers/ldap/sdap.h ++++ b/src/providers/ldap/sdap.h +@@ -465,6 +465,7 @@ struct sdap_certmap_ctx; + + struct sdap_options { + struct dp_option *basic; ++ struct data_provider *dp; + struct sdap_attr_map *gen_map; + struct sdap_attr_map *user_map; + size_t user_map_cnt; +diff --git a/src/tests/cmocka/common_mock_sdap.c b/src/tests/cmocka/common_mock_sdap.c +index cef321613..fa4787c4b 100644 +--- a/src/tests/cmocka/common_mock_sdap.c ++++ b/src/tests/cmocka/common_mock_sdap.c +@@ -48,7 +48,7 @@ struct sdap_options *mock_sdap_options_ldap(TALLOC_CTX *mem_ctx, + struct sdap_options *opts = NULL; + errno_t ret; + +- ret = ldap_get_options(mem_ctx, domain, confdb_ctx, conf_path, &opts); ++ ret = ldap_get_options(mem_ctx, domain, confdb_ctx, conf_path, NULL, &opts); + if (ret != EOK) { + return NULL; + } +diff --git a/src/tests/cmocka/test_ad_common.c b/src/tests/cmocka/test_ad_common.c +index 94f351e19..39ebbc633 100644 +--- a/src/tests/cmocka/test_ad_common.c ++++ b/src/tests/cmocka/test_ad_common.c +@@ -449,6 +449,7 @@ static void test_ad_create_1way_trust_options(void **state) + test_ctx->ad_ctx, + NULL, + NULL, ++ NULL, + test_ctx->subdom, + ONEWAY_HOST_NAME, + ONEWAY_KEYTAB_PATH, +@@ -515,6 +516,7 @@ static void test_ad_create_2way_trust_options(void **state) + test_ctx->ad_ctx, + NULL, + NULL, ++ NULL, + REALMNAME, + test_ctx->subdom, + HOST_NAME, +@@ -585,6 +587,7 @@ test_ldap_conn_setup(void **state) + ad_ctx, + NULL, + NULL, ++ NULL, + REALMNAME, + test_ctx->subdom, + HOST_NAME, +-- +2.14.3 + diff --git a/0041-SDAP-Add-sdap_handle_id_collision_for_incomplete_gro.patch b/0041-SDAP-Add-sdap_handle_id_collision_for_incomplete_gro.patch new file mode 100644 index 0000000..bcba007 --- /dev/null +++ b/0041-SDAP-Add-sdap_handle_id_collision_for_incomplete_gro.patch @@ -0,0 +1,95 @@ +From 87a0027c7dbc54422ac519ef8eef0323baff4b60 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 19 Feb 2018 12:43:06 +0100 +Subject: [PATCH] SDAP: Add sdap_handle_id_collision_for_incomplete_groups() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This newly added function is a helper to properly hadle group +id-collisions when renaming incomplete groups and it does: +- Deletes the group from sysdb +- Adds the new incomplete group +- Notifies the NSS responder that the entry also has to be deleted from + the memory cache + +This function will be called from +sdap_ad_save_group_membership_with_idmapping() and from +sdap_add_incomplete_groups(). + +Related: +https://pagure.io/SSSD/sssd/issue/2653 + +Signed-off-by: Fabiano Fidêncio +Reviewed-by: Jakub Hrozek +(cherry picked from commit a537df2ea99acb0181dc360ddf9a60b69c16faf0) +--- + src/providers/ldap/sdap_async.h | 11 ++++++++++ + src/providers/ldap/sdap_async_initgroups.c | 34 ++++++++++++++++++++++++++++++ + 2 files changed, 45 insertions(+) + +diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h +index 40da81fb9..6ca3ed8d8 100644 +--- a/src/providers/ldap/sdap_async.h ++++ b/src/providers/ldap/sdap_async.h +@@ -412,4 +412,15 @@ sdap_ad_tokengroups_initgroups_send(TALLOC_CTX *mem_ctx, + errno_t + sdap_ad_tokengroups_initgroups_recv(struct tevent_req *req); + ++errno_t ++sdap_handle_id_collision_for_incomplete_groups(struct data_provider *dp, ++ struct sss_domain_info *domain, ++ const char *name, ++ gid_t gid, ++ const char *original_dn, ++ const char *sid_str, ++ const char *uuid, ++ bool posix, ++ time_t now); ++ + #endif /* _SDAP_ASYNC_H_ */ +diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c +index 326294a1c..34747be59 100644 +--- a/src/providers/ldap/sdap_async_initgroups.c ++++ b/src/providers/ldap/sdap_async_initgroups.c +@@ -3543,3 +3543,37 @@ errno_t get_sysdb_grouplist_dn(TALLOC_CTX *mem_ctx, + return get_sysdb_grouplist_ex(mem_ctx, sysdb, domain, + name, grouplist, true); + } ++ ++errno_t ++sdap_handle_id_collision_for_incomplete_groups(struct data_provider *dp, ++ struct sss_domain_info *domain, ++ const char *name, ++ gid_t gid, ++ const char *original_dn, ++ const char *sid_str, ++ const char *uuid, ++ bool posix, ++ time_t now) ++{ ++ errno_t ret; ++ ++ ret = sysdb_delete_group(domain, NULL, gid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Due to an id collision, the new group with gid [\"%"PRIu32"\"] " ++ "will not be added as the old group (with the same gid) could " ++ "not be removed from the sysdb!", ++ gid); ++ return ret; ++ } ++ ++ ret = sysdb_add_incomplete_group(domain, name, gid, original_dn, sid_str, ++ uuid, posix, now); ++ if (ret != EOK) { ++ return ret; ++ } ++ ++ dp_sbus_invalidate_group_memcache(dp, gid); ++ ++ return EOK; ++} +-- +2.14.3 + diff --git a/0042-SDAP-Properly-handle-group-id-collision-when-renamin.patch b/0042-SDAP-Properly-handle-group-id-collision-when-renamin.patch new file mode 100644 index 0000000..71cdc20 --- /dev/null +++ b/0042-SDAP-Properly-handle-group-id-collision-when-renamin.patch @@ -0,0 +1,129 @@ +From de891b231464f10ce029593d7ee2ebb401e8a0b3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 19 Feb 2018 12:51:57 +0100 +Subject: [PATCH] SDAP: Properly handle group id-collision when renaming + incomplete groups +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Resolves: +https://pagure.io/SSSD/sssd/issue/2653 + +Signed-off-by: Fabiano Fidêncio +Reviewed-by: Jakub Hrozek +(cherry picked from commit a2e743cd23e8e2033340612c77a8dbb8ef48c1e1) +--- + src/providers/ad/ad_pac.c | 3 +++ + src/providers/ldap/sdap_async_ad.h | 1 + + src/providers/ldap/sdap_async_initgroups.c | 13 +++++++++++++ + src/providers/ldap/sdap_async_initgroups_ad.c | 15 +++++++++++++++ + 4 files changed, 32 insertions(+) + +diff --git a/src/providers/ad/ad_pac.c b/src/providers/ad/ad_pac.c +index 6b47462cf..1a344725f 100644 +--- a/src/providers/ad/ad_pac.c ++++ b/src/providers/ad/ad_pac.c +@@ -434,6 +434,7 @@ struct ad_handle_pac_initgr_state { + const char *err; + int dp_error; + int sdap_ret; ++ struct sdap_options *opts; + + size_t num_missing_sids; + char **missing_sids; +@@ -471,6 +472,7 @@ struct tevent_req *ad_handle_pac_initgr_send(TALLOC_CTX *mem_ctx, + return NULL; + } + state->user_dom = sdom->dom; ++ state->opts = id_ctx->opts; + + /* The following variables are currently unused because no sub-request + * returns any of them. But they are needed to allow the same signature as +@@ -514,6 +516,7 @@ struct tevent_req *ad_handle_pac_initgr_send(TALLOC_CTX *mem_ctx, + DEBUG(SSSDBG_TRACE_ALL, "Running PAC processing with id-mapping.\n"); + + ret = sdap_ad_save_group_membership_with_idmapping(state->username, ++ state->opts, + sdom->dom, + id_ctx->opts->idmap_ctx, + num_sids, group_sids); +diff --git a/src/providers/ldap/sdap_async_ad.h b/src/providers/ldap/sdap_async_ad.h +index 950f5a030..a5f47a1a9 100644 +--- a/src/providers/ldap/sdap_async_ad.h ++++ b/src/providers/ldap/sdap_async_ad.h +@@ -25,6 +25,7 @@ + #define SDAP_ASYNC_AD_H_ + + errno_t sdap_ad_save_group_membership_with_idmapping(const char *username, ++ struct sdap_options *opts, + struct sss_domain_info *user_dom, + struct sdap_idmap_ctx *idmap_ctx, + size_t num_sids, +diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c +index 34747be59..03f6de01a 100644 +--- a/src/providers/ldap/sdap_async_initgroups.c ++++ b/src/providers/ldap/sdap_async_initgroups.c +@@ -225,6 +225,19 @@ errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb, + ret = sysdb_add_incomplete_group(domain, groupname, gid, + original_dn, sid_str, + uuid, posix, now); ++ if (ret == ERR_GID_DUPLICATED) { ++ /* In case o group id-collision, do: ++ * - Delete the group from sysdb ++ * - Add the new incomplete group ++ * - Notify the NSS responder that the entry has also to be ++ * removed from the memory cache ++ */ ++ ret = sdap_handle_id_collision_for_incomplete_groups( ++ opts->dp, domain, groupname, gid, ++ original_dn, sid_str, uuid, posix, ++ now); ++ } ++ + if (ret != EOK) { + goto done; + } +diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c +index 30f1d3db2..eab103652 100644 +--- a/src/providers/ldap/sdap_async_initgroups_ad.c ++++ b/src/providers/ldap/sdap_async_initgroups_ad.c +@@ -836,6 +836,7 @@ sdap_ad_tokengroups_initgr_mapping_connect_done(struct tevent_req *subreq) + } + + errno_t sdap_ad_save_group_membership_with_idmapping(const char *username, ++ struct sdap_options *opts, + struct sss_domain_info *user_dom, + struct sdap_idmap_ctx *idmap_ctx, + size_t num_sids, +@@ -921,6 +922,19 @@ errno_t sdap_ad_save_group_membership_with_idmapping(const char *username, + + ret = sysdb_add_incomplete_group(domain, name, gid, + NULL, sid, NULL, false, now); ++ if (ret == ERR_GID_DUPLICATED) { ++ /* In case o group id-collision, do: ++ * - Delete the group from sysdb ++ * - Add the new incomplete group ++ * - Notify the NSS responder that the entry has also to be ++ * removed from the memory cache ++ */ ++ ret = sdap_handle_id_collision_for_incomplete_groups( ++ idmap_ctx->id_ctx->be->provider, ++ domain, name, gid, NULL, sid, NULL, ++ false, now); ++ } ++ + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, "Could not create incomplete " + "group: [%s]\n", strerror(ret)); +@@ -992,6 +1006,7 @@ static void sdap_ad_tokengroups_initgr_mapping_done(struct tevent_req *subreq) + } + + ret = sdap_ad_save_group_membership_with_idmapping(state->username, ++ state->opts, + state->domain, + state->idmap_ctx, + num_sids, +-- +2.14.3 + diff --git a/0043-SYSDB_OPS-Error-out-on-id-collision-when-adding-an-i.patch b/0043-SYSDB_OPS-Error-out-on-id-collision-when-adding-an-i.patch new file mode 100644 index 0000000..04c20b7 --- /dev/null +++ b/0043-SYSDB_OPS-Error-out-on-id-collision-when-adding-an-i.patch @@ -0,0 +1,64 @@ +From 5da97dcfb8499348080b5c7a3980c704294f22fa Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 19 Feb 2018 08:53:56 +0100 +Subject: [PATCH] SYSDB_OPS: Error out on id-collision when adding an + incomplete group +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This situation can be hit when renaming a group. For now, let's just +error this out so the caller can handle it properly on its own layer. + +Related: +https://pagure.io/SSSD/sssd/issue/2653 + +Signed-off-by: Fabiano Fidêncio +Reviewed-by: Jakub Hrozek +(cherry picked from commit 514b2be089bfd0e2702d7e9ab883ab071a61b719) +--- + src/db/sysdb_ops.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index 5d3cf643d..de4fdb592 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -2377,12 +2377,34 @@ int sysdb_add_incomplete_group(struct sss_domain_info *domain, + TALLOC_CTX *tmp_ctx; + int ret; + struct sysdb_attrs *attrs; ++ struct ldb_message *msg; ++ const char *previous = NULL; ++ const char *group_attrs[] = { SYSDB_SID_STR, SYSDB_UUID, SYSDB_ORIG_DN, NULL }; ++ const char *values[] = { sid_str, uuid, original_dn, NULL }; ++ bool same = false; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) { + return ENOMEM; + } + ++ ret = sysdb_search_group_by_gid(tmp_ctx, domain, gid, group_attrs, &msg); ++ if (ret == EOK) { ++ for (int i = 0; !same && group_attrs[i] != NULL; i++) { ++ previous = ldb_msg_find_attr_as_string(msg, ++ group_attrs[i], ++ NULL); ++ if (previous != NULL && values[i] != NULL) { ++ same = strcmp(previous, values[i]) == 0; ++ } ++ } ++ } ++ ++ if (same) { ++ ret = ERR_GID_DUPLICATED; ++ goto done; ++ } ++ + /* try to add the group */ + ret = sysdb_add_basic_group(domain, name, gid); + if (ret) goto done; +-- +2.14.3 + diff --git a/0044-TESTS-Add-an-integration-test-for-renaming-incomplet.patch b/0044-TESTS-Add-an-integration-test-for-renaming-incomplet.patch new file mode 100644 index 0000000..ef547d4 --- /dev/null +++ b/0044-TESTS-Add-an-integration-test-for-renaming-incomplet.patch @@ -0,0 +1,194 @@ +From ead866b198034c0b3101732e09a5524d0182d1cb Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 19 Feb 2018 18:26:05 +0100 +Subject: [PATCH] TESTS: Add an integration test for renaming incomplete groups + during initgroups +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +As we implemented the group renaming heuristics to rename only if we can +use another "hint" like the original DN or the SID to know the group is +the same, this patch adds two tests (positive and negative) to make sure +a group with a totally different RDN and hence different originalDN +cannot be renamed but a group whose name changed but the RDN stays the +same can be renamed. + +Related: +https://pagure.io/SSSD/sssd/issue/3282 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit 35d6fb7cabd6183252fd29b29aaf66264dca9135) +--- + src/tests/intg/test_ldap.py | 149 +++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 147 insertions(+), 2 deletions(-) + +diff --git a/src/tests/intg/test_ldap.py b/src/tests/intg/test_ldap.py +index db3253858..98b6349a8 100644 +--- a/src/tests/intg/test_ldap.py ++++ b/src/tests/intg/test_ldap.py +@@ -94,10 +94,11 @@ def create_ldap_cleanup(request, ldap_conn, ent_list=None): + request.addfinalizer(lambda: cleanup_ldap_entries(ldap_conn, ent_list)) + + +-def create_ldap_fixture(request, ldap_conn, ent_list=None): ++def create_ldap_fixture(request, ldap_conn, ent_list=None, cleanup=True): + """Add LDAP entries and add teardown for removing them""" + create_ldap_entries(ldap_conn, ent_list) +- create_ldap_cleanup(request, ldap_conn, ent_list) ++ if cleanup: ++ create_ldap_cleanup(request, ldap_conn, ent_list) + + + SCHEMA_RFC2307 = "rfc2307" +@@ -1437,3 +1438,147 @@ def test_ldap_auto_private_groups_direct_no_gid(ldap_conn, mpg_setup_no_gid): + ", ".join(["%s" % s for s in sorted(gids)]), + ", ".join(["%s" % s for s in sorted(user1_expected_gids)]) + ) ++ ++ ++def rename_setup_no_cleanup(request, ldap_conn, cleanup_ent=None): ++ ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn) ++ ent_list.add_user("user1", 1001, 2001) ++ ent_list.add_group_bis("user1_private", 2001) ++ ++ ent_list.add_user("user2", 1002, 2002) ++ ent_list.add_group_bis("user2_private", 2002) ++ ++ ent_list.add_group_bis("group1", 2015, ["user1", "user2"]) ++ ++ if cleanup_ent is None: ++ create_ldap_fixture(request, ldap_conn, ent_list) ++ else: ++ # Since the entries were renamed, we need to clean up ++ # the renamed entries.. ++ create_ldap_fixture(request, ldap_conn, ent_list, cleanup=False) ++ create_ldap_cleanup(request, ldap_conn, None) ++ ++ ++@pytest.fixture ++def rename_setup_cleanup(request, ldap_conn): ++ cleanup_ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn) ++ cleanup_ent_list.add_user("user1", 1001, 2001) ++ cleanup_ent_list.add_group_bis("new_user1_private", 2001) ++ ++ cleanup_ent_list.add_user("user2", 1002, 2002) ++ cleanup_ent_list.add_group_bis("new_user2_private", 2002) ++ ++ cleanup_ent_list.add_group_bis("new_group1", 2015, ["user1", "user2"]) ++ ++ rename_setup_no_cleanup(request, ldap_conn, cleanup_ent_list) ++ ++ conf = format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ return None ++ ++ ++@pytest.fixture ++def rename_setup_with_name(request, ldap_conn): ++ rename_setup_no_cleanup(request, ldap_conn) ++ ++ conf = format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS) + \ ++ unindent(""" ++ [nss] ++ [domain/LDAP] ++ ldap_group_name = name ++ timeout = 3000 ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ return None ++ ++ ++def test_rename_incomplete_group_same_dn(ldap_conn, rename_setup_with_name): ++ """ ++ Test that if a group's name attribute changes, but the DN stays the same, ++ the incomplete group object will be renamed. ++ ++ Because the RDN attribute must be present in the entry, we add another ++ attribute "name" that is purposefully different from the CN and make ++ sure the group names are reflected in name ++ ++ Regression test for https://pagure.io/SSSD/sssd/issue/3282 ++ """ ++ pvt_dn1 = 'cn=user1_private,ou=Groups,' + ldap_conn.ds_inst.base_dn ++ pvt_dn2 = 'cn=user2_private,ou=Groups,' + ldap_conn.ds_inst.base_dn ++ group1_dn = 'cn=group1,ou=Groups,' + ldap_conn.ds_inst.base_dn ++ ++ # Add the name we want for both private and secondary group ++ old = {'name': []} ++ new = {'name': [b"user1_group1"]} ++ ldif = ldap.modlist.modifyModlist(old, new) ++ ldap_conn.modify_s(group1_dn, ldif) ++ ++ new = {'name': [b"pvt_user1"]} ++ ldif = ldap.modlist.modifyModlist(old, new) ++ ldap_conn.modify_s(pvt_dn1, ldif) ++ ++ new = {'name': [b"pvt_user2"]} ++ ldif = ldap.modlist.modifyModlist(old, new) ++ ldap_conn.modify_s(pvt_dn2, ldif) ++ ++ # Make sure the old name shows up in the id output ++ (res, errno, grp_list) = sssd_id.get_user_groups("user1") ++ assert res == sssd_id.NssReturnCode.SUCCESS, \ ++ "Could not find groups for user1, %d" % errno ++ ++ assert sorted(grp_list) == sorted(["pvt_user1", "user1_group1"]) ++ ++ # Rename the group by changing the cn attribute, but keep the DN the same ++ old = {'name': [b"user1_group1"]} ++ new = {'name': [b"new_user1_group1"]} ++ ldif = ldap.modlist.modifyModlist(old, new) ++ ldap_conn.modify_s(group1_dn, ldif) ++ ++ (res, errno, grp_list) = sssd_id.get_user_groups("user2") ++ assert res == sssd_id.NssReturnCode.SUCCESS, \ ++ "Could not find groups for user2, %d" % errno ++ ++ assert sorted(grp_list) == sorted(["pvt_user2", "new_user1_group1"]) ++ ++ (res, errno, grp_list) = sssd_id.get_user_groups("user1") ++ assert res == sssd_id.NssReturnCode.SUCCESS, \ ++ "Could not find groups for user1, %d" % errno ++ ++ assert sorted(grp_list) == sorted(["pvt_user1", "new_user1_group1"]) ++ ++ ++def test_rename_incomplete_group_rdn_changed(ldap_conn, rename_setup_cleanup): ++ """ ++ Test that if a group's name attribute changes, and the DN changes with ++ the RDN. Then adding the second group will fail because we can't tell if ++ there are two duplicate groups in LDAP when saving the group or if the ++ group was renamed. ++ ++ Please note that with many directories (AD, IPA), the code can rely on ++ other heuristics (SID, UUID) to find out the group is in fact the same. ++ ++ Regression test for https://pagure.io/SSSD/sssd/issue/3282 ++ """ ++ pvt_dn = 'cn=user1_private,ou=Groups,' + ldap_conn.ds_inst.base_dn ++ group1_dn = 'cn=group1,ou=Groups,' + ldap_conn.ds_inst.base_dn ++ ++ # Make sure the old name shows up in the id output ++ (res, errno, grp_list) = sssd_id.get_user_groups("user1") ++ assert res == sssd_id.NssReturnCode.SUCCESS, \ ++ "Could not find groups for user1, %d" % errno ++ ++ assert sorted(grp_list) == sorted(["user1_private", "group1"]) ++ ++ # Rename the groups, changing the RDN ++ ldap_conn.rename_s(group1_dn, "cn=new_group1") ++ ldap_conn.rename_s(pvt_dn, "cn=new_user1_private") ++ ++ (res, errno, grp_list) = sssd_id.get_user_groups("user2") ++ assert res == sssd_id.NssReturnCode.SUCCESS, \ ++ "Could not find groups for user2, %d" % errno ++ ++ # The initgroups succeeds, but because saving the new group fails, ++ # SSSD will revert to the cache contents and return what's in the cache ++ assert sorted(grp_list) == sorted(["user2_private", "group1"]) +-- +2.14.3 + diff --git a/0045-SYSDB-sysdb_add_incomplete_group-now-returns-EEXIST-.patch b/0045-SYSDB-sysdb_add_incomplete_group-now-returns-EEXIST-.patch new file mode 100644 index 0000000..b314815 --- /dev/null +++ b/0045-SYSDB-sysdb_add_incomplete_group-now-returns-EEXIST-.patch @@ -0,0 +1,119 @@ +From 0a367914b87ef56dd4d5d56778e5770d1201f255 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 16 Apr 2018 20:29:28 +0200 +Subject: [PATCH] SYSDB: sysdb_add_incomplete_group now returns EEXIST with a + duplicate GID +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related: +https://pagure.io/SSSD/sssd/issue/2653 + +Reviewed-by: Fabiano Fidêncio +(cherry picked from commit ba2d5f7a0adefb017d3f85203d715b725ca8810f) +--- + src/db/sysdb_ops.c | 13 ++++++++++--- + src/tests/sysdb-tests.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 56 insertions(+), 4 deletions(-) + +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index de4fdb592..93b967e75 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -2398,10 +2398,17 @@ int sysdb_add_incomplete_group(struct sss_domain_info *domain, + same = strcmp(previous, values[i]) == 0; + } + } +- } + +- if (same) { +- ret = ERR_GID_DUPLICATED; ++ if (same == true) { ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "The group with GID [%"SPRIgid"] was renamed\n", gid); ++ ret = ERR_GID_DUPLICATED; ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Another group with GID [%"SPRIgid"] already exists\n", gid); ++ ret = EEXIST; + goto done; + } + +diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c +index 32b8ca856..416dedb5e 100644 +--- a/src/tests/sysdb-tests.c ++++ b/src/tests/sysdb-tests.c +@@ -989,6 +989,50 @@ START_TEST (test_sysdb_add_incomplete_group) + } + END_TEST + ++START_TEST (test_sysdb_incomplete_group_rename) ++{ ++ struct sysdb_test_ctx *test_ctx; ++ int ret; ++ ++ ret = setup_sysdb_tests(&test_ctx); ++ if (ret != EOK) { ++ fail("Could not set up the test"); ++ return; ++ } ++ ++ ret = sysdb_add_incomplete_group(test_ctx->domain, "incomplete_group", ++ 20000, NULL, ++ "S-1-5-21-123-456-789-111", ++ NULL, true, 0); ++ fail_unless(ret == EOK, ++ "sysdb_add_incomplete_group error [%d][%s]", ++ ret, strerror(ret)); ++ ++ /* Adding a group with the same GID and all the other characteristics uknown should fail */ ++ ret = sysdb_add_incomplete_group(test_ctx->domain, "incomplete_group_new", ++ 20000, NULL, NULL, NULL, true, 0); ++ fail_unless(ret == EEXIST, "Did not caught a duplicate\n"); ++ ++ /* A different SID should also trigger a failure */ ++ ret = sysdb_add_incomplete_group(test_ctx->domain, "incomplete_group_new", ++ 20000, NULL, ++ "S-1-5-21-123-456-789-222", ++ NULL, true, 0); ++ fail_unless(ret == EEXIST, "Did not caught a duplicate\n"); ++ ++ /* But if we know based on a SID that the group is in fact the same, ++ * let's just change its name ++ */ ++ ret = sysdb_add_incomplete_group(test_ctx->domain, "incomplete_group_new", ++ 20000, NULL, ++ "S-1-5-21-123-456-789-111", ++ NULL, true, 0); ++ fail_unless(ret == ERR_GID_DUPLICATED, ++ "Did not catch a legitimate rename", ++ ret, strerror(ret)); ++} ++END_TEST ++ + START_TEST (test_sysdb_getpwnam) + { + struct sysdb_test_ctx *test_ctx; +@@ -5526,7 +5570,7 @@ START_TEST(test_sysdb_search_sid_str) + ret = setup_sysdb_tests(&test_ctx); + fail_if(ret != EOK, "Could not set up the test"); + +- data = test_data_new_group(test_ctx, 2900); ++ data = test_data_new_group(test_ctx, 2902); + fail_if(data == NULL); + data->sid_str = "S-1-2-3-4"; + +@@ -7166,6 +7210,7 @@ Suite *create_sysdb_suite(void) + tcase_add_loop_test(tc_sysdb, + test_sysdb_remove_local_group_by_gid, + 28000, 28010); ++ tcase_add_test(tc_sysdb, test_sysdb_incomplete_group_rename); + + /* test custom operations */ + tcase_add_loop_test(tc_sysdb, test_sysdb_store_custom, 29010, 29020); +-- +2.14.3 + diff --git a/sssd.spec b/sssd.spec index 03845c2..13d273f 100644 --- a/sssd.spec +++ b/sssd.spec @@ -78,6 +78,15 @@ Patch0033: 0033-SDAP-Improve-a-DEBUG-message-about-GC-detection.patch Patch0034: 0034-MAN-Improve-docs-about-GC-detection.patch Patch0035: 0035-nss-idmap-do-not-set-a-limit.patch Patch0036: 0036-nss-idmap-use-right-group-list-pointer-after-sss_get.patch +Patch0037: 0037-NSS-Add-InvalidateGroupById-handler.patch +Patch0038: 0038-DP-Add-dp_sbus_invalidate_group_memcache.patch +Patch0039: 0039-ERRORS-Add-ERR_GID_DUPLICATED.patch +Patch0040: 0040-LDAP-Augment-the-sdap_opts-structure-with-a-data-pro.patch +Patch0041: 0041-SDAP-Add-sdap_handle_id_collision_for_incomplete_gro.patch +Patch0042: 0042-SDAP-Properly-handle-group-id-collision-when-renamin.patch +Patch0043: 0043-SYSDB_OPS-Error-out-on-id-collision-when-adding-an-i.patch +Patch0044: 0044-TESTS-Add-an-integration-test-for-renaming-incomplet.patch +Patch0045: 0045-SYSDB-sysdb_add_incomplete_group-now-returns-EEXIST-.patch Patch0502: 0502-SYSTEMD-Use-capabilities.patch Patch0503: 0503-Disable-stopping-idle-socket-activated-responders.patch @@ -1297,6 +1306,8 @@ fi - Improve docs/debug message about GC detection - Resolves: upstream#3715 - ipa 389-ds-base crash in krb5-libs - k5_copy_etypes list out of bound? +- Resolves: upstream#2653 - Group renaming issue when "id_provider = ldap" is + set. * Fri Mar 30 2018 Fabiano Fidêncio - 1.16.1-2 - Resolves: upstream#3573 - sssd won't show netgroups with blank domain