1*ec5c1277Schristos /* $NetBSD: getnfsargs.c,v 1.18 2017/02/05 00:24:24 christos Exp $ */
29abd2f56Sdsl
39abd2f56Sdsl /*
49abd2f56Sdsl * Copyright (c) 1992, 1993, 1994
59abd2f56Sdsl * The Regents of the University of California. All rights reserved.
69abd2f56Sdsl *
79abd2f56Sdsl * This code is derived from software contributed to Berkeley by
89abd2f56Sdsl * Rick Macklem at The University of Guelph.
99abd2f56Sdsl *
109abd2f56Sdsl * Redistribution and use in source and binary forms, with or without
119abd2f56Sdsl * modification, are permitted provided that the following conditions
129abd2f56Sdsl * are met:
139abd2f56Sdsl * 1. Redistributions of source code must retain the above copyright
149abd2f56Sdsl * notice, this list of conditions and the following disclaimer.
159abd2f56Sdsl * 2. Redistributions in binary form must reproduce the above copyright
169abd2f56Sdsl * notice, this list of conditions and the following disclaimer in the
179abd2f56Sdsl * documentation and/or other materials provided with the distribution.
189abd2f56Sdsl * 3. Neither the name of the University nor the names of its contributors
199abd2f56Sdsl * may be used to endorse or promote products derived from this software
209abd2f56Sdsl * without specific prior written permission.
219abd2f56Sdsl *
229abd2f56Sdsl * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
239abd2f56Sdsl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
249abd2f56Sdsl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
259abd2f56Sdsl * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
269abd2f56Sdsl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
279abd2f56Sdsl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
289abd2f56Sdsl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
299abd2f56Sdsl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
309abd2f56Sdsl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
319abd2f56Sdsl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
329abd2f56Sdsl * SUCH DAMAGE.
339abd2f56Sdsl */
349abd2f56Sdsl
359abd2f56Sdsl #include <sys/cdefs.h>
369abd2f56Sdsl #ifndef lint
376543a91fSlukem __COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\
386543a91fSlukem The Regents of the University of California. All rights reserved.");
399abd2f56Sdsl #endif /* not lint */
409abd2f56Sdsl
419abd2f56Sdsl #ifndef lint
429abd2f56Sdsl #if 0
439abd2f56Sdsl static char sccsid[] = "@(#)mount_nfs.c 8.11 (Berkeley) 5/4/95";
449abd2f56Sdsl #else
45*ec5c1277Schristos __RCSID("$NetBSD: getnfsargs.c,v 1.18 2017/02/05 00:24:24 christos Exp $");
469abd2f56Sdsl #endif
479abd2f56Sdsl #endif /* not lint */
489abd2f56Sdsl
499abd2f56Sdsl #include <sys/param.h>
509abd2f56Sdsl #include <sys/mount.h>
519abd2f56Sdsl #include <sys/socket.h>
529abd2f56Sdsl #include <sys/stat.h>
539abd2f56Sdsl #include <syslog.h>
549abd2f56Sdsl
559abd2f56Sdsl #include <rpc/rpc.h>
569abd2f56Sdsl #include <rpc/pmap_clnt.h>
579abd2f56Sdsl #include <rpc/pmap_prot.h>
589abd2f56Sdsl
599abd2f56Sdsl #include <nfs/rpcv2.h>
609abd2f56Sdsl #include <nfs/nfsproto.h>
619abd2f56Sdsl #include <nfs/nfs.h>
629abd2f56Sdsl #include <nfs/nfsmount.h>
639abd2f56Sdsl
649abd2f56Sdsl #include <arpa/inet.h>
659abd2f56Sdsl
669abd2f56Sdsl #include <err.h>
679abd2f56Sdsl #include <errno.h>
689abd2f56Sdsl #include <fcntl.h>
699abd2f56Sdsl #include <netdb.h>
709abd2f56Sdsl #include <signal.h>
719abd2f56Sdsl #include <stdio.h>
729abd2f56Sdsl #include <stdlib.h>
739abd2f56Sdsl #include <string.h>
749abd2f56Sdsl #include <unistd.h>
759abd2f56Sdsl #include <util.h>
769abd2f56Sdsl
779abd2f56Sdsl #include "mount_nfs.h"
789abd2f56Sdsl
7918c826e1Schristos int retrycnt = DEF_RETRY;
8018c826e1Schristos int opflags = 0;
8118c826e1Schristos int force2 = 0;
8218c826e1Schristos int force3 = 0;
8318c826e1Schristos int mnttcp_ok = 1;
8418c826e1Schristos int port = 0;
8518c826e1Schristos
869abd2f56Sdsl struct nfhret {
879abd2f56Sdsl u_long stat;
889abd2f56Sdsl long vers;
899abd2f56Sdsl long auth;
909abd2f56Sdsl long fhsize;
919abd2f56Sdsl u_char nfh[NFSX_V3FHMAX];
929abd2f56Sdsl };
939abd2f56Sdsl
949abd2f56Sdsl static int xdr_dir(XDR *, char *);
959abd2f56Sdsl static int xdr_fh(XDR *, struct nfhret *);
969abd2f56Sdsl
9783c92bb4Spooka #ifndef MOUNTNFS_RETRYRPC
9883c92bb4Spooka #define MOUNTNFS_RETRYRPC 60
9983c92bb4Spooka #endif
10083c92bb4Spooka
1019abd2f56Sdsl int
getnfsargs(char * spec,struct nfs_args * nfsargsp)1029abd2f56Sdsl getnfsargs(char *spec, struct nfs_args *nfsargsp)
1039abd2f56Sdsl {
1049abd2f56Sdsl CLIENT *clp;
1059abd2f56Sdsl struct addrinfo hints, *ai_nfs, *ai;
1069abd2f56Sdsl int ecode;
1079abd2f56Sdsl static struct netbuf nfs_nb;
1089abd2f56Sdsl static struct sockaddr_storage nfs_ss;
1099abd2f56Sdsl struct netconfig *nconf;
1109abd2f56Sdsl const char *netid;
1119abd2f56Sdsl struct timeval pertry, try;
1129abd2f56Sdsl enum clnt_stat clnt_stat;
113ebeaf83fSyamt int i, nfsvers, mntvers;
114ebeaf83fSyamt int retryleft;
1159abd2f56Sdsl char *hostp, *delimp;
1169abd2f56Sdsl static struct nfhret nfhret;
1179abd2f56Sdsl static char nam[MNAMELEN + 1];
1189abd2f56Sdsl
11933bed52cShubertf strlcpy(nam, spec, sizeof(nam));
1209abd2f56Sdsl if ((delimp = strchr(spec, '@')) != NULL) {
1219abd2f56Sdsl hostp = delimp + 1;
1229abd2f56Sdsl } else if ((delimp = strrchr(spec, ':')) != NULL) {
1239abd2f56Sdsl hostp = spec;
1249abd2f56Sdsl spec = delimp + 1;
1259abd2f56Sdsl } else {
1269abd2f56Sdsl warnx("no <host>:<dirpath> or <dirpath>@<host> spec");
1279abd2f56Sdsl return (0);
1289abd2f56Sdsl }
1299abd2f56Sdsl *delimp = '\0';
1309abd2f56Sdsl
1319abd2f56Sdsl /*
132dae26da4Syamt * Handle an internet host address.
1339abd2f56Sdsl */
1349abd2f56Sdsl memset(&hints, 0, sizeof hints);
1359abd2f56Sdsl hints.ai_flags = AI_NUMERICHOST;
1369abd2f56Sdsl hints.ai_socktype = nfsargsp->sotype;
137dae26da4Syamt if (getaddrinfo(hostp, "nfs", &hints, &ai_nfs) != 0) {
1389abd2f56Sdsl hints.ai_flags = 0;
1399abd2f56Sdsl if ((ecode = getaddrinfo(hostp, "nfs", &hints, &ai_nfs)) != 0) {
1409abd2f56Sdsl warnx("can't get net id for host \"%s\": %s", hostp,
1419abd2f56Sdsl gai_strerror(ecode));
1429abd2f56Sdsl return (0);
1439abd2f56Sdsl }
1449abd2f56Sdsl }
1459abd2f56Sdsl
146ebeaf83fSyamt if ((nfsargsp->flags & NFSMNT_NFSV3) != 0) {
1479abd2f56Sdsl nfsvers = NFS_VER3;
1489abd2f56Sdsl mntvers = RPCMNT_VER3;
149ebeaf83fSyamt } else {
150ebeaf83fSyamt nfsvers = NFS_VER2;
151ebeaf83fSyamt mntvers = RPCMNT_VER1;
1529abd2f56Sdsl }
1539abd2f56Sdsl nfhret.stat = EACCES; /* Mark not yet successful */
1549abd2f56Sdsl
1559abd2f56Sdsl for (ai = ai_nfs; ai; ai = ai->ai_next) {
1569abd2f56Sdsl /*
157d8a28639Shubertf * XXX. Need a generic (family, type, proto) -> nconf interface.
1589abd2f56Sdsl * __rpc_*2nconf exist, maybe they should be exported.
1599abd2f56Sdsl */
1609abd2f56Sdsl if (nfsargsp->sotype == SOCK_STREAM) {
1619abd2f56Sdsl if (ai->ai_family == AF_INET6)
1629abd2f56Sdsl netid = "tcp6";
1639abd2f56Sdsl else
1649abd2f56Sdsl netid = "tcp";
1659abd2f56Sdsl } else {
1669abd2f56Sdsl if (ai->ai_family == AF_INET6)
1679abd2f56Sdsl netid = "udp6";
1689abd2f56Sdsl else
1699abd2f56Sdsl netid = "udp";
1709abd2f56Sdsl }
1719abd2f56Sdsl
1729abd2f56Sdsl nconf = getnetconfigent(netid);
1739abd2f56Sdsl
1749abd2f56Sdsl tryagain:
175ebeaf83fSyamt retryleft = retrycnt;
1769abd2f56Sdsl
177ebeaf83fSyamt while (retryleft > 0) {
1789abd2f56Sdsl nfs_nb.buf = &nfs_ss;
1799abd2f56Sdsl nfs_nb.maxlen = sizeof nfs_ss;
1809abd2f56Sdsl if (!rpcb_getaddr(RPCPROG_NFS, nfsvers, nconf, &nfs_nb, hostp)){
1819abd2f56Sdsl if (rpc_createerr.cf_stat == RPC_SYSTEMERROR) {
1829abd2f56Sdsl nfhret.stat = rpc_createerr.cf_error.re_errno;
1839abd2f56Sdsl break;
1849abd2f56Sdsl }
1859abd2f56Sdsl if (rpc_createerr.cf_stat == RPC_UNKNOWNPROTO) {
1869abd2f56Sdsl nfhret.stat = EPROTONOSUPPORT;
1879abd2f56Sdsl break;
1889abd2f56Sdsl }
18956a6edc1Spooka if ((opflags & ISBGRND) == 0) {
19056a6edc1Spooka char buf[64];
19156a6edc1Spooka
19256a6edc1Spooka snprintf(buf, sizeof(buf),
19356a6edc1Spooka "%s: rpcbind to nfs on server",
19456a6edc1Spooka getprogname());
19556a6edc1Spooka clnt_pcreateerror(buf);
19656a6edc1Spooka }
1979abd2f56Sdsl } else {
1983c955ef2Syamt pertry.tv_sec = 30;
1999abd2f56Sdsl pertry.tv_usec = 0;
2009abd2f56Sdsl /*
2019abd2f56Sdsl * XXX relies on clnt_tcp_create to bind to a reserved
2029abd2f56Sdsl * socket.
2039abd2f56Sdsl */
2049abd2f56Sdsl clp = clnt_tp_create(hostp, RPCPROG_MNT, mntvers,
205e18b8724Schristos mnttcp_ok ? nconf : getnetconfigent(netid));
2069abd2f56Sdsl if (clp == NULL) {
2079abd2f56Sdsl if ((opflags & ISBGRND) == 0) {
2089abd2f56Sdsl clnt_pcreateerror(
2099abd2f56Sdsl "Cannot MNT RPC (mountd)");
2109abd2f56Sdsl }
2119abd2f56Sdsl } else {
2129abd2f56Sdsl CLNT_CONTROL(clp, CLSET_RETRY_TIMEOUT,
2139abd2f56Sdsl (char *)&pertry);
2149abd2f56Sdsl clp->cl_auth = authsys_create_default();
2153c955ef2Syamt try.tv_sec = 30;
2169abd2f56Sdsl try.tv_usec = 0;
2179abd2f56Sdsl nfhret.auth = RPCAUTH_UNIX;
2189abd2f56Sdsl nfhret.vers = mntvers;
2199abd2f56Sdsl clnt_stat = clnt_call(clp, RPCMNT_MOUNT,
2209abd2f56Sdsl xdr_dir, spec, xdr_fh, &nfhret, try);
2219abd2f56Sdsl switch (clnt_stat) {
2229abd2f56Sdsl case RPC_PROGVERSMISMATCH:
2239abd2f56Sdsl if (nfsvers == NFS_VER3 && !force3) {
2249abd2f56Sdsl nfsvers = NFS_VER2;
2259abd2f56Sdsl mntvers = RPCMNT_VER1;
2269abd2f56Sdsl nfsargsp->flags &=
2279abd2f56Sdsl ~NFSMNT_NFSV3;
2289abd2f56Sdsl goto tryagain;
2299abd2f56Sdsl } else {
2309abd2f56Sdsl errx(1, "%s", clnt_sperror(clp,
2319abd2f56Sdsl "MNT RPC"));
2329abd2f56Sdsl }
2339abd2f56Sdsl case RPC_SUCCESS:
2349abd2f56Sdsl auth_destroy(clp->cl_auth);
2359abd2f56Sdsl clnt_destroy(clp);
236ebeaf83fSyamt retryleft = 0;
2379abd2f56Sdsl break;
2389abd2f56Sdsl default:
2399abd2f56Sdsl /* XXX should give up on some errors */
2409abd2f56Sdsl if ((opflags & ISBGRND) == 0)
2419abd2f56Sdsl warnx("%s", clnt_sperror(clp,
2429abd2f56Sdsl "bad MNT RPC"));
2439abd2f56Sdsl break;
2449abd2f56Sdsl }
2459abd2f56Sdsl }
2469abd2f56Sdsl }
247ebeaf83fSyamt if (--retryleft > 0) {
2489abd2f56Sdsl if (opflags & BGRND) {
2499abd2f56Sdsl opflags &= ~BGRND;
2509abd2f56Sdsl if ((i = fork()) != 0) {
2519abd2f56Sdsl if (i == -1)
252084e92b6Spooka err(1, "fork");
2539abd2f56Sdsl exit(0);
2549abd2f56Sdsl }
2559abd2f56Sdsl (void) setsid();
2569abd2f56Sdsl (void) close(STDIN_FILENO);
2579abd2f56Sdsl (void) close(STDOUT_FILENO);
2589abd2f56Sdsl (void) close(STDERR_FILENO);
2599abd2f56Sdsl (void) chdir("/");
2609abd2f56Sdsl opflags |= ISBGRND;
2619abd2f56Sdsl }
26283c92bb4Spooka sleep(MOUNTNFS_RETRYRPC);
2639abd2f56Sdsl }
2649abd2f56Sdsl }
2659abd2f56Sdsl if (nfhret.stat == 0)
2669abd2f56Sdsl break;
2679abd2f56Sdsl }
2689abd2f56Sdsl freeaddrinfo(ai_nfs);
2699abd2f56Sdsl if (nfhret.stat) {
2709abd2f56Sdsl if (opflags & ISBGRND)
2719abd2f56Sdsl exit(1);
2729abd2f56Sdsl errno = nfhret.stat;
2739abd2f56Sdsl warnx("can't access %s: %s", spec, strerror(nfhret.stat));
2749abd2f56Sdsl return (0);
275e240adbdSjoerg } else {
2769abd2f56Sdsl nfsargsp->addr = (struct sockaddr *) nfs_nb.buf;
2779abd2f56Sdsl nfsargsp->addrlen = nfs_nb.len;
2789abd2f56Sdsl if (port != 0) {
2799abd2f56Sdsl struct sockaddr *sa = nfsargsp->addr;
2809abd2f56Sdsl switch (sa->sa_family) {
2819abd2f56Sdsl case AF_INET:
2829abd2f56Sdsl ((struct sockaddr_in *)sa)->sin_port = port;
283c23511b3Sdsl break;
2849abd2f56Sdsl #ifdef INET6
2859abd2f56Sdsl case AF_INET6:
2869abd2f56Sdsl ((struct sockaddr_in6 *)sa)->sin6_port = port;
2879abd2f56Sdsl break;
2889abd2f56Sdsl #endif
2899abd2f56Sdsl default:
2909abd2f56Sdsl errx(1, "Unsupported socket family %d",
2919abd2f56Sdsl sa->sa_family);
2929abd2f56Sdsl }
2939abd2f56Sdsl }
2949abd2f56Sdsl }
2959abd2f56Sdsl nfsargsp->fh = nfhret.nfh;
2969abd2f56Sdsl nfsargsp->fhsize = nfhret.fhsize;
2979abd2f56Sdsl nfsargsp->hostname = nam;
2989abd2f56Sdsl return (1);
2999abd2f56Sdsl }
3009abd2f56Sdsl
3019abd2f56Sdsl /*
3029abd2f56Sdsl * xdr routines for mount rpc's
3039abd2f56Sdsl */
3049abd2f56Sdsl static int
xdr_dir(XDR * xdrsp,char * dirp)3059abd2f56Sdsl xdr_dir(XDR *xdrsp, char *dirp)
3069abd2f56Sdsl {
3079abd2f56Sdsl return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
3089abd2f56Sdsl }
3099abd2f56Sdsl
3109abd2f56Sdsl static int
xdr_fh(XDR * xdrsp,struct nfhret * np)3119abd2f56Sdsl xdr_fh(XDR *xdrsp, struct nfhret *np)
3129abd2f56Sdsl {
3139abd2f56Sdsl int i;
3149abd2f56Sdsl long auth, authcnt, authfnd = 0;
3159abd2f56Sdsl
3169abd2f56Sdsl if (!xdr_u_long(xdrsp, &np->stat))
3179abd2f56Sdsl return (0);
3189abd2f56Sdsl if (np->stat)
3199abd2f56Sdsl return (1);
3209abd2f56Sdsl switch (np->vers) {
3219abd2f56Sdsl case 1:
3229abd2f56Sdsl np->fhsize = NFSX_V2FH;
3239abd2f56Sdsl return (xdr_opaque(xdrsp, (caddr_t)np->nfh, NFSX_V2FH));
3249abd2f56Sdsl case 3:
3259abd2f56Sdsl if (!xdr_long(xdrsp, &np->fhsize))
3269abd2f56Sdsl return (0);
3279abd2f56Sdsl if (np->fhsize <= 0 || np->fhsize > NFSX_V3FHMAX)
3289abd2f56Sdsl return (0);
3299abd2f56Sdsl if (!xdr_opaque(xdrsp, (caddr_t)np->nfh, np->fhsize))
3309abd2f56Sdsl return (0);
3319abd2f56Sdsl if (!xdr_long(xdrsp, &authcnt))
3329abd2f56Sdsl return (0);
3339abd2f56Sdsl for (i = 0; i < authcnt; i++) {
3349abd2f56Sdsl if (!xdr_long(xdrsp, &auth))
3359abd2f56Sdsl return (0);
3369abd2f56Sdsl if (auth == np->auth)
3379abd2f56Sdsl authfnd++;
3389abd2f56Sdsl }
3399abd2f56Sdsl /*
3409abd2f56Sdsl * Some servers, such as DEC's OSF/1 return a nil authenticator
3419abd2f56Sdsl * list to indicate RPCAUTH_UNIX.
3429abd2f56Sdsl */
3439abd2f56Sdsl if (!authfnd && (authcnt > 0 || np->auth != RPCAUTH_UNIX))
3449abd2f56Sdsl np->stat = EAUTH;
3459abd2f56Sdsl return (1);
3469abd2f56Sdsl };
3479abd2f56Sdsl return (0);
3489abd2f56Sdsl }
349