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