mountd.c revision 1.32 1 /* $NetBSD: mountd.c,v 1.32 1996/05/22 03:50:06 mrg 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.32 1996/05/22 03:50:06 mrg 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: %m", 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: %s", cp,
1370 hstrerror(h_errno));
1371 return (1);
1372 }
1373 }
1374 grp->gr_type = GT_HOST;
1375 nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
1376 malloc(sizeof(struct hostent));
1377 if (nhp == (struct hostent *)NULL)
1378 out_of_mem();
1379 memcpy(nhp, hp, sizeof(struct hostent));
1380 i = strlen(hp->h_name)+1;
1381 nhp->h_name = (char *)malloc(i);
1382 if (nhp->h_name == (char *)NULL)
1383 out_of_mem();
1384 memcpy(nhp->h_name, hp->h_name, i);
1385 addrp = hp->h_addr_list;
1386 i = 1;
1387 while (*addrp++)
1388 i++;
1389 naddrp = nhp->h_addr_list = (char **)
1390 malloc(i*sizeof(char *));
1391 if (naddrp == (char **)NULL)
1392 out_of_mem();
1393 addrp = hp->h_addr_list;
1394 while (*addrp) {
1395 *naddrp = (char *)
1396 malloc(hp->h_length);
1397 if (*naddrp == (char *)NULL)
1398 out_of_mem();
1399 memcpy(*naddrp, *addrp, hp->h_length);
1400 addrp++;
1401 naddrp++;
1402 }
1403 *naddrp = (char *)NULL;
1404 if (debug)
1405 fprintf(stderr, "got host %s\n", hp->h_name);
1406 return (0);
1407 }
1408
1409 /*
1410 * Free up an exports list component
1411 */
1412 void
1413 free_exp(ep)
1414 struct exportlist *ep;
1415 {
1416
1417 if (ep->ex_defdir) {
1418 free_host(ep->ex_defdir->dp_hosts);
1419 free((caddr_t)ep->ex_defdir);
1420 }
1421 if (ep->ex_fsdir)
1422 free(ep->ex_fsdir);
1423 free_dir(ep->ex_dirl);
1424 free((caddr_t)ep);
1425 }
1426
1427 /*
1428 * Free hosts.
1429 */
1430 void
1431 free_host(hp)
1432 struct hostlist *hp;
1433 {
1434 struct hostlist *hp2;
1435
1436 while (hp) {
1437 hp2 = hp;
1438 hp = hp->ht_next;
1439 free((caddr_t)hp2);
1440 }
1441 }
1442
1443 struct hostlist *
1444 get_ht()
1445 {
1446 struct hostlist *hp;
1447
1448 hp = (struct hostlist *)malloc(sizeof (struct hostlist));
1449 if (hp == (struct hostlist *)NULL)
1450 out_of_mem();
1451 hp->ht_next = (struct hostlist *)NULL;
1452 hp->ht_flag = 0;
1453 return (hp);
1454 }
1455
1456 #ifdef ISO
1457 /*
1458 * Translate an iso address.
1459 */
1460 get_isoaddr(cp, grp)
1461 char *cp;
1462 struct grouplist *grp;
1463 {
1464 struct iso_addr *isop;
1465 struct sockaddr_iso *isoaddr;
1466
1467 if (grp->gr_type != GT_NULL)
1468 return (1);
1469 if ((isop = iso_addr(cp)) == NULL) {
1470 syslog(LOG_ERR,
1471 "iso_addr failed, ignored");
1472 return (1);
1473 }
1474 isoaddr = (struct sockaddr_iso *)
1475 malloc(sizeof (struct sockaddr_iso));
1476 if (isoaddr == (struct sockaddr_iso *)NULL)
1477 out_of_mem();
1478 memset(isoaddr, 0, sizeof(struct sockaddr_iso));
1479 memcpy(&isoaddr->siso_addr, isop, sizeof(struct iso_addr));
1480 isoaddr->siso_len = sizeof(struct sockaddr_iso);
1481 isoaddr->siso_family = AF_ISO;
1482 grp->gr_type = GT_ISO;
1483 grp->gr_ptr.gt_isoaddr = isoaddr;
1484 return (0);
1485 }
1486 #endif /* ISO */
1487
1488 /*
1489 * Out of memory, fatal
1490 */
1491 void
1492 out_of_mem()
1493 {
1494
1495 syslog(LOG_ERR, "Out of memory");
1496 exit(2);
1497 }
1498
1499 /*
1500 * Do the mount syscall with the update flag to push the export info into
1501 * the kernel.
1502 */
1503 int
1504 do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
1505 struct exportlist *ep;
1506 struct grouplist *grp;
1507 int exflags;
1508 struct ucred *anoncrp;
1509 char *dirp;
1510 int dirplen;
1511 struct statfs *fsb;
1512 {
1513 char *cp = (char *)NULL;
1514 u_long **addrp;
1515 int done;
1516 char savedc = '\0';
1517 struct sockaddr_in sin, imask;
1518 union {
1519 struct ufs_args ua;
1520 struct iso_args ia;
1521 struct mfs_args ma;
1522 struct msdosfs_args da;
1523 struct adosfs_args aa;
1524 } args;
1525 u_long net;
1526
1527 args.ua.fspec = 0;
1528 args.ua.export.ex_flags = exflags;
1529 args.ua.export.ex_anon = *anoncrp;
1530 memset(&sin, 0, sizeof(sin));
1531 memset(&imask, 0, sizeof(imask));
1532 sin.sin_family = AF_INET;
1533 sin.sin_len = sizeof(sin);
1534 imask.sin_family = AF_INET;
1535 imask.sin_len = sizeof(sin);
1536 if (grp->gr_type == GT_HOST)
1537 addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list;
1538 else
1539 addrp = (u_long **)NULL;
1540 done = FALSE;
1541 while (!done) {
1542 switch (grp->gr_type) {
1543 case GT_HOST:
1544 if (addrp) {
1545 sin.sin_addr.s_addr = **addrp;
1546 args.ua.export.ex_addrlen = sizeof(sin);
1547 } else
1548 args.ua.export.ex_addrlen = 0;
1549 args.ua.export.ex_addr = (struct sockaddr *)&sin;
1550 args.ua.export.ex_masklen = 0;
1551 break;
1552 case GT_NET:
1553 if (grp->gr_ptr.gt_net.nt_mask)
1554 imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
1555 else {
1556 net = ntohl(grp->gr_ptr.gt_net.nt_net);
1557 if (IN_CLASSA(net))
1558 imask.sin_addr.s_addr = inet_addr("255.0.0.0");
1559 else if (IN_CLASSB(net))
1560 imask.sin_addr.s_addr =
1561 inet_addr("255.255.0.0");
1562 else
1563 imask.sin_addr.s_addr =
1564 inet_addr("255.255.255.0");
1565 grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
1566 }
1567 sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
1568 args.ua.export.ex_addr = (struct sockaddr *)&sin;
1569 args.ua.export.ex_addrlen = sizeof (sin);
1570 args.ua.export.ex_mask = (struct sockaddr *)&imask;
1571 args.ua.export.ex_masklen = sizeof (imask);
1572 break;
1573 #ifdef ISO
1574 case GT_ISO:
1575 args.ua.export.ex_addr =
1576 (struct sockaddr *)grp->gr_ptr.gt_isoaddr;
1577 args.ua.export.ex_addrlen =
1578 sizeof(struct sockaddr_iso);
1579 args.ua.export.ex_masklen = 0;
1580 break;
1581 #endif /* ISO */
1582 default:
1583 syslog(LOG_ERR, "Bad grouptype");
1584 if (cp)
1585 *cp = savedc;
1586 return (1);
1587 };
1588
1589 /*
1590 * XXX:
1591 * Maybe I should just use the fsb->f_mntonname path instead
1592 * of looping back up the dirp to the mount point??
1593 * Also, needs to know how to export all types of local
1594 * exportable file systems and not just MOUNT_FFS.
1595 */
1596 while (mount(fsb->f_fstypename, dirp,
1597 fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
1598 if (cp)
1599 *cp-- = savedc;
1600 else
1601 cp = dirp + dirplen - 1;
1602 if (errno == EPERM) {
1603 syslog(LOG_ERR,
1604 "Can't change attributes for %s to %s.\n",
1605 dirp, (grp->gr_type == GT_HOST) ?
1606 grp->gr_ptr.gt_hostent->h_name :
1607 (grp->gr_type == GT_NET) ?
1608 grp->gr_ptr.gt_net.nt_name :
1609 "Unknown");
1610 return (1);
1611 }
1612 if (opt_flags & OP_ALLDIRS) {
1613 syslog(LOG_ERR, "Could not remount %s: %m",
1614 dirp);
1615 return (1);
1616 }
1617 /* back up over the last component */
1618 while (*cp == '/' && cp > dirp)
1619 cp--;
1620 while (*(cp - 1) != '/' && cp > dirp)
1621 cp--;
1622 if (cp == dirp) {
1623 if (debug)
1624 fprintf(stderr,"mnt unsucc\n");
1625 syslog(LOG_ERR, "Can't export %s", dirp);
1626 return (1);
1627 }
1628 savedc = *cp;
1629 *cp = '\0';
1630 }
1631 if (addrp) {
1632 ++addrp;
1633 if (*addrp == (u_long *)NULL)
1634 done = TRUE;
1635 } else
1636 done = TRUE;
1637 }
1638 if (cp)
1639 *cp = savedc;
1640 return (0);
1641 }
1642
1643 /*
1644 * Translate a net address.
1645 */
1646 int
1647 get_net(cp, net, maskflg)
1648 char *cp;
1649 struct netmsk *net;
1650 int maskflg;
1651 {
1652 struct netent *np;
1653 long netaddr;
1654 struct in_addr inetaddr, inetaddr2;
1655 char *name;
1656
1657 if (np = getnetbyname(cp))
1658 inetaddr = inet_makeaddr(np->n_net, 0);
1659 else if (isdigit(*cp)) {
1660 if ((netaddr = inet_network(cp)) == -1)
1661 return (1);
1662 inetaddr = inet_makeaddr(netaddr, 0);
1663 /*
1664 * Due to arbritrary subnet masks, you don't know how many
1665 * bits to shift the address to make it into a network,
1666 * however you do know how to make a network address into
1667 * a host with host == 0 and then compare them.
1668 * (What a pest)
1669 */
1670 if (!maskflg) {
1671 setnetent(0);
1672 while (np = getnetent()) {
1673 inetaddr2 = inet_makeaddr(np->n_net, 0);
1674 if (inetaddr2.s_addr == inetaddr.s_addr)
1675 break;
1676 }
1677 endnetent();
1678 }
1679 } else
1680 return (1);
1681 if (maskflg)
1682 net->nt_mask = inetaddr.s_addr;
1683 else {
1684 if (np)
1685 name = np->n_name;
1686 else
1687 name = inet_ntoa(inetaddr);
1688 net->nt_name = (char *)malloc(strlen(name) + 1);
1689 if (net->nt_name == (char *)NULL)
1690 out_of_mem();
1691 strcpy(net->nt_name, name);
1692 net->nt_net = inetaddr.s_addr;
1693 }
1694 return (0);
1695 }
1696
1697 /*
1698 * Parse out the next white space separated field
1699 */
1700 void
1701 nextfield(cp, endcp)
1702 char **cp;
1703 char **endcp;
1704 {
1705 char *p;
1706
1707 p = *cp;
1708 while (*p == ' ' || *p == '\t')
1709 p++;
1710 if (*p == '\n' || *p == '\0')
1711 *cp = *endcp = p;
1712 else {
1713 *cp = p++;
1714 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
1715 p++;
1716 *endcp = p;
1717 }
1718 }
1719
1720 /*
1721 * Get an exports file line. Skip over blank lines and handle line
1722 * continuations.
1723 */
1724 int
1725 get_line()
1726 {
1727 char *p, *cp;
1728 int len;
1729 int totlen, cont_line;
1730
1731 /*
1732 * Loop around ignoring blank lines and getting all continuation lines.
1733 */
1734 p = line;
1735 totlen = 0;
1736 do {
1737 if (fgets(p, LINESIZ - totlen, exp_file) == NULL)
1738 return (0);
1739 len = strlen(p);
1740 cp = p + len - 1;
1741 cont_line = 0;
1742 while (cp >= p &&
1743 (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
1744 if (*cp == '\\')
1745 cont_line = 1;
1746 cp--;
1747 len--;
1748 }
1749 *++cp = '\0';
1750 if (len > 0) {
1751 totlen += len;
1752 if (totlen >= LINESIZ) {
1753 syslog(LOG_ERR, "Exports line too long");
1754 exit(2);
1755 }
1756 p = cp;
1757 }
1758 } while (totlen == 0 || cont_line);
1759 return (1);
1760 }
1761
1762 /*
1763 * Parse a description of a credential.
1764 */
1765 void
1766 parsecred(namelist, cr)
1767 char *namelist;
1768 struct ucred *cr;
1769 {
1770 char *name;
1771 int cnt;
1772 char *names;
1773 struct passwd *pw;
1774 struct group *gr;
1775 int ngroups, groups[NGROUPS + 1];
1776
1777 /*
1778 * Set up the unpriviledged user.
1779 */
1780 cr->cr_ref = 1;
1781 cr->cr_uid = -2;
1782 cr->cr_gid = -2;
1783 cr->cr_ngroups = 0;
1784 /*
1785 * Get the user's password table entry.
1786 */
1787 names = strsep(&namelist, " \t\n");
1788 name = strsep(&names, ":");
1789 if (isdigit(*name) || *name == '-')
1790 pw = getpwuid(atoi(name));
1791 else
1792 pw = getpwnam(name);
1793 /*
1794 * Credentials specified as those of a user.
1795 */
1796 if (names == NULL) {
1797 if (pw == NULL) {
1798 syslog(LOG_ERR, "Unknown user: %s", name);
1799 return;
1800 }
1801 cr->cr_uid = pw->pw_uid;
1802 ngroups = NGROUPS + 1;
1803 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
1804 syslog(LOG_ERR, "Too many groups");
1805 /*
1806 * Convert from int's to gid_t's and compress out duplicate
1807 */
1808 cr->cr_ngroups = ngroups - 1;
1809 cr->cr_gid = groups[0];
1810 for (cnt = 1; cnt < ngroups; cnt++)
1811 cr->cr_groups[cnt - 1] = groups[cnt];
1812 return;
1813 }
1814 /*
1815 * Explicit credential specified as a colon separated list:
1816 * uid:gid:gid:...
1817 */
1818 if (pw != NULL)
1819 cr->cr_uid = pw->pw_uid;
1820 else if (isdigit(*name) || *name == '-')
1821 cr->cr_uid = atoi(name);
1822 else {
1823 syslog(LOG_ERR, "Unknown user: %s", name);
1824 return;
1825 }
1826 cr->cr_ngroups = 0;
1827 while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
1828 name = strsep(&names, ":");
1829 if (isdigit(*name) || *name == '-') {
1830 cr->cr_groups[cr->cr_ngroups++] = atoi(name);
1831 } else {
1832 if ((gr = getgrnam(name)) == NULL) {
1833 syslog(LOG_ERR, "Unknown group: %s", name);
1834 continue;
1835 }
1836 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
1837 }
1838 }
1839 if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
1840 syslog(LOG_ERR, "Too many groups");
1841 }
1842
1843 #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
1844 /*
1845 * Routines that maintain the remote mounttab
1846 */
1847 void
1848 get_mountlist()
1849 {
1850 struct mountlist *mlp, **mlpp;
1851 char *host, *dirp, *cp;
1852 char str[STRSIZ];
1853 FILE *mlfile;
1854
1855 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
1856 syslog(LOG_ERR, "Can't open %s: %m", _PATH_RMOUNTLIST);
1857 return;
1858 }
1859 mlpp = &mlhead;
1860 while (fgets(str, STRSIZ, mlfile) != NULL) {
1861 cp = str;
1862 host = strsep(&cp, " \t\n");
1863 dirp = strsep(&cp, " \t\n");
1864 if (host == NULL || dirp == NULL)
1865 continue;
1866 mlp = (struct mountlist *)malloc(sizeof (*mlp));
1867 strncpy(mlp->ml_host, host, RPCMNT_NAMELEN);
1868 mlp->ml_host[RPCMNT_NAMELEN] = '\0';
1869 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
1870 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
1871 mlp->ml_next = (struct mountlist *)NULL;
1872 *mlpp = mlp;
1873 mlpp = &mlp->ml_next;
1874 }
1875 fclose(mlfile);
1876 }
1877
1878 void
1879 del_mlist(hostp, dirp)
1880 char *hostp, *dirp;
1881 {
1882 struct mountlist *mlp, **mlpp;
1883 struct mountlist *mlp2;
1884 FILE *mlfile;
1885 int fnd = 0;
1886
1887 mlpp = &mlhead;
1888 mlp = mlhead;
1889 while (mlp) {
1890 if (!strcmp(mlp->ml_host, hostp) &&
1891 (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
1892 fnd = 1;
1893 mlp2 = mlp;
1894 *mlpp = mlp = mlp->ml_next;
1895 free((caddr_t)mlp2);
1896 } else {
1897 mlpp = &mlp->ml_next;
1898 mlp = mlp->ml_next;
1899 }
1900 }
1901 if (fnd) {
1902 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
1903 syslog(LOG_ERR,"Can't update %s: %m", _PATH_RMOUNTLIST);
1904 return;
1905 }
1906 mlp = mlhead;
1907 while (mlp) {
1908 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
1909 mlp = mlp->ml_next;
1910 }
1911 fclose(mlfile);
1912 }
1913 }
1914
1915 void
1916 add_mlist(hostp, dirp)
1917 char *hostp, *dirp;
1918 {
1919 struct mountlist *mlp, **mlpp;
1920 FILE *mlfile;
1921
1922 mlpp = &mlhead;
1923 mlp = mlhead;
1924 while (mlp) {
1925 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
1926 return;
1927 mlpp = &mlp->ml_next;
1928 mlp = mlp->ml_next;
1929 }
1930 mlp = (struct mountlist *)malloc(sizeof (*mlp));
1931 strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
1932 mlp->ml_host[RPCMNT_NAMELEN] = '\0';
1933 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
1934 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
1935 mlp->ml_next = (struct mountlist *)NULL;
1936 *mlpp = mlp;
1937 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
1938 syslog(LOG_ERR, "Can't update %s: %m", _PATH_RMOUNTLIST);
1939 return;
1940 }
1941 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
1942 fclose(mlfile);
1943 }
1944
1945 /*
1946 * This function is called via. SIGTERM when the system is going down.
1947 * It sends a broadcast RPCMNT_UMNTALL.
1948 */
1949 void
1950 send_umntall()
1951 {
1952 (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
1953 xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
1954 exit(0);
1955 }
1956
1957 int
1958 umntall_each(resultsp, raddr)
1959 caddr_t resultsp;
1960 struct sockaddr_in *raddr;
1961 {
1962 return (1);
1963 }
1964
1965 /*
1966 * Free up a group list.
1967 */
1968 void
1969 free_grp(grp)
1970 struct grouplist *grp;
1971 {
1972 char **addrp;
1973
1974 if (grp->gr_type == GT_HOST) {
1975 if (grp->gr_ptr.gt_hostent->h_name) {
1976 addrp = grp->gr_ptr.gt_hostent->h_addr_list;
1977 while (addrp && *addrp)
1978 free(*addrp++);
1979 free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
1980 free(grp->gr_ptr.gt_hostent->h_name);
1981 }
1982 free((caddr_t)grp->gr_ptr.gt_hostent);
1983 } else if (grp->gr_type == GT_NET) {
1984 if (grp->gr_ptr.gt_net.nt_name)
1985 free(grp->gr_ptr.gt_net.nt_name);
1986 }
1987 #ifdef ISO
1988 else if (grp->gr_type == GT_ISO)
1989 free((caddr_t)grp->gr_ptr.gt_isoaddr);
1990 #endif
1991 free((caddr_t)grp);
1992 }
1993
1994 void
1995 SYSLOG(int pri, const char *fmt, ...)
1996 {
1997 va_list ap;
1998
1999 va_start(ap, fmt);
2000
2001 if (debug)
2002 vfprintf(stderr, fmt, ap);
2003 else
2004 vsyslog(pri, fmt, ap);
2005
2006 va_end(ap);
2007 }
2008
2009 /*
2010 * Check options for consistency.
2011 */
2012 int
2013 check_options(dp)
2014 struct dirlist *dp;
2015 {
2016
2017 if (dp == (struct dirlist *)NULL)
2018 return (1);
2019 if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) ||
2020 (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) ||
2021 (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) {
2022 syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive");
2023 return (1);
2024 }
2025 if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
2026 syslog(LOG_ERR, "-mask requires -net");
2027 return (1);
2028 }
2029 if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) {
2030 syslog(LOG_ERR, "-net and -iso mutually exclusive");
2031 return (1);
2032 }
2033 if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
2034 syslog(LOG_ERR, "-alldir has multiple directories");
2035 return (1);
2036 }
2037 return (0);
2038 }
2039
2040 /*
2041 * Check an absolute directory path for any symbolic links. Return true
2042 * if no symbolic links are found.
2043 */
2044 int
2045 check_dirpath(dirp)
2046 char *dirp;
2047 {
2048 char *cp;
2049 int ret = 1;
2050 struct stat sb;
2051
2052 cp = dirp + 1;
2053 while (*cp && ret) {
2054 if (*cp == '/') {
2055 *cp = '\0';
2056 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
2057 ret = 0;
2058 *cp = '/';
2059 }
2060 cp++;
2061 }
2062 if (lstat(dirp, &sb) < 0 ||
2063 (!S_ISDIR(sb.st_mode) && !S_ISREG(sb.st_mode)))
2064 ret = 0;
2065 return (ret);
2066 }
2067