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