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