9eb798
From 1229089c4023757ae15ff1866e4d89069325d2f0 Mon Sep 17 00:00:00 2001
9eb798
From: Alexander Bokovoy <abokovoy@redhat.com>
9eb798
Date: Thu, 7 Dec 2017 12:33:24 +0200
9eb798
Subject: [PATCH] Synchronize nsswitch backend code with freeIPA
9eb798
9eb798
FreeIPA ipa-extdom-extop plugin uses the same logic as slapi-nis
9eb798
schema-compat plugin to handle requests to SSSD. Thus, we keep the
9eb798
code synchronized across both code bases. Since both plugins are loaded
9eb798
into the same address space we currently rename functions to allow them
9eb798
to co-exist. In future we'd move some of common code to a shared
9eb798
library.
9eb798
---
9eb798
 src/back-sch-nss_sss.c   | 365 ++++++++++++++++++++++++-----------------------
9eb798
 src/back-sch-sss_idmap.c | 335 +++++++++++++++++++++++--------------------
9eb798
 src/back-sch.h           |   8 +-
9eb798
 src/plug-sch.c           |  32 +++--
9eb798
 4 files changed, 390 insertions(+), 350 deletions(-)
9eb798
9eb798
diff --git a/src/back-sch-nss_sss.c b/src/back-sch-nss_sss.c
9eb798
index 2b1b8b0..5ee911e 100644
9eb798
--- a/src/back-sch-nss_sss.c
9eb798
+++ b/src/back-sch-nss_sss.c
9eb798
@@ -32,232 +32,245 @@
9eb798
 #include <errno.h>
9eb798
 #include <pwd.h>
9eb798
 #include <grp.h>
9eb798
+#include <sys/param.h>
9eb798
 #include "back-sch-nss.h"
9eb798
 
9eb798
 struct nss_ops_ctx {
9eb798
-	void *dl_handle;
9eb798
-	long int initgroups_start;
9eb798
-
9eb798
-	enum nss_status (*getpwnam_r)(const char *name, struct passwd *result,
9eb798
-			  char *buffer, size_t buflen, int *errnop);
9eb798
-	enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result,
9eb798
-			  char *buffer, size_t buflen, int *errnop);
9eb798
-	enum nss_status (*getgrnam_r)(const char *name, struct group *result,
9eb798
-			  char *buffer, size_t buflen, int *errnop);
9eb798
-	enum nss_status (*getgrgid_r)(gid_t gid, struct group *result,
9eb798
-			  char *buffer, size_t buflen, int *errnop);
9eb798
-	enum nss_status (*initgroups_dyn)(const char *user, gid_t group,
9eb798
-			      long int *start, long int *size,
9eb798
-			      gid_t **groups, long int limit,
9eb798
-			      int *errnop);
9eb798
+    void *dl_handle;
9eb798
+    long int initgroups_start;
9eb798
+
9eb798
+    enum nss_status (*getpwnam_r)(const char *name, struct passwd *result,
9eb798
+                                  char *buffer, size_t buflen, int *errnop);
9eb798
+    enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result,
9eb798
+                                  char *buffer, size_t buflen, int *errnop);
9eb798
+    enum nss_status (*getgrnam_r)(const char *name, struct group *result,
9eb798
+                                  char *buffer, size_t buflen, int *errnop);
9eb798
+    enum nss_status (*getgrgid_r)(gid_t gid, struct group *result,
9eb798
+                                  char *buffer, size_t buflen, int *errnop);
9eb798
+    enum nss_status (*initgroups_dyn)(const char *user, gid_t group,
9eb798
+                                      long int *start, long int *size,
9eb798
+                                      gid_t **groups, long int limit,
9eb798
+                                      int *errnop);
9eb798
 };
9eb798
 
9eb798
 void backend_nss_free_context(struct nss_ops_ctx **nss_context)
9eb798
 {
9eb798
-	if (nss_context == NULL) {
9eb798
-		return;
9eb798
-	}
9eb798
+    if ((nss_context == NULL) || (*nss_context == NULL)) {
9eb798
+        return;
9eb798
+    }
9eb798
 
9eb798
-	if ((*nss_context)->dl_handle != NULL) {
9eb798
-		dlclose((*nss_context)->dl_handle);
9eb798
-	}
9eb798
+    if ((*nss_context)->dl_handle != NULL) {
9eb798
+        dlclose((*nss_context)->dl_handle);
9eb798
+    }
9eb798
 
9eb798
-	free((*nss_context));
9eb798
-	*nss_context = NULL;
9eb798
+    free((*nss_context));
9eb798
+    *nss_context = NULL;
9eb798
 }
9eb798
 
