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

Timo Aaltonen tjaalton at moszumanska.debian.org
Thu Dec 1 08:09:03 UTC 2016


 configure.ac       |    3 
 slapi-nis.spec     |   13 +-
 src/back-nis.c     |    6 +
 src/back-sch-nss.c |   14 ++
 src/back-sch.c     |  294 +++++++++++++++++++++++++++++++++++++++++++++++++----
 src/back-sch.h     |   20 +++
 src/back-shr.c     |  104 +++++++++++++++---
 src/back-shr.h     |    1 
 src/backend.h      |    1 
 src/plug-nis.c     |   34 ++++--
 src/plug-sch.c     |   58 +++++++++-
 src/plugin.h       |    3 
 src/wrap.c         |   90 ++++++++++++++++
 src/wrap.h         |    6 +
 14 files changed, 591 insertions(+), 56 deletions(-)

New commits:
commit 54b03fd9f5cf0e9d56bbeefd54adfb2f21c32974
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Sun Aug 7 23:36:08 2016 +0300

    Release 0.56.1

diff --git a/configure.ac b/configure.ac
index e5a4de7..f82a47e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT(slapi-nis,0.56)
+AC_INIT(slapi-nis,0.56.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 d945ad4..c50cd59 100644
--- a/slapi-nis.spec
+++ b/slapi-nis.spec
@@ -10,7 +10,7 @@
 %endif
 
 Name:		slapi-nis
-Version:	0.56
+Version:	0.56.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
+* Sun Aug 07 2016 Alexander Bokovoy <abokovoy at redhat.com> - 0.56.1-1
+- Support querying external users by UPN alias
+- Don't clobber target of the pblock for ID views
+
 * Mon Jun 20 2016 Alexander Bokovoy <abokovoy at redhat.com> - 0.56-1
 - Add priming thread to populate the map cache without blocking the DS
 - Add support for changing passwords for users from a primary tree

commit e6f9e2c9282905fa41046379e0bc5c2ac82ae3a9
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Wed Jul 27 17:37:14 2016 +0300

    back-sch-nss: for users with aliases, return alias as uid
    
    When SSSD resolves AD users on behalf of slapi-nis, it can accept
    any user identifier, including user principal name (UPN) which
    may be different than the canonical user name which SSSD returns.
    
    As result, the entry created by slapi-nis will be using canonical user
    name but the filter for search will refer to the original (aliased)
    name. The search will not match the newly created entry.
    
    Fix this issue by returning two values for 'uid' attribute: the
    canonical one and the aliased one. This way search will match.
    
    Verified that SSSD with id_provider=ldap happily consumes such entries.
    By LDAP schema, 'uid' attribute can have multiple values.
    
    Fixes https://fedorahosted.org/slapi-nis/ticket/12

diff --git a/src/back-sch-nss.c b/src/back-sch-nss.c
index 702590c..db63e59 100644
--- a/src/back-sch-nss.c
+++ b/src/back-sch-nss.c
@@ -230,6 +230,7 @@ backend_build_dn(const char *attribute, const char *value,
 static Slapi_Entry *
 backend_make_user_entry_from_nsswitch_passwd(struct passwd *pwd,
 					     char *container_sdn,
+					     char *user_name,
 					     struct backend_search_cbdata *cbdata)
 {
 	Slapi_Entry *entry;
@@ -272,6 +273,18 @@ backend_make_user_entry_from_nsswitch_passwd(struct passwd *pwd,
 			       "objectClass", "posixAccount");
 	slapi_entry_add_string(entry,
 			       "uid", name);
+	if (user_name != NULL) {
+		/* For non-NULL original user name check if it was
+		 * an alias/UPN. If so, add it to the entry.
+		 * Yes, LDAP schema allows multiple values of 'uid'
+		 * attribute.
+		 */
+		if (slapi_utf8casecmp((unsigned char*) user_name,
+				      (unsigned char*) name) != 0) {
+			slapi_entry_add_string(entry, "uid", user_name);
+		}
+	}
+
 	slapi_entry_attr_set_uint(entry,
 				 "uidNumber", pwd->pw_uid);
 	slapi_entry_attr_set_uint(entry,
@@ -510,6 +523,7 @@ repeat:
 	}
 
 	entry = backend_make_user_entry_from_nsswitch_passwd(&pwd, container_sdn,
+							     is_uid ? NULL : user_name,
 							     cbdata);
 	entries = malloc(sizeof(entries[0]) * 2);
 	if (entries != NULL) {

commit b59b9c87042cb8f4d99421e101349c5f48f91235
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Tue Jul 26 18:11:53 2016 +0300

    back-sch: do not clobber target of the pblock for idview
    
    When extracting idview all we care is the DN of new target.
    We don't really use the rewritten target as a string anymore,
    so there is no need to rewrite the string in the pblock.
    
    This fixes a bug when running with 389-ds 1.3.5.10+ which is more
    strict about modification of the values in pblock.
    
    Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1360245

diff --git a/src/back-sch.c b/src/back-sch.c
index 0745329..e15988f 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -1652,6 +1652,8 @@ backend_search_cb(Slapi_PBlock *pb)
 	struct backend_search_cbdata cbdata;
 	struct backend_staged_search *staged, *next;
 	int i, isroot, ret;
+	char *original_target = NULL;
+	char *target = NULL;
 
 	if (wrap_get_call_level() > 0) {
 		return 0;
@@ -1676,7 +1678,7 @@ backend_search_cb(Slapi_PBlock *pb)
 		return 0;
 	}
 
-	slapi_pblock_get(pb, SLAPI_SEARCH_TARGET, &cbdata.target);
+	slapi_pblock_get(pb, SLAPI_SEARCH_TARGET, &original_target);
 	slapi_pblock_get(pb, SLAPI_SEARCH_SCOPE, &cbdata.scope);
 	slapi_pblock_get(pb, SLAPI_SEARCH_SIZELIMIT, &cbdata.sizelimit);
 	slapi_pblock_get(pb, SLAPI_SEARCH_TIMELIMIT, &cbdata.timelimit);
@@ -1697,15 +1699,15 @@ backend_search_cb(Slapi_PBlock *pb)
 	/* Okay, we can search. */
 	slapi_log_error(SLAPI_LOG_PLUGIN, cbdata.state->plugin_desc->spd_id,
 			"searching from \"%s\" for \"%s\" with scope %d%s\n",
-			cbdata.target, cbdata.strfilter, cbdata.scope,
+			original_target, cbdata.strfilter, cbdata.scope,
 			backend_sch_scope_as_string(cbdata.scope));
-	cbdata.target_dn = slapi_sdn_new_dn_byval(cbdata.target);
+	cbdata.target_dn = slapi_sdn_new_dn_byval(original_target);
 	/* Check if there's a backend handling this search. */
 	if (!slapi_be_exist(cbdata.target_dn)) {
 		slapi_log_error(SLAPI_LOG_PLUGIN,
 				cbdata.state->plugin_desc->spd_id,
 				"slapi_be_exists(\"%s\") = 0, "
-				"ignoring search\n", cbdata.target);
+				"ignoring search\n", original_target);
 		slapi_sdn_free(&cbdata.target_dn);
 		return 0;
 	}
@@ -1716,22 +1718,23 @@ backend_search_cb(Slapi_PBlock *pb)
 	 * 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);
+		target = slapi_ch_strdup(original_target);
+		idview_replace_target_dn(&target, &cbdata.idview);
 		if (cbdata.idview != NULL) {
 			slapi_sdn_free(&cbdata.target_dn);
 			/* Perform another check, now for rewritten DN */
-			cbdata.target_dn = slapi_sdn_new_dn_byval(cbdata.target);
+			cbdata.target_dn = slapi_sdn_new_dn_byval(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,
+						cbdata.idview, 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(&target);
 				slapi_ch_free_string(&cbdata.idview);
 				slapi_log_error(SLAPI_LOG_PLUGIN,
 						cbdata.state->plugin_desc->spd_id,
@@ -1739,6 +1742,8 @@ backend_search_cb(Slapi_PBlock *pb)
 						"ignoring search\n");
 				return 0;
 			}
+		} else {
+			slapi_ch_free_string(&target);
 		}
 	}
 	cbdata.answer = FALSE;
@@ -1890,7 +1895,7 @@ backend_search_cb(Slapi_PBlock *pb)
 	}
 	slapi_sdn_free(&cbdata.target_dn);
 	if (cbdata.idview != NULL) {
-		slapi_ch_free_string(&cbdata.target);
+		slapi_ch_free_string(&target);
 	}
 	slapi_ch_free_string(&cbdata.idview);
 #ifdef USE_IPA_IDVIEWS
