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