]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/mount/network.c
mount command: use gethostbyname(3) when building on old systems
[nfs-utils.git] / utils / mount / network.c
1 /*
2  * network.c -- Provide common network functions for NFS mount/umount
3  *
4  * Copyright (C) 2007 Oracle.  All rights reserved.
5  * Copyright (C) 2007 Chuck Lever <chuck.lever@oracle.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public
18  * License along with this program; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 021110-1307, USA.
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <ctype.h>
29 #include <unistd.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <netdb.h>
35 #include <time.h>
36
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <sys/wait.h>
40 #include <netinet/in.h>
41 #include <rpc/rpc.h>
42 #include <rpc/pmap_prot.h>
43 #include <rpc/pmap_clnt.h>
44
45 #include "xcommon.h"
46 #include "mount.h"
47 #include "nls.h"
48 #include "nfs_mount.h"
49 #include "mount_constants.h"
50 #include "nfsrpc.h"
51 #include "network.h"
52
53 #define PMAP_TIMEOUT    (10)
54 #define CONNECT_TIMEOUT (20)
55 #define MOUNT_TIMEOUT   (30)
56
57 #if SIZEOF_SOCKLEN_T - 0 == 0
58 #define socklen_t unsigned int
59 #endif
60
61 extern int nfs_mount_data_version;
62 extern char *progname;
63 extern int verbose;
64
65 static const char *nfs_ns_pgmtbl[] = {
66         "status",
67         NULL,
68 };
69
70 static const unsigned long nfs_to_mnt[] = {
71         0,
72         0,
73         1,
74         3,
75 };
76
77 static const unsigned long mnt_to_nfs[] = {
78         0,
79         2,
80         2,
81         3,
82 };
83
84 /*
85  * Map an NFS version into the corresponding Mountd version
86  */
87 unsigned long nfsvers_to_mnt(const unsigned long vers)
88 {
89         if (vers <= 3)
90                 return nfs_to_mnt[vers];
91         return 0;
92 }
93
94 /*
95  * Map a Mountd version into the corresponding NFS version
96  */
97 static unsigned long mntvers_to_nfs(const unsigned long vers)
98 {
99         if (vers <= 3)
100                 return mnt_to_nfs[vers];
101         return 0;
102 }
103
104 static const unsigned int probe_udp_only[] = {
105         IPPROTO_UDP,
106         0,
107 };
108
109 static const unsigned int probe_udp_first[] = {
110         IPPROTO_UDP,
111         IPPROTO_TCP,
112         0,
113 };
114
115 static const unsigned int probe_tcp_first[] = {
116         IPPROTO_TCP,
117         IPPROTO_UDP,
118         0,
119 };
120
121 static const unsigned long probe_nfs2_only[] = {
122         2,
123         0,
124 };
125
126 static const unsigned long probe_nfs3_first[] = {
127         3,
128         2,
129         0,
130 };
131
132 static const unsigned long probe_mnt1_first[] = {
133         1,
134         2,
135         0,
136 };
137
138 static const unsigned long probe_mnt3_first[] = {
139         3,
140         1,
141         2,
142         0,
143 };
144
145 static void nfs_set_port(struct sockaddr *sap, const unsigned short port)
146 {
147         switch (sap->sa_family) {
148         case AF_INET:
149                 ((struct sockaddr_in *)sap)->sin_port = htons(port);
150                 break;
151         case AF_INET6:
152                 ((struct sockaddr_in6 *)sap)->sin6_port = htons(port);
153                 break;
154         default:
155                 nfs_error(_("%s: unrecognized address family in %s"),
156                         progname, __func__);
157         }
158 }
159
160 #ifdef HAVE_DECL_AI_ADDRCONFIG
161 /**
162  * nfs_name_to_address - resolve hostname to an IPv4 or IPv6 socket address
163  * @hostname: pointer to C string containing DNS hostname to resolve
164  * @sap: pointer to buffer to fill with socket address
165  * @len: IN: size of buffer to fill; OUT: size of socket address
166  *
167  * Returns 1 and places a socket address at @sap if successful;
168  * otherwise zero.
169  */
170 int nfs_name_to_address(const char *hostname,
171                         const sa_family_t af_hint,
172                         struct sockaddr *sap, socklen_t *salen)
173 {
174         struct addrinfo *gai_results;
175         struct addrinfo gai_hint = {
176                 .ai_family      = af_hint,
177                 .ai_flags       = AI_ADDRCONFIG,
178         };
179         socklen_t len = *salen;
180         int error, ret = 0;
181
182         if (af_hint == AF_INET6)
183                 gai_hint.ai_flags |= AI_V4MAPPED|AI_ALL;
184
185         *salen = 0;
186
187         error = getaddrinfo(hostname, NULL, &gai_hint, &gai_results);
188         if (error) {
189                 nfs_error(_("%s: DNS resolution failed for %s: %s"),
190                         progname, hostname, (error == EAI_SYSTEM ?
191                                 strerror(errno) : gai_strerror(error)));
192                 return ret;
193         }
194
195         switch (gai_results->ai_addr->sa_family) {
196         case AF_INET:
197         case AF_INET6:
198                 if (len >= gai_results->ai_addrlen) {
199                         *salen = gai_results->ai_addrlen;
200                         memcpy(sap, gai_results->ai_addr, *salen);
201                         ret = 1;
202                 }
203                 break;
204         default:
205                 /* things are really broken if we get here, so warn */
206                 nfs_error(_("%s: unrecognized DNS resolution results for %s"),
207                                 progname, hostname);
208                 break;
209         }
210
211         freeaddrinfo(gai_results);
212         return ret;
213 }
214 #else   /* HAVE_DECL_AI_ADDRCONFIG */
215 /**
216  * nfs_name_to_address - resolve hostname to an IPv4 socket address
217  * @hostname: pointer to C string containing DNS hostname to resolve
218  * @af_hint: hint to restrict resolution to one address family
219  * @sap: pointer to buffer to fill with socket address
220  * @len: IN: size of buffer to fill; OUT: size of socket address
221  *
222  * Returns 1 and places a socket address at @sap if successful;
223  * otherwise zero.
224  *
225  * Some older getaddrinfo(3) implementations don't support
226  * AI_ADDRCONFIG or AI_V4MAPPED properly.  For those cases, a DNS
227  * resolver based on the traditional gethostbyname(3) is provided.
228  */
229 int nfs_name_to_address(const char *hostname,
230                         const sa_family_t af_hint,
231                         struct sockaddr *sap, socklen_t *salen)
232 {
233         struct sockaddr_in *sin = (struct sockaddr_in *)sap;
234         socklen_t len = *salen;
235         struct hostent *hp;
236
237         *salen = 0;
238
239         if (af_hint != AF_INET) {
240                 nfs_error(_("%s: address family not supported by DNS resolver\n"),
241                                 progname, hostname);
242                 return 0;
243         }
244
245         sin->sin_family = AF_INET;
246         if (inet_aton(hostname, &sin->sin_addr)) {
247                 *salen = sizeof(*sin);
248                 return 1;
249         }
250
251         hp = gethostbyname(hostname);
252         if (hp == NULL) {
253                 nfs_error(_("%s: DNS resolution failed for %s: %s"),
254                                 progname, hostname, hstrerror(h_errno));
255                 return 0;
256         }
257
258         if (hp->h_length > len) {
259                 nfs_error(_("%s: DNS resolution results too long for buffer\n"),
260                                 progname);
261                 return 0;
262         }
263
264         memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
265         *salen = hp->h_length;
266         return 1;
267 }
268 #endif  /* HAVE_DECL_AI_ADDRCONFIG */
269
270 /**
271  * nfs_gethostbyname - resolve a hostname to an IPv4 address
272  * @hostname: pointer to a C string containing a DNS hostname
273  * @saddr: returns an IPv4 address 
274  *
275  * Returns 1 if successful, otherwise zero.
276  */
277 int nfs_gethostbyname(const char *hostname, struct sockaddr_in *sin)
278 {
279         socklen_t len = sizeof(*sin);
280
281         return nfs_name_to_address(hostname, AF_INET,
282                                         (struct sockaddr *)sin, &len);
283 }
284
285 /**
286  * nfs_string_to_sockaddr - convert string address to sockaddr
287  * @address:    pointer to presentation format address to convert
288  * @addrlen:    length of presentation address
289  * @sap:        pointer to socket address buffer to fill in
290  * @salen:      IN: length of address buffer
291  *              OUT: length of converted socket address
292  *
293  * Convert a presentation format address string to a socket address.
294  * Similar to nfs_name_to_address(), but the DNS query is squelched,
295  * and won't make any noise if the getaddrinfo() call fails.
296  *
297  * Returns 1 and fills in @sap and @salen if successful; otherwise zero.
298  *
299  * See RFC 4038 section 5.1 or RFC 3513 section 2.2 for more details
300  * on presenting IPv6 addresses as text strings.
301  */
302 int nfs_string_to_sockaddr(const char *address, const size_t addrlen,
303                            struct sockaddr *sap, socklen_t *salen)
304 {
305         struct addrinfo *gai_results;
306         struct addrinfo gai_hint = {
307                 .ai_flags       = AI_NUMERICHOST,
308         };
309         socklen_t len = *salen;
310         int ret = 0;
311
312         *salen = 0;
313
314         if (getaddrinfo(address, NULL, &gai_hint, &gai_results) == 0) {
315                 switch (gai_results->ai_addr->sa_family) {
316                 case AF_INET:
317                 case AF_INET6:
318                         if (len >= gai_results->ai_addrlen) {
319                                 *salen = gai_results->ai_addrlen;
320                                 memcpy(sap, gai_results->ai_addr, *salen);
321                                 ret = 1;
322                         }
323                         break;
324                 }
325                 freeaddrinfo(gai_results);
326         }
327
328         return ret;
329 }
330
331 /**
332  * nfs_present_sockaddr - convert sockaddr to string
333  * @sap: pointer to socket address to convert
334  * @salen: length of socket address
335  * @buf: pointer to buffer to fill in
336  * @buflen: length of buffer
337  *
338  * Convert the passed-in sockaddr-style address to presentation format.
339  * The presentation format address is placed in @buf and is
340  * '\0'-terminated.
341  *
342  * Returns 1 if successful; otherwise zero.
343  *
344  * See RFC 4038 section 5.1 or RFC 3513 section 2.2 for more details
345  * on presenting IPv6 addresses as text strings.
346  */
347 int nfs_present_sockaddr(const struct sockaddr *sap, const socklen_t salen,
348                          char *buf, const size_t buflen)
349 {
350 #ifdef HAVE_GETNAMEINFO
351         int result;
352
353         result = getnameinfo(sap, salen, buf, buflen,
354                                         NULL, 0, NI_NUMERICHOST);
355         if (!result)
356                 return 1;
357
358         nfs_error(_("%s: invalid server address: %s"), progname,
359                         gai_strerror(result));
360         return 0;
361 #else   /* HAVE_GETNAMEINFO */
362         char *addr;
363
364         if (sap->sa_family == AF_INET) {
365                 addr = inet_ntoa(((struct sockaddr_in *)sap)->sin_addr);
366                 if (addr && strlen(addr) < buflen) {
367                         strcpy(buf, addr);
368                         return 1;
369                 }
370         }
371
372         nfs_error(_("%s: invalid server address"), progname);
373         return 0;
374 #endif  /* HAVE_GETNAMEINFO */
375 }
376
377 /*
378  * Attempt to connect a socket, but time out after "timeout" seconds.
379  *
380  * On error return, caller closes the socket.
381  */
382 static int connect_to(int fd, struct sockaddr *addr,
383                         socklen_t addrlen, int timeout)
384 {
385         int ret, saved;
386         fd_set rset, wset;
387         struct timeval tv = {
388                 .tv_sec = timeout,
389         };
390
391         saved = fcntl(fd, F_GETFL, 0);
392         fcntl(fd, F_SETFL, saved | O_NONBLOCK);
393
394         ret = connect(fd, addr, addrlen);
395         if (ret < 0 && errno != EINPROGRESS)
396                 return -1;
397         if (ret == 0)
398                 goto out;
399
400         FD_ZERO(&rset);
401         FD_SET(fd, &rset);
402         wset = rset;
403         ret = select(fd + 1, &rset, &wset, NULL, &tv);
404         if (ret == 0) {
405                 errno = ETIMEDOUT;
406                 return -1;
407         }
408         if (FD_ISSET(fd, &rset) || FD_ISSET(fd, &wset)) {
409                 int error;
410                 socklen_t len = sizeof(error);
411                 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
412                         return -1;
413                 if (error) {
414                         errno = error;
415                         return -1;
416                 }
417         } else
418                 return -1;
419
420 out:
421         fcntl(fd, F_SETFL, saved);
422         return 0;
423 }
424
425 /*
426  * Create a socket that is locally bound to a reserved or non-reserved port.
427  *
428  * The caller should check rpc_createerr to determine the cause of any error.
429  */
430 static int get_socket(struct sockaddr_in *saddr, unsigned int p_prot,
431                         unsigned int timeout, int resvp, int conn)
432 {
433         int so, cc, type;
434         struct sockaddr_in laddr;
435         socklen_t namelen = sizeof(laddr);
436
437         type = (p_prot == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM);
438         if ((so = socket (AF_INET, type, p_prot)) < 0)
439                 goto err_socket;
440
441         laddr.sin_family = AF_INET;
442         laddr.sin_port = 0;
443         laddr.sin_addr.s_addr = htonl(INADDR_ANY);
444         if (resvp) {
445                 if (bindresvport(so, &laddr) < 0)
446                         goto err_bindresvport;
447         } else {
448                 cc = bind(so, (struct sockaddr *)&laddr, namelen);
449                 if (cc < 0)
450                         goto err_bind;
451         }
452         if (type == SOCK_STREAM || (conn && type == SOCK_DGRAM)) {
453                 cc = connect_to(so, (struct sockaddr *)saddr, namelen,
454                                 timeout);
455                 if (cc < 0)
456                         goto err_connect;
457         }
458         return so;
459
460 err_socket:
461         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
462         rpc_createerr.cf_error.re_errno = errno;
463         if (verbose) {
464                 nfs_error(_("%s: Unable to create %s socket: errno %d (%s)\n"),
465                         progname, p_prot == IPPROTO_UDP ? _("UDP") : _("TCP"),
466                         errno, strerror(errno));
467         }
468         return RPC_ANYSOCK;
469
470 err_bindresvport:
471         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
472         rpc_createerr.cf_error.re_errno = errno;
473         if (verbose) {
474                 nfs_error(_("%s: Unable to bindresvport %s socket: errno %d"
475                                 " (%s)\n"),
476                         progname, p_prot == IPPROTO_UDP ? _("UDP") : _("TCP"),
477                         errno, strerror(errno));
478         }
479         close(so);
480         return RPC_ANYSOCK;
481
482 err_bind:
483         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
484         rpc_createerr.cf_error.re_errno = errno;
485         if (verbose) {
486                 nfs_error(_("%s: Unable to bind to %s socket: errno %d (%s)\n"),
487                         progname, p_prot == IPPROTO_UDP ? _("UDP") : _("TCP"),
488                         errno, strerror(errno));
489         }
490         close(so);
491         return RPC_ANYSOCK;
492
493 err_connect:
494         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
495         rpc_createerr.cf_error.re_errno = errno;
496         if (verbose) {
497                 nfs_error(_("%s: Unable to connect to %s:%d, errno %d (%s)\n"),
498                         progname, inet_ntoa(saddr->sin_addr),
499                         ntohs(saddr->sin_port), errno, strerror(errno));
500         }
501         close(so);
502         return RPC_ANYSOCK;
503 }
504
505 static void nfs_pp_debug(const struct sockaddr *sap, const socklen_t salen,
506                          const rpcprog_t program, const rpcvers_t version,
507                          const unsigned short protocol,
508                          const unsigned short port)
509 {
510         char buf[NI_MAXHOST];
511
512         if (!verbose)
513                 return;
514
515         if (nfs_present_sockaddr(sap, salen, buf, sizeof(buf)) == 0) {
516                 buf[0] = '\0';
517                 strcat(buf, "unknown host");
518         }
519
520         fprintf(stderr, _("%s: trying %s prog %ld vers %ld prot %s port %d\n"),
521                         progname, buf, program, version,
522                         (protocol == IPPROTO_UDP ? _("UDP") : _("TCP")),
523                         port);
524 }
525
526 /*
527  * Use the portmapper to discover whether or not the service we want is
528  * available. The lists 'versions' and 'protos' define ordered sequences
529  * of service versions and udp/tcp protocols to probe for.
530  *
531  * Returns 1 if the requested service port is unambiguous and pingable;
532  * @pmap is filled in with the version, port, and transport protocol used
533  * during the successful ping.  Note that if a port is already specified
534  * in @pmap and it matches the rpcbind query result, nfs_probe_port() does
535  * not perform an RPC ping.
536  * 
537  * If an error occurs or the requested service isn't available, zero is
538  * returned; rpccreateerr.cf_stat is set to reflect the nature of the error.
539  */
540 static int nfs_probe_port(const struct sockaddr *sap, const socklen_t salen,
541                           struct pmap *pmap, const unsigned long *versions,
542                           const unsigned int *protos)
543 {
544         struct sockaddr_storage address;
545         struct sockaddr *saddr = (struct sockaddr *)&address;
546         const unsigned long prog = pmap->pm_prog, *p_vers;
547         const unsigned int prot = (u_int)pmap->pm_prot, *p_prot;
548         const u_short port = (u_short) pmap->pm_port;
549         unsigned long vers = pmap->pm_vers;
550         unsigned short p_port;
551
552         memcpy(saddr, sap, salen);
553         p_prot = prot ? &prot : protos;
554         p_vers = vers ? &vers : versions;
555         rpc_createerr.cf_stat = 0;
556
557         for (;;) {
558                 p_port = nfs_getport(saddr, salen, prog, *p_vers, *p_prot);
559                 if (p_port) {
560                         if (!port || port == p_port) {
561                                 nfs_set_port(saddr, p_port);
562                                 nfs_pp_debug(saddr, salen, prog, *p_vers,
563                                                 *p_prot, p_port);
564                                 if (nfs_rpc_ping(saddr, salen, prog,
565                                                         *p_vers, *p_prot, NULL))
566                                         goto out_ok;
567                         }
568                 }
569                 if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED &&
570                     rpc_createerr.cf_stat != RPC_TIMEDOUT &&
571                     rpc_createerr.cf_stat != RPC_CANTRECV &&
572                     rpc_createerr.cf_stat != RPC_PROGVERSMISMATCH)
573                         goto out_bad;
574
575                 if (!prot) {
576                         if (*++p_prot)
577                                 continue;
578                         p_prot = protos;
579                 }
580                 if (rpc_createerr.cf_stat == RPC_TIMEDOUT ||
581                     rpc_createerr.cf_stat == RPC_CANTRECV)
582                         goto out_bad;
583
584                 if (vers || !*++p_vers)
585                         break;
586         }
587
588 out_bad:
589         return 0;
590
591 out_ok:
592         if (!vers)
593                 pmap->pm_vers = *p_vers;
594         if (!prot)
595                 pmap->pm_prot = *p_prot;
596         if (!port)
597                 pmap->pm_port = p_port;
598         rpc_createerr.cf_stat = 0;
599         return 1;
600 }
601
602 /*
603  * Probe a server's NFS service to determine which versions and
604  * transport protocols are supported.
605  *
606  * Returns 1 if the requested service port is unambiguous and pingable;
607  * @pmap is filled in with the version, port, and transport protocol used
608  * during the successful ping.  If all three are already specified, simply
609  * return success without an rpcbind query or RPC ping (we may be trying
610  * to mount an NFS service that is not advertised via rpcbind).
611  *
612  * If an error occurs or the requested service isn't available, zero is
613  * returned; rpccreateerr.cf_stat is set to reflect the nature of the error.
614  */
615 static int nfs_probe_nfsport(const struct sockaddr *sap, const socklen_t salen,
616                                 struct pmap *pmap)
617 {
618         if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
619                 return 1;
620
621         if (nfs_mount_data_version >= 4)
622                 return nfs_probe_port(sap, salen, pmap,
623                                         probe_nfs3_first, probe_tcp_first);
624         else
625                 return nfs_probe_port(sap, salen, pmap,
626                                         probe_nfs2_only, probe_udp_only);
627 }
628
629 /*
630  * Probe a server's mountd service to determine which versions and
631  * transport protocols are supported.
632  *
633  * Returns 1 if the requested service port is unambiguous and pingable;
634  * @pmap is filled in with the version, port, and transport protocol used
635  * during the successful ping.  If all three are already specified, simply
636  * return success without an rpcbind query or RPC ping (we may be trying
637  * to mount an NFS service that is not advertised via rpcbind).
638  * 
639  * If an error occurs or the requested service isn't available, zero is
640  * returned; rpccreateerr.cf_stat is set to reflect the nature of the error.
641  */
642 static int nfs_probe_mntport(const struct sockaddr *sap, const socklen_t salen,
643                                 struct pmap *pmap)
644 {
645         if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
646                 return 1;
647
648         if (nfs_mount_data_version >= 4)
649                 return nfs_probe_port(sap, salen, pmap,
650                                         probe_mnt3_first, probe_udp_first);
651         else
652                 return nfs_probe_port(sap, salen, pmap,
653                                         probe_mnt1_first, probe_udp_only);
654 }
655
656 /*
657  * Probe a server's mountd service to determine which versions and
658  * transport protocols are supported.  Invoked when the protocol
659  * version is already known for both the NFS and mountd service.
660  *
661  * Returns 1 and fills in both @pmap structs if the requested service
662  * ports are unambiguous and pingable.  Otherwise zero is returned;
663  * rpccreateerr.cf_stat is set to reflect the nature of the error.
664  */
665 static int nfs_probe_version_fixed(const struct sockaddr *mnt_saddr,
666                         const socklen_t mnt_salen,
667                         struct pmap *mnt_pmap,
668                         const struct sockaddr *nfs_saddr,
669                         const socklen_t nfs_salen,
670                         struct pmap *nfs_pmap)
671 {
672         if (!nfs_probe_nfsport(nfs_saddr, nfs_salen, nfs_pmap))
673                 return 0;
674         return nfs_probe_mntport(mnt_saddr, mnt_salen, mnt_pmap);
675 }
676
677 /**
678  * nfs_probe_bothports - discover the RPC endpoints of mountd and NFS server
679  * @mnt_saddr:  pointer to socket address of mountd server
680  * @mnt_salen:  length of mountd server's address
681  * @mnt_pmap:   IN: partially filled-in mountd RPC service tuple;
682  *              OUT: fully filled-in mountd RPC service tuple
683  * @nfs_saddr:  pointer to socket address of NFS server
684  * @nfs_salen:  length of NFS server's address
685  * @nfs_pmap:   IN: partially filled-in NFS RPC service tuple;
686  *              OUT: fully filled-in NFS RPC service tuple
687  *
688  * Returns 1 and fills in both @pmap structs if the requested service
689  * ports are unambiguous and pingable.  Otherwise zero is returned;
690  * rpccreateerr.cf_stat is set to reflect the nature of the error.
691  */
692 int nfs_probe_bothports(const struct sockaddr *mnt_saddr,
693                         const socklen_t mnt_salen,
694                         struct pmap *mnt_pmap,
695                         const struct sockaddr *nfs_saddr,
696                         const socklen_t nfs_salen,
697                         struct pmap *nfs_pmap)
698 {
699         struct pmap save_nfs, save_mnt;
700         const unsigned long *probe_vers;
701
702         if (mnt_pmap->pm_vers && !nfs_pmap->pm_vers)
703                 nfs_pmap->pm_vers = mntvers_to_nfs(mnt_pmap->pm_vers);
704         else if (nfs_pmap->pm_vers && !mnt_pmap->pm_vers)
705                 mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers);
706
707         if (nfs_pmap->pm_vers)
708                 return nfs_probe_version_fixed(mnt_saddr, mnt_salen, mnt_pmap,
709                                                nfs_saddr, nfs_salen, nfs_pmap);
710
711         memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs));
712         memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt));
713         probe_vers = (nfs_mount_data_version >= 4) ?
714                         probe_mnt3_first : probe_mnt1_first;
715
716         for (; *probe_vers; probe_vers++) {
717                 nfs_pmap->pm_vers = mntvers_to_nfs(*probe_vers);
718                 if (nfs_probe_nfsport(nfs_saddr, nfs_salen, nfs_pmap) != 0) {
719                         mnt_pmap->pm_vers = *probe_vers;
720                         if (nfs_probe_mntport(mnt_saddr, mnt_salen, mnt_pmap) != 0)
721                                 return 1;
722                         memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap));
723                 }
724                 switch (rpc_createerr.cf_stat) {
725                 case RPC_PROGVERSMISMATCH:
726                 case RPC_PROGNOTREGISTERED:
727                         break;
728                 default:
729                         return 0;
730                 }
731                 memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap));
732         }
733
734         return 0;
735 }
736
737 /**
738  * probe_bothports - discover the RPC endpoints of mountd and NFS server
739  * @mnt_server: pointer to address and pmap argument for mountd results
740  * @nfs_server: pointer to address and pmap argument for NFS server
741  *
742  * This is the legacy API that takes "clnt_addr_t" for both servers,
743  * but supports only AF_INET addresses.
744  *
745  * Returns 1 and fills in the pmap field in both clnt_addr_t structs
746  * if the requested service ports are unambiguous and pingable.
747  * Otherwise zero is returned; rpccreateerr.cf_stat is set to reflect
748  * the nature of the error.
749  */
750 int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server)
751 {
752         return nfs_probe_bothports((struct sockaddr *)&mnt_server->saddr,
753                                         sizeof(mnt_server->saddr),
754                                         &mnt_server->pmap,
755                                         (struct sockaddr *)&nfs_server->saddr,
756                                         sizeof(nfs_server->saddr),
757                                         &nfs_server->pmap);
758 }
759
760 static int nfs_probe_statd(void)
761 {
762         struct sockaddr_in addr = {
763                 .sin_family             = AF_INET,
764                 .sin_addr.s_addr        = htonl(INADDR_LOOPBACK),
765         };
766         rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl);
767
768         return nfs_getport_ping((struct sockaddr *)&addr, sizeof(addr),
769                                 program, (rpcvers_t)1, IPPROTO_UDP);
770 }
771
772 /**
773  * start_statd - attempt to start rpc.statd
774  *
775  * Returns 1 if statd is running; otherwise zero.
776  */
777 int start_statd(void)
778 {
779 #ifdef START_STATD
780         struct stat stb;
781 #endif
782
783         if (nfs_probe_statd())
784                 return 1;
785
786 #ifdef START_STATD
787         if (stat(START_STATD, &stb) == 0) {
788                 if (S_ISREG(stb.st_mode) && (stb.st_mode & S_IXUSR)) {
789                         pid_t pid = fork();
790                         switch (pid) {
791                         case 0: /* child */
792                                 execl(START_STATD, START_STATD, NULL);
793                                 exit(1);
794                         case -1: /* error */
795                                 nfs_error(_("fork failed: %s"),
796                                                         strerror(errno));
797                                 break;
798                         default: /* parent */
799                                 waitpid(pid, NULL,0);
800                                 break;
801                         }
802                         if (nfs_probe_statd())
803                                 return 1;
804                 }
805         }
806 #endif
807
808         return 0;
809 }
810
811 /**
812  * nfs_call_umount - ask the server to remove a share from it's rmtab
813  * @mnt_server: address of RPC MNT program server
814  * @argp: directory path of share to "unmount"
815  *
816  * Returns one if the unmount call succeeded; zero if the unmount
817  * failed for any reason.
818  *
819  * Note that a side effect of calling this function is that rpccreateerr
820  * is set.
821  */
822 int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp)
823 {
824         struct sockaddr *sap = (struct sockaddr *)&mnt_server->saddr;
825         socklen_t salen = sizeof(mnt_server->saddr);
826         struct pmap *pmap = &mnt_server->pmap;
827         CLIENT *clnt;
828         enum clnt_stat res = 0;
829         int msock;
830
831         if (!nfs_probe_mntport(sap, salen, pmap))
832                 return 0;
833         clnt = mnt_openclnt(mnt_server, &msock);
834         if (!clnt)
835                 return 0;
836         res = clnt_call(clnt, MOUNTPROC_UMNT,
837                         (xdrproc_t)xdr_dirpath, (caddr_t)argp,
838                         (xdrproc_t)xdr_void, NULL,
839                         TIMEOUT);
840         mnt_closeclnt(clnt, msock);
841
842         if (res == RPC_SUCCESS)
843                 return 1;
844         return 0;
845 }
846
847 /**
848  * mnt_openclnt - get a handle for a remote mountd service
849  * @mnt_server: address and pmap arguments of mountd service
850  * @msock: returns a file descriptor of the underlying transport socket
851  *
852  * Returns an active handle for the remote's mountd service
853  */
854 CLIENT *mnt_openclnt(clnt_addr_t *mnt_server, int *msock)
855 {
856         struct sockaddr_in *mnt_saddr = &mnt_server->saddr;
857         struct pmap *mnt_pmap = &mnt_server->pmap;
858         CLIENT *clnt = NULL;
859
860         mnt_saddr->sin_port = htons((u_short)mnt_pmap->pm_port);
861         *msock = get_socket(mnt_saddr, mnt_pmap->pm_prot, MOUNT_TIMEOUT,
862                                 TRUE, FALSE);
863         if (*msock == RPC_ANYSOCK) {
864                 if (rpc_createerr.cf_error.re_errno == EADDRINUSE)
865                         /*
866                          * Probably in-use by a TIME_WAIT connection,
867                          * It is worth waiting a while and trying again.
868                          */
869                         rpc_createerr.cf_stat = RPC_TIMEDOUT;
870                 return NULL;
871         }
872
873         switch (mnt_pmap->pm_prot) {
874         case IPPROTO_UDP:
875                 clnt = clntudp_bufcreate(mnt_saddr,
876                                          mnt_pmap->pm_prog, mnt_pmap->pm_vers,
877                                          RETRY_TIMEOUT, msock,
878                                          MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
879                 break;
880         case IPPROTO_TCP:
881                 clnt = clnttcp_create(mnt_saddr,
882                                       mnt_pmap->pm_prog, mnt_pmap->pm_vers,
883                                       msock,
884                                       MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
885                 break;
886         }
887         if (clnt) {
888                 /* try to mount hostname:dirname */
889                 clnt->cl_auth = authunix_create_default();
890                 return clnt;
891         }
892         return NULL;
893 }
894
895 /**
896  * mnt_closeclnt - terminate a handle for a remote mountd service
897  * @clnt: pointer to an active handle for a remote mountd service
898  * @msock: file descriptor of the underlying transport socket
899  *
900  */
901 void mnt_closeclnt(CLIENT *clnt, int msock)
902 {
903         auth_destroy(clnt->cl_auth);
904         clnt_destroy(clnt);
905         close(msock);
906 }
907
908 /**
909  * clnt_ping - send an RPC ping to the remote RPC service endpoint
910  * @saddr: server's address
911  * @prog: target RPC program number
912  * @vers: target RPC version number
913  * @prot: target RPC protocol
914  * @caddr: filled in with our network address
915  *
916  * Sigh... GETPORT queries don't actually check the version number.
917  * In order to make sure that the server actually supports the service
918  * we're requesting, we open an RPC client, and fire off a NULL
919  * RPC call.
920  *
921  * caddr is the network address that the server will use to call us back.
922  * On multi-homed clients, this address depends on which NIC we use to
923  * route requests to the server.
924  *
925  * Returns one if successful, otherwise zero.
926  */
927 int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog,
928                 const unsigned long vers, const unsigned int prot,
929                 struct sockaddr_in *caddr)
930 {
931         CLIENT *clnt = NULL;
932         int sock, stat;
933         static char clnt_res;
934         struct sockaddr dissolve;
935
936         rpc_createerr.cf_stat = stat = 0;
937         sock = get_socket(saddr, prot, CONNECT_TIMEOUT, FALSE, TRUE);
938         if (sock == RPC_ANYSOCK) {
939                 if (rpc_createerr.cf_error.re_errno == ETIMEDOUT) {
940                         /*
941                          * TCP timeout. Bubble up the error to see 
942                          * how it should be handled.
943                          */
944                         rpc_createerr.cf_stat = RPC_TIMEDOUT;
945                 }
946                 return 0;
947         }
948
949         if (caddr) {
950                 /* Get the address of our end of this connection */
951                 socklen_t len = sizeof(*caddr);
952                 if (getsockname(sock, caddr, &len) != 0)
953                         caddr->sin_family = 0;
954         }
955
956         switch(prot) {
957         case IPPROTO_UDP:
958                 /* The socket is connected (so we could getsockname successfully),
959                  * but some servers on multi-homed hosts reply from
960                  * the wrong address, so if we stay connected, we lose the reply.
961                  */
962                 dissolve.sa_family = AF_UNSPEC;
963                 connect(sock, &dissolve, sizeof(dissolve));
964
965                 clnt = clntudp_bufcreate(saddr, prog, vers,
966                                          RETRY_TIMEOUT, &sock,
967                                          RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
968                 break;
969         case IPPROTO_TCP:
970                 clnt = clnttcp_create(saddr, prog, vers, &sock,
971                                       RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
972                 break;
973         }
974         if (!clnt) {
975                 close(sock);
976                 return 0;
977         }
978         memset(&clnt_res, 0, sizeof(clnt_res));
979         stat = clnt_call(clnt, NULLPROC,
980                          (xdrproc_t)xdr_void, (caddr_t)NULL,
981                          (xdrproc_t)xdr_void, (caddr_t)&clnt_res,
982                          TIMEOUT);
983         if (stat) {
984                 clnt_geterr(clnt, &rpc_createerr.cf_error);
985                 rpc_createerr.cf_stat = stat;
986         }
987         clnt_destroy(clnt);
988         close(sock);
989
990         if (stat == RPC_SUCCESS)
991                 return 1;
992         else
993                 return 0;
994 }
995
996 /*
997  * Try a getsockname() on a connected datagram socket.
998  *
999  * Returns 1 and fills in @buf if successful; otherwise, zero.
1000  *
1001  * A connected datagram socket prevents leaving a socket in TIME_WAIT.
1002  * This conserves the ephemeral port number space, helping reduce failed
1003  * socket binds during mount storms.
1004  */
1005 static int nfs_ca_sockname(const struct sockaddr *sap, const socklen_t salen,
1006                            struct sockaddr *buf, socklen_t *buflen)
1007 {
1008         struct sockaddr_in sin = {
1009                 .sin_family             = AF_INET,
1010                 .sin_addr.s_addr        = htonl(INADDR_ANY),
1011         };
1012         struct sockaddr_in6 sin6 = {
1013                 .sin6_family            = AF_INET6,
1014                 .sin6_addr              = IN6ADDR_ANY_INIT,
1015         };
1016         int sock;
1017
1018         sock = socket(sap->sa_family, SOCK_DGRAM, IPPROTO_UDP);
1019         if (sock < 0)
1020                 return 0;
1021
1022         switch (sap->sa_family) {
1023         case AF_INET:
1024                 if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
1025                         close(sock);
1026                         return 0;
1027                 }
1028                 break;
1029         case AF_INET6:
1030                 if (bind(sock, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) {
1031                         close(sock);
1032                         return 0;
1033                 }
1034                 break;
1035         default:
1036                 errno = EAFNOSUPPORT;
1037                 return 0;
1038         }
1039
1040         if (connect(sock, sap, salen) < 0) {
1041                 close(sock);
1042                 return 0;
1043         }
1044
1045         return !getsockname(sock, buf, buflen);
1046 }
1047
1048 /*
1049  * Try to generate an address that prevents the server from calling us.
1050  *
1051  * Returns 1 and fills in @buf if successful; otherwise, zero.
1052  */
1053 static int nfs_ca_gai(const struct sockaddr *sap, const socklen_t salen,
1054                       struct sockaddr *buf, socklen_t *buflen)
1055 {
1056         struct addrinfo *gai_results;
1057         struct addrinfo gai_hint = {
1058                 .ai_family      = sap->sa_family,
1059                 .ai_flags       = AI_PASSIVE,   /* ANYADDR */
1060         };
1061
1062         if (getaddrinfo(NULL, "", &gai_hint, &gai_results))
1063                 return 0;
1064
1065         *buflen = gai_results->ai_addrlen;
1066         memcpy(buf, gai_results->ai_addr, *buflen);
1067
1068         freeaddrinfo(gai_results);
1069
1070         return 1;
1071 }
1072
1073 /**
1074  * nfs_callback_address - acquire our local network address
1075  * @sap: pointer to address of remote
1076  * @sap_len: length of address
1077  * @buf: pointer to buffer to be filled in with local network address
1078  * @buflen: IN: length of buffer to fill in; OUT: length of filled-in address
1079  *
1080  * Discover a network address that an NFSv4 server can use to call us back.
1081  * On multi-homed clients, this address depends on which NIC we use to
1082  * route requests to the server.
1083  *
1084  * Returns 1 and fills in @buf if an unambiguous local address is
1085  * available; returns 1 and fills in an appropriate ANYADDR address
1086  * if a local address isn't available; otherwise, returns zero.
1087  */
1088 int nfs_callback_address(const struct sockaddr *sap, const socklen_t salen,
1089                          struct sockaddr *buf, socklen_t *buflen)
1090 {
1091         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)buf;
1092
1093         if (nfs_ca_sockname(sap, salen, buf, buflen) == 0)
1094                 if (nfs_ca_gai(sap, salen, buf, buflen) == 0)
1095                         goto out_failed;
1096
1097         /*
1098          * The server can't use an interface ID that was generated
1099          * here on the client, so always clear sin6_scope_id.
1100          */
1101         if (sin6->sin6_family == AF_INET6)
1102                 sin6->sin6_scope_id = 0;
1103
1104         return 1;
1105
1106 out_failed:
1107         *buflen = 0;
1108         if (verbose)
1109                 nfs_error(_("%s: failed to construct callback address"));
1110         return 0;
1111
1112 }