summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1998-01-31 08:39:55 +0000
committerUlrich Drepper <drepper@redhat.com>1998-01-31 08:39:55 +0000
commitd67281a7eac124e2f1b498c377dde3432f711039 (patch)
tree77832ea40d41c4c0858f1248829ad2dfdb513786
parent4eb36693e4452db4679a33c750c0738b73d1ebc5 (diff)
downloadglibc-d67281a7eac124e2f1b498c377dde3432f711039.tar.gz
glibc-d67281a7eac124e2f1b498c377dde3432f711039.tar.xz
glibc-d67281a7eac124e2f1b498c377dde3432f711039.zip
Update.
1998-01-31  Phil Blundell  <philb@gnu.org>

	* configure.in: Add --without-cvs option to suppress automatic
	checkin of regenerated files.
	* config.make: Likewise.
	* Makefile: Respect with-cvs setting.
	* Makerules: Likewise.

	* configure.in: Allow the standalone ARM port to be configured.

1998-01-31  Thorsten Kukuk  <kukuk@vt.uni-paderborn.de>

	* grp/getgrgid_r.c: Define USE_NSCD.
	* grp/getgrnam_r.c: Likewise.
	* pwd/getpwuid_r.c: Likewise.
	* pwd/getpwnam_r.c: Likewise.

	* sysdeps/unix/inet/Subdirs: Add nscd subdir.

	* nss/getXXbyYY_r.c: Try at first nscd.

	* nscd/Makefile: New, for the Name Switch Cache Daemon (nscd).
	* nscd/connections.c: New file.
	* nscd/dbg_log.c: New file.
	* nscd/dbg_log.h: New file.
	* nscd/grpcache.c: New file.
	* nscd/nscd.c: New file.
	* nscd/nscd.h: New file.
	* nscd/nscd_conf.c: New file.
	* nscd/nscd_stat.c: New file.
	* nscd/pwdcache.c: New file.

	* nscd/nscd_getgr_r.c: New, client code, linked into libc.
	* nscd/nscd_getpw_r.c: Likewise.
	* nscd/nscd_proto.h: New, prototypes for client functions.

	* nscd/nscd.conf: New, example for a configuration file.
	* nscd/nscd.init: New, example for a startup script.

	* nscd/getgrgid_r.c: Old grp/getgrgid_r version, used from nscd to
	avoid deadlocks.
	* nscd/getgrnam_r.c: Likewise.
	* nscd/getpwnam_r.c: Likewise.
	* nscd/getpwuid_r.c: Likewise.

	* nis/nis_cache.c: New file.
	* nis/nis_cache2.h: New file.
	* nis/nis_cache2_xdr.c: New file.
-rw-r--r--ChangeLog51
-rwxr-xr-xconfigure158
-rw-r--r--grp/getgrgid_r.c5
-rw-r--r--grp/getgrnam_r.c5
-rw-r--r--nscd/Makefile46
-rw-r--r--nscd/TODO7
-rw-r--r--nscd/connections.c529
-rw-r--r--nscd/dbg_log.c64
-rw-r--r--nscd/dbg_log.h27
-rw-r--r--nscd/getgrgid_r.c30
-rw-r--r--nscd/getgrnam_r.c29
-rw-r--r--nscd/getpwnam_r.c30
-rw-r--r--nscd/getpwuid_r.c30
-rw-r--r--nscd/grpcache.c589
-rw-r--r--nscd/nscd.c423
-rw-r--r--nscd/nscd.conf30
-rw-r--r--nscd/nscd.h149
-rw-r--r--nscd/nscd.init50
-rw-r--r--nscd/nscd_conf.c148
-rw-r--r--nscd/nscd_getgr_r.c211
-rw-r--r--nscd/nscd_getpw_r.c198
-rw-r--r--nscd/nscd_proto.h35
-rw-r--r--nscd/nscd_stat.c87
-rw-r--r--nscd/pwdcache.c581
-rw-r--r--nss/getXXbyYY_r.c21
-rw-r--r--pwd/getpwnam_r.c5
-rw-r--r--pwd/getpwuid_r.c5
-rw-r--r--sysdeps/unix/inet/Subdirs1
28 files changed, 3459 insertions, 85 deletions
diff --git a/ChangeLog b/ChangeLog
index 7bfd1af411..ea73c1c753 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,48 @@
+1998-01-31  Phil Blundell  <philb@gnu.org>
+
+	* configure.in: Add --without-cvs option to suppress automatic
+	checkin of regenerated files.
+	* config.make: Likewise.
+	* Makefile: Respect with-cvs setting.
+	* Makerules: Likewise.
+
+	* configure.in: Allow the standalone ARM port to be configured.
+
+1998-01-31  Thorsten Kukuk  <kukuk@vt.uni-paderborn.de>
+
+	* grp/getgrgid_r.c: Define USE_NSCD.
+	* grp/getgrnam_r.c: Likewise.
+	* pwd/getpwuid_r.c: Likewise.
+	* pwd/getpwnam_r.c: Likewise.
+
+	* sysdeps/unix/inet/Subdirs: Add nscd subdir.
+
+	* nss/getXXbyYY_r.c: Try at first nscd.
+
+	* nscd/Makefile: New, for the Name Switch Cache Daemon (nscd).
+	* nscd/connections.c: New file.
+	* nscd/dbg_log.c: New file.
+	* nscd/dbg_log.h: New file.
+	* nscd/grpcache.c: New file.
+	* nscd/nscd.c: New file.
+	* nscd/nscd.h: New file.
+	* nscd/nscd_conf.c: New file.
+	* nscd/nscd_stat.c: New file.
+	* nscd/pwdcache.c: New file.
+
+	* nscd/nscd_getgr_r.c: New, client code, linked into libc.
+	* nscd/nscd_getpw_r.c: Likewise.
+	* nscd/nscd_proto.h: New, prototypes for client functions.
+
+	* nscd/nscd.conf: New, example for a configuration file.
+	* nscd/nscd.init: New, example for a startup script.
+
+	* nscd/getgrgid_r.c: Old grp/getgrgid_r version, used from nscd to
+	avoid deadlocks.
+	* nscd/getgrnam_r.c: Likewise.
+	* nscd/getpwnam_r.c: Likewise.
+	* nscd/getpwuid_r.c: Likewise.
+
 1998-01-31 11:44  Ulrich Drepper  <drepper@cygnus.com>
 
 	* intl/Makefile: Use CVSOPTS in cvs invocation.
@@ -520,9 +565,9 @@
 
 	* nis/Makefile: Distribute nis_cache2.h, add nis cache functions
 	to routines.
-	* nis/nis_cache.c: New.
-	* nis/nis_cache2.h: New.
-	* nis/nis_cache2_xdr.c: New.
+	* nis/nis_cache.c: New file.
+	* nis/nis_cache2.h: New file.
+	* nis/nis_cache2_xdr.c: New file.
 	* nis/nis_call.c: Changes for cache2_info parameter.
 	* nis/nis_checkpoint.c: Likewise.
 	* nis/nis_intern.h: Likewise.
diff --git a/configure b/configure
index 185ad96fc9..473ab075d9 100755
--- a/configure
+++ b/configure
@@ -31,6 +31,8 @@ ac_help="$ac_help
 ac_help="$ac_help
   --with-elf		  if using the ELF object format"
 ac_help="$ac_help
+  --without-cvs	  if CVS should not be used"
+ac_help="$ac_help
   --enable-libio          build in GNU libio instead of GNU stdio"
 ac_help="$ac_help
   --disable-sanity-checks really do not use threads (should not be used
@@ -618,6 +620,15 @@ else
   elf=no
 fi
 
+# Check whether --with-cvs or --without-cvs was given.
+if test "${with_cvs+set}" = set; then
+  withval="$with_cvs"
+  with_cvs=$withval
+else
+  with_cvs=yes
+fi
+
+
 
 # Check whether --enable-libio or --disable-libio was given.
 if test "${enable_libio+set}" = set; then
@@ -762,7 +773,7 @@ else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
 fi
 
 echo $ac_n "checking host system type""... $ac_c" 1>&6
-echo "configure:766: checking host system type" >&5
+echo "configure:777: checking host system type" >&5
 
 host_alias=$host
 case "$host_alias" in
@@ -805,8 +816,8 @@ esac
 ### platforms.
 ###
 if test -z "$enable_hacker_mode"; then
-  case "$host_os" in
-  linux* | gnu*)
+  case "$machine-$host_os" in
+  *-linux* | *-gnu* | arm*-none*)
     ;;
   *)
     echo "*** The GNU C library is currently not available for this platform."
@@ -881,7 +892,7 @@ fi
 # This can take a while to compute.
 sysdep_dir=$srcdir/sysdeps
 echo $ac_n "checking sysdep dirs""... $ac_c" 1>&6
-echo "configure:885: checking sysdep dirs" >&5
+echo "configure:896: checking sysdep dirs" >&5
 # Make sco3.2v4 become sco3.2.4 and sunos4.1.1_U1 become sunos4.1.1.U1.
 os="`echo $os | sed 's/\([0-9A-Z]\)[v_]\([0-9A-Z]\)/\1.\2/g'`"
 
@@ -1082,7 +1093,7 @@ echo "$ac_t""sysdeps/generic" 1>&6
 # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
 # ./install, which can be erroneously created by make from ./install.sh.
 echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
-echo "configure:1086: checking for a BSD compatible install" >&5
+echo "configure:1097: checking for a BSD compatible install" >&5
 if test -z "$INSTALL"; then
 if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1136,7 +1147,7 @@ if test "$INSTALL" = "${srcdir}/install-sh -c"; then
   INSTALL='\$(..)./install-sh -c'
 fi
 echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
-echo "configure:1140: checking whether ln -s works" >&5
+echo "configure:1151: checking whether ln -s works" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1161,7 +1172,7 @@ do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1165: checking for $ac_word" >&5
+echo "configure:1176: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_MSGFMT'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1193,7 +1204,7 @@ test -n "$MSGFMT" || MSGFMT=":"
 # Extract the first word of "makeinfo", so it can be a program name with args.
 set dummy makeinfo; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1197: checking for $ac_word" >&5
+echo "configure:1208: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_MAKEINFO'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1233,7 +1244,7 @@ fi
 # Extract the first word of "gcc", so it can be a program name with args.
 set dummy gcc; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1237: checking for $ac_word" >&5
+echo "configure:1248: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1262,7 +1273,7 @@ if test -z "$CC"; then
   # Extract the first word of "cc", so it can be a program name with args.
 set dummy cc; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1266: checking for $ac_word" >&5
+echo "configure:1277: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1310,7 +1321,7 @@ fi
 fi
 
 echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
-echo "configure:1314: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+echo "configure:1325: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
 
 ac_ext=c
 # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
@@ -1320,11 +1331,11 @@ ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS
 cross_compiling=$ac_cv_prog_cc_cross
 
 cat > conftest.$ac_ext <<EOF
-#line 1324 "configure"
+#line 1335 "configure"
 #include "confdefs.h"
 main(){return(0);}
 EOF
