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