summaryrefslogtreecommitdiff
path: root/src/nsssd
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2018-06-26 00:25:28 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2018-06-26 00:25:28 +0000
commit633445be1a9be37ae727c044417f5607706cf4ae (patch)
tree3c037459f5249e5c18ee5b9e41802c5964364f95 /src/nsssd
downloadnsss-633445be1a9be37ae727c044417f5607706cf4ae.tar.xz
Initial commit
Diffstat (limited to 'src/nsssd')
-rw-r--r--src/nsssd/deps-exe/nsssd-nslcd2
-rw-r--r--src/nsssd/deps-exe/nsssd-unix3
-rw-r--r--src/nsssd/deps-lib/nsssd3
-rw-r--r--src/nsssd/nsssd-nslcd.c583
-rw-r--r--src/nsssd/nsssd-nslcd.h26
-rw-r--r--src/nsssd/nsssd-unix.c170
-rw-r--r--src/nsssd/nsssd_convert.c41
-rw-r--r--src/nsssd/nsssd_main.c419
8 files changed, 1247 insertions, 0 deletions
diff --git a/src/nsssd/deps-exe/nsssd-nslcd b/src/nsssd/deps-exe/nsssd-nslcd
new file mode 100644
index 0000000..8a77503
--- /dev/null
+++ b/src/nsssd/deps-exe/nsssd-nslcd
@@ -0,0 +1,2 @@
+${LIBNSSSD}
+-lskarnet
diff --git a/src/nsssd/deps-exe/nsssd-unix b/src/nsssd/deps-exe/nsssd-unix
new file mode 100644
index 0000000..deff087
--- /dev/null
+++ b/src/nsssd/deps-exe/nsssd-unix
@@ -0,0 +1,3 @@
+${LIBNSSS}
+${LIBNSSSD}
+-lskarnet
diff --git a/src/nsssd/deps-lib/nsssd b/src/nsssd/deps-lib/nsssd
new file mode 100644
index 0000000..7b2e85b
--- /dev/null
+++ b/src/nsssd/deps-lib/nsssd
@@ -0,0 +1,3 @@
+nsssd_main.o
+nsssd_convert.o
+-lskarnet
diff --git a/src/nsssd/nsssd-nslcd.c b/src/nsssd/nsssd-nslcd.c
new file mode 100644
index 0000000..dd8fdce
--- /dev/null
+++ b/src/nsssd/nsssd-nslcd.c
@@ -0,0 +1,583 @@
+/* ISC license. */
+
+#include <skalibs/nonposix.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <stdint.h>
+#include <errno.h>
+#include <skalibs/posixplz.h>
+#include <skalibs/error.h>
+#include <skalibs/uint32.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/buffer.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/webipc.h>
+#include <skalibs/unix-timed.h>
+#include <nsss/nsssd.h>
+#include "nsssd-nslcd.h"
+
+#define USAGE "nsssd-nslcd [ -t timeout ] path-to-nslcd-socket"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+typedef struct nslcd_handle_s nslcd_handle_t, *nslcd_handle_t_ref ;
+struct nslcd_handle_s
+{
+ char const *socketpath ;
+ genalloc entries[3] ; /* nsss_passwd_t, nsss_group_t, nsss_spwd_t */
+ stralloc data[3] ;
+ size_t head[3] ;
+ genalloc grmemc ; /* size_t */
+ genalloc grmem ; /* char * */
+ size_t grhead ;
+ unsigned int needdata ;
+} ;
+#define NSLCD_HANDLE_ZERO \
+{ \
+ .socketpath = 0, \
+ .entries = { GENALLOC_ZERO, GENALLOC_ZERO, GENALLOC_ZERO }, \
+ .data = { STRALLOC_ZERO, STRALLOC_ZERO, STRALLOC_ZERO }, \
+ .head = { 0, 0, 0 }, \
+ .grmemc = GENALLOC_ZERO, \
+ .grmem = GENALLOC_ZERO, \
+ .grhead = 0, \
+ .needdata = 0 \
+}
+
+static tain_t tto = TAIN_INFINITE_RELATIVE ;
+
+void *nsssd_handle_init (void)
+{
+ static nslcd_handle_t a = NSLCD_HANDLE_ZERO ;
+ return &a ;
+}
+
+int nsssd_handle_start (void *handle, char const *const *argv, char const *const *envp)
+{
+ nslcd_handle_t *a = handle ;
+ if (!argv[0]) strerr_dieusage(100, USAGE) ;
+ a->socketpath = argv[0] ;
+ return 1 ;
+}
+
+void nsssd_handle_end (void *handle)
+{
+ static const nslcd_handle_t nslcd_handle_zero = NSLCD_HANDLE_ZERO ;
+ nslcd_handle_t *a = handle ;
+ genalloc_free(nsssd_passwd_t, &a->entries[0]) ;
+ genalloc_free(nsssd_group_t, &a->entries[1]) ;
+ genalloc_free(nsssd_spwd_t, &a->entries[2]) ;
+ stralloc_free(&a->data[0]) ;
+ stralloc_free(&a->data[1]) ;
+ stralloc_free(&a->data[2]) ;
+ genalloc_free(size_t, &a->grmemc) ;
+ genalloc_free(char *, &a->grmem) ;
+ *a = nslcd_handle_zero ;
+}
+
+static int read_uint32 (buffer *b, uint32_t *x, tain_t const *deadline)
+{
+ char pack[4] ;
+ if (buffer_timed_get_g(b, pack, 4, deadline) < 4) return 0 ;
+ uint32_unpack_big(pack, x) ;
+ return 1 ;
+}
+
+static int read_string (buffer *b, size_t *value, stralloc *sa, tain_t const *deadline)
+{
+ uint32_t len ;
+ if (!read_uint32(b, &len, deadline)) return 0 ;
+ if (!stralloc_readyplus(sa, len+1)) return 0 ;
+ if (buffer_timed_get_g(b, sa->s + sa->len, len, deadline) < len) return 0 ;
+ *value = sa->len ;
+ sa->len += len ;
+ sa->s[sa->len++] = 0 ;
+ return 1 ;
+}
+
+static inline int read_stringlist (buffer *b, size_t *head, size_t *n, stralloc *sa, genalloc *ga, tain_t const *deadline)
+{
+ uint32_t i ;
+ size_t *p ;
+ if (!read_uint32(b, &i, deadline)) return 0 ;
+ if (!genalloc_readyplus(size_t, ga, i)) return 0 ;
+ *head = genalloc_len(size_t, ga) ;
+ p = genalloc_s(size_t, ga) + *head ;
+ *n = i ;
+ while (i--) if (!read_string(b, p++, sa, deadline)) return 0 ;
+ return 1 ;
+}
+
+static inline int read_header (buffer *b, uint32_t action, tain_t const *deadline)
+{
+ uint32_t x ;
+ char pack[8] ;
+ if (buffer_timed_get_g(b, pack, 8, deadline) < 8) return 0 ;
+ uint32_unpack_big(pack, &x) ;
+ if (x != NSLCD_VERSION) return (errno = EPROTO, 0) ;
+ uint32_unpack_big(pack+4, &x) ;
+ if (x != action) return (errno = EPROTO, 0) ;
+ return 1 ;
+}
+
+static int read_beginend (buffer *b, tain_t const *deadline)
+{
+ uint32_t x ;
+ if (!read_uint32(b, &x, deadline)) return -1 ;
+ switch (x)
+ {
+ case NSLCD_RESULT_BEGIN : return 1 ;
+ case NSLCD_RESULT_END : return 0 ;
+ default : return (errno = EPROTO, -1) ;
+ }
+}
+
+static int read_eof (buffer *b, tain_t const *deadline)
+{
+ char c ;
+ ssize_t r = buffer_timed_get_g(b, &c, 1, deadline) ;
+ if (r < 0) return 0 ;
+ if (r) return (errno = EPROTO, 0) ;
+ return 1 ;
+}
+
+static int read_endeof(buffer *b, tain_t const *deadline)
+{
+ int r = read_beginend(b, deadline) ;
+ if (r < 0) return 0 ;
+ if (r) return (errno = EPROTO, 0) ;
+ return read_eof(b, deadline) ;
+}
+
+static int read_pw (buffer *b, nsssd_passwd_t *pw, stralloc *sa, tain_t const *deadline)
+{
+ uint32_t x ;
+ if (!read_string(b, &pw->pw_name, sa, deadline)) return 0 ;
+ if (!read_string(b, &pw->pw_passwd, sa, deadline)) return 0 ;
+ if (!read_uint32(b, &x, deadline)) return 0 ;
+ pw->pw_uid = x ;
+ if (!read_uint32(b, &x, deadline)) return 0 ;
+ pw->pw_gid = x ;
+ if (!read_string(b, &pw->pw_gecos, sa, deadline)) return 0 ;
+ if (!read_string(b, &pw->pw_dir, sa, deadline)) return 0 ;
+ if (!read_string(b, &pw->pw_shell, sa, deadline)) return 0 ;
+ return 1 ;
+}
+
+static int read_gr (buffer *b, nsssd_group_t *gr, stralloc *sa, genalloc *ga, tain_t const *deadline)
+{
+ uint32_t x ;
+ if (!read_string(b, &gr->gr_name, sa, deadline)) return 0 ;
+ if (!read_string(b, &gr->gr_passwd, sa, deadline)) return 0 ;
+ if (!read_uint32(b, &x, deadline)) return 0 ;
+ gr->gr_gid = x ;
+ if (!read_stringlist(b, &gr->gr_mem, &gr->gr_mem_n, sa, ga, deadline)) return 0 ;
+ return 1 ;
+}
+
+static int read_sp (buffer *b, nsssd_spwd_t *sp, stralloc *sa, tain_t const *deadline)
+{
+ uint32_t x ;
+ if (!read_string(b, &sp->sp_namp, sa, deadline)) return 0 ;
+ if (!read_string(b, &sp->sp_pwdp, sa, deadline)) return 0 ;
+ if (!read_uint32(b, &x, deadline)) return 0 ;
+ sp->sp_lstchg = x ;
+ if (!read_uint32(b, &x, deadline)) return 0 ;
+ sp->sp_min = x ;
+ if (!read_uint32(b, &x, deadline)) return 0 ;
+ sp->sp_max = x ;
+ if (!read_uint32(b, &x, deadline)) return 0 ;
+ sp->sp_warn = x ;
+ if (!read_uint32(b, &x, deadline)) return 0 ;
+ sp->sp_inact = x ;
+ if (!read_uint32(b, &x, deadline)) return 0 ;
+ sp->sp_expire = x ;
+ if (!read_uint32(b, &x, deadline)) return 0 ;
+ sp->sp_flag = x ;
+ return 1 ;
+}
+
+static int nslcd_connect (nslcd_handle_t *a, uint32_t action, struct iovec const *v, unsigned int n, tain_t const *deadline)
+{
+ char pack[8] ;
+ int fd = ipc_stream_nbcoe() ;
+ struct iovec vv[n+1] ;
+ if (fd < 0) return 0 ;
+ vv[0].iov_base = pack ;
+ vv[0].iov_len = 8 ;
+ for (unsigned int i = 0 ; i < n ; i++) vv[i+1] = v[i] ;
+ if (!ipc_timed_connect_g(fd, a->socketpath, deadline)) goto err ;
+ uint32_pack_big(pack, NSLCD_VERSION) ;
+ uint32_pack_big(pack + 4, action) ;
+ if (!ipc_timed_sendv_g(fd, vv, n+1, deadline)) goto err ;
+ if (shutdown(fd, SHUT_WR) < 0) goto err ;
+ return fd ;
+
+ err:
+ fd_close(fd) ;
+ return -1 ;
+}
+
+int nsssd_pwd_start (void *handle)
+{
+ nslcd_handle_t *a = handle ;
+ a->head[0] = 0 ;
+ a->needdata |= 1 ;
+ return 1 ;
+}
+
+int nsssd_pwd_rewind (void *handle)
+{
+ nslcd_handle_t *a = handle ;
+ a->head[0] = 0 ;
+ a->needdata |= 1 ;
+ return 1 ;
+}
+
+static inline int pwd_getall (nslcd_handle_t *a)
+{
+ tain_t deadline ;
+ int fd ;
+ buffer b ;
+ char buf[8192] ;
+ tain_add_g(&deadline, &tto) ;
+ fd = nslcd_connect(a, NSLCD_ACTION_PASSWD_ALL, 0, 0, &deadline) ;
+ if (fd < 0) return 0 ;
+ buffer_init(&b, &buffer_read, fd, buf, 8192) ;
+ if (!read_header(&b, NSLCD_ACTION_PASSWD_ALL, &deadline)) goto err ;
+ genalloc_setlen(nsssd_passwd_t, &a->entries[0], 0) ;
+ a->data[0].len = 0 ;
+ for (;;)
+ {
+ int r = read_beginend(&b, &deadline) ;
+ if (r < 0) goto err ;
+ if (!r) break ;
+ if (!genalloc_readyplus(nsssd_passwd_t, &a->entries[0], 1)) goto err ;
+ if (!read_pw(&b, genalloc_s(nsssd_passwd_t, &a->entries[0]) + genalloc_len(nsssd_passwd_t, &a->entries[0]), &a->data[0], &deadline)) goto err ;
+ genalloc_setlen(nsssd_passwd_t, &a->entries[0], genalloc_len(nsssd_passwd_t, &a->entries[0]) + 1) ;
+ }
+ if (!read_eof(&b, &deadline)) goto err ;
+ fd_close(fd) ;
+ return 1 ;
+
+ err:
+ fd_close(fd) ;
+ return 0 ;
+}
+
+int nsssd_pwd_get (void *handle, struct passwd *pw)
+{
+ nslcd_handle_t *a = handle ;
+ if (a->needdata & 1)
+ {
+ if (!pwd_getall(a)) return 0 ;
+ a->needdata &= ~1 ;
+ }
+ if (a->head[0] >= genalloc_len(nsssd_passwd_t, &a->entries[0])) return 0 ;
+ nsssd_passwd_convert(pw, genalloc_s(nsssd_passwd_t, &a->entries[0]) + a->head[0]++, a->data[0].s) ;
+ return 1 ;
+}
+
+int nsssd_pwd_getbyuid (void *handle, struct passwd *pw, uid_t uid)
+{
+ nslcd_handle_t *a = handle ;
+ nsssd_passwd_t pwc ;
+ tain_t deadline ;
+ int fd ;
+ buffer b ;
+ char buf[4096] ;
+ struct iovec v = { .iov_base = buf, .iov_len = 4 } ;
+ tain_add_g(&deadline, &tto) ;
+ uint32_pack_big(buf, uid) ;
+ fd = nslcd_connect(a, NSLCD_ACTION_PASSWD_BYUID, &v, 1, &deadline) ;
+ if (fd < 0) return 0 ;
+ buffer_init(&b, &buffer_read, fd, buf, 4096) ;
+ if (!read_header(&b, NSLCD_ACTION_PASSWD_BYUID, &deadline)) goto err ;
+ if (read_beginend(&b, &deadline) <= 0) goto err ;
+ a->data[0].len = 0 ;
+ if (!read_pw(&b, &pwc, &a->data[0], &deadline)) goto err ;
+ if (!read_endeof(&b, &deadline)) goto err ;
+ fd_close(fd) ;
+ nsssd_passwd_convert(pw, &pwc, a->data[0].s) ;
+ return 1 ;
+
+ err:
+ fd_close(fd) ;
+ return 0 ;
+}
+
+int nsssd_pwd_getbyname (void *handle, struct passwd *pw, char const *name)
+{
+ nslcd_handle_t *a = handle ;
+ nsssd_passwd_t pwc ;
+ tain_t deadline ;
+ int fd ;
+ buffer b ;
+ char buf[4096] ;
+ struct iovec v[2] = { { .iov_base = buf, .iov_len = 4 }, { .iov_base = (char *)name, .iov_len = strlen(name) } } ;
+ tain_add_g(&deadline, &tto) ;
+ fd = nslcd_connect(a, NSLCD_ACTION_PASSWD_BYNAME, v, 2, &deadline) ;
+ if (fd < 0) return 0 ;
+ buffer_init(&b, &buffer_read, fd, buf, 4096) ;
+ if (!read_header(&b, NSLCD_ACTION_PASSWD_BYNAME, &deadline)) goto err ;
+ if (read_beginend(&b, &deadline) <= 0) goto err ;
+ a->data[0].len = 0 ;
+ if (!read_pw(&b, &pwc, &a->data[0], &deadline)) goto err ;
+ if (!read_endeof(&b, &deadline)) goto err ;
+ fd_close(fd) ;
+ nsssd_passwd_convert(pw, &pwc, a->data[0].s) ;
+ return 1 ;
+
+ err:
+ fd_close(fd) ;
+ return 0 ;
+}
+
+void nsssd_pwd_end (void *handle)
+{
+}
+
+int nsssd_grp_start (void *handle)
+{
+ nslcd_handle_t *a = handle ;
+ a->head[1] = 0 ;
+ a->grhead = 0 ;
+ a->needdata |= 2 ;
+ return 1 ;
+}
+
+int nsssd_grp_rewind (void *handle)
+{
+ nslcd_handle_t *a = handle ;
+ a->head[1] = 0 ;
+ a->grhead = 0 ;
+ a->needdata |= 2 ;
+ return 1 ;
+}
+
+static inline int grp_getall (nslcd_handle_t *a)
+{
+ tain_t deadline ;
+ int fd ;
+ buffer b ;
+ char buf[8192] ;
+ tain_add_g(&deadline, &tto) ;
+ fd = nslcd_connect(a, NSLCD_ACTION_GROUP_ALL, 0, 0, &deadline) ;
+ if (fd < 0) return 0 ;
+ buffer_init(&b, &buffer_read, fd, buf, 8192) ;
+ if (!read_header(&b, NSLCD_ACTION_GROUP_ALL, &deadline)) goto err ;
+ genalloc_setlen(nsssd_group_t, &a->entries[1], 0) ;
+ a->data[1].len = 0 ;
+ genalloc_setlen(size_t, &a->grmemc, 0) ;
+ for (;;)
+ {
+ int r = read_beginend(&b, &deadline) ;
+ if (r < 0) goto err ;
+ if (!r) break ;
+ if (!genalloc_readyplus(nsssd_group_t, &a->entries[1], 1)) goto err ;
+ if (!read_gr(&b, genalloc_s(nsssd_group_t, &a->entries[1]) + genalloc_len(nsssd_group_t, &a->entries[1]), &a->data[1], &a->grmemc, &deadline)) goto err ;
+ genalloc_setlen(nsssd_group_t, &a->entries[1], genalloc_len(nsssd_group_t, &a->entries[1]) + 1) ;
+ }
+ if (!read_eof(&b, &deadline)) goto err ;
+ fd_close(fd) ;
+ return 1 ;
+
+ err:
+ fd_close(fd) ;
+ return 0 ;
+}
+
+int nsssd_grp_get (void *handle, struct group *gr)
+{
+ nslcd_handle_t *a = handle ;
+ nsssd_group_t *grc ;
+ if (a->needdata & 2)
+ {
+ if (!grp_getall(a)) return 0 ;
+ a->needdata &= ~2 ;
+ }
+ if (a->head[1] >= genalloc_len(nsssd_group_t, &a->entries[1])) return 0 ;
+ grc = genalloc_s(nsssd_group_t, &a->entries[1]) + a->head[1]++ ;
+ if (!genalloc_ready(char *, &a->grmem, grc->gr_mem_n + 1)) return 0 ;
+ nsssd_group_convert(gr, genalloc_s(char *, &a->grmem), grc, a->data[1].s, genalloc_s(size_t, &a->grmemc) + a->grhead) ;
+ a->grhead += grc->gr_mem_n ;
+ return 1 ;
+}
+
+int nsssd_grp_getbygid (void *handle, struct group *gr, gid_t gid)
+{
+ nslcd_handle_t *a = handle ;
+ nsssd_group_t grc ;
+ tain_t deadline ;
+ int fd ;
+ buffer b ;
+ char buf[4096] ;
+ struct iovec v = { .iov_base = buf, .iov_len = 4 } ;
+ tain_add_g(&deadline, &tto) ;
+ uint32_pack_big(buf, gid) ;
+ fd = nslcd_connect(a, NSLCD_ACTION_GROUP_BYGID, &v, 1, &deadline) ;
+ if (fd < 0) return 0 ;
+ buffer_init(&b, &buffer_read, fd, buf, 4096) ;
+ if (!read_header(&b, NSLCD_ACTION_GROUP_BYGID, &deadline)) goto err ;
+ if (read_beginend(&b, &deadline) <= 0) goto err ;
+ a->data[1].len = 0 ;
+ genalloc_setlen(size_t, &a->grmemc, 0) ;
+ if (!read_gr(&b, &grc, &a->data[1], &a->grmemc, &deadline)) goto err ;
+ if (!read_endeof(&b, &deadline)) goto err ;
+ fd_close(fd) ;
+ if (!genalloc_ready(char *, &a->grmem, grc.gr_mem_n + 1)) return 0 ;
+ nsssd_group_convert(gr, genalloc_s(char *, &a->grmem), &grc, a->data[1].s, genalloc_s(size_t, &a->grmemc)) ;
+ return 1 ;
+
+ err:
+ fd_close(fd) ;
+ return 0 ;
+}
+
+int nsssd_grp_getbyname (void *handle, struct group *gr, char const *name)
+{
+ nslcd_handle_t *a = handle ;
+ nsssd_group_t grc ;
+ tain_t deadline ;
+ int fd ;
+ buffer b ;
+ char buf[4096] ;
+ struct iovec v[2] = { { .iov_base = buf, .iov_len = 4 }, { .iov_base = (char *)name, .iov_len = strlen(name) } } ;
+ tain_add_g(&deadline, &tto) ;
+ fd = nslcd_connect(a, NSLCD_ACTION_GROUP_BYNAME, v, 2, &deadline) ;
+ if (fd < 0) return 0 ;
+ buffer_init(&b, &buffer_read, fd, buf, 4096) ;
+ if (!read_header(&b, NSLCD_ACTION_GROUP_BYNAME, &deadline)) goto err ;
+ if (read_beginend(&b, &deadline) <= 0) goto err ;
+ a->data[1].len = 0 ;
+ genalloc_setlen(size_t, &a->grmemc, 0) ;
+ if (!read_gr(&b, &grc, &a->data[1], &a->grmemc, &deadline)) goto err ;
+ if (!read_endeof(&b, &deadline)) goto err ;
+ fd_close(fd) ;
+ if (!genalloc_ready(char *, &a->grmem, grc.gr_mem_n + 1)) return 0 ;
+ nsssd_group_convert(gr, genalloc_s(char *, &a->grmem), &grc, a->data[1].s, genalloc_s(size_t, &a->grmem)) ;
+ return 1 ;
+
+ err:
+ fd_close(fd) ;
+ return 0 ;
+}
+
+void nsssd_grp_end (void *handle)
+{
+}
+
+int nsssd_shadow_start (void *handle)
+{
+ nslcd_handle_t *a = handle ;
+ a->head[2] = 0 ;
+ a->needdata |= 4 ;
+ return 1 ;
+}
+
+int nsssd_shadow_rewind (void *handle)
+{
+ nslcd_handle_t *a = handle ;
+ a->head[2] = 0 ;
+ a->needdata |= 4 ;
+ return 1 ;
+}
+
+static inline int shadow_getall (nslcd_handle_t *a)
+{
+ tain_t deadline ;
+ int fd ;
+ buffer b ;
+ char buf[8192] ;
+ tain_add_g(&deadline, &tto) ;
+ fd = nslcd_connect(a, NSLCD_ACTION_SHADOW_ALL, 0, 0, &deadline) ;
+ if (fd < 0) return 0 ;
+ buffer_init(&b, &buffer_read, fd, buf, 8192) ;
+ if (!read_header(&b, NSLCD_ACTION_SHADOW_ALL, &deadline)) goto err ;
+ genalloc_setlen(nsssd_spwd_t, &a->entries[2], 0) ;
+ a->data[2].len = 0 ;
+ for (;;)
+ {
+ int r = read_beginend(&b, &deadline) ;
+ if (r < 0) goto err ;
+ if (!r) break ;
+ if (!genalloc_readyplus(nsssd_spwd_t, &a->entries[2], 1)) goto err ;
+ if (!read_sp(&b, genalloc_s(nsssd_spwd_t, &a->entries[2]) + genalloc_len(nsssd_spwd_t, &a->entries[2]), &a->data[2], &deadline)) goto err ;
+ genalloc_setlen(nsssd_spwd_t, &a->entries[2], genalloc_len(nsssd_spwd_t, &a->entries[2]) + 1) ;
+ }
+ if (!read_eof(&b, &deadline)) goto err ;
+ fd_close(fd) ;
+ return 1 ;
+
+ err:
+ fd_close(fd) ;
+ return 0 ;
+}
+
+int nsssd_shadow_get (void *handle, struct spwd *sp)
+{
+ nslcd_handle_t *a = handle ;
+ if (a->needdata & 4)
+ {
+ if (!shadow_getall(a)) return 0 ;
+ a->needdata &= ~4 ;
+ }
+ if (a->head[2] >= genalloc_len(nsssd_spwd_t, &a->entries[2])) return 0 ;
+ nsssd_spwd_convert(sp, genalloc_s(nsssd_spwd_t, &a->entries[2]) + a->head[2]++, a->data[2].s) ;
+ return 1 ;
+}
+
+int nsssd_shadow_getbyname (void *handle, struct spwd *sp, char const *name)
+{
+ nslcd_handle_t *a = handle ;
+ nsssd_spwd_t spc ;
+ tain_t deadline ;
+ int fd ;
+ buffer b ;
+ char buf[4096] ;
+ struct iovec v[2] = { { .iov_base = buf, .iov_len = 4 }, { .iov_base = (char *)name, .iov_len = strlen(name) } } ;
+ tain_add_g(&deadline, &tto) ;
+ fd = nslcd_connect(a, NSLCD_ACTION_SHADOW_BYNAME, v, 2, &deadline) ;
+ if (fd < 0) return 0 ;
+ buffer_init(&b, &buffer_read, fd, buf, 4096) ;
+ if (!read_header(&b, NSLCD_ACTION_SHADOW_BYNAME, &deadline)) goto err ;
+ if (read_beginend(&b, &deadline) <= 0) goto err ;
+ a->data[2].len = 0 ;
+ if (!read_sp(&b, &spc, &a->data[2], &deadline)) goto err ;
+ if (!read_endeof(&b, &deadline)) goto err ;
+ fd_close(fd) ;
+ nsssd_spwd_convert(sp, &spc, a->data[2].s) ;
+ return 1 ;
+
+ err:
+ fd_close(fd) ;
+ return 0 ;
+}
+
+void nsssd_shadow_end (void *handle)
+{
+}
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ PROG = "nsssd-nslcd" ;
+ {
+ subgetopt_t l = SUBGETOPT_ZERO ;
+ uint32_t t = 0 ;
+ for (;;)
+ {
+ int opt = subgetopt_r(argc, argv, "d", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 't' : if (!uint320_scan(l.arg, &t)) dieusage() ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ if (t) tain_from_millisecs(&tto, t) ;
+ }
+
+ return nsssd_main(argv, envp) ;
+}
diff --git a/src/nsssd/nsssd-nslcd.h b/src/nsssd/nsssd-nslcd.h
new file mode 100644
index 0000000..6980703
--- /dev/null
+++ b/src/nsssd/nsssd-nslcd.h
@@ -0,0 +1,26 @@
+/* ISC license. */
+
+#ifndef NSSSD_NSLCD_H
+#define NSSSD_NSLCD_H
+
+
+ /* Taken from nslcd.h */
+
+#define NSLCD_VERSION 0x00000002
+
+#define NSLCD_ACTION_PASSWD_BYNAME 0x00080001
+#define NSLCD_ACTION_PASSWD_BYUID 0x00080002
+#define NSLCD_ACTION_PASSWD_ALL 0x00080008
+
+#define NSLCD_ACTION_GROUP_BYNAME 0x00040001
+#define NSLCD_ACTION_GROUP_BYGID 0x00040002
+#define NSLCD_ACTION_GROUP_BYMEMBER 0x00040006
+#define NSLCD_ACTION_GROUP_ALL 0x00040008
+
+#define NSLCD_ACTION_SHADOW_BYNAME 0x000c0001
+#define NSLCD_ACTION_SHADOW_ALL 0x000c0008
+
+#define NSLCD_RESULT_BEGIN 1
+#define NSLCD_RESULT_END 2
+
+#endif
diff --git a/src/nsssd/nsssd-unix.c b/src/nsssd/nsssd-unix.c
new file mode 100644
index 0000000..e158c9f
--- /dev/null
+++ b/src/nsssd/nsssd-unix.c
@@ -0,0 +1,170 @@
+/* ISC license. */
+
+#include <skalibs/strerr2.h>
+#include <nsss/pwd-unix.h>
+#include <nsss/grp-unix.h>
+#include <nsss/shadow-unix.h>
+#include <nsss/nsssd.h>
+
+void *nsssd_handle_init (void)
+{
+ return 0 ;
+}
+
+int nsssd_handle_start (void *handle, char const *const *argv, char const *const *envp)
+{
+ (void)handle ;
+ (void)argv ;
+ (void)envp ;
+ return 1 ;
+}
+
+void nsssd_handle_end (void *handle)
+{
+ (void)handle ;
+}
+
+int nsssd_pwd_start (void *handle)
+{
+ (void)handle ;
+ return 1 ;
+}
+
+int nsssd_pwd_rewind (void *handle)
+{
+ nsss_unix_setpwent() ;
+ (void)handle ;
+ return 1 ;
+}
+
+int nsssd_pwd_get (void *handle, struct passwd *pw)
+{
+ struct passwd *pw2 = nsss_unix_getpwent() ;
+ if (!pw2) return 0 ;
+ *pw = *pw2 ;
+ (void)handle ;
+ return 1 ;
+}
+
+int nsssd_pwd_getbyuid (void *handle, struct passwd *pw, uid_t uid)
+{
+ struct passwd *pw2 = nsss_unix_getpwuid(uid) ;
+ if (!pw2) return 0 ;
+ *pw = *pw2 ;
+ (void)handle ;
+ return 1 ;
+}
+
+int nsssd_pwd_getbyname (void *handle, struct passwd *pw, char const *name)
+{
+ struct passwd *pw2 = nsss_unix_getpwnam(name) ;
+ if (!pw2) return 0 ;
+ *pw = *pw2 ;
+ (void)handle ;
+ return 1 ;
+}
+
+void nsssd_pwd_end (void *handle)
+{
+ nsss_unix_endpwent() ;
+ (void)handle ;
+}
+
+void nsssd_grp_handle_init (void *handle)
+{
+ (void)handle ;
+}
+
+int nsssd_grp_start (void *handle)
+{
+ (void)handle ;
+ return 1 ;
+}
+
+int nsssd_grp_rewind (void *handle)
+{
+ nsss_unix_setgrent() ;
+ (void)handle ;
+ return 1 ;
+}
+
+int nsssd_grp_get (void *handle, struct group *gr)
+{
+ struct group *gr2 = nsss_unix_getgrent() ;
+ if (!gr2) return 0 ;
+ *gr = *gr2 ;
+ (void)handle ;
+ return 1 ;
+}
+
+int nsssd_grp_getbygid (void *handle, struct group *gr, gid_t gid)
+{
+ struct group *gr2 = nsss_unix_getgrgid(gid) ;
+ if (!gr2) return 0 ;
+ *gr = *gr2 ;
+ (void)handle ;
+ return 1 ;
+}
+
+int nsssd_grp_getbyname (void *handle, struct group *gr, char const *name)
+{
+ struct group *gr2 = nsss_unix_getgrnam(name) ;
+ if (!gr2) return 0 ;
+ *gr = *gr2 ;
+ (void)handle ;
+ return 1 ;
+}
+
+void nsssd_grp_end (void *handle)
+{
+ nsss_unix_endgrent() ;
+ (void)handle ;
+}
+
+void nsssd_shadow_handle_init (void *handle)
+{
+ (void)handle ;
+}
+
+int nsssd_shadow_start (void *handle)
+{
+ (void)handle ;
+ return 1 ;
+}
+
+int nsssd_shadow_rewind (void *handle)
+{
+ nsss_unix_setspent() ;
+ (void)handle ;
+ return 1 ;
+}
+
+int nsssd_shadow_get (void *handle, struct spwd *sp)
+{
+ struct spwd *sp2 = nsss_unix_getspent() ;
+ if (!sp2) return 0 ;
+ *sp = *sp2 ;
+ (void)handle ;
+ return 1 ;
+}
+
+int nsssd_shadow_getbyname (void *handle, struct spwd *sp, char const *name)
+{
+ struct spwd *sp2 = nsss_unix_getspnam(name) ;
+ if (!sp2) return 0 ;
+ *sp = *sp2 ;
+ (void)handle ;
+ return 1 ;
+}
+
+void nsssd_shadow_end (void *handle)
+{
+ nsss_unix_endspent() ;
+ (void)handle ;
+}
+
+int main (int argc, char const *const *argv, char const *const *envp)
+{
+ PROG = "nsssd-unix" ;
+ return nsssd_main(argv+1, envp) ;
+}
diff --git a/src/nsssd/nsssd_convert.c b/src/nsssd/nsssd_convert.c
new file mode 100644
index 0000000..2113c6e
--- /dev/null
+++ b/src/nsssd/nsssd_convert.c
@@ -0,0 +1,41 @@
+/* ISC license. */
+
+#include <string.h>
+#include <nsss/pwd-def.h>
+#include <nsss/grp-def.h>
+#include <nsss/shadow-def.h>
+#include <nsss/nsssd.h>
+
+void nsssd_passwd_convert (struct passwd *pw, nsssd_passwd_t const *p, char const *s)
+{
+ pw->pw_name = (char *)s + p->pw_name ;
+ pw->pw_passwd = (char *)s + p->pw_passwd ;
+ pw->pw_uid = p->pw_uid ;
+ pw->pw_gid = p->pw_gid ;
+ pw->pw_gecos = (char *)s + p->pw_gecos ;
+ pw->pw_dir = (char *)s + p->pw_dir ;
+ pw->pw_shell = (char *)s + p->pw_shell ;
+}
+
+void nsssd_group_convert (struct group *gr, char **q, nsssd_group_t const *p, char const *s, size_t const *membase)
+{
+ gr->gr_name = (char *)s + p->gr_name ;
+ gr->gr_passwd = (char *)s + p->gr_passwd ;
+ gr->gr_gid = p->gr_gid ;
+ gr->gr_mem = q ;
+ for (size_t i = 0 ; i < p->gr_mem_n ; i++) *q++ = (char *)s + membase[p->gr_mem + i] ;
+ *q++ = 0 ;
+}
+
+void nsssd_spwd_convert (struct spwd *sp, nsssd_spwd_t const *p, char const *s)
+{
+ sp->sp_namp = (char *)s + p->sp_namp ;
+ sp->sp_pwdp = (char *)s + p->sp_pwdp ;
+ sp->sp_lstchg = p->sp_lstchg ;
+ sp->sp_min = p->sp_min ;
+ sp->sp_max = p->sp_max ;
+ sp->sp_warn = p->sp_warn ;
+ sp->sp_inact = p->sp_inact ;
+ sp->sp_expire = p->sp_expire ;
+ sp->sp_flag = p->sp_flag ;
+}
diff --git a/src/nsssd/nsssd_main.c b/src/nsssd/nsssd_main.c
new file mode 100644
index 0000000..8673df4
--- /dev/null
+++ b/src/nsssd/nsssd_main.c
@@ -0,0 +1,419 @@
+/* ISC license. */
+
+#include <string.h>
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/uint64.h>
+#include <skalibs/error.h>
+#include <skalibs/buffer.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/tai.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/unix-timed.h>
+#include <nsss/pwd-def.h>
+#include <nsss/grp-def.h>
+#include <nsss/shadow-def.h>
+#include <nsss/nsss-switch.h>
+#include <nsss/nsssd.h>
+
+static unsigned int initted = 0 ;
+
+static void get0 (char *s, size_t n)
+{
+ tain_t deadline ;
+ tain_ulong(&deadline, 30) ;
+ tain_add_g(&deadline, &deadline) ;
+ if (buffer_timed_get_g(buffer_0small, s, n, &deadline) < n)
+ strerr_diefu1sys(111, "read from stdin") ;
+}
+
+static void put1 (char const *s, size_t n)
+{
+ size_t w = 0 ;
+ tain_t deadline ;
+ tain_ulong(&deadline, 30) ;
+ tain_add_g(&deadline, &deadline) ;
+ while (!buffer_putall(buffer_1, s, n, &w))
+ {
+ if (!buffer_timed_flush_g(buffer_1, &deadline))
+ strerr_diefu1sys(111, "write to stdout") ;
+ }
+}
+
+static void flush1 (void)
+{
+ tain_t deadline ;
+ tain_ulong(&deadline, 2) ;
+ tain_add_g(&deadline, &deadline) ;
+ if (!buffer_timed_flush_g(buffer_1, &deadline))
+ strerr_diefu1sys(111, "write to stdout") ;
+}
+
+static void answer (int e)
+{
+ unsigned char c = e ;
+ buffer_putnoflush(buffer_1, (char *)&c, 1) ;
+ flush1() ;
+}
+
+static inline void print_pw (struct passwd const *pw)
+{
+ size_t len, namelen, passwdlen, gecoslen, dirlen, shelllen ;
+ char pack[12] ;
+ namelen = strlen(pw->pw_name) + 1 ;
+ passwdlen = strlen(pw->pw_passwd) + 1 ;
+ gecoslen = strlen(pw->pw_gecos) + 1 ;
+ dirlen = strlen(pw->pw_dir) + 1 ;
+ shelllen = strlen(pw->pw_shell) + 1 ;
+ len = namelen + passwdlen + gecoslen + dirlen + shelllen ;
+ if (len > 0xffffffff) { answer(ENAMETOOLONG) ; return ; }
+ put1("", 1) ;
+ uint32_pack_big(pack, pw->pw_uid) ;
+ uint32_pack_big(pack + 4, pw->pw_gid) ;
+ uint32_pack_big(pack + 8, len) ;
+ put1(pack, 12) ;
+ put1(pw->pw_name, namelen) ;
+ put1(pw->pw_passwd, passwdlen) ;
+ put1(pw->pw_gecos, gecoslen) ;
+ put1(pw->pw_dir, dirlen) ;
+ put1(pw->pw_shell, shelllen) ;
+ flush1() ;
+}
+
+static inline void print_gr (struct group const *gr)
+{
+ size_t len, namelen, passwdlen ;
+ size_t n = 0 ;
+ char pack[12] ;
+ namelen = strlen(gr->gr_name) + 1 ;
+ passwdlen = strlen(gr->gr_passwd) + 1 ;
+ len = namelen + passwdlen ;
+ for (char **p = gr->gr_mem ; *p ; n++, p++) len += strlen(*p) + 1 ;
+ if (len > 0xffffffffu || n > 0x30000000u) { answer(ENAMETOOLONG) ; return ; }
+ put1("", 1) ;
+ uint32_pack_big(pack, gr->gr_gid) ;
+ uint32_pack_big(pack, len) ;
+ uint32_pack_big(pack, n) ;
+ put1(pack, 12) ;
+ put1(gr->gr_name, namelen) ;
+ put1(gr->gr_passwd, passwdlen) ;
+ for (size_t i = 0 ; i < n ; i++)
+ put1(gr->gr_mem[i], strlen(gr->gr_mem[i]) + 1) ;
+ flush1() ;
+}
+
+static inline void print_sp (struct spwd const *sp)
+{
+ size_t len, namplen, pwdplen ;
+ char pack[60] ;
+ namplen = strlen(sp->sp_namp) + 1 ;
+ pwdplen = strlen(sp->sp_pwdp) + 1 ;
+ len = namplen + pwdplen ;
+ if (len > 0xffffffff) { answer(ENAMETOOLONG) ; return ; }
+ put1("", 1) ;
+ uint64_pack_big(pack, sp->sp_lstchg) ;
+ uint64_pack_big(pack + 8, sp->sp_min) ;
+ uint64_pack_big(pack + 16, sp->sp_max) ;
+ uint64_pack_big(pack + 24, sp->sp_warn) ;
+ uint64_pack_big(pack + 32, sp->sp_inact) ;
+ uint64_pack_big(pack + 40, sp->sp_expire) ;
+ uint64_pack_big(pack + 48, sp->sp_flag) ;
+ uint32_pack_big(pack + 56, len) ;
+ put1(pack, 60) ;
+ put1(sp->sp_namp, namplen) ;
+ put1(sp->sp_pwdp, pwdplen) ;
+ flush1() ;
+}
+
+
+static inline void do_pwend (void *a)
+{
+ nsssd_pwd_end(a) ;
+ answer(0) ;
+}
+
+static inline void do_pwrewind (void *a)
+{
+ if (!(initted & 1))
+ {
+ if (!nsssd_pwd_start(a))
+ {
+ answer(errno) ;
+ return ;
+ }
+ initted |= 1 ;
+ }
+ if (!nsssd_pwd_rewind(a))
+ {
+ answer(errno) ;
+ return ;
+ }
+ answer(0) ;
+}
+
+static inline void do_pwget (void *a)
+{
+ struct passwd pw ;
+ if (!(initted & 1))
+ {
+ if (!nsssd_pwd_start(a))
+ {
+ answer(errno ? errno : NSSSD_EOF) ;
+ return ;
+ }
+ initted |= 1 ;
+ }
+ if (!nsssd_pwd_get(a, &pw))
+ {
+ answer(errno ? errno : NSSSD_EOF) ;
+ return ;
+ }
+ print_pw(&pw) ;
+}
+
+static inline void do_pwnam (void *a)
+{
+ struct passwd pw ;
+ uint32_t len ;
+ char buf[4] ;
+ get0(buf, 4) ;
+ uint32_unpack_big(buf, &len) ;
+ if (!len || len > NSSS_SWITCH_NAME_MAXLEN - 1)
+ {
+ answer(EPROTO) ;
+ return ;
+ }
+ {
+ char name[len] ;
+ get0(name, len) ;
+ if (name[len-1])
+ {
+ answer(EPROTO) ;
+ return ;
+ }
+ if (!nsssd_pwd_getbyname(a, &pw, name))
+ {
+ answer(errno ? errno : NSSSD_EOF) ;
+ return ;
+ }
+ }
+ print_pw(&pw) ;
+}
+
+static inline void do_pwuid (void *a)
+{
+ struct passwd pw ;
+ uint32_t uid ;
+ char buf[4] ;
+ get0(buf, 4) ;
+ uint32_unpack_big(buf, &uid) ;
+ if (!nsssd_pwd_getbyuid(a, &pw, uid))
+ {
+ answer(errno ? errno : NSSSD_EOF) ;
+ return ;
+ }
+ print_pw(&pw) ;
+}
+
+static inline void do_grend (void *a)
+{
+ nsssd_grp_end(a) ;
+ answer(0) ;
+}
+
+static inline void do_grrewind (void *a)
+{
+ if (!(initted & 2))
+ {
+ if (!nsssd_grp_start(a))
+ {
+ answer(errno) ;
+ return ;
+ }
+ initted |= 2 ;
+ }
+ if (!nsssd_grp_rewind(a))
+ {
+ answer(errno) ;
+ return ;
+ }
+ answer(0) ;
+}
+
+static inline void do_grget (void *a)
+{
+ struct group gr ;
+ if (!(initted & 2))
+ {
+ if (!nsssd_grp_start(a))
+ {
+ answer(errno) ;
+ return ;
+ }
+ initted |= 2 ;
+ }
+ if (!nsssd_grp_get(a, &gr))
+ {
+ answer(errno ? errno : NSSSD_EOF) ;
+ return ;
+ }
+ print_gr(&gr) ;
+}
+
+static inline void do_grnam (void *a)
+{
+ struct group gr ;
+ uint32_t len ;
+ char buf[4] ;
+ get0(buf, 4) ;
+ uint32_unpack_big(buf, &len) ;
+ if (!len || len > NSSS_SWITCH_NAME_MAXLEN - 1)
+ {
+ answer(EPROTO) ;
+ return ;
+ }
+ {
+ char name[len] ;
+ get0(name, len) ;
+ if (name[len-1])
+ {
+ answer(EPROTO) ;
+ return ;
+ }
+ if (!nsssd_grp_getbyname(a, &gr, name))
+ {
+ answer(errno ? errno : NSSSD_EOF) ;
+ return ;
+ }
+ }
+ print_gr(&gr) ;
+}
+
+static inline void do_grgid (void *a)
+{
+ struct group gr ;
+ uint32_t gid ;
+ char buf[4] ;
+ get0(buf, 4) ;
+ uint32_unpack_big(buf, &gid) ;
+ if (!nsssd_grp_getbygid(a, &gr, gid))
+ {
+ answer(errno ? errno : NSSSD_EOF) ;
+ return ;
+ }
+ print_gr(&gr) ;
+}
+
+static inline void do_spend (void *a)
+{
+ nsssd_shadow_end(a) ;
+ answer(0) ;
+}
+
+static inline void do_sprewind (void *a)
+{
+ if (!(initted & 4))
+ {
+ if (!nsssd_shadow_start(a))
+ {
+ answer(errno) ;
+ return ;
+ }
+ initted |= 4 ;
+ }
+ if (!nsssd_shadow_rewind(a))
+ {
+ answer(errno) ;
+ return ;
+ }
+ answer(0) ;
+}
+
+static inline void do_spget (void *a)
+{
+ struct spwd sp ;
+ if (!(initted & 4))
+ {
+ if (!nsssd_shadow_start(a))
+ {
+ answer(errno) ;
+ return ;
+ }
+ initted |= 4 ;
+ }
+ if (!nsssd_shadow_get(a, &sp))
+ {
+ answer(errno ? errno : NSSSD_EOF) ;
+ return ;
+ }
+ print_sp(&sp) ;
+}
+static inline void do_spnam (void *a)
+{
+ struct spwd sp ;
+ uint32_t len ;
+ char buf[4] ;
+ get0(buf, 4) ;
+ uint32_unpack_big(buf, &len) ;
+ if (!len || len > NSSS_SWITCH_NAME_MAXLEN - 1)
+ {
+ answer(EPROTO) ;
+ return ;
+ }
+ {
+ char name[len] ;
+ get0(name, len) ;
+ if (name[len-1])
+ {
+ answer(EPROTO) ;
+ return ;
+ }
+ if (!nsssd_shadow_getbyname(a, &sp, name))
+ {
+ answer(errno ? errno : NSSSD_EOF) ;
+ return ;
+ }
+ }
+ print_sp(&sp) ;
+}
+
+
+int nsssd_main (char const *const *argv, char const *const *envp)
+{
+ void *a = nsssd_handle_init() ;
+ if (ndelay_on(0) < 0) strerr_diefu1sys(111, "set stdin non-blocking") ;
+ tain_now_g() ;
+ if (!nsssd_handle_start(a, argv, envp))
+ strerr_diefu1sys(111, "nsssd_handle_start") ;
+
+ for (;;)
+ {
+ tain_t deadline ;
+ char c ;
+ tain_add_g(&deadline, &tain_infinite_relative) ;
+ if (!buffer_timed_get_g(buffer_0small, &c, 1, &deadline)) break ;
+ errno = 0 ;
+ switch (c)
+ {
+ case NSSS_SWITCH_PWD_END : do_pwend(a) ; break ;
+ case NSSS_SWITCH_PWD_REWIND : do_pwrewind(a) ; break ;
+ case NSSS_SWITCH_PWD_GET : do_pwget(a) ; break ;
+ case NSSS_SWITCH_PWD_GETBYNAME : do_pwnam(a) ; break ;
+ case NSSS_SWITCH_PWD_GETBYUID : do_pwuid(a) ; break ;
+ case NSSS_SWITCH_GRP_END : do_grend(a) ; break ;
+ case NSSS_SWITCH_GRP_REWIND : do_grrewind(a) ; break ;
+ case NSSS_SWITCH_GRP_GET : do_grget(a) ; break ;
+ case NSSS_SWITCH_GRP_GETBYNAME : do_grnam(a) ; break ;
+ case NSSS_SWITCH_GRP_GETBYGID : do_grgid(a) ; break ;
+ case NSSS_SWITCH_SHADOW_END : do_spend(a) ; break ;
+ case NSSS_SWITCH_SHADOW_REWIND : do_sprewind(a) ; break ;
+ case NSSS_SWITCH_SHADOW_GET : do_spget(a) ; break ;
+ case NSSS_SWITCH_SHADOW_GETBYNAME : do_spnam(a) ; break ;
+ default :
+ errno = EPROTO ;
+ strerr_diefu1sys(1, "interpret stdin") ;
+ }
+ }
+ nsssd_handle_end(a) ;
+ return 0 ;
+}