]> git.pld-linux.org Git - packages/nfs-utils.git/blame - nfs-utils-git.patch
- mountd does no support --no-nfs-version 1 any more
[packages/nfs-utils.git] / nfs-utils-git.patch
CommitLineData
747453cc
JR
1diff --git a/aclocal/libcap.m4 b/aclocal/libcap.m4
2index 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
30diff --git a/autogen.sh b/autogen.sh
31old mode 100644
32new mode 100755
33diff --git a/configure.ac b/configure.ac
34index 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
64diff --git a/support/export/client.c b/support/export/client.c
65index 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 }
976diff --git a/support/export/export.c b/support/export/export.c
977index 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 }
1226diff --git a/support/export/hostname.c b/support/export/hostname.c
1227index 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 */
1876diff --git a/support/export/nfsctl.c b/support/export/nfsctl.c
1877index 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;
1921diff --git a/support/export/rmtab.c b/support/export/rmtab.c
1922index 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. */
2003diff --git a/support/include/exportfs.h b/support/include/exportfs.h
2004index 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);
2134diff --git a/support/include/misc.h b/support/include/misc.h
2135index 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 */
2152diff --git a/support/include/nfslib.h b/support/include/nfslib.h
2153index 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 */
2198diff --git a/support/include/nfsrpc.h b/support/include/nfsrpc.h
2199index 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 */
2210diff --git a/support/include/rpcmisc.h b/support/include/rpcmisc.h
2211index 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 */
2229diff --git a/support/nfs/cacheio.c b/support/nfs/cacheio.c
2230index 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 }
2275diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
2276index 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) {
2315diff --git a/support/nfs/exports.c b/support/nfs/exports.c
2316index 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
2328diff --git a/support/nfs/getfh.c b/support/nfs/getfh.c
2329index 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)
2451diff --git a/support/nfs/nfs_mntent.c b/support/nfs/nfs_mntent.c
2452index 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);
2464diff --git a/support/nfs/rmtab.c b/support/nfs/rmtab.c
2465index 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
2544diff --git a/support/nfs/rpc_socket.c b/support/nfs/rpc_socket.c
2545index 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+}
2573diff --git a/support/nfs/rpcdispatch.c b/support/nfs/rpcdispatch.c
2574index 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 }
2592diff --git a/support/nfs/rpcmisc.c b/support/nfs/rpcmisc.c
2593index 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.");
2605diff --git a/support/nfs/svc_socket.c b/support/nfs/svc_socket.c
2606index 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;
2630diff --git a/support/nsm/file.c b/support/nsm/file.c
2631index 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
2660diff --git a/tests/t0001-statd-basic-mon-unmon.sh b/tests/t0001-statd-basic-mon-unmon.sh
2661old mode 100644
2662new mode 100755
2663diff --git a/tools/Makefile.am b/tools/Makefile.am
2664index 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
2675diff --git a/tools/mountstats/Makefile.am b/tools/mountstats/Makefile.am
2676new file mode 100644
2677index 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
2694diff --git a/tools/mountstats/mountstats.man b/tools/mountstats/mountstats.man
2695new file mode 100644
2696index 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>
2732diff --git a/tools/nfs-iostat/Makefile.am b/tools/nfs-iostat/Makefile.am
2733new file mode 100644
2734index 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
2751diff --git a/tools/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py
2752index 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:
2768diff --git a/tools/nfs-iostat/nfsiostat.man b/tools/nfs-iostat/nfsiostat.man
2769new file mode 100644
2770index 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>
2845diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c
2846index 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 }
3174diff --git a/utils/exportfs/exportfs.man b/utils/exportfs/exportfs.man
3175index 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>
3567diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man
3568index 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.
3777diff --git a/utils/gssd/context.h b/utils/gssd/context.h
3778index 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);
3799diff --git a/utils/gssd/context_lucid.c b/utils/gssd/context_lucid.c
3800index 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 */
3997diff --git a/utils/gssd/context_mit.c b/utils/gssd/context_mit.c
3998index 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 }
4179diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c
4180index 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
4192diff --git a/utils/gssd/gssd_main_loop.c b/utils/gssd/gssd_main_loop.c
4193index 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
4205diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
4206index 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;
4353diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c
4354index 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 */
4574diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h
4575index 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 /*
4587diff --git a/utils/gssd/svcgssd.c b/utils/gssd/svcgssd.c
4588index 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
4600diff --git a/utils/gssd/svcgssd_proc.c b/utils/gssd/svcgssd_proc.c
4601index 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 }
4644diff --git a/utils/idmapd/atomicio.c b/utils/idmapd/atomicio.c
4645index 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);
4658diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c
4659index 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 ;
4759diff --git a/utils/mount/configfile.c b/utils/mount/configfile.c
4760index 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");
4783diff --git a/utils/mount/network.c b/utils/mount/network.c
4784index 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;
4954diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man
4955index 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
4976diff --git a/utils/mount/nfs4mount.c b/utils/mount/nfs4mount.c
4977index 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 }
4989diff --git a/utils/mount/nfsmount.c b/utils/mount/nfsmount.c
4990index 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;
5008diff --git a/utils/mount/nfsumount.c b/utils/mount/nfsumount.c
5009index 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)
5024diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
5025index 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 */
5074diff --git a/utils/mountd/auth.c b/utils/mountd/auth.c
5075index 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
5273diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c
5274index 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-
5860diff --git a/utils/mountd/fsloc.c b/utils/mountd/fsloc.c
5861index 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) {
5873diff --git a/utils/mountd/fsloc.h b/utils/mountd/fsloc.h
5874index 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 */
5886diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c
5887index 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
6452diff --git a/utils/mountd/mountd.h b/utils/mountd/mountd.h
6453index 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 */
6479diff --git a/utils/mountd/mountd.man b/utils/mountd/mountd.man
6480index 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.
6781diff --git a/utils/mountd/rmtab.c b/utils/mountd/rmtab.c
6782index 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 }
6926diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c
6927index 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[] =
6946diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c
6947index 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;
6993diff --git a/utils/nfsstat/nfsstat.c b/utils/nfsstat/nfsstat.c
6994index 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
7024diff --git a/utils/showmount/showmount.c b/utils/showmount/showmount.c
7025index 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
7043diff --git a/utils/statd/hostname.c b/utils/statd/hostname.c
7044index 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
7058diff --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c
7059index 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 /*
7164diff --git a/utils/statd/sm-notify.man b/utils/statd/sm-notify.man
7165index 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.
7223diff --git a/utils/statd/statd.man b/utils/statd/statd.man
7224index 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 0.840826 seconds and 4 git commands to generate.