diff --git a/SOURCES/slapi-0003-slapi-nis-resolve-IPA-groups-with-fully-qualified-su.patch b/SOURCES/slapi-0003-slapi-nis-resolve-IPA-groups-with-fully-qualified-su.patch index 4b0375b..dfa973f 100644 --- a/SOURCES/slapi-0003-slapi-nis-resolve-IPA-groups-with-fully-qualified-su.patch +++ b/SOURCES/slapi-0003-slapi-nis-resolve-IPA-groups-with-fully-qualified-su.patch @@ -1,7 +1,8 @@ -From d263ce2f95fcf6ec8afa5c9528182cce00f57da6 Mon Sep 17 00:00:00 2001 +From 0a5e61c042679679646f6f8f673028f8fbcf3ea7 Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Wed, 15 Jun 2016 12:15:46 +0300 -Subject: [PATCH 3/4] slapi-nis: resolve IPA groups with fully qualified suffix +Subject: [PATCH 03/17] slapi-nis: resolve IPA groups with fully qualified + suffix With SSSD 1.14+ there is a logic change to handling of a default domain suffix. @@ -90,7 +91,7 @@ index bb2aa74..cdd2b3c 100644 + if (ret.associated_domain != NULL) + break; + } -+ slapi_ch_free((void**)&entries); ++ slapi_ch_free((void**)entries); + } + } + slapi_pblock_destroy(pb); @@ -136,5 +137,5 @@ index 72ba641..c15d1ed 100644 struct backend_entry_data { -- -2.7.4 +2.13.6 diff --git a/SOURCES/slapi-0005-Double-free-on-ldap-entry-during-priming.patch b/SOURCES/slapi-0005-Double-free-on-ldap-entry-during-priming.patch new file mode 100644 index 0000000..375cfe3 --- /dev/null +++ b/SOURCES/slapi-0005-Double-free-on-ldap-entry-during-priming.patch @@ -0,0 +1,39 @@ +From 66177cbab545374ccc0bcacdd7a8ffea1ca7be6d Mon Sep 17 00:00:00 2001 +From: Thierry Bordaz +Date: Tue, 12 Jul 2016 11:43:28 +0200 +Subject: [PATCH 05/17] Double free on ldap entry during priming + +During Schema-compat cache priming, If it exists an associated domain +the entry returned by the internal search is freed twice. + +This was introduced in order for slapi-nis to resolve IPA groups with +fully qualified suffix. To support SSSD 1.14+ change of logic to handle +a default domain suffix. +--- + src/back-sch.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/src/back-sch.c b/src/back-sch.c +index cdd2b3c..0745329 100644 +--- a/src/back-sch.c ++++ b/src/back-sch.c +@@ -284,15 +284,13 @@ backend_set_config_read_config(struct plugin_state *state, Slapi_Entry *e, + slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &result); + if (result == 0) { + slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries); +- slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, NULL); + for (j=0; entries[j] != NULL; j++) { + ret.associated_domain = slapi_entry_attr_get_charptr(entries[j], "associatedDomain"); +- slapi_entry_free(entries[i]); + if (ret.associated_domain != NULL) + break; + } +- slapi_ch_free((void**)entries); + } ++ slapi_free_search_results_internal(pb); + } + slapi_pblock_destroy(pb); + pb = NULL; +-- +2.13.6 + diff --git a/SOURCES/slapi-0011-Move-a-helper-to-build-DN-to-a-format.c.patch b/SOURCES/slapi-0011-Move-a-helper-to-build-DN-to-a-format.c.patch new file mode 100644 index 0000000..73c9504 --- /dev/null +++ b/SOURCES/slapi-0011-Move-a-helper-to-build-DN-to-a-format.c.patch @@ -0,0 +1,144 @@ +From 96ff6873b024718fcbb7b011eee58aab84c3086f Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Mon, 11 Sep 2017 15:32:38 +0300 +Subject: [PATCH 11/17] Move a helper to build DN to a format.c + +--- + src/back-sch-nss.c | 45 ++------------------------------------------- + src/format.c | 41 +++++++++++++++++++++++++++++++++++++++++ + src/format.h | 2 ++ + 3 files changed, 45 insertions(+), 43 deletions(-) + +diff --git a/src/back-sch-nss.c b/src/back-sch-nss.c +index db63e59..e4d027e 100644 +--- a/src/back-sch-nss.c ++++ b/src/back-sch-nss.c +@@ -186,47 +186,6 @@ backend_search_filter_has_cn_uid(Slapi_Filter *filter, void *arg) + return SLAPI_FILTER_SCAN_CONTINUE; + } + +-static char * +-backend_build_dn(const char *attribute, const char *value, +- const char *container_sdn) +-{ +- Slapi_RDN *rdn; +- Slapi_DN *sdn; +- char *val, *dn = NULL; +- const char *ndn, *hexchars = "0123456789ABCDEF"; +- int i; +- +- val = malloc(strlen(value) * 3 + 1); +- if (val == NULL) { +- return NULL; +- } +- rdn = slapi_rdn_new(); +- if (rdn == NULL) { +- free(val); +- return NULL; +- } +- for (i = 0; value[i] != '\0'; i++) { +- val[i * 3] = '\\'; +- val[i * 3 + 1] = hexchars[(value[i] & 0xf0) >> 4]; +- val[i * 3 + 2] = hexchars[value[i] & 0xf]; +- } +- val[i * 3] = '\0'; +- if (slapi_rdn_add(rdn, attribute, val) == 1) { +- sdn = slapi_sdn_new_dn_byval(container_sdn); +- if (sdn != NULL) { +- sdn = slapi_sdn_add_rdn(sdn, rdn); +- ndn = slapi_sdn_get_ndn(sdn); +- if (ndn != NULL) { +- dn = slapi_ch_strdup(ndn); +- } +- slapi_sdn_free(&sdn); +- } +- } +- free(val); +- slapi_rdn_free(&rdn); +- return dn; +-} +- + static Slapi_Entry * + backend_make_user_entry_from_nsswitch_passwd(struct passwd *pwd, + char *container_sdn, +@@ -257,7 +216,7 @@ backend_make_user_entry_from_nsswitch_passwd(struct passwd *pwd, + return NULL; + } + +- dn = backend_build_dn("uid", name, container_sdn); ++ dn = format_build_dn("uid", name, container_sdn); + if (dn == NULL) { + slapi_log_error(SLAPI_LOG_FATAL, + cbdata->state->plugin_desc->spd_id, +@@ -556,7 +515,7 @@ backend_make_group_entry_from_nsswitch_group(struct group *grp, + return NULL; + } + +- dn = backend_build_dn("cn", grp->gr_name, container_sdn); ++ dn = format_build_dn("cn", grp->gr_name, container_sdn); + if (dn == NULL) { + slapi_log_error(SLAPI_LOG_FATAL, + cbdata->state->plugin_desc->spd_id, +diff --git a/src/format.c b/src/format.c +index ee6b8f3..ae4824c 100644 +--- a/src/format.c ++++ b/src/format.c +@@ -4825,3 +4825,44 @@ format_escape_for_filter(const char *unescaped) + } + return ret; + } ++ ++char * ++format_build_dn(const char *attribute, const char *value, ++ const char *container_sdn) ++{ ++ Slapi_RDN *rdn; ++ Slapi_DN *sdn; ++ char *val, *dn = NULL; ++ const char *ndn, *hexchars = "0123456789ABCDEF"; ++ int i; ++ ++ val = malloc(strlen(value) * 3 + 1); ++ if (val == NULL) { ++ return NULL; ++ } ++ rdn = slapi_rdn_new(); ++ if (rdn == NULL) { ++ free(val); ++ return NULL; ++ } ++ for (i = 0; value[i] != '\0'; i++) { ++ val[i * 3] = '\\'; ++ val[i * 3 + 1] = hexchars[(value[i] & 0xf0) >> 4]; ++ val[i * 3 + 2] = hexchars[value[i] & 0xf]; ++ } ++ val[i * 3] = '\0'; ++ if (slapi_rdn_add(rdn, attribute, val) == 1) { ++ sdn = slapi_sdn_new_dn_byval(container_sdn); ++ if (sdn != NULL) { ++ sdn = slapi_sdn_add_rdn(sdn, rdn); ++ ndn = slapi_sdn_get_ndn(sdn); ++ if (ndn != NULL) { ++ dn = slapi_ch_strdup(ndn); ++ } ++ slapi_sdn_free(&sdn); ++ } ++ } ++ free(val); ++ slapi_rdn_free(&rdn); ++ return dn; ++} +diff --git a/src/format.h b/src/format.h +index 4cde2dc..626d4a9 100644 +--- a/src/format.h ++++ b/src/format.h +@@ -83,4 +83,6 @@ char **format_get_data_set(struct plugin_state *state, + unsigned int **data_lengths); + + char *format_escape_for_filter(const char *unescaped); ++char *format_build_dn(const char *attribute, const char *value, ++ const char *container_sdn); + #endif +-- +2.13.6 + diff --git a/SOURCES/slapi-0012-Add-dummy-handler-for-a-related-add-delete-modify-to.patch b/SOURCES/slapi-0012-Add-dummy-handler-for-a-related-add-delete-modify-to.patch new file mode 100644 index 0000000..e5f1a30 --- /dev/null +++ b/SOURCES/slapi-0012-Add-dummy-handler-for-a-related-add-delete-modify-to.patch @@ -0,0 +1,53 @@ +From 79ddc12c93920840e9fbdf5c8ea25db1c4166af5 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Tue, 12 Sep 2017 14:52:21 +0300 +Subject: [PATCH 12/17] Add dummy handler for a related add/delete/modify to + NIS plugin + +NIS doesn't need to handle ID overrides, it has to always skip related entries +--- + src/back-nis.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/src/back-nis.c b/src/back-nis.c +index 7fb191d..244beba 100644 +--- a/src/back-nis.c ++++ b/src/back-nis.c +@@ -1014,6 +1014,34 @@ backend_check_empty(struct plugin_state *state, + } + } + ++bool_t ++backend_entry_is_add_related(const char *group, const char *set, bool_t flag, ++ void *shared_set_data, ++ Slapi_PBlock *pb, ++ Slapi_Entry *e) ++{ ++ return FALSE; ++} ++ ++bool_t ++backend_entry_is_modify_related(const char *group, const char *set, bool_t flag, ++ void *shared_set_data, ++ Slapi_PBlock *pb, ++ Slapi_Entry *e_pre, ++ Slapi_Entry *e_post) ++{ ++ return FALSE; ++} ++ ++bool_t ++backend_entry_is_delete_related(const char *group, const char *set, bool_t flag, ++ void *shared_set_data, ++ Slapi_PBlock *pb, ++ Slapi_Entry *e) ++{ ++ return FALSE; ++} ++ + /* Scan for the list of configured domains and maps. */ + void + backend_startup(Slapi_PBlock *pb, struct plugin_state *state) +-- +2.13.6 + diff --git a/SOURCES/slapi-0013-track-changes-to-ID-overrides-and-evict-map-cache-en.patch b/SOURCES/slapi-0013-track-changes-to-ID-overrides-and-evict-map-cache-en.patch new file mode 100644 index 0000000..49465ec --- /dev/null +++ b/SOURCES/slapi-0013-track-changes-to-ID-overrides-and-evict-map-cache-en.patch @@ -0,0 +1,340 @@ +From bcdcb8e762c6a8824ff1dd67f7e068ef519b3952 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Mon, 11 Sep 2017 15:33:24 +0300 +Subject: [PATCH 13/17] track changes to ID overrides and evict map cache + entries + +Plug into a processing of LDAP add/delete/modify to see if an ID override entry +was added/deleted/updated. ID overrides aren't directly used to produce +map cache entries but when AD user or group is resolved, SSSD on IPA +master amends that information with ID Override from a Default Trust +View. Since nothing else would remove AD user or group entry from the map cache +on ID override change, handle their removal here. + +Check if we have any nssswitch-generated entry in a map cache that +corresponds to this entry. Such entries would be evicted from the map +cache to allow their refresh. + +Allow backends to inspect entries related to a map set + +Entries may be related to a map set content but not used directly to +generate it. An example would be ID overrides in FreeIPA. An addition, +removal or change of an ID override in the Default Trust View should be +reflected by evicting an entry from the corresponding seti. + +Let backends to handle exact logic. NIS backend does not support +exposing AD users so it provides set of dummy callbacks that always +return FALSE (entry is not related). Schema Compat backend, on other +hand, does track ID overrides in a Default Trust View in FreeIPA. +--- + src/back-sch.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + src/back-shr.c | 55 ++++++++++++++---- + src/backend.h | 20 +++++++ + 3 files changed, 239 insertions(+), 12 deletions(-) + +diff --git a/src/back-sch.c b/src/back-sch.c +index e15988f..f98b0b4 100644 +--- a/src/back-sch.c ++++ b/src/back-sch.c +@@ -33,6 +33,7 @@ + #ifdef HAVE_DIRSRV_SLAPI_PLUGIN_H + #include + #include ++#include + #include + #include + #else +@@ -2099,6 +2100,181 @@ backend_write_cb(Slapi_PBlock *pb, struct plugin_state *state) + return ret; + } + ++#ifdef USE_IPA_IDVIEWS ++/* Check if ID override applies to an entry in our map cache ++ * and remove the entry in case it does. */ ++ ++static bool_t ++backend__get_original_uid_and_ndn(Slapi_Entry *e, ++ char **original_uid, ++ const char **original_anchor) ++{ ++ char **elem = NULL; ++ char *v = NULL; ++ char *ndn = NULL; ++ char *view = NULL; ++ int n_elem = 0; ++ int i = 0; ++ ++ if (e == NULL) { ++ return FALSE; ++ } ++ ++ elem = slapi_entry_attr_get_charray_ext(e, "objectClass", &n_elem); ++ if (elem == NULL) { ++ /* weird, objectClass should be existing */ ++ return FALSE; ++ } ++ ++ for (i=0; i < n_elem; i++) { ++ if (strncasecmp(elem[i], "ipaOverrideAnchor", 17) == 0) { ++ break; ++ } ++ } ++ ++ slapi_ch_array_free(elem); ++ if (i == n_elem) { ++ /* This is not an override, bail out */ ++ return FALSE; ++ } ++ ++ ndn = slapi_entry_get_ndn(e); ++ if (ndn == NULL) { ++ return FALSE; ++ } ++ ++ view = PL_strcasestr(ndn, "cn=Default Trust View,"); ++ if (view == NULL || view == ndn) { ++ return FALSE; ++ } ++ ++ /* This is an ID override, we need to search for a referenced ipaOriginalUid or cn in our maps */ ++ v = slapi_entry_attr_get_charptr(e, "ipaOriginalUid"); ++ if (v == NULL) { ++ v = slapi_entry_attr_get_charptr(e, "cn"); ++ if (v == NULL) { ++ return FALSE; ++ } ++ } ++ ++ *original_uid = v; ++ *original_anchor = ndn; ++ return TRUE; ++} ++ ++bool_t ++backend_entry_evict_if_related(const char *group, const char *set, bool_t flag, ++ void *shared_set_data, ++ Slapi_PBlock *pb, ++ Slapi_Entry *e) ++{ ++ struct backend_set_data *set_data; ++ struct plugin_state *state = NULL; ++ char *id = NULL; ++ char *original_uid = NULL; ++ const char *original_anchor = NULL; ++ const char *rdn_attribute[] = {NULL, "uid=%s,%s,%s", "cn=%s,%s,%s"}; ++ bool_t result = FALSE; ++ ++ set_data = shared_set_data; ++ ++ /* We only interested in NSSWITCH-capable maps */ ++ if (set_data->check_nsswitch == SCH_NSSWITCH_NONE) { ++ return FALSE; ++ } ++ ++ /* See if the entry pre modification had original UID */ ++ if (!backend__get_original_uid_and_ndn(e, ++ &original_uid, ++ &original_anchor)) { ++ return FALSE; ++ } ++ ++ id = slapi_ch_smprintf(rdn_attribute[set_data->check_nsswitch], ++ original_uid, set, group); ++ ++ if (id == NULL) { ++ slapi_ch_free_string(&original_uid); ++ return FALSE; ++ } ++ ++ slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state); ++ result = map_data_check_entry(state, group, set, id); ++ if (result) { ++ slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, ++ "evicted entry %s due to changed content of ID override %s\n", ++ id, original_anchor); ++ ++ /* An entry corresponding to our target is found, evict it */ ++ map_data_unset_entry(state, group, set, id); ++ } ++ ++ slapi_ch_free_string(&id); ++ slapi_ch_free_string(&original_uid); ++ return result; ++} ++ ++bool_t ++backend_entry_is_add_related(const char *group, const char *set, bool_t flag, ++ void *shared_set_data, ++ Slapi_PBlock *pb, ++ Slapi_Entry *e) ++{ ++ return backend_entry_evict_if_related(group, set, flag, shared_set_data, pb, e); ++} ++ ++ ++bool_t ++backend_entry_is_modify_related(const char *group, const char *set, bool_t flag, ++ void *shared_set_data, ++ Slapi_PBlock *pb, ++ Slapi_Entry *e_pre, ++ Slapi_Entry *e_post) ++{ ++ return backend_entry_evict_if_related(group, set, flag, shared_set_data, pb, e_pre); ++} ++ ++bool_t ++backend_entry_is_delete_related(const char *group, const char *set, bool_t flag, ++ void *shared_set_data, ++ Slapi_PBlock *pb, ++ Slapi_Entry *e) ++{ ++ return backend_entry_evict_if_related(group, set, flag, shared_set_data, pb, e); ++} ++ ++#else ++ ++bool_t ++backend_entry_is_add_related(const char *group, const char *set, bool_t flag, ++ void *shared_set_data, ++ Slapi_PBlock *pb, ++ Slapi_Entry *e) ++{ ++ return FALSE; ++} ++ ++bool_t ++backend_entry_is_modify_related(const char *group, const char *set, bool_t flag, ++ void *shared_set_data, ++ Slapi_PBlock *pb, ++ Slapi_Entry *e_pre, ++ Slapi_Entry *e_post) ++{ ++ return FALSE; ++} ++ ++bool_t ++backend_entry_is_delete_related(const char *group, const char *set, bool_t flag, ++ void *shared_set_data, ++ Slapi_PBlock *pb, ++ Slapi_Entry *e) ++{ ++ return FALSE; ++} ++ ++#endif ++ + static int + backend_pre_write_cb(Slapi_PBlock *pb) + { +diff --git a/src/back-shr.c b/src/back-shr.c +index 7842e05..a7ea92f 100644 +--- a/src/back-shr.c ++++ b/src/back-shr.c +@@ -1856,11 +1856,21 @@ backend_shr_add_entry_cb(const char *group, const char *set, bool_t secure, + + /* If the entry doesn't match the set, skip it. */ + if (!backend_shr_entry_matches_set(set_data, cbdata->pb, cbdata->e)) { +- slapi_log_error(SLAPI_LOG_PLUGIN, +- cbdata->state->plugin_desc->spd_id, +- "entry \"%s\" does not belong in " +- "\"%s\"/\"%s\"\n", +- cbdata->ndn, group, set); ++ /* Give backend a chance to perform other operations on the add op. ++ * For example, ID override addition in FreeIPA need to be noted to ++ * evict AD user/group entries from a map cache while ID overrides ++ * themselves aren't present in any map. ++ * Note that we could do this as a part of backend_shr_entry_matches_set() ++ * but it is better to isolate this operation in a separate call. */ ++ if (!backend_entry_is_add_related(group, set, secure, ++ set_data, cbdata->pb, ++ cbdata->e)) { ++ slapi_log_error(SLAPI_LOG_PLUGIN, ++ cbdata->state->plugin_desc->spd_id, ++ "entry \"%s\" does not belong in " ++ "\"%s\"/\"%s\"\n", ++ cbdata->ndn, group, set); ++ } + return TRUE; + } + +@@ -2010,13 +2020,24 @@ backend_shr_modify_entry_cb(const char *group, const char *set, bool_t flag, + cbdata->e_post) && + !backend_shr_entry_matches_set(set_data, cbdata->pb, + cbdata->e_pre)) { +- slapi_log_error(SLAPI_LOG_PLUGIN, +- cbdata->state->plugin_desc->spd_id, +- "\"%s\" not in \"%s\"/\"%s\", " +- "before or after modify\n", +- cbdata->ndn, +- set_data->group, +- set_data->set); ++ /* Give backend a chance to perform other operations on the modify op. ++ * For example, ID override updates in FreeIPA need to be noted to ++ * evict AD user/group entries from a map cache while ID overrides ++ * themselves aren't present in any map. ++ * Note that we could do this as a part of backend_shr_entry_matches_set() ++ * but it is better to isolate this operation in a separate call. */ ++ if (!backend_entry_is_modify_related(group, set, flag, ++ set_data, cbdata->pb, ++ cbdata->e_pre, ++ cbdata->e_post)) { ++ slapi_log_error(SLAPI_LOG_PLUGIN, ++ cbdata->state->plugin_desc->spd_id, ++ "\"%s\" not in \"%s\"/\"%s\", " ++ "before or after modify\n", ++ cbdata->ndn, ++ set_data->group, ++ set_data->set); ++ } + return TRUE; + } + if (set_data->skip_uninteresting_updates && +@@ -2631,6 +2652,16 @@ backend_shr_delete_entry_cb(const char *group, const char *set, bool_t flag, + group, set, set_data->group, set_data->set, + cbdata->ndn); + map_data_unset_entry(cbdata->state, group, set, cbdata->ndn); ++ } else { ++ /* Give backend a chance to perform other operations on the delete op. ++ * For example, ID override removal in FreeIPA need to be noted to ++ * evict AD user/group entries from a map cache while ID overrides ++ * themselves aren't present in any map. ++ * Note that we could do this as a part of backend_shr_entry_matches_set() ++ * but it is better to isolate this operation in a separate call. */ ++ (void) backend_entry_is_delete_related(group, set, flag, ++ set_data, cbdata->pb, ++ cbdata->e); + } + return TRUE; + } +diff --git a/src/backend.h b/src/backend.h +index 4608d2d..f0a5bbb 100644 +--- a/src/backend.h ++++ b/src/backend.h +@@ -115,4 +115,24 @@ void backend_update_params(Slapi_PBlock *pb, struct plugin_state *state); + bool_t backend_shr_is_caller(struct plugin_state *state, + struct slapi_pblock *pb); + ++/* Check if an operation is performed on an entry that is related to ++ * any entry in the set. This allows to catch changes of the entries that ++ * aren't directly included in the map set but should affect the set. */ ++bool_t ++backend_entry_is_modify_related(const char *group, const char *set, bool_t flag, ++ void *shared_set_data, ++ Slapi_PBlock *pb, ++ Slapi_Entry *e_pre, ++ Slapi_Entry *e_post); ++bool_t ++backend_entry_is_add_related(const char *group, const char *set, bool_t flag, ++ void *shared_set_data, ++ Slapi_PBlock *pb, ++ Slapi_Entry *e); ++bool_t ++backend_entry_is_delete_related(const char *group, const char *set, bool_t flag, ++ void *shared_set_data, ++ Slapi_PBlock *pb, ++ Slapi_Entry *e); ++ + #endif +-- +2.13.6 + diff --git a/SOURCES/slapi-0015-configure.ac-detect-extended-NSS-API-provided-by-SSS.patch b/SOURCES/slapi-0015-configure.ac-detect-extended-NSS-API-provided-by-SSS.patch new file mode 100644 index 0000000..76c6a0b --- /dev/null +++ b/SOURCES/slapi-0015-configure.ac-detect-extended-NSS-API-provided-by-SSS.patch @@ -0,0 +1,53 @@ +From 6c4e8869ba6121ddbc6e1eca880c39b0af3391e0 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Wed, 25 Oct 2017 11:38:55 +0300 +Subject: [PATCH 15/17] configure.ac: detect extended NSS API provided by SSSD + +SSSD exposes an extended NSS API via libsss_nss_idmap. This API allows +to query getpwnam()/getgrnam()/getgruid()/getpwuid()/getgrouplist() +information with a timeout per request. As result, an application has +possibility to cancel too long request. + +This API also allows to ignore SSSD cache or invalidate it when +requesting certain information. slapi-nis needs this functionality when +invalidating own entries as result of changes done by other LDAP clients +in the areas which slapi-nis doesn't track directly. + +For example, an update of ID override in the Default Trust View should +invalidate user or group entry for that AD object. Since retrieval of +the user/group information relies on SSSD, SSSD needs to be notified +that there is a change in ID override and evict the entry from its cache +as well. +--- + configure.ac | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/configure.ac b/configure.ac +index f82a47e..a958607 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -361,8 +361,13 @@ if test "x$use_nsswitch" != xno ; then + SSS_NSS_IDMAP_LIBS= + fi + fi ++ + AC_SUBST(SSS_NSS_IDMAP_CFLAGS) + AC_SUBST(SSS_NSS_IDMAP_LIBS) ++ AC_CHECK_LIB(sss_nss_idmap,sss_nss_getpwnam_timeout) ++ if test "x$ac_cv_lib_sss_nss_idmap_sss_nss_getpwnam_timeout" = xyes ; then ++ AC_DEFINE(USE_SSS_NSS_TIMEOUT,1,[Use extended NSS API provided by SSSD]) ++ fi + + if test "x$use_pam" != xno ; then + AC_CHECK_HEADERS(security/pam_appl.h) +@@ -384,6 +389,7 @@ if test "x$use_nsswitch" != xno ; then + fi + AC_DEFINE(USE_NSSWITCH,1,[Use nsswitch API to lookup users and groups not found in the LDAP tree]) + fi ++AM_CONDITIONAL([USE_SSS_NSS_TIMEOUT], [test "x$ac_cv_lib_sss_nss_idmap_sss_nss_getpwnam_timeout" = xyes]) + + use_idviews=true + AC_ARG_WITH(idviews, +-- +2.13.6 + diff --git a/SOURCES/slapi-0016-schema-compat-add-support-for-timeout-based-NSS-quer.patch b/SOURCES/slapi-0016-schema-compat-add-support-for-timeout-based-NSS-quer.patch new file mode 100644 index 0000000..972b735 --- /dev/null +++ b/SOURCES/slapi-0016-schema-compat-add-support-for-timeout-based-NSS-quer.patch @@ -0,0 +1,933 @@ +From 6fbf5891e9169142fc0ea37eb8f897a645b82d6f Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Wed, 1 Nov 2017 10:29:41 +0200 +Subject: [PATCH 16/17] schema-compat: add support for timeout-based NSS + queries with libsss_nss_idmap + +In case libsss_nss_idmap provides timeout-enabled NSS API, use it. +This solves a problem of too long queries to an NSS backend with +traditional POSIX NSS API. In case SSSD takes too long to respond +to a query, corresponding 389-ds thread running schema-compat plugin +would stuck waiting that response. It can lead to an exhaustion of +389-ds threads. + +A refactored interface to NSS backends is introduced with this commit. +A backend API looks like an API an NSS plugin has to implement in glibc +but also allows to handle timeout-based requests internally. + +If backend implements timeout-enabled calls, then +backend_nss_set_timeout() function can be used to modify a per-context +state. There is no need for a caller to know whether backend supports +timeout-enabled calls because either way these calls are synchronous +and backend choice is done at compile-time. + +schema-compat plugin uses 10 seconds as its default timeout. One can +change it via 'slapi-nss-timeout' attribute in the plugin config entry. +--- + src/Makefile.am | 11 ++- + src/back-sch-nss.c | 187 +++++------------------------------- + src/back-sch-nss.h | 70 ++++++++++++++ + src/back-sch-nss_sss.c | 231 +++++++++++++++++++++++++++++++++++++++++++++ + src/back-sch-sss_idmap.c | 239 +++++++++++++++++++++++++++++++++++++++++++++++ + src/back-sch.h | 9 +- + src/plug-sch.c | 7 ++ + 7 files changed, 588 insertions(+), 166 deletions(-) + create mode 100644 src/back-sch-nss.h + create mode 100644 src/back-sch-nss_sss.c + create mode 100644 src/back-sch-sss_idmap.c + +diff --git a/src/Makefile.am b/src/Makefile.am +index 6f4926e..cd1efc2 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -68,8 +68,17 @@ schemacompat_plugin_la_LIBADD = $(LDAP_LIBS) $(RUNTIME_LIBS) $(LIBPTHREAD) $(CON + + if USE_NSSWITCH + schemacompat_plugin_la_CFLAGS += $(SSS_NSS_IDMAP_CFLAGS) +-schemacompat_plugin_la_SOURCES += back-sch-nss.c ++schemacompat_plugin_la_SOURCES += back-sch-nss.c back-sch-nss.h + schemacompat_plugin_la_LIBADD += $(SSS_NSS_IDMAP_LIBS) ++# We have two backends for nss operations: ++# (1) directly loading nss_sss.so.2 ++# (2) using timeout-enabled API from libsss_nss_idmap ++# We prefer (2) if available ++if USE_SSS_NSS_TIMEOUT ++schemacompat_plugin_la_SOURCES += back-sch-sss_idmap.c ++else ++schemacompat_plugin_la_SOURCES += back-sch-nss_sss.c ++endif + endif + + if USE_PAM +diff --git a/src/back-sch-nss.c b/src/back-sch-nss.c +index e4d027e..e5f91b2 100644 +--- a/src/back-sch-nss.c ++++ b/src/back-sch-nss.c +@@ -28,7 +28,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -52,6 +51,7 @@ + #include "map.h" + #include "back-sch.h" + #include "format.h" ++#include "back-sch-nss.h" + + static int + bvstrprefix(const struct berval *bval, const char *s) +@@ -294,143 +294,6 @@ backend_make_user_entry_from_nsswitch_passwd(struct passwd *pwd, + return entry; + } + +-/* Possible results of lookup using a nss_* function. +- * Note: don't include nss.h as its path gets overriden by NSS library */ +-enum nss_status +-{ +- NSS_STATUS_TRYAGAIN = -2, +- NSS_STATUS_UNAVAIL, +- NSS_STATUS_NOTFOUND, +- NSS_STATUS_SUCCESS, +- NSS_STATUS_RETURN +-}; +- +-struct nss_ops_ctx { +- void *dl_handle; +- +- enum nss_status (*getpwnam_r)(const char *name, struct passwd *result, +- char *buffer, size_t buflen, int *errnop); +- enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result, +- char *buffer, size_t buflen, int *errnop); +- enum nss_status (*setpwent)(void); +- enum nss_status (*getpwent_r)(struct passwd *result, +- char *buffer, size_t buflen, int *errnop); +- enum nss_status (*endpwent)(void); +- +- enum nss_status (*getgrnam_r)(const char *name, struct group *result, +- char *buffer, size_t buflen, int *errnop); +- enum nss_status (*getgrgid_r)(gid_t gid, struct group *result, +- char *buffer, size_t buflen, int *errnop); +- enum nss_status (*setgrent)(void); +- enum nss_status (*getgrent_r)(struct group *result, +- char *buffer, size_t buflen, int *errnop); +- enum nss_status (*endgrent)(void); +- +- enum nss_status (*initgroups_dyn)(const char *user, gid_t group, +- long int *start, long int *size, +- gid_t **groups, long int limit, +- int *errnop); +-}; +- +-void backend_nss_init_context(struct nss_ops_ctx **nss_context) +-{ +- struct nss_ops_ctx *ctx = NULL; +- +- if (nss_context == NULL) { +- return; +- } +- +- ctx = calloc(1, sizeof(struct nss_ops_ctx)); +- +- *nss_context = ctx; +- if (ctx == NULL) { +- return; +- } +- +- ctx->dl_handle = dlopen("libnss_sss.so.2", RTLD_NOW); +- if (ctx->dl_handle == NULL) { +- goto fail; +- } +- +- ctx->getpwnam_r = dlsym(ctx->dl_handle, "_nss_sss_getpwnam_r"); +- if (ctx->getpwnam_r == NULL) { +- goto fail; +- } +- +- ctx->getpwuid_r = dlsym(ctx->dl_handle, "_nss_sss_getpwuid_r"); +- if (ctx->getpwuid_r == NULL) { +- goto fail; +- } +- +- ctx->setpwent = dlsym(ctx->dl_handle, "_nss_sss_setpwent"); +- if (ctx->setpwent == NULL) { +- goto fail; +- } +- +- ctx->getpwent_r = dlsym(ctx->dl_handle, "_nss_sss_getpwent_r"); +- if (ctx->getpwent_r == NULL) { +- goto fail; +- } +- +- ctx->endpwent = dlsym(ctx->dl_handle, "_nss_sss_endpwent"); +- if (ctx->endpwent == NULL) { +- goto fail; +- } +- +- ctx->getgrnam_r = dlsym(ctx->dl_handle, "_nss_sss_getgrnam_r"); +- if (ctx->getgrnam_r == NULL) { +- goto fail; +- } +- +- ctx->getgrgid_r = dlsym(ctx->dl_handle, "_nss_sss_getgrgid_r"); +- if (ctx->getgrgid_r == NULL) { +- goto fail; +- } +- +- ctx->setgrent = dlsym(ctx->dl_handle, "_nss_sss_setgrent"); +- if (ctx->setgrent == NULL) { +- goto fail; +- } +- +- ctx->getgrent_r = dlsym(ctx->dl_handle, "_nss_sss_getgrent_r"); +- if (ctx->getgrent_r == NULL) { +- goto fail; +- } +- +- ctx->endgrent = dlsym(ctx->dl_handle, "_nss_sss_endgrent"); +- if (ctx->endgrent == NULL) { +- goto fail; +- } +- +- ctx->initgroups_dyn = dlsym(ctx->dl_handle, "_nss_sss_initgroups_dyn"); +- if (ctx->initgroups_dyn == NULL) { +- goto fail; +- } +- +- return; +- +-fail: +- backend_nss_free_context(nss_context); +- +- return; +-} +- +-void +-backend_nss_free_context(struct nss_ops_ctx **nss_context) +-{ +- if (nss_context == NULL) { +- return; +- } +- +- if ((*nss_context)->dl_handle != NULL) { +- dlclose((*nss_context)->dl_handle); +- } +- +- free((*nss_context)); +- *nss_context = NULL; +-} +- +- + + static Slapi_Entry ** + backend_retrieve_user_entry_from_nsswitch(char *user_name, bool_t is_uid, +@@ -456,13 +319,13 @@ repeat: + } + + if (is_uid) { +- rc = ctx->getpwuid_r((uid_t) atoll(user_name), &pwd, +- cbdata->nsswitch_buffer, +- cbdata->nsswitch_buffer_len, &lerrno); ++ rc = backend_nss_getpwuid(ctx, (uid_t) atoll(user_name), &pwd, ++ cbdata->nsswitch_buffer, ++ cbdata->nsswitch_buffer_len, &result, &lerrno); + } else { +- rc = ctx->getpwnam_r(user_name, &pwd, +- cbdata->nsswitch_buffer, +- cbdata->nsswitch_buffer_len, &lerrno); ++ rc = backend_nss_getpwnam(ctx, user_name, &pwd, ++ cbdata->nsswitch_buffer, ++ cbdata->nsswitch_buffer_len, &result, &lerrno); + } + + if ((rc != NSS_STATUS_SUCCESS)) { +@@ -591,13 +454,13 @@ repeat: + } + + if (is_gid) { +- rc = ctx->getgrgid_r((gid_t) atoll(group_name), &grp, +- cbdata->nsswitch_buffer, +- cbdata->nsswitch_buffer_len, &lerrno); ++ rc = backend_nss_getgrgid(ctx, (gid_t) atoll(group_name), &grp, ++ cbdata->nsswitch_buffer, ++ cbdata->nsswitch_buffer_len, &result, &lerrno); + } else { +- rc = ctx->getgrnam_r(group_name, &grp, +- cbdata->nsswitch_buffer, +- cbdata->nsswitch_buffer_len, &lerrno); ++ rc = backend_nss_getgrnam(ctx, group_name, &grp, ++ cbdata->nsswitch_buffer, ++ cbdata->nsswitch_buffer_len, &result, &lerrno); + } + if ((rc != NSS_STATUS_SUCCESS)) { + if (lerrno == ERANGE) { +@@ -651,9 +514,9 @@ repeat: + return NULL; + } + +- rc = ctx->getgrgid_r(gid, &grp, +- cbdata->nsswitch_buffer, +- cbdata->nsswitch_buffer_len, &lerrno); ++ rc = backend_nss_getgrgid(ctx, gid, &grp, ++ cbdata->nsswitch_buffer, ++ cbdata->nsswitch_buffer_len, &result, &lerrno); + + if ((rc != NSS_STATUS_SUCCESS)) { + if (lerrno == ERANGE) { +@@ -689,7 +552,7 @@ backend_retrieve_group_list_from_nsswitch(char *user_name, char *container_sdn, + int i, idx; + struct nss_ops_ctx *ctx = NULL; + int lerrno = 0; +- long int ngroups = 0; ++ int ngroups = 0; + long int start = 0; + enum nss_status rc; + +@@ -702,9 +565,9 @@ repeat: + return NULL; + } + +- rc = ctx->getpwnam_r(user_name, &pwd, +- cbdata->nsswitch_buffer, +- cbdata->nsswitch_buffer_len, &lerrno); ++ rc = backend_nss_getpwnam(ctx, user_name, &pwd, ++ cbdata->nsswitch_buffer, ++ cbdata->nsswitch_buffer_len, &pwd_result, &lerrno); + + if ((rc != NSS_STATUS_SUCCESS)) { + if (lerrno == ERANGE) { +@@ -723,19 +586,15 @@ repeat: + } + + ngroups = 32; +- start = 0; + grouplist = malloc(sizeof(gid_t) * ngroups); + if (grouplist == NULL) { + return NULL; + } + +- grouplist[0] = pwd.pw_gid; +- start++; +- + do { +- rc = ctx->initgroups_dyn(user_name, pwd.pw_gid, +- &start, &ngroups, &grouplist, +- -1, &lerrno); ++ rc = backend_nss_getgrouplist(ctx, user_name, pwd.pw_gid, ++ grouplist, &ngroups, ++ &lerrno); + if ((rc != NSS_STATUS_SUCCESS)) { + tmp_list = realloc(grouplist, ngroups * sizeof(gid_t)); + if (tmp_list == NULL) { +diff --git a/src/back-sch-nss.h b/src/back-sch-nss.h +new file mode 100644 +index 0000000..54a3c07 +--- /dev/null ++++ b/src/back-sch-nss.h +@@ -0,0 +1,70 @@ ++/* ++ * Copyright 2017 Red Hat, Inc. ++ * ++ * 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; version 2 of the License. ++ * ++ * 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, write to the ++ * ++ * Free Software Foundation, Inc. ++ * 59 Temple Place, Suite 330 ++ * Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#ifndef back_sch_nss_h ++#define back_sch_nss_h ++#include ++#include ++#include ++ ++/* Possible results of lookup using a nss_* function. ++ * Note: don't include nss.h as its path gets overriden by NSS library */ ++enum nss_status ++{ ++ NSS_STATUS_TRYAGAIN = -2, ++ NSS_STATUS_UNAVAIL, ++ NSS_STATUS_NOTFOUND, ++ NSS_STATUS_SUCCESS, ++ NSS_STATUS_RETURN ++}; ++ ++struct nss_ops_ctx; ++ ++enum nss_status backend_nss_getpwnam(struct nss_ops_ctx *nss_context, ++ const char *name, struct passwd *pwd, ++ char *buffer, size_t buflen, ++ struct passwd **result, ++ int *lerrno); ++ ++enum nss_status backend_nss_getpwuid(struct nss_ops_ctx *nss_context, ++ uid_t uid, struct passwd *pwd, ++ char *buffer, size_t buflen, ++ struct passwd **result, ++ int *lerrno); ++ ++enum nss_status backend_nss_getgrnam(struct nss_ops_ctx *nss_context, ++ const char *name, struct group *grp, ++ char *buffer, size_t buflen, ++ struct group **result, ++ int *lerrno); ++ ++enum nss_status backend_nss_getgrgid(struct nss_ops_ctx *nss_context, ++ gid_t gid, struct group *grp, ++ char *buffer, size_t buflen, ++ struct group **result, ++ int *lerrno); ++ ++enum nss_status backend_nss_getgrouplist(struct nss_ops_ctx *nss_context, ++ const char *name, gid_t group, ++ gid_t *groups, int *ngroups, ++ int *lerrno); ++ ++#endif /* back_sch_nss_h */ +diff --git a/src/back-sch-nss_sss.c b/src/back-sch-nss_sss.c +new file mode 100644 +index 0000000..e3e6628 +--- /dev/null ++++ b/src/back-sch-nss_sss.c +@@ -0,0 +1,231 @@ ++/* ++ * Copyright 2013-2017 Red Hat, Inc. ++ * ++ * 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; version 2 of the License. ++ * ++ * 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, write to the ++ * ++ * Free Software Foundation, Inc. ++ * 59 Temple Place, Suite 330 ++ * Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "back-sch-nss.h" ++ ++struct nss_ops_ctx { ++ void *dl_handle; ++ long int initgroups_start; ++ ++ enum nss_status (*getpwnam_r)(const char *name, struct passwd *result, ++ char *buffer, size_t buflen, int *errnop); ++ enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result, ++ char *buffer, size_t buflen, int *errnop); ++ enum nss_status (*getgrnam_r)(const char *name, struct group *result, ++ char *buffer, size_t buflen, int *errnop); ++ enum nss_status (*getgrgid_r)(gid_t gid, struct group *result, ++ char *buffer, size_t buflen, int *errnop); ++ enum nss_status (*initgroups_dyn)(const char *user, gid_t group, ++ long int *start, long int *size, ++ gid_t **groups, long int limit, ++ int *errnop); ++}; ++ ++void backend_nss_init_context(struct nss_ops_ctx **nss_context) ++{ ++ struct nss_ops_ctx *ctx = NULL; ++ ++ if (nss_context == NULL) { ++ return; ++ } ++ ++ ctx = calloc(1, sizeof(struct nss_ops_ctx)); ++ ++ *nss_context = ctx; ++ if (ctx == NULL) { ++ return; ++ } ++ ++ ctx->dl_handle = dlopen("libnss_sss.so.2", RTLD_NOW); ++ if (ctx->dl_handle == NULL) { ++ goto fail; ++ } ++ ++ ctx->getpwnam_r = dlsym(ctx->dl_handle, "_nss_sss_getpwnam_r"); ++ if (ctx->getpwnam_r == NULL) { ++ goto fail; ++ } ++ ++ ctx->getpwuid_r = dlsym(ctx->dl_handle, "_nss_sss_getpwuid_r"); ++ if (ctx->getpwuid_r == NULL) { ++ goto fail; ++ } ++ ++ ctx->getgrnam_r = dlsym(ctx->dl_handle, "_nss_sss_getgrnam_r"); ++ if (ctx->getgrnam_r == NULL) { ++ goto fail; ++ } ++ ++ ctx->getgrgid_r = dlsym(ctx->dl_handle, "_nss_sss_getgrgid_r"); ++ if (ctx->getgrgid_r == NULL) { ++ goto fail; ++ } ++ ++ ctx->initgroups_dyn = dlsym(ctx->dl_handle, "_nss_sss_initgroups_dyn"); ++ if (ctx->initgroups_dyn == NULL) { ++ goto fail; ++ } ++ ++ return; ++ ++fail: ++ backend_nss_free_context(nss_context); ++ ++ return; ++} ++ ++void ++backend_nss_free_context(struct nss_ops_ctx **nss_context) ++{ ++ if (nss_context == NULL) { ++ return; ++ } ++ ++ if ((*nss_context)->dl_handle != NULL) { ++ dlclose((*nss_context)->dl_handle); ++ } ++ ++ free((*nss_context)); ++ *nss_context = NULL; ++} ++ ++ ++/* Following three functions cannot be implemented with nss_sss.so.2 ++ * As result, we simply do nothing here */ ++ ++void backend_nss_set_timeout(struct nss_ops_ctx **nss_context, ++ unsigned int timeout) { ++ /* no operation */ ++} ++ ++void backend_nss_evict_user(struct nss_ops_ctx **nss_context, ++ const char *name) { ++ /* no operation */ ++} ++ ++void backend_nss_evict_group(struct nss_ops_ctx **nss_context, ++ const char *name) { ++ /* no operation */ ++} ++ ++enum nss_status backend_nss_getpwnam(struct nss_ops_ctx *nss_context, ++ const char *name, struct passwd *pwd, ++ char *buffer, size_t buflen, ++ struct passwd **result, ++ int *lerrno) { ++ ++ if (nss_context == NULL) { ++ return NSS_STATUS_UNAVAIL; ++ } ++ ++ return (enum nss_status) ++ nss_context->getpwnam_r(name, pwd, ++ buffer, buflen, ++ result, lerrno); ++} ++ ++enum nss_status backend_nss_getpwuid(struct nss_ops_ctx *nss_context, ++ uid_t uid, struct passwd *pwd, ++ char *buffer, size_t buflen, ++ struct passwd **result, ++ int *lerrno) { ++ ++ if (nss_context == NULL) { ++ return NSS_STATUS_UNAVAIL; ++ } ++ ++ return (enum nss_status) ++ nss_context->getpwuid_r(uid, pwd, ++ buffer, buflen, ++ result, lerrno); ++} ++ ++enum nss_status backend_nss_getgrnam(struct nss_ops_ctx *nss_context, ++ const char *name, struct group *grp, ++ char *buffer, size_t buflen, ++ struct group **result, ++ int *lerrno) { ++ ++ if (nss_context == NULL) { ++ return NSS_STATUS_UNAVAIL; ++ } ++ ++ return (enum nss_status) ++ nss_context->getgrnam_r(name, grp, ++ buffer, buflen, ++ result, lerrno); ++} ++ ++enum nss_status backend_nss_getgrgid(struct nss_ops_ctx *nss_context, ++ gid_t gid, struct group *grp, ++ char *buffer, size_t buflen, ++ struct group **result, ++ int *lerrno) { ++ ++ if (nss_context == NULL) { ++ return NSS_STATUS_UNAVAIL; ++ } ++ ++ return (enum nss_status) ++ nss_context->getgrgid_r(gid, grp, ++ buffer, buflen, ++ result, lerrno); ++} ++ ++enum nss_status backend_nss_getgrouplist(struct nss_ops_ctx *nss_context, ++ const char *name, gid_t group, ++ gid_t *groups, int *ngroups, ++ int *lerrno) { ++ enum nss_status ret = NSS_STATUS_UNAVAIL; ++ ++ if (nss_context == NULL) { ++ return NSS_STATUS_UNAVAIL; ++ } ++ ++ if (nss_context->initgroups_start == 0) { ++ groups[0] = group; ++ nss_context->initgroups_start++; ++ } ++ ++ ret = nss_context->initgroups_dyn(name, group, ++ &nss_context->initgroups_start, ++ &ngroups, &groups, ++ -1, &lerrno); ++ if (ret == NSS_STATUS_SUCCESS) { ++ nss_context->initgroups_start = 0; ++ } ++ ++ return ret; ++} ++ +diff --git a/src/back-sch-sss_idmap.c b/src/back-sch-sss_idmap.c +new file mode 100644 +index 0000000..6a31267 +--- /dev/null ++++ b/src/back-sch-sss_idmap.c +@@ -0,0 +1,239 @@ ++/* ++ * Copyright 2013-2017 Red Hat, Inc. ++ * ++ * 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; version 2 of the License. ++ * ++ * 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, write to the ++ * ++ * Free Software Foundation, Inc. ++ * 59 Temple Place, Suite 330 ++ * Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "back-sch-nss.h" ++ ++/* SSSD only exposes *_timeout() variants if the following symbol is defined */ ++#define IPA_389DS_PLUGIN_HELPER_CALLS ++#include ++ ++struct nss_ops_ctx { ++ unsigned int timeout; ++}; ++ ++static enum nss_status __convert_sss_nss2nss_status(int errcode) { ++ enum nss_status ret = NSS_STATUS_UNAVAIL; ++ ++ if (errcode == 0) { ++ ret = NSS_STATUS_SUCCESS; ++ } else if (errcode == ENOENT) { ++ ret = NSS_STATUS_NOTFOUND; ++ } else if(errcode == ERANGE) { ++ ret = NSS_STATUS_TRYAGAIN; ++ } else if(errcode == ETIMEDOUT) { ++ ret = NSS_STATUS_UNAVAIL; ++ } else if(errcode == ETIME) { ++ ret = NSS_STATUS_TRYAGAIN; ++ }; ++ ++ return ret; ++} ++ ++void backend_nss_init_context(struct nss_ops_ctx **nss_context) ++{ ++ struct nss_ops_ctx *ctx = NULL; ++ ++ if (nss_context == NULL) { ++ return; ++ } ++ ++ ctx = calloc(1, sizeof(struct nss_ops_ctx)); ++ ++ *nss_context = ctx; ++} ++ ++void backend_nss_free_context(struct nss_ops_ctx **nss_context) ++{ ++ if (nss_context == NULL) { ++ return; ++ } ++ ++ free((*nss_context)); ++ *nss_context = NULL; ++} ++ ++ ++void backend_nss_set_timeout(struct nss_ops_ctx *nss_context, ++ unsigned int timeout) { ++ if (nss_context == NULL) { ++ return; ++ } ++ ++ nss_context->timeout = timeout; ++} ++ ++/* TODO: handle buffers and memory allocation in this function */ ++void backend_nss_evict_user(struct nss_ops_ctx *nss_context, ++ const char *name) { ++ if (nss_context == NULL) { ++ return; ++ } ++ ++ (void) sss_nss_getpwnam_timeout(name, NULL, ++ NULL, 0, ++ NULL, ++ SSS_NSS_EX_FLAG_INVALIDATE_CACHE, ++ nss_context->timeout); ++} ++ ++/* TODO: handle buffers and memory allocation in this function */ ++void backend_nss_evict_group(struct nss_ops_ctx *nss_context, ++ const char *name) { ++ if (nss_context == NULL) { ++ return; ++ } ++ ++ (void) sss_nss_getgrnam_timeout(name, NULL, ++ NULL, 0, ++ NULL, ++ SSS_NSS_EX_FLAG_INVALIDATE_CACHE, ++ nss_context->timeout); ++} ++ ++enum nss_status backend_nss_getpwnam(struct nss_ops_ctx *nss_context, ++ const char *name, struct passwd *pwd, ++ char *buffer, size_t buflen, ++ struct passwd **result, ++ int *lerrno) { ++ int ret = 0; ++ ++ if (nss_context == NULL) { ++ return NSS_STATUS_UNAVAIL; ++ } ++ ++ ret = sss_nss_getpwnam_timeout(name, pwd, ++ buffer, buflen, ++ result, ++ SSS_NSS_EX_FLAG_NO_FLAGS, ++ nss_context->timeout); ++ ++ if (ret != 0 && lerrno != NULL) { ++ /* SSSD translates errno into return code */ ++ *lerrno = ret; ++ } ++ return __convert_sss_nss2nss_status(ret); ++} ++ ++enum nss_status backend_nss_getpwuid(struct nss_ops_ctx *nss_context, ++ uid_t uid, struct passwd *pwd, ++ char *buffer, size_t buflen, ++ struct passwd **result, ++ int *lerrno) { ++ ++ int ret = 0; ++ ++ if (nss_context == NULL) { ++ return NSS_STATUS_UNAVAIL; ++ } ++ ++ ret = sss_nss_getpwuid_timeout(uid, pwd, ++ buffer, buflen, ++ result, ++ SSS_NSS_EX_FLAG_NO_FLAGS, ++ nss_context->timeout); ++ if (ret != 0 && lerrno != NULL) { ++ /* SSSD translates errno into return code */ ++ *lerrno = ret; ++ } ++ return __convert_sss_nss2nss_status(ret); ++} ++ ++enum nss_status backend_nss_getgrnam(struct nss_ops_ctx *nss_context, ++ const char *name, struct group *grp, ++ char *buffer, size_t buflen, ++ struct group **result, ++ int *lerrno) { ++ ++ int ret = 0; ++ ++ if (nss_context == NULL) { ++ return NSS_STATUS_UNAVAIL; ++ } ++ ++ ret = sss_nss_getgrnam_timeout(name, grp, ++ buffer, buflen, ++ result, ++ SSS_NSS_EX_FLAG_NO_FLAGS, ++ nss_context->timeout); ++ if (ret != 0 && lerrno != NULL) { ++ /* SSSD translates errno into return code */ ++ *lerrno = ret; ++ } ++ return __convert_sss_nss2nss_status(ret); ++} ++ ++enum nss_status backend_nss_getgrgid(struct nss_ops_ctx *nss_context, ++ gid_t gid, struct group *grp, ++ char *buffer, size_t buflen, ++ struct group **result, ++ int *lerrno) { ++ ++ int ret = 0; ++ ++ if (nss_context == NULL) { ++ return NSS_STATUS_UNAVAIL; ++ } ++ ++ ret = sss_nss_getgrgid_timeout(gid, grp, ++ buffer, buflen, ++ result, ++ SSS_NSS_EX_FLAG_NO_FLAGS, ++ nss_context->timeout); ++ if (ret != 0 && lerrno != NULL) { ++ /* SSSD translates errno into return code */ ++ *lerrno = ret; ++ } ++ return __convert_sss_nss2nss_status(ret); ++} ++ ++enum nss_status backend_nss_getgrouplist(struct nss_ops_ctx *nss_context, ++ const char *name, gid_t group, ++ gid_t *groups, int *ngroups, ++ int *lerrno) { ++ int ret = 0; ++ ++ if (nss_context == NULL) { ++ return NSS_STATUS_UNAVAIL; ++ } ++ ++ ret = sss_nss_getgrouplist_timeout(name, group, ++ groups, ngroups, ++ SSS_NSS_EX_FLAG_NO_FLAGS, ++ nss_context->timeout); ++ if (ret != 0 && lerrno != NULL) { ++ /* SSSD translates errno into return code */ ++ *lerrno = ret; ++ } ++ return __convert_sss_nss2nss_status(ret); ++} ++ +diff --git a/src/back-sch.h b/src/back-sch.h +index 9a9abc7..a400419 100644 +--- a/src/back-sch.h ++++ b/src/back-sch.h +@@ -152,10 +152,17 @@ typedef struct backend_extop_handlers { + + int backend_analyze_search_filter(Slapi_Filter *filter, struct backend_search_filter_config *config); + +-/* Operations against nsswitch API */ ++/* NSS backend operations implemented using either nss_sss.so.2 or libsss_nss_idmap API */ + struct nss_ops_ctx; ++ + void backend_nss_init_context(struct nss_ops_ctx **nss_context); + void backend_nss_free_context(struct nss_ops_ctx **nss_context); ++void backend_nss_set_timeout(struct nss_ops_ctx **nss_context, ++ unsigned int timeout); ++void backend_nss_evict_user(struct nss_ops_ctx **nss_context, ++ const char *name); ++void backend_nss_evict_group(struct nss_ops_ctx **nss_context, ++ const char *name); + + void backend_search_nsswitch(struct backend_set_data *set_data, + struct backend_search_cbdata *cbdata); +diff --git a/src/plug-sch.c b/src/plug-sch.c +index 00e7041..6ee4042 100644 +--- a/src/plug-sch.c ++++ b/src/plug-sch.c +@@ -104,6 +104,7 @@ plugin_startup(Slapi_PBlock *pb) + struct plugin_state *state; + Slapi_Entry *plugin_entry = NULL; + Slapi_DN *pluginsdn = NULL; ++ unsigned int nss_timeout = 10000; + + slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state); + slapi_pblock_get(pb, SLAPI_TARGET_SDN, &pluginsdn); +@@ -130,7 +131,13 @@ plugin_startup(Slapi_PBlock *pb) + state->use_entry_cache = backend_shr_get_vattr_boolean(state, plugin_entry, + "slapi-entry-cache", + 1); ++ nss_timeout = backend_shr_get_vattr_uint(state, plugin_entry, ++ "slapi-nss-timeout", ++ 10000); ++ + } ++ backend_nss_set_timeout(state->nss_context, nss_timeout); ++ + state->cached_entries_lock = wrap_new_rwlock(); + wrap_rwlock_wrlock(state->cached_entries_lock); + state->cached_entries = PL_NewHashTable(0, PL_HashString, PL_CompareStrings, PL_CompareValues, 0, 0); +-- +2.13.6 + diff --git a/SOURCES/slapi-0017-Fix-nss_sss-callers.patch b/SOURCES/slapi-0017-Fix-nss_sss-callers.patch new file mode 100644 index 0000000..d90305d --- /dev/null +++ b/SOURCES/slapi-0017-Fix-nss_sss-callers.patch @@ -0,0 +1,185 @@ +From 53f7f75ebf2a5086d63989bdf1da0d42983d6448 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Fri, 3 Nov 2017 23:49:19 +0200 +Subject: [PATCH 17/18] Fix nss_sss callers + +--- + src/back-sch-nss_sss.c | 82 +++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 57 insertions(+), 25 deletions(-) + +diff --git a/src/back-sch-nss_sss.c b/src/back-sch-nss_sss.c +index e3e6628..2b1b8b0 100644 +--- a/src/back-sch-nss_sss.c ++++ b/src/back-sch-nss_sss.c +@@ -52,6 +52,20 @@ struct nss_ops_ctx { + int *errnop); + }; + ++void backend_nss_free_context(struct nss_ops_ctx **nss_context) ++{ ++ if (nss_context == NULL) { ++ return; ++ } ++ ++ if ((*nss_context)->dl_handle != NULL) { ++ dlclose((*nss_context)->dl_handle); ++ } ++ ++ free((*nss_context)); ++ *nss_context = NULL; ++} ++ + void backend_nss_init_context(struct nss_ops_ctx **nss_context) + { + struct nss_ops_ctx *ctx = NULL; +@@ -105,21 +119,6 @@ fail: + return; + } + +-void +-backend_nss_free_context(struct nss_ops_ctx **nss_context) +-{ +- if (nss_context == NULL) { +- return; +- } +- +- if ((*nss_context)->dl_handle != NULL) { +- dlclose((*nss_context)->dl_handle); +- } +- +- free((*nss_context)); +- *nss_context = NULL; +-} +- + + /* Following three functions cannot be implemented with nss_sss.so.2 + * As result, we simply do nothing here */ +@@ -144,15 +143,22 @@ enum nss_status backend_nss_getpwnam(struct nss_ops_ctx *nss_context, + char *buffer, size_t buflen, + struct passwd **result, + int *lerrno) { ++ enum nss_status ret; + + if (nss_context == NULL) { + return NSS_STATUS_UNAVAIL; + } + +- return (enum nss_status) ++ ret = (enum nss_status) + nss_context->getpwnam_r(name, pwd, + buffer, buflen, +- result, lerrno); ++ lerrno); ++ ++ if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) { ++ *result = pwd; ++ } ++ ++ return ret; + } + + enum nss_status backend_nss_getpwuid(struct nss_ops_ctx *nss_context, +@@ -160,15 +166,22 @@ enum nss_status backend_nss_getpwuid(struct nss_ops_ctx *nss_context, + char *buffer, size_t buflen, + struct passwd **result, + int *lerrno) { ++ enum nss_status ret; + + if (nss_context == NULL) { + return NSS_STATUS_UNAVAIL; + } + +- return (enum nss_status) ++ ret = (enum nss_status) + nss_context->getpwuid_r(uid, pwd, + buffer, buflen, +- result, lerrno); ++ lerrno); ++ ++ if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) { ++ *result = pwd; ++ } ++ ++ return ret; + } + + enum nss_status backend_nss_getgrnam(struct nss_ops_ctx *nss_context, +@@ -176,15 +189,22 @@ enum nss_status backend_nss_getgrnam(struct nss_ops_ctx *nss_context, + char *buffer, size_t buflen, + struct group **result, + int *lerrno) { ++ enum nss_status ret; + + if (nss_context == NULL) { + return NSS_STATUS_UNAVAIL; + } + +- return (enum nss_status) ++ ret = (enum nss_status) + nss_context->getgrnam_r(name, grp, + buffer, buflen, +- result, lerrno); ++ lerrno); ++ ++ if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) { ++ *result = grp; ++ } ++ ++ return ret; + } + + enum nss_status backend_nss_getgrgid(struct nss_ops_ctx *nss_context, +@@ -193,21 +213,31 @@ enum nss_status backend_nss_getgrgid(struct nss_ops_ctx *nss_context, + struct group **result, + int *lerrno) { + ++ enum nss_status ret; ++ + if (nss_context == NULL) { + return NSS_STATUS_UNAVAIL; + } + +- return (enum nss_status) ++ ret = (enum nss_status) + nss_context->getgrgid_r(gid, grp, + buffer, buflen, +- result, lerrno); ++ lerrno); ++ ++ if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) { ++ *result = grp; ++ } ++ ++ return ret; + } + + enum nss_status backend_nss_getgrouplist(struct nss_ops_ctx *nss_context, + const char *name, gid_t group, + gid_t *groups, int *ngroups, + int *lerrno) { ++ + enum nss_status ret = NSS_STATUS_UNAVAIL; ++ long int size = 0; + + if (nss_context == NULL) { + return NSS_STATUS_UNAVAIL; +@@ -220,12 +250,14 @@ enum nss_status backend_nss_getgrouplist(struct nss_ops_ctx *nss_context, + + ret = nss_context->initgroups_dyn(name, group, + &nss_context->initgroups_start, +- &ngroups, &groups, +- -1, &lerrno); ++ &size, &groups, ++ -1, lerrno); + if (ret == NSS_STATUS_SUCCESS) { + nss_context->initgroups_start = 0; + } + ++ *ngroups = (int) size; ++ + return ret; + } + +-- +2.13.6 + diff --git a/SOURCES/slapi-0017-back-sch-cancel-memberof-retrieval-in-case-of-a-dirs.patch b/SOURCES/slapi-0017-back-sch-cancel-memberof-retrieval-in-case-of-a-dirs.patch new file mode 100644 index 0000000..7c5dd7f --- /dev/null +++ b/SOURCES/slapi-0017-back-sch-cancel-memberof-retrieval-in-case-of-a-dirs.patch @@ -0,0 +1,29 @@ +From 46649808918c027865dfaf78869aeeaddf97f47c Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Thu, 2 Nov 2017 17:14:14 +0200 +Subject: [PATCH 17/17] back-sch: cancel memberof retrieval in case of a dirsrv + shutdown + +Do not wait for SSSD to become online if directory server is going +for shutdown. Since it is guaranteed that SSSD will not be able to +function with 389-ds offline, it makes no sense to continue a loop. +--- + src/back-sch.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/back-sch.c b/src/back-sch.c +index f98b0b4..1998765 100644 +--- a/src/back-sch.c ++++ b/src/back-sch.c +@@ -507,7 +507,7 @@ backend_set_process_external_members(Slapi_PBlock *pb, + /* This group must exist because it exists in the original tree + * but as dirsrv was restarted, SSSD might still consider its domain offline. */ + is_group_exists = backend_retrieve_from_nsswitch(&staged, &cbdata); +- if (!is_group_exists) { ++ if (!is_group_exists && !slapi_is_shutting_down()) { + slapi_log_error(SLAPI_LOG_FATAL, plugin_id, + "group \"%s\" does not exist because SSSD is offline.\n", + staged.name); +-- +2.13.6 + diff --git a/SOURCES/slapi-0018-Clean-up-unused-code.patch b/SOURCES/slapi-0018-Clean-up-unused-code.patch new file mode 100644 index 0000000..8fab1e3 --- /dev/null +++ b/SOURCES/slapi-0018-Clean-up-unused-code.patch @@ -0,0 +1,68 @@ +From 9f8158841cc5ee3017de8f718203707d27ae87e1 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Sat, 4 Nov 2017 07:35:22 +0200 +Subject: [PATCH 18/18] Clean up unused code + +--- + src/back-sch-idview.c | 2 +- + src/back-sch-nss.c | 4 +--- + src/back-sch.h | 1 - + 3 files changed, 2 insertions(+), 5 deletions(-) + +diff --git a/src/back-sch-idview.c b/src/back-sch-idview.c +index 8842906..e83fb1d 100644 +--- a/src/back-sch-idview.c ++++ b/src/back-sch-idview.c +@@ -121,7 +121,7 @@ idview_process_overrides(struct backend_search_cbdata *cbdata, + "createtimestamp", "modifytimestamp", "parentid", + "entryusn", "entryid", "entrydn", "ipaoriginaluid", + "ipaanchoruuid", "nsuniqueid", "ipasshpubkey", NULL }; +- char *new_dn = NULL, *new_key = NULL, *sep = NULL, *new_val = NULL; ++ char *new_dn = NULL, *sep = NULL, *new_val = NULL; + char *override_type = NULL; + Slapi_Entry *override_entry = NULL; + Slapi_Attr *anchor = NULL, *id_attr = NULL; +diff --git a/src/back-sch-nss.c b/src/back-sch-nss.c +index e5f91b2..df04a96 100644 +--- a/src/back-sch-nss.c ++++ b/src/back-sch-nss.c +@@ -57,7 +57,6 @@ static int + bvstrprefix(const struct berval *bval, const char *s) + { + size_t len; +- int c; + + len = strlen(s); + if (len < bval->bv_len) { +@@ -553,7 +552,6 @@ backend_retrieve_group_list_from_nsswitch(char *user_name, char *container_sdn, + struct nss_ops_ctx *ctx = NULL; + int lerrno = 0; + int ngroups = 0; +- long int start = 0; + enum nss_status rc; + + ctx = cbdata->state->nss_context; +@@ -674,7 +672,7 @@ void + backend_search_nsswitch(struct backend_set_data *set_data, + struct backend_search_cbdata *cbdata) + { +- int result, rc; ++ int result; + struct backend_search_filter_config config = + {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL, NULL, NULL}; + struct backend_staged_search *staged = NULL; +diff --git a/src/back-sch.h b/src/back-sch.h +index a400419..483e288 100644 +--- a/src/back-sch.h ++++ b/src/back-sch.h +@@ -137,7 +137,6 @@ struct backend_search_filter_config { + #define LDAP_EXTOP_PASSMOD_TAG_NEWPWD 0x82U + + typedef int (*IFP)(); +-static int backend_passwdmod_extop(Slapi_PBlock *pb); + typedef struct backend_extop_handlers { + char *oid; + IFP extop_fct; +-- +2.13.6 + diff --git a/SOURCES/slapi-0019-Synchronize-nsswitch-backend-code-with-freeIPA.patch b/SOURCES/slapi-0019-Synchronize-nsswitch-backend-code-with-freeIPA.patch new file mode 100644 index 0000000..d7daa01 --- /dev/null +++ b/SOURCES/slapi-0019-Synchronize-nsswitch-backend-code-with-freeIPA.patch @@ -0,0 +1,905 @@ +From 1229089c4023757ae15ff1866e4d89069325d2f0 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Thu, 7 Dec 2017 12:33:24 +0200 +Subject: [PATCH] Synchronize nsswitch backend code with freeIPA + +FreeIPA ipa-extdom-extop plugin uses the same logic as slapi-nis +schema-compat plugin to handle requests to SSSD. Thus, we keep the +code synchronized across both code bases. Since both plugins are loaded +into the same address space we currently rename functions to allow them +to co-exist. In future we'd move some of common code to a shared +library. +--- + src/back-sch-nss_sss.c | 365 ++++++++++++++++++++++++----------------------- + src/back-sch-sss_idmap.c | 335 +++++++++++++++++++++++-------------------- + src/back-sch.h | 8 +- + src/plug-sch.c | 32 +++-- + 4 files changed, 390 insertions(+), 350 deletions(-) + +diff --git a/src/back-sch-nss_sss.c b/src/back-sch-nss_sss.c +index 2b1b8b0..5ee911e 100644 +--- a/src/back-sch-nss_sss.c ++++ b/src/back-sch-nss_sss.c +@@ -32,232 +32,245 @@ + #include + #include + #include ++#include + #include "back-sch-nss.h" + + struct nss_ops_ctx { +- void *dl_handle; +- long int initgroups_start; +- +- enum nss_status (*getpwnam_r)(const char *name, struct passwd *result, +- char *buffer, size_t buflen, int *errnop); +- enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result, +- char *buffer, size_t buflen, int *errnop); +- enum nss_status (*getgrnam_r)(const char *name, struct group *result, +- char *buffer, size_t buflen, int *errnop); +- enum nss_status (*getgrgid_r)(gid_t gid, struct group *result, +- char *buffer, size_t buflen, int *errnop); +- enum nss_status (*initgroups_dyn)(const char *user, gid_t group, +- long int *start, long int *size, +- gid_t **groups, long int limit, +- int *errnop); ++ void *dl_handle; ++ long int initgroups_start; ++ ++ enum nss_status (*getpwnam_r)(const char *name, struct passwd *result, ++ char *buffer, size_t buflen, int *errnop); ++ enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result, ++ char *buffer, size_t buflen, int *errnop); ++ enum nss_status (*getgrnam_r)(const char *name, struct group *result, ++ char *buffer, size_t buflen, int *errnop); ++ enum nss_status (*getgrgid_r)(gid_t gid, struct group *result, ++ char *buffer, size_t buflen, int *errnop); ++ enum nss_status (*initgroups_dyn)(const char *user, gid_t group, ++ long int *start, long int *size, ++ gid_t **groups, long int limit, ++ int *errnop); + }; + + void backend_nss_free_context(struct nss_ops_ctx **nss_context) + { +- if (nss_context == NULL) { +- return; +- } ++ if ((nss_context == NULL) || (*nss_context == NULL)) { ++ return; ++ } + +- if ((*nss_context)->dl_handle != NULL) { +- dlclose((*nss_context)->dl_handle); +- } ++ if ((*nss_context)->dl_handle != NULL) { ++ dlclose((*nss_context)->dl_handle); ++ } + +- free((*nss_context)); +- *nss_context = NULL; ++ free((*nss_context)); ++ *nss_context = NULL; + } + +-void backend_nss_init_context(struct nss_ops_ctx **nss_context) ++int backend_nss_init_context(struct nss_ops_ctx **nss_context) + { +- struct nss_ops_ctx *ctx = NULL; +- +- if (nss_context == NULL) { +- return; +- } +- +- ctx = calloc(1, sizeof(struct nss_ops_ctx)); +- +- *nss_context = ctx; +- if (ctx == NULL) { +- return; +- } +- +- ctx->dl_handle = dlopen("libnss_sss.so.2", RTLD_NOW); +- if (ctx->dl_handle == NULL) { +- goto fail; +- } +- +- ctx->getpwnam_r = dlsym(ctx->dl_handle, "_nss_sss_getpwnam_r"); +- if (ctx->getpwnam_r == NULL) { +- goto fail; +- } +- +- ctx->getpwuid_r = dlsym(ctx->dl_handle, "_nss_sss_getpwuid_r"); +- if (ctx->getpwuid_r == NULL) { +- goto fail; +- } +- +- ctx->getgrnam_r = dlsym(ctx->dl_handle, "_nss_sss_getgrnam_r"); +- if (ctx->getgrnam_r == NULL) { +- goto fail; +- } +- +- ctx->getgrgid_r = dlsym(ctx->dl_handle, "_nss_sss_getgrgid_r"); +- if (ctx->getgrgid_r == NULL) { +- goto fail; +- } +- +- ctx->initgroups_dyn = dlsym(ctx->dl_handle, "_nss_sss_initgroups_dyn"); +- if (ctx->initgroups_dyn == NULL) { +- goto fail; +- } +- +- return; ++ struct nss_ops_ctx *ctx = NULL; ++ ++ if (nss_context == NULL) { ++ return EINVAL; ++ } ++ ++ ctx = calloc(1, sizeof(struct nss_ops_ctx)); ++ if (ctx == NULL) { ++ return ENOMEM; ++ } ++ *nss_context = ctx; ++ ++ ctx->dl_handle = dlopen("libnss_sss.so.2", RTLD_NOW); ++ if (ctx->dl_handle == NULL) { ++ goto fail; ++ } ++ ++ ctx->getpwnam_r = dlsym(ctx->dl_handle, "_nss_sss_getpwnam_r"); ++ if (ctx->getpwnam_r == NULL) { ++ goto fail; ++ } ++ ++ ctx->getpwuid_r = dlsym(ctx->dl_handle, "_nss_sss_getpwuid_r"); ++ if (ctx->getpwuid_r == NULL) { ++ goto fail; ++ } ++ ++ ctx->getgrnam_r = dlsym(ctx->dl_handle, "_nss_sss_getgrnam_r"); ++ if (ctx->getgrnam_r == NULL) { ++ goto fail; ++ } ++ ++ ctx->getgrgid_r = dlsym(ctx->dl_handle, "_nss_sss_getgrgid_r"); ++ if (ctx->getgrgid_r == NULL) { ++ goto fail; ++ } ++ ++ ctx->initgroups_dyn = dlsym(ctx->dl_handle, "_nss_sss_initgroups_dyn"); ++ if (ctx->initgroups_dyn == NULL) { ++ goto fail; ++ } ++ ++ return 0; + + fail: +- backend_nss_free_context(nss_context); ++ backend_nss_free_context(nss_context); + +- return; ++ return EINVAL; + } + + + /* Following three functions cannot be implemented with nss_sss.so.2 + * As result, we simply do nothing here */ + +-void backend_nss_set_timeout(struct nss_ops_ctx **nss_context, +- unsigned int timeout) { +- /* no operation */ ++void backend_nss_set_timeout(struct nss_ops_ctx *nss_context, ++ unsigned int timeout) { ++ /* no operation */ + } + +-void backend_nss_evict_user(struct nss_ops_ctx **nss_context, +- const char *name) { +- /* no operation */ ++void backend_nss_evict_user(struct nss_ops_ctx *nss_context, ++ const char *name) { ++ /* no operation */ + } + +-void backend_nss_evict_group(struct nss_ops_ctx **nss_context, +- const char *name) { +- /* no operation */ ++void backend_nss_evict_group(struct nss_ops_ctx *nss_context, ++ const char *name) { ++ /* no operation */ + } + + enum nss_status backend_nss_getpwnam(struct nss_ops_ctx *nss_context, +- const char *name, struct passwd *pwd, +- char *buffer, size_t buflen, +- struct passwd **result, +- int *lerrno) { +- enum nss_status ret; +- +- if (nss_context == NULL) { +- return NSS_STATUS_UNAVAIL; +- } +- +- ret = (enum nss_status) +- nss_context->getpwnam_r(name, pwd, +- buffer, buflen, +- lerrno); +- +- if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) { +- *result = pwd; +- } +- +- return ret; ++ const char *name, struct passwd *pwd, ++ char *buffer, size_t buflen, ++ struct passwd **result, ++ int *lerrno) { ++ enum nss_status ret; ++ ++ if (nss_context == NULL) { ++ return NSS_STATUS_UNAVAIL; ++ } ++ ++ ret = nss_context->getpwnam_r(name, pwd, ++ buffer, buflen, ++ lerrno); ++ ++ if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) { ++ *result = pwd; ++ *lerrno = 0; ++ } ++ ++ return ret; + } + + enum nss_status backend_nss_getpwuid(struct nss_ops_ctx *nss_context, +- uid_t uid, struct passwd *pwd, +- char *buffer, size_t buflen, +- struct passwd **result, +- int *lerrno) { +- enum nss_status ret; +- +- if (nss_context == NULL) { +- return NSS_STATUS_UNAVAIL; +- } +- +- ret = (enum nss_status) +- nss_context->getpwuid_r(uid, pwd, +- buffer, buflen, +- lerrno); +- +- if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) { +- *result = pwd; +- } +- +- return ret; ++ uid_t uid, struct passwd *pwd, ++ char *buffer, size_t buflen, ++ struct passwd **result, ++ int *lerrno) { ++ enum nss_status ret; ++ ++ if (nss_context == NULL) { ++ return NSS_STATUS_UNAVAIL; ++ } ++ ++ ret = nss_context->getpwuid_r(uid, pwd, ++ buffer, buflen, ++ lerrno); ++ ++ if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) { ++ *result = pwd; ++ *lerrno = 0; ++ } ++ ++ return ret; + } + + enum nss_status backend_nss_getgrnam(struct nss_ops_ctx *nss_context, +- const char *name, struct group *grp, +- char *buffer, size_t buflen, +- struct group **result, +- int *lerrno) { +- enum nss_status ret; +- +- if (nss_context == NULL) { +- return NSS_STATUS_UNAVAIL; +- } +- +- ret = (enum nss_status) +- nss_context->getgrnam_r(name, grp, +- buffer, buflen, +- lerrno); +- +- if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) { +- *result = grp; +- } +- +- return ret; ++ const char *name, struct group *grp, ++ char *buffer, size_t buflen, ++ struct group **result, ++ int *lerrno) { ++ enum nss_status ret; ++ ++ if (nss_context == NULL) { ++ return NSS_STATUS_UNAVAIL; ++ } ++ ++ ret = nss_context->getgrnam_r(name, grp, ++ buffer, buflen, ++ lerrno); ++ ++ if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) { ++ *result = grp; ++ *lerrno = 0; ++ } ++ ++ return ret; + } + + enum nss_status backend_nss_getgrgid(struct nss_ops_ctx *nss_context, +- gid_t gid, struct group *grp, +- char *buffer, size_t buflen, +- struct group **result, +- int *lerrno) { ++ gid_t gid, struct group *grp, ++ char *buffer, size_t buflen, ++ struct group **result, ++ int *lerrno) { + +- enum nss_status ret; ++ enum nss_status ret; + +- if (nss_context == NULL) { +- return NSS_STATUS_UNAVAIL; +- } ++ if (nss_context == NULL) { ++ return NSS_STATUS_UNAVAIL; ++ } + +- ret = (enum nss_status) +- nss_context->getgrgid_r(gid, grp, +- buffer, buflen, +- lerrno); ++ ret = nss_context->getgrgid_r(gid, grp, ++ buffer, buflen, ++ lerrno); + +- if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) { +- *result = grp; +- } ++ if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) { ++ *result = grp; ++ *lerrno = 0; ++ } + +- return ret; ++ return ret; + } + + enum nss_status backend_nss_getgrouplist(struct nss_ops_ctx *nss_context, +- const char *name, gid_t group, +- gid_t *groups, int *ngroups, +- int *lerrno) { ++ const char *name, gid_t group, ++ gid_t *groups, int *ngroups, ++ int *lerrno) { ++ ++ enum nss_status ret = NSS_STATUS_UNAVAIL; ++ long int tsize = MAX (1, *ngroups); ++ gid_t *newgroups = NULL; ++ ++ if (nss_context == NULL) { ++ return NSS_STATUS_UNAVAIL; ++ } ++ ++ newgroups = (gid_t *) calloc (tsize, sizeof (gid_t)); ++ if (newgroups == NULL) { ++ *lerrno = ENOMEM; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ ++ newgroups[0] = group; ++ nss_context->initgroups_start = 1; + +- enum nss_status ret = NSS_STATUS_UNAVAIL; +- long int size = 0; ++ ret = nss_context->initgroups_dyn(name, group, ++ &nss_context->initgroups_start, ++ &tsize, &newgroups, ++ -1, lerrno); + +- if (nss_context == NULL) { +- return NSS_STATUS_UNAVAIL; +- } ++ (void) memcpy(groups, newgroups, ++ MIN(*ngroups, nss_context->initgroups_start) * sizeof(gid_t)); ++ free(newgroups); + +- if (nss_context->initgroups_start == 0) { +- groups[0] = group; +- nss_context->initgroups_start++; +- } ++ if (*ngroups < nss_context->initgroups_start) { ++ ret = NSS_STATUS_TRYAGAIN; ++ *lerrno = ERANGE; ++ } + +- ret = nss_context->initgroups_dyn(name, group, +- &nss_context->initgroups_start, +- &size, &groups, +- -1, lerrno); +- if (ret == NSS_STATUS_SUCCESS) { +- nss_context->initgroups_start = 0; +- } ++ *ngroups = (int) nss_context->initgroups_start; + +- *ngroups = (int) size; ++ nss_context->initgroups_start = 0; + +- return ret; ++ return ret; + } + +diff --git a/src/back-sch-sss_idmap.c b/src/back-sch-sss_idmap.c +index 6a31267..452ff4f 100644 +--- a/src/back-sch-sss_idmap.c ++++ b/src/back-sch-sss_idmap.c +@@ -38,202 +38,223 @@ + #include + + struct nss_ops_ctx { +- unsigned int timeout; ++ unsigned int timeout; + }; + + static enum nss_status __convert_sss_nss2nss_status(int errcode) { +- enum nss_status ret = NSS_STATUS_UNAVAIL; +- +- if (errcode == 0) { +- ret = NSS_STATUS_SUCCESS; +- } else if (errcode == ENOENT) { +- ret = NSS_STATUS_NOTFOUND; +- } else if(errcode == ERANGE) { +- ret = NSS_STATUS_TRYAGAIN; +- } else if(errcode == ETIMEDOUT) { +- ret = NSS_STATUS_UNAVAIL; +- } else if(errcode == ETIME) { +- ret = NSS_STATUS_TRYAGAIN; +- }; +- +- return ret; ++ switch(errcode) { ++ case 0: ++ return NSS_STATUS_SUCCESS; ++ case ENOENT: ++ return NSS_STATUS_NOTFOUND; ++ case ETIME: ++ /* fall-through */ ++ case ERANGE: ++ return NSS_STATUS_TRYAGAIN; ++ case ETIMEDOUT: ++ /* fall-through */ ++ default: ++ return NSS_STATUS_UNAVAIL; ++ } ++ return NSS_STATUS_UNAVAIL; + } + +-void backend_nss_init_context(struct nss_ops_ctx **nss_context) ++int backend_nss_init_context(struct nss_ops_ctx **nss_context) + { +- struct nss_ops_ctx *ctx = NULL; ++ struct nss_ops_ctx *ctx = NULL; + +- if (nss_context == NULL) { +- return; +- } ++ if (nss_context == NULL) { ++ return EINVAL; ++ } + +- ctx = calloc(1, sizeof(struct nss_ops_ctx)); ++ ctx = calloc(1, sizeof(struct nss_ops_ctx)); + +- *nss_context = ctx; ++ if (ctx == NULL) { ++ return ENOMEM; ++ } ++ *nss_context = ctx; ++ return 0; + } + + void backend_nss_free_context(struct nss_ops_ctx **nss_context) + { +- if (nss_context == NULL) { +- return; +- } ++ if ((nss_context == NULL) || (*nss_context == NULL)) { ++ return; ++ } + +- free((*nss_context)); +- *nss_context = NULL; ++ free((*nss_context)); ++ *nss_context = NULL; + } + + + void backend_nss_set_timeout(struct nss_ops_ctx *nss_context, +- unsigned int timeout) { +- if (nss_context == NULL) { +- return; +- } ++ unsigned int timeout) { ++ if (nss_context == NULL) { ++ return; ++ } + +- nss_context->timeout = timeout; ++ nss_context->timeout = timeout; + } + +-/* TODO: handle buffers and memory allocation in this function */ + void backend_nss_evict_user(struct nss_ops_ctx *nss_context, +- const char *name) { +- if (nss_context == NULL) { +- return; +- } +- +- (void) sss_nss_getpwnam_timeout(name, NULL, +- NULL, 0, +- NULL, +- SSS_NSS_EX_FLAG_INVALIDATE_CACHE, +- nss_context->timeout); ++ const char *name) { ++ if (nss_context == NULL) { ++ return; ++ } ++ ++ (void) sss_nss_getpwnam_timeout(name, NULL, ++ NULL, 0, ++ NULL, ++ SSS_NSS_EX_FLAG_INVALIDATE_CACHE, ++ nss_context->timeout); + } + +-/* TODO: handle buffers and memory allocation in this function */ + void backend_nss_evict_group(struct nss_ops_ctx *nss_context, +- const char *name) { +- if (nss_context == NULL) { +- return; +- } +- +- (void) sss_nss_getgrnam_timeout(name, NULL, +- NULL, 0, +- NULL, +- SSS_NSS_EX_FLAG_INVALIDATE_CACHE, +- nss_context->timeout); ++ const char *name) { ++ if (nss_context == NULL) { ++ return; ++ } ++ ++ (void) sss_nss_getgrnam_timeout(name, NULL, ++ NULL, 0, ++ NULL, ++ SSS_NSS_EX_FLAG_INVALIDATE_CACHE, ++ nss_context->timeout); + } + + enum nss_status backend_nss_getpwnam(struct nss_ops_ctx *nss_context, +- const char *name, struct passwd *pwd, +- char *buffer, size_t buflen, +- struct passwd **result, +- int *lerrno) { +- int ret = 0; +- +- if (nss_context == NULL) { +- return NSS_STATUS_UNAVAIL; +- } +- +- ret = sss_nss_getpwnam_timeout(name, pwd, +- buffer, buflen, +- result, +- SSS_NSS_EX_FLAG_NO_FLAGS, +- nss_context->timeout); +- +- if (ret != 0 && lerrno != NULL) { +- /* SSSD translates errno into return code */ +- *lerrno = ret; +- } +- return __convert_sss_nss2nss_status(ret); ++ const char *name, struct passwd *pwd, ++ char *buffer, size_t buflen, ++ struct passwd **result, ++ int *lerrno) { ++ int ret = 0; ++ ++ if (nss_context == NULL) { ++ return NSS_STATUS_UNAVAIL; ++ } ++ ++ ret = sss_nss_getpwnam_timeout(name, pwd, ++ buffer, buflen, ++ result, ++ SSS_NSS_EX_FLAG_NO_FLAGS, ++ nss_context->timeout); ++ ++ /* SSSD uses the same infrastructure to handle sss_nss_get* calls ++ * as nss_sss.so.2 module where 'int *errno' is passed to the helper ++ * but writes down errno into return code so we propagate it in case ++ * of error and translate the return code */ ++ if (lerrno != NULL) { ++ *lerrno = ret; ++ } ++ return __convert_sss_nss2nss_status(ret); + } + + enum nss_status backend_nss_getpwuid(struct nss_ops_ctx *nss_context, +- uid_t uid, struct passwd *pwd, +- char *buffer, size_t buflen, +- struct passwd **result, +- int *lerrno) { +- +- int ret = 0; +- +- if (nss_context == NULL) { +- return NSS_STATUS_UNAVAIL; +- } +- +- ret = sss_nss_getpwuid_timeout(uid, pwd, +- buffer, buflen, +- result, +- SSS_NSS_EX_FLAG_NO_FLAGS, +- nss_context->timeout); +- if (ret != 0 && lerrno != NULL) { +- /* SSSD translates errno into return code */ +- *lerrno = ret; +- } +- return __convert_sss_nss2nss_status(ret); ++ uid_t uid, struct passwd *pwd, ++ char *buffer, size_t buflen, ++ struct passwd **result, ++ int *lerrno) { ++ ++ int ret = 0; ++ ++ if (nss_context == NULL) { ++ return NSS_STATUS_UNAVAIL; ++ } ++ ++ ret = sss_nss_getpwuid_timeout(uid, pwd, ++ buffer, buflen, ++ result, ++ SSS_NSS_EX_FLAG_NO_FLAGS, ++ nss_context->timeout); ++ ++ /* SSSD uses the same infrastructure to handle sss_nss_get* calls ++ * as nss_sss.so.2 module where 'int *errno' is passed to the helper ++ * but writes down errno into return code so we propagate it in case ++ * of error and translate the return code */ ++ if (lerrno != NULL) { ++ *lerrno = ret; ++ } ++ return __convert_sss_nss2nss_status(ret); + } + + enum nss_status backend_nss_getgrnam(struct nss_ops_ctx *nss_context, +- const char *name, struct group *grp, +- char *buffer, size_t buflen, +- struct group **result, +- int *lerrno) { +- +- int ret = 0; +- +- if (nss_context == NULL) { +- return NSS_STATUS_UNAVAIL; +- } +- +- ret = sss_nss_getgrnam_timeout(name, grp, +- buffer, buflen, +- result, +- SSS_NSS_EX_FLAG_NO_FLAGS, +- nss_context->timeout); +- if (ret != 0 && lerrno != NULL) { +- /* SSSD translates errno into return code */ +- *lerrno = ret; +- } +- return __convert_sss_nss2nss_status(ret); ++ const char *name, struct group *grp, ++ char *buffer, size_t buflen, ++ struct group **result, ++ int *lerrno) { ++ ++ int ret = 0; ++ ++ if (nss_context == NULL) { ++ return NSS_STATUS_UNAVAIL; ++ } ++ ++ ret = sss_nss_getgrnam_timeout(name, grp, ++ buffer, buflen, ++ result, ++ SSS_NSS_EX_FLAG_NO_FLAGS, ++ nss_context->timeout); ++ ++ /* SSSD uses the same infrastructure to handle sss_nss_get* calls ++ * as nss_sss.so.2 module where 'int *errno' is passed to the helper ++ * but writes down errno into return code so we propagate it in case ++ * of error and translate the return code */ ++ if (lerrno != NULL) { ++ *lerrno = ret; ++ } ++ return __convert_sss_nss2nss_status(ret); + } + + enum nss_status backend_nss_getgrgid(struct nss_ops_ctx *nss_context, +- gid_t gid, struct group *grp, +- char *buffer, size_t buflen, +- struct group **result, +- int *lerrno) { +- +- int ret = 0; +- +- if (nss_context == NULL) { +- return NSS_STATUS_UNAVAIL; +- } +- +- ret = sss_nss_getgrgid_timeout(gid, grp, +- buffer, buflen, +- result, +- SSS_NSS_EX_FLAG_NO_FLAGS, +- nss_context->timeout); +- if (ret != 0 && lerrno != NULL) { +- /* SSSD translates errno into return code */ +- *lerrno = ret; +- } +- return __convert_sss_nss2nss_status(ret); ++ gid_t gid, struct group *grp, ++ char *buffer, size_t buflen, ++ struct group **result, ++ int *lerrno) { ++ ++ int ret = 0; ++ ++ if (nss_context == NULL) { ++ return NSS_STATUS_UNAVAIL; ++ } ++ ++ ret = sss_nss_getgrgid_timeout(gid, grp, ++ buffer, buflen, ++ result, ++ SSS_NSS_EX_FLAG_NO_FLAGS, ++ nss_context->timeout); ++ ++ /* SSSD uses the same infrastructure to handle sss_nss_get* calls ++ * as nss_sss.so.2 module where 'int *errno' is passed to the helper ++ * but writes down errno into return code so we propagate it in case ++ * of error and translate the return code */ ++ if (lerrno != NULL) { ++ *lerrno = ret; ++ } ++ return __convert_sss_nss2nss_status(ret); + } + + enum nss_status backend_nss_getgrouplist(struct nss_ops_ctx *nss_context, +- const char *name, gid_t group, +- gid_t *groups, int *ngroups, +- int *lerrno) { +- int ret = 0; +- +- if (nss_context == NULL) { +- return NSS_STATUS_UNAVAIL; +- } +- +- ret = sss_nss_getgrouplist_timeout(name, group, +- groups, ngroups, +- SSS_NSS_EX_FLAG_NO_FLAGS, +- nss_context->timeout); +- if (ret != 0 && lerrno != NULL) { +- /* SSSD translates errno into return code */ +- *lerrno = ret; +- } +- return __convert_sss_nss2nss_status(ret); ++ const char *name, gid_t group, ++ gid_t *groups, int *ngroups, ++ int *lerrno) { ++ int ret = 0; ++ ++ if (nss_context == NULL) { ++ return NSS_STATUS_UNAVAIL; ++ } ++ ++ ret = sss_nss_getgrouplist_timeout(name, group, ++ groups, ngroups, ++ SSS_NSS_EX_FLAG_NO_FLAGS, ++ nss_context->timeout); ++ ++ /* SSSD uses the same infrastructure to handle sss_nss_get* calls ++ * as nss_sss.so.2 module where 'int *errno' is passed to the helper ++ * but writes down errno into return code so we propagate it in case ++ * of error and translate the return code */ ++ if (lerrno != NULL) { ++ *lerrno = ret; ++ } ++ return __convert_sss_nss2nss_status(ret); + } + +diff --git a/src/back-sch.h b/src/back-sch.h +index 483e288..2d73f34 100644 +--- a/src/back-sch.h ++++ b/src/back-sch.h +@@ -154,13 +154,13 @@ int backend_analyze_search_filter(Slapi_Filter *filter, struct backend_search_fi + /* NSS backend operations implemented using either nss_sss.so.2 or libsss_nss_idmap API */ + struct nss_ops_ctx; + +-void backend_nss_init_context(struct nss_ops_ctx **nss_context); ++int backend_nss_init_context(struct nss_ops_ctx **nss_context); + void backend_nss_free_context(struct nss_ops_ctx **nss_context); +-void backend_nss_set_timeout(struct nss_ops_ctx **nss_context, ++void backend_nss_set_timeout(struct nss_ops_ctx *nss_context, + unsigned int timeout); +-void backend_nss_evict_user(struct nss_ops_ctx **nss_context, ++void backend_nss_evict_user(struct nss_ops_ctx *nss_context, + const char *name); +-void backend_nss_evict_group(struct nss_ops_ctx **nss_context, ++void backend_nss_evict_group(struct nss_ops_ctx *nss_context, + const char *name); + + void backend_search_nsswitch(struct backend_set_data *set_data, +diff --git a/src/plug-sch.c b/src/plug-sch.c +index 6ee4042..0c20a07 100644 +--- a/src/plug-sch.c ++++ b/src/plug-sch.c +@@ -105,27 +105,33 @@ plugin_startup(Slapi_PBlock *pb) + Slapi_Entry *plugin_entry = NULL; + Slapi_DN *pluginsdn = NULL; + unsigned int nss_timeout = 10000; ++ int ret = 0; + + slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state); + slapi_pblock_get(pb, SLAPI_TARGET_SDN, &pluginsdn); + /* plugin base need to be duplicated because it will be destroyed + * when pblock is destroyed but we need to use it in a separate thread */ + if (NULL == pluginsdn || 0 == slapi_sdn_get_ndn_len(pluginsdn)) { +- slapi_log_error(SLAPI_LOG_FATAL, state->plugin_desc->spd_id, +- "scheman compat plugin_startup: unable to retrieve plugin DN\n"); +- return -1; +- +- } else { +- state->plugin_base = slapi_ch_strdup(slapi_sdn_get_dn(pluginsdn)); +- slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, +- "configuration entry is %s%s%s\n", +- state->plugin_base ? "\"" : "", +- state->plugin_base ? state->plugin_base : "NULL", +- state->plugin_base ? "\"" : ""); +- } ++ slapi_log_error(SLAPI_LOG_FATAL, state->plugin_desc->spd_id, ++ "scheman compat plugin_startup: unable to retrieve plugin DN\n"); ++ return -1; ++ } else { ++ state->plugin_base = slapi_ch_strdup(slapi_sdn_get_dn(pluginsdn)); ++ slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, ++ "configuration entry is %s%s%s\n", ++ state->plugin_base ? "\"" : "", ++ state->plugin_base ? state->plugin_base : "NULL", ++ state->plugin_base ? "\"" : ""); ++ } + + state->pam_lock = wrap_new_rwlock(); +- backend_nss_init_context((struct nss_ops_ctx**) &state->nss_context); ++ ret = backend_nss_init_context((struct nss_ops_ctx**) &state->nss_context); ++ if (ret != 0) { ++ slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, ++ "failed to intiialize nsswitch backend: [%d]!\n", ++ ret); ++ return -1; ++ } + if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) && + (plugin_entry != NULL)) { + state->use_entry_cache = backend_shr_get_vattr_boolean(state, plugin_entry, +-- +2.14.3 + diff --git a/SOURCES/slapi-0020-Use-extended-SSSD-API-to-signal-that-an-entry-should.patch b/SOURCES/slapi-0020-Use-extended-SSSD-API-to-signal-that-an-entry-should.patch new file mode 100644 index 0000000..f91c79d --- /dev/null +++ b/SOURCES/slapi-0020-Use-extended-SSSD-API-to-signal-that-an-entry-should.patch @@ -0,0 +1,43 @@ +From 4cd8ef26ceb3f28d103d9b8381b025d9d3f087e5 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Thu, 7 Dec 2017 12:41:15 +0200 +Subject: [PATCH] Use extended SSSD API to signal that an entry should not be + cached anymore + +When ID override is changed, we remove affected entry from the schema +compat subtrees. However, we should also signal to SSSD that ID override +did change and thus SSSD should stop caching the entry. As result, next +look up of the affected entry should cause a refresh of the data in +SSSD. + +This is important for cases when group membership changes for AD users. +--- + src/back-sch.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/src/back-sch.c b/src/back-sch.c +index 1998765..4612051 100644 +--- a/src/back-sch.c ++++ b/src/back-sch.c +@@ -2207,6 +2207,18 @@ backend_entry_evict_if_related(const char *group, const char *set, bool_t flag, + + /* An entry corresponding to our target is found, evict it */ + map_data_unset_entry(state, group, set, id); ++ ++ /* Signal to SSSD that this entry is not cached anymore */ ++ switch(set_data->check_nsswitch) { ++ case SCH_NSSWITCH_USER: ++ backend_nss_evict_user(state->nss_context, original_uid); ++ break; ++ case SCH_NSSWITCH_GROUP: ++ backend_nss_evict_group(state->nss_context, original_uid); ++ break; ++ default: ++ break; ++ } + } + + slapi_ch_free_string(&id); +-- +2.14.3 + diff --git a/SPECS/slapi-nis.spec b/SPECS/slapi-nis.spec index 6b79862..ca86aee 100644 --- a/SPECS/slapi-nis.spec +++ b/SPECS/slapi-nis.spec @@ -11,7 +11,7 @@ Name: slapi-nis Version: 0.56.0 -Release: 4%{?dist} +Release: 8%{?dist} Summary: NIS Server and Schema Compatibility plugins for Directory Server Group: System Environment/Daemons License: GPLv2 @@ -22,14 +22,27 @@ Patch1: slapi-0001-Move-advance-definition-of-backend_passwdmod_extop-b.patch Patch2: slapi-0002-Initialize-ret-before-use.patch Patch3: slapi-0003-slapi-nis-resolve-IPA-groups-with-fully-qualified-su.patch Patch4: slapi-0004-Declare-int-backend_init_extop-for-reuse-in-plug-sch.patch +Patch5: slapi-0005-Double-free-on-ldap-entry-during-priming.patch Patch6: slapi-0006-back-sch-do-not-clobber-target-of-the-pblock-for-idv.patch Patch7: slapi-0007-back-sch-nss-for-users-with-aliases-return-alias-as-.patch +Patch11: slapi-0011-Move-a-helper-to-build-DN-to-a-format.c.patch +Patch12: slapi-0012-Add-dummy-handler-for-a-related-add-delete-modify-to.patch +Patch13: slapi-0013-track-changes-to-ID-overrides-and-evict-map-cache-en.patch +Patch15: slapi-0015-configure.ac-detect-extended-NSS-API-provided-by-SSS.patch +Patch16: slapi-0016-schema-compat-add-support-for-timeout-based-NSS-quer.patch +Patch17: slapi-0017-back-sch-cancel-memberof-retrieval-in-case-of-a-dirs.patch +Patch18: slapi-0017-Fix-nss_sss-callers.patch +Patch19: slapi-0018-Clean-up-unused-code.patch +Patch20: slapi-0019-Synchronize-nsswitch-backend-code-with-freeIPA.patch +Patch21: slapi-0020-Use-extended-SSSD-API-to-signal-that-an-entry-should.patch + BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +BuildRequires: libtool, automake, autoconf BuildRequires: 389-ds-base-devel >= 1.3.5.6, %{ldap_impl}-devel BuildRequires: nspr-devel, nss-devel, /usr/bin/rpcgen %if 0%{?fedora} > 18 || 0%{?rhel} > 6 -BuildRequires: libsss_nss_idmap-devel +BuildRequires: libsss_nss_idmap-devel >= 1.16.0-11 %define sss_nss_opts --with-sss-nss-idmap %else %define sss_nss_opts %{nil} @@ -47,6 +60,9 @@ BuildRequires: libtirpc-devel ExclusiveArch: x86_64 %{ix86} %endif Requires: 389-ds-base >= 1.3.5.6 +%if 0%{?fedora} > 18 || 0%{?rhel} > 6 +Requires: libsss_nss_idmap >= 1.16.0-11 +%endif %description This package provides two plugins for Red Hat and 389 Directory Server. @@ -67,11 +83,26 @@ for attributes from multiple entries in the tree. %patch2 -p1 %patch3 -p1 %patch4 -p1 -# patch 5 is part of patch 3 +%patch5 -p1 %patch6 -p1 %patch7 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 +%patch20 -p1 +%patch21 -p1 %build +libtoolize -f -c +aclocal --force -I m4 +autoheader +automake -f -a -i +autoconf -f -i %configure --disable-static --with-tcp-wrappers --with-ldap=%{ldap_impl} \ --with-nsswitch --with-pam --with-pam-service=system-auth \ %{sss_nss_opts} %{betxn_opts} @@ -100,6 +131,27 @@ rm -rf $RPM_BUILD_ROOT %{_sbindir}/nisserver-plugin-defs %changelog +* Fri Dec 08 2017 Alexander Bokovoy - 0.56.0-8 +- Fixed: #1473572 +- Changes of ID overrides now force clearing of affected SSSD cache entries on IPA master +- Related: #1473577 +- Synchronize timeout-enabled code with ipa-extdom-extop + +* Mon Nov 06 2017 Alexander Bokovoy - 0.56.0-7 +- Related: #1473577 +- Force at least SSSD 1.16.0-3 for timeout-enabled NSS API + +* Fri Nov 03 2017 Alexander Bokovoy - 0.56.0-6 +- Related: #1473577 +- Update configure and make files over the old release +- Fix nss_sss usage + +* Fri Nov 03 2017 Alexander Bokovoy - 0.56.0-5 +- Resolves: #1473572 +- Fixed: Make changes in overrides available in the compat tree at runtime +- Resolves: #1473577 +- Fixed: slapi-nis should use requests to SSSD with ability to cancel them with a timeout + * Tue Aug 09 2016 Alexander Bokovoy - 0.56.0-4 - Fixed: UPN-based search for AD users does not match an entry in slapi-nis map cache - Resolves: #1361123