From 6fbf5891e9169142fc0ea37eb8f897a645b82d6f Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Wed, 1 Nov 2017 10:29:41 +0200 Subject: [PATCH 16/17] 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. --- src/Makefile.am | 11 ++- src/back-sch-nss.c | 187 +++++------------------------------- src/back-sch-nss.h | 70 ++++++++++++++ src/back-sch-nss_sss.c | 231 +++++++++++++++++++++++++++++++++++++++++++++ src/back-sch-sss_idmap.c | 239 +++++++++++++++++++++++++++++++++++++++++++++++ src/back-sch.h | 9 +- src/plug-sch.c | 7 ++ 7 files changed, 588 insertions(+), 166 deletions(-) create mode 100644 src/back-sch-nss.h create mode 100644 src/back-sch-nss_sss.c create mode 100644 src/back-sch-sss_idmap.c diff --git a/src/Makefile.am b/src/Makefile.am index 6f4926e..cd1efc2 100644 --- 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 diff --git a/src/back-sch-nss.c b/src/back-sch-nss.c index e4d027e..e5f91b2 100644 --- a/src/back-sch-nss.c +++ b/src/back-sch-nss.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -52,6 +51,7 @@ #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) @@ -294,143 +294,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, @@ -456,13 +319,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)) { @@ -591,13 +454,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) { @@ -651,9 +514,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) { @@ -689,7 +552,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; + int ngroups = 0; long int start = 0; enum nss_status rc; @@ -702,9 +565,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) { @@ -723,19 +586,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) { diff --git a/src/back-sch-nss.h b/src/back-sch-nss.h new file mode 100644 index 0000000..54a3c07 --- /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 +#include +#include + +/* 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 */ diff --git a/src/back-sch-nss_sss.c b/src/back-sch-nss_sss.c new file mode 100644 index 0000000..e3e6628 --- /dev/null +++ b/src/back-sch-nss_sss.c @@ -0,0 +1,231 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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_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->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; + +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; +} + + +/* 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) { + + if (nss_context == NULL) { + return NSS_STATUS_UNAVAIL; + } + + return (enum nss_status) + nss_context->getpwnam_r(name, pwd, + buffer, buflen, + result, 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) { + + if (nss_context == NULL) { + return NSS_STATUS_UNAVAIL; + } + + return (enum nss_status) + nss_context->getpwuid_r(uid, pwd, + buffer, buflen, + result, 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) { + + if (nss_context == NULL) { + return NSS_STATUS_UNAVAIL; + } + + return (enum nss_status) + nss_context->getgrnam_r(name, grp, + buffer, buflen, + result, 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) { + + if (nss_context == NULL) { + return NSS_STATUS_UNAVAIL; + } + + return (enum nss_status) + nss_context->getgrgid_r(gid, grp, + buffer, buflen, + result, 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) { + enum nss_status ret = NSS_STATUS_UNAVAIL; + + if (nss_context == NULL) { + return NSS_STATUS_UNAVAIL; + } + + if (nss_context->initgroups_start == 0) { + groups[0] = group; + nss_context->initgroups_start++; + } + + ret = nss_context->initgroups_dyn(name, group, + &nss_context->initgroups_start, + &ngroups, &groups, + -1, &lerrno); + if (ret == NSS_STATUS_SUCCESS) { + nss_context->initgroups_start = 0; + } + + return ret; +} + diff --git a/src/back-sch-sss_idmap.c b/src/back-sch-sss_idmap.c new file mode 100644 index 0000000..6a31267 --- /dev/null +++ b/src/back-sch-sss_idmap.c @@ -0,0 +1,239 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include "back-sch-nss.h" + +/* SSSD only exposes *_timeout() variants if the following symbol is defined */ +#define IPA_389DS_PLUGIN_HELPER_CALLS +#include + +struct nss_ops_ctx { + unsigned int timeout; +}; + +static enum nss_status __convert_sss_nss2nss_status(int errcode) { + enum nss_status ret = NSS_STATUS_UNAVAIL; + + if (errcode == 0) { + ret = NSS_STATUS_SUCCESS; + } else if (errcode == ENOENT) { + ret = NSS_STATUS_NOTFOUND; + } else if(errcode == ERANGE) { + ret = NSS_STATUS_TRYAGAIN; + } else if(errcode == ETIMEDOUT) { + ret = NSS_STATUS_UNAVAIL; + } else if(errcode == ETIME) { + ret = NSS_STATUS_TRYAGAIN; + }; + + return ret; +} + +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; +} + +void backend_nss_free_context(struct nss_ops_ctx **nss_context) +{ + if (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; +} + +/* TODO: handle buffers and memory allocation in this function */ +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); +} + +/* TODO: handle buffers and memory allocation in this function */ +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); + + if (ret != 0 && lerrno != NULL) { + /* SSSD translates errno into return code */ + *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); + if (ret != 0 && lerrno != NULL) { + /* SSSD translates errno into return code */ + *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); + if (ret != 0 && lerrno != NULL) { + /* SSSD translates errno into return code */ + *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); + if (ret != 0 && lerrno != NULL) { + /* SSSD translates errno into return code */ + *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); + if (ret != 0 && lerrno != NULL) { + /* SSSD translates errno into return code */ + *lerrno = ret; + } + return __convert_sss_nss2nss_status(ret); +} + diff --git a/src/back-sch.h b/src/back-sch.h index 9a9abc7..a400419 100644 --- a/src/back-sch.h +++ b/src/back-sch.h @@ -152,10 +152,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); 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); diff --git a/src/plug-sch.c b/src/plug-sch.c index 00e7041..6ee4042 100644 --- a/src/plug-sch.c +++ b/src/plug-sch.c @@ -104,6 +104,7 @@ plugin_startup(Slapi_PBlock *pb) struct plugin_state *state; Slapi_Entry *plugin_entry = NULL; Slapi_DN *pluginsdn = NULL; + unsigned int nss_timeout = 10000; slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &state); slapi_pblock_get(pb, SLAPI_TARGET_SDN, &pluginsdn); @@ -130,7 +131,13 @@ plugin_startup(Slapi_PBlock *pb) 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); -- 2.13.6