Blame SOURCES/0023-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch

ced1f5
From 15d7f1aeb541615314b914b6be1149f6e289d3e2 Mon Sep 17 00:00:00 2001
ced1f5
From: Sumit Bose <sbose@redhat.com>
ced1f5
Date: Fri, 29 Sep 2017 16:16:01 +0200
ced1f5
Subject: [PATCH 23/31] nss-idmap: add nss like calls with timeout and flags
ced1f5
ced1f5
This patch adds new calls to libsss_nss_idmap to get NSS like user and
ced1f5
group information directly from SSSD without using the system's NSS
ced1f5
interfaces.
ced1f5
ced1f5
Additionally a timeout and a flags options are added which are not
ced1f5
available for system's NSS.
ced1f5
ced1f5
Related to https://pagure.io/SSSD/sssd/issue/2478
ced1f5
ced1f5
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
ced1f5
(cherry picked from commit 5e6622722e84d594298a8324f3685a1bda2b5868)
ced1f5
---
ced1f5
 Makefile.am                                  |  22 +-
ced1f5
 configure.ac                                 |  13 +
ced1f5
 src/sss_client/common.c                      |   9 +-
ced1f5
 src/sss_client/common_private.h              |  41 +++
ced1f5
 src/sss_client/idmap/common_ex.c             | 105 +++++++
ced1f5
 src/sss_client/idmap/sss_nss_ex.c            | 402 +++++++++++++++++++++++++++
ced1f5
 src/sss_client/idmap/sss_nss_idmap.exports   |  10 +
ced1f5
 src/sss_client/idmap/sss_nss_idmap.h         | 135 +++++++++
ced1f5
 src/sss_client/idmap/sss_nss_idmap_private.h |  30 ++
ced1f5
 9 files changed, 757 insertions(+), 10 deletions(-)
ced1f5
 create mode 100644 src/sss_client/common_private.h
ced1f5
 create mode 100644 src/sss_client/idmap/common_ex.c
ced1f5
 create mode 100644 src/sss_client/idmap/sss_nss_ex.c
ced1f5
 create mode 100644 src/sss_client/idmap/sss_nss_idmap_private.h
ced1f5
ced1f5
diff --git a/Makefile.am b/Makefile.am
ced1f5
index dc2f4b1857ce5bd376544488348731be29b6b293..dd25d1f7ea1be66388aa1b393bac290c4d7501a2 100644
ced1f5
--- a/Makefile.am
ced1f5
+++ b/Makefile.am
ced1f5
@@ -1159,13 +1159,28 @@ pkgconfig_DATA += src/sss_client/idmap/sss_nss_idmap.pc
ced1f5
 libsss_nss_idmap_la_DEPENDENCIES = src/sss_client/idmap/sss_nss_idmap.exports
ced1f5
 libsss_nss_idmap_la_SOURCES = \
ced1f5
     src/sss_client/idmap/sss_nss_idmap.c \
ced1f5
+    src/sss_client/idmap/sss_nss_ex.c \
ced1f5
+    src/sss_client/idmap/sss_nss_idmap_private.h \
ced1f5
     src/sss_client/common.c \
ced1f5
-    src/util/strtonum.c
ced1f5
+    src/sss_client/idmap/common_ex.c \
ced1f5
+    src/sss_client/nss_mc_passwd.c \
ced1f5
+    src/sss_client/nss_passwd.c \
ced1f5
+    src/sss_client/nss_mc_group.c \
ced1f5
+    src/sss_client/nss_group.c \
ced1f5
+    src/sss_client/nss_mc_initgr.c \
ced1f5
+    src/sss_client/nss_mc_common.c \
ced1f5
+    src/util/strtonum.c \
ced1f5
+    src/util/murmurhash3.c \
ced1f5
+    src/util/io.c \
ced1f5
+    $(NULL)
ced1f5
 libsss_nss_idmap_la_LIBADD = \
ced1f5
-    $(CLIENT_LIBS)
ced1f5
+    $(LIBCLOCK_GETTIME) \
ced1f5
+    $(CLIENT_LIBS) \
ced1f5
+    -lpthread \
ced1f5
+    $(NULL)
ced1f5
 libsss_nss_idmap_la_LDFLAGS = \
ced1f5
     -Wl,--version-script,$(srcdir)/src/sss_client/idmap/sss_nss_idmap.exports \
ced1f5
-    -version-info 3:0:3
ced1f5
+    -version-info 4:0:4
ced1f5
 
ced1f5
 dist_noinst_DATA += src/sss_client/idmap/sss_nss_idmap.exports
ced1f5
 
ced1f5
@@ -3624,6 +3639,7 @@ libnss_sss_la_SOURCES = \
ced1f5
     src/sss_client/sss_cli.h \
ced1f5
     src/sss_client/nss_compat.h \
ced1f5
     src/sss_client/nss_common.h \
ced1f5
+    src/sss_client/common_private.h \
ced1f5
     src/sss_client/nss_mc_common.c \
ced1f5
     src/util/io.c \
ced1f5
     src/util/murmurhash3.c \
