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

Timo Aaltonen tjaalton at moszumanska.debian.org
Mon Feb 22 05:45:48 UTC 2016


 configure.ac              |    2 
 doc/ipa/sch-ipa.txt       |   15 ++
 doc/nis-configuration.txt |    4 
 doc/sch-configuration.txt |   11 +
 slapi-nis.spec            |    7 
 src/back-sch-idview.c     |    6 
 src/back-sch-nss.c        |   29 +++
 src/back-sch.c            |  336 ++++++++++++++++++++++++++++++++++++++++++----
 src/back-sch.h            |   20 ++
 src/back-shr.c            |  155 ++++++++++++++++++---
 src/defs-nis.c            |   10 -
 src/plug-sch.c            |   38 ++++-
 src/plugin.h              |    4 
 13 files changed, 573 insertions(+), 64 deletions(-)

New commits:
commit dc18db811d26a9e376788688d4e68937b078ac58
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Tue Jan 26 13:42:54 2016 +0200

    Release 0.55

diff --git a/configure.ac b/configure.ac
index ae626de..5b10376 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT(slapi-nis,0.54.2)
+AC_INIT(slapi-nis,0.55)
 AC_CONFIG_MACRO_DIR([m4])
 AM_INIT_AUTOMAKE(foreign)
 LT_INIT([disable-static])
diff --git a/slapi-nis.spec b/slapi-nis.spec
index f0c2647..2546509 100644
--- a/slapi-nis.spec
+++ b/slapi-nis.spec
@@ -10,7 +10,7 @@
 %endif
 
 Name:		slapi-nis
-Version:	0.54.2
+Version:	0.55
 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
+* Tue Jan 26 2016 Alexander Bokovoy <abokovoy at redhat.com> - 0.55-1
+- Support external members of IPA groups in schema compat
+- Support bind over ID overrides when uid is not overridden
+- Populate schema compat trees in parallel to LDAP server startup
+
 * 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

commit 00468e8eebd455ab4e41d4d86772fb5f8a745d0a
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Thu Jan 21 19:16:30 2016 +0200

    idviews: bind with original DN if ID view does not override uid attribute
    
    With ID Views in FreeIPA one can override different kinds of attributes,
    including the uid. When uid attribute is overriden, LDAP BINDs with
    DNs using new (overridden) uid are properly modified to reference the
    original (non-overridden) object.
    
    However, when uid attribute is not overridden, slapi-nis did mistakenly
    avoided to build a reference to the original object without ID view.
    This resulted in inability to do LDAP BIND as overriden DN with original
    uid attribute.
    
    Fix the issue by always processing a DN after removing ID view reference
    from it, whether RDN value (uid) was replaced or not.
    
    Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1301300

diff --git a/src/back-sch-idview.c b/src/back-sch-idview.c
index 8ffab91..8842906 100644
--- a/src/back-sch-idview.c
+++ b/src/back-sch-idview.c
@@ -311,7 +311,7 @@ idview_replace_bval_by_override(const char *bval_usage, const char *attr_name,
 	}
 
 	attr_val = slapi_value_new_berval(bval);
