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 * @(#) Copyright (c) 1992, 1993, 1994 The Regents of the University of California. All rights reserved. 37 * @(#)mount_nfs.c 8.11 (Berkeley) 5/4/95 38 * $FreeBSD: src/sbin/mount_nfs/mount_nfs.c,v 1.36.2.6 2003/05/13 14:45:40 trhodes Exp $ 39 */ 40 41 #include <sys/param.h> 42 #include <sys/mount.h> 43 #include <sys/socket.h> 44 #include <sys/stat.h> 45 #include <sys/syslog.h> 46 47 #include <rpc/rpc.h> 48 #include <rpc/pmap_clnt.h> 49 #include <rpc/pmap_prot.h> 50 51 #include <vfs/nfs/rpcv2.h> 52 #include <vfs/nfs/nfsproto.h> 53 #include <vfs/nfs/nfs.h> 54 55 #include <arpa/inet.h> 56 57 #include <ctype.h> 58 #include <err.h> 59 #include <errno.h> 60 #include <fcntl.h> 61 #include <mntopts.h> 62 #include <netdb.h> 63 #include <stdio.h> 64 #include <stdlib.h> 65 #include <string.h> 66 #include <sysexits.h> 67 #include <unistd.h> 68 69 #include "mounttab.h" 70 71 #define ALTF_BG 0x1 72 #define ALTF_NOCONN 0x2 73 #define ALTF_DUMBTIMR 0x4 74 #define ALTF_INTR 0x8 75 #define ALTF_KERB 0x10 76 #define ALTF_NFSV3 0x20 77 #define ALTF_RDIRPLUS 0x40 78 #define ALTF_CACHE 0x80 79 #define ALTF_RESVPORT 0x100 80 #define ALTF_SEQPACKET 0x200 81 #define ALTF_UNUSED400 0x400 82 #define ALTF_SOFT 0x800 83 #define ALTF_TCP 0x1000 84 #define ALTF_PORT 0x2000 85 #define ALTF_NFSV2 0x4000 86 #define ALTF_ACREGMIN 0x8000 87 #define ALTF_ACREGMAX 0x10000 88 #define ALTF_ACDIRMIN 0x20000 89 #define ALTF_ACDIRMAX 0x40000 90 91 struct mntopt mopts[] = { 92 MOPT_STDOPTS, 93 MOPT_FORCE, 94 MOPT_UPDATE, 95 MOPT_ASYNC, 96 { "bg", 0, ALTF_BG, 1 }, 97 { "conn", 1, ALTF_NOCONN, 1 }, 98 { "dumbtimer", 0, ALTF_DUMBTIMR, 1 }, 99 { "intr", 0, ALTF_INTR, 1 }, 100 #ifdef NFSKERB 101 { "kerb", 0, ALTF_KERB, 1 }, 102 #endif 103 { "nfsv3", 0, ALTF_NFSV3, 1 }, 104 { "rdirplus", 0, ALTF_RDIRPLUS, 1 }, 105 { "mntudp", 1, ALTF_TCP, 1 }, 106 { "resvport", 0, ALTF_RESVPORT, 1 }, 107 { "soft", 0, ALTF_SOFT, 1 }, 108 { "tcp", 0, ALTF_TCP, 1 }, 109 { "udp", 1, ALTF_TCP, 1 }, 110 { "port=", 0, ALTF_PORT, 1 }, 111 { "nfsv2", 0, ALTF_NFSV2, 1 }, 112 { "acregmin=", 0, ALTF_ACREGMIN, 1 }, 113 { "acregmax=", 0, ALTF_ACREGMAX, 1 }, 114 { "acdirmin=", 0, ALTF_ACDIRMIN, 1 }, 115 { "acdirmax=", 0, ALTF_ACDIRMAX, 1 }, 116 { "cache", 0, ALTF_CACHE, 1 }, 117 MOPT_NULL 118 }; 119 120 struct nfs_args nfsdefargs = { 121 NFS_ARGSVERSION, 122 NULL, 123 sizeof (struct sockaddr_in), 124 0, 125 0, 126 NULL, 127 0, 128 NFSMNT_RESVPORT, 129 NFS_WSIZE, 130 NFS_RSIZE, 131 NFS_READDIRSIZE, 132 10, 133 NFS_RETRANS, 134 NFS_MAXGRPS, 135 NFS_DEFRAHEAD, 136 0, 137 NFS_DEADTHRESH, 138 NULL, 139 /* args version 4 */ 140 NFS_MINATTRTIMO, 141 NFS_MAXATTRTIMO, 142 NFS_MINDIRATTRTIMO, 143 NFS_MAXDIRATTRTIMO, 144 }; 145 146 /* Table for af,sotype -> netid conversions. */ 147 struct nc_protos { 148 const char *netid; 149 int af; 150 int sotype; 151 } nc_protos[] = { 152 {"udp", AF_INET, SOCK_DGRAM}, 153 {"tcp", AF_INET, SOCK_STREAM}, 154 {"udp6", AF_INET6, SOCK_DGRAM}, 155 {"tcp6", AF_INET6, SOCK_STREAM}, 156 {NULL, 0, 0} 157 }; 158 159 struct nfhret { 160 u_long stat; 161 long vers; 162 long auth; 163 long fhsize; 164 u_char nfh[NFSX_V3FHMAX]; 165 }; 166 #define BGRND 1 167 #define ISBGRND 2 168 int retrycnt = -1; 169 int opflags = 0; 170 int nfsproto; 171 char *portspec = NULL; /* Server nfs port; NULL means look up via rpcbind. */ 172 enum mountmode { 173 ANY, 174 V2, 175 V3 176 } mountmode = ANY; 177 178 #ifdef NFSKERB 179 char inst[INST_SZ]; 180 char realm[REALM_SZ]; 181 struct { 182 u_long kind; 183 KTEXT_ST kt; 184 } ktick; 185 struct nfsrpc_nickverf kverf; 186 struct nfsrpc_fullblock kin, kout; 187 NFSKERBKEY_T kivec; 188 CREDENTIALS kcr; 189 struct timeval ktv; 190 NFSKERBKEYSCHED_T kerb_keysched; 191 #endif 192 193 /* Return codes for nfs_tryproto. */ 194 enum tryret { 195 TRYRET_SUCCESS, 196 TRYRET_TIMEOUT, /* No response received. */ 197 TRYRET_REMOTEERR, /* Error received from remote server. */ 198 TRYRET_LOCALERR /* Local failure. */ 199 }; 200 201 #if 0 202 void set_rpc_maxgrouplist(int); 203 #endif 204 static struct netconfig *getnetconf_cached(const char *); 205 static const char *netidbytype(int, int); 206 static int getnfsargs(char *, struct nfs_args *); 207 static void usage(void) __dead2; 208 static int xdr_dir(XDR *, char *); 209 static int xdr_fh(XDR *, struct nfhret *); 210 static enum tryret 211 nfs_tryproto(struct nfs_args *, struct addrinfo *, 212 char *, char *, char **); 213 static enum tryret 214 returncode(enum clnt_stat, struct rpc_err *); 215 216 /* 217 * Used to set mount flags with getmntopts. Call with dir=TRUE to 218 * initialize altflags from the current mount flags. Call with 219 * dir=FALSE to update mount flags with the new value of altflags after 220 * the call to getmntopts. 221 */ 222 static void 223 set_flags(int* altflags, int* nfsflags, int dir) 224 { 225 #define F2(af, nf) \ 226 if (dir) { \ 227 if (*nfsflags & NFSMNT_##nf) \ 228 *altflags |= ALTF_##af; \ 229 else \ 230 *altflags &= ~ALTF_##af; \ 231 } else { \ 232 if (*altflags & ALTF_##af) \ 233 *nfsflags |= NFSMNT_##nf; \ 234 else \ 235 *nfsflags &= ~NFSMNT_##nf; \ 236 } 237 #define F(f) F2(f,f) 238 239 F(NOCONN); 240 F(DUMBTIMR); 241 F2(INTR, INT); 242 #ifdef NFSKERB 243 F(KERB); 244 #endif 245 F(RDIRPLUS); 246 F(RESVPORT); 247 F(SOFT); 248 F(ACREGMIN); 249 F(ACREGMAX); 250 F(ACDIRMIN); 251 F(ACDIRMAX); 252 #ifdef NFSMNT_CACHE 253 F(CACHE); 254 #endif 255 256 #undef F 257 #undef F2 258 } 259 260 int 261 main(int argc, char **argv) 262 { 263 int c; 264 struct nfs_args *nfsargsp; 265 struct nfs_args nfsargs; 266 struct nfsd_cargs ncd; 267 int mntflags, altflags, nfssvc_flag, num; 268 char *name, *p, *spec; 269 char mntpath[MAXPATHLEN]; 270 struct vfsconf vfc; 271 int error = 0; 272 #ifdef NFSKERB 273 uid_t last_ruid; 274 275 last_ruid = -1; 276 strcpy(realm, KRB_REALM); 277 if (sizeof (struct nfsrpc_nickverf) != RPCX_NICKVERF || 278 sizeof (struct nfsrpc_fullblock) != RPCX_FULLBLOCK || 279 ((char *)&ktick.kt) - ((char *)&ktick) != NFSX_UNSIGNED || 280 ((char *)ktick.kt.dat) - ((char *)&ktick) != 2 * NFSX_UNSIGNED) 281 fprintf(stderr, "Yikes! NFSKERB structs not packed!!\n"); 282 #endif /* NFSKERB */ 283 284 mntflags = 0; 285 altflags = ALTF_TCP | ALTF_RDIRPLUS; 286 nfsargs = nfsdefargs; 287 nfsargsp = &nfsargs; 288 if (altflags & ALTF_TCP) { 289 nfsproto = IPPROTO_TCP; 290 nfsargsp->sotype = SOCK_STREAM; 291 } else { 292 nfsproto = IPPROTO_UDP; 293 nfsargsp->sotype = SOCK_DGRAM; 294 } 295 while ((c = getopt(argc, argv, 296 "23a:bcdD:g:I:iKlm:No:PR:r:sTt:w:x:U")) != -1) 297 switch (c) { 298 case '2': 299 mountmode = V2; 300 break; 301 case '3': 302 mountmode = V3; 303 break; 304 case 'a': 305 num = strtol(optarg, &p, 10); 306 if (*p || num < 0) 307 errx(1, "illegal -a value -- %s", optarg); 308 nfsargsp->readahead = num; 309 nfsargsp->flags |= NFSMNT_READAHEAD; 310 break; 311 case 'b': 312 opflags |= BGRND; 313 break; 314 case 'c': 315 nfsargsp->flags |= NFSMNT_NOCONN; 316 break; 317 case 'D': 318 num = strtol(optarg, &p, 10); 319 if (*p || num <= 0) 320 errx(1, "illegal -D value -- %s", optarg); 321 nfsargsp->deadthresh = num; 322 nfsargsp->flags |= NFSMNT_DEADTHRESH; 323 break; 324 case 'd': 325 nfsargsp->flags |= NFSMNT_DUMBTIMR; 326 break; 327 #if 0 /* XXXX */ 328 case 'g': 329 num = strtol(optarg, &p, 10); 330 if (*p || num <= 0) 331 errx(1, "illegal -g value -- %s", optarg); 332 set_rpc_maxgrouplist(num); 333 nfsargsp->maxgrouplist = num; 334 nfsargsp->flags |= NFSMNT_MAXGRPS; 335 break; 336 #endif 337 case 'I': 338 num = strtol(optarg, &p, 10); 339 if (*p || num <= 0) 340 errx(1, "illegal -I value -- %s", optarg); 341 nfsargsp->readdirsize = num; 342 nfsargsp->flags |= NFSMNT_READDIRSIZE; 343 break; 344 case 'i': 345 nfsargsp->flags |= NFSMNT_INT; 346 break; 347 #ifdef NFSKERB 348 case 'K': 349 nfsargsp->flags |= NFSMNT_KERB; 350 break; 351 #endif 352 case 'l': 353 nfsargsp->flags |= NFSMNT_RDIRPLUS; 354 break; 355 #ifdef NFSKERB 356 case 'm': 357 strncpy(realm, optarg, REALM_SZ - 1); 358 realm[REALM_SZ - 1] = '\0'; 359 break; 360 #endif 361 case 'N': 362 nfsargsp->flags &= ~NFSMNT_RESVPORT; 363 break; 364 case 'o': 365 set_flags(&altflags, &nfsargsp->flags, TRUE); 366 altflags |= ALTF_RDIRPLUS; 367 if (nfsproto == IPPROTO_TCP) 368 altflags |= ALTF_TCP; 369 if (mountmode == V2) 370 altflags |= ALTF_NFSV2; 371 else if (mountmode == V3) 372 altflags |= ALTF_NFSV3; 373 getmntopts(optarg, mopts, &mntflags, &altflags); 374 set_flags(&altflags, &nfsargsp->flags, FALSE); 375 /* 376 * Handle altflags which don't map directly to 377 * mount flags. 378 */ 379 if(altflags & ALTF_BG) 380 opflags |= BGRND; 381 if (altflags & ALTF_TCP) { 382 nfsproto = IPPROTO_TCP; 383 nfsargsp->sotype = SOCK_STREAM; 384 } else { 385 nfsproto = IPPROTO_UDP; 386 nfsargsp->sotype = SOCK_DGRAM; 387 } 388 if(altflags & ALTF_PORT) { 389 /* 390 * XXX Converting from a string to an int 391 * and back again is silly, and we should 392 * allow /etc/services names. 393 */ 394 asprintf(&portspec, "%d", 395 atoi(strstr(optarg, "port=") + 5)); 396 if (portspec == NULL) 397 err(1, "asprintf"); 398 } 399 mountmode = ANY; 400 if(altflags & ALTF_NFSV2) 401 mountmode = V2; 402 if(altflags & ALTF_NFSV3) 403 mountmode = V3; 404 if(altflags & ALTF_ACREGMIN) 405 nfsargsp->acregmin = atoi(strstr(optarg, 406 "acregmin=") + 9); 407 if(altflags & ALTF_ACREGMAX) 408 nfsargsp->acregmax = atoi(strstr(optarg, 409 "acregmax=") + 9); 410 if(altflags & ALTF_ACDIRMIN) 411 nfsargsp->acdirmin = atoi(strstr(optarg, 412 "acdirmin=") + 9); 413 if(altflags & ALTF_ACDIRMAX) 414 nfsargsp->acdirmax = atoi(strstr(optarg, 415 "acdirmax=") + 9); 416 break; 417 case 'P': 418 /* obsolete for NFSMNT_RESVPORT, now default */ 419 break; 420 case 'R': 421 num = strtol(optarg, &p, 10); 422 if (*p || num < 0) 423 errx(1, "illegal -R value -- %s", optarg); 424 retrycnt = num; 425 break; 426 case 'r': 427 num = strtol(optarg, &p, 10); 428 if (*p || num <= 0) 429 errx(1, "illegal -r value -- %s", optarg); 430 nfsargsp->rsize = num; 431 nfsargsp->flags |= NFSMNT_RSIZE; 432 break; 433 case 's': 434 nfsargsp->flags |= NFSMNT_SOFT; 435 break; 436 case 'T': 437 nfsargsp->sotype = SOCK_STREAM; 438 nfsproto = IPPROTO_TCP; 439 altflags |= ALTF_TCP; 440 break; 441 case 't': 442 num = strtol(optarg, &p, 10); 443 if (*p || num <= 0) 444 errx(1, "illegal -t value -- %s", optarg); 445 nfsargsp->timeo = num; 446 nfsargsp->flags |= NFSMNT_TIMEO; 447 break; 448 case 'w': 449 num = strtol(optarg, &p, 10); 450 if (*p || num <= 0) 451 errx(1, "illegal -w value -- %s", optarg); 452 nfsargsp->wsize = num; 453 nfsargsp->flags |= NFSMNT_WSIZE; 454 break; 455 case 'x': 456 num = strtol(optarg, &p, 10); 457 if (*p || num <= 0) 458 errx(1, "illegal -x value -- %s", optarg); 459 nfsargsp->retrans = num; 460 nfsargsp->flags |= NFSMNT_RETRANS; 461 break; 462 case 'U': 463 nfsargsp->sotype = SOCK_DGRAM; 464 nfsproto = IPPROTO_UDP; 465 altflags &= ~ALTF_TCP; 466 break; 467 default: 468 usage(); 469 break; 470 } 471 argc -= optind; 472 argv += optind; 473 474 if (argc != 2) { 475 usage(); 476 /* NOTREACHED */ 477 } 478 479 spec = *argv++; 480 name = *argv; 481 482 if (retrycnt == -1) 483 /* The default is to keep retrying forever. */ 484 retrycnt = 0; 485 if (!getnfsargs(spec, nfsargsp)) 486 exit(1); 487 488 /* resolve the mountpoint with realpath(3) */ 489 checkpath(name, mntpath); 490 491 error = getvfsbyname("nfs", &vfc); 492 if (error && vfsisloadable("nfs")) { 493 if(vfsload("nfs")) 494 err(EX_OSERR, "vfsload(nfs)"); 495 endvfsent(); /* clear cache */ 496 error = getvfsbyname("nfs", &vfc); 497 } 498 if (error) 499 errx(EX_OSERR, "nfs filesystem is not available"); 500 501 if (mount(vfc.vfc_name, mntpath, mntflags, nfsargsp)) 502 err(1, "%s", mntpath); 503 if (nfsargsp->flags & NFSMNT_KERB) { 504 if ((opflags & ISBGRND) == 0) { 505 if (daemon(0, 0) != 0) 506 err(1, "daemon"); 507 } 508 openlog("mount_nfs", LOG_PID, LOG_DAEMON); 509 nfssvc_flag = NFSSVC_MNTD; 510 ncd.ncd_dirp = mntpath; 511 while (nfssvc(nfssvc_flag, (caddr_t)&ncd) < 0) { 512 if (errno != ENEEDAUTH) { 513 syslog(LOG_ERR, "nfssvc err %m"); 514 continue; 515 } 516 nfssvc_flag = 517 NFSSVC_MNTD | NFSSVC_GOTAUTH | NFSSVC_AUTHINFAIL; 518 #ifdef NFSKERB 519 /* 520 * Set up as ncd_authuid for the kerberos call. 521 * Must set ruid to ncd_authuid and reset the 522 * ticket name iff ncd_authuid is not the same 523 * as last time, so that the right ticket file 524 * is found. 525 * Get the Kerberos credential structure so that 526 * we have the session key and get a ticket for 527 * this uid. 528 * For more info see the IETF Draft "Authentication 529 * in ONC RPC". 530 */ 531 if (ncd.ncd_authuid != last_ruid) { 532 char buf[512]; 533 sprintf(buf, "%s%d", 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, NULL) == 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 static int 599 getnfsargs(char *spec, struct nfs_args *nfsargsp) 600 { 601 struct addrinfo hints, *ai_nfs, *ai; 602 #ifdef NFSKERB 603 char host[NI_MAXHOST], serv[NI_MAXSERV]; 604 #endif 605 enum tryret ret; 606 int ecode, speclen, remoteerr; 607 char *hostp, *delimp, *errstr; 608 #ifdef NFSKERB 609 char *cp; 610 #endif 611 size_t len; 612 static char nam[MNAMELEN + 1]; 613 614 if ((delimp = strrchr(spec, ':')) != NULL) { 615 hostp = spec; 616 spec = delimp + 1; 617 } else if ((delimp = strrchr(spec, '@')) != NULL) { 618 warnx("path@server syntax is deprecated, use server:path"); 619 hostp = delimp + 1; 620 } else { 621 warnx("no <host>:<dirpath> nfs-name"); 622 return (0); 623 } 624 *delimp = '\0'; 625 626 /* 627 * If there has been a trailing slash at mounttime it seems 628 * that some mountd implementations fail to remove the mount 629 * entries from their mountlist while unmounting. 630 */ 631 for (speclen = strlen(spec); 632 speclen > 1 && spec[speclen - 1] == '/'; 633 speclen--) 634 spec[speclen - 1] = '\0'; 635 if (strlen(hostp) + strlen(spec) + 1 > MNAMELEN) { 636 warnx("%s:%s: %s", hostp, spec, strerror(ENAMETOOLONG)); 637 return (0); 638 } 639 /* Make both '@' and ':' notations equal */ 640 if (*hostp != '\0') { 641 len = strlen(hostp); 642 memmove(nam, hostp, len); 643 nam[len] = ':'; 644 memmove(nam + len + 1, spec, speclen); 645 nam[len + speclen + 1] = '\0'; 646 } 647 648 /* 649 * Handle an internet host address and reverse resolve it if 650 * doing Kerberos. 651 */ 652 memset(&hints, 0, sizeof hints); 653 hints.ai_flags = AI_NUMERICHOST; 654 hints.ai_socktype = nfsargsp->sotype; 655 if (getaddrinfo(hostp, portspec, &hints, &ai_nfs) == 0) { 656 #ifdef NFSKERB 657 if ((nfsargsp->flags & NFSMNT_KERB)) { 658 hints.ai_flags = 0; 659 if (getnameinfo(ai_nfs->ai_addr, ai_nfs->ai_addrlen, 660 host, sizeof host, serv, sizeof serv, 0) != 0) { 661 warnx("can't reverse resolve net address"); 662 return (0); 663 } 664 hostp = host; 665 } 666 #endif /* NFSKERB */ 667 } else { 668 hints.ai_flags = 0; 669 if ((ecode = getaddrinfo(hostp, portspec, &hints, &ai_nfs)) 670 != 0) { 671 if (portspec == NULL) 672 errx(1, "%s: %s", hostp, gai_strerror(ecode)); 673 else 674 errx(1, "%s:%s: %s", hostp, portspec, 675 gai_strerror(ecode)); 676 return (0); 677 } 678 } 679 #ifdef NFSKERB 680 if (nfsargsp->flags & NFSMNT_KERB) { 681 strncpy(inst, hp->h_name, INST_SZ); 682 inst[INST_SZ - 1] = '\0'; 683 if (cp = strchr(inst, '.')) 684 *cp = '\0'; 685 } 686 #endif /* NFSKERB */ 687 688 ret = TRYRET_LOCALERR; 689 for (;;) { 690 /* 691 * Try each entry returned by getaddrinfo(). Note the 692 * occurence of remote errors by setting `remoteerr'. 693 */ 694 remoteerr = 0; 695 for (ai = ai_nfs; ai != NULL; ai = ai->ai_next) { 696 ret = nfs_tryproto(nfsargsp, ai, hostp, spec, &errstr); 697 if (ret == TRYRET_SUCCESS) 698 break; 699 if (ret != TRYRET_LOCALERR) 700 remoteerr = 1; 701 if ((opflags & ISBGRND) == 0) 702 fprintf(stderr, "%s\n", errstr); 703 } 704 if (ret == TRYRET_SUCCESS) 705 break; 706 707 /* Exit if all errors were local. */ 708 if (!remoteerr) 709 exit(1); 710 711 /* 712 * If retrycnt == 0, we are to keep retrying forever. 713 * Otherwise decrement it, and exit if it hits zero. 714 */ 715 if (retrycnt != 0 && --retrycnt == 0) 716 exit(1); 717 718 if ((opflags & (BGRND | ISBGRND)) == BGRND) { 719 warnx("Cannot immediately mount %s:%s, backgrounding", 720 hostp, spec); 721 opflags |= ISBGRND; 722 if (daemon(0, 0) != 0) 723 err(1, "daemon"); 724 } 725 sleep(60); 726 } 727 freeaddrinfo(ai_nfs); 728 nfsargsp->hostname = nam; 729 /* Add mounted filesystem to PATH_MOUNTTAB */ 730 if (!add_mtab(hostp, spec)) 731 warnx("can't update %s for %s:%s", PATH_MOUNTTAB, hostp, spec); 732 return (1); 733 } 734 735 /* 736 * Try to set up the NFS arguments according to the address 737 * family, protocol (and possibly port) specified in `ai'. 738 * 739 * Returns TRYRET_SUCCESS if successful, or: 740 * TRYRET_TIMEOUT The server did not respond. 741 * TRYRET_REMOTEERR The server reported an error. 742 * TRYRET_LOCALERR Local failure. 743 * 744 * In all error cases, *errstr will be set to a statically-allocated string 745 * describing the error. 746 */ 747 static enum tryret 748 nfs_tryproto(struct nfs_args *nfsargsp, struct addrinfo *ai, char *hostp, 749 char *spec, char **errstr) 750 { 751 static char errbuf[256]; 752 struct sockaddr_storage nfs_ss; 753 struct netbuf nfs_nb; 754 struct nfhret nfhret; 755 struct timeval try; 756 struct rpc_err rpcerr; 757 CLIENT *clp; 758 struct netconfig *nconf, *nconf_mnt; 759 const char *netid, *netid_mnt; 760 int doconnect, nfsvers, mntvers; 761 enum clnt_stat status; 762 enum mountmode trymntmode; 763 764 trymntmode = mountmode; 765 errbuf[0] = '\0'; 766 *errstr = errbuf; 767 768 if ((netid = netidbytype(ai->ai_family, nfsargsp->sotype)) == NULL) { 769 snprintf(errbuf, sizeof errbuf, 770 "af %d sotype %d not supported", ai->ai_family, 771 nfsargsp->sotype); 772 return (TRYRET_LOCALERR); 773 } 774 if ((nconf = getnetconf_cached(netid)) == NULL) { 775 snprintf(errbuf, sizeof errbuf, "%s: %s", netid, nc_sperror()); 776 return (TRYRET_LOCALERR); 777 } 778 779 netid_mnt = netid; 780 nconf_mnt = nconf; 781 782 tryagain: 783 if (trymntmode == V2) { 784 nfsvers = 2; 785 mntvers = 1; 786 } else { 787 nfsvers = 3; 788 mntvers = 3; 789 } 790 791 if (portspec != NULL) { 792 /* `ai' contains the complete nfsd sockaddr. */ 793 nfs_nb.buf = ai->ai_addr; 794 nfs_nb.len = nfs_nb.maxlen = ai->ai_addrlen; 795 } else { 796 /* Ask the remote rpcbind. */ 797 nfs_nb.buf = &nfs_ss; 798 nfs_nb.len = nfs_nb.maxlen = sizeof nfs_ss; 799 800 if (!rpcb_getaddr(RPCPROG_NFS, nfsvers, nconf, &nfs_nb, 801 hostp)) { 802 if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH && 803 trymntmode == ANY) { 804 trymntmode = V2; 805 goto tryagain; 806 } 807 snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", 808 netid, hostp, spec, 809 clnt_spcreateerror("RPCPROG_NFS")); 810 return (returncode(rpc_createerr.cf_stat, 811 &rpc_createerr.cf_error)); 812 } 813 } 814 815 /* Check that the server (nfsd) responds on the port we have chosen. */ 816 clp = clnt_tli_create(RPC_ANYFD, nconf, &nfs_nb, RPCPROG_NFS, nfsvers, 817 0, 0); 818 if (clp == NULL) { 819 snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid, 820 hostp, spec, clnt_spcreateerror("nfsd: RPCPROG_NFS")); 821 return (returncode(rpc_createerr.cf_stat, 822 &rpc_createerr.cf_error)); 823 } 824 if (nfsargsp->sotype == SOCK_DGRAM && 825 !(nfsargsp->flags & NFSMNT_NOCONN)) { 826 /* 827 * Use connect(), to match what the kernel does. This 828 * catches cases where the server responds from the 829 * wrong source address. 830 */ 831 doconnect = 1; 832 if (!clnt_control(clp, CLSET_CONNECT, (char *)&doconnect)) { 833 clnt_destroy(clp); 834 snprintf(errbuf, sizeof errbuf, 835 "[%s] %s:%s: CLSET_CONNECT failed", netid, hostp, 836 spec); 837 return (TRYRET_LOCALERR); 838 } 839 } 840 841 try.tv_sec = 10; 842 try.tv_usec = 0; 843 status = clnt_call(clp, NFSPROC_NULL, (xdrproc_t)xdr_void, NULL, 844 (xdrproc_t)xdr_void, NULL, try); 845 if (status != RPC_SUCCESS) { 846 if (status == RPC_PROGVERSMISMATCH && trymntmode == ANY) { 847 clnt_destroy(clp); 848 trymntmode = V2; 849 goto tryagain; 850 } 851 clnt_geterr(clp, &rpcerr); 852 snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid, 853 hostp, spec, clnt_sperror(clp, "NFSPROC_NULL")); 854 clnt_destroy(clp); 855 return (returncode(status, &rpcerr)); 856 } 857 clnt_destroy(clp); 858 859 /* Send the RPCMNT_MOUNT RPC to get the root filehandle. */ 860 try.tv_sec = 10; 861 try.tv_usec = 0; 862 clp = clnt_tp_create(hostp, RPCPROG_MNT, mntvers, nconf_mnt); 863 if (clp == NULL) { 864 snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt, 865 hostp, spec, clnt_spcreateerror("RPCMNT: clnt_create")); 866 return (returncode(rpc_createerr.cf_stat, 867 &rpc_createerr.cf_error)); 868 } 869 clp->cl_auth = authsys_create_default(); 870 if (nfsargsp->flags & NFSMNT_KERB) 871 nfhret.auth = RPCAUTH_KERB4; 872 else 873 nfhret.auth = RPCAUTH_UNIX; 874 nfhret.vers = mntvers; 875 status = clnt_call(clp, RPCMNT_MOUNT, (xdrproc_t)xdr_dir, spec, 876 (xdrproc_t)xdr_fh, &nfhret, try); 877 auth_destroy(clp->cl_auth); 878 if (status != RPC_SUCCESS) { 879 if (status == RPC_PROGVERSMISMATCH && trymntmode == ANY) { 880 clnt_destroy(clp); 881 trymntmode = V2; 882 goto tryagain; 883 } 884 clnt_geterr(clp, &rpcerr); 885 snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt, 886 hostp, spec, clnt_sperror(clp, "RPCPROG_MNT")); 887 clnt_destroy(clp); 888 return (returncode(status, &rpcerr)); 889 } 890 clnt_destroy(clp); 891 892 if (nfhret.stat != 0) { 893 snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt, 894 hostp, spec, strerror(nfhret.stat)); 895 return (TRYRET_REMOTEERR); 896 } 897 898 /* 899 * Store the filehandle and server address in nfsargsp, making 900 * sure to copy any locally allocated structures. 901 */ 902 nfsargsp->addrlen = nfs_nb.len; 903 nfsargsp->addr = malloc(nfsargsp->addrlen); 904 nfsargsp->fhsize = nfhret.fhsize; 905 nfsargsp->fh = malloc(nfsargsp->fhsize); 906 if (nfsargsp->addr == NULL || nfsargsp->fh == NULL) 907 err(1, "malloc"); 908 bcopy(nfs_nb.buf, nfsargsp->addr, nfsargsp->addrlen); 909 bcopy(nfhret.nfh, nfsargsp->fh, nfsargsp->fhsize); 910 911 if (nfsvers == 3) 912 nfsargsp->flags |= NFSMNT_NFSV3; 913 else 914 nfsargsp->flags &= ~NFSMNT_NFSV3; 915 916 return (TRYRET_SUCCESS); 917 } 918 919 920 /* 921 * Catagorise a RPC return status and error into an `enum tryret' 922 * return code. 923 */ 924 static enum tryret 925 returncode(enum clnt_stat status, struct rpc_err *rpcerr) 926 { 927 switch (status) { 928 case RPC_TIMEDOUT: 929 return (TRYRET_TIMEOUT); 930 case RPC_PMAPFAILURE: 931 case RPC_PROGNOTREGISTERED: 932 case RPC_PROGVERSMISMATCH: 933 /* XXX, these can be local or remote. */ 934 case RPC_CANTSEND: 935 case RPC_CANTRECV: 936 return (TRYRET_REMOTEERR); 937 case RPC_SYSTEMERROR: 938 switch (rpcerr->re_errno) { 939 case ETIMEDOUT: 940 return (TRYRET_TIMEOUT); 941 case ENOMEM: 942 break; 943 default: 944 return (TRYRET_REMOTEERR); 945 } 946 /* FALLTHROUGH */ 947 default: 948 break; 949 } 950 return (TRYRET_LOCALERR); 951 } 952 953 /* 954 * Look up a netid based on an address family and socket type. 955 * `af' is the address family, and `sotype' is SOCK_DGRAM or SOCK_STREAM. 956 * 957 * XXX there should be a library function for this. 958 */ 959 static const char * 960 netidbytype(int af, int sotype) 961 { 962 struct nc_protos *p; 963 964 for (p = nc_protos; p->netid != NULL; p++) { 965 if (af != p->af || sotype != p->sotype) 966 continue; 967 return (p->netid); 968 } 969 return (NULL); 970 } 971 972 /* 973 * Look up a netconfig entry based on a netid, and cache the result so 974 * that we don't need to remember to call freenetconfigent(). 975 * 976 * Otherwise it behaves just like getnetconfigent(), so nc_*error() 977 * work on failure. 978 */ 979 static struct netconfig * 980 getnetconf_cached(const char *netid) 981 { 982 static struct nc_entry { 983 struct netconfig *nconf; 984 struct nc_entry *next; 985 } *head; 986 struct nc_entry *p; 987 struct netconfig *nconf; 988 989 for (p = head; p != NULL; p = p->next) 990 if (strcmp(netid, p->nconf->nc_netid) == 0) 991 return (p->nconf); 992 993 if ((nconf = getnetconfigent(netid)) == NULL) 994 return (NULL); 995 if ((p = malloc(sizeof(*p))) == NULL) 996 err(1, "malloc"); 997 p->nconf = nconf; 998 p->next = head; 999 head = p; 1000 1001 return (p->nconf); 1002 } 1003 1004 /* 1005 * xdr routines for mount rpc's 1006 */ 1007 static int 1008 xdr_dir(XDR *xdrsp, char *dirp) 1009 { 1010 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 1011 } 1012 1013 static int 1014 xdr_fh(XDR *xdrsp, struct nfhret *np) 1015 { 1016 int i; 1017 long auth, authcnt, authfnd = 0; 1018 1019 if (!xdr_u_long(xdrsp, &np->stat)) 1020 return (0); 1021 if (np->stat) 1022 return (1); 1023 switch (np->vers) { 1024 case 1: 1025 np->fhsize = NFSX_V2FH; 1026 return (xdr_opaque(xdrsp, (caddr_t)np->nfh, NFSX_V2FH)); 1027 case 3: 1028 if (!xdr_long(xdrsp, &np->fhsize)) 1029 return (0); 1030 if (np->fhsize <= 0 || np->fhsize > NFSX_V3FHMAX) 1031 return (0); 1032 if (!xdr_opaque(xdrsp, (caddr_t)np->nfh, np->fhsize)) 1033 return (0); 1034 if (!xdr_long(xdrsp, &authcnt)) 1035 return (0); 1036 for (i = 0; i < authcnt; i++) { 1037 if (!xdr_long(xdrsp, &auth)) 1038 return (0); 1039 if (auth == np->auth) 1040 authfnd++; 1041 } 1042 /* 1043 * Some servers, such as DEC's OSF/1 return a nil authenticator 1044 * list to indicate RPCAUTH_UNIX. 1045 */ 1046 if (!authfnd && (authcnt > 0 || np->auth != RPCAUTH_UNIX)) 1047 np->stat = EAUTH; 1048 return (1); 1049 }; 1050 return (0); 1051 } 1052 1053 static void 1054 usage(void) 1055 { 1056 fprintf(stderr, "%s\n%s\n%s\n%s\n", 1057 "usage: mount_nfs [-23KNPTUbcdils] [-D deadthresh] [-I readdirsize]", 1058 " [-R retrycnt] [-a maxreadahead]", 1059 " [-g maxgroups] [-m realm] [-o options] [-r readsize]", 1060 " [-t timeout] [-w writesize] [-x retrans] rhost:path node"); 1061 exit(1); 1062 } 1063