@@ -1904,7 +1909,6 @@ backend_search_cb(Slapi_PBlock *pb)
 /* Locate the entry for a given DN. */
 struct backend_locate_cbdata {
 	struct plugin_state *state;
-	char *target;
 	Slapi_DN *target_dn;
 
 	struct backend_entry_data *entry_data;
@@ -1953,6 +1957,7 @@ static void
 backend_locate(Slapi_PBlock *pb, struct backend_entry_data **data, const char **group, const char**set)
 {
 	struct backend_locate_cbdata cbdata;
+	char *original_target = NULL;
 
 	slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &cbdata.state);
 	if (cbdata.state->plugin_base == NULL) {
@@ -1960,9 +1965,9 @@ backend_locate(Slapi_PBlock *pb, struct backend_entry_data **data, const char **
 		*data = NULL;
 		return;
 	}
-	slapi_pblock_get(pb, SLAPI_TARGET_DN, &cbdata.target);
+	slapi_pblock_get(pb, SLAPI_TARGET_DN, &original_target);
 
-	cbdata.target_dn = slapi_sdn_new_dn_byval(cbdata.target);
+	cbdata.target_dn = slapi_sdn_new_dn_byval(original_target);
 	cbdata.entry_data = NULL;
 	cbdata.entry_group = NULL;
 	cbdata.entry_set = NULL;
@@ -1972,12 +1977,9 @@ backend_locate(Slapi_PBlock *pb, struct backend_entry_data **data, const char **
 	 * 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);
+		char *target = NULL;
+		target = slapi_ch_strdup(original_target);
 		idview_replace_target_dn(&target, &idview);
-		if (target != original_target) {
-			slapi_ch_free_string(&original_target);
-		}
 		if (idview != NULL) {
 			char *rdnstr;
 			char *val;
@@ -1992,7 +1994,6 @@ backend_locate(Slapi_PBlock *pb, struct backend_entry_data **data, const char **
 					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);
@@ -2025,7 +2026,6 @@ backend_locate(Slapi_PBlock *pb, struct backend_entry_data **data, const char **
  * insufficient-access error. */
 struct backend_group_check_scope_cbdata {
 	struct plugin_state *state;
-	const char *target;
 	Slapi_DN *target_dn;
 	bool_t ours;
 };
@@ -2050,14 +2050,15 @@ static bool_t
 backend_check_scope_pb(Slapi_PBlock *pb)
 {
 	struct backend_group_check_scope_cbdata cbdata;
+	char *original_target = NULL;
 
 	slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &cbdata.state);
 	if (cbdata.state->plugin_base == NULL) {
 		/* The plugin was not actually started. */
 		return FALSE;
 	}
-	slapi_pblock_get(pb, SLAPI_TARGET_DN, &cbdata.target);
-	cbdata.target_dn = slapi_sdn_new_dn_byval(cbdata.target);
+	slapi_pblock_get(pb, SLAPI_TARGET_DN, &original_target);
+	cbdata.target_dn = slapi_sdn_new_dn_byval(original_target);
 	cbdata.ours = FALSE;
 	map_data_foreach_domain(cbdata.state, backend_group_check_scope_cb,
 				&cbdata);
diff --git a/src/back-sch.h b/src/back-sch.h
index 1258ae0..9a9abc7 100644
--- a/src/back-sch.h
+++ b/src/back-sch.h
@@ -88,7 +88,7 @@ struct entries_to_send {
 struct backend_search_cbdata {
 	Slapi_PBlock *pb;
 	struct plugin_state *state;
-	char *target, *strfilter, **attrs;
+	char *strfilter, **attrs;
 	char *idview;
 	Slapi_Entry **overrides;
 	int scope, sizelimit, timelimit, attrsonly;

commit 66177cbab545374ccc0bcacdd7a8ffea1ca7be6d
Author: Thierry Bordaz <tbordaz at redhat.com>
Date:   Tue Jul 12 11:43:28 2016 +0200

    Double free on ldap entry during priming
    
    During Schema-compat cache priming, If it exists an associated domain
    the entry returned by the internal search is freed twice.
    
    This was introduced in order for slapi-nis to resolve IPA groups with
    fully qualified suffix. To support SSSD 1.14+ change of logic to handle
    a default domain suffix.

diff --git a/src/back-sch.c b/src/back-sch.c
index cdd2b3c..0745329 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -284,15 +284,13 @@ backend_set_config_read_config(struct plugin_state *state, Slapi_Entry *e,
 				slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
 				if (result == 0) {
 					slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
-					slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, NULL);
 					for (j=0; entries[j] != NULL; j++) {
 						ret.associated_domain = slapi_entry_attr_get_charptr(entries[j], "associatedDomain");
-						slapi_entry_free(entries[i]);
 						if (ret.associated_domain != NULL)
 							break;
 					}
-					slapi_ch_free((void**)entries);
 				}
+				slapi_free_search_results_internal(pb);
 			}
 			slapi_pblock_destroy(pb);
 			pb = NULL;

commit 11df81960498e3e570e2ba46a2e80b7549fd16c1
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Mon Jun 20 21:45:37 2016 +0300

    Declare int backend_init_extop for reuse in plug-sch.c

diff --git a/src/back-sch.h b/src/back-sch.h
index c15d1ed..1258ae0 100644
--- a/src/back-sch.h
+++ b/src/back-sch.h
@@ -164,6 +164,7 @@ bool_t backend_retrieve_from_nsswitch(struct backend_staged_search *staged,
 				      struct backend_search_cbdata *cbdata);
 
 int backend_sch_do_pam_auth(Slapi_PBlock *pb, const char *username);
+int backend_init_extop(Slapi_PBlock *pb, struct plugin_state *state);
 
 #ifdef USE_IPA_IDVIEWS
 void idview_get_overrides(struct backend_search_cbdata *cbdata);

commit 0a5e61c042679679646f6f8f673028f8fbcf3ea7
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Wed Jun 15 12:15:46 2016 +0300

    slapi-nis: resolve IPA groups with fully qualified suffix
    
    With SSSD 1.14+ there is a logic change to handling of a default domain
    suffix.
    
    SSSD has two different formats to handle: the input and output. The
    input format is parsed into (name,domain) tuples with the re_expression
    option and the output is formatted with the full_name_format option.
    
    Because of the way SSSD used to store the usernames in sysdb, it was
    tied to the full_name_format option, just changing the output format
    changed the way the names are stored internally. SSSD changed the cache
    to always store names in a unified format (foo at bar) and use the
    full_name_format only for output, as it should be.
    
    This changed a logic of use_fully_qualified_names=True. It now mandates
    that the /input/ contains both the name and the domain part and then
    SSSD formats the output using the full_name_format option. The
    default_domain_suffix is a hack that just appends its value to an
    unqualified input, making all queries for "foo" into "foo at bar".
    
    In new SSSD if configuration contains:
        default_domain_suffix = win.domain
        full_name_format = $1 # only name
    
    then a request for "foo" will internally turn into "foo at win.domain" but
    return "foo" on the output. However, queries for IPA's foo will have to
    be qualified by the admin manually like "foo at ipa.domain" otherwise sssd
    doesn't know which foo you meant.
    
    Support this logic by querying associatedDomain attribute of the
    restricted bases of the data set. IPA stores this information in the
    $SUFFIX base dn (dc=example,dc=com) and configures slapi-nis with
    restricted base set to $SUFFIX (and the plugin config). While
    associatedDomain attribute is multivalued, the $SUFFIX object always has
    a single value corresponding to the IPA domain name that is the same as
    SSSD domain suffix.

diff --git a/src/back-sch.c b/src/back-sch.c
index bb2aa74..cdd2b3c 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -98,6 +98,7 @@ backend_set_config_free_config_contents(void *data)
 		slapi_sdn_free(&set_data->container_sdn);
 		free(set_data->rdn_format);
 		backend_shr_free_strlist(set_data->attribute_format);
+		slapi_ch_free_string(&set_data->associated_domain);
 	}
 }
 void
@@ -149,6 +150,7 @@ backend_copy_set_config(const struct backend_set_data *data)
 	ret->check_access = data->check_access;
 	ret->check_nsswitch = data->check_nsswitch;
 	ret->nsswitch_min_id = data->nsswitch_min_id;
+	ret->associated_domain = data->associated_domain ? slapi_ch_strdup(data->associated_domain) : NULL;
 
 	if ((ret->common.group == NULL) ||
 	    (ret->common.set == NULL) ||
@@ -266,6 +268,39 @@ backend_set_config_read_config(struct plugin_state *state, Slapi_Entry *e,
 		free(nsswitch_min_id);
 	}
 
+	ret.associated_domain = NULL;
+	if (ret.common.restrict_subtrees != NULL) {
+		Slapi_PBlock *pb = NULL;
+		int result = 0;
+		Slapi_Entry **entries = NULL;
+		int i,j;
+		for (i=0; ret.common.restrict_subtrees[i] != NULL; i++) {
+			pb = wrap_pblock_new(NULL);
+			if (pb != NULL) {
+				slapi_search_internal_set_pb_ext(pb, (Slapi_DN*) ret.common.restrict_subtrees[i], LDAP_SCOPE_BASE,
+								 "(&(objectclass=domainRelatedObject)(associatedDomain=*))",
+								 NULL, 0, NULL, NULL, state->plugin_identity, 0);
+				result = slapi_search_internal_pb(pb);
+				slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
+				if (result == 0) {
+					slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+					slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, NULL);
+					for (j=0; entries[j] != NULL; j++) {
+						ret.associated_domain = slapi_entry_attr_get_charptr(entries[j], "associatedDomain");
+						slapi_entry_free(entries[i]);
+						if (ret.associated_domain != NULL)
+							break;
+					}
+					slapi_ch_free((void**)entries);
+				}
+			}
+			slapi_pblock_destroy(pb);
+			pb = NULL;
+			if (ret.associated_domain != NULL)
+				break;
+		}
+	}
+
 	*pret = backend_copy_set_config(&ret);
 	if (*pret == NULL) {
 		if (strlen(container) > 0) {
@@ -437,6 +472,7 @@ backend_set_process_external_members(Slapi_PBlock *pb,
 	struct backend_staged_search staged = {0, };
 	struct backend_search_cbdata cbdata = {0, };
 	char *plugin_id = state->plugin_desc->spd_id;
+	char *gname = NULL;
 
 	is_attr_exists = slapi_entry_attr_find(e, IPA_ATTR_EXTERNAL_MEMBER, &attr) == 0;
 
@@ -448,6 +484,11 @@ backend_set_process_external_members(Slapi_PBlock *pb,
 	 * and update entry's memberUid attribute */
 
 	staged.name = slapi_entry_attr_get_charptr(e, "cn");
+	if (data->associated_domain != NULL) {
+		gname = slapi_ch_smprintf("%s@%s", staged.name, data->associated_domain);
+		slapi_ch_free_string(&staged.name);
+		staged.name = gname;
+	}
 	staged.type = SCH_NSSWITCH_GROUP;
 	staged.search_members = FALSE;
 	staged.is_id = FALSE;
diff --git a/src/back-sch.h b/src/back-sch.h
index 72ba641..c15d1ed 100644
--- a/src/back-sch.h
+++ b/src/back-sch.h
@@ -38,6 +38,7 @@ struct backend_set_data {
 	bool_t check_access;
 	enum sch_search_nsswitch_t check_nsswitch;
 	unsigned long nsswitch_min_id;
+        char *associated_domain;
 };
 
 struct backend_entry_data {

commit 95cced2f956b56b076bc7a33f281d71a6002d935
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Mon Jun 20 21:41:35 2016 +0300

    Initialize ret before use

diff --git a/src/back-sch.c b/src/back-sch.c
index ff8e8a2..bb2aa74 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -2376,7 +2376,7 @@ static int
 backend_extop_cb(Slapi_PBlock *pb)
 {
 	struct plugin_state *state;
-	int ret;
+	int ret = 0;
 	int i;
 	char *oid = NULL;
 	IFP fct = NULL;

commit 4a57f466a668d5a73436c3f13a17c8f2ca95628b
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Mon Jun 20 21:41:12 2016 +0300

    Move advance definition of backend_passwdmod_extop before use

diff --git a/src/back-sch.c b/src/back-sch.c
index 5ba04f4..ff8e8a2 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -54,6 +54,7 @@
 #include "map.h"
 #include "back-sch.h"
 
+static int backend_passwdmod_extop(Slapi_PBlock *pb);
 backend_extop_handlers_t extop_handlers[] = {{EXTOP_PASSWD_OID, (IFP) backend_passwdmod_extop},
 					    {NULL, NULL}};
 static void

commit 1dbb78cfdb4f4f06ffa0e5255c2adce060a7c1bf
Author: Alexander Bokovoy <abokovoy at redhat.com>
Date:   Mon Jun 20 17:35:58 2016 +0300

    Release 0.56

diff --git a/configure.ac b/configure.ac
index 9ce6bcf..e5a4de7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT(slapi-nis,0.55)
+AC_INIT(slapi-nis,0.56)
 AC_CONFIG_MACRO_DIR([m4])
 AM_INIT_AUTOMAKE(foreign)
 LT_INIT([disable-static])
diff --git a/slapi-nis.spec b/slapi-nis.spec
index 2546509..d945ad4 100644
--- a/slapi-nis.spec
+++ b/slapi-nis.spec
@@ -10,7 +10,7 @@
 %endif
 
 Name:		slapi-nis
-Version:	0.55
+Version:	0.56
 Release:	1%{?dist}
 Summary:	NIS Server and Schema Compatibility plugins for Directory Server
 Group:		System Environment/Daemons
@@ -19,7 +19,7 @@ URL:		http://slapi-nis.fedorahosted.org/
 Source0:	https://fedorahosted.org/releases/s/l/slapi-nis/slapi-nis-%{version}.tar.gz
 #Source1:	https://fedorahosted.org/releases/s/l/slapi-nis/slapi-nis-%{version}.tar.gz.sig
 BuildRoot:	%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-BuildRequires:	389-ds-base-devel, %{ldap_impl}-devel
+BuildRequires:	389-ds-base-devel > 1.3.5.6, %{ldap_impl}-devel
 BuildRequires:	nspr-devel, nss-devel, /usr/bin/rpcgen
 %if 0%{?fedora} > 18 || 0%{?rhel} > 6
 BuildRequires:	libsss_nss_idmap-devel
@@ -85,6 +85,11 @@ rm -rf $RPM_BUILD_ROOT
 %{_sbindir}/nisserver-plugin-defs
 
 %changelog
+* Mon Jun 20 2016 Alexander Bokovoy <abokovoy at redhat.com> - 0.56-1
+- Add priming thread to populate the map cache without blocking the DS
+- Add support for changing passwords for users from a primary tree
+  - requires DS 1.3.5.6 or later
+
 * 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

commit c129f8447fb8ca16189e05010e3f3d7def1f7a64
Author: Thierry Bordaz <tbordaz at redhat.com>
Date:   Mon Jun 13 18:13:04 2016 +0200

    slapi-nis should allow password update on a virtual entry
    
    During password modification ext. op (1.3.6.1.4.1.4203.1.11.1),
    if the target entry is in the compat tree, slapi-nis should
    remap the entry to the real entry.
    
    This needs to be done in a pre-op extop that calls the callback
    function handling a given OID.
    The password mod. callback does a reverse mapping of
    extop USERID and set it in SLAPI_TARGET_SDN.
    
    https://fedorahosted.org/freeipa/ticket/5955

diff --git a/configure.ac b/configure.ac
index 5b10376..9ce6bcf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -113,6 +113,7 @@ dirsrv)
 			SLAPI_PLUGIN_BE_TXN_POST_MODIFY_FN,
 			SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN,
 			SLAPI_PLUGIN_BE_TXN_POST_DELETE_FN,
+			SLAPI_PLUGIN_PRE_EXTOP_FN,
 			NULL]
 		       ,,,
 		       [AC_INCLUDES_DEFAULT
diff --git a/src/back-sch.c b/src/back-sch.c
index 32b1d9e..5ba04f4 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -54,6 +54,8 @@
 #include "map.h"
 #include "back-sch.h"
 
+backend_extop_handlers_t extop_handlers[] = {{EXTOP_PASSWD_OID, (IFP) backend_passwdmod_extop},
+					    {NULL, NULL}};
 static void
 backend_entries_to_return_push(struct backend_search_cbdata *cbdata, Slapi_Entry *e);
 
@@ -2223,6 +2225,191 @@ done_with_lock:
 	return ret;
 }
 
+/* This callback handles EXTOP_PASSWD_OID "1.3.6.1.4.1.4203.1.11.1"
+ * If the extop defines a USERID, it sets SLAPI_TARGET_SDN to
+ * the reverse mapping of the USERID.
+ *
+ * If it is not possible to retrieve USERID in the ber
+ * then value of SLAPI_TARGET_SDN is unchanged.
+ *
+ * Else the value of SLAPI_TARGET_SDN is freed and replaced
+ * either by the USERID or the reverse mapping of USERID (if it exists)
+ */
+static int
+backend_passwdmod_extop(Slapi_PBlock *pb)
+{
+	struct backend_entry_data *data;
+	struct plugin_state *state;
+	Slapi_DN *sdn = NULL;
+	char *extopdn;
+	char *ndn;
+	const char *entry_group = NULL;
+	const char *entry_set = NULL;
+	struct berval	*extop_value = NULL;
+	BerElement	*ber = NULL;
+	ber_tag_t	tag = 0;
+        ber_len_t	len = (ber_len_t) -1;
+
+	if (wrap_get_call_level() > 0) {
+		return 0;
+	}
+
+	slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state);
+	if (state->ready_to_serve == 0) {
+		/* No data to serve yet */
+		goto free_and_return;
+	}
+	/* Retrieve the original DN from the ber request */
+	/* Get the ber value of the extended operation */
+	slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value);
+	if (!BV_HAS_DATA(extop_value)) {
+		goto free_and_return;
+	}
+
+        if ((ber = ber_init(extop_value)) == NULL) {
+		goto free_and_return;
+	}
+
+	/* Format of request to parse
+	 *
+	 * PasswdModifyRequestValue ::= SEQUENCE {
+	 * userIdentity    [0]  OCTET STRING OPTIONAL
+	 * oldPasswd       [1]  OCTET STRING OPTIONAL
+	 * newPasswd       [2]  OCTET STRING OPTIONAL }
+	 *
+	 * The request value field is optional. If it is
+	 * provided, at least one field must be filled in.
+	 */
+
+	/* ber parse code */
+	if ( ber_scanf( ber, "{") == LBER_ERROR ) {
+		/* The request field wasn't provided.  We'll
+		 * now try to determine the userid and verify
+		 * knowledge of the old password via other
+		 * means.
+		 */
+		goto free_and_return;
+	} else {
+		tag = ber_peek_tag( ber, &len);
+	}
+
+	/* identify userID field by tags */
+	if (tag == LDAP_EXTOP_PASSMOD_TAG_USERID ) {
+
+		if ( ber_scanf( ber, "a", &extopdn) == LBER_ERROR ) {
+			slapi_ch_free_string(&extopdn);
+			goto free_and_return;
+		}
+
+                slapi_log_error(SLAPI_LOG_PLUGIN, "backend_passwdmod_extop",
+			"extopdn = %s\n", extopdn ? extopdn : "<unknown>" );
+
+		/* Free the current target_DN */
+		slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
+		if (sdn) {
+			const char *olddn;
+			olddn = slapi_sdn_get_ndn(sdn);
+			slapi_log_error(SLAPI_LOG_PLUGIN, "backend_passwdmod_extop",
+							  "olddn = %s (unknown expected)\n", olddn ? olddn : "<unknown>" );
+			slapi_sdn_free(&sdn);
+		}
+
+		/* replace it with the one in the extop req*/
+		sdn = slapi_sdn_new_dn_byref(extopdn);
+		slapi_pblock_set(pb, SLAPI_TARGET_SDN, sdn);
+	} else {
+		/* we can not retrieve the USERID */
+		goto free_and_return;
+	}
+
+	wrap_inc_call_level();
+	if (map_rdlock() != 0) {
+		slapi_log_error(SLAPI_LOG_FATAL, state->plugin_desc->spd_id,
+				"backend_passwdmod_extop unable to acquire read lock\n");
+		wrap_dec_call_level();
+		goto free_and_return;
+	}
+	backend_locate(pb, &data, &entry_group, &entry_set);
+	if (data != NULL) {
+		/* If there is a mapping to a real entry
+		 * ndn will contains its DN
+		 */
+		if (slapi_sdn_get_ndn(data->original_entry_dn)) {
+			ndn = slapi_ch_strdup(slapi_sdn_get_ndn(data->original_entry_dn));
+		} else {
+			ndn = NULL;
+		}
+		slapi_log_error(SLAPI_LOG_PLUGIN, "backend_passwdmod_extop",
+				"reverse mapped dn = %s\n", ndn ? ndn : "<unknown>" );
+
+		/* the rest does not require to hold the map lock */
+		map_unlock();
+		wrap_dec_call_level();
+
+		if (ndn) {
+			/* replace the TARGET_SDN by the one found in the map
+			 * This is the responsibility of the extop to free it
+			 */
+			slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn);
+			if (sdn != NULL) {
+				slapi_sdn_free(&sdn);
+			}
+			sdn = slapi_sdn_new_dn_byref(ndn);
+			slapi_pblock_set(pb, SLAPI_TARGET_SDN, (void*) sdn);
+		}
+	} else {
+		/* no mapping entry to real entry, this is fine */
+		map_unlock();
+		wrap_dec_call_level();
+	}
+
+free_and_return:
+
+	if ( ber != NULL ){
+		ber_free(ber, 1);
+		ber = NULL;
+	}
+	return 0;
+}
+static int
+backend_extop_cb(Slapi_PBlock *pb)
+{
+	struct plugin_state *state;
+	int ret;
+	int i;
+	char *oid = NULL;
+	IFP fct = NULL;
+
+	slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state);
+	if (state->ready_to_serve == 0) {
+		/* No data to serve yet */
+		return 0;
+	}
+
+	/* First check this is a supported OID (for slapi-nis) */
+	if ( slapi_pblock_get( pb, SLAPI_EXT_OP_REQ_OID, &oid ) != 0 )
+	{
+		slapi_log_error( SLAPI_LOG_FATAL, state->plugin_desc->spd_id, "Could not get OID from request\n" );
+		return 0;
+	}
+
+	for (i = 0; extop_handlers[i].oid != NULL; i++) {
+		if (strcmp( oid, extop_handlers[i].oid) == 0 ) {
+			fct = extop_handlers[i].extop_fct;
+			break;
+		}
+	}
+
+	if (fct) {
+		ret = fct(pb);
+		if (ret) {
+			slapi_log_error( SLAPI_LOG_FATAL, "backend_extop_cb",
+				 "pre-extop for %s failed %d\n", oid, ret );
+		}
+	}
+	return (ret);
+}
+
 static int
 backend_compare_cb(Slapi_PBlock *pb)
 {
@@ -2286,6 +2473,24 @@ backend_shutdown(struct plugin_state *state)
     backend_shr_shutdown(state);
 }
 
+#ifndef SLAPI_PLUGIN_PRE_EXTOP_FN
+#define SLAPI_PLUGIN_PRE_EXTOP_FN  413
+#endif
+int
+backend_init_extop(Slapi_PBlock *pb, struct plugin_state *state)
+{
+	slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+			"hooking up extop callbacks\n");
+	/* Intercept extended operation requests */
+	if (slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_EXTOP_FN,
+			     backend_extop_cb) != 0) {
+		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+				"error hooking up pre extop callback\n");
+		return -1;
+	}
+	return 0;
+}
+
 int
 backend_init_preop(Slapi_PBlock *pb, struct plugin_state *state)
 {
diff --git a/src/back-sch.h b/src/back-sch.h
index e8ec400..72ba641 100644
--- a/src/back-sch.h
+++ b/src/back-sch.h
@@ -127,6 +127,22 @@ struct backend_search_filter_config {
 	void *callback_data;
 };
 
+/* OIDs of the supported extended operation */
+#define EXTOP_PASSWD_OID	"1.3.6.1.4.1.4203.1.11.1"
+
+/* ber tags for the PasswdModifyRequestValue sequence */
+#define LDAP_EXTOP_PASSMOD_TAG_USERID	0x80U
+#define LDAP_EXTOP_PASSMOD_TAG_OLDPWD	0x81U
+#define LDAP_EXTOP_PASSMOD_TAG_NEWPWD	0x82U
+
+typedef int (*IFP)();
+static int backend_passwdmod_extop(Slapi_PBlock *pb);
+typedef struct backend_extop_handlers {
+    char *oid;
+    IFP extop_fct;
+} backend_extop_handlers_t;
+
+
 /* Analyzes the filter to decide what kind of NSS search is it
  * Returns 0 on success, 1 on failure
  * struct backend_search_filter_config is populated with information about the filter
diff --git a/src/plug-sch.c b/src/plug-sch.c
index 7af8480..00e7041 100644
--- a/src/plug-sch.c
+++ b/src/plug-sch.c
@@ -65,6 +65,7 @@
 #define PLUGIN_BETXN_POSTOP_ID PLUGIN_ID "-betxn_postop"
 #define PLUGIN_POSTOP_ID PLUGIN_ID "-postop"
 #define PLUGIN_INTERNAL_POSTOP_ID PLUGIN_ID "-internal-postop"
+#define PLUGIN_PRE_EXTOP_ID PLUGIN_ID "-extop-preop"
 
 /* the module initialization function */
 static Slapi_PluginDesc
@@ -185,6 +186,20 @@ plugin_shutdown(Slapi_PBlock *pb)
 			"plugin shutdown completed\n");
 	return 0;
 }
