nfs-utils/nfs-utils-1-2-3-rc3.patch

2110 lines
60 KiB
Diff
Raw Normal View History

diff -up nfs-utils-1.2.2/aclocal/libcap.m4.orig nfs-utils-1.2.2/aclocal/libcap.m4
--- nfs-utils-1.2.2/aclocal/libcap.m4.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/aclocal/libcap.m4 2010-05-06 07:16:37.851057000 -0400
@@ -5,11 +5,19 @@ AC_DEFUN([AC_LIBCAP], [
dnl look for prctl
AC_CHECK_FUNC([prctl], , )
- dnl look for the library; do not add to LIBS if found
- AC_CHECK_LIB([cap], [cap_get_proc], [LIBCAP=-lcap], ,)
- AC_SUBST(LIBCAP)
+ AC_ARG_ENABLE([caps],
+ [AS_HELP_STRING([--disable-caps], [Disable capabilities support])])
+
+ LIBCAP=
+
+ if test "x$enable_caps" != "xno" ; then
+ dnl look for the library; do not add to LIBS if found
+ AC_CHECK_LIB([cap], [cap_get_proc], [LIBCAP=-lcap], ,)
- AC_CHECK_HEADERS([sys/capability.h], ,
- [AC_MSG_ERROR([libcap headers not found.])])
+ AC_CHECK_HEADERS([sys/capability.h], ,
+ [test "x$enable_caps" = "xyes" && AC_MSG_ERROR([libcap headers not found.])])
+ fi
+
+ AC_SUBST(LIBCAP)
])dnl
diff -up nfs-utils-1.2.2/configure.ac.orig nfs-utils-1.2.2/configure.ac
--- nfs-utils-1.2.2/configure.ac.orig 2010-05-06 07:15:49.881176000 -0400
+++ nfs-utils-1.2.2/configure.ac 2010-05-06 07:16:37.856060000 -0400
@@ -89,7 +89,7 @@ AC_ARG_ENABLE(nfsv41,
if test "$enable_nfsv41" = yes; then
AC_DEFINE(NFS41_SUPPORTED, 1, [Define this if you want NFSv41 support compiled in])
else
- enable_nfsv4=
+ enable_nfsv41=
fi
AC_SUBST(enable_nfsv41)
AM_CONDITIONAL(CONFIG_NFSV41, [test "$enable_nfsv41" = "yes"])
@@ -436,6 +436,8 @@ AC_CONFIG_FILES([
tools/nlmtest/Makefile
tools/rpcdebug/Makefile
tools/rpcgen/Makefile
+ tools/mountstats/Makefile
+ tools/nfs-iostat/Makefile
utils/Makefile
utils/exportfs/Makefile
utils/gssd/Makefile
diff -up nfs-utils-1.2.2/support/export/client.c.orig nfs-utils-1.2.2/support/export/client.c
--- nfs-utils-1.2.2/support/export/client.c.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/support/export/client.c 2010-05-06 07:16:37.862057000 -0400
@@ -17,7 +17,7 @@
#include <string.h>
#include <ctype.h>
#include <netdb.h>
-#include "xmalloc.h"
+
#include "misc.h"
#include "nfslib.h"
#include "exportfs.h"
@@ -28,13 +28,116 @@
#if !defined(__GLIBC__) || __GLIBC__ < 2
extern int innetgr(char *netgr, char *host, char *, char *);
#endif
-static void client_init(nfs_client *clp, const char *hname,
- struct hostent *hp);
-static int client_checkaddr(nfs_client *clp, struct in_addr addr);
+
+static char *add_name(char *old, const char *add);
nfs_client *clientlist[MCL_MAXTYPES] = { NULL, };
+static void
+init_addrlist(nfs_client *clp, const struct hostent *hp)
+{
+ struct sockaddr_in sin = {
+ .sin_family = AF_INET,
+ };
+ char **ap;
+ int i;
+
+ if (hp == NULL)
+ return;
+
+ ap = hp->h_addr_list;
+ for (i = 0; *ap != NULL && i < NFSCLNT_ADDRMAX; i++, ap++) {
+ sin.sin_addr = *(struct in_addr *)*ap;
+ set_addrlist_in(clp, i, &sin);
+ }
+ clp->m_naddr = i;
+}
+
+static void
+client_free(nfs_client *clp)
+{
+ free(clp->m_hostname);
+ free(clp);
+}
+
+static int
+init_netmask(nfs_client *clp, const char *slash)
+{
+ struct sockaddr_in sin = {
+ .sin_family = AF_INET,
+ };
+
+ if (strchr(slash + 1, '.') != NULL)
+ sin.sin_addr.s_addr = inet_addr(slash + 1);
+ else {
+ int prefixlen = atoi(slash + 1);
+ if (0 < prefixlen && prefixlen <= 32)
+ sin.sin_addr.s_addr =
+ htonl((uint32_t)~0 << (32 - prefixlen));
+ else
+ goto out_badprefix;
+ }
+
+ set_addrlist_in(clp, 1, &sin);
+ return 1;
+
+out_badprefix:
+ xlog(L_ERROR, "Invalid prefix `%s' for %s", slash + 1, clp->m_hostname);
+ return 0;
+}
+
+static int
+init_subnetwork(nfs_client *clp)
+{
+ struct sockaddr_in sin = {
+ .sin_family = AF_INET,
+ };
+ static char slash32[] = "/32";
+ char *cp;
+
+ cp = strchr(clp->m_hostname, '/');
+ if (cp == NULL)
+ cp = slash32;
+
+ *cp = '\0';
+ sin.sin_addr.s_addr = inet_addr(clp->m_hostname);
+ set_addrlist_in(clp, 0, &sin);
+ *cp = '/';
+
+ return init_netmask(clp, cp);
+}
+
+static int
+client_init(nfs_client *clp, const char *hname, const struct hostent *hp)
+{
+ clp->m_hostname = strdup(hname);
+ if (clp->m_hostname == NULL)
+ return 0;
+
+ clp->m_exported = 0;
+ clp->m_count = 0;
+ clp->m_naddr = 0;
+
+ if (clp->m_type == MCL_SUBNETWORK)
+ return init_subnetwork(clp);
+
+ init_addrlist(clp, hp);
+ return 1;
+}
+
+static void
+client_add(nfs_client *clp)
+{
+ nfs_client **cpp;
+
+ cpp = &clientlist[clp->m_type];
+ while (*cpp != NULL)
+ cpp = &((*cpp)->m_next);
+ clp->m_next = NULL;
+ *cpp = clp;
+}
+
/* if canonical is set, then we *know* this is already a canonical name
* so hostname lookup is avoided.
* This is used when reading /proc/fs/nfs/exports
@@ -87,23 +190,23 @@ client_lookup(char *hname, int canonical
}
}
- if (!clp) {
- clp = (nfs_client *) xmalloc(sizeof(*clp));
- memset(clp, 0, sizeof(*clp));
+ if (clp == NULL) {
+ clp = calloc(1, sizeof(*clp));
+ if (clp == NULL)
+ goto out;
clp->m_type = htype;
- client_init(clp, hname, NULL);
+ if (!client_init(clp, hname, NULL)) {
+ client_free(clp);
+ clp = NULL;
+ goto out;
+ }
client_add(clp);
}
- if (htype == MCL_FQDN && clp->m_naddr == 0 && hp != NULL) {
- char **ap = hp->h_addr_list;
- int i;
-
- for (i = 0; *ap && i < NFSCLNT_ADDRMAX; i++, ap++)
- clp->m_addrlist[i] = *(struct in_addr *)*ap;
- clp->m_naddr = i;
- }
+ if (htype == MCL_FQDN && clp->m_naddr == 0)
+ init_addrlist(clp, hp);
+out:
if (hp)
free (hp);
@@ -115,78 +218,21 @@ client_dup(nfs_client *clp, struct hoste
{
nfs_client *new;
- new = (nfs_client *) xmalloc(sizeof(*new));
+ new = (nfs_client *)malloc(sizeof(*new));
+ if (new == NULL)
+ return NULL;
memcpy(new, clp, sizeof(*new));
new->m_type = MCL_FQDN;
new->m_hostname = NULL;
- client_init(new, (char *) hp->h_name, hp);
+ if (!client_init(new, hp->h_name, hp)) {
+ client_free(new);
+ return NULL;
+ }
client_add(new);
return new;
}
-static void
-client_init(nfs_client *clp, const char *hname, struct hostent *hp)
-{
- xfree(clp->m_hostname);
- if (hp)
- clp->m_hostname = xstrdup(hp->h_name);
- else
- clp->m_hostname = xstrdup(hname);
-
- clp->m_exported = 0;
- clp->m_count = 0;
-
- if (clp->m_type == MCL_SUBNETWORK) {
- char *cp = strchr(clp->m_hostname, '/');
- static char slash32[] = "/32";
-
- if(!cp) cp = slash32;
- *cp = '\0';
- clp->m_addrlist[0].s_addr = inet_addr(clp->m_hostname);
- if (strchr(cp + 1, '.')) {
- clp->m_addrlist[1].s_addr = inet_addr(cp+1);
- }
- else {
- int netmask = atoi(cp + 1);
- if (0 < netmask && netmask <= 32) {
- clp->m_addrlist[1].s_addr =
- htonl ((uint32_t) ~0 << (32 - netmask));
- }
- else {
- xlog(L_FATAL, "invalid netmask `%s' for %s",
- cp + 1, clp->m_hostname);
- }
- }
- *cp = '/';
- clp->m_naddr = 0;
- } else if (!hp) {
- clp->m_naddr = 0;
- } else {
- char **ap = hp->h_addr_list;
- int i;
-
- for (i = 0; *ap && i < NFSCLNT_ADDRMAX; i++, ap++) {
- clp->m_addrlist[i] = *(struct in_addr *)*ap;
- }
- clp->m_naddr = i;
- }
-}
-
-void
-client_add(nfs_client *clp)
-{
- nfs_client **cpp;
-
- if (clp->m_type < 0 || clp->m_type >= MCL_MAXTYPES)
- xlog(L_FATAL, "unknown client type in client_add");
- cpp = clientlist + clp->m_type;
- while (*cpp)
- cpp = &((*cpp)->m_next);
- clp->m_next = NULL;
- *cpp = clp;
-}
-
void
client_release(nfs_client *clp)
{
@@ -205,34 +251,11 @@ client_freeall(void)
head = clientlist + i;
while (*head) {
*head = (clp = *head)->m_next;
- xfree(clp->m_hostname);
- xfree(clp);
+ client_free(clp);
}
}
}
-nfs_client *
-client_find(struct hostent *hp)
-{
- nfs_client *clp;
- int i;
-
- for (i = 0; i < MCL_MAXTYPES; i++) {
- for (clp = clientlist[i]; clp; clp = clp->m_next) {
- if (!client_check(clp, hp))
- continue;
-#ifdef notdef
- if (clp->m_type == MCL_FQDN)
- return clp;
- return client_dup(clp, hp);
-#else
- return clp;
-#endif
- }
- }
- return NULL;
-}
-
struct hostent *
client_resolve(struct in_addr addr)
{
@@ -246,14 +269,18 @@ client_resolve(struct in_addr addr)
return he;
}
-/*
- * Find client name given an IP address
- * This is found by gathering all known names that match that IP address,
- * sorting them and joining them with '+'
+/**
+ * client_compose - Make a list of cached hostnames that match an IP address
+ * @he: pointer to hostent containing IP address information to match
+ *
+ * Gather all known client hostnames that match the IP address, and sort
+ * the result into a comma-separated list.
*
+ * Returns a '\0'-terminated ASCII string containing a comma-separated
+ * sorted list of client hostnames, or NULL if no client records matched
+ * the IP address or memory could not be allocated. Caller must free the
+ * returned string with free(3).
*/
-static char *add_name(char *old, char *add);
-
char *
client_compose(struct hostent *he)
{
@@ -271,13 +298,19 @@ client_compose(struct hostent *he)
return name;
}
+/**
+ * client_member - check if @name is contained in the list @client
+ * @client: '\0'-terminated ASCII string containing
+ * comma-separated list of hostnames
+ * @name: '\0'-terminated ASCII string containing hostname to look for
+ *
+ * Returns 1 if @name was found in @client, otherwise zero is returned.
+ */
int
-client_member(char *client, char *name)
+client_member(const char *client, const char *name)
{
- /* check if "client" (a ',' separated list of names)
- * contains 'name' as a member
- */
- int l = strlen(name);
+ size_t l = strlen(name);
+
while (*client) {
if (strncmp(client, name, l) == 0 &&
(client[l] == ',' || client[l] == '\0'))
@@ -290,9 +323,8 @@ client_member(char *client, char *name)
return 0;
}
-
-int
-name_cmp(char *a, char *b)
+static int
+name_cmp(const char *a, const char *b)
{
/* compare strings a and b, but only upto ',' in a */
while (*a && *b && *a != ',' && *a == *b)
@@ -305,9 +337,9 @@ name_cmp(char *a, char *b)
}
static char *
-add_name(char *old, char *add)
+add_name(char *old, const char *add)
{
- int len = strlen(add)+2;
+ size_t len = strlen(add) + 2;
char *new;
char *cp;
if (old) len += strlen(old);
@@ -340,101 +372,164 @@ add_name(char *old, char *add)
}
/*
- * Match a host (given its hostent record) to a client record. This
- * is usually called from mountd.
+ * Check each address listed in @hp against each address
+ * stored in @clp. Return 1 if a match is found, otherwise
+ * zero.
*/
-int
-client_check(nfs_client *clp, struct hostent *hp)
+static int
+check_fqdn(const nfs_client *clp, const struct hostent *hp)
{
- char *hname = (char *) hp->h_name;
- char *cname = clp->m_hostname;
- char **ap;
+ const struct sockaddr_in *sin;
+ struct in_addr addr;
+ char **ap;
+ int i;
- switch (clp->m_type) {
- case MCL_FQDN:
- case MCL_SUBNETWORK:
- for (ap = hp->h_addr_list; *ap; ap++) {
- if (client_checkaddr(clp, *(struct in_addr *) *ap))
+ for (ap = hp->h_addr_list; *ap; ap++) {
+ addr = *(struct in_addr *)*ap;
+
+ for (i = 0; i < clp->m_naddr; i++) {
+ sin = get_addrlist_in(clp, i);
+ if (sin->sin_addr.s_addr == addr.s_addr)
return 1;
}
- return 0;
- case MCL_WILDCARD:
- if (wildmat(hname, cname))
- return 1;
- else {
- for (ap = hp->h_aliases; *ap; ap++)
- if (wildmat(*ap, cname))
- return 1;
- }
- return 0;
- case MCL_NETGROUP:
-#ifdef HAVE_INNETGR
- {
- char *dot;
- int match, i;
- struct hostent *nhp = NULL;
- struct sockaddr_in addr;
-
- /* First, try to match the hostname without
- * splitting off the domain */
- if (innetgr(cname+1, hname, NULL, NULL))
- return 1;
+ }
+ return 0;
+}
- /* try the aliases as well */
- for (i = 0; hp->h_aliases[i]; i++) {
- if (innetgr(cname+1, hp->h_aliases[i], NULL, NULL))
- return 1;
- }
+/*
+ * Check each address listed in @hp against the subnetwork or
+ * host address stored in @clp. Return 1 if an address in @hp
+ * matches the host address stored in @clp, otherwise zero.
+ */
+static int
+check_subnetwork(const nfs_client *clp, const struct hostent *hp)
+{
+ const struct sockaddr_in *address, *mask;
+ struct in_addr addr;
+ char **ap;
+
+ for (ap = hp->h_addr_list; *ap; ap++) {
+ address = get_addrlist_in(clp, 0);
+ mask = get_addrlist_in(clp, 1);
+ addr = *(struct in_addr *)*ap;
- /* If hname is ip address convert to FQDN */
- if (inet_aton(hname, &addr.sin_addr) &&
- (nhp = gethostbyaddr((const char *)&(addr.sin_addr),
- sizeof(addr.sin_addr), AF_INET))) {
- hname = (char *)nhp->h_name;
- if (innetgr(cname+1, hname, NULL, NULL))
- return 1;
- }
+ if (!((address->sin_addr.s_addr ^ addr.s_addr) &
+ mask->sin_addr.s_addr))
+ return 1;
+ }
+ return 0;
+}
- /* Okay, strip off the domain (if we have one) */
- if ((dot = strchr(hname, '.')) == NULL)
- return 0;
-
- *dot = '\0';
- match = innetgr(cname+1, hname, NULL, NULL);
- *dot = '.';
+/*
+ * Check if a wildcard nfs_client record matches the canonical name
+ * or the aliases of a host. Return 1 if a match is found, otherwise
+ * zero.
+ */
+static int
+check_wildcard(const nfs_client *clp, const struct hostent *hp)
+{
+ char *cname = clp->m_hostname;
+ char *hname = hp->h_name;
+ char **ap;
- return match;
- }
-#else
- return 0;
-#endif
- case MCL_ANONYMOUS:
+ if (wildmat(hname, cname))
return 1;
- case MCL_GSS:
- return 0;
- default:
- xlog(L_FATAL, "internal: bad client type %d", clp->m_type);
+
+ /* See if hname aliases listed in /etc/hosts or nis[+]
+ * match the requested wildcard */
+ for (ap = hp->h_aliases; *ap; ap++) {
+ if (wildmat(*ap, cname))
+ return 1;
}
return 0;
}
+/*
+ * Check if @hp's hostname or aliases fall in a given netgroup.
+ * Return 1 if @hp represents a host in the netgroup, otherwise zero.
+ */
+#ifdef HAVE_INNETGR
+static int
+check_netgroup(const nfs_client *clp, const struct hostent *hp)
+{
+ const char *netgroup = clp->m_hostname + 1;
+ const char *hname = hp->h_name;
+ struct hostent *nhp = NULL;
+ struct sockaddr_in addr;
+ int match, i;
+ char *dot;
+
+ /* First, try to match the hostname without
+ * splitting off the domain */
+ if (innetgr(netgroup, hname, NULL, NULL))
+ return 1;
+
+ /* See if hname aliases listed in /etc/hosts or nis[+]
+ * match the requested netgroup */
+ for (i = 0; hp->h_aliases[i]; i++) {
+ if (innetgr(netgroup, hp->h_aliases[i], NULL, NULL))
+ return 1;
+ }
+
+ /* If hname is ip address convert to FQDN */
+ if (inet_aton(hname, &addr.sin_addr) &&
+ (nhp = gethostbyaddr((const char *)&(addr.sin_addr),
+ sizeof(addr.sin_addr), AF_INET))) {
+ hname = nhp->h_name;
+ if (innetgr(netgroup, hname, NULL, NULL))
+ return 1;
+ }
+
+ /* Okay, strip off the domain (if we have one) */
+ dot = strchr(hname, '.');
+ if (dot == NULL)
+ return 0;
+
+ *dot = '\0';
+ match = innetgr(netgroup, hname, NULL, NULL);
+ *dot = '.';
+
+ return match;
+}
+#else /* !HAVE_INNETGR */
static int
-client_checkaddr(nfs_client *clp, struct in_addr addr)
+check_netgroup(__attribute__((unused)) const nfs_client *clp,
+ __attribute__((unused)) const struct hostent *hp)
{
- int i;
+ return 0;
+}
+#endif /* !HAVE_INNETGR */
+/**
+ * client_check - check if IP address information matches a cached nfs_client
+ * @clp: pointer to a cached nfs_client record
+ * @hp: pointer to hostent containing host IP information
+ *
+ * Returns 1 if the address information matches the cached nfs_client,
+ * otherwise zero.
+ */
+int
+client_check(nfs_client *clp, struct hostent *hp)
+{
switch (clp->m_type) {
case MCL_FQDN:
- for (i = 0; i < clp->m_naddr; i++) {
- if (clp->m_addrlist[i].s_addr == addr.s_addr)
- return 1;
- }
- return 0;
+ return check_fqdn(clp, hp);
case MCL_SUBNETWORK:
- return !((clp->m_addrlist[0].s_addr ^ addr.s_addr)
- & clp->m_addrlist[1].s_addr);
+ return check_subnetwork(clp, hp);
+ case MCL_WILDCARD:
+ return check_wildcard(clp, hp);
+ case MCL_NETGROUP:
+ return check_netgroup(clp, hp);
+ case MCL_ANONYMOUS:
+ return 1;
+ case MCL_GSS:
+ return 0;
+ default:
+ xlog(D_GENERAL, "%s: unrecognized client type: %d",
+ __func__, clp->m_type);
}
+
return 0;
}
diff -up nfs-utils-1.2.2/support/export/export.c.orig nfs-utils-1.2.2/support/export/export.c
--- nfs-utils-1.2.2/support/export/export.c.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/support/export/export.c 2010-05-06 07:16:37.867057000 -0400
@@ -28,6 +28,18 @@ static int export_check(nfs_export *, st
static nfs_export *
export_allowed_internal(struct hostent *hp, char *path);
+static void
+export_free(nfs_export *exp)
+{
+ xfree(exp->m_export.e_squids);
+ xfree(exp->m_export.e_sqgids);
+ free(exp->m_export.e_mountpoint);
+ free(exp->m_export.e_fslocdata);
+
+ xfree(exp->m_export.e_hostname);
+ xfree(exp);
+}
+
static void warn_duplicated_exports(nfs_export *exp, struct exportent *eep)
{
if (exp->m_export.e_flags != eep->e_flags) {
@@ -117,6 +129,10 @@ export_dup(nfs_export *exp, struct hoste
if (exp->m_export.e_hostname)
new->m_export.e_hostname = xstrdup(exp->m_export.e_hostname);
clp = client_dup(exp->m_client, hp);
+ if (clp == NULL) {
+ export_free(new);
+ return NULL;
+ }
clp->m_count++;
new->m_client = clp;
new->m_mayexport = exp->m_mayexport;
@@ -128,6 +144,7 @@ export_dup(nfs_export *exp, struct hoste
return new;
}
+
/*
* Add export entry to hash table
*/
@@ -259,6 +276,10 @@ export_check(nfs_export *exp, struct hos
return client_check(exp->m_client, hp);
}
+/**
+ * export_freeall - deallocate all nfs_export records
+ *
+ */
void
export_freeall(void)
{
@@ -269,22 +290,13 @@ export_freeall(void)
for (exp = exportlist[i].p_head; exp; exp = nxt) {
nxt = exp->m_next;
client_release(exp->m_client);
- if (exp->m_export.e_squids)
- xfree(exp->m_export.e_squids);
- if (exp->m_export.e_sqgids)
- xfree(exp->m_export.e_sqgids);
- if (exp->m_export.e_mountpoint)
- free(exp->m_export.e_mountpoint);
- if (exp->m_export.e_fslocdata)
- xfree(exp->m_export.e_fslocdata);
- xfree(exp->m_export.e_hostname);
- xfree(exp);
+ export_free(exp);
+ }
+ for (j = 0; j < HASH_TABLE_SIZE; j++) {
+ exportlist[i].entries[j].p_first = NULL;
+ exportlist[i].entries[j].p_last = NULL;
}
- for(j = 0; j < HASH_TABLE_SIZE; j++) {
- exportlist[i].entries[j].p_first = NULL;
- exportlist[i].entries[j].p_last = NULL;
- }
- exportlist[i].p_head = NULL;
+ exportlist[i].p_head = NULL;
}
client_freeall();
}
diff -up nfs-utils-1.2.2/support/export/nfsctl.c.orig nfs-utils-1.2.2/support/export/nfsctl.c
--- nfs-utils-1.2.2/support/export/nfsctl.c.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/support/export/nfsctl.c 2010-05-06 07:16:37.872057000 -0400
@@ -66,7 +66,7 @@ str_tolower(char *s)
static int
cltsetup(struct nfsctl_client *cltarg, nfs_client *clp)
{
- int i;
+ int i, j;
if (clp->m_type != MCL_FQDN) {
xlog(L_ERROR, "internal: can't export non-FQDN host");
@@ -76,10 +76,19 @@ cltsetup(struct nfsctl_client *cltarg, n
strncpy(cltarg->cl_ident, clp->m_hostname,
sizeof (cltarg->cl_ident) - 1);
str_tolower(cltarg->cl_ident);
- cltarg->cl_naddr = clp->m_naddr;
- for (i = 0; i < cltarg->cl_naddr && i < NFSCLNT_ADDRMAX; i++)
- cltarg->cl_addrlist[i] = clp->m_addrlist[i];
+ j = 0;
+ for (i = 0; i < cltarg->cl_naddr && i < NFSCLNT_ADDRMAX; i++) {
+ struct sockaddr_in *sin = get_addrlist_in(clp, i);
+ if (sin->sin_family == AF_INET)
+ cltarg->cl_addrlist[j++] = sin->sin_addr;
+ }
+ if (j == 0) {
+ xlog(L_ERROR, "internal: no supported addresses in nfs_client");
+ return 0;
+ }
+
+ cltarg->cl_naddr = j;
return 1;
}
diff -up nfs-utils-1.2.2/support/include/exportfs.h.orig nfs-utils-1.2.2/support/include/exportfs.h
--- nfs-utils-1.2.2/support/include/exportfs.h.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/support/include/exportfs.h 2010-05-06 07:16:37.877057000 -0400
@@ -10,6 +10,8 @@
#define EXPORTFS_H
#include <netdb.h>
+
+#include "sockaddr.h"
#include "nfslib.h"
enum {
@@ -35,11 +37,56 @@ typedef struct mclient {
char * m_hostname;
int m_type;
int m_naddr;
- struct in_addr m_addrlist[NFSCLNT_ADDRMAX];
+ union nfs_sockaddr m_addrlist[NFSCLNT_ADDRMAX];
int m_exported; /* exported to nfsd */
int m_count;
} nfs_client;
+static inline const struct sockaddr *
+get_addrlist(const nfs_client *clp, const int i)
+{
+ return &clp->m_addrlist[i].sa;
+}
+
+static inline const struct sockaddr_in *
+get_addrlist_in(const nfs_client *clp, const int i)
+{
+ return &clp->m_addrlist[i].s4;
+}
+
+static inline const struct sockaddr_in6 *
+get_addrlist_in6(const nfs_client *clp, const int i)
+{
+ return &clp->m_addrlist[i].s6;
+}
+
+static inline void
+set_addrlist_in(nfs_client *clp, const int i, const struct sockaddr_in *sin)
+{
+ memcpy(&clp->m_addrlist[i].s4, sin, sizeof(*sin));
+}
+
+static inline void
+set_addrlist_in6(nfs_client *clp, const int i, const struct sockaddr_in6 *sin6)
+{
+ memcpy(&clp->m_addrlist[i].s6, sin6, sizeof(*sin6));
+}
+
+static inline void
+set_addrlist(nfs_client *clp, const int i, const struct sockaddr *sap)
+{
+ switch (sap->sa_family) {
+ case AF_INET:
+ memcpy(&clp->m_addrlist[i].s4, sap, sizeof(struct sockaddr_in));
+ break;
+#ifdef IPV6_SUPPORTED
+ case AF_INET6:
+ memcpy(&clp->m_addrlist[i].s6, sap, sizeof(struct sockaddr_in6));
+ break;
+#endif
+ }
+}
+
typedef struct mexport {
struct mexport * m_next;
struct mclient * m_client;
@@ -69,17 +116,15 @@ extern exp_hash_table exportlist[MCL_MAX
extern nfs_client * clientlist[MCL_MAXTYPES];
nfs_client * client_lookup(char *hname, int canonical);
-nfs_client * client_find(struct hostent *);
-void client_add(nfs_client *);
nfs_client * client_dup(nfs_client *, struct hostent *);
int client_gettype(char *hname);
int client_check(nfs_client *, struct hostent *);
-int client_match(nfs_client *, char *hname);
void client_release(nfs_client *);
void client_freeall(void);
char * client_compose(struct hostent *he);
struct hostent * client_resolve(struct in_addr addr);
-int client_member(char *client, char *name);
+int client_member(const char *client,
+ const char *name);
int export_read(char *fname);
void export_add(nfs_export *);
diff -up nfs-utils-1.2.2/support/include/nfslib.h.orig nfs-utils-1.2.2/support/include/nfslib.h
--- nfs-utils-1.2.2/support/include/nfslib.h.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/support/include/nfslib.h 2010-05-06 07:16:37.882059000 -0400
@@ -152,6 +152,8 @@ void qword_addhex(char **bpp, int *lp, c
void qword_addint(char **bpp, int *lp, int n);
void qword_adduint(char **bpp, int *lp, unsigned int n);
void qword_addeol(char **bpp, int *lp);
+int qword_get_uint(char **bpp, unsigned int *anint);
+void qword_printuint(FILE *f, unsigned int num);
void closeall(int min);
diff -up nfs-utils-1.2.2/support/include/nfsrpc.h.orig nfs-utils-1.2.2/support/include/nfsrpc.h
--- nfs-utils-1.2.2/support/include/nfsrpc.h.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/support/include/nfsrpc.h 2010-05-06 07:16:37.888057000 -0400
@@ -160,4 +160,7 @@ extern int nfs_rpc_ping(const struct so
const unsigned short protocol,
const struct timeval *timeout);
+/* create AUTH_SYS handle with no supplemental groups */
+extern AUTH * nfs_authsys_create(void);
+
#endif /* !__NFS_UTILS_NFSRPC_H */
diff -up nfs-utils-1.2.2/support/nfs/cacheio.c.orig nfs-utils-1.2.2/support/nfs/cacheio.c
--- nfs-utils-1.2.2/support/nfs/cacheio.c.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/support/nfs/cacheio.c 2010-05-06 07:16:37.893057000 -0400
@@ -148,6 +148,11 @@ void qword_printint(FILE *f, int num)
fprintf(f, "%d ", num);
}
+void qword_printuint(FILE *f, unsigned int num)
+{
+ fprintf(f, "%u ", num);
+}
+
int qword_eol(FILE *f)
{
int err;
@@ -236,6 +241,20 @@ int qword_get_int(char **bpp, int *anint
return 0;
}
+int qword_get_uint(char **bpp, unsigned int *anint)
+{
+ char buf[50];
+ char *ep;
+ unsigned int rv;
+ int len = qword_get(bpp, buf, 50);
+ if (len < 0) return -1;
+ if (len ==0) return -1;
+ rv = strtoul(buf, &ep, 0);
+ if (*ep) return -1;
+ *anint = rv;
+ return 0;
+}
+
#define READLINE_BUFFER_INCREMENT 2048
int readline(int fd, char **buf, int *lenp)
diff -up nfs-utils-1.2.2/support/nfs/rpc_socket.c.orig nfs-utils-1.2.2/support/nfs/rpc_socket.c
--- nfs-utils-1.2.2/support/nfs/rpc_socket.c.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/support/nfs/rpc_socket.c 2010-05-06 07:16:37.898057000 -0400
@@ -557,3 +557,24 @@ rpcprog_t nfs_getrpcbyname(const rpcprog
return program;
}
+
+/*
+ * AUTH_SYS doesn't allow more than 16 gids in the supplemental group list.
+ * If there are more than that, trying to determine which ones to include
+ * in the list is problematic. This function creates an auth handle that
+ * only has the primary gid in the supplemental gids list. It's intended to
+ * be used for protocols where credentials really don't matter much (the MNT
+ * protocol, for instance).
+ */
+AUTH *
+nfs_authsys_create(void)
+{
+ char machname[MAXHOSTNAMELEN + 1];
+ uid_t uid = geteuid();
+ gid_t gid = getegid();
+
+ if (gethostname(machname, sizeof(machname)) == -1)
+ return NULL;
+
+ return authunix_create(machname, uid, gid, 1, &gid);
+}
diff -up nfs-utils-1.2.2/support/nsm/file.c.orig nfs-utils-1.2.2/support/nsm/file.c
--- nfs-utils-1.2.2/support/nsm/file.c.orig 2010-05-06 07:15:49.888166000 -0400
+++ nfs-utils-1.2.2/support/nsm/file.c 2010-05-06 07:16:37.917057000 -0400
@@ -67,7 +67,9 @@
#endif
#include <sys/types.h>
+#ifdef HAVE_SYS_CAPABILITY_H
#include <sys/capability.h>
+#endif
#include <sys/prctl.h>
#include <sys/stat.h>
@@ -348,6 +350,7 @@ nsm_is_default_parentdir(void)
static _Bool
nsm_clear_capabilities(void)
{
+#ifdef HAVE_SYS_CAPABILITY_H
cap_t caps;
caps = cap_from_text("cap_net_bind_service=ep");
@@ -363,6 +366,7 @@ nsm_clear_capabilities(void)
}
(void)cap_free(caps);
+#endif
return true;
}
diff -up nfs-utils-1.2.2/tools/Makefile.am.orig nfs-utils-1.2.2/tools/Makefile.am
--- nfs-utils-1.2.2/tools/Makefile.am.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/tools/Makefile.am 2010-05-06 07:16:37.923062000 -0400
@@ -6,6 +6,6 @@ if CONFIG_RPCGEN
OPTDIRS += rpcgen
endif
-SUBDIRS = locktest rpcdebug nlmtest $(OPTDIRS)
+SUBDIRS = locktest rpcdebug nlmtest mountstats nfs-iostat $(OPTDIRS)
MAINTAINERCLEANFILES = Makefile.in
diff -up nfs-utils-1.2.2/tools/mountstats/Makefile.am.orig nfs-utils-1.2.2/tools/mountstats/Makefile.am
--- nfs-utils-1.2.2/tools/mountstats/Makefile.am.orig 2010-05-06 07:16:37.939040000 -0400
+++ nfs-utils-1.2.2/tools/mountstats/Makefile.am 2010-05-06 07:16:37.941038000 -0400
@@ -0,0 +1,13 @@
+## Process this file with automake to produce Makefile.in
+PYTHON_FILES = mountstats.py
+
+man8_MANS = mountstats.man
+
+EXTRA_DIST = $(man8_MANS) $(PYTHON_FILES)
+
+all-local: $(PYTHON_FILES)
+
+install-data-hook:
+ $(INSTALL) --mode 755 mountstats.py $(DESTDIR)$(sbindir)/mountstats
+
+MAINTAINERCLEANFILES=Makefile.in
diff -up nfs-utils-1.2.2/tools/mountstats/mountstats.man.orig nfs-utils-1.2.2/tools/mountstats/mountstats.man
--- nfs-utils-1.2.2/tools/mountstats/mountstats.man.orig 2010-05-06 07:16:37.944036000 -0400
+++ nfs-utils-1.2.2/tools/mountstats/mountstats.man 2010-05-06 07:16:37.945043000 -0400
@@ -0,0 +1,32 @@
+.\"
+.\" mountstats(8)
+.\"
+.TH mountstats 8 "15 Apr 2010"
+.SH NAME
+mountstats \- Displays NFS client per-mount statistics
+.SH SYNOPSIS
+.BI "mountstats ["<options> "] " <mount_point> " [ " <mount_point> "]"
+.SH DESCRIPTION
+The
+.B mountstats
+command displays NFS client statisitics on each given
+.I <mount_point>
+.SH OPTIONS
+.TP
+.B " \-\-nfs
+display only the NFS statistics
+.TP
+.B " \-\-rpc
+display only the RPC statistics
+.TP
+.B " \-\-version
+display the version of this command
+.SH FILES
+.TP
+.B /proc/self/mountstats
+.SH SEE ALSO
+.BR iostat (8),
+.BR nfsiostat (8),
+.BR nfsstat(8)
+.SH AUTHOR
+Chuck Lever <chuck.lever@oracle.com>
diff -up nfs-utils-1.2.2/tools/nfs-iostat/Makefile.am.orig nfs-utils-1.2.2/tools/nfs-iostat/Makefile.am
--- nfs-utils-1.2.2/tools/nfs-iostat/Makefile.am.orig 2010-05-06 07:16:37.958021000 -0400
+++ nfs-utils-1.2.2/tools/nfs-iostat/Makefile.am 2010-05-06 07:16:37.960024000 -0400
@@ -0,0 +1,13 @@
+## Process this file with automake to produce Makefile.in
+PYTHON_FILES = nfs-iostat.py
+
+man8_MANS = nfsiostat.man
+
+EXTRA_DIST = $(man8_MANS) $(PYTHON_FILES)
+
+all-local: $(PYTHON_FILES)
+
+install-data-hook:
+ $(INSTALL) --mode 755 nfs-iostat.py $(DESTDIR)$(sbindir)/nfsiostat
+
+MAINTAINERCLEANFILES=Makefile.in
diff -up nfs-utils-1.2.2/tools/nfs-iostat/nfsiostat.man.orig nfs-utils-1.2.2/tools/nfs-iostat/nfsiostat.man
--- nfs-utils-1.2.2/tools/nfs-iostat/nfsiostat.man.orig 2010-05-06 07:16:37.963021000 -0400
+++ nfs-utils-1.2.2/tools/nfs-iostat/nfsiostat.man 2010-05-06 07:16:37.965018000 -0400
@@ -0,0 +1,70 @@
+.\"
+.\" nfsiostat(8)
+.\"
+.TH nfsiostat 8 "15 Apr 2010"
+.SH NAME
+nfsiostat \- Emulate iostat for NFS mount points using /proc/self/mountstats
+.SH SYNOPSIS
+.BI "nfsiostat [[" <interval> "] [" <count> "]] [" <options> "]["<mount_point> "]
+.SH DESCRIPTION
+The
+.B nfsiostat
+command displays NFS client per-mount statisitics.
+.TP
+<interval>
+specifies the amount of time in seconds between each report.
+The first report contains statistics for the time since each file
+system was mounted. Each subsequent report contains statistics collected
+during the interval since the previous report.
+.TP
+<count>
+If the
+.I <count>
+parameter is
+specified, the value of
+.I <count>
+determines the number of reports generated at
+. <interval>
+seconds apart. if the interval parameter is
+specified without the
+.I <count>
+parameter, the command generates reports continuously.
+.TP
+<options>
+Define below
+.TP
+<mount_point>
+If one or more
+.I <mount point>
+names are specified, statistics for only these mount points will
+be displayed. Otherwise, all NFS mount points on the client are listed.
+.SH OPTIONS
+.TP
+.B \-a " or " \-\-attr
+displays statistics related to the attribute cache
+.TP
+.B \-d " or " \-\-dir
+displays statistics related to directory operations
+.TP
+.B \-h " or " \-\-help
+shows help message and exit
+.TP
+.B \-l LIST or " \-\-list=LIST
+only print stats for first LIST mount points
+.TP
+.B \-p " or " \-\-page
+displays statistics related to the page cache
+.TP
+.B \-s " or " \-\-sort
+Sort NFS mount points by ops/second
+.B \-\-version
+show program's version number and exit
+.SH FILES
+.TP
+.B /proc/self/mountstats
+.SH SEE ALSO
+.BR iostat (8),
+.BR mountstats (8),
+.BR nfsstat(8)
+.SH AUTHOR
+Chuck Lever <chuck.lever@oracle.com>
diff -up nfs-utils-1.2.2/utils/gssd/context.h.orig nfs-utils-1.2.2/utils/gssd/context.h
--- nfs-utils-1.2.2/utils/gssd/context.h.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/utils/gssd/context.h 2010-05-06 07:16:37.970009000 -0400
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2004 The Regents of the University of Michigan.
+ Copyright (c) 2004,2008 The Regents of the University of Michigan.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -36,6 +36,10 @@
/* Hopefully big enough to hold any serialized context */
#define MAX_CTX_LEN 4096
+/* New context format flag values */
+#define KRB5_CTX_FLAG_INITIATOR 0x00000001
+#define KRB5_CTX_FLAG_CFX 0x00000002
+#define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004
int serialize_context_for_kernel(gss_ctx_id_t ctx, gss_buffer_desc *buf,
gss_OID mech, int32_t *endtime);
diff -up nfs-utils-1.2.2/utils/gssd/context_lucid.c.orig nfs-utils-1.2.2/utils/gssd/context_lucid.c
--- nfs-utils-1.2.2/utils/gssd/context_lucid.c.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/utils/gssd/context_lucid.c 2010-05-06 07:16:37.975007000 -0400
@@ -42,6 +42,7 @@
#include <stdio.h>
#include <syslog.h>
#include <string.h>
+#include <errno.h>
#include <gssapi/gssapi_krb5.h>
@@ -119,15 +120,13 @@ prepare_krb5_rfc1964_buffer(gss_krb5_luc
* Note that the rfc1964 version only supports DES enctypes.
*/
if (lctx->rfc1964_kd.ctx_key.type != 4) {
- printerr(1, "prepare_krb5_rfc1964_buffer: "
- "overriding heimdal keytype (%d => %d)\n",
- lctx->rfc1964_kd.ctx_key.type, 4);
+ printerr(2, "%s: overriding heimdal keytype (%d => %d)\n",
+ __FUNCTION__, lctx->rfc1964_kd.ctx_key.type, 4);
lctx->rfc1964_kd.ctx_key.type = 4;
}
#endif
- printerr(2, "prepare_krb5_rfc1964_buffer: serializing keys with "
- "enctype %d and length %d\n",
- lctx->rfc1964_kd.ctx_key.type,
+ printerr(2, "%s: serializing keys with enctype %d and length %d\n",
+ __FUNCTION__, lctx->rfc1964_kd.ctx_key.type,
lctx->rfc1964_kd.ctx_key.length);
/* derive the encryption key and copy it into buffer */
@@ -158,11 +157,100 @@ out_err:
return -1;
}
+/* Flags for version 2 context flags */
+#define KRB5_CTX_FLAG_INITIATOR 0x00000001
+#define KRB5_CTX_FLAG_CFX 0x00000002
+#define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004
+
+/*
+ * Prepare a new-style buffer, as defined in rfc4121 (a.k.a. cfx),
+ * to send to the kernel for newer encryption types -- or for DES3.
+ *
+ * The new format is:
+ *
+ * u32 flags;
+ * #define KRB5_CTX_FLAG_INITIATOR 0x00000001
+ * #define KRB5_CTX_FLAG_CFX 0x00000002
+ * #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004
+ * s32 endtime;
+ * u64 seq_send;
+ * u32 enctype; ( encrption type of key )
+ * raw key; ( raw key bytes (kernel will derive))
+ *
+ */
static int
-prepare_krb5_rfc_cfx_buffer(gss_krb5_lucid_context_v1_t *lctx,
+prepare_krb5_rfc4121_buffer(gss_krb5_lucid_context_v1_t *lctx,
gss_buffer_desc *buf, int32_t *endtime)
{
- printerr(0, "ERROR: prepare_krb5_rfc_cfx_buffer: not implemented\n");
+ char *p, *end;
+ uint32_t v2_flags = 0;
+ uint32_t enctype;
+ uint32_t keysize;
+
+ if (!(buf->value = calloc(1, MAX_CTX_LEN)))
+ goto out_err;
+ p = buf->value;
+ end = buf->value + MAX_CTX_LEN;
+
+ /* Version 2 */
+ if (lctx->initiate)
+ v2_flags |= KRB5_CTX_FLAG_INITIATOR;
+ if (lctx->protocol != 0)
+ v2_flags |= KRB5_CTX_FLAG_CFX;
+ if (lctx->protocol != 0 && lctx->cfx_kd.have_acceptor_subkey == 1)
+ v2_flags |= KRB5_CTX_FLAG_ACCEPTOR_SUBKEY;
+
+ if (WRITE_BYTES(&p, end, v2_flags)) goto out_err;
+ if (WRITE_BYTES(&p, end, lctx->endtime)) goto out_err;
+ if (WRITE_BYTES(&p, end, lctx->send_seq)) goto out_err;
+
+ /* Protocol 0 here implies DES3 or RC4 */
+ printerr(2, "%s: protocol %d\n", __FUNCTION__, lctx->protocol);
+ if (lctx->protocol == 0) {
+ enctype = lctx->rfc1964_kd.ctx_key.type;
+ keysize = lctx->rfc1964_kd.ctx_key.length;
+ } else {
+ if (lctx->cfx_kd.have_acceptor_subkey) {
+ enctype = lctx->cfx_kd.acceptor_subkey.type;
+ keysize = lctx->cfx_kd.acceptor_subkey.length;
+ } else {
+ enctype = lctx->cfx_kd.ctx_key.type;
+ keysize = lctx->cfx_kd.ctx_key.length;
+ }
+ }
+ printerr(2, "%s: serializing key with enctype %d and size %d\n",
+ __FUNCTION__, enctype, keysize);
+
+ if (WRITE_BYTES(&p, end, enctype)) goto out_err;
+
+ if (lctx->protocol == 0) {
+ if (write_bytes(&p, end, lctx->rfc1964_kd.ctx_key.data,
+ lctx->rfc1964_kd.ctx_key.length))
+ goto out_err;
+ } else {
+ if (lctx->cfx_kd.have_acceptor_subkey) {
+ if (write_bytes(&p, end,
+ lctx->cfx_kd.acceptor_subkey.data,
+ lctx->cfx_kd.acceptor_subkey.length))
+ goto out_err;
+ } else {
+ if (write_bytes(&p, end, lctx->cfx_kd.ctx_key.data,
+ lctx->cfx_kd.ctx_key.length))
+ goto out_err;
+ }
+ }
+
+ buf->length = p - (char *)buf->value;
+ return 0;
+
+out_err:
+ printerr(0, "ERROR: %s: failed serializing krb5 context for kernel\n",
+ __FUNCTION__);
+ if (buf->value) {
+ free(buf->value);
+ buf->value = NULL;
+ }
+ buf->length = 0;
return -1;
}
@@ -176,7 +264,7 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss
gss_krb5_lucid_context_v1_t *lctx = 0;
int retcode = 0;
- printerr(2, "DEBUG: serialize_krb5_ctx: lucid version!\n");
+ printerr(2, "DEBUG: %s: lucid version!\n", __FUNCTION__);
maj_stat = gss_export_lucid_sec_context(&min_stat, &ctx,
1, &return_ctx);
if (maj_stat != GSS_S_COMPLETE) {
@@ -198,11 +286,20 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss
break;
}
- /* Now lctx points to a lucid context that we can send down to kernel */
- if (lctx->protocol == 0)
+ /*
+ * Now lctx points to a lucid context that we can send down to kernel
+ *
+ * Note: we send down different information to the kernel depending
+ * on the protocol version and the enctyption type.
+ * For protocol version 0 with all enctypes besides DES3, we use
+ * the original format. For protocol version != 0 or DES3, we
+ * send down the new style information.
+ */
+
+ if (lctx->protocol == 0 && lctx->rfc1964_kd.ctx_key.type <= 4)
retcode = prepare_krb5_rfc1964_buffer(lctx, buf, endtime);
else
- retcode = prepare_krb5_rfc_cfx_buffer(lctx, buf, endtime);
+ retcode = prepare_krb5_rfc4121_buffer(lctx, buf, endtime);
maj_stat = gss_free_lucid_sec_context(&min_stat, ctx, return_ctx);
if (maj_stat != GSS_S_COMPLETE) {
@@ -212,8 +309,8 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss
}
if (retcode) {
- printerr(1, "serialize_krb5_ctx: prepare_krb5_*_buffer "
- "failed (retcode = %d)\n", retcode);
+ printerr(1, "%s: prepare_krb5_*_buffer failed (retcode = %d)\n",
+ __FUNCTION__, retcode);
goto out_err;
}
@@ -223,4 +320,7 @@ out_err:
printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
return -1;
}
+
+
+
#endif /* HAVE_LUCID_CONTEXT_SUPPORT */
diff -up nfs-utils-1.2.2/utils/gssd/context_mit.c.orig nfs-utils-1.2.2/utils/gssd/context_mit.c
--- nfs-utils-1.2.2/utils/gssd/context_mit.c.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/utils/gssd/context_mit.c 2010-05-06 07:16:37.980998000 -0400
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2004 The Regents of the University of Michigan.
+ Copyright (c) 2004-2006 The Regents of the University of Michigan.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -38,6 +38,7 @@
#include <stdio.h>
#include <syslog.h>
#include <string.h>
+#include <errno.h>
#include <gssapi/gssapi.h>
#include <rpc/rpc.h>
#include <rpc/auth_gss.h>
@@ -52,8 +53,7 @@
/* XXX argggg, there's gotta be a better way than just duplicating this
* whole struct. Unfortunately, this is in a "private" header file,
* so this is our best choice at this point :-/
- *
- * XXX Does this match the Heimdal definition? */
+ */
typedef struct _krb5_gss_ctx_id_rec {
unsigned int initiate : 1; /* nonzero if initiating, zero if accepting */
@@ -156,50 +156,120 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss
{
krb5_gss_ctx_id_t kctx = ((gss_union_ctx_id_t)ctx)->internal_ctx_id;
char *p, *end;
- static int constant_one = 1;
static int constant_zero = 0;
+ static int constant_one = 1;
+ static int constant_two = 2;
uint32_t word_seq_send;
+ u_int64_t seq_send_64bit;
+ uint32_t v2_flags = 0;
if (!(buf->value = calloc(1, MAX_CTX_LEN)))
goto out_err;
p = buf->value;
end = buf->value + MAX_CTX_LEN;
- if (kctx->initiate) {
- if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
- }
- else {
- if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
- }
- if (kctx->seed_init) {
- if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
- }
- else {
- if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
- }
- if (write_bytes(&p, end, &kctx->seed, sizeof(kctx->seed)))
+ switch (kctx->enc->enctype) {
+ case ENCTYPE_DES_CBC_CRC:
+ case ENCTYPE_DES_CBC_MD4:
+ case ENCTYPE_DES_CBC_MD5:
+ case ENCTYPE_DES_CBC_RAW:
+ /* Old format of context to the kernel */
+ if (kctx->initiate) {
+ if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
+ }
+ else {
+ if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
+ }
+ if (kctx->seed_init) {
+ if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
+ }
+ else {
+ if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
+ }
+ if (write_bytes(&p, end, &kctx->seed, sizeof(kctx->seed)))
+ goto out_err;
+ if (WRITE_BYTES(&p, end, kctx->signalg)) goto out_err;
+ if (WRITE_BYTES(&p, end, kctx->sealalg)) goto out_err;
+ if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err;
+ word_seq_send = kctx->seq_send;
+ if (WRITE_BYTES(&p, end, word_seq_send)) goto out_err;
+ if (write_oid(&p, end, kctx->mech_used)) goto out_err;
+
+ printerr(2, "serialize_krb5_ctx: serializing keys with "
+ "enctype %d and length %d\n",
+ kctx->enc->enctype, kctx->enc->length);
+
+ if (write_keyblock(&p, end, kctx->enc)) goto out_err;
+ if (write_keyblock(&p, end, kctx->seq)) goto out_err;
+ break;
+ case ENCTYPE_DES3_CBC_RAW:
+ case ENCTYPE_DES3_CBC_SHA1:
+ case ENCTYPE_ARCFOUR_HMAC:
+ case ENCTYPE_ARCFOUR_HMAC_EXP:
+ case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
+ case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
+ /* New format of context to the kernel */
+ /* u32 flags;
+ * #define KRB5_CTX_FLAG_INITIATOR 0x00000001
+ * #define KRB5_CTX_FLAG_CFX 0x00000002
+ * #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004
+ * s32 endtime;
+ * u64 seq_send;
+ * u32 enctype;
+ * rawkey data
+ */
+
+ if (kctx->initiate)
+ v2_flags |= KRB5_CTX_FLAG_INITIATOR;
+ if (kctx->proto == 1)
+ v2_flags |= KRB5_CTX_FLAG_CFX;
+ if (kctx->have_acceptor_subkey)
+ v2_flags |= KRB5_CTX_FLAG_ACCEPTOR_SUBKEY;
+ if (WRITE_BYTES(&p, end, v2_flags)) goto out_err;
+ if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err;
+
+ seq_send_64bit = kctx->seq_send;
+ if (WRITE_BYTES(&p, end, seq_send_64bit)) goto out_err;
+
+ if (kctx->have_acceptor_subkey) {
+ if (WRITE_BYTES(&p, end, kctx->acceptor_subkey->enctype))
+ goto out_err;
+ printerr(2, "serialize_krb5_ctx: serializing subkey "
+ "with enctype %d and size %d\n",
+ kctx->acceptor_subkey->enctype,
+ kctx->acceptor_subkey->length);
+
+ if (write_bytes(&p, end,
+ kctx->acceptor_subkey->contents,
+ kctx->acceptor_subkey->length))
+ goto out_err;
+ } else {
+ if (WRITE_BYTES(&p, end, kctx->enc->enctype))
+ goto out_err;
+ printerr(2, "serialize_krb5_ctx: serializing key "
+ "with enctype %d and size %d\n",
+ kctx->enc->enctype, kctx->enc->length);
+
+ if (write_bytes(&p, end, kctx->enc->contents,
+ kctx->enc->length))
+ goto out_err;
+ }
+ break;
+ default:
+ printerr(0, "ERROR: serialize_krb5_ctx: unsupported encryption "
+ "algorithm %d\n", kctx->enc->enctype);
goto out_err;
- if (WRITE_BYTES(&p, end, kctx->signalg)) goto out_err;
- if (WRITE_BYTES(&p, end, kctx->sealalg)) goto out_err;
- if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err;
- if (endtime)
- *endtime = kctx->endtime;
- word_seq_send = kctx->seq_send;
- if (WRITE_BYTES(&p, end, word_seq_send)) goto out_err;
- if (write_oid(&p, end, kctx->mech_used)) goto out_err;
-
- printerr(2, "serialize_krb5_ctx: serializing keys with "
- "enctype %d and length %d\n",
- kctx->enc->enctype, kctx->enc->length);
-
- if (write_keyblock(&p, end, kctx->enc)) goto out_err;
- if (write_keyblock(&p, end, kctx->seq)) goto out_err;
+ }
buf->length = p - (char *)buf->value;
return 0;
+
out_err:
printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
- if (buf->value) free(buf->value);
+ if (buf->value) {
+ free(buf->value);
+ }
+ buf->value = NULL;
buf->length = 0;
return -1;
}
diff -up nfs-utils-1.2.2/utils/gssd/gssd_proc.c.orig nfs-utils-1.2.2/utils/gssd/gssd_proc.c
--- nfs-utils-1.2.2/utils/gssd/gssd_proc.c.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/utils/gssd/gssd_proc.c 2010-05-06 07:16:37.986992000 -0400
@@ -600,6 +600,67 @@ update_client_list(void)
return retval;
}
+/* Encryption types supported by the kernel rpcsec_gss code */
+int num_krb5_enctypes = 0;
+krb5_enctype *krb5_enctypes = NULL;
+
+/*
+ * Parse the supported encryption type information
+ */
+static int
+parse_enctypes(char *enctypes)
+{
+ int n = 0;
+ char *curr, *comma;
+ int i;
+ static char *cached_types;
+
+ if (cached_types && strcmp(cached_types, enctypes) == 0)
+ return 0;
+ free(cached_types);
+
+ if (krb5_enctypes != NULL) {
+ free(krb5_enctypes);
+ krb5_enctypes = NULL;
+ num_krb5_enctypes = 0;
+ }
+
+ /* count the number of commas */
+ for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) {
+ comma = strchr(curr, ',');
+ if (comma != NULL)
+ n++;
+ else
+ break;
+ }
+ /* If no more commas and we're not at the end, there's one more value */
+ if (*curr != '\0')
+ n++;
+
+ /* Empty string, return an error */
+ if (n == 0)
+ return ENOENT;
+
+ /* Allocate space for enctypes array */
+ if ((krb5_enctypes = (int *) calloc(n, sizeof(int))) == NULL) {
+ return ENOMEM;
+ }
+
+ /* Now parse each value into the array */
+ for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) {
+ krb5_enctypes[i++] = atoi(curr);
+ comma = strchr(curr, ',');
+ if (comma == NULL)
+ break;
+ }
+
+ num_krb5_enctypes = n;
+ if ((cached_types = malloc(strlen(enctypes)+1)))
+ strcpy(cached_types, enctypes);
+
+ return 0;
+}
+
static int
do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
gss_buffer_desc *context_token)
@@ -1133,6 +1194,7 @@ handle_gssd_upcall(struct clnt_info *clp
char *mech = NULL;
char *target = NULL;
char *service = NULL;
+ char *enctypes = NULL;
printerr(1, "handling gssd upcall (%s)\n", clp->dirname);
@@ -1176,6 +1238,23 @@ handle_gssd_upcall(struct clnt_info *clp
goto out;
}
+ /* read supported encryption types if supplied */
+ if ((p = strstr(lbuf, "enctypes=")) != NULL) {
+ enctypes = malloc(lbuflen);
+ if (!enctypes)
+ goto out;
+ if (sscanf(p, "enctypes=%s", enctypes) != 1) {
+ printerr(0, "WARNING: handle_gssd_upcall: "
+ "failed to parse target name "
+ "in upcall string '%s'\n", lbuf);
+ goto out;
+ }
+ if (parse_enctypes(enctypes) != 0) {
+ printerr(0, "WARNING: handle_gssd_upcall: "
+ "parsing encryption types failed: errno %d\n", errno);
+ }
+ }
+
/* read target name */
if ((p = strstr(lbuf, "target=")) != NULL) {
target = malloc(lbuflen);
@@ -1222,6 +1301,7 @@ handle_gssd_upcall(struct clnt_info *clp
out:
free(lbuf);
free(mech);
+ free(enctypes);
free(target);
free(service);
return;
diff -up nfs-utils-1.2.2/utils/gssd/krb5_util.c.orig nfs-utils-1.2.2/utils/gssd/krb5_util.c
--- nfs-utils-1.2.2/utils/gssd/krb5_util.c.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/utils/gssd/krb5_util.c 2010-05-06 07:16:37.992992000 -0400
@@ -292,61 +292,6 @@ gssd_find_existing_krb5_ccache(uid_t uid
return err;
}
-
-#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
-/*
- * this routine obtains a credentials handle via gss_acquire_cred()
- * then calls gss_krb5_set_allowable_enctypes() to limit the encryption
- * types negotiated.
- *
- * XXX Should call some function to determine the enctypes supported
- * by the kernel. (Only need to do that once!)
- *
- * Returns:
- * 0 => all went well
- * -1 => there was an error
- */
-
-int
-limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid)
-{
- u_int maj_stat, min_stat;
- gss_cred_id_t credh;
- gss_OID_set_desc desired_mechs;
- krb5_enctype enctypes[] = { ENCTYPE_DES_CBC_CRC,
- ENCTYPE_DES_CBC_MD5,
- ENCTYPE_DES_CBC_MD4 };
- int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]);
-
- /* We only care about getting a krb5 cred */
- desired_mechs.count = 1;
- desired_mechs.elements = &krb5oid;
-
- maj_stat = gss_acquire_cred(&min_stat, NULL, 0,
- &desired_mechs, GSS_C_INITIATE,
- &credh, NULL, NULL);
-
- if (maj_stat != GSS_S_COMPLETE) {
- if (get_verbosity() > 0)
- pgsserr("gss_acquire_cred",
- maj_stat, min_stat, &krb5oid);
- return -1;
- }
-
- maj_stat = gss_set_allowable_enctypes(&min_stat, credh, &krb5oid,
- num_enctypes, &enctypes);
- if (maj_stat != GSS_S_COMPLETE) {
- pgsserr("gss_set_allowable_enctypes",
- maj_stat, min_stat, &krb5oid);
- gss_release_cred(&min_stat, &credh);
- return -1;
- }
- sec->cred = credh;
-
- return 0;
-}
-#endif /* HAVE_SET_ALLOWABLE_ENCTYPES */
-
/*
* Obtain credentials via a key in the keytab given
* a keytab handle and a gssd_k5_kt_princ structure.
@@ -1304,3 +1249,68 @@ gssd_k5_get_default_realm(char **def_rea
krb5_free_context(context);
}
+
+#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
+/*
+ * this routine obtains a credentials handle via gss_acquire_cred()
+ * then calls gss_krb5_set_allowable_enctypes() to limit the encryption
+ * types negotiated.
+ *
+ * XXX Should call some function to determine the enctypes supported
+ * by the kernel. (Only need to do that once!)
+ *
+ * Returns:
+ * 0 => all went well
+ * -1 => there was an error
+ */
+
+int
+limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid)
+{
+ u_int maj_stat, min_stat;
+ gss_cred_id_t credh;
+ gss_OID_set_desc desired_mechs;
+ krb5_enctype enctypes[] = { ENCTYPE_DES_CBC_CRC,
+ ENCTYPE_DES_CBC_MD5,
+ ENCTYPE_DES_CBC_MD4 };
+ int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]);
+ extern int num_krb5_enctypes;
+ extern krb5_enctype *krb5_enctypes;
+
+ /* We only care about getting a krb5 cred */
+ desired_mechs.count = 1;
+ desired_mechs.elements = &krb5oid;
+
+ maj_stat = gss_acquire_cred(&min_stat, NULL, 0,
+ &desired_mechs, GSS_C_INITIATE,
+ &credh, NULL, NULL);
+
+ if (maj_stat != GSS_S_COMPLETE) {
+ if (get_verbosity() > 0)
+ pgsserr("gss_acquire_cred",
+ maj_stat, min_stat, &krb5oid);
+ return -1;
+ }
+
+ /*
+ * If we failed for any reason to produce global
+ * list of supported enctypes, use local default here.
+ */
+ if (krb5_enctypes == NULL)
+ maj_stat = gss_set_allowable_enctypes(&min_stat, credh,
+ &krb5oid, num_enctypes, enctypes);
+ else
+ maj_stat = gss_set_allowable_enctypes(&min_stat, credh,
+ &krb5oid, num_krb5_enctypes, krb5_enctypes);
+
+ if (maj_stat != GSS_S_COMPLETE) {
+ pgsserr("gss_set_allowable_enctypes",
+ maj_stat, min_stat, &krb5oid);
+ gss_release_cred(&min_stat, &credh);
+ return -1;
+ }
+ sec->cred = credh;
+
+ return 0;
+}
+#endif /* HAVE_SET_ALLOWABLE_ENCTYPES */
diff -up nfs-utils-1.2.2/utils/mountd/auth.c.orig nfs-utils-1.2.2/utils/mountd/auth.c
--- nfs-utils-1.2.2/utils/mountd/auth.c.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/utils/mountd/auth.c 2010-05-06 07:16:38.009992000 -0400
@@ -142,7 +142,7 @@ auth_authenticate_newcache(char *what, s
return NULL;
my_client.m_naddr = 1;
- my_client.m_addrlist[0] = caller->sin_addr;
+ set_addrlist_in(&my_client, 0, caller);
my_exp.m_client = &my_client;
exp = NULL;
diff -up nfs-utils-1.2.2/utils/mountd/cache.c.orig nfs-utils-1.2.2/utils/mountd/cache.c
--- nfs-utils-1.2.2/utils/mountd/cache.c.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/utils/mountd/cache.c 2010-05-06 07:16:38.014995000 -0400
@@ -125,7 +125,7 @@ void auth_unix_gid(FILE *f)
* reply is
* uid expiry count list of group ids
*/
- int uid;
+ uid_t uid;
struct passwd *pw;
gid_t glist[100], *groups = glist;
int ngroups = 100;
@@ -136,7 +136,7 @@ void auth_unix_gid(FILE *f)
return;
cp = lbuf;
- if (qword_get_int(&cp, &uid) != 0)
+ if (qword_get_uint(&cp, &uid) != 0)
return;
pw = getpwuid(uid);
@@ -153,14 +153,14 @@ void auth_unix_gid(FILE *f)
groups, &ngroups);
}
}
- qword_printint(f, uid);
- qword_printint(f, time(0)+30*60);
+ qword_printuint(f, uid);
+ qword_printuint(f, time(0)+30*60);
if (rv >= 0) {
- qword_printint(f, ngroups);
+ qword_printuint(f, ngroups);
for (i=0; i<ngroups; i++)
- qword_printint(f, groups[i]);
+ qword_printuint(f, groups[i]);
} else
- qword_printint(f, 0);
+ qword_printuint(f, 0);
qword_eol(f);
if (groups != glist)
@@ -614,12 +614,12 @@ static int dump_to_cache(FILE *f, char *
return qword_eol(f);
}
-static int is_subdirectory(char *subpath, char *path)
+static int is_subdirectory(char *child, char *parent)
{
- int l = strlen(path);
+ int l = strlen(parent);
- return strcmp(subpath, path) == 0
- || (strncmp(subpath, path, l) == 0 && path[l] == '/');
+ return strcmp(child, parent) == 0
+ || (strncmp(child, parent, l) == 0 && child[l] == '/');
}
static int path_matches(nfs_export *exp, char *path)
@@ -863,6 +863,7 @@ int cache_export_ent(char *domain, struc
int cache_export(nfs_export *exp, char *path)
{
+ struct sockaddr_in *sin = get_addrlist_in(exp->m_client, 0);
int err;
FILE *f;
@@ -871,7 +872,7 @@ int cache_export(nfs_export *exp, char *
return -1;
qword_print(f, "nfsd");
- qword_print(f, inet_ntoa(exp->m_client->m_addrlist[0]));
+ qword_print(f, inet_ntoa(sin->sin_addr));
qword_printint(f, time(0)+30*60);
qword_print(f, exp->m_client->m_hostname);
err = qword_eol(f);
diff -up nfs-utils-1.2.2/utils/mount/network.c.orig nfs-utils-1.2.2/utils/mount/network.c
--- nfs-utils-1.2.2/utils/mount/network.c.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/utils/mount/network.c 2010-05-06 07:16:37.998992000 -0400
@@ -857,7 +857,14 @@ int nfs_advise_umount(const struct socka
return 0;
}
- client->cl_auth = authunix_create_default();
+ client->cl_auth = nfs_authsys_create();
+ if (client->cl_auth == NULL) {
+ if (verbose)
+ nfs_error(_("%s: Failed to create RPC auth handle"),
+ progname);
+ CLNT_DESTROY(client);
+ return 0;
+ }
res = CLNT_CALL(client, MOUNTPROC_UMNT,
(xdrproc_t)xdr_dirpath, (caddr_t)argp,
@@ -957,8 +964,10 @@ CLIENT *mnt_openclnt(clnt_addr_t *mnt_se
}
if (clnt) {
/* try to mount hostname:dirname */
- clnt->cl_auth = authunix_create_default();
- return clnt;
+ clnt->cl_auth = nfs_authsys_create();
+ if (clnt->cl_auth)
+ return clnt;
+ CLNT_DESTROY(clnt);
}
return NULL;
}
diff -up nfs-utils-1.2.2/utils/mount/stropts.c.orig nfs-utils-1.2.2/utils/mount/stropts.c
--- nfs-utils-1.2.2/utils/mount/stropts.c.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/utils/mount/stropts.c 2010-05-06 07:16:38.004992000 -0400
@@ -799,6 +799,7 @@ static int nfs_is_permanent_error(int er
case ESTALE:
case ETIMEDOUT:
case ECONNREFUSED:
+ case EHOSTUNREACH:
return 0; /* temporary */
default:
return 1; /* permanent */
diff -up nfs-utils-1.2.2/utils/showmount/showmount.c.orig nfs-utils-1.2.2/utils/showmount/showmount.c
--- nfs-utils-1.2.2/utils/showmount/showmount.c.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/utils/showmount/showmount.c 2010-05-06 07:16:38.019995000 -0400
@@ -194,7 +194,13 @@ int main(int argc, char **argv)
}
mclient = nfs_get_mount_client(hostname, mount_vers_tbl[vers]);
- mclient->cl_auth = authunix_create_default();
+ mclient->cl_auth = nfs_authsys_create();
+ if (mclient->cl_auth == NULL) {
+ fprintf(stderr, "%s: unable to create RPC auth handle.\n",
+ program_name);
+ clnt_destroy(mclient);
+ exit(1);
+ }
total_timeout.tv_sec = TOTAL_TIMEOUT;
total_timeout.tv_usec = 0;
diff -up nfs-utils-1.2.2/utils/statd/sm-notify.c.orig nfs-utils-1.2.2/utils/statd/sm-notify.c
--- nfs-utils-1.2.2/utils/statd/sm-notify.c.orig 2010-02-18 07:35:00.000000000 -0500
+++ nfs-utils-1.2.2/utils/statd/sm-notify.c 2010-05-06 07:16:38.025992000 -0400
@@ -54,7 +54,7 @@ struct nsm_host {
uint32_t xid;
};
-static char nsm_hostname[256];
+static char nsm_hostname[SM_MAXSTRLEN + 1];
static int nsm_state;
static int nsm_family = AF_INET;
static int opt_debug = 0;
@@ -412,12 +412,33 @@ usage: fprintf(stderr,
}
}
- if (opt_srcaddr) {
- strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname)-1);
- } else
- if (gethostname(nsm_hostname, sizeof(nsm_hostname)) < 0) {
- xlog(L_ERROR, "Failed to obtain name of local host: %m");
- exit(1);
+ if (opt_srcaddr != NULL) {
+ struct addrinfo *ai = NULL;
+ struct addrinfo hint = {
+ .ai_family = AF_UNSPEC,
+ .ai_flags = AI_NUMERICHOST,
+ };
+
+ if (getaddrinfo(opt_srcaddr, NULL, &hint, &ai))
+ /* not a presentation address - use it */
+ strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname));
+ else {
+ /* was a presentation address - look it up in
+ * /etc/hosts, so it can be used for my_name */
+ int error;
+
+ freeaddrinfo(ai);
+ hint.ai_flags = AI_CANONNAME;
+ error = getaddrinfo(opt_srcaddr, NULL, &hint, &ai);
+ if (error != 0) {
+ xlog(L_ERROR, "Bind address %s is unusable: %s",
+ opt_srcaddr, gai_strerror(error));
+ exit(1);
+ }
+ strncpy(nsm_hostname, ai->ai_canonname,
+ sizeof(nsm_hostname));
+ freeaddrinfo(ai);
+ }
}
(void)nsm_retire_monitored_hosts();
@@ -535,6 +556,8 @@ notify(const int sock)
static int
notify_host(int sock, struct nsm_host *host)
{
+ const char *my_name = (opt_srcaddr != NULL ?
+ nsm_hostname : host->my_name);
struct sockaddr *sap;
socklen_t salen;
@@ -580,8 +603,8 @@ notify_host(int sock, struct nsm_host *h
host->xid = nsm_xmit_rpcbind(sock, sap, SM_PROG, SM_VERS);
else
host->xid = nsm_xmit_notify(sock, sap, salen,
- SM_PROG, nsm_hostname, nsm_state);
-
+ SM_PROG, my_name, nsm_state);
+
return 0;
}
@@ -611,15 +634,28 @@ recv_rpcbind_reply(struct sockaddr *sap,
}
/*
- * Successful NOTIFY call. Server returns void, so nothing
- * we need to do here.
+ * Successful NOTIFY call. Server returns void.
+ *
+ * Try sending another SM_NOTIFY with an unqualified "my_name"
+ * argument. Reuse the port number. If "my_name" is already
+ * unqualified, we're done.
*/
static void
recv_notify_reply(struct nsm_host *host)
{
- xlog(D_GENERAL, "Host %s notified successfully", host->name);
+ char *dot = strchr(host->my_name, '.');
- smn_forget_host(host);
+ if (dot != NULL) {
+ *dot = '\0';
+ host->send_next = time(NULL);
+ host->xid = 0;
+ if (host->timeout >= NSM_MAX_TIMEOUT / 4)
+ host->timeout = NSM_MAX_TIMEOUT / 4;
+ insert_host(host);
+ } else {
+ xlog(D_GENERAL, "Host %s notified successfully", host->name);
+ smn_forget_host(host);
+ }
}
/*
diff -up nfs-utils-1.2.2/utils/statd/sm-notify.man.orig nfs-utils-1.2.2/utils/statd/sm-notify.man
--- nfs-utils-1.2.2/utils/statd/sm-notify.man.orig 2010-05-06 07:15:49.867180000 -0400
+++ nfs-utils-1.2.2/utils/statd/sm-notify.man 2010-05-06 07:16:38.030995000 -0400
@@ -97,11 +97,9 @@ It uses the
string as the destination.
To identify which host has rebooted, the
.B sm-notify
-command normally sends the results of
-.BR gethostname (3)
-as the
+command normally sends
.I my_name
-string.
+string recorded when that remote was monitored.
The remote
.B rpc.statd
matches incoming SM_NOTIFY requests using this string,
@@ -202,15 +200,22 @@ argument to use when sending SM_NOTIFY r
If this option is not specified,
.B sm-notify
uses a wildcard address as the transport bind address,
-and uses the results of
-.BR gethostname (3)
-as the
+and uses the
+.I my_name
+recorded when the remote was monitored as the
.I mon_name
-argument.
+argument when sending SM_NOTIFY requests.
.IP
The
.I ipaddr
form can be expressed as either an IPv4 or an IPv6 presentation address.
+If the
+.I ipaddr
+form is used, the
+.B sm-notify
+command converts this address to a hostname for use as the
+.I mon_name
+argument when sending SM_NOTIFY requests.
.IP
This option can be useful in multi-homed configurations where
the remote requires notification from a specific network address.
@@ -252,13 +257,6 @@ consistent
The hostname the client uses to mount the server should match the server's
.I mon_name
in SM_NOTIFY requests it sends
-.IP
-The use of network addresses as a
-.I mon_name
-or a
-.I my_name
-string should be avoided when
-interoperating with non-Linux NFS implementations.
.PP
Unmounting an NFS file system does not necessarily stop
either the NFS client or server from monitoring each other.
diff -up nfs-utils-1.2.2/utils/statd/statd.man.orig nfs-utils-1.2.2/utils/statd/statd.man
--- nfs-utils-1.2.2/utils/statd/statd.man.orig 2010-05-06 07:15:49.874177000 -0400
+++ nfs-utils-1.2.2/utils/statd/statd.man 2010-05-06 07:16:38.036992000 -0400
@@ -100,11 +100,9 @@ It uses the
string as the destination.
To identify which host has rebooted, the
.B sm-notify
-command normally sends the results of
-.BR gethostname (3)
-as the
+command sends the
.I my_name
-string.
+string recorded when that remote was monitored.
The remote
.B rpc.statd
matches incoming SM_NOTIFY requests using this string,
@@ -292,7 +290,6 @@ man pages.
.SH ADDITIONAL NOTES
Lock recovery after a reboot is critical to maintaining data integrity
and preventing unnecessary application hangs.
-.PP
To help
.B rpc.statd
match SM_NOTIFY requests to NLM requests, a number of best practices
@@ -309,13 +306,6 @@ consistent
The hostname the client uses to mount the server should match the server's
.I mon_name
in SM_NOTIFY requests it sends
-.IP
-The use of network addresses as a
-.I mon_name
-or a
-.I my_name
-string should be avoided when
-interoperating with non-Linux NFS implementations.
.PP
Unmounting an NFS file system does not necessarily stop
either the NFS client or server from monitoring each other.