-	slapi_log_error(SLAPI_LOG_FATAL, cbdata->state->plugin_desc->spd_id,
+	slapi_log_error(SLAPI_LOG_PLUGIN, 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);
 
@@ -347,7 +347,7 @@ idview_replace_bval_by_override(const char *bval_usage, const char *attr_name,
 					slapi_ber_bvdone(bval);
 					slapi_ber_bvcpy(bval, slapi_value_get_berval(anchor_val));
 					anchor_override_found = TRUE;
-					slapi_log_error(SLAPI_LOG_FATAL, cbdata->state->plugin_desc->spd_id,
+					slapi_log_error(SLAPI_LOG_PLUGIN, 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,
diff --git a/src/back-sch.c b/src/back-sch.c
index 871734c..9a0e96b 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -465,13 +465,13 @@ backend_set_process_external_members(Slapi_PBlock *pb,
 		 * 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) {
-			slapi_log_error(SLAPI_LOG_PLUGIN, plugin_id,
-					"group \"%s\" does not exist because SSSD is offline.",
+			slapi_log_error(SLAPI_LOG_FATAL, plugin_id,
+					"group \"%s\" does not exist because SSSD is offline.\n",
 					staged.name);
 			if (state->ready_to_serve == 0) {
 				/* Only wait for SSSD when we populate the original set */
-				slapi_log_error(SLAPI_LOG_PLUGIN, plugin_id,
-						"waiting for SSSD to become online...");
+				slapi_log_error(SLAPI_LOG_FATAL, plugin_id,
+						"waiting for SSSD to become online...\n");
 				DS_Sleep(PR_SecondsToInterval(35));
 			} else {
 				break;
@@ -1609,15 +1609,15 @@ backend_search_cb(Slapi_PBlock *pb)
 {
 	struct backend_search_cbdata cbdata;
 	struct backend_staged_search *staged, *next;
-	int i, isroot;
+	int i, isroot, ret;
 
 	if (wrap_get_call_level() > 0) {
 		return 0;
 	}
 	memset(&cbdata, 0, sizeof(cbdata));
 	cbdata.pb = pb;
-	slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &cbdata.state);
-	if (cbdata.state->plugin_base == NULL) {
+	ret = slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &cbdata.state);
+	if ((ret == -1) || (cbdata.state->plugin_base == NULL)) {
 		/* The plugin was not actually started. */
 		return 0;
 	}
@@ -1626,9 +1626,9 @@ backend_search_cb(Slapi_PBlock *pb)
 		return 0;
 	}
 
-	slapi_pblock_get(pb, SLAPI_REQUESTOR_ISROOT, &isroot);
+	ret = slapi_pblock_get(pb, SLAPI_REQUESTOR_ISROOT, &isroot);
 
-	if (slapi_op_internal(pb) || (slapi_is_ldapi_conn(pb) && isroot)) {
+	if ((ret == -1) || (slapi_op_internal(pb) || (slapi_is_ldapi_conn(pb) && isroot))) {
 		/* The plugin should not engage in internal searches of other
 		 * plugins or ldapi+cn=DM */
 		return 0;
@@ -1959,10 +1959,10 @@ backend_locate(Slapi_PBlock *pb, struct backend_entry_data **data, const char **
 					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_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);

commit 5eaad9c4c218d9a59f6930a29f5bee54235c4fab
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Tue Jan 19 07:37:46 2016 +0200

    nis: lock out accounts if nsAccountLock is TRUE
    
    Add a rule that adds two bang characters in front of the password.
    
    When the password algorithm is defined as CRYPT and NIS is used to
    authenticate users on other systems, there is no way to disable or lock
    accounts. Traditional convention has been to put two bang (exclamation)
    characters in front of the password, creating an impossible password
    hash. This effectively locks the user account, preventing
    authentication.
    
    All UNIX systems agree that for encrypted passwords presence of a
    character which cannot be part of CRYPT password scheme renders
    impossible to login to system with such password. However, not all
    systems have meaning of locked accounts and even how these locked
    accounts express themselves.
    
    There is certain controversy in what could be used to indicate locked
    accounts:
     - GNU/Linux systems expect '!' as first character of the password field
     - FreeBSD expects '*LOCKED*' string at start of the password field
     - Various Solaris versions expect '*LOCK*' string at start of the
       password field
     - NetBSD has no meaning of locked passwords via content of password field
    
    Given that it is impossible to serve NIS maps with encrypted passwords
    in a different way to different clients, standardize on '!!' scheme as
    traditional among UNIX administrators.
    
    Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1298478

diff --git a/src/defs-nis.c b/src/defs-nis.c
index 3d2b9e9..ad0e7dc 100644
--- a/src/defs-nis.c
+++ b/src/defs-nis.c
@@ -52,17 +52,17 @@ static struct configuration {
 	{"passwd.byname", config_exact, FALSE, NULL,
 	 "(objectClass=posixAccount)",
 	 "%{uid}", NULL,
-	 "%{uid}:%ifeq(\"objectClass\",\"shadowAccount\",\"x\",\"%regsubi(\\\"%{userPassword}\\\",\\\"^\\\\\\\\{CRYPT\\\\\\\\}(..*)\\\",\\\"%1\\\",\\\"*\\\")\"):%regmatch(\"%{uidNumber}\",\"[0-9]+\"):%regmatch(\"%{gidNumber}\",\"[0-9]+\"):%{gecos:-%{cn:-}}:%{homeDirectory:-/}:%{loginShell:-" _PATH_BSHELL "}", NULL,
+	 "%{uid}:%ifeq(\"nsAccountLock\",\"TRUE\",\"!!\",\"\")%ifeq(\"objectClass\",\"shadowAccount\",\"x\",\"%regsubi(\\\"%{userPassword}\\\",\\\"^\\\\\\\\{CRYPT\\\\\\\\}(..*)\\\",\\\"%1\\\",\\\"*\\\")\"):%regmatch(\"%{uidNumber}\",\"[0-9]+\"):%regmatch(\"%{gidNumber}\",\"[0-9]+\"):%{gecos:-%{cn:-}}:%{homeDirectory:-/}:%{loginShell:-" _PATH_BSHELL "}", NULL,
 	 ":\r\n"},
 	{"passwd.byuid", config_exact, FALSE, NULL,
 	 "(objectClass=posixAccount)",
 	 "%{uidNumber}", NULL,
-	 "%{uid}:%ifeq(\"objectClass\",\"shadowAccount\",\"x\",\"%regsubi(\\\"%{userPassword}\\\",\\\"^\\\\\\\\{CRYPT\\\\\\\\}(..*)\\\",\\\"%1\\\",\\\"*\\\")\"):%regmatch(\"%{uidNumber}\",\"[0-9]+\"):%regmatch(\"%{gidNumber}\",\"[0-9]+\"):%{gecos:-%{cn:-}}:%{homeDirectory:-/}:%{loginShell:-" _PATH_BSHELL "}", NULL,
+	 "%{uid}:%ifeq(\"nsAccountLock\",\"TRUE\",\"!!\",\"\")%ifeq(\"objectClass\",\"shadowAccount\",\"x\",\"%regsubi(\\\"%{userPassword}\\\",\\\"^\\\\\\\\{CRYPT\\\\\\\\}(..*)\\\",\\\"%1\\\",\\\"*\\\")\"):%regmatch(\"%{uidNumber}\",\"[0-9]+\"):%regmatch(\"%{gidNumber}\",\"[0-9]+\"):%{gecos:-%{cn:-}}:%{homeDirectory:-/}:%{loginShell:-" _PATH_BSHELL "}", NULL,
 	 ":\r\n"},
 	{"shadow.byname", config_exact, TRUE, NULL,
 	 "(objectClass=shadowAccount)",
 	 "%{uid}", NULL,
-	 "%{uid}:%regsubi(\"%{userPassword}\",\"^\\\\{CRYPT\\\\}(..*)\",\"%1\",\"*\"):%{shadowLastChange:-}:%{shadowMin:-}:%{shadowMax:-}:%{shadowWarning:-}:%{shadowInactive:-}:%{shadowExpire:-}:%{shadowFlag:-}", NULL,
+	 "%{uid}:%ifeq(\"nsAccountLock\",\"TRUE\",\"!!\",\"\")%regsubi(\"%{userPassword}\",\"^\\\\{CRYPT\\\\}(..*)\",\"%1\",\"*\"):%{shadowLastChange:-}:%{shadowMin:-}:%{shadowMax:-}:%{shadowWarning:-}:%{shadowInactive:-}:%{shadowExpire:-}:%{shadowFlag:-}", NULL,
 	 ":\r\n"},
 	{"passwd.adjunct.byname", config_exact, TRUE, NULL,
 	 "(objectClass=shadowAccount)",
@@ -72,12 +72,12 @@ static struct configuration {
 	{"group.byname", config_exact, FALSE, NULL,
 	 "(objectClass=posixGroup)",
 	 "%{cn}", NULL,
-	 "%{cn}:%regsubi(\"%{userPassword}\",\"^\\\\{CRYPT\\\\}(..*)\",\"%1\",\"*\"):%regmatch(\"%{gidNumber}\",\"[0-9]+\"):%merge(\",\",\"%{memberUid}\",\"%deref_r(\\\"member\\\",\\\"uid\\\")\",\"%deref_r(\\\"uniqueMember\\\",\\\"uid\\\")\")", NULL,
+	 "%{cn}:%ifeq(\"nsAccountLock\",\"TRUE\",\"!!\",\"\")%regsubi(\"%{userPassword}\",\"^\\\\{CRYPT\\\\}(..*)\",\"%1\",\"*\"):%regmatch(\"%{gidNumber}\",\"[0-9]+\"):%merge(\",\",\"%{memberUid}\",\"%deref_r(\\\"member\\\",\\\"uid\\\")\",\"%deref_r(\\\"uniqueMember\\\",\\\"uid\\\")\")", NULL,
 	 ":,\r\n"},
 	{"group.bygid", config_exact, FALSE, NULL,
 	 "(objectClass=posixGroup)",
 	 "%{gidNumber}", NULL,
-	 "%{cn}:%regsubi(\"%{userPassword}\",\"^\\\\{CRYPT\\\\}(..*)\",\"%1\",\"*\"):%{gidNumber}:%merge(\",\",\"%{memberUid}\",\"%deref_r(\\\"member\\\",\\\"uid\\\")\",\"%deref_r(\\\"uniqueMember\\\",\\\"uid\\\")\")", NULL,
+	 "%{cn}:%ifeq(\"nsAccountLock\",\"TRUE\",\"!!\",\"\")%regsubi(\"%{userPassword}\",\"^\\\\{CRYPT\\\\}(..*)\",\"%1\",\"*\"):%{gidNumber}:%merge(\",\",\"%{memberUid}\",\"%deref_r(\\\"member\\\",\\\"uid\\\")\",\"%deref_r(\\\"uniqueMember\\\",\\\"uid\\\")\")", NULL,
 	 ":,\r\n"},
 	{"netgroup", config_exact, FALSE, NULL,
 	 "(objectClass=nisNetgroup)",

commit 3aaf4941fc17df388c43776eda6d41f62017a143
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Fri Jan 15 17:17:23 2016 +0200

    slapi-nis: serialize map cache initialization
    
    Serialize process of initiliazing map cache to avoid locking the
    directory server backends.

diff --git a/src/back-shr.c b/src/back-shr.c
index 131365d..0157582 100644
--- a/src/back-shr.c
+++ b/src/back-shr.c
@@ -678,49 +678,68 @@ backend_shr_data_initialize_thread_cb(void *arg)
 	struct backend_shr_data_init_cbdata *cbdata = (struct backend_shr_data_init_cbdata *)arg;
 	Slapi_PBlock *pb = NULL;
 	struct backend_set_config_entry_add_cbdata set_cbdata;
-	int result = 0;
+	int result = 0, i = 0;
+	Slapi_Entry **entries = NULL;
+	struct plugin_state *state = NULL;
+
 	if (cbdata == NULL) {
 		return;
 	}
 
+	state = cbdata->state;
+
 	/* Scan may require consulting SSSD for external identities
 	 * therefore, we need to make sure the scan starts after ns-slapd
 	 * started to serve LDAP clients. There is no a signal for this,
 	 * so we just wait some time. */
 	DS_Sleep(PR_SecondsToInterval(PLUGIN_SCAN_DELAY));
 
-	backend_update_params(cbdata->parent_pb, cbdata->state);
+	backend_update_params(cbdata->parent_pb, state);
 
 	slapi_log_error(SLAPI_LOG_PLUGIN,
-			cbdata->state->plugin_desc->spd_id,
+			state->plugin_desc->spd_id,
 			"searching under \"%s\" for configuration\n",
-			cbdata->state->plugin_base);
+			state->plugin_base);
 	pb = wrap_pblock_new(cbdata->parent_pb);
 	slapi_search_internal_set_pb(pb,
-				     cbdata->state->plugin_base,
+				     state->plugin_base,
 				     LDAP_SCOPE_ONELEVEL,
 				     cbdata->filter,
 				     NULL, FALSE,
 				     NULL,
 				     NULL,
-				     cbdata->state->plugin_identity,
+				     state->plugin_identity,
 				     0);
-	if (map_wrlock() != 0) {
-		slapi_log_error(SLAPI_LOG_PLUGIN,
-				cbdata->state->plugin_desc->spd_id,
+	wrap_inc_call_level();
+	set_cbdata.state = state;
+	set_cbdata.pb = pb;
+
+	/* Do a search and collect found entries to avoid locking the backends */
+	if (slapi_search_internal_pb(pb) == 0) {
+		if (map_wrlock() != 0) {
+			slapi_log_error(SLAPI_LOG_PLUGIN,
+				state->plugin_desc->spd_id,
 				"failed to search under \"%s\" for "
 				"configuration: failed to acquire a lock\n",
-				cbdata->state->plugin_base);
-		goto done_with_lock;
+				state->plugin_base);
+			goto done_with_lock;
+		}
+		slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
+		if (result == 0) {
+			slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+			for (i = 0; entries[i] != NULL; i++) {
+				backend_set_config_entry_add_cb(entries[i], &set_cbdata);
+			}
+		}
+		map_unlock();
+		slapi_free_search_results_internal(pb);
 	}
-	set_cbdata.state = cbdata->state;
-	set_cbdata.pb = pb;
-	slapi_search_internal_callback_pb(pb, &set_cbdata,
-					  NULL,
-					  backend_set_config_entry_add_cb,
-					  NULL);
-	map_unlock();
+	slapi_log_error(SLAPI_LOG_FATAL,
+			state->plugin_desc->spd_id,
+			"Finished plugin initialization.\n");
+
 done_with_lock:
+	wrap_dec_call_level();
 	slapi_pblock_destroy(pb);
         if (cbdata) {
 		slapi_ch_free((void**)&cbdata);

commit 594fcb2320033d01cfe2b8121793d431d1017987
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Fri Jan 15 16:39:12 2016 +0200

    slapi-nis: process requests only when initialization completed
    
    Initializing map cache may take time. Skip slapi-nis lookups untli
    the map cache is ready.

diff --git a/src/back-sch.c b/src/back-sch.c
index 04fe667..871734c 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -1609,7 +1609,7 @@ backend_search_cb(Slapi_PBlock *pb)
 {
 	struct backend_search_cbdata cbdata;
 	struct backend_staged_search *staged, *next;
-	int i;
+	int i, isroot;
 
 	if (wrap_get_call_level() > 0) {
 		return 0;
@@ -1621,6 +1621,19 @@ backend_search_cb(Slapi_PBlock *pb)
 		/* The plugin was not actually started. */
 		return 0;
 	}
+	if (cbdata.state->ready_to_serve == 0) {
+		/* No data to serve yet */
+		return 0;
+	}
+
+	slapi_pblock_get(pb, SLAPI_REQUESTOR_ISROOT, &isroot);
+
+	if (slapi_op_internal(pb) || (slapi_is_ldapi_conn(pb) && isroot)) {
+		/* The plugin should not engage in internal searches of other
+		 * plugins or ldapi+cn=DM */
+		return 0;
+	}
+
 	slapi_pblock_get(pb, SLAPI_SEARCH_TARGET, &cbdata.target);
 	slapi_pblock_get(pb, SLAPI_SEARCH_SCOPE, &cbdata.scope);
 	slapi_pblock_get(pb, SLAPI_SEARCH_SIZELIMIT, &cbdata.sizelimit);
@@ -2018,6 +2031,10 @@ backend_write_cb(Slapi_PBlock *pb, struct plugin_state *state)
 	if (wrap_get_call_level() > 0) {
 		return 0;
 	}
+	if (state->ready_to_serve == 0) {
+		/* No data to serve yet */
+		return 0;
+	}
 
 	wrap_inc_call_level();
 	if (map_rdlock() == 0) {
@@ -2125,6 +2142,10 @@ backend_bind_cb(Slapi_PBlock *pb)
 	}
 
 	slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state);
+	if (state->ready_to_serve == 0) {
+		/* No data to serve yet */
+		return 0;
+	}
 	/* The code below handles three separate facts:
 	 * 1. For NSSWITCH-discovered users PAM is responsible for authentication.
 	 *    We want to run PAM auth without any slapi-nis lock taken to avoid
diff --git a/src/back-shr.c b/src/back-shr.c
index 36ecc0b..131365d 100644
--- a/src/back-shr.c
+++ b/src/back-shr.c
@@ -725,6 +725,8 @@ done_with_lock:
         if (cbdata) {
 		slapi_ch_free((void**)&cbdata);
         }
+
+	PR_AtomicSet(&state->ready_to_serve, 1);
 }
 
 static void
@@ -769,6 +771,7 @@ backend_shr_startup(struct plugin_state *state,
 		return;
 	}
 
+	PR_AtomicSet(&state->ready_to_serve, 0);
 	cbdata->state = state;
 	cbdata->parent_pb = parent_pb;
 	cbdata->filter = filter;
@@ -1798,6 +1801,11 @@ backend_shr_add_cb(Slapi_PBlock *pb)
 		/* The plugin was not actually started. */
 		return 0;
 	}
+	if (cbdata.state->ready_to_serve == 0) {
+		/* No data yet, ignore */
+		return 0;
+	}
+
 	slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &cbdata.e);
 	slapi_pblock_get(pb, SLAPI_ADD_TARGET, &dn);
 	slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &rc);
@@ -2208,6 +2216,10 @@ backend_shr_modify_cb(Slapi_PBlock *pb)
 		/* The plugin was not actually started. */
 		return 0;
 	}
+	if (cbdata.state->ready_to_serve == 0) {
+		/* No data yet, ignore */
+		return 0;
+	}
 	slapi_pblock_get(pb, SLAPI_MODIFY_TARGET, &dn);
 	slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &cbdata.mods);
 	slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &cbdata.e_pre);
@@ -2410,6 +2422,10 @@ backend_shr_modrdn_cb(Slapi_PBlock *pb)
 		/* The plugin was not actually started. */
 		return 0;
 	}
+	if (cbdata.state->ready_to_serve == 0) {
+		/* No data yet, ignore */
+		return 0;
+	}
 	slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &cbdata.e_pre);
 	slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &cbdata.e_post);
 
@@ -2549,6 +2565,10 @@ backend_shr_delete_cb(Slapi_PBlock *pb)
 		/* The plugin was not actually started. */
 		return 0;
 	}
+	if (cbdata.state->ready_to_serve == 0) {
+		/* No data yet, ignore */
+		return 0;
+	}
 	slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &cbdata.e);
 	slapi_pblock_get(pb, SLAPI_DELETE_TARGET, &dn);
 	slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &rc);
diff --git a/src/plugin.h b/src/plugin.h
index 429e291..7a89ac7 100644
--- a/src/plugin.h
+++ b/src/plugin.h
@@ -33,6 +33,7 @@ struct plugin_state {
 	Slapi_ComponentId *plugin_identity;
 	Slapi_PluginDesc *plugin_desc;
 	unsigned int use_be_txns: 1;
+	PRInt32 ready_to_serve;
 
 	/* NIS-specific data. */
 	struct wrapped_thread *tid;

commit d1b87904462e890a855ac9d3b68ed02e089450d8
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Wed Dec 23 15:04:40 2015 +0200

    slapi-nis: add support to resolve external members of IPA groups
    
    FreeIPA allows to include external (non-LDAP) members into POSIX groups.
    To define external members, an attribute ipaExternalMember is set to
    the list of references to external members. Currently both FreeIPA and
    SSSD support only references done with SIDs (Security Identifiers) from
    the forests trusted by FreeIPA.
    
    Resolving external members of FreeIPA groups requires resolving SIDs to
    user and group names. However, since this resolution is already
    implemented by SSSD for the group in question, slapi-nis can use the
    fact that there is non-empty ipaExternalMember attribute's value to
    trigger lookup of the FreeIPA group via SSSD and then copy over
    memberUid attribute value set.
    
    This logic requires that ipaExternalMember attribute value is present in
    the entry to be put into the map cache. Thus, an additional
    configuration is needed for the groups container:
    
    schema-compat-entry-attribute: ipaexternalmember=%deref_r("member","ipaexternalmember")
    
    Note that resolving external members of IPA groups requires to use
    version of slapi-nis that populates the map cache after LDAP server
    startup, as SSSD needs to talk back to the LDAP server in the process of
    resolving external group members and that is not possible at the time
    when slapi-nis plugin starts up as the LDAP server is not yet listenting
    for incoming connections at that point.

diff --git a/doc/ipa/sch-ipa.txt b/doc/ipa/sch-ipa.txt
index 106e6cc..eb6238a 100644
--- a/doc/ipa/sch-ipa.txt
+++ b/doc/ipa/sch-ipa.txt
@@ -81,6 +81,21 @@ 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.
 
+Additionally, group area configuration should include following two attributes to
+allow resolving external members of IPA groups:
+
+schema-compat-entry-attribute: ipaexternalmember=%deref_r("member","ipaexternalmember")
+schema-compat-entry-attribute: objectclass=ipaexternalgroup
+
+When 'ipaExternalMember' attribute is present in the group entry generated by
+Schema Compatibility plugin, the plugin will attempt to retrieve the group
+members from SSSD daemon. If group has non-empty list of members, these new
+members will replace the original ones as they will include both IPA and external
+group members.
+
+SSSD greater than 1.13.3 is required to produce correct behavior due to bug
+https://fedorahosted.org/sssd/ticket/2522
+
 == Authentication of the trusted domains' users ==
 
 When the Schema Compatibility Plugin is configured to expose users from trusted
diff --git a/src/back-sch.c b/src/back-sch.c
index 98542c5..04fe667 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -419,6 +419,115 @@ backend_set_operational_attributes(Slapi_Entry *e,
 	}
 }
 
+#ifdef USE_NSSWITCH
+#define IPA_ATTR_EXTERNAL_MEMBER "ipaExternalMember"
+#define IPA_ATTR_MEMBERUID "memberUid"
+static void
+backend_set_process_external_members(Slapi_PBlock *pb,
+				   Slapi_Entry *e,
+				   struct plugin_state *state,
+				   struct backend_set_data *data)
+{
+	Slapi_Attr *attr = NULL;
+	Slapi_ValueSet *valueset = NULL;
+	bool_t is_attr_exists, is_group_exists;
+	struct backend_staged_search staged = {0, };
+	struct backend_search_cbdata cbdata = {0, };
+	char *plugin_id = state->plugin_desc->spd_id;
+
+	is_attr_exists = slapi_entry_attr_find(e, IPA_ATTR_EXTERNAL_MEMBER, &attr) == 0;
+
+	if (!is_attr_exists || attr == NULL) {
+		return;
+	}
+
+	/* There are external members in this entry, do group lookup via SSSD
+	 * and update entry's memberUid attribute */
+
+	staged.name = slapi_entry_attr_get_charptr(e, "cn");
+	staged.type = SCH_NSSWITCH_GROUP;
+	staged.search_members = FALSE;
+	staged.is_id = FALSE;
+	staged.is_sid = FALSE;
+	staged.container_sdn = (char*) slapi_sdn_get_dn(data->container_sdn);
+	staged.entries = NULL;
+	staged.count = 0;
+	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);
+	cbdata.state = state;
+	cbdata.staged = &staged;
+
+	slapi_log_error(SLAPI_LOG_PLUGIN, plugin_id,
+			"refreshing group membership for group \"%s\"\n", staged.name);
+
+	do {
+		/* 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) {
+			slapi_log_error(SLAPI_LOG_PLUGIN, plugin_id,
+					"group \"%s\" does not exist because SSSD is offline.",
+					staged.name);
+			if (state->ready_to_serve == 0) {
+				/* Only wait for SSSD when we populate the original set */
+				slapi_log_error(SLAPI_LOG_PLUGIN, plugin_id,
+						"waiting for SSSD to become online...");
+				DS_Sleep(PR_SecondsToInterval(35));
+			} else {
+				break;
+			}
+		}
+	} while (!is_group_exists);
+
+	if (staged.entries != NULL && staged.entries[0] != NULL) {
+			attr = NULL;
+			if (slapi_entry_attr_find(staged.entries[0], IPA_ATTR_MEMBERUID, &attr) == 0) {
+#if 0
+				/* Debug output of original and updated memberUid values */
+				char **ary1, **ary2;
+				ary1 = slapi_entry_attr_get_charray(e, "memberUid");
+				ary2 = slapi_entry_attr_get_charray(staged.entries[0], "memberUid");
+
+				slapi_log_error(SLAPI_LOG_FATAL, plugin_id,
+						"original group \"%s\":\n", staged.name);
+				for (int i = 0; ary1 && ary1[i] != NULL; ++i) {
+					slapi_log_error(SLAPI_LOG_FATAL, plugin_id,
+							"\t> %s\n", ary1[i]);
+				}
+				slapi_log_error(SLAPI_LOG_FATAL, plugin_id,
+						"new group \"%s\":\n", staged.name);
+				for (int i = 0; ary2 && ary2[i] != NULL; ++i) {
+					slapi_log_error(SLAPI_LOG_FATAL, plugin_id,
+							"\t> %s\n", ary2[i]);
+				}
+				slapi_ch_array_free(ary2);
+				slapi_ch_array_free(ary1);
+#endif
+
+				(void)slapi_attr_get_valueset(attr, &valueset);
+
+				if (slapi_entry_attr_find(e, IPA_ATTR_MEMBERUID, &attr) == 0) {
+					(void) slapi_entry_attr_delete(e, IPA_ATTR_MEMBERUID);
+				}
+				(void) slapi_entry_add_valueset(e, IPA_ATTR_MEMBERUID, valueset);
+				slapi_valueset_free(valueset);
+			} else {
+				slapi_log_error(SLAPI_LOG_PLUGIN, plugin_id,
+						"group \"%s\" doesn't have memberUid attribute\n", staged.name);
+			}
+			slapi_entry_free(staged.entries[0]);
+	}
+
+	if (staged.entries != NULL) {
+		free(staged.entries);
+	}
+
+	(void)slapi_entry_attr_delete(e, IPA_ATTR_EXTERNAL_MEMBER);
+	free(cbdata.nsswitch_buffer);
+	slapi_ch_free_string(&staged.name);
+}
+#endif
+
 /* Given a map-entry directory entry, determine a key, a value, and extra data
  * to be stored in the map cache, and add them to the map cache. */
 static void