9eb798
-void backend_nss_init_context(struct nss_ops_ctx **nss_context)
9eb798
+int backend_nss_init_context(struct nss_ops_ctx **nss_context)
9eb798
 {
9eb798
-	struct nss_ops_ctx *ctx = NULL;
9eb798
-
9eb798
-	if (nss_context == NULL) {
9eb798
-		return;
9eb798
-	}
9eb798
-
9eb798
-	ctx = calloc(1, sizeof(struct nss_ops_ctx));
9eb798
-
9eb798
-	*nss_context = ctx;
9eb798
-	if (ctx == NULL) {
9eb798
-		return;
9eb798
-	}
9eb798
-
9eb798
-	ctx->dl_handle = dlopen("libnss_sss.so.2", RTLD_NOW);
9eb798
-	if (ctx->dl_handle == NULL) {
9eb798
-		goto fail;
9eb798
-	}
9eb798
-
9eb798
-	ctx->getpwnam_r = dlsym(ctx->dl_handle, "_nss_sss_getpwnam_r");
9eb798
-	if (ctx->getpwnam_r == NULL) {
9eb798
-		goto fail;
9eb798
-	}
9eb798
-
9eb798
-	ctx->getpwuid_r = dlsym(ctx->dl_handle, "_nss_sss_getpwuid_r");
9eb798
-	if (ctx->getpwuid_r == NULL) {
9eb798
-		goto fail;
9eb798
-	}
9eb798
-
9eb798
-	ctx->getgrnam_r = dlsym(ctx->dl_handle, "_nss_sss_getgrnam_r");
9eb798
-	if (ctx->getgrnam_r == NULL) {
9eb798
-		goto fail;
9eb798
-	}
9eb798
-
9eb798
-	ctx->getgrgid_r = dlsym(ctx->dl_handle, "_nss_sss_getgrgid_r");
9eb798
-	if (ctx->getgrgid_r == NULL) {
9eb798
-		goto fail;
9eb798
-	}
9eb798
-
9eb798
-	ctx->initgroups_dyn = dlsym(ctx->dl_handle, "_nss_sss_initgroups_dyn");
9eb798
-	if (ctx->initgroups_dyn == NULL) {
9eb798
-		goto fail;
9eb798
-	}
9eb798
-
9eb798
-	return;
9eb798
+    struct nss_ops_ctx *ctx = NULL;
9eb798
+
9eb798
+    if (nss_context == NULL) {
9eb798
+        return EINVAL;
9eb798
+    }
9eb798
+
9eb798
+    ctx = calloc(1, sizeof(struct nss_ops_ctx));
9eb798
+    if (ctx == NULL) {
9eb798
+        return ENOMEM;
9eb798
+    }
9eb798
+    *nss_context = ctx;
9eb798
+
9eb798
+    ctx->dl_handle = dlopen("libnss_sss.so.2", RTLD_NOW);
9eb798
+    if (ctx->dl_handle == NULL) {
9eb798
+        goto fail;
9eb798
+    }
9eb798
+
9eb798
+    ctx->getpwnam_r = dlsym(ctx->dl_handle, "_nss_sss_getpwnam_r");
9eb798
+    if (ctx->getpwnam_r == NULL) {
9eb798
+        goto fail;
9eb798
+    }
9eb798
+
9eb798
+    ctx->getpwuid_r = dlsym(ctx->dl_handle, "_nss_sss_getpwuid_r");
9eb798
+    if (ctx->getpwuid_r == NULL) {
9eb798
+        goto fail;
9eb798
+    }
9eb798
+
9eb798
+    ctx->getgrnam_r = dlsym(ctx->dl_handle, "_nss_sss_getgrnam_r");
9eb798
+    if (ctx->getgrnam_r == NULL) {
9eb798
+        goto fail;
9eb798
+    }
9eb798
+
9eb798
+    ctx->getgrgid_r = dlsym(ctx->dl_handle, "_nss_sss_getgrgid_r");
9eb798
+    if (ctx->getgrgid_r == NULL) {
9eb798
+        goto fail;
9eb798
+    }
9eb798
+
9eb798
+    ctx->initgroups_dyn = dlsym(ctx->dl_handle, "_nss_sss_initgroups_dyn");
9eb798
+    if (ctx->initgroups_dyn == NULL) {
9eb798
+        goto fail;
9eb798
+    }
9eb798
+
9eb798
+    return 0;
9eb798
 
9eb798
 fail:
9eb798
-	backend_nss_free_context(nss_context);
9eb798
+    backend_nss_free_context(nss_context);
9eb798
 
9eb798
-	return;
9eb798
+    return EINVAL;
9eb798
 }
9eb798
 
9eb798
 
9eb798
 /* Following three functions cannot be implemented with nss_sss.so.2
9eb798
  * As result, we simply do nothing here */
9eb798
 
