diff options
Diffstat (limited to 'meta/recipes-devtools/unfs-server/unfs-server-2.1+2.2beta47/001-2.2b47-2.2b51.patch')
-rw-r--r-- | meta/recipes-devtools/unfs-server/unfs-server-2.1+2.2beta47/001-2.2b47-2.2b51.patch | 2344 |
1 files changed, 2344 insertions, 0 deletions
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.1+2.2beta47/001-2.2b47-2.2b51.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.1+2.2beta47/001-2.2b47-2.2b51.patch new file mode 100644 index 0000000000..886ce92b34 --- /dev/null +++ b/meta/recipes-devtools/unfs-server/unfs-server-2.1+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"; |