]>
Commit | Line | Data |
---|---|---|
747453cc JR |
1 | diff --git a/aclocal/libcap.m4 b/aclocal/libcap.m4 |
2 | index eabe507..68a624c 100644 | |
3 | --- a/aclocal/libcap.m4 | |
4 | +++ b/aclocal/libcap.m4 | |
5 | @@ -5,11 +5,19 @@ AC_DEFUN([AC_LIBCAP], [ | |
6 | dnl look for prctl | |
7 | AC_CHECK_FUNC([prctl], , ) | |
8 | ||
9 | - dnl look for the library; do not add to LIBS if found | |
10 | - AC_CHECK_LIB([cap], [cap_get_proc], [LIBCAP=-lcap], ,) | |
11 | - AC_SUBST(LIBCAP) | |
12 | + AC_ARG_ENABLE([caps], | |
13 | + [AS_HELP_STRING([--disable-caps], [Disable capabilities support])]) | |
14 | + | |
15 | + LIBCAP= | |
16 | + | |
17 | + if test "x$enable_caps" != "xno" ; then | |
18 | + dnl look for the library; do not add to LIBS if found | |
19 | + AC_CHECK_LIB([cap], [cap_get_proc], [LIBCAP=-lcap], ,) | |
20 | ||
21 | - AC_CHECK_HEADERS([sys/capability.h], , | |
22 | - [AC_MSG_ERROR([libcap headers not found.])]) | |
23 | + AC_CHECK_HEADERS([sys/capability.h], , | |
24 | + [test "x$enable_caps" = "xyes" && AC_MSG_ERROR([libcap headers not found.])]) | |
25 | + fi | |
26 | + | |
27 | + AC_SUBST(LIBCAP) | |
28 | ||
29 | ])dnl | |
30 | diff --git a/autogen.sh b/autogen.sh | |
31 | old mode 100644 | |
32 | new mode 100755 | |
33 | diff --git a/configure.ac b/configure.ac | |
34 | index b7520d8..7c9e61a 100644 | |
35 | --- a/configure.ac | |
36 | +++ b/configure.ac | |
37 | @@ -81,7 +81,7 @@ AC_ARG_ENABLE(nfsv41, | |
38 | if test "$enable_nfsv41" = yes; then | |
39 | AC_DEFINE(NFS41_SUPPORTED, 1, [Define this if you want NFSv41 support compiled in]) | |
40 | else | |
41 | - enable_nfsv4= | |
42 | + enable_nfsv41= | |
43 | fi | |
44 | AC_SUBST(enable_nfsv41) | |
45 | AM_CONDITIONAL(CONFIG_NFSV41, [test "$enable_nfsv41" = "yes"]) | |
46 | @@ -400,7 +400,7 @@ case $host in | |
47 | ARCHFLAGS="" ;; | |
48 | esac | |
49 | ||
50 | -my_am_cflags="-Wall -Wstrict-prototypes $ARCHFLAGS -pipe" | |
51 | +my_am_cflags="-Wall -Wextra -Wstrict-prototypes $ARCHFLAGS -pipe" | |
52 | ||
53 | AC_SUBST([AM_CFLAGS], ["$my_am_cflags"]) | |
54 | ||
55 | @@ -425,6 +425,8 @@ AC_CONFIG_FILES([ | |
56 | tools/nlmtest/Makefile | |
57 | tools/rpcdebug/Makefile | |
58 | tools/rpcgen/Makefile | |
59 | + tools/mountstats/Makefile | |
60 | + tools/nfs-iostat/Makefile | |
61 | utils/Makefile | |
62 | utils/exportfs/Makefile | |
63 | utils/gssd/Makefile | |
64 | diff --git a/support/export/client.c b/support/export/client.c | |
65 | index 6236561..c74961e 100644 | |
66 | --- a/support/export/client.c | |
67 | +++ b/support/export/client.c | |
68 | @@ -17,7 +17,9 @@ | |
69 | #include <string.h> | |
70 | #include <ctype.h> | |
71 | #include <netdb.h> | |
72 | -#include "xmalloc.h" | |
73 | +#include <errno.h> | |
74 | + | |
75 | +#include "sockaddr.h" | |
76 | #include "misc.h" | |
77 | #include "nfslib.h" | |
78 | #include "exportfs.h" | |
79 | @@ -28,58 +30,211 @@ | |
80 | #if !defined(__GLIBC__) || __GLIBC__ < 2 | |
81 | extern int innetgr(char *netgr, char *host, char *, char *); | |
82 | #endif | |
83 | -static void client_init(nfs_client *clp, const char *hname, | |
84 | - struct hostent *hp); | |
85 | -static int client_checkaddr(nfs_client *clp, struct in_addr addr); | |
86 | + | |
87 | +static char *add_name(char *old, const char *add); | |
88 | ||
89 | nfs_client *clientlist[MCL_MAXTYPES] = { NULL, }; | |
90 | ||
91 | ||
92 | -/* if canonical is set, then we *know* this is already a canonical name | |
93 | - * so hostname lookup is avoided. | |
94 | - * This is used when reading /proc/fs/nfs/exports | |
95 | +static void | |
96 | +init_addrlist(nfs_client *clp, const struct addrinfo *ai) | |
97 | +{ | |
98 | + int i; | |
99 | + | |
100 | + if (ai == NULL) | |
101 | + return; | |
102 | + | |
103 | + for (i = 0; (ai != NULL) && (i < NFSCLNT_ADDRMAX); i++) { | |
104 | + set_addrlist(clp, i, ai->ai_addr); | |
105 | + ai = ai->ai_next; | |
106 | + } | |
107 | + | |
108 | + clp->m_naddr = i; | |
109 | +} | |
110 | + | |
111 | +static void | |
112 | +client_free(nfs_client *clp) | |
113 | +{ | |
114 | + free(clp->m_hostname); | |
115 | + free(clp); | |
116 | +} | |
117 | + | |
118 | +static int | |
119 | +init_netmask(nfs_client *clp, const char *slash, const sa_family_t family) | |
120 | +{ | |
121 | + struct sockaddr_in sin = { | |
122 | + .sin_family = AF_INET, | |
123 | + }; | |
124 | + unsigned long prefixlen; | |
125 | + uint32_t shift; | |
126 | +#ifdef IPV6_SUPPORTED | |
127 | + struct sockaddr_in6 sin6 = { | |
128 | + .sin6_family = AF_INET6, | |
129 | + }; | |
130 | + int i; | |
131 | +#endif | |
132 | + | |
133 | + /* No slash present; assume netmask is all ones */ | |
134 | + if (slash == NULL) { | |
135 | + switch (family) { | |
136 | + case AF_INET: | |
137 | + prefixlen = 32; | |
138 | + break; | |
139 | +#ifdef IPV6_SUPPORTED | |
140 | + case AF_INET6: | |
141 | + prefixlen = 128; | |
142 | + break; | |
143 | +#endif | |
144 | + default: | |
145 | + goto out_badfamily; | |
146 | + } | |
147 | + } else { | |
148 | + char *endptr; | |
149 | + | |
150 | + /* A spelled out netmask address, perhaps? */ | |
151 | + if (strchr(slash + 1, '.') != NULL) { | |
152 | + if (inet_pton(AF_INET, slash + 1, | |
153 | + &sin.sin_addr.s_addr) == 0) | |
154 | + goto out_badmask; | |
155 | + set_addrlist_in(clp, 1, &sin); | |
156 | + return 1; | |
157 | + } | |
158 | +#ifdef IPV6_SUPPORTED | |
159 | + if (strchr(slash + 1, ':')) { | |
160 | + if (!inet_pton(AF_INET6, slash + 1, &sin6.sin6_addr)) | |
161 | + goto out_badmask; | |
162 | + set_addrlist_in6(clp, 1, &sin6); | |
163 | + return 1; | |
164 | + } | |
165 | +#endif | |
166 | + | |
167 | + /* A prefixlen was given */ | |
168 | + prefixlen = strtoul(slash + 1, &endptr, 10); | |
169 | + if (*endptr != '\0' && prefixlen != ULONG_MAX && errno != ERANGE) | |
170 | + goto out_badprefix; | |
171 | + } | |
172 | + | |
173 | + switch (family) { | |
174 | + case AF_INET: | |
175 | + if (prefixlen > 32) | |
176 | + goto out_badprefix; | |
177 | + shift = 32 - (uint32_t)prefixlen; | |
178 | + sin.sin_addr.s_addr = htonl((uint32_t)~0 << shift); | |
179 | + set_addrlist_in(clp, 1, &sin); | |
180 | + return 1; | |
181 | +#ifdef IPV6_SUPPORTED | |
182 | + case AF_INET6: | |
183 | + if (prefixlen > 128) | |
184 | + goto out_badprefix; | |
185 | + for (i = 0; prefixlen > 32; i++) { | |
186 | + sin6.sin6_addr.s6_addr32[i] = 0xffffffff; | |
187 | + prefixlen -= 32; | |
188 | + } | |
189 | + shift = 32 - (uint32_t)prefixlen; | |
190 | + sin6.sin6_addr.s6_addr32[i] = htonl((uint32_t)~0 << shift); | |
191 | + set_addrlist_in6(clp, 1, &sin6); | |
192 | + return 1; | |
193 | +#endif | |
194 | + } | |
195 | + | |
196 | +out_badfamily: | |
197 | + xlog(L_ERROR, "Unsupported address family for %s", clp->m_hostname); | |
198 | + return 0; | |
199 | + | |
200 | +out_badmask: | |
201 | + xlog(L_ERROR, "Invalid netmask `%s' for %s", slash + 1, clp->m_hostname); | |
202 | + return 0; | |
203 | + | |
204 | +out_badprefix: | |
205 | + xlog(L_ERROR, "Invalid prefix `%s' for %s", slash + 1, clp->m_hostname); | |
206 | + return 0; | |
207 | +} | |
208 | + | |
209 | +static int | |
210 | +init_subnetwork(nfs_client *clp) | |
211 | +{ | |
212 | + struct addrinfo *ai; | |
213 | + sa_family_t family; | |
214 | + char *slash; | |
215 | + | |
216 | + slash = strchr(clp->m_hostname, '/'); | |
217 | + if (slash != NULL) { | |
218 | + *slash = '\0'; | |
219 | + ai = host_pton(clp->m_hostname); | |
220 | + *slash = '/'; | |
221 | + } else | |
222 | + ai = host_pton(clp->m_hostname); | |
223 | + if (ai == NULL) { | |
224 | + xlog(L_ERROR, "Invalid IP address %s", clp->m_hostname); | |
225 | + return false; | |
226 | + } | |
227 | + | |
228 | + set_addrlist(clp, 0, ai->ai_addr); | |
229 | + family = ai->ai_addr->sa_family; | |
230 | + | |
231 | + freeaddrinfo(ai); | |
232 | + | |
233 | + return init_netmask(clp, slash, family); | |
234 | +} | |
235 | + | |
236 | +static int | |
237 | +client_init(nfs_client *clp, const char *hname, const struct addrinfo *ai) | |
238 | +{ | |
239 | + clp->m_hostname = strdup(hname); | |
240 | + if (clp->m_hostname == NULL) | |
241 | + return 0; | |
242 | + | |
243 | + clp->m_exported = 0; | |
244 | + clp->m_count = 0; | |
245 | + clp->m_naddr = 0; | |
246 | + | |
247 | + if (clp->m_type == MCL_SUBNETWORK) | |
248 | + return init_subnetwork(clp); | |
249 | + | |
250 | + init_addrlist(clp, ai); | |
251 | + return 1; | |
252 | +} | |
253 | + | |
254 | +static void | |
255 | +client_add(nfs_client *clp) | |
256 | +{ | |
257 | + nfs_client **cpp; | |
258 | + | |
259 | + cpp = &clientlist[clp->m_type]; | |
260 | + while (*cpp != NULL) | |
261 | + cpp = &((*cpp)->m_next); | |
262 | + clp->m_next = NULL; | |
263 | + *cpp = clp; | |
264 | +} | |
265 | + | |
266 | +/** | |
267 | + * client_lookup - look for @hname in our list of cached nfs_clients | |
268 | + * @hname: '\0'-terminated ASCII string containing hostname to look for | |
269 | + * @canonical: if set, @hname is known to be canonical DNS name | |
270 | + * | |
271 | + * Returns pointer to a matching or freshly created nfs_client. NULL | |
272 | + * is returned if some problem occurs. | |
273 | */ | |
274 | nfs_client * | |
275 | client_lookup(char *hname, int canonical) | |
276 | { | |
277 | nfs_client *clp = NULL; | |
278 | int htype; | |
279 | - struct hostent *hp = NULL; | |
280 | + struct addrinfo *ai = NULL; | |
281 | ||
282 | htype = client_gettype(hname); | |
283 | ||
284 | if (htype == MCL_FQDN && !canonical) { | |
285 | - struct hostent *hp2; | |
286 | - hp = gethostbyname(hname); | |
287 | - if (hp == NULL || hp->h_addrtype != AF_INET) { | |
288 | - xlog(L_ERROR, "%s has non-inet addr", hname); | |
289 | - return NULL; | |
290 | + ai = host_addrinfo(hname); | |
291 | + if (!ai) { | |
292 | + xlog(L_ERROR, "Failed to resolve %s", hname); | |
293 | + goto out; | |
294 | } | |
295 | - /* make sure we have canonical name */ | |
296 | - hp2 = hostent_dup(hp); | |
297 | - hp = gethostbyaddr(hp2->h_addr, hp2->h_length, | |
298 | - hp2->h_addrtype); | |
299 | - if (hp) { | |
300 | - hp = hostent_dup(hp); | |
301 | - /* but now we might not have all addresses... */ | |
302 | - if (hp2->h_addr_list[1]) { | |
303 | - struct hostent *hp3 = | |
304 | - gethostbyname(hp->h_name); | |
305 | - if (hp3) { | |
306 | - free(hp); | |
307 | - hp = hostent_dup(hp3); | |
308 | - } | |
309 | - } | |
310 | - free(hp2); | |
311 | - } else | |
312 | - hp = hp2; | |
313 | - | |
314 | - hname = (char *) hp->h_name; | |
315 | + hname = ai->ai_canonname; | |
316 | ||
317 | - for (clp = clientlist[htype]; clp; clp = clp->m_next) { | |
318 | - if (client_check(clp, hp)) | |
319 | + for (clp = clientlist[htype]; clp; clp = clp->m_next) | |
320 | + if (client_check(clp, ai)) | |
321 | break; | |
322 | - } | |
323 | } else { | |
324 | for (clp = clientlist[htype]; clp; clp = clp->m_next) { | |
325 | if (strcasecmp(hname, clp->m_hostname)==0) | |
326 | @@ -87,106 +242,60 @@ client_lookup(char *hname, int canonical) | |
327 | } | |
328 | } | |
329 | ||
330 | - if (!clp) { | |
331 | - clp = (nfs_client *) xmalloc(sizeof(*clp)); | |
332 | - memset(clp, 0, sizeof(*clp)); | |
333 | + if (clp == NULL) { | |
334 | + clp = calloc(1, sizeof(*clp)); | |
335 | + if (clp == NULL) | |
336 | + goto out; | |
337 | clp->m_type = htype; | |
338 | - client_init(clp, hname, NULL); | |
339 | + if (!client_init(clp, hname, NULL)) { | |
340 | + client_free(clp); | |
341 | + clp = NULL; | |
342 | + goto out; | |
343 | + } | |
344 | client_add(clp); | |
345 | } | |
346 | ||
347 | - if (htype == MCL_FQDN && clp->m_naddr == 0 && hp != NULL) { | |
348 | - char **ap = hp->h_addr_list; | |
349 | - int i; | |
350 | - | |
351 | - for (i = 0; *ap && i < NFSCLNT_ADDRMAX; i++, ap++) | |
352 | - clp->m_addrlist[i] = *(struct in_addr *)*ap; | |
353 | - clp->m_naddr = i; | |
354 | - } | |
355 | - | |
356 | - if (hp) | |
357 | - free (hp); | |
358 | + if (htype == MCL_FQDN && clp->m_naddr == 0) | |
359 | + init_addrlist(clp, ai); | |
360 | ||
361 | +out: | |
362 | + freeaddrinfo(ai); | |
363 | return clp; | |
364 | } | |
365 | ||
366 | +/** | |
367 | + * client_dup - create a copy of an nfs_client | |
368 | + * @clp: pointer to nfs_client to copy | |
369 | + * @ai: pointer to addrinfo used to initialize the new client's addrlist | |
370 | + * | |
371 | + * Returns a dynamically allocated nfs_client if successful, or | |
372 | + * NULL if some problem occurs. Caller must free the returned | |
373 | + * nfs_client with free(3). | |
374 | + */ | |
375 | nfs_client * | |
376 | -client_dup(nfs_client *clp, struct hostent *hp) | |
377 | +client_dup(const nfs_client *clp, const struct addrinfo *ai) | |
378 | { | |
379 | nfs_client *new; | |
380 | ||
381 | - new = (nfs_client *) xmalloc(sizeof(*new)); | |
382 | + new = (nfs_client *)malloc(sizeof(*new)); | |
383 | + if (new == NULL) | |
384 | + return NULL; | |
385 | memcpy(new, clp, sizeof(*new)); | |
386 | new->m_type = MCL_FQDN; | |
387 | new->m_hostname = NULL; | |
388 | ||
389 | - client_init(new, (char *) hp->h_name, hp); | |
390 | + if (!client_init(new, ai->ai_canonname, ai)) { | |
391 | + client_free(new); | |
392 | + return NULL; | |
393 | + } | |
394 | client_add(new); | |
395 | return new; | |
396 | } | |
397 | ||
398 | -static void | |
399 | -client_init(nfs_client *clp, const char *hname, struct hostent *hp) | |
400 | -{ | |
401 | - xfree(clp->m_hostname); | |
402 | - if (hp) | |
403 | - clp->m_hostname = xstrdup(hp->h_name); | |
404 | - else | |
405 | - clp->m_hostname = xstrdup(hname); | |
406 | - | |
407 | - clp->m_exported = 0; | |
408 | - clp->m_count = 0; | |
409 | - | |
410 | - if (clp->m_type == MCL_SUBNETWORK) { | |
411 | - char *cp = strchr(clp->m_hostname, '/'); | |
412 | - static char slash32[] = "/32"; | |
413 | - | |
414 | - if(!cp) cp = slash32; | |
415 | - *cp = '\0'; | |
416 | - clp->m_addrlist[0].s_addr = inet_addr(clp->m_hostname); | |
417 | - if (strchr(cp + 1, '.')) { | |
418 | - clp->m_addrlist[1].s_addr = inet_addr(cp+1); | |
419 | - } | |
420 | - else { | |
421 | - int netmask = atoi(cp + 1); | |
422 | - if (0 < netmask && netmask <= 32) { | |
423 | - clp->m_addrlist[1].s_addr = | |
424 | - htonl ((uint32_t) ~0 << (32 - netmask)); | |
425 | - } | |
426 | - else { | |
427 | - xlog(L_FATAL, "invalid netmask `%s' for %s", | |
428 | - cp + 1, clp->m_hostname); | |
429 | - } | |
430 | - } | |
431 | - *cp = '/'; | |
432 | - clp->m_naddr = 0; | |
433 | - } else if (!hp) { | |
434 | - clp->m_naddr = 0; | |
435 | - } else { | |
436 | - char **ap = hp->h_addr_list; | |
437 | - int i; | |
438 | - | |
439 | - for (i = 0; *ap && i < NFSCLNT_ADDRMAX; i++, ap++) { | |
440 | - clp->m_addrlist[i] = *(struct in_addr *)*ap; | |
441 | - } | |
442 | - clp->m_naddr = i; | |
443 | - } | |
444 | -} | |
445 | - | |
446 | -void | |
447 | -client_add(nfs_client *clp) | |
448 | -{ | |
449 | - nfs_client **cpp; | |
450 | - | |
451 | - if (clp->m_type < 0 || clp->m_type >= MCL_MAXTYPES) | |
452 | - xlog(L_FATAL, "unknown client type in client_add"); | |
453 | - cpp = clientlist + clp->m_type; | |
454 | - while (*cpp) | |
455 | - cpp = &((*cpp)->m_next); | |
456 | - clp->m_next = NULL; | |
457 | - *cpp = clp; | |
458 | -} | |
459 | - | |
460 | +/** | |
461 | + * client_release - drop a reference to an nfs_client record | |
462 | + * | |
463 | + */ | |
464 | void | |
465 | client_release(nfs_client *clp) | |
466 | { | |
467 | @@ -195,6 +304,10 @@ client_release(nfs_client *clp) | |
468 | clp->m_count--; | |
469 | } | |
470 | ||
471 | +/** | |
472 | + * client_freeall - deallocate all nfs_client records | |
473 | + * | |
474 | + */ | |
475 | void | |
476 | client_freeall(void) | |
477 | { | |
478 | @@ -205,57 +318,45 @@ client_freeall(void) | |
479 | head = clientlist + i; | |
480 | while (*head) { | |
481 | *head = (clp = *head)->m_next; | |
482 | - xfree(clp->m_hostname); | |
483 | - xfree(clp); | |
484 | - } | |
485 | - } | |
486 | -} | |
487 | - | |
488 | -nfs_client * | |
489 | -client_find(struct hostent *hp) | |
490 | -{ | |
491 | - nfs_client *clp; | |
492 | - int i; | |
493 | - | |
494 | - for (i = 0; i < MCL_MAXTYPES; i++) { | |
495 | - for (clp = clientlist[i]; clp; clp = clp->m_next) { | |
496 | - if (!client_check(clp, hp)) | |
497 | - continue; | |
498 | -#ifdef notdef | |
499 | - if (clp->m_type == MCL_FQDN) | |
500 | - return clp; | |
501 | - return client_dup(clp, hp); | |
502 | -#else | |
503 | - return clp; | |
504 | -#endif | |
505 | + client_free(clp); | |
506 | } | |
507 | } | |
508 | - return NULL; | |
509 | } | |
510 | ||
511 | -struct hostent * | |
512 | -client_resolve(struct in_addr addr) | |
513 | +/** | |
514 | + * client_resolve - look up an IP address | |
515 | + * @sap: pointer to socket address to resolve | |
516 | + * | |
517 | + * Returns an addrinfo structure, or NULL if some problem occurred. | |
518 | + * Caller must free the result with freeaddrinfo(3). | |
519 | + */ | |
520 | +struct addrinfo * | |
521 | +client_resolve(const struct sockaddr *sap) | |
522 | { | |
523 | - struct hostent *he = NULL; | |
524 | + struct addrinfo *ai = NULL; | |
525 | ||
526 | if (clientlist[MCL_WILDCARD] || clientlist[MCL_NETGROUP]) | |
527 | - he = get_reliable_hostbyaddr((const char*)&addr, sizeof(addr), AF_INET); | |
528 | - if (he == NULL) | |
529 | - he = get_hostent((const char*)&addr, sizeof(addr), AF_INET); | |
530 | + ai = host_reliable_addrinfo(sap); | |
531 | + if (ai == NULL) | |
532 | + ai = host_numeric_addrinfo(sap); | |
533 | ||
534 | - return he; | |
535 | + return ai; | |
536 | } | |
537 | ||
538 | -/* | |
539 | - * Find client name given an IP address | |
540 | - * This is found by gathering all known names that match that IP address, | |
541 | - * sorting them and joining them with '+' | |
542 | +/** | |
543 | + * client_compose - Make a list of cached hostnames that match an IP address | |
544 | + * @ai: pointer to addrinfo containing IP address information to match | |
545 | + * | |
546 | + * Gather all known client hostnames that match the IP address, and sort | |
547 | + * the result into a comma-separated list. | |
548 | * | |
549 | + * Returns a '\0'-terminated ASCII string containing a comma-separated | |
550 | + * sorted list of client hostnames, or NULL if no client records matched | |
551 | + * the IP address or memory could not be allocated. Caller must free the | |
552 | + * returned string with free(3). | |
553 | */ | |
554 | -static char *add_name(char *old, char *add); | |
555 | - | |
556 | char * | |
557 | -client_compose(struct hostent *he) | |
558 | +client_compose(const struct addrinfo *ai) | |
559 | { | |
560 | char *name = NULL; | |
561 | int i; | |
562 | @@ -263,7 +364,7 @@ client_compose(struct hostent *he) | |
563 | for (i = 0 ; i < MCL_MAXTYPES; i++) { | |
564 | nfs_client *clp; | |
565 | for (clp = clientlist[i]; clp ; clp = clp->m_next) { | |
566 | - if (!client_check(clp, he)) | |
567 | + if (!client_check(clp, ai)) | |
568 | continue; | |
569 | name = add_name(name, clp->m_hostname); | |
570 | } | |
571 | @@ -271,13 +372,19 @@ client_compose(struct hostent *he) | |
572 | return name; | |
573 | } | |
574 | ||
575 | +/** | |
576 | + * client_member - check if @name is contained in the list @client | |
577 | + * @client: '\0'-terminated ASCII string containing | |
578 | + * comma-separated list of hostnames | |
579 | + * @name: '\0'-terminated ASCII string containing hostname to look for | |
580 | + * | |
581 | + * Returns 1 if @name was found in @client, otherwise zero is returned. | |
582 | + */ | |
583 | int | |
584 | -client_member(char *client, char *name) | |
585 | +client_member(const char *client, const char *name) | |
586 | { | |
587 | - /* check if "client" (a ',' separated list of names) | |
588 | - * contains 'name' as a member | |
589 | - */ | |
590 | - int l = strlen(name); | |
591 | + size_t l = strlen(name); | |
592 | + | |
593 | while (*client) { | |
594 | if (strncmp(client, name, l) == 0 && | |
595 | (client[l] == ',' || client[l] == '\0')) | |
596 | @@ -290,9 +397,8 @@ client_member(char *client, char *name) | |
597 | return 0; | |
598 | } | |
599 | ||
600 | - | |
601 | -int | |
602 | -name_cmp(char *a, char *b) | |
603 | +static int | |
604 | +name_cmp(const char *a, const char *b) | |
605 | { | |
606 | /* compare strings a and b, but only upto ',' in a */ | |
607 | while (*a && *b && *a != ',' && *a == *b) | |
608 | @@ -305,9 +411,9 @@ name_cmp(char *a, char *b) | |
609 | } | |
610 | ||
611 | static char * | |
612 | -add_name(char *old, char *add) | |
613 | +add_name(char *old, const char *add) | |
614 | { | |
615 | - int len = strlen(add)+2; | |
616 | + size_t len = strlen(add) + 2; | |
617 | char *new; | |
618 | char *cp; | |
619 | if (old) len += strlen(old); | |
620 | @@ -340,108 +446,257 @@ add_name(char *old, char *add) | |
621 | } | |
622 | ||
623 | /* | |
624 | - * Match a host (given its hostent record) to a client record. This | |
625 | - * is usually called from mountd. | |
626 | + * Check each address listed in @ai against each address | |
627 | + * stored in @clp. Return 1 if a match is found, otherwise | |
628 | + * zero. | |
629 | */ | |
630 | -int | |
631 | -client_check(nfs_client *clp, struct hostent *hp) | |
632 | +static int | |
633 | +check_fqdn(const nfs_client *clp, const struct addrinfo *ai) | |
634 | { | |
635 | - char *hname = (char *) hp->h_name; | |
636 | - char *cname = clp->m_hostname; | |
637 | - char **ap; | |
638 | + int i; | |
639 | ||
640 | - switch (clp->m_type) { | |
641 | - case MCL_FQDN: | |
642 | - case MCL_SUBNETWORK: | |
643 | - for (ap = hp->h_addr_list; *ap; ap++) { | |
644 | - if (client_checkaddr(clp, *(struct in_addr *) *ap)) | |
645 | + for (; ai; ai = ai->ai_next) | |
646 | + for (i = 0; i < clp->m_naddr; i++) | |
647 | + if (nfs_compare_sockaddr(ai->ai_addr, | |
648 | + get_addrlist(clp, i))) | |
649 | return 1; | |
650 | - } | |
651 | - return 0; | |
652 | - case MCL_WILDCARD: | |
653 | - if (wildmat(hname, cname)) | |
654 | + | |
655 | + return 0; | |
656 | +} | |
657 | + | |
658 | +static _Bool | |
659 | +mask_match(const uint32_t a, const uint32_t b, const uint32_t m) | |
660 | +{ | |
661 | + return ((a ^ b) & m) == 0; | |
662 | +} | |
663 | + | |
664 | +static int | |
665 | +check_subnet_v4(const struct sockaddr_in *address, | |
666 | + const struct sockaddr_in *mask, const struct addrinfo *ai) | |
667 | +{ | |
668 | + for (; ai; ai = ai->ai_next) { | |
669 | + struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr; | |
670 | + | |
671 | + if (sin->sin_family != AF_INET) | |
672 | + continue; | |
673 | + | |
674 | + if (mask_match(address->sin_addr.s_addr, | |
675 | + sin->sin_addr.s_addr, | |
676 | + mask->sin_addr.s_addr)) | |
677 | return 1; | |
678 | - else { | |
679 | - for (ap = hp->h_aliases; *ap; ap++) | |
680 | - if (wildmat(*ap, cname)) | |
681 | - return 1; | |
682 | - } | |
683 | - return 0; | |
684 | - case MCL_NETGROUP: | |
685 | -#ifdef HAVE_INNETGR | |
686 | - { | |
687 | - char *dot; | |
688 | - int match, i; | |
689 | - struct hostent *nhp = NULL; | |
690 | - struct sockaddr_in addr; | |
691 | - | |
692 | - /* First, try to match the hostname without | |
693 | - * splitting off the domain */ | |
694 | - if (innetgr(cname+1, hname, NULL, NULL)) | |
695 | - return 1; | |
696 | + } | |
697 | + return 0; | |
698 | +} | |
699 | ||
700 | - /* try the aliases as well */ | |
701 | - for (i = 0; hp->h_aliases[i]; i++) { | |
702 | - if (innetgr(cname+1, hp->h_aliases[i], NULL, NULL)) | |
703 | - return 1; | |
704 | - } | |
705 | +#ifdef IPV6_SUPPORTED | |
706 | +static int | |
707 | +check_subnet_v6(const struct sockaddr_in6 *address, | |
708 | + const struct sockaddr_in6 *mask, const struct addrinfo *ai) | |
709 | +{ | |
710 | + for (; ai; ai = ai->ai_next) { | |
711 | + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr; | |
712 | + | |
713 | + if (sin6->sin6_family != AF_INET6) | |
714 | + continue; | |
715 | + | |
716 | + if (mask_match(address->sin6_addr.s6_addr32[0], | |
717 | + sin6->sin6_addr.s6_addr32[0], | |
718 | + mask->sin6_addr.s6_addr32[0]) && | |
719 | + mask_match(address->sin6_addr.s6_addr32[1], | |
720 | + sin6->sin6_addr.s6_addr32[1], | |
721 | + mask->sin6_addr.s6_addr32[1]) && | |
722 | + mask_match(address->sin6_addr.s6_addr32[2], | |
723 | + sin6->sin6_addr.s6_addr32[2], | |
724 | + mask->sin6_addr.s6_addr32[2]) && | |
725 | + mask_match(address->sin6_addr.s6_addr32[3], | |
726 | + sin6->sin6_addr.s6_addr32[3], | |
727 | + mask->sin6_addr.s6_addr32[3])) | |
728 | + return 1; | |
729 | + } | |
730 | + return 0; | |
731 | +} | |
732 | +#else /* !IPV6_SUPPORTED */ | |
733 | +static int | |
734 | +check_subnet_v6(const struct sockaddr_in6 *UNUSED(address), | |
735 | + const struct sockaddr_in6 *UNUSED(mask), | |
736 | + const struct addrinfo *UNUSED(ai)) | |
737 | +{ | |
738 | + return 0; | |
739 | +} | |
740 | +#endif /* !IPV6_SUPPORTED */ | |
741 | ||
742 | - /* If hname is ip address convert to FQDN */ | |
743 | - if (inet_aton(hname, &addr.sin_addr) && | |
744 | - (nhp = gethostbyaddr((const char *)&(addr.sin_addr), | |
745 | - sizeof(addr.sin_addr), AF_INET))) { | |
746 | - hname = (char *)nhp->h_name; | |
747 | - if (innetgr(cname+1, hname, NULL, NULL)) | |
748 | - return 1; | |
749 | - } | |
750 | +/* | |
751 | + * Check each address listed in @ai against the subnetwork or | |
752 | + * host address stored in @clp. Return 1 if an address in @hp | |
753 | + * matches the host address stored in @clp, otherwise zero. | |
754 | + */ | |
755 | +static int | |
756 | +check_subnetwork(const nfs_client *clp, const struct addrinfo *ai) | |
757 | +{ | |
758 | + switch (get_addrlist(clp, 0)->sa_family) { | |
759 | + case AF_INET: | |
760 | + return check_subnet_v4(get_addrlist_in(clp, 0), | |
761 | + get_addrlist_in(clp, 1), ai); | |
762 | + case AF_INET6: | |
763 | + return check_subnet_v6(get_addrlist_in6(clp, 0), | |
764 | + get_addrlist_in6(clp, 1), ai); | |
765 | + } | |
766 | ||
767 | - /* Okay, strip off the domain (if we have one) */ | |
768 | - if ((dot = strchr(hname, '.')) == NULL) | |
769 | - return 0; | |
770 | + return 0; | |
771 | +} | |
772 | ||
773 | - *dot = '\0'; | |
774 | - match = innetgr(cname+1, hname, NULL, NULL); | |
775 | - *dot = '.'; | |
776 | +/* | |
777 | + * Check if a wildcard nfs_client record matches the canonical name | |
778 | + * or the aliases of a host. Return 1 if a match is found, otherwise | |
779 | + * zero. | |
780 | + */ | |
781 | +static int | |
782 | +check_wildcard(const nfs_client *clp, const struct addrinfo *ai) | |
783 | +{ | |
784 | + char *cname = clp->m_hostname; | |
785 | + char *hname = ai->ai_canonname; | |
786 | + struct hostent *hp; | |
787 | + char **ap; | |
788 | ||
789 | - return match; | |
790 | - } | |
791 | -#else | |
792 | - return 0; | |
793 | -#endif | |
794 | - case MCL_ANONYMOUS: | |
795 | + if (wildmat(hname, cname)) | |
796 | return 1; | |
797 | - case MCL_GSS: | |
798 | - return 0; | |
799 | - default: | |
800 | - xlog(L_FATAL, "internal: bad client type %d", clp->m_type); | |
801 | + | |
802 | + /* See if hname aliases listed in /etc/hosts or nis[+] | |
803 | + * match the requested wildcard */ | |
804 | + hp = gethostbyname(hname); | |
805 | + if (hp != NULL) { | |
806 | + for (ap = hp->h_aliases; *ap; ap++) | |
807 | + if (wildmat(*ap, cname)) | |
808 | + return 1; | |
809 | } | |
810 | ||
811 | return 0; | |
812 | } | |
813 | ||
814 | +/* | |
815 | + * Check if @ai's hostname or aliases fall in a given netgroup. | |
816 | + * Return 1 if @ai represents a host in the netgroup, otherwise | |
817 | + * zero. | |
818 | + */ | |
819 | +#ifdef HAVE_INNETGR | |
820 | +static int | |
821 | +check_netgroup(const nfs_client *clp, const struct addrinfo *ai) | |
822 | +{ | |
823 | + const char *netgroup = clp->m_hostname + 1; | |
824 | + struct addrinfo *tmp = NULL; | |
825 | + struct hostent *hp; | |
826 | + char *dot, *hname; | |
827 | + int i, match; | |
828 | + | |
829 | + match = 0; | |
830 | + | |
831 | + hname = strdup(ai->ai_canonname); | |
832 | + if (hname == NULL) { | |
833 | + xlog(D_GENERAL, "%s: no memory for strdup", __func__); | |
834 | + goto out; | |
835 | + } | |
836 | + | |
837 | + /* First, try to match the hostname without | |
838 | + * splitting off the domain */ | |
839 | + if (innetgr(netgroup, hname, NULL, NULL)) { | |
840 | + match = 1; | |
841 | + goto out; | |
842 | + } | |
843 | + | |
844 | + /* See if hname aliases listed in /etc/hosts or nis[+] | |
845 | + * match the requested netgroup */ | |
846 | + hp = gethostbyname(hname); | |
847 | + if (hp != NULL) { | |
848 | + for (i = 0; hp->h_aliases[i]; i++) | |
849 | + if (innetgr(netgroup, hp->h_aliases[i], NULL, NULL)) { | |
850 | + match = 1; | |
851 | + goto out; | |
852 | + } | |
853 | + } | |
854 | + | |
855 | + /* If hname happens to be an IP address, convert it | |
856 | + * to a the canonical DNS name bound to this address. */ | |
857 | + tmp = host_pton(hname); | |
858 | + if (tmp != NULL) { | |
859 | + char *cname = host_canonname(tmp->ai_addr); | |
860 | + freeaddrinfo(tmp); | |
861 | + | |
862 | + /* The resulting FQDN may be in our netgroup. */ | |
863 | + if (cname != NULL) { | |
864 | + free(hname); | |
865 | + hname = cname; | |
866 | + if (innetgr(netgroup, hname, NULL, NULL)) { | |
867 | + match = 1; | |
868 | + goto out; | |
869 | + } | |
870 | + } | |
871 | + } | |
872 | + | |
873 | + /* Okay, strip off the domain (if we have one) */ | |
874 | + dot = strchr(hname, '.'); | |
875 | + if (dot == NULL) | |
876 | + goto out; | |
877 | + | |
878 | + *dot = '\0'; | |
879 | + match = innetgr(netgroup, hname, NULL, NULL); | |
880 | + | |
881 | +out: | |
882 | + free(hname); | |
883 | + return match; | |
884 | +} | |
885 | +#else /* !HAVE_INNETGR */ | |
886 | static int | |
887 | -client_checkaddr(nfs_client *clp, struct in_addr addr) | |
888 | +check_netgroup(__attribute__((unused)) const nfs_client *clp, | |
889 | + __attribute__((unused)) const struct addrinfo *ai) | |
890 | { | |
891 | - int i; | |
892 | + return 0; | |
893 | +} | |
894 | +#endif /* !HAVE_INNETGR */ | |
895 | ||
896 | +/** | |
897 | + * client_check - check if IP address information matches a cached nfs_client | |
898 | + * @clp: pointer to a cached nfs_client record | |
899 | + * @ai: pointer to addrinfo to compare it with | |
900 | + * | |
901 | + * Returns 1 if the address information matches the cached nfs_client, | |
902 | + * otherwise zero. | |
903 | + */ | |
904 | +int | |
905 | +client_check(const nfs_client *clp, const struct addrinfo *ai) | |
906 | +{ | |
907 | switch (clp->m_type) { | |
908 | case MCL_FQDN: | |
909 | - for (i = 0; i < clp->m_naddr; i++) { | |
910 | - if (clp->m_addrlist[i].s_addr == addr.s_addr) | |
911 | - return 1; | |
912 | - } | |
913 | - return 0; | |
914 | + return check_fqdn(clp, ai); | |
915 | case MCL_SUBNETWORK: | |
916 | - return !((clp->m_addrlist[0].s_addr ^ addr.s_addr) | |
917 | - & clp->m_addrlist[1].s_addr); | |
918 | + return check_subnetwork(clp, ai); | |
919 | + case MCL_WILDCARD: | |
920 | + return check_wildcard(clp, ai); | |
921 | + case MCL_NETGROUP: | |
922 | + return check_netgroup(clp, ai); | |
923 | + case MCL_ANONYMOUS: | |
924 | + return 1; | |
925 | + case MCL_GSS: | |
926 | + return 0; | |
927 | + default: | |
928 | + xlog(D_GENERAL, "%s: unrecognized client type: %d", | |
929 | + __func__, clp->m_type); | |
930 | } | |
931 | + | |
932 | return 0; | |
933 | } | |
934 | ||
935 | +/** | |
936 | + * client_gettype - determine type of nfs_client given an identifier | |
937 | + * @ident: '\0'-terminated ASCII string containing a client identifier | |
938 | + * | |
939 | + * Returns the type of nfs_client record that would be used for | |
940 | + * this client. | |
941 | + */ | |
942 | int | |
943 | client_gettype(char *ident) | |
944 | { | |
945 | - char *sp; | |
946 | + struct addrinfo *ai; | |
947 | + char *sp; | |
948 | ||
949 | if (ident[0] == '\0' || strcmp(ident, "*")==0) | |
950 | return MCL_ANONYMOUS; | |
951 | @@ -461,12 +716,16 @@ client_gettype(char *ident) | |
952 | if (*sp == '\\' && sp[1]) | |
953 | sp++; | |
954 | } | |
955 | - /* check for N.N.N.N */ | |
956 | - sp = ident; | |
957 | - if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN; | |
958 | - sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN; | |
959 | - sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN; | |
960 | - sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '\0') return MCL_FQDN; | |
961 | - /* we lie here a bit. but technically N.N.N.N == N.N.N.N/32 :) */ | |
962 | - return MCL_SUBNETWORK; | |
963 | + | |
964 | + /* | |
965 | + * Treat unadorned IP addresses as MCL_SUBNETWORK. | |
966 | + * Everything else is MCL_FQDN. | |
967 | + */ | |
968 | + ai = host_pton(ident); | |
969 | + if (ai != NULL) { | |
970 | + freeaddrinfo(ai); | |
971 | + return MCL_SUBNETWORK; | |
972 | + } | |
973 | + | |
974 | + return MCL_FQDN; | |
975 | } | |
976 | diff --git a/support/export/export.c b/support/export/export.c | |
977 | index 2943466..4fda30a 100644 | |
978 | --- a/support/export/export.c | |
979 | +++ b/support/export/export.c | |
980 | @@ -24,9 +24,25 @@ static int export_hash(char *); | |
981 | ||
982 | static void export_init(nfs_export *exp, nfs_client *clp, | |
983 | struct exportent *nep); | |
984 | -static int export_check(nfs_export *, struct hostent *, char *); | |
985 | +static void export_add(nfs_export *exp); | |
986 | +static int export_check(const nfs_export *exp, const struct addrinfo *ai, | |
987 | + const char *path); | |
988 | static nfs_export * | |
989 | - export_allowed_internal(struct hostent *hp, char *path); | |
990 | + export_allowed_internal(const struct addrinfo *ai, | |
991 | + const char *path); | |
992 | + | |
993 | +static void | |
994 | +export_free(nfs_export *exp) | |
995 | +{ | |
996 | + xfree(exp->m_export.e_squids); | |
997 | + xfree(exp->m_export.e_sqgids); | |
998 | + free(exp->m_export.e_mountpoint); | |
999 | + free(exp->m_export.e_fslocdata); | |
1000 | + free(exp->m_export.e_uuid); | |
1001 | + | |
1002 | + xfree(exp->m_export.e_hostname); | |
1003 | + xfree(exp); | |
1004 | +} | |
1005 | ||
1006 | static void warn_duplicated_exports(nfs_export *exp, struct exportent *eep) | |
1007 | { | |
1008 | @@ -44,7 +60,12 @@ static void warn_duplicated_exports(nfs_export *exp, struct exportent *eep) | |
1009 | } | |
1010 | } | |
1011 | ||
1012 | -int | |
1013 | +/** | |
1014 | + * export_read - read entries from /etc/exports | |
1015 | + * @fname: name of file to read from | |
1016 | + * | |
1017 | + */ | |
1018 | +void | |
1019 | export_read(char *fname) | |
1020 | { | |
1021 | struct exportent *eep; | |
1022 | @@ -59,11 +80,15 @@ export_read(char *fname) | |
1023 | warn_duplicated_exports(exp, eep); | |
1024 | } | |
1025 | endexportent(); | |
1026 | - return 0; | |
1027 | } | |
1028 | ||
1029 | -/* | |
1030 | - * Create an in-core export struct from an export entry. | |
1031 | +/** | |
1032 | + * export_create - create an in-core nfs_export record from an export entry | |
1033 | + * @xep: export entry to lookup | |
1034 | + * @canonical: if set, e_hostname is known to be canonical DNS name | |
1035 | + * | |
1036 | + * Returns a freshly instantiated export record, or NULL if | |
1037 | + * a problem occurred. | |
1038 | */ | |
1039 | nfs_export * | |
1040 | export_create(struct exportent *xep, int canonical) | |
1041 | @@ -105,8 +130,8 @@ export_init(nfs_export *exp, nfs_client *clp, struct exportent *nep) | |
1042 | * original hostname from /etc/exports, while the in-core client struct | |
1043 | * gets the newly found FQDN. | |
1044 | */ | |
1045 | -nfs_export * | |
1046 | -export_dup(nfs_export *exp, struct hostent *hp) | |
1047 | +static nfs_export * | |
1048 | +export_dup(nfs_export *exp, const struct addrinfo *ai) | |
1049 | { | |
1050 | nfs_export *new; | |
1051 | nfs_client *clp; | |
1052 | @@ -116,7 +141,11 @@ export_dup(nfs_export *exp, struct hostent *hp) | |
1053 | dupexportent(&new->m_export, &exp->m_export); | |
1054 | if (exp->m_export.e_hostname) | |
1055 | new->m_export.e_hostname = xstrdup(exp->m_export.e_hostname); | |
1056 | - clp = client_dup(exp->m_client, hp); | |
1057 | + clp = client_dup(exp->m_client, ai); | |
1058 | + if (clp == NULL) { | |
1059 | + export_free(new); | |
1060 | + return NULL; | |
1061 | + } | |
1062 | clp->m_count++; | |
1063 | new->m_client = clp; | |
1064 | new->m_mayexport = exp->m_mayexport; | |
1065 | @@ -128,10 +157,8 @@ export_dup(nfs_export *exp, struct hostent *hp) | |
1066 | ||
1067 | return new; | |
1068 | } | |
1069 | -/* | |
1070 | - * Add export entry to hash table | |
1071 | - */ | |
1072 | -void | |
1073 | + | |
1074 | +static void | |
1075 | export_add(nfs_export *exp) | |
1076 | { | |
1077 | exp_hash_table *p_tbl; | |
1078 | @@ -159,19 +186,27 @@ export_add(nfs_export *exp) | |
1079 | } | |
1080 | } | |
1081 | ||
1082 | +/** | |
1083 | + * export_find - find or create a suitable nfs_export for @ai and @path | |
1084 | + * @ai: pointer to addrinfo for client | |
1085 | + * @path: '\0'-terminated ASCII string containing export path | |
1086 | + * | |
1087 | + * Returns a pointer to nfs_export data matching @ai and @path, | |
1088 | + * or NULL if an error occurs. | |
1089 | + */ | |
1090 | nfs_export * | |
1091 | -export_find(struct hostent *hp, char *path) | |
1092 | +export_find(const struct addrinfo *ai, const char *path) | |
1093 | { | |
1094 | nfs_export *exp; | |
1095 | int i; | |
1096 | ||
1097 | for (i = 0; i < MCL_MAXTYPES; i++) { | |
1098 | for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { | |
1099 | - if (!export_check(exp, hp, path)) | |
1100 | + if (!export_check(exp, ai, path)) | |
1101 | continue; | |
1102 | if (exp->m_client->m_type == MCL_FQDN) | |
1103 | return exp; | |
1104 | - return export_dup(exp, hp); | |
1105 | + return export_dup(exp, ai); | |
1106 | } | |
1107 | } | |
1108 | ||
1109 | @@ -179,7 +214,7 @@ export_find(struct hostent *hp, char *path) | |
1110 | } | |
1111 | ||
1112 | static nfs_export * | |
1113 | -export_allowed_internal (struct hostent *hp, char *path) | |
1114 | +export_allowed_internal(const struct addrinfo *ai, const char *path) | |
1115 | { | |
1116 | nfs_export *exp; | |
1117 | int i; | |
1118 | @@ -187,7 +222,7 @@ export_allowed_internal (struct hostent *hp, char *path) | |
1119 | for (i = 0; i < MCL_MAXTYPES; i++) { | |
1120 | for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { | |
1121 | if (!exp->m_mayexport || | |
1122 | - !export_check(exp, hp, path)) | |
1123 | + !export_check(exp, ai, path)) | |
1124 | continue; | |
1125 | return exp; | |
1126 | } | |
1127 | @@ -196,8 +231,16 @@ export_allowed_internal (struct hostent *hp, char *path) | |
1128 | return NULL; | |
1129 | } | |
1130 | ||
1131 | +/** | |
1132 | + * export_allowed - determine if this export is allowed | |
1133 | + * @ai: pointer to addrinfo for client | |
1134 | + * @path: '\0'-terminated ASCII string containing export path | |
1135 | + * | |
1136 | + * Returns a pointer to nfs_export data matching @ai and @path, | |
1137 | + * or NULL if the export is not allowed. | |
1138 | + */ | |
1139 | nfs_export * | |
1140 | -export_allowed(struct hostent *hp, char *path) | |
1141 | +export_allowed(const struct addrinfo *ai, const char *path) | |
1142 | { | |
1143 | nfs_export *exp; | |
1144 | char epath[MAXPATHLEN+1]; | |
1145 | @@ -210,7 +253,7 @@ export_allowed(struct hostent *hp, char *path) | |
1146 | ||
1147 | /* Try the longest matching exported pathname. */ | |
1148 | while (1) { | |
1149 | - exp = export_allowed_internal (hp, epath); | |
1150 | + exp = export_allowed_internal(ai, epath); | |
1151 | if (exp) | |
1152 | return exp; | |
1153 | /* We have to treat the root, "/", specially. */ | |
1154 | @@ -223,11 +266,17 @@ export_allowed(struct hostent *hp, char *path) | |
1155 | return NULL; | |
1156 | } | |
1157 | ||
1158 | -/* | |
1159 | - * Search hash table for export entry. | |
1160 | - */ | |
1161 | +/** | |
1162 | + * export_lookup - search hash table for export entry | |
1163 | + * @hname: '\0'-terminated ASCII string containing client hostname to look for | |
1164 | + * @path: '\0'-terminated ASCII string containing export path to look for | |
1165 | + * @canonical: if set, @hname is known to be canonical DNS name | |
1166 | + * | |
1167 | + * Returns a pointer to nfs_export record matching @hname and @path, | |
1168 | + * or NULL if the export was not found. | |
1169 | + */ | |
1170 | nfs_export * | |
1171 | -export_lookup(char *hname, char *path, int canonical) | |
1172 | +export_lookup(char *hname, char *path, int canonical) | |
1173 | { | |
1174 | nfs_client *clp; | |
1175 | nfs_export *exp; | |
1176 | @@ -251,14 +300,18 @@ export_lookup(char *hname, char *path, int canonical) | |
1177 | } | |
1178 | ||
1179 | static int | |
1180 | -export_check(nfs_export *exp, struct hostent *hp, char *path) | |
1181 | +export_check(const nfs_export *exp, const struct addrinfo *ai, const char *path) | |
1182 | { | |
1183 | if (strcmp(path, exp->m_export.e_path)) | |
1184 | return 0; | |
1185 | ||
1186 | - return client_check(exp->m_client, hp); | |
1187 | + return client_check(exp->m_client, ai); | |
1188 | } | |
1189 | ||
1190 | +/** | |
1191 | + * export_freeall - deallocate all nfs_export records | |
1192 | + * | |
1193 | + */ | |
1194 | void | |
1195 | export_freeall(void) | |
1196 | { | |
1197 | @@ -269,22 +322,13 @@ export_freeall(void) | |
1198 | for (exp = exportlist[i].p_head; exp; exp = nxt) { | |
1199 | nxt = exp->m_next; | |
1200 | client_release(exp->m_client); | |
1201 | - if (exp->m_export.e_squids) | |
1202 | - xfree(exp->m_export.e_squids); | |
1203 | - if (exp->m_export.e_sqgids) | |
1204 | - xfree(exp->m_export.e_sqgids); | |
1205 | - if (exp->m_export.e_mountpoint) | |
1206 | - free(exp->m_export.e_mountpoint); | |
1207 | - if (exp->m_export.e_fslocdata) | |
1208 | - xfree(exp->m_export.e_fslocdata); | |
1209 | - xfree(exp->m_export.e_hostname); | |
1210 | - xfree(exp); | |
1211 | + export_free(exp); | |
1212 | + } | |
1213 | + for (j = 0; j < HASH_TABLE_SIZE; j++) { | |
1214 | + exportlist[i].entries[j].p_first = NULL; | |
1215 | + exportlist[i].entries[j].p_last = NULL; | |
1216 | } | |
1217 | - for(j = 0; j < HASH_TABLE_SIZE; j++) { | |
1218 | - exportlist[i].entries[j].p_first = NULL; | |
1219 | - exportlist[i].entries[j].p_last = NULL; | |
1220 | - } | |
1221 | - exportlist[i].p_head = NULL; | |
1222 | + exportlist[i].p_head = NULL; | |
1223 | } | |
1224 | client_freeall(); | |
1225 | } | |
1226 | diff --git a/support/export/hostname.c b/support/export/hostname.c | |
1227 | index 8a23a89..3c55ce7 100644 | |
1228 | --- a/support/export/hostname.c | |
1229 | +++ b/support/export/hostname.c | |
1230 | @@ -1,315 +1,376 @@ | |
1231 | /* | |
1232 | - * support/export/hostname.c | |
1233 | + * Copyright 2010 Oracle. All rights reserved. | |
1234 | * | |
1235 | - * Functions for hostname. | |
1236 | + * This file is part of nfs-utils. | |
1237 | * | |
1238 | + * nfs-utils is free software; you can redistribute it and/or modify | |
1239 | + * it under the terms of the GNU General Public License as published by | |
1240 | + * the Free Software Foundation; either version 2 of the License, or | |
1241 | + * (at your option) any later version. | |
1242 | + * | |
1243 | + * nfs-utils is distributed in the hope that it will be useful, | |
1244 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
1245 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
1246 | + * GNU General Public License for more details. | |
1247 | + * | |
1248 | + * You should have received a copy of the GNU General Public License | |
1249 | + * along with nfs-utils. If not, see <http://www.gnu.org/licenses/>. | |
1250 | */ | |
1251 | ||
1252 | #ifdef HAVE_CONFIG_H | |
1253 | #include <config.h> | |
1254 | #endif | |
1255 | ||
1256 | -/* | |
1257 | -#define TEST | |
1258 | -*/ | |
1259 | - | |
1260 | #include <string.h> | |
1261 | -#include <netdb.h> | |
1262 | -#include <netinet/in.h> | |
1263 | -#include <arpa/inet.h> | |
1264 | #include <stdlib.h> | |
1265 | -#include <xlog.h> | |
1266 | -#ifdef TEST | |
1267 | -#define xmalloc malloc | |
1268 | -#else | |
1269 | -#include "xmalloc.h" | |
1270 | -#include "misc.h" | |
1271 | -#endif | |
1272 | +#include <arpa/inet.h> | |
1273 | +#include <netdb.h> | |
1274 | +#include <errno.h> | |
1275 | ||
1276 | -#define ALIGNMENT sizeof (char *) | |
1277 | +#include "sockaddr.h" | |
1278 | +#include "exportfs.h" | |
1279 | ||
1280 | -static int | |
1281 | -align (int len, int al) | |
1282 | +#ifndef HAVE_DECL_AI_ADDRCONFIG | |
1283 | +#define AI_ADDRCONFIG 0 | |
1284 | +#endif | |
1285 | + | |
1286 | +/** | |
1287 | + * host_ntop - generate presentation address given a sockaddr | |
1288 | + * @sap: pointer to socket address | |
1289 | + * @buf: working storage | |
1290 | + * @buflen: size of @buf in bytes | |
1291 | + * | |
1292 | + * Returns a pointer to a @buf. | |
1293 | + */ | |
1294 | +#ifdef HAVE_GETNAMEINFO | |
1295 | +char * | |
1296 | +host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen) | |
1297 | { | |
1298 | - int i; | |
1299 | - i = len % al; | |
1300 | - if (i) | |
1301 | - len += al - i; | |
1302 | - return len; | |
1303 | -} | |
1304 | + socklen_t salen = nfs_sockaddr_length(sap); | |
1305 | + int error; | |
1306 | + | |
1307 | + memset(buf, 0, buflen); | |
1308 | + | |
1309 | + if (salen == 0) { | |
1310 | + (void)strncpy(buf, "bad family", buflen - 1); | |
1311 | + return buf; | |
1312 | + } | |
1313 | + | |
1314 | + error = getnameinfo(sap, salen, buf, (socklen_t)buflen, | |
1315 | + NULL, 0, NI_NUMERICHOST); | |
1316 | + if (error != 0) { | |
1317 | + buf[0] = '\0'; | |
1318 | + (void)strncpy(buf, "bad address", buflen - 1); | |
1319 | + } | |
1320 | ||
1321 | -struct hostent * | |
1322 | -get_hostent (const char *addr, int len, int type) | |
1323 | + return buf; | |
1324 | +} | |
1325 | +#else /* !HAVE_GETNAMEINFO */ | |
1326 | +char * | |
1327 | +host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen) | |
1328 | { | |
1329 | - struct hostent *cp; | |
1330 | - int len_ent; | |
1331 | - const char *name; | |
1332 | - int len_name; | |
1333 | - int num_aliases = 1; | |
1334 | - int len_aliases = sizeof (char *); | |
1335 | - int num_addr_list = 1; | |
1336 | - int len_addr_list = sizeof (char *); | |
1337 | - int pos; | |
1338 | - struct in_addr *ipv4; | |
1339 | - | |
1340 | - switch (type) | |
1341 | - { | |
1342 | - case AF_INET: | |
1343 | - ipv4 = (struct in_addr *) addr; | |
1344 | - name = inet_ntoa (*ipv4); | |
1345 | - break; | |
1346 | - | |
1347 | - default: | |
1348 | - return NULL; | |
1349 | - } | |
1350 | - | |
1351 | - len_ent = align (sizeof (*cp), ALIGNMENT); | |
1352 | - len_name = align (strlen (name) + 1, ALIGNMENT); | |
1353 | - | |
1354 | - num_addr_list++; | |
1355 | - len_addr_list += align (len, ALIGNMENT) + sizeof (char *); | |
1356 | - | |
1357 | - cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases | |
1358 | - + len_addr_list); | |
1359 | - | |
1360 | - cp->h_addrtype = type; | |
1361 | - cp->h_length = len; | |
1362 | - pos = len_ent; | |
1363 | - cp->h_name = (char *) &(((char *) cp) [pos]); | |
1364 | - strcpy (cp->h_name, name); | |
1365 | - | |
1366 | - pos += len_name; | |
1367 | - cp->h_aliases = (char **) &(((char *) cp) [pos]); | |
1368 | - pos += num_aliases * sizeof (char *); | |
1369 | - cp->h_aliases [0] = NULL; | |
1370 | - | |
1371 | - pos = len_ent + len_name + len_aliases; | |
1372 | - cp->h_addr_list = (char **) &(((char *) cp) [pos]); | |
1373 | - pos += num_addr_list * sizeof (char *); | |
1374 | - cp->h_addr_list [0] = (char *) &(((char *) cp) [pos]); | |
1375 | - memcpy (cp->h_addr_list [0], addr, cp->h_length); | |
1376 | - pos += align (cp->h_length, ALIGNMENT); | |
1377 | - cp->h_addr_list [1] = NULL; | |
1378 | - | |
1379 | - return cp; | |
1380 | + const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap; | |
1381 | + | |
1382 | + memset(buf, 0, buflen); | |
1383 | + | |
1384 | + if (sin->sin_family != AF_INET) | |
1385 | + (void)strncpy(buf, "bad family", buflen - 1); | |
1386 | + return buf; | |
1387 | + } | |
1388 | + | |
1389 | + if (inet_ntop(AF_INET, &sin->sin_addr.s_addr, buf, buflen) != NULL) | |
1390 | + return buf; | |
1391 | + | |
1392 | + buf[0] = '\0'; | |
1393 | + (void)strncpy(buf, "bad address", buflen - 1); | |
1394 | + return buf; | |
1395 | } | |
1396 | +#endif /* !HAVE_GETNAMEINFO */ | |
1397 | ||
1398 | -struct hostent * | |
1399 | -hostent_dup (struct hostent *hp) | |
1400 | +/** | |
1401 | + * host_pton - return addrinfo for a given presentation address | |
1402 | + * @paddr: pointer to a '\0'-terminated ASCII string containing an | |
1403 | + * IP presentation address | |
1404 | + * | |
1405 | + * Returns address info structure, or NULL if an error occurs. Caller | |
1406 | + * must free the returned structure with freeaddrinfo(3). | |
1407 | + */ | |
1408 | +__attribute_malloc__ | |
1409 | +struct addrinfo * | |
1410 | +host_pton(const char *paddr) | |
1411 | { | |
1412 | - int len_ent = align (sizeof (*hp), ALIGNMENT); | |
1413 | - int len_name = align (strlen (hp->h_name) + 1, ALIGNMENT); | |
1414 | - int num_aliases = 1; | |
1415 | - int len_aliases = sizeof (char *); | |
1416 | - int num_addr_list = 1; | |
1417 | - int len_addr_list = sizeof (char *); | |
1418 | - int pos, i; | |
1419 | - char **sp; | |
1420 | - struct hostent *cp; | |
1421 | - | |
1422 | - for (sp = hp->h_aliases; sp && *sp; sp++) | |
1423 | - { | |
1424 | - num_aliases++; | |
1425 | - len_aliases += align (strlen (*sp) + 1, ALIGNMENT) | |
1426 | - + sizeof (char *); | |
1427 | - } | |
1428 | - | |
1429 | - for (sp = hp->h_addr_list; *sp; sp++) | |
1430 | - { | |
1431 | - num_addr_list++; | |
1432 | - len_addr_list += align (hp->h_length, ALIGNMENT) | |
1433 | - + sizeof (char *); | |
1434 | - } | |
1435 | - | |
1436 | - cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases | |
1437 | - + len_addr_list); | |
1438 | - | |
1439 | - *cp = *hp; | |
1440 | - pos = len_ent; | |
1441 | - cp->h_name = (char *) &(((char *) cp) [pos]); | |
1442 | - strcpy (cp->h_name, hp->h_name); | |
1443 | - | |
1444 | - pos += len_name; | |
1445 | - cp->h_aliases = (char **) &(((char *) cp) [pos]); | |
1446 | - pos += num_aliases * sizeof (char *); | |
1447 | - for (sp = hp->h_aliases, i = 0; i < num_aliases; i++, sp++) | |
1448 | - if (sp && *sp) | |
1449 | - { | |
1450 | - cp->h_aliases [i] = (char *) &(((char *) cp) [pos]); | |
1451 | - strcpy (cp->h_aliases [i], *sp); | |
1452 | - pos += align (strlen (*sp) + 1, ALIGNMENT); | |
1453 | - } | |
1454 | - else | |
1455 | - cp->h_aliases [i] = NULL; | |
1456 | - | |
1457 | - pos = len_ent + len_name + len_aliases; | |
1458 | - cp->h_addr_list = (char **) &(((char *) cp) [pos]); | |
1459 | - pos += num_addr_list * sizeof (char *); | |
1460 | - for (sp = hp->h_addr_list, i = 0; i < num_addr_list; i++, sp++) | |
1461 | - if (*sp) | |
1462 | - { | |
1463 | - cp->h_addr_list [i] = (char *) &(((char *) cp) [pos]); | |
1464 | - memcpy (cp->h_addr_list [i], *sp, hp->h_length); | |
1465 | - pos += align (hp->h_length, ALIGNMENT); | |
1466 | - } | |
1467 | - else | |
1468 | - cp->h_addr_list [i] = *sp; | |
1469 | - | |
1470 | - return cp; | |
1471 | + struct addrinfo *ai = NULL; | |
1472 | + struct addrinfo hint = { | |
1473 | + /* don't return duplicates */ | |
1474 | + .ai_protocol = (int)IPPROTO_UDP, | |
1475 | + .ai_flags = AI_NUMERICHOST, | |
1476 | + .ai_family = AF_UNSPEC, | |
1477 | + }; | |
1478 | + struct sockaddr_in sin; | |
1479 | + int error, inet4; | |
1480 | + | |
1481 | + /* | |
1482 | + * Although getaddrinfo(3) is easier to use and supports | |
1483 | + * IPv6, it recognizes incomplete addresses like "10.4" | |
1484 | + * as valid AF_INET addresses. It also accepts presentation | |
1485 | + * addresses that end with a blank. | |
1486 | + * | |
1487 | + * inet_pton(3) is much stricter. Use it to be certain we | |
1488 | + * have a real AF_INET presentation address, before invoking | |
1489 | + * getaddrinfo(3) to generate the full addrinfo list. | |
1490 | + */ | |
1491 | + inet4 = 1; | |
1492 | + if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0) | |
1493 | + inet4 = 0; | |
1494 | + | |
1495 | + error = getaddrinfo(paddr, NULL, &hint, &ai); | |
1496 | + switch (error) { | |
1497 | + case 0: | |
1498 | + if (!inet4 && ai->ai_addr->sa_family == AF_INET) { | |
1499 | + freeaddrinfo(ai); | |
1500 | + break; | |
1501 | + } | |
1502 | + return ai; | |
1503 | + case EAI_NONAME: | |
1504 | + if (paddr == NULL) | |
1505 | + xlog(D_GENERAL, "%s: passed a NULL presentation address", | |
1506 | + __func__); | |
1507 | + break; | |
1508 | + case EAI_SYSTEM: | |
1509 | + xlog(D_GENERAL, "%s: failed to convert %s: (%d) %m", | |
1510 | + __func__, paddr, errno); | |
1511 | + break; | |
1512 | + default: | |
1513 | + xlog(D_GENERAL, "%s: failed to convert %s: %s", | |
1514 | + __func__, paddr, gai_strerror(error)); | |
1515 | + break; | |
1516 | + } | |
1517 | + | |
1518 | + return NULL; | |
1519 | } | |
1520 | ||
1521 | -static int | |
1522 | -is_hostname(const char *sp) | |
1523 | +/** | |
1524 | + * host_addrinfo - return addrinfo for a given hostname | |
1525 | + * @hostname: pointer to a '\0'-terminated ASCII string containing a hostname | |
1526 | + * | |
1527 | + * Returns address info structure with ai_canonname filled in, or NULL | |
1528 | + * if no information is available for @hostname. Caller must free the | |
1529 | + * returned structure with freeaddrinfo(3). | |
1530 | + */ | |
1531 | +__attribute_malloc__ | |
1532 | +struct addrinfo * | |
1533 | +host_addrinfo(const char *hostname) | |
1534 | { | |
1535 | - if (*sp == '\0' || *sp == '@') | |
1536 | - return 0; | |
1537 | - | |
1538 | - for (; *sp; sp++) | |
1539 | - { | |
1540 | - if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/') | |
1541 | - return 0; | |
1542 | - if (*sp == '\\' && sp[1]) | |
1543 | - sp++; | |
1544 | - } | |
1545 | - | |
1546 | - return 1; | |
1547 | + struct addrinfo *ai = NULL; | |
1548 | + struct addrinfo hint = { | |
1549 | +#ifdef IPV6_SUPPORTED | |
1550 | + .ai_family = AF_UNSPEC, | |
1551 | +#else | |
1552 | + .ai_family = AF_INET, | |
1553 | +#endif | |
1554 | + /* don't return duplicates */ | |
1555 | + .ai_protocol = (int)IPPROTO_UDP, | |
1556 | + .ai_flags = AI_ADDRCONFIG | AI_CANONNAME, | |
1557 | + }; | |
1558 | + int error; | |
1559 | + | |
1560 | + error = getaddrinfo(hostname, NULL, &hint, &ai); | |
1561 | + switch (error) { | |
1562 | + case 0: | |
1563 | + return ai; | |
1564 | + case EAI_SYSTEM: | |
1565 | + xlog(D_GENERAL, "%s: failed to resolve %s: (%d) %m", | |
1566 | + __func__, hostname, errno); | |
1567 | + break; | |
1568 | + default: | |
1569 | + xlog(D_GENERAL, "%s: failed to resolve %s: %s", | |
1570 | + __func__, hostname, gai_strerror(error)); | |
1571 | + break; | |
1572 | + } | |
1573 | + | |
1574 | + return NULL; | |
1575 | } | |
1576 | ||
1577 | -int | |
1578 | -matchhostname (const char *h1, const char *h2) | |
1579 | +/** | |
1580 | + * host_canonname - return canonical hostname bound to an address | |
1581 | + * @sap: pointer to socket address to look up | |
1582 | + * | |
1583 | + * Discover the canonical hostname associated with the given socket | |
1584 | + * address. The host's reverse mapping is verified in the process. | |
1585 | + * | |
1586 | + * Returns a '\0'-terminated ASCII string containing a hostname, or | |
1587 | + * NULL if no hostname can be found for @sap. Caller must free | |
1588 | + * the string. | |
1589 | + */ | |
1590 | +#ifdef HAVE_GETNAMEINFO | |
1591 | +__attribute_malloc__ | |
1592 | +char * | |
1593 | +host_canonname(const struct sockaddr *sap) | |
1594 | { | |
1595 | - struct hostent *hp1, *hp2; | |
1596 | - int status; | |
1597 | - | |
1598 | - if (strcasecmp (h1, h2) == 0) | |
1599 | - return 1; | |
1600 | - | |
1601 | - if (!is_hostname (h1) || !is_hostname (h2)) | |
1602 | - return 0; | |
1603 | - | |
1604 | - hp1 = gethostbyname (h1); | |
1605 | - if (hp1 == NULL) | |
1606 | - return 0; | |
1607 | - | |
1608 | - hp1 = hostent_dup (hp1); | |
1609 | - | |
1610 | - hp2 = gethostbyname (h2); | |
1611 | - if (hp2) | |
1612 | - { | |
1613 | - if (strcasecmp (hp1->h_name, hp2->h_name) == 0) | |
1614 | - status = 1; | |
1615 | - else | |
1616 | - { | |
1617 | - char **ap1, **ap2; | |
1618 | - | |
1619 | - status = 0; | |
1620 | - for (ap1 = hp1->h_addr_list; *ap1 && status == 0; ap1++) | |
1621 | - for (ap2 = hp2->h_addr_list; *ap2; ap2++) | |
1622 | - if (memcmp (*ap1, *ap2, sizeof (struct in_addr)) == 0) | |
1623 | - { | |
1624 | - status = 1; | |
1625 | - break; | |
1626 | - } | |
1627 | + socklen_t salen = nfs_sockaddr_length(sap); | |
1628 | + char buf[NI_MAXHOST]; | |
1629 | + int error; | |
1630 | + | |
1631 | + if (salen == 0) { | |
1632 | + xlog(D_GENERAL, "%s: unsupported address family %d", | |
1633 | + __func__, sap->sa_family); | |
1634 | + return NULL; | |
1635 | + } | |
1636 | + | |
1637 | + memset(buf, 0, sizeof(buf)); | |
1638 | + error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf), | |
1639 | + NULL, 0, NI_NAMEREQD); | |
1640 | + switch (error) { | |
1641 | + case 0: | |
1642 | + break; | |
1643 | + case EAI_SYSTEM: | |
1644 | + xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m", | |
1645 | + __func__, errno); | |
1646 | + return NULL; | |
1647 | + default: | |
1648 | + (void)getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf), | |
1649 | + NULL, 0, NI_NUMERICHOST); | |
1650 | + xlog(D_GENERAL, "%s: failed to resolve %s: %s", | |
1651 | + __func__, buf, gai_strerror(error)); | |
1652 | + return NULL; | |
1653 | } | |
1654 | - } | |
1655 | - else | |
1656 | - status = 0; | |
1657 | ||
1658 | - free (hp1); | |
1659 | - return status; | |
1660 | + return strdup(buf); | |
1661 | } | |
1662 | +#else /* !HAVE_GETNAMEINFO */ | |
1663 | +__attribute_malloc__ | |
1664 | +char * | |
1665 | +host_canonname(const struct sockaddr *sap) | |
1666 | +{ | |
1667 | + const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap; | |
1668 | + const struct in_addr *addr = &sin->sin_addr; | |
1669 | + struct hostent *hp; | |
1670 | + | |
1671 | + if (sap->sa_family != AF_INET) | |
1672 | + return NULL; | |
1673 | ||
1674 | + hp = gethostbyaddr(addr, (socklen_t)sizeof(addr), AF_INET); | |
1675 | + if (hp == NULL) | |
1676 | + return NULL; | |
1677 | + | |
1678 | + return strdup(hp->h_name); | |
1679 | +} | |
1680 | +#endif /* !HAVE_GETNAMEINFO */ | |
1681 | ||
1682 | -/* Map IP to hostname, and then map back to addr to make sure it is a | |
1683 | - * reliable hostname | |
1684 | +/** | |
1685 | + * host_reliable_addrinfo - return addrinfo for a given address | |
1686 | + * @sap: pointer to socket address to look up | |
1687 | + * | |
1688 | + * Reverse and forward lookups are performed to ensure the address has | |
1689 | + * proper forward and reverse mappings. | |
1690 | + * | |
1691 | + * Returns address info structure with ai_canonname filled in, or NULL | |
1692 | + * if no information is available for @sap. Caller must free the returned | |
1693 | + * structure with freeaddrinfo(3). | |
1694 | */ | |
1695 | -struct hostent * | |
1696 | -get_reliable_hostbyaddr(const char *addr, int len, int type) | |
1697 | +__attribute_malloc__ | |
1698 | +struct addrinfo * | |
1699 | +host_reliable_addrinfo(const struct sockaddr *sap) | |
1700 | { | |
1701 | - struct hostent *hp = NULL; | |
1702 | + struct addrinfo *ai; | |
1703 | + char *hostname; | |
1704 | ||
1705 | - struct hostent *reverse; | |
1706 | - struct hostent *forward; | |
1707 | - char **sp; | |
1708 | - | |
1709 | - reverse = gethostbyaddr (addr, len, type); | |
1710 | - if (!reverse) | |
1711 | + hostname = host_canonname(sap); | |
1712 | + if (hostname == NULL) | |
1713 | return NULL; | |
1714 | ||
1715 | - /* must make sure the hostent is authorative. */ | |
1716 | + ai = host_addrinfo(hostname); | |
1717 | ||
1718 | - reverse = hostent_dup (reverse); | |
1719 | - forward = gethostbyname (reverse->h_name); | |
1720 | + free(hostname); | |
1721 | + return ai; | |
1722 | +} | |
1723 | ||
1724 | - if (forward) { | |
1725 | - /* now make sure the "addr" is in the list */ | |
1726 | - for (sp = forward->h_addr_list ; *sp ; sp++) { | |
1727 | - if (memcmp (*sp, addr, forward->h_length) == 0) | |
1728 | - break; | |
1729 | - } | |
1730 | +/** | |
1731 | + * host_numeric_addrinfo - return addrinfo without doing DNS queries | |
1732 | + * @sap: pointer to socket address | |
1733 | + * | |
1734 | + * Returns address info structure, or NULL if an error occurred. | |
1735 | + * Caller must free the returned structure with freeaddrinfo(3). | |
1736 | + */ | |
1737 | +#ifdef HAVE_GETNAMEINFO | |
1738 | +__attribute_malloc__ | |
1739 | +struct addrinfo * | |
1740 | +host_numeric_addrinfo(const struct sockaddr *sap) | |
1741 | +{ | |
1742 | + socklen_t salen = nfs_sockaddr_length(sap); | |
1743 | + char buf[INET6_ADDRSTRLEN]; | |
1744 | + struct addrinfo *ai; | |
1745 | + int error; | |
1746 | + | |
1747 | + if (salen == 0) { | |
1748 | + xlog(D_GENERAL, "%s: unsupported address family %d", | |
1749 | + __func__, sap->sa_family); | |
1750 | + return NULL; | |
1751 | + } | |
1752 | ||
1753 | - if (*sp) { | |
1754 | - /* it's valid */ | |
1755 | - hp = hostent_dup (forward); | |
1756 | - } | |
1757 | - else { | |
1758 | - /* it was a FAKE */ | |
1759 | - xlog (L_WARNING, "Fake hostname %s for %s - forward lookup doesn't match reverse", | |
1760 | - reverse->h_name, inet_ntoa(*(struct in_addr*)addr)); | |
1761 | - } | |
1762 | + memset(buf, 0, sizeof(buf)); | |
1763 | + error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf), | |
1764 | + NULL, 0, NI_NUMERICHOST); | |
1765 | + switch (error) { | |
1766 | + case 0: | |
1767 | + break; | |
1768 | + case EAI_SYSTEM: | |
1769 | + xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m", | |
1770 | + __func__, errno); | |
1771 | + return NULL; | |
1772 | + default: | |
1773 | + xlog(D_GENERAL, "%s: getnameinfo(3) failed: %s", | |
1774 | + __func__, gai_strerror(error)); | |
1775 | + return NULL; | |
1776 | } | |
1777 | - else { | |
1778 | - /* never heard of it. misconfigured DNS? */ | |
1779 | - xlog (L_WARNING, "Fake hostname %s for %s - forward lookup doesn't exist", | |
1780 | - reverse->h_name, inet_ntoa(*(struct in_addr*)addr)); | |
1781 | + | |
1782 | + ai = host_pton(buf); | |
1783 | + | |
1784 | + /* | |
1785 | + * getaddrinfo(AI_NUMERICHOST) never fills in ai_canonname | |
1786 | + */ | |
1787 | + if (ai != NULL) { | |
1788 | + free(ai->ai_canonname); /* just in case */ | |
1789 | + ai->ai_canonname = strdup(buf); | |
1790 | + if (ai->ai_canonname == NULL) { | |
1791 | + freeaddrinfo(ai); | |
1792 | + ai = NULL; | |
1793 | + } | |
1794 | } | |
1795 | ||
1796 | - free (reverse); | |
1797 | - return hp; | |
1798 | + return ai; | |
1799 | } | |
1800 | +#else /* !HAVE_GETNAMEINFO */ | |
1801 | +__attribute_malloc__ | |
1802 | +struct addrinfo * | |
1803 | +host_numeric_addrinfo(const struct sockaddr *sap) | |
1804 | +{ | |
1805 | + const struct sockaddr_in *sin = (const struct sockaddr_in *)sap; | |
1806 | + const struct in_addr *addr = &sin->sin_addr; | |
1807 | + char buf[INET_ADDRSTRLEN]; | |
1808 | + struct addrinfo *ai; | |
1809 | ||
1810 | + if (sap->sa_family != AF_INET) | |
1811 | + return NULL; | |
1812 | ||
1813 | -#ifdef TEST | |
1814 | -void | |
1815 | -print_host (struct hostent *hp) | |
1816 | -{ | |
1817 | - char **sp; | |
1818 | - | |
1819 | - if (hp) | |
1820 | - { | |
1821 | - printf ("official hostname: %s\n", hp->h_name); | |
1822 | - printf ("aliases:\n"); | |
1823 | - for (sp = hp->h_aliases; *sp; sp++) | |
1824 | - printf (" %s\n", *sp); | |
1825 | - printf ("IP addresses:\n"); | |
1826 | - for (sp = hp->h_addr_list; *sp; sp++) | |
1827 | - printf (" %s\n", inet_ntoa (*(struct in_addr *) *sp)); | |
1828 | - } | |
1829 | - else | |
1830 | - printf ("Not host information\n"); | |
1831 | -} | |
1832 | + memset(buf, 0, sizeof(buf)); | |
1833 | + if (inet_ntop(AF_INET, (char *)addr, buf, | |
1834 | + (socklen_t)sizeof(buf)) == NULL) | |
1835 | + return NULL; | |
1836 | ||
1837 | -int | |
1838 | -main (int argc, char **argv) | |
1839 | -{ | |
1840 | - struct hostent *hp = gethostbyname (argv [1]); | |
1841 | - struct hostent *cp; | |
1842 | - struct in_addr addr; | |
1843 | - | |
1844 | - print_host (hp); | |
1845 | - | |
1846 | - if (hp) | |
1847 | - { | |
1848 | - cp = hostent_dup (hp); | |
1849 | - print_host (cp); | |
1850 | - free (cp); | |
1851 | - } | |
1852 | - printf ("127.0.0.1 == %s: %d\n", argv [1], | |
1853 | - matchhostname ("127.0.0.1", argv [1])); | |
1854 | - addr.s_addr = inet_addr(argv [2]); | |
1855 | - printf ("%s\n", inet_ntoa (addr)); | |
1856 | - cp = get_hostent ((const char *)&addr, sizeof(addr), AF_INET); | |
1857 | - print_host (cp); | |
1858 | - return 0; | |
1859 | + ai = host_pton(buf); | |
1860 | + | |
1861 | + /* | |
1862 | + * getaddrinfo(AI_NUMERICHOST) never fills in ai_canonname | |
1863 | + */ | |
1864 | + if (ai != NULL) { | |
1865 | + ai->ai_canonname = strdup(buf); | |
1866 | + if (ai->ai_canonname == NULL) { | |
1867 | + freeaddrinfo(ai); | |
1868 | + ai = NULL; | |
1869 | + } | |
1870 | + } | |
1871 | + | |
1872 | + return ai; | |
1873 | } | |
1874 | -#endif | |
1875 | +#endif /* !HAVE_GETNAMEINFO */ | |
1876 | diff --git a/support/export/nfsctl.c b/support/export/nfsctl.c | |
1877 | index e2877b9..f89c644 100644 | |
1878 | --- a/support/export/nfsctl.c | |
1879 | +++ b/support/export/nfsctl.c | |
1880 | @@ -66,7 +66,7 @@ str_tolower(char *s) | |
1881 | static int | |
1882 | cltsetup(struct nfsctl_client *cltarg, nfs_client *clp) | |
1883 | { | |
1884 | - int i; | |
1885 | + int i, j; | |
1886 | ||
1887 | if (clp->m_type != MCL_FQDN) { | |
1888 | xlog(L_ERROR, "internal: can't export non-FQDN host"); | |
1889 | @@ -76,10 +76,19 @@ cltsetup(struct nfsctl_client *cltarg, nfs_client *clp) | |
1890 | strncpy(cltarg->cl_ident, clp->m_hostname, | |
1891 | sizeof (cltarg->cl_ident) - 1); | |
1892 | str_tolower(cltarg->cl_ident); | |
1893 | - cltarg->cl_naddr = clp->m_naddr; | |
1894 | - for (i = 0; i < cltarg->cl_naddr && i < NFSCLNT_ADDRMAX; i++) | |
1895 | - cltarg->cl_addrlist[i] = clp->m_addrlist[i]; | |
1896 | ||
1897 | + j = 0; | |
1898 | + for (i = 0; i < cltarg->cl_naddr && i < NFSCLNT_ADDRMAX; i++) { | |
1899 | + const struct sockaddr_in *sin = get_addrlist_in(clp, i); | |
1900 | + if (sin->sin_family == AF_INET) | |
1901 | + cltarg->cl_addrlist[j++] = sin->sin_addr; | |
1902 | + } | |
1903 | + if (j == 0) { | |
1904 | + xlog(L_ERROR, "internal: no supported addresses in nfs_client"); | |
1905 | + return 0; | |
1906 | + } | |
1907 | + | |
1908 | + cltarg->cl_naddr = j; | |
1909 | return 1; | |
1910 | } | |
1911 | ||
1912 | @@ -100,7 +109,7 @@ expsetup(struct nfsctl_export *exparg, nfs_export *exp, int unexport) | |
1913 | str_tolower(exparg->ex_client); | |
1914 | exparg->ex_flags = exp->m_export.e_flags; | |
1915 | exparg->ex_dev = (!unexport && (exp->m_export.e_flags & NFSEXP_FSID)) ? | |
1916 | - exp->m_export.e_fsid : stb.st_dev; | |
1917 | + (__nfsd_dev_t)exp->m_export.e_fsid : stb.st_dev; | |
1918 | exparg->ex_ino = stb.st_ino; | |
1919 | exparg->ex_anon_uid = exp->m_export.e_anonuid; | |
1920 | exparg->ex_anon_gid = exp->m_export.e_anongid; | |
1921 | diff --git a/support/export/rmtab.c b/support/export/rmtab.c | |
1922 | index b49e1aa..31c0f50 100644 | |
1923 | --- a/support/export/rmtab.c | |
1924 | +++ b/support/export/rmtab.c | |
1925 | @@ -19,39 +19,54 @@ | |
1926 | #include "xio.h" | |
1927 | #include "xlog.h" | |
1928 | ||
1929 | +/* | |
1930 | + * See if the entry already exists. If not, | |
1931 | + * this was an instantiated wild card, and we | |
1932 | + * must add it. | |
1933 | + */ | |
1934 | +static void | |
1935 | +rmtab_read_wildcard(struct rmtabent *rep) | |
1936 | +{ | |
1937 | + nfs_export *exp, *exp2; | |
1938 | + struct addrinfo *ai; | |
1939 | + | |
1940 | + ai = host_addrinfo(rep->r_client); | |
1941 | + if (ai == NULL) | |
1942 | + return; | |
1943 | + | |
1944 | + exp = export_allowed(ai, rep->r_path); | |
1945 | + freeaddrinfo(ai); | |
1946 | + if (exp == NULL) | |
1947 | + return; | |
1948 | + | |
1949 | + exp2 = export_lookup(rep->r_client, exp->m_export.e_path, 0); | |
1950 | + if (exp2 == NULL) { | |
1951 | + struct exportent ee; | |
1952 | + | |
1953 | + memset(&ee, 0, sizeof(ee)); | |
1954 | + dupexportent(&ee, &exp->m_export); | |
1955 | + | |
1956 | + ee.e_hostname = rep->r_client; | |
1957 | + exp2 = export_create(&ee, 0); | |
1958 | + exp2->m_changed = exp->m_changed; | |
1959 | + } | |
1960 | + exp2->m_mayexport = 1; | |
1961 | +} | |
1962 | + | |
1963 | int | |
1964 | rmtab_read(void) | |
1965 | { | |
1966 | struct rmtabent *rep; | |
1967 | - nfs_export *exp = NULL; | |
1968 | ||
1969 | setrmtabent("r"); | |
1970 | while ((rep = getrmtabent(1, NULL)) != NULL) { | |
1971 | - struct hostent *hp = NULL; | |
1972 | int htype; | |
1973 | - | |
1974 | + | |
1975 | htype = client_gettype(rep->r_client); | |
1976 | - if ((htype == MCL_FQDN || htype == MCL_SUBNETWORK) | |
1977 | - && (hp = gethostbyname (rep->r_client)) | |
1978 | - && (hp = hostent_dup (hp), | |
1979 | - exp = export_allowed (hp, rep->r_path))) { | |
1980 | - /* see if the entry already exists, otherwise this was an instantiated | |
1981 | - * wild card, and we must add it | |
1982 | - */ | |
1983 | - nfs_export *exp2 = export_lookup(rep->r_client, | |
1984 | - exp->m_export.e_path, 0); | |
1985 | - if (!exp2) { | |
1986 | - struct exportent ee; | |
1987 | - dupexportent(&ee, &exp->m_export); | |
1988 | - ee.e_hostname = rep->r_client; | |
1989 | - exp2 = export_create(&ee, 0); | |
1990 | - exp2->m_changed = exp->m_changed; | |
1991 | - } | |
1992 | - free (hp); | |
1993 | - exp2->m_mayexport = 1; | |
1994 | - } else if (hp) /* export_allowed failed */ | |
1995 | - free(hp); | |
1996 | + if (htype == MCL_FQDN || htype == MCL_SUBNETWORK) | |
1997 | + rmtab_read_wildcard(rep); | |
1998 | } | |
1999 | + | |
2000 | if (errno == EINVAL) { | |
2001 | /* Something goes wrong. We need to fix the rmtab | |
2002 | file. */ | |
2003 | diff --git a/support/include/exportfs.h b/support/include/exportfs.h | |
2004 | index 470b2ec..3cf1ee8 100644 | |
2005 | --- a/support/include/exportfs.h | |
2006 | +++ b/support/include/exportfs.h | |
2007 | @@ -10,6 +10,8 @@ | |
2008 | #define EXPORTFS_H | |
2009 | ||
2010 | #include <netdb.h> | |
2011 | + | |
2012 | +#include "sockaddr.h" | |
2013 | #include "nfslib.h" | |
2014 | ||
2015 | enum { | |
2016 | @@ -35,11 +37,56 @@ typedef struct mclient { | |
2017 | char * m_hostname; | |
2018 | int m_type; | |
2019 | int m_naddr; | |
2020 | - struct in_addr m_addrlist[NFSCLNT_ADDRMAX]; | |
2021 | + union nfs_sockaddr m_addrlist[NFSCLNT_ADDRMAX]; | |
2022 | int m_exported; /* exported to nfsd */ | |
2023 | int m_count; | |
2024 | } nfs_client; | |
2025 | ||
2026 | +static inline const struct sockaddr * | |
2027 | +get_addrlist(const nfs_client *clp, const int i) | |
2028 | +{ | |
2029 | + return &clp->m_addrlist[i].sa; | |
2030 | +} | |
2031 | + | |
2032 | +static inline const struct sockaddr_in * | |
2033 | +get_addrlist_in(const nfs_client *clp, const int i) | |
2034 | +{ | |
2035 | + return &clp->m_addrlist[i].s4; | |
2036 | +} | |
2037 | + | |
2038 | +static inline const struct sockaddr_in6 * | |
2039 | +get_addrlist_in6(const nfs_client *clp, const int i) | |
2040 | +{ | |
2041 | + return &clp->m_addrlist[i].s6; | |
2042 | +} | |
2043 | + | |
2044 | +static inline void | |
2045 | +set_addrlist_in(nfs_client *clp, const int i, const struct sockaddr_in *sin) | |
2046 | +{ | |
2047 | + memcpy(&clp->m_addrlist[i].s4, sin, sizeof(*sin)); | |
2048 | +} | |
2049 | + | |
2050 | +static inline void | |
2051 | +set_addrlist_in6(nfs_client *clp, const int i, const struct sockaddr_in6 *sin6) | |
2052 | +{ | |
2053 | + memcpy(&clp->m_addrlist[i].s6, sin6, sizeof(*sin6)); | |
2054 | +} | |
2055 | + | |
2056 | +static inline void | |
2057 | +set_addrlist(nfs_client *clp, const int i, const struct sockaddr *sap) | |
2058 | +{ | |
2059 | + switch (sap->sa_family) { | |
2060 | + case AF_INET: | |
2061 | + memcpy(&clp->m_addrlist[i].s4, sap, sizeof(struct sockaddr_in)); | |
2062 | + break; | |
2063 | +#ifdef IPV6_SUPPORTED | |
2064 | + case AF_INET6: | |
2065 | + memcpy(&clp->m_addrlist[i].s6, sap, sizeof(struct sockaddr_in6)); | |
2066 | + break; | |
2067 | +#endif | |
2068 | + } | |
2069 | +} | |
2070 | + | |
2071 | typedef struct mexport { | |
2072 | struct mexport * m_next; | |
2073 | struct mclient * m_client; | |
2074 | @@ -69,26 +116,26 @@ extern exp_hash_table exportlist[MCL_MAXTYPES]; | |
2075 | extern nfs_client * clientlist[MCL_MAXTYPES]; | |
2076 | ||
2077 | nfs_client * client_lookup(char *hname, int canonical); | |
2078 | -nfs_client * client_find(struct hostent *); | |
2079 | -void client_add(nfs_client *); | |
2080 | -nfs_client * client_dup(nfs_client *, struct hostent *); | |
2081 | +nfs_client * client_dup(const nfs_client *clp, | |
2082 | + const struct addrinfo *ai); | |
2083 | int client_gettype(char *hname); | |
2084 | -int client_check(nfs_client *, struct hostent *); | |
2085 | -int client_match(nfs_client *, char *hname); | |
2086 | +int client_check(const nfs_client *clp, | |
2087 | + const struct addrinfo *ai); | |
2088 | void client_release(nfs_client *); | |
2089 | void client_freeall(void); | |
2090 | -char * client_compose(struct hostent *he); | |
2091 | -struct hostent * client_resolve(struct in_addr addr); | |
2092 | -int client_member(char *client, char *name); | |
2093 | +char * client_compose(const struct addrinfo *ai); | |
2094 | +struct addrinfo * client_resolve(const struct sockaddr *sap); | |
2095 | +int client_member(const char *client, | |
2096 | + const char *name); | |
2097 | ||
2098 | -int export_read(char *fname); | |
2099 | -void export_add(nfs_export *); | |
2100 | +void export_read(char *fname); | |
2101 | void export_reset(nfs_export *); | |
2102 | nfs_export * export_lookup(char *hname, char *path, int caconical); | |
2103 | -nfs_export * export_find(struct hostent *, char *path); | |
2104 | -nfs_export * export_allowed(struct hostent *, char *path); | |
2105 | +nfs_export * export_find(const struct addrinfo *ai, | |
2106 | + const char *path); | |
2107 | +nfs_export * export_allowed(const struct addrinfo *ai, | |
2108 | + const char *path); | |
2109 | nfs_export * export_create(struct exportent *, int canonical); | |
2110 | -nfs_export * export_dup(nfs_export *, struct hostent *); | |
2111 | void export_freeall(void); | |
2112 | int export_export(nfs_export *); | |
2113 | int export_unexport(nfs_export *); | |
2114 | @@ -101,6 +148,19 @@ void xtab_append(nfs_export *); | |
2115 | ||
2116 | int secinfo_addflavor(struct flav_info *, struct exportent *); | |
2117 | ||
2118 | +char * host_ntop(const struct sockaddr *sap, | |
2119 | + char *buf, const size_t buflen); | |
2120 | +__attribute_malloc__ | |
2121 | +struct addrinfo * host_pton(const char *paddr); | |
2122 | +__attribute_malloc__ | |
2123 | +struct addrinfo * host_addrinfo(const char *hostname); | |
2124 | +__attribute_malloc__ | |
2125 | +char * host_canonname(const struct sockaddr *sap); | |
2126 | +__attribute_malloc__ | |
2127 | +struct addrinfo * host_reliable_addrinfo(const struct sockaddr *sap); | |
2128 | +__attribute_malloc__ | |
2129 | +struct addrinfo * host_numeric_addrinfo(const struct sockaddr *sap); | |
2130 | + | |
2131 | int rmtab_read(void); | |
2132 | ||
2133 | struct nfskey * key_lookup(char *hname); | |
2134 | diff --git a/support/include/misc.h b/support/include/misc.h | |
2135 | index 9a1b25d..bc5ba23 100644 | |
2136 | --- a/support/include/misc.h | |
2137 | +++ b/support/include/misc.h | |
2138 | @@ -15,13 +15,6 @@ | |
2139 | int randomkey(unsigned char *keyout, int len); | |
2140 | int weakrandomkey(unsigned char *keyout, int len); | |
2141 | ||
2142 | -int matchhostname(const char *h1, const char *h2); | |
2143 | - | |
2144 | -struct hostent; | |
2145 | -struct hostent *hostent_dup(struct hostent *hp); | |
2146 | -struct hostent *get_hostent (const char *addr, int len, int type); | |
2147 | -struct hostent *get_reliable_hostbyaddr(const char *addr, int len, int type); | |
2148 | - | |
2149 | extern int is_mountpoint(char *path); | |
2150 | ||
2151 | #endif /* MISC_H */ | |
2152 | diff --git a/support/include/nfslib.h b/support/include/nfslib.h | |
2153 | index 537a31e..3db5bec 100644 | |
2154 | --- a/support/include/nfslib.h | |
2155 | +++ b/support/include/nfslib.h | |
2156 | @@ -83,7 +83,7 @@ struct exportent { | |
2157 | int e_nsquids; | |
2158 | int * e_sqgids; | |
2159 | int e_nsqgids; | |
2160 | - int e_fsid; | |
2161 | + unsigned int e_fsid; | |
2162 | char * e_mountpoint; | |
2163 | int e_fslocmethod; | |
2164 | char * e_fslocdata; | |
2165 | @@ -134,9 +134,12 @@ int nfsaddclient(struct nfsctl_client *clp); | |
2166 | int nfsdelclient(struct nfsctl_client *clp); | |
2167 | int nfsexport(struct nfsctl_export *exp); | |
2168 | int nfsunexport(struct nfsctl_export *exp); | |
2169 | -struct nfs_fh_len * getfh_old(struct sockaddr *addr, dev_t dev, ino_t ino); | |
2170 | -struct nfs_fh_len * getfh(struct sockaddr *addr, const char *); | |
2171 | -struct nfs_fh_len * getfh_size(struct sockaddr *addr, const char *, int size); | |
2172 | + | |
2173 | +struct nfs_fh_len * getfh_old(const struct sockaddr_in *sin, | |
2174 | + const dev_t dev, const ino_t ino); | |
2175 | +struct nfs_fh_len * getfh(const struct sockaddr_in *sin, const char *path); | |
2176 | +struct nfs_fh_len * getfh_size(const struct sockaddr_in *sin, | |
2177 | + const char *path, int const size); | |
2178 | ||
2179 | void qword_print(FILE *f, char *str); | |
2180 | void qword_printhex(FILE *f, char *str, int slen); | |
2181 | @@ -152,10 +155,15 @@ void qword_addhex(char **bpp, int *lp, char *buf, int blen); | |
2182 | void qword_addint(char **bpp, int *lp, int n); | |
2183 | void qword_adduint(char **bpp, int *lp, unsigned int n); | |
2184 | void qword_addeol(char **bpp, int *lp); | |
2185 | +int qword_get_uint(char **bpp, unsigned int *anint); | |
2186 | +void qword_printuint(FILE *f, unsigned int num); | |
2187 | ||
2188 | void closeall(int min); | |
2189 | ||
2190 | int svctcp_socket (u_long __number, int __reuse); | |
2191 | -int svcudp_socket (u_long __number, int __reuse); | |
2192 | +int svcudp_socket (u_long __number); | |
2193 | + | |
2194 | + | |
2195 | +#define UNUSED(x) UNUSED_ ## x __attribute__((unused)) | |
2196 | ||
2197 | #endif /* NFSLIB_H */ | |
2198 | diff --git a/support/include/nfsrpc.h b/support/include/nfsrpc.h | |
2199 | index 4db35ab..6ebefca 100644 | |
2200 | --- a/support/include/nfsrpc.h | |
2201 | +++ b/support/include/nfsrpc.h | |
2202 | @@ -160,4 +160,7 @@ extern int nfs_rpc_ping(const struct sockaddr *sap, | |
2203 | const unsigned short protocol, | |
2204 | const struct timeval *timeout); | |
2205 | ||
2206 | +/* create AUTH_SYS handle with no supplemental groups */ | |
2207 | +extern AUTH * nfs_authsys_create(void); | |
2208 | + | |
2209 | #endif /* !__NFS_UTILS_NFSRPC_H */ | |
2210 | diff --git a/support/include/rpcmisc.h b/support/include/rpcmisc.h | |
2211 | index 1b8f411..c5847fa 100644 | |
2212 | --- a/support/include/rpcmisc.h | |
2213 | +++ b/support/include/rpcmisc.h | |
2214 | @@ -60,12 +60,12 @@ extern int _rpcsvcdirty; | |
2215 | ||
2216 | static inline struct sockaddr_in *nfs_getrpccaller_in(SVCXPRT *xprt) | |
2217 | { | |
2218 | - return (struct sockaddr_in *)svc_getcaller(xprt); | |
2219 | + return (struct sockaddr_in *)(char *)svc_getcaller(xprt); | |
2220 | } | |
2221 | ||
2222 | static inline struct sockaddr *nfs_getrpccaller(SVCXPRT *xprt) | |
2223 | { | |
2224 | - return (struct sockaddr *)svc_getcaller(xprt); | |
2225 | + return (struct sockaddr *)(char *)svc_getcaller(xprt); | |
2226 | } | |
2227 | ||
2228 | #endif /* RPCMISC_H */ | |
2229 | diff --git a/support/nfs/cacheio.c b/support/nfs/cacheio.c | |
2230 | index bdf5d84..9bad8e6 100644 | |
2231 | --- a/support/nfs/cacheio.c | |
2232 | +++ b/support/nfs/cacheio.c | |
2233 | @@ -148,6 +148,11 @@ void qword_printint(FILE *f, int num) | |
2234 | fprintf(f, "%d ", num); | |
2235 | } | |
2236 | ||
2237 | +void qword_printuint(FILE *f, unsigned int num) | |
2238 | +{ | |
2239 | + fprintf(f, "%u ", num); | |
2240 | +} | |
2241 | + | |
2242 | int qword_eol(FILE *f) | |
2243 | { | |
2244 | int err; | |
2245 | @@ -236,6 +241,20 @@ int qword_get_int(char **bpp, int *anint) | |
2246 | return 0; | |
2247 | } | |
2248 | ||
2249 | +int qword_get_uint(char **bpp, unsigned int *anint) | |
2250 | +{ | |
2251 | + char buf[50]; | |
2252 | + char *ep; | |
2253 | + unsigned int rv; | |
2254 | + int len = qword_get(bpp, buf, 50); | |
2255 | + if (len < 0) return -1; | |
2256 | + if (len ==0) return -1; | |
2257 | + rv = strtoul(buf, &ep, 0); | |
2258 | + if (*ep) return -1; | |
2259 | + *anint = rv; | |
2260 | + return 0; | |
2261 | +} | |
2262 | + | |
2263 | #define READLINE_BUFFER_INCREMENT 2048 | |
2264 | ||
2265 | int readline(int fd, char **buf, int *lenp) | |
2266 | @@ -330,7 +349,7 @@ cache_flush(int force) | |
2267 | sprintf(path, "/proc/net/rpc/%s/flush", cachelist[c]); | |
2268 | fd = open(path, O_RDWR); | |
2269 | if (fd >= 0) { | |
2270 | - if (write(fd, stime, strlen(stime)) != strlen(stime)) { | |
2271 | + if (write(fd, stime, strlen(stime)) != (ssize_t)strlen(stime)) { | |
2272 | xlog_warn("Writing to '%s' failed: errno %d (%s)", | |
2273 | path, errno, strerror(errno)); | |
2274 | } | |
2275 | diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c | |
2276 | index b277c2a..24640f4 100644 | |
2277 | --- a/support/nfs/conffile.c | |
2278 | +++ b/support/nfs/conffile.c | |
2279 | @@ -49,7 +49,7 @@ | |
2280 | #include "conffile.h" | |
2281 | #include "xlog.h" | |
2282 | ||
2283 | -static void conf_load_defaults (int); | |
2284 | +static void conf_load_defaults(void); | |
2285 | static int conf_set(int , char *, char *, char *, | |
2286 | char *, int , int ); | |
2287 | ||
2288 | @@ -212,7 +212,7 @@ conf_parse_line(int trans, char *line, size_t sz) | |
2289 | { | |
2290 | char *val, *ptr; | |
2291 | size_t i; | |
2292 | - int j; | |
2293 | + size_t j; | |
2294 | static char *section = 0; | |
2295 | static char *arg = 0; | |
2296 | static int ln = 0; | |
2297 | @@ -353,7 +353,7 @@ conf_parse(int trans, char *buf, size_t sz) | |
2298 | } | |
2299 | ||
2300 | static void | |
2301 | -conf_load_defaults(int tr) | |
2302 | +conf_load_defaults(void) | |
2303 | { | |
2304 | /* No defaults */ | |
2305 | return; | |
2306 | @@ -412,7 +412,7 @@ conf_reinit(void) | |
2307 | trans = conf_begin(); | |
2308 | ||
2309 | /* Load default configuration values. */ | |
2310 | - conf_load_defaults(trans); | |
2311 | + conf_load_defaults(); | |
2312 | ||
2313 | /* Free potential existing configuration. */ | |
2314 | if (conf_addr) { | |
2315 | diff --git a/support/nfs/exports.c b/support/nfs/exports.c | |
2316 | index a93941c..1744ed6 100644 | |
2317 | --- a/support/nfs/exports.c | |
2318 | +++ b/support/nfs/exports.c | |
2319 | @@ -332,6 +332,8 @@ dupexportent(struct exportent *dst, struct exportent *src) | |
2320 | dst->e_mountpoint = strdup(src->e_mountpoint); | |
2321 | if (src->e_fslocdata) | |
2322 | dst->e_fslocdata = strdup(src->e_fslocdata); | |
2323 | + if (src->e_uuid) | |
2324 | + dst->e_uuid = strdup(src->e_uuid); | |
2325 | dst->e_hostname = NULL; | |
2326 | } | |
2327 | ||
2328 | diff --git a/support/nfs/getfh.c b/support/nfs/getfh.c | |
2329 | index 81266fd..611459b 100644 | |
2330 | --- a/support/nfs/getfh.c | |
2331 | +++ b/support/nfs/getfh.c | |
2332 | @@ -19,60 +19,112 @@ | |
2333 | #include <errno.h> | |
2334 | #include "nfslib.h" | |
2335 | ||
2336 | +/** | |
2337 | + * getfh_old - ask the kernel for an NFSv2 file handle via nfsctl() | |
2338 | + * @sin: pointer to IPv4 address of a client | |
2339 | + * @dev: device number of device where requested object resides | |
2340 | + * @ino: inode number of requested object | |
2341 | + * | |
2342 | + * Returns a pointer to an NFSv2 file handle, or NULL if some error | |
2343 | + * occurred. errno is set to reflect the specifics of the error. | |
2344 | + */ | |
2345 | struct nfs_fh_len * | |
2346 | -getfh_old (struct sockaddr *addr, dev_t dev, ino_t ino) | |
2347 | +getfh_old(const struct sockaddr_in *sin, const dev_t dev, const ino_t ino) | |
2348 | { | |
2349 | union nfsctl_res res; | |
2350 | struct nfsctl_arg arg; | |
2351 | static struct nfs_fh_len rfh; | |
2352 | ||
2353 | + if (sin->sin_family != AF_INET) { | |
2354 | + errno = EAFNOSUPPORT; | |
2355 | + return NULL; | |
2356 | + } | |
2357 | + | |
2358 | + memset(&arg, 0, sizeof(arg)); | |
2359 | + memset(&res, 0, sizeof(res)); | |
2360 | + | |
2361 | arg.ca_version = NFSCTL_VERSION; | |
2362 | arg.ca_getfh.gf_version = 2; /* obsolete */ | |
2363 | arg.ca_getfh.gf_dev = dev; | |
2364 | arg.ca_getfh.gf_ino = ino; | |
2365 | - memcpy(&arg.ca_getfh.gf_addr, addr, sizeof(struct sockaddr_in)); | |
2366 | + memcpy(&arg.ca_getfh.gf_addr, sin, sizeof(*sin)); | |
2367 | ||
2368 | if (nfsctl(NFSCTL_GETFH, &arg, &res) < 0) | |
2369 | return NULL; | |
2370 | ||
2371 | + memset(&rfh, 0, sizeof(rfh)); | |
2372 | rfh.fh_size = 32; | |
2373 | memcpy(rfh.fh_handle, &res.cr_getfh, 32); | |
2374 | return &rfh; | |
2375 | } | |
2376 | ||
2377 | +/** | |
2378 | + * getfh - ask the kernel for an NFSv2 file handle via nfsctl() | |
2379 | + * @sin: pointer to IPv4 address of a client | |
2380 | + * @path: pointer to a '\0'-terminated ASCII string containing an pathname | |
2381 | + * | |
2382 | + * Returns a pointer to an NFSv2 file handle, or NULL if some error | |
2383 | + * occurred. errno is set to reflect the specifics of the error. | |
2384 | + */ | |
2385 | struct nfs_fh_len * | |
2386 | -getfh(struct sockaddr *addr, const char *path) | |
2387 | +getfh(const struct sockaddr_in *sin, const char *path) | |
2388 | { | |
2389 | static union nfsctl_res res; | |
2390 | struct nfsctl_arg arg; | |
2391 | static struct nfs_fh_len rfh; | |
2392 | ||
2393 | + if (sin->sin_family != AF_INET) { | |
2394 | + errno = EAFNOSUPPORT; | |
2395 | + return NULL; | |
2396 | + } | |
2397 | + | |
2398 | + memset(&arg, 0, sizeof(arg)); | |
2399 | + memset(&res, 0, sizeof(res)); | |
2400 | + | |
2401 | arg.ca_version = NFSCTL_VERSION; | |
2402 | arg.ca_getfd.gd_version = 2; /* obsolete */ | |
2403 | strncpy(arg.ca_getfd.gd_path, path, | |
2404 | sizeof(arg.ca_getfd.gd_path) - 1); | |
2405 | arg.ca_getfd.gd_path[sizeof (arg.ca_getfd.gd_path) - 1] = '\0'; | |
2406 | - memcpy(&arg.ca_getfd.gd_addr, addr, sizeof(struct sockaddr_in)); | |
2407 | + memcpy(&arg.ca_getfd.gd_addr, sin, sizeof(*sin)); | |
2408 | ||
2409 | if (nfsctl(NFSCTL_GETFD, &arg, &res) < 0) | |
2410 | return NULL; | |
2411 | ||
2412 | + memset(&rfh, 0, sizeof(rfh)); | |
2413 | rfh.fh_size = 32; | |
2414 | memcpy(rfh.fh_handle, &res.cr_getfh, 32); | |
2415 | return &rfh; | |
2416 | } | |
2417 | ||
2418 | +/** | |
2419 | + * getfh_size - ask the kernel for a file handle via nfsctl() | |
2420 | + * @sin: pointer to IPv4 address of a client | |
2421 | + * @path: pointer to a '\0'-terminated ASCII string containing an pathname | |
2422 | + * @size: maximum size, in bytes, of the returned file handle | |
2423 | + * | |
2424 | + * Returns a pointer to an NFSv3 file handle, or NULL if some error | |
2425 | + * occurred. errno is set to reflect the specifics of the error. | |
2426 | + */ | |
2427 | struct nfs_fh_len * | |
2428 | -getfh_size(struct sockaddr *addr, const char *path, int size) | |
2429 | +getfh_size(const struct sockaddr_in *sin, const char *path, const int size) | |
2430 | { | |
2431 | static union nfsctl_res res; | |
2432 | struct nfsctl_arg arg; | |
2433 | ||
2434 | + if (sin->sin_family != AF_INET) { | |
2435 | + errno = EAFNOSUPPORT; | |
2436 | + return NULL; | |
2437 | + } | |
2438 | + | |
2439 | + memset(&arg, 0, sizeof(arg)); | |
2440 | + memset(&res, 0, sizeof(res)); | |
2441 | + | |
2442 | arg.ca_version = NFSCTL_VERSION; | |
2443 | strncpy(arg.ca_getfs.gd_path, path, | |
2444 | sizeof(arg.ca_getfs.gd_path) - 1); | |
2445 | arg.ca_getfs.gd_path[sizeof (arg.ca_getfs.gd_path) - 1] = '\0'; | |
2446 | - memcpy(&arg.ca_getfs.gd_addr, addr, sizeof(struct sockaddr_in)); | |
2447 | + memcpy(&arg.ca_getfs.gd_addr, sin, sizeof(*sin)); | |
2448 | arg.ca_getfs.gd_maxlen = size; | |
2449 | ||
2450 | if (nfsctl(NFSCTL_GETFS, &arg, &res) < 0) | |
2451 | diff --git a/support/nfs/nfs_mntent.c b/support/nfs/nfs_mntent.c | |
2452 | index a3fecfc..9c73ae0 100644 | |
2453 | --- a/support/nfs/nfs_mntent.c | |
2454 | +++ b/support/nfs/nfs_mntent.c | |
2455 | @@ -28,7 +28,7 @@ static char * | |
2456 | mangle(const char *arg) { | |
2457 | const unsigned char *s = (const unsigned char *)arg; | |
2458 | char *ss, *sp; | |
2459 | - int n; | |
2460 | + unsigned int n; | |
2461 | ||
2462 | n = strlen(arg); | |
2463 | ss = sp = xmalloc(4*n+1); | |
2464 | diff --git a/support/nfs/rmtab.c b/support/nfs/rmtab.c | |
2465 | index a28abf3..ca789a3 100644 | |
2466 | --- a/support/nfs/rmtab.c | |
2467 | +++ b/support/nfs/rmtab.c | |
2468 | @@ -19,6 +19,18 @@ | |
2469 | #include <signal.h> | |
2470 | #include "nfslib.h" | |
2471 | ||
2472 | +/* | |
2473 | + * Colons in incoming IPv6 presentation addresses have to | |
2474 | + * replaced with another character, since rmtab already | |
2475 | + * uses colons to delineate fields. | |
2476 | + * | |
2477 | + * Use a printable character, but one that would never be | |
2478 | + * found in a presentation address or domain name | |
2479 | + */ | |
2480 | +#define IPV6_COLON ';' | |
2481 | + | |
2482 | +#define LINELEN (2048) | |
2483 | + | |
2484 | static FILE *rmfp = NULL; | |
2485 | ||
2486 | int | |
2487 | @@ -56,7 +68,8 @@ struct rmtabent * | |
2488 | fgetrmtabent(FILE *fp, int log, long *pos) | |
2489 | { | |
2490 | static struct rmtabent re; | |
2491 | - char buf[2048], *count, *host, *path; | |
2492 | + char *count, *host, *path, *c; | |
2493 | + static char buf[LINELEN]; | |
2494 | ||
2495 | errno = 0; | |
2496 | if (!fp) | |
2497 | @@ -84,10 +97,16 @@ fgetrmtabent(FILE *fp, int log, long *pos) | |
2498 | else | |
2499 | re.r_count = 1; | |
2500 | } while (0); | |
2501 | + | |
2502 | strncpy(re.r_client, host, sizeof (re.r_client) - 1); | |
2503 | re.r_client[sizeof (re.r_client) - 1] = '\0'; | |
2504 | + for (c = re.r_client; *c != '\0'; c++) | |
2505 | + if (*c == IPV6_COLON) | |
2506 | + *c = ':'; | |
2507 | + | |
2508 | strncpy(re.r_path, path, sizeof (re.r_path) - 1); | |
2509 | re.r_path[sizeof (re.r_path) - 1] = '\0'; | |
2510 | + | |
2511 | return &re; | |
2512 | } | |
2513 | ||
2514 | @@ -100,10 +119,27 @@ putrmtabent(struct rmtabent *rep, long *pos) | |
2515 | void | |
2516 | fputrmtabent(FILE *fp, struct rmtabent *rep, long *pos) | |
2517 | { | |
2518 | + static char buf[LINELEN]; | |
2519 | + char *c; | |
2520 | + | |
2521 | if (!fp || (pos && fseek (fp, *pos, SEEK_SET) != 0)) | |
2522 | return; | |
2523 | - fprintf(fp, "%s:%s:0x%.8x\n", rep->r_client, rep->r_path, | |
2524 | - rep->r_count); | |
2525 | + | |
2526 | + /* | |
2527 | + * To avoid confusing the token parser in fgetrmtabent(), | |
2528 | + * convert colons in incoming IPv6 presentation addresses | |
2529 | + * to semicolons. | |
2530 | + */ | |
2531 | + if (strlen(rep->r_client) > sizeof(buf)) { | |
2532 | + xlog(L_ERROR, "client name too large"); | |
2533 | + return; | |
2534 | + } | |
2535 | + strncpy(buf, rep->r_client, sizeof(buf)); | |
2536 | + for (c = buf; *c != '\0'; c++) | |
2537 | + if (*c == ':') | |
2538 | + *c = IPV6_COLON; | |
2539 | + | |
2540 | + (void)fprintf(fp, "%s:%s:0x%.8x\n", buf, rep->r_path, rep->r_count); | |
2541 | } | |
2542 | ||
2543 | void | |
2544 | diff --git a/support/nfs/rpc_socket.c b/support/nfs/rpc_socket.c | |
2545 | index 0e20824..c14efe8 100644 | |
2546 | --- a/support/nfs/rpc_socket.c | |
2547 | +++ b/support/nfs/rpc_socket.c | |
2548 | @@ -557,3 +557,24 @@ rpcprog_t nfs_getrpcbyname(const rpcprog_t program, const char *table[]) | |
2549 | ||
2550 | return program; | |
2551 | } | |
2552 | + | |
2553 | +/* | |
2554 | + * AUTH_SYS doesn't allow more than 16 gids in the supplemental group list. | |
2555 | + * If there are more than that, trying to determine which ones to include | |
2556 | + * in the list is problematic. This function creates an auth handle that | |
2557 | + * only has the primary gid in the supplemental gids list. It's intended to | |
2558 | + * be used for protocols where credentials really don't matter much (the MNT | |
2559 | + * protocol, for instance). | |
2560 | + */ | |
2561 | +AUTH * | |
2562 | +nfs_authsys_create(void) | |
2563 | +{ | |
2564 | + char machname[MAXHOSTNAMELEN + 1]; | |
2565 | + uid_t uid = geteuid(); | |
2566 | + gid_t gid = getegid(); | |
2567 | + | |
2568 | + if (gethostname(machname, sizeof(machname)) == -1) | |
2569 | + return NULL; | |
2570 | + | |
2571 | + return authunix_create(machname, uid, gid, 1, &gid); | |
2572 | +} | |
2573 | diff --git a/support/nfs/rpcdispatch.c b/support/nfs/rpcdispatch.c | |
2574 | index 502fc5f..984c646 100644 | |
2575 | --- a/support/nfs/rpcdispatch.c | |
2576 | +++ b/support/nfs/rpcdispatch.c | |
2577 | @@ -27,12 +27,12 @@ rpc_dispatch(struct svc_req *rqstp, SVCXPRT *transp, | |
2578 | { | |
2579 | struct rpc_dentry *dent; | |
2580 | ||
2581 | - if (rqstp->rq_vers > nvers) { | |
2582 | + if (((int)rqstp->rq_vers) > nvers) { | |
2583 | svcerr_progvers(transp, 1, nvers); | |
2584 | return; | |
2585 | } | |
2586 | dtable += (rqstp->rq_vers - 1); | |
2587 | - if (rqstp->rq_proc > dtable->nproc) { | |
2588 | + if (((int)rqstp->rq_proc) > dtable->nproc) { | |
2589 | svcerr_noproc(transp); | |
2590 | return; | |
2591 | } | |
2592 | diff --git a/support/nfs/rpcmisc.c b/support/nfs/rpcmisc.c | |
2593 | index a0854e7..b73187a 100644 | |
2594 | --- a/support/nfs/rpcmisc.c | |
2595 | +++ b/support/nfs/rpcmisc.c | |
2596 | @@ -154,7 +154,7 @@ rpc_init(char *name, int prog, int vers, | |
2597 | sock = makesock(defport, IPPROTO_UDP); | |
2598 | } | |
2599 | if (sock == RPC_ANYSOCK) | |
2600 | - sock = svcudp_socket (prog, 1); | |
2601 | + sock = svcudp_socket (prog); | |
2602 | transp = svcudp_create(sock); | |
2603 | if (transp == NULL) { | |
2604 | xlog(L_FATAL, "cannot create udp service."); | |
2605 | diff --git a/support/nfs/svc_socket.c b/support/nfs/svc_socket.c | |
2606 | index f44217a..03a5325 100644 | |
2607 | --- a/support/nfs/svc_socket.c | |
2608 | +++ b/support/nfs/svc_socket.c | |
2609 | @@ -157,9 +157,9 @@ svctcp_socket (u_long number, int reuse) | |
2610 | * Create and bind a UDP socket based on program number | |
2611 | */ | |
2612 | int | |
2613 | -svcudp_socket (u_long number, int reuse) | |
2614 | +svcudp_socket (u_long number) | |
2615 | { | |
2616 | - return svc_socket (number, SOCK_DGRAM, IPPROTO_UDP, 0); | |
2617 | + return svc_socket (number, SOCK_DGRAM, IPPROTO_UDP, FALSE); | |
2618 | } | |
2619 | ||
2620 | #ifdef TEST | |
2621 | @@ -174,7 +174,7 @@ check (u_long number, u_short port, int protocol, int reuse) | |
2622 | if (protocol == IPPROTO_TCP) | |
2623 | socket = svctcp_socket (number, reuse); | |
2624 | else | |
2625 | - socket = svcudp_socket (number, reuse); | |
2626 | + socket = svcudp_socket (number); | |
2627 | ||
2628 | if (socket < 0) | |
2629 | return 1; | |
2630 | diff --git a/support/nsm/file.c b/support/nsm/file.c | |
2631 | index d469219..f4baeb9 100644 | |
2632 | --- a/support/nsm/file.c | |
2633 | +++ b/support/nsm/file.c | |
2634 | @@ -67,7 +67,9 @@ | |
2635 | #endif | |
2636 | ||
2637 | #include <sys/types.h> | |
2638 | +#ifdef HAVE_SYS_CAPABILITY_H | |
2639 | #include <sys/capability.h> | |
2640 | +#endif | |
2641 | #include <sys/prctl.h> | |
2642 | #include <sys/stat.h> | |
2643 | ||
2644 | @@ -347,6 +349,7 @@ nsm_is_default_parentdir(void) | |
2645 | static _Bool | |
2646 | nsm_clear_capabilities(void) | |
2647 | { | |
2648 | +#ifdef HAVE_SYS_CAPABILITY_H | |
2649 | cap_t caps; | |
2650 | ||
2651 | caps = cap_from_text("cap_net_bind_service=ep"); | |
2652 | @@ -362,6 +365,7 @@ nsm_clear_capabilities(void) | |
2653 | } | |
2654 | ||
2655 | (void)cap_free(caps); | |
2656 | +#endif | |
2657 | return true; | |
2658 | } | |
2659 | ||
2660 | diff --git a/tests/t0001-statd-basic-mon-unmon.sh b/tests/t0001-statd-basic-mon-unmon.sh | |
2661 | old mode 100644 | |
2662 | new mode 100755 | |
2663 | diff --git a/tools/Makefile.am b/tools/Makefile.am | |
2664 | index db15346..f2ce282 100644 | |
2665 | --- a/tools/Makefile.am | |
2666 | +++ b/tools/Makefile.am | |
2667 | @@ -6,6 +6,6 @@ if CONFIG_RPCGEN | |
2668 | OPTDIRS += rpcgen | |
2669 | endif | |
2670 | ||
2671 | -SUBDIRS = locktest rpcdebug nlmtest $(OPTDIRS) | |
2672 | +SUBDIRS = locktest rpcdebug nlmtest mountstats nfs-iostat $(OPTDIRS) | |
2673 | ||
2674 | MAINTAINERCLEANFILES = Makefile.in | |
2675 | diff --git a/tools/mountstats/Makefile.am b/tools/mountstats/Makefile.am | |
2676 | new file mode 100644 | |
2677 | index 0000000..ca617a2 | |
2678 | --- /dev/null | |
2679 | +++ b/tools/mountstats/Makefile.am | |
2680 | @@ -0,0 +1,13 @@ | |
2681 | +## Process this file with automake to produce Makefile.in | |
2682 | +PYTHON_FILES = mountstats.py | |
2683 | + | |
2684 | +man8_MANS = mountstats.man | |
2685 | + | |
2686 | +EXTRA_DIST = $(man8_MANS) $(PYTHON_FILES) | |
2687 | + | |
2688 | +all-local: $(PYTHON_FILES) | |
2689 | + | |
2690 | +install-data-hook: | |
2691 | + $(INSTALL) --mode 755 mountstats.py $(DESTDIR)$(sbindir)/mountstats | |
2692 | + | |
2693 | +MAINTAINERCLEANFILES=Makefile.in | |
2694 | diff --git a/tools/mountstats/mountstats.man b/tools/mountstats/mountstats.man | |
2695 | new file mode 100644 | |
2696 | index 0000000..0de31b7 | |
2697 | --- /dev/null | |
2698 | +++ b/tools/mountstats/mountstats.man | |
2699 | @@ -0,0 +1,32 @@ | |
2700 | +.\" | |
2701 | +.\" mountstats(8) | |
2702 | +.\" | |
2703 | +.TH mountstats 8 "15 Apr 2010" | |
2704 | +.SH NAME | |
2705 | +mountstats \- Displays NFS client per-mount statistics | |
2706 | +.SH SYNOPSIS | |
2707 | +.BI "mountstats ["<options> "] " <mount_point> " [ " <mount_point> "]" | |
2708 | +.SH DESCRIPTION | |
2709 | +The | |
2710 | +.B mountstats | |
2711 | +command displays NFS client statisitics on each given | |
2712 | +.I <mount_point> | |
2713 | +.SH OPTIONS | |
2714 | +.TP | |
2715 | +.B " \-\-nfs | |
2716 | +display only the NFS statistics | |
2717 | +.TP | |
2718 | +.B " \-\-rpc | |
2719 | +display only the RPC statistics | |
2720 | +.TP | |
2721 | +.B " \-\-version | |
2722 | +display the version of this command | |
2723 | +.SH FILES | |
2724 | +.TP | |
2725 | +.B /proc/self/mountstats | |
2726 | +.SH SEE ALSO | |
2727 | +.BR iostat (8), | |
2728 | +.BR nfsiostat (8), | |
2729 | +.BR nfsstat(8) | |
2730 | +.SH AUTHOR | |
2731 | +Chuck Lever <chuck.lever@oracle.com> | |
2732 | diff --git a/tools/nfs-iostat/Makefile.am b/tools/nfs-iostat/Makefile.am | |
2733 | new file mode 100644 | |
2734 | index 0000000..30f4054 | |
2735 | --- /dev/null | |
2736 | +++ b/tools/nfs-iostat/Makefile.am | |
2737 | @@ -0,0 +1,13 @@ | |
2738 | +## Process this file with automake to produce Makefile.in | |
2739 | +PYTHON_FILES = nfs-iostat.py | |
2740 | + | |
2741 | +man8_MANS = nfsiostat.man | |
2742 | + | |
2743 | +EXTRA_DIST = $(man8_MANS) $(PYTHON_FILES) | |
2744 | + | |
2745 | +all-local: $(PYTHON_FILES) | |
2746 | + | |
2747 | +install-data-hook: | |
2748 | + $(INSTALL) --mode 755 nfs-iostat.py $(DESTDIR)$(sbindir)/nfsiostat | |
2749 | + | |
2750 | +MAINTAINERCLEANFILES=Makefile.in | |
2751 | diff --git a/tools/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py | |
2752 | index 2d0b143..1207674 100644 | |
2753 | --- a/tools/nfs-iostat/nfs-iostat.py | |
2754 | +++ b/tools/nfs-iostat/nfs-iostat.py | |
2755 | @@ -366,6 +366,12 @@ class DeviceData: | |
2756 | sends = float(self.__rpc_data['rpcsends']) | |
2757 | if sample_time == 0: | |
2758 | sample_time = float(self.__nfs_data['age']) | |
2759 | + # sample_time could still be zero if the export was just mounted. | |
2760 | + # Set it to 1 to avoid divide by zero errors in this case since we'll | |
2761 | + # likely still have relevant mount statistics to show. | |
2762 | + # | |
2763 | + if sample_time == 0: | |
2764 | + sample_time = 1; | |
2765 | if sends != 0: | |
2766 | backlog = (float(self.__rpc_data['backlogutil']) / sends) / sample_time | |
2767 | else: | |
2768 | diff --git a/tools/nfs-iostat/nfsiostat.man b/tools/nfs-iostat/nfsiostat.man | |
2769 | new file mode 100644 | |
2770 | index 0000000..99e04fb | |
2771 | --- /dev/null | |
2772 | +++ b/tools/nfs-iostat/nfsiostat.man | |
2773 | @@ -0,0 +1,71 @@ | |
2774 | +.\" | |
2775 | +.\" nfsiostat(8) | |
2776 | +.\" | |
2777 | +.TH nfsiostat 8 "15 Apr 2010" | |
2778 | +.SH NAME | |
2779 | +nfsiostat \- Emulate iostat for NFS mount points using /proc/self/mountstats | |
2780 | +.SH SYNOPSIS | |
2781 | +.BI "nfsiostat [[" <interval> "] [" <count> "]] [" <options> "]["<mount_point> "] | |
2782 | +.SH DESCRIPTION | |
2783 | +The | |
2784 | +.B nfsiostat | |
2785 | +command displays NFS client per-mount statisitics. | |
2786 | +.TP | |
2787 | +<interval> | |
2788 | +specifies the amount of time in seconds between each report. | |
2789 | +The first report contains statistics for the time since each file | |
2790 | +system was mounted. Each subsequent report contains statistics collected | |
2791 | +during the interval since the previous report. | |
2792 | +.TP | |
2793 | +<count> | |
2794 | +If the | |
2795 | +.I <count> | |
2796 | +parameter is | |
2797 | +specified, the value of | |
2798 | +.I <count> | |
2799 | +determines the number of reports generated at | |
2800 | +. <interval> | |
2801 | +seconds apart. if the interval parameter is | |
2802 | +specified without the | |
2803 | +.I <count> | |
2804 | +parameter, the command generates reports continuously. | |
2805 | +.TP | |
2806 | +<options> | |
2807 | +Define below | |
2808 | +.TP | |
2809 | +<mount_point> | |
2810 | +If one or more | |
2811 | +.I <mount point> | |
2812 | +names are specified, statistics for only these mount points will | |
2813 | +be displayed. Otherwise, all NFS mount points on the client are listed. | |
2814 | +.SH OPTIONS | |
2815 | +.TP | |
2816 | +.B \-a " or " \-\-attr | |
2817 | +displays statistics related to the attribute cache | |
2818 | +.TP | |
2819 | +.B \-d " or " \-\-dir | |
2820 | +displays statistics related to directory operations | |
2821 | +.TP | |
2822 | +.B \-h " or " \-\-help | |
2823 | +shows help message and exit | |
2824 | +.TP | |
2825 | +.B \-l LIST or " \-\-list=LIST | |
2826 | +only print stats for first LIST mount points | |
2827 | +.TP | |
2828 | +.B \-p " or " \-\-page | |
2829 | +displays statistics related to the page cache | |
2830 | +.TP | |
2831 | +.B \-s " or " \-\-sort | |
2832 | +Sort NFS mount points by ops/second | |
2833 | +.TP | |
2834 | +.B \-\-version | |
2835 | +show program's version number and exit | |
2836 | +.SH FILES | |
2837 | +.TP | |
2838 | +.B /proc/self/mountstats | |
2839 | +.SH SEE ALSO | |
2840 | +.BR iostat (8), | |
2841 | +.BR mountstats (8), | |
2842 | +.BR nfsstat(8) | |
2843 | +.SH AUTHOR | |
2844 | +Chuck Lever <chuck.lever@oracle.com> | |
2845 | diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c | |
2846 | index 331e57e..b78957f 100644 | |
2847 | --- a/utils/exportfs/exportfs.c | |
2848 | +++ b/utils/exportfs/exportfs.c | |
2849 | @@ -12,20 +12,24 @@ | |
2850 | #include <config.h> | |
2851 | #endif | |
2852 | ||
2853 | +#include <sys/types.h> | |
2854 | +#include <sys/stat.h> | |
2855 | #include <sys/vfs.h> | |
2856 | #include <sys/stat.h> | |
2857 | #include <unistd.h> | |
2858 | +#include <stdbool.h> | |
2859 | #include <stdlib.h> | |
2860 | #include <string.h> | |
2861 | #include <stdarg.h> | |
2862 | #include <getopt.h> | |
2863 | +#include <fcntl.h> | |
2864 | #include <netdb.h> | |
2865 | #include <errno.h> | |
2866 | -#include "xmalloc.h" | |
2867 | + | |
2868 | +#include "sockaddr.h" | |
2869 | #include "misc.h" | |
2870 | #include "nfslib.h" | |
2871 | #include "exportfs.h" | |
2872 | -#include "xmalloc.h" | |
2873 | #include "xlog.h" | |
2874 | ||
2875 | static void export_all(int verbose); | |
2876 | @@ -34,13 +38,15 @@ static void unexportfs(char *arg, int verbose); | |
2877 | static void exports_update(int verbose); | |
2878 | static void dump(int verbose); | |
2879 | static void error(nfs_export *exp, int err); | |
2880 | -static void usage(void); | |
2881 | +static void usage(const char *progname); | |
2882 | static void validate_export(nfs_export *exp); | |
2883 | +static int matchhostname(const char *hostname1, const char *hostname2); | |
2884 | ||
2885 | int | |
2886 | main(int argc, char **argv) | |
2887 | { | |
2888 | char *options = NULL; | |
2889 | + char *progname = NULL; | |
2890 | int f_export = 1; | |
2891 | int f_all = 0; | |
2892 | int f_verbose = 0; | |
2893 | @@ -50,7 +56,14 @@ main(int argc, char **argv) | |
2894 | int new_cache = 0; | |
2895 | int force_flush = 0; | |
2896 | ||
2897 | - xlog_open("exportfs"); | |
2898 | + if ((progname = strrchr(argv[0], '/')) != NULL) | |
2899 | + progname++; | |
2900 | + else | |
2901 | + progname = argv[0]; | |
2902 | + | |
2903 | + xlog_open(progname); | |
2904 | + xlog_stderr(1); | |
2905 | + xlog_syslog(0); | |
2906 | ||
2907 | export_errno = 0; | |
2908 | ||
2909 | @@ -79,21 +92,21 @@ main(int argc, char **argv) | |
2910 | force_flush = 1; | |
2911 | break; | |
2912 | default: | |
2913 | - usage(); | |
2914 | + usage(progname); | |
2915 | break; | |
2916 | } | |
2917 | } | |
2918 | ||
2919 | if (optind != argc && f_all) { | |
2920 | - fprintf(stderr,"exportfs: extra arguments are not permitted with -a or -r.\n"); | |
2921 | + xlog(L_ERROR, "extra arguments are not permitted with -a or -r"); | |
2922 | return 1; | |
2923 | } | |
2924 | if (f_ignore && (f_all || ! f_export)) { | |
2925 | - fprintf(stderr,"exportfs: -i not meaningful with -a, -r or -u.\n"); | |
2926 | + xlog(L_ERROR, "-i not meaningful with -a, -r or -u"); | |
2927 | return 1; | |
2928 | } | |
2929 | if (f_reexport && ! f_export) { | |
2930 | - fprintf(stderr, "exportfs: -r and -u are incompatible.\n"); | |
2931 | + xlog(L_ERROR, "-r and -u are incompatible"); | |
2932 | return 1; | |
2933 | } | |
2934 | new_cache = check_new_cache(); | |
2935 | @@ -102,8 +115,10 @@ main(int argc, char **argv) | |
2936 | if (new_cache) | |
2937 | cache_flush(1); | |
2938 | else { | |
2939 | - fprintf(stderr, "exportfs: -f: only available with new cache controls: mount /proc/fs/nfsd first\n"); | |
2940 | - exit(1); | |
2941 | + xlog(L_ERROR, "-f is available only " | |
2942 | + "with new cache controls. " | |
2943 | + "Mount /proc/fs/nfsd first"); | |
2944 | + return 1; | |
2945 | } | |
2946 | return 0; | |
2947 | } else { | |
2948 | @@ -232,7 +247,7 @@ exportfs(char *arg, char *options, int verbose) | |
2949 | { | |
2950 | struct exportent *eep; | |
2951 | nfs_export *exp; | |
2952 | - struct hostent *hp = NULL; | |
2953 | + struct addrinfo *ai = NULL; | |
2954 | char *path; | |
2955 | char *hname = arg; | |
2956 | int htype; | |
2957 | @@ -241,36 +256,25 @@ exportfs(char *arg, char *options, int verbose) | |
2958 | *path++ = '\0'; | |
2959 | ||
2960 | if (!path || *path != '/') { | |
2961 | - fprintf(stderr, "Invalid exporting option: %s\n", arg); | |
2962 | + xlog(L_ERROR, "Invalid exporting option: %s", arg); | |
2963 | return; | |
2964 | } | |
2965 | ||
2966 | - if ((htype = client_gettype(hname)) == MCL_FQDN && | |
2967 | - (hp = gethostbyname(hname)) != NULL) { | |
2968 | - struct hostent *hp2 = hostent_dup (hp); | |
2969 | - hp = gethostbyaddr(hp2->h_addr, hp2->h_length, | |
2970 | - hp2->h_addrtype); | |
2971 | - if (hp) { | |
2972 | - free(hp2); | |
2973 | - hp = hostent_dup(hp); | |
2974 | - } else | |
2975 | - hp = hp2; | |
2976 | - exp = export_find(hp, path); | |
2977 | - hname = hp->h_name; | |
2978 | - } else { | |
2979 | + if ((htype = client_gettype(hname)) == MCL_FQDN) { | |
2980 | + ai = host_addrinfo(hname); | |
2981 | + if (ai != NULL) { | |
2982 | + exp = export_find(ai, path); | |
2983 | + hname = ai->ai_canonname; | |
2984 | + } | |
2985 | + } else | |
2986 | exp = export_lookup(hname, path, 0); | |
2987 | - } | |
2988 | ||
2989 | if (!exp) { | |
2990 | if (!(eep = mkexportent(hname, path, options)) || | |
2991 | - !(exp = export_create(eep, 0))) { | |
2992 | - if (hp) free (hp); | |
2993 | - return; | |
2994 | - } | |
2995 | - } else if (!updateexportent(&exp->m_export, options)) { | |
2996 | - if (hp) free (hp); | |
2997 | - return; | |
2998 | - } | |
2999 | + !(exp = export_create(eep, 0))) | |
3000 | + goto out; | |
3001 | + } else if (!updateexportent(&exp->m_export, options)) | |
3002 | + goto out; | |
3003 | ||
3004 | if (verbose) | |
3005 | printf("exporting %s:%s\n", exp->m_client->m_hostname, | |
3006 | @@ -280,14 +284,16 @@ exportfs(char *arg, char *options, int verbose) | |
3007 | exp->m_changed = 1; | |
3008 | exp->m_warned = 0; | |
3009 | validate_export(exp); | |
3010 | - if (hp) free (hp); | |
3011 | + | |
3012 | +out: | |
3013 | + freeaddrinfo(ai); | |
3014 | } | |
3015 | ||
3016 | static void | |
3017 | unexportfs(char *arg, int verbose) | |
3018 | { | |
3019 | nfs_export *exp; | |
3020 | - struct hostent *hp = NULL; | |
3021 | + struct addrinfo *ai = NULL; | |
3022 | char *path; | |
3023 | char *hname = arg; | |
3024 | int htype; | |
3025 | @@ -296,16 +302,14 @@ unexportfs(char *arg, int verbose) | |
3026 | *path++ = '\0'; | |
3027 | ||
3028 | if (!path || *path != '/') { | |
3029 | - fprintf(stderr, "Invalid unexporting option: %s\n", | |
3030 | - arg); | |
3031 | + xlog(L_ERROR, "Invalid unexporting option: %s", arg); | |
3032 | return; | |
3033 | } | |
3034 | ||
3035 | if ((htype = client_gettype(hname)) == MCL_FQDN) { | |
3036 | - if ((hp = gethostbyname(hname)) != 0) { | |
3037 | - hp = hostent_dup (hp); | |
3038 | - hname = (char *) hp->h_name; | |
3039 | - } | |
3040 | + ai = host_addrinfo(hname); | |
3041 | + if (ai) | |
3042 | + hname = ai->ai_canonname; | |
3043 | } | |
3044 | ||
3045 | for (exp = exportlist[htype].p_head; exp; exp = exp->m_next) { | |
3046 | @@ -341,7 +345,7 @@ unexportfs(char *arg, int verbose) | |
3047 | exp->m_mayexport = 0; | |
3048 | } | |
3049 | ||
3050 | - if (hp) free (hp); | |
3051 | + freeaddrinfo(ai); | |
3052 | } | |
3053 | ||
3054 | static int can_test(void) | |
3055 | @@ -393,14 +397,12 @@ validate_export(nfs_export *exp) | |
3056 | int fs_has_fsid = 0; | |
3057 | ||
3058 | if (stat(path, &stb) < 0) { | |
3059 | - fprintf(stderr, "exportfs: Warning: %s does not exist\n", | |
3060 | - path); | |
3061 | + xlog(L_ERROR, "Failed to stat %s: %m \n", path); | |
3062 | return; | |
3063 | } | |
3064 | if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) { | |
3065 | - fprintf(stderr, "exportfs: Warning: %s is neither " | |
3066 | - "a directory nor a file.\n" | |
3067 | - " remote access will fail\n", path); | |
3068 | + xlog(L_ERROR, "%s is neither a directory nor a file. " | |
3069 | + "Remote access will fail", path); | |
3070 | return; | |
3071 | } | |
3072 | if (!can_test()) | |
3073 | @@ -413,24 +415,75 @@ validate_export(nfs_export *exp) | |
3074 | if ((exp->m_export.e_flags & NFSEXP_FSID) || exp->m_export.e_uuid || | |
3075 | fs_has_fsid) { | |
3076 | if ( !test_export(path, 1)) { | |
3077 | - fprintf(stderr, "exportfs: Warning: %s does not " | |
3078 | - "support NFS export.\n", | |
3079 | - path); | |
3080 | + xlog(L_ERROR, "%s does not support NFS export", path); | |
3081 | return; | |
3082 | } | |
3083 | } else if ( ! test_export(path, 0)) { | |
3084 | if (test_export(path, 1)) | |
3085 | - fprintf(stderr, "exportfs: Warning: %s requires fsid= " | |
3086 | - "for NFS export\n", path); | |
3087 | + xlog(L_ERROR, "%s requires fsid= for NFS export", path); | |
3088 | else | |
3089 | - fprintf(stderr, "exportfs: Warning: %s does not " | |
3090 | - "support NFS export.\n", | |
3091 | - path); | |
3092 | + xlog(L_ERROR, "%s does not support NFS export", path); | |
3093 | return; | |
3094 | ||
3095 | } | |
3096 | } | |
3097 | ||
3098 | +static _Bool | |
3099 | +is_hostname(const char *sp) | |
3100 | +{ | |
3101 | + if (*sp == '\0' || *sp == '@') | |
3102 | + return false; | |
3103 | + | |
3104 | + for (; *sp != '\0'; sp++) { | |
3105 | + if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/') | |
3106 | + return false; | |
3107 | + if (*sp == '\\' && sp[1] != '\0') | |
3108 | + sp++; | |
3109 | + } | |
3110 | + | |
3111 | + return true; | |
3112 | +} | |
3113 | + | |
3114 | +static int | |
3115 | +matchhostname(const char *hostname1, const char *hostname2) | |
3116 | +{ | |
3117 | + struct addrinfo *results1 = NULL, *results2 = NULL; | |
3118 | + struct addrinfo *ai1, *ai2; | |
3119 | + int result = 0; | |
3120 | + | |
3121 | + if (strcasecmp(hostname1, hostname2) == 0) | |
3122 | + return 1; | |
3123 | + | |
3124 | + /* | |
3125 | + * Don't pass export wildcards or netgroup names to DNS | |
3126 | + */ | |
3127 | + if (!is_hostname(hostname1) || !is_hostname(hostname2)) | |
3128 | + return 0; | |
3129 | + | |
3130 | + results1 = host_addrinfo(hostname1); | |
3131 | + if (results1 == NULL) | |
3132 | + goto out; | |
3133 | + results2 = host_addrinfo(hostname2); | |
3134 | + if (results2 == NULL) | |
3135 | + goto out; | |
3136 | + | |
3137 | + if (strcasecmp(results1->ai_canonname, results2->ai_canonname) == 0) { | |
3138 | + result = 1; | |
3139 | + goto out; | |
3140 | + } | |
3141 | + | |
3142 | + for (ai1 = results1; ai1 != NULL; ai1 = ai1->ai_next) | |
3143 | + for (ai2 = results2; ai2 != NULL; ai2 = ai2->ai_next) | |
3144 | + if (nfs_compare_sockaddr(ai1->ai_addr, ai2->ai_addr)) { | |
3145 | + result = 1; | |
3146 | + break; | |
3147 | + } | |
3148 | + | |
3149 | +out: | |
3150 | + freeaddrinfo(results1); | |
3151 | + freeaddrinfo(results2); | |
3152 | + return result; | |
3153 | +} | |
3154 | ||
3155 | static char | |
3156 | dumpopt(char c, char *fmt, ...) | |
3157 | @@ -532,13 +585,13 @@ dump(int verbose) | |
3158 | static void | |
3159 | error(nfs_export *exp, int err) | |
3160 | { | |
3161 | - fprintf(stderr, "%s:%s: %s\n", exp->m_client->m_hostname, | |
3162 | + xlog(L_ERROR, "%s:%s: %s\n", exp->m_client->m_hostname, | |
3163 | exp->m_export.e_path, strerror(err)); | |
3164 | } | |
3165 | ||
3166 | static void | |
3167 | -usage(void) | |
3168 | +usage(const char *progname) | |
3169 | { | |
3170 | - fprintf(stderr, "usage: exportfs [-aruv] [host:/path]\n"); | |
3171 | + fprintf(stderr, "usage: %s [-aruv] [host:/path]\n", progname); | |
3172 | exit(1); | |
3173 | } | |
3174 | diff --git a/utils/exportfs/exportfs.man b/utils/exportfs/exportfs.man | |
3175 | index c7b230a..089f75b 100644 | |
3176 | --- a/utils/exportfs/exportfs.man | |
3177 | +++ b/utils/exportfs/exportfs.man | |
3178 | @@ -1,11 +1,11 @@ | |
3179 | +.\"@(#)exportfs.8" | |
3180 | .\" | |
3181 | -.\" exportfs(8) | |
3182 | -.\" | |
3183 | .\" Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de> | |
3184 | .\" Modifications 1999-2003 Neil Brown <neilb@cse.unsw.edu.au> | |
3185 | -.TH exportfs 8 "18 July 2003" | |
3186 | +.\" | |
3187 | +.TH exportfs 8 "31 December 2009" | |
3188 | .SH NAME | |
3189 | -exportfs \- maintain list of NFS exported file systems | |
3190 | +exportfs \- maintain table of exported NFS file systems | |
3191 | .SH SYNOPSIS | |
3192 | .BI "/usr/sbin/exportfs [-avi] [-o " "options,.." "] [" "client:/path" " ..] | |
3193 | .br | |
3194 | @@ -18,229 +18,236 @@ exportfs \- maintain list of NFS exported file systems | |
3195 | .BI "/usr/sbin/exportfs -f" | |
3196 | .br | |
3197 | .SH DESCRIPTION | |
3198 | +An NFS server maintains a table of local physical file systems | |
3199 | +that are accessible to NFS clients. | |
3200 | +Each file system in this table is referred to as an | |
3201 | +.IR "exported file system" , | |
3202 | +or | |
3203 | +.IR export , | |
3204 | +for short. | |
3205 | +.PP | |
3206 | The | |
3207 | .B exportfs | |
3208 | -command is used to maintain the current table of exported file systems for | |
3209 | -NFS. This list is kept in a separate file named | |
3210 | -.BR /var/lib/nfs/etab | |
3211 | -which is read by | |
3212 | -.B mountd | |
3213 | -when a remote host requests access to mount a file tree, and parts of | |
3214 | -the list which are active are kept in the kernel's export table. | |
3215 | -.P | |
3216 | -Normally this | |
3217 | -.B etab | |
3218 | -file is initialized with the list of all file systems named in | |
3219 | -.B /etc/exports | |
3220 | +command maintains the current table of exports for the NFS server. | |
3221 | +The master export table is kept in a file named | |
3222 | +.IR /var/lib/nfs/etab . | |
3223 | +This file is read by | |
3224 | +.B rpc.mountd | |
3225 | +when a client sends an NFS MOUNT request. | |
3226 | +.PP | |
3227 | +Normally the master export table is initialized with the contents of | |
3228 | +.I /etc/exports | |
3229 | by invoking | |
3230 | .BR "exportfs -a" . | |
3231 | -.P | |
3232 | -However, administrators can choose to add and delete individual file systems | |
3233 | -without modifying | |
3234 | -.B /etc/exports | |
3235 | -using | |
3236 | -.BR exportfs . | |
3237 | -.P | |
3238 | +However, a system administrator can choose to add or delete | |
3239 | +exports without modifying | |
3240 | +.I /etc/exports | |
3241 | +by using the | |
3242 | +.B exportfs | |
3243 | +command. | |
3244 | +.PP | |
3245 | .B exportfs | |
3246 | -and it's partner program | |
3247 | -.B mountd | |
3248 | -work in one of two modes, a legacy mode which applies to 2.4 and | |
3249 | +and its partner program | |
3250 | +.B rpc.mountd | |
3251 | +work in one of two modes: a legacy mode which applies to 2.4 and | |
3252 | earlier versions of the Linux kernel, and a new mode which applies to | |
3253 | -2.6 and later versions providing the | |
3254 | +2.6 and later versions, providing the | |
3255 | .B nfsd | |
3256 | virtual filesystem has been mounted at | |
3257 | -.B /proc/fs/nfsd | |
3258 | +.I /proc/fs/nfsd | |
3259 | or | |
3260 | -.BR /proc/fs/nfs . | |
3261 | -If this filesystem is not mounted in 2.6, the legacy mode is used. | |
3262 | -.P | |
3263 | +.IR /proc/fs/nfs . | |
3264 | +On 2.6 kernels, if this filesystem is not mounted, the legacy mode is used. | |
3265 | +.PP | |
3266 | In the new mode, | |
3267 | .B exportfs | |
3268 | -does not give any information to the kernel but only provides it to | |
3269 | -.B mountd | |
3270 | +does not give any information to the kernel, but provides it only to | |
3271 | +.B rpc.mountd | |
3272 | through the | |
3273 | -.B /var/lib/nfs/etab | |
3274 | +.I /var/lib/nfs/etab | |
3275 | file. | |
3276 | -.B mountd | |
3277 | -will listen to requests from the kernel and will provide information | |
3278 | -as needed. | |
3279 | -.P | |
3280 | +.B rpc.mountd | |
3281 | +then manages kernel requests for information about exports, as needed. | |
3282 | +.PP | |
3283 | In the legacy mode, | |
3284 | -any export requests which identify a specific host (rather than a | |
3285 | -subnet or netgroup etc) are entered directly into the kernel's export | |
3286 | -table as well as being written to | |
3287 | -.BR /var/lib/nfs/etab . | |
3288 | -Further, any mount points listed in | |
3289 | -.B /var/lib/nfs/rmtab | |
3290 | +exports which identify a specific host, rather than a subnet or netgroup, | |
3291 | +are entered directly into the kernel's export table, | |
3292 | +as well as being written to | |
3293 | +.IR /var/lib/nfs/etab . | |
3294 | +Further, exports listed in | |
3295 | +.I /var/lib/nfs/rmtab | |
3296 | which match a non host-specific export request will cause an | |
3297 | appropriate export entry for the host given in | |
3298 | -.B rmtab | |
3299 | -to be entered | |
3300 | -into the kernel's export table. | |
3301 | +.I rmtab | |
3302 | +to be added to the kernel's export table. | |
3303 | .SH OPTIONS | |
3304 | -.TP | |
3305 | +.TP | |
3306 | .B -a | |
3307 | Export or unexport all directories. | |
3308 | .TP | |
3309 | .BI "-o " options,... | |
3310 | Specify a list of export options in the same manner as in | |
3311 | -.BR exports(5) . | |
3312 | +.BR exports (5). | |
3313 | .TP | |
3314 | .B -i | |
3315 | Ignore the | |
3316 | -.B /etc/exports | |
3317 | -file, so that only default options and options given on the command | |
3318 | -line are used. | |
3319 | +.I /etc/exports | |
3320 | +file. Only default options and options given on the command line are used. | |
3321 | .TP | |
3322 | .B -r | |
3323 | -Reexport all directories. It synchronizes /var/lib/nfs/etab | |
3324 | -with /etc/exports. It removes entries in /var/lib/nfs/etab | |
3325 | -which are deleted from /etc/exports, and remove any entries from the | |
3326 | +Reexport all directories, synchronizing | |
3327 | +.I /var/lib/nfs/etab | |
3328 | +with | |
3329 | +.IR /etc/exports . | |
3330 | +This option removes entries in | |
3331 | +.I /var/lib/nfs/etab | |
3332 | +which have been deleted from | |
3333 | +.I /etc/exports, and removes any entries from the | |
3334 | kernel export table which are no longer valid. | |
3335 | .TP | |
3336 | .B -u | |
3337 | Unexport one or more directories. | |
3338 | .TP | |
3339 | .B -f | |
3340 | -In 'new' mode, flush everything out of the kernels export table. Any | |
3341 | -clients that are active will get new entries added by | |
3342 | -.B mountd | |
3343 | -when they make their next request. | |
3344 | +If | |
3345 | +.I /proc/fs/nfsd | |
3346 | +or | |
3347 | +.I /proc/fs/nfs | |
3348 | +is mounted, flush everything out of the kernel's export table. | |
3349 | +Fresh entries for active clients are added to the kernel's export table by | |
3350 | +.B rpc.mountd | |
3351 | +when they make their next NFS mount request. | |
3352 | .TP | |
3353 | .B -v | |
3354 | Be verbose. When exporting or unexporting, show what's going on. When | |
3355 | displaying the current export list, also display the list of export | |
3356 | options. | |
3357 | .SH DISCUSSION | |
3358 | -.\" -------------------- Exporting Directories -------------------- | |
3359 | .SS Exporting Directories | |
3360 | -The first synopsis shows how to invoke the command when adding new | |
3361 | -entries to the export table. When using | |
3362 | +The first synopsis shows how to invoke | |
3363 | +.B exportfs | |
3364 | +when adding new entries to the export table. When using | |
3365 | .BR "exportfs -a" , | |
3366 | -all directories in | |
3367 | -.B exports(5) | |
3368 | +all exports listed in | |
3369 | +.I /etc/exports | |
3370 | are added to | |
3371 | -.B etab | |
3372 | -and the resulting list is pushed into the kernel. | |
3373 | -.P | |
3374 | +.IR /var/lib/nfs/etab . | |
3375 | +The kernel's export table is also updated as needed. | |
3376 | +.PP | |
3377 | The | |
3378 | .I host:/path | |
3379 | -argument specifies the directory to export along with the host or hosts to | |
3380 | -export it to. All formats described in | |
3381 | +argument specifies a local directory to export, | |
3382 | +along with the client or clients who are permitted to access it. | |
3383 | +See | |
3384 | .B exports(5) | |
3385 | -are supported; to export a directory to the world, simply specify | |
3386 | +for a description of supported options and access list formats. | |
3387 | +To export a directory to the world, simply specify | |
3388 | .IR :/path . | |
3389 | -.P | |
3390 | +.PP | |
3391 | The export options for a particular host/directory pair derive from | |
3392 | -several sources. There is a set of default options which can be overridden by | |
3393 | -entries in | |
3394 | -.B /etc/exports | |
3395 | -(unless the | |
3396 | -.B -i | |
3397 | -option is given). | |
3398 | -In addition, the administrator may override any options from these sources | |
3399 | -using the | |
3400 | +several sources. | |
3401 | +The default export options are | |
3402 | +.BR sync,ro,root_squash,wdelay . | |
3403 | +These can be overridden by entries in | |
3404 | +.IR /etc/exports . | |
3405 | +.PP | |
3406 | +A system administrator may override options from these sources using the | |
3407 | .B -o | |
3408 | -argument which takes a comma-separated list of options in the same fashion | |
3409 | +command-line option on | |
3410 | +.BR exportfs . | |
3411 | +This option takes a comma-separated list of options in the same fashion | |
3412 | as one would specify them in | |
3413 | -.BR exports(5) . | |
3414 | -Thus, | |
3415 | +.IR /etc/exports . | |
3416 | +In this way | |
3417 | .B exportfs | |
3418 | -can also be used to modify the export options of an already exported | |
3419 | -directory. | |
3420 | -.P | |
3421 | -Modifications of the kernel export table used by | |
3422 | -.B nfsd(8) | |
3423 | -take place immediately after parsing the command line and updating the | |
3424 | -.B etab | |
3425 | -file. | |
3426 | -.P | |
3427 | -The default export options are | |
3428 | -.BR sync,ro,root_squash,wdelay . | |
3429 | -.\" -------------------- Unexporting Directories ------------------ | |
3430 | +can be used to modify the export options of an already exported directory. | |
3431 | .SS Unexporting Directories | |
3432 | The third synopsis shows how to unexported a currently exported directory. | |
3433 | When using | |
3434 | .BR "exportfs -ua" , | |
3435 | all entries listed in | |
3436 | -.B etab | |
3437 | +.I /var/lib/nfs/etab | |
3438 | are removed from the kernel export tables, and the file is cleared. This | |
3439 | effectively shuts down all NFS activity. | |
3440 | -.P | |
3441 | -To remove an export to a host, specify a | |
3442 | +.PP | |
3443 | +To remove an export, specify a | |
3444 | .I host:/path | |
3445 | pair. This deletes the specified entry from | |
3446 | -.B etab | |
3447 | +.I /var/lib/nfs/etab | |
3448 | and removes the corresponding kernel entry (if any). | |
3449 | -To remove one or more exports to several hosts, use | |
3450 | -.BR "exportfs -ua" . | |
3451 | -.P | |
3452 | -.\" -------------------- Dumping the Export Table ----------------- | |
3453 | -.SS Dumping the Export Table | |
3454 | +.PP | |
3455 | +.SS Dumping the Export Table | |
3456 | Invoking | |
3457 | .B exportfs | |
3458 | -without further options shows the current list of exported file systems. | |
3459 | -When giving the | |
3460 | +without options shows the current list of exported file systems. | |
3461 | +Adding the | |
3462 | .B -v | |
3463 | -option, the list of flags pertaining to each export are shown in addition. | |
3464 | -.\" -------------------- EXAMPLES --------------------------------- | |
3465 | +option causes | |
3466 | +.B exportfs | |
3467 | +to display the export options for each export. | |
3468 | .SH EXAMPLES | |
3469 | The following adds all directories listed in | |
3470 | -.B /etc/exports | |
3471 | +.I /etc/exports | |
3472 | to | |
3473 | -.B /var/lib/nfs/etab | |
3474 | +.I /var/lib/nfs/etab | |
3475 | and pushes the resulting export entries into the kernel: | |
3476 | -.P | |
3477 | +.PP | |
3478 | .nf | |
3479 | .B "# exportfs -a | |
3480 | .fi | |
3481 | -.P | |
3482 | +.PP | |
3483 | To export the | |
3484 | -.B /usr/tmp | |
3485 | -directory to host | |
3486 | +.I /usr/tmp | |
3487 | +directory to host | |
3488 | .BR django , | |
3489 | -allowing asynchronous writes, one would do this: | |
3490 | -.P | |
3491 | +allowing insecure file locking requests from clients: | |
3492 | +.PP | |
3493 | .nf | |
3494 | -.B "# exportfs -o async django:/usr/tmp | |
3495 | +.B "# exportfs -o insecure_locks django:/usr/tmp | |
3496 | .fi | |
3497 | -.P | |
3498 | +.PP | |
3499 | To unexport the | |
3500 | -.B /usr/tmp | |
3501 | +.I /usr/tmp | |
3502 | directory: | |
3503 | -.P | |
3504 | +.PP | |
3505 | .nf | |
3506 | .B "# exportfs -u django:/usr/tmp | |
3507 | .fi | |
3508 | -.P | |
3509 | -To unexport all the directories listed in | |
3510 | -.B /etc/exports: | |
3511 | -.P | |
3512 | +.PP | |
3513 | +To unexport all exports listed in | |
3514 | +.IR /etc/exports : | |
3515 | +.PP | |
3516 | .nf | |
3517 | .B "# exportfs -au | |
3518 | .fi | |
3519 | -.\" -------------------- DEPENDENCIES ----------------------------- | |
3520 | -.SH DEPENDENCIES | |
3521 | -Exporting to IP networks, DNS and NIS domains does not enable clients | |
3522 | -from these groups to access NFS immediately; rather, these sorts of | |
3523 | -exports are hints to | |
3524 | -.B mountd(8) | |
3525 | +.SH USAGE NOTES | |
3526 | +Exporting to IP networks or DNS and NIS domains does not enable clients | |
3527 | +from these groups to access NFS immediately. | |
3528 | +Rather, these sorts of exports are hints to | |
3529 | +.BR rpc.mountd (8) | |
3530 | to grant any mount requests from these clients. | |
3531 | -This is usually not a big problem, because any existing mounts are preserved | |
3532 | -in | |
3533 | -.B rmtab | |
3534 | +This is usually not a problem, because any existing mounts are preserved in | |
3535 | +.I rmtab | |
3536 | across reboots. | |
3537 | -.P | |
3538 | +.PP | |
3539 | When unexporting a network or domain entry, any current exports to members | |
3540 | of this group will be checked against the remaining valid exports and | |
3541 | if they themselves are no longer valid they will be removed. | |
3542 | -.P | |
3543 | -.\" -------------------- SEE ALSO -------------------------------- | |
3544 | +.SH FILES | |
3545 | +.TP 2.5i | |
3546 | +.I /etc/exports | |
3547 | +input file listing exports, export options, and access control lists | |
3548 | +.TP 2.5i | |
3549 | +.I /var/lib/nfs/etab | |
3550 | +master table of exports | |
3551 | +.TP 2.5i | |
3552 | +.I /var/lib/nfs/rmtab | |
3553 | +table of clients accessing server's exports | |
3554 | .SH SEE ALSO | |
3555 | -.BR exports(5) ", " mountd(8) | |
3556 | -.\" -------------------- AUTHOR ---------------------------------- | |
3557 | +.BR exports (5), | |
3558 | +.BR rpc.mountd (8), | |
3559 | +.BR netgroup (5) | |
3560 | .SH AUTHORS | |
3561 | -Olaf Kirch, <okir@monad.swb.de> | |
3562 | +Olaf Kirch <okir@monad.swb.de> | |
3563 | .br | |
3564 | -Neil Brown, <neilb@cse.unsw.edu.au> | |
3565 | - | |
3566 | +Neil Brown <neilb@cse.unsw.edu.au> | |
3567 | diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man | |
3568 | index ea28ca8..c726dd9 100644 | |
3569 | --- a/utils/exportfs/exports.man | |
3570 | +++ b/utils/exportfs/exports.man | |
3571 | @@ -1,18 +1,22 @@ | |
3572 | -.TH EXPORTS 5 "4 March 2005" "Linux" "Linux File Formats Manual" | |
3573 | +.\"@(#)exports.5" | |
3574 | +.\" | |
3575 | +.TH exports 5 "31 December 2009" | |
3576 | .SH NAME | |
3577 | -exports \- NFS file systems being exported (for Kernel based NFS) | |
3578 | -.SH SYNOPSIS | |
3579 | -.B /etc/exports | |
3580 | +exports \- NFS server export table | |
3581 | .SH DESCRIPTION | |
3582 | The file | |
3583 | .I /etc/exports | |
3584 | -serves as the access control list for file systems which may be | |
3585 | -exported to NFS clients. It is used by | |
3586 | -.IR exportfs (8) | |
3587 | +contains a table of local physical file systems on an NFS server | |
3588 | +that are accessible to NFS clients. | |
3589 | +The contents of the file are maintained by the server's system | |
3590 | +administrator. | |
3591 | +.PP | |
3592 | +Each file system in this table has a list of options and an | |
3593 | +access control list. | |
3594 | +The table is used by | |
3595 | +.BR exportfs (8) | |
3596 | to give information to | |
3597 | -.IR mountd (8) | |
3598 | -and to the kernel based NFS file server daemon | |
3599 | -.IR nfsd (8). | |
3600 | +.BR mountd (8). | |
3601 | .PP | |
3602 | The file format is similar to the SunOS | |
3603 | .I exports | |
3604 | @@ -34,7 +38,9 @@ double quotes. You can also specify spaces or other unusual character in | |
3605 | the export name using a backslash followed by the character code as three | |
3606 | octal digits. | |
3607 | .PP | |
3608 | -To apply changes to this file, run exportfs \-ra or restart the NFS server. | |
3609 | +To apply changes to this file, run | |
3610 | +.BR exportfs \-ra | |
3611 | +or restart the NFS server. | |
3612 | .PP | |
3613 | .SS Machine Name Formats | |
3614 | NFS clients may be specified in a number of ways: | |
3615 | @@ -61,9 +67,10 @@ simultaneously. This is done by specifying an IP address and netmask pair | |
3616 | as | |
3617 | .IR address/netmask | |
3618 | where the netmask can be specified in dotted-decimal format, or as a | |
3619 | -contiguous mask length (for example, either `/255.255.252.0' or `/22' appended | |
3620 | -to the network base address result in identical subnetworks with 10 bits of | |
3621 | -host). Wildcard characters generally do not work on IP addresses, though they | |
3622 | +contiguous mask length. | |
3623 | +For example, either `/255.255.252.0' or `/22' appended | |
3624 | +to the network base IPv4 address results in identical subnetworks with 10 bits of | |
3625 | +host. Wildcard characters generally do not work on IP addresses, though they | |
3626 | may work by accident when reverse DNS lookups fail. | |
3627 | '''.TP | |
3628 | '''.B =public | |
3629 | @@ -106,7 +113,7 @@ preceding sec= option. The only options that are permitted to vary in | |
3630 | this way are ro, rw, no_root_squash, root_squash, and all_squash. | |
3631 | .PP | |
3632 | .SS General Options | |
3633 | -.IR exportfs | |
3634 | +.BR exportfs | |
3635 | understands the following export options: | |
3636 | .TP | |
3637 | .IR secure "\*d | |
3638 | @@ -144,7 +151,8 @@ default. In all releases after 1.0.0, | |
3639 | is the default, and | |
3640 | .I async | |
3641 | must be explicitly requested if needed. | |
3642 | -To help make system administrators aware of this change, 'exportfs' | |
3643 | +To help make system administrators aware of this change, | |
3644 | +.B exportfs | |
3645 | will issue a warning if neither | |
3646 | .I sync | |
3647 | nor | |
3648 | @@ -188,7 +196,7 @@ The | |
3649 | option is currently only effective on | |
3650 | .I "single host | |
3651 | exports. It does not work reliably with netgroup, subnet, or wildcard | |
3652 | -exports. | |
3653 | +exports. | |
3654 | ||
3655 | This option can be very useful in some situations, but it should be | |
3656 | used with due care, and only after confirming that the client system | |
3657 | @@ -246,7 +254,7 @@ If you genuinely require subtree checking, you should explicitly put | |
3658 | that option in the | |
3659 | .B exports | |
3660 | file. If you put neither option, | |
3661 | -.I exportfs | |
3662 | +.B exportfs | |
3663 | will warn you that the change is pending. | |
3664 | ||
3665 | .TP | |
3666 | @@ -272,7 +280,9 @@ or | |
3667 | .TP | |
3668 | .IR no_acl | |
3669 | On some specially patched kernels, and when exporting filesystems that | |
3670 | -support ACLs, this option tells nfsd not to reveal ACLs to clients, so | |
3671 | +support ACLs, this option tells | |
3672 | +.B nfsd | |
3673 | +not to reveal ACLs to clients, so | |
3674 | they will see only a subset of actual permissions on the given file | |
3675 | system. This option is safe for filesystems used by NFSv2 clients and | |
3676 | old NFSv3 clients that perform access decisions locally. Current | |
3677 | @@ -381,7 +391,7 @@ of the filesystem must be handled elsewhere.) | |
3678 | ||
3679 | .SS User ID Mapping | |
3680 | .PP | |
3681 | -.I nfsd | |
3682 | +.B nfsd | |
3683 | bases its access control to files on the server machine on the uid and | |
3684 | gid provided in each NFS RPC request. The normal behavior a user would | |
3685 | expect is that she can access her files on the server just as she would | |
3686 | @@ -399,19 +409,19 @@ and can be turned off with | |
3687 | .IR no_root_squash . | |
3688 | .PP | |
3689 | By default, | |
3690 | -'''.I nfsd | |
3691 | +'''.B nfsd | |
3692 | '''tries to obtain the anonymous uid and gid by looking up user | |
3693 | '''.I nobody | |
3694 | '''in the password file at startup time. If it isn't found, a uid and gid | |
3695 | -.I exportfs | |
3696 | +.B exportfs | |
3697 | chooses a uid and gid | |
3698 | of 65534 for squashed access. These values can also be overridden by | |
3699 | the | |
3700 | .IR anonuid " and " anongid | |
3701 | options. | |
3702 | '''.PP | |
3703 | -'''In addition to this, | |
3704 | -'''.I nfsd | |
3705 | +'''In addition to this, | |
3706 | +'''.B nfsd | |
3707 | '''lets you specify arbitrary uids and gids that should be mapped to user | |
3708 | '''nobody as well. | |
3709 | Finally, you can map all user requests to the | |
3710 | @@ -424,7 +434,7 @@ Here's the complete list of mapping options: | |
3711 | Map requests from uid/gid 0 to the anonymous uid/gid. Note that this does | |
3712 | not apply to any other uids or gids that might be equally sensitive, such as | |
3713 | user | |
3714 | -.IR bin | |
3715 | +.IR bin | |
3716 | or group | |
3717 | .IR staff . | |
3718 | .TP | |
3719 | @@ -434,7 +444,7 @@ Turn off root squashing. This option is mainly useful for diskless clients. | |
3720 | .IR all_squash | |
3721 | Map all uids and gids to the anonymous user. Useful for NFS-exported | |
3722 | public FTP directories, news spool directories, etc. The opposite option | |
3723 | -is | |
3724 | +is | |
3725 | .IR no_all_squash , | |
3726 | which is the default setting. | |
3727 | .TP | |
3728 | @@ -468,7 +478,7 @@ and netgroups (this is the entry `@trusted'). The fourth line shows the | |
3729 | entry for the PC/NFS client discussed above. Line 5 exports the | |
3730 | public FTP directory to every host in the world, executing all requests | |
3731 | under the nobody account. The | |
3732 | -.I insecure | |
3733 | +.I insecure | |
3734 | option in this entry also allows clients with NFS implementations that | |
3735 | don't use a reserved port for NFS. | |
3736 | The sixth line exports a directory read-write to the machine 'server' | |
3737 | @@ -478,15 +488,15 @@ all three mounts with the `sync' option enabled. | |
3738 | '''access to the private directory. | |
3739 | '''.SH CAVEATS | |
3740 | '''Unlike other NFS server implementations, this | |
3741 | -'''.I nfsd | |
3742 | +'''.B nfsd | |
3743 | '''allows you to export both a directory and a subdirectory thereof to | |
3744 | -'''the same host, for instance | |
3745 | +'''the same host, for instance | |
3746 | '''.IR /usr " and " /usr/X11R6 . | |
3747 | '''In this case, the mount options of the most specific entry apply. For | |
3748 | -'''instance, when a user on the client host accesses a file in | |
3749 | +'''instance, when a user on the client host accesses a file in | |
3750 | '''.IR /usr/X11R6 , | |
3751 | -'''the mount options given in the | |
3752 | -'''.I /usr/X11R6 | |
3753 | +'''the mount options given in the | |
3754 | +'''.I /usr/X11R6 | |
3755 | '''entry apply. This is also true when the latter is a wildcard or netgroup | |
3756 | '''entry. | |
3757 | .SH FILES | |
3758 | @@ -499,7 +509,15 @@ all three mounts with the `sync' option enabled. | |
3759 | .BR showmount (8). | |
3760 | '''.SH DIAGNOSTICS | |
3761 | '''An error parsing the file is reported using syslogd(8) as level NOTICE from | |
3762 | -'''a DAEMON whenever nfsd(8) or mountd(8) is started up. Any unknown | |
3763 | +'''a DAEMON whenever | |
3764 | +'''.BR nfsd (8) | |
3765 | +'''or | |
3766 | +'''.BR mountd (8) | |
3767 | +'''is started up. Any unknown | |
3768 | '''host is reported at that time, but often not all hosts are not yet known | |
3769 | -'''to named(8) at boot time, thus as hosts are found they are reported | |
3770 | -'''with the same syslogd(8) parameters. | |
3771 | +'''to | |
3772 | +'''.BR named (8) | |
3773 | +'''at boot time, thus as hosts are found they are reported | |
3774 | +'''with the same | |
3775 | +'''.BR syslogd (8) | |
3776 | +'''parameters. | |
3777 | diff --git a/utils/gssd/context.h b/utils/gssd/context.h | |
3778 | index be47f9c..c9cb0bd 100644 | |
3779 | --- a/utils/gssd/context.h | |
3780 | +++ b/utils/gssd/context.h | |
3781 | @@ -1,5 +1,5 @@ | |
3782 | /* | |
3783 | - Copyright (c) 2004 The Regents of the University of Michigan. | |
3784 | + Copyright (c) 2004,2008 The Regents of the University of Michigan. | |
3785 | All rights reserved. | |
3786 | ||
3787 | Redistribution and use in source and binary forms, with or without | |
3788 | @@ -36,6 +36,10 @@ | |
3789 | /* Hopefully big enough to hold any serialized context */ | |
3790 | #define MAX_CTX_LEN 4096 | |
3791 | ||
3792 | +/* New context format flag values */ | |
3793 | +#define KRB5_CTX_FLAG_INITIATOR 0x00000001 | |
3794 | +#define KRB5_CTX_FLAG_CFX 0x00000002 | |
3795 | +#define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004 | |
3796 | ||
3797 | int serialize_context_for_kernel(gss_ctx_id_t ctx, gss_buffer_desc *buf, | |
3798 | gss_OID mech, int32_t *endtime); | |
3799 | diff --git a/utils/gssd/context_lucid.c b/utils/gssd/context_lucid.c | |
3800 | index 4a682ae..b8d4734 100644 | |
3801 | --- a/utils/gssd/context_lucid.c | |
3802 | +++ b/utils/gssd/context_lucid.c | |
3803 | @@ -42,6 +42,7 @@ | |
3804 | #include <stdio.h> | |
3805 | #include <syslog.h> | |
3806 | #include <string.h> | |
3807 | +#include <errno.h> | |
3808 | ||
3809 | #include <gssapi/gssapi_krb5.h> | |
3810 | ||
3811 | @@ -76,7 +77,7 @@ prepare_krb5_rfc1964_buffer(gss_krb5_lucid_context_v1_t *lctx, | |
3812 | unsigned char fakeseed[FAKESEED_SIZE]; | |
3813 | uint32_t word_send_seq; | |
3814 | gss_krb5_lucid_key_t enc_key; | |
3815 | - int i; | |
3816 | + uint32_t i; | |
3817 | char *skd, *dkd; | |
3818 | gss_buffer_desc fakeoid; | |
3819 | ||
3820 | @@ -119,15 +120,13 @@ prepare_krb5_rfc1964_buffer(gss_krb5_lucid_context_v1_t *lctx, | |
3821 | * Note that the rfc1964 version only supports DES enctypes. | |
3822 | */ | |
3823 | if (lctx->rfc1964_kd.ctx_key.type != 4) { | |
3824 | - printerr(1, "prepare_krb5_rfc1964_buffer: " | |
3825 | - "overriding heimdal keytype (%d => %d)\n", | |
3826 | - lctx->rfc1964_kd.ctx_key.type, 4); | |
3827 | + printerr(2, "%s: overriding heimdal keytype (%d => %d)\n", | |
3828 | + __FUNCTION__, lctx->rfc1964_kd.ctx_key.type, 4); | |
3829 | lctx->rfc1964_kd.ctx_key.type = 4; | |
3830 | } | |
3831 | #endif | |
3832 | - printerr(2, "prepare_krb5_rfc1964_buffer: serializing keys with " | |
3833 | - "enctype %d and length %d\n", | |
3834 | - lctx->rfc1964_kd.ctx_key.type, | |
3835 | + printerr(2, "%s: serializing keys with enctype %d and length %d\n", | |
3836 | + __FUNCTION__, lctx->rfc1964_kd.ctx_key.type, | |
3837 | lctx->rfc1964_kd.ctx_key.length); | |
3838 | ||
3839 | /* derive the encryption key and copy it into buffer */ | |
3840 | @@ -158,11 +157,102 @@ out_err: | |
3841 | return -1; | |
3842 | } | |
3843 | ||
3844 | +/* Flags for version 2 context flags */ | |
3845 | +#define KRB5_CTX_FLAG_INITIATOR 0x00000001 | |
3846 | +#define KRB5_CTX_FLAG_CFX 0x00000002 | |
3847 | +#define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004 | |
3848 | + | |
3849 | +/* | |
3850 | + * Prepare a new-style buffer, as defined in rfc4121 (a.k.a. cfx), | |
3851 | + * to send to the kernel for newer encryption types -- or for DES3. | |
3852 | + * | |
3853 | + * The new format is: | |
3854 | + * | |
3855 | + * u32 flags; | |
3856 | + * #define KRB5_CTX_FLAG_INITIATOR 0x00000001 | |
3857 | + * #define KRB5_CTX_FLAG_CFX 0x00000002 | |
3858 | + * #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004 | |
3859 | + * s32 endtime; | |
3860 | + * u64 seq_send; | |
3861 | + * u32 enctype; ( encrption type of key ) | |
3862 | + * raw key; ( raw key bytes (kernel will derive)) | |
3863 | + * | |
3864 | + */ | |
3865 | static int | |
3866 | -prepare_krb5_rfc_cfx_buffer(gss_krb5_lucid_context_v1_t *lctx, | |
3867 | +prepare_krb5_rfc4121_buffer(gss_krb5_lucid_context_v1_t *lctx, | |
3868 | gss_buffer_desc *buf, int32_t *endtime) | |
3869 | { | |
3870 | - printerr(0, "ERROR: prepare_krb5_rfc_cfx_buffer: not implemented\n"); | |
3871 | + char *p, *end; | |
3872 | + uint32_t v2_flags = 0; | |
3873 | + uint32_t enctype; | |
3874 | + uint32_t keysize; | |
3875 | + | |
3876 | + if (!(buf->value = calloc(1, MAX_CTX_LEN))) | |
3877 | + goto out_err; | |
3878 | + p = buf->value; | |
3879 | + end = buf->value + MAX_CTX_LEN; | |
3880 | + | |
3881 | + /* Version 2 */ | |
3882 | + if (lctx->initiate) | |
3883 | + v2_flags |= KRB5_CTX_FLAG_INITIATOR; | |
3884 | + if (lctx->protocol != 0) | |
3885 | + v2_flags |= KRB5_CTX_FLAG_CFX; | |
3886 | + if (lctx->protocol != 0 && lctx->cfx_kd.have_acceptor_subkey == 1) | |
3887 | + v2_flags |= KRB5_CTX_FLAG_ACCEPTOR_SUBKEY; | |
3888 | + | |
3889 | + if (WRITE_BYTES(&p, end, v2_flags)) goto out_err; | |
3890 | + if (WRITE_BYTES(&p, end, lctx->endtime)) goto out_err; | |
3891 | + if (endtime) | |
3892 | + *endtime = lctx->endtime; | |
3893 | + if (WRITE_BYTES(&p, end, lctx->send_seq)) goto out_err; | |
3894 | + | |
3895 | + /* Protocol 0 here implies DES3 or RC4 */ | |
3896 | + printerr(2, "%s: protocol %d\n", __FUNCTION__, lctx->protocol); | |
3897 | + if (lctx->protocol == 0) { | |
3898 | + enctype = lctx->rfc1964_kd.ctx_key.type; | |
3899 | + keysize = lctx->rfc1964_kd.ctx_key.length; | |
3900 | + } else { | |
3901 | + if (lctx->cfx_kd.have_acceptor_subkey) { | |
3902 | + enctype = lctx->cfx_kd.acceptor_subkey.type; | |
3903 | + keysize = lctx->cfx_kd.acceptor_subkey.length; | |
3904 | + } else { | |
3905 | + enctype = lctx->cfx_kd.ctx_key.type; | |
3906 | + keysize = lctx->cfx_kd.ctx_key.length; | |
3907 | + } | |
3908 | + } | |
3909 | + printerr(2, "%s: serializing key with enctype %d and size %d\n", | |
3910 | + __FUNCTION__, enctype, keysize); | |
3911 | + | |
3912 | + if (WRITE_BYTES(&p, end, enctype)) goto out_err; | |
3913 | + | |
3914 | + if (lctx->protocol == 0) { | |
3915 | + if (write_bytes(&p, end, lctx->rfc1964_kd.ctx_key.data, | |
3916 | + lctx->rfc1964_kd.ctx_key.length)) | |
3917 | + goto out_err; | |
3918 | + } else { | |
3919 | + if (lctx->cfx_kd.have_acceptor_subkey) { | |
3920 | + if (write_bytes(&p, end, | |
3921 | + lctx->cfx_kd.acceptor_subkey.data, | |
3922 | + lctx->cfx_kd.acceptor_subkey.length)) | |
3923 | + goto out_err; | |
3924 | + } else { | |
3925 | + if (write_bytes(&p, end, lctx->cfx_kd.ctx_key.data, | |
3926 | + lctx->cfx_kd.ctx_key.length)) | |
3927 | + goto out_err; | |
3928 | + } | |
3929 | + } | |
3930 | + | |
3931 | + buf->length = p - (char *)buf->value; | |
3932 | + return 0; | |
3933 | + | |
3934 | +out_err: | |
3935 | + printerr(0, "ERROR: %s: failed serializing krb5 context for kernel\n", | |
3936 | + __FUNCTION__); | |
3937 | + if (buf->value) { | |
3938 | + free(buf->value); | |
3939 | + buf->value = NULL; | |
3940 | + } | |
3941 | + buf->length = 0; | |
3942 | return -1; | |
3943 | } | |
3944 | ||
3945 | @@ -176,7 +266,7 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime) | |
3946 | gss_krb5_lucid_context_v1_t *lctx = 0; | |
3947 | int retcode = 0; | |
3948 | ||
3949 | - printerr(2, "DEBUG: serialize_krb5_ctx: lucid version!\n"); | |
3950 | + printerr(2, "DEBUG: %s: lucid version!\n", __FUNCTION__); | |
3951 | maj_stat = gss_export_lucid_sec_context(&min_stat, &ctx, | |
3952 | 1, &return_ctx); | |
3953 | if (maj_stat != GSS_S_COMPLETE) { | |
3954 | @@ -198,11 +288,20 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime) | |
3955 | break; | |
3956 | } | |
3957 | ||
3958 | - /* Now lctx points to a lucid context that we can send down to kernel */ | |
3959 | - if (lctx->protocol == 0) | |
3960 | + /* | |
3961 | + * Now lctx points to a lucid context that we can send down to kernel | |
3962 | + * | |
3963 | + * Note: we send down different information to the kernel depending | |
3964 | + * on the protocol version and the enctyption type. | |
3965 | + * For protocol version 0 with all enctypes besides DES3, we use | |
3966 | + * the original format. For protocol version != 0 or DES3, we | |
3967 | + * send down the new style information. | |
3968 | + */ | |
3969 | + | |
3970 | + if (lctx->protocol == 0 && lctx->rfc1964_kd.ctx_key.type <= 4) | |
3971 | retcode = prepare_krb5_rfc1964_buffer(lctx, buf, endtime); | |
3972 | else | |
3973 | - retcode = prepare_krb5_rfc_cfx_buffer(lctx, buf, endtime); | |
3974 | + retcode = prepare_krb5_rfc4121_buffer(lctx, buf, endtime); | |
3975 | ||
3976 | maj_stat = gss_free_lucid_sec_context(&min_stat, ctx, return_ctx); | |
3977 | if (maj_stat != GSS_S_COMPLETE) { | |
3978 | @@ -212,8 +311,8 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime) | |
3979 | } | |
3980 | ||
3981 | if (retcode) { | |
3982 | - printerr(1, "serialize_krb5_ctx: prepare_krb5_*_buffer " | |
3983 | - "failed (retcode = %d)\n", retcode); | |
3984 | + printerr(1, "%s: prepare_krb5_*_buffer failed (retcode = %d)\n", | |
3985 | + __FUNCTION__, retcode); | |
3986 | goto out_err; | |
3987 | } | |
3988 | ||
3989 | @@ -223,4 +322,7 @@ out_err: | |
3990 | printerr(0, "ERROR: failed serializing krb5 context for kernel\n"); | |
3991 | return -1; | |
3992 | } | |
3993 | + | |
3994 | + | |
3995 | + | |
3996 | #endif /* HAVE_LUCID_CONTEXT_SUPPORT */ | |
3997 | diff --git a/utils/gssd/context_mit.c b/utils/gssd/context_mit.c | |
3998 | index 709a903..e6db9cb 100644 | |
3999 | --- a/utils/gssd/context_mit.c | |
4000 | +++ b/utils/gssd/context_mit.c | |
4001 | @@ -1,5 +1,5 @@ | |
4002 | /* | |
4003 | - Copyright (c) 2004 The Regents of the University of Michigan. | |
4004 | + Copyright (c) 2004-2006 The Regents of the University of Michigan. | |
4005 | All rights reserved. | |
4006 | ||
4007 | Redistribution and use in source and binary forms, with or without | |
4008 | @@ -38,6 +38,7 @@ | |
4009 | #include <stdio.h> | |
4010 | #include <syslog.h> | |
4011 | #include <string.h> | |
4012 | +#include <errno.h> | |
4013 | #include <gssapi/gssapi.h> | |
4014 | #include <rpc/rpc.h> | |
4015 | #include <rpc/auth_gss.h> | |
4016 | @@ -52,8 +53,7 @@ | |
4017 | /* XXX argggg, there's gotta be a better way than just duplicating this | |
4018 | * whole struct. Unfortunately, this is in a "private" header file, | |
4019 | * so this is our best choice at this point :-/ | |
4020 | - * | |
4021 | - * XXX Does this match the Heimdal definition? */ | |
4022 | + */ | |
4023 | ||
4024 | typedef struct _krb5_gss_ctx_id_rec { | |
4025 | unsigned int initiate : 1; /* nonzero if initiating, zero if accepting */ | |
4026 | @@ -156,50 +156,122 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime) | |
4027 | { | |
4028 | krb5_gss_ctx_id_t kctx = ((gss_union_ctx_id_t)ctx)->internal_ctx_id; | |
4029 | char *p, *end; | |
4030 | - static int constant_one = 1; | |
4031 | static int constant_zero = 0; | |
4032 | + static int constant_one = 1; | |
4033 | + static int constant_two = 2; | |
4034 | uint32_t word_seq_send; | |
4035 | + u_int64_t seq_send_64bit; | |
4036 | + uint32_t v2_flags = 0; | |
4037 | ||
4038 | if (!(buf->value = calloc(1, MAX_CTX_LEN))) | |
4039 | goto out_err; | |
4040 | p = buf->value; | |
4041 | end = buf->value + MAX_CTX_LEN; | |
4042 | ||
4043 | - if (kctx->initiate) { | |
4044 | - if (WRITE_BYTES(&p, end, constant_one)) goto out_err; | |
4045 | - } | |
4046 | - else { | |
4047 | - if (WRITE_BYTES(&p, end, constant_zero)) goto out_err; | |
4048 | - } | |
4049 | - if (kctx->seed_init) { | |
4050 | - if (WRITE_BYTES(&p, end, constant_one)) goto out_err; | |
4051 | - } | |
4052 | - else { | |
4053 | - if (WRITE_BYTES(&p, end, constant_zero)) goto out_err; | |
4054 | - } | |
4055 | - if (write_bytes(&p, end, &kctx->seed, sizeof(kctx->seed))) | |
4056 | + switch (kctx->enc->enctype) { | |
4057 | + case ENCTYPE_DES_CBC_CRC: | |
4058 | + case ENCTYPE_DES_CBC_MD4: | |
4059 | + case ENCTYPE_DES_CBC_MD5: | |
4060 | + case ENCTYPE_DES_CBC_RAW: | |
4061 | + /* Old format of context to the kernel */ | |
4062 | + if (kctx->initiate) { | |
4063 | + if (WRITE_BYTES(&p, end, constant_one)) goto out_err; | |
4064 | + } | |
4065 | + else { | |
4066 | + if (WRITE_BYTES(&p, end, constant_zero)) goto out_err; | |
4067 | + } | |
4068 | + if (kctx->seed_init) { | |
4069 | + if (WRITE_BYTES(&p, end, constant_one)) goto out_err; | |
4070 | + } | |
4071 | + else { | |
4072 | + if (WRITE_BYTES(&p, end, constant_zero)) goto out_err; | |
4073 | + } | |
4074 | + if (write_bytes(&p, end, &kctx->seed, sizeof(kctx->seed))) | |
4075 | + goto out_err; | |
4076 | + if (WRITE_BYTES(&p, end, kctx->signalg)) goto out_err; | |
4077 | + if (WRITE_BYTES(&p, end, kctx->sealalg)) goto out_err; | |
4078 | + if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err; | |
4079 | + if (endtime) | |
4080 | + *endtime = kctx->endtime; | |
4081 | + word_seq_send = kctx->seq_send; | |
4082 | + if (WRITE_BYTES(&p, end, word_seq_send)) goto out_err; | |
4083 | + if (write_oid(&p, end, kctx->mech_used)) goto out_err; | |
4084 | + | |
4085 | + printerr(2, "serialize_krb5_ctx: serializing keys with " | |
4086 | + "enctype %d and length %d\n", | |
4087 | + kctx->enc->enctype, kctx->enc->length); | |
4088 | + | |
4089 | + if (write_keyblock(&p, end, kctx->enc)) goto out_err; | |
4090 | + if (write_keyblock(&p, end, kctx->seq)) goto out_err; | |
4091 | + break; | |
4092 | + case ENCTYPE_DES3_CBC_RAW: | |
4093 | + case ENCTYPE_DES3_CBC_SHA1: | |
4094 | + case ENCTYPE_ARCFOUR_HMAC: | |
4095 | + case ENCTYPE_ARCFOUR_HMAC_EXP: | |
4096 | + case ENCTYPE_AES128_CTS_HMAC_SHA1_96: | |
4097 | + case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | |
4098 | + /* New format of context to the kernel */ | |
4099 | + /* u32 flags; | |
4100 | + * #define KRB5_CTX_FLAG_INITIATOR 0x00000001 | |
4101 | + * #define KRB5_CTX_FLAG_CFX 0x00000002 | |
4102 | + * #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004 | |
4103 | + * s32 endtime; | |
4104 | + * u64 seq_send; | |
4105 | + * u32 enctype; | |
4106 | + * rawkey data | |
4107 | + */ | |
4108 | + | |
4109 | + if (kctx->initiate) | |
4110 | + v2_flags |= KRB5_CTX_FLAG_INITIATOR; | |
4111 | + if (kctx->proto == 1) | |
4112 | + v2_flags |= KRB5_CTX_FLAG_CFX; | |
4113 | + if (kctx->have_acceptor_subkey) | |
4114 | + v2_flags |= KRB5_CTX_FLAG_ACCEPTOR_SUBKEY; | |
4115 | + if (WRITE_BYTES(&p, end, v2_flags)) goto out_err; | |
4116 | + if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err; | |
4117 | + | |
4118 | + seq_send_64bit = kctx->seq_send; | |
4119 | + if (WRITE_BYTES(&p, end, seq_send_64bit)) goto out_err; | |
4120 | + | |
4121 | + if (kctx->have_acceptor_subkey) { | |
4122 | + if (WRITE_BYTES(&p, end, kctx->acceptor_subkey->enctype)) | |
4123 | + goto out_err; | |
4124 | + printerr(2, "serialize_krb5_ctx: serializing subkey " | |
4125 | + "with enctype %d and size %d\n", | |
4126 | + kctx->acceptor_subkey->enctype, | |
4127 | + kctx->acceptor_subkey->length); | |
4128 | + | |
4129 | + if (write_bytes(&p, end, | |
4130 | + kctx->acceptor_subkey->contents, | |
4131 | + kctx->acceptor_subkey->length)) | |
4132 | + goto out_err; | |
4133 | + } else { | |
4134 | + if (WRITE_BYTES(&p, end, kctx->enc->enctype)) | |
4135 | + goto out_err; | |
4136 | + printerr(2, "serialize_krb5_ctx: serializing key " | |
4137 | + "with enctype %d and size %d\n", | |
4138 | + kctx->enc->enctype, kctx->enc->length); | |
4139 | + | |
4140 | + if (write_bytes(&p, end, kctx->enc->contents, | |
4141 | + kctx->enc->length)) | |
4142 | + goto out_err; | |
4143 | + } | |
4144 | + break; | |
4145 | + default: | |
4146 | + printerr(0, "ERROR: serialize_krb5_ctx: unsupported encryption " | |
4147 | + "algorithm %d\n", kctx->enc->enctype); | |
4148 | goto out_err; | |
4149 | - if (WRITE_BYTES(&p, end, kctx->signalg)) goto out_err; | |
4150 | - if (WRITE_BYTES(&p, end, kctx->sealalg)) goto out_err; | |
4151 | - if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err; | |
4152 | - if (endtime) | |
4153 | - *endtime = kctx->endtime; | |
4154 | - word_seq_send = kctx->seq_send; | |
4155 | - if (WRITE_BYTES(&p, end, word_seq_send)) goto out_err; | |
4156 | - if (write_oid(&p, end, kctx->mech_used)) goto out_err; | |
4157 | - | |
4158 | - printerr(2, "serialize_krb5_ctx: serializing keys with " | |
4159 | - "enctype %d and length %d\n", | |
4160 | - kctx->enc->enctype, kctx->enc->length); | |
4161 | - | |
4162 | - if (write_keyblock(&p, end, kctx->enc)) goto out_err; | |
4163 | - if (write_keyblock(&p, end, kctx->seq)) goto out_err; | |
4164 | + } | |
4165 | ||
4166 | buf->length = p - (char *)buf->value; | |
4167 | return 0; | |
4168 | + | |
4169 | out_err: | |
4170 | printerr(0, "ERROR: failed serializing krb5 context for kernel\n"); | |
4171 | - if (buf->value) free(buf->value); | |
4172 | + if (buf->value) { | |
4173 | + free(buf->value); | |
4174 | + } | |
4175 | + buf->value = NULL; | |
4176 | buf->length = 0; | |
4177 | return -1; | |
4178 | } | |
4179 | diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c | |
4180 | index bd37a5f..ccadb07 100644 | |
4181 | --- a/utils/gssd/gssd.c | |
4182 | +++ b/utils/gssd/gssd.c | |
4183 | @@ -78,7 +78,7 @@ void | |
4184 | sig_hup(int signal) | |
4185 | { | |
4186 | /* don't exit on SIGHUP */ | |
4187 | - printerr(1, "Received SIGHUP... Ignoring.\n"); | |
4188 | + printerr(1, "Received SIGHUP(%d)... Ignoring.\n", signal); | |
4189 | return; | |
4190 | } | |
4191 | ||
4192 | diff --git a/utils/gssd/gssd_main_loop.c b/utils/gssd/gssd_main_loop.c | |
4193 | index f1a68d3..b06c223 100644 | |
4194 | --- a/utils/gssd/gssd_main_loop.c | |
4195 | +++ b/utils/gssd/gssd_main_loop.c | |
4196 | @@ -63,6 +63,8 @@ static volatile int dir_changed = 1; | |
4197 | ||
4198 | static void dir_notify_handler(int sig, siginfo_t *si, void *data) | |
4199 | { | |
4200 | + printerr(2, "dir_notify_handler: sig %d si %p data %p\n", sig, si, data); | |
4201 | + | |
4202 | dir_changed = 1; | |
4203 | } | |
4204 | ||
4205 | diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c | |
4206 | index be4fb11..c301d46 100644 | |
4207 | --- a/utils/gssd/gssd_proc.c | |
4208 | +++ b/utils/gssd/gssd_proc.c | |
4209 | @@ -600,6 +600,67 @@ update_client_list(void) | |
4210 | return retval; | |
4211 | } | |
4212 | ||
4213 | +/* Encryption types supported by the kernel rpcsec_gss code */ | |
4214 | +int num_krb5_enctypes = 0; | |
4215 | +krb5_enctype *krb5_enctypes = NULL; | |
4216 | + | |
4217 | +/* | |
4218 | + * Parse the supported encryption type information | |
4219 | + */ | |
4220 | +static int | |
4221 | +parse_enctypes(char *enctypes) | |
4222 | +{ | |
4223 | + int n = 0; | |
4224 | + char *curr, *comma; | |
4225 | + int i; | |
4226 | + static char *cached_types; | |
4227 | + | |
4228 | + if (cached_types && strcmp(cached_types, enctypes) == 0) | |
4229 | + return 0; | |
4230 | + free(cached_types); | |
4231 | + | |
4232 | + if (krb5_enctypes != NULL) { | |
4233 | + free(krb5_enctypes); | |
4234 | + krb5_enctypes = NULL; | |
4235 | + num_krb5_enctypes = 0; | |
4236 | + } | |
4237 | + | |
4238 | + /* count the number of commas */ | |
4239 | + for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) { | |
4240 | + comma = strchr(curr, ','); | |
4241 | + if (comma != NULL) | |
4242 | + n++; | |
4243 | + else | |
4244 | + break; | |
4245 | + } | |
4246 | + /* If no more commas and we're not at the end, there's one more value */ | |
4247 | + if (*curr != '\0') | |
4248 | + n++; | |
4249 | + | |
4250 | + /* Empty string, return an error */ | |
4251 | + if (n == 0) | |
4252 | + return ENOENT; | |
4253 | + | |
4254 | + /* Allocate space for enctypes array */ | |
4255 | + if ((krb5_enctypes = (int *) calloc(n, sizeof(int))) == NULL) { | |
4256 | + return ENOMEM; | |
4257 | + } | |
4258 | + | |
4259 | + /* Now parse each value into the array */ | |
4260 | + for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) { | |
4261 | + krb5_enctypes[i++] = atoi(curr); | |
4262 | + comma = strchr(curr, ','); | |
4263 | + if (comma == NULL) | |
4264 | + break; | |
4265 | + } | |
4266 | + | |
4267 | + num_krb5_enctypes = n; | |
4268 | + if ((cached_types = malloc(strlen(enctypes)+1))) | |
4269 | + strcpy(cached_types, enctypes); | |
4270 | + | |
4271 | + return 0; | |
4272 | +} | |
4273 | + | |
4274 | static int | |
4275 | do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd, | |
4276 | gss_buffer_desc *context_token) | |
4277 | @@ -798,7 +859,7 @@ int create_auth_rpc_client(struct clnt_info *clp, | |
4278 | * Do this before creating rpc connection since we won't need | |
4279 | * rpc connection if it fails! | |
4280 | */ | |
4281 | - if (limit_krb5_enctypes(&sec, uid)) { | |
4282 | + if (limit_krb5_enctypes(&sec)) { | |
4283 | printerr(1, "WARNING: Failed while limiting krb5 " | |
4284 | "encryption types for user with uid %d\n", | |
4285 | uid); | |
4286 | @@ -875,7 +936,7 @@ int create_auth_rpc_client(struct clnt_info *clp, | |
4287 | if (sec.cred != GSS_C_NO_CREDENTIAL) | |
4288 | gss_release_cred(&min_stat, &sec.cred); | |
4289 | /* Restore euid to original value */ | |
4290 | - if ((save_uid != -1) && (setfsuid(save_uid) != uid)) { | |
4291 | + if (((int)save_uid != -1) && (setfsuid(save_uid) != (int)uid)) { | |
4292 | printerr(0, "WARNING: Failed to restore fsuid" | |
4293 | " to uid %d from %d\n", save_uid, uid); | |
4294 | } | |
4295 | @@ -1100,7 +1161,7 @@ handle_krb5_upcall(struct clnt_info *clp) | |
4296 | { | |
4297 | uid_t uid; | |
4298 | ||
4299 | - if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) { | |
4300 | + if (read(clp->krb5_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) { | |
4301 | printerr(0, "WARNING: failed reading uid from krb5 " | |
4302 | "upcall pipe: %s\n", strerror(errno)); | |
4303 | return; | |
4304 | @@ -1114,7 +1175,7 @@ handle_spkm3_upcall(struct clnt_info *clp) | |
4305 | { | |
4306 | uid_t uid; | |
4307 | ||
4308 | - if (read(clp->spkm3_fd, &uid, sizeof(uid)) < sizeof(uid)) { | |
4309 | + if (read(clp->spkm3_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) { | |
4310 | printerr(0, "WARNING: failed reading uid from spkm3 " | |
4311 | "upcall pipe: %s\n", strerror(errno)); | |
4312 | return; | |
4313 | @@ -1133,6 +1194,7 @@ handle_gssd_upcall(struct clnt_info *clp) | |
4314 | char *mech = NULL; | |
4315 | char *target = NULL; | |
4316 | char *service = NULL; | |
4317 | + char *enctypes = NULL; | |
4318 | ||
4319 | printerr(1, "handling gssd upcall (%s)\n", clp->dirname); | |
4320 | ||
4321 | @@ -1176,6 +1238,23 @@ handle_gssd_upcall(struct clnt_info *clp) | |
4322 | goto out; | |
4323 | } | |
4324 | ||
4325 | + /* read supported encryption types if supplied */ | |
4326 | + if ((p = strstr(lbuf, "enctypes=")) != NULL) { | |
4327 | + enctypes = malloc(lbuflen); | |
4328 | + if (!enctypes) | |
4329 | + goto out; | |
4330 | + if (sscanf(p, "enctypes=%s", enctypes) != 1) { | |
4331 | + printerr(0, "WARNING: handle_gssd_upcall: " | |
4332 | + "failed to parse target name " | |
4333 | + "in upcall string '%s'\n", lbuf); | |
4334 | + goto out; | |
4335 | + } | |
4336 | + if (parse_enctypes(enctypes) != 0) { | |
4337 | + printerr(0, "WARNING: handle_gssd_upcall: " | |
4338 | + "parsing encryption types failed: errno %d\n", errno); | |
4339 | + } | |
4340 | + } | |
4341 | + | |
4342 | /* read target name */ | |
4343 | if ((p = strstr(lbuf, "target=")) != NULL) { | |
4344 | target = malloc(lbuflen); | |
4345 | @@ -1222,6 +1301,7 @@ handle_gssd_upcall(struct clnt_info *clp) | |
4346 | out: | |
4347 | free(lbuf); | |
4348 | free(mech); | |
4349 | + free(enctypes); | |
4350 | free(target); | |
4351 | free(service); | |
4352 | return; | |
4353 | diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c | |
4354 | index 1295f57..f071600 100644 | |
4355 | --- a/utils/gssd/krb5_util.c | |
4356 | +++ b/utils/gssd/krb5_util.c | |
4357 | @@ -224,6 +224,13 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d) | |
4358 | free(namelist[i]); | |
4359 | continue; | |
4360 | } | |
4361 | + if (uid == 0 && !root_uses_machine_creds && | |
4362 | + strstr(namelist[i]->d_name, "_machine_")) { | |
4363 | + printerr(3, "CC file '%s' not available to root\n", | |
4364 | + statname); | |
4365 | + free(namelist[i]); | |
4366 | + continue; | |
4367 | + } | |
4368 | if (!query_krb5_ccache(buf, &princname, &realm)) { | |
4369 | printerr(3, "CC file '%s' is expired or corrupt\n", | |
4370 | statname); | |
4371 | @@ -292,61 +299,6 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d) | |
4372 | return err; | |
4373 | } | |
4374 | ||
4375 | - | |
4376 | -#ifdef HAVE_SET_ALLOWABLE_ENCTYPES | |
4377 | -/* | |
4378 | - * this routine obtains a credentials handle via gss_acquire_cred() | |
4379 | - * then calls gss_krb5_set_allowable_enctypes() to limit the encryption | |
4380 | - * types negotiated. | |
4381 | - * | |
4382 | - * XXX Should call some function to determine the enctypes supported | |
4383 | - * by the kernel. (Only need to do that once!) | |
4384 | - * | |
4385 | - * Returns: | |
4386 | - * 0 => all went well | |
4387 | - * -1 => there was an error | |
4388 | - */ | |
4389 | - | |
4390 | -int | |
4391 | -limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid) | |
4392 | -{ | |
4393 | - u_int maj_stat, min_stat; | |
4394 | - gss_cred_id_t credh; | |
4395 | - gss_OID_set_desc desired_mechs; | |
4396 | - krb5_enctype enctypes[] = { ENCTYPE_DES_CBC_CRC, | |
4397 | - ENCTYPE_DES_CBC_MD5, | |
4398 | - ENCTYPE_DES_CBC_MD4 }; | |
4399 | - int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]); | |
4400 | - | |
4401 | - /* We only care about getting a krb5 cred */ | |
4402 | - desired_mechs.count = 1; | |
4403 | - desired_mechs.elements = &krb5oid; | |
4404 | - | |
4405 | - maj_stat = gss_acquire_cred(&min_stat, NULL, 0, | |
4406 | - &desired_mechs, GSS_C_INITIATE, | |
4407 | - &credh, NULL, NULL); | |
4408 | - | |
4409 | - if (maj_stat != GSS_S_COMPLETE) { | |
4410 | - if (get_verbosity() > 0) | |
4411 | - pgsserr("gss_acquire_cred", | |
4412 | - maj_stat, min_stat, &krb5oid); | |
4413 | - return -1; | |
4414 | - } | |
4415 | - | |
4416 | - maj_stat = gss_set_allowable_enctypes(&min_stat, credh, &krb5oid, | |
4417 | - num_enctypes, &enctypes); | |
4418 | - if (maj_stat != GSS_S_COMPLETE) { | |
4419 | - pgsserr("gss_set_allowable_enctypes", | |
4420 | - maj_stat, min_stat, &krb5oid); | |
4421 | - gss_release_cred(&min_stat, &credh); | |
4422 | - return -1; | |
4423 | - } | |
4424 | - sec->cred = credh; | |
4425 | - | |
4426 | - return 0; | |
4427 | -} | |
4428 | -#endif /* HAVE_SET_ALLOWABLE_ENCTYPES */ | |
4429 | - | |
4430 | /* | |
4431 | * Obtain credentials via a key in the keytab given | |
4432 | * a keytab handle and a gssd_k5_kt_princ structure. | |
4433 | @@ -661,24 +613,32 @@ out: | |
4434 | * and has *any* instance (hostname), return 1. | |
4435 | * Otherwise return 0, indicating no match. | |
4436 | */ | |
4437 | +#ifdef HAVE_KRB5 | |
4438 | static int | |
4439 | -realm_and_service_match(krb5_context context, krb5_principal p, | |
4440 | - const char *realm, const char *service) | |
4441 | +realm_and_service_match(krb5_principal p, const char *realm, const char *service) | |
4442 | { | |
4443 | -#ifdef HAVE_KRB5 | |
4444 | /* Must have two components */ | |
4445 | if (p->length != 2) | |
4446 | return 0; | |
4447 | + | |
4448 | if ((strlen(realm) == p->realm.length) | |
4449 | && (strncmp(realm, p->realm.data, p->realm.length) == 0) | |
4450 | && (strlen(service) == p->data[0].length) | |
4451 | && (strncmp(service, p->data[0].data, p->data[0].length) == 0)) | |
4452 | return 1; | |
4453 | + | |
4454 | + return 0; | |
4455 | +} | |
4456 | #else | |
4457 | +static int | |
4458 | +realm_and_service_match(krb5_context context, krb5_principal p, | |
4459 | + const char *realm, const char *service) | |
4460 | +{ | |
4461 | const char *name, *inst; | |
4462 | ||
4463 | if (p->name.name_string.len != 2) | |
4464 | return 0; | |
4465 | + | |
4466 | name = krb5_principal_get_comp_string(context, p, 0); | |
4467 | inst = krb5_principal_get_comp_string(context, p, 1); | |
4468 | if (name == NULL || inst == NULL) | |
4469 | @@ -686,9 +646,10 @@ realm_and_service_match(krb5_context context, krb5_principal p, | |
4470 | if ((strcmp(realm, p->realm) == 0) | |
4471 | && (strcmp(service, name) == 0)) | |
4472 | return 1; | |
4473 | -#endif | |
4474 | + | |
4475 | return 0; | |
4476 | } | |
4477 | +#endif | |
4478 | ||
4479 | /* | |
4480 | * Search the given keytab file looking for an entry with the given | |
4481 | @@ -710,7 +671,7 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt, | |
4482 | krb5_kt_cursor cursor; | |
4483 | krb5_error_code code; | |
4484 | struct gssd_k5_kt_princ *ple; | |
4485 | - int retval = -1; | |
4486 | + int retval = -1, status; | |
4487 | char kt_name[BUFSIZ]; | |
4488 | char *pname; | |
4489 | char *k5err = NULL; | |
4490 | @@ -753,8 +714,12 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt, | |
4491 | printerr(4, "Processing keytab entry for principal '%s'\n", | |
4492 | pname); | |
4493 | /* Use the first matching keytab entry found */ | |
4494 | - if ((realm_and_service_match(context, kte->principal, realm, | |
4495 | - service))) { | |
4496 | +#ifdef HAVE_KRB5 | |
4497 | + status = realm_and_service_match(kte->principal, realm, service); | |
4498 | +#else | |
4499 | + status = realm_and_service_match(context, kte->principal, realm, service); | |
4500 | +#endif | |
4501 | + if (status) { | |
4502 | printerr(4, "We WILL use this entry (%s)\n", pname); | |
4503 | ple = get_ple_by_princ(context, kte->principal); | |
4504 | /* | |
4505 | @@ -1304,3 +1269,68 @@ gssd_k5_get_default_realm(char **def_realm) | |
4506 | ||
4507 | krb5_free_context(context); | |
4508 | } | |
4509 | + | |
4510 | +#ifdef HAVE_SET_ALLOWABLE_ENCTYPES | |
4511 | +/* | |
4512 | + * this routine obtains a credentials handle via gss_acquire_cred() | |
4513 | + * then calls gss_krb5_set_allowable_enctypes() to limit the encryption | |
4514 | + * types negotiated. | |
4515 | + * | |
4516 | + * XXX Should call some function to determine the enctypes supported | |
4517 | + * by the kernel. (Only need to do that once!) | |
4518 | + * | |
4519 | + * Returns: | |
4520 | + * 0 => all went well | |
4521 | + * -1 => there was an error | |
4522 | + */ | |
4523 | + | |
4524 | +int | |
4525 | +limit_krb5_enctypes(struct rpc_gss_sec *sec) | |
4526 | +{ | |
4527 | + u_int maj_stat, min_stat; | |
4528 | + gss_cred_id_t credh; | |
4529 | + gss_OID_set_desc desired_mechs; | |
4530 | + krb5_enctype enctypes[] = { ENCTYPE_DES_CBC_CRC, | |
4531 | + ENCTYPE_DES_CBC_MD5, | |
4532 | + ENCTYPE_DES_CBC_MD4 }; | |
4533 | + int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]); | |
4534 | + extern int num_krb5_enctypes; | |
4535 | + extern krb5_enctype *krb5_enctypes; | |
4536 | + | |
4537 | + /* We only care about getting a krb5 cred */ | |
4538 | + desired_mechs.count = 1; | |
4539 | + desired_mechs.elements = &krb5oid; | |
4540 | + | |
4541 | + maj_stat = gss_acquire_cred(&min_stat, NULL, 0, | |
4542 | + &desired_mechs, GSS_C_INITIATE, | |
4543 | + &credh, NULL, NULL); | |
4544 | + | |
4545 | + if (maj_stat != GSS_S_COMPLETE) { | |
4546 | + if (get_verbosity() > 0) | |
4547 | + pgsserr("gss_acquire_cred", | |
4548 | + maj_stat, min_stat, &krb5oid); | |
4549 | + return -1; | |
4550 | + } | |
4551 | + | |
4552 | + /* | |
4553 | + * If we failed for any reason to produce global | |
4554 | + * list of supported enctypes, use local default here. | |
4555 | + */ | |
4556 | + if (krb5_enctypes == NULL) | |
4557 | + maj_stat = gss_set_allowable_enctypes(&min_stat, credh, | |
4558 | + &krb5oid, num_enctypes, enctypes); | |
4559 | + else | |
4560 | + maj_stat = gss_set_allowable_enctypes(&min_stat, credh, | |
4561 | + &krb5oid, num_krb5_enctypes, krb5_enctypes); | |
4562 | + | |
4563 | + if (maj_stat != GSS_S_COMPLETE) { | |
4564 | + pgsserr("gss_set_allowable_enctypes", | |
4565 | + maj_stat, min_stat, &krb5oid); | |
4566 | + gss_release_cred(&min_stat, &credh); | |
4567 | + return -1; | |
4568 | + } | |
4569 | + sec->cred = credh; | |
4570 | + | |
4571 | + return 0; | |
4572 | +} | |
4573 | +#endif /* HAVE_SET_ALLOWABLE_ENCTYPES */ | |
4574 | diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h | |
4575 | index 4602cc3..b42b91e 100644 | |
4576 | --- a/utils/gssd/krb5_util.h | |
4577 | +++ b/utils/gssd/krb5_util.h | |
4578 | @@ -36,7 +36,7 @@ char *gssd_k5_err_msg(krb5_context context, krb5_error_code code); | |
4579 | void gssd_k5_get_default_realm(char **def_realm); | |
4580 | ||
4581 | #ifdef HAVE_SET_ALLOWABLE_ENCTYPES | |
4582 | -int limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid); | |
4583 | +int limit_krb5_enctypes(struct rpc_gss_sec *sec); | |
4584 | #endif | |
4585 | ||
4586 | /* | |
4587 | diff --git a/utils/gssd/svcgssd.c b/utils/gssd/svcgssd.c | |
4588 | index 729b6a6..e7375a4 100644 | |
4589 | --- a/utils/gssd/svcgssd.c | |
4590 | +++ b/utils/gssd/svcgssd.c | |
4591 | @@ -160,7 +160,7 @@ void | |
4592 | sig_hup(int signal) | |
4593 | { | |
4594 | /* don't exit on SIGHUP */ | |
4595 | - printerr(1, "Received SIGHUP... Ignoring.\n"); | |
4596 | + printerr(1, "Received SIGHUP(%d)... Ignoring.\n", signal); | |
4597 | return; | |
4598 | } | |
4599 | ||
4600 | diff --git a/utils/gssd/svcgssd_proc.c b/utils/gssd/svcgssd_proc.c | |
4601 | index f1bfbef..3894078 100644 | |
4602 | --- a/utils/gssd/svcgssd_proc.c | |
4603 | +++ b/utils/gssd/svcgssd_proc.c | |
4604 | @@ -132,7 +132,7 @@ struct gss_verifier { | |
4605 | #define RPCSEC_GSS_SEQ_WIN 5 | |
4606 | ||
4607 | static int | |
4608 | -send_response(FILE *f, gss_buffer_desc *in_handle, gss_buffer_desc *in_token, | |
4609 | +send_response(gss_buffer_desc *in_handle, gss_buffer_desc *in_token, | |
4610 | u_int32_t maj_stat, u_int32_t min_stat, | |
4611 | gss_buffer_desc *out_handle, gss_buffer_desc *out_token) | |
4612 | { | |
4613 | @@ -431,12 +431,6 @@ handle_nullreq(FILE *f) { | |
4614 | print_hexl("in_tok", in_tok.value, in_tok.length); | |
4615 | #endif | |
4616 | ||
4617 | - if (in_tok.length < 0) { | |
4618 | - printerr(0, "WARNING: handle_nullreq: " | |
4619 | - "failed parsing request\n"); | |
4620 | - goto out_err; | |
4621 | - } | |
4622 | - | |
4623 | if (in_handle.length != 0) { /* CONTINUE_INIT case */ | |
4624 | if (in_handle.length != sizeof(ctx)) { | |
4625 | printerr(0, "WARNING: handle_nullreq: " | |
4626 | @@ -498,7 +492,7 @@ handle_nullreq(FILE *f) { | |
4627 | do_svc_downcall(&out_handle, &cred, mech, &ctx_token, ctx_endtime, | |
4628 | hostbased_name); | |
4629 | continue_needed: | |
4630 | - send_response(f, &in_handle, &in_tok, maj_stat, min_stat, | |
4631 | + send_response(&in_handle, &in_tok, maj_stat, min_stat, | |
4632 | &out_handle, &out_tok); | |
4633 | out: | |
4634 | if (ctx_token.value != NULL) | |
4635 | @@ -514,7 +508,7 @@ out: | |
4636 | out_err: | |
4637 | if (ctx != GSS_C_NO_CONTEXT) | |
4638 | gss_delete_sec_context(&ignore_min_stat, &ctx, &ignore_out_tok); | |
4639 | - send_response(f, &in_handle, &in_tok, maj_stat, min_stat, | |
4640 | + send_response(&in_handle, &in_tok, maj_stat, min_stat, | |
4641 | &null_token, &null_token); | |
4642 | goto out; | |
4643 | } | |
4644 | diff --git a/utils/idmapd/atomicio.c b/utils/idmapd/atomicio.c | |
4645 | index 05e7147..1fb1ff9 100644 | |
4646 | --- a/utils/idmapd/atomicio.c | |
4647 | +++ b/utils/idmapd/atomicio.c | |
4648 | @@ -43,7 +43,8 @@ atomicio( | |
4649 | size_t n) | |
4650 | { | |
4651 | char *s = _s; | |
4652 | - ssize_t res, pos = 0; | |
4653 | + ssize_t res; | |
4654 | + size_t pos = 0; | |
4655 | ||
4656 | while (n > pos) { | |
4657 | res = (f) (fd, s + pos, n - pos); | |
4658 | diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c | |
4659 | index 573abaa..9ecab66 100644 | |
4660 | --- a/utils/idmapd/idmapd.c | |
4661 | +++ b/utils/idmapd/idmapd.c | |
4662 | @@ -117,8 +117,24 @@ struct idmap_client { | |
4663 | TAILQ_ENTRY(idmap_client) ic_next; | |
4664 | }; | |
4665 | static struct idmap_client nfsd_ic[2] = { | |
4666 | -{IC_IDNAME, "Server", "", IC_IDNAME_CHAN, -1, -1, 0}, | |
4667 | -{IC_NAMEID, "Server", "", IC_NAMEID_CHAN, -1, -1, 0}, | |
4668 | +{ | |
4669 | + .ic_which = IC_IDNAME, | |
4670 | + .ic_clid = "Server", | |
4671 | + .ic_id = "", | |
4672 | + .ic_path = IC_IDNAME_CHAN, | |
4673 | + .ic_fd = -1, | |
4674 | + .ic_dirfd = -1, | |
4675 | + .ic_scanned = 0 | |
4676 | +}, | |
4677 | +{ | |
4678 | + .ic_which = IC_NAMEID, | |
4679 | + .ic_clid = "Server", | |
4680 | + .ic_id = "", | |
4681 | + .ic_path = IC_NAMEID_CHAN, | |
4682 | + .ic_fd = -1, | |
4683 | + .ic_dirfd = -1, | |
4684 | + .ic_scanned = 0 | |
4685 | +}, | |
4686 | }; | |
4687 | ||
4688 | TAILQ_HEAD(idmap_clientq, idmap_client); | |
4689 | @@ -170,7 +186,7 @@ flush_nfsd_cache(char *path, time_t now) | |
4690 | fd = open(path, O_RDWR); | |
4691 | if (fd == -1) | |
4692 | return -1; | |
4693 | - if (write(fd, stime, strlen(stime)) != strlen(stime)) { | |
4694 | + if (write(fd, stime, strlen(stime)) != (ssize_t)strlen(stime)) { | |
4695 | errx(1, "Flushing nfsd cache failed: errno %d (%s)", | |
4696 | errno, strerror(errno)); | |
4697 | } | |
4698 | @@ -381,7 +397,7 @@ main(int argc, char **argv) | |
4699 | } | |
4700 | ||
4701 | static void | |
4702 | -dirscancb(int fd, short which, void *data) | |
4703 | +dirscancb(int UNUSED(fd), short UNUSED(which), void *data) | |
4704 | { | |
4705 | int nent, i; | |
4706 | struct dirent **ents; | |
4707 | @@ -465,13 +481,13 @@ out: | |
4708 | } | |
4709 | ||
4710 | static void | |
4711 | -svrreopen(int fd, short which, void *data) | |
4712 | +svrreopen(int UNUSED(fd), short UNUSED(which), void *UNUSED(data)) | |
4713 | { | |
4714 | nfsdreopen(); | |
4715 | } | |
4716 | ||
4717 | static void | |
4718 | -clntscancb(int fd, short which, void *data) | |
4719 | +clntscancb(int UNUSED(fd), short UNUSED(which), void *data) | |
4720 | { | |
4721 | struct idmap_clientq *icq = data; | |
4722 | struct idmap_client *ic; | |
4723 | @@ -485,7 +501,7 @@ clntscancb(int fd, short which, void *data) | |
4724 | } | |
4725 | ||
4726 | static void | |
4727 | -nfsdcb(int fd, short which, void *data) | |
4728 | +nfsdcb(int UNUSED(fd), short which, void *data) | |
4729 | { | |
4730 | struct idmap_client *ic = data; | |
4731 | struct idmap_msg im; | |
4732 | @@ -660,7 +676,7 @@ imconv(struct idmap_client *ic, struct idmap_msg *im) | |
4733 | } | |
4734 | ||
4735 | static void | |
4736 | -nfscb(int fd, short which, void *data) | |
4737 | +nfscb(int UNUSED(fd), short which, void *data) | |
4738 | { | |
4739 | struct idmap_client *ic = data; | |
4740 | struct idmap_msg im; | |
4741 | @@ -845,7 +861,7 @@ nametoidres(struct idmap_msg *im) | |
4742 | static int | |
4743 | validateascii(char *string, u_int32_t len) | |
4744 | { | |
4745 | - int i; | |
4746 | + u_int32_t i; | |
4747 | ||
4748 | for (i = 0; i < len; i++) { | |
4749 | if (string[i] == '\0') | |
4750 | @@ -901,7 +917,7 @@ static int | |
4751 | getfield(char **bpp, char *fld, size_t fldsz) | |
4752 | { | |
4753 | char *bp; | |
4754 | - u_int val, n; | |
4755 | + int val, n; | |
4756 | ||
4757 | while ((bp = strsep(bpp, " ")) != NULL && bp[0] == '\0') | |
4758 | ; | |
4759 | diff --git a/utils/mount/configfile.c b/utils/mount/configfile.c | |
4760 | index 5cff009..6f2ee75 100644 | |
4761 | --- a/utils/mount/configfile.c | |
4762 | +++ b/utils/mount/configfile.c | |
4763 | @@ -192,7 +192,8 @@ void free_all(void) | |
4764 | } | |
4765 | } | |
4766 | static char *versions[] = {"v2", "v3", "v4", "vers", "nfsvers", NULL}; | |
4767 | -int inline check_vers(char *mopt, char *field) | |
4768 | +static int | |
4769 | +check_vers(char *mopt, char *field) | |
4770 | { | |
4771 | int i, found=0; | |
4772 | ||
4773 | @@ -229,7 +230,8 @@ extern sa_family_t config_default_family; | |
4774 | * If so, set the appropriate global value which will | |
4775 | * be used as the initial value in the server negation. | |
4776 | */ | |
4777 | -int inline default_value(char *mopt) | |
4778 | +static int | |
4779 | +default_value(char *mopt) | |
4780 | { | |
4781 | struct mount_options *options = NULL; | |
4782 | int dftlen = strlen("default"); | |
4783 | diff --git a/utils/mount/network.c b/utils/mount/network.c | |
4784 | index 8dc183a..d6b5205 100644 | |
4785 | --- a/utils/mount/network.c | |
4786 | +++ b/utils/mount/network.c | |
4787 | @@ -53,6 +53,7 @@ | |
4788 | #include "parse_opt.h" | |
4789 | #include "network.h" | |
4790 | #include "conffile.h" | |
4791 | +#include "nfslib.h" | |
4792 | ||
4793 | #define PMAP_TIMEOUT (10) | |
4794 | #define CONNECT_TIMEOUT (20) | |
4795 | @@ -857,7 +858,14 @@ int nfs_advise_umount(const struct sockaddr *sap, const socklen_t salen, | |
4796 | return 0; | |
4797 | } | |
4798 | ||
4799 | - client->cl_auth = authunix_create_default(); | |
4800 | + client->cl_auth = nfs_authsys_create(); | |
4801 | + if (client->cl_auth == NULL) { | |
4802 | + if (verbose) | |
4803 | + nfs_error(_("%s: Failed to create RPC auth handle"), | |
4804 | + progname); | |
4805 | + CLNT_DESTROY(client); | |
4806 | + return 0; | |
4807 | + } | |
4808 | ||
4809 | res = CLNT_CALL(client, MOUNTPROC_UMNT, | |
4810 | (xdrproc_t)xdr_dirpath, (caddr_t)argp, | |
4811 | @@ -957,8 +965,10 @@ CLIENT *mnt_openclnt(clnt_addr_t *mnt_server, int *msock) | |
4812 | } | |
4813 | if (clnt) { | |
4814 | /* try to mount hostname:dirname */ | |
4815 | - clnt->cl_auth = authunix_create_default(); | |
4816 | - return clnt; | |
4817 | + clnt->cl_auth = nfs_authsys_create(); | |
4818 | + if (clnt->cl_auth) | |
4819 | + return clnt; | |
4820 | + CLNT_DESTROY(clnt); | |
4821 | } | |
4822 | return NULL; | |
4823 | } | |
4824 | @@ -1203,6 +1213,8 @@ nfs_nfs_program(struct mount_options *options, unsigned long *program) | |
4825 | return 1; | |
4826 | } | |
4827 | case PO_BAD_VALUE: | |
4828 | + nfs_error(_("%s: invalid value for 'nfsprog=' option"), | |
4829 | + progname); | |
4830 | return 0; | |
4831 | } | |
4832 | ||
4833 | @@ -1242,9 +1254,12 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version) | |
4834 | } | |
4835 | return 0; | |
4836 | case PO_NOT_FOUND: | |
4837 | - nfs_error(_("%s: option parsing error\n"), | |
4838 | + nfs_error(_("%s: parsing error on 'vers=' option\n"), | |
4839 | progname); | |
4840 | + return 0; | |
4841 | case PO_BAD_VALUE: | |
4842 | + nfs_error(_("%s: invalid value for 'vers=' option"), | |
4843 | + progname); | |
4844 | return 0; | |
4845 | } | |
4846 | case 4: /* nfsvers */ | |
4847 | @@ -1256,9 +1271,12 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version) | |
4848 | } | |
4849 | return 0; | |
4850 | case PO_NOT_FOUND: | |
4851 | - nfs_error(_("%s: option parsing error\n"), | |
4852 | + nfs_error(_("%s: parsing error on 'nfsvers=' option\n"), | |
4853 | progname); | |
4854 | + return 0; | |
4855 | case PO_BAD_VALUE: | |
4856 | + nfs_error(_("%s: invalid value for 'nfsvers=' option"), | |
4857 | + progname); | |
4858 | return 0; | |
4859 | } | |
4860 | } | |
4861 | @@ -1294,6 +1312,8 @@ nfs_nfs_protocol(struct mount_options *options, unsigned long *protocol) | |
4862 | if (option != NULL) { | |
4863 | if (!nfs_get_proto(option, &family, protocol)) { | |
4864 | errno = EPROTONOSUPPORT; | |
4865 | + nfs_error(_("%s: Failed to find '%s' protocol"), | |
4866 | + progname, option); | |
4867 | return 0; | |
4868 | } | |
4869 | return 1; | |
4870 | @@ -1327,6 +1347,8 @@ nfs_nfs_port(struct mount_options *options, unsigned long *port) | |
4871 | return 1; | |
4872 | } | |
4873 | case PO_BAD_VALUE: | |
4874 | + nfs_error(_("%s: invalid value for 'port=' option"), | |
4875 | + progname); | |
4876 | return 0; | |
4877 | } | |
4878 | ||
4879 | @@ -1342,7 +1364,7 @@ nfs_nfs_port(struct mount_options *options, unsigned long *port) | |
4880 | sa_family_t config_default_family = AF_UNSPEC; | |
4881 | ||
4882 | static int | |
4883 | -nfs_verify_family(sa_family_t family) | |
4884 | +nfs_verify_family(sa_family_t UNUSED(family)) | |
4885 | { | |
4886 | return 1; | |
4887 | } | |
4888 | @@ -1380,8 +1402,13 @@ int nfs_nfs_proto_family(struct mount_options *options, | |
4889 | case 2: /* proto */ | |
4890 | option = po_get(options, "proto"); | |
4891 | if (option != NULL && | |
4892 | - !nfs_get_proto(option, &tmp_family, &protocol)) | |
4893 | - goto out_err; | |
4894 | + !nfs_get_proto(option, &tmp_family, &protocol)) { | |
4895 | + | |
4896 | + nfs_error(_("%s: Failed to find '%s' protocol"), | |
4897 | + progname, option); | |
4898 | + errno = EPROTONOSUPPORT; | |
4899 | + return 0; | |
4900 | + } | |
4901 | } | |
4902 | ||
4903 | if (!nfs_verify_family(tmp_family)) | |
4904 | @@ -1414,6 +1441,8 @@ nfs_mount_program(struct mount_options *options, unsigned long *program) | |
4905 | return 1; | |
4906 | } | |
4907 | case PO_BAD_VALUE: | |
4908 | + nfs_error(_("%s: invalid value for 'mountprog=' option"), | |
4909 | + progname); | |
4910 | return 0; | |
4911 | } | |
4912 | ||
4913 | @@ -1443,6 +1472,8 @@ nfs_mount_version(struct mount_options *options, unsigned long *version) | |
4914 | return 1; | |
4915 | } | |
4916 | case PO_BAD_VALUE: | |
4917 | + nfs_error(_("%s: invalid value for 'mountvers=' option"), | |
4918 | + progname); | |
4919 | return 0; | |
4920 | } | |
4921 | ||
4922 | @@ -1469,6 +1500,8 @@ nfs_mount_protocol(struct mount_options *options, unsigned long *protocol) | |
4923 | if (option != NULL) { | |
4924 | if (!nfs_get_proto(option, &family, protocol)) { | |
4925 | errno = EPROTONOSUPPORT; | |
4926 | + nfs_error(_("%s: Failed to find '%s' protocol"), | |
4927 | + progname, option); | |
4928 | return 0; | |
4929 | } | |
4930 | return 1; | |
4931 | @@ -1501,6 +1534,8 @@ nfs_mount_port(struct mount_options *options, unsigned long *port) | |
4932 | return 1; | |
4933 | } | |
4934 | case PO_BAD_VALUE: | |
4935 | + nfs_error(_("%s: invalid value for 'mountport=' option"), | |
4936 | + progname); | |
4937 | return 0; | |
4938 | } | |
4939 | ||
4940 | @@ -1526,8 +1561,12 @@ int nfs_mount_proto_family(struct mount_options *options, | |
4941 | ||
4942 | option = po_get(options, "mountproto"); | |
4943 | if (option != NULL) { | |
4944 | - if (!nfs_get_proto(option, &tmp_family, &protocol)) | |
4945 | + if (!nfs_get_proto(option, &tmp_family, &protocol)) { | |
4946 | + nfs_error(_("%s: Failed to find '%s' protocol"), | |
4947 | + progname, option); | |
4948 | + errno = EPROTONOSUPPORT; | |
4949 | goto out_err; | |
4950 | + } | |
4951 | if (!nfs_verify_family(tmp_family)) | |
4952 | goto out_err; | |
4953 | *family = tmp_family; | |
4954 | diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man | |
4955 | index c64de5f..3806635 100644 | |
4956 | --- a/utils/mount/nfs.man | |
4957 | +++ b/utils/mount/nfs.man | |
4958 | @@ -623,14 +623,9 @@ in such cases. | |
4959 | .TP 1.5i | |
4960 | .BI nfsvers= n | |
4961 | The NFS protocol version number used to contact the server's NFS service. | |
4962 | -The Linux client supports version 2 and version 3 of the NFS protocol | |
4963 | -when using the file system type | |
4964 | -.BR nfs . | |
4965 | -If the server does not support the requested version, | |
4966 | -the mount request fails. | |
4967 | -If this option is not specified, the client attempts to use version 3, | |
4968 | -but negotiates the NFS version with the server if version 3 support | |
4969 | -is not available. | |
4970 | +If the server does not support the requested version, the mount request fails. | |
4971 | +If this option is not specified, the client negociate a suitable version with | |
4972 | +the server, trying version 4 first, version 3 second, and version 2 last. | |
4973 | .TP 1.5i | |
4974 | .BI vers= n | |
4975 | This option is an alternative to the | |
4976 | diff --git a/utils/mount/nfs4mount.c b/utils/mount/nfs4mount.c | |
4977 | index 4a2fab7..028e7cd 100644 | |
4978 | --- a/utils/mount/nfs4mount.c | |
4979 | +++ b/utils/mount/nfs4mount.c | |
4980 | @@ -146,7 +146,7 @@ static int fill_ipv4_sockaddr(const char *hostname, struct sockaddr_in *addr) | |
4981 | progname, hostname); | |
4982 | return -1; | |
4983 | } | |
4984 | - if (hp->h_length > sizeof(struct in_addr)) { | |
4985 | + if (hp->h_length > (int)sizeof(struct in_addr)) { | |
4986 | nfs_error(_("%s: got bad hp->h_length"), progname); | |
4987 | hp->h_length = sizeof(struct in_addr); | |
4988 | } | |
4989 | diff --git a/utils/mount/nfsmount.c b/utils/mount/nfsmount.c | |
4990 | index 6b3356c..5b934b5 100644 | |
4991 | --- a/utils/mount/nfsmount.c | |
4992 | +++ b/utils/mount/nfsmount.c | |
4993 | @@ -510,8 +510,12 @@ nfsmount(const char *spec, const char *node, int flags, | |
4994 | int val; | |
4995 | static int doonce = 0; | |
4996 | ||
4997 | - clnt_addr_t mnt_server = { &mounthost, }; | |
4998 | - clnt_addr_t nfs_server = { &hostname, }; | |
4999 | + clnt_addr_t mnt_server = { | |
5000 | + .hostname = &mounthost | |
5001 | + }; | |
5002 | + clnt_addr_t nfs_server = { | |
5003 | + .hostname = &hostname | |
5004 | + }; | |
5005 | struct sockaddr_in *nfs_saddr = &nfs_server.saddr; | |
5006 | struct pmap *mnt_pmap = &mnt_server.pmap, | |
5007 | *nfs_pmap = &nfs_server.pmap; | |
5008 | diff --git a/utils/mount/nfsumount.c b/utils/mount/nfsumount.c | |
5009 | index 9d798a2..1514340 100644 | |
5010 | --- a/utils/mount/nfsumount.c | |
5011 | +++ b/utils/mount/nfsumount.c | |
5012 | @@ -179,10 +179,8 @@ static int nfs_umount_do_umnt(struct mount_options *options, | |
5013 | struct pmap nfs_pmap, mnt_pmap; | |
5014 | sa_family_t family; | |
5015 | ||
5016 | - if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap)) { | |
5017 | - nfs_error(_("%s: bad mount options"), progname); | |
5018 | + if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap)) | |
5019 | return EX_FAIL; | |
5020 | - } | |
5021 | ||
5022 | /* Skip UMNT call for vers=4 mounts */ | |
5023 | if (nfs_pmap.pm_vers == 4) | |
5024 | diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c | |
5025 | index 9b8c38f..0241400 100644 | |
5026 | --- a/utils/mount/stropts.c | |
5027 | +++ b/utils/mount/stropts.c | |
5028 | @@ -538,7 +538,10 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options) | |
5029 | ||
5030 | if (!nfs_construct_new_options(options, nfs_saddr, &nfs_pmap, | |
5031 | mnt_saddr, &mnt_pmap)) { | |
5032 | - errno = EINVAL; | |
5033 | + if (rpc_createerr.cf_stat == RPC_UNKNOWNPROTO) | |
5034 | + errno = EPROTONOSUPPORT; | |
5035 | + else | |
5036 | + errno = EINVAL; | |
5037 | return 0; | |
5038 | } | |
5039 | ||
5040 | @@ -586,18 +589,21 @@ static int nfs_do_mount_v3v2(struct nfsmount_info *mi, | |
5041 | errno = ENOMEM; | |
5042 | return result; | |
5043 | } | |
5044 | - | |
5045 | + errno = 0; | |
5046 | if (!nfs_append_addr_option(sap, salen, options)) { | |
5047 | - errno = EINVAL; | |
5048 | + if (errno == 0) | |
5049 | + errno = EINVAL; | |
5050 | goto out_fail; | |
5051 | } | |
5052 | ||
5053 | if (!nfs_fix_mounthost_option(options, mi->hostname)) { | |
5054 | - errno = EINVAL; | |
5055 | + if (errno == 0) | |
5056 | + errno = EINVAL; | |
5057 | goto out_fail; | |
5058 | } | |
5059 | if (!mi->fake && !nfs_verify_lock_option(options)) { | |
5060 | - errno = EINVAL; | |
5061 | + if (errno == 0) | |
5062 | + errno = EINVAL; | |
5063 | goto out_fail; | |
5064 | } | |
5065 | ||
5066 | @@ -799,6 +805,7 @@ static int nfs_is_permanent_error(int error) | |
5067 | case ESTALE: | |
5068 | case ETIMEDOUT: | |
5069 | case ECONNREFUSED: | |
5070 | + case EHOSTUNREACH: | |
5071 | return 0; /* temporary */ | |
5072 | default: | |
5073 | return 1; /* permanent */ | |
5074 | diff --git a/utils/mountd/auth.c b/utils/mountd/auth.c | |
5075 | index 13eba70..ccc849a 100644 | |
5076 | --- a/utils/mountd/auth.c | |
5077 | +++ b/utils/mountd/auth.c | |
5078 | @@ -15,6 +15,8 @@ | |
5079 | #include <arpa/inet.h> | |
5080 | #include <errno.h> | |
5081 | #include <unistd.h> | |
5082 | + | |
5083 | +#include "sockaddr.h" | |
5084 | #include "misc.h" | |
5085 | #include "nfslib.h" | |
5086 | #include "exportfs.h" | |
5087 | @@ -110,13 +112,16 @@ auth_reload() | |
5088 | return counter; | |
5089 | } | |
5090 | ||
5091 | -static char *get_client_hostname(struct sockaddr_in *caller, struct hostent *hp, enum auth_error *error) | |
5092 | +static char * | |
5093 | +get_client_hostname(const struct sockaddr *caller, struct addrinfo *ai, | |
5094 | + enum auth_error *error) | |
5095 | { | |
5096 | + char buf[INET6_ADDRSTRLEN]; | |
5097 | char *n; | |
5098 | ||
5099 | if (use_ipaddr) | |
5100 | - return strdup(inet_ntoa(caller->sin_addr)); | |
5101 | - n = client_compose(hp); | |
5102 | + return strdup(host_ntop(caller, buf, sizeof(buf))); | |
5103 | + n = client_compose(ai); | |
5104 | *error = unknown_host; | |
5105 | if (!n) | |
5106 | return NULL; | |
5107 | @@ -128,8 +133,8 @@ static char *get_client_hostname(struct sockaddr_in *caller, struct hostent *hp, | |
5108 | ||
5109 | /* return static nfs_export with details filled in */ | |
5110 | static nfs_export * | |
5111 | -auth_authenticate_newcache(char *what, struct sockaddr_in *caller, | |
5112 | - char *path, struct hostent *hp, | |
5113 | +auth_authenticate_newcache(const struct sockaddr *caller, | |
5114 | + const char *path, struct addrinfo *ai, | |
5115 | enum auth_error *error) | |
5116 | { | |
5117 | nfs_export *exp; | |
5118 | @@ -137,12 +142,12 @@ auth_authenticate_newcache(char *what, struct sockaddr_in *caller, | |
5119 | ||
5120 | free(my_client.m_hostname); | |
5121 | ||
5122 | - my_client.m_hostname = get_client_hostname(caller, hp, error); | |
5123 | + my_client.m_hostname = get_client_hostname(caller, ai, error); | |
5124 | if (my_client.m_hostname == NULL) | |
5125 | return NULL; | |
5126 | ||
5127 | my_client.m_naddr = 1; | |
5128 | - my_client.m_addrlist[0] = caller->sin_addr; | |
5129 | + set_addrlist(&my_client, 0, caller); | |
5130 | my_exp.m_client = &my_client; | |
5131 | ||
5132 | exp = NULL; | |
5133 | @@ -152,7 +157,7 @@ auth_authenticate_newcache(char *what, struct sockaddr_in *caller, | |
5134 | continue; | |
5135 | if (!use_ipaddr && !client_member(my_client.m_hostname, exp->m_client->m_hostname)) | |
5136 | continue; | |
5137 | - if (use_ipaddr && !client_check(exp->m_client, hp)) | |
5138 | + if (use_ipaddr && !client_check(exp->m_client, ai)) | |
5139 | continue; | |
5140 | break; | |
5141 | } | |
5142 | @@ -166,18 +171,18 @@ auth_authenticate_newcache(char *what, struct sockaddr_in *caller, | |
5143 | } | |
5144 | ||
5145 | static nfs_export * | |
5146 | -auth_authenticate_internal(char *what, struct sockaddr_in *caller, | |
5147 | - char *path, struct hostent *hp, | |
5148 | - enum auth_error *error) | |
5149 | +auth_authenticate_internal(const struct sockaddr *caller, const char *path, | |
5150 | + struct addrinfo *ai, enum auth_error *error) | |
5151 | { | |
5152 | nfs_export *exp; | |
5153 | ||
5154 | if (new_cache) { | |
5155 | - exp = auth_authenticate_newcache(what, caller, path, hp, error); | |
5156 | + exp = auth_authenticate_newcache(caller, path, ai, error); | |
5157 | if (!exp) | |
5158 | return NULL; | |
5159 | } else { | |
5160 | - if (!(exp = export_find(hp, path))) { | |
5161 | + exp = export_find(ai, path); | |
5162 | + if (exp == NULL) { | |
5163 | *error = no_entry; | |
5164 | return NULL; | |
5165 | } | |
5166 | @@ -187,7 +192,7 @@ auth_authenticate_internal(char *what, struct sockaddr_in *caller, | |
5167 | return NULL; | |
5168 | } | |
5169 | if (!(exp->m_export.e_flags & NFSEXP_INSECURE_PORT) && | |
5170 | - ntohs(caller->sin_port) >= IPPORT_RESERVED) { | |
5171 | + nfs_get_port(caller) >= IPPORT_RESERVED) { | |
5172 | *error = illegal_port; | |
5173 | return NULL; | |
5174 | } | |
5175 | @@ -197,18 +202,19 @@ auth_authenticate_internal(char *what, struct sockaddr_in *caller, | |
5176 | } | |
5177 | ||
5178 | nfs_export * | |
5179 | -auth_authenticate(char *what, struct sockaddr_in *caller, char *path) | |
5180 | +auth_authenticate(const char *what, const struct sockaddr *caller, | |
5181 | + const char *path) | |
5182 | { | |
5183 | nfs_export *exp = NULL; | |
5184 | char epath[MAXPATHLEN+1]; | |
5185 | char *p = NULL; | |
5186 | - struct hostent *hp = NULL; | |
5187 | - struct in_addr addr = caller->sin_addr; | |
5188 | + char buf[INET6_ADDRSTRLEN]; | |
5189 | + struct addrinfo *ai = NULL; | |
5190 | enum auth_error error = bad_path; | |
5191 | ||
5192 | - if (path [0] != '/') { | |
5193 | - xlog(L_WARNING, "bad path in %s request from %s: \"%s\"", | |
5194 | - what, inet_ntoa(addr), path); | |
5195 | + if (path[0] != '/') { | |
5196 | + xlog(L_WARNING, "Bad path in %s request from %s: \"%s\"", | |
5197 | + what, host_ntop(caller, buf, sizeof(buf)), path); | |
5198 | return exp; | |
5199 | } | |
5200 | ||
5201 | @@ -216,14 +222,13 @@ auth_authenticate(char *what, struct sockaddr_in *caller, char *path) | |
5202 | epath[sizeof (epath) - 1] = '\0'; | |
5203 | auth_fixpath(epath); /* strip duplicate '/' etc */ | |
5204 | ||
5205 | - hp = client_resolve(caller->sin_addr); | |
5206 | - if (!hp) | |
5207 | + ai = client_resolve(caller); | |
5208 | + if (ai == NULL) | |
5209 | return exp; | |
5210 | ||
5211 | /* Try the longest matching exported pathname. */ | |
5212 | while (1) { | |
5213 | - exp = auth_authenticate_internal(what, caller, epath, | |
5214 | - hp, &error); | |
5215 | + exp = auth_authenticate_internal(caller, epath, ai, &error); | |
5216 | if (exp || (error != not_exported && error != no_entry)) | |
5217 | break; | |
5218 | /* We have to treat the root, "/", specially. */ | |
5219 | @@ -236,41 +241,40 @@ auth_authenticate(char *what, struct sockaddr_in *caller, char *path) | |
5220 | switch (error) { | |
5221 | case bad_path: | |
5222 | xlog(L_WARNING, "bad path in %s request from %s: \"%s\"", | |
5223 | - what, inet_ntoa(addr), path); | |
5224 | + what, host_ntop(caller, buf, sizeof(buf)), path); | |
5225 | break; | |
5226 | ||
5227 | case unknown_host: | |
5228 | xlog(L_WARNING, "refused %s request from %s for %s (%s): unmatched host", | |
5229 | - what, inet_ntoa(addr), path, epath); | |
5230 | + what, host_ntop(caller, buf, sizeof(buf)), path, epath); | |
5231 | break; | |
5232 | ||
5233 | case no_entry: | |
5234 | xlog(L_WARNING, "refused %s request from %s for %s (%s): no export entry", | |
5235 | - what, hp->h_name, path, epath); | |
5236 | + what, ai->ai_canonname, path, epath); | |
5237 | break; | |
5238 | ||
5239 | case not_exported: | |
5240 | xlog(L_WARNING, "refused %s request from %s for %s (%s): not exported", | |
5241 | - what, hp->h_name, path, epath); | |
5242 | + what, ai->ai_canonname, path, epath); | |
5243 | break; | |
5244 | ||
5245 | case illegal_port: | |
5246 | - xlog(L_WARNING, "refused %s request from %s for %s (%s): illegal port %d", | |
5247 | - what, hp->h_name, path, epath, ntohs(caller->sin_port)); | |
5248 | + xlog(L_WARNING, "refused %s request from %s for %s (%s): illegal port %u", | |
5249 | + what, ai->ai_canonname, path, epath, nfs_get_port(caller)); | |
5250 | break; | |
5251 | ||
5252 | case success: | |
5253 | - xlog(L_NOTICE, "authenticated %s request from %s:%d for %s (%s)", | |
5254 | - what, hp->h_name, ntohs(caller->sin_port), path, epath); | |
5255 | + xlog(L_NOTICE, "authenticated %s request from %s:%u for %s (%s)", | |
5256 | + what, ai->ai_canonname, nfs_get_port(caller), path, epath); | |
5257 | break; | |
5258 | default: | |
5259 | - xlog(L_NOTICE, "%s request from %s:%d for %s (%s) gave %d", | |
5260 | - what, hp->h_name, ntohs(caller->sin_port), path, epath, error); | |
5261 | + xlog(L_NOTICE, "%s request from %s:%u for %s (%s) gave %d", | |
5262 | + what, ai->ai_canonname, nfs_get_port(caller), | |
5263 | + path, epath, error); | |
5264 | } | |
5265 | ||
5266 | - if (hp) | |
5267 | - free (hp); | |
5268 | - | |
5269 | + freeaddrinfo(ai); | |
5270 | return exp; | |
5271 | } | |
5272 | ||
5273 | diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c | |
5274 | index d63e10a..f70f4d6 100644 | |
5275 | --- a/utils/mountd/cache.c | |
5276 | +++ b/utils/mountd/cache.c | |
5277 | @@ -37,6 +37,11 @@ | |
5278 | #include "blkid/blkid.h" | |
5279 | #endif | |
5280 | ||
5281 | +/* | |
5282 | + * Invoked by RPC service loop | |
5283 | + */ | |
5284 | +void cache_set_fds(fd_set *fdset); | |
5285 | +int cache_process_req(fd_set *readfds); | |
5286 | ||
5287 | enum nfsd_fsid { | |
5288 | FSID_DEV = 0, | |
5289 | @@ -57,14 +62,14 @@ enum nfsd_fsid { | |
5290 | * Record is terminated with newline. | |
5291 | * | |
5292 | */ | |
5293 | -int cache_export_ent(char *domain, struct exportent *exp, char *p); | |
5294 | +static int cache_export_ent(char *domain, struct exportent *exp, char *p); | |
5295 | ||
5296 | ||
5297 | char *lbuf = NULL; | |
5298 | int lbuflen = 0; | |
5299 | extern int use_ipaddr; | |
5300 | ||
5301 | -void auth_unix_ip(FILE *f) | |
5302 | +static void auth_unix_ip(FILE *f) | |
5303 | { | |
5304 | /* requests are | |
5305 | * class IP-ADDR | |
5306 | @@ -75,10 +80,10 @@ void auth_unix_ip(FILE *f) | |
5307 | */ | |
5308 | char *cp; | |
5309 | char class[20]; | |
5310 | - char ipaddr[20]; | |
5311 | + char ipaddr[INET6_ADDRSTRLEN]; | |
5312 | char *client = NULL; | |
5313 | - struct in_addr addr; | |
5314 | - struct hostent *he = NULL; | |
5315 | + struct addrinfo *tmp = NULL; | |
5316 | + struct addrinfo *ai = NULL; | |
5317 | if (readline(fileno(f), &lbuf, &lbuflen) != 1) | |
5318 | return; | |
5319 | ||
5320 | @@ -90,20 +95,23 @@ void auth_unix_ip(FILE *f) | |
5321 | strcmp(class, "nfsd") != 0) | |
5322 | return; | |
5323 | ||
5324 | - if (qword_get(&cp, ipaddr, 20) <= 0) | |
5325 | + if (qword_get(&cp, ipaddr, sizeof(ipaddr)) <= 0) | |
5326 | return; | |
5327 | ||
5328 | - if (inet_aton(ipaddr, &addr)==0) | |
5329 | + tmp = host_pton(ipaddr); | |
5330 | + if (tmp == NULL) | |
5331 | return; | |
5332 | ||
5333 | auth_reload(); | |
5334 | ||
5335 | /* addr is a valid, interesting address, find the domain name... */ | |
5336 | if (!use_ipaddr) { | |
5337 | - he = client_resolve(addr); | |
5338 | - client = client_compose(he); | |
5339 | + ai = client_resolve(tmp->ai_addr); | |
5340 | + client = client_compose(ai); | |
5341 | + freeaddrinfo(ai); | |
5342 | } | |
5343 | - | |
5344 | + freeaddrinfo(tmp); | |
5345 | + | |
5346 | qword_print(f, "nfsd"); | |
5347 | qword_print(f, ipaddr); | |
5348 | qword_printint(f, time(0)+30*60); | |
5349 | @@ -114,18 +122,17 @@ void auth_unix_ip(FILE *f) | |
5350 | qword_eol(f); | |
5351 | xlog(D_CALL, "auth_unix_ip: client %p '%s'", client, client?client: "DEFAULT"); | |
5352 | ||
5353 | - if (client) free(client); | |
5354 | - free(he); | |
5355 | + free(client); | |
5356 | } | |
5357 | ||
5358 | -void auth_unix_gid(FILE *f) | |
5359 | +static void auth_unix_gid(FILE *f) | |
5360 | { | |
5361 | /* Request are | |
5362 | * uid | |
5363 | * reply is | |
5364 | * uid expiry count list of group ids | |
5365 | */ | |
5366 | - int uid; | |
5367 | + uid_t uid; | |
5368 | struct passwd *pw; | |
5369 | gid_t glist[100], *groups = glist; | |
5370 | int ngroups = 100; | |
5371 | @@ -136,7 +143,7 @@ void auth_unix_gid(FILE *f) | |
5372 | return; | |
5373 | ||
5374 | cp = lbuf; | |
5375 | - if (qword_get_int(&cp, &uid) != 0) | |
5376 | + if (qword_get_uint(&cp, &uid) != 0) | |
5377 | return; | |
5378 | ||
5379 | pw = getpwuid(uid); | |
5380 | @@ -153,14 +160,14 @@ void auth_unix_gid(FILE *f) | |
5381 | groups, &ngroups); | |
5382 | } | |
5383 | } | |
5384 | - qword_printint(f, uid); | |
5385 | - qword_printint(f, time(0)+30*60); | |
5386 | + qword_printuint(f, uid); | |
5387 | + qword_printuint(f, time(0)+30*60); | |
5388 | if (rv >= 0) { | |
5389 | - qword_printint(f, ngroups); | |
5390 | + qword_printuint(f, ngroups); | |
5391 | for (i=0; i<ngroups; i++) | |
5392 | - qword_printint(f, groups[i]); | |
5393 | + qword_printuint(f, groups[i]); | |
5394 | } else | |
5395 | - qword_printint(f, 0); | |
5396 | + qword_printuint(f, 0); | |
5397 | qword_eol(f); | |
5398 | ||
5399 | if (groups != glist) | |
5400 | @@ -170,13 +177,16 @@ void auth_unix_gid(FILE *f) | |
5401 | #if USE_BLKID | |
5402 | static const char *get_uuid_blkdev(char *path) | |
5403 | { | |
5404 | + /* We set *safe if we know that we need the | |
5405 | + * fsid from statfs too. | |
5406 | + */ | |
5407 | static blkid_cache cache = NULL; | |
5408 | struct stat stb; | |
5409 | char *devname; | |
5410 | blkid_tag_iterate iter; | |
5411 | blkid_dev dev; | |
5412 | const char *type; | |
5413 | - const char *val = NULL; | |
5414 | + const char *val, *uuid = NULL; | |
5415 | ||
5416 | if (cache == NULL) | |
5417 | blkid_get_cache(&cache, NULL); | |
5418 | @@ -193,42 +203,29 @@ static const char *get_uuid_blkdev(char *path) | |
5419 | iter = blkid_tag_iterate_begin(dev); | |
5420 | if (!iter) | |
5421 | return NULL; | |
5422 | - while (blkid_tag_next(iter, &type, &val) == 0) | |
5423 | + while (blkid_tag_next(iter, &type, &val) == 0) { | |
5424 | if (strcmp(type, "UUID") == 0) | |
5425 | + uuid = val; | |
5426 | + if (strcmp(type, "TYPE") == 0 && | |
5427 | + strcmp(val, "btrfs") == 0) { | |
5428 | + uuid = NULL; | |
5429 | break; | |
5430 | + } | |
5431 | + } | |
5432 | blkid_tag_iterate_end(iter); | |
5433 | - return val; | |
5434 | + return uuid; | |
5435 | } | |
5436 | #else | |
5437 | #define get_uuid_blkdev(path) (NULL) | |
5438 | #endif | |
5439 | ||
5440 | -int get_uuid(char *path, char *uuid, int uuidlen, char *u) | |
5441 | +static int get_uuid(const char *val, int uuidlen, char *u) | |
5442 | { | |
5443 | /* extract hex digits from uuidstr and compose a uuid | |
5444 | * of the given length (max 16), xoring bytes to make | |
5445 | - * a smaller uuid. Then compare with uuid | |
5446 | + * a smaller uuid. | |
5447 | */ | |
5448 | int i = 0; | |
5449 | - const char *val = NULL; | |
5450 | - char fsid_val[17]; | |
5451 | - | |
5452 | - if (path) { | |
5453 | - val = get_uuid_blkdev(path); | |
5454 | - if (!val) { | |
5455 | - struct statfs64 st; | |
5456 | - | |
5457 | - if (statfs64(path, &st)) | |
5458 | - return 0; | |
5459 | - if (!st.f_fsid.__val[0] && !st.f_fsid.__val[1]) | |
5460 | - return 0; | |
5461 | - snprintf(fsid_val, 17, "%08x%08x", | |
5462 | - st.f_fsid.__val[0], st.f_fsid.__val[1]); | |
5463 | - val = fsid_val; | |
5464 | - } | |
5465 | - } else { | |
5466 | - val = uuid; | |
5467 | - } | |
5468 | ||
5469 | memset(u, 0, uuidlen); | |
5470 | for ( ; *val ; val++) { | |
5471 | @@ -252,6 +249,60 @@ int get_uuid(char *path, char *uuid, int uuidlen, char *u) | |
5472 | return 1; | |
5473 | } | |
5474 | ||
5475 | +static int uuid_by_path(char *path, int type, int uuidlen, char *uuid) | |
5476 | +{ | |
5477 | + /* get a uuid for the filesystem found at 'path'. | |
5478 | + * There are several possible ways of generating the | |
5479 | + * uuids (types). | |
5480 | + * Type 0 is used for new filehandles, while other types | |
5481 | + * may be used to interpret old filehandle - to ensure smooth | |
5482 | + * forward migration. | |
5483 | + * We return 1 if a uuid was found (and it might be worth | |
5484 | + * trying the next type) or 0 if no more uuid types can be | |
5485 | + * extracted. | |
5486 | + */ | |
5487 | + | |
5488 | + /* Possible sources of uuid are | |
5489 | + * - blkid uuid | |
5490 | + * - statfs64 uuid | |
5491 | + * | |
5492 | + * On some filesystems (e.g. vfat) the statfs64 uuid is simply an | |
5493 | + * encoding of the device that the filesystem is mounted from, so | |
5494 | + * it we be very bad to use that (as device numbers change). blkid | |
5495 | + * must be preferred. | |
5496 | + * On other filesystems (e.g. btrfs) the statfs64 uuid contains | |
5497 | + * important info that the blkid uuid cannot contain: This happens | |
5498 | + * when multiple subvolumes are exported (they have the same | |
5499 | + * blkid uuid but different statfs64 uuids). | |
5500 | + * We rely on get_uuid_blkdev *knowing* which is which and not returning | |
5501 | + * a uuid for filesystems where the statfs64 uuid is better. | |
5502 | + * | |
5503 | + */ | |
5504 | + struct statfs64 st; | |
5505 | + char fsid_val[17]; | |
5506 | + const char *blkid_val; | |
5507 | + const char *val; | |
5508 | + | |
5509 | + blkid_val = get_uuid_blkdev(path); | |
5510 | + | |
5511 | + if (statfs64(path, &st) == 0 && | |
5512 | + (st.f_fsid.__val[0] || st.f_fsid.__val[1])) | |
5513 | + snprintf(fsid_val, 17, "%08x%08x", | |
5514 | + st.f_fsid.__val[0], st.f_fsid.__val[1]); | |
5515 | + else | |
5516 | + fsid_val[0] = 0; | |
5517 | + | |
5518 | + if (blkid_val && (type--) == 0) | |
5519 | + val = blkid_val; | |
5520 | + else if (fsid_val[0] && (type--) == 0) | |
5521 | + val = fsid_val; | |
5522 | + else | |
5523 | + return 0; | |
5524 | + | |
5525 | + get_uuid(val, uuidlen, uuid); | |
5526 | + return 1; | |
5527 | +} | |
5528 | + | |
5529 | /* Iterate through /etc/mtab, finding mountpoints | |
5530 | * at or below a given path | |
5531 | */ | |
5532 | @@ -277,7 +328,7 @@ static char *next_mnt(void **v, char *p) | |
5533 | return me->mnt_dir; | |
5534 | } | |
5535 | ||
5536 | -void nfsd_fh(FILE *f) | |
5537 | +static void nfsd_fh(FILE *f) | |
5538 | { | |
5539 | /* request are: | |
5540 | * domain fsidtype fsid | |
5541 | @@ -294,8 +345,7 @@ void nfsd_fh(FILE *f) | |
5542 | unsigned int fsidnum=0; | |
5543 | char fsid[32]; | |
5544 | struct exportent *found = NULL; | |
5545 | - struct hostent *he = NULL; | |
5546 | - struct in_addr addr; | |
5547 | + struct addrinfo *ai = NULL; | |
5548 | char *found_path = NULL; | |
5549 | nfs_export *exp; | |
5550 | int i; | |
5551 | @@ -398,6 +448,7 @@ void nfsd_fh(FILE *f) | |
5552 | struct stat stb; | |
5553 | char u[16]; | |
5554 | char *path; | |
5555 | + int type; | |
5556 | ||
5557 | if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT) { | |
5558 | static nfs_export *prev = NULL; | |
5559 | @@ -461,22 +512,29 @@ void nfsd_fh(FILE *f) | |
5560 | continue; | |
5561 | check_uuid: | |
5562 | if (exp->m_export.e_uuid) | |
5563 | - get_uuid(NULL, exp->m_export.e_uuid, | |
5564 | + get_uuid(exp->m_export.e_uuid, | |
5565 | uuidlen, u); | |
5566 | - else if (get_uuid(path, NULL, uuidlen, u) == 0) | |
5567 | - continue; | |
5568 | + else | |
5569 | + for (type = 0; | |
5570 | + uuid_by_path(path, type, uuidlen, u); | |
5571 | + type++) | |
5572 | + if (memcmp(u, fhuuid, uuidlen) == 0) | |
5573 | + break; | |
5574 | ||
5575 | if (memcmp(u, fhuuid, uuidlen) != 0) | |
5576 | continue; | |
5577 | break; | |
5578 | } | |
5579 | if (use_ipaddr) { | |
5580 | - if (he == NULL) { | |
5581 | - if (!inet_aton(dom, &addr)) | |
5582 | + if (ai == NULL) { | |
5583 | + struct addrinfo *tmp; | |
5584 | + tmp = host_pton(dom); | |
5585 | + if (tmp == NULL) | |
5586 | goto out; | |
5587 | - he = client_resolve(addr); | |
5588 | + ai = client_resolve(tmp->ai_addr); | |
5589 | + freeaddrinfo(tmp); | |
5590 | } | |
5591 | - if (!client_check(exp->m_client, he)) | |
5592 | + if (!client_check(exp->m_client, ai)) | |
5593 | continue; | |
5594 | } | |
5595 | /* It's a match !! */ | |
5596 | @@ -534,21 +592,20 @@ void nfsd_fh(FILE *f) | |
5597 | out: | |
5598 | if (found_path) | |
5599 | free(found_path); | |
5600 | - if (he) | |
5601 | - free(he); | |
5602 | + freeaddrinfo(ai); | |
5603 | free(dom); | |
5604 | xlog(D_CALL, "nfsd_fh: found %p path %s", found, found ? found->e_path : NULL); | |
5605 | return; | |
5606 | } | |
5607 | ||
5608 | -static void write_fsloc(FILE *f, struct exportent *ep, char *path) | |
5609 | +static void write_fsloc(FILE *f, struct exportent *ep) | |
5610 | { | |
5611 | struct servers *servers; | |
5612 | ||
5613 | if (ep->e_fslocmethod == FSLOC_NONE) | |
5614 | return; | |
5615 | ||
5616 | - servers = replicas_lookup(ep->e_fslocmethod, ep->e_fslocdata, path); | |
5617 | + servers = replicas_lookup(ep->e_fslocmethod, ep->e_fslocdata); | |
5618 | if (!servers) | |
5619 | return; | |
5620 | qword_print(f, "fsloc"); | |
5621 | @@ -596,17 +653,17 @@ static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *ex | |
5622 | qword_printint(f, exp->e_anonuid); | |
5623 | qword_printint(f, exp->e_anongid); | |
5624 | qword_printint(f, exp->e_fsid); | |
5625 | - write_fsloc(f, exp, path); | |
5626 | + write_fsloc(f, exp); | |
5627 | write_secinfo(f, exp, flag_mask); | |
5628 | if (exp->e_uuid == NULL || different_fs) { | |
5629 | char u[16]; | |
5630 | - if (get_uuid(path, NULL, 16, u)) { | |
5631 | + if (uuid_by_path(path, 0, 16, u)) { | |
5632 | qword_print(f, "uuid"); | |
5633 | qword_printhex(f, u, 16); | |
5634 | } | |
5635 | } else { | |
5636 | char u[16]; | |
5637 | - get_uuid(NULL, exp->e_uuid, 16, u); | |
5638 | + get_uuid(exp->e_uuid, 16, u); | |
5639 | qword_print(f, "uuid"); | |
5640 | qword_printhex(f, u, 16); | |
5641 | } | |
5642 | @@ -614,12 +671,12 @@ static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *ex | |
5643 | return qword_eol(f); | |
5644 | } | |
5645 | ||
5646 | -static int is_subdirectory(char *subpath, char *path) | |
5647 | +static int is_subdirectory(char *child, char *parent) | |
5648 | { | |
5649 | - int l = strlen(path); | |
5650 | + int l = strlen(parent); | |
5651 | ||
5652 | - return strcmp(subpath, path) == 0 | |
5653 | - || (strncmp(subpath, path, l) == 0 && path[l] == '/'); | |
5654 | + return strcmp(child, parent) == 0 | |
5655 | + || (strncmp(child, parent, l) == 0 && child[l] == '/'); | |
5656 | } | |
5657 | ||
5658 | static int path_matches(nfs_export *exp, char *path) | |
5659 | @@ -629,19 +686,22 @@ static int path_matches(nfs_export *exp, char *path) | |
5660 | return strcmp(path, exp->m_export.e_path) == 0; | |
5661 | } | |
5662 | ||
5663 | -static int client_matches(nfs_export *exp, char *dom, struct hostent *he) | |
5664 | +static int | |
5665 | +client_matches(nfs_export *exp, char *dom, struct addrinfo *ai) | |
5666 | { | |
5667 | if (use_ipaddr) | |
5668 | - return client_check(exp->m_client, he); | |
5669 | + return client_check(exp->m_client, ai); | |
5670 | return client_member(dom, exp->m_client->m_hostname); | |
5671 | } | |
5672 | ||
5673 | -static int export_matches(nfs_export *exp, char *dom, char *path, struct hostent *he) | |
5674 | +static int | |
5675 | +export_matches(nfs_export *exp, char *dom, char *path, struct addrinfo *ai) | |
5676 | { | |
5677 | - return path_matches(exp, path) && client_matches(exp, dom, he); | |
5678 | + return path_matches(exp, path) && client_matches(exp, dom, ai); | |
5679 | } | |
5680 | ||
5681 | -static nfs_export *lookup_export(char *dom, char *path, struct hostent *he) | |
5682 | +static nfs_export * | |
5683 | +lookup_export(char *dom, char *path, struct addrinfo *ai) | |
5684 | { | |
5685 | nfs_export *exp; | |
5686 | nfs_export *found = NULL; | |
5687 | @@ -650,7 +710,7 @@ static nfs_export *lookup_export(char *dom, char *path, struct hostent *he) | |
5688 | ||
5689 | for (i=0 ; i < MCL_MAXTYPES; i++) { | |
5690 | for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { | |
5691 | - if (!export_matches(exp, dom, path, he)) | |
5692 | + if (!export_matches(exp, dom, path, ai)) | |
5693 | continue; | |
5694 | if (!found) { | |
5695 | found = exp; | |
5696 | @@ -687,7 +747,7 @@ static nfs_export *lookup_export(char *dom, char *path, struct hostent *he) | |
5697 | return found; | |
5698 | } | |
5699 | ||
5700 | -void nfsd_export(FILE *f) | |
5701 | +static void nfsd_export(FILE *f) | |
5702 | { | |
5703 | /* requests are: | |
5704 | * domain path | |
5705 | @@ -698,9 +758,7 @@ void nfsd_export(FILE *f) | |
5706 | char *cp; | |
5707 | char *dom, *path; | |
5708 | nfs_export *found = NULL; | |
5709 | - struct in_addr addr; | |
5710 | - struct hostent *he = NULL; | |
5711 | - | |
5712 | + struct addrinfo *ai = NULL; | |
5713 | ||
5714 | if (readline(fileno(f), &lbuf, &lbuflen) != 1) | |
5715 | return; | |
5716 | @@ -722,12 +780,16 @@ void nfsd_export(FILE *f) | |
5717 | auth_reload(); | |
5718 | ||
5719 | if (use_ipaddr) { | |
5720 | - if (!inet_aton(dom, &addr)) | |
5721 | + struct addrinfo *tmp; | |
5722 | + tmp = host_pton(dom); | |
5723 | + if (tmp == NULL) | |
5724 | + goto out; | |
5725 | + ai = client_resolve(tmp->ai_addr); | |
5726 | + freeaddrinfo(tmp); | |
5727 | goto out; | |
5728 | - he = client_resolve(addr); | |
5729 | } | |
5730 | ||
5731 | - found = lookup_export(dom, path, he); | |
5732 | + found = lookup_export(dom, path, ai); | |
5733 | ||
5734 | if (found) { | |
5735 | if (dump_to_cache(f, dom, path, &found->m_export) < 0) { | |
5736 | @@ -743,7 +805,7 @@ void nfsd_export(FILE *f) | |
5737 | xlog(D_CALL, "nfsd_export: found %p path %s", found, path ? path : NULL); | |
5738 | if (dom) free(dom); | |
5739 | if (path) free(path); | |
5740 | - if (he) free(he); | |
5741 | + freeaddrinfo(ai); | |
5742 | } | |
5743 | ||
5744 | ||
5745 | @@ -752,14 +814,19 @@ struct { | |
5746 | void (*cache_handle)(FILE *f); | |
5747 | FILE *f; | |
5748 | } cachelist[] = { | |
5749 | - { "auth.unix.ip", auth_unix_ip}, | |
5750 | - { "auth.unix.gid", auth_unix_gid}, | |
5751 | - { "nfsd.export", nfsd_export}, | |
5752 | - { "nfsd.fh", nfsd_fh}, | |
5753 | - { NULL, NULL } | |
5754 | + { "auth.unix.ip", auth_unix_ip, NULL}, | |
5755 | + { "auth.unix.gid", auth_unix_gid, NULL}, | |
5756 | + { "nfsd.export", nfsd_export, NULL}, | |
5757 | + { "nfsd.fh", nfsd_fh, NULL}, | |
5758 | + { NULL, NULL, NULL } | |
5759 | }; | |
5760 | ||
5761 | extern int manage_gids; | |
5762 | + | |
5763 | +/** | |
5764 | + * cache_open - prepare communications channels with kernel RPC caches | |
5765 | + * | |
5766 | + */ | |
5767 | void cache_open(void) | |
5768 | { | |
5769 | int i; | |
5770 | @@ -772,6 +839,10 @@ void cache_open(void) | |
5771 | } | |
5772 | } | |
5773 | ||
5774 | +/** | |
5775 | + * cache_set_fds - prepare cache file descriptors for one iteration of the service loop | |
5776 | + * @fdset: pointer to fd_set to prepare | |
5777 | + */ | |
5778 | void cache_set_fds(fd_set *fdset) | |
5779 | { | |
5780 | int i; | |
5781 | @@ -781,6 +852,10 @@ void cache_set_fds(fd_set *fdset) | |
5782 | } | |
5783 | } | |
5784 | ||
5785 | +/** | |
5786 | + * cache_process_req - process any active cache file descriptors during service loop iteration | |
5787 | + * @fdset: pointer to fd_set to examine for activity | |
5788 | + */ | |
5789 | int cache_process_req(fd_set *readfds) | |
5790 | { | |
5791 | int i; | |
5792 | @@ -803,7 +878,7 @@ int cache_process_req(fd_set *readfds) | |
5793 | * % echo $domain $path $[now+30*60] $options $anonuid $anongid $fsid > /proc/net/rpc/nfsd.export/channel | |
5794 | */ | |
5795 | ||
5796 | -int cache_export_ent(char *domain, struct exportent *exp, char *path) | |
5797 | +static int cache_export_ent(char *domain, struct exportent *exp, char *path) | |
5798 | { | |
5799 | int err; | |
5800 | FILE *f = fopen("/proc/net/rpc/nfsd.export/channel", "w"); | |
5801 | @@ -824,8 +899,8 @@ int cache_export_ent(char *domain, struct exportent *exp, char *path) | |
5802 | * and export them with the same options | |
5803 | */ | |
5804 | struct stat stb; | |
5805 | - int l = strlen(exp->e_path); | |
5806 | - int dev; | |
5807 | + size_t l = strlen(exp->e_path); | |
5808 | + __dev_t dev; | |
5809 | ||
5810 | if (strlen(path) <= l || path[l] != '/' || | |
5811 | strncmp(exp->e_path, path, l) != 0) | |
5812 | @@ -861,8 +936,14 @@ int cache_export_ent(char *domain, struct exportent *exp, char *path) | |
5813 | return err; | |
5814 | } | |
5815 | ||
5816 | +/** | |
5817 | + * cache_export - Inform kernel of a new nfs_export | |
5818 | + * @exp: target nfs_export | |
5819 | + * @path: NUL-terminated C string containing export path | |
5820 | + */ | |
5821 | int cache_export(nfs_export *exp, char *path) | |
5822 | { | |
5823 | + char buf[INET6_ADDRSTRLEN]; | |
5824 | int err; | |
5825 | FILE *f; | |
5826 | ||
5827 | @@ -870,8 +951,10 @@ int cache_export(nfs_export *exp, char *path) | |
5828 | if (!f) | |
5829 | return -1; | |
5830 | ||
5831 | + | |
5832 | qword_print(f, "nfsd"); | |
5833 | - qword_print(f, inet_ntoa(exp->m_client->m_addrlist[0])); | |
5834 | + qword_print(f, | |
5835 | + host_ntop(get_addrlist(exp->m_client, 0), buf, sizeof(buf))); | |
5836 | qword_printint(f, time(0)+30*60); | |
5837 | qword_print(f, exp->m_client->m_hostname); | |
5838 | err = qword_eol(f); | |
5839 | @@ -883,7 +966,14 @@ int cache_export(nfs_export *exp, char *path) | |
5840 | return err; | |
5841 | } | |
5842 | ||
5843 | -/* Get a filehandle. | |
5844 | +/** | |
5845 | + * cache_get_filehandle - given an nfs_export, get its root filehandle | |
5846 | + * @exp: target nfs_export | |
5847 | + * @len: length of requested file handle | |
5848 | + * @p: NUL-terminated C string containing export path | |
5849 | + * | |
5850 | + * Returns pointer to NFS file handle of root directory of export | |
5851 | + * | |
5852 | * { | |
5853 | * echo $domain $path $length | |
5854 | * read filehandle <&0 | |
5855 | @@ -917,4 +1007,3 @@ cache_get_filehandle(nfs_export *exp, int len, char *p) | |
5856 | fh.fh_size = qword_get(&bp, (char *)fh.fh_handle, NFS3_FHSIZE); | |
5857 | return &fh; | |
5858 | } | |
5859 | - | |
5860 | diff --git a/utils/mountd/fsloc.c b/utils/mountd/fsloc.c | |
5861 | index 5b094b0..e2add2d 100644 | |
5862 | --- a/utils/mountd/fsloc.c | |
5863 | +++ b/utils/mountd/fsloc.c | |
5864 | @@ -146,7 +146,7 @@ static struct servers *method_list(char *data) | |
5865 | } | |
5866 | ||
5867 | /* Returns appropriately filled struct servers, or NULL if had a problem */ | |
5868 | -struct servers *replicas_lookup(int method, char *data, char *key) | |
5869 | +struct servers *replicas_lookup(int method, char *data) | |
5870 | { | |
5871 | struct servers *sp=NULL; | |
5872 | switch(method) { | |
5873 | diff --git a/utils/mountd/fsloc.h b/utils/mountd/fsloc.h | |
5874 | index 8296d1c..1605df4 100644 | |
5875 | --- a/utils/mountd/fsloc.h | |
5876 | +++ b/utils/mountd/fsloc.h | |
5877 | @@ -44,7 +44,7 @@ struct servers { | |
5878 | int h_referral; /* 0=replica, 1=referral */ | |
5879 | }; | |
5880 | ||
5881 | -struct servers *replicas_lookup(int method, char *data, char *key); | |
5882 | +struct servers *replicas_lookup(int method, char *data); | |
5883 | void release_replicas(struct servers *server); | |
5884 | ||
5885 | #endif /* FSLOC_H */ | |
5886 | diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c | |
5887 | index a0a1f2d..d309950 100644 | |
5888 | --- a/utils/mountd/mountd.c | |
5889 | +++ b/utils/mountd/mountd.c | |
5890 | @@ -28,10 +28,6 @@ | |
5891 | #include "rpcmisc.h" | |
5892 | #include "pseudoflavors.h" | |
5893 | ||
5894 | -extern void cache_open(void); | |
5895 | -extern struct nfs_fh_len *cache_get_filehandle(nfs_export *exp, int len, char *p); | |
5896 | -extern int cache_export(nfs_export *exp, char *path); | |
5897 | - | |
5898 | extern void my_svc_run(void); | |
5899 | ||
5900 | static void usage(const char *, int exitcode); | |
5901 | @@ -75,17 +71,40 @@ static struct option longopts[] = | |
5902 | { NULL, 0, 0, 0 } | |
5903 | }; | |
5904 | ||
5905 | -static int nfs_version = -1; | |
5906 | +#define NFSVERSBIT(vers) (0x1 << (vers - 1)) | |
5907 | +#define NFSVERSBIT_ALL (NFSVERSBIT(2) | NFSVERSBIT(3) | NFSVERSBIT(4)) | |
5908 | + | |
5909 | +static int nfs_version = NFSVERSBIT_ALL; | |
5910 | + | |
5911 | +static int version2(void) | |
5912 | +{ | |
5913 | + return nfs_version & NFSVERSBIT(2); | |
5914 | +} | |
5915 | + | |
5916 | +static int version3(void) | |
5917 | +{ | |
5918 | + return nfs_version & NFSVERSBIT(3); | |
5919 | +} | |
5920 | + | |
5921 | +static int version23(void) | |
5922 | +{ | |
5923 | + return nfs_version & (NFSVERSBIT(2) | NFSVERSBIT(3)); | |
5924 | +} | |
5925 | + | |
5926 | +static int version_any(void) | |
5927 | +{ | |
5928 | + return nfs_version & NFSVERSBIT_ALL; | |
5929 | +} | |
5930 | ||
5931 | static void | |
5932 | unregister_services (void) | |
5933 | { | |
5934 | - if (nfs_version & 0x1) | |
5935 | - pmap_unset (MOUNTPROG, MOUNTVERS); | |
5936 | - if (nfs_version & (0x1 << 1)) | |
5937 | - pmap_unset (MOUNTPROG, MOUNTVERS_POSIX); | |
5938 | - if (nfs_version & (0x1 << 2)) | |
5939 | - pmap_unset (MOUNTPROG, MOUNTVERS_NFSV3); | |
5940 | + if (version2()) { | |
5941 | + nfs_svc_unregister(MOUNTPROG, MOUNTVERS); | |
5942 | + nfs_svc_unregister(MOUNTPROG, MOUNTVERS_POSIX); | |
5943 | + } | |
5944 | + if (version3()) | |
5945 | + nfs_svc_unregister(MOUNTPROG, MOUNTVERS_NFSV3); | |
5946 | } | |
5947 | ||
5948 | static void | |
5949 | @@ -192,17 +211,28 @@ sig_hup (int sig) | |
5950 | } | |
5951 | ||
5952 | bool_t | |
5953 | -mount_null_1_svc(struct svc_req *rqstp, void *argp, void *resp) | |
5954 | +mount_null_1_svc(struct svc_req *rqstp, void *UNUSED(argp), | |
5955 | + void *UNUSED(resp)) | |
5956 | { | |
5957 | + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); | |
5958 | + char buf[INET6_ADDRSTRLEN]; | |
5959 | + | |
5960 | + xlog(D_CALL, "Received NULL request from %s", | |
5961 | + host_ntop(sap, buf, sizeof(buf))); | |
5962 | + | |
5963 | return 1; | |
5964 | } | |
5965 | ||
5966 | bool_t | |
5967 | mount_mnt_1_svc(struct svc_req *rqstp, dirpath *path, fhstatus *res) | |
5968 | { | |
5969 | + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); | |
5970 | + char buf[INET6_ADDRSTRLEN]; | |
5971 | struct nfs_fh_len *fh; | |
5972 | ||
5973 | - xlog(D_CALL, "MNT1(%s) called", *path); | |
5974 | + xlog(D_CALL, "Received MNT1(%s) request from %s", *path, | |
5975 | + host_ntop(sap, buf, sizeof(buf))); | |
5976 | + | |
5977 | fh = get_rootfh(rqstp, path, NULL, &res->fhs_status, 0); | |
5978 | if (fh) | |
5979 | memcpy(&res->fhstatus_u.fhs_fhandle, fh->fh_handle, 32); | |
5980 | @@ -210,23 +240,27 @@ mount_mnt_1_svc(struct svc_req *rqstp, dirpath *path, fhstatus *res) | |
5981 | } | |
5982 | ||
5983 | bool_t | |
5984 | -mount_dump_1_svc(struct svc_req *rqstp, void *argp, mountlist *res) | |
5985 | +mount_dump_1_svc(struct svc_req *rqstp, void *UNUSED(argp), mountlist *res) | |
5986 | { | |
5987 | - struct sockaddr_in *addr = nfs_getrpccaller_in(rqstp->rq_xprt); | |
5988 | + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); | |
5989 | + char buf[INET6_ADDRSTRLEN]; | |
5990 | + | |
5991 | + xlog(D_CALL, "Received DUMP request from %s", | |
5992 | + host_ntop(sap, buf, sizeof(buf))); | |
5993 | ||
5994 | - xlog(D_CALL, "dump request from %s.", inet_ntoa(addr->sin_addr)); | |
5995 | *res = mountlist_list(); | |
5996 | ||
5997 | return 1; | |
5998 | } | |
5999 | ||
6000 | bool_t | |
6001 | -mount_umnt_1_svc(struct svc_req *rqstp, dirpath *argp, void *resp) | |
6002 | +mount_umnt_1_svc(struct svc_req *rqstp, dirpath *argp, void *UNUSED(resp)) | |
6003 | { | |
6004 | - struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt); | |
6005 | + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); | |
6006 | nfs_export *exp; | |
6007 | char *p = *argp; | |
6008 | char rpath[MAXPATHLEN+1]; | |
6009 | + char buf[INET6_ADDRSTRLEN]; | |
6010 | ||
6011 | if (*p == '\0') | |
6012 | p = "/"; | |
6013 | @@ -236,41 +270,57 @@ mount_umnt_1_svc(struct svc_req *rqstp, dirpath *argp, void *resp) | |
6014 | p = rpath; | |
6015 | } | |
6016 | ||
6017 | - if (!(exp = auth_authenticate("unmount", sin, p))) { | |
6018 | + xlog(D_CALL, "Received UMNT(%s) request from %s", p, | |
6019 | + host_ntop(sap, buf, sizeof(buf))); | |
6020 | + | |
6021 | + exp = auth_authenticate("unmount", sap, p); | |
6022 | + if (exp == NULL) | |
6023 | return 1; | |
6024 | - } | |
6025 | ||
6026 | - mountlist_del(inet_ntoa(sin->sin_addr), p); | |
6027 | + mountlist_del(host_ntop(sap, buf, sizeof(buf)), p); | |
6028 | return 1; | |
6029 | } | |
6030 | ||
6031 | bool_t | |
6032 | -mount_umntall_1_svc(struct svc_req *rqstp, void *argp, void *resp) | |
6033 | +mount_umntall_1_svc(struct svc_req *rqstp, void *UNUSED(argp), | |
6034 | + void *UNUSED(resp)) | |
6035 | { | |
6036 | + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); | |
6037 | + char buf[INET6_ADDRSTRLEN]; | |
6038 | + | |
6039 | + xlog(D_CALL, "Received UMNTALL request from %s", | |
6040 | + host_ntop(sap, buf, sizeof(buf))); | |
6041 | + | |
6042 | /* Reload /etc/xtab if necessary */ | |
6043 | auth_reload(); | |
6044 | ||
6045 | - mountlist_del_all(nfs_getrpccaller_in(rqstp->rq_xprt)); | |
6046 | + mountlist_del_all(nfs_getrpccaller(rqstp->rq_xprt)); | |
6047 | return 1; | |
6048 | } | |
6049 | ||
6050 | bool_t | |
6051 | -mount_export_1_svc(struct svc_req *rqstp, void *argp, exports *resp) | |
6052 | +mount_export_1_svc(struct svc_req *rqstp, void *UNUSED(argp), exports *resp) | |
6053 | { | |
6054 | - struct sockaddr_in *addr = nfs_getrpccaller_in(rqstp->rq_xprt); | |
6055 | + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); | |
6056 | + char buf[INET6_ADDRSTRLEN]; | |
6057 | + | |
6058 | + xlog(D_CALL, "Received EXPORT request from %s.", | |
6059 | + host_ntop(sap, buf, sizeof(buf))); | |
6060 | ||
6061 | - xlog(D_CALL, "export request from %s.", inet_ntoa(addr->sin_addr)); | |
6062 | *resp = get_exportlist(); | |
6063 | ||
6064 | return 1; | |
6065 | } | |
6066 | ||
6067 | bool_t | |
6068 | -mount_exportall_1_svc(struct svc_req *rqstp, void *argp, exports *resp) | |
6069 | +mount_exportall_1_svc(struct svc_req *rqstp, void *UNUSED(argp), exports *resp) | |
6070 | { | |
6071 | - struct sockaddr_in *addr = nfs_getrpccaller_in(rqstp->rq_xprt); | |
6072 | + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); | |
6073 | + char buf[INET6_ADDRSTRLEN]; | |
6074 | + | |
6075 | + xlog(D_CALL, "Received EXPORTALL request from %s.", | |
6076 | + host_ntop(sap, buf, sizeof(buf))); | |
6077 | ||
6078 | - xlog(D_CALL, "exportall request from %s.", inet_ntoa(addr->sin_addr)); | |
6079 | *resp = get_exportlist(); | |
6080 | ||
6081 | return 1; | |
6082 | @@ -290,11 +340,12 @@ mount_exportall_1_svc(struct svc_req *rqstp, void *argp, exports *resp) | |
6083 | bool_t | |
6084 | mount_pathconf_2_svc(struct svc_req *rqstp, dirpath *path, ppathcnf *res) | |
6085 | { | |
6086 | - struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt); | |
6087 | + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); | |
6088 | struct stat stb; | |
6089 | nfs_export *exp; | |
6090 | char rpath[MAXPATHLEN+1]; | |
6091 | char *p = *path; | |
6092 | + char buf[INET6_ADDRSTRLEN]; | |
6093 | ||
6094 | memset(res, 0, sizeof(*res)); | |
6095 | ||
6096 | @@ -310,11 +361,14 @@ mount_pathconf_2_svc(struct svc_req *rqstp, dirpath *path, ppathcnf *res) | |
6097 | p = rpath; | |
6098 | } | |
6099 | ||
6100 | + xlog(D_CALL, "Received PATHCONF(%s) request from %s", p, | |
6101 | + host_ntop(sap, buf, sizeof(buf))); | |
6102 | + | |
6103 | /* Now authenticate the intruder... */ | |
6104 | - exp = auth_authenticate("pathconf", sin, p); | |
6105 | - if (!exp) { | |
6106 | + exp = auth_authenticate("pathconf", sap, p); | |
6107 | + if (exp == NULL) | |
6108 | return 1; | |
6109 | - } else if (stat(p, &stb) < 0) { | |
6110 | + else if (stat(p, &stb) < 0) { | |
6111 | xlog(L_WARNING, "can't stat exported dir %s: %s", | |
6112 | p, strerror(errno)); | |
6113 | return 1; | |
6114 | @@ -374,11 +428,15 @@ static void set_authflavors(struct mountres3_ok *ok, nfs_export *exp) | |
6115 | bool_t | |
6116 | mount_mnt_3_svc(struct svc_req *rqstp, dirpath *path, mountres3 *res) | |
6117 | { | |
6118 | + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); | |
6119 | struct mountres3_ok *ok = &res->mountres3_u.mountinfo; | |
6120 | + char buf[INET6_ADDRSTRLEN]; | |
6121 | nfs_export *exp; | |
6122 | struct nfs_fh_len *fh; | |
6123 | ||
6124 | - xlog(D_CALL, "MNT3(%s) called", *path); | |
6125 | + xlog(D_CALL, "Received MNT3(%s) request from %s", *path, | |
6126 | + host_ntop(sap, buf, sizeof(buf))); | |
6127 | + | |
6128 | fh = get_rootfh(rqstp, path, &exp, &res->fhs_status, 1); | |
6129 | if (!fh) | |
6130 | return 1; | |
6131 | @@ -393,12 +451,13 @@ static struct nfs_fh_len * | |
6132 | get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret, | |
6133 | mountstat3 *error, int v3) | |
6134 | { | |
6135 | - struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt); | |
6136 | + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); | |
6137 | struct stat stb, estb; | |
6138 | nfs_export *exp; | |
6139 | struct nfs_fh_len *fh; | |
6140 | char rpath[MAXPATHLEN+1]; | |
6141 | char *p = *path; | |
6142 | + char buf[INET6_ADDRSTRLEN]; | |
6143 | ||
6144 | if (*p == '\0') | |
6145 | p = "/"; | |
6146 | @@ -413,29 +472,29 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret, | |
6147 | } | |
6148 | ||
6149 | /* Now authenticate the intruder... */ | |
6150 | - exp = auth_authenticate("mount", sin, p); | |
6151 | - if (!exp) { | |
6152 | - *error = NFSERR_ACCES; | |
6153 | + exp = auth_authenticate("mount", sap, p); | |
6154 | + if (exp == NULL) { | |
6155 | + *error = MNT3ERR_ACCES; | |
6156 | return NULL; | |
6157 | } | |
6158 | if (stat(p, &stb) < 0) { | |
6159 | xlog(L_WARNING, "can't stat exported dir %s: %s", | |
6160 | p, strerror(errno)); | |
6161 | if (errno == ENOENT) | |
6162 | - *error = NFSERR_NOENT; | |
6163 | + *error = MNT3ERR_NOENT; | |
6164 | else | |
6165 | - *error = NFSERR_ACCES; | |
6166 | + *error = MNT3ERR_ACCES; | |
6167 | return NULL; | |
6168 | } | |
6169 | if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) { | |
6170 | xlog(L_WARNING, "%s is not a directory or regular file", p); | |
6171 | - *error = NFSERR_NOTDIR; | |
6172 | + *error = MNT3ERR_NOTDIR; | |
6173 | return NULL; | |
6174 | } | |
6175 | if (stat(exp->m_export.e_path, &estb) < 0) { | |
6176 | xlog(L_WARNING, "can't stat export point %s: %s", | |
6177 | p, strerror(errno)); | |
6178 | - *error = NFSERR_NOENT; | |
6179 | + *error = MNT3ERR_NOENT; | |
6180 | return NULL; | |
6181 | } | |
6182 | if (estb.st_dev != stb.st_dev | |
6183 | @@ -443,7 +502,7 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret, | |
6184 | || !(exp->m_export.e_flags & NFSEXP_CROSSMOUNT))) { | |
6185 | xlog(L_WARNING, "request to export directory %s below nearest filesystem %s", | |
6186 | p, exp->m_export.e_path); | |
6187 | - *error = NFSERR_ACCES; | |
6188 | + *error = MNT3ERR_ACCES; | |
6189 | return NULL; | |
6190 | } | |
6191 | if (exp->m_export.e_mountpoint && | |
6192 | @@ -452,7 +511,7 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret, | |
6193 | exp->m_export.e_path)) { | |
6194 | xlog(L_WARNING, "request to export an unmounted filesystem: %s", | |
6195 | p); | |
6196 | - *error = NFSERR_NOENT; | |
6197 | + *error = MNT3ERR_NOENT; | |
6198 | return NULL; | |
6199 | } | |
6200 | ||
6201 | @@ -463,12 +522,12 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret, | |
6202 | */ | |
6203 | ||
6204 | if (cache_export(exp, p)) { | |
6205 | - *error = NFSERR_ACCES; | |
6206 | + *error = MNT3ERR_ACCES; | |
6207 | return NULL; | |
6208 | } | |
6209 | fh = cache_get_filehandle(exp, v3?64:32, p); | |
6210 | if (fh == NULL) { | |
6211 | - *error = NFSERR_ACCES; | |
6212 | + *error = MNT3ERR_ACCES; | |
6213 | return NULL; | |
6214 | } | |
6215 | } else { | |
6216 | @@ -482,13 +541,13 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret, | |
6217 | xtab_append(exp); | |
6218 | ||
6219 | if (v3) | |
6220 | - fh = getfh_size ((struct sockaddr *) sin, p, 64); | |
6221 | + fh = getfh_size((struct sockaddr_in *)sap, p, 64); | |
6222 | if (!v3 || (fh == NULL && errno == EINVAL)) { | |
6223 | /* We first try the new nfs syscall. */ | |
6224 | - fh = getfh ((struct sockaddr *) sin, p); | |
6225 | + fh = getfh((struct sockaddr_in *)sap, p); | |
6226 | if (fh == NULL && errno == EINVAL) | |
6227 | /* Let's try the old one. */ | |
6228 | - fh = getfh_old ((struct sockaddr *) sin, | |
6229 | + fh = getfh_old((struct sockaddr_in *)sap, | |
6230 | stb.st_dev, stb.st_ino); | |
6231 | } | |
6232 | if (fh == NULL && !did_export) { | |
6233 | @@ -498,12 +557,12 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret, | |
6234 | ||
6235 | if (fh == NULL) { | |
6236 | xlog(L_WARNING, "getfh failed: %s", strerror(errno)); | |
6237 | - *error = NFSERR_ACCES; | |
6238 | + *error = MNT3ERR_ACCES; | |
6239 | return NULL; | |
6240 | } | |
6241 | } | |
6242 | - *error = NFS_OK; | |
6243 | - mountlist_add(inet_ntoa(sin->sin_addr), p); | |
6244 | + *error = MNT_OK; | |
6245 | + mountlist_add(host_ntop(sap, buf, sizeof(buf)), p); | |
6246 | if (expret) | |
6247 | *expret = exp; | |
6248 | return fh; | |
6249 | @@ -536,22 +595,21 @@ static void free_exportlist(exports *elist) | |
6250 | ||
6251 | static void prune_clients(nfs_export *exp, struct exportnode *e) | |
6252 | { | |
6253 | - struct hostent *hp; | |
6254 | + struct addrinfo *ai = NULL; | |
6255 | struct groupnode *c, **cp; | |
6256 | ||
6257 | cp = &e->ex_groups; | |
6258 | while ((c = *cp) != NULL) { | |
6259 | if (client_gettype(c->gr_name) == MCL_FQDN | |
6260 | - && (hp = gethostbyname(c->gr_name))) { | |
6261 | - hp = hostent_dup(hp); | |
6262 | - if (client_check(exp->m_client, hp)) { | |
6263 | + && (ai = host_addrinfo(c->gr_name))) { | |
6264 | + if (client_check(exp->m_client, ai)) { | |
6265 | *cp = c->gr_next; | |
6266 | xfree(c->gr_name); | |
6267 | xfree(c); | |
6268 | - xfree (hp); | |
6269 | + freeaddrinfo(ai); | |
6270 | continue; | |
6271 | } | |
6272 | - xfree (hp); | |
6273 | + freeaddrinfo(ai); | |
6274 | } | |
6275 | cp = &(c->gr_next); | |
6276 | } | |
6277 | @@ -634,13 +692,22 @@ main(int argc, char **argv) | |
6278 | { | |
6279 | char *export_file = _PATH_EXPORTS; | |
6280 | char *state_dir = NFS_STATEDIR; | |
6281 | + char *progname; | |
6282 | + unsigned int listeners = 0; | |
6283 | int foreground = 0; | |
6284 | int port = 0; | |
6285 | int descriptors = 0; | |
6286 | int c; | |
6287 | + int vers; | |
6288 | struct sigaction sa; | |
6289 | struct rlimit rlim; | |
6290 | ||
6291 | + /* Set the basename */ | |
6292 | + if ((progname = strrchr(argv[0], '/')) != NULL) | |
6293 | + progname++; | |
6294 | + else | |
6295 | + progname = argv[0]; | |
6296 | + | |
6297 | /* Parse the command line options and arguments. */ | |
6298 | opterr = 0; | |
6299 | while ((c = getopt_long(argc, argv, "o:nFd:f:p:P:hH:N:V:vrs:t:g", longopts, NULL)) != EOF) | |
6300 | @@ -652,8 +719,8 @@ main(int argc, char **argv) | |
6301 | descriptors = atoi(optarg); | |
6302 | if (descriptors <= 0) { | |
6303 | fprintf(stderr, "%s: bad descriptors: %s\n", | |
6304 | - argv [0], optarg); | |
6305 | - usage(argv [0], 1); | |
6306 | + progname, optarg); | |
6307 | + usage(progname, 1); | |
6308 | } | |
6309 | break; | |
6310 | case 'F': | |
6311 | @@ -669,19 +736,25 @@ main(int argc, char **argv) | |
6312 | ha_callout_prog = optarg; | |
6313 | break; | |
6314 | case 'h': | |
6315 | - usage(argv [0], 0); | |
6316 | + usage(progname, 0); | |
6317 | break; | |
6318 | case 'P': /* XXX for nfs-server compatibility */ | |
6319 | case 'p': | |
6320 | port = atoi(optarg); | |
6321 | if (port <= 0 || port > 65535) { | |
6322 | fprintf(stderr, "%s: bad port number: %s\n", | |
6323 | - argv [0], optarg); | |
6324 | - usage(argv [0], 1); | |
6325 | + progname, optarg); | |
6326 | + usage(progname, 1); | |
6327 | } | |
6328 | break; | |
6329 | case 'N': | |
6330 | - nfs_version &= ~(1 << (atoi (optarg) - 1)); | |
6331 | + vers = atoi(optarg); | |
6332 | + if (vers < 2 || vers > 4) { | |
6333 | + fprintf(stderr, "%s: bad version number: %s\n", | |
6334 | + argv[0], optarg); | |
6335 | + usage(argv[0], 1); | |
6336 | + } | |
6337 | + nfs_version &= ~NFSVERSBIT(vers); | |
6338 | break; | |
6339 | case 'n': | |
6340 | _rpcfdtype = SOCK_DGRAM; | |
6341 | @@ -692,7 +765,7 @@ main(int argc, char **argv) | |
6342 | case 's': | |
6343 | if ((state_dir = xstrdup(optarg)) == NULL) { | |
6344 | fprintf(stderr, "%s: xstrdup(%s) failed!\n", | |
6345 | - argv[0], optarg); | |
6346 | + progname, optarg); | |
6347 | exit(1); | |
6348 | } | |
6349 | break; | |
6350 | @@ -700,31 +773,37 @@ main(int argc, char **argv) | |
6351 | num_threads = atoi (optarg); | |
6352 | break; | |
6353 | case 'V': | |
6354 | - nfs_version |= 1 << (atoi (optarg) - 1); | |
6355 | + vers = atoi(optarg); | |
6356 | + if (vers < 2 || vers > 4) { | |
6357 | + fprintf(stderr, "%s: bad version number: %s\n", | |
6358 | + argv[0], optarg); | |
6359 | + usage(argv[0], 1); | |
6360 | + } | |
6361 | + nfs_version |= NFSVERSBIT(vers); | |
6362 | break; | |
6363 | case 'v': | |
6364 | - printf("kmountd %s\n", VERSION); | |
6365 | + printf("%s version " VERSION "\n", progname); | |
6366 | exit(0); | |
6367 | case 0: | |
6368 | break; | |
6369 | case '?': | |
6370 | default: | |
6371 | - usage(argv [0], 1); | |
6372 | + usage(progname, 1); | |
6373 | } | |
6374 | ||
6375 | /* No more arguments allowed. */ | |
6376 | - if (optind != argc || !(nfs_version & 0x7)) | |
6377 | - usage(argv [0], 1); | |
6378 | + if (optind != argc || !version_any()) | |
6379 | + usage(progname, 1); | |
6380 | ||
6381 | if (chdir(state_dir)) { | |
6382 | fprintf(stderr, "%s: chdir(%s) failed: %s\n", | |
6383 | - argv [0], state_dir, strerror(errno)); | |
6384 | + progname, state_dir, strerror(errno)); | |
6385 | exit(1); | |
6386 | } | |
6387 | ||
6388 | if (getrlimit (RLIMIT_NOFILE, &rlim) != 0) | |
6389 | fprintf(stderr, "%s: getrlimit (RLIMIT_NOFILE) failed: %s\n", | |
6390 | - argv [0], strerror(errno)); | |
6391 | + progname, strerror(errno)); | |
6392 | else { | |
6393 | /* glibc sunrpc code dies if getdtablesize > FD_SETSIZE */ | |
6394 | if ((descriptors == 0 && rlim.rlim_cur > FD_SETSIZE) || | |
6395 | @@ -734,14 +813,14 @@ main(int argc, char **argv) | |
6396 | rlim.rlim_cur = descriptors; | |
6397 | if (setrlimit (RLIMIT_NOFILE, &rlim) != 0) { | |
6398 | fprintf(stderr, "%s: setrlimit (RLIMIT_NOFILE) failed: %s\n", | |
6399 | - argv [0], strerror(errno)); | |
6400 | + progname, strerror(errno)); | |
6401 | exit(1); | |
6402 | } | |
6403 | } | |
6404 | } | |
6405 | /* Initialize logging. */ | |
6406 | if (!foreground) xlog_stderr(0); | |
6407 | - xlog_open("mountd"); | |
6408 | + xlog_open(progname); | |
6409 | ||
6410 | sa.sa_handler = SIG_IGN; | |
6411 | sa.sa_flags = 0; | |
6412 | @@ -761,15 +840,17 @@ main(int argc, char **argv) | |
6413 | if (new_cache) | |
6414 | cache_open(); | |
6415 | ||
6416 | - if (nfs_version & 0x1) | |
6417 | - rpc_init("mountd", MOUNTPROG, MOUNTVERS, | |
6418 | - mount_dispatch, port); | |
6419 | - if (nfs_version & (0x1 << 1)) | |
6420 | - rpc_init("mountd", MOUNTPROG, MOUNTVERS_POSIX, | |
6421 | - mount_dispatch, port); | |
6422 | - if (nfs_version & (0x1 << 2)) | |
6423 | - rpc_init("mountd", MOUNTPROG, MOUNTVERS_NFSV3, | |
6424 | - mount_dispatch, port); | |
6425 | + if (version2()) { | |
6426 | + listeners += nfs_svc_create("mountd", MOUNTPROG, | |
6427 | + MOUNTVERS, mount_dispatch, port); | |
6428 | + listeners += nfs_svc_create("mountd", MOUNTPROG, | |
6429 | + MOUNTVERS_POSIX, mount_dispatch, port); | |
6430 | + } | |
6431 | + if (version3()) | |
6432 | + listeners += nfs_svc_create("mountd", MOUNTPROG, | |
6433 | + MOUNTVERS_NFSV3, mount_dispatch, port); | |
6434 | + if (version23() && listeners == 0) | |
6435 | + xlog(L_FATAL, "mountd: could not create listeners\n"); | |
6436 | ||
6437 | sa.sa_handler = killer; | |
6438 | sigaction(SIGINT, &sa, NULL); | |
6439 | @@ -810,9 +891,11 @@ main(int argc, char **argv) | |
6440 | if (num_threads > 1) | |
6441 | fork_workers(); | |
6442 | ||
6443 | + xlog(L_NOTICE, "Version " VERSION " starting"); | |
6444 | my_svc_run(); | |
6445 | ||
6446 | - xlog(L_ERROR, "Ack! Gack! svc_run returned!\n"); | |
6447 | + xlog(L_ERROR, "RPC service loop terminated unexpectedly. Exiting...\n"); | |
6448 | + unregister_services(); | |
6449 | exit(1); | |
6450 | } | |
6451 | ||
6452 | diff --git a/utils/mountd/mountd.h b/utils/mountd/mountd.h | |
6453 | index 31bacb5..4c184d2 100644 | |
6454 | --- a/utils/mountd/mountd.h | |
6455 | +++ b/utils/mountd/mountd.h | |
6456 | @@ -41,14 +41,19 @@ bool_t mount_mnt_3_svc(struct svc_req *, dirpath *, mountres3 *); | |
6457 | void mount_dispatch(struct svc_req *, SVCXPRT *); | |
6458 | void auth_init(char *export_file); | |
6459 | unsigned int auth_reload(void); | |
6460 | -nfs_export * auth_authenticate(char *what, struct sockaddr_in *sin, | |
6461 | - char *path); | |
6462 | +nfs_export * auth_authenticate(const char *what, | |
6463 | + const struct sockaddr *caller, | |
6464 | + const char *path); | |
6465 | void auth_export(nfs_export *exp); | |
6466 | ||
6467 | void mountlist_add(char *host, const char *path); | |
6468 | void mountlist_del(char *host, const char *path); | |
6469 | -void mountlist_del_all(struct sockaddr_in *sin); | |
6470 | +void mountlist_del_all(const struct sockaddr *sap); | |
6471 | mountlist mountlist_list(void); | |
6472 | ||
6473 | +void cache_open(void); | |
6474 | +struct nfs_fh_len * | |
6475 | + cache_get_filehandle(nfs_export *exp, int len, char *p); | |
6476 | +int cache_export(nfs_export *exp, char *path); | |
6477 | ||
6478 | #endif /* MOUNTD_H */ | |
6479 | diff --git a/utils/mountd/mountd.man b/utils/mountd/mountd.man | |
6480 | index bfa06e0..4bb96e8 100644 | |
6481 | --- a/utils/mountd/mountd.man | |
6482 | +++ b/utils/mountd/mountd.man | |
6483 | @@ -1,9 +1,9 @@ | |
6484 | -.\" | |
6485 | -.\" mountd(8) | |
6486 | +.\"@(#)rpc.mountd.8" | |
6487 | .\" | |
6488 | .\" Copyright (C) 1999 Olaf Kirch <okir@monad.swb.de> | |
6489 | .\" Modified by Paul Clements, 2004. | |
6490 | -.TH rpc.mountd 8 "31 Aug 2004" | |
6491 | +.\" | |
6492 | +.TH rpc.mountd 8 "31 Dec 2009" | |
6493 | .SH NAME | |
6494 | rpc.mountd \- NFS mount daemon | |
6495 | .SH SYNOPSIS | |
6496 | @@ -11,48 +11,73 @@ rpc.mountd \- NFS mount daemon | |
6497 | .SH DESCRIPTION | |
6498 | The | |
6499 | .B rpc.mountd | |
6500 | -program implements the NFS mount protocol. When receiving a MOUNT | |
6501 | -request from an NFS client, it checks the request against the list of | |
6502 | -currently exported file systems. If the client is permitted to mount | |
6503 | -the file system, | |
6504 | -.B rpc.mountd | |
6505 | -obtains a file handle for requested directory and returns it to | |
6506 | -the client. | |
6507 | -.SS Exporting NFS File Systems | |
6508 | -Making file systems available to NFS clients is called | |
6509 | -.IR exporting . | |
6510 | -.P | |
6511 | -Usually, a file system and the hosts it should be made available to | |
6512 | -are listed in the | |
6513 | -.B /etc/exports | |
6514 | -file, and invoking | |
6515 | -.B exportfs -a | |
6516 | -whenever the system is booted. The | |
6517 | +daemon implements the server side of the NFS MOUNT protocol, | |
6518 | +an NFS side protocol used by NFS version 2 [RFC1094] and NFS version 3 [RFC1813]. | |
6519 | +.PP | |
6520 | +An NFS server maintains a table of local physical file systems | |
6521 | +that are accessible to NFS clients. | |
6522 | +Each file system in this table is referred to as an | |
6523 | +.IR "exported file system" , | |
6524 | +or | |
6525 | +.IR export , | |
6526 | +for short. | |
6527 | +.PP | |
6528 | +Each file system in the export table has an access control list. | |
6529 | +.B rpc.mountd | |
6530 | +uses these access control lists to determine | |
6531 | +whether an NFS client is permitted to access a given file system. | |
6532 | +For details on how to manage your NFS server's export table, see the | |
6533 | +.BR exports (5) | |
6534 | +and | |
6535 | .BR exportfs (8) | |
6536 | -command makes export information available to both the kernel NFS | |
6537 | -server module and the | |
6538 | -.B rpc.mountd | |
6539 | -daemon. | |
6540 | -.P | |
6541 | -Alternatively, you can export individual directories temporarily | |
6542 | -using | |
6543 | -.BR exportfs 's | |
6544 | -.IB host : /directory | |
6545 | -syntax. | |
6546 | +man pages. | |
6547 | +.SS Mounting exported NFS File Systems | |
6548 | +The NFS MOUNT protocol has several procedures. | |
6549 | +The most important of these are | |
6550 | +MNT (mount an export) and | |
6551 | +UMNT (unmount an export). | |
6552 | +.PP | |
6553 | +A MNT request has two arguments: an explicit argument that | |
6554 | +contains the pathname of the root directory of the export to be mounted, | |
6555 | +and an implicit argument that is the sender's IP address. | |
6556 | +.PP | |
6557 | +When receiving a MNT request from an NFS client, | |
6558 | +.B rpc.mountd | |
6559 | +checks both the pathname and the sender's IP address against its export table. | |
6560 | +If the sender is permitted to access the requested export, | |
6561 | +.B rpc.mountd | |
6562 | +returns an NFS file handle for the export's root directory to the client. | |
6563 | +The client can then use the root file handle and NFS LOOKUP requests | |
6564 | +to navigate the directory structure of the export. | |
6565 | .SS The rmtab File | |
6566 | -For every mount request received from an NFS client, | |
6567 | -.B rpc.mountd | |
6568 | -adds an entry to the | |
6569 | -.B /var/lib/nfs/rmtab | |
6570 | -file. When receiving an unmount request, that entry is removed. | |
6571 | -.P | |
6572 | -However, this file is mostly ornamental. One, the client can continue | |
6573 | -to use the file handle even after calling | |
6574 | -.B rpc.mountd 's | |
6575 | -UMOUNT procedure. And two, if a client reboots without notifying | |
6576 | -.B rpc.mountd , | |
6577 | -a stale entry will remain in | |
6578 | -.BR rmtab . | |
6579 | +The | |
6580 | +.B rpc.mountd | |
6581 | +daemon registers every successful MNT request by adding an entry to the | |
6582 | +.I /var/lib/nfs/rmtab | |
6583 | +file. | |
6584 | +When receivng a UMNT request from an NFS client, | |
6585 | +.B rpc.mountd | |
6586 | +simply removes the matching entry from | |
6587 | +.IR /var/lib/nfs/rmtab , | |
6588 | +as long as the access control list for that export allows that sender | |
6589 | +to access the export. | |
6590 | +.PP | |
6591 | +Clients can discover the list of file systems an NFS server is | |
6592 | +currently exporting, or the list of other clients that have mounted | |
6593 | +its exports, by using the | |
6594 | +.BR showmount (8) | |
6595 | +command. | |
6596 | +.BR showmount (8) | |
6597 | +uses other procedures in the NFS MOUNT protocol to report information | |
6598 | +about the server's exported file systems. | |
6599 | +.PP | |
6600 | +Note, however, that there is little to guarantee that the contents of | |
6601 | +.I /var/lib/nfs/rmtab | |
6602 | +are accurate. | |
6603 | +A client may continue accessing an export even after invoking UMNT. | |
6604 | +If the client reboots without sending a UMNT request, stale entries | |
6605 | +remain for that client in | |
6606 | +.IR /var/lib/nfs/rmtab . | |
6607 | .SH OPTIONS | |
6608 | .TP | |
6609 | .B \-d kind " or " \-\-debug kind | |
6610 | @@ -94,22 +119,25 @@ Don't advertise TCP for mount. | |
6611 | Ignored (compatibility with unfsd??). | |
6612 | .TP | |
6613 | .B \-p " or " \-\-port num | |
6614 | -Force | |
6615 | +Specifies the port number used for RPC listener sockets. | |
6616 | +If this option is not specified, | |
6617 | .B rpc.mountd | |
6618 | -to bind to the specified port num, instead of using the random port | |
6619 | -number assigned by the portmapper. | |
6620 | +chooses a random ephemeral port for each listener socket. | |
6621 | +.IP | |
6622 | +This option can be used to fix the port value of | |
6623 | +.BR rpc.mountd 's | |
6624 | +listeners when NFS MOUNT requests must traverse a firewall | |
6625 | +between clients and servers. | |
6626 | .TP | |
6627 | .B \-H " or " \-\-ha-callout prog | |
6628 | -Specify a high availability callout program, which will receive callouts | |
6629 | -for all client mount and unmount requests. This allows | |
6630 | -.B rpc.mountd | |
6631 | -to be used in a High Availability NFS (HA-NFS) environment. This callout is not | |
6632 | -needed (and should not be used) with 2.6 and later kernels (instead, | |
6633 | -mount the nfsd filesystem on | |
6634 | -.B /proc/fs/nfsd | |
6635 | -). | |
6636 | -The program will be called with 4 arguments. | |
6637 | -The first will be | |
6638 | +Specify a high availability callout program. | |
6639 | +This program receives callouts for all MOUNT and UNMOUNT requests. | |
6640 | +This allows | |
6641 | +.B rpc.mountd | |
6642 | +to be used in a High Availability NFS (HA-NFS) environment. | |
6643 | +.IP | |
6644 | +The callout program is run with 4 arguments. | |
6645 | +The first is | |
6646 | .B mount | |
6647 | or | |
6648 | .B unmount | |
6649 | @@ -118,19 +146,30 @@ The second will be the name of the client performing the mount. | |
6650 | The third will be the path that the client is mounting. | |
6651 | The last is the number of concurrent mounts that we believe the client | |
6652 | has of that path. | |
6653 | +.IP | |
6654 | +This callout is not needed with 2.6 and later kernels. | |
6655 | +Instead, mount the nfsd filesystem on | |
6656 | +.IR /proc/fs/nfsd . | |
6657 | .TP | |
6658 | .BI "\-s," "" " \-\-state\-directory\-path " directory | |
6659 | -specify a directory in which to place statd state information. | |
6660 | +Specify a directory in which to place statd state information. | |
6661 | If this option is not specified the default of | |
6662 | -.BR /var/lib/nfs | |
6663 | +.I /var/lib/nfs | |
6664 | is used. | |
6665 | .TP | |
6666 | .BI "\-r," "" " \-\-reverse\-lookup" | |
6667 | -mountd tracks IP addresses in the rmtab, and when a DUMP request is made (by | |
6668 | -someone running showmount -a, for instance), it returns IP addresses instead | |
6669 | -of hostnames by default. This option causes mountd to do a reverse | |
6670 | -lookup on each IP address and return that hostname instead. Enabling this can | |
6671 | -have a substantial negative effect on performance in some situations. | |
6672 | +.B rpc.mountd | |
6673 | +tracks IP addresses in the | |
6674 | +.I rmtab | |
6675 | +file. When a DUMP request is made (by | |
6676 | +someone running | |
6677 | +.BR "showmount -a" , | |
6678 | +for instance), it returns IP addresses instead | |
6679 | +of hostnames by default. This option causes | |
6680 | +.B rpc.mountd | |
6681 | +to perform a reverse lookup on each IP address and return that hostname instead. | |
6682 | +Enabling this can have a substantial negative effect on performance | |
6683 | +in some situations. | |
6684 | .TP | |
6685 | .BR "\-t N" " or " "\-\-num\-threads=N" | |
6686 | This option specifies the number of worker threads that rpc.mountd | |
6687 | @@ -162,41 +201,70 @@ If you use the | |
6688 | flag, then the list of group ids received from the client will be | |
6689 | replaced by a list of group ids determined by an appropriate lookup on | |
6690 | the server. Note that the 'primary' group id is not affected so a | |
6691 | -.I newgroup | |
6692 | +.B newgroup | |
6693 | command on the client will still be effective. This function requires | |
6694 | a Linux Kernel with version at least 2.6.21. | |
6695 | - | |
6696 | .SH TCP_WRAPPERS SUPPORT | |
6697 | -This | |
6698 | +You can protect your | |
6699 | .B rpc.mountd | |
6700 | -version is protected by the | |
6701 | +listeners using the | |
6702 | +.B tcp_wrapper | |
6703 | +library or | |
6704 | +.BR iptables (8). | |
6705 | +.PP | |
6706 | +Note that the | |
6707 | .B tcp_wrapper | |
6708 | -library. You have to give the clients access to | |
6709 | -.B rpc.mountd | |
6710 | -if they should be allowed to use it. To allow connects from clients of | |
6711 | -the .bar.com domain you could use the following line in /etc/hosts.allow: | |
6712 | - | |
6713 | -mountd: .bar.com | |
6714 | - | |
6715 | -You have to use the daemon name | |
6716 | +library supports only IPv4 networking. | |
6717 | +.PP | |
6718 | +Add the hostnames of NFS peers that are allowed to access | |
6719 | +.B rpc.mountd | |
6720 | +to | |
6721 | +.IR /etc/hosts.allow . | |
6722 | +Use the daemon name | |
6723 | .B mountd | |
6724 | -for the daemon name (even if the binary has a different name). | |
6725 | -.B Note: | |
6726 | -hostnames used in either access file will be ignored when | |
6727 | +even if the | |
6728 | +.B rpc.mountd | |
6729 | +binary has a different name. | |
6730 | +.PP | |
6731 | +Hostnames used in either access file will be ignored when | |
6732 | they can not be resolved into IP addresses. | |
6733 | - | |
6734 | -For further information please have a look at the | |
6735 | +For further information see the | |
6736 | .BR tcpd (8) | |
6737 | and | |
6738 | .BR hosts_access (5) | |
6739 | -manual pages. | |
6740 | +man pages. | |
6741 | +.SS IPv6 and TI-RPC support | |
6742 | +TI-RPC is a pre-requisite for supporting NFS on IPv6. | |
6743 | +If TI-RPC support is built into | |
6744 | +.BR rpc.mountd , | |
6745 | +it attempts to start listeners on network transports marked 'visible' in | |
6746 | +.IR /etc/netconfig . | |
6747 | +As long as at least one network transport listener starts successfully, | |
6748 | +.B rpc.mountd | |
6749 | +will operate. | |
6750 | +.SH FILES | |
6751 | +.TP 2.5i | |
6752 | +.I /etc/exports | |
6753 | +input file for | |
6754 | +.BR exportfs , | |
6755 | +listing exports, export options, and access control lists | |
6756 | +.TP 2.5i | |
6757 | +.I /var/lib/nfs/rmtab | |
6758 | +table of clients accessing server's exports | |
6759 | .SH SEE ALSO | |
6760 | -.BR rpc.nfsd (8), | |
6761 | .BR exportfs (8), | |
6762 | .BR exports (5), | |
6763 | -.BR rpc.rquotad (8). | |
6764 | -.SH FILES | |
6765 | -.BR /etc/exports , | |
6766 | -.BR /var/lib/nfs/xtab . | |
6767 | +.BR showmount (8), | |
6768 | +.BR rpc.nfsd (8), | |
6769 | +.BR rpc.rquotad (8), | |
6770 | +.BR nfs (5), | |
6771 | +.BR tcpd (8), | |
6772 | +.BR hosts_access (5), | |
6773 | +.BR iptables (8), | |
6774 | +.BR netconfig (5) | |
6775 | +.sp | |
6776 | +RFC 1094 - "NFS: Network File System Protocol Specification" | |
6777 | +.br | |
6778 | +RFC 1813 - "NFS Version 3 Protocol Specification" | |
6779 | .SH AUTHOR | |
6780 | Olaf Kirch, H. J. Lu, G. Allan Morris III, and a host of others. | |
6781 | diff --git a/utils/mountd/rmtab.c b/utils/mountd/rmtab.c | |
6782 | index 19b22ee..d339296 100644 | |
6783 | --- a/utils/mountd/rmtab.c | |
6784 | +++ b/utils/mountd/rmtab.c | |
6785 | @@ -16,7 +16,7 @@ | |
6786 | #include <netinet/in.h> | |
6787 | #include <arpa/inet.h> | |
6788 | #include <netdb.h> | |
6789 | -#include "xmalloc.h" | |
6790 | + | |
6791 | #include "misc.h" | |
6792 | #include "exportfs.h" | |
6793 | #include "xio.h" | |
6794 | @@ -131,22 +131,22 @@ mountlist_del(char *hname, const char *path) | |
6795 | } | |
6796 | ||
6797 | void | |
6798 | -mountlist_del_all(struct sockaddr_in *sin) | |
6799 | +mountlist_del_all(const struct sockaddr *sap) | |
6800 | { | |
6801 | - struct in_addr addr = sin->sin_addr; | |
6802 | - struct hostent *hp; | |
6803 | + char *hostname; | |
6804 | struct rmtabent *rep; | |
6805 | - nfs_export *exp; | |
6806 | FILE *fp; | |
6807 | int lockid; | |
6808 | ||
6809 | if ((lockid = xflock(_PATH_RMTABLCK, "w")) < 0) | |
6810 | return; | |
6811 | - if (!(hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET))) { | |
6812 | - xlog(L_ERROR, "can't get hostname of %s", inet_ntoa(addr)); | |
6813 | + hostname = host_canonname(sap); | |
6814 | + if (hostname == NULL) { | |
6815 | + char buf[INET6_ADDRSTRLEN]; | |
6816 | + xlog(L_ERROR, "can't get hostname of %s", | |
6817 | + host_ntop(sap, buf, sizeof(buf))); | |
6818 | goto out_unlock; | |
6819 | } | |
6820 | - hp = hostent_dup (hp); | |
6821 | ||
6822 | if (!setrmtabent("r")) | |
6823 | goto out_free; | |
6824 | @@ -155,8 +155,8 @@ mountlist_del_all(struct sockaddr_in *sin) | |
6825 | goto out_close; | |
6826 | ||
6827 | while ((rep = getrmtabent(1, NULL)) != NULL) { | |
6828 | - if (strcmp(rep->r_client, hp->h_name) == 0 && | |
6829 | - (exp = auth_authenticate("umountall", sin, rep->r_path))) | |
6830 | + if (strcmp(rep->r_client, hostname) == 0 && | |
6831 | + auth_authenticate("umountall", sap, rep->r_path) != NULL) | |
6832 | continue; | |
6833 | fputrmtabent(fp, rep, NULL); | |
6834 | } | |
6835 | @@ -168,11 +168,23 @@ mountlist_del_all(struct sockaddr_in *sin) | |
6836 | out_close: | |
6837 | endrmtabent(); /* close & unlink */ | |
6838 | out_free: | |
6839 | - free (hp); | |
6840 | + free(hostname); | |
6841 | out_unlock: | |
6842 | xfunlock(lockid); | |
6843 | } | |
6844 | ||
6845 | +static void | |
6846 | +mountlist_freeall(mountlist list) | |
6847 | +{ | |
6848 | + while (list != NULL) { | |
6849 | + mountlist m = list; | |
6850 | + list = m->ml_next; | |
6851 | + free(m->ml_hostname); | |
6852 | + free(m->ml_directory); | |
6853 | + free(m); | |
6854 | + } | |
6855 | +} | |
6856 | + | |
6857 | mountlist | |
6858 | mountlist_list(void) | |
6859 | { | |
6860 | @@ -182,8 +194,6 @@ mountlist_list(void) | |
6861 | struct rmtabent *rep; | |
6862 | struct stat stb; | |
6863 | int lockid; | |
6864 | - struct in_addr addr; | |
6865 | - struct hostent *he; | |
6866 | ||
6867 | if ((lockid = xflock(_PATH_RMTABLCK, "r")) < 0) | |
6868 | return NULL; | |
6869 | @@ -194,26 +204,41 @@ mountlist_list(void) | |
6870 | return NULL; | |
6871 | } | |
6872 | if (stb.st_mtime != last_mtime) { | |
6873 | - while (mlist) { | |
6874 | - mlist = (m = mlist)->ml_next; | |
6875 | - xfree(m->ml_hostname); | |
6876 | - xfree(m->ml_directory); | |
6877 | - xfree(m); | |
6878 | - } | |
6879 | + mountlist_freeall(mlist); | |
6880 | last_mtime = stb.st_mtime; | |
6881 | ||
6882 | setrmtabent("r"); | |
6883 | while ((rep = getrmtabent(1, NULL)) != NULL) { | |
6884 | - m = (mountlist) xmalloc(sizeof(*m)); | |
6885 | - | |
6886 | - if (reverse_resolve && | |
6887 | - inet_aton((const char *) rep->r_client, &addr) && | |
6888 | - (he = gethostbyaddr(&addr, sizeof(addr), AF_INET))) | |
6889 | - m->ml_hostname = xstrdup(he->h_name); | |
6890 | - else | |
6891 | - m->ml_hostname = xstrdup(rep->r_client); | |
6892 | + m = calloc(1, sizeof(*m)); | |
6893 | + if (m == NULL) { | |
6894 | + mountlist_freeall(mlist); | |
6895 | + mlist = NULL; | |
6896 | + xlog(L_ERROR, "%s: memory allocation failed", | |
6897 | + __func__); | |
6898 | + break; | |
6899 | + } | |
6900 | + | |
6901 | + if (reverse_resolve) { | |
6902 | + struct addrinfo *ai; | |
6903 | + ai = host_pton(rep->r_client); | |
6904 | + if (ai != NULL) { | |
6905 | + m->ml_hostname = host_canonname(ai->ai_addr); | |
6906 | + freeaddrinfo(ai); | |
6907 | + } | |
6908 | + } | |
6909 | + if (m->ml_hostname == NULL) | |
6910 | + m->ml_hostname = strdup(rep->r_client); | |
6911 | + | |
6912 | + m->ml_directory = strdup(rep->r_path); | |
6913 | + | |
6914 | + if (m->ml_hostname == NULL || m->ml_directory == NULL) { | |
6915 | + mountlist_freeall(mlist); | |
6916 | + mlist = NULL; | |
6917 | + xlog(L_ERROR, "%s: memory allocation failed", | |
6918 | + __func__); | |
6919 | + break; | |
6920 | + } | |
6921 | ||
6922 | - m->ml_directory = xstrdup(rep->r_path); | |
6923 | m->ml_next = mlist; | |
6924 | mlist = m; | |
6925 | } | |
6926 | diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c | |
6927 | index 1cda1e5..650c593 100644 | |
6928 | --- a/utils/nfsd/nfsd.c | |
6929 | +++ b/utils/nfsd/nfsd.c | |
6930 | @@ -27,15 +27,6 @@ | |
6931 | #include "nfssvc.h" | |
6932 | #include "xlog.h" | |
6933 | ||
6934 | -/* | |
6935 | - * IPv6 support for nfsd was finished before some of the other daemons (mountd | |
6936 | - * and statd in particular). That could be a problem in the future if someone | |
6937 | - * were to boot a kernel that supports IPv6 serving with an older nfs-utils. For | |
6938 | - * now, hardcode the IPv6 switch into the off position until the other daemons | |
6939 | - * are functional. | |
6940 | - */ | |
6941 | -#undef IPV6_SUPPORTED | |
6942 | - | |
6943 | static void usage(const char *); | |
6944 | ||
6945 | static struct option longopts[] = | |
6946 | diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c | |
6947 | index 60232b8..25cd459 100644 | |
6948 | --- a/utils/nfsd/nfssvc.c | |
6949 | +++ b/utils/nfsd/nfssvc.c | |
6950 | @@ -22,15 +22,6 @@ | |
6951 | #include "nfslib.h" | |
6952 | #include "xlog.h" | |
6953 | ||
6954 | -/* | |
6955 | - * IPv6 support for nfsd was finished before some of the other daemons (mountd | |
6956 | - * and statd in particular). That could be a problem in the future if someone | |
6957 | - * were to boot a kernel that supports IPv6 serving with an older nfs-utils. For | |
6958 | - * now, hardcode the IPv6 switch into the off position until the other daemons | |
6959 | - * are functional. | |
6960 | - */ | |
6961 | -#undef IPV6_SUPPORTED | |
6962 | - | |
6963 | #define NFSD_PORTS_FILE "/proc/fs/nfsd/portlist" | |
6964 | #define NFSD_VERS_FILE "/proc/fs/nfsd/versions" | |
6965 | #define NFSD_THREAD_FILE "/proc/fs/nfsd/threads" | |
6966 | @@ -181,7 +172,7 @@ nfssvc_setfds(const struct addrinfo *hints, const char *node, const char *port) | |
6967 | } | |
6968 | ||
6969 | snprintf(buf, sizeof(buf), "%d\n", sockfd); | |
6970 | - if (write(fd, buf, strlen(buf)) != strlen(buf)) { | |
6971 | + if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) { | |
6972 | /* | |
6973 | * this error may be common on older kernels that don't | |
6974 | * support IPv6, so turn into a debug message. | |
6975 | @@ -251,7 +242,7 @@ nfssvc_setvers(unsigned int ctlbits, int minorvers4) | |
6976 | } | |
6977 | xlog(D_GENERAL, "Writing version string to kernel: %s", buf); | |
6978 | snprintf(ptr+off, sizeof(buf) - off, "\n"); | |
6979 | - if (write(fd, buf, strlen(buf)) != strlen(buf)) | |
6980 | + if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) | |
6981 | xlog(L_ERROR, "Setting version failed: errno %d (%m)", errno); | |
6982 | ||
6983 | close(fd); | |
6984 | @@ -277,7 +268,7 @@ nfssvc_threads(unsigned short port, const int nrservs) | |
6985 | snprintf(buf, sizeof(buf), "%d\n", nrservs); | |
6986 | n = write(fd, buf, strlen(buf)); | |
6987 | close(fd); | |
6988 | - if (n != strlen(buf)) | |
6989 | + if (n != (ssize_t)strlen(buf)) | |
6990 | return -1; | |
6991 | else | |
6992 | return 0; | |
6993 | diff --git a/utils/nfsstat/nfsstat.c b/utils/nfsstat/nfsstat.c | |
6994 | index 99d77c9..740a803 100644 | |
6995 | --- a/utils/nfsstat/nfsstat.c | |
6996 | +++ b/utils/nfsstat/nfsstat.c | |
6997 | @@ -791,7 +791,7 @@ print_callstats(const char *hdr, const char **names, | |
6998 | { | |
6999 | unsigned long long total; | |
7000 | unsigned long long pct; | |
7001 | - int i, j; | |
7002 | + unsigned int i, j; | |
7003 | ||
7004 | fputs(hdr, stdout); | |
7005 | for (i = 0, total = 0; i < nr; i++) | |
7006 | @@ -816,7 +816,7 @@ print_callstats_list(const char *hdr, const char **names, | |
7007 | unsigned int *callinfo, unsigned int nr) | |
7008 | { | |
7009 | unsigned long long calltotal; | |
7010 | - int i; | |
7011 | + unsigned int i; | |
7012 | ||
7013 | for (i = 0, calltotal = 0; i < nr; i++) { | |
7014 | calltotal += callinfo[i]; | |
7015 | @@ -1118,7 +1118,7 @@ unpause(int sig) | |
7016 | time_diff = difftime(endtime, starttime); | |
7017 | minutes = time_diff / 60; | |
7018 | seconds = (int)time_diff % 60; | |
7019 | - printf("Signal received; displaying (only) statistics gathered over the last %d minutes, %d seconds:\n\n", minutes, seconds); | |
7020 | + printf("Signal %d received; displaying (only) statistics gathered over the last %d minutes, %d seconds:\n\n", sig, minutes, seconds); | |
7021 | } | |
7022 | ||
7023 | static void | |
7024 | diff --git a/utils/showmount/showmount.c b/utils/showmount/showmount.c | |
7025 | index f567093..394f528 100644 | |
7026 | --- a/utils/showmount/showmount.c | |
7027 | +++ b/utils/showmount/showmount.c | |
7028 | @@ -194,7 +194,13 @@ int main(int argc, char **argv) | |
7029 | } | |
7030 | ||
7031 | mclient = nfs_get_mount_client(hostname, mount_vers_tbl[vers]); | |
7032 | - mclient->cl_auth = authunix_create_default(); | |
7033 | + mclient->cl_auth = nfs_authsys_create(); | |
7034 | + if (mclient->cl_auth == NULL) { | |
7035 | + fprintf(stderr, "%s: unable to create RPC auth handle.\n", | |
7036 | + program_name); | |
7037 | + clnt_destroy(mclient); | |
7038 | + exit(1); | |
7039 | + } | |
7040 | total_timeout.tv_sec = TOTAL_TIMEOUT; | |
7041 | total_timeout.tv_usec = 0; | |
7042 | ||
7043 | diff --git a/utils/statd/hostname.c b/utils/statd/hostname.c | |
7044 | index 7d704cc..38f2265 100644 | |
7045 | --- a/utils/statd/hostname.c | |
7046 | +++ b/utils/statd/hostname.c | |
7047 | @@ -212,7 +212,9 @@ statd_canonical_name(const char *hostname) | |
7048 | buf, (socklen_t)sizeof(buf)); | |
7049 | freeaddrinfo(ai); | |
7050 | if (!result) | |
7051 | - return NULL; | |
7052 | + /* OK to use presentation address, | |
7053 | + * if no reverse map exists */ | |
7054 | + return strdup(hostname); | |
7055 | return strdup(buf); | |
7056 | } | |
7057 | ||
7058 | diff --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c | |
7059 | index 3259a3e..437e37a 100644 | |
7060 | --- a/utils/statd/sm-notify.c | |
7061 | +++ b/utils/statd/sm-notify.c | |
7062 | @@ -54,7 +54,7 @@ struct nsm_host { | |
7063 | uint32_t xid; | |
7064 | }; | |
7065 | ||
7066 | -static char nsm_hostname[256]; | |
7067 | +static char nsm_hostname[SM_MAXSTRLEN + 1]; | |
7068 | static int nsm_state; | |
7069 | static int nsm_family = AF_INET; | |
7070 | static int opt_debug = 0; | |
7071 | @@ -412,12 +412,33 @@ usage: fprintf(stderr, | |
7072 | } | |
7073 | } | |
7074 | ||
7075 | - if (opt_srcaddr) { | |
7076 | - strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname)-1); | |
7077 | - } else | |
7078 | - if (gethostname(nsm_hostname, sizeof(nsm_hostname)) < 0) { | |
7079 | - xlog(L_ERROR, "Failed to obtain name of local host: %m"); | |
7080 | - exit(1); | |
7081 | + if (opt_srcaddr != NULL) { | |
7082 | + struct addrinfo *ai = NULL; | |
7083 | + struct addrinfo hint = { | |
7084 | + .ai_family = AF_UNSPEC, | |
7085 | + .ai_flags = AI_NUMERICHOST, | |
7086 | + }; | |
7087 | + | |
7088 | + if (getaddrinfo(opt_srcaddr, NULL, &hint, &ai)) | |
7089 | + /* not a presentation address - use it */ | |
7090 | + strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname)); | |
7091 | + else { | |
7092 | + /* was a presentation address - look it up in | |
7093 | + * /etc/hosts, so it can be used for my_name */ | |
7094 | + int error; | |
7095 | + | |
7096 | + freeaddrinfo(ai); | |
7097 | + hint.ai_flags = AI_CANONNAME; | |
7098 | + error = getaddrinfo(opt_srcaddr, NULL, &hint, &ai); | |
7099 | + if (error != 0) { | |
7100 | + xlog(L_ERROR, "Bind address %s is unusable: %s", | |
7101 | + opt_srcaddr, gai_strerror(error)); | |
7102 | + exit(1); | |
7103 | + } | |
7104 | + strncpy(nsm_hostname, ai->ai_canonname, | |
7105 | + sizeof(nsm_hostname)); | |
7106 | + freeaddrinfo(ai); | |
7107 | + } | |
7108 | } | |
7109 | ||
7110 | (void)nsm_retire_monitored_hosts(); | |
7111 | @@ -535,6 +556,8 @@ notify(const int sock) | |
7112 | static int | |
7113 | notify_host(int sock, struct nsm_host *host) | |
7114 | { | |
7115 | + const char *my_name = (opt_srcaddr != NULL ? | |
7116 | + nsm_hostname : host->my_name); | |
7117 | struct sockaddr *sap; | |
7118 | socklen_t salen; | |
7119 | ||
7120 | @@ -580,8 +603,8 @@ notify_host(int sock, struct nsm_host *host) | |
7121 | host->xid = nsm_xmit_rpcbind(sock, sap, SM_PROG, SM_VERS); | |
7122 | else | |
7123 | host->xid = nsm_xmit_notify(sock, sap, salen, | |
7124 | - SM_PROG, nsm_hostname, nsm_state); | |
7125 | - | |
7126 | + SM_PROG, my_name, nsm_state); | |
7127 | + | |
7128 | return 0; | |
7129 | } | |
7130 | ||
7131 | @@ -611,15 +634,28 @@ recv_rpcbind_reply(struct sockaddr *sap, struct nsm_host *host, XDR *xdr) | |
7132 | } | |
7133 | ||
7134 | /* | |
7135 | - * Successful NOTIFY call. Server returns void, so nothing | |
7136 | - * we need to do here. | |
7137 | + * Successful NOTIFY call. Server returns void. | |
7138 | + * | |
7139 | + * Try sending another SM_NOTIFY with an unqualified "my_name" | |
7140 | + * argument. Reuse the port number. If "my_name" is already | |
7141 | + * unqualified, we're done. | |
7142 | */ | |
7143 | static void | |
7144 | recv_notify_reply(struct nsm_host *host) | |
7145 | { | |
7146 | - xlog(D_GENERAL, "Host %s notified successfully", host->name); | |
7147 | + char *dot = strchr(host->my_name, '.'); | |
7148 | ||
7149 | - smn_forget_host(host); | |
7150 | + if (dot != NULL) { | |
7151 | + *dot = '\0'; | |
7152 | + host->send_next = time(NULL); | |
7153 | + host->xid = 0; | |
7154 | + if (host->timeout >= NSM_MAX_TIMEOUT / 4) | |
7155 | + host->timeout = NSM_MAX_TIMEOUT / 4; | |
7156 | + insert_host(host); | |
7157 | + } else { | |
7158 | + xlog(D_GENERAL, "Host %s notified successfully", host->name); | |
7159 | + smn_forget_host(host); | |
7160 | + } | |
7161 | } | |
7162 | ||
7163 | /* | |
7164 | diff --git a/utils/statd/sm-notify.man b/utils/statd/sm-notify.man | |
7165 | index 163713e..7a1cbfa 100644 | |
7166 | --- a/utils/statd/sm-notify.man | |
7167 | +++ b/utils/statd/sm-notify.man | |
7168 | @@ -97,11 +97,9 @@ It uses the | |
7169 | string as the destination. | |
7170 | To identify which host has rebooted, the | |
7171 | .B sm-notify | |
7172 | -command normally sends the results of | |
7173 | -.BR gethostname (3) | |
7174 | -as the | |
7175 | +command normally sends | |
7176 | .I my_name | |
7177 | -string. | |
7178 | +string recorded when that remote was monitored. | |
7179 | The remote | |
7180 | .B rpc.statd | |
7181 | matches incoming SM_NOTIFY requests using this string, | |
7182 | @@ -202,15 +200,22 @@ argument to use when sending SM_NOTIFY requests. | |
7183 | If this option is not specified, | |
7184 | .B sm-notify | |
7185 | uses a wildcard address as the transport bind address, | |
7186 | -and uses the results of | |
7187 | -.BR gethostname (3) | |
7188 | -as the | |
7189 | +and uses the | |
7190 | +.I my_name | |
7191 | +recorded when the remote was monitored as the | |
7192 | .I mon_name | |
7193 | -argument. | |
7194 | +argument when sending SM_NOTIFY requests. | |
7195 | .IP | |
7196 | The | |
7197 | .I ipaddr | |
7198 | form can be expressed as either an IPv4 or an IPv6 presentation address. | |
7199 | +If the | |
7200 | +.I ipaddr | |
7201 | +form is used, the | |
7202 | +.B sm-notify | |
7203 | +command converts this address to a hostname for use as the | |
7204 | +.I mon_name | |
7205 | +argument when sending SM_NOTIFY requests. | |
7206 | .IP | |
7207 | This option can be useful in multi-homed configurations where | |
7208 | the remote requires notification from a specific network address. | |
7209 | @@ -252,13 +257,6 @@ consistent | |
7210 | The hostname the client uses to mount the server should match the server's | |
7211 | .I mon_name | |
7212 | in SM_NOTIFY requests it sends | |
7213 | -.IP | |
7214 | -The use of network addresses as a | |
7215 | -.I mon_name | |
7216 | -or a | |
7217 | -.I my_name | |
7218 | -string should be avoided when | |
7219 | -interoperating with non-Linux NFS implementations. | |
7220 | .PP | |
7221 | Unmounting an NFS file system does not necessarily stop | |
7222 | either the NFS client or server from monitoring each other. | |
7223 | diff --git a/utils/statd/statd.man b/utils/statd/statd.man | |
7224 | index ffc5e95..ca00e24 100644 | |
7225 | --- a/utils/statd/statd.man | |
7226 | +++ b/utils/statd/statd.man | |
7227 | @@ -100,11 +100,9 @@ It uses the | |
7228 | string as the destination. | |
7229 | To identify which host has rebooted, the | |
7230 | .B sm-notify | |
7231 | -command normally sends the results of | |
7232 | -.BR gethostname (3) | |
7233 | -as the | |
7234 | +command sends the | |
7235 | .I my_name | |
7236 | -string. | |
7237 | +string recorded when that remote was monitored. | |
7238 | The remote | |
7239 | .B rpc.statd | |
7240 | matches incoming SM_NOTIFY requests using this string, | |
7241 | @@ -292,7 +290,6 @@ man pages. | |
7242 | .SH ADDITIONAL NOTES | |
7243 | Lock recovery after a reboot is critical to maintaining data integrity | |
7244 | and preventing unnecessary application hangs. | |
7245 | -.PP | |
7246 | To help | |
7247 | .B rpc.statd | |
7248 | match SM_NOTIFY requests to NLM requests, a number of best practices | |
7249 | @@ -309,13 +306,6 @@ consistent | |
7250 | The hostname the client uses to mount the server should match the server's | |
7251 | .I mon_name | |
7252 | in SM_NOTIFY requests it sends | |
7253 | -.IP | |
7254 | -The use of network addresses as a | |
7255 | -.I mon_name | |
7256 | -or a | |
7257 | -.I my_name | |
7258 | -string should be avoided when | |
7259 | -interoperating with non-Linux NFS implementations. | |
7260 | .PP | |
7261 | Unmounting an NFS file system does not necessarily stop | |
7262 | either the NFS client or server from monitoring each other. |