9eb798
-void backend_nss_set_timeout(struct nss_ops_ctx **nss_context,
9eb798
-			     unsigned int timeout) {
9eb798
-	/* no operation */
9eb798
+void backend_nss_set_timeout(struct nss_ops_ctx *nss_context,
9eb798
+                             unsigned int timeout) {
9eb798
+        /* no operation */
9eb798
 }
9eb798
 
9eb798
-void backend_nss_evict_user(struct nss_ops_ctx **nss_context,
9eb798
-			    const char *name) {
9eb798
-	/* no operation */
9eb798
+void backend_nss_evict_user(struct nss_ops_ctx *nss_context,
9eb798
+                            const char *name) {
9eb798
+        /* no operation */
9eb798
 }
9eb798
 
9eb798
-void backend_nss_evict_group(struct nss_ops_ctx **nss_context,
9eb798
-			     const char *name) {
9eb798
-	/* no operation */
9eb798
+void backend_nss_evict_group(struct nss_ops_ctx *nss_context,
9eb798
+                             const char *name) {
9eb798
+        /* no operation */
9eb798
 }
9eb798
 
9eb798
 enum nss_status backend_nss_getpwnam(struct nss_ops_ctx *nss_context,
9eb798
-				     const char *name, struct passwd *pwd,
9eb798
-				     char *buffer, size_t buflen,
9eb798
-				     struct passwd **result,
9eb798
-				     int *lerrno) {
9eb798
-	enum nss_status ret;
9eb798
-
9eb798
-	if (nss_context == NULL) {
9eb798
-		return NSS_STATUS_UNAVAIL;
9eb798
-	}
9eb798
-
9eb798
-	ret = (enum nss_status)
9eb798
-		nss_context->getpwnam_r(name, pwd,
9eb798
-					buffer, buflen,
9eb798
-					lerrno);
9eb798
-
9eb798
-	if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) {
9eb798
-		*result = pwd;
9eb798
-	}
9eb798
-
9eb798
-	return ret;
9eb798
+                                     const char *name, struct passwd *pwd,
9eb798
+                                     char *buffer, size_t buflen,
9eb798
+                                     struct passwd **result,
9eb798
+                                     int *lerrno) {
9eb798
+    enum nss_status ret;
9eb798
+
9eb798
+    if (nss_context == NULL) {
9eb798
+        return NSS_STATUS_UNAVAIL;
9eb798
+    }
9eb798
+
9eb798
+    ret = nss_context->getpwnam_r(name, pwd,
9eb798
+                                  buffer, buflen,
9eb798
+                                  lerrno);
9eb798
+
9eb798
+    if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) {
9eb798
+        *result = pwd;
9eb798
+        *lerrno = 0;
9eb798
+    }
9eb798
+
9eb798
+    return ret;
9eb798
 }
9eb798
 
9eb798
 enum nss_status backend_nss_getpwuid(struct nss_ops_ctx *nss_context,
9eb798
-				     uid_t uid, struct passwd *pwd,
9eb798
-				     char *buffer, size_t buflen,
9eb798
-				     struct passwd **result,
9eb798
-				     int *lerrno) {
9eb798
-	enum nss_status ret;
9eb798
-
9eb798
-	if (nss_context == NULL) {
9eb798
-		return NSS_STATUS_UNAVAIL;
9eb798
-	}
9eb798
-
9eb798
-	ret = (enum nss_status)
9eb798
-		nss_context->getpwuid_r(uid, pwd,
9eb798
-					buffer, buflen,
9eb798
-					lerrno);
9eb798
-
9eb798
-	if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) {
9eb798
-		*result = pwd;
9eb798
-	}
9eb798
-
9eb798
-	return ret;
9eb798
+                                     uid_t uid, struct passwd *pwd,
9eb798
+                                     char *buffer, size_t buflen,
9eb798
+                                     struct passwd **result,
9eb798
+                                     int *lerrno) {
9eb798
+    enum nss_status ret;
9eb798
+
9eb798
+    if (nss_context == NULL) {
9eb798
+        return NSS_STATUS_UNAVAIL;
9eb798
+    }
9eb798
+
9eb798
+    ret = nss_context->getpwuid_r(uid, pwd,
9eb798
+                                  buffer, buflen,
9eb798
+                                  lerrno);
9eb798
+
9eb798
+    if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) {
9eb798
+        *result = pwd;
9eb798
+        *lerrno = 0;
9eb798
+    }
9eb798
+
9eb798
+    return ret;
9eb798
 }
9eb798
 
9eb798
 enum nss_status backend_nss_getgrnam(struct nss_ops_ctx *nss_context,
9eb798
-				     const char *name, struct group *grp,
9eb798
-				     char *buffer, size_t buflen,
9eb798
-				     struct group **result,
9eb798
-				     int *lerrno) {
9eb798
-	enum nss_status ret;
9eb798
-
9eb798
-	if (nss_context == NULL) {
9eb798
-		return NSS_STATUS_UNAVAIL;
9eb798
-	}
9eb798
-
9eb798
-	ret = (enum nss_status)
9eb798
-		nss_context->getgrnam_r(name, grp,
9eb798
-					buffer, buflen,
9eb798
-					lerrno);
9eb798
-
9eb798
-	if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) {
9eb798
-		*result = grp;
9eb798
-	}
9eb798
-
9eb798
-	return ret;
9eb798
+                                     const char *name, struct group *grp,
9eb798
+                                     char *buffer, size_t buflen,
9eb798
+                                     struct group **result,
9eb798
+                                     int *lerrno) {
9eb798
+    enum nss_status ret;
9eb798
+
9eb798
+    if (nss_context == NULL) {
9eb798
+        return NSS_STATUS_UNAVAIL;
9eb798
+    }
9eb798
+
9eb798
+    ret = nss_context->getgrnam_r(name, grp,
9eb798
+                                  buffer, buflen,
9eb798
+                                  lerrno);
9eb798
+
9eb798
+    if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) {
9eb798
+        *result = grp;
9eb798
+        *lerrno = 0;
9eb798
+    }
9eb798
+
9eb798
+    return ret;
9eb798
 }
9eb798
 