+static int
+schema_compat_plugin_init_extop(Slapi_PBlock *pb)
+{
+	slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_03);
+	slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, &plugin_description);
+	slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, global_plugin_state);
+	if (backend_init_extop(pb, global_plugin_state) == -1) {
+		slapi_log_error(SLAPI_LOG_PLUGIN,
+				global_plugin_state->plugin_desc->spd_id,
+				"error registering extop hooks\n");
+		return -1;
+	}
+	return 0;
+}
 
 static int
 schema_compat_plugin_init_preop(Slapi_PBlock *pb)
@@ -343,6 +358,15 @@ schema_compat_plugin_init(Slapi_PBlock *pb)
 		return -1;
 	}
 #endif
+	if (slapi_register_plugin("preextendedop", TRUE,
+				  "schema_compat_plugin_init_extop",
+				  schema_compat_plugin_init_extop,
+				  PLUGIN_PRE_EXTOP_ID, NULL,
+				  state->plugin_identity) != 0) {
+		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+				"error registering extop plugin\n");
+		return -1;
+	}
 	slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
 			"registered plugin hooks\n");
 	global_plugin_state = NULL;

commit c2dfe9836596565edea1fe7c2bffca3efc6839e2
Author: Thierry Bordaz <tbordaz at redhat.com>
Date:   Tue Apr 26 13:17:46 2016 +0300

    schema-compat: add backend shutdown support for priming thread
    
    Resolves: rhbz#1327197

