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 38 static 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 44 static 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 89 #define ALTF_BG 0x1 90 #define ALTF_NOCONN 0x2 91 #define ALTF_DUMBTIMR 0x4 92 #define ALTF_INTR 0x8 93 #define ALTF_KERB 0x10 94 #define ALTF_NQLOOKLSE 0x20 95 #define ALTF_RDIRALOOK 0x40 96 #define ALTF_MYWRITE 0x80 97 #define ALTF_RESVPORT 0x100 98 #define ALTF_SEQPACKET 0x200 99 #define ALTF_NQNFS 0x400 100 #define ALTF_SOFT 0x800 101 #define ALTF_TCP 0x1000 102 103 struct mntopt mopts[] = { 104 MOPT_STDOPTS, 105 MOPT_FORCE, 106 MOPT_UPDATE, 107 { "bg", 0, ALTF_BG, 1 }, 108 { "conn", 1, ALTF_NOCONN, 1 }, 109 { "dumbtimer", 0, ALTF_DUMBTIMR, 1 }, 110 { "intr", 0, ALTF_INTR, 1 }, 111 #ifdef KERBEROS 112 { "kerb", 0, ALTF_KERB, 1 }, 113 #endif 114 { "nqlooklease", 0, ALTF_NQLOOKLSE, 1 }, 115 { "rdiralook", 0, ALTF_RDIRALOOK, 1 }, 116 { "mywrite", 0, ALTF_MYWRITE, 1 }, 117 { "resvport", 0, ALTF_RESVPORT, 1 }, 118 #ifdef ISO 119 { "seqpacket", 0, ALTF_SEQPACKET, 1 }, 120 #endif 121 { "nqnfs", 0, ALTF_NQNFS, 1 }, 122 { "soft", 0, ALTF_SOFT, 1 }, 123 { "tcp", 0, ALTF_TCP, 1 }, 124 { NULL } 125 }; 126 127 struct nfs_args nfsdefargs = { 128 (struct sockaddr *)0, 129 sizeof (struct sockaddr_in), 130 SOCK_DGRAM, 131 0, 132 (nfsv2fh_t *)0, 133 0, 134 NFS_WSIZE, 135 NFS_RSIZE, 136 NFS_TIMEO, 137 NFS_RETRANS, 138 NFS_MAXGRPS, 139 NFS_DEFRAHEAD, 140 NQ_DEFLEASE, 141 NQ_DEADTHRESH, 142 (char *)0, 143 }; 144 145 struct nfhret { 146 u_long stat; 147 nfsv2fh_t nfh; 148 }; 149 #define DEF_RETRY 10000 150 #define BGRND 1 151 #define ISBGRND 2 152 int retrycnt = DEF_RETRY; 153 int opflags = 0; 154 155 #ifdef KERBEROS 156 char inst[INST_SZ]; 157 char realm[REALM_SZ]; 158 KTEXT_ST kt; 159 #endif 160 161 int getnfsargs __P((char *, struct nfs_args *)); 162 #ifdef ISO 163 struct iso_addr *iso_addr __P((const char *)); 164 #endif 165 void set_rpc_maxgrouplist __P((int)); 166 __dead void usage __P((void)); 167 int xdr_dir __P((XDR *, char *)); 168 int xdr_fh __P((XDR *, struct nfhret *)); 169 170 int 171 main(argc, argv) 172 int argc; 173 char *argv[]; 174 { 175 register int c; 176 register struct nfs_args *nfsargsp; 177 struct nfs_args nfsargs; 178 struct nfsd_cargs ncd; 179 int mntflags, altflags, i, nfssvc_flag, num; 180 char *name, *p, *spec; 181 struct vfsconf *vfc; 182 #ifdef KERBEROS 183 uid_t last_ruid; 184 #endif 185 186 #ifdef KERBEROS 187 last_ruid = -1; 188 (void)strcpy(realm, KRB_REALM); 189 #endif 190 retrycnt = DEF_RETRY; 191 192 mntflags = 0; 193 altflags = 0; 194 nfsargs = nfsdefargs; 195 nfsargsp = &nfsargs; 196 while ((c = getopt(argc, argv, 197 "a:bcdD:g:iKklL:Mm:o:PpqR:r:sTt:w:x:")) != EOF) 198 switch (c) { 199 case 'a': 200 num = strtol(optarg, &p, 10); 201 if (*p || num < 0) 202 errx(1, "illegal -a value -- %s", optarg); 203 nfsargsp->readahead = num; 204 nfsargsp->flags |= NFSMNT_READAHEAD; 205 break; 206 case 'b': 207 opflags |= BGRND; 208 break; 209 case 'c': 210 nfsargsp->flags |= NFSMNT_NOCONN; 211 break; 212 case 'D': 213 num = strtol(optarg, &p, 10); 214 if (*p || num <= 0) 215 errx(1, "illegal -D value -- %s", optarg); 216 nfsargsp->deadthresh = num; 217 nfsargsp->flags |= NFSMNT_DEADTHRESH; 218 break; 219 case 'd': 220 nfsargsp->flags |= NFSMNT_DUMBTIMR; 221 break; 222 case 'g': 223 num = strtol(optarg, &p, 10); 224 if (*p || num <= 0) 225 errx(1, "illegal -g value -- %s", optarg); 226 set_rpc_maxgrouplist(num); 227 nfsargsp->maxgrouplist = num; 228 nfsargsp->flags |= NFSMNT_MAXGRPS; 229 break; 230 case 'i': 231 nfsargsp->flags |= NFSMNT_INT; 232 break; 233 #ifdef KERBEROS 234 case 'K': 235 nfsargsp->flags |= NFSMNT_KERB; 236 break; 237 #endif 238 case 'k': 239 nfsargsp->flags |= NFSMNT_NQLOOKLEASE; 240 break; 241 case 'L': 242 num = strtol(optarg, &p, 10); 243 if (*p || num < 2) 244 errx(1, "illegal -L value -- %s", optarg); 245 nfsargsp->leaseterm = num; 246 nfsargsp->flags |= NFSMNT_LEASETERM; 247 break; 248 case 'l': 249 nfsargsp->flags |= NFSMNT_RDIRALOOK; 250 break; 251 case 'M': 252 nfsargsp->flags |= NFSMNT_MYWRITE; 253 break; 254 #ifdef KERBEROS 255 case 'm': 256 (void)strncpy(realm, optarg, REALM_SZ - 1); 257 realm[REALM_SZ - 1] = '\0'; 258 break; 259 #endif 260 case 'o': 261 getmntopts(optarg, mopts, &mntflags, &altflags); 262 if(altflags & ALTF_BG) 263 opflags |= BGRND; 264 if(altflags & ALTF_NOCONN) 265 nfsargsp->flags |= NFSMNT_NOCONN; 266 if(altflags & ALTF_DUMBTIMR) 267 nfsargsp->flags |= NFSMNT_DUMBTIMR; 268 if(altflags & ALTF_INTR) 269 nfsargsp->flags |= NFSMNT_INT; 270 #ifdef KERBEROS 271 if(altflags & ALTF_KERB) 272 nfsargsp->flags |= NFSMNT_KERB; 273 #endif 274 if(altflags & ALTF_NQLOOKLSE) 275 nfsargsp->flags |= NFSMNT_NQLOOKLEASE; 276 if(altflags & ALTF_RDIRALOOK) 277 nfsargsp->flags |= NFSMNT_RDIRALOOK; 278 if(altflags & ALTF_MYWRITE) 279 nfsargsp->flags |= NFSMNT_MYWRITE; 280 if(altflags & ALTF_RESVPORT) 281 nfsargsp->flags |= NFSMNT_RESVPORT; 282 #ifdef ISO 283 if(altflags & ALTF_SEQPACKET) 284 nfsargsp->sotype = SOCK_SEQPACKET; 285 #endif 286 if(altflags & ALTF_NQNFS) 287 nfsargsp->flags |= NFSMNT_NQNFS; 288 if(altflags & ALTF_SOFT) 289 nfsargsp->flags |= NFSMNT_SOFT; 290 if(altflags & ALTF_TCP) 291 nfsargsp->sotype = SOCK_STREAM; 292 altflags = 0; 293 break; 294 case 'P': 295 nfsargsp->flags |= NFSMNT_RESVPORT; 296 break; 297 #ifdef ISO 298 case 'p': 299 nfsargsp->sotype = SOCK_SEQPACKET; 300 break; 301 #endif 302 case 'q': 303 nfsargsp->flags |= NFSMNT_NQNFS; 304 break; 305 case 'R': 306 num = strtol(optarg, &p, 10); 307 if (*p || num <= 0) 308 errx(1, "illegal -R value -- %s", optarg); 309 retrycnt = num; 310 break; 311 case 'r': 312 num = strtol(optarg, &p, 10); 313 if (*p || num <= 0) 314 errx(1, "illegal -r value -- %s", optarg); 315 nfsargsp->rsize = num; 316 nfsargsp->flags |= NFSMNT_RSIZE; 317 break; 318 case 's': 319 nfsargsp->flags |= NFSMNT_SOFT; 320 break; 321 case 'T': 322 nfsargsp->sotype = SOCK_STREAM; 323 break; 324 case 't': 325 num = strtol(optarg, &p, 10); 326 if (*p || num <= 0) 327 errx(1, "illegal -t value -- %s", optarg); 328 nfsargsp->timeo = num; 329 nfsargsp->flags |= NFSMNT_TIMEO; 330 break; 331 case 'w': 332 num = strtol(optarg, &p, 10); 333 if (*p || num <= 0) 334 errx(1, "illegal -w value -- %s", optarg); 335 nfsargsp->wsize = num; 336 nfsargsp->flags |= NFSMNT_WSIZE; 337 break; 338 case 'x': 339 num = strtol(optarg, &p, 10); 340 if (*p || num <= 0) 341 errx(1, "illegal -x value -- %s", optarg); 342 nfsargsp->retrans = num; 343 nfsargsp->flags |= NFSMNT_RETRANS; 344 break; 345 default: 346 usage(); 347 break; 348 } 349 argc -= optind; 350 argv += optind; 351 352 if (argc != 2) 353 usage(); 354 355 spec = *argv++; 356 name = *argv; 357 358 if (!getnfsargs(spec, nfsargsp)) 359 exit(1); 360 361 vfc = getvfsbyname("nfs"); 362 if(!vfc && vfsisloadable("nfs")) { 363 if(vfsload("nfs")) 364 err(1, "vfsload(nfs)"); 365 endvfsent(); /* flush cache */ 366 vfc = getvfsbyname("nfs"); 367 } 368 369 if (mount(vfc ? vfc->vfc_index : MOUNT_NFS, name, mntflags, nfsargsp)) 370 err(1, "%s", name); 371 if (nfsargsp->flags & (NFSMNT_NQNFS | NFSMNT_KERB)) { 372 if ((opflags & ISBGRND) == 0) { 373 if (i = fork()) { 374 if (i == -1) 375 err(1, "nqnfs 1"); 376 exit(0); 377 } 378 (void) setsid(); 379 (void) close(STDIN_FILENO); 380 (void) close(STDOUT_FILENO); 381 (void) close(STDERR_FILENO); 382 (void) chdir("/"); 383 } 384 openlog("mount_nfs:", LOG_PID, LOG_DAEMON); 385 nfssvc_flag = NFSSVC_MNTD; 386 ncd.ncd_dirp = name; 387 while (nfssvc(nfssvc_flag, (caddr_t)&ncd) < 0) { 388 if (errno != ENEEDAUTH) { 389 syslog(LOG_ERR, "nfssvc err %m"); 390 continue; 391 } 392 nfssvc_flag = 393 NFSSVC_MNTD | NFSSVC_GOTAUTH | NFSSVC_AUTHINFAIL; 394 #ifdef KERBEROS 395 /* 396 * Set up as ncd_authuid for the kerberos call. 397 * Must set ruid to ncd_authuid and reset the 398 * ticket name iff ncd_authuid is not the same 399 * as last time, so that the right ticket file 400 * is found. 401 */ 402 if (ncd.ncd_authuid != last_ruid) { 403 char buf[512]; 404 (void)sprintf(buf, "%s%d", 405 TKT_ROOT, ncd.ncd_authuid); 406 krb_set_tkt_string(buf); 407 last_ruid = ncd.ncd_authuid; 408 } 409 if (krb_mk_req(&kt, "rcmd", inst, realm, 0) == 410 KSUCCESS && 411 kt.length <= (RPCAUTH_MAXSIZ - 2 * NFSX_UNSIGNED)) { 412 ncd.ncd_authtype = RPCAUTH_NQNFS; 413 ncd.ncd_authlen = kt.length; 414 ncd.ncd_authstr = (char *)kt.dat; 415 nfssvc_flag = NFSSVC_MNTD | NFSSVC_GOTAUTH; 416 } 417 #endif /* KERBEROS */ 418 } 419 } 420 exit(0); 421 } 422 423 int 424 getnfsargs(spec, nfsargsp) 425 char *spec; 426 struct nfs_args *nfsargsp; 427 { 428 register CLIENT *clp; 429 struct hostent *hp; 430 static struct sockaddr_in saddr; 431 #ifdef ISO 432 static struct sockaddr_iso isoaddr; 433 struct iso_addr *isop; 434 int isoflag = 0; 435 #endif 436 struct timeval pertry, try; 437 enum clnt_stat clnt_stat; 438 int so = RPC_ANYSOCK, i; 439 char *hostp, *delimp; 440 #ifdef KERBEROS 441 char *cp; 442 #endif 443 u_short tport; 444 static struct nfhret nfhret; 445 static char nam[MNAMELEN + 1]; 446 447 strncpy(nam, spec, MNAMELEN); 448 nam[MNAMELEN] = '\0'; 449 if ((delimp = strchr(spec, '@')) != NULL) { 450 hostp = delimp + 1; 451 } else if ((delimp = strchr(spec, ':')) != NULL) { 452 hostp = spec; 453 spec = delimp + 1; 454 } else { 455 warnx("no <host>:<dirpath> or <dirpath>@<host> spec"); 456 return (0); 457 } 458 *delimp = '\0'; 459 /* 460 * DUMB!! Until the mount protocol works on iso transport, we must 461 * supply both an iso and an inet address for the host. 462 */ 463 #ifdef ISO 464 if (!strncmp(hostp, "iso=", 4)) { 465 u_short isoport; 466 467 hostp += 4; 468 isoflag++; 469 if ((delimp = strchr(hostp, '+')) == NULL) { 470 warnx("no iso+inet address"); 471 return (0); 472 } 473 *delimp = '\0'; 474 if ((isop = iso_addr(hostp)) == NULL) { 475 warnx("bad ISO address"); 476 return (0); 477 } 478 bzero((caddr_t)&isoaddr, sizeof (isoaddr)); 479 bcopy((caddr_t)isop, (caddr_t)&isoaddr.siso_addr, 480 sizeof (struct iso_addr)); 481 isoaddr.siso_len = sizeof (isoaddr); 482 isoaddr.siso_family = AF_ISO; 483 isoaddr.siso_tlen = 2; 484 isoport = htons(NFS_PORT); 485 bcopy((caddr_t)&isoport, TSEL(&isoaddr), isoaddr.siso_tlen); 486 hostp = delimp + 1; 487 } 488 #endif /* ISO */ 489 490 /* 491 * Handle an internet host address and reverse resolve it if 492 * doing Kerberos. 493 */ 494 if (isdigit(*hostp)) { 495 if ((saddr.sin_addr.s_addr = inet_addr(hostp)) == -1) { 496 warnx("bad net address %s", hostp); 497 return (0); 498 } 499 } else if ((hp = gethostbyname(hostp)) != NULL) { 500 bcopy(hp->h_addr, (caddr_t)&saddr.sin_addr, hp->h_length); 501 } else { 502 warnx("can't get net id for host"); 503 return (0); 504 } 505 #ifdef KERBEROS 506 if ((nfsargsp->flags & NFSMNT_KERB)) { 507 if ((hp = gethostbyaddr((char *)&saddr.sin_addr.s_addr, 508 sizeof (u_long), AF_INET)) == (struct hostent *)0) { 509 warnx("can't reverse resolve net address"); 510 return (0); 511 } 512 bcopy(hp->h_addr, (caddr_t)&saddr.sin_addr, hp->h_length); 513 strncpy(inst, hp->h_name, INST_SZ); 514 inst[INST_SZ - 1] = '\0'; 515 if (cp = strchr(inst, '.')) 516 *cp = '\0'; 517 } 518 #endif /* KERBEROS */ 519 520 nfhret.stat = EACCES; /* Mark not yet successful */ 521 while (retrycnt > 0) { 522 saddr.sin_family = AF_INET; 523 saddr.sin_port = htons(PMAPPORT); 524 if ((tport = pmap_getport(&saddr, RPCPROG_NFS, 525 NFS_VER2, nfsargsp->sotype == SOCK_STREAM ? IPPROTO_TCP : 526 IPPROTO_UDP)) == 0) { 527 if ((opflags & ISBGRND) == 0) 528 clnt_pcreateerror("NFS Portmap"); 529 } else { 530 saddr.sin_port = 0; 531 pertry.tv_sec = 10; 532 pertry.tv_usec = 0; 533 if ((clp = (nfsargsp->sotype == SOCK_STREAM ? 534 clnttcp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1, 535 &so, 0, 0) : 536 clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1, 537 pertry, &so))) == NULL) { 538 if ((opflags & ISBGRND) == 0) 539 clnt_pcreateerror("Cannot MNT RPC"); 540 } else { 541 clp->cl_auth = authunix_create_default(); 542 try.tv_sec = 10; 543 try.tv_usec = 0; 544 clnt_stat = clnt_call(clp, RPCMNT_MOUNT, 545 xdr_dir, spec, xdr_fh, &nfhret, try); 546 if (clnt_stat != RPC_SUCCESS) { 547 if ((opflags & ISBGRND) == 0) 548 warnx("%s", clnt_sperror(clp, 549 "bad MNT RPC")); 550 } else { 551 auth_destroy(clp->cl_auth); 552 clnt_destroy(clp); 553 retrycnt = 0; 554 } 555 } 556 } 557 if (--retrycnt > 0) { 558 if (opflags & BGRND) { 559 opflags &= ~BGRND; 560 if (i = fork()) { 561 if (i == -1) 562 err(1, "nqnfs 2"); 563 exit(0); 564 } 565 (void) setsid(); 566 (void) close(STDIN_FILENO); 567 (void) close(STDOUT_FILENO); 568 (void) close(STDERR_FILENO); 569 (void) chdir("/"); 570 opflags |= ISBGRND; 571 } 572 sleep(60); 573 } 574 } 575 if (nfhret.stat) { 576 if (opflags & ISBGRND) 577 exit(1); 578 errno = nfhret.stat; 579 warn("can't access %s", spec); 580 return (0); 581 } 582 saddr.sin_port = htons(tport); 583 #ifdef ISO 584 if (isoflag) { 585 nfsargsp->addr = (struct sockaddr *) &isoaddr; 586 nfsargsp->addrlen = sizeof (isoaddr); 587 } else 588 #endif /* ISO */ 589 { 590 nfsargsp->addr = (struct sockaddr *) &saddr; 591 nfsargsp->addrlen = sizeof (saddr); 592 } 593 nfsargsp->fh = &nfhret.nfh; 594 nfsargsp->hostname = nam; 595 return (1); 596 } 597 598 /* 599 * xdr routines for mount rpc's 600 */ 601 int 602 xdr_dir(xdrsp, dirp) 603 XDR *xdrsp; 604 char *dirp; 605 { 606 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 607 } 608 609 int 610 xdr_fh(xdrsp, np) 611 XDR *xdrsp; 612 struct nfhret *np; 613 { 614 if (!xdr_u_long(xdrsp, &(np->stat))) 615 return (0); 616 if (np->stat) 617 return (1); 618 return (xdr_opaque(xdrsp, (caddr_t)&(np->nfh), NFSX_FH)); 619 } 620 621 __dead void 622 usage() 623 { 624 (void)fprintf(stderr, "usage: mount_nfs %s\n%s\n%s\n%s\n", 625 "[-bcdiKklMPqsT] [-a maxreadahead] [-D deadthresh]", 626 "\t[-g maxgroups] [-L leaseterm] [-m realm] [-o options] [-R retrycnt]", 627 "\t[-r readsize] [-t timeout] [-w writesize] [-x retrans]", 628 "\trhost:path node"); 629 exit(1); 630 } 631