about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1996-12-11 01:40:39 +0000
committerUlrich Drepper <drepper@redhat.com>1996-12-11 01:40:39 +0000
commit6259ec0d78fd301572fcb616fdfa0500b828a824 (patch)
treeb1a008ed66281799defcaf56a92d3b592ca1f34a
parentaee321f468f9214700b24e7aef39ef27bda4c42c (diff)
downloadglibc-cvs/libc-961211.tar.gz
glibc-cvs/libc-961211.tar.xz
glibc-cvs/libc-961211.zip
update from main arcive 961210 cvs/libc-961211
Wed Dec 11 01:04:30 1996  Ulrich Drepper  <drepper@cygnus.com>

	Add NIS NSS implementation.
	* shlib-versions: Add versions for NIS libraries.
	* sysdeps/unix/inet/Subdirs: Add nis.
	* nis/Banner: New file.
	* nis/Makefile: New file.
	* nis/nss-nis.h: New file.
	* nis/yp_xdr.h: New file.
	* nis/ypclnt.h: New file.
	* nis/ypupdate_xdr.c: New file.
	* nis/nss_compat/compat-grp.c: New file.
	* nis/nss_compat/compat-pwd.c: New file.
	* nis/nss_compat/compat-spwd.c: New file.
	* nis/nss_nis/nis-alias.c: New file.
	* nis/nss_nis/nis-ethers.c: New file.
	* nis/nss_nis/nis-grp.c: New file.
	* nis/nss_nis/nis-hosts.c: New file.
	* nis/nss_nis/nis-netgrp.c: New file.
	* nis/nss_nis/nis-network.c: New file.
	* nis/nss_nis/nis-proto.c: New file.
	* nis/nss_nis/nis-publickey.c: New file.
	* nis/nss_nis/nis-pwd.c: New file.
	* nis/nss_nis/nis-rpc.c: New file.
	* nis/nss_nis/nis-service.c: New file.
	* nis/nss_nis/nis-spwd.c: New file.
	* nis/rpcsvc/yp.h: New file.
	* nis/rpcsvc/yp.x: New file.
	* nis/rpcsvc/yp_prot.h: New file.
	* nis/rpcsvc/ypclnt.h: New file.
	* nis/rpcsvc/ypupd.h: New file.

	* libio/_G_config.h: Define _G_HAVE_SYS_WAIT and _G_HAVE_PRINTF_FP.

	* locale/C-numeric.c: Update copyright.

	* locale/Makefile: Add rules to build libBrokenLocale.
	* locale/broken_cur_max.c: New file.
	* locale/mb_cur_max.c: Update copyright.
	(__ctype_get_mb_cur_max): Make function weak.

	* new-malloc/malloc.c: Correct copyright.
	* new-malloc/thread-m.h: Correct key handling.

	* shadow/lckpwdf.c: Update copyright.
	(PWD_LOCKFILE): Change to /etc/.pwd.lock.

	* stdlib/strtod.c: Add another assertion.
	* stdlib/tst-strtod.c: Add another test case.

	* sysdeps/generic/paths.h: Add _PATH_PRESERVE.  Needed by nvi.
	* sysdeps/unix/sysv/linux/paths.h: Likewise.

	* sysdeps/gnu/utmpbits.h: Rename ut_addr field to ut_addr_v6.
	ut_addr names a single element in ut_addr_v6.

	* sysdeps/mach/hurd/xmknod.c: Remove alias from __mknod to mknod.
	Patch by Thomas Bushnell, n/BSG.

Tue Dec 10 11:35:28 1996  Richard Henderson  <rth@tamu.edu>

	* sysdeps/alpha/strncmp.S: Fix aligned short truncated compare
	corner condition.

	* sysdeps/alpha/memchr.S: Don't read ahead, even if the load
	did fit nicely into that delay slot (patch from David Mosberger-Tang).

Mon Dec  9 23:53:43 1996  Thomas Bushnell, n/BSG  <thomas@gnu.ai.mit.edu>

	* sysdeps/mach/hurd/ttyname_r.c (__ttyname_r): Renamed from
	`ttyname_r'.
	(ttyname_r): New alias.

	* stdio-common/printf_fp.c (__guess_grouping): Fix off by one
-rw-r--r--ChangeLog75
-rw-r--r--libio/_G_config.h3
-rw-r--r--locale/C-numeric.c28
-rw-r--r--locale/Makefile10
-rw-r--r--locale/broken_cur_max.c50
-rw-r--r--locale/mb_cur_max.c31
-rw-r--r--malloc/malloc.c3
-rw-r--r--malloc/thread-m.h21
-rw-r--r--nis/Banner1
-rw-r--r--nis/Makefile100
-rw-r--r--nis/nss-nis.h58
-rw-r--r--nis/nss_compat/compat-grp.c421
-rw-r--r--nis/nss_compat/compat-pwd.c695
-rw-r--r--nis/nss_compat/compat-spwd.c612
-rw-r--r--nis/nss_nis/nis-alias.c269
-rw-r--r--nis/nss_nis/nis-ethers.c264
-rw-r--r--nis/nss_nis/nis-grp.c246
-rw-r--r--nis/nss_nis/nis-hosts.c389
-rw-r--r--nis/nss_nis/nis-netgrp.c128
-rw-r--r--nis/nss_nis/nis-network.c292
-rw-r--r--nis/nss_nis/nis-proto.c246
-rw-r--r--nis/nss_nis/nis-publickey.c220
-rw-r--r--nis/nss_nis/nis-pwd.c246
-rw-r--r--nis/nss_nis/nis-rpc.c270
-rw-r--r--nis/nss_nis/nis-service.c249
-rw-r--r--nis/nss_nis/nis-spwd.c196
-rw-r--r--nis/rpcsvc/yp.h611
-rw-r--r--nis/rpcsvc/yp.x300
-rw-r--r--nis/rpcsvc/yp_prot.h334
-rw-r--r--nis/rpcsvc/ypclnt.h88
-rw-r--r--nis/rpcsvc/ypupd.h88
-rw-r--r--nis/yp_xdr.c342
-rw-r--r--nis/ypclnt.c868
-rw-r--r--nis/ypupdate_xdr.c73
-rw-r--r--shadow/lckpwdf.c40
-rw-r--r--shlib-versions8
-rw-r--r--stdlib/strtod.c2
-rw-r--r--stdlib/tst-strtod.c1
-rw-r--r--sysdeps/alpha/memchr.S29
-rw-r--r--sysdeps/alpha/strncmp.S8
-rw-r--r--sysdeps/generic/paths.h1
-rw-r--r--sysdeps/gnu/utmpbits.h6
-rw-r--r--sysdeps/mach/hurd/ttyname_r.c4
-rw-r--r--sysdeps/mach/hurd/xmknod.c30
-rw-r--r--sysdeps/unix/inet/Subdirs1
-rw-r--r--sysdeps/unix/sysv/linux/paths.h1
46 files changed, 7861 insertions, 97 deletions
diff --git a/ChangeLog b/ChangeLog
index a44bf03a26..c67e8d1978 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,79 @@
+Wed Dec 11 01:04:30 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+	Add NIS NSS implementation.
+	* shlib-versions: Add versions for NIS libraries.
+	* sysdeps/unix/inet/Subdirs: Add nis.
+	* nis/Banner: New file.
+	* nis/Makefile: New file.
+	* nis/nss-nis.h: New file.
+	* nis/yp_xdr.h: New file.
+	* nis/ypclnt.h: New file.
+	* nis/ypupdate_xdr.c: New file.
+	* nis/nss_compat/compat-grp.c: New file.
+	* nis/nss_compat/compat-pwd.c: New file.
+	* nis/nss_compat/compat-spwd.c: New file.
+	* nis/nss_nis/nis-alias.c: New file.
+	* nis/nss_nis/nis-ethers.c: New file.
+	* nis/nss_nis/nis-grp.c: New file.
+	* nis/nss_nis/nis-hosts.c: New file.
+	* nis/nss_nis/nis-netgrp.c: New file.
+	* nis/nss_nis/nis-network.c: New file.
+	* nis/nss_nis/nis-proto.c: New file.
+	* nis/nss_nis/nis-publickey.c: New file.
+	* nis/nss_nis/nis-pwd.c: New file.
+	* nis/nss_nis/nis-rpc.c: New file.
+	* nis/nss_nis/nis-service.c: New file.
+	* nis/nss_nis/nis-spwd.c: New file.
+	* nis/rpcsvc/yp.h: New file.
+	* nis/rpcsvc/yp.x: New file.
+	* nis/rpcsvc/yp_prot.h: New file.
+	* nis/rpcsvc/ypclnt.h: New file.
+	* nis/rpcsvc/ypupd.h: New file.
+
+	* libio/_G_config.h: Define _G_HAVE_SYS_WAIT and _G_HAVE_PRINTF_FP.
+
+	* locale/C-numeric.c: Update copyright.
+
+	* locale/Makefile: Add rules to build libBrokenLocale.
+	* locale/broken_cur_max.c: New file.
+	* locale/mb_cur_max.c: Update copyright.
+	(__ctype_get_mb_cur_max): Make function weak.
+
+	* new-malloc/malloc.c: Correct copyright.
+	* new-malloc/thread-m.h: Correct key handling.
+
+	* shadow/lckpwdf.c: Update copyright.
+	(PWD_LOCKFILE): Change to /etc/.pwd.lock.
+
+	* stdlib/strtod.c: Add another assertion.
+	* stdlib/tst-strtod.c: Add another test case.
+
+	* sysdeps/generic/paths.h: Add _PATH_PRESERVE.  Needed by nvi.
+	* sysdeps/unix/sysv/linux/paths.h: Likewise.
+
+	* sysdeps/gnu/utmpbits.h: Rename ut_addr field to ut_addr_v6.
+	ut_addr names a single element in ut_addr_v6.
+
+	* sysdeps/mach/hurd/xmknod.c: Remove alias from __mknod to mknod.
+	Patch by Thomas Bushnell, n/BSG.
+
+Tue Dec 10 11:35:28 1996  Richard Henderson  <rth@tamu.edu>
+
+	* sysdeps/alpha/strncmp.S: Fix aligned short truncated compare
+	corner condition.
+
+	* sysdeps/alpha/memchr.S: Don't read ahead, even if the load
+	did fit nicely into that delay slot (patch from David Mosberger-Tang).
+
+Mon Dec  9 23:53:43 1996  Thomas Bushnell, n/BSG  <thomas@gnu.ai.mit.edu>
+
+	* sysdeps/mach/hurd/ttyname_r.c (__ttyname_r): Renamed from
+	`ttyname_r'.
+	(ttyname_r): New alias.
+
 Tue Dec 10 02:17:31 1996  Ulrich Drepper  <drepper@cygnus.com>
 
-	* stdio-common/printf_fp.c (__guess_grouping): Fix of by one
+	* stdio-common/printf_fp.c (__guess_grouping): Fix off by one
 	error in computation of number of groups.
 	Patch sent by Harald Schreiber <Harald.Schreiber@post.rwth-aachen.de>.
 
diff --git a/libio/_G_config.h b/libio/_G_config.h
index 5340055fc7..34d77e2b80 100644
--- a/libio/_G_config.h
+++ b/libio/_G_config.h
@@ -19,10 +19,13 @@
 
 /* These library features are always available in the GNU C library.  */
 #define _G_HAVE_ATEXIT 1
+#define _G_HAVE_SYS_CDEFS 1
 #define _G_HAVE_SYS_WAIT 1
 #define _G_NEED_STDARG_H 1
 #define _G_va_list __gnuc_va_list
 
+#define _G_HAVE_PRINTF_FP 1
+
 /* This is defined by <statbuf.h> if `st_blksize' exists.  */
 #define _G_HAVE_ST_BLKSIZE defined (_STATBUF_ST_BLKSIZE)
 
diff --git a/locale/C-numeric.c b/locale/C-numeric.c
index 9a981f195a..d3fbd91917 100644
--- a/locale/C-numeric.c
+++ b/locale/C-numeric.c
@@ -1,21 +1,21 @@
 /* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
-Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
 
-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 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.
+   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.  */
+   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 "localeinfo.h"
 
diff --git a/locale/Makefile b/locale/Makefile
index ef6c2dd744..b5eccf35c1 100644
--- a/locale/Makefile
+++ b/locale/Makefile
@@ -40,6 +40,11 @@ install-bin	= localedef locale
 extra-objs	= $(localedef-modules:=.o) $(locale-modules:=.o) \
 		  $(lib-modules:=.o)
 
+extra-libs	= libBrokenLocale
+extra-libs-others = $(extra-libs)
+
+libBrokenLocale-routines = broken_cur_max
+
 subdir-dirs	= programs
 vpath %.c programs
 vpath %.h programs
@@ -74,3 +79,8 @@ CPPFLAGS := -DLOCALE_PATH='$(localepath)' \
 
 CFLAGS-charmap.c = -Wno-write-strings
 CFLAGS-locfile.c = -Wno-write-strings
+
+# Depend on libc.so so a DT_NEEDED is generated in the shared objects.
+# This ensures they will load libc.so for needed symbols if loaded by
+# a statically-linked program that hasn't already loaded it.
+$(objpfx)libBrokenLocale.so: $(common-objpfx)libc.so
diff --git a/locale/broken_cur_max.c b/locale/broken_cur_max.c
new file mode 100644
index 0000000000..0374f84a57
--- /dev/null
+++ b/locale/broken_cur_max.c
@@ -0,0 +1,50 @@
+/* Return number of characters in multibyte representation for current
+   character set.
+   Copyright (C) 1996 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 <langinfo.h>
+#include <locale.h>
+#include <stdlib.h>
+#include "localeinfo.h"
+
+
+/* This is a gross hack to get borken programs running.
+
+   ISO C provides no mean to find out how many bytes the wide
+   character representation really uses.  But it defines MB_CUR_LEN to
+   return the information for the multi-byte character representation.
+   Many programmers don't know the difference between the two and
+   thing this means the same.  But assuming all characters have a size
+   of MB_CUR_LEN after they have been processed by `mbrtowc' is wrong.
+   Instead the maximal number of character used for the conversion is
+   MB_CURLEN.
+
+   It is known that some Motif applications have this problem.  To
+   cure this one has to make sure the glibc uses the function in this
+   file instead of the one in locale/mb_cur_max.c.  This can either be
+   done by linking with this file or by using the LD_PRELOAD feature
+   of the dynamic linker.  */
+int
+__ctype_get_mb_cur_max (void)
+{
+  int correct_value = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MB_CUR_MAX);
+
+  return ((int []) { 1, 1, 1, 2, 2, 3, 4 })[correct_value];
+}
diff --git a/locale/mb_cur_max.c b/locale/mb_cur_max.c
index 750d2155c8..cfb93ffba8 100644
--- a/locale/mb_cur_max.c
+++ b/locale/mb_cur_max.c
@@ -1,23 +1,23 @@
 /* Return number of characters in multibyte representation for current
    character set.
-Copyright (C) 1996 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
-Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+   Copyright (C) 1996 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 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.
+   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.  */
+   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 <langinfo.h>
 #include <locale.h>
@@ -26,6 +26,7 @@ Boston, MA 02111-1307, USA.  */
 
 
 int
+weak_function
 __ctype_get_mb_cur_max (void)
 {
   return _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MB_CUR_MAX);
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 22f2ee89ed..3e843541eb 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -1,7 +1,8 @@
 /* Malloc implementation for multiple threads without lock contention.
    Copyright (C) 1996 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Wolfram Gloger <wmglo@dent.med.uni-muenchen.de>, 1996.
+   Contributed by Wolfram Gloger <wmglo@dent.med.uni-muenchen.de>
+   and Doug Lea <dl@cs.oswego.edu>, 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
diff --git a/malloc/thread-m.h b/malloc/thread-m.h
index 331afc71e8..10da26ba32 100644
--- a/malloc/thread-m.h
+++ b/malloc/thread-m.h
@@ -19,7 +19,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-/* One out of _LIBC, USE_PTHREADS, USE_THR, or USE_SPROC should be
+/* One out of _LIBC, USE_PTHREADS, USE_THR or USE_SPROC should be
    defined, otherwise the token NO_THREADS and dummy implementations
    of the macros will be defined.  */
 
@@ -42,12 +42,19 @@ typedef pthread_key_t tsd_key_t;
 
 #define MUTEX_INITIALIZER	PTHREAD_MUTEX_INITIALIZER
 
-#define tsd_key_create(key, destr)	\
-  if (__pthread_key_create != NULL) { __pthread_key_create(key, destr); }
-#define tsd_setspecific(key, data)	\
-  if (__pthread_setspecific != NULL) { __pthread_setspecific(key, data); }
-#define tsd_getspecific(key, vptr)	\
-  (vptr = (__pthread_getspecific != NULL ? __pthread_getspecific(key) : NULL))
+static Void_t *malloc_key_data;
+
+#define tsd_key_create(key, destr) \
+  if (__pthread_key_create != NULL) {					      \
+    __pthread_key_create(key, destr);					      \
+  } else { *(key) = (tsd_key_t) 0; }
+#define tsd_setspecific(key, data) \
+  if (__pthread_setspecific != NULL) {					      \
+    __pthread_setspecific(key, data);					      \
+  } else { malloc_key_data = (Void_t *) data; }
+#define tsd_getspecific(key, vptr) \
+  (vptr = (__pthread_getspecific != NULL				      \
+	   ? __pthread_getspecific(key) : malloc_key_data))
 
 #define mutex_init(m)		\
    (__pthread_mutex_init != NULL ? __pthread_mutex_init (m, NULL) : 0)