9eb798
 enum nss_status backend_nss_getgrgid(struct nss_ops_ctx *nss_context,
9eb798
-				     gid_t gid, struct group *grp,
9eb798
-				     char *buffer, size_t buflen,
9eb798
-				     struct group **result,
9eb798
-				     int *lerrno) {
9eb798
+                                     gid_t gid, struct group *grp,
9eb798
+                                     char *buffer, size_t buflen,
9eb798
+                                     struct group **result,
9eb798
+                                     int *lerrno) {
9eb798
 
9eb798
-	enum nss_status ret;
9eb798
+    enum nss_status ret;
9eb798
 
9eb798
-	if (nss_context == NULL) {
9eb798
-		return NSS_STATUS_UNAVAIL;
9eb798
-	}
9eb798
+    if (nss_context == NULL) {
9eb798
+        return NSS_STATUS_UNAVAIL;
9eb798
+    }
9eb798
 
9eb798
-	ret = (enum nss_status)
9eb798
-		nss_context->getgrgid_r(gid, grp,
9eb798
-					buffer, buflen,
9eb798
-					lerrno);
9eb798
+    ret = nss_context->getgrgid_r(gid, grp,
9eb798
+                                  buffer, buflen,
9eb798
+                                  lerrno);
9eb798
 
9eb798
-	if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) {
9eb798
-		*result = grp;
9eb798
-	}
9eb798
+    if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) {
9eb798
+        *result = grp;
9eb798
+        *lerrno = 0;
9eb798
+    }
9eb798
 
9eb798
-	return ret;
9eb798
+    return ret;
9eb798
 }
9eb798
 
9eb798
 enum nss_status backend_nss_getgrouplist(struct nss_ops_ctx *nss_context,
9eb798
-					 const char *name, gid_t group,
9eb798
-					 gid_t *groups, int *ngroups,
9eb798
-					 int *lerrno) {
9eb798
+                                         const char *name, gid_t group,
9eb798
+                                         gid_t *groups, int *ngroups,
9eb798
+                                         int *lerrno) {
9eb798
+
9eb798
+    enum nss_status ret = NSS_STATUS_UNAVAIL;
9eb798
+    long int tsize = MAX (1, *ngroups);
9eb798
+    gid_t *newgroups = NULL;
9eb798
+
9eb798
+    if (nss_context == NULL) {
9eb798
+        return NSS_STATUS_UNAVAIL;
9eb798
+    }
9eb798
+
9eb798
+    newgroups = (gid_t *) calloc (tsize, sizeof (gid_t));
9eb798
+    if (newgroups == NULL) {
9eb798
+        *lerrno = ENOMEM;
9eb798
+        return NSS_STATUS_TRYAGAIN;
9eb798
+    }
9eb798
+
9eb798
+    newgroups[0] = group;
9eb798
+    nss_context->initgroups_start = 1;
9eb798
 
9eb798
-	enum nss_status ret = NSS_STATUS_UNAVAIL;
9eb798
-	long int size = 0;
9eb798
+    ret = nss_context->initgroups_dyn(name, group,
9eb798
+                                      &nss_context->initgroups_start,
9eb798
+                                      &tsize, &newgroups,
9eb798
+                                      -1, lerrno);
9eb798
 
9eb798
-	if (nss_context == NULL) {
9eb798
-		return NSS_STATUS_UNAVAIL;
9eb798
-	}
9eb798
+    (void) memcpy(groups, newgroups,
9eb798
+                  MIN(*ngroups, nss_context->initgroups_start) * sizeof(gid_t));
9eb798
+    free(newgroups);
9eb798
 
9eb798
-	if (nss_context->initgroups_start == 0) {
9eb798
-		groups[0] = group;
9eb798
-		nss_context->initgroups_start++;
9eb798
-	}
9eb798
+    if (*ngroups < nss_context->initgroups_start) {
9eb798
+        ret = NSS_STATUS_TRYAGAIN;
9eb798
+        *lerrno = ERANGE;
9eb798
+    }
9eb798
 
9eb798
-	ret = nss_context->initgroups_dyn(name, group,
9eb798
-					  &nss_context->initgroups_start,
9eb798
-					  &size, &groups,
9eb798
-					  -1, lerrno);
9eb798
-	if (ret == NSS_STATUS_SUCCESS) {
9eb798
-		nss_context->initgroups_start = 0;
9eb798
-	}
9eb798
+    *ngroups = (int) nss_context->initgroups_start;
9eb798
 
9eb798
-	*ngroups = (int) size;
9eb798
+    nss_context->initgroups_start = 0;
9eb798
 
9eb798
-	return ret;
9eb798
+    return ret;
9eb798
 }
9eb798
 
9eb798
diff --git a/src/back-sch-sss_idmap.c b/src/back-sch-sss_idmap.c
9eb798
index 6a31267..452ff4f 100644
9eb798
--- a/src/back-sch-sss_idmap.c
9eb798
+++ b/src/back-sch-sss_idmap.c
9eb798
@@ -38,202 +38,223 @@
9eb798
 #include <sss_nss_idmap.h>
9eb798
 
9eb798
 struct nss_ops_ctx {
9eb798
-	unsigned int timeout;
9eb798
+    unsigned int timeout;
9eb798
 };
9eb798
 