ced1f5
diff --git a/configure.ac b/configure.ac
ced1f5
index 7037927b5f7045b29d3774c85758e00e35e6def6..7e699d33e342c70d210d3f320c8a29a99e0c78a6 100644
ced1f5
--- a/configure.ac
ced1f5
+++ b/configure.ac
ced1f5
@@ -75,6 +75,19 @@ AC_SEARCH_LIBS([timer_create], [rt posix4],
ced1f5
 AC_SUBST([LIBADD_TIMER])
ced1f5
 LIBS=$SAVE_LIBS
ced1f5
 
ced1f5
+# Check library for the clock_gettime function
ced1f5
+SAVE_LIBS=$LIBS
ced1f5
+LIBS=
ced1f5
+LIBCLOCK_GETTIME=
ced1f5
+AC_SEARCH_LIBS([clock_gettime], [rt posix4],
ced1f5
+    [AC_DEFINE([HAVE_LIBRT], [1],
ced1f5
+         [Define if you have the librt library or equivalent.])
ced1f5
+     LIBCLOCK_GETTIME="$LIBS"],
ced1f5
+    [AC_MSG_ERROR([unable to find library for the clock_gettime() function])])
ced1f5
+
ced1f5
+AC_SUBST([LIBCLOCK_GETTIME])
ced1f5
+LIBS=$SAVE_LIBS
ced1f5
+
ced1f5
 # Check for presence of modern functions for setting file timestamps
ced1f5
 AC_CHECK_FUNCS([ utimensat \
ced1f5
                  futimens ])
ced1f5
diff --git a/src/sss_client/common.c b/src/sss_client/common.c
ced1f5
index e5e0cbf854e4c977c03f9b1ca1ac90bfd8cbdb77..40252a35281dc4e94c712c3e7f8253af8b19b35a 100644
ced1f5
--- a/src/sss_client/common.c
ced1f5
+++ b/src/sss_client/common.c
ced1f5
@@ -43,6 +43,7 @@
ced1f5
 #include <libintl.h>
ced1f5
 #define _(STRING) dgettext (PACKAGE, STRING)
ced1f5
 #include "sss_cli.h"
ced1f5
+#include "common_private.h"
ced1f5
 
ced1f5
 #if HAVE_PTHREAD
ced1f5
 #include <pthread.h>
ced1f5
@@ -1113,13 +1114,7 @@ errno_t sss_strnlen(const char *str, size_t maxlen, size_t *len)
ced1f5
 #if HAVE_PTHREAD
ced1f5
 typedef void (*sss_mutex_init)(void);
ced1f5
 
ced1f5
-struct sss_mutex {
ced1f5
-    pthread_mutex_t mtx;
ced1f5
-
ced1f5
-    int old_cancel_state;
ced1f5
-};
ced1f5
-
ced1f5
-static struct sss_mutex sss_nss_mtx = { .mtx  = PTHREAD_MUTEX_INITIALIZER };
ced1f5
+struct sss_mutex sss_nss_mtx = { .mtx  = PTHREAD_MUTEX_INITIALIZER };
ced1f5
 
ced1f5
 static struct sss_mutex sss_pam_mtx = { .mtx  = PTHREAD_MUTEX_INITIALIZER };
ced1f5
 
ced1f5
diff --git a/src/sss_client/common_private.h b/src/sss_client/common_private.h
ced1f5
new file mode 100644
ced1f5
index 0000000000000000000000000000000000000000..a98d2c062caeecdbab02ecdaa6ae44d688a791bb
ced1f5
--- /dev/null
ced1f5
+++ b/src/sss_client/common_private.h
ced1f5
@@ -0,0 +1,41 @@
ced1f5
+/*
ced1f5
+    SSSD
ced1f5
+
ced1f5
+    SSS client - private calls
ced1f5
+
ced1f5
+    Authors:
ced1f5
+        Sumit Bose <sbose@redhat.com>
ced1f5
+
ced1f5
+    Copyright (C) 2017 Red Hat
ced1f5
+
ced1f5
+    This program is free software; you can redistribute it and/or modify
ced1f5
+    it under the terms of the GNU General Public License as published by
ced1f5
+    the Free Software Foundation; either version 3 of the License, or
ced1f5
+    (at your option) any later version.
ced1f5
+
ced1f5
+    This program is distributed in the hope that it will be useful,
ced1f5
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
ced1f5
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
ced1f5
+    GNU General Public License for more details.
ced1f5
+
ced1f5
+    You should have received a copy of the GNU General Public License
ced1f5
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
ced1f5
+*/
ced1f5
+
ced1f5
+#ifndef COMMON_PRIVATE_H_
ced1f5
+#define COMMON_PRIVATE_H_
ced1f5
+
ced1f5
+#include "config.h"
ced1f5
+
ced1f5
+#if HAVE_PTHREAD
ced1f5
+#include <pthread.h>
ced1f5
+
ced1f5
+struct sss_mutex {
ced1f5
+    pthread_mutex_t mtx;
ced1f5
+
ced1f5
+    int old_cancel_state;
ced1f5
+};
ced1f5
+
ced1f5
+#endif /* HAVE_PTHREAD */
ced1f5
+
ced1f5
+#endif /* COMMON_PRIVATE_H_ */
ced1f5
diff --git a/src/sss_client/idmap/common_ex.c b/src/sss_client/idmap/common_ex.c
ced1f5
new file mode 100644
ced1f5
index 0000000000000000000000000000000000000000..5efe9fabed7896ce674615472dbb256c4eae2144
ced1f5
--- /dev/null
ced1f5
+++ b/src/sss_client/idmap/common_ex.c
ced1f5
@@ -0,0 +1,105 @@
ced1f5
+/*
ced1f5
+    Authors:
ced1f5
+        Sumit Bose <sbose@redhat.com>
ced1f5
+
ced1f5
+    Copyright (C) 2017 Red Hat
ced1f5
+
ced1f5
+    SSSD's enhanced NSS API
ced1f5
+
ced1f5
+    This program is free software; you can redistribute it and/or modify
ced1f5
+    it under the terms of the GNU General Public License as published by
ced1f5
+    the Free Software Foundation; either version 3 of the License, or
ced1f5
+    (at your option) any later version.
ced1f5
+
ced1f5
+    This program is distributed in the hope that it will be useful,
ced1f5
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
ced1f5
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
ced1f5
+    GNU General Public License for more details.
ced1f5
+
ced1f5
+    You should have received a copy of the GNU General Public License
ced1f5
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
ced1f5
+*/
ced1f5
+
ced1f5
+#include <time.h>
ced1f5
+#include <errno.h>
ced1f5
+
ced1f5
+#include "sss_cli.h"
ced1f5
+#include "common_private.h"
ced1f5
+
ced1f5
+extern struct sss_mutex sss_nss_mtx;
ced1f5
+
ced1f5
+#define SEC_FROM_MSEC(ms) ((ms) / 1000)
ced1f5
+#define NSEC_FROM_MSEC(ms) (((ms) % 1000) * 1000 * 1000)
ced1f5
+
ced1f5
+/* adopted from timersub() defined in /usr/include/sys/time.h */
ced1f5
+#define TIMESPECSUB(a, b, result)                                             \
ced1f5
+  do {                                                                        \
ced1f5
+    (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                             \
ced1f5
+    (result)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec;                          \
ced1f5
+    if ((result)->tv_nsec < 0) {                                              \
ced1f5
+      --(result)->tv_sec;                                                     \
ced1f5
+      (result)->tv_nsec += 1000000000;                                        \
ced1f5
+    }                                                                         \
ced1f5
+  } while (0)
ced1f5
+
ced1f5
+#define TIMESPEC_TO_MS(ts) (  ((ts)->tv_sec * 1000) \
ced1f5
+                            + ((ts)->tv_nsec) / (1000 * 1000) )
ced1f5
+
ced1f5
+static int sss_mt_timedlock(struct sss_mutex *m, struct timespec *endtime)
ced1f5
+{
ced1f5
+    int ret;
ced1f5
+
ced1f5
+    ret = pthread_mutex_timedlock(&m->mtx, endtime);
ced1f5
+    if (ret != 0) {
ced1f5
+        return ret;
ced1f5
+    }
ced1f5
+    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &m->old_cancel_state);
ced1f5
+
ced1f5
+    return 0;
ced1f5
+}
ced1f5
+
ced1f5
+int sss_nss_timedlock(unsigned int timeout_ms, int *time_left_ms)
ced1f5
+{
ced1f5
+    int ret;
ced1f5
+    int left;
ced1f5
+    struct timespec starttime;
ced1f5
+    struct timespec endtime;
ced1f5
+    struct timespec diff;
ced1f5
+
ced1f5
+    /* make sure there is no overrun when calculating the time left */
ced1f5
+    if (timeout_ms > INT_MAX) {
ced1f5
+        timeout_ms = INT_MAX;
ced1f5
+    }
ced1f5
+
ced1f5
+    ret = clock_gettime(CLOCK_REALTIME, &starttime);
ced1f5
+    if (ret != 0) {
ced1f5
+        return ret;
ced1f5
+    }
ced1f5
+    endtime.tv_sec = starttime.tv_sec + SEC_FROM_MSEC(timeout_ms);
ced1f5
+    endtime.tv_nsec = starttime.tv_nsec + NSEC_FROM_MSEC(timeout_ms);
ced1f5
+
ced1f5
+    ret = sss_mt_timedlock(&sss_nss_mtx, &endtime);
ced1f5
+
ced1f5
+    if (ret == 0) {
ced1f5
+        ret = clock_gettime(CLOCK_REALTIME, &endtime);
ced1f5
+        if (ret != 0) {
ced1f5
+            return ret;
ced1f5
+        }
ced1f5
+
ced1f5
+        if (timeout_ms == 0) {
ced1f5
+            *time_left_ms = 0;
ced1f5
+        } else {
ced1f5
+            TIMESPECSUB(&endtime, &starttime, &diff);
ced1f5
+            left = timeout_ms - TIMESPEC_TO_MS(&diff);
ced1f5
+            if (left <= 0) {
ced1f5
+                return EIO;
ced1f5
+            } else if (left > SSS_CLI_SOCKET_TIMEOUT) {
ced1f5
+                *time_left_ms = SSS_CLI_SOCKET_TIMEOUT;
ced1f5
+            } else {
ced1f5
+                *time_left_ms = left;
ced1f5
+            }
ced1f5
+        }
ced1f5
+    }
ced1f5
+
ced1f5
+    return ret;
ced1f5
+}
ced1f5
diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c
ced1f5
new file mode 100644
ced1f5
index 0000000000000000000000000000000000000000..582d1373ec35305cf128e04fd3d705457d304789
ced1f5
--- /dev/null
ced1f5
+++ b/src/sss_client/idmap/sss_nss_ex.c
ced1f5
@@ -0,0 +1,402 @@
ced1f5
+/*
ced1f5
+    SSSD
ced1f5
+
ced1f5
+    Extended NSS Responder Interface
ced1f5
+
ced1f5
+    Authors:
ced1f5
+        Sumit Bose <sbose@redhat.com>
ced1f5
+
ced1f5
+    Copyright (C) 2017 Red Hat
ced1f5
+
ced1f5
+    This program is free software; you can redistribute it and/or modify
ced1f5
+    it under the terms of the GNU General Public License as published by
ced1f5
+    the Free Software Foundation; either version 3 of the License, or
ced1f5
+    (at your option) any later version.
ced1f5
+
ced1f5
+    This program is distributed in the hope that it will be useful,
ced1f5
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
ced1f5
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
ced1f5
+    GNU General Public License for more details.
ced1f5
+
ced1f5
+    You should have received a copy of the GNU General Public License
ced1f5
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
ced1f5
+*/
ced1f5
+#include <stdlib.h>
ced1f5
+#include <errno.h>
ced1f5
+
ced1f5
+#include <sys/param.h> /* for MIN() */
ced1f5
+
ced1f5
+#include "sss_client/sss_cli.h"
ced1f5
+#include "sss_client/nss_mc.h"
ced1f5
+#include "sss_client/nss_common.h"
ced1f5
+#include "sss_client/idmap/sss_nss_idmap.h"
ced1f5
+#include "sss_client/idmap/sss_nss_idmap_private.h"
ced1f5
+
ced1f5
+#ifndef discard_const
ced1f5
+#define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
ced1f5
+#endif
ced1f5
+
ced1f5
+struct sss_nss_initgr_rep {
ced1f5
+    gid_t *groups;
ced1f5
+    long int *ngroups;
ced1f5
+    long int *start;
ced1f5
+};
ced1f5
+
ced1f5
+struct nss_input {
ced1f5
+    union {
ced1f5
+        const char *name;
ced1f5
+        uid_t uid;
ced1f5
+        gid_t gid;
ced1f5
+    } input;
ced1f5
+    struct sss_cli_req_data rd;
ced1f5
+    enum sss_cli_command cmd;
ced1f5
+    union {
ced1f5
+        struct sss_nss_pw_rep pwrep;
ced1f5
+        struct sss_nss_gr_rep grrep;
ced1f5
+        struct sss_nss_initgr_rep initgrrep;
ced1f5
+    } result;
ced1f5
+};
ced1f5
+
ced1f5
+errno_t sss_nss_mc_get(struct nss_input *inp)
ced1f5
+{
ced1f5
+    switch(inp->cmd) {
ced1f5
+    case SSS_NSS_GETPWNAM:
ced1f5
+        return sss_nss_mc_getpwnam(inp->input.name, (inp->rd.len - 1),
ced1f5
+                                   inp->result.pwrep.result,
ced1f5
+                                   inp->result.pwrep.buffer,
ced1f5
+                                   inp->result.pwrep.buflen);
ced1f5
+        break;
ced1f5
+    case SSS_NSS_GETPWUID:
ced1f5
+        return sss_nss_mc_getpwuid(inp->input.uid,
ced1f5
+                                   inp->result.pwrep.result,
ced1f5
+                                   inp->result.pwrep.buffer,
ced1f5
+                                   inp->result.pwrep.buflen);
ced1f5
+        break;
ced1f5
+    case SSS_NSS_GETGRNAM:
ced1f5
+        return sss_nss_mc_getgrnam(inp->input.name, (inp->rd.len - 1),
ced1f5
+                                   inp->result.grrep.result,
ced1f5
+                                   inp->result.grrep.buffer,
ced1f5
+                                   inp->result.grrep.buflen);
ced1f5
+        break;
ced1f5
+    case SSS_NSS_GETGRGID:
ced1f5
+        return sss_nss_mc_getgrgid(inp->input.gid,
ced1f5
+                                   inp->result.grrep.result,
ced1f5
+                                   inp->result.grrep.buffer,
ced1f5
+                                   inp->result.grrep.buflen);
ced1f5
+        break;
ced1f5
+    case SSS_NSS_INITGR:
ced1f5
+        return sss_nss_mc_initgroups_dyn(inp->input.name, (inp->rd.len - 1),
ced1f5
+                                         -1 /* currently ignored */,
ced1f5
+                                         inp->result.initgrrep.start,
ced1f5
+                                         inp->result.initgrrep.ngroups,
ced1f5
+                                         &(inp->result.initgrrep.groups),
ced1f5
+                                         *(inp->result.initgrrep.ngroups));
ced1f5
+        break;
ced1f5
+    default:
ced1f5
+        return EINVAL;
ced1f5
+    }
ced1f5
+}
ced1f5
+
ced1f5
+int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout)
ced1f5
+{
ced1f5
+    uint8_t *repbuf = NULL;
ced1f5
+    size_t replen;
ced1f5
+    size_t len;
ced1f5
+    uint32_t num_results;
ced1f5
+    int ret;
ced1f5
+    int time_left;
ced1f5
+    int errnop;
ced1f5
+    size_t c;
ced1f5
+    gid_t *new_groups;
ced1f5
+    size_t idx;
ced1f5
+
ced1f5
+    ret = sss_nss_mc_get(inp);
ced1f5
+    switch (ret) {
ced1f5
+    case 0:
ced1f5
+        return 0;
ced1f5
+    case ERANGE:
ced1f5
+        return ERANGE;
ced1f5
+    case ENOENT:
ced1f5
+        /* fall through, we need to actively ask the parent
ced1f5
+         * if no entry is found */
ced1f5
+        break;
ced1f5
+    default:
ced1f5
+        /* if using the mmaped cache failed,
ced1f5
+         * fall back to socket based comms */
ced1f5
+        break;
ced1f5
+    }
ced1f5
+
ced1f5
+    sss_nss_timedlock(timeout, &time_left);
ced1f5
+
ced1f5
+    /* previous thread might already initialize entry in mmap cache */
ced1f5
+    ret = sss_nss_mc_get(inp);
ced1f5
+    switch (ret) {
ced1f5
+    case 0:
ced1f5
+        ret = 0;
ced1f5
+        goto out;
ced1f5
+    case ERANGE:
ced1f5
+        ret = ERANGE;
ced1f5
+        goto out;
ced1f5
+    case ENOENT:
ced1f5
+        /* fall through, we need to actively ask the parent
ced1f5
+         * if no entry is found */
ced1f5
+        break;
ced1f5
+    default:
ced1f5
+        /* if using the mmaped cache failed,
ced1f5
+         * fall back to socket based comms */
ced1f5
+        break;
ced1f5
+    }
ced1f5
+
ced1f5
+    ret = sss_nss_make_request_timeout(inp->cmd, &inp->rd, time_left,
ced1f5
+                                       &repbuf, &replen, &errnop);
ced1f5
+    if (ret != NSS_STATUS_SUCCESS) {
ced1f5
+        ret = errnop != 0 ? errnop : EIO;
ced1f5
+        goto out;
ced1f5
+    }
ced1f5
+
ced1f5
+    /* Get number of results from repbuf. */
ced1f5
+    SAFEALIGN_COPY_UINT32(&num_results, repbuf, NULL);
ced1f5
+
ced1f5
+    /* no results if not found */
ced1f5
+    if (num_results == 0) {
ced1f5
+        ret = ENOENT;
ced1f5
+        goto out;
ced1f5
+    }
ced1f5
+
ced1f5
+    if (inp->cmd == SSS_NSS_INITGR) {
ced1f5
+        if ((*(inp->result.initgrrep.ngroups) - *(inp->result.initgrrep.start))
ced1f5
+                    < num_results) {
ced1f5
+            new_groups = realloc(inp->result.initgrrep.groups,
ced1f5
+                                 (num_results + *(inp->result.initgrrep.start))
ced1f5
+                                    * sizeof(gid_t));
ced1f5
+            if (new_groups == NULL) {
ced1f5
+                ret = ENOMEM;
ced1f5
+                goto out;
ced1f5
+            }
ced1f5
+
ced1f5
+            inp->result.initgrrep.groups = new_groups;
ced1f5
+        }
ced1f5
+        *(inp->result.initgrrep.ngroups) = num_results
ced1f5
+                                            + *(inp->result.initgrrep.start);
ced1f5
+
ced1f5
+        idx = 2 * sizeof(uint32_t);
ced1f5
+        for (c = 0; c < num_results; c++) {
ced1f5
+            SAFEALIGN_COPY_UINT32(
ced1f5
+                &(inp->result.initgrrep.groups[*(inp->result.initgrrep.start)]),
ced1f5
+                repbuf + idx, &idx);
ced1f5
+            *(inp->result.initgrrep.start) += 1;
ced1f5
+        }
ced1f5
+
ced1f5
+        ret = 0;
ced1f5
+        goto out;
ced1f5
+    }
ced1f5
+
ced1f5
+    /* only 1 result is accepted for this function */
ced1f5
+    if (num_results != 1) {
ced1f5
+        ret = EBADMSG;
ced1f5
+        goto out;
ced1f5
+    }
ced1f5
+
ced1f5
+    len = replen - 8;
ced1f5
+    if (inp->cmd == SSS_NSS_GETPWNAM || inp->cmd == SSS_NSS_GETPWUID) {
ced1f5
+        ret = sss_nss_getpw_readrep(&(inp->result.pwrep), repbuf+8, &len;;
ced1f5
+    } else if (inp->cmd == SSS_NSS_GETGRNAM || inp->cmd == SSS_NSS_GETGRGID) {
ced1f5
+        ret = sss_nss_getgr_readrep(&(inp->result.grrep), repbuf+8, &len;;
ced1f5
+    } else {
ced1f5
+        ret = EINVAL;
ced1f5
+        goto out;
ced1f5
+    }
ced1f5
+    if (ret) {
ced1f5
+        goto out;
ced1f5
+    }
ced1f5
+
ced1f5
+    if (len == 0) {
ced1f5
+        /* no extra data */
ced1f5
+        ret = 0;
ced1f5
+        goto out;
ced1f5
+    }
ced1f5
+
ced1f5
+out:
ced1f5
+    free(repbuf);
ced1f5
+
ced1f5
+    sss_nss_unlock();
ced1f5
+    return ret;
ced1f5
+}
ced1f5
+
ced1f5
+int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd,
ced1f5
+                             char *buffer, size_t buflen,
ced1f5
+                             struct passwd **result,
ced1f5
+                             uint32_t flags, unsigned int timeout)
ced1f5
+{
ced1f5
+    int ret;
ced1f5
+    struct nss_input inp = {
ced1f5
+        .input.name = name,
ced1f5
+        .cmd = SSS_NSS_GETPWNAM,
ced1f5
+        .rd.data = name,
ced1f5
+        .result.pwrep.result = pwd,
ced1f5
+        .result.pwrep.buffer = buffer,
ced1f5
+        .result.pwrep.buflen = buflen};
ced1f5
+
ced1f5
+    if (buffer == NULL || buflen == 0) {
ced1f5
+        return ERANGE;
ced1f5
+    }
ced1f5
+
ced1f5
+    ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len);
ced1f5
+    if (ret != 0) {
ced1f5
+        return EINVAL;
ced1f5
+    }
ced1f5
+    inp.rd.len++;
ced1f5
+
ced1f5
+    *result = NULL;
ced1f5
+
ced1f5
+    ret = sss_get_ex(&inp, flags, timeout);
ced1f5
+    if (ret == 0) {
ced1f5
+        *result = inp.result.pwrep.result;
ced1f5
+    }
ced1f5
+    return ret;
ced1f5
+}
ced1f5
+
ced1f5
+int sss_nss_getpwuid_timeout(uid_t uid, struct passwd *pwd,
ced1f5
+                             char *buffer, size_t buflen,
ced1f5
+                             struct passwd **result,
ced1f5
+                             uint32_t flags, unsigned int timeout)
ced1f5
+{
ced1f5
+    int ret;
ced1f5
+    uint32_t user_uid = uid;
ced1f5
+    struct nss_input inp = {
ced1f5
+        .input.uid = uid,
ced1f5
+        .cmd = SSS_NSS_GETPWUID,
ced1f5
+        .rd.len = sizeof(uint32_t),
ced1f5
+        .rd.data = &user_uid,
ced1f5
+        .result.pwrep.result = pwd,
ced1f5
+        .result.pwrep.buffer = buffer,
ced1f5
+        .result.pwrep.buflen = buflen};
ced1f5
+
ced1f5
+    if (buffer == NULL || buflen == 0) {
ced1f5
+        return ERANGE;
ced1f5
+    }
ced1f5
+
ced1f5
+    *result = NULL;
ced1f5
+
ced1f5
+    ret = sss_get_ex(&inp, flags, timeout);
ced1f5
+    if (ret == 0) {
ced1f5
+        *result = inp.result.pwrep.result;
ced1f5
+    }
ced1f5
+    return ret;
ced1f5
+}
ced1f5
+
ced1f5
+int sss_nss_getgrnam_timeout(const char *name, struct group *grp,
ced1f5
+                             char *buffer, size_t buflen, struct group **result,
ced1f5
+                             uint32_t flags, unsigned int timeout)
ced1f5
+{
ced1f5
+    int ret;
ced1f5
+    struct nss_input inp = {
ced1f5
+        .input.name = name,
ced1f5
+        .cmd = SSS_NSS_GETGRNAM,
ced1f5
+        .rd.data = name,
ced1f5
+        .result.grrep.result = grp,
ced1f5
+        .result.grrep.buffer = buffer,
ced1f5
+        .result.grrep.buflen = buflen};
ced1f5
+
ced1f5
+    if (buffer == NULL || buflen == 0) {
ced1f5
+        return ERANGE;
ced1f5
+    }
ced1f5
+
ced1f5
+    ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len);
ced1f5
+    if (ret != 0) {
ced1f5
+        return EINVAL;
ced1f5
+    }
ced1f5
+    inp.rd.len++;
ced1f5
+
ced1f5
+    *result = NULL;
ced1f5
+
ced1f5
+    ret = sss_get_ex(&inp, flags, timeout);
ced1f5
+    if (ret == 0) {
ced1f5
+        *result = inp.result.grrep.result;
ced1f5
+    }
ced1f5
+    return ret;
ced1f5
+}
ced1f5
+
ced1f5
+int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp,
ced1f5
+                             char *buffer, size_t buflen, struct group **result,
ced1f5
+                             uint32_t flags, unsigned int timeout)
ced1f5
+{
ced1f5
+    int ret;
ced1f5
+    uint32_t group_gid = gid;
ced1f5
+    struct nss_input inp = {
ced1f5
+        .input.gid = gid,
ced1f5
+        .cmd = SSS_NSS_GETGRGID,
ced1f5
+        .rd.len = sizeof(uint32_t),
ced1f5
+        .rd.data = &group_gid,
ced1f5
+        .result.grrep.result = grp,
ced1f5
+        .result.grrep.buffer = buffer,
ced1f5
+        .result.grrep.buflen = buflen};
ced1f5
+
ced1f5
+    if (buffer == NULL || buflen == 0) {
ced1f5
+        return ERANGE;
ced1f5
+    }
ced1f5
+
ced1f5
+    *result = NULL;
ced1f5
+
ced1f5
+    ret = sss_get_ex(&inp, flags, timeout);
ced1f5
+    if (ret == 0) {
ced1f5
+        *result = inp.result.grrep.result;
ced1f5
+    }
ced1f5
+    return ret;
ced1f5
+}
ced1f5
+
ced1f5
+int sss_nss_getgrouplist_timeout(const char *name, gid_t group,
ced1f5
+                                 gid_t *groups, int *ngroups,
ced1f5
+                                 uint32_t flags, unsigned int timeout)
ced1f5
+{
ced1f5
+    int ret;
ced1f5
+    gid_t *new_groups;
ced1f5
+    long int new_ngroups;
ced1f5
+    long int start = 1;
ced1f5
+    struct nss_input inp = {
ced1f5
+        .input.name = name,
ced1f5
+        .cmd = SSS_NSS_INITGR,
ced1f5
+        .rd.data = name};
ced1f5
+
ced1f5
+    if (groups == NULL || ngroups == NULL || *ngroups == 0) {
ced1f5
+        return EINVAL;
ced1f5
+    }
ced1f5
+
ced1f5
+    ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len);
ced1f5
+    if (ret != 0) {
ced1f5
+        return ret;
ced1f5
+    }
ced1f5
+    inp.rd.len++;
ced1f5
+
ced1f5
+    new_ngroups = MAX(1, *ngroups);
ced1f5
+    new_groups = malloc(new_ngroups * sizeof(gid_t));
ced1f5
+    if (new_groups == NULL) {
ced1f5
+        free(discard_const(inp.rd.data));
ced1f5
+        return ENOMEM;
ced1f5
+    }
ced1f5
+    new_groups[0] = group;
ced1f5
+
ced1f5
+    inp.result.initgrrep.groups = new_groups,
ced1f5
+    inp.result.initgrrep.ngroups = &new_ngroups;
ced1f5
+    inp.result.initgrrep.start = &start;
ced1f5
+
ced1f5
+
ced1f5
+    ret = sss_get_ex(&inp, flags, timeout);
ced1f5
+    free(discard_const(inp.rd.data));
ced1f5
+    if (ret != 0) {
ced1f5
+        free(new_groups);
ced1f5
+        return ret;
ced1f5
+    }
ced1f5
+
ced1f5
+    memcpy(groups, new_groups, MIN(*ngroups, start) * sizeof(gid_t));
ced1f5
+    free(new_groups);
ced1f5
+
ced1f5
+    if (start > *ngroups) {
ced1f5
+        ret = ERANGE;
ced1f5
+    } else {
ced1f5
+        ret = 0;
ced1f5
+    }
ced1f5
+    *ngroups = start;
ced1f5
+
ced1f5
+    return ret;
ced1f5
+}
ced1f5
diff --git a/src/sss_client/idmap/sss_nss_idmap.exports b/src/sss_client/idmap/sss_nss_idmap.exports
ced1f5
index 49dac6fc9351b0ca98cd46e83b85ec8ef0075a0d..788d05ecc3bd56fa88e68a98b9c8096cf7140a09 100644
ced1f5
--- a/src/sss_client/idmap/sss_nss_idmap.exports
ced1f5
+++ b/src/sss_client/idmap/sss_nss_idmap.exports
ced1f5
@@ -31,3 +31,13 @@ SSS_NSS_IDMAP_0.3.0 {
ced1f5
     global:
ced1f5
         sss_nss_getlistbycert;
ced1f5
 } SSS_NSS_IDMAP_0.2.0;
