mount_nfs.c revision 1.10 1 /* $NetBSD: mount_nfs.c,v 1.10 1995/05/21 15:17:13 mycroft Exp $ */
2
3 /*
4 * Copyright (c) 1992, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #ifndef lint
40 static char copyright[] =
41 "@(#) Copyright (c) 1992, 1993, 1994\n\
42 The Regents of the University of California. All rights reserved.\n";
43 #endif /* not lint */
44
45 #ifndef lint
46 #if 0
47 static char sccsid[] = "@(#)mount_nfs.c 8.3 (Berkeley) 3/27/94";
48 #else
49 static char rcsid[] = "$NetBSD: mount_nfs.c,v 1.10 1995/05/21 15:17:13 mycroft Exp $";
50 #endif
51 #endif /* not lint */
52
53 #include <sys/param.h>
54 #include <sys/mount.h>
55 #include <sys/socket.h>
56 #include <sys/socketvar.h>
57 #include <sys/stat.h>
58 #include <syslog.h>
59
60 #include <rpc/rpc.h>
61 #include <rpc/pmap_clnt.h>
62 #include <rpc/pmap_prot.h>
63
64 #ifdef ISO
65 #include <netiso/iso.h>
66 #endif
67
68 #ifdef KERBEROS
69 #include <kerberosIV/des.h>
70 #include <kerberosIV/krb.h>
71 #endif
72
73 #include <nfs/rpcv2.h>
74 #include <nfs/nfsv2.h>
75 #define _KERNEL
76 #include <nfs/nfs.h>
77 #undef _KERNEL
78 #include <nfs/nqnfs.h>
79
80 #include <arpa/inet.h>
81
82 #include <ctype.h>
83 #include <err.h>
84 #include <errno.h>
85 #include <fcntl.h>
86 #include <netdb.h>
87 #include <signal.h>
88 #include <stdio.h>
89 #include <stdlib.h>
90 #include <strings.h>
91 #include <unistd.h>
92
93 #include "mntopts.h"
94
95 struct mntopt mopts[] = {
96 MOPT_STDOPTS,
97 MOPT_FORCE,
98 MOPT_UPDATE,
99 { NULL }
100 };
101
102 struct nfs_args nfsdefargs = {
103 (struct sockaddr *)0,
104 sizeof (struct sockaddr_in),
105 SOCK_DGRAM,
106 0,
107 (nfsv2fh_t *)0,
108 0,
109 NFS_WSIZE,
110 NFS_RSIZE,
111 NFS_TIMEO,
112 NFS_RETRANS,
113 NFS_MAXGRPS,
114 NFS_DEFRAHEAD,
115 NQ_DEFLEASE,
116 NQ_DEADTHRESH,
117 (char *)0,
118 };
119
120 struct nfhret {
121 u_long stat;
122 nfsv2fh_t nfh;
123 };
124 #define DEF_RETRY 10000
125 #define BGRND 1
126 #define ISBGRND 2
127 int retrycnt = DEF_RETRY;
128 int opflags = 0;
129
130 #ifdef KERBEROS
131 char inst[INST_SZ];
132 char realm[REALM_SZ];
133 KTEXT_ST kt;
134 #endif
135
136 int getnfsargs __P((char *, struct nfs_args *));
137 #ifdef ISO
138 struct iso_addr *iso_addr __P((const char *));
139 #endif
140 void set_rpc_maxgrouplist __P((int));
141 __dead void usage __P((void));
142 int xdr_dir __P((XDR *, char *));
143 int xdr_fh __P((XDR *, struct nfhret *));
144
145 int
146 main(argc, argv)
147 int argc;
148 char *argv[];
149 {
150 register int c;
151 register struct nfs_args *nfsargsp;
152 struct nfs_args nfsargs;
153 struct nfsd_cargs ncd;
154 int mntflags, i, nfssvc_flag, num;
155 char *name, *p, *spec;
156 int error = 0;
157 #ifdef KERBEROS
158 uid_t last_ruid;
159 #endif
160
161 #ifdef KERBEROS
162 last_ruid = -1;
163 if (krb_get_lrealm(realm, 0) != KSUCCESS)
164 (void)strcpy(realm, KRB_REALM);
165 #endif
166 retrycnt = DEF_RETRY;
167
168 mntflags = 0;
169 nfsargs = nfsdefargs;
170 nfsargsp = &nfsargs;
171 while ((c = getopt(argc, argv,
172 "a:bcdD:g:iKklL:Mm:o:PpqR:r:sTt:w:x:")) != EOF)
173 switch (c) {
174 case 'a':
175 num = strtol(optarg, &p, 10);
176 if (*p || num < 0)
177 errx(1, "illegal -a value -- %s", optarg);
178 nfsargsp->readahead = num;
179 nfsargsp->flags |= NFSMNT_READAHEAD;
180 break;
181 case 'b':
182 opflags |= BGRND;
183 break;
184 case 'c':
185 nfsargsp->flags |= NFSMNT_NOCONN;
186 break;
187 case 'D':
188 num = strtol(optarg, &p, 10);
189 if (*p || num <= 0)
190 errx(1, "illegal -D value -- %s", optarg);
191 nfsargsp->deadthresh = num;
192 nfsargsp->flags |= NFSMNT_DEADTHRESH;
193 break;
194 case 'd':
195 nfsargsp->flags |= NFSMNT_DUMBTIMR;
196 break;
197 #if 0 /* XXXX */
198 case 'g':
199 num = strtol(optarg, &p, 10);
200 if (*p || num <= 0)
201 errx(1, "illegal -g value -- %s", optarg);
202 set_rpc_maxgrouplist(num);
203 nfsargsp->maxgrouplist = num;
204 nfsargsp->flags |= NFSMNT_MAXGRPS;
205 break;
206 #endif
207 case 'i':
208 nfsargsp->flags |= NFSMNT_INT;
209 break;
210 #ifdef KERBEROS
211 case 'K':
212 nfsargsp->flags |= NFSMNT_KERB;
213 break;
214 #endif
215 case 'k':
216 nfsargsp->flags |= NFSMNT_NQLOOKLEASE;
217 break;
218 case 'L':
219 num = strtol(optarg, &p, 10);
220 if (*p || num < 2)
221 errx(1, "illegal -L value -- %s", optarg);
222 nfsargsp->leaseterm = num;
223 nfsargsp->flags |= NFSMNT_LEASETERM;
224 break;
225 case 'l':
226 nfsargsp->flags |= NFSMNT_RDIRALOOK;
227 break;
228 case 'M':
229 nfsargsp->flags |= NFSMNT_MYWRITE;
230 break;
231 #ifdef KERBEROS
232 case 'm':
233 (void)strncpy(realm, optarg, REALM_SZ - 1);
234 realm[REALM_SZ - 1] = '\0';
235 break;
236 #endif
237 case 'o':
238 getmntopts(optarg, mopts, &mntflags);
239 break;
240 case 'P':
241 nfsargsp->flags |= NFSMNT_RESVPORT;
242 break;
243 #ifdef ISO
244 case 'p':
245 nfsargsp->sotype = SOCK_SEQPACKET;
246 break;
247 #endif
248 case 'q':
249 nfsargsp->flags |= NFSMNT_NQNFS;
250 break;
251 case 'R':
252 num = strtol(optarg, &p, 10);
253 if (*p || num <= 0)
254 errx(1, "illegal -R value -- %s", optarg);
255 retrycnt = num;
256 break;
257 case 'r':
258 num = strtol(optarg, &p, 10);
259 if (*p || num <= 0)
260 errx(1, "illegal -r value -- %s", optarg);
261 nfsargsp->rsize = num;
262 nfsargsp->flags |= NFSMNT_RSIZE;
263 break;
264 case 's':
265 nfsargsp->flags |= NFSMNT_SOFT;
266 break;
267 case 'T':
268 nfsargsp->sotype = SOCK_STREAM;
269 break;
270 case 't':
271 num = strtol(optarg, &p, 10);
272 if (*p || num <= 0)
273 errx(1, "illegal -t value -- %s", optarg);
274 nfsargsp->timeo = num;
275 nfsargsp->flags |= NFSMNT_TIMEO;
276 break;
277 case 'w':
278 num = strtol(optarg, &p, 10);
279 if (*p || num <= 0)
280 errx(1, "illegal -w value -- %s", optarg);
281 nfsargsp->wsize = num;
282 nfsargsp->flags |= NFSMNT_WSIZE;
283 break;
284 case 'x':
285 num = strtol(optarg, &p, 10);
286 if (*p || num <= 0)
287 errx(1, "illegal -x value -- %s", optarg);
288 nfsargsp->retrans = num;
289 nfsargsp->flags |= NFSMNT_RETRANS;
290 break;
291 default:
292 usage();
293 break;
294 }
295 argc -= optind;
296 argv += optind;
297
298 if (argc != 2)
299 usage();
300
301 spec = *argv++;
302 name = *argv;
303
304 if (!getnfsargs(spec, nfsargsp))
305 exit(1);
306 if (mount(MOUNT_NFS, name, mntflags, nfsargsp))
307 err(1, "%s", name);
308 if (nfsargsp->flags & (NFSMNT_NQNFS | NFSMNT_KERB)) {
309 if ((opflags & ISBGRND) == 0) {
310 if (i = fork()) {
311 if (i == -1)
312 err(1, "nqnfs 1");
313 exit(0);
314 }
315 (void) setsid();
316 (void) close(STDIN_FILENO);
317 (void) close(STDOUT_FILENO);
318 (void) close(STDERR_FILENO);
319 (void) chdir("/");
320 }
321 openlog("mount_nfs:", LOG_PID, LOG_DAEMON);
322 nfssvc_flag = NFSSVC_MNTD;
323 ncd.ncd_dirp = name;
324 while (nfssvc(nfssvc_flag, (caddr_t)&ncd) < 0) {
325 if (errno != ENEEDAUTH) {
326 syslog(LOG_ERR, "nfssvc err %m");
327 continue;
328 }
329 nfssvc_flag =
330 NFSSVC_MNTD | NFSSVC_GOTAUTH | NFSSVC_AUTHINFAIL;
331 #ifdef KERBEROS
332 /*
333 * Set up as ncd_authuid for the kerberos call.
334 * Must set ruid to ncd_authuid and reset the
335 * ticket name iff ncd_authuid is not the same
336 * as last time, so that the right ticket file
337 * is found.
338 */
339 if (ncd.ncd_authuid != last_ruid) {
340 krb_set_tkt_string("");
341 last_ruid = ncd.ncd_authuid;
342 }
343 setreuid(ncd.ncd_authuid, 0);
344 if (krb_mk_req(&kt, "rcmd", inst, realm, 0) ==
345 KSUCCESS &&
346 kt.length <= (RPCAUTH_MAXSIZ - 2 * NFSX_UNSIGNED)) {
347 ncd.ncd_authtype = RPCAUTH_NQNFS;
348 ncd.ncd_authlen = kt.length;
349 ncd.ncd_authstr = (char *)kt.dat;
350 nfssvc_flag = NFSSVC_MNTD | NFSSVC_GOTAUTH;
351 }
352 setreuid(0, 0);
353 #endif /* KERBEROS */
354 }
355 }
356 exit(0);
357 }
358
359 int
360 getnfsargs(spec, nfsargsp)
361 char *spec;
362 struct nfs_args *nfsargsp;
363 {
364 register CLIENT *clp;
365 struct hostent *hp;
366 static struct sockaddr_in saddr;
367 #ifdef ISO
368 static struct sockaddr_iso isoaddr;
369 struct iso_addr *isop;
370 int isoflag = 0;
371 #endif
372 struct timeval pertry, try;
373 enum clnt_stat clnt_stat;
374 int so = RPC_ANYSOCK, i;
375 char *hostp, *delimp;
376 #ifdef KERBEROS
377 char *cp;
378 #endif
379 u_short tport;
380 static struct nfhret nfhret;
381 static char nam[MNAMELEN + 1];
382
383 strncpy(nam, spec, MNAMELEN);
384 nam[MNAMELEN] = '\0';
385 if ((delimp = strchr(spec, '@')) != NULL) {
386 hostp = delimp + 1;
387 } else if ((delimp = strchr(spec, ':')) != NULL) {
388 hostp = spec;
389 spec = delimp + 1;
390 } else {
391 warnx("no <host>:<dirpath> or <dirpath>@<host> spec");
392 return (0);
393 }
394 *delimp = '\0';
395 /*
396 * DUMB!! Until the mount protocol works on iso transport, we must
397 * supply both an iso and an inet address for the host.
398 */
399 #ifdef ISO
400 if (!strncmp(hostp, "iso=", 4)) {
401 u_short isoport;
402
403 hostp += 4;
404 isoflag++;
405 if ((delimp = strchr(hostp, '+')) == NULL) {
406 warnx("no iso+inet address");
407 return (0);
408 }
409 *delimp = '\0';
410 if ((isop = iso_addr(hostp)) == NULL) {
411 warnx("bad ISO address");
412 return (0);
413 }
414 memset(&isoaddr, 0, sizeof (isoaddr));
415 memcpy(&isoaddr.siso_addr, isop, sizeof (struct iso_addr));
416 isoaddr.siso_len = sizeof (isoaddr);
417 isoaddr.siso_family = AF_ISO;
418 isoaddr.siso_tlen = 2;
419 isoport = htons(NFS_PORT);
420 memcpy(TSEL(&isoaddr), &isoport, isoaddr.siso_tlen);
421 hostp = delimp + 1;
422 }
423 #endif /* ISO */
424
425 /*
426 * Handle an internet host address and reverse resolve it if
427 * doing Kerberos.
428 */
429 if (inet_aton(hostp, &saddr.sin_addr) != 0) {
430 if ((nfsargsp->flags & NFSMNT_KERB)) {
431 if ((hp = gethostbyaddr((char *)&saddr.sin_addr.s_addr,
432 sizeof (u_long), AF_INET)) == (struct hostent *)0) {
433 warnx("can't reverse resolve net address");
434 return (0);
435 }
436 }
437 } else {
438 hp = gethostbyname(hostp);
439 if (hp == NULL) {
440 warnx("can't get net id for host");
441 return (0);
442 }
443 memcpy(&saddr.sin_addr, hp->h_addr, hp->h_length);
444 }
445 #ifdef KERBEROS
446 if (nfsargsp->flags & NFSMNT_KERB) {
447 strncpy(inst, hp->h_name, INST_SZ);
448 inst[INST_SZ - 1] = '\0';
449 if (cp = strchr(inst, '.'))
450 *cp = '\0';
451 }
452 #endif /* KERBEROS */
453
454 nfhret.stat = EACCES; /* Mark not yet successful */
455 while (retrycnt > 0) {
456 saddr.sin_family = AF_INET;
457 saddr.sin_port = htons(PMAPPORT);
458 if ((tport = pmap_getport(&saddr, RPCPROG_NFS,
459 NFS_VER2, nfsargsp->sotype == SOCK_STREAM ? IPPROTO_TCP :
460 IPPROTO_UDP)) == 0) {
461 if ((opflags & ISBGRND) == 0)
462 clnt_pcreateerror("NFS Portmap");
463 } else {
464 saddr.sin_port = 0;
465 pertry.tv_sec = 10;
466 pertry.tv_usec = 0;
467 if ((clp = (nfsargsp->sotype == SOCK_STREAM ?
468 clnttcp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1,
469 &so, 0, 0) :
470 clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1,
471 pertry, &so))) == NULL) {
472 if ((opflags & ISBGRND) == 0)
473 clnt_pcreateerror("Cannot MNT PRC");
474 } else {
475 clp->cl_auth = authunix_create_default();
476 try.tv_sec = 10;
477 try.tv_usec = 0;
478 clnt_stat = clnt_call(clp, RPCMNT_MOUNT,
479 xdr_dir, spec, xdr_fh, &nfhret, try);
480 if (clnt_stat != RPC_SUCCESS) {
481 if ((opflags & ISBGRND) == 0)
482 warnx("%s", clnt_sperror(clp,
483 "bad MNT RPC"));
484 } else {
485 auth_destroy(clp->cl_auth);
486 clnt_destroy(clp);
487 retrycnt = 0;
488 }
489 }
490 }
491 if (--retrycnt > 0) {
492 if (opflags & BGRND) {
493 opflags &= ~BGRND;
494 if (i = fork()) {
495 if (i == -1)
496 err(1, "nqnfs 2");
497 exit(0);
498 }
499 (void) setsid();
500 (void) close(STDIN_FILENO);
501 (void) close(STDOUT_FILENO);
502 (void) close(STDERR_FILENO);
503 (void) chdir("/");
504 opflags |= ISBGRND;
505 }
506 sleep(60);
507 }
508 }
509 if (nfhret.stat) {
510 if (opflags & ISBGRND)
511 exit(1);
512 errno = nfhret.stat;
513 warn("can't access %s", spec);
514 return (0);
515 }
516 saddr.sin_port = htons(tport);
517 #ifdef ISO
518 if (isoflag) {
519 nfsargsp->addr = (struct sockaddr *) &isoaddr;
520 nfsargsp->addrlen = sizeof (isoaddr);
521 } else
522 #endif /* ISO */
523 {
524 nfsargsp->addr = (struct sockaddr *) &saddr;
525 nfsargsp->addrlen = sizeof (saddr);
526 }
527 nfsargsp->fh = &nfhret.nfh;
528 nfsargsp->hostname = nam;
529 return (1);
530 }
531
532 /*
533 * xdr routines for mount rpc's
534 */
535 int
536 xdr_dir(xdrsp, dirp)
537 XDR *xdrsp;
538 char *dirp;
539 {
540 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
541 }
542
543 int
544 xdr_fh(xdrsp, np)
545 XDR *xdrsp;
546 struct nfhret *np;
547 {
548 if (!xdr_u_long(xdrsp, &(np->stat)))
549 return (0);
550 if (np->stat)
551 return (1);
552 return (xdr_opaque(xdrsp, (caddr_t)&(np->nfh), NFSX_FH));
553 }
554
555 __dead void
556 usage()
557 {
558 (void)fprintf(stderr, "usage: mount_nfs %s\n%s\n%s\n%s\n",
559 "[-bcdiKklMPqsT] [-a maxreadahead] [-D deadthresh]",
560 "\t[-g maxgroups] [-L leaseterm] [-m realm] [-o options] [-R retrycnt]",
561 "\t[-r readsize] [-t timeout] [-w writesize] [-x retrans]",
562 "\trhost:path node");
563 exit(1);
564 }
565