9eb798
 static enum nss_status __convert_sss_nss2nss_status(int errcode) {
9eb798
-	enum nss_status ret = NSS_STATUS_UNAVAIL;
9eb798
-
9eb798
-	if (errcode == 0) {
9eb798
-		ret = NSS_STATUS_SUCCESS;
9eb798
-	} else if (errcode == ENOENT) {
9eb798
-		ret = NSS_STATUS_NOTFOUND;
9eb798
-	} else if(errcode == ERANGE) {
9eb798
-		ret = NSS_STATUS_TRYAGAIN;
9eb798
-	} else if(errcode == ETIMEDOUT) {
9eb798
-		ret = NSS_STATUS_UNAVAIL;
9eb798
-	} else if(errcode == ETIME) {
9eb798
-		ret = NSS_STATUS_TRYAGAIN;
9eb798
-	};
9eb798
-
9eb798
-	return ret;
9eb798
+    switch(errcode) {
9eb798
+    case 0:
9eb798
+        return NSS_STATUS_SUCCESS;
9eb798
+    case ENOENT:
9eb798
+        return NSS_STATUS_NOTFOUND;
9eb798
+    case ETIME:
9eb798
+        /* fall-through */
9eb798
+    case ERANGE:
9eb798
+        return NSS_STATUS_TRYAGAIN;
9eb798
+    case ETIMEDOUT:
9eb798
+        /* fall-through */
9eb798
+    default:
9eb798
+        return NSS_STATUS_UNAVAIL;
9eb798
+    }
9eb798
+    return NSS_STATUS_UNAVAIL;
9eb798
 }
9eb798
 
9eb798
-void backend_nss_init_context(struct nss_ops_ctx **nss_context)
9eb798
+int backend_nss_init_context(struct nss_ops_ctx **nss_context)
9eb798
 {
9eb798
-	struct nss_ops_ctx *ctx = NULL;
9eb798
+    struct nss_ops_ctx *ctx = NULL;
9eb798
 
9eb798
-	if (nss_context == NULL) {
9eb798
-		return;
9eb798
-	}
9eb798
+    if (nss_context == NULL) {
9eb798
+        return EINVAL;
9eb798
+    }
9eb798
 
9eb798
-	ctx = calloc(1, sizeof(struct nss_ops_ctx));
9eb798
+    ctx = calloc(1, sizeof(struct nss_ops_ctx));
9eb798
 
9eb798
-	*nss_context = ctx;
9eb798
+    if (ctx == NULL) {
9eb798
+        return ENOMEM;
9eb798
+    }
9eb798
+    *nss_context = ctx;
9eb798
+    return 0;
9eb798
 }
9eb798
 
9eb798
 void backend_nss_free_context(struct nss_ops_ctx **nss_context)
9eb798
 {
9eb798
-	if (nss_context == NULL) {
9eb798
-		return;
9eb798
-	}
9eb798
+    if ((nss_context == NULL) || (*nss_context == NULL)) {
9eb798
+        return;
9eb798
+    }
9eb798
 
9eb798
-	free((*nss_context));
9eb798
-	*nss_context = NULL;
9eb798
+    free((*nss_context));
9eb798
+    *nss_context = NULL;
9eb798
 }
9eb798
 
9eb798
 
9eb798
 void backend_nss_set_timeout(struct nss_ops_ctx *nss_context,
9eb798
-			     unsigned int timeout) {
9eb798
-	if (nss_context == NULL) {
9eb798
-		return;
9eb798
-	}
9eb798
+                             unsigned int timeout) {
9eb798
+    if (nss_context == NULL) {
9eb798
+        return;
9eb798
+    }
9eb798
 
9eb798
-	nss_context->timeout = timeout;
9eb798
+    nss_context->timeout = timeout;
9eb798
 }
9eb798
 
9eb798
-/* TODO: handle buffers and memory allocation in this function */
9eb798
 void backend_nss_evict_user(struct nss_ops_ctx *nss_context,
9eb798
-			    const char *name) {
9eb798
-	if (nss_context == NULL) {
9eb798
-		return;
9eb798
-	}
9eb798
-
9eb798
-	(void) sss_nss_getpwnam_timeout(name, NULL,
9eb798
-					NULL, 0,
9eb798
-					NULL,
9eb798
-					SSS_NSS_EX_FLAG_INVALIDATE_CACHE,
9eb798
-					nss_context->timeout);
9eb798
+                            const char *name) {
9eb798
+    if (nss_context == NULL) {
9eb798
+        return;
9eb798
+    }
9eb798
+
9eb798
+    (void) sss_nss_getpwnam_timeout(name, NULL,
9eb798
+                                    NULL, 0,
9eb798
+                                    NULL,
9eb798
+                                    SSS_NSS_EX_FLAG_INVALIDATE_CACHE,
9eb798
+                                    nss_context->timeout);
9eb798
 }
9eb798
 
9eb798
-/* TODO: handle buffers and memory allocation in this function */
9eb798
 void backend_nss_evict_group(struct nss_ops_ctx *nss_context,
9eb798
-			     const char *name) {
9eb798
-	if (nss_context == NULL) {
9eb798
-		return;
9eb798
-	}
9eb798
-
9eb798
-	(void) sss_nss_getgrnam_timeout(name, NULL,
9eb798
-					NULL, 0,
9eb798
-					NULL,
9eb798
-					SSS_NSS_EX_FLAG_INVALIDATE_CACHE,
9eb798
-					nss_context->timeout);
9eb798
+                             const char *name) {
9eb798
+    if (nss_context == NULL) {
9eb798
+            return;
9eb798
+    }
9eb798
+
9eb798
+    (void) sss_nss_getgrnam_timeout(name, NULL,
9eb798
+                                    NULL, 0,
9eb798
+                                    NULL,
9eb798
+                                    SSS_NSS_EX_FLAG_INVALIDATE_CACHE,
9eb798
+                                    nss_context->timeout);
9eb798
 }
9eb798
 
