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