[Pkg-freeipa-devel] slapi-nis: Changes to 'upstream'

Timo Aaltonen tjaalton at moszumanska.debian.org
Thu Apr 2 11:25:47 UTC 2015


 configure.ac          |    3 
 doc/ipa/sch-ipa.txt   |   14 ++
 slapi-nis.spec        |   11 ++
 src/back-sch-idview.c |   86 ++++++++++++-----
 src/back-sch-nss.c    |  250 +++++++++++++++++++++++++++++++++++++++++++-------
 src/back-sch.c        |  150 +++++++++++++++++++++++++-----
 src/back-sch.h        |    9 +
 src/plug-sch.c        |    3 
 src/plugin.h          |    1 
 9 files changed, 440 insertions(+), 87 deletions(-)

New commits:
commit 6573f91c95f7a353ad3bdf2fe95b0c15932aa097
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Thu Mar 26 11:02:14 2015 +0200

    Tag release 0.54.2
    CVE-2015-0283 slapi-nis: infinite loop in getgrnam_r() and getgrgid_r()

diff --git a/configure.ac b/configure.ac
index 92647ea..ae626de 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT(slapi-nis,0.54.1)
+AC_INIT(slapi-nis,0.54.2)
 AC_CONFIG_MACRO_DIR([m4])
 AM_INIT_AUTOMAKE(foreign)
 LT_INIT([disable-static])
diff --git a/slapi-nis.spec b/slapi-nis.spec
index f77f2a4..f0c2647 100644
--- a/slapi-nis.spec
+++ b/slapi-nis.spec
@@ -10,7 +10,7 @@
 %endif
 
 Name:		slapi-nis
-Version:	0.54.1
+Version:	0.54.2
 Release:	1%{?dist}
 Summary:	NIS Server and Schema Compatibility plugins for Directory Server
 Group:		System Environment/Daemons
@@ -85,6 +85,11 @@ rm -rf $RPM_BUILD_ROOT
 %{_sbindir}/nisserver-plugin-defs
 
 %changelog
+* Thu Mar 26 2015 Alexander Bokovoy <abokovoy at 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 at redhat.com> - 0.54.1-1
 - support FreeIPA overrides in LDAP BIND callback
 - ignore FreeIPA override searchs outside configured schema compat subtrees

commit dd1d44730f2724986f820151d6ec2a49f6e52ddf
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Wed Feb 25 10:08:39 2015 +0200

    Make sure default buffer for nsswitch operations is big enough
    
    By default initial buffer sizes for getgrent/getgrnam/... functions
    are way small for large groups in Active Directory so make sure
    we have something reasonable for groups with hundreds or thousands members.

diff --git a/src/back-sch.c b/src/back-sch.c
index d0ed323..dd6f92d 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -1448,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 */

commit 44c97a46a1920f6db18b8c90b396a94a653d755c
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Tue Feb 24 13:18:34 2015 +0200

    nss: make sure to remember the length of reallocated buffer

diff --git a/src/back-sch-nss.c b/src/back-sch-nss.c
index 3a21ff6..f8177d7 100644
--- a/src/back-sch-nss.c
+++ b/src/back-sch-nss.c
@@ -484,6 +484,7 @@ repeat:
 			buf = realloc(cbdata->nsswitch_buffer, cbdata->nsswitch_buffer_len * 2);
 			if (buf != NULL) {
 				cbdata->nsswitch_buffer = buf;
+				cbdata->nsswitch_buffer_len *= 2;
 				goto repeat;
 			}
 		}
@@ -613,6 +614,7 @@ repeat:
 			buf = realloc(cbdata->nsswitch_buffer, cbdata->nsswitch_buffer_len * 2);
 			if (buf != NULL) {
 				cbdata->nsswitch_buffer = buf;
+				cbdata->nsswitch_buffer_len *= 2;
 				goto repeat;
 			}
 		}
