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