program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.61 for linux nfs-utils 1.1.3.
+# Generated by GNU Autoconf 2.61 for linux nfs-utils 1.1.4.
#
# Report bugs to <linux-nfs@vger.kernel.org>.
#
# Identity of this package.
PACKAGE_NAME='linux nfs-utils'
PACKAGE_TARNAME='nfs-utils'
-PACKAGE_VERSION='1.1.3'
-PACKAGE_STRING='linux nfs-utils 1.1.3'
+PACKAGE_VERSION='1.1.4'
+PACKAGE_STRING='linux nfs-utils 1.1.4'
PACKAGE_BUGREPORT='linux-nfs@vger.kernel.org'
ac_default_prefix=/usr
CONFIG_GSS_TRUE
CONFIG_GSS_FALSE
kprefix
-secure_statd
RPCGEN_PATH
CONFIG_RPCGEN_TRUE
CONFIG_RPCGEN_FALSE
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures linux nfs-utils 1.1.3 to adapt to many kinds of systems.
+\`configure' configures linux nfs-utils 1.1.4 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of linux nfs-utils 1.1.3:";;
+ short | recursive ) echo "Configuration of linux nfs-utils 1.1.4:";;
esac
cat <<\_ACEOF
--enable-nfsv4 enable support for NFSv4 [default=yes]
--enable-gss enable support for rpcsec_gss [default=yes]
--enable-kprefix install progs as rpc.knfsd etc
- --enable-secure-statd Only lockd can use statd (security)
--without-uuid Exclude uuid support and so avoid possibly buggy
libblkid
--enable-mount Create mount.nfs and don't use the util-linux
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-linux nfs-utils configure 1.1.3
+linux nfs-utils configure 1.1.4
generated by GNU Autoconf 2.61
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by linux nfs-utils $as_me 1.1.3, which was
+It was created by linux nfs-utils $as_me 1.1.4, which was
generated by GNU Autoconf 2.61. Invocation command line was
$ $0 $@
# Define the identity of the package.
PACKAGE='nfs-utils'
- VERSION='1.1.3'
+ VERSION='1.1.4'
cat >>confdefs.h <<_ACEOF
fi
-# Check whether --enable-secure-statd was given.
-if test "${enable_secure_statd+set}" = set; then
- enableval=$enable_secure_statd; test "$enableval" = "yes" && secure_statd=yes
-else
- secure_statd=yes
-fi
-
- if test "$secure_statd" = yes; then
-
-cat >>confdefs.h <<\_ACEOF
-#define RESTRICTED_STATD 1
-_ACEOF
-
- fi
-
# Check whether --with-rpcgen was given.
if test "${with_rpcgen+set}" = set; then
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 6724 "configure"' > conftest.$ac_ext
+ echo '#line 6707 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:8765: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:8748: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:8769: \$? = $ac_status" >&5
+ echo "$as_me:8752: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:9055: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:9038: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:9059: \$? = $ac_status" >&5
+ echo "$as_me:9042: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:9159: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:9142: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:9163: \$? = $ac_status" >&5
+ echo "$as_me:9146: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 11510 "configure"
+#line 11493 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 11610 "configure"
+#line 11593 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:14030: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:14013: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:14034: \$? = $ac_status" >&5
+ echo "$as_me:14017: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:14134: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:14117: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:14138: \$? = $ac_status" >&5
+ echo "$as_me:14121: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:15698: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:15681: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:15702: \$? = $ac_status" >&5
+ echo "$as_me:15685: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:15802: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:15785: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:15806: \$? = $ac_status" >&5
+ echo "$as_me:15789: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:17991: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:17974: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:17995: \$? = $ac_status" >&5
+ echo "$as_me:17978: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:18281: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:18264: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:18285: \$? = $ac_status" >&5
+ echo "$as_me:18268: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:18385: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:18368: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:18389: \$? = $ac_status" >&5
+ echo "$as_me:18372: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by linux nfs-utils $as_me 1.1.3, which was
+This file was extended by linux nfs-utils $as_me 1.1.4, which was
generated by GNU Autoconf 2.61. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
-linux nfs-utils config.status 1.1.3
+linux nfs-utils config.status 1.1.4
configured by $0, generated by GNU Autoconf 2.61,
with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
CONFIG_GSS_TRUE!$CONFIG_GSS_TRUE$ac_delim
CONFIG_GSS_FALSE!$CONFIG_GSS_FALSE$ac_delim
kprefix!$kprefix$ac_delim
-secure_statd!$secure_statd$ac_delim
RPCGEN_PATH!$RPCGEN_PATH$ac_delim
CONFIG_RPCGEN_TRUE!$CONFIG_RPCGEN_TRUE$ac_delim
CONFIG_RPCGEN_FALSE!$CONFIG_RPCGEN_FALSE$ac_delim
CC!$CC$ac_delim
CFLAGS!$CFLAGS$ac_delim
LDFLAGS!$LDFLAGS$ac_delim
+CPPFLAGS!$CPPFLAGS$ac_delim
_ACEOF
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
ac_delim='%!_!# '
for ac_last_try in false false false false false :; do
cat >conf$$subs.sed <<_ACEOF
-CPPFLAGS!$CPPFLAGS$ac_delim
ac_ct_CC!$ac_ct_CC$ac_delim
EXEEXT!$EXEEXT$ac_delim
OBJEXT!$OBJEXT$ac_delim
LTLIBOBJS!$LTLIBOBJS$ac_delim
_ACEOF
- if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 62; then
+ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 61; then
break
elif $ac_last_try; then
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
dnl Process this file with autoconf to produce a configure script.
dnl
-AC_INIT([linux nfs-utils],[1.1.3],[linux-nfs@vger.kernel.org],[nfs-utils])
+AC_INIT([linux nfs-utils],[1.1.4],[linux-nfs@vger.kernel.org],[nfs-utils])
AC_CANONICAL_BUILD([])
AC_CANONICAL_HOST([])
AC_CONFIG_MACRO_DIR(aclocal)
test "$enableval" = "yes" && kprefix=k,
kprefix=)
AC_SUBST(kprefix)
-AC_ARG_ENABLE(secure-statd,
- [AC_HELP_STRING([--enable-secure-statd],
- [Only lockd can use statd (security)])],
- test "$enableval" = "yes" && secure_statd=yes,
- secure_statd=yes)
- if test "$secure_statd" = yes; then
- AC_DEFINE(RESTRICTED_STATD, 1, [Define this if you want to enable various security checks in statd. These checks basically keep anyone but lockd from using this service.])
- fi
- AC_SUBST(secure_statd)
AC_ARG_WITH(rpcgen,
[AC_HELP_STRING([--with-rpcgen=internal], [use internal rpcgen instead of system one])],
rpcgen_path=$withval,
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
}
client_freeall();
}
-
-void
-export_reset(nfs_export *exp)
-{
- if (!exp)
- return;
-
- /* Restore m_path. */
- strncpy(exp->m_export.m_path, exp->m_export.e_path,
- sizeof (exp->m_export.m_path) - 1);
- exp->m_export.m_path[sizeof (exp->m_export.m_path) - 1] = '\0';
-}
nfs_client *clp = exp->m_client;
struct stat stb;
- if (stat(exp->m_export.m_path, &stb) < 0)
+ if (stat(exp->m_export.e_path, &stb) < 0)
return 0;
memset(exparg, 0, sizeof(*exparg));
- strncpy(exparg->ex_path, exp->m_export.m_path,
+ strncpy(exparg->ex_path, exp->m_export.e_path,
sizeof (exparg->ex_path) - 1);
strncpy(exparg->ex_client, clp->m_hostname,
sizeof (exparg->ex_client) - 1);
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
/* Define to the version of this package. */
#undef PACKAGE_VERSION
-/* Define this if you want to enable various security checks in statd. These
- checks basically keep anyone but lockd from using this service. */
-#undef RESTRICTED_STATD
-
/* Define as the return type of signal handlers (`int' or `void'). */
#undef RETSIGTYPE
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
struct exportent {
char * e_hostname;
char e_path[NFS_MAXPATHLEN+1];
- /* The mount path may be different from the exported path due
- to submount. It may change for every mount. The idea is we
- set m_path every time when we process a mount. We should not
- use it for anything else. */
- char m_path[NFS_MAXPATHLEN+1];
int e_flags;
int e_anonuid;
int e_anongid;
}
-int makesock(int port, int proto);
void rpc_init(char *name, int prog, int vers,
void (*dispatch)(struct svc_req *, SVCXPRT *),
int defport);
-void rpc_svcrun(void);
void rpc_dispatch(struct svc_req *rq, SVCXPRT *xprt,
struct rpc_dtable *dtable, int nvers,
void *argp, void *resp);
-void rpc_logcall(struct svc_req *, char *xname, char *args);
extern int _rpcpmstart;
extern int _rpcfdtype;
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
if (ok <= 0)
return NULL;
- strncpy (def_ee.m_path, def_ee.e_path, sizeof (def_ee.m_path) - 1);
- def_ee.m_path [sizeof (def_ee.m_path) - 1] = '\0';
ok = getexport(exp, sizeof(exp));
}
if (ok < 0) {
rpath[sizeof (rpath) - 1] = '\0';
strncpy(ee.e_path, rpath, sizeof (ee.e_path) - 1);
ee.e_path[sizeof (ee.e_path) - 1] = '\0';
- strncpy (ee.m_path, ee.e_path, sizeof (ee.m_path) - 1);
- ee.m_path [sizeof (ee.m_path) - 1] = '\0';
}
return ⅇ
}
strncpy(ee.e_path, path, sizeof (ee.e_path));
ee.e_path[sizeof (ee.e_path) - 1] = '\0';
- strncpy (ee.m_path, ee.e_path, sizeof (ee.m_path) - 1);
- ee.m_path [sizeof (ee.m_path) - 1] = '\0';
if (parseopts(options, &ee, 0, NULL) < 0)
return NULL;
return ⅇ
if (opt[5]!='\0' && *oe == '\0')
ep->e_flags |= NFSEXP_FSID;
else if (valid_uuid(opt+5))
- ep->e_uuid = strdup(opt+7);
+ ep->e_uuid = strdup(opt+5);
else {
xlog(L_ERROR, "%s: %d: bad fsid \"%s\"\n",
flname, flline, opt);
exit (2);
}
}
-
-#if 0
-/*
- * This is our replacement for svc_run. It turns off some signals while
- * executing the server procedures to avoid nasty race conditions.
- */
-void
-rpc_svcrun(fd_set *morefds, void (*func)(int fd))
-{
- sigset_t block, current;
- fd_set readfds;
-
- for (;;) {
- readfds = svc_fdset;
- if (morefds) {
- int i;
-
- /* most efficient */
- for (i = 0; i < FD_SETSIZE; i++)
- if (FD_ISSET(i, morefds))
- FD_SET(i, &readfs);
- }
- switch (select(FD_SETSIZE, &readfds, NULL, NULL, NULL)) {
- case -1:
- if (errno == EINTR)
- continue;
- xlog(L_ERROR, "svc_run: - select failed");
- break;
- case 0:
- continue;
- default:
- if (morefds) {
- int i;
-
- /* most efficient */
- for (i = 0; i < FD_SETSIZE; i++)
- if (FD_ISSET(i, morefds) &&
- FD_ISSET(i, &readfds))
- func(i);
- }
- sigemptyset(&block);
- sigaddset(&block, SIGALRM);
- sigaddset(&block, SIGVTALRM);
- sigaddset(&block, SIGIO);
- sigprocmask(SIG_BLOCK, &block, ¤t);
- svc_getreqset(&readfds);
- sigprocmask(SIG_SETMASK, ¤t, NULL);
- }
- }
-}
-#endif
/*
- * support/nfs/rpcmisc.c
+ * Miscellaneous functions for RPC service startup and shutdown.
*
- * Miscellaneous functions for RPC startup and shutdown.
* This code is partially snarfed from rpcgen -s tcp -s udp,
- * partly written by Mark Shand, Donald Becker, and Rick
+ * partly written by Mark Shand, Donald Becker, and Rick
* Sladkey. It was tweaked slightly by Olaf Kirch to be
* usable by both unfsd and mountd.
*
#define socklen_t int
#endif
-static void closedown(int sig);
-int makesock(int port, int proto);
-
#define _RPCSVC_CLOSEDOWN 120
int _rpcpmstart = 0;
int _rpcfdtype = 0;
int _rpcsvcdirty = 0;
+static void
+closedown(int sig)
+{
+ (void) signal(sig, closedown);
+
+ if (_rpcsvcdirty == 0) {
+ static int size;
+ int i, openfd;
+
+ if (_rpcfdtype == SOCK_DGRAM)
+ exit(0);
+
+ if (size == 0)
+ size = getdtablesize();
+
+ for (i = 0, openfd = 0; i < size && openfd < 2; i++)
+ if (FD_ISSET(i, &svc_fdset))
+ openfd++;
+ if (openfd <= 1)
+ exit(0);
+ }
+
+ (void) alarm(_RPCSVC_CLOSEDOWN);
+}
+
+/*
+ * Create listener socket for a given port
+ *
+ * Return an open network socket on success; otherwise return -1
+ * if some error occurs.
+ */
+static int
+makesock(int port, int proto)
+{
+ struct sockaddr_in sin;
+ int sock, sock_type, val;
+
+ sock_type = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
+ sock = socket(AF_INET, sock_type, proto);
+ if (sock < 0) {
+ xlog(L_FATAL, "Could not make a socket: %s",
+ strerror(errno));
+ return -1;
+ }
+ memset((char *) &sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(INADDR_ANY);
+ sin.sin_port = htons(port);
+
+ val = 1;
+ if (proto == IPPROTO_TCP)
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+ &val, sizeof(val)) < 0)
+ xlog(L_ERROR, "setsockopt failed: %s",
+ strerror(errno));
+
+ if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
+ xlog(L_FATAL, "Could not bind name to socket: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ return sock;
+}
+
void
rpc_init(char *name, int prog, int vers,
void (*dispatch)(struct svc_req *, register SVCXPRT *),
sock = 0;
if (getsockname(0, (struct sockaddr *) &saddr, &asize) == 0
&& saddr.sin_family == AF_INET) {
- socklen_t ssize = sizeof (int);
+ socklen_t ssize = sizeof(int);
int fdtype = 0;
if (getsockopt(0, SOL_SOCKET, SO_TYPE,
(char *)&fdtype, &ssize) == -1)
if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) {
static SVCXPRT *last_transp = NULL;
-
+
if (_rpcpmstart == 0) {
if (last_transp
&& (!defport || defport == last_transp->xp_port)) {
}
if (defport == 0)
sock = RPC_ANYSOCK;
- else if ((sock = makesock(defport, IPPROTO_UDP)) < 0) {
- xlog(L_FATAL, "%s: cannot make a UDP socket\n",
- name);
- }
+ else
+ sock = makesock(defport, IPPROTO_UDP);
}
if (sock == RPC_ANYSOCK)
sock = svcudp_socket (prog, 1);
}
if (defport == 0)
sock = RPC_ANYSOCK;
- else if ((sock = makesock(defport, IPPROTO_TCP)) < 0) {
- xlog(L_FATAL, "%s: cannot make a TCP socket\n",
- name);
- }
+ else
+ sock = makesock(defport, IPPROTO_TCP);
}
if (sock == RPC_ANYSOCK)
sock = svctcp_socket (prog, 1);
}
if (_rpcpmstart) {
- signal (SIGALRM, closedown);
- alarm (_RPCSVC_CLOSEDOWN);
- }
-}
-
-static void closedown(sig)
-int sig;
-{
- (void) signal(sig, closedown);
- if (_rpcsvcdirty == 0) {
- static int size;
- int i, openfd;
-
- if (_rpcfdtype == SOCK_DGRAM)
- exit(0);
- if (size == 0) {
- size = getdtablesize();
- }
- for (i = 0, openfd = 0; i < size && openfd < 2; i++)
- if (FD_ISSET(i, &svc_fdset))
- openfd++;
- if (openfd <= 1)
- exit(0);
- }
- (void) alarm(_RPCSVC_CLOSEDOWN);
-}
-
-int makesock(int port, int proto)
-{
- struct sockaddr_in sin;
- int s;
- int sock_type;
- int val;
-
- sock_type = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
- s = socket(AF_INET, sock_type, proto);
- if (s < 0) {
- xlog(L_FATAL, "Could not make a socket: %s\n",
- strerror(errno));
- return (-1);
- }
- memset((char *) &sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = INADDR_ANY;
- sin.sin_port = htons(port);
-
- val = 1;
- if (proto == IPPROTO_TCP)
- if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
- &val, sizeof(val)) < 0)
- xlog(L_ERROR, "setsockopt failed: %s\n",
- strerror(errno));
-
-#if 0
- /* I was told it didn't work with gigabit ethernet.
- Don't bothet with it. H.J. */
-#ifdef SO_SNDBUF
- {
- int sblen, rblen;
-
- /* 1024 for rpc & transport overheads */
- sblen = rblen = socksz + 1024;
- if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sblen, sizeof sblen) < 0 ||
- setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rblen, sizeof rblen) < 0)
- xlog(L_ERROR, "setsockopt failed: %s\n", strerror(errno));
- }
-#endif /* SO_SNDBUF */
-#endif
-
- if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
- xlog(L_FATAL, "Could not bind name to socket: %s\n",
- strerror(errno));
- return (-1);
- }
- return (s);
-}
-
-
-/* Log an incoming call. */
-void
-rpc_logcall(struct svc_req *rqstp, char *xname, char *arg)
-{
- char buff[1024];
- int buflen=sizeof(buff);
- int len;
- char *sp;
- int i;
-
- if (!xlog_enabled(D_CALL))
- return;
-
- sp = buff;
- switch (rqstp->rq_cred.oa_flavor) {
- case AUTH_NULL:
- sprintf(sp, "NULL");
- break;
- case AUTH_UNIX: {
- struct authunix_parms *unix_cred;
- time_t time;
- struct tm *tm;
-
- unix_cred = (struct authunix_parms *) rqstp->rq_clntcred;
- time = unix_cred->aup_time;
- tm = localtime(&time);
- snprintf(sp, buflen, "UNIX %d/%d/%d %02d:%02d:%02d %s %d.%d",
- tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
- tm->tm_hour, tm->tm_min, tm->tm_sec,
- unix_cred->aup_machname,
- unix_cred->aup_uid,
- unix_cred->aup_gid);
- sp[buflen-1] = 0;
- len = strlen(sp);
- sp += buflen;
- buflen -= len;
- if ((int) unix_cred->aup_len > 0) {
- snprintf(sp, buflen, "+%d", unix_cred->aup_gids[0]);
- sp[buflen-1] = 0;
- len = strlen(sp);
- sp += buflen;
- buflen -= len;
- for (i = 1; i < unix_cred->aup_len; i++) {
- snprintf(sp, buflen, ",%d",
- unix_cred->aup_gids[i]);
- sp[buflen-1] = 0;
- len = strlen(sp);
- sp += buflen;
- buflen -= len;
- }
- }
- }
- break;
- default:
- sprintf(sp, "CRED %d", rqstp->rq_cred.oa_flavor);
+ signal(SIGALRM, closedown);
+ alarm(_RPCSVC_CLOSEDOWN);
}
- xlog(D_CALL, "%s [%s]\n\t%s\n", xname, buff, arg);
}
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
#ifndef linux
if( !tirpcflag && inetdflag )
f_print(fout, "#include <sys/ttycom.h>/* TIOCNOTTY */\n");
+#else
+ if( !tirpcflag )
+ f_print(fout, "#include <sys/ttycom.h>/* TIOCNOTTY */\n");
#endif
if( Cflag && (inetdflag || pmflag ) ) {
f_print(fout, "#ifdef __cplusplus\n");
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
#include <config.h>
#endif
+#include <sys/vfs.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
*/
struct stat stb;
char *path = exp->m_export.e_path;
+ struct statfs64 stf;
+ int fs_has_fsid = 0;
if (stat(path, &stb) < 0) {
fprintf(stderr, "exportfs: Warning: %s does not exist\n",
if (!can_test())
return;
- if ((exp->m_export.e_flags & NFSEXP_FSID) || exp->m_export.e_uuid) {
+ if (!statfs64(path, &stf) &&
+ (stf.f_fsid.__val[0] || stf.f_fsid.__val[1]))
+ fs_has_fsid = 1;
+
+ if ((exp->m_export.e_flags & NFSEXP_FSID) || exp->m_export.e_uuid ||
+ fs_has_fsid) {
if ( !test_export(path, 1)) {
fprintf(stderr, "exportfs: Warning: %s does not "
"support NFS export.\n",
above).
In releases of nfs-utils up to and including 1.0.0, this option was the
-default. In all subsequence releases,
+default. In all releases after 1.0.0,
.I sync
is the default, and
.I async
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
+++ /dev/null
-[General]
-
-Verbosity = 0
-Pipefs-Directory = /var/lib/nfs/rpc_pipefs
-Domain = localdomain
-
-[Mapping]
-
-Nobody-User = nobody
-Nobody-Group = nobody
# These binaries go in /sbin (not /usr/sbin), and that cannot be
# overriden at config time.
sbindir = /sbin
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
#include "mount_constants.h"
#include "network.h"
+/*
+ * Earlier versions of glibc's /usr/include/netdb.h exclude these
+ * definitions because it was thought they were not part of a stable
+ * POSIX standard. However, they are defined by RFC 2553 and 3493
+ * and in POSIX 1003.1-2001, so these definitions were added in later
+ * versions of netdb.h.
+ */
+#ifndef AI_V4MAPPED
+#define AI_V4MAPPED 0x0008 /* IPv4-mapped addresses are acceptable. */
+#endif /* AI_V4MAPPED */
+#ifndef AI_ALL
+#define AI_ALL 0x0010 /* Return both IPv4 and IPv6 addresses. */
+#endif /* AI_ALL */
+#ifndef AI_ADDRCONFIG
+#define AI_ADDRCONFIG 0x0020 /* Use configuration of this host to choose \
+ returned address type. */
+#endif /* AI_ADDRCONFIG */
+
#define PMAP_TIMEOUT (10)
#define CONNECT_TIMEOUT (20)
#define MOUNT_TIMEOUT (30)
bind_saddr = *saddr;
bind_saddr.sin_port = htons(PMAPPORT);
- socket = get_socket(&bind_saddr, proto, PMAP_TIMEOUT, FALSE, FALSE);
+ socket = get_socket(&bind_saddr, proto, PMAP_TIMEOUT, FALSE, TRUE);
if (socket == RPC_ANYSOCK) {
if (proto == IPPROTO_TCP &&
rpc_createerr.cf_error.re_errno == ETIMEDOUT)
}
if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED &&
rpc_createerr.cf_stat != RPC_TIMEDOUT &&
+ rpc_createerr.cf_stat != RPC_CANTRECV &&
rpc_createerr.cf_stat != RPC_PROGVERSMISMATCH)
goto out_bad;
continue;
p_prot = protos;
}
- if (rpc_createerr.cf_stat == RPC_TIMEDOUT)
+ if (rpc_createerr.cf_stat == RPC_TIMEDOUT ||
+ rpc_createerr.cf_stat == RPC_CANTRECV)
goto out_bad;
if (vers || !*++p_vers)
.B nfs
file system type.
.TP 1.5i
-.BI proto= netid
-The transport protocol used by the NFS client
+.BI proto= transport
+The transport the NFS client uses
to transmit requests to the NFS server for this mount point.
-.I netid
+.I transport
can be either
.B udp
or
.BR tcp .
-Each transport protocol uses different default
+Each transport uses different default
.B retrans
and
.B timeo
This option can be used when mounting an NFS server
through a firewall that blocks the rpcbind protocol.
.TP 1.5i
-.BI mountproto= netid
-The transport protocol used by the NFS client
+.BI mountproto= transport
+The transport the NFS client uses
to transmit requests to the NFS server's mountd service when performing
this mount request, and when later unmounting this mount point.
-.I netid
+.I transport
can be either
.B udp
or
.BR tcp .
.IP
This option can be used when mounting an NFS server
-through a firewall that blocks a particular transport protocol.
+through a firewall that blocks a particular transport.
When used in combination with the
.B proto
option, different transports for mountd requests and NFS requests
can be specified.
If the server's mountd service is not available via the specified
transport, the mount request fails.
+Refer to the TRANSPORT METHODS section for more on how the
+.B mountproto
+mount option interacts with the
+.B proto
+mount option.
.TP 1.5i
.BI mounthost= name
The hostname of the host running mountd.
.B nfs4
file system type.
.TP 1.5i
-.BI proto= netid
-The transport protocol used by the NFS client
+.BI proto= transport
+The transport the NFS client uses
to transmit requests to the NFS server for this mount point.
-.I netid
+.I transport
can be either
.B udp
or
.B wsize
can safely be allowed to default to the largest values supported by
both client and server, independent of the network's MTU size.
+.SS "Using the mountproto mount option"
+This section applies only to NFS version 2 and version 3 mounts
+since NFS version 4 does not use a separate protocol for mount
+requests.
+.P
+The Linux NFS client can use a different transport for
+contacting an NFS server's rpcbind service, its mountd service,
+its Network Lock Manager (NLM) service, and its NFS service.
+The exact transports employed by the Linux NFS client for
+each mount point depends on the settings of the transport
+mount options, which include
+.BR proto ,
+.BR mountproto ,
+.BR udp ", and " tcp .
+.P
+The client sends Network Status Manager (NSM) notifications
+via UDP no matter what transport options are specified, but
+listens for server NSM notifications on both UDP and TCP.
+The NFS Access Control List (NFSACL) protocol shares the same
+transport as the main NFS service.
+.P
+If no transport options are specified, the Linux NFS client
+uses UDP to contact the server's mountd service, and TCP to
+contact its NLM and NFS services by default.
+.P
+If the server does not support these transports for these services, the
+.BR mount (8)
+command attempts to discover what the server supports, and then retries
+the mount request once using the discovered transports.
+If the server does not advertise any transport supported by the client
+or is misconfigured, the mount request fails.
+If the
+.B bg
+option is in effect, the mount command backgrounds itself and continues
+to attempt the specified mount request.
+.P
+When the
+.B proto
+option, the
+.B udp
+option, or the
+.B tcp
+option is specified but the
+.B mountproto
+option is not, the specified transport is used to contact
+both the server's mountd service and for the NLM and NFS services.
+.P
+If the
+.B mountproto
+option is specified but none of the
+.BR proto ", " udp " or " tcp
+options are specified, then the specified transport is used for the
+initial mountd request, but the mount command attempts to discover
+what the server supports for the NFS protocol, preferring TCP if
+both transports are supported.
+.P
+If both the
+.BR mountproto " and " proto
+(or
+.BR udp " or " tcp )
+options are specified, then the transport specified by the
+.B mountproto
+option is used for the initial mountd request, and the transport
+specified by the
+.B proto
+option (or the
+.BR udp " or " tcp " options)"
+is used for NFS, no matter what order these options appear.
+No automatic service discovery is performed if these options are
+specified.
+.P
+If any of the
+.BR proto ", " udp ", " tcp ", "
+or
+.B mountproto
+options are specified more than once on the same mount command line,
+then the value of the rightmost instance of each of these options
+takes effect.
.SH "DATA AND METADATA COHERENCE"
Some modern cluster file systems provide
perfect cache coherence among their clients.
.BR umount.nfs (5),
.BR exports (5),
.BR nfsd (8),
+.BR sm-notify (8),
+.BR rpc.statd (8),
.BR rpc.idmapd (8),
.BR rpc.gssd (8),
.BR rpc.svcgssd (8),
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
break;
case unknown_host:
- xlog(L_WARNING, "%s request from unknown host %s for %s (%s)",
+ xlog(L_WARNING, "refused %s request from %s for %s (%s): unmatched host",
what, inet_ntoa(addr), path, epath);
break;
#include <sys/types.h>
#include <sys/select.h>
#include <sys/stat.h>
+#include <sys/vfs.h>
#include <time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
qword_printint(f, ngroups);
for (i=0; i<ngroups; i++)
qword_printint(f, groups[i]);
- }
+ } else
+ qword_printint(f, 0);
qword_eol(f);
+
if (groups != glist)
free(groups);
}
#if USE_BLKID
+static const char *get_uuid_blkdev(char *path)
+{
+ static blkid_cache cache = NULL;
+ struct stat stb;
+ char *devname;
+ blkid_tag_iterate iter;
+ blkid_dev dev;
+ const char *type;
+ const char *val = NULL;
+
+ if (cache == NULL)
+ blkid_get_cache(&cache, NULL);
+
+ if (stat(path, &stb) != 0)
+ return NULL;
+ devname = blkid_devno_to_devname(stb.st_dev);
+ if (!devname)
+ return NULL;
+ dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL);
+ free(devname);
+ if (!dev)
+ return NULL;
+ iter = blkid_tag_iterate_begin(dev);
+ if (!iter)
+ return NULL;
+ while (blkid_tag_next(iter, &type, &val) == 0)
+ if (strcmp(type, "UUID") == 0)
+ break;
+ blkid_tag_iterate_end(iter);
+ return val;
+}
+#else
+#define get_uuid_blkdev(path) (NULL)
+#endif
+
int get_uuid(char *path, char *uuid, int uuidlen, char *u)
{
/* extract hex digits from uuidstr and compose a uuid
* a smaller uuid. Then compare with uuid
*/
int i = 0;
- const char *val;
+ const char *val = NULL;
+ char fsid_val[17];
if (path) {
- static blkid_cache cache = NULL;
- struct stat stb;
- char *devname;
- blkid_tag_iterate iter;
- blkid_dev dev;
- const char *type;
- if (cache == NULL)
- blkid_get_cache(&cache, NULL);
-
- if (stat(path, &stb) != 0)
- return 0;
- devname = blkid_devno_to_devname(stb.st_dev);
- if (!devname)
- return 0;
- dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL);
- free(devname);
- if (!dev)
- return 0;
- iter = blkid_tag_iterate_begin(dev);
- if (!iter)
- return 0;
- while (blkid_tag_next(iter, &type, &val) == 0)
- if (strcmp(type, "UUID") == 0)
- break;
- blkid_tag_iterate_end(iter);
- if (!type)
- return 0;
+ val = get_uuid_blkdev(path);
+ if (!val) {
+ struct statfs64 st;
+
+ if (statfs64(path, &st))
+ return 0;
+ if (!st.f_fsid.__val[0] && !st.f_fsid.__val[1])
+ return 0;
+ snprintf(fsid_val, 17, "%08x%08x",
+ st.f_fsid.__val[0], st.f_fsid.__val[1]);
+ val = fsid_val;
+ }
} else {
val = uuid;
}
}
return 1;
}
-#endif
/* Iterate through /etc/mtab, finding mountpoints
* at or below a given path
if (!is_mountpoint(path))
continue;
check_uuid:
-#if USE_BLKID
if (exp->m_export.e_uuid)
get_uuid(NULL, exp->m_export.e_uuid,
uuidlen, u);
- else if (get_uuid(path, NULL,
- uuidlen, u) == 0)
+ else if (get_uuid(path, NULL, uuidlen, u) == 0)
continue;
if (memcmp(u, fhuuid, uuidlen) != 0)
continue;
break;
-#else
- continue;
-#endif
}
if (use_ipaddr) {
if (he == NULL) {
qword_printint(f, exp->e_fsid);
write_fsloc(f, exp, path);
write_secinfo(f, exp);
-#if USE_BLKID
if (exp->e_uuid == NULL || different_fs) {
char u[16];
if (get_uuid(path, NULL, 16, u)) {
qword_printhex(f, u, 16);
}
} else {
+ char u[16];
+ get_uuid(NULL, exp->e_uuid, 16, u);
qword_print(f, "uuid");
- qword_printhex(f, exp->e_uuid, 16);
+ qword_printhex(f, u, 16);
}
-#endif
}
return qword_eol(f);
}
#include "misc.h"
#include "mountd.h"
#include "rpcmisc.h"
+#include "pseudoflavors.h"
extern void cache_open(void);
extern struct nfs_fh_len *cache_get_filehandle(nfs_export *exp, int len, char *p);
static void usage(const char *, int exitcode);
static exports get_exportlist(void);
-static struct nfs_fh_len *get_rootfh(struct svc_req *, dirpath *, mountstat3 *, int v3);
+static struct nfs_fh_len *get_rootfh(struct svc_req *, dirpath *, nfs_export **, mountstat3 *, int v3);
int reverse_resolve = 0;
int new_cache = 0;
static void
sig_hup (int sig)
{
- /* don't exit on SIGHUP */
- xlog (L_NOTICE, "Received SIGHUP... Ignoring.\n", sig);
- return;
+ /* don't exit on SIGHUP */
+ xlog (L_NOTICE, "Received SIGHUP... Ignoring.\n", sig);
+ return;
}
bool_t
struct nfs_fh_len *fh;
xlog(D_CALL, "MNT1(%s) called", *path);
- if ((fh = get_rootfh(rqstp, path, &res->fhs_status, 0)) != NULL)
+ fh = get_rootfh(rqstp, path, NULL, &res->fhs_status, 0);
+ if (fh)
memcpy(&res->fhstatus_u.fhs_fhandle, fh->fh_handle, 32);
return 1;
}
return 1;
}
- if (!new_cache)
- export_reset (exp);
-
mountlist_del(inet_ntoa(sin->sin_addr), p);
return 1;
}
}
/* Now authenticate the intruder... */
- if (!(exp = auth_authenticate("pathconf", sin, p))) {
+ exp = auth_authenticate("pathconf", sin, p);
+ if (!exp) {
return 1;
} else if (stat(p, &stb) < 0) {
xlog(L_WARNING, "can't stat exported dir %s: %s",
p, strerror(errno));
- export_reset (exp);
return 1;
}
res->pc_mask[0] = 0;
res->pc_mask[1] = 0;
- export_reset (exp);
-
return 1;
}
+/*
+ * We should advertise the preferred flavours first. (See RFC 2623
+ * section 2.7.) We leave that to the administrator, by advertising
+ * flavours in the order they were listed in /etc/exports. AUTH_NULL is
+ * dropped from the list to avoid backward compatibility issue with
+ * older Linux clients, who inspect the list in reversed order.
+ *
+ * XXX: It might be more helpful to rearrange these so that flavors
+ * giving more access (as determined from readonly and id-squashing
+ * options) come first. (If we decide to do that we should probably do
+ * that when reading the exports rather than here.)
+ */
+static void set_authflavors(struct mountres3_ok *ok, nfs_export *exp)
+{
+ struct sec_entry *s;
+ static int flavors[SECFLAVOR_COUNT];
+ int i = 0;
+
+ for (s = exp->m_export.e_secinfo; s->flav; s++) {
+ if (s->flav->fnum == AUTH_NULL)
+ continue;
+ flavors[i] = s->flav->fnum;
+ i++;
+ }
+ ok->auth_flavors.auth_flavors_val = flavors;
+ ok->auth_flavors.auth_flavors_len = i;
+}
+
/*
* NFSv3 MOUNT procedure
*/
bool_t
mount_mnt_3_svc(struct svc_req *rqstp, dirpath *path, mountres3 *res)
{
-#define AUTH_GSS_KRB5 390003
-#define AUTH_GSS_KRB5I 390004
-#define AUTH_GSS_KRB5P 390005
- static int flavors[] = { AUTH_UNIX, AUTH_GSS_KRB5, AUTH_GSS_KRB5I, AUTH_GSS_KRB5P};
- /*
- * We should advertise the preferred flavours first. (See RFC 2623
- * section 2.7.) AUTH_UNIX is arbitrarily ranked over the GSS's.
- * AUTH_NULL is dropped from the list to avoid backward compatibility
- * issue with older Linux clients, who inspect the list in reversed
- * order.
- */
+ struct mountres3_ok *ok = &res->mountres3_u.mountinfo;
+ nfs_export *exp;
struct nfs_fh_len *fh;
xlog(D_CALL, "MNT3(%s) called", *path);
- if ((fh = get_rootfh(rqstp, path, &res->fhs_status, 1)) != NULL) {
- struct mountres3_ok *ok = &res->mountres3_u.mountinfo;
-
- ok->fhandle.fhandle3_len = fh->fh_size;
- ok->fhandle.fhandle3_val = (char *)fh->fh_handle;
- ok->auth_flavors.auth_flavors_len
- = sizeof(flavors)/sizeof(flavors[0]);
- ok->auth_flavors.auth_flavors_val = flavors;
- }
+ fh = get_rootfh(rqstp, path, &exp, &res->fhs_status, 1);
+ if (!fh)
+ return 1;
+
+ ok->fhandle.fhandle3_len = fh->fh_size;
+ ok->fhandle.fhandle3_val = (char *)fh->fh_handle;
+ set_authflavors(ok, exp);
return 1;
}
static struct nfs_fh_len *
-get_rootfh(struct svc_req *rqstp, dirpath *path, mountstat3 *error, int v3)
+get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
+ mountstat3 *error, int v3)
{
struct sockaddr_in *sin =
(struct sockaddr_in *) svc_getcaller(rqstp->rq_xprt);
struct stat stb, estb;
nfs_export *exp;
+ struct nfs_fh_len *fh;
char rpath[MAXPATHLEN+1];
char *p = *path;
}
/* Now authenticate the intruder... */
- if (!(exp = auth_authenticate("mount", sin, p))) {
+ exp = auth_authenticate("mount", sin, p);
+ if (!exp) {
*error = NFSERR_ACCES;
- } else if (stat(p, &stb) < 0) {
+ return NULL;
+ }
+ if (stat(p, &stb) < 0) {
xlog(L_WARNING, "can't stat exported dir %s: %s",
p, strerror(errno));
if (errno == ENOENT)
*error = NFSERR_NOENT;
else
*error = NFSERR_ACCES;
- } else if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) {
+ return NULL;
+ }
+ if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) {
xlog(L_WARNING, "%s is not a directory or regular file", p);
*error = NFSERR_NOTDIR;
- } else if (stat(exp->m_export.e_path, &estb) < 0) {
+ return NULL;
+ }
+ if (stat(exp->m_export.e_path, &estb) < 0) {
xlog(L_WARNING, "can't stat export point %s: %s",
p, strerror(errno));
*error = NFSERR_NOENT;
- } else if (estb.st_dev != stb.st_dev
- && (!new_cache || !(exp->m_export.e_flags & NFSEXP_CROSSMOUNT))
- ) {
+ return NULL;
+ }
+ if (estb.st_dev != stb.st_dev
+ && (!new_cache
+ || !(exp->m_export.e_flags & NFSEXP_CROSSMOUNT))) {
xlog(L_WARNING, "request to export directory %s below nearest filesystem %s",
p, exp->m_export.e_path);
*error = NFSERR_ACCES;
- } else if (exp->m_export.e_mountpoint &&
+ return NULL;
+ }
+ if (exp->m_export.e_mountpoint &&
!is_mountpoint(exp->m_export.e_mountpoint[0]?
exp->m_export.e_mountpoint:
exp->m_export.e_path)) {
xlog(L_WARNING, "request to export an unmounted filesystem: %s",
p);
*error = NFSERR_NOENT;
- } else if (new_cache) {
+ return NULL;
+ }
+
+ if (new_cache) {
/* This will be a static private nfs_export with just one
* address. We feed it to kernel then extract the filehandle,
*
*/
- struct nfs_fh_len *fh;
if (cache_export(exp, p)) {
*error = NFSERR_ACCES;
return NULL;
}
fh = cache_get_filehandle(exp, v3?64:32, p);
- if (fh == NULL)
+ if (fh == NULL) {
*error = NFSERR_ACCES;
- else {
- *error = NFS_OK;
- mountlist_add(inet_ntoa(sin->sin_addr), p);
+ return NULL;
}
- return fh;
} else {
- struct nfs_fh_len *fh;
-
if (exp->m_exported<1)
export_export(exp);
if (!exp->m_xtabent)
fh = getfh_old ((struct sockaddr *) sin,
stb.st_dev, stb.st_ino);
}
- if (fh != NULL) {
- mountlist_add(inet_ntoa(sin->sin_addr), p);
- *error = NFS_OK;
- export_reset (exp);
- return fh;
+ if (fh == NULL) {
+ xlog(L_WARNING, "getfh failed: %s", strerror(errno));
+ *error = NFSERR_ACCES;
+ return NULL;
}
- xlog(L_WARNING, "getfh failed: %s", strerror(errno));
- *error = NFSERR_ACCES;
}
- export_reset (exp);
- return NULL;
+ *error = NFS_OK;
+ mountlist_add(inet_ntoa(sin->sin_addr), p);
+ if (expret)
+ *expret = exp;
+ return fh;
}
static exports
for (i = 0; i < MCL_MAXTYPES; i++) {
for (exp = exportlist[i]; exp; exp = exp->m_next) {
for (e = elist; e != NULL; e = e->ex_next) {
- if (!strcmp(exp->m_export.m_path, e->ex_dir))
+ if (!strcmp(exp->m_export.e_path, e->ex_dir))
break;
}
if (!e) {
e = (struct exportnode *) xmalloc(sizeof(*e));
e->ex_next = elist;
e->ex_groups = NULL;
- e->ex_dir = xstrdup(exp->m_export.m_path);
+ e->ex_dir = xstrdup(exp->m_export.e_path);
elist = e;
}
}
while ((rep = getrmtabent(1, NULL)) != NULL) {
if (strcmp(rep->r_client, hp->h_name) == 0 &&
- (exp = auth_authenticate("umountall", sin, rep->r_path))) {
- export_reset(exp);
+ (exp = auth_authenticate("umountall", sin, rep->r_path)))
continue;
- }
fputrmtabent(fp, rep, NULL);
}
if (slink_safe_rename(_PATH_RMTABTMP, _PATH_RMTAB) < 0) {
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
.B rpc.nfsd
program implements the user level part of the NFS service. The
main functionality is handled by the
-.B nfsd.o
+.B nfsd
kernel module; the user space program merely starts the specified
number of kernel threads.
.P
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
* tout contains the timeout. It will be modified to contain the time
* remaining (i.e. time provided - time elasped).
*
- * Returns 0 for success
+ * Returns zero on success; otherwise, -1 is returned and errno is set
+ * to reflect the nature of the error.
*/
static int connect_nb(int fd, struct sockaddr_in *addr, struct timeval *tout)
{
len = sizeof(struct sockaddr);
ret = connect(fd, (struct sockaddr *)addr, len);
if (ret < 0 && errno != EINPROGRESS) {
- ret = -errno;
+ ret = -1;
goto done;
}
ret = select(fd + 1, NULL, &rset, NULL, tout);
if (ret <= 0) {
if (ret == 0)
- ret = -ETIMEDOUT;
- else
- ret = -errno;
+ errno = ETIMEDOUT;
+ ret = -1;
goto done;
}
len = sizeof(ret);
status = getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &len);
if (status < 0) {
- ret = -errno;
+ ret = -1;
goto done;
}
/* Oops - something wrong with connect */
- if (ret)
- ret = -ret;
+ if (ret != 0) {
+ errno = ret;
+ ret = -1;
+ }
}
done:
tout.tv_sec = TIMEOUT_TCP;
ret = connect_nb(sock, &saddr, &tout);
- if (ret < 0) {
- close(sock);
+ if (ret != 0) {
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
rpc_createerr.cf_error.re_errno = errno;
+ close(sock);
return 0;
}
client = clnttcp_create(&saddr,
total_timeout);
if (clnt_stat != RPC_SUCCESS) {
clnt_perror(mclient, "rpc mount export");
+ clnt_destroy(mclient);
exit(1);
}
if (headers)
printf("\n");
exportlist = exportlist->ex_next;
}
+ clnt_destroy(mclient);
exit(0);
}
total_timeout);
if (clnt_stat != RPC_SUCCESS) {
clnt_perror(mclient, "rpc mount dump");
+ clnt_destroy(mclient);
exit(1);
}
+ clnt_destroy(mclient);
n = 0;
for (list = dumplist; list; list = list->ml_next)
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
-secure_statd = @secure_statd@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
startstatd = @startstatd@
argp->mon_name, argp->state);
/* quick check - don't bother if we're not monitoring anyone */
- /* LH - this was != MULL, meaning that if anyone _was_ in our RTNL,
- * we'd never pass this point. */
- if (!(lp = rtnl)) {
+ if (rtnl == NULL) {
note(N_WARNING, "SM_NOTIFY from %s while not monitoring any hosts.",
- argp->mon_name, argp->state);
+ argp->mon_name);
return ((void *) &result);
}
#define LINELEN (4*(8+1)+SM_PRIV_SIZE*2+1)
+/*
+ * Reject requests from non-loopback addresses in order
+ * to prevent attack described in CERT CA-99.05.
+ */
+static int
+caller_is_localhost(struct svc_req *rqstp)
+{
+ struct in_addr caller;
+
+ caller = svc_getcaller(rqstp->rq_xprt)->sin_addr;
+ if (caller.s_addr != htonl(INADDR_LOOPBACK)) {
+ note(N_WARNING,
+ "Call to statd from non-local host %s",
+ inet_ntoa(caller));
+ return 0;
+ }
+ return 1;
+}
+
/*
* Services SM_MON requests.
*/
notify_list *clnt;
struct in_addr my_addr;
char *dnsname;
-#ifdef RESTRICTED_STATD
- struct in_addr caller;
-#endif
struct hostent *hostinfo = NULL;
/* Assume that we'll fail. */
result.res_stat = STAT_FAIL;
result.state = -1; /* State is undefined for STAT_FAIL. */
- /* Restrict access to statd.
- * In the light of CERT CA-99.05, we tighten access to
- * statd. --okir
- */
-#ifdef RESTRICTED_STATD
- /* 1. Reject anyone not calling from 127.0.0.1.
+ /* 1. Reject any remote callers.
* Ignore the my_name specified by the caller, and
* use "127.0.0.1" instead.
*/
- caller = svc_getcaller(rqstp->rq_xprt)->sin_addr;
- if (caller.s_addr != htonl(INADDR_LOOPBACK)) {
- note(N_WARNING,
- "Call to statd from non-local host %s",
- inet_ntoa(caller));
+ if (!caller_is_localhost(rqstp))
goto failure;
- }
my_addr.s_addr = htonl(INADDR_LOOPBACK);
/* 2. Reject any registrations for non-lockd services.
goto failure;
}
-#if 0
- This is not usable anymore. Linux-kernel can be configured to use
- host names with NSM so that multi-homed hosts are handled properly.
- NeilBrown 15mar2007
-
- /* 3. mon_name must be an address in dotted quad.
- * Again, specific to the linux kernel lockd.
- */
- if (!inet_aton(mon_name, &mon_addr)) {
- note(N_WARNING,
- "Attempt to register host %s (not a dotted quad)",
- mon_name);
- goto failure;
- }
-#endif
-#else
- if (!(hostinfo = gethostbyname(my_name))) {
- note(N_WARNING, "gethostbyname error for %s", my_name);
- goto failure;
- } else
- my_addr = *(struct in_addr *) hostinfo->h_addr;
-#endif
/*
* Check hostnames. If I can't look them up, I won't monitor. This
* might not be legal, but it adds a little bit of safety and sanity.
*my_name = argp->my_id.my_name;
struct my_id *id = &argp->my_id;
char *cp;
-#ifdef RESTRICTED_STATD
- struct in_addr caller;
-#endif
result.state = MY_STATE;
-#ifdef RESTRICTED_STATD
- /* 1. Reject anyone not calling from 127.0.0.1.
- * Ignore the my_name specified by the caller, and
- * use "127.0.0.1" instead.
- */
- caller = svc_getcaller(rqstp->rq_xprt)->sin_addr;
- if (caller.s_addr != htonl(INADDR_LOOPBACK)) {
- note(N_WARNING,
- "Call to statd from non-local host %s",
- inet_ntoa(caller));
+ if (!caller_is_localhost(rqstp))
goto failure;
- }
-#endif
+
/* my_name must not have white space */
for (cp=my_name ; *cp ; cp++)
if (*cp == ' ' || *cp == '\t' || *cp == '\r' || *cp == '\n')
/* Check if we're monitoring anyone. */
- if (!(clnt = rtnl)) {
+ if (rtnl == NULL) {
note(N_WARNING,
"Received SM_UNMON request from %s for %s while not "
"monitoring any hosts.", my_name, argp->mon_name);
return (&result);
}
+ clnt = rtnl;
/*
* OK, we are. Now look for appropriate entry in run-time list.
clnt = NL_NEXT(clnt);
}
-#ifdef RESTRICTED_STATD
failure:
-#endif
note(N_WARNING, "Received erroneous SM_UNMON request from %s for %s",
my_name, mon_name);
return (&result);
static sm_stat result;
notify_list *clnt;
char *my_name = argp->my_name;
-#ifdef RESTRICTED_STATD
- struct in_addr caller;
- /* 1. Reject anyone not calling from 127.0.0.1.
- * Ignore the my_name specified by the caller, and
- * use "127.0.0.1" instead.
- */
- caller = svc_getcaller(rqstp->rq_xprt)->sin_addr;
- if (caller.s_addr != htonl(INADDR_LOOPBACK)) {
- note(N_WARNING,
- "Call to statd from non-local host %s",
- inet_ntoa(caller));
+ if (!caller_is_localhost(rqstp))
goto failure;
- }
-#endif
result.state = MY_STATE;
- if (!(clnt = rtnl)) {
+ if (rtnl == NULL) {
note(N_WARNING, "Received SM_UNMON_ALL request from %s "
"while not monitoring any hosts", my_name);
return (&result);
}
+ clnt = rtnl;
while ((clnt = nlist_gethost(clnt, my_name, 1))) {
if (NL_MY_PROC(clnt) == argp->my_proc &&
dprintf(N_DEBUG, "SM_UNMON_ALL request from %s with no "
"SM_MON requests from it.", my_name);
}
-#ifdef RESTRICTED_STATD
+
failure:
-#endif
return (&result);
}
static int sockfd = -1; /* notify socket */
/*
- * Initialize callback socket
+ * Initialize socket used to notify lockd of peer reboots.
+ *
+ * Returns the file descriptor of the new socket if successful;
+ * otherwise returns -1 and logs an error.
+ *
+ * Lockd rejects such requests if the source port is not privileged.
+ * statd_get_socket() must be invoked while statd still holds root
+ * privileges in order for the socket to acquire a privileged source
+ * port.
*/
int
statd_get_socket(void)
if (sockfd >= 0) close(sockfd);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
- note(N_CRIT, "Can't create socket: %m");
+ note(N_CRIT, "%s: Can't create socket: %m", __func__);
return -1;
}
sin.sin_addr.s_addr = INADDR_ANY;
if (bindresvport(sockfd, &sin) < 0) {
- dprintf(N_WARNING,
- "process_hosts: can't bind to reserved port\n");
+ dprintf(N_WARNING, "%s: can't bind to reserved port",
+ __func__);
break;
}
se = getservbyport(sin.sin_port, "udp");
}
static unsigned long
-xmit_call(int sockfd, struct sockaddr_in *sin,
+xmit_call(struct sockaddr_in *sin,
u_int32_t prog, u_int32_t vers, u_int32_t proc,
xdrproc_t func, void *obj)
/* __u32 prog, __u32 vers, __u32 proc, xdrproc_t func, void *obj) */
/* Encode the RPC header part and payload */
if (!xdr_callmsg(xdrs, &mesg) || !func(xdrs, obj)) {
- dprintf(N_WARNING, "xmit_mesg: can't encode RPC message!\n");
+ dprintf(N_WARNING, "%s: can't encode RPC message!", __func__);
xdr_destroy(xdrs);
return 0;
}
if ((err = sendto(sockfd, msgbuf, msglen, 0,
(struct sockaddr *) sin, sizeof(*sin))) < 0) {
- dprintf(N_WARNING, "xmit_mesg: sendto failed: %m");
+ dprintf(N_WARNING, "%s: sendto failed: %m", __func__);
} else if (err != msglen) {
- dprintf(N_WARNING, "xmit_mesg: short write: %m\n");
+ dprintf(N_WARNING, "%s: short write: %m", __func__);
}
xdr_destroy(xdrs);
}
static notify_list *
-recv_rply(int sockfd, struct sockaddr_in *sin, u_long *portp)
+recv_rply(struct sockaddr_in *sin, u_long *portp)
{
unsigned int msgbuf[MAXMSGSIZE], msglen;
struct rpc_msg mesg;
/* Receive message */
if ((msglen = recvfrom(sockfd, msgbuf, sizeof(msgbuf), 0,
(struct sockaddr *) sin, &alen)) < 0) {
- dprintf(N_WARNING, "recv_rply: recvfrom failed: %m");
+ dprintf(N_WARNING, "%s: recvfrom failed: %m", __func__);
return NULL;
}
mesg.rm_reply.rp_acpt.ar_results.proc = (xdrproc_t) xdr_void;
if (!xdr_replymsg(xdrs, &mesg)) {
- note(N_WARNING, "recv_rply: can't decode RPC message!\n");
+ note(N_WARNING, "%s: can't decode RPC message!", __func__);
goto done;
}
if (mesg.rm_reply.rp_stat != 0) {
- note(N_WARNING, "recv_rply: [%s] RPC status %d\n",
+ note(N_WARNING, "%s: [%s] RPC status %d",
+ __func__,
inet_ntoa(sin->sin_addr),
mesg.rm_reply.rp_stat);
goto done;
}
if (mesg.rm_reply.rp_acpt.ar_stat != 0) {
- note(N_WARNING, "recv_rply: [%s] RPC status %d\n",
+ note(N_WARNING, "%s: [%s] RPC status %d",
+ __func__,
inet_ntoa(sin->sin_addr),
mesg.rm_reply.rp_acpt.ar_stat);
goto done;
strncpy (addr, inet_ntoa(lp->addr),
sizeof (addr) - 1);
addr [sizeof (addr) - 1] = '\0';
- dprintf(N_WARNING, "address mismatch: "
- "expected %s, got %s\n",
+ dprintf(N_WARNING, "%s: address mismatch: "
+ "expected %s, got %s", __func__,
addr, inet_ntoa(sin->sin_addr));
}
if (lp->port == 0) {
if (!xdr_u_long(xdrs, portp)) {
- note(N_WARNING, "recv_rply: [%s] "
- "can't decode reply body!\n",
+ note(N_WARNING,
+ "%s: [%s] can't decode reply body!",
+ __func__,
inet_ntoa(sin->sin_addr));
lp = NULL;
goto done;
* Notify operation for a single list entry
*/
static int
-process_entry(int sockfd, notify_list *lp)
+process_entry(notify_list *lp)
{
struct sockaddr_in sin;
struct status new_status;
/* __u32 proc, vers, prog; */
if (NL_TIMES(lp) == 0) {
- note(N_DEBUG, "Cannot notify %s, giving up.\n",
- inet_ntoa(NL_ADDR(lp)));
+ note(N_DEBUG, "%s: Cannot notify %s, giving up.",
+ __func__, inet_ntoa(NL_ADDR(lp)));
return 0;
}
new_status.state = NL_STATE(lp);
memcpy(new_status.priv, NL_PRIV(lp), SM_PRIV_SIZE);
- lp->xid = xmit_call(sockfd, &sin, prog, vers, proc, func, objp);
+ lp->xid = xmit_call(&sin, prog, vers, proc, func, objp);
if (!lp->xid) {
- note(N_WARNING, "notify_host: failed to notify port %d\n",
- ntohs(lp->port));
+ note(N_WARNING, "%s: failed to notify port %d",
+ __func__, ntohs(lp->port));
}
NL_TIMES(lp) -= 1;
if (sockfd == -1 || !FD_ISSET(sockfd, rfds))
return 0;
- if (!(lp = recv_rply(sockfd, &sin, &port)))
+ if (!(lp = recv_rply(&sin, &port)))
return 1;
if (lp->port == 0) {
if (port != 0) {
lp->port = htons((unsigned short) port);
- process_entry(sockfd, lp);
+ process_entry(lp);
NL_WHEN(lp) = time(NULL) + NOTIFY_TIMEOUT;
nlist_remove(¬ify, lp);
nlist_insert_timer(¬ify, lp);
return 1;
}
- note(N_WARNING, "recv_rply: [%s] service %d not registered",
- inet_ntoa(lp->addr), NL_MY_PROG(lp));
+ note(N_WARNING, "%s: [%s] service %d not registered",
+ __func__, inet_ntoa(lp->addr), NL_MY_PROG(lp));
} else {
- dprintf(N_DEBUG, "Callback to %s (for %d) succeeded.",
- NL_MY_NAME(lp), NL_MON_NAME(lp));
+ dprintf(N_DEBUG, "%s: Callback to %s (for %d) succeeded.",
+ __func__, NL_MY_NAME(lp), NL_MON_NAME(lp));
}
nlist_free(¬ify, lp);
return 1;
{
notify_list *entry;
time_t now;
- int fd;
-
- if ((fd = statd_get_socket()) < 0)
- return 0;
while ((entry = notify) != NULL && NL_WHEN(entry) < time(&now)) {
- if (process_entry(fd, entry)) {
+ if (process_entry(entry)) {
NL_WHEN(entry) = time(NULL) + NOTIFY_TIMEOUT;
nlist_remove(¬ify, entry);
nlist_insert_timer(¬ify, entry);
} else {
note(N_ERROR,
- "Can't callback %s (%d,%d), giving up.",
+ "%s: Can't callback %s (%d,%d), giving up.",
+ __func__,
NL_MY_NAME(entry),
NL_MY_PROG(entry),
NL_MY_VERS(entry));
sm_simu_crash_1_svc (void *argp, struct svc_req *rqstp)
{
static char *result = NULL;
+ struct in_addr caller;
+
+ caller = svc_getcaller(rqstp->rq_xprt)->sin_addr;
+ if (caller.s_addr != htonl(INADDR_LOOPBACK)) {
+ note(N_WARNING, "Call to statd from non-local host %s",
+ inet_ntoa(caller));
+ goto failure;
+ }
+
+ if (ntohs(svc_getcaller(rqstp->rq_xprt)->sin_port) >= 1024) {
+ note(N_WARNING, "Call to statd-simu-crash from unprivileged port");
+ goto failure;
+ }
-#ifdef RESTRICTED_STATD
- struct in_addr caller;
-
- /* 1. Reject anyone not calling from 127.0.0.1.
- * Ignore the my_name specified by the caller, and
- * use "127.0.0.1" instead.
- */
- caller = svc_getcaller(rqstp->rq_xprt)->sin_addr;
- if (caller.s_addr != htonl(INADDR_LOOPBACK)) {
- note(N_WARNING,
- "Call to statd from non-local host %s",
- inet_ntoa(caller));
- goto failure;
- }
- if (ntohs(svc_getcaller(rqstp->rq_xprt)->sin_port) >= 1024) {
- note(N_WARNING,
- "Call to statd-simu-crash from unprivileged port\n");
- goto failure;
- }
-#endif
note (N_WARNING, "*** SIMULATING CRASH! ***");
my_svc_exit ();
if (rtnl)
nlist_kill (&rtnl);
-#ifdef RESTRICTED_STATD
failure:
-#endif
return ((void *)&result);
}
* Copyright (C) 2004-2006 Olaf Kirch <okir@suse.de>
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <errno.h>
#include <grp.h>
-#include "config.h"
-
#ifndef BASEDIR
# ifdef NFS_STATEDIR
# define BASEDIR NFS_STATEDIR
#define NSM_MAX_TIMEOUT 120 /* don't make this too big */
#define MAXMSGSIZE 256
-typedef struct sockaddr_storage nsm_address;
-
struct nsm_host {
struct nsm_host * next;
char * name;
char * path;
- nsm_address addr;
+ struct sockaddr_storage addr;
struct addrinfo *ai;
time_t last_used;
time_t send_next;
static void backup_hosts(const char *, const char *);
static void get_hosts(const char *);
static void insert_host(struct nsm_host *);
-struct nsm_host * find_host(uint32_t);
-static int addr_get_port(nsm_address *);
-static void addr_set_port(nsm_address *, int);
-static struct addrinfo *host_lookup(int, const char *);
-void nsm_log(int fac, const char *fmt, ...);
+static struct nsm_host *find_host(uint32_t);
+static void nsm_log(int fac, const char *fmt, ...);
static int record_pid(void);
static void drop_privs(void);
-static void set_kernel_nsm_state(int state);
+static void set_kernel_nsm_state(int state);
static struct nsm_host * hosts = NULL;
+/*
+ * Address handling utilities
+ */
+
+static unsigned short smn_get_port(const struct sockaddr *sap)
+{
+ switch (sap->sa_family) {
+ case AF_INET:
+ return ntohs(((struct sockaddr_in *)sap)->sin_port);
+ case AF_INET6:
+ return ntohs(((struct sockaddr_in6 *)sap)->sin6_port);
+ }
+ return 0;
+}
+
+static void smn_set_port(struct sockaddr *sap, const unsigned short port)
+{
+ switch (sap->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)sap)->sin_port = htons(port);
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *)sap)->sin6_port = htons(port);
+ break;
+ }
+}
+
+static struct addrinfo *smn_lookup(const sa_family_t family, const char *name)
+{
+ struct addrinfo *ai, hint = {
+ .ai_family = family,
+ .ai_protocol = IPPROTO_UDP,
+ };
+
+ if (getaddrinfo(name, NULL, &hint, &ai) != 0)
+ return NULL;
+
+ return ai;
+}
+
int
main(int argc, char **argv)
{
_SM_STATE_PATH == NULL ||
_SM_DIR_PATH == NULL ||
_SM_BAK_PATH == NULL) {
- nsm_log(LOG_WARNING, "unable to allocate memory");
+ nsm_log(LOG_ERR, "unable to allocate memory");
exit(1);
}
strcat(strcpy(_SM_STATE_PATH, _SM_BASE_PATH), "/state");
usage: fprintf(stderr,
"Usage: sm-notify [-dfq] [-m max-retry-minutes] [-p srcport]\n"
" [-P /path/to/state/directory] [-v my_host_name]\n");
- return 1;
+ exit(1);
}
+ log_syslog = 1;
+ openlog("sm-notify", LOG_PID, LOG_DAEMON);
+
if (strcmp(_SM_BASE_PATH, BASEDIR) == 0) {
if (record_pid() == 0 && force == 0 && opt_update_state == 1)
/* already run, don't try again */
+ nsm_log(LOG_NOTICE, "Already notifying clients; Exiting!");
exit(0);
}
strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname)-1);
} else
if (gethostname(nsm_hostname, sizeof(nsm_hostname)) < 0) {
- perror("gethostname");
- return 1;
+ nsm_log(LOG_ERR, "Failed to obtain name of local host: %s",
+ strerror(errno));
+ exit(1);
}
backup_hosts(_SM_DIR_PATH, _SM_BAK_PATH);
get_hosts(_SM_BAK_PATH);
+ /* If there are not hosts to notify, just exit */
+ if (!hosts) {
+ nsm_log(LOG_DEBUG, "No hosts to notify; exiting");
+ return 0;
+ }
+
/* Get and update the NSM state. This will call sync() */
nsm_state = nsm_get_state(opt_update_state);
set_kernel_nsm_state(nsm_state);
if (!opt_quiet)
printf("Backgrounding to notify hosts...\n");
- openlog("sm-notify", LOG_PID, LOG_DAEMON);
- log_syslog = 1;
-
if (daemon(0, 0) < 0) {
- nsm_log(LOG_WARNING, "unable to background: %s",
+ nsm_log(LOG_ERR, "unable to background: %s",
strerror(errno));
- return 1;
+ exit(1);
}
close(0);
"Unable to notify %s, giving up",
hp->name);
}
- return 1;
+ exit(1);
}
- return 0;
+ exit(0);
}
/*
* Notify hosts
*/
-void
+static void
notify(void)
{
- nsm_address local_addr;
+ struct sockaddr_storage address;
+ struct sockaddr *local_addr = (struct sockaddr *)&address;
time_t failtime = 0;
int sock = -1;
int retry_cnt = 0;
retry:
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
- perror("socket");
+ nsm_log(LOG_ERR, "Failed to create RPC socket: %s",
+ strerror(errno));
exit(1);
}
fcntl(sock, F_SETFL, O_NONBLOCK);
- memset(&local_addr, 0, sizeof(local_addr));
- local_addr.ss_family = AF_INET; /* Default to IPv4 */
+ memset(&address, 0, sizeof(address));
+ local_addr->sa_family = AF_INET; /* Default to IPv4 */
/* Bind source IP if provided on command line */
if (opt_srcaddr) {
- struct addrinfo *ai = host_lookup(AF_INET, opt_srcaddr);
+ struct addrinfo *ai = smn_lookup(AF_INET, opt_srcaddr);
if (!ai) {
- nsm_log(LOG_WARNING,
- "Not a valid hostname or address: \"%s\"\n",
+ nsm_log(LOG_ERR,
+ "Not a valid hostname or address: \"%s\"",
opt_srcaddr);
exit(1);
}
- memcpy(&local_addr, ai->ai_addr, ai->ai_addrlen);
+
/* We know it's IPv4 at this point */
+ memcpy(local_addr, ai->ai_addr, ai->ai_addrlen);
+
+ freeaddrinfo(ai);
}
/* Use source port if provided on the command line,
* otherwise use bindresvport */
if (opt_srcport) {
- addr_set_port(&local_addr, opt_srcport);
- if (bind(sock, (struct sockaddr *) &local_addr, sizeof(local_addr)) < 0) {
- perror("bind");
+ smn_set_port(local_addr, opt_srcport);
+ if (bind(sock, local_addr, sizeof(struct sockaddr_in)) < 0) {
+ nsm_log(LOG_ERR, "Failed to bind RPC socket: %s",
+ strerror(errno));
exit(1);
}
} else {
struct servent *se;
- struct sockaddr_in *sin = (struct sockaddr_in *)&local_addr;
+ struct sockaddr_in *sin = (struct sockaddr_in *)local_addr;
(void) bindresvport(sock, sin);
/* try to avoid known ports */
se = getservbyport(sin->sin_port, "udp");
/*
* Send notification to a single host
*/
-int
+static int
notify_host(int sock, struct nsm_host *host)
{
+ struct sockaddr_storage address;
+ struct sockaddr *dest = (struct sockaddr *)&address;
+ socklen_t destlen = sizeof(address);
static unsigned int xid = 0;
- nsm_address dest;
uint32_t msgbuf[MAXMSGSIZE], *p;
unsigned int len;
host->xid = xid++;
if (host->ai == NULL) {
- host->ai = host_lookup(AF_UNSPEC, host->name);
+ host->ai = smn_lookup(AF_UNSPEC, host->name);
if (host->ai == NULL) {
nsm_log(LOG_WARNING,
"%s doesn't seem to be a valid address,"
/* put first entry at end */
*next = first;
memcpy(&host->addr, first->ai_addr, first->ai_addrlen);
- addr_set_port(&host->addr, 0);
+ smn_set_port((struct sockaddr *)&host->addr, 0);
host->retries = 0;
}
- dest = host->addr;
- if (addr_get_port(&dest) == 0) {
+ memcpy(dest, &host->addr, destlen);
+ if (smn_get_port(dest) == 0) {
/* Build a PMAP packet */
nsm_log(LOG_DEBUG, "Sending portmap query to %s", host->name);
- addr_set_port(&dest, 111);
+ smn_set_port(dest, 111);
*p++ = htonl(100000);
*p++ = htonl(2);
*p++ = htonl(3);
}
len = (p - msgbuf) << 2;
- if (sendto(sock, msgbuf, len, 0, (struct sockaddr *) &dest, sizeof(dest)) < 0)
+ if (sendto(sock, msgbuf, len, 0, dest, destlen) < 0)
nsm_log(LOG_WARNING, "Sending Reboot Notification to "
"'%s' failed: errno %d (%s)", host->name, errno, strerror(errno));
/*
* Receive reply from remote host
*/
-void
+static void
recv_reply(int sock)
{
struct nsm_host *hp;
+ struct sockaddr *sap;
uint32_t msgbuf[MAXMSGSIZE], *p, *end;
uint32_t xid;
int res;
this reply */
if ((hp = find_host(xid)) == NULL)
return;
+ sap = (struct sockaddr *)&hp->addr;
- if (addr_get_port(&hp->addr) == 0) {
+ if (smn_get_port(sap) == 0) {
/* This was a portmap request */
unsigned int port;
hp->timeout = NSM_MAX_TIMEOUT;
hp->send_next += NSM_MAX_TIMEOUT;
} else {
- addr_set_port(&hp->addr, port);
+ smn_set_port(sap, port);
if (hp->timeout >= NSM_MAX_TIMEOUT / 4)
hp->timeout = NSM_MAX_TIMEOUT / 4;
}
* packet)
*/
if (p <= end) {
- nsm_log(LOG_DEBUG, "Host %s notified successfully", hp->name);
+ nsm_log(LOG_DEBUG, "Host %s notified successfully",
+ hp->name);
unlink(hp->path);
free(hp->name);
free(hp->path);
DIR *dir;
if (!(dir = opendir(dirname))) {
- perror(dirname);
+ nsm_log(LOG_WARNING,
+ "Failed to open %s: %s", dirname, strerror(errno));
return;
}
DIR *dir;
if (!(dir = opendir(dirname))) {
- perror(dirname);
+ nsm_log(LOG_WARNING,
+ "Failed to open %s: %s", dirname, strerror(errno));
return;
}
continue;
if (host == NULL)
host = calloc(1, sizeof(*host));
+ if (host == NULL) {
+ nsm_log(LOG_WARNING, "Unable to allocate memory");
+ return;
+ }
snprintf(path, sizeof(path), "%s/%s", dirname, de->d_name);
if (stat(path, &stb) < 0)
/*
* Insert host into sorted list
*/
-void
+static void
insert_host(struct nsm_host *host)
{
struct nsm_host **where, *p;
/*
* Find host given the XID
*/
-struct nsm_host *
+static struct nsm_host *
find_host(uint32_t xid)
{
struct nsm_host **where, *p;
/*
* Retrieve the current NSM state
*/
-unsigned int
+static unsigned int
nsm_get_state(int update)
{
char newfile[PATH_MAX];
snprintf(newfile, sizeof(newfile),
"%s.new", _SM_STATE_PATH);
if ((fd = open(newfile, O_CREAT|O_WRONLY, 0644)) < 0) {
- nsm_log(LOG_WARNING, "Cannot create %s: %m", newfile);
+ nsm_log(LOG_ERR, "Cannot create %s: %m", newfile);
exit(1);
}
if (write(fd, &state, sizeof(state)) != sizeof(state)) {
- nsm_log(LOG_WARNING,
+ nsm_log(LOG_ERR,
"Failed to write state to %s", newfile);
exit(1);
}
close(fd);
if (rename(newfile, _SM_STATE_PATH) < 0) {
- nsm_log(LOG_WARNING,
+ nsm_log(LOG_ERR,
"Cannot create %s: %m", _SM_STATE_PATH);
exit(1);
}
return state;
}
-/*
- * Address handling utilities
- */
-
-int
-addr_get_port(nsm_address *addr)
-{
- switch (((struct sockaddr *) addr)->sa_family) {
- case AF_INET:
- return ntohs(((struct sockaddr_in *) addr)->sin_port);
- case AF_INET6:
- return ntohs(((struct sockaddr_in6 *) addr)->sin6_port);
- }
- return 0;
-}
-
-static void
-addr_set_port(nsm_address *addr, int port)
-{
- switch (((struct sockaddr *) addr)->sa_family) {
- case AF_INET:
- ((struct sockaddr_in *) addr)->sin_port = htons(port);
- break;
- case AF_INET6:
- ((struct sockaddr_in6 *) addr)->sin6_port = htons(port);
- }
-}
-
-static struct addrinfo *
-host_lookup(int af, const char *name)
-{
- struct addrinfo hints, *ai;
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = af;
- hints.ai_protocol = IPPROTO_UDP;
-
- if (getaddrinfo(name, NULL, &hints, &ai) != 0)
- return NULL;
-
- return ai;
-}
-
/*
* Log a message
*/
-void
+static void
nsm_log(int fac, const char *fmt, ...)
{
va_list ap;
if (st.st_uid == 0) {
nsm_log(LOG_WARNING,
- "sm-notify running as root. chown %s to choose different user\n",
+ "sm-notify running as root. chown %s to choose different user",
_SM_DIR_PATH);
return;
}
};
extern void sm_prog_1 (struct svc_req *, register SVCXPRT *);
-extern int statd_get_socket(void);
static void load_state_number(void);
#ifdef SIMULATIONS
}
/* Make sure we have a privilege port for calling into the kernel */
- statd_get_socket();
+ if (statd_get_socket() < 0)
+ exit(1);
/* If sm-notify didn't take all the state files, load
* state information into our notify-list so we can
extern void my_svc_run(void);
extern void notify_hosts(void);
extern void shuffle_dirs(void);
+extern int statd_get_socket(void);
extern int process_notify_list(void);
extern int process_reply(FD_SET_TYPE *);
extern char * xstrdup(const char *);