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