Rick Macklem notes that NFS should get MNT_RDONLY and MNT_UPDATE
[unix-history] / usr / src / sbin / mount_nfs / mount_nfs.c
CommitLineData
c882a0dc 1/*
79ae9f1e 2 * Copyright (c) 1992, 1993, 1994
1ca341e6 3 * The Regents of the University of California. All rights reserved.
c882a0dc
KM
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
1ca341e6 12static char copyright[] =
79ae9f1e 13"@(#) Copyright (c) 1992, 1993, 1994\n\
1ca341e6 14 The Regents of the University of California. All rights reserved.\n";
c882a0dc
KM
15#endif /* not lint */
16
17#ifndef lint
d56c93e6 18static char sccsid[] = "@(#)mount_nfs.c 8.3 (Berkeley) %G%";
c882a0dc
KM
19#endif /* not lint */
20
c882a0dc 21#include <sys/param.h>
c882a0dc
KM
22#include <sys/mount.h>
23#include <sys/socket.h>
24#include <sys/socketvar.h>
5c60eb94
KB
25#include <sys/stat.h>
26#include <sys/syslog.h>
27
c882a0dc
KM
28#include <rpc/rpc.h>
29#include <rpc/pmap_clnt.h>
30#include <rpc/pmap_prot.h>
5c60eb94 31
c882a0dc
KM
32#ifdef ISO
33#include <netiso/iso.h>
34#endif
5c60eb94 35
c882a0dc 36#ifdef KERBEROS
dbbed105 37#include <kerberosIV/des.h>
c882a0dc
KM
38#include <kerberosIV/krb.h>
39#endif
5c60eb94 40
c882a0dc
KM
41#include <nfs/rpcv2.h>
42#include <nfs/nfsv2.h>
5c60eb94 43#define KERNEL
c882a0dc 44#include <nfs/nfs.h>
5c60eb94 45#undef KERNEL
c882a0dc
KM
46#include <nfs/nqnfs.h>
47
5c60eb94
KB
48#include <arpa/inet.h>
49
50#include <ctype.h>
79ae9f1e 51#include <err.h>
5c60eb94
KB
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
79ae9f1e
KB
61#include "mntopts.h"
62
79ae9f1e
KB
63struct mntopt mopts[] = {
64 MOPT_STDOPTS,
79ae9f1e 65 MOPT_FORCE,
79ae9f1e
KB
66 MOPT_UPDATE,
67 { NULL }
68};
69
c882a0dc
KM
70struct 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
88struct nfhret {
89 u_long stat;
90 nfsv2fh_t nfh;
91};
92#define DEF_RETRY 10000
93#define BGRND 1
94#define ISBGRND 2
95int retrycnt = DEF_RETRY;
96int opflags = 0;
c882a0dc
KM
97
98#ifdef KERBEROS
99char inst[INST_SZ];
100char realm[REALM_SZ];
101KTEXT_ST kt;
102#endif
103
5c60eb94
KB
104int getnfsargs __P((char *, struct nfs_args *));
105#ifdef ISO
106struct iso_addr *iso_addr __P((const char *));
107#endif
108void set_rpc_maxgrouplist __P((int));
109__dead void usage __P((void));
5c60eb94
KB
110int xdr_dir __P((XDR *, char *));
111int xdr_fh __P((XDR *, struct nfhret *));
112
113int
114main(argc, argv)
c882a0dc 115 int argc;
5c60eb94 116 char *argv[];
c882a0dc 117{
c882a0dc 118 register int c;
5c60eb94
KB
119 register struct nfs_args *nfsargsp;
120 struct nfs_args nfsargs;
c882a0dc 121 struct nfsd_cargs ncd;
79ae9f1e 122 int mntflags, i, nfssvc_flag, num;
5c60eb94 123 char *name, *p, *spec;
79ae9f1e 124 int error = 0;
5c60eb94
KB
125#ifdef KERBEROS
126 uid_t last_ruid;
127#endif
c882a0dc
KM
128
129#ifdef KERBEROS
5c60eb94
KB
130 last_ruid = -1;
131 (void)strcpy(realm, KRB_REALM);
c882a0dc 132#endif
c882a0dc 133 retrycnt = DEF_RETRY;
5c60eb94 134
79ae9f1e 135 mntflags = 0;
5c60eb94
KB
136 nfsargs = nfsdefargs;
137 nfsargsp = &nfsargs;
138 while ((c = getopt(argc, argv,
79ae9f1e 139 "a:bcdD:g:iKklL:Mm:o:PpqR:r:sTt:w:x:")) != EOF)
c882a0dc 140 switch (c) {
5c60eb94
KB
141 case 'a':
142 num = strtol(optarg, &p, 10);
143 if (*p || num < 0)
79ae9f1e 144 errx(1, "illegal -a value -- %s", optarg);
5c60eb94
KB
145 nfsargsp->readahead = num;
146 nfsargsp->flags |= NFSMNT_READAHEAD;
147 break;
c882a0dc
KM
148 case 'b':
149 opflags |= BGRND;
150 break;
5c60eb94
KB
151 case 'c':
152 nfsargsp->flags |= NFSMNT_NOCONN;
153 break;
154 case 'D':
155 num = strtol(optarg, &p, 10);
156 if (*p || num <= 0)
79ae9f1e 157 errx(1, "illegal -D value -- %s", optarg);
5c60eb94
KB
158 nfsargsp->deadthresh = num;
159 nfsargsp->flags |= NFSMNT_DEADTHRESH;
160 break;
161 case 'd':
162 nfsargsp->flags |= NFSMNT_DUMBTIMR;
163 break;
5c60eb94
KB
164 case 'g':
165 num = strtol(optarg, &p, 10);
efdcf411 166 if (*p || num <= 0)
79ae9f1e 167 errx(1, "illegal -g value -- %s", optarg);
5c60eb94
KB
168 set_rpc_maxgrouplist(num);
169 nfsargsp->maxgrouplist = num;
170 nfsargsp->flags |= NFSMNT_MAXGRPS;
c882a0dc
KM
171 break;
172 case 'i':
173 nfsargsp->flags |= NFSMNT_INT;
174 break;
5c60eb94
KB
175#ifdef KERBEROS
176 case 'K':
177 nfsargsp->flags |= NFSMNT_KERB;
c882a0dc
KM
178 break;
179#endif
5c60eb94
KB
180 case 'k':
181 nfsargsp->flags |= NFSMNT_NQLOOKLEASE;
182 break;
183 case 'L':
184 num = strtol(optarg, &p, 10);
185 if (*p || num < 2)
79ae9f1e 186 errx(1, "illegal -L value -- %s", optarg);
5c60eb94
KB
187 nfsargsp->leaseterm = num;
188 nfsargsp->flags |= NFSMNT_LEASETERM;
c882a0dc
KM
189 break;
190 case 'l':
191 nfsargsp->flags |= NFSMNT_RDIRALOOK;
192 break;
5c60eb94
KB
193 case 'M':
194 nfsargsp->flags |= NFSMNT_MYWRITE;
c882a0dc 195 break;
5c60eb94
KB
196#ifdef KERBEROS
197 case 'm':
198 (void)strncpy(realm, optarg, REALM_SZ - 1);
199 realm[REALM_SZ - 1] = '\0';
c882a0dc 200 break;
5c60eb94 201#endif
79ae9f1e
KB
202 case 'o':
203 getmntopts(optarg, mopts, &mntflags);
204 break;
2bb04e15
KM
205 case 'P':
206 nfsargsp->flags |= NFSMNT_RESVPORT;
207 break;
5c60eb94
KB
208#ifdef ISO
209 case 'p':
210 nfsargsp->sotype = SOCK_SEQPACKET;
211 break;
212#endif
213 case 'q':
214 nfsargsp->flags |= NFSMNT_NQNFS;
c882a0dc
KM
215 break;
216 case 'R':
5c60eb94
KB
217 num = strtol(optarg, &p, 10);
218 if (*p || num <= 0)
79ae9f1e 219 errx(1, "illegal -R value -- %s", optarg);
5c60eb94 220 retrycnt = num;
c882a0dc
KM
221 break;
222 case 'r':
5c60eb94
KB
223 num = strtol(optarg, &p, 10);
224 if (*p || num <= 0)
79ae9f1e 225 errx(1, "illegal -r value -- %s", optarg);
5c60eb94
KB
226 nfsargsp->rsize = num;
227 nfsargsp->flags |= NFSMNT_RSIZE;
c882a0dc 228 break;
5c60eb94
KB
229 case 's':
230 nfsargsp->flags |= NFSMNT_SOFT;
c882a0dc 231 break;
5c60eb94
KB
232 case 'T':
233 nfsargsp->sotype = SOCK_STREAM;
c882a0dc 234 break;
5c60eb94
KB
235 case 't':
236 num = strtol(optarg, &p, 10);
237 if (*p || num <= 0)
79ae9f1e 238 errx(1, "illegal -t value -- %s", optarg);
5c60eb94
KB
239 nfsargsp->timeo = num;
240 nfsargsp->flags |= NFSMNT_TIMEO;
c882a0dc 241 break;
5c60eb94
KB
242 case 'w':
243 num = strtol(optarg, &p, 10);
244 if (*p || num <= 0)
79ae9f1e 245 errx(1, "illegal -w value -- %s", optarg);
5c60eb94
KB
246 nfsargsp->wsize = num;
247 nfsargsp->flags |= NFSMNT_WSIZE;
c882a0dc 248 break;
5c60eb94
KB
249 case 'x':
250 num = strtol(optarg, &p, 10);
251 if (*p || num <= 0)
79ae9f1e 252 errx(1, "illegal -x value -- %s", optarg);
5c60eb94
KB
253 nfsargsp->retrans = num;
254 nfsargsp->flags |= NFSMNT_RETRANS;
c882a0dc 255 break;
c882a0dc 256 default:
5c60eb94 257 usage();
79ae9f1e
KB
258 break;
259 }
260 argc -= optind;
261 argv += optind;
5c60eb94 262
79ae9f1e
KB
263 if (argc != 2)
264 error = 1;
5c60eb94 265
79ae9f1e
KB
266 spec = *argv++;
267 name = *argv;
5c60eb94
KB
268
269 if (!getnfsargs(spec, nfsargsp))
270 exit(1);
79ae9f1e
KB
271 if (mount(MOUNT_NFS, name, mntflags, nfsargsp))
272 err(1, "%s", name);
5c60eb94
KB
273 if (nfsargsp->flags & (NFSMNT_NQNFS | NFSMNT_KERB)) {
274 if ((opflags & ISBGRND) == 0) {
275 if (i = fork()) {
276 if (i == -1)
79ae9f1e 277 err(1, "nqnfs 1");
5c60eb94
KB
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;
c882a0dc 293 }
5c60eb94
KB
294 nfssvc_flag =
295 NFSSVC_MNTD | NFSSVC_GOTAUTH | NFSSVC_AUTHINFAIL;
c882a0dc 296#ifdef KERBEROS
5c60eb94
KB
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)) {
5c60eb94
KB
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;
c882a0dc 316 }
5c60eb94 317 setreuid(0, 0);
5c60eb94 318#endif /* KERBEROS */
c882a0dc 319 }
5c60eb94
KB
320 }
321 exit(0);
c882a0dc
KM
322}
323
5c60eb94 324int
c882a0dc
KM
325getnfsargs(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;
5c60eb94 335 int isoflag = 0;
c882a0dc
KM
336#endif
337 struct timeval pertry, try;
338 enum clnt_stat clnt_stat;
5c60eb94
KB
339 int so = RPC_ANYSOCK, i;
340 char *hostp, *delimp;
341#ifdef KERBEROS
342 char *cp;
343#endif
c882a0dc
KM
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';
79ae9f1e 350 if ((delimp = strchr(spec, '@')) != NULL) {
c882a0dc 351 hostp = delimp + 1;
79ae9f1e 352 } else if ((delimp = strchr(spec, ':')) != NULL) {
c882a0dc
KM
353 hostp = spec;
354 spec = delimp + 1;
355 } else {
79ae9f1e 356 warnx("no <host>:<dirpath> or <dirpath>@<host> spec");
c882a0dc
KM
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++;
79ae9f1e
KB
370 if ((delimp = strchr(hostp, '+')) == NULL) {
371 warnx("no iso+inet address");
c882a0dc
KM
372 return (0);
373 }
374 *delimp = '\0';
375 if ((isop = iso_addr(hostp)) == NULL) {
79ae9f1e 376 warnx("bad ISO address");
c882a0dc
KM
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) {
79ae9f1e 397 warnx("bad net address %s", hostp);
c882a0dc
KM
398 return (0);
399 }
400 if ((nfsargsp->flags & NFSMNT_KERB) &&
401 (hp = gethostbyaddr((char *)&saddr.sin_addr.s_addr,
5c60eb94 402 sizeof (u_long), AF_INET)) == (struct hostent *)0) {
79ae9f1e 403 warnx("can't reverse resolve net address");
c882a0dc
KM
404 return (0);
405 }
406 } else if ((hp = gethostbyname(hostp)) == NULL) {
79ae9f1e 407 warnx("can't get net id for host");
c882a0dc
KM
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';
79ae9f1e 414 if (cp = strchr(inst, '.'))
c882a0dc
KM
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, IPPROTO_UDP)) == 0) {
426 if ((opflags & ISBGRND) == 0)
427 clnt_pcreateerror("NFS Portmap");
428 } else {
429 saddr.sin_port = 0;
430 pertry.tv_sec = 10;
431 pertry.tv_usec = 0;
432 if ((clp = clntudp_create(&saddr, RPCPROG_MNT,
433 RPCMNT_VER1, pertry, &so)) == NULL) {
434 if ((opflags & ISBGRND) == 0)
435 clnt_pcreateerror("Cannot MNT PRC");
436 } else {
437 clp->cl_auth = authunix_create_default();
438 try.tv_sec = 10;
439 try.tv_usec = 0;
440 clnt_stat = clnt_call(clp, RPCMNT_MOUNT,
441 xdr_dir, spec, xdr_fh, &nfhret, try);
442 if (clnt_stat != RPC_SUCCESS) {
79ae9f1e
KB
443 if ((opflags & ISBGRND) == 0)
444 warnx("%s", clnt_sperror(clp,
5c60eb94 445 "bad MNT RPC"));
c882a0dc
KM
446 } else {
447 auth_destroy(clp->cl_auth);
448 clnt_destroy(clp);
449 retrycnt = 0;
450 }
451 }
452 }
453 if (--retrycnt > 0) {
454 if (opflags & BGRND) {
455 opflags &= ~BGRND;
456 if (i = fork()) {
5c60eb94 457 if (i == -1)
79ae9f1e 458 err(1, "nqnfs 2");
7cd40046 459 exit(0);
c882a0dc
KM
460 }
461 (void) setsid();
5c60eb94
KB
462 (void) close(STDIN_FILENO);
463 (void) close(STDOUT_FILENO);
464 (void) close(STDERR_FILENO);
c882a0dc
KM
465 (void) chdir("/");
466 opflags |= ISBGRND;
5c60eb94 467 }
c882a0dc
KM
468 sleep(60);
469 }
470 }
471 if (nfhret.stat) {
472 if (opflags & ISBGRND)
473 exit(1);
79ae9f1e 474 warn("can't access %s", spec);
c882a0dc
KM
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 */
5c60eb94 496int
c882a0dc
KM
497xdr_dir(xdrsp, dirp)
498 XDR *xdrsp;
499 char *dirp;
500{
501 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
502}
503
5c60eb94 504int
c882a0dc
KM
505xdr_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
5c60eb94
KB
516__dead void
517usage()
c882a0dc 518{
5c60eb94
KB
519 (void)fprintf(stderr, "usage: mount_nfs %s\n%s\n%s\n%s\n",
520"[-bcdiKklMPqsT] [-a maxreadahead] [-D deadthresh]",
79ae9f1e 521"\t[-g maxgroups] [-L leaseterm] [-m realm] [-o options] [-R retrycnt]",
5c60eb94
KB
522"\t[-r readsize] [-t timeout] [-w writesize] [-x retrans]",
523"\trhost:path node");
524 exit(1);
525}