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