9eb798
 enum nss_status backend_nss_getpwnam(struct nss_ops_ctx *nss_context,
9eb798
-				     const char *name, struct passwd *pwd,
9eb798
-				     char *buffer, size_t buflen,
9eb798
-				     struct passwd **result,
9eb798
-				     int *lerrno) {
9eb798
-	int ret = 0;
9eb798
-
9eb798
-	if (nss_context == NULL) {
9eb798
-		return NSS_STATUS_UNAVAIL;
9eb798
-	}
9eb798
-
9eb798
-	ret = sss_nss_getpwnam_timeout(name, pwd,
9eb798
-				       buffer, buflen,
9eb798
-				       result,
9eb798
-				       SSS_NSS_EX_FLAG_NO_FLAGS,
9eb798
-				       nss_context->timeout);
9eb798
-
9eb798
-	if (ret != 0 && lerrno != NULL) {
9eb798
-		/* SSSD translates errno into return code */
9eb798
-		*lerrno = ret;
9eb798
-	}
9eb798
-	return __convert_sss_nss2nss_status(ret);
9eb798
+                                     const char *name, struct passwd *pwd,
9eb798
+                                     char *buffer, size_t buflen,
9eb798
+                                     struct passwd **result,
9eb798
+                                     int *lerrno) {
9eb798
+    int ret = 0;
9eb798
+
9eb798
+    if (nss_context == NULL) {
9eb798
+        return NSS_STATUS_UNAVAIL;
9eb798
+    }
9eb798
+
9eb798
+    ret = sss_nss_getpwnam_timeout(name, pwd,
9eb798
+                                   buffer, buflen,
9eb798
+                                   result,
9eb798
+                                   SSS_NSS_EX_FLAG_NO_FLAGS,
9eb798
+                                   nss_context->timeout);
9eb798
+
9eb798
+    /* SSSD uses the same infrastructure to handle sss_nss_get* calls
9eb798
+     * as nss_sss.so.2 module where 'int *errno' is passed to the helper
9eb798
+     * but writes down errno into return code so we propagate it in case
9eb798
+     * of error and translate the return code */
9eb798
+    if (lerrno != NULL) {
9eb798
+        *lerrno = ret;
9eb798
+    }
9eb798
+    return __convert_sss_nss2nss_status(ret);
9eb798
 }
9eb798
 
9eb798
 enum nss_status backend_nss_getpwuid(struct nss_ops_ctx *nss_context,
9eb798
-				     uid_t uid, struct passwd *pwd,
9eb798
-				     char *buffer, size_t buflen,
9eb798
-				     struct passwd **result,
9eb798
-				     int *lerrno) {
9eb798
-
9eb798
-	int ret = 0;
9eb798
-
9eb798
-	if (nss_context == NULL) {
9eb798
-		return NSS_STATUS_UNAVAIL;
9eb798
-	}
9eb798
-
9eb798
-	ret = sss_nss_getpwuid_timeout(uid, pwd,
9eb798
-				       buffer, buflen,
9eb798
-				       result,
9eb798
-				       SSS_NSS_EX_FLAG_NO_FLAGS,
9eb798
-				       nss_context->timeout);
9eb798
-	if (ret != 0 && lerrno != NULL) {
9eb798
-		/* SSSD translates errno into return code */
9eb798
-		*lerrno = ret;
9eb798
-	}
9eb798
-	return __convert_sss_nss2nss_status(ret);
9eb798
+                                     uid_t uid, struct passwd *pwd,
9eb798
+                                     char *buffer, size_t buflen,
9eb798
+                                     struct passwd **result,
9eb798
+                                     int *lerrno) {
9eb798
+
9eb798
+    int ret = 0;
9eb798
+
9eb798
+    if (nss_context == NULL) {
9eb798
+        return NSS_STATUS_UNAVAIL;
9eb798
+    }
9eb798
+
9eb798
+    ret = sss_nss_getpwuid_timeout(uid, pwd,
9eb798
+                                   buffer, buflen,
9eb798
+                                   result,
9eb798
+                                   SSS_NSS_EX_FLAG_NO_FLAGS,
9eb798
+                                   nss_context->timeout);
9eb798
+
9eb798
+    /* SSSD uses the same infrastructure to handle sss_nss_get* calls
9eb798
+     * as nss_sss.so.2 module where 'int *errno' is passed to the helper
9eb798
+     * but writes down errno into return code so we propagate it in case
9eb798
+     * of error and translate the return code */
9eb798
+    if (lerrno != NULL) {
9eb798
+        *lerrno = ret;
9eb798
+    }
9eb798
+    return __convert_sss_nss2nss_status(ret);
9eb798
 }
9eb798
 
