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