1 diff --git a/aclocal/libcap.m4 b/aclocal/libcap.m4
2 index eabe507..68a624c 100644
3 --- a/aclocal/libcap.m4
4 +++ b/aclocal/libcap.m4
5 @@ -5,11 +5,19 @@ AC_DEFUN([AC_LIBCAP], [
7 AC_CHECK_FUNC([prctl], , )
9 - dnl look for the library; do not add to LIBS if found
10 - AC_CHECK_LIB([cap], [cap_get_proc], [LIBCAP=-lcap], ,)
12 + AC_ARG_ENABLE([caps],
13 + [AS_HELP_STRING([--disable-caps], [Disable capabilities support])])
17 + if test "x$enable_caps" != "xno" ; then
18 + dnl look for the library; do not add to LIBS if found
19 + AC_CHECK_LIB([cap], [cap_get_proc], [LIBCAP=-lcap], ,)
21 - AC_CHECK_HEADERS([sys/capability.h], ,
22 - [AC_MSG_ERROR([libcap headers not found.])])
23 + AC_CHECK_HEADERS([sys/capability.h], ,
24 + [test "x$enable_caps" = "xyes" && AC_MSG_ERROR([libcap headers not found.])])
30 diff --git a/autogen.sh b/autogen.sh
33 diff --git a/configure.ac b/configure.ac
34 index b7520d8..7c9e61a 100644
37 @@ -81,7 +81,7 @@ AC_ARG_ENABLE(nfsv41,
38 if test "$enable_nfsv41" = yes; then
39 AC_DEFINE(NFS41_SUPPORTED, 1, [Define this if you want NFSv41 support compiled in])
44 AC_SUBST(enable_nfsv41)
45 AM_CONDITIONAL(CONFIG_NFSV41, [test "$enable_nfsv41" = "yes"])
46 @@ -400,7 +400,7 @@ case $host in
50 -my_am_cflags="-Wall -Wstrict-prototypes $ARCHFLAGS -pipe"
51 +my_am_cflags="-Wall -Wextra -Wstrict-prototypes $ARCHFLAGS -pipe"
53 AC_SUBST([AM_CFLAGS], ["$my_am_cflags"])
55 @@ -425,6 +425,8 @@ AC_CONFIG_FILES([
56 tools/nlmtest/Makefile
57 tools/rpcdebug/Makefile
59 + tools/mountstats/Makefile
60 + tools/nfs-iostat/Makefile
62 utils/exportfs/Makefile
64 diff --git a/support/export/client.c b/support/export/client.c
65 index 6236561..c74961e 100644
66 --- a/support/export/client.c
67 +++ b/support/export/client.c
75 +#include "sockaddr.h"
80 #if !defined(__GLIBC__) || __GLIBC__ < 2
81 extern int innetgr(char *netgr, char *host, char *, char *);
83 -static void client_init(nfs_client *clp, const char *hname,
84 - struct hostent *hp);
85 -static int client_checkaddr(nfs_client *clp, struct in_addr addr);
87 +static char *add_name(char *old, const char *add);
89 nfs_client *clientlist[MCL_MAXTYPES] = { NULL, };
92 -/* if canonical is set, then we *know* this is already a canonical name
93 - * so hostname lookup is avoided.
94 - * This is used when reading /proc/fs/nfs/exports
96 +init_addrlist(nfs_client *clp, const struct addrinfo *ai)
103 + for (i = 0; (ai != NULL) && (i < NFSCLNT_ADDRMAX); i++) {
104 + set_addrlist(clp, i, ai->ai_addr);
112 +client_free(nfs_client *clp)
114 + free(clp->m_hostname);
119 +init_netmask(nfs_client *clp, const char *slash, const sa_family_t family)
121 + struct sockaddr_in sin = {
122 + .sin_family = AF_INET,
124 + unsigned long prefixlen;
126 +#ifdef IPV6_SUPPORTED
127 + struct sockaddr_in6 sin6 = {
128 + .sin6_family = AF_INET6,
133 + /* No slash present; assume netmask is all ones */
134 + if (slash == NULL) {
139 +#ifdef IPV6_SUPPORTED
145 + goto out_badfamily;
150 + /* A spelled out netmask address, perhaps? */
151 + if (strchr(slash + 1, '.') != NULL) {
152 + if (inet_pton(AF_INET, slash + 1,
153 + &sin.sin_addr.s_addr) == 0)
155 + set_addrlist_in(clp, 1, &sin);
158 +#ifdef IPV6_SUPPORTED
159 + if (strchr(slash + 1, ':')) {
160 + if (!inet_pton(AF_INET6, slash + 1, &sin6.sin6_addr))
162 + set_addrlist_in6(clp, 1, &sin6);
167 + /* A prefixlen was given */
168 + prefixlen = strtoul(slash + 1, &endptr, 10);
169 + if (*endptr != '\0' && prefixlen != ULONG_MAX && errno != ERANGE)
170 + goto out_badprefix;
175 + if (prefixlen > 32)
176 + goto out_badprefix;
177 + shift = 32 - (uint32_t)prefixlen;
178 + sin.sin_addr.s_addr = htonl((uint32_t)~0 << shift);
179 + set_addrlist_in(clp, 1, &sin);
181 +#ifdef IPV6_SUPPORTED
183 + if (prefixlen > 128)
184 + goto out_badprefix;
185 + for (i = 0; prefixlen > 32; i++) {
186 + sin6.sin6_addr.s6_addr32[i] = 0xffffffff;
189 + shift = 32 - (uint32_t)prefixlen;
190 + sin6.sin6_addr.s6_addr32[i] = htonl((uint32_t)~0 << shift);
191 + set_addrlist_in6(clp, 1, &sin6);
197 + xlog(L_ERROR, "Unsupported address family for %s", clp->m_hostname);
201 + xlog(L_ERROR, "Invalid netmask `%s' for %s", slash + 1, clp->m_hostname);
205 + xlog(L_ERROR, "Invalid prefix `%s' for %s", slash + 1, clp->m_hostname);
210 +init_subnetwork(nfs_client *clp)
212 + struct addrinfo *ai;
213 + sa_family_t family;
216 + slash = strchr(clp->m_hostname, '/');
217 + if (slash != NULL) {
219 + ai = host_pton(clp->m_hostname);
222 + ai = host_pton(clp->m_hostname);
224 + xlog(L_ERROR, "Invalid IP address %s", clp->m_hostname);
228 + set_addrlist(clp, 0, ai->ai_addr);
229 + family = ai->ai_addr->sa_family;
233 + return init_netmask(clp, slash, family);
237 +client_init(nfs_client *clp, const char *hname, const struct addrinfo *ai)
239 + clp->m_hostname = strdup(hname);
240 + if (clp->m_hostname == NULL)
243 + clp->m_exported = 0;
247 + if (clp->m_type == MCL_SUBNETWORK)
248 + return init_subnetwork(clp);
250 + init_addrlist(clp, ai);
255 +client_add(nfs_client *clp)
259 + cpp = &clientlist[clp->m_type];
260 + while (*cpp != NULL)
261 + cpp = &((*cpp)->m_next);
262 + clp->m_next = NULL;
267 + * client_lookup - look for @hname in our list of cached nfs_clients
268 + * @hname: '\0'-terminated ASCII string containing hostname to look for
269 + * @canonical: if set, @hname is known to be canonical DNS name
271 + * Returns pointer to a matching or freshly created nfs_client. NULL
272 + * is returned if some problem occurs.
275 client_lookup(char *hname, int canonical)
277 nfs_client *clp = NULL;
279 - struct hostent *hp = NULL;
280 + struct addrinfo *ai = NULL;
282 htype = client_gettype(hname);
284 if (htype == MCL_FQDN && !canonical) {
285 - struct hostent *hp2;
286 - hp = gethostbyname(hname);
287 - if (hp == NULL || hp->h_addrtype != AF_INET) {
288 - xlog(L_ERROR, "%s has non-inet addr", hname);
290 + ai = host_addrinfo(hname);
292 + xlog(L_ERROR, "Failed to resolve %s", hname);
295 - /* make sure we have canonical name */
296 - hp2 = hostent_dup(hp);
297 - hp = gethostbyaddr(hp2->h_addr, hp2->h_length,
300 - hp = hostent_dup(hp);
301 - /* but now we might not have all addresses... */
302 - if (hp2->h_addr_list[1]) {
303 - struct hostent *hp3 =
304 - gethostbyname(hp->h_name);
307 - hp = hostent_dup(hp3);
314 - hname = (char *) hp->h_name;
315 + hname = ai->ai_canonname;
317 - for (clp = clientlist[htype]; clp; clp = clp->m_next) {
318 - if (client_check(clp, hp))
319 + for (clp = clientlist[htype]; clp; clp = clp->m_next)
320 + if (client_check(clp, ai))
324 for (clp = clientlist[htype]; clp; clp = clp->m_next) {
325 if (strcasecmp(hname, clp->m_hostname)==0)
326 @@ -87,106 +242,60 @@ client_lookup(char *hname, int canonical)
331 - clp = (nfs_client *) xmalloc(sizeof(*clp));
332 - memset(clp, 0, sizeof(*clp));
334 + clp = calloc(1, sizeof(*clp));
338 - client_init(clp, hname, NULL);
339 + if (!client_init(clp, hname, NULL)) {
347 - if (htype == MCL_FQDN && clp->m_naddr == 0 && hp != NULL) {
348 - char **ap = hp->h_addr_list;
351 - for (i = 0; *ap && i < NFSCLNT_ADDRMAX; i++, ap++)
352 - clp->m_addrlist[i] = *(struct in_addr *)*ap;
358 + if (htype == MCL_FQDN && clp->m_naddr == 0)
359 + init_addrlist(clp, ai);
367 + * client_dup - create a copy of an nfs_client
368 + * @clp: pointer to nfs_client to copy
369 + * @ai: pointer to addrinfo used to initialize the new client's addrlist
371 + * Returns a dynamically allocated nfs_client if successful, or
372 + * NULL if some problem occurs. Caller must free the returned
373 + * nfs_client with free(3).
376 -client_dup(nfs_client *clp, struct hostent *hp)
377 +client_dup(const nfs_client *clp, const struct addrinfo *ai)
381 - new = (nfs_client *) xmalloc(sizeof(*new));
382 + new = (nfs_client *)malloc(sizeof(*new));
385 memcpy(new, clp, sizeof(*new));
386 new->m_type = MCL_FQDN;
387 new->m_hostname = NULL;
389 - client_init(new, (char *) hp->h_name, hp);
390 + if (!client_init(new, ai->ai_canonname, ai)) {
399 -client_init(nfs_client *clp, const char *hname, struct hostent *hp)
401 - xfree(clp->m_hostname);
403 - clp->m_hostname = xstrdup(hp->h_name);
405 - clp->m_hostname = xstrdup(hname);
407 - clp->m_exported = 0;
410 - if (clp->m_type == MCL_SUBNETWORK) {
411 - char *cp = strchr(clp->m_hostname, '/');
412 - static char slash32[] = "/32";
414 - if(!cp) cp = slash32;
416 - clp->m_addrlist[0].s_addr = inet_addr(clp->m_hostname);
417 - if (strchr(cp + 1, '.')) {
418 - clp->m_addrlist[1].s_addr = inet_addr(cp+1);
421 - int netmask = atoi(cp + 1);
422 - if (0 < netmask && netmask <= 32) {
423 - clp->m_addrlist[1].s_addr =
424 - htonl ((uint32_t) ~0 << (32 - netmask));
427 - xlog(L_FATAL, "invalid netmask `%s' for %s",
428 - cp + 1, clp->m_hostname);
436 - char **ap = hp->h_addr_list;
439 - for (i = 0; *ap && i < NFSCLNT_ADDRMAX; i++, ap++) {
440 - clp->m_addrlist[i] = *(struct in_addr *)*ap;
447 -client_add(nfs_client *clp)
451 - if (clp->m_type < 0 || clp->m_type >= MCL_MAXTYPES)
452 - xlog(L_FATAL, "unknown client type in client_add");
453 - cpp = clientlist + clp->m_type;
455 - cpp = &((*cpp)->m_next);
456 - clp->m_next = NULL;
461 + * client_release - drop a reference to an nfs_client record
465 client_release(nfs_client *clp)
467 @@ -195,6 +304,10 @@ client_release(nfs_client *clp)
472 + * client_freeall - deallocate all nfs_client records
478 @@ -205,57 +318,45 @@ client_freeall(void)
479 head = clientlist + i;
481 *head = (clp = *head)->m_next;
482 - xfree(clp->m_hostname);
489 -client_find(struct hostent *hp)
494 - for (i = 0; i < MCL_MAXTYPES; i++) {
495 - for (clp = clientlist[i]; clp; clp = clp->m_next) {
496 - if (!client_check(clp, hp))
499 - if (clp->m_type == MCL_FQDN)
501 - return client_dup(clp, hp);
512 -client_resolve(struct in_addr addr)
514 + * client_resolve - look up an IP address
515 + * @sap: pointer to socket address to resolve
517 + * Returns an addrinfo structure, or NULL if some problem occurred.
518 + * Caller must free the result with freeaddrinfo(3).
521 +client_resolve(const struct sockaddr *sap)
523 - struct hostent *he = NULL;
524 + struct addrinfo *ai = NULL;
526 if (clientlist[MCL_WILDCARD] || clientlist[MCL_NETGROUP])
527 - he = get_reliable_hostbyaddr((const char*)&addr, sizeof(addr), AF_INET);
529 - he = get_hostent((const char*)&addr, sizeof(addr), AF_INET);
530 + ai = host_reliable_addrinfo(sap);
532 + ai = host_numeric_addrinfo(sap);
539 - * Find client name given an IP address
540 - * This is found by gathering all known names that match that IP address,
541 - * sorting them and joining them with '+'
543 + * client_compose - Make a list of cached hostnames that match an IP address
544 + * @ai: pointer to addrinfo containing IP address information to match
546 + * Gather all known client hostnames that match the IP address, and sort
547 + * the result into a comma-separated list.
549 + * Returns a '\0'-terminated ASCII string containing a comma-separated
550 + * sorted list of client hostnames, or NULL if no client records matched
551 + * the IP address or memory could not be allocated. Caller must free the
552 + * returned string with free(3).
554 -static char *add_name(char *old, char *add);
557 -client_compose(struct hostent *he)
558 +client_compose(const struct addrinfo *ai)
562 @@ -263,7 +364,7 @@ client_compose(struct hostent *he)
563 for (i = 0 ; i < MCL_MAXTYPES; i++) {
565 for (clp = clientlist[i]; clp ; clp = clp->m_next) {
566 - if (!client_check(clp, he))
567 + if (!client_check(clp, ai))
569 name = add_name(name, clp->m_hostname);
571 @@ -271,13 +372,19 @@ client_compose(struct hostent *he)
576 + * client_member - check if @name is contained in the list @client
577 + * @client: '\0'-terminated ASCII string containing
578 + * comma-separated list of hostnames
579 + * @name: '\0'-terminated ASCII string containing hostname to look for
581 + * Returns 1 if @name was found in @client, otherwise zero is returned.
584 -client_member(char *client, char *name)
585 +client_member(const char *client, const char *name)
587 - /* check if "client" (a ',' separated list of names)
588 - * contains 'name' as a member
590 - int l = strlen(name);
591 + size_t l = strlen(name);
594 if (strncmp(client, name, l) == 0 &&
595 (client[l] == ',' || client[l] == '\0'))
596 @@ -290,9 +397,8 @@ client_member(char *client, char *name)
602 -name_cmp(char *a, char *b)
604 +name_cmp(const char *a, const char *b)
606 /* compare strings a and b, but only upto ',' in a */
607 while (*a && *b && *a != ',' && *a == *b)
608 @@ -305,9 +411,9 @@ name_cmp(char *a, char *b)
612 -add_name(char *old, char *add)
613 +add_name(char *old, const char *add)
615 - int len = strlen(add)+2;
616 + size_t len = strlen(add) + 2;
619 if (old) len += strlen(old);
620 @@ -340,108 +446,257 @@ add_name(char *old, char *add)
624 - * Match a host (given its hostent record) to a client record. This
625 - * is usually called from mountd.
626 + * Check each address listed in @ai against each address
627 + * stored in @clp. Return 1 if a match is found, otherwise
631 -client_check(nfs_client *clp, struct hostent *hp)
633 +check_fqdn(const nfs_client *clp, const struct addrinfo *ai)
635 - char *hname = (char *) hp->h_name;
636 - char *cname = clp->m_hostname;
640 - switch (clp->m_type) {
642 - case MCL_SUBNETWORK:
643 - for (ap = hp->h_addr_list; *ap; ap++) {
644 - if (client_checkaddr(clp, *(struct in_addr *) *ap))
645 + for (; ai; ai = ai->ai_next)
646 + for (i = 0; i < clp->m_naddr; i++)
647 + if (nfs_compare_sockaddr(ai->ai_addr,
648 + get_addrlist(clp, i)))
653 - if (wildmat(hname, cname))
659 +mask_match(const uint32_t a, const uint32_t b, const uint32_t m)
661 + return ((a ^ b) & m) == 0;
665 +check_subnet_v4(const struct sockaddr_in *address,
666 + const struct sockaddr_in *mask, const struct addrinfo *ai)
668 + for (; ai; ai = ai->ai_next) {
669 + struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
671 + if (sin->sin_family != AF_INET)
674 + if (mask_match(address->sin_addr.s_addr,
675 + sin->sin_addr.s_addr,
676 + mask->sin_addr.s_addr))
679 - for (ap = hp->h_aliases; *ap; ap++)
680 - if (wildmat(*ap, cname))
689 - struct hostent *nhp = NULL;
690 - struct sockaddr_in addr;
692 - /* First, try to match the hostname without
693 - * splitting off the domain */
694 - if (innetgr(cname+1, hname, NULL, NULL))
700 - /* try the aliases as well */
701 - for (i = 0; hp->h_aliases[i]; i++) {
702 - if (innetgr(cname+1, hp->h_aliases[i], NULL, NULL))
705 +#ifdef IPV6_SUPPORTED
707 +check_subnet_v6(const struct sockaddr_in6 *address,
708 + const struct sockaddr_in6 *mask, const struct addrinfo *ai)
710 + for (; ai; ai = ai->ai_next) {
711 + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr;
713 + if (sin6->sin6_family != AF_INET6)
716 + if (mask_match(address->sin6_addr.s6_addr32[0],
717 + sin6->sin6_addr.s6_addr32[0],
718 + mask->sin6_addr.s6_addr32[0]) &&
719 + mask_match(address->sin6_addr.s6_addr32[1],
720 + sin6->sin6_addr.s6_addr32[1],
721 + mask->sin6_addr.s6_addr32[1]) &&
722 + mask_match(address->sin6_addr.s6_addr32[2],
723 + sin6->sin6_addr.s6_addr32[2],
724 + mask->sin6_addr.s6_addr32[2]) &&
725 + mask_match(address->sin6_addr.s6_addr32[3],
726 + sin6->sin6_addr.s6_addr32[3],
727 + mask->sin6_addr.s6_addr32[3]))
732 +#else /* !IPV6_SUPPORTED */
734 +check_subnet_v6(const struct sockaddr_in6 *UNUSED(address),
735 + const struct sockaddr_in6 *UNUSED(mask),
736 + const struct addrinfo *UNUSED(ai))
740 +#endif /* !IPV6_SUPPORTED */
742 - /* If hname is ip address convert to FQDN */
743 - if (inet_aton(hname, &addr.sin_addr) &&
744 - (nhp = gethostbyaddr((const char *)&(addr.sin_addr),
745 - sizeof(addr.sin_addr), AF_INET))) {
746 - hname = (char *)nhp->h_name;
747 - if (innetgr(cname+1, hname, NULL, NULL))
751 + * Check each address listed in @ai against the subnetwork or
752 + * host address stored in @clp. Return 1 if an address in @hp
753 + * matches the host address stored in @clp, otherwise zero.
756 +check_subnetwork(const nfs_client *clp, const struct addrinfo *ai)
758 + switch (get_addrlist(clp, 0)->sa_family) {
760 + return check_subnet_v4(get_addrlist_in(clp, 0),
761 + get_addrlist_in(clp, 1), ai);
763 + return check_subnet_v6(get_addrlist_in6(clp, 0),
764 + get_addrlist_in6(clp, 1), ai);
767 - /* Okay, strip off the domain (if we have one) */
768 - if ((dot = strchr(hname, '.')) == NULL)
774 - match = innetgr(cname+1, hname, NULL, NULL);
777 + * Check if a wildcard nfs_client record matches the canonical name
778 + * or the aliases of a host. Return 1 if a match is found, otherwise
782 +check_wildcard(const nfs_client *clp, const struct addrinfo *ai)
784 + char *cname = clp->m_hostname;
785 + char *hname = ai->ai_canonname;
786 + struct hostent *hp;
794 - case MCL_ANONYMOUS:
795 + if (wildmat(hname, cname))
800 - xlog(L_FATAL, "internal: bad client type %d", clp->m_type);
802 + /* See if hname aliases listed in /etc/hosts or nis[+]
803 + * match the requested wildcard */
804 + hp = gethostbyname(hname);
806 + for (ap = hp->h_aliases; *ap; ap++)
807 + if (wildmat(*ap, cname))
815 + * Check if @ai's hostname or aliases fall in a given netgroup.
816 + * Return 1 if @ai represents a host in the netgroup, otherwise
821 +check_netgroup(const nfs_client *clp, const struct addrinfo *ai)
823 + const char *netgroup = clp->m_hostname + 1;
824 + struct addrinfo *tmp = NULL;
825 + struct hostent *hp;
831 + hname = strdup(ai->ai_canonname);
832 + if (hname == NULL) {
833 + xlog(D_GENERAL, "%s: no memory for strdup", __func__);
837 + /* First, try to match the hostname without
838 + * splitting off the domain */
839 + if (innetgr(netgroup, hname, NULL, NULL)) {
844 + /* See if hname aliases listed in /etc/hosts or nis[+]
845 + * match the requested netgroup */
846 + hp = gethostbyname(hname);
848 + for (i = 0; hp->h_aliases[i]; i++)
849 + if (innetgr(netgroup, hp->h_aliases[i], NULL, NULL)) {
855 + /* If hname happens to be an IP address, convert it
856 + * to a the canonical DNS name bound to this address. */
857 + tmp = host_pton(hname);
859 + char *cname = host_canonname(tmp->ai_addr);
862 + /* The resulting FQDN may be in our netgroup. */
863 + if (cname != NULL) {
866 + if (innetgr(netgroup, hname, NULL, NULL)) {
873 + /* Okay, strip off the domain (if we have one) */
874 + dot = strchr(hname, '.');
879 + match = innetgr(netgroup, hname, NULL, NULL);
885 +#else /* !HAVE_INNETGR */
887 -client_checkaddr(nfs_client *clp, struct in_addr addr)
888 +check_netgroup(__attribute__((unused)) const nfs_client *clp,
889 + __attribute__((unused)) const struct addrinfo *ai)
894 +#endif /* !HAVE_INNETGR */
897 + * client_check - check if IP address information matches a cached nfs_client
898 + * @clp: pointer to a cached nfs_client record
899 + * @ai: pointer to addrinfo to compare it with
901 + * Returns 1 if the address information matches the cached nfs_client,
905 +client_check(const nfs_client *clp, const struct addrinfo *ai)
907 switch (clp->m_type) {
909 - for (i = 0; i < clp->m_naddr; i++) {
910 - if (clp->m_addrlist[i].s_addr == addr.s_addr)
914 + return check_fqdn(clp, ai);
916 - return !((clp->m_addrlist[0].s_addr ^ addr.s_addr)
917 - & clp->m_addrlist[1].s_addr);
918 + return check_subnetwork(clp, ai);
920 + return check_wildcard(clp, ai);
922 + return check_netgroup(clp, ai);
923 + case MCL_ANONYMOUS:
928 + xlog(D_GENERAL, "%s: unrecognized client type: %d",
929 + __func__, clp->m_type);
936 + * client_gettype - determine type of nfs_client given an identifier
937 + * @ident: '\0'-terminated ASCII string containing a client identifier
939 + * Returns the type of nfs_client record that would be used for
943 client_gettype(char *ident)
946 + struct addrinfo *ai;
949 if (ident[0] == '\0' || strcmp(ident, "*")==0)
950 return MCL_ANONYMOUS;
951 @@ -461,12 +716,16 @@ client_gettype(char *ident)
952 if (*sp == '\\' && sp[1])
955 - /* check for N.N.N.N */
957 - if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN;
958 - sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN;
959 - sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN;
960 - sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '\0') return MCL_FQDN;
961 - /* we lie here a bit. but technically N.N.N.N == N.N.N.N/32 :) */
962 - return MCL_SUBNETWORK;
965 + * Treat unadorned IP addresses as MCL_SUBNETWORK.
966 + * Everything else is MCL_FQDN.
968 + ai = host_pton(ident);
971 + return MCL_SUBNETWORK;
976 diff --git a/support/export/export.c b/support/export/export.c
977 index 2943466..4fda30a 100644
978 --- a/support/export/export.c
979 +++ b/support/export/export.c
980 @@ -24,9 +24,25 @@ static int export_hash(char *);
982 static void export_init(nfs_export *exp, nfs_client *clp,
983 struct exportent *nep);
984 -static int export_check(nfs_export *, struct hostent *, char *);
985 +static void export_add(nfs_export *exp);
986 +static int export_check(const nfs_export *exp, const struct addrinfo *ai,
989 - export_allowed_internal(struct hostent *hp, char *path);
990 + export_allowed_internal(const struct addrinfo *ai,
994 +export_free(nfs_export *exp)
996 + xfree(exp->m_export.e_squids);
997 + xfree(exp->m_export.e_sqgids);
998 + free(exp->m_export.e_mountpoint);
999 + free(exp->m_export.e_fslocdata);
1000 + free(exp->m_export.e_uuid);
1002 + xfree(exp->m_export.e_hostname);
1006 static void warn_duplicated_exports(nfs_export *exp, struct exportent *eep)
1008 @@ -44,7 +60,12 @@ static void warn_duplicated_exports(nfs_export *exp, struct exportent *eep)
1014 + * export_read - read entries from /etc/exports
1015 + * @fname: name of file to read from
1019 export_read(char *fname)
1021 struct exportent *eep;
1022 @@ -59,11 +80,15 @@ export_read(char *fname)
1023 warn_duplicated_exports(exp, eep);
1030 - * Create an in-core export struct from an export entry.
1032 + * export_create - create an in-core nfs_export record from an export entry
1033 + * @xep: export entry to lookup
1034 + * @canonical: if set, e_hostname is known to be canonical DNS name
1036 + * Returns a freshly instantiated export record, or NULL if
1037 + * a problem occurred.
1040 export_create(struct exportent *xep, int canonical)
1041 @@ -105,8 +130,8 @@ export_init(nfs_export *exp, nfs_client *clp, struct exportent *nep)
1042 * original hostname from /etc/exports, while the in-core client struct
1043 * gets the newly found FQDN.
1046 -export_dup(nfs_export *exp, struct hostent *hp)
1047 +static nfs_export *
1048 +export_dup(nfs_export *exp, const struct addrinfo *ai)
1052 @@ -116,7 +141,11 @@ export_dup(nfs_export *exp, struct hostent *hp)
1053 dupexportent(&new->m_export, &exp->m_export);
1054 if (exp->m_export.e_hostname)
1055 new->m_export.e_hostname = xstrdup(exp->m_export.e_hostname);
1056 - clp = client_dup(exp->m_client, hp);
1057 + clp = client_dup(exp->m_client, ai);
1058 + if (clp == NULL) {
1063 new->m_client = clp;
1064 new->m_mayexport = exp->m_mayexport;
1065 @@ -128,10 +157,8 @@ export_dup(nfs_export *exp, struct hostent *hp)
1070 - * Add export entry to hash table
1075 export_add(nfs_export *exp)
1077 exp_hash_table *p_tbl;
1078 @@ -159,19 +186,27 @@ export_add(nfs_export *exp)
1083 + * export_find - find or create a suitable nfs_export for @ai and @path
1084 + * @ai: pointer to addrinfo for client
1085 + * @path: '\0'-terminated ASCII string containing export path
1087 + * Returns a pointer to nfs_export data matching @ai and @path,
1088 + * or NULL if an error occurs.
1091 -export_find(struct hostent *hp, char *path)
1092 +export_find(const struct addrinfo *ai, const char *path)
1097 for (i = 0; i < MCL_MAXTYPES; i++) {
1098 for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
1099 - if (!export_check(exp, hp, path))
1100 + if (!export_check(exp, ai, path))
1102 if (exp->m_client->m_type == MCL_FQDN)
1104 - return export_dup(exp, hp);
1105 + return export_dup(exp, ai);
1109 @@ -179,7 +214,7 @@ export_find(struct hostent *hp, char *path)
1113 -export_allowed_internal (struct hostent *hp, char *path)
1114 +export_allowed_internal(const struct addrinfo *ai, const char *path)
1118 @@ -187,7 +222,7 @@ export_allowed_internal (struct hostent *hp, char *path)
1119 for (i = 0; i < MCL_MAXTYPES; i++) {
1120 for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
1121 if (!exp->m_mayexport ||
1122 - !export_check(exp, hp, path))
1123 + !export_check(exp, ai, path))
1127 @@ -196,8 +231,16 @@ export_allowed_internal (struct hostent *hp, char *path)
1132 + * export_allowed - determine if this export is allowed
1133 + * @ai: pointer to addrinfo for client
1134 + * @path: '\0'-terminated ASCII string containing export path
1136 + * Returns a pointer to nfs_export data matching @ai and @path,
1137 + * or NULL if the export is not allowed.
1140 -export_allowed(struct hostent *hp, char *path)
1141 +export_allowed(const struct addrinfo *ai, const char *path)
1144 char epath[MAXPATHLEN+1];
1145 @@ -210,7 +253,7 @@ export_allowed(struct hostent *hp, char *path)
1147 /* Try the longest matching exported pathname. */
1149 - exp = export_allowed_internal (hp, epath);
1150 + exp = export_allowed_internal(ai, epath);
1153 /* We have to treat the root, "/", specially. */
1154 @@ -223,11 +266,17 @@ export_allowed(struct hostent *hp, char *path)
1159 - * Search hash table for export entry.
1162 + * export_lookup - search hash table for export entry
1163 + * @hname: '\0'-terminated ASCII string containing client hostname to look for
1164 + * @path: '\0'-terminated ASCII string containing export path to look for
1165 + * @canonical: if set, @hname is known to be canonical DNS name
1167 + * Returns a pointer to nfs_export record matching @hname and @path,
1168 + * or NULL if the export was not found.
1171 -export_lookup(char *hname, char *path, int canonical)
1172 +export_lookup(char *hname, char *path, int canonical)
1176 @@ -251,14 +300,18 @@ export_lookup(char *hname, char *path, int canonical)
1180 -export_check(nfs_export *exp, struct hostent *hp, char *path)
1181 +export_check(const nfs_export *exp, const struct addrinfo *ai, const char *path)
1183 if (strcmp(path, exp->m_export.e_path))
1186 - return client_check(exp->m_client, hp);
1187 + return client_check(exp->m_client, ai);
1191 + * export_freeall - deallocate all nfs_export records
1195 export_freeall(void)
1197 @@ -269,22 +322,13 @@ export_freeall(void)
1198 for (exp = exportlist[i].p_head; exp; exp = nxt) {
1200 client_release(exp->m_client);
1201 - if (exp->m_export.e_squids)
1202 - xfree(exp->m_export.e_squids);
1203 - if (exp->m_export.e_sqgids)
1204 - xfree(exp->m_export.e_sqgids);
1205 - if (exp->m_export.e_mountpoint)
1206 - free(exp->m_export.e_mountpoint);
1207 - if (exp->m_export.e_fslocdata)
1208 - xfree(exp->m_export.e_fslocdata);
1209 - xfree(exp->m_export.e_hostname);
1213 + for (j = 0; j < HASH_TABLE_SIZE; j++) {
1214 + exportlist[i].entries[j].p_first = NULL;
1215 + exportlist[i].entries[j].p_last = NULL;
1217 - for(j = 0; j < HASH_TABLE_SIZE; j++) {
1218 - exportlist[i].entries[j].p_first = NULL;
1219 - exportlist[i].entries[j].p_last = NULL;
1221 - exportlist[i].p_head = NULL;
1222 + exportlist[i].p_head = NULL;
1226 diff --git a/support/export/hostname.c b/support/export/hostname.c
1227 index 8a23a89..3c55ce7 100644
1228 --- a/support/export/hostname.c
1229 +++ b/support/export/hostname.c
1232 - * support/export/hostname.c
1233 + * Copyright 2010 Oracle. All rights reserved.
1235 - * Functions for hostname.
1236 + * This file is part of nfs-utils.
1238 + * nfs-utils is free software; you can redistribute it and/or modify
1239 + * it under the terms of the GNU General Public License as published by
1240 + * the Free Software Foundation; either version 2 of the License, or
1241 + * (at your option) any later version.
1243 + * nfs-utils is distributed in the hope that it will be useful,
1244 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1245 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1246 + * GNU General Public License for more details.
1248 + * You should have received a copy of the GNU General Public License
1249 + * along with nfs-utils. If not, see <http://www.gnu.org/licenses/>.
1252 #ifdef HAVE_CONFIG_H
1262 -#include <netinet/in.h>
1263 -#include <arpa/inet.h>
1267 -#define xmalloc malloc
1269 -#include "xmalloc.h"
1272 +#include <arpa/inet.h>
1276 -#define ALIGNMENT sizeof (char *)
1277 +#include "sockaddr.h"
1278 +#include "exportfs.h"
1281 -align (int len, int al)
1282 +#ifndef HAVE_DECL_AI_ADDRCONFIG
1283 +#define AI_ADDRCONFIG 0
1287 + * host_ntop - generate presentation address given a sockaddr
1288 + * @sap: pointer to socket address
1289 + * @buf: working storage
1290 + * @buflen: size of @buf in bytes
1292 + * Returns a pointer to a @buf.
1294 +#ifdef HAVE_GETNAMEINFO
1296 +host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
1304 + socklen_t salen = nfs_sockaddr_length(sap);
1307 + memset(buf, 0, buflen);
1310 + (void)strncpy(buf, "bad family", buflen - 1);
1314 + error = getnameinfo(sap, salen, buf, (socklen_t)buflen,
1315 + NULL, 0, NI_NUMERICHOST);
1318 + (void)strncpy(buf, "bad address", buflen - 1);
1322 -get_hostent (const char *addr, int len, int type)
1325 +#else /* !HAVE_GETNAMEINFO */
1327 +host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
1329 - struct hostent *cp;
1333 - int num_aliases = 1;
1334 - int len_aliases = sizeof (char *);
1335 - int num_addr_list = 1;
1336 - int len_addr_list = sizeof (char *);
1338 - struct in_addr *ipv4;
1343 - ipv4 = (struct in_addr *) addr;
1344 - name = inet_ntoa (*ipv4);
1351 - len_ent = align (sizeof (*cp), ALIGNMENT);
1352 - len_name = align (strlen (name) + 1, ALIGNMENT);
1355 - len_addr_list += align (len, ALIGNMENT) + sizeof (char *);
1357 - cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases
1360 - cp->h_addrtype = type;
1361 - cp->h_length = len;
1363 - cp->h_name = (char *) &(((char *) cp) [pos]);
1364 - strcpy (cp->h_name, name);
1367 - cp->h_aliases = (char **) &(((char *) cp) [pos]);
1368 - pos += num_aliases * sizeof (char *);
1369 - cp->h_aliases [0] = NULL;
1371 - pos = len_ent + len_name + len_aliases;
1372 - cp->h_addr_list = (char **) &(((char *) cp) [pos]);
1373 - pos += num_addr_list * sizeof (char *);
1374 - cp->h_addr_list [0] = (char *) &(((char *) cp) [pos]);
1375 - memcpy (cp->h_addr_list [0], addr, cp->h_length);
1376 - pos += align (cp->h_length, ALIGNMENT);
1377 - cp->h_addr_list [1] = NULL;
1380 + const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap;
1382 + memset(buf, 0, buflen);
1384 + if (sin->sin_family != AF_INET)
1385 + (void)strncpy(buf, "bad family", buflen - 1);
1389 + if (inet_ntop(AF_INET, &sin->sin_addr.s_addr, buf, buflen) != NULL)
1393 + (void)strncpy(buf, "bad address", buflen - 1);
1396 +#endif /* !HAVE_GETNAMEINFO */
1399 -hostent_dup (struct hostent *hp)
1401 + * host_pton - return addrinfo for a given presentation address
1402 + * @paddr: pointer to a '\0'-terminated ASCII string containing an
1403 + * IP presentation address
1405 + * Returns address info structure, or NULL if an error occurs. Caller
1406 + * must free the returned structure with freeaddrinfo(3).
1408 +__attribute_malloc__
1410 +host_pton(const char *paddr)
1412 - int len_ent = align (sizeof (*hp), ALIGNMENT);
1413 - int len_name = align (strlen (hp->h_name) + 1, ALIGNMENT);
1414 - int num_aliases = 1;
1415 - int len_aliases = sizeof (char *);
1416 - int num_addr_list = 1;
1417 - int len_addr_list = sizeof (char *);
1420 - struct hostent *cp;
1422 - for (sp = hp->h_aliases; sp && *sp; sp++)
1425 - len_aliases += align (strlen (*sp) + 1, ALIGNMENT)
1426 - + sizeof (char *);
1429 - for (sp = hp->h_addr_list; *sp; sp++)
1432 - len_addr_list += align (hp->h_length, ALIGNMENT)
1433 - + sizeof (char *);
1436 - cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases
1441 - cp->h_name = (char *) &(((char *) cp) [pos]);
1442 - strcpy (cp->h_name, hp->h_name);
1445 - cp->h_aliases = (char **) &(((char *) cp) [pos]);
1446 - pos += num_aliases * sizeof (char *);
1447 - for (sp = hp->h_aliases, i = 0; i < num_aliases; i++, sp++)
1450 - cp->h_aliases [i] = (char *) &(((char *) cp) [pos]);
1451 - strcpy (cp->h_aliases [i], *sp);
1452 - pos += align (strlen (*sp) + 1, ALIGNMENT);
1455 - cp->h_aliases [i] = NULL;
1457 - pos = len_ent + len_name + len_aliases;
1458 - cp->h_addr_list = (char **) &(((char *) cp) [pos]);
1459 - pos += num_addr_list * sizeof (char *);
1460 - for (sp = hp->h_addr_list, i = 0; i < num_addr_list; i++, sp++)
1463 - cp->h_addr_list [i] = (char *) &(((char *) cp) [pos]);
1464 - memcpy (cp->h_addr_list [i], *sp, hp->h_length);
1465 - pos += align (hp->h_length, ALIGNMENT);
1468 - cp->h_addr_list [i] = *sp;
1471 + struct addrinfo *ai = NULL;
1472 + struct addrinfo hint = {
1473 + /* don't return duplicates */
1474 + .ai_protocol = (int)IPPROTO_UDP,
1475 + .ai_flags = AI_NUMERICHOST,
1476 + .ai_family = AF_UNSPEC,
1478 + struct sockaddr_in sin;
1482 + * Although getaddrinfo(3) is easier to use and supports
1483 + * IPv6, it recognizes incomplete addresses like "10.4"
1484 + * as valid AF_INET addresses. It also accepts presentation
1485 + * addresses that end with a blank.
1487 + * inet_pton(3) is much stricter. Use it to be certain we
1488 + * have a real AF_INET presentation address, before invoking
1489 + * getaddrinfo(3) to generate the full addrinfo list.
1492 + if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0)
1495 + error = getaddrinfo(paddr, NULL, &hint, &ai);
1498 + if (!inet4 && ai->ai_addr->sa_family == AF_INET) {
1504 + if (paddr == NULL)
1505 + xlog(D_GENERAL, "%s: passed a NULL presentation address",
1509 + xlog(D_GENERAL, "%s: failed to convert %s: (%d) %m",
1510 + __func__, paddr, errno);
1513 + xlog(D_GENERAL, "%s: failed to convert %s: %s",
1514 + __func__, paddr, gai_strerror(error));
1522 -is_hostname(const char *sp)
1524 + * host_addrinfo - return addrinfo for a given hostname
1525 + * @hostname: pointer to a '\0'-terminated ASCII string containing a hostname
1527 + * Returns address info structure with ai_canonname filled in, or NULL
1528 + * if no information is available for @hostname. Caller must free the
1529 + * returned structure with freeaddrinfo(3).
1531 +__attribute_malloc__
1533 +host_addrinfo(const char *hostname)
1535 - if (*sp == '\0' || *sp == '@')
1540 - if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/')
1542 - if (*sp == '\\' && sp[1])
1547 + struct addrinfo *ai = NULL;
1548 + struct addrinfo hint = {
1549 +#ifdef IPV6_SUPPORTED
1550 + .ai_family = AF_UNSPEC,
1552 + .ai_family = AF_INET,
1554 + /* don't return duplicates */
1555 + .ai_protocol = (int)IPPROTO_UDP,
1556 + .ai_flags = AI_ADDRCONFIG | AI_CANONNAME,
1560 + error = getaddrinfo(hostname, NULL, &hint, &ai);
1565 + xlog(D_GENERAL, "%s: failed to resolve %s: (%d) %m",
1566 + __func__, hostname, errno);
1569 + xlog(D_GENERAL, "%s: failed to resolve %s: %s",
1570 + __func__, hostname, gai_strerror(error));
1578 -matchhostname (const char *h1, const char *h2)
1580 + * host_canonname - return canonical hostname bound to an address
1581 + * @sap: pointer to socket address to look up
1583 + * Discover the canonical hostname associated with the given socket
1584 + * address. The host's reverse mapping is verified in the process.
1586 + * Returns a '\0'-terminated ASCII string containing a hostname, or
1587 + * NULL if no hostname can be found for @sap. Caller must free
1590 +#ifdef HAVE_GETNAMEINFO
1591 +__attribute_malloc__
1593 +host_canonname(const struct sockaddr *sap)
1595 - struct hostent *hp1, *hp2;
1598 - if (strcasecmp (h1, h2) == 0)
1601 - if (!is_hostname (h1) || !is_hostname (h2))
1604 - hp1 = gethostbyname (h1);
1608 - hp1 = hostent_dup (hp1);
1610 - hp2 = gethostbyname (h2);
1613 - if (strcasecmp (hp1->h_name, hp2->h_name) == 0)
1617 - char **ap1, **ap2;
1620 - for (ap1 = hp1->h_addr_list; *ap1 && status == 0; ap1++)
1621 - for (ap2 = hp2->h_addr_list; *ap2; ap2++)
1622 - if (memcmp (*ap1, *ap2, sizeof (struct in_addr)) == 0)
1627 + socklen_t salen = nfs_sockaddr_length(sap);
1628 + char buf[NI_MAXHOST];
1632 + xlog(D_GENERAL, "%s: unsupported address family %d",
1633 + __func__, sap->sa_family);
1637 + memset(buf, 0, sizeof(buf));
1638 + error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
1639 + NULL, 0, NI_NAMEREQD);
1644 + xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m",
1648 + (void)getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
1649 + NULL, 0, NI_NUMERICHOST);
1650 + xlog(D_GENERAL, "%s: failed to resolve %s: %s",
1651 + __func__, buf, gai_strerror(error));
1660 + return strdup(buf);
1662 +#else /* !HAVE_GETNAMEINFO */
1663 +__attribute_malloc__
1665 +host_canonname(const struct sockaddr *sap)
1667 + const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap;
1668 + const struct in_addr *addr = &sin->sin_addr;
1669 + struct hostent *hp;
1671 + if (sap->sa_family != AF_INET)
1674 + hp = gethostbyaddr(addr, (socklen_t)sizeof(addr), AF_INET);
1678 + return strdup(hp->h_name);
1680 +#endif /* !HAVE_GETNAMEINFO */
1682 -/* Map IP to hostname, and then map back to addr to make sure it is a
1683 - * reliable hostname
1685 + * host_reliable_addrinfo - return addrinfo for a given address
1686 + * @sap: pointer to socket address to look up
1688 + * Reverse and forward lookups are performed to ensure the address has
1689 + * proper forward and reverse mappings.
1691 + * Returns address info structure with ai_canonname filled in, or NULL
1692 + * if no information is available for @sap. Caller must free the returned
1693 + * structure with freeaddrinfo(3).
1696 -get_reliable_hostbyaddr(const char *addr, int len, int type)
1697 +__attribute_malloc__
1699 +host_reliable_addrinfo(const struct sockaddr *sap)
1701 - struct hostent *hp = NULL;
1702 + struct addrinfo *ai;
1705 - struct hostent *reverse;
1706 - struct hostent *forward;
1709 - reverse = gethostbyaddr (addr, len, type);
1711 + hostname = host_canonname(sap);
1712 + if (hostname == NULL)
1715 - /* must make sure the hostent is authorative. */
1716 + ai = host_addrinfo(hostname);
1718 - reverse = hostent_dup (reverse);
1719 - forward = gethostbyname (reverse->h_name);
1725 - /* now make sure the "addr" is in the list */
1726 - for (sp = forward->h_addr_list ; *sp ; sp++) {
1727 - if (memcmp (*sp, addr, forward->h_length) == 0)
1731 + * host_numeric_addrinfo - return addrinfo without doing DNS queries
1732 + * @sap: pointer to socket address
1734 + * Returns address info structure, or NULL if an error occurred.
1735 + * Caller must free the returned structure with freeaddrinfo(3).
1737 +#ifdef HAVE_GETNAMEINFO
1738 +__attribute_malloc__
1740 +host_numeric_addrinfo(const struct sockaddr *sap)
1742 + socklen_t salen = nfs_sockaddr_length(sap);
1743 + char buf[INET6_ADDRSTRLEN];
1744 + struct addrinfo *ai;
1748 + xlog(D_GENERAL, "%s: unsupported address family %d",
1749 + __func__, sap->sa_family);
1755 - hp = hostent_dup (forward);
1758 - /* it was a FAKE */
1759 - xlog (L_WARNING, "Fake hostname %s for %s - forward lookup doesn't match reverse",
1760 - reverse->h_name, inet_ntoa(*(struct in_addr*)addr));
1762 + memset(buf, 0, sizeof(buf));
1763 + error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
1764 + NULL, 0, NI_NUMERICHOST);
1769 + xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m",
1773 + xlog(D_GENERAL, "%s: getnameinfo(3) failed: %s",
1774 + __func__, gai_strerror(error));
1778 - /* never heard of it. misconfigured DNS? */
1779 - xlog (L_WARNING, "Fake hostname %s for %s - forward lookup doesn't exist",
1780 - reverse->h_name, inet_ntoa(*(struct in_addr*)addr));
1782 + ai = host_pton(buf);
1785 + * getaddrinfo(AI_NUMERICHOST) never fills in ai_canonname
1788 + free(ai->ai_canonname); /* just in case */
1789 + ai->ai_canonname = strdup(buf);
1790 + if (ai->ai_canonname == NULL) {
1800 +#else /* !HAVE_GETNAMEINFO */
1801 +__attribute_malloc__
1803 +host_numeric_addrinfo(const struct sockaddr *sap)
1805 + const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
1806 + const struct in_addr *addr = &sin->sin_addr;
1807 + char buf[INET_ADDRSTRLEN];
1808 + struct addrinfo *ai;
1810 + if (sap->sa_family != AF_INET)
1815 -print_host (struct hostent *hp)
1821 - printf ("official hostname: %s\n", hp->h_name);
1822 - printf ("aliases:\n");
1823 - for (sp = hp->h_aliases; *sp; sp++)
1824 - printf (" %s\n", *sp);
1825 - printf ("IP addresses:\n");
1826 - for (sp = hp->h_addr_list; *sp; sp++)
1827 - printf (" %s\n", inet_ntoa (*(struct in_addr *) *sp));
1830 - printf ("Not host information\n");
1832 + memset(buf, 0, sizeof(buf));
1833 + if (inet_ntop(AF_INET, (char *)addr, buf,
1834 + (socklen_t)sizeof(buf)) == NULL)
1838 -main (int argc, char **argv)
1840 - struct hostent *hp = gethostbyname (argv [1]);
1841 - struct hostent *cp;
1842 - struct in_addr addr;
1848 - cp = hostent_dup (hp);
1852 - printf ("127.0.0.1 == %s: %d\n", argv [1],
1853 - matchhostname ("127.0.0.1", argv [1]));
1854 - addr.s_addr = inet_addr(argv [2]);
1855 - printf ("%s\n", inet_ntoa (addr));
1856 - cp = get_hostent ((const char *)&addr, sizeof(addr), AF_INET);
1859 + ai = host_pton(buf);
1862 + * getaddrinfo(AI_NUMERICHOST) never fills in ai_canonname
1865 + ai->ai_canonname = strdup(buf);
1866 + if (ai->ai_canonname == NULL) {
1875 +#endif /* !HAVE_GETNAMEINFO */
1876 diff --git a/support/export/nfsctl.c b/support/export/nfsctl.c
1877 index e2877b9..f89c644 100644
1878 --- a/support/export/nfsctl.c
1879 +++ b/support/export/nfsctl.c
1880 @@ -66,7 +66,7 @@ str_tolower(char *s)
1882 cltsetup(struct nfsctl_client *cltarg, nfs_client *clp)
1887 if (clp->m_type != MCL_FQDN) {
1888 xlog(L_ERROR, "internal: can't export non-FQDN host");
1889 @@ -76,10 +76,19 @@ cltsetup(struct nfsctl_client *cltarg, nfs_client *clp)
1890 strncpy(cltarg->cl_ident, clp->m_hostname,
1891 sizeof (cltarg->cl_ident) - 1);
1892 str_tolower(cltarg->cl_ident);
1893 - cltarg->cl_naddr = clp->m_naddr;
1894 - for (i = 0; i < cltarg->cl_naddr && i < NFSCLNT_ADDRMAX; i++)
1895 - cltarg->cl_addrlist[i] = clp->m_addrlist[i];
1898 + for (i = 0; i < cltarg->cl_naddr && i < NFSCLNT_ADDRMAX; i++) {
1899 + const struct sockaddr_in *sin = get_addrlist_in(clp, i);
1900 + if (sin->sin_family == AF_INET)
1901 + cltarg->cl_addrlist[j++] = sin->sin_addr;
1904 + xlog(L_ERROR, "internal: no supported addresses in nfs_client");
1908 + cltarg->cl_naddr = j;
1912 @@ -100,7 +109,7 @@ expsetup(struct nfsctl_export *exparg, nfs_export *exp, int unexport)
1913 str_tolower(exparg->ex_client);
1914 exparg->ex_flags = exp->m_export.e_flags;
1915 exparg->ex_dev = (!unexport && (exp->m_export.e_flags & NFSEXP_FSID)) ?
1916 - exp->m_export.e_fsid : stb.st_dev;
1917 + (__nfsd_dev_t)exp->m_export.e_fsid : stb.st_dev;
1918 exparg->ex_ino = stb.st_ino;
1919 exparg->ex_anon_uid = exp->m_export.e_anonuid;
1920 exparg->ex_anon_gid = exp->m_export.e_anongid;
1921 diff --git a/support/export/rmtab.c b/support/export/rmtab.c
1922 index b49e1aa..31c0f50 100644
1923 --- a/support/export/rmtab.c
1924 +++ b/support/export/rmtab.c
1930 + * See if the entry already exists. If not,
1931 + * this was an instantiated wild card, and we
1935 +rmtab_read_wildcard(struct rmtabent *rep)
1937 + nfs_export *exp, *exp2;
1938 + struct addrinfo *ai;
1940 + ai = host_addrinfo(rep->r_client);
1944 + exp = export_allowed(ai, rep->r_path);
1949 + exp2 = export_lookup(rep->r_client, exp->m_export.e_path, 0);
1950 + if (exp2 == NULL) {
1951 + struct exportent ee;
1953 + memset(&ee, 0, sizeof(ee));
1954 + dupexportent(&ee, &exp->m_export);
1956 + ee.e_hostname = rep->r_client;
1957 + exp2 = export_create(&ee, 0);
1958 + exp2->m_changed = exp->m_changed;
1960 + exp2->m_mayexport = 1;
1966 struct rmtabent *rep;
1967 - nfs_export *exp = NULL;
1970 while ((rep = getrmtabent(1, NULL)) != NULL) {
1971 - struct hostent *hp = NULL;
1975 htype = client_gettype(rep->r_client);
1976 - if ((htype == MCL_FQDN || htype == MCL_SUBNETWORK)
1977 - && (hp = gethostbyname (rep->r_client))
1978 - && (hp = hostent_dup (hp),
1979 - exp = export_allowed (hp, rep->r_path))) {
1980 - /* see if the entry already exists, otherwise this was an instantiated
1981 - * wild card, and we must add it
1983 - nfs_export *exp2 = export_lookup(rep->r_client,
1984 - exp->m_export.e_path, 0);
1986 - struct exportent ee;
1987 - dupexportent(&ee, &exp->m_export);
1988 - ee.e_hostname = rep->r_client;
1989 - exp2 = export_create(&ee, 0);
1990 - exp2->m_changed = exp->m_changed;
1993 - exp2->m_mayexport = 1;
1994 - } else if (hp) /* export_allowed failed */
1996 + if (htype == MCL_FQDN || htype == MCL_SUBNETWORK)
1997 + rmtab_read_wildcard(rep);
2000 if (errno == EINVAL) {
2001 /* Something goes wrong. We need to fix the rmtab
2003 diff --git a/support/include/exportfs.h b/support/include/exportfs.h
2004 index 470b2ec..3cf1ee8 100644
2005 --- a/support/include/exportfs.h
2006 +++ b/support/include/exportfs.h
2012 +#include "sockaddr.h"
2016 @@ -35,11 +37,56 @@ typedef struct mclient {
2020 - struct in_addr m_addrlist[NFSCLNT_ADDRMAX];
2021 + union nfs_sockaddr m_addrlist[NFSCLNT_ADDRMAX];
2022 int m_exported; /* exported to nfsd */
2026 +static inline const struct sockaddr *
2027 +get_addrlist(const nfs_client *clp, const int i)
2029 + return &clp->m_addrlist[i].sa;
2032 +static inline const struct sockaddr_in *
2033 +get_addrlist_in(const nfs_client *clp, const int i)
2035 + return &clp->m_addrlist[i].s4;
2038 +static inline const struct sockaddr_in6 *
2039 +get_addrlist_in6(const nfs_client *clp, const int i)
2041 + return &clp->m_addrlist[i].s6;
2045 +set_addrlist_in(nfs_client *clp, const int i, const struct sockaddr_in *sin)
2047 + memcpy(&clp->m_addrlist[i].s4, sin, sizeof(*sin));
2051 +set_addrlist_in6(nfs_client *clp, const int i, const struct sockaddr_in6 *sin6)
2053 + memcpy(&clp->m_addrlist[i].s6, sin6, sizeof(*sin6));
2057 +set_addrlist(nfs_client *clp, const int i, const struct sockaddr *sap)
2059 + switch (sap->sa_family) {
2061 + memcpy(&clp->m_addrlist[i].s4, sap, sizeof(struct sockaddr_in));
2063 +#ifdef IPV6_SUPPORTED
2065 + memcpy(&clp->m_addrlist[i].s6, sap, sizeof(struct sockaddr_in6));
2071 typedef struct mexport {
2072 struct mexport * m_next;
2073 struct mclient * m_client;
2074 @@ -69,26 +116,26 @@ extern exp_hash_table exportlist[MCL_MAXTYPES];
2075 extern nfs_client * clientlist[MCL_MAXTYPES];
2077 nfs_client * client_lookup(char *hname, int canonical);
2078 -nfs_client * client_find(struct hostent *);
2079 -void client_add(nfs_client *);
2080 -nfs_client * client_dup(nfs_client *, struct hostent *);
2081 +nfs_client * client_dup(const nfs_client *clp,
2082 + const struct addrinfo *ai);
2083 int client_gettype(char *hname);
2084 -int client_check(nfs_client *, struct hostent *);
2085 -int client_match(nfs_client *, char *hname);
2086 +int client_check(const nfs_client *clp,
2087 + const struct addrinfo *ai);
2088 void client_release(nfs_client *);
2089 void client_freeall(void);
2090 -char * client_compose(struct hostent *he);
2091 -struct hostent * client_resolve(struct in_addr addr);
2092 -int client_member(char *client, char *name);
2093 +char * client_compose(const struct addrinfo *ai);
2094 +struct addrinfo * client_resolve(const struct sockaddr *sap);
2095 +int client_member(const char *client,
2096 + const char *name);
2098 -int export_read(char *fname);
2099 -void export_add(nfs_export *);
2100 +void export_read(char *fname);
2101 void export_reset(nfs_export *);
2102 nfs_export * export_lookup(char *hname, char *path, int caconical);
2103 -nfs_export * export_find(struct hostent *, char *path);
2104 -nfs_export * export_allowed(struct hostent *, char *path);
2105 +nfs_export * export_find(const struct addrinfo *ai,
2106 + const char *path);
2107 +nfs_export * export_allowed(const struct addrinfo *ai,
2108 + const char *path);
2109 nfs_export * export_create(struct exportent *, int canonical);
2110 -nfs_export * export_dup(nfs_export *, struct hostent *);
2111 void export_freeall(void);
2112 int export_export(nfs_export *);
2113 int export_unexport(nfs_export *);
2114 @@ -101,6 +148,19 @@ void xtab_append(nfs_export *);
2116 int secinfo_addflavor(struct flav_info *, struct exportent *);
2118 +char * host_ntop(const struct sockaddr *sap,
2119 + char *buf, const size_t buflen);
2120 +__attribute_malloc__
2121 +struct addrinfo * host_pton(const char *paddr);
2122 +__attribute_malloc__
2123 +struct addrinfo * host_addrinfo(const char *hostname);
2124 +__attribute_malloc__
2125 +char * host_canonname(const struct sockaddr *sap);
2126 +__attribute_malloc__
2127 +struct addrinfo * host_reliable_addrinfo(const struct sockaddr *sap);
2128 +__attribute_malloc__
2129 +struct addrinfo * host_numeric_addrinfo(const struct sockaddr *sap);
2131 int rmtab_read(void);
2133 struct nfskey * key_lookup(char *hname);
2134 diff --git a/support/include/misc.h b/support/include/misc.h
2135 index 9a1b25d..bc5ba23 100644
2136 --- a/support/include/misc.h
2137 +++ b/support/include/misc.h
2139 int randomkey(unsigned char *keyout, int len);
2140 int weakrandomkey(unsigned char *keyout, int len);
2142 -int matchhostname(const char *h1, const char *h2);
2145 -struct hostent *hostent_dup(struct hostent *hp);
2146 -struct hostent *get_hostent (const char *addr, int len, int type);
2147 -struct hostent *get_reliable_hostbyaddr(const char *addr, int len, int type);
2149 extern int is_mountpoint(char *path);
2152 diff --git a/support/include/nfslib.h b/support/include/nfslib.h
2153 index 537a31e..3db5bec 100644
2154 --- a/support/include/nfslib.h
2155 +++ b/support/include/nfslib.h
2156 @@ -83,7 +83,7 @@ struct exportent {
2161 + unsigned int e_fsid;
2162 char * e_mountpoint;
2165 @@ -134,9 +134,12 @@ int nfsaddclient(struct nfsctl_client *clp);
2166 int nfsdelclient(struct nfsctl_client *clp);
2167 int nfsexport(struct nfsctl_export *exp);
2168 int nfsunexport(struct nfsctl_export *exp);
2169 -struct nfs_fh_len * getfh_old(struct sockaddr *addr, dev_t dev, ino_t ino);
2170 -struct nfs_fh_len * getfh(struct sockaddr *addr, const char *);
2171 -struct nfs_fh_len * getfh_size(struct sockaddr *addr, const char *, int size);
2173 +struct nfs_fh_len * getfh_old(const struct sockaddr_in *sin,
2174 + const dev_t dev, const ino_t ino);
2175 +struct nfs_fh_len * getfh(const struct sockaddr_in *sin, const char *path);
2176 +struct nfs_fh_len * getfh_size(const struct sockaddr_in *sin,
2177 + const char *path, int const size);
2179 void qword_print(FILE *f, char *str);
2180 void qword_printhex(FILE *f, char *str, int slen);
2181 @@ -152,10 +155,15 @@ void qword_addhex(char **bpp, int *lp, char *buf, int blen);
2182 void qword_addint(char **bpp, int *lp, int n);
2183 void qword_adduint(char **bpp, int *lp, unsigned int n);
2184 void qword_addeol(char **bpp, int *lp);
2185 +int qword_get_uint(char **bpp, unsigned int *anint);
2186 +void qword_printuint(FILE *f, unsigned int num);
2188 void closeall(int min);
2190 int svctcp_socket (u_long __number, int __reuse);
2191 -int svcudp_socket (u_long __number, int __reuse);
2192 +int svcudp_socket (u_long __number);
2195 +#define UNUSED(x) UNUSED_ ## x __attribute__((unused))
2197 #endif /* NFSLIB_H */
2198 diff --git a/support/include/nfsrpc.h b/support/include/nfsrpc.h
2199 index 4db35ab..6ebefca 100644
2200 --- a/support/include/nfsrpc.h
2201 +++ b/support/include/nfsrpc.h
2202 @@ -160,4 +160,7 @@ extern int nfs_rpc_ping(const struct sockaddr *sap,
2203 const unsigned short protocol,
2204 const struct timeval *timeout);
2206 +/* create AUTH_SYS handle with no supplemental groups */
2207 +extern AUTH * nfs_authsys_create(void);
2209 #endif /* !__NFS_UTILS_NFSRPC_H */
2210 diff --git a/support/include/rpcmisc.h b/support/include/rpcmisc.h
2211 index 1b8f411..c5847fa 100644
2212 --- a/support/include/rpcmisc.h
2213 +++ b/support/include/rpcmisc.h
2214 @@ -60,12 +60,12 @@ extern int _rpcsvcdirty;
2216 static inline struct sockaddr_in *nfs_getrpccaller_in(SVCXPRT *xprt)
2218 - return (struct sockaddr_in *)svc_getcaller(xprt);
2219 + return (struct sockaddr_in *)(char *)svc_getcaller(xprt);
2222 static inline struct sockaddr *nfs_getrpccaller(SVCXPRT *xprt)
2224 - return (struct sockaddr *)svc_getcaller(xprt);
2225 + return (struct sockaddr *)(char *)svc_getcaller(xprt);
2228 #endif /* RPCMISC_H */
2229 diff --git a/support/nfs/cacheio.c b/support/nfs/cacheio.c
2230 index bdf5d84..9bad8e6 100644
2231 --- a/support/nfs/cacheio.c
2232 +++ b/support/nfs/cacheio.c
2233 @@ -148,6 +148,11 @@ void qword_printint(FILE *f, int num)
2234 fprintf(f, "%d ", num);
2237 +void qword_printuint(FILE *f, unsigned int num)
2239 + fprintf(f, "%u ", num);
2242 int qword_eol(FILE *f)
2245 @@ -236,6 +241,20 @@ int qword_get_int(char **bpp, int *anint)
2249 +int qword_get_uint(char **bpp, unsigned int *anint)
2254 + int len = qword_get(bpp, buf, 50);
2255 + if (len < 0) return -1;
2256 + if (len ==0) return -1;
2257 + rv = strtoul(buf, &ep, 0);
2258 + if (*ep) return -1;
2263 #define READLINE_BUFFER_INCREMENT 2048
2265 int readline(int fd, char **buf, int *lenp)
2266 @@ -330,7 +349,7 @@ cache_flush(int force)
2267 sprintf(path, "/proc/net/rpc/%s/flush", cachelist[c]);
2268 fd = open(path, O_RDWR);
2270 - if (write(fd, stime, strlen(stime)) != strlen(stime)) {
2271 + if (write(fd, stime, strlen(stime)) != (ssize_t)strlen(stime)) {
2272 xlog_warn("Writing to '%s' failed: errno %d (%s)",
2273 path, errno, strerror(errno));
2275 diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
2276 index b277c2a..24640f4 100644
2277 --- a/support/nfs/conffile.c
2278 +++ b/support/nfs/conffile.c
2280 #include "conffile.h"
2283 -static void conf_load_defaults (int);
2284 +static void conf_load_defaults(void);
2285 static int conf_set(int , char *, char *, char *,
2286 char *, int , int );
2288 @@ -212,7 +212,7 @@ conf_parse_line(int trans, char *line, size_t sz)
2294 static char *section = 0;
2295 static char *arg = 0;
2297 @@ -353,7 +353,7 @@ conf_parse(int trans, char *buf, size_t sz)
2301 -conf_load_defaults(int tr)
2302 +conf_load_defaults(void)
2306 @@ -412,7 +412,7 @@ conf_reinit(void)
2307 trans = conf_begin();
2309 /* Load default configuration values. */
2310 - conf_load_defaults(trans);
2311 + conf_load_defaults();
2313 /* Free potential existing configuration. */
2315 diff --git a/support/nfs/exports.c b/support/nfs/exports.c
2316 index a93941c..1744ed6 100644
2317 --- a/support/nfs/exports.c
2318 +++ b/support/nfs/exports.c
2319 @@ -332,6 +332,8 @@ dupexportent(struct exportent *dst, struct exportent *src)
2320 dst->e_mountpoint = strdup(src->e_mountpoint);
2321 if (src->e_fslocdata)
2322 dst->e_fslocdata = strdup(src->e_fslocdata);
2324 + dst->e_uuid = strdup(src->e_uuid);
2325 dst->e_hostname = NULL;
2328 diff --git a/support/nfs/getfh.c b/support/nfs/getfh.c
2329 index 81266fd..611459b 100644
2330 --- a/support/nfs/getfh.c
2331 +++ b/support/nfs/getfh.c
2332 @@ -19,60 +19,112 @@
2337 + * getfh_old - ask the kernel for an NFSv2 file handle via nfsctl()
2338 + * @sin: pointer to IPv4 address of a client
2339 + * @dev: device number of device where requested object resides
2340 + * @ino: inode number of requested object
2342 + * Returns a pointer to an NFSv2 file handle, or NULL if some error
2343 + * occurred. errno is set to reflect the specifics of the error.
2346 -getfh_old (struct sockaddr *addr, dev_t dev, ino_t ino)
2347 +getfh_old(const struct sockaddr_in *sin, const dev_t dev, const ino_t ino)
2349 union nfsctl_res res;
2350 struct nfsctl_arg arg;
2351 static struct nfs_fh_len rfh;
2353 + if (sin->sin_family != AF_INET) {
2354 + errno = EAFNOSUPPORT;
2358 + memset(&arg, 0, sizeof(arg));
2359 + memset(&res, 0, sizeof(res));
2361 arg.ca_version = NFSCTL_VERSION;
2362 arg.ca_getfh.gf_version = 2; /* obsolete */
2363 arg.ca_getfh.gf_dev = dev;
2364 arg.ca_getfh.gf_ino = ino;
2365 - memcpy(&arg.ca_getfh.gf_addr, addr, sizeof(struct sockaddr_in));
2366 + memcpy(&arg.ca_getfh.gf_addr, sin, sizeof(*sin));
2368 if (nfsctl(NFSCTL_GETFH, &arg, &res) < 0)
2371 + memset(&rfh, 0, sizeof(rfh));
2373 memcpy(rfh.fh_handle, &res.cr_getfh, 32);
2378 + * getfh - ask the kernel for an NFSv2 file handle via nfsctl()
2379 + * @sin: pointer to IPv4 address of a client
2380 + * @path: pointer to a '\0'-terminated ASCII string containing an pathname
2382 + * Returns a pointer to an NFSv2 file handle, or NULL if some error
2383 + * occurred. errno is set to reflect the specifics of the error.
2386 -getfh(struct sockaddr *addr, const char *path)
2387 +getfh(const struct sockaddr_in *sin, const char *path)
2389 static union nfsctl_res res;
2390 struct nfsctl_arg arg;
2391 static struct nfs_fh_len rfh;
2393 + if (sin->sin_family != AF_INET) {
2394 + errno = EAFNOSUPPORT;
2398 + memset(&arg, 0, sizeof(arg));
2399 + memset(&res, 0, sizeof(res));
2401 arg.ca_version = NFSCTL_VERSION;
2402 arg.ca_getfd.gd_version = 2; /* obsolete */
2403 strncpy(arg.ca_getfd.gd_path, path,
2404 sizeof(arg.ca_getfd.gd_path) - 1);
2405 arg.ca_getfd.gd_path[sizeof (arg.ca_getfd.gd_path) - 1] = '\0';
2406 - memcpy(&arg.ca_getfd.gd_addr, addr, sizeof(struct sockaddr_in));
2407 + memcpy(&arg.ca_getfd.gd_addr, sin, sizeof(*sin));
2409 if (nfsctl(NFSCTL_GETFD, &arg, &res) < 0)
2412 + memset(&rfh, 0, sizeof(rfh));
2414 memcpy(rfh.fh_handle, &res.cr_getfh, 32);
2419 + * getfh_size - ask the kernel for a file handle via nfsctl()
2420 + * @sin: pointer to IPv4 address of a client
2421 + * @path: pointer to a '\0'-terminated ASCII string containing an pathname
2422 + * @size: maximum size, in bytes, of the returned file handle
2424 + * Returns a pointer to an NFSv3 file handle, or NULL if some error
2425 + * occurred. errno is set to reflect the specifics of the error.
2428 -getfh_size(struct sockaddr *addr, const char *path, int size)
2429 +getfh_size(const struct sockaddr_in *sin, const char *path, const int size)
2431 static union nfsctl_res res;
2432 struct nfsctl_arg arg;
2434 + if (sin->sin_family != AF_INET) {
2435 + errno = EAFNOSUPPORT;
2439 + memset(&arg, 0, sizeof(arg));
2440 + memset(&res, 0, sizeof(res));
2442 arg.ca_version = NFSCTL_VERSION;
2443 strncpy(arg.ca_getfs.gd_path, path,
2444 sizeof(arg.ca_getfs.gd_path) - 1);
2445 arg.ca_getfs.gd_path[sizeof (arg.ca_getfs.gd_path) - 1] = '\0';
2446 - memcpy(&arg.ca_getfs.gd_addr, addr, sizeof(struct sockaddr_in));
2447 + memcpy(&arg.ca_getfs.gd_addr, sin, sizeof(*sin));
2448 arg.ca_getfs.gd_maxlen = size;
2450 if (nfsctl(NFSCTL_GETFS, &arg, &res) < 0)
2451 diff --git a/support/nfs/nfs_mntent.c b/support/nfs/nfs_mntent.c
2452 index a3fecfc..9c73ae0 100644
2453 --- a/support/nfs/nfs_mntent.c
2454 +++ b/support/nfs/nfs_mntent.c
2455 @@ -28,7 +28,7 @@ static char *
2456 mangle(const char *arg) {
2457 const unsigned char *s = (const unsigned char *)arg;
2463 ss = sp = xmalloc(4*n+1);
2464 diff --git a/support/nfs/rmtab.c b/support/nfs/rmtab.c
2465 index a28abf3..ca789a3 100644
2466 --- a/support/nfs/rmtab.c
2467 +++ b/support/nfs/rmtab.c
2473 + * Colons in incoming IPv6 presentation addresses have to
2474 + * replaced with another character, since rmtab already
2475 + * uses colons to delineate fields.
2477 + * Use a printable character, but one that would never be
2478 + * found in a presentation address or domain name
2480 +#define IPV6_COLON ';'
2482 +#define LINELEN (2048)
2484 static FILE *rmfp = NULL;
2487 @@ -56,7 +68,8 @@ struct rmtabent *
2488 fgetrmtabent(FILE *fp, int log, long *pos)
2490 static struct rmtabent re;
2491 - char buf[2048], *count, *host, *path;
2492 + char *count, *host, *path, *c;
2493 + static char buf[LINELEN];
2497 @@ -84,10 +97,16 @@ fgetrmtabent(FILE *fp, int log, long *pos)
2502 strncpy(re.r_client, host, sizeof (re.r_client) - 1);
2503 re.r_client[sizeof (re.r_client) - 1] = '\0';
2504 + for (c = re.r_client; *c != '\0'; c++)
2505 + if (*c == IPV6_COLON)
2508 strncpy(re.r_path, path, sizeof (re.r_path) - 1);
2509 re.r_path[sizeof (re.r_path) - 1] = '\0';
2514 @@ -100,10 +119,27 @@ putrmtabent(struct rmtabent *rep, long *pos)
2516 fputrmtabent(FILE *fp, struct rmtabent *rep, long *pos)
2518 + static char buf[LINELEN];
2521 if (!fp || (pos && fseek (fp, *pos, SEEK_SET) != 0))
2523 - fprintf(fp, "%s:%s:0x%.8x\n", rep->r_client, rep->r_path,
2527 + * To avoid confusing the token parser in fgetrmtabent(),
2528 + * convert colons in incoming IPv6 presentation addresses
2531 + if (strlen(rep->r_client) > sizeof(buf)) {
2532 + xlog(L_ERROR, "client name too large");
2535 + strncpy(buf, rep->r_client, sizeof(buf));
2536 + for (c = buf; *c != '\0'; c++)
2540 + (void)fprintf(fp, "%s:%s:0x%.8x\n", buf, rep->r_path, rep->r_count);
2544 diff --git a/support/nfs/rpc_socket.c b/support/nfs/rpc_socket.c
2545 index 0e20824..c14efe8 100644
2546 --- a/support/nfs/rpc_socket.c
2547 +++ b/support/nfs/rpc_socket.c
2548 @@ -557,3 +557,24 @@ rpcprog_t nfs_getrpcbyname(const rpcprog_t program, const char *table[])
2554 + * AUTH_SYS doesn't allow more than 16 gids in the supplemental group list.
2555 + * If there are more than that, trying to determine which ones to include
2556 + * in the list is problematic. This function creates an auth handle that
2557 + * only has the primary gid in the supplemental gids list. It's intended to
2558 + * be used for protocols where credentials really don't matter much (the MNT
2559 + * protocol, for instance).
2562 +nfs_authsys_create(void)
2564 + char machname[MAXHOSTNAMELEN + 1];
2565 + uid_t uid = geteuid();
2566 + gid_t gid = getegid();
2568 + if (gethostname(machname, sizeof(machname)) == -1)
2571 + return authunix_create(machname, uid, gid, 1, &gid);
2573 diff --git a/support/nfs/rpcdispatch.c b/support/nfs/rpcdispatch.c
2574 index 502fc5f..984c646 100644
2575 --- a/support/nfs/rpcdispatch.c
2576 +++ b/support/nfs/rpcdispatch.c
2577 @@ -27,12 +27,12 @@ rpc_dispatch(struct svc_req *rqstp, SVCXPRT *transp,
2579 struct rpc_dentry *dent;
2581 - if (rqstp->rq_vers > nvers) {
2582 + if (((int)rqstp->rq_vers) > nvers) {
2583 svcerr_progvers(transp, 1, nvers);
2586 dtable += (rqstp->rq_vers - 1);
2587 - if (rqstp->rq_proc > dtable->nproc) {
2588 + if (((int)rqstp->rq_proc) > dtable->nproc) {
2589 svcerr_noproc(transp);
2592 diff --git a/support/nfs/rpcmisc.c b/support/nfs/rpcmisc.c
2593 index a0854e7..b73187a 100644
2594 --- a/support/nfs/rpcmisc.c
2595 +++ b/support/nfs/rpcmisc.c
2596 @@ -154,7 +154,7 @@ rpc_init(char *name, int prog, int vers,
2597 sock = makesock(defport, IPPROTO_UDP);
2599 if (sock == RPC_ANYSOCK)
2600 - sock = svcudp_socket (prog, 1);
2601 + sock = svcudp_socket (prog);
2602 transp = svcudp_create(sock);
2603 if (transp == NULL) {
2604 xlog(L_FATAL, "cannot create udp service.");
2605 diff --git a/support/nfs/svc_socket.c b/support/nfs/svc_socket.c
2606 index f44217a..03a5325 100644
2607 --- a/support/nfs/svc_socket.c
2608 +++ b/support/nfs/svc_socket.c
2609 @@ -157,9 +157,9 @@ svctcp_socket (u_long number, int reuse)
2610 * Create and bind a UDP socket based on program number
2613 -svcudp_socket (u_long number, int reuse)
2614 +svcudp_socket (u_long number)
2616 - return svc_socket (number, SOCK_DGRAM, IPPROTO_UDP, 0);
2617 + return svc_socket (number, SOCK_DGRAM, IPPROTO_UDP, FALSE);
2621 @@ -174,7 +174,7 @@ check (u_long number, u_short port, int protocol, int reuse)
2622 if (protocol == IPPROTO_TCP)
2623 socket = svctcp_socket (number, reuse);
2625 - socket = svcudp_socket (number, reuse);
2626 + socket = svcudp_socket (number);
2630 diff --git a/support/nsm/file.c b/support/nsm/file.c
2631 index d469219..f4baeb9 100644
2632 --- a/support/nsm/file.c
2633 +++ b/support/nsm/file.c
2637 #include <sys/types.h>
2638 +#ifdef HAVE_SYS_CAPABILITY_H
2639 #include <sys/capability.h>
2641 #include <sys/prctl.h>
2642 #include <sys/stat.h>
2644 @@ -347,6 +349,7 @@ nsm_is_default_parentdir(void)
2646 nsm_clear_capabilities(void)
2648 +#ifdef HAVE_SYS_CAPABILITY_H
2651 caps = cap_from_text("cap_net_bind_service=ep");
2652 @@ -362,6 +365,7 @@ nsm_clear_capabilities(void)
2655 (void)cap_free(caps);
2660 diff --git a/tests/t0001-statd-basic-mon-unmon.sh b/tests/t0001-statd-basic-mon-unmon.sh
2663 diff --git a/tools/Makefile.am b/tools/Makefile.am
2664 index db15346..f2ce282 100644
2665 --- a/tools/Makefile.am
2666 +++ b/tools/Makefile.am
2667 @@ -6,6 +6,6 @@ if CONFIG_RPCGEN
2671 -SUBDIRS = locktest rpcdebug nlmtest $(OPTDIRS)
2672 +SUBDIRS = locktest rpcdebug nlmtest mountstats nfs-iostat $(OPTDIRS)
2674 MAINTAINERCLEANFILES = Makefile.in
2675 diff --git a/tools/mountstats/Makefile.am b/tools/mountstats/Makefile.am
2676 new file mode 100644
2677 index 0000000..ca617a2
2679 +++ b/tools/mountstats/Makefile.am
2681 +## Process this file with automake to produce Makefile.in
2682 +PYTHON_FILES = mountstats.py
2684 +man8_MANS = mountstats.man
2686 +EXTRA_DIST = $(man8_MANS) $(PYTHON_FILES)
2688 +all-local: $(PYTHON_FILES)
2691 + $(INSTALL) --mode 755 mountstats.py $(DESTDIR)$(sbindir)/mountstats
2693 +MAINTAINERCLEANFILES=Makefile.in
2694 diff --git a/tools/mountstats/mountstats.man b/tools/mountstats/mountstats.man
2695 new file mode 100644
2696 index 0000000..0de31b7
2698 +++ b/tools/mountstats/mountstats.man
2703 +.TH mountstats 8 "15 Apr 2010"
2705 +mountstats \- Displays NFS client per-mount statistics
2707 +.BI "mountstats ["<options> "] " <mount_point> " [ " <mount_point> "]"
2711 +command displays NFS client statisitics on each given
2716 +display only the NFS statistics
2719 +display only the RPC statistics
2722 +display the version of this command
2725 +.B /proc/self/mountstats
2731 +Chuck Lever <chuck.lever@oracle.com>
2732 diff --git a/tools/nfs-iostat/Makefile.am b/tools/nfs-iostat/Makefile.am
2733 new file mode 100644
2734 index 0000000..30f4054
2736 +++ b/tools/nfs-iostat/Makefile.am
2738 +## Process this file with automake to produce Makefile.in
2739 +PYTHON_FILES = nfs-iostat.py
2741 +man8_MANS = nfsiostat.man
2743 +EXTRA_DIST = $(man8_MANS) $(PYTHON_FILES)
2745 +all-local: $(PYTHON_FILES)
2748 + $(INSTALL) --mode 755 nfs-iostat.py $(DESTDIR)$(sbindir)/nfsiostat
2750 +MAINTAINERCLEANFILES=Makefile.in
2751 diff --git a/tools/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py
2752 index 2d0b143..1207674 100644
2753 --- a/tools/nfs-iostat/nfs-iostat.py
2754 +++ b/tools/nfs-iostat/nfs-iostat.py
2755 @@ -366,6 +366,12 @@ class DeviceData:
2756 sends = float(self.__rpc_data['rpcsends'])
2757 if sample_time == 0:
2758 sample_time = float(self.__nfs_data['age'])
2759 + # sample_time could still be zero if the export was just mounted.
2760 + # Set it to 1 to avoid divide by zero errors in this case since we'll
2761 + # likely still have relevant mount statistics to show.
2763 + if sample_time == 0:
2766 backlog = (float(self.__rpc_data['backlogutil']) / sends) / sample_time
2768 diff --git a/tools/nfs-iostat/nfsiostat.man b/tools/nfs-iostat/nfsiostat.man
2769 new file mode 100644
2770 index 0000000..99e04fb
2772 +++ b/tools/nfs-iostat/nfsiostat.man
2777 +.TH nfsiostat 8 "15 Apr 2010"
2779 +nfsiostat \- Emulate iostat for NFS mount points using /proc/self/mountstats
2781 +.BI "nfsiostat [[" <interval> "] [" <count> "]] [" <options> "]["<mount_point> "]
2785 +command displays NFS client per-mount statisitics.
2788 +specifies the amount of time in seconds between each report.
2789 +The first report contains statistics for the time since each file
2790 +system was mounted. Each subsequent report contains statistics collected
2791 +during the interval since the previous report.
2797 +specified, the value of
2799 +determines the number of reports generated at
2801 +seconds apart. if the interval parameter is
2802 +specified without the
2804 +parameter, the command generates reports continuously.
2812 +names are specified, statistics for only these mount points will
2813 +be displayed. Otherwise, all NFS mount points on the client are listed.
2816 +.B \-a " or " \-\-attr
2817 +displays statistics related to the attribute cache
2819 +.B \-d " or " \-\-dir
2820 +displays statistics related to directory operations
2822 +.B \-h " or " \-\-help
2823 +shows help message and exit
2825 +.B \-l LIST or " \-\-list=LIST
2826 +only print stats for first LIST mount points
2828 +.B \-p " or " \-\-page
2829 +displays statistics related to the page cache
2831 +.B \-s " or " \-\-sort
2832 +Sort NFS mount points by ops/second
2835 +show program's version number and exit
2838 +.B /proc/self/mountstats
2841 +.BR mountstats (8),
2844 +Chuck Lever <chuck.lever@oracle.com>
2845 diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c
2846 index 331e57e..b78957f 100644
2847 --- a/utils/exportfs/exportfs.c
2848 +++ b/utils/exportfs/exportfs.c
2853 +#include <sys/types.h>
2854 +#include <sys/stat.h>
2855 #include <sys/vfs.h>
2856 #include <sys/stat.h>
2858 +#include <stdbool.h>
2866 -#include "xmalloc.h"
2868 +#include "sockaddr.h"
2871 #include "exportfs.h"
2872 -#include "xmalloc.h"
2875 static void export_all(int verbose);
2876 @@ -34,13 +38,15 @@ static void unexportfs(char *arg, int verbose);
2877 static void exports_update(int verbose);
2878 static void dump(int verbose);
2879 static void error(nfs_export *exp, int err);
2880 -static void usage(void);
2881 +static void usage(const char *progname);
2882 static void validate_export(nfs_export *exp);
2883 +static int matchhostname(const char *hostname1, const char *hostname2);
2886 main(int argc, char **argv)
2888 char *options = NULL;
2889 + char *progname = NULL;
2893 @@ -50,7 +56,14 @@ main(int argc, char **argv)
2895 int force_flush = 0;
2897 - xlog_open("exportfs");
2898 + if ((progname = strrchr(argv[0], '/')) != NULL)
2901 + progname = argv[0];
2903 + xlog_open(progname);
2909 @@ -79,21 +92,21 @@ main(int argc, char **argv)
2919 if (optind != argc && f_all) {
2920 - fprintf(stderr,"exportfs: extra arguments are not permitted with -a or -r.\n");
2921 + xlog(L_ERROR, "extra arguments are not permitted with -a or -r");
2924 if (f_ignore && (f_all || ! f_export)) {
2925 - fprintf(stderr,"exportfs: -i not meaningful with -a, -r or -u.\n");
2926 + xlog(L_ERROR, "-i not meaningful with -a, -r or -u");
2929 if (f_reexport && ! f_export) {
2930 - fprintf(stderr, "exportfs: -r and -u are incompatible.\n");
2931 + xlog(L_ERROR, "-r and -u are incompatible");
2934 new_cache = check_new_cache();
2935 @@ -102,8 +115,10 @@ main(int argc, char **argv)
2939 - fprintf(stderr, "exportfs: -f: only available with new cache controls: mount /proc/fs/nfsd first\n");
2941 + xlog(L_ERROR, "-f is available only "
2942 + "with new cache controls. "
2943 + "Mount /proc/fs/nfsd first");
2948 @@ -232,7 +247,7 @@ exportfs(char *arg, char *options, int verbose)
2950 struct exportent *eep;
2952 - struct hostent *hp = NULL;
2953 + struct addrinfo *ai = NULL;
2957 @@ -241,36 +256,25 @@ exportfs(char *arg, char *options, int verbose)
2960 if (!path || *path != '/') {
2961 - fprintf(stderr, "Invalid exporting option: %s\n", arg);
2962 + xlog(L_ERROR, "Invalid exporting option: %s", arg);
2966 - if ((htype = client_gettype(hname)) == MCL_FQDN &&
2967 - (hp = gethostbyname(hname)) != NULL) {
2968 - struct hostent *hp2 = hostent_dup (hp);
2969 - hp = gethostbyaddr(hp2->h_addr, hp2->h_length,
2973 - hp = hostent_dup(hp);
2976 - exp = export_find(hp, path);
2977 - hname = hp->h_name;
2979 + if ((htype = client_gettype(hname)) == MCL_FQDN) {
2980 + ai = host_addrinfo(hname);
2982 + exp = export_find(ai, path);
2983 + hname = ai->ai_canonname;
2986 exp = export_lookup(hname, path, 0);
2990 if (!(eep = mkexportent(hname, path, options)) ||
2991 - !(exp = export_create(eep, 0))) {
2992 - if (hp) free (hp);
2995 - } else if (!updateexportent(&exp->m_export, options)) {
2996 - if (hp) free (hp);
2999 + !(exp = export_create(eep, 0)))
3001 + } else if (!updateexportent(&exp->m_export, options))
3005 printf("exporting %s:%s\n", exp->m_client->m_hostname,
3006 @@ -280,14 +284,16 @@ exportfs(char *arg, char *options, int verbose)
3009 validate_export(exp);
3010 - if (hp) free (hp);
3017 unexportfs(char *arg, int verbose)
3020 - struct hostent *hp = NULL;
3021 + struct addrinfo *ai = NULL;
3025 @@ -296,16 +302,14 @@ unexportfs(char *arg, int verbose)
3028 if (!path || *path != '/') {
3029 - fprintf(stderr, "Invalid unexporting option: %s\n",
3031 + xlog(L_ERROR, "Invalid unexporting option: %s", arg);
3035 if ((htype = client_gettype(hname)) == MCL_FQDN) {
3036 - if ((hp = gethostbyname(hname)) != 0) {
3037 - hp = hostent_dup (hp);
3038 - hname = (char *) hp->h_name;
3040 + ai = host_addrinfo(hname);
3042 + hname = ai->ai_canonname;
3045 for (exp = exportlist[htype].p_head; exp; exp = exp->m_next) {
3046 @@ -341,7 +345,7 @@ unexportfs(char *arg, int verbose)
3047 exp->m_mayexport = 0;
3050 - if (hp) free (hp);
3054 static int can_test(void)
3055 @@ -393,14 +397,12 @@ validate_export(nfs_export *exp)
3056 int fs_has_fsid = 0;
3058 if (stat(path, &stb) < 0) {
3059 - fprintf(stderr, "exportfs: Warning: %s does not exist\n",
3061 + xlog(L_ERROR, "Failed to stat %s: %m \n", path);
3064 if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) {
3065 - fprintf(stderr, "exportfs: Warning: %s is neither "
3066 - "a directory nor a file.\n"
3067 - " remote access will fail\n", path);
3068 + xlog(L_ERROR, "%s is neither a directory nor a file. "
3069 + "Remote access will fail", path);
3073 @@ -413,24 +415,75 @@ validate_export(nfs_export *exp)
3074 if ((exp->m_export.e_flags & NFSEXP_FSID) || exp->m_export.e_uuid ||
3076 if ( !test_export(path, 1)) {
3077 - fprintf(stderr, "exportfs: Warning: %s does not "
3078 - "support NFS export.\n",
3080 + xlog(L_ERROR, "%s does not support NFS export", path);
3083 } else if ( ! test_export(path, 0)) {
3084 if (test_export(path, 1))
3085 - fprintf(stderr, "exportfs: Warning: %s requires fsid= "
3086 - "for NFS export\n", path);
3087 + xlog(L_ERROR, "%s requires fsid= for NFS export", path);
3089 - fprintf(stderr, "exportfs: Warning: %s does not "
3090 - "support NFS export.\n",
3092 + xlog(L_ERROR, "%s does not support NFS export", path);
3099 +is_hostname(const char *sp)
3101 + if (*sp == '\0' || *sp == '@')
3104 + for (; *sp != '\0'; sp++) {
3105 + if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/')
3107 + if (*sp == '\\' && sp[1] != '\0')
3115 +matchhostname(const char *hostname1, const char *hostname2)
3117 + struct addrinfo *results1 = NULL, *results2 = NULL;
3118 + struct addrinfo *ai1, *ai2;
3121 + if (strcasecmp(hostname1, hostname2) == 0)
3125 + * Don't pass export wildcards or netgroup names to DNS
3127 + if (!is_hostname(hostname1) || !is_hostname(hostname2))
3130 + results1 = host_addrinfo(hostname1);
3131 + if (results1 == NULL)
3133 + results2 = host_addrinfo(hostname2);
3134 + if (results2 == NULL)
3137 + if (strcasecmp(results1->ai_canonname, results2->ai_canonname) == 0) {
3142 + for (ai1 = results1; ai1 != NULL; ai1 = ai1->ai_next)
3143 + for (ai2 = results2; ai2 != NULL; ai2 = ai2->ai_next)
3144 + if (nfs_compare_sockaddr(ai1->ai_addr, ai2->ai_addr)) {
3150 + freeaddrinfo(results1);
3151 + freeaddrinfo(results2);
3156 dumpopt(char c, char *fmt, ...)
3157 @@ -532,13 +585,13 @@ dump(int verbose)
3159 error(nfs_export *exp, int err)
3161 - fprintf(stderr, "%s:%s: %s\n", exp->m_client->m_hostname,
3162 + xlog(L_ERROR, "%s:%s: %s\n", exp->m_client->m_hostname,
3163 exp->m_export.e_path, strerror(err));
3168 +usage(const char *progname)
3170 - fprintf(stderr, "usage: exportfs [-aruv] [host:/path]\n");
3171 + fprintf(stderr, "usage: %s [-aruv] [host:/path]\n", progname);
3174 diff --git a/utils/exportfs/exportfs.man b/utils/exportfs/exportfs.man
3175 index c7b230a..089f75b 100644
3176 --- a/utils/exportfs/exportfs.man
3177 +++ b/utils/exportfs/exportfs.man
3183 .\" Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de>
3184 .\" Modifications 1999-2003 Neil Brown <neilb@cse.unsw.edu.au>
3185 -.TH exportfs 8 "18 July 2003"
3187 +.TH exportfs 8 "31 December 2009"
3189 -exportfs \- maintain list of NFS exported file systems
3190 +exportfs \- maintain table of exported NFS file systems
3192 .BI "/usr/sbin/exportfs [-avi] [-o " "options,.." "] [" "client:/path" " ..]
3194 @@ -18,229 +18,236 @@ exportfs \- maintain list of NFS exported file systems
3195 .BI "/usr/sbin/exportfs -f"
3198 +An NFS server maintains a table of local physical file systems
3199 +that are accessible to NFS clients.
3200 +Each file system in this table is referred to as an
3201 +.IR "exported file system" ,
3208 -command is used to maintain the current table of exported file systems for
3209 -NFS. This list is kept in a separate file named
3210 -.BR /var/lib/nfs/etab
3213 -when a remote host requests access to mount a file tree, and parts of
3214 -the list which are active are kept in the kernel's export table.
3218 -file is initialized with the list of all file systems named in
3220 +command maintains the current table of exports for the NFS server.
3221 +The master export table is kept in a file named
3222 +.IR /var/lib/nfs/etab .
3223 +This file is read by
3225 +when a client sends an NFS MOUNT request.
3227 +Normally the master export table is initialized with the contents of
3232 -However, administrators can choose to add and delete individual file systems
3238 +However, a system administrator can choose to add or delete
3239 +exports without modifying
3246 -and it's partner program
3248 -work in one of two modes, a legacy mode which applies to 2.4 and
3249 +and its partner program
3251 +work in one of two modes: a legacy mode which applies to 2.4 and
3252 earlier versions of the Linux kernel, and a new mode which applies to
3253 -2.6 and later versions providing the
3254 +2.6 and later versions, providing the
3256 virtual filesystem has been mounted at
3261 -If this filesystem is not mounted in 2.6, the legacy mode is used.
3264 +On 2.6 kernels, if this filesystem is not mounted, the legacy mode is used.
3268 -does not give any information to the kernel but only provides it to
3270 +does not give any information to the kernel, but provides it only to
3273 -.B /var/lib/nfs/etab
3274 +.I /var/lib/nfs/etab
3277 -will listen to requests from the kernel and will provide information
3281 +then manages kernel requests for information about exports, as needed.
3284 -any export requests which identify a specific host (rather than a
3285 -subnet or netgroup etc) are entered directly into the kernel's export
3286 -table as well as being written to
3287 -.BR /var/lib/nfs/etab .
3288 -Further, any mount points listed in
3289 -.B /var/lib/nfs/rmtab
3290 +exports which identify a specific host, rather than a subnet or netgroup,
3291 +are entered directly into the kernel's export table,
3292 +as well as being written to
3293 +.IR /var/lib/nfs/etab .
3294 +Further, exports listed in
3295 +.I /var/lib/nfs/rmtab
3296 which match a non host-specific export request will cause an
3297 appropriate export entry for the host given in
3300 -into the kernel's export table.
3302 +to be added to the kernel's export table.
3307 Export or unexport all directories.
3309 .BI "-o " options,...
3310 Specify a list of export options in the same manner as in
3317 -file, so that only default options and options given on the command
3320 +file. Only default options and options given on the command line are used.
3323 -Reexport all directories. It synchronizes /var/lib/nfs/etab
3324 -with /etc/exports. It removes entries in /var/lib/nfs/etab
3325 -which are deleted from /etc/exports, and remove any entries from the
3326 +Reexport all directories, synchronizing
3327 +.I /var/lib/nfs/etab
3330 +This option removes entries in
3331 +.I /var/lib/nfs/etab
3332 +which have been deleted from
3333 +.I /etc/exports, and removes any entries from the
3334 kernel export table which are no longer valid.
3337 Unexport one or more directories.
3340 -In 'new' mode, flush everything out of the kernels export table. Any
3341 -clients that are active will get new entries added by
3343 -when they make their next request.
3348 +is mounted, flush everything out of the kernel's export table.
3349 +Fresh entries for active clients are added to the kernel's export table by
3351 +when they make their next NFS mount request.
3354 Be verbose. When exporting or unexporting, show what's going on. When
3355 displaying the current export list, also display the list of export
3358 -.\" -------------------- Exporting Directories --------------------
3359 .SS Exporting Directories
3360 -The first synopsis shows how to invoke the command when adding new
3361 -entries to the export table. When using
3362 +The first synopsis shows how to invoke
3364 +when adding new entries to the export table. When using
3368 +all exports listed in
3372 -and the resulting list is pushed into the kernel.
3374 +.IR /var/lib/nfs/etab .
3375 +The kernel's export table is also updated as needed.
3379 -argument specifies the directory to export along with the host or hosts to
3380 -export it to. All formats described in
3381 +argument specifies a local directory to export,
3382 +along with the client or clients who are permitted to access it.
3385 -are supported; to export a directory to the world, simply specify
3386 +for a description of supported options and access list formats.
3387 +To export a directory to the world, simply specify
3391 The export options for a particular host/directory pair derive from
3392 -several sources. There is a set of default options which can be overridden by
3398 -In addition, the administrator may override any options from these sources
3401 +The default export options are
3402 +.BR sync,ro,root_squash,wdelay .
3403 +These can be overridden by entries in
3406 +A system administrator may override options from these sources using the
3408 -argument which takes a comma-separated list of options in the same fashion
3409 +command-line option on
3411 +This option takes a comma-separated list of options in the same fashion
3412 as one would specify them in
3418 -can also be used to modify the export options of an already exported
3421 -Modifications of the kernel export table used by
3423 -take place immediately after parsing the command line and updating the
3427 -The default export options are
3428 -.BR sync,ro,root_squash,wdelay .
3429 -.\" -------------------- Unexporting Directories ------------------
3430 +can be used to modify the export options of an already exported directory.
3431 .SS Unexporting Directories
3432 The third synopsis shows how to unexported a currently exported directory.
3434 .BR "exportfs -ua" ,
3435 all entries listed in
3437 +.I /var/lib/nfs/etab
3438 are removed from the kernel export tables, and the file is cleared. This
3439 effectively shuts down all NFS activity.
3441 -To remove an export to a host, specify a
3443 +To remove an export, specify a
3445 pair. This deletes the specified entry from
3447 +.I /var/lib/nfs/etab
3448 and removes the corresponding kernel entry (if any).
3449 -To remove one or more exports to several hosts, use
3450 -.BR "exportfs -ua" .
3452 -.\" -------------------- Dumping the Export Table -----------------
3453 -.SS Dumping the Export Table
3455 +.SS Dumping the Export Table
3458 -without further options shows the current list of exported file systems.
3460 +without options shows the current list of exported file systems.
3463 -option, the list of flags pertaining to each export are shown in addition.
3464 -.\" -------------------- EXAMPLES ---------------------------------
3467 +to display the export options for each export.
3469 The following adds all directories listed in
3473 -.B /var/lib/nfs/etab
3474 +.I /var/lib/nfs/etab
3475 and pushes the resulting export entries into the kernel:
3489 -allowing asynchronous writes, one would do this:
3491 +allowing insecure file locking requests from clients:
3494 -.B "# exportfs -o async django:/usr/tmp
3495 +.B "# exportfs -o insecure_locks django:/usr/tmp
3506 .B "# exportfs -u django:/usr/tmp
3509 -To unexport all the directories listed in
3513 +To unexport all exports listed in
3519 -.\" -------------------- DEPENDENCIES -----------------------------
3521 -Exporting to IP networks, DNS and NIS domains does not enable clients
3522 -from these groups to access NFS immediately; rather, these sorts of
3523 -exports are hints to
3526 +Exporting to IP networks or DNS and NIS domains does not enable clients
3527 +from these groups to access NFS immediately.
3528 +Rather, these sorts of exports are hints to
3530 to grant any mount requests from these clients.
3531 -This is usually not a big problem, because any existing mounts are preserved
3534 +This is usually not a problem, because any existing mounts are preserved in
3539 When unexporting a network or domain entry, any current exports to members
3540 of this group will be checked against the remaining valid exports and
3541 if they themselves are no longer valid they will be removed.
3543 -.\" -------------------- SEE ALSO --------------------------------
3547 +input file listing exports, export options, and access control lists
3549 +.I /var/lib/nfs/etab
3550 +master table of exports
3552 +.I /var/lib/nfs/rmtab
3553 +table of clients accessing server's exports
3555 -.BR exports(5) ", " mountd(8)
3556 -.\" -------------------- AUTHOR ----------------------------------
3558 +.BR rpc.mountd (8),
3561 -Olaf Kirch, <okir@monad.swb.de>
3562 +Olaf Kirch <okir@monad.swb.de>
3564 -Neil Brown, <neilb@cse.unsw.edu.au>
3566 +Neil Brown <neilb@cse.unsw.edu.au>
3567 diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man
3568 index ea28ca8..c726dd9 100644
3569 --- a/utils/exportfs/exports.man
3570 +++ b/utils/exportfs/exports.man
3572 -.TH EXPORTS 5 "4 March 2005" "Linux" "Linux File Formats Manual"
3575 +.TH exports 5 "31 December 2009"
3577 -exports \- NFS file systems being exported (for Kernel based NFS)
3580 +exports \- NFS server export table
3584 -serves as the access control list for file systems which may be
3585 -exported to NFS clients. It is used by
3587 +contains a table of local physical file systems on an NFS server
3588 +that are accessible to NFS clients.
3589 +The contents of the file are maintained by the server's system
3592 +Each file system in this table has a list of options and an
3593 +access control list.
3594 +The table is used by
3596 to give information to
3598 -and to the kernel based NFS file server daemon
3602 The file format is similar to the SunOS
3604 @@ -34,7 +38,9 @@ double quotes. You can also specify spaces or other unusual character in
3605 the export name using a backslash followed by the character code as three
3608 -To apply changes to this file, run exportfs \-ra or restart the NFS server.
3609 +To apply changes to this file, run
3611 +or restart the NFS server.
3613 .SS Machine Name Formats
3614 NFS clients may be specified in a number of ways:
3615 @@ -61,9 +67,10 @@ simultaneously. This is done by specifying an IP address and netmask pair
3618 where the netmask can be specified in dotted-decimal format, or as a
3619 -contiguous mask length (for example, either `/255.255.252.0' or `/22' appended
3620 -to the network base address result in identical subnetworks with 10 bits of
3621 -host). Wildcard characters generally do not work on IP addresses, though they
3622 +contiguous mask length.
3623 +For example, either `/255.255.252.0' or `/22' appended
3624 +to the network base IPv4 address results in identical subnetworks with 10 bits of
3625 +host. Wildcard characters generally do not work on IP addresses, though they
3626 may work by accident when reverse DNS lookups fail.
3629 @@ -106,7 +113,7 @@ preceding sec= option. The only options that are permitted to vary in
3630 this way are ro, rw, no_root_squash, root_squash, and all_squash.
3635 understands the following export options:
3638 @@ -144,7 +151,8 @@ default. In all releases after 1.0.0,
3641 must be explicitly requested if needed.
3642 -To help make system administrators aware of this change, 'exportfs'
3643 +To help make system administrators aware of this change,
3645 will issue a warning if neither
3648 @@ -188,7 +196,7 @@ The
3649 option is currently only effective on
3651 exports. It does not work reliably with netgroup, subnet, or wildcard
3655 This option can be very useful in some situations, but it should be
3656 used with due care, and only after confirming that the client system
3657 @@ -246,7 +254,7 @@ If you genuinely require subtree checking, you should explicitly put
3660 file. If you put neither option,
3663 will warn you that the change is pending.
3666 @@ -272,7 +280,9 @@ or
3669 On some specially patched kernels, and when exporting filesystems that
3670 -support ACLs, this option tells nfsd not to reveal ACLs to clients, so
3671 +support ACLs, this option tells
3673 +not to reveal ACLs to clients, so
3674 they will see only a subset of actual permissions on the given file
3675 system. This option is safe for filesystems used by NFSv2 clients and
3676 old NFSv3 clients that perform access decisions locally. Current
3677 @@ -381,7 +391,7 @@ of the filesystem must be handled elsewhere.)
3683 bases its access control to files on the server machine on the uid and
3684 gid provided in each NFS RPC request. The normal behavior a user would
3685 expect is that she can access her files on the server just as she would
3686 @@ -399,19 +409,19 @@ and can be turned off with
3687 .IR no_root_squash .
3692 '''tries to obtain the anonymous uid and gid by looking up user
3694 '''in the password file at startup time. If it isn't found, a uid and gid
3697 chooses a uid and gid
3698 of 65534 for squashed access. These values can also be overridden by
3700 .IR anonuid " and " anongid
3703 -'''In addition to this,
3705 +'''In addition to this,
3707 '''lets you specify arbitrary uids and gids that should be mapped to user
3709 Finally, you can map all user requests to the
3710 @@ -424,7 +434,7 @@ Here's the complete list of mapping options:
3711 Map requests from uid/gid 0 to the anonymous uid/gid. Note that this does
3712 not apply to any other uids or gids that might be equally sensitive, such as
3719 @@ -434,7 +444,7 @@ Turn off root squashing. This option is mainly useful for diskless clients.
3721 Map all uids and gids to the anonymous user. Useful for NFS-exported
3722 public FTP directories, news spool directories, etc. The opposite option
3726 which is the default setting.
3728 @@ -468,7 +478,7 @@ and netgroups (this is the entry `@trusted'). The fourth line shows the
3729 entry for the PC/NFS client discussed above. Line 5 exports the
3730 public FTP directory to every host in the world, executing all requests
3731 under the nobody account. The
3734 option in this entry also allows clients with NFS implementations that
3735 don't use a reserved port for NFS.
3736 The sixth line exports a directory read-write to the machine 'server'
3737 @@ -478,15 +488,15 @@ all three mounts with the `sync' option enabled.
3738 '''access to the private directory.
3740 '''Unlike other NFS server implementations, this
3743 '''allows you to export both a directory and a subdirectory thereof to
3744 -'''the same host, for instance
3745 +'''the same host, for instance
3746 '''.IR /usr " and " /usr/X11R6 .
3747 '''In this case, the mount options of the most specific entry apply. For
3748 -'''instance, when a user on the client host accesses a file in
3749 +'''instance, when a user on the client host accesses a file in
3751 -'''the mount options given in the
3753 +'''the mount options given in the
3755 '''entry apply. This is also true when the latter is a wildcard or netgroup
3758 @@ -499,7 +509,15 @@ all three mounts with the `sync' option enabled.
3761 '''An error parsing the file is reported using syslogd(8) as level NOTICE from
3762 -'''a DAEMON whenever nfsd(8) or mountd(8) is started up. Any unknown
3763 +'''a DAEMON whenever
3767 +'''is started up. Any unknown
3768 '''host is reported at that time, but often not all hosts are not yet known
3769 -'''to named(8) at boot time, thus as hosts are found they are reported
3770 -'''with the same syslogd(8) parameters.
3773 +'''at boot time, thus as hosts are found they are reported
3777 diff --git a/utils/gssd/context.h b/utils/gssd/context.h
3778 index be47f9c..c9cb0bd 100644
3779 --- a/utils/gssd/context.h
3780 +++ b/utils/gssd/context.h
3783 - Copyright (c) 2004 The Regents of the University of Michigan.
3784 + Copyright (c) 2004,2008 The Regents of the University of Michigan.
3785 All rights reserved.
3787 Redistribution and use in source and binary forms, with or without
3789 /* Hopefully big enough to hold any serialized context */
3790 #define MAX_CTX_LEN 4096
3792 +/* New context format flag values */
3793 +#define KRB5_CTX_FLAG_INITIATOR 0x00000001
3794 +#define KRB5_CTX_FLAG_CFX 0x00000002
3795 +#define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004
3797 int serialize_context_for_kernel(gss_ctx_id_t ctx, gss_buffer_desc *buf,
3798 gss_OID mech, int32_t *endtime);
3799 diff --git a/utils/gssd/context_lucid.c b/utils/gssd/context_lucid.c
3800 index 4a682ae..b8d4734 100644
3801 --- a/utils/gssd/context_lucid.c
3802 +++ b/utils/gssd/context_lucid.c
3809 #include <gssapi/gssapi_krb5.h>
3811 @@ -76,7 +77,7 @@ prepare_krb5_rfc1964_buffer(gss_krb5_lucid_context_v1_t *lctx,
3812 unsigned char fakeseed[FAKESEED_SIZE];
3813 uint32_t word_send_seq;
3814 gss_krb5_lucid_key_t enc_key;
3818 gss_buffer_desc fakeoid;
3820 @@ -119,15 +120,13 @@ prepare_krb5_rfc1964_buffer(gss_krb5_lucid_context_v1_t *lctx,
3821 * Note that the rfc1964 version only supports DES enctypes.
3823 if (lctx->rfc1964_kd.ctx_key.type != 4) {
3824 - printerr(1, "prepare_krb5_rfc1964_buffer: "
3825 - "overriding heimdal keytype (%d => %d)\n",
3826 - lctx->rfc1964_kd.ctx_key.type, 4);
3827 + printerr(2, "%s: overriding heimdal keytype (%d => %d)\n",
3828 + __FUNCTION__, lctx->rfc1964_kd.ctx_key.type, 4);
3829 lctx->rfc1964_kd.ctx_key.type = 4;
3832 - printerr(2, "prepare_krb5_rfc1964_buffer: serializing keys with "
3833 - "enctype %d and length %d\n",
3834 - lctx->rfc1964_kd.ctx_key.type,
3835 + printerr(2, "%s: serializing keys with enctype %d and length %d\n",
3836 + __FUNCTION__, lctx->rfc1964_kd.ctx_key.type,
3837 lctx->rfc1964_kd.ctx_key.length);
3839 /* derive the encryption key and copy it into buffer */
3840 @@ -158,11 +157,102 @@ out_err:
3844 +/* Flags for version 2 context flags */
3845 +#define KRB5_CTX_FLAG_INITIATOR 0x00000001
3846 +#define KRB5_CTX_FLAG_CFX 0x00000002
3847 +#define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004
3850 + * Prepare a new-style buffer, as defined in rfc4121 (a.k.a. cfx),
3851 + * to send to the kernel for newer encryption types -- or for DES3.
3853 + * The new format is:
3856 + * #define KRB5_CTX_FLAG_INITIATOR 0x00000001
3857 + * #define KRB5_CTX_FLAG_CFX 0x00000002
3858 + * #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004
3861 + * u32 enctype; ( encrption type of key )
3862 + * raw key; ( raw key bytes (kernel will derive))
3866 -prepare_krb5_rfc_cfx_buffer(gss_krb5_lucid_context_v1_t *lctx,
3867 +prepare_krb5_rfc4121_buffer(gss_krb5_lucid_context_v1_t *lctx,
3868 gss_buffer_desc *buf, int32_t *endtime)
3870 - printerr(0, "ERROR: prepare_krb5_rfc_cfx_buffer: not implemented\n");
3872 + uint32_t v2_flags = 0;
3876 + if (!(buf->value = calloc(1, MAX_CTX_LEN)))
3879 + end = buf->value + MAX_CTX_LEN;
3882 + if (lctx->initiate)
3883 + v2_flags |= KRB5_CTX_FLAG_INITIATOR;
3884 + if (lctx->protocol != 0)
3885 + v2_flags |= KRB5_CTX_FLAG_CFX;
3886 + if (lctx->protocol != 0 && lctx->cfx_kd.have_acceptor_subkey == 1)
3887 + v2_flags |= KRB5_CTX_FLAG_ACCEPTOR_SUBKEY;
3889 + if (WRITE_BYTES(&p, end, v2_flags)) goto out_err;
3890 + if (WRITE_BYTES(&p, end, lctx->endtime)) goto out_err;
3892 + *endtime = lctx->endtime;
3893 + if (WRITE_BYTES(&p, end, lctx->send_seq)) goto out_err;
3895 + /* Protocol 0 here implies DES3 or RC4 */
3896 + printerr(2, "%s: protocol %d\n", __FUNCTION__, lctx->protocol);
3897 + if (lctx->protocol == 0) {
3898 + enctype = lctx->rfc1964_kd.ctx_key.type;
3899 + keysize = lctx->rfc1964_kd.ctx_key.length;
3901 + if (lctx->cfx_kd.have_acceptor_subkey) {
3902 + enctype = lctx->cfx_kd.acceptor_subkey.type;
3903 + keysize = lctx->cfx_kd.acceptor_subkey.length;
3905 + enctype = lctx->cfx_kd.ctx_key.type;
3906 + keysize = lctx->cfx_kd.ctx_key.length;
3909 + printerr(2, "%s: serializing key with enctype %d and size %d\n",
3910 + __FUNCTION__, enctype, keysize);
3912 + if (WRITE_BYTES(&p, end, enctype)) goto out_err;
3914 + if (lctx->protocol == 0) {
3915 + if (write_bytes(&p, end, lctx->rfc1964_kd.ctx_key.data,
3916 + lctx->rfc1964_kd.ctx_key.length))
3919 + if (lctx->cfx_kd.have_acceptor_subkey) {
3920 + if (write_bytes(&p, end,
3921 + lctx->cfx_kd.acceptor_subkey.data,
3922 + lctx->cfx_kd.acceptor_subkey.length))
3925 + if (write_bytes(&p, end, lctx->cfx_kd.ctx_key.data,
3926 + lctx->cfx_kd.ctx_key.length))
3931 + buf->length = p - (char *)buf->value;
3935 + printerr(0, "ERROR: %s: failed serializing krb5 context for kernel\n",
3939 + buf->value = NULL;
3945 @@ -176,7 +266,7 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime)
3946 gss_krb5_lucid_context_v1_t *lctx = 0;
3949 - printerr(2, "DEBUG: serialize_krb5_ctx: lucid version!\n");
3950 + printerr(2, "DEBUG: %s: lucid version!\n", __FUNCTION__);
3951 maj_stat = gss_export_lucid_sec_context(&min_stat, &ctx,
3953 if (maj_stat != GSS_S_COMPLETE) {
3954 @@ -198,11 +288,20 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime)
3958 - /* Now lctx points to a lucid context that we can send down to kernel */
3959 - if (lctx->protocol == 0)
3961 + * Now lctx points to a lucid context that we can send down to kernel
3963 + * Note: we send down different information to the kernel depending
3964 + * on the protocol version and the enctyption type.
3965 + * For protocol version 0 with all enctypes besides DES3, we use
3966 + * the original format. For protocol version != 0 or DES3, we
3967 + * send down the new style information.
3970 + if (lctx->protocol == 0 && lctx->rfc1964_kd.ctx_key.type <= 4)
3971 retcode = prepare_krb5_rfc1964_buffer(lctx, buf, endtime);
3973 - retcode = prepare_krb5_rfc_cfx_buffer(lctx, buf, endtime);
3974 + retcode = prepare_krb5_rfc4121_buffer(lctx, buf, endtime);
3976 maj_stat = gss_free_lucid_sec_context(&min_stat, ctx, return_ctx);
3977 if (maj_stat != GSS_S_COMPLETE) {
3978 @@ -212,8 +311,8 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime)
3982 - printerr(1, "serialize_krb5_ctx: prepare_krb5_*_buffer "
3983 - "failed (retcode = %d)\n", retcode);
3984 + printerr(1, "%s: prepare_krb5_*_buffer failed (retcode = %d)\n",
3985 + __FUNCTION__, retcode);
3989 @@ -223,4 +322,7 @@ out_err:
3990 printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
3996 #endif /* HAVE_LUCID_CONTEXT_SUPPORT */
3997 diff --git a/utils/gssd/context_mit.c b/utils/gssd/context_mit.c
3998 index 709a903..e6db9cb 100644
3999 --- a/utils/gssd/context_mit.c
4000 +++ b/utils/gssd/context_mit.c
4003 - Copyright (c) 2004 The Regents of the University of Michigan.
4004 + Copyright (c) 2004-2006 The Regents of the University of Michigan.
4005 All rights reserved.
4007 Redistribution and use in source and binary forms, with or without
4013 #include <gssapi/gssapi.h>
4014 #include <rpc/rpc.h>
4015 #include <rpc/auth_gss.h>
4017 /* XXX argggg, there's gotta be a better way than just duplicating this
4018 * whole struct. Unfortunately, this is in a "private" header file,
4019 * so this is our best choice at this point :-/
4021 - * XXX Does this match the Heimdal definition? */
4024 typedef struct _krb5_gss_ctx_id_rec {
4025 unsigned int initiate : 1; /* nonzero if initiating, zero if accepting */
4026 @@ -156,50 +156,122 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime)
4028 krb5_gss_ctx_id_t kctx = ((gss_union_ctx_id_t)ctx)->internal_ctx_id;
4030 - static int constant_one = 1;
4031 static int constant_zero = 0;
4032 + static int constant_one = 1;
4033 + static int constant_two = 2;
4034 uint32_t word_seq_send;
4035 + u_int64_t seq_send_64bit;
4036 + uint32_t v2_flags = 0;
4038 if (!(buf->value = calloc(1, MAX_CTX_LEN)))
4041 end = buf->value + MAX_CTX_LEN;
4043 - if (kctx->initiate) {
4044 - if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
4047 - if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
4049 - if (kctx->seed_init) {
4050 - if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
4053 - if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
4055 - if (write_bytes(&p, end, &kctx->seed, sizeof(kctx->seed)))
4056 + switch (kctx->enc->enctype) {
4057 + case ENCTYPE_DES_CBC_CRC:
4058 + case ENCTYPE_DES_CBC_MD4:
4059 + case ENCTYPE_DES_CBC_MD5:
4060 + case ENCTYPE_DES_CBC_RAW:
4061 + /* Old format of context to the kernel */
4062 + if (kctx->initiate) {
4063 + if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
4066 + if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
4068 + if (kctx->seed_init) {
4069 + if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
4072 + if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
4074 + if (write_bytes(&p, end, &kctx->seed, sizeof(kctx->seed)))
4076 + if (WRITE_BYTES(&p, end, kctx->signalg)) goto out_err;
4077 + if (WRITE_BYTES(&p, end, kctx->sealalg)) goto out_err;
4078 + if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err;
4080 + *endtime = kctx->endtime;
4081 + word_seq_send = kctx->seq_send;
4082 + if (WRITE_BYTES(&p, end, word_seq_send)) goto out_err;
4083 + if (write_oid(&p, end, kctx->mech_used)) goto out_err;
4085 + printerr(2, "serialize_krb5_ctx: serializing keys with "
4086 + "enctype %d and length %d\n",
4087 + kctx->enc->enctype, kctx->enc->length);
4089 + if (write_keyblock(&p, end, kctx->enc)) goto out_err;
4090 + if (write_keyblock(&p, end, kctx->seq)) goto out_err;
4092 + case ENCTYPE_DES3_CBC_RAW:
4093 + case ENCTYPE_DES3_CBC_SHA1:
4094 + case ENCTYPE_ARCFOUR_HMAC:
4095 + case ENCTYPE_ARCFOUR_HMAC_EXP:
4096 + case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
4097 + case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
4098 + /* New format of context to the kernel */
4100 + * #define KRB5_CTX_FLAG_INITIATOR 0x00000001
4101 + * #define KRB5_CTX_FLAG_CFX 0x00000002
4102 + * #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004
4109 + if (kctx->initiate)
4110 + v2_flags |= KRB5_CTX_FLAG_INITIATOR;
4111 + if (kctx->proto == 1)
4112 + v2_flags |= KRB5_CTX_FLAG_CFX;
4113 + if (kctx->have_acceptor_subkey)
4114 + v2_flags |= KRB5_CTX_FLAG_ACCEPTOR_SUBKEY;
4115 + if (WRITE_BYTES(&p, end, v2_flags)) goto out_err;
4116 + if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err;
4118 + seq_send_64bit = kctx->seq_send;
4119 + if (WRITE_BYTES(&p, end, seq_send_64bit)) goto out_err;
4121 + if (kctx->have_acceptor_subkey) {
4122 + if (WRITE_BYTES(&p, end, kctx->acceptor_subkey->enctype))
4124 + printerr(2, "serialize_krb5_ctx: serializing subkey "
4125 + "with enctype %d and size %d\n",
4126 + kctx->acceptor_subkey->enctype,
4127 + kctx->acceptor_subkey->length);
4129 + if (write_bytes(&p, end,
4130 + kctx->acceptor_subkey->contents,
4131 + kctx->acceptor_subkey->length))
4134 + if (WRITE_BYTES(&p, end, kctx->enc->enctype))
4136 + printerr(2, "serialize_krb5_ctx: serializing key "
4137 + "with enctype %d and size %d\n",
4138 + kctx->enc->enctype, kctx->enc->length);
4140 + if (write_bytes(&p, end, kctx->enc->contents,
4141 + kctx->enc->length))
4146 + printerr(0, "ERROR: serialize_krb5_ctx: unsupported encryption "
4147 + "algorithm %d\n", kctx->enc->enctype);
4149 - if (WRITE_BYTES(&p, end, kctx->signalg)) goto out_err;
4150 - if (WRITE_BYTES(&p, end, kctx->sealalg)) goto out_err;
4151 - if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err;
4153 - *endtime = kctx->endtime;
4154 - word_seq_send = kctx->seq_send;
4155 - if (WRITE_BYTES(&p, end, word_seq_send)) goto out_err;
4156 - if (write_oid(&p, end, kctx->mech_used)) goto out_err;
4158 - printerr(2, "serialize_krb5_ctx: serializing keys with "
4159 - "enctype %d and length %d\n",
4160 - kctx->enc->enctype, kctx->enc->length);
4162 - if (write_keyblock(&p, end, kctx->enc)) goto out_err;
4163 - if (write_keyblock(&p, end, kctx->seq)) goto out_err;
4166 buf->length = p - (char *)buf->value;
4170 printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
4171 - if (buf->value) free(buf->value);
4175 + buf->value = NULL;
4179 diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c
4180 index bd37a5f..ccadb07 100644
4181 --- a/utils/gssd/gssd.c
4182 +++ b/utils/gssd/gssd.c
4183 @@ -78,7 +78,7 @@ void
4186 /* don't exit on SIGHUP */
4187 - printerr(1, "Received SIGHUP... Ignoring.\n");
4188 + printerr(1, "Received SIGHUP(%d)... Ignoring.\n", signal);
4192 diff --git a/utils/gssd/gssd_main_loop.c b/utils/gssd/gssd_main_loop.c
4193 index f1a68d3..b06c223 100644
4194 --- a/utils/gssd/gssd_main_loop.c
4195 +++ b/utils/gssd/gssd_main_loop.c
4196 @@ -63,6 +63,8 @@ static volatile int dir_changed = 1;
4198 static void dir_notify_handler(int sig, siginfo_t *si, void *data)
4200 + printerr(2, "dir_notify_handler: sig %d si %p data %p\n", sig, si, data);
4205 diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
4206 index be4fb11..c301d46 100644
4207 --- a/utils/gssd/gssd_proc.c
4208 +++ b/utils/gssd/gssd_proc.c
4209 @@ -600,6 +600,67 @@ update_client_list(void)
4213 +/* Encryption types supported by the kernel rpcsec_gss code */
4214 +int num_krb5_enctypes = 0;
4215 +krb5_enctype *krb5_enctypes = NULL;
4218 + * Parse the supported encryption type information
4221 +parse_enctypes(char *enctypes)
4224 + char *curr, *comma;
4226 + static char *cached_types;
4228 + if (cached_types && strcmp(cached_types, enctypes) == 0)
4230 + free(cached_types);
4232 + if (krb5_enctypes != NULL) {
4233 + free(krb5_enctypes);
4234 + krb5_enctypes = NULL;
4235 + num_krb5_enctypes = 0;
4238 + /* count the number of commas */
4239 + for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) {
4240 + comma = strchr(curr, ',');
4241 + if (comma != NULL)
4246 + /* If no more commas and we're not at the end, there's one more value */
4247 + if (*curr != '\0')
4250 + /* Empty string, return an error */
4254 + /* Allocate space for enctypes array */
4255 + if ((krb5_enctypes = (int *) calloc(n, sizeof(int))) == NULL) {
4259 + /* Now parse each value into the array */
4260 + for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) {
4261 + krb5_enctypes[i++] = atoi(curr);
4262 + comma = strchr(curr, ',');
4263 + if (comma == NULL)
4267 + num_krb5_enctypes = n;
4268 + if ((cached_types = malloc(strlen(enctypes)+1)))
4269 + strcpy(cached_types, enctypes);
4275 do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
4276 gss_buffer_desc *context_token)
4277 @@ -798,7 +859,7 @@ int create_auth_rpc_client(struct clnt_info *clp,
4278 * Do this before creating rpc connection since we won't need
4279 * rpc connection if it fails!
4281 - if (limit_krb5_enctypes(&sec, uid)) {
4282 + if (limit_krb5_enctypes(&sec)) {
4283 printerr(1, "WARNING: Failed while limiting krb5 "
4284 "encryption types for user with uid %d\n",
4286 @@ -875,7 +936,7 @@ int create_auth_rpc_client(struct clnt_info *clp,
4287 if (sec.cred != GSS_C_NO_CREDENTIAL)
4288 gss_release_cred(&min_stat, &sec.cred);
4289 /* Restore euid to original value */
4290 - if ((save_uid != -1) && (setfsuid(save_uid) != uid)) {
4291 + if (((int)save_uid != -1) && (setfsuid(save_uid) != (int)uid)) {
4292 printerr(0, "WARNING: Failed to restore fsuid"
4293 " to uid %d from %d\n", save_uid, uid);
4295 @@ -1100,7 +1161,7 @@ handle_krb5_upcall(struct clnt_info *clp)
4299 - if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) {
4300 + if (read(clp->krb5_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) {
4301 printerr(0, "WARNING: failed reading uid from krb5 "
4302 "upcall pipe: %s\n", strerror(errno));
4304 @@ -1114,7 +1175,7 @@ handle_spkm3_upcall(struct clnt_info *clp)
4308 - if (read(clp->spkm3_fd, &uid, sizeof(uid)) < sizeof(uid)) {
4309 + if (read(clp->spkm3_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) {
4310 printerr(0, "WARNING: failed reading uid from spkm3 "
4311 "upcall pipe: %s\n", strerror(errno));
4313 @@ -1133,6 +1194,7 @@ handle_gssd_upcall(struct clnt_info *clp)
4315 char *target = NULL;
4316 char *service = NULL;
4317 + char *enctypes = NULL;
4319 printerr(1, "handling gssd upcall (%s)\n", clp->dirname);
4321 @@ -1176,6 +1238,23 @@ handle_gssd_upcall(struct clnt_info *clp)
4325 + /* read supported encryption types if supplied */
4326 + if ((p = strstr(lbuf, "enctypes=")) != NULL) {
4327 + enctypes = malloc(lbuflen);
4330 + if (sscanf(p, "enctypes=%s", enctypes) != 1) {
4331 + printerr(0, "WARNING: handle_gssd_upcall: "
4332 + "failed to parse target name "
4333 + "in upcall string '%s'\n", lbuf);
4336 + if (parse_enctypes(enctypes) != 0) {
4337 + printerr(0, "WARNING: handle_gssd_upcall: "
4338 + "parsing encryption types failed: errno %d\n", errno);
4342 /* read target name */
4343 if ((p = strstr(lbuf, "target=")) != NULL) {
4344 target = malloc(lbuflen);
4345 @@ -1222,6 +1301,7 @@ handle_gssd_upcall(struct clnt_info *clp)
4353 diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c
4354 index 1295f57..f071600 100644
4355 --- a/utils/gssd/krb5_util.c
4356 +++ b/utils/gssd/krb5_util.c
4357 @@ -224,6 +224,13 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d)
4361 + if (uid == 0 && !root_uses_machine_creds &&
4362 + strstr(namelist[i]->d_name, "_machine_")) {
4363 + printerr(3, "CC file '%s' not available to root\n",
4365 + free(namelist[i]);
4368 if (!query_krb5_ccache(buf, &princname, &realm)) {
4369 printerr(3, "CC file '%s' is expired or corrupt\n",
4371 @@ -292,61 +299,6 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d)
4376 -#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
4378 - * this routine obtains a credentials handle via gss_acquire_cred()
4379 - * then calls gss_krb5_set_allowable_enctypes() to limit the encryption
4380 - * types negotiated.
4382 - * XXX Should call some function to determine the enctypes supported
4383 - * by the kernel. (Only need to do that once!)
4386 - * 0 => all went well
4387 - * -1 => there was an error
4391 -limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid)
4393 - u_int maj_stat, min_stat;
4394 - gss_cred_id_t credh;
4395 - gss_OID_set_desc desired_mechs;
4396 - krb5_enctype enctypes[] = { ENCTYPE_DES_CBC_CRC,
4397 - ENCTYPE_DES_CBC_MD5,
4398 - ENCTYPE_DES_CBC_MD4 };
4399 - int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]);
4401 - /* We only care about getting a krb5 cred */
4402 - desired_mechs.count = 1;
4403 - desired_mechs.elements = &krb5oid;
4405 - maj_stat = gss_acquire_cred(&min_stat, NULL, 0,
4406 - &desired_mechs, GSS_C_INITIATE,
4407 - &credh, NULL, NULL);
4409 - if (maj_stat != GSS_S_COMPLETE) {
4410 - if (get_verbosity() > 0)
4411 - pgsserr("gss_acquire_cred",
4412 - maj_stat, min_stat, &krb5oid);
4416 - maj_stat = gss_set_allowable_enctypes(&min_stat, credh, &krb5oid,
4417 - num_enctypes, &enctypes);
4418 - if (maj_stat != GSS_S_COMPLETE) {
4419 - pgsserr("gss_set_allowable_enctypes",
4420 - maj_stat, min_stat, &krb5oid);
4421 - gss_release_cred(&min_stat, &credh);
4424 - sec->cred = credh;
4428 -#endif /* HAVE_SET_ALLOWABLE_ENCTYPES */
4431 * Obtain credentials via a key in the keytab given
4432 * a keytab handle and a gssd_k5_kt_princ structure.
4433 @@ -661,24 +613,32 @@ out:
4434 * and has *any* instance (hostname), return 1.
4435 * Otherwise return 0, indicating no match.
4439 -realm_and_service_match(krb5_context context, krb5_principal p,
4440 - const char *realm, const char *service)
4441 +realm_and_service_match(krb5_principal p, const char *realm, const char *service)
4444 /* Must have two components */
4448 if ((strlen(realm) == p->realm.length)
4449 && (strncmp(realm, p->realm.data, p->realm.length) == 0)
4450 && (strlen(service) == p->data[0].length)
4451 && (strncmp(service, p->data[0].data, p->data[0].length) == 0))
4458 +realm_and_service_match(krb5_context context, krb5_principal p,
4459 + const char *realm, const char *service)
4461 const char *name, *inst;
4463 if (p->name.name_string.len != 2)
4466 name = krb5_principal_get_comp_string(context, p, 0);
4467 inst = krb5_principal_get_comp_string(context, p, 1);
4468 if (name == NULL || inst == NULL)
4469 @@ -686,9 +646,10 @@ realm_and_service_match(krb5_context context, krb5_principal p,
4470 if ((strcmp(realm, p->realm) == 0)
4471 && (strcmp(service, name) == 0))
4480 * Search the given keytab file looking for an entry with the given
4481 @@ -710,7 +671,7 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt,
4482 krb5_kt_cursor cursor;
4483 krb5_error_code code;
4484 struct gssd_k5_kt_princ *ple;
4486 + int retval = -1, status;
4487 char kt_name[BUFSIZ];
4490 @@ -753,8 +714,12 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt,
4491 printerr(4, "Processing keytab entry for principal '%s'\n",
4493 /* Use the first matching keytab entry found */
4494 - if ((realm_and_service_match(context, kte->principal, realm,
4497 + status = realm_and_service_match(kte->principal, realm, service);
4499 + status = realm_and_service_match(context, kte->principal, realm, service);
4502 printerr(4, "We WILL use this entry (%s)\n", pname);
4503 ple = get_ple_by_princ(context, kte->principal);
4505 @@ -1304,3 +1269,68 @@ gssd_k5_get_default_realm(char **def_realm)
4507 krb5_free_context(context);
4510 +#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
4512 + * this routine obtains a credentials handle via gss_acquire_cred()
4513 + * then calls gss_krb5_set_allowable_enctypes() to limit the encryption
4514 + * types negotiated.
4516 + * XXX Should call some function to determine the enctypes supported
4517 + * by the kernel. (Only need to do that once!)
4520 + * 0 => all went well
4521 + * -1 => there was an error
4525 +limit_krb5_enctypes(struct rpc_gss_sec *sec)
4527 + u_int maj_stat, min_stat;
4528 + gss_cred_id_t credh;
4529 + gss_OID_set_desc desired_mechs;
4530 + krb5_enctype enctypes[] = { ENCTYPE_DES_CBC_CRC,
4531 + ENCTYPE_DES_CBC_MD5,
4532 + ENCTYPE_DES_CBC_MD4 };
4533 + int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]);
4534 + extern int num_krb5_enctypes;
4535 + extern krb5_enctype *krb5_enctypes;
4537 + /* We only care about getting a krb5 cred */
4538 + desired_mechs.count = 1;
4539 + desired_mechs.elements = &krb5oid;
4541 + maj_stat = gss_acquire_cred(&min_stat, NULL, 0,
4542 + &desired_mechs, GSS_C_INITIATE,
4543 + &credh, NULL, NULL);
4545 + if (maj_stat != GSS_S_COMPLETE) {
4546 + if (get_verbosity() > 0)
4547 + pgsserr("gss_acquire_cred",
4548 + maj_stat, min_stat, &krb5oid);
4553 + * If we failed for any reason to produce global
4554 + * list of supported enctypes, use local default here.
4556 + if (krb5_enctypes == NULL)
4557 + maj_stat = gss_set_allowable_enctypes(&min_stat, credh,
4558 + &krb5oid, num_enctypes, enctypes);
4560 + maj_stat = gss_set_allowable_enctypes(&min_stat, credh,
4561 + &krb5oid, num_krb5_enctypes, krb5_enctypes);
4563 + if (maj_stat != GSS_S_COMPLETE) {
4564 + pgsserr("gss_set_allowable_enctypes",
4565 + maj_stat, min_stat, &krb5oid);
4566 + gss_release_cred(&min_stat, &credh);
4569 + sec->cred = credh;
4573 +#endif /* HAVE_SET_ALLOWABLE_ENCTYPES */
4574 diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h
4575 index 4602cc3..b42b91e 100644
4576 --- a/utils/gssd/krb5_util.h
4577 +++ b/utils/gssd/krb5_util.h
4578 @@ -36,7 +36,7 @@ char *gssd_k5_err_msg(krb5_context context, krb5_error_code code);
4579 void gssd_k5_get_default_realm(char **def_realm);
4581 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
4582 -int limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid);
4583 +int limit_krb5_enctypes(struct rpc_gss_sec *sec);
4587 diff --git a/utils/gssd/svcgssd.c b/utils/gssd/svcgssd.c
4588 index 729b6a6..e7375a4 100644
4589 --- a/utils/gssd/svcgssd.c
4590 +++ b/utils/gssd/svcgssd.c
4591 @@ -160,7 +160,7 @@ void
4594 /* don't exit on SIGHUP */
4595 - printerr(1, "Received SIGHUP... Ignoring.\n");
4596 + printerr(1, "Received SIGHUP(%d)... Ignoring.\n", signal);
4600 diff --git a/utils/gssd/svcgssd_proc.c b/utils/gssd/svcgssd_proc.c
4601 index f1bfbef..3894078 100644
4602 --- a/utils/gssd/svcgssd_proc.c
4603 +++ b/utils/gssd/svcgssd_proc.c
4604 @@ -132,7 +132,7 @@ struct gss_verifier {
4605 #define RPCSEC_GSS_SEQ_WIN 5
4608 -send_response(FILE *f, gss_buffer_desc *in_handle, gss_buffer_desc *in_token,
4609 +send_response(gss_buffer_desc *in_handle, gss_buffer_desc *in_token,
4610 u_int32_t maj_stat, u_int32_t min_stat,
4611 gss_buffer_desc *out_handle, gss_buffer_desc *out_token)
4613 @@ -431,12 +431,6 @@ handle_nullreq(FILE *f) {
4614 print_hexl("in_tok", in_tok.value, in_tok.length);
4617 - if (in_tok.length < 0) {
4618 - printerr(0, "WARNING: handle_nullreq: "
4619 - "failed parsing request\n");
4623 if (in_handle.length != 0) { /* CONTINUE_INIT case */
4624 if (in_handle.length != sizeof(ctx)) {
4625 printerr(0, "WARNING: handle_nullreq: "
4626 @@ -498,7 +492,7 @@ handle_nullreq(FILE *f) {
4627 do_svc_downcall(&out_handle, &cred, mech, &ctx_token, ctx_endtime,
4630 - send_response(f, &in_handle, &in_tok, maj_stat, min_stat,
4631 + send_response(&in_handle, &in_tok, maj_stat, min_stat,
4632 &out_handle, &out_tok);
4634 if (ctx_token.value != NULL)
4635 @@ -514,7 +508,7 @@ out:
4637 if (ctx != GSS_C_NO_CONTEXT)
4638 gss_delete_sec_context(&ignore_min_stat, &ctx, &ignore_out_tok);
4639 - send_response(f, &in_handle, &in_tok, maj_stat, min_stat,
4640 + send_response(&in_handle, &in_tok, maj_stat, min_stat,
4641 &null_token, &null_token);
4644 diff --git a/utils/idmapd/atomicio.c b/utils/idmapd/atomicio.c
4645 index 05e7147..1fb1ff9 100644
4646 --- a/utils/idmapd/atomicio.c
4647 +++ b/utils/idmapd/atomicio.c
4648 @@ -43,7 +43,8 @@ atomicio(
4652 - ssize_t res, pos = 0;
4657 res = (f) (fd, s + pos, n - pos);
4658 diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c
4659 index 573abaa..9ecab66 100644
4660 --- a/utils/idmapd/idmapd.c
4661 +++ b/utils/idmapd/idmapd.c
4662 @@ -117,8 +117,24 @@ struct idmap_client {
4663 TAILQ_ENTRY(idmap_client) ic_next;
4665 static struct idmap_client nfsd_ic[2] = {
4666 -{IC_IDNAME, "Server", "", IC_IDNAME_CHAN, -1, -1, 0},
4667 -{IC_NAMEID, "Server", "", IC_NAMEID_CHAN, -1, -1, 0},
4669 + .ic_which = IC_IDNAME,
4670 + .ic_clid = "Server",
4672 + .ic_path = IC_IDNAME_CHAN,
4678 + .ic_which = IC_NAMEID,
4679 + .ic_clid = "Server",
4681 + .ic_path = IC_NAMEID_CHAN,
4688 TAILQ_HEAD(idmap_clientq, idmap_client);
4689 @@ -170,7 +186,7 @@ flush_nfsd_cache(char *path, time_t now)
4690 fd = open(path, O_RDWR);
4693 - if (write(fd, stime, strlen(stime)) != strlen(stime)) {
4694 + if (write(fd, stime, strlen(stime)) != (ssize_t)strlen(stime)) {
4695 errx(1, "Flushing nfsd cache failed: errno %d (%s)",
4696 errno, strerror(errno));
4698 @@ -381,7 +397,7 @@ main(int argc, char **argv)
4702 -dirscancb(int fd, short which, void *data)
4703 +dirscancb(int UNUSED(fd), short UNUSED(which), void *data)
4706 struct dirent **ents;
4707 @@ -465,13 +481,13 @@ out:
4711 -svrreopen(int fd, short which, void *data)
4712 +svrreopen(int UNUSED(fd), short UNUSED(which), void *UNUSED(data))
4718 -clntscancb(int fd, short which, void *data)
4719 +clntscancb(int UNUSED(fd), short UNUSED(which), void *data)
4721 struct idmap_clientq *icq = data;
4722 struct idmap_client *ic;
4723 @@ -485,7 +501,7 @@ clntscancb(int fd, short which, void *data)
4727 -nfsdcb(int fd, short which, void *data)
4728 +nfsdcb(int UNUSED(fd), short which, void *data)
4730 struct idmap_client *ic = data;
4731 struct idmap_msg im;
4732 @@ -660,7 +676,7 @@ imconv(struct idmap_client *ic, struct idmap_msg *im)
4736 -nfscb(int fd, short which, void *data)
4737 +nfscb(int UNUSED(fd), short which, void *data)
4739 struct idmap_client *ic = data;
4740 struct idmap_msg im;
4741 @@ -845,7 +861,7 @@ nametoidres(struct idmap_msg *im)
4743 validateascii(char *string, u_int32_t len)
4748 for (i = 0; i < len; i++) {
4749 if (string[i] == '\0')
4750 @@ -901,7 +917,7 @@ static int
4751 getfield(char **bpp, char *fld, size_t fldsz)
4757 while ((bp = strsep(bpp, " ")) != NULL && bp[0] == '\0')
4759 diff --git a/utils/mount/configfile.c b/utils/mount/configfile.c
4760 index 5cff009..6f2ee75 100644
4761 --- a/utils/mount/configfile.c
4762 +++ b/utils/mount/configfile.c
4763 @@ -192,7 +192,8 @@ void free_all(void)
4766 static char *versions[] = {"v2", "v3", "v4", "vers", "nfsvers", NULL};
4767 -int inline check_vers(char *mopt, char *field)
4769 +check_vers(char *mopt, char *field)
4773 @@ -229,7 +230,8 @@ extern sa_family_t config_default_family;
4774 * If so, set the appropriate global value which will
4775 * be used as the initial value in the server negation.
4777 -int inline default_value(char *mopt)
4779 +default_value(char *mopt)
4781 struct mount_options *options = NULL;
4782 int dftlen = strlen("default");
4783 diff --git a/utils/mount/network.c b/utils/mount/network.c
4784 index 8dc183a..d6b5205 100644
4785 --- a/utils/mount/network.c
4786 +++ b/utils/mount/network.c
4788 #include "parse_opt.h"
4789 #include "network.h"
4790 #include "conffile.h"
4791 +#include "nfslib.h"
4793 #define PMAP_TIMEOUT (10)
4794 #define CONNECT_TIMEOUT (20)
4795 @@ -857,7 +858,14 @@ int nfs_advise_umount(const struct sockaddr *sap, const socklen_t salen,
4799 - client->cl_auth = authunix_create_default();
4800 + client->cl_auth = nfs_authsys_create();
4801 + if (client->cl_auth == NULL) {
4803 + nfs_error(_("%s: Failed to create RPC auth handle"),
4805 + CLNT_DESTROY(client);
4809 res = CLNT_CALL(client, MOUNTPROC_UMNT,
4810 (xdrproc_t)xdr_dirpath, (caddr_t)argp,
4811 @@ -957,8 +965,10 @@ CLIENT *mnt_openclnt(clnt_addr_t *mnt_server, int *msock)
4814 /* try to mount hostname:dirname */
4815 - clnt->cl_auth = authunix_create_default();
4817 + clnt->cl_auth = nfs_authsys_create();
4818 + if (clnt->cl_auth)
4820 + CLNT_DESTROY(clnt);
4824 @@ -1203,6 +1213,8 @@ nfs_nfs_program(struct mount_options *options, unsigned long *program)
4828 + nfs_error(_("%s: invalid value for 'nfsprog=' option"),
4833 @@ -1242,9 +1254,12 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version)
4837 - nfs_error(_("%s: option parsing error\n"),
4838 + nfs_error(_("%s: parsing error on 'vers=' option\n"),
4842 + nfs_error(_("%s: invalid value for 'vers=' option"),
4846 case 4: /* nfsvers */
4847 @@ -1256,9 +1271,12 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version)
4851 - nfs_error(_("%s: option parsing error\n"),
4852 + nfs_error(_("%s: parsing error on 'nfsvers=' option\n"),
4856 + nfs_error(_("%s: invalid value for 'nfsvers=' option"),
4861 @@ -1294,6 +1312,8 @@ nfs_nfs_protocol(struct mount_options *options, unsigned long *protocol)
4862 if (option != NULL) {
4863 if (!nfs_get_proto(option, &family, protocol)) {
4864 errno = EPROTONOSUPPORT;
4865 + nfs_error(_("%s: Failed to find '%s' protocol"),
4866 + progname, option);
4870 @@ -1327,6 +1347,8 @@ nfs_nfs_port(struct mount_options *options, unsigned long *port)
4874 + nfs_error(_("%s: invalid value for 'port=' option"),
4879 @@ -1342,7 +1364,7 @@ nfs_nfs_port(struct mount_options *options, unsigned long *port)
4880 sa_family_t config_default_family = AF_UNSPEC;
4883 -nfs_verify_family(sa_family_t family)
4884 +nfs_verify_family(sa_family_t UNUSED(family))
4888 @@ -1380,8 +1402,13 @@ int nfs_nfs_proto_family(struct mount_options *options,
4890 option = po_get(options, "proto");
4891 if (option != NULL &&
4892 - !nfs_get_proto(option, &tmp_family, &protocol))
4894 + !nfs_get_proto(option, &tmp_family, &protocol)) {
4896 + nfs_error(_("%s: Failed to find '%s' protocol"),
4897 + progname, option);
4898 + errno = EPROTONOSUPPORT;
4903 if (!nfs_verify_family(tmp_family))
4904 @@ -1414,6 +1441,8 @@ nfs_mount_program(struct mount_options *options, unsigned long *program)
4908 + nfs_error(_("%s: invalid value for 'mountprog=' option"),
4913 @@ -1443,6 +1472,8 @@ nfs_mount_version(struct mount_options *options, unsigned long *version)
4917 + nfs_error(_("%s: invalid value for 'mountvers=' option"),
4922 @@ -1469,6 +1500,8 @@ nfs_mount_protocol(struct mount_options *options, unsigned long *protocol)
4923 if (option != NULL) {
4924 if (!nfs_get_proto(option, &family, protocol)) {
4925 errno = EPROTONOSUPPORT;
4926 + nfs_error(_("%s: Failed to find '%s' protocol"),
4927 + progname, option);
4931 @@ -1501,6 +1534,8 @@ nfs_mount_port(struct mount_options *options, unsigned long *port)
4935 + nfs_error(_("%s: invalid value for 'mountport=' option"),
4940 @@ -1526,8 +1561,12 @@ int nfs_mount_proto_family(struct mount_options *options,
4942 option = po_get(options, "mountproto");
4943 if (option != NULL) {
4944 - if (!nfs_get_proto(option, &tmp_family, &protocol))
4945 + if (!nfs_get_proto(option, &tmp_family, &protocol)) {
4946 + nfs_error(_("%s: Failed to find '%s' protocol"),
4947 + progname, option);
4948 + errno = EPROTONOSUPPORT;
4951 if (!nfs_verify_family(tmp_family))
4953 *family = tmp_family;
4954 diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man
4955 index c64de5f..3806635 100644
4956 --- a/utils/mount/nfs.man
4957 +++ b/utils/mount/nfs.man
4958 @@ -623,14 +623,9 @@ in such cases.
4961 The NFS protocol version number used to contact the server's NFS service.
4962 -The Linux client supports version 2 and version 3 of the NFS protocol
4963 -when using the file system type
4965 -If the server does not support the requested version,
4966 -the mount request fails.
4967 -If this option is not specified, the client attempts to use version 3,
4968 -but negotiates the NFS version with the server if version 3 support
4970 +If the server does not support the requested version, the mount request fails.
4971 +If this option is not specified, the client negociate a suitable version with
4972 +the server, trying version 4 first, version 3 second, and version 2 last.
4975 This option is an alternative to the
4976 diff --git a/utils/mount/nfs4mount.c b/utils/mount/nfs4mount.c
4977 index 4a2fab7..028e7cd 100644
4978 --- a/utils/mount/nfs4mount.c
4979 +++ b/utils/mount/nfs4mount.c
4980 @@ -146,7 +146,7 @@ static int fill_ipv4_sockaddr(const char *hostname, struct sockaddr_in *addr)
4981 progname, hostname);
4984 - if (hp->h_length > sizeof(struct in_addr)) {
4985 + if (hp->h_length > (int)sizeof(struct in_addr)) {
4986 nfs_error(_("%s: got bad hp->h_length"), progname);
4987 hp->h_length = sizeof(struct in_addr);
4989 diff --git a/utils/mount/nfsmount.c b/utils/mount/nfsmount.c
4990 index 6b3356c..5b934b5 100644
4991 --- a/utils/mount/nfsmount.c
4992 +++ b/utils/mount/nfsmount.c
4993 @@ -510,8 +510,12 @@ nfsmount(const char *spec, const char *node, int flags,
4995 static int doonce = 0;
4997 - clnt_addr_t mnt_server = { &mounthost, };
4998 - clnt_addr_t nfs_server = { &hostname, };
4999 + clnt_addr_t mnt_server = {
5000 + .hostname = &mounthost
5002 + clnt_addr_t nfs_server = {
5003 + .hostname = &hostname
5005 struct sockaddr_in *nfs_saddr = &nfs_server.saddr;
5006 struct pmap *mnt_pmap = &mnt_server.pmap,
5007 *nfs_pmap = &nfs_server.pmap;
5008 diff --git a/utils/mount/nfsumount.c b/utils/mount/nfsumount.c
5009 index 9d798a2..1514340 100644
5010 --- a/utils/mount/nfsumount.c
5011 +++ b/utils/mount/nfsumount.c
5012 @@ -179,10 +179,8 @@ static int nfs_umount_do_umnt(struct mount_options *options,
5013 struct pmap nfs_pmap, mnt_pmap;
5016 - if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap)) {
5017 - nfs_error(_("%s: bad mount options"), progname);
5018 + if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap))
5022 /* Skip UMNT call for vers=4 mounts */
5023 if (nfs_pmap.pm_vers == 4)
5024 diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
5025 index 9b8c38f..0241400 100644
5026 --- a/utils/mount/stropts.c
5027 +++ b/utils/mount/stropts.c
5028 @@ -538,7 +538,10 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options)
5030 if (!nfs_construct_new_options(options, nfs_saddr, &nfs_pmap,
5031 mnt_saddr, &mnt_pmap)) {
5033 + if (rpc_createerr.cf_stat == RPC_UNKNOWNPROTO)
5034 + errno = EPROTONOSUPPORT;
5040 @@ -586,18 +589,21 @@ static int nfs_do_mount_v3v2(struct nfsmount_info *mi,
5046 if (!nfs_append_addr_option(sap, salen, options)) {
5053 if (!nfs_fix_mounthost_option(options, mi->hostname)) {
5059 if (!mi->fake && !nfs_verify_lock_option(options)) {
5066 @@ -799,6 +805,7 @@ static int nfs_is_permanent_error(int error)
5070 + case EHOSTUNREACH:
5071 return 0; /* temporary */
5073 return 1; /* permanent */
5074 diff --git a/utils/mountd/auth.c b/utils/mountd/auth.c
5075 index 13eba70..ccc849a 100644
5076 --- a/utils/mountd/auth.c
5077 +++ b/utils/mountd/auth.c
5079 #include <arpa/inet.h>
5083 +#include "sockaddr.h"
5086 #include "exportfs.h"
5087 @@ -110,13 +112,16 @@ auth_reload()
5091 -static char *get_client_hostname(struct sockaddr_in *caller, struct hostent *hp, enum auth_error *error)
5093 +get_client_hostname(const struct sockaddr *caller, struct addrinfo *ai,
5094 + enum auth_error *error)
5096 + char buf[INET6_ADDRSTRLEN];
5100 - return strdup(inet_ntoa(caller->sin_addr));
5101 - n = client_compose(hp);
5102 + return strdup(host_ntop(caller, buf, sizeof(buf)));
5103 + n = client_compose(ai);
5104 *error = unknown_host;
5107 @@ -128,8 +133,8 @@ static char *get_client_hostname(struct sockaddr_in *caller, struct hostent *hp,
5109 /* return static nfs_export with details filled in */
5111 -auth_authenticate_newcache(char *what, struct sockaddr_in *caller,
5112 - char *path, struct hostent *hp,
5113 +auth_authenticate_newcache(const struct sockaddr *caller,
5114 + const char *path, struct addrinfo *ai,
5115 enum auth_error *error)
5118 @@ -137,12 +142,12 @@ auth_authenticate_newcache(char *what, struct sockaddr_in *caller,
5120 free(my_client.m_hostname);
5122 - my_client.m_hostname = get_client_hostname(caller, hp, error);
5123 + my_client.m_hostname = get_client_hostname(caller, ai, error);
5124 if (my_client.m_hostname == NULL)
5127 my_client.m_naddr = 1;
5128 - my_client.m_addrlist[0] = caller->sin_addr;
5129 + set_addrlist(&my_client, 0, caller);
5130 my_exp.m_client = &my_client;
5133 @@ -152,7 +157,7 @@ auth_authenticate_newcache(char *what, struct sockaddr_in *caller,
5135 if (!use_ipaddr && !client_member(my_client.m_hostname, exp->m_client->m_hostname))
5137 - if (use_ipaddr && !client_check(exp->m_client, hp))
5138 + if (use_ipaddr && !client_check(exp->m_client, ai))
5142 @@ -166,18 +171,18 @@ auth_authenticate_newcache(char *what, struct sockaddr_in *caller,
5146 -auth_authenticate_internal(char *what, struct sockaddr_in *caller,
5147 - char *path, struct hostent *hp,
5148 - enum auth_error *error)
5149 +auth_authenticate_internal(const struct sockaddr *caller, const char *path,
5150 + struct addrinfo *ai, enum auth_error *error)
5155 - exp = auth_authenticate_newcache(what, caller, path, hp, error);
5156 + exp = auth_authenticate_newcache(caller, path, ai, error);
5160 - if (!(exp = export_find(hp, path))) {
5161 + exp = export_find(ai, path);
5162 + if (exp == NULL) {
5166 @@ -187,7 +192,7 @@ auth_authenticate_internal(char *what, struct sockaddr_in *caller,
5169 if (!(exp->m_export.e_flags & NFSEXP_INSECURE_PORT) &&
5170 - ntohs(caller->sin_port) >= IPPORT_RESERVED) {
5171 + nfs_get_port(caller) >= IPPORT_RESERVED) {
5172 *error = illegal_port;
5175 @@ -197,18 +202,19 @@ auth_authenticate_internal(char *what, struct sockaddr_in *caller,
5179 -auth_authenticate(char *what, struct sockaddr_in *caller, char *path)
5180 +auth_authenticate(const char *what, const struct sockaddr *caller,
5183 nfs_export *exp = NULL;
5184 char epath[MAXPATHLEN+1];
5186 - struct hostent *hp = NULL;
5187 - struct in_addr addr = caller->sin_addr;
5188 + char buf[INET6_ADDRSTRLEN];
5189 + struct addrinfo *ai = NULL;
5190 enum auth_error error = bad_path;
5192 - if (path [0] != '/') {
5193 - xlog(L_WARNING, "bad path in %s request from %s: \"%s\"",
5194 - what, inet_ntoa(addr), path);
5195 + if (path[0] != '/') {
5196 + xlog(L_WARNING, "Bad path in %s request from %s: \"%s\"",
5197 + what, host_ntop(caller, buf, sizeof(buf)), path);
5201 @@ -216,14 +222,13 @@ auth_authenticate(char *what, struct sockaddr_in *caller, char *path)
5202 epath[sizeof (epath) - 1] = '\0';
5203 auth_fixpath(epath); /* strip duplicate '/' etc */
5205 - hp = client_resolve(caller->sin_addr);
5207 + ai = client_resolve(caller);
5211 /* Try the longest matching exported pathname. */
5213 - exp = auth_authenticate_internal(what, caller, epath,
5215 + exp = auth_authenticate_internal(caller, epath, ai, &error);
5216 if (exp || (error != not_exported && error != no_entry))
5218 /* We have to treat the root, "/", specially. */
5219 @@ -236,41 +241,40 @@ auth_authenticate(char *what, struct sockaddr_in *caller, char *path)
5222 xlog(L_WARNING, "bad path in %s request from %s: \"%s\"",
5223 - what, inet_ntoa(addr), path);
5224 + what, host_ntop(caller, buf, sizeof(buf)), path);
5228 xlog(L_WARNING, "refused %s request from %s for %s (%s): unmatched host",
5229 - what, inet_ntoa(addr), path, epath);
5230 + what, host_ntop(caller, buf, sizeof(buf)), path, epath);
5234 xlog(L_WARNING, "refused %s request from %s for %s (%s): no export entry",
5235 - what, hp->h_name, path, epath);
5236 + what, ai->ai_canonname, path, epath);
5240 xlog(L_WARNING, "refused %s request from %s for %s (%s): not exported",
5241 - what, hp->h_name, path, epath);
5242 + what, ai->ai_canonname, path, epath);
5246 - xlog(L_WARNING, "refused %s request from %s for %s (%s): illegal port %d",
5247 - what, hp->h_name, path, epath, ntohs(caller->sin_port));
5248 + xlog(L_WARNING, "refused %s request from %s for %s (%s): illegal port %u",
5249 + what, ai->ai_canonname, path, epath, nfs_get_port(caller));
5253 - xlog(L_NOTICE, "authenticated %s request from %s:%d for %s (%s)",
5254 - what, hp->h_name, ntohs(caller->sin_port), path, epath);
5255 + xlog(L_NOTICE, "authenticated %s request from %s:%u for %s (%s)",
5256 + what, ai->ai_canonname, nfs_get_port(caller), path, epath);
5259 - xlog(L_NOTICE, "%s request from %s:%d for %s (%s) gave %d",
5260 - what, hp->h_name, ntohs(caller->sin_port), path, epath, error);
5261 + xlog(L_NOTICE, "%s request from %s:%u for %s (%s) gave %d",
5262 + what, ai->ai_canonname, nfs_get_port(caller),
5263 + path, epath, error);
5273 diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c
5274 index d63e10a..f70f4d6 100644
5275 --- a/utils/mountd/cache.c
5276 +++ b/utils/mountd/cache.c
5278 #include "blkid/blkid.h"
5282 + * Invoked by RPC service loop
5284 +void cache_set_fds(fd_set *fdset);
5285 +int cache_process_req(fd_set *readfds);
5289 @@ -57,14 +62,14 @@ enum nfsd_fsid {
5290 * Record is terminated with newline.
5293 -int cache_export_ent(char *domain, struct exportent *exp, char *p);
5294 +static int cache_export_ent(char *domain, struct exportent *exp, char *p);
5299 extern int use_ipaddr;
5301 -void auth_unix_ip(FILE *f)
5302 +static void auth_unix_ip(FILE *f)
5306 @@ -75,10 +80,10 @@ void auth_unix_ip(FILE *f)
5311 + char ipaddr[INET6_ADDRSTRLEN];
5312 char *client = NULL;
5313 - struct in_addr addr;
5314 - struct hostent *he = NULL;
5315 + struct addrinfo *tmp = NULL;
5316 + struct addrinfo *ai = NULL;
5317 if (readline(fileno(f), &lbuf, &lbuflen) != 1)
5320 @@ -90,20 +95,23 @@ void auth_unix_ip(FILE *f)
5321 strcmp(class, "nfsd") != 0)
5324 - if (qword_get(&cp, ipaddr, 20) <= 0)
5325 + if (qword_get(&cp, ipaddr, sizeof(ipaddr)) <= 0)
5328 - if (inet_aton(ipaddr, &addr)==0)
5329 + tmp = host_pton(ipaddr);
5335 /* addr is a valid, interesting address, find the domain name... */
5337 - he = client_resolve(addr);
5338 - client = client_compose(he);
5339 + ai = client_resolve(tmp->ai_addr);
5340 + client = client_compose(ai);
5344 + freeaddrinfo(tmp);
5346 qword_print(f, "nfsd");
5347 qword_print(f, ipaddr);
5348 qword_printint(f, time(0)+30*60);
5349 @@ -114,18 +122,17 @@ void auth_unix_ip(FILE *f)
5351 xlog(D_CALL, "auth_unix_ip: client %p '%s'", client, client?client: "DEFAULT");
5353 - if (client) free(client);
5358 -void auth_unix_gid(FILE *f)
5359 +static void auth_unix_gid(FILE *f)
5364 * uid expiry count list of group ids
5369 gid_t glist[100], *groups = glist;
5371 @@ -136,7 +143,7 @@ void auth_unix_gid(FILE *f)
5375 - if (qword_get_int(&cp, &uid) != 0)
5376 + if (qword_get_uint(&cp, &uid) != 0)
5380 @@ -153,14 +160,14 @@ void auth_unix_gid(FILE *f)
5384 - qword_printint(f, uid);
5385 - qword_printint(f, time(0)+30*60);
5386 + qword_printuint(f, uid);
5387 + qword_printuint(f, time(0)+30*60);
5389 - qword_printint(f, ngroups);
5390 + qword_printuint(f, ngroups);
5391 for (i=0; i<ngroups; i++)
5392 - qword_printint(f, groups[i]);
5393 + qword_printuint(f, groups[i]);
5395 - qword_printint(f, 0);
5396 + qword_printuint(f, 0);
5399 if (groups != glist)
5400 @@ -170,13 +177,16 @@ void auth_unix_gid(FILE *f)
5402 static const char *get_uuid_blkdev(char *path)
5404 + /* We set *safe if we know that we need the
5405 + * fsid from statfs too.
5407 static blkid_cache cache = NULL;
5410 blkid_tag_iterate iter;
5413 - const char *val = NULL;
5414 + const char *val, *uuid = NULL;
5417 blkid_get_cache(&cache, NULL);
5418 @@ -193,42 +203,29 @@ static const char *get_uuid_blkdev(char *path)
5419 iter = blkid_tag_iterate_begin(dev);
5422 - while (blkid_tag_next(iter, &type, &val) == 0)
5423 + while (blkid_tag_next(iter, &type, &val) == 0) {
5424 if (strcmp(type, "UUID") == 0)
5426 + if (strcmp(type, "TYPE") == 0 &&
5427 + strcmp(val, "btrfs") == 0) {
5432 blkid_tag_iterate_end(iter);
5437 #define get_uuid_blkdev(path) (NULL)
5440 -int get_uuid(char *path, char *uuid, int uuidlen, char *u)
5441 +static int get_uuid(const char *val, int uuidlen, char *u)
5443 /* extract hex digits from uuidstr and compose a uuid
5444 * of the given length (max 16), xoring bytes to make
5445 - * a smaller uuid. Then compare with uuid
5449 - const char *val = NULL;
5450 - char fsid_val[17];
5453 - val = get_uuid_blkdev(path);
5455 - struct statfs64 st;
5457 - if (statfs64(path, &st))
5459 - if (!st.f_fsid.__val[0] && !st.f_fsid.__val[1])
5461 - snprintf(fsid_val, 17, "%08x%08x",
5462 - st.f_fsid.__val[0], st.f_fsid.__val[1]);
5469 memset(u, 0, uuidlen);
5470 for ( ; *val ; val++) {
5471 @@ -252,6 +249,60 @@ int get_uuid(char *path, char *uuid, int uuidlen, char *u)
5475 +static int uuid_by_path(char *path, int type, int uuidlen, char *uuid)
5477 + /* get a uuid for the filesystem found at 'path'.
5478 + * There are several possible ways of generating the
5480 + * Type 0 is used for new filehandles, while other types
5481 + * may be used to interpret old filehandle - to ensure smooth
5482 + * forward migration.
5483 + * We return 1 if a uuid was found (and it might be worth
5484 + * trying the next type) or 0 if no more uuid types can be
5488 + /* Possible sources of uuid are
5492 + * On some filesystems (e.g. vfat) the statfs64 uuid is simply an
5493 + * encoding of the device that the filesystem is mounted from, so
5494 + * it we be very bad to use that (as device numbers change). blkid
5495 + * must be preferred.
5496 + * On other filesystems (e.g. btrfs) the statfs64 uuid contains
5497 + * important info that the blkid uuid cannot contain: This happens
5498 + * when multiple subvolumes are exported (they have the same
5499 + * blkid uuid but different statfs64 uuids).
5500 + * We rely on get_uuid_blkdev *knowing* which is which and not returning
5501 + * a uuid for filesystems where the statfs64 uuid is better.
5504 + struct statfs64 st;
5505 + char fsid_val[17];
5506 + const char *blkid_val;
5509 + blkid_val = get_uuid_blkdev(path);
5511 + if (statfs64(path, &st) == 0 &&
5512 + (st.f_fsid.__val[0] || st.f_fsid.__val[1]))
5513 + snprintf(fsid_val, 17, "%08x%08x",
5514 + st.f_fsid.__val[0], st.f_fsid.__val[1]);
5518 + if (blkid_val && (type--) == 0)
5520 + else if (fsid_val[0] && (type--) == 0)
5525 + get_uuid(val, uuidlen, uuid);
5529 /* Iterate through /etc/mtab, finding mountpoints
5530 * at or below a given path
5532 @@ -277,7 +328,7 @@ static char *next_mnt(void **v, char *p)
5536 -void nfsd_fh(FILE *f)
5537 +static void nfsd_fh(FILE *f)
5540 * domain fsidtype fsid
5541 @@ -294,8 +345,7 @@ void nfsd_fh(FILE *f)
5542 unsigned int fsidnum=0;
5544 struct exportent *found = NULL;
5545 - struct hostent *he = NULL;
5546 - struct in_addr addr;
5547 + struct addrinfo *ai = NULL;
5548 char *found_path = NULL;
5551 @@ -398,6 +448,7 @@ void nfsd_fh(FILE *f)
5557 if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT) {
5558 static nfs_export *prev = NULL;
5559 @@ -461,22 +512,29 @@ void nfsd_fh(FILE *f)
5562 if (exp->m_export.e_uuid)
5563 - get_uuid(NULL, exp->m_export.e_uuid,
5564 + get_uuid(exp->m_export.e_uuid,
5566 - else if (get_uuid(path, NULL, uuidlen, u) == 0)
5570 + uuid_by_path(path, type, uuidlen, u);
5572 + if (memcmp(u, fhuuid, uuidlen) == 0)
5575 if (memcmp(u, fhuuid, uuidlen) != 0)
5581 - if (!inet_aton(dom, &addr))
5583 + struct addrinfo *tmp;
5584 + tmp = host_pton(dom);
5587 - he = client_resolve(addr);
5588 + ai = client_resolve(tmp->ai_addr);
5589 + freeaddrinfo(tmp);
5591 - if (!client_check(exp->m_client, he))
5592 + if (!client_check(exp->m_client, ai))
5595 /* It's a match !! */
5596 @@ -534,21 +592,20 @@ void nfsd_fh(FILE *f)
5604 xlog(D_CALL, "nfsd_fh: found %p path %s", found, found ? found->e_path : NULL);
5608 -static void write_fsloc(FILE *f, struct exportent *ep, char *path)
5609 +static void write_fsloc(FILE *f, struct exportent *ep)
5611 struct servers *servers;
5613 if (ep->e_fslocmethod == FSLOC_NONE)
5616 - servers = replicas_lookup(ep->e_fslocmethod, ep->e_fslocdata, path);
5617 + servers = replicas_lookup(ep->e_fslocmethod, ep->e_fslocdata);
5620 qword_print(f, "fsloc");
5621 @@ -596,17 +653,17 @@ static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *ex
5622 qword_printint(f, exp->e_anonuid);
5623 qword_printint(f, exp->e_anongid);
5624 qword_printint(f, exp->e_fsid);
5625 - write_fsloc(f, exp, path);
5626 + write_fsloc(f, exp);
5627 write_secinfo(f, exp, flag_mask);
5628 if (exp->e_uuid == NULL || different_fs) {
5630 - if (get_uuid(path, NULL, 16, u)) {
5631 + if (uuid_by_path(path, 0, 16, u)) {
5632 qword_print(f, "uuid");
5633 qword_printhex(f, u, 16);
5637 - get_uuid(NULL, exp->e_uuid, 16, u);
5638 + get_uuid(exp->e_uuid, 16, u);
5639 qword_print(f, "uuid");
5640 qword_printhex(f, u, 16);
5642 @@ -614,12 +671,12 @@ static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *ex
5643 return qword_eol(f);
5646 -static int is_subdirectory(char *subpath, char *path)
5647 +static int is_subdirectory(char *child, char *parent)
5649 - int l = strlen(path);
5650 + int l = strlen(parent);
5652 - return strcmp(subpath, path) == 0
5653 - || (strncmp(subpath, path, l) == 0 && path[l] == '/');
5654 + return strcmp(child, parent) == 0
5655 + || (strncmp(child, parent, l) == 0 && child[l] == '/');
5658 static int path_matches(nfs_export *exp, char *path)
5659 @@ -629,19 +686,22 @@ static int path_matches(nfs_export *exp, char *path)
5660 return strcmp(path, exp->m_export.e_path) == 0;
5663 -static int client_matches(nfs_export *exp, char *dom, struct hostent *he)
5665 +client_matches(nfs_export *exp, char *dom, struct addrinfo *ai)
5668 - return client_check(exp->m_client, he);
5669 + return client_check(exp->m_client, ai);
5670 return client_member(dom, exp->m_client->m_hostname);
5673 -static int export_matches(nfs_export *exp, char *dom, char *path, struct hostent *he)
5675 +export_matches(nfs_export *exp, char *dom, char *path, struct addrinfo *ai)
5677 - return path_matches(exp, path) && client_matches(exp, dom, he);
5678 + return path_matches(exp, path) && client_matches(exp, dom, ai);
5681 -static nfs_export *lookup_export(char *dom, char *path, struct hostent *he)
5682 +static nfs_export *
5683 +lookup_export(char *dom, char *path, struct addrinfo *ai)
5686 nfs_export *found = NULL;
5687 @@ -650,7 +710,7 @@ static nfs_export *lookup_export(char *dom, char *path, struct hostent *he)
5689 for (i=0 ; i < MCL_MAXTYPES; i++) {
5690 for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
5691 - if (!export_matches(exp, dom, path, he))
5692 + if (!export_matches(exp, dom, path, ai))
5696 @@ -687,7 +747,7 @@ static nfs_export *lookup_export(char *dom, char *path, struct hostent *he)
5700 -void nfsd_export(FILE *f)
5701 +static void nfsd_export(FILE *f)
5705 @@ -698,9 +758,7 @@ void nfsd_export(FILE *f)
5708 nfs_export *found = NULL;
5709 - struct in_addr addr;
5710 - struct hostent *he = NULL;
5712 + struct addrinfo *ai = NULL;
5714 if (readline(fileno(f), &lbuf, &lbuflen) != 1)
5716 @@ -722,12 +780,16 @@ void nfsd_export(FILE *f)
5720 - if (!inet_aton(dom, &addr))
5721 + struct addrinfo *tmp;
5722 + tmp = host_pton(dom);
5725 + ai = client_resolve(tmp->ai_addr);
5726 + freeaddrinfo(tmp);
5728 - he = client_resolve(addr);
5731 - found = lookup_export(dom, path, he);
5732 + found = lookup_export(dom, path, ai);
5735 if (dump_to_cache(f, dom, path, &found->m_export) < 0) {
5736 @@ -743,7 +805,7 @@ void nfsd_export(FILE *f)
5737 xlog(D_CALL, "nfsd_export: found %p path %s", found, path ? path : NULL);
5739 if (path) free(path);
5745 @@ -752,14 +814,19 @@ struct {
5746 void (*cache_handle)(FILE *f);
5749 - { "auth.unix.ip", auth_unix_ip},
5750 - { "auth.unix.gid", auth_unix_gid},
5751 - { "nfsd.export", nfsd_export},
5752 - { "nfsd.fh", nfsd_fh},
5754 + { "auth.unix.ip", auth_unix_ip, NULL},
5755 + { "auth.unix.gid", auth_unix_gid, NULL},
5756 + { "nfsd.export", nfsd_export, NULL},
5757 + { "nfsd.fh", nfsd_fh, NULL},
5758 + { NULL, NULL, NULL }
5761 extern int manage_gids;
5764 + * cache_open - prepare communications channels with kernel RPC caches
5767 void cache_open(void)
5770 @@ -772,6 +839,10 @@ void cache_open(void)
5775 + * cache_set_fds - prepare cache file descriptors for one iteration of the service loop
5776 + * @fdset: pointer to fd_set to prepare
5778 void cache_set_fds(fd_set *fdset)
5781 @@ -781,6 +852,10 @@ void cache_set_fds(fd_set *fdset)
5786 + * cache_process_req - process any active cache file descriptors during service loop iteration
5787 + * @fdset: pointer to fd_set to examine for activity
5789 int cache_process_req(fd_set *readfds)
5792 @@ -803,7 +878,7 @@ int cache_process_req(fd_set *readfds)
5793 * % echo $domain $path $[now+30*60] $options $anonuid $anongid $fsid > /proc/net/rpc/nfsd.export/channel
5796 -int cache_export_ent(char *domain, struct exportent *exp, char *path)
5797 +static int cache_export_ent(char *domain, struct exportent *exp, char *path)
5800 FILE *f = fopen("/proc/net/rpc/nfsd.export/channel", "w");
5801 @@ -824,8 +899,8 @@ int cache_export_ent(char *domain, struct exportent *exp, char *path)
5802 * and export them with the same options
5805 - int l = strlen(exp->e_path);
5807 + size_t l = strlen(exp->e_path);
5810 if (strlen(path) <= l || path[l] != '/' ||
5811 strncmp(exp->e_path, path, l) != 0)
5812 @@ -861,8 +936,14 @@ int cache_export_ent(char *domain, struct exportent *exp, char *path)
5817 + * cache_export - Inform kernel of a new nfs_export
5818 + * @exp: target nfs_export
5819 + * @path: NUL-terminated C string containing export path
5821 int cache_export(nfs_export *exp, char *path)
5823 + char buf[INET6_ADDRSTRLEN];
5827 @@ -870,8 +951,10 @@ int cache_export(nfs_export *exp, char *path)
5832 qword_print(f, "nfsd");
5833 - qword_print(f, inet_ntoa(exp->m_client->m_addrlist[0]));
5835 + host_ntop(get_addrlist(exp->m_client, 0), buf, sizeof(buf)));
5836 qword_printint(f, time(0)+30*60);
5837 qword_print(f, exp->m_client->m_hostname);
5839 @@ -883,7 +966,14 @@ int cache_export(nfs_export *exp, char *path)
5843 -/* Get a filehandle.
5845 + * cache_get_filehandle - given an nfs_export, get its root filehandle
5846 + * @exp: target nfs_export
5847 + * @len: length of requested file handle
5848 + * @p: NUL-terminated C string containing export path
5850 + * Returns pointer to NFS file handle of root directory of export
5853 * echo $domain $path $length
5854 * read filehandle <&0
5855 @@ -917,4 +1007,3 @@ cache_get_filehandle(nfs_export *exp, int len, char *p)
5856 fh.fh_size = qword_get(&bp, (char *)fh.fh_handle, NFS3_FHSIZE);
5860 diff --git a/utils/mountd/fsloc.c b/utils/mountd/fsloc.c
5861 index 5b094b0..e2add2d 100644
5862 --- a/utils/mountd/fsloc.c
5863 +++ b/utils/mountd/fsloc.c
5864 @@ -146,7 +146,7 @@ static struct servers *method_list(char *data)
5867 /* Returns appropriately filled struct servers, or NULL if had a problem */
5868 -struct servers *replicas_lookup(int method, char *data, char *key)
5869 +struct servers *replicas_lookup(int method, char *data)
5871 struct servers *sp=NULL;
5873 diff --git a/utils/mountd/fsloc.h b/utils/mountd/fsloc.h
5874 index 8296d1c..1605df4 100644
5875 --- a/utils/mountd/fsloc.h
5876 +++ b/utils/mountd/fsloc.h
5877 @@ -44,7 +44,7 @@ struct servers {
5878 int h_referral; /* 0=replica, 1=referral */
5881 -struct servers *replicas_lookup(int method, char *data, char *key);
5882 +struct servers *replicas_lookup(int method, char *data);
5883 void release_replicas(struct servers *server);
5885 #endif /* FSLOC_H */
5886 diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c
5887 index a0a1f2d..d309950 100644
5888 --- a/utils/mountd/mountd.c
5889 +++ b/utils/mountd/mountd.c
5891 #include "rpcmisc.h"
5892 #include "pseudoflavors.h"
5894 -extern void cache_open(void);
5895 -extern struct nfs_fh_len *cache_get_filehandle(nfs_export *exp, int len, char *p);
5896 -extern int cache_export(nfs_export *exp, char *path);
5898 extern void my_svc_run(void);
5900 static void usage(const char *, int exitcode);
5901 @@ -75,17 +71,40 @@ static struct option longopts[] =
5905 -static int nfs_version = -1;
5906 +#define NFSVERSBIT(vers) (0x1 << (vers - 1))
5907 +#define NFSVERSBIT_ALL (NFSVERSBIT(2) | NFSVERSBIT(3) | NFSVERSBIT(4))
5909 +static int nfs_version = NFSVERSBIT_ALL;
5911 +static int version2(void)
5913 + return nfs_version & NFSVERSBIT(2);
5916 +static int version3(void)
5918 + return nfs_version & NFSVERSBIT(3);
5921 +static int version23(void)
5923 + return nfs_version & (NFSVERSBIT(2) | NFSVERSBIT(3));
5926 +static int version_any(void)
5928 + return nfs_version & NFSVERSBIT_ALL;
5932 unregister_services (void)
5934 - if (nfs_version & 0x1)
5935 - pmap_unset (MOUNTPROG, MOUNTVERS);
5936 - if (nfs_version & (0x1 << 1))
5937 - pmap_unset (MOUNTPROG, MOUNTVERS_POSIX);
5938 - if (nfs_version & (0x1 << 2))
5939 - pmap_unset (MOUNTPROG, MOUNTVERS_NFSV3);
5941 + nfs_svc_unregister(MOUNTPROG, MOUNTVERS);
5942 + nfs_svc_unregister(MOUNTPROG, MOUNTVERS_POSIX);
5945 + nfs_svc_unregister(MOUNTPROG, MOUNTVERS_NFSV3);
5949 @@ -192,17 +211,28 @@ sig_hup (int sig)
5953 -mount_null_1_svc(struct svc_req *rqstp, void *argp, void *resp)
5954 +mount_null_1_svc(struct svc_req *rqstp, void *UNUSED(argp),
5955 + void *UNUSED(resp))
5957 + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
5958 + char buf[INET6_ADDRSTRLEN];
5960 + xlog(D_CALL, "Received NULL request from %s",
5961 + host_ntop(sap, buf, sizeof(buf)));
5967 mount_mnt_1_svc(struct svc_req *rqstp, dirpath *path, fhstatus *res)
5969 + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
5970 + char buf[INET6_ADDRSTRLEN];
5971 struct nfs_fh_len *fh;
5973 - xlog(D_CALL, "MNT1(%s) called", *path);
5974 + xlog(D_CALL, "Received MNT1(%s) request from %s", *path,
5975 + host_ntop(sap, buf, sizeof(buf)));
5977 fh = get_rootfh(rqstp, path, NULL, &res->fhs_status, 0);
5979 memcpy(&res->fhstatus_u.fhs_fhandle, fh->fh_handle, 32);
5980 @@ -210,23 +240,27 @@ mount_mnt_1_svc(struct svc_req *rqstp, dirpath *path, fhstatus *res)
5984 -mount_dump_1_svc(struct svc_req *rqstp, void *argp, mountlist *res)
5985 +mount_dump_1_svc(struct svc_req *rqstp, void *UNUSED(argp), mountlist *res)
5987 - struct sockaddr_in *addr = nfs_getrpccaller_in(rqstp->rq_xprt);
5988 + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
5989 + char buf[INET6_ADDRSTRLEN];
5991 + xlog(D_CALL, "Received DUMP request from %s",
5992 + host_ntop(sap, buf, sizeof(buf)));
5994 - xlog(D_CALL, "dump request from %s.", inet_ntoa(addr->sin_addr));
5995 *res = mountlist_list();
6001 -mount_umnt_1_svc(struct svc_req *rqstp, dirpath *argp, void *resp)
6002 +mount_umnt_1_svc(struct svc_req *rqstp, dirpath *argp, void *UNUSED(resp))
6004 - struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt);
6005 + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
6008 char rpath[MAXPATHLEN+1];
6009 + char buf[INET6_ADDRSTRLEN];
6013 @@ -236,41 +270,57 @@ mount_umnt_1_svc(struct svc_req *rqstp, dirpath *argp, void *resp)
6017 - if (!(exp = auth_authenticate("unmount", sin, p))) {
6018 + xlog(D_CALL, "Received UMNT(%s) request from %s", p,
6019 + host_ntop(sap, buf, sizeof(buf)));
6021 + exp = auth_authenticate("unmount", sap, p);
6026 - mountlist_del(inet_ntoa(sin->sin_addr), p);
6027 + mountlist_del(host_ntop(sap, buf, sizeof(buf)), p);
6032 -mount_umntall_1_svc(struct svc_req *rqstp, void *argp, void *resp)
6033 +mount_umntall_1_svc(struct svc_req *rqstp, void *UNUSED(argp),
6034 + void *UNUSED(resp))
6036 + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
6037 + char buf[INET6_ADDRSTRLEN];
6039 + xlog(D_CALL, "Received UMNTALL request from %s",
6040 + host_ntop(sap, buf, sizeof(buf)));
6042 /* Reload /etc/xtab if necessary */
6045 - mountlist_del_all(nfs_getrpccaller_in(rqstp->rq_xprt));
6046 + mountlist_del_all(nfs_getrpccaller(rqstp->rq_xprt));
6051 -mount_export_1_svc(struct svc_req *rqstp, void *argp, exports *resp)
6052 +mount_export_1_svc(struct svc_req *rqstp, void *UNUSED(argp), exports *resp)
6054 - struct sockaddr_in *addr = nfs_getrpccaller_in(rqstp->rq_xprt);
6055 + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
6056 + char buf[INET6_ADDRSTRLEN];
6058 + xlog(D_CALL, "Received EXPORT request from %s.",
6059 + host_ntop(sap, buf, sizeof(buf)));
6061 - xlog(D_CALL, "export request from %s.", inet_ntoa(addr->sin_addr));
6062 *resp = get_exportlist();
6068 -mount_exportall_1_svc(struct svc_req *rqstp, void *argp, exports *resp)
6069 +mount_exportall_1_svc(struct svc_req *rqstp, void *UNUSED(argp), exports *resp)
6071 - struct sockaddr_in *addr = nfs_getrpccaller_in(rqstp->rq_xprt);
6072 + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
6073 + char buf[INET6_ADDRSTRLEN];
6075 + xlog(D_CALL, "Received EXPORTALL request from %s.",
6076 + host_ntop(sap, buf, sizeof(buf)));
6078 - xlog(D_CALL, "exportall request from %s.", inet_ntoa(addr->sin_addr));
6079 *resp = get_exportlist();
6082 @@ -290,11 +340,12 @@ mount_exportall_1_svc(struct svc_req *rqstp, void *argp, exports *resp)
6084 mount_pathconf_2_svc(struct svc_req *rqstp, dirpath *path, ppathcnf *res)
6086 - struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt);
6087 + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
6090 char rpath[MAXPATHLEN+1];
6092 + char buf[INET6_ADDRSTRLEN];
6094 memset(res, 0, sizeof(*res));
6096 @@ -310,11 +361,14 @@ mount_pathconf_2_svc(struct svc_req *rqstp, dirpath *path, ppathcnf *res)
6100 + xlog(D_CALL, "Received PATHCONF(%s) request from %s", p,
6101 + host_ntop(sap, buf, sizeof(buf)));
6103 /* Now authenticate the intruder... */
6104 - exp = auth_authenticate("pathconf", sin, p);
6106 + exp = auth_authenticate("pathconf", sap, p);
6109 - } else if (stat(p, &stb) < 0) {
6110 + else if (stat(p, &stb) < 0) {
6111 xlog(L_WARNING, "can't stat exported dir %s: %s",
6112 p, strerror(errno));
6114 @@ -374,11 +428,15 @@ static void set_authflavors(struct mountres3_ok *ok, nfs_export *exp)
6116 mount_mnt_3_svc(struct svc_req *rqstp, dirpath *path, mountres3 *res)
6118 + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
6119 struct mountres3_ok *ok = &res->mountres3_u.mountinfo;
6120 + char buf[INET6_ADDRSTRLEN];
6122 struct nfs_fh_len *fh;
6124 - xlog(D_CALL, "MNT3(%s) called", *path);
6125 + xlog(D_CALL, "Received MNT3(%s) request from %s", *path,
6126 + host_ntop(sap, buf, sizeof(buf)));
6128 fh = get_rootfh(rqstp, path, &exp, &res->fhs_status, 1);
6131 @@ -393,12 +451,13 @@ static struct nfs_fh_len *
6132 get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
6133 mountstat3 *error, int v3)
6135 - struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt);
6136 + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
6137 struct stat stb, estb;
6139 struct nfs_fh_len *fh;
6140 char rpath[MAXPATHLEN+1];
6142 + char buf[INET6_ADDRSTRLEN];
6146 @@ -413,29 +472,29 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
6149 /* Now authenticate the intruder... */
6150 - exp = auth_authenticate("mount", sin, p);
6152 - *error = NFSERR_ACCES;
6153 + exp = auth_authenticate("mount", sap, p);
6154 + if (exp == NULL) {
6155 + *error = MNT3ERR_ACCES;
6158 if (stat(p, &stb) < 0) {
6159 xlog(L_WARNING, "can't stat exported dir %s: %s",
6160 p, strerror(errno));
6161 if (errno == ENOENT)
6162 - *error = NFSERR_NOENT;
6163 + *error = MNT3ERR_NOENT;
6165 - *error = NFSERR_ACCES;
6166 + *error = MNT3ERR_ACCES;
6169 if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) {
6170 xlog(L_WARNING, "%s is not a directory or regular file", p);
6171 - *error = NFSERR_NOTDIR;
6172 + *error = MNT3ERR_NOTDIR;
6175 if (stat(exp->m_export.e_path, &estb) < 0) {
6176 xlog(L_WARNING, "can't stat export point %s: %s",
6177 p, strerror(errno));
6178 - *error = NFSERR_NOENT;
6179 + *error = MNT3ERR_NOENT;
6182 if (estb.st_dev != stb.st_dev
6183 @@ -443,7 +502,7 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
6184 || !(exp->m_export.e_flags & NFSEXP_CROSSMOUNT))) {
6185 xlog(L_WARNING, "request to export directory %s below nearest filesystem %s",
6186 p, exp->m_export.e_path);
6187 - *error = NFSERR_ACCES;
6188 + *error = MNT3ERR_ACCES;
6191 if (exp->m_export.e_mountpoint &&
6192 @@ -452,7 +511,7 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
6193 exp->m_export.e_path)) {
6194 xlog(L_WARNING, "request to export an unmounted filesystem: %s",
6196 - *error = NFSERR_NOENT;
6197 + *error = MNT3ERR_NOENT;
6201 @@ -463,12 +522,12 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
6204 if (cache_export(exp, p)) {
6205 - *error = NFSERR_ACCES;
6206 + *error = MNT3ERR_ACCES;
6209 fh = cache_get_filehandle(exp, v3?64:32, p);
6211 - *error = NFSERR_ACCES;
6212 + *error = MNT3ERR_ACCES;
6216 @@ -482,13 +541,13 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
6220 - fh = getfh_size ((struct sockaddr *) sin, p, 64);
6221 + fh = getfh_size((struct sockaddr_in *)sap, p, 64);
6222 if (!v3 || (fh == NULL && errno == EINVAL)) {
6223 /* We first try the new nfs syscall. */
6224 - fh = getfh ((struct sockaddr *) sin, p);
6225 + fh = getfh((struct sockaddr_in *)sap, p);
6226 if (fh == NULL && errno == EINVAL)
6227 /* Let's try the old one. */
6228 - fh = getfh_old ((struct sockaddr *) sin,
6229 + fh = getfh_old((struct sockaddr_in *)sap,
6230 stb.st_dev, stb.st_ino);
6232 if (fh == NULL && !did_export) {
6233 @@ -498,12 +557,12 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
6236 xlog(L_WARNING, "getfh failed: %s", strerror(errno));
6237 - *error = NFSERR_ACCES;
6238 + *error = MNT3ERR_ACCES;
6243 - mountlist_add(inet_ntoa(sin->sin_addr), p);
6245 + mountlist_add(host_ntop(sap, buf, sizeof(buf)), p);
6249 @@ -536,22 +595,21 @@ static void free_exportlist(exports *elist)
6251 static void prune_clients(nfs_export *exp, struct exportnode *e)
6253 - struct hostent *hp;
6254 + struct addrinfo *ai = NULL;
6255 struct groupnode *c, **cp;
6258 while ((c = *cp) != NULL) {
6259 if (client_gettype(c->gr_name) == MCL_FQDN
6260 - && (hp = gethostbyname(c->gr_name))) {
6261 - hp = hostent_dup(hp);
6262 - if (client_check(exp->m_client, hp)) {
6263 + && (ai = host_addrinfo(c->gr_name))) {
6264 + if (client_check(exp->m_client, ai)) {
6277 @@ -634,13 +692,22 @@ main(int argc, char **argv)
6279 char *export_file = _PATH_EXPORTS;
6280 char *state_dir = NFS_STATEDIR;
6282 + unsigned int listeners = 0;
6285 int descriptors = 0;
6288 struct sigaction sa;
6291 + /* Set the basename */
6292 + if ((progname = strrchr(argv[0], '/')) != NULL)
6295 + progname = argv[0];
6297 /* Parse the command line options and arguments. */
6299 while ((c = getopt_long(argc, argv, "o:nFd:f:p:P:hH:N:V:vrs:t:g", longopts, NULL)) != EOF)
6300 @@ -652,8 +719,8 @@ main(int argc, char **argv)
6301 descriptors = atoi(optarg);
6302 if (descriptors <= 0) {
6303 fprintf(stderr, "%s: bad descriptors: %s\n",
6304 - argv [0], optarg);
6305 - usage(argv [0], 1);
6306 + progname, optarg);
6307 + usage(progname, 1);
6311 @@ -669,19 +736,25 @@ main(int argc, char **argv)
6312 ha_callout_prog = optarg;
6315 - usage(argv [0], 0);
6316 + usage(progname, 0);
6318 case 'P': /* XXX for nfs-server compatibility */
6320 port = atoi(optarg);
6321 if (port <= 0 || port > 65535) {
6322 fprintf(stderr, "%s: bad port number: %s\n",
6323 - argv [0], optarg);
6324 - usage(argv [0], 1);
6325 + progname, optarg);
6326 + usage(progname, 1);
6330 - nfs_version &= ~(1 << (atoi (optarg) - 1));
6331 + vers = atoi(optarg);
6332 + if (vers < 2 || vers > 4) {
6333 + fprintf(stderr, "%s: bad version number: %s\n",
6335 + usage(argv[0], 1);
6337 + nfs_version &= ~NFSVERSBIT(vers);
6340 _rpcfdtype = SOCK_DGRAM;
6341 @@ -692,7 +765,7 @@ main(int argc, char **argv)
6343 if ((state_dir = xstrdup(optarg)) == NULL) {
6344 fprintf(stderr, "%s: xstrdup(%s) failed!\n",
6346 + progname, optarg);
6350 @@ -700,31 +773,37 @@ main(int argc, char **argv)
6351 num_threads = atoi (optarg);
6354 - nfs_version |= 1 << (atoi (optarg) - 1);
6355 + vers = atoi(optarg);
6356 + if (vers < 2 || vers > 4) {
6357 + fprintf(stderr, "%s: bad version number: %s\n",
6359 + usage(argv[0], 1);
6361 + nfs_version |= NFSVERSBIT(vers);
6364 - printf("kmountd %s\n", VERSION);
6365 + printf("%s version " VERSION "\n", progname);
6371 - usage(argv [0], 1);
6372 + usage(progname, 1);
6375 /* No more arguments allowed. */
6376 - if (optind != argc || !(nfs_version & 0x7))
6377 - usage(argv [0], 1);
6378 + if (optind != argc || !version_any())
6379 + usage(progname, 1);
6381 if (chdir(state_dir)) {
6382 fprintf(stderr, "%s: chdir(%s) failed: %s\n",
6383 - argv [0], state_dir, strerror(errno));
6384 + progname, state_dir, strerror(errno));
6388 if (getrlimit (RLIMIT_NOFILE, &rlim) != 0)
6389 fprintf(stderr, "%s: getrlimit (RLIMIT_NOFILE) failed: %s\n",
6390 - argv [0], strerror(errno));
6391 + progname, strerror(errno));
6393 /* glibc sunrpc code dies if getdtablesize > FD_SETSIZE */
6394 if ((descriptors == 0 && rlim.rlim_cur > FD_SETSIZE) ||
6395 @@ -734,14 +813,14 @@ main(int argc, char **argv)
6396 rlim.rlim_cur = descriptors;
6397 if (setrlimit (RLIMIT_NOFILE, &rlim) != 0) {
6398 fprintf(stderr, "%s: setrlimit (RLIMIT_NOFILE) failed: %s\n",
6399 - argv [0], strerror(errno));
6400 + progname, strerror(errno));
6405 /* Initialize logging. */
6406 if (!foreground) xlog_stderr(0);
6407 - xlog_open("mountd");
6408 + xlog_open(progname);
6410 sa.sa_handler = SIG_IGN;
6412 @@ -761,15 +840,17 @@ main(int argc, char **argv)
6416 - if (nfs_version & 0x1)
6417 - rpc_init("mountd", MOUNTPROG, MOUNTVERS,
6418 - mount_dispatch, port);
6419 - if (nfs_version & (0x1 << 1))
6420 - rpc_init("mountd", MOUNTPROG, MOUNTVERS_POSIX,
6421 - mount_dispatch, port);
6422 - if (nfs_version & (0x1 << 2))
6423 - rpc_init("mountd", MOUNTPROG, MOUNTVERS_NFSV3,
6424 - mount_dispatch, port);
6426 + listeners += nfs_svc_create("mountd", MOUNTPROG,
6427 + MOUNTVERS, mount_dispatch, port);
6428 + listeners += nfs_svc_create("mountd", MOUNTPROG,
6429 + MOUNTVERS_POSIX, mount_dispatch, port);
6432 + listeners += nfs_svc_create("mountd", MOUNTPROG,
6433 + MOUNTVERS_NFSV3, mount_dispatch, port);
6434 + if (version23() && listeners == 0)
6435 + xlog(L_FATAL, "mountd: could not create listeners\n");
6437 sa.sa_handler = killer;
6438 sigaction(SIGINT, &sa, NULL);
6439 @@ -810,9 +891,11 @@ main(int argc, char **argv)
6440 if (num_threads > 1)
6443 + xlog(L_NOTICE, "Version " VERSION " starting");
6446 - xlog(L_ERROR, "Ack! Gack! svc_run returned!\n");
6447 + xlog(L_ERROR, "RPC service loop terminated unexpectedly. Exiting...\n");
6448 + unregister_services();
6452 diff --git a/utils/mountd/mountd.h b/utils/mountd/mountd.h
6453 index 31bacb5..4c184d2 100644
6454 --- a/utils/mountd/mountd.h
6455 +++ b/utils/mountd/mountd.h
6456 @@ -41,14 +41,19 @@ bool_t mount_mnt_3_svc(struct svc_req *, dirpath *, mountres3 *);
6457 void mount_dispatch(struct svc_req *, SVCXPRT *);
6458 void auth_init(char *export_file);
6459 unsigned int auth_reload(void);
6460 -nfs_export * auth_authenticate(char *what, struct sockaddr_in *sin,
6462 +nfs_export * auth_authenticate(const char *what,
6463 + const struct sockaddr *caller,
6464 + const char *path);
6465 void auth_export(nfs_export *exp);
6467 void mountlist_add(char *host, const char *path);
6468 void mountlist_del(char *host, const char *path);
6469 -void mountlist_del_all(struct sockaddr_in *sin);
6470 +void mountlist_del_all(const struct sockaddr *sap);
6471 mountlist mountlist_list(void);
6473 +void cache_open(void);
6474 +struct nfs_fh_len *
6475 + cache_get_filehandle(nfs_export *exp, int len, char *p);
6476 +int cache_export(nfs_export *exp, char *path);
6478 #endif /* MOUNTD_H */
6479 diff --git a/utils/mountd/mountd.man b/utils/mountd/mountd.man
6480 index bfa06e0..4bb96e8 100644
6481 --- a/utils/mountd/mountd.man
6482 +++ b/utils/mountd/mountd.man
6486 +.\"@(#)rpc.mountd.8"
6488 .\" Copyright (C) 1999 Olaf Kirch <okir@monad.swb.de>
6489 .\" Modified by Paul Clements, 2004.
6490 -.TH rpc.mountd 8 "31 Aug 2004"
6492 +.TH rpc.mountd 8 "31 Dec 2009"
6494 rpc.mountd \- NFS mount daemon
6496 @@ -11,48 +11,73 @@ rpc.mountd \- NFS mount daemon
6500 -program implements the NFS mount protocol. When receiving a MOUNT
6501 -request from an NFS client, it checks the request against the list of
6502 -currently exported file systems. If the client is permitted to mount
6505 -obtains a file handle for requested directory and returns it to
6507 -.SS Exporting NFS File Systems
6508 -Making file systems available to NFS clients is called
6511 -Usually, a file system and the hosts it should be made available to
6516 -whenever the system is booted. The
6517 +daemon implements the server side of the NFS MOUNT protocol,
6518 +an NFS side protocol used by NFS version 2 [RFC1094] and NFS version 3 [RFC1813].
6520 +An NFS server maintains a table of local physical file systems
6521 +that are accessible to NFS clients.
6522 +Each file system in this table is referred to as an
6523 +.IR "exported file system" ,
6528 +Each file system in the export table has an access control list.
6530 +uses these access control lists to determine
6531 +whether an NFS client is permitted to access a given file system.
6532 +For details on how to manage your NFS server's export table, see the
6536 -command makes export information available to both the kernel NFS
6537 -server module and the
6541 -Alternatively, you can export individual directories temporarily
6544 -.IB host : /directory
6547 +.SS Mounting exported NFS File Systems
6548 +The NFS MOUNT protocol has several procedures.
6549 +The most important of these are
6550 +MNT (mount an export) and
6551 +UMNT (unmount an export).
6553 +A MNT request has two arguments: an explicit argument that
6554 +contains the pathname of the root directory of the export to be mounted,
6555 +and an implicit argument that is the sender's IP address.
6557 +When receiving a MNT request from an NFS client,
6559 +checks both the pathname and the sender's IP address against its export table.
6560 +If the sender is permitted to access the requested export,
6562 +returns an NFS file handle for the export's root directory to the client.
6563 +The client can then use the root file handle and NFS LOOKUP requests
6564 +to navigate the directory structure of the export.
6566 -For every mount request received from an NFS client,
6568 -adds an entry to the
6569 -.B /var/lib/nfs/rmtab
6570 -file. When receiving an unmount request, that entry is removed.
6572 -However, this file is mostly ornamental. One, the client can continue
6573 -to use the file handle even after calling
6575 -UMOUNT procedure. And two, if a client reboots without notifying
6577 -a stale entry will remain in
6581 +daemon registers every successful MNT request by adding an entry to the
6582 +.I /var/lib/nfs/rmtab
6584 +When receivng a UMNT request from an NFS client,
6586 +simply removes the matching entry from
6587 +.IR /var/lib/nfs/rmtab ,
6588 +as long as the access control list for that export allows that sender
6589 +to access the export.
6591 +Clients can discover the list of file systems an NFS server is
6592 +currently exporting, or the list of other clients that have mounted
6593 +its exports, by using the
6597 +uses other procedures in the NFS MOUNT protocol to report information
6598 +about the server's exported file systems.
6600 +Note, however, that there is little to guarantee that the contents of
6601 +.I /var/lib/nfs/rmtab
6603 +A client may continue accessing an export even after invoking UMNT.
6604 +If the client reboots without sending a UMNT request, stale entries
6605 +remain for that client in
6606 +.IR /var/lib/nfs/rmtab .
6609 .B \-d kind " or " \-\-debug kind
6610 @@ -94,22 +119,25 @@ Don't advertise TCP for mount.
6611 Ignored (compatibility with unfsd??).
6613 .B \-p " or " \-\-port num
6615 +Specifies the port number used for RPC listener sockets.
6616 +If this option is not specified,
6618 -to bind to the specified port num, instead of using the random port
6619 -number assigned by the portmapper.
6620 +chooses a random ephemeral port for each listener socket.
6622 +This option can be used to fix the port value of
6624 +listeners when NFS MOUNT requests must traverse a firewall
6625 +between clients and servers.
6627 .B \-H " or " \-\-ha-callout prog
6628 -Specify a high availability callout program, which will receive callouts
6629 -for all client mount and unmount requests. This allows
6631 -to be used in a High Availability NFS (HA-NFS) environment. This callout is not
6632 -needed (and should not be used) with 2.6 and later kernels (instead,
6633 -mount the nfsd filesystem on
6636 -The program will be called with 4 arguments.
6638 +Specify a high availability callout program.
6639 +This program receives callouts for all MOUNT and UNMOUNT requests.
6642 +to be used in a High Availability NFS (HA-NFS) environment.
6644 +The callout program is run with 4 arguments.
6649 @@ -118,19 +146,30 @@ The second will be the name of the client performing the mount.
6650 The third will be the path that the client is mounting.
6651 The last is the number of concurrent mounts that we believe the client
6654 +This callout is not needed with 2.6 and later kernels.
6655 +Instead, mount the nfsd filesystem on
6656 +.IR /proc/fs/nfsd .
6658 .BI "\-s," "" " \-\-state\-directory\-path " directory
6659 -specify a directory in which to place statd state information.
6660 +Specify a directory in which to place statd state information.
6661 If this option is not specified the default of
6666 .BI "\-r," "" " \-\-reverse\-lookup"
6667 -mountd tracks IP addresses in the rmtab, and when a DUMP request is made (by
6668 -someone running showmount -a, for instance), it returns IP addresses instead
6669 -of hostnames by default. This option causes mountd to do a reverse
6670 -lookup on each IP address and return that hostname instead. Enabling this can
6671 -have a substantial negative effect on performance in some situations.
6673 +tracks IP addresses in the
6675 +file. When a DUMP request is made (by
6677 +.BR "showmount -a" ,
6678 +for instance), it returns IP addresses instead
6679 +of hostnames by default. This option causes
6681 +to perform a reverse lookup on each IP address and return that hostname instead.
6682 +Enabling this can have a substantial negative effect on performance
6683 +in some situations.
6685 .BR "\-t N" " or " "\-\-num\-threads=N"
6686 This option specifies the number of worker threads that rpc.mountd
6687 @@ -162,41 +201,70 @@ If you use the
6688 flag, then the list of group ids received from the client will be
6689 replaced by a list of group ids determined by an appropriate lookup on
6690 the server. Note that the 'primary' group id is not affected so a
6693 command on the client will still be effective. This function requires
6694 a Linux Kernel with version at least 2.6.21.
6696 .SH TCP_WRAPPERS SUPPORT
6698 +You can protect your
6700 -version is protected by the
6701 +listeners using the
6708 -library. You have to give the clients access to
6710 -if they should be allowed to use it. To allow connects from clients of
6711 -the .bar.com domain you could use the following line in /etc/hosts.allow:
6715 -You have to use the daemon name
6716 +library supports only IPv4 networking.
6718 +Add the hostnames of NFS peers that are allowed to access
6721 +.IR /etc/hosts.allow .
6722 +Use the daemon name
6724 -for the daemon name (even if the binary has a different name).
6726 -hostnames used in either access file will be ignored when
6729 +binary has a different name.
6731 +Hostnames used in either access file will be ignored when
6732 they can not be resolved into IP addresses.
6734 -For further information please have a look at the
6735 +For further information see the
6738 .BR hosts_access (5)
6741 +.SS IPv6 and TI-RPC support
6742 +TI-RPC is a pre-requisite for supporting NFS on IPv6.
6743 +If TI-RPC support is built into
6745 +it attempts to start listeners on network transports marked 'visible' in
6746 +.IR /etc/netconfig .
6747 +As long as at least one network transport listener starts successfully,
6755 +listing exports, export options, and access control lists
6757 +.I /var/lib/nfs/rmtab
6758 +table of clients accessing server's exports
6763 -.BR rpc.rquotad (8).
6766 -.BR /var/lib/nfs/xtab .
6769 +.BR rpc.rquotad (8),
6772 +.BR hosts_access (5),
6776 +RFC 1094 - "NFS: Network File System Protocol Specification"
6778 +RFC 1813 - "NFS Version 3 Protocol Specification"
6780 Olaf Kirch, H. J. Lu, G. Allan Morris III, and a host of others.
6781 diff --git a/utils/mountd/rmtab.c b/utils/mountd/rmtab.c
6782 index 19b22ee..d339296 100644
6783 --- a/utils/mountd/rmtab.c
6784 +++ b/utils/mountd/rmtab.c
6786 #include <netinet/in.h>
6787 #include <arpa/inet.h>
6789 -#include "xmalloc.h"
6792 #include "exportfs.h"
6794 @@ -131,22 +131,22 @@ mountlist_del(char *hname, const char *path)
6798 -mountlist_del_all(struct sockaddr_in *sin)
6799 +mountlist_del_all(const struct sockaddr *sap)
6801 - struct in_addr addr = sin->sin_addr;
6802 - struct hostent *hp;
6804 struct rmtabent *rep;
6809 if ((lockid = xflock(_PATH_RMTABLCK, "w")) < 0)
6811 - if (!(hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET))) {
6812 - xlog(L_ERROR, "can't get hostname of %s", inet_ntoa(addr));
6813 + hostname = host_canonname(sap);
6814 + if (hostname == NULL) {
6815 + char buf[INET6_ADDRSTRLEN];
6816 + xlog(L_ERROR, "can't get hostname of %s",
6817 + host_ntop(sap, buf, sizeof(buf)));
6820 - hp = hostent_dup (hp);
6822 if (!setrmtabent("r"))
6824 @@ -155,8 +155,8 @@ mountlist_del_all(struct sockaddr_in *sin)
6827 while ((rep = getrmtabent(1, NULL)) != NULL) {
6828 - if (strcmp(rep->r_client, hp->h_name) == 0 &&
6829 - (exp = auth_authenticate("umountall", sin, rep->r_path)))
6830 + if (strcmp(rep->r_client, hostname) == 0 &&
6831 + auth_authenticate("umountall", sap, rep->r_path) != NULL)
6833 fputrmtabent(fp, rep, NULL);
6835 @@ -168,11 +168,23 @@ mountlist_del_all(struct sockaddr_in *sin)
6837 endrmtabent(); /* close & unlink */
6846 +mountlist_freeall(mountlist list)
6848 + while (list != NULL) {
6849 + mountlist m = list;
6850 + list = m->ml_next;
6851 + free(m->ml_hostname);
6852 + free(m->ml_directory);
6858 mountlist_list(void)
6860 @@ -182,8 +194,6 @@ mountlist_list(void)
6861 struct rmtabent *rep;
6864 - struct in_addr addr;
6865 - struct hostent *he;
6867 if ((lockid = xflock(_PATH_RMTABLCK, "r")) < 0)
6869 @@ -194,26 +204,41 @@ mountlist_list(void)
6872 if (stb.st_mtime != last_mtime) {
6874 - mlist = (m = mlist)->ml_next;
6875 - xfree(m->ml_hostname);
6876 - xfree(m->ml_directory);
6879 + mountlist_freeall(mlist);
6880 last_mtime = stb.st_mtime;
6883 while ((rep = getrmtabent(1, NULL)) != NULL) {
6884 - m = (mountlist) xmalloc(sizeof(*m));
6886 - if (reverse_resolve &&
6887 - inet_aton((const char *) rep->r_client, &addr) &&
6888 - (he = gethostbyaddr(&addr, sizeof(addr), AF_INET)))
6889 - m->ml_hostname = xstrdup(he->h_name);
6891 - m->ml_hostname = xstrdup(rep->r_client);
6892 + m = calloc(1, sizeof(*m));
6894 + mountlist_freeall(mlist);
6896 + xlog(L_ERROR, "%s: memory allocation failed",
6901 + if (reverse_resolve) {
6902 + struct addrinfo *ai;
6903 + ai = host_pton(rep->r_client);
6905 + m->ml_hostname = host_canonname(ai->ai_addr);
6909 + if (m->ml_hostname == NULL)
6910 + m->ml_hostname = strdup(rep->r_client);
6912 + m->ml_directory = strdup(rep->r_path);
6914 + if (m->ml_hostname == NULL || m->ml_directory == NULL) {
6915 + mountlist_freeall(mlist);
6917 + xlog(L_ERROR, "%s: memory allocation failed",
6922 - m->ml_directory = xstrdup(rep->r_path);
6926 diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c
6927 index 1cda1e5..650c593 100644
6928 --- a/utils/nfsd/nfsd.c
6929 +++ b/utils/nfsd/nfsd.c
6935 - * IPv6 support for nfsd was finished before some of the other daemons (mountd
6936 - * and statd in particular). That could be a problem in the future if someone
6937 - * were to boot a kernel that supports IPv6 serving with an older nfs-utils. For
6938 - * now, hardcode the IPv6 switch into the off position until the other daemons
6941 -#undef IPV6_SUPPORTED
6943 static void usage(const char *);
6945 static struct option longopts[] =
6946 diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c
6947 index 60232b8..25cd459 100644
6948 --- a/utils/nfsd/nfssvc.c
6949 +++ b/utils/nfsd/nfssvc.c
6955 - * IPv6 support for nfsd was finished before some of the other daemons (mountd
6956 - * and statd in particular). That could be a problem in the future if someone
6957 - * were to boot a kernel that supports IPv6 serving with an older nfs-utils. For
6958 - * now, hardcode the IPv6 switch into the off position until the other daemons
6961 -#undef IPV6_SUPPORTED
6963 #define NFSD_PORTS_FILE "/proc/fs/nfsd/portlist"
6964 #define NFSD_VERS_FILE "/proc/fs/nfsd/versions"
6965 #define NFSD_THREAD_FILE "/proc/fs/nfsd/threads"
6966 @@ -181,7 +172,7 @@ nfssvc_setfds(const struct addrinfo *hints, const char *node, const char *port)
6969 snprintf(buf, sizeof(buf), "%d\n", sockfd);
6970 - if (write(fd, buf, strlen(buf)) != strlen(buf)) {
6971 + if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) {
6973 * this error may be common on older kernels that don't
6974 * support IPv6, so turn into a debug message.
6975 @@ -251,7 +242,7 @@ nfssvc_setvers(unsigned int ctlbits, int minorvers4)
6977 xlog(D_GENERAL, "Writing version string to kernel: %s", buf);
6978 snprintf(ptr+off, sizeof(buf) - off, "\n");
6979 - if (write(fd, buf, strlen(buf)) != strlen(buf))
6980 + if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
6981 xlog(L_ERROR, "Setting version failed: errno %d (%m)", errno);
6984 @@ -277,7 +268,7 @@ nfssvc_threads(unsigned short port, const int nrservs)
6985 snprintf(buf, sizeof(buf), "%d\n", nrservs);
6986 n = write(fd, buf, strlen(buf));
6988 - if (n != strlen(buf))
6989 + if (n != (ssize_t)strlen(buf))
6993 diff --git a/utils/nfsstat/nfsstat.c b/utils/nfsstat/nfsstat.c
6994 index 99d77c9..740a803 100644
6995 --- a/utils/nfsstat/nfsstat.c
6996 +++ b/utils/nfsstat/nfsstat.c
6997 @@ -791,7 +791,7 @@ print_callstats(const char *hdr, const char **names,
6999 unsigned long long total;
7000 unsigned long long pct;
7002 + unsigned int i, j;
7005 for (i = 0, total = 0; i < nr; i++)
7006 @@ -816,7 +816,7 @@ print_callstats_list(const char *hdr, const char **names,
7007 unsigned int *callinfo, unsigned int nr)
7009 unsigned long long calltotal;
7013 for (i = 0, calltotal = 0; i < nr; i++) {
7014 calltotal += callinfo[i];
7015 @@ -1118,7 +1118,7 @@ unpause(int sig)
7016 time_diff = difftime(endtime, starttime);
7017 minutes = time_diff / 60;
7018 seconds = (int)time_diff % 60;
7019 - printf("Signal received; displaying (only) statistics gathered over the last %d minutes, %d seconds:\n\n", minutes, seconds);
7020 + printf("Signal %d received; displaying (only) statistics gathered over the last %d minutes, %d seconds:\n\n", sig, minutes, seconds);
7024 diff --git a/utils/showmount/showmount.c b/utils/showmount/showmount.c
7025 index f567093..394f528 100644
7026 --- a/utils/showmount/showmount.c
7027 +++ b/utils/showmount/showmount.c
7028 @@ -194,7 +194,13 @@ int main(int argc, char **argv)
7031 mclient = nfs_get_mount_client(hostname, mount_vers_tbl[vers]);
7032 - mclient->cl_auth = authunix_create_default();
7033 + mclient->cl_auth = nfs_authsys_create();
7034 + if (mclient->cl_auth == NULL) {
7035 + fprintf(stderr, "%s: unable to create RPC auth handle.\n",
7037 + clnt_destroy(mclient);
7040 total_timeout.tv_sec = TOTAL_TIMEOUT;
7041 total_timeout.tv_usec = 0;
7043 diff --git a/utils/statd/hostname.c b/utils/statd/hostname.c
7044 index 7d704cc..38f2265 100644
7045 --- a/utils/statd/hostname.c
7046 +++ b/utils/statd/hostname.c
7047 @@ -212,7 +212,9 @@ statd_canonical_name(const char *hostname)
7048 buf, (socklen_t)sizeof(buf));
7052 + /* OK to use presentation address,
7053 + * if no reverse map exists */
7054 + return strdup(hostname);
7058 diff --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c
7059 index 3259a3e..437e37a 100644
7060 --- a/utils/statd/sm-notify.c
7061 +++ b/utils/statd/sm-notify.c
7062 @@ -54,7 +54,7 @@ struct nsm_host {
7066 -static char nsm_hostname[256];
7067 +static char nsm_hostname[SM_MAXSTRLEN + 1];
7068 static int nsm_state;
7069 static int nsm_family = AF_INET;
7070 static int opt_debug = 0;
7071 @@ -412,12 +412,33 @@ usage: fprintf(stderr,
7075 - if (opt_srcaddr) {
7076 - strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname)-1);
7078 - if (gethostname(nsm_hostname, sizeof(nsm_hostname)) < 0) {
7079 - xlog(L_ERROR, "Failed to obtain name of local host: %m");
7081 + if (opt_srcaddr != NULL) {
7082 + struct addrinfo *ai = NULL;
7083 + struct addrinfo hint = {
7084 + .ai_family = AF_UNSPEC,
7085 + .ai_flags = AI_NUMERICHOST,
7088 + if (getaddrinfo(opt_srcaddr, NULL, &hint, &ai))
7089 + /* not a presentation address - use it */
7090 + strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname));
7092 + /* was a presentation address - look it up in
7093 + * /etc/hosts, so it can be used for my_name */
7097 + hint.ai_flags = AI_CANONNAME;
7098 + error = getaddrinfo(opt_srcaddr, NULL, &hint, &ai);
7100 + xlog(L_ERROR, "Bind address %s is unusable: %s",
7101 + opt_srcaddr, gai_strerror(error));
7104 + strncpy(nsm_hostname, ai->ai_canonname,
7105 + sizeof(nsm_hostname));
7110 (void)nsm_retire_monitored_hosts();
7111 @@ -535,6 +556,8 @@ notify(const int sock)
7113 notify_host(int sock, struct nsm_host *host)
7115 + const char *my_name = (opt_srcaddr != NULL ?
7116 + nsm_hostname : host->my_name);
7117 struct sockaddr *sap;
7120 @@ -580,8 +603,8 @@ notify_host(int sock, struct nsm_host *host)
7121 host->xid = nsm_xmit_rpcbind(sock, sap, SM_PROG, SM_VERS);
7123 host->xid = nsm_xmit_notify(sock, sap, salen,
7124 - SM_PROG, nsm_hostname, nsm_state);
7126 + SM_PROG, my_name, nsm_state);
7131 @@ -611,15 +634,28 @@ recv_rpcbind_reply(struct sockaddr *sap, struct nsm_host *host, XDR *xdr)
7135 - * Successful NOTIFY call. Server returns void, so nothing
7136 - * we need to do here.
7137 + * Successful NOTIFY call. Server returns void.
7139 + * Try sending another SM_NOTIFY with an unqualified "my_name"
7140 + * argument. Reuse the port number. If "my_name" is already
7141 + * unqualified, we're done.
7144 recv_notify_reply(struct nsm_host *host)
7146 - xlog(D_GENERAL, "Host %s notified successfully", host->name);
7147 + char *dot = strchr(host->my_name, '.');
7149 - smn_forget_host(host);
7150 + if (dot != NULL) {
7152 + host->send_next = time(NULL);
7154 + if (host->timeout >= NSM_MAX_TIMEOUT / 4)
7155 + host->timeout = NSM_MAX_TIMEOUT / 4;
7156 + insert_host(host);
7158 + xlog(D_GENERAL, "Host %s notified successfully", host->name);
7159 + smn_forget_host(host);
7164 diff --git a/utils/statd/sm-notify.man b/utils/statd/sm-notify.man
7165 index 163713e..7a1cbfa 100644
7166 --- a/utils/statd/sm-notify.man
7167 +++ b/utils/statd/sm-notify.man
7168 @@ -97,11 +97,9 @@ It uses the
7169 string as the destination.
7170 To identify which host has rebooted, the
7172 -command normally sends the results of
7173 -.BR gethostname (3)
7175 +command normally sends
7178 +string recorded when that remote was monitored.
7181 matches incoming SM_NOTIFY requests using this string,
7182 @@ -202,15 +200,22 @@ argument to use when sending SM_NOTIFY requests.
7183 If this option is not specified,
7185 uses a wildcard address as the transport bind address,
7186 -and uses the results of
7187 -.BR gethostname (3)
7191 +recorded when the remote was monitored as the
7194 +argument when sending SM_NOTIFY requests.
7198 form can be expressed as either an IPv4 or an IPv6 presentation address.
7203 +command converts this address to a hostname for use as the
7205 +argument when sending SM_NOTIFY requests.
7207 This option can be useful in multi-homed configurations where
7208 the remote requires notification from a specific network address.
7209 @@ -252,13 +257,6 @@ consistent
7210 The hostname the client uses to mount the server should match the server's
7212 in SM_NOTIFY requests it sends
7214 -The use of network addresses as a
7218 -string should be avoided when
7219 -interoperating with non-Linux NFS implementations.
7221 Unmounting an NFS file system does not necessarily stop
7222 either the NFS client or server from monitoring each other.
7223 diff --git a/utils/statd/statd.man b/utils/statd/statd.man
7224 index ffc5e95..ca00e24 100644
7225 --- a/utils/statd/statd.man
7226 +++ b/utils/statd/statd.man
7227 @@ -100,11 +100,9 @@ It uses the
7228 string as the destination.
7229 To identify which host has rebooted, the
7231 -command normally sends the results of
7232 -.BR gethostname (3)
7237 +string recorded when that remote was monitored.
7240 matches incoming SM_NOTIFY requests using this string,
7241 @@ -292,7 +290,6 @@ man pages.
7242 .SH ADDITIONAL NOTES
7243 Lock recovery after a reboot is critical to maintaining data integrity
7244 and preventing unnecessary application hangs.
7248 match SM_NOTIFY requests to NLM requests, a number of best practices
7249 @@ -309,13 +306,6 @@ consistent
7250 The hostname the client uses to mount the server should match the server's
7252 in SM_NOTIFY requests it sends
7254 -The use of network addresses as a
7258 -string should be avoided when
7259 -interoperating with non-Linux NFS implementations.
7261 Unmounting an NFS file system does not necessarily stop
7262 either the NFS client or server from monitoring each other.