9eb798
 enum nss_status backend_nss_getgrnam(struct nss_ops_ctx *nss_context,
9eb798
-				     const char *name, struct group *grp,
9eb798
-				     char *buffer, size_t buflen,
9eb798
-				     struct group **result,
9eb798
-				     int *lerrno) {
9eb798
-
9eb798
-	int ret = 0;
9eb798
-
9eb798
-	if (nss_context == NULL) {
9eb798
-		return NSS_STATUS_UNAVAIL;
9eb798
-	}
9eb798
-
9eb798
-	ret = sss_nss_getgrnam_timeout(name, grp,
9eb798
-				       buffer, buflen,
9eb798
-				       result,
9eb798
-				       SSS_NSS_EX_FLAG_NO_FLAGS,
9eb798
-				       nss_context->timeout);
9eb798
-	if (ret != 0 && lerrno != NULL) {
9eb798
-		/* SSSD translates errno into return code */
9eb798
-		*lerrno = ret;
9eb798
-	}
9eb798
-	return __convert_sss_nss2nss_status(ret);
9eb798
+                                     const char *name, struct group *grp,
9eb798
+                                     char *buffer, size_t buflen,
9eb798
+                                     struct group **result,
9eb798
+                                     int *lerrno) {
9eb798
+
9eb798
+    int ret = 0;
9eb798
+
9eb798
+    if (nss_context == NULL) {
9eb798
+        return NSS_STATUS_UNAVAIL;
9eb798
+    }
9eb798
+
9eb798
+    ret = sss_nss_getgrnam_timeout(name, grp,
9eb798
+                                   buffer, buflen,
9eb798
+                                   result,
9eb798
+                                   SSS_NSS_EX_FLAG_NO_FLAGS,
9eb798
+                                   nss_context->timeout);
9eb798
+
9eb798
+    /* SSSD uses the same infrastructure to handle sss_nss_get* calls
9eb798
+     * as nss_sss.so.2 module where 'int *errno' is passed to the helper
9eb798
+     * but writes down errno into return code so we propagate it in case
9eb798
+     * of error and translate the return code */
9eb798
+    if (lerrno != NULL) {
9eb798
+        *lerrno = ret;
9eb798
+    }
9eb798
+    return __convert_sss_nss2nss_status(ret);
9eb798
 }
9eb798
 
9eb798
 enum nss_status backend_nss_getgrgid(struct nss_ops_ctx *nss_context,
9eb798
-				     gid_t gid, struct group *grp,
9eb798
-				     char *buffer, size_t buflen,
9eb798
-				     struct group **result,
9eb798
-				     int *lerrno) {
9eb798
-
9eb798
-	int ret = 0;
9eb798
-
9eb798
-	if (nss_context == NULL) {
9eb798
-		return NSS_STATUS_UNAVAIL;
9eb798
-	}
9eb798
-
9eb798
-	ret = sss_nss_getgrgid_timeout(gid, grp,
9eb798
-				       buffer, buflen,
9eb798
-				       result,
9eb798
-				       SSS_NSS_EX_FLAG_NO_FLAGS,
9eb798
-				       nss_context->timeout);
9eb798
-	if (ret != 0 && lerrno != NULL) {
9eb798
-		/* SSSD translates errno into return code */
9eb798
-		*lerrno = ret;
9eb798
-	}
9eb798
-	return __convert_sss_nss2nss_status(ret);
9eb798
+                                     gid_t gid, struct group *grp,
9eb798
+                                     char *buffer, size_t buflen,
9eb798
+                                     struct group **result,
9eb798
+                                     int *lerrno) {
9eb798
+
9eb798
+    int ret = 0;
9eb798
+
9eb798
+    if (nss_context == NULL) {
9eb798
+        return NSS_STATUS_UNAVAIL;
9eb798
+    }
9eb798
+
9eb798
+    ret = sss_nss_getgrgid_timeout(gid, grp,
9eb798
+                                   buffer, buflen,
9eb798
+                                   result,
9eb798
+                                   SSS_NSS_EX_FLAG_NO_FLAGS,
9eb798
+                                   nss_context->timeout);
9eb798
+
9eb798
+    /* SSSD uses the same infrastructure to handle sss_nss_get* calls
9eb798
+     * as nss_sss.so.2 module where 'int *errno' is passed to the helper
9eb798
+     * but writes down errno into return code so we propagate it in case
9eb798
+     * of error and translate the return code */
9eb798
+    if (lerrno != NULL) {
9eb798
+        *lerrno = ret;
9eb798
+    }
9eb798
+    return __convert_sss_nss2nss_status(ret);
9eb798
 }
9eb798
 
9eb798
 enum nss_status backend_nss_getgrouplist(struct nss_ops_ctx *nss_context,
9eb798
-					 const char *name, gid_t group,
9eb798
-					 gid_t *groups, int *ngroups,
9eb798
-					 int *lerrno) {
9eb798
-	int ret = 0;
9eb798
-
9eb798
-	if (nss_context == NULL) {
9eb798
-		return NSS_STATUS_UNAVAIL;
9eb798
-	}
9eb798
-
9eb798
-	ret = sss_nss_getgrouplist_timeout(name, group,
9eb798
-					   groups, ngroups,
9eb798
-					   SSS_NSS_EX_FLAG_NO_FLAGS,
9eb798
-					   nss_context->timeout);
9eb798
-	if (ret != 0 && lerrno != NULL) {
9eb798
-		/* SSSD translates errno into return code */
9eb798
-		*lerrno = ret;
9eb798
-	}
9eb798
-	return __convert_sss_nss2nss_status(ret);
9eb798
+                                         const char *name, gid_t group,
9eb798
+                                         gid_t *groups, int *ngroups,
9eb798
+                                         int *lerrno) {
9eb798
+    int ret = 0;
9eb798
+
9eb798
+    if (nss_context == NULL) {
9eb798
+        return NSS_STATUS_UNAVAIL;
9eb798
+    }
9eb798
+
9eb798
+    ret = sss_nss_getgrouplist_timeout(name, group,
9eb798
+                                       groups, ngroups,
9eb798
+                                       SSS_NSS_EX_FLAG_NO_FLAGS,
9eb798
+                                       nss_context->timeout);
9eb798
+
9eb798
+    /* SSSD uses the same infrastructure to handle sss_nss_get* calls
9eb798
+     * as nss_sss.so.2 module where 'int *errno' is passed to the helper
9eb798
+     * but writes down errno into return code so we propagate it in case
9eb798
+     * of error and translate the return code */
9eb798
+    if (lerrno != NULL) {
9eb798
+        *lerrno = ret;
9eb798
+    }
9eb798
+    return __convert_sss_nss2nss_status(ret);
9eb798
 }
