summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/001-2.2b47-2.2b51.patch
diff options
context:
space:
mode:
authorRichard Purdie <rpurdie@linux.intel.com>2010-08-27 15:14:24 +0100
committerRichard Purdie <rpurdie@linux.intel.com>2010-08-27 15:29:45 +0100
commit29d6678fd546377459ef75cf54abeef5b969b5cf (patch)
tree8edd65790e37a00d01c3f203f773fe4b5012db18 /meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/001-2.2b47-2.2b51.patch
parentda49de6885ee1bc424e70bc02f21f6ab920efb55 (diff)
downloadast2050-yocto-poky-29d6678fd546377459ef75cf54abeef5b969b5cf.zip
ast2050-yocto-poky-29d6678fd546377459ef75cf54abeef5b969b5cf.tar.gz
Major layout change to the packages directory
Having one monolithic packages directory makes it hard to find things and is generally overwhelming. This commit splits it into several logical sections roughly based on function, recipes.txt gives more information about the classifications used. The opportunity is also used to switch from "packages" to "recipes" as used in OpenEmbedded as the term "packages" can be confusing to people and has many different meanings. Not all recipes have been classified yet, this is just a first pass at separating things out. Some packages are moved to meta-extras as they're no longer actively used or maintained. Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
Diffstat (limited to 'meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/001-2.2b47-2.2b51.patch')
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/001-2.2b47-2.2b51.patch2344
1 files changed, 2344 insertions, 0 deletions
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/001-2.2b47-2.2b51.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/001-2.2b47-2.2b51.patch
new file mode 100644
index 0000000..886ce92
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/001-2.2b47-2.2b51.patch
@@ -0,0 +1,2344 @@
+# Patch origin: nfs-server source RPM from openSUSE 10.3
+
+diff -urN nfs-server-2.2beta47/.version nfs-server-2.2beta51/.version
+--- nfs-server-2.2beta47/.version Tue Sep 7 09:47:27 1999
++++ nfs-server-2.2beta51/.version Fri Nov 8 14:45:36 2002
+@@ -1 +1 @@
+-2.2beta46
++2.2beta51
+diff -urN nfs-server-2.2beta47/ChangeLog nfs-server-2.2beta51/ChangeLog
+--- nfs-server-2.2beta47/ChangeLog Wed Nov 10 10:17:51 1999
++++ nfs-server-2.2beta51/ChangeLog Fri Nov 8 14:45:36 2002
+@@ -1,8 +1,59 @@
++Thu Nov 9 17:03:05 2000
++
++ * No longer use OPEN_MAX
++
++ * Reworked configure.in, BUILD script no longer needed
++ (nor functioning)
++
++ * Be more anal about matching cached fh's and real files.
++ In addition to the psi, we also store dev/ino/type now
++ and match that in fh_find.
++
++ * Write pidfiles
++
++ * Support nosetuid
++
++Wed Feb 9 14:52:34 2000
++
++ * auth_init.c didn't properly parse options--rot_squash
++ which is obviously a typo was parsed as ro.
++ Thanks to Jan Steffan for complaining about this :-)
++
++Mon Jan 31 11:48:34 2000
++
++ * Fixed Y2K bug in logging.c.
++ Thanks to Jonathan Hankins <jhankins@homewood.k12.al.us>.
++
++Thu Dec 9 11:14:21 1999
++
++ * Fix handling of NFS-mounted and /proc directories.
++ They weren't properly hidden.
++ Thanks to Dick Streefland <dick_streefland@tasking.com>
++ for the report and a first patch.
++
+ Wed Nov 10 10:17:16 1999
+
+ * Security fix for buffer overflow in fh_buildpath
+ No thanks to Mariusz who reported it to bugtraq
+ rather than me.
++
++Wed Nov 09 17:10:00 1999
++
++ * Workaround for broken Solaris clients that can't handle
++ atime/mtime/ctime of 0.
++ Thanks to Frank Wuebbelin for his problem report and
++ testing the fix.
++
++ * Fixed typo in exports.man
++
++Tue Nov 2 10:31:14 1999
++
++ * Patch for mode 0100 and 0100 executables by
++ Michael Deutschmann <michael@talamasca.wkpowerlink.com>
++
++ * Common startup stuff for all daemons.
++ Inspired by code sent to me by someone (sorry, I forgot
++ your name, and the mail's gone!)
+
+ Wed Sep 8 09:07:38 1999
+
+diff -urN nfs-server-2.2beta47/Makefile.in nfs-server-2.2beta51/Makefile.in
+--- nfs-server-2.2beta47/Makefile.in Tue Jun 22 14:53:10 1999
++++ nfs-server-2.2beta51/Makefile.in Fri Nov 8 14:45:36 2002
+@@ -17,23 +17,30 @@
+
+ #### Start of system configuration section. ####
+
+-srcdir = @srcdir@
+-VPATH = @srcdir@
++srcdir = @srcdir@
++VPATH = @srcdir@
+
+-CC = @CC@
+-AR = ar
+-RANLIB = @RANLIB@
+-
+-INSTALL = @INSTALL@
+-INSTALL_PROGRAM = @INSTALL_PROGRAM@ -m 755
+-INSTALL_DATA = @INSTALL_DATA@
+-MAKEINFO = makeinfo
+-TEXI2DVI = texi2dvi
+-RPCGEN = @RPCGEN@ @RPCGEN_C@
++CC = @CC@
++AR = ar
++RANLIB = @RANLIB@
++
++INSTALL = @INSTALL@
++INSTALL_PROGRAM = @INSTALL_PROGRAM@ -m 755
++INSTALL_DATA = @INSTALL_DATA@
++MAKEINFO = makeinfo
++TEXI2DVI = texi2dvi
++RPCGEN = @RPCGEN@ @RPCGEN_C@
+
+ # General compile options and libs:
+-DEFS = @DEFS@ $(NFSD_DEFS)
+-LIBS = libnfs.a @LIBS@
++DEFS = @DEFS@ $(NFSD_DEFS)
++LIBS = libnfs.a @LIBS@
++
++# Ugidd support
++UGIDD_PROG = @UGIDD_PROG@
++UGIDD_MAN = @UGIDD_MAN@
++
++# New inode mapping scheme
++DEVTAB_FILE = $(install_prefix)@PATH_DEVTAB@
+
+ # Compile options for nfsd:
+ # CALL_PROFILING
+@@ -80,9 +87,6 @@
+
+ #### End of system configuration section. ####
+
+-# include site-specific defintions generated by BUILD.
+-include site.mk
+-
+ SHELL = /bin/sh
+
+ SRCS = version.c logging.c fh.c devtab.c \
+@@ -96,19 +100,19 @@
+ utimes.c mkdir.c rename.c getopt.c getopt_long.c \
+ alloca.c mountlist.c xmalloc.c \
+ xstrdup.c strdup.c strstr.c nfsmounted.c faccess.c \
+- haccess.c failsafe.c signals.c
++ haccess.c daemon.c signals.c
+ XDRFILES = mount.x nfs_prot.x
+ GENFILES = mount.h mount_xdr.c mount_svc.c nfs_prot.h nfs_prot_xdr.c \
+ ugid.h ugid_xdr.c ugid_clnt.c
+ HDRS = system.h nfsd.h auth.h fh.h logging.h fakefsuid.h \
+ rpcmisc.h faccess.h rquotad.h rquota.h haccess.h
+-LIBHDRS = fsusage.h getopt.h mountlist.h failsafe.h signals.h
++LIBHDRS = fsusage.h getopt.h mountlist.h daemon.h signals.h
+ MANPAGES5 = exports
+ MANPAGES8p = mountd nfsd $(UGIDD_MAN)
+ MANPAGES8 = showmount
+ MANPAGES = $(MANPAGES5) $(MANPAGES8p) $(MANPAGES8)
+ LIBOBJS = version.o fsusage.o mountlist.o xmalloc.o xstrdup.o \
+- nfsmounted.o faccess.o haccess.o failsafe.o \
++ nfsmounted.o faccess.o haccess.o daemon.o \
+ signals.o @LIBOBJS@ @ALLOCA@
+ OBJS = logging.o fh.o devtab.o auth_init.o auth_clnt.o auth.o
+ NFSD_OBJS = nfsd.o rpcmisc.o nfs_dispatch.o getattr.o setattr.o \
+@@ -174,15 +178,13 @@
+ ${srcdir}/mkinstalldirs $(bindir) $(man5dir) $(man8dir)
+
+ $(rpcprefix)mountd: $(MOUNTD_OBJS) libnfs.a
+- $(CC) $(LDFLAGS) -o $@ $(MOUNTD_OBJS) $(LIBS) \
+- $(LIBWRAP_DIR) $(LIBWRAP_LIB)
++ $(CC) $(LDFLAGS) -o $@ $(MOUNTD_OBJS) $(LIBS)
+
+ $(rpcprefix)nfsd: $(NFSD_OBJS) libnfs.a
+ $(CC) $(LDFLAGS) -o $@ $(NFSD_OBJS) $(LIBS)
+
+ $(rpcprefix)ugidd: $(UGIDD_OBJS) libnfs.a
+- $(CC) $(LDFLAGS) -o $@ $(UGIDD_OBJS) $(LIBS) \
+- $(LIBWRAP_DIR) $(LIBWRAP_LIB)
++ $(CC) $(LDFLAGS) -o $@ $(UGIDD_OBJS) $(LIBS)
+
+ showmount: $(SHOWMOUNT_OBJS) libnfs.a
+ $(CC) $(LDFLAGS) -o $@ $(SHOWMOUNT_OBJS) $(LIBS)
+diff -urN nfs-server-2.2beta47/aclocal.m4 nfs-server-2.2beta51/aclocal.m4
+--- nfs-server-2.2beta47/aclocal.m4 Fri Jun 11 12:04:22 1999
++++ nfs-server-2.2beta51/aclocal.m4 Fri Nov 8 14:45:36 2002
+@@ -221,20 +221,14 @@
+ ])dnl
+ dnl *********** libwrap bug **************
+ define(AC_LIBWRAP_BUG,
+- [if test -f site.mk; then
+- . ./site.mk
+- fi
+- if test ! -z "$LIBWRAP_DIR"; then
++ [if test "$ac_cv_lib_wrap_main" = yes; then
+ AC_MSG_CHECKING(for link problem with libwrap.a)
+ AC_CACHE_VAL(nfsd_cv_lib_wrap_bug,
+- [ac_save_LIBS=$LIBS
+- LIBS="$LIBS $LIBWRAP_DIR $LIBWRAP_LIB"
+- AC_TRY_LINK([
++ [AC_TRY_LINK([
+ extern int deny_severity;
+ ],[
+ deny_severity=1;
+ ], nfsd_cv_lib_wrap_bug=no, nfsd_cv_lib_wrap_bug=yes)
+- LIBS=$ac_save_LIBS
+ ]) dnl
+ AC_MSG_RESULT($nfsd_cv_lib_wrap_bug)
+ test $nfsd_cv_lib_wrap_bug = yes && AC_DEFINE(HAVE_LIBWRAP_BUG)
+diff -urN nfs-server-2.2beta47/auth.c nfs-server-2.2beta51/auth.c
+--- nfs-server-2.2beta47/auth.c Mon Sep 13 16:56:03 1999
++++ nfs-server-2.2beta51/auth.c Fri Nov 8 14:45:36 2002
+@@ -84,8 +84,9 @@
+ 0, /* relative links */
+ 0, /* noaccess */
+ 1, /* cross_mounts */
+- (uid_t)-2, /* default uid */
+- (gid_t)-2, /* default gid */
++ 1, /* allow setuid */
++ 65534, /* default uid */
++ 65534, /* default gid */
+ 0, /* no NIS domain */
+ };
+
+@@ -99,8 +100,9 @@
+ 0, /* relative links */
+ 0, /* noaccess */
+ 1, /* cross_mounts */
+- (uid_t)-2, /* default uid */
+- (gid_t)-2, /* default gid */
++ 0, /* allow setuid */
++ 65534, /* default uid */
++ 65534, /* default gid */
+ 0, /* no NIS domain */
+ };
+
+@@ -673,6 +675,7 @@
+ cpp = &unknown_clients;
+ } else {
+ cpp = &known_clients;
++ cp->clnt_addr = *(struct in_addr *) hp->h_addr;
+ auth_hash_host(cp, hp);
+ }
+ cp->next = *cpp;
+diff -urN nfs-server-2.2beta47/auth.h nfs-server-2.2beta51/auth.h
+--- nfs-server-2.2beta47/auth.h Thu Apr 8 14:47:56 1999
++++ nfs-server-2.2beta51/auth.h Fri Nov 8 14:45:36 2002
+@@ -23,14 +23,6 @@
+ extern char * public_root_path;
+ extern struct nfs_fh public_root;
+
+-#if defined(linux) && defined(i386) && !defined(HAVE_SETFSUID)
+-# define MAYBE_HAVE_SETFSUID
+-#endif
+-
+-#ifdef MAYBE_HAVE_SETFSUID
+-extern int have_setfsuid;
+-#endif
+-
+ /*
+ * These externs are set in the dispatcher (dispatch.c) and auth_fh
+ * (nfsd.c) so that we can determine access rights, export options,
+@@ -59,6 +51,7 @@
+ int link_relative;
+ int noaccess;
+ int cross_mounts;
++ int allow_setuid;
+ uid_t nobody_uid;
+ gid_t nobody_gid;
+ char * clnt_nisdomain;
+@@ -112,7 +105,7 @@
+ extern void auth_free_lists(void);
+ extern nfs_client *auth_clnt(struct svc_req *rqstp);
+ extern nfs_mount *auth_path(nfs_client *, struct svc_req *, char *);
+-extern void auth_user(nfs_mount *, struct svc_req *);
++extern int auth_user(nfs_mount *, struct svc_req *);
+
+ extern nfs_client *auth_get_client(char *);
+ extern nfs_mount *auth_match_mount(nfs_client *, char *);
+diff -urN nfs-server-2.2beta47/auth_clnt.c nfs-server-2.2beta51/auth_clnt.c
+--- nfs-server-2.2beta47/auth_clnt.c Wed Nov 10 10:18:06 1999
++++ nfs-server-2.2beta51/auth_clnt.c Fri Nov 8 14:45:36 2002
+@@ -12,20 +12,17 @@
+ */
+
+
++#include <sys/fsuid.h>
+ #include "system.h"
+ #include "nfsd.h"
+-#include "fakefsuid.h"
+-
+-#ifndef svc_getcaller
+-#define svc_getcaller(x) ((struct sockaddr_in *) &(x)->xp_rtaddr.buf)
+-#endif
++#include "rpcmisc.h"
+
+
+-#if defined(HAVE_SETFSUID) || defined(MAYBE_HAVE_SETFSUID)
+-static void setfsids(uid_t, gid_t, gid_t *, int);
++#if defined(HAVE_SETFSUID)
++static int setfsids(uid_t, gid_t, gid_t *, int);
+ #endif
+ #ifndef HAVE_SETFSUID
+-static void seteids(uid_t, gid_t, gid_t *, int);
++static int seteids(uid_t, gid_t, gid_t *, int);
+ #endif
+
+ uid_t auth_uid = 0; /* Current effective user ids */
+@@ -43,6 +40,17 @@
+ short *gid, short *nrgids, int *groups);
+ #endif
+
++/*
++ * The following crap is required for glibc 2.1 which has 32bit uids
++ * in user land mapped to 16bit uids in the Linux kernel
++ */
++#if defined(HAVE_BROKEN_SETFSUID)
++# define native_uid(u) ((unsigned short)(u))
++# define native_gid(g) ((unsigned short)(g))
++#else
++# define native_uid(u) (u)
++# define native_gid(g) (g)
++#endif
+
+ /*
+ * For an RPC request, look up the NFS client info along with the
+@@ -92,8 +100,9 @@
+ }
+
+ if (logging_enabled(D_AUTH)) {
+- Dprintf(D_AUTH, "auth_path(%s): mount point %s, (%s%s%s%s%s)\n",
+- path, mp->path,
++ Dprintf(D_AUTH, "auth_path(%s, %s): "
++ "mount point %s, (%s%s%s%s%s)\n",
++ inet_ntoa(cp->clnt_addr), path, mp->path,
+ mp->o.all_squash? "all_squash " : (
+ mp->o.root_squash? "root_squash " : ""),
+ (mp->o.uidmap == map_daemon)? "uidmap " : "",
+@@ -105,7 +114,8 @@
+ return mp;
+ }
+
+-void auth_user(nfs_mount *mp, struct svc_req *rqstp)
++int
++auth_user(nfs_mount *mp, struct svc_req *rqstp)
+ {
+ uid_t cuid;
+ gid_t cgid;
+@@ -160,23 +170,18 @@
+ else if (cred_len > NGRPS)
+ cred_len = NGRPS;
+
+- cuid = luid(cred_uid, mp, rqstp);
+- cgid = lgid(cred_gid, mp, rqstp);
++ cuid = luid(native_uid(cred_uid), mp, rqstp);
++ cgid = lgid(native_gid(cred_gid), mp, rqstp);
+ clen = cred_len;
+ for (i = 0; i < cred_len; i++)
+- cgids[i] = lgid(cred_gids[i], mp, rqstp);
++ cgids[i] = lgid(native_gid(cred_gids[i]), mp, rqstp);
+ } else {
+ /* On systems that have 32bit uid_t in user space but
+ * 16bit in the kernel, we need to truncate the
+ * nobody ID (default -2).
+ */
+-#if !defined(HAVE_BROKEN_SETFSUID)
+- cuid = mp->o.nobody_uid;
+- cgid = mp->o.nobody_gid;
+-#else
+- cuid = (unsigned short) mp->o.nobody_uid;
+- cgid = (unsigned short) mp->o.nobody_gid;
+-#endif
++ cuid = native_uid(mp->o.nobody_uid);
++ cgid = native_gid(mp->o.nobody_gid);
+ /* Construct a list of one gid. */
+ cgids[0] = cgid;
+ clen = 1;
+@@ -193,14 +198,9 @@
+ * upper 16 bits set (including our default nobody uid -2).
+ */
+ #if defined(HAVE_SETFSUID)
+- setfsids(cuid, cgid, cgids, clen);
++ return setfsids(cuid, cgid, cgids, clen);
+ #else
+-#if defined(MAYBE_HAVE_SETFSUID)
+- if (have_setfsuid)
+- setfsids(cuid, cgid, cgids, clen);
+- else
+-#endif
+- seteids(cuid, cgid, cgids, clen);
++ return seteids(cuid, cgid, cgids, clen);
+ #endif
+ }
+
+@@ -210,6 +210,8 @@
+ void
+ auth_override_uid(uid_t uid)
+ {
++ int res;
++
+ /* extension hooks: */
+ efs_setfsuid(uid);
+
+@@ -217,19 +219,18 @@
+ uid = (unsigned short) uid;
+ #endif
+ #if defined(HAVE_SETFSUID)
+- setfsuid(uid);
++ res = setfsuid(uid);
+ #else
+-#if defined(MAYBE_HAVE_SETFSUID)
+- if (have_setfsuid)
+- setfsuid(uid);
+- else
+-#endif
+- seteuid(uid);
++ res = seteuid(uid);
+ #endif
++ /* should never happen */
++ if (res < 0)
++ Dprintf(L_FATAL, "auth_override_uid(%d) failed: %s",
++ uid, strerror(errno));
+ }
+
+-#if defined(HAVE_SETFSUID) || defined(MAYBE_HAVE_SETFSUID)
+-static void
++#if defined(HAVE_SETFSUID)
++static int
+ setfsids(uid_t cred_uid, gid_t cred_gid, gid_t *cred_gids, int cred_len)
+ {
+ /* extension hooks: */
+@@ -238,43 +239,47 @@
+
+ /* First, set the user ID. */
+ if (auth_uid != cred_uid) {
+- if (setfsuid(cred_uid) < 0)
++ if (setfsuid(cred_uid) < 0) {
+ Dprintf(L_ERROR, "Unable to setfsuid %d: %s\n",
+ cred_uid, strerror(errno));
+- else
+- auth_uid = cred_uid;
++ return 0;
++ }
++ auth_uid = cred_uid;
+ }
+
+ /* Next, the group ID. */
+ if (auth_gid != cred_gid) {
+- if (setfsgid(cred_gid) < 0)
++ if (setfsgid(cred_gid) < 0) {
+ Dprintf(L_ERROR, "Unable to setfsgid %d: %s\n",
+ cred_gid, strerror(errno));
+- else
+- auth_gid = cred_gid;
++ return 0;
++ }
++ auth_gid = cred_gid;
+ }
+
+ #ifdef HAVE_SETGROUPS
+ /* Finally, set the supplementary group IDs if possible. */
+- if (cred_len < 0 || cred_len > NGRPS)
++ if (cred_len < 0 || cred_len > NGRPS) {
+ Dprintf(L_ERROR, "Negative or huge cred_len: %d\n", cred_len);
+- else if (cred_len != auth_gidlen
+- || memcmp(cred_gids, auth_gids, auth_gidlen*sizeof(gid_t))) {
+- if (setgroups(cred_len, cred_gids) < 0)
++ return 0;
++ }
++ if (cred_len != auth_gidlen
++ || memcmp(cred_gids, auth_gids, auth_gidlen*sizeof(gid_t))) {
++ if (setgroups(cred_len, cred_gids) < 0) {
+ Dprintf(L_ERROR, "Unable to setgroups: %s\n",
+ strerror(errno));
+- else {
+- memcpy(auth_gids, cred_gids, cred_len*sizeof(gid_t));
+- auth_gidlen = cred_len;
++ return 0;
+ }
++ memcpy(auth_gids, cred_gids, cred_len*sizeof(gid_t));
++ auth_gidlen = cred_len;
+ }
+ #endif /* HAVE_SETGROUPS */
+-
++ return 1;
+ }
+ #endif
+
+ #if !defined(HAVE_SETFSUID)
+-static void
++static int
+ seteids(uid_t cred_uid, gid_t cred_gid, gid_t *cred_gids, int cred_len)
+ {
+ /* extension hooks: */
+@@ -286,52 +291,62 @@
+ /* First set the group ID. */
+ if (auth_gid != cred_gid) {
+ if (auth_uid != ROOT_UID) {
+- if (seteuid(ROOT_UID) < 0)
++ if (seteuid(ROOT_UID) < 0) {
+ Dprintf(L_ERROR, "Unable to seteuid(%d): %s\n",
+ ROOT_UID, strerror(errno));
+- else
+- auth_uid = ROOT_UID;
++ return 0;
++ }
++ auth_uid = ROOT_UID;
+ }
+- if (setegid(cred_gid) < 0)
++ if (setegid(cred_gid) < 0) {
+ Dprintf(L_ERROR, "Unable to setegid(%d): %s\n",
+ cred_gid, strerror(errno));
+- else
+- auth_gid = cred_gid;
++ return 0;
++ }
++ auth_gid = cred_gid;
+ }
+
+ #ifdef HAVE_SETGROUPS
+ /* Next set the supplementary group IDs if possible. */
+- if (cred_len < 0 || cred_len > NGRPS)
++ if (cred_len < 0 || cred_len > NGRPS) {
+ Dprintf(L_ERROR, "Negative or huge cred_len: %d\n", cred_len);
+- else if (cred_len != auth_gidlen
+- || memcmp(cred_gids, auth_gids, auth_gidlen*sizeof(gid_t))) {
++ return 0;
++ }
++ if (cred_len != auth_gidlen
++ || memcmp(cred_gids, auth_gids, auth_gidlen*sizeof(gid_t))) {
+ if (auth_uid != ROOT_UID) {
+- if (seteuid(ROOT_UID) < 0)
++ if (seteuid(ROOT_UID) < 0) {
+ Dprintf(L_ERROR, "Unable to seteuid(%d): %s\n",
+ ROOT_UID, strerror(errno));
+- else
+- auth_uid = ROOT_UID;
++ return 0;
++ }
++ auth_uid = ROOT_UID;
+ }
+- if (setgroups(cred_len, cred_gids) < 0)
++ if (setgroups(cred_len, cred_gids) < 0) {
+ Dprintf(L_ERROR, "Unable to setgroups: %s\n",
+ strerror(errno));
+- else {
+- memcpy(auth_gids, cred_gids, cred_len*sizeof(gid_t));
+- auth_gidlen = cred_len;
++ return 0;
+ }
++ memcpy(auth_gids, cred_gids, cred_len*sizeof(gid_t));
++ auth_gidlen = cred_len;
+ }
+ #endif /* HAVE_SETGROUPS */
+
+ /* Finally, set the user ID. */
+ if (auth_uid != cred_uid) {
+- if (auth_uid != ROOT_UID && seteuid(ROOT_UID) < 0)
++ if (auth_uid != ROOT_UID && seteuid(ROOT_UID) < 0) {
+ Dprintf(L_ERROR, "Unable to seteuid(%d): %s\n",
+ ROOT_UID, strerror(errno));
+- if (seteuid(cred_uid) < 0)
++ return 0;
++ }
++ if (seteuid(cred_uid) < 0) {
+ Dprintf(L_ERROR, "Unable to seteuid(%d): %s\n",
+ cred_uid, strerror(errno));
+- else
+- auth_uid = cred_uid;
++ return 0;
++ }
++ auth_uid = cred_uid;
+ }
++
++ return 1;
+ }
+ #endif
+diff -urN nfs-server-2.2beta47/auth_init.c nfs-server-2.2beta51/auth_init.c
+--- nfs-server-2.2beta47/auth_init.c Mon Apr 19 14:01:21 1999
++++ nfs-server-2.2beta51/auth_init.c Fri Nov 8 14:45:36 2002
+@@ -13,7 +13,6 @@
+ */
+
+ #include "nfsd.h"
+-#include "fakefsuid.h"
+ #include <pwd.h>
+
+ #define LINE_SIZE 1024
+@@ -263,55 +262,63 @@
+ cp++;
+ while (*cp != terminator) {
+ kwd = cp;
+- while (isalpha(*cp) || *cp == '_' || *cp == '=') {
+- /* break out of loop after = sign */
+- if (*cp++ == '=')
+- break;
+- }
++ /* Gobble up keyword and "=" if there is one */
++ while (isalpha(*cp) || *cp == '_')
++ ++cp;
++ if (*cp == '=')
++ ++cp;
++
+ klen = cp - kwd;
+
+ /* process keyword */
+- if (strncmp(kwd, "secure", 6) == 0)
++#define ifkwd(n, string) \
++ if (klen == (n) && !strncmp(kwd, string, (n)))
++
++ ifkwd(2, "ro")
++ mp->o.read_only = 1;
++ else ifkwd(2, "rw")
++ mp->o.read_only = 0;
++ else ifkwd(6, "secure")
+ mp->o.secure_port = 1;
+- else if (strncmp(kwd, "insecure", 8) == 0)
++ else ifkwd(8, "insecure")
+ mp->o.secure_port = 0;
+- else if (strncmp(kwd, "root_squash", 11) == 0)
++ else ifkwd(11, "root_squash")
+ mp->o.root_squash = 1;
+- else if (strncmp(kwd, "no_root_squash", 14) == 0)
++ else ifkwd(14, "no_root_squash")
+ mp->o.root_squash = 0;
+- else if (strncmp(kwd, "ro", 2) == 0)
+- mp->o.read_only = 1;
+- else if (strncmp(kwd, "rw", 2) == 0)
+- mp->o.read_only = 0;
+- else if (strncmp(kwd, "link_relative", 13) == 0)
++ else ifkwd(13, "link_relative")
+ mp->o.link_relative = 1;
+- else if (strncmp(kwd, "link_absolute", 13) == 0)
++ else ifkwd(13, "link_absolute")
+ mp->o.link_relative = 0;
+- else if (strncmp(kwd, "map_daemon", 10) == 0)
++ else ifkwd(10, "map_daemon")
+ mp->o.uidmap = map_daemon;
+- else if (strncmp(kwd, "map_nis=", 8) == 0)
++ else ifkwd(8, "map_nis=")
+ parse_nis_uidmap(mp, &cp);
+- else if (strncmp(kwd, "map_static=", 11) == 0)
++ else ifkwd(11, "map_static=")
+ parse_static_uidmap(mp, &cp);
+- else if (strncmp(kwd, "map_identity", 12) == 0)
++ else ifkwd(12, "map_identity")
+ mp->o.uidmap = identity;
+- else if (strncmp(kwd, "all_squash", 10) == 0)
++ else ifkwd(10, "all_squash")
+ mp->o.all_squash = 1;
+- else if (strncmp(kwd, "no_all_squash", 13) == 0)
++ else ifkwd(13, "no_all_squash")
+ mp->o.all_squash = 0;
+- else if (strncmp(kwd, "noaccess", 8) == 0)
++ else ifkwd(8, "noaccess")
+ mp->o.noaccess = 1;
+- else if (strncmp(kwd, "squash_uids=", 12) == 0)
++ else ifkwd(12, "squash_uids=")
+ parse_squash(mp, 1, &cp);
+- else if (strncmp(kwd, "squash_gids=", 12) == 0)
++ else ifkwd(12, "squash_gids=")
+ parse_squash(mp, 0, &cp);
+- else if (strncmp(kwd, "anonuid=", 8) == 0)
++ else ifkwd(8, "anonuid=")
+ mp->o.nobody_uid = parse_num(&cp);
+- else if (strncmp(kwd, "anongid=", 8) == 0)
++ else ifkwd(8, "anongid=")
+ mp->o.nobody_gid = parse_num(&cp);
+- else if (strncmp(kwd, "async", 5) == 0)
++ else ifkwd(6, "setuid")
++ mp->o.allow_setuid = 1;
++ else ifkwd(8, "nosetuid")
++ mp->o.allow_setuid = 0;
++ else ifkwd(5, "async")
+ /* knfsd compatibility, ignore */;
+- else if (strncmp(kwd, "sync", 4) == 0)
++ else ifkwd(4, "sync")
+ /* knfsd compatibility, ignore */;
+ else {
+ Dprintf(L_ERROR,
+@@ -566,11 +573,6 @@
+ auth_check_all_wildcards();
+ auth_sort_all_mountlists();
+ auth_log_all();
+-
+-#if defined(MAYBE_HAVE_SETFSUID) && !defined(HAVE_SETFSUID)
+- /* check if the a.out setfsuid syscall works on this machine */
+- have_setfsuid = (setfsuid(0) >= 0);
+-#endif
+
+ auth_initialized = 1;
+ }
+diff -urN nfs-server-2.2beta47/config.h.in nfs-server-2.2beta51/config.h.in
+--- nfs-server-2.2beta47/config.h.in Fri Jun 11 12:01:22 1999
++++ nfs-server-2.2beta51/config.h.in Fri Nov 8 14:45:36 2002
+@@ -3,7 +3,7 @@
+ /* Define if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+-#ifndef _ALL_SOURCE
++#ifdef _ALL_SOURCE
+ #undef _ALL_SOURCE
+ #endif
+
+diff -urN nfs-server-2.2beta47/configure.in nfs-server-2.2beta51/configure.in
+--- nfs-server-2.2beta47/configure.in Fri Jun 11 11:58:10 1999
++++ nfs-server-2.2beta51/configure.in Fri Nov 8 14:45:36 2002
+@@ -2,7 +2,36 @@
+ dnl Updated for autoconf 2.
+ dnl
+ AC_INIT(nfsd.c)
+-AC_CONFIG_HEADER(config.h)
++AC_CONFIG_HEADER(config.h site.h)
++
++dnl **************************************************************
++dnl * handle --enable options
++dnl **************************************************************
++AC_ARG_ENABLE(new-inodes,
++ [ --enable-new-inodes Enable new-style inode inodes])
++AC_ARG_WITH(devtab,
++ [ --with-devtab=file Specify location for devtab [/var/lib/nfs/devtab]],
++ PATH_DEVTAB=$withval,
++ PATH_DEVTAB=/var/lib/nfs/devtab)
++AC_ARG_ENABLE(ugid-dynamic,
++ [ --enable-ugid-dynamic Enable uid mapping using rpc.ugidd (not recommended)])
++AC_ARG_ENABLE(ugid-nis,
++ [ --enable-ugid-nis Enable NIS-based uid mapping])
++AC_ARG_ENABLE(host-access,
++ [ --enable-host-access Enable host access checking])
++AC_ARG_ENABLE(mount-logging,
++ [ --disable-mount-logging Do not log mount operations to syslog],,
++ enable_mount_logging=yes)
++AC_ARG_WITH(exports-uid,
++ [ --with-exports-uid=N Make sure that /etc/exports is owned by uid N],,
++ with_exports_uid=0)
++AC_ARG_WITH(exports-gid,
++ [ --with-exports-gid=N Make sure that /etc/exports is owned by gid N],,
++ with_exports_gid=0)
++
++dnl **************************************************************
++dnl * Check for all kinds of stuff
++dnl **************************************************************
+ AC_PROG_CC
+ # If we're using gcc, we want warning flags
+ test -n "$GCC" &&
+@@ -19,7 +48,7 @@
+ AC_MINIX
+ AC_ISC_POSIX
+ AC_PROG_INSTALL
+-AC_CROSS_CHECK
++dnl AC_CROSS_CHECK
+ AC_STDC_HEADERS
+ AC_GNULIBC
+ AC_CONST
+@@ -52,14 +81,45 @@
+ AC_CHECK_LIB(rpc, main)
+ AC_CHECK_LIB(crypt, main)
+ AC_CHECK_LIB(nys, main)
+-AC_REPLACE_FUNCS(strerror realpath mkdir rename utimes strdup strstr getopt getopt_long)
+ AC_HAVE_FUNCS(getcwd seteuid setreuid getdtablesize setgroups lchown setsid setfsuid setfsgid innetgr quotactl authdes_getucred)
+ AC_AUTHDES_GETUCRED
+ AC_BROKEN_SETFSUID
+ AC_MOUNTLIST
+ AC_FSUSAGE
++AC_CHECK_LIB(wrap, main)
+ AC_LIBWRAP_BUG
+ AC_BSD_SIGNALS
++
++dnl **************************************************************
++dnl * Munge user specified options
++dnl **************************************************************
++if test "$enable_new_inodes" = yes; then
++ AC_DEFINE(ENABLE_DEVTAB)
++fi
++if test "$enable_ugid_dynamic" = yes; then
++ AC_DEFINE(ENABLE_UGID_DAEMON)
++ UGIDD_PROG=\${rpcprefix}.ugidd
++ UGIDD_MAN=ugidd
++fi
++if test "$enable_ugid_nis" = yes; then
++ AC_DEFINE(ENABLE_UGID_NIS)
++fi
++if test "$enable_host_access" = yes; then
++ AC_DEFINE(HOSTS_ACCESS)
++fi
++if test "$enable_mount_logging" = yes; then
++ AC_DEFINE(WANT_LOG_MOUNTS)
++fi
++AC_DEFINE_UNQUOTED(EXPORTSOWNERUID, $with_exports_uid)
++AC_DEFINE_UNQUOTED(EXPORTSOWNERGID, $with_exports_gid)
++AC_SUBST(PATH_DEVTAB)
++AC_SUBST(UGIDD_PROG)
++AC_SUBST(UGIDD_MAN)
++
++dnl **************************************************************
++dnl * Output CFLAGS and LDFLAGS
++dnl **************************************************************
+ AC_SUBST(LDFLAGS)
+ AC_SUBST(CFLAGS)
++
+ AC_OUTPUT(Makefile)
+diff -urN nfs-server-2.2beta47/daemon.c nfs-server-2.2beta51/daemon.c
+--- nfs-server-2.2beta47/daemon.c Thu Jan 1 01:00:00 1970
++++ nfs-server-2.2beta51/daemon.c Fri Nov 8 14:45:52 2002
+@@ -0,0 +1,270 @@
++/*
++ * daemon.c
++ *
++ * Copyright (C) 1998, <okir@monad.swb.de>
++ *
++ * Implements common daemon stuff and
++ * fail-safe mode for nfsd/mountd.
++ */
++
++#include "system.h"
++#include "logging.h"
++#include "signals.h"
++#include <sys/wait.h>
++
++static const char * pidfilename = 0;
++static const char * get_signame(int signo);
++
++/*
++ * Do the Crawley Thing
++ */
++void
++daemonize(void)
++{
++ int c;
++
++ /* Ignore SIGHUP so the parent can exit while we're still
++ * in limbo */
++ ignore_signal(SIGHUP);
++
++ /* Now fork */
++ c = fork();
++ if (c < 0)
++ Dprintf(L_FATAL, "unable to fork: %s", strerror(errno));
++
++ /* Parent process: exit */
++ if (c > 0)
++ exit(0);
++
++ /* Do the session stuff */
++ close(0);
++ close(1);
++ close(2);
++#ifdef HAVE_SETSID
++ setsid();
++#else
++ if ((c = open("/dev/tty", O_RDWR)) >= 0) {
++ ioctl(c, TIOCNOTTY, (char *) NULL);
++ close(c);
++ }
++#endif
++
++ /* Stop stderr logging */
++ background_logging();
++}
++
++void
++setpidpath(const char *filename)
++{
++ pidfilename = filename;
++}
++
++void
++writepid(pid_t pid, int clear)
++{
++ FILE *fp;
++
++ fp = fopen(pidfilename, clear? "w" : "a");
++ if (fp == NULL)
++ Dprintf(L_FATAL, "Unable to open %s: %m", pidfilename);
++ fprintf(fp, "%d\n", pid);
++ fclose(fp);
++ return;
++}
++
++void
++failsafe(int level, int ncopies)
++{
++ int *servers, running, child, i;
++ int pid, signo, status;
++ time_t last_restart = 0, now;
++ int restarts = 0, backoff = 60;
++
++ servers = (int *) xmalloc(ncopies * sizeof(int));
++ memset(servers, 0, ncopies * sizeof(int));
++
++ /* Loop forever, until we get SIGTERM */
++ running = 0;
++ while (1) {
++ /* Rewrite the pidfile */
++ writepid(getpid(), 1);
++ for (i = 0; i < ncopies; i++) {
++ if (servers[i] != 0)
++ writepid(servers[i], 0);
++ }
++
++ while (running < ncopies) {
++ if ((now = time(NULL)) == last_restart) {
++ if (++restarts > 2 * ncopies) {
++ Dprintf(L_ERROR,
++ "Servers restarting too "
++ "quickly, backing off.");
++ if (backoff < 60 * 60)
++ backoff <<= 1;
++ sleep(backoff);
++ }
++ } else {
++ last_restart = now;
++ restarts = 0;
++ backoff = 60;
++ }
++
++ /* Locate a free pid slot */
++ for (i = 0, child = -1; i < ncopies; i++) {
++ if (servers[i] == 0) {
++ child = i;
++ break;
++ }
++ }
++
++ if (child < 0)
++ Dprintf(L_FATAL, "failsafe: no pid slot?!");
++
++ Dprintf(D_GENERAL,
++ "starting server thread %d...\n", child + 1);
++
++ pid = fork();
++ if (pid < 0)
++ Dprintf(L_FATAL,
++ "Unable to fork for failsafe: %s",
++ strerror(errno));
++
++ if (pid == 0) {
++ /* Child process: continue with execution. */
++ return;
++ }
++
++ writepid(pid, 0);
++ servers[child] = pid;
++ running++;
++ }
++
++ /* Ignore some signals */
++ ignore_signal(SIGTERM);
++ ignore_signal(SIGHUP);
++ ignore_signal(SIGINT);
++ ignore_signal(SIGCHLD);
++
++ if ((pid = wait(&status)) < 0) {
++ Dprintf((errno == ECHILD)? L_FATAL : L_WARNING,
++ "failsafe: wait(): %s", strerror(errno));
++ continue;
++ }
++
++ /* Locate the child */
++ for (i = 0, child = -1; i < ncopies; i++) {
++ if (servers[i] == pid) {
++ child = i;
++ break;
++ }
++ }
++
++ if (child < 0) {
++ Dprintf(L_WARNING,
++ "failsafe: unknown child (pid %d) terminated",
++ pid);
++ continue;
++ }
++
++ /* Book-keeping */
++ servers[child] = 0;
++ running--;
++
++ if (WIFSIGNALED(status)) {
++ signo = WTERMSIG(status);
++ if (signo == SIGTERM) {
++ Dprintf(L_NOTICE, "failsafe: "
++ "child %d terminated by SIGTERM. %s.",
++ pid, running? "Continue" : "Exit");
++ } else {
++ Dprintf(L_WARNING, "failsafe: "
++ "child %d terminated by %s. "
++ "Restarting.",
++ pid, get_signame(signo));
++ child = -1; /* Restart */
++ }
++ } else if (WIFEXITED(status)) {
++ Dprintf(L_NOTICE, "failsafe: "
++ "child %d exited, status %d.",
++ pid, WEXITSTATUS(status));
++ } else {
++ Dprintf(L_ERROR, "failsafe: "
++ "abnormal child termination, "
++ "pid=%d status=%d. Restarting.",
++ pid, status);
++ child = -1; /* Restart */
++ }
++
++ /* If child >= 0, we should not restart */
++ if (child >= 0) {
++ if (!running) {
++ Dprintf(D_GENERAL,
++ "No more children, exiting.");
++ exit(0);
++ }
++ for (i = child; i < ncopies-1; i++)
++ servers[i] = servers[i+1];
++ ncopies--; /* Make sure we start no new servers */
++ }
++ }
++}
++
++/*
++ * Failsafe session, catch core file.
++ *
++ * Not yet implemented.
++ * General outline: we need to fork first, because nfsd changes
++ * uids frequently, and the kernel won't write out a core file after
++ * that. The forked proc starts out with a clean dumpable flag though.
++ *
++ * After the fork, we might want to make sure we end up in some common
++ * directory that the failsafe loop knows about.
++ */
++void
++failsafe_loop(int level, void (*function)(void))
++{
++ /* NOP */
++}
++
++static const char *
++get_signame(int signo)
++{
++ static char namebuf[30];
++
++ switch (signo) {
++ case SIGHUP: return "SIGHUP";
++ case SIGINT: return "SIGINT";
++ case SIGQUIT: return "SIGQUIT";
++ case SIGILL: return "SIGILL";
++ case SIGTRAP: return "SIGTRAP";
++ case SIGIOT: return "SIGIOT";
++ case SIGBUS: return "SIGBUS";
++ case SIGFPE: return "SIGFPE";
++ case SIGKILL: return "SIGKILL";
++ case SIGUSR1: return "SIGUSR1";
++ case SIGSEGV: return "SIGSEGV";
++ case SIGUSR2: return "SIGUSR2";
++ case SIGPIPE: return "SIGPIPE";
++ case SIGALRM: return "SIGALRM";
++ case SIGTERM: return "SIGTERM";
++ case SIGCHLD: return "SIGCHLD";
++ case SIGCONT: return "SIGCONT";
++ case SIGSTOP: return "SIGSTOP";
++ case SIGTSTP: return "SIGTSTP";
++ case SIGTTIN: return "SIGTTIN";
++ case SIGTTOU: return "SIGTTOU";
++ case SIGURG: return "SIGURG";
++ case SIGXCPU: return "SIGXCPU";
++ case SIGXFSZ: return "SIGXFSZ";
++ case SIGVTALRM: return "SIGVTALRM";
++ case SIGPROF: return "SIGPROF";
++ case SIGWINCH: return "SIGWINCH";
++ case SIGIO: return "SIGIO";
++#ifdef SIGPWR
++ case SIGPWR: return "SIGPWR";
++#endif
++ }
++
++ sprintf(namebuf, "signal #%d", signo);
++ return namebuf;
++}
+diff -urN nfs-server-2.2beta47/daemon.h nfs-server-2.2beta51/daemon.h
+--- nfs-server-2.2beta47/daemon.h Thu Jan 1 01:00:00 1970
++++ nfs-server-2.2beta51/daemon.h Fri Nov 8 14:45:52 2002
+@@ -0,0 +1,18 @@
++/*
++ * daemon.h
++ *
++ * Daemon support
++ */
++
++#ifndef CRAWLEY_H
++#define CRAWLEY_H
++
++#define _PATH_NFSD_PIDFILE "/var/run/nfsd.pid"
++#define _PATH_MOUNTD_PIDFILE "/var/run/mountd.pid"
++
++extern void daemonize(void);
++extern void setpidpath(const char *);
++extern void writepid(pid_t, int);
++extern void failsafe(int level, int ncopies);
++
++#endif /* CRAWLEY_H */
+diff -urN nfs-server-2.2beta47/exports.man nfs-server-2.2beta51/exports.man
+--- nfs-server-2.2beta47/exports.man Wed Nov 10 10:18:49 1999
++++ nfs-server-2.2beta51/exports.man Fri Nov 8 14:45:36 2002
+@@ -45,6 +45,12 @@
+ simultaneously. This is done by specifying an IP address and netmask pair
+ as
+ .IR address/netmask .
++.IP "world
++You can export a directory to the world (i.e. to all computers that
++are able to reach your NFS server network-wise) by using the empty
++hostname. When exporting to the world, the
++.BR root_squash ", " all_squash ", " ro " and " nosetuid
++options are turned on by default.
+ .TP
+ .B =public
+ This is a special ``hostname'' that identifies the given directory name
+@@ -81,6 +87,12 @@
+ by using the
+ .IR ro " option.
+ .TP
++.I setuid
++This allows clients to assert the setuid and setgid bits on regular
++files. For non-anonymous exports, this option is on by default.
++For anonymous exports, the default is
++.IR nosetuid .
++.TP
+ .I noaccess
+ This makes everything below the directory inaccessible for the named
+ client. This is useful when you want to export a directory hierarchy to
+@@ -296,6 +308,22 @@
+ .I /usr/X11R6
+ entry apply. This is also true when the latter is a wildcard or netgroup
+ entry.
++.PP
++You should also be careful about where you place spaces in the
++exports file. For instance, the following may appear as if you've
++exported
++.BR /pub " readonly to host " foozle ,
++but what this does in fact is export the directory to
++.B foozle
++with the default options,
++.I and
++export it to the world with the readonly option:
++.PP
++.nf
++.ta +3i
++# bad: export to the world
++/pub foozle (ro)
++.fi
+ .SH FILES
+ /etc/exports
+ .SH DIAGNOSTICS
+diff -urN nfs-server-2.2beta47/fh.c nfs-server-2.2beta51/fh.c
+--- nfs-server-2.2beta47/fh.c Wed Nov 10 10:41:14 1999
++++ nfs-server-2.2beta51/fh.c Fri Nov 8 14:45:36 2002
+@@ -95,17 +95,14 @@
+ static int fh_list_size;
+ static time_t curtime;
+
+-#ifndef FOPEN_MAX
+-#define FOPEN_MAX 256
+-#endif
+-
+ #ifndef FHTRACE
+ #undef D_FHTRACE
+ #define D_FHTRACE D_FHCACHE
+ #endif
+
+-static fhcache * fd_cache[FOPEN_MAX] = { NULL };
++static fhcache ** fd_cache = NULL;
+ static int fd_cache_size = 0;
++static int fd_cache_max = 0;
+
+ #ifndef NFSERR_INVAL /* that Sun forgot */
+ #define NFSERR_INVAL 22
+@@ -141,10 +138,13 @@
+
+ /* Forward declared local functions */
+ static psi_t path_psi(char *, nfsstat *, struct stat *, int);
++static psi_t path_psi_m(char *, nfsstat *, struct stat *,
++ struct stat *, int);
+ static int fh_flush_fds(void);
+ static char * fh_dump(svc_fh *);
+ static void fh_insert_fdcache(fhcache *fhc);
+ static void fh_unlink_fdcache(fhcache *fhc);
++static void fh_complain(const char *msg, fhcache *fhc);
+
+ static void
+ fh_move_to_front(fhcache *fhc)
+@@ -192,6 +192,13 @@
+ static void
+ fh_insert_fdcache(fhcache *fhc)
+ {
++#ifdef FHTRACE
++ Dprintf(D_FHTRACE, "insert fh %x into fdcache @%d\n", fhc->h.psi, fhc->fd);
++ if (fhc->fd < 0) {
++ fh_complain("fd cache bug: bad fd", fhc);
++ return;
++ }
++#endif
+ if (fhc == fd_lru_head)
+ return;
+ if (fhc->fd_next || fhc->fd_prev)
+@@ -203,9 +210,20 @@
+ fhc->fd_next = fd_lru_head;
+ fd_lru_head = fhc;
+
++ if (fhc->fd >= fd_cache_max) {
++ int oldmax = fd_cache_max, newmax;
++
++ newmax = (fhc->fd + 8) & ~7;
++ fd_cache = (fhcache **) xrealloc(fd_cache, newmax * sizeof(fhcache *));
++ memset(fd_cache + oldmax, 0, (newmax - oldmax) * sizeof(fhcache *));
++ fd_cache_max = newmax;
++ }
++
+ #ifdef FHTRACE
+ if (fd_cache[fhc->fd] != NULL) {
+- Dprintf(L_ERROR, "fd cache inconsistency!\n");
++ Dprintf(L_ERROR, "fd cache inconsistency (two fh's for same fd)");
++ fh_complain("new fh", fhc);
++ fh_complain("old fh", fd_cache[fhc->fd]);
+ return;
+ }
+ #endif
+@@ -225,7 +243,7 @@
+ } else if (fd_lru_tail == fhc) {
+ fd_lru_tail = prev;
+ } else {
+- Dprintf(L_ERROR, "fd cache inconsistency\n");
++ fh_complain("fd cache inconsistency (no next and not at tail)", fhc);
+ return;
+ }
+ if (prev) {
+@@ -233,13 +251,13 @@
+ } else if (fd_lru_head == fhc) {
+ fd_lru_head = next;
+ } else {
+- Dprintf(L_ERROR, "fd cache inconsistency\n");
++ fh_complain("fd cache inconsistency (no prev and not at head)", fhc);
+ return;
+ }
+
+ #ifdef FHTRACE
+ if (fd_cache[fhc->fd] != fhc) {
+- Dprintf(L_ERROR, "fd cache inconsistency!\n");
++ fh_complain("fd cache inconsistency (fd cache ptr mismatch)", fhc);
+ return;
+ }
+ #endif
+@@ -285,7 +303,7 @@
+ hash_slot = &((*hash_slot)->hash_next);
+ if (*hash_slot == NULL)
+ Dprintf(L_ERROR,
+- "internal inconsistency -- fhc(%x) not in hash table\n",
++ "internal inconsistency -- fhc(%x) not in hash table!\n",
+ fhc);
+ else
+ *hash_slot = fhc->hash_next;
+@@ -572,7 +590,7 @@
+ efs_seekdir(dir, cookie_stack[i]);
+ while ((dp = efs_readdir(dir))) {
+ char *name = dp->d_name;
+- int n = strlen(name);
++ int n = strlen(name); /* or: dp->d_reclen */
+
+ if (pathlen + n + 1 >= NFS_MAXPATHLEN
+ || (name[0] == '.'
+@@ -738,7 +756,16 @@
+ static psi_t
+ path_psi(char *path, nfsstat *status, struct stat *sbp, int svalid)
+ {
+- struct stat sbuf;
++ struct stat smounted;
++
++ return path_psi_m(path, status, sbp, &smounted, svalid);
++}
++
++static psi_t
++path_psi_m(char *path, nfsstat *status,
++ struct stat *sbp, struct stat *mbp, int svalid)
++{
++ struct stat sbuf, ddbuf;
+
+ if (sbp == NULL)
+ sbp = &sbuf;
+@@ -746,10 +773,10 @@
+ *status = nfs_errno();
+ return (0);
+ }
++ *mbp = *sbp;
+ if (S_ISDIR(sbp->st_mode) && strcmp(path, "/") != 0) {
+ /* Special case for directories--test for mount point. */
+- struct stat ddbuf;
+- char *fname;
++ char *fname;
+
+ /* Find start of last component of path. */
+ #if 1
+@@ -819,6 +846,19 @@
+ return (pseudo_inode(sbp->st_ino, sbp->st_dev));
+ }
+
++/*
++ * Match attributes to make sure we're still referring to the original file
++ */
++static inline int
++fh_attrmatch(struct fhcache *fhc, struct stat *attr)
++{
++ if (fhc->dev == attr->st_dev
++ && fhc->ino == attr->st_ino
++ && fhc->type == (attr->st_mode & S_IFMT))
++ return 1;
++ return 0;
++}
++
+ fhcache *
+ fh_find(svc_fh *h, int mode)
+ {
+@@ -838,6 +878,9 @@
+ ex_state = active;
+ time(&curtime);
+ while ((fhc = fh_lookup(h->psi)) != NULL) {
++ struct stat sbuf, *s = NULL;
++ nfsstat dummy;
++
+ Dprintf(D_FHCACHE, "fh_find: psi=%lx... found '%s', fd=%d\n",
+ (unsigned long) h->psi,
+ fhc->path ? fhc->path : "<unnamed>",
+@@ -857,33 +900,27 @@
+ * If it doesn't try to rebuild the path.
+ */
+ if (check) {
+- struct stat *s = &fhc->attrs;
+- psi_t psi;
+- nfsstat dummy;
+-
++ s = &sbuf;
+ if (efs_lstat(fhc->path, s) < 0) {
+ Dprintf(D_FHTRACE,
+ "fh_find: stale fh: lstat: %m\n");
+ } else {
+- fhc->flags |= FHC_ATTRVALID;
+- /* If pseudo-inos don't match, we fhc->path
+- * may be a mount point (hence lstat() returns
++ /* If device/ino don't match, fhc->path may
++ * be a mount point (hence lstat() returns
+ * a different inode number than the readdir()
+ * stuff used in path_psi)
+ */
+- psi = pseudo_inode(s->st_ino, s->st_dev);
+- if (h->psi == psi)
++ if (fh_attrmatch(fhc, s))
+ goto fh_return;
+
+- /* Try again by computing the path psi */
+- psi = path_psi(fhc->path, &dummy, s, 1);
+- if (h->psi == psi)
++ /* Get the dev/ino of the underlying
++ * mount point. */
++ path_psi(fhc->path, &dummy, s, 1);
++ if (fh_attrmatch(fhc, s))
+ goto fh_return;
+
+- Dprintf(D_FHTRACE, "fh_find: stale fh: "
+- "dev/ino %x/%lx psi %lx",
+- s->st_dev, s->st_ino,
+- (unsigned long) psi);
++ Dprintf(D_FHTRACE, "fh_find: stale fh: %lx",
++ (unsigned long) h->psi);
+ }
+
+ fh_discard:
+@@ -896,6 +933,12 @@
+ }
+
+ fh_return:
++ /* Valid attributes; cache them */
++ if (s != NULL) {
++ memcpy(&fhc->attrs, s, sizeof(*s));
++ fhc->flags |= FHC_ATTRVALID;
++ }
++
+ /* The cached fh seems valid */
+ if (fhc != fh_head.next)
+ fh_move_to_front(fhc);
+@@ -905,7 +948,8 @@
+ }
+
+ Dprintf(D_FHCACHE, "fh_find: psi=%lx... not found\n",
+- (unsigned long) h->psi);
++ (unsigned long) h->psi);
++
+ if (mode == FHFIND_FCACHED) {
+ ex_state = inactive;
+ return NULL;
+@@ -918,6 +962,7 @@
+ fhc = flush->prev;
+ fh_delete(flush);
+ }
++
+ fhc = (fhcache *) xmalloc(sizeof *fhc);
+ if (mode == FHFIND_FCREATE) {
+ /* File will be created */
+@@ -937,11 +982,31 @@
+ }
+ fhc->path = path;
+ }
++
+ fhc->flags = 0;
+ if (fhc->path && efs_lstat(fhc->path, &fhc->attrs) >= 0) {
+- if (re_export && nfsmounted(fhc->path, &fhc->attrs))
++ if (nfsmounted(fhc->path, &fhc->attrs)) {
+ fhc->flags |= FHC_NFSMOUNTED;
++#if 0
++ /* We must allow the client to send us the
++ * file handle for the NFS mount point itself,
++ * but not for entries within an NFS mount.
++ * XXX: needs fixing.
++ */
++ if (!re_export) {
++ Dprintf(D_FHTRACE,
++ "Attempt to use %s (non-exportable)\n",
++ fhc->path);
++ free(fhc);
++ ex_state = inactive;
++ return NULL;
++ }
++#endif
++ }
+ fhc->flags |= FHC_ATTRVALID;
++ fhc->dev = fhc->attrs.st_dev;
++ fhc->ino = fhc->attrs.st_ino;
++ fhc->type = fhc->attrs.st_mode & S_IFMT;
+ }
+ fhc->fd = -1;
+ fhc->last_used = curtime;
+@@ -993,6 +1058,14 @@
+ return buf;
+ }
+
++static void
++fh_complain(const char *msg, fhcache *fhc)
++{
++ Dprintf(L_ERROR, "%s: ptr=%p fd=%d path=%s\n", msg,
++ fhc, fhc->fd,
++ fhc->path? fhc->path : "<unnamed>");
++}
++
+ /*
+ * This routine is only used by the mount daemon.
+ * It creates the initial file handle.
+@@ -1000,23 +1073,25 @@
+ int
+ fh_create(nfs_fh *fh, char *path)
+ {
+- svc_fh key;
+- fhcache *h;
+- psi_t psi;
+- nfsstat status;
+- char *s;
++ struct stat stb;
++ svc_fh key;
++ fhcache *h;
++ psi_t psi;
++ nfsstat status;
++ char *s;
+
+ memset(&key, 0, sizeof(key));
+ status = NFS_OK;
+- if ((psi = path_psi("/", &status, NULL, 0)) == 0)
++ if ((psi = path_psi("/", &status, &stb, 0)) == 0)
+ return ((int) status);
++
+ s = path;
+ while ((s = strchr(s + 1, '/')) != NULL) {
+ if (++(key.hash_path[0]) >= HP_LEN)
+ return ((int) NFSERR_NAMETOOLONG);
+ key.hash_path[key.hash_path[0]] = hash_psi(psi);
+ *s = '\0';
+- if ((psi = path_psi(path, &status, NULL, 0)) == 0)
++ if ((psi = path_psi(path, &status, &stb, 0)) == 0)
+ return ((int) status);
+ *s = '/';
+ }
+@@ -1024,7 +1099,7 @@
+ if (++(key.hash_path[0]) >= HP_LEN)
+ return ((int) NFSERR_NAMETOOLONG);
+ key.hash_path[key.hash_path[0]] = hash_psi(psi);
+- if ((psi = path_psi(path, &status, NULL, 0)) == 0)
++ if ((psi = path_psi(path, &status, &stb, 0)) == 0)
+ return ((int) status);
+ }
+ key.psi = psi;
+@@ -1037,9 +1112,12 @@
+
+ /* assert(h != NULL); */
+ if (h->path == NULL) {
+- h->fd = -1;
+- h->path = xstrdup(path);
++ h->fd = -1;
++ h->path = xstrdup(path);
+ h->flags = 0;
++ h->dev = stb.st_dev;
++ h->ino = stb.st_ino;
++ h->type = stb.st_mode & S_IFMT;
+ }
+ memcpy(fh, &key, sizeof(key));
+ return ((int) status);
+@@ -1064,6 +1142,44 @@
+ return ((nfs_fh*)&(h->h));
+ }
+
++
++static inline int
++access_override(int omode, int perm, struct stat *buf)
++{
++ /* Be suspicous of flags, particularly O_CREAT/O_TRUNC. A previous
++ * comment said:
++ *
++ * "[Not checking this] would truncate read-only files on creat()
++ * calls. Of course, ftruncate(fd, 0) should still be legal for
++ * the user when the file was chmoded *after* opening it, but we
++ * have no way to tell, and a semi-succeding `cp foo readonly-file'
++ * is much more unintuitive and destructive than a failing
++ * ftruncate()."
++ */
++ if (omode & ~O_ACCMODE)
++ return 0;
++
++ /* Users can do anything to their own files. Harmless (since they
++ * could chown anyway), and helps to mask NFSes statelessness.
++ *
++ * (in passing, this also handles mode 0100 execution)
++ */
++ if (buf->st_uid == auth_uid)
++ return 1;
++
++ /* Henceforth, we are considering granting read access to facilitate
++ * exec access. This is read only */
++ if (omode != O_RDONLY)
++ return 0;
++
++ /* Mode 0110 execution */
++ if (buf->st_gid == auth_gid)
++ return (buf->st_mode & S_IXGRP) != 0;
++
++ /* Mode 0111 execution */
++ return (buf->st_mode & S_IXOTH) != 0;
++}
++
+ int
+ path_open(char *path, int omode, int perm)
+ {
+@@ -1113,30 +1229,15 @@
+ * lishes two things: first, it gives the file owner r/w access to
+ * the file whatever the permissions are, so that files are still
+ * accessible after an fchown(fd, 0). The second part of the
+- * condition allows read access to mode 0111 executables.
+- *
+- * The old conditon read like this:
+- * if (fd < 0 && oerrno == EACCES) {
+- * if (oerrno == EACCES && (buf.st_uid == auth_uid
+- * || (omode == O_RDONLY && (buf.st_mode & S_IXOTH)))) {
+- * override uid; etc...
+- * }
+- * }
+- * This would truncate read-only files on creat() calls. Now
+- * ftruncate(fd, 0) should still be legal for the user when the
+- * file was chmoded *after* opening it, but we have no way to tell,
+- * and a semi-succeding `cp foo readonly-file' is much more
+- * unintuitive and destructive than a failing ftruncate().
++ * condition allows read access to `execute-only' files.
+ */
+- if (fd < 0 && oerrno == EACCES && !(omode & (O_CREAT|O_TRUNC))) {
+- if ((buf.st_uid == auth_uid && (omode & O_ACCMODE) == omode)
+- || ((buf.st_mode & S_IXOTH) && omode == O_RDONLY)) {
+- auth_override_uid(ROOT_UID);
+- fd = efs_open(path, omode, perm);
+- oerrno = errno;
+- auth_override_uid(auth_uid);
+- }
++ if (fd < 0 && oerrno == EACCES && access_override(omode, perm, &buf)) {
++ auth_override_uid(ROOT_UID);
++ fd = efs_open(path, omode, perm);
++ oerrno = errno;
++ auth_override_uid(auth_uid);
+ }
++
+
+ if (fd < 0) {
+ Dprintf(D_FHCACHE,
+@@ -1241,7 +1342,7 @@
+ char *sindx;
+ int is_dd;
+ nfsstat ret;
+- struct stat sbuf;
++ struct stat sbuf, smount;
+ char pathbuf[PATH_MAX + NAME_MAX + 1], *fname;
+
+ /* should not happen */
+@@ -1318,7 +1419,7 @@
+
+ *new_fh = dopa->dir;
+ key = (svc_fh *) new_fh;
+- if ((key->psi = path_psi(pathbuf, &ret, sbp, 0)) == 0)
++ if ((key->psi = path_psi_m(pathbuf, &ret, sbp, &smount, 0)) == 0)
+ return (ret);
+
+ if (is_dd) {
+@@ -1344,6 +1445,10 @@
+ h->h.hash_path[0]);
+ return NFSERR_STALE;
+ }
++ if (sbp->st_dev != smount.st_dev) {
++ Dprintf(D_FHTRACE, "fh_compose: %s hit%s mount point\n",
++ pathbuf, nfsmounted(pathbuf, &smount)? " NFS" : "");
++ }
+ #endif
+
+ /* New code added by Don Becker */
+@@ -1356,7 +1461,8 @@
+ if (!h) return NFSERR_STALE;
+ #endif
+ if (h->path)
+- Dprintf(L_ERROR, "Internal inconsistency: double entry (path '%s', now '%s').\n",
++ Dprintf(L_ERROR,
++ "internal inconsistency: double entry (path '%s', now '%s').\n",
+ h->path, pathbuf);
+ }
+ Dprintf(D_FHCACHE, "fh_compose: using handle %x ('%s', fd=%d)\n",
+@@ -1365,9 +1471,18 @@
+
+ /* assert(h != NULL); */
+ if (h->path == 0) {
+- h->path = xstrdup(pathbuf);
++ h->path = xstrdup(pathbuf);
+ h->flags = 0;
+- if (!re_export && nfsmounted(pathbuf, sbp))
++ h->dev = sbp->st_dev;
++ h->ino = sbp->st_ino;
++ h->type = sbp->st_mode & S_IFMT;
++
++ /* Note: in the case of a mount point,
++ * sbp contains the stats of the mount point, while
++ * ddbuf has the dev/ino of the underlying directory
++ */
++ if (sbp->st_dev != smount.st_dev
++ && nfsmounted(pathbuf, &smount))
+ h->flags |= FHC_NFSMOUNTED;
+ #ifdef FHTRACE
+ Dprintf(D_FHTRACE, "fh_compose: created handle %s\n", h->path);
+diff -urN nfs-server-2.2beta47/fh.h nfs-server-2.2beta51/fh.h
+--- nfs-server-2.2beta47/fh.h Mon Nov 23 12:15:43 1998
++++ nfs-server-2.2beta51/fh.h Fri Nov 8 14:45:36 2002
+@@ -97,7 +97,13 @@
+ struct fhcache * hash_next;
+ struct fhcache * fd_next;
+ struct fhcache * fd_prev;
++
++ /* These are fixed during the lifetime of this object */
+ svc_fh h;
++ dev_t dev;
++ ino_t ino;
++ mode_t type; /* st_mode & S_IFMT */
++
+ int fd;
+ int omode;
+ char * path;
+diff -urN nfs-server-2.2beta47/getattr.c nfs-server-2.2beta51/getattr.c
+--- nfs-server-2.2beta47/getattr.c Fri Oct 30 18:10:11 1998
++++ nfs-server-2.2beta51/getattr.c Fri Nov 8 14:45:36 2002
+@@ -115,6 +115,16 @@
+ attr->fsid = 1;
+ attr->fileid = fh_psi((nfs_fh *)&(fhc->h));
+ #endif
++
++ /* This may be needed by some Suns... testing */
++#define MINTIME (24 * 2600)
++ if (s->st_atime < MINTIME)
++ s->st_atime = MINTIME;
++ if (s->st_mtime < MINTIME)
++ s->st_mtime = MINTIME;
++ if (s->st_ctime < MINTIME)
++ s->st_ctime = MINTIME;
++
+ attr->atime.seconds = s->st_atime;
+ attr->atime.useconds = 0;
+ attr->mtime.seconds = s->st_mtime;
+diff -urN nfs-server-2.2beta47/logging.c nfs-server-2.2beta51/logging.c
+--- nfs-server-2.2beta47/logging.c Fri Oct 30 17:11:22 1998
++++ nfs-server-2.2beta51/logging.c Fri Nov 8 14:45:36 2002
+@@ -147,8 +147,9 @@
+ (void) time(&now);
+ tm = localtime(&now);
+ fprintf(log_fp, "%s %02d/%02d/%02d %02d:%02d %s",
+- log_name, tm->tm_mon + 1, tm->tm_mday, tm->tm_year,
+- tm->tm_hour, tm->tm_min, buff);
++ log_name, tm->tm_mon + 1, tm->tm_mday,
++ tm->tm_year % 100,
++ tm->tm_hour, tm->tm_min, buff);
+ if (strchr(buff, '\n') == NULL)
+ fputc('\n', log_fp);
+ }
+@@ -182,7 +183,8 @@
+ tm = localtime(&unix_cred->aup_time);
+ snprintf(buffer + len, total - len,
+ "%d/%d/%d %02d:%02d:%02d %s %d.%d",
+- tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
++ tm->tm_year %100,
++ tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec,
+ unix_cred->aup_machname,
+ unix_cred->aup_uid,
+diff -urN nfs-server-2.2beta47/mountd.c nfs-server-2.2beta51/mountd.c
+--- nfs-server-2.2beta47/mountd.c Wed Jun 2 14:10:33 1999
++++ nfs-server-2.2beta51/mountd.c Fri Nov 8 14:45:36 2002
+@@ -32,7 +32,7 @@
+ #include "rpcmisc.h"
+ #include "rmtab.h"
+ #include "haccess.h"
+-#include "failsafe.h"
++#include "daemon.h"
+ #include "signals.h"
+ #include <rpc/pmap_clnt.h>
+
+@@ -44,6 +44,8 @@
+ /*
+ * Option table for mountd
+ */
++#define OPT_NOTCP 300
++#define OPT_LOOPBACK 301
+ static struct option longopts[] =
+ {
+ { "debug", required_argument, 0, 'd' },
+@@ -56,6 +58,8 @@
+ { "no-spoof-trace", 0, 0, 't' },
+ { "version", 0, 0, 'v' },
+ { "fail-safe", optional_argument, 0, 'z' },
++ { "no-tcp", 0, 0, OPT_NOTCP },
++ { "loopback-only", 0, 0, OPT_LOOPBACK },
+
+ { NULL, 0, 0, 0 }
+ };
+@@ -358,6 +362,12 @@
+ break;
+ case 0:
+ break;
++ case OPT_NOTCP:
++ udp_only = 1;
++ break;
++ case OPT_LOOPBACK:
++ loopback_only = 1;
++ break;
+ case '?':
+ default:
+ usage(stderr, 1);
+@@ -384,38 +394,27 @@
+ /* Create services and register with portmapper */
+ rpc_init("mountd", MOUNTPROG, mountd_versions, mount_dispatch, port, 0);
+
+- if (!foreground && !_rpcpmstart) {
+-#ifndef RPC_SVC_FG
+- /* We first fork off a child. */
+- if ((c = fork()) > 0)
+- exit(0);
+- if (c < 0) {
+- Dprintf(L_FATAL, "mountd: cannot fork: %s\n",
+- strerror(errno));
+- }
+- /* No more logging to stderr */
+- background_logging();
++ if (_rpcpmstart) {
++ /* Always foreground mode */
++ foreground = 1;
+
+- /* Now we remove ourselves from the foreground. */
+- (void) close(0);
+- (void) close(1);
+- (void) close(2);
+-#ifdef TIOCNOTTY
+- if ((c = open("/dev/tty", O_RDWR)) >= 0) {
+- (void) ioctl(c, TIOCNOTTY, (char *) NULL);
+- (void) close(c);
+- }
+-#else
+- setsid();
+-#endif
+-#endif /* not RPC_SVC_FG */
++ /* ... but no logging */
++ background_logging();
+ }
+
++ /* Become a daemon */
++ if (!foreground)
++ daemonize();
++
+ /* Initialize the FH module. */
+ fh_init();
+
+ /* Initialize the AUTH module. */
+ auth_init(auth_file);
++
++ /* Write pidfile */
++ setpidpath(_PATH_MOUNTD_PIDFILE);
++ writepid(getpid(), 1);
+
+ /* Failsafe mode */
+ if (failsafe_level)
+diff -urN nfs-server-2.2beta47/mountd.man nfs-server-2.2beta51/mountd.man
+--- nfs-server-2.2beta47/mountd.man Wed Jun 2 14:12:21 1999
++++ nfs-server-2.2beta51/mountd.man Fri Nov 8 14:45:36 2002
+@@ -14,6 +14,8 @@
+ .B "[\ \-\-allow\-non\-root\ ]"
+ .B "[\ \-\-re\-export\ ]"
+ .B "[\ \-\-no\-spoof\-trace\ ]"
++.B "[\ \-\-no\-tcp ]"
++.B "[\ \-\-loopback\-only ]"
+ .B "[\ \-\-version\ ]"
+ .ad b
+ .SH DESCRIPTION
+@@ -123,6 +125,18 @@
+ .TP
+ .BR \-v " or " \-\-version
+ Report the current version number of the program.
++.TP
++.BR \-\-no\-tcp
++Force
++.I mountd
++to register only the UDP transport, but no TCP.
++This is an experimental option.
++.TP
++.BR \-\-loopback\-only
++Force
++.I mountd
++to bind to the loopback interface.
++This is an experimental option.
+ .SS Access Control
+ For enhanced security, access to
+ .I mountd
+diff -urN nfs-server-2.2beta47/nfsd.c nfs-server-2.2beta51/nfsd.c
+--- nfs-server-2.2beta47/nfsd.c Wed Nov 10 10:33:28 1999
++++ nfs-server-2.2beta51/nfsd.c Fri Nov 8 14:45:36 2002
+@@ -21,7 +21,7 @@
+ #include "getopt.h"
+ #include "fsusage.h"
+ #include "rpcmisc.h"
+-#include "failsafe.h"
++#include "daemon.h"
+ #include "signals.h"
+ #ifdef __linux__ /* XXX - MvS: for UNIX sockets. */
+ # include <sys/un.h>
+@@ -30,7 +30,6 @@
+ # include <syslog.h>
+ #endif
+
+-#define MULTIPLE_SERVERS
+
+ /* Flags for auth_fh */
+ #define CHK_READ 0
+@@ -51,6 +50,8 @@
+ /*
+ * Option table
+ */
++#define OPT_NOTCP 300
++#define OPT_LOOPBACK 301
+ static struct option longopts[] = {
+ { "auth-deamon", required_argument, 0, 'a' },
+ { "debug", required_argument, 0, 'd' },
+@@ -68,6 +69,9 @@
+ { "version", 0, 0, 'v' },
+ { "no-cross-mounts", 0, 0, 'x' },
+ { "fail-safe", optional_argument, 0, 'z' },
++ { "no-tcp", 0, 0, OPT_NOTCP },
++ { "udp-only", 0, 0, OPT_NOTCP },
++ { "loopback-only", 0, 0, OPT_LOOPBACK },
+
+ { NULL, 0, 0, 0 }
+ };
+@@ -173,7 +177,10 @@
+ return NULL;
+ }
+
+- auth_user(nfsmount, rqstp);
++ if (!auth_user(nfsmount, rqstp)) {
++ *statp = NFSERR_ACCES;
++ return NULL;
++ }
+
+ *statp = NFS_OK;
+ return fhc;
+@@ -211,7 +218,11 @@
+
+ if ((nfsmount = auth_path(nfsclient, rqstp, path)) == NULL)
+ return NFSERR_ACCES;
+- auth_user(nfsmount, rqstp);
++
++ /* XXX: really need to call it again here?
++ * Already invoked in auth_fh */
++ if (!auth_user(nfsmount, rqstp))
++ return NFSERR_ACCES;
+
+ return (NFS_OK);
+ }
+@@ -575,7 +586,8 @@
+ #endif
+
+ /* MvS: Some clients use chardev 0xFFFF for a FIFO. */
+- if (S_ISCHR(argp->attributes.mode) && dev == 0xFFFF) {
++ if (S_ISCHR(argp->attributes.mode)
++ && (dev == 0xFFFF || dev == (dev_t) -1)) {
+ is_borc = 0;
+ dev = 0;
+ argp->attributes.mode &= ~S_IFMT;
+@@ -623,7 +635,7 @@
+ flags = (argp->attributes.size == 0 ?
+ CREATE_OMODE | O_TRUNC : CREATE_OMODE);
+ if (!exists)
+- flags |= O_CREAT;
++ flags |= O_CREAT|O_EXCL;
+ tmpfd = path_open(pathbuf, flags,
+ argp->attributes.mode & ~S_IFMT);
+ if (tmpfd < 0)
+@@ -965,9 +977,7 @@
+ int nfsport = 0;
+ int failsafe_level = 0;
+ int c;
+-#ifdef MULTIPLE_SERVERS
+ int i, ncopies = 1;
+-#endif
+
+ program_name = argv[0];
+ chdir("/");
+@@ -1031,12 +1041,17 @@
+ break;
+ case 0:
+ break;
++ case OPT_NOTCP:
++ udp_only = 1;
++ break;
++ case OPT_LOOPBACK:
++ loopback_only = 1;
++ break;
+ case '?':
+ default:
+ usage(stderr, 1);
+ }
+
+-#ifdef MULTIPLE_SERVERS
+ if (optind == argc-1 && isdigit(argv[optind][0])) {
+ ncopies = atoi(argv[optind++]);
+ if (ncopies <= 0) {
+@@ -1051,7 +1066,6 @@
+ ncopies = 1;
+ }
+ }
+-#endif
+
+ /* No more arguments allowed. */
+ if (optind != argc)
+@@ -1075,72 +1089,54 @@
+ rpc_init("nfsd", NFS_PROGRAM, nfsd_versions, nfs_dispatch,
+ nfsport, NFS_MAXDATA);
+
+- /* No more than 1 copy when run from inetd */
+- if (_rpcpmstart && ncopies > 1) {
+- Dprintf(L_WARNING,
+- "nfsd: warning: can run only "
+- "one server in inetd mode\n");
+- ncopies = 1;
++ if (_rpcpmstart) {
++ /* Always do foreground mode */
++ foreground = 1;
++
++ /* ... but don't log to stderr */
++ background_logging();
++
++ /* No more than 1 copy when run from inetd */
++ if (ncopies > 1) {
++ Dprintf(L_WARNING,
++ "nfsd: warning: can run only "
++ "one server in inetd mode\n");
++ ncopies = 1;
++ }
+ }
+
+-#ifndef MULTIPLE_SERVERS_READWRITE
+ if (ncopies > 1)
+ read_only = 1;
+-#endif
+
+- /* We first fork off a child. */
+- if (!foreground) {
+- if ((c = fork()) > 0)
+- exit(0);
+- if (c < 0) {
+- Dprintf(L_FATAL, "nfsd: cannot fork: %s\n",
+- strerror(errno));
+- }
+- }
++ /*
++ * We first fork off a child and detach from tty
++ */
++ if (!foreground)
++ daemonize();
+
+ /* Initialize the AUTH module. */
+ auth_init(auth_file);
+
++ setpidpath(_PATH_NFSD_PIDFILE);
+ if (failsafe_level == 0) {
+ /* Start multiple copies of the server */
++ writepid(getpid(), 1);
+ for (i = 1; i < ncopies; i++) {
++ pid_t pid;
++
+ Dprintf(D_GENERAL, "Forking server thread...\n");
+- if ((c = fork()) < 0) {
++ if ((pid = fork()) < 0) {
+ Dprintf(L_ERROR, "Unable to fork: %s",
+ strerror(errno));
+- } else if (c == 0) {
+- /* Child process */
+- break;
++ } else if (pid != 0) {
++ writepid(pid, 0);
++ } else {
++ break; /* Child process */
+ }
+ }
+ } else {
+ /* Init for failsafe mode */
+ failsafe(failsafe_level, ncopies);
+- }
+-
+- /* Now that we've done all the required forks, we make do all the
+- * session magic.
+- */
+- if (!foreground) {
+- /* No more logging to stderr */
+- background_logging();
+-
+- /* Now we remove ourselves from the foreground. */
+- close(0);
+- close(1);
+- close(2);
+-#ifdef HAVE_SETSID
+- setsid();
+-#else
+- {
+- int fd;
+-
+- if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
+- ioctl(fd, TIOCNOTTY, (char *) NULL);
+- close(fd);
+- }
+- }
+-#endif
+ }
+
+ /*
+diff -urN nfs-server-2.2beta47/nfsd.man nfs-server-2.2beta51/nfsd.man
+--- nfs-server-2.2beta47/nfsd.man Wed Jun 2 14:13:37 1999
++++ nfs-server-2.2beta51/nfsd.man Fri Nov 8 14:45:36 2002
+@@ -8,7 +8,7 @@
+ .B "[\ \-d\ facility\ ]"
+ .B "[\ \-P\ port\ ]"
+ .B "[\ \-R\ dirname\ ]"
+-.B "[\ \-Fhlnprstv\ ]"
++.B "[\ \-Fhlnprstuv\ ]"
+ .B "[\ \-\-debug\ facility\ ]"
+ .B "[\ \-\-exports\-file=file\ ]"
+ .B "[\ \-\-foreground\ ]"
+@@ -18,6 +18,8 @@
+ .B "[\ \-\-public\-root\ dirname\ ]"
+ .\".B "[\ \-\-synchronous\-writes\ ]"
+ .B "[\ \-\-no\-spoof\-trace\ ]"
++.B "[\ \-\-no\-tcp ]"
++.B "[\ \-\-loopback-only ]"
+ .B "[\ \-\-port\ port\ ]"
+ .B "[\ \-\-log-transfers\ ]"
+ .B "[\ \-\-version\ ]"
+@@ -56,7 +58,7 @@
+ .PP
+ When run from
+ .IR inetd ,
+-.i nfsd
++.I nfsd
+ will terminate after a certain period of inactivity.
+ .SH OPTIONS
+ .TP
+@@ -167,6 +169,14 @@
+ .BR \-v " or " \-\-version
+ Report the current version number of the program.
+ .TP
++.BR \-\-no\-tcp
++Force nfsd to only register a UDP transport, but not TCP.
++This is an experimental option.
++.TP
++.BR \-\-loopback\-only
++Force nfsd to bind to the loopback interface.
++This is an experimental option.
++.TP
+ .BR numcopies
+ This is an experimental feature that lets you run several instances of
+ .I nfsd
+@@ -174,15 +184,8 @@
+ .B numcopies
+ greater than one,
+ .I nfsd
+-will fork as many times as specified by this value.
+-However, the servers do not share a common file handle
+-cache, which makes certain file operations impossible.
+-.IP
+-For this reason,
+-.I nfsd
+-will disallow all write operations when invoked with this option. Although
+-this is very limiting, this feature may still prove useful for exporting
+-public FTP areas or Usenet News spools.
++will fork as many times as specified by this value so it is able to
++handle that many NFS requests in parallel.
+ .SS WebNFS Support
+ WebNFS is an extension to the normal NFS protocol developed by Sun
+ that is particularly well-suited for file retrieval over the
+@@ -268,6 +271,19 @@
+ .I nfsd
+ writes out a transfer record whenever it encounters a READ or WRITE
+ request at offset zero.
++.SS Generating a debug trace
++When suspecting a bug in nfsd, it is helpful to look at a debug trace
++of what's going on. You can create such a trace by first killing nfsd,
++and then restarting it as
++.PP
++.nf
++.ta +3i
++/usr/sbin/rpc.nfsd -F -d all
++.fi
++.PP
++Instead of
++.BR all ,
++you can use less verbose debug facilities as described above.
+ .SH "SEE ALSO"
+ exports(5), mountd(8), ugidd(8C)
+ .SH AUTHORS
+diff -urN nfs-server-2.2beta47/rmtab.c nfs-server-2.2beta51/rmtab.c
+--- nfs-server-2.2beta47/rmtab.c Fri Feb 6 09:43:25 1998
++++ nfs-server-2.2beta51/rmtab.c Fri Nov 8 14:45:36 2002
+@@ -8,6 +8,7 @@
+
+ #include "nfsd.h"
+ #include "rmtab.h"
++#include "rpcmisc.h"
+
+ static char * rmtab_gethost(struct svc_req *);
+ static int rmtab_insert(char *, char *);
+diff -urN nfs-server-2.2beta47/rpcmisc.c nfs-server-2.2beta51/rpcmisc.c
+--- nfs-server-2.2beta47/rpcmisc.c Tue Sep 7 10:42:58 1999
++++ nfs-server-2.2beta51/rpcmisc.c Fri Nov 8 14:45:36 2002
+@@ -39,6 +39,8 @@
+ int _rpcfdtype = 0;
+ int _rpcsvcdirty = 0;
+ const char * auth_daemon = 0;
++int udp_only = 0;
++int loopback_only = 0;
+
+ #ifdef AUTH_DAEMON
+ static bool_t (*tcp_rendevouser)(SVCXPRT *, struct rpc_msg *);
+@@ -96,7 +98,7 @@
+ }
+ }
+
+- if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) {
++ if ((_rpcfdtype == 0 && !udp_only) || (_rpcfdtype == SOCK_STREAM)) {
+ if (_rpcfdtype == 0 && defport != 0)
+ sock = makesock(defport, IPPROTO_TCP, bufsiz);
+ transp = svctcp_create(sock, 0, 0);
+@@ -199,6 +201,9 @@
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = INADDR_ANY;
+ sin.sin_port = htons(port);
++
++ if (loopback_only)
++ sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ #ifdef DEBUG
+ {
+diff -urN nfs-server-2.2beta47/rpcmisc.h nfs-server-2.2beta51/rpcmisc.h
+--- nfs-server-2.2beta47/rpcmisc.h Tue Sep 7 10:37:38 1999
++++ nfs-server-2.2beta51/rpcmisc.h Fri Nov 8 14:45:36 2002
+@@ -9,6 +9,8 @@
+ extern int _rpcpmstart;
+ extern int _rpcfdtype;
+ extern int _rpcsvcdirty;
++extern int udp_only;
++extern int loopback_only;
+ extern const char * auth_daemon;
+
+ extern void rpc_init(const char *name, int prog, int *verstbl,
+@@ -16,5 +18,13 @@
+ int defport, int bufsize);
+ extern void rpc_exit(int prog, int *verstbl);
+ extern void rpc_closedown(void);
++
++/*
++ * Some older systems don't have svc_getcaller.
++ * Some, like glibc 2.2, have it but it returns some type that's
++ * not a sockaddr_in anymore.
++ */
++#undef svc_getcaller
++#define svc_getcaller(xprt) ((struct sockaddr_in *) (&(xprt)->xp_raddr))
+
+ #endif /* RPCMISC_H */
+diff -urN nfs-server-2.2beta47/setattr.c nfs-server-2.2beta51/setattr.c
+--- nfs-server-2.2beta47/setattr.c Fri Oct 30 18:29:42 1998
++++ nfs-server-2.2beta51/setattr.c Fri Nov 8 14:45:36 2002
+@@ -103,6 +103,10 @@
+ if (flags & SATTR_CHMOD) {
+ unsigned int mode = attr->mode;
+
++ /* If setuid is not allowed, silently squash them */
++ if (!nfsmount->o.allow_setuid && S_ISREG(s->st_mode))
++ mode &= ~(S_ISUID|S_ISGID) | s->st_mode;
++
+ if (mode != -1 && mode != 0xFFFF /* ultrix bug */
+ && (mode & 07777) != (s->st_mode & 07777)) {
+ if (efs_chmod(path, mode) < 0)
+diff -urN nfs-server-2.2beta47/showmount.c nfs-server-2.2beta51/showmount.c
+--- nfs-server-2.2beta47/showmount.c Wed Jun 12 22:31:04 1996
++++ nfs-server-2.2beta51/showmount.c Fri Nov 8 14:45:36 2002
+@@ -162,17 +162,13 @@
+ break;
+ }
+
+- if (hostname[0] >= '0' && hostname[0] <= '9') {
+- server_addr.sin_family = AF_INET;
+- server_addr.sin_addr.s_addr = inet_addr(hostname);
+- }
+- else {
++ server_addr.sin_family = AF_INET;
++ if (!inet_aton(hostname, &server_addr.sin_addr)) {
+ if ((hp = gethostbyname(hostname)) == NULL) {
+ fprintf(stderr, "%s: can't get address for %s\n",
+ program_name, hostname);
+ exit(1);
+ }
+- server_addr.sin_family = AF_INET;
+ memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
+ }
+
+diff -urN nfs-server-2.2beta47/site.h.in nfs-server-2.2beta51/site.h.in
+--- nfs-server-2.2beta47/site.h.in Thu Jan 1 01:00:00 1970
++++ nfs-server-2.2beta51/site.h.in Fri Nov 8 14:45:57 2002
+@@ -0,0 +1,50 @@
++/*
++ * Site-specific configuration options generated by BUILD.
++ * Please do not edit.
++ */
++
++/*
++ * If ENABLE_DEVTAB is defined, nfsd will use the new inode
++ * number generation scheme for avoiding inode number clashes
++ * on big hard disks.
++ */
++#undef ENABLE_DEVTAB
++
++/*
++ * If MULTIPLE_SERVER_READWRITE is defined, you will be able
++ * to run several nfsd process in parallel servicing all NFS
++ * requests.
++ */
++#define MULTIPLE_SERVERS_READWRITE
++
++/*
++ * If ENABLE_UGID_DAEMON is defined, the real rpc.ugidd is built,
++ * nfsd is built to support ugidd queries.
++ * Otherwise, a dummy program is created
++ */
++#undef ENABLE_UGID_DAEMON
++
++/*
++ * If ENABLE_UGID_NIS is defined, nfsd will support user mapping
++ * vie the client's NIS server.
++ */
++#undef ENABLE_UGID_NIS
++
++/*
++ * if HOSTS_ACCESS is defined, ugidd uses host access control
++ * provided by libwrap.a from tcp_wrappers
++ */
++#define HOSTS_ACCESS
++
++/*
++ * Define correct ownership of export control file
++ */
++#define EXPORTSOWNERUID 0
++#define EXPORTSOWNERGID 0
++
++/*
++ * If WANT_LOG_MOUNTS is defined, every mount request will be logged
++ * to syslogd with the name of source site and a path that was
++ * it requested
++ */
++#define WANT_LOG_MOUNTS
+diff -urN nfs-server-2.2beta47/ugidd.c nfs-server-2.2beta51/ugidd.c
+--- nfs-server-2.2beta47/ugidd.c Wed Dec 10 12:34:16 1997
++++ nfs-server-2.2beta51/ugidd.c Fri Nov 8 14:45:36 2002
+@@ -43,9 +43,7 @@
+ };
+
+ int
+-main(argc, argv)
+-int argc;
+-char **argv;
++main(int argc, char **argv)
+ {
+ SVCXPRT *transp;
+ int c, longind;
+@@ -92,32 +90,11 @@
+ exit(1);
+ }
+
+- if (!foreground) {
+- if ((c = fork()) > 0)
+- exit(0);
+- if (c < 0) {
+- fprintf(stderr, "ugidd: cannot fork: %s\n",
+- strerror(errno));
+- exit(-1);
+- }
+- close(0);
+- close(1);
+- close(2);
+-#ifdef HAVE_SETSID
+- setsid();
+-#else
+- {
+- int fd;
+-
+- if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
+- ioctl(fd, TIOCNOTTY, (char *) NULL);
+- close(fd);
+- }
+- }
+-#endif
+- }
+-
+ log_open("ugidd", foreground);
++
++ /* Become a daemon */
++ if (!foreground)
++ daemonize();
+
+ svc_run();
+ Dprintf(L_ERROR, "svc_run returned\n");
+diff -urN nfs-server-2.2beta47/version.c nfs-server-2.2beta51/version.c
+--- nfs-server-2.2beta47/version.c Wed Nov 10 10:33:33 1999
++++ nfs-server-2.2beta51/version.c Fri Nov 8 14:45:36 2002
+@@ -1 +1 @@
+-char version[] = "Universal NFS Server 2.2beta47";
++char version[] = "Universal NFS Server 2.2beta51";
OpenPOWER on IntegriCloud