about summary refs log tree commit diff
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
downloadnsss-633445be1a9be37ae727c044417f5607706cf4ae.tar.gz
nsss-633445be1a9be37ae727c044417f5607706cf4ae.tar.xz
nsss-633445be1a9be37ae727c044417f5607706cf4ae.zip
Initial commit
-rw-r--r--.gitignore10
-rw-r--r--AUTHORS5
-rw-r--r--COPYING13
-rw-r--r--INSTALL175
-rw-r--r--Makefile154
-rw-r--r--NEWS6
-rw-r--r--README28
-rw-r--r--README.macosx4
-rw-r--r--README.solaris12
-rwxr-xr-xconfigure466
-rw-r--r--doc/index.html163
-rw-r--r--doc/libnsss/index.html97
-rw-r--r--doc/overview.html35
-rw-r--r--doc/upgrade.html28
-rwxr-xr-xexamples/openrc/nsssd6
-rw-r--r--examples/s6-rc/nsssd-log/consumer-for1
-rw-r--r--examples/s6-rc/nsssd-log/dependencies1
-rw-r--r--examples/s6-rc/nsssd-log/run5
-rw-r--r--examples/s6-rc/nsssd-log/type1
-rw-r--r--examples/s6-rc/nsssd/dependencies1
-rw-r--r--examples/s6-rc/nsssd/notification-fd1
-rw-r--r--examples/s6-rc/nsssd/pipeline-name1
-rw-r--r--examples/s6-rc/nsssd/producer-for1
-rw-r--r--examples/s6-rc/nsssd/run7
-rw-r--r--examples/s6-rc/nsssd/type1
-rwxr-xr-xexamples/s6/nsssd/log/run5
-rw-r--r--examples/s6/nsssd/notification-fd1
-rwxr-xr-xexamples/s6/nsssd/run7
-rw-r--r--package/deps-build1
-rw-r--r--package/deps.mak160
-rw-r--r--package/info4
-rw-r--r--package/modes2
-rw-r--r--package/targets.mak7
-rwxr-xr-xpatch-for-solaris21
-rw-r--r--src/include/grp.h27
-rw-r--r--src/include/nsss/grp-all.h20
-rw-r--r--src/include/nsss/grp-def.h16
-rw-r--r--src/include/nsss/grp-switch.h20
-rw-r--r--src/include/nsss/grp-unix.h20
-rw-r--r--src/include/nsss/grp.h58
-rw-r--r--src/include/nsss/nsss-all.h10
-rw-r--r--src/include/nsss/nsss-switch.h93
-rw-r--r--src/include/nsss/nsss-unix.h61
-rw-r--r--src/include/nsss/nsss.h10
-rw-r--r--src/include/nsss/nsssd.h84
-rw-r--r--src/include/nsss/pwd-all.h20
-rw-r--r--src/include/nsss/pwd-def.h19
-rw-r--r--src/include/nsss/pwd-switch.h20
-rw-r--r--src/include/nsss/pwd-unix.h20
-rw-r--r--src/include/nsss/pwd.h58
-rw-r--r--src/include/nsss/shadow-all.h18
-rw-r--r--src/include/nsss/shadow-def.h21
-rw-r--r--src/include/nsss/shadow-switch.h18
-rw-r--r--src/include/nsss/shadow-unix.h18
-rw-r--r--src/include/nsss/shadow.h52
-rw-r--r--src/include/pwd.h20
-rw-r--r--src/include/shadow.h26
-rw-r--r--src/libnsss/deps-lib/nsss111
-rw-r--r--src/libnsss/nsss-all-internal.h8
-rw-r--r--src/libnsss/nsss-internal.h35
-rw-r--r--src/libnsss/nsss-switch-internal.h21
-rw-r--r--src/libnsss/nsss-unix-internal.h13
-rw-r--r--src/libnsss/nsss_all_endgrent.c17
-rw-r--r--src/libnsss/nsss_all_endpwent.c17
-rw-r--r--src/libnsss/nsss_all_endspent.c17
-rw-r--r--src/libnsss/nsss_all_errno.c5
-rw-r--r--src/libnsss/nsss_all_getgrent.c28
-rw-r--r--src/libnsss/nsss_all_getgrent_r.c44
-rw-r--r--src/libnsss/nsss_all_getgrgid.c29
-rw-r--r--src/libnsss/nsss_all_getgrgid_r.c41
-rw-r--r--src/libnsss/nsss_all_getgrnam.c29
-rw-r--r--src/libnsss/nsss_all_getgrnam_r.c41
-rw-r--r--src/libnsss/nsss_all_getpwent.c26
-rw-r--r--src/libnsss/nsss_all_getpwent_r.c42
-rw-r--r--src/libnsss/nsss_all_getpwnam.c27
-rw-r--r--src/libnsss/nsss_all_getpwnam_r.c39
-rw-r--r--src/libnsss/nsss_all_getpwuid.c27
-rw-r--r--src/libnsss/nsss_all_getpwuid_r.c39
-rw-r--r--src/libnsss/nsss_all_getspent.c26
-rw-r--r--src/libnsss/nsss_all_getspent_r.c42
-rw-r--r--src/libnsss/nsss_all_getspnam.c27
-rw-r--r--src/libnsss/nsss_all_getspnam_r.c39
-rw-r--r--src/libnsss/nsss_all_setgrent.c22
-rw-r--r--src/libnsss/nsss_all_setpwent.c22
-rw-r--r--src/libnsss/nsss_all_setspent.c22
-rw-r--r--src/libnsss/nsss_grp_copy.c27
-rw-r--r--src/libnsss/nsss_grp_here.c10
-rw-r--r--src/libnsss/nsss_pwd_copy.c19
-rw-r--r--src/libnsss/nsss_pwd_here.c8
-rw-r--r--src/libnsss/nsss_shadow_copy.c21
-rw-r--r--src/libnsss/nsss_shadow_here.c8
-rw-r--r--src/libnsss/nsss_switch_end.c17
-rw-r--r--src/libnsss/nsss_switch_endgrent.c10
-rw-r--r--src/libnsss/nsss_switch_endpwent.c10
-rw-r--r--src/libnsss/nsss_switch_endspent.c10
-rw-r--r--src/libnsss/nsss_switch_getgrent.c17
-rw-r--r--src/libnsss/nsss_switch_getgrent_r.c36
-rw-r--r--src/libnsss/nsss_switch_getgrgid.c22
-rw-r--r--src/libnsss/nsss_switch_getgrgid_r.c36
-rw-r--r--src/libnsss/nsss_switch_getgrnam.c22
-rw-r--r--src/libnsss/nsss_switch_getgrnam_r.c36
-rw-r--r--src/libnsss/nsss_switch_getpwent.c15
-rw-r--r--src/libnsss/nsss_switch_getpwent_r.c34
-rw-r--r--src/libnsss/nsss_switch_getpwnam.c20
-rw-r--r--src/libnsss/nsss_switch_getpwnam_r.c34
-rw-r--r--src/libnsss/nsss_switch_getpwuid.c20
-rw-r--r--src/libnsss/nsss_switch_getpwuid_r.c34
-rw-r--r--src/libnsss/nsss_switch_getspent.c15
-rw-r--r--src/libnsss/nsss_switch_getspent_r.c34
-rw-r--r--src/libnsss/nsss_switch_getspnam.c20
-rw-r--r--src/libnsss/nsss_switch_getspnam_r.c34
-rw-r--r--src/libnsss/nsss_switch_grp_end.c9
-rw-r--r--src/libnsss/nsss_switch_grp_get.c17
-rw-r--r--src/libnsss/nsss_switch_grp_getbygid.c19
-rw-r--r--src/libnsss/nsss_switch_grp_getbyname.c24
-rw-r--r--src/libnsss/nsss_switch_grp_read.c58
-rw-r--r--src/libnsss/nsss_switch_grp_rewind.c9
-rw-r--r--src/libnsss/nsss_switch_here.c6
-rw-r--r--src/libnsss/nsss_switch_op.c16
-rw-r--r--src/libnsss/nsss_switch_pwd_end.c9
-rw-r--r--src/libnsss/nsss_switch_pwd_get.c17
-rw-r--r--src/libnsss/nsss_switch_pwd_getbyname.c24
-rw-r--r--src/libnsss/nsss_switch_pwd_getbyuid.c19
-rw-r--r--src/libnsss/nsss_switch_pwd_read.c53
-rw-r--r--src/libnsss/nsss_switch_pwd_rewind.c9
-rw-r--r--src/libnsss/nsss_switch_setgrent.c12
-rw-r--r--src/libnsss/nsss_switch_setpwent.c12
-rw-r--r--src/libnsss/nsss_switch_setspent.c12
-rw-r--r--src/libnsss/nsss_switch_shadow_end.c9
-rw-r--r--src/libnsss/nsss_switch_shadow_get.c17
-rw-r--r--src/libnsss/nsss_switch_shadow_getbyname.c24
-rw-r--r--src/libnsss/nsss_switch_shadow_read.c56
-rw-r--r--src/libnsss/nsss_switch_shadow_rewind.c9
-rw-r--r--src/libnsss/nsss_switch_start.c26
-rw-r--r--src/libnsss/nsss_unix_end.c11
-rw-r--r--src/libnsss/nsss_unix_endgrent.c9
-rw-r--r--src/libnsss/nsss_unix_endpwent.c9
-rw-r--r--src/libnsss/nsss_unix_endspent.c9
-rw-r--r--src/libnsss/nsss_unix_field.c14
-rw-r--r--src/libnsss/nsss_unix_getgrent.c16
-rw-r--r--src/libnsss/nsss_unix_getgrent_r.c35
-rw-r--r--src/libnsss/nsss_unix_getgrgid.c21
-rw-r--r--src/libnsss/nsss_unix_getgrgid_r.c35
-rw-r--r--src/libnsss/nsss_unix_getgrnam.c21
-rw-r--r--src/libnsss/nsss_unix_getgrnam_r.c35
-rw-r--r--src/libnsss/nsss_unix_getpwent.c14
-rw-r--r--src/libnsss/nsss_unix_getpwent_r.c33
-rw-r--r--src/libnsss/nsss_unix_getpwnam.c19
-rw-r--r--src/libnsss/nsss_unix_getpwnam_r.c33
-rw-r--r--src/libnsss/nsss_unix_getpwuid.c19
-rw-r--r--src/libnsss/nsss_unix_getpwuid_r.c33
-rw-r--r--src/libnsss/nsss_unix_getspent.c14
-rw-r--r--src/libnsss/nsss_unix_getspent_r.c33
-rw-r--r--src/libnsss/nsss_unix_getspnam.c19
-rw-r--r--src/libnsss/nsss_unix_getspnam_r.c33
-rw-r--r--src/libnsss/nsss_unix_grp_get.c62
-rw-r--r--src/libnsss/nsss_unix_grp_getbygid.c22
-rw-r--r--src/libnsss/nsss_unix_grp_getbyname.c22
-rw-r--r--src/libnsss/nsss_unix_grp_here.c5
-rw-r--r--src/libnsss/nsss_unix_maybe_start.c9
-rw-r--r--src/libnsss/nsss_unix_pwd_get.c45
-rw-r--r--src/libnsss/nsss_unix_pwd_getbyname.c19
-rw-r--r--src/libnsss/nsss_unix_pwd_getbyuid.c19
-rw-r--r--src/libnsss/nsss_unix_pwd_here.c5
-rw-r--r--src/libnsss/nsss_unix_rewind.c13
-rw-r--r--src/libnsss/nsss_unix_setgrent.c11
-rw-r--r--src/libnsss/nsss_unix_setpwent.c11
-rw-r--r--src/libnsss/nsss_unix_setspent.c11
-rw-r--r--src/libnsss/nsss_unix_shadow_get.c52
-rw-r--r--src/libnsss/nsss_unix_shadow_getbyname.c19
-rw-r--r--src/libnsss/nsss_unix_shadow_here.c5
-rw-r--r--src/libnsss/nsss_unix_start.c13
-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
-rwxr-xr-xtools/gen-deps.sh93
-rwxr-xr-xtools/install.sh64
182 files changed, 6262 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a3a3520
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+*.o
+*.lo
+/config.mak
+/src/include/nsss/config.h
+/libnsss.a.xyzzy
+/libnsss.so.xyzzy
+/libnsssd.a.xyzzy
+/libnsssd.so.xyzzy
+/nsssd-unix
+/nsssd-nslcd
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..1a38c57
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,5 @@
+Main author:
+  Laurent Bercot <ska-skaware@skarnet.org>
+
+Thanks to:
+  A. Wilcox <AWilcox@Wilcox-Tech.com>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..361dcb6
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,13 @@
+Copyright (c) 2018 Laurent Bercot <ska-skaware@skarnet.org>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..247834f
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,175 @@
+Build Instructions
+------------------
+
+* Requirements
+  ------------
+
+  - A POSIX-compliant C development environment
+  - GNU make version 3.81 or later
+  - skalibs version 2.6.5.0 or later: http://skarnet.org/software/skalibs/
+
+ This software will run on any operating system that implements
+POSIX.1-2008, available at:
+  http://pubs.opengroup.org/onlinepubs/9699919799/
+
+
+* Standard usage
+  --------------
+
+  ./configure && make && sudo make install
+
+ will work for most users.
+ It will install the binaries in /bin and the static libraries in
+/usr/lib/nsss.
+
+ Please note that static libraries in /usr/lib/nsss *will not*
+be found by a default linker invocation: you need -L/usr/lib/nsss.
+Other skarnet.org software automatically handles that case if the
+default configuration is used, but if you change the configuration,
+remember to use the appropriate --with-lib configure option.
+
+ You can strip the binaries and libraries of their extra symbols via
+"make strip" before the "make install" phase. It will shave a few bytes
+off them.
+
+
+* Customization
+  -------------
+
+ You can customize paths via flags given to configure.
+ See ./configure --help for a list of all available configure options.
+
+
+* Environment variables
+  ---------------------
+
+ Controlling a build process via environment variables is a big and
+dangerous hammer. You should try and pass flags to configure instead;
+nevertheless, a few standard environment variables are recognized.
+
+ If the CC environment variable is set, its value will override compiler
+detection by configure. The --host=HOST option will still add a HOST-
+prefix to the value of CC.
+
+ The values of CFLAGS, CPPFLAGS and LDFLAGS will be appended to flags
+auto-detected by configure. To entirely override the flags set by
+configure instead, use make variables.
+
+
+* Make variables
+  --------------
+
+ You can invoke make with a few variables for more configuration.
+
+ CC, CFLAGS, CPPFLAGS, LDFLAGS, LDLIBS, AR, RANLIB, STRIP, INSTALL and
+CROSS_COMPILE can all be overridden on the make command line. This is
+an even bigger hammer than running ./configure with environment
+variables, so it is advised to only do this when it is the only way of
+obtaining the behaviour you want.
+
+ DESTDIR can be given on the "make install" command line in order to
+install to a staging directory.
+
+
+* Shared libraries
+  ----------------
+
+ Software from skarnet.org is small enough that shared libraries are
+generally not worth using. Static linking is simpler and incurs less
+runtime overhead and less points of failure: so by default, shared
+libraries are not built and binaries are linked against the static
+versions of the skarnet.org libraries. Nevertheless, you can:
+  * build shared libraries: --enable-shared
+  * link binaries against shared libraries: --disable-allstatic
+
+
+* Static binaries
+  ---------------
+
+ By default, binaries are linked against static versions of all the
+libraries they depend on, except for the libc. You can enforce
+linking against the static libc with --enable-static-libc.
+
+ (If you are using a GNU/Linux system, be aware that the GNU libc
+behaves badly with static linking and produces huge executables,
+which is why it is not the default. Other libcs are better suited
+to static linking, for instance musl: http://musl-libc.org/. If
+you're using nsss, chances are you're running musl, or a similar
+libc, anyway.)
+
+
+* Cross-compilation
+  -----------------
+
+ skarnet.org packages centralize all the difficulty of
+cross-compilation in one place: skalibs. Once you have
+cross-compiled skalibs, the rest is easy.
+
+ * Use the --host=HOST option to configure, HOST being the triplet
+for your target.
+ * Make sure your cross-toolchain binaries (i.e. prefixed with HOST-)
+are accessible via your PATH environment variable.
+ * Make sure to use the correct version of skalibs for your target,
+and the correct sysdeps directory, making use of the
+--with-include, --with-lib, --with-dynlib and --with-sysdeps
+options as necessary.
+
+
+* The slashpackage convention
+  ---------------------------
+
+ The slashpackage convention (http://cr.yp.to/slashpackage.html)
+is a package installation scheme that provides a few guarantees
+over other conventions such as the FHS, for instance fixed
+absolute pathnames. skarnet.org packages support it: use the
+--enable-slashpackage option to configure, or
+--enable-slashpackage=DIR for a prefixed DIR/package tree.
+This option will activate slashpackage support during the build
+and set slashpackage-compatible installation directories.
+If $package_home is the home of the package, defined as
+DIR/package/$category/$package-$version with the variables
+read from the package/info file, then:
+
+  --dynlibdir is set to $package_home/library.so
+  --bindir is set to $package_home/command
+  --sbindir is also set to $package_home/command (slashpackage
+differentiates root-only binaries by their Unix rights, not their
+location in the filesystem)
+  --libexecdir is also set to $package_home/command (slashpackage
+does not need a specific directory for internal binaries)
+  --libdir is set to $package_home/library
+  --includedir is set to $package_home/include
+
+ --prefix is pretty much ignored when you use --enable-slashpackage.
+You should probably not use both --enable-slashpackage and --prefix.
+
+ When using slashpackage, two additional Makefile targets are
+available after "make install":
+ - "make update" changes the default version of the software to the
+freshly installed one. (This is useful when you have several installed
+versions of the same software, which slashpackage supports.)
+ - "make -L global-links" adds links from /command and /library.so to the
+default version of the binaries and shared libraries. The "-L" option to
+make is necessary because targets are symbolic links, and the default make
+behaviour is to check the pointed file's timestamp and not the symlink's
+timestamp.
+
+
+* Absolute pathnames
+  ------------------
+
+ You may want to use fixed absolute pathnames even if you're not
+following the slashpackage convention: for instance, the Nix packaging
+system prefers calling binaries with immutable paths rather than rely on
+PATH resolution. If you are in that case, use the --enable-absolute-paths
+option to configure. This will ensure that programs calling binaries from
+this package will call them with their full installation path (in bindir)
+without relying on a PATH search.
+
+
+* Out-of-tree builds
+  ------------------
+
+ skarnet.org packages do not support out-of-tree builds. They
+are small, so it does not cost much to duplicate the entire
+source tree if parallel builds are needed.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..36b6402
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,154 @@
+#
+# This Makefile requires GNU make.
+#
+# Do not make changes here.
+# Use the included .mak files.
+#
+
+it: all
+
+make_need := 3.81
+ifeq "" "$(strip $(filter $(make_need), $(firstword $(sort $(make_need) $(MAKE_VERSION)))))"
+fail := $(error Your make ($(MAKE_VERSION)) is too old. You need $(make_need) or newer)
+endif
+
+CC = $(error Please use ./configure first)
+
+STATIC_LIBS :=
+SHARED_LIBS :=
+INTERNAL_LIBS :=
+EXTRA_TARGETS :=
+LIB_DEFS :=
+
+define library_definition
+LIB$(firstword $(subst =, ,$(1))) := lib$(lastword $(subst =, ,$(1))).$(if $(DO_ALLSTATIC),a,so).xyzzy
+ifdef DO_SHARED
+SHARED_LIBS += lib$(lastword $(subst =, ,$(1))).so.xyzzy
+endif
+ifdef DO_STATIC
+STATIC_LIBS += lib$(lastword $(subst =, ,$(1))).a.xyzzy
+endif
+endef
+
+-include config.mak
+include package/targets.mak
+
+$(foreach var,$(LIB_DEFS),$(eval $(call library_definition,$(var))))
+
+include package/deps.mak
+
+version_m := $(basename $(version))
+version_M := $(basename $(version_m))
+version_l := $(basename $(version_M))
+CPPFLAGS_ALL := $(CPPFLAGS_AUTO) $(CPPFLAGS)
+CFLAGS_ALL := $(CFLAGS_AUTO) $(CFLAGS)
+ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),)
+CFLAGS_SHARED := -fPIC
+else
+CFLAGS_SHARED :=
+endif
+LDFLAGS_ALL := $(LDFLAGS_AUTO) $(LDFLAGS)
+REALCC = $(CROSS_COMPILE)$(CC)
+AR := $(CROSS_COMPILE)ar
+RANLIB := $(CROSS_COMPILE)ranlib
+STRIP := $(CROSS_COMPILE)strip
+INSTALL := ./tools/install.sh
+
+ALL_BINS := $(LIBEXEC_TARGETS) $(BIN_TARGETS)
+ALL_LIBS := $(SHARED_LIBS) $(STATIC_LIBS) $(INTERNAL_LIBS)
+ALL_INCLUDES := $(wildcard src/include/$(package)/*.h)
+
+all: $(ALL_LIBS) $(ALL_BINS) $(ALL_INCLUDES) src/include/pwd.h src/include/grp.h src/include/shadow.h
+
+clean:
+	@exec rm -f $(ALL_LIBS) $(ALL_BINS) $(wildcard src/*/*.o src/*/*.lo) $(EXTRA_TARGETS)
+
+distclean: clean
+	@exec rm -f config.mak src/include/$(package)/config.h
+
+tgz: distclean
+	@. package/info && \
+	rm -rf /tmp/$$package-$$version && \
+	cp -a . /tmp/$$package-$$version && \
+	cd /tmp && \
+	tar -zpcv --owner=0 --group=0 --numeric-owner --exclude=.git* -f /tmp/$$package-$$version.tar.gz $$package-$$version && \
+	exec rm -rf /tmp/$$package-$$version
+
+strip: $(ALL_LIBS) $(ALL_BINS)
+ifneq ($(strip $(STATIC_LIBS)),)
+	exec $(STRIP) -x -R .note -R .comment -R .note.GNU-stack $(STATIC_LIBS)
+endif
+ifneq ($(strip $(ALL_BINS)$(SHARED_LIBS)),)
+	exec $(STRIP) -R .note -R .comment -R .note.GNU-stack $(ALL_BINS) $(SHARED_LIBS)
+endif
+
+install: install-dynlib install-libexec install-bin install-lib install-include
+install-dynlib: $(SHARED_LIBS:lib%.so.xyzzy=$(DESTDIR)$(dynlibdir)/lib%.so)
+install-libexec: $(LIBEXEC_TARGETS:%=$(DESTDIR)$(libexecdir)/%)
+install-bin: $(BIN_TARGETS:%=$(DESTDIR)$(bindir)/%)
+install-lib: $(STATIC_LIBS:lib%.a.xyzzy=$(DESTDIR)$(libdir)/lib%.a)
+install-include: $(ALL_INCLUDES:src/include/$(package)/%.h=$(DESTDIR)$(includedir)/$(package)/%.h) $(DESTDIR)$(includedir)/utmpx.h
+install-data: $(ALL_DATA:src/etc/%=$(DESTDIR)$(datadir)/%)
+
+ifneq ($(exthome),)
+
+$(DESTDIR)$(exthome): $(DESTDIR)$(home)
+	exec $(INSTALL) -l $(notdir $(home)) $(DESTDIR)$(exthome)
+
+update: $(DESTDIR)$(exthome)
+
+global-links: $(DESTDIR)$(exthome) $(SHARED_LIBS:lib%.so.xyzzy=$(DESTDIR)$(sproot)/library.so/lib%.so.$(version_M)) $(BIN_TARGETS:%=$(DESTDIR)$(sproot)/command/%)
+
+$(DESTDIR)$(sproot)/command/%: $(DESTDIR)$(home)/command/%
+	exec $(INSTALL) -D -l ..$(subst $(sproot),,$(exthome))/command/$(<F) $@
+
+$(DESTDIR)$(sproot)/library.so/lib%.so.$(version_M): $(DESTDIR)$(dynlibdir)/lib%.so.$(version_M)
+	exec $(INSTALL) -D -l ..$(subst $(sproot),,$(exthome))/library.so/$(<F) $@
+
+.PHONY: update global-links
+
+endif
+
+$(DESTDIR)$(datadir)/%: src/etc/%
+	exec $(INSTALL) -D -m 644 $< $@
+
+$(DESTDIR)$(dynlibdir)/lib%.so: lib%.so.xyzzy
+	$(INSTALL) -D -m 755 $< $@.$(version) && \
+	$(INSTALL) -l $(@F).$(version) $@.$(version_m) && \
+	$(INSTALL) -l $(@F).$(version_m) $@.$(version_M) && \
+	exec $(INSTALL) -l $(@F).$(version_M) $@
+
+$(DESTDIR)$(libexecdir)/% $(DESTDIR)$(bindir)/%: % package/modes
+	exec $(INSTALL) -D -m 600 $< $@
+	grep -- ^$(@F) < package/modes | { read name mode owner && \
+	if [ x$$owner != x ] ; then chown -- $$owner $@ ; fi && \
+	chmod $$mode $@ ; }
+
+$(DESTDIR)$(libdir)/lib%.a: lib%.a.xyzzy
+	exec $(INSTALL) -D -m 644 $< $@
+
+$(DESTDIR)$(includedir)/$(package)/%.h: src/include/$(package)/%.h
+	exec $(INSTALL) -D -m 644 $< $@
+
+$(DESTDIR)$(includedir)/utmpx.h: src/include/utmpx.h
+	exec $(INSTALL) -D -m 644 $< $@
+
+%.o: %.c
+	exec $(REALCC) $(CPPFLAGS_ALL) $(CFLAGS_ALL) -c -o $@ $<
+
+%.lo: %.c
+	exec $(REALCC) $(CPPFLAGS_ALL) $(CFLAGS_ALL) $(CFLAGS_SHARED) -c -o $@ $<
+
+$(ALL_BINS):
+	exec $(REALCC) -o $@ $(CFLAGS_ALL) $(LDFLAGS_ALL) $(LDFLAGS_NOSHARED) $^ $(EXTRA_LIBS) $(LDLIBS)
+
+lib%.a.xyzzy:
+	exec $(AR) rc $@ $^
+	exec $(RANLIB) $@
+
+lib%.so.xyzzy:
+	exec $(REALCC) -o $@ $(CFLAGS_ALL) $(CFLAGS_SHARED) $(LDFLAGS_ALL) $(LDFLAGS_SHARED) -Wl,-soname,$(patsubst lib%.so.xyzzy,lib%.so.$(version_M),$@) $^ $(EXTRA_LIBS) $(LDLIBS)
+
+.PHONY: it all clean distclean tgz strip install install-dynlib install-bin install-lib install-include install-data
+
+.DELETE_ON_ERROR:
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..6ca3afb
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,6 @@
+Changelog for nsss.
+
+In 0.0.1.0
+----------
+
+ - Initial release.
diff --git a/README b/README
new file mode 100644
index 0000000..afec687
--- /dev/null
+++ b/README
@@ -0,0 +1,28 @@
+nsssd - a secure NSS-like implementation for small libcs
+--------------------------------------------------------
+
+ nsss is a library implementing a subset of pwd.h, group.h
+and shadow.h family of functions - the subset that can use a
+different backend than the standard /etc/passwd (et al.) files.
+It is intended to be used with certain libcs, such as musl, that
+do not implement the NSS protocol and so do not allow user/group
+credentials to be stored in other databases.
+
+ Unlike NSS, nsss does not load dynamic modules and is fully
+compatible with static linking. The backend is chosen at boot time
+by running the appropriate daemon that will communicate with
+clients.
+
+ See http://skarnet.org/software/nsss/ for details.
+
+
+* Installation
+  ------------
+
+ See the INSTALL file.
+
+
+* Contact information
+  -------------------
+
+ Laurent Bercot <ska-skaware at skarnet.org>
diff --git a/README.macosx b/README.macosx
new file mode 100644
index 0000000..d71a096
--- /dev/null
+++ b/README.macosx
@@ -0,0 +1,4 @@
+
+ This package will compile and run on Darwin (MacOS X), but the building of
+shared libraries is not supported.
+ Make sure you use the --disable-shared option to configure.
diff --git a/README.solaris b/README.solaris
new file mode 100644
index 0000000..91a5b26
--- /dev/null
+++ b/README.solaris
@@ -0,0 +1,12 @@
+
+ This package assumes the existence of a POSIX shell in /bin/sh.
+ On Solaris, /bin/sh is not POSIX. Most versions of Solaris provide
+a POSIX shell in /usr/xpg4/bin/sh.
+
+ To compile this package on Solaris, you will need to run
+
+     ./patch-for-solaris
+
+ before you run ./configure. This script will change the #! invocation
+of the configure script and various tools so that a POSIX shell is used
+for the compilation process.
diff --git a/configure b/configure
new file mode 100755
index 0000000..1080f58
--- /dev/null
+++ b/configure
@@ -0,0 +1,466 @@
+#!/bin/sh
+
+. package/info
+
+usage () {
+cat <<EOF
+Usage: $0 [OPTION]... [TARGET]
+
+Defaults for the options are specified in brackets.
+
+System types:
+  --target=TARGET               configure to run on target TARGET [detected]
+  --host=TARGET                 same as --target
+
+Installation directories:
+  --prefix=PREFIX               main installation prefix [/]
+  --exec-prefix=EPREFIX         installation prefix for executable files [PREFIX]
+
+Fine tuning of the installation directories:
+  --dynlibdir=DIR               shared library files [PREFIX/lib]
+  --bindir=BINDIR               user executables [EPREFIX/bin]
+  --libexecdir=DIR              package-scoped executables [EPREFIX/libexec]
+  --libdir=DIR                  static library files [PREFIX/lib/$package]
+  --includedir=DIR              C header files [PREFIX/include]
+
+ If no --prefix option is given, by default libdir (but not dynlibdir) will be
+ /usr/lib/$package, and includedir will be /usr/include.
+
+Dependencies:
+  --with-sysdeps=DIR            use sysdeps in DIR [PREFIX/lib/skalibs/sysdeps]
+  --with-include=DIR            add DIR to the list of searched directories for headers
+  --with-lib=DIR                add DIR to the list of searched directories for static libraries
+  --with-dynlib=DIR             add DIR to the list of searched directories for shared libraries
+
+ If no --prefix option is given, by default sysdeps will be fetched from
+ /usr/lib/skalibs/sysdeps.
+
+Optional features:
+  --enable-shared               build shared libraries [disabled]
+  --disable-static              do not build static libraries [enabled]
+  --disable-allstatic           do not prefer linking against static libraries [enabled]
+  --enable-static-libc          make entirely static binaries [disabled]
+  --enable-all-pic              build everything as PIC [enabled iff toolchain builds PIE]
+  --enable-slashpackage[=ROOT]  assume /package installation at ROOT [disabled]
+  --enable-absolute-paths       do not rely on PATH to access this package's binaries,
+                                  hardcode absolute BINDIR/foobar paths instead [disabled]
+
+  --with-nsssd-socket=PATH      assume the nsssd socket is at PATH [/run/service/nsssd/s]
+
+EOF
+exit 0
+}
+
+# Helper functions
+
+# If your system does not have printf, you can comment this, but it is
+# generally not a good idea to use echo.
+# See http://www.etalabs.net/sh_tricks.html
+echo () {
+  IFS=" "
+  printf %s\\n "$*"
+}
+
+quote () {
+  tr '\n' ' ' <<EOF | grep '^[-[:alnum:]_=,./:]* $' >/dev/null 2>&1 && { echo "$1" ; return 0 ; }
+$1
+EOF
+  echo "$1" | sed -e "s/'/'\\\\''/g" -e "1s/^/'/" -e "\$s/\$/'/" -e "s#^'\([-[:alnum:]_,./:]*\)=\(.*\)\$#\1='\2#" -e "s|\*/|* /|g"
+}
+
+fail () {
+  echo "$*"
+  exit 1
+}
+
+fnmatch () {
+  eval "case \"\$2\" in $1) return 0 ;; *) return 1 ;; esac"
+}
+
+cmdexists () {
+  type "$1" >/dev/null 2>&1
+}
+
+trycc () {
+  test -z "$CC_AUTO" && cmdexists "$1" && CC_AUTO="$*"
+}
+
+stripdir () {
+  while eval "fnmatch '*/' \"\${$1}\"" ; do
+    eval "$1=\${$1%/}"
+  done
+}
+
+tryflag () {
+  echo "checking whether compiler accepts $2 ..."
+  echo "typedef int x;" > "$tmpc"
+  if $CC_AUTO $CPPFLAGS_AUTO $CPPFLAGS $CPPFLAGS_POST $CFLAGS_AUTO $CFLAGS $CFLAGS_POST "$2" -c -o /dev/null "$tmpc" >/dev/null 2>&1 ; then
+    echo "  ... yes"
+    eval "$1=\"\${$1} \$2\""
+    eval "$1=\${$1# }"
+    return 0
+  else
+    echo "  ... no"
+    return 1
+  fi
+}
+
+tryldflag () {
+  echo "checking whether linker accepts $2 ..."
+  echo "typedef int x;" > "$tmpc"
+  if $CC_AUTO $CFLAGS_AUTO $CFLAGS $CFLAGS_POST $LDFLAGS_AUTO $LDFLAGS $LDFLAGS_POST -nostdlib "$2" -o /dev/null "$tmpc" >/dev/null 2>&1 ; then
+    echo "  ... yes"
+    eval "$1=\"\${$1} \$2\""
+    eval "$1=\${$1# }"
+    return 0
+  else
+    echo "  ... no"
+    return 1
+  fi
+}
+
+
+# Actual script
+
+CC_AUTO=
+CPPFLAGS_AUTO="-D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -iquote src/include-local -Isrc/include"
+CPPFLAGS_POST="$CPPFLAGS"
+CPPFLAGS=
+CFLAGS_AUTO="-pipe -Wall"
+CFLAGS_POST="$CFLAGS"
+CFLAGS=-O2
+LDFLAGS_AUTO=
+LDFLAGS_POST="$LDFLAGS"
+LDFLAGS=
+LDFLAGS_NOSHARED=
+LDFLAGS_SHARED=-shared
+prefix=
+exec_prefix='$prefix'
+dynlibdir='$prefix/lib'
+libexecdir='$exec_prefix/libexec'
+bindir='$exec_prefix/bin'
+libdir='$prefix/lib/$package'
+includedir='$prefix/include'
+sysdeps='$prefix/lib/skalibs/sysdeps'
+manualsysdeps=false
+shared=false
+static=true
+allpic=detect
+slashpackage=false
+abspath=false
+sproot=
+home=
+exthome=
+allstatic=true
+evenmorestatic=false
+addincpath=''
+addlibspath=''
+addlibdpath=''
+vpaths=''
+vpathd=''
+build=
+nsssdpath=/run/service/nsssd/s
+
+for arg ; do
+  case "$arg" in
+    --help) usage ;;
+    --prefix=*) prefix=${arg#*=} ;;
+    --exec-prefix=*) exec_prefix=${arg#*=} ;;
+    --dynlibdir=*) dynlibdir=${arg#*=} ;;
+    --libexecdir=*) libexecdir=${arg#*=} ;;
+    --bindir=*) bindir=${arg#*=} ;;
+    --libdir=*) libdir=${arg#*=} ;;
+    --includedir=*) includedir=${arg#*=} ;;
+    --with-sysdeps=*) sysdeps=${arg#*=} manualsysdeps=true ;;
+    --with-include=*) var=${arg#*=} ; stripdir var ; addincpath="$addincpath -I$var" ;;
+    --with-lib=*) var=${arg#*=} ; stripdir var ; addlibspath="$addlibspath -L$var" ; vpaths="$vpaths $var" ;;
+    --with-dynlib=*) var=${arg#*=} ; stripdir var ; addlibdpath="$addlibdpath -L$var" ; vpathd="$vpathd $var" ;;
+    --enable-shared|--enable-shared=yes) shared=true ;;
+    --disable-shared|--enable-shared=no) shared=false ;;
+    --enable-static|--enable-static=yes) static=true ;;
+    --disable-static|--enable-static=no) static=false ;;
+    --enable-allstatic|--enable-allstatic=yes) allstatic=true ;;
+    --disable-allstatic|--enable-allstatic=no) allstatic=false ; evenmorestatic=false ;;
+    --enable-static-libc|--enable-static-libc=yes) allstatic=true ; evenmorestatic=true ;;
+    --disable-static-libc|--enable-static-libc=no) evenmorestatic=false ;;
+    --enable-all-pic|--enable-all-pic=yes) allpic=true ;;
+    --disable-all-pic|--enable-all-pic=no) allpic=false ;;
+    --enable-slashpackage=*) sproot=${arg#*=} ; slashpackage=true ; ;;
+    --enable-slashpackage) sproot= ; slashpackage=true ;;
+    --disable-slashpackage) sproot= ; slashpackage=false ;;
+    --enable-absolute-paths|--enable-absolute-paths=yes) abspath=true ;;
+    --disable-absolute-paths|--enable-absolute-paths=no) abspath=false ;;
+    --enable-*|--disable-*|--with-*|--without-*|--*dir=*) ;;
+    --host=*|--target=*) target=${arg#*=} ;;
+    --build=*) build=${arg#*=} ;;
+    --with-nsssd-socket=*) nsssdpath=${arg#*=} ;;
+    -* ) echo "$0: unknown option $arg" ;;
+    *=*) ;;
+    *) target=$arg ;;
+  esac
+done
+
+# Add /usr in the default default case
+if test -z "$prefix" ; then
+  if test "$libdir" = '$prefix/lib/$package' ; then
+    libdir=/usr/lib/$package
+  fi
+  if test "$includedir" = '$prefix/include' ; then
+    includedir=/usr/include
+  fi
+  if test "$sysdeps" = '$prefix/lib/skalibs/sysdeps' ; then
+    sysdeps=/usr/lib/skalibs/sysdeps
+  fi
+fi
+
+# Expand installation directories
+stripdir prefix
+for i in exec_prefix dynlibdir libexecdir bindir libdir includedir sysdeps sproot ; do
+  eval tmp=\${$i}
+  eval $i=$tmp
+  stripdir $i
+done
+
+# Get usable temp filenames
+i=0
+set -C
+while : ; do
+  i=$(($i+1))
+  tmpc="./tmp-configure-$$-$PPID-$i.c"
+  tmpe="./tmp-configure-$$-$PPID-$i.tmp"
+  2>|/dev/null > "$tmpc" && break
+  2>|/dev/null > "$tmpe" && break
+  test "$i" -gt 50 && fail "$0: cannot create temporary files"
+done
+set +C
+trap 'rm -f "$tmpc" "$tmpe"' EXIT ABRT INT QUIT TERM HUP
+
+# Set slashpackage values
+if $slashpackage ; then
+  home=${sproot}/package/${category}/${package}-${version}
+  exthome=${sproot}/package/${category}/${package}
+  if $manualsysdeps ; then
+    :
+  else
+    sysdeps=${sproot}/package/prog/skalibs/sysdeps
+  fi
+  extbinprefix=${exthome}/command
+  dynlibdir=${home}/library.so
+  bindir=${home}/command
+  libdir=${home}/library
+  libexecdir=$bindir
+  includedir=${home}/include
+  while read dep ; do
+    addincpath="$addincpath -I${sproot}${dep}/include"
+    vpaths="$vpaths ${sproot}${dep}/library"
+    addlibspath="$addlibspath -L${sproot}${dep}/library"
+    vpathd="$vpathd ${sproot}${dep}/library.so"
+    addlibdpath="$addlibdpath -L${sproot}${dep}/library.so"
+  done < package/deps-build
+fi
+
+# Find a C compiler to use
+if test -n "$target" && test x${build} != x${target} ; then
+  cross=${target}-
+else
+  cross=
+fi
+echo "checking for C compiler..."
+trycc ${cross}${CC}
+trycc ${cross}gcc
+trycc ${cross}clang
+trycc ${cross}cc
+test -n "$CC_AUTO" || { echo "$0: cannot find a C compiler" ; exit 1 ; }
+echo "  ... $CC_AUTO"
+echo "checking whether C compiler works... "
+echo "typedef int x;" > "$tmpc"
+if $CC_AUTO $CPPFLAGS_AUTO $CPPFLAGS $CPPFLAGS_POST $CFLAGS_AUTO $CFLAGS $CFLAGS_POST -c -o /dev/null "$tmpc" 2>"$tmpe" ; then
+  echo "  ... yes"
+else
+  echo "  ... no. Compiler output follows:"
+  cat < "$tmpe"
+  exit 1
+fi
+
+echo "checking target system type..."
+if test -z "$target" ; then
+  if test -n "$build" ; then
+    target=$build ;
+  else
+    target=$($CC_AUTO -dumpmachine 2>/dev/null) || target=unknown
+  fi
+fi
+echo "  ... $target"
+if test ! -d $sysdeps || test ! -f $sysdeps/target ; then
+  echo "$0: error: $sysdeps is not a valid sysdeps directory"
+  exit 1
+fi
+if [ "x$target" != "x$(cat $sysdeps/target)" ] ; then
+  echo "$0: error: target $target does not match the contents of $sysdeps/target"
+  exit 1
+fi
+
+if test $allpic = detect ; then
+  echo "Checking whether we need to build everything as PIC..."
+  if $CC_AUTO $CPPFLAGS_AUTO $CPPFLAGS $CPPFLAGS_POST $CFLAGS_AUTO $CFLAGS $CFLAGS_POST -dM -E - < /dev/null | grep -qF __PIE__ ; then
+    allpic=true
+    echo "  ... yes"
+  else
+    allpic=false
+    echo "  ... no"
+  fi
+fi
+if $allpic ; then
+  tryflag CFLAGS_AUTO -fPIC
+fi
+
+spawn_lib=$(cat $sysdeps/spawn.lib)
+socket_lib=$(cat $sysdeps/socket.lib)
+sysclock_lib=$(cat $sysdeps/sysclock.lib)
+tainnow_lib=$(cat $sysdeps/tainnow.lib)
+timer_lib=$(cat $sysdeps/timer.lib)
+util_lib=$(cat $sysdeps/util.lib)
+
+tryflag CFLAGS_AUTO -std=c99
+tryflag CFLAGS -fomit-frame-pointer
+tryflag CFLAGS_AUTO -fno-exceptions
+tryflag CFLAGS_AUTO -fno-unwind-tables
+tryflag CFLAGS_AUTO -fno-asynchronous-unwind-tables
+tryflag CFLAGS_AUTO -Wa,--noexecstack
+tryflag CFLAGS -fno-stack-protector
+tryflag CPPFLAGS_AUTO -Werror=implicit-function-declaration
+tryflag CPPFLAGS_AUTO -Werror=implicit-int
+tryflag CPPFLAGS_AUTO -Werror=pointer-sign
+tryflag CPPFLAGS_AUTO -Werror=pointer-arith
+tryflag CFLAGS_AUTO -ffunction-sections
+tryflag CFLAGS_AUTO -fdata-sections
+
+tryldflag LDFLAGS_AUTO -Wl,--sort-section=alignment
+tryldflag LDFLAGS_AUTO -Wl,--sort-common
+
+CPPFLAGS_AUTO="${CPPFLAGS_AUTO}${addincpath}"
+
+if $evenmorestatic ; then
+  LDFLAGS_NOSHARED=-static
+fi
+
+if $shared ; then
+  tryldflag LDFLAGS -Wl,--hash-style=both
+fi
+
+LDFLAGS_SHARED="${LDFLAGS_SHARED}${addlibdpath}"
+
+if $allstatic ; then
+  LDFLAGS_NOSHARED="${LDFLAGS_NOSHARED}${addlibspath}"
+  tryldflag LDFLAGS_NOSHARED -Wl,--gc-sections
+else
+  LDFLAGS_NOSHARED="${LDFLAGS_NOSHARED}${addlibdpath}"
+fi
+
+if test -z "$vpaths" ; then
+  while read dep ; do
+    base=$(basename $dep) ;
+    vpaths="$vpaths /usr/lib/$base"
+    addlibspath="$addlibspath -L/usr/lib/$base"
+  done < package/deps-build  
+fi
+
+echo "creating config.mak..."
+cmdline=$(quote "$0")
+for i ; do cmdline="$cmdline $(quote "$i")" ; done
+exec 3>&1 1>config.mak
+cat << EOF
+# This file was generated by:
+# $cmdline
+# Any changes made here will be lost if configure is re-run.
+
+target := $target
+package := $package
+prefix := $prefix
+exec_prefix := $exec_prefix
+dynlibdir := $dynlibdir
+libexecdir := $libexecdir
+bindir := $bindir
+libdir := $libdir
+includedir := $includedir
+sysdeps := $sysdeps
+slashpackage := $slashpackage
+sproot := $sproot
+version := $version
+home := $home
+exthome := $exthome
+SPAWN_LIB := ${spawn_lib}
+SOCKET_LIB := ${socket_lib}
+SYSCLOCK_LIB := ${sysclock_lib}
+TAINNOW_LIB := ${tainnow_lib}
+TIMER_LIB := ${timer_lib}
+UTIL_LIB := ${util_lib}
+
+CC := ${CC_AUTO##${cross}}
+CPPFLAGS_AUTO := $CPPFLAGS_AUTO
+CPPFLAGS := $CPPFLAGS $CPPFLAGS_POST
+CFLAGS_AUTO := $CFLAGS_AUTO
+CFLAGS := $CFLAGS $CFLAGS_POST
+LDFLAGS_AUTO := $LDFLAGS_AUTO
+LDFLAGS := $LDFLAGS $LDFLAGS_POST
+LDFLAGS_SHARED := $LDFLAGS_SHARED
+LDFLAGS_NOSHARED := $LDFLAGS_NOSHARED
+CROSS_COMPILE := $cross
+
+vpath lib%.a$vpaths
+vpath lib%.so$vpathd
+EOF
+if $allstatic ; then
+  echo ".LIBPATTERNS := lib%.a"
+  echo "DO_ALLSTATIC := 1"
+else
+  echo ".LIBPATTERNS := lib%.so"
+fi
+if $static ; then
+  echo "DO_STATIC := 1"
+else
+  echo "DO_STATIC :="
+fi
+if $shared ; then
+  echo "DO_SHARED := 1"
+else
+  echo "DO_SHARED :="
+fi
+if $allpic ; then
+  echo "STATIC_LIBS_ARE_PIC := 1"
+else
+  echo "STATIC_LIBS_ARE_PIC :="
+fi
+
+exec 1>&3 3>&-
+echo "  ... done."
+
+echo "creating src/include/${package}/config.h..."
+mkdir -p -m 0755 src/include/${package}
+exec 3>&1 1> src/include/${package}/config.h
+cat <<EOF
+/* ISC license. */
+
+/* Generated by: $cmdline */
+
+#ifndef ${package_macro_name}_CONFIG_H
+#define ${package_macro_name}_CONFIG_H
+
+#define ${package_macro_name}_VERSION "$version"
+EOF
+if $slashpackage ; then
+  echo "#define ${package_macro_name}_BINPREFIX \"$bindir/\""
+  echo "#define ${package_macro_name}_EXTBINPREFIX \"$extbinprefix/\""
+elif $abspath ; then
+  echo "#define ${package_macro_name}_BINPREFIX \"$bindir/\""
+  echo "#define ${package_macro_name}_EXTBINPREFIX \"$bindir/\""
+else
+  echo "#define ${package_macro_name}_BINPREFIX \"\""
+  echo "#define ${package_macro_name}_EXTBINPREFIX \"\""
+fi
+echo "#define ${package_macro_name}_LIBEXECPREFIX \"$libexecdir/\""
+echo "#define ${package_macro_name}_NSSSD_PATH \"$nsssdpath\""
+echo
+echo "#endif"
+exec 1>&3 3>&-
+echo "  ... done."
diff --git a/doc/index.html b/doc/index.html
new file mode 100644
index 0000000..49cf697
--- /dev/null
+++ b/doc/index.html
@@ -0,0 +1,163 @@
+<html>
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <meta http-equiv="Content-Language" content="en" />
+    <title>nsss - a secure NSS-like implementation for small libcs</title>
+    <meta name="Description" content="utmps - a secure NSS-like implementation for small libcs" />
+    <meta name="Keywords" content="nsss NSS musl libc unix passwd grp shadow laurent bercot skarnet" />
+    <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
+  </head>
+<body>
+
+<p>
+<a href="//skarnet.org/software/">Software</a><br />
+<a href="//skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> nsss </h1>
+
+<h2> What is it&nbsp;? </h2>
+
+<p>
+ nsss is an implementation of a subset of the <tt>pwd.h</tt>,
+<tt>group.h</tt> and <tt>shadow.h</tt> family of functions,
+performing user database access on Unix systems.
+</p>
+
+<p>
+ Usually, user database access via <tt>getpwnam()</tt> and similar
+function is provided by the system's libc. However, not all libcs implement
+a configurable backend for the user/group database. For instance the
+<a href="https://musl-libc.org/">musl</a> libc, on Linux, only supports
+the standard <tt>/etc/passwd</tt> mechanism; it also supports the
+<tt>nscd</tt> protocol but this is not quite enough to implement the
+full set of database access functions with certain backends (such as a
+LDAP server).
+</p>
+
+<p>
+ <tt>nsss</tt> is a secure implementation of configurable user/group/shadow
+database access, providing <tt>getpwnam()</tt> et al. functionality
+by communicating over a Unix domain socket with a daemon; the daemon
+can perform lookups in any database it chooses.
+</p>
+
+<p>
+ Unlike NSS, <tt>nsss</tt> does not perform dynamic module
+loading, only adds a small footprint to the application's binary,
+and does not add any complex decision engine into the client's address
+space. Applications can be statically linked against the <tt>nsss</tt>
+library, and still benefit from configurable user database access
+functions.
+</p>
+
+<hr />
+
+<ul>
+ <li> <a href="overview.html">An overview of nsss</a> </li>
+</ul>
+
+<hr />
+
+<h2> Installation </h2>
+
+<h3> Requirements </h3>
+
+<ul>
+ <li> A POSIX-compliant system with a standard C development environment </li>
+ <li> GNU make, version 3.81 or later </li>
+ <li> <a href="//skarnet.org/software/skalibs/">skalibs</a> version
+2.6.5.0 or later. It's a build-time requirement. It's also a run-time
+requirement if you link against the shared version of the skalibs
+library. </li>
+</ul>
+
+<h3> Licensing </h3>
+
+<p>
+ nsss is free software. It is available under the
+<a href="http://opensource.org/licenses/ISC">ISC license</a>.
+</p>
+
+<h3> Download </h3>
+
+<ul>
+ <li> The current released version of nsss is <a href="nsss-0.0.1.0.tar.gz">0.0.1.0</a>. </li>
+ <li> Alternatively, you can checkout a copy of the
+<a href="//git.skarnet.org/cgi-bin/cgit.cgi/nsss/">nsss
+git repository</a>:
+<pre> git clone git://git.skarnet.org/nsss </pre> </li>
+ <li> There's also a
+<a href="https://github.com/skarnet/nsss">GitHub mirror</a>
+of the nsss git repository. </li>
+</ul>
+
+<h3> Compilation </h3>
+
+<ul>
+ <li> See the enclosed INSTALL file for installation details. </li>
+</ul>
+
+<h3> Upgrade notes </h3>
+
+<ul>
+ <li> <a href="upgrade.html">This page</a> lists the differences to be aware of between
+the previous versions of nsss and the current one. </li>
+</ul>
+
+<hr />
+
+<h2> Reference </h2>
+
+<h3> Commands </h3>
+
+<ul>
+</ul>
+
+<h3> Libraries </h3>
+
+<ul>
+ <li> <a href="libnsss/">The <tt>nsss</tt> library interface</a> </li>
+ <li> The following primitives are also implemented:
+  <ul>
+   <li> endpwent() </li>
+   <li> setpwent() </li>
+   <li> getpwent() </li>
+   <li> getpwent_r() </li>
+   <li> getpwuid() </li>
+   <li> getpwuid_r() </li>
+   <li> getpwnam() </li>
+   <li> getpwnam_r() </li>
+   <li> endgrent() </li>
+   <li> setgrent() </li>
+   <li> getgrent() </li>
+   <li> getgrent_r() </li>
+   <li> getgrgid() </li>
+   <li> getgrgid_r() </li>
+   <li> getgrnam() </li>
+   <li> getgrnam_r() </li>
+   <li> endspent() </li>
+   <li> setspent() </li>
+   <li> getspent() </li>
+   <li> getspent_r() </li>
+   <li> getspnam() </li>
+   <li> getspnam_r() </li>
+  </ul> </li>
+</ul>
+
+<hr />
+
+<a name="related">
+<h2> Related resources </h2>
+</a>
+
+<h3> nsss discussion </h3>
+
+<ul>
+ <li> <tt>nsss</tt> is discussed on the
+<a href="//skarnet.org/lists.html#skaware">skaware</a> mailing-list. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/libnsss/index.html b/doc/libnsss/index.html
new file mode 100644
index 0000000..0307725
--- /dev/null
+++ b/doc/libnsss/index.html
@@ -0,0 +1,97 @@
+<html>
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <meta http-equiv="Content-Language" content="en" />
+    <title>nsss: the nsss library interface</title>
+    <meta name="Description" content="nsss: the nsss library interface" />
+    <meta name="Keywords" content="NSS pwd group shadow library libnsss skarnet" />
+    <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
+  </head>
+<body>
+
+<p>
+<a href="../">nsss</a><br />
+<a href="//skarnet.org/software/">Software</a><br />
+<a href="//skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>nsss</tt> library interface </h1>
+
+<h2> General information </h2>
+
+<p>
+ <tt>libnsss</tt> is a client library meant to be used by client
+programs needing utmp functionality. It interacts with various
+server-side daemons such as
+<a href="../nsssd-unix.html">nsssd-unix</a>.
+</p>
+
+<p>
+ Application programs can use it directly, but most existing programs
+simply use the standard
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/pwd.h.html">pwd.h</a>,
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/grp.h.html">grp.h</a> or
+<a href="http://man7.org/linux/man-pages/man3/getspnam.3.html">shadow.h</a>
+interfaces, which in nsss are implemented as a series of thin wrappers
+around the nsss library.
+</p>
+
+<h2> Compiling </h2>
+
+<ul>
+ <li> Make sure the nsss headers, as well as the skalibs headers,
+are visible in your header search path. </li>
+ <li> Use <tt>#include &lt;nsss/nsss.h&gt;</tt> </li>
+ <li> To use the standard <tt>pwd.h</tt> interface, you can
+just <tt>#include &lt;pwd.h&gt;</tt>, which will work as long
+as the <tt>nsss/pwd.h</tt> header is accessible in your header
+search path. </li>
+ <li> Same thing for <tt>grp.h</tt> and <tt>shadow.h</tt>. </li>
+</ul>
+
+<h2> Linking </h2>
+
+<ul>
+ <li> Make sure the nsss library, as well as the skalibs library,
+are visible in your library search path. </li>
+ <li> Link against <tt>-lnsss</tt>, <tt>-lskarnet</tt>, </li>
+<tt>`cat $SYSDEPS/socket.lib`</tt> and
+<tt>`cat $SYSDEPS/tainnow.lib`</tt>, $SYSDEPS being your skalibs
+sysdeps directory. </li>
+</ul>
+
+<h2> Programming </h2>
+
+<p>
+ The <tt>nsss/nsss.h</tt> header is actually a collection of headers:
+</p>
+
+<ul>
+ <li> <tt>nsss/nsss-unix.h</tt> implements basic access to the
+<tt>/etc/passwd</tt>, <tt>/etc/group</tt> and <tt>/etc/shadow</tt>
+database. </li>
+ <li> <tt>nsss/nsss-switch.h</tt> implements connection via a Unix
+domain socket to a listening <tt>nsssd</tt> daemon, implementing an
+authentication backend based on what implementation of
+the daemon is listening. </li>
+ <li> <tt>nsss/nsss-all.h</tt> implements a safe policy: first a
+connection via <tt>nsss-switch</tt> is attempted, and if no daemon
+is listening, the safe <tt>nsss-unix</tt> backend is used. </li>
+</ul>
+
+<p>
+ By default, the <tt>getpwnam()</tt> et al. functions are aliased
+to their <tt>nsss-all</tt> implementations. You can disable the
+<tt>nsss-unix</tt> fallback by compiling with the NSSS_DISABLE_UNIX
+macro defined (-DNSSS_DISABLE_UNIX). Or you can disable any
+attempt to connect to a daemon by compiling with the
+NSSS_DISABLE_SWITCH macro defined (-DNSSS_DISABLE_SWITCH).
+</p>
+
+<p>
+ (To be completed.)
+</p>
+
+</body>
+</html>
diff --git a/doc/overview.html b/doc/overview.html
new file mode 100644
index 0000000..222e296
--- /dev/null
+++ b/doc/overview.html
@@ -0,0 +1,35 @@
+<html>
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <meta http-equiv="Content-Language" content="en" />
+    <title>nsss: an overview</title>
+    <meta name="Description" content="nsss: an overview" />
+    <meta name="Keywords" content="nsss overview pwd grp shadow password group authentication unix ldap" />
+    <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
+  </head>
+<body>
+
+<p>
+<a href="index.html">nsss</a><br />
+<a href="//skarnet.org/software/">Software</a><br />
+<a href="//skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> An overview of nsss </h1>
+
+<p>
+ nsss is a secure implementation of a subset of the
+<tt>pwd.h</tt>, <tt>grp.h</tt> and <tt>shadow.h</tt> functionality, i.e.
+user authentication on Unix systems. It includes full POSIX
+functionality, a few GNU extensions, and an underlying
+<a href="libnsss/">C client library</a> with better error reporting
+than the POSIX interface specifies.
+</p>
+
+<p>
+ To be completed.
+</p>
+
+</body>
+</html>
diff --git a/doc/upgrade.html b/doc/upgrade.html
new file mode 100644
index 0000000..5ff9e3b
--- /dev/null
+++ b/doc/upgrade.html
@@ -0,0 +1,28 @@
+<html>
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <meta http-equiv="Content-Language" content="en" />
+    <title>How to upgrade nsss</title>
+    <meta name="Description" content="How to upgrade nsss" />
+    <meta name="Keywords" content="nsss installation upgrade" />
+    <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
+  </head>
+<body>
+
+<p>
+<a href="index.html">nsss</a><br />
+<a href="//skarnet.org/software/">Software</a><br />
+<a href="//skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> What has changed in nsss </h1>
+
+<h2> in 0.0.1.0 </h2>
+
+<p>
+ Initial release.
+</p>
+
+</body>
+</html>
diff --git a/examples/openrc/nsssd b/examples/openrc/nsssd
new file mode 100755
index 0000000..8a0c412
--- /dev/null
+++ b/examples/openrc/nsssd
@@ -0,0 +1,6 @@
+#!/sbin/openrc-run
+
+name="nsssd"
+command="s6-ipcserver -- /run/service/nsssd/s nsssd-unix"
+pidfile="/run/service/nsssd/nsssd.pid"
+start_stop_daemon_args="-b -m -c nsssd -d /run/service/nsssd"
diff --git a/examples/s6-rc/nsssd-log/consumer-for b/examples/s6-rc/nsssd-log/consumer-for
new file mode 100644
index 0000000..e089e8b
--- /dev/null
+++ b/examples/s6-rc/nsssd-log/consumer-for
@@ -0,0 +1 @@
+nsssd
diff --git a/examples/s6-rc/nsssd-log/dependencies b/examples/s6-rc/nsssd-log/dependencies
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/examples/s6-rc/nsssd-log/dependencies
@@ -0,0 +1 @@
+
diff --git a/examples/s6-rc/nsssd-log/run b/examples/s6-rc/nsssd-log/run
new file mode 100644
index 0000000..c133770
--- /dev/null
+++ b/examples/s6-rc/nsssd-log/run
@@ -0,0 +1,5 @@
+#!/bin/execlineb -P
+
+s6-setuidgid nssslog
+exec -c
+s6-log t /var/log/nsssd
diff --git a/examples/s6-rc/nsssd-log/type b/examples/s6-rc/nsssd-log/type
new file mode 100644
index 0000000..5883cff
--- /dev/null
+++ b/examples/s6-rc/nsssd-log/type
@@ -0,0 +1 @@
+longrun
diff --git a/examples/s6-rc/nsssd/dependencies b/examples/s6-rc/nsssd/dependencies
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/examples/s6-rc/nsssd/dependencies
@@ -0,0 +1 @@
+
diff --git a/examples/s6-rc/nsssd/notification-fd b/examples/s6-rc/nsssd/notification-fd
new file mode 100644
index 0000000..00750ed
--- /dev/null
+++ b/examples/s6-rc/nsssd/notification-fd
@@ -0,0 +1 @@
+3
diff --git a/examples/s6-rc/nsssd/pipeline-name b/examples/s6-rc/nsssd/pipeline-name
new file mode 100644
index 0000000..84fdc32
--- /dev/null
+++ b/examples/s6-rc/nsssd/pipeline-name
@@ -0,0 +1 @@
+nsssd-pipeline
diff --git a/examples/s6-rc/nsssd/producer-for b/examples/s6-rc/nsssd/producer-for
new file mode 100644
index 0000000..465ee2c
--- /dev/null
+++ b/examples/s6-rc/nsssd/producer-for
@@ -0,0 +1 @@
+nsssd-log
diff --git a/examples/s6-rc/nsssd/run b/examples/s6-rc/nsssd/run
new file mode 100644
index 0000000..24074c6
--- /dev/null
+++ b/examples/s6-rc/nsssd/run
@@ -0,0 +1,7 @@
+#!/bin/execlineb -P
+
+fdmove -c 2 1
+s6-envuidgid nsss
+fdmove 1 3
+s6-ipcserver -1 0U -- s
+nsssd-unix
diff --git a/examples/s6-rc/nsssd/type b/examples/s6-rc/nsssd/type
new file mode 100644
index 0000000..5883cff
--- /dev/null
+++ b/examples/s6-rc/nsssd/type
@@ -0,0 +1 @@
+longrun
diff --git a/examples/s6/nsssd/log/run b/examples/s6/nsssd/log/run
new file mode 100755
index 0000000..c133770
--- /dev/null
+++ b/examples/s6/nsssd/log/run
@@ -0,0 +1,5 @@
+#!/bin/execlineb -P
+
+s6-setuidgid nssslog
+exec -c
+s6-log t /var/log/nsssd
diff --git a/examples/s6/nsssd/notification-fd b/examples/s6/nsssd/notification-fd
new file mode 100644
index 0000000..00750ed
--- /dev/null
+++ b/examples/s6/nsssd/notification-fd
@@ -0,0 +1 @@
+3
diff --git a/examples/s6/nsssd/run b/examples/s6/nsssd/run
new file mode 100755
index 0000000..626edd4
--- /dev/null
+++ b/examples/s6/nsssd/run
@@ -0,0 +1,7 @@
+#!/bin/execlineb -P
+
+fdmove -c 2 1
+s6-envuidgid nsss
+fdmove 1 3
+s6-ipcserver -1 -U -- s
+nsssd-unix
diff --git a/package/deps-build b/package/deps-build
new file mode 100644
index 0000000..05d5af4
--- /dev/null
+++ b/package/deps-build
@@ -0,0 +1 @@
+/package/prog/skalibs
diff --git a/package/deps.mak b/package/deps.mak
new file mode 100644
index 0000000..db56346
--- /dev/null
+++ b/package/deps.mak
@@ -0,0 +1,160 @@
+#
+# This file has been generated by tools/gen-deps.sh
+#
+
+src/include/nsss/grp-all.h: src/include/nsss/grp-def.h
+src/include/nsss/grp-switch.h: src/include/nsss/grp-def.h
+src/include/nsss/grp-unix.h: src/include/nsss/grp-def.h
+src/include/nsss/grp.h: src/include/nsss/grp-all.h src/include/nsss/grp-switch.h src/include/nsss/grp-unix.h
+src/include/nsss/nsss-all.h: src/include/nsss/grp-all.h src/include/nsss/pwd-all.h src/include/nsss/shadow-all.h
+src/include/nsss/nsss-switch.h: src/include/nsss/grp-switch.h src/include/nsss/pwd-switch.h src/include/nsss/shadow-switch.h
+src/include/nsss/nsss-unix.h: src/include/nsss/grp-unix.h src/include/nsss/pwd-unix.h src/include/nsss/shadow-unix.h
+src/include/nsss/nsss.h: src/include/nsss/nsss-all.h src/include/nsss/nsss-switch.h src/include/nsss/nsss-unix.h
+src/include/nsss/nsssd.h: src/include/nsss/grp-def.h src/include/nsss/pwd-def.h src/include/nsss/shadow-def.h
+src/include/nsss/pwd-all.h: src/include/nsss/pwd-def.h
+src/include/nsss/pwd-switch.h: src/include/nsss/pwd-def.h
+src/include/nsss/pwd-unix.h: src/include/nsss/pwd-def.h
+src/include/nsss/pwd.h: src/include/nsss/pwd-all.h src/include/nsss/pwd-switch.h src/include/nsss/pwd-unix.h
+src/include/nsss/shadow-all.h: src/include/nsss/shadow-def.h
+src/include/nsss/shadow-switch.h: src/include/nsss/shadow-def.h
+src/include/nsss/shadow-unix.h: src/include/nsss/shadow-def.h
+src/include/nsss/shadow.h: src/include/nsss/shadow-all.h src/include/nsss/shadow-switch.h src/include/nsss/shadow-unix.h
+src/include/grp.h: src/include/nsss/grp.h
+src/include/pwd.h: src/include/nsss/pwd.h
+src/include/shadow.h: src/include/nsss/shadow.h
+src/libnsss/nsss-internal.h: src/include/nsss/grp-def.h src/include/nsss/pwd-def.h src/include/nsss/shadow-def.h
+src/libnsss/nsss-switch-internal.h: src/include/nsss/grp-def.h src/include/nsss/nsss-switch.h src/include/nsss/pwd-def.h src/include/nsss/shadow-def.h
+src/libnsss/nsss-unix-internal.h: src/include/nsss/nsss-unix.h
+src/libnsss/nsss_all_endgrent.o src/libnsss/nsss_all_endgrent.lo: src/libnsss/nsss_all_endgrent.c src/libnsss/nsss-all-internal.h src/include/nsss/grp-all.h src/include/nsss/grp-switch.h src/include/nsss/grp-unix.h
+src/libnsss/nsss_all_endpwent.o src/libnsss/nsss_all_endpwent.lo: src/libnsss/nsss_all_endpwent.c src/libnsss/nsss-all-internal.h src/include/nsss/pwd-all.h src/include/nsss/pwd-switch.h src/include/nsss/pwd-unix.h
+src/libnsss/nsss_all_endspent.o src/libnsss/nsss_all_endspent.lo: src/libnsss/nsss_all_endspent.c src/libnsss/nsss-all-internal.h src/include/nsss/shadow-all.h src/include/nsss/shadow-switch.h src/include/nsss/shadow-unix.h
+src/libnsss/nsss_all_errno.o src/libnsss/nsss_all_errno.lo: src/libnsss/nsss_all_errno.c src/libnsss/nsss-all-internal.h
+src/libnsss/nsss_all_getgrent.o src/libnsss/nsss_all_getgrent.lo: src/libnsss/nsss_all_getgrent.c src/libnsss/nsss-all-internal.h src/libnsss/nsss-internal.h src/libnsss/nsss-switch-internal.h src/include/nsss/config.h src/include/nsss/grp-all.h src/include/nsss/grp-unix.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_all_getgrent_r.o src/libnsss/nsss_all_getgrent_r.lo: src/libnsss/nsss_all_getgrent_r.c src/libnsss/nsss-all-internal.h src/libnsss/nsss-internal.h src/libnsss/nsss-switch-internal.h src/include/nsss/config.h src/include/nsss/grp-all.h src/include/nsss/grp-unix.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_all_getgrgid.o src/libnsss/nsss_all_getgrgid.lo: src/libnsss/nsss_all_getgrgid.c src/libnsss/nsss-internal.h src/include/nsss/config.h src/include/nsss/grp-all.h src/include/nsss/grp-unix.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_all_getgrgid_r.o src/libnsss/nsss_all_getgrgid_r.lo: src/libnsss/nsss_all_getgrgid_r.c src/libnsss/nsss-internal.h src/include/nsss/config.h src/include/nsss/grp-all.h src/include/nsss/grp-unix.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_all_getgrnam.o src/libnsss/nsss_all_getgrnam.lo: src/libnsss/nsss_all_getgrnam.c src/libnsss/nsss-internal.h src/include/nsss/config.h src/include/nsss/grp-all.h src/include/nsss/grp-unix.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_all_getgrnam_r.o src/libnsss/nsss_all_getgrnam_r.lo: src/libnsss/nsss_all_getgrnam_r.c src/libnsss/nsss-internal.h src/include/nsss/config.h src/include/nsss/grp-all.h src/include/nsss/grp-unix.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_all_getpwent.o src/libnsss/nsss_all_getpwent.lo: src/libnsss/nsss_all_getpwent.c src/libnsss/nsss-all-internal.h src/libnsss/nsss-internal.h src/libnsss/nsss-switch-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/pwd-all.h src/include/nsss/pwd-unix.h
+src/libnsss/nsss_all_getpwent_r.o src/libnsss/nsss_all_getpwent_r.lo: src/libnsss/nsss_all_getpwent_r.c src/libnsss/nsss-all-internal.h src/libnsss/nsss-internal.h src/libnsss/nsss-switch-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/pwd-all.h src/include/nsss/pwd-unix.h
+src/libnsss/nsss_all_getpwnam.o src/libnsss/nsss_all_getpwnam.lo: src/libnsss/nsss_all_getpwnam.c src/libnsss/nsss-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/pwd-all.h src/include/nsss/pwd-unix.h
+src/libnsss/nsss_all_getpwnam_r.o src/libnsss/nsss_all_getpwnam_r.lo: src/libnsss/nsss_all_getpwnam_r.c src/libnsss/nsss-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/pwd-all.h src/include/nsss/pwd-unix.h
+src/libnsss/nsss_all_getpwuid.o src/libnsss/nsss_all_getpwuid.lo: src/libnsss/nsss_all_getpwuid.c src/libnsss/nsss-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/pwd-all.h src/include/nsss/pwd-unix.h
+src/libnsss/nsss_all_getpwuid_r.o src/libnsss/nsss_all_getpwuid_r.lo: src/libnsss/nsss_all_getpwuid_r.c src/libnsss/nsss-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/pwd-all.h src/include/nsss/pwd-unix.h
+src/libnsss/nsss_all_getspent.o src/libnsss/nsss_all_getspent.lo: src/libnsss/nsss_all_getspent.c src/libnsss/nsss-all-internal.h src/libnsss/nsss-internal.h src/libnsss/nsss-switch-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/shadow-all.h src/include/nsss/shadow-unix.h
+src/libnsss/nsss_all_getspent_r.o src/libnsss/nsss_all_getspent_r.lo: src/libnsss/nsss_all_getspent_r.c src/libnsss/nsss-all-internal.h src/libnsss/nsss-internal.h src/libnsss/nsss-switch-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/shadow-all.h src/include/nsss/shadow-unix.h
+src/libnsss/nsss_all_getspnam.o src/libnsss/nsss_all_getspnam.lo: src/libnsss/nsss_all_getspnam.c src/libnsss/nsss-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/shadow-all.h src/include/nsss/shadow-unix.h
+src/libnsss/nsss_all_getspnam_r.o src/libnsss/nsss_all_getspnam_r.lo: src/libnsss/nsss_all_getspnam_r.c src/libnsss/nsss-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/shadow-all.h src/include/nsss/shadow-unix.h
+src/libnsss/nsss_all_setgrent.o src/libnsss/nsss_all_setgrent.lo: src/libnsss/nsss_all_setgrent.c src/libnsss/nsss-all-internal.h src/libnsss/nsss-switch-internal.h src/include/nsss/config.h src/include/nsss/grp-all.h src/include/nsss/grp-unix.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_all_setpwent.o src/libnsss/nsss_all_setpwent.lo: src/libnsss/nsss_all_setpwent.c src/libnsss/nsss-all-internal.h src/libnsss/nsss-switch-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/pwd-all.h src/include/nsss/pwd-unix.h
+src/libnsss/nsss_all_setspent.o src/libnsss/nsss_all_setspent.lo: src/libnsss/nsss_all_setspent.c src/libnsss/nsss-all-internal.h src/libnsss/nsss-switch-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/shadow-all.h src/include/nsss/shadow-unix.h
+src/libnsss/nsss_grp_copy.o src/libnsss/nsss_grp_copy.lo: src/libnsss/nsss_grp_copy.c src/libnsss/nsss-internal.h
+src/libnsss/nsss_grp_here.o src/libnsss/nsss_grp_here.lo: src/libnsss/nsss_grp_here.c src/libnsss/nsss-internal.h src/include/nsss/grp-def.h
+src/libnsss/nsss_pwd_copy.o src/libnsss/nsss_pwd_copy.lo: src/libnsss/nsss_pwd_copy.c src/libnsss/nsss-internal.h
+src/libnsss/nsss_pwd_here.o src/libnsss/nsss_pwd_here.lo: src/libnsss/nsss_pwd_here.c src/libnsss/nsss-internal.h src/include/nsss/pwd-def.h
+src/libnsss/nsss_shadow_copy.o src/libnsss/nsss_shadow_copy.lo: src/libnsss/nsss_shadow_copy.c src/libnsss/nsss-internal.h
+src/libnsss/nsss_shadow_here.o src/libnsss/nsss_shadow_here.lo: src/libnsss/nsss_shadow_here.c src/libnsss/nsss-internal.h src/include/nsss/shadow-def.h
+src/libnsss/nsss_switch_end.o src/libnsss/nsss_switch_end.lo: src/libnsss/nsss_switch_end.c src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_endgrent.o src/libnsss/nsss_switch_endgrent.lo: src/libnsss/nsss_switch_endgrent.c src/libnsss/nsss-switch-internal.h src/include/nsss/grp-switch.h
+src/libnsss/nsss_switch_endpwent.o src/libnsss/nsss_switch_endpwent.lo: src/libnsss/nsss_switch_endpwent.c src/libnsss/nsss-switch-internal.h src/include/nsss/pwd-switch.h
+src/libnsss/nsss_switch_endspent.o src/libnsss/nsss_switch_endspent.lo: src/libnsss/nsss_switch_endspent.c src/libnsss/nsss-switch-internal.h src/include/nsss/shadow-switch.h
+src/libnsss/nsss_switch_getgrent.o src/libnsss/nsss_switch_getgrent.lo: src/libnsss/nsss_switch_getgrent.c src/libnsss/nsss-internal.h src/libnsss/nsss-switch-internal.h src/include/nsss/config.h src/include/nsss/grp-switch.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_getgrent_r.o src/libnsss/nsss_switch_getgrent_r.lo: src/libnsss/nsss_switch_getgrent_r.c src/libnsss/nsss-internal.h src/libnsss/nsss-switch-internal.h src/include/nsss/config.h src/include/nsss/grp-switch.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_getgrgid.o src/libnsss/nsss_switch_getgrgid.lo: src/libnsss/nsss_switch_getgrgid.c src/libnsss/nsss-internal.h src/include/nsss/config.h src/include/nsss/grp-switch.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_getgrgid_r.o src/libnsss/nsss_switch_getgrgid_r.lo: src/libnsss/nsss_switch_getgrgid_r.c src/libnsss/nsss-internal.h src/include/nsss/config.h src/include/nsss/grp-switch.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_getgrnam.o src/libnsss/nsss_switch_getgrnam.lo: src/libnsss/nsss_switch_getgrnam.c src/libnsss/nsss-internal.h src/include/nsss/config.h src/include/nsss/grp-switch.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_getgrnam_r.o src/libnsss/nsss_switch_getgrnam_r.lo: src/libnsss/nsss_switch_getgrnam_r.c src/libnsss/nsss-internal.h src/include/nsss/config.h src/include/nsss/grp-switch.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_getpwent.o src/libnsss/nsss_switch_getpwent.lo: src/libnsss/nsss_switch_getpwent.c src/libnsss/nsss-internal.h src/libnsss/nsss-switch-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/pwd-switch.h
+src/libnsss/nsss_switch_getpwent_r.o src/libnsss/nsss_switch_getpwent_r.lo: src/libnsss/nsss_switch_getpwent_r.c src/libnsss/nsss-internal.h src/libnsss/nsss-switch-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/pwd-switch.h
+src/libnsss/nsss_switch_getpwnam.o src/libnsss/nsss_switch_getpwnam.lo: src/libnsss/nsss_switch_getpwnam.c src/libnsss/nsss-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/pwd-switch.h
+src/libnsss/nsss_switch_getpwnam_r.o src/libnsss/nsss_switch_getpwnam_r.lo: src/libnsss/nsss_switch_getpwnam_r.c src/libnsss/nsss-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/pwd-switch.h
+src/libnsss/nsss_switch_getpwuid.o src/libnsss/nsss_switch_getpwuid.lo: src/libnsss/nsss_switch_getpwuid.c src/libnsss/nsss-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/pwd-switch.h
+src/libnsss/nsss_switch_getpwuid_r.o src/libnsss/nsss_switch_getpwuid_r.lo: src/libnsss/nsss_switch_getpwuid_r.c src/libnsss/nsss-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/pwd-switch.h
+src/libnsss/nsss_switch_getspent.o src/libnsss/nsss_switch_getspent.lo: src/libnsss/nsss_switch_getspent.c src/libnsss/nsss-internal.h src/libnsss/nsss-switch-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/shadow-switch.h
+src/libnsss/nsss_switch_getspent_r.o src/libnsss/nsss_switch_getspent_r.lo: src/libnsss/nsss_switch_getspent_r.c src/libnsss/nsss-internal.h src/libnsss/nsss-switch-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/shadow-switch.h
+src/libnsss/nsss_switch_getspnam.o src/libnsss/nsss_switch_getspnam.lo: src/libnsss/nsss_switch_getspnam.c src/libnsss/nsss-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/shadow-switch.h
+src/libnsss/nsss_switch_getspnam_r.o src/libnsss/nsss_switch_getspnam_r.lo: src/libnsss/nsss_switch_getspnam_r.c src/libnsss/nsss-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/shadow-switch.h
+src/libnsss/nsss_switch_grp_end.o src/libnsss/nsss_switch_grp_end.lo: src/libnsss/nsss_switch_grp_end.c src/libnsss/nsss-switch-internal.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_grp_get.o src/libnsss/nsss_switch_grp_get.lo: src/libnsss/nsss_switch_grp_get.c src/libnsss/nsss-switch-internal.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_grp_getbygid.o src/libnsss/nsss_switch_grp_getbygid.lo: src/libnsss/nsss_switch_grp_getbygid.c src/libnsss/nsss-switch-internal.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_grp_getbyname.o src/libnsss/nsss_switch_grp_getbyname.lo: src/libnsss/nsss_switch_grp_getbyname.c src/libnsss/nsss-switch-internal.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_grp_read.o src/libnsss/nsss_switch_grp_read.lo: src/libnsss/nsss_switch_grp_read.c src/libnsss/nsss-switch-internal.h src/include/nsss/grp-def.h
+src/libnsss/nsss_switch_grp_rewind.o src/libnsss/nsss_switch_grp_rewind.lo: src/libnsss/nsss_switch_grp_rewind.c src/libnsss/nsss-switch-internal.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_here.o src/libnsss/nsss_switch_here.lo: src/libnsss/nsss_switch_here.c src/libnsss/nsss-switch-internal.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_op.o src/libnsss/nsss_switch_op.lo: src/libnsss/nsss_switch_op.c src/libnsss/nsss-switch-internal.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_pwd_end.o src/libnsss/nsss_switch_pwd_end.lo: src/libnsss/nsss_switch_pwd_end.c src/libnsss/nsss-switch-internal.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_pwd_get.o src/libnsss/nsss_switch_pwd_get.lo: src/libnsss/nsss_switch_pwd_get.c src/libnsss/nsss-switch-internal.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_pwd_getbyname.o src/libnsss/nsss_switch_pwd_getbyname.lo: src/libnsss/nsss_switch_pwd_getbyname.c src/libnsss/nsss-switch-internal.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_pwd_getbyuid.o src/libnsss/nsss_switch_pwd_getbyuid.lo: src/libnsss/nsss_switch_pwd_getbyuid.c src/libnsss/nsss-switch-internal.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_pwd_read.o src/libnsss/nsss_switch_pwd_read.lo: src/libnsss/nsss_switch_pwd_read.c src/libnsss/nsss-switch-internal.h src/include/nsss/pwd-def.h
+src/libnsss/nsss_switch_pwd_rewind.o src/libnsss/nsss_switch_pwd_rewind.lo: src/libnsss/nsss_switch_pwd_rewind.c src/libnsss/nsss-switch-internal.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_setgrent.o src/libnsss/nsss_switch_setgrent.lo: src/libnsss/nsss_switch_setgrent.c src/libnsss/nsss-switch-internal.h src/include/nsss/config.h src/include/nsss/grp-switch.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_setpwent.o src/libnsss/nsss_switch_setpwent.lo: src/libnsss/nsss_switch_setpwent.c src/libnsss/nsss-switch-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/pwd-switch.h
+src/libnsss/nsss_switch_setspent.o src/libnsss/nsss_switch_setspent.lo: src/libnsss/nsss_switch_setspent.c src/libnsss/nsss-switch-internal.h src/include/nsss/config.h src/include/nsss/nsss-switch.h src/include/nsss/shadow-switch.h
+src/libnsss/nsss_switch_shadow_end.o src/libnsss/nsss_switch_shadow_end.lo: src/libnsss/nsss_switch_shadow_end.c src/libnsss/nsss-switch-internal.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_shadow_get.o src/libnsss/nsss_switch_shadow_get.lo: src/libnsss/nsss_switch_shadow_get.c src/libnsss/nsss-switch-internal.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_shadow_getbyname.o src/libnsss/nsss_switch_shadow_getbyname.lo: src/libnsss/nsss_switch_shadow_getbyname.c src/libnsss/nsss-switch-internal.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_shadow_read.o src/libnsss/nsss_switch_shadow_read.lo: src/libnsss/nsss_switch_shadow_read.c src/libnsss/nsss-switch-internal.h src/include/nsss/shadow-def.h
+src/libnsss/nsss_switch_shadow_rewind.o src/libnsss/nsss_switch_shadow_rewind.lo: src/libnsss/nsss_switch_shadow_rewind.c src/libnsss/nsss-switch-internal.h src/include/nsss/nsss-switch.h
+src/libnsss/nsss_switch_start.o src/libnsss/nsss_switch_start.lo: src/libnsss/nsss_switch_start.c src/include/nsss/nsss-switch.h
+src/libnsss/nsss_unix_end.o src/libnsss/nsss_unix_end.lo: src/libnsss/nsss_unix_end.c src/include/nsss/nsss-unix.h
+src/libnsss/nsss_unix_endgrent.o src/libnsss/nsss_unix_endgrent.lo: src/libnsss/nsss_unix_endgrent.c src/libnsss/nsss-unix-internal.h src/include/nsss/grp-unix.h
+src/libnsss/nsss_unix_endpwent.o src/libnsss/nsss_unix_endpwent.lo: src/libnsss/nsss_unix_endpwent.c src/libnsss/nsss-unix-internal.h src/include/nsss/pwd-unix.h
+src/libnsss/nsss_unix_endspent.o src/libnsss/nsss_unix_endspent.lo: src/libnsss/nsss_unix_endspent.c src/libnsss/nsss-unix-internal.h src/include/nsss/shadow-unix.h
+src/libnsss/nsss_unix_field.o src/libnsss/nsss_unix_field.lo: src/libnsss/nsss_unix_field.c src/libnsss/nsss-unix-internal.h
+src/libnsss/nsss_unix_getgrent.o src/libnsss/nsss_unix_getgrent.lo: src/libnsss/nsss_unix_getgrent.c src/libnsss/nsss-internal.h src/libnsss/nsss-unix-internal.h src/include/nsss/grp-unix.h src/include/nsss/nsss-unix.h
+src/libnsss/nsss_unix_getgrent_r.o src/libnsss/nsss_unix_getgrent_r.lo: src/libnsss/nsss_unix_getgrent_r.c src/libnsss/nsss-internal.h src/libnsss/nsss-unix-internal.h src/include/nsss/grp-unix.h src/include/nsss/nsss-unix.h
+src/libnsss/nsss_unix_getgrgid.o src/libnsss/nsss_unix_getgrgid.lo: src/libnsss/nsss_unix_getgrgid.c src/libnsss/nsss-internal.h src/include/nsss/grp-unix.h src/include/nsss/nsss-unix.h
+src/libnsss/nsss_unix_getgrgid_r.o src/libnsss/nsss_unix_getgrgid_r.lo: src/libnsss/nsss_unix_getgrgid_r.c src/libnsss/nsss-internal.h src/include/nsss/grp-unix.h src/include/nsss/nsss-unix.h
+src/libnsss/nsss_unix_getgrnam.o src/libnsss/nsss_unix_getgrnam.lo: src/libnsss/nsss_unix_getgrnam.c src/libnsss/nsss-internal.h src/include/nsss/grp-unix.h src/include/nsss/nsss-unix.h
+src/libnsss/nsss_unix_getgrnam_r.o src/libnsss/nsss_unix_getgrnam_r.lo: src/libnsss/nsss_unix_getgrnam_r.c src/libnsss/nsss-internal.h src/include/nsss/grp-unix.h src/include/nsss/nsss-unix.h
+src/libnsss/nsss_unix_getpwent.o src/libnsss/nsss_unix_getpwent.lo: src/libnsss/nsss_unix_getpwent.c src/libnsss/nsss-internal.h src/libnsss/nsss-unix-internal.h src/include/nsss/nsss-unix.h src/include/nsss/pwd-unix.h
+src/libnsss/nsss_unix_getpwent_r.o src/libnsss/nsss_unix_getpwent_r.lo: src/libnsss/nsss_unix_getpwent_r.c src/libnsss/nsss-internal.h src/libnsss/nsss-unix-internal.h src/include/nsss/nsss-unix.h src/include/nsss/pwd-unix.h
+src/libnsss/nsss_unix_getpwnam.o src/libnsss/nsss_unix_getpwnam.lo: src/libnsss/nsss_unix_getpwnam.c src/libnsss/nsss-internal.h src/include/nsss/nsss-unix.h src/include/nsss/pwd-unix.h
+src/libnsss/nsss_unix_getpwnam_r.o src/libnsss/nsss_unix_getpwnam_r.lo: src/libnsss/nsss_unix_getpwnam_r.c src/libnsss/nsss-internal.h src/include/nsss/nsss-unix.h src/include/nsss/pwd-unix.h
+src/libnsss/nsss_unix_getpwuid.o src/libnsss/nsss_unix_getpwuid.lo: src/libnsss/nsss_unix_getpwuid.c src/libnsss/nsss-internal.h src/include/nsss/nsss-unix.h src/include/nsss/pwd-unix.h
+src/libnsss/nsss_unix_getpwuid_r.o src/libnsss/nsss_unix_getpwuid_r.lo: src/libnsss/nsss_unix_getpwuid_r.c src/libnsss/nsss-internal.h src/include/nsss/nsss-unix.h src/include/nsss/pwd-unix.h
+src/libnsss/nsss_unix_getspent.o src/libnsss/nsss_unix_getspent.lo: src/libnsss/nsss_unix_getspent.c src/libnsss/nsss-internal.h src/libnsss/nsss-unix-internal.h src/include/nsss/nsss-unix.h src/include/nsss/shadow-unix.h
+src/libnsss/nsss_unix_getspent_r.o src/libnsss/nsss_unix_getspent_r.lo: src/libnsss/nsss_unix_getspent_r.c src/libnsss/nsss-internal.h src/libnsss/nsss-unix-internal.h src/include/nsss/nsss-unix.h src/include/nsss/shadow-unix.h
+src/libnsss/nsss_unix_getspnam.o src/libnsss/nsss_unix_getspnam.lo: src/libnsss/nsss_unix_getspnam.c src/libnsss/nsss-internal.h src/include/nsss/nsss-unix.h src/include/nsss/shadow-unix.h
+src/libnsss/nsss_unix_getspnam_r.o src/libnsss/nsss_unix_getspnam_r.lo: src/libnsss/nsss_unix_getspnam_r.c src/libnsss/nsss-internal.h src/include/nsss/nsss-unix.h src/include/nsss/shadow-unix.h
+src/libnsss/nsss_unix_grp_get.o src/libnsss/nsss_unix_grp_get.lo: src/libnsss/nsss_unix_grp_get.c src/libnsss/nsss-unix-internal.h src/include/nsss/grp-def.h src/include/nsss/nsss-unix.h
+src/libnsss/nsss_unix_grp_getbygid.o src/libnsss/nsss_unix_grp_getbygid.lo: src/libnsss/nsss_unix_grp_getbygid.c src/include/nsss/grp-def.h src/include/nsss/nsss-unix.h
+src/libnsss/nsss_unix_grp_getbyname.o src/libnsss/nsss_unix_grp_getbyname.lo: src/libnsss/nsss_unix_grp_getbyname.c src/include/nsss/grp-def.h src/include/nsss/nsss-unix.h
+src/libnsss/nsss_unix_grp_here.o src/libnsss/nsss_unix_grp_here.lo: src/libnsss/nsss_unix_grp_here.c src/libnsss/nsss-unix-internal.h
+src/libnsss/nsss_unix_maybe_start.o src/libnsss/nsss_unix_maybe_start.lo: src/libnsss/nsss_unix_maybe_start.c src/include/nsss/nsss-unix.h
+src/libnsss/nsss_unix_pwd_get.o src/libnsss/nsss_unix_pwd_get.lo: src/libnsss/nsss_unix_pwd_get.c src/libnsss/nsss-unix-internal.h src/include/nsss/nsss-unix.h src/include/nsss/pwd-def.h
+src/libnsss/nsss_unix_pwd_getbyname.o src/libnsss/nsss_unix_pwd_getbyname.lo: src/libnsss/nsss_unix_pwd_getbyname.c src/include/nsss/nsss-unix.h src/include/nsss/pwd-def.h
+src/libnsss/nsss_unix_pwd_getbyuid.o src/libnsss/nsss_unix_pwd_getbyuid.lo: src/libnsss/nsss_unix_pwd_getbyuid.c src/include/nsss/nsss-unix.h src/include/nsss/pwd-def.h
+src/libnsss/nsss_unix_pwd_here.o src/libnsss/nsss_unix_pwd_here.lo: src/libnsss/nsss_unix_pwd_here.c src/libnsss/nsss-unix-internal.h
+src/libnsss/nsss_unix_rewind.o src/libnsss/nsss_unix_rewind.lo: src/libnsss/nsss_unix_rewind.c src/include/nsss/nsss-unix.h
+src/libnsss/nsss_unix_setgrent.o src/libnsss/nsss_unix_setgrent.lo: src/libnsss/nsss_unix_setgrent.c src/libnsss/nsss-unix-internal.h src/include/nsss/grp-unix.h src/include/nsss/nsss-unix.h
+src/libnsss/nsss_unix_setpwent.o src/libnsss/nsss_unix_setpwent.lo: src/libnsss/nsss_unix_setpwent.c src/libnsss/nsss-unix-internal.h src/include/nsss/nsss-unix.h src/include/nsss/pwd-unix.h
+src/libnsss/nsss_unix_setspent.o src/libnsss/nsss_unix_setspent.lo: src/libnsss/nsss_unix_setspent.c src/libnsss/nsss-unix-internal.h src/include/nsss/nsss-unix.h src/include/nsss/shadow-unix.h
+src/libnsss/nsss_unix_shadow_get.o src/libnsss/nsss_unix_shadow_get.lo: src/libnsss/nsss_unix_shadow_get.c src/libnsss/nsss-unix-internal.h src/include/nsss/nsss-unix.h src/include/nsss/shadow-def.h
+src/libnsss/nsss_unix_shadow_getbyname.o src/libnsss/nsss_unix_shadow_getbyname.lo: src/libnsss/nsss_unix_shadow_getbyname.c src/include/nsss/nsss-unix.h src/include/nsss/shadow-def.h
+src/libnsss/nsss_unix_shadow_here.o src/libnsss/nsss_unix_shadow_here.lo: src/libnsss/nsss_unix_shadow_here.c src/libnsss/nsss-unix-internal.h
+src/libnsss/nsss_unix_start.o src/libnsss/nsss_unix_start.lo: src/libnsss/nsss_unix_start.c src/include/nsss/nsss-unix.h
+src/nsssd/nsssd-nslcd.o src/nsssd/nsssd-nslcd.lo: src/nsssd/nsssd-nslcd.c src/include/nsss/nsssd.h src/nsssd/nsssd-nslcd.h
+src/nsssd/nsssd-unix.o src/nsssd/nsssd-unix.lo: src/nsssd/nsssd-unix.c src/include/nsss/grp-unix.h src/include/nsss/nsssd.h src/include/nsss/pwd-unix.h src/include/nsss/shadow-unix.h
+src/nsssd/nsssd_convert.o src/nsssd/nsssd_convert.lo: src/nsssd/nsssd_convert.c src/include/nsss/grp-def.h src/include/nsss/nsssd.h src/include/nsss/pwd-def.h src/include/nsss/shadow-def.h
+src/nsssd/nsssd_main.o src/nsssd/nsssd_main.lo: src/nsssd/nsssd_main.c src/include/nsss/grp-def.h src/include/nsss/nsss-switch.h src/include/nsss/nsssd.h src/include/nsss/pwd-def.h src/include/nsss/shadow-def.h
+
+ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),)
+libnsss.a.xyzzy: src/libnsss/nsss_all_endgrent.o src/libnsss/nsss_all_endpwent.o src/libnsss/nsss_all_endspent.o src/libnsss/nsss_all_errno.o src/libnsss/nsss_all_getgrent.o src/libnsss/nsss_all_getgrent_r.o src/libnsss/nsss_all_getgrgid.o src/libnsss/nsss_all_getgrgid_r.o src/libnsss/nsss_all_getgrnam.o src/libnsss/nsss_all_getgrnam_r.o src/libnsss/nsss_all_getpwent.o src/libnsss/nsss_all_getpwent_r.o src/libnsss/nsss_all_getpwnam.o src/libnsss/nsss_all_getpwnam_r.o src/libnsss/nsss_all_getpwuid.o src/libnsss/nsss_all_getpwuid_r.o src/libnsss/nsss_all_getspent.o src/libnsss/nsss_all_getspent_r.o src/libnsss/nsss_all_getspnam.o src/libnsss/nsss_all_getspnam_r.o src/libnsss/nsss_all_setgrent.o src/libnsss/nsss_all_setpwent.o src/libnsss/nsss_all_setspent.o src/libnsss/nsss_grp_copy.o src/libnsss/nsss_grp_here.o src/libnsss/nsss_pwd_copy.o src/libnsss/nsss_pwd_here.o src/libnsss/nsss_shadow_copy.o src/libnsss/nsss_shadow_here.o src/libnsss/nsss_switch_end.o src/libnsss/nsss_switch_endgrent.o src/libnsss/nsss_switch_endpwent.o src/libnsss/nsss_switch_endspent.o src/libnsss/nsss_switch_getgrent.o src/libnsss/nsss_switch_getgrent_r.o src/libnsss/nsss_switch_getgrgid.o src/libnsss/nsss_switch_getgrgid_r.o src/libnsss/nsss_switch_getgrnam.o src/libnsss/nsss_switch_getgrnam_r.o src/libnsss/nsss_switch_getpwent.o src/libnsss/nsss_switch_getpwent_r.o src/libnsss/nsss_switch_getpwnam.o src/libnsss/nsss_switch_getpwnam_r.o src/libnsss/nsss_switch_getpwuid.o src/libnsss/nsss_switch_getpwuid_r.o src/libnsss/nsss_switch_getspent.o src/libnsss/nsss_switch_getspent_r.o src/libnsss/nsss_switch_getspnam.o src/libnsss/nsss_switch_getspnam_r.o src/libnsss/nsss_switch_grp_end.o src/libnsss/nsss_switch_grp_get.o src/libnsss/nsss_switch_grp_getbygid.o src/libnsss/nsss_switch_grp_getbyname.o src/libnsss/nsss_switch_grp_read.o src/libnsss/nsss_switch_grp_rewind.o src/libnsss/nsss_switch_here.o src/libnsss/nsss_switch_op.o src/libnsss/nsss_switch_pwd_end.o src/libnsss/nsss_switch_pwd_get.o src/libnsss/nsss_switch_pwd_getbyname.o src/libnsss/nsss_switch_pwd_getbyuid.o src/libnsss/nsss_switch_pwd_read.o src/libnsss/nsss_switch_pwd_rewind.o src/libnsss/nsss_switch_setgrent.o src/libnsss/nsss_switch_setpwent.o src/libnsss/nsss_switch_setspent.o src/libnsss/nsss_switch_shadow_end.o src/libnsss/nsss_switch_shadow_get.o src/libnsss/nsss_switch_shadow_getbyname.o src/libnsss/nsss_switch_shadow_read.o src/libnsss/nsss_switch_shadow_rewind.o src/libnsss/nsss_switch_start.o src/libnsss/nsss_unix_end.o src/libnsss/nsss_unix_endgrent.o src/libnsss/nsss_unix_endpwent.o src/libnsss/nsss_unix_endspent.o src/libnsss/nsss_unix_field.o src/libnsss/nsss_unix_getgrent.o src/libnsss/nsss_unix_getgrent_r.o src/libnsss/nsss_unix_getgrgid.o src/libnsss/nsss_unix_getgrgid_r.o src/libnsss/nsss_unix_getgrnam.o src/libnsss/nsss_unix_getgrnam_r.o src/libnsss/nsss_unix_getpwent.o src/libnsss/nsss_unix_getpwent_r.o src/libnsss/nsss_unix_getpwnam.o src/libnsss/nsss_unix_getpwnam_r.o src/libnsss/nsss_unix_getpwuid.o src/libnsss/nsss_unix_getpwuid_r.o src/libnsss/nsss_unix_getspent.o src/libnsss/nsss_unix_getspent_r.o src/libnsss/nsss_unix_getspnam.o src/libnsss/nsss_unix_getspnam_r.o src/libnsss/nsss_unix_grp_get.o src/libnsss/nsss_unix_grp_getbygid.o src/libnsss/nsss_unix_grp_getbyname.o src/libnsss/nsss_unix_grp_here.o src/libnsss/nsss_unix_maybe_start.o src/libnsss/nsss_unix_pwd_get.o src/libnsss/nsss_unix_pwd_getbyname.o src/libnsss/nsss_unix_pwd_getbyuid.o src/libnsss/nsss_unix_pwd_here.o src/libnsss/nsss_unix_rewind.o src/libnsss/nsss_unix_setgrent.o src/libnsss/nsss_unix_setpwent.o src/libnsss/nsss_unix_setspent.o src/libnsss/nsss_unix_shadow_get.o src/libnsss/nsss_unix_shadow_getbyname.o src/libnsss/nsss_unix_shadow_here.o src/libnsss/nsss_unix_start.o
+else
+libnsss.a.xyzzy: src/libnsss/nsss_all_endgrent.lo src/libnsss/nsss_all_endpwent.lo src/libnsss/nsss_all_endspent.lo src/libnsss/nsss_all_errno.lo src/libnsss/nsss_all_getgrent.lo src/libnsss/nsss_all_getgrent_r.lo src/libnsss/nsss_all_getgrgid.lo src/libnsss/nsss_all_getgrgid_r.lo src/libnsss/nsss_all_getgrnam.lo src/libnsss/nsss_all_getgrnam_r.lo src/libnsss/nsss_all_getpwent.lo src/libnsss/nsss_all_getpwent_r.lo src/libnsss/nsss_all_getpwnam.lo src/libnsss/nsss_all_getpwnam_r.lo src/libnsss/nsss_all_getpwuid.lo src/libnsss/nsss_all_getpwuid_r.lo src/libnsss/nsss_all_getspent.lo src/libnsss/nsss_all_getspent_r.lo src/libnsss/nsss_all_getspnam.lo src/libnsss/nsss_all_getspnam_r.lo src/libnsss/nsss_all_setgrent.lo src/libnsss/nsss_all_setpwent.lo src/libnsss/nsss_all_setspent.lo src/libnsss/nsss_grp_copy.lo src/libnsss/nsss_grp_here.lo src/libnsss/nsss_pwd_copy.lo src/libnsss/nsss_pwd_here.lo src/libnsss/nsss_shadow_copy.lo src/libnsss/nsss_shadow_here.lo src/libnsss/nsss_switch_end.lo src/libnsss/nsss_switch_endgrent.lo src/libnsss/nsss_switch_endpwent.lo src/libnsss/nsss_switch_endspent.lo src/libnsss/nsss_switch_getgrent.lo src/libnsss/nsss_switch_getgrent_r.lo src/libnsss/nsss_switch_getgrgid.lo src/libnsss/nsss_switch_getgrgid_r.lo src/libnsss/nsss_switch_getgrnam.lo src/libnsss/nsss_switch_getgrnam_r.lo src/libnsss/nsss_switch_getpwent.lo src/libnsss/nsss_switch_getpwent_r.lo src/libnsss/nsss_switch_getpwnam.lo src/libnsss/nsss_switch_getpwnam_r.lo src/libnsss/nsss_switch_getpwuid.lo src/libnsss/nsss_switch_getpwuid_r.lo src/libnsss/nsss_switch_getspent.lo src/libnsss/nsss_switch_getspent_r.lo src/libnsss/nsss_switch_getspnam.lo src/libnsss/nsss_switch_getspnam_r.lo src/libnsss/nsss_switch_grp_end.lo src/libnsss/nsss_switch_grp_get.lo src/libnsss/nsss_switch_grp_getbygid.lo src/libnsss/nsss_switch_grp_getbyname.lo src/libnsss/nsss_switch_grp_read.lo src/libnsss/nsss_switch_grp_rewind.lo src/libnsss/nsss_switch_here.lo src/libnsss/nsss_switch_op.lo src/libnsss/nsss_switch_pwd_end.lo src/libnsss/nsss_switch_pwd_get.lo src/libnsss/nsss_switch_pwd_getbyname.lo src/libnsss/nsss_switch_pwd_getbyuid.lo src/libnsss/nsss_switch_pwd_read.lo src/libnsss/nsss_switch_pwd_rewind.lo src/libnsss/nsss_switch_setgrent.lo src/libnsss/nsss_switch_setpwent.lo src/libnsss/nsss_switch_setspent.lo src/libnsss/nsss_switch_shadow_end.lo src/libnsss/nsss_switch_shadow_get.lo src/libnsss/nsss_switch_shadow_getbyname.lo src/libnsss/nsss_switch_shadow_read.lo src/libnsss/nsss_switch_shadow_rewind.lo src/libnsss/nsss_switch_start.lo src/libnsss/nsss_unix_end.lo src/libnsss/nsss_unix_endgrent.lo src/libnsss/nsss_unix_endpwent.lo src/libnsss/nsss_unix_endspent.lo src/libnsss/nsss_unix_field.lo src/libnsss/nsss_unix_getgrent.lo src/libnsss/nsss_unix_getgrent_r.lo src/libnsss/nsss_unix_getgrgid.lo src/libnsss/nsss_unix_getgrgid_r.lo src/libnsss/nsss_unix_getgrnam.lo src/libnsss/nsss_unix_getgrnam_r.lo src/libnsss/nsss_unix_getpwent.lo src/libnsss/nsss_unix_getpwent_r.lo src/libnsss/nsss_unix_getpwnam.lo src/libnsss/nsss_unix_getpwnam_r.lo src/libnsss/nsss_unix_getpwuid.lo src/libnsss/nsss_unix_getpwuid_r.lo src/libnsss/nsss_unix_getspent.lo src/libnsss/nsss_unix_getspent_r.lo src/libnsss/nsss_unix_getspnam.lo src/libnsss/nsss_unix_getspnam_r.lo src/libnsss/nsss_unix_grp_get.lo src/libnsss/nsss_unix_grp_getbygid.lo src/libnsss/nsss_unix_grp_getbyname.lo src/libnsss/nsss_unix_grp_here.lo src/libnsss/nsss_unix_maybe_start.lo src/libnsss/nsss_unix_pwd_get.lo src/libnsss/nsss_unix_pwd_getbyname.lo src/libnsss/nsss_unix_pwd_getbyuid.lo src/libnsss/nsss_unix_pwd_here.lo src/libnsss/nsss_unix_rewind.lo src/libnsss/nsss_unix_setgrent.lo src/libnsss/nsss_unix_setpwent.lo src/libnsss/nsss_unix_setspent.lo src/libnsss/nsss_unix_shadow_get.lo src/libnsss/nsss_unix_shadow_getbyname.lo src/libnsss/nsss_unix_shadow_here.lo src/libnsss/nsss_unix_start.lo
+endif
+libnsss.so.xyzzy: EXTRA_LIBS := -lskarnet
+libnsss.so.xyzzy: src/libnsss/nsss_all_endgrent.lo src/libnsss/nsss_all_endpwent.lo src/libnsss/nsss_all_endspent.lo src/libnsss/nsss_all_errno.lo src/libnsss/nsss_all_getgrent.lo src/libnsss/nsss_all_getgrent_r.lo src/libnsss/nsss_all_getgrgid.lo src/libnsss/nsss_all_getgrgid_r.lo src/libnsss/nsss_all_getgrnam.lo src/libnsss/nsss_all_getgrnam_r.lo src/libnsss/nsss_all_getpwent.lo src/libnsss/nsss_all_getpwent_r.lo src/libnsss/nsss_all_getpwnam.lo src/libnsss/nsss_all_getpwnam_r.lo src/libnsss/nsss_all_getpwuid.lo src/libnsss/nsss_all_getpwuid_r.lo src/libnsss/nsss_all_getspent.lo src/libnsss/nsss_all_getspent_r.lo src/libnsss/nsss_all_getspnam.lo src/libnsss/nsss_all_getspnam_r.lo src/libnsss/nsss_all_setgrent.lo src/libnsss/nsss_all_setpwent.lo src/libnsss/nsss_all_setspent.lo src/libnsss/nsss_grp_copy.lo src/libnsss/nsss_grp_here.lo src/libnsss/nsss_pwd_copy.lo src/libnsss/nsss_pwd_here.lo src/libnsss/nsss_shadow_copy.lo src/libnsss/nsss_shadow_here.lo src/libnsss/nsss_switch_end.lo src/libnsss/nsss_switch_endgrent.lo src/libnsss/nsss_switch_endpwent.lo src/libnsss/nsss_switch_endspent.lo src/libnsss/nsss_switch_getgrent.lo src/libnsss/nsss_switch_getgrent_r.lo src/libnsss/nsss_switch_getgrgid.lo src/libnsss/nsss_switch_getgrgid_r.lo src/libnsss/nsss_switch_getgrnam.lo src/libnsss/nsss_switch_getgrnam_r.lo src/libnsss/nsss_switch_getpwent.lo src/libnsss/nsss_switch_getpwent_r.lo src/libnsss/nsss_switch_getpwnam.lo src/libnsss/nsss_switch_getpwnam_r.lo src/libnsss/nsss_switch_getpwuid.lo src/libnsss/nsss_switch_getpwuid_r.lo src/libnsss/nsss_switch_getspent.lo src/libnsss/nsss_switch_getspent_r.lo src/libnsss/nsss_switch_getspnam.lo src/libnsss/nsss_switch_getspnam_r.lo src/libnsss/nsss_switch_grp_end.lo src/libnsss/nsss_switch_grp_get.lo src/libnsss/nsss_switch_grp_getbygid.lo src/libnsss/nsss_switch_grp_getbyname.lo src/libnsss/nsss_switch_grp_read.lo src/libnsss/nsss_switch_grp_rewind.lo src/libnsss/nsss_switch_here.lo src/libnsss/nsss_switch_op.lo src/libnsss/nsss_switch_pwd_end.lo src/libnsss/nsss_switch_pwd_get.lo src/libnsss/nsss_switch_pwd_getbyname.lo src/libnsss/nsss_switch_pwd_getbyuid.lo src/libnsss/nsss_switch_pwd_read.lo src/libnsss/nsss_switch_pwd_rewind.lo src/libnsss/nsss_switch_setgrent.lo src/libnsss/nsss_switch_setpwent.lo src/libnsss/nsss_switch_setspent.lo src/libnsss/nsss_switch_shadow_end.lo src/libnsss/nsss_switch_shadow_get.lo src/libnsss/nsss_switch_shadow_getbyname.lo src/libnsss/nsss_switch_shadow_read.lo src/libnsss/nsss_switch_shadow_rewind.lo src/libnsss/nsss_switch_start.lo src/libnsss/nsss_unix_end.lo src/libnsss/nsss_unix_endgrent.lo src/libnsss/nsss_unix_endpwent.lo src/libnsss/nsss_unix_endspent.lo src/libnsss/nsss_unix_field.lo src/libnsss/nsss_unix_getgrent.lo src/libnsss/nsss_unix_getgrent_r.lo src/libnsss/nsss_unix_getgrgid.lo src/libnsss/nsss_unix_getgrgid_r.lo src/libnsss/nsss_unix_getgrnam.lo src/libnsss/nsss_unix_getgrnam_r.lo src/libnsss/nsss_unix_getpwent.lo src/libnsss/nsss_unix_getpwent_r.lo src/libnsss/nsss_unix_getpwnam.lo src/libnsss/nsss_unix_getpwnam_r.lo src/libnsss/nsss_unix_getpwuid.lo src/libnsss/nsss_unix_getpwuid_r.lo src/libnsss/nsss_unix_getspent.lo src/libnsss/nsss_unix_getspent_r.lo src/libnsss/nsss_unix_getspnam.lo src/libnsss/nsss_unix_getspnam_r.lo src/libnsss/nsss_unix_grp_get.lo src/libnsss/nsss_unix_grp_getbygid.lo src/libnsss/nsss_unix_grp_getbyname.lo src/libnsss/nsss_unix_grp_here.lo src/libnsss/nsss_unix_maybe_start.lo src/libnsss/nsss_unix_pwd_get.lo src/libnsss/nsss_unix_pwd_getbyname.lo src/libnsss/nsss_unix_pwd_getbyuid.lo src/libnsss/nsss_unix_pwd_here.lo src/libnsss/nsss_unix_rewind.lo src/libnsss/nsss_unix_setgrent.lo src/libnsss/nsss_unix_setpwent.lo src/libnsss/nsss_unix_setspent.lo src/libnsss/nsss_unix_shadow_get.lo src/libnsss/nsss_unix_shadow_getbyname.lo src/libnsss/nsss_unix_shadow_here.lo src/libnsss/nsss_unix_start.lo
+ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),)
+libnsssd.a.xyzzy: src/nsssd/nsssd_main.o src/nsssd/nsssd_convert.o
+else
+libnsssd.a.xyzzy: src/nsssd/nsssd_main.lo src/nsssd/nsssd_convert.lo
+endif
+libnsssd.so.xyzzy: EXTRA_LIBS := -lskarnet
+libnsssd.so.xyzzy: src/nsssd/nsssd_main.lo src/nsssd/nsssd_convert.lo
+nsssd-nslcd: EXTRA_LIBS :=
+nsssd-nslcd: src/nsssd/nsssd-nslcd.o ${LIBNSSSD} -lskarnet
+nsssd-unix: EXTRA_LIBS :=
+nsssd-unix: src/nsssd/nsssd-unix.o ${LIBNSSS} ${LIBNSSSD} -lskarnet
diff --git a/package/info b/package/info
new file mode 100644
index 0000000..2242df4
--- /dev/null
+++ b/package/info
@@ -0,0 +1,4 @@
+package=nsss
+version=0.0.1.0
+category=admin
+package_macro_name=NSSS
diff --git a/package/modes b/package/modes
new file mode 100644
index 0000000..013611d
--- /dev/null
+++ b/package/modes
@@ -0,0 +1,2 @@
+nsssd-unix	0755
+nsssd-nslcd	0755
diff --git a/package/targets.mak b/package/targets.mak
new file mode 100644
index 0000000..2dd3b81
--- /dev/null
+++ b/package/targets.mak
@@ -0,0 +1,7 @@
+BIN_TARGETS := \
+nsssd-unix \
+nsssd-nslcd
+
+LIBEXEC_TARGETS :=
+
+LIB_DEFS := NSSS=nsss NSSSD=nsssd
diff --git a/patch-for-solaris b/patch-for-solaris
new file mode 100755
index 0000000..2d1296b
--- /dev/null
+++ b/patch-for-solaris
@@ -0,0 +1,21 @@
+#!/usr/xpg4/bin/sh
+
+patchit () {
+  echo '#!/usr/xpg4/bin/sh' > $1.tmp
+  tail -n +2 $1 >> $1.tmp
+  mv -f $1.tmp $1
+  chmod 755 $1
+}
+
+# Solaris doesn't understand POSIX.1-2008 either.
+sed -e 's/XOPEN_SOURCE=700/XOPEN_SOURCE=600/' < configure > configure.tmp
+mv -f configure.tmp configure
+
+patchit ./configure
+patchit ./tools/install.sh
+patchit ./tools/gen-deps.sh
+
+echo 'SHELL := /usr/xpg4/bin/sh' > Makefile.tmp
+echo >> Makefile.tmp
+cat Makefile >> Makefile.tmp
+mv -f Makefile.tmp Makefile
diff --git a/src/include/grp.h b/src/include/grp.h
new file mode 100644
index 0000000..4516a19
--- /dev/null
+++ b/src/include/grp.h
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+/*
+  This file is part of the nsss package.
+  See https://skarnet.org/software/nsss/
+*/
+
+#ifndef GRP_H
+#define GRP_H
+
+#include <nsss/grp.h>
+
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+#include <sys/types.h>
+extern int getgrouplist (char const *, gid_t, gid_t *, int *) ;
+extern int setgroups (size_t, gid_t const *) ;
+extern int initgroups (char const *, gid_t) ;
+#endif
+
+#ifdef _GNU_SOURCE
+#include <stdio.h>
+extern struct group *fgetgrent (FILE *) ;
+extern int fgetgrent_r (FILE *, struct group *, char *, size_t, struct group **) ;
+extern int putgrent (struct group const *, FILE *) ;
+#endif
+
+#endif
diff --git a/src/include/nsss/grp-all.h b/src/include/nsss/grp-all.h
new file mode 100644
index 0000000..54ea213
--- /dev/null
+++ b/src/include/nsss/grp-all.h
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#ifndef NSSS_GRP_ALL_H
+#define NSSS_GRP_ALL_H
+
+#include <nsss/grp-def.h>
+
+/* switch then fallback on unix */
+
+extern void nsss_all_setgrent (void) ;
+extern struct group *nsss_all_getgrent (void) ;
+extern int nsss_all_getgrent_r (struct group *, char *, size_t, struct group **) ;
+extern void nsss_all_endgrent (void) ;
+
+extern struct group *nsss_all_getgrgid (gid_t) ;
+extern struct group *nsss_all_getgrnam (char const *) ;
+extern int nsss_all_getgrgid_r (gid_t, struct group *, char *, size_t, struct group **) ;
+extern int nsss_all_getgrnam_r (char const *, struct group *, char *, size_t, struct group **) ;
+
+#endif
diff --git a/src/include/nsss/grp-def.h b/src/include/nsss/grp-def.h
new file mode 100644
index 0000000..0a6db50
--- /dev/null
+++ b/src/include/nsss/grp-def.h
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#ifndef NSSS_GRP_DEF_H
+#define NSSS_GRP_DEF_H
+
+#include <sys/types.h>
+
+struct group
+{
+  char *gr_name ;
+  char *gr_passwd ;
+  gid_t gr_gid ;
+  char **gr_mem ;
+} ;
+
+#endif
diff --git a/src/include/nsss/grp-switch.h b/src/include/nsss/grp-switch.h
new file mode 100644
index 0000000..6a9ba10
--- /dev/null
+++ b/src/include/nsss/grp-switch.h
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#ifndef NSSS_GRP_SWITCH_H
+#define NSSS_GRP_SWITCH_H
+
+#include <nsss/grp-def.h>
+
+ /* Group functions contacting the nsssd daemon */
+
+extern void nsss_switch_setgrent (void) ;
+extern struct group *nsss_switch_getgrent (void) ;
+extern int nsss_switch_getgrent_r (struct group *, char *, size_t, struct group **) ;
+extern void nsss_switch_endgrent (void) ;
+
+extern struct group *nsss_switch_getgrgid (gid_t) ;
+extern struct group *nsss_switch_getgrnam (char const *) ;
+extern int nsss_switch_getgrgid_r (gid_t, struct group *, char *, size_t, struct group **) ;
+extern int nsss_switch_getgrnam_r (char const *, struct group *, char *, size_t, struct group **) ;
+
+#endif
diff --git a/src/include/nsss/grp-unix.h b/src/include/nsss/grp-unix.h
new file mode 100644
index 0000000..fe089f1
--- /dev/null
+++ b/src/include/nsss/grp-unix.h
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#ifndef NSSS_GRP_UNIX_H
+#define NSSS_GRP_UNIX_H
+
+#include <nsss/grp-def.h>
+
+ /* /etc/group backend */
+
+extern void nsss_unix_setgrent (void) ;
+extern struct group *nsss_unix_getgrent (void) ;
+extern int nsss_unix_getgrent_r (struct group *, char *, size_t, struct group **) ;
+extern void nsss_unix_endgrent (void) ;
+
+extern struct group *nsss_unix_getgrgid (gid_t) ;
+extern struct group *nsss_unix_getgrnam (char const *) ;
+extern int nsss_unix_getgrgid_r (gid_t, struct group *, char *, size_t, struct group **) ;
+extern int nsss_unix_getgrnam_r (char const *, struct group *, char *, size_t, struct group **) ;
+
+#endif
diff --git a/src/include/nsss/grp.h b/src/include/nsss/grp.h
new file mode 100644
index 0000000..ea963b6
--- /dev/null
+++ b/src/include/nsss/grp.h
@@ -0,0 +1,58 @@
+/* ISC license. */
+
+#ifndef NSSS_GRP_H
+#define NSSS_GRP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef NSSS_DISABLE_SWITCH
+
+#include <nsss/grp-unix.h>
+
+#define setgrent nsss_unix_setgrent
+#define getgrent nsss_unix_getgrent
+#define getgrent_r nsss_unix_getgrent_r
+#define endgrent nsss_unix_endgrent
+#define getgrgid nsss_unix_getgrgid
+#define getgrgid_r nsss_unix_getgrgid_r
+#define getgrnam nsss_unix_getgrnam
+#define getgrnam_r nsss_unix_getgrnam_r
+
+#else
+#ifdef NSSS_DISABLE_UNIX
+
+#include <nsss/grp-switch.h>
+
+#define setgrent nsss_switch_setgrent
+#define getgrent nsss_switch_getgrent
+#define getgrent_r nsss_switch_getgrent_r
+#define endgrent nsss_switch_endgrent
+#define getgrgid nsss_switch_getgrgid
+#define getgrgid_r nsss_switch_getgrgid_r
+#define getgrnam nsss_switch_getgrnam
+#define getgrnam_r nsss_switch_getgrnam_r
+
+#else
+
+#include <nsss/grp-all.h>
+
+#define setgrent nsss_all_setgrent
+#define getgrent nsss_all_getgrent
+#define getgrent_r nsss_all_getgrent_r
+#define endgrent nsss_all_endgrent
+#define getgrgid nsss_all_getgrgid
+#define getgrgid_r nsss_all_getgrgid_r
+#define getgrnam nsss_all_getgrnam
+#define getgrnam_r nsss_all_getgrnam_r
+
+#endif
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/include/nsss/nsss-all.h b/src/include/nsss/nsss-all.h
new file mode 100644
index 0000000..4530e97
--- /dev/null
+++ b/src/include/nsss/nsss-all.h
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#ifndef NSSS_ALL_H
+#define NSSS_ALL_H
+
+#include <nsss/pwd-all.h>
+#include <nsss/grp-all.h>
+#include <nsss/shadow-all.h>
+
+#endif
diff --git a/src/include/nsss/nsss-switch.h b/src/include/nsss/nsss-switch.h
new file mode 100644
index 0000000..1bfe50f
--- /dev/null
+++ b/src/include/nsss/nsss-switch.h
@@ -0,0 +1,93 @@
+/* ISC license. */
+
+#ifndef NSSS_SWITCH_H
+#define NSSS_SWITCH_H
+
+#include <sys/types.h>
+#include <limits.h>
+#include <skalibs/tai.h>
+#include <skalibs/buffer.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <nsss/pwd-switch.h>
+#include <nsss/grp-switch.h>
+#include <nsss/shadow-switch.h>
+
+#define NSSS_SWITCH_BUFSIZE 4096
+#define NSSS_SWITCH_NAME_MAXLEN LOGIN_NAME_MAX
+
+typedef struct nsss_switch_s nsss_switch_t, *nsss_switch_t_ref ;
+struct nsss_switch_s
+{
+  unsigned int held ;
+  buffer b ;
+  char buf[NSSS_SWITCH_BUFSIZE] ;
+} ;
+#define NSSS_SWITCH_ZERO { .held = 0, .b = BUFFER_ZERO }
+
+#define NSSS_SWITCH_PWD 0
+#define NSSS_SWITCH_GRP 1
+#define NSSS_SWITCH_SHADOW 2
+
+extern int nsss_switch_start (nsss_switch_t *, unsigned int, char const *, tain_t const *, tain_t *) ;
+#define nsss_switch_start_g(a, what, s, deadline) nsss_switch_start(a, what, s, (deadline), &STAMP)
+extern void nsss_switch_end (nsss_switch_t *, unsigned int) ;
+
+
+ /* Password */
+
+#define NSSS_SWITCH_PWD_END '\0'
+#define NSSS_SWITCH_PWD_REWIND '\001'
+#define NSSS_SWITCH_PWD_GET '\002'
+#define NSSS_SWITCH_PWD_GETBYNAME '\003'
+#define NSSS_SWITCH_PWD_GETBYUID '\004'
+
+extern int nsss_switch_pwd_end (nsss_switch_t *, tain_t const *, tain_t *) ;
+#define nsss_switch_pwd_end_g(a, deadline) nsss_switch_pwd_end(a, (deadline), &STAMP)
+extern int nsss_switch_pwd_rewind (nsss_switch_t *, tain_t const *, tain_t *) ;
+#define nsss_switch_pwd_rewind_g(a, deadline) nsss_switch_pwd_rewind(a, (deadline), &STAMP)
+extern int nsss_switch_pwd_get (nsss_switch_t *, struct passwd *, stralloc *, tain_t const *, tain_t *) ;
+#define nsss_switch_pwd_get_g(a, b, sa, deadline) nsss_switch_pwd_get(a, b, sa, (deadline), &STAMP)
+extern int nsss_switch_pwd_getbyname (nsss_switch_t *, struct passwd *, stralloc *, char const *, tain_t const *, tain_t *) ;
+#define nsss_switch_pwd_getbyname_g(a, b, sa, name, deadline) nsss_switch_pwd_getbyname(a, b, sa, name, (deadline), &STAMP)
+extern int nsss_switch_pwd_getbyuid (nsss_switch_t *, struct passwd *, stralloc *, uid_t, tain_t const *, tain_t *) ;
+#define nsss_switch_pwd_getbyuid_g(a, b, sa, u, deadline) nsss_switch_pwd_getbyuid(a, b, sa, u, (deadline), &STAMP)
+
+
+ /* Group */
+
+#define NSSS_SWITCH_GRP_END '\020'
+#define NSSS_SWITCH_GRP_REWIND '\021'
+#define NSSS_SWITCH_GRP_GET '\022'
+#define NSSS_SWITCH_GRP_GETBYNAME '\023'
+#define NSSS_SWITCH_GRP_GETBYGID '\024'
+
+extern int nsss_switch_grp_end (nsss_switch_t *, tain_t const *, tain_t *) ;
+#define nsss_switch_grp_end_g(a, deadline) nsss_switch_grp_end(a, (deadline), &STAMP)
+extern int nsss_switch_grp_rewind (nsss_switch_t *, tain_t const *, tain_t *) ;
+#define nsss_switch_grp_rewind_g(a, deadline) nsss_switch_grp_rewind(a, (deadline), &STAMP)
+extern int nsss_switch_grp_get (nsss_switch_t *, struct group *, stralloc *, genalloc *, tain_t const *, tain_t *) ;
+#define nsss_switch_grp_get_g(a, b, sa, ga, deadline) nsss_switch_grp_get(a, b, sa, ga, (deadline), &STAMP)
+extern int nsss_switch_grp_getbyname (nsss_switch_t *, struct group *, stralloc *, genalloc *, char const *, tain_t const *, tain_t *) ;
+#define nsss_switch_grp_getbyname_g(a, b, sa, ga, name, deadline) nsss_switch_grp_getbyname(a, b, sa, ga, name, (deadline), &STAMP)
+extern int nsss_switch_grp_getbygid (nsss_switch_t *, struct group *, stralloc *, genalloc *, gid_t, tain_t const *, tain_t *) ;
+#define nsss_switch_grp_getbygid_g(a, b, sa, ga, g, deadline) nsss_switch_grp_getbygid(a, b, sa, ga, g, (deadline), &STAMP)
+
+
+ /* Shadow */
+
+#define NSSS_SWITCH_SHADOW_END '\040'
+#define NSSS_SWITCH_SHADOW_REWIND '\041'
+#define NSSS_SWITCH_SHADOW_GET '\042'
+#define NSSS_SWITCH_SHADOW_GETBYNAME '\043'
+
+extern int nsss_switch_shadow_end (nsss_switch_t *, tain_t const *, tain_t *) ;
+#define nsss_switch_shadow_end_g(a, deadline) nsss_switch_shadow_end(a, (deadline), &STAMP)
+extern int nsss_switch_shadow_rewind (nsss_switch_t *, tain_t const *, tain_t *) ;
+#define nsss_switch_shadow_rewind_g(a, deadline) nsss_switch_shadow_rewind(a, (deadline), &STAMP)
+extern int nsss_switch_shadow_get (nsss_switch_t *, struct spwd *, stralloc *, tain_t const *, tain_t *) ;
+#define nsss_switch_shadow_get_g(a, b, sa, deadline) nsss_switch_shadow_get(a, b, sa, (deadline), &STAMP)
+extern int nsss_switch_shadow_getbyname (nsss_switch_t *, struct spwd *, stralloc *, char const *, tain_t const *, tain_t *) ;
+#define nsss_switch_shadow_getbyname_g(a, b, sa, name, deadline) nsss_switch_shadow_getbyname(a, b, sa, name, (deadline), &STAMP)
+
+#endif
diff --git a/src/include/nsss/nsss-unix.h b/src/include/nsss/nsss-unix.h
new file mode 100644
index 0000000..786bf88
--- /dev/null
+++ b/src/include/nsss/nsss-unix.h
@@ -0,0 +1,61 @@
+/* ISC license. */
+
+#ifndef NSSS_UNIX_H
+#define NSSS_UNIX_H
+
+#include <sys/types.h>
+#include <skalibs/buffer.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <nsss/pwd-unix.h>
+#include <nsss/grp-unix.h>
+#include <nsss/shadow-unix.h>
+
+#define NSSS_UNIX_BUFSIZE 4096
+
+typedef struct nsss_unix_s nsss_unix_t, *nsss_unix_t_ref ;
+struct nsss_unix_s
+{
+  buffer b ;
+  char buf[NSSS_UNIX_BUFSIZE] ;
+} ;
+#define NSSS_UNIX_ZERO { .b = BUFFER_ZERO }
+
+extern int nsss_unix_start (nsss_unix_t *, char const *) ;
+extern int nsss_unix_maybe_start (nsss_unix_t *, char const *) ;
+extern void nsss_unix_end (nsss_unix_t *) ;
+extern int nsss_unix_rewind (nsss_unix_t *) ;
+
+
+ /* Password */
+
+#define nsss_unix_pwd_start(a) nsss_unix_start(a, "/etc/passwd")
+#define nsss_unix_pwd_maybe_start(a) nsss_unix_maybe_start(a, "/etc/passwd")
+#define nsss_unix_pwd_end(a) nsss_unix_end(a)
+#define nsss_unix_pwd_rewind(a) nsss_unix_rewind(a)
+extern int nsss_unix_pwd_get (nsss_unix_t *, struct passwd *, stralloc *) ;
+extern int nsss_unix_pwd_getbyname (nsss_unix_t *, struct passwd *, stralloc *, char const *) ;
+extern int nsss_unix_pwd_getbyuid (nsss_unix_t *, struct passwd *, stralloc *, uid_t) ;
+
+
+ /* Group */
+
+#define nsss_unix_grp_start(a) nsss_unix_start(a, "/etc/group")
+#define nsss_unix_grp_maybe_start(a) nsss_unix_maybe_start(a, "/etc/group")
+#define nsss_unix_grp_end(a) nsss_unix_end(a)
+#define nsss_unix_grp_rewind(a) nsss_unix_rewind(a)
+extern int nsss_unix_grp_get (nsss_unix_t *, struct group *, stralloc *, genalloc *) ;
+extern int nsss_unix_grp_getbyname (nsss_unix_t *, struct group *, stralloc *, genalloc *, char const *) ;
+extern int nsss_unix_grp_getbygid (nsss_unix_t *, struct group *, stralloc *, genalloc *, gid_t) ;
+
+
+ /* Shadow */
+
+#define nsss_unix_shadow_start(a) nsss_unix_start(a, "/etc/shadow")
+#define nsss_unix_shadow_maybe_start(a) nsss_unix_maybe_start(a, "/etc/shadow")
+#define nsss_unix_shadow_end(a) nsss_unix_end(a)
+#define nsss_unix_shadow_rewind(a) nsss_unix_rewind(a)
+extern int nsss_unix_shadow_get (nsss_unix_t *, struct spwd *, stralloc *) ;
+extern int nsss_unix_shadow_getbyname (nsss_unix_t *, struct spwd *, stralloc *, char const *) ;
+
+#endif
diff --git a/src/include/nsss/nsss.h b/src/include/nsss/nsss.h
new file mode 100644
index 0000000..56e7c08
--- /dev/null
+++ b/src/include/nsss/nsss.h
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#ifndef NSSS_H
+#define NSSS_H
+
+#include <nsss/nsss-unix.h>
+#include <nsss/nsss-switch.h>
+#include <nsss/nsss-all.h>
+
+#endif
diff --git a/src/include/nsss/nsssd.h b/src/include/nsss/nsssd.h
new file mode 100644
index 0000000..7649873
--- /dev/null
+++ b/src/include/nsss/nsssd.h
@@ -0,0 +1,84 @@
+/* ISC license. */
+
+#ifndef NSSSD_H
+#define NSSSD_H
+
+#include <sys/types.h>
+#include <nsss/pwd-def.h>
+#include <nsss/grp-def.h>
+#include <nsss/shadow-def.h>
+
+#define NSSSD_EOF 255
+
+typedef struct nsssd_passwd_s nsssd_passwd_t, *nsssd_passwd_t_ref ;
+struct nsssd_passwd_s
+{
+  size_t pw_name ;
+  size_t pw_passwd ;
+  uid_t pw_uid ;
+  uid_t pw_gid ;
+  size_t pw_gecos ;
+  size_t pw_dir ;
+  size_t pw_shell ;
+} ;
+
+typedef struct nsssd_group_s nsssd_group_t, *nsssd_group_t_ref ;
+struct nsssd_group_s
+{
+  size_t gr_name ;
+  size_t gr_passwd ;
+  gid_t gr_gid ;
+  size_t gr_mem ;
+  size_t gr_mem_n ;
+} ;
+
+typedef struct nsssd_spwd_s nsssd_spwd_t, *nsssd_spwd_t_ref ;
+struct nsssd_spwd_s
+{
+  size_t sp_namp ;
+  size_t sp_pwdp ;
+  long sp_lstchg ;
+  long sp_min ;
+  long sp_max ;
+  long sp_warn ;
+  long sp_inact ;
+  long sp_expire ;
+  unsigned long sp_flag ;
+} ;
+
+
+/* Functions provided by libnsssd */
+
+extern int nsssd_main (char const *const *, char const *const *) ;
+extern void nsssd_passwd_convert (struct passwd *, nsssd_passwd_t const *, char const *) ;
+extern void nsssd_group_convert (struct group *, char **, nsssd_group_t const *, char const *, size_t const *) ;
+extern void nsssd_spwd_convert (struct spwd *, nsssd_spwd_t const *, char const *) ;
+
+
+/* Functions that must be provided by the backend */
+
+extern void *nsssd_handle_init (void) ;
+extern int nsssd_handle_start (void *, char const *const *, char const *const *) ;
+extern void nsssd_handle_end (void *) ;
+
+extern int nsssd_pwd_start (void *) ;
+extern int nsssd_pwd_rewind (void *) ;
+extern int nsssd_pwd_get (void *, struct passwd *) ;
+extern int nsssd_pwd_getbyuid (void *, struct passwd *, uid_t) ;
+extern int nsssd_pwd_getbyname (void *, struct passwd *, char const *) ;
+extern void nsssd_pwd_end (void *) ;
+
+extern int nsssd_grp_start (void *) ;
+extern int nsssd_grp_rewind (void *) ;
+extern int nsssd_grp_get (void *, struct group *) ;
+extern int nsssd_grp_getbygid (void *, struct group *, gid_t) ;
+extern int nsssd_grp_getbyname (void *, struct group *, char const *) ;
+extern void nsssd_grp_end (void *) ;
+
+extern int nsssd_shadow_start (void *) ;
+extern int nsssd_shadow_rewind (void *) ;
+extern int nsssd_shadow_get (void *, struct spwd *) ;
+extern int nsssd_shadow_getbyname (void *, struct spwd *, char const *) ;
+extern void nsssd_shadow_end (void *) ;
+
+#endif
diff --git a/src/include/nsss/pwd-all.h b/src/include/nsss/pwd-all.h
new file mode 100644
index 0000000..02d38a3
--- /dev/null
+++ b/src/include/nsss/pwd-all.h
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#ifndef NSSS_PWD_ALL_H
+#define NSSS_PWD_ALL_H
+
+#include <nsss/pwd-def.h>
+
+ /* switch then fallback on unix */
+
+extern void nsss_all_setpwent (void) ;
+extern struct passwd *nsss_all_getpwent (void) ;
+extern int nsss_all_getpwent_r (struct passwd *, char *, size_t, struct passwd **) ;
+extern void nsss_all_endpwent (void) ;
+
+extern struct passwd *nsss_all_getpwuid (uid_t) ;
+extern int nsss_all_getpwuid_r (uid_t, struct passwd *, char *, size_t, struct passwd **) ;
+extern struct passwd *nsss_all_getpwnam (char const *) ;
+extern int nsss_all_getpwnam_r (char const *, struct passwd *, char *, size_t, struct passwd **) ;
+
+#endif
diff --git a/src/include/nsss/pwd-def.h b/src/include/nsss/pwd-def.h
new file mode 100644
index 0000000..44a4538
--- /dev/null
+++ b/src/include/nsss/pwd-def.h
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#ifndef NSSS_PWD_DEF_H
+#define NSSS_PWD_DEF_H
+
+#include <sys/types.h>
+
+struct passwd
+{
+  char *pw_name ;
+  char *pw_passwd ;
+  uid_t pw_uid ;
+  gid_t pw_gid ;
+  char *pw_gecos ;
+  char *pw_dir ;
+  char *pw_shell ;
+} ;
+
+#endif
diff --git a/src/include/nsss/pwd-switch.h b/src/include/nsss/pwd-switch.h
new file mode 100644
index 0000000..f9ac48c
--- /dev/null
+++ b/src/include/nsss/pwd-switch.h
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#ifndef NSSS_PWD_SWITCH_H
+#define NSSS_PWD_SWITCH_H
+
+#include <nsss/pwd-def.h>
+
+ /* Password functions contacting the nsssd daemon */
+
+extern void nsss_switch_setpwent (void) ;
+extern struct passwd *nsss_switch_getpwent (void) ;
+extern int nsss_switch_getpwent_r (struct passwd *, char *, size_t, struct passwd **) ;
+extern void nsss_switch_endpwent (void) ;
+
+extern struct passwd *nsss_switch_getpwuid (uid_t) ;
+extern int nsss_switch_getpwuid_r (uid_t, struct passwd *, char *, size_t, struct passwd **) ;
+extern struct passwd *nsss_switch_getpwnam (char const *) ;
+extern int nsss_switch_getpwnam_r (char const *, struct passwd *, char *, size_t, struct passwd **) ;
+
+#endif
diff --git a/src/include/nsss/pwd-unix.h b/src/include/nsss/pwd-unix.h
new file mode 100644
index 0000000..9b1d60c
--- /dev/null
+++ b/src/include/nsss/pwd-unix.h
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#ifndef NSSS_PWD_UNIX_H
+#define NSSS_PWD_UNIX_H
+
+#include <nsss/pwd-def.h>
+
+ /* /etc/passwd backend */
+
+extern void nsss_unix_setpwent (void) ;
+extern struct passwd *nsss_unix_getpwent (void) ;
+extern int nsss_unix_getpwent_r (struct passwd *, char *, size_t, struct passwd **) ;
+extern void nsss_unix_endpwent (void) ;
+
+extern struct passwd *nsss_unix_getpwuid (uid_t) ;
+extern int nsss_unix_getpwuid_r (uid_t, struct passwd *, char *, size_t, struct passwd **) ;
+extern struct passwd *nsss_unix_getpwnam (char const *) ;
+extern int nsss_unix_getpwnam_r (char const *, struct passwd *, char *, size_t, struct passwd **) ;
+
+#endif
diff --git a/src/include/nsss/pwd.h b/src/include/nsss/pwd.h
new file mode 100644
index 0000000..950a5ce
--- /dev/null
+++ b/src/include/nsss/pwd.h
@@ -0,0 +1,58 @@
+/* ISC license. */
+
+#ifndef NSSS_PWD_H
+#define NSSS_PWD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef NSSS_DISABLE_SWITCH
+
+#include <nsss/pwd-unix.h>
+
+#define setpwent nsss_unix_setpwent
+#define getpwent nsss_unix_getpwent
+#define getpwent_r nsss_unix_getpwent_r
+#define endpwent nsss_unix_endpwent
+#define getpwuid nsss_unix_getpwuid
+#define getpwuid_r nsss_unix_getpwuid_r
+#define getpwnam nsss_unix_getpwnam
+#define getpwnam_r nsss_unix_getpwnam_r
+
+#else
+#ifdef NSSS_DISABLE_UNIX
+
+#include <nsss/pwd-switch.h>
+
+#define setpwent nsss_switch_setpwent
+#define getpwent nsss_switch_getpwent
+#define getpwent_r nsss_switch_getpwent_r
+#define endpwent nsss_switch_endpwent
+#define getpwuid nsss_switch_getpwuid
+#define getpwuid_r nsss_switch_getpwuid_r
+#define getpwnam nsss_switch_getpwnam
+#define getpwnam_r nsss_switch_getpwnam_r
+
+#else
+
+#include <nsss/pwd-all.h>
+
+#define setpwent nsss_all_setpwent
+#define getpwent nsss_all_getpwent
+#define getpwent_r nsss_all_getpwent_r
+#define endpwent nsss_all_endpwent
+#define getpwuid nsss_all_getpwuid
+#define getpwuid_r nsss_all_getpwuid_r
+#define getpwnam nsss_all_getpwnam
+#define getpwnam_r nsss_all_getpwnam_r
+
+#endif
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/include/nsss/shadow-all.h b/src/include/nsss/shadow-all.h
new file mode 100644
index 0000000..09da550
--- /dev/null
+++ b/src/include/nsss/shadow-all.h
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#ifndef NSSS_SHADOW_ALL_H
+#define NSSS_SHADOW_ALL_H
+
+#include <nsss/shadow-def.h>
+
+/* switch then fallback on unix */
+
+extern void nsss_all_setspent (void) ;
+extern struct spwd *nsss_all_getspent (void) ;
+extern int nsss_all_getspent_r (struct spwd *, char *, size_t, struct spwd **) ;
+extern void nsss_all_endspent (void) ;
+
+extern struct spwd *nsss_all_getspnam (char const *) ;
+extern int nsss_all_getspnam_r (char const *, struct spwd *, char *, size_t, struct spwd **) ;
+
+#endif
diff --git a/src/include/nsss/shadow-def.h b/src/include/nsss/shadow-def.h
new file mode 100644
index 0000000..7b73b95
--- /dev/null
+++ b/src/include/nsss/shadow-def.h
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#ifndef NSSS_SHADOW_DEF_H
+#define NSSS_SHADOW_DEF_H
+
+#include <sys/types.h>
+
+struct spwd
+{
+  char *sp_namp ;
+  char *sp_pwdp ;
+  long sp_lstchg ;
+  long sp_min ;
+  long sp_max ;
+  long sp_warn ;
+  long sp_inact ;
+  long sp_expire ;
+  unsigned long sp_flag ;
+} ;
+
+#endif
diff --git a/src/include/nsss/shadow-switch.h b/src/include/nsss/shadow-switch.h
new file mode 100644
index 0000000..0126125
--- /dev/null
+++ b/src/include/nsss/shadow-switch.h
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#ifndef NSSS_SHADOW_SWITCH_H
+#define NSSS_SHADOW_SWITCH_H
+
+#include <nsss/shadow-def.h>
+
+ /* Shadow functions contacting the nsssd daemon */
+
+extern void nsss_switch_setspent (void) ;
+extern struct spwd *nsss_switch_getspent (void) ;
+extern int nsss_switch_getspent_r (struct spwd *, char *, size_t, struct spwd **) ;
+extern void nsss_switch_endspent (void) ;
+
+extern struct spwd *nsss_switch_getspnam (char const *) ;
+extern int nsss_switch_getspnam_r (char const *, struct spwd *, char *, size_t, struct spwd **) ;
+
+#endif
diff --git a/src/include/nsss/shadow-unix.h b/src/include/nsss/shadow-unix.h
new file mode 100644
index 0000000..6b7a111
--- /dev/null
+++ b/src/include/nsss/shadow-unix.h
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#ifndef NSSS_SHADOW_UNIX_H
+#define NSSS_SHADOW_UNIX_H
+
+#include <nsss/shadow-def.h>
+
+ /* /etc/shadow functions */
+
+extern void nsss_unix_setspent (void) ;
+extern struct spwd *nsss_unix_getspent (void) ;
+extern int nsss_unix_getspent_r (struct spwd *, char *, size_t, struct spwd **) ;
+extern void nsss_unix_endspent (void) ;
+
+extern struct spwd *nsss_unix_getspnam (char const *) ;
+extern int nsss_unix_getspnam_r (char const *, struct spwd *, char *, size_t, struct spwd **) ;
+
+#endif
diff --git a/src/include/nsss/shadow.h b/src/include/nsss/shadow.h
new file mode 100644
index 0000000..c3357fd
--- /dev/null
+++ b/src/include/nsss/shadow.h
@@ -0,0 +1,52 @@
+/* ISC license. */
+
+#ifndef NSSS_SHADOW_H
+#define NSSS_SHADOW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef NSSS_DISABLE_SWITCH
+
+#include <nsss/shadow-unix.h>
+
+#define setspent nsss_unix_setspent
+#define getspent nsss_unix_getspent
+#define getspent_r nsss_unix_getspent_r
+#define endspent nsss_unix_endspent
+#define getspnam nsss_unix_getspnam
+#define getspnam_r nsss_unix_getspnam_r
+
+#else
+#ifdef NSSS_DISABLE_UNIX
+
+#include <nsss/shadow-switch.h>
+
+#define setspent nsss_switch_setspent
+#define getspent nsss_switch_getspent
+#define getspent_r nsss_switch_getspent_r
+#define endspent nsss_switch_endspent
+#define getspnam nsss_switch_getspnam
+#define getspnam_r nsss_switch_getspnam_r
+
+#else
+
+#include <nsss/shadow-all.h>
+
+#define setspent nsss_all_setspent
+#define getspent nsss_all_getspent
+#define getspent_r nsss_all_getspent_r
+#define endspent nsss_all_endspent
+#define getspnam nsss_all_getspnam
+#define getspnam_r nsss_all_getspnam_r
+
+#endif
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/include/pwd.h b/src/include/pwd.h
new file mode 100644
index 0000000..6ad4faf
--- /dev/null
+++ b/src/include/pwd.h
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+/*
+  This file is part of the nsss package.
+  See https://skarnet.org/software/nsss/
+*/
+
+#ifndef PWD_H
+#define PWD_H
+
+#include <nsss/pwd.h>
+
+#ifdef _GNU_SOURCE
+#include <stdio.h>
+extern struct passwd *fgetpwent (FILE *) ;
+extern int fgetpwent_r (FILE *, struct passwd *, char *, size_t, struct passwd **) ;
+extern int putpwent (struct passwd const *, FILE *) ;
+#endif
+
+#endif
diff --git a/src/include/shadow.h b/src/include/shadow.h
new file mode 100644
index 0000000..00d1944
--- /dev/null
+++ b/src/include/shadow.h
@@ -0,0 +1,26 @@
+/* ISC license. */
+
+/*
+  This file is part of the nsss package.
+  See https://skarnet.org/software/nsss/
+*/
+
+#ifndef SHADOW_H
+#define SHADOW_H
+
+#include <nsss/shadow.h>
+
+#include <stdio.h>
+
+extern struct spwd *fgetspent (FILE *) ;
+extern struct spwd *sgetspent (char const *) ;
+extern int putspent (struct spwd const *, FILE *) ;
+extern int lckpwdf (void) ;
+extern int ulckpwdf (void) ;
+
+#ifdef _DEFAULT_SOURCE
+extern int fgetspent_r(FILE *, struct spwd *, char *, size_t, struct spwd **) ;
+extern int sgetspent_r (char const *, struct spwd *, char *, size_t, struct spwd **) ;
+#endif
+
+#endif
diff --git a/src/libnsss/deps-lib/nsss b/src/libnsss/deps-lib/nsss
new file mode 100644
index 0000000..6a51e6a
--- /dev/null
+++ b/src/libnsss/deps-lib/nsss
@@ -0,0 +1,111 @@
+nsss_all_endgrent.o
+nsss_all_endpwent.o
+nsss_all_endspent.o
+nsss_all_errno.o
+nsss_all_getgrent.o
+nsss_all_getgrent_r.o
+nsss_all_getgrgid.o
+nsss_all_getgrgid_r.o
+nsss_all_getgrnam.o
+nsss_all_getgrnam_r.o
+nsss_all_getpwent.o
+nsss_all_getpwent_r.o
+nsss_all_getpwnam.o
+nsss_all_getpwnam_r.o
+nsss_all_getpwuid.o
+nsss_all_getpwuid_r.o
+nsss_all_getspent.o
+nsss_all_getspent_r.o
+nsss_all_getspnam.o
+nsss_all_getspnam_r.o
+nsss_all_setgrent.o
+nsss_all_setpwent.o
+nsss_all_setspent.o
+nsss_grp_copy.o
+nsss_grp_here.o
+nsss_pwd_copy.o
+nsss_pwd_here.o
+nsss_shadow_copy.o
+nsss_shadow_here.o
+nsss_switch_end.o
+nsss_switch_endgrent.o
+nsss_switch_endpwent.o
+nsss_switch_endspent.o
+nsss_switch_getgrent.o
+nsss_switch_getgrent_r.o
+nsss_switch_getgrgid.o
+nsss_switch_getgrgid_r.o
+nsss_switch_getgrnam.o
+nsss_switch_getgrnam_r.o
+nsss_switch_getpwent.o
+nsss_switch_getpwent_r.o
+nsss_switch_getpwnam.o
+nsss_switch_getpwnam_r.o
+nsss_switch_getpwuid.o
+nsss_switch_getpwuid_r.o
+nsss_switch_getspent.o
+nsss_switch_getspent_r.o
+nsss_switch_getspnam.o
+nsss_switch_getspnam_r.o
+nsss_switch_grp_end.o
+nsss_switch_grp_get.o
+nsss_switch_grp_getbygid.o
+nsss_switch_grp_getbyname.o
+nsss_switch_grp_read.o
+nsss_switch_grp_rewind.o
+nsss_switch_here.o
+nsss_switch_op.o
+nsss_switch_pwd_end.o
+nsss_switch_pwd_get.o
+nsss_switch_pwd_getbyname.o
+nsss_switch_pwd_getbyuid.o
+nsss_switch_pwd_read.o
+nsss_switch_pwd_rewind.o
+nsss_switch_setgrent.o
+nsss_switch_setpwent.o
+nsss_switch_setspent.o
+nsss_switch_shadow_end.o
+nsss_switch_shadow_get.o
+nsss_switch_shadow_getbyname.o
+nsss_switch_shadow_read.o
+nsss_switch_shadow_rewind.o
+nsss_switch_start.o
+nsss_unix_end.o
+nsss_unix_endgrent.o
+nsss_unix_endpwent.o
+nsss_unix_endspent.o
+nsss_unix_field.o
+nsss_unix_getgrent.o
+nsss_unix_getgrent_r.o
+nsss_unix_getgrgid.o
+nsss_unix_getgrgid_r.o
+nsss_unix_getgrnam.o
+nsss_unix_getgrnam_r.o
+nsss_unix_getpwent.o
+nsss_unix_getpwent_r.o
+nsss_unix_getpwnam.o
+nsss_unix_getpwnam_r.o
+nsss_unix_getpwuid.o
+nsss_unix_getpwuid_r.o
+nsss_unix_getspent.o
+nsss_unix_getspent_r.o
+nsss_unix_getspnam.o
+nsss_unix_getspnam_r.o
+nsss_unix_grp_get.o
+nsss_unix_grp_getbygid.o
+nsss_unix_grp_getbyname.o
+nsss_unix_grp_here.o
+nsss_unix_maybe_start.o
+nsss_unix_pwd_get.o
+nsss_unix_pwd_getbyname.o
+nsss_unix_pwd_getbyuid.o
+nsss_unix_pwd_here.o
+nsss_unix_rewind.o
+nsss_unix_setgrent.o
+nsss_unix_setpwent.o
+nsss_unix_setspent.o
+nsss_unix_shadow_get.o
+nsss_unix_shadow_getbyname.o
+nsss_unix_shadow_here.o
+nsss_unix_start.o
+-lskarnet
diff --git a/src/libnsss/nsss-all-internal.h b/src/libnsss/nsss-all-internal.h
new file mode 100644
index 0000000..91bd552
--- /dev/null
+++ b/src/libnsss/nsss-all-internal.h
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#ifndef NSSS_ALL_INTERNAL_H
+#define NSSS_ALL_INTERNAL_H
+
+extern int nsss_all_errno ;
+
+#endif
diff --git a/src/libnsss/nsss-internal.h b/src/libnsss/nsss-internal.h
new file mode 100644
index 0000000..f9dbeb3
--- /dev/null
+++ b/src/libnsss/nsss-internal.h
@@ -0,0 +1,35 @@
+/* ISC license. */
+
+#ifndef NSSS_INTERNAL_H
+#define NSSS_INTERNAL_H
+
+#include <sys/types.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <nsss/pwd-def.h>
+#include <nsss/grp-def.h>
+#include <nsss/shadow-def.h>
+
+
+ /* Password */
+
+extern struct passwd nsss_pwd_here ;
+extern stralloc nsss_pwd_sa_here ;
+extern int nsss_pwd_copy (struct passwd *, char *, size_t, struct passwd const *, char const *, size_t) ;
+
+
+ /* Group */
+
+extern struct group nsss_grp_here ;
+extern stralloc nsss_grp_sa_here ;
+extern genalloc nsss_grp_ga_here ;
+extern int nsss_grp_copy (struct group *, char *, size_t, struct group const *, char const *, size_t, char *const *, size_t) ;
+
+
+ /* Shadow */
+
+extern struct spwd nsss_shadow_here ;
+extern stralloc nsss_shadow_sa_here ;
+extern int nsss_shadow_copy (struct spwd *, char *, size_t, struct spwd const *, char const *, size_t) ;
+
+#endif
diff --git a/src/libnsss/nsss-switch-internal.h b/src/libnsss/nsss-switch-internal.h
new file mode 100644
index 0000000..e005ffc
--- /dev/null
+++ b/src/libnsss/nsss-switch-internal.h
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#ifndef NSSS_SWITCH_INTERNAL_H
+#define NSSS_SWITCH_INTERNAL_H
+
+#include <skalibs/tai.h>
+#include <skalibs/buffer.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <nsss/pwd-def.h>
+#include <nsss/grp-def.h>
+#include <nsss/shadow-def.h>
+#include <nsss/nsss-switch.h>
+
+extern nsss_switch_t nsss_switch_here ;
+extern int nsss_switch_op (nsss_switch_t *, char, tain_t const *, tain_t *) ;
+extern int nsss_switch_pwd_read (buffer *, struct passwd *, stralloc *, tain_t const *, tain_t *) ;
+extern int nsss_switch_grp_read (buffer *, struct group *, stralloc *, genalloc *, tain_t const *, tain_t *) ;
+extern int nsss_switch_shadow_read (buffer *, struct spwd *, stralloc *, tain_t const *, tain_t *) ;
+
+#endif
diff --git a/src/libnsss/nsss-unix-internal.h b/src/libnsss/nsss-unix-internal.h
new file mode 100644
index 0000000..9413a3b
--- /dev/null
+++ b/src/libnsss/nsss-unix-internal.h
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#ifndef NSSS_UNIX_INTERNAL_H
+#define NSSS_UNIX_INTERNAL_H
+
+#include <nsss/nsss-unix.h>
+
+extern int nsss_unix_field (char **, char **) ;
+extern nsss_unix_t nsss_unix_pwd_here ;
+extern nsss_unix_t nsss_unix_grp_here ;
+extern nsss_unix_t nsss_unix_shadow_here ;
+
+#endif
diff --git a/src/libnsss/nsss_all_endgrent.c b/src/libnsss/nsss_all_endgrent.c
new file mode 100644
index 0000000..059eca4
--- /dev/null
+++ b/src/libnsss/nsss_all_endgrent.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <nsss/grp-unix.h>
+#include <nsss/grp-switch.h>
+#include <nsss/grp-all.h>
+#include "nsss-all-internal.h"
+
+void nsss_all_endgrent (void)
+{
+  if (nsss_all_errno) goto fallback ;
+  nsss_switch_endgrent() ;
+  return ;
+
+ fallback:
+  nsss_unix_endgrent() ;
+  nsss_all_errno = 0 ;
+}
diff --git a/src/libnsss/nsss_all_endpwent.c b/src/libnsss/nsss_all_endpwent.c
new file mode 100644
index 0000000..c3ce953
--- /dev/null
+++ b/src/libnsss/nsss_all_endpwent.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <nsss/pwd-unix.h>
+#include <nsss/pwd-switch.h>
+#include <nsss/pwd-all.h>
+#include "nsss-all-internal.h"
+
+void nsss_all_endpwent (void)
+{
+  if (nsss_all_errno) goto fallback ;
+  nsss_switch_endpwent() ;
+  return ;
+
+ fallback:
+  nsss_unix_endpwent() ;
+  nsss_all_errno = 0 ;
+}
diff --git a/src/libnsss/nsss_all_endspent.c b/src/libnsss/nsss_all_endspent.c
new file mode 100644
index 0000000..c5587cb
--- /dev/null
+++ b/src/libnsss/nsss_all_endspent.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <nsss/shadow-unix.h>
+#include <nsss/shadow-switch.h>
+#include <nsss/shadow-all.h>
+#include "nsss-all-internal.h"
+
+void nsss_all_endspent (void)
+{
+  if (nsss_all_errno) goto fallback ;
+  nsss_switch_endspent() ;
+  return ;
+
+ fallback:
+  nsss_unix_endspent() ;
+  nsss_all_errno = 0 ;
+}
diff --git a/src/libnsss/nsss_all_errno.c b/src/libnsss/nsss_all_errno.c
new file mode 100644
index 0000000..8c50835
--- /dev/null
+++ b/src/libnsss/nsss_all_errno.c
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#include "nsss-all-internal.h"
+
+int nsss_all_errno = 0 ;
diff --git a/src/libnsss/nsss_all_getgrent.c b/src/libnsss/nsss_all_getgrent.c
new file mode 100644
index 0000000..15b5894
--- /dev/null
+++ b/src/libnsss/nsss_all_getgrent.c
@@ -0,0 +1,28 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/genalloc.h>
+#include <nsss/config.h>
+#include <nsss/grp-unix.h>
+#include <nsss/grp-all.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+#include "nsss-switch-internal.h"
+#include "nsss-all-internal.h"
+
+struct group *nsss_all_getgrent (void)
+{
+  int e = errno ;
+  if (nsss_all_errno) goto fallback ;
+  if (!nsss_switch_start(&nsss_switch_here, NSSS_SWITCH_GRP, NSSS_NSSSD_PATH, 0, 0)) goto efallback ;
+  nsss_grp_sa_here.len = 0 ;
+  genalloc_setlen(char *, &nsss_grp_ga_here, 0) ;
+  if (!nsss_switch_grp_get(&nsss_switch_here, &nsss_grp_here, &nsss_grp_sa_here, &nsss_grp_ga_here, 0, 0)) return 0 ;
+  return &nsss_grp_here ;
+
+ efallback:
+  nsss_all_errno = errno ;
+  errno = e ;
+ fallback:
+  return nsss_unix_getgrent() ;
+}
diff --git a/src/libnsss/nsss_all_getgrent_r.c b/src/libnsss/nsss_all_getgrent_r.c
new file mode 100644
index 0000000..8cdcad6
--- /dev/null
+++ b/src/libnsss/nsss_all_getgrent_r.c
@@ -0,0 +1,44 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <nsss/config.h>
+#include <nsss/grp-unix.h>
+#include <nsss/grp-all.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+#include "nsss-switch-internal.h"
+#include "nsss-all-internal.h"
+
+int nsss_all_getgrent_r (struct group *gr, char *buf, size_t buflen, struct group **grp)
+{
+  struct group gr2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  genalloc ga = GENALLOC_ZERO ;
+  int e = errno ;
+  if (nsss_all_errno) goto fallback ;
+  if (!nsss_switch_start(&nsss_switch_here, NSSS_SWITCH_GRP, NSSS_NSSSD_PATH, 0, 0)) goto efallback ;
+  errno = 0 ;
+  if (!nsss_switch_grp_get(&nsss_switch_here, &gr2, &sa, &ga, 0, 0))
+  {
+    *grp = 0 ;
+    if (!errno) errno = ENOENT ;
+    return errno ;
+  }
+  if (!nsss_grp_copy(gr, buf, buflen, &gr2, sa.s, sa.len, genalloc_s(char *, &ga), genalloc_len(char *, &ga)))
+  {
+    stralloc_free(&sa) ;
+    *grp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *grp = gr ;
+  return (errno = e, 0) ;
+
+ efallback:
+  nsss_all_errno = errno ;
+  errno = e ;
+ fallback:
+  return nsss_unix_getgrent_r(gr, buf, buflen, grp) ;
+}
diff --git a/src/libnsss/nsss_all_getgrgid.c b/src/libnsss/nsss_all_getgrgid.c
new file mode 100644
index 0000000..da67518
--- /dev/null
+++ b/src/libnsss/nsss_all_getgrgid.c
@@ -0,0 +1,29 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/genalloc.h>
+#include <nsss/config.h>
+#include <nsss/grp-unix.h>
+#include <nsss/grp-all.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+
+struct group *nsss_all_getgrgid (gid_t gid)
+{
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  int e = errno ;
+  if (!nsss_switch_start(&a, NSSS_SWITCH_GRP, NSSS_NSSSD_PATH, 0, 0)) goto fallback ;
+  nsss_grp_sa_here.len = 0 ;
+  genalloc_setlen(char *, &nsss_grp_ga_here, 0) ;
+  if (!nsss_switch_grp_getbygid(&a, &nsss_grp_here, &nsss_grp_sa_here, &nsss_grp_ga_here, gid, 0, 0))
+  {
+    nsss_switch_end(&a, NSSS_SWITCH_GRP) ;
+    return 0 ;
+  }
+  nsss_switch_end(&a, NSSS_SWITCH_GRP) ;
+  return &nsss_grp_here ;
+
+ fallback:
+  errno = e ;
+  return nsss_unix_getgrgid(gid) ;
+}
diff --git a/src/libnsss/nsss_all_getgrgid_r.c b/src/libnsss/nsss_all_getgrgid_r.c
new file mode 100644
index 0000000..bd48322
--- /dev/null
+++ b/src/libnsss/nsss_all_getgrgid_r.c
@@ -0,0 +1,41 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <nsss/config.h>
+#include <nsss/grp-unix.h>
+#include <nsss/grp-all.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+
+int nsss_all_getgrgid_r (gid_t gid, struct group *gr, char *buf, size_t buflen, struct group **grp)
+{
+  struct group gr2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  genalloc ga = GENALLOC_ZERO ;
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  int e = errno ;
+  if (!nsss_switch_start(&a, NSSS_SWITCH_GRP, NSSS_NSSSD_PATH, 0, 0)) goto fallback ;
+  errno = 0 ;
+  if (!nsss_switch_grp_getbygid(&a, &gr2, &sa, &ga, gid, 0, 0))
+  {
+    nsss_switch_end(&a, NSSS_SWITCH_GRP) ;
+    *grp = 0 ;
+    return errno ? errno : (errno = e, 0) ;
+  }
+  nsss_switch_end(&a, NSSS_SWITCH_GRP) ;
+  if (!nsss_grp_copy(gr, buf, buflen, &gr2, sa.s, sa.len, genalloc_s(char *, &ga), genalloc_len(char *, &ga)))
+  {
+    stralloc_free(&sa) ;
+    *grp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *grp = gr ;
+  return (errno = e, 0) ;
+
+ fallback:
+  errno = e ;
+  return nsss_unix_getgrgid_r(gid, gr, buf, buflen, grp) ;
+}
diff --git a/src/libnsss/nsss_all_getgrnam.c b/src/libnsss/nsss_all_getgrnam.c
new file mode 100644
index 0000000..a729bff
--- /dev/null
+++ b/src/libnsss/nsss_all_getgrnam.c
@@ -0,0 +1,29 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/genalloc.h>
+#include <nsss/config.h>
+#include <nsss/grp-unix.h>
+#include <nsss/grp-all.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+
+struct group *nsss_all_getgrnam (char const *name)
+{
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  int e = errno ;
+  if (!nsss_switch_start(&a, NSSS_SWITCH_GRP, NSSS_NSSSD_PATH, 0, 0)) goto fallback ;
+  nsss_grp_sa_here.len = 0 ;
+  genalloc_setlen(char *, &nsss_grp_ga_here, 0) ;
+  if (!nsss_switch_grp_getbyname(&a, &nsss_grp_here, &nsss_grp_sa_here, &nsss_grp_ga_here, name, 0, 0))
+  {
+    nsss_switch_end(&a, NSSS_SWITCH_GRP) ;
+    return 0 ;
+  }
+  nsss_switch_end(&a, NSSS_SWITCH_GRP) ;
+  return &nsss_grp_here ;
+
+ fallback:
+  errno = e ;
+  return nsss_unix_getgrnam(name) ;
+}
diff --git a/src/libnsss/nsss_all_getgrnam_r.c b/src/libnsss/nsss_all_getgrnam_r.c
new file mode 100644
index 0000000..d129d3c
--- /dev/null
+++ b/src/libnsss/nsss_all_getgrnam_r.c
@@ -0,0 +1,41 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <nsss/config.h>
+#include <nsss/grp-unix.h>
+#include <nsss/grp-all.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+
+int nsss_all_getgrnam_r (char const *name, struct group *gr, char *buf, size_t buflen, struct group **grp)
+{
+  struct group gr2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  genalloc ga = GENALLOC_ZERO ;
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  int e = errno ;
+  if (!nsss_switch_start(&a, NSSS_SWITCH_GRP, NSSS_NSSSD_PATH, 0, 0)) goto fallback ;
+  errno = 0 ;
+  if (!nsss_switch_grp_getbyname(&a, &gr2, &sa, &ga, name, 0, 0))
+  {
+    nsss_switch_end(&a, NSSS_SWITCH_GRP) ;
+    *grp = 0 ;
+    return errno ? errno : (errno = e, 0) ;
+  }
+  nsss_switch_end(&a, NSSS_SWITCH_GRP) ;
+  if (!nsss_grp_copy(gr, buf, buflen, &gr2, sa.s, sa.len, genalloc_s(char *, &ga), genalloc_len(char *, &ga)))
+  {
+    stralloc_free(&sa) ;
+    *grp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *grp = gr ;
+  return (errno = e, 0) ;
+
+ fallback:
+  errno = e ;
+  return nsss_unix_getgrnam_r(name, gr, buf, buflen, grp) ;
+}
diff --git a/src/libnsss/nsss_all_getpwent.c b/src/libnsss/nsss_all_getpwent.c
new file mode 100644
index 0000000..b68a4b3
--- /dev/null
+++ b/src/libnsss/nsss_all_getpwent.c
@@ -0,0 +1,26 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <nsss/config.h>
+#include <nsss/pwd-unix.h>
+#include <nsss/pwd-all.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+#include "nsss-switch-internal.h"
+#include "nsss-all-internal.h"
+
+struct passwd *nsss_all_getpwent (void)
+{
+  int e = errno ;
+  if (nsss_all_errno) goto fallback ;
+  if (!nsss_switch_start(&nsss_switch_here, NSSS_SWITCH_PWD, NSSS_NSSSD_PATH, 0, 0)) goto efallback ;
+  nsss_pwd_sa_here.len = 0 ;
+  if (!nsss_switch_pwd_get(&nsss_switch_here, &nsss_pwd_here, &nsss_pwd_sa_here, 0, 0)) return 0 ;
+  return &nsss_pwd_here ;
+
+ efallback:
+  nsss_all_errno = errno ;
+  errno = e ;
+ fallback:
+  return nsss_unix_getpwent() ;
+}
diff --git a/src/libnsss/nsss_all_getpwent_r.c b/src/libnsss/nsss_all_getpwent_r.c
new file mode 100644
index 0000000..08e69dc
--- /dev/null
+++ b/src/libnsss/nsss_all_getpwent_r.c
@@ -0,0 +1,42 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <nsss/config.h>
+#include <nsss/pwd-unix.h>
+#include <nsss/pwd-all.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+#include "nsss-switch-internal.h"
+#include "nsss-all-internal.h"
+
+int nsss_all_getpwent_r (struct passwd *pw, char *buf, size_t buflen, struct passwd **pwp)
+{
+  struct passwd pw2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  int e = errno ;
+  if (nsss_all_errno) goto fallback ;
+  if (!nsss_switch_start(&nsss_switch_here, NSSS_SWITCH_PWD, NSSS_NSSSD_PATH, 0, 0)) goto efallback ;
+  errno = 0 ;
+  if (!nsss_switch_pwd_get(&nsss_switch_here, &pw2, &sa, 0, 0))
+  {
+    *pwp = 0 ;
+    if (!errno) errno = ENOENT ;
+    return errno ;
+  }
+  if (!nsss_pwd_copy(pw, buf, buflen, &pw2, sa.s, sa.len))
+  {
+    stralloc_free(&sa) ;
+    *pwp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *pwp = pw ;
+  return (errno = e, 0) ;
+
+ efallback:
+  nsss_all_errno = errno ;
+  errno = e ;
+ fallback:
+  return nsss_unix_getpwent_r(pw, buf, buflen, pwp) ;
+}
diff --git a/src/libnsss/nsss_all_getpwnam.c b/src/libnsss/nsss_all_getpwnam.c
new file mode 100644
index 0000000..db855d7
--- /dev/null
+++ b/src/libnsss/nsss_all_getpwnam.c
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <nsss/config.h>
+#include <nsss/pwd-unix.h>
+#include <nsss/pwd-all.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+
+struct passwd *nsss_all_getpwnam (char const *name)
+{
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  int e = errno ;
+  if (!nsss_switch_start(&a, NSSS_SWITCH_PWD, NSSS_NSSSD_PATH, 0, 0)) goto fallback ;
+  nsss_pwd_sa_here.len = 0 ;
+  if (!nsss_switch_pwd_getbyname(&a, &nsss_pwd_here, &nsss_pwd_sa_here, name, 0, 0))
+  {
+    nsss_switch_end(&a, NSSS_SWITCH_PWD) ;
+    return 0 ;
+  }
+  nsss_switch_end(&a, NSSS_SWITCH_PWD) ;
+  return &nsss_pwd_here ;
+
+ fallback:
+  errno = e ;
+  return nsss_unix_getpwnam(name) ;
+}
diff --git a/src/libnsss/nsss_all_getpwnam_r.c b/src/libnsss/nsss_all_getpwnam_r.c
new file mode 100644
index 0000000..e3169b1
--- /dev/null
+++ b/src/libnsss/nsss_all_getpwnam_r.c
@@ -0,0 +1,39 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <nsss/config.h>
+#include <nsss/pwd-unix.h>
+#include <nsss/pwd-all.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+
+int nsss_all_getpwnam_r (char const *name, struct passwd *pw, char *buf, size_t buflen, struct passwd **pwp)
+{
+  struct passwd pw2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  int e = errno ;
+  if (!nsss_switch_start(&a, NSSS_SWITCH_PWD, NSSS_NSSSD_PATH, 0, 0)) goto fallback ;
+  errno = 0 ;
+  if (!nsss_switch_pwd_getbyname(&a, &pw2, &sa, name, 0, 0))
+  {
+    nsss_switch_end(&a, NSSS_SWITCH_PWD) ;
+    *pwp = 0 ;
+    return errno ? errno : (errno = e, 0) ;
+  }
+  nsss_switch_end(&a, NSSS_SWITCH_PWD) ;
+  if (!nsss_pwd_copy(pw, buf, buflen, &pw2, sa.s, sa.len))
+  {
+    stralloc_free(&sa) ;
+    *pwp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *pwp = pw ;
+  return (errno = e, 0) ;
+
+ fallback:
+  errno = e ;
+  return nsss_unix_getpwnam_r(name, pw, buf, buflen, pwp) ;
+}
diff --git a/src/libnsss/nsss_all_getpwuid.c b/src/libnsss/nsss_all_getpwuid.c
new file mode 100644
index 0000000..26f0e21
--- /dev/null
+++ b/src/libnsss/nsss_all_getpwuid.c
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <nsss/config.h>
+#include <nsss/pwd-unix.h>
+#include <nsss/pwd-all.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+
+struct passwd *nsss_all_getpwuid (uid_t uid)
+{
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  int e = errno ;
+  if (!nsss_switch_start(&a, NSSS_SWITCH_PWD, NSSS_NSSSD_PATH, 0, 0)) goto fallback ;
+  nsss_pwd_sa_here.len = 0 ;
+  if (!nsss_switch_pwd_getbyuid(&a, &nsss_pwd_here, &nsss_pwd_sa_here, uid, 0, 0))
+  {
+    nsss_switch_end(&a, NSSS_SWITCH_PWD) ;
+    return 0 ;
+  }
+  nsss_switch_end(&a, NSSS_SWITCH_PWD) ;
+  return &nsss_pwd_here ;
+
+ fallback:
+  errno = e ;
+  return nsss_unix_getpwuid(uid) ;
+}
diff --git a/src/libnsss/nsss_all_getpwuid_r.c b/src/libnsss/nsss_all_getpwuid_r.c
new file mode 100644
index 0000000..2da32e1
--- /dev/null
+++ b/src/libnsss/nsss_all_getpwuid_r.c
@@ -0,0 +1,39 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <nsss/config.h>
+#include <nsss/pwd-unix.h>
+#include <nsss/pwd-all.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+
+int nsss_all_getpwuid_r (uid_t uid, struct passwd *pw, char *buf, size_t buflen, struct passwd **pwp)
+{
+  struct passwd pw2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  int e = errno ;
+  if (!nsss_switch_start(&a, NSSS_SWITCH_PWD, NSSS_NSSSD_PATH, 0, 0)) goto fallback ;
+  errno = 0 ;
+  if (!nsss_switch_pwd_getbyuid(&a, &pw2, &sa, uid, 0, 0))
+  {
+    nsss_switch_end(&a, NSSS_SWITCH_PWD) ;
+    *pwp = 0 ;
+    return errno ? errno : (errno = e, 0) ;
+  }
+  nsss_switch_end(&a, NSSS_SWITCH_PWD) ;
+  if (!nsss_pwd_copy(pw, buf, buflen, &pw2, sa.s, sa.len))
+  {
+    stralloc_free(&sa) ;
+    *pwp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *pwp = pw ;
+  return (errno = e, 0) ;
+
+ fallback:
+  errno = e ;
+  return nsss_unix_getpwuid_r(uid, pw, buf, buflen, pwp) ;
+}
diff --git a/src/libnsss/nsss_all_getspent.c b/src/libnsss/nsss_all_getspent.c
new file mode 100644
index 0000000..7ca5048
--- /dev/null
+++ b/src/libnsss/nsss_all_getspent.c
@@ -0,0 +1,26 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <nsss/config.h>
+#include <nsss/shadow-unix.h>
+#include <nsss/shadow-all.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+#include "nsss-switch-internal.h"
+#include "nsss-all-internal.h"
+
+struct spwd *nsss_all_getspent (void)
+{
+  int e = errno ;
+  if (nsss_all_errno) goto fallback ;
+  if (!nsss_switch_start(&nsss_switch_here, NSSS_SWITCH_SHADOW, NSSS_NSSSD_PATH, 0, 0)) goto efallback ;
+  nsss_shadow_sa_here.len = 0 ;
+  if (!nsss_switch_shadow_get(&nsss_switch_here, &nsss_shadow_here, &nsss_shadow_sa_here, 0, 0)) return 0 ;
+  return &nsss_shadow_here ;
+
+ efallback:
+  nsss_all_errno = errno ;
+  errno = e ;
+ fallback:
+  return nsss_unix_getspent() ;
+}
diff --git a/src/libnsss/nsss_all_getspent_r.c b/src/libnsss/nsss_all_getspent_r.c
new file mode 100644
index 0000000..ab3e531
--- /dev/null
+++ b/src/libnsss/nsss_all_getspent_r.c
@@ -0,0 +1,42 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <nsss/config.h>
+#include <nsss/shadow-unix.h>
+#include <nsss/shadow-all.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+#include "nsss-switch-internal.h"
+#include "nsss-all-internal.h"
+
+int nsss_all_getspent_r (struct spwd *sp, char *buf, size_t buflen, struct spwd **spp)
+{
+  struct spwd sp2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  int e = errno ;
+  if (nsss_all_errno) goto fallback ;
+  if (!nsss_switch_start(&nsss_switch_here, NSSS_SWITCH_SHADOW, NSSS_NSSSD_PATH, 0, 0)) goto efallback ;
+  errno = 0 ;
+  if (!nsss_switch_shadow_get(&nsss_switch_here, &sp2, &sa, 0, 0))
+  {
+    *spp = 0 ;
+    if (!errno) errno = ENOENT ;
+    return errno ;
+  }
+  if (!nsss_shadow_copy(sp, buf, buflen, &sp2, sa.s, sa.len))
+  {
+    stralloc_free(&sa) ;
+    *spp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *spp = sp ;
+  return (errno = e, 0) ;
+
+ efallback:
+  nsss_all_errno = errno ;
+  errno = e ;
+ fallback:
+  return nsss_unix_getspent_r(sp, buf, buflen, spp) ;
+}
diff --git a/src/libnsss/nsss_all_getspnam.c b/src/libnsss/nsss_all_getspnam.c
new file mode 100644
index 0000000..040d5e4
--- /dev/null
+++ b/src/libnsss/nsss_all_getspnam.c
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <nsss/config.h>
+#include <nsss/shadow-unix.h>
+#include <nsss/shadow-all.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+
+struct spwd *nsss_all_getspnam (char const *name)
+{
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  int e = errno ;
+  if (!nsss_switch_start(&a, NSSS_SWITCH_SHADOW, NSSS_NSSSD_PATH, 0, 0)) goto fallback ;
+  nsss_shadow_sa_here.len = 0 ;
+  if (!nsss_switch_shadow_getbyname(&a, &nsss_shadow_here, &nsss_shadow_sa_here, name, 0, 0))
+  {
+    nsss_switch_end(&a, NSSS_SWITCH_SHADOW) ;
+    return 0 ;
+  }
+  nsss_switch_end(&a, NSSS_SWITCH_SHADOW) ;
+  return &nsss_shadow_here ;
+
+ fallback:
+  errno = e ;
+  return nsss_unix_getspnam(name) ;
+}
diff --git a/src/libnsss/nsss_all_getspnam_r.c b/src/libnsss/nsss_all_getspnam_r.c
new file mode 100644
index 0000000..0cee461
--- /dev/null
+++ b/src/libnsss/nsss_all_getspnam_r.c
@@ -0,0 +1,39 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <nsss/config.h>
+#include <nsss/shadow-unix.h>
+#include <nsss/shadow-all.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+
+int nsss_all_getspnam_r (char const *name, struct spwd *sp, char *buf, size_t buflen, struct spwd **spp)
+{
+  struct spwd sp2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  int e = errno ;
+  if (!nsss_switch_start(&a, NSSS_SWITCH_SHADOW, NSSS_NSSSD_PATH, 0, 0)) goto fallback ;
+  errno = 0 ;
+  if (!nsss_switch_shadow_getbyname(&a, &sp2, &sa, name, 0, 0))
+  {
+    nsss_switch_end(&a, NSSS_SWITCH_SHADOW) ;
+    *spp = 0 ;
+    return errno ? errno : (errno = e, 0) ;
+  }
+  nsss_switch_end(&a, NSSS_SWITCH_SHADOW) ;
+  if (!nsss_shadow_copy(sp, buf, buflen, &sp2, sa.s, sa.len))
+  {
+    stralloc_free(&sa) ;
+    *spp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *spp = sp ;
+  return (errno = e, 0) ;
+
+ fallback:
+  errno = e ;
+  return nsss_unix_getspnam_r(name, sp, buf, buflen, spp) ;
+}
diff --git a/src/libnsss/nsss_all_setgrent.c b/src/libnsss/nsss_all_setgrent.c
new file mode 100644
index 0000000..78fee56
--- /dev/null
+++ b/src/libnsss/nsss_all_setgrent.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <nsss/config.h>
+#include <nsss/grp-unix.h>
+#include <nsss/grp-all.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+#include "nsss-all-internal.h"
+
+void nsss_all_setgrent (void)
+{
+  int e = errno ;
+  if (!nsss_switch_start(&nsss_switch_here, NSSS_SWITCH_GRP, NSSS_NSSSD_PATH, 0, 0)) goto fallback ;
+  nsss_switch_grp_rewind(&nsss_switch_here, 0, 0) ;
+  return ;
+
+ fallback:
+  nsss_all_errno = errno ;
+  errno = e ;
+  nsss_unix_setgrent() ;
+}
diff --git a/src/libnsss/nsss_all_setpwent.c b/src/libnsss/nsss_all_setpwent.c
new file mode 100644
index 0000000..e22411a
--- /dev/null
+++ b/src/libnsss/nsss_all_setpwent.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <nsss/config.h>
+#include <nsss/pwd-unix.h>
+#include <nsss/pwd-all.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+#include "nsss-all-internal.h"
+
+void nsss_all_setpwent (void)
+{
+  int e = errno ;
+  if (!nsss_switch_start(&nsss_switch_here, NSSS_SWITCH_PWD, NSSS_NSSSD_PATH, 0, 0)) goto fallback ;
+  nsss_switch_pwd_rewind(&nsss_switch_here, 0, 0) ;
+  return ;
+
+ fallback:
+  nsss_all_errno = errno ;
+  errno = e ;
+  nsss_unix_setpwent() ;
+}
diff --git a/src/libnsss/nsss_all_setspent.c b/src/libnsss/nsss_all_setspent.c
new file mode 100644
index 0000000..ab6c456
--- /dev/null
+++ b/src/libnsss/nsss_all_setspent.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <nsss/config.h>
+#include <nsss/shadow-unix.h>
+#include <nsss/shadow-all.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+#include "nsss-all-internal.h"
+
+void nsss_all_setspent (void)
+{
+  int e = errno ;
+  if (!nsss_switch_start(&nsss_switch_here, NSSS_SWITCH_SHADOW, NSSS_NSSSD_PATH, 0, 0)) goto fallback ;
+  nsss_switch_shadow_rewind(&nsss_switch_here, 0, 0) ;
+  return ;
+
+ fallback:
+  nsss_all_errno = errno ;
+  errno = e ;
+  nsss_unix_setspent() ;
+}
diff --git a/src/libnsss/nsss_grp_copy.c b/src/libnsss/nsss_grp_copy.c
new file mode 100644
index 0000000..684996e
--- /dev/null
+++ b/src/libnsss/nsss_grp_copy.c
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include "nsss-internal.h"
+
+int nsss_grp_copy (struct group *gr, char *buf, size_t buflen, struct group const *gr2, char const *s, size_t len, char *const *p, size_t n)
+{
+  char **q ;
+  size_t offset = (uintptr_t)buf % 16 ;
+  offset = offset ? 16 - offset : 0 ;
+  if (buflen < offset) return (errno = ERANGE, 0) ;
+  buf += offset ; buflen -= offset ;
+  offset = (n+1) * sizeof(char *) ;
+  if (buflen < offset || buflen - offset < len) return (errno = ERANGE, 0) ;
+  q = (char **)buf ;
+  gr->gr_mem = q ;
+  buf += offset ;
+  memcpy(buf, s, len) ;
+  for (size_t i = 0 ; i < n ; i++) q[i] = buf + (p[i] - s) ;
+  q[n] = 0 ;
+  gr->gr_name = buf + (gr2->gr_name - s) ;
+  gr->gr_passwd = buf + (gr2->gr_passwd - s) ;
+  gr->gr_gid = gr2->gr_gid ;
+  return 1 ;
+}
diff --git a/src/libnsss/nsss_grp_here.c b/src/libnsss/nsss_grp_here.c
new file mode 100644
index 0000000..9b64ffd
--- /dev/null
+++ b/src/libnsss/nsss_grp_here.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <nsss/grp-def.h>
+#include "nsss-internal.h"
+
+struct group nsss_grp_here ;
+stralloc nsss_grp_sa_here = STRALLOC_ZERO ;
+genalloc nsss_grp_ga_here = GENALLOC_ZERO ;
diff --git a/src/libnsss/nsss_pwd_copy.c b/src/libnsss/nsss_pwd_copy.c
new file mode 100644
index 0000000..e163cf2
--- /dev/null
+++ b/src/libnsss/nsss_pwd_copy.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <string.h>
+#include <errno.h>
+#include "nsss-internal.h"
+
+int nsss_pwd_copy (struct passwd *pw, char *buf, size_t buflen, struct passwd const *pw2, char const *s, size_t len)
+{
+  if (len > buflen) return (errno = ERANGE, 0) ;
+  memcpy(buf, s, len) ;
+  pw->pw_name = buf + (pw2->pw_name - s) ;
+  pw->pw_passwd = buf + (pw2->pw_passwd - s) ;
+  pw->pw_uid = pw2->pw_uid ;
+  pw->pw_gid = pw2->pw_gid ;
+  pw->pw_gecos = buf + (pw2->pw_gecos - s) ;
+  pw->pw_dir = buf + (pw2->pw_dir - s) ;
+  pw->pw_shell = buf + (pw2->pw_shell - s) ;
+  return 1 ;
+}
diff --git a/src/libnsss/nsss_pwd_here.c b/src/libnsss/nsss_pwd_here.c
new file mode 100644
index 0000000..fdb95a4
--- /dev/null
+++ b/src/libnsss/nsss_pwd_here.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+#include <nsss/pwd-def.h>
+#include "nsss-internal.h"
+
+struct passwd nsss_pwd_here ;
+stralloc nsss_pwd_sa_here = STRALLOC_ZERO ;
diff --git a/src/libnsss/nsss_shadow_copy.c b/src/libnsss/nsss_shadow_copy.c
new file mode 100644
index 0000000..bb629db
--- /dev/null
+++ b/src/libnsss/nsss_shadow_copy.c
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#include <string.h>
+#include <errno.h>
+#include "nsss-internal.h"
+
+int nsss_shadow_copy (struct spwd *sp, char *buf, size_t buflen, struct spwd const *sp2, char const *s, size_t len)
+{
+  if (len > buflen) return (errno = ERANGE, 0) ;
+  memcpy(buf, s, len) ;
+  sp->sp_namp = buf + (sp2->sp_namp - s) ;
+  sp->sp_pwdp = buf + (sp2->sp_pwdp - s) ;
+  sp->sp_lstchg = sp2->sp_lstchg ;
+  sp->sp_min = sp2->sp_min ;
+  sp->sp_max = sp2->sp_max ;
+  sp->sp_warn = sp2->sp_warn ;
+  sp->sp_inact = sp2->sp_inact ;
+  sp->sp_expire = sp2->sp_expire ;
+  sp->sp_flag = sp2->sp_flag ;
+  return 1 ;
+}
diff --git a/src/libnsss/nsss_shadow_here.c b/src/libnsss/nsss_shadow_here.c
new file mode 100644
index 0000000..ecf83c9
--- /dev/null
+++ b/src/libnsss/nsss_shadow_here.c
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#include <skalibs/stralloc.h>
+#include <nsss/shadow-def.h>
+#include "nsss-internal.h"
+
+struct spwd nsss_shadow_here ;
+stralloc nsss_shadow_sa_here = STRALLOC_ZERO ;
diff --git a/src/libnsss/nsss_switch_end.c b/src/libnsss/nsss_switch_end.c
new file mode 100644
index 0000000..3922721
--- /dev/null
+++ b/src/libnsss/nsss_switch_end.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+#include <skalibs/djbunix.h>
+#include <nsss/nsss-switch.h>
+
+static inline void nsss_switch_disconnect (nsss_switch_t *a)
+{
+  fd_close(buffer_fd(&a->b)) ;
+  a->b.fd = -1 ;
+}
+
+void nsss_switch_end (nsss_switch_t *a, unsigned int what)
+{
+  a->held &= ~(1U << what) ;
+  if (!a->held) nsss_switch_disconnect(a) ;
+}
diff --git a/src/libnsss/nsss_switch_endgrent.c b/src/libnsss/nsss_switch_endgrent.c
new file mode 100644
index 0000000..8ae43ea
--- /dev/null
+++ b/src/libnsss/nsss_switch_endgrent.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <nsss/grp-switch.h>
+#include "nsss-switch-internal.h"
+
+void nsss_switch_endgrent (void)
+{
+  nsss_switch_grp_end(&nsss_switch_here, 0, 0) ;
+  nsss_switch_end(&nsss_switch_here, NSSS_SWITCH_GRP) ;
+}
diff --git a/src/libnsss/nsss_switch_endpwent.c b/src/libnsss/nsss_switch_endpwent.c
new file mode 100644
index 0000000..8dbec92
--- /dev/null
+++ b/src/libnsss/nsss_switch_endpwent.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <nsss/pwd-switch.h>
+#include "nsss-switch-internal.h"
+
+void nsss_switch_endpwent (void)
+{
+  nsss_switch_pwd_end(&nsss_switch_here, 0, 0) ;
+  nsss_switch_end(&nsss_switch_here, NSSS_SWITCH_PWD) ;
+}
diff --git a/src/libnsss/nsss_switch_endspent.c b/src/libnsss/nsss_switch_endspent.c
new file mode 100644
index 0000000..8527072
--- /dev/null
+++ b/src/libnsss/nsss_switch_endspent.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <nsss/shadow-switch.h>
+#include "nsss-switch-internal.h"
+
+void nsss_switch_endspent (void)
+{
+  nsss_switch_shadow_end(&nsss_switch_here, 0, 0) ;
+  nsss_switch_end(&nsss_switch_here, NSSS_SWITCH_SHADOW) ;
+}
diff --git a/src/libnsss/nsss_switch_getgrent.c b/src/libnsss/nsss_switch_getgrent.c
new file mode 100644
index 0000000..6a6c8dc
--- /dev/null
+++ b/src/libnsss/nsss_switch_getgrent.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/genalloc.h>
+#include <nsss/config.h>
+#include <nsss/grp-switch.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+#include "nsss-switch-internal.h"
+
+struct group *nsss_switch_getgrent (void)
+{
+  if (!nsss_switch_start(&nsss_switch_here, NSSS_SWITCH_GRP, NSSS_NSSSD_PATH, 0, 0)) return 0 ;
+  nsss_grp_sa_here.len = 0 ;
+  genalloc_setlen(char *, &nsss_grp_ga_here, 0) ;
+  if (!nsss_switch_grp_get(&nsss_switch_here, &nsss_grp_here, &nsss_grp_sa_here, &nsss_grp_ga_here, 0, 0)) return 0 ;
+  return &nsss_grp_here ;
+}
diff --git a/src/libnsss/nsss_switch_getgrent_r.c b/src/libnsss/nsss_switch_getgrent_r.c
new file mode 100644
index 0000000..97a7bbd
--- /dev/null
+++ b/src/libnsss/nsss_switch_getgrent_r.c
@@ -0,0 +1,36 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <nsss/config.h>
+#include <nsss/grp-switch.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+#include "nsss-switch-internal.h"
+
+int nsss_switch_getgrent_r (struct group *gr, char *buf, size_t buflen, struct group **grp)
+{
+  struct group gr2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  genalloc ga = GENALLOC_ZERO ;
+  int e ;
+  if (!nsss_switch_start(&nsss_switch_here, NSSS_SWITCH_GRP, NSSS_NSSSD_PATH, 0, 0)) return errno ;
+  e = errno ;
+  errno = 0 ;
+  if (!nsss_switch_grp_get(&nsss_switch_here, &gr2, &sa, &ga, 0, 0))
+  {
+    *grp = 0 ;
+    if (!errno) errno = ENOENT ;
+    return errno ;
+  }
+  if (!nsss_grp_copy(gr, buf, buflen, &gr2, sa.s, sa.len, genalloc_s(char *, &ga), genalloc_len(char *, &ga)))
+  {
+    stralloc_free(&sa) ;
+    *grp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *grp = gr ;
+  return (errno = e, 0) ;
+}
diff --git a/src/libnsss/nsss_switch_getgrgid.c b/src/libnsss/nsss_switch_getgrgid.c
new file mode 100644
index 0000000..65dbeef
--- /dev/null
+++ b/src/libnsss/nsss_switch_getgrgid.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <skalibs/genalloc.h>
+#include <nsss/config.h>
+#include <nsss/grp-switch.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+
+struct group *nsss_switch_getgrgid (gid_t gid)
+{
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  if (!nsss_switch_start(&a, NSSS_SWITCH_GRP, NSSS_NSSSD_PATH, 0, 0)) return 0 ;
+  nsss_grp_sa_here.len = 0 ;
+  genalloc_setlen(char *, &nsss_grp_ga_here, 0) ;
+  if (!nsss_switch_grp_getbygid(&a, &nsss_grp_here, &nsss_grp_sa_here, &nsss_grp_ga_here, gid, 0, 0))
+  {
+    nsss_switch_end(&a, NSSS_SWITCH_GRP) ;
+    return 0 ;
+  }
+  nsss_switch_end(&a, NSSS_SWITCH_GRP) ;
+  return &nsss_grp_here ;
+}
diff --git a/src/libnsss/nsss_switch_getgrgid_r.c b/src/libnsss/nsss_switch_getgrgid_r.c
new file mode 100644
index 0000000..c87b57d
--- /dev/null
+++ b/src/libnsss/nsss_switch_getgrgid_r.c
@@ -0,0 +1,36 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <nsss/config.h>
+#include <nsss/grp-switch.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+
+int nsss_switch_getgrgid_r (gid_t gid, struct group *gr, char *buf, size_t buflen, struct group **grp)
+{
+  struct group gr2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  genalloc ga = GENALLOC_ZERO ;
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  int e = errno ;
+  if (!nsss_switch_start(&a, NSSS_SWITCH_GRP, NSSS_NSSSD_PATH, 0, 0)) return errno ;
+  errno = 0 ;
+  if (!nsss_switch_grp_getbygid(&a, &gr2, &sa, &ga, gid, 0, 0))
+  {
+    nsss_switch_end(&a, NSSS_SWITCH_GRP) ;
+    *grp = 0 ;
+    return errno ? errno : (errno = e, 0) ;
+  }
+  nsss_switch_end(&a, NSSS_SWITCH_GRP) ;
+  if (!nsss_grp_copy(gr, buf, buflen, &gr2, sa.s, sa.len, genalloc_s(char *, &ga), genalloc_len(char *, &ga)))
+  {
+    stralloc_free(&sa) ;
+    *grp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *grp = gr ;
+  return (errno = e, 0) ;
+}
diff --git a/src/libnsss/nsss_switch_getgrnam.c b/src/libnsss/nsss_switch_getgrnam.c
new file mode 100644
index 0000000..396f44e
--- /dev/null
+++ b/src/libnsss/nsss_switch_getgrnam.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <skalibs/genalloc.h>
+#include <nsss/config.h>
+#include <nsss/grp-switch.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+
+struct group *nsss_switch_getgrnam (char const *name)
+{
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  if (!nsss_switch_start(&a, NSSS_SWITCH_GRP, NSSS_NSSSD_PATH, 0, 0)) return 0 ;
+  nsss_grp_sa_here.len = 0 ;
+  genalloc_setlen(char *, &nsss_grp_ga_here, 0) ;
+  if (!nsss_switch_grp_getbyname(&a, &nsss_grp_here, &nsss_grp_sa_here, &nsss_grp_ga_here, name, 0, 0))
+  {
+    nsss_switch_end(&a, NSSS_SWITCH_GRP) ;
+    return 0 ;
+  }
+  nsss_switch_end(&a, NSSS_SWITCH_GRP) ;
+  return &nsss_grp_here ;
+}
diff --git a/src/libnsss/nsss_switch_getgrnam_r.c b/src/libnsss/nsss_switch_getgrnam_r.c
new file mode 100644
index 0000000..e6d00ec
--- /dev/null
+++ b/src/libnsss/nsss_switch_getgrnam_r.c
@@ -0,0 +1,36 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <nsss/config.h>
+#include <nsss/grp-switch.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+
+int nsss_switch_getgrnam_r (char const *name, struct group *gr, char *buf, size_t buflen, struct group **grp)
+{
+  struct group gr2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  genalloc ga = GENALLOC_ZERO ;
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  int e = errno ;
+  if (!nsss_switch_start(&a, NSSS_SWITCH_GRP, NSSS_NSSSD_PATH, 0, 0)) return errno ;
+  errno = 0 ;
+  if (!nsss_switch_grp_getbyname(&a, &gr2, &sa, &ga, name, 0, 0))
+  {
+    nsss_switch_end(&a, NSSS_SWITCH_GRP) ;
+    *grp = 0 ;
+    return errno ? errno : (errno = e, 0) ;
+  }
+  nsss_switch_end(&a, NSSS_SWITCH_GRP) ;
+  if (!nsss_grp_copy(gr, buf, buflen, &gr2, sa.s, sa.len, genalloc_s(char *, &ga), genalloc_len(char *, &ga)))
+  {
+    stralloc_free(&sa) ;
+    *grp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *grp = gr ;
+  return (errno = e, 0) ;
+}
diff --git a/src/libnsss/nsss_switch_getpwent.c b/src/libnsss/nsss_switch_getpwent.c
new file mode 100644
index 0000000..89cabfd
--- /dev/null
+++ b/src/libnsss/nsss_switch_getpwent.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <nsss/config.h>
+#include <nsss/pwd-switch.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+#include "nsss-switch-internal.h"
+
+struct passwd *nsss_switch_getpwent (void)
+{
+  if (!nsss_switch_start(&nsss_switch_here, NSSS_SWITCH_PWD, NSSS_NSSSD_PATH, 0, 0)) return 0 ;
+  nsss_pwd_sa_here.len = 0 ;
+  if (!nsss_switch_pwd_get(&nsss_switch_here, &nsss_pwd_here, &nsss_pwd_sa_here, 0, 0)) return 0 ;
+  return &nsss_pwd_here ;
+}
diff --git a/src/libnsss/nsss_switch_getpwent_r.c b/src/libnsss/nsss_switch_getpwent_r.c
new file mode 100644
index 0000000..7795af0
--- /dev/null
+++ b/src/libnsss/nsss_switch_getpwent_r.c
@@ -0,0 +1,34 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <nsss/config.h>
+#include <nsss/pwd-switch.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+#include "nsss-switch-internal.h"
+
+int nsss_switch_getpwent_r (struct passwd *pw, char *buf, size_t buflen, struct passwd **pwp)
+{
+  struct passwd pw2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  int e ;
+  if (!nsss_switch_start(&nsss_switch_here, NSSS_SWITCH_PWD, NSSS_NSSSD_PATH, 0, 0)) return errno ;
+  e = errno ;
+  errno = 0 ;
+  if (!nsss_switch_pwd_get(&nsss_switch_here, &pw2, &sa, 0, 0))
+  {
+    *pwp = 0 ;
+    if (!errno) errno = ENOENT ;
+    return errno ;
+  }
+  if (!nsss_pwd_copy(pw, buf, buflen, &pw2, sa.s, sa.len))
+  {
+    stralloc_free(&sa) ;
+    *pwp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *pwp = pw ;
+  return (errno = e, 0) ;
+}
diff --git a/src/libnsss/nsss_switch_getpwnam.c b/src/libnsss/nsss_switch_getpwnam.c
new file mode 100644
index 0000000..393503d
--- /dev/null
+++ b/src/libnsss/nsss_switch_getpwnam.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <nsss/config.h>
+#include <nsss/pwd-switch.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+
+struct passwd *nsss_switch_getpwnam (char const *name)
+{
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  if (!nsss_switch_start(&a, NSSS_SWITCH_PWD, NSSS_NSSSD_PATH, 0, 0)) return 0 ;
+  nsss_pwd_sa_here.len = 0 ;
+  if (!nsss_switch_pwd_getbyname(&a, &nsss_pwd_here, &nsss_pwd_sa_here, name, 0, 0))
+  {
+    nsss_switch_end(&a, NSSS_SWITCH_PWD) ;
+    return 0 ;
+  }
+  nsss_switch_end(&a, NSSS_SWITCH_PWD) ;
+  return &nsss_pwd_here ;
+}
diff --git a/src/libnsss/nsss_switch_getpwnam_r.c b/src/libnsss/nsss_switch_getpwnam_r.c
new file mode 100644
index 0000000..e1c1e71
--- /dev/null
+++ b/src/libnsss/nsss_switch_getpwnam_r.c
@@ -0,0 +1,34 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <nsss/config.h>
+#include <nsss/pwd-switch.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+
+int nsss_switch_getpwnam_r (char const *name, struct passwd *pw, char *buf, size_t buflen, struct passwd **pwp)
+{
+  struct passwd pw2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  int e = errno ;
+  if (!nsss_switch_start(&a, NSSS_SWITCH_PWD, NSSS_NSSSD_PATH, 0, 0)) return errno ;
+  errno = 0 ;
+  if (!nsss_switch_pwd_getbyname(&a, &pw2, &sa, name, 0, 0))
+  {
+    nsss_switch_end(&a, NSSS_SWITCH_PWD) ;
+    *pwp = 0 ;
+    return errno ? errno : (errno = e, 0) ;
+  }
+  nsss_switch_end(&a, NSSS_SWITCH_PWD) ;
+  if (!nsss_pwd_copy(pw, buf, buflen, &pw2, sa.s, sa.len))
+  {
+    stralloc_free(&sa) ;
+    *pwp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *pwp = pw ;
+  return (errno = e, 0) ;
+}
diff --git a/src/libnsss/nsss_switch_getpwuid.c b/src/libnsss/nsss_switch_getpwuid.c
new file mode 100644
index 0000000..3d765bf
--- /dev/null
+++ b/src/libnsss/nsss_switch_getpwuid.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <nsss/config.h>
+#include <nsss/pwd-switch.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+
+struct passwd *nsss_switch_getpwuid (uid_t uid)
+{
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  if (!nsss_switch_start(&a, NSSS_SWITCH_PWD, NSSS_NSSSD_PATH, 0, 0)) return 0 ;
+  nsss_pwd_sa_here.len = 0 ;
+  if (!nsss_switch_pwd_getbyuid(&a, &nsss_pwd_here, &nsss_pwd_sa_here, uid, 0, 0))
+  {
+    nsss_switch_end(&a, NSSS_SWITCH_PWD) ;
+    return 0 ;
+  }
+  nsss_switch_end(&a, NSSS_SWITCH_PWD) ;
+  return &nsss_pwd_here ;
+}
diff --git a/src/libnsss/nsss_switch_getpwuid_r.c b/src/libnsss/nsss_switch_getpwuid_r.c
new file mode 100644
index 0000000..8e63a75
--- /dev/null
+++ b/src/libnsss/nsss_switch_getpwuid_r.c
@@ -0,0 +1,34 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <nsss/config.h>
+#include <nsss/pwd-switch.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+
+int nsss_switch_getpwuid_r (uid_t uid, struct passwd *pw, char *buf, size_t buflen, struct passwd **pwp)
+{
+  struct passwd pw2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  int e = errno ;
+  if (!nsss_switch_start(&a, NSSS_SWITCH_PWD, NSSS_NSSSD_PATH, 0, 0)) return errno ;
+  errno = 0 ;
+  if (!nsss_switch_pwd_getbyuid(&a, &pw2, &sa, uid, 0, 0))
+  {
+    nsss_switch_end(&a, NSSS_SWITCH_PWD) ;
+    *pwp = 0 ;
+    return errno ? errno : (errno = e, 0) ;
+  }
+  nsss_switch_end(&a, NSSS_SWITCH_PWD) ;
+  if (!nsss_pwd_copy(pw, buf, buflen, &pw2, sa.s, sa.len))
+  {
+    stralloc_free(&sa) ;
+    *pwp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *pwp = pw ;
+  return (errno = e, 0) ;
+}
diff --git a/src/libnsss/nsss_switch_getspent.c b/src/libnsss/nsss_switch_getspent.c
new file mode 100644
index 0000000..65064a1
--- /dev/null
+++ b/src/libnsss/nsss_switch_getspent.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <nsss/config.h>
+#include <nsss/shadow-switch.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+#include "nsss-switch-internal.h"
+
+struct spwd *nsss_switch_getspent (void)
+{
+  if (!nsss_switch_start(&nsss_switch_here, NSSS_SWITCH_SHADOW, NSSS_NSSSD_PATH, 0, 0)) return 0 ;
+  nsss_shadow_sa_here.len = 0 ;
+  if (!nsss_switch_shadow_get(&nsss_switch_here, &nsss_shadow_here, &nsss_shadow_sa_here, 0, 0)) return 0 ;
+  return &nsss_shadow_here ;
+}
diff --git a/src/libnsss/nsss_switch_getspent_r.c b/src/libnsss/nsss_switch_getspent_r.c
new file mode 100644
index 0000000..118e095
--- /dev/null
+++ b/src/libnsss/nsss_switch_getspent_r.c
@@ -0,0 +1,34 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <nsss/config.h>
+#include <nsss/shadow-switch.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+#include "nsss-switch-internal.h"
+
+int nsss_switch_getspent_r (struct spwd *sp, char *buf, size_t buflen, struct spwd **spp)
+{
+  struct spwd sp2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  int e ;
+  if (!nsss_switch_start(&nsss_switch_here, NSSS_SWITCH_SHADOW, NSSS_NSSSD_PATH, 0, 0)) return errno ;
+  e = errno ;
+  errno = 0 ;
+  if (!nsss_switch_shadow_get(&nsss_switch_here, &sp2, &sa, 0, 0))
+  {
+    *spp = 0 ;
+    if (!errno) errno = ENOENT ;
+    return errno ;
+  }
+  if (!nsss_shadow_copy(sp, buf, buflen, &sp2, sa.s, sa.len))
+  {
+    stralloc_free(&sa) ;
+    *spp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *spp = sp ;
+  return (errno = e, 0) ;
+}
diff --git a/src/libnsss/nsss_switch_getspnam.c b/src/libnsss/nsss_switch_getspnam.c
new file mode 100644
index 0000000..01184ec
--- /dev/null
+++ b/src/libnsss/nsss_switch_getspnam.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <nsss/config.h>
+#include <nsss/shadow-switch.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+
+struct spwd *nsss_switch_getspnam (char const *name)
+{
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  if (!nsss_switch_start(&a, NSSS_SWITCH_SHADOW, NSSS_NSSSD_PATH, 0, 0)) return 0 ;
+  nsss_shadow_sa_here.len = 0 ;
+  if (!nsss_switch_shadow_getbyname(&a, &nsss_shadow_here, &nsss_shadow_sa_here, name, 0, 0))
+  {
+    nsss_switch_end(&a, NSSS_SWITCH_SHADOW) ;
+    return 0 ;
+  }
+  nsss_switch_end(&a, NSSS_SWITCH_SHADOW) ;
+  return &nsss_shadow_here ;
+}
diff --git a/src/libnsss/nsss_switch_getspnam_r.c b/src/libnsss/nsss_switch_getspnam_r.c
new file mode 100644
index 0000000..9c6b86f
--- /dev/null
+++ b/src/libnsss/nsss_switch_getspnam_r.c
@@ -0,0 +1,34 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <nsss/config.h>
+#include <nsss/shadow-switch.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-internal.h"
+
+int nsss_switch_getspnam_r (char const *name, struct spwd *sp, char *buf, size_t buflen, struct spwd **spp)
+{
+  struct spwd sp2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  nsss_switch_t a = NSSS_SWITCH_ZERO ;
+  int e = errno ;
+  if (!nsss_switch_start(&a, NSSS_SWITCH_SHADOW, NSSS_NSSSD_PATH, 0, 0)) return errno ;
+  errno = 0 ;
+  if (!nsss_switch_shadow_getbyname(&a, &sp2, &sa, name, 0, 0))
+  {
+    nsss_switch_end(&a, NSSS_SWITCH_SHADOW) ;
+    *spp = 0 ;
+    return errno ? errno : (errno = e, 0) ;
+  }
+  nsss_switch_end(&a, NSSS_SWITCH_SHADOW) ;
+  if (!nsss_shadow_copy(sp, buf, buflen, &sp2, sa.s, sa.len))
+  {
+    stralloc_free(&sa) ;
+    *spp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *spp = sp ;
+  return (errno = e, 0) ;
+}
diff --git a/src/libnsss/nsss_switch_grp_end.c b/src/libnsss/nsss_switch_grp_end.c
new file mode 100644
index 0000000..3b25cdf
--- /dev/null
+++ b/src/libnsss/nsss_switch_grp_end.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+
+int nsss_grent_end (nsss_switch_t *a, tain_t const *deadline, tain_t *stamp)
+{
+  return nsss_switch_op(a, NSSS_SWITCH_GRP_END, deadline, stamp) ;
+}
diff --git a/src/libnsss/nsss_switch_grp_get.c b/src/libnsss/nsss_switch_grp_get.c
new file mode 100644
index 0000000..4cfb67e
--- /dev/null
+++ b/src/libnsss/nsss_switch_grp_get.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+#include <skalibs/unix-timed.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+
+int nsss_switch_grp_get (nsss_switch_t *a, struct group *gr, stralloc *sa, genalloc *ga, tain_t const *deadline, tain_t *stamp)
+{
+  char c = NSSS_SWITCH_GRP_GET ;
+  if (!ipc_timed_send(buffer_fd(&a->b), &c, 1, deadline, stamp)) return 0 ;
+  if (!buffer_timed_get(&a->b, &c, 1, deadline, stamp)) return 0 ;
+  if ((unsigned char)c == 255) return 0 ;
+  if (c) return (errno = c, 0) ;
+  return nsss_switch_grp_read(&a->b, gr, sa, ga, deadline, stamp) ;
+}
diff --git a/src/libnsss/nsss_switch_grp_getbygid.c b/src/libnsss/nsss_switch_grp_getbygid.c
new file mode 100644
index 0000000..3b9802b
--- /dev/null
+++ b/src/libnsss/nsss_switch_grp_getbygid.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/buffer.h>
+#include <skalibs/unix-timed.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+
+int nsss_switch_grp_getbygid (nsss_switch_t *a, struct group *gr, stralloc *sa, genalloc *ga, gid_t gid, tain_t const *deadline, tain_t *stamp)
+{
+  char buf[5] = { NSSS_SWITCH_GRP_GETBYGID } ;
+  uint32_pack_big(buf + 1, gid) ;
+  if (!ipc_timed_send(buffer_fd(&a->b), buf, 5, deadline, stamp)) return 0 ;
+  if (!buffer_timed_get(&a->b, &buf[0], 1, deadline, stamp)) return 0 ;
+  if ((unsigned char)buf[0] == 255) return 0 ;
+  if (buf[0]) return (errno = buf[0], 0) ;
+  return nsss_switch_grp_read(&a->b, gr, sa, ga, deadline, stamp) ;
+}
diff --git a/src/libnsss/nsss_switch_grp_getbyname.c b/src/libnsss/nsss_switch_grp_getbyname.c
new file mode 100644
index 0000000..2ece9d2
--- /dev/null
+++ b/src/libnsss/nsss_switch_grp_getbyname.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <string.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/buffer.h>
+#include <skalibs/unix-timed.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+
+int nsss_switch_grp_getbyname (nsss_switch_t *a, struct group *gr, stralloc *sa, genalloc *ga, char const *name, tain_t const *deadline, tain_t *stamp)
+{
+  char buf[5] = { NSSS_SWITCH_GRP_GETBYNAME } ;
+  size_t len = strlen(name) ;
+  struct iovec v[2] = { { .iov_base = buf, .iov_len = 5 }, { .iov_base = (char *)name, .iov_len = len + 1 } } ;
+  if (len > NSSS_SWITCH_NAME_MAXLEN - 1) return (errno = EINVAL, 0) ;
+  uint32_pack_big(buf + 1, len + 1) ;
+  if (!ipc_timed_sendv(buffer_fd(&a->b), v, 2, deadline, stamp)) return 0 ;
+  if (!buffer_timed_get(&a->b, &buf[0], 1, deadline, stamp)) return 0 ;
+  if ((unsigned char)buf[0] == 255) return 0 ;
+  if (buf[0]) return (errno = buf[0], 0) ;
+  return nsss_switch_grp_read(&a->b, gr, sa, ga, deadline, stamp) ;
+}
diff --git a/src/libnsss/nsss_switch_grp_read.c b/src/libnsss/nsss_switch_grp_read.c
new file mode 100644
index 0000000..6152484
--- /dev/null
+++ b/src/libnsss/nsss_switch_grp_read.c
@@ -0,0 +1,58 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <skalibs/posixplz.h>
+#include <skalibs/uint32.h>
+#include <skalibs/error.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/unix-timed.h>
+#include <nsss/grp-def.h>
+#include "nsss-switch-internal.h"
+
+/*
+   Expects:
+     4 bytes gr_gid
+     4 bytes total length of strings (including \0's)
+     4 bytes number of strings in gr_mem (n)
+     \0-terminated gr_name
+     \0-terminated gr_passwd
+     sequence of n \0-terminated elements in gr_mem
+*/
+
+int nsss_switch_grp_read (buffer *b, struct group *gr, stralloc *sa, genalloc *ga, tain_t const *deadline, tain_t *stamp)
+{
+  struct group grtmp ;
+  uint32_t total, len, n, x ;
+  char **q ;
+  char *p ;
+  char buf[12] ;
+  if (!buffer_timed_get(b, buf, 12, deadline, stamp)) return 0 ;
+  uint32_unpack_big(buf, &x) ; grtmp.gr_gid = x ;
+  uint32_unpack_big(buf + 4, &total) ;
+  uint32_unpack_big(buf + 8, &n) ;
+  if (n >= 0x30000000u) return (errno = EPROTO, 0) ;
+  if (!stralloc_readyplus(sa, total)) return 0 ;
+  if (!genalloc_readyplus(char *, ga, n+1)) return 0 ;
+  if (!buffer_timed_get(b, sa->s + sa->len, total, deadline, stamp)) return 0 ;
+  if (sa->s[sa->len + total - 1]) return (errno = EPROTO, 0) ;
+  p = sa->s + sa->len ; len = total ;
+  q = genalloc_s(char *, ga) + genalloc_len(char *, ga) ;
+  grtmp.gr_mem = q ;
+  grtmp.gr_name = p ; x = strnlen(p, len) + 1 ; p += x ; len -= x ;
+  if (!len) return (errno = EPROTO, 0) ;
+  grtmp.gr_passwd = p ; x = strnlen(p, len) + 1 ; p += x ; len -= x ;
+  for (uint32_t i = 0 ; i < n ; i++)
+  {
+    if (!len) return (errno = EPROTO, 0) ;
+    q[i] = p ; x = strnlen(p, len) + 1 ; p += x ; len -= x ;
+  }
+  if (len) return (errno = EPROTO, 0) ;
+  q[n] = 0 ;
+  sa->len += total ;
+  genalloc_setlen(char *, ga, genalloc_len(char *, ga) + n + 1) ;
+  *gr = grtmp ;
+  return 1 ;
+}
diff --git a/src/libnsss/nsss_switch_grp_rewind.c b/src/libnsss/nsss_switch_grp_rewind.c
new file mode 100644
index 0000000..347b071
--- /dev/null
+++ b/src/libnsss/nsss_switch_grp_rewind.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+
+int nsss_switch_grp_rewind (nsss_switch_t *a, tain_t const *deadline, tain_t *stamp)
+{
+  return nsss_switch_op(a, NSSS_SWITCH_GRP_REWIND, deadline, stamp) ;
+}
diff --git a/src/libnsss/nsss_switch_here.c b/src/libnsss/nsss_switch_here.c
new file mode 100644
index 0000000..994974b
--- /dev/null
+++ b/src/libnsss/nsss_switch_here.c
@@ -0,0 +1,6 @@
+/* ISC license. */
+
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+
+nsss_switch_t nsss_switch_here = NSSS_SWITCH_ZERO ;
diff --git a/src/libnsss/nsss_switch_op.c b/src/libnsss/nsss_switch_op.c
new file mode 100644
index 0000000..8b5bee3
--- /dev/null
+++ b/src/libnsss/nsss_switch_op.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+#include <skalibs/unix-timed.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+
+int nsss_switch_op (nsss_switch_t *a, char op, tain_t const *deadline, tain_t *stamp)
+{
+  char c ;
+  if (!ipc_timed_send(buffer_fd(&a->b), &op, 1, deadline, stamp)) return 0 ;
+  if (!buffer_timed_get(&a->b, &c, 1, deadline, stamp)) return 0 ;
+  if (c) return (errno = c, 0) ;
+  return 1 ;
+}
diff --git a/src/libnsss/nsss_switch_pwd_end.c b/src/libnsss/nsss_switch_pwd_end.c
new file mode 100644
index 0000000..a082474
--- /dev/null
+++ b/src/libnsss/nsss_switch_pwd_end.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+
+int nsss_switch_pwd_end (nsss_switch_t *a, tain_t const *deadline, tain_t *stamp)
+{
+  return nsss_switch_op(a, NSSS_SWITCH_PWD_END, deadline, stamp) ;
+}
diff --git a/src/libnsss/nsss_switch_pwd_get.c b/src/libnsss/nsss_switch_pwd_get.c
new file mode 100644
index 0000000..0c630f8
--- /dev/null
+++ b/src/libnsss/nsss_switch_pwd_get.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+#include <skalibs/unix-timed.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+
+int nsss_switch_pwd_get (nsss_switch_t *a, struct passwd *pw, stralloc *sa, tain_t const *deadline, tain_t *stamp)
+{
+  char c = NSSS_SWITCH_PWD_GET ;
+  if (!ipc_timed_send(buffer_fd(&a->b), &c, 1, deadline, stamp)) return 0 ;
+  if (!buffer_timed_get(&a->b, &c, 1, deadline, stamp)) return 0 ;
+  if ((unsigned char)c == 255) return 0 ;
+  if (c) return (errno = c, 0) ;
+  return nsss_switch_pwd_read(&a->b, pw, sa, deadline, stamp) ;
+}
diff --git a/src/libnsss/nsss_switch_pwd_getbyname.c b/src/libnsss/nsss_switch_pwd_getbyname.c
new file mode 100644
index 0000000..a10d129
--- /dev/null
+++ b/src/libnsss/nsss_switch_pwd_getbyname.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <string.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/buffer.h>
+#include <skalibs/unix-timed.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+
+int nsss_switch_pwd_getbyname (nsss_switch_t *a, struct passwd *pw, stralloc *sa, char const *name, tain_t const *deadline, tain_t *stamp)
+{
+  char buf[5] = { NSSS_SWITCH_PWD_GETBYNAME } ;
+  size_t len = strlen(name) ;
+  struct iovec v[2] = { { .iov_base = buf, .iov_len = 5 }, { .iov_base = (char *)name, .iov_len = len + 1 } } ;
+  if (len > NSSS_SWITCH_NAME_MAXLEN - 1) return (errno = EINVAL, 0) ;
+  uint32_pack_big(buf + 1, len + 1) ;
+  if (!ipc_timed_sendv(buffer_fd(&a->b), v, 2, deadline, stamp)) return 0 ;
+  if (!buffer_timed_get(&a->b, &buf[0], 1, deadline, stamp)) return 0 ;
+  if ((unsigned char)buf[0] == 255) return 0 ;
+  if (buf[0]) return (errno = buf[0], 0) ;
+  return nsss_switch_pwd_read(&a->b, pw, sa, deadline, stamp) ;
+}
diff --git a/src/libnsss/nsss_switch_pwd_getbyuid.c b/src/libnsss/nsss_switch_pwd_getbyuid.c
new file mode 100644
index 0000000..b1d98cf
--- /dev/null
+++ b/src/libnsss/nsss_switch_pwd_getbyuid.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/buffer.h>
+#include <skalibs/unix-timed.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+
+int nsss_switch_pwd_getbyuid (nsss_switch_t *a, struct passwd *pw, stralloc *sa, uid_t uid, tain_t const *deadline, tain_t *stamp)
+{
+  char buf[5] = { NSSS_SWITCH_PWD_GETBYUID } ;
+  uint32_pack_big(buf + 1, uid) ;
+  if (!ipc_timed_send(buffer_fd(&a->b), buf, 5, deadline, stamp)) return 0 ;
+  if (!buffer_timed_get(&a->b, &buf[0], 1, deadline, stamp)) return 0 ;
+  if ((unsigned char)buf[0] == 255) return 0 ;
+  if (buf[0]) return (errno = buf[0], 0) ;
+  return nsss_switch_pwd_read(&a->b, pw, sa, deadline, stamp) ;
+}
diff --git a/src/libnsss/nsss_switch_pwd_read.c b/src/libnsss/nsss_switch_pwd_read.c
new file mode 100644
index 0000000..936b0f4
--- /dev/null
+++ b/src/libnsss/nsss_switch_pwd_read.c
@@ -0,0 +1,53 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <skalibs/posixplz.h>
+#include <skalibs/uint32.h>
+#include <skalibs/error.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/unix-timed.h>
+#include <nsss/pwd-def.h>
+#include "nsss-switch-internal.h"
+
+/*
+   Expects:
+     4 bytes pw_uid
+     4 bytes pw_gid
+     4 bytes total length of strings (including \0's)
+     \0-terminated pw_name
+     \0-terminated pw_passwd
+     \0-terminated pw_gecos
+     \0-terminated pw_dir
+     \0-terminated pw_shell
+*/
+
+int nsss_switch_pwd_read (buffer *b, struct passwd *pw, stralloc *sa, tain_t const *deadline, tain_t *stamp)
+{
+  struct passwd pwtmp ;
+  uint32_t total, len, x ;
+  char *p ;
+  char buf[12] ;
+  if (!buffer_timed_get(b, buf, 12, deadline, stamp)) return 0 ;
+  uint32_unpack_big(buf, &x) ; pwtmp.pw_uid = x ;
+  uint32_unpack_big(buf + 4, &x) ; pwtmp.pw_gid = x ;
+  uint32_unpack_big(buf + 8, &total) ;
+  if (!stralloc_readyplus(sa, total)) return 0 ;
+  if (!buffer_timed_get(b, sa->s + sa->len, total, deadline, stamp)) return 0 ;
+  if (sa->s[sa->len + total - 1]) return (errno = EPROTO, 0) ;
+  p = sa->s + sa->len ; len = total ;
+  pwtmp.pw_name = p ; x = strnlen(p, len) + 1 ; p += x ; len -= x ;
+  if (!len) return (errno = EPROTO, 0) ;
+  pwtmp.pw_passwd = p ; x = strnlen(p, len) + 1 ; p += x ; len -= x ;
+  if (!len) return (errno = EPROTO, 0) ;
+  pwtmp.pw_gecos = p ; x = strnlen(p, len) + 1 ; p += x ; len -= x ;
+  if (!len) return (errno = EPROTO, 0) ;
+  pwtmp.pw_dir = p ; x = strnlen(p, len) + 1 ; p += x ; len -= x ;
+  if (!len) return (errno = EPROTO, 0) ;
+  pwtmp.pw_shell = p ; x = strnlen(p, len) + 1 ; p += x ; len -= x ;
+  if (len) return (errno = EPROTO, 0) ;
+  sa->len += total ;
+  *pw = pwtmp ;
+  return 1 ;
+}
diff --git a/src/libnsss/nsss_switch_pwd_rewind.c b/src/libnsss/nsss_switch_pwd_rewind.c
new file mode 100644
index 0000000..9920760
--- /dev/null
+++ b/src/libnsss/nsss_switch_pwd_rewind.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+
+int nsss_switch_pwd_rewind (nsss_switch_t *a, tain_t const *deadline, tain_t *stamp)
+{
+  return nsss_switch_op(a, NSSS_SWITCH_PWD_REWIND, deadline, stamp) ;
+}
diff --git a/src/libnsss/nsss_switch_setgrent.c b/src/libnsss/nsss_switch_setgrent.c
new file mode 100644
index 0000000..a930568
--- /dev/null
+++ b/src/libnsss/nsss_switch_setgrent.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <nsss/config.h>
+#include <nsss/grp-switch.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+
+void nsss_switch_setgrent (void)
+{
+  if (!nsss_switch_start(&nsss_switch_here, NSSS_SWITCH_GRP, NSSS_NSSSD_PATH, 0, 0)) return ;
+  nsss_switch_grp_rewind(&nsss_switch_here, 0, 0) ;
+}
diff --git a/src/libnsss/nsss_switch_setpwent.c b/src/libnsss/nsss_switch_setpwent.c
new file mode 100644
index 0000000..371423e
--- /dev/null
+++ b/src/libnsss/nsss_switch_setpwent.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <nsss/config.h>
+#include <nsss/pwd-switch.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+
+void nsss_switch_setpwent (void)
+{
+  if (!nsss_switch_start(&nsss_switch_here, NSSS_SWITCH_PWD, NSSS_NSSSD_PATH, 0, 0)) return ;
+  nsss_switch_pwd_rewind(&nsss_switch_here, 0, 0) ;
+}
diff --git a/src/libnsss/nsss_switch_setspent.c b/src/libnsss/nsss_switch_setspent.c
new file mode 100644
index 0000000..5f5ed8a
--- /dev/null
+++ b/src/libnsss/nsss_switch_setspent.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <nsss/config.h>
+#include <nsss/shadow-switch.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+
+void nsss_switch_setspent (void)
+{
+  if (!nsss_switch_start(&nsss_switch_here, NSSS_SWITCH_SHADOW, NSSS_NSSSD_PATH, 0, 0)) return ;
+  nsss_switch_shadow_rewind(&nsss_switch_here, 0, 0) ;
+}
diff --git a/src/libnsss/nsss_switch_shadow_end.c b/src/libnsss/nsss_switch_shadow_end.c
new file mode 100644
index 0000000..eb3454d
--- /dev/null
+++ b/src/libnsss/nsss_switch_shadow_end.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+
+int nsss_switch_shadow_end (nsss_switch_t *a, tain_t const *deadline, tain_t *stamp)
+{
+  return nsss_switch_op(a, NSSS_SWITCH_SHADOW_END, deadline, stamp) ;
+}
diff --git a/src/libnsss/nsss_switch_shadow_get.c b/src/libnsss/nsss_switch_shadow_get.c
new file mode 100644
index 0000000..e510232
--- /dev/null
+++ b/src/libnsss/nsss_switch_shadow_get.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/buffer.h>
+#include <skalibs/unix-timed.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+
+int nsss_switch_shadow_get (nsss_switch_t *a, struct spwd *sp, stralloc *sa, tain_t const *deadline, tain_t *stamp)
+{
+  char c = NSSS_SWITCH_SHADOW_GET ;
+  if (!ipc_timed_send(buffer_fd(&a->b), &c, 1, deadline, stamp)) return 0 ;
+  if (!buffer_timed_get(&a->b, &c, 1, deadline, stamp)) return 0 ;
+  if ((unsigned char)c == 255) return 0 ;
+  if (c) return (errno = c, 0) ;
+  return nsss_switch_shadow_read(&a->b, sp, sa, deadline, stamp) ;
+}
diff --git a/src/libnsss/nsss_switch_shadow_getbyname.c b/src/libnsss/nsss_switch_shadow_getbyname.c
new file mode 100644
index 0000000..33fa426
--- /dev/null
+++ b/src/libnsss/nsss_switch_shadow_getbyname.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <string.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <skalibs/uint32.h>
+#include <skalibs/buffer.h>
+#include <skalibs/unix-timed.h>
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+
+int nsss_switch_shadow_getbyname (nsss_switch_t *a, struct spwd *sp, stralloc *sa, char const *name, tain_t const *deadline, tain_t *stamp)
+{
+  char buf[5] = { NSSS_SWITCH_SHADOW_GETBYNAME } ;
+  size_t len = strlen(name) ;
+  struct iovec v[2] = { { .iov_base = buf, .iov_len = 5 }, { .iov_base = (char *)name, .iov_len = len + 1 } } ;
+  if (len > NSSS_SWITCH_NAME_MAXLEN - 1) return (errno = EINVAL, 0) ;
+  uint32_pack_big(buf + 1, len + 1) ;
+  if (!ipc_timed_sendv(buffer_fd(&a->b), v, 2, deadline, stamp)) return 0 ;
+  if (!buffer_timed_get(&a->b, &buf[0], 1, deadline, stamp)) return 0 ;
+  if ((unsigned char)buf[0] == 255) return 0 ;
+  if (buf[0]) return (errno = buf[0], 0) ;
+  return nsss_switch_shadow_read(&a->b, sp, sa, deadline, stamp) ;
+}
diff --git a/src/libnsss/nsss_switch_shadow_read.c b/src/libnsss/nsss_switch_shadow_read.c
new file mode 100644
index 0000000..1806c6d
--- /dev/null
+++ b/src/libnsss/nsss_switch_shadow_read.c
@@ -0,0 +1,56 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <skalibs/posixplz.h>
+#include <skalibs/uint32.h>
+#include <skalibs/uint64.h>
+#include <skalibs/error.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/unix-timed.h>
+#include <nsss/shadow-def.h>
+#include "nsss-switch-internal.h"
+
+/*
+   Expects:
+     8 bytes sp_lstchg
+     8 bytes sp_min
+     8 bytes sp_max
+     8 bytes sp_warn
+     8 bytes sp_inact
+     8 bytes sp_expire
+     8 bytes sp_flag
+     4 bytes total length of strings (including \0's)
+     \0-terminated sp_namp
+     \0-terminated sp_pwdp
+*/
+
+int nsss_switch_shadow_read (buffer *b, struct spwd *sp, stralloc *sa, tain_t const *deadline, tain_t *stamp)
+{
+  struct spwd sptmp ;
+  uint64_t x ;
+  uint32_t total, len ;
+  char *p ;
+  char buf[60] ;
+  if (!buffer_timed_get(b, buf, 60, deadline, stamp)) return 0 ;
+  uint64_unpack_big(buf, &x) ; sptmp.sp_lstchg = x ;
+  uint64_unpack_big(buf + 8, &x) ; sptmp.sp_min = x ;
+  uint64_unpack_big(buf + 16, &x) ; sptmp.sp_max = x ;
+  uint64_unpack_big(buf + 24, &x) ; sptmp.sp_warn = x ;
+  uint64_unpack_big(buf + 32, &x) ; sptmp.sp_inact = x ;
+  uint64_unpack_big(buf + 40, &x) ; sptmp.sp_expire = x ;
+  uint64_unpack_big(buf + 48, &x) ; sptmp.sp_flag = x ;
+  uint32_unpack_big(buf + 56, &total) ;
+  if (!stralloc_readyplus(sa, total)) return 0 ;
+  if (!buffer_timed_get(b, sa->s + sa->len, total, deadline, stamp)) return 0 ;
+  if (sa->s[sa->len + total - 1]) return (errno = EPROTO, 0) ;
+  p = sa->s + sa->len ; len = total ;
+  sptmp.sp_namp = p ; x = strnlen(p, len) + 1 ; p += x ; len -= x ;
+  if (!len) return (errno = EPROTO, 0) ;
+  sptmp.sp_pwdp = p ; x = strnlen(p, len) + 1 ; p += x ; len -= x ;
+  if (len) return (errno = EPROTO, 0) ;
+  sa->len += total ;
+  *sp = sptmp ;
+  return 1 ;
+}
diff --git a/src/libnsss/nsss_switch_shadow_rewind.c b/src/libnsss/nsss_switch_shadow_rewind.c
new file mode 100644
index 0000000..449f25c
--- /dev/null
+++ b/src/libnsss/nsss_switch_shadow_rewind.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <nsss/nsss-switch.h>
+#include "nsss-switch-internal.h"
+
+int nsss_switch_shadow_rewind (nsss_switch_t *a, tain_t const *deadline, tain_t *stamp)
+{
+  return nsss_switch_op(a, NSSS_SWITCH_SHADOW_REWIND, deadline, stamp) ;
+}
diff --git a/src/libnsss/nsss_switch_start.c b/src/libnsss/nsss_switch_start.c
new file mode 100644
index 0000000..5d7a183
--- /dev/null
+++ b/src/libnsss/nsss_switch_start.c
@@ -0,0 +1,26 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/webipc.h>
+#include <nsss/nsss-switch.h>
+
+static inline int nsss_switch_connect (nsss_switch_t *a, char const *path, tain_t const *deadline, tain_t *stamp)
+{
+  int fd = ipc_stream_nbcoe() ;
+  if (fd < 0) return 0 ;
+  if (!ipc_timed_connect(fd, path, deadline, stamp))
+  {
+    fd_close(fd) ;
+    return 0 ;
+  }
+  buffer_init(&a->b, &buffer_read, fd, a->buf, NSSS_SWITCH_BUFSIZE) ;
+  return 1 ;
+}
+
+int nsss_switch_start (nsss_switch_t *a, unsigned int what, char const *path, tain_t const *deadline, tain_t *stamp)
+{
+  if (!a->held && !nsss_switch_connect(a, path, deadline, stamp)) return 0 ;
+  a->held |= (1U << what) ;
+  return 1 ;
+}
diff --git a/src/libnsss/nsss_unix_end.c b/src/libnsss/nsss_unix_end.c
new file mode 100644
index 0000000..1d6b867
--- /dev/null
+++ b/src/libnsss/nsss_unix_end.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+#include <skalibs/djbunix.h>
+#include <nsss/nsss-unix.h>
+
+void nsss_unix_end (nsss_unix_t *a)
+{
+  fd_close(buffer_fd(&a->b)) ;
+  a->b.fd = -1 ;
+}
diff --git a/src/libnsss/nsss_unix_endgrent.c b/src/libnsss/nsss_unix_endgrent.c
new file mode 100644
index 0000000..58c2422
--- /dev/null
+++ b/src/libnsss/nsss_unix_endgrent.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <nsss/grp-unix.h>
+#include "nsss-unix-internal.h"
+
+void nsss_unix_endgrent (void)
+{
+  nsss_unix_grp_end(&nsss_unix_grp_here) ;
+}
diff --git a/src/libnsss/nsss_unix_endpwent.c b/src/libnsss/nsss_unix_endpwent.c
new file mode 100644
index 0000000..c7d87af
--- /dev/null
+++ b/src/libnsss/nsss_unix_endpwent.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <nsss/pwd-unix.h>
+#include "nsss-unix-internal.h"
+
+void nsss_unix_endpwent (void)
+{
+  nsss_unix_pwd_end(&nsss_unix_pwd_here) ;
+}
diff --git a/src/libnsss/nsss_unix_endspent.c b/src/libnsss/nsss_unix_endspent.c
new file mode 100644
index 0000000..3e28e75
--- /dev/null
+++ b/src/libnsss/nsss_unix_endspent.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <nsss/shadow-unix.h>
+#include "nsss-unix-internal.h"
+
+void nsss_unix_endspent (void)
+{
+  nsss_unix_shadow_end(&nsss_unix_shadow_here) ;
+}
diff --git a/src/libnsss/nsss_unix_field.c b/src/libnsss/nsss_unix_field.c
new file mode 100644
index 0000000..b77bb04
--- /dev/null
+++ b/src/libnsss/nsss_unix_field.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <string.h>
+#include "nsss-unix-internal.h"
+
+int nsss_unix_field (char **field, char **s)
+{
+  char *p = strchr(*s, ':') ;
+  if (!p) return 0 ;
+  *p++ = 0 ;
+  *field = *s ;
+  *s = p ;
+  return 1 ;
+}
diff --git a/src/libnsss/nsss_unix_getgrent.c b/src/libnsss/nsss_unix_getgrent.c
new file mode 100644
index 0000000..e531510
--- /dev/null
+++ b/src/libnsss/nsss_unix_getgrent.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <skalibs/genalloc.h>
+#include <nsss/grp-unix.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-internal.h"
+#include "nsss-unix-internal.h"
+
+struct group *nsss_unix_getgrent (void)
+{
+  if (!nsss_unix_grp_maybe_start(&nsss_unix_grp_here)) return 0 ;
+  nsss_grp_sa_here.len = 0 ;
+  genalloc_setlen(char *, &nsss_grp_ga_here, 0) ;
+  if (!nsss_unix_grp_get(&nsss_unix_grp_here, &nsss_grp_here, &nsss_grp_sa_here, &nsss_grp_ga_here)) return 0 ;
+  return &nsss_grp_here ;
+}
diff --git a/src/libnsss/nsss_unix_getgrent_r.c b/src/libnsss/nsss_unix_getgrent_r.c
new file mode 100644
index 0000000..5ddc526
--- /dev/null
+++ b/src/libnsss/nsss_unix_getgrent_r.c
@@ -0,0 +1,35 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <nsss/grp-unix.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-internal.h"
+#include "nsss-unix-internal.h"
+
+int nsss_unix_getgrent_r (struct group *gr, char *buf, size_t buflen, struct group **grp)
+{
+  struct group gr2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  genalloc ga = GENALLOC_ZERO ;
+  int e ;
+  if (!nsss_unix_grp_maybe_start(&nsss_unix_grp_here)) return errno ;
+  e = errno ;
+  errno = 0 ;
+  if (!nsss_unix_grp_get(&nsss_unix_grp_here, &gr2, &sa, &ga))
+  {
+    *grp = 0 ;
+    if (!errno) errno = ENOENT ;
+    return errno ;
+  }
+  if (!nsss_grp_copy(gr, buf, buflen, &gr2, sa.s, sa.len, genalloc_s(char *, &ga), genalloc_len(char *, &ga)))
+  {
+    stralloc_free(&sa) ;
+    *grp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *grp = gr ;
+  return (errno = e, 0) ;
+}
diff --git a/src/libnsss/nsss_unix_getgrgid.c b/src/libnsss/nsss_unix_getgrgid.c
new file mode 100644
index 0000000..e6d8979
--- /dev/null
+++ b/src/libnsss/nsss_unix_getgrgid.c
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#include <skalibs/genalloc.h>
+#include <nsss/grp-unix.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-internal.h"
+
+struct group *nsss_unix_getgrgid (gid_t gid)
+{
+  nsss_unix_t a = NSSS_UNIX_ZERO ;
+  if (!nsss_unix_grp_start(&a)) return 0 ;
+  nsss_grp_sa_here.len = 0 ;
+  genalloc_setlen(char *, &nsss_grp_ga_here, 0) ;
+  if (!nsss_unix_grp_getbygid(&a, &nsss_grp_here, &nsss_grp_sa_here, &nsss_grp_ga_here, gid))
+  {
+    nsss_unix_grp_end(&a) ;
+    return 0 ;
+  }
+  nsss_unix_grp_end(&a) ;
+  return &nsss_grp_here ;
+}
diff --git a/src/libnsss/nsss_unix_getgrgid_r.c b/src/libnsss/nsss_unix_getgrgid_r.c
new file mode 100644
index 0000000..5d3dbe5
--- /dev/null
+++ b/src/libnsss/nsss_unix_getgrgid_r.c
@@ -0,0 +1,35 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <nsss/grp-unix.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-internal.h"
+
+int nsss_unix_getgrgid_r (gid_t gid, struct group *gr, char *buf, size_t buflen, struct group **grp)
+{
+  struct group gr2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  genalloc ga = GENALLOC_ZERO ;
+  nsss_unix_t a = NSSS_UNIX_ZERO ;
+  int e = errno ;
+  if (!nsss_unix_grp_start(&a)) return errno ;
+  errno = 0 ;
+  if (!nsss_unix_grp_getbygid(&a, &gr2, &sa, &ga, gid))
+  {
+    nsss_unix_grp_end(&a) ;
+    *grp = 0 ;
+    return errno ? errno : (errno = e, 0) ;
+  }
+  nsss_unix_grp_end(&a) ;
+  if (!nsss_grp_copy(gr, buf, buflen, &gr2, sa.s, sa.len, genalloc_s(char *, &ga), genalloc_len(char *, &ga)))
+  {
+    stralloc_free(&sa) ;
+    *grp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *grp = gr ;
+  return (errno = e, 0) ;
+}
diff --git a/src/libnsss/nsss_unix_getgrnam.c b/src/libnsss/nsss_unix_getgrnam.c
new file mode 100644
index 0000000..ca9d9b9
--- /dev/null
+++ b/src/libnsss/nsss_unix_getgrnam.c
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#include <skalibs/genalloc.h>
+#include <nsss/grp-unix.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-internal.h"
+
+struct group *nsss_unix_getgrnam (char const *name)
+{
+  nsss_unix_t a = NSSS_UNIX_ZERO ;
+  if (!nsss_unix_grp_start(&a)) return 0 ;
+  nsss_grp_sa_here.len = 0 ;
+  genalloc_setlen(char *, &nsss_grp_ga_here, 0) ;
+  if (!nsss_unix_grp_getbyname(&a, &nsss_grp_here, &nsss_grp_sa_here, &nsss_grp_ga_here, name))
+  {
+    nsss_unix_grp_end(&a) ;
+    return 0 ;
+  }
+  nsss_unix_grp_end(&a) ;
+  return &nsss_grp_here ;
+}
diff --git a/src/libnsss/nsss_unix_getgrnam_r.c b/src/libnsss/nsss_unix_getgrnam_r.c
new file mode 100644
index 0000000..bc63d78
--- /dev/null
+++ b/src/libnsss/nsss_unix_getgrnam_r.c
@@ -0,0 +1,35 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <nsss/grp-unix.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-internal.h"
+
+int nsss_unix_getgrnam_r (char const *name, struct group *gr, char *buf, size_t buflen, struct group **grp)
+{
+  struct group gr2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  genalloc ga = GENALLOC_ZERO ;
+  nsss_unix_t a = NSSS_UNIX_ZERO ;
+  int e = errno ;
+  if (!nsss_unix_grp_start(&a)) return errno ;
+  errno = 0 ;
+  if (!nsss_unix_grp_getbyname(&a, &gr2, &sa, &ga, name))
+  {
+    nsss_unix_grp_end(&a) ;
+    *grp = 0 ;
+    return errno ? errno : (errno = e, 0) ;
+  }
+  nsss_unix_grp_end(&a) ;
+  if (!nsss_grp_copy(gr, buf, buflen, &gr2, sa.s, sa.len, genalloc_s(char *, &ga), genalloc_len(char *, &ga)))
+  {
+    stralloc_free(&sa) ;
+    *grp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *grp = gr ;
+  return (errno = e, 0) ;
+}
diff --git a/src/libnsss/nsss_unix_getpwent.c b/src/libnsss/nsss_unix_getpwent.c
new file mode 100644
index 0000000..4271f0b
--- /dev/null
+++ b/src/libnsss/nsss_unix_getpwent.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <nsss/pwd-unix.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-internal.h"
+#include "nsss-unix-internal.h"
+
+struct passwd *nsss_unix_getpwent (void)
+{
+  if (!nsss_unix_pwd_maybe_start(&nsss_unix_pwd_here)) return 0 ;
+  nsss_pwd_sa_here.len = 0 ;
+  if (!nsss_unix_pwd_get(&nsss_unix_pwd_here, &nsss_pwd_here, &nsss_pwd_sa_here)) return 0 ;
+  return &nsss_pwd_here ;
+}
diff --git a/src/libnsss/nsss_unix_getpwent_r.c b/src/libnsss/nsss_unix_getpwent_r.c
new file mode 100644
index 0000000..183bfd7
--- /dev/null
+++ b/src/libnsss/nsss_unix_getpwent_r.c
@@ -0,0 +1,33 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <nsss/pwd-unix.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-internal.h"
+#include "nsss-unix-internal.h"
+
+int nsss_unix_getpwent_r (struct passwd *pw, char *buf, size_t buflen, struct passwd **pwp)
+{
+  struct passwd pw2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  int e ;
+  if (!nsss_unix_pwd_maybe_start(&nsss_unix_pwd_here)) return errno ;
+  e = errno ;
+  errno = 0 ;
+  if (!nsss_unix_pwd_get(&nsss_unix_pwd_here, &pw2, &sa))
+  {
+    *pwp = 0 ;
+    if (!errno) errno = ENOENT ;
+    return errno ;
+  }
+  if (!nsss_pwd_copy(pw, buf, buflen, &pw2, sa.s, sa.len))
+  {
+    stralloc_free(&sa) ;
+    *pwp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *pwp = pw ;
+  return (errno = e, 0) ;
+}
diff --git a/src/libnsss/nsss_unix_getpwnam.c b/src/libnsss/nsss_unix_getpwnam.c
new file mode 100644
index 0000000..eb5d6b1
--- /dev/null
+++ b/src/libnsss/nsss_unix_getpwnam.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <nsss/pwd-unix.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-internal.h"
+
+struct passwd *nsss_unix_getpwnam (char const *name)
+{
+  nsss_unix_t a = NSSS_UNIX_ZERO ;
+  if (!nsss_unix_pwd_start(&a)) return 0 ;
+  nsss_pwd_sa_here.len = 0 ;
+  if (!nsss_unix_pwd_getbyname(&a, &nsss_pwd_here, &nsss_pwd_sa_here, name))
+  {
+    nsss_unix_pwd_end(&a) ;
+    return 0 ;
+  }
+  nsss_unix_pwd_end(&a) ;
+  return &nsss_pwd_here ;
+}
diff --git a/src/libnsss/nsss_unix_getpwnam_r.c b/src/libnsss/nsss_unix_getpwnam_r.c
new file mode 100644
index 0000000..b41ce70
--- /dev/null
+++ b/src/libnsss/nsss_unix_getpwnam_r.c
@@ -0,0 +1,33 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <nsss/pwd-unix.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-internal.h"
+
+int nsss_unix_getpwnam_r (char const *name, struct passwd *pw, char *buf, size_t buflen, struct passwd **pwp)
+{
+  struct passwd pw2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  nsss_unix_t a = NSSS_UNIX_ZERO ;
+  int e = errno ;
+  if (!nsss_unix_pwd_start(&a)) return errno ;
+  errno = 0 ;
+  if (!nsss_unix_pwd_getbyname(&a, &pw2, &sa, name))
+  {
+    nsss_unix_pwd_end(&a) ;
+    *pwp = 0 ;
+    return errno ? errno : (errno = e, 0) ;
+  }
+  nsss_unix_pwd_end(&a) ;
+  if (!nsss_pwd_copy(pw, buf, buflen, &pw2, sa.s, sa.len))
+  {
+    stralloc_free(&sa) ;
+    *pwp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *pwp = pw ;
+  return (errno = e, 0) ;
+}
diff --git a/src/libnsss/nsss_unix_getpwuid.c b/src/libnsss/nsss_unix_getpwuid.c
new file mode 100644
index 0000000..35f019d
--- /dev/null
+++ b/src/libnsss/nsss_unix_getpwuid.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <nsss/pwd-unix.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-internal.h"
+
+struct passwd *nsss_unix_getpwuid (uid_t uid)
+{
+  nsss_unix_t a = NSSS_UNIX_ZERO ;
+  if (!nsss_unix_pwd_start(&a)) return 0 ;
+  nsss_pwd_sa_here.len = 0 ;
+  if (!nsss_unix_pwd_getbyuid(&a, &nsss_pwd_here, &nsss_pwd_sa_here, uid))
+  {
+    nsss_unix_pwd_end(&a) ;
+    return 0 ;
+  }
+  nsss_unix_pwd_end(&a) ;
+  return &nsss_pwd_here ;
+}
diff --git a/src/libnsss/nsss_unix_getpwuid_r.c b/src/libnsss/nsss_unix_getpwuid_r.c
new file mode 100644
index 0000000..0601008
--- /dev/null
+++ b/src/libnsss/nsss_unix_getpwuid_r.c
@@ -0,0 +1,33 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <nsss/pwd-unix.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-internal.h"
+
+int nsss_unix_getpwuid_r (uid_t uid, struct passwd *pw, char *buf, size_t buflen, struct passwd **pwp)
+{
+  struct passwd pw2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  nsss_unix_t a = NSSS_UNIX_ZERO ;
+  int e = errno ;
+  if (!nsss_unix_pwd_start(&a)) return errno ;
+  errno = 0 ;
+  if (!nsss_unix_pwd_getbyuid(&a, &pw2, &sa, uid))
+  {
+    nsss_unix_pwd_end(&a) ;
+    *pwp = 0 ;
+    return errno ? errno : (errno = e, 0) ;
+  }
+  nsss_unix_pwd_end(&a) ;
+  if (!nsss_pwd_copy(pw, buf, buflen, &pw2, sa.s, sa.len))
+  {
+    stralloc_free(&sa) ;
+    *pwp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *pwp = pw ;
+  return (errno = e, 0) ;
+}
diff --git a/src/libnsss/nsss_unix_getspent.c b/src/libnsss/nsss_unix_getspent.c
new file mode 100644
index 0000000..f442a40
--- /dev/null
+++ b/src/libnsss/nsss_unix_getspent.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <nsss/shadow-unix.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-internal.h"
+#include "nsss-unix-internal.h"
+
+struct spwd *nsss_unix_getspent (void)
+{
+  if (!nsss_unix_shadow_maybe_start(&nsss_unix_shadow_here)) return 0 ;
+  nsss_shadow_sa_here.len = 0 ;
+  if (!nsss_unix_shadow_get(&nsss_unix_shadow_here, &nsss_shadow_here, &nsss_shadow_sa_here)) return 0 ;
+  return &nsss_shadow_here ;
+}
diff --git a/src/libnsss/nsss_unix_getspent_r.c b/src/libnsss/nsss_unix_getspent_r.c
new file mode 100644
index 0000000..6ae4f8a
--- /dev/null
+++ b/src/libnsss/nsss_unix_getspent_r.c
@@ -0,0 +1,33 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <nsss/shadow-unix.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-internal.h"
+#include "nsss-unix-internal.h"
+
+int nsss_unix_getspent_r (struct spwd *sp, char *buf, size_t buflen, struct spwd **spp)
+{
+  struct spwd sp2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  int e ;
+  if (!nsss_unix_shadow_maybe_start(&nsss_unix_shadow_here)) return errno ;
+  e = errno ;
+  errno = 0 ;
+  if (!nsss_unix_shadow_get(&nsss_unix_shadow_here, &sp2, &sa))
+  {
+    *spp = 0 ;
+    if (!errno) errno = ENOENT ;
+    return errno ;
+  }
+  if (!nsss_shadow_copy(sp, buf, buflen, &sp2, sa.s, sa.len))
+  {
+    stralloc_free(&sa) ;
+    *spp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *spp = sp ;
+  return (errno = e, 0) ;
+}
diff --git a/src/libnsss/nsss_unix_getspnam.c b/src/libnsss/nsss_unix_getspnam.c
new file mode 100644
index 0000000..810d45f
--- /dev/null
+++ b/src/libnsss/nsss_unix_getspnam.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <nsss/shadow-unix.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-internal.h"
+
+struct spwd *nsss_unix_getspnam (char const *name)
+{
+  nsss_unix_t a = NSSS_UNIX_ZERO ;
+  if (!nsss_unix_shadow_start(&a)) return 0 ;
+  nsss_shadow_sa_here.len = 0 ;
+  if (!nsss_unix_shadow_getbyname(&a, &nsss_shadow_here, &nsss_shadow_sa_here, name))
+  {
+    nsss_unix_shadow_end(&a) ;
+    return 0 ;
+  }
+  nsss_unix_shadow_end(&a) ;
+  return &nsss_shadow_here ;
+}
diff --git a/src/libnsss/nsss_unix_getspnam_r.c b/src/libnsss/nsss_unix_getspnam_r.c
new file mode 100644
index 0000000..f0bfed4
--- /dev/null
+++ b/src/libnsss/nsss_unix_getspnam_r.c
@@ -0,0 +1,33 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/stralloc.h>
+#include <nsss/shadow-unix.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-internal.h"
+
+int nsss_unix_getspnam_r (char const *name, struct spwd *sp, char *buf, size_t buflen, struct spwd **spp)
+{
+  struct spwd sp2 ;
+  stralloc sa = STRALLOC_ZERO ;
+  nsss_unix_t a = NSSS_UNIX_ZERO ;
+  int e = errno ;
+  if (!nsss_unix_shadow_start(&a)) return errno ;
+  errno = 0 ;
+  if (!nsss_unix_shadow_getbyname(&a, &sp2, &sa, name))
+  {
+    nsss_unix_shadow_end(&a) ;
+    *spp = 0 ;
+    return errno ? errno : (errno = e, 0) ;
+  }
+  nsss_unix_shadow_end(&a) ;
+  if (!nsss_shadow_copy(sp, buf, buflen, &sp2, sa.s, sa.len))
+  {
+    stralloc_free(&sa) ;
+    *spp = 0 ;
+    return errno ;
+  }
+  stralloc_free(&sa) ;
+  *spp = sp ;
+  return (errno = e, 0) ;
+}
diff --git a/src/libnsss/nsss_unix_grp_get.c b/src/libnsss/nsss_unix_grp_get.c
new file mode 100644
index 0000000..f7984a4
--- /dev/null
+++ b/src/libnsss/nsss_unix_grp_get.c
@@ -0,0 +1,62 @@
+/* ISC license. */
+
+#include <string.h>
+#include <pthread.h>
+#include <skalibs/types.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/skamisc.h>
+#include <nsss/grp-def.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-unix-internal.h"
+
+static inline char **grp_parsemem (char *s, genalloc *ga)
+{
+  char **grmem ;
+  char **p ;
+  size_t n = 0 ;
+  for (char *t = s ; *t ; t++) if (*t == ',') { n++ ; *t = 0 ; } ;
+  if (*s) n++ ;
+  if (!genalloc_readyplus(char *, ga, n+1)) return 0 ;
+  p = genalloc_s(char *, ga) + genalloc_len(char *, ga) ;
+  grmem = p ;
+  for (size_t i = 0 ; i < n ; i++) { *p++ = s ; s += strlen(s) + 1 ; }
+  *p++ = 0 ;
+  genalloc_setlen(char *, ga, genalloc_len(char *, ga) + n+1) ;
+  return grmem ;
+}
+
+static inline int grp_parseline (struct group *gr, char *s, size_t max, genalloc *ga)
+{
+  struct group gr2 ;
+  char *p ;
+  s[max-1] = 0 ;
+  if (!nsss_unix_field(&gr2.gr_name, &s)) return 0 ;
+  if (!nsss_unix_field(&gr2.gr_passwd, &s)) return 0 ;
+  if (!nsss_unix_field(&p, &s)) return 0 ;
+  if (!gid0_scan(p, &gr2.gr_gid)) return 0 ;
+  gr2.gr_mem = grp_parsemem(s, ga) ;
+  if (!gr2.gr_mem) return 0 ;
+  *gr = gr2 ;
+  return 1 ;
+}
+
+int nsss_unix_grp_get (nsss_unix_t *a, struct group *gr, stralloc *sa, genalloc *ga)
+{
+  int cs ;
+  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs) ;
+  for (;;)
+  {
+    size_t sabase = sa->len ;
+    size_t gabase = genalloc_len(char *, ga) ;
+    if (skagetln_loose(&a->b, sa, '\n') <= 0) goto err ;
+    if (grp_parseline(gr, sa->s + sabase, sa->len - sabase, ga)) break ;
+    sa->len = sabase ;
+    genalloc_setlen(char *, ga, gabase) ;
+  }
+  pthread_setcancelstate(cs, 0) ;
+  return 1 ;
+
+ err:
+  pthread_setcancelstate(cs, 0) ;
+  return 0 ;
+}
diff --git a/src/libnsss/nsss_unix_grp_getbygid.c b/src/libnsss/nsss_unix_grp_getbygid.c
new file mode 100644
index 0000000..48cfecf
--- /dev/null
+++ b/src/libnsss/nsss_unix_grp_getbygid.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <skalibs/genalloc.h>
+#include <nsss/grp-def.h>
+#include <nsss/nsss-unix.h>
+
+int nsss_unix_grp_getbygid (nsss_unix_t *a, struct group *gr, stralloc *sa, genalloc *ga, gid_t gid)
+{
+  struct group gr2 ;
+  for (;;)
+  {
+    size_t sabase = sa->len ;
+    size_t gabase = genalloc_len(char *, ga) ;
+    if (!nsss_unix_grp_get(a, &gr2, sa, ga)) return 0 ;
+    if (gid == gr2.gr_gid) break ;
+    sa->len = sabase ;
+    genalloc_setlen(char *, ga, gabase) ;
+  }
+  *gr = gr2 ;
+  return 1 ;
+}
diff --git a/src/libnsss/nsss_unix_grp_getbyname.c b/src/libnsss/nsss_unix_grp_getbyname.c
new file mode 100644
index 0000000..0b8e3b8
--- /dev/null
+++ b/src/libnsss/nsss_unix_grp_getbyname.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <string.h>
+#include <skalibs/genalloc.h>
+#include <nsss/grp-def.h>
+#include <nsss/nsss-unix.h>
+
+int nsss_unix_grp_getbyname (nsss_unix_t *a, struct group *gr, stralloc *sa, genalloc *ga, char const *name)
+{
+  struct group gr2 ;
+  for (;;)
+  {
+    size_t sabase = sa->len ;
+    size_t gabase = genalloc_len(char *, ga) ;
+    if (!nsss_unix_grp_get(a, &gr2, sa, ga)) return 0 ;
+    if (!strcmp(name, gr2.gr_name)) break ;
+    sa->len = sabase ;
+    genalloc_setlen(char *, ga, gabase) ;
+  }
+  *gr = gr2 ;
+  return 1 ;
+}
diff --git a/src/libnsss/nsss_unix_grp_here.c b/src/libnsss/nsss_unix_grp_here.c
new file mode 100644
index 0000000..b2adfe9
--- /dev/null
+++ b/src/libnsss/nsss_unix_grp_here.c
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#include "nsss-unix-internal.h"
+
+nsss_unix_t nsss_unix_grp_here = NSSS_UNIX_ZERO ;
diff --git a/src/libnsss/nsss_unix_maybe_start.c b/src/libnsss/nsss_unix_maybe_start.c
new file mode 100644
index 0000000..9aad8d4
--- /dev/null
+++ b/src/libnsss/nsss_unix_maybe_start.c
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+#include <nsss/nsss-unix.h>
+
+int nsss_unix_maybe_start (nsss_unix_t *a, char const *path)
+{
+  return buffer_fd(&a->b) >= 0 || nsss_unix_start(a, path) ;
+}
diff --git a/src/libnsss/nsss_unix_pwd_get.c b/src/libnsss/nsss_unix_pwd_get.c
new file mode 100644
index 0000000..b0c1200
--- /dev/null
+++ b/src/libnsss/nsss_unix_pwd_get.c
@@ -0,0 +1,45 @@
+/* ISC license. */
+
+#include <pthread.h>
+#include <skalibs/types.h>
+#include <skalibs/skamisc.h>
+#include <nsss/pwd-def.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-unix-internal.h"
+
+static inline int pwd_parseline (struct passwd *pw, char *s, size_t max)
+{
+  struct passwd pw2 ;
+  char *p ;
+  s[max-1] = 0 ;
+  if (!nsss_unix_field(&pw2.pw_name, &s)) return 0 ;
+  if (!nsss_unix_field(&pw2.pw_passwd, &s)) return 0 ;
+  if (!nsss_unix_field(&p, &s)) return 0 ;
+  if (!uid0_scan(p, &pw2.pw_uid)) return 0 ;
+  if (!nsss_unix_field(&p, &s)) return 0 ;
+  if (!gid0_scan(p, &pw2.pw_gid)) return 0 ;
+  if (!nsss_unix_field(&pw2.pw_gecos, &s)) return 0 ;
+  if (!nsss_unix_field(&pw2.pw_dir, &s)) return 0 ;
+  pw2.pw_shell = s ;
+  *pw = pw2 ;
+  return 1 ;
+}
+
+int nsss_unix_pwd_get (nsss_unix_t *a, struct passwd *pw, stralloc *sa)
+{
+  int cs ;
+  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs) ;
+  for (;;)
+  {
+    size_t base = sa->len ;
+    if (skagetln_loose(&a->b, sa, '\n') <= 0) goto err ;
+    if (pwd_parseline(pw, sa->s + base, sa->len - base)) break ;
+    sa->len = base ;
+  }
+  pthread_setcancelstate(cs, 0) ;
+  return 1 ;
+
+ err:
+  pthread_setcancelstate(cs, 0) ;
+  return 0 ;
+}
diff --git a/src/libnsss/nsss_unix_pwd_getbyname.c b/src/libnsss/nsss_unix_pwd_getbyname.c
new file mode 100644
index 0000000..4d60e8c
--- /dev/null
+++ b/src/libnsss/nsss_unix_pwd_getbyname.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <string.h>
+#include <nsss/pwd-def.h>
+#include <nsss/nsss-unix.h>
+
+int nsss_unix_pwd_getbyname (nsss_unix_t *a, struct passwd *pw, stralloc *sa, char const *name)
+{
+  struct passwd pw2 ;
+  for (;;)
+  {
+    size_t base = sa->len ;
+    if (!nsss_unix_pwd_get(a, &pw2, sa)) return 0 ;
+    if (!strcmp(name, pw2.pw_name)) break ;
+    sa->len = base ;
+  }
+  *pw = pw2 ;
+  return 1 ;
+}
diff --git a/src/libnsss/nsss_unix_pwd_getbyuid.c b/src/libnsss/nsss_unix_pwd_getbyuid.c
new file mode 100644
index 0000000..4964cdd
--- /dev/null
+++ b/src/libnsss/nsss_unix_pwd_getbyuid.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <sys/types.h>
+#include <nsss/pwd-def.h>
+#include <nsss/nsss-unix.h>
+
+int nsss_unix_pwd_getbyuid (nsss_unix_t *a, struct passwd *pw, stralloc *sa, uid_t uid)
+{
+  struct passwd pw2 ;
+  for (;;)
+  {
+    size_t base = sa->len ;
+    if (!nsss_unix_pwd_get(a, &pw2, sa)) return 0 ;
+    if (uid == pw2.pw_uid) break ;
+    sa->len = base ;
+  }
+  *pw = pw2 ;
+  return 1 ;
+}
diff --git a/src/libnsss/nsss_unix_pwd_here.c b/src/libnsss/nsss_unix_pwd_here.c
new file mode 100644
index 0000000..33aa911
--- /dev/null
+++ b/src/libnsss/nsss_unix_pwd_here.c
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#include "nsss-unix-internal.h"
+
+nsss_unix_t nsss_unix_pwd_here = NSSS_UNIX_ZERO ;
diff --git a/src/libnsss/nsss_unix_rewind.c b/src/libnsss/nsss_unix_rewind.c
new file mode 100644
index 0000000..2b8c6b3
--- /dev/null
+++ b/src/libnsss/nsss_unix_rewind.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <skalibs/buffer.h>
+#include <nsss/nsss-unix.h>
+
+int nsss_unix_rewind (nsss_unix_t *a)
+{
+  int fd = buffer_fd(&a->b) ;
+  if (lseek(fd, 0, SEEK_SET) < 0) return 0 ;
+  buffer_init(&a->b, &buffer_read, fd, a->buf, NSSS_UNIX_BUFSIZE) ;
+  return 1 ;
+}
diff --git a/src/libnsss/nsss_unix_setgrent.c b/src/libnsss/nsss_unix_setgrent.c
new file mode 100644
index 0000000..e01744f
--- /dev/null
+++ b/src/libnsss/nsss_unix_setgrent.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <nsss/grp-unix.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-unix-internal.h"
+
+void nsss_unix_setgrent (void)
+{
+  if (!nsss_unix_grp_maybe_start(&nsss_unix_grp_here)) return ;
+  nsss_unix_grp_rewind(&nsss_unix_grp_here) ;
+}
diff --git a/src/libnsss/nsss_unix_setpwent.c b/src/libnsss/nsss_unix_setpwent.c
new file mode 100644
index 0000000..666680b
--- /dev/null
+++ b/src/libnsss/nsss_unix_setpwent.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <nsss/pwd-unix.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-unix-internal.h"
+
+void nsss_unix_setpwent (void)
+{
+  if (!nsss_unix_pwd_maybe_start(&nsss_unix_pwd_here)) return ;
+  nsss_unix_pwd_rewind(&nsss_unix_pwd_here) ;
+}
diff --git a/src/libnsss/nsss_unix_setspent.c b/src/libnsss/nsss_unix_setspent.c
new file mode 100644
index 0000000..2b38e8d
--- /dev/null
+++ b/src/libnsss/nsss_unix_setspent.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <nsss/shadow-unix.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-unix-internal.h"
+
+void nsss_unix_setspent (void)
+{
+  if (!nsss_unix_shadow_maybe_start(&nsss_unix_shadow_here)) return ;
+  nsss_unix_shadow_rewind(&nsss_unix_shadow_here) ;
+}
diff --git a/src/libnsss/nsss_unix_shadow_get.c b/src/libnsss/nsss_unix_shadow_get.c
new file mode 100644
index 0000000..0d87088
--- /dev/null
+++ b/src/libnsss/nsss_unix_shadow_get.c
@@ -0,0 +1,52 @@
+/* ISC license. */
+
+#include <pthread.h>
+#include <skalibs/types.h>
+#include <skalibs/skamisc.h>
+#include <nsss/shadow-def.h>
+#include <nsss/nsss-unix.h>
+#include "nsss-unix-internal.h"
+
+static inline int shadow_parseline (struct spwd *sp, char *s, size_t max)
+{
+  struct spwd sp2 ;
+  char *p ;
+  s[max-1] = 0 ;
+  if (!nsss_unix_field(&sp2.sp_namp, &s)) return 0 ;
+  if (!nsss_unix_field(&sp2.sp_pwdp, &s)) return 0 ;
+  if (!nsss_unix_field(&p, &s)) return 0 ;
+  if (!ulong0_scan(p, (unsigned long *)&sp2.sp_lstchg)) return 0 ;
+  if (!nsss_unix_field(&p, &s)) return 0 ;
+  if (!ulong0_scan(p, (unsigned long *)&sp2.sp_min)) return 0 ;
+  if (!nsss_unix_field(&p, &s)) return 0 ;
+  if (!ulong0_scan(p, (unsigned long *)&sp2.sp_max)) return 0 ;
+  if (!nsss_unix_field(&p, &s)) return 0 ;
+  if (!ulong0_scan(p, (unsigned long *)&sp2.sp_warn)) return 0 ;
+  if (!nsss_unix_field(&p, &s)) return 0 ;
+  if (!ulong0_scan(p, (unsigned long *)&sp2.sp_inact)) return 0 ;
+  if (!nsss_unix_field(&p, &s)) return 0 ;
+  if (!ulong0_scan(p, (unsigned long *)&sp2.sp_expire)) return 0 ;
+  if (!nsss_unix_field(&p, &s)) return 0 ;
+  if (!ulong0_scan(p, &sp2.sp_flag)) return 0 ;
+  *sp = sp2 ;
+  return 1 ;
+}
+
+int nsss_unix_shadow_get (nsss_unix_t *a, struct spwd *sp, stralloc *sa)
+{
+  int cs ;
+  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs) ;
+  for (;;)
+  {
+    size_t base = sa->len ;
+    if (skagetln_loose(&a->b, sa, '\n') <= 0) goto err ;
+    if (shadow_parseline(sp, sa->s + base, sa->len - base)) break ;
+    sa->len = base ;
+  }
+  pthread_setcancelstate(cs, 0) ;
+  return 1 ;
+
+ err:
+  pthread_setcancelstate(cs, 0) ;
+  return 0 ;
+}
diff --git a/src/libnsss/nsss_unix_shadow_getbyname.c b/src/libnsss/nsss_unix_shadow_getbyname.c
new file mode 100644
index 0000000..154e5ec
--- /dev/null
+++ b/src/libnsss/nsss_unix_shadow_getbyname.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <string.h>
+#include <nsss/shadow-def.h>
+#include <nsss/nsss-unix.h>
+
+int nsss_unix_shadow_getbyname (nsss_unix_t *a, struct spwd *sp, stralloc *sa, char const *name)
+{
+  struct spwd sp2 ;
+  for (;;)
+  {
+    size_t base = sa->len ;
+    if (!nsss_unix_shadow_get(a, &sp2, sa)) return 0 ;
+    if (!strcmp(name, sp2.sp_namp)) break ;
+    sa->len = base ;
+  }
+  *sp = sp2 ;
+  return 1 ;
+}
diff --git a/src/libnsss/nsss_unix_shadow_here.c b/src/libnsss/nsss_unix_shadow_here.c
new file mode 100644
index 0000000..2f500f4
--- /dev/null
+++ b/src/libnsss/nsss_unix_shadow_here.c
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#include "nsss-unix-internal.h"
+
+nsss_unix_t nsss_unix_shadow_here = NSSS_UNIX_ZERO ;
diff --git a/src/libnsss/nsss_unix_start.c b/src/libnsss/nsss_unix_start.c
new file mode 100644
index 0000000..1f6c5df
--- /dev/null
+++ b/src/libnsss/nsss_unix_start.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+#include <skalibs/djbunix.h>
+#include <nsss/nsss-unix.h>
+
+int nsss_unix_start (nsss_unix_t *a, char const *path)
+{
+  int fd = open_readb(path) ;
+  if (fd < 0) return 0 ;
+  buffer_init(&a->b, &buffer_read, fd, a->buf, NSSS_UNIX_BUFSIZE) ;
+  return 1 ;
+}
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 ;
+}
diff --git a/tools/gen-deps.sh b/tools/gen-deps.sh
new file mode 100755
index 0000000..6383ac2
--- /dev/null
+++ b/tools/gen-deps.sh
@@ -0,0 +1,93 @@
+#!/bin/sh -e
+
+. package/info
+
+echo '#'
+echo '# This file has been generated by tools/gen-deps.sh'
+echo '#'
+echo
+
+for dir in src/include/${package} src/* ; do
+  for file in $(ls -1 $dir | grep -- \\.h$) ; do
+    {
+      grep -F -- "#include <${package}/" < ${dir}/$file | cut -d'<' -f2 | cut -d'>' -f1 ;
+      grep -- '#include ".*\.h"' < ${dir}/$file | cut -d'"' -f2
+    } | sort -u | {
+      deps=
+      while read dep ; do
+        if echo $dep | grep -q "^${package}/" ; then
+          deps="$deps src/include/$dep"
+        elif test -f "${dir}/$dep" ; then
+          deps="$deps ${dir}/$dep"
+        else
+          deps="$deps src/include-local/$dep"
+        fi
+      done
+      if test -n "$deps" ; then
+        echo "${dir}/${file}:${deps}"
+      fi
+    }
+  done
+done
+
+for dir in src/* ; do
+  for file in $(ls -1 $dir | grep -- \\.c$) ; do
+    {
+      grep -F -- "#include <${package}/" < ${dir}/$file | cut -d'<' -f2 | cut -d'>' -f1 ;
+      grep -- '#include ".*\.h"' < ${dir}/$file | cut -d'"' -f2
+    } | sort -u | {
+      deps=" ${dir}/$file"
+      while read dep ; do
+        if echo $dep | grep -q "^${package}/" ; then
+          deps="$deps src/include/$dep"
+        elif test -f "${dir}/$dep" ; then
+          deps="$deps ${dir}/$dep"
+        else
+          deps="$deps src/include-local/$dep"
+        fi
+      done
+      o=$(echo $file | sed s/\\.c$/.o/)
+      lo=$(echo $file | sed s/\\.c$/.lo/)
+      echo "${dir}/${o} ${dir}/${lo}:${deps}"
+    }
+  done
+done
+echo
+
+for dir in $(ls -1 src | grep -v ^include) ; do
+  for file in $(ls -1 src/$dir/deps-lib) ; do
+    deps=
+    libs=
+    while read dep ; do
+      if echo $dep | grep -q -e ^-l -e '^\${.*_LIB}' ; then
+        libs="$libs $dep"
+      else
+        deps="$deps src/$dir/$dep"
+      fi
+    done < src/$dir/deps-lib/$file
+    echo 'ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),)'
+    echo "lib${file}.a.xyzzy:$deps"
+    echo else
+    echo "lib${file}.a.xyzzy:$(echo "$deps" | sed 's/\.o/.lo/g')"
+    echo endif
+    echo "lib${file}.so.xyzzy: EXTRA_LIBS :=$libs"
+    echo "lib${file}.so.xyzzy:$(echo "$deps" | sed 's/\.o/.lo/g')"
+  done
+
+  for file in $(ls -1 src/$dir/deps-exe) ; do
+    deps=
+    libs=
+    while read dep ; do
+      if echo $dep | grep -q -- \\.o$ ; then
+        dep="src/$dir/$dep"
+      fi
+      if echo $dep | grep -q -- '^\${.*_LIB}' ; then
+        libs="$libs $dep"
+      else
+        deps="$deps $dep"
+      fi
+    done < src/$dir/deps-exe/$file
+    echo "$file: EXTRA_LIBS :=$libs"
+    echo "$file: src/$dir/$file.o$deps"
+  done
+done
diff --git a/tools/install.sh b/tools/install.sh
new file mode 100755
index 0000000..89f9428
--- /dev/null
+++ b/tools/install.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+usage() {
+  echo "usage: $0 [-D] [-l] [-m mode] src dst" 1>&2
+  exit 1
+}
+
+mkdirp=false
+symlink=false
+mode=0755
+
+while getopts Dlm: name ; do
+  case "$name" in
+    D) mkdirp=true ;;
+    l) symlink=true ;;
+    m) mode=$OPTARG ;;
+    ?) usage ;;
+  esac
+done
+shift $(($OPTIND - 1))
+
+test "$#" -eq 2 || usage
+src=$1
+dst=$2
+tmp="$dst.tmp.$$"
+
+case "$dst" in
+  */) echo "$0: $dst ends in /" 1>&2 ; exit 1 ;;
+esac
+
+set -C
+set -e
+
+if $mkdirp ; then
+  umask 022
+  case "$2" in
+    */*) mkdir -p "${dst%/*}" ;;
+  esac
+fi
+
+trap 'rm -f "$tmp"' EXIT INT QUIT TERM HUP
+
+umask 077
+
+if $symlink ; then
+  ln -s "$src" "$tmp"
+else
+  cat < "$1" > "$tmp"
+  chmod "$mode" "$tmp"
+fi
+
+mv -f "$tmp" "$dst"
+if test -d "$dst" ; then
+  rm -f "$dst/$(basename $tmp)"
+  if $symlink ; then
+    mkdir "$tmp"
+    ln -s "$src" "$tmp/$(basename $dst)"
+    mv -f "$tmp/$(basename $dst)" "${dst%/*}"
+    rmdir "$tmp"
+  else
+    echo "$0: $dst is a directory" 1>&2
+    exit 1
+  fi
+fi