ced1f5
+
ced1f5
+SSS_NSS_IDMAP_0.4.0 {
ced1f5
+    # public functions
ced1f5
+    global:
ced1f5
+        sss_nss_getpwnam_timeout;
ced1f5
+        sss_nss_getpwuid_timeout;
ced1f5
+        sss_nss_getgrnam_timeout;
ced1f5
+        sss_nss_getgrgid_timeout;
ced1f5
+        sss_nss_getgrouplist_timeout;
ced1f5
+} SSS_NSS_IDMAP_0.3.0;
ced1f5
diff --git a/src/sss_client/idmap/sss_nss_idmap.h b/src/sss_client/idmap/sss_nss_idmap.h
ced1f5
index cbf19479ff9ec6e0d6e07e1f7e48a1571e147740..2334b6cb3fb8ef62e4ce3a7187c7affaeaa034e7 100644
ced1f5
--- a/src/sss_client/idmap/sss_nss_idmap.h
ced1f5
+++ b/src/sss_client/idmap/sss_nss_idmap.h
ced1f5
@@ -26,6 +26,9 @@
ced1f5
 #define SSS_NSS_IDMAP_H_
ced1f5
 
ced1f5
 #include <stdint.h>
ced1f5
+#include <sys/types.h>
ced1f5
+#include <pwd.h>
ced1f5
+#include <grp.h>
ced1f5
 
