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 const 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 #if 0 45 static char sccsid[] = "@(#)mount_nfs.c 8.11 (Berkeley) 5/4/95"; 46 #endif 47 static const char rcsid[] = 48 "$FreeBSD$"; 49 #endif /* not lint */ 50 51 #include <sys/param.h> 52 #include <sys/mount.h> 53 #include <sys/stat.h> 54 #include <sys/syslog.h> 55 56 #include <rpc/rpc.h> 57 #include <rpc/pmap_clnt.h> 58 #include <rpc/pmap_prot.h> 59 60 #ifdef ISO 61 #include <netiso/iso.h> 62 #endif 63 64 #ifdef NFSKERB 65 #include <kerberosIV/des.h> 66 #include <kerberosIV/krb.h> 67 #endif 68 69 #include <nfs/rpcv2.h> 70 #include <nfs/nfsproto.h> 71 #include <nfs/nfs.h> 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 <netdb.h> 80 #include <stdio.h> 81 #include <stdlib.h> 82 #include <strings.h> 83 #include <sysexits.h> 84 #include <unistd.h> 85 86 #include "mntopts.h" 87 88 #define ALTF_BG 0x1 89 #define ALTF_NOCONN 0x2 90 #define ALTF_DUMBTIMR 0x4 91 #define ALTF_INTR 0x8 92 #define ALTF_KERB 0x10 93 #define ALTF_NFSV3 0x20 94 #define ALTF_RDIRPLUS 0x40 95 #define ALTF_MNTUDP 0x80 96 #define ALTF_RESVPORT 0x100 97 #define ALTF_SEQPACKET 0x200 98 #define ALTF_NQNFS 0x400 99 #define ALTF_SOFT 0x800 100 #define ALTF_TCP 0x1000 101 #define ALTF_PORT 0x2000 102 #define ALTF_NFSV2 0x4000 103 #define ALTF_ACREGMIN 0x8000 104 #define ALTF_ACREGMAX 0x10000 105 #define ALTF_ACDIRMIN 0x20000 106 #define ALTF_ACDIRMAX 0x40000 107 108 struct mntopt mopts[] = { 109 MOPT_STDOPTS, 110 MOPT_FORCE, 111 MOPT_UPDATE, 112 MOPT_ASYNC, 113 { "bg", 0, ALTF_BG, 1 }, 114 { "conn", 1, ALTF_NOCONN, 1 }, 115 { "dumbtimer", 0, ALTF_DUMBTIMR, 1 }, 116 { "intr", 0, ALTF_INTR, 1 }, 117 #ifdef NFSKERB 118 { "kerb", 0, ALTF_KERB, 1 }, 119 #endif 120 { "nfsv3", 0, ALTF_NFSV3, 1 }, 121 { "rdirplus", 0, ALTF_RDIRPLUS, 1 }, 122 { "mntudp", 0, ALTF_MNTUDP, 1 }, 123 { "resvport", 0, ALTF_RESVPORT, 1 }, 124 #ifdef ISO 125 { "seqpacket", 0, ALTF_SEQPACKET, 1 }, 126 #endif 127 { "nqnfs", 0, ALTF_NQNFS, 1 }, 128 { "soft", 0, ALTF_SOFT, 1 }, 129 { "tcp", 0, ALTF_TCP, 1 }, 130 { "port=", 0, ALTF_PORT, 1 }, 131 { "nfsv2", 0, ALTF_NFSV2, 1 }, 132 { "acregmin=", 0, ALTF_ACREGMIN, 1 }, 133 { "acregmax=", 0, ALTF_ACREGMAX, 1 }, 134 { "acdirmin=", 0, ALTF_ACDIRMIN, 1 }, 135 { "acdirmax=", 0, ALTF_ACDIRMAX, 1 }, 136 { NULL } 137 }; 138 139 struct nfs_args nfsdefargs = { 140 NFS_ARGSVERSION, 141 (struct sockaddr *)0, 142 sizeof (struct sockaddr_in), 143 SOCK_DGRAM, 144 0, 145 (u_char *)0, 146 0, 147 NFSMNT_RESVPORT, 148 NFS_WSIZE, 149 NFS_RSIZE, 150 NFS_READDIRSIZE, 151 10, 152 NFS_RETRANS, 153 NFS_MAXGRPS, 154 NFS_DEFRAHEAD, 155 NQ_DEFLEASE, 156 NQ_DEADTHRESH, 157 (char *)0, 158 /* args version 4 */ 159 NFS_MINATTRTIMO, 160 NFS_MAXATTRTIMO, 161 NFS_MINDIRATTRTIMO, 162 NFS_MAXDIRATTRTIMO, 163 }; 164 165 struct nfhret { 166 u_long stat; 167 long vers; 168 long auth; 169 long fhsize; 170 u_char nfh[NFSX_V3FHMAX]; 171 }; 172 #define DEF_RETRY 10000 173 #define BGRND 1 174 #define ISBGRND 2 175 int retrycnt = DEF_RETRY; 176 int opflags = 0; 177 int nfsproto = IPPROTO_UDP; 178 int mnttcp_ok = 1; 179 u_short port_no = 0; 180 enum { 181 ANY, 182 V2, 183 V3 184 } mountmode = ANY; 185 186 #ifdef NFSKERB 187 char inst[INST_SZ]; 188 char realm[REALM_SZ]; 189 struct { 190 u_long kind; 191 KTEXT_ST kt; 192 } ktick; 193 struct nfsrpc_nickverf kverf; 194 struct nfsrpc_fullblock kin, kout; 195 NFSKERBKEY_T kivec; 196 CREDENTIALS kcr; 197 struct timeval ktv; 198 NFSKERBKEYSCHED_T kerb_keysched; 199 #endif 200 201 int getnfsargs __P((char *, struct nfs_args *)); 202 #ifdef ISO 203 struct iso_addr *iso_addr __P((const char *)); 204 #endif 205 void set_rpc_maxgrouplist __P((int)); 206 void usage __P((void)) __dead2; 207 int xdr_dir __P((XDR *, char *)); 208 int xdr_fh __P((XDR *, struct nfhret *)); 209 210 /* 211 * Used to set mount flags with getmntopts. Call with dir=TRUE to 212 * initialize altflags from the current mount flags. Call with 213 * dir=FALSE to update mount flags with the new value of altflags after 214 * the call to getmntopts. 215 */ 216 static void 217 setflags(int* altflags, int* nfsflags, int dir) 218 { 219 #define F2(af, nf) \ 220 if (dir) { \ 221 if (*nfsflags & NFSMNT_##nf) \ 222 *altflags |= ALTF_##af; \ 223 else \ 224 *altflags &= ~ALTF_##af; \ 225 } else { \ 226 if (*altflags & ALTF_##af) \ 227 *nfsflags |= NFSMNT_##nf; \ 228 else \ 229 *nfsflags &= ~NFSMNT_##nf; \ 230 } 231 #define F(f) F2(f,f) 232 233 F(NOCONN); 234 F(DUMBTIMR); 235 F2(INTR, INT); 236 #ifdef NFSKERB 237 F(KERB); 238 #endif 239 F(RDIRPLUS); 240 F(RESVPORT); 241 F(NQNFS); 242 F(SOFT); 243 244 #undef F 245 #undef F2 246 } 247 248 int 249 main(argc, argv) 250 int argc; 251 char *argv[]; 252 { 253 register int c; 254 register struct nfs_args *nfsargsp; 255 struct nfs_args nfsargs; 256 struct nfsd_cargs ncd; 257 int mntflags, altflags, i, nfssvc_flag, num; 258 char *name, *p, *spec; 259 char mntpath[MAXPATHLEN]; 260 struct vfsconf vfc; 261 int error = 0; 262 #ifdef NFSKERB 263 uid_t last_ruid; 264 265 last_ruid = -1; 266 (void)strcpy(realm, KRB_REALM); 267 if (sizeof (struct nfsrpc_nickverf) != RPCX_NICKVERF || 268 sizeof (struct nfsrpc_fullblock) != RPCX_FULLBLOCK || 269 ((char *)&ktick.kt) - ((char *)&ktick) != NFSX_UNSIGNED || 270 ((char *)ktick.kt.dat) - ((char *)&ktick) != 2 * NFSX_UNSIGNED) 271 fprintf(stderr, "Yikes! NFSKERB structs not packed!!\n"); 272 #endif /* NFSKERB */ 273 retrycnt = DEF_RETRY; 274 275 mntflags = 0; 276 altflags = 0; 277 nfsargs = nfsdefargs; 278 nfsargsp = &nfsargs; 279 while ((c = getopt(argc, argv, 280 "23a:bcdD:g:I:iKL:lm:No:PpqR:r:sTt:w:x:U")) != -1) 281 switch (c) { 282 case '2': 283 mountmode = V2; 284 break; 285 case '3': 286 mountmode = V3; 287 break; 288 case 'a': 289 num = strtol(optarg, &p, 10); 290 if (*p || num < 0) 291 errx(1, "illegal -a value -- %s", optarg); 292 nfsargsp->readahead = num; 293 nfsargsp->flags |= NFSMNT_READAHEAD; 294 break; 295 case 'b': 296 opflags |= BGRND; 297 break; 298 case 'c': 299 nfsargsp->flags |= NFSMNT_NOCONN; 300 break; 301 case 'D': 302 num = strtol(optarg, &p, 10); 303 if (*p || num <= 0) 304 errx(1, "illegal -D value -- %s", optarg); 305 nfsargsp->deadthresh = num; 306 nfsargsp->flags |= NFSMNT_DEADTHRESH; 307 break; 308 case 'd': 309 nfsargsp->flags |= NFSMNT_DUMBTIMR; 310 break; 311 case 'g': 312 num = strtol(optarg, &p, 10); 313 if (*p || num <= 0) 314 errx(1, "illegal -g value -- %s", optarg); 315 #ifdef __FreeBSD__ 316 set_rpc_maxgrouplist(num); 317 #endif 318 nfsargsp->maxgrouplist = num; 319 nfsargsp->flags |= NFSMNT_MAXGRPS; 320 break; 321 case 'I': 322 num = strtol(optarg, &p, 10); 323 if (*p || num <= 0) 324 errx(1, "illegal -I value -- %s", optarg); 325 nfsargsp->readdirsize = num; 326 nfsargsp->flags |= NFSMNT_READDIRSIZE; 327 break; 328 case 'i': 329 nfsargsp->flags |= NFSMNT_INT; 330 break; 331 #ifdef NFSKERB 332 case 'K': 333 nfsargsp->flags |= NFSMNT_KERB; 334 break; 335 #endif 336 case 'L': 337 num = strtol(optarg, &p, 10); 338 if (*p || num < 2) 339 errx(1, "illegal -L value -- %s", optarg); 340 nfsargsp->leaseterm = num; 341 nfsargsp->flags |= NFSMNT_LEASETERM; 342 break; 343 case 'l': 344 nfsargsp->flags |= NFSMNT_RDIRPLUS; 345 break; 346 #ifdef NFSKERB 347 case 'm': 348 (void)strncpy(realm, optarg, REALM_SZ - 1); 349 realm[REALM_SZ - 1] = '\0'; 350 break; 351 #endif 352 case 'N': 353 nfsargsp->flags &= ~NFSMNT_RESVPORT; 354 break; 355 case 'o': 356 altflags = 0; 357 setflags(&altflags, &nfsargsp->flags, TRUE); 358 if (mountmode == V2) 359 altflags |= ALTF_NFSV2; 360 else if (mountmode == V3) 361 altflags |= ALTF_NFSV3; 362 getmntopts(optarg, mopts, &mntflags, &altflags); 363 setflags(&altflags, &nfsargsp->flags, FALSE); 364 /* 365 * Handle altflags which don't map directly to 366 * mount flags. 367 */ 368 if(altflags & ALTF_BG) 369 opflags |= BGRND; 370 if(altflags & ALTF_MNTUDP) 371 mnttcp_ok = 0; 372 #ifdef ISO 373 if(altflags & ALTF_SEQPACKET) 374 nfsargsp->sotype = SOCK_SEQPACKET; 375 #endif 376 if(altflags & ALTF_TCP) { 377 nfsargsp->sotype = SOCK_STREAM; 378 nfsproto = IPPROTO_TCP; 379 } 380 if(altflags & ALTF_PORT) 381 port_no = atoi(strstr(optarg, "port=") + 5); 382 mountmode = ANY; 383 if(altflags & ALTF_NFSV2) 384 mountmode = V2; 385 if(altflags & ALTF_NFSV3) 386 mountmode = V3; 387 if(altflags & ALTF_ACREGMIN) 388 nfsargsp->acregmin = atoi(strstr(optarg, 389 "acregmin=") + 9); 390 if(altflags & ALTF_ACREGMAX) 391 nfsargsp->acregmax = atoi(strstr(optarg, 392 "acregmax=") + 9); 393 if(altflags & ALTF_ACDIRMIN) 394 nfsargsp->acdirmin = atoi(strstr(optarg, 395 "acdirmin=") + 9); 396 if(altflags & ALTF_ACDIRMAX) 397 nfsargsp->acdirmax = atoi(strstr(optarg, 398 "acdirmax=") + 9); 399 break; 400 case 'P': 401 /* obsolete for NFSMNT_RESVPORT, now default */ 402 break; 403 #ifdef ISO 404 case 'p': 405 nfsargsp->sotype = SOCK_SEQPACKET; 406 break; 407 #endif 408 case 'q': 409 mountmode = V3; 410 nfsargsp->flags |= NFSMNT_NQNFS; 411 break; 412 case 'R': 413 num = strtol(optarg, &p, 10); 414 if (*p || num <= 0) 415 errx(1, "illegal -R value -- %s", optarg); 416 retrycnt = num; 417 break; 418 case 'r': 419 num = strtol(optarg, &p, 10); 420 if (*p || num <= 0) 421 errx(1, "illegal -r value -- %s", optarg); 422 nfsargsp->rsize = num; 423 nfsargsp->flags |= NFSMNT_RSIZE; 424 break; 425 case 's': 426 nfsargsp->flags |= NFSMNT_SOFT; 427 break; 428 case 'T': 429 nfsargsp->sotype = SOCK_STREAM; 430 nfsproto = IPPROTO_TCP; 431 break; 432 case 't': 433 num = strtol(optarg, &p, 10); 434 if (*p || num <= 0) 435 errx(1, "illegal -t value -- %s", optarg); 436 nfsargsp->timeo = num; 437 nfsargsp->flags |= NFSMNT_TIMEO; 438 break; 439 case 'w': 440 num = strtol(optarg, &p, 10); 441 if (*p || num <= 0) 442 errx(1, "illegal -w value -- %s", optarg); 443 nfsargsp->wsize = num; 444 nfsargsp->flags |= NFSMNT_WSIZE; 445 break; 446 case 'x': 447 num = strtol(optarg, &p, 10); 448 if (*p || num <= 0) 449 errx(1, "illegal -x value -- %s", optarg); 450 nfsargsp->retrans = num; 451 nfsargsp->flags |= NFSMNT_RETRANS; 452 break; 453 case 'U': 454 mnttcp_ok = 0; 455 break; 456 default: 457 usage(); 458 break; 459 } 460 argc -= optind; 461 argv += optind; 462 463 if (argc != 2) { 464 usage(); 465 /* NOTREACHED */ 466 } 467 468 spec = *argv++; 469 name = *argv; 470 471 if (!getnfsargs(spec, nfsargsp)) 472 exit(1); 473 474 /* resolve the mountpoint with realpath(3) */ 475 (void)checkpath(name, mntpath); 476 477 #ifdef __FreeBSD__ 478 error = getvfsbyname("nfs", &vfc); 479 if (error && vfsisloadable("nfs")) { 480 if(vfsload("nfs")) 481 err(EX_OSERR, "vfsload(nfs)"); 482 endvfsent(); /* clear cache */ 483 error = getvfsbyname("nfs", &vfc); 484 } 485 if (error) 486 errx(EX_OSERR, "nfs filesystem is not available"); 487 488 if (mount(vfc.vfc_name, mntpath, mntflags, nfsargsp)) 489 err(1, "%s", mntpath); 490 #else 491 if (mount("nfs", mntpath, mntflags, nfsargsp)) 492 err(1, "%s", mntpath); 493 #endif 494 if (nfsargsp->flags & (NFSMNT_NQNFS | NFSMNT_KERB)) { 495 if ((opflags & ISBGRND) == 0) { 496 if ((i = fork())) { 497 if (i == -1) 498 err(1, "nqnfs 1"); 499 exit(0); 500 } 501 (void) setsid(); 502 (void) close(STDIN_FILENO); 503 (void) close(STDOUT_FILENO); 504 (void) close(STDERR_FILENO); 505 (void) chdir("/"); 506 } 507 openlog("mount_nfs:", LOG_PID, LOG_DAEMON); 508 nfssvc_flag = NFSSVC_MNTD; 509 ncd.ncd_dirp = mntpath; 510 while (nfssvc(nfssvc_flag, (caddr_t)&ncd) < 0) { 511 if (errno != ENEEDAUTH) { 512 syslog(LOG_ERR, "nfssvc err %m"); 513 continue; 514 } 515 nfssvc_flag = 516 NFSSVC_MNTD | NFSSVC_GOTAUTH | NFSSVC_AUTHINFAIL; 517 #ifdef NFSKERB 518 /* 519 * Set up as ncd_authuid for the kerberos call. 520 * Must set ruid to ncd_authuid and reset the 521 * ticket name iff ncd_authuid is not the same 522 * as last time, so that the right ticket file 523 * is found. 524 * Get the Kerberos credential structure so that 525 * we have the session key and get a ticket for 526 * this uid. 527 * For more info see the IETF Draft "Authentication 528 * in ONC RPC". 529 */ 530 if (ncd.ncd_authuid != last_ruid) { 531 char buf[512]; 532 (void)sprintf(buf, "%s%d", 533 TKT_ROOT, ncd.ncd_authuid); 534 krb_set_tkt_string(buf); 535 last_ruid = ncd.ncd_authuid; 536 } 537 setreuid(ncd.ncd_authuid, 0); 538 kret = krb_get_cred(NFS_KERBSRV, inst, realm, &kcr); 539 if (kret == RET_NOTKT) { 540 kret = get_ad_tkt(NFS_KERBSRV, inst, realm, 541 DEFAULT_TKT_LIFE); 542 if (kret == KSUCCESS) 543 kret = krb_get_cred(NFS_KERBSRV, inst, realm, 544 &kcr); 545 } 546 if (kret == KSUCCESS) 547 kret = krb_mk_req(&ktick.kt, NFS_KERBSRV, inst, 548 realm, 0); 549 550 /* 551 * Fill in the AKN_FULLNAME authenticator and verifier. 552 * Along with the Kerberos ticket, we need to build 553 * the timestamp verifier and encrypt it in CBC mode. 554 */ 555 if (kret == KSUCCESS && 556 ktick.kt.length <= (RPCAUTH_MAXSIZ-3*NFSX_UNSIGNED) 557 && gettimeofday(&ktv, (struct timezone *)0) == 0) { 558 ncd.ncd_authtype = RPCAUTH_KERB4; 559 ncd.ncd_authstr = (u_char *)&ktick; 560 ncd.ncd_authlen = nfsm_rndup(ktick.kt.length) + 561 3 * NFSX_UNSIGNED; 562 ncd.ncd_verfstr = (u_char *)&kverf; 563 ncd.ncd_verflen = sizeof (kverf); 564 memmove(ncd.ncd_key, kcr.session, 565 sizeof (kcr.session)); 566 kin.t1 = htonl(ktv.tv_sec); 567 kin.t2 = htonl(ktv.tv_usec); 568 kin.w1 = htonl(NFS_KERBTTL); 569 kin.w2 = htonl(NFS_KERBTTL - 1); 570 bzero((caddr_t)kivec, sizeof (kivec)); 571 572 /* 573 * Encrypt kin in CBC mode using the session 574 * key in kcr. 575 */ 576 XXX 577 578 /* 579 * Finally, fill the timestamp verifier into the 580 * authenticator and verifier. 581 */ 582 ktick.kind = htonl(RPCAKN_FULLNAME); 583 kverf.kind = htonl(RPCAKN_FULLNAME); 584 NFS_KERBW1(ktick.kt) = kout.w1; 585 ktick.kt.length = htonl(ktick.kt.length); 586 kverf.verf.t1 = kout.t1; 587 kverf.verf.t2 = kout.t2; 588 kverf.verf.w2 = kout.w2; 589 nfssvc_flag = NFSSVC_MNTD | NFSSVC_GOTAUTH; 590 } 591 setreuid(0, 0); 592 #endif /* NFSKERB */ 593 } 594 } 595 exit(0); 596 } 597 598 /* 599 * Return RPC_SUCCESS if server responds. 600 */ 601 enum clnt_stat 602 pingnfsserver(addr, version, sotype) 603 struct sockaddr_in *addr; 604 int version; 605 int sotype; 606 { 607 struct sockaddr_in sin; 608 int tport; 609 CLIENT *clp; 610 int so = RPC_ANYSOCK; 611 enum clnt_stat stat; 612 struct timeval pertry, try; 613 614 sin = *addr; 615 616 if ((tport = port_no ? port_no : 617 pmap_getport(&sin, RPCPROG_NFS, version, nfsproto)) == 0) { 618 return rpc_createerr.cf_stat; 619 } 620 621 sin.sin_port = htons(tport); 622 623 pertry.tv_sec = 10; 624 pertry.tv_usec = 0; 625 if (sotype == SOCK_STREAM) 626 clp = clnttcp_create(&sin, RPCPROG_NFS, version, 627 &so, 0, 0); 628 else 629 clp = clntudp_create(&sin, RPCPROG_NFS, version, 630 pertry, &so); 631 if (clp == NULL) 632 return rpc_createerr.cf_stat; 633 634 try.tv_sec = 10; 635 try.tv_usec = 0; 636 stat = clnt_call(clp, NFSPROC_NULL, 637 xdr_void, NULL, xdr_void, NULL, try); 638 639 clnt_destroy(clp); 640 641 return stat; 642 } 643 644 int 645 getnfsargs(spec, nfsargsp) 646 char *spec; 647 struct nfs_args *nfsargsp; 648 { 649 register CLIENT *clp; 650 struct hostent *hp; 651 static struct sockaddr_in saddr; 652 #ifdef ISO 653 static struct sockaddr_iso isoaddr; 654 struct iso_addr *isop; 655 int isoflag = 0; 656 #endif 657 struct timeval pertry, try; 658 enum clnt_stat clnt_stat; 659 int so = RPC_ANYSOCK, i, nfsvers, mntvers, orgcnt, speclen; 660 char *hostp, *delimp; 661 #ifdef NFSKERB 662 char *cp; 663 #endif 664 u_short tport; 665 size_t len; 666 static struct nfhret nfhret; 667 static char nam[MNAMELEN + 1]; 668 669 tport = 0; 670 671 if ((delimp = strchr(spec, ':')) != NULL) { 672 hostp = spec; 673 spec = delimp + 1; 674 } else if ((delimp = strrchr(spec, '@')) != NULL) { 675 warnx("path@server syntax is deprecated, use server:path"); 676 hostp = delimp + 1; 677 } else { 678 warnx("no <host>:<dirpath> nfs-name"); 679 return (0); 680 } 681 682 *delimp = '\0'; 683 684 /* 685 * If there has been a trailing slash at mounttime it seems 686 * that some mountd implementations fail to remove the mount 687 * entries from their mountlist while unmounting. 688 */ 689 for (speclen = strlen(spec); 690 speclen > 1 && spec[speclen - 1] == '/'; 691 speclen--) 692 spec[speclen - 1] = '\0'; 693 if (strlen(hostp) + strlen(spec) + 1 > MNAMELEN) { 694 warnx("%s:%s: %s", hostp, spec, strerror(ENAMETOOLONG)); 695 return (0); 696 } 697 /* Make both '@' and ':' notations equal */ 698 if (*hostp != '\0') { 699 len = strlen(hostp); 700 memmove(nam, hostp, len); 701 nam[len] = ':'; 702 memmove(nam + len + 1, spec, speclen); 703 nam[len + speclen + 1] = '\0'; 704 } 705 /* 706 * DUMB!! Until the mount protocol works on iso transport, we must 707 * supply both an iso and an inet address for the host. 708 */ 709 #ifdef ISO 710 if (!strncmp(hostp, "iso=", 4)) { 711 u_short isoport; 712 713 hostp += 4; 714 isoflag++; 715 if ((delimp = strchr(hostp, '+')) == NULL) { 716 warnx("no iso+inet address"); 717 return (0); 718 } 719 *delimp = '\0'; 720 if ((isop = iso_addr(hostp)) == NULL) { 721 warnx("bad ISO address"); 722 return (0); 723 } 724 memset(&isoaddr, 0, sizeof (isoaddr)); 725 memmove(&isoaddr.siso_addr, isop, sizeof (struct iso_addr)); 726 isoaddr.siso_len = sizeof (isoaddr); 727 isoaddr.siso_family = AF_ISO; 728 isoaddr.siso_tlen = 2; 729 isoport = htons(NFS_PORT); 730 memmove(TSEL(&isoaddr), &isoport, isoaddr.siso_tlen); 731 hostp = delimp + 1; 732 } 733 #endif /* ISO */ 734 735 /* 736 * Handle an internet host address and reverse resolve it if 737 * doing Kerberos. 738 */ 739 if (isdigit(*hostp)) { 740 if ((saddr.sin_addr.s_addr = inet_addr(hostp)) == -1) { 741 warnx("bad net address %s", hostp); 742 return (0); 743 } 744 } else if ((hp = gethostbyname(hostp)) != NULL) 745 memmove(&saddr.sin_addr, hp->h_addr, 746 MIN(hp->h_length, sizeof(saddr.sin_addr))); 747 else { 748 warnx("can't get net id for host"); 749 return (0); 750 } 751 #ifdef NFSKERB 752 if ((nfsargsp->flags & NFSMNT_KERB)) { 753 if ((hp = gethostbyaddr((char *)&saddr.sin_addr.s_addr, 754 sizeof (u_long), AF_INET)) == (struct hostent *)0) { 755 warnx("can't reverse resolve net address"); 756 return (0); 757 } 758 memmove(&saddr.sin_addr, hp->h_addr, 759 MIN(hp->h_length, sizeof(saddr.sin_addr))); 760 strncpy(inst, hp->h_name, INST_SZ); 761 inst[INST_SZ - 1] = '\0'; 762 if (cp = strchr(inst, '.')) 763 *cp = '\0'; 764 } 765 #endif /* NFSKERB */ 766 767 orgcnt = retrycnt; 768 tryagain: 769 if (mountmode == ANY || mountmode == V3) { 770 nfsvers = 3; 771 mntvers = 3; 772 nfsargsp->flags |= NFSMNT_NFSV3; 773 } else { 774 nfsvers = 2; 775 mntvers = 1; 776 nfsargsp->flags &= ~NFSMNT_NFSV3; 777 } 778 nfhret.stat = EACCES; /* Mark not yet successful */ 779 while (retrycnt > 0) { 780 saddr.sin_family = AF_INET; 781 saddr.sin_port = htons(PMAPPORT); 782 if ((tport = port_no ? port_no : 783 pmap_getport(&saddr, RPCPROG_NFS, 784 nfsvers, nfsproto)) == 0) { 785 if ((opflags & ISBGRND) == 0) 786 clnt_pcreateerror("NFS Portmap"); 787 } else { 788 /* 789 * First ping the nfs server to see if it supports 790 * the version of the protocol we want to use. 791 */ 792 clnt_stat = pingnfsserver(&saddr, nfsvers, 793 nfsargsp->sotype); 794 if (clnt_stat == RPC_PROGVERSMISMATCH) { 795 if (mountmode == ANY) { 796 mountmode = V2; 797 goto tryagain; 798 } else { 799 errx(1, "can't contact NFS server"); 800 } 801 } 802 saddr.sin_port = 0; 803 pertry.tv_sec = 10; 804 pertry.tv_usec = 0; 805 if (mnttcp_ok && nfsargsp->sotype == SOCK_STREAM) 806 clp = clnttcp_create(&saddr, RPCPROG_MNT, mntvers, 807 &so, 0, 0); 808 else 809 clp = clntudp_create(&saddr, RPCPROG_MNT, mntvers, 810 pertry, &so); 811 if (clp == NULL) { 812 if ((opflags & ISBGRND) == 0) 813 clnt_pcreateerror("Cannot MNT RPC"); 814 } else { 815 clp->cl_auth = authunix_create_default(); 816 try.tv_sec = 10; 817 try.tv_usec = 0; 818 if (nfsargsp->flags & NFSMNT_KERB) 819 nfhret.auth = RPCAUTH_KERB4; 820 else 821 nfhret.auth = RPCAUTH_UNIX; 822 nfhret.vers = mntvers; 823 clnt_stat = clnt_call(clp, RPCMNT_MOUNT, 824 xdr_dir, spec, xdr_fh, &nfhret, try); 825 if (clnt_stat != RPC_SUCCESS) { 826 if (clnt_stat == RPC_PROGVERSMISMATCH) { 827 if (mountmode == ANY) { 828 mountmode = V2; 829 goto tryagain; 830 } else { 831 errx(1, "%s", 832 clnt_sperror(clp, "MNT RPC")); 833 } 834 } 835 if ((opflags & ISBGRND) == 0) 836 warnx("%s", clnt_sperror(clp, 837 "bad MNT RPC")); 838 } else { 839 auth_destroy(clp->cl_auth); 840 clnt_destroy(clp); 841 retrycnt = 0; 842 } 843 } 844 } 845 if (--retrycnt > 0) { 846 if (opflags & BGRND) { 847 warnx("Cannot immediately mount %s:%s, backgrounding", hostp, spec); 848 opflags &= ~BGRND; 849 if ((i = fork())) { 850 if (i == -1) 851 err(1, "nqnfs 2"); 852 exit(0); 853 } 854 (void) setsid(); 855 (void) close(STDIN_FILENO); 856 (void) close(STDOUT_FILENO); 857 (void) close(STDERR_FILENO); 858 (void) chdir("/"); 859 opflags |= ISBGRND; 860 } 861 sleep(60); 862 } 863 } 864 if (nfhret.stat) { 865 if (opflags & ISBGRND) 866 exit(1); 867 warnx("can't access %s: %s", spec, strerror(nfhret.stat)); 868 return (0); 869 } 870 saddr.sin_port = htons(tport); 871 #ifdef ISO 872 if (isoflag) { 873 nfsargsp->addr = (struct sockaddr *) &isoaddr; 874 nfsargsp->addrlen = sizeof (isoaddr); 875 } else 876 #endif /* ISO */ 877 { 878 nfsargsp->addr = (struct sockaddr *) &saddr; 879 nfsargsp->addrlen = sizeof (saddr); 880 } 881 nfsargsp->fh = nfhret.nfh; 882 nfsargsp->fhsize = nfhret.fhsize; 883 nfsargsp->hostname = nam; 884 return (1); 885 } 886 887 /* 888 * xdr routines for mount rpc's 889 */ 890 int 891 xdr_dir(xdrsp, dirp) 892 XDR *xdrsp; 893 char *dirp; 894 { 895 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 896 } 897 898 int 899 xdr_fh(xdrsp, np) 900 XDR *xdrsp; 901 register struct nfhret *np; 902 { 903 register int i; 904 long auth, authcnt, authfnd = 0; 905 906 if (!xdr_u_long(xdrsp, &np->stat)) 907 return (0); 908 if (np->stat) 909 return (1); 910 switch (np->vers) { 911 case 1: 912 np->fhsize = NFSX_V2FH; 913 return (xdr_opaque(xdrsp, (caddr_t)np->nfh, NFSX_V2FH)); 914 case 3: 915 if (!xdr_long(xdrsp, &np->fhsize)) 916 return (0); 917 if (np->fhsize <= 0 || np->fhsize > NFSX_V3FHMAX) 918 return (0); 919 if (!xdr_opaque(xdrsp, (caddr_t)np->nfh, np->fhsize)) 920 return (0); 921 if (!xdr_long(xdrsp, &authcnt)) 922 return (0); 923 for (i = 0; i < authcnt; i++) { 924 if (!xdr_long(xdrsp, &auth)) 925 return (0); 926 if (auth == np->auth) 927 authfnd++; 928 } 929 /* 930 * Some servers, such as DEC's OSF/1 return a nil authenticator 931 * list to indicate RPCAUTH_UNIX. 932 */ 933 if (!authfnd && (authcnt > 0 || np->auth != RPCAUTH_UNIX)) 934 np->stat = EAUTH; 935 return (1); 936 }; 937 return (0); 938 } 939 940 void 941 usage() 942 { 943 (void)fprintf(stderr, "%s\n%s\n%s\n%s\n", 944 "usage: mount_nfs [-23KNPTUbcdilqs] [-D deadthresh] [-I readdirsize]", 945 " [-L leaseterm] [-R retrycnt] [-a maxreadahead]", 946 " [-g maxgroups] [-m realm] [-o options] [-r readsize]", 947 " [-t timeout] [-w writesize] [-x retrans] rhost:path node"); 948 exit(1); 949 } 950