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