ced1f5
 /**
ced1f5
  * Object types
ced1f5
@@ -159,4 +162,136 @@ int sss_nss_getlistbycert(const char *cert, char ***fq_name,
ced1f5
  * @param[in] kv_list Key-value list returned by sss_nss_getorigbyname().
ced1f5
  */
ced1f5
 void sss_nss_free_kv(struct sss_nss_kv *kv_list);
ced1f5
+
ced1f5
+/**
ced1f5
+ * Flags to control the behavior and the results for sss_*_ex() calls
ced1f5
+ */
ced1f5
+
ced1f5
+#define SSS_NSS_EX_FLAG_NO_FLAGS 0
ced1f5
+
ced1f5
+#ifdef IPA_389DS_PLUGIN_HELPER_CALLS
ced1f5
+
ced1f5
+/**
ced1f5
+ * @brief Return user information based on the user name
ced1f5
+ *
ced1f5
+ * @param[in]  name       same as for getpwnam_r(3)
ced1f5
+ * @param[in]  pwd        same as for getpwnam_r(3)
ced1f5
+ * @param[in]  buffer     same as for getpwnam_r(3)
ced1f5
+ * @param[in]  buflen     same as for getpwnam_r(3)
ced1f5
+ * @param[out] result     same as for getpwnam_r(3)
ced1f5
+ * @param[in]  flags      flags to control the behavior and the results of the
ced1f5
+ *                        call
ced1f5
+ * @param[in]  timeout    timeout in milliseconds
ced1f5
+ *
ced1f5
+ * @return
ced1f5
+ *  - 0:
ced1f5
+ *  - ENOENT:    no user with the given name found
ced1f5
+ *  - ERANGE:    Insufficient buffer space supplied
ced1f5
+ *  - ETIME:     request timed out but was send to SSSD
ced1f5
+ *  - ETIMEDOUT: request timed out but was not send to SSSD
ced1f5
+ */
ced1f5
+int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd,
ced1f5
+                             char *buffer, size_t buflen,
ced1f5
+                             struct passwd **result,
ced1f5
+                             uint32_t flags, unsigned int timeout);
ced1f5
+
ced1f5
+/**
ced1f5
+ * @brief Return user information based on the user uid
ced1f5
+ *
ced1f5
+ * @param[in]  uid        same as for getpwuid_r(3)
ced1f5
+ * @param[in]  pwd        same as for getpwuid_r(3)
ced1f5
+ * @param[in]  buffer     same as for getpwuid_r(3)
ced1f5
+ * @param[in]  buflen     same as for getpwuid_r(3)
ced1f5
+ * @param[out] result     same as for getpwuid_r(3)
ced1f5
+ * @param[in]  flags      flags to control the behavior and the results of the
ced1f5
+ *                        call
ced1f5
+ * @param[in]  timeout    timeout in milliseconds
ced1f5
+ *
ced1f5
+ * @return
ced1f5
+ *  - 0:
ced1f5
+ *  - ENOENT:    no user with the given uid found
ced1f5
+ *  - ERANGE:    Insufficient buffer space supplied
ced1f5
+ *  - ETIME:     request timed out but was send to SSSD
ced1f5
+ *  - ETIMEDOUT: request timed out but was not send to SSSD
ced1f5
+ */
ced1f5
+int sss_nss_getpwuid_timeout(uid_t uid, struct passwd *pwd,
ced1f5
+                             char *buffer, size_t buflen,
ced1f5
+                             struct passwd **result,
ced1f5
+                             uint32_t flags, unsigned int timeout);
ced1f5
+
ced1f5
+/**
ced1f5
+ * @brief Return group information based on the group name
ced1f5
+ *
ced1f5
+ * @param[in]  name       same as for getgrnam_r(3)
ced1f5
+ * @param[in]  pwd        same as for getgrnam_r(3)
ced1f5
+ * @param[in]  buffer     same as for getgrnam_r(3)
ced1f5
+ * @param[in]  buflen     same as for getgrnam_r(3)
ced1f5
+ * @param[out] result     same as for getgrnam_r(3)
ced1f5
+ * @param[in]  flags      flags to control the behavior and the results of the
ced1f5
+ *                        call
ced1f5
+ * @param[in]  timeout    timeout in milliseconds
ced1f5
+ *
ced1f5
+ * @return
ced1f5
+ *  - 0:
ced1f5
+ *  - ENOENT:    no group with the given name found
ced1f5
+ *  - ERANGE:    Insufficient buffer space supplied
ced1f5
+ *  - ETIME:     request timed out but was send to SSSD
ced1f5
+ *  - ETIMEDOUT: request timed out but was not send to SSSD
ced1f5
+ */
ced1f5
+int sss_nss_getgrnam_timeout(const char *name, struct group *grp,
ced1f5
+                             char *buffer, size_t buflen, struct group **result,
ced1f5
+                             uint32_t flags, unsigned int timeout);
ced1f5
+
ced1f5
+/**
ced1f5
+ * @brief Return group information based on the group gid
ced1f5
+ *
ced1f5
+ * @param[in]  gid        same as for getgrgid_r(3)
ced1f5
+ * @param[in]  pwd        same as for getgrgid_r(3)
ced1f5
+ * @param[in]  buffer     same as for getgrgid_r(3)
ced1f5
+ * @param[in]  buflen     same as for getgrgid_r(3)
ced1f5
+ * @param[out] result     same as for getgrgid_r(3)
ced1f5
+ * @param[in]  flags      flags to control the behavior and the results of the
ced1f5
+ *                        call
ced1f5
+ * @param[in]  timeout    timeout in milliseconds
ced1f5
+ *
ced1f5
+ * @return
ced1f5
+ *  - 0:
ced1f5
+ *  - ENOENT:    no group with the given gid found
ced1f5
+ *  - ERANGE:    Insufficient buffer space supplied
ced1f5
+ *  - ETIME:     request timed out but was send to SSSD
ced1f5
+ *  - ETIMEDOUT: request timed out but was not send to SSSD
ced1f5
+ */
ced1f5
+int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp,
ced1f5
+                             char *buffer, size_t buflen, struct group **result,
ced1f5
+                             uint32_t flags, unsigned int timeout);
ced1f5
+
ced1f5
+/**
ced1f5
+ * @brief Return a list of groups to which a user belongs
ced1f5
+ *
ced1f5
+ * @param[in]      name       name of the user
ced1f5
+ * @param[in]      group      same as second argument of getgrouplist(3)
ced1f5
+ * @param[in]      groups     array of gid_t of size ngroups, will be filled
ced1f5
+ *                            with GIDs of groups the user belongs to
ced1f5
+ * @param[in,out]  ngroups    size of the groups array on input. On output it
ced1f5
+ *                            will contain the actual number of groups the
ced1f5
+ *                            user belongs to. With a return value of 0 the
ced1f5
+ *                            groups array was large enough to hold all group.
ced1f5
+ *                            With a return valu of ERANGE the array was not
ced1f5
+ *                            large enough and ngroups will have the needed
ced1f5
+ *                            size.
ced1f5
+ * @param[in]  flags          flags to control the behavior and the results of
ced1f5
+ *                            the call
ced1f5
+ * @param[in]  timeout        timeout in milliseconds
ced1f5
+ *
ced1f5
+ * @return
ced1f5
+ *  - 0:         success
ced1f5
+ *  - ENOENT:    no user with the given name found
ced1f5
+ *  - ERANGE:    Insufficient buffer space supplied
ced1f5
+ *  - ETIME:     request timed out but was send to SSSD
ced1f5
+ *  - ETIMEDOUT: request timed out but was not send to SSSD
ced1f5
+ */
ced1f5
+int sss_nss_getgrouplist_timeout(const char *name, gid_t group,
ced1f5
+                                 gid_t *groups, int *ngroups,
ced1f5
+                                 uint32_t flags, unsigned int timeout);
ced1f5
+#endif /* IPA_389DS_PLUGIN_HELPER_CALLS */
ced1f5
 #endif /* SSS_NSS_IDMAP_H_ */