-if { (eval echo configure:1328: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:1339: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
   ac_cv_prog_cc_works=yes
   # If we can't run a trivial program, we are probably using a cross compiler.
   if (./conftest; exit) 2>/dev/null; then
@@ -1347,13 +1358,13 @@ else
  cross_linkable=yes
 fi
 echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
-echo "configure:1351: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "configure:1362: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
 
 cross_compiling=$ac_cv_prog_cc_cross
 
 echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
-echo "configure:1357: checking whether we are using GNU C" >&5
+echo "configure:1368: checking whether we are using GNU C" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1362,7 +1373,7 @@ else
   yes;
 #endif
 EOF
-if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1366: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1377: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
   ac_cv_prog_gcc=yes
 else
   ac_cv_prog_gcc=no
@@ -1379,7 +1390,7 @@ if test $ac_cv_prog_gcc = yes; then
   yes;
 #endif
 EOF
-  if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1383: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1394: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
     if test -z "$CFLAGS"; then
       CFLAGS="-g -O2"
     fi
@@ -1391,7 +1402,7 @@ else
 fi
 
 echo $ac_n "checking build system type""... $ac_c" 1>&6
-echo "configure:1395: checking build system type" >&5
+echo "configure:1406: checking build system type" >&5
 
 build_alias=$build
 case "$build_alias" in
@@ -1414,7 +1425,7 @@ do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1418: checking for $ac_word" >&5
+echo "configure:1429: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_BUILD_CC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1445,7 +1456,7 @@ done
 fi
 
 echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
-echo "configure:1449: checking how to run the C preprocessor" >&5
+echo "configure:1460: checking how to run the C preprocessor" >&5
 # On Suns, sometimes $CPP names a directory.
 if test -n "$CPP" && test -d "$CPP"; then
   CPP=
@@ -1460,13 +1471,13 @@ else
   # On the NeXT, cc -E runs the code through the compiler's parser,
   # not just through cpp.
   cat > conftest.$ac_ext <<EOF
-#line 1464 "configure"
+#line 1475 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1470: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1481: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out`
 if test -z "$ac_err"; then
   :
@@ -1477,13 +1488,13 @@ else
   rm -rf conftest*
   CPP="${CC-cc} -E -traditional-cpp"
   cat > conftest.$ac_ext <<EOF
-#line 1481 "configure"
+#line 1492 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1487: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1498: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out`
 if test -z "$ac_err"; then
   :
@@ -1516,7 +1527,7 @@ LD=`$CC -print-file-name=ld`
 
 # Determine whether we are using GNU binutils.
 echo $ac_n "checking whether $AS is GNU as""... $ac_c" 1>&6
-echo "configure:1520: checking whether $AS is GNU as" >&5
+echo "configure:1531: checking whether $AS is GNU as" >&5
 if eval "test \"`echo '$''{'libc_cv_prog_as_gnu'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1534,7 +1545,7 @@ rm -f a.out
 gnu_as=$libc_cv_prog_as_gnu
 
 echo $ac_n "checking whether $LD is GNU ld""... $ac_c" 1>&6
-echo "configure:1538: checking whether $LD is GNU ld" >&5
+echo "configure:1549: checking whether $LD is GNU ld" >&5
 if eval "test \"`echo '$''{'libc_cv_prog_ld_gnu'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1558,7 +1569,7 @@ fi
 # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
 set dummy ${ac_tool_prefix}ar; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1562: checking for $ac_word" >&5
+echo "configure:1573: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1589,7 +1600,7 @@ fi
 # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
 set dummy ${ac_tool_prefix}ranlib; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1593: checking for $ac_word" >&5
+echo "configure:1604: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1620,7 +1631,7 @@ if test -n "$ac_tool_prefix"; then
   # Extract the first word of "ranlib", so it can be a program name with args.
 set dummy ranlib; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1624: checking for $ac_word" >&5
+echo "configure:1635: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1655,7 +1666,7 @@ fi
 # Extract the first word of "bash", so it can be a program name with args.
 set dummy bash; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1659: checking for $ac_word" >&5
+echo "configure:1670: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_BASH'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1697,7 +1708,7 @@ if test "$BASH" = no; then
   # Extract the first word of "ksh", so it can be a program name with args.
 set dummy ksh; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1701: checking for $ac_word" >&5
+echo "configure:1712: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_KSH'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1743,7 +1754,7 @@ do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1747: checking for $ac_word" >&5
+echo "configure:1758: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_PERL'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1778,7 +1789,7 @@ test -n "$PERL" || PERL="no"
 
 
 echo $ac_n "checking for signed size_t type""... $ac_c" 1>&6
-echo "configure:1782: checking for signed size_t type" >&5
+echo "configure:1793: checking for signed size_t type" >&5
 if eval "test \"`echo '$''{'libc_cv_signed_size_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1802,12 +1813,12 @@ EOF
 fi
 
 echo $ac_n "checking for libc-friendly stddef.h""... $ac_c" 1>&6
-echo "configure:1806: checking for libc-friendly stddef.h" >&5
+echo "configure:1817: checking for libc-friendly stddef.h" >&5
 if eval "test \"`echo '$''{'libc_cv_friendly_stddef'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1811 "configure"
+#line 1822 "configure"
 #include "confdefs.h"
 #define __need_size_t
 #define __need_wchar_t
@@ -1822,7 +1833,7 @@ size_t size; wchar_t wchar;
 if (&size == NULL || &wchar == NULL) abort ();
 ; return 0; }
 EOF
-if { (eval echo configure:1826: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1837: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   libc_cv_friendly_stddef=yes
 else
@@ -1841,7 +1852,7 @@ override stddef.h = # The installed <stddef.h> seems to be libc-friendly."
 fi
 
 echo $ac_n "checking whether we need to use -P to assemble .S files""... $ac_c" 1>&6
-echo "configure:1845: checking whether we need to use -P to assemble .S files" >&5
+echo "configure:1856: checking whether we need to use -P to assemble .S files" >&5
 if eval "test \"`echo '$''{'libc_cv_need_minus_P'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1872,7 +1883,7 @@ if test $ac_cv_prog_gcc = yes; then
   # We must check this even if -pipe is not given here, because the user
   # might do `make CFLAGS=-pipe'.
   echo $ac_n "checking for gcc 2.7.x -pipe bug""... $ac_c" 1>&6
-echo "configure:1876: checking for gcc 2.7.x -pipe bug" >&5
+echo "configure:1887: checking for gcc 2.7.x -pipe bug" >&5
 if eval "test \"`echo '$''{'libc_cv_gcc_pipe_bug'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1901,7 +1912,7 @@ else
 fi
 
 echo $ac_n "checking for assembler global-symbol directive""... $ac_c" 1>&6
-echo "configure:1905: checking for assembler global-symbol directive" >&5
+echo "configure:1916: checking for assembler global-symbol directive" >&5
 if eval "test \"`echo '$''{'libc_cv_asm_global_directive'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1931,7 +1942,7 @@ EOF
 fi
 
 echo $ac_n "checking for .set assembler directive""... $ac_c" 1>&6
-echo "configure:1935: checking for .set assembler directive" >&5
+echo "configure:1946: checking for .set assembler directive" >&5
 if eval "test \"`echo '$''{'libc_cv_asm_set_directive'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1965,7 +1976,7 @@ EOF
 fi
 
 echo $ac_n "checking for .symver assembler directive""... $ac_c" 1>&6
-echo "configure:1969: checking for .symver assembler directive" >&5
+echo "configure:1980: checking for .symver assembler directive" >&5
 if eval "test \"`echo '$''{'libc_cv_asm_symver_directive'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1984,7 +1995,7 @@ fi
 
 echo "$ac_t""$libc_cv_asm_symver_directive" 1>&6
 echo $ac_n "checking for ld --version-script""... $ac_c" 1>&6
-echo "configure:1988: checking for ld --version-script" >&5
+echo "configure:1999: checking for ld --version-script" >&5
 if eval "test \"`echo '$''{'libc_cv_ld_version_script_option'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2007,7 +2018,7 @@ EOF
     if { ac_try='${CC-cc} $CFLAGS -shared -o conftest.so conftest.o
 					-nostartfiles -nostdlib
 					-Wl,--version-script,conftest.map
-		       1>&5'; { (eval echo configure:2011: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; };
+		       1>&5'; { (eval echo configure:2022: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; };
     then
       libc_cv_ld_version_script_option=yes
     else
@@ -2045,7 +2056,7 @@ if test $VERSIONING = no; then
 fi
 if test $elf = yes; then
   echo $ac_n "checking for .previous assembler directive""... $ac_c" 1>&6
-echo "configure:2049: checking for .previous assembler directive" >&5
+echo "configure:2060: checking for .previous assembler directive" >&5
 if eval "test \"`echo '$''{'libc_cv_asm_previous_directive'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2053,7 +2064,7 @@ else
 .section foo_section
 .previous
 EOF
-  if { ac_try='${CC-cc} -c $CFLAGS conftest.s 1>&5'; { (eval echo configure:2057: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then
+  if { ac_try='${CC-cc} -c $CFLAGS conftest.s 1>&5'; { (eval echo configure:2068: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then
     libc_cv_asm_previous_directive=yes
   else
     libc_cv_asm_previous_directive=no
@@ -2069,7 +2080,7 @@ EOF
 
   else
     echo $ac_n "checking for .popsection assembler directive""... $ac_c" 1>&6
-echo "configure:2073: checking for .popsection assembler directive" >&5
+echo "configure:2084: checking for .popsection assembler directive" >&5
 if eval "test \"`echo '$''{'libc_cv_asm_popsection_directive'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2077,7 +2088,7 @@ else
 .pushsection foo_section
 .popsection
 EOF
-    if { ac_try='${CC-cc} -c $CFLAGS conftest.s 1>&5'; { (eval echo configure:2081: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then
+    if { ac_try='${CC-cc} -c $CFLAGS conftest.s 1>&5'; { (eval echo configure:2092: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then
       libc_cv_asm_popsection_directive=yes
     else
       libc_cv_asm_popsection_directive=no
@@ -2097,12 +2108,12 @@ fi
 
 if test $elf != yes; then
   echo $ac_n "checking for .init and .fini sections""... $ac_c" 1>&6
-echo "configure:2101: checking for .init and .fini sections" >&5
+echo "configure:2112: checking for .init and .fini sections" >&5
 if eval "test \"`echo '$''{'libc_cv_have_initfini'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2106 "configure"
+#line 2117 "configure"
 #include "confdefs.h"
 
 int main() {
@@ -2111,7 +2122,7 @@ asm (".section .init");
 				    asm (".text");
 ; return 0; }
 EOF
-if { (eval echo configure:2115: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2126: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   libc_cv_have_initfini=yes
 else
@@ -2139,19 +2150,19 @@ if test $elf = yes; then
 else
   if test $ac_cv_prog_cc_works = yes; then
     echo $ac_n "checking for _ prefix on C symbol names""... $ac_c" 1>&6
-echo "configure:2143: checking for _ prefix on C symbol names" >&5
+echo "configure:2154: checking for _ prefix on C symbol names" >&5
 if eval "test \"`echo '$''{'libc_cv_asm_underscores'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2148 "configure"
+#line 2159 "configure"
 #include "confdefs.h"
 asm ("_glibc_foobar:");
 int main() {
 glibc_foobar ();
 ; return 0; }
 EOF
-if { (eval echo configure:2155: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+if { (eval echo configure:2166: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
   rm -rf conftest*
   libc_cv_asm_underscores=yes
 else
@@ -2166,17 +2177,17 @@ fi
 echo "$ac_t""$libc_cv_asm_underscores" 1>&6
   else
     echo $ac_n "checking for _ prefix on C symbol names""... $ac_c" 1>&6
-echo "configure:2170: checking for _ prefix on C symbol names" >&5
+echo "configure:2181: checking for _ prefix on C symbol names" >&5
 if eval "test \"`echo '$''{'libc_cv_asm_underscores'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2175 "configure"
+#line 2186 "configure"
 #include "confdefs.h"
 void underscore_test(void) {
 return; }
 EOF
-if { (eval echo configure:2180: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2191: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   if grep _underscore_test conftest* >/dev/null; then
     rm -f conftest*
     libc_cv_asm_underscores=yes
@@ -2209,7 +2220,7 @@ if test $elf = yes; then
   libc_cv_asm_weakext_directive=no
 else
   echo $ac_n "checking for assembler .weak directive""... $ac_c" 1>&6
-echo "configure:2213: checking for assembler .weak directive" >&5
+echo "configure:2224: checking for assembler .weak directive" >&5
 if eval "test \"`echo '$''{'libc_cv_asm_weak_directive'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2232,7 +2243,7 @@ echo "$ac_t""$libc_cv_asm_weak_directive" 1>&6
 
 if test $libc_cv_asm_weak_directive = no; then
   echo $ac_n "checking for assembler .weakext directive""... $ac_c" 1>&6
-echo "configure:2236: checking for assembler .weakext directive" >&5
+echo "configure:2247: checking for assembler .weakext directive" >&5
 if eval "test \"`echo '$''{'libc_cv_asm_weakext_directive'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2269,7 +2280,7 @@ EOF
 fi
 
 echo $ac_n "checking for ld --no-whole-archive""... $ac_c" 1>&6
-echo "configure:2273: checking for ld --no-whole-archive" >&5
+echo "configure:2284: checking for ld --no-whole-archive" >&5
 if eval "test \"`echo '$''{'libc_cv_ld_no_whole_archive'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2280,7 +2291,7 @@ __throw () {}
 EOF
 if { ac_try='${CC-cc} $CFLAGS
 			    -nostdlib -nostartfiles -Wl,--no-whole-archive
-			    -o conftest conftest.c 1>&5'; { (eval echo configure:2284: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then
+			    -o conftest conftest.c 1>&5'; { (eval echo configure:2295: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then
   libc_cv_ld_no_whole_archive=yes
 else
   libc_cv_ld_no_whole_archive=no
@@ -2291,7 +2302,7 @@ fi
 echo "$ac_t""$libc_cv_ld_no_whole_archive" 1>&6
 
 echo $ac_n "checking for gcc -fno-exceptions""... $ac_c" 1>&6
-echo "configure:2295: checking for gcc -fno-exceptions" >&5
+echo "configure:2306: checking for gcc -fno-exceptions" >&5
 if eval "test \"`echo '$''{'libc_cv_gcc_no_exceptions'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2302,7 +2313,7 @@ __throw () {}
 EOF
 if { ac_try='${CC-cc} $CFLAGS
 			    -nostdlib -nostartfiles -fno-exceptions
-			    -o conftest conftest.c 1>&5'; { (eval echo configure:2306: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then
+			    -o conftest conftest.c 1>&5'; { (eval echo configure:2317: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then
   libc_cv_gcc_no_exceptions=yes
 else
   libc_cv_gcc_no_exceptions=no
@@ -2314,14 +2325,14 @@ echo "$ac_t""$libc_cv_gcc_no_exceptions" 1>&6
 
 if test "$base_machine" = alpha ; then
 echo $ac_n "checking for function ..ng prefix""... $ac_c" 1>&6
-echo "configure:2318: checking for function ..ng prefix" >&5
+echo "configure:2329: checking for function ..ng prefix" >&5
 if eval "test \"`echo '$''{'libc_cv_gcc_alpha_ng_prefix'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.c <<\EOF
 foo () { }
 EOF
-if { ac_try='${CC-cc} -S conftest.c -o - | fgrep "\$foo..ng" > /dev/null'; { (eval echo configure:2325: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; };
+if { ac_try='${CC-cc} -S conftest.c -o - | fgrep "\$foo..ng" > /dev/null'; { (eval echo configure:2336: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; };
 then
   libc_cv_gcc_alpha_ng_prefix=yes
 else
@@ -2345,12 +2356,12 @@ fi
 fi
 
 echo $ac_n "checking for DWARF2 unwind info support""... $ac_c" 1>&6
-echo "configure:2349: checking for DWARF2 unwind info support" >&5
+echo "configure:2360: checking for DWARF2 unwind info support" >&5
 if eval "test \"`echo '$''{'libc_cv_gcc_dwarf2_unwind_info'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.c <<EOF
-#line 2354 "configure"
+#line 2365 "configure"
 static char __EH_FRAME_BEGIN__;
 _start ()
 {
@@ -2377,7 +2388,7 @@ __bzero () {}
 EOF
 if { ac_try='${CC-cc} $CFLAGS -DCHECK__register_frame_info
 			    -nostdlib -nostartfiles
-			    -o conftest conftest.c -lgcc >&5'; { (eval echo configure:2381: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then
+			    -o conftest conftest.c -lgcc >&5'; { (eval echo configure:2392: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then
   libc_cv_gcc_dwarf2_unwind_info=static
 else
   libc_cv_gcc_dwarf2_unwind_info=no
@@ -2385,7 +2396,7 @@ fi
 if test $libc_cv_gcc_dwarf2_unwind_info = no; then
   if { ac_try='${CC-cc} $CFLAGS -DCHECK__register_frame
 			      -nostdlib -nostartfiles
-			      -o conftest conftest.c -lgcc >&5'; { (eval echo configure:2389: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then
+			      -o conftest conftest.c -lgcc >&5'; { (eval echo configure:2400: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then
     libc_cv_gcc_dwarf2_unwind_info=yes
   else
     libc_cv_gcc_dwarf2_unwind_info=no
@@ -2456,7 +2467,7 @@ if test "$uname" = "sysdeps/generic"; then
   fi
 
   echo $ac_n "checking OS release for uname""... $ac_c" 1>&6
-echo "configure:2460: checking OS release for uname" >&5
+echo "configure:2471: checking OS release for uname" >&5
 if eval "test \"`echo '$''{'libc_cv_uname_release'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2478,7 +2489,7 @@ echo "$ac_t""$libc_cv_uname_release" 1>&6
   uname_release="$libc_cv_uname_release"
 
   echo $ac_n "checking OS version for uname""... $ac_c" 1>&6
-echo "configure:2482: checking OS version for uname" >&5
+echo "configure:2493: checking OS version for uname" >&5
 if eval "test \"`echo '$''{'libc_cv_uname_version'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2500,7 +2511,7 @@ else
 fi
 
 echo $ac_n "checking stdio selection""... $ac_c" 1>&6
-echo "configure:2504: checking stdio selection" >&5
+echo "configure:2515: checking stdio selection" >&5
 
 case $stdio in
 libio) cat >> confdefs.h <<\EOF
@@ -2512,7 +2523,7 @@ esac
 echo "$ac_t""$stdio" 1>&6
 
 echo $ac_n "checking ldap selection""... $ac_c" 1>&6
-echo "configure:2516: checking ldap selection" >&5
+echo "configure:2527: checking ldap selection" >&5
 
 case $add_ons in
 *ldap*)
@@ -2574,7 +2585,7 @@ if test $static = no && test $shared = yes; then
 fi
 
 echo $ac_n "checking whether -fPIC is default""... $ac_c" 1>&6
-echo "configure:2578: checking whether -fPIC is default" >&5
+echo "configure:2589: checking whether -fPIC is default" >&5
 if eval "test \"`echo '$''{'pic_default'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2756,6 +2767,7 @@ s%@includedir@%$includedir%g
 s%@oldincludedir@%$oldincludedir%g
 s%@infodir@%$infodir%g
 s%@mandir@%$mandir%g
+s%@with_cvs@%$with_cvs%g
 s%@subdirs@%$subdirs%g
 s%@host@%$host%g
 s%@host_alias@%$host_alias%g
diff --git a/grp/getgrgid_r.c b/grp/getgrgid_r.c
index 8f05ae5060..8d5122a2cd 100644
--- a/grp/getgrgid_r.c
+++ b/grp/getgrgid_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
@@ -26,5 +26,6 @@
 #define ADD_PARAMS	gid_t gid
 #define ADD_VARIABLES	gid
 #define BUFLEN		NSS_BUFLEN_GROUP
+#define USE_NSCD	1
 
-#include "../nss/getXXbyYY_r.c"
+#include <nss/getXXbyYY_r.c>
diff --git a/grp/getgrnam_r.c b/grp/getgrnam_r.c
index eb34c1f777..ee84cfe5ec 100644
--- a/grp/getgrnam_r.c
+++ b/grp/getgrnam_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
@@ -25,5 +25,6 @@
 #define DATABASE_NAME	group
 #define ADD_PARAMS	const char *name
 #define ADD_VARIABLES	name
+#define USE_NSCD	1
 
-#include "../nss/getXXbyYY_r.c"
+#include <nss/getXXbyYY_r.c>
diff --git a/nscd/Makefile b/nscd/Makefile
new file mode 100644
index 0000000000..4510c4d452
--- /dev/null
+++ b/nscd/Makefile
@@ -0,0 +1,46 @@
+# Copyright (C) 1998 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Library General Public License for more details.
+
+# You should have received a copy of the GNU Library General Public
+# License along with the GNU C Library; see the file COPYING.LIB.  If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+#
+#	Sub-makefile for nscd portion of the library.
+#
+subdir	:= nscd
+
+routines := nscd_getpw_r nscd_getgr_r
+
+# We can later add the names of other thread packages here.
+ifeq (,$(findstring linuxthreads,$(add-ons)))
+
+others := nscd
+install-sbin := nscd
+
+endif
+
+nscd-routines := nscd connections pwdcache getpwnam_r getpwuid_r grpcache\
+		 getgrnam_r getgrgid_r dbg_log nscd_conf nscd_stat
+extra-objs := $(nscd-routines:=.o)
+
+distribute := nscd.h dbg_log.h
+
+include ../Rules
+
+ifeq ($(build-shared),yes)
+$(objpfx)nscd: $(nscd-routines:%=$(objpfx)%.o) $(objpfx)../linuxthreads/libpthread.so$(libpthread.so-version) $(objpfx)../nis/libnsl.so$(libnsl.so-version)
+else
+$(objpfx)nscd: $(nscd-routines:%=$(objpfx)%.o) $(objpfx)../linuxthreads/libpthread.a $(objpfx)../nis/libnsl.a
+endif
diff --git a/nscd/TODO b/nscd/TODO
new file mode 100644
index 0000000000..16c2835468
--- /dev/null
+++ b/nscd/TODO
@@ -0,0 +1,7 @@
+
+* We should use readv/writev for group entries, too
+
+* If we have reached the max. # of process, close accept socket.
+  ! THIS COULD CAUSE THE KERNEL TO HANG ! BE CAREFUL !
+
+* Implement cache for hosts
diff --git a/nscd/connections.c b/nscd/connections.c
new file mode 100644
index 0000000000..abde747a8a
--- /dev/null
+++ b/nscd/connections.c
@@ -0,0 +1,529 @@
+/* Copyright (c) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA. */
+
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <libintl.h>
+#include <locale.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+
+#include "nscd.h"
+#include "dbg_log.h"
+
+/* Socket 0 in the array is named and exported into the file namespace
+   as a connection point for clients.  */
+static int sock[MAX_NUM_CONNECTIONS];
+static int socks_active;
+static fd_set read_set;
+static pthread_mutex_t sock_lock = PTHREAD_MUTEX_INITIALIZER;
+
+
+/* Cleanup.  */
+void
+close_sockets (void)
+{
+  int i;
+
+  if (debug_flag)
+    dbg_log (_("close_sockets called"));
+
+  pthread_mutex_lock (&sock_lock);
+
+  /* Close sockets.  */
+  for (i = 0; i < MAX_NUM_CONNECTIONS; ++i)
+    if (sock[i] != 0)
+      {
+	if (close (sock[i]))
+	  dbg_log (_("socket [%d|%d] close: %s"), strerror (errno));
+
+	sock[i] = 0;
+	--socks_active;
+      }
+
+  pthread_mutex_unlock (&sock_lock);
+}
+
+void
+close_socket (int conn)
+{
+  if (debug_flag > 2)
+    dbg_log (_("close socket (%d|%d)"), conn, sock[conn]);
+
+  pthread_mutex_lock (&sock_lock);
+
+  close (sock[conn]);
+  sock[conn] = 0;
+  --socks_active;
+
+  pthread_mutex_unlock (&sock_lock);
+}
+
+/* Local rountine, assigns a socket to a new connection request.  */
+static void
+handle_new_connection (void)
+{
+  int i;
+
+  if (debug_flag > 2)
+    dbg_log (_("handle_new_connection"));
+
+  pthread_mutex_lock (&sock_lock);
+
+  if (socks_active < MAX_NUM_CONNECTIONS)
+    /* Find a free socket entry to use.  */
+    for (i = 1; i < MAX_NUM_CONNECTIONS; ++i)
+      {
+	if (sock[i] == 0)
+	  {
+	    if ((sock[i] = accept (sock[0], NULL, NULL)) < 0)
+	      {
+		dbg_log (_("socket accept: %s"), strerror (errno));
+		return;
+	      }
+	    ++socks_active;
+	    FD_SET (sock[i], &read_set);
+	    if (debug_flag > 2)
+	      dbg_log (_("handle_new_connection used socket %d|%d"), i,
+		       sock[i]);
+	    break;
+	  }
+      }
+  else
+    {
+      int black_widow_sock;
+      dbg_log (_("Supported number of simultainious connections exceeded"));
+      dbg_log (_("Ignoring client connect request"));
+      /* There has to be a better way to ignore a connection request,..
+	 when I get my hands on a sockets wiz I'll modify this.  */
+      black_widow_sock  = accept (sock[0], NULL, NULL);
+      close (black_widow_sock);
+    }
+  pthread_mutex_unlock (&sock_lock);
+}
+
+/* Local routine, reads a request off a socket indicated by a selectset.  */
+static int
+handle_new_request (fd_set read_selects, int **connp, request_header **reqp,
+		    char **key)
+{
+  ssize_t nbytes;
+  int i;
+
+  if (debug_flag)
+    dbg_log ("handle_new_request");
+
+  /* Find the descriptor.  */
+  for (i = 1; i < MAX_NUM_CONNECTIONS; ++i)
+    if (FD_ISSET(sock[i], &read_selects))
+      break;
+
+  if (debug_flag > 2)
+    dbg_log (_("handle_new_request uses socket %d"), i);
+
+  /* Read from it.  */
+  nbytes = read (sock[i], *reqp, sizeof (request_header));
+  if (nbytes != sizeof (request_header))
+    {
+      /* Handle non-data read cases.  */
+      if (nbytes == 0)
+	{
+	  /* Close socket down.  */
+	  if (debug_flag > 2)
+	    dbg_log (_("Real close socket %d|%d"), i, sock[i]);
+
+	  pthread_mutex_lock (&sock_lock);
+	  FD_CLR (sock[i], &read_set);
+	  close (sock[i]);
+	  sock[i] = 0;
+	  --socks_active;
+	  pthread_mutex_unlock (&sock_lock);
+	}
+      else
+	if (nbytes < 0)
+	  {
+	    dbg_log (_("Read(%d|%d) error on get request: %s"),
+		     i, sock[i], strerror (errno));
+	    exit (1);
+	  }
+	else
+	  dbg_log (_("Read, data < request buf size, ignoring data"));
+
+      return -1;
+    }
+  else
+    {
+      *key = malloc ((*reqp)->key_len + 1);
+      /* Read the key from it */
+      nbytes = read (sock[i], *key, (*reqp)->key_len);
+      if (nbytes != (*reqp)->key_len)
+	{
+	  /* Handle non-data read cases.  */
+	  if (nbytes == 0)
+	    {
+	      /* Close socket down.  */
+	      if (debug_flag > 2)
+		dbg_log (_("Real close socket %d|%d"), i, sock[i]);
+
+	      pthread_mutex_lock (&sock_lock);
+	      FD_CLR (sock[i], &read_set);
+	      close (sock[i]);
+	      sock[i] = 0;
+	      --socks_active;
+	      pthread_mutex_unlock (&sock_lock);
+	    }
+	  else
+	    if (nbytes < 0)
+	      {
+		perror (_("Read() error on get request"));
+		return 0;
+	      }
+	    else
+	      fputs (_("Read, data < request buf size, ignoring data"),
+		     stderr);
+
+	  free (*key);
+	  return -1;
+	}
+      else
+	{
+	  /* Ok, have a live one, A real data req buf has been obtained.  */
+	  (*key)[(*reqp)->key_len] = '\0';
+	  **connp = i;
+	  return 0;
+	}
+    }
+}
+
+void
+get_request (int *conn, request_header *req, char **key)
+{
+  int i, nr, done = 0;
+  fd_set read_selects;
+
+  if (debug_flag)
+    dbg_log ("get_request");
+
+  /* loop, processing new connection requests until a client buffer
+     is read in on an existing connection.  */
+  while (!done)
+    {
+      /* Set up the socket descriptor mask for the select.
+	 copy read_set into the local copy.  */
+
+      FD_ZERO (&read_selects);
+      pthread_mutex_lock (&sock_lock);
+      for (i = 0; i < MAX_NUM_CONNECTIONS; ++i)
+	{
+	  if (FD_ISSET (sock[i], &read_set))
+	    FD_SET (sock[i], &read_selects);
+	}
+      pthread_mutex_unlock (&sock_lock);
+      /* Poll active connections using select().  */
+      nr = select (FD_SETSIZE, &read_selects, NULL, NULL, NULL);
+      if (nr <= 0)
+	{
+	  perror (_("Select new reads"));
+	  exit (1);
+	}
+      if (FD_ISSET (sock[0], &read_selects))
+	/* Handle the case of a new connection request on the named socket.  */
+	handle_new_connection ();
+      else
+	{
+	  /* Read data from client specific descriptor.  */
+	  if (handle_new_request (read_selects, &conn, &req, key) == 0)
+	    {
+	      FD_CLR (sock[*conn], &read_set);
+	      done = 1;
+	    }
+	}
+    } /* While not_done.  */
+}
+
+void
+init_sockets (void)
+{
+  struct sockaddr_un sock_addr;
+
+  /* Initialize the connections db.  */
+  socks_active = 0;
+  FD_ZERO (&read_set);
+
+  /* Create the socket.  */
+  sock[0] = socket (AF_UNIX, SOCK_STREAM, 0);
+  if (sock[0] < 0)
+    {
+      perror (_("cannot create socket"));
+      exit (1);
+    }
+  /* Bind a name to the socket.  */
+  sock_addr.sun_family = AF_UNIX;
+  strcpy (sock_addr.sun_path, _PATH_NSCDSOCKET);
+  if (bind (sock[0], (struct sockaddr *) &sock_addr, sizeof (sock_addr)) < 0)
+    {
+      dbg_log ("%s: %s", _PATH_NSCDSOCKET, strerror (errno));
+      exit (1);
+    }
+  /* Set permissions for the socket.  */
+  chmod (_PATH_NSCDSOCKET, 0666);
+
+  /* Set the socket up to accept connections.  */
+  if (listen (sock[0], MAX_NUM_CONNECTIONS) < 0)
+    {
+      perror (_("cannot enable socket to accept connections"));
+      exit (1);
+    }
+
+  /* Add the socket to the server's set of active sockets.  */
+  FD_SET (sock[0], &read_set);
+  ++socks_active;
+}
+
+void
+pw_send_answer (int conn, struct passwd *pwd)
+{
+  pw_response_header resp;
+
+  resp.version = NSCD_VERSION;
+  if (pwd != NULL)
+    {
+      resp.found = 1;
+      resp.pw_name_len = strlen (pwd->pw_name);
+      resp.pw_passwd_len = strlen (pwd->pw_passwd);
+      resp.pw_uid = pwd->pw_uid;
+      resp.pw_gid = pwd->pw_gid;
+      resp.pw_gecos_len = strlen (pwd->pw_gecos);
+      resp.pw_dir_len = strlen (pwd->pw_dir);
+      resp.pw_shell_len = strlen (pwd->pw_shell);
+    }
+  else
+    {
+      resp.found = 0;
+      resp.pw_name_len = 0;
+      resp.pw_passwd_len = 0;
+      resp.pw_uid = -1;
+      resp.pw_gid = -1;
+      resp.pw_gecos_len = 0;
+      resp.pw_dir_len = 0;
+      resp.pw_shell_len = 0;
+    }
+  if (sock[conn] == 0)
+    {
+      dbg_log (_("bad connection id on send response [%d|%d]"),
+	       conn, sock[conn]);
+      return;
+    }
+
+  /* Send response header.  */
+  if (write (sock[conn], &resp, sizeof (pw_response_header)) !=
+      sizeof (pw_response_header))
+    {
+      dbg_log (_("write incomplete on send response: %s"), strerror (errno));
+      return;
+    }
+
+  if (resp.found)
+    {
+      struct iovec vec[5];
+
+      /* Send pw_name.  */
+      vec[0].iov_base = pwd->pw_name;
+      vec[0].iov_len = resp.pw_name_len;
+      /* Send pw_passwd.  */
+      vec[1].iov_base = pwd->pw_passwd;
+      vec[1].iov_len = resp.pw_passwd_len;
+      /* Send pw_gecos.  */
+      vec[2].iov_base = pwd->pw_gecos;
+      vec[2].iov_len = resp.pw_gecos_len;
+      /* Send pw_dir.  */
+      vec[3].iov_base = pwd->pw_dir;
+      vec[3].iov_len = resp.pw_dir_len;
+      /* Send pw_shell.  */
+      vec[4].iov_base = pwd->pw_shell;
+      vec[4].iov_len = resp.pw_shell_len;
+
+      if (writev (sock[conn], vec, 5) != (resp.pw_name_len + resp.pw_passwd_len
+					  + resp.pw_gecos_len + resp.pw_dir_len
+					  + resp.pw_shell_len))
+	dbg_log (_("write incomplete on send passwd answer: %s"),
+		 strerror (errno));
+    }
+}
+
+void
+pw_send_disabled (int conn)
+{
+  pw_response_header resp;
+
+  resp.version = NSCD_VERSION;
+  resp.found = -1;
+  resp.pw_name_len = 0;
+  resp.pw_passwd_len = 0;
+  resp.pw_uid = -1;
+  resp.pw_gid = -1;
+  resp.pw_gecos_len = 0;
+  resp.pw_dir_len = 0;
+  resp.pw_shell_len = 0;
+
+  if (sock[conn] == 0)
+    {
+      dbg_log ("bad connection id on send response [%d|%d]",
+	       conn, sock[conn]);
+      return;
+    }
+
+  /* Send response header.  */
+  if (write (sock[conn], &resp, sizeof (pw_response_header))
+      != sizeof (pw_response_header))
+    dbg_log (_("write incomplete on send response: %s"), strerror (errno));
+}
+
+void
+gr_send_answer (int conn, struct group *grp)
+{
+  gr_response_header resp;
+
+  resp.version = NSCD_VERSION;
+  if (grp != NULL)
+    {
+      resp.found = 1;
+      resp.gr_name_len = strlen (grp->gr_name);
+      resp.gr_passwd_len = strlen (grp->gr_passwd);
+      resp.gr_gid = grp->gr_gid;
+      resp.gr_mem_len = 0;
+      while (grp->gr_mem[resp.gr_mem_len])
+	++resp.gr_mem_len;
+    }
+  else
+    {
+      resp.found = 0;
+      resp.gr_name_len = 0;
+      resp.gr_passwd_len = 0;
+      resp.gr_gid = -1;
+      resp.gr_mem_len = 0;
+    }
+  if (sock[conn] == 0)
+    {
+      dbg_log (_("bad connection id on send response [%d|%d]"),
+	       conn, sock[conn]);
+      return;
+    }
+
+  /* Send response header.  */
+  if (write (sock[conn], &resp, sizeof (gr_response_header))
+      != sizeof (gr_response_header))
+    {
+      dbg_log (_("write incomplete on send response: %s"), strerror (errno));
+      return;
+    }
+
+  if (resp.found)
+    {
+      unsigned int l = 0;
+
+      /* Send gr_name.  */
+      if (write (sock[conn], grp->gr_name, resp.gr_name_len)
+	  != resp.gr_name_len)
+	{
+	  dbg_log (_("write incomplete on send response: %s"),
+		   strerror (errno));
+	  return;
+	}
+      /* Send gr_passwd.  */
+      if (write (sock[conn], grp->gr_passwd, resp.gr_passwd_len)
+	  != resp.gr_passwd_len)
+	{
+	  dbg_log (_("write incomplete on send response: %s"),
+		   strerror (errno));
+	  return;
+	}
+
+      while (grp->gr_mem[l])
+	{
+	  size_t len = strlen (grp->gr_mem[l]);
+
+	  if (write (sock[conn], &len, sizeof (len)) != sizeof (len))
+	    {
+	      dbg_log (_("write incomplete on send response: %s"),
+		       strerror (errno));
+	      return;
+	    }
+	  if (write (sock[conn], grp->gr_mem[l], len) != len)
+	    {
+	      dbg_log (_("write incomplete on send response: %s"),
+		       strerror (errno));
+	      return;
+	    }
+	  ++l;
+	}
+    }
+}
+
+void
+gr_send_disabled (int conn)
+{
+  gr_response_header resp;
+
+  resp.version = NSCD_VERSION;
+  resp.found = -1;
+  resp.gr_name_len = 0;
+  resp.gr_passwd_len = 0;
+  resp.gr_gid = -1;
+  resp.gr_mem_len = 0;
+
+  if (sock[conn] == 0)
+    {
+      dbg_log (_("bad connection id on send gr_disabled response [%d|%d]"),
+	       conn, sock[conn]);
+      return;
+    }
+
+  /* Send response header.  */
+  if (write (sock[conn], &resp, sizeof (gr_response_header))
+      != sizeof (gr_response_header))
+    dbg_log (_("write incomplete on send gr_disabled response: %s"),
+	     strerror (errno));
+}
+
+void
+stat_send (int conn, stat_response_header *resp)
+{
+  if (sock[conn] == 0)
+    {
+      dbg_log (_("bad connection id on send stat response [%d|%d]"),
+	       conn, sock[conn]);
+      return;
+    }
+
+  /* send response header.  */
+  if (write (sock[conn], resp, sizeof (stat_response_header))
+      != sizeof (stat_response_header))
+    dbg_log (_("write incomplete on send stat response: %s"),
+	     strerror (errno));
+}
diff --git a/nscd/dbg_log.c b/nscd/dbg_log.c
new file mode 100644
index 0000000000..37065e446e
--- /dev/null
+++ b/nscd/dbg_log.c
@@ -0,0 +1,64 @@
+/* Copyright (c) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA. */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "dbg_log.h"
+#include "nscd.h"
+
+/* if in debug mode and we have a debug file, we write the messages to it,
+   if in debug mode and no debug file, we write the messages to stderr,
+   else to syslog.  */
+
+FILE *dbgout = NULL;
+int debug_flag = 0;
+
+int
+set_logfile (const char *logfile)
+{
+  dbgout = fopen (logfile, "a");
+  return dbgout == NULL ? 0 : 1;
+}
+
+void
+dbg_log (const char *fmt,...)
+{
+  va_list ap;
+  char msg[512], msg2[512];
+
+  va_start (ap, fmt);
+  vsnprintf (msg2, sizeof (msg), fmt, ap);
+
+  if (debug_flag)
+    {
+      snprintf (msg, sizeof (msg), "%d: %s\n", getpid (), msg2);
+      if (dbgout)
+	fputs (msg, dbgout);
+      else
+	fputs (msg, stderr);
+    }
+  else
+    {
+      snprintf (msg, sizeof (msg), "%d: %s", getpid (), msg2);
+      syslog (LOG_NOTICE, msg);
+    }
+  va_end (ap);
+}
diff --git a/nscd/dbg_log.h b/nscd/dbg_log.h
new file mode 100644
index 0000000000..c3d1dc4559
--- /dev/null
+++ b/nscd/dbg_log.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA. */
+
+#ifndef _DBG_LOG_H
+#define _DBG_LOG_H	1
+
+extern int debug_flag;
+
+extern void dbg_log (const char *, ...);
+
+#endif
diff --git a/nscd/getgrgid_r.c b/nscd/getgrgid_r.c
new file mode 100644
index 0000000000..3011602671
--- /dev/null
+++ b/nscd/getgrgid_r.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <grp.h>
+
+
+#define LOOKUP_TYPE	struct group
+#define FUNCTION_NAME	getgrgid
+#define DATABASE_NAME	group
+#define ADD_PARAMS	gid_t gid
+#define ADD_VARIABLES	gid
+#define BUFLEN		NSS_BUFLEN_GROUP
+
+#include <nss/getXXbyYY_r.c>
diff --git a/nscd/getgrnam_r.c b/nscd/getgrnam_r.c
new file mode 100644
index 0000000000..3575e74b1f
--- /dev/null
+++ b/nscd/getgrnam_r.c
@@ -0,0 +1,29 @@
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <grp.h>
+
+
+#define LOOKUP_TYPE	struct group
+#define FUNCTION_NAME	getgrnam
+#define DATABASE_NAME	group
+#define ADD_PARAMS	const char *name
+#define ADD_VARIABLES	name
+
+#include <nss/getXXbyYY_r.c>
diff --git a/nscd/getpwnam_r.c b/nscd/getpwnam_r.c
new file mode 100644
index 0000000000..328c3055f8
--- /dev/null
+++ b/nscd/getpwnam_r.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <pwd.h>
+
+
+#define LOOKUP_TYPE	struct passwd
+#define FUNCTION_NAME	getpwnam
+#define DATABASE_NAME	passwd
+#define ADD_PARAMS	const char *name
+#define ADD_VARIABLES	name
+#define BUFLEN		NSS_BUFLEN_PASSWD
+
+#include <nss/getXXbyYY_r.c>
diff --git a/nscd/getpwuid_r.c b/nscd/getpwuid_r.c
new file mode 100644
index 0000000000..91bd802d61
--- /dev/null
+++ b/nscd/getpwuid_r.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <pwd.h>
+
+
+#define LOOKUP_TYPE	struct passwd
+#define FUNCTION_NAME	getpwuid
+#define DATABASE_NAME	passwd
+#define ADD_PARAMS	uid_t uid
+#define ADD_VARIABLES	uid
+#define BUFLEN		NSS_BUFLEN_PASSWD
+
+#include <nss/getXXbyYY_r.c>
diff --git a/nscd/grpcache.c b/nscd/grpcache.c
new file mode 100644
index 0000000000..9f6c767fd7
--- /dev/null
+++ b/nscd/grpcache.c
@@ -0,0 +1,589 @@
+/* Copyright (c) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA. */
+
+#include <errno.h>
+#include <grp.h>
+#include <malloc.h>
+#include <pthread.h>
+#include <string.h>
+#include <rpcsvc/nis.h>
+#include <sys/types.h>
+
+#include "dbg_log.h"
+#include "nscd.h"
+
+static unsigned long modulo = 211;
+static unsigned long postimeout = 3600;
+static unsigned long negtimeout = 60;
+
+static unsigned long poshit = 0;
+static unsigned long posmiss = 0;
+static unsigned long neghit = 0;
+static unsigned long negmiss = 0;
+
+struct grphash
+{
+  time_t create;
+  struct grphash *next;
+  struct group *grp;
+};
+typedef struct grphash grphash;
+
+struct gidhash
+{
+  struct gidhash *next;
+  struct grphash *grptr;
+};
+typedef struct gidhash gidhash;
+
+struct neghash
+{
+  time_t create;
+  struct neghash *next;
+  char *key;
+};
+typedef struct neghash neghash;
+
+static grphash *grptbl;
+static gidhash *gidtbl;
+static neghash *negtbl;
+
+static pthread_rwlock_t grplock = PTHREAD_RWLOCK_INITIALIZER;
+static pthread_rwlock_t neglock = PTHREAD_RWLOCK_INITIALIZER;
+
+static void *grptable_update (void *);
+static void *negtable_update (void *);
+
+void
+get_gr_stat (stat_response_header *stat)
+{
+  stat->gr_poshit = poshit;
+  stat->gr_posmiss = posmiss;
+  stat->gr_neghit = neghit;
+  stat->gr_negmiss = negmiss;
+  stat->gr_size = modulo;
+  stat->gr_posttl = postimeout;
+  stat->gr_negttl = negtimeout;
+}
+
+void
+set_grp_modulo (unsigned long mod)
+{
+  modulo = mod;
+}
+
+void
+set_pos_grp_ttl (unsigned long ttl)
+{
+  postimeout = ttl;
+}
+
+void
+set_neg_grp_ttl (unsigned long ttl)
+{
+  negtimeout = ttl;
+}
+
+int
+cache_grpinit ()
+{
+  pthread_attr_t attr;
+  pthread_t thread;
+
+  grptbl = calloc (1, modulo * sizeof (grphash));
+  if (grptbl == NULL)
+    return -1;
+  calloc (1, modulo * sizeof (grphash));
+  if (gidtbl == NULL)
+    return -1;
+  negtbl = calloc (1, modulo * sizeof (neghash));
+  if (negtbl == NULL)
+    return -1;
+
+  pthread_attr_init (&attr);
+  pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+
+  pthread_create (&thread, NULL, grptable_update, &attr);
+  pthread_create (&thread, NULL, negtable_update, &attr);
+
+  pthread_attr_destroy (&attr);
+
+  return 0;
+}
+
+static struct group *
+save_grp (struct group *src)
+{
+  struct group *dest;
+  unsigned long int l;
+
+  dest = calloc (1, sizeof (struct group));
+  dest->gr_name = strdup (src->gr_name);
+  dest->gr_passwd = strdup (src->gr_passwd);
+  dest->gr_gid = src->gr_gid;
+
+  /* How many members does this group have?  */
+  l = 0;
+  while (src->gr_mem[l])
+    ++l;
+
+  dest->gr_mem = calloc (1, sizeof (char *) * (l+1));
+  l = 0;
+  while (src->gr_mem[l])
+    {
+      dest->gr_mem[l] = strdup (src->gr_mem[l]);
+      ++l;
+    }
+
+  return dest;
+}
+
+static void
+free_grp (struct group *src)
+{
+  unsigned long int l;
+
+  free (src->gr_name);
+  free (src->gr_passwd);
+
+  l = 0;
+  while (src->gr_mem[l])
+    {
+      free (src->gr_mem[l]);
+      ++l;
+    }
+  free (src->gr_mem);
+  free (src);
+}
+
+static int
+add_cache (struct group *grp)
+{
+  grphash *work;
+  unsigned long int hash = __nis_hash (grp->gr_name,
+				       strlen (grp->gr_name)) % modulo;
+
+  work = &grptbl[hash];
+
+  if (grptbl[hash].grp == NULL)
+    grptbl[hash].grp = save_grp (grp);
+  else
+    {
+      while (work->next != NULL)
+	work = work->next;
+
+      work->next = calloc (1, sizeof (grphash));
+      work->next->grp = save_grp (grp);
+      work = work->next;
+    }
+
+  time (&work->create);
+  gidtbl[grp->gr_gid % modulo].grptr = work;
+
+  return 0;
+}
+
+static struct group *
+cache_search_name (const char *name)
+{
+  grphash *work;
+  unsigned long int hash = __nis_hash (name, strlen(name)) % modulo;
+
+  work = &grptbl[hash];
+
+  while (work->grp != NULL)
+    {
+      if (strcmp (work->grp->gr_name, name) == 0)
+	return work->grp;
+      if (work->next != NULL)
+	work = work->next;
+      else
+	return NULL;
+    }
+  return NULL;
+}
+
+static struct group *
+cache_search_gid (gid_t gid)
+{
+  gidhash *work;
+
+  work = &gidtbl[gid % modulo];
+
+  while (work->grptr != NULL)
+    {
+      if (work->grptr->grp->gr_gid == gid)
+	return work->grptr->grp;
+      if (work->next != NULL)
+	work = work->next;
+      else
+	return NULL;
+    }
+  return NULL;
+}
+
+static int
+add_negcache (char *key)
+{
+  neghash *work;
+  unsigned long int hash = __nis_hash (key, strlen (key)) % modulo;
+
+  work = &negtbl[hash];
+
+  if (negtbl[hash].key == NULL)
+    negtbl[hash].key = strdup (key);
+  else
+    {
+      while (work->next != NULL)
+	work = work->next;
+
+      work->next = calloc (1, sizeof (neghash));
+      work->next->key = strdup (key);
+      work = work->next;
+    }
+
+  time (&work->create);
+  return 0;
+}
+
+static int
+cache_search_neg (const char *key)
+{
+  neghash *work;
+  unsigned long int hash = __nis_hash (key, strlen (key)) % modulo;
+
+  work = &negtbl[hash];
+
+  while (work->key != NULL)
+    {
+      if (strcmp (work->key, key) == 0)
+	return 1;
+      if (work->next != NULL)
+	work = work->next;
+      else
+	return 0;
+    }
+  return 0;
+}
+
+void *
+cache_getgrnam (void *v_param)
+{
+  param_t *param = (param_t *)v_param;
+  struct group *grp, resultbuf;
+
+  pthread_rwlock_rdlock (&grplock);
+  grp = cache_search_name (param->key);
+
+  /* I don't like it to hold the read only lock longer, but it is
+     necessary to avoid to much malloc/free/strcpy.  */
+
+  if (grp)
+    {
+      if (debug_flag)
+	dbg_log (_("Found \"%s\" in cache !"), param->key);
+
+      ++poshit;
+      gr_send_answer (param->conn, grp);
+      close_socket (param->conn);
+
+      pthread_rwlock_unlock (&grplock);
+    }
+  else
+    {
+      int buflen = 1024;
+      char *buffer = calloc (1, buflen);
+      int status;
+
+      if (debug_flag)
+	dbg_log (_("Doesn't found \"%s\" in cache !"), param->key);
+
+      pthread_rwlock_unlock (&grplock);
+
+      pthread_rwlock_rdlock (&neglock);
+      status = cache_search_neg (param->key);
+      pthread_rwlock_unlock (&neglock);
+
+      if (status == 0)
+	{
+	  while (buffer != NULL
+		 && (getgrnam_r (param->key, &resultbuf, buffer, buflen, &grp)
+		     != 0)
+		 && errno == ERANGE)
+	    {
+	      errno = 0;
+	      buflen += 1024;
+	      buffer = realloc (buffer, buflen);
+	    }
+
+	  if (buffer != NULL && grp != NULL)
+	    {
+	      struct group *tmp;
+
+	      ++poshit;
+	      pthread_rwlock_wrlock (&grplock);
+	      /* While we are waiting on the lock, somebody else could
+		 add this entry.  */
+	      tmp = cache_search_name (param->key);
+	      if (tmp == NULL)
+		add_cache (grp);
+	      pthread_rwlock_unlock (&grplock);
+	    }
+	  else
+	    {
+	      pthread_rwlock_wrlock (&neglock);
+	      add_negcache (param->key);
+	      ++negmiss;
+	      pthread_rwlock_unlock (&neglock);
+	    }
+	}
+      else
+	++neghit;
+
+      gr_send_answer (param->conn, grp);
+      close_socket (param->conn);
+      if (buffer != NULL)
+	free (buffer);
+    }
+  free (param->key);
+  free (param);
+  return NULL;
+}
+
+void *
+cache_gr_disabled (void *v_param)
+{
+  param_t *param = (param_t *)v_param;
+
+  gr_send_disabled (param->conn);
+  return NULL;
+}
+
+void *
+cache_getgrgid (void *v_param)
+{
+  param_t *param = (param_t *)v_param;
+  struct group *grp, resultbuf;
+  gid_t gid = strtol (param->key, NULL, 10);
+
+  pthread_rwlock_rdlock (&grplock);
+  grp = cache_search_gid (gid);
+
+  /* I don't like it to hold the read only lock longer, but it is
+     necessary to avoid to much malloc/free/strcpy.  */
+
+  if (grp != NULL)
+    {
+      if (debug_flag)
+	dbg_log (_("Found \"%d\" in cache !\n"), gid);
+
+      ++poshit;
+      gr_send_answer (param->conn, grp);
+      close_socket (param->conn);
+
+      pthread_rwlock_unlock (&grplock);
+    }
+  else
+    {
+      int buflen = 1024;
+      char *buffer = malloc (buflen);
+      int status;
+
+      if (debug_flag)
+	dbg_log (_("Doesn't found \"%d\" in cache !\n"), gid);
+
+      pthread_rwlock_unlock (&grplock);
+
+      pthread_rwlock_rdlock (&neglock);
+      status = cache_search_neg (param->key);
+      pthread_rwlock_unlock (&neglock);
+
+      if (status == 0)
+        {
+	  while (buffer != NULL
+		 && (getgrgid_r (gid, &resultbuf, buffer, buflen, &grp) != 0)
+		 && errno == ERANGE)
+	    {
+	      errno = 0;
+	      buflen += 1024;
+	      buffer = realloc (buffer, buflen);
+	    }
+
+	  if (buffer != NULL && grp != NULL)
+	    {
+	      struct group *tmp;
+
+	      ++posmiss;
+	      pthread_rwlock_wrlock (&grplock);
+	      /* While we are waiting on the lock, somebody else could
+		 add this entry.  */
+	      tmp = cache_search_gid (gid);
+	      if (tmp == NULL)
+		add_cache (grp);
+	      pthread_rwlock_unlock (&grplock);
+	    }
+	  else
+	    {
+	      ++negmiss;
+	      pthread_rwlock_wrlock (&neglock);
+	      add_negcache (param->key);
+	      pthread_rwlock_unlock (&neglock);
+	    }
+	}
+      else
+	++neghit;
+
+      gr_send_answer (param->conn, grp);
+      close_socket (param->conn);
+      if (buffer != NULL)
+	free (buffer);
+    }
+  free (param->key);
+  free (param);
+  return NULL;
+}
+
+void *
+grptable_update (void *v)
+{
+  time_t now;
+  int i;
+
+  sleep (20);
+
+  while (!do_shutdown)
+    {
+      if (debug_flag > 2)
+	dbg_log (_("(grptable_update) Wait for write lock!"));
+
+      pthread_rwlock_wrlock (&grplock);
+
+      if (debug_flag > 2)
+	dbg_log (_("(grptable_update) Have write lock"));
+
+      time (&now);
+      for (i = 0; i < modulo; ++i)
+	{
+	  grphash *work = &grptbl[i];
+
+	  while (work && work->grp)
+	    {
+	      if ((now - work->create) >= postimeout)
+		{
+		  gidhash *uh = &gidtbl[work->grp->gr_gid % modulo];
+
+		  if (debug_flag)
+		    dbg_log (_("Give \"%s\" free"), work->grp->gr_name);
+
+		  while (uh && uh->grptr)
+		    {
+		      if (uh->grptr->grp->gr_gid == work->grp->gr_gid)
+			{
+			  if (debug_flag > 3)
+			    dbg_log (_("Give gid for \"%s\" free"),
+				     work->grp->gr_name);
+			  if (uh->next != NULL)
+			    {
+			      gidhash *tmp = uh->next;
+			      uh->grptr = tmp->grptr;
+			      uh->next = tmp->next;
+			      free (tmp);
+			    }
+			  else
+			    uh->grptr = NULL;
+			}
+		      uh = uh->next;
+		    }
+
+		  free_grp (work->grp);
+		  if (work->next != NULL)
+		    {
+		      grphash *tmp = work->next;
+		      work->create = tmp->create;
+		      work->next = tmp->next;
+		      work->grp = tmp->grp;
+		      free (tmp);
+		    }
+		  else
+		    work->grp = NULL;
+		}
+	      work = work->next;
+	    }
+	}
+      if (debug_flag > 2)
+	dbg_log (_("(pwdtable_update) Release wait lock\n"));
+      pthread_rwlock_unlock (&grplock);
+      sleep (20);
+    }
+  return NULL;
+}
+
+void *
+negtable_update (void *v)
+{
+  time_t now;
+  int i;
+
+  sleep (30);
+
+  while (!do_shutdown)
+    {
+      if (debug_flag > 2)
+	dbg_log (_("(negtable_update) Wait for write lock!"));
+
+      pthread_rwlock_wrlock (&neglock);
+
+      if (debug_flag > 2)
+	dbg_log (_("(negtable_update) Have write lock"));
+
+      time (&now);
+      for (i = 0; i < modulo; ++i)
+	{
+	  neghash *work = &negtbl[i];
+
+	  while (work && work->key)
+	    {
+	      if ((now - work->create) >= negtimeout)
+		{
+		  if (debug_flag)
+		    dbg_log (_("Give \"%s\" free"), work->key);
+
+		  free (work->key);
+
+		  if (work->next != NULL)
+		    {
+		      neghash *tmp = work->next;
+		      work->create = tmp->create;
+		      work->next = tmp->next;
+		      work->key = tmp->key;
+		      free (tmp);
+		    }
+		  else
+		    work->key = NULL;
+		}
+	      work = work->next;
+	    }
+	}
+      if (debug_flag > 2)
+	dbg_log (_("(negtable_update) Release wait lock"));
+      pthread_rwlock_unlock (&neglock);
+      sleep (10);
+    }
+  return NULL;
+}
diff --git a/nscd/nscd.c b/nscd/nscd.c
new file mode 100644
index 0000000000..59d4a60e02
--- /dev/null
+++ b/nscd/nscd.c
@@ -0,0 +1,423 @@
+/* Copyright (c) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA. */
+
+/* nscd - Name Service Cache Daemon. Caches passwd and group.  */
+
+#include <errno.h>
+#include <getopt.h>
+#include <libintl.h>
+#include <locale.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "dbg_log.h"
+#include "nscd.h"
+
+/* Get libc version number.  */
+#include <version.h>
+
+#define PACKAGE _libc_intl_domainname
+
+/* Structure used by main() thread to keep track of the number of
+   active threads.  Used to limit how many threads it will create
+   and under a shutdown condition to wait till all in-progress
+   requests have finished before "turning off the lights".  */
+
+typedef struct
+{
+  int             num_active;
+  pthread_cond_t  thread_exit_cv;
+  pthread_mutex_t mutex;
+} thread_info_t;
+
+thread_info_t thread_info;
+
+int do_shutdown = 0;
+int disabled_passwd = 0;
+int disabled_group = 0;
+
+static void termination_handler (int signum);
+static int check_pid (const char *file);
+static int write_pid (const char *file);
+static void usage (int status) __attribute__ ((noreturn));
+static void handle_requests (void);
+
+int
+main (int argc, char **argv)
+{
+  int go_background = 1;
+  const char *conffile = _PATH_NSCDCONF;
+
+  /* Set locale via LC_ALL.  */
+  setlocale (LC_ALL, "");
+  /* Set the text message domain.  */
+  textdomain (PACKAGE);
+
+  while (1)
+    {
+      int c;
+      int option_index = 0;
+      static struct option long_options[] = {
+	{ "debug", no_argument, NULL, 'd' },
+	{ "help", no_argument, NULL, 'h' },
+	{ "version", no_argument, NULL, 'V' },
+	{ "shutdown", no_argument, NULL, 'K' },
+        {NULL, 0, NULL, '\0'}
+      };
+
+      c = getopt_long (argc, argv, "df:ghKV", long_options, &option_index);
+      if (c == (-1))
+        break;
+      switch (c)
+	{
+	case 'd':
+	  debug_flag = 1;
+	  go_background = 0;
+	  break;
+	case 'f':
+	  conffile = optarg;
+	  break;
+	case 'h':
+	  usage (EXIT_SUCCESS);
+	  break;
+	case 'K':
+	  if (getuid () != 0)
+	    {
+	      printf (_("Only root is allowed to use this option!\n\n"));
+	      usage (EXIT_FAILURE);
+	    }
+	  {
+	    int sock = __nscd_open_socket ();
+	    request_header req;
+	    ssize_t nbytes;
+
+	    if (sock == -1)
+	      exit (EXIT_FAILURE);
+
+	    req.version = NSCD_VERSION;
+	    req.type = SHUTDOWN;
+	    req.key_len = 0;
+	    nbytes = write (sock, &req, sizeof (request_header));
+	    close (sock);
+	    if (nbytes != req.key_len)
+	      exit (EXIT_FAILURE);
+	    else
+	      exit (EXIT_SUCCESS);
+	  }
+	case 'g':
+	  print_stat ();
+	  exit (EXIT_SUCCESS);
+	case 'V':
+	  printf ("nscd (GNU %s) %s\n", PACKAGE, VERSION);
+	  printf (_("\
+Copyright (C) %s Free Software Foundation, Inc.\n\
+This is free software; see the source for copying conditions.  There is NO\n\
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
+"), "1998");
+	  printf (_("Written by %s.\n"), "Thorsten Kukuk");
+	  exit (EXIT_SUCCESS);
+	default:
+	  usage (EXIT_FAILURE);
+	}
+    }
+
+  signal (SIGINT, termination_handler);
+  signal (SIGQUIT, termination_handler);
+  signal (SIGTERM, termination_handler);
+
+  /* Check if we are already running. */
+  if (check_pid (_PATH_NSCDPID))
+    {
+      fputs (_("already running"), stderr);
+      exit (EXIT_FAILURE);
+    }
+
+  /* Behave like a daemon.  */
+  if (go_background)
+    {
+      openlog ("nscd", LOG_CONS | LOG_ODELAY, LOG_DAEMON);
+
+      if (daemon (0, 0) < 0)
+	{
+	  fprintf (stderr, _("connot auto-background: %s\n"),
+		   strerror (errno));
+	  exit (EXIT_FAILURE);
+	}
+      if (write_pid (_PATH_NSCDPID) < 0)
+        dbg_log ("%s: %s", _PATH_NSCDPID, strerror (errno));
+
+      /* Ignore job control signals */
+      signal (SIGTTOU, SIG_IGN);
+      signal (SIGTTIN, SIG_IGN);
+      signal (SIGTSTP, SIG_IGN);
+    }
+  /* Cleanup files created by a previous `bind' */
+  unlink (_PATH_NSCDSOCKET);
+
+  nscd_parse_file (conffile);
+
+  /* Create first sockets */
+  init_sockets ();
+  /* Init databases */
+  cache_pwdinit ();
+  cache_grpinit ();
+  /* Handle incoming requests */
+  handle_requests ();
+
+  return 0;
+}
+
+/* Create a socket connected to a name. */
+int
+__nscd_open_socket (void)
+{
+  struct sockaddr_un addr;
+  int sock;
+
+  sock = socket (PF_UNIX, SOCK_STREAM, 0);
+  if (sock < 0)
+    return -1;
+
+  addr.sun_family = AF_UNIX;
+  strcpy (addr.sun_path, _PATH_NSCDSOCKET);
+  if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
+    {
+      close (sock);
+      return -1;
+    }
+
+  return sock;
+}
+
+/* Cleanup.  */
+static void
+termination_handler (int signum)
+{
+  close_sockets ();
+
+  /* Clean up the files created by `bind'.  */
+  unlink (_PATH_NSCDSOCKET);
+
+  /* Clean up pid file.  */
+  unlink (_PATH_NSCDPID);
+
+  exit (EXIT_SUCCESS);
+}
+
+/* Display usage information and exit.  */
+static void
+usage (int status)
+{
+  if (status != EXIT_SUCCESS)
+    fprintf (stderr, _("Try `%s --help' for more information.\n"),
+             program_invocation_name);
+  else
+    {
+      printf (_("\
+Usage: %s [OPTION]...\n\
+  -d, --debug           do not fork and display messages on the current tty\n\
+  -h, --help            display this help and exit\n\
+  -V, --version         output version information and exit\n\
+  -f configuration-file read configuration data from the specified file.\n\
+  -K, --shutdown        shut the server down.\n\
+  -g                    Prints configuration and statistics to stdout.\n"),
+              program_invocation_name);
+      fputs (_("\
+Report bugs using the `glibcbug' script to <bugs@gnu.org>.\n"),
+             stdout);
+    }
+  exit (status);
+}
+
+/* Returns 1 if the process in pid file FILE is running, 0 if not.  */
+static int
+check_pid (const char *file)
+{
+  FILE *fp;
+
+  fp = fopen (file, "r");
+  if (fp)
+    {
+      pid_t pid;
+
+      fscanf (fp, "%d", &pid);
+      fclose (fp);
+
+      if (kill (pid, 0) == 0)
+        return 1;
+    }
+
+  return 0;
+}
+
+/* Write the current process id to the file FILE.
+   Returns 0 if successful, -1 if not.  */
+static int
+write_pid (const char *file)
+{
+  FILE *fp;
+
+  fp = fopen (file, "w");
+  if (fp == NULL)
+    return -1;
+
+  fprintf (fp, "%d\n", getpid ());
+  if (ferror (fp))
+    return -1;
+
+  fclose (fp);
+
+  return 0;
+}
+
+/* Type of the lookup function for netname2user.  */
+typedef int (*pwbyname_function) (const char *name, struct passwd *pw,
+				   char *buffer, size_t buflen);
+
+/* Hanlde incoming requests.  */
+static
+void handle_requests (void)
+{
+  request_header req;
+  int conn; /* Handle on which connection (client) the request came from.  */
+  int done = 0;
+  char *key;
+
+  while (!done)
+    {
+      key = NULL;
+      get_request (&conn, &req, &key);
+      if (debug_flag)
+	dbg_log (_("handle_requests: request received (Version = %d)"),
+		 req.version);
+      switch (req.type)
+	{
+	case GETPWBYNAME:
+	  {
+	    param_t *param = malloc (sizeof (param_t));
+	    pthread_t thread;
+
+	    if (debug_flag)
+	      dbg_log ("\tGETPWBYNAME (%s)", key);
+	    param->key = key;
+	    param->conn = conn;
+	    if (disabled_passwd)
+	      pthread_create (&thread, NULL, cache_pw_disabled, (void *)param);
+	    else
+	      pthread_create (&thread, NULL, cache_getpwnam, (void *)param);
+	    pthread_detach (thread);
+	  }
+	  break;
+	case GETPWBYUID:
+	  {
+	    param_t *param = malloc (sizeof (param_t));
+	    pthread_t thread;
+
+	    if (debug_flag)
+	      dbg_log ("\tGETPWBYUID (%s)", key);
+	    param->key = key;
+	    param->conn = conn;
+	    if (disabled_passwd)
+	      pthread_create (&thread, NULL, cache_pw_disabled, (void *)param);
+	    else
+	      pthread_create (&thread, NULL, cache_getpwuid, (void *)param);
+	    pthread_detach (thread);
+	  }
+	  break;
+	case GETGRBYNAME:
+	  {
+	    param_t *param = malloc (sizeof (param_t));
+	    pthread_t thread;
+
+	    if (debug_flag)
+	      dbg_log ("\tGETGRBYNAME (%s)", key);
+	    param->key = key;
+	    param->conn = conn;
+	    if (disabled_group)
+	      pthread_create (&thread, NULL, cache_gr_disabled, (void *)param);
+	    else
+	      pthread_create (&thread, NULL, cache_getgrnam, (void *)param);
+	    pthread_detach (thread);
+	  }
+	  break;
+	case GETGRBYGID:
+	  {
+	    param_t *param = malloc (sizeof (param_t));
+	    pthread_t thread;
+
+	    if (debug_flag)
+	      dbg_log ("\tGETGRBYGID (%s)", key);
+	    param->key = key;
+	    param->conn = conn;
+	    if (disabled_group)
+	      pthread_create (&thread, NULL, cache_gr_disabled, (void *)param);
+	    else
+	      pthread_create (&thread, NULL, cache_getgrgid, (void *)param);
+	    pthread_detach (thread);
+	  }
+	  break;
+	case GETHOSTBYNAME:
+	  /* Not yetimplemented.  */
+	  close_socket (conn);
+	  break;
+	case GETHOSTBYADDR:
+	  /* Not yet implemented. */
+	  close_socket (conn);
+	  break;
+	case SHUTDOWN:
+	  do_shutdown = 1;
+	  close_socket (0);
+	  close_socket (conn);
+	  /* Clean up the files created by `bind'.  */
+	  unlink (_PATH_NSCDSOCKET);
+	  /* Clean up pid file.  */
+	  unlink (_PATH_NSCDPID);
+	  done = 1;
+	  break;
+	case GETSTAT:
+	  {
+	    stat_response_header resp;
+
+	    if (debug_flag)
+	      dbg_log ("\tGETSTAT");
+
+	    get_pw_stat (&resp);
+	    get_gr_stat (&resp);
+	    resp.debug_level = debug_flag;
+	    resp.pw_enabled = !disabled_passwd;
+	    resp.gr_enabled = !disabled_group;
+
+	    stat_send (conn, &resp);
+
+	    close_socket (conn);
+	  }
+	  break;
+	default:
+	  dbg_log (_("Unknown request (%d)"), req.type);
+	  break;
+	}
+    }
+}
diff --git a/nscd/nscd.conf b/nscd/nscd.conf
new file mode 100644
index 0000000000..5d8c7f31ac
--- /dev/null
+++ b/nscd/nscd.conf
@@ -0,0 +1,30 @@
+#
+# /etc/nscd.conf
+#
+# An example Name Service Cache config file.  This file is needed by nscd.
+#
+# Legal entries are:
+#
+#	logfile			<file>
+#       enable-cache		<service> <yes|no>
+#	debug-level		<level>
+#	positive-time-to-live	<service> <time in seconds>
+#	negative-time-to-live   <service> <time in seconds>
+#       suggested-size		<service> <prime number>
+#
+# Currently supported cache names (services): passwd, group
+#
+
+
+#	logfile			/var/adm/nscd.log
+#	enable-cache		hosts		no
+
+	debug-level		0
+
+	positive-time-to-live	passwd		600
+	negative-time-to-live	passwd		20
+	suggested-size		passwd		211
+
+	positive-time-to-live	group		3600
+	negative-time-to-live	group		60
+	suggested-size		group		211
diff --git a/nscd/nscd.h b/nscd/nscd.h
new file mode 100644
index 0000000000..4835542619
--- /dev/null
+++ b/nscd/nscd.h
@@ -0,0 +1,149 @@
+/* Copyright (c) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA. */
+
+#ifndef _NSCD_H
+#define _NSCD_H 1
+
+#include <grp.h>
+#include <pwd.h>
+
+/* Version number of the daemon interface */
+#define NSCD_VERSION 1
+
+/* How many threads do we spawn maximal ? */
+#define MAX_NUM_CONNECTIONS 16
+
+/* Services provided */
+typedef enum
+{
+  GETPWBYNAME,
+  GETPWBYUID,
+  GETGRBYNAME,
+  GETGRBYGID,
+  GETHOSTBYNAME,
+  GETHOSTBYADDR,
+  SHUTDOWN,		/* Shut the server down */
+  GETSTAT               /* Get the server statistic */
+} request_type;
+
+/* Header common to all requests */
+typedef struct
+{
+  /* Version number of the daemon interface */
+  int version;
+  /* Service requested */
+  request_type type;
+  /* key len */
+  ssize_t key_len;
+} request_header;
+
+typedef struct
+{
+  int version;
+  int found;
+  ssize_t pw_name_len;
+  ssize_t pw_passwd_len;
+  uid_t pw_uid;
+  gid_t pw_gid;
+  ssize_t pw_gecos_len;
+  ssize_t pw_dir_len;
+  ssize_t pw_shell_len;
+} pw_response_header;
+
+typedef struct
+{
+  int version;
+  int found;
+  ssize_t gr_name_len;
+  ssize_t gr_passwd_len;
+  gid_t gr_gid;
+  ssize_t gr_mem_len;
+} gr_response_header;
+
+typedef struct
+{
+  int debug_level;
+  int pw_enabled;
+  unsigned long pw_poshit;
+  unsigned long pw_posmiss;
+  unsigned long pw_neghit;
+  unsigned long pw_negmiss;
+  unsigned long pw_size;
+  unsigned long pw_posttl;
+  unsigned long pw_negttl;
+  int gr_enabled;
+  unsigned long gr_poshit;
+  unsigned long gr_posmiss;
+  unsigned long gr_neghit;
+  unsigned long gr_negmiss;
+  unsigned long gr_size;
+  unsigned long gr_posttl;
+  unsigned long gr_negttl;
+} stat_response_header;
+
+#define _PATH_NSCDPID	 "/var/run/nscd.pid"
+#define _PATH_NSCDSOCKET "/var/run/.nscd_socket"
+#define _PATH_NSCDCONF	 "/etc/nscd.conf"
+
+typedef struct
+{
+  char *key;
+  int conn;
+} param_t;
+
+extern int  do_shutdown; /* 1 if we should quit the programm.  */
+extern int  disabled_passwd;
+extern int  disabled_group;
+
+extern int  nscd_parse_file __P ((const char *fname));
+extern int  set_logfile __P ((const char *logfile));
+extern void set_pos_pwd_ttl __P ((unsigned long));
+extern void set_neg_pwd_ttl __P ((unsigned long));
+extern void set_pos_grp_ttl __P ((unsigned long));
+extern void set_neg_grp_ttl __P ((unsigned long));
+extern void set_pwd_modulo __P ((unsigned long));
+extern void set_grp_modulo __P ((unsigned long));
+
+extern void init_sockets __P ((void));
+extern void close_socket __P ((int conn));
+extern void close_sockets __P ((void));
+extern void get_request __P ((int *conn, request_header *req, char **key));
+extern void pw_send_answer __P ((int conn, struct passwd *pwd));
+extern void pw_send_disabled __P ((int conn));
+extern void gr_send_answer __P ((int conn, struct group *grp));
+extern void gr_send_disabled __P ((int conn));
+
+extern int  cache_pwdinit __P ((void));
+extern void *cache_getpwnam __P ((void *param));
+extern void *cache_getpwuid __P ((void *param));
+extern void *cache_pw_disabled __P ((void *param));
+
+extern int  cache_grpinit __P ((void));
+extern void *cache_getgrnam __P ((void *param));
+extern void *cache_getgrgid __P ((void *param));
+extern void *cache_gr_disabled __P ((void *param));
+
+extern int __nscd_open_socket __P ((void));
+
+extern void get_pw_stat __P ((stat_response_header *resp));
+extern void get_gr_stat __P ((stat_response_header *resp));
+extern void print_stat __P ((void));
+extern void stat_send __P ((int conn, stat_response_header *resp));
+
+#endif
diff --git a/nscd/nscd.init b/nscd/nscd.init
new file mode 100644
index 0000000000..097ce42c99
--- /dev/null
+++ b/nscd/nscd.init
@@ -0,0 +1,50 @@
+#!/bin/sh
+#
+# nscd:		Starts the Name Switch Cache Daemon
+#
+# chkconfig: 345 52 25
+# description:  This is a daemon which handles passwd and group lookups
+#		for running programs and cache the results for the next
+#		query.  You should start this daemon only if you use
+#		slow Services like NIS or NIS+
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+# See how we were called.
+case "$1" in
+    start)
+	test -f /etc/nscd.conf -a -f /usr/sbin/nscd || exit 0
+	secure=""
+#	for table in passwd group
+#	do
+#		if egrep '^'$table':.*nisplus' /etc/nsswitch.conf >/dev/null
+#		then
+#			/usr/lib/nscd_nischeck $table ||
+#				secure="$secure -S $table,yes"
+#		fi
+#	done
+        echo -n "Starting Name Switch Cache Daemon: "
+	daemon nscd $secure
+        echo
+        touch /var/lock/subsys/nscd
+	;;
+    stop)
+	test -f /usr/sbin/nscd || exit 0
+	echo -n "Stopping Name Switch Cache Daemon: "
+	/usr/sbin/nscd -K
+        rm -f /var/lock/subsys/nscd
+        echo nscd
+	;;
+  status)
+        status nscd
+        ;;
+  restart)
+        $0 stop
+        $0 start
+        ;;
+    *)
+	echo "Usage: /etc/rc.d/init.d/nscd.init {start|stop|status|restart}"
+	;;
+esac
+exit 0
diff --git a/nscd/nscd_conf.c b/nscd/nscd_conf.c
new file mode 100644
index 0000000000..59c225e566
--- /dev/null
+++ b/nscd/nscd_conf.c
@@ -0,0 +1,148 @@
+/* Copyright (c) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA. */
+
+#include <ctype.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "dbg_log.h"
+#include "nscd.h"
+
+int
+nscd_parse_file (const char *fname)
+{
+  FILE *fp;
+  char *line, *cp, *entry, *arg1, *arg2;
+  size_t len;
+
+  /* Open the configuration file.  */
+  fp = fopen (fname, "r");
+  if (fp == NULL)
+    return -1;
+
+  line = NULL;
+  len = 0;
+
+  do
+    {
+      ssize_t n = getline (&line, &len, fp);
+      if (n < 0)
+	break;
+      if (line[n - 1] == '\n')
+	line[n - 1] = '\0';
+
+      /* Because the file format does not know any form of quoting we
+	 can search forward for the next '#' character and if found
+	 make it terminating the line.  */
+      cp = strchr (line, '#');
+      if (cp != NULL)
+	*cp = '\0';
+
+      /* If the line is blank it is ignored.  */
+      if (line[0] == '\0')
+	continue;
+
+      entry = line;
+      while (isspace (*entry) && *entry != '\0')
+	++entry;
+      cp = entry;
+      while (!isspace (*cp) && *cp != '\0')
+	++cp;
+      arg1 = cp;
+      ++arg1;
+      *cp = '\0';
+      if (*cp = '\0' || strlen (entry) == 0)
+	dbg_log (_("Parse error: %s"), line);
+      while (isspace (*arg1) && *arg1 != '\0')
+	++arg1;
+      cp = arg1;
+      while (!isspace (*cp) && *cp != '\0')
+	++cp;
+      arg2 = cp;
+      ++arg2;
+      *cp = '\0';
+      if (strlen (arg2) > 0)
+	{
+	  while (isspace (*arg2) && *arg2 != '\0')
+	    ++arg2;
+	  cp = arg2;
+	  while (!isspace (*cp) && *cp != '\0')
+	    ++cp;
+	  *cp = '\0';
+	}
+
+      if (strcmp (entry, "positive-time-to-live") == 0)
+	{
+	  if (strcmp (arg1, "passwd") == 0)
+	    set_pos_pwd_ttl (atol (arg2));
+	  else if (strcmp (arg1, "group") == 0)
+	    set_pos_grp_ttl (atol (arg2));
+	  else
+	    dbg_log ("server %s is not supported\n", arg1);
+	}
+      else if (strcmp (entry, "negative-time-to-live") == 0)
+	{
+	  if (strcmp (arg1, "passwd") == 0)
+	    set_neg_pwd_ttl (atol (arg2));
+	  else if (strcmp (arg1, "group") == 0)
+	    set_neg_grp_ttl (atol (arg2));
+	  else
+	    dbg_log (_("service %s is not supported"), arg1);
+	}
+      else if (strcmp (entry, "suggested-size") == 0)
+	{
+	  if (strcmp (arg1, "passwd") == 0)
+	    set_pwd_modulo (atol (arg2));
+	  else if (strcmp (arg1, "group") == 0)
+	    set_grp_modulo (atol (arg2));
+	  else
+	    dbg_log (_("service %s is not supported"), arg1);
+	}
+      else if (strcmp (entry, "enable-cache") ==0)
+	{
+	  if (strcmp (arg1, "passwd") == 0
+	      && strcmp (arg2, "no") == 0)
+	    disabled_passwd = 1;
+	}
+      else if (strcmp (entry, "logfile") == 0)
+	{
+	  if (!set_logfile (arg1))
+	    dbg_log (_("Could not create log file \"%s\""), arg1);
+	}
+      else if (strcmp (entry, "debug-level") == 0)
+	{
+	  int level = atoi (arg1);
+	  if (level > 0)
+	    debug_flag = level;
+	}
+      else
+	dbg_log (_("Unknown option: %s %s %s"), entry, arg1, arg2);
+    }
+  while (!feof (fp));
+
+  /* Free the buffer.  */
+  free (line);
+  /* Close configuration file.  */
+  fclose (fp);
+
+  return 0;
+}
diff --git a/nscd/nscd_getgr_r.c b/nscd/nscd_getgr_r.c
new file mode 100644
index 0000000000..6739657e48
--- /dev/null
+++ b/nscd/nscd_getgr_r.c
@@ -0,0 +1,211 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "nscd.h"
+#include "nscd_proto.h"
+
+static int __nscd_getgr_r (const char *key, request_type type,
+			   struct group *resultbuf, char *buffer,
+			   size_t buflen);
+
+int
+__nscd_getgrnam_r (const char *name, struct group *resultbuf, char *buffer,
+		   size_t buflen)
+{
+  if (name == NULL)
+    return 1;
+
+  return __nscd_getgr_r (name, GETGRBYNAME, resultbuf, buffer, buflen);
+}
+
+int
+__nscd_getgrgid_r (gid_t gid, struct group *resultbuf, char *buffer,
+		   size_t buflen)
+{
+  char *p = buffer;
+  char plen;
+
+  plen = snprintf (buffer, buflen, "%d", gid);
+  if (plen == -1)
+    {
+      __set_errno (ERANGE);
+      return -1;
+    }
+  p = buffer + plen + 1;
+
+  return __nscd_getgr_r (buffer, GETGRBYGID, resultbuf, p, buflen - plen -1);
+}
+
+/* Create a socket connected to a name. */
+static int
+nscd_open_socket (void)
+{
+  struct sockaddr_un addr;
+  int sock;
+
+  sock = socket (PF_UNIX, SOCK_STREAM, 0);
+  if (sock < 0)
+    return -1;
+
+  addr.sun_family = AF_UNIX;
+  strcpy (addr.sun_path, _PATH_NSCDSOCKET);
+  if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
+    {
+      close (sock);
+      return -1;
+    }
+
+  return sock;
+}
+
+static int
+__nscd_getgr_r (const char *key, request_type type, struct group *resultbuf,
+		char *buffer, size_t buflen)
+{
+  int sock = nscd_open_socket ();
+  request_header req;
+  gr_response_header gr_resp;
+  ssize_t nbytes;
+
+  if (sock == -1)
+    return 1;
+
+  req.version = NSCD_VERSION;
+  req.type = type;
+  req.key_len = strlen (key);
+  nbytes = write (sock, &req, sizeof (request_header));
+  if (nbytes != sizeof (request_header))
+    {
+      close (sock);
+      return 1;
+    }
+
+  nbytes = write (sock, key, req.key_len);
+  if (nbytes != req.key_len)
+    {
+      close (sock);
+      return 1;
+    }
+
+  nbytes = read (sock, &gr_resp, sizeof (gr_response_header));
+  if (nbytes != sizeof (gr_response_header))
+    {
+      close (sock);
+      return 1;
+    }
+
+  if (gr_resp.found == -1)
+    {
+      close (sock);
+      return 1;
+    }
+
+  if (gr_resp.found == 1)
+    {
+      size_t i;
+      char *p = buffer;
+
+      if (buflen < gr_resp.gr_name_len + 1)
+	{
+	  __set_errno (ERANGE);
+	  close (sock);
+	  return -1;
+	}
+      resultbuf->gr_name = p;
+      p += gr_resp.gr_name_len + 1;
+      buflen -= (gr_resp.gr_name_len + 1);
+      nbytes = read (sock, resultbuf->gr_name, gr_resp.gr_name_len);
+      if (nbytes != gr_resp.gr_name_len)
+	{
+	  close (sock);
+	  return 1;
+	}
+      resultbuf->gr_name[gr_resp.gr_name_len] = '\0';
+
+      if (buflen < gr_resp.gr_passwd_len + 1)
+	{
+	  __set_errno (ERANGE);
+	  close (sock);
+	  return -1;
+	}
+      resultbuf->gr_passwd = p;
+      p += gr_resp.gr_passwd_len + 1;
+      buflen -= (gr_resp.gr_passwd_len + 1);
+      nbytes = read (sock, resultbuf->gr_passwd, gr_resp.gr_passwd_len);
+      if (nbytes != gr_resp.gr_passwd_len)
+	{
+	  close (sock);
+	  return 1;
+	}
+      resultbuf->gr_passwd[gr_resp.gr_passwd_len] = '\0';
+
+      resultbuf->gr_gid = gr_resp.gr_gid;
+
+      if (buflen < ((gr_resp.gr_mem_len + 1) * sizeof (char *)))
+	{
+	  __set_errno (ERANGE);
+	  close (sock);
+	  return -1;
+	}
+      resultbuf->gr_mem = (char **)p;
+      p += ((gr_resp.gr_mem_len + 1) * sizeof (char *));
+      buflen -= ((gr_resp.gr_mem_len + 1) * sizeof (char *));
+
+      resultbuf->gr_mem[gr_resp.gr_mem_len] = NULL;
+
+      for (i = 0; i < gr_resp.gr_mem_len; ++i)
+	{
+	  size_t len;
+	  nbytes = read (sock, &len, sizeof (len));
+	  if (nbytes != sizeof (len))
+	    {
+	      close (sock);
+	      return 1;
+	    }
+
+	  if (buflen < (len + 1))
+	    {
+	      __set_errno (ERANGE);
+	      close (sock);
+	      return -1;
+	    }
+	  resultbuf->gr_mem[i] = p;
+	  p += len + 1;
+	  buflen -= (len + 1);
+	  nbytes = read (sock, resultbuf->gr_mem[i], len);
+	  resultbuf->gr_mem[i][len] = '\0';
+	  if (nbytes != len)
+	    {
+	      close (sock);
+	      return 1;
+	    }
+	}
+    }
+  close (sock);
+  return 0;
+}
diff --git a/nscd/nscd_getpw_r.c b/nscd/nscd_getpw_r.c
new file mode 100644
index 0000000000..c956abc3b4
--- /dev/null
+++ b/nscd/nscd_getpw_r.c
@@ -0,0 +1,198 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+
+#include "nscd.h"
+
+static int __nscd_getpw_r (const char *key, request_type type,
+			   struct passwd *resultbuf, char *buffer,
+			   size_t buflen);
+
+int
+__nscd_getpwnam_r (const char *name, struct passwd *resultbuf, char *buffer,
+		   size_t buflen)
+{
+  if (name == NULL)
+    return 1;
+
+  return __nscd_getpw_r (name, GETPWBYNAME, resultbuf, buffer, buflen);
+}
+
+int
+__nscd_getpwuid_r (uid_t uid, struct passwd *resultbuf, char *buffer,
+		   size_t buflen)
+{
+  char *p = buffer;
+  char plen;
+
+  plen = snprintf (buffer, buflen, "%d", uid);
+  if (plen == -1)
+    {
+      __set_errno (ERANGE);
+      return -1;
+    }
+  p = buffer + plen + 1;
+
+  return __nscd_getpw_r (buffer, GETPWBYUID, resultbuf, p, buflen - plen -1);
+}
+
+/* Create a socket connected to a name. */
+static int
+nscd_open_socket (void)
+{
+  struct sockaddr_un addr;
+  int sock;
+
+  sock = socket (PF_UNIX, SOCK_STREAM, 0);
+  if (sock < 0)
+    return -1;
+
+  addr.sun_family = AF_UNIX;
+  strcpy (addr.sun_path, _PATH_NSCDSOCKET);
+  if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0)
+    {
+      close (sock);
+      return -1;
+    }
+
+  return sock;
+}
+
+static int
+__nscd_getpw_r (const char *key, request_type type, struct passwd *resultbuf,
+		char *buffer, size_t buflen)
+{
+  int sock = nscd_open_socket ();
+  request_header req;
+  pw_response_header pw_resp;
+  ssize_t nbytes;
+
+  if (sock == -1)
+    return 1;
+
+  req.version = NSCD_VERSION;
+  req.type = type;
+  req.key_len = strlen (key);
+  nbytes = write (sock, &req, sizeof (request_header));
+  if (nbytes != sizeof (request_header))
+    {
+      close (sock);
+      return 1;
+    }
+
+  nbytes = write (sock, key, req.key_len);
+  if (nbytes != req.key_len)
+    {
+      close (sock);
+      return 1;
+    }
+
+  nbytes = read (sock, &pw_resp, sizeof (pw_response_header));
+  if (nbytes != sizeof (pw_response_header))
+    {
+      close (sock);
+      return 1;
+    }
+
+  if (pw_resp.found == -1)
+    {
+      close (sock);
+      return 1;
+    }
+
+  if (pw_resp.found == 1)
+    {
+      struct iovec vec[5];
+      char *p = buffer;
+
+      if (buflen < pw_resp.pw_name_len + 1 + pw_resp.pw_passwd_len + 1
+	  + pw_resp.pw_gecos_len + 1 + pw_resp.pw_dir_len + 1
+	  + pw_resp.pw_shell_len + 1)
+	{
+	  __set_errno (ERANGE);
+	  close (sock);
+	  return -1;
+	}
+
+      /* get pw_name */
+      vec[0].iov_base = p;
+      vec[0].iov_len = pw_resp.pw_name_len;
+      p += pw_resp.pw_name_len + 1;
+      buflen -= (pw_resp.pw_name_len + 1);
+      /* get pw_passwd */
+      vec[1].iov_base = p;
+      vec[1].iov_len = pw_resp.pw_passwd_len;
+      p += pw_resp.pw_passwd_len + 1;
+      buflen -= (pw_resp.pw_passwd_len + 1);
+      /* get pw_gecos */
+      vec[2].iov_base = p;
+      vec[2].iov_len = pw_resp.pw_gecos_len;
+      p += pw_resp.pw_gecos_len + 1;
+      buflen -= (pw_resp.pw_gecos_len + 1);
+      /* get pw_dir */
+      vec[3].iov_base = p;
+      vec[3].iov_len = pw_resp.pw_dir_len;
+      p += pw_resp.pw_dir_len + 1;
+      buflen -= (pw_resp.pw_dir_len + 1);
+      /* get pw_pshell */
+      vec[4].iov_base = p;
+      vec[4].iov_len = pw_resp.pw_dir_len;
+      p += pw_resp.pw_dir_len + 1;
+      buflen -= (pw_resp.pw_dir_len + 1);
+
+      nbytes = readv (sock, vec, 5);
+      if (nbytes !=  pw_resp.pw_name_len + 1 + pw_resp.pw_passwd_len + 1 +
+	  pw_resp.pw_gecos_len + 1 + pw_resp.pw_dir_len + 1 +
+	  pw_resp.pw_shell_len + 1)
+	{
+	  close (sock);
+	  return 1;
+	}
+
+      resultbuf->pw_name = vec[0].iov_base;
+      resultbuf->pw_name[pw_resp.pw_name_len] = '\0';
+      resultbuf->pw_passwd = vec[1].iov_base;
+      resultbuf->pw_passwd[pw_resp.pw_passwd_len] = '\0';
+      resultbuf->pw_uid = pw_resp.pw_uid;
+      resultbuf->pw_gid = pw_resp.pw_gid;
+      resultbuf->pw_gecos = vec[2].iov_base;
+      resultbuf->pw_gecos[pw_resp.pw_gecos_len] = '\0';
+      resultbuf->pw_dir = vec[3].iov_base;
+      resultbuf->pw_dir[pw_resp.pw_dir_len] = '\0';
+      resultbuf->pw_shell = vec[4].iov_base;
+      resultbuf->pw_shell[pw_resp.pw_shell_len] = '\0';
+
+      close (sock);
+      return 0;
+    }
+  else
+    {
+      close (sock);
+      return -1;
+    }
+}
diff --git a/nscd/nscd_proto.h b/nscd/nscd_proto.h
new file mode 100644
index 0000000000..6f7b30df88
--- /dev/null
+++ b/nscd/nscd_proto.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _NSCD_PROTO_H
+#define _NSCD_PROTO_H 1
+
+#include <grp.h>
+#include <pwd.h>
+
+extern int __nscd_getpwnam_r __P ((const char *name, struct passwd *resultbuf,
+				   char *buffer, size_t buflen));
+extern int __nscd_getpwuid_r __P ((uid_t uid, struct passwd *resultbuf,
+				   char *buffer,  size_t buflen));
+extern int __nscd_getgrnam_r __P ((const char *name, struct group *resultbuf,
+				   char *buffer, size_t buflen));
+extern int __nscd_getgrgid_r __P ((uid_t uid, struct group *resultbuf,
+				   char *buffer,  size_t buflen));
+
+#endif /* _NSCD_PROTO_H */
diff --git a/nscd/nscd_stat.c b/nscd/nscd_stat.c
new file mode 100644
index 0000000000..d8182885ac
--- /dev/null
+++ b/nscd/nscd_stat.c
@@ -0,0 +1,87 @@
+/* Copyright (c) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "nscd.h"
+
+void
+print_stat (void)
+{
+  int sock = __nscd_open_socket ();
+  request_header req;
+  stat_response_header resp;
+  ssize_t nbytes;
+
+  if (sock == -1)
+    {
+      fputs (_("nscd not running!\n"), stdout);
+      exit (EXIT_FAILURE);
+    }
+
+  req.version = NSCD_VERSION;
+  req.type = GETSTAT;
+  req.key_len = 0;
+  nbytes = write (sock, &req, sizeof (request_header));
+  if (nbytes != sizeof (request_header))
+    {
+      perror (_("write incomplete"));
+      close (sock);
+      exit (EXIT_FAILURE);
+    }
+
+  nbytes = read (sock, &resp, sizeof (stat_response_header));
+  if (nbytes != sizeof (stat_response_header))
+    {
+      perror (_("read incomplete"));
+      close (sock);
+      exit (EXIT_FAILURE);
+    }
+
+  close (sock);
+
+  printf (_("nscd configuration:\n\n"));
+  printf (_("%12d  server debug level\n\n"), resp.debug_level);
+
+  printf (_("passwd cache:\n\n"));
+  printf (_("%12s  cache is enabled\n"), resp.pw_enabled ? _("Yes") : _("No"));
+  printf (_("%12ld  cache hits on positive entries\n"), resp.pw_poshit);
+  printf (_("%12ld  cache hits on negative entries\n"), resp.pw_neghit);
+  printf (_("%12ld  cache misses on positive entries\n"), resp.pw_posmiss);
+  printf (_("%12ld  cache misses on negative entries\n"), resp.pw_negmiss);
+  printf (_("%12ld  suggested size\n"), resp.pw_size);
+  printf (_("%12ld  seconds time to live for positive entries\n"),
+	  resp.pw_posttl);
+  printf (_("%12ld  seconds time to live for negative entries\n\n"),
+	  resp.pw_negttl);
+
+  printf (_("group cache:\n\n"));
+  printf (_("%12s  cache is enabled\n"), resp.gr_enabled ? _("Yes") : _("No"));
+  printf (_("%12ld  cache hits on positive entries\n"), resp.gr_poshit);
+  printf (_("%12ld  cache hits on negative entries\n"), resp.gr_neghit);
+  printf (_("%12ld  cache misses on positive entries\n"), resp.gr_posmiss);
+  printf (_("%12ld  cache misses on negative entries\n"), resp.gr_negmiss);
+  printf (_("%12ld  suggested size\n"), resp.gr_size);
+  printf (_("%12ld  seconds time to live for positive entries\n"),
+	  resp.gr_posttl);
+  printf (_("%12ld  seconds time to live for negative entries\n"),
+	  resp.gr_negttl);
+}
diff --git a/nscd/pwdcache.c b/nscd/pwdcache.c
new file mode 100644
index 0000000000..a3676666da
--- /dev/null
+++ b/nscd/pwdcache.c
@@ -0,0 +1,581 @@
+/* Copyright (c) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA. */
+
+#include <errno.h>
+#include <malloc.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <string.h>
+#include <rpcsvc/nis.h>
+#include <sys/types.h>
+
+#include "dbg_log.h"
+#include "nscd.h"
+
+static unsigned long int modulo = 211;
+static unsigned long int postimeout = 600;
+static unsigned long int negtimeout = 20;
+
+static unsigned long int poshit = 0;
+static unsigned long int posmiss = 0;
+static unsigned long int neghit = 0;
+static unsigned long int negmiss = 0;
+
+struct pwdhash
+{
+  time_t create;
+  struct pwdhash *next;
+  struct passwd *pwd;
+};
+typedef struct pwdhash pwdhash;
+
+struct uidhash
+{
+  struct uidhash *next;
+  struct pwdhash *pwptr;
+};
+typedef struct uidhash uidhash;
+
+struct neghash
+{
+  time_t create;
+  struct neghash *next;
+  char *key;
+};
+typedef struct neghash neghash;
+
+static pwdhash *pwdtbl;
+static uidhash *uidtbl;
+static neghash *negtbl;
+
+static pthread_rwlock_t pwdlock = PTHREAD_RWLOCK_INITIALIZER;
+static pthread_rwlock_t neglock = PTHREAD_RWLOCK_INITIALIZER;
+
+static void *pwdtable_update (void *);
+static void *negtable_update (void *);
+
+void
+get_pw_stat (stat_response_header *stat)
+{
+  stat->pw_poshit = poshit;
+  stat->pw_posmiss = posmiss;
+  stat->pw_neghit = neghit;
+  stat->pw_negmiss = negmiss;
+  stat->pw_size = modulo;
+  stat->pw_posttl = postimeout;
+  stat->pw_negttl = negtimeout;
+}
+
+void
+set_pwd_modulo (unsigned long int mod)
+{
+  modulo = mod;
+}
+
+void
+set_pos_pwd_ttl (unsigned long int ttl)
+{
+  postimeout = ttl;
+}
+
+void
+set_neg_pwd_ttl (unsigned long int ttl)
+{
+  negtimeout = ttl;
+}
+
+int
+cache_pwdinit ()
+{
+  pthread_t thread;
+
+  pwdtbl = calloc (modulo, sizeof (pwdhash));
+  if (pwdtbl == NULL)
+    return -1;
+  uidtbl = calloc (modulo, sizeof (pwdhash));
+  if (uidtbl == NULL)
+    return -1;
+  negtbl = calloc (modulo, sizeof (neghash));
+  if (negtbl == NULL)
+    return -1;
+
+  pthread_create (&thread, NULL, pwdtable_update, (void *)NULL);
+  pthread_detach (thread);
+  pthread_create (&thread, NULL, negtable_update, (void *)NULL);
+  pthread_detach (thread);
+  return 0;
+}
+
+static struct passwd *
+save_pwd (struct passwd *src)
+{
+  struct passwd *dest;
+
+  dest = calloc (1, sizeof (struct passwd));
+  dest->pw_name = strdup (src->pw_name);
+  dest->pw_passwd = strdup (src->pw_passwd);
+  dest->pw_uid = src->pw_uid;
+  dest->pw_gid = src->pw_gid;
+  dest->pw_gecos = strdup (src->pw_gecos);
+  dest->pw_dir = strdup (src->pw_dir);
+  dest->pw_shell = strdup (src->pw_shell);
+
+  return dest;
+}
+
+static void
+free_pwd (struct passwd *src)
+{
+  free (src->pw_name);
+  free (src->pw_passwd);
+  free (src->pw_gecos);
+  free (src->pw_dir);
+  free (src->pw_shell);
+  free (src);
+}
+
+static int
+add_cache (struct passwd *pwd)
+{
+  pwdhash *work;
+  unsigned long int hash = __nis_hash (pwd->pw_name,
+				       strlen (pwd->pw_name)) % modulo;
+
+  if (debug_flag)
+    dbg_log (_("add_cache (%s)"), pwd->pw_name);
+
+  work = &pwdtbl[hash];
+
+  if (pwdtbl[hash].pwd == NULL)
+    pwdtbl[hash].pwd = save_pwd (pwd);
+  else
+    {
+      while (work->next != NULL)
+	work = work->next;
+
+      work->next = calloc (1, sizeof (pwdhash));
+      work->next->pwd = save_pwd (pwd);
+      work = work->next;
+    }
+  /* Set a pointer from the pwuid hash table to the pwname hash table */
+  time (&work->create);
+  uidtbl[pwd->pw_uid % modulo].pwptr = work;
+
+  return 0;
+}
+
+static struct passwd *
+cache_search_name (const char *name)
+{
+  pwdhash *work;
+  unsigned long int hash = __nis_hash (name, strlen (name)) % modulo;
+
+  work = &pwdtbl[hash];
+
+  while (work->pwd != NULL)
+    {
+      if (strcmp (work->pwd->pw_name, name) == 0)
+	return work->pwd;
+      if (work->next != NULL)
+	work = work->next;
+      else
+	return NULL;
+    }
+  return NULL;
+}
+
+static struct passwd *
+cache_search_uid (uid_t uid)
+{
+  uidhash *work;
+
+  work = &uidtbl[uid % modulo];
+
+  while (work->pwptr != NULL)
+    {
+      if (work->pwptr->pwd->pw_uid == uid)
+	return work->pwptr->pwd;
+      if (work->next != NULL)
+	work = work->next;
+      else
+	return NULL;
+    }
+  return NULL;
+}
+
+static int
+add_negcache (char *key)
+{
+  neghash *work;
+  unsigned long int hash = __nis_hash (key, strlen (key)) % modulo;
+
+  if (debug_flag)
+    dbg_log (_("add_netgache (%s|%ld)"), key, hash);
+
+  work = &negtbl[hash];
+
+  if (negtbl[hash].key == NULL)
+    {
+      negtbl[hash].key = strdup (key);
+      negtbl[hash].next = NULL;
+    }
+  else
+    {
+      while (work->next != NULL)
+	work = work->next;
+
+      work->next = calloc (1, sizeof (neghash));
+      work->next->key = strdup (key);
+      work = work->next;
+    }
+  /* Set a pointer from the pwuid hash table to the pwname hash table */
+  time (&work->create);
+
+  return 0;
+}
+
+static int
+cache_search_neg (const char *key)
+{
+  neghash *work;
+  unsigned long int hash = __nis_hash (key, strlen (key)) % modulo;
+
+  work = &negtbl[hash];
+
+  if (debug_flag)
+    dbg_log (_("cache_search_neg (%s|%ld)"), key, hash);
+
+  while (work->key != NULL)
+    {
+      if (strcmp (work->key, key) == 0)
+	return 1;
+      if (work->next != NULL)
+	work = work->next;
+      else
+	return 0;
+    }
+  return 0;
+}
+
+void *
+cache_getpwnam (void *v_param)
+{
+  param_t *param = (param_t *)v_param;
+  struct passwd *pwd, resultbuf;
+
+  pthread_rwlock_rdlock (&pwdlock);
+  pwd = cache_search_name (param->key);
+
+  /* I don't like it to hold the read only lock longer, but it is
+     necessary to avoid to much malloc/free/strcpy.  */
+
+  if (pwd != NULL)
+    {
+      if (debug_flag)
+	dbg_log (_("Found \"%s\" in cache !"), param->key);
+
+      ++poshit;
+      pw_send_answer (param->conn, pwd);
+      close_socket (param->conn);
+
+      pthread_rwlock_unlock (&pwdlock);
+      pwd = &resultbuf;
+    }
+  else
+    {
+      int status;
+      int buflen = 1024;
+      char *buffer = malloc (buflen);
+
+      if (debug_flag)
+	dbg_log (_("Doesn't found \"%s\" in cache !"), param->key);
+
+      pthread_rwlock_unlock (&pwdlock);
+
+      pthread_rwlock_rdlock (&neglock);
+      status = cache_search_neg (param->key);
+      pthread_rwlock_unlock (&neglock);
+
+      if (status == 0)
+	{
+	  while (buffer != NULL
+		 && (getpwnam_r (param->key, &resultbuf, buffer, buflen, &pwd)
+		     != 0)
+		 && errno == ERANGE)
+	    {
+	      errno = 0;
+	      buflen += 1024;
+	      buffer = realloc (buffer, buflen);
+	    }
+
+	  if (buffer != NULL && pwd != NULL)
+	    {
+	      struct passwd *tmp;
+
+	      ++posmiss;
+	      pthread_rwlock_wrlock (&pwdlock);
+	      /* While we are waiting on the lock, somebody else could
+		 add this entry.  */
+	      tmp = cache_search_name (param->key);
+	      if (tmp == NULL)
+		add_cache (pwd);
+	      pthread_rwlock_unlock (&pwdlock);
+	    }
+	  else
+	    {
+	      ++negmiss;
+	      pthread_rwlock_wrlock (&neglock);
+	      add_negcache (param->key);
+	      pthread_rwlock_unlock (&neglock);
+	    }
+	}
+      else
+	++neghit;
+      pw_send_answer (param->conn, pwd);
+      close_socket (param->conn);
+      if (buffer != NULL)
+	free (buffer);
+    }
+  free (param->key);
+  free (param);
+  return NULL;
+}
+
+void *
+cache_pw_disabled (void *v_param)
+{
+  param_t *param = (param_t *)v_param;
+
+  pw_send_disabled (param->conn);
+  return NULL;
+}
+
+void *
+cache_getpwuid (void *v_param)
+{
+  param_t *param = (param_t *)v_param;
+  struct passwd *pwd, resultbuf;
+  uid_t uid = strtol (param->key, NULL, 10);
+
+  pthread_rwlock_rdlock (&pwdlock);
+  pwd = cache_search_uid (uid);
+
+  /* I don't like it to hold the read only lock longer, but it is
+     necessary to avoid to much malloc/free/strcpy.  */
+
+  if (pwd != NULL)
+    {
+      if (debug_flag)
+	dbg_log (_("Found \"%d\" in cache !"), uid);
+
+      ++poshit;
+      pw_send_answer (param->conn, pwd);
+      close_socket (param->conn);
+
+      pthread_rwlock_unlock (&pwdlock);
+    }
+  else
+    {
+      int buflen = 1024;
+      char *buffer = malloc (buflen);
+      int status;
+
+      if (debug_flag)
+	dbg_log (_("Doesn't found \"%d\" in cache !"), uid);
+
+      pthread_rwlock_unlock (&pwdlock);
+
+      pthread_rwlock_rdlock (&neglock);
+      status = cache_search_neg (param->key);
+      pthread_rwlock_unlock (&neglock);
+
+      if (status == 0)
+        {
+	  while (buffer != NULL
+		 && (getpwuid_r (uid, &resultbuf, buffer, buflen, &pwd) != 0)
+		 && errno == ERANGE)
+	    {
+	      errno = 0;
+	      buflen += 1024;
+	      buffer = realloc (buffer, buflen);
+	    }
+
+	  if (buffer != NULL && pwd != NULL)
+	    {
+	      struct passwd *tmp;
+
+	      ++posmiss;
+	      pthread_rwlock_wrlock (&pwdlock);
+	      /* While we are waiting on the lock, somebody else could
+		 add this entry.  */
+	      tmp = cache_search_uid (uid);
+	      if (tmp == NULL)
+		add_cache (pwd);
+	      pthread_rwlock_unlock (&pwdlock);
+	    }
+	  else
+	    {
+	      ++negmiss;
+	      pthread_rwlock_wrlock (&neglock);
+	      add_negcache (param->key);
+	      pthread_rwlock_unlock (&neglock);
+	    }
+	}
+      else
+	++neghit;
+
+      pw_send_answer (param->conn, pwd);
+      close_socket (param->conn);
+      if (buffer != NULL)
+	free (buffer);
+    }
+  free (param->key);
+  free (param);
+  return NULL;
+}
+
+void *
+pwdtable_update (void *v)
+{
+  time_t now;
+  int i;
+
+  sleep (20);
+
+  while (!do_shutdown)
+    {
+      if (debug_flag > 2)
+	dbg_log (_("(pwdtable_update) Wait for write lock!"));
+
+      pthread_rwlock_wrlock (&pwdlock);
+
+      if (debug_flag > 2)
+	dbg_log (_("(pwdtable_update) Have write lock"));
+
+      time (&now);
+      for (i = 0; i < modulo; ++i)
+	{
+	  pwdhash *work = &pwdtbl[i];
+
+	  while (work && work->pwd)
+	    {
+	      if ((now - work->create) >= postimeout)
+		{
+		  uidhash *uh = &uidtbl[work->pwd->pw_uid % modulo];
+
+		  if (debug_flag)
+		    dbg_log (_("Give \"%s\" free"), work->pwd->pw_name);
+
+		  while (uh != NULL && uh->pwptr)
+		    {
+		      if (uh->pwptr->pwd->pw_uid == work->pwd->pw_uid)
+			{
+			  if (debug_flag)
+			    dbg_log (_("Give uid for \"%s\" free"),
+				     work->pwd->pw_name);
+			  if (uh->next != NULL)
+			    {
+			      uidhash *tmp = uh->next;
+			      uh->pwptr = tmp->pwptr;
+			      uh->next = tmp->next;
+			      free (tmp);
+			    }
+			  else
+			    uh->pwptr = NULL;
+			}
+		      uh = uh->next;
+		    }
+
+		  free_pwd (work->pwd);
+		  if (work->next != NULL)
+		    {
+		      pwdhash *tmp = work->next;
+		      work->create = tmp->create;
+		      work->next = tmp->next;
+		      work->pwd = tmp->pwd;
+		      free (tmp);
+		    }
+		  else
+		    work->pwd = NULL;
+		}
+	      work = work->next;
+	    }
+	}
+      if (debug_flag > 2)
+	dbg_log (_("(pwdtable_update) Release wait lock"));
+      pthread_rwlock_unlock (&pwdlock);
+      sleep (20);
+    }
+  return NULL;
+}
+
+void *
+negtable_update (void *v)
+{
+  time_t now;
+  int i;
+
+  sleep (30);
+
+  while (!do_shutdown)
+    {
+      if (debug_flag > 2)
+	dbg_log (_("(negtable_update) Wait for write lock!"));
+
+      pthread_rwlock_wrlock (&neglock);
+
+      if (debug_flag)
+	dbg_log (_("(negtable_update) Have write lock"));
+
+      time (&now);
+      for (i = 0; i < modulo; ++i)
+	{
+	  neghash *work = &negtbl[i];
+
+	  while (work && work->key)
+	    {
+	      if ((now - work->create) >= negtimeout)
+		{
+		  if (debug_flag)
+		    dbg_log (_("Give \"%s\" free"), work->key);
+
+		  free (work->key);
+
+		  if (work->next != NULL)
+		    {
+		      neghash *tmp = work->next;
+		      work->create = tmp->create;
+		      work->next = tmp->next;
+		      work->key = tmp->key;
+		      free (tmp);
+		    }
+		  else
+		    work->key = NULL;
+		}
+	      work = work->next;
+	    }
+	}
+      if (debug_flag)
+	dbg_log (_("(negtable_update) Release wait lock"));
+
+      pthread_rwlock_unlock (&neglock);
+      sleep (10);
+    }
+  return NULL;
+}
diff --git a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c
index 47df01054e..d20fa34498 100644
--- a/nss/getXXbyYY_r.c
+++ b/nss/getXXbyYY_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
@@ -19,6 +19,7 @@
 
 #include <errno.h>
 #include "nsswitch.h"
+#include <nscd/nscd_proto.h>
 
 /*******************************************************************\
 |* Here we assume several symbols to be defined:		   *|
@@ -51,6 +52,12 @@
 #define INTERNAL(name) INTERNAL1 (name)
 #define INTERNAL1(name) __##name
 
+#ifdef USE_NSCD
+# define NSCD_NAME ADD_NSCD (REENTRANT_NAME)
+# define ADD_NSCD(name) ADD_NSCD1 (name)
+# define ADD_NSCD1(name) __nscd_##name
+#endif
+
 #define FUNCTION_NAME_STRING STRINGIZE (FUNCTION_NAME)
 #define REENTRANT_NAME_STRING STRINGIZE (REENTRANT_NAME)
 #define DATABASE_NAME_STRING STRINGIZE (DATABASE_NAME)
@@ -93,6 +100,9 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
   lookup_function fct;
   int no_more;
   enum nss_status status = NSS_STATUS_UNAVAIL;
+#ifdef USE_NSCD
+  int nscd_status;
+#endif
 
 #ifdef HANDLE_DIGITS_DOTS
 # define resbuf (*resbuf)
@@ -100,6 +110,15 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
 # undef resbuf
 #endif
 
+#ifdef USE_NSCD
+  nscd_status = NSCD_NAME (ADD_VARIABLES, resbuf, buffer, buflen H_ERRNO_VAR);
+  if (nscd_status < 1)
+    {
+      *result = nscd_status == 0 ? resbuf : NULL;
+      return nscd_status;
+    }
+#endif
+
   if (startp == NULL)
     {
       no_more = DB_LOOKUP_FCT (&nip, REENTRANT_NAME_STRING, (void **) &fct);
diff --git a/pwd/getpwnam_r.c b/pwd/getpwnam_r.c
index 0dc1eacaed..429d3c47b0 100644
--- a/pwd/getpwnam_r.c
+++ b/pwd/getpwnam_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
@@ -26,5 +26,6 @@
 #define ADD_PARAMS	const char *name
 #define ADD_VARIABLES	name
 #define BUFLEN		NSS_BUFLEN_PASSWD
+#define USE_NSCD	1
 
-#include "../nss/getXXbyYY_r.c"
+#include <nss/getXXbyYY_r.c>
diff --git a/pwd/getpwuid_r.c b/pwd/getpwuid_r.c
index 4db8bc0317..18b925b794 100644
--- a/pwd/getpwuid_r.c
+++ b/pwd/getpwuid_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
@@ -26,5 +26,6 @@
 #define ADD_PARAMS	uid_t uid
 #define ADD_VARIABLES	uid
 #define BUFLEN		NSS_BUFLEN_PASSWD
+#define USE_NSCD	1
 
-#include "../nss/getXXbyYY_r.c"
+#include <nss/getXXbyYY_r.c>
diff --git a/sysdeps/unix/inet/Subdirs b/sysdeps/unix/inet/Subdirs
index 0dc102b03f..4a191e2993 100644
--- a/sysdeps/unix/inet/Subdirs
+++ b/sysdeps/unix/inet/Subdirs
@@ -3,4 +3,5 @@ resolv
 hesiod
 sunrpc
 nis
+nscd
 streams