@@ -613,6 +722,9 @@ backend_set_entry_from(Slapi_PBlock *pb, enum backend_entry_source source,
 		slapi_entry_add_string(entry,
 				       "objectClass", "extensibleObject");
 	}
+#ifdef USE_NSSWITCH
+	backend_set_process_external_members(pb, entry, data->common.state, data);
+#endif
 	/* Clean up the entry by doing a round trip through the LDIF parser. */
 	ldif = slapi_entry2str(entry, &len);
 	slapi_entry_free(entry);

commit 52beb5e79905712a8aaabf19e52e654fc4648a94
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Fri Jan 15 16:16:00 2016 +0200

    nss: force lower case for memberUid attribute as per RFC2307
    
    When memberUid attribute is generated, it has to be normalized or
    otherwise searches for members against groups in compat tree will fail.
    slapi-nis already normalizes elements of a search filter that mention
    memberUid attribute values but the original memberUid value should be
    normalized as well.

diff --git a/src/back-sch-nss.c b/src/back-sch-nss.c
index 16d4164..702590c 100644
--- a/src/back-sch-nss.c
+++ b/src/back-sch-nss.c
@@ -246,8 +246,8 @@ backend_make_user_entry_from_nsswitch_passwd(struct passwd *pwd,
 		return NULL;
 	}
 
