[Pkg-freeipa-devel] [Git][freeipa-team/slapi-nis][master] 20 commits: Update README

Timo Aaltonen gitlab at salsa.debian.org
Sat Jun 2 07:23:13 BST 2018


Timo Aaltonen pushed to branch master at FreeIPA packaging / slapi-nis


Commits:
71ca6132 by stlaz at 2017-04-11T12:53:15+02:00
Update README

Replacing the old link pointing to fedorahosted.org retirement page.

Signed-off-by: Stanislav Laznicka <slaznick at redhat.com>

- - - - -
1020e4ec by Alexander Bokovoy at 2017-11-03T22:56:39+02:00
Update spec file to Fedora version

- - - - -
aab5d0f0 by Alexander Bokovoy at 2017-11-03T22:56:39+02:00
Move a helper to build DN to a format.c

- - - - -
d0189d78 by Alexander Bokovoy at 2017-11-03T22:56:39+02:00
Add dummy handler for a related add/delete/modify to NIS plugin

NIS doesn't need to handle ID overrides, it has to always skip related entries

- - - - -
e83cdaa4 by Alexander Bokovoy at 2017-11-03T22:56:39+02:00
track changes to ID overrides and evict map cache entries

Plug into a processing of LDAP add/delete/modify to see if an ID override entry
was added/deleted/updated. ID overrides aren't directly used to produce
map cache entries but when AD user or group is resolved, SSSD on IPA
master amends that information with ID Override from a Default Trust
View. Since nothing else would remove AD user or group entry from the map cache
on ID override change, handle their removal here.

Check if we have any nssswitch-generated entry in a map cache that
corresponds to this entry. Such entries would be evicted from the map
cache to allow their refresh.

Allow backends to inspect entries related to a map set

Entries may be related to a map set content but not used directly to
generate it. An example would be ID overrides in FreeIPA. An addition,
removal or change of an ID override in the Default Trust View should be
reflected by evicting an entry from the corresponding seti.

Let backends to handle exact logic. NIS backend does not support
exposing AD users so it provides set of dummy callbacks that always
return FALSE (entry is not related). Schema Compat backend, on other
hand, does track ID overrides in a Default Trust View in FreeIPA.

- - - - -
9481aa38 by Alexander Bokovoy at 2017-11-03T22:56:39+02:00
configure.ac: detect extended NSS API provided by SSSD

SSSD exposes an extended NSS API via libsss_nss_idmap. This API allows
to query getpwnam()/getgrnam()/getgruid()/getpwuid()/getgrouplist()
information with a timeout per request. As result, an application has
possibility to cancel too long request.

This API also allows to ignore SSSD cache or invalidate it when
requesting certain information. slapi-nis needs this functionality when
invalidating own entries as result of changes done by other LDAP clients
in the areas which slapi-nis doesn't track directly.

For example, an update of ID override in the Default Trust View should
invalidate user or group entry for that AD object. Since retrieval of
the user/group information relies on SSSD, SSSD needs to be notified
that there is a change in ID override and evict the entry from its cache
as well.

- - - - -
9cbb660d by Alexander Bokovoy at 2017-11-03T22:56:39+02:00
schema-compat: add support for timeout-based NSS queries with libsss_nss_idmap

In case libsss_nss_idmap provides timeout-enabled NSS API, use it.
This solves a problem of too long queries to an NSS backend with
traditional POSIX NSS API. In case SSSD takes too long to respond
to a query, corresponding 389-ds thread running schema-compat plugin
would stuck waiting that response. It can lead to an exhaustion of
389-ds threads.

A refactored interface to NSS backends is introduced with this commit.
A backend API looks like an API an NSS plugin has to implement in glibc
but also allows to handle timeout-based requests internally.

If backend implements timeout-enabled calls, then
backend_nss_set_timeout() function can be used to modify a per-context
state. There is no need for a caller to know whether backend supports
timeout-enabled calls because either way these calls are synchronous
and backend choice is done at compile-time.

schema-compat plugin uses 10 seconds as its default timeout. One can
change it via 'slapi-nss-timeout' attribute in the plugin config entry.

- - - - -
f11619d5 by Alexander Bokovoy at 2017-11-03T22:56:39+02:00
back-sch: cancel memberof retrieval in case of a dirsrv shutdown

Do not wait for SSSD to become online if directory server is going
for shutdown. Since it is guaranteed that SSSD will not be able to
function with 389-ds offline, it makes no sense to continue a loop.

- - - - -
fc259fa6 by Alexander Bokovoy at 2017-11-04T07:54:06+02:00
Fix nss_sss callers

- - - - -
b8aece71 by Alexander Bokovoy at 2017-11-04T07:54:15+02:00
Clean up unused code

- - - - -
1229089c by Alexander Bokovoy at 2017-12-08T16:08:33+02:00
Synchronize nsswitch backend code with freeIPA

FreeIPA ipa-extdom-extop plugin uses the same logic as slapi-nis
schema-compat plugin to handle requests to SSSD. Thus, we keep the
code synchronized across both code bases. Since both plugins are loaded
into the same address space we currently rename functions to allow them
to co-exist. In future we'd move some of common code to a shared
library.

- - - - -
4cd8ef26 by Alexander Bokovoy at 2017-12-08T16:08:42+02:00
Use extended SSSD API to signal that an entry should not be cached anymore

When ID override is changed, we remove affected entry from the schema
compat subtrees. However, we should also signal to SSSD that ID override
did change and thus SSSD should stop caching the entry. As result, next
look up of the affected entry should cause a refresh of the data in
SSSD.

This is important for cases when group membership changes for AD users.

- - - - -
1ce22281 by Alexander Bokovoy at 2018-01-19T12:43:42+02:00
Release 0.56.2

- - - - -
19e64837 by Timo Aaltonen at 2018-06-02T08:44:52+03:00
Merge branch 'upstream'

- - - - -
49497ac3 by Timo Aaltonen at 2018-06-02T08:45:20+03:00
update the changelog

- - - - -
7ee8287f by Timo Aaltonen at 2018-06-02T08:46:29+03:00
control: Update maintainer address.

- - - - -
9a7e65f2 by Timo Aaltonen at 2018-06-02T08:48:52+03:00
control, copyright, watch: Update urls.

- - - - -
4ec93bef by Timo Aaltonen at 2018-06-02T08:49:12+03:00
control: Bump policy to 4.1.4, no changes.

- - - - -
bb5fa8a4 by Timo Aaltonen at 2018-06-02T08:50:05+03:00
Bump debhelper to 11.

- - - - -
85704ac0 by Timo Aaltonen at 2018-06-02T08:51:16+03:00
releasing package slapi-nis version 0.56.2-1

- - - - -


22 changed files:

- README
- configure.ac
- debian/changelog
- debian/compat
- debian/control
- debian/copyright
- debian/watch
- slapi-nis.spec
- src/Makefile.am
- src/back-nis.c
- src/back-sch-idview.c
- src/back-sch-nss.c
- + src/back-sch-nss.h
- + src/back-sch-nss_sss.c
- + src/back-sch-sss_idmap.c
- src/back-sch.c
- src/back-sch.h
- src/back-shr.c
- src/backend.h
- src/format.c
- src/format.h
- src/plug-sch.c


Changes:

=====================================
README
=====================================
--- a/README
+++ b/README
@@ -10,4 +10,4 @@ alternate view of entries stored in part of the DIT, optionally adding,
 dropping, or renaming attribute values, and optionally retrieving values
 for attributes from multiple entries in the tree.
 
-This project is hosted at http://slapi-nis.fedorahosted.org/.
+This project is hosted at https://pagure.io/slapi-nis/.


=====================================
configure.ac
=====================================
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT(slapi-nis,0.56.1)
+AC_INIT(slapi-nis,0.56.2)
 AC_CONFIG_MACRO_DIR([m4])
 AM_INIT_AUTOMAKE(foreign)
 LT_INIT([disable-static])
@@ -361,8 +361,13 @@ if test "x$use_nsswitch" != xno ; then
 			SSS_NSS_IDMAP_LIBS=
 		fi
 	fi
+
 	AC_SUBST(SSS_NSS_IDMAP_CFLAGS)
 	AC_SUBST(SSS_NSS_IDMAP_LIBS)