@@ -668,6 +670,7 @@ repeat:
 			buf = realloc(cbdata->nsswitch_buffer, cbdata->nsswitch_buffer_len * 2);
 			if (buf != NULL) {
 				cbdata->nsswitch_buffer = buf;
+				cbdata->nsswitch_buffer_len *= 2;
 				goto repeat;
 			}
 		}
@@ -718,6 +721,7 @@ repeat:
 			buf = realloc(cbdata->nsswitch_buffer, cbdata->nsswitch_buffer_len * 2);
 			if (buf != NULL) {
 				cbdata->nsswitch_buffer = buf;
+				cbdata->nsswitch_buffer_len *= 2;
 				goto repeat;
 			}
 		}

commit 3368b2c04c870ffa5bfb831980d28bfa50534e0b
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Wed Nov 12 13:23:17 2014 +0200

    schema-compat: use libnss_sss.so.2 explicitly to resolve trusted domain users via NSS
    
    When Schema Compatibility plugin is configured to enumerate users and groups
    from Active Directory domains trusted by FreeIPA, use nss_sss module directly
    instead of following nsswitch.conf configuration.
    
    The issue with nsswitch.conf configuration is in the fact that for each request
    all modules in NSS chain are processed while only one of them is responsible
    for users from trusted Active Directory domains, namely, nss_sss.

diff --git a/configure.ac b/configure.ac
index 9174980..92647ea 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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/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/src/back-sch-nss.c b/src/back-sch-nss.c
index 12ae589..3a21ff6 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,25 +454,33 @@ 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;
@@ -437,25 +584,32 @@ 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;
@@ -490,20 +644,27 @@ 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;
@@ -532,19 +693,28 @@ 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;
@@ -559,14 +729,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 +750,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.h b/src/back-sch.h
index 26e12d1..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);
 
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

commit 13ebc3edfe1d6d8888f3d70f189638cf5ddd71ed
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Tue Oct 14 17:25:46 2014 +0300

    Use slapi_entry_find_attr instead of slapi_entry_attr_exists
    
    To keep slapi-nis code portable to older versions of 389-ds-base,
    avoid using slapi_entry_attr_exists() as it was only introduced in
    389-ds-base 1.3.3.0.

diff --git a/src/back-sch-idview.c b/src/back-sch-idview.c
index f1150cd..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);
 				}
diff --git a/src/back-sch.c b/src/back-sch.c
index 2388d2f..d0ed323 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");
 		}

commit a42204ee958a380648ade421a742db2ad2d5eb39
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Thu Nov 6 14:32:11 2014 +0200

    Tag slapi-nis 0.54.1

diff --git a/configure.ac b/configure.ac
index 59fa6e5..9174980 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT(slapi-nis,0.54)
+AC_INIT(slapi-nis,0.54.1)
 AC_CONFIG_MACRO_DIR([m4])
 AM_INIT_AUTOMAKE(foreign)
 LT_INIT([disable-static])
diff --git a/slapi-nis.spec b/slapi-nis.spec
index 21935ca..f77f2a4 100644
--- a/slapi-nis.spec
+++ b/slapi-nis.spec
@@ -10,7 +10,7 @@
 %endif
 
 Name:		slapi-nis
-Version:	0.54
+Version:	0.54.1
 Release:	1%{?dist}
 Summary:	NIS Server and Schema Compatibility plugins for Directory Server
 Group:		System Environment/Daemons
@@ -85,6 +85,10 @@ rm -rf $RPM_BUILD_ROOT
 %{_sbindir}/nisserver-plugin-defs
 
 %changelog
+* Thu Nov  6 2014 Alexander Bokovoy <abokovoy at 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 at redhat.com> - 0.54-1
 - Add support for FreeIPA's ID views
 - Allow searching SSSD-provided users as memberUid case-insensitevly

commit c9c9d1413a6950344bc842024fda84212cc7322f
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Tue Oct 28 11:16:50 2014 +0200

    schema-compat: support ID overrides in bind callback
    
    If RDN of the bind DN is overridden within the ID view, rewrite the
    target to use original value of the uid attribute.
    
    If original uid attribute is not available, fail the search and thus
    the whole bind request by claiming that bind DN does not exist.