diff --git a/src/back-sch.c b/src/back-sch.c
index 9a0e96b..32b1d9e 100644
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -2280,6 +2280,12 @@ backend_startup(Slapi_PBlock *pb, struct plugin_state *state)
 	backend_shr_startup(state, pb, SCH_CONTAINER_CONFIGURATION_FILTER);
 }
 
+void
+backend_shutdown(struct plugin_state *state)
+{
+    backend_shr_shutdown(state);
+}
+
 int
 backend_init_preop(Slapi_PBlock *pb, struct plugin_state *state)
 {
diff --git a/src/plug-sch.c b/src/plug-sch.c
index 95a4fd8..7af8480 100644
--- a/src/plug-sch.c
+++ b/src/plug-sch.c
@@ -102,13 +102,26 @@ plugin_startup(Slapi_PBlock *pb)
 	/* Populate the maps and data. */
 	struct plugin_state *state;
 	Slapi_Entry *plugin_entry = NULL;
+	Slapi_DN *pluginsdn = NULL;
+
 	slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state);
-	slapi_pblock_get(pb, SLAPI_TARGET_DN, &state->plugin_base);
-	slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
-			"configuration entry is %s%s%s\n",
-			state->plugin_base ? "\"" : "",
-			state->plugin_base ? state->plugin_base : "NULL",
-			state->plugin_base ? "\"" : "");
+	slapi_pblock_get(pb, SLAPI_TARGET_SDN, &pluginsdn);
+	/* plugin base need to be duplicated because it will be destroyed
+	 * when pblock is destroyed but we need to use it in a separate thread */
+	if (NULL == pluginsdn || 0 == slapi_sdn_get_ndn_len(pluginsdn)) {
+        slapi_log_error(SLAPI_LOG_FATAL, state->plugin_desc->spd_id,
+                        "scheman compat plugin_startup: unable to retrieve plugin DN\n");
+		return -1;
+
+    } else {
+        state->plugin_base = slapi_ch_strdup(slapi_sdn_get_dn(pluginsdn));
+		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+				"configuration entry is %s%s%s\n",
+				state->plugin_base ? "\"" : "",
+				state->plugin_base ? state->plugin_base : "NULL",
+				state->plugin_base ? "\"" : "");
+    }
+
 	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) &&
@@ -122,6 +135,10 @@ plugin_startup(Slapi_PBlock *pb)
 	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. */
+        if (state->priming_mutex == NULL) {
+            state->priming_mutex = wrap_new_mutex();
+            state->start_priming_thread = 1;
+        }
 	backend_startup(pb, state);
 	/* Note that the plugin is ready to go. */



More information about the Pkg-freeipa-devel mailing list