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