1 1.18 christos /* $NetBSD: getnfsargs.c,v 1.18 2017/02/05 00:24:24 christos Exp $ */ 2 1.1 dsl 3 1.1 dsl /* 4 1.1 dsl * Copyright (c) 1992, 1993, 1994 5 1.1 dsl * The Regents of the University of California. All rights reserved. 6 1.1 dsl * 7 1.1 dsl * This code is derived from software contributed to Berkeley by 8 1.1 dsl * Rick Macklem at The University of Guelph. 9 1.1 dsl * 10 1.1 dsl * Redistribution and use in source and binary forms, with or without 11 1.1 dsl * modification, are permitted provided that the following conditions 12 1.1 dsl * are met: 13 1.1 dsl * 1. Redistributions of source code must retain the above copyright 14 1.1 dsl * notice, this list of conditions and the following disclaimer. 15 1.1 dsl * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 dsl * notice, this list of conditions and the following disclaimer in the 17 1.1 dsl * documentation and/or other materials provided with the distribution. 18 1.1 dsl * 3. Neither the name of the University nor the names of its contributors 19 1.1 dsl * may be used to endorse or promote products derived from this software 20 1.1 dsl * without specific prior written permission. 21 1.1 dsl * 22 1.1 dsl * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 dsl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 dsl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 dsl * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 dsl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 dsl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 dsl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 dsl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 dsl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 dsl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 dsl * SUCH DAMAGE. 33 1.1 dsl */ 34 1.1 dsl 35 1.1 dsl #include <sys/cdefs.h> 36 1.1 dsl #ifndef lint 37 1.11 lukem __COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\ 38 1.11 lukem The Regents of the University of California. All rights reserved."); 39 1.1 dsl #endif /* not lint */ 40 1.1 dsl 41 1.1 dsl #ifndef lint 42 1.1 dsl #if 0 43 1.1 dsl static char sccsid[] = "@(#)mount_nfs.c 8.11 (Berkeley) 5/4/95"; 44 1.1 dsl #else 45 1.18 christos __RCSID("$NetBSD: getnfsargs.c,v 1.18 2017/02/05 00:24:24 christos Exp $"); 46 1.1 dsl #endif 47 1.1 dsl #endif /* not lint */ 48 1.1 dsl 49 1.1 dsl #include <sys/param.h> 50 1.1 dsl #include <sys/mount.h> 51 1.1 dsl #include <sys/socket.h> 52 1.1 dsl #include <sys/stat.h> 53 1.1 dsl #include <syslog.h> 54 1.1 dsl 55 1.1 dsl #include <rpc/rpc.h> 56 1.1 dsl #include <rpc/pmap_clnt.h> 57 1.1 dsl #include <rpc/pmap_prot.h> 58 1.1 dsl 59 1.1 dsl #include <nfs/rpcv2.h> 60 1.1 dsl #include <nfs/nfsproto.h> 61 1.1 dsl #include <nfs/nfs.h> 62 1.1 dsl #include <nfs/nfsmount.h> 63 1.1 dsl 64 1.1 dsl #include <arpa/inet.h> 65 1.1 dsl 66 1.1 dsl #include <err.h> 67 1.1 dsl #include <errno.h> 68 1.1 dsl #include <fcntl.h> 69 1.1 dsl #include <netdb.h> 70 1.1 dsl #include <signal.h> 71 1.1 dsl #include <stdio.h> 72 1.1 dsl #include <stdlib.h> 73 1.1 dsl #include <string.h> 74 1.1 dsl #include <unistd.h> 75 1.1 dsl #include <util.h> 76 1.1 dsl 77 1.1 dsl #include "mount_nfs.h" 78 1.1 dsl 79 1.16 christos int retrycnt = DEF_RETRY; 80 1.16 christos int opflags = 0; 81 1.16 christos int force2 = 0; 82 1.16 christos int force3 = 0; 83 1.16 christos int mnttcp_ok = 1; 84 1.16 christos int port = 0; 85 1.16 christos 86 1.1 dsl struct nfhret { 87 1.1 dsl u_long stat; 88 1.1 dsl long vers; 89 1.1 dsl long auth; 90 1.1 dsl long fhsize; 91 1.1 dsl u_char nfh[NFSX_V3FHMAX]; 92 1.1 dsl }; 93 1.1 dsl 94 1.1 dsl static int xdr_dir(XDR *, char *); 95 1.1 dsl static int xdr_fh(XDR *, struct nfhret *); 96 1.1 dsl 97 1.14 pooka #ifndef MOUNTNFS_RETRYRPC 98 1.14 pooka #define MOUNTNFS_RETRYRPC 60 99 1.14 pooka #endif 100 1.14 pooka 101 1.1 dsl int 102 1.1 dsl getnfsargs(char *spec, struct nfs_args *nfsargsp) 103 1.1 dsl { 104 1.1 dsl CLIENT *clp; 105 1.1 dsl struct addrinfo hints, *ai_nfs, *ai; 106 1.1 dsl int ecode; 107 1.1 dsl static struct netbuf nfs_nb; 108 1.1 dsl static struct sockaddr_storage nfs_ss; 109 1.1 dsl struct netconfig *nconf; 110 1.1 dsl const char *netid; 111 1.1 dsl struct timeval pertry, try; 112 1.1 dsl enum clnt_stat clnt_stat; 113 1.5 yamt int i, nfsvers, mntvers; 114 1.5 yamt int retryleft; 115 1.1 dsl char *hostp, *delimp; 116 1.1 dsl static struct nfhret nfhret; 117 1.1 dsl static char nam[MNAMELEN + 1]; 118 1.1 dsl 119 1.6 hubertf strlcpy(nam, spec, sizeof(nam)); 120 1.1 dsl if ((delimp = strchr(spec, '@')) != NULL) { 121 1.1 dsl hostp = delimp + 1; 122 1.1 dsl } else if ((delimp = strrchr(spec, ':')) != NULL) { 123 1.1 dsl hostp = spec; 124 1.1 dsl spec = delimp + 1; 125 1.1 dsl } else { 126 1.1 dsl warnx("no <host>:<dirpath> or <dirpath>@<host> spec"); 127 1.1 dsl return (0); 128 1.1 dsl } 129 1.1 dsl *delimp = '\0'; 130 1.1 dsl 131 1.1 dsl /* 132 1.8 yamt * Handle an internet host address. 133 1.1 dsl */ 134 1.1 dsl memset(&hints, 0, sizeof hints); 135 1.1 dsl hints.ai_flags = AI_NUMERICHOST; 136 1.1 dsl hints.ai_socktype = nfsargsp->sotype; 137 1.8 yamt if (getaddrinfo(hostp, "nfs", &hints, &ai_nfs) != 0) { 138 1.1 dsl hints.ai_flags = 0; 139 1.1 dsl if ((ecode = getaddrinfo(hostp, "nfs", &hints, &ai_nfs)) != 0) { 140 1.1 dsl warnx("can't get net id for host \"%s\": %s", hostp, 141 1.1 dsl gai_strerror(ecode)); 142 1.1 dsl return (0); 143 1.1 dsl } 144 1.1 dsl } 145 1.1 dsl 146 1.5 yamt if ((nfsargsp->flags & NFSMNT_NFSV3) != 0) { 147 1.5 yamt nfsvers = NFS_VER3; 148 1.5 yamt mntvers = RPCMNT_VER3; 149 1.5 yamt } else { 150 1.1 dsl nfsvers = NFS_VER2; 151 1.1 dsl mntvers = RPCMNT_VER1; 152 1.1 dsl } 153 1.1 dsl nfhret.stat = EACCES; /* Mark not yet successful */ 154 1.1 dsl 155 1.1 dsl for (ai = ai_nfs; ai; ai = ai->ai_next) { 156 1.1 dsl /* 157 1.9 hubertf * XXX. Need a generic (family, type, proto) -> nconf interface. 158 1.1 dsl * __rpc_*2nconf exist, maybe they should be exported. 159 1.1 dsl */ 160 1.1 dsl if (nfsargsp->sotype == SOCK_STREAM) { 161 1.1 dsl if (ai->ai_family == AF_INET6) 162 1.1 dsl netid = "tcp6"; 163 1.1 dsl else 164 1.1 dsl netid = "tcp"; 165 1.1 dsl } else { 166 1.1 dsl if (ai->ai_family == AF_INET6) 167 1.1 dsl netid = "udp6"; 168 1.1 dsl else 169 1.1 dsl netid = "udp"; 170 1.1 dsl } 171 1.1 dsl 172 1.1 dsl nconf = getnetconfigent(netid); 173 1.1 dsl 174 1.1 dsl tryagain: 175 1.5 yamt retryleft = retrycnt; 176 1.1 dsl 177 1.5 yamt while (retryleft > 0) { 178 1.1 dsl nfs_nb.buf = &nfs_ss; 179 1.1 dsl nfs_nb.maxlen = sizeof nfs_ss; 180 1.1 dsl if (!rpcb_getaddr(RPCPROG_NFS, nfsvers, nconf, &nfs_nb, hostp)){ 181 1.1 dsl if (rpc_createerr.cf_stat == RPC_SYSTEMERROR) { 182 1.1 dsl nfhret.stat = rpc_createerr.cf_error.re_errno; 183 1.1 dsl break; 184 1.1 dsl } 185 1.1 dsl if (rpc_createerr.cf_stat == RPC_UNKNOWNPROTO) { 186 1.1 dsl nfhret.stat = EPROTONOSUPPORT; 187 1.1 dsl break; 188 1.1 dsl } 189 1.13 pooka if ((opflags & ISBGRND) == 0) { 190 1.13 pooka char buf[64]; 191 1.13 pooka 192 1.13 pooka snprintf(buf, sizeof(buf), 193 1.13 pooka "%s: rpcbind to nfs on server", 194 1.13 pooka getprogname()); 195 1.13 pooka clnt_pcreateerror(buf); 196 1.13 pooka } 197 1.1 dsl } else { 198 1.10 yamt pertry.tv_sec = 30; 199 1.1 dsl pertry.tv_usec = 0; 200 1.1 dsl /* 201 1.1 dsl * XXX relies on clnt_tcp_create to bind to a reserved 202 1.1 dsl * socket. 203 1.1 dsl */ 204 1.1 dsl clp = clnt_tp_create(hostp, RPCPROG_MNT, mntvers, 205 1.17 christos mnttcp_ok ? nconf : getnetconfigent(netid)); 206 1.1 dsl if (clp == NULL) { 207 1.1 dsl if ((opflags & ISBGRND) == 0) { 208 1.1 dsl clnt_pcreateerror( 209 1.1 dsl "Cannot MNT RPC (mountd)"); 210 1.1 dsl } 211 1.1 dsl } else { 212 1.1 dsl CLNT_CONTROL(clp, CLSET_RETRY_TIMEOUT, 213 1.1 dsl (char *)&pertry); 214 1.1 dsl clp->cl_auth = authsys_create_default(); 215 1.10 yamt try.tv_sec = 30; 216 1.1 dsl try.tv_usec = 0; 217 1.8 yamt nfhret.auth = RPCAUTH_UNIX; 218 1.1 dsl nfhret.vers = mntvers; 219 1.1 dsl clnt_stat = clnt_call(clp, RPCMNT_MOUNT, 220 1.1 dsl xdr_dir, spec, xdr_fh, &nfhret, try); 221 1.1 dsl switch (clnt_stat) { 222 1.1 dsl case RPC_PROGVERSMISMATCH: 223 1.1 dsl if (nfsvers == NFS_VER3 && !force3) { 224 1.1 dsl nfsvers = NFS_VER2; 225 1.1 dsl mntvers = RPCMNT_VER1; 226 1.1 dsl nfsargsp->flags &= 227 1.1 dsl ~NFSMNT_NFSV3; 228 1.1 dsl goto tryagain; 229 1.1 dsl } else { 230 1.1 dsl errx(1, "%s", clnt_sperror(clp, 231 1.1 dsl "MNT RPC")); 232 1.1 dsl } 233 1.1 dsl case RPC_SUCCESS: 234 1.1 dsl auth_destroy(clp->cl_auth); 235 1.1 dsl clnt_destroy(clp); 236 1.5 yamt retryleft = 0; 237 1.1 dsl break; 238 1.1 dsl default: 239 1.1 dsl /* XXX should give up on some errors */ 240 1.1 dsl if ((opflags & ISBGRND) == 0) 241 1.1 dsl warnx("%s", clnt_sperror(clp, 242 1.1 dsl "bad MNT RPC")); 243 1.1 dsl break; 244 1.1 dsl } 245 1.1 dsl } 246 1.1 dsl } 247 1.5 yamt if (--retryleft > 0) { 248 1.1 dsl if (opflags & BGRND) { 249 1.1 dsl opflags &= ~BGRND; 250 1.1 dsl if ((i = fork()) != 0) { 251 1.1 dsl if (i == -1) 252 1.12 pooka err(1, "fork"); 253 1.1 dsl exit(0); 254 1.1 dsl } 255 1.1 dsl (void) setsid(); 256 1.1 dsl (void) close(STDIN_FILENO); 257 1.1 dsl (void) close(STDOUT_FILENO); 258 1.1 dsl (void) close(STDERR_FILENO); 259 1.1 dsl (void) chdir("/"); 260 1.1 dsl opflags |= ISBGRND; 261 1.1 dsl } 262 1.14 pooka sleep(MOUNTNFS_RETRYRPC); 263 1.1 dsl } 264 1.1 dsl } 265 1.1 dsl if (nfhret.stat == 0) 266 1.1 dsl break; 267 1.1 dsl } 268 1.1 dsl freeaddrinfo(ai_nfs); 269 1.1 dsl if (nfhret.stat) { 270 1.1 dsl if (opflags & ISBGRND) 271 1.1 dsl exit(1); 272 1.1 dsl errno = nfhret.stat; 273 1.1 dsl warnx("can't access %s: %s", spec, strerror(nfhret.stat)); 274 1.1 dsl return (0); 275 1.15 joerg } else { 276 1.1 dsl nfsargsp->addr = (struct sockaddr *) nfs_nb.buf; 277 1.1 dsl nfsargsp->addrlen = nfs_nb.len; 278 1.1 dsl if (port != 0) { 279 1.1 dsl struct sockaddr *sa = nfsargsp->addr; 280 1.1 dsl switch (sa->sa_family) { 281 1.1 dsl case AF_INET: 282 1.1 dsl ((struct sockaddr_in *)sa)->sin_port = port; 283 1.3 dsl break; 284 1.1 dsl #ifdef INET6 285 1.1 dsl case AF_INET6: 286 1.1 dsl ((struct sockaddr_in6 *)sa)->sin6_port = port; 287 1.1 dsl break; 288 1.1 dsl #endif 289 1.1 dsl default: 290 1.1 dsl errx(1, "Unsupported socket family %d", 291 1.1 dsl sa->sa_family); 292 1.1 dsl } 293 1.1 dsl } 294 1.1 dsl } 295 1.1 dsl nfsargsp->fh = nfhret.nfh; 296 1.1 dsl nfsargsp->fhsize = nfhret.fhsize; 297 1.1 dsl nfsargsp->hostname = nam; 298 1.1 dsl return (1); 299 1.1 dsl } 300 1.1 dsl 301 1.1 dsl /* 302 1.1 dsl * xdr routines for mount rpc's 303 1.1 dsl */ 304 1.1 dsl static int 305 1.1 dsl xdr_dir(XDR *xdrsp, char *dirp) 306 1.1 dsl { 307 1.1 dsl return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 308 1.1 dsl } 309 1.1 dsl 310 1.1 dsl static int 311 1.1 dsl xdr_fh(XDR *xdrsp, struct nfhret *np) 312 1.1 dsl { 313 1.1 dsl int i; 314 1.1 dsl long auth, authcnt, authfnd = 0; 315 1.1 dsl 316 1.1 dsl if (!xdr_u_long(xdrsp, &np->stat)) 317 1.1 dsl return (0); 318 1.1 dsl if (np->stat) 319 1.1 dsl return (1); 320 1.1 dsl switch (np->vers) { 321 1.1 dsl case 1: 322 1.1 dsl np->fhsize = NFSX_V2FH; 323 1.1 dsl return (xdr_opaque(xdrsp, (caddr_t)np->nfh, NFSX_V2FH)); 324 1.1 dsl case 3: 325 1.1 dsl if (!xdr_long(xdrsp, &np->fhsize)) 326 1.1 dsl return (0); 327 1.1 dsl if (np->fhsize <= 0 || np->fhsize > NFSX_V3FHMAX) 328 1.1 dsl return (0); 329 1.1 dsl if (!xdr_opaque(xdrsp, (caddr_t)np->nfh, np->fhsize)) 330 1.1 dsl return (0); 331 1.1 dsl if (!xdr_long(xdrsp, &authcnt)) 332 1.1 dsl return (0); 333 1.1 dsl for (i = 0; i < authcnt; i++) { 334 1.1 dsl if (!xdr_long(xdrsp, &auth)) 335 1.1 dsl return (0); 336 1.1 dsl if (auth == np->auth) 337 1.1 dsl authfnd++; 338 1.1 dsl } 339 1.1 dsl /* 340 1.1 dsl * Some servers, such as DEC's OSF/1 return a nil authenticator 341 1.1 dsl * list to indicate RPCAUTH_UNIX. 342 1.1 dsl */ 343 1.1 dsl if (!authfnd && (authcnt > 0 || np->auth != RPCAUTH_UNIX)) 344 1.1 dsl np->stat = EAUTH; 345 1.1 dsl return (1); 346 1.1 dsl }; 347 1.1 dsl return (0); 348 1.1 dsl } 349