1 /* $NetBSD: mount_nfs.c,v 1.47 2005/02/05 15:04:56 xtraeme Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Rick Macklem at The University of Guelph. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 #ifndef lint 37 __COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\n\ 38 The Regents of the University of California. All rights reserved.\n"); 39 #endif /* not lint */ 40 41 #ifndef lint 42 #if 0 43 static char sccsid[] = "@(#)mount_nfs.c 8.11 (Berkeley) 5/4/95"; 44 #else 45 __RCSID("$NetBSD: mount_nfs.c,v 1.47 2005/02/05 15:04:56 xtraeme Exp $"); 46 #endif 47 #endif /* not lint */ 48 49 #include <sys/param.h> 50 #include <sys/mount.h> 51 #include <sys/socket.h> 52 #include <sys/stat.h> 53 #include <syslog.h> 54 55 #include <rpc/rpc.h> 56 #include <rpc/pmap_clnt.h> 57 #include <rpc/pmap_prot.h> 58 59 #ifdef ISO 60 #include <netiso/iso.h> 61 #endif 62 63 #ifdef NFSKERB 64 #include <des.h> 65 #include <kerberosIV/krb.h> 66 #endif 67 68 #include <nfs/rpcv2.h> 69 #include <nfs/nfsproto.h> 70 #include <nfs/nfs.h> 71 #include <nfs/nqnfs.h> 72 #include <nfs/nfsmount.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 <string.h> 85 #include <unistd.h> 86 #include <util.h> 87 88 #include <mntopts.h> 89 90 #define ALTF_BG 0x00000001 91 #define ALTF_CONN 0x00000002 92 #define ALTF_DUMBTIMR 0x00000004 93 #define ALTF_INTR 0x00000008 94 #define ALTF_KERB 0x00000010 95 #define ALTF_NFSV3 0x00000020 96 #define ALTF_RDIRPLUS 0x00000040 97 #define ALTF_MNTUDP 0x00000080 98 #define ALTF_NORESPORT 0x00000100 99 #define ALTF_SEQPACKET 0x00000200 100 #define ALTF_NQNFS 0x00000400 101 #define ALTF_SOFT 0x00000800 102 #define ALTF_TCP 0x00001000 103 #define ALTF_NFSV2 0x00002000 104 #define ALTF_PORT 0x00004000 105 #define ALTF_RSIZE 0x00008000 106 #define ALTF_WSIZE 0x00010000 107 #define ALTF_RDIRSIZE 0x00020000 108 #define ALTF_MAXGRPS 0x00040000 109 #define ALTF_LEASETERM 0x00080000 110 #define ALTF_READAHEAD 0x00100000 111 #define ALTF_DEADTHRESH 0x00200000 112 #define ALTF_TIMEO 0x00400000 113 #define ALTF_RETRANS 0x00800000 114 115 static const struct mntopt mopts[] = { 116 MOPT_STDOPTS, 117 MOPT_FORCE, 118 MOPT_UPDATE, 119 MOPT_GETARGS, 120 { "bg", 0, ALTF_BG, 1 }, 121 { "conn", 0, ALTF_CONN, 1 }, 122 { "dumbtimer", 0, ALTF_DUMBTIMR, 1 }, 123 { "intr", 0, ALTF_INTR, 1 }, 124 #ifdef NFSKERB 125 { "kerb", 0, ALTF_KERB, 1 }, 126 #endif 127 { "nfsv3", 0, ALTF_NFSV3, 1 }, 128 { "rdirplus", 0, ALTF_RDIRPLUS, 1 }, 129 { "mntudp", 0, ALTF_MNTUDP, 1 }, 130 { "noresport", 0, ALTF_NORESPORT, 1 }, 131 #ifdef ISO 132 { "seqpacket", 0, ALTF_SEQPACKET, 1 }, 133 #endif 134 { "nqnfs", 0, ALTF_NQNFS, 1 }, 135 { "soft", 0, ALTF_SOFT, 1 }, 136 { "tcp", 0, ALTF_TCP, 1 }, 137 { "nfsv2", 0, ALTF_NFSV2, 1 }, 138 { "port", 0, ALTF_PORT, 1 }, 139 { "rsize", 0, ALTF_RSIZE, 1 }, 140 { "wsize", 0, ALTF_WSIZE, 1 }, 141 { "rdirsize", 0, ALTF_RDIRSIZE, 1 }, 142 { "maxgrps", 0, ALTF_MAXGRPS, 1 }, 143 { "leaseterm", 0, ALTF_LEASETERM, 1 }, 144 { "readahead", 0, ALTF_READAHEAD, 1 }, 145 { "deadthresh", 0, ALTF_DEADTHRESH, 1 }, 146 { "timeo", 0, ALTF_TIMEO, 1 }, 147 { NULL } 148 149 }; 150 151 struct nfs_args nfsdefargs = { 152 NFS_ARGSVERSION, 153 (struct sockaddr *)0, 154 sizeof (struct sockaddr_in), 155 SOCK_DGRAM, 156 0, 157 (u_char *)0, 158 0, 159 NFSMNT_NFSV3|NFSMNT_NOCONN|NFSMNT_RESVPORT, 160 NFS_WSIZE, 161 NFS_RSIZE, 162 NFS_READDIRSIZE, 163 10, 164 NFS_RETRANS, 165 NFS_MAXGRPS, 166 NFS_DEFRAHEAD, 167 NQ_DEFLEASE, 168 NQ_DEADTHRESH, 169 (char *)0, 170 }; 171 172 struct nfhret { 173 u_long stat; 174 long vers; 175 long auth; 176 long fhsize; 177 u_char nfh[NFSX_V3FHMAX]; 178 }; 179 #define DEF_RETRY 10000 180 #define BGRND 1 181 #define ISBGRND 2 182 int retrycnt; 183 int opflags = 0; 184 int nfsproto = IPPROTO_UDP; 185 int force2 = 0; 186 int force3 = 0; 187 int mnttcp_ok = 1; 188 int port = 0; 189 190 #ifdef NFSKERB 191 static char inst[INST_SZ]; 192 static char realm[REALM_SZ]; 193 static struct { 194 u_long kind; 195 KTEXT_ST kt; 196 } ktick; 197 static struct nfsrpc_nickverf kverf; 198 static struct nfsrpc_fullblock kin, kout; 199 static NFSKERBKEY_T kivec; 200 static CREDENTIALS kcr; 201 static struct timeval ktv; 202 static NFSKERBKEYSCHED_T kerb_keysched; 203 #endif 204 205 static void shownfsargs(const struct nfs_args *); 206 static int getnfsargs(char *, struct nfs_args *); 207 #ifdef ISO 208 static struct iso_addr *iso_addr(const char *); 209 #endif 210 int mount_nfs(int argc, char **argv); 211 /* void set_rpc_maxgrouplist(int); */ 212 static void usage(void); 213 static int xdr_dir(XDR *, char *); 214 static int xdr_fh(XDR *, struct nfhret *); 215 216 #ifndef MOUNT_NOMAIN 217 int 218 main(int argc, char **argv) 219 { 220 return mount_nfs(argc, argv); 221 } 222 #endif 223 224 int 225 mount_nfs(int argc, char *argv[]) 226 { 227 int c, retval; 228 struct nfs_args *nfsargsp; 229 struct nfs_args nfsargs; 230 struct nfsd_cargs ncd; 231 struct sockaddr_storage sa; 232 int mntflags, altflags, i, nfssvc_flag, num; 233 char name[MAXPATHLEN], *p, *spec, *ospec; 234 mntoptparse_t mp; 235 #ifdef NFSKERB 236 uid_t last_ruid; 237 238 last_ruid = -1; 239 if (krb_get_lrealm(realm, 0) != KSUCCESS) 240 (void)strlcpy(realm, KRB_REALM, sizeof(realm)); 241 if (sizeof (struct nfsrpc_nickverf) != RPCX_NICKVERF || 242 sizeof (struct nfsrpc_fullblock) != RPCX_FULLBLOCK || 243 ((char *)&ktick.kt) - ((char *)&ktick) != NFSX_UNSIGNED || 244 ((char *)ktick.kt.dat) - ((char *)&ktick) != 2 * NFSX_UNSIGNED) 245 warnx("Yikes! NFSKERB structs not packed!!\n"); 246 #endif 247 retrycnt = DEF_RETRY; 248 249 mntflags = 0; 250 altflags = 0; 251 nfsargs = nfsdefargs; 252 nfsargsp = &nfsargs; 253 while ((c = getopt(argc, argv, 254 "23a:bcCdD:g:I:iKL:lm:o:PpqR:r:sTt:w:x:UX")) != -1) 255 switch (c) { 256 case '3': 257 if (force2) 258 errx(1, "-2 and -3 are mutually exclusive"); 259 force3 = 1; 260 break; 261 case '2': 262 if (force3) 263 errx(1, "-2 and -3 are mutually exclusive"); 264 force2 = 1; 265 nfsargsp->flags &= ~NFSMNT_NFSV3; 266 break; 267 case 'a': 268 num = strtol(optarg, &p, 10); 269 if (*p || num < 0) 270 errx(1, "illegal -a value -- %s", optarg); 271 nfsargsp->readahead = num; 272 nfsargsp->flags |= NFSMNT_READAHEAD; 273 break; 274 case 'b': 275 opflags |= BGRND; 276 break; 277 case 'c': 278 nfsargsp->flags |= NFSMNT_NOCONN; 279 break; 280 case 'C': 281 nfsargsp->flags &= ~NFSMNT_NOCONN; 282 break; 283 case 'D': 284 num = strtol(optarg, &p, 10); 285 if (*p || num <= 0) 286 errx(1, "illegal -D value -- %s", optarg); 287 nfsargsp->deadthresh = num; 288 nfsargsp->flags |= NFSMNT_DEADTHRESH; 289 break; 290 case 'd': 291 nfsargsp->flags |= NFSMNT_DUMBTIMR; 292 break; 293 #if 0 /* XXXX */ 294 case 'g': 295 num = strtol(optarg, &p, 10); 296 if (*p || num <= 0) 297 errx(1, "illegal -g value -- %s", optarg); 298 set_rpc_maxgrouplist(num); 299 nfsargsp->maxgrouplist = num; 300 nfsargsp->flags |= NFSMNT_MAXGRPS; 301 break; 302 #endif 303 case 'I': 304 num = strtol(optarg, &p, 10); 305 if (*p || num <= 0) 306 errx(1, "illegal -I value -- %s", optarg); 307 nfsargsp->readdirsize = num; 308 nfsargsp->flags |= NFSMNT_READDIRSIZE; 309 break; 310 case 'i': 311 nfsargsp->flags |= NFSMNT_INT; 312 break; 313 #ifdef NFSKERB 314 case 'K': 315 nfsargsp->flags |= NFSMNT_KERB; 316 break; 317 #endif 318 case 'L': 319 num = strtol(optarg, &p, 10); 320 if (*p || num < 2) 321 errx(1, "illegal -L value -- %s", optarg); 322 nfsargsp->leaseterm = num; 323 nfsargsp->flags |= NFSMNT_LEASETERM; 324 break; 325 case 'l': 326 nfsargsp->flags |= NFSMNT_RDIRPLUS; 327 break; 328 #ifdef NFSKERB 329 case 'm': 330 (void)strlcpy(realm, optarg, sizeof(realm)); 331 break; 332 #endif 333 case 'o': 334 mp = getmntopts(optarg, mopts, &mntflags, &altflags); 335 if (mp == NULL) 336 err(1, NULL); 337 if (altflags & ALTF_BG) 338 opflags |= BGRND; 339 if (altflags & ALTF_CONN) 340 nfsargsp->flags &= ~NFSMNT_NOCONN; 341 if (altflags & ALTF_DUMBTIMR) 342 nfsargsp->flags |= NFSMNT_DUMBTIMR; 343 if (altflags & ALTF_INTR) 344 nfsargsp->flags |= NFSMNT_INT; 345 #ifdef NFSKERB 346 if (altflags & ALTF_KERB) 347 nfsargsp->flags |= NFSMNT_KERB; 348 #endif 349 if (altflags & ALTF_NFSV3) { 350 if (force2) 351 errx(1, "conflicting version options"); 352 force3 = 1; 353 } 354 if (altflags & ALTF_NFSV2) { 355 if (force3) 356 errx(1, "conflicting version options"); 357 force2 = 1; 358 nfsargsp->flags &= ~NFSMNT_NFSV3; 359 } 360 if (altflags & ALTF_RDIRPLUS) 361 nfsargsp->flags |= NFSMNT_RDIRPLUS; 362 if (altflags & ALTF_MNTUDP) 363 mnttcp_ok = 0; 364 if (altflags & ALTF_NORESPORT) 365 nfsargsp->flags &= ~NFSMNT_RESVPORT; 366 #ifdef ISO 367 if (altflags & ALTF_SEQPACKET) 368 nfsargsp->sotype = SOCK_SEQPACKET; 369 #endif 370 if (altflags & ALTF_NQNFS) { 371 if (force2) 372 errx(1, "nqnfs only available with v3"); 373 force3 = 1; 374 nfsargsp->flags |= NFSMNT_NQNFS; 375 } 376 if (altflags & ALTF_SOFT) 377 nfsargsp->flags |= NFSMNT_SOFT; 378 if (altflags & ALTF_TCP) { 379 nfsargsp->sotype = SOCK_STREAM; 380 nfsproto = IPPROTO_TCP; 381 } 382 if (altflags & ALTF_PORT) { 383 port = getmntoptnum(mp, "port"); 384 } 385 if (altflags & ALTF_RSIZE) { 386 nfsargsp->rsize = 387 (int)getmntoptnum(mp, "rsize"); 388 nfsargsp->flags |= NFSMNT_RSIZE; 389 } 390 if (altflags & ALTF_WSIZE) { 391 nfsargsp->wsize = 392 (int)getmntoptnum(mp, "wsize"); 393 nfsargsp->flags |= NFSMNT_WSIZE; 394 } 395 if (altflags & ALTF_RDIRSIZE) { 396 nfsargsp->rsize = 397 (int)getmntoptnum(mp, "rdirsize"); 398 nfsargsp->flags |= NFSMNT_READDIRSIZE; 399 } 400 #if 0 401 if (altflags & ALTF_MAXGRPS) { 402 set_rpc_maxgrouplist(num); 403 nfsargsp->maxgrouplist = 404 (int)getmntoptnum(mp, "maxgrps"); 405 nfsargsp->flags |= NFSMNT_MAXGRPS; 406 } 407 #endif 408 if (altflags & ALTF_LEASETERM) { 409 nfsargsp->leaseterm = 410 (int)getmntoptnum(mp, "leaseterm"); 411 nfsargsp->flags |= NFSMNT_LEASETERM; 412 } 413 if (altflags & ALTF_READAHEAD) { 414 nfsargsp->readahead = 415 (int)getmntoptnum(mp, "readahead"); 416 nfsargsp->flags |= NFSMNT_READAHEAD; 417 } 418 if (altflags & ALTF_DEADTHRESH) { 419 nfsargsp->deadthresh = 420 (int)getmntoptnum(mp, "deadthresh"); 421 nfsargsp->flags |= NFSMNT_DEADTHRESH; 422 } 423 if (altflags & ALTF_TIMEO) { 424 nfsargsp->timeo = 425 (int)getmntoptnum(mp, "timeo"); 426 nfsargsp->flags |= NFSMNT_TIMEO; 427 } 428 if (altflags & ALTF_RETRANS) { 429 nfsargsp->retrans = 430 (int)getmntoptnum(mp, "retrans"); 431 nfsargsp->flags |= NFSMNT_RETRANS; 432 } 433 altflags = 0; 434 freemntopts(mp); 435 break; 436 case 'P': 437 nfsargsp->flags |= NFSMNT_RESVPORT; 438 break; 439 case 'p': 440 nfsargsp->flags &= ~NFSMNT_RESVPORT; 441 break; 442 case 'q': 443 if (force2) 444 errx(1, "nqnfs only available with v3"); 445 force3 = 1; 446 nfsargsp->flags |= NFSMNT_NQNFS; 447 break; 448 case 'R': 449 num = strtol(optarg, &p, 10); 450 if (*p || num <= 0) 451 errx(1, "illegal -R value -- %s", optarg); 452 retrycnt = num; 453 break; 454 case 'r': 455 num = strtol(optarg, &p, 10); 456 if (*p || num <= 0) 457 errx(1, "illegal -r value -- %s", optarg); 458 nfsargsp->rsize = num; 459 nfsargsp->flags |= NFSMNT_RSIZE; 460 break; 461 #ifdef ISO 462 case 'S': 463 nfsargsp->sotype = SOCK_SEQPACKET; 464 break; 465 #endif 466 case 's': 467 nfsargsp->flags |= NFSMNT_SOFT; 468 break; 469 case 'T': 470 nfsargsp->sotype = SOCK_STREAM; 471 nfsproto = IPPROTO_TCP; 472 break; 473 case 't': 474 num = strtol(optarg, &p, 10); 475 if (*p || num <= 0) 476 errx(1, "illegal -t value -- %s", optarg); 477 nfsargsp->timeo = num; 478 nfsargsp->flags |= NFSMNT_TIMEO; 479 break; 480 case 'w': 481 num = strtol(optarg, &p, 10); 482 if (*p || num <= 0) 483 errx(1, "illegal -w value -- %s", optarg); 484 nfsargsp->wsize = num; 485 nfsargsp->flags |= NFSMNT_WSIZE; 486 break; 487 case 'x': 488 num = strtol(optarg, &p, 10); 489 if (*p || num <= 0) 490 errx(1, "illegal -x value -- %s", optarg); 491 nfsargsp->retrans = num; 492 nfsargsp->flags |= NFSMNT_RETRANS; 493 break; 494 case 'X': 495 nfsargsp->flags |= NFSMNT_XLATECOOKIE; 496 break; 497 case 'U': 498 mnttcp_ok = 0; 499 break; 500 default: 501 usage(); 502 break; 503 } 504 argc -= optind; 505 argv += optind; 506 507 if (argc != 2) 508 usage(); 509 510 spec = *argv++; 511 if (realpath(*argv, name) == NULL) /* Check mounton path */ 512 err(1, "realpath %s", *argv); 513 if (strncmp(*argv, name, MAXPATHLEN)) { 514 warnx("\"%s\" is a relative path.", *argv); 515 warnx("using \"%s\" instead.", name); 516 } 517 518 if ((ospec = strdup(spec)) == NULL) { 519 err(1, "strdup"); 520 } 521 522 if ((mntflags & MNT_GETARGS) != 0) { 523 memset(&sa, 0, sizeof(sa)); 524 nfsargsp->addr = (struct sockaddr *)&sa; 525 nfsargsp->addrlen = sizeof(sa); 526 } else { 527 if (!getnfsargs(spec, nfsargsp)) 528 exit(1); 529 } 530 if ((retval = mount(MOUNT_NFS, name, mntflags, nfsargsp))) { 531 /* Did we just default to v3 on a v2-only kernel? 532 * If so, default to v2 & try again */ 533 if ((errno == EPROGMISMATCH) && !force3) { 534 nfsargsp->flags &= ~NFSMNT_NFSV3; 535 retval = mount(MOUNT_NFS, name, mntflags, nfsargsp); 536 } 537 } 538 if (retval) 539 err(1, "%s on %s", ospec, name); 540 if (mntflags & MNT_GETARGS) { 541 shownfsargs(nfsargsp); 542 return (0); 543 } 544 545 if (nfsargsp->flags & (NFSMNT_NQNFS | NFSMNT_KERB)) { 546 if ((opflags & ISBGRND) == 0) { 547 if ((i = fork()) != 0) { 548 if (i == -1) 549 err(1, "nqnfs 1"); 550 exit(0); 551 } 552 (void) setsid(); 553 (void) close(STDIN_FILENO); 554 (void) close(STDOUT_FILENO); 555 (void) close(STDERR_FILENO); 556 (void) chdir("/"); 557 } 558 openlog("mount_nfs", LOG_PID, LOG_DAEMON); 559 nfssvc_flag = NFSSVC_MNTD; 560 ncd.ncd_dirp = name; 561 while (nfssvc(nfssvc_flag, (caddr_t)&ncd) < 0) { 562 if (errno != ENEEDAUTH) { 563 syslog(LOG_ERR, "nfssvc err %m"); 564 continue; 565 } 566 nfssvc_flag = 567 NFSSVC_MNTD | NFSSVC_GOTAUTH | NFSSVC_AUTHINFAIL; 568 #ifdef NFSKERB 569 /* 570 * Set up as ncd_authuid for the kerberos call. 571 * Must set ruid to ncd_authuid and reset the 572 * ticket name iff ncd_authuid is not the same 573 * as last time, so that the right ticket file 574 * is found. 575 * Get the Kerberos credential structure so that 576 * we have the seesion key and get a ticket for 577 * this uid. 578 * For more info see the IETF Draft "Authentication 579 * in ONC RPC". 580 */ 581 if (ncd.ncd_authuid != last_ruid) { 582 krb_set_tkt_string(""); 583 last_ruid = ncd.ncd_authuid; 584 } 585 setreuid(ncd.ncd_authuid, 0); 586 kret = krb_get_cred(NFS_KERBSRV, inst, realm, &kcr); 587 if (kret == RET_NOTKT) { 588 kret = get_ad_tkt(NFS_KERBSRV, inst, realm, 589 DEFAULT_TKT_LIFE); 590 if (kret == KSUCCESS) 591 kret = krb_get_cred(NFS_KERBSRV, inst, realm, 592 &kcr); 593 } 594 if (kret == KSUCCESS) 595 kret = krb_mk_req(&ktick.kt, NFS_KERBSRV, inst, 596 realm, 0); 597 598 /* 599 * Fill in the AKN_FULLNAME authenticator and verfier. 600 * Along with the Kerberos ticket, we need to build 601 * the timestamp verifier and encrypt it in CBC mode. 602 */ 603 if (kret == KSUCCESS && 604 ktick.kt.length <= (RPCAUTH_MAXSIZ-3*NFSX_UNSIGNED) 605 && gettimeofday(&ktv, (struct timezone *)0) == 0) { 606 ncd.ncd_authtype = RPCAUTH_KERB4; 607 ncd.ncd_authstr = (u_char *)&ktick; 608 ncd.ncd_authlen = nfsm_rndup(ktick.kt.length) + 609 3 * NFSX_UNSIGNED; 610 ncd.ncd_verfstr = (u_char *)&kverf; 611 ncd.ncd_verflen = sizeof (kverf); 612 memmove(ncd.ncd_key, kcr.session, 613 sizeof (kcr.session)); 614 kin.t1 = htonl(ktv.tv_sec); 615 kin.t2 = htonl(ktv.tv_usec); 616 kin.w1 = htonl(NFS_KERBTTL); 617 kin.w2 = htonl(NFS_KERBTTL - 1); 618 memset((caddr_t)kivec, 0, sizeof (kivec)); 619 620 /* 621 * Encrypt kin in CBC mode using the session 622 * key in kcr. 623 */ 624 XXX 625 626 /* 627 * Finally, fill the timestamp verifier into the 628 * authenticator and verifier. 629 */ 630 ktick.kind = htonl(RPCAKN_FULLNAME); 631 kverf.kind = htonl(RPCAKN_FULLNAME); 632 NFS_KERBW1(ktick.kt) = kout.w1; 633 ktick.kt.length = htonl(ktick.kt.length); 634 kverf.verf.t1 = kout.t1; 635 kverf.verf.t2 = kout.t2; 636 kverf.verf.w2 = kout.w2; 637 nfssvc_flag = NFSSVC_MNTD | NFSSVC_GOTAUTH; 638 } 639 setreuid(0, 0); 640 #endif /* NFSKERB */ 641 } 642 } 643 exit(0); 644 } 645 646 static void 647 shownfsargs(const struct nfs_args *nfsargsp) 648 { 649 char fbuf[2048]; 650 char host[NI_MAXHOST], serv[NI_MAXSERV]; 651 int error; 652 653 (void)snprintb(fbuf, sizeof(fbuf), NFSMNT_BITS, nfsargsp->flags); 654 if (nfsargsp->addr != NULL) { 655 error = getnameinfo(nfsargsp->addr, nfsargsp->addrlen, host, 656 sizeof(host), serv, sizeof(serv), 657 NI_NUMERICHOST | NI_NUMERICSERV); 658 if (error != 0) 659 warnx("getnameinfo: %s", gai_strerror(error)); 660 } else 661 error = -1; 662 663 if (error == 0) 664 printf("addr=%s, port=%s, addrlen=%d, ", 665 host, serv, nfsargsp->addrlen); 666 printf("sotype=%d, proto=%d, fhsize=%d, " 667 "flags=%s, wsize=%d, rsize=%d, readdirsize=%d, timeo=%d, " 668 "retrans=%d, maxgrouplist=%d, readahead=%d, leaseterm=%d, " 669 "deadthresh=%d\n", 670 nfsargsp->sotype, 671 nfsargsp->proto, 672 nfsargsp->fhsize, 673 fbuf, 674 nfsargsp->wsize, 675 nfsargsp->rsize, 676 nfsargsp->readdirsize, 677 nfsargsp->timeo, 678 nfsargsp->retrans, 679 nfsargsp->maxgrouplist, 680 nfsargsp->readahead, 681 nfsargsp->leaseterm, 682 nfsargsp->deadthresh); 683 } 684 685 static int 686 getnfsargs(char *spec, struct nfs_args *nfsargsp) 687 { 688 CLIENT *clp; 689 struct addrinfo hints, *ai_nfs, *ai; 690 int ecode; 691 char host[NI_MAXHOST], serv[NI_MAXSERV]; 692 static struct netbuf nfs_nb; 693 static struct sockaddr_storage nfs_ss; 694 struct netconfig *nconf; 695 char *netid; 696 #ifdef ISO 697 static struct sockaddr_iso isoaddr; 698 struct iso_addr *isop; 699 int isoflag = 0; 700 #endif 701 struct timeval pertry, try; 702 enum clnt_stat clnt_stat; 703 int i, nfsvers, mntvers, orgcnt; 704 char *hostp, *delimp; 705 #ifdef NFSKERB 706 char *cp; 707 #endif 708 static struct nfhret nfhret; 709 static char nam[MNAMELEN + 1]; 710 711 strncpy(nam, spec, MNAMELEN); 712 nam[MNAMELEN] = '\0'; 713 if ((delimp = strchr(spec, '@')) != NULL) { 714 hostp = delimp + 1; 715 } else if ((delimp = strrchr(spec, ':')) != NULL) { 716 hostp = spec; 717 spec = delimp + 1; 718 } else { 719 warnx("no <host>:<dirpath> or <dirpath>@<host> spec"); 720 return (0); 721 } 722 *delimp = '\0'; 723 /* 724 * DUMB!! Until the mount protocol works on iso transport, we must 725 * supply both an iso and an inet address for the host. 726 */ 727 #ifdef ISO 728 if (!strncmp(hostp, "iso=", 4)) { 729 u_short isoport; 730 731 hostp += 4; 732 isoflag++; 733 if ((delimp = strchr(hostp, '+')) == NULL) { 734 warnx("no iso+inet address"); 735 return (0); 736 } 737 *delimp = '\0'; 738 if ((isop = iso_addr(hostp)) == NULL) { 739 warnx("bad ISO address"); 740 return (0); 741 } 742 memset(&isoaddr, 0, sizeof (isoaddr)); 743 memcpy(&isoaddr.siso_addr, isop, sizeof (struct iso_addr)); 744 isoaddr.siso_len = sizeof (isoaddr); 745 isoaddr.siso_family = AF_ISO; 746 isoaddr.siso_tlen = 2; 747 isoport = htons(NFS_PORT); 748 memcpy(TSEL(&isoaddr), &isoport, isoaddr.siso_tlen); 749 hostp = delimp + 1; 750 } 751 #endif /* ISO */ 752 753 /* 754 * Handle an internet host address and reverse resolve it if 755 * doing Kerberos. 756 */ 757 memset(&hints, 0, sizeof hints); 758 hints.ai_flags = AI_NUMERICHOST; 759 hints.ai_socktype = nfsargsp->sotype; 760 if (getaddrinfo(hostp, "nfs", &hints, &ai_nfs) == 0) { 761 if ((nfsargsp->flags & NFSMNT_KERB)) { 762 hints.ai_flags = 0; 763 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 764 sizeof host, serv, sizeof serv, 0) != 0) { 765 warnx("can't reverse resolve net address for " 766 "host \"%s\": %s", hostp, 767 gai_strerror(ecode)); 768 return (0); 769 } 770 hostp = host; 771 } 772 } else { 773 hints.ai_flags = 0; 774 if ((ecode = getaddrinfo(hostp, "nfs", &hints, &ai_nfs)) != 0) { 775 warnx("can't get net id for host \"%s\": %s", hostp, 776 gai_strerror(ecode)); 777 return (0); 778 } 779 } 780 #ifdef NFSKERB 781 if (nfsargsp->flags & NFSMNT_KERB) { 782 strncpy(inst, hp->h_name, INST_SZ); 783 inst[INST_SZ - 1] = '\0'; 784 if (cp = strchr(inst, '.')) 785 *cp = '\0'; 786 } 787 #endif /* NFSKERB */ 788 789 if (force2) { 790 nfsvers = NFS_VER2; 791 mntvers = RPCMNT_VER1; 792 } else { 793 nfsvers = NFS_VER3; 794 mntvers = RPCMNT_VER3; 795 } 796 orgcnt = retrycnt; 797 nfhret.stat = EACCES; /* Mark not yet successful */ 798 799 for (ai = ai_nfs; ai; ai = ai->ai_next) { 800 /* 801 * XXX. Nead a generic (family, type, proto) -> nconf interface. 802 * __rpc_*2nconf exist, maybe they should be exported. 803 */ 804 if (nfsargsp->sotype == SOCK_STREAM) { 805 if (ai->ai_family == AF_INET6) 806 netid = "tcp6"; 807 else 808 netid = "tcp"; 809 } else { 810 if (ai->ai_family == AF_INET6) 811 netid = "udp6"; 812 else 813 netid = "udp"; 814 } 815 816 nconf = getnetconfigent(netid); 817 818 tryagain: 819 retrycnt = orgcnt; 820 821 while (retrycnt > 0) { 822 nfs_nb.buf = &nfs_ss; 823 nfs_nb.maxlen = sizeof nfs_ss; 824 if (!rpcb_getaddr(RPCPROG_NFS, nfsvers, nconf, &nfs_nb, hostp)){ 825 if (rpc_createerr.cf_stat == RPC_SYSTEMERROR) { 826 nfhret.stat = rpc_createerr.cf_error.re_errno; 827 break; 828 } 829 if (rpc_createerr.cf_stat == RPC_UNKNOWNPROTO) { 830 nfhret.stat = EPROTONOSUPPORT; 831 break; 832 } 833 if ((opflags & ISBGRND) == 0) 834 clnt_pcreateerror( 835 "mount_nfs: rpcbind to nfs on server"); 836 } else { 837 pertry.tv_sec = 10; 838 pertry.tv_usec = 0; 839 /* 840 * XXX relies on clnt_tcp_create to bind to a reserved 841 * socket. 842 */ 843 clp = clnt_tp_create(hostp, RPCPROG_MNT, mntvers, 844 mnttcp_ok ? nconf : getnetconfigent("udp")); 845 if (clp == NULL) { 846 if ((opflags & ISBGRND) == 0) { 847 clnt_pcreateerror( 848 "Cannot MNT RPC (mountd)"); 849 } 850 } else { 851 CLNT_CONTROL(clp, CLSET_RETRY_TIMEOUT, 852 (char *)&pertry); 853 clp->cl_auth = authsys_create_default(); 854 try.tv_sec = 10; 855 try.tv_usec = 0; 856 if (nfsargsp->flags & NFSMNT_KERB) 857 nfhret.auth = RPCAUTH_KERB4; 858 else 859 nfhret.auth = RPCAUTH_UNIX; 860 nfhret.vers = mntvers; 861 clnt_stat = clnt_call(clp, RPCMNT_MOUNT, 862 xdr_dir, spec, xdr_fh, &nfhret, try); 863 switch (clnt_stat) { 864 case RPC_PROGVERSMISMATCH: 865 if (nfsvers == NFS_VER3 && !force3) { 866 nfsvers = NFS_VER2; 867 mntvers = RPCMNT_VER1; 868 nfsargsp->flags &= 869 ~NFSMNT_NFSV3; 870 goto tryagain; 871 } else { 872 errx(1, "%s", clnt_sperror(clp, 873 "MNT RPC")); 874 } 875 case RPC_SUCCESS: 876 auth_destroy(clp->cl_auth); 877 clnt_destroy(clp); 878 retrycnt = 0; 879 break; 880 default: 881 /* XXX should give up on some errors */ 882 if ((opflags & ISBGRND) == 0) 883 warnx("%s", clnt_sperror(clp, 884 "bad MNT RPC")); 885 break; 886 } 887 } 888 } 889 if (--retrycnt > 0) { 890 if (opflags & BGRND) { 891 opflags &= ~BGRND; 892 if ((i = fork()) != 0) { 893 if (i == -1) 894 err(1, "nqnfs 2"); 895 exit(0); 896 } 897 (void) setsid(); 898 (void) close(STDIN_FILENO); 899 (void) close(STDOUT_FILENO); 900 (void) close(STDERR_FILENO); 901 (void) chdir("/"); 902 opflags |= ISBGRND; 903 } 904 sleep(60); 905 } 906 } 907 if (nfhret.stat == 0) 908 break; 909 } 910 freeaddrinfo(ai_nfs); 911 if (nfhret.stat) { 912 if (opflags & ISBGRND) 913 exit(1); 914 errno = nfhret.stat; 915 warnx("can't access %s: %s", spec, strerror(nfhret.stat)); 916 return (0); 917 } 918 #ifdef ISO 919 if (isoflag) { 920 nfsargsp->addr = (struct sockaddr *) &isoaddr; 921 nfsargsp->addrlen = sizeof (isoaddr); 922 } else 923 #endif /* ISO */ 924 { 925 nfsargsp->addr = (struct sockaddr *) nfs_nb.buf; 926 nfsargsp->addrlen = nfs_nb.len; 927 if (port != 0) { 928 struct sockaddr *sa = nfsargsp->addr; 929 switch (sa->sa_family) { 930 case AF_INET: 931 ((struct sockaddr_in *)sa)->sin_port = port; 932 #ifdef INET6 933 case AF_INET6: 934 ((struct sockaddr_in6 *)sa)->sin6_port = port; 935 break; 936 #endif 937 default: 938 errx(1, "Unsupported socket family %d", 939 sa->sa_family); 940 } 941 } 942 } 943 nfsargsp->fh = nfhret.nfh; 944 nfsargsp->fhsize = nfhret.fhsize; 945 nfsargsp->hostname = nam; 946 return (1); 947 } 948 949 /* 950 * xdr routines for mount rpc's 951 */ 952 static int 953 xdr_dir(XDR *xdrsp, char *dirp) 954 { 955 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 956 } 957 958 static int 959 xdr_fh(XDR *xdrsp, struct nfhret *np) 960 { 961 int i; 962 long auth, authcnt, authfnd = 0; 963 964 if (!xdr_u_long(xdrsp, &np->stat)) 965 return (0); 966 if (np->stat) 967 return (1); 968 switch (np->vers) { 969 case 1: 970 np->fhsize = NFSX_V2FH; 971 return (xdr_opaque(xdrsp, (caddr_t)np->nfh, NFSX_V2FH)); 972 case 3: 973 if (!xdr_long(xdrsp, &np->fhsize)) 974 return (0); 975 if (np->fhsize <= 0 || np->fhsize > NFSX_V3FHMAX) 976 return (0); 977 if (!xdr_opaque(xdrsp, (caddr_t)np->nfh, np->fhsize)) 978 return (0); 979 if (!xdr_long(xdrsp, &authcnt)) 980 return (0); 981 for (i = 0; i < authcnt; i++) { 982 if (!xdr_long(xdrsp, &auth)) 983 return (0); 984 if (auth == np->auth) 985 authfnd++; 986 } 987 /* 988 * Some servers, such as DEC's OSF/1 return a nil authenticator 989 * list to indicate RPCAUTH_UNIX. 990 */ 991 if (!authfnd && (authcnt > 0 || np->auth != RPCAUTH_UNIX)) 992 np->stat = EAUTH; 993 return (1); 994 }; 995 return (0); 996 } 997 998 static void 999 usage(void) 1000 { 1001 (void)fprintf(stderr, "usage: mount_nfs %s\n%s\n%s\n%s\n%s\n", 1002 "[-23bcCdiKlpPqsTUX] [-a maxreadahead] [-D deadthresh]", 1003 "\t[-g maxgroups] [-I readdirsize] [-L leaseterm] [-m realm]", 1004 "\t[-o options] [-R retrycnt] [-r readsize] [-t timeout]", 1005 "\t[-w writesize] [-x retrans]", 1006 "\trhost:path node"); 1007 exit(1); 1008 } 1009