mountd.c revision 1.9 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.9 1993/09/09 16:34:34 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 || (stb.st_mode&S_IFMT) !=
245 S_IFDIR) {
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 struct export_args args;
458 struct stat sb;
459 FILE *inf;
460 char *cp, *endcp;
461 char savedc;
462 int len, dirplen;
463 int rootuid, exflags, alldirflg;
464 u_long saddr;
465 struct exportlist *fep;
466 static int first = 0;
467 static struct stat last_exportstat;
468
469 /*
470 * Check if the file has changed
471 */
472 if (first++) {
473 if (stat(exname, &sb) < 0) {
474 syslog(LOG_ERR, "stat of export file %s failed. %m", exname);
475 ep = exphead.ex_next;
476 while (ep != NULL) {
477 ep2 = ep;
478 ep = ep->ex_next;
479 free_exp(ep2);
480 }
481 return;
482 }
483 if (last_exportstat.st_mtime == sb.st_mtime)
484 return;
485 }
486
487 /*
488 * First, get rid of the old list
489 */
490 ep = exphead.ex_next;
491 while (ep != NULL) {
492 ep2 = ep;
493 ep = ep->ex_next;
494 free_exp(ep2);
495 }
496
497 /*
498 * Read in the exports file and build the list, calling
499 * exportfs() as we go along
500 */
501 exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
502 if ((inf = fopen(exname, "r")) == NULL) {
503 syslog(LOG_ERR, "Can't open %s", exname);
504 exit(2);
505 }
506 while (fgets(line, LINESIZ, inf)) {
507 exflags = MNT_EXPORTED;
508 rootuid = def_rootuid;
509 alldirflg = 0;
510 cp = line;
511 nextfield(&cp, &endcp);
512
513 /*
514 * Get file system devno and see if an entry for this
515 * file system already exists.
516 */
517 savedc = *endcp;
518 *endcp = '\0';
519 if (stat(cp, &sb) < 0 || (sb.st_mode & S_IFMT) != S_IFDIR) {
520 syslog(LOG_ERR,
521 "Bad Exports File, %s: %s, mountd Failed",
522 cp, "Not a directory");
523 exit(2);
524 }
525 fep = (struct exportlist *)0;
526 ep = exphead.ex_next;
527 while (ep) {
528 if (ep->ex_dev == sb.st_dev) {
529 fep = ep;
530 break;
531 }
532 ep = ep->ex_next;
533 }
534 *endcp = savedc;
535
536 /*
537 * Create new exports list entry
538 */
539 len = endcp-cp;
540 if (len <= MNTPATHLEN && len > 0) {
541 ep = (struct exportlist *)malloc(sizeof(*ep));
542 if (ep == NULL)
543 goto err;
544 ep->ex_next = ep->ex_prev = (struct exportlist *)0;
545 ep->ex_groups = (struct grouplist *)0;
546 bcopy(cp, ep->ex_dirp, len);
547 ep->ex_dirp[len] = '\0';
548 dirplen = len;
549 } else {
550 syslog(LOG_ERR, "Bad Exports File, mountd Failed");
551 exit(2);
552 }
553 cp = endcp;
554 nextfield(&cp, &endcp);
555 len = endcp-cp;
556 while (len > 0) {
557 savedc = *endcp;
558 *endcp = '\0';
559 if (len > MNTNAMLEN)
560 goto more;
561 if (*cp == '-') {
562 do_opt(cp + 1, fep, ep, &exflags, &rootuid,
563 &alldirflg);
564 goto more;
565 }
566 if (isdigit(*cp)) {
567 saddr = inet_addr(cp);
568 if (saddr == -1 ||
569 (hp = gethostbyaddr((caddr_t)&saddr,
570 sizeof(saddr), AF_INET)) == NULL) {
571 syslog(LOG_ERR,
572 "Bad Exports File, %s: %s", cp,
573 "Gethostbyaddr failed, ignored");
574 goto more;
575 }
576 } else if ((hp = gethostbyname(cp)) == NULL) {
577 syslog(LOG_ERR, "Bad Exports File, %s: %s",
578 cp, "Gethostbyname failed, ignored");
579 goto more;
580 }
581 grp = (struct grouplist *)
582 malloc(sizeof(struct grouplist));
583 if (grp == NULL)
584 goto err;
585 nhp = grp->gr_hp = (struct hostent *)
586 malloc(sizeof(struct hostent));
587 if (nhp == NULL)
588 goto err;
589 bcopy((caddr_t)hp, (caddr_t)nhp,
590 sizeof(struct hostent));
591 i = strlen(hp->h_name)+1;
592 nhp->h_name = (char *)malloc(i);
593 if (nhp->h_name == NULL)
594 goto err;
595 bcopy(hp->h_name, nhp->h_name, i);
596 addrp = hp->h_addr_list;
597 i = 1;
598 while (*addrp++)
599 i++;
600 naddrp = nhp->h_addr_list = (char **)
601 malloc(i*sizeof(char *));
602 if (naddrp == NULL)
603 goto err;
604 addrp = hp->h_addr_list;
605 while (*addrp) {
606 *naddrp = (char *)
607 malloc(hp->h_length);
608 if (*naddrp == NULL)
609 goto err;
610 bcopy(*addrp, *naddrp,
611 hp->h_length);
612 addrp++;
613 naddrp++;
614 }
615 *naddrp = (char *)0;
616 grp->gr_next = ep->ex_groups;
617 ep->ex_groups = grp;
618 more:
619 cp = endcp;
620 *cp = savedc;
621 nextfield(&cp, &endcp);
622 len = endcp - cp;
623 }
624 if (fep == NULL) {
625 args.exroot = rootuid;
626 cp = (char *)0;
627 while (statfs(ep->ex_dirp, &stfsbuf) < 0 ||
628 mount(MOUNT_EXPORT, ep->ex_dirp,
629 stfsbuf.f_flags|(MNT_UPDATE|exflags),
630 &args) < 0) {
631 /* 08 Sep 92*/ if (cp)
632 *cp-- = savedc;
633 else
634 cp = ep->ex_dirp + dirplen - 1;
635 #ifdef OMIT
636 if (cp == NULL)
637 cp = ep->ex_dirp + dirplen - 1;
638 else
639 *cp = savedc;
640 #endif /* OMIT*/
641 /* back up over the last component */
642 while (*cp == '/' && cp > ep->ex_dirp)
643 cp--;
644 /* 08 Sep 92*/ while (cp > ep->ex_dirp && *(cp - 1) != '/')
645 cp--;
646 if (cp == ep->ex_dirp) {
647 syslog(LOG_WARNING,
648 "Can't export %s", ep->ex_dirp);
649 free_exp(ep);
650 goto nextline;
651 }
652 savedc = *cp;
653 *cp = '\0';
654 }
655 if (cp)
656 *cp = savedc;
657 ep->ex_rootuid = rootuid;
658 ep->ex_exflags = exflags;
659 ep->ex_alldirflg = alldirflg;
660 } else {
661 if (alldirflg || fep->ex_alldirflg) {
662 syslog(LOG_WARNING,
663 "Can't export alldirs plus other exports");
664 free_exp(ep);
665 goto nextline;
666 }
667 ep->ex_rootuid = fep->ex_rootuid;
668 ep->ex_exflags = fep->ex_exflags;
669 ep->ex_alldirflg = 0;
670 }
671 ep->ex_dev = sb.st_dev;
672 ep->ex_next = exphead.ex_next;
673 ep->ex_prev = &exphead;
674 if (ep->ex_next != NULL)
675 ep->ex_next->ex_prev = ep;
676 exphead.ex_next = ep;
677 nextline:
678 ;
679 }
680 fclose(inf);
681 return;
682 err:
683 syslog(LOG_ERR, "No more memory: mountd Failed");
684 exit(2);
685 }
686
687 /*
688 * Parse out the next white space separated field
689 */
690 nextfield(cp, endcp)
691 char **cp;
692 char **endcp;
693 {
694 register char *p;
695
696 p = *cp;
697 while (*p == ' ' || *p == '\t')
698 p++;
699 if (*p == '\n' || *p == '\0') {
700 *cp = *endcp = p;
701 return;
702 }
703 *cp = p++;
704 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
705 p++;
706 *endcp = p;
707 }
708
709 /*
710 * Parse the option string
711 */
712 do_opt(cpopt, fep, ep, exflagsp, rootuidp, alldirflgp)
713 register char *cpopt;
714 struct exportlist *fep, *ep;
715 int *exflagsp, *rootuidp, *alldirflgp;
716 {
717 register char *cpoptarg, *cpoptend;
718
719 while (cpopt && *cpopt) {
720 if (cpoptend = index(cpopt, ','))
721 *cpoptend++ = '\0';
722 if (cpoptarg = index(cpopt, '='))
723 *cpoptarg++ = '\0';
724 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
725 if (fep && (fep->ex_exflags & MNT_EXRDONLY) == 0)
726 syslog(LOG_WARNING, "ro failed for %s",
727 ep->ex_dirp);
728 else
729 *exflagsp |= MNT_EXRDONLY;
730 } else if (!strcmp(cpopt, "root") || !strcmp(cpopt, "r")) {
731 if (cpoptarg && isdigit(*cpoptarg)) {
732 *rootuidp = atoi(cpoptarg);
733 if (fep && fep->ex_rootuid != *rootuidp)
734 syslog(LOG_WARNING,
735 "uid failed for %s",
736 ep->ex_dirp);
737 } else
738 syslog(LOG_WARNING,
739 "uid failed for %s",
740 ep->ex_dirp);
741 } else if (!strcmp(cpopt, "alldirs") || !strcmp(cpopt, "a")) {
742 *alldirflgp = 1;
743 } else
744 syslog(LOG_WARNING, "opt %s ignored for %s", cpopt,
745 ep->ex_dirp);
746 cpopt = cpoptend;
747 }
748 }
749
750 #define STRSIZ (MNTNAMLEN+MNTPATHLEN+50)
751 /*
752 * Routines that maintain the remote mounttab
753 */
754 void get_mountlist()
755 {
756 register struct mountlist *mlp, **mlpp;
757 register char *eos, *dirp;
758 int len;
759 char str[STRSIZ];
760 FILE *mlfile;
761
762 if (((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) &&
763 ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL)) {
764 syslog(LOG_WARNING, "Can't open %s", _PATH_RMOUNTLIST);
765 return;
766 }
767 mlpp = &mlhead;
768 while (fgets(str, STRSIZ, mlfile) != NULL) {
769 if ((dirp = index(str, '\t')) == NULL &&
770 (dirp = index(str, ' ')) == NULL)
771 continue;
772 mlp = (struct mountlist *)malloc(sizeof (*mlp));
773 len = dirp-str;
774 if (len > MNTNAMLEN)
775 len = MNTNAMLEN;
776 bcopy(str, mlp->ml_host, len);
777 mlp->ml_host[len] = '\0';
778 while (*dirp == '\t' || *dirp == ' ')
779 dirp++;
780 if ((eos = index(dirp, '\t')) == NULL &&
781 (eos = index(dirp, ' ')) == NULL &&
782 (eos = index(dirp, '\n')) == NULL)
783 len = strlen(dirp);
784 else
785 len = eos-dirp;
786 if (len > MNTPATHLEN)
787 len = MNTPATHLEN;
788 bcopy(dirp, mlp->ml_dirp, len);
789 mlp->ml_dirp[len] = '\0';
790 mlp->ml_next = (struct mountlist *)0;
791 *mlpp = mlp;
792 mlpp = &mlp->ml_next;
793 }
794 fclose(mlfile);
795 }
796
797 void del_mlist(hostp, dirp)
798 register char *hostp, *dirp;
799 {
800 register struct mountlist *mlp, **mlpp;
801 FILE *mlfile;
802 int fnd = 0;
803
804 mlpp = &mlhead;
805 mlp = mlhead;
806 while (mlp) {
807 if (!strcmp(mlp->ml_host, hostp) &&
808 (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
809 fnd = 1;
810 *mlpp = mlp->ml_next;
811 free((caddr_t)mlp);
812 }
813 mlpp = &mlp->ml_next;
814 mlp = mlp->ml_next;
815 }
816 if (fnd) {
817 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
818 syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
819 return;
820 }
821 mlp = mlhead;
822 while (mlp) {
823 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
824 mlp = mlp->ml_next;
825 }
826 fclose(mlfile);
827 }
828 }
829
830 void add_mlist(hostp, dirp)
831 register char *hostp, *dirp;
832 {
833 register struct mountlist *mlp, **mlpp;
834 FILE *mlfile;
835
836 mlpp = &mlhead;
837 mlp = mlhead;
838 while (mlp) {
839 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
840 return;
841 mlpp = &mlp->ml_next;
842 mlp = mlp->ml_next;
843 }
844 mlp = (struct mountlist *)malloc(sizeof (*mlp));
845 strncpy(mlp->ml_host, hostp, MNTNAMLEN);
846 mlp->ml_host[MNTNAMLEN] = '\0';
847 strncpy(mlp->ml_dirp, dirp, MNTPATHLEN);
848 mlp->ml_dirp[MNTPATHLEN] = '\0';
849 mlp->ml_next = (struct mountlist *)0;
850 *mlpp = mlp;
851 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
852 syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
853 return;
854 }
855 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
856 fclose(mlfile);
857 }
858
859 /*
860 * This function is called via. SIGTERM when the system is going down.
861 * It sends a broadcast RPCMNT_UMNTALL.
862 */
863 void
864 send_umntall()
865 {
866 (void) clnt_broadcast(MOUNTPROG, MOUNTVERS, MOUNTPROC_UMNTALL,
867 xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
868 exit();
869 }
870
871 umntall_each(resultsp, raddr)
872 caddr_t resultsp;
873 struct sockaddr_in *raddr;
874 {
875 return (1);
876 }
877
878 /*
879 * Free up an exports list component
880 */
881 free_exp(ep)
882 register struct exportlist *ep;
883 {
884 register struct grouplist *grp;
885 register char **addrp;
886 struct grouplist *grp2;
887
888 grp = ep->ex_groups;
889 while (grp != NULL) {
890 addrp = grp->gr_hp->h_addr_list;
891 while (*addrp)
892 free(*addrp++);
893 free((caddr_t)grp->gr_hp->h_addr_list);
894 free(grp->gr_hp->h_name);
895 free((caddr_t)grp->gr_hp);
896 grp2 = grp;
897 grp = grp->gr_next;
898 free((caddr_t)grp2);
899 }
900 free((caddr_t)ep);
901 }
902