mountd.c revision 1.16 1 /*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Herb Hasler and 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 static char copyright[] =
39 "@(#) Copyright (c) 1989, 1993\n\
40 The Regents of the University of California. All rights reserved.\n";
41 #endif not lint
42
43 #ifndef lint
44 /*static char sccsid[] = "from: @(#)mountd.c 8.8 (Berkeley) 2/20/94";*/
45 static char *rcsid = "$Id: mountd.c,v 1.16 1994/10/15 03:55:33 mycroft Exp $";
46 #endif not lint
47
48 #include <sys/param.h>
49 #include <sys/file.h>
50 #include <sys/ioctl.h>
51 #include <sys/mount.h>
52 #include <sys/socket.h>
53 #include <sys/stat.h>
54 #include <sys/syslog.h>
55 #include <sys/ucred.h>
56
57 #include <rpc/rpc.h>
58 #include <rpc/pmap_clnt.h>
59 #include <rpc/pmap_prot.h>
60 #ifdef ISO
61 #include <netiso/iso.h>
62 #endif
63 #include <nfs/rpcv2.h>
64 #include <nfs/nfsv2.h>
65
66 #include <arpa/inet.h>
67
68 #include <ctype.h>
69 #include <errno.h>
70 #include <grp.h>
71 #include <netdb.h>
72 #include <pwd.h>
73 #include <signal.h>
74 #include <stdio.h>
75 #include <stdlib.h>
76 #include <string.h>
77 #include <unistd.h>
78 #include "pathnames.h"
79
80 #ifdef DEBUG
81 #include <stdarg.h>
82 #endif
83
84 /*
85 * Structures for keeping the mount list and export list
86 */
87 struct mountlist {
88 struct mountlist *ml_next;
89 char ml_host[RPCMNT_NAMELEN+1];
90 char ml_dirp[RPCMNT_PATHLEN+1];
91 };
92
93 struct dirlist {
94 struct dirlist *dp_left;
95 struct dirlist *dp_right;
96 int dp_flag;
97 struct hostlist *dp_hosts; /* List of hosts this dir exported to */
98 char dp_dirp[1]; /* Actually malloc'd to size of dir */
99 };
100 /* dp_flag bits */
101 #define DP_DEFSET 0x1
102
103 struct exportlist {
104 struct exportlist *ex_next;
105 struct dirlist *ex_dirl;
106 struct dirlist *ex_defdir;
107 int ex_flag;
108 fsid_t ex_fs;
109 char *ex_fsdir;
110 };
111 /* ex_flag bits */
112 #define EX_LINKED 0x1
113
114 struct netmsk {
115 u_long nt_net;
116 u_long nt_mask;
117 char *nt_name;
118 };
119
120 union grouptypes {
121 struct hostent *gt_hostent;
122 struct netmsk gt_net;
123 #ifdef ISO
124 struct sockaddr_iso *gt_isoaddr;
125 #endif
126 };
127
128 struct grouplist {
129 int gr_type;
130 union grouptypes gr_ptr;
131 struct grouplist *gr_next;
132 };
133 /* Group types */
134 #define GT_NULL 0x0
135 #define GT_HOST 0x1
136 #define GT_NET 0x2
137 #define GT_ISO 0x4
138
139 struct hostlist {
140 struct grouplist *ht_grp;
141 struct hostlist *ht_next;
142 };
143
144 /* Global defs */
145 char *add_expdir __P((struct dirlist **, char *, int));
146 void add_dlist __P((struct dirlist **, struct dirlist *,
147 struct grouplist *));
148 void add_mlist __P((char *, char *));
149 int check_dirpath __P((char *));
150 int check_options __P((struct dirlist *));
151 int chk_host __P((struct dirlist *, u_long, int *));
152 void del_mlist __P((char *, char *));
153 struct dirlist *dirp_search __P((struct dirlist *, char *));
154 int do_mount __P((struct exportlist *, struct grouplist *, int,
155 struct ucred *, char *, int, struct statfs *));
156 int do_opt __P((char **, char **, struct exportlist *, struct grouplist *,
157 int *, int *, struct ucred *));
158 struct exportlist *ex_search __P((fsid_t *));
159 struct exportlist *get_exp __P((void));
160 void free_dir __P((struct dirlist *));
161 void free_exp __P((struct exportlist *));
162 void free_grp __P((struct grouplist *));
163 void free_host __P((struct hostlist *));
164 void get_exportlist __P((void));
165 int get_host __P((char *, struct grouplist *));
166 struct hostlist *get_ht __P((void));
167 int get_line __P((void));
168 void get_mountlist __P((void));
169 int get_net __P((char *, struct netmsk *, int));
170 void getexp_err __P((struct exportlist *, struct grouplist *));
171 struct grouplist *get_grp __P((void));
172 void hang_dirp __P((struct dirlist *, struct grouplist *,
173 struct exportlist *, int));
174 void mntsrv __P((struct svc_req *, SVCXPRT *));
175 void nextfield __P((char **, char **));
176 void out_of_mem __P((void));
177 void parsecred __P((char *, struct ucred *));
178 int put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *));
179 int scan_tree __P((struct dirlist *, u_long));
180 void send_umntall __P((void));
181 int umntall_each __P((caddr_t, struct sockaddr_in *));
182 int xdr_dir __P((XDR *, char *));
183 int xdr_explist __P((XDR *, caddr_t));
184 int xdr_fhs __P((XDR *, nfsv2fh_t *));
185 int xdr_mlist __P((XDR *, caddr_t));
186
187 /* C library */
188 int getnetgrent();
189 void endnetgrent();
190 void setnetgrent();
191
192 #ifdef ISO
193 struct iso_addr *iso_addr();
194 #endif
195
196 struct exportlist *exphead;
197 struct mountlist *mlhead;
198 struct grouplist *grphead;
199 char exname[MAXPATHLEN];
200 struct ucred def_anon = {
201 1,
202 (uid_t) -2,
203 1,
204 { (gid_t) -2 }
205 };
206 int resvport_only = 1;
207 int opt_flags;
208 /* Bits for above */
209 #define OP_MAPROOT 0x01
210 #define OP_MAPALL 0x02
211 #define OP_KERB 0x04
212 #define OP_MASK 0x08
213 #define OP_NET 0x10
214 #define OP_ISO 0x20
215 #define OP_ALLDIRS 0x40
216
217 #ifdef DEBUG
218 int debug = 1;
219 void SYSLOG __P((int, const char *, ...));
220 #define syslog SYSLOG
221 #else
222 int debug = 0;
223 #endif
224
225 /*
226 * Mountd server for NFS mount protocol as described in:
227 * NFS: Network File System Protocol Specification, RFC1094, Appendix A
228 * The optional arguments are the exports file name
229 * default: _PATH_EXPORTS
230 * and "-n" to allow nonroot mount.
231 */
232 int
233 main(argc, argv)
234 int argc;
235 char **argv;
236 {
237 SVCXPRT *udptransp, *tcptransp;
238 int c;
239
240 while ((c = getopt(argc, argv, "n")) != EOF)
241 switch (c) {
242 case 'n':
243 resvport_only = 0;
244 break;
245 default:
246 fprintf(stderr, "Usage: mountd [-n] [export_file]\n");
247 exit(1);
248 };
249 argc -= optind;
250 argv += optind;
251 grphead = (struct grouplist *)NULL;
252 exphead = (struct exportlist *)NULL;
253 mlhead = (struct mountlist *)NULL;
254 if (argc == 1) {
255 strncpy(exname, *argv, MAXPATHLEN-1);
256 exname[MAXPATHLEN-1] = '\0';
257 } else
258 strcpy(exname, _PATH_EXPORTS);
259 openlog("mountd", LOG_PID, LOG_DAEMON);
260 if (debug)
261 fprintf(stderr,"Getting export list.\n");
262 get_exportlist();
263 if (debug)
264 fprintf(stderr,"Getting mount list.\n");
265 get_mountlist();
266 if (debug)
267 fprintf(stderr,"Here we go.\n");
268 if (debug == 0) {
269 daemon(0, 0);
270 signal(SIGINT, SIG_IGN);
271 signal(SIGQUIT, SIG_IGN);
272 }
273 signal(SIGHUP, (void (*) __P((int))) get_exportlist);
274 signal(SIGTERM, (void (*) __P((int))) send_umntall);
275 { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w");
276 if (pidfile != NULL) {
277 fprintf(pidfile, "%d\n", getpid());
278 fclose(pidfile);
279 }
280 }
281 if ((udptransp = svcudp_create(RPC_ANYSOCK)) == NULL ||
282 (tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) {
283 syslog(LOG_ERR, "Can't create socket");
284 exit(1);
285 }
286 pmap_unset(RPCPROG_MNT, RPCMNT_VER1);
287 if (!svc_register(udptransp, RPCPROG_MNT, RPCMNT_VER1, mntsrv,
288 IPPROTO_UDP) ||
289 !svc_register(tcptransp, RPCPROG_MNT, RPCMNT_VER1, mntsrv,
290 IPPROTO_TCP)) {
291 syslog(LOG_ERR, "Can't register mount");
292 exit(1);
293 }
294 svc_run();
295 syslog(LOG_ERR, "Mountd died");
296 exit(1);
297 }
298
299 /*
300 * The mount rpc service
301 */
302 void
303 mntsrv(rqstp, transp)
304 struct svc_req *rqstp;
305 SVCXPRT *transp;
306 {
307 struct exportlist *ep;
308 struct dirlist *dp;
309 nfsv2fh_t nfh;
310 struct stat stb;
311 struct statfs fsb;
312 struct hostent *hp;
313 u_long saddr;
314 u_short sport;
315 char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN];
316 int bad = ENOENT, omask, defset;
317
318 saddr = transp->xp_raddr.sin_addr.s_addr;
319 sport = ntohs(transp->xp_raddr.sin_port);
320 hp = (struct hostent *)NULL;
321 switch (rqstp->rq_proc) {
322 case NULLPROC:
323 if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
324 syslog(LOG_ERR, "Can't send reply");
325 return;
326 case RPCMNT_MOUNT:
327 if (sport >= IPPORT_RESERVED && resvport_only) {
328 svcerr_weakauth(transp);
329 return;
330 }
331 if (!svc_getargs(transp, xdr_dir, rpcpath)) {
332 svcerr_decode(transp);
333 return;
334 }
335
336 /*
337 * Get the real pathname and make sure it is a file or
338 * directory that exists.
339 */
340 if (realpath(rpcpath, dirpath) == 0 ||
341 stat(dirpath, &stb) < 0 ||
342 (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) ||
343 statfs(dirpath, &fsb) < 0) {
344 chdir("/"); /* Just in case realpath doesn't */
345 if (debug)
346 fprintf(stderr, "stat failed on %s\n", dirpath);
347 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
348 syslog(LOG_ERR, "Can't send reply");
349 return;
350 }
351
352 /* Check in the exports list */
353 omask = sigblock(sigmask(SIGHUP));
354 ep = ex_search(&fsb.f_fsid);
355 defset = 0;
356 if (ep && (chk_host(ep->ex_defdir, saddr, &defset) ||
357 ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
358 chk_host(dp, saddr, &defset)) ||
359 (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
360 scan_tree(ep->ex_dirl, saddr) == 0))) {
361 /* Get the file handle */
362 memset(&nfh, 0, sizeof(nfh));
363 if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
364 bad = errno;
365 syslog(LOG_ERR, "Can't get fh for %s", dirpath);
366 if (!svc_sendreply(transp, xdr_long,
367 (caddr_t)&bad))
368 syslog(LOG_ERR, "Can't send reply");
369 sigsetmask(omask);
370 return;
371 }
372 if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
373 syslog(LOG_ERR, "Can't send reply");
374 if (hp == NULL)
375 hp = gethostbyaddr((caddr_t)&saddr,
376 sizeof(saddr), AF_INET);
377 if (hp)
378 add_mlist(hp->h_name, dirpath);
379 else
380 add_mlist(inet_ntoa(transp->xp_raddr.sin_addr),
381 dirpath);
382 if (debug)
383 fprintf(stderr,"Mount successfull.\n");
384 } else {
385 bad = EACCES;
386 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
387 syslog(LOG_ERR, "Can't send reply");
388 }
389 sigsetmask(omask);
390 return;
391 case RPCMNT_DUMP:
392 if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL))
393 syslog(LOG_ERR, "Can't send reply");
394 return;
395 case RPCMNT_UMOUNT:
396 if (sport >= IPPORT_RESERVED && resvport_only) {
397 svcerr_weakauth(transp);
398 return;
399 }
400 if (!svc_getargs(transp, xdr_dir, dirpath)) {
401 svcerr_decode(transp);
402 return;
403 }
404 if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
405 syslog(LOG_ERR, "Can't send reply");
406 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
407 if (hp)
408 del_mlist(hp->h_name, dirpath);
409 del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath);
410 return;
411 case RPCMNT_UMNTALL:
412 if (sport >= IPPORT_RESERVED && resvport_only) {
413 svcerr_weakauth(transp);
414 return;
415 }
416 if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
417 syslog(LOG_ERR, "Can't send reply");
418 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
419 if (hp)
420 del_mlist(hp->h_name, (char *)NULL);
421 del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)NULL);
422 return;
423 case RPCMNT_EXPORT:
424 if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL))
425 syslog(LOG_ERR, "Can't send reply");
426 return;
427 default:
428 svcerr_noproc(transp);
429 return;
430 }
431 }
432
433 /*
434 * Xdr conversion for a dirpath string
435 */
436 int
437 xdr_dir(xdrsp, dirp)
438 XDR *xdrsp;
439 char *dirp;
440 {
441 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
442 }
443
444 /*
445 * Xdr routine to generate fhstatus
446 */
447 int
448 xdr_fhs(xdrsp, nfh)
449 XDR *xdrsp;
450 nfsv2fh_t *nfh;
451 {
452 int ok = 0;
453
454 if (!xdr_long(xdrsp, &ok))
455 return (0);
456 return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
457 }
458
459 int
460 xdr_mlist(xdrsp, cp)
461 XDR *xdrsp;
462 caddr_t cp;
463 {
464 struct mountlist *mlp;
465 int true = 1;
466 int false = 0;
467 char *strp;
468
469 mlp = mlhead;
470 while (mlp) {
471 if (!xdr_bool(xdrsp, &true))
472 return (0);
473 strp = &mlp->ml_host[0];
474 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
475 return (0);
476 strp = &mlp->ml_dirp[0];
477 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
478 return (0);
479 mlp = mlp->ml_next;
480 }
481 if (!xdr_bool(xdrsp, &false))
482 return (0);
483 return (1);
484 }
485
486 /*
487 * Xdr conversion for export list
488 */
489 int
490 xdr_explist(xdrsp, cp)
491 XDR *xdrsp;
492 caddr_t cp;
493 {
494 struct exportlist *ep;
495 int false = 0;
496 int omask, putdef;
497
498 omask = sigblock(sigmask(SIGHUP));
499 ep = exphead;
500 while (ep) {
501 putdef = 0;
502 if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef))
503 goto errout;
504 if (ep->ex_defdir && putdef == 0 &&
505 put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL,
506 &putdef))
507 goto errout;
508 ep = ep->ex_next;
509 }
510 sigsetmask(omask);
511 if (!xdr_bool(xdrsp, &false))
512 return (0);
513 return (1);
514 errout:
515 sigsetmask(omask);
516 return (0);
517 }
518
519 /*
520 * Called from xdr_explist() to traverse the tree and export the
521 * directory paths.
522 */
523 int
524 put_exlist(dp, xdrsp, adp, putdefp)
525 struct dirlist *dp;
526 XDR *xdrsp;
527 struct dirlist *adp;
528 int *putdefp;
529 {
530 struct grouplist *grp;
531 struct hostlist *hp;
532 int true = 1;
533 int false = 0;
534 int gotalldir = 0;
535 char *strp;
536
537 if (dp) {
538 if (put_exlist(dp->dp_left, xdrsp, adp, putdefp))
539 return (1);
540 if (!xdr_bool(xdrsp, &true))
541 return (1);
542 strp = dp->dp_dirp;
543 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
544 return (1);
545 if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) {
546 gotalldir = 1;
547 *putdefp = 1;
548 }
549 if ((dp->dp_flag & DP_DEFSET) == 0 &&
550 (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) {
551 hp = dp->dp_hosts;
552 while (hp) {
553 grp = hp->ht_grp;
554 if (grp->gr_type == GT_HOST) {
555 if (!xdr_bool(xdrsp, &true))
556 return (1);
557 strp = grp->gr_ptr.gt_hostent->h_name;
558 if (!xdr_string(xdrsp, &strp,
559 RPCMNT_NAMELEN))
560 return (1);
561 } else if (grp->gr_type == GT_NET) {
562 if (!xdr_bool(xdrsp, &true))
563 return (1);
564 strp = grp->gr_ptr.gt_net.nt_name;
565 if (!xdr_string(xdrsp, &strp,
566 RPCMNT_NAMELEN))
567 return (1);
568 }
569 hp = hp->ht_next;
570 if (gotalldir && hp == (struct hostlist *)NULL) {
571 hp = adp->dp_hosts;
572 gotalldir = 0;
573 }
574 }
575 }
576 if (!xdr_bool(xdrsp, &false))
577 return (1);
578 if (put_exlist(dp->dp_right, xdrsp, adp, putdefp))
579 return (1);
580 }
581 return (0);
582 }
583
584 #define LINESIZ 10240
585 char line[LINESIZ];
586 FILE *exp_file;
587
588 /*
589 * Get the export list
590 */
591 void
592 get_exportlist()
593 {
594 struct exportlist *ep, *ep2;
595 struct grouplist *grp, *tgrp;
596 struct exportlist **epp;
597 struct dirlist *dirhead;
598 struct statfs fsb, *fsp;
599 struct hostent *hpe;
600 struct ucred anon;
601 char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
602 int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp;
603
604 /*
605 * First, get rid of the old list
606 */
607 ep = exphead;
608 while (ep) {
609 ep2 = ep;
610 ep = ep->ex_next;
611 free_exp(ep2);
612 }
613 exphead = (struct exportlist *)NULL;
614
615 grp = grphead;
616 while (grp) {
617 tgrp = grp;
618 grp = grp->gr_next;
619 free_grp(tgrp);
620 }
621 grphead = (struct grouplist *)NULL;
622
623 /*
624 * And delete exports that are in the kernel for all local
625 * file systems.
626 * XXX: Should know how to handle all local exportable file systems
627 * instead of just MOUNT_UFS.
628 */
629 num = getmntinfo(&fsp, MNT_NOWAIT);
630 for (i = 0; i < num; i++) {
631 union {
632 struct ufs_args ua;
633 struct iso_args ia;
634 struct mfs_args ma;
635 struct msdosfs_args da;
636 } targs;
637
638 if (!strcmp(fsp->f_fstypename, MOUNT_MFS) ||
639 !strcmp(fsp->f_fstypename, MOUNT_UFS) ||
640 !strcmp(fsp->f_fstypename, MOUNT_MSDOS) ||
641 !strcmp(fsp->f_fstypename, MOUNT_CD9660)) {
642 targs.ua.fspec = NULL;
643 targs.ua.export.ex_flags = MNT_DELEXPORT;
644 if (mount(fsp->f_fstypename, fsp->f_mntonname,
645 fsp->f_flags | MNT_UPDATE,
646 (caddr_t)&targs) < 0)
647 syslog(LOG_ERR, "Can't delete exports for %s",
648 fsp->f_mntonname);
649 }
650 fsp++;
651 }
652
653 /*
654 * Read in the exports file and build the list, calling
655 * mount() as we go along to push the export rules into the kernel.
656 */
657 if ((exp_file = fopen(exname, "r")) == NULL) {
658 syslog(LOG_ERR, "Can't open %s", exname);
659 exit(2);
660 }
661 dirhead = (struct dirlist *)NULL;
662 while (get_line()) {
663 if (debug)
664 fprintf(stderr,"Got line %s\n",line);
665 cp = line;
666 nextfield(&cp, &endcp);
667 if (*cp == '#')
668 goto nextline;
669
670 /*
671 * Set defaults.
672 */
673 has_host = FALSE;
674 anon = def_anon;
675 exflags = MNT_EXPORTED;
676 got_nondir = 0;
677 opt_flags = 0;
678 ep = (struct exportlist *)NULL;
679
680 /*
681 * Create new exports list entry
682 */
683 len = endcp-cp;
684 tgrp = grp = get_grp();
685 while (len > 0) {
686 if (len > RPCMNT_NAMELEN) {
687 getexp_err(ep, tgrp);
688 goto nextline;
689 }
690 if (*cp == '-') {
691 if (ep == (struct exportlist *)NULL) {
692 getexp_err(ep, tgrp);
693 goto nextline;
694 }
695 if (debug)
696 fprintf(stderr, "doing opt %s\n", cp);
697 got_nondir = 1;
698 if (do_opt(&cp, &endcp, ep, grp, &has_host,
699 &exflags, &anon)) {
700 getexp_err(ep, tgrp);
701 goto nextline;
702 }
703 } else if (*cp == '/') {
704 savedc = *endcp;
705 *endcp = '\0';
706 if (check_dirpath(cp) &&
707 statfs(cp, &fsb) >= 0) {
708 if (got_nondir) {
709 syslog(LOG_ERR, "Dirs must be first");
710 getexp_err(ep, tgrp);
711 goto nextline;
712 }
713 if (ep) {
714 if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] ||
715 ep->ex_fs.val[1] != fsb.f_fsid.val[1]) {
716 getexp_err(ep, tgrp);
717 goto nextline;
718 }
719 } else {
720 /*
721 * See if this directory is already
722 * in the list.
723 */
724 ep = ex_search(&fsb.f_fsid);
725 if (ep == (struct exportlist *)NULL) {
726 ep = get_exp();
727 ep->ex_fs = fsb.f_fsid;
728 ep->ex_fsdir = (char *)
729 malloc(strlen(fsb.f_mntonname) + 1);
730 if (ep->ex_fsdir)
731 strcpy(ep->ex_fsdir,
732 fsb.f_mntonname);
733 else
734 out_of_mem();
735 if (debug)
736 fprintf(stderr,
737 "Making new ep fs=0x%x,0x%x\n",
738 fsb.f_fsid.val[0],
739 fsb.f_fsid.val[1]);
740 } else if (debug)
741 fprintf(stderr,
742 "Found ep fs=0x%x,0x%x\n",
743 fsb.f_fsid.val[0],
744 fsb.f_fsid.val[1]);
745 }
746
747 /*
748 * Add dirpath to export mount point.
749 */
750 dirp = add_expdir(&dirhead, cp, len);
751 dirplen = len;
752 } else {
753 getexp_err(ep, tgrp);
754 goto nextline;
755 }
756 *endcp = savedc;
757 } else {
758 savedc = *endcp;
759 *endcp = '\0';
760 got_nondir = 1;
761 if (ep == (struct exportlist *)NULL) {
762 getexp_err(ep, tgrp);
763 goto nextline;
764 }
765
766 /*
767 * Get the host or netgroup.
768 */
769 setnetgrent(cp);
770 netgrp = getnetgrent(&hst, &usr, &dom);
771 do {
772 if (has_host) {
773 grp->gr_next = get_grp();
774 grp = grp->gr_next;
775 }
776 if (netgrp) {
777 if (get_host(hst, grp)) {
778 syslog(LOG_ERR, "Bad netgroup %s", cp);
779 getexp_err(ep, tgrp);
780 goto nextline;
781 }
782 } else if (get_host(cp, grp)) {
783 getexp_err(ep, tgrp);
784 goto nextline;
785 }
786 has_host = TRUE;
787 } while (netgrp && getnetgrent(&hst, &usr, &dom));
788 endnetgrent();
789 *endcp = savedc;
790 }
791 cp = endcp;
792 nextfield(&cp, &endcp);
793 len = endcp - cp;
794 }
795 if (check_options(dirhead)) {
796 getexp_err(ep, tgrp);
797 goto nextline;
798 }
799 if (!has_host) {
800 grp->gr_type = GT_HOST;
801 if (debug)
802 fprintf(stderr,"Adding a default entry\n");
803 /* add a default group and make the grp list NULL */
804 hpe = (struct hostent *)malloc(sizeof(struct hostent));
805 if (hpe == (struct hostent *)NULL)
806 out_of_mem();
807 hpe->h_name = "Default";
808 hpe->h_addrtype = AF_INET;
809 hpe->h_length = sizeof (u_long);
810 hpe->h_addr_list = (char **)NULL;
811 grp->gr_ptr.gt_hostent = hpe;
812
813 /*
814 * Don't allow a network export coincide with a list of
815 * host(s) on the same line.
816 */
817 } else if ((opt_flags & OP_NET) && tgrp->gr_next) {
818 getexp_err(ep, tgrp);
819 goto nextline;
820 }
821
822 /*
823 * Loop through hosts, pushing the exports into the kernel.
824 * After loop, tgrp points to the start of the list and
825 * grp points to the last entry in the list.
826 */
827 grp = tgrp;
828 do {
829 if (do_mount(ep, grp, exflags, &anon, dirp,
830 dirplen, &fsb)) {
831 getexp_err(ep, tgrp);
832 goto nextline;
833 }
834 } while (grp->gr_next && (grp = grp->gr_next));
835
836 /*
837 * Success. Update the data structures.
838 */
839 if (has_host) {
840 hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS));
841 grp->gr_next = grphead;
842 grphead = tgrp;
843 } else {
844 hang_dirp(dirhead, (struct grouplist *)NULL, ep,
845 (opt_flags & OP_ALLDIRS));
846 free_grp(grp);
847 }
848 dirhead = (struct dirlist *)NULL;
849 if ((ep->ex_flag & EX_LINKED) == 0) {
850 ep2 = exphead;
851 epp = &exphead;
852
853 /*
854 * Insert in the list in alphabetical order.
855 */
856 while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
857 epp = &ep2->ex_next;
858 ep2 = ep2->ex_next;
859 }
860 if (ep2)
861 ep->ex_next = ep2;
862 *epp = ep;
863 ep->ex_flag |= EX_LINKED;
864 }
865 nextline:
866 if (dirhead) {
867 free_dir(dirhead);
868 dirhead = (struct dirlist *)NULL;
869 }
870 }
871 fclose(exp_file);
872 }
873
874 /*
875 * Allocate an export list element
876 */
877 struct exportlist *
878 get_exp()
879 {
880 struct exportlist *ep;
881
882 ep = (struct exportlist *)malloc(sizeof (struct exportlist));
883 if (ep == (struct exportlist *)NULL)
884 out_of_mem();
885 memset(ep, 0, sizeof(struct exportlist));
886 return (ep);
887 }
888
889 /*
890 * Allocate a group list element
891 */
892 struct grouplist *
893 get_grp()
894 {
895 struct grouplist *gp;
896
897 gp = (struct grouplist *)malloc(sizeof (struct grouplist));
898 if (gp == (struct grouplist *)NULL)
899 out_of_mem();
900 memset(gp, 0, sizeof(struct grouplist));
901 return (gp);
902 }
903
904 /*
905 * Clean up upon an error in get_exportlist().
906 */
907 void
908 getexp_err(ep, grp)
909 struct exportlist *ep;
910 struct grouplist *grp;
911 {
912 struct grouplist *tgrp;
913
914 syslog(LOG_ERR, "Bad exports list line %s", line);
915 if (ep && (ep->ex_flag & EX_LINKED) == 0)
916 free_exp(ep);
917 while (grp) {
918 tgrp = grp;
919 grp = grp->gr_next;
920 free_grp(tgrp);
921 }
922 }
923
924 /*
925 * Search the export list for a matching fs.
926 */
927 struct exportlist *
928 ex_search(fsid)
929 fsid_t *fsid;
930 {
931 struct exportlist *ep;
932
933 ep = exphead;
934 while (ep) {
935 if (ep->ex_fs.val[0] == fsid->val[0] &&
936 ep->ex_fs.val[1] == fsid->val[1])
937 return (ep);
938 ep = ep->ex_next;
939 }
940 return (ep);
941 }
942
943 /*
944 * Add a directory path to the list.
945 */
946 char *
947 add_expdir(dpp, cp, len)
948 struct dirlist **dpp;
949 char *cp;
950 int len;
951 {
952 struct dirlist *dp;
953
954 dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
955 dp->dp_left = *dpp;
956 dp->dp_right = (struct dirlist *)NULL;
957 dp->dp_flag = 0;
958 dp->dp_hosts = (struct hostlist *)NULL;
959 strcpy(dp->dp_dirp, cp);
960 *dpp = dp;
961 return (dp->dp_dirp);
962 }
963
964 /*
965 * Hang the dir list element off the dirpath binary tree as required
966 * and update the entry for host.
967 */
968 void
969 hang_dirp(dp, grp, ep, alldirs)
970 struct dirlist *dp;
971 struct grouplist *grp;
972 struct exportlist *ep;
973 int alldirs;
974 {
975 struct hostlist *hp;
976 struct dirlist *dp2;
977
978 if (alldirs) {
979 if (ep->ex_defdir)
980 free((caddr_t)dp);
981 else
982 ep->ex_defdir = dp;
983 if (grp == (struct grouplist *)NULL)
984 ep->ex_defdir->dp_flag |= DP_DEFSET;
985 else while (grp) {
986 hp = get_ht();
987 hp->ht_grp = grp;
988 hp->ht_next = ep->ex_defdir->dp_hosts;
989 ep->ex_defdir->dp_hosts = hp;
990 grp = grp->gr_next;
991 }
992 } else {
993
994 /*
995 * Loop throught the directories adding them to the tree.
996 */
997 while (dp) {
998 dp2 = dp->dp_left;
999 add_dlist(&ep->ex_dirl, dp, grp);
1000 dp = dp2;
1001 }
1002 }
1003 }
1004
1005 /*
1006 * Traverse the binary tree either updating a node that is already there
1007 * for the new directory or adding the new node.
1008 */
1009 void
1010 add_dlist(dpp, newdp, grp)
1011 struct dirlist **dpp;
1012 struct dirlist *newdp;
1013 struct grouplist *grp;
1014 {
1015 struct dirlist *dp;
1016 struct hostlist *hp;
1017 int cmp;
1018
1019 dp = *dpp;
1020 if (dp) {
1021 cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
1022 if (cmp > 0) {
1023 add_dlist(&dp->dp_left, newdp, grp);
1024 return;
1025 } else if (cmp < 0) {
1026 add_dlist(&dp->dp_right, newdp, grp);
1027 return;
1028 } else
1029 free((caddr_t)newdp);
1030 } else {
1031 dp = newdp;
1032 dp->dp_left = (struct dirlist *)NULL;
1033 *dpp = dp;
1034 }
1035 if (grp) {
1036
1037 /*
1038 * Hang all of the host(s) off of the directory point.
1039 */
1040 do {
1041 hp = get_ht();
1042 hp->ht_grp = grp;
1043 hp->ht_next = dp->dp_hosts;
1044 dp->dp_hosts = hp;
1045 grp = grp->gr_next;
1046 } while (grp);
1047 } else
1048 dp->dp_flag |= DP_DEFSET;
1049 }
1050
1051 /*
1052 * Search for a dirpath on the export point.
1053 */
1054 struct dirlist *
1055 dirp_search(dp, dirpath)
1056 struct dirlist *dp;
1057 char *dirpath;
1058 {
1059 int cmp;
1060
1061 if (dp) {
1062 cmp = strcmp(dp->dp_dirp, dirpath);
1063 if (cmp > 0)
1064 return (dirp_search(dp->dp_left, dirpath));
1065 else if (cmp < 0)
1066 return (dirp_search(dp->dp_right, dirpath));
1067 else
1068 return (dp);
1069 }
1070 return (dp);
1071 }
1072
1073 /*
1074 * Scan for a host match in a directory tree.
1075 */
1076 int
1077 chk_host(dp, saddr, defsetp)
1078 struct dirlist *dp;
1079 u_long saddr;
1080 int *defsetp;
1081 {
1082 struct hostlist *hp;
1083 struct grouplist *grp;
1084 u_long **addrp;
1085
1086 if (dp) {
1087 if (dp->dp_flag & DP_DEFSET)
1088 *defsetp = 1;
1089 hp = dp->dp_hosts;
1090 while (hp) {
1091 grp = hp->ht_grp;
1092 switch (grp->gr_type) {
1093 case GT_HOST:
1094 addrp = (u_long **)
1095 grp->gr_ptr.gt_hostent->h_addr_list;
1096 while (*addrp) {
1097 if (**addrp == saddr)
1098 return (1);
1099 addrp++;
1100 }
1101 break;
1102 case GT_NET:
1103 if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
1104 grp->gr_ptr.gt_net.nt_net)
1105 return (1);
1106 break;
1107 };
1108 hp = hp->ht_next;
1109 }
1110 }
1111 return (0);
1112 }
1113
1114 /*
1115 * Scan tree for a host that matches the address.
1116 */
1117 int
1118 scan_tree(dp, saddr)
1119 struct dirlist *dp;
1120 u_long saddr;
1121 {
1122 int defset;
1123
1124 if (dp) {
1125 if (scan_tree(dp->dp_left, saddr))
1126 return (1);
1127 if (chk_host(dp, saddr, &defset))
1128 return (1);
1129 if (scan_tree(dp->dp_right, saddr))
1130 return (1);
1131 }
1132 return (0);
1133 }
1134
1135 /*
1136 * Traverse the dirlist tree and free it up.
1137 */
1138 void
1139 free_dir(dp)
1140 struct dirlist *dp;
1141 {
1142
1143 if (dp) {
1144 free_dir(dp->dp_left);
1145 free_dir(dp->dp_right);
1146 free_host(dp->dp_hosts);
1147 free((caddr_t)dp);
1148 }
1149 }
1150
1151 /*
1152 * Parse the option string and update fields.
1153 * Option arguments may either be -<option>=<value> or
1154 * -<option> <value>
1155 */
1156 int
1157 do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
1158 char **cpp, **endcpp;
1159 struct exportlist *ep;
1160 struct grouplist *grp;
1161 int *has_hostp;
1162 int *exflagsp;
1163 struct ucred *cr;
1164 {
1165 char *cpoptarg, *cpoptend;
1166 char *cp, *endcp, *cpopt, savedc, savedc2;
1167 int allflag, usedarg;
1168
1169 cpopt = *cpp;
1170 cpopt++;
1171 cp = *endcpp;
1172 savedc = *cp;
1173 *cp = '\0';
1174 while (cpopt && *cpopt) {
1175 allflag = 1;
1176 usedarg = -2;
1177 if (cpoptend = strchr(cpopt, ',')) {
1178 *cpoptend++ = '\0';
1179 if (cpoptarg = strchr(cpopt, '='))
1180 *cpoptarg++ = '\0';
1181 } else {
1182 if (cpoptarg = strchr(cpopt, '='))
1183 *cpoptarg++ = '\0';
1184 else {
1185 *cp = savedc;
1186 nextfield(&cp, &endcp);
1187 **endcpp = '\0';
1188 if (endcp > cp && *cp != '-') {
1189 cpoptarg = cp;
1190 savedc2 = *endcp;
1191 *endcp = '\0';
1192 usedarg = 0;
1193 }
1194 }
1195 }
1196 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
1197 *exflagsp |= MNT_EXRDONLY;
1198 } else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
1199 !(allflag = strcmp(cpopt, "mapall")) ||
1200 !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
1201 usedarg++;
1202 parsecred(cpoptarg, cr);
1203 if (allflag == 0) {
1204 *exflagsp |= MNT_EXPORTANON;
1205 opt_flags |= OP_MAPALL;
1206 } else
1207 opt_flags |= OP_MAPROOT;
1208 } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {
1209 *exflagsp |= MNT_EXKERB;
1210 opt_flags |= OP_KERB;
1211 } else if (cpoptarg && (!strcmp(cpopt, "mask") ||
1212 !strcmp(cpopt, "m"))) {
1213 if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
1214 syslog(LOG_ERR, "Bad mask: %s", cpoptarg);
1215 return (1);
1216 }
1217 usedarg++;
1218 opt_flags |= OP_MASK;
1219 } else if (cpoptarg && (!strcmp(cpopt, "network") ||
1220 !strcmp(cpopt, "n"))) {
1221 if (grp->gr_type != GT_NULL) {
1222 syslog(LOG_ERR, "Network/host conflict");
1223 return (1);
1224 } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
1225 syslog(LOG_ERR, "Bad net: %s", cpoptarg);
1226 return (1);
1227 }
1228 grp->gr_type = GT_NET;
1229 *has_hostp = 1;
1230 usedarg++;
1231 opt_flags |= OP_NET;
1232 } else if (!strcmp(cpopt, "alldirs")) {
1233 opt_flags |= OP_ALLDIRS;
1234 #ifdef ISO
1235 } else if (cpoptarg && !strcmp(cpopt, "iso")) {
1236 if (get_isoaddr(cpoptarg, grp)) {
1237 syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg);
1238 return (1);
1239 }
1240 *has_hostp = 1;
1241 usedarg++;
1242 opt_flags |= OP_ISO;
1243 #endif /* ISO */
1244 } else {
1245 syslog(LOG_ERR, "Bad opt %s", cpopt);
1246 return (1);
1247 }
1248 if (usedarg >= 0) {
1249 *endcp = savedc2;
1250 **endcpp = savedc;
1251 if (usedarg > 0) {
1252 *cpp = cp;
1253 *endcpp = endcp;
1254 }
1255 return (0);
1256 }
1257 cpopt = cpoptend;
1258 }
1259 **endcpp = savedc;
1260 return (0);
1261 }
1262
1263 /*
1264 * Translate a character string to the corresponding list of network
1265 * addresses for a hostname.
1266 */
1267 int
1268 get_host(cp, grp)
1269 char *cp;
1270 struct grouplist *grp;
1271 {
1272 struct hostent *hp, *nhp;
1273 char **addrp, **naddrp;
1274 struct hostent t_host;
1275 int i;
1276 u_long saddr;
1277 char *aptr[2];
1278
1279 if (grp->gr_type != GT_NULL)
1280 return (1);
1281 if ((hp = gethostbyname(cp)) == NULL) {
1282 if (isdigit(*cp)) {
1283 saddr = inet_addr(cp);
1284 if (saddr == -1) {
1285 syslog(LOG_ERR, "Inet_addr failed");
1286 return (1);
1287 }
1288 if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
1289 AF_INET)) == NULL) {
1290 hp = &t_host;
1291 hp->h_name = cp;
1292 hp->h_addrtype = AF_INET;
1293 hp->h_length = sizeof (u_long);
1294 hp->h_addr_list = aptr;
1295 aptr[0] = (char *)&saddr;
1296 aptr[1] = (char *)NULL;
1297 }
1298 } else {
1299 syslog(LOG_ERR, "Gethostbyname failed");
1300 return (1);
1301 }
1302 }
1303 grp->gr_type = GT_HOST;
1304 nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
1305 malloc(sizeof(struct hostent));
1306 if (nhp == (struct hostent *)NULL)
1307 out_of_mem();
1308 memcpy(nhp, hp, sizeof(struct hostent));
1309 i = strlen(hp->h_name)+1;
1310 nhp->h_name = (char *)malloc(i);
1311 if (nhp->h_name == (char *)NULL)
1312 out_of_mem();
1313 memcpy(nhp->h_name, hp->h_name, i);
1314 addrp = hp->h_addr_list;
1315 i = 1;
1316 while (*addrp++)
1317 i++;
1318 naddrp = nhp->h_addr_list = (char **)
1319 malloc(i*sizeof(char *));
1320 if (naddrp == (char **)NULL)
1321 out_of_mem();
1322 addrp = hp->h_addr_list;
1323 while (*addrp) {
1324 *naddrp = (char *)
1325 malloc(hp->h_length);
1326 if (*naddrp == (char *)NULL)
1327 out_of_mem();
1328 memcpy(*naddrp, *addrp, hp->h_length);
1329 addrp++;
1330 naddrp++;
1331 }
1332 *naddrp = (char *)NULL;
1333 if (debug)
1334 fprintf(stderr, "got host %s\n", hp->h_name);
1335 return (0);
1336 }
1337
1338 /*
1339 * Free up an exports list component
1340 */
1341 void
1342 free_exp(ep)
1343 struct exportlist *ep;
1344 {
1345
1346 if (ep->ex_defdir) {
1347 free_host(ep->ex_defdir->dp_hosts);
1348 free((caddr_t)ep->ex_defdir);
1349 }
1350 if (ep->ex_fsdir)
1351 free(ep->ex_fsdir);
1352 free_dir(ep->ex_dirl);
1353 free((caddr_t)ep);
1354 }
1355
1356 /*
1357 * Free hosts.
1358 */
1359 void
1360 free_host(hp)
1361 struct hostlist *hp;
1362 {
1363 struct hostlist *hp2;
1364
1365 while (hp) {
1366 hp2 = hp;
1367 hp = hp->ht_next;
1368 free((caddr_t)hp2);
1369 }
1370 }
1371
1372 struct hostlist *
1373 get_ht()
1374 {
1375 struct hostlist *hp;
1376
1377 hp = (struct hostlist *)malloc(sizeof (struct hostlist));
1378 if (hp == (struct hostlist *)NULL)
1379 out_of_mem();
1380 hp->ht_next = (struct hostlist *)NULL;
1381 return (hp);
1382 }
1383
1384 #ifdef ISO
1385 /*
1386 * Translate an iso address.
1387 */
1388 get_isoaddr(cp, grp)
1389 char *cp;
1390 struct grouplist *grp;
1391 {
1392 struct iso_addr *isop;
1393 struct sockaddr_iso *isoaddr;
1394
1395 if (grp->gr_type != GT_NULL)
1396 return (1);
1397 if ((isop = iso_addr(cp)) == NULL) {
1398 syslog(LOG_ERR,
1399 "iso_addr failed, ignored");
1400 return (1);
1401 }
1402 isoaddr = (struct sockaddr_iso *)
1403 malloc(sizeof (struct sockaddr_iso));
1404 if (isoaddr == (struct sockaddr_iso *)NULL)
1405 out_of_mem();
1406 memset(isoaddr, 0, sizeof(struct sockaddr_iso));
1407 memcpy(&isoaddr->siso_addr, isop, sizeof(struct iso_addr));
1408 isoaddr->siso_len = sizeof(struct sockaddr_iso);
1409 isoaddr->siso_family = AF_ISO;
1410 grp->gr_type = GT_ISO;
1411 grp->gr_ptr.gt_isoaddr = isoaddr;
1412 return (0);
1413 }
1414 #endif /* ISO */
1415
1416 /*
1417 * Out of memory, fatal
1418 */
1419 void
1420 out_of_mem()
1421 {
1422
1423 syslog(LOG_ERR, "Out of memory");
1424 exit(2);
1425 }
1426
1427 /*
1428 * Do the mount syscall with the update flag to push the export info into
1429 * the kernel.
1430 */
1431 int
1432 do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
1433 struct exportlist *ep;
1434 struct grouplist *grp;
1435 int exflags;
1436 struct ucred *anoncrp;
1437 char *dirp;
1438 int dirplen;
1439 struct statfs *fsb;
1440 {
1441 char *cp = (char *)NULL;
1442 u_long **addrp;
1443 int done;
1444 char savedc = '\0';
1445 struct sockaddr_in sin, imask;
1446 union {
1447 struct ufs_args ua;
1448 struct iso_args ia;
1449 struct mfs_args ma;
1450 struct msdosfs_args da;
1451 } args;
1452 u_long net;
1453
1454 args.ua.fspec = 0;
1455 args.ua.export.ex_flags = exflags;
1456 args.ua.export.ex_anon = *anoncrp;
1457 memset(&sin, 0, sizeof(sin));
1458 memset(&imask, 0, sizeof(imask));
1459 sin.sin_family = AF_INET;
1460 sin.sin_len = sizeof(sin);
1461 imask.sin_family = AF_INET;
1462 imask.sin_len = sizeof(sin);
1463 if (grp->gr_type == GT_HOST)
1464 addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list;
1465 else
1466 addrp = (u_long **)NULL;
1467 done = FALSE;
1468 while (!done) {
1469 switch (grp->gr_type) {
1470 case GT_HOST:
1471 if (addrp) {
1472 sin.sin_addr.s_addr = **addrp;
1473 args.ua.export.ex_addrlen = sizeof(sin);
1474 } else
1475 args.ua.export.ex_addrlen = 0;
1476 args.ua.export.ex_addr = (struct sockaddr *)&sin;
1477 args.ua.export.ex_masklen = 0;
1478 break;
1479 case GT_NET:
1480 if (grp->gr_ptr.gt_net.nt_mask)
1481 imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
1482 else {
1483 net = ntohl(grp->gr_ptr.gt_net.nt_net);
1484 if (IN_CLASSA(net))
1485 imask.sin_addr.s_addr = inet_addr("255.0.0.0");
1486 else if (IN_CLASSB(net))
1487 imask.sin_addr.s_addr =
1488 inet_addr("255.255.0.0");
1489 else
1490 imask.sin_addr.s_addr =
1491 inet_addr("255.255.255.0");
1492 grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
1493 }
1494 sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
1495 args.ua.export.ex_addr = (struct sockaddr *)&sin;
1496 args.ua.export.ex_addrlen = sizeof (sin);
1497 args.ua.export.ex_mask = (struct sockaddr *)&imask;
1498 args.ua.export.ex_masklen = sizeof (imask);
1499 break;
1500 #ifdef ISO
1501 case GT_ISO:
1502 args.ua.export.ex_addr =
1503 (struct sockaddr *)grp->gr_ptr.gt_isoaddr;
1504 args.ua.export.ex_addrlen =
1505 sizeof(struct sockaddr_iso);
1506 args.ua.export.ex_masklen = 0;
1507 break;
1508 #endif /* ISO */
1509 default:
1510 syslog(LOG_ERR, "Bad grouptype");
1511 if (cp)
1512 *cp = savedc;
1513 return (1);
1514 };
1515
1516 /*
1517 * XXX:
1518 * Maybe I should just use the fsb->f_mntonname path instead
1519 * of looping back up the dirp to the mount point??
1520 * Also, needs to know how to export all types of local
1521 * exportable file systems and not just MOUNT_UFS.
1522 */
1523 while (mount(fsb->f_fstypename, dirp,
1524 fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
1525 if (cp)
1526 *cp-- = savedc;
1527 else
1528 cp = dirp + dirplen - 1;
1529 if (errno == EPERM) {
1530 syslog(LOG_ERR,
1531 "Can't change attributes for %s.\n", dirp);
1532 return (1);
1533 }
1534 if (opt_flags & OP_ALLDIRS) {
1535 syslog(LOG_ERR, "Not root dir");
1536 return (1);
1537 }
1538 /* back up over the last component */
1539 while (*cp == '/' && cp > dirp)
1540 cp--;
1541 while (*(cp - 1) != '/' && cp > dirp)
1542 cp--;
1543 if (cp == dirp) {
1544 if (debug)
1545 fprintf(stderr,"mnt unsucc\n");
1546 syslog(LOG_ERR, "Can't export %s", dirp);
1547 return (1);
1548 }
1549 savedc = *cp;
1550 *cp = '\0';
1551 }
1552 if (addrp) {
1553 ++addrp;
1554 if (*addrp == (u_long *)NULL)
1555 done = TRUE;
1556 } else
1557 done = TRUE;
1558 }
1559 if (cp)
1560 *cp = savedc;
1561 return (0);
1562 }
1563
1564 /*
1565 * Translate a net address.
1566 */
1567 int
1568 get_net(cp, net, maskflg)
1569 char *cp;
1570 struct netmsk *net;
1571 int maskflg;
1572 {
1573 struct netent *np;
1574 long netaddr;
1575 struct in_addr inetaddr, inetaddr2;
1576 char *name;
1577
1578 if (np = getnetbyname(cp))
1579 inetaddr = inet_makeaddr(np->n_net, 0);
1580 else if (isdigit(*cp)) {
1581 if ((netaddr = inet_network(cp)) == -1)
1582 return (1);
1583 inetaddr = inet_makeaddr(netaddr, 0);
1584 /*
1585 * Due to arbritrary subnet masks, you don't know how many
1586 * bits to shift the address to make it into a network,
1587 * however you do know how to make a network address into
1588 * a host with host == 0 and then compare them.
1589 * (What a pest)
1590 */
1591 if (!maskflg) {
1592 setnetent(0);
1593 while (np = getnetent()) {
1594 inetaddr2 = inet_makeaddr(np->n_net, 0);
1595 if (inetaddr2.s_addr == inetaddr.s_addr)
1596 break;
1597 }
1598 endnetent();
1599 }
1600 } else
1601 return (1);
1602 if (maskflg)
1603 net->nt_mask = inetaddr.s_addr;
1604 else {
1605 if (np)
1606 name = np->n_name;
1607 else
1608 name = inet_ntoa(inetaddr);
1609 net->nt_name = (char *)malloc(strlen(name) + 1);
1610 if (net->nt_name == (char *)NULL)
1611 out_of_mem();
1612 strcpy(net->nt_name, name);
1613 net->nt_net = inetaddr.s_addr;
1614 }
1615 return (0);
1616 }
1617
1618 /*
1619 * Parse out the next white space separated field
1620 */
1621 void
1622 nextfield(cp, endcp)
1623 char **cp;
1624 char **endcp;
1625 {
1626 char *p;
1627
1628 p = *cp;
1629 while (*p == ' ' || *p == '\t')
1630 p++;
1631 if (*p == '\n' || *p == '\0')
1632 *cp = *endcp = p;
1633 else {
1634 *cp = p++;
1635 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
1636 p++;
1637 *endcp = p;
1638 }
1639 }
1640
1641 /*
1642 * Get an exports file line. Skip over blank lines and handle line
1643 * continuations.
1644 */
1645 int
1646 get_line()
1647 {
1648 char *p, *cp;
1649 int len;
1650 int totlen, cont_line;
1651
1652 /*
1653 * Loop around ignoring blank lines and getting all continuation lines.
1654 */
1655 p = line;
1656 totlen = 0;
1657 do {
1658 if (fgets(p, LINESIZ - totlen, exp_file) == NULL)
1659 return (0);
1660 len = strlen(p);
1661 cp = p + len - 1;
1662 cont_line = 0;
1663 while (cp >= p &&
1664 (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
1665 if (*cp == '\\')
1666 cont_line = 1;
1667 cp--;
1668 len--;
1669 }
1670 *++cp = '\0';
1671 if (len > 0) {
1672 totlen += len;
1673 if (totlen >= LINESIZ) {
1674 syslog(LOG_ERR, "Exports line too long");
1675 exit(2);
1676 }
1677 p = cp;
1678 }
1679 } while (totlen == 0 || cont_line);
1680 return (1);
1681 }
1682
1683 /*
1684 * Parse a description of a credential.
1685 */
1686 void
1687 parsecred(namelist, cr)
1688 char *namelist;
1689 struct ucred *cr;
1690 {
1691 char *name;
1692 int cnt;
1693 char *names;
1694 struct passwd *pw;
1695 struct group *gr;
1696 int ngroups, groups[NGROUPS + 1];
1697
1698 /*
1699 * Set up the unpriviledged user.
1700 */
1701 cr->cr_ref = 1;
1702 cr->cr_uid = -2;
1703 cr->cr_groups[0] = -2;
1704 cr->cr_ngroups = 1;
1705 /*
1706 * Get the user's password table entry.
1707 */
1708 names = strsep(&namelist, " \t\n");
1709 name = strsep(&names, ":");
1710 if (isdigit(*name) || *name == '-')
1711 pw = getpwuid(atoi(name));
1712 else
1713 pw = getpwnam(name);
1714 /*
1715 * Credentials specified as those of a user.
1716 */
1717 if (names == NULL) {
1718 if (pw == NULL) {
1719 syslog(LOG_ERR, "Unknown user: %s", name);
1720 return;
1721 }
1722 cr->cr_uid = pw->pw_uid;
1723 ngroups = NGROUPS + 1;
1724 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
1725 syslog(LOG_ERR, "Too many groups");
1726 /*
1727 * Convert from int's to gid_t's and compress out duplicate
1728 */
1729 cr->cr_ngroups = ngroups - 1;
1730 cr->cr_groups[0] = groups[0];
1731 for (cnt = 2; cnt < ngroups; cnt++)
1732 cr->cr_groups[cnt - 1] = groups[cnt];
1733 return;
1734 }
1735 /*
1736 * Explicit credential specified as a colon separated list:
1737 * uid:gid:gid:...
1738 */
1739 if (pw != NULL)
1740 cr->cr_uid = pw->pw_uid;
1741 else if (isdigit(*name) || *name == '-')
1742 cr->cr_uid = atoi(name);
1743 else {
1744 syslog(LOG_ERR, "Unknown user: %s", name);
1745 return;
1746 }
1747 cr->cr_ngroups = 0;
1748 while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
1749 name = strsep(&names, ":");
1750 if (isdigit(*name) || *name == '-') {
1751 cr->cr_groups[cr->cr_ngroups++] = atoi(name);
1752 } else {
1753 if ((gr = getgrnam(name)) == NULL) {
1754 syslog(LOG_ERR, "Unknown group: %s", name);
1755 continue;
1756 }
1757 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
1758 }
1759 }
1760 if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
1761 syslog(LOG_ERR, "Too many groups");
1762 }
1763
1764 #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
1765 /*
1766 * Routines that maintain the remote mounttab
1767 */
1768 void
1769 get_mountlist()
1770 {
1771 struct mountlist *mlp, **mlpp;
1772 char *host, *dirp, *cp;
1773 int len;
1774 char str[STRSIZ];
1775 FILE *mlfile;
1776
1777 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
1778 syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST);
1779 return;
1780 }
1781 mlpp = &mlhead;
1782 while (fgets(str, STRSIZ, mlfile) != NULL) {
1783 cp = str;
1784 host = strsep(&cp, " \t\n");
1785 dirp = strsep(&cp, " \t\n");
1786 if (host == NULL || dirp == NULL)
1787 continue;
1788 mlp = (struct mountlist *)malloc(sizeof (*mlp));
1789 strncpy(mlp->ml_host, host, RPCMNT_NAMELEN);
1790 mlp->ml_host[RPCMNT_NAMELEN] = '\0';
1791 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
1792 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
1793 mlp->ml_next = (struct mountlist *)NULL;
1794 *mlpp = mlp;
1795 mlpp = &mlp->ml_next;
1796 }
1797 fclose(mlfile);
1798 }
1799
1800 void
1801 del_mlist(hostp, dirp)
1802 char *hostp, *dirp;
1803 {
1804 struct mountlist *mlp, **mlpp;
1805 struct mountlist *mlp2;
1806 FILE *mlfile;
1807 int fnd = 0;
1808
1809 mlpp = &mlhead;
1810 mlp = mlhead;
1811 while (mlp) {
1812 if (!strcmp(mlp->ml_host, hostp) &&
1813 (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
1814 fnd = 1;
1815 mlp2 = mlp;
1816 *mlpp = mlp = mlp->ml_next;
1817 free((caddr_t)mlp2);
1818 } else {
1819 mlpp = &mlp->ml_next;
1820 mlp = mlp->ml_next;
1821 }
1822 }
1823 if (fnd) {
1824 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
1825 syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST);
1826 return;
1827 }
1828 mlp = mlhead;
1829 while (mlp) {
1830 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
1831 mlp = mlp->ml_next;
1832 }
1833 fclose(mlfile);
1834 }
1835 }
1836
1837 void
1838 add_mlist(hostp, dirp)
1839 char *hostp, *dirp;
1840 {
1841 struct mountlist *mlp, **mlpp;
1842 FILE *mlfile;
1843
1844 mlpp = &mlhead;
1845 mlp = mlhead;
1846 while (mlp) {
1847 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
1848 return;
1849 mlpp = &mlp->ml_next;
1850 mlp = mlp->ml_next;
1851 }
1852 mlp = (struct mountlist *)malloc(sizeof (*mlp));
1853 strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
1854 mlp->ml_host[RPCMNT_NAMELEN] = '\0';
1855 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
1856 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
1857 mlp->ml_next = (struct mountlist *)NULL;
1858 *mlpp = mlp;
1859 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
1860 syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST);
1861 return;
1862 }
1863 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
1864 fclose(mlfile);
1865 }
1866
1867 /*
1868 * This function is called via. SIGTERM when the system is going down.
1869 * It sends a broadcast RPCMNT_UMNTALL.
1870 */
1871 void
1872 send_umntall()
1873 {
1874 (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
1875 xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
1876 exit(0);
1877 }
1878
1879 int
1880 umntall_each(resultsp, raddr)
1881 caddr_t resultsp;
1882 struct sockaddr_in *raddr;
1883 {
1884 return (1);
1885 }
1886
1887 /*
1888 * Free up a group list.
1889 */
1890 void
1891 free_grp(grp)
1892 struct grouplist *grp;
1893 {
1894 char **addrp;
1895
1896 if (grp->gr_type == GT_HOST) {
1897 if (grp->gr_ptr.gt_hostent->h_name) {
1898 addrp = grp->gr_ptr.gt_hostent->h_addr_list;
1899 while (addrp && *addrp)
1900 free(*addrp++);
1901 free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
1902 free(grp->gr_ptr.gt_hostent->h_name);
1903 }
1904 free((caddr_t)grp->gr_ptr.gt_hostent);
1905 } else if (grp->gr_type == GT_NET) {
1906 if (grp->gr_ptr.gt_net.nt_name)
1907 free(grp->gr_ptr.gt_net.nt_name);
1908 }
1909 #ifdef ISO
1910 else if (grp->gr_type == GT_ISO)
1911 free((caddr_t)grp->gr_ptr.gt_isoaddr);
1912 #endif
1913 free((caddr_t)grp);
1914 }
1915
1916 #ifdef DEBUG
1917 void
1918 SYSLOG(int pri, const char *fmt, ...)
1919 {
1920 va_list ap;
1921
1922 va_start(ap, fmt);
1923 vfprintf(stderr, fmt, ap);
1924 va_end(ap);
1925 }
1926 #endif /* DEBUG */
1927
1928 /*
1929 * Check options for consistency.
1930 */
1931 int
1932 check_options(dp)
1933 struct dirlist *dp;
1934 {
1935
1936 if (dp == (struct dirlist *)NULL)
1937 return (1);
1938 if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) ||
1939 (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) ||
1940 (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) {
1941 syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive");
1942 return (1);
1943 }
1944 if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
1945 syslog(LOG_ERR, "-mask requires -net");
1946 return (1);
1947 }
1948 if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) {
1949 syslog(LOG_ERR, "-net and -iso mutually exclusive");
1950 return (1);
1951 }
1952 if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
1953 syslog(LOG_ERR, "-alldir has multiple directories");
1954 return (1);
1955 }
1956 return (0);
1957 }
1958
1959 /*
1960 * Check an absolute directory path for any symbolic links. Return true
1961 * if no symbolic links are found.
1962 */
1963 int
1964 check_dirpath(dirp)
1965 char *dirp;
1966 {
1967 char *cp;
1968 int ret = 1;
1969 struct stat sb;
1970
1971 cp = dirp + 1;
1972 while (*cp && ret) {
1973 if (*cp == '/') {
1974 *cp = '\0';
1975 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
1976 ret = 0;
1977 *cp = '/';
1978 }
1979 cp++;
1980 }
1981 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
1982 ret = 0;
1983 return (ret);
1984 }
1985