diff --git a/src/back-sch-idview.c b/src/back-sch-idview.c
index a56a9e9..f1150cd 100644
--- a/src/back-sch-idview.c
+++ b/src/back-sch-idview.c
@@ -290,21 +290,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,31 +306,34 @@ 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;
-						slapi_log_error(SLAPI_LOG_PLUGIN, cbdata->state->plugin_desc->spd_id,
-								"Overriding the filter %s with %s=%*s from the override %s\n.",
-								filter_type, filter_type, bval->bv_len, bval->bv_val,
+						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;
 					}
@@ -346,14 +343,13 @@ 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;
-					slapi_log_error(SLAPI_LOG_PLUGIN, cbdata->state->plugin_desc->spd_id,
-							"Overriding the filter %s with %s=%*s from the override %s\n.",
-							filter_type, IPA_IDVIEWS_ATTR_ANCHORUUID,
-							bval->bv_len, bval->bv_val,
+					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;
 				}
@@ -362,7 +358,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;
 
diff --git a/src/back-sch.c b/src/back-sch.c
index 27ac24f..2388d2f 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -1631,7 +1631,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) {
@@ -1640,22 +1639,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..26e12d1 100644
--- a/src/back-sch.h
+++ b/src/back-sch.h
@@ -131,6 +131,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

commit 778c95866f28d894822e37223b69816981d29529
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Tue Oct 28 10:09:47 2014 +0200

    ID views: ignore searches for views outside the subtrees of schema-compat sets
    
    schema-compat plugin may provide multiple disjoint subtrees which
    can be used to request overridden entries by prefixing the subtree
    suffix with a
    
      cn=<name of view>,cn=views,<subtree suffix>
    
    As subtrees may be disjoint, we cannot rely on the common suffix. Thus,
    any attempt to replace target DN and update filter terms must only be
    done once we are sure the search will be done in the subtree.
    
    This optimization prevents mistakenly changing the search filter when
    FreeIPA and SSSD search for the ID overrides themselves, as the same
    structure of the target DN is used for  cn=views,cn=accounts,$SUFFIX
    subtree in FreeIPA. This subtree is never handled by slapi-nis and
    should be ignored.
    
    https://bugzilla.redhat.com/show_bug.cgi?id=1157989

diff --git a/src/back-sch-idview.c b/src/back-sch-idview.c
index 5a2b450..a56a9e9 100644
--- a/src/back-sch-idview.c
+++ b/src/back-sch-idview.c
@@ -334,6 +334,10 @@ idview_process_filter_cb(Slapi_Filter *filter, const char *filter_type, struct b
 						slapi_ber_bvdone(bval);
 						slapi_ber_bvcpy(bval, slapi_value_get_berval(anchor_val));
 						config->override_found = TRUE;
+						slapi_log_error(SLAPI_LOG_PLUGIN, cbdata->state->plugin_desc->spd_id,
+								"Overriding the filter %s with %s=%*s from the override %s\n.",
+								filter_type, filter_type, bval->bv_len, bval->bv_val,
+								slapi_entry_get_dn_const(cbdata->overrides[i]));
 						break;
 					}
 				}
@@ -346,6 +350,11 @@ idview_process_filter_cb(Slapi_Filter *filter, const char *filter_type, struct b
 					slapi_ber_bvdone(bval);
 					slapi_ber_bvcpy(bval, slapi_value_get_berval(anchor_val));
 					config->override_found = TRUE;
+					slapi_log_error(SLAPI_LOG_PLUGIN, cbdata->state->plugin_desc->spd_id,
+							"Overriding the filter %s with %s=%*s from the override %s\n.",
+							filter_type, IPA_IDVIEWS_ATTR_ANCHORUUID,
+							bval->bv_len, bval->bv_val,
+							slapi_entry_get_dn_const(cbdata->overrides[i]));
 					break;
 				}
 
@@ -366,8 +375,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)
 {



More information about the Pkg-freeipa-devel mailing list