+	AC_CHECK_LIB(sss_nss_idmap,sss_nss_getpwnam_timeout)
+	if test "x$ac_cv_lib_sss_nss_idmap_sss_nss_getpwnam_timeout" = xyes ; then
+		AC_DEFINE(USE_SSS_NSS_TIMEOUT,1,[Use extended NSS API provided by SSSD])
+	fi
 
 	if test "x$use_pam" != xno ; then
 		AC_CHECK_HEADERS(security/pam_appl.h)
@@ -384,6 +389,7 @@ if test "x$use_nsswitch" != xno ; then
 	fi
 	AC_DEFINE(USE_NSSWITCH,1,[Use nsswitch API to lookup users and groups not found in the LDAP tree])
 fi
+AM_CONDITIONAL([USE_SSS_NSS_TIMEOUT], [test "x$ac_cv_lib_sss_nss_idmap_sss_nss_getpwnam_timeout" = xyes])
 
 use_idviews=true
 AC_ARG_WITH(idviews,


=====================================
debian/changelog
=====================================
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,13 @@
+slapi-nis (0.56.2-1) unstable; urgency=medium
+
+  * New upstream release.
+  * control: Update maintainer address.
+  * control, copyright, watch: Update urls.
+  * control: Bump policy to 4.1.4, no changes.
+  * Bump debhelper to 11.
+
+ -- Timo Aaltonen <tjaalton at debian.org>  Sat, 02 Jun 2018 08:51:10 +0300
+
 slapi-nis (0.56.1-1) unstable; urgency=medium
 
   * New upstream release.


=====================================
debian/compat
=====================================
--- a/debian/compat
+++ b/debian/compat
@@ -1 +1 @@
-9
+11


=====================================
debian/control
=====================================
--- a/debian/control
+++ b/debian/control
@@ -1,11 +1,11 @@
 Source: slapi-nis
 Section: net
 Priority: optional
-Maintainer: Debian FreeIPA Team <pkg-freeipa-devel at lists.alioth.debian.org>
+Maintainer: Debian FreeIPA Team <pkg-freeipa-devel at alioth-lists.debian.net>
 Uploaders: Timo Aaltonen <tjaalton at debian.org>
 Build-Depends:
  389-ds-base-dev,
- debhelper (>= 9),
+ debhelper (>= 11),
  libldap2-dev,
  libnspr4-dev,
  libnss3-dev,
@@ -14,10 +14,10 @@ Build-Depends:
  libtirpc-dev,
  libwrap0-dev,
  pkg-config
-Standards-Version: 3.9.6
-Homepage: http://fedorahosted.org/slapi-nis
-Vcs-Git: git://anonscm.debian.org/pkg-freeipa/slapi-nis.git
-Vcs-Browser: http://anonscm.debian.org/cgit/pkg-freeipa/slapi-nis.git
+Standards-Version: 4.1.4
+Homepage: https://pagure.io/slapi-nis
+Vcs-Git: https://salsa.debian.org/freeipa-team/slapi-nis.git
+Vcs-Browser: https://salsa.debian.org/freeipa-team/slapi-nis
 
 Package: slapi-nis
 Architecture: any


=====================================
debian/copyright
=====================================
--- a/debian/copyright
+++ b/debian/copyright
@@ -1,6 +1,6 @@
 Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 Upstream-Name: slapi-nis
-Source: https://fedorahosted.org/slapi-nis/
+Source: https://pagure.io/slapi-nis
 
 Files: *
 Copyright: 2008-2014 Red Hat, Inc


=====================================
debian/watch
=====================================
--- a/debian/watch
+++ b/debian/watch
@@ -1,2 +1,2 @@
 version=3
-https://fedorahosted.org/releases/s/l/slapi-nis/slapi-nis-(.*)\.tar\.gz
+https://releases.pagure.org/slapi-nis/slapi-nis-(.*)\.tar\.gz


=====================================
slapi-nis.spec
=====================================
--- a/slapi-nis.spec
+++ b/slapi-nis.spec
@@ -10,7 +10,7 @@
 %endif
 
 Name:		slapi-nis
-Version:	0.56.1
+Version:	0.56.2
 Release:	1%{?dist}
 Summary:	NIS Server and Schema Compatibility plugins for Directory Server
 Group:		System Environment/Daemons
@@ -19,10 +19,10 @@ 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 > 1.3.5.6, %{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
+BuildRequires:	libsss_nss_idmap-devel > 1.16.0-5
 %define sss_nss_opts --with-sss-nss-idmap --with-idviews
 %else
 %define sss_nss_opts %{nil}
@@ -39,6 +39,7 @@ BuildRequires:	libtirpc-devel
 %if 0%{?rhel} > 0 && 0%{?rhel} < 7
 ExclusiveArch:	x86_64 %{ix86}
 %endif
+Requires: 389-ds-base >= 1.3.5.6
 
 %description
 This package provides two plugins for Red Hat and 389 Directory Server.
@@ -85,22 +86,41 @@ rm -rf $RPM_BUILD_ROOT
 %{_sbindir}/nisserver-plugin-defs
 
 %changelog
-* Sun Aug 07 2016 Alexander Bokovoy <abokovoy at redhat.com> - 0.56.1-1
+* Fri Jan 19 2018 Alexander Bokovoy <abokovoy at redhat.com> - 0.56.2-1
+- New upstream release
+- Use extended SSSD API to signal that an entry should not be cached anymore
+- Add support for timeout-based NSS queries with libsss_nss_idmap
+
+* Sat Feb 11 2017 Fedora Release Engineering <releng at fedoraproject.org> - 0.56.1-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
+
+* Mon Aug 08 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.0-2
+- Updated upstream tarball
+
 * 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
 
+* Mon May 30 2016 Alexander Bokovoy <abokovoy at redhat.com> - 0.55-3
+- Add support to properly shutdown priming cache from RHEL 7.2.4
+
+* Fri Feb 05 2016 Fedora Release Engineering <releng at fedoraproject.org> - 0.55-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
+
 * 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
 
+* Fri Jun 19 2015 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 0.54.2-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
+
 * 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()
+- CVE-2015-0283 slapi-nis: infinite loop in getgrnam_r() and getgrgid_r() (#1206049)
 - 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
 
@@ -113,6 +133,12 @@ rm -rf $RPM_BUILD_ROOT
 - Allow searching SSSD-provided users as memberUid case-insensitevly
   Fixes bug #1130131
 
+* Mon Aug 18 2014 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 0.53-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild
+
+* Sun Jun 08 2014 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 0.53-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
+
 * Tue Apr 22 2014 Nalin Dahyabhai <nalin at redhat.com> - 0.53-1
 - correct the default NIS map settings for hosts.byname and hosts.byaddr,
   from report by Rik Megens


=====================================
src/Makefile.am
=====================================
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -68,8 +68,17 @@ schemacompat_plugin_la_LIBADD = $(LDAP_LIBS) $(RUNTIME_LIBS) $(LIBPTHREAD) $(CON
 
 if USE_NSSWITCH
 schemacompat_plugin_la_CFLAGS += $(SSS_NSS_IDMAP_CFLAGS)
-schemacompat_plugin_la_SOURCES += back-sch-nss.c
+schemacompat_plugin_la_SOURCES += back-sch-nss.c back-sch-nss.h
 schemacompat_plugin_la_LIBADD += $(SSS_NSS_IDMAP_LIBS)
+# We have two backends for nss operations:
+# (1) directly loading nss_sss.so.2
+# (2) using timeout-enabled API from libsss_nss_idmap
+# We prefer (2) if available
+if USE_SSS_NSS_TIMEOUT
+schemacompat_plugin_la_SOURCES += back-sch-sss_idmap.c
+else
+schemacompat_plugin_la_SOURCES += back-sch-nss_sss.c
+endif
 endif
 
 if USE_PAM


=====================================
src/back-nis.c
=====================================
--- a/src/back-nis.c
+++ b/src/back-nis.c
@@ -1014,6 +1014,34 @@ backend_check_empty(struct plugin_state *state,
 	}
 }
 
+bool_t
+backend_entry_is_add_related(const char *group, const char *set, bool_t flag,
+			     void *shared_set_data,
+			     Slapi_PBlock *pb,
+			     Slapi_Entry *e)
+{
+	return FALSE;
+}
+
+bool_t
+backend_entry_is_modify_related(const char *group, const char *set, bool_t flag,
+				void *shared_set_data,
+				Slapi_PBlock *pb,
+				Slapi_Entry *e_pre,
+				Slapi_Entry *e_post)
+{
+	return FALSE;
+}
+
+bool_t
+backend_entry_is_delete_related(const char *group, const char *set, bool_t flag,
+				void *shared_set_data,
+				Slapi_PBlock *pb,
+				Slapi_Entry *e)
+{
+	return FALSE;
+}
+
 /* Scan for the list of configured domains and maps. */
 void
 backend_startup(Slapi_PBlock *pb, struct plugin_state *state)


=====================================
src/back-sch-idview.c
=====================================
--- a/src/back-sch-idview.c
+++ b/src/back-sch-idview.c
@@ -121,7 +121,7 @@ idview_process_overrides(struct backend_search_cbdata *cbdata,
 					 "createtimestamp", "modifytimestamp", "parentid",
 					 "entryusn", "entryid", "entrydn", "ipaoriginaluid",
 					 "ipaanchoruuid", "nsuniqueid", "ipasshpubkey", NULL };
-	char *new_dn = NULL, *new_key = NULL, *sep = NULL, *new_val = NULL;
+	char *new_dn = NULL, *sep = NULL, *new_val = NULL;
 	char *override_type = NULL;
 	Slapi_Entry *override_entry = NULL;
 	Slapi_Attr *anchor = NULL, *id_attr = NULL;


=====================================
src/back-sch-nss.c
=====================================
--- a/src/back-sch-nss.c
+++ b/src/back-sch-nss.c
@@ -28,7 +28,6 @@
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
-#include <dlfcn.h>
 #include <errno.h>
 #include <pwd.h>
 #include <grp.h>
@@ -52,12 +51,12 @@
 #include "map.h"
 #include "back-sch.h"
 #include "format.h"
+#include "back-sch-nss.h"
 
 static int
 bvstrprefix(const struct berval *bval, const char *s)
 {
 	size_t len;
-	int c;
 
 	len = strlen(s);
 	if (len < bval->bv_len) {
@@ -186,47 +185,6 @@ backend_search_filter_has_cn_uid(Slapi_Filter *filter, void *arg)
 	return SLAPI_FILTER_SCAN_CONTINUE;
 }
 
-static char *
-backend_build_dn(const char *attribute, const char *value,
-		 const char *container_sdn)
-{
-	Slapi_RDN *rdn;
-	Slapi_DN *sdn;
-	char *val, *dn = NULL;
-	const char *ndn, *hexchars = "0123456789ABCDEF";
-	int i;
-
-	val = malloc(strlen(value) * 3 + 1);
-	if (val == NULL) {
-		return NULL;
-	}
-	rdn = slapi_rdn_new();
-	if (rdn == NULL) {
-		free(val);
-		return NULL;
-	}
-        for (i = 0; value[i] != '\0'; i++) {
-		val[i * 3] = '\\';
-		val[i * 3 + 1] = hexchars[(value[i] & 0xf0) >> 4];
-		val[i * 3 + 2] = hexchars[value[i] & 0xf];
-	}
-	val[i * 3] = '\0';
-	if (slapi_rdn_add(rdn, attribute, val) == 1) {
-		sdn = slapi_sdn_new_dn_byval(container_sdn);
-		if (sdn != NULL) {
-			sdn = slapi_sdn_add_rdn(sdn, rdn);
-			ndn = slapi_sdn_get_ndn(sdn);
-			if (ndn != NULL) {
-				dn = slapi_ch_strdup(ndn);
-			}
-			slapi_sdn_free(&sdn);
-		}
-	}
-	free(val);
-	slapi_rdn_free(&rdn);
-	return dn;
-}
-
 static Slapi_Entry *
 backend_make_user_entry_from_nsswitch_passwd(struct passwd *pwd,
 					     char *container_sdn,
@@ -257,7 +215,7 @@ backend_make_user_entry_from_nsswitch_passwd(struct passwd *pwd,
 		return NULL;
 	}
 
-	dn = backend_build_dn("uid", name, container_sdn);
+	dn = format_build_dn("uid", name, container_sdn);
 	if (dn == NULL) {
 		slapi_log_error(SLAPI_LOG_FATAL,
 				cbdata->state->plugin_desc->spd_id,
@@ -335,143 +293,6 @@ backend_make_user_entry_from_nsswitch_passwd(struct passwd *pwd,
 	return entry;
 }
 
-/* Possible results of lookup using a nss_* function.
- * Note: don't include nss.h as its path gets overriden by NSS library */
-enum nss_status
-{
-  NSS_STATUS_TRYAGAIN = -2,
-  NSS_STATUS_UNAVAIL,
-  NSS_STATUS_NOTFOUND,
-  NSS_STATUS_SUCCESS,
-  NSS_STATUS_RETURN
-};
-
-struct nss_ops_ctx {
-	void *dl_handle;
-
-	enum nss_status (*getpwnam_r)(const char *name, struct passwd *result,
-			  char *buffer, size_t buflen, int *errnop);
-	enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result,
-			  char *buffer, size_t buflen, int *errnop);
-	enum nss_status (*setpwent)(void);
-	enum nss_status (*getpwent_r)(struct passwd *result,
-			  char *buffer, size_t buflen, int *errnop);
-	enum nss_status (*endpwent)(void);
-
-	enum nss_status (*getgrnam_r)(const char *name, struct group *result,
-			  char *buffer, size_t buflen, int *errnop);
-	enum nss_status (*getgrgid_r)(gid_t gid, struct group *result,
-			  char *buffer, size_t buflen, int *errnop);
-	enum nss_status (*setgrent)(void);
-	enum nss_status (*getgrent_r)(struct group *result,
-			  char *buffer, size_t buflen, int *errnop);
-	enum nss_status (*endgrent)(void);
-
-	enum nss_status (*initgroups_dyn)(const char *user, gid_t group,
-			      long int *start, long int *size,
-			      gid_t **groups, long int limit,
-			      int *errnop);
-};
-
-void backend_nss_init_context(struct nss_ops_ctx **nss_context)
-{
-	struct nss_ops_ctx *ctx = NULL;
-
-	if (nss_context == NULL) {
-		return;
-	}
-
-	ctx = calloc(1, sizeof(struct nss_ops_ctx));
-
-	*nss_context = ctx;
-	if (ctx == NULL) {
-		return;
-	}
-
-	ctx->dl_handle = dlopen("libnss_sss.so.2", RTLD_NOW);
-	if (ctx->dl_handle == NULL) {
-		goto fail;
-	}
-
-	ctx->getpwnam_r = dlsym(ctx->dl_handle, "_nss_sss_getpwnam_r");
-	if (ctx->getpwnam_r == NULL) {
-		goto fail;
-	}
-
-	ctx->getpwuid_r = dlsym(ctx->dl_handle, "_nss_sss_getpwuid_r");
-	if (ctx->getpwuid_r == NULL) {
-		goto fail;
-	}
-
-	ctx->setpwent = dlsym(ctx->dl_handle, "_nss_sss_setpwent");
-	if (ctx->setpwent == NULL) {
-		goto fail;
-	}
-
-	ctx->getpwent_r = dlsym(ctx->dl_handle, "_nss_sss_getpwent_r");
-	if (ctx->getpwent_r == NULL) {
-		goto fail;
-	}
-
-	ctx->endpwent = dlsym(ctx->dl_handle, "_nss_sss_endpwent");
-	if (ctx->endpwent == NULL) {
-		goto fail;
-	}
-
-	ctx->getgrnam_r = dlsym(ctx->dl_handle, "_nss_sss_getgrnam_r");
-	if (ctx->getgrnam_r == NULL) {
-		goto fail;
-	}
-
-	ctx->getgrgid_r = dlsym(ctx->dl_handle, "_nss_sss_getgrgid_r");
-	if (ctx->getgrgid_r == NULL) {
-		goto fail;
-	}
-
-	ctx->setgrent = dlsym(ctx->dl_handle, "_nss_sss_setgrent");
-	if (ctx->setgrent == NULL) {
-		goto fail;
-	}
-
-	ctx->getgrent_r = dlsym(ctx->dl_handle, "_nss_sss_getgrent_r");
-	if (ctx->getgrent_r == NULL) {
-		goto fail;
-	}
-
-	ctx->endgrent = dlsym(ctx->dl_handle, "_nss_sss_endgrent");
-	if (ctx->endgrent == NULL) {
-		goto fail;
-	}
-
-	ctx->initgroups_dyn = dlsym(ctx->dl_handle, "_nss_sss_initgroups_dyn");
-	if (ctx->initgroups_dyn == NULL) {
-		goto fail;
-	}
-
-	return;
-
-fail:
-	backend_nss_free_context(nss_context);
-
-	return;
-}
-
-void
-backend_nss_free_context(struct nss_ops_ctx **nss_context)
-{
-	if (nss_context == NULL) {
-		return;
-	}
-
-	if ((*nss_context)->dl_handle != NULL) {
-		dlclose((*nss_context)->dl_handle);
-	}
-
-	free((*nss_context));
-	*nss_context = NULL;
-}
-
-
 
 static Slapi_Entry **
 backend_retrieve_user_entry_from_nsswitch(char *user_name, bool_t is_uid,
@@ -497,13 +318,13 @@ repeat:
 	}
 
 	if (is_uid) {
-		rc = ctx->getpwuid_r((uid_t) atoll(user_name), &pwd,
-				     cbdata->nsswitch_buffer,
-				     cbdata->nsswitch_buffer_len, &lerrno);
+		rc = backend_nss_getpwuid(ctx, (uid_t) atoll(user_name), &pwd,
+					  cbdata->nsswitch_buffer,
+					  cbdata->nsswitch_buffer_len, &result, &lerrno);
 	} else {
-		rc = ctx->getpwnam_r(user_name, &pwd,
-				     cbdata->nsswitch_buffer,
-				     cbdata->nsswitch_buffer_len, &lerrno);
+		rc = backend_nss_getpwnam(ctx, user_name, &pwd,
+					  cbdata->nsswitch_buffer,
+					  cbdata->nsswitch_buffer_len, &result, &lerrno);
 	}
 
 	if ((rc != NSS_STATUS_SUCCESS)) {
@@ -556,7 +377,7 @@ backend_make_group_entry_from_nsswitch_group(struct group *grp,
 		return NULL;
 	}
 
-	dn = backend_build_dn("cn", grp->gr_name, container_sdn);
+	dn = format_build_dn("cn", grp->gr_name, container_sdn);
 	if (dn == NULL) {
 		slapi_log_error(SLAPI_LOG_FATAL,
 				cbdata->state->plugin_desc->spd_id,
@@ -632,13 +453,13 @@ repeat:
 	}
 
 	if (is_gid) {
-		rc = ctx->getgrgid_r((gid_t) atoll(group_name), &grp,
-				     cbdata->nsswitch_buffer,
-				     cbdata->nsswitch_buffer_len, &lerrno);
+		rc = backend_nss_getgrgid(ctx, (gid_t) atoll(group_name), &grp,
+					  cbdata->nsswitch_buffer,
+					  cbdata->nsswitch_buffer_len, &result, &lerrno);
 	} else {
-		rc = ctx->getgrnam_r(group_name, &grp,
-				     cbdata->nsswitch_buffer,
-				     cbdata->nsswitch_buffer_len, &lerrno);
+		rc = backend_nss_getgrnam(ctx, group_name, &grp,
+					  cbdata->nsswitch_buffer,
+					  cbdata->nsswitch_buffer_len, &result, &lerrno);
 	}
 	if ((rc != NSS_STATUS_SUCCESS)) {
 		if (lerrno == ERANGE) {
@@ -692,9 +513,9 @@ repeat:
 		return NULL;
 	}
 
-	rc = ctx->getgrgid_r(gid, &grp,
-			     cbdata->nsswitch_buffer,
-			     cbdata->nsswitch_buffer_len, &lerrno);
+	rc = backend_nss_getgrgid(ctx, gid, &grp,
+				  cbdata->nsswitch_buffer,
+				  cbdata->nsswitch_buffer_len, &result, &lerrno);
 
 	if ((rc != NSS_STATUS_SUCCESS)) {
 		if (lerrno == ERANGE) {
@@ -730,8 +551,7 @@ backend_retrieve_group_list_from_nsswitch(char *user_name, char *container_sdn,
 	int i, idx;
 	struct nss_ops_ctx *ctx = NULL;
 	int lerrno = 0;
-	long int ngroups = 0;
-	long int start = 0;
+	int ngroups = 0;
 	enum nss_status rc;
 
 	ctx = cbdata->state->nss_context;
@@ -743,9 +563,9 @@ repeat:
 		return NULL;
 	}
 
-	rc = ctx->getpwnam_r(user_name, &pwd,
-			     cbdata->nsswitch_buffer,
-			     cbdata->nsswitch_buffer_len, &lerrno);
+	rc = backend_nss_getpwnam(ctx, user_name, &pwd,
+				  cbdata->nsswitch_buffer,
+				  cbdata->nsswitch_buffer_len, &pwd_result, &lerrno);
 
 	if ((rc != NSS_STATUS_SUCCESS)) {
 		if (lerrno == ERANGE) {
@@ -764,19 +584,15 @@ repeat:
 	}
 
 	ngroups = 32;
-	start = 0;
 	grouplist = malloc(sizeof(gid_t) * ngroups);
 	if (grouplist == NULL) {
 		return NULL;
 	}
 
-	grouplist[0] = pwd.pw_gid;
-	start++;
-
 	do {
-		rc = ctx->initgroups_dyn(user_name, pwd.pw_gid,
-					 &start, &ngroups, &grouplist,
-					 -1, &lerrno);
+		rc = backend_nss_getgrouplist(ctx, user_name, pwd.pw_gid,
+					      grouplist, &ngroups,
+					      &lerrno);
 		if ((rc != NSS_STATUS_SUCCESS)) {
 			tmp_list = realloc(grouplist, ngroups * sizeof(gid_t));
 			if (tmp_list == NULL) {
@@ -856,7 +672,7 @@ void
 backend_search_nsswitch(struct backend_set_data *set_data,
 			struct backend_search_cbdata *cbdata)
 {
-	int result, rc;
+	int result;
 	struct backend_search_filter_config config =
 		{FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL, NULL, NULL};
 	struct backend_staged_search *staged = NULL;


=====================================
src/back-sch-nss.h
=====================================
--- /dev/null
+++ b/src/back-sch-nss.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2017 Red Hat, Inc.
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; if not, write to the
+ *
+ *   Free Software Foundation, Inc.
+ *   59 Temple Place, Suite 330
+ *   Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef back_sch_nss_h
+#define back_sch_nss_h
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+
+/* Possible results of lookup using a nss_* function.
+ * Note: don't include nss.h as its path gets overriden by NSS library */
+enum nss_status
+{
+  NSS_STATUS_TRYAGAIN = -2,
+  NSS_STATUS_UNAVAIL,
+  NSS_STATUS_NOTFOUND,
+  NSS_STATUS_SUCCESS,
+  NSS_STATUS_RETURN
+};
+
+struct nss_ops_ctx;
+
+enum nss_status backend_nss_getpwnam(struct nss_ops_ctx *nss_context,
+				     const char *name, struct passwd *pwd,
+				     char *buffer, size_t buflen,
+				     struct passwd **result,
+				     int *lerrno);
+
+enum nss_status backend_nss_getpwuid(struct nss_ops_ctx *nss_context,
+				     uid_t uid, struct passwd *pwd,
+				     char *buffer, size_t buflen,
+				     struct passwd **result,
+				     int *lerrno);
+
+enum nss_status backend_nss_getgrnam(struct nss_ops_ctx *nss_context,
+				     const char *name, struct group *grp,
+				     char *buffer, size_t buflen,
+				     struct group **result,
+				     int *lerrno);
+
+enum nss_status backend_nss_getgrgid(struct nss_ops_ctx *nss_context,
+				     gid_t gid, struct group *grp,
+				     char *buffer, size_t buflen,
+				     struct group **result,
+				     int *lerrno);
+
+enum nss_status backend_nss_getgrouplist(struct nss_ops_ctx *nss_context,
+					 const char *name, gid_t group,
+					 gid_t *groups, int *ngroups,
+					 int *lerrno);
+
+#endif /* back_sch_nss_h */


=====================================
src/back-sch-nss_sss.c
=====================================
--- /dev/null
+++ b/src/back-sch-nss_sss.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2013-2017 Red Hat, Inc.
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; if not, write to the
+ *
+ *   Free Software Foundation, Inc.
+ *   59 Temple Place, Suite 330
+ *   Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/param.h>
+#include "back-sch-nss.h"
+
+struct nss_ops_ctx {
+    void *dl_handle;
+    long int initgroups_start;
+
+    enum nss_status (*getpwnam_r)(const char *name, struct passwd *result,
+                                  char *buffer, size_t buflen, int *errnop);
+    enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result,
+                                  char *buffer, size_t buflen, int *errnop);
+    enum nss_status (*getgrnam_r)(const char *name, struct group *result,
+                                  char *buffer, size_t buflen, int *errnop);
+    enum nss_status (*getgrgid_r)(gid_t gid, struct group *result,
+                                  char *buffer, size_t buflen, int *errnop);
+    enum nss_status (*initgroups_dyn)(const char *user, gid_t group,
+                                      long int *start, long int *size,
+                                      gid_t **groups, long int limit,
+                                      int *errnop);
+};
+
+void backend_nss_free_context(struct nss_ops_ctx **nss_context)
+{
+    if ((nss_context == NULL) || (*nss_context == NULL)) {
+        return;
+    }
+
+    if ((*nss_context)->dl_handle != NULL) {
+        dlclose((*nss_context)->dl_handle);
+    }
+
+    free((*nss_context));
+    *nss_context = NULL;
+}
+
+int backend_nss_init_context(struct nss_ops_ctx **nss_context)
+{
+    struct nss_ops_ctx *ctx = NULL;
+
+    if (nss_context == NULL) {
+        return EINVAL;
+    }
+
+    ctx = calloc(1, sizeof(struct nss_ops_ctx));
+    if (ctx == NULL) {
+        return ENOMEM;
+    }
+    *nss_context = ctx;
+
+    ctx->dl_handle = dlopen("libnss_sss.so.2", RTLD_NOW);
+    if (ctx->dl_handle == NULL) {
+        goto fail;
+    }
+
+    ctx->getpwnam_r = dlsym(ctx->dl_handle, "_nss_sss_getpwnam_r");
+    if (ctx->getpwnam_r == NULL) {
+        goto fail;
+    }
+
+    ctx->getpwuid_r = dlsym(ctx->dl_handle, "_nss_sss_getpwuid_r");
+    if (ctx->getpwuid_r == NULL) {
+        goto fail;
+    }
+
+    ctx->getgrnam_r = dlsym(ctx->dl_handle, "_nss_sss_getgrnam_r");
+    if (ctx->getgrnam_r == NULL) {
+        goto fail;
+    }
+
+    ctx->getgrgid_r = dlsym(ctx->dl_handle, "_nss_sss_getgrgid_r");
+    if (ctx->getgrgid_r == NULL) {
+        goto fail;
+    }
+
+    ctx->initgroups_dyn = dlsym(ctx->dl_handle, "_nss_sss_initgroups_dyn");
+    if (ctx->initgroups_dyn == NULL) {
+        goto fail;
+    }
+
+    return 0;
+
+fail:
+    backend_nss_free_context(nss_context);
+
+    return EINVAL;
+}
+
+
+/* Following three functions cannot be implemented with nss_sss.so.2
+ * As result, we simply do nothing here */
+
+void backend_nss_set_timeout(struct nss_ops_ctx *nss_context,
+                             unsigned int timeout) {
+        /* no operation */
+}
+
+void backend_nss_evict_user(struct nss_ops_ctx *nss_context,
+                            const char *name) {
+        /* no operation */
+}
+
+void backend_nss_evict_group(struct nss_ops_ctx *nss_context,
+                             const char *name) {
+        /* no operation */
+}
+
+enum nss_status backend_nss_getpwnam(struct nss_ops_ctx *nss_context,
+                                     const char *name, struct passwd *pwd,
+                                     char *buffer, size_t buflen,
+                                     struct passwd **result,
+                                     int *lerrno) {
+    enum nss_status ret;
+
+    if (nss_context == NULL) {
+        return NSS_STATUS_UNAVAIL;
+    }
+
+    ret = nss_context->getpwnam_r(name, pwd,
+                                  buffer, buflen,
+                                  lerrno);
+
+    if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) {
+        *result = pwd;
+        *lerrno = 0;
+    }
+
+    return ret;
+}
+
+enum nss_status backend_nss_getpwuid(struct nss_ops_ctx *nss_context,
+                                     uid_t uid, struct passwd *pwd,
+                                     char *buffer, size_t buflen,
+                                     struct passwd **result,
+                                     int *lerrno) {
+    enum nss_status ret;
+
+    if (nss_context == NULL) {
+        return NSS_STATUS_UNAVAIL;
+    }
+
+    ret = nss_context->getpwuid_r(uid, pwd,
+                                  buffer, buflen,
+                                  lerrno);
+
+    if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) {
+        *result = pwd;
+        *lerrno = 0;
+    }
+
+    return ret;
+}
+
+enum nss_status backend_nss_getgrnam(struct nss_ops_ctx *nss_context,
+                                     const char *name, struct group *grp,
+                                     char *buffer, size_t buflen,
+                                     struct group **result,
+                                     int *lerrno) {
+    enum nss_status ret;
+
+    if (nss_context == NULL) {
+        return NSS_STATUS_UNAVAIL;
+    }
+
+    ret = nss_context->getgrnam_r(name, grp,
+                                  buffer, buflen,
+                                  lerrno);
+
+    if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) {
+        *result = grp;
+        *lerrno = 0;
+    }
+
+    return ret;
+}
+
+enum nss_status backend_nss_getgrgid(struct nss_ops_ctx *nss_context,
+                                     gid_t gid, struct group *grp,
+                                     char *buffer, size_t buflen,
+                                     struct group **result,
+                                     int *lerrno) {
+
+    enum nss_status ret;
+
+    if (nss_context == NULL) {
+        return NSS_STATUS_UNAVAIL;
+    }
+
+    ret = nss_context->getgrgid_r(gid, grp,
+                                  buffer, buflen,
+                                  lerrno);
+
+    if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) {
+        *result = grp;
+        *lerrno = 0;
+    }
+
+    return ret;
+}
+
+enum nss_status backend_nss_getgrouplist(struct nss_ops_ctx *nss_context,
+                                         const char *name, gid_t group,
+                                         gid_t *groups, int *ngroups,
+                                         int *lerrno) {
+
+    enum nss_status ret = NSS_STATUS_UNAVAIL;
+    long int tsize = MAX (1, *ngroups);
+    gid_t *newgroups = NULL;
+
+    if (nss_context == NULL) {
+        return NSS_STATUS_UNAVAIL;
+    }
+
+    newgroups = (gid_t *) calloc (tsize, sizeof (gid_t));
+    if (newgroups == NULL) {
+        *lerrno = ENOMEM;
+        return NSS_STATUS_TRYAGAIN;
+    }
+
+    newgroups[0] = group;
+    nss_context->initgroups_start = 1;
+
+    ret = nss_context->initgroups_dyn(name, group,
+                                      &nss_context->initgroups_start,
+                                      &tsize, &newgroups,
+                                      -1, lerrno);
+
+    (void) memcpy(groups, newgroups,
+                  MIN(*ngroups, nss_context->initgroups_start) * sizeof(gid_t));
+    free(newgroups);
+
+    if (*ngroups < nss_context->initgroups_start) {
+        ret = NSS_STATUS_TRYAGAIN;
+        *lerrno = ERANGE;
+    }
+
+    *ngroups = (int) nss_context->initgroups_start;
+
+    nss_context->initgroups_start = 0;
+
+    return ret;
+}
+


=====================================
src/back-sch-sss_idmap.c
=====================================
--- /dev/null
+++ b/src/back-sch-sss_idmap.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2013-2017 Red Hat, Inc.
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This Program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this Program; if not, write to the
+ *
+ *   Free Software Foundation, Inc.
+ *   59 Temple Place, Suite 330
+ *   Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+#include "back-sch-nss.h"
+
+/* SSSD only exposes *_timeout() variants if the following symbol is defined */
+#define IPA_389DS_PLUGIN_HELPER_CALLS
+#include <sss_nss_idmap.h>
+
+struct nss_ops_ctx {
+    unsigned int timeout;
+};
+
+static enum nss_status __convert_sss_nss2nss_status(int errcode) {
+    switch(errcode) {
+    case 0:
+        return NSS_STATUS_SUCCESS;
+    case ENOENT:
+        return NSS_STATUS_NOTFOUND;
+    case ETIME:
+        /* fall-through */
+    case ERANGE:
+        return NSS_STATUS_TRYAGAIN;
+    case ETIMEDOUT:
+        /* fall-through */
+    default:
+        return NSS_STATUS_UNAVAIL;
+    }
+    return NSS_STATUS_UNAVAIL;
+}
+
+int backend_nss_init_context(struct nss_ops_ctx **nss_context)
+{
+    struct nss_ops_ctx *ctx = NULL;
+
+    if (nss_context == NULL) {
+        return EINVAL;
+    }
+
+    ctx = calloc(1, sizeof(struct nss_ops_ctx));
+
+    if (ctx == NULL) {
+        return ENOMEM;
+    }
+    *nss_context = ctx;
+    return 0;
+}
+
+void backend_nss_free_context(struct nss_ops_ctx **nss_context)
+{
+    if ((nss_context == NULL) || (*nss_context == NULL)) {
+        return;
+    }
+
+    free((*nss_context));
+    *nss_context = NULL;
+}
+
+
+void backend_nss_set_timeout(struct nss_ops_ctx *nss_context,
+                             unsigned int timeout) {
+    if (nss_context == NULL) {
+        return;
+    }
+
+    nss_context->timeout = timeout;
+}
+
+void backend_nss_evict_user(struct nss_ops_ctx *nss_context,
+                            const char *name) {
+    if (nss_context == NULL) {
+        return;
+    }
+
+    (void) sss_nss_getpwnam_timeout(name, NULL,
+                                    NULL, 0,
+                                    NULL,
+                                    SSS_NSS_EX_FLAG_INVALIDATE_CACHE,
+                                    nss_context->timeout);
+}
+
+void backend_nss_evict_group(struct nss_ops_ctx *nss_context,
+                             const char *name) {
+    if (nss_context == NULL) {
+            return;
+    }
+
+    (void) sss_nss_getgrnam_timeout(name, NULL,
+                                    NULL, 0,
+                                    NULL,
+                                    SSS_NSS_EX_FLAG_INVALIDATE_CACHE,
+                                    nss_context->timeout);
+}
+
+enum nss_status backend_nss_getpwnam(struct nss_ops_ctx *nss_context,
+                                     const char *name, struct passwd *pwd,
+                                     char *buffer, size_t buflen,
+                                     struct passwd **result,
+                                     int *lerrno) {
+    int ret = 0;
+
+    if (nss_context == NULL) {
+        return NSS_STATUS_UNAVAIL;
+    }
+
+    ret = sss_nss_getpwnam_timeout(name, pwd,
+                                   buffer, buflen,
+                                   result,
+                                   SSS_NSS_EX_FLAG_NO_FLAGS,
+                                   nss_context->timeout);
+
+    /* SSSD uses the same infrastructure to handle sss_nss_get* calls
+     * as nss_sss.so.2 module where 'int *errno' is passed to the helper
+     * but writes down errno into return code so we propagate it in case
+     * of error and translate the return code */
+    if (lerrno != NULL) {
+        *lerrno = ret;
+    }
+    return __convert_sss_nss2nss_status(ret);
+}
+
+enum nss_status backend_nss_getpwuid(struct nss_ops_ctx *nss_context,
+                                     uid_t uid, struct passwd *pwd,
+                                     char *buffer, size_t buflen,
+                                     struct passwd **result,
+                                     int *lerrno) {
+
+    int ret = 0;
+
+    if (nss_context == NULL) {
+        return NSS_STATUS_UNAVAIL;
+    }
+
+    ret = sss_nss_getpwuid_timeout(uid, pwd,
+                                   buffer, buflen,
+                                   result,
+                                   SSS_NSS_EX_FLAG_NO_FLAGS,
+                                   nss_context->timeout);
+
+    /* SSSD uses the same infrastructure to handle sss_nss_get* calls
+     * as nss_sss.so.2 module where 'int *errno' is passed to the helper
+     * but writes down errno into return code so we propagate it in case
+     * of error and translate the return code */
+    if (lerrno != NULL) {
+        *lerrno = ret;
+    }
+    return __convert_sss_nss2nss_status(ret);
+}
+
+enum nss_status backend_nss_getgrnam(struct nss_ops_ctx *nss_context,
+                                     const char *name, struct group *grp,
+                                     char *buffer, size_t buflen,
+                                     struct group **result,
+                                     int *lerrno) {
+
+    int ret = 0;
+
+    if (nss_context == NULL) {
+        return NSS_STATUS_UNAVAIL;
+    }
+
+    ret = sss_nss_getgrnam_timeout(name, grp,
+                                   buffer, buflen,
+                                   result,
+                                   SSS_NSS_EX_FLAG_NO_FLAGS,
+                                   nss_context->timeout);
+
+    /* SSSD uses the same infrastructure to handle sss_nss_get* calls
+     * as nss_sss.so.2 module where 'int *errno' is passed to the helper
+     * but writes down errno into return code so we propagate it in case
+     * of error and translate the return code */
+    if (lerrno != NULL) {
+        *lerrno = ret;
+    }
+    return __convert_sss_nss2nss_status(ret);
+}
+
+enum nss_status backend_nss_getgrgid(struct nss_ops_ctx *nss_context,
+                                     gid_t gid, struct group *grp,
+                                     char *buffer, size_t buflen,
+                                     struct group **result,
+                                     int *lerrno) {
+
+    int ret = 0;
+
+    if (nss_context == NULL) {
+        return NSS_STATUS_UNAVAIL;
+    }
+
+    ret = sss_nss_getgrgid_timeout(gid, grp,
+                                   buffer, buflen,
+                                   result,
+                                   SSS_NSS_EX_FLAG_NO_FLAGS,
+                                   nss_context->timeout);
+
+    /* SSSD uses the same infrastructure to handle sss_nss_get* calls
+     * as nss_sss.so.2 module where 'int *errno' is passed to the helper
+     * but writes down errno into return code so we propagate it in case
+     * of error and translate the return code */
+    if (lerrno != NULL) {
+        *lerrno = ret;
+    }
+    return __convert_sss_nss2nss_status(ret);
+}
+
+enum nss_status backend_nss_getgrouplist(struct nss_ops_ctx *nss_context,
+                                         const char *name, gid_t group,
+                                         gid_t *groups, int *ngroups,
+                                         int *lerrno) {
+    int ret = 0;
+
+    if (nss_context == NULL) {
+        return NSS_STATUS_UNAVAIL;
+    }
+
+    ret = sss_nss_getgrouplist_timeout(name, group,
+                                       groups, ngroups,
+                                       SSS_NSS_EX_FLAG_NO_FLAGS,
+                                       nss_context->timeout);
+
+    /* SSSD uses the same infrastructure to handle sss_nss_get* calls
+     * as nss_sss.so.2 module where 'int *errno' is passed to the helper
+     * but writes down errno into return code so we propagate it in case
+     * of error and translate the return code */
+    if (lerrno != NULL) {
+        *lerrno = ret;
+    }
+    return __convert_sss_nss2nss_status(ret);
+}
+


=====================================
src/back-sch.c
=====================================
--- a/src/back-sch.c
+++ b/src/back-sch.c
@@ -33,6 +33,7 @@
 #ifdef HAVE_DIRSRV_SLAPI_PLUGIN_H
 #include <nspr.h>
 #include <plhash.h>
+#include <plstr.h>
 #include <nss.h>
 #include <dirsrv/slapi-plugin.h>
 #else
@@ -506,7 +507,7 @@ backend_set_process_external_members(Slapi_PBlock *pb,
 		/* This group must exist because it exists in the original tree
 		 * but as dirsrv was restarted, SSSD might still consider its domain offline. */
 		is_group_exists = backend_retrieve_from_nsswitch(&staged, &cbdata);
-		if (!is_group_exists) {
+		if (!is_group_exists && !slapi_is_shutting_down()) {
 			slapi_log_error(SLAPI_LOG_FATAL, plugin_id,
 					"group \"%s\" does not exist because SSSD is offline.\n",
 					staged.name);
@@ -2099,6 +2100,193 @@ backend_write_cb(Slapi_PBlock *pb, struct plugin_state *state)
 	return ret;
 }
 
+#ifdef USE_IPA_IDVIEWS
+/* Check if ID override applies to an entry in our map cache
+ * and remove the entry in case it does. */
+
+static bool_t
+backend__get_original_uid_and_ndn(Slapi_Entry *e,
+				  char **original_uid,
+				  const char **original_anchor)
+{
+	char **elem = NULL;
+	char *v = NULL;
+	char *ndn = NULL;
+	char *view = NULL;
+	int n_elem = 0;
+	int i = 0;
+
+	if (e == NULL) {
+		return FALSE;
+	}
+
+	elem = slapi_entry_attr_get_charray_ext(e, "objectClass", &n_elem);
+	if (elem == NULL) {
+		/* weird, objectClass should be existing */
+		return FALSE;
+	}
+
+	for (i=0; i < n_elem; i++) {
+		if (strncasecmp(elem[i], "ipaOverrideAnchor", 17) == 0) {
+			break;
+		}
+	}
+
+	slapi_ch_array_free(elem);
+	if (i == n_elem) {
+		/* This is not an override, bail out */
+		return FALSE;
+	}
+
+	ndn = slapi_entry_get_ndn(e);
+	if (ndn == NULL) {
+		return FALSE;
+	}
+
+	view = PL_strcasestr(ndn, "cn=Default Trust View,");
+	if (view == NULL || view == ndn) {
+		return FALSE;
+	}
+
+	/* This is an ID override, we need to search for a referenced ipaOriginalUid or cn in our maps */
+	v = slapi_entry_attr_get_charptr(e, "ipaOriginalUid");
+	if (v == NULL) {
+		v = slapi_entry_attr_get_charptr(e, "cn");
+		if (v == NULL) {
+			return FALSE;
+		}
+	}
+
+	*original_uid = v;
+	*original_anchor = ndn;
+	return TRUE;
+}
+
+bool_t
+backend_entry_evict_if_related(const char *group, const char *set, bool_t flag,
+			       void *shared_set_data,
+			       Slapi_PBlock *pb,
+			       Slapi_Entry *e)
+{
+	struct backend_set_data *set_data;
+	struct plugin_state *state = NULL;
+	char *id = NULL;
+	char *original_uid = NULL;
+	const char *original_anchor = NULL;
+	const char *rdn_attribute[] = {NULL, "uid=%s,%s,%s", "cn=%s,%s,%s"};
+	bool_t result = FALSE;
+
+	set_data = shared_set_data;
+
+	/* We only interested in NSSWITCH-capable maps */
+	if (set_data->check_nsswitch == SCH_NSSWITCH_NONE) {
+		return FALSE;
+	}
+
+	/* See if the entry pre modification had original UID */
+	if (!backend__get_original_uid_and_ndn(e,
+					       &original_uid,
+					       &original_anchor)) {
+		return FALSE;
+	}
+
+	id = slapi_ch_smprintf(rdn_attribute[set_data->check_nsswitch],
+			       original_uid, set, group);
+
+	if (id == NULL) {
+		slapi_ch_free_string(&original_uid);
+		return FALSE;
+	}
+
+	slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state);
+	result = map_data_check_entry(state, group, set, id);
+	if (result) {
+		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+				"evicted entry %s due to changed content of ID override %s\n",
+				id, original_anchor);
+
+		/* An entry corresponding to our target is found, evict it */
+		map_data_unset_entry(state, group, set, id);
+
+		/* Signal to SSSD that this entry is not cached anymore */
+		switch(set_data->check_nsswitch) {
+                case SCH_NSSWITCH_USER:
+			backend_nss_evict_user(state->nss_context, original_uid);
+			break;
+		case SCH_NSSWITCH_GROUP:
+			backend_nss_evict_group(state->nss_context, original_uid);
+			break;
+		default:
+			break;
+		}
+	}
+
+	slapi_ch_free_string(&id);
+	slapi_ch_free_string(&original_uid);
+	return result;
+}
+
+bool_t
+backend_entry_is_add_related(const char *group, const char *set, bool_t flag,
+			     void *shared_set_data,
+			     Slapi_PBlock *pb,
+			     Slapi_Entry *e)
+{
+	return backend_entry_evict_if_related(group, set, flag, shared_set_data, pb, e);
+}
+
+
+bool_t
+backend_entry_is_modify_related(const char *group, const char *set, bool_t flag,
+				void *shared_set_data,
+				Slapi_PBlock *pb,
+				Slapi_Entry *e_pre,
+				Slapi_Entry *e_post)
+{
+	return backend_entry_evict_if_related(group, set, flag, shared_set_data, pb, e_pre);
+}
+
+bool_t
+backend_entry_is_delete_related(const char *group, const char *set, bool_t flag,
+				void *shared_set_data,
+				Slapi_PBlock *pb,
+				Slapi_Entry *e)
+{
+	return backend_entry_evict_if_related(group, set, flag, shared_set_data, pb, e);
+}
+
+#else
+
+bool_t
+backend_entry_is_add_related(const char *group, const char *set, bool_t flag,
+			     void *shared_set_data,
+			     Slapi_PBlock *pb,
+			     Slapi_Entry *e)
+{
+	return FALSE;
+}
+
+bool_t
+backend_entry_is_modify_related(const char *group, const char *set, bool_t flag,
+				void *shared_set_data,
+				Slapi_PBlock *pb,
+				Slapi_Entry *e_pre,
+				Slapi_Entry *e_post)
+{
+	return FALSE;
+}
+
+bool_t
+backend_entry_is_delete_related(const char *group, const char *set, bool_t flag,
+				void *shared_set_data,
+				Slapi_PBlock *pb,
+				Slapi_Entry *e)
+{
+	return FALSE;
+}
+
+#endif
+
 static int
 backend_pre_write_cb(Slapi_PBlock *pb)
 {


=====================================
src/back-sch.h
=====================================
--- a/src/back-sch.h
+++ b/src/back-sch.h
@@ -137,7 +137,6 @@ struct backend_search_filter_config {
 #define LDAP_EXTOP_PASSMOD_TAG_NEWPWD	0x82U
 
 typedef int (*IFP)();
-static int backend_passwdmod_extop(Slapi_PBlock *pb);
 typedef struct backend_extop_handlers {
     char *oid;
     IFP extop_fct;
@@ -152,10 +151,17 @@ typedef struct backend_extop_handlers {
 
 int backend_analyze_search_filter(Slapi_Filter *filter, struct backend_search_filter_config *config);
 
-/* Operations against nsswitch API */
+/* NSS backend operations implemented using either nss_sss.so.2 or libsss_nss_idmap API */
 struct nss_ops_ctx;
-void backend_nss_init_context(struct nss_ops_ctx **nss_context);
+
+int backend_nss_init_context(struct nss_ops_ctx **nss_context);
 void backend_nss_free_context(struct nss_ops_ctx **nss_context);
+void backend_nss_set_timeout(struct nss_ops_ctx *nss_context,
+			     unsigned int timeout);
+void backend_nss_evict_user(struct nss_ops_ctx *nss_context,
+			    const char *name);
+void backend_nss_evict_group(struct nss_ops_ctx *nss_context,
+			     const char *name);
 
 void backend_search_nsswitch(struct backend_set_data *set_data,
 			     struct backend_search_cbdata *cbdata);


=====================================
src/back-shr.c
=====================================
--- a/src/back-shr.c
+++ b/src/back-shr.c
@@ -1856,11 +1856,21 @@ backend_shr_add_entry_cb(const char *group, const char *set, bool_t secure,
 
 	/* If the entry doesn't match the set, skip it. */
 	if (!backend_shr_entry_matches_set(set_data, cbdata->pb, cbdata->e)) {
-		slapi_log_error(SLAPI_LOG_PLUGIN,
-				cbdata->state->plugin_desc->spd_id,
-				"entry \"%s\" does not belong in "
-				"\"%s\"/\"%s\"\n",
-				cbdata->ndn, group, set);
+		/* Give backend a chance to perform other operations on the add op.
+		 * For example, ID override addition in FreeIPA need to be noted to
+		 * evict AD user/group entries from a map cache while ID overrides
+		 * themselves aren't present in any map.
+		 * Note that we could do this as a part of backend_shr_entry_matches_set()
+		 * but it is better to isolate this operation in a separate call. */
+		if (!backend_entry_is_add_related(group, set, secure,
+						  set_data, cbdata->pb,
+						  cbdata->e)) {
+			slapi_log_error(SLAPI_LOG_PLUGIN,
+					cbdata->state->plugin_desc->spd_id,
+					"entry \"%s\" does not belong in "
+					"\"%s\"/\"%s\"\n",
+					cbdata->ndn, group, set);
+		}
 		return TRUE;
 	}
 
@@ -2010,13 +2020,24 @@ backend_shr_modify_entry_cb(const char *group, const char *set, bool_t flag,
 					   cbdata->e_post) &&
 	    !backend_shr_entry_matches_set(set_data, cbdata->pb,
 					   cbdata->e_pre)) {
-		slapi_log_error(SLAPI_LOG_PLUGIN,
-				cbdata->state->plugin_desc->spd_id,
-				"\"%s\" not in \"%s\"/\"%s\", "
-				"before or after modify\n",
-				cbdata->ndn,
-				set_data->group,
-				set_data->set);
+		/* Give backend a chance to perform other operations on the modify op.
+		 * For example, ID override updates in FreeIPA need to be noted to
+		 * evict AD user/group entries from a map cache while ID overrides
+		 * themselves aren't present in any map.
+		 * Note that we could do this as a part of backend_shr_entry_matches_set()
+		 * but it is better to isolate this operation in a separate call. */
+		if (!backend_entry_is_modify_related(group, set, flag,
+						     set_data, cbdata->pb,
+						     cbdata->e_pre,
+						     cbdata->e_post)) {
+			slapi_log_error(SLAPI_LOG_PLUGIN,
+					cbdata->state->plugin_desc->spd_id,
+					"\"%s\" not in \"%s\"/\"%s\", "
+					"before or after modify\n",
+					cbdata->ndn,
+					set_data->group,
+					set_data->set);
+		}
 		return TRUE;
 	}
 	if (set_data->skip_uninteresting_updates &&
@@ -2631,6 +2652,16 @@ backend_shr_delete_entry_cb(const char *group, const char *set, bool_t flag,
 				group, set, set_data->group, set_data->set,
 				cbdata->ndn);
 		map_data_unset_entry(cbdata->state, group, set, cbdata->ndn);
+	} else {
+		/* Give backend a chance to perform other operations on the delete op.
+		 * For example, ID override removal in FreeIPA need to be noted to
+		 * evict AD user/group entries from a map cache while ID overrides
+		 * themselves aren't present in any map.
+		 * Note that we could do this as a part of backend_shr_entry_matches_set()
+		 * but it is better to isolate this operation in a separate call. */
+		(void) backend_entry_is_delete_related(group, set, flag,
+						       set_data, cbdata->pb,
+						       cbdata->e);
 	}
 	return TRUE;
 }


=====================================
src/backend.h
=====================================
--- a/src/backend.h
+++ b/src/backend.h
@@ -115,4 +115,24 @@ void backend_update_params(Slapi_PBlock *pb, struct plugin_state *state);
 bool_t backend_shr_is_caller(struct plugin_state *state,
 			     struct slapi_pblock *pb);
 
+/* Check if an operation is performed on an entry that is related to
+ * any entry in the set. This allows to catch changes of the entries that
+ * aren't directly included in the map set but should affect the set. */
+bool_t
+backend_entry_is_modify_related(const char *group, const char *set, bool_t flag,
+				void *shared_set_data,
+				Slapi_PBlock *pb,
+				Slapi_Entry *e_pre,
+				Slapi_Entry *e_post);
+bool_t
+backend_entry_is_add_related(const char *group, const char *set, bool_t flag,
+			     void *shared_set_data,
+			     Slapi_PBlock *pb,
+			     Slapi_Entry *e);
+bool_t
+backend_entry_is_delete_related(const char *group, const char *set, bool_t flag,
+				void *shared_set_data,
+				Slapi_PBlock *pb,
+				Slapi_Entry *e);
+
 #endif


=====================================
src/format.c
=====================================
--- a/src/format.c
+++ b/src/format.c
@@ -4825,3 +4825,44 @@ format_escape_for_filter(const char *unescaped)
 	}
 	return ret;
 }
+
+char *
+format_build_dn(const char *attribute, const char *value,
+		const char *container_sdn)
+{
+	Slapi_RDN *rdn;
+	Slapi_DN *sdn;
+	char *val, *dn = NULL;
+	const char *ndn, *hexchars = "0123456789ABCDEF";
+	int i;
+
+	val = malloc(strlen(value) * 3 + 1);
+	if (val == NULL) {
+		return NULL;
+	}
+	rdn = slapi_rdn_new();
+	if (rdn == NULL) {
+		free(val);
+		return NULL;
+	}
+        for (i = 0; value[i] != '\0'; i++) {
+		val[i * 3] = '\\';
+		val[i * 3 + 1] = hexchars[(value[i] & 0xf0) >> 4];
+		val[i * 3 + 2] = hexchars[value[i] & 0xf];
+	}
+	val[i * 3] = '\0';
+	if (slapi_rdn_add(rdn, attribute, val) == 1) {
+		sdn = slapi_sdn_new_dn_byval(container_sdn);
+		if (sdn != NULL) {
+			sdn = slapi_sdn_add_rdn(sdn, rdn);
+			ndn = slapi_sdn_get_ndn(sdn);
+			if (ndn != NULL) {
+				dn = slapi_ch_strdup(ndn);
+			}
+			slapi_sdn_free(&sdn);
+		}
+	}
+	free(val);
+	slapi_rdn_free(&rdn);
+	return dn;
+}


=====================================
src/format.h
=====================================
--- a/src/format.h
+++ b/src/format.h
@@ -83,4 +83,6 @@ char **format_get_data_set(struct plugin_state *state,
 			   unsigned int **data_lengths);
 
 char *format_escape_for_filter(const char *unescaped);
+char *format_build_dn(const char *attribute, const char *value,
+		      const char *container_sdn);
 #endif


=====================================
src/plug-sch.c
=====================================
--- a/src/plug-sch.c
+++ b/src/plug-sch.c
@@ -104,33 +104,46 @@ plugin_startup(Slapi_PBlock *pb)
 	struct plugin_state *state;
 	Slapi_Entry *plugin_entry = NULL;
 	Slapi_DN *pluginsdn = NULL;
+	unsigned int nss_timeout = 10000;
+	int ret = 0;
 
 	slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state);
 	slapi_pblock_get(pb, SLAPI_TARGET_SDN, &pluginsdn);
 	/* plugin base need to be duplicated because it will be destroyed
 	 * when pblock is destroyed but we need to use it in a separate thread */
 	if (NULL == pluginsdn || 0 == slapi_sdn_get_ndn_len(pluginsdn)) {
-        slapi_log_error(SLAPI_LOG_FATAL, state->plugin_desc->spd_id,
-                        "scheman compat plugin_startup: unable to retrieve plugin DN\n");
-		return -1;
-
-    } else {
-        state->plugin_base = slapi_ch_strdup(slapi_sdn_get_dn(pluginsdn));
-		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
-				"configuration entry is %s%s%s\n",
-				state->plugin_base ? "\"" : "",
-				state->plugin_base ? state->plugin_base : "NULL",
-				state->plugin_base ? "\"" : "");
-    }
+            slapi_log_error(SLAPI_LOG_FATAL, state->plugin_desc->spd_id,
+                            "scheman compat plugin_startup: unable to retrieve plugin DN\n");
+	    return -1;
+        } else {
+            state->plugin_base = slapi_ch_strdup(slapi_sdn_get_dn(pluginsdn));
+	    slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+			    "configuration entry is %s%s%s\n",
+			    state->plugin_base ? "\"" : "",
+			    state->plugin_base ? state->plugin_base : "NULL",
+			    state->plugin_base ? "\"" : "");
+        }
 
 	state->pam_lock = wrap_new_rwlock();
-	backend_nss_init_context((struct nss_ops_ctx**) &state->nss_context);
+	ret = backend_nss_init_context((struct nss_ops_ctx**) &state->nss_context);
+	if (ret != 0) {
+	    slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
+			    "failed to intiialize nsswitch backend: [%d]!\n",
+			    ret);
+	    return -1;
+	}
 	if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
 	    (plugin_entry != NULL)) {
 		state->use_entry_cache = backend_shr_get_vattr_boolean(state, plugin_entry,
 									"slapi-entry-cache",
 									1);
+		nss_timeout = backend_shr_get_vattr_uint(state, plugin_entry,
+							 "slapi-nss-timeout",
+							 10000);
+
 	}
+	backend_nss_set_timeout(state->nss_context, nss_timeout);
+
 	state->cached_entries_lock = wrap_new_rwlock();
 	wrap_rwlock_wrlock(state->cached_entries_lock);
 	state->cached_entries = PL_NewHashTable(0, PL_HashString, PL_CompareStrings, PL_CompareValues, 0, 0);



View it on GitLab: https://salsa.debian.org/freeipa-team/slapi-nis/compare/955099748bb1dc0b3fb58a5966e98e7d9f38f803...85704ac0eaca00363f359ce945631627bf601381

-- 
View it on GitLab: https://salsa.debian.org/freeipa-team/slapi-nis/compare/955099748bb1dc0b3fb58a5966e98e7d9f38f803...85704ac0eaca00363f359ce945631627bf601381
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-freeipa-devel/attachments/20180602/2e4dd7ea/attachment-0001.html>


More information about the Pkg-freeipa-devel mailing list