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-09-09 11:02:27.029025000 -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-09-09 11:01:45.340743000 -0400 +++ nfs-utils-1.2.2/configure.ac 2010-09-09 11:02:27.035022000 -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"]) @@ -411,7 +411,7 @@ case $host in ARCHFLAGS="" ;; esac -my_am_cflags="-Wall -Wstrict-prototypes $ARCHFLAGS -pipe" +my_am_cflags="-Wall -Wextra -Wstrict-prototypes $ARCHFLAGS -pipe" AC_SUBST([AM_CFLAGS], ["$my_am_cflags"]) @@ -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-09-09 11:02:27.041022000 -0400 @@ -17,7 +17,9 @@ #include #include #include -#include "xmalloc.h" +#include + +#include "sockaddr.h" #include "misc.h" #include "nfslib.h" #include "exportfs.h" @@ -28,58 +30,260 @@ #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, }; -/* 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 +static void +init_addrlist(nfs_client *clp, const struct addrinfo *ai) +{ + int i; + + if (ai == NULL) + return; + + for (i = 0; (ai != NULL) && (i < NFSCLNT_ADDRMAX); i++) { + set_addrlist(clp, i, ai->ai_addr); + ai = ai->ai_next; + } + + clp->m_naddr = i; +} + +static void +client_free(nfs_client *clp) +{ + free(clp->m_hostname); + free(clp); +} + +static int +init_netmask4(nfs_client *clp, const char *slash) +{ + struct sockaddr_in sin = { + .sin_family = AF_INET, + }; + uint32_t shift; + + /* + * Decide what kind of netmask was specified. If there's + * no '/' present, assume the netmask is all ones. If + * there is a '/' and at least one '.', look for a spelled- + * out netmask. Otherwise, assume it was a prefixlen. + */ + if (slash == NULL) + shift = 0; + else { + unsigned long prefixlen; + + if (strchr(slash + 1, '.') != NULL) { + if (inet_pton(AF_INET, slash + 1, + &sin.sin_addr.s_addr) == 0) + goto out_badmask; + set_addrlist_in(clp, 1, &sin); + return 1; + } else { + char *endptr; + + prefixlen = strtoul(slash + 1, &endptr, 10); + if (*endptr != '\0' && prefixlen != ULONG_MAX && + errno != ERANGE) + goto out_badprefix; + } + if (prefixlen > 32) + goto out_badprefix; + shift = 32 - (uint32_t)prefixlen; + } + + /* + * Now construct the full netmask bitmask in a sockaddr_in, + * and plant it in the nfs_client record. + */ + sin.sin_addr.s_addr = htonl((uint32_t)~0 << shift); + set_addrlist_in(clp, 1, &sin); + + return 1; + +out_badmask: + xlog(L_ERROR, "Invalid netmask `%s' for %s", slash + 1, clp->m_hostname); + return 0; + +out_badprefix: + xlog(L_ERROR, "Invalid prefix `%s' for %s", slash + 1, clp->m_hostname); + return 0; +} + +#ifdef IPV6_SUPPORTED +static int +init_netmask6(nfs_client *clp, const char *slash) +{ + struct sockaddr_in6 sin6 = { + .sin6_family = AF_INET6, + }; + unsigned long prefixlen; + uint32_t shift; + int i; + + /* + * Decide what kind of netmask was specified. If there's + * no '/' present, assume the netmask is all ones. If + * there is a '/' and at least one ':', look for a spelled- + * out netmask. Otherwise, assume it was a prefixlen. + */ + if (slash == NULL) + prefixlen = 128; + else { + if (strchr(slash + 1, ':') != NULL) { + if (!inet_pton(AF_INET6, slash + 1, &sin6.sin6_addr)) + goto out_badmask; + set_addrlist_in6(clp, 1, &sin6); + return 1; + } else { + char *endptr; + + prefixlen = strtoul(slash + 1, &endptr, 10); + if (*endptr != '\0' && prefixlen != ULONG_MAX && + errno != ERANGE) + goto out_badprefix; + } + if (prefixlen > 128) + goto out_badprefix; + } + + /* + * Now construct the full netmask bitmask in a sockaddr_in6, + * and plant it in the nfs_client record. + */ + for (i = 0; prefixlen > 32; i++) { + sin6.sin6_addr.s6_addr32[i] = 0xffffffff; + prefixlen -= 32; + } + shift = 32 - (uint32_t)prefixlen; + sin6.sin6_addr.s6_addr32[i] = htonl((uint32_t)~0 << shift); + set_addrlist_in6(clp, 1, &sin6); + + return 1; + +out_badmask: + xlog(L_ERROR, "Invalid netmask `%s' for %s", slash + 1, clp->m_hostname); + return 0; + +out_badprefix: + xlog(L_ERROR, "Invalid prefix `%s' for %s", slash + 1, clp->m_hostname); + return 0; +} +#else /* IPV6_SUPPORTED */ +static int +init_netmask6(nfs_client *UNUSED(clp), const char *UNUSED(slash)) +{ +} +#endif /* IPV6_SUPPORTED */ + +/* + * Parse the network mask for M_SUBNETWORK type clients. + * + * Return TRUE if successful, or FALSE if some error occurred. + */ +static int +init_subnetwork(nfs_client *clp) +{ + struct addrinfo *ai; + sa_family_t family; + int result = 0; + char *slash; + + slash = strchr(clp->m_hostname, '/'); + if (slash != NULL) { + *slash = '\0'; + ai = host_pton(clp->m_hostname); + *slash = '/'; + } else + ai = host_pton(clp->m_hostname); + if (ai == NULL) { + xlog(L_ERROR, "Invalid IP address %s", clp->m_hostname); + return result; + } + + set_addrlist(clp, 0, ai->ai_addr); + family = ai->ai_addr->sa_family; + + freeaddrinfo(ai); + + switch (family) { + case AF_INET: + result = init_netmask4(clp, slash); + break; + case AF_INET6: + result = init_netmask6(clp, slash); + break; + default: + xlog(L_ERROR, "Unsupported address family for %s", + clp->m_hostname); + } + + return result; +} + +static int +client_init(nfs_client *clp, const char *hname, const struct addrinfo *ai) +{ + 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, ai); + 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; +} + +/** + * client_lookup - look for @hname in our list of cached nfs_clients + * @hname: '\0'-terminated ASCII string containing hostname to look for + * @canonical: if set, @hname is known to be canonical DNS name + * + * Returns pointer to a matching or freshly created nfs_client. NULL + * is returned if some problem occurs. */ nfs_client * client_lookup(char *hname, int canonical) { nfs_client *clp = NULL; int htype; - struct hostent *hp = NULL; + struct addrinfo *ai = NULL; htype = client_gettype(hname); if (htype == MCL_FQDN && !canonical) { - struct hostent *hp2; - hp = gethostbyname(hname); - if (hp == NULL || hp->h_addrtype != AF_INET) { - xlog(L_ERROR, "%s has non-inet addr", hname); - return NULL; + ai = host_addrinfo(hname); + if (!ai) { + xlog(L_ERROR, "Failed to resolve %s", hname); + goto out; } - /* make sure we have canonical name */ - hp2 = hostent_dup(hp); - hp = gethostbyaddr(hp2->h_addr, hp2->h_length, - hp2->h_addrtype); - if (hp) { - hp = hostent_dup(hp); - /* but now we might not have all addresses... */ - if (hp2->h_addr_list[1]) { - struct hostent *hp3 = - gethostbyname(hp->h_name); - if (hp3) { - free(hp); - hp = hostent_dup(hp3); - } - } - free(hp2); - } else - hp = hp2; - - hname = (char *) hp->h_name; + hname = ai->ai_canonname; - for (clp = clientlist[htype]; clp; clp = clp->m_next) { - if (client_check(clp, hp)) + for (clp = clientlist[htype]; clp; clp = clp->m_next) + if (client_check(clp, ai)) break; - } } else { for (clp = clientlist[htype]; clp; clp = clp->m_next) { if (strcasecmp(hname, clp->m_hostname)==0) @@ -87,106 +291,60 @@ 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 (hp) - free (hp); + if (htype == MCL_FQDN && clp->m_naddr == 0) + init_addrlist(clp, ai); +out: + freeaddrinfo(ai); return clp; } +/** + * client_dup - create a copy of an nfs_client + * @clp: pointer to nfs_client to copy + * @ai: pointer to addrinfo used to initialize the new client's addrlist + * + * Returns a dynamically allocated nfs_client if successful, or + * NULL if some problem occurs. Caller must free the returned + * nfs_client with free(3). + */ nfs_client * -client_dup(nfs_client *clp, struct hostent *hp) +client_dup(const nfs_client *clp, const struct addrinfo *ai) { 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, ai->ai_canonname, ai)) { + 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; -} - +/** + * client_release - drop a reference to an nfs_client record + * + */ void client_release(nfs_client *clp) { @@ -195,6 +353,10 @@ client_release(nfs_client *clp) clp->m_count--; } +/** + * client_freeall - deallocate all nfs_client records + * + */ void client_freeall(void) { @@ -205,57 +367,45 @@ 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) +/** + * client_resolve - look up an IP address + * @sap: pointer to socket address to resolve + * + * Returns an addrinfo structure, or NULL if some problem occurred. + * Caller must free the result with freeaddrinfo(3). + */ +struct addrinfo * +client_resolve(const struct sockaddr *sap) { - struct hostent *he = NULL; + struct addrinfo *ai = NULL; if (clientlist[MCL_WILDCARD] || clientlist[MCL_NETGROUP]) - he = get_reliable_hostbyaddr((const char*)&addr, sizeof(addr), AF_INET); - if (he == NULL) - he = get_hostent((const char*)&addr, sizeof(addr), AF_INET); + ai = host_reliable_addrinfo(sap); + if (ai == NULL) + ai = host_numeric_addrinfo(sap); - return he; + return ai; } -/* - * 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 + * @ai: pointer to addrinfo 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) +client_compose(const struct addrinfo *ai) { char *name = NULL; int i; @@ -263,7 +413,7 @@ client_compose(struct hostent *he) for (i = 0 ; i < MCL_MAXTYPES; i++) { nfs_client *clp; for (clp = clientlist[i]; clp ; clp = clp->m_next) { - if (!client_check(clp, he)) + if (!client_check(clp, ai)) continue; name = add_name(name, clp->m_hostname); } @@ -271,13 +421,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 +446,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 +460,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,108 +495,257 @@ 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 @ai 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 addrinfo *ai) { - char *hname = (char *) hp->h_name; - char *cname = clp->m_hostname; - 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 (; ai; ai = ai->ai_next) + for (i = 0; i < clp->m_naddr; i++) + if (nfs_compare_sockaddr(ai->ai_addr, + get_addrlist(clp, i))) return 1; - } - return 0; - case MCL_WILDCARD: - if (wildmat(hname, cname)) + + return 0; +} + +static _Bool +mask_match(const uint32_t a, const uint32_t b, const uint32_t m) +{ + return ((a ^ b) & m) == 0; +} + +static int +check_subnet_v4(const struct sockaddr_in *address, + const struct sockaddr_in *mask, const struct addrinfo *ai) +{ + for (; ai; ai = ai->ai_next) { + struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr; + + if (sin->sin_family != AF_INET) + continue; + + if (mask_match(address->sin_addr.s_addr, + sin->sin_addr.s_addr, + mask->sin_addr.s_addr)) 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; - } +#ifdef IPV6_SUPPORTED +static int +check_subnet_v6(const struct sockaddr_in6 *address, + const struct sockaddr_in6 *mask, const struct addrinfo *ai) +{ + for (; ai; ai = ai->ai_next) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr; - /* 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 (sin6->sin6_family != AF_INET6) + continue; - /* 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 = '.'; + if (mask_match(address->sin6_addr.s6_addr32[0], + sin6->sin6_addr.s6_addr32[0], + mask->sin6_addr.s6_addr32[0]) && + mask_match(address->sin6_addr.s6_addr32[1], + sin6->sin6_addr.s6_addr32[1], + mask->sin6_addr.s6_addr32[1]) && + mask_match(address->sin6_addr.s6_addr32[2], + sin6->sin6_addr.s6_addr32[2], + mask->sin6_addr.s6_addr32[2]) && + mask_match(address->sin6_addr.s6_addr32[3], + sin6->sin6_addr.s6_addr32[3], + mask->sin6_addr.s6_addr32[3])) + return 1; + } + return 0; +} +#else /* !IPV6_SUPPORTED */ +static int +check_subnet_v6(const struct sockaddr_in6 *UNUSED(address), + const struct sockaddr_in6 *UNUSED(mask), + const struct addrinfo *UNUSED(ai)) +{ + return 0; +} +#endif /* !IPV6_SUPPORTED */ - return match; - } -#else - return 0; -#endif - case MCL_ANONYMOUS: +/* + * Check each address listed in @ai 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 addrinfo *ai) +{ + switch (get_addrlist(clp, 0)->sa_family) { + case AF_INET: + return check_subnet_v4(get_addrlist_in(clp, 0), + get_addrlist_in(clp, 1), ai); + case AF_INET6: + return check_subnet_v6(get_addrlist_in6(clp, 0), + get_addrlist_in6(clp, 1), ai); + } + + return 0; +} + +/* + * 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 addrinfo *ai) +{ + char *cname = clp->m_hostname; + char *hname = ai->ai_canonname; + struct hostent *hp; + char **ap; + + 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 */ + hp = gethostbyname(hname); + if (hp != NULL) { + for (ap = hp->h_aliases; *ap; ap++) + if (wildmat(*ap, cname)) + return 1; } return 0; } +/* + * Check if @ai's hostname or aliases fall in a given netgroup. + * Return 1 if @ai represents a host in the netgroup, otherwise + * zero. + */ +#ifdef HAVE_INNETGR +static int +check_netgroup(const nfs_client *clp, const struct addrinfo *ai) +{ + const char *netgroup = clp->m_hostname + 1; + struct addrinfo *tmp = NULL; + struct hostent *hp; + char *dot, *hname; + int i, match; + + match = 0; + + hname = strdup(ai->ai_canonname); + if (hname == NULL) { + xlog(D_GENERAL, "%s: no memory for strdup", __func__); + goto out; + } + + /* First, try to match the hostname without + * splitting off the domain */ + if (innetgr(netgroup, hname, NULL, NULL)) { + match = 1; + goto out; + } + + /* See if hname aliases listed in /etc/hosts or nis[+] + * match the requested netgroup */ + hp = gethostbyname(hname); + if (hp != NULL) { + for (i = 0; hp->h_aliases[i]; i++) + if (innetgr(netgroup, hp->h_aliases[i], NULL, NULL)) { + match = 1; + goto out; + } + } + + /* If hname happens to be an IP address, convert it + * to a the canonical DNS name bound to this address. */ + tmp = host_pton(hname); + if (tmp != NULL) { + char *cname = host_canonname(tmp->ai_addr); + freeaddrinfo(tmp); + + /* The resulting FQDN may be in our netgroup. */ + if (cname != NULL) { + free(hname); + hname = cname; + if (innetgr(netgroup, hname, NULL, NULL)) { + match = 1; + goto out; + } + } + } + + /* Okay, strip off the domain (if we have one) */ + dot = strchr(hname, '.'); + if (dot == NULL) + goto out; + + *dot = '\0'; + match = innetgr(netgroup, hname, NULL, NULL); + +out: + free(hname); + 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 addrinfo *ai) { - 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 + * @ai: pointer to addrinfo to compare it with + * + * Returns 1 if the address information matches the cached nfs_client, + * otherwise zero. + */ +int +client_check(const nfs_client *clp, const struct addrinfo *ai) +{ 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, ai); case MCL_SUBNETWORK: - return !((clp->m_addrlist[0].s_addr ^ addr.s_addr) - & clp->m_addrlist[1].s_addr); + return check_subnetwork(clp, ai); + case MCL_WILDCARD: + return check_wildcard(clp, ai); + case MCL_NETGROUP: + return check_netgroup(clp, ai); + 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; } +/** + * client_gettype - determine type of nfs_client given an identifier + * @ident: '\0'-terminated ASCII string containing a client identifier + * + * Returns the type of nfs_client record that would be used for + * this client. + */ int client_gettype(char *ident) { - char *sp; + struct addrinfo *ai; + char *sp; if (ident[0] == '\0' || strcmp(ident, "*")==0) return MCL_ANONYMOUS; @@ -461,12 +765,16 @@ client_gettype(char *ident) if (*sp == '\\' && sp[1]) sp++; } - /* check for N.N.N.N */ - sp = ident; - if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN; - sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN; - sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN; - sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '\0') return MCL_FQDN; - /* we lie here a bit. but technically N.N.N.N == N.N.N.N/32 :) */ - return MCL_SUBNETWORK; + + /* + * Treat unadorned IP addresses as MCL_SUBNETWORK. + * Everything else is MCL_FQDN. + */ + ai = host_pton(ident); + if (ai != NULL) { + freeaddrinfo(ai); + return MCL_SUBNETWORK; + } + + return MCL_FQDN; } 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-09-09 11:02:27.046023000 -0400 @@ -24,9 +24,24 @@ static int export_hash(char *); static void export_init(nfs_export *exp, nfs_client *clp, struct exportent *nep); -static int export_check(nfs_export *, struct hostent *, char *); +static void export_add(nfs_export *exp); +static int export_check(const nfs_export *exp, const struct addrinfo *ai, + const char *path); static nfs_export * - export_allowed_internal(struct hostent *hp, char *path); + export_allowed_internal(const struct addrinfo *ai, + const 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) { @@ -44,7 +59,12 @@ static void warn_duplicated_exports(nfs_ } } -int +/** + * export_read - read entries from /etc/exports + * @fname: name of file to read from + * + */ +void export_read(char *fname) { struct exportent *eep; @@ -59,11 +79,15 @@ export_read(char *fname) warn_duplicated_exports(exp, eep); } endexportent(); - return 0; } -/* - * Create an in-core export struct from an export entry. +/** + * export_create - create an in-core nfs_export record from an export entry + * @xep: export entry to lookup + * @canonical: if set, e_hostname is known to be canonical DNS name + * + * Returns a freshly instantiated export record, or NULL if + * a problem occurred. */ nfs_export * export_create(struct exportent *xep, int canonical) @@ -105,8 +129,8 @@ export_init(nfs_export *exp, nfs_client * original hostname from /etc/exports, while the in-core client struct * gets the newly found FQDN. */ -nfs_export * -export_dup(nfs_export *exp, struct hostent *hp) +static nfs_export * +export_dup(nfs_export *exp, const struct addrinfo *ai) { nfs_export *new; nfs_client *clp; @@ -116,7 +140,11 @@ export_dup(nfs_export *exp, struct hoste dupexportent(&new->m_export, &exp->m_export); if (exp->m_export.e_hostname) new->m_export.e_hostname = xstrdup(exp->m_export.e_hostname); - clp = client_dup(exp->m_client, hp); + clp = client_dup(exp->m_client, ai); + if (clp == NULL) { + export_free(new); + return NULL; + } clp->m_count++; new->m_client = clp; new->m_mayexport = exp->m_mayexport; @@ -128,10 +156,8 @@ export_dup(nfs_export *exp, struct hoste return new; } -/* - * Add export entry to hash table - */ -void + +static void export_add(nfs_export *exp) { exp_hash_table *p_tbl; @@ -159,19 +185,27 @@ export_add(nfs_export *exp) } } +/** + * export_find - find or create a suitable nfs_export for @ai and @path + * @ai: pointer to addrinfo for client + * @path: '\0'-terminated ASCII string containing export path + * + * Returns a pointer to nfs_export data matching @ai and @path, + * or NULL if an error occurs. + */ nfs_export * -export_find(struct hostent *hp, char *path) +export_find(const struct addrinfo *ai, const char *path) { nfs_export *exp; int i; for (i = 0; i < MCL_MAXTYPES; i++) { for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { - if (!export_check(exp, hp, path)) + if (!export_check(exp, ai, path)) continue; if (exp->m_client->m_type == MCL_FQDN) return exp; - return export_dup(exp, hp); + return export_dup(exp, ai); } } @@ -179,7 +213,7 @@ export_find(struct hostent *hp, char *pa } static nfs_export * -export_allowed_internal (struct hostent *hp, char *path) +export_allowed_internal(const struct addrinfo *ai, const char *path) { nfs_export *exp; int i; @@ -187,7 +221,7 @@ export_allowed_internal (struct hostent for (i = 0; i < MCL_MAXTYPES; i++) { for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { if (!exp->m_mayexport || - !export_check(exp, hp, path)) + !export_check(exp, ai, path)) continue; return exp; } @@ -196,8 +230,16 @@ export_allowed_internal (struct hostent return NULL; } +/** + * export_allowed - determine if this export is allowed + * @ai: pointer to addrinfo for client + * @path: '\0'-terminated ASCII string containing export path + * + * Returns a pointer to nfs_export data matching @ai and @path, + * or NULL if the export is not allowed. + */ nfs_export * -export_allowed(struct hostent *hp, char *path) +export_allowed(const struct addrinfo *ai, const char *path) { nfs_export *exp; char epath[MAXPATHLEN+1]; @@ -210,7 +252,7 @@ export_allowed(struct hostent *hp, char /* Try the longest matching exported pathname. */ while (1) { - exp = export_allowed_internal (hp, epath); + exp = export_allowed_internal(ai, epath); if (exp) return exp; /* We have to treat the root, "/", specially. */ @@ -223,11 +265,17 @@ export_allowed(struct hostent *hp, char return NULL; } -/* - * Search hash table for export entry. - */ +/** + * export_lookup - search hash table for export entry + * @hname: '\0'-terminated ASCII string containing client hostname to look for + * @path: '\0'-terminated ASCII string containing export path to look for + * @canonical: if set, @hname is known to be canonical DNS name + * + * Returns a pointer to nfs_export record matching @hname and @path, + * or NULL if the export was not found. + */ nfs_export * -export_lookup(char *hname, char *path, int canonical) +export_lookup(char *hname, char *path, int canonical) { nfs_client *clp; nfs_export *exp; @@ -251,14 +299,18 @@ export_lookup(char *hname, char *path, i } static int -export_check(nfs_export *exp, struct hostent *hp, char *path) +export_check(const nfs_export *exp, const struct addrinfo *ai, const char *path) { if (strcmp(path, exp->m_export.e_path)) return 0; - return client_check(exp->m_client, hp); + return client_check(exp->m_client, ai); } +/** + * export_freeall - deallocate all nfs_export records + * + */ void export_freeall(void) { @@ -269,22 +321,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/hostname.c.orig nfs-utils-1.2.2/support/export/hostname.c --- nfs-utils-1.2.2/support/export/hostname.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/support/export/hostname.c 2010-09-09 11:02:27.051025000 -0400 @@ -1,315 +1,377 @@ /* - * support/export/hostname.c + * Copyright 2010 Oracle. All rights reserved. * - * Functions for hostname. + * 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 . */ #ifdef HAVE_CONFIG_H #include #endif -/* -#define TEST -*/ - #include -#include -#include -#include #include -#include -#ifdef TEST -#define xmalloc malloc -#else -#include "xmalloc.h" -#include "misc.h" -#endif +#include +#include +#include -#define ALIGNMENT sizeof (char *) +#include "sockaddr.h" +#include "exportfs.h" -static int -align (int len, int al) +#ifndef HAVE_DECL_AI_ADDRCONFIG +#define AI_ADDRCONFIG 0 +#endif + +#ifdef HAVE_GETNAMEINFO +static socklen_t +sockaddr_size(const struct sockaddr *sap) { - int i; - i = len % al; - if (i) - len += al - i; - return len; + if (sap->sa_family != AF_INET) + return 0; + return (socklen_t)sizeof(struct sockaddr_in); } +#endif /* HAVE_GETNAMEINFO */ -struct hostent * -get_hostent (const char *addr, int len, int type) +/** + * host_ntop - generate presentation address given a sockaddr + * @sap: pointer to socket address + * @buf: working storage + * @buflen: size of @buf in bytes + * + * Returns a pointer to a @buf. + */ +#ifdef HAVE_GETNAMEINFO +char * +host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen) { - struct hostent *cp; - int len_ent; - const char *name; - int len_name; - int num_aliases = 1; - int len_aliases = sizeof (char *); - int num_addr_list = 1; - int len_addr_list = sizeof (char *); - int pos; - struct in_addr *ipv4; - - switch (type) - { - case AF_INET: - ipv4 = (struct in_addr *) addr; - name = inet_ntoa (*ipv4); - break; - - default: - return NULL; - } - - len_ent = align (sizeof (*cp), ALIGNMENT); - len_name = align (strlen (name) + 1, ALIGNMENT); - - num_addr_list++; - len_addr_list += align (len, ALIGNMENT) + sizeof (char *); - - cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases - + len_addr_list); - - cp->h_addrtype = type; - cp->h_length = len; - pos = len_ent; - cp->h_name = (char *) &(((char *) cp) [pos]); - strcpy (cp->h_name, name); - - pos += len_name; - cp->h_aliases = (char **) &(((char *) cp) [pos]); - pos += num_aliases * sizeof (char *); - cp->h_aliases [0] = NULL; - - pos = len_ent + len_name + len_aliases; - cp->h_addr_list = (char **) &(((char *) cp) [pos]); - pos += num_addr_list * sizeof (char *); - cp->h_addr_list [0] = (char *) &(((char *) cp) [pos]); - memcpy (cp->h_addr_list [0], addr, cp->h_length); - pos += align (cp->h_length, ALIGNMENT); - cp->h_addr_list [1] = NULL; + socklen_t salen = sockaddr_size(sap); + int error; - return cp; -} + memset(buf, 0, buflen); -struct hostent * -hostent_dup (struct hostent *hp) + if (salen == 0) { + (void)strncpy(buf, "bad family", buflen - 1); + return buf; + } + + error = getnameinfo(sap, salen, buf, (socklen_t)buflen, + NULL, 0, NI_NUMERICHOST); + if (error != 0) { + buf[0] = '\0'; + (void)strncpy(buf, "bad address", buflen - 1); + } + + return buf; +} +#else /* !HAVE_GETNAMEINFO */ +char * +host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen) { - int len_ent = align (sizeof (*hp), ALIGNMENT); - int len_name = align (strlen (hp->h_name) + 1, ALIGNMENT); - int num_aliases = 1; - int len_aliases = sizeof (char *); - int num_addr_list = 1; - int len_addr_list = sizeof (char *); - int pos, i; - char **sp; - struct hostent *cp; - - for (sp = hp->h_aliases; sp && *sp; sp++) - { - num_aliases++; - len_aliases += align (strlen (*sp) + 1, ALIGNMENT) - + sizeof (char *); - } - - for (sp = hp->h_addr_list; *sp; sp++) - { - num_addr_list++; - len_addr_list += align (hp->h_length, ALIGNMENT) - + sizeof (char *); - } - - cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases - + len_addr_list); - - *cp = *hp; - pos = len_ent; - cp->h_name = (char *) &(((char *) cp) [pos]); - strcpy (cp->h_name, hp->h_name); - - pos += len_name; - cp->h_aliases = (char **) &(((char *) cp) [pos]); - pos += num_aliases * sizeof (char *); - for (sp = hp->h_aliases, i = 0; i < num_aliases; i++, sp++) - if (sp && *sp) - { - cp->h_aliases [i] = (char *) &(((char *) cp) [pos]); - strcpy (cp->h_aliases [i], *sp); - pos += align (strlen (*sp) + 1, ALIGNMENT); - } - else - cp->h_aliases [i] = NULL; - - pos = len_ent + len_name + len_aliases; - cp->h_addr_list = (char **) &(((char *) cp) [pos]); - pos += num_addr_list * sizeof (char *); - for (sp = hp->h_addr_list, i = 0; i < num_addr_list; i++, sp++) - if (*sp) - { - cp->h_addr_list [i] = (char *) &(((char *) cp) [pos]); - memcpy (cp->h_addr_list [i], *sp, hp->h_length); - pos += align (hp->h_length, ALIGNMENT); - } - else - cp->h_addr_list [i] = *sp; + const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap; - return cp; + memset(buf, 0, buflen); + + if (sin->sin_family != AF_INET) + (void)strncpy(buf, "bad family", buflen - 1); + return buf; + } + + if (inet_ntop(AF_INET, &sin->sin_addr.s_addr, buf, buflen) != NULL) + return buf; + + buf[0] = '\0'; + (void)strncpy(buf, "bad address", buflen - 1); + return buf; } +#endif /* !HAVE_GETNAMEINFO */ -static int -is_hostname(const char *sp) +/** + * host_pton - return addrinfo for a given presentation address + * @paddr: pointer to a '\0'-terminated ASCII string containing an + * IP presentation address + * + * Returns address info structure, or NULL if an error occurs. Caller + * must free the returned structure with freeaddrinfo(3). + */ +__attribute_malloc__ +struct addrinfo * +host_pton(const char *paddr) { - if (*sp == '\0' || *sp == '@') - return 0; + struct addrinfo *ai = NULL; + struct addrinfo hint = { + /* don't return duplicates */ + .ai_protocol = (int)IPPROTO_UDP, + .ai_flags = AI_NUMERICHOST, + .ai_family = AF_UNSPEC, + }; + struct sockaddr_in sin; + int error; + + /* + * Although getaddrinfo(3) is easier to use and supports + * IPv6, it recognizes incomplete addresses like "10.4" + * as valid AF_INET addresses. It also accepts presentation + * addresses that end with a blank. + * + * inet_pton(3) is much stricter. Use it to be certain we + * have a real AF_INET presentation address, before invoking + * getaddrinfo(3) to generate the full addrinfo list. + */ + if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0) + return NULL; - for (; *sp; sp++) - { - if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/') - return 0; - if (*sp == '\\' && sp[1]) - sp++; - } + error = getaddrinfo(paddr, NULL, &hint, &ai); + switch (error) { + case 0: + return ai; + case EAI_NONAME: + if (paddr == NULL) + xlog(D_GENERAL, "%s: passed a NULL presentation address", + __func__); + break; + case EAI_SYSTEM: + xlog(D_GENERAL, "%s: failed to convert %s: (%d) %m", + __func__, paddr, errno); + break; + default: + xlog(D_GENERAL, "%s: failed to convert %s: %s", + __func__, paddr, gai_strerror(error)); + break; + } - return 1; + return NULL; } -int -matchhostname (const char *h1, const char *h2) +/** + * host_addrinfo - return addrinfo for a given hostname + * @hostname: pointer to a '\0'-terminated ASCII string containing a hostname + * + * Returns address info structure with ai_canonname filled in, or NULL + * if no information is available for @hostname. Caller must free the + * returned structure with freeaddrinfo(3). + */ +__attribute_malloc__ +struct addrinfo * +host_addrinfo(const char *hostname) { - struct hostent *hp1, *hp2; - int status; + struct addrinfo *ai = NULL; + struct addrinfo hint = { + .ai_family = AF_INET, + /* don't return duplicates */ + .ai_protocol = (int)IPPROTO_UDP, + .ai_flags = AI_ADDRCONFIG | AI_CANONNAME, + }; + int error; + + error = getaddrinfo(hostname, NULL, &hint, &ai); + switch (error) { + case 0: + return ai; + case EAI_SYSTEM: + xlog(D_GENERAL, "%s: failed to resolve %s: (%d) %m", + __func__, hostname, errno); + break; + default: + xlog(D_GENERAL, "%s: failed to resolve %s: %s", + __func__, hostname, gai_strerror(error)); + break; + } - if (strcasecmp (h1, h2) == 0) - return 1; + return NULL; +} - if (!is_hostname (h1) || !is_hostname (h2)) - return 0; +/** + * host_canonname - return canonical hostname bound to an address + * @sap: pointer to socket address to look up + * + * Discover the canonical hostname associated with the given socket + * address. The host's reverse mapping is verified in the process. + * + * Returns a '\0'-terminated ASCII string containing a hostname, or + * NULL if no hostname can be found for @sap. Caller must free + * the string. + */ +#ifdef HAVE_GETNAMEINFO +__attribute_malloc__ +char * +host_canonname(const struct sockaddr *sap) +{ + socklen_t salen = sockaddr_size(sap); + char buf[NI_MAXHOST]; + int error; + + if (salen == 0) { + xlog(D_GENERAL, "%s: unsupported address family %d", + __func__, sap->sa_family); + return NULL; + } - hp1 = gethostbyname (h1); - if (hp1 == NULL) - return 0; - - hp1 = hostent_dup (hp1); - - hp2 = gethostbyname (h2); - if (hp2) - { - if (strcasecmp (hp1->h_name, hp2->h_name) == 0) - status = 1; - else - { - char **ap1, **ap2; - - status = 0; - for (ap1 = hp1->h_addr_list; *ap1 && status == 0; ap1++) - for (ap2 = hp2->h_addr_list; *ap2; ap2++) - if (memcmp (*ap1, *ap2, sizeof (struct in_addr)) == 0) - { - status = 1; - break; - } + memset(buf, 0, sizeof(buf)); + error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf), + NULL, 0, NI_NAMEREQD); + switch (error) { + case 0: + break; + case EAI_SYSTEM: + xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m", + __func__, errno); + return NULL; + default: + (void)getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf), + NULL, 0, NI_NUMERICHOST); + xlog(D_GENERAL, "%s: failed to resolve %s: %s", + __func__, buf, gai_strerror(error)); + return NULL; } - } - else - status = 0; - free (hp1); - return status; + return strdup(buf); } +#else /* !HAVE_GETNAMEINFO */ +__attribute_malloc__ +char * +host_canonname(const struct sockaddr *sap) +{ + const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap; + const struct in_addr *addr = &sin->sin_addr; + struct hostent *hp; + if (sap->sa_family != AF_INET) + return NULL; + + hp = gethostbyaddr(addr, (socklen_t)sizeof(addr), AF_INET); + if (hp == NULL) + return NULL; + + return strdup(hp->h_name); +} +#endif /* !HAVE_GETNAMEINFO */ -/* Map IP to hostname, and then map back to addr to make sure it is a - * reliable hostname +/** + * host_reliable_addrinfo - return addrinfo for a given address + * @sap: pointer to socket address to look up + * + * Reverse and forward lookups are performed to ensure the address has + * proper forward and reverse mappings. + * + * Returns address info structure with ai_canonname filled in, or NULL + * if no information is available for @sap. Caller must free the returned + * structure with freeaddrinfo(3). */ -struct hostent * -get_reliable_hostbyaddr(const char *addr, int len, int type) +__attribute_malloc__ +struct addrinfo * +host_reliable_addrinfo(const struct sockaddr *sap) { - struct hostent *hp = NULL; - - struct hostent *reverse; - struct hostent *forward; - char **sp; + struct addrinfo *ai; + char *hostname; - reverse = gethostbyaddr (addr, len, type); - if (!reverse) + hostname = host_canonname(sap); + if (hostname == NULL) return NULL; - /* must make sure the hostent is authorative. */ + ai = host_addrinfo(hostname); - reverse = hostent_dup (reverse); - forward = gethostbyname (reverse->h_name); + free(hostname); + return ai; +} - if (forward) { - /* now make sure the "addr" is in the list */ - for (sp = forward->h_addr_list ; *sp ; sp++) { - if (memcmp (*sp, addr, forward->h_length) == 0) - break; - } +/** + * host_numeric_addrinfo - return addrinfo without doing DNS queries + * @sap: pointer to socket address + * + * Returns address info structure, or NULL if an error occurred. + * Caller must free the returned structure with freeaddrinfo(3). + */ +#ifdef HAVE_GETNAMEINFO +__attribute_malloc__ +struct addrinfo * +host_numeric_addrinfo(const struct sockaddr *sap) +{ + socklen_t salen = sockaddr_size(sap); + char buf[INET_ADDRSTRLEN]; + struct addrinfo *ai; + int error; + + if (salen == 0) { + xlog(D_GENERAL, "%s: unsupported address family %d", + __func__, sap->sa_family); + return NULL; + } - if (*sp) { - /* it's valid */ - hp = hostent_dup (forward); - } - else { - /* it was a FAKE */ - xlog (L_WARNING, "Fake hostname %s for %s - forward lookup doesn't match reverse", - reverse->h_name, inet_ntoa(*(struct in_addr*)addr)); - } + memset(buf, 0, sizeof(buf)); + error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf), + NULL, 0, NI_NUMERICHOST); + switch (error) { + case 0: + break; + case EAI_SYSTEM: + xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m", + __func__, errno); + return NULL; + default: + xlog(D_GENERAL, "%s: getnameinfo(3) failed: %s", + __func__, gai_strerror(error)); + return NULL; } - else { - /* never heard of it. misconfigured DNS? */ - xlog (L_WARNING, "Fake hostname %s for %s - forward lookup doesn't exist", - reverse->h_name, inet_ntoa(*(struct in_addr*)addr)); + + ai = host_pton(buf); + + /* + * getaddrinfo(AI_NUMERICHOST) never fills in ai_canonname + */ + if (ai != NULL) { + free(ai->ai_canonname); /* just in case */ + ai->ai_canonname = strdup(buf); + if (ai->ai_canonname == NULL) { + freeaddrinfo(ai); + ai = NULL; + } } - free (reverse); - return hp; + return ai; } +#else /* !HAVE_GETNAMEINFO */ +__attribute_malloc__ +struct addrinfo * +host_numeric_addrinfo(const struct sockaddr *sap) +{ + const struct sockaddr_in *sin = (const struct sockaddr_in *)sap; + const struct in_addr *addr = &sin->sin_addr; + char buf[INET_ADDRSTRLEN]; + struct addrinfo *ai; + if (sap->sa_family != AF_INET) + return NULL; -#ifdef TEST -void -print_host (struct hostent *hp) -{ - char **sp; + memset(buf, 0, sizeof(buf)); + if (inet_ntop(AF_INET, (char *)addr, buf, + (socklen_t)sizeof(buf)) == NULL) + return NULL; - if (hp) - { - printf ("official hostname: %s\n", hp->h_name); - printf ("aliases:\n"); - for (sp = hp->h_aliases; *sp; sp++) - printf (" %s\n", *sp); - printf ("IP addresses:\n"); - for (sp = hp->h_addr_list; *sp; sp++) - printf (" %s\n", inet_ntoa (*(struct in_addr *) *sp)); - } - else - printf ("Not host information\n"); -} + ai = host_pton(buf); -int -main (int argc, char **argv) -{ - struct hostent *hp = gethostbyname (argv [1]); - struct hostent *cp; - struct in_addr addr; - - print_host (hp); - - if (hp) - { - cp = hostent_dup (hp); - print_host (cp); - free (cp); - } - printf ("127.0.0.1 == %s: %d\n", argv [1], - matchhostname ("127.0.0.1", argv [1])); - addr.s_addr = inet_addr(argv [2]); - printf ("%s\n", inet_ntoa (addr)); - cp = get_hostent ((const char *)&addr, sizeof(addr), AF_INET); - print_host (cp); - return 0; + /* + * getaddrinfo(AI_NUMERICHOST) never fills in ai_canonname + */ + if (ai != NULL) { + ai->ai_canonname = strdup(buf); + if (ai->ai_canonname == NULL) { + freeaddrinfo(ai); + ai = NULL; + } + } + + return ai; } -#endif +#endif /* !HAVE_GETNAMEINFO */ 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-09-09 11:02:27.056025000 -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++) { + const 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; } @@ -100,7 +109,7 @@ expsetup(struct nfsctl_export *exparg, n str_tolower(exparg->ex_client); exparg->ex_flags = exp->m_export.e_flags; exparg->ex_dev = (!unexport && (exp->m_export.e_flags & NFSEXP_FSID)) ? - exp->m_export.e_fsid : stb.st_dev; + (__nfsd_dev_t)exp->m_export.e_fsid : stb.st_dev; exparg->ex_ino = stb.st_ino; exparg->ex_anon_uid = exp->m_export.e_anonuid; exparg->ex_anon_gid = exp->m_export.e_anongid; diff -up nfs-utils-1.2.2/support/export/rmtab.c.orig nfs-utils-1.2.2/support/export/rmtab.c --- nfs-utils-1.2.2/support/export/rmtab.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/support/export/rmtab.c 2010-09-09 11:02:27.061025000 -0400 @@ -19,39 +19,54 @@ #include "xio.h" #include "xlog.h" +/* + * See if the entry already exists. If not, + * this was an instantiated wild card, and we + * must add it. + */ +static void +rmtab_read_wildcard(struct rmtabent *rep) +{ + nfs_export *exp, *exp2; + struct addrinfo *ai; + + ai = host_addrinfo(rep->r_client); + if (ai == NULL) + return; + + exp = export_allowed(ai, rep->r_path); + freeaddrinfo(ai); + if (exp == NULL) + return; + + exp2 = export_lookup(rep->r_client, exp->m_export.e_path, 0); + if (exp2 == NULL) { + struct exportent ee; + + memset(&ee, 0, sizeof(ee)); + dupexportent(&ee, &exp->m_export); + + ee.e_hostname = rep->r_client; + exp2 = export_create(&ee, 0); + exp2->m_changed = exp->m_changed; + } + exp2->m_mayexport = 1; +} + int rmtab_read(void) { struct rmtabent *rep; - nfs_export *exp = NULL; setrmtabent("r"); while ((rep = getrmtabent(1, NULL)) != NULL) { - struct hostent *hp = NULL; int htype; - + htype = client_gettype(rep->r_client); - if ((htype == MCL_FQDN || htype == MCL_SUBNETWORK) - && (hp = gethostbyname (rep->r_client)) - && (hp = hostent_dup (hp), - exp = export_allowed (hp, rep->r_path))) { - /* see if the entry already exists, otherwise this was an instantiated - * wild card, and we must add it - */ - nfs_export *exp2 = export_lookup(rep->r_client, - exp->m_export.e_path, 0); - if (!exp2) { - struct exportent ee; - dupexportent(&ee, &exp->m_export); - ee.e_hostname = rep->r_client; - exp2 = export_create(&ee, 0); - exp2->m_changed = exp->m_changed; - } - free (hp); - exp2->m_mayexport = 1; - } else if (hp) /* export_allowed failed */ - free(hp); + if (htype == MCL_FQDN || htype == MCL_SUBNETWORK) + rmtab_read_wildcard(rep); } + if (errno == EINVAL) { /* Something goes wrong. We need to fix the rmtab file. */ 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-09-09 11:02:27.066025000 -0400 @@ -10,6 +10,8 @@ #define EXPORTFS_H #include + +#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,26 +116,26 @@ 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 *); +nfs_client * client_dup(const nfs_client *clp, + const struct addrinfo *ai); int client_gettype(char *hname); -int client_check(nfs_client *, struct hostent *); -int client_match(nfs_client *, char *hname); +int client_check(const nfs_client *clp, + const struct addrinfo *ai); 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); +char * client_compose(const struct addrinfo *ai); +struct addrinfo * client_resolve(const struct sockaddr *sap); +int client_member(const char *client, + const char *name); -int export_read(char *fname); -void export_add(nfs_export *); +void export_read(char *fname); void export_reset(nfs_export *); nfs_export * export_lookup(char *hname, char *path, int caconical); -nfs_export * export_find(struct hostent *, char *path); -nfs_export * export_allowed(struct hostent *, char *path); +nfs_export * export_find(const struct addrinfo *ai, + const char *path); +nfs_export * export_allowed(const struct addrinfo *ai, + const char *path); nfs_export * export_create(struct exportent *, int canonical); -nfs_export * export_dup(nfs_export *, struct hostent *); void export_freeall(void); int export_export(nfs_export *); int export_unexport(nfs_export *); @@ -101,6 +148,19 @@ void xtab_append(nfs_export *); int secinfo_addflavor(struct flav_info *, struct exportent *); +char * host_ntop(const struct sockaddr *sap, + char *buf, const size_t buflen); +__attribute_malloc__ +struct addrinfo * host_pton(const char *paddr); +__attribute_malloc__ +struct addrinfo * host_addrinfo(const char *hostname); +__attribute_malloc__ +char * host_canonname(const struct sockaddr *sap); +__attribute_malloc__ +struct addrinfo * host_reliable_addrinfo(const struct sockaddr *sap); +__attribute_malloc__ +struct addrinfo * host_numeric_addrinfo(const struct sockaddr *sap); + int rmtab_read(void); struct nfskey * key_lookup(char *hname); diff -up nfs-utils-1.2.2/support/include/misc.h.orig nfs-utils-1.2.2/support/include/misc.h --- nfs-utils-1.2.2/support/include/misc.h.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/support/include/misc.h 2010-09-09 11:02:27.071028000 -0400 @@ -15,13 +15,6 @@ int randomkey(unsigned char *keyout, int len); int weakrandomkey(unsigned char *keyout, int len); -int matchhostname(const char *h1, const char *h2); - -struct hostent; -struct hostent *hostent_dup(struct hostent *hp); -struct hostent *get_hostent (const char *addr, int len, int type); -struct hostent *get_reliable_hostbyaddr(const char *addr, int len, int type); - extern int is_mountpoint(char *path); #endif /* MISC_H */ 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-09-09 11:02:27.076025000 -0400 @@ -83,7 +83,7 @@ struct exportent { int e_nsquids; int * e_sqgids; int e_nsqgids; - int e_fsid; + unsigned int e_fsid; char * e_mountpoint; int e_fslocmethod; char * e_fslocdata; @@ -152,10 +152,15 @@ 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); int svctcp_socket (u_long __number, int __reuse); -int svcudp_socket (u_long __number, int __reuse); +int svcudp_socket (u_long __number); + + +#define UNUSED(x) UNUSED_ ## x __attribute__((unused)) #endif /* NFSLIB_H */ 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-09-09 11:02:27.081025000 -0400 @@ -27,6 +27,12 @@ #include /* + * IANA does not define an IP protocol number for RDMA transports. + * Choose an arbitrary value we can use locally. + */ +#define NFSPROTO_RDMA (3939) + +/* * Conventional RPC program numbers */ #ifndef RPCBPROG @@ -160,4 +166,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/include/rpcmisc.h.orig nfs-utils-1.2.2/support/include/rpcmisc.h --- nfs-utils-1.2.2/support/include/rpcmisc.h.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/support/include/rpcmisc.h 2010-09-09 11:02:27.086024000 -0400 @@ -60,12 +60,12 @@ extern int _rpcsvcdirty; static inline struct sockaddr_in *nfs_getrpccaller_in(SVCXPRT *xprt) { - return (struct sockaddr_in *)svc_getcaller(xprt); + return (struct sockaddr_in *)(char *)svc_getcaller(xprt); } static inline struct sockaddr *nfs_getrpccaller(SVCXPRT *xprt) { - return (struct sockaddr *)svc_getcaller(xprt); + return (struct sockaddr *)(char *)svc_getcaller(xprt); } #endif /* RPCMISC_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-09-09 11:02:27.091025000 -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) @@ -330,7 +349,7 @@ cache_flush(int force) sprintf(path, "/proc/net/rpc/%s/flush", cachelist[c]); fd = open(path, O_RDWR); if (fd >= 0) { - if (write(fd, stime, strlen(stime)) != strlen(stime)) { + if (write(fd, stime, strlen(stime)) != (ssize_t)strlen(stime)) { xlog_warn("Writing to '%s' failed: errno %d (%s)", path, errno, strerror(errno)); } diff -up nfs-utils-1.2.2/support/nfs/conffile.c.orig nfs-utils-1.2.2/support/nfs/conffile.c --- nfs-utils-1.2.2/support/nfs/conffile.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/support/nfs/conffile.c 2010-09-09 11:02:27.097022000 -0400 @@ -49,7 +49,7 @@ #include "conffile.h" #include "xlog.h" -static void conf_load_defaults (int); +static void conf_load_defaults(void); static int conf_set(int , char *, char *, char *, char *, int , int ); @@ -212,7 +212,7 @@ conf_parse_line(int trans, char *line, s { char *val, *ptr; size_t i; - int j; + size_t j; static char *section = 0; static char *arg = 0; static int ln = 0; @@ -353,7 +353,7 @@ conf_parse(int trans, char *buf, size_t } static void -conf_load_defaults(int tr) +conf_load_defaults(void) { /* No defaults */ return; @@ -412,7 +412,7 @@ conf_reinit(void) trans = conf_begin(); /* Load default configuration values. */ - conf_load_defaults(trans); + conf_load_defaults(); /* Free potential existing configuration. */ if (conf_addr) { diff -up nfs-utils-1.2.2/support/nfs/getport.c.orig nfs-utils-1.2.2/support/nfs/getport.c --- nfs-utils-1.2.2/support/nfs/getport.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/support/nfs/getport.c 2010-09-09 11:02:27.103022000 -0400 @@ -216,6 +216,21 @@ nfs_get_proto(const char *netid, sa_fami struct netconfig *nconf; struct protoent *proto; + /* + * IANA does not define a protocol number for rdma netids, + * since "rdma" is not an IP protocol. + */ + if (strcmp(netid, "rdma") == 0) { + *family = AF_INET; + *protocol = NFSPROTO_RDMA; + return 1; + } + if (strcmp(netid, "rdma6") == 0) { + *family = AF_INET6; + *protocol = NFSPROTO_RDMA; + return 1; + } + nconf = getnetconfigent(netid); if (nconf == NULL) return 0; @@ -242,6 +257,16 @@ nfs_get_proto(const char *netid, sa_fami { struct protoent *proto; + /* + * IANA does not define a protocol number for rdma netids, + * since "rdma" is not an IP protocol. + */ + if (strcmp(netid, "rdma") == 0) { + *family = AF_INET; + *protocol = NFSPROTO_RDMA; + return 1; + } + proto = getprotobyname(netid); if (proto == NULL) return 0; diff -up nfs-utils-1.2.2/support/nfs/nfs_mntent.c.orig nfs-utils-1.2.2/support/nfs/nfs_mntent.c --- nfs-utils-1.2.2/support/nfs/nfs_mntent.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/support/nfs/nfs_mntent.c 2010-09-09 11:02:27.108025000 -0400 @@ -28,7 +28,7 @@ static char * mangle(const char *arg) { const unsigned char *s = (const unsigned char *)arg; char *ss, *sp; - int n; + unsigned int n; n = strlen(arg); ss = sp = xmalloc(4*n+1); diff -up nfs-utils-1.2.2/support/nfs/rmtab.c.orig nfs-utils-1.2.2/support/nfs/rmtab.c --- nfs-utils-1.2.2/support/nfs/rmtab.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/support/nfs/rmtab.c 2010-09-09 11:02:27.113025000 -0400 @@ -19,6 +19,18 @@ #include #include "nfslib.h" +/* + * Colons in incoming IPv6 presentation addresses have to + * replaced with another character, since rmtab already + * uses colons to delineate fields. + * + * Use a printable character, but one that would never be + * found in a presentation address or domain name + */ +#define IPV6_COLON ';' + +#define LINELEN (2048) + static FILE *rmfp = NULL; int @@ -56,7 +68,8 @@ struct rmtabent * fgetrmtabent(FILE *fp, int log, long *pos) { static struct rmtabent re; - char buf[2048], *count, *host, *path; + char *count, *host, *path, *c; + static char buf[LINELEN]; errno = 0; if (!fp) @@ -84,10 +97,16 @@ fgetrmtabent(FILE *fp, int log, long *po else re.r_count = 1; } while (0); + strncpy(re.r_client, host, sizeof (re.r_client) - 1); re.r_client[sizeof (re.r_client) - 1] = '\0'; + for (c = re.r_client; *c != '\0'; c++) + if (*c == IPV6_COLON) + *c = ':'; + strncpy(re.r_path, path, sizeof (re.r_path) - 1); re.r_path[sizeof (re.r_path) - 1] = '\0'; + return &re; } @@ -100,10 +119,27 @@ putrmtabent(struct rmtabent *rep, long * void fputrmtabent(FILE *fp, struct rmtabent *rep, long *pos) { + static char buf[LINELEN]; + char *c; + if (!fp || (pos && fseek (fp, *pos, SEEK_SET) != 0)) return; - fprintf(fp, "%s:%s:0x%.8x\n", rep->r_client, rep->r_path, - rep->r_count); + + /* + * To avoid confusing the token parser in fgetrmtabent(), + * convert colons in incoming IPv6 presentation addresses + * to semicolons. + */ + if (strlen(rep->r_client) > sizeof(buf)) { + xlog(L_ERROR, "client name too large"); + return; + } + strncpy(buf, rep->r_client, sizeof(buf)); + for (c = buf; *c != '\0'; c++) + if (*c == ':') + *c = IPV6_COLON; + + (void)fprintf(fp, "%s:%s:0x%.8x\n", buf, rep->r_path, rep->r_count); } void diff -up nfs-utils-1.2.2/support/nfs/rpcdispatch.c.orig nfs-utils-1.2.2/support/nfs/rpcdispatch.c --- nfs-utils-1.2.2/support/nfs/rpcdispatch.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/support/nfs/rpcdispatch.c 2010-09-09 11:02:27.136025000 -0400 @@ -27,12 +27,12 @@ rpc_dispatch(struct svc_req *rqstp, SVCX { struct rpc_dentry *dent; - if (rqstp->rq_vers > nvers) { + if (((int)rqstp->rq_vers) > nvers) { svcerr_progvers(transp, 1, nvers); return; } dtable += (rqstp->rq_vers - 1); - if (rqstp->rq_proc > dtable->nproc) { + if (((int)rqstp->rq_proc) > dtable->nproc) { svcerr_noproc(transp); return; } diff -up nfs-utils-1.2.2/support/nfs/rpcmisc.c.orig nfs-utils-1.2.2/support/nfs/rpcmisc.c --- nfs-utils-1.2.2/support/nfs/rpcmisc.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/support/nfs/rpcmisc.c 2010-09-09 11:02:27.145022000 -0400 @@ -154,7 +154,7 @@ rpc_init(char *name, int prog, int vers, sock = makesock(defport, IPPROTO_UDP); } if (sock == RPC_ANYSOCK) - sock = svcudp_socket (prog, 1); + sock = svcudp_socket (prog); transp = svcudp_create(sock); if (transp == NULL) { xlog(L_FATAL, "cannot create udp service."); 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-09-09 11:02:27.131022000 -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/nfs/svc_socket.c.orig nfs-utils-1.2.2/support/nfs/svc_socket.c --- nfs-utils-1.2.2/support/nfs/svc_socket.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/support/nfs/svc_socket.c 2010-09-09 11:02:27.150025000 -0400 @@ -157,9 +157,9 @@ svctcp_socket (u_long number, int reuse) * Create and bind a UDP socket based on program number */ int -svcudp_socket (u_long number, int reuse) +svcudp_socket (u_long number) { - return svc_socket (number, SOCK_DGRAM, IPPROTO_UDP, 0); + return svc_socket (number, SOCK_DGRAM, IPPROTO_UDP, FALSE); } #ifdef TEST @@ -174,7 +174,7 @@ check (u_long number, u_short port, int if (protocol == IPPROTO_TCP) socket = svctcp_socket (number, reuse); else - socket = svcudp_socket (number, reuse); + socket = svcudp_socket (number); if (socket < 0) return 1; 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-09-09 11:01:45.345738000 -0400 +++ nfs-utils-1.2.2/support/nsm/file.c 2010-09-09 11:02:27.167022000 -0400 @@ -67,7 +67,9 @@ #endif #include +#ifdef HAVE_SYS_CAPABILITY_H #include +#endif #include #include @@ -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-09-09 11:02:27.172025000 -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-09-09 11:02:27.191022000 -0400 +++ nfs-utils-1.2.2/tools/mountstats/Makefile.am 2010-09-09 11:02:27.193022000 -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-09-09 11:02:27.196022000 -0400 +++ nfs-utils-1.2.2/tools/mountstats/mountstats.man 2010-09-09 11:02:27.197027000 -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 [" "] " " [ " "]" +.SH DESCRIPTION +The +.B mountstats +command displays NFS client statisitics on each given +.I +.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 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-09-09 11:02:27.218022000 -0400 +++ nfs-utils-1.2.2/tools/nfs-iostat/Makefile.am 2010-09-09 11:02:27.219031000 -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-09-09 11:02:27.228021000 -0400 +++ nfs-utils-1.2.2/tools/nfs-iostat/nfsiostat.man 2010-09-09 11:02:27.229027000 -0400 @@ -0,0 +1,71 @@ +.\" +.\" 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 [[" "] [" "]] [" "][" "] +.SH DESCRIPTION +The +.B nfsiostat +command displays NFS client per-mount statisitics. +.TP + +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 + +If the +.I +parameter is +specified, the value of +.I +determines the number of reports generated at +. +seconds apart. if the interval parameter is +specified without the +.I +parameter, the command generates reports continuously. +.TP + +Define below +.TP + +If one or more +.I +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 +.TP +.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 diff -up nfs-utils-1.2.2/tools/nfs-iostat/nfs-iostat.py.orig nfs-utils-1.2.2/tools/nfs-iostat/nfs-iostat.py --- nfs-utils-1.2.2/tools/nfs-iostat/nfs-iostat.py.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/tools/nfs-iostat/nfs-iostat.py 2010-09-09 11:02:27.224025000 -0400 @@ -366,6 +366,12 @@ class DeviceData: sends = float(self.__rpc_data['rpcsends']) if sample_time == 0: sample_time = float(self.__nfs_data['age']) + # sample_time could still be zero if the export was just mounted. + # Set it to 1 to avoid divide by zero errors in this case since we'll + # likely still have relevant mount statistics to show. + # + if sample_time == 0: + sample_time = 1; if sends != 0: backlog = (float(self.__rpc_data['backlogutil']) / sends) / sample_time else: diff -up nfs-utils-1.2.2/utils/exportfs/exportfs.c.orig nfs-utils-1.2.2/utils/exportfs/exportfs.c --- nfs-utils-1.2.2/utils/exportfs/exportfs.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/utils/exportfs/exportfs.c 2010-09-09 11:02:27.234025000 -0400 @@ -12,20 +12,23 @@ #include #endif +#include +#include #include #include #include +#include #include #include #include #include +#include #include #include -#include "xmalloc.h" + #include "misc.h" #include "nfslib.h" #include "exportfs.h" -#include "xmalloc.h" #include "xlog.h" static void export_all(int verbose); @@ -34,13 +37,15 @@ static void unexportfs(char *arg, int ve static void exports_update(int verbose); static void dump(int verbose); static void error(nfs_export *exp, int err); -static void usage(void); +static void usage(const char *progname); static void validate_export(nfs_export *exp); +static int matchhostname(const char *hostname1, const char *hostname2); int main(int argc, char **argv) { char *options = NULL; + char *progname = NULL; int f_export = 1; int f_all = 0; int f_verbose = 0; @@ -50,7 +55,14 @@ main(int argc, char **argv) int new_cache = 0; int force_flush = 0; - xlog_open("exportfs"); + if ((progname = strrchr(argv[0], '/')) != NULL) + progname++; + else + progname = argv[0]; + + xlog_open(progname); + xlog_stderr(1); + xlog_syslog(0); export_errno = 0; @@ -79,21 +91,21 @@ main(int argc, char **argv) force_flush = 1; break; default: - usage(); + usage(progname); break; } } if (optind != argc && f_all) { - fprintf(stderr,"exportfs: extra arguments are not permitted with -a or -r.\n"); + xlog(L_ERROR, "extra arguments are not permitted with -a or -r"); return 1; } if (f_ignore && (f_all || ! f_export)) { - fprintf(stderr,"exportfs: -i not meaningful with -a, -r or -u.\n"); + xlog(L_ERROR, "-i not meaningful with -a, -r or -u"); return 1; } if (f_reexport && ! f_export) { - fprintf(stderr, "exportfs: -r and -u are incompatible.\n"); + xlog(L_ERROR, "-r and -u are incompatible"); return 1; } new_cache = check_new_cache(); @@ -102,8 +114,10 @@ main(int argc, char **argv) if (new_cache) cache_flush(1); else { - fprintf(stderr, "exportfs: -f: only available with new cache controls: mount /proc/fs/nfsd first\n"); - exit(1); + xlog(L_ERROR, "-f is available only " + "with new cache controls. " + "Mount /proc/fs/nfsd first"); + return 1; } return 0; } else { @@ -232,7 +246,7 @@ exportfs(char *arg, char *options, int v { struct exportent *eep; nfs_export *exp; - struct hostent *hp = NULL; + struct addrinfo *ai = NULL; char *path; char *hname = arg; int htype; @@ -241,36 +255,25 @@ exportfs(char *arg, char *options, int v *path++ = '\0'; if (!path || *path != '/') { - fprintf(stderr, "Invalid exporting option: %s\n", arg); + xlog(L_ERROR, "Invalid exporting option: %s", arg); return; } - if ((htype = client_gettype(hname)) == MCL_FQDN && - (hp = gethostbyname(hname)) != NULL) { - struct hostent *hp2 = hostent_dup (hp); - hp = gethostbyaddr(hp2->h_addr, hp2->h_length, - hp2->h_addrtype); - if (hp) { - free(hp2); - hp = hostent_dup(hp); - } else - hp = hp2; - exp = export_find(hp, path); - hname = hp->h_name; - } else { + if ((htype = client_gettype(hname)) == MCL_FQDN) { + ai = host_addrinfo(hname); + if (ai != NULL) { + exp = export_find(ai, path); + hname = ai->ai_canonname; + } + } else exp = export_lookup(hname, path, 0); - } if (!exp) { if (!(eep = mkexportent(hname, path, options)) || - !(exp = export_create(eep, 0))) { - if (hp) free (hp); - return; - } - } else if (!updateexportent(&exp->m_export, options)) { - if (hp) free (hp); - return; - } + !(exp = export_create(eep, 0))) + goto out; + } else if (!updateexportent(&exp->m_export, options)) + goto out; if (verbose) printf("exporting %s:%s\n", exp->m_client->m_hostname, @@ -280,14 +283,16 @@ exportfs(char *arg, char *options, int v exp->m_changed = 1; exp->m_warned = 0; validate_export(exp); - if (hp) free (hp); + +out: + freeaddrinfo(ai); } static void unexportfs(char *arg, int verbose) { nfs_export *exp; - struct hostent *hp = NULL; + struct addrinfo *ai = NULL; char *path; char *hname = arg; int htype; @@ -296,16 +301,14 @@ unexportfs(char *arg, int verbose) *path++ = '\0'; if (!path || *path != '/') { - fprintf(stderr, "Invalid unexporting option: %s\n", - arg); + xlog(L_ERROR, "Invalid unexporting option: %s", arg); return; } if ((htype = client_gettype(hname)) == MCL_FQDN) { - if ((hp = gethostbyname(hname)) != 0) { - hp = hostent_dup (hp); - hname = (char *) hp->h_name; - } + ai = host_addrinfo(hname); + if (ai) + hname = ai->ai_canonname; } for (exp = exportlist[htype].p_head; exp; exp = exp->m_next) { @@ -341,7 +344,7 @@ unexportfs(char *arg, int verbose) exp->m_mayexport = 0; } - if (hp) free (hp); + freeaddrinfo(ai); } static int can_test(void) @@ -393,14 +396,12 @@ validate_export(nfs_export *exp) int fs_has_fsid = 0; if (stat(path, &stb) < 0) { - fprintf(stderr, "exportfs: Warning: %s does not exist\n", - path); + xlog(L_ERROR, "Failed to stat %s: %m \n", path); return; } if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) { - fprintf(stderr, "exportfs: Warning: %s is neither " - "a directory nor a file.\n" - " remote access will fail\n", path); + xlog(L_ERROR, "%s is neither a directory nor a file. " + "Remote access will fail", path); return; } if (!can_test()) @@ -413,24 +414,95 @@ validate_export(nfs_export *exp) if ((exp->m_export.e_flags & NFSEXP_FSID) || exp->m_export.e_uuid || fs_has_fsid) { if ( !test_export(path, 1)) { - fprintf(stderr, "exportfs: Warning: %s does not " - "support NFS export.\n", - path); + xlog(L_ERROR, "%s does not support NFS export", path); return; } } else if ( ! test_export(path, 0)) { if (test_export(path, 1)) - fprintf(stderr, "exportfs: Warning: %s requires fsid= " - "for NFS export\n", path); + xlog(L_ERROR, "%s requires fsid= for NFS export", path); else - fprintf(stderr, "exportfs: Warning: %s does not " - "support NFS export.\n", - path); + xlog(L_ERROR, "%s does not support NFS export", path); return; } } +static _Bool +is_hostname(const char *sp) +{ + if (*sp == '\0' || *sp == '@') + return false; + + for (; *sp != '\0'; sp++) { + if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/') + return false; + if (*sp == '\\' && sp[1] != '\0') + sp++; + } + + return true; +} + +static _Bool +compare_sockaddrs4(const struct sockaddr *sa1, const struct sockaddr *sa2) +{ + const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1; + const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2; + return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr; +} + +static _Bool +compare_sockaddrs(const struct sockaddr *sa1, const struct sockaddr *sa2) +{ + if (sa1->sa_family == sa2->sa_family) + switch (sa1->sa_family) { + case AF_INET: + return compare_sockaddrs4(sa1, sa2); + } + + return false; +} + +static int +matchhostname(const char *hostname1, const char *hostname2) +{ + struct addrinfo *results1 = NULL, *results2 = NULL; + struct addrinfo *ai1, *ai2; + int result = 0; + + if (strcasecmp(hostname1, hostname2) == 0) + return 1; + + /* + * Don't pass export wildcards or netgroup names to DNS + */ + if (!is_hostname(hostname1) || !is_hostname(hostname2)) + return 0; + + results1 = host_addrinfo(hostname1); + if (results1 == NULL) + goto out; + results2 = host_addrinfo(hostname2); + if (results2 == NULL) + goto out; + + if (strcasecmp(results1->ai_canonname, results2->ai_canonname) == 0) { + result = 1; + goto out; + } + + for (ai1 = results1; ai1 != NULL; ai1 = ai1->ai_next) + for (ai2 = results2; ai2 != NULL; ai2 = ai2->ai_next) + if (compare_sockaddrs(ai1->ai_addr, ai2->ai_addr)) { + result = 1; + break; + } + +out: + freeaddrinfo(results1); + freeaddrinfo(results2); + return result; +} static char dumpopt(char c, char *fmt, ...) @@ -532,13 +604,13 @@ dump(int verbose) static void error(nfs_export *exp, int err) { - fprintf(stderr, "%s:%s: %s\n", exp->m_client->m_hostname, + xlog(L_ERROR, "%s:%s: %s\n", exp->m_client->m_hostname, exp->m_export.e_path, strerror(err)); } static void -usage(void) +usage(const char *progname) { - fprintf(stderr, "usage: exportfs [-aruv] [host:/path]\n"); + fprintf(stderr, "usage: %s [-aruv] [host:/path]\n", progname); exit(1); } 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-09-09 11:02:27.239025000 -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-09-09 11:02:27.245022000 -0400 @@ -42,6 +42,7 @@ #include #include #include +#include #include @@ -76,7 +77,7 @@ prepare_krb5_rfc1964_buffer(gss_krb5_luc unsigned char fakeseed[FAKESEED_SIZE]; uint32_t word_send_seq; gss_krb5_lucid_key_t enc_key; - int i; + uint32_t i; char *skd, *dkd; gss_buffer_desc fakeoid; @@ -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,102 @@ 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 (endtime) + *endtime = lctx->endtime; + 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 +266,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 +288,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 +311,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 +322,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-09-09 11:02:27.250022000 -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 #include #include +#include #include #include #include @@ -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,122 @@ 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; + 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; + 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.c.orig nfs-utils-1.2.2/utils/gssd/gssd.c --- nfs-utils-1.2.2/utils/gssd/gssd.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/utils/gssd/gssd.c 2010-09-09 11:02:27.255022000 -0400 @@ -78,7 +78,7 @@ void sig_hup(int signal) { /* don't exit on SIGHUP */ - printerr(1, "Received SIGHUP... Ignoring.\n"); + printerr(1, "Received SIGHUP(%d)... Ignoring.\n", signal); return; } diff -up nfs-utils-1.2.2/utils/gssd/gssd_main_loop.c.orig nfs-utils-1.2.2/utils/gssd/gssd_main_loop.c --- nfs-utils-1.2.2/utils/gssd/gssd_main_loop.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/utils/gssd/gssd_main_loop.c 2010-09-09 11:02:27.260025000 -0400 @@ -63,6 +63,8 @@ static volatile int dir_changed = 1; static void dir_notify_handler(int sig, siginfo_t *si, void *data) { + printerr(2, "dir_notify_handler: sig %d si %p data %p\n", sig, si, data); + dir_changed = 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-09-09 11:02:27.266022000 -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) @@ -798,7 +859,7 @@ int create_auth_rpc_client(struct clnt_i * Do this before creating rpc connection since we won't need * rpc connection if it fails! */ - if (limit_krb5_enctypes(&sec, uid)) { + if (limit_krb5_enctypes(&sec)) { printerr(1, "WARNING: Failed while limiting krb5 " "encryption types for user with uid %d\n", uid); @@ -875,7 +936,7 @@ int create_auth_rpc_client(struct clnt_i if (sec.cred != GSS_C_NO_CREDENTIAL) gss_release_cred(&min_stat, &sec.cred); /* Restore euid to original value */ - if ((save_uid != -1) && (setfsuid(save_uid) != uid)) { + if (((int)save_uid != -1) && (setfsuid(save_uid) != (int)uid)) { printerr(0, "WARNING: Failed to restore fsuid" " to uid %d from %d\n", save_uid, uid); } @@ -1100,7 +1161,7 @@ handle_krb5_upcall(struct clnt_info *clp { uid_t uid; - if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) { + if (read(clp->krb5_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) { printerr(0, "WARNING: failed reading uid from krb5 " "upcall pipe: %s\n", strerror(errno)); return; @@ -1114,7 +1175,7 @@ handle_spkm3_upcall(struct clnt_info *cl { uid_t uid; - if (read(clp->spkm3_fd, &uid, sizeof(uid)) < sizeof(uid)) { + if (read(clp->spkm3_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) { printerr(0, "WARNING: failed reading uid from spkm3 " "upcall pipe: %s\n", strerror(errno)); return; @@ -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-09-09 11:02:27.272022000 -0400 @@ -224,6 +224,13 @@ gssd_find_existing_krb5_ccache(uid_t uid free(namelist[i]); continue; } + if (uid == 0 && !root_uses_machine_creds && + strstr(namelist[i]->d_name, "_machine_")) { + printerr(3, "CC file '%s' not available to root\n", + statname); + free(namelist[i]); + continue; + } if (!query_krb5_ccache(buf, &princname, &realm)) { printerr(3, "CC file '%s' is expired or corrupt\n", statname); @@ -292,61 +299,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. @@ -661,24 +613,32 @@ out: * and has *any* instance (hostname), return 1. * Otherwise return 0, indicating no match. */ +#ifdef HAVE_KRB5 static int -realm_and_service_match(krb5_context context, krb5_principal p, - const char *realm, const char *service) +realm_and_service_match(krb5_principal p, const char *realm, const char *service) { -#ifdef HAVE_KRB5 /* Must have two components */ if (p->length != 2) return 0; + if ((strlen(realm) == p->realm.length) && (strncmp(realm, p->realm.data, p->realm.length) == 0) && (strlen(service) == p->data[0].length) && (strncmp(service, p->data[0].data, p->data[0].length) == 0)) return 1; + + return 0; +} #else +static int +realm_and_service_match(krb5_context context, krb5_principal p, + const char *realm, const char *service) +{ const char *name, *inst; if (p->name.name_string.len != 2) return 0; + name = krb5_principal_get_comp_string(context, p, 0); inst = krb5_principal_get_comp_string(context, p, 1); if (name == NULL || inst == NULL) @@ -686,9 +646,10 @@ realm_and_service_match(krb5_context con if ((strcmp(realm, p->realm) == 0) && (strcmp(service, name) == 0)) return 1; -#endif + return 0; } +#endif /* * Search the given keytab file looking for an entry with the given @@ -710,7 +671,7 @@ gssd_search_krb5_keytab(krb5_context con krb5_kt_cursor cursor; krb5_error_code code; struct gssd_k5_kt_princ *ple; - int retval = -1; + int retval = -1, status; char kt_name[BUFSIZ]; char *pname; char *k5err = NULL; @@ -753,8 +714,12 @@ gssd_search_krb5_keytab(krb5_context con printerr(4, "Processing keytab entry for principal '%s'\n", pname); /* Use the first matching keytab entry found */ - if ((realm_and_service_match(context, kte->principal, realm, - service))) { +#ifdef HAVE_KRB5 + status = realm_and_service_match(kte->principal, realm, service); +#else + status = realm_and_service_match(context, kte->principal, realm, service); +#endif + if (status) { printerr(4, "We WILL use this entry (%s)\n", pname); ple = get_ple_by_princ(context, kte->principal); /* @@ -1304,3 +1269,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) +{ + 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/gssd/krb5_util.h.orig nfs-utils-1.2.2/utils/gssd/krb5_util.h --- nfs-utils-1.2.2/utils/gssd/krb5_util.h.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/utils/gssd/krb5_util.h 2010-09-09 11:02:27.277030000 -0400 @@ -36,7 +36,7 @@ char *gssd_k5_err_msg(krb5_context conte void gssd_k5_get_default_realm(char **def_realm); #ifdef HAVE_SET_ALLOWABLE_ENCTYPES -int limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid); +int limit_krb5_enctypes(struct rpc_gss_sec *sec); #endif /* diff -up nfs-utils-1.2.2/utils/gssd/svcgssd.c.orig nfs-utils-1.2.2/utils/gssd/svcgssd.c --- nfs-utils-1.2.2/utils/gssd/svcgssd.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/utils/gssd/svcgssd.c 2010-09-09 11:02:27.282029000 -0400 @@ -160,7 +160,7 @@ void sig_hup(int signal) { /* don't exit on SIGHUP */ - printerr(1, "Received SIGHUP... Ignoring.\n"); + printerr(1, "Received SIGHUP(%d)... Ignoring.\n", signal); return; } diff -up nfs-utils-1.2.2/utils/gssd/svcgssd_proc.c.orig nfs-utils-1.2.2/utils/gssd/svcgssd_proc.c --- nfs-utils-1.2.2/utils/gssd/svcgssd_proc.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/utils/gssd/svcgssd_proc.c 2010-09-09 11:02:27.288022000 -0400 @@ -132,7 +132,7 @@ struct gss_verifier { #define RPCSEC_GSS_SEQ_WIN 5 static int -send_response(FILE *f, gss_buffer_desc *in_handle, gss_buffer_desc *in_token, +send_response(gss_buffer_desc *in_handle, gss_buffer_desc *in_token, u_int32_t maj_stat, u_int32_t min_stat, gss_buffer_desc *out_handle, gss_buffer_desc *out_token) { @@ -431,12 +431,6 @@ handle_nullreq(FILE *f) { print_hexl("in_tok", in_tok.value, in_tok.length); #endif - if (in_tok.length < 0) { - printerr(0, "WARNING: handle_nullreq: " - "failed parsing request\n"); - goto out_err; - } - if (in_handle.length != 0) { /* CONTINUE_INIT case */ if (in_handle.length != sizeof(ctx)) { printerr(0, "WARNING: handle_nullreq: " @@ -498,7 +492,7 @@ handle_nullreq(FILE *f) { 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, + send_response(&in_handle, &in_tok, maj_stat, min_stat, &out_handle, &out_tok); out: if (ctx_token.value != NULL) @@ -514,7 +508,7 @@ out: out_err: if (ctx != GSS_C_NO_CONTEXT) gss_delete_sec_context(&ignore_min_stat, &ctx, &ignore_out_tok); - send_response(f, &in_handle, &in_tok, maj_stat, min_stat, + send_response(&in_handle, &in_tok, maj_stat, min_stat, &null_token, &null_token); goto out; } diff -up nfs-utils-1.2.2/utils/idmapd/atomicio.c.orig nfs-utils-1.2.2/utils/idmapd/atomicio.c --- nfs-utils-1.2.2/utils/idmapd/atomicio.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/utils/idmapd/atomicio.c 2010-09-09 11:02:27.311022000 -0400 @@ -43,7 +43,8 @@ atomicio( size_t n) { char *s = _s; - ssize_t res, pos = 0; + ssize_t res; + size_t pos = 0; while (n > pos) { res = (f) (fd, s + pos, n - pos); diff -up nfs-utils-1.2.2/utils/idmapd/idmapd.c.orig nfs-utils-1.2.2/utils/idmapd/idmapd.c --- nfs-utils-1.2.2/utils/idmapd/idmapd.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/utils/idmapd/idmapd.c 2010-09-09 11:02:27.316022000 -0400 @@ -117,8 +117,24 @@ struct idmap_client { TAILQ_ENTRY(idmap_client) ic_next; }; static struct idmap_client nfsd_ic[2] = { -{IC_IDNAME, "Server", "", IC_IDNAME_CHAN, -1, -1, 0}, -{IC_NAMEID, "Server", "", IC_NAMEID_CHAN, -1, -1, 0}, +{ + .ic_which = IC_IDNAME, + .ic_clid = "Server", + .ic_id = "", + .ic_path = IC_IDNAME_CHAN, + .ic_fd = -1, + .ic_dirfd = -1, + .ic_scanned = 0 +}, +{ + .ic_which = IC_NAMEID, + .ic_clid = "Server", + .ic_id = "", + .ic_path = IC_NAMEID_CHAN, + .ic_fd = -1, + .ic_dirfd = -1, + .ic_scanned = 0 +}, }; TAILQ_HEAD(idmap_clientq, idmap_client); @@ -170,7 +186,7 @@ flush_nfsd_cache(char *path, time_t now) fd = open(path, O_RDWR); if (fd == -1) return -1; - if (write(fd, stime, strlen(stime)) != strlen(stime)) { + if (write(fd, stime, strlen(stime)) != (ssize_t)strlen(stime)) { errx(1, "Flushing nfsd cache failed: errno %d (%s)", errno, strerror(errno)); } @@ -381,7 +397,7 @@ main(int argc, char **argv) } static void -dirscancb(int fd, short which, void *data) +dirscancb(int UNUSED(fd), short UNUSED(which), void *data) { int nent, i; struct dirent **ents; @@ -465,13 +481,13 @@ out: } static void -svrreopen(int fd, short which, void *data) +svrreopen(int UNUSED(fd), short UNUSED(which), void *UNUSED(data)) { nfsdreopen(); } static void -clntscancb(int fd, short which, void *data) +clntscancb(int UNUSED(fd), short UNUSED(which), void *data) { struct idmap_clientq *icq = data; struct idmap_client *ic; @@ -485,7 +501,7 @@ clntscancb(int fd, short which, void *da } static void -nfsdcb(int fd, short which, void *data) +nfsdcb(int UNUSED(fd), short which, void *data) { struct idmap_client *ic = data; struct idmap_msg im; @@ -660,7 +676,7 @@ imconv(struct idmap_client *ic, struct i } static void -nfscb(int fd, short which, void *data) +nfscb(int UNUSED(fd), short which, void *data) { struct idmap_client *ic = data; struct idmap_msg im; @@ -845,7 +861,7 @@ nametoidres(struct idmap_msg *im) static int validateascii(char *string, u_int32_t len) { - int i; + u_int32_t i; for (i = 0; i < len; i++) { if (string[i] == '\0') @@ -901,7 +917,7 @@ static int getfield(char **bpp, char *fld, size_t fldsz) { char *bp; - u_int val, n; + int val, n; while ((bp = strsep(bpp, " ")) != NULL && bp[0] == '\0') ; diff -up nfs-utils-1.2.2/utils/mount/configfile.c.orig nfs-utils-1.2.2/utils/mount/configfile.c --- nfs-utils-1.2.2/utils/mount/configfile.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/utils/mount/configfile.c 2010-09-09 11:02:27.321025000 -0400 @@ -192,7 +192,8 @@ void free_all(void) } } static char *versions[] = {"v2", "v3", "v4", "vers", "nfsvers", NULL}; -int inline check_vers(char *mopt, char *field) +static int +check_vers(char *mopt, char *field) { int i, found=0; @@ -229,7 +230,8 @@ extern sa_family_t config_default_family * If so, set the appropriate global value which will * be used as the initial value in the server negation. */ -int inline default_value(char *mopt) +static int +default_value(char *mopt) { struct mount_options *options = NULL; int dftlen = strlen("default"); 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-09-09 11:02:27.375018000 -0400 @@ -110,13 +110,15 @@ auth_reload() return counter; } -static char *get_client_hostname(struct sockaddr_in *caller, struct hostent *hp, enum auth_error *error) +static char * +get_client_hostname(struct sockaddr_in *caller, struct addrinfo *ai, + enum auth_error *error) { char *n; if (use_ipaddr) return strdup(inet_ntoa(caller->sin_addr)); - n = client_compose(hp); + n = client_compose(ai); *error = unknown_host; if (!n) return NULL; @@ -128,8 +130,8 @@ static char *get_client_hostname(struct /* return static nfs_export with details filled in */ static nfs_export * -auth_authenticate_newcache(char *what, struct sockaddr_in *caller, - char *path, struct hostent *hp, +auth_authenticate_newcache(struct sockaddr_in *caller, + char *path, struct addrinfo *ai, enum auth_error *error) { nfs_export *exp; @@ -137,12 +139,12 @@ auth_authenticate_newcache(char *what, s free(my_client.m_hostname); - my_client.m_hostname = get_client_hostname(caller, hp, error); + my_client.m_hostname = get_client_hostname(caller, ai, error); if (my_client.m_hostname == NULL) 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; @@ -152,7 +154,7 @@ auth_authenticate_newcache(char *what, s 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)) + if (use_ipaddr && !client_check(exp->m_client, ai)) continue; break; } @@ -166,18 +168,19 @@ auth_authenticate_newcache(char *what, s } static nfs_export * -auth_authenticate_internal(char *what, struct sockaddr_in *caller, - char *path, struct hostent *hp, +auth_authenticate_internal(struct sockaddr_in *caller, + char *path, struct addrinfo *ai, enum auth_error *error) { nfs_export *exp; if (new_cache) { - exp = auth_authenticate_newcache(what, caller, path, hp, error); + exp = auth_authenticate_newcache(caller, path, ai, error); if (!exp) return NULL; } else { - if (!(exp = export_find(hp, path))) { + exp = export_find(ai, path); + if (exp == NULL) { *error = no_entry; return NULL; } @@ -202,7 +205,7 @@ auth_authenticate(char *what, struct soc nfs_export *exp = NULL; char epath[MAXPATHLEN+1]; char *p = NULL; - struct hostent *hp = NULL; + struct addrinfo *ai = NULL; struct in_addr addr = caller->sin_addr; enum auth_error error = bad_path; @@ -216,14 +219,14 @@ auth_authenticate(char *what, struct soc epath[sizeof (epath) - 1] = '\0'; auth_fixpath(epath); /* strip duplicate '/' etc */ - hp = client_resolve(caller->sin_addr); - if (!hp) + ai = client_resolve((struct sockaddr *)caller); + if (ai == NULL) return exp; /* Try the longest matching exported pathname. */ while (1) { - exp = auth_authenticate_internal(what, caller, epath, - hp, &error); + exp = auth_authenticate_internal(caller, epath, + ai, &error); if (exp || (error != not_exported && error != no_entry)) break; /* We have to treat the root, "/", specially. */ @@ -246,31 +249,30 @@ auth_authenticate(char *what, struct soc case no_entry: xlog(L_WARNING, "refused %s request from %s for %s (%s): no export entry", - what, hp->h_name, path, epath); + what, ai->ai_canonname, path, epath); break; case not_exported: xlog(L_WARNING, "refused %s request from %s for %s (%s): not exported", - what, hp->h_name, path, epath); + what, ai->ai_canonname, path, epath); break; case illegal_port: xlog(L_WARNING, "refused %s request from %s for %s (%s): illegal port %d", - what, hp->h_name, path, epath, ntohs(caller->sin_port)); + what, ai->ai_canonname, path, epath, ntohs(caller->sin_port)); break; case success: xlog(L_NOTICE, "authenticated %s request from %s:%d for %s (%s)", - what, hp->h_name, ntohs(caller->sin_port), path, epath); + what, ai->ai_canonname, ntohs(caller->sin_port), path, epath); break; default: xlog(L_NOTICE, "%s request from %s:%d for %s (%s) gave %d", - what, hp->h_name, ntohs(caller->sin_port), path, epath, error); + what, ai->ai_canonname, ntohs(caller->sin_port), + path, epath, error); } - if (hp) - free (hp); - + freeaddrinfo(ai); return exp; } 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-09-09 11:02:27.380016000 -0400 @@ -77,8 +77,8 @@ void auth_unix_ip(FILE *f) char class[20]; char ipaddr[20]; char *client = NULL; - struct in_addr addr; - struct hostent *he = NULL; + struct addrinfo *tmp = NULL; + struct addrinfo *ai = NULL; if (readline(fileno(f), &lbuf, &lbuflen) != 1) return; @@ -93,17 +93,20 @@ void auth_unix_ip(FILE *f) if (qword_get(&cp, ipaddr, 20) <= 0) return; - if (inet_aton(ipaddr, &addr)==0) + tmp = host_pton(ipaddr); + if (tmp == NULL) return; auth_reload(); /* addr is a valid, interesting address, find the domain name... */ if (!use_ipaddr) { - he = client_resolve(addr); - client = client_compose(he); + ai = client_resolve(tmp->ai_addr); + client = client_compose(ai); + freeaddrinfo(ai); } - + freeaddrinfo(tmp); + qword_print(f, "nfsd"); qword_print(f, ipaddr); qword_printint(f, time(0)+30*60); @@ -114,8 +117,7 @@ void auth_unix_ip(FILE *f) qword_eol(f); xlog(D_CALL, "auth_unix_ip: client %p '%s'", client, client?client: "DEFAULT"); - if (client) free(client); - free(he); + free(client); } void auth_unix_gid(FILE *f) @@ -125,7 +127,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 +138,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 +155,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; im_export.e_flags & NFSEXP_CROSSMOUNT) { static nfs_export *prev = NULL; @@ -461,22 +507,29 @@ void nfsd_fh(FILE *f) continue; check_uuid: if (exp->m_export.e_uuid) - get_uuid(NULL, exp->m_export.e_uuid, + get_uuid(exp->m_export.e_uuid, uuidlen, u); - else if (get_uuid(path, NULL, uuidlen, u) == 0) - continue; + else + for (type = 0; + uuid_by_path(path, type, uuidlen, u); + type++) + if (memcmp(u, fhuuid, uuidlen) == 0) + break; if (memcmp(u, fhuuid, uuidlen) != 0) continue; break; } if (use_ipaddr) { - if (he == NULL) { - if (!inet_aton(dom, &addr)) + if (ai == NULL) { + struct addrinfo *tmp; + tmp = host_pton(dom); + if (tmp == NULL) goto out; - he = client_resolve(addr); + ai = client_resolve(tmp->ai_addr); + freeaddrinfo(tmp); } - if (!client_check(exp->m_client, he)) + if (!client_check(exp->m_client, ai)) continue; } /* It's a match !! */ @@ -534,21 +587,20 @@ void nfsd_fh(FILE *f) out: if (found_path) free(found_path); - if (he) - free(he); + freeaddrinfo(ai); free(dom); xlog(D_CALL, "nfsd_fh: found %p path %s", found, found ? found->e_path : NULL); return; } -static void write_fsloc(FILE *f, struct exportent *ep, char *path) +static void write_fsloc(FILE *f, struct exportent *ep) { struct servers *servers; if (ep->e_fslocmethod == FSLOC_NONE) return; - servers = replicas_lookup(ep->e_fslocmethod, ep->e_fslocdata, path); + servers = replicas_lookup(ep->e_fslocmethod, ep->e_fslocdata); if (!servers) return; qword_print(f, "fsloc"); @@ -596,17 +648,17 @@ static int dump_to_cache(FILE *f, char * qword_printint(f, exp->e_anonuid); qword_printint(f, exp->e_anongid); qword_printint(f, exp->e_fsid); - write_fsloc(f, exp, path); + write_fsloc(f, exp); write_secinfo(f, exp, flag_mask); if (exp->e_uuid == NULL || different_fs) { char u[16]; - if (get_uuid(path, NULL, 16, u)) { + if (uuid_by_path(path, 0, 16, u)) { qword_print(f, "uuid"); qword_printhex(f, u, 16); } } else { char u[16]; - get_uuid(NULL, exp->e_uuid, 16, u); + get_uuid(exp->e_uuid, 16, u); qword_print(f, "uuid"); qword_printhex(f, u, 16); } @@ -614,12 +666,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) @@ -629,19 +681,22 @@ static int path_matches(nfs_export *exp, return strcmp(path, exp->m_export.e_path) == 0; } -static int client_matches(nfs_export *exp, char *dom, struct hostent *he) +static int +client_matches(nfs_export *exp, char *dom, struct addrinfo *ai) { if (use_ipaddr) - return client_check(exp->m_client, he); + return client_check(exp->m_client, ai); return client_member(dom, exp->m_client->m_hostname); } -static int export_matches(nfs_export *exp, char *dom, char *path, struct hostent *he) +static int +export_matches(nfs_export *exp, char *dom, char *path, struct addrinfo *ai) { - return path_matches(exp, path) && client_matches(exp, dom, he); + return path_matches(exp, path) && client_matches(exp, dom, ai); } -static nfs_export *lookup_export(char *dom, char *path, struct hostent *he) +static nfs_export * +lookup_export(char *dom, char *path, struct addrinfo *ai) { nfs_export *exp; nfs_export *found = NULL; @@ -650,7 +705,7 @@ static nfs_export *lookup_export(char *d for (i=0 ; i < MCL_MAXTYPES; i++) { for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { - if (!export_matches(exp, dom, path, he)) + if (!export_matches(exp, dom, path, ai)) continue; if (!found) { found = exp; @@ -698,9 +753,7 @@ void nfsd_export(FILE *f) char *cp; char *dom, *path; nfs_export *found = NULL; - struct in_addr addr; - struct hostent *he = NULL; - + struct addrinfo *ai = NULL; if (readline(fileno(f), &lbuf, &lbuflen) != 1) return; @@ -722,12 +775,16 @@ void nfsd_export(FILE *f) auth_reload(); if (use_ipaddr) { - if (!inet_aton(dom, &addr)) + struct addrinfo *tmp; + tmp = host_pton(dom); + if (tmp == NULL) + goto out; + ai = client_resolve(tmp->ai_addr); + freeaddrinfo(tmp); goto out; - he = client_resolve(addr); } - found = lookup_export(dom, path, he); + found = lookup_export(dom, path, ai); if (found) { if (dump_to_cache(f, dom, path, &found->m_export) < 0) { @@ -743,7 +800,7 @@ void nfsd_export(FILE *f) xlog(D_CALL, "nfsd_export: found %p path %s", found, path ? path : NULL); if (dom) free(dom); if (path) free(path); - if (he) free(he); + freeaddrinfo(ai); } @@ -752,11 +809,11 @@ struct { void (*cache_handle)(FILE *f); FILE *f; } cachelist[] = { - { "auth.unix.ip", auth_unix_ip}, - { "auth.unix.gid", auth_unix_gid}, - { "nfsd.export", nfsd_export}, - { "nfsd.fh", nfsd_fh}, - { NULL, NULL } + { "auth.unix.ip", auth_unix_ip, NULL}, + { "auth.unix.gid", auth_unix_gid, NULL}, + { "nfsd.export", nfsd_export, NULL}, + { "nfsd.fh", nfsd_fh, NULL}, + { NULL, NULL, NULL } }; extern int manage_gids; @@ -824,8 +881,8 @@ int cache_export_ent(char *domain, struc * and export them with the same options */ struct stat stb; - int l = strlen(exp->e_path); - int dev; + size_t l = strlen(exp->e_path); + __dev_t dev; if (strlen(path) <= l || path[l] != '/' || strncmp(exp->e_path, path, l) != 0) @@ -863,6 +920,7 @@ int cache_export_ent(char *domain, struc int cache_export(nfs_export *exp, char *path) { + char buf[INET_ADDRSTRLEN]; int err; FILE *f; @@ -870,8 +928,10 @@ int cache_export(nfs_export *exp, char * if (!f) return -1; + qword_print(f, "nfsd"); - qword_print(f, inet_ntoa(exp->m_client->m_addrlist[0])); + qword_print(f, + host_ntop(get_addrlist(exp->m_client, 0), buf, sizeof(buf))); 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/mountd/fsloc.c.orig nfs-utils-1.2.2/utils/mountd/fsloc.c --- nfs-utils-1.2.2/utils/mountd/fsloc.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/utils/mountd/fsloc.c 2010-09-09 11:02:27.385011000 -0400 @@ -146,7 +146,7 @@ static struct servers *method_list(char } /* Returns appropriately filled struct servers, or NULL if had a problem */ -struct servers *replicas_lookup(int method, char *data, char *key) +struct servers *replicas_lookup(int method, char *data) { struct servers *sp=NULL; switch(method) { diff -up nfs-utils-1.2.2/utils/mountd/fsloc.h.orig nfs-utils-1.2.2/utils/mountd/fsloc.h --- nfs-utils-1.2.2/utils/mountd/fsloc.h.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/utils/mountd/fsloc.h 2010-09-09 11:02:27.390006000 -0400 @@ -44,7 +44,7 @@ struct servers { int h_referral; /* 0=replica, 1=referral */ }; -struct servers *replicas_lookup(int method, char *data, char *key); +struct servers *replicas_lookup(int method, char *data); void release_replicas(struct servers *server); #endif /* FSLOC_H */ diff -up nfs-utils-1.2.2/utils/mountd/mountd.c.orig nfs-utils-1.2.2/utils/mountd/mountd.c --- nfs-utils-1.2.2/utils/mountd/mountd.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/utils/mountd/mountd.c 2010-09-09 11:02:27.395001000 -0400 @@ -80,10 +80,10 @@ static int nfs_version = -1; static void unregister_services (void) { - if (nfs_version & 0x1) + if (nfs_version & (0x1 << 1)) { pmap_unset (MOUNTPROG, MOUNTVERS); - if (nfs_version & (0x1 << 1)) pmap_unset (MOUNTPROG, MOUNTVERS_POSIX); + } if (nfs_version & (0x1 << 2)) pmap_unset (MOUNTPROG, MOUNTVERS_NFSV3); } @@ -192,7 +192,8 @@ sig_hup (int sig) } bool_t -mount_null_1_svc(struct svc_req *rqstp, void *argp, void *resp) +mount_null_1_svc(struct svc_req *UNUSED(rqstp), void *UNUSED(argp), + void *UNUSED(resp)) { return 1; } @@ -210,7 +211,7 @@ mount_mnt_1_svc(struct svc_req *rqstp, d } bool_t -mount_dump_1_svc(struct svc_req *rqstp, void *argp, mountlist *res) +mount_dump_1_svc(struct svc_req *rqstp, void *UNUSED(argp), mountlist *res) { struct sockaddr_in *addr = nfs_getrpccaller_in(rqstp->rq_xprt); @@ -221,7 +222,7 @@ mount_dump_1_svc(struct svc_req *rqstp, } bool_t -mount_umnt_1_svc(struct svc_req *rqstp, dirpath *argp, void *resp) +mount_umnt_1_svc(struct svc_req *rqstp, dirpath *argp, void *UNUSED(resp)) { struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt); nfs_export *exp; @@ -245,7 +246,8 @@ mount_umnt_1_svc(struct svc_req *rqstp, } bool_t -mount_umntall_1_svc(struct svc_req *rqstp, void *argp, void *resp) +mount_umntall_1_svc(struct svc_req *rqstp, void *UNUSED(argp), + void *UNUSED(resp)) { /* Reload /etc/xtab if necessary */ auth_reload(); @@ -255,7 +257,7 @@ mount_umntall_1_svc(struct svc_req *rqst } bool_t -mount_export_1_svc(struct svc_req *rqstp, void *argp, exports *resp) +mount_export_1_svc(struct svc_req *rqstp, void *UNUSED(argp), exports *resp) { struct sockaddr_in *addr = nfs_getrpccaller_in(rqstp->rq_xprt); @@ -266,7 +268,7 @@ mount_export_1_svc(struct svc_req *rqstp } bool_t -mount_exportall_1_svc(struct svc_req *rqstp, void *argp, exports *resp) +mount_exportall_1_svc(struct svc_req *rqstp, void *UNUSED(argp), exports *resp) { struct sockaddr_in *addr = nfs_getrpccaller_in(rqstp->rq_xprt); @@ -536,22 +538,21 @@ static void free_exportlist(exports *eli static void prune_clients(nfs_export *exp, struct exportnode *e) { - struct hostent *hp; + struct addrinfo *ai = NULL; 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)) { + && (ai = host_addrinfo(c->gr_name))) { + if (client_check(exp->m_client, ai)) { *cp = c->gr_next; xfree(c->gr_name); xfree(c); - xfree (hp); + freeaddrinfo(ai); continue; } - xfree (hp); + freeaddrinfo(ai); } cp = &(c->gr_next); } @@ -712,8 +713,10 @@ main(int argc, char **argv) usage(argv [0], 1); } - /* No more arguments allowed. */ - if (optind != argc || !(nfs_version & 0x7)) + /* No more arguments allowed. + * Require at least one valid version (2, 3, or 4) + */ + if (optind != argc || !(nfs_version & 0xE)) usage(argv [0], 1); if (chdir(state_dir)) { @@ -761,12 +764,12 @@ main(int argc, char **argv) if (new_cache) cache_open(); - if (nfs_version & 0x1) + if (nfs_version & (0x1 << 1)) { rpc_init("mountd", MOUNTPROG, MOUNTVERS, mount_dispatch, port); - if (nfs_version & (0x1 << 1)) rpc_init("mountd", MOUNTPROG, MOUNTVERS_POSIX, mount_dispatch, port); + } if (nfs_version & (0x1 << 2)) rpc_init("mountd", MOUNTPROG, MOUNTVERS_NFSV3, mount_dispatch, port); diff -up nfs-utils-1.2.2/utils/mountd/rmtab.c.orig nfs-utils-1.2.2/utils/mountd/rmtab.c --- nfs-utils-1.2.2/utils/mountd/rmtab.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/utils/mountd/rmtab.c 2010-09-09 11:02:27.399996000 -0400 @@ -133,8 +133,7 @@ mountlist_del(char *hname, const char *p void mountlist_del_all(struct sockaddr_in *sin) { - struct in_addr addr = sin->sin_addr; - struct hostent *hp; + char *hostname; struct rmtabent *rep; nfs_export *exp; FILE *fp; @@ -142,11 +141,13 @@ mountlist_del_all(struct sockaddr_in *si if ((lockid = xflock(_PATH_RMTABLCK, "w")) < 0) return; - if (!(hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET))) { - xlog(L_ERROR, "can't get hostname of %s", inet_ntoa(addr)); + hostname = host_canonname((struct sockaddr *)sin); + if (hostname == NULL) { + char buf[INET_ADDRSTRLEN]; + xlog(L_ERROR, "can't get hostname of %s", + host_ntop((struct sockaddr *)sin, buf, sizeof(buf))); goto out_unlock; } - hp = hostent_dup (hp); if (!setrmtabent("r")) goto out_free; @@ -155,7 +156,7 @@ mountlist_del_all(struct sockaddr_in *si goto out_close; while ((rep = getrmtabent(1, NULL)) != NULL) { - if (strcmp(rep->r_client, hp->h_name) == 0 && + if (strcmp(rep->r_client, hostname) == 0 && (exp = auth_authenticate("umountall", sin, rep->r_path))) continue; fputrmtabent(fp, rep, NULL); @@ -168,7 +169,7 @@ mountlist_del_all(struct sockaddr_in *si out_close: endrmtabent(); /* close & unlink */ out_free: - free (hp); + free(hostname); out_unlock: xfunlock(lockid); } 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-09-09 11:02:27.327022000 -0400 @@ -53,6 +53,7 @@ #include "parse_opt.h" #include "network.h" #include "conffile.h" +#include "nfslib.h" #define PMAP_TIMEOUT (10) #define CONNECT_TIMEOUT (20) @@ -82,6 +83,7 @@ static const char *nfs_nfs_pgmtbl[] = { static const char *nfs_transport_opttbl[] = { "udp", "tcp", + "rdma", "proto", NULL, }; @@ -857,7 +859,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 +966,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; } @@ -1203,6 +1214,8 @@ nfs_nfs_program(struct mount_options *op return 1; } case PO_BAD_VALUE: + nfs_error(_("%s: invalid value for 'nfsprog=' option"), + progname); return 0; } @@ -1242,9 +1255,12 @@ nfs_nfs_version(struct mount_options *op } return 0; case PO_NOT_FOUND: - nfs_error(_("%s: option parsing error\n"), + nfs_error(_("%s: parsing error on 'vers=' option\n"), progname); + return 0; case PO_BAD_VALUE: + nfs_error(_("%s: invalid value for 'vers=' option"), + progname); return 0; } case 4: /* nfsvers */ @@ -1256,9 +1272,12 @@ nfs_nfs_version(struct mount_options *op } return 0; case PO_NOT_FOUND: - nfs_error(_("%s: option parsing error\n"), + nfs_error(_("%s: parsing error on 'nfsvers=' option\n"), progname); + return 0; case PO_BAD_VALUE: + nfs_error(_("%s: invalid value for 'nfsvers=' option"), + progname); return 0; } } @@ -1289,11 +1308,16 @@ nfs_nfs_protocol(struct mount_options *o case 1: /* tcp */ *protocol = IPPROTO_TCP; return 1; - case 2: /* proto */ + case 2: /* rdma */ + *protocol = NFSPROTO_RDMA; + return 1; + case 3: /* proto */ option = po_get(options, "proto"); if (option != NULL) { if (!nfs_get_proto(option, &family, protocol)) { errno = EPROTONOSUPPORT; + nfs_error(_("%s: Failed to find '%s' protocol"), + progname, option); return 0; } return 1; @@ -1327,6 +1351,8 @@ nfs_nfs_port(struct mount_options *optio return 1; } case PO_BAD_VALUE: + nfs_error(_("%s: invalid value for 'port=' option"), + progname); return 0; } @@ -1342,7 +1368,7 @@ nfs_nfs_port(struct mount_options *optio sa_family_t config_default_family = AF_UNSPEC; static int -nfs_verify_family(sa_family_t family) +nfs_verify_family(sa_family_t UNUSED(family)) { return 1; } @@ -1374,14 +1400,20 @@ int nfs_nfs_proto_family(struct mount_op switch (po_rightmost(options, nfs_transport_opttbl)) { case 0: /* udp */ case 1: /* tcp */ + case 2: /* rdma */ /* for compatibility; these are always AF_INET */ *family = AF_INET; return 1; - case 2: /* proto */ + case 3: /* proto */ option = po_get(options, "proto"); if (option != NULL && - !nfs_get_proto(option, &tmp_family, &protocol)) - goto out_err; + !nfs_get_proto(option, &tmp_family, &protocol)) { + + nfs_error(_("%s: Failed to find '%s' protocol"), + progname, option); + errno = EPROTONOSUPPORT; + return 0; + } } if (!nfs_verify_family(tmp_family)) @@ -1414,6 +1446,8 @@ nfs_mount_program(struct mount_options * return 1; } case PO_BAD_VALUE: + nfs_error(_("%s: invalid value for 'mountprog=' option"), + progname); return 0; } @@ -1443,6 +1477,8 @@ nfs_mount_version(struct mount_options * return 1; } case PO_BAD_VALUE: + nfs_error(_("%s: invalid value for 'mountvers=' option"), + progname); return 0; } @@ -1469,6 +1505,8 @@ nfs_mount_protocol(struct mount_options if (option != NULL) { if (!nfs_get_proto(option, &family, protocol)) { errno = EPROTONOSUPPORT; + nfs_error(_("%s: Failed to find '%s' protocol"), + progname, option); return 0; } return 1; @@ -1501,6 +1539,8 @@ nfs_mount_port(struct mount_options *opt return 1; } case PO_BAD_VALUE: + nfs_error(_("%s: invalid value for 'mountport=' option"), + progname); return 0; } @@ -1526,8 +1566,12 @@ int nfs_mount_proto_family(struct mount_ option = po_get(options, "mountproto"); if (option != NULL) { - if (!nfs_get_proto(option, &tmp_family, &protocol)) + if (!nfs_get_proto(option, &tmp_family, &protocol)) { + nfs_error(_("%s: Failed to find '%s' protocol"), + progname, option); + errno = EPROTONOSUPPORT; goto out_err; + } if (!nfs_verify_family(tmp_family)) goto out_err; *family = tmp_family; diff -up nfs-utils-1.2.2/utils/mount/nfs4mount.c.orig nfs-utils-1.2.2/utils/mount/nfs4mount.c --- nfs-utils-1.2.2/utils/mount/nfs4mount.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/utils/mount/nfs4mount.c 2010-09-09 11:02:27.339022000 -0400 @@ -146,7 +146,7 @@ static int fill_ipv4_sockaddr(const char progname, hostname); return -1; } - if (hp->h_length > sizeof(struct in_addr)) { + if (hp->h_length > (int)sizeof(struct in_addr)) { nfs_error(_("%s: got bad hp->h_length"), progname); hp->h_length = sizeof(struct in_addr); } diff -up nfs-utils-1.2.2/utils/mount/nfs.man.orig nfs-utils-1.2.2/utils/mount/nfs.man --- nfs-utils-1.2.2/utils/mount/nfs.man.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/utils/mount/nfs.man 2010-09-09 11:02:27.333022000 -0400 @@ -3,8 +3,6 @@ .SH NAME nfs \- fstab format and options for the .B nfs -and -.B nfs4 file systems .SH SYNOPSIS .I /etc/fstab @@ -71,14 +69,10 @@ for details on specifying raw IPv6 addre .P The .I fstype -field contains either "nfs" (for version 2 or version 3 NFS mounts) -or "nfs4" (for NFS version 4 mounts). +field contains "nfs", for whatever version of the protocol. The .B nfs -and -.B nfs4 -file system types share similar mount options, -which are described below. +allow several mount options, which are described below. .SH "MOUNT OPTIONS" Refer to .BR mount (8) @@ -89,14 +83,8 @@ specify any mount options, use the gener in .IR /etc/fstab . .DT -.SS "Valid options for either the nfs or nfs4 file system type" -These options are valid to use when mounting either -.B nfs -or -.B nfs4 -file system types. -They imply the same behavior -and have the same default for both file system types. +.SS "Options supported by all versions" +These options are valid to use with any NFS version. .TP 1.5i .BR soft " / " hard Determines the recovery behavior of the NFS client @@ -476,11 +464,9 @@ by other clients, but can impact applica .IP The DATA AND METADATA COHERENCE section contains a detailed discussion of these trade-offs. -.SS "Valid options for the nfs file system type" +.SS "Options for versions 2 and 3 only" Use these options, along with the options in the above subsection, -for mounting the -.B nfs -file system type. +for NFSv2/v3 only. They will be ignored for newer versions. .TP 1.5i .BI proto= netid The transport protocol name and protocol family the NFS client uses @@ -495,7 +481,10 @@ command, .I netid is a valid netid listed in .IR /etc/netconfig . -Otherwise, +The value "rdma" may also be specified. +If the +.B mount.nfs +command does not have TI-RPC support, then .I netid is one of "tcp," "udp," or "rdma," and only IPv4 may be used. .IP @@ -537,6 +526,12 @@ option is an alternative to specifying .BR proto=tcp. It is included for compatibility with other operating systems. .TP 1.5i +.B rdma +The +.B rdma +option is an alternative to specifying +.BR proto=rdma. +.TP 1.5i .BI port= n The numeric value of the server's NFS service port. If the server's NFS service is not available on the specified port, @@ -623,14 +618,9 @@ in such cases. .TP 1.5i .BI nfsvers= n The NFS protocol version number used to contact the server's NFS service. -The Linux client supports version 2 and version 3 of the NFS protocol -when using the file system type -.BR nfs . -If the server does not support the requested version, -the mount request fails. -If this option is not specified, the client attempts to use version 3, -but negotiates the NFS version with the server if version 3 support -is not available. +If the server does not support the requested version, the mount request fails. +If this option is not specified, the client negociate a suitable version with +the server, trying version 4 first, version 3 second, and version 2 last. .TP 1.5i .BI vers= n This option is an alternative to the @@ -727,11 +717,9 @@ If this option is not specified, the NFS on NFS version 3 mounts to read small directories. Some applications perform better if the client uses only READDIR requests for all directories. -.SS "Valid options for the nfs4 file system type" +.SS "Options for version 4 only" Use these options, along with the options in the first subsection above, -for mounting the -.B nfs4 -file system type. +for NFSv4 only. They will be ignored with older versions. .TP 1.5i .BI proto= netid The transport protocol name and protocol family the NFS client uses @@ -828,6 +816,13 @@ In the presence of multiple client netwo special routing policies, or atypical network topologies, the exact address to use for callbacks may be nontrivial to determine. +.SH nfs4 FILE SYSTEM TYPE +The +.BR nfs4 +file system type is an old syntax for specifying NFSv4 usage. It can still +be used with all NFSv4-specific and common options, excepted the +.B nfsvers +mount option. .SH MOUNT CONFIGURATION FILE If the mount command is configured to do so, all of the mount options described in the previous section can also be configured in the @@ -849,12 +844,11 @@ file system type and specify the .B nfsvers=3 mount option. To mount using NFS version 4, -use the -.B nfs4 -file system type. -The -.B nfsvers -mount option is not supported for the +use either the +.B nfs +file system type, with the +.B nfsvers=4 +mount option, or the .B nfs4 file system type. .P diff -up nfs-utils-1.2.2/utils/mount/nfsmount.c.orig nfs-utils-1.2.2/utils/mount/nfsmount.c --- nfs-utils-1.2.2/utils/mount/nfsmount.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/utils/mount/nfsmount.c 2010-09-09 11:02:27.344025000 -0400 @@ -510,8 +510,12 @@ nfsmount(const char *spec, const char *n int val; static int doonce = 0; - clnt_addr_t mnt_server = { &mounthost, }; - clnt_addr_t nfs_server = { &hostname, }; + clnt_addr_t mnt_server = { + .hostname = &mounthost + }; + clnt_addr_t nfs_server = { + .hostname = &hostname + }; struct sockaddr_in *nfs_saddr = &nfs_server.saddr; struct pmap *mnt_pmap = &mnt_server.pmap, *nfs_pmap = &nfs_server.pmap; diff -up nfs-utils-1.2.2/utils/mount/nfsumount.c.orig nfs-utils-1.2.2/utils/mount/nfsumount.c --- nfs-utils-1.2.2/utils/mount/nfsumount.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/utils/mount/nfsumount.c 2010-09-09 11:02:27.350022000 -0400 @@ -179,10 +179,8 @@ static int nfs_umount_do_umnt(struct mou 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); + if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap)) return EX_FAIL; - } /* Skip UMNT call for vers=4 mounts */ if (nfs_pmap.pm_vers == 4) 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-09-09 11:02:27.355022000 -0400 @@ -302,11 +302,6 @@ static int nfs_set_version(struct nfsmou if (strncmp(mi->type, "nfs4", 4) == 0) mi->version = 4; - else { - char *option = po_get(mi->options, "proto"); - if (option && strcmp(option, "rdma") == 0) - mi->version = 3; - } /* * If we still don't know, check for version-specific @@ -490,14 +485,18 @@ nfs_rewrite_pmap_mount_options(struct mo union nfs_sockaddr mnt_address; struct sockaddr *mnt_saddr = &mnt_address.sa; socklen_t mnt_salen = sizeof(mnt_address); + unsigned long protocol; struct pmap mnt_pmap; - char *option; /* - * Skip option negotiation for proto=rdma mounts. + * Version and transport negotiation is not required + * and does not work for RDMA mounts. */ - option = po_get(options, "proto"); - if (option && strcmp(option, "rdma") == 0) + if (!nfs_nfs_protocol(options, &protocol)) { + errno = EINVAL; + return 0; + } + if (protocol == NFSPROTO_RDMA) goto out; /* @@ -538,7 +537,10 @@ nfs_rewrite_pmap_mount_options(struct mo if (!nfs_construct_new_options(options, nfs_saddr, &nfs_pmap, mnt_saddr, &mnt_pmap)) { - errno = EINVAL; + if (rpc_createerr.cf_stat == RPC_UNKNOWNPROTO) + errno = EPROTONOSUPPORT; + else + errno = EINVAL; return 0; } @@ -586,18 +588,21 @@ static int nfs_do_mount_v3v2(struct nfsm errno = ENOMEM; return result; } - + errno = 0; if (!nfs_append_addr_option(sap, salen, options)) { - errno = EINVAL; + if (errno == 0) + errno = EINVAL; goto out_fail; } if (!nfs_fix_mounthost_option(options, mi->hostname)) { - errno = EINVAL; + if (errno == 0) + errno = EINVAL; goto out_fail; } if (!mi->fake && !nfs_verify_lock_option(options)) { - errno = EINVAL; + if (errno == 0) + errno = EINVAL; goto out_fail; } @@ -799,6 +804,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/nfsd/nfssvc.c.orig nfs-utils-1.2.2/utils/nfsd/nfssvc.c --- nfs-utils-1.2.2/utils/nfsd/nfssvc.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/utils/nfsd/nfssvc.c 2010-09-09 11:02:27.414978000 -0400 @@ -181,7 +181,7 @@ nfssvc_setfds(const struct addrinfo *hin } snprintf(buf, sizeof(buf), "%d\n", sockfd); - if (write(fd, buf, strlen(buf)) != strlen(buf)) { + if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) { /* * this error may be common on older kernels that don't * support IPv6, so turn into a debug message. @@ -251,7 +251,7 @@ nfssvc_setvers(unsigned int ctlbits, int } xlog(D_GENERAL, "Writing version string to kernel: %s", buf); snprintf(ptr+off, sizeof(buf) - off, "\n"); - if (write(fd, buf, strlen(buf)) != strlen(buf)) + if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) xlog(L_ERROR, "Setting version failed: errno %d (%m)", errno); close(fd); @@ -277,7 +277,7 @@ nfssvc_threads(unsigned short port, cons snprintf(buf, sizeof(buf), "%d\n", nrservs); n = write(fd, buf, strlen(buf)); close(fd); - if (n != strlen(buf)) + if (n != (ssize_t)strlen(buf)) return -1; else return 0; diff -up nfs-utils-1.2.2/utils/nfsstat/nfsstat.c.orig nfs-utils-1.2.2/utils/nfsstat/nfsstat.c --- nfs-utils-1.2.2/utils/nfsstat/nfsstat.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/utils/nfsstat/nfsstat.c 2010-09-09 11:02:27.419973000 -0400 @@ -791,7 +791,7 @@ print_callstats(const char *hdr, const c { unsigned long long total; unsigned long long pct; - int i, j; + unsigned int i, j; fputs(hdr, stdout); for (i = 0, total = 0; i < nr; i++) @@ -816,7 +816,7 @@ print_callstats_list(const char *hdr, co unsigned int *callinfo, unsigned int nr) { unsigned long long calltotal; - int i; + unsigned int i; for (i = 0, calltotal = 0; i < nr; i++) { calltotal += callinfo[i]; @@ -1118,7 +1118,7 @@ unpause(int sig) time_diff = difftime(endtime, starttime); minutes = time_diff / 60; seconds = (int)time_diff % 60; - printf("Signal received; displaying (only) statistics gathered over the last %d minutes, %d seconds:\n\n", minutes, seconds); + printf("Signal %d received; displaying (only) statistics gathered over the last %d minutes, %d seconds:\n\n", sig, minutes, seconds); } static void 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-09-09 11:02:27.436957000 -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/hostname.c.orig nfs-utils-1.2.2/utils/statd/hostname.c --- nfs-utils-1.2.2/utils/statd/hostname.c.orig 2010-02-18 07:35:00.000000000 -0500 +++ nfs-utils-1.2.2/utils/statd/hostname.c 2010-09-09 11:02:27.441960000 -0400 @@ -212,7 +212,9 @@ statd_canonical_name(const char *hostnam buf, (socklen_t)sizeof(buf)); freeaddrinfo(ai); if (!result) - return NULL; + /* OK to use presentation address, + * if no reverse map exists */ + return strdup(hostname); return strdup(buf); } 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-09-09 11:02:27.447957000 -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-09-09 11:01:45.327752000 -0400 +++ nfs-utils-1.2.2/utils/statd/sm-notify.man 2010-09-09 11:02:27.452960000 -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-09-09 11:01:45.333750000 -0400 +++ nfs-utils-1.2.2/utils/statd/statd.man 2010-09-09 11:02:27.457960000 -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.