ced1f5
diff --git a/src/sss_client/idmap/sss_nss_idmap_private.h b/src/sss_client/idmap/sss_nss_idmap_private.h
ced1f5
new file mode 100644
ced1f5
index 0000000000000000000000000000000000000000..afcd8e355981b9a2dc29a62bab143756b39ed654
ced1f5
--- /dev/null
ced1f5
+++ b/src/sss_client/idmap/sss_nss_idmap_private.h
ced1f5
@@ -0,0 +1,30 @@
ced1f5
+/*
ced1f5
+    SSSD
ced1f5
+
ced1f5
+    NSS Responder ID-mapping interface - private calls
ced1f5
+
ced1f5
+    Authors:
ced1f5
+        Sumit Bose <sbose@redhat.com>
ced1f5
+
ced1f5
+    Copyright (C) 2017 Red Hat
ced1f5
+
ced1f5
+    This program is free software; you can redistribute it and/or modify
ced1f5
+    it under the terms of the GNU General Public License as published by
ced1f5
+    the Free Software Foundation; either version 3 of the License, or
ced1f5
+    (at your option) any later version.
ced1f5
+
ced1f5
+    This program is distributed in the hope that it will be useful,
ced1f5
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
ced1f5
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
ced1f5
+    GNU General Public License for more details.
ced1f5
+
ced1f5
+    You should have received a copy of the GNU General Public License
ced1f5
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
ced1f5
+*/
ced1f5
+
ced1f5
+#ifndef SSS_NSS_IDMAP_PRIVATE_H_
ced1f5
+#define SSS_NSS_IDMAP_PRIVATE_H_
ced1f5
+
ced1f5
+int sss_nss_timedlock(unsigned int timeout_ms, int *time_left_ms);
ced1f5
+
ced1f5
+#endif /* SSS_NSS_IDMAP_PRIVATE_H_ */
ced1f5
-- 
ced1f5
2.13.6
ced1f5