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