nfs-utils/nfs-utils-1.2.2-rc6.patch

7425 lines
211 KiB
Diff
Raw Normal View History

diff -up nfs-utils-1.2.1/configure.ac.orig nfs-utils-1.2.1/configure.ac
--- nfs-utils-1.2.1/configure.ac.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/configure.ac 2010-01-14 03:53:55.433919206 -0500
@@ -402,6 +402,7 @@ AC_CONFIG_FILES([
support/include/Makefile
support/misc/Makefile
support/nfs/Makefile
+ support/nsm/Makefile
tools/Makefile
tools/locktest/Makefile
tools/nlmtest/Makefile
@@ -416,6 +417,8 @@ AC_CONFIG_FILES([
utils/nfsd/Makefile
utils/nfsstat/Makefile
utils/showmount/Makefile
- utils/statd/Makefile])
+ utils/statd/Makefile
+ tests/Makefile
+ tests/nsm_client/Makefile])
AC_OUTPUT
diff -up nfs-utils-1.2.1/.gitignore.orig nfs-utils-1.2.1/.gitignore
--- nfs-utils-1.2.1/.gitignore.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/.gitignore 2010-01-14 03:53:55.432898989 -0500
@@ -55,10 +55,15 @@ support/export/mount.h
support/export/mount_clnt.c
support/export/mount_xdr.c
support/include/mount.h
-utils/statd/sm_inter.h
-utils/statd/sm_inter_clnt.c
-utils/statd/sm_inter_svc.c
-utils/statd/sm_inter_xdr.c
+support/nsm/sm_inter.h
+support/nsm/sm_inter_clnt.c
+support/nsm/sm_inter_svc.c
+support/nsm/sm_inter_xdr.c
+support/include/sm_inter.h
+tests/nsm_client/nlm_sm_inter.h
+tests/nsm_client/nlm_sm_inter_clnt.c
+tests/nsm_client/nlm_sm_inter_svc.c
+tests/nsm_client/nlm_sm_inter_xdr.c
# cscope database files
cscope.*
# generic editor backup et al
diff -up nfs-utils-1.2.1/Makefile.am.orig nfs-utils-1.2.1/Makefile.am
--- nfs-utils-1.2.1/Makefile.am.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/Makefile.am 2010-01-14 03:53:55.432898989 -0500
@@ -2,7 +2,7 @@
AUTOMAKE_OPTIONS = foreign
-SUBDIRS = tools support utils linux-nfs
+SUBDIRS = tools support utils linux-nfs tests
MAINTAINERCLEANFILES = Makefile.in
diff -up nfs-utils-1.2.1/support/export/client.c.orig nfs-utils-1.2.1/support/export/client.c
--- nfs-utils-1.2.1/support/export/client.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/support/export/client.c 2010-01-14 03:53:55.434909240 -0500
@@ -297,7 +297,7 @@ name_cmp(char *a, char *b)
/* compare strings a and b, but only upto ',' in a */
while (*a && *b && *a != ',' && *a == *b)
a++, b++;
- if (!*b && (!*a || !a == ',') )
+ if (!*b && (!*a || *a == ','))
return 0;
if (!*b) return 1;
if (!*a || *a == ',') return -1;
diff -up nfs-utils-1.2.1/support/export/export.c.orig nfs-utils-1.2.1/support/export/export.c
--- nfs-utils-1.2.1/support/export/export.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/support/export/export.c 2010-01-14 03:53:55.435909478 -0500
@@ -28,6 +28,22 @@ static int export_check(nfs_export *, st
static nfs_export *
export_allowed_internal(struct hostent *hp, char *path);
+static void warn_duplicated_exports(nfs_export *exp, struct exportent *eep)
+{
+ if (exp->m_export.e_flags != eep->e_flags) {
+ xlog(L_ERROR, "incompatible duplicated export entries:");
+ xlog(L_ERROR, "\t%s:%s (0x%x) [IGNORED]", eep->e_hostname,
+ eep->e_path, eep->e_flags);
+ xlog(L_ERROR, "\t%s:%s (0x%x)", exp->m_export.e_hostname,
+ exp->m_export.e_path, exp->m_export.e_flags);
+ } else {
+ xlog(L_ERROR, "duplicated export entries:");
+ xlog(L_ERROR, "\t%s:%s", eep->e_hostname, eep->e_path);
+ xlog(L_ERROR, "\t%s:%s", exp->m_export.e_hostname,
+ exp->m_export.e_path);
+ }
+}
+
int
export_read(char *fname)
{
@@ -36,27 +52,13 @@ export_read(char *fname)
setexportent(fname, "r");
while ((eep = getexportent(0,1)) != NULL) {
- exp = export_lookup(eep->e_hostname, eep->e_path, 0);
- if (!exp)
- export_create(eep,0);
- else {
- if (exp->m_export.e_flags != eep->e_flags) {
- xlog(L_ERROR, "incompatible duplicated export entries:");
- xlog(L_ERROR, "\t%s:%s (0x%x) [IGNORED]", eep->e_hostname,
- eep->e_path, eep->e_flags);
- xlog(L_ERROR, "\t%s:%s (0x%x)", exp->m_export.e_hostname,
- exp->m_export.e_path, exp->m_export.e_flags);
- }
- else {
- xlog(L_ERROR, "duplicated export entries:");
- xlog(L_ERROR, "\t%s:%s", eep->e_hostname, eep->e_path);
- xlog(L_ERROR, "\t%s:%s", exp->m_export.e_hostname,
- exp->m_export.e_path);
- }
- }
+ exp = export_lookup(eep->e_hostname, eep->e_path, 0);
+ if (!exp)
+ export_create(eep, 0);
+ else
+ warn_duplicated_exports(exp, eep);
}
endexportent();
-
return 0;
}
diff -up nfs-utils-1.2.1/support/export/xtab.c.orig nfs-utils-1.2.1/support/export/xtab.c
--- nfs-utils-1.2.1/support/export/xtab.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/support/export/xtab.c 2010-01-14 03:53:55.435909478 -0500
@@ -19,7 +19,9 @@
#include "exportfs.h"
#include "xio.h"
#include "xlog.h"
+#include "v4root.h"
+int v4root_needed;
static void cond_rename(char *newfile, char *oldfile);
static int
@@ -36,6 +38,8 @@ xtab_read(char *xtab, char *lockfn, int
if ((lockid = xflock(lockfn, "r")) < 0)
return 0;
setexportent(xtab, "r");
+ if (is_export == 1)
+ v4root_needed = 1;
while ((xp = getexportent(is_export==0, 0)) != NULL) {
if (!(exp = export_lookup(xp->e_hostname, xp->e_path, is_export != 1)) &&
!(exp = export_create(xp, is_export!=1))) {
@@ -48,6 +52,8 @@ xtab_read(char *xtab, char *lockfn, int
case 1:
exp->m_xtabent = 1;
exp->m_mayexport = 1;
+ if ((xp->e_flags & NFSEXP_FSID) && xp->e_fsid == 0)
+ v4root_needed = 0;
break;
case 2:
exp->m_exported = -1;/* may be exported */
diff -up nfs-utils-1.2.1/support/include/exportfs.h.orig nfs-utils-1.2.1/support/include/exportfs.h
--- nfs-utils-1.2.1/support/include/exportfs.h.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/support/include/exportfs.h 2010-01-14 03:53:55.437919091 -0500
@@ -99,10 +99,19 @@ int xtab_mount_write(void);
int xtab_export_write(void);
void xtab_append(nfs_export *);
+int secinfo_addflavor(struct flav_info *, struct exportent *);
+
int rmtab_read(void);
struct nfskey * key_lookup(char *hname);
+struct export_features {
+ unsigned int flags;
+ unsigned int secinfo_flags;
+};
+
+struct export_features *get_export_features(void);
+
/* Record export error. */
extern int export_errno;
diff -up nfs-utils-1.2.1/support/include/ha-callout.h.orig nfs-utils-1.2.1/support/include/ha-callout.h
--- nfs-utils-1.2.1/support/include/ha-callout.h.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/support/include/ha-callout.h 2010-01-14 03:53:55.437919091 -0500
@@ -53,11 +53,7 @@ ha_callout(char *event, char *arg1, char
default: pid = waitpid(pid, &ret, 0);
}
sigaction(SIGCHLD, &oldact, &newact);
-#ifdef dprintf
- dprintf(N_DEBUG, "ha callout returned %d\n", WEXITSTATUS(ret));
-#else
xlog(D_GENERAL, "ha callout returned %d\n", WEXITSTATUS(ret));
-#endif
}
#endif
diff -up nfs-utils-1.2.1/support/include/Makefile.am.orig nfs-utils-1.2.1/support/include/Makefile.am
--- nfs-utils-1.2.1/support/include/Makefile.am.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/support/include/Makefile.am 2010-01-14 03:53:55.436909205 -0500
@@ -9,6 +9,8 @@ noinst_HEADERS = \
nfs_mntent.h \
nfs_paths.h \
nfslib.h \
+ nfsrpc.h \
+ nsm.h \
rpcmisc.h \
tcpwrapper.h \
xio.h \
diff -up nfs-utils-1.2.1/support/include/nfs/export.h.orig nfs-utils-1.2.1/support/include/nfs/export.h
--- nfs-utils-1.2.1/support/include/nfs/export.h.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/support/include/nfs/export.h 2010-01-14 03:53:55.438909200 -0500
@@ -24,6 +24,17 @@
#define NFSEXP_FSID 0x2000
#define NFSEXP_CROSSMOUNT 0x4000
#define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */
-#define NFSEXP_ALLFLAGS 0xFFFF
+#define NFSEXP_V4ROOT 0x10000
+/*
+ * All flags supported by the kernel before addition of the
+ * export_features interface:
+ */
+#define NFSEXP_OLDFLAGS 0x7E3F
+/*
+ * Flags that can vary per flavor, for kernels before addition of the
+ * export_features interface:
+ */
+#define NFSEXP_OLD_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \
+ | NFSEXP_ALLSQUASH)
#endif /* _NSF_EXPORT_H */
diff -up nfs-utils-1.2.1/support/include/nfsrpc.h.orig nfs-utils-1.2.1/support/include/nfsrpc.h
--- nfs-utils-1.2.1/support/include/nfsrpc.h.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/support/include/nfsrpc.h 2010-01-14 03:53:55.438909200 -0500
@@ -90,6 +90,18 @@ extern CLIENT *nfs_get_priv_rpcclient(
struct timeval *);
/*
+ * Convert a netid to a protocol number and protocol family
+ */
+extern int nfs_get_proto(const char *netid, sa_family_t *family,
+ unsigned long *protocol);
+
+/*
+ * Convert a protocol family and protocol name to a netid
+ */
+extern char *nfs_get_netid(const sa_family_t family,
+ const unsigned long protocol);
+
+/*
* Convert a socket address to a universal address
*/
extern char *nfs_sockaddr2universal(const struct sockaddr *);
diff -up nfs-utils-1.2.1/support/include/nsm.h.orig nfs-utils-1.2.1/support/include/nsm.h
--- nfs-utils-1.2.1/support/include/nsm.h.orig 2010-01-14 03:53:55.439819030 -0500
+++ nfs-utils-1.2.1/support/include/nsm.h 2010-01-14 03:53:55.439819030 -0500
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2009 Oracle. All rights reserved.
+ *
+ * This file is part of nfs-utils.
+ *
+ * nfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * nfs-utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nfs-utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * NSM for Linux.
+ */
+
+#ifndef NFS_UTILS_SUPPORT_NSM_H
+#define NFS_UTILS_SUPPORT_NSM_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdbool.h>
+
+#include <netdb.h>
+#include <time.h>
+
+#include "sm_inter.h"
+
+typedef unsigned int
+ (*nsm_populate_t)(const char *hostname,
+ const struct sockaddr *sap,
+ const struct mon *mon,
+ const time_t timestamp);
+
+/* file.c */
+
+extern _Bool nsm_setup_pathnames(const char *progname,
+ const char *parentdir);
+extern _Bool nsm_is_default_parentdir(void);
+extern _Bool nsm_drop_privileges(const int pidfd);
+
+extern int nsm_get_state(_Bool update);
+extern void nsm_update_kernel_state(const int state);
+
+extern unsigned int
+ nsm_retire_monitored_hosts(void);
+extern unsigned int
+ nsm_load_monitor_list(nsm_populate_t func);
+extern unsigned int
+ nsm_load_notify_list(nsm_populate_t func);
+
+extern _Bool nsm_insert_monitored_host(const char *hostname,
+ const struct sockaddr *sap, const struct mon *m);
+extern void nsm_delete_monitored_host(const char *hostname);
+extern void nsm_delete_notified_host(const char *hostname);
+extern size_t nsm_priv_to_hex(const char *priv, char *buf,
+ const size_t buflen);
+
+#endif /* !NFS_UTILS_SUPPORT_NSM_H */
diff -up nfs-utils-1.2.1/support/include/v4root.h.orig nfs-utils-1.2.1/support/include/v4root.h
--- nfs-utils-1.2.1/support/include/v4root.h.orig 2010-01-14 03:53:55.439819030 -0500
+++ nfs-utils-1.2.1/support/include/v4root.h 2010-01-14 03:53:55.440816366 -0500
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2009 Red Hat <nfs@redhat.com>
+ * support/include/v4root.h
+ *
+ * Support routines for dynamic pseudo roots.
+ *
+ */
+
+#ifndef V4ROOT_H
+#define V4ROOT_H
+
+extern int v4root_needed;
+extern void v4root_set(void);
+
+#endif /* V4ROOT_H */
diff -up nfs-utils-1.2.1/support/Makefile.am.orig nfs-utils-1.2.1/support/Makefile.am
--- nfs-utils-1.2.1/support/Makefile.am.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/support/Makefile.am 2010-01-14 03:53:55.434909240 -0500
@@ -1,6 +1,6 @@
## Process this file with automake to produce Makefile.in
-SUBDIRS = export include misc nfs
+SUBDIRS = export include misc nfs nsm
MAINTAINERCLEANFILES = Makefile.in
diff -up nfs-utils-1.2.1/support/nfs/exports.c.orig nfs-utils-1.2.1/support/nfs/exports.c
--- nfs-utils-1.2.1/support/nfs/exports.c.orig 2010-01-14 03:53:10.150981266 -0500
+++ nfs-utils-1.2.1/support/nfs/exports.c 2010-01-14 03:55:37.560911606 -0500
@@ -84,6 +84,31 @@ setexportent(char *fname, char *type)
first = 1;
}
+static void init_exportent (struct exportent *ee, int fromkernel)
+{
+ ee->e_flags = EXPORT_DEFAULT_FLAGS;
+ /* some kernels assume the default is sync rather than
+ * async. More recent kernels always report one or other,
+ * but this test makes sure we assume same as kernel
+ * Ditto for wgather
+ */
+ if (fromkernel) {
+ ee->e_flags &= ~NFSEXP_ASYNC;
+ ee->e_flags &= ~NFSEXP_GATHERED_WRITES;
+ }
+ ee->e_anonuid = 65534;
+ ee->e_anongid = 65534;
+ ee->e_squids = NULL;
+ ee->e_sqgids = NULL;
+ ee->e_mountpoint = NULL;
+ ee->e_fslocmethod = FSLOC_NONE;
+ ee->e_fslocdata = NULL;
+ ee->e_secinfo[0].flav = NULL;
+ ee->e_nsquids = 0;
+ ee->e_nsqgids = 0;
+ ee->e_uuid = NULL;
+}
+
struct exportent *
getexportent(int fromkernel, int fromexports)
{
@@ -102,26 +127,7 @@ getexportent(int fromkernel, int fromexp
has_default_opts = 0;
has_default_subtree_opts = 0;
- def_ee.e_flags = EXPORT_DEFAULT_FLAGS;
- /* some kernels assume the default is sync rather than
- * async. More recent kernels always report one or other,
- * but this test makes sure we assume same as kernel
- * Ditto for wgather
- */
- if (fromkernel) {
- def_ee.e_flags &= ~NFSEXP_ASYNC;
- def_ee.e_flags &= ~NFSEXP_GATHERED_WRITES;
- }
- def_ee.e_anonuid = 65534;
- def_ee.e_anongid = 65534;
- def_ee.e_squids = NULL;
- def_ee.e_sqgids = NULL;
- def_ee.e_mountpoint = NULL;
- def_ee.e_fslocmethod = FSLOC_NONE;
- def_ee.e_fslocdata = NULL;
- def_ee.e_secinfo[0].flav = NULL;
- def_ee.e_nsquids = 0;
- def_ee.e_nsqgids = 0;
+ init_exportent(&def_ee, fromkernel);
ok = getpath(def_ee.e_path, sizeof(def_ee.e_path));
if (ok <= 0)
@@ -334,18 +340,7 @@ mkexportent(char *hname, char *path, cha
{
static struct exportent ee;
- ee.e_flags = EXPORT_DEFAULT_FLAGS;
- ee.e_anonuid = 65534;
- ee.e_anongid = 65534;
- ee.e_squids = NULL;
- ee.e_sqgids = NULL;
- ee.e_mountpoint = NULL;
- ee.e_fslocmethod = FSLOC_NONE;
- ee.e_fslocdata = NULL;
- ee.e_secinfo[0].flav = NULL;
- ee.e_nsquids = 0;
- ee.e_nsqgids = 0;
- ee.e_uuid = NULL;
+ init_exportent(&ee, 0);
xfree(ee.e_hostname);
ee.e_hostname = xstrdup(hname);
@@ -385,7 +380,7 @@ static int valid_uuid(char *uuid)
* do nothing if it's already there. Returns the index of flavor
* in the resulting array in any case.
*/
-static int secinfo_addflavor(struct flav_info *flav, struct exportent *ep)
+int secinfo_addflavor(struct flav_info *flav, struct exportent *ep)
{
struct sec_entry *p;
@@ -467,9 +462,20 @@ static void clearflags(int mask, unsigne
}
}
-/* options that can vary per flavor: */
-#define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \
- | NFSEXP_ALLSQUASH)
+/*
+ * For those flags which are not allowed to vary by pseudoflavor,
+ * ensure that the export flags agree with the flags on each
+ * pseudoflavor:
+ */
+static void fix_pseudoflavor_flags(struct exportent *ep)
+{
+ struct export_features *ef;
+ struct sec_entry *p;
+
+ ef = get_export_features();
+ for (p = ep->e_secinfo; p->flav; p++)
+ p->flags |= ep->e_flags & ~ef->secinfo_flags;
+}
/*
* Parse option string pointed to by cp and set mount options accordingly.
@@ -477,7 +483,6 @@ static void clearflags(int mask, unsigne
static int
parseopts(char *cp, struct exportent *ep, int warn, int *had_subtree_opt_ptr)
{
- struct sec_entry *p;
int had_subtree_opt = 1;
char *flname = efname?efname:"command line";
int flline = efp?efp->x_line:0;
@@ -507,25 +512,25 @@ parseopts(char *cp, struct exportent *ep
else if (strcmp(opt, "rw") == 0)
clearflags(NFSEXP_READONLY, active, ep);
else if (!strcmp(opt, "secure"))
- ep->e_flags &= ~NFSEXP_INSECURE_PORT;
+ clearflags(NFSEXP_INSECURE_PORT, active, ep);
else if (!strcmp(opt, "insecure"))
- ep->e_flags |= NFSEXP_INSECURE_PORT;
+ setflags(NFSEXP_INSECURE_PORT, active, ep);
else if (!strcmp(opt, "sync"))
- ep->e_flags &= ~NFSEXP_ASYNC;
+ clearflags(NFSEXP_ASYNC, active, ep);
else if (!strcmp(opt, "async"))
- ep->e_flags |= NFSEXP_ASYNC;
+ setflags(NFSEXP_ASYNC, active, ep);
else if (!strcmp(opt, "nohide"))
- ep->e_flags |= NFSEXP_NOHIDE;
+ setflags(NFSEXP_NOHIDE, active, ep);
else if (!strcmp(opt, "hide"))
- ep->e_flags &= ~NFSEXP_NOHIDE;
+ clearflags(NFSEXP_NOHIDE, active, ep);
else if (!strcmp(opt, "crossmnt"))
- ep->e_flags |= NFSEXP_CROSSMOUNT;
+ setflags(NFSEXP_CROSSMOUNT, active, ep);
else if (!strcmp(opt, "nocrossmnt"))
- ep->e_flags &= ~NFSEXP_CROSSMOUNT;
+ clearflags(NFSEXP_CROSSMOUNT, active, ep);
else if (!strcmp(opt, "wdelay"))
- ep->e_flags |= NFSEXP_GATHERED_WRITES;
+ setflags(NFSEXP_GATHERED_WRITES, active, ep);
else if (!strcmp(opt, "no_wdelay"))
- ep->e_flags &= ~NFSEXP_GATHERED_WRITES;
+ clearflags(NFSEXP_GATHERED_WRITES, active, ep);
else if (strcmp(opt, "root_squash") == 0)
setflags(NFSEXP_ROOTSQUASH, active, ep);
else if (!strcmp(opt, "no_root_squash"))
@@ -536,22 +541,22 @@ parseopts(char *cp, struct exportent *ep
clearflags(NFSEXP_ALLSQUASH, active, ep);
else if (strcmp(opt, "subtree_check") == 0) {
had_subtree_opt = 1;
- ep->e_flags &= ~NFSEXP_NOSUBTREECHECK;
+ clearflags(NFSEXP_NOSUBTREECHECK, active, ep);
} else if (strcmp(opt, "no_subtree_check") == 0) {
had_subtree_opt = 1;
- ep->e_flags |= NFSEXP_NOSUBTREECHECK;
+ setflags(NFSEXP_NOSUBTREECHECK, active, ep);
} else if (strcmp(opt, "auth_nlm") == 0)
- ep->e_flags &= ~NFSEXP_NOAUTHNLM;
+ clearflags(NFSEXP_NOAUTHNLM, active, ep);
else if (strcmp(opt, "no_auth_nlm") == 0)
- ep->e_flags |= NFSEXP_NOAUTHNLM;
+ setflags(NFSEXP_NOAUTHNLM, active, ep);
else if (strcmp(opt, "secure_locks") == 0)
- ep->e_flags &= ~NFSEXP_NOAUTHNLM;
+ clearflags(NFSEXP_NOAUTHNLM, active, ep);
else if (strcmp(opt, "insecure_locks") == 0)
- ep->e_flags |= NFSEXP_NOAUTHNLM;
+ setflags(NFSEXP_NOAUTHNLM, active, ep);
else if (strcmp(opt, "acl") == 0)
- ep->e_flags &= ~NFSEXP_NOACL;
+ clearflags(NFSEXP_NOACL, active, ep);
else if (strcmp(opt, "no_acl") == 0)
- ep->e_flags |= NFSEXP_NOACL;
+ setflags(NFSEXP_NOACL, active, ep);
else if (strncmp(opt, "anonuid=", 8) == 0) {
char *oe;
ep->e_anonuid = strtol(opt+8, &oe, 10);
@@ -583,11 +588,11 @@ bad_option:
char *oe;
if (strcmp(opt+5, "root") == 0) {
ep->e_fsid = 0;
- ep->e_flags |= NFSEXP_FSID;
+ setflags(NFSEXP_FSID, active, ep);
} else {
ep->e_fsid = strtoul(opt+5, &oe, 0);
if (opt[5]!='\0' && *oe == '\0')
- ep->e_flags |= NFSEXP_FSID;
+ setflags(NFSEXP_FSID, active, ep);
else if (valid_uuid(opt+5))
ep->e_uuid = strdup(opt+5);
else {
@@ -628,22 +633,15 @@ bad_option:
} else {
xlog(L_ERROR, "%s:%d: unknown keyword \"%s\"\n",
flname, flline, opt);
- ep->e_flags |= NFSEXP_ALLSQUASH | NFSEXP_READONLY;
+ setflags(NFSEXP_ALLSQUASH | NFSEXP_READONLY, active, ep);
goto bad_option;
}
free(opt);
while (isblank(*cp))
cp++;
}
- /*
- * Turn on nohide which will allow this export to cross over
- * the 'mount --bind' mount point.
- */
- if (ep->e_fslocdata)
- ep->e_flags |= NFSEXP_NOHIDE;
- for (p = ep->e_secinfo; p->flav; p++)
- p->flags |= ep->e_flags & ~NFSEXP_SECINFO_FLAGS;
+ fix_pseudoflavor_flags(ep);
ep->e_squids = squids;
ep->e_sqgids = sqgids;
ep->e_nsquids = nsquids;
@@ -760,4 +758,34 @@ syntaxerr(char *msg)
xlog(L_ERROR, "%s:%d: syntax error: %s",
efname, efp?efp->x_line:0, msg);
}
-
+struct export_features *get_export_features(void)
+{
+ static char *path = "/proc/fs/nfsd/export_features";
+ static struct export_features ef;
+ static int cached = 0;
+ char buf[50];
+ int c;
+ int fd;
+
+ if (cached)
+ return &ef;
+
+ ef.flags = NFSEXP_OLDFLAGS;
+ ef.secinfo_flags = NFSEXP_OLD_SECINFO_FLAGS;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ goto good;
+ fd = read(fd, buf, 50);
+ if (fd == -1)
+ goto err;
+ c = sscanf(buf, "%x %x", &ef.flags, &ef.secinfo_flags);
+ if (c != 2)
+ goto err;
+good:
+ cached = 1;
+ return &ef;
+err:
+ xlog(L_WARNING, "unexpected error reading %s", path);
+ return &ef;
+}
diff -up nfs-utils-1.2.1/support/nfs/getport.c.orig nfs-utils-1.2.1/support/nfs/getport.c
--- nfs-utils-1.2.1/support/nfs/getport.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/support/nfs/getport.c 2010-01-14 03:53:55.441842012 -0500
@@ -199,7 +199,63 @@ static CLIENT *nfs_gp_get_rpcbclient(str
return clnt;
}
-/*
+/**
+ * nfs_get_proto - Convert a netid to an address family and protocol number
+ * @netid: C string containing a netid
+ * @family: OUT: address family
+ * @protocol: OUT: protocol number
+ *
+ * Returns 1 and fills in @protocol if the netid was recognized;
+ * otherwise zero is returned.
+ */
+#ifdef HAVE_LIBTIRPC
+int
+nfs_get_proto(const char *netid, sa_family_t *family, unsigned long *protocol)
+{
+ struct netconfig *nconf;
+ struct protoent *proto;
+
+ nconf = getnetconfigent(netid);
+ if (nconf == NULL)
+ return 0;
+
+ proto = getprotobyname(nconf->nc_proto);
+ if (proto == NULL) {
+ freenetconfigent(nconf);
+ return 0;
+ }
+
+ *family = AF_UNSPEC;
+ if (strcmp(nconf->nc_protofmly, NC_INET) == 0)
+ *family = AF_INET;
+ if (strcmp(nconf->nc_protofmly, NC_INET6) == 0)
+ *family = AF_INET6;
+ freenetconfigent(nconf);
+
+ *protocol = (unsigned long)proto->p_proto;
+ return 1;
+}
+#else /* !HAVE_LIBTIRPC */
+int
+nfs_get_proto(const char *netid, sa_family_t *family, unsigned long *protocol)
+{
+ struct protoent *proto;
+
+ proto = getprotobyname(netid);
+ if (proto == NULL)
+ return 0;
+
+ *family = AF_INET;
+ *protocol = (unsigned long)proto->p_proto;
+ return 1;
+}
+#endif /* !HAVE_LIBTIRPC */
+
+/**
+ * nfs_get_netid - Convert a protocol family and protocol name to a netid
+ * @family: protocol family
+ * @protocol: protocol number
+ *
* One of the arguments passed when querying remote rpcbind services
* via rpcbind v3 or v4 is a netid string. This replaces the pm_prot
* field used in legacy PMAP_GETPORT calls.
@@ -213,13 +269,12 @@ static CLIENT *nfs_gp_get_rpcbclient(str
* first entry that matches @family and @protocol and whose netid string
* fits in the provided buffer.
*
- * Returns a '\0'-terminated string if successful; otherwise NULL.
+ * Returns a '\0'-terminated string if successful. Caller must
+ * free the returned string. Otherwise NULL is returned, and
* rpc_createerr.cf_stat is set to reflect the error.
*/
#ifdef HAVE_LIBTIRPC
-
-static char *nfs_gp_get_netid(const sa_family_t family,
- const unsigned short protocol)
+char *nfs_get_netid(const sa_family_t family, const unsigned long protocol)
{
char *nc_protofmly, *nc_proto, *nc_netid;
struct netconfig *nconf;
@@ -255,6 +310,9 @@ static char *nfs_gp_get_netid(const sa_f
nc_netid = strdup(nconf->nc_netid);
endnetconfig(handle);
+
+ if (nc_netid == NULL)
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
return nc_netid;
}
endnetconfig(handle);
@@ -263,8 +321,28 @@ out:
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
return NULL;
}
+#else /* !HAVE_LIBTIRPC */
+char *nfs_get_netid(const sa_family_t family, const unsigned long protocol)
+{
+ struct protoent *proto;
+ char *netid;
-#endif /* HAVE_LIBTIRPC */
+ if (family != AF_INET)
+ goto out;
+ proto = getprotobynumber((int)protocol);
+ if (proto == NULL)
+ goto out;
+
+ netid = strdup(proto->p_name);
+ if (netid == NULL)
+ rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+ return netid;
+
+out:
+ rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+ return NULL;
+}
+#endif /* !HAVE_LIBTIRPC */
/*
* Extract a port number from a universal address, and terminate the
@@ -421,7 +499,7 @@ static int nfs_gp_init_rpcb_parms(const
{
char *netid, *addr;
- netid = nfs_gp_get_netid(sap->sa_family, protocol);
+ netid = nfs_get_netid(sap->sa_family, protocol);
if (netid == NULL)
return 0;
diff -up nfs-utils-1.2.1/support/nsm/file.c.orig nfs-utils-1.2.1/support/nsm/file.c
--- nfs-utils-1.2.1/support/nsm/file.c.orig 2010-01-14 03:53:55.443909113 -0500
+++ nfs-utils-1.2.1/support/nsm/file.c 2010-01-14 03:53:55.443909113 -0500
@@ -0,0 +1,843 @@
+/*
+ * Copyright 2009 Oracle. All rights reserved.
+ *
+ * This file is part of nfs-utils.
+ *
+ * nfs-utils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * nfs-utils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nfs-utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * NSM for Linux.
+ *
+ * Callback information and NSM state is stored in files, usually
+ * under /var/lib/nfs. A database of information contained in local
+ * files stores NLM callback data and what remote peers to notify of
+ * reboots.
+ *
+ * For each monitored remote peer, a text file is created under the
+ * directory specified by NSM_MONITOR_DIR. The name of the file
+ * is a valid DNS hostname. The hostname string must be a valid
+ * ASCII DNS name, and must not contain slash characters, white space,
+ * or '\0' (ie. anything that might have some special meaning in a
+ * path name).
+ *
+ * The contents of each file include seven blank-separated fields of
+ * text, finished with '\n'. The first field contains the network
+ * address of the NLM service to call back. The current implementation
+ * supports using only IPv4 addresses, so the only contents of this
+ * field are a network order IPv4 address expressed in 8 hexadecimal
+ * characters.
+ *
+ * The next four fields are text strings of hexadecimal characters,
+ * representing:
+ *
+ * 2. A 4 byte RPC program number of the NLM service to call back
+ * 3. A 4 byte RPC version number of the NLM service to call back
+ * 4. A 4 byte RPC procedure number of the NLM service to call back
+ * 5. A 16 byte opaque cookie that the NLM service uses to identify
+ * the monitored host
+ *
+ * The sixth field is the monitored host's mon_name, passed to statd
+ * via an SM_MON request.
+ *
+ * The seventh field is the my_name for this peer, which is the
+ * hostname of the local NLM (currently on Linux, the result of
+ * `uname -n`). This can be used as the source address/hostname
+ * when sending SM_NOTIFY requests.
+ *
+ * The NSM protocol does not limit the contents of these strings
+ * in any way except that they must fit into 1024 bytes. Our
+ * implementation requires that these strings not contain
+ * white space or '\0'.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <string.h>
+#include <stdint.h>
+#ifndef S_SPLINT_S
+#include <unistd.h>
+#endif
+#include <libgen.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <grp.h>
+
+#include "xlog.h"
+#include "nsm.h"
+
+#define RPCARGSLEN (4 * (8 + 1))
+#define LINELEN (RPCARGSLEN + SM_PRIV_SIZE * 2 + 1)
+
+#define NSM_KERNEL_STATE_FILE "/proc/sys/fs/nfs/nsm_local_state"
+
+/*
+ * Some distributions place statd's files in a subdirectory
+ */
+#define NSM_PATH_EXTENSION
+/* #define NSM_PATH_EXTENSION "/statd" */
+
+#define NSM_DEFAULT_STATEDIR NFS_STATEDIR NSM_PATH_EXTENSION
+
+static char nsm_base_dirname[PATH_MAX] = NSM_DEFAULT_STATEDIR;
+
+#define NSM_MONITOR_DIR "sm"
+#define NSM_NOTIFY_DIR "sm.bak"
+#define NSM_STATE_FILE "state"
+
+
+static _Bool
+error_check(const int len, const size_t buflen)
+{
+ return (len < 0) || ((size_t)len >= buflen);
+}
+
+static _Bool
+exact_error_check(const ssize_t len, const size_t buflen)
+{
+ return (len < 0) || ((size_t)len != buflen);
+}
+
+/*
+ * Returns a dynamically allocated, '\0'-terminated buffer
+ * containing an appropriate pathname, or NULL if an error
+ * occurs. Caller must free the returned result with free(3).
+ */
+__attribute_malloc__
+static char *
+nsm_make_record_pathname(const char *directory, const char *hostname)
+{
+ const char *c;
+ size_t size;
+ char *path;
+ int len;
+
+ /*
+ * Block hostnames that contain characters that have
+ * meaning to the file system (like '/'), or that can
+ * be confusing on visual inspection (like ' ').
+ */
+ for (c = hostname; *c != '\0'; c++)
+ if (*c == '/' || isspace((int)*c) != 0) {
+ xlog(D_GENERAL, "Hostname contains invalid characters");
+ return NULL;
+ }
+
+ size = strlen(nsm_base_dirname) + strlen(directory) + strlen(hostname) + 3;
+ if (size > PATH_MAX) {
+ xlog(D_GENERAL, "Hostname results in pathname that is too long");
+ return NULL;
+ }
+
+ path = malloc(size);
+ if (path == NULL) {
+ xlog(D_GENERAL, "Failed to allocate memory for pathname");
+ return NULL;
+ }
+
+ len = snprintf(path, size, "%s/%s/%s",
+ nsm_base_dirname, directory, hostname);
+ if (error_check(len, size)) {
+ xlog(D_GENERAL, "Pathname did not fit in specified buffer");
+ free(path);
+ return NULL;
+ }
+
+ return path;
+}
+
+/*
+ * Returns a dynamically allocated, '\0'-terminated buffer
+ * containing an appropriate pathname, or NULL if an error
+ * occurs. Caller must free the returned result with free(3).
+ */
+__attribute_malloc__
+static char *
+nsm_make_pathname(const char *directory)
+{
+ size_t size;
+ char *path;
+ int len;
+
+ size = strlen(nsm_base_dirname) + strlen(directory) + 2;
+ if (size > PATH_MAX)
+ return NULL;
+
+ path = malloc(size);
+ if (path == NULL)
+ return NULL;
+
+ len = snprintf(path, size, "%s/%s", nsm_base_dirname, directory);
+ if (error_check(len, size)) {
+ free(path);
+ return NULL;
+ }
+
+ return path;
+}
+
+/**
+ * nsm_setup_pathnames - set up pathname
+ * @progname: C string containing name of program, for error messages
+ * @parentdir: C string containing pathname to on-disk state, or NULL
+ *
+ * This runs before logging is set up, so error messages are directed
+ * to stderr.
+ *
+ * Returns true and sets up our pathnames, if @parentdir was valid
+ * and usable; otherwise false is returned.
+ */
+_Bool
+nsm_setup_pathnames(const char *progname, const char *parentdir)
+{
+ static char buf[PATH_MAX];
+ struct stat st;
+ char *path;
+
+ /* First: test length of name and whether it exists */
+ if (lstat(parentdir, &st) == -1) {
+ (void)fprintf(stderr, "%s: Failed to stat %s: %s",
+ progname, parentdir, strerror(errno));
+ return false;
+ }
+
+ /* Ensure we have a clean directory pathname */
+ strncpy(buf, parentdir, sizeof(buf));
+ path = dirname(buf);
+ if (*path == '.') {
+ (void)fprintf(stderr, "%s: Unusable directory %s",
+ progname, parentdir);
+ return false;
+ }
+
+ xlog(D_CALL, "Using %s as the state directory", parentdir);
+ strncpy(nsm_base_dirname, parentdir, sizeof(nsm_base_dirname));
+ return true;
+}
+
+/**
+ * nsm_is_default_parentdir - check if parent directory is default
+ *
+ * Returns true if the active statd parent directory, set by
+ * nsm_change_pathname(), is the same as the built-in default
+ * parent directory; otherwise false is returned.
+ */
+_Bool
+nsm_is_default_parentdir(void)
+{
+ return strcmp(nsm_base_dirname, NSM_DEFAULT_STATEDIR) == 0;
+}
+
+/**
+ * nsm_drop_privileges - drop root privileges
+ * @pidfd: file descriptor of a pid file
+ *
+ * Returns true if successful, or false if some error occurred.
+ *
+ * Set our effective UID and GID to that of our on-disk database.
+ */
+_Bool
+nsm_drop_privileges(const int pidfd)
+{
+ struct stat st;
+
+ (void)umask(S_IRWXO);
+
+ /*
+ * XXX: If we can't stat dirname, or if dirname is owned by
+ * root, we should use "statduser" instead, which is set up
+ * by configure.ac. Nothing in nfs-utils seems to use
+ * "statduser," though.
+ */
+ if (lstat(nsm_base_dirname, &st) == -1) {
+ xlog(L_ERROR, "Failed to stat %s: %m", nsm_base_dirname);
+ return false;
+ }
+
+ if (st.st_uid == 0) {
+ xlog_warn("Running as root. "
+ "chown %s to choose different user", nsm_base_dirname);
+ return true;
+ }
+
+ if (chdir(nsm_base_dirname) == -1) {
+ xlog(L_ERROR, "Failed to change working directory to %s: %m",
+ nsm_base_dirname);
+ return false;
+ }
+
+ /*
+ * If the pidfile happens to reside on NFS, dropping privileges
+ * will probably cause us to lose access, even though we are
+ * holding it open. Chown it to prevent this.
+ */
+ if (pidfd >= 0)
+ if (fchown(pidfd, st.st_uid, st.st_gid) == -1)
+ xlog_warn("Failed to change owner of pidfile: %m");
+
+ if (setgroups(0, NULL) == -1) {
+ xlog(L_ERROR, "Failed to drop supplementary groups: %m");
+ return false;
+ }
+
+ /*
+ * ORDER
+ *
+ * setgid(2) first, as setuid(2) may remove privileges needed
+ * to set the group id.
+ */
+ if (setgid(st.st_gid) == -1 || setuid(st.st_uid) == -1) {
+ xlog(L_ERROR, "Failed to drop privileges: %m");
+ return false;
+ }
+
+ xlog(D_CALL, "Effective UID, GID: %u, %u", st.st_uid, st.st_gid);
+ return true;
+}
+
+/**
+ * nsm_get_state - retrieve on-disk NSM state number
+ *
+ * Returns an odd NSM state number read from disk, or an initial
+ * state number. Zero is returned if some error occurs.
+ */
+int
+nsm_get_state(_Bool update)
+{
+ int fd, state = 0;
+ ssize_t result;
+ char *path = NULL;
+ char *newpath = NULL;
+
+ path = nsm_make_pathname(NSM_STATE_FILE);
+ if (path == NULL) {
+ xlog(L_ERROR, "Failed to allocate path for " NSM_STATE_FILE);
+ goto out;
+ }
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ if (errno != ENOENT) {
+ xlog(L_ERROR, "Failed to open %s: %m", path);
+ goto out;
+ }
+
+ xlog(L_NOTICE, "Initializing NSM state");
+ state = 1;
+ update = true;
+ goto update;
+ }
+
+ result = read(fd, &state, sizeof(state));
+ if (exact_error_check(result, sizeof(state))) {
+ xlog_warn("Failed to read %s: %m", path);
+
+ xlog(L_NOTICE, "Initializing NSM state");
+ state = 1;
+ update = true;
+ goto update;
+ }
+
+ if ((state & 1) == 0)
+ state++;
+
+update:
+ (void)close(fd);
+
+ if (update) {
+ state += 2;
+
+ newpath = nsm_make_pathname(NSM_STATE_FILE ".new");
+ if (newpath == NULL) {
+ xlog(L_ERROR,
+ "Failed to create path for " NSM_STATE_FILE ".new");
+ state = 0;
+ goto out;
+ }
+
+ fd = open(newpath, O_CREAT | O_SYNC | O_WRONLY, 0644);
+ if (fd == -1) {
+ xlog(L_ERROR, "Failed to create %s: %m", newpath);
+ state = 0;
+ goto out;
+ }
+
+ result = write(fd, &state, sizeof(state));
+ if (exact_error_check(result, sizeof(state))) {
+ xlog(L_ERROR, "Failed to write %s: %m", newpath);
+ (void)close(fd);
+ (void)unlink(newpath);
+ state = 0;
+ goto out;
+ }
+
+ if (close(fd) == -1) {
+ xlog(L_ERROR, "Failed to close %s: %m", newpath);
+ (void)unlink(newpath);
+ state = 0;
+ goto out;
+ }
+
+ if (rename(newpath, path) == -1) {
+ xlog(L_ERROR, "Failed to rename %s -> %s: %m",
+ newpath, path);
+ (void)unlink(newpath);
+ state = 0;
+ goto out;
+ }
+
+ /* Ostensibly, a sync(2) is not needed here because
+ * open(O_CREAT), write(O_SYNC), and rename(2) are
+ * already synchronous with persistent storage, for
+ * any file system we care about. */
+ }
+
+out:
+ free(newpath);
+ free(path);
+ return state;
+}
+
+/**
+ * nsm_update_kernel_state - attempt to post new NSM state to kernel
+ * @state: NSM state number
+ *
+ */
+void
+nsm_update_kernel_state(const int state)
+{
+ ssize_t result;
+ char buf[20];
+ int fd, len;
+
+ fd = open(NSM_KERNEL_STATE_FILE, O_WRONLY);
+ if (fd == -1) {
+ xlog(D_GENERAL, "Failed to open " NSM_KERNEL_STATE_FILE ": %m");
+ return;
+ }
+
+ len = snprintf(buf, sizeof(buf), "%d", state);
+ if (error_check(len, sizeof(buf))) {
+ xlog_warn("Failed to form NSM state number string");
+ return;
+ }
+
+ result = write(fd, buf, strlen(buf));
+ if (exact_error_check(result, strlen(buf)))
+ xlog_warn("Failed to write NSM state number: %m");
+
+ if (close(fd) == -1)
+ xlog(L_ERROR, "Failed to close NSM state file "
+ NSM_KERNEL_STATE_FILE ": %m");
+}
+
+/**
+ * nsm_retire_monitored_hosts - back up all hosts from "sm/" to "sm.bak/"
+ *
+ * Returns the count of host records that were moved.
+ *
+ * Note that if any error occurs during this process, some monitor
+ * records may be left in the "sm" directory.
+ */
+unsigned int
+nsm_retire_monitored_hosts(void)
+{
+ unsigned int count = 0;
+ struct dirent *de;
+ char *path;
+ DIR *dir;
+
+ path = nsm_make_pathname(NSM_MONITOR_DIR);
+ if (path == NULL) {
+ xlog(L_ERROR, "Failed to allocate path for " NSM_MONITOR_DIR);
+ return count;
+ }
+
+ dir = opendir(path);
+ free(path);
+ if (dir == NULL) {
+ xlog_warn("Failed to open " NSM_MONITOR_DIR ": %m");
+ return count;
+ }
+
+ while ((de = readdir(dir)) != NULL) {
+ char *src, *dst;
+
+ if (de->d_type != (unsigned char)DT_REG)
+ continue;
+ if (de->d_name[0] == '.')
+ continue;
+
+ src = nsm_make_record_pathname(NSM_MONITOR_DIR, de->d_name);
+ if (src == NULL) {
+ xlog_warn("Bad monitor file name, skipping");
+ continue;
+ }
+
+ dst = nsm_make_record_pathname(NSM_NOTIFY_DIR, de->d_name);
+ if (dst == NULL) {
+ free(src);
+ xlog_warn("Bad notify file name, skipping");
+ continue;
+ }
+
+ if (rename(src, dst) == -1)
+ xlog_warn("Failed to rename %s -> %s: %m",
+ src, dst);
+ else {
+ xlog(D_GENERAL, "Retired record for mon_name %s",
+ de->d_name);
+ count++;
+ }
+
+ free(dst);
+ free(src);
+ }
+
+ (void)closedir(dir);
+ return count;
+}
+
+/*
+ * nsm_priv_to_hex - convert a NSM private cookie to a hex string.
+ *
+ * @priv: buffer holding the binary NSM private cookie
+ * @buf: output buffer for NULL terminated hex string
+ * @buflen: size of output buffer
+ *
+ * Returns the length of the resulting string or 0 on error
+ */
+size_t
+nsm_priv_to_hex(const char *priv, char *buf, const size_t buflen)
+{
+ int i, len;
+ size_t remaining = buflen;
+
+ for (i = 0; i < SM_PRIV_SIZE; i++) {
+ len = snprintf(buf, remaining, "%02x",
+ (unsigned int)(0xff & priv[i]));
+ if (error_check(len, remaining))
+ return 0;
+ buf += len;
+ remaining -= (size_t)len;
+ }
+
+ return buflen - remaining;
+}
+
+/*
+ * Returns the length in bytes of the created record.
+ */
+__attribute_noinline__
+static size_t
+nsm_create_monitor_record(char *buf, const size_t buflen,
+ const struct sockaddr *sap, const struct mon *m)
+{
+ const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
+ size_t hexlen, remaining = buflen;
+ int len;
+
+ len = snprintf(buf, remaining, "%08x %08x %08x %08x ",
+ (unsigned int)sin->sin_addr.s_addr,
+ (unsigned int)m->mon_id.my_id.my_prog,
+ (unsigned int)m->mon_id.my_id.my_vers,
+ (unsigned int)m->mon_id.my_id.my_proc);
+ if (error_check(len, remaining))
+ return 0;
+ buf += len;
+ remaining -= (size_t)len;
+
+ hexlen = nsm_priv_to_hex(m->priv, buf, remaining);
+ if (hexlen == 0)
+ return 0;
+ buf += hexlen;
+ remaining -= hexlen;
+
+ len = snprintf(buf, remaining, " %s %s\n",
+ m->mon_id.mon_name, m->mon_id.my_id.my_name);
+ if (error_check(len, remaining))
+ return 0;
+ remaining -= (size_t)len;
+
+ return buflen - remaining;
+}
+
+/**
+ * nsm_insert_monitored_host - write callback data for one host to disk
+ * @hostname: C string containing a hostname
+ * @sap: sockaddr containing NLM callback address
+ * @mon: SM_MON arguments to save
+ *
+ * Returns true if successful, otherwise false if some error occurs.
+ */
+_Bool
+nsm_insert_monitored_host(const char *hostname, const struct sockaddr *sap,
+ const struct mon *m)
+{
+ static char buf[LINELEN + 1 + SM_MAXSTRLEN + 2];
+ char *path;
+ _Bool result = false;
+ ssize_t len;
+ size_t size;
+ int fd;
+
+ path = nsm_make_record_pathname(NSM_MONITOR_DIR, hostname);
+ if (path == NULL) {
+ xlog(L_ERROR, "Failed to insert: bad monitor hostname '%s'",
+ hostname);
+ return false;
+ }
+
+ size = nsm_create_monitor_record(buf, sizeof(buf), sap, m);
+ if (size == 0) {
+ xlog(L_ERROR, "Failed to insert: record too long");
+ goto out;
+ }
+
+ fd = open(path, O_WRONLY | O_CREAT | O_SYNC, S_IRUSR | S_IWUSR);
+ if (fd == -1) {
+ xlog(L_ERROR, "Failed to insert: creating %s: %m", path);
+ goto out;
+ }
+ result = true;
+
+ len = write(fd, buf, size);
+ if (exact_error_check(len, size)) {
+ xlog_warn("Failed to insert: writing %s: %m", path);
+ (void)unlink(path);
+ result = false;
+ }
+
+ if (close(fd) == -1) {
+ xlog(L_ERROR, "Failed to insert: closing %s: %m", path);
+ (void)unlink(path);
+ result = false;
+ }
+
+out:
+ free(path);
+ return result;
+}
+
+__attribute_noinline__
+static _Bool
+nsm_parse_line(char *line, struct sockaddr_in *sin, struct mon *m)
+{
+ unsigned int i, tmp;
+ int count;
+ char *c;
+
+ c = strchr(line, '\n');
+ if (c != NULL)
+ *c = '\0';
+
+ count = sscanf(line, "%8x %8x %8x %8x ",
+ (unsigned int *)&sin->sin_addr.s_addr,
+ (unsigned int *)&m->mon_id.my_id.my_prog,
+ (unsigned int *)&m->mon_id.my_id.my_vers,
+ (unsigned int *)&m->mon_id.my_id.my_proc);
+ if (count != 4)
+ return false;
+
+ c = line + RPCARGSLEN;
+ for (i = 0; i < SM_PRIV_SIZE; i++) {
+ if (sscanf(c, "%2x", &tmp) != 1)
+ return false;
+ m->priv[i] = (char)tmp;
+ c += 2;
+ }
+
+ c++;
+ m->mon_id.mon_name = c;
+ while (*c != '\0' && *c != ' ')
+ c++;
+ if (*c != '\0')
+ *c++ = '\0';
+ while (*c == ' ')
+ c++;
+ m->mon_id.my_id.my_name = c;
+
+ return true;
+}
+
+/*
+ * Stuff a 'struct mon' with callback data, and call @func.
+ *
+ * Returns the count of in-core records created.
+ */
+static unsigned int
+nsm_read_line(const char *hostname, const time_t timestamp, char *line,
+ nsm_populate_t func)
+{
+ struct sockaddr_in sin = {
+ .sin_family = AF_INET,
+ };
+ struct mon m;
+
+ if (!nsm_parse_line(line, &sin, &m))
+ return 0;
+
+ return func(hostname, (struct sockaddr *)(char *)&sin, &m, timestamp);
+}
+
+/*
+ * Given a filename, reads data from a file under NSM_MONITOR_DIR
+ * and invokes @func so caller can populate their in-core
+ * database with this data.
+ */
+static unsigned int
+nsm_load_host(const char *directory, const char *filename, nsm_populate_t func)
+{
+ char buf[LINELEN + 1 + SM_MAXSTRLEN + 2];
+ unsigned int result = 0;
+ struct stat stb;
+ char *path;
+ FILE *f;
+
+ path = nsm_make_record_pathname(directory, filename);
+ if (path == NULL)
+ goto out_err;
+
+ if (stat(path, &stb) == -1) {
+ xlog(L_ERROR, "Failed to stat %s: %m", path);
+ goto out_freepath;
+ }
+
+ f = fopen(path, "r");
+ if (f == NULL) {
+ xlog(L_ERROR, "Failed to open %s: %m", path);
+ goto out_freepath;
+ }
+
+ while (fgets(buf, (int)sizeof(buf), f) != NULL) {
+ buf[sizeof(buf) - 1] = '\0';
+ result += nsm_read_line(filename, stb.st_mtime, buf, func);
+ }
+ if (result == 0)
+ xlog(L_ERROR, "Failed to read monitor data from %s", path);
+
+ (void)fclose(f);
+
+out_freepath:
+ free(path);
+out_err:
+ return result;
+}
+
+static unsigned int
+nsm_load_dir(const char *directory, nsm_populate_t func)
+{
+ unsigned int count = 0;
+ struct dirent *de;
+ char *path;
+ DIR *dir;
+
+ path = nsm_make_pathname(directory);
+ if (path == NULL) {
+ xlog(L_ERROR, "Failed to allocate path for directory %s",
+ directory);
+ return 0;
+ }
+
+ dir = opendir(path);
+ free(path);
+ if (dir == NULL) {
+ xlog(L_ERROR, "Failed to open directory %s: %m",
+ directory);
+ return 0;
+ }
+
+ while ((de = readdir(dir)) != NULL) {
+ if (de->d_type != (unsigned char)DT_REG)
+ continue;
+ if (de->d_name[0] == '.')
+ continue;
+
+ count += nsm_load_host(directory, de->d_name, func);
+ }
+
+ (void)closedir(dir);
+ return count;
+}
+
+/**
+ * nsm_load_monitor_list - load list of hosts to monitor
+ * @func: callback function to create entry for one host
+ *
+ * Returns the count of hosts that were found in the directory.
+ */
+unsigned int
+nsm_load_monitor_list(nsm_populate_t func)
+{
+ return nsm_load_dir(NSM_MONITOR_DIR, func);
+}
+
+/**
+ * nsm_load_notify_list - load list of hosts to notify
+ * @func: callback function to create entry for one host
+ *
+ * Returns the count of hosts that were found in the directory.
+ */
+unsigned int
+nsm_load_notify_list(nsm_populate_t func)
+{
+ return nsm_load_dir(NSM_NOTIFY_DIR, func);
+}
+
+static void
+nsm_delete_host(const char *directory, const char *hostname)
+{
+ char *path;
+
+ path = nsm_make_record_pathname(directory, hostname);
+ if (path == NULL) {
+ xlog(L_ERROR, "Bad filename, not deleting");
+ return;
+ }
+
+ if (unlink(path) == -1)
+ xlog(L_ERROR, "Failed to unlink %s: %m", path);
+
+ free(path);
+}
+
+/**
+ * nsm_delete_monitored_host - delete on-disk record for monitored host
+ * @hostname: '\0'-terminated C string containing hostname of record to delete
+ *
+ */
+void
+nsm_delete_monitored_host(const char *hostname)
+{
+ nsm_delete_host(NSM_MONITOR_DIR, hostname);
+}
+
+/**
+ * nsm_delete_notified_host - delete on-disk host record after notification
+ * @hostname: '\0'-terminated C string containing hostname of record to delete
+ *
+ */
+void
+nsm_delete_notified_host(const char *hostname)
+{
+ nsm_delete_host(NSM_NOTIFY_DIR, hostname);
+}
diff -up nfs-utils-1.2.1/support/nsm/Makefile.am.orig nfs-utils-1.2.1/support/nsm/Makefile.am
--- nfs-utils-1.2.1/support/nsm/Makefile.am.orig 2010-01-14 03:53:55.442869278 -0500
+++ nfs-utils-1.2.1/support/nsm/Makefile.am 2010-01-14 03:53:55.442869278 -0500
@@ -0,0 +1,45 @@
+## Process this file with automake to produce Makefile.in
+
+GENFILES_CLNT = sm_inter_clnt.c
+GENFILES_SVC = sm_inter_svc.c
+GENFILES_XDR = sm_inter_xdr.c
+GENFILES_H = sm_inter.h
+
+GENFILES = $(GENFILES_CLNT) $(GENFILES_SVC) $(GENFILES_XDR) $(GENFILES_H)
+
+EXTRA_DIST = sm_inter.x
+
+noinst_LIBRARIES = libnsm.a
+libnsm_a_SOURCES = $(GENFILES) file.c
+
+BUILT_SOURCES = $(GENFILES)
+
+if CONFIG_RPCGEN
+RPCGEN = $(top_builddir)/tools/rpcgen/rpcgen
+$(RPCGEN):
+ make -C ../../tools/rpcgen all
+else
+RPCGEN = @RPCGEN_PATH@
+endif
+
+$(GENFILES_CLNT): %_clnt.c: %.x $(RPCGEN)
+ test -f $@ && rm -rf $@ || true
+ $(RPCGEN) -l -o $@ $<
+
+$(GENFILES_SVC): %_svc.c: %.x $(RPCGEN)
+ test -f $@ && rm -rf $@ || true
+ $(RPCGEN) -m -o $@ $<
+
+$(GENFILES_XDR): %_xdr.c: %.x $(RPCGEN)
+ test -f $@ && rm -rf $@ || true
+ $(RPCGEN) -c -o $@ $<
+
+$(GENFILES_H): %.h: %.x $(RPCGEN)
+ test -f $@ && rm -rf $@ || true
+ $(RPCGEN) -h -o $@ $<
+ rm -f $(top_builddir)/support/include/sm_inter.h
+ $(LN_S) ../nsm/sm_inter.h $(top_builddir)/support/include/sm_inter.h
+
+MAINTAINERCLEANFILES = Makefile.in
+
+CLEANFILES = $(GENFILES) $(top_builddir)/support/include/sm_inter.h
diff -up nfs-utils-1.2.1/support/nsm/sm_inter.x.orig nfs-utils-1.2.1/support/nsm/sm_inter.x
--- nfs-utils-1.2.1/support/nsm/sm_inter.x.orig 2010-01-14 03:53:55.444899011 -0500
+++ nfs-utils-1.2.1/support/nsm/sm_inter.x 2010-01-14 03:53:55.444899011 -0500
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 1986 Sun Microsystems, Inc.
+ * Modified by Jeffrey A. Uphoff, 1995, 1997-1999.
+ * Modified by Olaf Kirch, 1996.
+ * Modified by H.J. Lu, 1998.
+ *
+ * NSM for Linux.
+ */
+
+/*
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Status monitor protocol specification
+ */
+
+#ifdef RPC_CLNT
+%#include <string.h>
+#endif
+
+program SM_PROG {
+ version SM_VERS {
+ /* res_stat = stat_succ if status monitor agrees to monitor */
+ /* res_stat = stat_fail if status monitor cannot monitor */
+ /* if res_stat == stat_succ, state = state number of site sm_name */
+ struct sm_stat_res SM_STAT(struct sm_name) = 1;
+
+ /* res_stat = stat_succ if status monitor agrees to monitor */
+ /* res_stat = stat_fail if status monitor cannot monitor */
+ /* stat consists of state number of local site */
+ struct sm_stat_res SM_MON(struct mon) = 2;
+
+ /* stat consists of state number of local site */
+ struct sm_stat SM_UNMON(struct mon_id) = 3;
+
+ /* stat consists of state number of local site */
+ struct sm_stat SM_UNMON_ALL(struct my_id) = 4;
+
+ void SM_SIMU_CRASH(void) = 5;
+
+ void SM_NOTIFY(struct stat_chge) = 6;
+
+ } = 1;
+} = 100024;
+
+const SM_MAXSTRLEN = 1024;
+const SM_PRIV_SIZE = 16;
+
+struct sm_name {
+ string mon_name<SM_MAXSTRLEN>;
+};
+
+struct my_id {
+ string my_name<SM_MAXSTRLEN>; /* name of the site iniates the monitoring request*/
+ int my_prog; /* rpc program # of the requesting process */
+ int my_vers; /* rpc version # of the requesting process */
+ int my_proc; /* rpc procedure # of the requesting process */
+};
+
+struct mon_id {
+ string mon_name<SM_MAXSTRLEN>; /* name of the site to be monitored */
+ struct my_id my_id;
+};
+
+
+struct mon {
+ struct mon_id mon_id;
+ opaque priv[SM_PRIV_SIZE]; /* private information to store at monitor for requesting process */
+};
+
+struct stat_chge {
+ string mon_name<SM_MAXSTRLEN>; /* name of the site that had the state change */
+ int state;
+};
+
+/*
+ * state # of status monitor monitonically increases each time
+ * status of the site changes:
+ * an even number (>= 0) indicates the site is down and
+ * an odd number (> 0) indicates the site is up;
+ */
+struct sm_stat {
+ int state; /* state # of status monitor */
+};
+
+enum res {
+ stat_succ = 0, /* status monitor agrees to monitor */
+ stat_fail = 1 /* status monitor cannot monitor */
+};
+
+struct sm_stat_res {
+ res res_stat;
+ int state;
+};
+
+/*
+ * structure of the status message sent back by the status monitor
+ * when monitor site status changes
+ */
+struct status {
+ string mon_name<SM_MAXSTRLEN>;
+ int state;
+ opaque priv[SM_PRIV_SIZE]; /* stored private information */
+};
+
+%#define SM_INTER_X
diff -up nfs-utils-1.2.1/tests/Makefile.am.orig nfs-utils-1.2.1/tests/Makefile.am
--- nfs-utils-1.2.1/tests/Makefile.am.orig 2010-01-14 03:53:55.444899011 -0500
+++ nfs-utils-1.2.1/tests/Makefile.am 2010-01-14 03:53:55.444899011 -0500
@@ -0,0 +1,13 @@
+## Process this file with automake to produce Makefile.in
+
+check_PROGRAMS = statdb_dump
+statdb_dump_SOURCES = statdb_dump.c
+
+statdb_dump_LDADD = ../support/nfs/libnfs.a \
+ ../support/nsm/libnsm.a $(LIBCAP)
+
+SUBDIRS = nsm_client
+
+MAINTAINERCLEANFILES = Makefile.in
+
+TESTS = t0001-statd-basic-mon-unmon.sh
diff -up nfs-utils-1.2.1/tests/nsm_client/Makefile.am.orig nfs-utils-1.2.1/tests/nsm_client/Makefile.am
--- nfs-utils-1.2.1/tests/nsm_client/Makefile.am.orig 2010-01-14 03:53:55.445919616 -0500
+++ nfs-utils-1.2.1/tests/nsm_client/Makefile.am 2010-01-14 03:53:55.445919616 -0500
@@ -0,0 +1,45 @@
+## Process this file with automake to produce Makefile.in
+
+GENFILES_CLNT = nlm_sm_inter_clnt.c
+GENFILES_SVC = nlm_sm_inter_svc.c
+GENFILES_XDR = nlm_sm_inter_xdr.c
+GENFILES_H = nlm_sm_inter.h
+
+GENFILES = $(GENFILES_CLNT) $(GENFILES_SVC) $(GENFILES_XDR) $(GENFILES_H)
+
+
+check_PROGRAMS = nsm_client
+nsm_client_SOURCES = $(GENFILES) nsm_client.c
+
+BUILT_SOURCES = $(GENFILES)
+nsm_client_LDADD = ../../support/nfs/libnfs.a \
+ ../../support/nsm/libnsm.a $(LIBCAP)
+
+if CONFIG_RPCGEN
+RPCGEN = $(top_builddir)/tools/rpcgen/rpcgen
+$(RPCGEN):
+ make -C ../../tools/rpcgen all
+else
+RPCGEN = @RPCGEN_PATH@
+endif
+
+$(GENFILES_CLNT): %_clnt.c: %.x $(RPCGEN)
+ test -f $@ && rm -rf $@ || true
+ $(RPCGEN) -l -o $@ $<
+
+$(GENFILES_SVC): %_svc.c: %.x $(RPCGEN)
+ test -f $@ && rm -rf $@ || true
+ $(RPCGEN) -m -o $@ $<
+
+$(GENFILES_XDR): %_xdr.c: %.x $(RPCGEN)
+ test -f $@ && rm -rf $@ || true
+ $(RPCGEN) -c -o $@ $<
+
+$(GENFILES_H): %.h: %.x $(RPCGEN)
+ test -f $@ && rm -rf $@ || true
+ $(RPCGEN) -h -o $@ $<
+
+MAINTAINERCLEANFILES = Makefile.in
+
+CLEANFILES = $(GENFILES)
+
diff -up nfs-utils-1.2.1/tests/nsm_client/nlm_sm_inter.x.orig nfs-utils-1.2.1/tests/nsm_client/nlm_sm_inter.x
--- nfs-utils-1.2.1/tests/nsm_client/nlm_sm_inter.x.orig 2010-01-14 03:53:55.446910417 -0500
+++ nfs-utils-1.2.1/tests/nsm_client/nlm_sm_inter.x 2010-01-14 03:53:55.446910417 -0500
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 1995, 1997-1999 Jeffrey A. Uphoff
+ * Modified by Olaf Kirch, 1996.
+ * Modified by H.J. Lu, 1998.
+ * Modified by Jeff Layton, 2010.
+ *
+ * NLM similator for Linux
+ */
+
+#ifdef RPC_CLNT
+%#include <string.h>
+#endif
+
+/*
+ * statd rejects monitor registrations for any non-lockd services, so pretend
+ * to be lockd when testing. Furthermore, the only call we care about from
+ * statd is #16, which is the downcall to notify the kernel of a host's status
+ * change.
+ */
+program NLM_SM_PROG {
+ /* version 3 of the NLM protocol */
+ version NLM_SM_VERS3 {
+ void NLM_SM_NOTIFY(struct nlm_sm_notify) = 16;
+ } = 3;
+
+ /* version 2 of NLM protocol */
+ version NLM_SM_VERS4 {
+ void NLM_SM_NOTIFY(struct nlm_sm_notify) = 16;
+ } = 4;
+} = 100021;
+
+const SM_MAXSTRLEN = 1024;
+const SM_PRIV_SIZE = 16;
+
+/*
+ * structure of the status message sent back by the status monitor
+ * when monitor site status changes
+ */
+struct nlm_sm_notify {
+ string mon_name<SM_MAXSTRLEN>;
+ int state;
+ opaque priv[SM_PRIV_SIZE]; /* stored private information */
+};
diff -up nfs-utils-1.2.1/tests/nsm_client/nsm_client.c.orig nfs-utils-1.2.1/tests/nsm_client/nsm_client.c
--- nfs-utils-1.2.1/tests/nsm_client/nsm_client.c.orig 2010-01-14 03:53:55.447919112 -0500
+++ nfs-utils-1.2.1/tests/nsm_client/nsm_client.c 2010-01-14 03:53:55.447919112 -0500
@@ -0,0 +1,465 @@
+/*
+ * nsm_client.c -- synthetic client and lockd simulator for testing statd
+ *
+ * Copyright (C) 2010 Red Hat, Jeff Layton <jlayton@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Very loosely based on "simulator.c" in the statd directory. Original
+ * copyright for that program follows:
+ *
+ * Copyright (C) 1995-1997, 1999 Jeffrey A. Uphoff
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <getopt.h>
+#include <netdb.h>
+#include <signal.h>
+#include <string.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include <rpcmisc.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "nfslib.h"
+#include "nfsrpc.h"
+#include "nsm.h"
+#include "sm_inter.h"
+#include "nlm_sm_inter.h"
+#include "sockaddr.h"
+#include "xcommon.h"
+
+static void daemon_simulator(void);
+static void sim_killer(int sig);
+static int nsm_client_crash(char *);
+static int nsm_client_mon(char *, char *, char *, char *, int, int);
+static int nsm_client_stat(char *, char *);
+static int nsm_client_notify(char *, char *, char *);
+static int nsm_client_unmon(char *, char *, char *, int, int);
+static int nsm_client_unmon_all(char *, char *, int, int);
+
+extern void nlm_sm_prog_4(struct svc_req *rqstp, register SVCXPRT *transp);
+extern void svc_exit(void);
+
+/*
+ * default to 15 retransmit interval, which seems to be the default for
+ * UDP clients w/ legacy glibc RPC
+ */
+static struct timeval retrans_interval =
+{
+ .tv_sec = 15,
+};
+
+static struct option longopts[] =
+{
+ { "help", 0, 0, 'h' },
+ { "host", 0, 0, 'H' },
+ { "name", 1, 0, 'n' },
+ { "program", 1, 0, 'P' },
+ { "version", 1, 0, 'v' },
+ { NULL, 0, 0, 0 },
+};
+
+static int
+usage(char *program)
+{
+ printf("Usage:\n");
+ printf("%s [options] <command> [arg]...\n", program);
+ printf("where command is one of these with the specified args:\n");
+ printf("crash\t\t\t\ttell host to simulate crash\n");
+ printf("daemon\t\t\t\t\tstart up lockd daemon simulator\n");
+ printf("notify <mon_name> <state>\tsend a reboot notification to host\n");
+ printf("stat <mon_name>\t\t\tget status of <mon_name> on host\n");
+ printf("unmon_all\t\t\ttell host to unmon everything\n");
+ printf("unmon <mon_name>\t\t\ttell host to unmon <mon_name>\n");
+ printf("mon <mon_name> <cookie>\t\ttell host to monitor <mon_name> with private <cookie>\n");
+ return 1;
+}
+
+static int
+hex2bin(char *dst, size_t dstlen, char *src)
+{
+ int i;
+ unsigned int tmp;
+
+ for (i = 0; *src && i < dstlen; i++) {
+ if (sscanf(src, "%2x", &tmp) != 1)
+ return 0;
+ dst[i] = tmp;
+ src++;
+ if (!*src)
+ break;
+ src++;
+ }
+
+ return 1;
+}
+
+static void
+bin2hex(char *dst, char *src, size_t srclen)
+{
+ int i;
+
+ for (i = 0; i < srclen; i++)
+ dst += sprintf(dst, "%02x", 0xff & src[i]);
+}
+
+int
+main(int argc, char **argv)
+{
+ int arg, err = 0;
+ int remaining_args;
+ char my_name[NI_MAXHOST], host[NI_MAXHOST];
+ char cookie[SM_PRIV_SIZE];
+ int my_prog = NLM_SM_PROG;
+ int my_vers = NLM_SM_VERS4;
+
+ my_name[0] = '\0';
+ host[0] = '\0';
+
+ while ((arg = getopt_long(argc, argv, "hHn:P:v:", longopts,
+ NULL)) != EOF) {
+ switch (arg) {
+ case 'H':
+ strncpy(host, optarg, sizeof(host));
+ case 'n':
+ strncpy(my_name, optarg, sizeof(my_name));
+ case 'P':
+ my_prog = atoi(optarg);
+ case 'v':
+ my_vers = atoi(optarg);
+ }
+ }
+
+ remaining_args = argc - optind;
+ if (remaining_args <= 0)
+ usage(argv[0]);
+
+ if (!my_name[0])
+ gethostname(my_name, sizeof(my_name));
+ if (!host[0])
+ strncpy(host, "127.0.0.1", sizeof(host));
+
+ if (!strcasecmp(argv[optind], "daemon")) {
+ daemon_simulator();
+ } else if (!strcasecmp(argv[optind], "crash")) {
+ err = nsm_client_crash(host);
+ } else if (!strcasecmp(argv[optind], "stat")) {
+ if (remaining_args < 2)
+ usage(argv[0]);
+ err = nsm_client_stat(host, argv[optind + 2]);
+ } else if (!strcasecmp(argv[optind], "unmon_all")) {
+ err = nsm_client_unmon_all(host, my_name, my_prog, my_vers);
+ } else if (!strcasecmp(argv[optind], "unmon")) {
+ if (remaining_args < 2)
+ usage(argv[0]);
+ err = nsm_client_unmon(host, argv[optind + 1], my_name, my_prog,
+ my_vers);
+ } else if (!strcasecmp(argv[optind], "notify")) {
+ if (remaining_args < 2)
+ usage(argv[0]);
+ err = nsm_client_notify(host, argv[optind + 1],
+ argv[optind + 2]);
+ } else if (!strcasecmp(argv[optind], "mon")) {
+ if (remaining_args < 2)
+ usage(argv[0]);
+
+ memset(cookie, '\0', SM_PRIV_SIZE);
+ if (!hex2bin(cookie, sizeof(cookie), argv[optind + 2])) {
+ fprintf(stderr, "SYS:%d\n", EINVAL);
+ printf("Unable to convert hex cookie %s to binary.\n",
+ argv[optind + 2]);
+ return 1;
+ }
+
+ err = nsm_client_mon(host, argv[optind + 1], cookie, my_name,
+ my_prog, my_vers);
+ } else {
+ err = usage(argv[0]);
+ }
+
+ return err;
+}
+
+static CLIENT *
+nsm_client_get_rpcclient(const char *node)
+{
+ unsigned short port;
+ struct addrinfo *ai;
+ struct addrinfo hints = { .ai_flags = AI_ADDRCONFIG };
+ int err;
+ CLIENT *client = NULL;
+
+#ifndef IPV6_ENABLED
+ hints.ai_family = AF_INET;
+#endif /* IPV6_ENABLED */
+
+ /* FIXME: allow support for providing port? */
+ err = getaddrinfo(node, NULL, &hints, &ai);
+ if (err) {
+ fprintf(stderr, "EAI:%d\n", err);
+ if (err == EAI_SYSTEM)
+ fprintf(stderr, "SYS:%d\n", errno);
+ printf("Unable to translate host to address: %s\n",
+ err == EAI_SYSTEM ? strerror(errno) :
+ gai_strerror(err));
+ return client;
+ }
+
+ /* FIXME: allow for TCP too? */
+ port = nfs_getport(ai->ai_addr, ai->ai_addrlen, SM_PROG,
+ SM_VERS, IPPROTO_UDP);
+ if (!port) {
+ fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
+ printf("Unable to determine port for service\n");
+ goto out;
+ }
+
+ nfs_set_port(ai->ai_addr, port);
+
+ client = nfs_get_rpcclient(ai->ai_addr, ai->ai_addrlen, IPPROTO_UDP,
+ SM_PROG, SM_VERS, &retrans_interval);
+ if (!client) {
+ fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
+ printf("RPC client creation failed\n");
+ }
+out:
+ freeaddrinfo(ai);
+ return client;
+}
+
+static int
+nsm_client_mon(char *calling, char *monitoring, char *cookie, char *my_name,
+ int my_prog, int my_vers)
+{
+ CLIENT *client;
+ sm_stat_res *result;
+ mon mon;
+ int err = 0;
+
+ printf("Calling %s (as %s) to monitor %s\n", calling, my_name,
+ monitoring);
+
+ if ((client = nsm_client_get_rpcclient(calling)) == NULL)
+ return 1;
+
+ memcpy(mon.priv, cookie, SM_PRIV_SIZE);
+ mon.mon_id.my_id.my_name = my_name;
+ mon.mon_id.my_id.my_prog = my_prog;
+ mon.mon_id.my_id.my_vers = my_vers;
+ mon.mon_id.my_id.my_proc = NLM_SM_NOTIFY;
+ mon.mon_id.mon_name = monitoring;
+
+ if (!(result = sm_mon_1(&mon, client))) {
+ fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
+ printf("%s\n", clnt_sperror(client, "sm_mon_1"));
+ err = 1;
+ goto mon_out;
+ }
+
+ printf("SM_MON request %s, state: %d\n",
+ result->res_stat == stat_succ ? "successful" : "failed",
+ result->state);
+
+ if (result->res_stat != stat_succ) {
+ fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
+ err = 1;
+ }
+
+mon_out:
+ clnt_destroy(client);
+ return err;
+}
+
+static int
+nsm_client_unmon(char *calling, char *unmonitoring, char *my_name, int my_prog,
+ int my_vers)
+{
+ CLIENT *client;
+ sm_stat *result;
+ mon_id mon_id;
+ int err = 0;
+
+ printf("Calling %s (as %s) to unmonitor %s\n", calling, my_name,
+ unmonitoring);
+
+ if ((client = nsm_client_get_rpcclient(calling)) == NULL)
+ return 1;
+
+ mon_id.my_id.my_name = my_name;
+ mon_id.my_id.my_prog = my_prog;
+ mon_id.my_id.my_vers = my_vers;
+ mon_id.my_id.my_proc = NLM_SM_NOTIFY;
+ mon_id.mon_name = unmonitoring;
+
+ if (!(result = sm_unmon_1(&mon_id, client))) {
+ fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
+ printf("%s\n", clnt_sperror(client, "sm_unmon_1"));
+ err = 1;
+ goto unmon_out;
+ }
+
+ printf("SM_UNMON state: %d\n", result->state);
+
+unmon_out:
+ clnt_destroy(client);
+ return err;
+}
+
+static int
+nsm_client_unmon_all(char *calling, char *my_name, int my_prog, int my_vers)
+{
+ CLIENT *client;
+ sm_stat *result;
+ my_id my_id;
+ int err = 0;
+
+ printf("Calling %s (as %s) to unmonitor all hosts\n", calling, my_name);
+
+ if ((client = nsm_client_get_rpcclient(calling)) == NULL) {
+ printf("RPC client creation failed\n");
+ return 1;
+ }
+
+ my_id.my_name = my_name;
+ my_id.my_prog = my_prog;
+ my_id.my_vers = my_vers;
+ my_id.my_proc = NLM_SM_NOTIFY;
+
+ if (!(result = sm_unmon_all_1(&my_id, client))) {
+ fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
+ printf("%s\n", clnt_sperror(client, "sm_unmon_all_1"));
+ err = 1;
+ goto unmon_all_out;
+ }
+
+ printf("SM_UNMON_ALL state: %d\n", result->state);
+
+unmon_all_out:
+ return err;
+}
+
+static int
+nsm_client_crash(char *host)
+{
+ CLIENT *client;
+
+ if ((client = nsm_client_get_rpcclient(host)) == NULL)
+ return 1;
+
+ if (!sm_simu_crash_1(NULL, client)) {
+ fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
+ printf("%s\n", clnt_sperror(client, "sm_simu_crash_1"));
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+nsm_client_stat(char *calling, char *monitoring)
+{
+ CLIENT *client;
+ sm_name checking;
+ sm_stat_res *result;
+
+ if ((client = nsm_client_get_rpcclient(calling)) == NULL)
+ return 1;
+
+ checking.mon_name = monitoring;
+
+ if (!(result = sm_stat_1(&checking, client))) {
+ fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
+ printf("%s\n", clnt_sperror(client, "sm_stat_1"));
+ return 1;
+ }
+
+ if (result->res_stat != stat_succ) {
+ fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
+ printf("stat_fail from %s for %s, state: %d\n", calling,
+ monitoring, result->state);
+ return 1;
+ }
+
+ printf("stat_succ from %s for %s, state: %d\n", calling,
+ monitoring, result->state);
+
+ return 0;
+}
+
+static int
+nsm_client_notify(char *calling, char *mon_name, char *statestr)
+{
+ CLIENT *client;
+
+ stat_chge stat_chge = { .mon_name = mon_name };
+
+ stat_chge.state = atoi(statestr);
+
+ if ((client = nsm_client_get_rpcclient(calling)) == NULL)
+ return 1;
+
+ if (!sm_notify_1(&stat_chge, client)) {
+ fprintf(stderr, "RPC:%d\n", rpc_createerr.cf_stat);
+ printf("%s\n", clnt_sperror(client, "sm_notify_1"));
+ return 1;
+ }
+
+ return 0;
+}
+
+static void sim_killer(int sig)
+{
+#ifdef HAVE_LIBTIRPC
+ (void) rpcb_unset(NLM_SM_PROG, NLM_SM_VERS4, NULL);
+#else
+ (void) pmap_unset(NLM_SM_PROG, NLM_SM_VERS4);
+#endif
+ exit(0);
+}
+
+static void daemon_simulator(void)
+{
+ signal(SIGHUP, sim_killer);
+ signal(SIGINT, sim_killer);
+ signal(SIGTERM, sim_killer);
+ /* FIXME: allow for different versions? */
+ nfs_svc_create("nlmsim", NLM_SM_PROG, NLM_SM_VERS4, nlm_sm_prog_4, 0);
+ svc_run();
+}
+
+void *nlm_sm_notify_4_svc(struct nlm_sm_notify *argp, struct svc_req *rqstp)
+{
+ static char *result;
+ char priv[SM_PRIV_SIZE * 2 + 1];
+
+ bin2hex(priv, argp->priv, SM_PRIV_SIZE);
+
+ printf("state=%d:mon_name=%s:private=%s\n", argp->state,
+ argp->mon_name, priv);
+ return (void *) &result;
+}
+
+void *nlm_sm_notify_3_svc(struct nlm_sm_notify *argp, struct svc_req *rqstp)
+{
+ return nlm_sm_notify_4_svc(argp, rqstp);
+}
diff -up nfs-utils-1.2.1/tests/nsm_client/README.orig nfs-utils-1.2.1/tests/nsm_client/README
--- nfs-utils-1.2.1/tests/nsm_client/README.orig 2010-01-14 03:53:55.445919616 -0500
+++ nfs-utils-1.2.1/tests/nsm_client/README 2010-01-14 03:53:55.445919616 -0500
@@ -0,0 +1,12 @@
+The nsm_client program is intended for testing statd. It has the ability
+to act as a synthetic NSM client for sending artificial NSM calls to any
+host you choose.
+
+It also has an NLM simulator that implements the call that statd uses to
+communicate with lockd. The daemon simulator will start itself up,
+register as an NLM service and listen for "downcalls" from statd. When
+it gets one, it will log a message.
+
+Note that lockd will need to be down when using the daemon simulator. It
+also does not implement the entire NLM protocol and is only really
+useful for testing statd's downcall.
diff -up nfs-utils-1.2.1/tests/statdb_dump.c.orig nfs-utils-1.2.1/tests/statdb_dump.c
--- nfs-utils-1.2.1/tests/statdb_dump.c.orig 2010-01-14 03:53:55.447919112 -0500
+++ nfs-utils-1.2.1/tests/statdb_dump.c 2010-01-14 03:53:55.447919112 -0500
@@ -0,0 +1,99 @@
+/*
+ * statdb_dump.c -- dump contents of statd's monitor DB
+ *
+ * Copyright (C) 2010 Red Hat, Jeff Layton <jlayton@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#include "nsm.h"
+#include "xlog.h"
+
+static char cookiebuf[(SM_PRIV_SIZE * 2) + 1];
+static char addrbuf[INET6_ADDRSTRLEN + 1];
+
+static unsigned int
+dump_host(const char *hostname, const struct sockaddr *sa, const struct mon *m,
+ const time_t timestamp)
+{
+ int ret;
+ const char *addr;
+ const struct sockaddr_in *sin;
+ const struct sockaddr_in6 *sin6;
+
+ ret = nsm_priv_to_hex(m->priv, cookiebuf, sizeof(cookiebuf));
+ if (!ret) {
+ xlog(L_ERROR, "Unable to convert cookie to hex string.\n");
+ return ret;
+ }
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ sin = (struct sockaddr_in *)(char *)sa;
+ addr = inet_ntop(sa->sa_family, &sin->sin_addr.s_addr, addrbuf,
+ (socklen_t)sizeof(addrbuf));
+ break;
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)(char *)sa;
+ addr = inet_ntop(sa->sa_family, &sin6->sin6_addr, addrbuf,
+ (socklen_t)sizeof(addrbuf));
+ break;
+ default:
+ xlog(L_ERROR, "Unrecognized address family: %hu\n",
+ sa->sa_family);
+ return 0;
+ }
+
+ if (addr == NULL) {
+ xlog(L_ERROR, "Unable to convert sockaddr to string: %s\n",
+ strerror(errno));
+ return 0;
+ }
+
+ /*
+ * Callers of this program should assume that in the future, extra
+ * fields may be added to the output. Anyone adding extra fields to
+ * the output should add them to the end of the line.
+ */
+ printf("%s %s %s %s %s %d %d %d\n",
+ hostname, addr, cookiebuf,
+ m->mon_id.mon_name,
+ m->mon_id.my_id.my_name,
+ m->mon_id.my_id.my_prog,
+ m->mon_id.my_id.my_vers,
+ m->mon_id.my_id.my_proc);
+
+ return 1;
+}
+
+int
+main(int argc, char **argv)
+{
+ xlog_syslog(0);
+ xlog_stderr(1);
+ xlog_open(argv[0]);
+
+ nsm_load_monitor_list(dump_host);
+ return 0;
+}
diff -up nfs-utils-1.2.1/tests/t0001-statd-basic-mon-unmon.sh.orig nfs-utils-1.2.1/tests/t0001-statd-basic-mon-unmon.sh
--- nfs-utils-1.2.1/tests/t0001-statd-basic-mon-unmon.sh.orig 2010-01-14 03:53:55.448909534 -0500
+++ nfs-utils-1.2.1/tests/t0001-statd-basic-mon-unmon.sh 2010-01-14 03:53:55.448909534 -0500
@@ -0,0 +1,58 @@
+#!/bin/bash
+#
+# statd_basic_mon_unmon -- test basic mon/unmon functionality with statd
+#
+# Copyright (C) 2010 Red Hat, Jeff Layton <jlayton@redhat.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+
+. ./test-lib.sh
+
+# This test needs root privileges
+check_root
+
+start_statd
+if [ $? -ne 0 ]; then
+ echo "FAIL: problem starting statd"
+ exit 1
+fi
+
+COOKIE=`echo $$ | md5sum | cut -d' ' -f1`
+MON_NAME=`hostname`
+
+nsm_client mon $MON_NAME $COOKIE
+if [ $? -ne 0 ]; then
+ echo "FAIL: mon failed"
+ kill_statd
+ exit 1
+fi
+
+statdb_dump | grep $MON_NAME | grep -q $COOKIE
+if [ $? -ne 0 ]; then
+ echo "FAIL: monitor DB doesn't seem to contain entry"
+ kill_statd
+ exit 1
+fi
+
+nsm_client unmon $MON_NAME
+if [ $? -ne 0 ]; then
+ echo "FAIL: unmon failed"
+ kill_statd
+ exit 1
+fi
+
+kill_statd
+
diff -up nfs-utils-1.2.1/tests/test-lib.sh.orig nfs-utils-1.2.1/tests/test-lib.sh
--- nfs-utils-1.2.1/tests/test-lib.sh.orig 2010-01-14 03:53:55.448909534 -0500
+++ nfs-utils-1.2.1/tests/test-lib.sh 2010-01-14 03:53:55.448909534 -0500
@@ -0,0 +1,60 @@
+#!/bin/bash
+#
+# test-lib.sh -- library of functions for nfs-utils tests
+#
+# Copyright (C) 2010 Red Hat, Jeff Layton <jlayton@redhat.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+
+# make sure $srcdir is set and sanity check it
+srcdir=${srcdir-.}
+if [ ! -d ${srcdir} ]; then
+ echo "***ERROR***: bad installation -- \$srcdir=${srcdir}"
+ exit 1
+fi
+
+export PATH=$PATH:${srcdir}:${srcdir}/nsm_client
+
+# Some tests require root privileges. Check for them and skip the test (exit 77)
+# if the caller doesn't have them.
+check_root() {
+ if [ $EUID -ne 0 ]; then
+ echo "*** Skipping this test as it requires root privs ***"
+ exit 77
+ fi
+}
+
+# is lockd registered as a service?
+lockd_registered() {
+ rpcinfo -p | grep -q nlockmgr
+ return $?
+}
+
+# start up statd
+start_statd() {
+ rpcinfo -u 127.0.0.1 status 1 &> /dev/null
+ if [ $? -eq 0 ]; then
+ echo "***ERROR***: statd is already running and should "
+ echo " be down when starting this test"
+ return 1
+ fi
+ $srcdir/../utils/statd/statd --no-notify
+}
+
+# shut down statd
+kill_statd() {
+ kill `cat /var/run/rpc.statd.pid`
+}
diff -up nfs-utils-1.2.1/utils/gssd/gssd.c.orig nfs-utils-1.2.1/utils/gssd/gssd.c
--- nfs-utils-1.2.1/utils/gssd/gssd.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/gssd/gssd.c 2010-01-14 03:53:55.449919561 -0500
@@ -56,7 +56,6 @@
#include "krb5_util.h"
char pipefs_dir[PATH_MAX] = GSSD_PIPEFS_DIR;
-char pipefs_nfsdir[PATH_MAX] = GSSD_PIPEFS_DIR;
char keytabfile[PATH_MAX] = GSSD_DEFAULT_KEYTAB_FILE;
char ccachedir[PATH_MAX] = GSSD_DEFAULT_CRED_DIR;
char *ccachesearch[GSSD_MAX_CCACHE_SEARCH + 1];
@@ -159,11 +158,6 @@ main(int argc, char *argv[])
if (preferred_realm == NULL)
gssd_k5_get_default_realm(&preferred_realm);
- snprintf(pipefs_nfsdir, sizeof(pipefs_nfsdir), "%s/%s",
- pipefs_dir, GSSD_SERVICE_NAME);
- if (pipefs_nfsdir[sizeof(pipefs_nfsdir)-1] != '\0')
- errx(1, "pipefs_nfsdir path name too long");
-
if ((progname = strrchr(argv[0], '/')))
progname++;
else
diff -up nfs-utils-1.2.1/utils/gssd/gssd.h.orig nfs-utils-1.2.1/utils/gssd/gssd.h
--- nfs-utils-1.2.1/utils/gssd/gssd.h.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/gssd/gssd.h 2010-01-14 03:53:55.449919561 -0500
@@ -60,7 +60,6 @@ enum {AUTHTYPE_KRB5, AUTHTYPE_SPKM3, AUT
extern char pipefs_dir[PATH_MAX];
-extern char pipefs_nfsdir[PATH_MAX];
extern char keytabfile[PATH_MAX];
extern char *ccachesearch[];
extern int use_memcache;
@@ -83,13 +82,24 @@ struct clnt_info {
int krb5_poll_index;
int spkm3_fd;
int spkm3_poll_index;
+ int gssd_fd;
+ int gssd_poll_index;
struct sockaddr_storage addr;
};
+TAILQ_HEAD(topdirs_list_head, topdirs_info) topdirs_list;
+
+struct topdirs_info {
+ TAILQ_ENTRY(topdirs_info) list;
+ char *dirname;
+ int fd;
+};
+
void init_client_list(void);
int update_client_list(void);
void handle_krb5_upcall(struct clnt_info *clp);
void handle_spkm3_upcall(struct clnt_info *clp);
+void handle_gssd_upcall(struct clnt_info *clp);
int gssd_acquire_cred(char *server_name);
void gssd_run(void);
diff -up nfs-utils-1.2.1/utils/gssd/gssd_main_loop.c.orig nfs-utils-1.2.1/utils/gssd/gssd_main_loop.c
--- nfs-utils-1.2.1/utils/gssd/gssd_main_loop.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/gssd/gssd_main_loop.c 2010-01-14 03:53:55.450909216 -0500
@@ -49,6 +49,7 @@
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
+#include <dirent.h>
#include "gssd.h"
#include "err_util.h"
@@ -73,6 +74,17 @@ scan_poll_results(int ret)
for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next)
{
+ i = clp->gssd_poll_index;
+ if (i >= 0 && pollarray[i].revents) {
+ if (pollarray[i].revents & POLLHUP)
+ dir_changed = 1;
+ if (pollarray[i].revents & POLLIN)
+ handle_gssd_upcall(clp);
+ pollarray[clp->gssd_poll_index].revents = 0;
+ ret--;
+ if (!ret)
+ break;
+ }
i = clp->krb5_poll_index;
if (i >= 0 && pollarray[i].revents) {
if (pollarray[i].revents & POLLHUP)
@@ -98,12 +110,85 @@ scan_poll_results(int ret)
}
};
+static int
+topdirs_add_entry(struct dirent *dent)
+{
+ struct topdirs_info *tdi;
+
+ tdi = calloc(sizeof(struct topdirs_info), 1);
+ if (tdi == NULL) {
+ printerr(0, "ERROR: Couldn't allocate struct topdirs_info\n");
+ return -1;
+ }
+ tdi->dirname = malloc(PATH_MAX);
+ if (tdi->dirname == NULL) {
+ printerr(0, "ERROR: Couldn't allocate directory name\n");
+ free(tdi);
+ return -1;
+ }
+ snprintf(tdi->dirname, PATH_MAX, "%s/%s", pipefs_dir, dent->d_name);
+ tdi->fd = open(tdi->dirname, O_RDONLY);
+ if (tdi->fd != -1) {
+ fcntl(tdi->fd, F_SETSIG, DNOTIFY_SIGNAL);
+ fcntl(tdi->fd, F_NOTIFY,
+ DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT);
+ }
+
+ TAILQ_INSERT_HEAD(&topdirs_list, tdi, list);
+ return 0;
+}
+
+static void
+topdirs_free_list(void)
+{
+ struct topdirs_info *tdi;
+
+ TAILQ_FOREACH(tdi, &topdirs_list, list) {
+ free(tdi->dirname);
+ if (tdi->fd != -1)
+ close(tdi->fd);
+ TAILQ_REMOVE(&topdirs_list, tdi, list);
+ free(tdi);
+ }
+}
+
+static int
+topdirs_init_list(void)
+{
+ DIR *pipedir;
+ struct dirent *dent;
+ int ret;
+
+ TAILQ_INIT(&topdirs_list);
+
+ pipedir = opendir(pipefs_dir);
+ if (pipedir == NULL) {
+ printerr(0, "ERROR: could not open rpc_pipefs directory '%s': "
+ "%s\n", pipefs_dir, strerror(errno));
+ return -1;
+ }
+ for (dent = readdir(pipedir); dent != NULL; dent = readdir(pipedir)) {
+ if (dent->d_type != DT_DIR ||
+ strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0) {
+ continue;
+ }
+ ret = topdirs_add_entry(dent);
+ if (ret)
+ goto out_err;
+ }
+ closedir(pipedir);
+ return 0;
+out_err:
+ topdirs_free_list();
+ return -1;
+}
+
void
gssd_run()
{
int ret;
struct sigaction dn_act;
- int fd;
sigset_t set;
/* Taken from linux/Documentation/dnotify.txt: */
@@ -117,13 +202,8 @@ gssd_run()
sigaddset(&set, DNOTIFY_SIGNAL);
sigprocmask(SIG_UNBLOCK, &set, NULL);
- if ((fd = open(pipefs_nfsdir, O_RDONLY)) == -1) {
- printerr(0, "ERROR: failed to open %s: %s\n",
- pipefs_nfsdir, strerror(errno));
- exit(1);
- }
- fcntl(fd, F_SETSIG, DNOTIFY_SIGNAL);
- fcntl(fd, F_NOTIFY, DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT);
+ if (topdirs_init_list() != 0)
+ return;
init_client_list();
@@ -132,8 +212,7 @@ gssd_run()
while (dir_changed) {
dir_changed = 0;
if (update_client_list()) {
- printerr(0, "ERROR: couldn't update "
- "client list\n");
+ /* Error msg is already printed */
exit(1);
}
}
@@ -151,6 +230,7 @@ gssd_run()
scan_poll_results(ret);
}
}
- close(fd);
+ topdirs_free_list();
+
return;
}
diff -up nfs-utils-1.2.1/utils/gssd/gssd_proc.c.orig nfs-utils-1.2.1/utils/gssd/gssd_proc.c
--- nfs-utils-1.2.1/utils/gssd/gssd_proc.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/gssd/gssd_proc.c 2010-01-14 03:53:55.451909067 -0500
@@ -73,6 +73,7 @@
#include "krb5_util.h"
#include "context.h"
#include "nfsrpc.h"
+#include "nfslib.h"
/*
* pollarray:
@@ -83,20 +84,22 @@
* linked list of struct clnt_info which associates a clntXXX directory
* with an index into pollarray[], and other basic data about that client.
*
- * Directory structure: created by the kernel nfs client
- * {pipefs_nfsdir}/clntXX : one per rpc_clnt struct in the kernel
- * {pipefs_nfsdir}/clntXX/krb5 : read uid for which kernel wants
+ * Directory structure: created by the kernel
+ * {rpc_pipefs}/{dir}/clntXX : one per rpc_clnt struct in the kernel
+ * {rpc_pipefs}/{dir}/clntXX/krb5 : read uid for which kernel wants
* a context, write the resulting context
- * {pipefs_nfsdir}/clntXX/info : stores info such as server name
+ * {rpc_pipefs}/{dir}/clntXX/info : stores info such as server name
+ * {rpc_pipefs}/{dir}/clntXX/gssd : pipe for all gss mechanisms using
+ * a text-based string of parameters
*
* Algorithm:
- * Poll all {pipefs_nfsdir}/clntXX/krb5 files. When ready, data read
- * is a uid; performs rpcsec_gss context initialization protocol to
+ * Poll all {rpc_pipefs}/{dir}/clntXX/YYYY files. When data is ready,
+ * read and process; performs rpcsec_gss context initialization protocol to
* get a cred for that user. Writes result to corresponding krb5 file
* in a form the kernel code will understand.
* In addition, we make sure we are notified whenever anything is
- * created or destroyed in {pipefs_nfsdir} or in an of the clntXX directories,
- * and rescan the whole {pipefs_nfsdir} when this happens.
+ * created or destroyed in {rpc_pipefs} or in any of the clntXX directories,
+ * and rescan the whole {rpc_pipefs} when this happens.
*/
struct pollfd * pollarray;
@@ -105,7 +108,7 @@ int pollsize; /* the size of pollaray (
/*
* convert a presentation address string to a sockaddr_storage struct. Returns
- * true on success and false on failure.
+ * true on success or false on failure.
*
* Note that we do not populate the sin6_scope_id field here for IPv6 addrs.
* gssd nececessarily relies on hostname resolution and DNS AAAA records
@@ -117,26 +120,43 @@ int pollsize; /* the size of pollaray (
* not really feasible at present.
*/
static int
-addrstr_to_sockaddr(struct sockaddr *sa, const char *addr, const int port)
+addrstr_to_sockaddr(struct sockaddr *sa, const char *node, const char *port)
{
- struct sockaddr_in *s4 = (struct sockaddr_in *) sa;
-#ifdef IPV6_SUPPORTED
- struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) sa;
-#endif /* IPV6_SUPPORTED */
+ int rc;
+ struct addrinfo *res;
+ struct addrinfo hints = { .ai_flags = AI_NUMERICHOST | AI_NUMERICSERV };
- if (inet_pton(AF_INET, addr, &s4->sin_addr)) {
- s4->sin_family = AF_INET;
- s4->sin_port = htons(port);
-#ifdef IPV6_SUPPORTED
- } else if (inet_pton(AF_INET6, addr, &s6->sin6_addr)) {
- s6->sin6_family = AF_INET6;
- s6->sin6_port = htons(port);
+#ifndef IPV6_SUPPORTED
+ hints.ai_family = AF_INET;
#endif /* IPV6_SUPPORTED */
- } else {
- printerr(0, "ERROR: unable to convert %s to address\n", addr);
+
+ rc = getaddrinfo(node, port, &hints, &res);
+ if (rc) {
+ printerr(0, "ERROR: unable to convert %s|%s to sockaddr: %s\n",
+ node, port, rc == EAI_SYSTEM ? strerror(errno) :
+ gai_strerror(rc));
return 0;
}
+#ifdef IPV6_SUPPORTED
+ /*
+ * getnameinfo ignores the scopeid. If the address turns out to have
+ * a non-zero scopeid, we can't use it -- the resolved host might be
+ * completely different from the one intended.
+ */
+ if (res->ai_addr->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)res->ai_addr;
+ if (sin6->sin6_scope_id) {
+ printerr(0, "ERROR: address %s has non-zero "
+ "sin6_scope_id!\n", node);
+ freeaddrinfo(res);
+ return 0;
+ }
+ }
+#endif /* IPV6_SUPPORTED */
+
+ memcpy(sa, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
return 1;
}
@@ -194,11 +214,10 @@ read_service_info(char *info_file_name,
char program[16];
char version[16];
char protoname[16];
- char cb_port[128];
+ char port[128];
char *p;
int fd = -1;
int numfields;
- int port = 0;
*servicename = *servername = *protocol = NULL;
@@ -227,20 +246,22 @@ read_service_info(char *info_file_name,
goto fail;
}
- cb_port[0] = '\0';
+ port[0] = '\0';
if ((p = strstr(buf, "port")) != NULL)
- sscanf(p, "port: %127s\n", cb_port);
+ sscanf(p, "port: %127s\n", port);
/* check service, program, and version */
- if(memcmp(service, "nfs", 3)) return -1;
+ if (memcmp(service, "nfs", 3) != 0)
+ return -1;
*prog = atoi(program + 1); /* skip open paren */
*vers = atoi(version);
- if((*prog != 100003) || ((*vers != 2) && (*vers != 3) && (*vers != 4)))
- goto fail;
- if (cb_port[0] != '\0') {
- port = atoi(cb_port);
- if (port < 0 || port > 65535)
+ if (strlen(service) == 3 ) {
+ if ((*prog != 100003) || ((*vers != 2) && (*vers != 3) &&
+ (*vers != 4)))
+ goto fail;
+ } else if (memcmp(service, "nfs4_cb", 7) == 0) {
+ if (*vers != 1)
goto fail;
}
@@ -281,9 +302,13 @@ destroy_client(struct clnt_info *clp)
if (clp->spkm3_poll_index != -1)
memset(&pollarray[clp->spkm3_poll_index], 0,
sizeof(struct pollfd));
+ if (clp->gssd_poll_index != -1)
+ memset(&pollarray[clp->gssd_poll_index], 0,
+ sizeof(struct pollfd));
if (clp->dir_fd != -1) close(clp->dir_fd);
if (clp->krb5_fd != -1) close(clp->krb5_fd);
if (clp->spkm3_fd != -1) close(clp->spkm3_fd);
+ if (clp->gssd_fd != -1) close(clp->gssd_fd);
free(clp->dirname);
free(clp->servicename);
free(clp->servername);
@@ -303,8 +328,10 @@ insert_new_clnt(void)
}
clp->krb5_poll_index = -1;
clp->spkm3_poll_index = -1;
+ clp->gssd_poll_index = -1;
clp->krb5_fd = -1;
clp->spkm3_fd = -1;
+ clp->gssd_fd = -1;
clp->dir_fd = -1;
TAILQ_INSERT_HEAD(&clnt_list, clp, list);
@@ -315,19 +342,43 @@ out:
static int
process_clnt_dir_files(struct clnt_info * clp)
{
- char kname[32];
- char sname[32];
- char info_file_name[32];
-
- if (clp->krb5_fd == -1) {
- snprintf(kname, sizeof(kname), "%s/krb5", clp->dirname);
- clp->krb5_fd = open(kname, O_RDWR);
- }
- if (clp->spkm3_fd == -1) {
- snprintf(sname, sizeof(sname), "%s/spkm3", clp->dirname);
- clp->spkm3_fd = open(sname, O_RDWR);
+ char name[PATH_MAX];
+ char gname[PATH_MAX];
+ char info_file_name[PATH_MAX];
+
+ if (clp->gssd_fd == -1) {
+ snprintf(gname, sizeof(gname), "%s/gssd", clp->dirname);
+ clp->gssd_fd = open(gname, O_RDWR);
+ }
+ if (clp->gssd_fd == -1) {
+ if (clp->krb5_fd == -1) {
+ snprintf(name, sizeof(name), "%s/krb5", clp->dirname);
+ clp->krb5_fd = open(name, O_RDWR);
+ }
+ if (clp->spkm3_fd == -1) {
+ snprintf(name, sizeof(name), "%s/spkm3", clp->dirname);
+ clp->spkm3_fd = open(name, O_RDWR);
+ }
+
+ /* If we opened a gss-specific pipe, let's try opening
+ * the new upcall pipe again. If we succeed, close
+ * gss-specific pipe(s).
+ */
+ if (clp->krb5_fd != -1 || clp->spkm3_fd != -1) {
+ clp->gssd_fd = open(gname, O_RDWR);
+ if (clp->gssd_fd != -1) {
+ if (clp->krb5_fd != -1)
+ close(clp->krb5_fd);
+ clp->krb5_fd = -1;
+ if (clp->spkm3_fd != -1)
+ close(clp->spkm3_fd);
+ clp->spkm3_fd = -1;
+ }
+ }
}
- if((clp->krb5_fd == -1) && (clp->spkm3_fd == -1))
+
+ if ((clp->krb5_fd == -1) && (clp->spkm3_fd == -1) &&
+ (clp->gssd_fd == -1))
return -1;
snprintf(info_file_name, sizeof(info_file_name), "%s/info",
clp->dirname);
@@ -362,6 +413,15 @@ get_poll_index(int *ind)
static int
insert_clnt_poll(struct clnt_info *clp)
{
+ if ((clp->gssd_fd != -1) && (clp->gssd_poll_index == -1)) {
+ if (get_poll_index(&clp->gssd_poll_index)) {
+ printerr(0, "ERROR: Too many gssd clients\n");
+ return -1;
+ }
+ pollarray[clp->gssd_poll_index].fd = clp->gssd_fd;
+ pollarray[clp->gssd_poll_index].events |= POLLIN;
+ }
+
if ((clp->krb5_fd != -1) && (clp->krb5_poll_index == -1)) {
if (get_poll_index(&clp->krb5_poll_index)) {
printerr(0, "ERROR: Too many krb5 clients\n");
@@ -384,17 +444,18 @@ insert_clnt_poll(struct clnt_info *clp)
}
static void
-process_clnt_dir(char *dir)
+process_clnt_dir(char *dir, char *pdir)
{
struct clnt_info * clp;
if (!(clp = insert_new_clnt()))
goto fail_destroy_client;
- if (!(clp->dirname = calloc(strlen(dir) + 1, 1))) {
+ /* An extra for the '/', and an extra for the null */
+ if (!(clp->dirname = calloc(strlen(dir) + strlen(pdir) + 2, 1))) {
goto fail_destroy_client;
}
- memcpy(clp->dirname, dir, strlen(dir));
+ sprintf(clp->dirname, "%s/%s", pdir, dir);
if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) {
printerr(0, "ERROR: can't open %s: %s\n",
clp->dirname, strerror(errno));
@@ -438,16 +499,24 @@ init_client_list(void)
* directories, since the DNOTIFY could have been in there.
*/
static void
-update_old_clients(struct dirent **namelist, int size)
+update_old_clients(struct dirent **namelist, int size, char *pdir)
{
struct clnt_info *clp;
void *saveprev;
int i, stillhere;
+ char fname[PATH_MAX];
for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
+ /* only compare entries in the global list that are from the
+ * same pipefs parent directory as "pdir"
+ */
+ if (strncmp(clp->dirname, pdir, strlen(pdir)) != 0) continue;
+
stillhere = 0;
for (i=0; i < size; i++) {
- if (!strcmp(clp->dirname, namelist[i]->d_name)) {
+ snprintf(fname, sizeof(fname), "%s/%s",
+ pdir, namelist[i]->d_name);
+ if (strcmp(clp->dirname, fname) == 0) {
stillhere = 1;
break;
}
@@ -468,48 +537,69 @@ update_old_clients(struct dirent **namel
/* Search for a client by directory name, return 1 if found, 0 otherwise */
static int
-find_client(char *dirname)
+find_client(char *dirname, char *pdir)
{
struct clnt_info *clp;
+ char fname[PATH_MAX];
- for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next)
- if (!strcmp(clp->dirname, dirname))
+ for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
+ snprintf(fname, sizeof(fname), "%s/%s", pdir, dirname);
+ if (strcmp(clp->dirname, fname) == 0)
return 1;
+ }
return 0;
}
-/* Used to read (and re-read) list of clients, set up poll array. */
-int
-update_client_list(void)
+static int
+process_pipedir(char *pipe_name)
{
struct dirent **namelist;
int i, j;
- if (chdir(pipefs_nfsdir) < 0) {
+ if (chdir(pipe_name) < 0) {
printerr(0, "ERROR: can't chdir to %s: %s\n",
- pipefs_nfsdir, strerror(errno));
+ pipe_name, strerror(errno));
return -1;
}
- j = scandir(pipefs_nfsdir, &namelist, NULL, alphasort);
+ j = scandir(pipe_name, &namelist, NULL, alphasort);
if (j < 0) {
printerr(0, "ERROR: can't scandir %s: %s\n",
- pipefs_nfsdir, strerror(errno));
+ pipe_name, strerror(errno));
return -1;
}
- update_old_clients(namelist, j);
+
+ update_old_clients(namelist, j, pipe_name);
for (i=0; i < j; i++) {
if (i < FD_ALLOC_BLOCK
&& !strncmp(namelist[i]->d_name, "clnt", 4)
- && !find_client(namelist[i]->d_name))
- process_clnt_dir(namelist[i]->d_name);
+ && !find_client(namelist[i]->d_name, pipe_name))
+ process_clnt_dir(namelist[i]->d_name, pipe_name);
free(namelist[i]);
}
free(namelist);
+
return 0;
}
+/* Used to read (and re-read) list of clients, set up poll array. */
+int
+update_client_list(void)
+{
+ int retval = -1;
+ struct topdirs_info *tdi;
+
+ TAILQ_FOREACH(tdi, &topdirs_list, list) {
+ retval = process_pipedir(tdi->dirname);
+ if (retval)
+ printerr(1, "WARNING: error processing %s\n",
+ tdi->dirname);
+
+ }
+ return retval;
+}
+
static int
do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
gss_buffer_desc *context_token)
@@ -798,15 +888,14 @@ int create_auth_rpc_client(struct clnt_i
goto out;
}
-
/*
* this code uses the userland rpcsec gss library to create a krb5
* context on behalf of the kernel
*/
-void
-handle_krb5_upcall(struct clnt_info *clp)
+static void
+process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
+ char *service)
{
- uid_t uid;
CLIENT *rpc_clnt = NULL;
AUTH *auth = NULL;
struct authgss_private_data pd;
2010-01-12 13:08:18 +00:00
@@ -815,23 +904,51 @@ handle_krb5_upcall(struct clnt_info *clp
char **ccname;
char **dirname;
int create_resp = -1;
2010-01-12 13:08:18 +00:00
+ int err, downcall_err = -EACCES;
- printerr(1, "handling krb5 upcall\n");
+ printerr(1, "handling krb5 upcall (%s)\n", clp->dirname);
+ if (tgtname) {
+ if (clp->servicename) {
+ free(clp->servicename);
+ clp->servicename = strdup(tgtname);
+ }
+ }
token.length = 0;
token.value = NULL;
memset(&pd, 0, sizeof(struct authgss_private_data));
- if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) {
- printerr(0, "WARNING: failed reading uid from krb5 "
- "upcall pipe: %s\n", strerror(errno));
- goto out;
- }
-
- if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0)) {
+ /*
+ * If "service" is specified, then the kernel is indicating that
+ * we must use machine credentials for this request. (Regardless
+ * of the uid value or the setting of root_uses_machine_creds.)
+ * If the service value is "*", then any service name can be used.
+ * Otherwise, it specifies the service name that should be used.
+ * (For now, the values of service will only be "*" or "nfs".)
+ *
+ * Restricting gssd to use "nfs" service name is needed for when
+ * the NFS server is doing a callback to the NFS client. In this
+ * case, the NFS server has to authenticate itself as "nfs" --
+ * even if there are other service keys such as "host" or "root"
+ * in the keytab.
+ *
+ * Another case when the kernel may specify the service attribute
+ * is when gssd is being asked to create the context for a
+ * SETCLIENT_ID operation. In this case, machine credentials
+ * must be used for the authentication. However, the service name
+ * used for this case is not important.
+ *
+ */
+ printerr(2, "%s: service is '%s'\n", __func__,
+ service ? service : "<null>");
+ if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 &&
+ service == NULL)) {
/* Tell krb5 gss which credentials cache to use */
for (dirname = ccachesearch; *dirname != NULL; dirname++) {
2010-01-12 13:08:18 +00:00
- if (gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname) == 0)
+ err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname);
+ if (err == -EKEYEXPIRED)
+ downcall_err = -EKEYEXPIRED;
+ else if (!err)
create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
AUTHTYPE_KRB5);
if (create_resp == 0)
@@ -839,12 +956,13 @@ handle_krb5_upcall(struct clnt_info *clp
}
}
if (create_resp != 0) {
- if (uid == 0 && root_uses_machine_creds == 1) {
+ if (uid == 0 && (root_uses_machine_creds == 1 ||
+ service != NULL)) {
int nocache = 0;
int success = 0;
do {
gssd_refresh_krb5_machine_credential(clp->servername,
- NULL, nocache);
+ NULL, service);
/*
* Get a list of credential cache names and try each
* of them until one works or we've tried them all
2010-01-12 13:08:18 +00:00
@@ -904,7 +1022,7 @@ handle_krb5_upcall(struct clnt_info *clp
goto out_return_error;
}
- do_downcall(clp->krb5_fd, uid, &pd, &token);
+ do_downcall(fd, uid, &pd, &token);
out:
if (token.value)
2010-01-12 13:08:18 +00:00
@@ -920,7 +1038,7 @@ out:
return;
out_return_error:
- do_error_downcall(clp->krb5_fd, uid, -1);
2010-01-12 13:08:18 +00:00
+ do_error_downcall(fd, uid, downcall_err);
goto out;
}
2010-01-12 13:08:18 +00:00
@@ -928,26 +1046,19 @@ out_return_error:
* this code uses the userland rpcsec gss library to create an spkm3
* context on behalf of the kernel
*/
-void
-handle_spkm3_upcall(struct clnt_info *clp)
+static void
+process_spkm3_upcall(struct clnt_info *clp, uid_t uid, int fd)
{
- uid_t uid;
CLIENT *rpc_clnt = NULL;
AUTH *auth = NULL;
struct authgss_private_data pd;
gss_buffer_desc token;
- printerr(2, "handling spkm3 upcall\n");
+ printerr(2, "handling spkm3 upcall (%s)\n", clp->dirname);
token.length = 0;
token.value = NULL;
- if (read(clp->spkm3_fd, &uid, sizeof(uid)) < sizeof(uid)) {
- printerr(0, "WARNING: failed reading uid from spkm3 "
- "upcall pipe: %s\n", strerror(errno));
- goto out;
- }
-
if (create_auth_rpc_client(clp, &rpc_clnt, &auth, uid, AUTHTYPE_SPKM3)) {
printerr(0, "WARNING: Failed to create spkm3 context for "
"user with uid %d\n", uid);
2010-01-12 13:08:18 +00:00
@@ -968,7 +1079,7 @@ handle_spkm3_upcall(struct clnt_info *cl
goto out_return_error;
}
- do_downcall(clp->spkm3_fd, uid, &pd, &token);
+ do_downcall(fd, uid, &pd, &token);
out:
if (token.value)
2010-01-12 13:08:18 +00:00
@@ -980,6 +1091,139 @@ out:
return;
out_return_error:
- do_error_downcall(clp->spkm3_fd, uid, -1);
+ do_error_downcall(fd, uid, -1);
goto out;
}
+
+void
+handle_krb5_upcall(struct clnt_info *clp)
+{
+ uid_t uid;
+
+ if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) {
+ printerr(0, "WARNING: failed reading uid from krb5 "
+ "upcall pipe: %s\n", strerror(errno));
+ return;
+ }
+
+ return process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL);
+}
+
+void
+handle_spkm3_upcall(struct clnt_info *clp)
+{
+ uid_t uid;
+
+ if (read(clp->spkm3_fd, &uid, sizeof(uid)) < sizeof(uid)) {
+ printerr(0, "WARNING: failed reading uid from spkm3 "
+ "upcall pipe: %s\n", strerror(errno));
+ return;
+ }
+
+ return process_spkm3_upcall(clp, uid, clp->spkm3_fd);
+}
+
+void
+handle_gssd_upcall(struct clnt_info *clp)
+{
+ uid_t uid;
+ char *lbuf = NULL;
+ int lbuflen = 0;
+ char *p;
+ char *mech = NULL;
+ char *target = NULL;
+ char *service = NULL;
+
+ printerr(1, "handling gssd upcall (%s)\n", clp->dirname);
+
+ if (readline(clp->gssd_fd, &lbuf, &lbuflen) != 1) {
+ printerr(0, "WARNING: handle_gssd_upcall: "
+ "failed reading request\n");
+ return;
+ }
+ printerr(2, "%s: '%s'\n", __func__, lbuf);
+
+ /* find the mechanism name */
+ if ((p = strstr(lbuf, "mech=")) != NULL) {
+ mech = malloc(lbuflen);
+ if (!mech)
+ goto out;
+ if (sscanf(p, "mech=%s", mech) != 1) {
+ printerr(0, "WARNING: handle_gssd_upcall: "
+ "failed to parse gss mechanism name "
+ "in upcall string '%s'\n", lbuf);
+ goto out;
+ }
+ } else {
+ printerr(0, "WARNING: handle_gssd_upcall: "
+ "failed to find gss mechanism name "
+ "in upcall string '%s'\n", lbuf);
+ goto out;
+ }
+
+ /* read uid */
+ if ((p = strstr(lbuf, "uid=")) != NULL) {
+ if (sscanf(p, "uid=%d", &uid) != 1) {
+ printerr(0, "WARNING: handle_gssd_upcall: "
+ "failed to parse uid "
+ "in upcall string '%s'\n", lbuf);
+ goto out;
+ }
+ } else {
+ printerr(0, "WARNING: handle_gssd_upcall: "
+ "failed to find uid "
+ "in upcall string '%s'\n", lbuf);
+ goto out;
+ }
+
+ /* read target name */
+ if ((p = strstr(lbuf, "target=")) != NULL) {
+ target = malloc(lbuflen);
+ if (!target)
+ goto out;
+ if (sscanf(p, "target=%s", target) != 1) {
+ printerr(0, "WARNING: handle_gssd_upcall: "
+ "failed to parse target name "
+ "in upcall string '%s'\n", lbuf);
+ goto out;
+ }
+ }
+
+ /*
+ * read the service name
+ *
+ * The presence of attribute "service=" indicates that machine
+ * credentials should be used for this request. If the value
+ * is "*", then any machine credentials available can be used.
+ * If the value is anything else, then machine credentials for
+ * the specified service name (always "nfs" for now) should be
+ * used.
+ */
+ if ((p = strstr(lbuf, "service=")) != NULL) {
+ service = malloc(lbuflen);
+ if (!service)
+ goto out;
+ if (sscanf(p, "service=%s", service) != 1) {
+ printerr(0, "WARNING: handle_gssd_upcall: "
+ "failed to parse service type "
+ "in upcall string '%s'\n", lbuf);
+ goto out;
+ }
+ }
+
+ if (strcmp(mech, "krb5") == 0)
+ process_krb5_upcall(clp, uid, clp->gssd_fd, target, service);
+ else if (strcmp(mech, "spkm3") == 0)
+ process_spkm3_upcall(clp, uid, clp->gssd_fd);
+ else
+ printerr(0, "WARNING: handle_gssd_upcall: "
+ "received unknown gss mech '%s'\n", mech);
+
+out:
+ free(lbuf);
+ free(mech);
+ free(target);
+ free(service);
+ return;
+}
+
diff -up nfs-utils-1.2.1/utils/gssd/krb5_util.c.orig nfs-utils-1.2.1/utils/gssd/krb5_util.c
--- nfs-utils-1.2.1/utils/gssd/krb5_util.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/gssd/krb5_util.c 2010-01-14 03:53:55.452888183 -0500
2010-01-12 13:08:18 +00:00
@@ -170,9 +170,8 @@ select_krb5_ccache(const struct dirent *
* what we want. Otherwise, return zero and no dirent pointer.
* The caller is responsible for freeing the dirent if one is returned.
*
- * Returns:
- * 0 => could not find an existing entry
- * 1 => found an existing entry
+ * Returns 0 if a valid-looking entry was found and a non-zero error
+ * code otherwise.
*/
static int
gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d)
@@ -186,7 +185,7 @@ gssd_find_existing_krb5_ccache(uid_t uid
char buf[1030];
char *princname = NULL;
char *realm = NULL;
- int score, best_match_score = 0;
+ int score, best_match_score = 0, err = -EACCES;
memset(&best_match_stat, 0, sizeof(best_match_stat));
*d = NULL;
@@ -229,6 +228,7 @@ gssd_find_existing_krb5_ccache(uid_t uid
printerr(3, "CC file '%s' is expired or corrupt\n",
statname);
free(namelist[i]);
+ err = -EKEYEXPIRED;
continue;
}
@@ -284,11 +284,12 @@ gssd_find_existing_krb5_ccache(uid_t uid
}
free(namelist);
}
- if (found)
- {
+ if (found) {
*d = best_match_dir;
+ return 0;
}
- return found;
+
+ return err;
}
@@ -797,10 +798,9 @@ gssd_search_krb5_keytab(krb5_context con
*/
static int
find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname,
- krb5_keytab_entry *kte)
+ krb5_keytab_entry *kte, const char **svcnames)
{
krb5_error_code code;
- const char *svcnames[] = { "root", "nfs", "host", NULL };
char **realmnames = NULL;
char myhostname[NI_MAXHOST], targethostname[NI_MAXHOST];
int i, j, retval;
2010-01-12 13:08:18 +00:00
@@ -1025,29 +1025,29 @@ err_cache:
* given only a UID. We really need more information, but we
* do the best we can.
*
- * Returns:
- * 0 => a ccache was found
- * 1 => no ccache was found
+ * Returns 0 if a ccache was found, and a non-zero error code otherwise.
*/
int
gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirname)
{
char buf[MAX_NETOBJ_SZ];
struct dirent *d;
+ int err;
printerr(2, "getting credentials for client with uid %u for "
"server %s\n", uid, servername);
memset(buf, 0, sizeof(buf));
- if (gssd_find_existing_krb5_ccache(uid, dirname, &d)) {
- snprintf(buf, sizeof(buf), "FILE:%s/%s", dirname, d->d_name);
- free(d);
- }
- else
- return 1;
+ err = gssd_find_existing_krb5_ccache(uid, dirname, &d);
+ if (err)
+ return err;
+
+ snprintf(buf, sizeof(buf), "FILE:%s/%s", dirname, d->d_name);
+ free(d);
+
printerr(2, "using %s as credentials cache for client with "
"uid %u for server %s\n", buf, uid, servername);
gssd_set_krb5_ccache_name(buf);
- return 0;
+ return err;
}
/*
@@ -1096,7 +1096,8 @@ gssd_get_krb5_machine_cred_list(char ***
for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) {
if (ple->ccname) {
/* Make sure cred is up-to-date before returning it */
- retval = gssd_refresh_krb5_machine_credential(NULL, ple, 0);
+ retval = gssd_refresh_krb5_machine_credential(NULL, ple,
+ NULL);
if (retval)
continue;
if (i + 1 > listsize) {
2010-01-12 13:08:18 +00:00
@@ -1186,14 +1187,24 @@ gssd_destroy_krb5_machine_creds(void)
*/
int
gssd_refresh_krb5_machine_credential(char *hostname,
- struct gssd_k5_kt_princ *ple, int nocache)
+ struct gssd_k5_kt_princ *ple,
+ char *service)
{
krb5_error_code code = 0;
krb5_context context;
krb5_keytab kt = NULL;;
int retval = 0;
char *k5err = NULL;
+ const char *svcnames[4] = { "root", "nfs", "host", NULL };
+ /*
+ * If a specific service name was specified, use it.
+ * Otherwise, use the default list.
+ */
+ if (service != NULL && strcmp(service, "*") != 0) {
+ svcnames[0] = service;
+ svcnames[1] = NULL;
+ }
if (hostname == NULL && ple == NULL)
return EINVAL;
2010-01-12 13:08:18 +00:00
@@ -1216,7 +1227,7 @@ gssd_refresh_krb5_machine_credential(cha
if (ple == NULL) {
krb5_keytab_entry kte;
- code = find_keytab_entry(context, kt, hostname, &kte);
+ code = find_keytab_entry(context, kt, hostname, &kte, svcnames);
if (code) {
printerr(0, "ERROR: %s: no usable keytab entry found "
"in keytab %s for connection with host %s\n",
2010-01-12 13:08:18 +00:00
@@ -1241,7 +1252,7 @@ gssd_refresh_krb5_machine_credential(cha
goto out;
}
}
- retval = gssd_get_single_krb5_cred(context, kt, ple, nocache);
+ retval = gssd_get_single_krb5_cred(context, kt, ple, 0);
out:
if (kt)
krb5_kt_close(context, kt);
diff -up nfs-utils-1.2.1/utils/gssd/krb5_util.h.orig nfs-utils-1.2.1/utils/gssd/krb5_util.h
--- nfs-utils-1.2.1/utils/gssd/krb5_util.h.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/gssd/krb5_util.h 2010-01-14 03:53:55.453930141 -0500
@@ -30,7 +30,8 @@ void gssd_free_krb5_machine_cred_list(ch
void gssd_setup_krb5_machine_gss_ccache(char *servername);
void gssd_destroy_krb5_machine_creds(void);
int gssd_refresh_krb5_machine_credential(char *hostname,
- struct gssd_k5_kt_princ *ple, int nocache);
+ struct gssd_k5_kt_princ *ple,
+ char *service);
char *gssd_k5_err_msg(krb5_context context, krb5_error_code code);
void gssd_k5_get_default_realm(char **def_realm);
diff -up nfs-utils-1.2.1/utils/gssd/svcgssd_proc.c.orig nfs-utils-1.2.1/utils/gssd/svcgssd_proc.c
--- nfs-utils-1.2.1/utils/gssd/svcgssd_proc.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/gssd/svcgssd_proc.c 2010-01-14 03:53:55.454909195 -0500
@@ -56,6 +56,7 @@
#include "gss_util.h"
#include "err_util.h"
#include "context.h"
+#include "gss_oids.h"
extern char * mech2file(gss_OID mech);
#define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.rpcsec.context/channel"
@@ -73,7 +74,7 @@ struct svc_cred {
static int
do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred,
gss_OID mech, gss_buffer_desc *context_token,
- int32_t endtime)
+ int32_t endtime, char *client_name)
{
FILE *f;
int i;
@@ -98,9 +99,10 @@ do_svc_downcall(gss_buffer_desc *out_han
qword_printint(f, cred->cr_gid);
qword_printint(f, cred->cr_ngroups);
printerr(2, "mech: %s, hndl len: %d, ctx len %d, timeout: %d (%d from now), "
- "uid: %d, gid: %d, num aux grps: %d:\n",
+ "clnt: %s, uid: %d, gid: %d, num aux grps: %d:\n",
fname, out_handle->length, context_token->length,
endtime, endtime - time(0),
+ client_name ? client_name : "<null>",
cred->cr_uid, cred->cr_gid, cred->cr_ngroups);
for (i=0; i < cred->cr_ngroups; i++) {
qword_printint(f, cred->cr_groups[i]);
@@ -108,6 +110,8 @@ do_svc_downcall(gss_buffer_desc *out_han
}
qword_print(f, fname);
qword_printhex(f, context_token->value, context_token->length);
+ if (client_name)
+ qword_print(f, client_name);
err = qword_eol(f);
if (err) {
printerr(1, "WARNING: error writing to downcall channel "
@@ -307,6 +311,75 @@ print_hexl(const char *description, unsi
}
#endif
+static int
+get_krb5_hostbased_name (gss_buffer_desc *name, char **hostbased_name)
+{
+ char *p, *sname = NULL;
+ if (strchr(name->value, '@') && strchr(name->value, '/')) {
+ if ((sname = calloc(name->length, 1)) == NULL) {
+ printerr(0, "ERROR: get_krb5_hostbased_name failed "
+ "to allocate %d bytes\n", name->length);
+ return -1;
+ }
+ /* read in name and instance and replace '/' with '@' */
+ sscanf(name->value, "%[^@]", sname);
+ p = strrchr(sname, '/');
+ if (p == NULL) { /* The '@' preceeded the '/' */
+ free(sname);
+ return -1;
+ }
+ *p = '@';
+ }
+ *hostbased_name = sname;
+ return 0;
+}
+
+static int
+get_hostbased_client_name(gss_name_t client_name, gss_OID mech,
+ char **hostbased_name)
+{
+ u_int32_t maj_stat, min_stat;
+ gss_buffer_desc name;
+ gss_OID name_type = GSS_C_NO_OID;
+ char *cname;
+ int res = -1;
+
+ *hostbased_name = NULL; /* preset in case we fail */
+
+ /* Get the client's gss authenticated name */
+ maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type);
+ if (maj_stat != GSS_S_COMPLETE) {
+ pgsserr("get_hostbased_client_name: gss_display_name",
+ maj_stat, min_stat, mech);
+ goto out_err;
+ }
+ if (name.length >= 0xffff) { /* don't overflow */
+ printerr(0, "ERROR: get_hostbased_client_name: "
+ "received gss_name is too long (%d bytes)\n",
+ name.length);
+ goto out_rel_buf;
+ }
+
+ /* For Kerberos, transform the NT_KRB5_PRINCIPAL name to
+ * an NT_HOSTBASED_SERVICE name */
+ if (g_OID_equal(&krb5oid, mech)) {
+ if (get_krb5_hostbased_name(&name, &cname) == 0)
+ *hostbased_name = cname;
+ }
+
+ /* No support for SPKM3, just print a warning (for now) */
+ if (g_OID_equal(&spkm3oid, mech)) {
+ printerr(1, "WARNING: get_hostbased_client_name: "
+ "no hostbased_name support for SPKM3\n");
+ }
+
+ res = 0;
+out_rel_buf:
+ gss_release_buffer(&min_stat, &name);
+out_err:
+ return res;
+}
+
void
handle_nullreq(FILE *f) {
/* XXX initialize to a random integer to reduce chances of unnecessary
@@ -325,7 +398,7 @@ handle_nullreq(FILE *f) {
null_token = {.value = NULL};
u_int32_t ret_flags;
gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
- gss_name_t client_name;
+ gss_name_t client_name = NULL;
gss_OID mech = GSS_C_NO_OID;
u_int32_t maj_stat = GSS_S_FAILURE, min_stat = 0;
u_int32_t ignore_min_stat;
@@ -334,6 +407,7 @@ handle_nullreq(FILE *f) {
static int lbuflen = 0;
static char *cp;
int32_t ctx_endtime;
+ char *hostbased_name = NULL;
printerr(1, "handling null request\n");
@@ -396,11 +470,13 @@ handle_nullreq(FILE *f) {
if (get_ids(client_name, mech, &cred)) {
/* get_ids() prints error msg */
maj_stat = GSS_S_BAD_NAME; /* XXX ? */
- gss_release_name(&ignore_min_stat, &client_name);
goto out_err;
}
- gss_release_name(&ignore_min_stat, &client_name);
-
+ if (get_hostbased_client_name(client_name, mech, &hostbased_name)) {
+ /* get_hostbased_client_name() prints error msg */
+ maj_stat = GSS_S_BAD_NAME; /* XXX ? */
+ goto out_err;
+ }
/* Context complete. Pass handle_seq in out_handle to use
* for context lookup in the kernel. */
@@ -419,7 +495,8 @@ handle_nullreq(FILE *f) {
/* We no longer need the gss context */
gss_delete_sec_context(&ignore_min_stat, &ctx, &ignore_out_tok);
- do_svc_downcall(&out_handle, &cred, mech, &ctx_token, ctx_endtime);
+ do_svc_downcall(&out_handle, &cred, mech, &ctx_token, ctx_endtime,
+ hostbased_name);
continue_needed:
send_response(f, &in_handle, &in_tok, maj_stat, min_stat,
&out_handle, &out_tok);
@@ -428,6 +505,9 @@ out:
free(ctx_token.value);
if (out_tok.value != NULL)
gss_release_buffer(&ignore_min_stat, &out_tok);
+ if (client_name)
+ gss_release_name(&ignore_min_stat, &client_name);
+ free(hostbased_name);
printerr(1, "finished handling null request\n");
return;
diff -up nfs-utils-1.2.1/utils/mountd/auth.c.orig nfs-utils-1.2.1/utils/mountd/auth.c
--- nfs-utils-1.2.1/utils/mountd/auth.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/mountd/auth.c 2010-01-14 03:53:55.462909434 -0500
@@ -20,6 +20,7 @@
#include "exportfs.h"
#include "mountd.h"
#include "xmalloc.h"
+#include "v4root.h"
enum auth_error
{
@@ -102,75 +103,91 @@ auth_reload()
memset(&my_client, 0, sizeof(my_client));
xtab_export_read();
check_useipaddr();
+ v4root_set();
+
++counter;
return counter;
}
+static char *get_client_hostname(struct sockaddr_in *caller, struct hostent *hp, enum auth_error *error)
+{
+ char *n;
+
+ if (use_ipaddr)
+ return strdup(inet_ntoa(caller->sin_addr));
+ n = client_compose(hp);
+ *error = unknown_host;
+ if (!n)
+ return NULL;
+ if (*n)
+ return n;
+ free(n);
+ return strdup("DEFAULT");
+}
+
+/* return static nfs_export with details filled in */
static nfs_export *
-auth_authenticate_internal(char *what, struct sockaddr_in *caller,
+auth_authenticate_newcache(char *what, struct sockaddr_in *caller,
char *path, struct hostent *hp,
enum auth_error *error)
{
- nfs_export *exp;
+ nfs_export *exp;
+ int i;
- if (new_cache) {
- int i;
- /* return static nfs_export with details filled in */
- char *n;
- free(my_client.m_hostname);
- if (use_ipaddr) {
- my_client.m_hostname =
- strdup(inet_ntoa(caller->sin_addr));
- } else {
- n = client_compose(hp);
- *error = unknown_host;
- if (!n)
- my_client.m_hostname = NULL;
- else if (*n)
- my_client.m_hostname = n;
- else {
- free(n);
- my_client.m_hostname = strdup("DEFAULT");
- }
+ free(my_client.m_hostname);
+
+ my_client.m_hostname = get_client_hostname(caller, hp, error);
+ if (my_client.m_hostname == NULL)
+ return NULL;
+
+ my_client.m_naddr = 1;
+ my_client.m_addrlist[0] = caller->sin_addr;
+ my_exp.m_client = &my_client;
+
+ exp = NULL;
+ for (i = 0; !exp && i < MCL_MAXTYPES; i++)
+ for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
+ if (strcmp(path, exp->m_export.e_path))
+ continue;
+ if (!use_ipaddr && !client_member(my_client.m_hostname, exp->m_client->m_hostname))
+ continue;
+ if (use_ipaddr && !client_check(exp->m_client, hp))
+ continue;
+ break;
}
- if (my_client.m_hostname == NULL)
- return NULL;
- my_client.m_naddr = 1;
- my_client.m_addrlist[0] = caller->sin_addr;
- my_exp.m_client = &my_client;
-
- exp = NULL;
- for (i = 0; !exp && i < MCL_MAXTYPES; i++)
- for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
- if (strcmp(path, exp->m_export.e_path))
- continue;
- if (!use_ipaddr && !client_member(my_client.m_hostname, exp->m_client->m_hostname))
- continue;
- if (use_ipaddr && !client_check(exp->m_client, hp))
- continue;
- break;
- }
- *error = not_exported;
- if (!exp)
- return exp;
+ *error = not_exported;
+ if (!exp)
+ return NULL;
- my_exp.m_export = exp->m_export;
- exp = &my_exp;
+ my_exp.m_export = exp->m_export;
+ exp = &my_exp;
+ return exp;
+}
+
+static nfs_export *
+auth_authenticate_internal(char *what, struct sockaddr_in *caller,
+ char *path, struct hostent *hp,
+ enum auth_error *error)
+{
+ nfs_export *exp;
+ if (new_cache) {
+ exp = auth_authenticate_newcache(what, caller, path, hp, error);
+ if (!exp)
+ return NULL;
} else {
if (!(exp = export_find(hp, path))) {
*error = no_entry;
return NULL;
}
- if (!exp->m_mayexport) {
- *error = not_exported;
- return NULL;
- }
+ }
+ if (exp->m_export.e_flags & NFSEXP_V4ROOT) {
+ *error = no_entry;
+ return NULL;
}
if (!(exp->m_export.e_flags & NFSEXP_INSECURE_PORT) &&
- (ntohs(caller->sin_port) < IPPORT_RESERVED/2 ||
- ntohs(caller->sin_port) >= IPPORT_RESERVED)) {
+ ntohs(caller->sin_port) >= IPPORT_RESERVED) {
*error = illegal_port;
return NULL;
}
diff -up nfs-utils-1.2.1/utils/mountd/cache.c.orig nfs-utils-1.2.1/utils/mountd/cache.c
--- nfs-utils-1.2.1/utils/mountd/cache.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/mountd/cache.c 2010-01-14 03:53:55.463909067 -0500
@@ -614,73 +614,54 @@ static int dump_to_cache(FILE *f, char *
return qword_eol(f);
}
-void nfsd_export(FILE *f)
+static int is_subdirectory(char *subpath, char *path)
{
- /* requests are:
- * domain path
- * determine export options and return:
- * domain path expiry flags anonuid anongid fsid
- */
+ int l = strlen(path);
- char *cp;
- int i;
- char *dom, *path;
- nfs_export *exp, *found = NULL;
- int found_type = 0;
- struct in_addr addr;
- struct hostent *he = NULL;
-
-
- if (readline(fileno(f), &lbuf, &lbuflen) != 1)
- return;
-
- xlog(D_CALL, "nfsd_export: inbuf '%s'", lbuf);
+ return strcmp(subpath, path) == 0
+ || (strncmp(subpath, path, l) == 0 && path[l] == '/');
+}
- cp = lbuf;
- dom = malloc(strlen(cp));
- path = malloc(strlen(cp));
+static int path_matches(nfs_export *exp, char *path)
+{
+ if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT)
+ return is_subdirectory(path, exp->m_export.e_path);
+ return strcmp(path, exp->m_export.e_path) == 0;
+}
- if (!dom || !path)
- goto out;
+static int client_matches(nfs_export *exp, char *dom, struct hostent *he)
+{
+ if (use_ipaddr)
+ return client_check(exp->m_client, he);
+ return client_member(dom, exp->m_client->m_hostname);
+}
- if (qword_get(&cp, dom, strlen(lbuf)) <= 0)
- goto out;
- if (qword_get(&cp, path, strlen(lbuf)) <= 0)
- goto out;
+static int export_matches(nfs_export *exp, char *dom, char *path, struct hostent *he)
+{
+ return path_matches(exp, path) && client_matches(exp, dom, he);
+}
- auth_reload();
+static nfs_export *lookup_export(char *dom, char *path, struct hostent *he)
+{
+ nfs_export *exp;
+ nfs_export *found = NULL;
+ int found_type = 0;
+ int i;
- /* now find flags for this export point in this domain */
for (i=0 ; i < MCL_MAXTYPES; i++) {
for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
- if (!use_ipaddr && !client_member(dom, exp->m_client->m_hostname))
- continue;
- if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT) {
- /* if path is a mountpoint below e_path, then OK */
- int l = strlen(exp->m_export.e_path);
- if (strcmp(path, exp->m_export.e_path) == 0 ||
- (strncmp(path, exp->m_export.e_path, l) == 0 &&
- path[l] == '/' &&
- is_mountpoint(path)))
- /* ok */;
- else
- continue;
- } else if (strcmp(path, exp->m_export.e_path) != 0)
+ if (!export_matches(exp, dom, path, he))
continue;
- if (use_ipaddr) {
- if (he == NULL) {
- if (!inet_aton(dom, &addr))
- goto out;
- he = client_resolve(addr);
- }
- if (!client_check(exp->m_client, he))
- continue;
- }
if (!found) {
found = exp;
found_type = i;
continue;
}
+
+ /* Always prefer non-V4ROOT mounts */
+ if (found->m_export.e_flags & NFSEXP_V4ROOT)
+ continue;
+
/* If one is a CROSSMOUNT, then prefer the longest path */
if (((found->m_export.e_flags & NFSEXP_CROSSMOUNT) ||
(exp->m_export.e_flags & NFSEXP_CROSSMOUNT)) &&
@@ -703,6 +684,50 @@ void nfsd_export(FILE *f)
}
}
}
+ return found;
+}
+
+void nfsd_export(FILE *f)
+{
+ /* requests are:
+ * domain path
+ * determine export options and return:
+ * domain path expiry flags anonuid anongid fsid
+ */
+
+ char *cp;
+ char *dom, *path;
+ nfs_export *found = NULL;
+ struct in_addr addr;
+ struct hostent *he = NULL;
+
+
+ if (readline(fileno(f), &lbuf, &lbuflen) != 1)
+ return;
+
+ xlog(D_CALL, "nfsd_export: inbuf '%s'", lbuf);
+
+ cp = lbuf;
+ dom = malloc(strlen(cp));
+ path = malloc(strlen(cp));
+
+ if (!dom || !path)
+ goto out;
+
+ if (qword_get(&cp, dom, strlen(lbuf)) <= 0)
+ goto out;
+ if (qword_get(&cp, path, strlen(lbuf)) <= 0)
+ goto out;
+
+ auth_reload();
+
+ if (use_ipaddr) {
+ if (!inet_aton(dom, &addr))
+ goto out;
+ he = client_resolve(addr);
+ }
+
+ found = lookup_export(dom, path, he);
if (found) {
if (dump_to_cache(f, dom, path, &found->m_export) < 0) {
diff -up nfs-utils-1.2.1/utils/mountd/Makefile.am.orig nfs-utils-1.2.1/utils/mountd/Makefile.am
--- nfs-utils-1.2.1/utils/mountd/Makefile.am.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/mountd/Makefile.am 2010-01-14 03:53:55.461898931 -0500
@@ -8,7 +8,7 @@ KPREFIX = @kprefix@
sbin_PROGRAMS = mountd
mountd_SOURCES = mountd.c mount_dispatch.c auth.c rmtab.c cache.c \
- svc_run.c fsloc.c mountd.h
+ svc_run.c fsloc.c v4root.c mountd.h
mountd_LDADD = ../../support/export/libexport.a \
../../support/nfs/libnfs.a \
../../support/misc/libmisc.a \
diff -up nfs-utils-1.2.1/utils/mountd/mountd.c.orig nfs-utils-1.2.1/utils/mountd/mountd.c
--- nfs-utils-1.2.1/utils/mountd/mountd.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/mountd/mountd.c 2010-01-14 03:53:55.464824245 -0500
@@ -509,12 +509,89 @@ get_rootfh(struct svc_req *rqstp, dirpat
return fh;
}
+static void remove_all_clients(exportnode *e)
+{
+ struct groupnode *g, *ng;
+
+ for (g = e->ex_groups; g; g = ng) {
+ ng = g->gr_next;
+ xfree(g->gr_name);
+ xfree(g);
+ }
+ e->ex_groups = NULL;
+}
+
+static void free_exportlist(exports *elist)
+{
+ struct exportnode *e, *ne;
+
+ for (e = *elist; e != NULL; e = ne) {
+ ne = e->ex_next;
+ remove_all_clients(e);
+ xfree(e->ex_dir);
+ xfree(e);
+ }
+ *elist = NULL;
+}
+
+static void prune_clients(nfs_export *exp, struct exportnode *e)
+{
+ struct hostent *hp;
+ struct groupnode *c, **cp;
+
+ cp = &e->ex_groups;
+ while ((c = *cp) != NULL) {
+ if (client_gettype(c->gr_name) == MCL_FQDN
+ && (hp = gethostbyname(c->gr_name))) {
+ hp = hostent_dup(hp);
+ if (client_check(exp->m_client, hp)) {
+ *cp = c->gr_next;
+ xfree(c->gr_name);
+ xfree(c);
+ xfree (hp);
+ continue;
+ }
+ xfree (hp);
+ }
+ cp = &(c->gr_next);
+ }
+}
+
+static exportnode *lookup_or_create_elist_entry(exports *elist, nfs_export *exp)
+{
+ exportnode *e;
+
+ for (e = *elist; e != NULL; e = e->ex_next) {
+ if (!strcmp(exp->m_export.e_path, e->ex_dir))
+ return e;
+ }
+ e = xmalloc(sizeof(*e));
+ e->ex_next = *elist;
+ e->ex_groups = NULL;
+ e->ex_dir = xstrdup(exp->m_export.e_path);
+ *elist = e;
+ return e;
+}
+
+static void insert_group(struct exportnode *e, char *newname)
+{
+ struct groupnode *g;
+
+ for (g = e->ex_groups; g; g = g->gr_next)
+ if (strcmp(g->gr_name, newname))
+ return;
+
+ g = xmalloc(sizeof(*g));
+ g->gr_name = xstrdup(newname);
+ g->gr_next = e->ex_groups;
+ e->ex_groups = g;
+}
+
static exports
get_exportlist(void)
{
static exports elist = NULL;
- struct exportnode *e, *ne;
- struct groupnode *g, *ng, *c, **cp;
+ struct exportnode *e;
nfs_export *exp;
int i;
static unsigned int ecounter;
@@ -526,77 +603,26 @@ get_exportlist(void)
ecounter = acounter;
- for (e = elist; e != NULL; e = ne) {
- ne = e->ex_next;
- for (g = e->ex_groups; g != NULL; g = ng) {
- ng = g->gr_next;
- xfree(g->gr_name);
- xfree(g);
- }
- xfree(e->ex_dir);
- xfree(e);
- }
- elist = NULL;
+ free_exportlist(&elist);
for (i = 0; i < MCL_MAXTYPES; i++) {
for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
- for (e = elist; e != NULL; e = e->ex_next) {
- 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.e_path);
- elist = e;
- }
-
- /* We need to check if we should remove
- previous ones. */
- if (i == MCL_ANONYMOUS && e->ex_groups) {
- for (g = e->ex_groups; g; g = ng) {
- ng = g->gr_next;
- xfree(g->gr_name);
- xfree(g);
- }
- e->ex_groups = NULL;
+ /* Don't show pseudo exports */
+ if (exp->m_export.e_flags & NFSEXP_V4ROOT)
continue;
- }
-
- if (i != MCL_FQDN && e->ex_groups) {
- struct hostent *hp;
+ e = lookup_or_create_elist_entry(&elist, exp);
- cp = &e->ex_groups;
- while ((c = *cp) != NULL) {
- if (client_gettype (c->gr_name) == MCL_FQDN
- && (hp = gethostbyname(c->gr_name))) {
- hp = hostent_dup (hp);
- if (client_check(exp->m_client, hp)) {
- *cp = c->gr_next;
- xfree(c->gr_name);
- xfree(c);
- xfree (hp);
+ /* exports to "*" absorb any others */
+ if (i == MCL_ANONYMOUS && e->ex_groups) {
+ remove_all_clients(e);
continue;
- }
- xfree (hp);
- }
- cp = &(c->gr_next);
- }
}
+ /* non-FQDN's absorb FQDN's they contain: */
+ if (i != MCL_FQDN && e->ex_groups)
+ prune_clients(exp, e);
- if (exp->m_export.e_hostname [0] != '\0') {
- for (g = e->ex_groups; g; g = g->gr_next)
- if (strcmp (exp->m_export.e_hostname,
- g->gr_name) == 0)
- break;
- if (g)
- continue;
- g = (struct groupnode *) xmalloc(sizeof(*g));
- g->gr_name = xstrdup(exp->m_export.e_hostname);
- g->gr_next = e->ex_groups;
- e->ex_groups = g;
- }
+ if (exp->m_export.e_hostname[0] != '\0')
+ insert_group(e, exp->m_export.e_hostname);
}
}
diff -up nfs-utils-1.2.1/utils/mountd/rmtab.c.orig nfs-utils-1.2.1/utils/mountd/rmtab.c
--- nfs-utils-1.2.1/utils/mountd/rmtab.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/mountd/rmtab.c 2010-01-14 03:53:55.464824245 -0500
@@ -143,23 +143,16 @@ mountlist_del_all(struct sockaddr_in *si
return;
if (!(hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET))) {
xlog(L_ERROR, "can't get hostname of %s", inet_ntoa(addr));
- xfunlock(lockid);
- return;
+ goto out_unlock;
}
- else
- hp = hostent_dup (hp);
+ hp = hostent_dup (hp);
+
+ if (!setrmtabent("r"))
+ goto out_free;
+
+ if (!(fp = fsetrmtabent(_PATH_RMTABTMP, "w")))
+ goto out_close;
- if (!setrmtabent("r")) {
- xfunlock(lockid);
- free (hp);
- return;
- }
- if (!(fp = fsetrmtabent(_PATH_RMTABTMP, "w"))) {
- endrmtabent();
- xfunlock(lockid);
- free (hp);
- return;
- }
while ((rep = getrmtabent(1, NULL)) != NULL) {
if (strcmp(rep->r_client, hp->h_name) == 0 &&
(exp = auth_authenticate("umountall", sin, rep->r_path)))
@@ -170,10 +163,13 @@ mountlist_del_all(struct sockaddr_in *si
xlog(L_ERROR, "couldn't rename %s to %s",
_PATH_RMTABTMP, _PATH_RMTAB);
}
- endrmtabent(); /* close & unlink */
fendrmtabent(fp);
- xfunlock(lockid);
+out_close:
+ endrmtabent(); /* close & unlink */
+out_free:
free (hp);
+out_unlock:
+ xfunlock(lockid);
}
mountlist
diff -up nfs-utils-1.2.1/utils/mountd/v4root.c.orig nfs-utils-1.2.1/utils/mountd/v4root.c
--- nfs-utils-1.2.1/utils/mountd/v4root.c.orig 2010-01-14 03:53:55.465872101 -0500
+++ nfs-utils-1.2.1/utils/mountd/v4root.c 2010-01-14 03:53:55.465872101 -0500
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2009 Red Hat <nfs@redhat.com>
+ *
+ * support/export/v4root.c
+ *
+ * Routines used to support NFSv4 pseudo roots
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <unistd.h>
+#include <errno.h>
+
+#include "xlog.h"
+#include "exportfs.h"
+#include "nfslib.h"
+#include "misc.h"
+#include "v4root.h"
+
+int v4root_needed;
+
+static nfs_export pseudo_root = {
+ .m_next = NULL,
+ .m_client = NULL,
+ .m_export = {
+ .e_hostname = "*",
+ .e_path = "/",
+ .e_flags = NFSEXP_READONLY | NFSEXP_ROOTSQUASH
+ | NFSEXP_NOSUBTREECHECK | NFSEXP_FSID
+ | NFSEXP_V4ROOT,
+ .e_anonuid = 65534,
+ .e_anongid = 65534,
+ .e_squids = NULL,
+ .e_nsquids = 0,
+ .e_sqgids = NULL,
+ .e_nsqgids = 0,
+ .e_fsid = 0,
+ .e_mountpoint = NULL,
+ },
+ .m_exported = 0,
+ .m_xtabent = 1,
+ .m_mayexport = 1,
+ .m_changed = 0,
+ .m_warned = 0,
+};
+
+void set_pseudofs_security(struct exportent *pseudo, struct exportent *source)
+{
+ struct sec_entry *se;
+ int i;
+
+ if (source->e_flags & NFSEXP_INSECURE_PORT)
+ pseudo->e_flags |= NFSEXP_INSECURE_PORT;
+ for (se = source->e_secinfo; se->flav; se++) {
+ struct sec_entry *new;
+
+ i = secinfo_addflavor(se->flav, pseudo);
+ new = &pseudo->e_secinfo[i];
+
+ if (se->flags & NFSEXP_INSECURE_PORT)
+ new->flags |= NFSEXP_INSECURE_PORT;
+ }
+}
+
+/*
+ * Create a pseudo export
+ */
+static struct exportent *
+v4root_create(char *path, nfs_export *export)
+{
+ nfs_export *exp;
+ struct exportent eep;
+ struct exportent *curexp = &export->m_export;
+
+ dupexportent(&eep, &pseudo_root.m_export);
+ eep.e_hostname = strdup(curexp->e_hostname);
+ strncpy(eep.e_path, path, sizeof(eep.e_path));
+ if (strcmp(path, "/") != 0)
+ eep.e_flags &= ~NFSEXP_FSID;
+ set_pseudofs_security(&eep, curexp);
+ exp = export_create(&eep, 0);
+ if (exp == NULL)
+ return NULL;
+ xlog(D_CALL, "v4root_create: path '%s'", exp->m_export.e_path);
+ return &exp->m_export;
+}
+
+/*
+ * Make sure the kernel has pseudo root support.
+ */
+static int
+v4root_support(void)
+{
+ struct export_features *ef;
+ static int warned = 0;
+
+ ef = get_export_features();
+
+ if (ef->flags & NFSEXP_V4ROOT)
+ return 1;
+ if (!warned) {
+ xlog(L_WARNING, "Kernel does not have pseudo root support.");
+ xlog(L_WARNING, "NFS v4 mounts will be disabled unless fsid=0");
+ xlog(L_WARNING, "is specfied in /etc/exports file.");
+ warned++;
+ }
+ return 0;
+}
+
+int pseudofs_update(char *hostname, char *path, nfs_export *source)
+{
+ nfs_export *exp;
+
+ exp = export_lookup(hostname, path, 0);
+ if (exp && !(exp->m_export.e_flags & NFSEXP_V4ROOT))
+ return 0;
+ if (!exp) {
+ if (v4root_create(path, source) == NULL) {
+ xlog(L_WARNING, "v4root_set: Unable to create "
+ "pseudo export for '%s'", path);
+ return -ENOMEM;
+ }
+ return 0;
+ }
+ /* Update an existing V4ROOT export: */
+ set_pseudofs_security(&exp->m_export, &source->m_export);
+ return 0;
+}
+
+static int v4root_add_parents(nfs_export *exp)
+{
+ char *hostname = exp->m_export.e_hostname;
+ char *path;
+ char *ptr;
+
+ path = strdup(exp->m_export.e_path);
+ if (!path)
+ return -ENOMEM;
+ for (ptr = path + 1; ptr; ptr = strchr(ptr, '/')) {
+ int ret;
+ char saved;
+
+ saved = *ptr;
+ *ptr = '\0';
+ ret = pseudofs_update(hostname, path, exp);
+ if (ret)
+ return ret;
+ *ptr = saved;
+ ptr++;
+ }
+ free(path);
+ return 0;
+}
+
+/*
+ * Create pseudo exports by running through the real export
+ * looking at the components of the path that make up the export.
+ * Those path components, if not exported, will become pseudo
+ * exports allowing them to be found when the kernel does an upcall
+ * looking for components of the v4 mount.
+ */
+void
+v4root_set()
+{
+ nfs_export *exp;
+ int i, ret;
+
+ if (!v4root_needed)
+ return;
+ if (!v4root_support())
+ return;
+
+ for (i = 0; i < MCL_MAXTYPES; i++) {
+ for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
+ if (exp->m_export.e_flags & NFSEXP_V4ROOT)
+ /*
+ * We just added this one, so its
+ * parents are already dealt with!
+ */
+ continue;
+
+ ret = v4root_add_parents(exp);
+ /* XXX: error handling! */
+ }
+ }
+}
diff -up nfs-utils-1.2.1/utils/mount/mount.c.orig nfs-utils-1.2.1/utils/mount/mount.c
--- nfs-utils-1.2.1/utils/mount/mount.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/mount/mount.c 2010-01-14 03:53:55.455909069 -0500
@@ -593,6 +593,9 @@ int main(int argc, char *argv[])
if (mnt_err == EX_BG) {
printf(_("%s: backgrounding \"%s\"\n"),
progname, spec);
+ printf(_("%s: mount options: \"%s\"\n"),
+ progname, extra_opts);
+
fflush(stdout);
/*
diff -up nfs-utils-1.2.1/utils/mount/network.c.orig nfs-utils-1.2.1/utils/mount/network.c
--- nfs-utils-1.2.1/utils/mount/network.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/mount/network.c 2010-01-14 03:53:55.456899100 -0500
@@ -193,8 +193,18 @@ static const unsigned int *nfs_default_p
}
#endif /* MOUNT_CONFIG */
-static int nfs_lookup(const char *hostname, const sa_family_t family,
- struct sockaddr *sap, socklen_t *salen)
+/**
+ * nfs_lookup - resolve hostname to an IPv4 or IPv6 socket address
+ * @hostname: pointer to C string containing DNS hostname to resolve
+ * @family: address family hint
+ * @sap: pointer to buffer to fill with socket address
+ * @len: IN: size of buffer to fill; OUT: size of socket address
+ *
+ * Returns 1 and places a socket address at @sap if successful;
+ * otherwise zero.
+ */
+int nfs_lookup(const char *hostname, const sa_family_t family,
+ struct sockaddr *sap, socklen_t *salen)
{
struct addrinfo *gai_results;
struct addrinfo gai_hint = {
@@ -243,25 +253,6 @@ static int nfs_lookup(const char *hostna
}
/**
- * nfs_name_to_address - resolve hostname to an IPv4 or IPv6 socket address
- * @hostname: pointer to C string containing DNS hostname to resolve
- * @sap: pointer to buffer to fill with socket address
- * @len: IN: size of buffer to fill; OUT: size of socket address
- *
- * Returns 1 and places a socket address at @sap if successful;
- * otherwise zero.
- */
-int nfs_name_to_address(const char *hostname,
- struct sockaddr *sap, socklen_t *salen)
-{
-#ifdef IPV6_SUPPORTED
- return nfs_lookup(hostname, AF_UNSPEC, sap, salen);
-#else /* !IPV6_SUPPORTED */
- return nfs_lookup(hostname, AF_INET, sap, salen);
-#endif /* !IPV6_SUPPORTED */
-}
-
-/**
* nfs_gethostbyname - resolve a hostname to an IPv4 address
* @hostname: pointer to a C string containing a DNS hostname
* @sin: returns an IPv4 address
@@ -283,8 +274,8 @@ int nfs_gethostbyname(const char *hostna
* OUT: length of converted socket address
*
* Convert a presentation format address string to a socket address.
- * Similar to nfs_name_to_address(), but the DNS query is squelched,
- * and won't make any noise if the getaddrinfo() call fails.
+ * Similar to nfs_lookup(), but the DNS query is squelched, and it
+ * won't make any noise if the getaddrinfo() call fails.
*
* Returns 1 and fills in @sap and @salen if successful; otherwise zero.
*
@@ -1289,6 +1280,7 @@ nfs_nfs_version(struct mount_options *op
int
nfs_nfs_protocol(struct mount_options *options, unsigned long *protocol)
{
+ sa_family_t family;
char *option;
switch (po_rightmost(options, nfs_transport_opttbl)) {
@@ -1300,17 +1292,8 @@ nfs_nfs_protocol(struct mount_options *o
return 1;
case 2: /* proto */
option = po_get(options, "proto");
- if (option) {
- if (strcmp(option, "tcp") == 0) {
- *protocol = IPPROTO_TCP;
- return 1;
- }
- if (strcmp(option, "udp") == 0) {
- *protocol = IPPROTO_UDP;
- return 1;
- }
- return 0;
- }
+ if (option != NULL)
+ return nfs_get_proto(option, &family, protocol);
}
/*
@@ -1352,6 +1335,40 @@ nfs_nfs_port(struct mount_options *optio
}
/*
+ * Returns TRUE and fills in @family if a valid NFS protocol option
+ * is found, or FALSE if the option was specified with an invalid value.
+ */
+int nfs_nfs_proto_family(struct mount_options *options,
+ sa_family_t *family)
+{
+ unsigned long protocol;
+ char *option;
+
+#ifdef IPV6_SUPPORTED
+ *family = AF_UNSPEC;
+#else
+ *family = AF_INET;
+#endif
+
+ switch (po_rightmost(options, nfs_transport_opttbl)) {
+ case 0: /* udp */
+ return 1;
+ case 1: /* tcp */
+ return 1;
+ case 2: /* proto */
+ option = po_get(options, "proto");
+ if (option != NULL)
+ return nfs_get_proto(option, family, &protocol);
+ }
+
+ /*
+ * NFS transport protocol wasn't specified. Return the
+ * default address family.
+ */
+ return 1;
+}
+
+/*
* "mountprog" is supported only by the legacy mount command. The
* kernel mount client does not support this option.
*
@@ -1419,20 +1436,12 @@ nfs_mount_version(struct mount_options *
static int
nfs_mount_protocol(struct mount_options *options, unsigned long *protocol)
{
+ sa_family_t family;
char *option;
option = po_get(options, "mountproto");
- if (option) {
- if (strcmp(option, "tcp") == 0) {
- *protocol = IPPROTO_TCP;
- return 1;
- }
- if (strcmp(option, "udp") == 0) {
- *protocol = IPPROTO_UDP;
- return 1;
- }
- return 0;
- }
+ if (option != NULL)
+ return nfs_get_proto(option, &family, protocol);
/*
* MNT transport protocol wasn't specified. If the NFS
@@ -1472,6 +1481,35 @@ nfs_mount_port(struct mount_options *opt
return 1;
}
+/*
+ * Returns TRUE and fills in @family if a valid MNT protocol option
+ * is found, or FALSE if the option was specified with an invalid value.
+ */
+int nfs_mount_proto_family(struct mount_options *options,
+ sa_family_t *family)
+{
+ unsigned long protocol;
+ char *option;
+
+#ifdef HAVE_LIBTIRPC
+ *family = AF_UNSPEC;
+#else
+ *family = AF_INET;
+#endif
+
+ option = po_get(options, "mountproto");
+ if (option != NULL)
+ return nfs_get_proto(option, family, &protocol);
+
+ /*
+ * MNT transport protocol wasn't specified. If the NFS
+ * transport protocol was specified, derive the family
+ * from that; otherwise, return the default family for
+ * NFS.
+ */
+ return nfs_nfs_proto_family(options, family);
+}
+
/**
* nfs_options2pmap - set up pmap structs based on mount options
* @options: pointer to mount options
diff -up nfs-utils-1.2.1/utils/mount/network.h.orig nfs-utils-1.2.1/utils/mount/network.h
--- nfs-utils-1.2.1/utils/mount/network.h.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/mount/network.h 2010-01-14 03:53:55.456899100 -0500
@@ -44,7 +44,8 @@ int nfs_probe_bothports(const struct soc
struct pmap *, const struct sockaddr *,
const socklen_t, struct pmap *);
int nfs_gethostbyname(const char *, struct sockaddr_in *);
-int nfs_name_to_address(const char *, struct sockaddr *, socklen_t *);
+int nfs_lookup(const char *hostname, const sa_family_t family,
+ struct sockaddr *sap, socklen_t *salen);
int nfs_string_to_sockaddr(const char *, struct sockaddr *, socklen_t *);
int nfs_present_sockaddr(const struct sockaddr *,
const socklen_t, char *, const size_t);
@@ -56,6 +57,8 @@ int clnt_ping(struct sockaddr_in *, cons
struct mount_options;
+int nfs_nfs_proto_family(struct mount_options *options, sa_family_t *family);
+int nfs_mount_proto_family(struct mount_options *options, sa_family_t *family);
int nfs_nfs_version(struct mount_options *options, unsigned long *version);
int nfs_nfs_protocol(struct mount_options *options, unsigned long *protocol);
diff -up nfs-utils-1.2.1/utils/mount/nfs4mount.c.orig nfs-utils-1.2.1/utils/mount/nfs4mount.c
--- nfs-utils-1.2.1/utils/mount/nfs4mount.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/mount/nfs4mount.c 2010-01-14 03:53:55.458888689 -0500
@@ -217,8 +217,11 @@ int nfs4mount(const char *spec, const ch
progname);
goto fail;
}
- snprintf(new_opts, sizeof(new_opts), "%s%saddr=%s",
- old_opts, *old_opts ? "," : "", s);
+ if (running_bg)
+ strncpy(new_opts, old_opts, sizeof(new_opts));
+ else
+ snprintf(new_opts, sizeof(new_opts), "%s%saddr=%s",
+ old_opts, *old_opts ? "," : "", s);
*extra_opts = xstrdup(new_opts);
/* Set default options.
@@ -434,15 +437,17 @@ int nfs4mount(const char *spec, const ch
break;
}
- switch(rpc_createerr.cf_stat){
- case RPC_TIMEDOUT:
- break;
- case RPC_SYSTEMERROR:
- if (errno == ETIMEDOUT)
+ if (!bg) {
+ switch(rpc_createerr.cf_stat) {
+ case RPC_TIMEDOUT:
break;
- default:
- rpc_mount_errors(hostname, 0, bg);
- goto fail;
+ case RPC_SYSTEMERROR:
+ if (errno == ETIMEDOUT)
+ break;
+ default:
+ rpc_mount_errors(hostname, 0, bg);
+ goto fail;
+ }
}
if (bg && !running_bg) {
diff -up nfs-utils-1.2.1/utils/mount/nfs.man.orig nfs-utils-1.2.1/utils/mount/nfs.man
--- nfs-utils-1.2.1/utils/mount/nfs.man.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/mount/nfs.man 2010-01-14 03:53:55.457909473 -0500
@@ -58,9 +58,17 @@ The server's hostname and export pathnam
are separated by a colon, while
the mount options are separated by commas. The remaining fields
are separated by blanks or tabs.
+.P
The server's hostname can be an unqualified hostname,
a fully qualified domain name,
-or a dotted quad IPv4 address.
+a dotted quad IPv4 address, or
+an IPv6 address enclosed in square brackets.
+Link-local and site-local IPv6 addresses must be accompanied by an
+interface identifier.
+See
+.BR ipv6 (7)
+for details on specifying raw IPv6 addresses.
+.P
The
.I fstype
field contains either "nfs" (for version 2 or version 3 NFS mounts)
@@ -470,32 +478,38 @@ for mounting the
.B nfs
file system type.
.TP 1.5i
-.BI proto= transport
-The transport the NFS client uses
+.BI proto= netid
+The transport protocol name and protocol family the NFS client uses
to transmit requests to the NFS server for this mount point.
-.I transport
-can be either
-.B udp
-or
-.BR tcp .
-Each transport uses different default
+If an NFS server has both an IPv4 and an IPv6 address, using a specific
+netid will force the use of IPv4 or IPv6 networking to communicate
+with that server.
+.IP
+If support for TI-RPC is built into the
+.B mount.nfs
+command,
+.I netid
+is a valid netid listed in
+.IR /etc/netconfig .
+Otherwise,
+.I netid
+is one of "tcp," "udp," or "rdma," and only IPv4 may be used.
+.IP
+Each transport protocol uses different default
.B retrans
and
.B timeo
-settings; refer to the description of these two mount options for details.
+settings.
+Refer to the description of these two mount options for details.
.IP
In addition to controlling how the NFS client transmits requests to
the server, this mount option also controls how the
.BR mount (8)
command communicates with the server's rpcbind and mountd services.
-Specifying
-.B proto=tcp
-forces all traffic from the
+Specifying a netid that uses TCP forces all traffic from the
.BR mount (8)
command and the NFS client to use TCP.
-Specifying
-.B proto=udp
-forces all traffic types to use UDP.
+Specifying a netid that uses UDP forces all traffic types to use UDP.
.IP
If the
.B proto
@@ -548,15 +562,20 @@ or the server's mountd service is not av
This option can be used when mounting an NFS server
through a firewall that blocks the rpcbind protocol.
.TP 1.5i
-.BI mountproto= transport
-The transport the NFS client uses
+.BI mountproto= netid
+The transport protocol name and protocol family 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 transport
-can be either
-.B udp
-or
-.BR tcp .
+.IP
+If support for TI-RPC is built into the
+.B mount.nfs
+command,
+.I netid
+is a valid netid listed in
+.IR /etc/netconfig .
+Otherwise,
+.I netid
+is one of "tcp" or "udp," and only IPv4 may be used.
.IP
This option can be used when mounting an NFS server
through a firewall that blocks a particular transport.
@@ -566,6 +585,7 @@ option, different transports for mountd
can be specified.
If the server's mountd service is not available via the specified
transport, the mount request fails.
+.IP
Refer to the TRANSPORT METHODS section for more on how the
.B mountproto
mount option interacts with the
@@ -709,17 +729,26 @@ for mounting the
.B nfs4
file system type.
.TP 1.5i
-.BI proto= transport
-The transport the NFS client uses
+.BI proto= netid
+The transport protocol name and protocol family the NFS client uses
to transmit requests to the NFS server for this mount point.
-.I transport
-can be either
-.B udp
-or
-.BR tcp .
+If an NFS server has both an IPv4 and an IPv6 address, using a specific
+netid will force the use of IPv4 or IPv6 networking to communicate
+with that server.
+.IP
+If support for TI-RPC is built into the
+.B mount.nfs
+command,
+.I netid
+is a valid netid listed in
+.IR /etc/netconfig .
+Otherwise,
+.I netid
+is one of "tcp" or "udp," and only IPv4 may be used.
+.IP
All NFS version 4 servers are required to support TCP,
so if this mount option is not specified, the NFS version 4 client
-uses the TCP transport protocol.
+uses the TCP protocol.
Refer to the TRANSPORT METHODS section for more details.
.TP 1.5i
.BI port= n
@@ -779,7 +808,8 @@ The DATA AND METADATA COHERENCE section
the behavior of this option in more detail.
.TP 1.5i
.BI clientaddr= n.n.n.n
-Specifies a single IPv4 address (in dotted-quad form)
+Specifies a single IPv4 address (in dotted-quad form),
+or a non-link-local IPv6 address,
that the NFS client advertises to allow servers
to perform NFS version 4 callback requests against
files on this mount point. If the server is unable to
@@ -855,6 +885,14 @@ This example can be used to mount /usr o
.TA 2.5i +0.7i +0.7i +.7i
server:/export /usr nfs ro,nolock,nocto,actimeo=3600 0 0
.FI
+.P
+This example shows how to mount an NFS server
+using a raw IPv6 link-local address.
+.P
+.NF
+.TA 2.5i +0.7i +0.7i +.7i
+ [fe80::215:c5ff:fb3e:e2b1%eth0]:/export /mnt nfs defaults 0 0
+.FI
.SH "TRANSPORT METHODS"
NFS clients send requests to NFS servers via
Remote Procedure Calls, or
@@ -1498,6 +1536,8 @@ such as security negotiation, server ref
.BR mount.nfs (5),
.BR umount.nfs (5),
.BR exports (5),
+.BR netconfig (5),
+.BR ipv6 (7),
.BR nfsd (8),
.BR sm-notify (8),
.BR rpc.statd (8),
diff -up nfs-utils-1.2.1/utils/mount/nfsmount.c.orig nfs-utils-1.2.1/utils/mount/nfsmount.c
--- nfs-utils-1.2.1/utils/mount/nfsmount.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/mount/nfsmount.c 2010-01-14 03:53:55.459818043 -0500
@@ -170,7 +170,7 @@ parse_options(char *old_opts, struct nfs
struct pmap *mnt_pmap = &mnt_server->pmap;
struct pmap *nfs_pmap = &nfs_server->pmap;
int len;
- char *opt, *opteq, *p, *opt_b;
+ char *opt, *opteq, *p, *opt_b, *tmp_opts;
char *mounthost = NULL;
char cbuf[128];
int open_quote = 0;
@@ -179,7 +179,8 @@ parse_options(char *old_opts, struct nfs
*bg = 0;
len = strlen(new_opts);
- for (p=old_opts, opt_b=NULL; p && *p; p++) {
+ tmp_opts = xstrdup(old_opts);
+ for (p=tmp_opts, opt_b=NULL; p && *p; p++) {
if (!opt_b)
opt_b = p; /* begin of the option item */
if (*p == '"')
@@ -457,10 +458,12 @@ parse_options(char *old_opts, struct nfs
goto out_bad;
*mnt_server->hostname = mounthost;
}
+ free(tmp_opts);
return 1;
bad_parameter:
nfs_error(_("%s: Bad nfs mount parameter: %s\n"), progname, opt);
out_bad:
+ free(tmp_opts);
return 0;
}
diff -up nfs-utils-1.2.1/utils/mount/nfsumount.c.orig nfs-utils-1.2.1/utils/mount/nfsumount.c
--- nfs-utils-1.2.1/utils/mount/nfsumount.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/mount/nfsumount.c 2010-01-14 03:53:55.460908972 -0500
@@ -169,10 +169,15 @@ out:
static int nfs_umount_do_umnt(struct mount_options *options,
char **hostname, char **dirname)
{
- struct sockaddr_storage address;
- struct sockaddr *sap = (struct sockaddr *)&address;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in s4;
+ struct sockaddr_in6 s6;
+ } address;
+ struct sockaddr *sap = &address.sa;
socklen_t salen = sizeof(address);
struct pmap nfs_pmap, mnt_pmap;
+ sa_family_t family;
if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap)) {
nfs_error(_("%s: bad mount options"), progname);
@@ -189,8 +194,10 @@ static int nfs_umount_do_umnt(struct mou
return EX_FAIL;
}
- if (nfs_name_to_address(*hostname, sap, &salen) == 0)
- /* nfs_name_to_address reports any errors */
+ if (!nfs_mount_proto_family(options, &family))
+ return 0;
+ if (!nfs_lookup(*hostname, family, sap, &salen))
+ /* nfs_lookup reports any errors */
return EX_FAIL;
if (nfs_advise_umount(sap, salen, &mnt_pmap, dirname) == 0)
diff -up nfs-utils-1.2.1/utils/mount/stropts.c.orig nfs-utils-1.2.1/utils/mount/stropts.c
--- nfs-utils-1.2.1/utils/mount/stropts.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/mount/stropts.c 2010-01-14 03:53:55.461898931 -0500
@@ -38,6 +38,7 @@
#include "xcommon.h"
#include "mount.h"
#include "nls.h"
+#include "nfsrpc.h"
#include "mount_constants.h"
#include "stropts.h"
#include "error.h"
@@ -76,12 +77,18 @@ extern char *progname;
extern int verbose;
extern int sloppy;
+union nfs_sockaddr {
+ struct sockaddr sa;
+ struct sockaddr_in s4;
+ struct sockaddr_in6 s6;
+};
+
struct nfsmount_info {
const char *spec, /* server:/path */
*node, /* mounted-on dir */
*type; /* "nfs" or "nfs4" */
char *hostname; /* server's hostname */
- struct sockaddr_storage address; /* server's address */
+ union nfs_sockaddr address;
socklen_t salen; /* size of server's address */
struct mount_options *options; /* parsed mount options */
@@ -204,9 +211,9 @@ static int nfs_append_clientaddr_option(
socklen_t salen,
struct mount_options *options)
{
- struct sockaddr_storage dummy;
- struct sockaddr *my_addr = (struct sockaddr *)&dummy;
- socklen_t my_len = sizeof(dummy);
+ union nfs_sockaddr address;
+ struct sockaddr *my_addr = &address.sa;
+ socklen_t my_len = sizeof(address);
if (po_contains(options, "clientaddr") == PO_FOUND)
return 1;
@@ -218,21 +225,33 @@ static int nfs_append_clientaddr_option(
}
/*
- * Resolve the 'mounthost=' hostname and append a new option using
- * the resulting address.
+ * Determine whether to append a 'mountaddr=' option. The option is needed if:
+ *
+ * 1. "mounthost=" was specified, or
+ * 2. The address families for proto= and mountproto= are different.
*/
-static int nfs_fix_mounthost_option(struct mount_options *options)
+static int nfs_fix_mounthost_option(struct mount_options *options,
+ const char *nfs_hostname)
{
- struct sockaddr_storage dummy;
- struct sockaddr *sap = (struct sockaddr *)&dummy;
- socklen_t salen = sizeof(dummy);
+ union nfs_sockaddr address;
+ struct sockaddr *sap = &address.sa;
+ socklen_t salen = sizeof(address);
+ sa_family_t nfs_family, mnt_family;
char *mounthost;
+ if (!nfs_nfs_proto_family(options, &nfs_family))
+ return 0;
+ if (!nfs_mount_proto_family(options, &mnt_family))
+ return 0;
+
mounthost = po_get(options, "mounthost");
- if (!mounthost)
- return 1;
+ if (mounthost == NULL) {
+ if (nfs_family == mnt_family)
+ return 1;
+ mounthost = (char *)nfs_hostname;
+ }
- if (!nfs_name_to_address(mounthost, sap, &salen)) {
+ if (!nfs_lookup(mounthost, mnt_family, sap, &salen)) {
nfs_error(_("%s: unable to determine mount server's address"),
progname);
return 0;
@@ -319,13 +338,16 @@ static int nfs_set_version(struct nfsmou
*/
static int nfs_validate_options(struct nfsmount_info *mi)
{
- struct sockaddr *sap = (struct sockaddr *)&mi->address;
+ struct sockaddr *sap = &mi->address.sa;
+ sa_family_t family;
if (!nfs_parse_devname(mi->spec, &mi->hostname, NULL))
return 0;
+ if (!nfs_nfs_proto_family(mi->options, &family))
+ return 0;
mi->salen = sizeof(mi->address);
- if (!nfs_name_to_address(mi->hostname, sap, &mi->salen))
+ if (!nfs_lookup(mi->hostname, family, sap, &mi->salen))
return 0;
if (!nfs_set_version(mi))
@@ -371,10 +393,13 @@ static int nfs_extract_server_addresses(
}
static int nfs_construct_new_options(struct mount_options *options,
+ struct sockaddr *nfs_saddr,
struct pmap *nfs_pmap,
+ struct sockaddr *mnt_saddr,
struct pmap *mnt_pmap)
{
char new_option[64];
+ char *netid;
po_remove_all(options, "nfsprog");
po_remove_all(options, "mountprog");
@@ -391,20 +416,14 @@ static int nfs_construct_new_options(str
po_remove_all(options, "proto");
po_remove_all(options, "udp");
po_remove_all(options, "tcp");
- switch (nfs_pmap->pm_prot) {
- case IPPROTO_TCP:
- snprintf(new_option, sizeof(new_option) - 1,
- "proto=tcp");
- if (po_append(options, new_option) == PO_FAILED)
- return 0;
- break;
- case IPPROTO_UDP:
- snprintf(new_option, sizeof(new_option) - 1,
- "proto=udp");
- if (po_append(options, new_option) == PO_FAILED)
- return 0;
- break;
- }
+ netid = nfs_get_netid(nfs_saddr->sa_family, nfs_pmap->pm_prot);
+ if (netid == NULL)
+ return 0;
+ snprintf(new_option, sizeof(new_option) - 1,
+ "proto=%s", netid);
+ free(netid);
+ if (po_append(options, new_option) == PO_FAILED)
+ return 0;
po_remove_all(options, "port");
if (nfs_pmap->pm_port != NFS_PORT) {
@@ -421,20 +440,14 @@ static int nfs_construct_new_options(str
return 0;
po_remove_all(options, "mountproto");
- switch (mnt_pmap->pm_prot) {
- case IPPROTO_TCP:
- snprintf(new_option, sizeof(new_option) - 1,
- "mountproto=tcp");
- if (po_append(options, new_option) == PO_FAILED)
- return 0;
- break;
- case IPPROTO_UDP:
- snprintf(new_option, sizeof(new_option) - 1,
- "mountproto=udp");
- if (po_append(options, new_option) == PO_FAILED)
- return 0;
- break;
- }
+ netid = nfs_get_netid(mnt_saddr->sa_family, mnt_pmap->pm_prot);
+ if (netid == NULL)
+ return 0;
+ snprintf(new_option, sizeof(new_option) - 1,
+ "mountproto=%s", netid);
+ free(netid);
+ if (po_append(options, new_option) == PO_FAILED)
+ return 0;
po_remove_all(options, "mountport");
snprintf(new_option, sizeof(new_option) - 1,
@@ -461,12 +474,12 @@ static int nfs_construct_new_options(str
static int
nfs_rewrite_pmap_mount_options(struct mount_options *options)
{
- struct sockaddr_storage nfs_address;
- struct sockaddr *nfs_saddr = (struct sockaddr *)&nfs_address;
+ union nfs_sockaddr nfs_address;
+ struct sockaddr *nfs_saddr = &nfs_address.sa;
socklen_t nfs_salen = sizeof(nfs_address);
struct pmap nfs_pmap;
- struct sockaddr_storage mnt_address;
- struct sockaddr *mnt_saddr = (struct sockaddr *)&mnt_address;
+ union nfs_sockaddr mnt_address;
+ struct sockaddr *mnt_saddr = &mnt_address.sa;
socklen_t mnt_salen = sizeof(mnt_address);
struct pmap mnt_pmap;
char *option;
@@ -510,7 +523,8 @@ nfs_rewrite_pmap_mount_options(struct mo
return 0;
}
- if (!nfs_construct_new_options(options, &nfs_pmap, &mnt_pmap)) {
+ if (!nfs_construct_new_options(options, nfs_saddr, &nfs_pmap,
+ mnt_saddr, &mnt_pmap)) {
errno = EINVAL;
return 0;
}
@@ -566,7 +580,7 @@ static int nfs_try_mount_v3v2(struct nfs
return result;
}
- if (!nfs_fix_mounthost_option(options)) {
+ if (!nfs_fix_mounthost_option(options, mi->hostname)) {
errno = EINVAL;
goto out_fail;
}
@@ -601,7 +615,7 @@ out_fail:
*/
static int nfs_try_mount_v4(struct nfsmount_info *mi)
{
- struct sockaddr *sap = (struct sockaddr *)&mi->address;
+ struct sockaddr *sap = &mi->address.sa;
struct mount_options *options = po_dup(mi->options);
int result = 0;
@@ -611,6 +625,18 @@ static int nfs_try_mount_v4(struct nfsmo
}
if (mi->version == 0) {
+ if (po_contains(options, "mounthost") ||
+ po_contains(options, "mountaddr") ||
+ po_contains(options, "mountvers") ||
+ po_contains(options, "mountproto")) {
+ /*
+ * Since these mountd options are set assume version 3
+ * is wanted so error out with EPROTONOSUPPORT so the
+ * protocol negation starts with v3.
+ */
+ errno = EPROTONOSUPPORT;
+ goto out_fail;
+ }
if (po_append(options, "vers=4") == PO_FAILED) {
errno = EINVAL;
goto out_fail;
@@ -656,9 +682,10 @@ static int nfs_try_mount(struct nfsmount
/*
* To deal with legacy Linux servers that don't
* automatically export a pseudo root, retry
- * ENOENT errors using version 3
+ * ENOENT errors using version 3. And for
+ * Linux servers prior to 2.6.25, retry EPERM
*/
- if (errno != ENOENT)
+ if (errno != ENOENT && errno != EPERM)
break;
}
}
diff -up nfs-utils-1.2.1/utils/nfsd/nfssvc.c.orig nfs-utils-1.2.1/utils/nfsd/nfssvc.c
--- nfs-utils-1.2.1/utils/nfsd/nfssvc.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/nfsd/nfssvc.c 2010-01-14 03:53:55.465872101 -0500
@@ -212,7 +212,7 @@ int
nfssvc_set_sockets(const int family, const unsigned int protobits,
const char *host, const char *port)
{
- struct addrinfo hints = { .ai_flags = AI_PASSIVE | AI_ADDRCONFIG };
+ struct addrinfo hints = { .ai_flags = AI_PASSIVE };
hints.ai_family = family;
diff -up nfs-utils-1.2.1/utils/showmount/showmount.c.orig nfs-utils-1.2.1/utils/showmount/showmount.c
--- nfs-utils-1.2.1/utils/showmount/showmount.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/showmount/showmount.c 2010-01-14 03:53:55.466899193 -0500
@@ -78,29 +78,36 @@ static void usage(FILE *fp, int n)
exit(n);
}
-static const char *nfs_sm_pgmtbl[] = {
+static const char *mount_pgm_tbl[] = {
"showmount",
"mount",
"mountd",
NULL,
};
+static const rpcvers_t mount_vers_tbl[] = {
+ MOUNTVERS_NFSV3,
+ MOUNTVERS_POSIX,
+ MOUNTVERS,
+};
+static const unsigned int max_vers_tblsz =
+ (sizeof(mount_vers_tbl)/sizeof(mount_vers_tbl[0]));
+
/*
* Generate an RPC client handle connected to the mountd service
* at @hostname, or die trying.
*
* Supports both AF_INET and AF_INET6 server addresses.
*/
-static CLIENT *nfs_get_mount_client(const char *hostname)
+static CLIENT *nfs_get_mount_client(const char *hostname, rpcvers_t vers)
{
- rpcprog_t program = nfs_getrpcbyname(MOUNTPROG, nfs_sm_pgmtbl);
+ rpcprog_t program = nfs_getrpcbyname(MOUNTPROG, mount_pgm_tbl);
CLIENT *client;
- client = clnt_create(hostname, program, MOUNTVERS, "tcp");
+ client = clnt_create(hostname, program, vers, "tcp");
if (client)
return client;
-
- client = clnt_create(hostname, program, MOUNTVERS, "udp");
+ client = clnt_create(hostname, program, vers, "udp");
if (client)
return client;
@@ -123,6 +130,7 @@ int main(int argc, char **argv)
int i;
int n;
int maxlen;
+ int unsigned vers=0;
char **dumpv;
program_name = argv[0];
@@ -185,11 +193,12 @@ int main(int argc, char **argv)
break;
}
- mclient = nfs_get_mount_client(hostname);
+ mclient = nfs_get_mount_client(hostname, mount_vers_tbl[vers]);
mclient->cl_auth = authunix_create_default();
total_timeout.tv_sec = TOTAL_TIMEOUT;
total_timeout.tv_usec = 0;
+again:
if (eflag) {
memset(&exportlist, '\0', sizeof(exportlist));
@@ -197,6 +206,13 @@ int main(int argc, char **argv)
(xdrproc_t) xdr_void, NULL,
(xdrproc_t) xdr_exports, (caddr_t) &exportlist,
total_timeout);
+ if (clnt_stat == RPC_PROGVERSMISMATCH) {
+ if (++vers < max_vers_tblsz) {
+ (void)CLNT_CONTROL(mclient, CLSET_VERS,
+ (void *)&mount_vers_tbl[vers]);
+ goto again;
+ }
+ }
if (clnt_stat != RPC_SUCCESS) {
clnt_perror(mclient, "rpc mount export");
clnt_destroy(mclient);
@@ -232,6 +248,13 @@ int main(int argc, char **argv)
(xdrproc_t) xdr_void, NULL,
(xdrproc_t) xdr_mountlist, (caddr_t) &dumplist,
total_timeout);
+ if (clnt_stat == RPC_PROGVERSMISMATCH) {
+ if (++vers < max_vers_tblsz) {
+ (void)CLNT_CONTROL(mclient, CLSET_VERS,
+ (void *)&mount_vers_tbl[vers]);
+ goto again;
+ }
+ }
if (clnt_stat != RPC_SUCCESS) {
clnt_perror(mclient, "rpc mount dump");
clnt_destroy(mclient);
diff -up nfs-utils-1.2.1/utils/statd/callback.c.orig nfs-utils-1.2.1/utils/statd/callback.c
--- nfs-utils-1.2.1/utils/statd/callback.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/statd/callback.c 2010-01-14 03:53:55.467921698 -0500
@@ -35,12 +35,12 @@ sm_notify_1_svc(struct stat_chge *argp,
struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt);
char *ip_addr = xstrdup(inet_ntoa(sin->sin_addr));
- dprintf(N_DEBUG, "Received SM_NOTIFY from %s, state: %d",
+ xlog(D_CALL, "Received SM_NOTIFY from %s, state: %d",
argp->mon_name, argp->state);
/* quick check - don't bother if we're not monitoring anyone */
if (rtnl == NULL) {
- note(N_WARNING, "SM_NOTIFY from %s while not monitoring any hosts.",
+ xlog_warn("SM_NOTIFY from %s while not monitoring any hosts",
argp->mon_name);
return ((void *) &result);
}
diff -up nfs-utils-1.2.1/utils/statd/Makefile.am.orig nfs-utils-1.2.1/utils/statd/Makefile.am
--- nfs-utils-1.2.1/utils/statd/Makefile.am.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/statd/Makefile.am 2010-01-14 03:53:55.467921698 -0500
@@ -2,31 +2,26 @@
man8_MANS = statd.man sm-notify.man
-GENFILES_CLNT = sm_inter_clnt.c
-GENFILES_SVC = sm_inter_svc.c
-GENFILES_XDR = sm_inter_xdr.c
-GENFILES_H = sm_inter.h
-
-GENFILES = $(GENFILES_CLNT) $(GENFILES_SVC) $(GENFILES_XDR) $(GENFILES_H)
-
RPCPREFIX = rpc.
KPREFIX = @kprefix@
sbin_PROGRAMS = statd sm-notify
dist_sbin_SCRIPTS = start-statd
-statd_SOURCES = callback.c notlist.c log.c misc.c monitor.c \
+statd_SOURCES = callback.c notlist.c misc.c monitor.c \
simu.c stat.c statd.c svc_run.c rmtcall.c \
- sm_inter_clnt.c sm_inter_svc.c sm_inter_xdr.c log.h \
- notlist.h statd.h system.h version.h sm_inter.h
+ notlist.h statd.h system.h version.h
sm_notify_SOURCES = sm-notify.c
BUILT_SOURCES = $(GENFILES)
statd_LDADD = ../../support/export/libexport.a \
+ ../../support/nsm/libnsm.a \
../../support/nfs/libnfs.a \
../../support/misc/libmisc.a \
$(LIBWRAP) $(LIBNSL)
-sm_notify_LDADD = $(LIBNSL)
+sm_notify_LDADD = ../../support/nsm/libnsm.a \
+ ../../support/nfs/libnfs.a \
+ $(LIBNSL)
-EXTRA_DIST = sim_sm_inter.x sm_inter.x $(man8_MANS) COPYRIGHT simulate.c
+EXTRA_DIST = sim_sm_inter.x $(man8_MANS) COPYRIGHT simulate.c
if CONFIG_RPCGEN
RPCGEN = $(top_builddir)/tools/rpcgen/rpcgen
diff -up nfs-utils-1.2.1/utils/statd/misc.c.orig nfs-utils-1.2.1/utils/statd/misc.c
--- nfs-utils-1.2.1/utils/statd/misc.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/statd/misc.c 2010-01-14 03:53:55.468909425 -0500
@@ -29,8 +29,7 @@ xmalloc (size_t size)
return ((void *)NULL);
if (!(ptr = malloc (size)))
- /* SHIT! SHIT! SHIT! */
- die ("malloc failed");
+ xlog_err ("malloc failed");
return (ptr);
}
@@ -46,32 +45,7 @@ xstrdup (const char *string)
/* Will only fail if underlying malloc() fails (ENOMEM). */
if (!(result = strdup (string)))
- die ("strdup failed");
+ xlog_err ("strdup failed");
return (result);
}
-
-
-/*
- * Unlinking a file.
- */
-void
-xunlink (char *path, char *host)
-{
- char *tozap;
-
- tozap = malloc(strlen(path)+strlen(host)+2);
- if (tozap == NULL) {
- note(N_ERROR, "xunlink: malloc failed: errno %d (%s)",
- errno, strerror(errno));
- return;
- }
- sprintf (tozap, "%s/%s", path, host);
-
- if (unlink (tozap) == -1)
- note(N_ERROR, "unlink (%s): %s", tozap, strerror (errno));
- else
- dprintf (N_DEBUG, "Unlinked %s", tozap);
-
- free(tozap);
-}
diff -up nfs-utils-1.2.1/utils/statd/monitor.c.orig nfs-utils-1.2.1/utils/statd/monitor.c
--- nfs-utils-1.2.1/utils/statd/monitor.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/statd/monitor.c 2010-01-14 03:53:55.469889080 -0500
@@ -23,14 +23,13 @@
#include "rpcmisc.h"
#include "misc.h"
+#include "nsm.h"
#include "statd.h"
#include "notlist.h"
#include "ha-callout.h"
notify_list * rtnl = NULL; /* Run-time notify list. */
-#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.
@@ -43,8 +42,7 @@ caller_is_localhost(struct svc_req *rqst
caller = sin->sin_addr;
if (caller.s_addr != htonl(INADDR_LOOPBACK)) {
- note(N_WARNING,
- "Call to statd from non-local host %s",
+ xlog_warn("Call to statd from non-local host %s",
inet_ntoa(caller));
return 0;
}
@@ -61,14 +59,17 @@ sm_mon_1_svc(struct mon *argp, struct sv
char *mon_name = argp->mon_id.mon_name,
*my_name = argp->mon_id.my_id.my_name;
struct my_id *id = &argp->mon_id.my_id;
- char *path;
char *cp;
- int fd;
notify_list *clnt;
- struct in_addr my_addr;
+ struct sockaddr_in my_addr = {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
+ };
char *dnsname;
struct hostent *hostinfo = NULL;
+ xlog(D_CALL, "Received SM_MON for %s from %s", mon_name, my_name);
+
/* Assume that we'll fail. */
result.res_stat = STAT_FAIL;
result.state = -1; /* State is undefined for STAT_FAIL. */
@@ -79,7 +80,6 @@ sm_mon_1_svc(struct mon *argp, struct sv
*/
if (!caller_is_localhost(rqstp))
goto failure;
- my_addr.s_addr = htonl(INADDR_LOOPBACK);
/* 2. Reject any registrations for non-lockd services.
*
@@ -92,8 +92,7 @@ sm_mon_1_svc(struct mon *argp, struct sv
if (id->my_prog != 100021 ||
(id->my_proc != 16 && id->my_proc != 24))
{
- note(N_WARNING,
- "Attempt to register callback to %d/%d",
+ xlog_warn("Attempt to register callback to %d/%d",
id->my_prog, id->my_proc);
goto failure;
}
@@ -105,12 +104,12 @@ sm_mon_1_svc(struct mon *argp, struct sv
/* must check for /'s in hostname! See CERT's CA-96.09 for details. */
if (strchr(mon_name, '/') || mon_name[0] == '.') {
- note(N_CRIT, "SM_MON request for hostname containing '/' "
+ xlog(L_ERROR, "SM_MON request for hostname containing '/' "
"or starting '.': %s", mon_name);
- note(N_CRIT, "POSSIBLE SPOOF/ATTACK ATTEMPT!");
+ xlog(L_ERROR, "POSSIBLE SPOOF/ATTACK ATTEMPT!");
goto failure;
} else if ((hostinfo = gethostbyname(mon_name)) == NULL) {
- note(N_WARNING, "gethostbyname error for %s", mon_name);
+ xlog_warn("gethostbyname error for %s", mon_name);
goto failure;
}
@@ -152,7 +151,7 @@ sm_mon_1_svc(struct mon *argp, struct sv
NL_MY_VERS(clnt) == id->my_vers &&
memcmp(NL_PRIV(clnt), argp->priv, SM_PRIV_SIZE) == 0) {
/* Hey! We already know you guys! */
- dprintf(N_DEBUG,
+ xlog(D_GENERAL,
"Duplicate SM_MON request for %s "
"from procedure on %s",
mon_name, my_name);
@@ -168,11 +167,11 @@ sm_mon_1_svc(struct mon *argp, struct sv
* doesn't fail. (I should probably fix this assumption.)
*/
if (!(clnt = nlist_new(my_name, mon_name, 0))) {
- note(N_WARNING, "out of memory");
+ xlog_warn("out of memory");
goto failure;
}
- NL_ADDR(clnt) = my_addr;
+ NL_ADDR(clnt) = my_addr.sin_addr;
NL_MY_PROG(clnt) = id->my_prog;
NL_MY_VERS(clnt) = id->my_vers;
NL_MY_PROC(clnt) = id->my_proc;
@@ -182,40 +181,16 @@ sm_mon_1_svc(struct mon *argp, struct sv
/*
* Now, Create file on stable storage for host.
*/
-
- path=xmalloc(strlen(SM_DIR)+strlen(dnsname)+2);
- sprintf(path, "%s/%s", SM_DIR, dnsname);
- if ((fd = open(path, O_WRONLY|O_SYNC|O_CREAT|O_APPEND,
- S_IRUSR|S_IWUSR)) < 0) {
- /* Didn't fly. We won't monitor. */
- note(N_ERROR, "creat(%s) failed: %s", path, strerror (errno));
+ if (!nsm_insert_monitored_host(dnsname,
+ (struct sockaddr *)(char *)&my_addr, argp)) {
nlist_free(NULL, clnt);
- free(path);
goto failure;
}
- {
- char buf[LINELEN + 1 + SM_MAXSTRLEN*2 + 4];
- char *e;
- int i;
- e = buf + sprintf(buf, "%08x %08x %08x %08x ",
- my_addr.s_addr, id->my_prog,
- id->my_vers, id->my_proc);
- for (i=0; i<SM_PRIV_SIZE; i++)
- e += sprintf(e, "%02x", 0xff & (argp->priv[i]));
- if (e+1-buf != LINELEN) abort();
- e += sprintf(e, " %s %s\n", mon_name, my_name);
- if (write(fd, buf, e-buf) != (e-buf)) {
- note(N_WARNING, "writing to %s failed: errno %d (%s)",
- path, errno, strerror(errno));
- }
- }
- free(path);
/* PRC: do the HA callout: */
ha_callout("add-client", mon_name, my_name, -1);
nlist_insert(&rtnl, clnt);
- close(fd);
- dprintf(N_DEBUG, "MONITORING %s for %s", mon_name, my_name);
+ xlog(D_GENERAL, "MONITORING %s for %s", mon_name, my_name);
success:
result.res_stat = STAT_SUCC;
/* SUN's sm_inter.x says this should be "state number of local site".
@@ -232,75 +207,50 @@ sm_mon_1_svc(struct mon *argp, struct sv
return (&result);
failure:
- note(N_WARNING, "STAT_FAIL to %s for SM_MON of %s", my_name, mon_name);
+ xlog_warn("STAT_FAIL to %s for SM_MON of %s", my_name, mon_name);
return (&result);
}
-void load_state(void)
+static unsigned int
+load_one_host(const char *hostname, const struct sockaddr *sap,
+ const struct mon *m,
+ __attribute__ ((unused)) const time_t timestamp)
{
- DIR *d;
- struct dirent *de;
- char buf[LINELEN + 1 + SM_MAXSTRLEN + 2];
-
- d = opendir(SM_DIR);
- if (!d)
- return;
- while ((de = readdir(d))) {
- char *path;
- FILE *f;
- int p;
-
- if (de->d_name[0] == '.')
- continue;
- path = xmalloc(strlen(SM_DIR)+strlen(de->d_name)+2);
- sprintf(path, "%s/%s", SM_DIR, de->d_name);
- f = fopen(path, "r");
- free(path);
- if (f == NULL)
- continue;
- while (fgets(buf, sizeof(buf), f) != NULL) {
- int addr, proc, prog, vers;
- char priv[SM_PRIV_SIZE];
- char *monname, *myname;
- char *b;
- int i;
- notify_list *clnt;
-
- buf[sizeof(buf)-1] = 0;
- b = strchr(buf, '\n');
- if (b) *b = 0;
- sscanf(buf, "%x %x %x %x ",
- &addr, &prog, &vers, &proc);
- b = buf+36;
- for (i=0; i<SM_PRIV_SIZE; i++) {
- sscanf(b, "%2x", &p);
- priv[i] = p;
- b += 2;
- }
- b++;
- monname = b;
- while (*b && *b != ' ') b++;
- if (*b) *b++ = '\0';
- while (*b == ' ') b++;
- myname = b;
- clnt = nlist_new(myname, monname, 0);
- if (!clnt)
- break;
- NL_ADDR(clnt).s_addr = addr;
- NL_MY_PROG(clnt) = prog;
- NL_MY_VERS(clnt) = vers;
- NL_MY_PROC(clnt) = proc;
- clnt->dns_name = xstrdup(de->d_name);
- memcpy(NL_PRIV(clnt), priv, SM_PRIV_SIZE);
- nlist_insert(&rtnl, clnt);
- }
- fclose(f);
+ const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
+ notify_list *clnt;
+
+ clnt = nlist_new(m->mon_id.my_id.my_name,
+ m->mon_id.mon_name, 0);
+ if (clnt == NULL)
+ return 0;
+
+ clnt->dns_name = strdup(hostname);
+ if (clnt->dns_name == NULL) {
+ nlist_free(NULL, clnt);
+ return 0;
}
- closedir(d);
-}
+ xlog(D_GENERAL, "Adding record for %s to the monitor list...",
+ hostname);
+
+ NL_ADDR(clnt) = sin->sin_addr;
+ NL_MY_PROG(clnt) = m->mon_id.my_id.my_prog;
+ NL_MY_VERS(clnt) = m->mon_id.my_id.my_vers;
+ NL_MY_PROC(clnt) = m->mon_id.my_id.my_proc;
+ memcpy(NL_PRIV(clnt), m->priv, SM_PRIV_SIZE);
+
+ nlist_insert(&rtnl, clnt);
+ return 1;
+}
+void load_state(void)
+{
+ unsigned int count;
+ count = nsm_load_monitor_list(load_one_host);
+ if (count)
+ xlog(D_GENERAL, "Loaded %u previously monitored hosts");
+}
/*
* Services SM_UNMON requests.
@@ -320,6 +270,8 @@ sm_unmon_1_svc(struct mon_id *argp, stru
struct my_id *id = &argp->my_id;
char *cp;
+ xlog(D_CALL, "Received SM_UNMON for %s from %s", mon_name, my_name);
+
result.state = MY_STATE;
if (!caller_is_localhost(rqstp))
@@ -333,9 +285,8 @@ sm_unmon_1_svc(struct mon_id *argp, stru
/* Check if we're monitoring anyone. */
if (rtnl == NULL) {
- note(N_WARNING,
- "Received SM_UNMON request from %s for %s while not "
- "monitoring any hosts.", my_name, argp->mon_name);
+ xlog_warn("Received SM_UNMON request from %s for %s while not "
+ "monitoring any hosts", my_name, argp->mon_name);
return (&result);
}
clnt = rtnl;
@@ -352,13 +303,13 @@ sm_unmon_1_svc(struct mon_id *argp, stru
NL_MY_PROG(clnt) == id->my_prog &&
NL_MY_VERS(clnt) == id->my_vers) {
/* Match! */
- dprintf(N_DEBUG, "UNMONITORING %s for %s",
+ xlog(D_GENERAL, "UNMONITORING %s for %s",
mon_name, my_name);
/* PRC: do the HA callout: */
ha_callout("del-client", mon_name, my_name, -1);
- xunlink(SM_DIR, clnt->dns_name);
+ nsm_delete_monitored_host(clnt->dns_name);
nlist_free(&rtnl, clnt);
return (&result);
@@ -367,7 +318,7 @@ sm_unmon_1_svc(struct mon_id *argp, stru
}
failure:
- note(N_WARNING, "Received erroneous SM_UNMON request from %s for %s",
+ xlog_warn("Received erroneous SM_UNMON request from %s for %s",
my_name, mon_name);
return (&result);
}
@@ -381,13 +332,15 @@ sm_unmon_all_1_svc(struct my_id *argp, s
notify_list *clnt;
char *my_name = argp->my_name;
+ xlog(D_CALL, "Received SM_UNMON_ALL for %s", my_name);
+
if (!caller_is_localhost(rqstp))
goto failure;
result.state = MY_STATE;
if (rtnl == NULL) {
- note(N_WARNING, "Received SM_UNMON_ALL request from %s "
+ xlog_warn("Received SM_UNMON_ALL request from %s "
"while not monitoring any hosts", my_name);
return (&result);
}
@@ -401,7 +354,7 @@ sm_unmon_all_1_svc(struct my_id *argp, s
char mon_name[SM_MAXSTRLEN + 1];
notify_list *temp;
- dprintf(N_DEBUG,
+ xlog(D_GENERAL,
"UNMONITORING (SM_UNMON_ALL) %s for %s",
NL_MON_NAME(clnt), NL_MY_NAME(clnt));
strncpy(mon_name, NL_MON_NAME(clnt),
@@ -410,7 +363,7 @@ sm_unmon_all_1_svc(struct my_id *argp, s
temp = NL_NEXT(clnt);
/* PRC: do the HA callout: */
ha_callout("del-client", mon_name, my_name, -1);
- xunlink(SM_DIR, clnt->dns_name);
+ nsm_delete_monitored_host(clnt->dns_name);
nlist_free(&rtnl, clnt);
++count;
clnt = temp;
@@ -419,8 +372,8 @@ sm_unmon_all_1_svc(struct my_id *argp, s
}
if (!count) {
- dprintf(N_DEBUG, "SM_UNMON_ALL request from %s with no "
- "SM_MON requests from it.", my_name);
+ xlog(D_GENERAL, "SM_UNMON_ALL request from %s with no "
+ "SM_MON requests from it", my_name);
}
failure:
diff -up nfs-utils-1.2.1/utils/statd/rmtcall.c.orig nfs-utils-1.2.1/utils/statd/rmtcall.c
--- nfs-utils-1.2.1/utils/statd/rmtcall.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/statd/rmtcall.c 2010-01-14 03:53:55.470815782 -0500
@@ -43,7 +43,6 @@
#include "sm_inter.h"
#include "statd.h"
#include "notlist.h"
-#include "log.h"
#include "ha-callout.h"
#if SIZEOF_SOCKLEN_T - 0 == 0
@@ -81,7 +80,7 @@ statd_get_socket(void)
if (sockfd >= 0) close(sockfd);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
- note(N_CRIT, "%s: Can't create socket: %m", __func__);
+ xlog(L_ERROR, "%s: Can't create socket: %m", __func__);
return -1;
}
@@ -91,7 +90,7 @@ statd_get_socket(void)
sin.sin_addr.s_addr = INADDR_ANY;
if (bindresvport(sockfd, &sin) < 0) {
- dprintf(N_WARNING, "%s: can't bind to reserved port",
+ xlog(D_GENERAL, "%s: can't bind to reserved port",
__func__);
break;
}
@@ -150,7 +149,7 @@ xmit_call(struct sockaddr_in *sin,
/* Encode the RPC header part and payload */
if (!xdr_callmsg(xdrs, &mesg) || !func(xdrs, obj)) {
- dprintf(N_WARNING, "%s: can't encode RPC message!", __func__);
+ xlog(D_GENERAL, "%s: can't encode RPC message!", __func__);
xdr_destroy(xdrs);
return 0;
}
@@ -160,9 +159,9 @@ xmit_call(struct sockaddr_in *sin,
if ((err = sendto(sockfd, msgbuf, msglen, 0,
(struct sockaddr *) sin, sizeof(*sin))) < 0) {
- dprintf(N_WARNING, "%s: sendto failed: %m", __func__);
+ xlog_warn("%s: sendto failed: %m", __func__);
} else if (err != msglen) {
- dprintf(N_WARNING, "%s: short write: %m", __func__);
+ xlog_warn("%s: short write: %m", __func__);
}
xdr_destroy(xdrs);
@@ -182,7 +181,7 @@ recv_rply(struct sockaddr_in *sin, u_lon
/* Receive message */
if ((msglen = recvfrom(sockfd, msgbuf, sizeof(msgbuf), 0,
(struct sockaddr *) sin, &alen)) < 0) {
- dprintf(N_WARNING, "%s: recvfrom failed: %m", __func__);
+ xlog_warn("%s: recvfrom failed: %m", __func__);
return NULL;
}
@@ -194,19 +193,19 @@ recv_rply(struct sockaddr_in *sin, u_lon
mesg.rm_reply.rp_acpt.ar_results.proc = (xdrproc_t) xdr_void;
if (!xdr_replymsg(xdrs, &mesg)) {
- note(N_WARNING, "%s: can't decode RPC message!", __func__);
+ xlog_warn("%s: can't decode RPC message!", __func__);
goto done;
}
if (mesg.rm_reply.rp_stat != 0) {
- note(N_WARNING, "%s: [%s] RPC status %d",
+ xlog_warn("%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, "%s: [%s] RPC status %d",
+ xlog_warn("%s: [%s] RPC status %d",
__func__,
inet_ntoa(sin->sin_addr),
mesg.rm_reply.rp_acpt.ar_stat);
@@ -224,14 +223,13 @@ recv_rply(struct sockaddr_in *sin, u_lon
strncpy (addr, inet_ntoa(lp->addr),
sizeof (addr) - 1);
addr [sizeof (addr) - 1] = '\0';
- dprintf(N_WARNING, "%s: address mismatch: "
+ xlog_warn("%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,
- "%s: [%s] can't decode reply body!",
+ xlog_warn("%s: [%s] can't decode reply body!",
__func__,
inet_ntoa(sin->sin_addr));
lp = NULL;
@@ -260,7 +258,7 @@ process_entry(notify_list *lp)
/* __u32 proc, vers, prog; */
if (NL_TIMES(lp) == 0) {
- note(N_DEBUG, "%s: Cannot notify %s, giving up.",
+ xlog(D_GENERAL, "%s: Cannot notify %s, giving up",
__func__, inet_ntoa(NL_ADDR(lp)));
return 0;
}
@@ -286,7 +284,7 @@ process_entry(notify_list *lp)
lp->xid = xmit_call(&sin, prog, vers, proc, func, objp);
if (!lp->xid) {
- note(N_WARNING, "%s: failed to notify port %d",
+ xlog_warn("%s: failed to notify port %d",
__func__, ntohs(lp->port));
}
NL_TIMES(lp) -= 1;
@@ -319,10 +317,10 @@ process_reply(FD_SET_TYPE *rfds)
nlist_insert_timer(&notify, lp);
return 1;
}
- note(N_WARNING, "%s: [%s] service %d not registered",
+ xlog_warn("%s: [%s] service %d not registered",
__func__, inet_ntoa(lp->addr), NL_MY_PROG(lp));
} else {
- dprintf(N_DEBUG, "%s: Callback to %s (for %d) succeeded.",
+ xlog(D_GENERAL, "%s: Callback to %s (for %d) succeeded",
__func__, NL_MY_NAME(lp), NL_MON_NAME(lp));
}
nlist_free(&notify, lp);
@@ -346,8 +344,8 @@ process_notify_list(void)
nlist_remove(&notify, entry);
nlist_insert_timer(&notify, entry);
} else {
- note(N_ERROR,
- "%s: Can't callback %s (%d,%d), giving up.",
+ xlog(L_ERROR,
+ "%s: Can't callback %s (%d,%d), giving up",
__func__,
NL_MY_NAME(entry),
NL_MY_PROG(entry),
diff -up nfs-utils-1.2.1/utils/statd/simu.c.orig nfs-utils-1.2.1/utils/statd/simu.c
--- nfs-utils-1.2.1/utils/statd/simu.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/statd/simu.c 2010-01-14 03:53:55.470815782 -0500
@@ -27,24 +27,26 @@ sm_simu_crash_1_svc (void *argp, struct
static char *result = NULL;
struct in_addr caller;
+ xlog(D_CALL, "Received SM_SIMU_CRASH");
+
if (sin->sin_family != AF_INET) {
- note(N_WARNING, "Call to statd from non-AF_INET address");
+ xlog_warn("Call to statd from non-AF_INET address");
goto failure;
}
caller = sin->sin_addr;
if (caller.s_addr != htonl(INADDR_LOOPBACK)) {
- note(N_WARNING, "Call to statd from non-local host %s",
+ xlog_warn("Call to statd from non-local host %s",
inet_ntoa(caller));
goto failure;
}
if (ntohs(sin->sin_port) >= 1024) {
- note(N_WARNING, "Call to statd-simu-crash from unprivileged port");
+ xlog_warn("Call to statd-simu-crash from unprivileged port");
goto failure;
}
- note (N_WARNING, "*** SIMULATING CRASH! ***");
+ xlog_warn("*** SIMULATING CRASH! ***");
my_svc_exit ();
if (rtnl)
diff -up nfs-utils-1.2.1/utils/statd/simulate.c.orig nfs-utils-1.2.1/utils/statd/simulate.c
--- nfs-utils-1.2.1/utils/statd/simulate.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/statd/simulate.c 2010-01-14 03:53:55.471842390 -0500
@@ -38,7 +38,9 @@ extern void svc_exit (void);
void
simulator (int argc, char **argv)
{
- log_enable (1);
+ xlog_stderr (1);
+ xlog_syslog (0);
+ xlog_open ("statd simulator");
if (argc == 2)
if (!strcasecmp (*argv, "crash"))
@@ -61,7 +63,7 @@ simulator (int argc, char **argv)
simulate_mon (*(&argv[1]), *(&argv[2]), *(&argv[3]), *(&argv[4]),
*(&argv[5]));
}
- die ("WTF? Give me something I can use!");
+ xlog_err ("WTF? Give me something I can use!");
}
static void
@@ -72,11 +74,11 @@ simulate_mon (char *calling, char *monit
sm_stat_res *result;
mon mon;
- dprintf (N_DEBUG, "Calling %s (as %s) to monitor %s", calling, as,
+ xlog (D_GENERAL, "Calling %s (as %s) to monitor %s", calling, as,
monitoring);
if ((client = clnt_create (calling, SM_PROG, SM_VERS, "udp")) == NULL)
- die ("%s", clnt_spcreateerror ("clnt_create"));
+ xlog_err ("%s", clnt_spcreateerror ("clnt_create"));
memcpy (mon.priv, fool, SM_PRIV_SIZE);
mon.mon_id.my_id.my_name = xstrdup (as);
@@ -87,16 +89,15 @@ simulate_mon (char *calling, char *monit
mon.mon_id.mon_name = monitoring;
if (!(result = sm_mon_1 (&mon, client)))
- die ("%s", clnt_sperror (client, "sm_mon_1"));
+ xlog_err ("%s", clnt_sperror (client, "sm_mon_1"));
free (mon.mon_id.my_id.my_name);
if (result->res_stat != STAT_SUCC) {
- note (N_FATAL, "SM_MON request failed, state: %d", result->state);
- exit (0);
+ xlog_err ("SM_MON request failed, state: %d", result->state);
} else {
- dprintf (N_DEBUG, "SM_MON result successful, state: %d\n", result->state);
- dprintf (N_DEBUG, "Waiting for callback.");
+ xlog (D_GENERAL, "SM_MON result successful, state: %d\n", result->state);
+ xlog (D_GENERAL, "Waiting for callback");
daemon_simulator ();
exit (0);
}
@@ -109,11 +110,11 @@ simulate_unmon (char *calling, char *unm
sm_stat *result;
mon_id mon_id;
- dprintf (N_DEBUG, "Calling %s (as %s) to unmonitor %s", calling, as,
+ xlog (D_GENERAL, "Calling %s (as %s) to unmonitor %s", calling, as,
unmonitoring);
if ((client = clnt_create (calling, SM_PROG, SM_VERS, "udp")) == NULL)
- die ("%s", clnt_spcreateerror ("clnt_create"));
+ xlog_err ("%s", clnt_spcreateerror ("clnt_create"));
mon_id.my_id.my_name = xstrdup (as);
mon_id.my_id.my_prog = atoi (proggy) * SIM_SM_PROG;
@@ -122,10 +123,10 @@ simulate_unmon (char *calling, char *unm
mon_id.mon_name = unmonitoring;
if (!(result = sm_unmon_1 (&mon_id, client)))
- die ("%s", clnt_sperror (client, "sm_unmon_1"));
+ xlog_err ("%s", clnt_sperror (client, "sm_unmon_1"));
free (mon_id.my_id.my_name);
- dprintf (N_DEBUG, "SM_UNMON request returned state: %d\n", result->state);
+ xlog (D_GENERAL, "SM_UNMON request returned state: %d\n", result->state);
exit (0);
}
@@ -136,10 +137,10 @@ simulate_unmon_all (char *calling, char
sm_stat *result;
my_id my_id;
- dprintf (N_DEBUG, "Calling %s (as %s) to unmonitor all hosts", calling, as);
+ xlog (D_GENERAL, "Calling %s (as %s) to unmonitor all hosts", calling, as);
if ((client = clnt_create (calling, SM_PROG, SM_VERS, "udp")) == NULL)
- die ("%s", clnt_spcreateerror ("clnt_create"));
+ xlog_err ("%s", clnt_spcreateerror ("clnt_create"));
my_id.my_name = xstrdup (as);
my_id.my_prog = atoi (proggy) * SIM_SM_PROG;
@@ -147,10 +148,10 @@ simulate_unmon_all (char *calling, char
my_id.my_proc = SIM_SM_MON;
if (!(result = sm_unmon_all_1 (&my_id, client)))
- die ("%s", clnt_sperror (client, "sm_unmon_all_1"));
+ xlog_err ("%s", clnt_sperror (client, "sm_unmon_all_1"));
free (my_id.my_name);
- dprintf (N_DEBUG, "SM_UNMON_ALL request returned state: %d\n", result->state);
+ xlog (D_GENERAL, "SM_UNMON_ALL request returned state: %d\n", result->state);
exit (0);
}
@@ -160,10 +161,10 @@ simulate_crash (char *host)
CLIENT *client;
if ((client = clnt_create (host, SM_PROG, SM_VERS, "udp")) == NULL)
- die ("%s", clnt_spcreateerror ("clnt_create"));
+ xlog_err ("%s", clnt_spcreateerror ("clnt_create"));
if (!sm_simu_crash_1 (NULL, client))
- die ("%s", clnt_sperror (client, "sm_simu_crash_1"));
+ xlog_err ("%s", clnt_sperror (client, "sm_simu_crash_1"));
exit (0);
}
@@ -176,18 +177,18 @@ simulate_stat (char *calling, char *moni
sm_stat_res *result;
if ((client = clnt_create (calling, SM_PROG, SM_VERS, "udp")) == NULL)
- die ("%s", clnt_spcreateerror ("clnt_create"));
+ xlog_err ("%s", clnt_spcreateerror ("clnt_create"));
checking.mon_name = monitoring;
if (!(result = sm_stat_1 (&checking, client)))
- die ("%s", clnt_sperror (client, "sm_stat_1"));
+ xlog_err ("%s", clnt_sperror (client, "sm_stat_1"));
if (result->res_stat == STAT_SUCC)
- dprintf (N_DEBUG, "STAT_SUCC from %s for %s, state: %d", calling,
+ xlog (D_GENERAL, "STAT_SUCC from %s for %s, state: %d", calling,
monitoring, result->state);
else
- dprintf (N_DEBUG, "STAT_FAIL from %s for %s, state: %d", calling,
+ xlog (D_GENERAL, "STAT_FAIL from %s for %s, state: %d", calling,
monitoring, result->state);
exit (0);
@@ -196,9 +197,8 @@ simulate_stat (char *calling, char *moni
static void
sim_killer (int sig)
{
- note (N_FATAL, "Simulator caught signal %d, un-registering and exiting.", sig);
pmap_unset (sim_port, SIM_SM_VERS);
- exit (0);
+ xlog_err ("Simulator caught signal %d, un-registering and exiting", sig);
}
static void
@@ -219,7 +219,7 @@ sim_sm_mon_1_svc (struct status *argp, s
{
static char *result;
- dprintf (N_DEBUG, "Recieved state %d for mon_name %s (opaque \"%s\")",
+ xlog (D_GENERAL, "Recieved state %d for mon_name %s (opaque \"%s\")",
argp->state, argp->mon_name, argp->priv);
svc_exit ();
return ((void *)&result);
diff -up nfs-utils-1.2.1/utils/statd/sm-notify.c.orig nfs-utils-1.2.1/utils/statd/sm-notify.c
--- nfs-utils-1.2.1/utils/statd/sm-notify.c.orig 2010-01-14 03:53:10.146951642 -0500
+++ nfs-utils-1.2.1/utils/statd/sm-notify.c 2010-01-14 03:56:10.166043804 -0500
@@ -8,6 +8,7 @@
#include <config.h>
#endif
+#include <err.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
@@ -28,24 +29,9 @@
#include <errno.h>
#include <grp.h>
-#define STATD_PATH_XTN "statd/"
-
-#ifndef BASEDIR
-# ifdef NFS_STATEDIR
-# define BASEDIR NFS_STATEDIR "/" STATD_PATH_XTN
-# else
-# define BASEDIR "/var/lib/nfs" "/" STATD_PATH_XTN
-# endif
-#endif
-
-#define DEFAULT_SM_STATE_PATH BASEDIR "/state"
-#define DEFAULT_SM_DIR_PATH BASEDIR "/sm"
-#define DEFAULT_SM_BAK_PATH DEFAULT_SM_DIR_PATH ".bak"
-
-char *_SM_BASE_PATH = BASEDIR;
-char *_SM_STATE_PATH = DEFAULT_SM_STATE_PATH;
-char *_SM_DIR_PATH = DEFAULT_SM_DIR_PATH;
-char *_SM_BAK_PATH = DEFAULT_SM_BAK_PATH;
+#include "xlog.h"
+#include "nsm.h"
+#include "nfsrpc.h"
#define NSM_PROG 100024
#define NSM_PROGRAM 100024
@@ -58,7 +44,6 @@ char *_SM_BAK_PATH = DEFAULT_SM_BAK_PATH
struct nsm_host {
struct nsm_host * next;
char * name;
- char * path;
struct sockaddr_storage addr;
struct addrinfo *ai;
time_t last_used;
@@ -69,57 +54,22 @@ struct nsm_host {
};
static char nsm_hostname[256];
-static uint32_t nsm_state;
+static int nsm_state;
static int opt_debug = 0;
-static int opt_quiet = 0;
-static int opt_update_state = 1;
+static _Bool opt_update_state = true;
static unsigned int opt_max_retry = 15 * 60;
static char * opt_srcaddr = 0;
static uint16_t opt_srcport = 0;
-static int log_syslog = 0;
-static unsigned int nsm_get_state(int);
static void notify(void);
static int notify_host(int, struct nsm_host *);
static void recv_reply(int);
-static void backup_hosts(const char *, const char *);
-static void get_hosts(const char *);
static void insert_host(struct nsm_host *);
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 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 char *name)
{
struct addrinfo *ai, hint = {
@@ -132,27 +82,47 @@ static struct addrinfo *smn_lookup(const
int error;
error = getaddrinfo(name, NULL, &hint, &ai);
- switch (error) {
- case 0:
- return ai;
- case EAI_SYSTEM:
- if (opt_debug)
- nsm_log(LOG_ERR, "getaddrinfo(3): %s",
- strerror(errno));
- break;
- default:
- if (opt_debug)
- nsm_log(LOG_ERR, "getaddrinfo(3): %s",
- gai_strerror(error));
+ if (error) {
+ xlog(D_GENERAL, "getaddrinfo(3): %s", gai_strerror(error));
+ return NULL;
+ }
+
+ return ai;
+}
+
+__attribute_malloc__
+static struct nsm_host *
+smn_alloc_host(const char *hostname, const time_t timestamp)
+{
+ struct nsm_host *host;
+
+ host = calloc(1, sizeof(*host));
+ if (host == NULL)
+ goto out_nomem;
+
+ host->name = strdup(hostname);
+ if (host->name == NULL) {
+ free(host);
+ goto out_nomem;
}
+ host->last_used = timestamp;
+ host->timeout = NSM_TIMEOUT;
+ host->retries = 100; /* force address retry */
+
+ return host;
+
+out_nomem:
+ xlog_warn("Unable to allocate memory");
return NULL;
}
static void smn_forget_host(struct nsm_host *host)
{
- unlink(host->path);
- free(host->path);
+ xlog(D_CALL, "Removing %s from notify list", host->name);
+
+ nsm_delete_notified_host(host->name);
+
free(host->name);
if (host->ai)
freeaddrinfo(host->ai);
@@ -160,13 +130,37 @@ static void smn_forget_host(struct nsm_h
free(host);
}
+static unsigned int
+smn_get_host(const char *hostname,
+ __attribute__ ((unused)) const struct sockaddr *sap,
+ __attribute__ ((unused)) const struct mon *m,
+ const time_t timestamp)
+{
+ struct nsm_host *host;
+
+ host = smn_alloc_host(hostname, timestamp);
+ if (host == NULL)
+ return 0;
+
+ insert_host(host);
+ xlog(D_GENERAL, "Added host %s to notify list", hostname);
+ return 1;
+}
+
int
main(int argc, char **argv)
{
int c;
int force = 0;
+ char * progname;
+
+ progname = strrchr(argv[0], '/');
+ if (progname != NULL)
+ progname++;
+ else
+ progname = argv[0];
- while ((c = getopt(argc, argv, "dm:np:v:qP:f")) != -1) {
+ while ((c = getopt(argc, argv, "dm:np:v:P:f")) != -1) {
switch (c) {
case 'f':
force = 1;
@@ -178,7 +172,7 @@ main(int argc, char **argv)
opt_max_retry = atoi(optarg) * 60;
break;
case 'n':
- opt_update_state = 0;
+ opt_update_state = false;
break;
case 'p':
opt_srcport = atoi(optarg);
@@ -186,24 +180,9 @@ main(int argc, char **argv)
case 'v':
opt_srcaddr = optarg;
break;
- case 'q':
- opt_quiet = 1;
- break;
case 'P':
- _SM_BASE_PATH = strdup(optarg);
- _SM_STATE_PATH = malloc(strlen(optarg)+1+sizeof("state"));
- _SM_DIR_PATH = malloc(strlen(optarg)+1+sizeof("sm"));
- _SM_BAK_PATH = malloc(strlen(optarg)+1+sizeof("sm.bak"));
- if (_SM_BASE_PATH == NULL ||
- _SM_STATE_PATH == NULL ||
- _SM_DIR_PATH == NULL ||
- _SM_BAK_PATH == NULL) {
- nsm_log(LOG_ERR, "unable to allocate memory");
+ if (!nsm_setup_pathnames(argv[0], optarg))
exit(1);
- }
- strcat(strcpy(_SM_STATE_PATH, _SM_BASE_PATH), "/state");
- strcat(strcpy(_SM_DIR_PATH, _SM_BASE_PATH), "/sm");
- strcat(strcpy(_SM_BAK_PATH, _SM_BASE_PATH), "/sm.bak");
break;
default:
@@ -213,18 +192,26 @@ main(int argc, char **argv)
if (optind < argc) {
usage: fprintf(stderr,
- "Usage: sm-notify [-dfq] [-m max-retry-minutes] [-p srcport]\n"
- " [-P /path/to/state/directory] [-v my_host_name]\n");
+ "Usage: %s -notify [-dfq] [-m max-retry-minutes] [-p srcport]\n"
+ " [-P /path/to/state/directory] [-v my_host_name]\n",
+ progname);
exit(1);
}
- log_syslog = 1;
- openlog("sm-notify", LOG_PID, LOG_DAEMON);
+ xlog_syslog(1);
+ if (opt_debug) {
+ xlog_stderr(1);
+ xlog_config(D_ALL, 1);
+ } else
+ xlog_stderr(0);
+
+ xlog_open(progname);
+ xlog(L_NOTICE, "Version " VERSION " starting");
- if (strcmp(_SM_BASE_PATH, BASEDIR) == 0) {
- if (record_pid() == 0 && force == 0 && opt_update_state == 1) {
+ if (nsm_is_default_parentdir()) {
+ if (record_pid() == 0 && force == 0 && opt_update_state) {
/* already run, don't try again */
- nsm_log(LOG_NOTICE, "Already notifying clients; Exiting!");
+ xlog(L_NOTICE, "Already notifying clients; Exiting!");
exit(0);
}
}
@@ -233,31 +220,26 @@ usage: fprintf(stderr,
strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname)-1);
} else
if (gethostname(nsm_hostname, sizeof(nsm_hostname)) < 0) {
- nsm_log(LOG_ERR, "Failed to obtain name of local host: %s",
- strerror(errno));
+ xlog(L_ERROR, "Failed to obtain name of local host: %m");
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");
+ (void)nsm_retire_monitored_hosts();
+ if (nsm_load_notify_list(smn_get_host) == 0) {
+ xlog(D_GENERAL, "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 (nsm_state == 0)
+ exit(1);
+ nsm_update_kernel_state(nsm_state);
if (!opt_debug) {
- if (!opt_quiet)
- printf("Backgrounding to notify hosts...\n");
+ xlog(L_NOTICE, "Backgrounding to notify hosts...\n");
if (daemon(0, 0) < 0) {
- nsm_log(LOG_ERR, "unable to background: %s",
- strerror(errno));
+ xlog(L_ERROR, "unable to background: %m");
exit(1);
}
@@ -273,8 +255,7 @@ usage: fprintf(stderr,
while ((hp = hosts) != 0) {
hosts = hp->next;
- nsm_log(LOG_NOTICE,
- "Unable to notify %s, giving up",
+ xlog(L_NOTICE, "Unable to notify %s, giving up",
hp->name);
}
exit(1);
@@ -298,8 +279,7 @@ notify(void)
retry:
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
- nsm_log(LOG_ERR, "Failed to create RPC socket: %s",
- strerror(errno));
+ xlog(L_ERROR, "Failed to create RPC socket: %m");
exit(1);
}
fcntl(sock, F_SETFL, O_NONBLOCK);
@@ -311,7 +291,7 @@ notify(void)
if (opt_srcaddr) {
struct addrinfo *ai = smn_lookup(opt_srcaddr);
if (!ai) {
- nsm_log(LOG_ERR,
+ xlog(L_ERROR,
"Not a valid hostname or address: \"%s\"",
opt_srcaddr);
exit(1);
@@ -326,10 +306,9 @@ notify(void)
/* Use source port if provided on the command line,
* otherwise use bindresvport */
if (opt_srcport) {
- smn_set_port(local_addr, opt_srcport);
+ nfs_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));
+ xlog(L_ERROR, "Failed to bind RPC socket: %m");
exit(1);
}
} else {
@@ -348,7 +327,8 @@ notify(void)
if (opt_max_retry)
failtime = time(NULL) + opt_max_retry;
- drop_privs();
+ if (!nsm_drop_privileges(-1))
+ exit(1);
while (hosts) {
struct pollfd pfd;
@@ -385,7 +365,7 @@ notify(void)
if (hosts == NULL)
return;
- nsm_log(LOG_DEBUG, "Host %s due in %ld seconds",
+ xlog(D_GENERAL, "Host %s due in %ld seconds",
hosts->name, wait);
pfd.fd = sock;
@@ -422,8 +402,7 @@ notify_host(int sock, struct nsm_host *h
if (host->ai == NULL) {
host->ai = smn_lookup(host->name);
if (host->ai == NULL) {
- nsm_log(LOG_WARNING,
- "DNS resolution of %s failed; "
+ xlog_warn("DNS resolution of %s failed; "
"retrying later", host->name);
return 0;
}
@@ -462,16 +441,16 @@ notify_host(int sock, struct nsm_host *h
first->ai_addrlen);
}
- smn_set_port((struct sockaddr *)&host->addr, 0);
+ nfs_set_port((struct sockaddr *)&host->addr, 0);
host->retries = 0;
}
memcpy(dest, &host->addr, destlen);
- if (smn_get_port(dest) == 0) {
+ if (nfs_get_port(dest) == 0) {
/* Build a PMAP packet */
- nsm_log(LOG_DEBUG, "Sending portmap query to %s", host->name);
+ xlog(D_GENERAL, "Sending portmap query to %s", host->name);
- smn_set_port(dest, 111);
+ nfs_set_port(dest, 111);
*p++ = htonl(100000);
*p++ = htonl(2);
*p++ = htonl(3);
@@ -486,7 +465,7 @@ notify_host(int sock, struct nsm_host *h
*p++ = 0;
} else {
/* Build an SM_NOTIFY packet */
- nsm_log(LOG_DEBUG, "Sending SM_NOTIFY to %s", host->name);
+ xlog(D_GENERAL, "Sending SM_NOTIFY to %s", host->name);
*p++ = htonl(NSM_PROGRAM);
*p++ = htonl(NSM_VERSION);
@@ -506,8 +485,8 @@ notify_host(int sock, struct nsm_host *h
len = (p - msgbuf) << 2;
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));
+ xlog_warn("Sending Reboot Notification to "
+ "'%s' failed: errno %d (%m)", host->name, errno);
return 0;
}
@@ -528,7 +507,7 @@ recv_reply(int sock)
if (res < 0)
return;
- nsm_log(LOG_DEBUG, "Received packet...");
+ xlog(D_GENERAL, "Received packet...");
p = msgbuf;
end = p + (res >> 2);
@@ -547,7 +526,7 @@ recv_reply(int sock)
return;
sap = (struct sockaddr *)&hp->addr;
- if (smn_get_port(sap) == 0) {
+ if (nfs_get_port(sap) == 0) {
/* This was a portmap request */
unsigned int port;
@@ -559,11 +538,11 @@ recv_reply(int sock)
if (port == 0) {
/* No binding for statd. Delay the next
* portmap query for max timeout */
- nsm_log(LOG_DEBUG, "No statd on %s", hp->name);
+ xlog(D_GENERAL, "No statd on %s", hp->name);
hp->timeout = NSM_MAX_TIMEOUT;
hp->send_next += NSM_MAX_TIMEOUT;
} else {
- smn_set_port(sap, port);
+ nfs_set_port(sap, port);
if (hp->timeout >= NSM_MAX_TIMEOUT / 4)
hp->timeout = NSM_MAX_TIMEOUT / 4;
}
@@ -575,7 +554,7 @@ recv_reply(int sock)
* packet)
*/
if (p <= end) {
- nsm_log(LOG_DEBUG, "Host %s notified successfully",
+ xlog(D_GENERAL, "Host %s notified successfully",
hp->name);
smn_forget_host(hp);
return;
@@ -587,87 +566,6 @@ fail: /* Re-insert the host */
}
/*
- * Back up all hosts from the sm directory to sm.bak
- */
-static void
-backup_hosts(const char *dirname, const char *bakname)
-{
- struct dirent *de;
- DIR *dir;
-
- if (!(dir = opendir(dirname))) {
- nsm_log(LOG_WARNING,
- "Failed to open %s: %s", dirname, strerror(errno));
- return;
- }
-
- while ((de = readdir(dir)) != NULL) {
- char src[1024], dst[1024];
-
- if (de->d_name[0] == '.')
- continue;
-
- snprintf(src, sizeof(src), "%s/%s", dirname, de->d_name);
- snprintf(dst, sizeof(dst), "%s/%s", bakname, de->d_name);
- if (rename(src, dst) < 0) {
- nsm_log(LOG_WARNING,
- "Failed to rename %s -> %s: %m",
- src, dst);
- }
- }
- closedir(dir);
-}
-
-/*
- * Get all entries from sm.bak and convert them to host entries
- */
-static void
-get_hosts(const char *dirname)
-{
- struct nsm_host *host;
- struct dirent *de;
- DIR *dir;
-
- if (!(dir = opendir(dirname))) {
- nsm_log(LOG_WARNING,
- "Failed to open %s: %s", dirname, strerror(errno));
- return;
- }
-
- host = NULL;
- while ((de = readdir(dir)) != NULL) {
- struct stat stb;
- char path[1024];
-
- if (de->d_name[0] == '.')
- 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)
- continue;
-
- host->last_used = stb.st_mtime;
- host->timeout = NSM_TIMEOUT;
- host->path = strdup(path);
- host->name = strdup(de->d_name);
- host->retries = 100; /* force address retry */
-
- insert_host(host);
- host = NULL;
- }
- closedir(dir);
-
- if (host)
- free(host);
-}
-
-/*
* Insert host into sorted list
*/
static void
@@ -714,84 +612,6 @@ find_host(uint32_t xid)
return NULL;
}
-
-/*
- * Retrieve the current NSM state
- */
-static unsigned int
-nsm_get_state(int update)
-{
- char newfile[PATH_MAX];
- int fd, state;
-
- if ((fd = open(_SM_STATE_PATH, O_RDONLY)) < 0) {
- if (!opt_quiet) {
- nsm_log(LOG_WARNING, "%s: %m", _SM_STATE_PATH);
- nsm_log(LOG_WARNING, "Creating %s, set initial state 1",
- _SM_STATE_PATH);
- }
- state = 1;
- update = 1;
- } else {
- if (read(fd, &state, sizeof(state)) != sizeof(state)) {
- nsm_log(LOG_WARNING,
- "%s: bad file size, setting state = 1",
- _SM_STATE_PATH);
- state = 1;
- update = 1;
- } else {
- if (!(state & 1))
- state += 1;
- }
- close(fd);
- }
-
- if (update) {
- state += 2;
- snprintf(newfile, sizeof(newfile),
- "%s.new", _SM_STATE_PATH);
- if ((fd = open(newfile, O_CREAT|O_WRONLY, 0644)) < 0) {
- nsm_log(LOG_ERR, "Cannot create %s: %m", newfile);
- exit(1);
- }
- if (write(fd, &state, sizeof(state)) != sizeof(state)) {
- 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_ERR,
- "Cannot create %s: %m", _SM_STATE_PATH);
- exit(1);
- }
- sync();
- }
-
- return state;
-}
-
-/*
- * Log a message
- */
-static void
-nsm_log(int fac, const char *fmt, ...)
-{
- va_list ap;
-
- if (fac == LOG_DEBUG && !opt_debug)
- return;
-
- va_start(ap, fmt);
- if (log_syslog)
- vsyslog(fac, fmt, ap);
- else {
- vfprintf(stderr, fmt, ap);
- fputs("\n", stderr);
- }
- va_end(ap);
-}
-
/*
* Record pid in /var/run/sm-notify.pid
* This file should remain until a reboot, even if the
@@ -801,61 +621,20 @@ nsm_log(int fac, const char *fmt, ...)
static int record_pid(void)
{
char pid[20];
+ ssize_t len;
int fd;
- snprintf(pid, 20, "%d\n", getpid());
+ (void)snprintf(pid, sizeof(pid), "%d\n", (int)getpid());
fd = open("/var/run/sm-notify.pid", O_CREAT|O_EXCL|O_WRONLY, 0600);
if (fd < 0)
return 0;
- if (write(fd, pid, strlen(pid)) != strlen(pid)) {
- nsm_log(LOG_WARNING, "Writing to pid file failed: errno %d(%s)",
- errno, strerror(errno));
- }
- close(fd);
- return 1;
-}
-/* Drop privileges to match owner of state-directory
- * (in case a reply triggers some unknown bug).
- */
-static void drop_privs(void)
-{
- struct stat st;
-
- if (stat(_SM_DIR_PATH, &st) == -1 &&
- stat(_SM_BASE_PATH, &st) == -1) {
- st.st_uid = 0;
- st.st_gid = 0;
- }
-
- if (st.st_uid == 0) {
- nsm_log(LOG_WARNING,
- "sm-notify running as root. chown %s to choose different user",
- _SM_DIR_PATH);
- return;
- }
-
- setgroups(0, NULL);
- if (setgid(st.st_gid) == -1
- || setuid(st.st_uid) == -1) {
- nsm_log(LOG_ERR, "Fail to drop privileges");
- exit(1);
+ len = write(fd, pid, strlen(pid));
+ if ((len < 0) || ((size_t)len != strlen(pid))) {
+ xlog_warn("Writing to pid file failed: errno %d (%m)",
+ errno);
}
-}
-
-static void set_kernel_nsm_state(int state)
-{
- int fd;
- const char *file = "/proc/sys/fs/nfs/nsm_local_state";
- fd = open(file ,O_WRONLY);
- if (fd >= 0) {
- char buf[20];
- snprintf(buf, sizeof(buf), "%d", state);
- if (write(fd, buf, strlen(buf)) != strlen(buf)) {
- nsm_log(LOG_WARNING, "Writing to '%s' failed: errno %d (%s)",
- file, errno, strerror(errno));
- }
- close(fd);
- }
+ (void)close(fd);
+ return 1;
}
diff -up nfs-utils-1.2.1/utils/statd/sm-notify.man.orig nfs-utils-1.2.1/utils/statd/sm-notify.man
--- nfs-utils-1.2.1/utils/statd/sm-notify.man.orig 2010-01-14 03:53:10.147941356 -0500
+++ nfs-utils-1.2.1/utils/statd/sm-notify.man 2010-01-14 03:53:55.473878740 -0500
@@ -6,7 +6,7 @@
.SH NAME
sm-notify \- Send out NSM reboot notifications
.SH SYNOPSIS
-.BI "/sbin/sm-notify [-dfq] [-m " time "] [-p " port "] [-P " path "] [-v " my_name " ]
+.BI "/sbin/sm-notify [-df] [-m " time "] [-p " port "] [-P " path "] [-v " my_name " ]
.SH DESCRIPTION
File locking over NFS (v2 and v3) requires a facility to notify peers in
case of a reboot, so that clients can reclaim locks after
@@ -101,10 +101,6 @@ to bind to the indicated IP
number. If this option is not given, it will try to bind to
a randomly chosen privileged port below 1024.
.TP
-.B -q
-Be quiet. This suppresses all messages except error
-messages while collecting the list of hosts.
-.TP
.BI -P " /path/to/state/directory
If
.B sm-notify
diff -up nfs-utils-1.2.1/utils/statd/stat.c.orig nfs-utils-1.2.1/utils/statd/stat.c
--- nfs-utils-1.2.1/utils/statd/stat.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/statd/stat.c 2010-01-14 03:53:55.474909456 -0500
@@ -42,13 +42,15 @@ sm_stat_1_svc (struct sm_name *argp, str
{
static sm_stat_res result;
+ xlog(D_CALL, "Received SM_STAT from %s", argp->mon_name);
+
if (gethostbyname (argp->mon_name) == NULL) {
- note (N_WARNING, "gethostbyname error for %s", argp->mon_name);
+ xlog_warn ("gethostbyname error for %s", argp->mon_name);
result.res_stat = STAT_FAIL;
- dprintf (N_DEBUG, "STAT_FAIL for %s", argp->mon_name);
+ xlog (D_GENERAL, "STAT_FAIL for %s", argp->mon_name);
} else {
result.res_stat = STAT_SUCC;
- dprintf (N_DEBUG, "STAT_SUCC for %s", argp->mon_name);
+ xlog (D_GENERAL, "STAT_SUCC for %s", argp->mon_name);
}
result.state = MY_STATE;
return(&result);
diff -up nfs-utils-1.2.1/utils/statd/statd.c.orig nfs-utils-1.2.1/utils/statd/statd.c
--- nfs-utils-1.2.1/utils/statd/statd.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/statd/statd.c 2010-01-14 03:53:55.475888849 -0500
@@ -25,33 +25,21 @@
#include <sys/resource.h>
#include <sys/wait.h>
#include <grp.h>
+
#include "statd.h"
-#include "version.h"
#include "nfslib.h"
+#include "nsm.h"
/* Socket operations */
#include <sys/types.h>
#include <sys/socket.h>
-/* Added to enable specification of state directory path at run-time
- * j_carlos_gomez@yahoo.com
- */
-
-char * DIR_BASE = DEFAULT_DIR_BASE;
-
-char * SM_DIR = DEFAULT_SM_DIR;
-char * SM_BAK_DIR = DEFAULT_SM_BAK_DIR;
-char * SM_STAT_PATH = DEFAULT_SM_STAT_PATH;
-
-/* ----- end of state directory path stuff ------- */
-
int run_mode = 0; /* foreground logging mode */
/* LH - I had these local to main, but it seemed silly to have
* two copies of each - one in main(), one static in log.c...
* It also eliminates the 256-char static in log.c */
-char *name_p = NULL;
-const char *version_p = NULL;
+static char *name_p = NULL;
/* PRC: a high-availability callout program can be specified with -H
* When this is done, the program will receive callouts whenever clients
@@ -75,7 +63,6 @@ static struct option longopts[] =
};
extern void sm_prog_1 (struct svc_req *, register SVCXPRT *);
-static void load_state_number(void);
#ifdef SIMULATIONS
extern void simulator (int, char **);
@@ -109,17 +96,15 @@ sm_prog_1_wrapper (struct svc_req *rqstp
static void
killer (int sig)
{
- note (N_FATAL, "Caught signal %d, un-registering and exiting.", sig);
pmap_unset (SM_PROG, SM_VERS);
-
- exit (0);
+ xlog_err ("Caught signal %d, un-registering and exiting", sig);
}
static void
sigusr (int sig)
{
extern void my_svc_exit (void);
- dprintf (N_DEBUG, "Caught signal %d, re-notifying (state %d).", sig,
+ xlog(D_GENERAL, "Caught signal %d, re-notifying (state %d)", sig,
MY_STATE);
my_svc_exit();
}
@@ -141,7 +126,7 @@ static void log_modes(void)
if (run_mode & MODE_LOG_STDERR)
strcat(buf,"Log-STDERR ");
- note(N_WARNING,buf);
+ xlog_warn(buf);
}
/*
@@ -175,13 +160,12 @@ static void create_pidfile(void)
unlink(pidfile);
fp = fopen(pidfile, "w");
if (!fp)
- die("Opening %s failed: %s\n",
- pidfile, strerror(errno));
+ xlog_err("Opening %s failed: %m\n", pidfile);
fprintf(fp, "%d\n", getpid());
pidfd = dup(fileno(fp));
if (fclose(fp) < 0) {
- note(N_WARNING, "Flushing pid file failed: errno %d (%s)\n",
- errno, strerror(errno));
+ xlog_warn("Flushing pid file failed: errno %d (%m)\n",
+ errno);
}
}
@@ -189,42 +173,10 @@ static void truncate_pidfile(void)
{
if (pidfd >= 0) {
if (ftruncate(pidfd, 0) < 0) {
- note(N_WARNING, "truncating pid file failed: errno %d (%s)\n",
- errno, strerror(errno));
- }
- }
-}
-
-static void drop_privs(void)
-{
- struct stat st;
-
- if (stat(SM_DIR, &st) == -1 &&
- stat(DIR_BASE, &st) == -1) {
- st.st_uid = 0;
- st.st_gid = 0;
- }
-
- if (st.st_uid == 0) {
- note(N_WARNING, "statd running as root. chown %s to choose different user\n",
- SM_DIR);
- return;
- }
- /* better chown the pid file before dropping, as if it
- * if over nfs we might loose access
- */
- if (pidfd >= 0) {
- if (fchown(pidfd, st.st_uid, st.st_gid) < 0) {
- note(N_ERROR, "Unable to change owner of %s: %d (%s)",
- SM_DIR, strerror (errno));
+ xlog_warn("truncating pid file failed: errno %d (%m)\n",
+ errno);
}
}
- setgroups(0, NULL);
- if (setgid(st.st_gid) == -1
- || setuid(st.st_uid) == -1) {
- note(N_ERROR, "Fail to drop privileges");
- exit(1);
- }
}
static void run_sm_notify(int outport)
@@ -266,6 +218,8 @@ int main (int argc, char **argv)
/* Default: daemon mode, no other options */
run_mode = 0;
+ xlog_stderr(0);
+ xlog_syslog(1);
/* Set the basename */
if ((name_p = strrchr(argv[0],'/')) != NULL) {
@@ -274,13 +228,6 @@ int main (int argc, char **argv)
name_p = argv[0];
}
- /* Get the version */
- if ((version_p = strrchr(VERSION,' ')) != NULL) {
- version_p++;
- } else {
- version_p = VERSION;
- }
-
/* Set hostname */
MY_NAME = NULL;
@@ -289,7 +236,7 @@ int main (int argc, char **argv)
switch (arg) {
case 'V': /* Version */
case 'v':
- printf("%s version %s\n",name_p,version_p);
+ printf("%s version " VERSION "\n",name_p);
exit(0);
case 'F': /* Foreground/nodaemon mode */
run_mode |= MODE_NODAEMON;
@@ -326,34 +273,8 @@ int main (int argc, char **argv)
MY_NAME = xstrdup(optarg);
break;
case 'P':
-
- if ((DIR_BASE = xstrdup(optarg)) == NULL) {
- fprintf(stderr, "%s: xstrdup(%s) failed!\n",
- argv[0], optarg);
+ if (!nsm_setup_pathnames(argv[0], optarg))
exit(1);
- }
-
- SM_DIR = xmalloc(strlen(DIR_BASE) + 1 + sizeof("sm"));
- SM_BAK_DIR = xmalloc(strlen(DIR_BASE) + 1 + sizeof("sm.bak"));
- SM_STAT_PATH = xmalloc(strlen(DIR_BASE) + 1 + sizeof("state"));
-
- if ((SM_DIR == NULL)
- || (SM_BAK_DIR == NULL)
- || (SM_STAT_PATH == NULL)) {
-
- fprintf(stderr, "%s: xmalloc() failed!\n",
- argv[0]);
- exit(1);
- }
- if (DIR_BASE[strlen(DIR_BASE)-1] == '/') {
- sprintf(SM_DIR, "%ssm", DIR_BASE );
- sprintf(SM_BAK_DIR, "%ssm.bak", DIR_BASE );
- sprintf(SM_STAT_PATH, "%sstate", DIR_BASE );
- } else {
- sprintf(SM_DIR, "%s/sm", DIR_BASE );
- sprintf(SM_BAK_DIR, "%s/sm.bak", DIR_BASE );
- sprintf(SM_STAT_PATH, "%s/state", DIR_BASE );
- }
break;
case 'H': /* PRC: specify the ha-callout program */
if ((ha_callout_prog = xstrdup(optarg)) == NULL) {
@@ -383,7 +304,6 @@ int main (int argc, char **argv)
run_sm_notify(out_port);
}
-
if (!(run_mode & MODE_NODAEMON)) {
run_mode &= ~MODE_LOG_STDERR; /* Never log to console in
daemon mode. */
@@ -432,10 +352,6 @@ int main (int argc, char **argv)
/* Child. */
close(pipefds[0]);
setsid ();
- if (chdir (DIR_BASE) == -1) {
- perror("statd: Could not chdir");
- exit(1);
- }
while (pipefds[1] <= 2) {
pipefds[1] = dup(pipefds[1]);
@@ -455,7 +371,13 @@ int main (int argc, char **argv)
/* Child. */
- log_init (/*name_p,version_p*/);
+ if (run_mode & MODE_LOG_STDERR) {
+ xlog_syslog(0);
+ xlog_stderr(1);
+ xlog_config(D_ALL, 1);
+ }
+ xlog_open(name_p);
+ xlog(L_NOTICE, "Version " VERSION " starting");
log_modes();
@@ -495,7 +417,13 @@ int main (int argc, char **argv)
* pass on any SM_NOTIFY that arrives
*/
load_state();
- load_state_number();
+
+ MY_STATE = nsm_get_state(0);
+ if (MY_STATE == 0)
+ exit(1);
+ xlog(D_GENERAL, "Local NSM state number: %d", MY_STATE);
+ nsm_update_kernel_state(MY_STATE);
+
pmap_unset (SM_PROG, SM_VERS);
/* this registers both UDP and TCP services */
@@ -505,14 +433,15 @@ int main (int argc, char **argv)
if (pipefds[1] > 0) {
status = 0;
if (write(pipefds[1], &status, 1) != 1) {
- note(N_WARNING, "writing to parent pipe failed: errno %d (%s)\n",
+ xlog_warn("writing to parent pipe failed: errno %d (%s)\n",
errno, strerror(errno));
}
close(pipefds[1]);
pipefds[1] = -1;
}
- drop_privs();
+ if (!nsm_drop_privileges(pidfd))
+ exit(1);
for (;;) {
/*
@@ -541,29 +470,3 @@ int main (int argc, char **argv)
}
return 0;
}
-
-static void
-load_state_number(void)
-{
- int fd;
- const char *file = "/proc/sys/fs/nfs/nsm_local_state";
-
- if ((fd = open(SM_STAT_PATH, O_RDONLY)) == -1)
- return;
-
- if (read(fd, &MY_STATE, sizeof(MY_STATE)) != sizeof(MY_STATE)) {
- note(N_WARNING, "Unable to read state from '%s': errno %d (%s)",
- SM_STAT_PATH, errno, strerror(errno));
- }
- close(fd);
- fd = open(file, O_WRONLY);
- if (fd >= 0) {
- char buf[20];
- snprintf(buf, sizeof(buf), "%d", MY_STATE);
- if (write(fd, buf, strlen(buf)) != strlen(buf))
- note(N_WARNING, "Writing to '%s' failed: errno %d (%s)",
- file, errno, strerror(errno));
- close(fd);
- }
-
-}
diff -up nfs-utils-1.2.1/utils/statd/statd.h.orig nfs-utils-1.2.1/utils/statd/statd.h
--- nfs-utils-1.2.1/utils/statd/statd.h.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/statd/statd.h 2010-01-14 03:53:55.475888849 -0500
@@ -11,29 +11,7 @@
#include "sm_inter.h"
#include "system.h"
-#include "log.h"
-
-/*
- * Paths and filenames.
- */
-#if defined(NFS_STATEDIR)
-# define DEFAULT_DIR_BASE NFS_STATEDIR "/"
-#else
-# define DEFAULT_DIR_BASE "/var/lib/nfs/"
-#endif
-
-#define DEFAULT_SM_DIR DEFAULT_DIR_BASE "sm"
-#define DEFAULT_SM_BAK_DIR DEFAULT_DIR_BASE "sm.bak"
-#define DEFAULT_SM_STAT_PATH DEFAULT_DIR_BASE "state"
-
-/* Added to support run-time specification of state directory path.
- * j_carlos_gomez@yahoo.com
- */
-
-extern char * DIR_BASE;
-extern char * SM_DIR;
-extern char * SM_BAK_DIR;
-extern char * SM_STAT_PATH;
+#include "xlog.h"
/*
* Status definitions.
@@ -53,7 +31,6 @@ extern int process_notify_list(void);
extern int process_reply(FD_SET_TYPE *);
extern char * xstrdup(const char *);
extern void * xmalloc(size_t);
-extern void xunlink (char *, char *);
extern void load_state(void);
/*
@@ -84,10 +61,3 @@ extern int run_mode;
* another host.... */
#define STATIC_HOSTNAME 8 /* Always use the hostname set by -n */
#define MODE_NO_NOTIFY 16 /* Don't notify peers of a reboot */
-/*
- * Program name and version pointers -- See statd.c for the reasoning
- * as to why they're global.
- */
-extern char *name_p; /* program basename */
-extern const char *version_p; /* program version */
-
diff -up nfs-utils-1.2.1/utils/statd/svc_run.c.orig nfs-utils-1.2.1/utils/statd/svc_run.c
--- nfs-utils-1.2.1/utils/statd/svc_run.c.orig 2009-11-04 06:13:56.000000000 -0500
+++ nfs-utils-1.2.1/utils/statd/svc_run.c 2010-01-14 03:53:55.476824925 -0500
@@ -101,12 +101,12 @@ my_svc_run(void)
tv.tv_sec = NL_WHEN(notify) - now;
tv.tv_usec = 0;
- dprintf(N_DEBUG, "Waiting for reply... (timeo %d)",
+ xlog(D_GENERAL, "Waiting for reply... (timeo %d)",
tv.tv_sec);
selret = select(FD_SETSIZE, &readfds,
(void *) 0, (void *) 0, &tv);
} else {
- dprintf(N_DEBUG, "Waiting for client connections.");
+ xlog(D_GENERAL, "Waiting for client connections");
selret = select(FD_SETSIZE, &readfds,
(void *) 0, (void *) 0, (struct timeval *) 0);
}
@@ -116,8 +116,7 @@ my_svc_run(void)
if (errno == EINTR || errno == ECONNREFUSED
|| errno == ENETUNREACH || errno == EHOSTUNREACH)
continue;
- note(N_ERROR, "my_svc_run() - select: %s",
- strerror (errno));
+ xlog(L_ERROR, "my_svc_run() - select: %m");
return;
case 0: