]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/mount/network.c
4831990c2b6c305246c61937e93c2181c3735bc2
[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 #include <ctype.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <netdb.h>
31 #include <time.h>
32 #include <rpc/rpc.h>
33 #include <rpc/pmap_prot.h>
34 #include <rpc/pmap_clnt.h>
35 #include <sys/socket.h>
36
37 #include "conn.h"
38 #include "xcommon.h"
39 #include "mount.h"
40 #include "nls.h"
41 #include "nfs_mount.h"
42 #include "mount_constants.h"
43 #include "network.h"
44
45 #ifdef HAVE_RPCSVC_NFS_PROT_H
46 #include <rpcsvc/nfs_prot.h>
47 #else
48 #include <linux/nfs.h>
49 #define nfsstat nfs_stat
50 #endif
51
52 #ifndef NFS_PORT
53 #define NFS_PORT 2049
54 #endif
55
56 #if SIZEOF_SOCKLEN_T - 0 == 0
57 #define socklen_t unsigned int
58 #endif
59
60 extern int nfs_mount_data_version;
61 extern char *progname;
62 extern int verbose;
63
64 static const unsigned long nfs_to_mnt[] = {
65         0,
66         0,
67         1,
68         3,
69 };
70
71 static const unsigned long mnt_to_nfs[] = {
72         0,
73         2,
74         2,
75         3,
76 };
77
78 /*
79  * Map an NFS version into the corresponding Mountd version
80  */
81 unsigned long nfsvers_to_mnt(const unsigned long vers)
82 {
83         if (vers <= 3)
84                 return nfs_to_mnt[vers];
85         return 0;
86 }
87
88 /*
89  * Map a Mountd version into the corresponding NFS version
90  */
91 static unsigned long mntvers_to_nfs(const unsigned long vers)
92 {
93         if (vers <= 3)
94                 return mnt_to_nfs[vers];
95         return 0;
96 }
97
98 static const unsigned int probe_udp_only[] = {
99         IPPROTO_UDP,
100         0,
101 };
102
103 static const unsigned int probe_udp_first[] = {
104         IPPROTO_UDP,
105         IPPROTO_TCP,
106         0,
107 };
108
109 static const unsigned int probe_tcp_first[] = {
110         IPPROTO_TCP,
111         IPPROTO_UDP,
112         0,
113 };
114
115 static const unsigned long probe_nfs2_only[] = {
116         2,
117         0,
118 };
119
120 static const unsigned long probe_nfs3_first[] = {
121         3,
122         2,
123         0,
124 };
125
126 static const unsigned long probe_mnt1_first[] = {
127         1,
128         2,
129         0,
130 };
131
132 static const unsigned long probe_mnt3_first[] = {
133         3,
134         1,
135         2,
136         0,
137 };
138
139 int nfs_gethostbyname(const char *hostname, struct sockaddr_in *saddr)
140 {
141         struct hostent *hp;
142
143         saddr->sin_family = AF_INET;
144         if (!inet_aton(hostname, &saddr->sin_addr)) {
145                 if ((hp = gethostbyname(hostname)) == NULL) {
146                         nfs_error(_("%s: can't get address for %s\n"),
147                                         progname, hostname);
148                         return 0;
149                 } else {
150                         if (hp->h_length > sizeof(*saddr)) {
151                                 nfs_error(_("%s: got bad hp->h_length\n"),
152                                                 progname);
153                                 hp->h_length = sizeof(*saddr);
154                         }
155                         memcpy(&saddr->sin_addr, hp->h_addr, hp->h_length);
156                 }
157         }
158         return 1;
159 }
160
161 /*
162  * Create a socket that is locally bound to a reserved or non-reserved
163  * port. For any failures, RPC_ANYSOCK is returned which will cause 
164  * the RPC code to create the socket instead. 
165  */
166 static int get_socket(struct sockaddr_in *saddr, unsigned int p_prot,
167                         int resvp, int conn)
168 {
169         int so, cc, type;
170         struct sockaddr_in laddr;
171         socklen_t namelen = sizeof(laddr);
172
173         type = (p_prot == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM);
174         if ((so = socket (AF_INET, type, p_prot)) < 0) {
175                 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
176                 rpc_createerr.cf_error.re_errno = errno;
177                 if (verbose) {
178                         fprintf(stderr, 
179                                 "mount: Unable to create %s socket: errno %d (%s)\n",
180                                 p_prot == IPPROTO_UDP ? "UDP" : "TCP", 
181                                 errno, strerror(errno));
182                 }
183                 return RPC_ANYSOCK;
184         }
185         laddr.sin_family = AF_INET;
186         laddr.sin_port = 0;
187         laddr.sin_addr.s_addr = htonl(INADDR_ANY);
188         if (resvp) {
189                 if (bindresvport(so, &laddr) < 0) {
190                         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
191                         rpc_createerr.cf_error.re_errno = errno;
192                         if (verbose) {
193                                 fprintf(stderr, 
194                                         "mount: Unable to bindresvport %s socket: errno %d (%s)\n",
195                                         p_prot == IPPROTO_UDP ? "UDP" : "TCP", 
196                                         errno, strerror(errno));
197                         }
198                         close(so);
199                         return RPC_ANYSOCK;
200                 }
201         } else {
202                 cc = bind(so, (struct sockaddr *)&laddr, namelen);
203                 if (cc < 0) {
204                         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
205                         rpc_createerr.cf_error.re_errno = errno;
206                         if (verbose) {
207                                 fprintf(stderr, 
208                                         "mount: Unable to bind to %s socket: errno %d (%s)\n",
209                                         p_prot == IPPROTO_UDP ? "UDP" : "TCP", 
210                                         errno, strerror(errno));
211                         }
212                         close(so);
213                         return RPC_ANYSOCK;
214                 }
215         }
216         if (type == SOCK_STREAM || (conn && type == SOCK_DGRAM)) {
217                 cc = connect(so, (struct sockaddr *)saddr, namelen);
218                 if (cc < 0) {
219                         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
220                         rpc_createerr.cf_error.re_errno = errno;
221                         if (verbose) {
222                                 fprintf(stderr, 
223                                         "mount: Unable to connect to %s:%d, errno %d (%s)\n",
224                                         inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port),
225                                         errno, strerror(errno));
226                         }
227                         close(so);
228                         return RPC_ANYSOCK;
229                 }
230         }
231         return so;
232 }
233
234 /*
235  * getport() is very similar to pmap_getport() with the exception that
236  * this version tries to use an ephemeral port, since reserved ports are
237  * not needed for GETPORT queries.  This conserves the very limited
238  * reserved port space, which helps reduce failed socket binds
239  * during mount storms.
240  *
241  * A side effect of calling this function is that rpccreateerr is set.
242  */
243 static unsigned short getport(struct sockaddr_in *saddr,
244                                 unsigned long program,
245                                 unsigned long version,
246                                 unsigned int proto)
247 {
248         unsigned short port = 0;
249         int socket;
250         CLIENT *clnt = NULL;
251         enum clnt_stat stat;
252
253         saddr->sin_port = htons(PMAPPORT);
254
255         /*
256          * Try to get a socket with a non-privileged port.
257          * clnt*create() will create one anyway if this
258          * fails.
259          */
260         socket = get_socket(saddr, proto, FALSE, FALSE);
261         if (socket == RPC_ANYSOCK) {
262                 if (proto == IPPROTO_TCP && errno == ETIMEDOUT) {
263                         /*
264                          * TCP SYN timed out, so exit now.
265                          */
266                         rpc_createerr.cf_stat = RPC_TIMEDOUT;
267                 }
268                 return 0;
269         }
270
271         switch (proto) {
272         case IPPROTO_UDP:
273                 clnt = clntudp_bufcreate(saddr,
274                                          PMAPPROG, PMAPVERS,
275                                          RETRY_TIMEOUT, &socket,
276                                          RPCSMALLMSGSIZE,
277                                          RPCSMALLMSGSIZE);
278                 break;
279         case IPPROTO_TCP:
280                 clnt = clnttcp_create(saddr, PMAPPROG, PMAPVERS, &socket,
281                                       RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
282                 break;
283         }
284         if (clnt != NULL) {
285                 struct pmap parms = {
286                         .pm_prog        = program,
287                         .pm_vers        = version,
288                         .pm_prot        = proto,
289                 };
290
291                 stat = clnt_call(clnt, PMAPPROC_GETPORT,
292                                  (xdrproc_t)xdr_pmap, (caddr_t)&parms,
293                                  (xdrproc_t)xdr_u_short, (caddr_t)&port,
294                                  TIMEOUT);
295                 if (stat) {
296                         clnt_geterr(clnt, &rpc_createerr.cf_error);
297                         rpc_createerr.cf_stat = stat;
298                 }
299                 clnt_destroy(clnt);
300                 if (stat != RPC_SUCCESS)
301                         port = 0;
302                 else if (port == 0)
303                         rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
304         }
305         if (socket != 1)
306                 close(socket);
307
308         return port;
309 }
310
311 /*
312  * Use the portmapper to discover whether or not the service we want is
313  * available. The lists 'versions' and 'protos' define ordered sequences
314  * of service versions and udp/tcp protocols to probe for.
315  */
316 static int probe_port(clnt_addr_t *server, const unsigned long *versions,
317                         const unsigned int *protos)
318 {
319         struct sockaddr_in *saddr = &server->saddr;
320         struct pmap *pmap = &server->pmap;
321         const unsigned long prog = pmap->pm_prog, *p_vers;
322         const unsigned int prot = (u_int)pmap->pm_prot, *p_prot;
323         const u_short port = (u_short) pmap->pm_port;
324         unsigned long vers = pmap->pm_vers;
325         unsigned short p_port;
326
327         p_prot = prot ? &prot : protos;
328         p_vers = vers ? &vers : versions;
329         rpc_createerr.cf_stat = 0;
330         for (;;) {
331                 saddr->sin_port = htons(PMAPPORT);
332                 p_port = getport(saddr, prog, *p_vers, *p_prot);
333                 if (p_port) {
334                         if (!port || port == p_port) {
335                                 saddr->sin_port = htons(p_port);
336                                 if (verbose) {
337                                         printf(_("%s: trying %s prog %ld vers "
338                                                 "%ld prot %s port %d\n"),
339                                                 progname,
340                                                 inet_ntoa(saddr->sin_addr),
341                                                 prog, *p_vers,
342                                                 *p_prot == IPPROTO_UDP ?
343                                                         "udp" : "tcp",
344                                                 p_port);
345                                 }
346                                 if (clnt_ping(saddr, prog, *p_vers, *p_prot, NULL))
347                                         goto out_ok;
348                                 if (rpc_createerr.cf_stat == RPC_TIMEDOUT)
349                                         goto out_bad;
350                         }
351                 }
352                 if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED)
353                         goto out_bad;
354
355                 if (!prot) {
356                         if (*++p_prot)
357                                 continue;
358                         p_prot = protos;
359                 }
360                 if (vers == pmap->pm_vers) {
361                         p_vers = versions;
362                         vers = 0;
363                 }
364                 if (vers || !*++p_vers)
365                         break;
366         }
367
368 out_bad:
369         return 0;
370
371 out_ok:
372         if (!vers)
373                 pmap->pm_vers = *p_vers;
374         if (!prot)
375                 pmap->pm_prot = *p_prot;
376         if (!port)
377                 pmap->pm_port = p_port;
378         rpc_createerr.cf_stat = 0;
379         return 1;
380 }
381
382 static int probe_nfsport(clnt_addr_t *nfs_server)
383 {
384         struct pmap *pmap = &nfs_server->pmap;
385
386         if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
387                 return 1;
388
389         if (nfs_mount_data_version >= 4)
390                 return probe_port(nfs_server, probe_nfs3_first, probe_tcp_first);
391         else
392                 return probe_port(nfs_server, probe_nfs2_only, probe_udp_only);
393 }
394
395 static int probe_mntport(clnt_addr_t *mnt_server)
396 {
397         struct pmap *pmap = &mnt_server->pmap;
398
399         if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
400                 return 1;
401
402         if (nfs_mount_data_version >= 4)
403                 return probe_port(mnt_server, probe_mnt3_first, probe_udp_first);
404         else
405                 return probe_port(mnt_server, probe_mnt1_first, probe_udp_only);
406 }
407
408 int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server)
409 {
410         struct pmap *nfs_pmap = &nfs_server->pmap;
411         struct pmap *mnt_pmap = &mnt_server->pmap;
412         struct pmap save_nfs, save_mnt;
413         int res;
414         const unsigned long *probe_vers;
415
416         if (mnt_pmap->pm_vers && !nfs_pmap->pm_vers)
417                 nfs_pmap->pm_vers = mntvers_to_nfs(mnt_pmap->pm_vers);
418         else if (nfs_pmap->pm_vers && !mnt_pmap->pm_vers)
419                 mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers);
420         if (nfs_pmap->pm_vers)
421                 goto version_fixed;
422
423         memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs));
424         memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt));
425         probe_vers = (nfs_mount_data_version >= 4) ?
426                         probe_mnt3_first : probe_mnt1_first;
427
428         for (; *probe_vers; probe_vers++) {
429                 nfs_pmap->pm_vers = mntvers_to_nfs(*probe_vers);
430                 if ((res = probe_nfsport(nfs_server) != 0)) {
431                         mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers);
432                         if ((res = probe_mntport(mnt_server)) != 0)
433                                 return 1;
434                         memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap));
435                 }
436                 switch (rpc_createerr.cf_stat) {
437                 case RPC_PROGVERSMISMATCH:
438                 case RPC_PROGNOTREGISTERED:
439                         break;
440                 default:
441                         goto out_bad;
442                 }
443                 memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap));
444         }
445
446 out_bad:
447         return 0;
448
449 version_fixed:
450         if (!probe_nfsport(nfs_server))
451                 goto out_bad;
452         return probe_mntport(mnt_server);
453 }
454
455 static int probe_statd(void)
456 {
457         struct sockaddr_in addr;
458         unsigned short port;
459
460         memset(&addr, 0, sizeof(addr));
461         addr.sin_family = AF_INET;
462         addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
463         port = getport(&addr, 100024, 1, IPPROTO_UDP);
464
465         if (port == 0)
466                 return 0;
467         addr.sin_port = htons(port);
468
469         if (clnt_ping(&addr, 100024, 1, IPPROTO_UDP, NULL) <= 0)
470                 return 0;
471
472         return 1;
473 }
474
475 /*
476  * Attempt to start rpc.statd
477  */
478 int start_statd(void)
479 {
480 #ifdef START_STATD
481         struct stat stb;
482 #endif
483
484         if (probe_statd())
485                 return 1;
486
487 #ifdef START_STATD
488         if (stat(START_STATD, &stb) == 0) {
489                 if (S_ISREG(stb.st_mode) && (stb.st_mode & S_IXUSR)) {
490                         system(START_STATD);
491                         if (probe_statd())
492                                 return 1;
493                 }
494         }
495 #endif
496
497         return 0;
498 }
499
500 /*
501  * nfs_call_umount - ask the server to remove a share from it's rmtab
502  * @mnt_server: address of RPC MNT program server
503  * @argp: directory path of share to "unmount"
504  *
505  * Returns one if the unmount call succeeded; zero if the unmount
506  * failed for any reason.
507  *
508  * Note that a side effect of calling this function is that rpccreateerr
509  * is set.
510  */
511 int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp)
512 {
513         CLIENT *clnt;
514         enum clnt_stat res = 0;
515         int msock;
516
517         switch (mnt_server->pmap.pm_vers) {
518         case 3:
519         case 2:
520         case 1:
521                 if (!probe_mntport(mnt_server))
522                         return 0;
523                 clnt = mnt_openclnt(mnt_server, &msock);
524                 if (!clnt)
525                         return 0;
526                 res = clnt_call(clnt, MOUNTPROC_UMNT,
527                                 (xdrproc_t)xdr_dirpath, (caddr_t)argp,
528                                 (xdrproc_t)xdr_void, NULL,
529                                 TIMEOUT);
530                 mnt_closeclnt(clnt, msock);
531                 if (res == RPC_SUCCESS)
532                         return 1;
533                 break;
534         default:
535                 res = RPC_SUCCESS;
536                 break;
537         }
538
539         if (res == RPC_SUCCESS)
540                 return 1;
541         return 0;
542 }
543
544 CLIENT *mnt_openclnt(clnt_addr_t *mnt_server, int *msock)
545 {
546         struct sockaddr_in *mnt_saddr = &mnt_server->saddr;
547         struct pmap *mnt_pmap = &mnt_server->pmap;
548         CLIENT *clnt = NULL;
549
550         mnt_saddr->sin_port = htons((u_short)mnt_pmap->pm_port);
551         *msock = get_socket(mnt_saddr, mnt_pmap->pm_prot, TRUE, FALSE);
552         if (*msock == RPC_ANYSOCK) {
553                 if (rpc_createerr.cf_error.re_errno == EADDRINUSE)
554                         /*
555                          * Probably in-use by a TIME_WAIT connection,
556                          * It is worth waiting a while and trying again.
557                          */
558                         rpc_createerr.cf_stat = RPC_TIMEDOUT;
559                 return NULL;
560         }
561
562         switch (mnt_pmap->pm_prot) {
563         case IPPROTO_UDP:
564                 clnt = clntudp_bufcreate(mnt_saddr,
565                                          mnt_pmap->pm_prog, mnt_pmap->pm_vers,
566                                          RETRY_TIMEOUT, msock,
567                                          MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
568                 break;
569         case IPPROTO_TCP:
570                 clnt = clnttcp_create(mnt_saddr,
571                                       mnt_pmap->pm_prog, mnt_pmap->pm_vers,
572                                       msock,
573                                       MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
574                 break;
575         }
576         if (clnt) {
577                 /* try to mount hostname:dirname */
578                 clnt->cl_auth = authunix_create_default();
579                 return clnt;
580         }
581         return NULL;
582 }
583
584 void mnt_closeclnt(CLIENT *clnt, int msock)
585 {
586         auth_destroy(clnt->cl_auth);
587         clnt_destroy(clnt);
588         close(msock);
589 }
590
591 /*
592  * Sigh... getport() doesn't actually check the version number.
593  * In order to make sure that the server actually supports the service
594  * we're requesting, we open and RPC client, and fire off a NULL
595  * RPC call.
596  */
597 int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog,
598                 const unsigned long vers, const unsigned int prot,
599                 struct sockaddr_in *caddr)
600 {
601         CLIENT *clnt = NULL;
602         int sock, stat;
603         static char clnt_res;
604         struct sockaddr dissolve;
605
606         rpc_createerr.cf_stat = stat = errno = 0;
607         sock = get_socket(saddr, prot, FALSE, TRUE);
608         if (sock == RPC_ANYSOCK) {
609                 if (errno == ETIMEDOUT) {
610                         /*
611                          * TCP timeout. Bubble up the error to see 
612                          * how it should be handled.
613                          */
614                         rpc_createerr.cf_stat = RPC_TIMEDOUT;
615                 }
616                 return 0;
617         }
618
619         if (caddr) {
620                 /* Get the address of our end of this connection */
621                 socklen_t len = sizeof(*caddr);
622                 if (getsockname(sock, caddr, &len) != 0)
623                         caddr->sin_family = 0;
624         }
625
626         switch(prot) {
627         case IPPROTO_UDP:
628                 /* The socket is connected (so we could getsockname successfully),
629                  * but some servers on multi-homed hosts reply from
630                  * the wrong address, so if we stay connected, we lose the reply.
631                  */
632                 dissolve.sa_family = AF_UNSPEC;
633                 connect(sock, &dissolve, sizeof(dissolve));
634
635                 clnt = clntudp_bufcreate(saddr, prog, vers,
636                                          RETRY_TIMEOUT, &sock,
637                                          RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
638                 break;
639         case IPPROTO_TCP:
640                 clnt = clnttcp_create(saddr, prog, vers, &sock,
641                                       RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
642                 break;
643         }
644         if (!clnt) {
645                 close(sock);
646                 return 0;
647         }
648         memset(&clnt_res, 0, sizeof(clnt_res));
649         stat = clnt_call(clnt, NULLPROC,
650                          (xdrproc_t)xdr_void, (caddr_t)NULL,
651                          (xdrproc_t)xdr_void, (caddr_t)&clnt_res,
652                          TIMEOUT);
653         if (stat) {
654                 clnt_geterr(clnt, &rpc_createerr.cf_error);
655                 rpc_createerr.cf_stat = stat;
656         }
657         clnt_destroy(clnt);
658         close(sock);
659
660         if (stat == RPC_SUCCESS)
661                 return 1;
662         else
663                 return 0;
664 }