]> git.pld-linux.org Git - packages/nfs-utils.git/blob - nfs-utils-git.patch
- idmapd does not need portmapper to work
[packages/nfs-utils.git] / nfs-utils-git.patch
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], [
6    dnl look for prctl
7    AC_CHECK_FUNC([prctl], , )
8  
9 -  dnl look for the library; do not add to LIBS if found
10 -  AC_CHECK_LIB([cap], [cap_get_proc], [LIBCAP=-lcap], ,)
11 -  AC_SUBST(LIBCAP)
12 +  AC_ARG_ENABLE([caps],
13 +    [AS_HELP_STRING([--disable-caps], [Disable capabilities support])])
14 +
15 +  LIBCAP=
16 +
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], ,)
20  
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.])])
25 +  fi
26 +
27 +  AC_SUBST(LIBCAP)
28  
29  ])dnl
30 diff --git a/autogen.sh b/autogen.sh
31 old mode 100644
32 new mode 100755
33 diff --git a/configure.ac b/configure.ac
34 index b7520d8..7c9e61a 100644
35 --- a/configure.ac
36 +++ b/configure.ac
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])
40         else
41 -               enable_nfsv4=
42 +               enable_nfsv41=
43         fi
44         AC_SUBST(enable_nfsv41)
45         AM_CONDITIONAL(CONFIG_NFSV41, [test "$enable_nfsv41" = "yes"])
46 @@ -400,7 +400,7 @@ case $host in
47      ARCHFLAGS="" ;;
48  esac
49  
50 -my_am_cflags="-Wall -Wstrict-prototypes $ARCHFLAGS -pipe"
51 +my_am_cflags="-Wall -Wextra -Wstrict-prototypes $ARCHFLAGS -pipe"
52  
53  AC_SUBST([AM_CFLAGS], ["$my_am_cflags"])
54  
55 @@ -425,6 +425,8 @@ AC_CONFIG_FILES([
56         tools/nlmtest/Makefile
57         tools/rpcdebug/Makefile
58         tools/rpcgen/Makefile
59 +       tools/mountstats/Makefile
60 +       tools/nfs-iostat/Makefile
61         utils/Makefile
62         utils/exportfs/Makefile
63         utils/gssd/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
68 @@ -17,7 +17,9 @@
69  #include <string.h>
70  #include <ctype.h>
71  #include <netdb.h>
72 -#include "xmalloc.h"
73 +#include <errno.h>
74 +
75 +#include "sockaddr.h"
76  #include "misc.h"
77  #include "nfslib.h"
78  #include "exportfs.h"
79 @@ -28,58 +30,211 @@
80  #if !defined(__GLIBC__) || __GLIBC__ < 2
81  extern int     innetgr(char *netgr, char *host, char *, char *);
82  #endif
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);
86 +
87 +static char    *add_name(char *old, const char *add);
88  
89  nfs_client     *clientlist[MCL_MAXTYPES] = { NULL, };
90  
91  
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
95 +static void
96 +init_addrlist(nfs_client *clp, const struct addrinfo *ai)
97 +{
98 +       int i;
99 +
100 +       if (ai == NULL)
101 +               return;
102 +
103 +       for (i = 0; (ai != NULL) && (i < NFSCLNT_ADDRMAX); i++) {
104 +               set_addrlist(clp, i, ai->ai_addr);
105 +               ai = ai->ai_next;
106 +       }
107 +
108 +       clp->m_naddr = i;
109 +}
110 +
111 +static void
112 +client_free(nfs_client *clp)
113 +{
114 +       free(clp->m_hostname);
115 +       free(clp);
116 +}
117 +
118 +static int
119 +init_netmask(nfs_client *clp, const char *slash, const sa_family_t family)
120 +{
121 +       struct sockaddr_in sin = {
122 +               .sin_family             = AF_INET,
123 +       };
124 +       unsigned long prefixlen;
125 +       uint32_t shift;
126 +#ifdef IPV6_SUPPORTED
127 +       struct sockaddr_in6 sin6 = {
128 +               .sin6_family            = AF_INET6,
129 +       };
130 +       int i;
131 +#endif
132 +
133 +       /* No slash present; assume netmask is all ones */
134 +       if (slash == NULL) {
135 +               switch (family) {
136 +               case AF_INET:
137 +                       prefixlen = 32;
138 +                       break;
139 +#ifdef IPV6_SUPPORTED
140 +               case AF_INET6:
141 +                       prefixlen = 128;
142 +                       break;
143 +#endif
144 +               default:
145 +                       goto out_badfamily;
146 +               }
147 +       } else {
148 +               char *endptr;
149 +
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)
154 +                               goto out_badmask;
155 +                       set_addrlist_in(clp, 1, &sin);
156 +                       return 1;
157 +               }
158 +#ifdef IPV6_SUPPORTED
159 +               if (strchr(slash + 1, ':')) {
160 +                       if (!inet_pton(AF_INET6, slash + 1, &sin6.sin6_addr))
161 +                               goto out_badmask;
162 +                       set_addrlist_in6(clp, 1, &sin6);
163 +                       return 1;
164 +               }
165 +#endif
166 +
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;
171 +       }
172 +
173 +       switch (family) {
174 +       case AF_INET:
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);
180 +               return 1;
181 +#ifdef IPV6_SUPPORTED
182 +       case AF_INET6:
183 +               if (prefixlen > 128)
184 +                       goto out_badprefix;
185 +               for (i = 0; prefixlen > 32; i++) {
186 +                       sin6.sin6_addr.s6_addr32[i] = 0xffffffff;
187 +                       prefixlen -= 32;
188 +               }
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);
192 +               return 1;
193 +#endif
194 +       }
195 +
196 +out_badfamily:
197 +       xlog(L_ERROR, "Unsupported address family for %s", clp->m_hostname);
198 +       return 0;
199 +
200 +out_badmask:
201 +       xlog(L_ERROR, "Invalid netmask `%s' for %s", slash + 1, clp->m_hostname);
202 +       return 0;
203 +
204 +out_badprefix:
205 +       xlog(L_ERROR, "Invalid prefix `%s' for %s", slash + 1, clp->m_hostname);
206 +       return 0;
207 +}
208 +
209 +static int
210 +init_subnetwork(nfs_client *clp)
211 +{
212 +       struct addrinfo *ai;
213 +       sa_family_t family;
214 +       char *slash;
215 +
216 +       slash = strchr(clp->m_hostname, '/');
217 +       if (slash != NULL) {
218 +               *slash = '\0';
219 +               ai = host_pton(clp->m_hostname);
220 +               *slash = '/';
221 +       } else
222 +               ai = host_pton(clp->m_hostname);
223 +       if (ai == NULL) {
224 +               xlog(L_ERROR, "Invalid IP address %s", clp->m_hostname);
225 +               return false;
226 +       }
227 +
228 +       set_addrlist(clp, 0, ai->ai_addr);
229 +       family = ai->ai_addr->sa_family;
230 +
231 +       freeaddrinfo(ai);
232 +
233 +       return init_netmask(clp, slash, family);
234 +}
235 +
236 +static int
237 +client_init(nfs_client *clp, const char *hname, const struct addrinfo *ai)
238 +{
239 +       clp->m_hostname = strdup(hname);
240 +       if (clp->m_hostname == NULL)
241 +               return 0;
242 +
243 +       clp->m_exported = 0;
244 +       clp->m_count = 0;
245 +       clp->m_naddr = 0;
246 +
247 +       if (clp->m_type == MCL_SUBNETWORK)
248 +               return init_subnetwork(clp);
249 +
250 +       init_addrlist(clp, ai);
251 +       return 1;
252 +}
253 +
254 +static void
255 +client_add(nfs_client *clp)
256 +{
257 +       nfs_client **cpp;
258 +
259 +       cpp = &clientlist[clp->m_type];
260 +       while (*cpp != NULL)
261 +               cpp = &((*cpp)->m_next);
262 +       clp->m_next = NULL;
263 +       *cpp = clp;
264 +}
265 +
266 +/**
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
270 + *
271 + * Returns pointer to a matching or freshly created nfs_client.  NULL
272 + * is returned if some problem occurs.
273   */
274  nfs_client *
275  client_lookup(char *hname, int canonical)
276  {
277         nfs_client      *clp = NULL;
278         int             htype;
279 -       struct hostent  *hp = NULL;
280 +       struct addrinfo *ai = NULL;
281  
282         htype = client_gettype(hname);
283  
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);
289 -                       return NULL;
290 +               ai = host_addrinfo(hname);
291 +               if (!ai) {
292 +                       xlog(L_ERROR, "Failed to resolve %s", hname);
293 +                       goto out;
294                 }
295 -               /* make sure we have canonical name */
296 -               hp2 = hostent_dup(hp);
297 -               hp = gethostbyaddr(hp2->h_addr, hp2->h_length,
298 -                                  hp2->h_addrtype);
299 -               if (hp) {
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);
305 -                               if (hp3) {
306 -                                       free(hp);
307 -                                       hp = hostent_dup(hp3);
308 -                               }
309 -                       }
310 -                       free(hp2);
311 -               } else
312 -                       hp = hp2;
313 -
314 -               hname = (char *) hp->h_name;
315 +               hname = ai->ai_canonname;
316  
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))
321                                 break;
322 -               }
323         } else {
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)
327                 }
328         }
329  
330 -       if (!clp) {
331 -               clp = (nfs_client *) xmalloc(sizeof(*clp));
332 -               memset(clp, 0, sizeof(*clp));
333 +       if (clp == NULL) {
334 +               clp = calloc(1, sizeof(*clp));
335 +               if (clp == NULL)
336 +                       goto out;
337                 clp->m_type = htype;
338 -               client_init(clp, hname, NULL);
339 +               if (!client_init(clp, hname, NULL)) {
340 +                       client_free(clp);
341 +                       clp = NULL;
342 +                       goto out;
343 +               }
344                 client_add(clp);
345         }
346  
347 -       if (htype == MCL_FQDN && clp->m_naddr == 0 && hp != NULL) {
348 -               char    **ap = hp->h_addr_list;
349 -               int     i;
350 -
351 -               for (i = 0; *ap && i < NFSCLNT_ADDRMAX; i++, ap++)
352 -                       clp->m_addrlist[i] = *(struct in_addr *)*ap;
353 -               clp->m_naddr = i;
354 -       }
355 -
356 -       if (hp)
357 -               free (hp);
358 +       if (htype == MCL_FQDN && clp->m_naddr == 0)
359 +               init_addrlist(clp, ai);
360  
361 +out:
362 +       freeaddrinfo(ai);
363         return clp;
364  }
365  
366 +/**
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
370 + *
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).
374 + */
375  nfs_client *
376 -client_dup(nfs_client *clp, struct hostent *hp)
377 +client_dup(const nfs_client *clp, const struct addrinfo *ai)
378  {
379         nfs_client              *new;
380  
381 -       new = (nfs_client *) xmalloc(sizeof(*new));
382 +       new = (nfs_client *)malloc(sizeof(*new));
383 +       if (new == NULL)
384 +               return NULL;
385         memcpy(new, clp, sizeof(*new));
386         new->m_type = MCL_FQDN;
387         new->m_hostname = NULL;
388  
389 -       client_init(new, (char *) hp->h_name, hp);
390 +       if (!client_init(new, ai->ai_canonname, ai)) {
391 +               client_free(new);
392 +               return NULL;
393 +       }
394         client_add(new);
395         return new;
396  }
397  
398 -static void
399 -client_init(nfs_client *clp, const char *hname, struct hostent *hp)
400 -{
401 -       xfree(clp->m_hostname);
402 -       if (hp)
403 -               clp->m_hostname = xstrdup(hp->h_name);
404 -       else
405 -               clp->m_hostname = xstrdup(hname);
406 -
407 -       clp->m_exported = 0;
408 -       clp->m_count = 0;
409 -
410 -       if (clp->m_type == MCL_SUBNETWORK) {
411 -               char    *cp = strchr(clp->m_hostname, '/');
412 -               static char slash32[] = "/32";
413 -
414 -               if(!cp) cp = slash32;
415 -               *cp = '\0';
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);
419 -               }
420 -               else {
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));
425 -                       }
426 -                       else {
427 -                               xlog(L_FATAL, "invalid netmask `%s' for %s",
428 -                                    cp + 1, clp->m_hostname);
429 -                       }
430 -               }
431 -               *cp = '/';
432 -               clp->m_naddr = 0;
433 -       } else if (!hp) {
434 -               clp->m_naddr = 0;
435 -       } else {
436 -               char    **ap = hp->h_addr_list;
437 -               int     i;
438 -
439 -               for (i = 0; *ap && i < NFSCLNT_ADDRMAX; i++, ap++) {
440 -                       clp->m_addrlist[i] = *(struct in_addr *)*ap;
441 -               }
442 -               clp->m_naddr = i;
443 -       }
444 -}
445 -
446 -void
447 -client_add(nfs_client *clp)
448 -{
449 -       nfs_client      **cpp;
450 -
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;
454 -       while (*cpp)
455 -               cpp = &((*cpp)->m_next);
456 -       clp->m_next = NULL;
457 -       *cpp = clp;
458 -}
459 -
460 +/**
461 + * client_release - drop a reference to an nfs_client record
462 + *
463 + */
464  void
465  client_release(nfs_client *clp)
466  {
467 @@ -195,6 +304,10 @@ client_release(nfs_client *clp)
468         clp->m_count--;
469  }
470  
471 +/**
472 + * client_freeall - deallocate all nfs_client records
473 + *
474 + */
475  void
476  client_freeall(void)
477  {
478 @@ -205,57 +318,45 @@ client_freeall(void)
479                 head = clientlist + i;
480                 while (*head) {
481                         *head = (clp = *head)->m_next;
482 -                       xfree(clp->m_hostname);
483 -                       xfree(clp);
484 -               }
485 -       }
486 -}
487 -
488 -nfs_client *
489 -client_find(struct hostent *hp)
490 -{
491 -       nfs_client      *clp;
492 -       int             i;
493 -
494 -       for (i = 0; i < MCL_MAXTYPES; i++) {
495 -               for (clp = clientlist[i]; clp; clp = clp->m_next) {
496 -                       if (!client_check(clp, hp))
497 -                               continue;
498 -#ifdef notdef
499 -                       if (clp->m_type == MCL_FQDN)
500 -                               return clp;
501 -                       return client_dup(clp, hp);
502 -#else
503 -                       return clp;
504 -#endif
505 +                       client_free(clp);
506                 }
507         }
508 -       return NULL;
509  }
510  
511 -struct hostent *
512 -client_resolve(struct in_addr addr)
513 +/**
514 + * client_resolve - look up an IP address
515 + * @sap: pointer to socket address to resolve
516 + *
517 + * Returns an addrinfo structure, or NULL if some problem occurred.
518 + * Caller must free the result with freeaddrinfo(3).
519 + */
520 +struct addrinfo *
521 +client_resolve(const struct sockaddr *sap)
522  {
523 -       struct hostent *he = NULL;
524 +       struct addrinfo *ai = NULL;
525  
526         if (clientlist[MCL_WILDCARD] || clientlist[MCL_NETGROUP])
527 -               he = get_reliable_hostbyaddr((const char*)&addr, sizeof(addr), AF_INET);
528 -       if (he == NULL)
529 -               he = get_hostent((const char*)&addr, sizeof(addr), AF_INET);
530 +               ai = host_reliable_addrinfo(sap);
531 +       if (ai == NULL)
532 +               ai = host_numeric_addrinfo(sap);
533  
534 -       return he;
535 +       return ai;
536  }
537  
538 -/*
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 '+'
542 +/**
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
545 + *
546 + * Gather all known client hostnames that match the IP address, and sort
547 + * the result into a comma-separated list.
548   *
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).
553   */
554 -static char *add_name(char *old, char *add);
555 -
556  char *
557 -client_compose(struct hostent *he)
558 +client_compose(const struct addrinfo *ai)
559  {
560         char *name = NULL;
561         int i;
562 @@ -263,7 +364,7 @@ client_compose(struct hostent *he)
563         for (i = 0 ; i < MCL_MAXTYPES; i++) {
564                 nfs_client      *clp;
565                 for (clp = clientlist[i]; clp ; clp = clp->m_next) {
566 -                       if (!client_check(clp, he))
567 +                       if (!client_check(clp, ai))
568                                 continue;
569                         name = add_name(name, clp->m_hostname);
570                 }
571 @@ -271,13 +372,19 @@ client_compose(struct hostent *he)
572         return name;
573  }
574  
575 +/**
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
580 + *
581 + * Returns 1 if @name was found in @client, otherwise zero is returned.
582 + */
583  int
584 -client_member(char *client, char *name)
585 +client_member(const char *client, const char *name)
586  {
587 -       /* check if "client" (a ',' separated list of names)
588 -        * contains 'name' as a member
589 -        */
590 -       int l = strlen(name);
591 +       size_t l = strlen(name);
592 +
593         while (*client) {
594                 if (strncmp(client, name, l) == 0 &&
595                     (client[l] == ',' || client[l] == '\0'))
596 @@ -290,9 +397,8 @@ client_member(char *client, char *name)
597         return 0;
598  }
599  
600 -
601 -int
602 -name_cmp(char *a, char *b)
603 +static int
604 +name_cmp(const char *a, const char *b)
605  {
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)
609  }
610  
611  static char *
612 -add_name(char *old, char *add)
613 +add_name(char *old, const char *add)
614  {
615 -       int len = strlen(add)+2;
616 +       size_t len = strlen(add) + 2;
617         char *new;
618         char *cp;
619         if (old) len += strlen(old);
620 @@ -340,108 +446,257 @@ add_name(char *old, char *add)
621  }
622  
623  /*
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
628 + * zero.
629   */
630 -int
631 -client_check(nfs_client *clp, struct hostent *hp)
632 +static int
633 +check_fqdn(const nfs_client *clp, const struct addrinfo *ai)
634  {
635 -       char    *hname = (char *) hp->h_name;
636 -       char    *cname = clp->m_hostname;
637 -       char    **ap;
638 +       int i;
639  
640 -       switch (clp->m_type) {
641 -       case MCL_FQDN:
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)))
649                                 return 1;
650 -               }
651 -               return 0;
652 -       case MCL_WILDCARD:
653 -               if (wildmat(hname, cname))
654 +
655 +       return 0;
656 +}
657 +
658 +static _Bool
659 +mask_match(const uint32_t a, const uint32_t b, const uint32_t m)
660 +{
661 +       return ((a ^ b) & m) == 0;
662 +}
663 +
664 +static int
665 +check_subnet_v4(const struct sockaddr_in *address,
666 +               const struct sockaddr_in *mask, const struct addrinfo *ai)
667 +{
668 +       for (; ai; ai = ai->ai_next) {
669 +               struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
670 +
671 +               if (sin->sin_family != AF_INET)
672 +                       continue;
673 +
674 +               if (mask_match(address->sin_addr.s_addr,
675 +                               sin->sin_addr.s_addr,
676 +                               mask->sin_addr.s_addr))
677                         return 1;
678 -               else {
679 -                       for (ap = hp->h_aliases; *ap; ap++)
680 -                               if (wildmat(*ap, cname))
681 -                                       return 1;
682 -               }
683 -               return 0;
684 -       case MCL_NETGROUP:
685 -#ifdef HAVE_INNETGR
686 -               {
687 -                       char    *dot;
688 -                       int     match, i;
689 -                       struct hostent *nhp = NULL;
690 -                       struct sockaddr_in addr;
691 -
692 -                       /* First, try to match the hostname without
693 -                        * splitting off the domain */
694 -                       if (innetgr(cname+1, hname, NULL, NULL))
695 -                               return 1;
696 +       }
697 +       return 0;
698 +}
699  
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))
703 -                                       return 1;
704 -                       }
705 +#ifdef IPV6_SUPPORTED
706 +static int
707 +check_subnet_v6(const struct sockaddr_in6 *address,
708 +               const struct sockaddr_in6 *mask, const struct addrinfo *ai)
709 +{
710 +       for (; ai; ai = ai->ai_next) {
711 +               struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr;
712 +
713 +               if (sin6->sin6_family != AF_INET6)
714 +                       continue;
715 +
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]))
728 +                       return 1;
729 +       }
730 +       return 0;
731 +}
732 +#else  /* !IPV6_SUPPORTED */
733 +static int
734 +check_subnet_v6(const struct sockaddr_in6 *UNUSED(address),
735 +               const struct sockaddr_in6 *UNUSED(mask),
736 +               const struct addrinfo *UNUSED(ai))
737 +{
738 +       return 0;
739 +}
740 +#endif /* !IPV6_SUPPORTED */
741  
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))
748 -                                       return 1;
749 -                       }
750 +/*
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.
754 + */
755 +static int
756 +check_subnetwork(const nfs_client *clp, const struct addrinfo *ai)
757 +{
758 +       switch (get_addrlist(clp, 0)->sa_family) {
759 +       case AF_INET:
760 +               return check_subnet_v4(get_addrlist_in(clp, 0),
761 +                               get_addrlist_in(clp, 1), ai);
762 +       case AF_INET6:
763 +               return check_subnet_v6(get_addrlist_in6(clp, 0),
764 +                               get_addrlist_in6(clp, 1), ai);
765 +       }
766  
767 -                       /* Okay, strip off the domain (if we have one) */
768 -                       if ((dot = strchr(hname, '.')) == NULL)
769 -                               return 0;
770 +       return 0;
771 +}
772  
773 -                       *dot = '\0';
774 -                       match = innetgr(cname+1, hname, NULL, NULL);
775 -                       *dot = '.';
776 +/*
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
779 + * zero.
780 + */
781 +static int
782 +check_wildcard(const nfs_client *clp, const struct addrinfo *ai)
783 +{
784 +       char *cname = clp->m_hostname;
785 +       char *hname = ai->ai_canonname;
786 +       struct hostent *hp;
787 +       char **ap;
788  
789 -                       return match;
790 -               }
791 -#else
792 -               return 0;
793 -#endif
794 -       case MCL_ANONYMOUS:
795 +       if (wildmat(hname, cname))
796                 return 1;
797 -       case MCL_GSS:
798 -               return 0;
799 -       default:
800 -               xlog(L_FATAL, "internal: bad client type %d", clp->m_type);
801 +
802 +       /* See if hname aliases listed in /etc/hosts or nis[+]
803 +        * match the requested wildcard */
804 +       hp = gethostbyname(hname);
805 +       if (hp != NULL) {
806 +               for (ap = hp->h_aliases; *ap; ap++)
807 +                       if (wildmat(*ap, cname))
808 +                               return 1;
809         }
810  
811         return 0;
812  }
813  
814 +/*
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
817 + * zero.
818 + */
819 +#ifdef HAVE_INNETGR
820 +static int
821 +check_netgroup(const nfs_client *clp, const struct addrinfo *ai)
822 +{
823 +       const char *netgroup = clp->m_hostname + 1;
824 +       struct addrinfo *tmp = NULL;
825 +       struct hostent *hp;
826 +       char *dot, *hname;
827 +       int i, match;
828 +
829 +       match = 0;
830 +
831 +       hname = strdup(ai->ai_canonname);
832 +       if (hname == NULL) {
833 +               xlog(D_GENERAL, "%s: no memory for strdup", __func__);
834 +               goto out;
835 +       }
836 +
837 +       /* First, try to match the hostname without
838 +        * splitting off the domain */
839 +       if (innetgr(netgroup, hname, NULL, NULL)) {
840 +               match = 1;
841 +               goto out;
842 +       }
843 +
844 +       /* See if hname aliases listed in /etc/hosts or nis[+]
845 +        * match the requested netgroup */
846 +       hp = gethostbyname(hname);
847 +       if (hp != NULL) {
848 +               for (i = 0; hp->h_aliases[i]; i++)
849 +                       if (innetgr(netgroup, hp->h_aliases[i], NULL, NULL)) {
850 +                               match = 1;
851 +                               goto out;
852 +                       }
853 +       }
854 +
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);
858 +       if (tmp != NULL) {
859 +               char *cname = host_canonname(tmp->ai_addr);
860 +               freeaddrinfo(tmp);
861 +
862 +               /* The resulting FQDN may be in our netgroup. */
863 +               if (cname != NULL) {
864 +                       free(hname);
865 +                       hname = cname;
866 +                       if (innetgr(netgroup, hname, NULL, NULL)) {
867 +                               match = 1;
868 +                               goto out;
869 +                       }
870 +               }
871 +       }
872 +
873 +       /* Okay, strip off the domain (if we have one) */
874 +       dot = strchr(hname, '.');
875 +       if (dot == NULL)
876 +               goto out;
877 +
878 +       *dot = '\0';
879 +       match = innetgr(netgroup, hname, NULL, NULL);
880 +
881 +out:
882 +       free(hname);
883 +       return match;
884 +}
885 +#else  /* !HAVE_INNETGR */
886  static int
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)
890  {
891 -       int     i;
892 +       return 0;
893 +}
894 +#endif /* !HAVE_INNETGR */
895  
896 +/**
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
900 + *
901 + * Returns 1 if the address information matches the cached nfs_client,
902 + * otherwise zero.
903 + */
904 +int
905 +client_check(const nfs_client *clp, const struct addrinfo *ai)
906 +{
907         switch (clp->m_type) {
908         case MCL_FQDN:
909 -               for (i = 0; i < clp->m_naddr; i++) {
910 -                       if (clp->m_addrlist[i].s_addr == addr.s_addr)
911 -                               return 1;
912 -               }
913 -               return 0;
914 +               return check_fqdn(clp, ai);
915         case MCL_SUBNETWORK:
916 -               return !((clp->m_addrlist[0].s_addr ^ addr.s_addr)
917 -                       & clp->m_addrlist[1].s_addr);
918 +               return check_subnetwork(clp, ai);
919 +       case MCL_WILDCARD:
920 +               return check_wildcard(clp, ai);
921 +       case MCL_NETGROUP:
922 +               return check_netgroup(clp, ai);
923 +       case MCL_ANONYMOUS:
924 +               return 1;
925 +       case MCL_GSS:
926 +               return 0;
927 +       default:
928 +               xlog(D_GENERAL, "%s: unrecognized client type: %d",
929 +                               __func__, clp->m_type);
930         }
931 +
932         return 0;
933  }
934  
935 +/**
936 + * client_gettype - determine type of nfs_client given an identifier
937 + * @ident: '\0'-terminated ASCII string containing a client identifier
938 + *
939 + * Returns the type of nfs_client record that would be used for
940 + * this client.
941 + */
942  int
943  client_gettype(char *ident)
944  {
945 -       char    *sp;
946 +       struct addrinfo *ai;
947 +       char *sp;
948  
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])
953                         sp++;
954         }
955 -       /* check for N.N.N.N */
956 -       sp = ident;
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;
963 +
964 +       /*
965 +        * Treat unadorned IP addresses as MCL_SUBNETWORK.
966 +        * Everything else is MCL_FQDN.
967 +        */
968 +       ai = host_pton(ident);
969 +       if (ai != NULL) {
970 +               freeaddrinfo(ai);
971 +               return MCL_SUBNETWORK;
972 +       }
973 +
974 +       return MCL_FQDN;
975  }
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 *);
981  
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,
987 +                               const char *path);
988  static nfs_export *
989 -               export_allowed_internal(struct hostent *hp, char *path);
990 +               export_allowed_internal(const struct addrinfo *ai,
991 +                               const char *path);
992 +
993 +static void
994 +export_free(nfs_export *exp)
995 +{
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);
1001 +
1002 +       xfree(exp->m_export.e_hostname);
1003 +       xfree(exp);
1004 +}
1005  
1006  static void warn_duplicated_exports(nfs_export *exp, struct exportent *eep)
1007  {
1008 @@ -44,7 +60,12 @@ static void warn_duplicated_exports(nfs_export *exp, struct exportent *eep)
1009         }
1010  }
1011  
1012 -int
1013 +/**
1014 + * export_read - read entries from /etc/exports
1015 + * @fname: name of file to read from
1016 + *
1017 + */
1018 +void
1019  export_read(char *fname)
1020  {
1021         struct exportent        *eep;
1022 @@ -59,11 +80,15 @@ export_read(char *fname)
1023                         warn_duplicated_exports(exp, eep);
1024         }
1025         endexportent();
1026 -       return 0;
1027  }
1028  
1029 -/*
1030 - * Create an in-core export struct from an export entry.
1031 +/**
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
1035 + *
1036 + * Returns a freshly instantiated export record, or NULL if
1037 + * a problem occurred.
1038   */
1039  nfs_export *
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.
1044   */
1045 -nfs_export *
1046 -export_dup(nfs_export *exp, struct hostent *hp)
1047 +static nfs_export *
1048 +export_dup(nfs_export *exp, const struct addrinfo *ai)
1049  {
1050         nfs_export              *new;
1051         nfs_client              *clp;
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) {
1059 +               export_free(new);
1060 +               return NULL;
1061 +       }
1062         clp->m_count++;
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)
1066  
1067         return new;
1068  }
1069 -/*
1070 - * Add export entry to hash table
1071 - */
1072 -void 
1073 +
1074 +static void
1075  export_add(nfs_export *exp)
1076  {
1077         exp_hash_table *p_tbl;
1078 @@ -159,19 +186,27 @@ export_add(nfs_export *exp)
1079         }
1080  }
1081  
1082 +/**
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
1086 + *
1087 + * Returns a pointer to nfs_export data matching @ai and @path,
1088 + * or NULL if an error occurs.
1089 + */
1090  nfs_export *
1091 -export_find(struct hostent *hp, char *path)
1092 +export_find(const struct addrinfo *ai, const char *path)
1093  {
1094         nfs_export      *exp;
1095         int             i;
1096  
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))
1101                                 continue;
1102                         if (exp->m_client->m_type == MCL_FQDN)
1103                                 return exp;
1104 -                       return export_dup(exp, hp);
1105 +                       return export_dup(exp, ai);
1106                 }
1107         }
1108  
1109 @@ -179,7 +214,7 @@ export_find(struct hostent *hp, char *path)
1110  }
1111  
1112  static nfs_export *
1113 -export_allowed_internal (struct hostent *hp, char *path)
1114 +export_allowed_internal(const struct addrinfo *ai, const char *path)
1115  {
1116         nfs_export      *exp;
1117         int             i;
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))
1124                                 continue;
1125                         return exp;
1126                 }
1127 @@ -196,8 +231,16 @@ export_allowed_internal (struct hostent *hp, char *path)
1128         return NULL;
1129  }
1130  
1131 +/**
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
1135 + *
1136 + * Returns a pointer to nfs_export data matching @ai and @path,
1137 + * or NULL if the export is not allowed.
1138 + */
1139  nfs_export *
1140 -export_allowed(struct hostent *hp, char *path)
1141 +export_allowed(const struct addrinfo *ai, const char *path)
1142  {
1143         nfs_export              *exp;
1144         char                    epath[MAXPATHLEN+1];
1145 @@ -210,7 +253,7 @@ export_allowed(struct hostent *hp, char *path)
1146  
1147         /* Try the longest matching exported pathname. */
1148         while (1) {
1149 -               exp = export_allowed_internal (hp, epath);
1150 +               exp = export_allowed_internal(ai, epath);
1151                 if (exp)
1152                         return exp;
1153                 /* We have to treat the root, "/", specially. */
1154 @@ -223,11 +266,17 @@ export_allowed(struct hostent *hp, char *path)
1155         return NULL;
1156  }
1157  
1158 -/*
1159 - * Search hash table for export entry. 
1160 - */  
1161 +/**
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
1166 + *
1167 + * Returns a pointer to nfs_export record matching @hname and @path,
1168 + * or NULL if the export was not found.
1169 + */
1170  nfs_export *
1171 -export_lookup(char *hname, char *path, int canonical) 
1172 +export_lookup(char *hname, char *path, int canonical)
1173  {
1174         nfs_client *clp;
1175         nfs_export *exp;
1176 @@ -251,14 +300,18 @@ export_lookup(char *hname, char *path, int canonical)
1177  }
1178  
1179  static int
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)
1182  {
1183         if (strcmp(path, exp->m_export.e_path))
1184                 return 0;
1185  
1186 -       return client_check(exp->m_client, hp);
1187 +       return client_check(exp->m_client, ai);
1188  }
1189  
1190 +/**
1191 + * export_freeall - deallocate all nfs_export records
1192 + *
1193 + */
1194  void
1195  export_freeall(void)
1196  {
1197 @@ -269,22 +322,13 @@ export_freeall(void)
1198                 for (exp = exportlist[i].p_head; exp; exp = nxt) {
1199                         nxt = exp->m_next;
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);
1210 -                       xfree(exp);
1211 +                       export_free(exp);
1212 +               }
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;
1216                 }
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;
1220 -      }
1221 -      exportlist[i].p_head = NULL;
1222 +               exportlist[i].p_head = NULL;
1223         }
1224         client_freeall();
1225  }
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
1230 @@ -1,315 +1,376 @@
1231  /*
1232 - * support/export/hostname.c
1233 + * Copyright 2010 Oracle.  All rights reserved.
1234   *
1235 - * Functions for hostname.
1236 + * This file is part of nfs-utils.
1237   *
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.
1242 + *
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.
1247 + *
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/>.
1250   */
1251  
1252  #ifdef HAVE_CONFIG_H
1253  #include <config.h>
1254  #endif
1255  
1256 -/*
1257 -#define TEST
1258 -*/
1259 -
1260  #include <string.h>
1261 -#include <netdb.h>
1262 -#include <netinet/in.h>
1263 -#include <arpa/inet.h>
1264  #include <stdlib.h>
1265 -#include <xlog.h>
1266 -#ifdef TEST
1267 -#define xmalloc malloc
1268 -#else
1269 -#include "xmalloc.h"
1270 -#include "misc.h"
1271 -#endif
1272 +#include <arpa/inet.h>
1273 +#include <netdb.h>
1274 +#include <errno.h>
1275  
1276 -#define ALIGNMENT      sizeof (char *)
1277 +#include "sockaddr.h"
1278 +#include "exportfs.h"
1279  
1280 -static int
1281 -align (int len, int al)
1282 +#ifndef HAVE_DECL_AI_ADDRCONFIG
1283 +#define AI_ADDRCONFIG  0
1284 +#endif
1285 +
1286 +/**
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
1291 + *
1292 + * Returns a pointer to a @buf.
1293 + */
1294 +#ifdef HAVE_GETNAMEINFO
1295 +char *
1296 +host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
1297  {
1298 -  int i;
1299 -  i = len % al;
1300 -  if (i)
1301 -    len += al - i;
1302 -  return len;
1303 -}
1304 +       socklen_t salen = nfs_sockaddr_length(sap);
1305 +       int error;
1306 +
1307 +       memset(buf, 0, buflen);
1308 +
1309 +       if (salen == 0) {
1310 +               (void)strncpy(buf, "bad family", buflen - 1);
1311 +               return buf;
1312 +       }
1313 +
1314 +       error = getnameinfo(sap, salen, buf, (socklen_t)buflen,
1315 +                                               NULL, 0, NI_NUMERICHOST);
1316 +       if (error != 0) {
1317 +               buf[0] = '\0';
1318 +               (void)strncpy(buf, "bad address", buflen - 1);
1319 +       }
1320  
1321 -struct hostent *
1322 -get_hostent (const char *addr, int len, int type)
1323 +       return buf;
1324 +}
1325 +#else  /* !HAVE_GETNAMEINFO */
1326 +char *
1327 +host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
1328  {
1329 -  struct hostent *cp;
1330 -  int len_ent;
1331 -  const char *name;
1332 -  int len_name;
1333 -  int num_aliases = 1;
1334 -  int len_aliases = sizeof (char *);
1335 -  int num_addr_list = 1;
1336 -  int len_addr_list = sizeof (char *);
1337 -  int pos;
1338 -  struct in_addr *ipv4;
1339 -
1340 -  switch (type)
1341 -    {
1342 -    case AF_INET:
1343 -      ipv4 = (struct in_addr *) addr;
1344 -      name = inet_ntoa (*ipv4);
1345 -      break;
1346 -
1347 -    default:
1348 -      return NULL;
1349 -    }
1350 -
1351 -  len_ent = align (sizeof (*cp), ALIGNMENT);
1352 -  len_name = align (strlen (name) + 1, ALIGNMENT);
1353 -
1354 -  num_addr_list++;
1355 -  len_addr_list += align (len, ALIGNMENT) + sizeof (char *);
1356 -
1357 -  cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases
1358 -                                  + len_addr_list);
1359 -
1360 -  cp->h_addrtype = type;
1361 -  cp->h_length = len;
1362 -  pos = len_ent;
1363 -  cp->h_name = (char *) &(((char *) cp) [pos]);
1364 -  strcpy (cp->h_name, name);
1365 -
1366 -  pos += len_name;
1367 -  cp->h_aliases = (char **) &(((char *) cp) [pos]);
1368 -  pos += num_aliases * sizeof (char *);
1369 -  cp->h_aliases [0] = NULL;
1370 -
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;
1378 -
1379 -  return cp;
1380 +       const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap;
1381 +
1382 +       memset(buf, 0, buflen);
1383 +
1384 +       if (sin->sin_family != AF_INET)
1385 +               (void)strncpy(buf, "bad family", buflen - 1);
1386 +               return buf;
1387 +       }
1388 +
1389 +       if (inet_ntop(AF_INET, &sin->sin_addr.s_addr, buf, buflen) != NULL)
1390 +               return buf;
1391 +
1392 +       buf[0] = '\0';
1393 +       (void)strncpy(buf, "bad address", buflen - 1);
1394 +       return buf;
1395  }
1396 +#endif /* !HAVE_GETNAMEINFO */
1397  
1398 -struct hostent *
1399 -hostent_dup (struct hostent *hp)
1400 +/**
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
1404 + *
1405 + * Returns address info structure, or NULL if an error occurs.  Caller
1406 + * must free the returned structure with freeaddrinfo(3).
1407 + */
1408 +__attribute_malloc__
1409 +struct addrinfo *
1410 +host_pton(const char *paddr)
1411  {
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 *);
1418 -  int pos, i;
1419 -  char **sp;
1420 -  struct hostent *cp;
1421 -
1422 -  for (sp = hp->h_aliases; sp && *sp; sp++)
1423 -    {
1424 -      num_aliases++;
1425 -      len_aliases += align (strlen (*sp) + 1, ALIGNMENT)
1426 -                    + sizeof (char *);
1427 -    }
1428 -
1429 -  for (sp = hp->h_addr_list; *sp; sp++)
1430 -    {
1431 -      num_addr_list++;
1432 -      len_addr_list += align (hp->h_length, ALIGNMENT)
1433 -                      + sizeof (char *);
1434 -    }
1435 -
1436 -  cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases
1437 -                                  + len_addr_list);
1438 -
1439 -  *cp = *hp;
1440 -  pos = len_ent;
1441 -  cp->h_name = (char *) &(((char *) cp) [pos]);
1442 -  strcpy (cp->h_name, hp->h_name);
1443 -
1444 -  pos += len_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++)
1448 -    if (sp && *sp)
1449 -      {
1450 -       cp->h_aliases [i] = (char *) &(((char *) cp) [pos]);
1451 -       strcpy (cp->h_aliases [i], *sp);
1452 -       pos += align (strlen (*sp) + 1, ALIGNMENT);
1453 -      }
1454 -    else
1455 -      cp->h_aliases [i] = NULL;
1456 -
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++)
1461 -    if (*sp)
1462 -      {
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);
1466 -      }
1467 -    else
1468 -      cp->h_addr_list [i] = *sp;
1469 -
1470 -  return cp;
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,
1477 +       };
1478 +       struct sockaddr_in sin;
1479 +       int error, inet4;
1480 +
1481 +       /*
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.
1486 +        *
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.
1490 +        */
1491 +       inet4 = 1;
1492 +       if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0)
1493 +               inet4 = 0;
1494 +
1495 +       error = getaddrinfo(paddr, NULL, &hint, &ai);
1496 +       switch (error) {
1497 +       case 0:
1498 +               if (!inet4 && ai->ai_addr->sa_family == AF_INET) {
1499 +                       freeaddrinfo(ai);
1500 +                       break;
1501 +               }
1502 +               return ai;
1503 +       case EAI_NONAME:
1504 +               if (paddr == NULL)
1505 +                       xlog(D_GENERAL, "%s: passed a NULL presentation address",
1506 +                               __func__);
1507 +               break;
1508 +       case EAI_SYSTEM:
1509 +               xlog(D_GENERAL, "%s: failed to convert %s: (%d) %m",
1510 +                               __func__, paddr, errno);
1511 +               break;
1512 +       default:
1513 +               xlog(D_GENERAL, "%s: failed to convert %s: %s",
1514 +                               __func__, paddr, gai_strerror(error));
1515 +               break;
1516 +       }
1517 +
1518 +       return NULL;
1519  }
1520  
1521 -static int
1522 -is_hostname(const char *sp)
1523 +/**
1524 + * host_addrinfo - return addrinfo for a given hostname
1525 + * @hostname: pointer to a '\0'-terminated ASCII string containing a hostname
1526 + *
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).
1530 + */
1531 +__attribute_malloc__
1532 +struct addrinfo *
1533 +host_addrinfo(const char *hostname)
1534  {
1535 -  if (*sp == '\0' || *sp == '@')
1536 -    return 0;
1537 -
1538 -  for (; *sp; sp++)
1539 -    {
1540 -      if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/')
1541 -       return 0;
1542 -      if (*sp == '\\' && sp[1])
1543 -       sp++;
1544 -    }
1545 -
1546 -  return 1;
1547 +       struct addrinfo *ai = NULL;
1548 +       struct addrinfo hint = {
1549 +#ifdef IPV6_SUPPORTED
1550 +               .ai_family      = AF_UNSPEC,
1551 +#else
1552 +               .ai_family      = AF_INET,
1553 +#endif
1554 +               /* don't return duplicates */
1555 +               .ai_protocol    = (int)IPPROTO_UDP,
1556 +               .ai_flags       = AI_ADDRCONFIG | AI_CANONNAME,
1557 +       };
1558 +       int error;
1559 +
1560 +       error = getaddrinfo(hostname, NULL, &hint, &ai);
1561 +       switch (error) {
1562 +       case 0:
1563 +               return ai;
1564 +       case EAI_SYSTEM:
1565 +               xlog(D_GENERAL, "%s: failed to resolve %s: (%d) %m",
1566 +                               __func__, hostname, errno);
1567 +               break;
1568 +       default:
1569 +               xlog(D_GENERAL, "%s: failed to resolve %s: %s",
1570 +                               __func__, hostname, gai_strerror(error));
1571 +               break;
1572 +       }
1573 +
1574 +       return NULL;
1575  }
1576  
1577 -int
1578 -matchhostname (const char *h1, const char *h2)
1579 +/**
1580 + * host_canonname - return canonical hostname bound to an address
1581 + * @sap: pointer to socket address to look up
1582 + *
1583 + * Discover the canonical hostname associated with the given socket
1584 + * address.  The host's reverse mapping is verified in the process.
1585 + *
1586 + * Returns a '\0'-terminated ASCII string containing a hostname, or
1587 + * NULL if no hostname can be found for @sap.  Caller must free
1588 + * the string.
1589 + */
1590 +#ifdef HAVE_GETNAMEINFO
1591 +__attribute_malloc__
1592 +char *
1593 +host_canonname(const struct sockaddr *sap)
1594  {
1595 -  struct hostent *hp1, *hp2;
1596 -  int status;
1597 -
1598 -  if (strcasecmp (h1, h2) == 0)
1599 -    return 1;
1600 -
1601 -  if (!is_hostname (h1) || !is_hostname (h2))
1602 -    return 0;
1603 -
1604 -  hp1 = gethostbyname (h1);
1605 -  if (hp1 == NULL)
1606 -    return 0;
1607 -
1608 -  hp1 = hostent_dup (hp1);
1609 -
1610 -  hp2 = gethostbyname (h2);
1611 -  if (hp2)
1612 -    {
1613 -      if (strcasecmp (hp1->h_name, hp2->h_name) == 0)
1614 -       status = 1;
1615 -      else
1616 -       {
1617 -         char **ap1, **ap2;
1618 -
1619 -         status = 0;
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)
1623 -               {
1624 -                 status = 1;
1625 -                 break;
1626 -               }
1627 +       socklen_t salen = nfs_sockaddr_length(sap);
1628 +       char buf[NI_MAXHOST];
1629 +       int error;
1630 +
1631 +       if (salen == 0) {
1632 +               xlog(D_GENERAL, "%s: unsupported address family %d",
1633 +                               __func__, sap->sa_family);
1634 +               return NULL;
1635 +       }
1636 +
1637 +       memset(buf, 0, sizeof(buf));
1638 +       error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
1639 +                                                       NULL, 0, NI_NAMEREQD);
1640 +       switch (error) {
1641 +       case 0:
1642 +               break;
1643 +       case EAI_SYSTEM:
1644 +               xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m",
1645 +                               __func__, errno);
1646 +               return NULL;
1647 +       default:
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));
1652 +               return NULL;
1653         }
1654 -    }
1655 -  else
1656 -    status = 0;
1657  
1658 -  free (hp1);
1659 -  return status;
1660 +       return strdup(buf);
1661  }
1662 +#else  /* !HAVE_GETNAMEINFO */
1663 +__attribute_malloc__
1664 +char *
1665 +host_canonname(const struct sockaddr *sap)
1666 +{
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;
1670 +
1671 +       if (sap->sa_family != AF_INET)
1672 +               return NULL;
1673  
1674 +       hp = gethostbyaddr(addr, (socklen_t)sizeof(addr), AF_INET);
1675 +       if (hp == NULL)
1676 +               return NULL;
1677 +
1678 +       return strdup(hp->h_name);
1679 +}
1680 +#endif /* !HAVE_GETNAMEINFO */
1681  
1682 -/* Map IP to hostname, and then map back to addr to make sure it is a
1683 - * reliable hostname
1684 +/**
1685 + * host_reliable_addrinfo - return addrinfo for a given address
1686 + * @sap: pointer to socket address to look up
1687 + *
1688 + * Reverse and forward lookups are performed to ensure the address has
1689 + * proper forward and reverse mappings.
1690 + *
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).
1694   */
1695 -struct hostent *
1696 -get_reliable_hostbyaddr(const char *addr, int len, int type)
1697 +__attribute_malloc__
1698 +struct addrinfo *
1699 +host_reliable_addrinfo(const struct sockaddr *sap)
1700  {
1701 -       struct hostent *hp = NULL;
1702 +       struct addrinfo *ai;
1703 +       char *hostname;
1704  
1705 -       struct hostent *reverse;
1706 -       struct hostent *forward;
1707 -       char **sp;
1708 -
1709 -       reverse = gethostbyaddr (addr, len, type);
1710 -       if (!reverse)
1711 +       hostname = host_canonname(sap);
1712 +       if (hostname == NULL)
1713                 return NULL;
1714  
1715 -       /* must make sure the hostent is authorative. */
1716 +       ai = host_addrinfo(hostname);
1717  
1718 -       reverse = hostent_dup (reverse);
1719 -       forward = gethostbyname (reverse->h_name);
1720 +       free(hostname);
1721 +       return ai;
1722 +}
1723  
1724 -       if (forward) {
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)
1728 -                               break;
1729 -               }
1730 +/**
1731 + * host_numeric_addrinfo - return addrinfo without doing DNS queries
1732 + * @sap: pointer to socket address
1733 + *
1734 + * Returns address info structure, or NULL if an error occurred.
1735 + * Caller must free the returned structure with freeaddrinfo(3).
1736 + */
1737 +#ifdef HAVE_GETNAMEINFO
1738 +__attribute_malloc__
1739 +struct addrinfo *
1740 +host_numeric_addrinfo(const struct sockaddr *sap)
1741 +{
1742 +       socklen_t salen = nfs_sockaddr_length(sap);
1743 +       char buf[INET6_ADDRSTRLEN];
1744 +       struct addrinfo *ai;
1745 +       int error;
1746 +
1747 +       if (salen == 0) {
1748 +               xlog(D_GENERAL, "%s: unsupported address family %d",
1749 +                               __func__, sap->sa_family);
1750 +               return NULL;
1751 +       }
1752  
1753 -               if (*sp) {
1754 -                       /* it's valid */
1755 -                       hp = hostent_dup (forward);
1756 -               }
1757 -               else {
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));
1761 -               }
1762 +       memset(buf, 0, sizeof(buf));
1763 +       error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
1764 +                                               NULL, 0, NI_NUMERICHOST);
1765 +       switch (error) {
1766 +       case 0:
1767 +               break;
1768 +       case EAI_SYSTEM:
1769 +               xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m",
1770 +                               __func__, errno);
1771 +               return NULL;
1772 +       default:
1773 +               xlog(D_GENERAL, "%s: getnameinfo(3) failed: %s",
1774 +                               __func__, gai_strerror(error));
1775 +               return NULL;
1776         }
1777 -       else {
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));
1781 +
1782 +       ai = host_pton(buf);
1783 +
1784 +       /*
1785 +        * getaddrinfo(AI_NUMERICHOST) never fills in ai_canonname
1786 +        */
1787 +       if (ai != NULL) {
1788 +               free(ai->ai_canonname);         /* just in case */
1789 +               ai->ai_canonname = strdup(buf);
1790 +               if (ai->ai_canonname == NULL) {
1791 +                       freeaddrinfo(ai);
1792 +                       ai = NULL;
1793 +               }
1794         }
1795  
1796 -       free (reverse);
1797 -       return hp;
1798 +       return ai;
1799  }
1800 +#else  /* !HAVE_GETNAMEINFO */
1801 +__attribute_malloc__
1802 +struct addrinfo *
1803 +host_numeric_addrinfo(const struct sockaddr *sap)
1804 +{
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;
1809  
1810 +       if (sap->sa_family != AF_INET)
1811 +               return NULL;
1812  
1813 -#ifdef TEST
1814 -void
1815 -print_host (struct hostent *hp)
1816 -{
1817 -  char **sp;
1818 -
1819 -  if (hp)
1820 -    {
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));
1828 -    }
1829 -  else
1830 -    printf ("Not host information\n");
1831 -}
1832 +       memset(buf, 0, sizeof(buf));
1833 +       if (inet_ntop(AF_INET, (char *)addr, buf,
1834 +                                       (socklen_t)sizeof(buf)) == NULL)
1835 +               return NULL;
1836  
1837 -int
1838 -main (int argc, char **argv)
1839 -{
1840 -  struct hostent *hp = gethostbyname (argv [1]);
1841 -  struct hostent *cp;
1842 -  struct in_addr addr;
1843 -
1844 -  print_host (hp);
1845 -
1846 -  if (hp)
1847 -    {
1848 -      cp = hostent_dup (hp);
1849 -      print_host (cp);
1850 -      free (cp);
1851 -    }
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);
1857 -  print_host (cp);
1858 -  return 0;
1859 +       ai = host_pton(buf);
1860 +
1861 +       /*
1862 +        * getaddrinfo(AI_NUMERICHOST) never fills in ai_canonname
1863 +        */
1864 +       if (ai != NULL) {
1865 +               ai->ai_canonname = strdup(buf);
1866 +               if (ai->ai_canonname == NULL) {
1867 +                       freeaddrinfo(ai);
1868 +                       ai = NULL;
1869 +               }
1870 +       }
1871 +
1872 +       return ai;
1873  }
1874 -#endif
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)
1881  static int
1882  cltsetup(struct nfsctl_client *cltarg, nfs_client *clp)
1883  {
1884 -       int     i;
1885 +       int i, j;
1886  
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];
1896  
1897 +       j = 0;
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;
1902 +       }
1903 +       if (j == 0) {
1904 +               xlog(L_ERROR, "internal: no supported addresses in nfs_client");
1905 +               return 0;
1906 +       }
1907 +
1908 +       cltarg->cl_naddr = j;
1909         return 1;
1910  }
1911  
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
1925 @@ -19,39 +19,54 @@
1926  #include "xio.h"
1927  #include "xlog.h"
1928  
1929 +/*
1930 + * See if the entry already exists.  If not,
1931 + * this was an instantiated wild card, and we
1932 + * must add it.
1933 + */
1934 +static void
1935 +rmtab_read_wildcard(struct rmtabent *rep)
1936 +{
1937 +       nfs_export *exp, *exp2;
1938 +       struct addrinfo *ai;
1939 +
1940 +       ai = host_addrinfo(rep->r_client);
1941 +       if (ai == NULL)
1942 +               return;
1943 +
1944 +       exp = export_allowed(ai, rep->r_path);
1945 +       freeaddrinfo(ai);
1946 +       if (exp == NULL)
1947 +               return;
1948 +
1949 +       exp2 = export_lookup(rep->r_client, exp->m_export.e_path, 0);
1950 +       if (exp2 == NULL) {
1951 +               struct exportent ee;
1952 +
1953 +               memset(&ee, 0, sizeof(ee));
1954 +               dupexportent(&ee, &exp->m_export);
1955 +
1956 +               ee.e_hostname = rep->r_client;
1957 +               exp2 = export_create(&ee, 0);
1958 +               exp2->m_changed = exp->m_changed;
1959 +       }
1960 +       exp2->m_mayexport = 1;
1961 +}
1962 +
1963  int
1964  rmtab_read(void)
1965  {
1966         struct rmtabent         *rep;
1967 -       nfs_export              *exp = NULL;
1968  
1969         setrmtabent("r");
1970         while ((rep = getrmtabent(1, NULL)) != NULL) {
1971 -               struct hostent          *hp = NULL;
1972                 int                     htype;
1973 -               
1974 +
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
1982 -                        */
1983 -                       nfs_export *exp2 = export_lookup(rep->r_client,
1984 -                                                       exp->m_export.e_path, 0);
1985 -                       if (!exp2) {
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;
1991 -                       }
1992 -                       free (hp);
1993 -                       exp2->m_mayexport = 1;
1994 -               } else if (hp) /* export_allowed failed */
1995 -                       free(hp);
1996 +               if (htype == MCL_FQDN || htype == MCL_SUBNETWORK)
1997 +                       rmtab_read_wildcard(rep);
1998         }
1999 +
2000         if (errno == EINVAL) {
2001                 /* Something goes wrong. We need to fix the rmtab
2002                    file. */
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
2007 @@ -10,6 +10,8 @@
2008  #define EXPORTFS_H
2009  
2010  #include <netdb.h>
2011 +
2012 +#include "sockaddr.h"
2013  #include "nfslib.h"
2014  
2015  enum {
2016 @@ -35,11 +37,56 @@ typedef struct mclient {
2017         char *                  m_hostname;
2018         int                     m_type;
2019         int                     m_naddr;
2020 -       struct in_addr          m_addrlist[NFSCLNT_ADDRMAX];
2021 +       union nfs_sockaddr      m_addrlist[NFSCLNT_ADDRMAX];
2022         int                     m_exported;     /* exported to nfsd */
2023         int                     m_count;
2024  } nfs_client;
2025  
2026 +static inline const struct sockaddr *
2027 +get_addrlist(const nfs_client *clp, const int i)
2028 +{
2029 +       return &clp->m_addrlist[i].sa;
2030 +}
2031 +
2032 +static inline const struct sockaddr_in *
2033 +get_addrlist_in(const nfs_client *clp, const int i)
2034 +{
2035 +       return &clp->m_addrlist[i].s4;
2036 +}
2037 +
2038 +static inline const struct sockaddr_in6 *
2039 +get_addrlist_in6(const nfs_client *clp, const int i)
2040 +{
2041 +       return &clp->m_addrlist[i].s6;
2042 +}
2043 +
2044 +static inline void
2045 +set_addrlist_in(nfs_client *clp, const int i, const struct sockaddr_in *sin)
2046 +{
2047 +       memcpy(&clp->m_addrlist[i].s4, sin, sizeof(*sin));
2048 +}
2049 +
2050 +static inline void
2051 +set_addrlist_in6(nfs_client *clp, const int i, const struct sockaddr_in6 *sin6)
2052 +{
2053 +       memcpy(&clp->m_addrlist[i].s6, sin6, sizeof(*sin6));
2054 +}
2055 +
2056 +static inline void
2057 +set_addrlist(nfs_client *clp, const int i, const struct sockaddr *sap)
2058 +{
2059 +       switch (sap->sa_family) {
2060 +       case AF_INET:
2061 +               memcpy(&clp->m_addrlist[i].s4, sap, sizeof(struct sockaddr_in));
2062 +               break;
2063 +#ifdef IPV6_SUPPORTED
2064 +       case AF_INET6:
2065 +               memcpy(&clp->m_addrlist[i].s6, sap, sizeof(struct sockaddr_in6));
2066 +               break;
2067 +#endif
2068 +       }
2069 +}
2070 +
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];
2076  
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);
2097  
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 *);
2115  
2116  int                            secinfo_addflavor(struct flav_info *, struct exportent *);
2117  
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);
2130 +
2131  int                            rmtab_read(void);
2132  
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
2138 @@ -15,13 +15,6 @@
2139  int    randomkey(unsigned char *keyout, int len);
2140  int    weakrandomkey(unsigned char *keyout, int len);
2141  
2142 -int    matchhostname(const char *h1, const char *h2); 
2143 -
2144 -struct hostent;
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);
2148 -
2149  extern int is_mountpoint(char *path);
2150  
2151  #endif /* MISC_H */
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 {
2157         int             e_nsquids;
2158         int *           e_sqgids;
2159         int             e_nsqgids;
2160 -       int             e_fsid;
2161 +       unsigned int    e_fsid;
2162         char *          e_mountpoint;
2163         int             e_fslocmethod;
2164         char *          e_fslocdata;
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);
2172 +
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);
2178  
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);
2187  
2188  void closeall(int min);
2189  
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);
2193 +
2194 +
2195 +#define UNUSED(x) UNUSED_ ## x __attribute__((unused))
2196  
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);
2205  
2206 +/* create AUTH_SYS handle with no supplemental groups */
2207 +extern AUTH *                   nfs_authsys_create(void);
2208 +
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;
2215  
2216  static inline struct sockaddr_in *nfs_getrpccaller_in(SVCXPRT *xprt)
2217  {
2218 -       return (struct sockaddr_in *)svc_getcaller(xprt);
2219 +       return (struct sockaddr_in *)(char *)svc_getcaller(xprt);
2220  }
2221  
2222  static inline struct sockaddr *nfs_getrpccaller(SVCXPRT *xprt)
2223  {
2224 -       return (struct sockaddr *)svc_getcaller(xprt);
2225 +       return (struct sockaddr *)(char *)svc_getcaller(xprt);
2226  }
2227  
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);
2235  }
2236  
2237 +void qword_printuint(FILE *f, unsigned int num)
2238 +{
2239 +       fprintf(f, "%u ", num);
2240 +}
2241 +
2242  int qword_eol(FILE *f)
2243  {
2244         int err;
2245 @@ -236,6 +241,20 @@ int qword_get_int(char **bpp, int *anint)
2246         return 0;
2247  }
2248  
2249 +int qword_get_uint(char **bpp, unsigned int *anint)
2250 +{
2251 +       char buf[50];
2252 +       char *ep;
2253 +       unsigned int rv;
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;
2259 +       *anint = rv;
2260 +       return 0;
2261 +}
2262 +
2263  #define READLINE_BUFFER_INCREMENT 2048
2264  
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);
2269                 if (fd >= 0) {
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));
2274                         }
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
2279 @@ -49,7 +49,7 @@
2280  #include "conffile.h"
2281  #include "xlog.h"
2282  
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 );
2287  
2288 @@ -212,7 +212,7 @@ conf_parse_line(int trans, char *line, size_t sz)
2289  {
2290         char *val, *ptr;
2291         size_t i;
2292 -       int j;
2293 +       size_t j;
2294         static char *section = 0;
2295         static char *arg = 0;
2296         static int ln = 0;
2297 @@ -353,7 +353,7 @@ conf_parse(int trans, char *buf, size_t sz)
2298  }
2299  
2300  static void
2301 -conf_load_defaults(int tr)
2302 +conf_load_defaults(void)
2303  {
2304         /* No defaults */
2305         return;
2306 @@ -412,7 +412,7 @@ conf_reinit(void)
2307                 trans = conf_begin();
2308  
2309         /* Load default configuration values.  */
2310 -       conf_load_defaults(trans);
2311 +       conf_load_defaults();
2312  
2313         /* Free potential existing configuration.  */
2314         if (conf_addr) {
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);
2323 +       if (src->e_uuid)
2324 +               dst->e_uuid = strdup(src->e_uuid);
2325         dst->e_hostname = NULL;
2326  }
2327  
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 @@
2333  #include <errno.h>
2334  #include "nfslib.h"
2335  
2336 +/**
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
2341 + *
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.
2344 + */
2345  struct nfs_fh_len *
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)
2348  {
2349         union nfsctl_res        res;
2350         struct nfsctl_arg       arg;
2351         static struct nfs_fh_len rfh;
2352  
2353 +       if (sin->sin_family != AF_INET) {
2354 +               errno = EAFNOSUPPORT;
2355 +               return NULL;
2356 +       }
2357 +
2358 +       memset(&arg, 0, sizeof(arg));
2359 +       memset(&res, 0, sizeof(res));
2360 +
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));
2367  
2368         if (nfsctl(NFSCTL_GETFH, &arg, &res) < 0)
2369                 return NULL;
2370  
2371 +       memset(&rfh, 0, sizeof(rfh));
2372         rfh.fh_size = 32;
2373         memcpy(rfh.fh_handle, &res.cr_getfh, 32);
2374         return &rfh;
2375  }
2376  
2377 +/**
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
2381 + *
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.
2384 + */
2385  struct nfs_fh_len *
2386 -getfh(struct sockaddr *addr, const char *path)
2387 +getfh(const struct sockaddr_in *sin, const char *path)
2388  {
2389         static union nfsctl_res res;
2390          struct nfsctl_arg       arg;
2391         static struct nfs_fh_len rfh;
2392  
2393 +       if (sin->sin_family != AF_INET) {
2394 +               errno = EAFNOSUPPORT;
2395 +               return NULL;
2396 +       }
2397 +
2398 +       memset(&arg, 0, sizeof(arg));
2399 +       memset(&res, 0, sizeof(res));
2400 +
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));
2408  
2409          if (nfsctl(NFSCTL_GETFD, &arg, &res) < 0)
2410                  return NULL;
2411  
2412 +       memset(&rfh, 0, sizeof(rfh));
2413         rfh.fh_size = 32;
2414         memcpy(rfh.fh_handle, &res.cr_getfh, 32);
2415         return &rfh;
2416  }
2417  
2418 +/**
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
2423 + *
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.
2426 + */
2427  struct nfs_fh_len *
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)
2430  {
2431          static union nfsctl_res res;
2432          struct nfsctl_arg       arg;
2433  
2434 +       if (sin->sin_family != AF_INET) {
2435 +               errno = EAFNOSUPPORT;
2436 +               return NULL;
2437 +       }
2438 +
2439 +       memset(&arg, 0, sizeof(arg));
2440 +       memset(&res, 0, sizeof(res));
2441 +
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;
2449  
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;
2458         char *ss, *sp;
2459 -       int n;
2460 +       unsigned int n;
2461  
2462         n = strlen(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
2468 @@ -19,6 +19,18 @@
2469  #include <signal.h>
2470  #include "nfslib.h"
2471  
2472 +/*
2473 + * Colons in incoming IPv6 presentation addresses have to
2474 + * replaced with another character, since rmtab already
2475 + * uses colons to delineate fields.
2476 + *
2477 + * Use a printable character, but one that would never be
2478 + * found in a presentation address or domain name
2479 + */
2480 +#define IPV6_COLON     ';'
2481 +
2482 +#define LINELEN                (2048)
2483 +
2484  static FILE    *rmfp = NULL;
2485  
2486  int
2487 @@ -56,7 +68,8 @@ struct rmtabent *
2488  fgetrmtabent(FILE *fp, int log, long *pos)
2489  {
2490         static struct rmtabent  re;
2491 -       char    buf[2048], *count, *host, *path;
2492 +       char            *count, *host, *path, *c;
2493 +       static char     buf[LINELEN];
2494  
2495         errno = 0;
2496         if (!fp)
2497 @@ -84,10 +97,16 @@ fgetrmtabent(FILE *fp, int log, long *pos)
2498                 else
2499                         re.r_count = 1;
2500         } while (0);
2501 +
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)
2506 +                       *c = ':';
2507 +
2508         strncpy(re.r_path, path, sizeof (re.r_path) - 1);
2509         re.r_path[sizeof (re.r_path) - 1] = '\0';
2510 +
2511         return &re;
2512  }
2513  
2514 @@ -100,10 +119,27 @@ putrmtabent(struct rmtabent *rep, long *pos)
2515  void
2516  fputrmtabent(FILE *fp, struct rmtabent *rep, long *pos)
2517  {
2518 +       static char     buf[LINELEN];
2519 +       char            *c;
2520 +
2521         if (!fp || (pos && fseek (fp, *pos, SEEK_SET) != 0))
2522                 return;
2523 -       fprintf(fp, "%s:%s:0x%.8x\n", rep->r_client, rep->r_path,
2524 -               rep->r_count);
2525 +
2526 +       /*
2527 +        * To avoid confusing the token parser in fgetrmtabent(),
2528 +        * convert colons in incoming IPv6 presentation addresses
2529 +        * to semicolons.
2530 +        */
2531 +       if (strlen(rep->r_client) > sizeof(buf)) {
2532 +               xlog(L_ERROR, "client name too large");
2533 +               return;
2534 +       }
2535 +       strncpy(buf, rep->r_client, sizeof(buf));
2536 +       for (c = buf; *c != '\0'; c++)
2537 +               if (*c == ':')
2538 +                       *c = IPV6_COLON;
2539 +
2540 +       (void)fprintf(fp, "%s:%s:0x%.8x\n", buf, rep->r_path, rep->r_count);
2541  }
2542  
2543  void
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[])
2549  
2550         return program;
2551  }
2552 +
2553 +/*
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).
2560 + */
2561 +AUTH *
2562 +nfs_authsys_create(void)
2563 +{
2564 +       char machname[MAXHOSTNAMELEN + 1];
2565 +       uid_t   uid = geteuid();
2566 +       gid_t   gid = getegid();
2567 +
2568 +       if (gethostname(machname, sizeof(machname)) == -1)
2569 +               return NULL;
2570 +
2571 +       return authunix_create(machname, uid, gid, 1, &gid);
2572 +}
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,
2578  {
2579         struct rpc_dentry       *dent;
2580  
2581 -       if (rqstp->rq_vers > nvers) {
2582 +       if (((int)rqstp->rq_vers) > nvers) {
2583                 svcerr_progvers(transp, 1, nvers);
2584                 return;
2585         }
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);
2590                 return;
2591         }
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);
2598                 }
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
2611   */
2612  int
2613 -svcudp_socket (u_long number, int reuse)
2614 +svcudp_socket (u_long number)
2615  {
2616 -  return svc_socket (number, SOCK_DGRAM, IPPROTO_UDP, 0);
2617 +  return svc_socket (number, SOCK_DGRAM, IPPROTO_UDP, FALSE);
2618  }
2619  
2620  #ifdef TEST
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);
2624    else
2625 -    socket = svcudp_socket (number, reuse);
2626 +    socket = svcudp_socket (number);
2627  
2628    if (socket < 0)
2629      return 1;
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
2634 @@ -67,7 +67,9 @@
2635  #endif
2636  
2637  #include <sys/types.h>
2638 +#ifdef HAVE_SYS_CAPABILITY_H
2639  #include <sys/capability.h>
2640 +#endif
2641  #include <sys/prctl.h>
2642  #include <sys/stat.h>
2643  
2644 @@ -347,6 +349,7 @@ nsm_is_default_parentdir(void)
2645  static _Bool
2646  nsm_clear_capabilities(void)
2647  {
2648 +#ifdef HAVE_SYS_CAPABILITY_H
2649         cap_t caps;
2650  
2651         caps = cap_from_text("cap_net_bind_service=ep");
2652 @@ -362,6 +365,7 @@ nsm_clear_capabilities(void)
2653         }
2654  
2655         (void)cap_free(caps);
2656 +#endif
2657         return true;
2658  }
2659  
2660 diff --git a/tests/t0001-statd-basic-mon-unmon.sh b/tests/t0001-statd-basic-mon-unmon.sh
2661 old mode 100644
2662 new mode 100755
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
2668  OPTDIRS += rpcgen
2669  endif
2670  
2671 -SUBDIRS = locktest rpcdebug nlmtest $(OPTDIRS)
2672 +SUBDIRS = locktest rpcdebug nlmtest mountstats nfs-iostat $(OPTDIRS)
2673  
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
2678 --- /dev/null
2679 +++ b/tools/mountstats/Makefile.am
2680 @@ -0,0 +1,13 @@
2681 +## Process this file with automake to produce Makefile.in
2682 +PYTHON_FILES =  mountstats.py
2683 +
2684 +man8_MANS      = mountstats.man
2685 +
2686 +EXTRA_DIST     = $(man8_MANS) $(PYTHON_FILES)
2687 +
2688 +all-local: $(PYTHON_FILES)
2689 +
2690 +install-data-hook:
2691 +       $(INSTALL) --mode 755 mountstats.py $(DESTDIR)$(sbindir)/mountstats
2692 +
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
2697 --- /dev/null
2698 +++ b/tools/mountstats/mountstats.man
2699 @@ -0,0 +1,32 @@
2700 +.\"
2701 +.\" mountstats(8)
2702 +.\"
2703 +.TH mountstats 8 "15 Apr 2010"
2704 +.SH NAME
2705 +mountstats \- Displays NFS client per-mount statistics
2706 +.SH SYNOPSIS
2707 +.BI "mountstats ["<options> "] " <mount_point> " [ " <mount_point> "]" 
2708 +.SH DESCRIPTION
2709 +The
2710 +.B mountstats
2711 +command displays NFS client statisitics on each given
2712 +.I <mount_point>
2713 +.SH OPTIONS
2714 +.TP
2715 +.B " \-\-nfs
2716 +display only the NFS statistics
2717 +.TP
2718 +.B " \-\-rpc 
2719 +display only the RPC statistics
2720 +.TP
2721 +.B " \-\-version 
2722 +display the version of this command
2723 +.SH FILES
2724 +.TP
2725 +.B /proc/self/mountstats
2726 +.SH SEE ALSO
2727 +.BR iostat (8),
2728 +.BR nfsiostat (8),
2729 +.BR nfsstat(8)
2730 +.SH AUTHOR
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
2735 --- /dev/null
2736 +++ b/tools/nfs-iostat/Makefile.am
2737 @@ -0,0 +1,13 @@
2738 +## Process this file with automake to produce Makefile.in
2739 +PYTHON_FILES =  nfs-iostat.py
2740 +
2741 +man8_MANS      = nfsiostat.man
2742 +
2743 +EXTRA_DIST     = $(man8_MANS) $(PYTHON_FILES)
2744 +
2745 +all-local: $(PYTHON_FILES)
2746 +
2747 +install-data-hook:
2748 +       $(INSTALL) --mode 755 nfs-iostat.py $(DESTDIR)$(sbindir)/nfsiostat
2749 +
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.
2762 +        #
2763 +        if sample_time == 0:
2764 +            sample_time = 1;
2765          if sends != 0:
2766              backlog = (float(self.__rpc_data['backlogutil']) / sends) / sample_time
2767          else:
2768 diff --git a/tools/nfs-iostat/nfsiostat.man b/tools/nfs-iostat/nfsiostat.man
2769 new file mode 100644
2770 index 0000000..99e04fb
2771 --- /dev/null
2772 +++ b/tools/nfs-iostat/nfsiostat.man
2773 @@ -0,0 +1,71 @@
2774 +.\"
2775 +.\" nfsiostat(8)
2776 +.\"
2777 +.TH nfsiostat 8 "15 Apr 2010"
2778 +.SH NAME
2779 +nfsiostat \- Emulate iostat for NFS mount points using /proc/self/mountstats
2780 +.SH SYNOPSIS
2781 +.BI "nfsiostat [[" <interval> "] [" <count> "]] [" <options> "]["<mount_point> "]
2782 +.SH DESCRIPTION
2783 +The
2784 +.B nfsiostat
2785 +command displays NFS client per-mount statisitics. 
2786 +.TP 
2787 +<interval>
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.
2792 +.TP
2793 +<count>
2794 +If the
2795 +.I <count>
2796 +parameter is
2797 +specified, the value of 
2798 +.I <count> 
2799 +determines the number of reports generated at
2800 +. <interval> 
2801 +seconds apart. if the interval parameter is 
2802 +specified without the
2803 +.I <count> 
2804 +parameter, the command generates reports continuously.
2805 +.TP
2806 +<options>
2807 +Define below
2808 +.TP
2809 +<mount_point>
2810 +If one or more
2811 +.I <mount point> 
2812 +names are specified, statistics for only these mount points will
2813 +be displayed.  Otherwise, all NFS mount points on the client are listed.
2814 +.SH OPTIONS
2815 +.TP
2816 +.B \-a " or " \-\-attr
2817 +displays statistics related to the attribute cache
2818 +.TP
2819 +.B \-d " or " \-\-dir 
2820 +displays statistics related to directory operations
2821 +.TP
2822 +.B \-h " or " \-\-help 
2823 +shows help message and exit
2824 +.TP
2825 +.B \-l LIST or " \-\-list=LIST 
2826 +only print stats for first LIST mount points
2827 +.TP
2828 +.B \-p " or " \-\-page
2829 +displays statistics related to the page cache
2830 +.TP
2831 +.B \-s " or " \-\-sort
2832 +Sort NFS mount points by ops/second
2833 +.TP
2834 +.B \-\-version
2835 +show program's version number and exit
2836 +.SH FILES
2837 +.TP
2838 +.B /proc/self/mountstats
2839 +.SH SEE ALSO
2840 +.BR iostat (8),
2841 +.BR mountstats (8),
2842 +.BR nfsstat(8)
2843 +.SH AUTHOR
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
2849 @@ -12,20 +12,24 @@
2850  #include <config.h>
2851  #endif
2852  
2853 +#include <sys/types.h>
2854 +#include <sys/stat.h>
2855  #include <sys/vfs.h>
2856  #include <sys/stat.h>
2857  #include <unistd.h>
2858 +#include <stdbool.h>
2859  #include <stdlib.h>
2860  #include <string.h>
2861  #include <stdarg.h>
2862  #include <getopt.h>
2863 +#include <fcntl.h>
2864  #include <netdb.h>
2865  #include <errno.h>
2866 -#include "xmalloc.h"
2867 +
2868 +#include "sockaddr.h"
2869  #include "misc.h"
2870  #include "nfslib.h"
2871  #include "exportfs.h"
2872 -#include "xmalloc.h"
2873  #include "xlog.h"
2874  
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);
2884  
2885  int
2886  main(int argc, char **argv)
2887  {
2888         char    *options = NULL;
2889 +       char    *progname = NULL;
2890         int     f_export = 1;
2891         int     f_all = 0;
2892         int     f_verbose = 0;
2893 @@ -50,7 +56,14 @@ main(int argc, char **argv)
2894         int     new_cache = 0;
2895         int     force_flush = 0;
2896  
2897 -       xlog_open("exportfs");
2898 +       if ((progname = strrchr(argv[0], '/')) != NULL)
2899 +               progname++;
2900 +       else
2901 +               progname = argv[0];
2902 +
2903 +       xlog_open(progname);
2904 +       xlog_stderr(1);
2905 +       xlog_syslog(0);
2906  
2907         export_errno = 0;
2908  
2909 @@ -79,21 +92,21 @@ main(int argc, char **argv)
2910                         force_flush = 1;
2911                         break;
2912                 default:
2913 -                       usage();
2914 +                       usage(progname);
2915                         break;
2916                 }
2917         }
2918  
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");
2922                 return 1;
2923         }
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");
2927                 return 1;
2928         }
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");
2932                 return 1;
2933         }
2934         new_cache = check_new_cache();
2935 @@ -102,8 +115,10 @@ main(int argc, char **argv)
2936                         if (new_cache)
2937                                 cache_flush(1);
2938                         else {
2939 -                               fprintf(stderr, "exportfs: -f: only available with new cache controls: mount /proc/fs/nfsd first\n");
2940 -                               exit(1);
2941 +                               xlog(L_ERROR, "-f is available only "
2942 +                                       "with new cache controls. "
2943 +                                       "Mount /proc/fs/nfsd first");
2944 +                               return 1;
2945                         }
2946                         return 0;
2947                 } else {
2948 @@ -232,7 +247,7 @@ exportfs(char *arg, char *options, int verbose)
2949  {
2950         struct exportent *eep;
2951         nfs_export      *exp;
2952 -       struct hostent  *hp = NULL;
2953 +       struct addrinfo *ai = NULL;
2954         char            *path;
2955         char            *hname = arg;
2956         int             htype;
2957 @@ -241,36 +256,25 @@ exportfs(char *arg, char *options, int verbose)
2958                 *path++ = '\0';
2959  
2960         if (!path || *path != '/') {
2961 -               fprintf(stderr, "Invalid exporting option: %s\n", arg);
2962 +               xlog(L_ERROR, "Invalid exporting option: %s", arg);
2963                 return;
2964         }
2965  
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,
2970 -                                  hp2->h_addrtype);
2971 -               if (hp) {
2972 -                       free(hp2);
2973 -                       hp = hostent_dup(hp);
2974 -               } else
2975 -                       hp = hp2;
2976 -               exp = export_find(hp, path);
2977 -               hname = hp->h_name;
2978 -       } else {
2979 +       if ((htype = client_gettype(hname)) == MCL_FQDN) {
2980 +               ai = host_addrinfo(hname);
2981 +               if (ai != NULL) {
2982 +                       exp = export_find(ai, path);
2983 +                       hname = ai->ai_canonname;
2984 +               }
2985 +       } else
2986                 exp = export_lookup(hname, path, 0);
2987 -       }
2988  
2989         if (!exp) {
2990                 if (!(eep = mkexportent(hname, path, options)) ||
2991 -                   !(exp = export_create(eep, 0))) {
2992 -                       if (hp) free (hp);
2993 -                       return;
2994 -               }
2995 -       } else if (!updateexportent(&exp->m_export, options)) {
2996 -               if (hp) free (hp);
2997 -               return;
2998 -       }
2999 +                   !(exp = export_create(eep, 0)))
3000 +                       goto out;
3001 +       } else if (!updateexportent(&exp->m_export, options))
3002 +               goto out;
3003  
3004         if (verbose)
3005                 printf("exporting %s:%s\n", exp->m_client->m_hostname, 
3006 @@ -280,14 +284,16 @@ exportfs(char *arg, char *options, int verbose)
3007         exp->m_changed = 1;
3008         exp->m_warned = 0;
3009         validate_export(exp);
3010 -       if (hp) free (hp);
3011 +
3012 +out:
3013 +       freeaddrinfo(ai);
3014  }
3015  
3016  static void
3017  unexportfs(char *arg, int verbose)
3018  {
3019         nfs_export      *exp;
3020 -       struct hostent  *hp = NULL;
3021 +       struct addrinfo *ai = NULL;
3022         char            *path;
3023         char            *hname = arg;
3024         int             htype;
3025 @@ -296,16 +302,14 @@ unexportfs(char *arg, int verbose)
3026                 *path++ = '\0';
3027  
3028         if (!path || *path != '/') {
3029 -               fprintf(stderr, "Invalid unexporting option: %s\n",
3030 -                       arg);
3031 +               xlog(L_ERROR, "Invalid unexporting option: %s", arg);
3032                 return;
3033         }
3034  
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;
3039 -               }
3040 +               ai = host_addrinfo(hname);
3041 +               if (ai)
3042 +                       hname = ai->ai_canonname;
3043         }
3044  
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;
3048         }
3049  
3050 -       if (hp) free (hp);
3051 +       freeaddrinfo(ai);
3052  }
3053  
3054  static int can_test(void)
3055 @@ -393,14 +397,12 @@ validate_export(nfs_export *exp)
3056         int fs_has_fsid = 0;
3057  
3058         if (stat(path, &stb) < 0) {
3059 -               fprintf(stderr, "exportfs: Warning: %s does not exist\n",
3060 -                       path);
3061 +               xlog(L_ERROR, "Failed to stat %s: %m \n", path);
3062                 return;
3063         }
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);
3070                 return;
3071         }
3072         if (!can_test())
3073 @@ -413,24 +415,75 @@ validate_export(nfs_export *exp)
3074         if ((exp->m_export.e_flags & NFSEXP_FSID) || exp->m_export.e_uuid ||
3075             fs_has_fsid) {
3076                 if ( !test_export(path, 1)) {
3077 -                       fprintf(stderr, "exportfs: Warning: %s does not "
3078 -                               "support NFS export.\n",
3079 -                               path);
3080 +                       xlog(L_ERROR, "%s does not support NFS export", path);
3081                         return;
3082                 }
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);
3088                 else
3089 -                       fprintf(stderr, "exportfs: Warning: %s does not "
3090 -                               "support NFS export.\n",
3091 -                               path);
3092 +                       xlog(L_ERROR, "%s does not support NFS export", path);
3093                 return;
3094  
3095         }
3096  }
3097  
3098 +static _Bool
3099 +is_hostname(const char *sp)
3100 +{
3101 +       if (*sp == '\0' || *sp == '@')
3102 +               return false;
3103 +
3104 +       for (; *sp != '\0'; sp++) {
3105 +               if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/')
3106 +                       return false;
3107 +               if (*sp == '\\' && sp[1] != '\0')
3108 +                       sp++;
3109 +       }
3110 +
3111 +       return true;
3112 +}
3113 +
3114 +static int
3115 +matchhostname(const char *hostname1, const char *hostname2)
3116 +{
3117 +       struct addrinfo *results1 = NULL, *results2 = NULL;
3118 +       struct addrinfo *ai1, *ai2;
3119 +       int result = 0;
3120 +
3121 +       if (strcasecmp(hostname1, hostname2) == 0)
3122 +               return 1;
3123 +
3124 +       /*
3125 +        * Don't pass export wildcards or netgroup names to DNS
3126 +        */
3127 +       if (!is_hostname(hostname1) || !is_hostname(hostname2))
3128 +               return 0;
3129 +
3130 +       results1 = host_addrinfo(hostname1);
3131 +       if (results1 == NULL)
3132 +               goto out;
3133 +       results2 = host_addrinfo(hostname2);
3134 +       if (results2 == NULL)
3135 +               goto out;
3136 +
3137 +       if (strcasecmp(results1->ai_canonname, results2->ai_canonname) == 0) {
3138 +               result = 1;
3139 +               goto out;
3140 +       }
3141 +
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)) {
3145 +                               result = 1;
3146 +                               break;
3147 +                       }
3148 +
3149 +out:
3150 +       freeaddrinfo(results1);
3151 +       freeaddrinfo(results2);
3152 +       return result;
3153 +}
3154  
3155  static char
3156  dumpopt(char c, char *fmt, ...)
3157 @@ -532,13 +585,13 @@ dump(int verbose)
3158  static void
3159  error(nfs_export *exp, int err)
3160  {
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));
3164  }
3165  
3166  static void
3167 -usage(void)
3168 +usage(const char *progname)
3169  {
3170 -       fprintf(stderr, "usage: exportfs [-aruv] [host:/path]\n");
3171 +       fprintf(stderr, "usage: %s [-aruv] [host:/path]\n", progname);
3172         exit(1);
3173  }
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
3178 @@ -1,11 +1,11 @@
3179 +.\"@(#)exportfs.8"
3180  .\"
3181 -.\" exportfs(8)
3182 -.\" 
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"
3186 +.\"
3187 +.TH exportfs 8 "31 December 2009"
3188  .SH NAME
3189 -exportfs \- maintain list of NFS exported file systems
3190 +exportfs \- maintain table of exported NFS file systems
3191  .SH SYNOPSIS
3192  .BI "/usr/sbin/exportfs [-avi] [-o " "options,.." "] [" "client:/path" " ..]
3193  .br
3194 @@ -18,229 +18,236 @@ exportfs \- maintain list of NFS exported file systems
3195  .BI "/usr/sbin/exportfs -f"
3196  .br
3197  .SH DESCRIPTION
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" ,
3202 +or
3203 +.IR export ,
3204 +for short.
3205 +.PP
3206  The
3207  .B exportfs
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
3211 -which is read by
3212 -.B mountd
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.
3215 -.P
3216 -Normally this 
3217 -.B etab
3218 -file is initialized with the list of all file systems named in
3219 -.B /etc/exports 
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
3224 +.B rpc.mountd
3225 +when a client sends an NFS MOUNT request.
3226 +.PP
3227 +Normally the master export table is initialized with the contents of
3228 +.I /etc/exports
3229  by invoking
3230  .BR "exportfs -a" .
3231 -.P
3232 -However, administrators can choose to add and delete individual file systems
3233 -without modifying
3234 -.B /etc/exports
3235 -using
3236 -.BR exportfs .
3237 -.P
3238 +However, a system administrator can choose to add or delete
3239 +exports without modifying
3240 +.I /etc/exports
3241 +by using the
3242 +.B exportfs
3243 +command.
3244 +.PP
3245  .B exportfs
3246 -and it's partner program
3247 -.B mountd
3248 -work in one of two modes, a legacy mode which applies to 2.4 and
3249 +and its partner program
3250 +.B rpc.mountd
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
3255  .B nfsd
3256  virtual filesystem has been mounted at
3257 -.B /proc/fs/nfsd
3258 +.I /proc/fs/nfsd
3259  or
3260 -.BR /proc/fs/nfs .
3261 -If this filesystem is not mounted in 2.6, the legacy mode is used.
3262 -.P
3263 +.IR /proc/fs/nfs .
3264 +On 2.6 kernels, if this filesystem is not mounted, the legacy mode is used.
3265 +.PP
3266  In the new mode,
3267  .B exportfs
3268 -does not give any information to the kernel but only provides it to
3269 -.B mountd
3270 +does not give any information to the kernel, but provides it only to
3271 +.B rpc.mountd
3272  through the
3273 -.B /var/lib/nfs/etab
3274 +.I /var/lib/nfs/etab
3275  file.
3276 -.B mountd
3277 -will listen to requests from the kernel and will provide information
3278 -as needed.
3279 -.P
3280 +.B rpc.mountd
3281 +then manages kernel requests for information about exports, as needed.
3282 +.PP
3283  In the legacy mode,
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
3298 -.B rmtab
3299 -to be entered
3300 -into the kernel's export table.
3301 +.I rmtab
3302 +to be added to the kernel's export table.
3303  .SH OPTIONS
3304 -.TP 
3305 +.TP
3306  .B -a
3307  Export or unexport all directories.
3308  .TP
3309  .BI "-o " options,...
3310  Specify a list of export options in the same manner as in
3311 -.BR exports(5) .
3312 +.BR exports (5).
3313  .TP
3314  .B -i
3315  Ignore the
3316 -.B /etc/exports
3317 -file, so that only default options and options given on the command
3318 -line are used.
3319 +.I /etc/exports
3320 +file.  Only default options and options given on the command line are used.
3321  .TP
3322  .B -r
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
3328 +with
3329 +.IR /etc/exports .
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.
3335  .TP
3336  .B -u
3337  Unexport one or more directories.
3338  .TP
3339  .B -f
3340 -In 'new' mode, flush everything out of the kernels export table. Any
3341 -clients that are active will get new entries added by
3342 -.B mountd
3343 -when they make their next request.
3344 +If
3345 +.I /proc/fs/nfsd
3346 +or
3347 +.I /proc/fs/nfs
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
3350 +.B rpc.mountd
3351 +when they make their next NFS mount request.
3352  .TP
3353  .B -v
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
3356  options.
3357  .SH DISCUSSION
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
3363 +.B exportfs
3364 +when adding new entries to the export table.  When using
3365  .BR "exportfs -a" ,
3366 -all directories in
3367 -.B exports(5)
3368 +all exports listed in
3369 +.I /etc/exports
3370  are added to
3371 -.B etab
3372 -and the resulting list is pushed into the kernel.
3373 -.P
3374 +.IR /var/lib/nfs/etab .
3375 +The kernel's export table is also updated as needed.
3376 +.PP
3377  The
3378  .I host:/path
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.
3383 +See
3384  .B exports(5)
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
3388  .IR :/path .
3389 -.P
3390 +.PP
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
3393 -entries in
3394 -.B /etc/exports
3395 -(unless the
3396 -.B -i
3397 -option is given).
3398 -In addition, the administrator may override any options from these sources
3399 -using the
3400 +several sources.
3401 +The default export options are
3402 +.BR sync,ro,root_squash,wdelay .
3403 +These can be overridden by entries in
3404 +.IR /etc/exports .
3405 +.PP
3406 +A system administrator may override options from these sources using the
3407  .B -o
3408 -argument which takes a comma-separated list of options in the same fashion
3409 +command-line option on
3410 +.BR exportfs .
3411 +This option takes a comma-separated list of options in the same fashion
3412  as one would specify them in
3413 -.BR exports(5) .
3414 -Thus,
3415 +.IR /etc/exports .
3416 +In this way
3417  .B exportfs
3418 -can also be used to modify the export options of an already exported
3419 -directory.
3420 -.P
3421 -Modifications of the kernel export table used by
3422 -.B nfsd(8)
3423 -take place immediately after parsing the command line and updating the
3424 -.B etab
3425 -file.
3426 -.P
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.
3433  When using
3434  .BR "exportfs -ua" ,
3435  all entries listed in
3436 -.B etab
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.
3440 -.P
3441 -To remove an export to a host, specify a
3442 +.PP
3443 +To remove an export, specify a
3444  .I host:/path
3445  pair. This deletes the specified entry from
3446 -.B etab
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" .
3451 -.P
3452 -.\" -------------------- Dumping the Export Table -----------------
3453 -.SS Dumping the Export Table 
3454 +.PP
3455 +.SS Dumping the Export Table
3456  Invoking
3457  .B exportfs
3458 -without further options shows the current list of exported file systems.
3459 -When giving the
3460 +without options shows the current list of exported file systems.
3461 +Adding the
3462  .B -v
3463 -option, the list of flags pertaining to each export are shown in addition.
3464 -.\" -------------------- EXAMPLES ---------------------------------
3465 +option causes
3466 +.B exportfs
3467 +to display the export options for each export.
3468  .SH EXAMPLES
3469  The following adds all directories listed in
3470 -.B /etc/exports
3471 +.I /etc/exports
3472  to
3473 -.B /var/lib/nfs/etab
3474 +.I /var/lib/nfs/etab
3475  and pushes the resulting export entries into the kernel:
3476 -.P
3477 +.PP
3478  .nf
3479  .B "# exportfs -a
3480  .fi
3481 -.P
3482 +.PP
3483  To export the
3484 -.B /usr/tmp
3485 -directory to host 
3486 +.I /usr/tmp
3487 +directory to host
3488  .BR django ,
3489 -allowing asynchronous writes, one would do this:
3490 -.P
3491 +allowing insecure file locking requests from clients:
3492 +.PP
3493  .nf
3494 -.B "# exportfs -o async django:/usr/tmp
3495 +.B "# exportfs -o insecure_locks django:/usr/tmp
3496  .fi
3497 -.P
3498 +.PP
3499  To unexport the
3500 -.B /usr/tmp
3501 +.I /usr/tmp
3502  directory:
3503 -.P
3504 +.PP
3505  .nf
3506  .B "# exportfs -u django:/usr/tmp
3507  .fi
3508 -.P
3509 -To unexport all the directories listed in
3510 -.B /etc/exports:
3511 -.P
3512 +.PP
3513 +To unexport all exports listed in
3514 +.IR /etc/exports :
3515 +.PP
3516  .nf
3517  .B "# exportfs -au
3518  .fi
3519 -.\" -------------------- DEPENDENCIES -----------------------------
3520 -.SH 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
3524 -.B mountd(8)
3525 +.SH USAGE NOTES
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
3529 +.BR rpc.mountd (8)
3530  to grant any mount requests from these clients.
3531 -This is usually not a big problem, because any existing mounts are preserved
3532 -in
3533 -.B rmtab
3534 +This is usually not a problem, because any existing mounts are preserved in
3535 +.I rmtab
3536  across reboots.
3537 -.P
3538 +.PP
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.
3542 -.P
3543 -.\" -------------------- SEE ALSO --------------------------------
3544 +.SH FILES
3545 +.TP 2.5i
3546 +.I /etc/exports
3547 +input file listing exports, export options, and access control lists
3548 +.TP 2.5i
3549 +.I /var/lib/nfs/etab
3550 +master table of exports
3551 +.TP 2.5i
3552 +.I /var/lib/nfs/rmtab
3553 +table of clients accessing server's exports
3554  .SH SEE ALSO
3555 -.BR exports(5) ", " mountd(8)
3556 -.\" -------------------- AUTHOR ----------------------------------
3557 +.BR exports (5),
3558 +.BR rpc.mountd (8),
3559 +.BR netgroup (5)
3560  .SH AUTHORS
3561 -Olaf Kirch, <okir@monad.swb.de>
3562 +Olaf Kirch <okir@monad.swb.de>
3563  .br
3564 -Neil Brown, <neilb@cse.unsw.edu.au>
3565 -
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
3571 @@ -1,18 +1,22 @@
3572 -.TH EXPORTS 5 "4 March 2005" "Linux" "Linux File Formats Manual"
3573 +.\"@(#)exports.5"
3574 +.\"
3575 +.TH exports 5 "31 December 2009"
3576  .SH NAME
3577 -exports \- NFS file systems being exported (for Kernel based NFS)
3578 -.SH SYNOPSIS
3579 -.B /etc/exports
3580 +exports \- NFS server export table
3581  .SH DESCRIPTION
3582  The file
3583  .I /etc/exports
3584 -serves as the access control list for file systems which may be
3585 -exported to NFS clients.  It is used by
3586 -.IR exportfs (8)
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
3590 +administrator.
3591 +.PP
3592 +Each file system in this table has a list of options and an
3593 +access control list.
3594 +The table is used by
3595 +.BR exportfs (8)
3596  to give information to
3597 -.IR mountd (8)
3598 -and to the kernel based NFS file server daemon
3599 -.IR nfsd (8).
3600 +.BR mountd (8).
3601  .PP
3602  The file format is similar to the SunOS
3603  .I exports
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
3606  octal digits.
3607  .PP
3608 -To apply changes to this file, run exportfs \-ra or restart the NFS server.
3609 +To apply changes to this file, run
3610 +.BR exportfs \-ra
3611 +or restart the NFS server.
3612  .PP
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
3616  as
3617  .IR address/netmask
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.
3627  '''.TP
3628  '''.B =public
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.
3631  .PP
3632  .SS General Options
3633 -.IR exportfs
3634 +.BR exportfs
3635  understands the following export options:
3636  .TP
3637  .IR secure "\*d
3638 @@ -144,7 +151,8 @@ default.  In all releases after 1.0.0,
3639  is the default, and
3640  .I async
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,
3644 +.B exportfs
3645  will issue a warning if neither
3646  .I sync
3647  nor
3648 @@ -188,7 +196,7 @@ The
3649  option is currently only effective on
3650  .I "single host
3651  exports.  It does not work reliably with netgroup, subnet, or wildcard
3652 -exports. 
3653 +exports.
3654  
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
3658  that option in the
3659  .B exports
3660  file.  If you put neither option,
3661 -.I exportfs
3662 +.B exportfs
3663  will warn you that the change is pending.
3664  
3665  .TP
3666 @@ -272,7 +280,9 @@ or
3667  .TP
3668  .IR no_acl
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
3672 +.B nfsd
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.)
3678  
3679  .SS User ID Mapping
3680  .PP
3681 -.I nfsd
3682 +.B nfsd
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 .
3688  .PP
3689  By default,
3690 -'''.I nfsd
3691 +'''.B nfsd
3692  '''tries to obtain the anonymous uid and gid by looking up user
3693  '''.I nobody
3694  '''in the password file at startup time. If it isn't found, a uid and gid
3695 -.I exportfs
3696 +.B exportfs
3697  chooses a uid and gid
3698  of 65534 for squashed access. These values can also be overridden by
3699  the
3700  .IR anonuid " and " anongid
3701  options.
3702  '''.PP
3703 -'''In addition to this, 
3704 -'''.I nfsd
3705 +'''In addition to this,
3706 +'''.B nfsd
3707  '''lets you specify arbitrary uids and gids that should be mapped to user
3708  '''nobody as well.
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
3713  user
3714 -.IR bin 
3715 +.IR bin
3716  or group
3717  .IR staff .
3718  .TP
3719 @@ -434,7 +444,7 @@ Turn off root squashing. This option is mainly useful for diskless clients.
3720  .IR all_squash
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
3723 -is 
3724 +is
3725  .IR no_all_squash ,
3726  which is the default setting.
3727  .TP
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
3732 -.I insecure 
3733 +.I insecure
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.
3739  '''.SH CAVEATS
3740  '''Unlike other NFS server implementations, this
3741 -'''.I nfsd
3742 +'''.B nfsd
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
3750  '''.IR /usr/X11R6 ,
3751 -'''the mount options given in the 
3752 -'''.I /usr/X11R6 
3753 +'''the mount options given in the
3754 +'''.I /usr/X11R6
3755  '''entry apply. This is also true when the latter is a wildcard or netgroup
3756  '''entry.
3757  .SH FILES
3758 @@ -499,7 +509,15 @@ all three mounts with the `sync' option enabled.
3759  .BR showmount (8).
3760  '''.SH DIAGNOSTICS
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
3764 +'''.BR nfsd (8)
3765 +'''or
3766 +'''.BR mountd (8)
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.
3771 +'''to
3772 +'''.BR named (8)
3773 +'''at boot time, thus as hosts are found they are reported
3774 +'''with the same
3775 +'''.BR syslogd (8)
3776 +'''parameters.
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
3781 @@ -1,5 +1,5 @@
3782  /*
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.
3786  
3787    Redistribution and use in source and binary forms, with or without
3788 @@ -36,6 +36,10 @@
3789  /* Hopefully big enough to hold any serialized context */
3790  #define MAX_CTX_LEN 4096
3791  
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
3796  
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
3803 @@ -42,6 +42,7 @@
3804  #include <stdio.h>
3805  #include <syslog.h>
3806  #include <string.h>
3807 +#include <errno.h>
3808  
3809  #include <gssapi/gssapi_krb5.h>
3810  
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;
3815 -       int i;
3816 +       uint32_t i;
3817         char *skd, *dkd;
3818         gss_buffer_desc fakeoid;
3819  
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.
3822          */
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;
3830         }
3831  #endif
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);
3838  
3839         /* derive the encryption key and copy it into buffer */
3840 @@ -158,11 +157,102 @@ out_err:
3841         return -1;
3842  }
3843  
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
3848 +
3849 +/*
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.
3852 + *
3853 + * The new format is:
3854 + *
3855 + *     u32 flags;
3856 + *     #define KRB5_CTX_FLAG_INITIATOR         0x00000001
3857 + *     #define KRB5_CTX_FLAG_CFX               0x00000002
3858 + *     #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY   0x00000004
3859 + *     s32 endtime;
3860 + *     u64 seq_send;
3861 + *     u32  enctype;                   ( encrption type of key )
3862 + *     raw key;                        ( raw key bytes (kernel will derive))
3863 + *
3864 + */
3865  static int
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)
3869  {
3870 -       printerr(0, "ERROR: prepare_krb5_rfc_cfx_buffer: not implemented\n");
3871 +       char *p, *end;
3872 +       uint32_t v2_flags = 0;
3873 +       uint32_t enctype;
3874 +       uint32_t keysize;
3875 +
3876 +       if (!(buf->value = calloc(1, MAX_CTX_LEN)))
3877 +               goto out_err;
3878 +       p = buf->value;
3879 +       end = buf->value + MAX_CTX_LEN;
3880 +
3881 +       /* Version 2 */
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;
3888 +
3889 +       if (WRITE_BYTES(&p, end, v2_flags)) goto out_err;
3890 +       if (WRITE_BYTES(&p, end, lctx->endtime)) goto out_err;
3891 +       if (endtime)
3892 +               *endtime = lctx->endtime;
3893 +       if (WRITE_BYTES(&p, end, lctx->send_seq)) goto out_err;
3894 +
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;
3900 +       } else {
3901 +               if (lctx->cfx_kd.have_acceptor_subkey) {
3902 +                       enctype = lctx->cfx_kd.acceptor_subkey.type;
3903 +                       keysize = lctx->cfx_kd.acceptor_subkey.length;
3904 +               } else {
3905 +                       enctype = lctx->cfx_kd.ctx_key.type;
3906 +                       keysize = lctx->cfx_kd.ctx_key.length;
3907 +               }
3908 +       }
3909 +       printerr(2, "%s: serializing key with enctype %d and size %d\n",
3910 +                __FUNCTION__, enctype, keysize);
3911 +
3912 +       if (WRITE_BYTES(&p, end, enctype)) goto out_err;
3913 +
3914 +       if (lctx->protocol == 0) {
3915 +               if (write_bytes(&p, end, lctx->rfc1964_kd.ctx_key.data,
3916 +                               lctx->rfc1964_kd.ctx_key.length))
3917 +                       goto out_err;
3918 +       } else {
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))
3923 +                               goto out_err;
3924 +               } else {
3925 +                       if (write_bytes(&p, end, lctx->cfx_kd.ctx_key.data,
3926 +                                       lctx->cfx_kd.ctx_key.length))
3927 +                               goto out_err;
3928 +               }
3929 +       }
3930 +
3931 +       buf->length = p - (char *)buf->value;
3932 +       return 0;
3933 +
3934 +out_err:
3935 +       printerr(0, "ERROR: %s: failed serializing krb5 context for kernel\n",
3936 +                __FUNCTION__);
3937 +       if (buf->value) {
3938 +               free(buf->value);
3939 +               buf->value = NULL;
3940 +       }
3941 +       buf->length = 0;
3942         return -1;
3943  }
3944  
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;
3947         int retcode = 0;
3948  
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,
3952                                                 1, &return_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)
3955                 break;
3956         }
3957  
3958 -       /* Now lctx points to a lucid context that we can send down to kernel */
3959 -       if (lctx->protocol == 0)
3960 +       /*
3961 +        * Now lctx points to a lucid context that we can send down to kernel
3962 +        *
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.
3968 +        */
3969 +
3970 +       if (lctx->protocol == 0 && lctx->rfc1964_kd.ctx_key.type <= 4)
3971                 retcode = prepare_krb5_rfc1964_buffer(lctx, buf, endtime);
3972         else
3973 -               retcode = prepare_krb5_rfc_cfx_buffer(lctx, buf, endtime);
3974 +               retcode = prepare_krb5_rfc4121_buffer(lctx, buf, endtime);
3975  
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)
3979         }
3980  
3981         if (retcode) {
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);
3986                 goto out_err;
3987         }
3988  
3989 @@ -223,4 +322,7 @@ out_err:
3990         printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
3991         return -1;
3992  }
3993 +
3994 +
3995 +
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
4001 @@ -1,5 +1,5 @@
4002  /*
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.
4006  
4007    Redistribution and use in source and binary forms, with or without
4008 @@ -38,6 +38,7 @@
4009  #include <stdio.h>
4010  #include <syslog.h>
4011  #include <string.h>
4012 +#include <errno.h>
4013  #include <gssapi/gssapi.h>
4014  #include <rpc/rpc.h>
4015  #include <rpc/auth_gss.h>
4016 @@ -52,8 +53,7 @@
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 :-/
4020 - *
4021 - * XXX Does this match the Heimdal definition?  */
4022 + */
4023  
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)
4027  {
4028         krb5_gss_ctx_id_t kctx = ((gss_union_ctx_id_t)ctx)->internal_ctx_id;
4029         char *p, *end;
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;
4037  
4038         if (!(buf->value = calloc(1, MAX_CTX_LEN)))
4039                 goto out_err;
4040         p = buf->value;
4041         end = buf->value + MAX_CTX_LEN;
4042  
4043 -       if (kctx->initiate) {
4044 -               if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
4045 -       }
4046 -       else {
4047 -               if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
4048 -       }
4049 -       if (kctx->seed_init) {
4050 -               if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
4051 -       }
4052 -       else {
4053 -               if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
4054 -       }
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;
4064 +               }
4065 +               else {
4066 +                       if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
4067 +               }
4068 +               if (kctx->seed_init) {
4069 +                       if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
4070 +               }
4071 +               else {
4072 +                       if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
4073 +               }
4074 +               if (write_bytes(&p, end, &kctx->seed, sizeof(kctx->seed)))
4075 +                       goto out_err;
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;
4079 +               if (endtime)
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;
4084 +
4085 +               printerr(2, "serialize_krb5_ctx: serializing keys with "
4086 +                        "enctype %d and length %d\n",
4087 +                        kctx->enc->enctype, kctx->enc->length);
4088 +
4089 +               if (write_keyblock(&p, end, kctx->enc)) goto out_err;
4090 +               if (write_keyblock(&p, end, kctx->seq)) goto out_err;
4091 +               break;
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 */
4099 +               /* u32 flags;
4100 +                * #define KRB5_CTX_FLAG_INITIATOR        0x00000001
4101 +                * #define KRB5_CTX_FLAG_CFX              0x00000002
4102 +                * #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY  0x00000004
4103 +                * s32 endtime;
4104 +                * u64 seq_send;
4105 +                * u32  enctype;
4106 +                * rawkey data
4107 +                */
4108 +
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;
4117 +
4118 +               seq_send_64bit = kctx->seq_send;
4119 +               if (WRITE_BYTES(&p, end, seq_send_64bit)) goto out_err;
4120 +
4121 +               if (kctx->have_acceptor_subkey) {
4122 +                       if (WRITE_BYTES(&p, end, kctx->acceptor_subkey->enctype))
4123 +                               goto out_err;
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);
4128 +
4129 +                       if (write_bytes(&p, end,
4130 +                                       kctx->acceptor_subkey->contents,
4131 +                                       kctx->acceptor_subkey->length))
4132 +                               goto out_err;
4133 +               } else {
4134 +                       if (WRITE_BYTES(&p, end, kctx->enc->enctype))
4135 +                               goto out_err;
4136 +                       printerr(2, "serialize_krb5_ctx: serializing key "
4137 +                                "with enctype %d and size %d\n",
4138 +                                kctx->enc->enctype, kctx->enc->length);
4139 +
4140 +                       if (write_bytes(&p, end, kctx->enc->contents,
4141 +                                       kctx->enc->length))
4142 +                               goto out_err;
4143 +               }
4144 +               break;
4145 +       default:
4146 +               printerr(0, "ERROR: serialize_krb5_ctx: unsupported encryption "
4147 +                        "algorithm %d\n", kctx->enc->enctype);
4148                 goto out_err;
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;
4152 -       if (endtime)
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;
4157 -
4158 -       printerr(2, "serialize_krb5_ctx: serializing keys with "
4159 -                "enctype %d and length %d\n",
4160 -                kctx->enc->enctype, kctx->enc->length);
4161 -
4162 -       if (write_keyblock(&p, end, kctx->enc)) goto out_err;
4163 -       if (write_keyblock(&p, end, kctx->seq)) goto out_err;
4164 +       }
4165  
4166         buf->length = p - (char *)buf->value;
4167         return 0;
4168 +
4169  out_err:
4170         printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
4171 -       if (buf->value) free(buf->value);
4172 +       if (buf->value) {
4173 +               free(buf->value);
4174 +       }
4175 +       buf->value = NULL;
4176         buf->length = 0;
4177         return -1;
4178  }
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
4184  sig_hup(int signal)
4185  {
4186         /* don't exit on SIGHUP */
4187 -       printerr(1, "Received SIGHUP... Ignoring.\n");
4188 +       printerr(1, "Received SIGHUP(%d)... Ignoring.\n", signal);
4189         return;
4190  }
4191  
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;
4197  
4198  static void dir_notify_handler(int sig, siginfo_t *si, void *data)
4199  {
4200 +       printerr(2, "dir_notify_handler: sig %d si %p data %p\n", sig, si, data);
4201 +
4202         dir_changed = 1;
4203  }
4204  
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)
4210         return retval;
4211  }
4212  
4213 +/* Encryption types supported by the kernel rpcsec_gss code */
4214 +int num_krb5_enctypes = 0;
4215 +krb5_enctype *krb5_enctypes = NULL;
4216 +
4217 +/*
4218 + * Parse the supported encryption type information
4219 + */
4220 +static int
4221 +parse_enctypes(char *enctypes)
4222 +{
4223 +       int n = 0;
4224 +       char *curr, *comma;
4225 +       int i;
4226 +       static char *cached_types;
4227 +
4228 +       if (cached_types && strcmp(cached_types, enctypes) == 0)
4229 +               return 0;
4230 +       free(cached_types);
4231 +
4232 +       if (krb5_enctypes != NULL) {
4233 +               free(krb5_enctypes);
4234 +               krb5_enctypes = NULL;
4235 +               num_krb5_enctypes = 0;
4236 +       }
4237 +
4238 +       /* count the number of commas */
4239 +       for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) {
4240 +               comma = strchr(curr, ',');
4241 +               if (comma != NULL)
4242 +                       n++;
4243 +               else
4244 +                       break;
4245 +       }
4246 +       /* If no more commas and we're not at the end, there's one more value */
4247 +       if (*curr != '\0')
4248 +               n++;
4249 +
4250 +       /* Empty string, return an error */
4251 +       if (n == 0)
4252 +               return ENOENT;
4253 +
4254 +       /* Allocate space for enctypes array */
4255 +       if ((krb5_enctypes = (int *) calloc(n, sizeof(int))) == NULL) {
4256 +               return ENOMEM;
4257 +       }
4258 +
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)
4264 +                       break;
4265 +       }
4266 +
4267 +       num_krb5_enctypes = n;
4268 +       if ((cached_types = malloc(strlen(enctypes)+1)))
4269 +               strcpy(cached_types, enctypes);
4270 +
4271 +       return 0;
4272 +}
4273 +
4274  static int
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!
4280                  */
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",
4285                                  uid);
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);
4294         }
4295 @@ -1100,7 +1161,7 @@ handle_krb5_upcall(struct clnt_info *clp)
4296  {
4297         uid_t                   uid;
4298  
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));
4303                 return;
4304 @@ -1114,7 +1175,7 @@ handle_spkm3_upcall(struct clnt_info *clp)
4305  {
4306         uid_t                   uid;
4307  
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));
4312                 return;
4313 @@ -1133,6 +1194,7 @@ handle_gssd_upcall(struct clnt_info *clp)
4314         char                    *mech = NULL;
4315         char                    *target = NULL;
4316         char                    *service = NULL;
4317 +       char                    *enctypes = NULL;
4318  
4319         printerr(1, "handling gssd upcall (%s)\n", clp->dirname);
4320  
4321 @@ -1176,6 +1238,23 @@ handle_gssd_upcall(struct clnt_info *clp)
4322                 goto out;
4323         }
4324  
4325 +       /* read supported encryption types if supplied */
4326 +       if ((p = strstr(lbuf, "enctypes=")) != NULL) {
4327 +               enctypes = malloc(lbuflen);
4328 +               if (!enctypes)
4329 +                       goto out;
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);
4334 +                       goto out;
4335 +               }
4336 +               if (parse_enctypes(enctypes) != 0) {
4337 +                       printerr(0, "WARNING: handle_gssd_upcall: "
4338 +                               "parsing encryption types failed: errno %d\n", errno);
4339 +               }
4340 +       }
4341 +
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)
4346  out:
4347         free(lbuf);
4348         free(mech);
4349 +       free(enctypes);
4350         free(target);
4351         free(service);
4352         return; 
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)
4358                                 free(namelist[i]);
4359                                 continue;
4360                         }
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",
4364 +                                        statname);
4365 +                               free(namelist[i]);
4366 +                               continue;
4367 +                       }
4368                         if (!query_krb5_ccache(buf, &princname, &realm)) {
4369                                 printerr(3, "CC file '%s' is expired or corrupt\n",
4370                                          statname);
4371 @@ -292,61 +299,6 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d)
4372         return err;
4373  }
4374  
4375 -
4376 -#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
4377 -/*
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.
4381 - *
4382 - * XXX Should call some function to determine the enctypes supported
4383 - * by the kernel. (Only need to do that once!)
4384 - *
4385 - * Returns:
4386 - *     0 => all went well
4387 - *     -1 => there was an error
4388 - */
4389 -
4390 -int
4391 -limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid)
4392 -{
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]);
4400 -
4401 -       /* We only care about getting a krb5 cred */
4402 -       desired_mechs.count = 1;
4403 -       desired_mechs.elements = &krb5oid;
4404 -
4405 -       maj_stat = gss_acquire_cred(&min_stat, NULL, 0,
4406 -                                   &desired_mechs, GSS_C_INITIATE,
4407 -                                   &credh, NULL, NULL);
4408 -
4409 -       if (maj_stat != GSS_S_COMPLETE) {
4410 -               if (get_verbosity() > 0)
4411 -                       pgsserr("gss_acquire_cred",
4412 -                               maj_stat, min_stat, &krb5oid);
4413 -               return -1;
4414 -       }
4415 -
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);
4422 -               return -1;
4423 -       }
4424 -       sec->cred = credh;
4425 -
4426 -       return 0;
4427 -}
4428 -#endif /* HAVE_SET_ALLOWABLE_ENCTYPES */
4429 -
4430  /*
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.
4436   */
4437 +#ifdef HAVE_KRB5
4438  static int
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)
4442  {
4443 -#ifdef HAVE_KRB5
4444         /* Must have two components */
4445         if (p->length != 2)
4446                 return 0;
4447 +
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))
4452                 return 1;
4453 +
4454 +       return 0;
4455 +}
4456  #else
4457 +static int
4458 +realm_and_service_match(krb5_context context, krb5_principal p,
4459 +                       const char *realm, const char *service)
4460 +{
4461         const char *name, *inst;
4462  
4463         if (p->name.name_string.len != 2)
4464                 return 0;
4465 +
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))
4472                 return 1;
4473 -#endif
4474 +
4475         return 0;
4476  }
4477 +#endif
4478  
4479  /*
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;
4485 -       int retval = -1;
4486 +       int retval = -1, status;
4487         char kt_name[BUFSIZ];
4488         char *pname;
4489         char *k5err = NULL;
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",
4492                          pname);
4493                 /* Use the first matching keytab entry found */
4494 -               if ((realm_and_service_match(context, kte->principal, realm,
4495 -                                            service))) {
4496 +#ifdef HAVE_KRB5
4497 +               status = realm_and_service_match(kte->principal, realm, service);
4498 +#else
4499 +               status = realm_and_service_match(context, kte->principal, realm, service);
4500 +#endif
4501 +               if (status) {
4502                         printerr(4, "We WILL use this entry (%s)\n", pname);
4503                         ple = get_ple_by_princ(context, kte->principal);
4504                         /*
4505 @@ -1304,3 +1269,68 @@ gssd_k5_get_default_realm(char **def_realm)
4506  
4507         krb5_free_context(context);
4508  }
4509 +
4510 +#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
4511 +/*
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.
4515 + *
4516 + * XXX Should call some function to determine the enctypes supported
4517 + * by the kernel. (Only need to do that once!)
4518 + *
4519 + * Returns:
4520 + *     0 => all went well
4521 + *     -1 => there was an error
4522 + */
4523 +
4524 +int
4525 +limit_krb5_enctypes(struct rpc_gss_sec *sec)
4526 +{
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;
4536 +
4537 +       /* We only care about getting a krb5 cred */
4538 +       desired_mechs.count = 1;
4539 +       desired_mechs.elements = &krb5oid;
4540 +
4541 +       maj_stat = gss_acquire_cred(&min_stat, NULL, 0,
4542 +                                   &desired_mechs, GSS_C_INITIATE,
4543 +                                   &credh, NULL, NULL);
4544 +
4545 +       if (maj_stat != GSS_S_COMPLETE) {
4546 +               if (get_verbosity() > 0)
4547 +                       pgsserr("gss_acquire_cred",
4548 +                               maj_stat, min_stat, &krb5oid);
4549 +               return -1;
4550 +       }
4551 +
4552 +       /*
4553 +        * If we failed for any reason to produce global
4554 +        * list of supported enctypes, use local default here.
4555 +        */
4556 +       if (krb5_enctypes == NULL)
4557 +               maj_stat = gss_set_allowable_enctypes(&min_stat, credh,
4558 +                                       &krb5oid, num_enctypes, enctypes);
4559 +       else
4560 +               maj_stat = gss_set_allowable_enctypes(&min_stat, credh,
4561 +                                       &krb5oid, num_krb5_enctypes, krb5_enctypes);
4562 +
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);
4567 +               return -1;
4568 +       }
4569 +       sec->cred = credh;
4570 +
4571 +       return 0;
4572 +}
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);
4580  
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);
4584  #endif
4585  
4586  /*
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
4592  sig_hup(int signal)
4593  {
4594         /* don't exit on SIGHUP */
4595 -       printerr(1, "Received SIGHUP... Ignoring.\n");
4596 +       printerr(1, "Received SIGHUP(%d)... Ignoring.\n", signal);
4597         return;
4598  }
4599  
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
4606  
4607  static int
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)
4612  {
4613 @@ -431,12 +431,6 @@ handle_nullreq(FILE *f) {
4614         print_hexl("in_tok", in_tok.value, in_tok.length);
4615  #endif
4616  
4617 -       if (in_tok.length < 0) {
4618 -               printerr(0, "WARNING: handle_nullreq: "
4619 -                           "failed parsing request\n");
4620 -               goto out_err;
4621 -       }
4622 -
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,
4628                         hostbased_name);
4629  continue_needed:
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);
4633  out:
4634         if (ctx_token.value != NULL)
4635 @@ -514,7 +508,7 @@ out:
4636  out_err:
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);
4642         goto out;
4643  }
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(
4649         size_t n)
4650  {
4651         char *s = _s;
4652 -       ssize_t res, pos = 0;
4653 +       ssize_t res;
4654 +       size_t pos = 0;
4655  
4656         while (n > pos) {
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;
4664  };
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},
4668 +{
4669 +       .ic_which = IC_IDNAME, 
4670 +       .ic_clid = "Server", 
4671 +       .ic_id = "", 
4672 +       .ic_path = IC_IDNAME_CHAN, 
4673 +       .ic_fd = -1, 
4674 +       .ic_dirfd = -1, 
4675 +       .ic_scanned = 0
4676 +},
4677 +{
4678 +       .ic_which = IC_NAMEID, 
4679 +       .ic_clid = "Server", 
4680 +       .ic_id = "", 
4681 +       .ic_path = IC_NAMEID_CHAN, 
4682 +       .ic_fd = -1, 
4683 +       .ic_dirfd = -1, 
4684 +       .ic_scanned = 0
4685 +},
4686  };
4687  
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);
4691         if (fd == -1)
4692                 return -1;
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));
4697         }
4698 @@ -381,7 +397,7 @@ main(int argc, char **argv)
4699  }
4700  
4701  static void
4702 -dirscancb(int fd, short which, void *data)
4703 +dirscancb(int UNUSED(fd), short UNUSED(which), void *data)
4704  {
4705         int nent, i;
4706         struct dirent **ents;
4707 @@ -465,13 +481,13 @@ out:
4708  }
4709  
4710  static void
4711 -svrreopen(int fd, short which, void *data)
4712 +svrreopen(int UNUSED(fd), short UNUSED(which), void *UNUSED(data))
4713  {
4714         nfsdreopen();
4715  }
4716  
4717  static void
4718 -clntscancb(int fd, short which, void *data)
4719 +clntscancb(int UNUSED(fd), short UNUSED(which), void *data)
4720  {
4721         struct idmap_clientq *icq = data;
4722         struct idmap_client *ic;
4723 @@ -485,7 +501,7 @@ clntscancb(int fd, short which, void *data)
4724  }
4725  
4726  static void
4727 -nfsdcb(int fd, short which, void *data)
4728 +nfsdcb(int UNUSED(fd), short which, void *data)
4729  {
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)
4733  }
4734  
4735  static void
4736 -nfscb(int fd, short which, void *data)
4737 +nfscb(int UNUSED(fd), short which, void *data)
4738  {
4739         struct idmap_client *ic = data;
4740         struct idmap_msg im;
4741 @@ -845,7 +861,7 @@ nametoidres(struct idmap_msg *im)
4742  static int
4743  validateascii(char *string, u_int32_t len)
4744  {
4745 -       int i;
4746 +       u_int32_t i;
4747  
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)
4752  {
4753         char *bp;
4754 -       u_int val, n;
4755 +       int val, n;
4756  
4757         while ((bp = strsep(bpp, " ")) != NULL && bp[0] == '\0')
4758                 ;
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)
4764         }
4765  }
4766  static char *versions[] = {"v2", "v3", "v4", "vers", "nfsvers", NULL};
4767 -int inline check_vers(char *mopt, char *field)
4768 +static int 
4769 +check_vers(char *mopt, char *field)
4770  {
4771         int i, found=0;
4772  
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.
4776   */
4777 -int inline default_value(char *mopt)
4778 +static int 
4779 +default_value(char *mopt)
4780  {
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
4787 @@ -53,6 +53,7 @@
4788  #include "parse_opt.h"
4789  #include "network.h"
4790  #include "conffile.h"
4791 +#include "nfslib.h"
4792  
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,
4796                 return 0;
4797         }
4798  
4799 -       client->cl_auth = authunix_create_default();
4800 +       client->cl_auth = nfs_authsys_create();
4801 +       if (client->cl_auth == NULL) {
4802 +               if (verbose)
4803 +                       nfs_error(_("%s: Failed to create RPC auth handle"),
4804 +                               progname);
4805 +               CLNT_DESTROY(client);
4806 +               return 0;
4807 +       }
4808  
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)
4812         }
4813         if (clnt) {
4814                 /* try to mount hostname:dirname */
4815 -               clnt->cl_auth = authunix_create_default();
4816 -               return clnt;
4817 +               clnt->cl_auth = nfs_authsys_create();
4818 +               if (clnt->cl_auth)
4819 +                       return clnt;
4820 +               CLNT_DESTROY(clnt);
4821         }
4822         return NULL;
4823  }
4824 @@ -1203,6 +1213,8 @@ nfs_nfs_program(struct mount_options *options, unsigned long *program)
4825                         return 1;
4826                 }
4827         case PO_BAD_VALUE:
4828 +               nfs_error(_("%s: invalid value for 'nfsprog=' option"),
4829 +                               progname);
4830                 return 0;
4831         }
4832  
4833 @@ -1242,9 +1254,12 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version)
4834                         }
4835                         return 0;
4836                 case PO_NOT_FOUND:
4837 -                       nfs_error(_("%s: option parsing error\n"),
4838 +                       nfs_error(_("%s: parsing error on 'vers=' option\n"),
4839                                         progname);
4840 +                       return 0;
4841                 case PO_BAD_VALUE:
4842 +                       nfs_error(_("%s: invalid value for 'vers=' option"),
4843 +                                       progname);
4844                         return 0;
4845                 }
4846         case 4: /* nfsvers */
4847 @@ -1256,9 +1271,12 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version)
4848                         }
4849                         return 0;
4850                 case PO_NOT_FOUND:
4851 -                       nfs_error(_("%s: option parsing error\n"),
4852 +                       nfs_error(_("%s: parsing error on 'nfsvers=' option\n"),
4853                                         progname);
4854 +                       return 0;
4855                 case PO_BAD_VALUE:
4856 +                       nfs_error(_("%s: invalid value for 'nfsvers=' option"),
4857 +                                       progname);
4858                         return 0;
4859                 }
4860         }
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);
4867                                 return 0;
4868                         }
4869                         return 1;
4870 @@ -1327,6 +1347,8 @@ nfs_nfs_port(struct mount_options *options, unsigned long *port)
4871                         return 1;
4872                 }
4873         case PO_BAD_VALUE:
4874 +               nfs_error(_("%s: invalid value for 'port=' option"),
4875 +                               progname);
4876                 return 0;
4877         }
4878  
4879 @@ -1342,7 +1364,7 @@ nfs_nfs_port(struct mount_options *options, unsigned long *port)
4880  sa_family_t    config_default_family = AF_UNSPEC;
4881  
4882  static int
4883 -nfs_verify_family(sa_family_t family)
4884 +nfs_verify_family(sa_family_t UNUSED(family))
4885  {
4886         return 1;
4887  }
4888 @@ -1380,8 +1402,13 @@ int nfs_nfs_proto_family(struct mount_options *options,
4889         case 2: /* proto */
4890                 option = po_get(options, "proto");
4891                 if (option != NULL &&
4892 -                   !nfs_get_proto(option, &tmp_family, &protocol))
4893 -                       goto out_err;
4894 +                   !nfs_get_proto(option, &tmp_family, &protocol)) {
4895 +
4896 +                       nfs_error(_("%s: Failed to find '%s' protocol"), 
4897 +                               progname, option);
4898 +                       errno = EPROTONOSUPPORT;
4899 +                       return 0;
4900 +               }
4901         }
4902  
4903         if (!nfs_verify_family(tmp_family))
4904 @@ -1414,6 +1441,8 @@ nfs_mount_program(struct mount_options *options, unsigned long *program)
4905                         return 1;
4906                 }
4907         case PO_BAD_VALUE:
4908 +               nfs_error(_("%s: invalid value for 'mountprog=' option"),
4909 +                               progname);
4910                 return 0;
4911         }
4912  
4913 @@ -1443,6 +1472,8 @@ nfs_mount_version(struct mount_options *options, unsigned long *version)
4914                         return 1;
4915                 }
4916         case PO_BAD_VALUE:
4917 +               nfs_error(_("%s: invalid value for 'mountvers=' option"),
4918 +                               progname);
4919                 return 0;
4920         }
4921  
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);
4928                         return 0;
4929                 }
4930                 return 1;
4931 @@ -1501,6 +1534,8 @@ nfs_mount_port(struct mount_options *options, unsigned long *port)
4932                         return 1;
4933                 }
4934         case PO_BAD_VALUE:
4935 +               nfs_error(_("%s: invalid value for 'mountport=' option"),
4936 +                               progname);
4937                 return 0;
4938         }
4939  
4940 @@ -1526,8 +1561,12 @@ int nfs_mount_proto_family(struct mount_options *options,
4941  
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;
4949                         goto out_err;
4950 +               }
4951                 if (!nfs_verify_family(tmp_family))
4952                         goto out_err;
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.
4959  .TP 1.5i
4960  .BI nfsvers= n
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
4964 -.BR nfs .
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
4969 -is not available.
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.
4973  .TP 1.5i
4974  .BI vers= n
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);
4982                 return -1;
4983         }
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);
4988         }
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,
4994         int val;
4995         static int doonce = 0;
4996  
4997 -       clnt_addr_t mnt_server = { &mounthost, };
4998 -       clnt_addr_t nfs_server = { &hostname, };
4999 +       clnt_addr_t mnt_server = { 
5000 +               .hostname = &mounthost 
5001 +       };
5002 +       clnt_addr_t nfs_server = { 
5003 +               .hostname = &hostname 
5004 +       };
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;
5014         sa_family_t family;
5015  
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))
5019                 return EX_FAIL;
5020 -       }
5021  
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)
5029  
5030         if (!nfs_construct_new_options(options, nfs_saddr, &nfs_pmap,
5031                                         mnt_saddr, &mnt_pmap)) {
5032 -               errno = EINVAL;
5033 +               if (rpc_createerr.cf_stat == RPC_UNKNOWNPROTO)
5034 +                       errno = EPROTONOSUPPORT;
5035 +               else
5036 +                       errno = EINVAL;
5037                 return 0;
5038         }
5039  
5040 @@ -586,18 +589,21 @@ static int nfs_do_mount_v3v2(struct nfsmount_info *mi,
5041                 errno = ENOMEM;
5042                 return result;
5043         }
5044 -
5045 +       errno = 0;
5046         if (!nfs_append_addr_option(sap, salen, options)) {
5047 -               errno = EINVAL;
5048 +               if (errno == 0)
5049 +                       errno = EINVAL;
5050                 goto out_fail;
5051         }
5052  
5053         if (!nfs_fix_mounthost_option(options, mi->hostname)) {
5054 -               errno = EINVAL;
5055 +               if (errno == 0)
5056 +                       errno = EINVAL;
5057                 goto out_fail;
5058         }
5059         if (!mi->fake && !nfs_verify_lock_option(options)) {
5060 -               errno = EINVAL;
5061 +               if (errno == 0)
5062 +                       errno = EINVAL;
5063                 goto out_fail;
5064         }
5065  
5066 @@ -799,6 +805,7 @@ static int nfs_is_permanent_error(int error)
5067         case ESTALE:
5068         case ETIMEDOUT:
5069         case ECONNREFUSED:
5070 +       case EHOSTUNREACH:
5071                 return 0;       /* temporary */
5072         default:
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
5078 @@ -15,6 +15,8 @@
5079  #include <arpa/inet.h>
5080  #include <errno.h>
5081  #include <unistd.h>
5082 +
5083 +#include "sockaddr.h"
5084  #include "misc.h"
5085  #include "nfslib.h"
5086  #include "exportfs.h"
5087 @@ -110,13 +112,16 @@ auth_reload()
5088         return counter;
5089  }
5090  
5091 -static char *get_client_hostname(struct sockaddr_in *caller, struct hostent *hp, enum auth_error *error)
5092 +static char *
5093 +get_client_hostname(const struct sockaddr *caller, struct addrinfo *ai,
5094 +               enum auth_error *error)
5095  {
5096 +       char buf[INET6_ADDRSTRLEN];
5097         char *n;
5098  
5099         if (use_ipaddr)
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;
5105         if (!n)
5106                 return NULL;
5107 @@ -128,8 +133,8 @@ static char *get_client_hostname(struct sockaddr_in *caller, struct hostent *hp,
5108  
5109  /* return static nfs_export with details filled in */
5110  static nfs_export *
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)
5116  {
5117         nfs_export *exp;
5118 @@ -137,12 +142,12 @@ auth_authenticate_newcache(char *what, struct sockaddr_in *caller,
5119  
5120         free(my_client.m_hostname);
5121  
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)
5125                 return NULL;
5126  
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;
5131  
5132         exp = NULL;
5133 @@ -152,7 +157,7 @@ auth_authenticate_newcache(char *what, struct sockaddr_in *caller,
5134                                 continue;
5135                         if (!use_ipaddr && !client_member(my_client.m_hostname, exp->m_client->m_hostname))
5136                                 continue;
5137 -                       if (use_ipaddr && !client_check(exp->m_client, hp))
5138 +                       if (use_ipaddr && !client_check(exp->m_client, ai))
5139                                 continue;
5140                         break;
5141                 }
5142 @@ -166,18 +171,18 @@ auth_authenticate_newcache(char *what, struct sockaddr_in *caller,
5143  }
5144  
5145  static nfs_export *
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)
5151  {
5152         nfs_export *exp;
5153  
5154         if (new_cache) {
5155 -               exp = auth_authenticate_newcache(what, caller, path, hp, error);
5156 +               exp = auth_authenticate_newcache(caller, path, ai, error);
5157                 if (!exp)
5158                         return NULL;
5159         } else {
5160 -               if (!(exp = export_find(hp, path))) {
5161 +               exp = export_find(ai, path);
5162 +               if (exp == NULL) {
5163                         *error = no_entry;
5164                         return NULL;
5165                 }
5166 @@ -187,7 +192,7 @@ auth_authenticate_internal(char *what, struct sockaddr_in *caller,
5167                 return NULL;
5168         }
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;
5173                 return NULL;
5174         }
5175 @@ -197,18 +202,19 @@ auth_authenticate_internal(char *what, struct sockaddr_in *caller,
5176  }
5177  
5178  nfs_export *
5179 -auth_authenticate(char *what, struct sockaddr_in *caller, char *path)
5180 +auth_authenticate(const char *what, const struct sockaddr *caller,
5181 +               const char *path)
5182  {
5183         nfs_export      *exp = NULL;
5184         char            epath[MAXPATHLEN+1];
5185         char            *p = NULL;
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;
5191  
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);
5198                 return exp;
5199         }
5200  
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 */
5204  
5205 -       hp = client_resolve(caller->sin_addr);
5206 -       if (!hp)
5207 +       ai = client_resolve(caller);
5208 +       if (ai == NULL)
5209                 return exp;
5210  
5211         /* Try the longest matching exported pathname. */
5212         while (1) {
5213 -               exp = auth_authenticate_internal(what, caller, epath,
5214 -                                                hp, &error);
5215 +               exp = auth_authenticate_internal(caller, epath, ai, &error);
5216                 if (exp || (error != not_exported && error != no_entry))
5217                         break;
5218                 /* We have to treat the root, "/", specially. */
5219 @@ -236,41 +241,40 @@ auth_authenticate(char *what, struct sockaddr_in *caller, char *path)
5220         switch (error) {
5221         case bad_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);
5225                 break;
5226  
5227         case unknown_host:
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);
5231                 break;
5232  
5233         case no_entry:
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);
5237                 break;
5238  
5239         case not_exported:
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);
5243                 break;
5244  
5245         case illegal_port:
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));
5250                 break;
5251  
5252         case success:
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);
5257                 break;
5258         default:
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);
5264         }
5265  
5266 -       if (hp)
5267 -               free (hp);
5268 -
5269 +       freeaddrinfo(ai);
5270         return exp;
5271  }
5272  
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
5277 @@ -37,6 +37,11 @@
5278  #include "blkid/blkid.h"
5279  #endif
5280  
5281 +/*
5282 + * Invoked by RPC service loop
5283 + */
5284 +void   cache_set_fds(fd_set *fdset);
5285 +int    cache_process_req(fd_set *readfds);
5286  
5287  enum nfsd_fsid {
5288         FSID_DEV = 0,
5289 @@ -57,14 +62,14 @@ enum nfsd_fsid {
5290   * Record is terminated with newline.
5291   *
5292   */
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);
5295  
5296  
5297  char *lbuf  = NULL;
5298  int lbuflen = 0;
5299  extern int use_ipaddr;
5300  
5301 -void auth_unix_ip(FILE *f)
5302 +static void auth_unix_ip(FILE *f)
5303  {
5304         /* requests are
5305          *  class IP-ADDR
5306 @@ -75,10 +80,10 @@ void auth_unix_ip(FILE *f)
5307          */
5308         char *cp;
5309         char class[20];
5310 -       char ipaddr[20];
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)
5318                 return;
5319  
5320 @@ -90,20 +95,23 @@ void auth_unix_ip(FILE *f)
5321             strcmp(class, "nfsd") != 0)
5322                 return;
5323  
5324 -       if (qword_get(&cp, ipaddr, 20) <= 0)
5325 +       if (qword_get(&cp, ipaddr, sizeof(ipaddr)) <= 0)
5326                 return;
5327  
5328 -       if (inet_aton(ipaddr, &addr)==0)
5329 +       tmp = host_pton(ipaddr);
5330 +       if (tmp == NULL)
5331                 return;
5332  
5333         auth_reload();
5334  
5335         /* addr is a valid, interesting address, find the domain name... */
5336         if (!use_ipaddr) {
5337 -               he = client_resolve(addr);
5338 -               client = client_compose(he);
5339 +               ai = client_resolve(tmp->ai_addr);
5340 +               client = client_compose(ai);
5341 +               freeaddrinfo(ai);
5342         }
5343 -       
5344 +       freeaddrinfo(tmp);
5345 +
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)
5350         qword_eol(f);
5351         xlog(D_CALL, "auth_unix_ip: client %p '%s'", client, client?client: "DEFAULT");
5352  
5353 -       if (client) free(client);
5354 -       free(he);
5355 +       free(client);
5356  }
5357  
5358 -void auth_unix_gid(FILE *f)
5359 +static void auth_unix_gid(FILE *f)
5360  {
5361         /* Request are
5362          *  uid
5363          * reply is
5364          *  uid expiry count list of group ids
5365          */
5366 -       int uid;
5367 +       uid_t uid;
5368         struct passwd *pw;
5369         gid_t glist[100], *groups = glist;
5370         int ngroups = 100;
5371 @@ -136,7 +143,7 @@ void auth_unix_gid(FILE *f)
5372                 return;
5373  
5374         cp = lbuf;
5375 -       if (qword_get_int(&cp, &uid) != 0)
5376 +       if (qword_get_uint(&cp, &uid) != 0)
5377                 return;
5378  
5379         pw = getpwuid(uid);
5380 @@ -153,14 +160,14 @@ void auth_unix_gid(FILE *f)
5381                                                   groups, &ngroups);
5382                 }
5383         }
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);
5388         if (rv >= 0) {
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]);
5394         } else
5395 -               qword_printint(f, 0);
5396 +               qword_printuint(f, 0);
5397         qword_eol(f);
5398  
5399         if (groups != glist)
5400 @@ -170,13 +177,16 @@ void auth_unix_gid(FILE *f)
5401  #if USE_BLKID
5402  static const char *get_uuid_blkdev(char *path)
5403  {
5404 +       /* We set *safe if we know that we need the
5405 +        * fsid from statfs too.
5406 +        */
5407         static blkid_cache cache = NULL;
5408         struct stat stb;
5409         char *devname;
5410         blkid_tag_iterate iter;
5411         blkid_dev dev;
5412         const char *type;
5413 -       const char *val = NULL;
5414 +       const char *val, *uuid = NULL;
5415  
5416         if (cache == 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);
5420         if (!iter)
5421                 return NULL;
5422 -       while (blkid_tag_next(iter, &type, &val) == 0)
5423 +       while (blkid_tag_next(iter, &type, &val) == 0) {
5424                 if (strcmp(type, "UUID") == 0)
5425 +                       uuid = val;
5426 +               if (strcmp(type, "TYPE") == 0 &&
5427 +                   strcmp(val, "btrfs") == 0) {
5428 +                       uuid = NULL;
5429                         break;
5430 +               }
5431 +       }
5432         blkid_tag_iterate_end(iter);
5433 -       return val;
5434 +       return uuid;
5435  }
5436  #else
5437  #define get_uuid_blkdev(path) (NULL)
5438  #endif
5439  
5440 -int get_uuid(char *path, char *uuid, int uuidlen, char *u)
5441 +static int get_uuid(const char *val, int uuidlen, char *u)
5442  {
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
5446 +        * a smaller uuid.
5447          */
5448         int i = 0;
5449 -       const char *val = NULL;
5450 -       char fsid_val[17];
5451 -
5452 -       if (path) {
5453 -               val = get_uuid_blkdev(path);
5454 -               if (!val) {
5455 -                       struct statfs64 st;
5456 -
5457 -                       if (statfs64(path, &st))
5458 -                               return 0;
5459 -                       if (!st.f_fsid.__val[0] && !st.f_fsid.__val[1])
5460 -                               return 0;
5461 -                       snprintf(fsid_val, 17, "%08x%08x",
5462 -                                st.f_fsid.__val[0], st.f_fsid.__val[1]);
5463 -                       val = fsid_val;
5464 -               }
5465 -       } else {
5466 -               val = uuid;
5467 -       }
5468         
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)
5472         return 1;
5473  }
5474  
5475 +static int uuid_by_path(char *path, int type, int uuidlen, char *uuid)
5476 +{
5477 +       /* get a uuid for the filesystem found at 'path'.
5478 +        * There are several possible ways of generating the
5479 +        * uuids (types).
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
5485 +        * extracted.
5486 +        */
5487 +
5488 +       /* Possible sources of uuid are
5489 +        * - blkid uuid
5490 +        * - statfs64 uuid
5491 +        *
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.
5502 +        *
5503 +        */
5504 +       struct statfs64 st;
5505 +       char fsid_val[17];
5506 +       const char *blkid_val;
5507 +       const char *val;
5508 +
5509 +       blkid_val = get_uuid_blkdev(path);
5510 +
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]);
5515 +       else
5516 +               fsid_val[0] = 0;
5517 +
5518 +       if (blkid_val && (type--) == 0)
5519 +               val = blkid_val;
5520 +       else if (fsid_val[0] && (type--) == 0)
5521 +               val = fsid_val;
5522 +       else
5523 +               return 0;
5524 +
5525 +       get_uuid(val, uuidlen, uuid);
5526 +       return 1;
5527 +}
5528 +
5529  /* Iterate through /etc/mtab, finding mountpoints
5530   * at or below a given path
5531   */
5532 @@ -277,7 +328,7 @@ static char *next_mnt(void **v, char *p)
5533         return me->mnt_dir;
5534  }
5535  
5536 -void nfsd_fh(FILE *f)
5537 +static void nfsd_fh(FILE *f)
5538  {
5539         /* request are:
5540          *  domain fsidtype fsid
5541 @@ -294,8 +345,7 @@ void nfsd_fh(FILE *f)
5542         unsigned int fsidnum=0;
5543         char fsid[32];
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;
5549         nfs_export *exp;
5550         int i;
5551 @@ -398,6 +448,7 @@ void nfsd_fh(FILE *f)
5552                         struct stat stb;
5553                         char u[16];
5554                         char *path;
5555 +                       int type;
5556  
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)
5560                                         continue;
5561                         check_uuid:
5562                                 if (exp->m_export.e_uuid)
5563 -                                       get_uuid(NULL, exp->m_export.e_uuid,
5564 +                                       get_uuid(exp->m_export.e_uuid,
5565                                                  uuidlen, u);
5566 -                               else if (get_uuid(path, NULL, uuidlen, u) == 0)
5567 -                                       continue;
5568 +                               else
5569 +                                       for (type = 0;
5570 +                                            uuid_by_path(path, type, uuidlen, u);
5571 +                                            type++)
5572 +                                               if (memcmp(u, fhuuid, uuidlen) == 0)
5573 +                                                       break;
5574  
5575                                 if (memcmp(u, fhuuid, uuidlen) != 0)
5576                                         continue;
5577                                 break;
5578                         }
5579                         if (use_ipaddr) {
5580 -                               if (he == NULL) {
5581 -                                       if (!inet_aton(dom, &addr))
5582 +                               if (ai == NULL) {
5583 +                                       struct addrinfo *tmp;
5584 +                                       tmp = host_pton(dom);
5585 +                                       if (tmp == NULL)
5586                                                 goto out;
5587 -                                       he = client_resolve(addr);
5588 +                                       ai = client_resolve(tmp->ai_addr);
5589 +                                       freeaddrinfo(tmp);
5590                                 }
5591 -                               if (!client_check(exp->m_client, he))
5592 +                               if (!client_check(exp->m_client, ai))
5593                                         continue;
5594                         }
5595                         /* It's a match !! */
5596 @@ -534,21 +592,20 @@ void nfsd_fh(FILE *f)
5597   out:
5598         if (found_path)
5599                 free(found_path);
5600 -       if (he)
5601 -               free(he);
5602 +       freeaddrinfo(ai);
5603         free(dom);
5604         xlog(D_CALL, "nfsd_fh: found %p path %s", found, found ? found->e_path : NULL);
5605         return;         
5606  }
5607  
5608 -static void write_fsloc(FILE *f, struct exportent *ep, char *path)
5609 +static void write_fsloc(FILE *f, struct exportent *ep)
5610  {
5611         struct servers *servers;
5612  
5613         if (ep->e_fslocmethod == FSLOC_NONE)
5614                 return;
5615  
5616 -       servers = replicas_lookup(ep->e_fslocmethod, ep->e_fslocdata, path);
5617 +       servers = replicas_lookup(ep->e_fslocmethod, ep->e_fslocdata);
5618         if (!servers)
5619                 return;
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) {
5629                         char u[16];
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);
5634                         }
5635                 } else {
5636                         char 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);
5641                 }
5642 @@ -614,12 +671,12 @@ static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *ex
5643         return qword_eol(f);
5644  }
5645  
5646 -static int is_subdirectory(char *subpath, char *path)
5647 +static int is_subdirectory(char *child, char *parent)
5648  {
5649 -       int l = strlen(path);
5650 +       int l = strlen(parent);
5651  
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] == '/');
5656  }
5657  
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;
5661  }
5662  
5663 -static int client_matches(nfs_export *exp, char *dom, struct hostent *he)
5664 +static int
5665 +client_matches(nfs_export *exp, char *dom, struct addrinfo *ai)
5666  {
5667         if (use_ipaddr)
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);
5671  }
5672  
5673 -static int export_matches(nfs_export *exp, char *dom, char *path, struct hostent *he)
5674 +static int
5675 +export_matches(nfs_export *exp, char *dom, char *path, struct addrinfo *ai)
5676  {
5677 -       return path_matches(exp, path) && client_matches(exp, dom, he);
5678 +       return path_matches(exp, path) && client_matches(exp, dom, ai);
5679  }
5680  
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)
5684  {
5685         nfs_export *exp;
5686         nfs_export *found = NULL;
5687 @@ -650,7 +710,7 @@ static nfs_export *lookup_export(char *dom, char *path, struct hostent *he)
5688  
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))
5693                                 continue;
5694                         if (!found) {
5695                                 found = exp;
5696 @@ -687,7 +747,7 @@ static nfs_export *lookup_export(char *dom, char *path, struct hostent *he)
5697         return found;
5698  }
5699  
5700 -void nfsd_export(FILE *f)
5701 +static void nfsd_export(FILE *f)
5702  {
5703         /* requests are:
5704          *  domain path
5705 @@ -698,9 +758,7 @@ void nfsd_export(FILE *f)
5706         char *cp;
5707         char *dom, *path;
5708         nfs_export *found = NULL;
5709 -       struct in_addr addr;
5710 -       struct hostent *he = NULL;
5711 -
5712 +       struct addrinfo *ai = NULL;
5713  
5714         if (readline(fileno(f), &lbuf, &lbuflen) != 1)
5715                 return;
5716 @@ -722,12 +780,16 @@ void nfsd_export(FILE *f)
5717         auth_reload();
5718  
5719         if (use_ipaddr) {
5720 -               if (!inet_aton(dom, &addr))
5721 +               struct addrinfo *tmp;
5722 +               tmp = host_pton(dom);
5723 +               if (tmp == NULL)
5724 +                       goto out;
5725 +               ai = client_resolve(tmp->ai_addr);
5726 +               freeaddrinfo(tmp);
5727                         goto out;
5728 -               he = client_resolve(addr);
5729         }
5730  
5731 -       found = lookup_export(dom, path, he);
5732 +       found = lookup_export(dom, path, ai);
5733  
5734         if (found) {
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);
5738         if (dom) free(dom);
5739         if (path) free(path);
5740 -       if (he) free(he);
5741 +       freeaddrinfo(ai);
5742  }
5743  
5744  
5745 @@ -752,14 +814,19 @@ struct {
5746         void (*cache_handle)(FILE *f);
5747         FILE *f;
5748  } cachelist[] = {
5749 -       { "auth.unix.ip", auth_unix_ip},
5750 -       { "auth.unix.gid", auth_unix_gid},
5751 -       { "nfsd.export", nfsd_export},
5752 -       { "nfsd.fh", nfsd_fh},
5753 -       { NULL, NULL }
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 }
5759  };
5760  
5761  extern int manage_gids;
5762 +
5763 +/**
5764 + * cache_open - prepare communications channels with kernel RPC caches
5765 + *
5766 + */
5767  void cache_open(void) 
5768  {
5769         int i;
5770 @@ -772,6 +839,10 @@ void cache_open(void)
5771         }
5772  }
5773  
5774 +/**
5775 + * cache_set_fds - prepare cache file descriptors for one iteration of the service loop
5776 + * @fdset: pointer to fd_set to prepare
5777 + */
5778  void cache_set_fds(fd_set *fdset)
5779  {
5780         int i;
5781 @@ -781,6 +852,10 @@ void cache_set_fds(fd_set *fdset)
5782         }
5783  }
5784  
5785 +/**
5786 + * cache_process_req - process any active cache file descriptors during service loop iteration
5787 + * @fdset: pointer to fd_set to examine for activity
5788 + */
5789  int cache_process_req(fd_set *readfds) 
5790  {
5791         int i;
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
5794   */
5795  
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)
5798  {
5799         int err;
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
5803                  */
5804                 struct stat stb;
5805 -               int l = strlen(exp->e_path);
5806 -               int dev;
5807 +               size_t l = strlen(exp->e_path);
5808 +               __dev_t dev;
5809  
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)
5813         return err;
5814  }
5815  
5816 +/**
5817 + * cache_export - Inform kernel of a new nfs_export
5818 + * @exp: target nfs_export
5819 + * @path: NUL-terminated C string containing export path
5820 + */
5821  int cache_export(nfs_export *exp, char *path)
5822  {
5823 +       char buf[INET6_ADDRSTRLEN];
5824         int err;
5825         FILE *f;
5826  
5827 @@ -870,8 +951,10 @@ int cache_export(nfs_export *exp, char *path)
5828         if (!f)
5829                 return -1;
5830  
5831 +
5832         qword_print(f, "nfsd");
5833 -       qword_print(f, inet_ntoa(exp->m_client->m_addrlist[0]));
5834 +       qword_print(f,
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);
5838         err = qword_eol(f);
5839 @@ -883,7 +966,14 @@ int cache_export(nfs_export *exp, char *path)
5840         return err;
5841  }
5842  
5843 -/* Get a filehandle.
5844 +/**
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
5849 + *
5850 + * Returns pointer to NFS file handle of root directory of export
5851 + *
5852   * { 
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);
5857         return &fh;
5858  }
5859 -
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)
5865  }
5866  
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)
5870  {
5871         struct servers *sp=NULL;
5872         switch(method) {
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 */
5879  };
5880  
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);
5884  
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
5890 @@ -28,10 +28,6 @@
5891  #include "rpcmisc.h"
5892  #include "pseudoflavors.h"
5893  
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);
5897 -
5898  extern void my_svc_run(void);
5899  
5900  static void            usage(const char *, int exitcode);
5901 @@ -75,17 +71,40 @@ static struct option longopts[] =
5902         { NULL, 0, 0, 0 }
5903  };
5904  
5905 -static int nfs_version = -1;
5906 +#define NFSVERSBIT(vers)       (0x1 << (vers - 1))
5907 +#define NFSVERSBIT_ALL         (NFSVERSBIT(2) | NFSVERSBIT(3) | NFSVERSBIT(4))
5908 +
5909 +static int nfs_version = NFSVERSBIT_ALL;
5910 +
5911 +static int version2(void)
5912 +{
5913 +       return nfs_version & NFSVERSBIT(2);
5914 +}
5915 +
5916 +static int version3(void)
5917 +{
5918 +       return nfs_version & NFSVERSBIT(3);
5919 +}
5920 +
5921 +static int version23(void)
5922 +{
5923 +       return nfs_version & (NFSVERSBIT(2) | NFSVERSBIT(3));
5924 +}
5925 +
5926 +static int version_any(void)
5927 +{
5928 +       return nfs_version & NFSVERSBIT_ALL;
5929 +}
5930  
5931  static void
5932  unregister_services (void)
5933  {
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);
5940 +       if (version2()) {
5941 +               nfs_svc_unregister(MOUNTPROG, MOUNTVERS);
5942 +               nfs_svc_unregister(MOUNTPROG, MOUNTVERS_POSIX);
5943 +       }
5944 +       if (version3())
5945 +               nfs_svc_unregister(MOUNTPROG, MOUNTVERS_NFSV3);
5946  }
5947  
5948  static void
5949 @@ -192,17 +211,28 @@ sig_hup (int sig)
5950  }
5951  
5952  bool_t
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))
5956  {
5957 +       struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
5958 +       char buf[INET6_ADDRSTRLEN];
5959 +
5960 +       xlog(D_CALL, "Received NULL request from %s",
5961 +               host_ntop(sap, buf, sizeof(buf)));
5962 +
5963         return 1;
5964  }
5965  
5966  bool_t
5967  mount_mnt_1_svc(struct svc_req *rqstp, dirpath *path, fhstatus *res)
5968  {
5969 +       struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
5970 +       char buf[INET6_ADDRSTRLEN];
5971         struct nfs_fh_len *fh;
5972  
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)));
5976 +
5977         fh = get_rootfh(rqstp, path, NULL, &res->fhs_status, 0);
5978         if (fh)
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)
5981  }
5982  
5983  bool_t
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)
5986  {
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];
5990 +
5991 +       xlog(D_CALL, "Received DUMP request from %s",
5992 +               host_ntop(sap, buf, sizeof(buf)));
5993  
5994 -       xlog(D_CALL, "dump request from %s.", inet_ntoa(addr->sin_addr));
5995         *res = mountlist_list();
5996  
5997         return 1;
5998  }
5999  
6000  bool_t
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))
6003  {
6004 -       struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt);
6005 +       struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
6006         nfs_export      *exp;
6007         char            *p = *argp;
6008         char            rpath[MAXPATHLEN+1];
6009 +       char            buf[INET6_ADDRSTRLEN];
6010  
6011         if (*p == '\0')
6012                 p = "/";
6013 @@ -236,41 +270,57 @@ mount_umnt_1_svc(struct svc_req *rqstp, dirpath *argp, void *resp)
6014                 p = rpath;
6015         }
6016  
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)));
6020 +
6021 +       exp = auth_authenticate("unmount", sap, p);
6022 +       if (exp == NULL)
6023                 return 1;
6024 -       }
6025  
6026 -       mountlist_del(inet_ntoa(sin->sin_addr), p);
6027 +       mountlist_del(host_ntop(sap, buf, sizeof(buf)), p);
6028         return 1;
6029  }
6030  
6031  bool_t
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))
6035  {
6036 +       struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
6037 +       char            buf[INET6_ADDRSTRLEN];
6038 +
6039 +       xlog(D_CALL, "Received UMNTALL request from %s",
6040 +               host_ntop(sap, buf, sizeof(buf)));
6041 +
6042         /* Reload /etc/xtab if necessary */
6043         auth_reload();
6044  
6045 -       mountlist_del_all(nfs_getrpccaller_in(rqstp->rq_xprt));
6046 +       mountlist_del_all(nfs_getrpccaller(rqstp->rq_xprt));
6047         return 1;
6048  }
6049  
6050  bool_t
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)
6053  {
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];
6057 +
6058 +       xlog(D_CALL, "Received EXPORT request from %s.",
6059 +               host_ntop(sap, buf, sizeof(buf)));
6060  
6061 -       xlog(D_CALL, "export request from %s.", inet_ntoa(addr->sin_addr));
6062         *resp = get_exportlist();
6063                 
6064         return 1;
6065  }
6066  
6067  bool_t
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)
6070  {
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];
6074 +
6075 +       xlog(D_CALL, "Received EXPORTALL request from %s.",
6076 +               host_ntop(sap, buf, sizeof(buf)));
6077  
6078 -       xlog(D_CALL, "exportall request from %s.", inet_ntoa(addr->sin_addr));
6079         *resp = get_exportlist();
6080  
6081         return 1;
6082 @@ -290,11 +340,12 @@ mount_exportall_1_svc(struct svc_req *rqstp, void *argp, exports *resp)
6083  bool_t
6084  mount_pathconf_2_svc(struct svc_req *rqstp, dirpath *path, ppathcnf *res)
6085  {
6086 -       struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt);
6087 +       struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
6088         struct stat     stb;
6089         nfs_export      *exp;
6090         char            rpath[MAXPATHLEN+1];
6091         char            *p = *path;
6092 +       char buf[INET6_ADDRSTRLEN];
6093  
6094         memset(res, 0, sizeof(*res));
6095  
6096 @@ -310,11 +361,14 @@ mount_pathconf_2_svc(struct svc_req *rqstp, dirpath *path, ppathcnf *res)
6097                 p = rpath;
6098         }
6099  
6100 +       xlog(D_CALL, "Received PATHCONF(%s) request from %s", p,
6101 +               host_ntop(sap, buf, sizeof(buf)));
6102 +
6103         /* Now authenticate the intruder... */
6104 -       exp = auth_authenticate("pathconf", sin, p);
6105 -       if (!exp) {
6106 +       exp = auth_authenticate("pathconf", sap, p);
6107 +       if (exp == NULL)
6108                 return 1;
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));
6113                 return 1;
6114 @@ -374,11 +428,15 @@ static void set_authflavors(struct mountres3_ok *ok, nfs_export *exp)
6115  bool_t
6116  mount_mnt_3_svc(struct svc_req *rqstp, dirpath *path, mountres3 *res)
6117  {
6118 +       struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
6119         struct mountres3_ok *ok = &res->mountres3_u.mountinfo;
6120 +       char buf[INET6_ADDRSTRLEN];
6121         nfs_export *exp;
6122         struct nfs_fh_len *fh;
6123  
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)));
6127 +
6128         fh = get_rootfh(rqstp, path, &exp, &res->fhs_status, 1);
6129         if (!fh)
6130                 return 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)
6134  {
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;
6138         nfs_export      *exp;
6139         struct nfs_fh_len *fh;
6140         char            rpath[MAXPATHLEN+1];
6141         char            *p = *path;
6142 +       char            buf[INET6_ADDRSTRLEN];
6143  
6144         if (*p == '\0')
6145                 p = "/";
6146 @@ -413,29 +472,29 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
6147         }
6148  
6149         /* Now authenticate the intruder... */
6150 -       exp = auth_authenticate("mount", sin, p);
6151 -       if (!exp) {
6152 -               *error = NFSERR_ACCES;
6153 +       exp = auth_authenticate("mount", sap, p);
6154 +       if (exp == NULL) {
6155 +               *error = MNT3ERR_ACCES;
6156                 return NULL;
6157         }
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;
6164                 else
6165 -                       *error = NFSERR_ACCES;
6166 +                       *error = MNT3ERR_ACCES;
6167                 return NULL;
6168         }
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;
6173                 return NULL;
6174         }
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;
6180                 return NULL;
6181         }
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;
6189                 return NULL;
6190         }
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",
6195                      p);
6196 -               *error = NFSERR_NOENT;
6197 +               *error = MNT3ERR_NOENT;
6198                 return NULL;
6199         }
6200  
6201 @@ -463,12 +522,12 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
6202                  */
6203  
6204                 if (cache_export(exp, p)) {
6205 -                       *error = NFSERR_ACCES;
6206 +                       *error = MNT3ERR_ACCES;
6207                         return NULL;
6208                 }
6209                 fh = cache_get_filehandle(exp, v3?64:32, p);
6210                 if (fh == NULL) {
6211 -                       *error = NFSERR_ACCES;
6212 +                       *error = MNT3ERR_ACCES;
6213                         return NULL;
6214                 }
6215         } else {
6216 @@ -482,13 +541,13 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
6217                         xtab_append(exp);
6218  
6219                 if (v3)
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);
6231                 }
6232                 if (fh == NULL && !did_export) {
6233 @@ -498,12 +557,12 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret,
6234  
6235                 if (fh == NULL) {
6236                         xlog(L_WARNING, "getfh failed: %s", strerror(errno));
6237 -                       *error = NFSERR_ACCES;
6238 +                       *error = MNT3ERR_ACCES;
6239                         return NULL;
6240                 }
6241         }
6242 -       *error = NFS_OK;
6243 -       mountlist_add(inet_ntoa(sin->sin_addr), p);
6244 +       *error = MNT_OK;
6245 +       mountlist_add(host_ntop(sap, buf, sizeof(buf)), p);
6246         if (expret)
6247                 *expret = exp;
6248         return fh;
6249 @@ -536,22 +595,21 @@ static void free_exportlist(exports *elist)
6250  
6251  static void prune_clients(nfs_export *exp, struct exportnode *e)
6252  {
6253 -       struct hostent  *hp;
6254 +       struct addrinfo *ai = NULL;
6255         struct groupnode *c, **cp;
6256  
6257         cp = &e->ex_groups;
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)) {
6265                                 *cp = c->gr_next;
6266                                 xfree(c->gr_name);
6267                                 xfree(c);
6268 -                               xfree (hp);
6269 +                               freeaddrinfo(ai);
6270                                 continue;
6271                         }
6272 -                       xfree (hp);
6273 +                       freeaddrinfo(ai);
6274                 }
6275                 cp = &(c->gr_next);
6276         }
6277 @@ -634,13 +692,22 @@ main(int argc, char **argv)
6278  {
6279         char    *export_file = _PATH_EXPORTS;
6280         char    *state_dir = NFS_STATEDIR;
6281 +       char    *progname;
6282 +       unsigned int listeners = 0;
6283         int     foreground = 0;
6284         int     port = 0;
6285         int     descriptors = 0;
6286         int     c;
6287 +       int     vers;
6288         struct sigaction sa;
6289         struct rlimit rlim;
6290  
6291 +       /* Set the basename */
6292 +       if ((progname = strrchr(argv[0], '/')) != NULL)
6293 +               progname++;
6294 +       else
6295 +               progname = argv[0];
6296 +
6297         /* Parse the command line options and arguments. */
6298         opterr = 0;
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);
6308                         }
6309                         break;
6310                 case 'F':
6311 @@ -669,19 +736,25 @@ main(int argc, char **argv)
6312                         ha_callout_prog = optarg;
6313                         break;
6314                 case 'h':
6315 -                       usage(argv [0], 0);
6316 +                       usage(progname, 0);
6317                         break;
6318                 case 'P':       /* XXX for nfs-server compatibility */
6319                 case 'p':
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);
6327                         }
6328                         break;
6329                 case 'N':
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",
6334 +                                       argv[0], optarg);
6335 +                               usage(argv[0], 1);
6336 +                       }
6337 +                       nfs_version &= ~NFSVERSBIT(vers);
6338                         break;
6339                 case 'n':
6340                         _rpcfdtype = SOCK_DGRAM;
6341 @@ -692,7 +765,7 @@ main(int argc, char **argv)
6342                 case 's':
6343                         if ((state_dir = xstrdup(optarg)) == NULL) {
6344                                 fprintf(stderr, "%s: xstrdup(%s) failed!\n",
6345 -                                       argv[0], optarg);
6346 +                                       progname, optarg);
6347                                 exit(1);
6348                         }
6349                         break;
6350 @@ -700,31 +773,37 @@ main(int argc, char **argv)
6351                         num_threads = atoi (optarg);
6352                         break;
6353                 case 'V':
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",
6358 +                                       argv[0], optarg);
6359 +                               usage(argv[0], 1);
6360 +                       }
6361 +                       nfs_version |= NFSVERSBIT(vers);
6362                         break;
6363                 case 'v':
6364 -                       printf("kmountd %s\n", VERSION);
6365 +                       printf("%s version " VERSION "\n", progname);
6366                         exit(0);
6367                 case 0:
6368                         break;
6369                 case '?':
6370                 default:
6371 -                       usage(argv [0], 1);
6372 +                       usage(progname, 1);
6373                 }
6374  
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);
6380  
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));
6385                 exit(1);
6386         }
6387  
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));
6392         else {
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));
6401                                 exit(1);
6402                         }
6403                 }
6404         }
6405         /* Initialize logging. */
6406         if (!foreground) xlog_stderr(0);
6407 -       xlog_open("mountd");
6408 +       xlog_open(progname);
6409  
6410         sa.sa_handler = SIG_IGN;
6411         sa.sa_flags = 0;
6412 @@ -761,15 +840,17 @@ main(int argc, char **argv)
6413         if (new_cache)
6414                 cache_open();
6415  
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);
6425 +       if (version2()) {
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);
6430 +       }
6431 +       if (version3())
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");
6436  
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)
6441                 fork_workers();
6442  
6443 +       xlog(L_NOTICE, "Version " VERSION " starting");
6444         my_svc_run();
6445  
6446 -       xlog(L_ERROR, "Ack! Gack! svc_run returned!\n");
6447 +       xlog(L_ERROR, "RPC service loop terminated unexpectedly. Exiting...\n");
6448 +       unregister_services();
6449         exit(1);
6450  }
6451  
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,
6461 -                                       char *path);
6462 +nfs_export *   auth_authenticate(const char *what,
6463 +                                       const struct sockaddr *caller,
6464 +                                       const char *path);
6465  void           auth_export(nfs_export *exp);
6466  
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);
6472  
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);
6477  
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
6483 @@ -1,9 +1,9 @@
6484 -.\"
6485 -.\" mountd(8)
6486 +.\"@(#)rpc.mountd.8"
6487  .\"
6488  .\" Copyright (C) 1999 Olaf Kirch <okir@monad.swb.de>
6489  .\" Modified by Paul Clements, 2004.
6490 -.TH rpc.mountd 8 "31 Aug 2004"
6491 +.\"
6492 +.TH rpc.mountd 8 "31 Dec 2009"
6493  .SH NAME
6494  rpc.mountd \- NFS mount daemon
6495  .SH SYNOPSIS
6496 @@ -11,48 +11,73 @@ rpc.mountd \- NFS mount daemon
6497  .SH DESCRIPTION
6498  The
6499  .B rpc.mountd
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
6503 -the file system,
6504 -.B rpc.mountd
6505 -obtains a file handle for requested directory and returns it to
6506 -the client.
6507 -.SS Exporting NFS File Systems
6508 -Making file systems available to NFS clients is called
6509 -.IR exporting .
6510 -.P
6511 -Usually, a file system and the hosts it should be made available to
6512 -are listed in the
6513 -.B /etc/exports
6514 -file, and invoking
6515 -.B exportfs -a
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].
6519 +.PP
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" ,
6524 +or
6525 +.IR export ,
6526 +for short.
6527 +.PP
6528 +Each file system in the export table has an access control list.
6529 +.B rpc.mountd
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
6533 +.BR exports (5)
6534 +and
6535  .BR exportfs (8)
6536 -command makes export information available to both the kernel NFS
6537 -server module and the
6538 -.B rpc.mountd
6539 -daemon.
6540 -.P
6541 -Alternatively, you can export individual directories temporarily 
6542 -using
6543 -.BR exportfs 's
6544 -.IB host : /directory
6545 -syntax.
6546 +man pages.
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).
6552 +.PP
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.
6556 +.PP
6557 +When receiving a MNT request from an NFS client,
6558 +.B rpc.mountd
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,
6561 +.B rpc.mountd
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.
6565  .SS The rmtab File
6566 -For every mount request received from an NFS client,
6567 -.B rpc.mountd
6568 -adds an entry to the
6569 -.B /var/lib/nfs/rmtab
6570 -file. When receiving an unmount request, that entry is removed.
6571 -.P
6572 -However, this file is mostly ornamental. One, the client can continue
6573 -to use the file handle even after calling
6574 -.B rpc.mountd 's
6575 -UMOUNT procedure. And two, if a client reboots without notifying
6576 -.B rpc.mountd ,
6577 -a stale entry will remain in
6578 -.BR rmtab .
6579 +The
6580 +.B rpc.mountd
6581 +daemon registers every successful MNT request by adding an entry to the
6582 +.I /var/lib/nfs/rmtab
6583 +file.
6584 +When receivng a UMNT request from an NFS client,
6585 +.B rpc.mountd
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.
6590 +.PP
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
6594 +.BR showmount (8)
6595 +command.
6596 +.BR showmount (8)
6597 +uses other procedures in the NFS MOUNT protocol to report information
6598 +about the server's exported file systems.
6599 +.PP
6600 +Note, however, that there is little to guarantee that the contents of
6601 +.I /var/lib/nfs/rmtab
6602 +are accurate.
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 .
6607  .SH OPTIONS
6608  .TP
6609  .B \-d kind " or " \-\-debug kind
6610 @@ -94,22 +119,25 @@ Don't advertise TCP for mount.
6611  Ignored (compatibility with unfsd??).
6612  .TP
6613  .B \-p " or " \-\-port num
6614 -Force
6615 +Specifies the port number used for RPC listener sockets.
6616 +If this option is not specified,
6617  .B rpc.mountd
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.
6621 +.IP
6622 +This option can be used to fix the port value of
6623 +.BR rpc.mountd 's
6624 +listeners when NFS MOUNT requests must traverse a firewall
6625 +between clients and servers.
6626  .TP
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 
6630 -.B rpc.mountd
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
6634 -.B /proc/fs/nfsd
6635 -).
6636 -The program will be called with 4 arguments.
6637 -The first will be
6638 +Specify a high availability callout program.
6639 +This program receives callouts for all MOUNT and UNMOUNT requests.
6640 +This allows
6641 +.B rpc.mountd
6642 +to be used in a High Availability NFS (HA-NFS) environment.
6643 +.IP
6644 +The callout program is run with 4 arguments.
6645 +The first is
6646  .B mount
6647  or
6648  .B unmount
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
6652  has of that path.
6653 +.IP
6654 +This callout is not needed with 2.6 and later kernels.
6655 +Instead, mount the nfsd filesystem on
6656 +.IR /proc/fs/nfsd .
6657  .TP
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
6662 -.BR /var/lib/nfs
6663 +.I /var/lib/nfs
6664  is used.
6665  .TP
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.
6672 +.B rpc.mountd
6673 +tracks IP addresses in the
6674 +.I rmtab
6675 +file.  When a DUMP request is made (by
6676 +someone running
6677 +.BR "showmount -a" ,
6678 +for instance), it returns IP addresses instead
6679 +of hostnames by default. This option causes
6680 +.B rpc.mountd
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.
6684  .TP
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
6691 -.I newgroup
6692 +.B newgroup
6693  command on the client will still be effective.  This function requires
6694  a Linux Kernel with version at least 2.6.21.
6695 -
6696  .SH TCP_WRAPPERS SUPPORT
6697 -This
6698 +You can protect your
6699  .B rpc.mountd
6700 -version is protected by the
6701 +listeners using the
6702 +.B tcp_wrapper
6703 +library or
6704 +.BR iptables (8).
6705 +.PP
6706 +Note that the
6707  .B tcp_wrapper
6708 -library. You have to give the clients access to
6709 -.B rpc.mountd
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:
6712 -
6713 -mountd: .bar.com
6714 -
6715 -You have to use the daemon name 
6716 +library supports only IPv4 networking.
6717 +.PP
6718 +Add the hostnames of NFS peers that are allowed to access
6719 +.B rpc.mountd
6720 +to
6721 +.IR /etc/hosts.allow .
6722 +Use the daemon name
6723  .B mountd
6724 -for the daemon name (even if the binary has a different name).
6725 -.B Note:
6726 -hostnames used in either access file will be ignored when
6727 +even if the
6728 +.B rpc.mountd
6729 +binary has a different name.
6730 +.PP
6731 +Hostnames used in either access file will be ignored when
6732  they can not be resolved into IP addresses.
6733 -
6734 -For further information please have a look at the
6735 +For further information see the
6736  .BR tcpd (8)
6737  and
6738  .BR hosts_access (5)
6739 -manual pages.
6740 +man pages.
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
6744 +.BR rpc.mountd ,
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,
6748 +.B rpc.mountd
6749 +will operate.
6750 +.SH FILES
6751 +.TP 2.5i
6752 +.I /etc/exports
6753 +input file for
6754 +.BR exportfs ,
6755 +listing exports, export options, and access control lists
6756 +.TP 2.5i
6757 +.I /var/lib/nfs/rmtab
6758 +table of clients accessing server's exports
6759  .SH SEE ALSO
6760 -.BR rpc.nfsd (8),
6761  .BR exportfs (8),
6762  .BR exports (5),
6763 -.BR rpc.rquotad (8).
6764 -.SH FILES
6765 -.BR /etc/exports ,
6766 -.BR /var/lib/nfs/xtab .
6767 +.BR showmount (8),
6768 +.BR rpc.nfsd (8),
6769 +.BR rpc.rquotad (8),
6770 +.BR nfs (5),
6771 +.BR tcpd (8),
6772 +.BR hosts_access (5),
6773 +.BR iptables (8),
6774 +.BR netconfig (5)
6775 +.sp
6776 +RFC 1094 - "NFS: Network File System Protocol Specification"
6777 +.br
6778 +RFC 1813 - "NFS Version 3 Protocol Specification"
6779  .SH AUTHOR
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
6785 @@ -16,7 +16,7 @@
6786  #include <netinet/in.h>
6787  #include <arpa/inet.h>
6788  #include <netdb.h>
6789 -#include "xmalloc.h"
6790 +
6791  #include "misc.h"
6792  #include "exportfs.h"
6793  #include "xio.h"
6794 @@ -131,22 +131,22 @@ mountlist_del(char *hname, const char *path)
6795  }
6796  
6797  void
6798 -mountlist_del_all(struct sockaddr_in *sin)
6799 +mountlist_del_all(const struct sockaddr *sap)
6800  {
6801 -       struct in_addr  addr = sin->sin_addr;
6802 -       struct hostent  *hp;
6803 +       char            *hostname;
6804         struct rmtabent *rep;
6805 -       nfs_export      *exp;
6806         FILE            *fp;
6807         int             lockid;
6808  
6809         if ((lockid = xflock(_PATH_RMTABLCK, "w")) < 0)
6810                 return;
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)));
6818                 goto out_unlock;
6819         }
6820 -       hp = hostent_dup (hp);
6821  
6822         if (!setrmtabent("r"))
6823                 goto out_free;
6824 @@ -155,8 +155,8 @@ mountlist_del_all(struct sockaddr_in *sin)
6825                 goto out_close;
6826  
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)
6832                         continue;
6833                 fputrmtabent(fp, rep, NULL);
6834         }
6835 @@ -168,11 +168,23 @@ mountlist_del_all(struct sockaddr_in *sin)
6836  out_close:
6837         endrmtabent();  /* close & unlink */
6838  out_free:
6839 -       free (hp);
6840 +       free(hostname);
6841  out_unlock:
6842         xfunlock(lockid);
6843  }
6844  
6845 +static void
6846 +mountlist_freeall(mountlist list)
6847 +{
6848 +       while (list != NULL) {
6849 +               mountlist m = list;
6850 +               list = m->ml_next;
6851 +               free(m->ml_hostname);
6852 +               free(m->ml_directory);
6853 +               free(m);
6854 +       }
6855 +}
6856 +
6857  mountlist
6858  mountlist_list(void)
6859  {
6860 @@ -182,8 +194,6 @@ mountlist_list(void)
6861         struct rmtabent         *rep;
6862         struct stat             stb;
6863         int                     lockid;
6864 -       struct in_addr          addr;
6865 -       struct hostent          *he;
6866  
6867         if ((lockid = xflock(_PATH_RMTABLCK, "r")) < 0)
6868                 return NULL;
6869 @@ -194,26 +204,41 @@ mountlist_list(void)
6870                 return NULL;
6871         }
6872         if (stb.st_mtime != last_mtime) {
6873 -               while (mlist) {
6874 -                       mlist = (m = mlist)->ml_next;
6875 -                       xfree(m->ml_hostname);
6876 -                       xfree(m->ml_directory);
6877 -                       xfree(m);
6878 -               }
6879 +               mountlist_freeall(mlist);
6880                 last_mtime = stb.st_mtime;
6881  
6882                 setrmtabent("r");
6883                 while ((rep = getrmtabent(1, NULL)) != NULL) {
6884 -                       m = (mountlist) xmalloc(sizeof(*m));
6885 -
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);
6890 -                       else
6891 -                               m->ml_hostname = xstrdup(rep->r_client);
6892 +                       m = calloc(1, sizeof(*m));
6893 +                       if (m == NULL) {
6894 +                               mountlist_freeall(mlist);
6895 +                               mlist = NULL;
6896 +                               xlog(L_ERROR, "%s: memory allocation failed",
6897 +                                               __func__);
6898 +                               break;
6899 +                       }
6900 +
6901 +                       if (reverse_resolve) {
6902 +                               struct addrinfo *ai;
6903 +                               ai = host_pton(rep->r_client);
6904 +                               if (ai != NULL) {
6905 +                                       m->ml_hostname = host_canonname(ai->ai_addr);
6906 +                                       freeaddrinfo(ai);
6907 +                               }
6908 +                       }
6909 +                       if (m->ml_hostname == NULL)
6910 +                               m->ml_hostname = strdup(rep->r_client);
6911 +
6912 +                       m->ml_directory = strdup(rep->r_path);
6913 +
6914 +                       if (m->ml_hostname == NULL || m->ml_directory == NULL) {
6915 +                               mountlist_freeall(mlist);
6916 +                               mlist = NULL;
6917 +                               xlog(L_ERROR, "%s: memory allocation failed",
6918 +                                               __func__);
6919 +                               break;
6920 +                       }
6921  
6922 -                       m->ml_directory = xstrdup(rep->r_path);
6923                         m->ml_next = mlist;
6924                         mlist = m;
6925                 }
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
6930 @@ -27,15 +27,6 @@
6931  #include "nfssvc.h"
6932  #include "xlog.h"
6933  
6934 -/*
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
6939 - * are functional.
6940 - */
6941 -#undef IPV6_SUPPORTED
6942 -
6943  static void    usage(const char *);
6944  
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
6950 @@ -22,15 +22,6 @@
6951  #include "nfslib.h"
6952  #include "xlog.h"
6953  
6954 -/*
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
6959 - * are functional.
6960 - */
6961 -#undef IPV6_SUPPORTED
6962 -
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)
6967                 }
6968  
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)) {
6972                         /*
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)
6976         }
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);
6982  
6983         close(fd);
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));
6987                 close(fd);
6988 -               if (n != strlen(buf))
6989 +               if (n != (ssize_t)strlen(buf))
6990                         return -1;
6991                 else
6992                         return 0;
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,
6998  {
6999         unsigned long long      total;
7000         unsigned long long      pct;
7001 -       int             i, j;
7002 +       unsigned int            i, j;
7003  
7004         fputs(hdr, stdout);
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)
7008  {
7009         unsigned long long      calltotal;
7010 -       int                     i;
7011 +       unsigned int                    i;
7012  
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);
7021  }
7022  
7023  static void
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)
7029         }
7030  
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",
7036 +                               program_name);
7037 +               clnt_destroy(mclient);
7038 +               exit(1);
7039 +       }
7040         total_timeout.tv_sec = TOTAL_TIMEOUT;
7041         total_timeout.tv_usec = 0;
7042  
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));
7049                 freeaddrinfo(ai);
7050                 if (!result)
7051 -                       return NULL;
7052 +                       /* OK to use presentation address,
7053 +                        * if no reverse map exists */
7054 +                       return strdup(hostname);
7055                 return strdup(buf);
7056         }
7057  
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 {
7063         uint32_t                xid;
7064  };
7065  
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,
7072                 }
7073         }
7074  
7075 -       if (opt_srcaddr) {
7076 -               strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname)-1);
7077 -       } else
7078 -       if (gethostname(nsm_hostname, sizeof(nsm_hostname)) < 0) {
7079 -               xlog(L_ERROR, "Failed to obtain name of local host: %m");
7080 -               exit(1);
7081 +       if (opt_srcaddr != NULL) {
7082 +               struct addrinfo *ai = NULL;
7083 +               struct addrinfo hint = {
7084 +                       .ai_family      = AF_UNSPEC,
7085 +                       .ai_flags       = AI_NUMERICHOST,
7086 +               };
7087 +
7088 +               if (getaddrinfo(opt_srcaddr, NULL, &hint, &ai))
7089 +                       /* not a presentation address - use it */
7090 +                       strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname));
7091 +               else {
7092 +                       /* was a presentation address - look it up in
7093 +                        * /etc/hosts, so it can be used for my_name */
7094 +                       int error;
7095 +
7096 +                       freeaddrinfo(ai);
7097 +                       hint.ai_flags = AI_CANONNAME;
7098 +                       error = getaddrinfo(opt_srcaddr, NULL, &hint, &ai);
7099 +                       if (error != 0) {
7100 +                               xlog(L_ERROR, "Bind address %s is unusable: %s",
7101 +                                               opt_srcaddr, gai_strerror(error));
7102 +                               exit(1);
7103 +                       }
7104 +                       strncpy(nsm_hostname, ai->ai_canonname,
7105 +                                                       sizeof(nsm_hostname));
7106 +                       freeaddrinfo(ai);
7107 +               }
7108         }
7109  
7110         (void)nsm_retire_monitored_hosts();
7111 @@ -535,6 +556,8 @@ notify(const int sock)
7112  static int
7113  notify_host(int sock, struct nsm_host *host)
7114  {
7115 +       const char *my_name = (opt_srcaddr != NULL ?
7116 +                                       nsm_hostname : host->my_name);
7117         struct sockaddr *sap;
7118         socklen_t salen;
7119  
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);
7122         else
7123                 host->xid = nsm_xmit_notify(sock, sap, salen,
7124 -                               SM_PROG, nsm_hostname, nsm_state);
7125 -       
7126 +                                       SM_PROG, my_name, nsm_state);
7127 +
7128         return 0;
7129  }
7130  
7131 @@ -611,15 +634,28 @@ recv_rpcbind_reply(struct sockaddr *sap, struct nsm_host *host, XDR *xdr)
7132  }
7133  
7134  /*
7135 - * Successful NOTIFY call. Server returns void, so nothing
7136 - * we need to do here.
7137 + * Successful NOTIFY call. Server returns void.
7138 + *
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.
7142   */
7143  static void
7144  recv_notify_reply(struct nsm_host *host)
7145  {
7146 -       xlog(D_GENERAL, "Host %s notified successfully", host->name);
7147 +       char *dot = strchr(host->my_name, '.');
7148  
7149 -       smn_forget_host(host);
7150 +       if (dot != NULL) {
7151 +               *dot = '\0';
7152 +               host->send_next = time(NULL);
7153 +               host->xid = 0;
7154 +               if (host->timeout >= NSM_MAX_TIMEOUT / 4)
7155 +                       host->timeout = NSM_MAX_TIMEOUT / 4;
7156 +               insert_host(host);
7157 +       } else {
7158 +               xlog(D_GENERAL, "Host %s notified successfully", host->name);
7159 +               smn_forget_host(host);
7160 +       }
7161  }
7162  
7163  /*
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
7171  .B sm-notify
7172 -command normally sends the results of
7173 -.BR gethostname (3)
7174 -as the
7175 +command normally sends
7176  .I my_name
7177 -string.
7178 +string recorded when that remote was monitored.
7179  The remote
7180  .B rpc.statd
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,
7184  .B sm-notify
7185  uses a wildcard address as the transport bind address,
7186 -and uses the results of
7187 -.BR gethostname (3)
7188 -as the
7189 +and uses the
7190 +.I my_name
7191 +recorded when the remote was monitored as the
7192  .I mon_name
7193 -argument.
7194 +argument when sending SM_NOTIFY requests.
7195  .IP
7196  The
7197  .I ipaddr
7198  form can be expressed as either an IPv4 or an IPv6 presentation address.
7199 +If the
7200 +.I ipaddr
7201 +form is used, the
7202 +.B sm-notify
7203 +command converts this address to a hostname for use as the
7204 +.I mon_name
7205 +argument when sending SM_NOTIFY requests.
7206  .IP
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
7211  .I mon_name
7212  in SM_NOTIFY requests it sends
7213 -.IP
7214 -The use of network addresses as a
7215 -.I mon_name
7216 -or a
7217 -.I my_name
7218 -string should be avoided when
7219 -interoperating with non-Linux NFS implementations.
7220  .PP
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
7230  .B sm-notify
7231 -command normally sends the results of
7232 -.BR gethostname (3)
7233 -as the
7234 +command sends the
7235  .I my_name
7236 -string.
7237 +string recorded when that remote was monitored.
7238  The remote
7239  .B rpc.statd
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.
7245 -.PP
7246  To help
7247  .B rpc.statd
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
7251  .I mon_name
7252  in SM_NOTIFY requests it sends
7253 -.IP
7254 -The use of network addresses as a
7255 -.I mon_name
7256 -or a
7257 -.I my_name
7258 -string should be avoided when
7259 -interoperating with non-Linux NFS implementations.
7260  .PP
7261  Unmounting an NFS file system does not necessarily stop
7262  either the NFS client or server from monitoring each other.
This page took 1.558328 seconds and 3 git commands to generate.