-	dn = backend_build_dn("uid", pwd->pw_name, container_sdn);
-	if (dn == NULL) {
+	name = (char *) slapi_utf8StrToLower((unsigned char *) pwd->pw_name);
+	if (name == NULL) {
 		slapi_log_error(SLAPI_LOG_FATAL,
 				cbdata->state->plugin_desc->spd_id,
 				"error building DN for uid=%s,%s skipping\n",
@@ -256,12 +256,22 @@ backend_make_user_entry_from_nsswitch_passwd(struct passwd *pwd,
 		return NULL;
 	}
 
+	dn = backend_build_dn("uid", name, container_sdn);
+	if (dn == NULL) {
+		slapi_log_error(SLAPI_LOG_FATAL,
+				cbdata->state->plugin_desc->spd_id,
+				"error building DN for uid=%s,%s skipping\n",
+				name, container_sdn);
+		slapi_entry_free(entry);
+		return NULL;
+	}
+
 	slapi_entry_add_string(entry,
 			       "objectClass", "top");
 	slapi_entry_add_string(entry,
 			       "objectClass", "posixAccount");
 	slapi_entry_add_string(entry,
-			       "uid", pwd->pw_name);
+			       "uid", name);
 	slapi_entry_attr_set_uint(entry,
 				 "uidNumber", pwd->pw_uid);
 	slapi_entry_attr_set_uint(entry,
@@ -286,6 +296,7 @@ backend_make_user_entry_from_nsswitch_passwd(struct passwd *pwd,
 	}
 
 	slapi_entry_set_dn(entry, dn);
+	slapi_ch_free_string(&name);
 
 #ifdef HAVE_SSS_NSS_IDMAP
 	rc = sss_nss_getsidbyid(pwd->pw_uid, &sid_str, &id_type);
@@ -520,6 +531,7 @@ backend_make_group_entry_from_nsswitch_group(struct group *grp,
 	Slapi_Entry *entry;
 	int rc, i;
 	char *dn = NULL;
+	char *name = NULL;
 #ifdef HAVE_SSS_NSS_IDMAP
 	enum sss_id_type id_type;
 	char *sid_str;
@@ -551,7 +563,9 @@ backend_make_group_entry_from_nsswitch_group(struct group *grp,
 
 	if (grp->gr_mem) {
 		for (i=0; grp->gr_mem[i]; i++) {
-			slapi_entry_add_string(entry, "memberUid", grp->gr_mem[i]);
+			name = (char *) slapi_utf8StrToLower((unsigned char*) grp->gr_mem[i]);
+			slapi_entry_add_string(entry, "memberUid", name);
+			slapi_ch_free_string(&name);
 		}
 	}
 

commit 2df48b57adb666112cab22e62750dd984fc7450a
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Wed Dec 23 14:57:03 2015 +0200

    slapi-nis: populate data trees asynchronously after LDAP server startup
    
    Currently slapi-nis design assumes the map cache is populated by
    scanning the original trees on plugin start up. This has few
    consequences:
       - LDAP server cannot serve LDAP clients until all plugins are
         initialized
    
       - slapi-nis cannot ask SSSD to resolve external identities at
         this point as SSSD will need to talk to the LDAP server which
         is at this point not listening for connections. SSSD will put
         whole IPA domain into offline and always will respond
         with negative result
    
    To solve these issues, schedule tree scan after LDAP server startup.
    The problem here is that it is not possible to reliably detect when
    389-ds starts to listen to the incoming connections. However, it is
    possible to schedule an event into 389-ds event queue that will run
    shortly after start of the event loop. Given that the call back function
    which is registered to be called is called within the event loop thread,
    one can fire off another thread and wait in the thread function some
    time until the LDAP server is ready for connections.
    
    The time interval is something that would depend on a specific
    deployment profile but experiments show that having 5 seconds delay
    should be enough as event queue is created just before starting the
    listeners.

diff --git a/src/back-shr.c b/src/back-shr.c
index c68640a..36ecc0b 100644
--- a/src/back-shr.c
+++ b/src/back-shr.c
@@ -664,40 +664,56 @@ backend_shr_get_vattr_sdnlist(struct plugin_state *state,
 	return ret;
 }
 
-/* Scan for the list of configured groups and sets. */
-void
-backend_shr_startup(struct plugin_state *state,
-		    Slapi_PBlock *parent_pb,
-		    const char *filter)
+struct backend_shr_data_init_cbdata {
+	Slapi_PBlock *parent_pb;
+	struct plugin_state *state;
+	const char *filter;
+};
+
+#define PLUGIN_SCAN_DELAY 5
+
+static void
+backend_shr_data_initialize_thread_cb(void *arg)
 {
-	Slapi_PBlock *pb;
+	struct backend_shr_data_init_cbdata *cbdata = (struct backend_shr_data_init_cbdata *)arg;
+	Slapi_PBlock *pb = NULL;
 	struct backend_set_config_entry_add_cbdata set_cbdata;
+	int result = 0;
+	if (cbdata == NULL) {
+		return;
+	}
+
+	/* Scan may require consulting SSSD for external identities
+	 * therefore, we need to make sure the scan starts after ns-slapd
+	 * started to serve LDAP clients. There is no a signal for this,
+	 * so we just wait some time. */
+	DS_Sleep(PR_SecondsToInterval(PLUGIN_SCAN_DELAY));
 
-	backend_update_params(parent_pb, state);
+	backend_update_params(cbdata->parent_pb, cbdata->state);
 
 	slapi_log_error(SLAPI_LOG_PLUGIN,
-			state->plugin_desc->spd_id,
+			cbdata->state->plugin_desc->spd_id,
 			"searching under \"%s\" for configuration\n",
-			state->plugin_base);
-	pb = wrap_pblock_new(parent_pb);
+			cbdata->state->plugin_base);
+	pb = wrap_pblock_new(cbdata->parent_pb);
 	slapi_search_internal_set_pb(pb,
-				     state->plugin_base,
+				     cbdata->state->plugin_base,
 				     LDAP_SCOPE_ONELEVEL,
-				     filter,
+				     cbdata->filter,
 				     NULL, FALSE,
 				     NULL,
 				     NULL,
-				     state->plugin_identity,
+				     cbdata->state->plugin_identity,
 				     0);
 	if (map_wrlock() != 0) {
 		slapi_log_error(SLAPI_LOG_PLUGIN,
-				state->plugin_desc->spd_id,
+				cbdata->state->plugin_desc->spd_id,
 				"failed to search under \"%s\" for "
 				"configuration: failed to acquire a lock\n",
-				state->plugin_base);
+				cbdata->state->plugin_base);
 		goto done_with_lock;
 	}
-	set_cbdata.state = state;
+	set_cbdata.state = cbdata->state;
 	set_cbdata.pb = pb;
 	slapi_search_internal_callback_pb(pb, &set_cbdata,
 					  NULL,
@@ -706,6 +722,68 @@ backend_shr_startup(struct plugin_state *state,
 	map_unlock();
 done_with_lock:
 	slapi_pblock_destroy(pb);
+        if (cbdata) {
+		slapi_ch_free((void**)&cbdata);
+        }
+}
+
+static void
+backend_shr_data_initialize_thread(time_t when, void *arg)
+{
+	struct backend_shr_data_init_cbdata *cbdata = (struct backend_shr_data_init_cbdata *)arg;
+	PRThread *thread = NULL;
+
+	/* start data import as a separate thread */
+	thread = PR_CreateThread(PR_USER_THREAD, backend_shr_data_initialize_thread_cb,
+			(void *)arg, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+			PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
+	if (thread == NULL) {
+		slapi_log_error(SLAPI_LOG_FATAL,
+				cbdata->state->plugin_desc->spd_id,
+				"unable to create compatibility tree scan thread!\n");
+	} else {
+		slapi_log_error(SLAPI_LOG_FATAL,
+				cbdata->state->plugin_desc->spd_id,
+				"%s tree scan will start in about %d seconds!\n",
+				cbdata->state->plugin_desc->spd_id, PLUGIN_SCAN_DELAY);
+	}
+
+}
+
+/* Scan for the list of configured groups and sets. */
+void
+backend_shr_startup(struct plugin_state *state,
+		    Slapi_PBlock *parent_pb,
+		    const char *filter)
+{
+	struct backend_shr_data_init_cbdata *cbdata = NULL;
+
+	cbdata = (struct backend_shr_data_init_cbdata *) 
+		 slapi_ch_malloc(sizeof(struct backend_shr_data_init_cbdata));
+
+	if (cbdata == NULL) {
+		slapi_log_error(SLAPI_LOG_FATAL,
+				state->plugin_desc->spd_id,
+				"failed to create a task for populating "
+				"compatibility tree\n");
+		return;
+	}
+
+	cbdata->state = state;
+	cbdata->parent_pb = parent_pb;
+	cbdata->filter = filter;
+
+	/* Schedule running a callback that will create a thread */
+	slapi_eq_once(backend_shr_data_initialize_thread,
+		      cbdata, PR_SecondsToInterval(PLUGIN_SCAN_DELAY));
+
+	slapi_log_error(SLAPI_LOG_FATAL,
+			cbdata->state->plugin_desc->spd_id,
+			"scheduled %s tree scan in about %d seconds after the server startup!\n",
+			state->plugin_desc->spd_id, PLUGIN_SCAN_DELAY);
+
+	return;
+
 }
 
 /* Process a set configuration directory entry.  Pull out the group and set
diff --git a/src/plug-sch.c b/src/plug-sch.c
index f132e6d..95a4fd8 100644
--- a/src/plug-sch.c
+++ b/src/plug-sch.c
@@ -109,8 +109,6 @@ plugin_startup(Slapi_PBlock *pb)
 			state->plugin_base ? "\"" : "",
 			state->plugin_base ? state->plugin_base : "NULL",
 			state->plugin_base ? "\"" : "");
-	/* 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);
 	if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
@@ -123,6 +121,8 @@ plugin_startup(Slapi_PBlock *pb)
 	wrap_rwlock_wrlock(state->cached_entries_lock);
 	state->cached_entries = PL_NewHashTable(0, PL_HashString, PL_CompareStrings, PL_CompareValues, 0, 0);
 	wrap_rwlock_unlock(state->cached_entries_lock);
+	/* Populate the tree of fake entries. */
+	backend_startup(pb, state);
 	/* Note that the plugin is ready to go. */
 	slapi_log_error(SLAPI_LOG_PLUGIN, plugin_description.spd_id,
 			"plugin startup completed\n");

commit da26d9595e6449009575e8d2a4c888176829a97f
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Tue Nov 3 14:42:05 2015 +0200

    slapi-nis: fix processing of ID views
    
    - ID View processing should only happen if ID view is defined
    - When finding attribute with slapi_entry_attr_find() use correct return
      code (slapi_entry_attr_exists() returns 1, _find() returns 0)
    - cn=<view>,cn=views,cn=compat,$SUFFIX lookup is fixed
    
    Resolves: rhbz#1277576, rhbz#1265465
    
    https://bugzilla.redhat.com/show_bug.cgi?id=1277576
    https://bugzilla.redhat.com/show_bug.cgi?id=1265465

diff --git a/src/back-sch-idview.c b/src/back-sch-idview.c
index 93fbab5..8ffab91 100644
--- a/src/back-sch-idview.c
+++ b/src/back-sch-idview.c
@@ -175,7 +175,7 @@ idview_process_overrides(struct backend_search_cbdata *cbdata,
 				/* Replace the attribute's value with the override or
 				 * add an override value if the attribute didn't exist */
 				result = slapi_entry_attr_find(entry, override_type, &sattr);
-				if (result == 1) {
+				if (result == 0) {
 					result = slapi_entry_attr_delete(entry, override_type);
 				}
 				result = slapi_attr_get_valueset(override_attr, &override_valueset);
diff --git a/src/back-sch.c b/src/back-sch.c
index b2362d0..98542c5 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -1043,17 +1043,21 @@ backend_search_entry_cb(const char *domain, const char *map, bool_t secure,
 				slapi_sdn_get_ndn(sdn));
 		entry = entry_data->e;
 #ifdef USE_IPA_IDVIEWS
-		entry = slapi_entry_dup(entry_data->e);
 		if (cbdata->idview != NULL) {
-			idview_process_overrides(cbdata, key, map, domain, entry);
-		}
+			entry = slapi_entry_dup(entry_data->e);



More information about the Pkg-freeipa-devel mailing list