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 int error = 0; 182 struct vfsconf *vfc; 183 #ifdef KERBEROS 184 uid_t last_ruid; 185 #endif 186 187 #ifdef KERBEROS 188 last_ruid = -1; 189 (void)strcpy(realm, KRB_REALM); 190 #endif 191 retrycnt = DEF_RETRY; 192 193 mntflags = 0; 194 altflags = 0; 195 nfsargs = nfsdefargs; 196 nfsargsp = &nfsargs; 197 while ((c = getopt(argc, argv, 198 "a:bcdD:g:iKklL:Mm:o:PpqR:r:sTt:w:x:")) != EOF) 199 switch (c) { 200 case 'a': 201 num = strtol(optarg, &p, 10); 202 if (*p || num < 0) 203 errx(1, "illegal -a value -- %s", optarg); 204 nfsargsp->readahead = num; 205 nfsargsp->flags |= NFSMNT_READAHEAD; 206 break; 207 case 'b': 208 opflags |= BGRND; 209 break; 210 case 'c': 211 nfsargsp->flags |= NFSMNT_NOCONN; 212 break; 213 case 'D': 214 num = strtol(optarg, &p, 10); 215 if (*p || num <= 0) 216 errx(1, "illegal -D value -- %s", optarg); 217 nfsargsp->deadthresh = num; 218 nfsargsp->flags |= NFSMNT_DEADTHRESH; 219 break; 220 case 'd': 221 nfsargsp->flags |= NFSMNT_DUMBTIMR; 222 break; 223 case 'g': 224 num = strtol(optarg, &p, 10); 225 if (*p || num <= 0) 226 errx(1, "illegal -g value -- %s", optarg); 227 set_rpc_maxgrouplist(num); 228 nfsargsp->maxgrouplist = num; 229 nfsargsp->flags |= NFSMNT_MAXGRPS; 230 break; 231 case 'i': 232 nfsargsp->flags |= NFSMNT_INT; 233 break; 234 #ifdef KERBEROS 235 case 'K': 236 nfsargsp->flags |= NFSMNT_KERB; 237 break; 238 #endif 239 case 'k': 240 nfsargsp->flags |= NFSMNT_NQLOOKLEASE; 241 break; 242 case 'L': 243 num = strtol(optarg, &p, 10); 244 if (*p || num < 2) 245 errx(1, "illegal -L value -- %s", optarg); 246 nfsargsp->leaseterm = num; 247 nfsargsp->flags |= NFSMNT_LEASETERM; 248 break; 249 case 'l': 250 nfsargsp->flags |= NFSMNT_RDIRALOOK; 251 break; 252 case 'M': 253 nfsargsp->flags |= NFSMNT_MYWRITE; 254 break; 255 #ifdef KERBEROS 256 case 'm': 257 (void)strncpy(realm, optarg, REALM_SZ - 1); 258 realm[REALM_SZ - 1] = '\0'; 259 break; 260 #endif 261 case 'o': 262 getmntopts(optarg, mopts, &mntflags, &altflags); 263 if(altflags & ALTF_BG) 264 opflags |= BGRND; 265 if(altflags & ALTF_NOCONN) 266 nfsargsp->flags |= NFSMNT_NOCONN; 267 if(altflags & ALTF_DUMBTIMR) 268 nfsargsp->flags |= NFSMNT_DUMBTIMR; 269 if(altflags & ALTF_INTR) 270 nfsargsp->flags |= NFSMNT_INT; 271 #ifdef KERBEROS 272 if(altflags & ALTF_KERB) 273 nfsargsp->flags |= NFSMNT_KERB; 274 #endif 275 if(altflags & ALTF_NQLOOKLSE) 276 nfsargsp->flags |= NFSMNT_NQLOOKLEASE; 277 if(altflags & ALTF_RDIRALOOK) 278 nfsargsp->flags |= NFSMNT_RDIRALOOK; 279 if(altflags & ALTF_MYWRITE) 280 nfsargsp->flags |= NFSMNT_MYWRITE; 281 if(altflags & ALTF_RESVPORT) 282 nfsargsp->flags |= NFSMNT_RESVPORT; 283 #ifdef ISO 284 if(altflags & ALTF_SEQPACKET) 285 nfsargsp->sotype = SOCK_SEQPACKET; 286 #endif 287 if(altflags & ALTF_NQNFS) 288 nfsargsp->flags |= NFSMNT_NQNFS; 289 if(altflags & ALTF_SOFT) 290 nfsargsp->flags |= NFSMNT_SOFT; 291 if(altflags & ALTF_TCP) 292 nfsargsp->sotype = SOCK_STREAM; 293 altflags = 0; 294 break; 295 case 'P': 296 nfsargsp->flags |= NFSMNT_RESVPORT; 297 break; 298 #ifdef ISO 299 case 'p': 300 nfsargsp->sotype = SOCK_SEQPACKET; 301 break; 302 #endif 303 case 'q': 304 nfsargsp->flags |= NFSMNT_NQNFS; 305 break; 306 case 'R': 307 num = strtol(optarg, &p, 10); 308 if (*p || num <= 0) 309 errx(1, "illegal -R value -- %s", optarg); 310 retrycnt = num; 311 break; 312 case 'r': 313 num = strtol(optarg, &p, 10); 314 if (*p || num <= 0) 315 errx(1, "illegal -r value -- %s", optarg); 316 nfsargsp->rsize = num; 317 nfsargsp->flags |= NFSMNT_RSIZE; 318 break; 319 case 's': 320 nfsargsp->flags |= NFSMNT_SOFT; 321 break; 322 case 'T': 323 nfsargsp->sotype = SOCK_STREAM; 324 break; 325 case 't': 326 num = strtol(optarg, &p, 10); 327 if (*p || num <= 0) 328 errx(1, "illegal -t value -- %s", optarg); 329 nfsargsp->timeo = num; 330 nfsargsp->flags |= NFSMNT_TIMEO; 331 break; 332 case 'w': 333 num = strtol(optarg, &p, 10); 334 if (*p || num <= 0) 335 errx(1, "illegal -w value -- %s", optarg); 336 nfsargsp->wsize = num; 337 nfsargsp->flags |= NFSMNT_WSIZE; 338 break; 339 case 'x': 340 num = strtol(optarg, &p, 10); 341 if (*p || num <= 0) 342 errx(1, "illegal -x value -- %s", optarg); 343 nfsargsp->retrans = num; 344 nfsargsp->flags |= NFSMNT_RETRANS; 345 break; 346 default: 347 usage(); 348 break; 349 } 350 argc -= optind; 351 argv += optind; 352 353 if (argc != 2) 354 error = 1; 355 356 spec = *argv++; 357 name = *argv; 358 359 if (!getnfsargs(spec, nfsargsp)) 360 exit(1); 361 362 vfc = getvfsbyname("nfs"); 363 if(!vfc && vfsisloadable("nfs")) { 364 if(vfsload("nfs")) 365 err(1, "vfsload(nfs)"); 366 endvfsent(); /* flush cache */ 367 vfc = getvfsbyname("nfs"); 368 } 369 370 if (mount(vfc ? vfc->vfc_index : MOUNT_NFS, name, mntflags, nfsargsp)) 371 err(1, "%s", name); 372 if (nfsargsp->flags & (NFSMNT_NQNFS | NFSMNT_KERB)) { 373 if ((opflags & ISBGRND) == 0) { 374 if (i = fork()) { 375 if (i == -1) 376 err(1, "nqnfs 1"); 377 exit(0); 378 } 379 (void) setsid(); 380 (void) close(STDIN_FILENO); 381 (void) close(STDOUT_FILENO); 382 (void) close(STDERR_FILENO); 383 (void) chdir("/"); 384 } 385 openlog("mount_nfs:", LOG_PID, LOG_DAEMON); 386 nfssvc_flag = NFSSVC_MNTD; 387 ncd.ncd_dirp = name; 388 while (nfssvc(nfssvc_flag, (caddr_t)&ncd) < 0) { 389 if (errno != ENEEDAUTH) { 390 syslog(LOG_ERR, "nfssvc err %m"); 391 continue; 392 } 393 nfssvc_flag = 394 NFSSVC_MNTD | NFSSVC_GOTAUTH | NFSSVC_AUTHINFAIL; 395 #ifdef KERBEROS 396 /* 397 * Set up as ncd_authuid for the kerberos call. 398 * Must set ruid to ncd_authuid and reset the 399 * ticket name iff ncd_authuid is not the same 400 * as last time, so that the right ticket file 401 * is found. 402 */ 403 if (ncd.ncd_authuid != last_ruid) { 404 krb_set_tkt_string(""); 405 last_ruid = ncd.ncd_authuid; 406 } 407 setreuid(ncd.ncd_authuid, 0); 408 if (krb_mk_req(&kt, "rcmd", inst, realm, 0) == 409 KSUCCESS && 410 kt.length <= (RPCAUTH_MAXSIZ - 2 * NFSX_UNSIGNED)) { 411 ncd.ncd_authtype = RPCAUTH_NQNFS; 412 ncd.ncd_authlen = kt.length; 413 ncd.ncd_authstr = (char *)kt.dat; 414 nfssvc_flag = NFSSVC_MNTD | NFSSVC_GOTAUTH; 415 } 416 setreuid(0, 0); 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, IPPROTO_UDP)) == 0) { 526 if ((opflags & ISBGRND) == 0) 527 clnt_pcreateerror("NFS Portmap"); 528 } else { 529 saddr.sin_port = 0; 530 pertry.tv_sec = 10; 531 pertry.tv_usec = 0; 532 if ((clp = clntudp_create(&saddr, RPCPROG_MNT, 533 RPCMNT_VER1, pertry, &so)) == NULL) { 534 if ((opflags & ISBGRND) == 0) 535 clnt_pcreateerror("Cannot MNT RPC"); 536 } else { 537 clp->cl_auth = authunix_create_default(); 538 try.tv_sec = 10; 539 try.tv_usec = 0; 540 clnt_stat = clnt_call(clp, RPCMNT_MOUNT, 541 xdr_dir, spec, xdr_fh, &nfhret, try); 542 if (clnt_stat != RPC_SUCCESS) { 543 if ((opflags & ISBGRND) == 0) 544 warnx("%s", clnt_sperror(clp, 545 "bad MNT RPC")); 546 } else { 547 auth_destroy(clp->cl_auth); 548 clnt_destroy(clp); 549 retrycnt = 0; 550 } 551 } 552 } 553 if (--retrycnt > 0) { 554 if (opflags & BGRND) { 555 opflags &= ~BGRND; 556 if (i = fork()) { 557 if (i == -1) 558 err(1, "nqnfs 2"); 559 exit(0); 560 } 561 (void) setsid(); 562 (void) close(STDIN_FILENO); 563 (void) close(STDOUT_FILENO); 564 (void) close(STDERR_FILENO); 565 (void) chdir("/"); 566 opflags |= ISBGRND; 567 } 568 sleep(60); 569 } 570 } 571 if (nfhret.stat) { 572 if (opflags & ISBGRND) 573 exit(1); 574 warn("can't access %s", spec); 575 return (0); 576 } 577 saddr.sin_port = htons(tport); 578 #ifdef ISO 579 if (isoflag) { 580 nfsargsp->addr = (struct sockaddr *) &isoaddr; 581 nfsargsp->addrlen = sizeof (isoaddr); 582 } else 583 #endif /* ISO */ 584 { 585 nfsargsp->addr = (struct sockaddr *) &saddr; 586 nfsargsp->addrlen = sizeof (saddr); 587 } 588 nfsargsp->fh = &nfhret.nfh; 589 nfsargsp->hostname = nam; 590 return (1); 591 } 592 593 /* 594 * xdr routines for mount rpc's 595 */ 596 int 597 xdr_dir(xdrsp, dirp) 598 XDR *xdrsp; 599 char *dirp; 600 { 601 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 602 } 603 604 int 605 xdr_fh(xdrsp, np) 606 XDR *xdrsp; 607 struct nfhret *np; 608 { 609 if (!xdr_u_long(xdrsp, &(np->stat))) 610 return (0); 611 if (np->stat) 612 return (1); 613 return (xdr_opaque(xdrsp, (caddr_t)&(np->nfh), NFSX_FH)); 614 } 615 616 __dead void 617 usage() 618 { 619 (void)fprintf(stderr, "usage: mount_nfs %s\n%s\n%s\n%s\n", 620 "[-bcdiKklMPqsT] [-a maxreadahead] [-D deadthresh]", 621 "\t[-g maxgroups] [-L leaseterm] [-m realm] [-o options] [-R retrycnt]", 622 "\t[-r readsize] [-t timeout] [-w writesize] [-x retrans]", 623 "\trhost:path node"); 624 exit(1); 625 } 626