mount_nfs.c revision 2776
1/* 2 * Copyright (c) 1992, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37#ifndef lint 38static char copyright[] = 39"@(#) Copyright (c) 1992, 1993, 1994\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41#endif /* not lint */ 42 43#ifndef lint 44static char sccsid[] = "@(#)mount_nfs.c 8.3 (Berkeley) 3/27/94"; 45#endif /* not lint */ 46 47#include <sys/param.h> 48#include <sys/mount.h> 49#include <sys/socket.h> 50#include <sys/socketvar.h> 51#include <sys/stat.h> 52#include <sys/syslog.h> 53 54#include <rpc/rpc.h> 55#include <rpc/pmap_clnt.h> 56#include <rpc/pmap_prot.h> 57 58#ifdef ISO 59#include <netiso/iso.h> 60#endif 61 62#ifdef KERBEROS 63#include <kerberosIV/des.h> 64#include <kerberosIV/krb.h> 65#endif 66 67#include <nfs/rpcv2.h> 68#include <nfs/nfsv2.h> 69#define KERNEL 70#include <nfs/nfs.h> 71#undef KERNEL 72#include <nfs/nqnfs.h> 73 74#include <arpa/inet.h> 75 76#include <ctype.h> 77#include <err.h> 78#include <errno.h> 79#include <fcntl.h> 80#include <netdb.h> 81#include <signal.h> 82#include <stdio.h> 83#include <stdlib.h> 84#include <strings.h> 85#include <unistd.h> 86 87#include "mntopts.h" 88 89struct mntopt mopts[] = { 90 MOPT_STDOPTS, 91 MOPT_FORCE, 92 MOPT_UPDATE, 93 { NULL } 94}; 95 96struct nfs_args nfsdefargs = { 97 (struct sockaddr *)0, 98 sizeof (struct sockaddr_in), 99 SOCK_DGRAM, 100 0, 101 (nfsv2fh_t *)0, 102 0, 103 NFS_WSIZE, 104 NFS_RSIZE, 105 NFS_TIMEO, 106 NFS_RETRANS, 107 NFS_MAXGRPS, 108 NFS_DEFRAHEAD, 109 NQ_DEFLEASE, 110 NQ_DEADTHRESH, 111 (char *)0, 112}; 113 114struct nfhret { 115 u_long stat; 116 nfsv2fh_t nfh; 117}; 118#define DEF_RETRY 10000 119#define BGRND 1 120#define ISBGRND 2 121int retrycnt = DEF_RETRY; 122int opflags = 0; 123 124#ifdef KERBEROS 125char inst[INST_SZ]; 126char realm[REALM_SZ]; 127KTEXT_ST kt; 128#endif 129 130int getnfsargs __P((char *, struct nfs_args *)); 131#ifdef ISO 132struct iso_addr *iso_addr __P((const char *)); 133#endif 134void set_rpc_maxgrouplist __P((int)); 135__dead void usage __P((void)); 136int xdr_dir __P((XDR *, char *)); 137int xdr_fh __P((XDR *, struct nfhret *)); 138 139int 140main(argc, argv) 141 int argc; 142 char *argv[]; 143{ 144 register int c; 145 register struct nfs_args *nfsargsp; 146 struct nfs_args nfsargs; 147 struct nfsd_cargs ncd; 148 int mntflags, i, nfssvc_flag, num; 149 char *name, *p, *spec; 150 int error = 0; 151#ifdef KERBEROS 152 uid_t last_ruid; 153#endif 154 155#ifdef KERBEROS 156 last_ruid = -1; 157 (void)strcpy(realm, KRB_REALM); 158#endif 159 retrycnt = DEF_RETRY; 160 161 mntflags = 0; 162 nfsargs = nfsdefargs; 163 nfsargsp = &nfsargs; 164 while ((c = getopt(argc, argv, 165 "a:bcdD:g:iKklL:Mm:o:PpqR:r:sTt:w:x:")) != EOF) 166 switch (c) { 167 case 'a': 168 num = strtol(optarg, &p, 10); 169 if (*p || num < 0) 170 errx(1, "illegal -a value -- %s", optarg); 171 nfsargsp->readahead = num; 172 nfsargsp->flags |= NFSMNT_READAHEAD; 173 break; 174 case 'b': 175 opflags |= BGRND; 176 break; 177 case 'c': 178 nfsargsp->flags |= NFSMNT_NOCONN; 179 break; 180 case 'D': 181 num = strtol(optarg, &p, 10); 182 if (*p || num <= 0) 183 errx(1, "illegal -D value -- %s", optarg); 184 nfsargsp->deadthresh = num; 185 nfsargsp->flags |= NFSMNT_DEADTHRESH; 186 break; 187 case 'd': 188 nfsargsp->flags |= NFSMNT_DUMBTIMR; 189 break; 190 case 'g': 191 num = strtol(optarg, &p, 10); 192 if (*p || num <= 0) 193 errx(1, "illegal -g value -- %s", optarg); 194 set_rpc_maxgrouplist(num); 195 nfsargsp->maxgrouplist = num; 196 nfsargsp->flags |= NFSMNT_MAXGRPS; 197 break; 198 case 'i': 199 nfsargsp->flags |= NFSMNT_INT; 200 break; 201#ifdef KERBEROS 202 case 'K': 203 nfsargsp->flags |= NFSMNT_KERB; 204 break; 205#endif 206 case 'k': 207 nfsargsp->flags |= NFSMNT_NQLOOKLEASE; 208 break; 209 case 'L': 210 num = strtol(optarg, &p, 10); 211 if (*p || num < 2) 212 errx(1, "illegal -L value -- %s", optarg); 213 nfsargsp->leaseterm = num; 214 nfsargsp->flags |= NFSMNT_LEASETERM; 215 break; 216 case 'l': 217 nfsargsp->flags |= NFSMNT_RDIRALOOK; 218 break; 219 case 'M': 220 nfsargsp->flags |= NFSMNT_MYWRITE; 221 break; 222#ifdef KERBEROS 223 case 'm': 224 (void)strncpy(realm, optarg, REALM_SZ - 1); 225 realm[REALM_SZ - 1] = '\0'; 226 break; 227#endif 228 case 'o': 229 getmntopts(optarg, mopts, &mntflags); 230 break; 231 case 'P': 232 nfsargsp->flags |= NFSMNT_RESVPORT; 233 break; 234#ifdef ISO 235 case 'p': 236 nfsargsp->sotype = SOCK_SEQPACKET; 237 break; 238#endif 239 case 'q': 240 nfsargsp->flags |= NFSMNT_NQNFS; 241 break; 242 case 'R': 243 num = strtol(optarg, &p, 10); 244 if (*p || num <= 0) 245 errx(1, "illegal -R value -- %s", optarg); 246 retrycnt = num; 247 break; 248 case 'r': 249 num = strtol(optarg, &p, 10); 250 if (*p || num <= 0) 251 errx(1, "illegal -r value -- %s", optarg); 252 nfsargsp->rsize = num; 253 nfsargsp->flags |= NFSMNT_RSIZE; 254 break; 255 case 's': 256 nfsargsp->flags |= NFSMNT_SOFT; 257 break; 258 case 'T': 259 nfsargsp->sotype = SOCK_STREAM; 260 break; 261 case 't': 262 num = strtol(optarg, &p, 10); 263 if (*p || num <= 0) 264 errx(1, "illegal -t value -- %s", optarg); 265 nfsargsp->timeo = num; 266 nfsargsp->flags |= NFSMNT_TIMEO; 267 break; 268 case 'w': 269 num = strtol(optarg, &p, 10); 270 if (*p || num <= 0) 271 errx(1, "illegal -w value -- %s", optarg); 272 nfsargsp->wsize = num; 273 nfsargsp->flags |= NFSMNT_WSIZE; 274 break; 275 case 'x': 276 num = strtol(optarg, &p, 10); 277 if (*p || num <= 0) 278 errx(1, "illegal -x value -- %s", optarg); 279 nfsargsp->retrans = num; 280 nfsargsp->flags |= NFSMNT_RETRANS; 281 break; 282 default: 283 usage(); 284 break; 285 } 286 argc -= optind; 287 argv += optind; 288 289 if (argc != 2) 290 error = 1; 291 292 spec = *argv++; 293 name = *argv; 294 295 if (!getnfsargs(spec, nfsargsp)) 296 exit(1); 297 if (mount(MOUNT_NFS, name, mntflags, nfsargsp)) 298 err(1, "%s", name); 299 if (nfsargsp->flags & (NFSMNT_NQNFS | NFSMNT_KERB)) { 300 if ((opflags & ISBGRND) == 0) { 301 if (i = fork()) { 302 if (i == -1) 303 err(1, "nqnfs 1"); 304 exit(0); 305 } 306 (void) setsid(); 307 (void) close(STDIN_FILENO); 308 (void) close(STDOUT_FILENO); 309 (void) close(STDERR_FILENO); 310 (void) chdir("/"); 311 } 312 openlog("mount_nfs:", LOG_PID, LOG_DAEMON); 313 nfssvc_flag = NFSSVC_MNTD; 314 ncd.ncd_dirp = name; 315 while (nfssvc(nfssvc_flag, (caddr_t)&ncd) < 0) { 316 if (errno != ENEEDAUTH) { 317 syslog(LOG_ERR, "nfssvc err %m"); 318 continue; 319 } 320 nfssvc_flag = 321 NFSSVC_MNTD | NFSSVC_GOTAUTH | NFSSVC_AUTHINFAIL; 322#ifdef KERBEROS 323 /* 324 * Set up as ncd_authuid for the kerberos call. 325 * Must set ruid to ncd_authuid and reset the 326 * ticket name iff ncd_authuid is not the same 327 * as last time, so that the right ticket file 328 * is found. 329 */ 330 if (ncd.ncd_authuid != last_ruid) { 331 krb_set_tkt_string(""); 332 last_ruid = ncd.ncd_authuid; 333 } 334 setreuid(ncd.ncd_authuid, 0); 335 if (krb_mk_req(&kt, "rcmd", inst, realm, 0) == 336 KSUCCESS && 337 kt.length <= (RPCAUTH_MAXSIZ - 2 * NFSX_UNSIGNED)) { 338 ncd.ncd_authtype = RPCAUTH_NQNFS; 339 ncd.ncd_authlen = kt.length; 340 ncd.ncd_authstr = (char *)kt.dat; 341 nfssvc_flag = NFSSVC_MNTD | NFSSVC_GOTAUTH; 342 } 343 setreuid(0, 0); 344#endif /* KERBEROS */ 345 } 346 } 347 exit(0); 348} 349 350int 351getnfsargs(spec, nfsargsp) 352 char *spec; 353 struct nfs_args *nfsargsp; 354{ 355 register CLIENT *clp; 356 struct hostent *hp; 357 static struct sockaddr_in saddr; 358#ifdef ISO 359 static struct sockaddr_iso isoaddr; 360 struct iso_addr *isop; 361 int isoflag = 0; 362#endif 363 struct timeval pertry, try; 364 enum clnt_stat clnt_stat; 365 int so = RPC_ANYSOCK, i; 366 char *hostp, *delimp; 367#ifdef KERBEROS 368 char *cp; 369#endif 370 u_short tport; 371 static struct nfhret nfhret; 372 static char nam[MNAMELEN + 1]; 373 374 strncpy(nam, spec, MNAMELEN); 375 nam[MNAMELEN] = '\0'; 376 if ((delimp = strchr(spec, '@')) != NULL) { 377 hostp = delimp + 1; 378 } else if ((delimp = strchr(spec, ':')) != NULL) { 379 hostp = spec; 380 spec = delimp + 1; 381 } else { 382 warnx("no <host>:<dirpath> or <dirpath>@<host> spec"); 383 return (0); 384 } 385 *delimp = '\0'; 386 /* 387 * DUMB!! Until the mount protocol works on iso transport, we must 388 * supply both an iso and an inet address for the host. 389 */ 390#ifdef ISO 391 if (!strncmp(hostp, "iso=", 4)) { 392 u_short isoport; 393 394 hostp += 4; 395 isoflag++; 396 if ((delimp = strchr(hostp, '+')) == NULL) { 397 warnx("no iso+inet address"); 398 return (0); 399 } 400 *delimp = '\0'; 401 if ((isop = iso_addr(hostp)) == NULL) { 402 warnx("bad ISO address"); 403 return (0); 404 } 405 bzero((caddr_t)&isoaddr, sizeof (isoaddr)); 406 bcopy((caddr_t)isop, (caddr_t)&isoaddr.siso_addr, 407 sizeof (struct iso_addr)); 408 isoaddr.siso_len = sizeof (isoaddr); 409 isoaddr.siso_family = AF_ISO; 410 isoaddr.siso_tlen = 2; 411 isoport = htons(NFS_PORT); 412 bcopy((caddr_t)&isoport, TSEL(&isoaddr), isoaddr.siso_tlen); 413 hostp = delimp + 1; 414 } 415#endif /* ISO */ 416 417 /* 418 * Handle an internet host address and reverse resolve it if 419 * doing Kerberos. 420 */ 421 if (isdigit(*hostp)) { 422 if ((saddr.sin_addr.s_addr = inet_addr(hostp)) == -1) { 423 warnx("bad net address %s", hostp); 424 return (0); 425 } 426 } else if ((hp = gethostbyname(hostp)) != NULL) { 427 bcopy(hp->h_addr, (caddr_t)&saddr.sin_addr, hp->h_length); 428 } else { 429 warnx("can't get net id for host"); 430 return (0); 431 } 432#ifdef KERBEROS 433 if ((nfsargsp->flags & NFSMNT_KERB)) { 434 if ((hp = gethostbyaddr((char *)&saddr.sin_addr.s_addr, 435 sizeof (u_long), AF_INET)) == (struct hostent *)0) { 436 warnx("can't reverse resolve net address"); 437 return (0); 438 } 439 bcopy(hp->h_addr, (caddr_t)&saddr.sin_addr, hp->h_length); 440 strncpy(inst, hp->h_name, INST_SZ); 441 inst[INST_SZ - 1] = '\0'; 442 if (cp = strchr(inst, '.')) 443 *cp = '\0'; 444 } 445#endif /* KERBEROS */ 446 447 nfhret.stat = EACCES; /* Mark not yet successful */ 448 while (retrycnt > 0) { 449 saddr.sin_family = AF_INET; 450 saddr.sin_port = htons(PMAPPORT); 451 if ((tport = pmap_getport(&saddr, RPCPROG_NFS, 452 NFS_VER2, IPPROTO_UDP)) == 0) { 453 if ((opflags & ISBGRND) == 0) 454 clnt_pcreateerror("NFS Portmap"); 455 } else { 456 saddr.sin_port = 0; 457 pertry.tv_sec = 10; 458 pertry.tv_usec = 0; 459 if ((clp = clntudp_create(&saddr, RPCPROG_MNT, 460 RPCMNT_VER1, pertry, &so)) == NULL) { 461 if ((opflags & ISBGRND) == 0) 462 clnt_pcreateerror("Cannot MNT PRC"); 463 } else { 464 clp->cl_auth = authunix_create_default(); 465 try.tv_sec = 10; 466 try.tv_usec = 0; 467 clnt_stat = clnt_call(clp, RPCMNT_MOUNT, 468 xdr_dir, spec, xdr_fh, &nfhret, try); 469 if (clnt_stat != RPC_SUCCESS) { 470 if ((opflags & ISBGRND) == 0) 471 warnx("%s", clnt_sperror(clp, 472 "bad MNT RPC")); 473 } else { 474 auth_destroy(clp->cl_auth); 475 clnt_destroy(clp); 476 retrycnt = 0; 477 } 478 } 479 } 480 if (--retrycnt > 0) { 481 if (opflags & BGRND) { 482 opflags &= ~BGRND; 483 if (i = fork()) { 484 if (i == -1) 485 err(1, "nqnfs 2"); 486 exit(0); 487 } 488 (void) setsid(); 489 (void) close(STDIN_FILENO); 490 (void) close(STDOUT_FILENO); 491 (void) close(STDERR_FILENO); 492 (void) chdir("/"); 493 opflags |= ISBGRND; 494 } 495 sleep(60); 496 } 497 } 498 if (nfhret.stat) { 499 if (opflags & ISBGRND) 500 exit(1); 501 warn("can't access %s", spec); 502 return (0); 503 } 504 saddr.sin_port = htons(tport); 505#ifdef ISO 506 if (isoflag) { 507 nfsargsp->addr = (struct sockaddr *) &isoaddr; 508 nfsargsp->addrlen = sizeof (isoaddr); 509 } else 510#endif /* ISO */ 511 { 512 nfsargsp->addr = (struct sockaddr *) &saddr; 513 nfsargsp->addrlen = sizeof (saddr); 514 } 515 nfsargsp->fh = &nfhret.nfh; 516 nfsargsp->hostname = nam; 517 return (1); 518} 519 520/* 521 * xdr routines for mount rpc's 522 */ 523int 524xdr_dir(xdrsp, dirp) 525 XDR *xdrsp; 526 char *dirp; 527{ 528 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 529} 530 531int 532xdr_fh(xdrsp, np) 533 XDR *xdrsp; 534 struct nfhret *np; 535{ 536 if (!xdr_u_long(xdrsp, &(np->stat))) 537 return (0); 538 if (np->stat) 539 return (1); 540 return (xdr_opaque(xdrsp, (caddr_t)&(np->nfh), NFSX_FH)); 541} 542 543__dead void 544usage() 545{ 546 (void)fprintf(stderr, "usage: mount_nfs %s\n%s\n%s\n%s\n", 547"[-bcdiKklMPqsT] [-a maxreadahead] [-D deadthresh]", 548"\t[-g maxgroups] [-L leaseterm] [-m realm] [-o options] [-R retrycnt]", 549"\t[-r readsize] [-t timeout] [-w writesize] [-x retrans]", 550"\trhost:path node"); 551 exit(1); 552} 553