mount_nfs.c revision 5966
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
38static 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
44static char sccsid[] = "@(#)mount_nfs.c	8.3 (Berkeley) 3/27/94";
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 KERBEROS
63#include <kerberosIV/des.h>
64#include <kerberosIV/krb.h>
65#endif
66
67#include <nfs/rpcv2.h>
68#include <nfs/nfsv2.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_NQLOOKLSE	0x20
95#define ALTF_RDIRALOOK	0x40
96#define	ALTF_MYWRITE	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
103struct 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 KERBEROS
112	{ "kerb", 0, ALTF_KERB, 1 },
113#endif
114	{ "nqlooklease", 0, ALTF_NQLOOKLSE, 1 },
115	{ "rdiralook", 0, ALTF_RDIRALOOK, 1 },
116	{ "mywrite", 0, ALTF_MYWRITE, 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
127struct nfs_args nfsdefargs = {
128	(struct sockaddr *)0,
129	sizeof (struct sockaddr_in),
130	SOCK_DGRAM,
131	0,
132	(nfsv2fh_t *)0,
133	0,
134	NFS_WSIZE,
135	NFS_RSIZE,
136	NFS_TIMEO,
137	NFS_RETRANS,
138	NFS_MAXGRPS,
139	NFS_DEFRAHEAD,
140	NQ_DEFLEASE,
141	NQ_DEADTHRESH,
142	(char *)0,
143};
144
145struct nfhret {
146	u_long	stat;
147	nfsv2fh_t nfh;
148};
149#define	DEF_RETRY	10000
150#define	BGRND	1
151#define	ISBGRND	2
152int retrycnt = DEF_RETRY;
153int opflags = 0;
154
155#ifdef KERBEROS
156char inst[INST_SZ];
157char realm[REALM_SZ];
158KTEXT_ST kt;
159#endif
160
161int	getnfsargs __P((char *, struct nfs_args *));
162#ifdef ISO
163struct	iso_addr *iso_addr __P((const char *));
164#endif
165void	set_rpc_maxgrouplist __P((int));
166__dead	void usage __P((void));
167int	xdr_dir __P((XDR *, char *));
168int	xdr_fh __P((XDR *, struct nfhret *));
169
170int
171main(argc, argv)
172	int argc;
173	char *argv[];
174{
175	register int c;
176	register struct nfs_args *nfsargsp;
177	struct nfs_args nfsargs;
178	struct nfsd_cargs ncd;
179	int mntflags, altflags, i, nfssvc_flag, num;
180	char *name, *p, *spec;
181	int error = 0;
182	struct vfsconf *vfc;
183#ifdef KERBEROS
184	uid_t last_ruid;
185#endif
186
187#ifdef KERBEROS
188	last_ruid = -1;
189	(void)strcpy(realm, KRB_REALM);
190#endif
191	retrycnt = DEF_RETRY;
192
193	mntflags = 0;
194	altflags = 0;
195	nfsargs = nfsdefargs;
196	nfsargsp = &nfsargs;
197	while ((c = getopt(argc, argv,
198	    "a:bcdD:g:iKklL:Mm:o:PpqR:r:sTt:w:x:")) != EOF)
199		switch (c) {
200		case 'a':
201			num = strtol(optarg, &p, 10);
202			if (*p || num < 0)
203				errx(1, "illegal -a value -- %s", optarg);
204			nfsargsp->readahead = num;
205			nfsargsp->flags |= NFSMNT_READAHEAD;
206			break;
207		case 'b':
208			opflags |= BGRND;
209			break;
210		case 'c':
211			nfsargsp->flags |= NFSMNT_NOCONN;
212			break;
213		case 'D':
214			num = strtol(optarg, &p, 10);
215			if (*p || num <= 0)
216				errx(1, "illegal -D value -- %s", optarg);
217			nfsargsp->deadthresh = num;
218			nfsargsp->flags |= NFSMNT_DEADTHRESH;
219			break;
220		case 'd':
221			nfsargsp->flags |= NFSMNT_DUMBTIMR;
222			break;
223		case 'g':
224			num = strtol(optarg, &p, 10);
225			if (*p || num <= 0)
226				errx(1, "illegal -g value -- %s", optarg);
227			set_rpc_maxgrouplist(num);
228			nfsargsp->maxgrouplist = num;
229			nfsargsp->flags |= NFSMNT_MAXGRPS;
230			break;
231		case 'i':
232			nfsargsp->flags |= NFSMNT_INT;
233			break;
234#ifdef KERBEROS
235		case 'K':
236			nfsargsp->flags |= NFSMNT_KERB;
237			break;
238#endif
239		case 'k':
240			nfsargsp->flags |= NFSMNT_NQLOOKLEASE;
241			break;
242		case 'L':
243			num = strtol(optarg, &p, 10);
244			if (*p || num < 2)
245				errx(1, "illegal -L value -- %s", optarg);
246			nfsargsp->leaseterm = num;
247			nfsargsp->flags |= NFSMNT_LEASETERM;
248			break;
249		case 'l':
250			nfsargsp->flags |= NFSMNT_RDIRALOOK;
251			break;
252		case 'M':
253			nfsargsp->flags |= NFSMNT_MYWRITE;
254			break;
255#ifdef KERBEROS
256		case 'm':
257			(void)strncpy(realm, optarg, REALM_SZ - 1);
258			realm[REALM_SZ - 1] = '\0';
259			break;
260#endif
261		case 'o':
262			getmntopts(optarg, mopts, &mntflags, &altflags);
263			if(altflags & ALTF_BG)
264				opflags |= BGRND;
265			if(altflags & ALTF_NOCONN)
266				nfsargsp->flags |= NFSMNT_NOCONN;
267			if(altflags & ALTF_DUMBTIMR)
268				nfsargsp->flags |= NFSMNT_DUMBTIMR;
269			if(altflags & ALTF_INTR)
270				nfsargsp->flags |= NFSMNT_INT;
271#ifdef KERBEROS
272			if(altflags & ALTF_KERB)
273				nfsargsp->flags |= NFSMNT_KERB;
274#endif
275			if(altflags & ALTF_NQLOOKLSE)
276				nfsargsp->flags |= NFSMNT_NQLOOKLEASE;
277			if(altflags & ALTF_RDIRALOOK)
278				nfsargsp->flags |= NFSMNT_RDIRALOOK;
279			if(altflags & ALTF_MYWRITE)
280				nfsargsp->flags |= NFSMNT_MYWRITE;
281			if(altflags & ALTF_RESVPORT)
282				nfsargsp->flags |= NFSMNT_RESVPORT;
283#ifdef ISO
284			if(altflags & ALTF_SEQPACKET)
285				nfsargsp->sotype = SOCK_SEQPACKET;
286#endif
287			if(altflags & ALTF_NQNFS)
288				nfsargsp->flags |= NFSMNT_NQNFS;
289			if(altflags & ALTF_SOFT)
290				nfsargsp->flags |= NFSMNT_SOFT;
291			if(altflags & ALTF_TCP)
292				nfsargsp->sotype = SOCK_STREAM;
293			altflags = 0;
294			break;
295		case 'P':
296			nfsargsp->flags |= NFSMNT_RESVPORT;
297			break;
298#ifdef ISO
299		case 'p':
300			nfsargsp->sotype = SOCK_SEQPACKET;
301			break;
302#endif
303		case 'q':
304			nfsargsp->flags |= NFSMNT_NQNFS;
305			break;
306		case 'R':
307			num = strtol(optarg, &p, 10);
308			if (*p || num <= 0)
309				errx(1, "illegal -R value -- %s", optarg);
310			retrycnt = num;
311			break;
312		case 'r':
313			num = strtol(optarg, &p, 10);
314			if (*p || num <= 0)
315				errx(1, "illegal -r value -- %s", optarg);
316			nfsargsp->rsize = num;
317			nfsargsp->flags |= NFSMNT_RSIZE;
318			break;
319		case 's':
320			nfsargsp->flags |= NFSMNT_SOFT;
321			break;
322		case 'T':
323			nfsargsp->sotype = SOCK_STREAM;
324			break;
325		case 't':
326			num = strtol(optarg, &p, 10);
327			if (*p || num <= 0)
328				errx(1, "illegal -t value -- %s", optarg);
329			nfsargsp->timeo = num;
330			nfsargsp->flags |= NFSMNT_TIMEO;
331			break;
332		case 'w':
333			num = strtol(optarg, &p, 10);
334			if (*p || num <= 0)
335				errx(1, "illegal -w value -- %s", optarg);
336			nfsargsp->wsize = num;
337			nfsargsp->flags |= NFSMNT_WSIZE;
338			break;
339		case 'x':
340			num = strtol(optarg, &p, 10);
341			if (*p || num <= 0)
342				errx(1, "illegal -x value -- %s", optarg);
343			nfsargsp->retrans = num;
344			nfsargsp->flags |= NFSMNT_RETRANS;
345			break;
346		default:
347			usage();
348			break;
349		}
350	argc -= optind;
351	argv += optind;
352
353	if (argc != 2)
354		usage();
355
356	spec = *argv++;
357	name = *argv;
358
359	if (!getnfsargs(spec, nfsargsp))
360		exit(1);
361
362	vfc = getvfsbyname("nfs");
363	if(!vfc && vfsisloadable("nfs")) {
364		if(vfsload("nfs"))
365			err(1, "vfsload(nfs)");
366		endvfsent();	/* flush cache */
367		vfc = getvfsbyname("nfs");
368	}
369
370	if (mount(vfc ? vfc->vfc_index : MOUNT_NFS, name, mntflags, nfsargsp))
371		err(1, "%s", name);
372	if (nfsargsp->flags & (NFSMNT_NQNFS | NFSMNT_KERB)) {
373		if ((opflags & ISBGRND) == 0) {
374			if (i = fork()) {
375				if (i == -1)
376					err(1, "nqnfs 1");
377				exit(0);
378			}
379			(void) setsid();
380			(void) close(STDIN_FILENO);
381			(void) close(STDOUT_FILENO);
382			(void) close(STDERR_FILENO);
383			(void) chdir("/");
384		}
385		openlog("mount_nfs:", LOG_PID, LOG_DAEMON);
386		nfssvc_flag = NFSSVC_MNTD;
387		ncd.ncd_dirp = name;
388		while (nfssvc(nfssvc_flag, (caddr_t)&ncd) < 0) {
389			if (errno != ENEEDAUTH) {
390				syslog(LOG_ERR, "nfssvc err %m");
391				continue;
392			}
393			nfssvc_flag =
394			    NFSSVC_MNTD | NFSSVC_GOTAUTH | NFSSVC_AUTHINFAIL;
395#ifdef KERBEROS
396			/*
397			 * Set up as ncd_authuid for the kerberos call.
398			 * Must set ruid to ncd_authuid and reset the
399			 * ticket name iff ncd_authuid is not the same
400			 * as last time, so that the right ticket file
401			 * is found.
402			 */
403			if (ncd.ncd_authuid != last_ruid) {
404				krb_set_tkt_string("");
405				last_ruid = ncd.ncd_authuid;
406			}
407			setreuid(ncd.ncd_authuid, 0);
408			if (krb_mk_req(&kt, "rcmd", inst, realm, 0) ==
409			    KSUCCESS &&
410			    kt.length <= (RPCAUTH_MAXSIZ - 2 * NFSX_UNSIGNED)) {
411				ncd.ncd_authtype = RPCAUTH_NQNFS;
412				ncd.ncd_authlen = kt.length;
413				ncd.ncd_authstr = (char *)kt.dat;
414				nfssvc_flag = NFSSVC_MNTD | NFSSVC_GOTAUTH;
415			}
416			setreuid(0, 0);
417#endif /* KERBEROS */
418		}
419	}
420	exit(0);
421}
422
423int
424getnfsargs(spec, nfsargsp)
425	char *spec;
426	struct nfs_args *nfsargsp;
427{
428	register CLIENT *clp;
429	struct hostent *hp;
430	static struct sockaddr_in saddr;
431#ifdef ISO
432	static struct sockaddr_iso isoaddr;
433	struct iso_addr *isop;
434	int isoflag = 0;
435#endif
436	struct timeval pertry, try;
437	enum clnt_stat clnt_stat;
438	int so = RPC_ANYSOCK, i;
439	char *hostp, *delimp;
440#ifdef KERBEROS
441	char *cp;
442#endif
443	u_short tport;
444	static struct nfhret nfhret;
445	static char nam[MNAMELEN + 1];
446
447	strncpy(nam, spec, MNAMELEN);
448	nam[MNAMELEN] = '\0';
449	if ((delimp = strchr(spec, '@')) != NULL) {
450		hostp = delimp + 1;
451	} else if ((delimp = strchr(spec, ':')) != NULL) {
452		hostp = spec;
453		spec = delimp + 1;
454	} else {
455		warnx("no <host>:<dirpath> or <dirpath>@<host> spec");
456		return (0);
457	}
458	*delimp = '\0';
459	/*
460	 * DUMB!! Until the mount protocol works on iso transport, we must
461	 * supply both an iso and an inet address for the host.
462	 */
463#ifdef ISO
464	if (!strncmp(hostp, "iso=", 4)) {
465		u_short isoport;
466
467		hostp += 4;
468		isoflag++;
469		if ((delimp = strchr(hostp, '+')) == NULL) {
470			warnx("no iso+inet address");
471			return (0);
472		}
473		*delimp = '\0';
474		if ((isop = iso_addr(hostp)) == NULL) {
475			warnx("bad ISO address");
476			return (0);
477		}
478		bzero((caddr_t)&isoaddr, sizeof (isoaddr));
479		bcopy((caddr_t)isop, (caddr_t)&isoaddr.siso_addr,
480			sizeof (struct iso_addr));
481		isoaddr.siso_len = sizeof (isoaddr);
482		isoaddr.siso_family = AF_ISO;
483		isoaddr.siso_tlen = 2;
484		isoport = htons(NFS_PORT);
485		bcopy((caddr_t)&isoport, TSEL(&isoaddr), isoaddr.siso_tlen);
486		hostp = delimp + 1;
487	}
488#endif /* ISO */
489
490	/*
491	 * Handle an internet host address and reverse resolve it if
492	 * doing Kerberos.
493	 */
494	if (isdigit(*hostp)) {
495		if ((saddr.sin_addr.s_addr = inet_addr(hostp)) == -1) {
496			warnx("bad net address %s", hostp);
497			return (0);
498		}
499	} else if ((hp = gethostbyname(hostp)) != NULL) {
500		bcopy(hp->h_addr, (caddr_t)&saddr.sin_addr, hp->h_length);
501	} else {
502		warnx("can't get net id for host");
503		return (0);
504        }
505#ifdef KERBEROS
506	if ((nfsargsp->flags & NFSMNT_KERB)) {
507		if ((hp = gethostbyaddr((char *)&saddr.sin_addr.s_addr,
508		    sizeof (u_long), AF_INET)) == (struct hostent *)0) {
509			warnx("can't reverse resolve net address");
510			return (0);
511		}
512		bcopy(hp->h_addr, (caddr_t)&saddr.sin_addr, hp->h_length);
513		strncpy(inst, hp->h_name, INST_SZ);
514		inst[INST_SZ - 1] = '\0';
515		if (cp = strchr(inst, '.'))
516			*cp = '\0';
517	}
518#endif /* KERBEROS */
519
520	nfhret.stat = EACCES;	/* Mark not yet successful */
521	while (retrycnt > 0) {
522		saddr.sin_family = AF_INET;
523		saddr.sin_port = htons(PMAPPORT);
524		if ((tport = pmap_getport(&saddr, RPCPROG_NFS,
525		    NFS_VER2, IPPROTO_UDP)) == 0) {
526			if ((opflags & ISBGRND) == 0)
527				clnt_pcreateerror("NFS Portmap");
528		} else {
529			saddr.sin_port = 0;
530			pertry.tv_sec = 10;
531			pertry.tv_usec = 0;
532			if ((clp = clntudp_create(&saddr, RPCPROG_MNT,
533			    RPCMNT_VER1, pertry, &so)) == NULL) {
534				if ((opflags & ISBGRND) == 0)
535					clnt_pcreateerror("Cannot MNT RPC");
536			} else {
537				clp->cl_auth = authunix_create_default();
538				try.tv_sec = 10;
539				try.tv_usec = 0;
540				clnt_stat = clnt_call(clp, RPCMNT_MOUNT,
541				    xdr_dir, spec, xdr_fh, &nfhret, try);
542				if (clnt_stat != RPC_SUCCESS) {
543					if ((opflags & ISBGRND) == 0)
544						warnx("%s", clnt_sperror(clp,
545						    "bad MNT RPC"));
546				} else {
547					auth_destroy(clp->cl_auth);
548					clnt_destroy(clp);
549					retrycnt = 0;
550				}
551			}
552		}
553		if (--retrycnt > 0) {
554			if (opflags & BGRND) {
555				opflags &= ~BGRND;
556				if (i = fork()) {
557					if (i == -1)
558						err(1, "nqnfs 2");
559					exit(0);
560				}
561				(void) setsid();
562				(void) close(STDIN_FILENO);
563				(void) close(STDOUT_FILENO);
564				(void) close(STDERR_FILENO);
565				(void) chdir("/");
566				opflags |= ISBGRND;
567			}
568			sleep(60);
569		}
570	}
571	if (nfhret.stat) {
572		if (opflags & ISBGRND)
573			exit(1);
574		errno = nfhret.stat;
575		warn("can't access %s", spec);
576		return (0);
577	}
578	saddr.sin_port = htons(tport);
579#ifdef ISO
580	if (isoflag) {
581		nfsargsp->addr = (struct sockaddr *) &isoaddr;
582		nfsargsp->addrlen = sizeof (isoaddr);
583	} else
584#endif /* ISO */
585	{
586		nfsargsp->addr = (struct sockaddr *) &saddr;
587		nfsargsp->addrlen = sizeof (saddr);
588	}
589	nfsargsp->fh = &nfhret.nfh;
590	nfsargsp->hostname = nam;
591	return (1);
592}
593
594/*
595 * xdr routines for mount rpc's
596 */
597int
598xdr_dir(xdrsp, dirp)
599	XDR *xdrsp;
600	char *dirp;
601{
602	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
603}
604
605int
606xdr_fh(xdrsp, np)
607	XDR *xdrsp;
608	struct nfhret *np;
609{
610	if (!xdr_u_long(xdrsp, &(np->stat)))
611		return (0);
612	if (np->stat)
613		return (1);
614	return (xdr_opaque(xdrsp, (caddr_t)&(np->nfh), NFSX_FH));
615}
616
617__dead void
618usage()
619{
620	(void)fprintf(stderr, "usage: mount_nfs %s\n%s\n%s\n%s\n",
621"[-bcdiKklMPqsT] [-a maxreadahead] [-D deadthresh]",
622"\t[-g maxgroups] [-L leaseterm] [-m realm] [-o options] [-R retrycnt]",
623"\t[-r readsize] [-t timeout] [-w writesize] [-x retrans]",
624"\trhost:path node");
625	exit(1);
626}
627