mount_nfs.c revision 1.1.1.2 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.11 (Berkeley) 5/4/95";
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 NFSKERB
63 #include <kerberosIV/des.h>
64 #include <kerberosIV/krb.h>
65 #endif
66
67 #include <nfs/rpcv2.h>
68 #include <nfs/nfsproto.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 #define ALTF_BG 0x1
90 #define ALTF_NOCONN 0x2
91 #define ALTF_DUMBTIMR 0x4
92 #define ALTF_INTR 0x8
93 #define ALTF_KERB 0x10
94 #define ALTF_NFSV3 0x20
95 #define ALTF_RDIRPLUS 0x40
96 #define ALTF_MNTUDP 0x80
97 #define ALTF_RESVPORT 0x100
98 #define ALTF_SEQPACKET 0x200
99 #define ALTF_NQNFS 0x400
100 #define ALTF_SOFT 0x800
101 #define ALTF_TCP 0x1000
102
103 struct mntopt mopts[] = {
104 MOPT_STDOPTS,
105 MOPT_FORCE,
106 MOPT_UPDATE,
107 { "bg", 0, ALTF_BG, 1 },
108 { "conn", 1, ALTF_NOCONN, 1 },
109 { "dumbtimer", 0, ALTF_DUMBTIMR, 1 },
110 { "intr", 0, ALTF_INTR, 1 },
111 #ifdef NFSKERB
112 { "kerb", 0, ALTF_KERB, 1 },
113 #endif
114 { "nfsv3", 0, ALTF_NFSV3, 1 },
115 { "rdirplus", 0, ALTF_RDIRPLUS, 1 },
116 { "mntudp", 0, ALTF_MNTUDP, 1 },
117 { "resvport", 0, ALTF_RESVPORT, 1 },
118 #ifdef ISO
119 { "seqpacket", 0, ALTF_SEQPACKET, 1 },
120 #endif
121 { "nqnfs", 0, ALTF_NQNFS, 1 },
122 { "soft", 0, ALTF_SOFT, 1 },
123 { "tcp", 0, ALTF_TCP, 1 },
124 { NULL }
125 };
126
127 struct nfs_args nfsdefargs = {
128 NFS_ARGSVERSION,
129 (struct sockaddr *)0,
130 sizeof (struct sockaddr_in),
131 SOCK_DGRAM,
132 0,
133 (u_char *)0,
134 0,
135 0,
136 NFS_WSIZE,
137 NFS_RSIZE,
138 NFS_READDIRSIZE,
139 10,
140 NFS_RETRANS,
141 NFS_MAXGRPS,
142 NFS_DEFRAHEAD,
143 NQ_DEFLEASE,
144 NQ_DEADTHRESH,
145 (char *)0,
146 };
147
148 struct nfhret {
149 u_long stat;
150 long vers;
151 long auth;
152 long fhsize;
153 u_char nfh[NFSX_V3FHMAX];
154 };
155 #define DEF_RETRY 10000
156 #define BGRND 1
157 #define ISBGRND 2
158 int retrycnt = DEF_RETRY;
159 int opflags = 0;
160 int nfsproto = IPPROTO_UDP;
161 int mnttcp_ok = 1;
162
163 #ifdef NFSKERB
164 char inst[INST_SZ];
165 char realm[REALM_SZ];
166 struct {
167 u_long kind;
168 KTEXT_ST kt;
169 } ktick;
170 struct nfsrpc_nickverf kverf;
171 struct nfsrpc_fullblock kin, kout;
172 NFSKERBKEY_T kivec;
173 CREDENTIALS kcr;
174 struct timeval ktv;
175 NFSKERBKEYSCHED_T kerb_keysched;
176 #endif
177
178 int getnfsargs __P((char *, struct nfs_args *));
179 #ifdef ISO
180 struct iso_addr *iso_addr __P((const char *));
181 #endif
182 void set_rpc_maxgrouplist __P((int));
183 __dead void usage __P((void));
184 int xdr_dir __P((XDR *, char *));
185 int xdr_fh __P((XDR *, struct nfhret *));
186
187 int
188 main(argc, argv)
189 int argc;
190 char *argv[];
191 {
192 register int c;
193 register struct nfs_args *nfsargsp;
194 struct nfs_args nfsargs;
195 struct nfsd_cargs ncd;
196 int mntflags, altflags, i, nfssvc_flag, num;
197 char *name, *p, *spec;
198 int error = 0;
199 #ifdef NFSKERB
200 uid_t last_ruid;
201
202 last_ruid = -1;
203 (void)strcpy(realm, KRB_REALM);
204 if (sizeof (struct nfsrpc_nickverf) != RPCX_NICKVERF ||
205 sizeof (struct nfsrpc_fullblock) != RPCX_FULLBLOCK ||
206 ((char *)&ktick.kt) - ((char *)&ktick) != NFSX_UNSIGNED ||
207 ((char *)ktick.kt.dat) - ((char *)&ktick) != 2 * NFSX_UNSIGNED)
208 fprintf(stderr, "Yikes! NFSKERB structs not packed!!\n");
209 #endif /* NFSKERB */
210 retrycnt = DEF_RETRY;
211
212 mntflags = 0;
213 altflags = 0;
214 nfsargs = nfsdefargs;
215 nfsargsp = &nfsargs;
216 while ((c = getopt(argc, argv,
217 "3a:bcdD:g:I:iKL:lm:o:PpqR:r:sTt:w:x:U")) != EOF)
218 switch (c) {
219 case '3':
220 nfsargsp->flags |= NFSMNT_NFSV3;
221 break;
222 case 'a':
223 num = strtol(optarg, &p, 10);
224 if (*p || num < 0)
225 errx(1, "illegal -a value -- %s", optarg);
226 nfsargsp->readahead = num;
227 nfsargsp->flags |= NFSMNT_READAHEAD;
228 break;
229 case 'b':
230 opflags |= BGRND;
231 break;
232 case 'c':
233 nfsargsp->flags |= NFSMNT_NOCONN;
234 break;
235 case 'D':
236 num = strtol(optarg, &p, 10);
237 if (*p || num <= 0)
238 errx(1, "illegal -D value -- %s", optarg);
239 nfsargsp->deadthresh = num;
240 nfsargsp->flags |= NFSMNT_DEADTHRESH;
241 break;
242 case 'd':
243 nfsargsp->flags |= NFSMNT_DUMBTIMR;
244 break;
245 case 'g':
246 num = strtol(optarg, &p, 10);
247 if (*p || num <= 0)
248 errx(1, "illegal -g value -- %s", optarg);
249 set_rpc_maxgrouplist(num);
250 nfsargsp->maxgrouplist = num;
251 nfsargsp->flags |= NFSMNT_MAXGRPS;
252 break;
253 case 'I':
254 num = strtol(optarg, &p, 10);
255 if (*p || num <= 0)
256 errx(1, "illegal -I value -- %s", optarg);
257 nfsargsp->readdirsize = num;
258 nfsargsp->flags |= NFSMNT_READDIRSIZE;
259 break;
260 case 'i':
261 nfsargsp->flags |= NFSMNT_INT;
262 break;
263 #ifdef NFSKERB
264 case 'K':
265 nfsargsp->flags |= NFSMNT_KERB;
266 break;
267 #endif
268 case 'L':
269 num = strtol(optarg, &p, 10);
270 if (*p || num < 2)
271 errx(1, "illegal -L value -- %s", optarg);
272 nfsargsp->leaseterm = num;
273 nfsargsp->flags |= NFSMNT_LEASETERM;
274 break;
275 case 'l':
276 nfsargsp->flags |= NFSMNT_RDIRPLUS;
277 break;
278 #ifdef NFSKERB
279 case 'm':
280 (void)strncpy(realm, optarg, REALM_SZ - 1);
281 realm[REALM_SZ - 1] = '\0';
282 break;
283 #endif
284 case 'o':
285 getmntopts(optarg, mopts, &mntflags, &altflags);
286 if(altflags & ALTF_BG)
287 opflags |= BGRND;
288 if(altflags & ALTF_NOCONN)
289 nfsargsp->flags |= NFSMNT_NOCONN;
290 if(altflags & ALTF_DUMBTIMR)
291 nfsargsp->flags |= NFSMNT_DUMBTIMR;
292 if(altflags & ALTF_INTR)
293 nfsargsp->flags |= NFSMNT_INT;
294 #ifdef NFSKERB
295 if(altflags & ALTF_KERB)
296 nfsargsp->flags |= NFSMNT_KERB;
297 #endif
298 if(altflags & ALTF_NFSV3)
299 nfsargsp->flags |= NFSMNT_NFSV3;
300 if(altflags & ALTF_RDIRPLUS)
301 nfsargsp->flags |= NFSMNT_RDIRPLUS;
302 if(altflags & ALTF_MNTUDP)
303 mnttcp_ok = 0;
304 if(altflags & ALTF_RESVPORT)
305 nfsargsp->flags |= NFSMNT_RESVPORT;
306 #ifdef ISO
307 if(altflags & ALTF_SEQPACKET)
308 nfsargsp->sotype = SOCK_SEQPACKET;
309 #endif
310 if(altflags & ALTF_NQNFS)
311 nfsargsp->flags |= (NFSMNT_NQNFS|NFSMNT_NFSV3);
312 if(altflags & ALTF_SOFT)
313 nfsargsp->flags |= NFSMNT_SOFT;
314 if(altflags & ALTF_TCP) {
315 nfsargsp->sotype = SOCK_STREAM;
316 nfsproto = IPPROTO_TCP;
317 }
318 altflags = 0;
319 break;
320 case 'P':
321 nfsargsp->flags |= NFSMNT_RESVPORT;
322 break;
323 #ifdef ISO
324 case 'p':
325 nfsargsp->sotype = SOCK_SEQPACKET;
326 break;
327 #endif
328 case 'q':
329 nfsargsp->flags |= (NFSMNT_NQNFS | NFSMNT_NFSV3);
330 break;
331 case 'R':
332 num = strtol(optarg, &p, 10);
333 if (*p || num <= 0)
334 errx(1, "illegal -R value -- %s", optarg);
335 retrycnt = num;
336 break;
337 case 'r':
338 num = strtol(optarg, &p, 10);
339 if (*p || num <= 0)
340 errx(1, "illegal -r value -- %s", optarg);
341 nfsargsp->rsize = num;
342 nfsargsp->flags |= NFSMNT_RSIZE;
343 break;
344 case 's':
345 nfsargsp->flags |= NFSMNT_SOFT;
346 break;
347 case 'T':
348 nfsargsp->sotype = SOCK_STREAM;
349 nfsproto = IPPROTO_TCP;
350 break;
351 case 't':
352 num = strtol(optarg, &p, 10);
353 if (*p || num <= 0)
354 errx(1, "illegal -t value -- %s", optarg);
355 nfsargsp->timeo = num;
356 nfsargsp->flags |= NFSMNT_TIMEO;
357 break;
358 case 'w':
359 num = strtol(optarg, &p, 10);
360 if (*p || num <= 0)
361 errx(1, "illegal -w value -- %s", optarg);
362 nfsargsp->wsize = num;
363 nfsargsp->flags |= NFSMNT_WSIZE;
364 break;
365 case 'x':
366 num = strtol(optarg, &p, 10);
367 if (*p || num <= 0)
368 errx(1, "illegal -x value -- %s", optarg);
369 nfsargsp->retrans = num;
370 nfsargsp->flags |= NFSMNT_RETRANS;
371 break;
372 case 'U':
373 mnttcp_ok = 0;
374 break;
375 default:
376 usage();
377 break;
378 }
379 argc -= optind;
380 argv += optind;
381
382 if (argc != 2) {
383 usage();
384 /* NOTREACHED */
385 }
386
387 spec = *argv++;
388 name = *argv;
389
390 if (!getnfsargs(spec, nfsargsp))
391 exit(1);
392
393 if (mount("nfs", name, mntflags, nfsargsp))
394 err(1, "%s", name);
395 if (nfsargsp->flags & (NFSMNT_NQNFS | NFSMNT_KERB)) {
396 if ((opflags & ISBGRND) == 0) {
397 if (i = fork()) {
398 if (i == -1)
399 err(1, "nqnfs 1");
400 exit(0);
401 }
402 (void) setsid();
403 (void) close(STDIN_FILENO);
404 (void) close(STDOUT_FILENO);
405 (void) close(STDERR_FILENO);
406 (void) chdir("/");
407 }
408 openlog("mount_nfs:", LOG_PID, LOG_DAEMON);
409 nfssvc_flag = NFSSVC_MNTD;
410 ncd.ncd_dirp = name;
411 while (nfssvc(nfssvc_flag, (caddr_t)&ncd) < 0) {
412 if (errno != ENEEDAUTH) {
413 syslog(LOG_ERR, "nfssvc err %m");
414 continue;
415 }
416 nfssvc_flag =
417 NFSSVC_MNTD | NFSSVC_GOTAUTH | NFSSVC_AUTHINFAIL;
418 #ifdef NFSKERB
419 /*
420 * Set up as ncd_authuid for the kerberos call.
421 * Must set ruid to ncd_authuid and reset the
422 * ticket name iff ncd_authuid is not the same
423 * as last time, so that the right ticket file
424 * is found.
425 * Get the Kerberos credential structure so that
426 * we have the seesion key and get a ticket for
427 * this uid.
428 * For more info see the IETF Draft "Authentication
429 * in ONC RPC".
430 */
431 if (ncd.ncd_authuid != last_ruid) {
432 krb_set_tkt_string("");
433 last_ruid = ncd.ncd_authuid;
434 }
435 setreuid(ncd.ncd_authuid, 0);
436 kret = krb_get_cred(NFS_KERBSRV, inst, realm, &kcr);
437 if (kret == RET_NOTKT) {
438 kret = get_ad_tkt(NFS_KERBSRV, inst, realm,
439 DEFAULT_TKT_LIFE);
440 if (kret == KSUCCESS)
441 kret = krb_get_cred(NFS_KERBSRV, inst, realm,
442 &kcr);
443 }
444 if (kret == KSUCCESS)
445 kret = krb_mk_req(&ktick.kt, NFS_KERBSRV, inst,
446 realm, 0);
447
448 /*
449 * Fill in the AKN_FULLNAME authenticator and verfier.
450 * Along with the Kerberos ticket, we need to build
451 * the timestamp verifier and encrypt it in CBC mode.
452 */
453 if (kret == KSUCCESS &&
454 ktick.kt.length <= (RPCAUTH_MAXSIZ-3*NFSX_UNSIGNED)
455 && gettimeofday(&ktv, (struct timezone *)0) == 0) {
456 ncd.ncd_authtype = RPCAUTH_KERB4;
457 ncd.ncd_authstr = (u_char *)&ktick;
458 ncd.ncd_authlen = nfsm_rndup(ktick.kt.length) +
459 3 * NFSX_UNSIGNED;
460 ncd.ncd_verfstr = (u_char *)&kverf;
461 ncd.ncd_verflen = sizeof (kverf);
462 memmove(ncd.ncd_key, kcr.session,
463 sizeof (kcr.session));
464 kin.t1 = htonl(ktv.tv_sec);
465 kin.t2 = htonl(ktv.tv_usec);
466 kin.w1 = htonl(NFS_KERBTTL);
467 kin.w2 = htonl(NFS_KERBTTL - 1);
468 bzero((caddr_t)kivec, sizeof (kivec));
469
470 /*
471 * Encrypt kin in CBC mode using the session
472 * key in kcr.
473 */
474 XXX
475
476 /*
477 * Finally, fill the timestamp verifier into the
478 * authenticator and verifier.
479 */
480 ktick.kind = htonl(RPCAKN_FULLNAME);
481 kverf.kind = htonl(RPCAKN_FULLNAME);
482 NFS_KERBW1(ktick.kt) = kout.w1;
483 ktick.kt.length = htonl(ktick.kt.length);
484 kverf.verf.t1 = kout.t1;
485 kverf.verf.t2 = kout.t2;
486 kverf.verf.w2 = kout.w2;
487 nfssvc_flag = NFSSVC_MNTD | NFSSVC_GOTAUTH;
488 }
489 setreuid(0, 0);
490 #endif /* NFSKERB */
491 }
492 }
493 exit(0);
494 }
495
496 int
497 getnfsargs(spec, nfsargsp)
498 char *spec;
499 struct nfs_args *nfsargsp;
500 {
501 register CLIENT *clp;
502 struct hostent *hp;
503 static struct sockaddr_in saddr;
504 #ifdef ISO
505 static struct sockaddr_iso isoaddr;
506 struct iso_addr *isop;
507 int isoflag = 0;
508 #endif
509 struct timeval pertry, try;
510 enum clnt_stat clnt_stat;
511 int so = RPC_ANYSOCK, i, nfsvers, mntvers;
512 char *hostp, *delimp;
513 #ifdef NFSKERB
514 char *cp;
515 #endif
516 u_short tport;
517 static struct nfhret nfhret;
518 static char nam[MNAMELEN + 1];
519
520 strncpy(nam, spec, MNAMELEN);
521 nam[MNAMELEN] = '\0';
522 if ((delimp = strchr(spec, '@')) != NULL) {
523 hostp = delimp + 1;
524 } else if ((delimp = strchr(spec, ':')) != NULL) {
525 hostp = spec;
526 spec = delimp + 1;
527 } else {
528 warnx("no <host>:<dirpath> or <dirpath>@<host> spec");
529 return (0);
530 }
531 *delimp = '\0';
532 /*
533 * DUMB!! Until the mount protocol works on iso transport, we must
534 * supply both an iso and an inet address for the host.
535 */
536 #ifdef ISO
537 if (!strncmp(hostp, "iso=", 4)) {
538 u_short isoport;
539
540 hostp += 4;
541 isoflag++;
542 if ((delimp = strchr(hostp, '+')) == NULL) {
543 warnx("no iso+inet address");
544 return (0);
545 }
546 *delimp = '\0';
547 if ((isop = iso_addr(hostp)) == NULL) {
548 warnx("bad ISO address");
549 return (0);
550 }
551 memset(&isoaddr, 0, sizeof (isoaddr));
552 memmove(&isoaddr.siso_addr, isop, sizeof (struct iso_addr));
553 isoaddr.siso_len = sizeof (isoaddr);
554 isoaddr.siso_family = AF_ISO;
555 isoaddr.siso_tlen = 2;
556 isoport = htons(NFS_PORT);
557 memmove(TSEL(&isoaddr), &isoport, isoaddr.siso_tlen);
558 hostp = delimp + 1;
559 }
560 #endif /* ISO */
561
562 /*
563 * Handle an internet host address and reverse resolve it if
564 * doing Kerberos.
565 */
566 if (isdigit(*hostp)) {
567 if ((saddr.sin_addr.s_addr = inet_addr(hostp)) == -1) {
568 warnx("bad net address %s", hostp);
569 return (0);
570 }
571 } else if ((hp = gethostbyname(hostp)) != NULL)
572 memmove(&saddr.sin_addr, hp->h_addr, hp->h_length);
573 else {
574 warnx("can't get net id for host");
575 return (0);
576 }
577 #ifdef NFSKERB
578 if ((nfsargsp->flags & NFSMNT_KERB)) {
579 if ((hp = gethostbyaddr((char *)&saddr.sin_addr.s_addr,
580 sizeof (u_long), AF_INET)) == (struct hostent *)0) {
581 warnx("can't reverse resolve net address");
582 return (0);
583 }
584 memmove(&saddr.sin_addr, hp->h_addr, hp->h_length);
585 strncpy(inst, hp->h_name, INST_SZ);
586 inst[INST_SZ - 1] = '\0';
587 if (cp = strchr(inst, '.'))
588 *cp = '\0';
589 }
590 #endif /* NFSKERB */
591
592 if (nfsargsp->flags & NFSMNT_NFSV3) {
593 nfsvers = 3;
594 mntvers = 3;
595 } else {
596 nfsvers = 2;
597 mntvers = 1;
598 }
599 nfhret.stat = EACCES; /* Mark not yet successful */
600 while (retrycnt > 0) {
601 saddr.sin_family = AF_INET;
602 saddr.sin_port = htons(PMAPPORT);
603 if ((tport = pmap_getport(&saddr, RPCPROG_NFS,
604 nfsvers, nfsproto)) == 0) {
605 if ((opflags & ISBGRND) == 0)
606 clnt_pcreateerror("NFS Portmap");
607 } else {
608 saddr.sin_port = 0;
609 pertry.tv_sec = 10;
610 pertry.tv_usec = 0;
611 if (mnttcp_ok && nfsargsp->sotype == SOCK_STREAM)
612 clp = clnttcp_create(&saddr, RPCPROG_MNT, mntvers,
613 &so, 0, 0);
614 else
615 clp = clntudp_create(&saddr, RPCPROG_MNT, mntvers,
616 pertry, &so);
617 if (clp == NULL) {
618 if ((opflags & ISBGRND) == 0)
619 clnt_pcreateerror("Cannot MNT PRC");
620 } else {
621 clp->cl_auth = authunix_create_default();
622 try.tv_sec = 10;
623 try.tv_usec = 0;
624 if (nfsargsp->flags & NFSMNT_KERB)
625 nfhret.auth = RPCAUTH_KERB4;
626 else
627 nfhret.auth = RPCAUTH_UNIX;
628 nfhret.vers = mntvers;
629 clnt_stat = clnt_call(clp, RPCMNT_MOUNT,
630 xdr_dir, spec, xdr_fh, &nfhret, try);
631 if (clnt_stat != RPC_SUCCESS) {
632 if ((opflags & ISBGRND) == 0)
633 warnx("%s", clnt_sperror(clp,
634 "bad MNT RPC"));
635 } else {
636 auth_destroy(clp->cl_auth);
637 clnt_destroy(clp);
638 retrycnt = 0;
639 }
640 }
641 }
642 if (--retrycnt > 0) {
643 if (opflags & BGRND) {
644 opflags &= ~BGRND;
645 if (i = fork()) {
646 if (i == -1)
647 err(1, "nqnfs 2");
648 exit(0);
649 }
650 (void) setsid();
651 (void) close(STDIN_FILENO);
652 (void) close(STDOUT_FILENO);
653 (void) close(STDERR_FILENO);
654 (void) chdir("/");
655 opflags |= ISBGRND;
656 }
657 sleep(60);
658 }
659 }
660 if (nfhret.stat) {
661 if (opflags & ISBGRND)
662 exit(1);
663 warnx("can't access %s: %s", spec, strerror(nfhret.stat));
664 return (0);
665 }
666 saddr.sin_port = htons(tport);
667 #ifdef ISO
668 if (isoflag) {
669 nfsargsp->addr = (struct sockaddr *) &isoaddr;
670 nfsargsp->addrlen = sizeof (isoaddr);
671 } else
672 #endif /* ISO */
673 {
674 nfsargsp->addr = (struct sockaddr *) &saddr;
675 nfsargsp->addrlen = sizeof (saddr);
676 }
677 nfsargsp->fh = nfhret.nfh;
678 nfsargsp->fhsize = nfhret.fhsize;
679 nfsargsp->hostname = nam;
680 return (1);
681 }
682
683 /*
684 * xdr routines for mount rpc's
685 */
686 int
687 xdr_dir(xdrsp, dirp)
688 XDR *xdrsp;
689 char *dirp;
690 {
691 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
692 }
693
694 int
695 xdr_fh(xdrsp, np)
696 XDR *xdrsp;
697 register struct nfhret *np;
698 {
699 register int i;
700 long auth, authcnt, authfnd = 0;
701
702 if (!xdr_u_long(xdrsp, &np->stat))
703 return (0);
704 if (np->stat)
705 return (1);
706 switch (np->vers) {
707 case 1:
708 np->fhsize = NFSX_V2FH;
709 return (xdr_opaque(xdrsp, (caddr_t)np->nfh, NFSX_V2FH));
710 case 3:
711 if (!xdr_long(xdrsp, &np->fhsize))
712 return (0);
713 if (np->fhsize <= 0 || np->fhsize > NFSX_V3FHMAX)
714 return (0);
715 if (!xdr_opaque(xdrsp, (caddr_t)np->nfh, np->fhsize))
716 return (0);
717 if (!xdr_long(xdrsp, &authcnt))
718 return (0);
719 for (i = 0; i < authcnt; i++) {
720 if (!xdr_long(xdrsp, &auth))
721 return (0);
722 if (auth == np->auth)
723 authfnd++;
724 }
725 /*
726 * Some servers, such as DEC's OSF/1 return a nil authenticator
727 * list to indicate RPCAUTH_UNIX.
728 */
729 if (!authfnd && (authcnt > 0 || np->auth != RPCAUTH_UNIX))
730 np->stat = EAUTH;
731 return (1);
732 };
733 return (0);
734 }
735
736 __dead void
737 usage()
738 {
739 (void)fprintf(stderr, "usage: mount_nfs %s\n%s\n%s\n%s\n",
740 "[-bcdiKklMPqsT] [-a maxreadahead] [-D deadthresh]",
741 "\t[-g maxgroups] [-L leaseterm] [-m realm] [-o options] [-R retrycnt]",
742 "\t[-r readsize] [-t timeout] [-w writesize] [-x retrans]",
743 "\trhost:path node");
744 exit(1);
745 }
746