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