[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#781793: unblock: slapi-nis/0.54.2-1



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Please unblock package slapi-nis

This upload fixed bug #781346 (CVE-2015-0283), and upstream said
that all commits between 0.54.1 and .2 were needed for it (though I see now that there's one for rhel builds).
0.54.1 itself was just two commits:

c9c9d1413a69503 schema-compat: support ID overrides in bind callback
778c95866f28d89 ID views: ignore searches for views outside the subtrees of schema-compat sets

both of which are for a new feature in freeipa 4.1.x (ID views), which is not even in experimental yet. The other option would be to drop slapi-nis from jessie, as it doesn't have any reverse deps there.

diff:

diff --git a/configure.ac b/configure.ac
index 59fa6e5..ae626de 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT(slapi-nis,0.54)
+AC_INIT(slapi-nis,0.54.2)
 AC_CONFIG_MACRO_DIR([m4])
 AM_INIT_AUTOMAKE(foreign)
 LT_INIT([disable-static])
@@ -343,6 +343,7 @@ fi
 AM_CONDITIONAL([USE_PAM], [test "x$use_pam" != xno])
 
 if test "x$use_nsswitch" != xno ; then
+       AC_CHECK_HEADERS([stdint.h nss.h dlfcn.h])
        if pkg-config sss_nss_idmap 2> /dev/null ; then
                if test x$use_sss_nss_idmap != xno ; then
                        AC_DEFINE(HAVE_SSS_NSS_IDMAP,1,[Define if you have libsss_nss_idmap.])
diff --git a/debian/changelog b/debian/changelog
index f037e9e..9d0dbd0 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+slapi-nis (0.54.2-1) unstable; urgency=medium
+
+  * New upstream bugfix release
+    - CVE-2015-0283: infinite loop in getgrnam_r() and getgrgid_r()
+      (Closes: #781346)
+
+ -- Timo Aaltonen <tjaalton@debian.org>  Thu, 02 Apr 2015 09:24:07 +0300
+
 slapi-nis (0.54-1) unstable; urgency=medium
 
   * New upstream release.
diff --git a/doc/ipa/sch-ipa.txt b/doc/ipa/sch-ipa.txt
index f560580..106e6cc 100644
--- a/doc/ipa/sch-ipa.txt
+++ b/doc/ipa/sch-ipa.txt
@@ -47,6 +47,11 @@ Plugin allows to expose users and groups from trusted domains. These users
 and groups are available on the compatibility trees and can be used for
 querying their attributes and authenticating against them.
 
+Schema Compatibility Plugin relies on SSSD to discover users from trusted
+domains. NSS module provided by SSSD (libnss_sss.so.2) is loaded explicitly by
+Schema Compatibility Plugin and all calls are directed to SSSD instead of using
+generic NSSWITCH API.
+
 Additionally, authentication against IPA users is also supported, provided
 that the Schema Compatibility Plugin is given an ordering preference in
 the Directory Server configuration. By default, all Directory server plugins
@@ -70,10 +75,11 @@ schema-compat-nsswitch-min-id: <value>
 specifies that the minimal numeric id of the user or group should be not less
 than the value. Defaults to 1000.
 
-When FreeIPA 3.3 is in use, ipa-adtrust-install utility will automatically configure
-the Schema Compatibility Plugin to allow serving users and groups from trusted domains.
-No additional configuration is needed. ipa-adtrust-install, however, will not set the
-minimal numeric id for user or group.
+When FreeIPA 3.3 or later is in use, ipa-adtrust-install utility will
+automatically configure the Schema Compatibility Plugin to allow serving users
+and groups from trusted domains. No additional configuration is needed.
+ipa-adtrust-install, however, will not set the minimal numeric id for user or
+group.
 
 == Authentication of the trusted domains' users ==
 
diff --git a/slapi-nis.spec b/slapi-nis.spec
index 21935ca..f0c2647 100644
--- a/slapi-nis.spec
+++ b/slapi-nis.spec
@@ -10,7 +10,7 @@
 %endif
 
 Name:          slapi-nis
-Version:       0.54
+Version:       0.54.2
 Release:       1%{?dist}
 Summary:       NIS Server and Schema Compatibility plugins for Directory Server
 Group:         System Environment/Daemons
@@ -85,6 +85,15 @@ rm -rf $RPM_BUILD_ROOT
 %{_sbindir}/nisserver-plugin-defs
 
 %changelog
+* Thu Mar 26 2015 Alexander Bokovoy <abokovoy@redhat.com> - 0.54.2-1
+- CVE-2015-0283 slapi-nis: infinite loop in getgrnam_r() and getgrgid_r()
+- Make sure nss_sss.so.2 module is used directly
+- Allow building slapi-nis with ID views against 389-ds-base from RHEL7.0/CentOS7.0 releases
+
+* Thu Nov  6 2014 Alexander Bokovoy <abokovoy@redhat.com> - 0.54.1-1
+- support FreeIPA overrides in LDAP BIND callback
+- ignore FreeIPA override searchs outside configured schema compat subtrees
+
 * Fri Oct 10 2014 Alexander Bokovoy <abokovoy@redhat.com> - 0.54-1
 - Add support for FreeIPA's ID views
 - Allow searching SSSD-provided users as memberUid case-insensitevly
diff --git a/src/back-sch-idview.c b/src/back-sch-idview.c
index 5a2b450..93fbab5 100644
--- a/src/back-sch-idview.c
+++ b/src/back-sch-idview.c
@@ -157,6 +157,7 @@ idview_process_overrides(struct backend_search_cbdata *cbdata,
        /* 2. If there is indeed an override, replace attribute values except for the ones that should be ignored */
        if (override_entry != NULL) {
                Slapi_Attr  *override_attr = NULL;
+               Slapi_Attr  *sattr = NULL;
 
                result = slapi_entry_first_attr(override_entry, &override_attr);
                while (result == 0) {
@@ -173,7 +174,7 @@ idview_process_overrides(struct backend_search_cbdata *cbdata,
                        if (filterout_attrs[i] == NULL) {
                                /* Replace the attribute's value with the override or
                                 * add an override value if the attribute didn't exist */
-                               result = slapi_entry_attr_exists(entry, override_type);
+                               result = slapi_entry_attr_find(entry, override_type, &sattr);
                                if (result == 1) {
                                        result = slapi_entry_attr_delete(entry, override_type);
                                }
@@ -290,21 +291,15 @@ idview_replace_target_dn(char **target, char **idview)
        }
 }
 
-static int
-idview_process_filter_cb(Slapi_Filter *filter, const char *filter_type, struct berval *bval, struct backend_search_filter_config *config)
+int
+idview_replace_bval_by_override(const char *bval_usage, const char *attr_name,
+                               struct berval *bval, struct backend_search_cbdata *cbdata)
 {
        int res, i;
-       Slapi_Value *filter_val, *value, *anchor_val;
+       Slapi_Value *attr_val, *value, *anchor_val;
        Slapi_Attr *anchor, *attr = NULL;
-       struct backend_search_cbdata *cbdata = (struct backend_search_cbdata *) config->callback_data;
-
-       if (cbdata == NULL || cbdata->idview == NULL) {
-               return SLAPI_FILTER_SCAN_CONTINUE;
-       }
-
-       if (filter_type == NULL || config->name == NULL) {
-               return SLAPI_FILTER_SCAN_CONTINUE;
-       }
+       bool_t uid_override_found = FALSE;
+       bool_t anchor_override_found = FALSE;
 
        if (cbdata->overrides == NULL) {
                /* Only retrieve overrides for the view first time when neccessary */
@@ -312,28 +307,35 @@ idview_process_filter_cb(Slapi_Filter *filter, const char *filter_type, struct b
        }
 
        if (cbdata->overrides == NULL) {
-               return SLAPI_FILTER_SCAN_CONTINUE;
+               return 0;
        }
 
-       filter_val = slapi_value_new_berval(bval);
+       attr_val = slapi_value_new_berval(bval);
+       slapi_log_error(SLAPI_LOG_FATAL, cbdata->state->plugin_desc->spd_id,
+                       "Searching for an override of the %s %s with %s=%*s from the overrides\n.",
+                       bval_usage, attr_name, attr_name, (int) bval->bv_len, bval->bv_val);
 
        /* If filter contains an attribute name which is overridden in the view and filter value
         * corresponds to the override, replace the filter by (ipaAnchorUUID=...) from the override
         * to point to the original because otherwise an entry will not be found in the slapi-nis map */
        for(i=0; cbdata->overrides[i] != NULL; i++) {
-               res = slapi_entry_attr_find(cbdata->overrides[i], filter_type, &attr);
+               res = slapi_entry_attr_find(cbdata->overrides[i], attr_name, &attr);
                if ((res == 0) && (attr != NULL)) {
                        res = slapi_attr_first_value(attr, &value);
-                       res = slapi_value_compare(attr, value, filter_val);
+                       res = slapi_value_compare(attr, value, attr_val);
                        if (res == 0) {
                                /* For uid overrides we should have ipaOriginalUID in the override */
-                               if (strcasecmp(filter_type, "uid") == 0) {
+                               if (strcasecmp(attr_name, "uid") == 0) {
                                        res = slapi_entry_attr_find(cbdata->overrides[i], IPA_IDVIEWS_ATTR_ORIGINALUID, &anchor);
                                        if (res == 0) {
                                                res = slapi_attr_first_value(anchor, &anchor_val);
                                                slapi_ber_bvdone(bval);
                                                slapi_ber_bvcpy(bval, slapi_value_get_berval(anchor_val));
-                                               config->override_found = TRUE;
+                                               uid_override_found = TRUE;
+                                               slapi_log_error(SLAPI_LOG_FATAL, cbdata->state->plugin_desc->spd_id,
+                                                               "Overriding the %s %s with %s=%*s from the override %s\n.",
+                                                               bval_usage, attr_name, attr_name, (int) bval->bv_len, bval->bv_val,
+                                                               slapi_entry_get_dn_const(cbdata->overrides[i]));
                                                break;
                                        }
                                }
@@ -342,10 +344,14 @@ idview_process_filter_cb(Slapi_Filter *filter, const char *filter_type, struct b
                                res = slapi_entry_attr_find(cbdata->overrides[i], IPA_IDVIEWS_ATTR_ANCHORUUID, &anchor);
                                if (res == 0) {
                                        res = slapi_attr_first_value(anchor, &anchor_val);
-                                       slapi_filter_changetype(filter, IPA_IDVIEWS_ATTR_ANCHORUUID);
                                        slapi_ber_bvdone(bval);
                                        slapi_ber_bvcpy(bval, slapi_value_get_berval(anchor_val));
-                                       config->override_found = TRUE;
+                                       anchor_override_found = TRUE;
+                                       slapi_log_error(SLAPI_LOG_FATAL, cbdata->state->plugin_desc->spd_id,
+                                                       "Overriding the %s %s with %s=%*s from the override %s\n.",
+                                                       bval_usage, attr_name, IPA_IDVIEWS_ATTR_ANCHORUUID,
+                                                       (int) bval->bv_len, bval->bv_val,
+                                                       slapi_entry_get_dn_const(cbdata->overrides[i]));
                                        break;
                                }
 
@@ -353,7 +359,41 @@ idview_process_filter_cb(Slapi_Filter *filter, const char *filter_type, struct b
                }
        }
 
-       slapi_value_free(&filter_val);
+       slapi_value_free(&attr_val);
+
+       if (uid_override_found) {
+               return 1;
+       }
+
+       if (anchor_override_found) {
+               return 2;
+       }
+
+       return 0;
+}
+
+static int
+idview_process_filter_cb(Slapi_Filter *filter, const char *filter_type,
+                        struct berval *bval, struct backend_search_filter_config *config)
+{
+       int res;
+       struct backend_search_cbdata *cbdata = (struct backend_search_cbdata *) config->callback_data;
+
+       if (cbdata == NULL || cbdata->idview == NULL) {
+               return SLAPI_FILTER_SCAN_CONTINUE;
+       }
+
+       if (filter_type == NULL || config->name == NULL) {
+               return SLAPI_FILTER_SCAN_CONTINUE;
+       }
+
+       res = idview_replace_bval_by_override("filter", filter_type, bval, cbdata);
+
+       if (res == 2) {
+               slapi_filter_changetype(filter, IPA_IDVIEWS_ATTR_ANCHORUUID);
+       }
+
+       config->override_found = (res != 0);
 
        return SLAPI_FILTER_SCAN_CONTINUE;
 
@@ -366,8 +406,6 @@ idview_process_filter_cb(Slapi_Filter *filter, const char *filter_type, struct b
  *
  * Note that in reality we don't use original value of the uid/cn attribue. Instead, we use ipaAnchorUUID
  * to refer to the original entry. */
-extern char *
-slapi_filter_to_string( const struct slapi_filter *f, char *buf, size_t bufsize );
 void
 idview_replace_filter(struct backend_search_cbdata *cbdata)
 {
diff --git a/src/back-sch-nss.c b/src/back-sch-nss.c
index 12ae589..f8177d7 100644
--- a/src/back-sch-nss.c
+++ b/src/back-sch-nss.c
@@ -28,9 +28,10 @@
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
+#include <dlfcn.h>
+#include <errno.h>
 #include <pwd.h>
 #include <grp.h>
-#include <errno.h>
 
 #ifdef HAVE_DIRSRV_SLAPI_PLUGIN_H
 #include <nspr.h>
@@ -307,6 +308,144 @@ 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,
                                          char *container_sdn,
@@ -315,28 +454,37 @@ backend_retrieve_user_entry_from_nsswitch(char *user_name, bool_t is_uid,
 {
        struct passwd pwd, *result;
        Slapi_Entry *entry, **entries;
-       int rc;
+       enum nss_status rc;
        char *buf = NULL;
+       struct nss_ops_ctx *ctx = NULL;
+       int lerrno;
+
+       ctx = cbdata->state->nss_context;
 
+       if (ctx == NULL) {
+               return NULL;
+       }
 repeat:
        if (cbdata->nsswitch_buffer == NULL) {
                return NULL;
        }
 
        if (is_uid) {
-               rc = getpwuid_r((uid_t) atoll(user_name), &pwd,
-                               cbdata->nsswitch_buffer,
-                               cbdata->nsswitch_buffer_len, &result);
+               rc = ctx->getpwuid_r((uid_t) atoll(user_name), &pwd,
+                                    cbdata->nsswitch_buffer,
+                                    cbdata->nsswitch_buffer_len, &lerrno);
        } else {
-               rc = getpwnam_r(user_name, &pwd,
-                               cbdata->nsswitch_buffer,
-                               cbdata->nsswitch_buffer_len, &result);
+               rc = ctx->getpwnam_r(user_name, &pwd,
+                                    cbdata->nsswitch_buffer,
+                                    cbdata->nsswitch_buffer_len, &lerrno);
        }
-       if ((result == NULL) || (rc != 0)) {
-               if (rc == ERANGE) {
+
+       if ((rc != NSS_STATUS_SUCCESS)) {
+               if (lerrno == ERANGE) {
                        buf = realloc(cbdata->nsswitch_buffer, cbdata->nsswitch_buffer_len * 2);
                        if (buf != NULL) {
                                cbdata->nsswitch_buffer = buf;
+                               cbdata->nsswitch_buffer_len *= 2;
                                goto repeat;
                        }
                }
@@ -437,28 +585,36 @@ backend_retrieve_group_entry_from_nsswitch(char *group_name, bool_t is_gid,
 {
        struct group grp, *result;
        Slapi_Entry *entry, **entries;
-       int rc;
+       enum nss_status rc;
        char *buf = NULL;
+       struct nss_ops_ctx *ctx = NULL;
+       int lerrno = 0;
+
+       ctx = cbdata->state->nss_context;
 
+       if (ctx == NULL) {
+               return NULL;
+       }
 repeat:
        if (cbdata->nsswitch_buffer == NULL) {
                return NULL;
        }
 
        if (is_gid) {
-               rc = getgrgid_r((gid_t) atoll(group_name), &grp,
-                               cbdata->nsswitch_buffer,
-                               cbdata->nsswitch_buffer_len, &result);
+               rc = ctx->getgrgid_r((gid_t) atoll(group_name), &grp,
+                                    cbdata->nsswitch_buffer,
+                                    cbdata->nsswitch_buffer_len, &lerrno);
        } else {
-               rc = getgrnam_r(group_name, &grp,
-                               cbdata->nsswitch_buffer,
-                               cbdata->nsswitch_buffer_len, &result);
+               rc = ctx->getgrnam_r(group_name, &grp,
+                                    cbdata->nsswitch_buffer,
+                                    cbdata->nsswitch_buffer_len, &lerrno);
        }
-       if ((result == NULL) || (rc != 0)) {
-               if (rc == ERANGE) {
+       if ((rc != NSS_STATUS_SUCCESS)) {
+               if (lerrno == ERANGE) {
                        buf = realloc(cbdata->nsswitch_buffer, cbdata->nsswitch_buffer_len * 2);
                        if (buf != NULL) {
                                cbdata->nsswitch_buffer = buf;
+                               cbdata->nsswitch_buffer_len *= 2;
                                goto repeat;
                        }
                }
@@ -490,23 +646,31 @@ backend_retrieve_group_entry_from_nsswitch_by_gid(gid_t gid,
 {
        struct group grp, *result;
        Slapi_Entry *entry;
-       int rc;
+       enum nss_status rc;
        char *buf = NULL;
+       struct nss_ops_ctx *ctx = NULL;
+       int lerrno = 0;
 
+       ctx = cbdata->state->nss_context;
+
+       if (ctx == NULL) {
+               return NULL;
+       }
 repeat:
        if (cbdata->nsswitch_buffer == NULL) {
                return NULL;
        }
 
-       rc = getgrgid_r(gid, &grp,
-                       cbdata->nsswitch_buffer,
-                       cbdata->nsswitch_buffer_len, &result);
+       rc = ctx->getgrgid_r(gid, &grp,
+                            cbdata->nsswitch_buffer,
+                            cbdata->nsswitch_buffer_len, &lerrno);
 
-       if ((result == NULL) || (rc != 0)) {
-               if (rc == ERANGE) {
+       if ((rc != NSS_STATUS_SUCCESS)) {
+               if (lerrno == ERANGE) {
                        buf = realloc(cbdata->nsswitch_buffer, cbdata->nsswitch_buffer_len * 2);
                        if (buf != NULL) {
                                cbdata->nsswitch_buffer = buf;
+                               cbdata->nsswitch_buffer_len *= 2;
                                goto repeat;
                        }
                }
@@ -532,22 +696,32 @@ backend_retrieve_group_list_from_nsswitch(char *user_name, char *container_sdn,
        gid_t *grouplist, *tmp_list;
        Slapi_Entry **entries, *entry, **tmp;
        char *buf = NULL;
-       int rc, ngroups, i, idx;
-
+       int i, idx;
+       struct nss_ops_ctx *ctx = NULL;
+       int lerrno = 0;
+       long int ngroups = 0;
+       long int start = 0;
+       enum nss_status rc;
+
+       ctx = cbdata->state->nss_context;
+       if (ctx == NULL) {
+               return NULL;
+       }
 repeat:
        if (cbdata->nsswitch_buffer == NULL) {
                return NULL;
        }
 
-       rc = getpwnam_r(user_name, &pwd,
-                       cbdata->nsswitch_buffer,
-                       cbdata->nsswitch_buffer_len, &pwd_result);
+       rc = ctx->getpwnam_r(user_name, &pwd,
+                            cbdata->nsswitch_buffer,
+                            cbdata->nsswitch_buffer_len, &lerrno);
 
-       if ((pwd_result == NULL) || (rc != 0)) {
-               if (rc == ERANGE) {
+       if ((rc != NSS_STATUS_SUCCESS)) {
+               if (lerrno == ERANGE) {
                        buf = realloc(cbdata->nsswitch_buffer, cbdata->nsswitch_buffer_len * 2);
                        if (buf != NULL) {
                                cbdata->nsswitch_buffer = buf;
+                               cbdata->nsswitch_buffer_len *= 2;
                                goto repeat;
                        }
                }
@@ -559,14 +733,20 @@ repeat:
        }
 
        ngroups = 32;
+       start = 0;
        grouplist = malloc(sizeof(gid_t) * ngroups);
        if (grouplist == NULL) {
                return NULL;
        }
 
+       grouplist[0] = pwd.pw_gid;
+       start++;
+
        do {
-               rc = getgrouplist(user_name, pwd.pw_gid, grouplist, &ngroups);
-               if (rc < ngroups) {
+               rc = ctx->initgroups_dyn(user_name, pwd.pw_gid,
+                                        &start, &ngroups, &grouplist,
+                                        -1, &lerrno);
+               if ((rc != NSS_STATUS_SUCCESS)) {
                        tmp_list = realloc(grouplist, ngroups * sizeof(gid_t));
                        if (tmp_list == NULL) {
                                free(grouplist);
@@ -574,7 +754,7 @@ repeat:
                        }
                        grouplist = tmp_list;
                }
-       } while (rc != ngroups);
+       } while (rc != NSS_STATUS_SUCCESS);
 
        entries = calloc(ngroups + 1, sizeof(entries[0]));
        if (entries == NULL) {
diff --git a/src/back-sch.c b/src/back-sch.c
index 27d5101..dd6f92d 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -997,9 +997,11 @@ backend_search_entry_cb(const char *domain, const char *map, bool_t secure,
 {
        Slapi_DN *sdn;
        Slapi_Entry *entry;
+       Slapi_Attr *attr = NULL;
        struct backend_search_cbdata *cbdata;
        struct backend_entry_data *entry_data;
        int result;
+       bool_t is_attr_exists = FALSE;
 
        cbdata = cb_data;
        entry_data = backend_data;
@@ -1042,7 +1044,10 @@ backend_search_entry_cb(const char *domain, const char *map, bool_t secure,
                        idview_process_overrides(cbdata, key, map, domain, entry);
                }
 
-               if (slapi_entry_attr_exists(entry, IPA_IDVIEWS_ATTR_ANCHORUUID) == 1) {
+               /* slapi_entry_attr_exists() was introduced only in https://fedorahosted.org/389/ticket/47710 */
+               is_attr_exists = slapi_entry_attr_find(entry, IPA_IDVIEWS_ATTR_ANCHORUUID, &attr) == 0;
+
+               if (is_attr_exists == TRUE) {
                        slapi_entry_attr_delete(entry, IPA_IDVIEWS_ATTR_ANCHORUUID);
                        slapi_entry_delete_string(entry, "objectClass", "ipaOverrideTarget");
                }
@@ -1166,6 +1171,44 @@ backend_search_set_cb(const char *group, const char *set, bool_t flag,
        return TRUE;
 }
 
+/* Routines to search if a target DN is within any of the sets we handle */
+static bool_t
+backend_search_find_set_dn_in_group_cb(const char *group, const char *set, bool_t flag,
+                                        void *backend_data, void *cb_data)
+{
+       struct backend_search_cbdata *cbdata;
+       struct backend_set_data *set_data;
+
+       cbdata = cb_data;
+       set_data = backend_data;
+
+       if (slapi_sdn_scope_test(cbdata->target_dn,
+                                set_data->container_sdn,
+                                cbdata->scope) == 1) {
+               cbdata->answer = TRUE;
+       }
+
+       if (slapi_sdn_compare(set_data->container_sdn,
+                             cbdata->target_dn) == 0) {
+               cbdata->answer = TRUE;
+       }
+
+       return TRUE;
+
+}
+
+static bool_t
+backend_search_find_set_dn_cb(const char *group, void *cb_data)
+{
+       struct backend_search_cbdata *cbdata;
+
+       cbdata = cb_data;
+       map_data_foreach_map(cbdata->state, group,
+                            backend_search_find_set_dn_in_group_cb, cb_data);
+       return TRUE;
+}
+
+/* Routines to find out the set that has the same group as requested */
 static bool_t
 backend_search_find_set_data_in_group_cb(const char *group, const char *set, bool_t flag,
                                         void *backend_data, void *cb_data)
@@ -1340,9 +1383,6 @@ backend_search_cb(Slapi_PBlock *pb)
                        "searching from \"%s\" for \"%s\" with scope %d%s\n",
                        cbdata.target, cbdata.strfilter, cbdata.scope,
                        backend_sch_scope_as_string(cbdata.scope));
-#ifdef USE_IPA_IDVIEWS
-       idview_replace_target_dn(&cbdata.target, &cbdata.idview);
-#endif
        cbdata.target_dn = slapi_sdn_new_dn_byval(cbdata.target);
        /* Check if there's a backend handling this search. */
        if (!slapi_be_exist(cbdata.target_dn)) {
@@ -1351,19 +1391,47 @@ backend_search_cb(Slapi_PBlock *pb)
                                "slapi_be_exists(\"%s\") = 0, "
                                "ignoring search\n", cbdata.target);
                slapi_sdn_free(&cbdata.target_dn);
+               return 0;
+       }
+
+#ifdef USE_IPA_IDVIEWS
+       /* We may have multiple disjoint trees in the sets, search if the target matches any of them
+        * as in general there don't have to be a single subtree (cn=compat,$SUFFIX) for all trees to easily
+        * detect the ID view use. Unless the ID view is within the set we control, don't consider the override */
+       map_data_foreach_domain(cbdata.state, backend_search_find_set_dn_cb, &cbdata);
+       if (cbdata.answer == FALSE) {
+               idview_replace_target_dn(&cbdata.target, &cbdata.idview);
                if (cbdata.idview != NULL) {
-                       slapi_ch_free_string(&cbdata.target);
+                       slapi_sdn_free(&cbdata.target_dn);
+                       /* Perform another check, now for rewritten DN */
+                       cbdata.target_dn = slapi_sdn_new_dn_byval(cbdata.target);
+                       map_data_foreach_domain(cbdata.state, backend_search_find_set_dn_cb, &cbdata);
+                       /* Rewritten DN might still be outside of our trees */
+                       if (cbdata.answer == TRUE) {
+                               slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id,
+                                               "Use of ID view '%s' is detected, searching from \"%s\" "
+                                               "for \"%s\" with scope %d%s. Filter may get overridden later.\n",
+                                               cbdata.idview, cbdata.target, cbdata.strfilter, cbdata.scope,
+                                               backend_sch_scope_as_string(cbdata.scope));
+                       } else {
+                               slapi_sdn_free(&cbdata.target_dn);
+                               slapi_ch_free_string(&cbdata.target);
+                               slapi_ch_free_string(&cbdata.idview);
+                               slapi_log_error(SLAPI_LOG_PLUGIN,
+                                               cbdata.state->plugin_desc->spd_id,
+                                               "The search base didn't match any of the containers, "
+                                               "ignoring search\n");
+                               return 0;
+                       }
                }
-               slapi_ch_free_string(&cbdata.idview);
-#ifdef USE_IPA_IDVIEWS
-               idview_free_overrides(&cbdata);
-#endif
-               return 0;
        }
+       cbdata.answer = FALSE;
+#endif
 
        /* Walk the list of groups. */
        wrap_inc_call_level();
 #ifdef USE_IPA_IDVIEWS
+       /* Filter replacement requires increased call level as we may fetch overrides and thus come back here */
        idview_replace_filter(&cbdata);
 #endif
        if (map_rdlock() == 0) {
@@ -1380,10 +1448,7 @@ backend_search_cb(Slapi_PBlock *pb)
        /* If during search of some sets we staged additional lookups, perform them. */
        if (cbdata.staged != NULL) {
                /* Allocate buffer to be used for getpwnam_r/getgrnam_r requests */
-               cbdata.nsswitch_buffer_len = MAX(sysconf(_SC_GETPW_R_SIZE_MAX), sysconf(_SC_GETGR_R_SIZE_MAX));
-               if (cbdata.nsswitch_buffer_len == -1) {
-                       cbdata.nsswitch_buffer_len = 16384;
-               }
+               cbdata.nsswitch_buffer_len = MAX(16384, MAX(sysconf(_SC_GETPW_R_SIZE_MAX), sysconf(_SC_GETGR_R_SIZE_MAX)));
                cbdata.nsswitch_buffer = malloc(cbdata.nsswitch_buffer_len);
                /* Go over the list of staged requests and retrieve entries.
                 * It is important to perform the retrieval *without* holding any locks to the map cache */
@@ -1568,7 +1633,6 @@ static void
 backend_locate(Slapi_PBlock *pb, struct backend_entry_data **data, const char **group, const char**set)
 {
        struct backend_locate_cbdata cbdata;
-       char *idview = NULL;
 
        slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &cbdata.state);
        if (cbdata.state->plugin_base == NULL) {
@@ -1577,22 +1641,64 @@ backend_locate(Slapi_PBlock *pb, struct backend_entry_data **data, const char **
                return;
        }
        slapi_pblock_get(pb, SLAPI_TARGET_DN, &cbdata.target);
-#ifdef USE_IPA_IDVIEWS
-       idview_replace_target_dn(&cbdata.target, &idview);
-#endif
+
        cbdata.target_dn = slapi_sdn_new_dn_byval(cbdata.target);
        cbdata.entry_data = NULL;
        cbdata.entry_group = NULL;
        cbdata.entry_set = NULL;
        map_data_foreach_map(cbdata.state, NULL, backend_locate_cb, &cbdata);
+#ifdef USE_IPA_IDVIEWS
+       /* In case nothing was found but we are operating on the ID override,
+        * rebuild the target's RDN to use original attribute's value */
+       if (cbdata.entry_data == NULL) {
+               char *idview = NULL;
+               char *target, *original_target;
+               target = original_target = slapi_ch_strdup(cbdata.target);
+               idview_replace_target_dn(&target, &idview);
+               if (target != original_target) {
+                       slapi_ch_free_string(&original_target);
+               }
+               if (idview != NULL) {
+                       char *rdnstr;
+                       char *val;
+                       struct berval bval;
+                       int res;
+                       struct backend_search_cbdata scbdata;
+                       Slapi_RDN *rdn = slapi_rdn_new_all_dn(target);
+                       if (rdn != NULL) {
+                               res = slapi_rdn_get_first(rdn, &rdnstr, &val);
+                               if (res == 1) {
+                                       bval.bv_len = strlen(val) + 1;
+                                       bval.bv_val = slapi_ch_strdup(val);
+                                       memset(&scbdata, 0, sizeof(scbdata));
+                                       scbdata.idview = idview;
+                                       scbdata.target = target;
+                                       scbdata.pb = pb;
+                                       scbdata.state = cbdata.state;
+                                       scbdata.target_dn = slapi_sdn_new_dn_byval(target);
+                                       res = idview_replace_bval_by_override("rdn", rdnstr, &bval, &scbdata);
+                                       /* only accept uid overrides */
+                                       if (res == 1) {
+                                               slapi_rdn_remove_index(rdn, 1);
+                                               slapi_rdn_add(rdn, "uid", bval.bv_val);
+                                               slapi_sdn_free(&cbdata.target_dn);
+                                               cbdata.target_dn = slapi_sdn_set_rdn(scbdata.target_dn, rdn);
+                                               map_data_foreach_map(cbdata.state, NULL, backend_locate_cb, &cbdata);
+                                       }
+                                       slapi_ber_bvdone(&bval);
+                                       slapi_rdn_free(&rdn);
+                                       idview_free_overrides(&scbdata);
+                               }
+                       }
+               }
+               slapi_ch_free_string(&target);
+               slapi_ch_free_string(&idview);
+       }
+#endif
        *data = cbdata.entry_data;
        *group = cbdata.entry_group;
        *set = cbdata.entry_set;
        slapi_sdn_free(&cbdata.target_dn);
-       if (idview != NULL) {
-               slapi_ch_free_string(&cbdata.target);
-       }
-       slapi_ch_free_string(&idview);
 }
 
 /* Check if the target DN is part of this group's tree.  If it is, return an
diff --git a/src/back-sch.h b/src/back-sch.h
index 9f0b201..1aedf36 100644
--- a/src/back-sch.h
+++ b/src/back-sch.h
@@ -115,6 +115,11 @@ struct backend_search_filter_config {
 
 int backend_analyze_search_filter(Slapi_Filter *filter, struct backend_search_filter_config *config);
 
+/* Operations against nsswitch 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_search_nsswitch(struct backend_set_data *set_data,
                             struct backend_search_cbdata *cbdata);
 
@@ -131,6 +136,10 @@ void idview_process_overrides(struct backend_search_cbdata *cbdata,
                              Slapi_Entry *entry);
 void idview_replace_target_dn(char **target, char **idview);
 void idview_replace_filter(struct backend_search_cbdata *cbdata);
+/* Takes struct berval value of an attribute attr_name and replaces it with an override
+ * Returns 0 if no override was found, 1 for 'uid' replacement, 2 for ipaAnchorUUID replacement */
+int  idview_replace_bval_by_override(const char *bval_usage, const char *attr_name,
+                                    struct berval *bval, struct backend_search_cbdata *cbdata);
 #endif
 
 #endif
diff --git a/src/plug-sch.c b/src/plug-sch.c
index 5d74beb..5a6e736 100644
--- a/src/plug-sch.c
+++ b/src/plug-sch.c
@@ -52,6 +52,7 @@
 
 #include "backend.h"
 #include "back-shr.h"
+#include "back-sch.h"
 #include "map.h"
 #include "plugin.h"
 #include "portmap.h"
@@ -109,6 +110,7 @@ plugin_startup(Slapi_PBlock *pb)
        /* Populate the tree of fake entries. */
        backend_startup(pb, state);
        state->pam_lock = wrap_new_rwlock();
+       backend_nss_init_context((struct nss_ops_ctx**) &state->nss_context);
        /* Note that the plugin is ready to go. */
        slapi_log_error(SLAPI_LOG_PLUGIN, plugin_description.spd_id,
                        "plugin startup completed\n");
@@ -123,6 +125,7 @@ plugin_shutdown(Slapi_PBlock *pb)
        map_done(state);
        wrap_free_rwlock(state->pam_lock);
        state->pam_lock = NULL;
+       backend_nss_free_context((struct nss_ops_ctx**) &state->nss_context);
        state->plugin_base = NULL;
        slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
                        "plugin shutdown completed\n");
diff --git a/src/plugin.h b/src/plugin.h
index 3967fb0..94ad747 100644
--- a/src/plugin.h
+++ b/src/plugin.h
@@ -46,6 +46,7 @@ struct plugin_state {
        } listener[4];
        /* Schema compat-specific data. */
        struct wrapped_rwlock *pam_lock;
+       void *nss_context;
 };
 
 #endif



unblock slapi-nis/0.54.2-1


Reply to: