mountd.c revision 1.11 1 /*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * 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 char copyright[] =
39 "@(#) Copyright (c) 1989 Regents of the University of California.\n\
40 All rights reserved.\n";
41 #endif not lint
42
43 #ifndef lint
44 /*static char sccsid[] = "from: @(#)mountd.c 5.14 (Berkeley) 2/26/91";*/
45 static char rcsid[] = "$Id: mountd.c,v 1.11 1994/01/06 22:48:51 ws Exp $";
46 #endif not lint
47
48 #include <sys/param.h>
49 #include <sys/ioctl.h>
50 #include <sys/stat.h>
51 #include <sys/file.h>
52 #include <sys/mount.h>
53 #include <sys/socket.h>
54 #include <sys/errno.h>
55 #include <sys/signal.h>
56 #include <stdio.h>
57 #include <string.h>
58 #include <syslog.h>
59 #include <netdb.h>
60 #include <rpc/rpc.h>
61 #include <rpc/pmap_clnt.h>
62 #include <rpc/pmap_prot.h>
63 #include <nfs/nfsv2.h>
64 #include <rpcsvc/mount.h>
65 #include "pathnames.h"
66
67 struct ufid {
68 u_short ufid_len;
69 ino_t ufid_ino;
70 long ufid_gen;
71 };
72 /*
73 * Structures for keeping the mount list and export list
74 */
75 struct mountlist {
76 struct mountlist *ml_next;
77 char ml_host[MNTNAMLEN+1];
78 char ml_dirp[MNTPATHLEN+1];
79 };
80
81 struct exportlist {
82 struct exportlist *ex_next;
83 struct exportlist *ex_prev;
84 struct grouplist *ex_groups;
85 int ex_rootuid;
86 int ex_exflags;
87 int ex_alldirflg;
88 dev_t ex_dev;
89 char ex_dirp[MNTPATHLEN+1];
90 };
91
92 struct grouplist {
93 struct grouplist *gr_next;
94 struct hostent *gr_hp;
95 };
96
97 /* Global defs */
98 void mntsrv();
99 int umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
100 void add_mlist(), del_mlist(), get_exportlist(), get_mountlist();
101 void send_umntall();
102 struct exportlist exphead;
103 struct mountlist *mlhead;
104 char exname[MAXPATHLEN];
105 int def_rootuid = -2;
106 int root_only = 1;
107 extern int errno;
108
109 /*
110 * Mountd server for NFS mount protocol as described in:
111 * NFS: Network File System Protocol Specification, RFC1094, Appendix A
112 * The optional arguments are the exports file name
113 * default: _PATH_EXPORTS
114 * and "-n" to allow nonroot mount.
115 */
116 main(argc, argv)
117 int argc;
118 char **argv;
119 {
120 FILE *pidfile;
121 extern int optind;
122 extern char *optarg;
123 SVCXPRT *transp;
124 int c;
125 int sock = 0;
126 int proto = 0;
127 int from_inetd = 1;
128 struct sockaddr_in from;
129 int fromlen;
130
131 while ((c = getopt(argc, argv, "n")) != EOF)
132 switch (c) {
133 case 'n':
134 root_only = 0;
135 break;
136 default:
137 fprintf(stderr, "Usage: mountd [-n] [export_file]\n");
138 exit(1);
139 };
140 argc -= optind;
141 argv += optind;
142
143 exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
144 mlhead = (struct mountlist *)0;
145
146 if (argc == 1) {
147 strncpy(exname, *argv, MAXPATHLEN-1);
148 exname[MAXPATHLEN-1] = '\0';
149 } else
150 strcpy(exname, _PATH_EXPORTS);
151
152 if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) {
153 from_inetd = 0;
154 sock = RPC_ANYSOCK;
155 proto = IPPROTO_UDP;
156 }
157
158 if (!from_inetd) {
159 daemon(0, 0);
160 pmap_unset(MOUNTPROG, MOUNTVERS);
161 signal(SIGINT, SIG_IGN);
162 signal(SIGQUIT, SIG_IGN);
163 }
164
165 openlog("mountd", LOG_PID, LOG_DAEMON);
166
167 if ((transp = svcudp_create(sock)) == NULL) {
168 syslog(LOG_ERR, "Can't create socket: %m");
169 exit(1);
170 }
171
172 if (!svc_register(transp, MOUNTPROG, MOUNTVERS, mntsrv, proto)) {
173 syslog(LOG_ERR, "Can't register mount");
174 exit(1);
175 }
176
177 get_exportlist();
178 get_mountlist();
179
180 signal(SIGHUP, get_exportlist);
181 signal(SIGTERM, send_umntall);
182
183 pidfile = fopen(_PATH_MOUNTDPID, "w");
184 if (pidfile != NULL) {
185 fprintf(pidfile, "%d\n", getpid());
186 fclose(pidfile);
187 }
188
189 svc_run();
190 syslog(LOG_ERR, "Mountd died");
191 exit(1);
192 }
193
194 /*
195 * The mount rpc service
196 */
197 void
198 mntsrv(rqstp, transp)
199 register struct svc_req *rqstp;
200 register SVCXPRT *transp;
201 {
202 register struct grouplist *grp;
203 register u_long **addrp;
204 register struct exportlist *ep;
205 nfsv2fh_t nfh;
206 struct authunix_parms *ucr;
207 struct stat stb;
208 struct hostent *hp;
209 u_long saddr;
210 char dirpath[MNTPATHLEN+1];
211 int bad = ENOENT;
212 int omask;
213 uid_t uid = -2;
214
215 /* Get authorization */
216 switch (rqstp->rq_cred.oa_flavor) {
217 case AUTH_UNIX:
218 ucr = (struct authunix_parms *)rqstp->rq_clntcred;
219 uid = ucr->aup_uid;
220 break;
221 case AUTH_NULL:
222 default:
223 break;
224 }
225
226 saddr = transp->xp_raddr.sin_addr.s_addr;
227 hp = (struct hostent *)0;
228 switch (rqstp->rq_proc) {
229 case NULLPROC:
230 if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
231 syslog(LOG_ERR, "Can't send reply");
232 return;
233 case MOUNTPROC_MNT:
234 if (uid != 0 && root_only) {
235 svcerr_weakauth(transp);
236 return;
237 }
238 if (!svc_getargs(transp, xdr_dir, dirpath)) {
239 svcerr_decode(transp);
240 return;
241 }
242
243 /* Check to see if it's a valid dirpath */
244 if (stat(dirpath, &stb) < 0 ||
245 (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode))) {
246 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
247 syslog(LOG_ERR, "Can't send reply");
248 return;
249 }
250
251 /* Check in the exports list */
252 omask = sigblock(sigmask(SIGHUP));
253 ep = exphead.ex_next;
254 while (ep != NULL) {
255 if (!strcmp(ep->ex_dirp, dirpath) ||
256 (stb.st_dev == ep->ex_dev && ep->ex_alldirflg)) {
257 grp = ep->ex_groups;
258 if (grp == NULL)
259 break;
260
261 /* Check for a host match */
262 addrp = (u_long **)grp->gr_hp->h_addr_list;
263 for (;;) {
264 if (**addrp == saddr)
265 break;
266 if (*++addrp == NULL)
267 if (grp = grp->gr_next) {
268 addrp = (u_long **)
269 grp->gr_hp->h_addr_list;
270 } else {
271 bad = EACCES;
272 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
273 syslog(LOG_ERR, "Can't send reply");
274 sigsetmask(omask);
275 return;
276 }
277 }
278 hp = grp->gr_hp;
279 break;
280 }
281 ep = ep->ex_next;
282 }
283 sigsetmask(omask);
284 if (ep == NULL) {
285 bad = EACCES;
286 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
287 syslog(LOG_ERR, "Can't send reply");
288 return;
289 }
290
291 /* Get the file handle */
292 bzero((caddr_t)&nfh, sizeof(nfh));
293 if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
294 bad = errno;
295 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
296 syslog(LOG_ERR, "Can't send reply");
297 return;
298 }
299 if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
300 syslog(LOG_ERR, "Can't send reply");
301 if (hp == NULL)
302 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
303 if (hp)
304 add_mlist(hp->h_name, dirpath);
305 return;
306 case MOUNTPROC_DUMP:
307 if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0))
308 syslog(LOG_ERR, "Can't send reply");
309 return;
310 case MOUNTPROC_UMNT:
311 if (uid != 0 && root_only) {
312 svcerr_weakauth(transp);
313 return;
314 }
315 if (!svc_getargs(transp, xdr_dir, dirpath)) {
316 svcerr_decode(transp);
317 return;
318 }
319 if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
320 syslog(LOG_ERR, "Can't send reply");
321 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
322 if (hp)
323 del_mlist(hp->h_name, dirpath);
324 return;
325 case MOUNTPROC_UMNTALL:
326 if (uid != 0 && root_only) {
327 svcerr_weakauth(transp);
328 return;
329 }
330 if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
331 syslog(LOG_ERR, "Can't send reply");
332 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
333 if (hp)
334 del_mlist(hp->h_name, (char *)0);
335 return;
336 case MOUNTPROC_EXPORT:
337 case MOUNTPROC_EXPORTALL:
338 get_exportlist();
339 if (!svc_sendreply(transp, xdr_explist, (caddr_t)exphead.ex_next))
340 syslog(LOG_ERR, "Can't send reply");
341 return;
342 default:
343 svcerr_noproc(transp);
344 return;
345 }
346 }
347
348 /*
349 * Xdr conversion for a dirpath string
350 */
351 xdr_dir(xdrsp, dirp)
352 XDR *xdrsp;
353 char *dirp;
354 {
355 return (xdr_string(xdrsp, &dirp, MNTPATHLEN));
356 }
357
358 /*
359 * Xdr routine to generate fhstatus
360 */
361 xdr_fhs(xdrsp, nfh)
362 XDR *xdrsp;
363 nfsv2fh_t *nfh;
364 {
365 long ok = 0;
366
367 if (!xdr_long(xdrsp, &ok))
368 return (0);
369 return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
370 }
371
372 xdr_mlist(xdrsp, cp)
373 XDR *xdrsp;
374 caddr_t cp;
375 {
376 register struct mountlist *mlp;
377 int true = 1;
378 int false = 0;
379 char *strp;
380
381 mlp = mlhead;
382 while (mlp) {
383 if (!xdr_bool(xdrsp, &true))
384 return (0);
385 strp = &mlp->ml_host[0];
386 if (!xdr_string(xdrsp, &strp, MNTNAMLEN))
387 return (0);
388 strp = &mlp->ml_dirp[0];
389 if (!xdr_string(xdrsp, &strp, MNTPATHLEN))
390 return (0);
391 mlp = mlp->ml_next;
392 }
393 if (!xdr_bool(xdrsp, &false))
394 return (0);
395 return (1);
396 }
397
398 /*
399 * Xdr conversion for export list
400 */
401 xdr_explist(xdrsp, cp)
402 XDR *xdrsp;
403 caddr_t cp;
404 {
405 register struct exportlist *ep = (struct exportlist *)cp;
406 register struct grouplist *grp;
407 int true = 1;
408 int false = 0;
409 char *strp;
410 int omask;
411
412 omask = sigblock(sigmask(SIGHUP));
413 while (ep != NULL) {
414 if (!xdr_bool(xdrsp, &true))
415 goto errout;
416 strp = &ep->ex_dirp[0];
417 if (!xdr_string(xdrsp, &strp, MNTPATHLEN))
418 goto errout;
419 grp = ep->ex_groups;
420 while (grp != NULL) {
421 if (!xdr_bool(xdrsp, &true))
422 goto errout;
423 strp = grp->gr_hp->h_name;
424 if (!xdr_string(xdrsp, &strp, MNTNAMLEN))
425 goto errout;
426 grp = grp->gr_next;
427 }
428 if (!xdr_bool(xdrsp, &false))
429 goto errout;
430 ep = ep->ex_next;
431 }
432 sigsetmask(omask);
433 if (!xdr_bool(xdrsp, &false))
434 return (0);
435 return (1);
436 errout:
437 sigsetmask(omask);
438 return (0);
439 }
440
441 #define LINESIZ 10240
442 char line[LINESIZ];
443
444 /*
445 * Get the export list
446 */
447
448 void
449 get_exportlist()
450 {
451 register struct hostent *hp, *nhp;
452 register char **addrp, **naddrp;
453 register int i;
454 register struct grouplist *grp;
455 register struct exportlist *ep, *ep2;
456 struct statfs stfsbuf;
457 nfsv2fh_t nfh;
458 struct export_args args;
459 struct stat sb;
460 FILE *inf;
461 char *cp, *endcp;
462 char savedc;
463 int len, dirplen;
464 int rootuid, exflags, alldirflg;
465 u_long saddr;
466 struct exportlist *fep;
467 static int first = 0;
468 static struct stat last_exportstat;
469
470 /*
471 * Check if the file has changed
472 */
473 if (first++) {
474 if (stat(exname, &sb) < 0) {
475 syslog(LOG_ERR, "stat of export file %s failed. %m", exname);
476 ep = exphead.ex_next;
477 while (ep != NULL) {
478 ep2 = ep;
479 ep = ep->ex_next;
480 free_exp(ep2);
481 }
482 return;
483 }
484 if (last_exportstat.st_mtime == sb.st_mtime)
485 return;
486 }
487
488 /*
489 * First, get rid of the old list
490 */
491 ep = exphead.ex_next;
492 while (ep != NULL) {
493 ep2 = ep;
494 ep = ep->ex_next;
495 free_exp(ep2);
496 }
497
498 /*
499 * Read in the exports file and build the list, calling
500 * exportfs() as we go along
501 */
502 exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
503 if ((inf = fopen(exname, "r")) == NULL) {
504 syslog(LOG_ERR, "Can't open %s", exname);
505 exit(2);
506 }
507 while (fgets(line, LINESIZ, inf)) {
508 exflags = MNT_EXPORTED;
509 rootuid = def_rootuid;
510 alldirflg = 0;
511 cp = line;
512 nextfield(&cp, &endcp);
513
514 /*
515 * Get file system devno and see if an entry for this
516 * file system already exists.
517 */
518 savedc = *endcp;
519 *endcp = '\0';
520 if (stat(cp, &sb) < 0 ||
521 (!S_ISDIR(sb.st_mode) && !S_ISREG(sb.st_mode))) {
522 syslog(LOG_ERR,
523 "Bad Exports File, %s: %s, mountd Failed",
524 cp, "Not a directory or regular file");
525 exit(2);
526 }
527 fep = (struct exportlist *)0;
528 ep = exphead.ex_next;
529 while (ep) {
530 if (ep->ex_dev == sb.st_dev) {
531 fep = ep;
532 break;
533 }
534 ep = ep->ex_next;
535 }
536 *endcp = savedc;
537
538 /*
539 * Create new exports list entry
540 */
541 len = endcp-cp;
542 if (len <= MNTPATHLEN && len > 0) {
543 ep = (struct exportlist *)malloc(sizeof(*ep));
544 if (ep == NULL)
545 goto err;
546 ep->ex_next = ep->ex_prev = (struct exportlist *)0;
547 ep->ex_groups = (struct grouplist *)0;
548 bcopy(cp, ep->ex_dirp, len);
549 ep->ex_dirp[len] = '\0';
550 dirplen = len;
551 } else {
552 syslog(LOG_ERR, "Bad Exports File, mountd Failed");
553 exit(2);
554 }
555 cp = endcp;
556 nextfield(&cp, &endcp);
557 len = endcp-cp;
558 while (len > 0) {
559 savedc = *endcp;
560 *endcp = '\0';
561 if (len > MNTNAMLEN)
562 goto more;
563 if (*cp == '-') {
564 do_opt(cp + 1, fep, ep, &exflags, &rootuid,
565 &alldirflg);
566 goto more;
567 }
568 if (isdigit(*cp)) {
569 saddr = inet_addr(cp);
570 if (saddr == -1 ||
571 (hp = gethostbyaddr((caddr_t)&saddr,
572 sizeof(saddr), AF_INET)) == NULL) {
573 syslog(LOG_ERR,
574 "Bad Exports File, %s: %s", cp,
575 "Gethostbyaddr failed, ignored");
576 goto more;
577 }
578 } else if ((hp = gethostbyname(cp)) == NULL) {
579 syslog(LOG_ERR, "Bad Exports File, %s: %s",
580 cp, "Gethostbyname failed, ignored");
581 goto more;
582 }
583 grp = (struct grouplist *)
584 malloc(sizeof(struct grouplist));
585 if (grp == NULL)
586 goto err;
587 nhp = grp->gr_hp = (struct hostent *)
588 malloc(sizeof(struct hostent));
589 if (nhp == NULL)
590 goto err;
591 bcopy((caddr_t)hp, (caddr_t)nhp,
592 sizeof(struct hostent));
593 i = strlen(hp->h_name)+1;
594 nhp->h_name = (char *)malloc(i);
595 if (nhp->h_name == NULL)
596 goto err;
597 bcopy(hp->h_name, nhp->h_name, i);
598 addrp = hp->h_addr_list;
599 i = 1;
600 while (*addrp++)
601 i++;
602 naddrp = nhp->h_addr_list = (char **)
603 malloc(i*sizeof(char *));
604 if (naddrp == NULL)
605 goto err;
606 addrp = hp->h_addr_list;
607 while (*addrp) {
608 *naddrp = (char *)
609 malloc(hp->h_length);
610 if (*naddrp == NULL)
611 goto err;
612 bcopy(*addrp, *naddrp,
613 hp->h_length);
614 addrp++;
615 naddrp++;
616 }
617 *naddrp = (char *)0;
618 grp->gr_next = ep->ex_groups;
619 ep->ex_groups = grp;
620 more:
621 cp = endcp;
622 *cp = savedc;
623 nextfield(&cp, &endcp);
624 len = endcp - cp;
625 }
626 if (fep == NULL) {
627 args.exroot = rootuid;
628 cp = (char *)0;
629 while (statfs(ep->ex_dirp, &stfsbuf) < 0 ||
630 mount(MOUNT_EXPORT, ep->ex_dirp,
631 stfsbuf.f_flags|(MNT_UPDATE|exflags),
632 &args) < 0) {
633 /* 08 Sep 92*/ if (cp)
634 *cp-- = savedc;
635 else
636 cp = ep->ex_dirp + dirplen - 1;
637 #ifdef OMIT
638 if (cp == NULL)
639 cp = ep->ex_dirp + dirplen - 1;
640 else
641 *cp = savedc;
642 #endif /* OMIT*/
643 /* back up over the last component */
644 while (*cp == '/' && cp > ep->ex_dirp)
645 cp--;
646 /* 08 Sep 92*/ while (cp > ep->ex_dirp && *(cp - 1) != '/')
647 cp--;
648 if (cp == ep->ex_dirp) {
649 syslog(LOG_WARNING,
650 "Can't export %s", ep->ex_dirp);
651 free_exp(ep);
652 goto nextline;
653 }
654 savedc = *cp;
655 *cp = '\0';
656 }
657 if (cp)
658 *cp = savedc;
659 ep->ex_rootuid = rootuid;
660 ep->ex_exflags = exflags;
661 ep->ex_alldirflg = alldirflg;
662 } else {
663 if (alldirflg || fep->ex_alldirflg) {
664 syslog(LOG_WARNING,
665 "Can't export alldirs plus other exports");
666 free_exp(ep);
667 goto nextline;
668 }
669 ep->ex_rootuid = fep->ex_rootuid;
670 ep->ex_exflags = fep->ex_exflags;
671 ep->ex_alldirflg = 0;
672 }
673 if (getfh(ep->ex_dirp, (fhandle_t *)&nfh) < 0) {
674 syslog(LOG_WARNING, "Can't export %s", ep->ex_dirp);
675 free_exp(ep);
676 goto nextline;
677 }
678 ep->ex_dev = sb.st_dev;
679 ep->ex_next = exphead.ex_next;
680 ep->ex_prev = &exphead;
681 if (ep->ex_next != NULL)
682 ep->ex_next->ex_prev = ep;
683 exphead.ex_next = ep;
684 nextline:
685 ;
686 }
687 fclose(inf);
688 return;
689 err:
690 syslog(LOG_ERR, "No more memory: mountd Failed");
691 exit(2);
692 }
693
694 /*
695 * Parse out the next white space separated field
696 */
697 nextfield(cp, endcp)
698 char **cp;
699 char **endcp;
700 {
701 register char *p;
702
703 p = *cp;
704 while (*p == ' ' || *p == '\t')
705 p++;
706 if (*p == '\n' || *p == '\0') {
707 *cp = *endcp = p;
708 return;
709 }
710 *cp = p++;
711 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
712 p++;
713 *endcp = p;
714 }
715
716 /*
717 * Parse the option string
718 */
719 do_opt(cpopt, fep, ep, exflagsp, rootuidp, alldirflgp)
720 register char *cpopt;
721 struct exportlist *fep, *ep;
722 int *exflagsp, *rootuidp, *alldirflgp;
723 {
724 register char *cpoptarg, *cpoptend;
725
726 while (cpopt && *cpopt) {
727 if (cpoptend = index(cpopt, ','))
728 *cpoptend++ = '\0';
729 if (cpoptarg = index(cpopt, '='))
730 *cpoptarg++ = '\0';
731 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
732 if (fep && (fep->ex_exflags & MNT_EXRDONLY) == 0)
733 syslog(LOG_WARNING, "ro failed for %s",
734 ep->ex_dirp);
735 else
736 *exflagsp |= MNT_EXRDONLY;
737 } else if (!strcmp(cpopt, "root") || !strcmp(cpopt, "r")) {
738 if (cpoptarg && isdigit(*cpoptarg)) {
739 *rootuidp = atoi(cpoptarg);
740 if (fep && fep->ex_rootuid != *rootuidp)
741 syslog(LOG_WARNING,
742 "uid failed for %s",
743 ep->ex_dirp);
744 } else
745 syslog(LOG_WARNING,
746 "uid failed for %s",
747 ep->ex_dirp);
748 } else if (!strcmp(cpopt, "alldirs") || !strcmp(cpopt, "a")) {
749 *alldirflgp = 1;
750 } else
751 syslog(LOG_WARNING, "opt %s ignored for %s", cpopt,
752 ep->ex_dirp);
753 cpopt = cpoptend;
754 }
755 }
756
757 #define STRSIZ (MNTNAMLEN+MNTPATHLEN+50)
758 /*
759 * Routines that maintain the remote mounttab
760 */
761 void get_mountlist()
762 {
763 register struct mountlist *mlp, **mlpp;
764 register char *eos, *dirp;
765 int len;
766 char str[STRSIZ];
767 FILE *mlfile;
768
769 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
770 syslog(LOG_WARNING, "Can't open %s", _PATH_RMOUNTLIST);
771 return;
772 }
773 mlpp = &mlhead;
774 while (fgets(str, STRSIZ, mlfile) != NULL) {
775 if ((dirp = index(str, '\t')) == NULL &&
776 (dirp = index(str, ' ')) == NULL)
777 continue;
778 mlp = (struct mountlist *)malloc(sizeof (*mlp));
779 len = dirp-str;
780 if (len > MNTNAMLEN)
781 len = MNTNAMLEN;
782 bcopy(str, mlp->ml_host, len);
783 mlp->ml_host[len] = '\0';
784 while (*dirp == '\t' || *dirp == ' ')
785 dirp++;
786 if ((eos = index(dirp, '\t')) == NULL &&
787 (eos = index(dirp, ' ')) == NULL &&
788 (eos = index(dirp, '\n')) == NULL)
789 len = strlen(dirp);
790 else
791 len = eos-dirp;
792 if (len > MNTPATHLEN)
793 len = MNTPATHLEN;
794 bcopy(dirp, mlp->ml_dirp, len);
795 mlp->ml_dirp[len] = '\0';
796 mlp->ml_next = (struct mountlist *)0;
797 *mlpp = mlp;
798 mlpp = &mlp->ml_next;
799 }
800 fclose(mlfile);
801 }
802
803 void del_mlist(hostp, dirp)
804 register char *hostp, *dirp;
805 {
806 register struct mountlist *mlp, **mlpp;
807 FILE *mlfile;
808 int fnd = 0;
809
810 mlpp = &mlhead;
811 mlp = mlhead;
812 while (mlp) {
813 if (!strcmp(mlp->ml_host, hostp) &&
814 (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
815 fnd = 1;
816 *mlpp = mlp->ml_next;
817 free((caddr_t)mlp);
818 }
819 mlpp = &mlp->ml_next;
820 mlp = mlp->ml_next;
821 }
822 if (fnd) {
823 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
824 syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
825 return;
826 }
827 mlp = mlhead;
828 while (mlp) {
829 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
830 mlp = mlp->ml_next;
831 }
832 fclose(mlfile);
833 }
834 }
835
836 void add_mlist(hostp, dirp)
837 register char *hostp, *dirp;
838 {
839 register struct mountlist *mlp, **mlpp;
840 FILE *mlfile;
841
842 mlpp = &mlhead;
843 mlp = mlhead;
844 while (mlp) {
845 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
846 return;
847 mlpp = &mlp->ml_next;
848 mlp = mlp->ml_next;
849 }
850 mlp = (struct mountlist *)malloc(sizeof (*mlp));
851 strncpy(mlp->ml_host, hostp, MNTNAMLEN);
852 mlp->ml_host[MNTNAMLEN] = '\0';
853 strncpy(mlp->ml_dirp, dirp, MNTPATHLEN);
854 mlp->ml_dirp[MNTPATHLEN] = '\0';
855 mlp->ml_next = (struct mountlist *)0;
856 *mlpp = mlp;
857 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
858 syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
859 return;
860 }
861 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
862 fclose(mlfile);
863 }
864
865 /*
866 * This function is called via. SIGTERM when the system is going down.
867 * It sends a broadcast RPCMNT_UMNTALL.
868 */
869 void
870 send_umntall()
871 {
872 (void) clnt_broadcast(MOUNTPROG, MOUNTVERS, MOUNTPROC_UMNTALL,
873 xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
874 exit();
875 }
876
877 umntall_each(resultsp, raddr)
878 caddr_t resultsp;
879 struct sockaddr_in *raddr;
880 {
881 return (1);
882 }
883
884 /*
885 * Free up an exports list component
886 */
887 free_exp(ep)
888 register struct exportlist *ep;
889 {
890 register struct grouplist *grp;
891 register char **addrp;
892 struct grouplist *grp2;
893
894 grp = ep->ex_groups;
895 while (grp != NULL) {
896 addrp = grp->gr_hp->h_addr_list;
897 while (*addrp)
898 free(*addrp++);
899 free((caddr_t)grp->gr_hp->h_addr_list);
900 free(grp->gr_hp->h_name);
901 free((caddr_t)grp->gr_hp);
902 grp2 = grp;
903 grp = grp->gr_next;
904 free((caddr_t)grp2);
905 }
906 free((caddr_t)ep);
907 }
908