diff --git a/nis/Banner b/nis/Banner
new file mode 100644
index 0000000000..be5280c5d4
--- /dev/null
+++ b/nis/Banner
@@ -0,0 +1 @@
+NIS(YP) NSS modules 0.8 by Thorsten Kukuk
diff --git a/nis/Makefile b/nis/Makefile
new file mode 100644
index 0000000000..475ee67175
--- /dev/null
+++ b/nis/Makefile
@@ -0,0 +1,100 @@
+# Copyright (C) 1996 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.
+
+#
+#	Makefile for NIS part.
+#
+subdir	:= nis
+
+headers			:= $(wildcard rpcsvc/*.[hx])
+
+# These are the databases available for the nis (and perhaps later nisplus)
+# service.  This must be a superset of the services in nss.
+databases		= proto service hosts network grp pwd rpc ethers \
+			  spwd netgrp alias
+
+# Specify rules for the nss_* modules.  Later we may have nisplus as well.
+services		:= nis compat
+
+extra-libs		= libnsl $(services:%=libnss_%)
+# These libraries will be built in the `others' pass rather than
+# the `lib' pass, because they depend on libc.so being built already.
+extra-libs-others	= $(extra-libs)
+
+others = ypcat ypmatch yppoll ypset ypwhich
+install-bin = ypcat ypmatch ypwhich
+install-sbin = ypset yppoll
+
+# The sources are found in the appropriate subdir.
+subdir-dirs = bsd-tools $(services:%=nss_%)
+vpath %.c $(subdir-dirs)
+
+libnsl-routines = yp_xdr ypclnt ypupdate_xdr
+
+libnss_compat-routines	:= $(addprefix compat-,grp pwd spwd)
+libnss_compat-inhibit-o	= $(filter-out .so,$(object-suffixes))
+
+libnss_nis-routines	:= $(addprefix nis-,$(databases))
+libnss_nis-inhibit-o	= $(filter-out .so,$(object-suffixes))
+
+
+# Sun's header files are not too clean.
+CFLAGS-compat-pwd.c = -Wno-strict-prototypes
+CFLAGS-compat-spwd.c = -Wno-strict-prototypes
+CFLAGS-compat-grp.c = -Wno-strict-prototypes
+CFLAGS-nis-alias.c = -Wno-strict-prototypes
+CFLAGS-nis-ethers.c = -Wno-strict-prototypes
+CFLAGS-nis-grp.c = -Wno-strict-prototypes
+CFLAGS-nis-hosts.c = -Wno-strict-prototypes
+CFLAGS-nis-netgrp.c = -Wno-strict-prototypes
+CFLAGS-nis-network.c = -Wno-strict-prototypes
+CFLAGS-nis-proto.c = -Wno-strict-prototypes
+CFLAGS-nis-publickey.c = -Wno-strict-prototypes
+CFLAGS-nis-pwd.c = -Wno-strict-prototypes
+CFLAGS-nis-rpc.c = -Wno-strict-prototypes
+CFLAGS-nis-service.c = -Wno-strict-prototypes
+CFLAGS-nis-spwd.c = -Wno-strict-prototypes
+CFLAGS-ypclnt.c = -Wno-strict-prototypes -Wno-write-strings
+CFLAGS-yp_xdr.c = -Wno-strict-prototypes
+CFLAGS-ypupdate_xdr.c = -Wno-strict-prototypes
+CFLAGS-ypcat.c = -Wno-strict-prototypes
+CFLAGS-ypmatch.c = -Wno-strict-prototypes
+CFLAGS-ypwhich.c = -Wno-strict-prototypes
+CFLAGS-ypset.c = -Wno-strict-prototypes
+CFLAGS-yppoll.c = -Wno-strict-prototypes
+
+
+include ../Rules
+
+
+$(objpfx)libnss_compat.so: $(objpfx)libnsl.so$(libnsl.so-version) \
+			   $(common-objpfx)nss/libnss_files.so
+$(objpfx)libnss_nis.so: $(objpfx)libnsl.so$(libnsl.so-version) \
+			$(common-objpfx)nss/libnss_files.so
+
+# Depend on libc.so so a DT_NEEDED is generated in the shared objects.
+# This ensures they will load libc.so for needed symbols if loaded by
+# a statically-linked program that hasn't already loaded it.
+$(services:%=$(objpfx)libnss_%.so): $(common-objpfx)libc.so
+
+
+ifeq ($(build-shared),yes)
+$(others:%=$(objpfx)%): $(objpfx)libnsl.so$(libnsl.so-version)
+else
+$(others:%=$(objpfx)%): $(objpfx)libnsl.a
+endif
diff --git a/nis/nss-nis.h b/nis/nss-nis.h
new file mode 100644
index 0000000000..13ba62ed9f
--- /dev/null
+++ b/nis/nss-nis.h
@@ -0,0 +1,58 @@
+/* Copyright (C) 1996 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.  */
+
+#ifndef _NIS_NSS_NIS_H
+#define _NIS_NSS_NIS_H	1
+
+#include <rpcsvc/ypclnt.h>
+
+#include "nsswitch.h"
+
+
+/* Convert YP error number to NSS error number.  */
+static enum nss_status yperr2nss_tab[] =
+{
+  [YPERR_SUCCESS] = NSS_STATUS_SUCCESS,
+  [YPERR_BADARGS] = NSS_STATUS_UNAVAIL,
+  [YPERR_RPC]     = NSS_STATUS_UNAVAIL,
+  [YPERR_DOMAIN]  = NSS_STATUS_UNAVAIL,
+  [YPERR_MAP]     = NSS_STATUS_UNAVAIL,
+  [YPERR_KEY]     = NSS_STATUS_NOTFOUND,
+  [YPERR_YPERR]   = NSS_STATUS_UNAVAIL,
+  [YPERR_RESRC]   = NSS_STATUS_TRYAGAIN,
+  [YPERR_NOMORE]  = NSS_STATUS_NOTFOUND,
+  [YPERR_PMAP]    = NSS_STATUS_UNAVAIL,
+  [YPERR_YPBIND]  = NSS_STATUS_UNAVAIL,
+  [YPERR_YPSERV]  = NSS_STATUS_UNAVAIL,
+  [YPERR_NODOM]   = NSS_STATUS_UNAVAIL,
+  [YPERR_BADDB]   = NSS_STATUS_UNAVAIL,
+  [YPERR_VERS]    = NSS_STATUS_UNAVAIL,
+  [YPERR_ACCESS]  = NSS_STATUS_UNAVAIL,
+  [YPERR_BUSY]    = NSS_STATUS_TRYAGAIN
+};
+#define YPERR_COUNT (sizeof (yperr2nss_tab) / sizeof (yperr2nss_tab[0]))
+
+static inline enum nss_status
+yperr2nss (int errval)
+{
+  if ((unsigned int) errval > YPERR_COUNT)
+    return NSS_STATUS_UNAVAIL;
+  return yperr2nss_tab[errval];
+}
+
+#endif /* nis/nss-nis.h */
diff --git a/nis/nss_compat/compat-grp.c b/nis/nss_compat/compat-grp.c
new file mode 100644
index 0000000000..0b4ed40e59
--- /dev/null
+++ b/nis/nss_compat/compat-grp.c
@@ -0,0 +1,421 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <errno.h>
+#include <nss.h>
+#include <grp.h>
+#include <ctype.h>
+#include <libc-lock.h>
+#include <string.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+/* Structure for remembering -@netgroup and -user members ... */
+#define BLACKLIST_INITIAL_SIZE 512
+#define BLACKLIST_INCREMENT 256
+struct blacklist_t
+  {
+    char *data;
+    int current;
+    int size;
+  };
+
+struct ent_t
+  {
+    bool_t nis;
+    bool_t nis_first;
+    char *oldkey;
+    int oldkeylen;
+    FILE *stream;
+    struct blacklist_t blacklist;
+  };
+typedef struct ent_t ent_t;
+
+static ent_t ext_ent = {0, 0, NULL, 0, NULL, {NULL, 0, 0}};
+
+/* Protect global state against multiple changers.  */
+__libc_lock_define_initialized (static, lock)
+
+/* Prototypes for local functions.  */
+static void blacklist_store_name (const char *, ent_t *);
+static int in_blacklist (const char *, int, ent_t *);
+
+static enum nss_status
+internal_setgrent (ent_t *ent)
+{
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  ent->nis = ent->nis_first = 0;
+
+  if (ent->oldkey != NULL)
+    {
+      free (ent->oldkey);
+      ent->oldkey = NULL;
+      ent->oldkeylen = 0;
+    }
+
+  ent->blacklist.current = 0;
+  if (ent->blacklist.data != NULL)
+    ent->blacklist.data[0] = '\0';
+
+  if (ent->stream == NULL)
+    {
+      ent->stream = fopen ("/etc/group", "r");
+
+      if (ent->stream == NULL)
+	status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+    }
+  else
+    rewind (ent->stream);
+
+  return status;
+}
+
+
+enum nss_status
+_nss_compat_setgrent (void)
+{
+  enum nss_status result;
+
+  __libc_lock_lock (lock);
+
+  result = internal_setgrent (&ext_ent);
+
+  __libc_lock_unlock (lock);
+
+  return result;
+}
+
+
+static enum nss_status
+internal_endgrent (ent_t *ent)
+{
+  if (ent->stream != NULL)
+    {
+      fclose (ent->stream);
+      ent->stream = NULL;
+    }
+
+  ent->nis = ent->nis_first = 0;
+
+  if (ent->oldkey != NULL)
+    {
+      free (ent->oldkey);
+      ent->oldkey = NULL;
+      ent->oldkeylen = 0;
+    }
+
+  ent->blacklist.current = 0;
+  if (ent->blacklist.data != NULL)
+    ent->blacklist.data[0] = '\0';
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_compat_endgrent (void)
+{
+  enum nss_status result;
+
+  __libc_lock_lock (lock);
+
+  result = internal_endgrent (&ext_ent);
+
+  __libc_lock_unlock (lock);
+
+  return result;
+}
+
+static enum nss_status
+getgrent_next_nis (struct group *result, ent_t *ent, char *buffer,
+		   size_t buflen)
+{
+  char *domain;
+  char *outkey, *outval;
+  int outkeylen, outvallen;
+  char *p;
+
+  if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
+    {
+      ent->nis = 0;
+      return NSS_STATUS_NOTFOUND;
+    }
+
+  do
+    {
+      if (ent->nis_first)
+	{
+	  if (yp_first (domain, "group.byname", &outkey, &outkeylen,
+			&outval, &outvallen) != YPERR_SUCCESS)
+	    {
+	      ent->nis = 0;
+	      return NSS_STATUS_UNAVAIL;
+	    }
+
+	  ent->oldkey = outkey;
+	  ent->oldkeylen = outkeylen;
+	  ent->nis_first = FALSE;
+	}
+      else
+	{
+	  if (yp_next (domain, "group.byname", ent->oldkey, ent->oldkeylen,
+		       &outkey, &outkeylen, &outval, &outvallen)
+	      != YPERR_SUCCESS)
+	    {
+	      ent->nis = 0;
+	      return NSS_STATUS_NOTFOUND;
+	    }
+
+	  free (ent->oldkey);
+	  ent->oldkey = outkey;
+	  ent->oldkeylen = outkeylen;
+	}
+
+      /* Copy the found data to our buffer  */
+      p = strncpy (buffer, outval, buflen);
+
+      /* ...and free the data.  */
+      free (outval);
+
+      while (isspace (*p))
+	++p;
+    }
+  while (!_nss_files_parse_grent (p, result, buffer, buflen));
+
+  if (!in_blacklist (result->gr_name, strlen (result->gr_name), ent))
+    return NSS_STATUS_SUCCESS;
+  else
+    return NSS_STATUS_NOTFOUND;
+}
+
+
+static enum nss_status
+getgrent_next_file (struct group *result, ent_t *ent,
+		    char *buffer, size_t buflen)
+{
+  while (1)
+    {
+      char *p;
+
+      do
+	{
+	  p = fgets (buffer, buflen, ent->stream);
+	  if (p == NULL)
+	    return NSS_STATUS_NOTFOUND;
+
+	  /* Terminate the line for any case.  */
+	  buffer[buflen - 1] = '\0';
+
+	  /* Skip leading blanks.  */
+	  while (isspace (*p))
+	    ++p;
+	}
+      /* Ignore empty and comment lines.  */
+      while (*p == '\0' || *p == '#' ||
+      /* Parse the line.  If it is invalid, loop to
+         get the next line of the file to parse.  */
+	     !_nss_files_parse_grent (p, result, buffer, buflen));
+
+      if (result->gr_name[0] != '+' && result->gr_name[0] != '-')
+	/* This is a real entry.  */
+	break;
+
+      /* -group */
+      if (result->gr_name[0] == '-' && result->gr_name[1] != '\0'
+	  && result->gr_name[1] != '@')
+	{
+	  blacklist_store_name (&result->gr_name[1], ent);
+	  continue;
+	}
+
+      /* +group */
+      if (result->gr_name[0] == '+' && result->gr_name[1] != '\0'
+	  && result->gr_name[1] != '@')
+	{
+	  char *domain;
+	  char *outval;
+	  int outvallen;
+
+	  if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
+	    /* XXX Should we regard this as an fatal error?  I don't
+	       think so.  Just continue working.  --drepper@gnu  */
+	    continue;
+
+	  if (yp_match (domain, "group.byname", &result->gr_name[1],
+			strlen (result->gr_name) - 1, &outval, &outvallen)
+	      != YPERR_SUCCESS)
+	    continue;
+
+	  p = strncpy (buffer, outval, buflen);
+	  while (isspace (*p))
+	    p++;
+	  free (outval);
+	  if (_nss_files_parse_grent (p, result, buffer, buflen))
+	    /* We found the entry.  */
+	    break;
+	}
+
+      /* +:... */
+      if (result->gr_name[0] == '+' && result->gr_name[1] == '\0')
+	{
+	  ent->nis = TRUE;
+	  ent->nis_first = TRUE;
+
+	  return getgrent_next_nis (result, ent, buffer, buflen);
+	}
+    }
+
+  return NSS_STATUS_SUCCESS;
+}
+
+
+static enum nss_status
+internal_getgrent_r (struct group *gr, ent_t *ent, char *buffer,
+		     size_t buflen)
+{
+  if (ent->nis)
+    return getgrent_next_nis (gr, ent, buffer, buflen);
+  else
+    return getgrent_next_file (gr, ent, buffer, buflen);
+}
+
+enum nss_status
+_nss_compat_getgrent_r (struct group *grp, char *buffer, size_t buflen)
+{
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  __libc_lock_lock (lock);
+
+  /* Be prepared that the setgrent function was not called before.  */
+  if (ext_ent.stream == NULL)
+    status = internal_setgrent (&ext_ent);
+
+  if (status == NSS_STATUS_SUCCESS)
+    status = internal_getgrent_r (grp, &ext_ent, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+
+enum nss_status
+_nss_compat_getgrnam_r (const char *name, struct group *grp,
+			char *buffer, size_t buflen)
+{
+  ent_t ent = {0, 0, NULL, 0, NULL, {NULL, 0, 0}};
+  enum nss_status status;
+
+  if (name[0] == '-' || name[0] == '+')
+    return NSS_STATUS_NOTFOUND;
+
+
+  status = internal_setgrent (&ent);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+  while ((status = internal_getgrent_r (grp, &ent, buffer, buflen))
+	 == NSS_STATUS_SUCCESS)
+    if (strcmp (grp->gr_name, name) == 0)
+      break;
+
+  internal_endgrent (&ent);
+  return status;
+}
+
+
+enum nss_status
+_nss_compat_getgrgid_r (gid_t gid, struct group *grp,
+			char *buffer, size_t buflen)
+{
+  ent_t ent = {0, 0, NULL, 0, NULL, {NULL, 0, 0}};
+  enum nss_status status;
+
+  status = internal_setgrent (&ent);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+  while ((status = internal_getgrent_r (grp, &ent, buffer, buflen))
+	 == NSS_STATUS_SUCCESS)
+    if (grp->gr_gid == gid && grp->gr_name[0] != '+' && grp->gr_name[0] != '-')
+      break;
+
+  internal_endgrent (&ent);
+  return status;
+}
+
+
+/* Support routines for remembering -@netgroup and -user entries.
+   The names are stored in a single string with `|' as separator. */
+static void
+blacklist_store_name (const char *name, ent_t *ent)
+{
+  int namelen = strlen (name);
+  char *tmp;
+
+  /* first call, setup cache */
+  if (ent->blacklist.size == 0)
+    {
+      ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen);
+      ent->blacklist.data = malloc (ent->blacklist.size);
+      if (ent->blacklist.data == NULL)
+	return;
+      ent->blacklist.data[0] = '|';
+      ent->blacklist.data[1] = '\0';
+      ent->blacklist.current = 1;
+    }
+  else
+    {
+      if (in_blacklist (name, namelen, ent))
+	return;			/* no duplicates */
+
+      if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size)
+	{
+	  ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen);
+	  tmp = realloc (ent->blacklist.data, ent->blacklist.size);
+	  if (tmp == NULL)
+	    {
+	      free (ent->blacklist.data);
+	      ent->blacklist.size = 0;
+	      return;
+	    }
+	  ent->blacklist.data = tmp;
+	}
+    }
+
+  tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name);
+  *tmp++ = '|';
+  *tmp = '\0';
+  ent->blacklist.current += namelen + 1;
+
+  return;
+}
+
+/* returns TRUE if ent->blacklist contains name, else FALSE */
+static bool_t
+in_blacklist (const char *name, int namelen, ent_t *ent)
+{
+  char buf[namelen + 3];
+
+  if (ent->blacklist.data == NULL)
+    return FALSE;
+
+  stpcpy (stpcpy (stpcpy (buf, "|"), name), "|");
+  return strstr (ent->blacklist.data, buf) != NULL;
+}
diff --git a/nis/nss_compat/compat-pwd.c b/nis/nss_compat/compat-pwd.c
new file mode 100644
index 0000000000..503aafb51e
--- /dev/null
+++ b/nis/nss_compat/compat-pwd.c
@@ -0,0 +1,695 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h>
+#include <pwd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <string.h>
+#include <libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "netgroup.h"
+
+/* Structure for remembering -@netgroup and -user members ... */
+#define BLACKLIST_INITIAL_SIZE 512
+#define BLACKLIST_INCREMENT 256
+struct blacklist_t
+  {
+    char *data;
+    int current;
+    int size;
+  };
+
+struct ent_t
+  {
+    bool_t netgroup;
+    bool_t nis;
+    bool_t first;
+    char *oldkey;
+    int oldkeylen;
+    FILE *stream;
+    struct blacklist_t blacklist;
+    struct passwd pwd;
+    struct __netgrent netgrdata;
+  };
+typedef struct ent_t ent_t;
+
+static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0},
+			{NULL, NULL, 0, 0, NULL, NULL, NULL}};
+
+/* Protect global state against multiple changers.  */
+__libc_lock_define_initialized (static, lock)
+
+/* Prototypes for local functions.  */
+static void blacklist_store_name (const char *, ent_t *);
+static int in_blacklist (const char *, int, ent_t *);
+
+static void
+give_pwd_free (struct passwd *pwd)
+{
+  if (pwd->pw_name != NULL)
+    free (pwd->pw_name);
+  if (pwd->pw_passwd != NULL)
+    free (pwd->pw_passwd);
+  if (pwd->pw_gecos != NULL)
+    free (pwd->pw_gecos);
+  if (pwd->pw_dir != NULL)
+    free (pwd->pw_dir);
+  if (pwd->pw_shell != NULL)
+    free (pwd->pw_shell);
+
+  memset (pwd, '\0', sizeof (struct passwd));
+}
+
+static size_t
+pwd_need_buflen (struct passwd *pwd)
+{
+  size_t len = 0;
+
+  if (pwd->pw_passwd != NULL)
+    len += strlen (pwd->pw_passwd) + 1;
+
+  if (pwd->pw_gecos != NULL)
+    len += strlen (pwd->pw_gecos) + 1;
+
+  if (pwd->pw_dir != NULL)
+    len += strlen (pwd->pw_dir) + 1;
+
+  if (pwd->pw_shell != NULL)
+    len += strlen (pwd->pw_shell) + 1;
+
+  return len;
+}
+
+static void
+copy_pwd_changes (struct passwd *dest, struct passwd *src,
+		  char *buffer, size_t buflen)
+{
+  if (src->pw_passwd != NULL && strlen (src->pw_passwd))
+    {
+      if (buffer == NULL)
+	dest->pw_passwd = strdup (src->pw_passwd);
+      else if (dest->pw_passwd &&
+	       strlen (dest->pw_passwd) >= strlen (src->pw_passwd))
+	strcpy (dest->pw_passwd, src->pw_passwd);
+      else
+	{
+	  dest->pw_passwd = buffer;
+	  strcpy (dest->pw_passwd, src->pw_passwd);
+	  buffer += strlen (dest->pw_passwd) + 1;
+	  buflen = buflen - (strlen (dest->pw_passwd) + 1);
+	}
+    }
+
+  if (src->pw_gecos != NULL && strlen (src->pw_gecos))
+    {
+      if (buffer == NULL)
+	dest->pw_gecos = strdup (src->pw_gecos);
+      else if (dest->pw_gecos &&
+	       strlen (dest->pw_gecos) >= strlen (src->pw_gecos))
+	strcpy (dest->pw_gecos, src->pw_gecos);
+      else
+	{
+	  dest->pw_gecos = buffer;
+	  strcpy (dest->pw_gecos, src->pw_gecos);
+	  buffer += strlen (dest->pw_gecos) + 1;
+	  buflen = buflen - (strlen (dest->pw_gecos) + 1);
+	}
+    }
+  if (src->pw_dir != NULL && strlen (src->pw_dir))
+    {
+      if (buffer == NULL)
+	dest->pw_dir = strdup (src->pw_dir);
+      else if (dest->pw_dir &&
+	       strlen (dest->pw_dir) >= strlen (src->pw_dir))
+	strcpy (dest->pw_dir, src->pw_dir);
+      else
+	{
+	  dest->pw_dir = buffer;
+	  strcpy (dest->pw_dir, src->pw_dir);
+	  buffer += strlen (dest->pw_dir) + 1;
+	  buflen = buflen - (strlen (dest->pw_dir) + 1);
+	}
+    }
+
+  if (src->pw_shell != NULL && strlen (src->pw_shell))
+    {
+      if (buffer == NULL)
+	dest->pw_shell = strdup (src->pw_shell);
+      else if (dest->pw_shell &&
+	       strlen (dest->pw_shell) >= strlen (src->pw_shell))
+	strcpy (dest->pw_shell, src->pw_shell);
+      else
+	{
+	  dest->pw_shell = buffer;
+	  strcpy (dest->pw_shell, src->pw_shell);
+	  buffer += strlen (dest->pw_shell) + 1;
+	  buflen = buflen - (strlen (dest->pw_shell) + 1);
+	}
+    }
+}
+
+static enum nss_status
+internal_setpwent (ent_t *ent)
+{
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  ent->nis = ent->first = ent->netgroup = 0;
+
+  /* If something was left over free it.  */
+  if (ent->netgroup)
+    __internal_endnetgrent (&ent->netgrdata);
+
+  if (ent->oldkey != NULL)
+    {
+      free (ent->oldkey);
+      ent->oldkey = NULL;
+      ent->oldkeylen = 0;
+    }
+
+  ent->blacklist.current = 0;
+  if (ent->blacklist.data != NULL)
+    ent->blacklist.data[0] = '\0';
+
+  if (ent->stream == NULL)
+    {
+      ent->stream = fopen ("/etc/passwd", "r");
+
+      if (ent->stream == NULL)
+	status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+    }
+  else
+    rewind (ent->stream);
+
+  give_pwd_free (&ent->pwd);
+
+  return status;
+}
+
+
+enum nss_status
+_nss_compat_setpwent (void)
+{
+  enum nss_status result;
+
+  __libc_lock_lock (lock);
+
+  result = internal_setpwent (&ext_ent);
+
+  __libc_lock_unlock (lock);
+
+  return result;
+}
+
+
+static enum nss_status
+internal_endpwent (ent_t *ent)
+{
+  if (ent->stream != NULL)
+    {
+      fclose (ent->stream);
+      ent->stream = NULL;
+    }
+
+  ent->nis = ent->first = ent->netgroup = 0;
+
+  if (ent->oldkey != NULL)
+    {
+      free (ent->oldkey);
+      ent->oldkey = NULL;
+      ent->oldkeylen = 0;
+    }
+
+  ent->blacklist.current = 0;
+  if (ent->blacklist.data != NULL)
+    ent->blacklist.data[0] = '\0';
+
+  give_pwd_free (&ent->pwd);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_compat_endpwent (void)
+{
+  enum nss_status result;
+
+  __libc_lock_lock (lock);
+
+  if (ext_ent.netgroup)
+    __internal_endnetgrent (&ext_ent.netgrdata);
+
+  result = internal_endpwent (&ext_ent);
+
+  __libc_lock_unlock (lock);
+
+  return result;
+}
+
+static enum nss_status
+getpwent_next_netgr (struct passwd *result, ent_t *ent, char *group,
+		     char *buffer, size_t buflen)
+{
+  char *ypdomain, *host, *user, *domain, *outval, *p, *p2;
+  int status, outvallen, p2len;
+
+  if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
+    {
+      ent->netgroup = 0;
+      ent->first = 0;
+      give_pwd_free (&ent->pwd);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (ent->first == TRUE)
+    {
+      bzero (&ent->netgrdata, sizeof (struct __netgrent));
+      __internal_setnetgrent (group, &ent->netgrdata);
+      ent->first = FALSE;
+    }
+
+  while (1)
+    {
+      status = __internal_getnetgrent (&host, &user, &domain, &ent->netgrdata,
+				       buffer, buflen);
+      if (status != 1)
+	{
+	  __internal_endnetgrent (&ent->netgrdata);
+	  ent->netgroup = 0;
+	  give_pwd_free (&ent->pwd);
+	  return NSS_STATUS_RETURN;
+	}
+
+      if (user == NULL || user[0] == '-')
+	continue;
+
+      if (domain != NULL && strcmp (ypdomain, domain) != 0)
+	continue;
+
+      if (yp_match (ypdomain, "passwd.byname", user,
+		    strlen (user), &outval, &outvallen)
+	  != YPERR_SUCCESS)
+	continue;
+
+      p2len = pwd_need_buflen (&ent->pwd);
+      if (p2len > buflen)
+	{
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      p2 = buffer + (buflen - p2len);
+      buflen -= p2len;
+      p = strncpy (buffer, outval, buflen);
+      while (isspace (*p))
+	p++;
+      free (outval);
+      if (_nss_files_parse_pwent (p, result, buffer, buflen))
+	{
+	  copy_pwd_changes (result, &ent->pwd, p2, p2len);
+	  break;
+	}
+    }
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+getpwent_next_nis (struct passwd *result, ent_t *ent, char *buffer,
+		   size_t buflen)
+{
+  char *domain, *outkey, *outval, *p, *p2;
+  int outkeylen, outvallen, p2len;
+
+  if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
+    {
+      ent->nis = 0;
+      give_pwd_free (&ent->pwd);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  p2len = pwd_need_buflen (&ent->pwd);
+  if (p2len > buflen)
+    {
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+  p2 = buffer + (buflen - p2len);
+  buflen -= p2len;
+  do
+    {
+      if (ent->first)
+	{
+	  if (yp_first (domain, "passwd.byname", &outkey, &outkeylen,
+			&outval, &outvallen) != YPERR_SUCCESS)
+	    {
+	      ent->nis = 0;
+	      give_pwd_free (&ent->pwd);
+	      return NSS_STATUS_UNAVAIL;
+	    }
+
+	  ent->oldkey = outkey;
+	  ent->oldkeylen = outkeylen;
+	  ent->first = FALSE;
+	}
+      else
+	{
+	  if (yp_next (domain, "passwd.byname", ent->oldkey, ent->oldkeylen,
+		       &outkey, &outkeylen, &outval, &outvallen)
+	      != YPERR_SUCCESS)
+	    {
+	      ent->nis = 0;
+	      give_pwd_free (&ent->pwd);
+	      return NSS_STATUS_NOTFOUND;
+	    }
+
+	  free (ent->oldkey);
+	  ent->oldkey = outkey;
+	  ent->oldkeylen = outkeylen;
+	}
+
+      /* Copy the found data to our buffer  */
+      p = strncpy (buffer, outval, buflen);
+
+      /* ...and free the data.  */
+      free (outval);
+
+      while (isspace (*p))
+	++p;
+    }
+  while (!_nss_files_parse_pwent (p, result, buffer, buflen));
+
+  copy_pwd_changes (result, &ent->pwd, p2, p2len);
+
+  if (!in_blacklist (result->pw_name, strlen (result->pw_name), ent))
+    return NSS_STATUS_SUCCESS;
+  else
+    return NSS_STATUS_NOTFOUND;
+}
+
+
+static enum nss_status
+getpwent_next_file (struct passwd *result, ent_t *ent,
+		    char *buffer, size_t buflen)
+{
+  while (1)
+    {
+      char *p, *p2;
+      int p2len;
+
+      do
+	{
+	  p = fgets (buffer, buflen, ent->stream);
+	  if (p == NULL)
+	    return NSS_STATUS_NOTFOUND;
+
+	  /* Terminate the line for any case.  */
+	  buffer[buflen - 1] = '\0';
+
+	  /* Skip leading blanks.  */
+	  while (isspace (*p))
+	    ++p;
+	}
+      while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines.  */
+      /* Parse the line.  If it is invalid, loop to
+         get the next line of the file to parse.  */
+	     !_nss_files_parse_pwent (p, result, buffer, buflen));
+
+      if (result->pw_name[0] != '+' && result->pw_name[0] != '-')
+	/* This is a real entry.  */
+	break;
+
+      /* -@netgroup */
+      if (result->pw_name[0] == '-' && result->pw_name[1] == '@'
+	  && result->pw_name[2] != '\0')
+	{
+	  char *user, *host, *domain;
+
+	  setnetgrent (&result->pw_name[2]);
+	  while (getnetgrent (&host, &user, &domain))
+	    {
+	      if (user != NULL && user[0] != '-')
+		blacklist_store_name (user, ent);
+	    }
+	  endnetgrent ();
+	  continue;
+	}
+
+      /* +@netgroup */
+      if (result->pw_name[0] == '+' && result->pw_name[1] == '@'
+	  && result->pw_name[2] != '\0')
+	{
+	  int status;
+
+	  ent->netgroup = TRUE;
+	  ent->first = TRUE;
+	  copy_pwd_changes (&ent->pwd, result, NULL, 0);
+
+	  status = getpwent_next_netgr (result, ent, &result->pw_name[2],
+					buffer, buflen);
+	  if (status == NSS_STATUS_RETURN)
+	    continue;
+	  else
+	    return status;
+	}
+
+      /* -user */
+      if (result->pw_name[0] == '-' && result->pw_name[1] != '\0'
+	  && result->pw_name[1] != '@')
+	{
+	  blacklist_store_name (&result->pw_name[1], ent);
+	  continue;
+	}
+
+      /* +user */
+      if (result->pw_name[0] == '+' && result->pw_name[1] != '\0'
+	  && result->pw_name[1] != '@')
+	{
+	  char *domain;
+	  char *outval;
+	  int outvallen;
+	  struct passwd pwd;
+
+	  memset (&pwd, '\0', sizeof (struct passwd));
+
+	  if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
+	    /* XXX Should we regard this as an fatal error?  I don't
+	       think so.  Just continue working.  --drepper@gnu  */
+	    continue;
+
+	  if (yp_match (domain, "passwd.byname", &result->pw_name[1],
+			strlen (result->pw_name) - 1, &outval, &outvallen)
+	      != YPERR_SUCCESS)
+	    continue;
+
+	  copy_pwd_changes (&pwd, result, NULL, 0);
+
+	  p2len = pwd_need_buflen (&pwd);
+	  if (p2len > buflen)
+	    {
+	      __set_errno (ERANGE);
+	      return NSS_STATUS_TRYAGAIN;
+	    }
+	  p2 = buffer + (buflen - p2len);
+	  buflen -= p2len;
+	  p = strncpy (buffer, outval, buflen);
+	  while (isspace (*p))
+	    p++;
+	  free (outval);
+	  if (_nss_files_parse_pwent (p, result, buffer, buflen))
+	    {
+	      copy_pwd_changes (result, &pwd, p2, p2len);
+	      give_pwd_free (&pwd);
+	      /* We found the entry.  */
+	      break;
+	    }
+	  else
+	    {
+	      /* Give buffer the old len back */
+	      buflen += p2len;
+	      give_pwd_free (&pwd);
+	    }
+	}
+
+      /* +:... */
+      if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
+	{
+	  ent->nis = TRUE;
+	  ent->first = TRUE;
+	  copy_pwd_changes (&ent->pwd, result, NULL, 0);
+
+	  return getpwent_next_nis (result, ent, buffer, buflen);
+	}
+    }
+
+  return NSS_STATUS_SUCCESS;
+}
+
+
+static enum nss_status
+internal_getpwent_r (struct passwd *pw, ent_t *ent, char *buffer,
+		     size_t buflen)
+{
+  if (ent->netgroup)
+    {
+      int status;
+
+      /* We are searching members in a netgroup */
+      /* Since this is not the first call, we don't need the group name */
+      status = getpwent_next_netgr (pw, ent, NULL, buffer, buflen);
+      if (status == NSS_STATUS_RETURN)
+	return getpwent_next_file (pw, ent, buffer, buflen);
+      else
+	return status;
+    }
+  else if (ent->nis)
+    return getpwent_next_nis (pw, ent, buffer, buflen);
+  else
+    return getpwent_next_file (pw, ent, buffer, buflen);
+}
+
+enum nss_status
+_nss_compat_getpwent_r (struct passwd *pwd, char *buffer,
+			size_t buflen)
+{
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  __libc_lock_lock (lock);
+
+  /* Be prepared that the setpwent function was not called before.  */
+  if (ext_ent.stream == NULL)
+    status = internal_setpwent (&ext_ent);
+
+  if (status == NSS_STATUS_SUCCESS)
+    status = internal_getpwent_r (pwd, &ext_ent, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+
+enum nss_status
+_nss_compat_getpwnam_r (const char *name, struct passwd *pwd,
+			char *buffer, size_t buflen)
+{
+  ent_t ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0},
+	       {NULL, NULL, 0, 0, NULL, NULL, NULL}};
+  enum nss_status status;
+
+  if (name[0] == '-' || name[0] == '+')
+    return NSS_STATUS_NOTFOUND;
+
+
+  status = internal_setpwent (&ent);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+  while ((status = internal_getpwent_r (pwd, &ent, buffer, buflen))
+	 == NSS_STATUS_SUCCESS)
+    if (strcmp (pwd->pw_name, name) == 0)
+      break;
+
+  internal_endpwent (&ent);
+  return status;
+}
+
+
+enum nss_status
+_nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd,
+			char *buffer, size_t buflen)
+{
+  ent_t ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0},
+	       {NULL, NULL, 0, 0, NULL, NULL, NULL}};
+  enum nss_status status;
+
+  status = internal_setpwent (&ent);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+  while ((status = internal_getpwent_r (pwd, &ent, buffer, buflen))
+	 == NSS_STATUS_SUCCESS)
+    if (pwd->pw_uid == uid && pwd->pw_name[0] != '+' && pwd->pw_name[0] != '-')
+      break;
+
+  internal_endpwent (&ent);
+  return status;
+}
+
+
+/* Support routines for remembering -@netgroup and -user entries.
+   The names are stored in a single string with `|' as separator. */
+static void
+blacklist_store_name (const char *name, ent_t *ent)
+{
+  int namelen = strlen (name);
+  char *tmp;
+
+  /* first call, setup cache */
+  if (ent->blacklist.size == 0)
+    {
+      ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen);
+      ent->blacklist.data = malloc (ent->blacklist.size);
+      if (ent->blacklist.data == NULL)
+	return;
+      ent->blacklist.data[0] = '|';
+      ent->blacklist.data[1] = '\0';
+      ent->blacklist.current = 1;
+    }
+  else
+    {
+      if (in_blacklist (name, namelen, ent))
+	return;			/* no duplicates */
+
+      if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size)
+	{
+	  ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen);
+	  tmp = realloc (ent->blacklist.data, ent->blacklist.size);
+	  if (tmp == NULL)
+	    {
+	      free (ent->blacklist.data);
+	      ent->blacklist.size = 0;
+	      return;
+	    }
+	  ent->blacklist.data = tmp;
+	}
+    }
+
+  tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name);
+  *tmp++ = '|';
+  *tmp = '\0';
+  ent->blacklist.current += namelen + 1;
+
+  return;
+}
+
+/* returns TRUE if ent->blacklist contains name, else FALSE */
+static bool_t
+in_blacklist (const char *name, int namelen, ent_t *ent)
+{
+  char buf[namelen + 3];
+
+  if (ent->blacklist.data == NULL)
+    return FALSE;
+
+  stpcpy (stpcpy (stpcpy (buf, "|"), name), "|");
+  return strstr (ent->blacklist.data, buf) != NULL;
+}
diff --git a/nis/nss_compat/compat-spwd.c b/nis/nss_compat/compat-spwd.c
new file mode 100644
index 0000000000..ba73b1846f
--- /dev/null
+++ b/nis/nss_compat/compat-spwd.c
@@ -0,0 +1,612 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h>
+#include <errno.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <shadow.h>
+#include <string.h>
+#include <libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+/* Structure for remembering -@netgroup and -user members ... */
+#define BLACKLIST_INITIAL_SIZE 512
+#define BLACKLIST_INCREMENT 256
+struct blacklist_t
+  {
+    char *data;
+    int current;
+    int size;
+  };
+
+struct ent_t
+  {
+    bool_t netgroup;
+    bool_t nis;
+    bool_t first;
+    char *oldkey;
+    int oldkeylen;
+    FILE *stream;
+    struct blacklist_t blacklist;
+    struct spwd pwd;
+  };
+typedef struct ent_t ent_t;
+
+static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL,	{NULL, 0, 0},
+			{NULL, NULL, 0, 0, 0, 0, 0, 0, 0}};
+
+/* Protect global state against multiple changers.  */
+__libc_lock_define_initialized (static, lock)
+
+/* Prototypes for local functions.  */
+static void blacklist_store_name (const char *, ent_t *);
+static int in_blacklist (const char *, int, ent_t *);
+
+static void
+give_spwd_free (struct spwd *pwd)
+{
+  if (pwd->sp_namp != NULL)
+    free (pwd->sp_namp);
+  if (pwd->sp_pwdp != NULL)
+    free (pwd->sp_pwdp);
+
+  memset (pwd, '\0', sizeof (struct spwd));
+}
+
+static int
+spwd_need_buflen (struct spwd *pwd)
+{
+  int len = 0;
+
+  if (pwd->sp_pwdp != NULL)
+    len += strlen (pwd->sp_pwdp) + 1;
+
+  return len;
+}
+
+static void
+copy_spwd_changes (struct spwd *dest, struct spwd *src,
+		   char *buffer, size_t buflen)
+{
+  if (src->sp_pwdp != NULL && strlen (src->sp_pwdp))
+    {
+      if (buffer == NULL)
+	dest->sp_pwdp = strdup (src->sp_pwdp);
+      else if (dest->sp_pwdp &&
+	       strlen (dest->sp_pwdp) >= strlen (src->sp_pwdp))
+	strcpy (dest->sp_pwdp, src->sp_pwdp);
+      else
+	{
+	  dest->sp_pwdp = buffer;
+	  strcpy (dest->sp_pwdp, src->sp_pwdp);
+	  buffer += strlen (dest->sp_pwdp) + 1;
+	  buflen = buflen - (strlen (dest->sp_pwdp) + 1);
+	}
+    }
+  if (src->sp_lstchg != 0)
+    dest->sp_lstchg = src->sp_lstchg;
+  if (src->sp_min != 0)
+    dest->sp_min = src->sp_min;
+  if (src->sp_max != 0)
+    dest->sp_max = src->sp_max;
+  if (src->sp_warn != 0)
+    dest->sp_warn = src->sp_warn;
+  if (src->sp_inact != 0)
+    dest->sp_inact = src->sp_inact;
+  if (src->sp_expire != 0)
+    dest->sp_expire = src->sp_expire;
+  if (src->sp_flag != 0)
+    dest->sp_flag = src->sp_flag;
+}
+
+static enum nss_status
+internal_setspent (ent_t *ent)
+{
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  ent->nis = ent->first = ent->netgroup = 0;
+
+  if (ent->oldkey != NULL)
+    {
+      free (ent->oldkey);
+      ent->oldkey = NULL;
+      ent->oldkeylen = 0;
+    }
+
+  ent->blacklist.current = 0;
+  if (ent->blacklist.data != NULL)
+    ent->blacklist.data[0] = '\0';
+
+  if (ent->stream == NULL)
+    {
+      ent->stream = fopen ("/etc/shadow", "r");
+
+      if (ent->stream == NULL)
+	status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+    }
+  else
+    rewind (ent->stream);
+
+  give_spwd_free (&ent->pwd);
+
+  return status;
+}
+
+
+enum nss_status
+_nss_compat_setspent (void)
+{
+  enum nss_status result;
+
+  __libc_lock_lock (lock);
+
+  result = internal_setspent (&ext_ent);
+
+  __libc_lock_unlock (lock);
+
+  return result;
+}
+
+
+static enum nss_status
+internal_endspent (ent_t *ent)
+{
+  if (ent->stream != NULL)
+    {
+      fclose (ent->stream);
+      ent->stream = NULL;
+    }
+
+  ent->nis = ent->first = ent->netgroup = 0;
+
+  if (ent->oldkey != NULL)
+    {
+      free (ent->oldkey);
+      ent->oldkey = NULL;
+      ent->oldkeylen = 0;
+    }
+
+  ent->blacklist.current = 0;
+  if (ent->blacklist.data != NULL)
+    ent->blacklist.data[0] = '\0';
+
+  give_spwd_free (&ent->pwd);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_compat_endspent (void)
+{
+  enum nss_status result;
+
+  __libc_lock_lock (lock);
+
+  result = internal_endspent (&ext_ent);
+
+  __libc_lock_unlock (lock);
+
+  return result;
+}
+
+
+static enum nss_status
+getspent_next_netgr (struct spwd *result, ent_t *ent, char *group,
+		     char *buffer, size_t buflen)
+{
+  char *ypdomain, *host, *user, *domain, *outval, *p, *p2;
+  int status, outvallen;
+  size_t p2len;
+
+  if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
+    {
+      ent->netgroup = 0;
+      ent->first = 0;
+      give_spwd_free (&ent->pwd);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (ent->first == TRUE)
+    {
+      setnetgrent (group);
+      ent->first = FALSE;
+    }
+
+  while (1)
+    {
+      if ((status = getnetgrent (&host, &user, &domain)) != 1)
+	{
+	  endnetgrent ();
+	  ent->netgroup = 0;
+	  give_spwd_free (&ent->pwd);
+	  return NSS_STATUS_RETURN;
+	}
+
+      if (user == NULL || user[0] == '-')
+	continue;
+
+      if (domain != NULL && strcmp (ypdomain, domain) != 0)
+	continue;
+
+      if (yp_match (ypdomain, "shadow.byname", user,
+		    strlen (user), &outval, &outvallen)
+	  != YPERR_SUCCESS)
+	continue;
+
+      p2len = spwd_need_buflen (&ent->pwd);
+      if (p2len > buflen)
+	{
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      p2 = buffer + (buflen - p2len);
+      buflen -= p2len;
+      p = strncpy (buffer, outval, buflen);
+      while (isspace (*p))
+	p++;
+      free (outval);
+      if (_nss_files_parse_spent (p, result, buffer, buflen))
+	{
+	  copy_spwd_changes (result, &ent->pwd, p2, p2len);
+	  break;
+	}
+    }
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+getspent_next_nis (struct spwd *result, ent_t *ent,
+		   char *buffer, size_t buflen)
+{
+  char *domain, *outkey, *outval, *p, *p2;
+  int outkeylen, outvallen;
+  size_t p2len;
+
+  if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
+    {
+      ent->nis = 0;
+      give_spwd_free (&ent->pwd);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  p2len = spwd_need_buflen (&ent->pwd);
+  if (p2len > buflen)
+    {
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+  p2 = buffer + (buflen - p2len);
+  buflen -= p2len;
+  do
+    {
+      if (ent->first)
+	{
+	  if (yp_first (domain, "shadow.byname", &outkey, &outkeylen,
+			&outval, &outvallen) != YPERR_SUCCESS)
+	    {
+	      ent->nis = 0;
+	      give_spwd_free (&ent->pwd);
+	      return NSS_STATUS_UNAVAIL;
+	    }
+
+	  ent->oldkey = outkey;
+	  ent->oldkeylen = outkeylen;
+	  ent->first = FALSE;
+	}
+      else
+	{
+	  if (yp_next (domain, "shadow.byname", ent->oldkey, ent->oldkeylen,
+		       &outkey, &outkeylen, &outval, &outvallen)
+	      != YPERR_SUCCESS)
+	    {
+	      ent->nis = 0;
+	      give_spwd_free (&ent->pwd);
+	      return NSS_STATUS_NOTFOUND;
+	    }
+
+	  free (ent->oldkey);
+	  ent->oldkey = outkey;
+	  ent->oldkeylen = outkeylen;
+	}
+
+      /* Copy the found data to our buffer  */
+      p = strncpy (buffer, outval, buflen);
+
+      /* ...and free the data.  */
+      free (outval);
+
+      while (isspace (*p))
+	++p;
+    }
+  while (!_nss_files_parse_spent (p, result, buffer, buflen));
+
+  copy_spwd_changes (result, &ent->pwd, p2, p2len);
+
+  if (!in_blacklist (result->sp_namp, strlen (result->sp_namp), ent))
+    return NSS_STATUS_SUCCESS;
+  else
+    return NSS_STATUS_NOTFOUND;
+}
+
+
+static enum nss_status
+getspent_next_file (struct spwd *result, ent_t *ent,
+		    char *buffer, size_t buflen)
+{
+  while (1)
+    {
+      char *p, *p2;
+      size_t p2len;
+
+      do
+	{
+	  p = fgets (buffer, buflen, ent->stream);
+	  if (p == NULL)
+	    return NSS_STATUS_NOTFOUND;
+
+	  /* Terminate the line for any case.  */
+	  buffer[buflen - 1] = '\0';
+
+	  /* Skip leading blanks.  */
+	  while (isspace (*p))
+	    ++p;
+	}
+      while (*p == '\0' || *p == '#' ||		/* Ignore empty and comment lines.  */
+      /* Parse the line.  If it is invalid, loop to
+         get the next line of the file to parse.  */
+	     !_nss_files_parse_spent (p, result, buffer, buflen));
+
+      if (result->sp_namp[0] != '+' && result->sp_namp[0] != '-')
+	/* This is a real entry.  */
+	break;
+
+      /* -@netgroup */
+      if (result->sp_namp[0] == '-' && result->sp_namp[1] == '@'
+	  && result->sp_namp[2] != '\0')
+	{
+	  char *user, *host, *domain;
+
+	  setnetgrent (&result->sp_namp[2]);
+	  while (getnetgrent (&host, &user, &domain))
+	    {
+	      if (user != NULL && user[0] != '-')
+		blacklist_store_name (user, ent);
+	    }
+	  endnetgrent ();
+	  continue;
+	}
+
+      /* +@netgroup */
+      if (result->sp_namp[0] == '+' && result->sp_namp[1] == '@'
+	  && result->sp_namp[2] != '\0')
+	{
+	  int status;
+
+	  ent->netgroup = TRUE;
+	  ent->first = TRUE;
+	  copy_spwd_changes (&ent->pwd, result, NULL, 0);
+
+	  status = getspent_next_netgr (result, ent, &result->sp_namp[2],
+					buffer, buflen);
+	  if (status == NSS_STATUS_RETURN)
+	    continue;
+	  else
+	    return status;
+	}
+
+      /* -user */
+      if (result->sp_namp[0] == '-' && result->sp_namp[1] != '\0'
+	  && result->sp_namp[1] != '@')
+	{
+	  blacklist_store_name (&result->sp_namp[1], ent);
+	  continue;
+	}
+
+      /* +user */
+      if (result->sp_namp[0] == '+' && result->sp_namp[1] != '\0'
+	  && result->sp_namp[1] != '@')
+	{
+	  char *domain;
+	  char *outval;
+	  int outvallen;
+	  struct spwd pwd;
+
+	  memset (&pwd, '\0', sizeof (struct spwd));
+
+	  if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
+	    /* XXX Should we regard this as an fatal error?  I don't
+	       think so.  Just continue working.  --drepper@gnu  */
+	    continue;
+
+	  if (yp_match (domain, "shadow.byname", &result->sp_namp[1],
+			strlen (result->sp_namp) - 1, &outval, &outvallen)
+	      != YPERR_SUCCESS)
+	    continue;
+
+	  copy_spwd_changes (&pwd, result, NULL, 0);
+
+	  p2len = spwd_need_buflen (&pwd);
+	  if (p2len > buflen)
+	    {
+	      __set_errno (ERANGE);
+	      return NSS_STATUS_TRYAGAIN;
+	    }
+	  p2 = buffer + (buflen - p2len);
+	  buflen -= p2len;
+	  p = strncpy (buffer, outval, buflen);
+	  while (isspace (*p))
+	    p++;
+	  free (outval);
+	  if (_nss_files_parse_spent (p, result, buffer, buflen))
+	    {
+	      copy_spwd_changes (result, &pwd, p2, p2len);
+	      give_spwd_free (&pwd);
+	      /* We found the entry.  */
+	      break;
+	    }
+	  else
+	    {
+	      /* Give buffer the old len back */
+	      buflen += p2len;
+	      give_spwd_free (&pwd);
+	    }
+	}
+
+      /* +:... */
+      if (result->sp_namp[0] == '+' && result->sp_namp[1] == '\0')
+	{
+	  ent->nis = TRUE;
+	  ent->first = TRUE;
+	  copy_spwd_changes (&ent->pwd, result, NULL, 0);
+
+	  return getspent_next_nis (result, ent, buffer, buflen);
+	}
+    }
+
+  return NSS_STATUS_SUCCESS;
+}
+
+
+static enum nss_status
+internal_getspent_r (struct spwd *pw, ent_t *ent,
+		     char *buffer, size_t buflen)
+{
+  if (ent->netgroup)
+    {
+      int status;
+
+      /* We are searching members in a netgroup */
+      /* Since this is not the first call, we don't need the group name */
+      status = getspent_next_netgr (pw, ent, NULL, buffer, buflen);
+      if (status == NSS_STATUS_RETURN)
+	return getspent_next_file (pw, ent, buffer, buflen);
+      else
+	return status;
+    }
+  else if (ent->nis)
+    return getspent_next_nis (pw, ent, buffer, buflen);
+  else
+    return getspent_next_file (pw, ent, buffer, buflen);
+}
+
+enum nss_status
+_nss_compat_getspent_r (struct spwd *pwd, char *buffer, size_t buflen)
+{
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  __libc_lock_lock (lock);
+
+  /* Be prepared that the setspent function was not called before.  */
+  if (ext_ent.stream == NULL)
+    status = internal_setspent (&ext_ent);
+
+  if (status == NSS_STATUS_SUCCESS)
+    status = internal_getspent_r (pwd, &ext_ent, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+
+enum nss_status
+_nss_compat_getspnam_r (const char *name, struct spwd *pwd,
+			char *buffer, size_t buflen)
+{
+  ent_t ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0},
+	       {NULL, NULL, 0, 0, 0, 0, 0, 0, 0}};
+  enum nss_status status;
+
+  if (name[0] == '-' || name[0] == '+')
+    return NSS_STATUS_NOTFOUND;
+
+  status = internal_setspent (&ent);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+  while ((status = internal_getspent_r (pwd, &ent, buffer, buflen))
+	 == NSS_STATUS_SUCCESS)
+    if (strcmp (pwd->sp_namp, name) == 0)
+      break;
+
+  internal_endspent (&ent);
+  return status;
+}
+
+/* Support routines for remembering -@netgroup and -user entries.
+   The names are stored in a single string with `|' as separator. */
+static void
+blacklist_store_name (const char *name, ent_t *ent)
+{
+  int namelen = strlen (name);
+  char *tmp;
+
+  /* first call, setup cache */
+  if (ent->blacklist.size == 0)
+    {
+      ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen);
+      ent->blacklist.data = malloc (ent->blacklist.size);
+      if (ent->blacklist.data == NULL)
+	return;
+      ent->blacklist.data[0] = '|';
+      ent->blacklist.data[1] = '\0';
+      ent->blacklist.current = 1;
+    }
+  else
+    {
+      if (in_blacklist (name, namelen, ent))
+	return;			/* no duplicates */
+
+      if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size)
+	{
+	  ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen);
+	  tmp = realloc (ent->blacklist.data, ent->blacklist.size);
+	  if (tmp == NULL)
+	    {
+	      free (ent->blacklist.data);
+	      ent->blacklist.size = 0;
+	      return;
+	    }
+	  ent->blacklist.data = tmp;
+	}
+    }
+
+  tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name);
+  *tmp++ = '|';
+  *tmp = '\0';
+  ent->blacklist.current += namelen + 1;
+
+  return;
+}
+
+/* returns TRUE if ent->blacklist contains name, else FALSE */
+static bool_t
+in_blacklist (const char *name, int namelen, ent_t *ent)
+{
+  char buf[namelen + 3];
+
+  if (ent->blacklist.data == NULL)
+    return FALSE;
+
+  stpcpy (stpcpy (stpcpy (buf, "|"), name), "|");
+  return strstr (ent->blacklist.data, buf) != NULL;
+}
diff --git a/nis/nss_nis/nis-alias.c b/nis/nss_nis/nis-alias.c
new file mode 100644
index 0000000000..af83d9cd7c
--- /dev/null
+++ b/nis/nss_nis/nis-alias.c
@@ -0,0 +1,269 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <aliases.h>
+#include <libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+__libc_lock_define_initialized (static, lock)
+
+static bool_t new_start = 1;
+static char *oldkey = NULL;
+static int oldkeylen = 0;
+
+static int
+_nss_nis_parse_aliasent (char *key, char *alias, struct aliasent *result,
+			 char *buffer, size_t buflen)
+{
+  char *first_unused = buffer + strlen (alias) + 1;
+  size_t room_left =
+    buflen - (buflen % __alignof__ (char *)) - strlen (alias) - 2;
+  char *line;
+  char *cp;
+
+  result->alias_members_len = 0;
+  *first_unused = '\0';
+  first_unused++;
+  strcpy (first_unused, key);
+
+  if (first_unused[room_left - 1] != '\0')
+    {
+      /* The line is too long for our buffer.  */
+    no_more_room:
+      __set_errno (ERANGE);
+      return -1;
+    }
+
+  result->alias_name = first_unused;
+
+  /* Terminate the line for any case.  */
+  cp = strpbrk (alias, "#\n");
+  if (cp != NULL)
+    *cp = '\0';
+
+  first_unused += strlen (result->alias_name) + 1;
+  /* Adjust the pointer so it is aligned for
+     storing pointers.  */
+  first_unused += __alignof__ (char *) - 1;
+  first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
+  result->alias_members = (char **) first_unused;
+
+  line = alias;
+
+  while (*line != '\0')
+    {
+      /* Skip leading blanks.  */
+      while (isspace (*line))
+	line++;
+
+      if (*line == '\0')
+	break;
+
+      if (room_left < sizeof (char *))
+	  goto no_more_room;
+      room_left -= sizeof (char *);
+      result->alias_members[result->alias_members_len] = line;
+
+      while (*line != '\0' && *line != ',')
+	line++;
+
+      if (line != result->alias_members[result->alias_members_len])
+	{
+	  *line = '\0';
+	  line++;
+	  result->alias_members_len++;
+	}
+    }
+  return result->alias_members_len == 0 ? 0 : 1;
+}
+
+enum nss_status
+_nss_nis_setaliasent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_endaliasent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+internal_nis_getaliasent_r (struct aliasent *alias, char *buffer,
+			    size_t buflen)
+{
+  char *domain;
+  char *result;
+  int len;
+  char *outkey;
+  int keylen;
+  char *p;
+  int parse_res;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  alias->alias_local = 0;
+
+  /* Get the next entry until we found a correct one. */
+  do
+    {
+      enum nss_status retval;
+
+      if (new_start)
+        retval = yperr2nss (yp_first (domain, "mail.aliases",
+				      &outkey, &keylen, &result, &len));
+      else
+        retval = yperr2nss ( yp_next (domain, "mail.aliases", oldkey,
+				      oldkeylen, &outkey, &keylen,
+				      &result, &len));
+      if (retval != NSS_STATUS_SUCCESS)
+	{
+	  if (retval == NSS_STATUS_TRYAGAIN)
+            __set_errno (EAGAIN);
+          return retval;
+        }
+
+      if (len + 1 > buflen)
+        {
+	  free (result);
+          __set_errno (ERANGE);
+          return NSS_STATUS_TRYAGAIN;
+        }
+      p = strncpy (buffer, result, len);
+      buffer[len] = '\0';
+      while (isspace (*p))
+        ++p;
+      free (result);
+
+      parse_res = _nss_nis_parse_aliasent (outkey, p, alias, buffer, buflen);
+      if (parse_res == -1)
+	{
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      free (oldkey);
+      oldkey = outkey;
+      oldkeylen = keylen;
+      new_start = 0;
+    }
+  while (!parse_res);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getaliasent_r (struct aliasent *alias, char *buffer, size_t buflen)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_getaliasent_r (alias, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_getaliasbyname_r (const char *name, struct aliasent *alias,
+			   char *buffer, size_t buflen)
+{
+  enum nss_status retval;
+  int parse_res;
+  char *domain;
+  char *result;
+  int len;
+  char *p;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  retval = yperr2nss (yp_match (domain, "mail.aliases", name, strlen (name),
+				&result, &len));
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+	__set_errno (EAGAIN);
+      return retval;
+    }
+
+  if (len + 1 > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  alias->alias_local = 0;
+  parse_res = _nss_nis_parse_aliasent (name, p, alias, buffer, buflen);
+  if (parse_res == -1)
+    return NSS_STATUS_TRYAGAIN;
+  else
+    if (parse_res == 0)
+      return NSS_STATUS_NOTFOUND;
+    else
+      return NSS_STATUS_SUCCESS;
+}
diff --git a/nis/nss_nis/nis-ethers.c b/nis/nss_nis/nis-ethers.c
new file mode 100644
index 0000000000..26449720bb
--- /dev/null
+++ b/nis/nss_nis/nis-ethers.c
@@ -0,0 +1,264 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+#include <netinet/if_ether.h>
+
+#include "nss-nis.h"
+
+/* Protect global state against multiple changers */
+__libc_lock_define_initialized (static, lock)
+
+struct ether
+{
+  char *e_name;
+  struct ether_addr e_addr;
+};
+
+static bool_t new_start = 1;
+static char *oldkey = NULL;
+static int oldkeylen = 0;
+
+enum nss_status
+_nss_nis_setetherent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_endetherent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+internal_nis_getetherent_r (struct ether *eth, char *buffer, size_t buflen)
+{
+  char *domain, *result, *outkey;
+  int len, keylen, parse_res;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  /* Get the next entry until we found a correct one. */
+  do
+    {
+      enum nss_status retval;
+      char *p;
+
+      if (new_start)
+        retval = yperr2nss (yp_first (domain, "ethers.byaddr",
+                                      &outkey, &keylen, &result, &len));
+      else
+        retval = yperr2nss ( yp_next (domain, "ethers.byaddr",
+                                      oldkey, oldkeylen,
+                                      &outkey, &keylen, &result, &len));
+
+      if (retval != NSS_STATUS_SUCCESS)
+        {
+          if (retval == NSS_STATUS_TRYAGAIN)
+            __set_errno (EAGAIN);
+          return retval;
+        }
+
+      if (len + 1 > buflen)
+        {
+          free (result);
+          __set_errno (ERANGE);
+          return NSS_STATUS_TRYAGAIN;
+        }
+
+      p = strncpy (buffer, result, len);
+      buffer[len] = '\0';
+      while (isspace (*p))
+        ++p;
+      free (result);
+
+      parse_res = _nss_files_parse_etherent (p, eth, buffer, buflen);
+      if (!parse_res && errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+
+      free (oldkey);
+      oldkey = outkey;
+      oldkeylen = keylen;
+      new_start = 0;
+    }
+  while (!parse_res);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getetherent_r (struct ether *result, char *buffer, size_t buflen)
+{
+  int status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_getetherent_r (result, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_getethernam_r (const char *name, struct ether *eth,
+			char *buffer, size_t buflen)
+{
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, parse_res;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  retval = yperr2nss (yp_match (domain, "ethers.byname", name,
+				strlen (name), &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+        __set_errno (EAGAIN);
+      return retval;
+    }
+
+  if (len + 1 > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_etherent (p, eth, buffer, buflen);
+
+  if (!parse_res)
+    {
+      if (errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+      else
+        return NSS_STATUS_NOTFOUND;
+    }
+  else
+    return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getetherbyaddr_r (struct ether_addr *addr, struct ether *eth,
+			   char *buffer, size_t buflen)
+{
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, nlen, parse_res;
+  char buf[33];
+
+  if (addr == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  nlen = sprintf (buf, "%x:%x:%x:%x:%x:%x",
+		  (int) addr->ether_addr_octet[0],
+		  (int) addr->ether_addr_octet[1],
+		  (int) addr->ether_addr_octet[2],
+		  (int) addr->ether_addr_octet[3],
+		  (int) addr->ether_addr_octet[4],
+		  (int) addr->ether_addr_octet[5]);
+
+  retval = yperr2nss (yp_match (domain, "ethers.byaddr", buf,
+				nlen, &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+        __set_errno (EAGAIN);
+      return retval;
+    }
+
+  if (len + 1 > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_etherent (p, eth, buffer, buflen);
+
+  if (!parse_res)
+    {
+      if (errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+      else
+        return NSS_STATUS_NOTFOUND;
+    }
+  else
+    return NSS_STATUS_SUCCESS;
+}
diff --git a/nis/nss_nis/nis-grp.c b/nis/nss_nis/nis-grp.c
new file mode 100644
index 0000000000..1bab862c2f
--- /dev/null
+++ b/nis/nss_nis/nis-grp.c
@@ -0,0 +1,246 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h>
+#include <grp.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+/* Protect global state against multiple changers */
+__libc_lock_define_initialized (static, lock)
+
+static bool_t new_start = 1;
+static char *oldkey = NULL;
+static int oldkeylen = 0;
+
+enum nss_status
+_nss_nis_setgrent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_endgrent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+internal_nis_getgrent_r (struct group *grp, char *buffer, size_t buflen)
+{
+  char *domain, *result, *outkey;
+  int len, keylen, parse_res;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  /* Get the next entry until we found a correct one. */
+  do
+    {
+      enum nss_status retval;
+      char *p;
+
+      if (new_start)
+        retval = yperr2nss (yp_first (domain, "group.byname",
+                                      &outkey, &keylen, &result, &len));
+      else
+        retval = yperr2nss ( yp_next (domain, "group.byname",
+                                      oldkey, oldkeylen,
+                                      &outkey, &keylen, &result, &len));
+
+      if (retval != NSS_STATUS_SUCCESS)
+        {
+          if (retval == NSS_STATUS_TRYAGAIN)
+            __set_errno (EAGAIN);
+          return retval;
+        }
+
+      if (len + 1 > buflen)
+        {
+          free (result);
+          __set_errno (ERANGE);
+          return NSS_STATUS_TRYAGAIN;
+        }
+
+      p = strncpy (buffer, result, len);
+      buffer[len] = '\0';
+      while (isspace (*p))
+        ++p;
+      free (result);
+
+      parse_res = _nss_files_parse_grent (p, grp, buffer, buflen);
+      if (!parse_res && errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+
+      free (oldkey);
+      oldkey = outkey;
+      oldkeylen = keylen;
+      new_start = 0;
+    }
+  while (!parse_res);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getgrent_r (struct group *result, char *buffer, size_t buflen)
+{
+  int status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_getgrent_r (result, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_getgrnam_r (const char *name, struct group *grp,
+		     char *buffer, size_t buflen)
+{
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, parse_res;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  retval = yperr2nss (yp_match (domain, "group.byname", name,
+				strlen (name), &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+        __set_errno (EAGAIN);
+      return retval;
+    }
+
+  if (len + 1 > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_grent (p, grp, buffer, buflen);
+
+  if (!parse_res)
+    {
+      if (errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+      else
+        return NSS_STATUS_NOTFOUND;
+    }
+  else
+    return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getgrgid_r (gid_t gid, struct group *grp,
+		     char *buffer, size_t buflen)
+{
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, nlen, parse_res;
+  char buf[32];
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  nlen = sprintf (buf, "%d", gid);
+
+  retval = yperr2nss (yp_match (domain, "group.bygid", buf,
+				nlen, &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+        __set_errno (EAGAIN);
+      return retval;
+    }
+
+  if (len + 1 > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_grent (p, grp, buffer, buflen);
+
+  if (!parse_res)
+    {
+      if (errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+      else
+        return NSS_STATUS_NOTFOUND;
+    }
+  else
+    return NSS_STATUS_SUCCESS;
+}
diff --git a/nis/nss_nis/nis-hosts.c b/nis/nss_nis/nis-hosts.c
new file mode 100644
index 0000000000..9adce18ca3
--- /dev/null
+++ b/nis/nss_nis/nis-hosts.c
@@ -0,0 +1,389 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+/* Get implementation for some internal functions. */
+#include "../../resolv/mapv4v6addr.h"
+#include "../../resolv/mapv4v6hostent.h"
+
+#define ENTNAME         hostent
+#define DATABASE        "hosts"
+#define NEED_H_ERRNO
+
+#define ENTDATA hostent_data
+struct hostent_data
+  {
+    unsigned char host_addr[16];	/* IPv4 or IPv6 address.  */
+    char *h_addr_ptrs[2];	/* Points to that and null terminator.  */
+  };
+
+#define TRAILING_LIST_MEMBER            h_aliases
+#define TRAILING_LIST_SEPARATOR_P       isspace
+#include "../../nss/nss_files/files-parse.c"
+LINE_PARSER
+("#",
+ {
+   char *addr;
+
+   STRING_FIELD (addr, isspace, 1);
+
+   /* Parse address.  */
+   if ((_res.options & RES_USE_INET6)
+       && inet_pton (AF_INET6, addr, entdata->host_addr) > 0)
+     {
+       result->h_addrtype = AF_INET6;
+       result->h_length = IN6ADDRSZ;
+     }
+   else
+     if (inet_pton (AF_INET, addr, entdata->host_addr) > 0)
+       {
+	 if (_res.options & RES_USE_INET6)
+	   {
+	     map_v4v6_address ((char *) entdata->host_addr,
+			       (char *) entdata->host_addr);
+	     result->h_addrtype = AF_INET6;
+	     result->h_length = IN6ADDRSZ;
+	   }
+	 else
+	   {
+	     result->h_addrtype = AF_INET;
+	     result->h_length = INADDRSZ;
+	   }
+       }
+     else
+       /* Illegal address: ignore line.  */
+       return 0;
+
+   /* Store a pointer to the address in the expected form.  */
+   entdata->h_addr_ptrs[0] = entdata->host_addr;
+   entdata->h_addr_ptrs[1] = NULL;
+   result->h_addr_list = entdata->h_addr_ptrs;
+
+   /* If we need the host entry in IPv6 form change it now.  */
+   if (_res.options & RES_USE_INET6)
+     {
+       char *bufptr = data->linebuffer;
+       size_t buflen = (char *) data + datalen - bufptr;
+       map_v4v6_hostent (result, &bufptr, &buflen);
+     }
+
+   STRING_FIELD (result->h_name, isspace, 1);
+ }
+)
+
+__libc_lock_define_initialized (static, lock)
+
+static bool_t new_start = 1;
+static char *oldkey = NULL;
+static int oldkeylen = 0;
+
+enum nss_status
+_nss_nis_sethostent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_endhostent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+internal_nis_gethostent_r (struct hostent *host, char *buffer,
+			   size_t buflen, int *h_errnop)
+{
+  char *domain;
+  char *result;
+  int len, parse_res;
+  char *outkey;
+  int keylen;
+  struct parser_data *data = (void *) buffer;
+  size_t linebuflen = buffer + buflen - data->linebuffer;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  if (buflen < sizeof *data + 1)
+    {
+      __set_errno (ERANGE);
+      *h_errnop = NETDB_INTERNAL;
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  /* Get the next entry until we found a correct one. */
+  do
+    {
+      enum nss_status retval;
+      char *p;
+
+      if (new_start)
+        retval = yperr2nss (yp_first (domain, "hosts.byname",
+                                      &outkey, &keylen, &result, &len));
+      else
+        retval = yperr2nss ( yp_next (domain, "hosts.byname",
+                                      oldkey, oldkeylen,
+                                      &outkey, &keylen, &result, &len));
+
+      if (retval != NSS_STATUS_SUCCESS)
+        {
+	  switch (retval)
+	    {
+	    case NSS_STATUS_TRYAGAIN:
+	      __set_errno (EAGAIN);
+	      *h_errnop = TRY_AGAIN;
+	      break;
+	    case NSS_STATUS_NOTFOUND:
+	      *h_errnop = HOST_NOT_FOUND;
+	      break;
+	    default:
+	      *h_errnop = NO_RECOVERY;
+	      break;
+	    }
+	  return retval;
+	}
+
+      if (len + 1 > linebuflen)
+        {
+          free (result);
+	  *h_errnop = NETDB_INTERNAL;
+          __set_errno (ERANGE);
+          return NSS_STATUS_TRYAGAIN;
+        }
+
+      p = strncpy (data->linebuffer, result, len);
+      data->linebuffer[len] = '\0';
+      while (isspace (*p))
+	++p;
+      free (result);
+
+      parse_res = parse_line (p, host, data, buflen);
+      if (!parse_res && errno == ERANGE)
+	{
+	  *h_errnop = NETDB_INTERNAL;;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      free (oldkey);
+      oldkey = outkey;
+      oldkeylen = keylen;
+      new_start = 0;
+    }
+  while (!parse_res);
+
+  *h_errnop = NETDB_SUCCESS;
+  return NSS_STATUS_SUCCESS;
+}
+
+int
+_nss_nis_gethostent_r (struct hostent *host, char *buffer, size_t buflen,
+		       int *h_errnop)
+{
+  int status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_gethostent_r (host, buffer, buflen, h_errnop);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_gethostbyname_r (const char *name, struct hostent *host,
+			  char *buffer, size_t buflen, int *h_errnop)
+{
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, parse_res;
+  struct parser_data *data = (void *) buffer;
+  size_t linebuflen = buffer + buflen - data->linebuffer;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  if (buflen < sizeof *data + 1)
+    {
+      *h_errnop = NETDB_INTERNAL;
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+  retval = yperr2nss (yp_match (domain, "hosts.byname", name,
+                                strlen (name), &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+	{
+	  *h_errnop = TRY_AGAIN;
+	  __set_errno (EAGAIN);
+	}
+      if (retval == NSS_STATUS_NOTFOUND)
+	*h_errnop = HOST_NOT_FOUND;
+      return retval;
+    }
+
+  if (len + 1 > linebuflen)
+    {
+      free (result);
+      *h_errnop = NETDB_INTERNAL;
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (data->linebuffer, result, len);
+  data->linebuffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = parse_line (p, host, data, buflen);
+
+  if (!parse_res)
+    {
+      if (errno == ERANGE)
+	{
+	  *h_errnop = NETDB_INTERNAL;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      else
+	{
+	  *h_errnop = HOST_NOT_FOUND;
+	  return NSS_STATUS_NOTFOUND;
+	}
+    }
+
+  *h_errnop = NETDB_SUCCESS;
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_gethostbyaddr_r (char *addr, int addrlen, int type,
+			  struct hostent *host, char *buffer, size_t buflen,
+			  int *h_errnop)
+{
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, parse_res;
+  char *buf;
+  struct parser_data *data = (void *) buffer;
+  size_t linebuflen = buffer + buflen - data->linebuffer;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  if (buflen < sizeof *data + 1)
+    {
+      __set_errno (ERANGE);
+      *h_errnop = NETDB_INTERNAL;
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  buf = inet_ntoa (*(struct in_addr *) addr);
+
+  retval = yperr2nss (yp_match (domain, "hosts.byaddr", buf,
+                                strlen (buf), &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+	{
+	  *h_errnop = TRY_AGAIN;
+	  __set_errno (EAGAIN);
+	}
+      if (retval == NSS_STATUS_NOTFOUND)
+	*h_errnop = HOST_NOT_FOUND;
+      return retval;
+    }
+
+  if (len + 1 > linebuflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      *h_errnop = NETDB_INTERNAL;
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (data->linebuffer, result, len);
+  data->linebuffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = parse_line (p, host, data, buflen);
+
+  if (!parse_res)
+    {
+      if (errno == ERANGE)
+	{
+	  *h_errnop = NETDB_INTERNAL;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      else
+	{
+	  *h_errnop = HOST_NOT_FOUND;
+	  return NSS_STATUS_NOTFOUND;
+	}
+    }
+
+  *h_errnop = NETDB_SUCCESS;
+  return NSS_STATUS_SUCCESS;
+}
diff --git a/nis/nss_nis/nis-netgrp.c b/nis/nss_nis/nis-netgrp.c
new file mode 100644
index 0000000000..7609ea08ed
--- /dev/null
+++ b/nis/nss_nis/nis-netgrp.c
@@ -0,0 +1,128 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h>
+#include <ctype.h>
+#include <errno.h>
+#include <libc-lock.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netgroup.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+/* Locks the static variables in this file.  */
+__libc_lock_define_initialized (static, lock)
+
+static char *data = NULL;
+static size_t data_size = 0;
+static char *cursor = NULL;;
+
+extern enum nss_status
+_nss_netgroup_parseline (char **cursor, struct __netgrent *result,
+			 char *buffer, size_t buflen);
+
+enum nss_status
+_nss_nis_setnetgrent (char *group)
+{
+  char *domain;
+  char *result;
+  int len, group_len;
+  enum nss_status status;
+
+  status = NSS_STATUS_SUCCESS;
+
+  if (group[0] == '\0')
+    return NSS_STATUS_UNAVAIL;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  __libc_lock_lock (lock);
+
+  if (data != NULL)
+    {
+      free (data);
+      data = NULL;
+      data_size = 0;
+      cursor = NULL;
+    }
+
+  group_len = strlen (group);
+
+  status = yperr2nss (yp_match (domain, "netgroup", group, group_len,
+				&result, &len));
+  if (status == NSS_STATUS_SUCCESS)
+    {
+      if (len > 0)
+	{
+	  data = malloc (len + 1);
+	  data_size = len;
+	  cursor = strncpy (data, result, len + 1);
+	  data[len] = '\0';
+	  free (result);
+	}
+      else
+	status = NSS_STATUS_NOTFOUND;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+
+enum nss_status
+_nss_nis_endnetgrent (void)
+{
+  __libc_lock_lock (lock);
+
+  if (data != NULL)
+    {
+      free (data);
+      data = NULL;
+      data_size = 0;
+      cursor = NULL;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getnetgrent_r (struct __netgrent *result, char *buffer, size_t buflen)
+{
+  enum nss_status status;
+
+  if (cursor == NULL)
+    return NSS_STATUS_NOTFOUND;
+
+  __libc_lock_lock (lock);
+
+  status = _nss_netgroup_parseline (&cursor, result, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
diff --git a/nis/nss_nis/nis-network.c b/nis/nss_nis/nis-network.c
new file mode 100644
index 0000000000..2795feb421
--- /dev/null
+++ b/nis/nss_nis/nis-network.c
@@ -0,0 +1,292 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+__libc_lock_define_initialized (static, lock)
+
+static bool_t new_start = 1;
+static char *oldkey = NULL;
+static int oldkeylen = 0;
+
+enum nss_status
+_nss_nis_setnetent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_endnetent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+internal_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen,
+			  int *herrnop)
+{
+  char *domain, *result, *outkey;
+  int len, keylen, parse_res;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  /* Get the next entry until we found a correct one. */
+  do
+    {
+      enum nss_status retval;
+      char *p;
+
+      if (new_start)
+        retval = yperr2nss (yp_first (domain, "networks.byname",
+                                      &outkey, &keylen, &result, &len));
+      else
+        retval = yperr2nss ( yp_next (domain, "networks.byname",
+                                      oldkey, oldkeylen,
+                                      &outkey, &keylen, &result, &len));
+
+      if (retval != NSS_STATUS_SUCCESS)
+        {
+          if (retval == NSS_STATUS_TRYAGAIN)
+	    {
+	      *herrnop = NETDB_INTERNAL;
+	      __set_errno (EAGAIN);
+	    }
+          return retval;
+        }
+
+      if (len + 1 > buflen)
+        {
+          free (result);
+          __set_errno (ERANGE);
+	  *herrnop = NETDB_INTERNAL;
+          return NSS_STATUS_TRYAGAIN;
+        }
+
+      p = strncpy (buffer, result, len);
+      buffer[len] = '\0';
+      while (isspace (*p))
+        ++p;
+      free (result);
+
+      parse_res = _nss_files_parse_netent (p, net, buffer, buflen);
+      if (!parse_res && errno == ERANGE)
+	{
+	  *herrnop = NETDB_INTERNAL;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      free (oldkey);
+      oldkey = outkey;
+      oldkeylen = keylen;
+      new_start = 0;
+    }
+  while (!parse_res);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen,
+		      int *herrnop)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_getnetent_r (net, buffer, buflen, herrnop);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_getnetbyname_r (const char *name, struct netent *net,
+			 char *buffer, size_t buflen, int *herrnop)
+{
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, parse_res;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      *herrnop = NETDB_INTERNAL;
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  retval = yperr2nss (yp_match (domain, "networks.byname", name,
+                                strlen (name), &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+	{
+	  __set_errno (EAGAIN);
+	  *herrnop = NETDB_INTERNAL;
+	}
+      return retval;
+    }
+
+  if (len + 1 > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      *herrnop = NETDB_INTERNAL;
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_netent (p, net, buffer, buflen);
+
+  if (!parse_res)
+    {
+      *herrnop = NETDB_INTERNAL;
+      if (errno == ERANGE)
+	return NSS_STATUS_TRYAGAIN;
+      else
+        return NSS_STATUS_NOTFOUND;
+    }
+  else
+    return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getnetbyaddr_r (unsigned long addr, int type, struct netent *net,
+			 char *buffer, size_t buflen, int *herrnop)
+{
+  char *domain;
+  char *result;
+  int len;
+  char buf[256];
+  int blen;
+  struct in_addr in;
+  char *p;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  in = inet_makeaddr (addr, 0);
+  strcpy (buf, inet_ntoa (in));
+  blen = strlen (buf);
+
+  while (1)
+    {
+      enum nss_status retval;
+      int parse_res;
+
+      retval = yperr2nss (yp_match (domain, "networks.byaddr", buf,
+				    strlen (buf), &result, &len));
+
+	if (retval != NSS_STATUS_SUCCESS)
+	  {
+	    if (retval == NSS_STATUS_NOTFOUND)
+	      {
+		if (buf[blen - 2] == '.' && buf[blen - 1] == '0')
+		  {
+		    /* Try again, but with trailing dot(s)
+		       removed (one by one) */
+		    buf[blen - 2] = '\0';
+		    blen -= 2;
+		    continue;
+		  }
+		else
+		  return NSS_STATUS_NOTFOUND;
+	      }
+	    else
+	      {
+		if (retval == NSS_STATUS_TRYAGAIN)
+		  __set_errno (EAGAIN);
+		return retval;
+	      }
+	  }
+
+      if (len + 1 > buflen)
+	{
+	  free (result);
+	  __set_errno (ERANGE);
+	  *herrnop = NETDB_INTERNAL;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+        p = strncpy (buffer, result, len);
+	buffer[len] = '\0';
+	while (isspace (*p))
+	  ++p;
+	free (result);
+
+	parse_res = _nss_files_parse_netent (p, net, buffer, buflen);
+
+
+	if (!parse_res)
+	  {
+	    *herrnop = NETDB_INTERNAL;
+	    if (errno == ERANGE)
+	      return NSS_STATUS_TRYAGAIN;
+	    else
+	      return NSS_STATUS_NOTFOUND;
+	  }
+	else
+	  return NSS_STATUS_SUCCESS;
+    }
+}
diff --git a/nis/nss_nis/nis-proto.c b/nis/nss_nis/nis-proto.c
new file mode 100644
index 0000000000..f62dfb1492
--- /dev/null
+++ b/nis/nss_nis/nis-proto.c
@@ -0,0 +1,246 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+__libc_lock_define_initialized (static, lock)
+
+static bool_t new_start = 1;
+static char *oldkey = NULL;
+static int oldkeylen = 0;
+
+enum nss_status
+_nss_nis_setprotoent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_endprotoent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+internal_nis_getprotoent_r (struct protoent *proto,
+			    char *buffer, size_t buflen)
+{
+  char *domain, *result, *outkey;
+  int len, keylen, parse_res;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  /* Get the next entry until we found a correct one. */
+  do
+    {
+      enum nss_status retval;
+      char *p;
+
+      if (new_start)
+        retval = yperr2nss (yp_first (domain, "protocols.bynumber",
+                                      &outkey, &keylen, &result, &len));
+      else
+        retval = yperr2nss ( yp_next (domain, "protocols.bynumber",
+                                      oldkey, oldkeylen,
+                                      &outkey, &keylen, &result, &len));
+
+      if (retval != NSS_STATUS_SUCCESS)
+        {
+          if (retval == NSS_STATUS_TRYAGAIN)
+            __set_errno (EAGAIN);
+          return retval;
+        }
+
+      if (len + 1 > buflen)
+        {
+          free (result);
+          __set_errno (ERANGE);
+          return NSS_STATUS_TRYAGAIN;
+        }
+
+      p = strncpy (buffer, result, len);
+      buffer[len] = '\0';
+      while (isspace (*p))
+        ++p;
+      free (result);
+
+      parse_res = _nss_files_parse_protoent (p, proto, buffer, buflen);
+      if (!parse_res && errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+
+      free (oldkey);
+      oldkey = outkey;
+      oldkeylen = keylen;
+      new_start = 0;
+    }
+  while (!parse_res);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getprotoent_r (struct protoent *proto, char *buffer, size_t buflen)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_getprotoent_r (proto, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_getprotobyname_r (const char *name, struct protoent *proto,
+			   char *buffer, size_t buflen)
+{
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, parse_res;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  retval = yperr2nss (yp_match (domain, "protocols.byname", name,
+                                strlen (name), &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+        __set_errno (EAGAIN);
+      return retval;
+    }
+
+  if (len + 1 > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_protoent (p, proto, buffer, buflen);
+
+  if (!parse_res)
+    {
+      if (errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+      else
+        return NSS_STATUS_NOTFOUND;
+    }
+  else
+    return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getprotobynumber_r (int number, struct protoent *proto,
+			     char *buffer, size_t buflen)
+{
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, nlen, parse_res;
+  char buf[32];
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  nlen = sprintf (buf, "%d", number);
+
+  retval = yperr2nss (yp_match (domain, "protocols.bynumber", buf,
+                                nlen, &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+        __set_errno (EAGAIN);
+      return retval;
+    }
+
+  if (len + 1 > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_protoent (p, proto, buffer, buflen);
+
+  if (!parse_res)
+    {
+      if (errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+      else
+        return NSS_STATUS_NOTFOUND;
+    }
+  else
+    return NSS_STATUS_SUCCESS;
+}
diff --git a/nis/nss_nis/nis-publickey.c b/nis/nss_nis/nis-publickey.c
new file mode 100644
index 0000000000..b9eda6a742
--- /dev/null
+++ b/nis/nss_nis/nis-publickey.c
@@ -0,0 +1,220 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <syslog.h>
+#include <libc-lock.h>
+#include <rpc/key_prot.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+extern int xdecrypt (char *, char *);
+
+/* If we found the entry, we give a SUCCESS and an empty key back. */
+enum nss_status
+_nss_nis_getpublickey (const char *netname, char *pkey)
+{
+  enum nss_status retval;
+  char *domain, *result;
+  int len;
+
+  pkey[0] = 0;
+
+  if (netname == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  domain = strchr (netname, '@');
+  if (!domain)
+    return NSS_STATUS_UNAVAIL;
+  domain++;
+
+  retval = yperr2nss (yp_match (domain, "publickey.byname", netname,
+				strlen (netname), &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+	__set_errno (EAGAIN);
+      return retval;
+    }
+
+  if (result != NULL)
+    {
+      char *p = strchr (result, ':');
+      if (p != NULL)
+	*p = 0;
+      strcpy (pkey, result);
+    }
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getsecretkey (const char *netname, char *skey, char *passwd)
+{
+  enum nss_status retval;
+  char buf[1024];
+  char *domain, *result;
+  int len;
+
+  skey[0] = 0;
+
+  if (netname == NULL || passwd == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  domain = strchr (netname, '@');
+  if (!domain)
+    return NSS_STATUS_UNAVAIL;
+  domain++;
+
+  retval = yperr2nss (yp_match (domain, "publickey.byname", netname,
+				strlen (netname), &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+	__set_errno (EAGAIN);
+      return retval;
+    }
+
+  if (result != NULL)
+    {
+      char *p = strchr (result, ':');
+      if (p == NULL)
+	return NSS_STATUS_SUCCESS;
+
+      p++;
+      strcpy (buf, p);
+      if (!xdecrypt (buf, passwd))
+	return NSS_STATUS_SUCCESS;
+
+      if (memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) != 0)
+	return NSS_STATUS_SUCCESS;
+
+      buf[HEXKEYBYTES] = 0;
+      strcpy (skey, buf);
+    }
+  return NSS_STATUS_SUCCESS;
+}
+
+/* Parse uid and group information from the passed string.
+   The format of the string passed is uid:gid,grp,grp, ...  */
+static enum nss_status
+parse_netid_str (const char *s, uid_t *uidp, gid_t *gidp, int *gidlenp,
+		 gid_t *gidlist)
+{
+  char *p;
+
+  if (!s || !isdigit (*s))
+    {
+      syslog (LOG_ERR, "netname2user: expecting uid '%s'", s);
+      return NSS_STATUS_NOTFOUND;	/* XXX need a better error */
+    }
+
+  /* Fetch the uid */
+  *uidp = (atoi (s));
+
+  if (*uidp == 0)
+    {
+      syslog (LOG_ERR, "netname2user: should not have uid 0");
+      return NSS_STATUS_NOTFOUND;
+    }
+
+  /* Now get the group list */
+  p = strchr (s, ':');
+  if (!p)
+    {
+      syslog (LOG_ERR, "netname2user: missing group id list in '%s'", s);
+      return NSS_STATUS_NOTFOUND;
+    }
+  ++p;				/* skip ':' */
+  if (!p || (!isdigit (*p)))
+    {
+      syslog (LOG_ERR, "netname2user: missing group id list in '%s'.", p);
+      return NSS_STATUS_NOTFOUND;
+    }
+
+  *gidp = (atoi (p));
+
+  *gidlenp = 0;
+#if 0
+  while ((p = strchr (p, ',')) != NULL)
+    {
+      p++;
+      gidlist[*gidlenp++] = atoi (p);
+    }
+#endif
+
+  return NSS_STATUS_SUCCESS;
+}
+
+
+enum nss_status
+_nss_nis_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
+		       gid_t *gidp, int *gidlenp, gid_t *gidlist)
+{
+  char *domain;
+  int yperr;
+  char *lookup;
+  int len;
+
+  domain = strchr (netname, '@');
+  if (!domain)
+    return NSS_STATUS_UNAVAIL;
+
+  /* Point past the '@' character */
+  domain++;
+  lookup = NULL;
+  yperr = yp_match (domain, "netid.byname", netname, strlen (netname),
+		    &lookup, &len);
+  switch (yperr)
+    {
+    case YPERR_SUCCESS:
+      break;			/* the successful case */
+    case YPERR_DOMAIN:
+    case YPERR_KEY:
+      return NSS_STATUS_NOTFOUND;
+    case YPERR_MAP:
+    default:
+      return NSS_STATUS_UNAVAIL;
+    }
+  if (lookup)
+    {
+      enum nss_status err;
+
+      lookup[len] = '\0';
+      err = parse_netid_str (lookup, uidp, gidp, gidlenp, gidlist);
+      free (lookup);
+      return err;
+    }
+  else
+    return NSS_STATUS_NOTFOUND;
+
+  return NSS_STATUS_SUCCESS;
+}
diff --git a/nis/nss_nis/nis-pwd.c b/nis/nss_nis/nis-pwd.c
new file mode 100644
index 0000000000..afcc7a428e
--- /dev/null
+++ b/nis/nss_nis/nis-pwd.c
@@ -0,0 +1,246 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h>
+#include <pwd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+/* Protect global state against multiple changers */
+__libc_lock_define_initialized (static, lock)
+
+static bool_t new_start = 1;
+static char *oldkey = NULL;
+static int oldkeylen = 0;
+
+enum nss_status
+_nss_nis_setpwent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_endpwent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen)
+{
+  char *domain, *result, *outkey;
+  int len, keylen, parse_res;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  /* Get the next entry until we found a correct one. */
+  do
+    {
+      enum nss_status retval;
+      char *p;
+
+      if (new_start)
+        retval = yperr2nss (yp_first (domain, "passwd.byname",
+                                      &outkey, &keylen, &result, &len));
+      else
+        retval = yperr2nss ( yp_next (domain, "passwd.byname",
+                                      oldkey, oldkeylen,
+                                      &outkey, &keylen, &result, &len));
+
+      if (retval != NSS_STATUS_SUCCESS)
+        {
+          if (retval == NSS_STATUS_TRYAGAIN)
+            __set_errno (EAGAIN);
+          return retval;
+        }
+
+      if (len + 1 > buflen)
+        {
+          free (result);
+          __set_errno (ERANGE);
+          return NSS_STATUS_TRYAGAIN;
+        }
+
+      p = strncpy (buffer, result, len);
+      buffer[len] = '\0';
+      while (isspace (*p))
+        ++p;
+      free (result);
+
+      parse_res = _nss_files_parse_pwent (p, pwd, buffer, buflen);
+      if (!parse_res && errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+
+      free (oldkey);
+      oldkey = outkey;
+      oldkeylen = keylen;
+      new_start = 0;
+    }
+  while (!parse_res);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getpwent_r (struct passwd *result, char *buffer, size_t buflen)
+{
+  int status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_getpwent_r (result, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_getpwnam_r (const char *name, struct passwd *pwd,
+		     char *buffer, size_t buflen)
+{
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, parse_res;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  retval = yperr2nss (yp_match (domain, "passwd.byname", name,
+				strlen (name), &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+        __set_errno (EAGAIN);
+      return retval;
+    }
+
+  if (len + 1 > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_pwent (p, pwd, buffer, buflen);
+
+  if (!parse_res)
+    {
+      if (errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+      else
+        return NSS_STATUS_NOTFOUND;
+    }
+  else
+    return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd,
+		     char *buffer, size_t buflen)
+{
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, nlen, parse_res;
+  char buf[32];
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  nlen = sprintf (buf, "%d", uid);
+
+  retval = yperr2nss (yp_match (domain, "passwd.byuid", buf,
+				nlen, &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+        __set_errno (EAGAIN);
+      return retval;
+    }
+
+  if (len + 1 > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_pwent (p, pwd, buffer, buflen);
+
+  if (!parse_res)
+    {
+      if (errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+      else
+        return NSS_STATUS_NOTFOUND;
+    }
+  else
+    return NSS_STATUS_SUCCESS;
+}
diff --git a/nis/nss_nis/nis-rpc.c b/nis/nss_nis/nis-rpc.c
new file mode 100644
index 0000000000..91f54be3a9
--- /dev/null
+++ b/nis/nss_nis/nis-rpc.c
@@ -0,0 +1,270 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+__libc_lock_define_initialized (static, lock)
+
+struct intern_t
+{
+  bool_t new_start;
+  char *oldkey;
+  int oldkeylen;
+};
+typedef struct intern_t intern_t;
+
+static intern_t intern = {TRUE, NULL, 0};
+
+static enum nss_status
+internal_nis_setrpcent (intern_t *data)
+{
+  data->new_start = 1;
+  if (data->oldkey != NULL)
+    {
+      free (data->oldkey);
+      data->oldkey = NULL;
+      data->oldkeylen = 0;
+    }
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_setrpcent (void)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_setrpcent (&intern);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+static enum nss_status
+internal_nis_endrpcent (intern_t *data)
+{
+  data->new_start = 1;
+  if (data->oldkey != NULL)
+    {
+      free (data->oldkey);
+      data->oldkey = NULL;
+      data->oldkeylen = 0;
+    }
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_endrpcent (void)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_endrpcent (&intern);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+static enum nss_status
+internal_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen,
+			  intern_t *data)
+{
+  char *domain;
+  char *result;
+  int len, parse_res;
+  char *outkey;
+  int keylen;
+  char *p;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  /* Get the next entry until we found a correct one. */
+  do
+    {
+      enum nss_status retval;
+
+      if (data->new_start)
+        retval = yperr2nss (yp_first (domain, "rpc.bynumber",
+                                      &outkey, &keylen, &result, &len));
+      else
+        retval = yperr2nss ( yp_next (domain, "rpc.bynumber",
+				      data->oldkey, data->oldkeylen,
+				      &outkey, &keylen, &result, &len));
+
+      if (retval != NSS_STATUS_SUCCESS)
+        {
+          if (retval == NSS_STATUS_TRYAGAIN)
+            __set_errno (EAGAIN);
+          return retval;
+        }
+
+      if (len + 1 > buflen)
+        {
+          free (result);
+          __set_errno (ERANGE);
+          return NSS_STATUS_TRYAGAIN;
+        }
+
+      p = strncpy (buffer, result, len);
+      buffer[len] = '\0';
+      while (isspace (*p))
+        ++p;
+      free (result);
+
+      parse_res = _nss_files_parse_rpcent (p, rpc, buffer, buflen);
+      if (!parse_res && errno == ERANGE)
+	return NSS_STATUS_TRYAGAIN;
+
+      free (data->oldkey);
+      data->oldkey = outkey;
+      data->oldkeylen = keylen;
+      data->new_start = 0;
+    }
+  while (!parse_res);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_getrpcent_r (rpc, buffer, buflen, &intern);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_getrpcbyname_r (const char *name, struct rpcent *rpc,
+			 char *buffer, size_t buflen)
+{
+  intern_t data = {TRUE, NULL, 0};
+  enum nss_status status;
+  int found;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  status = internal_nis_setrpcent (&data);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+  found = 0;
+  while (!found &&
+         ((status = internal_nis_getrpcent_r (rpc, buffer, buflen, &data))
+          == NSS_STATUS_SUCCESS))
+    {
+      if (strcmp (rpc->r_name, name) == 0)
+	found = 1;
+      else
+	{
+	  int i = 0;
+
+	  while (rpc->r_aliases[i] != NULL)
+	    {
+	      if (strcmp (rpc->r_aliases[i], name) == 0)
+		{
+		  found = 1;
+		  break;
+		}
+	      else
+		++i;
+	    }
+	}
+    }
+
+  internal_nis_endrpcent (&data);
+
+  if (!found && status == NSS_STATUS_SUCCESS)
+    return NSS_STATUS_NOTFOUND;
+  else
+    return status;
+}
+
+enum nss_status
+_nss_nis_getrpcbynumber_r (int number, struct rpcent *rpc,
+			   char *buffer, size_t buflen)
+{
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, nlen, parse_res;
+  char buf[32];
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  nlen = sprintf (buf, "%d", number);
+
+  retval = yperr2nss (yp_match (domain, "rpc.bynumber", buf,
+				 nlen, &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+	__set_errno (EAGAIN);
+      return retval;
+    }
+
+  if (len + 1 > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_rpcent (p, rpc, buffer, buflen);
+
+  if (!parse_res)
+    {
+      if (errno == ERANGE)
+	return NSS_STATUS_TRYAGAIN;
+      else
+	return NSS_STATUS_NOTFOUND;
+    }
+  else
+    return NSS_STATUS_SUCCESS;
+}
diff --git a/nis/nss_nis/nis-service.c b/nis/nss_nis/nis-service.c
new file mode 100644
index 0000000000..03a9fbf48e
--- /dev/null
+++ b/nis/nss_nis/nis-service.c
@@ -0,0 +1,249 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+__libc_lock_define_initialized (static, lock)
+
+struct intern_t
+{
+  bool_t new_start;
+  char *oldkey;
+  int oldkeylen;
+};
+typedef struct intern_t intern_t;
+
+static intern_t intern = {TRUE, NULL, 0};
+
+static enum nss_status
+internal_nis_setservent (intern_t * intern)
+{
+  intern->new_start = 1;
+  if (intern->oldkey != NULL)
+    {
+      free (intern->oldkey);
+      intern->oldkey = NULL;
+      intern->oldkeylen = 0;
+    }
+  return NSS_STATUS_SUCCESS;
+}
+enum nss_status
+_nss_nis_setservent (void)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_setservent (&intern);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+static enum nss_status
+internal_nis_endservent (intern_t * intern)
+{
+  intern->new_start = 1;
+  if (intern->oldkey != NULL)
+    {
+      free (intern->oldkey);
+      intern->oldkey = NULL;
+      intern->oldkeylen = 0;
+    }
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_endservent (void)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_endservent (&intern);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+static enum nss_status
+internal_nis_getservent_r (struct servent *serv, char *buffer,
+			   size_t buflen, intern_t *data)
+{
+  char *domain;
+  char *result;
+  int len, parse_res;
+  char *outkey;
+  int keylen;
+  char *p;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  /* Get the next entry until we found a correct one. */
+  do
+    {
+      enum nss_status retval;
+
+      if (data->new_start)
+        retval = yperr2nss (yp_first (domain, "services.byname",
+                                      &outkey, &keylen, &result, &len));
+      else
+        retval = yperr2nss ( yp_next (domain, "services.byname",
+                                      data->oldkey, data->oldkeylen,
+                                      &outkey, &keylen, &result, &len));
+
+      if (retval != NSS_STATUS_SUCCESS)
+        {
+          if (retval == NSS_STATUS_TRYAGAIN)
+            __set_errno (EAGAIN);
+          return retval;
+        }
+
+      if (len + 1 > buflen)
+        {
+          free (result);
+          __set_errno (ERANGE);
+          return NSS_STATUS_TRYAGAIN;
+        }
+
+      p = strncpy (buffer, result, len);
+      buffer[len] = '\0';
+      while (isspace (*p))
+        ++p;
+      free (result);
+
+      parse_res = _nss_files_parse_servent (p, serv, buffer, buflen);
+      if (!parse_res && errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+
+      free (data->oldkey);
+      data->oldkey = outkey;
+      data->oldkeylen = keylen;
+      data->new_start = 0;
+    }
+  while (!parse_res);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getservent_r (struct servent *serv, char *buffer, size_t buflen)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_getservent_r (serv, buffer, buflen, &intern);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_getservbyname_r (const char *name, char *protocol,
+			  struct servent *serv, char *buffer, size_t buflen)
+{
+  intern_t data = {TRUE, NULL, 0};
+  enum nss_status status;
+  int found;
+
+  if (name == NULL || protocol == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  status = internal_nis_setservent (&data);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+  found = 0;
+  while (!found &&
+         ((status = internal_nis_getservent_r (serv, buffer, buflen, &data))
+          == NSS_STATUS_SUCCESS))
+    {
+      if (strcmp (serv->s_name, name) == 0)
+        {
+          if (strcmp (serv->s_proto, protocol) == 0)
+            {
+              found = 1;
+            }
+        }
+    }
+
+  internal_nis_endservent (&data);
+
+  if (!found && status == NSS_STATUS_SUCCESS)
+    return NSS_STATUS_NOTFOUND;
+  else
+    return status;
+}
+
+enum nss_status
+_nss_nis_getservbyport_r (int port, char *protocol, struct servent *serv,
+			  char *buffer, size_t buflen)
+{
+  intern_t data = {TRUE, NULL, 0};
+  enum nss_status status;
+  int found;
+
+  if (protocol == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  status = internal_nis_setservent (&data);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+  found = 0;
+  while (!found &&
+         ((status = internal_nis_getservent_r (serv, buffer, buflen, &data))
+          == NSS_STATUS_SUCCESS))
+    {
+      if (htons (serv->s_port) == port)
+        {
+          if  (strcmp (serv->s_proto, protocol) == 0)
+            {
+              found = 1;
+            }
+        }
+    }
+
+  internal_nis_endservent (&data);
+
+  if (!found && status == NSS_STATUS_SUCCESS)
+    return NSS_STATUS_NOTFOUND;
+  else
+    return status;
+}
diff --git a/nis/nss_nis/nis-spwd.c b/nis/nss_nis/nis-spwd.c
new file mode 100644
index 0000000000..928489245b
--- /dev/null
+++ b/nis/nss_nis/nis-spwd.c
@@ -0,0 +1,196 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <nss.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <shadow.h>
+#include <libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+/* Protect global state against multiple changers */
+__libc_lock_define_initialized (static, lock)
+
+static bool_t new_start = 1;
+static char *oldkey = NULL;
+static int oldkeylen = 0;
+
+enum nss_status
+_nss_nis_setspent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_endspent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+internal_nis_getspent_r (struct spwd *sp, char *buffer, size_t buflen)
+{
+  char *domain, *result, *outkey;
+  int len, keylen, parse_res;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  /* Get the next entry until we found a correct one. */
+  do
+    {
+      enum nss_status retval;
+      char *p;
+
+      if (new_start)
+        retval = yperr2nss (yp_first (domain, "shadow.byname",
+                                      &outkey, &keylen, &result, &len));
+      else
+        retval = yperr2nss ( yp_next (domain, "shadow.byname",
+                                      oldkey, oldkeylen,
+                                      &outkey, &keylen, &result, &len));
+
+      if (retval != NSS_STATUS_SUCCESS)
+        {
+          if (retval == NSS_STATUS_TRYAGAIN)
+            __set_errno (EAGAIN);
+          return retval;
+        }
+
+      if (len + 1 > buflen)
+        {
+          free (result);
+          __set_errno (ERANGE);
+          return NSS_STATUS_TRYAGAIN;
+        }
+
+      p = strncpy (buffer, result, len);
+      buffer[len] = '\0';
+      while (isspace (*p))
+        ++p;
+      free (result);
+
+      parse_res = _nss_files_parse_spent (p, sp, buffer, buflen);
+      if (!parse_res && errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+
+      free (oldkey);
+      oldkey = outkey;
+      oldkeylen = keylen;
+      new_start = 0;
+    }
+  while (!parse_res);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getspent_r (struct spwd *result, char *buffer, size_t buflen)
+{
+  int status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_getspent_r (result, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_getspnam_r (const char *name, struct spwd *sp,
+		     char *buffer, size_t buflen)
+{
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, parse_res;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  retval = yperr2nss (yp_match (domain, "shadow.byname", name,
+				strlen (name), &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+        __set_errno (EAGAIN);
+      return retval;
+    }
+
+  if (len + 1 > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_spent (p, sp, buffer, buflen);
+
+  if (!parse_res)
+    {
+      if (errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+      else
+        return NSS_STATUS_NOTFOUND;
+    }
+  else
+    return NSS_STATUS_SUCCESS;
+}
diff --git a/nis/rpcsvc/yp.h b/nis/rpcsvc/yp.h
new file mode 100644
index 0000000000..f625eced50
--- /dev/null
+++ b/nis/rpcsvc/yp.h
@@ -0,0 +1,611 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+#ifndef __RPCSVC_YP_H__
+#define __RPCSVC_YP_H__
+
+#include <rpc/rpc.h>
+
+#define YPMAXRECORD 1024
+#define YPMAXDOMAIN 64
+#define YPMAXMAP 64
+#define YPMAXPEER 64
+
+enum ypstat {
+	YP_TRUE = 1,
+	YP_NOMORE = 2,
+	YP_FALSE = 0,
+	YP_NOMAP = -1,
+	YP_NODOM = -2,
+	YP_NOKEY = -3,
+	YP_BADOP = -4,
+	YP_BADDB = -5,
+	YP_YPERR = -6,
+	YP_BADARGS = -7,
+	YP_VERS = -8,
+};
+typedef enum ypstat ypstat;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_ypstat(XDR *, ypstat*);
+#elif __STDC__ 
+extern  bool_t xdr_ypstat(XDR *, ypstat*);
+#else /* Old Style C */ 
+bool_t xdr_ypstat();
+#endif /* Old Style C */ 
+
+
+enum ypxfrstat {
+	YPXFR_SUCC = 1,
+	YPXFR_AGE = 2,
+	YPXFR_NOMAP = -1,
+	YPXFR_NODOM = -2,
+	YPXFR_RSRC = -3,
+	YPXFR_RPC = -4,
+	YPXFR_MADDR = -5,
+	YPXFR_YPERR = -6,
+	YPXFR_BADARGS = -7,
+	YPXFR_DBM = -8,
+	YPXFR_FILE = -9,
+	YPXFR_SKEW = -10,
+	YPXFR_CLEAR = -11,
+	YPXFR_FORCE = -12,
+	YPXFR_XFRERR = -13,
+	YPXFR_REFUSED = -14,
+};
+typedef enum ypxfrstat ypxfrstat;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_ypxfrstat(XDR *, ypxfrstat*);
+#elif __STDC__ 
+extern  bool_t xdr_ypxfrstat(XDR *, ypxfrstat*);
+#else /* Old Style C */ 
+bool_t xdr_ypxfrstat();
+#endif /* Old Style C */ 
+
+
+typedef char *domainname;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_domainname(XDR *, domainname*);
+#elif __STDC__ 
+extern  bool_t xdr_domainname(XDR *, domainname*);
+#else /* Old Style C */ 
+bool_t xdr_domainname();
+#endif /* Old Style C */ 
+
+
+typedef char *mapname;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_mapname(XDR *, mapname*);
+#elif __STDC__ 
+extern  bool_t xdr_mapname(XDR *, mapname*);
+#else /* Old Style C */ 
+bool_t xdr_mapname();
+#endif /* Old Style C */ 
+
+
+typedef char *peername;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_peername(XDR *, peername*);
+#elif __STDC__ 
+extern  bool_t xdr_peername(XDR *, peername*);
+#else /* Old Style C */ 
+bool_t xdr_peername();
+#endif /* Old Style C */ 
+
+
+typedef struct {
+	u_int keydat_len;
+	char *keydat_val;
+} keydat;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_keydat(XDR *, keydat*);
+#elif __STDC__ 
+extern  bool_t xdr_keydat(XDR *, keydat*);
+#else /* Old Style C */ 
+bool_t xdr_keydat();
+#endif /* Old Style C */ 
+
+
+typedef struct {
+	u_int valdat_len;
+	char *valdat_val;
+} valdat;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_valdat(XDR *, valdat*);
+#elif __STDC__ 
+extern  bool_t xdr_valdat(XDR *, valdat*);
+#else /* Old Style C */ 
+bool_t xdr_valdat();
+#endif /* Old Style C */ 
+
+
+struct ypmap_parms {
+	domainname domain;
+	mapname map;
+	u_int ordernum;
+	peername peer;
+};
+typedef struct ypmap_parms ypmap_parms;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_ypmap_parms(XDR *, ypmap_parms*);
+#elif __STDC__ 
+extern  bool_t xdr_ypmap_parms(XDR *, ypmap_parms*);
+#else /* Old Style C */ 
+bool_t xdr_ypmap_parms();
+#endif /* Old Style C */ 
+
+
+struct ypreq_key {
+	domainname domain;
+	mapname map;
+	keydat key;
+};
+typedef struct ypreq_key ypreq_key;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_ypreq_key(XDR *, ypreq_key*);
+#elif __STDC__ 
+extern  bool_t xdr_ypreq_key(XDR *, ypreq_key*);
+#else /* Old Style C */ 
+bool_t xdr_ypreq_key();
+#endif /* Old Style C */ 
+
+
+struct ypreq_nokey {
+	domainname domain;
+	mapname map;
+};
+typedef struct ypreq_nokey ypreq_nokey;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_ypreq_nokey(XDR *, ypreq_nokey*);
+#elif __STDC__ 
+extern  bool_t xdr_ypreq_nokey(XDR *, ypreq_nokey*);
+#else /* Old Style C */ 
+bool_t xdr_ypreq_nokey();
+#endif /* Old Style C */ 
+
+
+struct ypreq_xfr {
+	ypmap_parms map_parms;
+	u_int transid;
+	u_int prog;
+	u_int port;
+};
+typedef struct ypreq_xfr ypreq_xfr;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_ypreq_xfr(XDR *, ypreq_xfr*);
+#elif __STDC__ 
+extern  bool_t xdr_ypreq_xfr(XDR *, ypreq_xfr*);
+#else /* Old Style C */ 
+bool_t xdr_ypreq_xfr();
+#endif /* Old Style C */ 
+
+
+struct ypresp_val {
+	ypstat stat;
+	valdat val;
+};
+typedef struct ypresp_val ypresp_val;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_ypresp_val(XDR *, ypresp_val*);
+#elif __STDC__ 
+extern  bool_t xdr_ypresp_val(XDR *, ypresp_val*);
+#else /* Old Style C */ 
+bool_t xdr_ypresp_val();
+#endif /* Old Style C */ 
+
+
+struct ypresp_key_val {
+	ypstat stat;
+	valdat val;
+	keydat key;
+};
+typedef struct ypresp_key_val ypresp_key_val;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_ypresp_key_val(XDR *, ypresp_key_val*);
+#elif __STDC__ 
+extern  bool_t xdr_ypresp_key_val(XDR *, ypresp_key_val*);
+#else /* Old Style C */ 
+bool_t xdr_ypresp_key_val();
+#endif /* Old Style C */ 
+
+
+struct ypresp_master {
+	ypstat stat;
+	peername peer;
+};
+typedef struct ypresp_master ypresp_master;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_ypresp_master(XDR *, ypresp_master*);
+#elif __STDC__ 
+extern  bool_t xdr_ypresp_master(XDR *, ypresp_master*);
+#else /* Old Style C */ 
+bool_t xdr_ypresp_master();
+#endif /* Old Style C */ 
+
+
+struct ypresp_order {
+	ypstat stat;
+	u_int ordernum;
+};
+typedef struct ypresp_order ypresp_order;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_ypresp_order(XDR *, ypresp_order*);
+#elif __STDC__ 
+extern  bool_t xdr_ypresp_order(XDR *, ypresp_order*);
+#else /* Old Style C */ 
+bool_t xdr_ypresp_order();
+#endif /* Old Style C */ 
+
+
+struct ypresp_all {
+	bool_t more;
+	union {
+		ypresp_key_val val;
+	} ypresp_all_u;
+};
+typedef struct ypresp_all ypresp_all;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_ypresp_all(XDR *, ypresp_all*);
+#elif __STDC__ 
+extern  bool_t xdr_ypresp_all(XDR *, ypresp_all*);
+#else /* Old Style C */ 
+bool_t xdr_ypresp_all();
+#endif /* Old Style C */ 
+
+
+struct ypresp_xfr {
+	u_int transid;
+	ypxfrstat xfrstat;
+};
+typedef struct ypresp_xfr ypresp_xfr;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_ypresp_xfr(XDR *, ypresp_xfr*);
+#elif __STDC__ 
+extern  bool_t xdr_ypresp_xfr(XDR *, ypresp_xfr*);
+#else /* Old Style C */ 
+bool_t xdr_ypresp_xfr();
+#endif /* Old Style C */ 
+
+
+struct ypmaplist {
+	mapname map;
+	struct ypmaplist *next;
+};
+typedef struct ypmaplist ypmaplist;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_ypmaplist(XDR *, ypmaplist*);
+#elif __STDC__ 
+extern  bool_t xdr_ypmaplist(XDR *, ypmaplist*);
+#else /* Old Style C */ 
+bool_t xdr_ypmaplist();
+#endif /* Old Style C */ 
+
+
+struct ypresp_maplist {
+	ypstat stat;
+	ypmaplist *maps;
+};
+typedef struct ypresp_maplist ypresp_maplist;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_ypresp_maplist(XDR *, ypresp_maplist*);
+#elif __STDC__ 
+extern  bool_t xdr_ypresp_maplist(XDR *, ypresp_maplist*);
+#else /* Old Style C */ 
+bool_t xdr_ypresp_maplist();
+#endif /* Old Style C */ 
+
+
+enum yppush_status {
+	YPPUSH_SUCC = 1,
+	YPPUSH_AGE = 2,
+	YPPUSH_NOMAP = -1,
+	YPPUSH_NODOM = -2,
+	YPPUSH_RSRC = -3,
+	YPPUSH_RPC = -4,
+	YPPUSH_MADDR = -5,
+	YPPUSH_YPERR = -6,
+	YPPUSH_BADARGS = -7,
+	YPPUSH_DBM = -8,
+	YPPUSH_FILE = -9,
+	YPPUSH_SKEW = -10,
+	YPPUSH_CLEAR = -11,
+	YPPUSH_FORCE = -12,
+	YPPUSH_XFRERR = -13,
+	YPPUSH_REFUSED = -14,
+};
+typedef enum yppush_status yppush_status;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_yppush_status(XDR *, yppush_status*);
+#elif __STDC__ 
+extern  bool_t xdr_yppush_status(XDR *, yppush_status*);
+#else /* Old Style C */ 
+bool_t xdr_yppush_status();
+#endif /* Old Style C */ 
+
+
+struct yppushresp_xfr {
+	u_int transid;
+	yppush_status status;
+};
+typedef struct yppushresp_xfr yppushresp_xfr;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_yppushresp_xfr(XDR *, yppushresp_xfr*);
+#elif __STDC__ 
+extern  bool_t xdr_yppushresp_xfr(XDR *, yppushresp_xfr*);
+#else /* Old Style C */ 
+bool_t xdr_yppushresp_xfr();
+#endif /* Old Style C */ 
+
+
+enum ypbind_resptype {
+	YPBIND_SUCC_VAL = 1,
+	YPBIND_FAIL_VAL = 2,
+};
+typedef enum ypbind_resptype ypbind_resptype;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_ypbind_resptype(XDR *, ypbind_resptype*);
+#elif __STDC__ 
+extern  bool_t xdr_ypbind_resptype(XDR *, ypbind_resptype*);
+#else /* Old Style C */ 
+bool_t xdr_ypbind_resptype();
+#endif /* Old Style C */ 
+
+
+struct ypbind_binding {
+	char ypbind_binding_addr[4];
+	char ypbind_binding_port[2];
+};
+typedef struct ypbind_binding ypbind_binding;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_ypbind_binding(XDR *, ypbind_binding*);
+#elif __STDC__ 
+extern  bool_t xdr_ypbind_binding(XDR *, ypbind_binding*);
+#else /* Old Style C */ 
+bool_t xdr_ypbind_binding();
+#endif /* Old Style C */ 
+
+
+struct ypbind_resp {
+	ypbind_resptype ypbind_status;
+	union {
+		u_int ypbind_error;
+		ypbind_binding ypbind_bindinfo;
+	} ypbind_resp_u;
+};
+typedef struct ypbind_resp ypbind_resp;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_ypbind_resp(XDR *, ypbind_resp*);
+#elif __STDC__ 
+extern  bool_t xdr_ypbind_resp(XDR *, ypbind_resp*);
+#else /* Old Style C */ 
+bool_t xdr_ypbind_resp();
+#endif /* Old Style C */ 
+
+#define YPBIND_ERR_ERR 1
+#define YPBIND_ERR_NOSERV 2
+#define YPBIND_ERR_RESC 3
+
+struct ypbind_setdom {
+	domainname ypsetdom_domain;
+	ypbind_binding ypsetdom_binding;
+	u_int ypsetdom_vers;
+};
+typedef struct ypbind_setdom ypbind_setdom;
+#ifdef __cplusplus 
+extern "C" bool_t xdr_ypbind_setdom(XDR *, ypbind_setdom*);
+#elif __STDC__ 
+extern  bool_t xdr_ypbind_setdom(XDR *, ypbind_setdom*);
+#else /* Old Style C */ 
+bool_t xdr_ypbind_setdom();
+#endif /* Old Style C */ 
+
+
+#define YPPROG ((u_long)100004)
+#define YPVERS ((u_long)2)
+
+#ifdef __cplusplus
+#define YPPROC_NULL ((u_long)0)
+extern "C" void * ypproc_null_2(void *, CLIENT *);
+extern "C" void * ypproc_null_2_svc(void *, struct svc_req *);
+#define YPPROC_DOMAIN ((u_long)1)
+extern "C" bool_t * ypproc_domain_2(domainname *, CLIENT *);
+extern "C" bool_t * ypproc_domain_2_svc(domainname *, struct svc_req *);
+#define YPPROC_DOMAIN_NONACK ((u_long)2)
+extern "C" bool_t * ypproc_domain_nonack_2(domainname *, CLIENT *);
+extern "C" bool_t * ypproc_domain_nonack_2_svc(domainname *, struct svc_req *);
+#define YPPROC_MATCH ((u_long)3)
+extern "C" ypresp_val * ypproc_match_2(ypreq_key *, CLIENT *);
+extern "C" ypresp_val * ypproc_match_2_svc(ypreq_key *, struct svc_req *);
+#define YPPROC_FIRST ((u_long)4)
+extern "C" ypresp_key_val * ypproc_first_2(ypreq_key *, CLIENT *);
+extern "C" ypresp_key_val * ypproc_first_2_svc(ypreq_key *, struct svc_req *);
+#define YPPROC_NEXT ((u_long)5)
+extern "C" ypresp_key_val * ypproc_next_2(ypreq_key *, CLIENT *);
+extern "C" ypresp_key_val * ypproc_next_2_svc(ypreq_key *, struct svc_req *);
+#define YPPROC_XFR ((u_long)6)
+extern "C" ypresp_xfr * ypproc_xfr_2(ypreq_xfr *, CLIENT *);
+extern "C" ypresp_xfr * ypproc_xfr_2_svc(ypreq_xfr *, struct svc_req *);
+#define YPPROC_CLEAR ((u_long)7)
+extern "C" void * ypproc_clear_2(void *, CLIENT *);
+extern "C" void * ypproc_clear_2_svc(void *, struct svc_req *);
+#define YPPROC_ALL ((u_long)8)
+extern "C" ypresp_all * ypproc_all_2(ypreq_nokey *, CLIENT *);
+extern "C" ypresp_all * ypproc_all_2_svc(ypreq_nokey *, struct svc_req *);
+#define YPPROC_MASTER ((u_long)9)
+extern "C" ypresp_master * ypproc_master_2(ypreq_nokey *, CLIENT *);
+extern "C" ypresp_master * ypproc_master_2_svc(ypreq_nokey *, struct svc_req *);
+#define YPPROC_ORDER ((u_long)10)
+extern "C" ypresp_order * ypproc_order_2(ypreq_nokey *, CLIENT *);
+extern "C" ypresp_order * ypproc_order_2_svc(ypreq_nokey *, struct svc_req *);
+#define YPPROC_MAPLIST ((u_long)11)
+extern "C" ypresp_maplist * ypproc_maplist_2(domainname *, CLIENT *);
+extern "C" ypresp_maplist * ypproc_maplist_2_svc(domainname *, struct svc_req *);
+
+#elif __STDC__
+#define YPPROC_NULL ((u_long)0)
+extern  void * ypproc_null_2(void *, CLIENT *);
+extern  void * ypproc_null_2_svc(void *, struct svc_req *);
+#define YPPROC_DOMAIN ((u_long)1)
+extern  bool_t * ypproc_domain_2(domainname *, CLIENT *);
+extern  bool_t * ypproc_domain_2_svc(domainname *, struct svc_req *);
+#define YPPROC_DOMAIN_NONACK ((u_long)2)
+extern  bool_t * ypproc_domain_nonack_2(domainname *, CLIENT *);
+extern  bool_t * ypproc_domain_nonack_2_svc(domainname *, struct svc_req *);
+#define YPPROC_MATCH ((u_long)3)
+extern  ypresp_val * ypproc_match_2(ypreq_key *, CLIENT *);
+extern  ypresp_val * ypproc_match_2_svc(ypreq_key *, struct svc_req *);
+#define YPPROC_FIRST ((u_long)4)
+extern  ypresp_key_val * ypproc_first_2(ypreq_key *, CLIENT *);
+extern  ypresp_key_val * ypproc_first_2_svc(ypreq_key *, struct svc_req *);
+#define YPPROC_NEXT ((u_long)5)
+extern  ypresp_key_val * ypproc_next_2(ypreq_key *, CLIENT *);
+extern  ypresp_key_val * ypproc_next_2_svc(ypreq_key *, struct svc_req *);
+#define YPPROC_XFR ((u_long)6)
+extern  ypresp_xfr * ypproc_xfr_2(ypreq_xfr *, CLIENT *);
+extern  ypresp_xfr * ypproc_xfr_2_svc(ypreq_xfr *, struct svc_req *);
+#define YPPROC_CLEAR ((u_long)7)
+extern  void * ypproc_clear_2(void *, CLIENT *);
+extern  void * ypproc_clear_2_svc(void *, struct svc_req *);
+#define YPPROC_ALL ((u_long)8)
+extern  ypresp_all * ypproc_all_2(ypreq_nokey *, CLIENT *);
+extern  ypresp_all * ypproc_all_2_svc(ypreq_nokey *, struct svc_req *);
+#define YPPROC_MASTER ((u_long)9)
+extern  ypresp_master * ypproc_master_2(ypreq_nokey *, CLIENT *);
+extern  ypresp_master * ypproc_master_2_svc(ypreq_nokey *, struct svc_req *);
+#define YPPROC_ORDER ((u_long)10)
+extern  ypresp_order * ypproc_order_2(ypreq_nokey *, CLIENT *);
+extern  ypresp_order * ypproc_order_2_svc(ypreq_nokey *, struct svc_req *);
+#define YPPROC_MAPLIST ((u_long)11)
+extern  ypresp_maplist * ypproc_maplist_2(domainname *, CLIENT *);
+extern  ypresp_maplist * ypproc_maplist_2_svc(domainname *, struct svc_req *);
+
+#else /* Old Style C */ 
+#define YPPROC_NULL ((u_long)0)
+extern  void * ypproc_null_2();
+extern  void * ypproc_null_2_svc();
+#define YPPROC_DOMAIN ((u_long)1)
+extern  bool_t * ypproc_domain_2();
+extern  bool_t * ypproc_domain_2_svc();
+#define YPPROC_DOMAIN_NONACK ((u_long)2)
+extern  bool_t * ypproc_domain_nonack_2();
+extern  bool_t * ypproc_domain_nonack_2_svc();
+#define YPPROC_MATCH ((u_long)3)
+extern  ypresp_val * ypproc_match_2();
+extern  ypresp_val * ypproc_match_2_svc();
+#define YPPROC_FIRST ((u_long)4)
+extern  ypresp_key_val * ypproc_first_2();
+extern  ypresp_key_val * ypproc_first_2_svc();
+#define YPPROC_NEXT ((u_long)5)
+extern  ypresp_key_val * ypproc_next_2();
+extern  ypresp_key_val * ypproc_next_2_svc();
+#define YPPROC_XFR ((u_long)6)
+extern  ypresp_xfr * ypproc_xfr_2();
+extern  ypresp_xfr * ypproc_xfr_2_svc();
+#define YPPROC_CLEAR ((u_long)7)
+extern  void * ypproc_clear_2();
+extern  void * ypproc_clear_2_svc();
+#define YPPROC_ALL ((u_long)8)
+extern  ypresp_all * ypproc_all_2();
+extern  ypresp_all * ypproc_all_2_svc();
+#define YPPROC_MASTER ((u_long)9)
+extern  ypresp_master * ypproc_master_2();
+extern  ypresp_master * ypproc_master_2_svc();
+#define YPPROC_ORDER ((u_long)10)
+extern  ypresp_order * ypproc_order_2();
+extern  ypresp_order * ypproc_order_2_svc();
+#define YPPROC_MAPLIST ((u_long)11)
+extern  ypresp_maplist * ypproc_maplist_2();
+extern  ypresp_maplist * ypproc_maplist_2_svc();
+#endif /* Old Style C */ 
+
+#define YPPUSH_XFRRESPPROG ((u_long)0x40000000)
+#define YPPUSH_XFRRESPVERS ((u_long)1)
+
+#ifdef __cplusplus
+#define YPPUSHPROC_NULL ((u_long)0)
+extern "C" void * yppushproc_null_1(void *, CLIENT *);
+extern "C" void * yppushproc_null_1_svc(void *, struct svc_req *);
+#define YPPUSHPROC_XFRRESP ((u_long)1)
+extern "C" void * yppushproc_xfrresp_1(yppushresp_xfr *, CLIENT *);
+extern "C" void * yppushproc_xfrresp_1_svc(yppushresp_xfr *, struct svc_req *);
+
+#elif __STDC__
+#define YPPUSHPROC_NULL ((u_long)0)
+extern  void * yppushproc_null_1(void *, CLIENT *);
+extern  void * yppushproc_null_1_svc(void *, struct svc_req *);
+#define YPPUSHPROC_XFRRESP ((u_long)1)
+extern  void * yppushproc_xfrresp_1(yppushresp_xfr *, CLIENT *);
+extern  void * yppushproc_xfrresp_1_svc(yppushresp_xfr *, struct svc_req *);
+
+#else /* Old Style C */ 
+#define YPPUSHPROC_NULL ((u_long)0)
+extern  void * yppushproc_null_1();
+extern  void * yppushproc_null_1_svc();
+#define YPPUSHPROC_XFRRESP ((u_long)1)
+extern  void * yppushproc_xfrresp_1();
+extern  void * yppushproc_xfrresp_1_svc();
+#endif /* Old Style C */ 
+
+#define YPBINDPROG ((u_long)100007)
+#define YPBINDVERS ((u_long)2)
+
+#ifdef __cplusplus
+#define YPBINDPROC_NULL ((u_long)0)
+extern "C" void * ypbindproc_null_2(void *, CLIENT *);
+extern "C" void * ypbindproc_null_2_svc(void *, struct svc_req *);
+#define YPBINDPROC_DOMAIN ((u_long)1)
+extern "C" ypbind_resp * ypbindproc_domain_2(domainname *, CLIENT *);
+extern "C" ypbind_resp * ypbindproc_domain_2_svc(domainname *, struct svc_req *);
+#define YPBINDPROC_SETDOM ((u_long)2)
+extern "C" void * ypbindproc_setdom_2(ypbind_setdom *, CLIENT *);
+extern "C" void * ypbindproc_setdom_2_svc(ypbind_setdom *, struct svc_req *);
+
+#elif __STDC__
+#define YPBINDPROC_NULL ((u_long)0)
+extern  void * ypbindproc_null_2(void *, CLIENT *);
+extern  void * ypbindproc_null_2_svc(void *, struct svc_req *);
+#define YPBINDPROC_DOMAIN ((u_long)1)
+extern  ypbind_resp * ypbindproc_domain_2(domainname *, CLIENT *);
+extern  ypbind_resp * ypbindproc_domain_2_svc(domainname *, struct svc_req *);
+#define YPBINDPROC_SETDOM ((u_long)2)
+extern  void * ypbindproc_setdom_2(ypbind_setdom *, CLIENT *);
+extern  void * ypbindproc_setdom_2_svc(ypbind_setdom *, struct svc_req *);
+
+#else /* Old Style C */ 
+#define YPBINDPROC_NULL ((u_long)0)
+extern  void * ypbindproc_null_2();
+extern  void * ypbindproc_null_2_svc();
+#define YPBINDPROC_DOMAIN ((u_long)1)
+extern  ypbind_resp * ypbindproc_domain_2();
+extern  ypbind_resp * ypbindproc_domain_2_svc();
+#define YPBINDPROC_SETDOM ((u_long)2)
+extern  void * ypbindproc_setdom_2();
+extern  void * ypbindproc_setdom_2_svc();
+#endif /* Old Style C */ 
+
+#endif /* !__RPCSVC_YP_H__ */
diff --git a/nis/rpcsvc/yp.x b/nis/rpcsvc/yp.x
new file mode 100644
index 0000000000..be855df749
--- /dev/null
+++ b/nis/rpcsvc/yp.x
@@ -0,0 +1,300 @@
+/* @(#)yp.x	2.1 88/08/01 4.0 RPCSRC */
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+/*
+ * Protocol description file for the Yellow Pages Service
+ */
+
+const YPMAXRECORD = 1024;
+const YPMAXDOMAIN = 64;
+const YPMAXMAP = 64;
+const YPMAXPEER = 64;
+
+
+enum ypstat {
+	YP_TRUE		=  1,
+	YP_NOMORE	=  2,
+	YP_FALSE	=  0,
+	YP_NOMAP	= -1,
+	YP_NODOM	= -2,
+	YP_NOKEY	= -3,
+	YP_BADOP	= -4,
+	YP_BADDB	= -5,
+	YP_YPERR	= -6,
+	YP_BADARGS	= -7,
+	YP_VERS		= -8
+};
+
+
+enum ypxfrstat {
+	YPXFR_SUCC	=  1,
+	YPXFR_AGE	=  2,
+	YPXFR_NOMAP	= -1,
+	YPXFR_NODOM	= -2,
+	YPXFR_RSRC	= -3,
+	YPXFR_RPC	= -4,
+	YPXFR_MADDR	= -5,
+	YPXFR_YPERR	= -6,
+	YPXFR_BADARGS	= -7,
+	YPXFR_DBM	= -8,
+	YPXFR_FILE	= -9,
+	YPXFR_SKEW	= -10,
+	YPXFR_CLEAR	= -11,
+	YPXFR_FORCE	= -12,
+	YPXFR_XFRERR	= -13,
+	YPXFR_REFUSED	= -14
+};
+
+
+typedef string domainname<YPMAXDOMAIN>;
+typedef string mapname<YPMAXMAP>;
+typedef string peername<YPMAXPEER>;
+typedef opaque keydat<YPMAXRECORD>;
+typedef opaque valdat<YPMAXRECORD>;
+
+
+struct ypmap_parms {
+	domainname domain;	
+	mapname map;
+	unsigned int ordernum;
+	peername peer;
+};
+
+struct ypreq_key {
+	domainname domain;
+	mapname map;
+	keydat key;
+};
+
+struct ypreq_nokey {
+	domainname domain;	
+	mapname map;
+};
+	
+struct ypreq_xfr {
+	ypmap_parms map_parms;
+	unsigned int transid;
+	unsigned int prog;
+	unsigned int port;
+};
+
+
+struct ypresp_val {
+	ypstat stat;
+	valdat val;
+};
+
+struct ypresp_key_val {
+	ypstat stat;
+#ifdef STUPID_SUN_BUG
+	keydat key;
+	valdat val;
+#else
+	valdat val;
+	keydat key;
+#endif
+};
+
+
+struct ypresp_master {
+	ypstat stat;	
+	peername peer;
+};
+
+struct ypresp_order {
+	ypstat stat;
+	unsigned int ordernum;
+};
+
+union ypresp_all switch (bool more) {
+case TRUE:
+	ypresp_key_val val;
+case FALSE:
+	void;
+};
+
+struct ypresp_xfr {
+	unsigned int transid;
+	ypxfrstat xfrstat;
+};
+
+struct ypmaplist {
+	mapname map;
+	ypmaplist *next;
+};
+
+struct ypresp_maplist {
+	ypstat stat;
+	ypmaplist *maps;
+};
+
+enum yppush_status {
+	YPPUSH_SUCC	=  1,	/* Success */
+	YPPUSH_AGE 	=  2,	/* Master's version not newer */
+	YPPUSH_NOMAP	= -1,	/* Can't find server for map */
+	YPPUSH_NODOM	= -2,	/* Domain not supported */
+	YPPUSH_RSRC	= -3,	/* Local resource alloc failure */
+	YPPUSH_RPC	= -4,	/* RPC failure talking to server */
+	YPPUSH_MADDR 	= -5,	/* Can't get master address */
+	YPPUSH_YPERR	= -6,	/* YP server/map db error */
+	YPPUSH_BADARGS	= -7,	/* Request arguments bad */
+	YPPUSH_DBM	= -8,	/* Local dbm operation failed */
+	YPPUSH_FILE	= -9,	/* Local file I/O operation failed */
+	YPPUSH_SKEW	= -10,	/* Map version skew during transfer */
+	YPPUSH_CLEAR	= -11,	/* Can't send "Clear" req to local ypserv */
+	YPPUSH_FORCE	= -12,	/* No local order number in map  use -f flag. */
+	YPPUSH_XFRERR 	= -13,	/* ypxfr error */
+	YPPUSH_REFUSED	= -14 	/* Transfer request refused by ypserv */
+};
+
+struct yppushresp_xfr {
+	unsigned transid;
+	yppush_status status;
+};
+
+/*
+ * Response structure and overall result status codes.  Success and failure
+ * represent two separate response message types.
+ */
+ 
+enum ypbind_resptype {
+	YPBIND_SUCC_VAL = 1, 
+	YPBIND_FAIL_VAL = 2
+};
+ 
+struct ypbind_binding {
+    opaque ypbind_binding_addr[4]; /* In network order */
+    opaque ypbind_binding_port[2]; /* In network order */
+};   
+
+union ypbind_resp switch (ypbind_resptype ypbind_status) {
+case YPBIND_FAIL_VAL:
+        unsigned ypbind_error;
+case YPBIND_SUCC_VAL:
+        ypbind_binding ypbind_bindinfo;
+};     
+
+/* Detailed failure reason codes for response field ypbind_error*/
+ 
+const YPBIND_ERR_ERR    = 1;	/* Internal error */
+const YPBIND_ERR_NOSERV = 2;	/* No bound server for passed domain */
+const YPBIND_ERR_RESC   = 3;	/* System resource allocation failure */
+ 
+ 
+/*
+ * Request data structure for ypbind "Set domain" procedure.
+ */
+struct ypbind_setdom {
+	domainname ypsetdom_domain;
+	ypbind_binding ypsetdom_binding;
+	unsigned ypsetdom_vers;
+};
+
+
+/*
+ * YP access protocol
+ */
+program YPPROG {
+	version YPVERS {
+		void 
+		YPPROC_NULL(void) = 0;
+
+		bool 
+		YPPROC_DOMAIN(domainname) = 1;	
+
+		bool
+		YPPROC_DOMAIN_NONACK(domainname) = 2;
+
+		ypresp_val
+		YPPROC_MATCH(ypreq_key) = 3;
+
+		ypresp_key_val 
+		YPPROC_FIRST(ypreq_key) = 4;
+
+		ypresp_key_val 
+		YPPROC_NEXT(ypreq_key) = 5;
+
+		ypresp_xfr
+		YPPROC_XFR(ypreq_xfr) = 6;
+
+		void
+		YPPROC_CLEAR(void) = 7;
+
+		ypresp_all
+		YPPROC_ALL(ypreq_nokey) = 8;
+
+		ypresp_master
+		YPPROC_MASTER(ypreq_nokey) = 9;
+
+		ypresp_order
+		YPPROC_ORDER(ypreq_nokey) = 10;
+
+		ypresp_maplist 
+		YPPROC_MAPLIST(domainname) = 11;
+	} = 2;
+} = 100004;
+
+
+/*
+ * YPPUSHPROC_XFRRESP is the callback routine for result of YPPROC_XFR
+ */
+program YPPUSH_XFRRESPPROG {
+	version YPPUSH_XFRRESPVERS {
+		void
+		YPPUSHPROC_NULL(void) = 0;
+
+#ifdef STUPID_SUN_BUG
+		yppushresp_xfr	
+		YPPUSHPROC_XFRRESP(void) = 1;
+#else
+		void
+		YPPUSHPROC_XFRRESP(yppushresp_xfr) = 1;
+#endif
+	} = 1;
+} = 0x40000000;	/* transient: could be anything up to 0x5fffffff */
+
+/*
+ * YP binding protocol
+ */
+program YPBINDPROG {
+	version YPBINDVERS {
+		void
+		YPBINDPROC_NULL(void) = 0;
+	
+		ypbind_resp
+		YPBINDPROC_DOMAIN(domainname) = 1;
+
+		void
+		YPBINDPROC_SETDOM(ypbind_setdom) = 2;
+	} = 2;
+} = 100007;
+
+
diff --git a/nis/rpcsvc/yp_prot.h b/nis/rpcsvc/yp_prot.h
new file mode 100644
index 0000000000..60c24a2f5f
--- /dev/null
+++ b/nis/rpcsvc/yp_prot.h
@@ -0,0 +1,334 @@
+/*
+ * This file contains symbols and structures defining the rpc protocol
+ * between the NIS clients and the NIS servers.  The servers
+ * are the NIS database servers, and the NIS binders.  
+ */
+
+#ifndef _RPCSVC_YP_PROT_H
+#define _RPCSVC_YP_PROT_H
+
+#include <features.h>
+
+#include <rpc/rpc.h>
+#include <rpcsvc/ypclnt.h>
+
+/*
+ * The following procedures are supported by the protocol:
+ * 
+ * YPPROC_NULL() returns () takes nothing, returns nothing.  This indicates
+ * that the NIS server is alive.
+ * 
+ * YPPROC_DOMAIN (char *) returns (bool_t) TRUE.  Indicates that the
+ * responding NIS server does serve the named domain; FALSE indicates no
+ * support.
+ * 
+ * YPPROC_DOMAIN_NONACK (char *) returns (TRUE) if the NIS server does serve
+ * the named domain, otherwise does not return.  Used in the broadcast case.
+ * 
+ * YPPROC_MATCH (struct ypreq_key) returns (struct ypresp_val).  Returns the
+ * right-hand value for a passed left-hand key, within a named map and
+ * domain.
+ * 
+ * YPPROC_FIRST (struct ypreq_nokey) returns (struct ypresp_key_val).
+ * Returns the first key-value pair from a named domain and map.
+ * 
+ * YPPROC_NEXT (struct ypreq_key) returns (struct ypresp_key_val).  Returns
+ * the key-value pair following a passed key-value pair within a named
+ * domain and map.
+ *
+ * YPPROC_XFR (struct ypreq_xfr) returns nothing.  Indicates to a server that
+ * a map should be updated.
+ *
+ * YPPROC_CLEAR	takes nothing, returns nothing.  Instructs a NIS server to
+ * close the current map, so that old versions of the disk file don't get
+ * held open.
+ * 
+ * YPPROC_ALL (struct ypreq_nokey), returns
+ * 	union switch (bool_t more) {
+ *		TRUE:	(struct ypresp_key_val);
+ *		FALSE:	(struct) {};
+ *	}
+ *
+ * YPPROC_MASTER (struct ypreq_nokey), returns (ypresp_master)
+ *
+ * YPPROC_ORDER (struct ypreq_nokey), returns (ypresp_order)
+ *
+ * YPPROC_MAPLIST (char *), returns (struct ypmaplist *)
+ */
+
+/* Program and version symbols, magic numbers */
+
+#define YPPROG		((u_long)100004)
+#define YPVERS		((u_long)2)
+#define YPVERS_ORIG	((u_long)1)
+#define YPMAXRECORD	((u_long)1024)
+#define YPMAXDOMAIN	((u_long)256)
+#define YPMAXMAP	((u_long)64)
+#define YPMAXPEER	((u_long)256)
+
+/* byte size of a large NIS packet */
+#define YPMSGSZ		1600
+
+#ifndef DATUM
+typedef struct {
+	char	*dptr;
+	int	dsize;
+} datum;
+#define DATUM
+#endif
+
+struct ypmap_parms {
+  char *domain;			/* Null string means not available */
+  char *map;			/* Null string means not available */
+  unsigned long int ordernum;	/* 0 means not available */
+  char *owner;			/* Null string means not available */
+};
+
+/*
+ * Request parameter structures
+ */
+
+struct ypreq_key {
+  char *domain;
+  char *map;
+  datum keydat;
+};
+
+struct ypreq_nokey {
+  char *domain;
+  char *map;
+};
+
+struct ypreq_xfr {
+  struct ypmap_parms map_parms;
+  unsigned long transid;
+  unsigned long proto;
+  unsigned short port;
+};
+
+struct ypreq_newxfr {
+  struct ypmap_parms map_parms;
+  unsigned long transid;
+  unsigned long proto;
+  char *name;
+};
+
+#define ypxfr_domain map_parms.domain
+#define ypxfr_map map_parms.map
+#define ypxfr_ordernum map_parms.ordernum
+#define ypxfr_owner map_parms.owner
+
+/*
+ * Response parameter structures
+ */
+
+struct ypresp_val {
+  long unsigned status;
+  datum valdat;
+};
+
+struct ypresp_key_val {
+  long unsigned status;
+  datum keydat;
+  datum valdat;
+};
+
+struct ypresp_master {
+  long unsigned status;
+  char *master;
+};
+
+struct ypresp_order {
+  long unsigned status;
+  unsigned long int ordernum;
+};
+
+struct ypmaplist {
+  char ypml_name[YPMAXMAP + 1];
+  struct ypmaplist *ypml_next;
+};
+
+struct ypresp_maplist {
+  long unsigned status;
+  struct ypmaplist *list;
+};
+
+/*
+ * Procedure symbols.  YPPROC_NULL, YPPROC_DOMAIN, and YPPROC_DOMAIN_NONACK
+ * must keep the same values (0, 1, and 2) that they had in the first version
+ * of the protocol.
+ */
+
+#define YPPROC_NULL	((u_long)0)
+#define YPPROC_DOMAIN	((u_long)1)
+#define YPPROC_DOMAIN_NONACK ((u_long)2)
+#define YPPROC_MATCH	((u_long)3)
+#define YPPROC_FIRST	((u_long)4)
+#define YPPROC_NEXT	((u_long)5)
+#define YPPROC_XFR	((u_long)6)
+#define YPPROC_CLEAR	((u_long)7)
+#define YPPROC_ALL	((u_long)8)
+#define YPPROC_MASTER	((u_long)9)
+#define YPPROC_ORDER	((u_long)10)
+#define YPPROC_MAPLIST	((u_long)11)
+#define	YPPROC_NEWXFR	((u_long)12)
+
+/* Return status values */
+
+#define YP_TRUE	 	((long)1)	/* General purpose success code */
+#define YP_NOMORE 	((long)2)	/* No more entries in map */
+#define YP_FALSE 	((long)0)	/* General purpose failure code */
+#define YP_NOMAP 	((long)-1)	/* No such map in domain */
+#define YP_NODOM 	((long)-2)	/* Domain not supported */
+#define YP_NOKEY 	((long)-3)	/* No such key in map */
+#define YP_BADOP 	((long)-4)	/* Invalid operation */
+#define YP_BADDB 	((long)-5)	/* Server data base is bad */
+#define YP_YPERR 	((long)-6)	/* NIS server error */
+#define YP_BADARGS 	((long)-7)	/* Request arguments bad */
+#define YP_VERS		((long)-8)	/* NIS server version mismatch - server
+					 *   can't supply requested service. */
+/*
+ *		Protocol between clients and NIS binder servers
+ */
+
+/*
+ * The following procedures are supported by the protocol:
+ *
+ * YPBINDPROC_NULL() returns ()
+ * 	takes nothing, returns nothing
+ *
+ * YPBINDPROC_DOMAIN takes (char *) returns (struct ypbind_resp)
+ *
+ * YPBINDPROC_SETDOM takes (struct ypbind_setdom) returns nothing
+ */
+ 
+/* Program and version symbols, magic numbers */
+
+#define YPBINDPROG		((u_long)100007)
+#define YPBINDVERS		((u_long)2)
+#define YPBINDVERS_ORIG		((u_long)1)
+
+/* Procedure symbols */
+
+#define YPBINDPROC_NULL		((u_long)0)
+#define YPBINDPROC_DOMAIN	((u_long)1)
+#define YPBINDPROC_SETDOM	((u_long)2)
+/*
+ * Response structure and overall result status codes.  Success and failure
+ * represent two separate response message types.
+ */
+
+enum ypbind_resptype {YPBIND_SUCC_VAL = 1, YPBIND_FAIL_VAL = 2};
+
+struct ypbind_binding {
+  struct in_addr ypbind_binding_addr;	        /* In network order */
+  unsigned short int ypbind_binding_port;	/* In network order */
+};
+
+struct ypbind_resp {
+  enum ypbind_resptype ypbind_status;
+  union {
+    unsigned long ypbind_error;
+    struct ypbind_binding ypbind_bindinfo;
+  } ypbind_respbody;
+};
+
+
+/* Detailed failure reason codes for response field ypbind_error*/
+
+#define YPBIND_ERR_ERR 1		/* Internal error */
+#define YPBIND_ERR_NOSERV 2		/* No bound server for passed domain */
+#define YPBIND_ERR_RESC 3		/* System resource allocation failure */
+
+/*
+ * Request data structure for ypbind "Set domain" procedure.
+ */
+struct ypbind_setdom {
+  char ypsetdom_domain[YPMAXDOMAIN + 1];
+  struct ypbind_binding ypsetdom_binding;
+  unsigned short ypsetdom_vers;
+};
+#define ypsetdom_addr ypsetdom_binding.ypbind_binding_addr
+#define ypsetdom_port ypsetdom_binding.ypbind_binding_port
+
+/*
+ *		Protocol between clients (ypxfr, only) and yppush
+ *		yppush speaks a protocol in the transient range, which
+ *		is supplied to ypxfr as a command-line parameter when it
+ *		is activated by ypserv.
+ */
+#define YPPUSHVERS		((u_long) 1)
+#define YPPUSHVERS_ORIG		((u_long)1)
+
+/* Procedure symbols */
+
+#define YPPUSHPROC_NULL		((u_long)0)
+#define YPPUSHPROC_XFRRESP	((u_long)1)
+
+struct yppushresp_xfr {
+  unsigned long transid;
+  unsigned long status;
+};
+
+/* Status values for yppushresp_xfr.status */
+
+#define YPPUSH_SUCC	((long)1)	/* Success */
+#define YPPUSH_AGE	((long)2)	/* Master's version not newer */
+#define YPPUSH_NOMAP 	((long)-1)	/* Can't find server for map */
+#define YPPUSH_NODOM 	((long)-2)	/* Domain not supported */
+#define YPPUSH_RSRC 	((long)-3)	/* Local resouce alloc failure */
+#define YPPUSH_RPC 	((long)-4)	/* RPC failure talking to server */
+#define YPPUSH_MADDR	((long)-5)	/* Can't get master address */
+#define YPPUSH_YPERR 	((long)-6)	/* NIS server/map db error */
+#define YPPUSH_BADARGS 	((long)-7)	/* Request arguments bad */
+#define YPPUSH_DBM	((long)-8)	/* Local dbm operation failed */
+#define YPPUSH_FILE	((long)-9)	/* Local file I/O operation failed */
+#define YPPUSH_SKEW	((long)-10)	/* Map version skew during transfer */
+#define YPPUSH_CLEAR	((long)-11)	/* Can't send "Clear" req to local
+					 *   ypserv */
+#define YPPUSH_FORCE	((long)-12)	/* No local order number in map -
+					 *   use -f flag. */
+#define YPPUSH_XFRERR	((long)-13)	/* ypxfr error */
+#define YPPUSH_REFUSED	((long)-14)	/* Transfer request refused by ypserv */
+#define	YPPUSH_NOALIAS	((long)-15)	/* Alias not found for map or domain */
+
+struct ypresp_all {
+  bool_t more;
+  union {
+    struct ypresp_key_val val;
+  } ypresp_all_u;
+};
+
+__BEGIN_DECLS
+
+extern bool_t xdr_datum __P ((XDR *__xdrs, datum * __objp));
+extern bool_t xdr_ypdomain_wrap_string __P ((XDR *__xdrs, char ** __objp));
+extern bool_t xdr_ypmap_wrap_string __P ((XDR *__xdrs, char ** __objp));
+extern bool_t xdr_ypreq_key __P ((XDR *__xdrs, struct ypreq_key * __objp));
+extern bool_t xdr_ypreq_nokey __P ((XDR *__xdrs, struct ypreq_nokey * __objp));
+extern bool_t xdr_ypreq_xfr __P ((XDR *__xdrs, struct ypreq_xfr * __objp));
+extern bool_t xdr_ypreq_newxfr __P ((XDR *__xdrs, struct ypreq_newxfr * __objp));
+extern bool_t xdr_ypresp_val __P ((XDR *__xdrs, struct ypresp_val * __objp));
+extern bool_t xdr_ypresp_key_val __P ((XDR *__xdrs, struct ypresp_key_val * __objp));
+extern bool_t xdr_ypbind_resp __P ((XDR *__xdrs, struct ypbind_resp * __objp));
+extern bool_t xdr_ypbind_setdom __P ((XDR *__xdrs, struct ypbind_setdom * __objp));
+extern bool_t xdr_ypmap_parms __P ((XDR *__xdrs, struct ypmap_parms * __objp));
+extern bool_t xdr_ypowner_wrap_string __P ((XDR *__xdrs, char ** __objp));
+extern bool_t xdr_yppushresp_xfr __P ((XDR *__xdrs, struct yppushresp_xfr * __objp));
+extern bool_t xdr_ypresp_order __P ((XDR *__xdrs, struct ypresp_order  * __objp));
+extern bool_t xdr_ypresp_master __P ((XDR *__xdrs, struct ypresp_master * __objp));
+extern bool_t xdr_ypall __P ((XDR *__xdrs, struct ypall_callback * __objp));
+extern bool_t xdr_ypresp_maplist __P ((XDR *__xdrs, struct ypresp_maplist * __objp));
+
+extern bool_t xdr_domainname_ypbind __P ((XDR *__xdrs, char * __objp));
+extern bool_t xdr_ypbind_binding __P ((XDR *__xdrs, struct ypbind_binding * __objp));
+extern bool_t xdr_ypbind_resptype __P ((XDR *__xdrs, enum ypbind_resptype * __objp));
+extern bool_t xdr_ypstat __P ((XDR *__xdrs, enum ypbind_resptype * __objp));
+extern bool_t xdr_ypresp_all __P ((XDR *__xdrs, struct ypresp_all  * __objp));
+extern bool_t xdr_ypresp_all_seq __P ((XDR *__xdrs, u_long * __objp));
+extern bool_t xdr_ypmaplist_str __P ((XDR *__xdrs, char * __objp));
+extern bool_t xdr_ypmaplist __P ((XDR *__xdrs, struct ypmaplist * __objp));
+
+__END_DECLS
+
+#endif	/* _RPCSVC_YP_PROT_H */
diff --git a/nis/rpcsvc/ypclnt.h b/nis/rpcsvc/ypclnt.h
new file mode 100644
index 0000000000..b61a498417
--- /dev/null
+++ b/nis/rpcsvc/ypclnt.h
@@ -0,0 +1,88 @@
+/*
+** Copyright (c) 1996 Thorsten Kukuk, Germany
+**
+** This 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.
+** 
+** This 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 this library; if not, write to the Free
+** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Author: Thorsten Kukuk <kukuk@vt.uni-paderborn.de>
+**
+*/
+
+#ifndef	__RPCSVC_YPCLNT_H__
+#define	__RPCSVC_YPCLNT_H__
+
+#include <features.h>
+
+/* some defines */
+#define YPERR_SUCCESS 0                 /* There is no error */
+#define	YPERR_BADARGS 1			/* Args to function are bad */
+#define	YPERR_RPC 2			/* RPC failure */
+#define	YPERR_DOMAIN 3			/* Can't bind to a server with this domain */
+#define	YPERR_MAP 4			/* No such map in server's domain */
+#define	YPERR_KEY 5			/* No such key in map */
+#define	YPERR_YPERR 6			/* Internal yp server or client error */
+#define	YPERR_RESRC 7			/* Local resource allocation failure */
+#define	YPERR_NOMORE 8			/* No more records in map database */
+#define	YPERR_PMAP 9			/* Can't communicate with portmapper */
+#define	YPERR_YPBIND 10			/* Can't communicate with ypbind */
+#define	YPERR_YPSERV 11			/* Can't communicate with ypserv */
+#define	YPERR_NODOM 12			/* Local domain name not set */
+#define	YPERR_BADDB 13			/* yp data base is bad */
+#define	YPERR_VERS 14			/* YP version mismatch */
+#define	YPERR_ACCESS 15			/* Access violation */
+#define	YPERR_BUSY 16			/* Database is busy */
+
+/* Types of update operations */
+#define	YPOP_CHANGE 1			/* change, do not add */
+#define	YPOP_INSERT 2			/* add, do not change */
+#define	YPOP_DELETE 3			/* delete this entry */
+#define	YPOP_STORE  4			/* add, or change */
+
+__BEGIN_DECLS
+
+/* struct ypall_callback * is the arg which must be passed to yp_all */
+struct ypall_callback {
+	int (*foreach)();
+	char *data;
+};
+
+/* External NIS client function references. */
+extern int yp_bind __P ((__const char *));
+extern void yp_unbind __P ((__const char *));
+extern int yp_get_default_domain __P ((char **));
+extern int yp_match __P ((__const char *, __const char *, __const char *, 
+			  __const int, char **, int *));
+extern int yp_first __P ((__const char *, __const char *, char **, 
+			  int *, char **, int *));
+extern int yp_next __P ((__const char *, __const char *, __const char *, 
+			 __const int, char **, int *, char **, int *));
+extern int yp_master __P ((__const char *, __const char *, char **));
+extern int yp_order __P ((__const char *, __const char *, unsigned int *));
+extern int yp_all __P ((__const char *, __const char *, 
+			__const struct ypall_callback *));
+extern __const char *yperr_string __P ((__const int));
+extern __const char *ypbinderr_string __P ((__const int));
+extern int ypprot_err __P ((__const int));
+extern int yp_update __P ((char *, char *, unsigned,  char *,
+			   int, char *, int));
+#if 0
+extern int yp_maplist __P ((__const char *, struct ypmaplist **));
+#endif
+
+/* Exist only under BSD and Linux systems */
+extern int __yp_check __P ((char **)); 
+
+__END_DECLS
+
+#endif	/* __RPCSVC_YPCLNT_H__ */
diff --git a/nis/rpcsvc/ypupd.h b/nis/rpcsvc/ypupd.h
new file mode 100644
index 0000000000..dace7824d4
--- /dev/null
+++ b/nis/rpcsvc/ypupd.h
@@ -0,0 +1,88 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*
+ * Copyright (c) 1986, 1990 by Sun Microsystems, Inc.
+ */
+/* from @(#)ypupdate_prot.x	1.3 91/03/11 TIRPC 1.0 */
+
+#ifndef __RPCSVC_YPUPD_H__
+#define __RPCSVC_YPUPD_H__
+
+#include <features.h>
+
+#include <rpc/rpc.h>
+
+#define MAXMAPNAMELEN 255
+#define MAXYPDATALEN 1023
+#define MAXERRMSGLEN 255
+
+__BEGIN_DECLS
+
+typedef struct {
+	u_int yp_buf_len;
+	char *yp_buf_val;
+} yp_buf;
+
+extern  bool_t xdr_yp_buf __P ((XDR *, yp_buf*));
+
+struct ypupdate_args {
+	char *mapname;
+	yp_buf key;
+	yp_buf datum;
+};
+typedef struct ypupdate_args ypupdate_args;
+
+extern  bool_t xdr_ypupdate_args __P ((XDR *, ypupdate_args*));
+
+struct ypdelete_args {
+	char *mapname;
+	yp_buf key;
+};
+typedef struct ypdelete_args ypdelete_args;
+
+extern  bool_t xdr_ypdelete_args __P ((XDR *, ypdelete_args*));
+
+#define YPU_PROG ((u_long)100028)
+#define YPU_VERS ((u_long)1)
+
+#define YPU_CHANGE ((u_long)1)
+extern  u_int * ypu_change_1 __P ((ypupdate_args *, CLIENT *));
+extern  u_int * ypu_change_1_svc __P((ypupdate_args *, struct svc_req *));
+#define YPU_INSERT ((u_long)2)
+extern  u_int * ypu_insert_1 __P ((ypupdate_args *, CLIENT *));
+extern  u_int * ypu_insert_1_svc __P ((ypupdate_args *, struct svc_req *));
+#define YPU_DELETE ((u_long)3)
+extern  u_int * ypu_delete_1 __P ((ypdelete_args *, CLIENT *));
+extern  u_int * ypu_delete_1_svc __P ((ypdelete_args *, struct svc_req *));
+#define YPU_STORE ((u_long)4)
+extern  u_int * ypu_store_1 __P ((ypupdate_args *, CLIENT *));
+extern  u_int * ypu_store_1_svc __P ((ypupdate_args *, struct svc_req *));
+
+#endif /* !__RPCSVC_YPUPD_H__ */
diff --git a/nis/yp_xdr.c b/nis/yp_xdr.c
new file mode 100644
index 0000000000..e6477be778
--- /dev/null
+++ b/nis/yp_xdr.c
@@ -0,0 +1,342 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+#include <rpcsvc/yp.h>
+
+bool_t
+xdr_ypstat (XDR *xdrs, ypstat *objp)
+{
+  if (!xdr_enum(xdrs, (enum_t *)objp))
+    return (FALSE);
+  return (TRUE);
+}
+
+bool_t
+xdr_ypxfrstat(XDR *xdrs, ypxfrstat *objp)
+{
+  if (!xdr_enum(xdrs, (enum_t *)objp)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_domainname(XDR *xdrs, domainname *objp)
+{
+  if (!xdr_string(xdrs, objp, YPMAXDOMAIN)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_mapname(XDR *xdrs, mapname *objp)
+{
+  if (!xdr_string(xdrs, objp, YPMAXMAP)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_peername(XDR *xdrs, peername *objp)
+{
+  if (!xdr_string(xdrs, objp, YPMAXPEER)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_keydat(XDR *xdrs, keydat *objp)
+{
+  if (!xdr_bytes(xdrs, (char **)&objp->keydat_val, (u_int *)&objp->keydat_len, YPMAXRECORD)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_valdat(XDR *xdrs, valdat *objp)
+{
+  if (!xdr_bytes(xdrs, (char **)&objp->valdat_val, (u_int *)&objp->valdat_len, YPMAXRECORD)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_ypmap_parms(XDR *xdrs, ypmap_parms *objp)
+{
+  if (!xdr_domainname(xdrs, &objp->domain)) {
+    return (FALSE);
+  }
+  if (!xdr_mapname(xdrs, &objp->map)) {
+    return (FALSE);
+  }
+  if (!xdr_u_int(xdrs, &objp->ordernum)) {
+    return (FALSE);
+  }
+  if (!xdr_peername(xdrs, &objp->peer)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_ypreq_key(XDR *xdrs, ypreq_key *objp)
+{
+  if (!xdr_domainname(xdrs, &objp->domain)) {
+    return (FALSE);
+  }
+  if (!xdr_mapname(xdrs, &objp->map)) {
+    return (FALSE);
+  }
+  if (!xdr_keydat(xdrs, &objp->key)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_ypreq_nokey(XDR *xdrs, ypreq_nokey *objp)
+{
+  if (!xdr_domainname(xdrs, &objp->domain)) {
+    return (FALSE);
+  }
+  if (!xdr_mapname(xdrs, &objp->map)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_ypreq_xfr(XDR *xdrs, ypreq_xfr *objp)
+{
+  if (!xdr_ypmap_parms(xdrs, &objp->map_parms)) {
+    return (FALSE);
+  }
+  if (!xdr_u_int(xdrs, &objp->transid)) {
+    return (FALSE);
+  }
+  if (!xdr_u_int(xdrs, &objp->prog)) {
+    return (FALSE);
+  }
+  if (!xdr_u_int(xdrs, &objp->port)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_ypresp_val(XDR *xdrs, ypresp_val *objp)
+{
+  if (!xdr_ypstat(xdrs, &objp->stat)) {
+    return (FALSE);
+  }
+  if (!xdr_valdat(xdrs, &objp->val)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_ypresp_key_val(XDR *xdrs, ypresp_key_val *objp)
+{
+  if (!xdr_ypstat(xdrs, &objp->stat)) {
+    return (FALSE);
+  }
+  if (!xdr_valdat(xdrs, &objp->val)) {
+    return (FALSE);
+  }
+  if (!xdr_keydat(xdrs, &objp->key)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_ypresp_master(XDR *xdrs, ypresp_master *objp)
+{
+  if (!xdr_ypstat(xdrs, &objp->stat)) {
+    return (FALSE);
+  }
+  if (!xdr_peername(xdrs, &objp->peer)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_ypresp_order(XDR *xdrs, ypresp_order *objp)
+{
+  if (!xdr_ypstat(xdrs, &objp->stat)) {
+    return (FALSE);
+  }
+  if (!xdr_u_int(xdrs, &objp->ordernum)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_ypresp_all(XDR *xdrs, ypresp_all *objp)
+{
+  if (!xdr_bool(xdrs, &objp->more)) {
+    return (FALSE);
+  }
+  switch (objp->more) {
+  case TRUE:
+    if (!xdr_ypresp_key_val(xdrs, &objp->ypresp_all_u.val)) {
+      return (FALSE);
+    }
+    break;
+  case FALSE:
+    break;
+  default:
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_ypresp_xfr(XDR *xdrs, ypresp_xfr *objp)
+{
+  if (!xdr_u_int(xdrs, &objp->transid)) {
+    return (FALSE);
+  }
+  if (!xdr_ypxfrstat(xdrs, &objp->xfrstat)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_ypmaplist(XDR *xdrs, ypmaplist *objp)
+{
+  if (!xdr_mapname(xdrs, &objp->map)) {
+    return (FALSE);
+  }
+  if (!xdr_pointer(xdrs, (char **)&objp->next, sizeof(ypmaplist), (xdrproc_t)xdr_ypmaplist)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_ypresp_maplist(XDR *xdrs, ypresp_maplist *objp)
+{
+  if (!xdr_ypstat(xdrs, &objp->stat)) {
+    return (FALSE);
+  }
+  if (!xdr_pointer(xdrs, (char **)&objp->maps, sizeof(ypmaplist), (xdrproc_t)xdr_ypmaplist)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_yppush_status(XDR *xdrs, yppush_status *objp)
+{
+  if (!xdr_enum(xdrs, (enum_t *)objp)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_yppushresp_xfr(XDR *xdrs, yppushresp_xfr *objp)
+{
+  if (!xdr_u_int(xdrs, &objp->transid)) {
+    return (FALSE);
+  }
+  if (!xdr_yppush_status(xdrs, &objp->status)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_ypbind_resptype(XDR *xdrs, ypbind_resptype *objp)
+{
+  if (!xdr_enum(xdrs, (enum_t *)objp)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_ypbind_binding(XDR *xdrs, ypbind_binding *objp)
+{
+  if (!xdr_opaque(xdrs, objp->ypbind_binding_addr, 4)) {
+    return (FALSE);
+  }
+  if (!xdr_opaque(xdrs, objp->ypbind_binding_port, 2)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_ypbind_resp(XDR *xdrs, ypbind_resp *objp)
+{
+  if (!xdr_ypbind_resptype(xdrs, &objp->ypbind_status)) {
+    return (FALSE);
+  }
+  switch (objp->ypbind_status) {
+  case YPBIND_FAIL_VAL:
+    if (!xdr_u_int(xdrs, &objp->ypbind_resp_u.ypbind_error)) {
+      return (FALSE);
+		 }
+    break;
+  case YPBIND_SUCC_VAL:
+    if (!xdr_ypbind_binding(xdrs, &objp->ypbind_resp_u.ypbind_bindinfo)) {
+      return (FALSE);
+    }
+    break;
+  default:
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+bool_t
+xdr_ypbind_setdom(XDR *xdrs, ypbind_setdom *objp)
+{
+  if (!xdr_domainname(xdrs, &objp->ypsetdom_domain)) {
+    return (FALSE);
+  }
+  if (!xdr_ypbind_binding(xdrs, &objp->ypsetdom_binding)) {
+    return (FALSE);
+  }
+  if (!xdr_u_int(xdrs, &objp->ypsetdom_vers)) {
+    return (FALSE);
+  }
+  return (TRUE);
+}
diff --git a/nis/ypclnt.c b/nis/ypclnt.c
new file mode 100644
index 0000000000..3e05cf984c
--- /dev/null
+++ b/nis/ypclnt.c
@@ -0,0 +1,868 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 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 <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/ypupd.h>
+
+struct dom_binding
+  {
+    struct dom_binding *dom_pnext;
+    char dom_domain[YPMAXDOMAIN + 1];
+    struct sockaddr_in dom_server_addr;
+    int dom_socket;
+    CLIENT *dom_client;
+    long int dom_vers;
+  };
+typedef struct dom_binding dom_binding;
+
+static struct timeval TIMEOUT = {25, 0};
+static int const MAXTRIES = 5;
+static char __ypdomainname[MAXHOSTNAMELEN + 1] = "\0";
+__libc_lock_define_initialized (static, ypbindlist_lock)
+static dom_binding *__ypbindlist = NULL;
+
+static int
+__yp_bind (char *domain, dom_binding ** ypdb)
+{
+  struct sockaddr_in clnt_saddr;
+  struct ypbind_resp ypbr;
+  dom_binding *ysd;
+  int clnt_sock;
+  CLIENT *client;
+  int is_new = 0;
+  int try;
+
+  if (ypdb != NULL)
+    *ypdb = NULL;
+
+  if ((domain == NULL) || (strlen (domain) == 0))
+    return YPERR_BADARGS;
+
+  ysd = __ypbindlist;
+  while (ysd != NULL)
+    {
+      if (strcmp (domain, ysd->dom_domain) == 0)
+        break;
+      ysd = ysd->dom_pnext;
+    }
+
+  if (ysd == NULL)
+    {
+      is_new = 1;
+      ysd = (dom_binding *) malloc (sizeof *ysd);
+      memset (ysd, '\0', sizeof *ysd);
+      ysd->dom_socket = -1;
+      ysd->dom_vers = -1;
+    }
+
+  try = 0;
+
+  do
+    {
+      try++;
+      if (try > MAXTRIES)
+        {
+          if (is_new)
+            free (ysd);
+          return YPERR_YPBIND;
+        }
+
+      if (ysd->dom_vers == -1)
+        {
+          if(ysd->dom_client)
+            {
+              clnt_destroy(ysd->dom_client);
+              ysd->dom_client = NULL;
+              ysd->dom_socket = -1;
+            }
+          memset (&clnt_saddr, '\0', sizeof clnt_saddr);
+          clnt_saddr.sin_family = AF_INET;
+          clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+          clnt_sock = RPC_ANYSOCK;
+          client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS,
+                                   &clnt_sock, 0, 0);
+          if (client == NULL)
+            {
+              if (is_new)
+                free (ysd);
+              return YPERR_YPBIND;
+            }
+          /*
+          ** Check the port number -- should be < IPPORT_RESERVED.
+          ** If not, it's possible someone has registered a bogus
+          ** ypbind with the portmapper and is trying to trick us.
+          */
+          if (ntohs(clnt_saddr.sin_port) >= IPPORT_RESERVED)
+            {
+              clnt_destroy(client);
+              if (is_new)
+                free(ysd);
+              return(YPERR_YPBIND);
+            }
+
+          if (clnt_call (client, YPBINDPROC_DOMAIN,
+                         (xdrproc_t) xdr_domainname, &domain,
+                         (xdrproc_t) xdr_ypbind_resp,
+                         &ypbr, TIMEOUT) != RPC_SUCCESS)
+            {
+              clnt_destroy (client);
+              if (is_new)
+                free (ysd);
+              return YPERR_YPBIND;
+            }
+
+          clnt_destroy (client);
+          if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
+            {
+              switch (ypbr.ypbind_resp_u.ypbind_error)
+                {
+                case YPBIND_ERR_ERR:
+                  fputs (_("YPBINDPROC_DOMAIN: Internal error\n"), stderr);
+                  break;
+                case YPBIND_ERR_NOSERV:
+                  fprintf (stderr,
+                           _("YPBINDPROC_DOMAIN: No server for domain %s\n"),
+                           domain);
+                  break;
+                case YPBIND_ERR_RESC:
+                  fputs (_("YPBINDPROC_DOMAIN: Resource allocation failure\n"),
+                         stderr);
+                  break;
+                default:
+                  fputs (_("YPBINDPROC_DOMAIN: Unknown error\n"), stderr);
+                  break;
+                }
+              if (is_new)
+                free (ysd);
+              return YPERR_DOMAIN;
+            }
+          memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr);
+          ysd->dom_server_addr.sin_family = AF_INET;
+          memcpy (&ysd->dom_server_addr.sin_port,
+                  ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
+                  sizeof (ysd->dom_server_addr.sin_port));
+          memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
+                  ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
+                  sizeof (ysd->dom_server_addr.sin_addr.s_addr));
+          ysd->dom_vers = YPVERS;
+          strcpy (ysd->dom_domain, domain);
+        }
+
+      if (ysd->dom_client)
+        clnt_destroy (ysd->dom_client);
+      ysd->dom_socket = RPC_ANYSOCK;
+      ysd->dom_client = clntudp_create (&ysd->dom_server_addr, YPPROG, YPVERS,
+                                        TIMEOUT, &ysd->dom_socket);
+      if (ysd->dom_client == NULL)
+        ysd->dom_vers = -1;
+
+    }
+  while (ysd->dom_client == NULL);
+
+  /* If the program exists, close the socket */
+  if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1)
+    perror (_("fcntl: F_SETFD"));
+
+  if (is_new)
+    {
+      ysd->dom_pnext = __ypbindlist;
+      __ypbindlist = ysd;
+    }
+
+  if (NULL != ypdb)
+    *ypdb = ysd;
+
+  return YPERR_SUCCESS;
+}
+
+static void
+__yp_unbind (dom_binding *ydb)
+{
+  clnt_destroy (ydb->dom_client);
+  ydb->dom_client = NULL;
+  ydb->dom_socket = -1;
+}
+
+static int
+do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
+	   caddr_t req, xdrproc_t xres, caddr_t resp)
+{
+  dom_binding *ydb = NULL;
+  int try, result;
+
+  try = 0;
+  result = YPERR_YPERR;
+
+  while (try < MAXTRIES && result != RPC_SUCCESS)
+    {
+      __libc_lock_lock (ypbindlist_lock);
+
+      if (__yp_bind (domain, &ydb) != 0)
+	{
+	  __libc_lock_unlock (ypbindlist_lock);
+	  return YPERR_DOMAIN;
+	}
+
+      result = clnt_call (ydb->dom_client, prog,
+			  xargs, req, xres, resp, TIMEOUT);
+
+      if (result != RPC_SUCCESS)
+	{
+	  clnt_perror (ydb->dom_client, "do_ypcall: clnt_call");
+	  ydb->dom_vers = -1;
+	  __yp_unbind (ydb);
+	  result = YPERR_RPC;
+	}
+
+      __libc_lock_unlock (ypbindlist_lock);
+
+      try++;
+    }
+
+  return result;
+}
+
+int
+yp_bind (const char *indomain)
+{
+  int status;
+
+  __libc_lock_lock (ypbindlist_lock);
+
+  status = __yp_bind (indomain, NULL);
+
+  __libc_lock_unlock (ypbindlist_lock);
+
+  return status;
+}
+
+void
+yp_unbind (const char *indomain)
+{
+  dom_binding *ydbptr, *ydbptr2;
+
+  __libc_lock_lock (ypbindlist_lock);
+
+  ydbptr2 = NULL;
+  ydbptr = __ypbindlist;
+  while (ydbptr != NULL)
+    {
+      if (strcmp (ydbptr->dom_domain, indomain) == 0)
+	{
+	  dom_binding *work;
+
+	  work = ydbptr;
+	  if (ydbptr2 == NULL)
+	    __ypbindlist = __ypbindlist->dom_pnext;
+	  else
+	    ydbptr2 = ydbptr->dom_pnext;
+	  __yp_unbind (work);
+	  free (work);
+	  break;
+	}
+      ydbptr2 = ydbptr;
+      ydbptr = ydbptr->dom_pnext;
+    }
+
+  __libc_lock_unlock (ypbindlist_lock);
+
+  return;
+}
+
+__libc_lock_define_initialized (static, domainname_lock)
+
+int
+yp_get_default_domain (char **outdomain)
+{
+  int result = YPERR_SUCCESS;;
+  *outdomain = NULL;
+
+  __libc_lock_lock (domainname_lock);
+
+  if (__ypdomainname[0] == '\0')
+    {
+      if (getdomainname (__ypdomainname, MAXHOSTNAMELEN))
+	result = YPERR_NODOM;
+      else
+	*outdomain = __ypdomainname;
+    }
+  else
+    *outdomain = __ypdomainname;
+
+  __libc_lock_unlock (domainname_lock);
+
+  return result;
+}
+
+int
+__yp_check (char **domain)
+{
+  char *unused;
+
+  if (__ypdomainname[0] == '\0')
+    if (yp_get_default_domain (&unused))
+      return 0;
+    else if (strcmp (__ypdomainname, "(none)") == 0)
+      return 0;
+
+  if (domain)
+    *domain = __ypdomainname;
+
+  if (yp_bind (__ypdomainname) == 0)
+    return 1;
+  return 0;
+}
+
+int
+yp_match (const char *indomain, const char *inmap, const char *inkey,
+	  const int inkeylen, char **outval, int *outvallen)
+{
+  ypreq_key req;
+  ypresp_val resp;
+  int result;
+
+  if (indomain == NULL || indomain[0] == '\0' ||
+      inmap == NULL || inmap[0] == '\0' ||
+      inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
+    return YPERR_BADARGS;
+
+  req.domain = indomain;
+  req.map = inmap;
+  req.key.keydat_val = inkey;
+  req.key.keydat_len = inkeylen;
+
+  *outval = NULL;
+  *outvallen = 0;
+  memset (&resp, '\0', sizeof (resp));
+
+  result = do_ypcall (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
+		      (caddr_t) & req, (xdrproc_t) xdr_ypresp_val,
+		      (caddr_t) & resp);
+
+  if (result != RPC_SUCCESS)
+    return result;
+  if (resp.stat != YP_TRUE)
+    return ypprot_err (resp.stat);
+
+  *outvallen = resp.val.valdat_len;
+  *outval = malloc (*outvallen + 1);
+  memcpy (*outval, resp.val.valdat_val, *outvallen);
+  (*outval)[*outvallen] = '\0';
+
+  xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
+
+  return YPERR_SUCCESS;
+}
+
+int
+yp_first (const char *indomain, const char *inmap, char **outkey,
+	  int *outkeylen, char **outval, int *outvallen)
+{
+  ypreq_nokey req;
+  ypresp_key_val resp;
+  int result;
+
+  if (indomain == NULL || indomain[0] == '\0' ||
+      inmap == NULL || inmap[0] == '\0')
+    return YPERR_BADARGS;
+
+  req.domain = indomain;
+  req.map = inmap;
+
+  *outkey = *outval = NULL;
+  *outkeylen = *outvallen = 0;
+  memset (&resp, '\0', sizeof (resp));
+
+  result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
+		      (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
+		      (caddr_t) & resp);
+
+  if (result != RPC_SUCCESS)
+    return result;
+  if (resp.stat != YP_TRUE)
+    return ypprot_err (resp.stat);
+
+  *outkeylen = resp.key.keydat_len;
+  *outkey = malloc (*outkeylen + 1);
+  memcpy (*outkey, resp.key.keydat_val, *outkeylen);
+  (*outkey)[*outkeylen] = '\0';
+  *outvallen = resp.val.valdat_len;
+  *outval = malloc (*outvallen + 1);
+  memcpy (*outval, resp.val.valdat_val, *outvallen);
+  (*outval)[*outvallen] = '\0';
+
+  xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
+
+  return YPERR_SUCCESS;
+}
+
+int
+yp_next (const char *indomain, const char *inmap, const char *inkey,
+	 const int inkeylen, char **outkey, int *outkeylen, char **outval,
+	 int *outvallen)
+{
+  ypreq_key req;
+  ypresp_key_val resp;
+  int result;
+
+  if (indomain == NULL || indomain[0] == '\0' ||
+      inmap == NULL || inmap[0] == '\0' ||
+      inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
+    return YPERR_BADARGS;
+
+  req.domain = indomain;
+  req.map = inmap;
+  req.key.keydat_val = inkey;
+  req.key.keydat_len = inkeylen;
+
+  *outkey = *outval = NULL;
+  *outkeylen = *outvallen = 0;
+  memset (&resp, '\0', sizeof (resp));
+
+  result = do_ypcall (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
+		      (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
+		      (caddr_t) & resp);
+
+  if (result != RPC_SUCCESS)
+    return result;
+  if (resp.stat != YP_TRUE)
+    return ypprot_err (resp.stat);
+
+  *outkeylen = resp.key.keydat_len;
+  *outkey = malloc (*outkeylen + 1);
+  memcpy (*outkey, resp.key.keydat_val, *outkeylen);
+  (*outkey)[*outkeylen] = '\0';
+  *outvallen = resp.val.valdat_len;
+  *outval = malloc (*outvallen + 1);
+  memcpy (*outval, resp.val.valdat_val, *outvallen);
+  (*outval)[*outvallen] = '\0';
+
+  xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
+
+  return YPERR_SUCCESS;
+}
+
+int
+yp_master (const char *indomain, const char *inmap, char **outname)
+{
+  ypreq_nokey req;
+  ypresp_master resp;
+  int result;
+
+  if (indomain == NULL || indomain[0] == '\0' ||
+      inmap == NULL || inmap[0] == '\0')
+    return YPERR_BADARGS;
+
+  req.domain = indomain;
+  req.map = inmap;
+
+  memset (&resp, '\0', sizeof (ypresp_master));
+
+  result = do_ypcall (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
+	  (caddr_t) & req, (xdrproc_t) xdr_ypresp_master, (caddr_t) & resp);
+
+  if (result != RPC_SUCCESS)
+    return result;
+  if (resp.stat != YP_TRUE)
+    return ypprot_err (resp.stat);
+
+  *outname = strdup (resp.peer);
+  xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
+
+  return YPERR_SUCCESS;
+}
+
+int
+yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
+{
+  struct ypreq_nokey req;
+  struct ypresp_order resp;
+  int result;
+
+  if (indomain == NULL || indomain[0] == '\0' ||
+      inmap == NULL || inmap == '\0')
+    return YPERR_BADARGS;
+
+  req.domain = indomain;
+  req.map = inmap;
+
+  memset (&resp, '\0', sizeof (resp));
+
+  result = do_ypcall (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
+	   (caddr_t) & req, (xdrproc_t) xdr_ypresp_order, (caddr_t) & resp);
+
+  if (result != RPC_SUCCESS)
+    return result;
+  if (resp.stat != YP_TRUE)
+    return ypprot_err (resp.stat);
+
+  *outorder = resp.ordernum;
+  xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
+
+  return YPERR_SUCCESS;
+}
+
+static void *ypall_data;
+static int (*ypall_foreach) ();
+
+static bool_t
+__xdr_ypresp_all (XDR * xdrs, u_long * objp)
+{
+  while (1)
+    {
+      struct ypresp_all resp;
+
+      memset (&resp, '\0', sizeof (struct ypresp_all));
+      if (!xdr_ypresp_all (xdrs, &resp))
+	{
+	  xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
+	  *objp = YP_YPERR;
+	  return (FALSE);
+	}
+      if (resp.more == 0)
+	{
+	  xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
+	  *objp = YP_NOMORE;
+	  return (FALSE);
+	}
+
+      switch (resp.ypresp_all_u.val.stat)
+	{
+	case YP_TRUE:
+	  {
+	    char key[resp.ypresp_all_u.val.key.keydat_len + 1];
+	    char val[resp.ypresp_all_u.val.val.valdat_len + 1];
+	    int keylen = resp.ypresp_all_u.val.key.keydat_len;
+	    int vallen = resp.ypresp_all_u.val.val.valdat_len;
+
+	    *objp = YP_TRUE;
+	    memcpy (key, resp.ypresp_all_u.val.key.keydat_val, keylen);
+	    key[keylen] = '\0';
+	    memcpy (val, resp.ypresp_all_u.val.val.valdat_val, vallen);
+	    val[vallen] = '\0';
+	    xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
+	    if ((*ypall_foreach) (*objp, key, keylen,
+				  val, vallen, ypall_data))
+	      return TRUE;
+	  }
+	  break;
+	case YP_NOMORE:
+	  *objp = YP_NOMORE;
+	  xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
+	  return TRUE;
+	  break;
+	default:
+	  *objp = resp.ypresp_all_u.val.stat;
+	  xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
+	  return TRUE;
+	}
+    }
+}
+
+int
+yp_all (const char *indomain, const char *inmap,
+	const struct ypall_callback *incallback)
+{
+  struct ypreq_nokey req;
+  dom_binding *ydb;
+  int try, result;
+  struct sockaddr_in clnt_sin;
+  CLIENT *clnt;
+  unsigned long status;
+  int clnt_sock;
+
+  if (indomain == NULL || indomain[0] == '\0' ||
+      inmap == NULL || inmap == '\0')
+    return YPERR_BADARGS;
+
+  try = 0;
+  result = YPERR_YPERR;
+
+  while (try < MAXTRIES && result != RPC_SUCCESS)
+    {
+      __libc_lock_lock (ypbindlist_lock);
+
+      if (__yp_bind (indomain, &ydb) != 0)
+	{
+	  __libc_lock_unlock (ypbindlist_lock);
+	  return YPERR_DOMAIN;
+	}
+
+      /* YPPROC_ALL get its own TCP channel to ypserv */
+      clnt_sock = RPC_ANYSOCK;
+      clnt_sin = ydb->dom_server_addr;
+      clnt_sin.sin_port = 0;
+      clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
+      if (clnt == NULL)
+	{
+	  puts ("yp_all: clnttcp_create failed");
+	  __libc_lock_unlock (ypbindlist_lock);
+	  return YPERR_PMAP;
+	}
+      req.domain = indomain;
+      req.map = inmap;
+
+      ypall_foreach = incallback->foreach;
+      ypall_data = (void *) incallback->data;
+
+      result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey, &req,
+			  (xdrproc_t) __xdr_ypresp_all, &status, TIMEOUT);
+
+      if (result != RPC_SUCCESS)
+	{
+	  clnt_perror (ydb->dom_client, "yp_all: clnt_call");
+	  clnt_destroy (clnt);
+	  __yp_unbind (ydb);
+	  result = YPERR_RPC;
+	}
+      else
+	{
+	  clnt_destroy (clnt);
+	  result = YPERR_SUCCESS;
+	}
+
+      __libc_lock_unlock (ypbindlist_lock);
+
+      if (status != YP_NOMORE)
+	return ypprot_err (status);
+      try++;
+    }
+
+  return result;
+}
+
+int
+yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
+{
+  struct ypresp_maplist resp;
+  int result;
+
+  if (indomain == NULL || indomain[0] == '\0')
+    return YPERR_BADARGS;
+
+  memset (&resp, '\0', sizeof (resp));
+
+  result = do_ypcall (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
+    (caddr_t) & indomain, (xdrproc_t) xdr_ypresp_maplist, (caddr_t) & resp);
+
+  if (result != RPC_SUCCESS)
+    return result;
+  if (resp.stat != YP_TRUE)
+    return ypprot_err (resp.stat);
+
+  *outmaplist = resp.maps;
+  /* We give the list not free, this will be done by ypserv
+     xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
+
+  return YPERR_SUCCESS;
+}
+
+const char *
+yperr_string (const int error)
+{
+  switch (error)
+    {
+    case YPERR_SUCCESS:
+      return _("Success");
+    case YPERR_BADARGS:
+      return _("Request arguments bad");
+    case YPERR_RPC:
+      return _("RPC failure on NIS operation");
+    case YPERR_DOMAIN:
+      return _("Can't bind to server which serves this domain");
+    case YPERR_MAP:
+      return _("No such map in server's domain");
+    case YPERR_KEY:
+      return _("No such key in map");
+    case YPERR_YPERR:
+      return _("Internal NIS error");
+    case YPERR_RESRC:
+      return _("Local resource allocation failure");
+    case YPERR_NOMORE:
+      return _("No more records in map database");
+    case YPERR_PMAP:
+      return _("Can't communicate with portmapper");
+    case YPERR_YPBIND:
+      return _("Can't communicate with ypbind");
+    case YPERR_YPSERV:
+      return _("Can't communicate with ypserv");
+    case YPERR_NODOM:
+      return _("Local domain name not set");
+    case YPERR_BADDB:
+      return _("NIS map data base is bad");
+    case YPERR_VERS:
+      return _("NIS client/server version mismatch - can't supply service");
+    case YPERR_ACCESS:
+      return _("Permission denied");
+    case YPERR_BUSY:
+      return _("Database is busy");
+    }
+  return _("Unknown NIS error code");
+}
+
+int
+ypprot_err (const int code)
+{
+  switch (code)
+    {
+    case YP_TRUE:
+      return YPERR_SUCCESS;
+    case YP_NOMORE:
+      return YPERR_NOMORE;
+    case YP_FALSE:
+      return YPERR_YPERR;
+    case YP_NOMAP:
+      return YPERR_MAP;
+    case YP_NODOM:
+      return YPERR_DOMAIN;
+    case YP_NOKEY:
+      return YPERR_KEY;
+    case YP_BADOP:
+      return YPERR_YPERR;
+    case YP_BADDB:
+      return YPERR_BADDB;
+    case YP_YPERR:
+      return YPERR_YPERR;
+    case YP_BADARGS:
+      return YPERR_BADARGS;
+    case YP_VERS:
+      return YPERR_VERS;
+    }
+  return YPERR_YPERR;
+}
+
+const char *
+ypbinderr_string (const int error)
+{
+  switch (error)
+    {
+    case 0:
+      return _("Success");
+    case YPBIND_ERR_ERR:
+      return _("Internal ypbind error");
+    case YPBIND_ERR_NOSERV:
+      return _("Domain not bound");
+    case YPBIND_ERR_RESC:
+      return _("System resource allocation failure");
+    default:
+      return _("Unknown ypbind error");
+    }
+}
+
+
+#define WINDOW 60
+
+int
+yp_update (char *domain, char *map, unsigned ypop,
+	   char *key, int keylen, char *data, int datalen)
+{
+#if 0
+  union
+    {
+      ypupdate_args update_args;
+      ypdelete_args delete_args;
+    }
+  args;
+  xdrproc_t xdr_argument;
+  unsigned res = 0;
+  CLIENT *clnt;
+  char *master;
+  struct sockaddr saddr;
+  char servername[MAXNETNAMELEN + 1];
+  int r;
+
+  if (!domain || !map || !key || (ypop != YPOP_DELETE && !data))
+    return YPERR_BADARGS;
+
+  args.update_args.mapname = map;
+  args.update_args.key.yp_buf_len = keylen;
+  args.update_args.key.yp_buf_val = key;
+  args.update_args.datum.yp_buf_len = datalen;
+  args.update_args.datum.yp_buf_val = data;
+
+  if ((r = yp_master (domain, map, &master)) != 0)
+    return r;
+
+  if (!host2netname (servername, master, domain))
+    {
+      fputs (_("yp_update: cannot convert host to netname\n"), stderr);
+      return YPERR_YPERR;
+    }
+
+  if ((clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp")) == NULL)
+    {
+      clnt_pcreateerror ("yp_update: clnt_create");
+      return YPERR_RPC;
+    }
+
+  if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr))
+    {
+      fputs (_("yp_update: cannot get server address\n"), stderr);
+      return YPERR_RPC;
+    }
+
+  switch (ypop)
+    {
+    case YPOP_CHANGE:
+    case YPOP_INSERT:
+    case YPOP_STORE:
+      xdr_argument = (xdrproc_t) xdr_ypupdate_args;
+      break;
+    case YPOP_DELETE:
+      xdr_argument = (xdrproc_t) xdr_ypdelete_args;
+      break;
+    default:
+      return YPERR_BADARGS;
+      break;
+    }
+
+  clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL);
+
+  if (clnt->cl_auth == NULL)
+    clnt->cl_auth = authunix_create_default ();
+
+again:
+  r = clnt_call (clnt, ypop, xdr_argument, &args,
+		 (xdrproc_t) xdr_u_int, &res, TIMEOUT);
+
+  if (r == RPC_AUTHERROR)
+    {
+      if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
+	{
+	  clnt->cl_auth = authunix_create_default ();
+	  goto again;
+	}
+      else
+	return YPERR_ACCESS;
+    }
+  if (r != RPC_SUCCESS)
+    {
+      clnt_perror (clnt, "yp_update: clnt_call");
+      return YPERR_RPC;
+    }
+  return res;
+#else
+  return YPERR_YPERR;
+#endif
+}
diff --git a/nis/ypupdate_xdr.c b/nis/ypupdate_xdr.c
new file mode 100644
index 0000000000..53624337ab
--- /dev/null
+++ b/nis/ypupdate_xdr.c
@@ -0,0 +1,73 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*
+ * Copyright (c) 1986, 1990 by Sun Microsystems, Inc.
+ */
+
+/* from @(#)ypupdate_prot.x     1.3 91/03/11 TIRPC 1.0 */
+
+/*
+ * Compiled from ypupdate_prot.x using rpcgen
+ * This is NOT source code!
+ * DO NOT EDIT THIS FILE!
+ */
+
+
+#include <rpcsvc/ypupd.h>
+
+bool_t 
+xdr_yp_buf (XDR * xdrs, yp_buf * objp)
+{
+  if (!xdr_bytes (xdrs, (char **) &objp->yp_buf_val, (u_int *) & objp->yp_buf_len, MAXYPDATALEN))
+    return (FALSE);
+  return (TRUE);
+}
+
+bool_t 
+xdr_ypupdate_args (XDR * xdrs, ypupdate_args * objp)
+{
+  if (!xdr_string (xdrs, &objp->mapname, MAXMAPNAMELEN))
+    return (FALSE);
+  if (!xdr_yp_buf (xdrs, &objp->key))
+    return (FALSE);
+  if (!xdr_yp_buf (xdrs, &objp->datum))
+    return (FALSE);
+  return (TRUE);
+}
+
+bool_t 
+xdr_ypdelete_args (XDR * xdrs, ypdelete_args * objp)
+{
+  if (!xdr_string (xdrs, &objp->mapname, MAXMAPNAMELEN))
+    return (FALSE);
+  if (!xdr_yp_buf (xdrs, &objp->key))
+    return (FALSE);
+  return (TRUE);
+}
diff --git a/shadow/lckpwdf.c b/shadow/lckpwdf.c
index 707c00965d..d21a744336 100644
--- a/shadow/lckpwdf.c
+++ b/shadow/lckpwdf.c
@@ -1,22 +1,22 @@
-/* lckpwdf - handle locking of password file.
-Copyright (C) 1996 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.  */
+/* Handle locking of password file.
+   Copyright (C) 1996 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 <fcntl.h>
 #include <libc-lock.h>
@@ -28,7 +28,7 @@ Boston, MA 02111-1307, USA.  */
 
 
 /* Name of the lock file.  */
-#define PWD_LOCKFILE "/etc/lock.pwd"
+#define PWD_LOCKFILE "/etc/.pwd.lock"
 
 /* How long to wait for getting the lock before returning with an
    error.  */
diff --git a/shlib-versions b/shlib-versions
index f2dbb79635..243f206fb9 100644
--- a/shlib-versions
+++ b/shlib-versions
@@ -49,9 +49,17 @@ i.86-.*-linux.*		ld=ld-linux.so.2
 .*-.*-.*		libnss_files=1
 .*-.*-.*		libnss_dns=1
 .*-.*-.*		libnss_db=1
+.*-.*-.*		libnss_compat=1
+.*-.*-.*		libnss_nis=1
+
+# Version for libnsl with YP functions.
+.*-.*-.*		libnsl=1
 
 # We use libdb.so.2 for the interface in version 1.85 of the Berkeley DB code.
 .*-.*-.*		libdb=2
 
 # This defines the shared library version numbers we will install.
 .*-.*-.*		libcrypt=1
+
+# The gross patch for programs assuming broken locale implemenations.
+.*-.*-.*		libBrokenLocale=1
diff --git a/stdlib/strtod.c b/stdlib/strtod.c
index 859e077b66..60a3de5228 100644
--- a/stdlib/strtod.c
+++ b/stdlib/strtod.c
@@ -406,7 +406,7 @@ INTERNAL (STRTOF) (nptr, endptr, group)
   if (mbtowc ((wchar_t *) &decimal, _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT),
 	      strlen (_NL_CURRENT (LC_NUMERIC, DECIMAL_POINT))) <= 0)
     decimal = (wint_t) *_NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
-
+  assert (decimal != L'\0');
 
   /* Prepare number representation.  */
   exponent = 0;
diff --git a/stdlib/tst-strtod.c b/stdlib/tst-strtod.c
index 681bace013..a76529c4dd 100644
--- a/stdlib/tst-strtod.c
+++ b/stdlib/tst-strtod.c
@@ -37,6 +37,7 @@ static const struct ltest tests[] =
     { ".125", .125, '\0', 0 },
     { "1e20", 1e20, '\0', 0 },
     { "0e-19", 0, '\0', 0 },
+    { "4\00012", 4.0, '\0', 0 },
     { NULL, 0, '\0', 0 }
   };
 
diff --git a/sysdeps/alpha/memchr.S b/sysdeps/alpha/memchr.S
index ecd26e8d6f..7456735aad 100644
--- a/sysdeps/alpha/memchr.S
+++ b/sysdeps/alpha/memchr.S
@@ -1,22 +1,21 @@
 /* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
    Contributed by David Mosberger (davidm@cs.arizona.edu).
 
-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 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.
 
-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., 675 Mass Ave,
-Cambridge, MA 02139, USA.  */
+   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.  */
 
 /* Finds characters in a memory area.  Optimized for the Alpha
 architecture:
@@ -53,7 +52,6 @@ ENTRY(memchr)
         ldq_u   t0, 0(a0)       # load first quadword (a0 may be misaligned)
 	addq	a0, a2, t4
 	and	a1, 0xff, a1	# a1 = 00000000000000ch
-	ldq_u	t5, -1(t4)
 	sll	a1,  8, t1	# t1 = 000000000000ch00
 	cmpult	a2, 9, t3
 	or	t1, a1, a1	# a1 = 000000000000chch
@@ -66,6 +64,7 @@ ENTRY(memchr)
 
 	beq	t3, $first_quad
 
+	ldq_u	t5, -1(t4)
 	extqh	t5, a0, t5
 	mov	a0, v0
 	or	t6, t5, t0	# t0 = quadword starting at a0
diff --git a/sysdeps/alpha/strncmp.S b/sysdeps/alpha/strncmp.S
index 682759042f..a6c6c61213 100644
--- a/sysdeps/alpha/strncmp.S
+++ b/sysdeps/alpha/strncmp.S
@@ -62,8 +62,8 @@ $aligned:
 	ornot	t0, t3, t0	# .. e1 :
 	cmpbge	zero, t1, t7	# e0    : bits set iff null found
 	beq	a2, $eoc	# .. e1 : check end of count
-	unop			#       :
-	bne	t7, $eos	# e1    :
+	subq	a2, 1, a2	# e0    :
+	bne	t7, $eos	# .. e1 :
 
 	/* Aligned compare main loop.
 	   On entry to this basic block:
@@ -73,8 +73,8 @@ $aligned:
 $a_loop:
 	xor	t0, t1, t2	# e0	:
 	bne	t2, $wordcmp	# .. e1 (zdb)
-	ldq_u	t1, 0(a1)	# e0    :
-	ldq_u	t0, 0(a0)	# .. e1 :
+	ldq_u	t1, 8(a1)	# e0    :
+	ldq_u	t0, 8(a0)	# .. e1 :
 	addq	a1, 8, a1	# e0    :
 	addq	a0, 8, a0	# .. e1 :
 	cmpbge	zero, t1, t7	# e0    :
diff --git a/sysdeps/generic/paths.h b/sysdeps/generic/paths.h
index e5f34014a8..3e6053aeaf 100644
--- a/sysdeps/generic/paths.h
+++ b/sysdeps/generic/paths.h
@@ -56,6 +56,7 @@
 #define	_PATH_MNTTAB    "/etc/fstab"
 #define	_PATH_MOUNTED   "/var/run/mtab"
 #define	_PATH_NOLOGIN	"/etc/nologin"
+#define	_PATH_PRESERVE	"/var/preserve"
 #define	_PATH_SENDMAIL	"/usr/sbin/sendmail"
 #define	_PATH_SHADOW	"/etc/shadow"
 #define	_PATH_SHELLS	"/etc/shells"
diff --git a/sysdeps/gnu/utmpbits.h b/sysdeps/gnu/utmpbits.h
index 5bb230b243..4ba3a19960 100644
--- a/sysdeps/gnu/utmpbits.h
+++ b/sysdeps/gnu/utmpbits.h
@@ -90,13 +90,15 @@ struct utmp
 				   as DEAD_PROCESS.  */
   long ut_session;		/* Session ID, used for windowing.  */
   struct timeval ut_tv;		/* Time entry was made.  */
-  int32_t ut_addr[4];		/* Internet address of remote host.  */
+  int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
   enum utlogin ut_login;	/* To store information about source.  */
   short int ut_syslen;		/* Significant length of ut_host.  */
   char pad[14];			/* Reserved for future use.  */
 };
 
-#define ut_time	ut_tv.tv_sec	/* Backwards compatibility.  */
+/* Backwards compatibility hacks.  */
+#define ut_time	ut_tv.tv_sec
+#define ut_addr ut_addr_v6[0]
 
 /* Tell the user that we have a modern system with UT_HOST, UT_PID,
    UT_TYPE, UT_ID and UT_TV fields.  */
diff --git a/sysdeps/mach/hurd/ttyname_r.c b/sysdeps/mach/hurd/ttyname_r.c
index 05c2a6f2fa..8a2cdd6605 100644
--- a/sysdeps/mach/hurd/ttyname_r.c
+++ b/sysdeps/mach/hurd/ttyname_r.c
@@ -26,7 +26,7 @@
 /* Store at most BUFLEN characters of the pathname of the terminal FD is
    open on in BUF.  Return 0 on success, -1 otherwise.  */
 int
-ttyname_r (int fd, char *buf, size_t buflen)
+__ttyname_r (int fd, char *buf, size_t buflen)
 {
   error_t err;
   char nodename[1024];	/* XXX */
@@ -47,3 +47,5 @@ ttyname_r (int fd, char *buf, size_t buflen)
   memcpy (buf, nodename, len);
   return 0;
 }
+
+weak_alias (__ttyname_r, ttyname_r)
diff --git a/sysdeps/mach/hurd/xmknod.c b/sysdeps/mach/hurd/xmknod.c
index 3552874bb0..fefc955324 100644
--- a/sysdeps/mach/hurd/xmknod.c
+++ b/sysdeps/mach/hurd/xmknod.c
@@ -1,20 +1,20 @@
 /* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
+   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 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.
+   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., 675 Mass Ave,
-Cambridge, MA 02139, USA.  */
+   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 <sys/stat.h>
@@ -25,7 +25,7 @@ Cambridge, MA 02139, USA.  */
 #include <string.h>
 
 /* Temporary hack; this belongs in a header file, probably types.h. */
-#define major(x) ((int)(((unsigned) (x) >> 8) & 0xff))
+#define major(x) ((int)(((unsigned int) (x) >> 8) & 0xff))
 #define minor(x) ((int)((x) & 0xff))
 
 
@@ -111,5 +111,3 @@ __xmknod (int vers, const char *file_name, mode_t mode, dev_t *dev)
     return __hurd_fail (err);
   return 0;
 }
-
-weak_alias (__mknod, mknod)
diff --git a/sysdeps/unix/inet/Subdirs b/sysdeps/unix/inet/Subdirs
index 4a40811754..bce3ada782 100644
--- a/sysdeps/unix/inet/Subdirs
+++ b/sysdeps/unix/inet/Subdirs
@@ -1,3 +1,4 @@
 inet
+nis
 resolv
 sunrpc
diff --git a/sysdeps/unix/sysv/linux/paths.h b/sysdeps/unix/sysv/linux/paths.h
index eaa6aa632f..f5629fc3fc 100644
--- a/sysdeps/unix/sysv/linux/paths.h
+++ b/sysdeps/unix/sysv/linux/paths.h
@@ -56,6 +56,7 @@
 #define	_PATH_MNTTAB	"/etc/fstab"
 #define	_PATH_MOUNTED	"/etc/mtab"
 #define	_PATH_NOLOGIN	"/etc/nologin"
+#define	_PATH_PRESERVE	"/var/preserve"
 #define	_PATH_SENDMAIL	"/usr/sbin/sendmail"
 #define	_PATH_SHADOW	"/etc/shadow"
 #define	_PATH_SHELLS	"/etc/shells"