9eb798
 
9eb798
diff --git a/src/back-sch.h b/src/back-sch.h
9eb798
index 483e288..2d73f34 100644
9eb798
--- a/src/back-sch.h
9eb798
+++ b/src/back-sch.h
9eb798
@@ -154,13 +154,13 @@ int backend_analyze_search_filter(Slapi_Filter *filter, struct backend_search_fi
9eb798
 /* NSS backend operations implemented using either nss_sss.so.2 or libsss_nss_idmap API */
9eb798
 struct nss_ops_ctx;
9eb798
 
9eb798
-void backend_nss_init_context(struct nss_ops_ctx **nss_context);
9eb798
+int backend_nss_init_context(struct nss_ops_ctx **nss_context);
9eb798
 void backend_nss_free_context(struct nss_ops_ctx **nss_context);
9eb798
-void backend_nss_set_timeout(struct nss_ops_ctx **nss_context,
9eb798
+void backend_nss_set_timeout(struct nss_ops_ctx *nss_context,
9eb798
 			     unsigned int timeout);
9eb798
-void backend_nss_evict_user(struct nss_ops_ctx **nss_context,
9eb798
+void backend_nss_evict_user(struct nss_ops_ctx *nss_context,
9eb798
 			    const char *name);
9eb798
-void backend_nss_evict_group(struct nss_ops_ctx **nss_context,
9eb798
+void backend_nss_evict_group(struct nss_ops_ctx *nss_context,
9eb798
 			     const char *name);
9eb798
 
9eb798
 void backend_search_nsswitch(struct backend_set_data *set_data,
9eb798
diff --git a/src/plug-sch.c b/src/plug-sch.c
9eb798
index 6ee4042..0c20a07 100644
9eb798
--- a/src/plug-sch.c
9eb798
+++ b/src/plug-sch.c
9eb798
@@ -105,27 +105,33 @@ plugin_startup(Slapi_PBlock *pb)
9eb798
 	Slapi_Entry *plugin_entry = NULL;
9eb798
 	Slapi_DN *pluginsdn = NULL;
9eb798
 	unsigned int nss_timeout = 10000;
9eb798
+	int ret = 0;
9eb798
 
9eb798
 	slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state);
9eb798
 	slapi_pblock_get(pb, SLAPI_TARGET_SDN, &pluginsdn);
9eb798
 	/* plugin base need to be duplicated because it will be destroyed
9eb798
 	 * when pblock is destroyed but we need to use it in a separate thread */
9eb798
 	if (NULL == pluginsdn || 0 == slapi_sdn_get_ndn_len(pluginsdn)) {
9eb798
-        slapi_log_error(SLAPI_LOG_FATAL, state->plugin_desc->spd_id,
9eb798
-                        "scheman compat plugin_startup: unable to retrieve plugin DN\n");
9eb798
-		return -1;
9eb798
-
9eb798
-    } else {
9eb798
-        state->plugin_base = slapi_ch_strdup(slapi_sdn_get_dn(pluginsdn));
9eb798
-		slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
9eb798
-				"configuration entry is %s%s%s\n",
9eb798
-				state->plugin_base ? "\"" : "",
9eb798
-				state->plugin_base ? state->plugin_base : "NULL",
9eb798
-				state->plugin_base ? "\"" : "");
9eb798
-    }
9eb798
+            slapi_log_error(SLAPI_LOG_FATAL, state->plugin_desc->spd_id,
9eb798
+                            "scheman compat plugin_startup: unable to retrieve plugin DN\n");
9eb798
+	    return -1;
9eb798
+        } else {
9eb798
+            state->plugin_base = slapi_ch_strdup(slapi_sdn_get_dn(pluginsdn));
9eb798
+	    slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
9eb798
+			    "configuration entry is %s%s%s\n",
9eb798
+			    state->plugin_base ? "\"" : "",
9eb798
+			    state->plugin_base ? state->plugin_base : "NULL",
9eb798
+			    state->plugin_base ? "\"" : "");
9eb798
+        }
9eb798
 
9eb798
 	state->pam_lock = wrap_new_rwlock();
9eb798
-	backend_nss_init_context((struct nss_ops_ctx**) &state->nss_context);
9eb798
+	ret = backend_nss_init_context((struct nss_ops_ctx**) &state->nss_context);
9eb798
+	if (ret != 0) {
9eb798
+	    slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id,
9eb798
+			    "failed to intiialize nsswitch backend: [%d]!\n",
9eb798
+			    ret);
9eb798
+	    return -1;
9eb798
+	}
9eb798
 	if ((slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &plugin_entry) == 0) &&
9eb798
 	    (plugin_entry != NULL)) {
9eb798
 		state->use_entry_cache = backend_shr_get_vattr_boolean(state, plugin_entry,
9eb798
-- 
9eb798
2.14.3
9eb798