minor bug reported by cgd that doesn't affect operation of command
[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
a7bcb6c2 18static char sccsid[] = "@(#)mountd.c 8.10 (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);
749 goto nextline;
750 }
751 } else if (get_host(cp, grp)) {
752 getexp_err(ep, tgrp);
753 goto nextline;
754 }
755 has_host = TRUE;
756 } while (netgrp && getnetgrent(&hst, &usr, &dom));
757 endnetgrent();
e2d13e81
KM
758 *endcp = savedc;
759 }
760 cp = endcp;
761 nextfield(&cp, &endcp);
762 len = endcp - cp;
763 }
764 if (check_options(dirhead)) {
bf8bfd86 765 getexp_err(ep, tgrp);
2faf3d0a 766 goto nextline;
e4fde528 767 }
e2d13e81
KM
768 if (!has_host) {
769 grp->gr_type = GT_HOST;
770 if (debug)
771 fprintf(stderr,"Adding a default entry\n");
772 /* add a default group and make the grp list NULL */
773 hpe = (struct hostent *)malloc(sizeof(struct hostent));
9c1ead23 774 if (hpe == (struct hostent *)NULL)
e2d13e81
KM
775 out_of_mem();
776 hpe->h_name = "Default";
777 hpe->h_addrtype = AF_INET;
778 hpe->h_length = sizeof (u_long);
9c1ead23 779 hpe->h_addr_list = (char **)NULL;
e2d13e81 780 grp->gr_ptr.gt_hostent = hpe;
bf8bfd86
KM
781
782 /*
783 * Don't allow a network export coincide with a list of
784 * host(s) on the same line.
785 */
786 } else if ((opt_flags & OP_NET) && tgrp->gr_next) {
787 getexp_err(ep, tgrp);
788 goto nextline;
e2d13e81 789 }
bf8bfd86
KM
790
791 /*
792 * Loop through hosts, pushing the exports into the kernel.
793 * After loop, tgrp points to the start of the list and
794 * grp points to the last entry in the list.
795 */
796 grp = tgrp;
797 do {
798 if (do_mount(ep, grp, exflags, &anon, dirp,
e2d13e81 799 dirplen, &fsb)) {
bf8bfd86 800 getexp_err(ep, tgrp);
e2d13e81 801 goto nextline;
bf8bfd86
KM
802 }
803 } while (grp->gr_next && (grp = grp->gr_next));
e2d13e81
KM
804
805 /*
806 * Success. Update the data structures.
807 */
808 if (has_host) {
bf8bfd86 809 hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS));
e2d13e81 810 grp->gr_next = grphead;
bf8bfd86 811 grphead = tgrp;
e2d13e81 812 } else {
9c1ead23 813 hang_dirp(dirhead, (struct grouplist *)NULL, ep,
bf8bfd86 814 (opt_flags & OP_ALLDIRS));
e2d13e81
KM
815 free_grp(grp);
816 }
9c1ead23 817 dirhead = (struct dirlist *)NULL;
e2d13e81
KM
818 if ((ep->ex_flag & EX_LINKED) == 0) {
819 ep2 = exphead;
820 epp = &exphead;
821
822 /*
823 * Insert in the list in alphabetical order.
824 */
825 while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
826 epp = &ep2->ex_next;
827 ep2 = ep2->ex_next;
828 }
829 if (ep2)
830 ep->ex_next = ep2;
831 *epp = ep;
832 ep->ex_flag |= EX_LINKED;
833 }
834nextline:
835 if (dirhead) {
836 free_dir(dirhead);
9c1ead23 837 dirhead = (struct dirlist *)NULL;
e2d13e81
KM
838 }
839 }
840 fclose(exp_file);
841}
842
843/*
844 * Allocate an export list element
845 */
846struct exportlist *
847get_exp()
848{
9c1ead23 849 struct exportlist *ep;
e2d13e81
KM
850
851 ep = (struct exportlist *)malloc(sizeof (struct exportlist));
9c1ead23 852 if (ep == (struct exportlist *)NULL)
e2d13e81
KM
853 out_of_mem();
854 bzero((caddr_t)ep, sizeof (struct exportlist));
855 return (ep);
856}
857
858/*
859 * Allocate a group list element
860 */
861struct grouplist *
862get_grp()
863{
9c1ead23 864 struct grouplist *gp;
e2d13e81
KM
865
866 gp = (struct grouplist *)malloc(sizeof (struct grouplist));
9c1ead23 867 if (gp == (struct grouplist *)NULL)
e2d13e81
KM
868 out_of_mem();
869 bzero((caddr_t)gp, sizeof (struct grouplist));
870 return (gp);
871}
872
873/*
874 * Clean up upon an error in get_exportlist().
875 */
876void
877getexp_err(ep, grp)
878 struct exportlist *ep;
879 struct grouplist *grp;
880{
bf8bfd86 881 struct grouplist *tgrp;
e2d13e81
KM
882
883 syslog(LOG_ERR, "Bad exports list line %s", line);
ffb7ccf0 884 if (ep && (ep->ex_flag & EX_LINKED) == 0)
e2d13e81 885 free_exp(ep);
bf8bfd86
KM
886 while (grp) {
887 tgrp = grp;
888 grp = grp->gr_next;
889 free_grp(tgrp);
890 }
e2d13e81
KM
891}
892
893/*
894 * Search the export list for a matching fs.
895 */
896struct exportlist *
897ex_search(fsid)
cdfb534d 898 fsid_t *fsid;
e2d13e81 899{
9c1ead23 900 struct exportlist *ep;
e2d13e81
KM
901
902 ep = exphead;
903 while (ep) {
904 if (ep->ex_fs.val[0] == fsid->val[0] &&
905 ep->ex_fs.val[1] == fsid->val[1])
906 return (ep);
907 ep = ep->ex_next;
908 }
909 return (ep);
910}
911
912/*
913 * Add a directory path to the list.
914 */
915char *
916add_expdir(dpp, cp, len)
917 struct dirlist **dpp;
918 char *cp;
919 int len;
920{
9c1ead23 921 struct dirlist *dp;
e2d13e81
KM
922
923 dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
924 dp->dp_left = *dpp;
9c1ead23 925 dp->dp_right = (struct dirlist *)NULL;
e2d13e81 926 dp->dp_flag = 0;
9c1ead23 927 dp->dp_hosts = (struct hostlist *)NULL;
e2d13e81
KM
928 strcpy(dp->dp_dirp, cp);
929 *dpp = dp;
930 return (dp->dp_dirp);
931}
932
933/*
934 * Hang the dir list element off the dirpath binary tree as required
935 * and update the entry for host.
936 */
937void
938hang_dirp(dp, grp, ep, alldirs)
9c1ead23 939 struct dirlist *dp;
e2d13e81
KM
940 struct grouplist *grp;
941 struct exportlist *ep;
942 int alldirs;
943{
9c1ead23 944 struct hostlist *hp;
e2d13e81
KM
945 struct dirlist *dp2;
946
947 if (alldirs) {
948 if (ep->ex_defdir)
949 free((caddr_t)dp);
950 else
951 ep->ex_defdir = dp;
9c1ead23 952 if (grp == (struct grouplist *)NULL)
171215af
KM
953 ep->ex_defdir->dp_flag |= DP_DEFSET;
954 else while (grp) {
e2d13e81
KM
955 hp = get_ht();
956 hp->ht_grp = grp;
957 hp->ht_next = ep->ex_defdir->dp_hosts;
958 ep->ex_defdir->dp_hosts = hp;
171215af
KM
959 grp = grp->gr_next;
960 }
e2d13e81 961 } else {
bf8bfd86
KM
962
963 /*
964 * Loop throught the directories adding them to the tree.
965 */
e2d13e81 966 while (dp) {
e2d13e81 967 dp2 = dp->dp_left;
bf8bfd86 968 add_dlist(&ep->ex_dirl, dp, grp);
e2d13e81
KM
969 dp = dp2;
970 }
971 }
972}
973
974/*
975 * Traverse the binary tree either updating a node that is already there
976 * for the new directory or adding the new node.
977 */
978void
bf8bfd86 979add_dlist(dpp, newdp, grp)
e2d13e81
KM
980 struct dirlist **dpp;
981 struct dirlist *newdp;
9c1ead23 982 struct grouplist *grp;
e2d13e81 983{
9c1ead23
JSP
984 struct dirlist *dp;
985 struct hostlist *hp;
e2d13e81
KM
986 int cmp;
987
988 dp = *dpp;
989 if (dp) {
990 cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
991 if (cmp > 0) {
bf8bfd86 992 add_dlist(&dp->dp_left, newdp, grp);
e2d13e81
KM
993 return;
994 } else if (cmp < 0) {
bf8bfd86 995 add_dlist(&dp->dp_right, newdp, grp);
e2d13e81
KM
996 return;
997 } else
998 free((caddr_t)newdp);
999 } else {
1000 dp = newdp;
9c1ead23 1001 dp->dp_left = (struct dirlist *)NULL;
e2d13e81
KM
1002 *dpp = dp;
1003 }
bf8bfd86
KM
1004 if (grp) {
1005
1006 /*
1007 * Hang all of the host(s) off of the directory point.
1008 */
1009 do {
1010 hp = get_ht();
1011 hp->ht_grp = grp;
1012 hp->ht_next = dp->dp_hosts;
1013 dp->dp_hosts = hp;
1014 grp = grp->gr_next;
1015 } while (grp);
e2d13e81
KM
1016 } else
1017 dp->dp_flag |= DP_DEFSET;
1018}
1019
1020/*
1021 * Search for a dirpath on the export point.
1022 */
1023struct dirlist *
1024dirp_search(dp, dirpath)
9c1ead23 1025 struct dirlist *dp;
e2d13e81
KM
1026 char *dirpath;
1027{
9c1ead23 1028 int cmp;
e2d13e81
KM
1029
1030 if (dp) {
1031 cmp = strcmp(dp->dp_dirp, dirpath);
1032 if (cmp > 0)
1033 return (dirp_search(dp->dp_left, dirpath));
1034 else if (cmp < 0)
1035 return (dirp_search(dp->dp_right, dirpath));
1036 else
1037 return (dp);
1038 }
1039 return (dp);
1040}
1041
1042/*
1043 * Scan for a host match in a directory tree.
1044 */
9c1ead23 1045int
e2d13e81
KM
1046chk_host(dp, saddr, defsetp)
1047 struct dirlist *dp;
1048 u_long saddr;
1049 int *defsetp;
1050{
9c1ead23
JSP
1051 struct hostlist *hp;
1052 struct grouplist *grp;
1053 u_long **addrp;
e2d13e81
KM
1054
1055 if (dp) {
1056 if (dp->dp_flag & DP_DEFSET)
1057 *defsetp = 1;
1058 hp = dp->dp_hosts;
1059 while (hp) {
1060 grp = hp->ht_grp;
1061 switch (grp->gr_type) {
1062 case GT_HOST:
1063 addrp = (u_long **)
1064 grp->gr_ptr.gt_hostent->h_addr_list;
1065 while (*addrp) {
1066 if (**addrp == saddr)
1067 return (1);
1068 addrp++;
1069 }
1070 break;
1071 case GT_NET:
1072 if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
1073 grp->gr_ptr.gt_net.nt_net)
1074 return (1);
1075 break;
1076 };
1077 hp = hp->ht_next;
1078 }
1079 }
1080 return (0);
1081}
1082
1083/*
1084 * Scan tree for a host that matches the address.
1085 */
9c1ead23 1086int
e2d13e81 1087scan_tree(dp, saddr)
9c1ead23 1088 struct dirlist *dp;
e2d13e81
KM
1089 u_long saddr;
1090{
1091 int defset;
1092
1093 if (dp) {
1094 if (scan_tree(dp->dp_left, saddr))
1095 return (1);
1096 if (chk_host(dp, saddr, &defset))
1097 return (1);
1098 if (scan_tree(dp->dp_right, saddr))
1099 return (1);
1100 }
1101 return (0);
1102}
1103
1104/*
1105 * Traverse the dirlist tree and free it up.
1106 */
1107void
1108free_dir(dp)
9c1ead23 1109 struct dirlist *dp;
e2d13e81
KM
1110{
1111
1112 if (dp) {
1113 free_dir(dp->dp_left);
1114 free_dir(dp->dp_right);
1115 free_host(dp->dp_hosts);
1116 free((caddr_t)dp);
1117 }
1118}
1119
1120/*
1121 * Parse the option string and update fields.
1122 * Option arguments may either be -<option>=<value> or
1123 * -<option> <value>
1124 */
9c1ead23 1125int
e2d13e81
KM
1126do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
1127 char **cpp, **endcpp;
1128 struct exportlist *ep;
1129 struct grouplist *grp;
1130 int *has_hostp;
1131 int *exflagsp;
1132 struct ucred *cr;
1133{
9c1ead23 1134 char *cpoptarg, *cpoptend;
e2d13e81
KM
1135 char *cp, *endcp, *cpopt, savedc, savedc2;
1136 int allflag, usedarg;
1137
1138 cpopt = *cpp;
1139 cpopt++;
1140 cp = *endcpp;
1141 savedc = *cp;
1142 *cp = '\0';
1143 while (cpopt && *cpopt) {
1144 allflag = 1;
1145 usedarg = -2;
1146 if (cpoptend = index(cpopt, ',')) {
1147 *cpoptend++ = '\0';
1148 if (cpoptarg = index(cpopt, '='))
1149 *cpoptarg++ = '\0';
1150 } else {
1151 if (cpoptarg = index(cpopt, '='))
1152 *cpoptarg++ = '\0';
1153 else {
1154 *cp = savedc;
1155 nextfield(&cp, &endcp);
1156 **endcpp = '\0';
1157 if (endcp > cp && *cp != '-') {
1158 cpoptarg = cp;
1159 savedc2 = *endcp;
1160 *endcp = '\0';
1161 usedarg = 0;
1162 }
1163 }
1164 }
1165 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
1166 *exflagsp |= MNT_EXRDONLY;
1167 } else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
1168 !(allflag = strcmp(cpopt, "mapall")) ||
1169 !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
1170 usedarg++;
1171 parsecred(cpoptarg, cr);
1172 if (allflag == 0) {
1173 *exflagsp |= MNT_EXPORTANON;
1174 opt_flags |= OP_MAPALL;
1175 } else
1176 opt_flags |= OP_MAPROOT;
1177 } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {
1178 *exflagsp |= MNT_EXKERB;
1179 opt_flags |= OP_KERB;
bf8bfd86
KM
1180 } else if (cpoptarg && (!strcmp(cpopt, "mask") ||
1181 !strcmp(cpopt, "m"))) {
e2d13e81
KM
1182 if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
1183 syslog(LOG_ERR, "Bad mask: %s", cpoptarg);
1184 return (1);
1185 }
1186 usedarg++;
1187 opt_flags |= OP_MASK;
bf8bfd86
KM
1188 } else if (cpoptarg && (!strcmp(cpopt, "network") ||
1189 !strcmp(cpopt, "n"))) {
e2d13e81
KM
1190 if (grp->gr_type != GT_NULL) {
1191 syslog(LOG_ERR, "Network/host conflict");
1192 return (1);
1193 } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
1194 syslog(LOG_ERR, "Bad net: %s", cpoptarg);
1195 return (1);
1196 }
1197 grp->gr_type = GT_NET;
1198 *has_hostp = 1;
1199 usedarg++;
1200 opt_flags |= OP_NET;
1201 } else if (!strcmp(cpopt, "alldirs")) {
1202 opt_flags |= OP_ALLDIRS;
1203#ifdef ISO
1204 } else if (cpoptarg && !strcmp(cpopt, "iso")) {
1205 if (get_isoaddr(cpoptarg, grp)) {
1206 syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg);
1207 return (1);
1208 }
1209 *has_hostp = 1;
1210 usedarg++;
1211 opt_flags |= OP_ISO;
1212#endif /* ISO */
1213 } else {
1214 syslog(LOG_ERR, "Bad opt %s", cpopt);
1215 return (1);
1216 }
1217 if (usedarg >= 0) {
1218 *endcp = savedc2;
1219 **endcpp = savedc;
1220 if (usedarg > 0) {
1221 *cpp = cp;
1222 *endcpp = endcp;
1223 }
1224 return (0);
1225 }
1226 cpopt = cpoptend;
1227 }
1228 **endcpp = savedc;
1229 return (0);
1230}
1231
1232/*
1233 * Translate a character string to the corresponding list of network
1234 * addresses for a hostname.
1235 */
9c1ead23 1236int
e2d13e81
KM
1237get_host(cp, grp)
1238 char *cp;
9c1ead23 1239 struct grouplist *grp;
e2d13e81 1240{
9c1ead23
JSP
1241 struct hostent *hp, *nhp;
1242 char **addrp, **naddrp;
e2d13e81
KM
1243 struct hostent t_host;
1244 int i;
1245 u_long saddr;
1246 char *aptr[2];
1247
1248 if (grp->gr_type != GT_NULL)
1249 return (1);
1250 if ((hp = gethostbyname(cp)) == NULL) {
1251 if (isdigit(*cp)) {
1252 saddr = inet_addr(cp);
1253 if (saddr == -1) {
1254 syslog(LOG_ERR, "Inet_addr failed");
1255 return (1);
1256 }
1257 if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
1258 AF_INET)) == NULL) {
1259 hp = &t_host;
1260 hp->h_name = cp;
1261 hp->h_addrtype = AF_INET;
1262 hp->h_length = sizeof (u_long);
1263 hp->h_addr_list = aptr;
1264 aptr[0] = (char *)&saddr;
9c1ead23 1265 aptr[1] = (char *)NULL;
e2d13e81
KM
1266 }
1267 } else {
1268 syslog(LOG_ERR, "Gethostbyname failed");
1269 return (1);
1270 }
1271 }
1272 grp->gr_type = GT_HOST;
1273 nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
1274 malloc(sizeof(struct hostent));
9c1ead23 1275 if (nhp == (struct hostent *)NULL)
e2d13e81
KM
1276 out_of_mem();
1277 bcopy((caddr_t)hp, (caddr_t)nhp,
1278 sizeof(struct hostent));
1279 i = strlen(hp->h_name)+1;
1280 nhp->h_name = (char *)malloc(i);
9c1ead23 1281 if (nhp->h_name == (char *)NULL)
e2d13e81
KM
1282 out_of_mem();
1283 bcopy(hp->h_name, nhp->h_name, i);
1284 addrp = hp->h_addr_list;
1285 i = 1;
1286 while (*addrp++)
1287 i++;
1288 naddrp = nhp->h_addr_list = (char **)
1289 malloc(i*sizeof(char *));
9c1ead23 1290 if (naddrp == (char **)NULL)
e2d13e81
KM
1291 out_of_mem();
1292 addrp = hp->h_addr_list;
1293 while (*addrp) {
1294 *naddrp = (char *)
1295 malloc(hp->h_length);
9c1ead23 1296 if (*naddrp == (char *)NULL)
e2d13e81
KM
1297 out_of_mem();
1298 bcopy(*addrp, *naddrp,
1299 hp->h_length);
1300 addrp++;
1301 naddrp++;
1302 }
9c1ead23 1303 *naddrp = (char *)NULL;
bf8bfd86
KM
1304 if (debug)
1305 fprintf(stderr, "got host %s\n", hp->h_name);
e2d13e81
KM
1306 return (0);
1307}
1308
1309/*
1310 * Free up an exports list component
1311 */
1312void
1313free_exp(ep)
9c1ead23 1314 struct exportlist *ep;
e2d13e81
KM
1315{
1316
1317 if (ep->ex_defdir) {
1318 free_host(ep->ex_defdir->dp_hosts);
1319 free((caddr_t)ep->ex_defdir);
1320 }
1321 if (ep->ex_fsdir)
1322 free(ep->ex_fsdir);
1323 free_dir(ep->ex_dirl);
1324 free((caddr_t)ep);
1325}
1326
1327/*
1328 * Free hosts.
1329 */
1330void
1331free_host(hp)
9c1ead23 1332 struct hostlist *hp;
e2d13e81 1333{
9c1ead23 1334 struct hostlist *hp2;
e2d13e81
KM
1335
1336 while (hp) {
1337 hp2 = hp;
1338 hp = hp->ht_next;
1339 free((caddr_t)hp2);
1340 }
1341}
1342
1343struct hostlist *
1344get_ht()
1345{
9c1ead23 1346 struct hostlist *hp;
e4fde528 1347
e2d13e81 1348 hp = (struct hostlist *)malloc(sizeof (struct hostlist));
9c1ead23 1349 if (hp == (struct hostlist *)NULL)
e2d13e81 1350 out_of_mem();
9c1ead23 1351 hp->ht_next = (struct hostlist *)NULL;
e2d13e81
KM
1352 return (hp);
1353}
1354
1355#ifdef ISO
1356/*
1357 * Translate an iso address.
1358 */
1359get_isoaddr(cp, grp)
1360 char *cp;
1361 struct grouplist *grp;
1362{
1363 struct iso_addr *isop;
1364 struct sockaddr_iso *isoaddr;
1365
1366 if (grp->gr_type != GT_NULL)
1367 return (1);
1368 if ((isop = iso_addr(cp)) == NULL) {
1369 syslog(LOG_ERR,
1370 "iso_addr failed, ignored");
1371 return (1);
2faf3d0a 1372 }
e2d13e81
KM
1373 isoaddr = (struct sockaddr_iso *)
1374 malloc(sizeof (struct sockaddr_iso));
9c1ead23 1375 if (isoaddr == (struct sockaddr_iso *)NULL)
e2d13e81
KM
1376 out_of_mem();
1377 bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso));
1378 bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr,
1379 sizeof (struct iso_addr));
1380 isoaddr->siso_len = sizeof (struct sockaddr_iso);
1381 isoaddr->siso_family = AF_ISO;
1382 grp->gr_type = GT_ISO;
1383 grp->gr_ptr.gt_isoaddr = isoaddr;
1384 return (0);
1385}
1386#endif /* ISO */
1387
1388/*
1389 * Out of memory, fatal
1390 */
1391void
1392out_of_mem()
1393{
1394
1395 syslog(LOG_ERR, "Out of memory");
2faf3d0a
KM
1396 exit(2);
1397}
1398
e2d13e81
KM
1399/*
1400 * Do the mount syscall with the update flag to push the export info into
1401 * the kernel.
1402 */
9c1ead23 1403int
e2d13e81 1404do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
2faf3d0a
KM
1405 struct exportlist *ep;
1406 struct grouplist *grp;
e2d13e81 1407 int exflags;
2faf3d0a 1408 struct ucred *anoncrp;
e2d13e81
KM
1409 char *dirp;
1410 int dirplen;
1411 struct statfs *fsb;
2faf3d0a 1412{
9c1ead23
JSP
1413 char *cp = (char *)NULL;
1414 u_long **addrp;
e2d13e81 1415 int done;
9c1ead23 1416 char savedc = '\0';
e2d13e81 1417 struct sockaddr_in sin, imask;
2941bd18
MH
1418 union {
1419 struct ufs_args ua;
1420 struct iso_args ia;
1421 struct mfs_args ma;
1422 } args;
e2d13e81 1423 u_long net;
2faf3d0a 1424
2941bd18
MH
1425 args.ua.fspec = 0;
1426 args.ua.export.ex_flags = exflags;
1427 args.ua.export.ex_anon = *anoncrp;
82da00ce
KM
1428 bzero((char *)&sin, sizeof(sin));
1429 bzero((char *)&imask, sizeof(imask));
2faf3d0a 1430 sin.sin_family = AF_INET;
2faf3d0a 1431 sin.sin_len = sizeof(sin);
e2d13e81 1432 imask.sin_family = AF_INET;
e2d13e81
KM
1433 imask.sin_len = sizeof(sin);
1434 if (grp->gr_type == GT_HOST)
2faf3d0a 1435 addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list;
e2d13e81 1436 else
9c1ead23 1437 addrp = (u_long **)NULL;
2faf3d0a 1438 done = FALSE;
e2d13e81
KM
1439 while (!done) {
1440 switch (grp->gr_type) {
1441 case GT_HOST:
e23baac5 1442 if (addrp) {
2faf3d0a 1443 sin.sin_addr.s_addr = **addrp;
2941bd18 1444 args.ua.export.ex_addrlen = sizeof(sin);
e23baac5 1445 } else
2941bd18
MH
1446 args.ua.export.ex_addrlen = 0;
1447 args.ua.export.ex_addr = (struct sockaddr *)&sin;
1448 args.ua.export.ex_masklen = 0;
e2d13e81
KM
1449 break;
1450 case GT_NET:
1451 if (grp->gr_ptr.gt_net.nt_mask)
1452 imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
1453 else {
1454 net = ntohl(grp->gr_ptr.gt_net.nt_net);
1455 if (IN_CLASSA(net))
1456 imask.sin_addr.s_addr = inet_addr("255.0.0.0");
1457 else if (IN_CLASSB(net))
1458 imask.sin_addr.s_addr =
1459 inet_addr("255.255.0.0");
1460 else
1461 imask.sin_addr.s_addr =
1462 inet_addr("255.255.255.0");
1463 grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
1464 }
1465 sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
2941bd18
MH
1466 args.ua.export.ex_addr = (struct sockaddr *)&sin;
1467 args.ua.export.ex_addrlen = sizeof (sin);
1468 args.ua.export.ex_mask = (struct sockaddr *)&imask;
1469 args.ua.export.ex_masklen = sizeof (imask);
e2d13e81 1470 break;
2faf3d0a 1471#ifdef ISO
e2d13e81 1472 case GT_ISO:
2941bd18
MH
1473 args.ua.export.ex_addr =
1474 (struct sockaddr *)grp->gr_ptr.gt_isoaddr;
1475 args.ua.export.ex_addrlen =
1476 sizeof(struct sockaddr_iso);
1477 args.ua.export.ex_masklen = 0;
e2d13e81 1478 break;
2faf3d0a 1479#endif /* ISO */
e2d13e81 1480 default:
2faf3d0a 1481 syslog(LOG_ERR, "Bad grouptype");
e2d13e81
KM
1482 if (cp)
1483 *cp = savedc;
1484 return (1);
1485 };
cdfb534d
KM
1486
1487 /*
1488 * XXX:
1489 * Maybe I should just use the fsb->f_mntonname path instead
1490 * of looping back up the dirp to the mount point??
1491 * Also, needs to know how to export all types of local
1492 * exportable file systems and not just MOUNT_UFS.
1493 */
1494 while (mount(fsb->f_type, dirp,
1495 fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
e2d13e81
KM
1496 if (cp)
1497 *cp-- = savedc;
1498 else
1499 cp = dirp + dirplen - 1;
2faf3d0a
KM
1500 if (errno == EPERM) {
1501 syslog(LOG_ERR,
e2d13e81
KM
1502 "Can't change attributes for %s.\n", dirp);
1503 return (1);
1504 }
1505 if (opt_flags & OP_ALLDIRS) {
1506 syslog(LOG_ERR, "Not root dir");
1507 return (1);
2faf3d0a 1508 }
2faf3d0a 1509 /* back up over the last component */
e2d13e81 1510 while (*cp == '/' && cp > dirp)
2faf3d0a 1511 cp--;
e2d13e81 1512 while (*(cp - 1) != '/' && cp > dirp)
2faf3d0a 1513 cp--;
e2d13e81
KM
1514 if (cp == dirp) {
1515 if (debug)
2faf3d0a 1516 fprintf(stderr,"mnt unsucc\n");
e2d13e81
KM
1517 syslog(LOG_ERR, "Can't export %s", dirp);
1518 return (1);
2faf3d0a
KM
1519 }
1520 savedc = *cp;
1521 *cp = '\0';
1522 }
e2d13e81 1523 if (addrp) {
2faf3d0a 1524 ++addrp;
9c1ead23 1525 if (*addrp == (u_long *)NULL)
2faf3d0a 1526 done = TRUE;
e2d13e81
KM
1527 } else
1528 done = TRUE;
e3ab21d9 1529 }
e2d13e81
KM
1530 if (cp)
1531 *cp = savedc;
1532 return (0);
e3ab21d9
KM
1533}
1534
e2d13e81
KM
1535/*
1536 * Translate a net address.
1537 */
9c1ead23 1538int
e2d13e81
KM
1539get_net(cp, net, maskflg)
1540 char *cp;
1541 struct netmsk *net;
1542 int maskflg;
1543{
9c1ead23
JSP
1544 struct netent *np;
1545 long netaddr;
e2d13e81
KM
1546 struct in_addr inetaddr, inetaddr2;
1547 char *name;
1548
1549 if (np = getnetbyname(cp))
1550 inetaddr = inet_makeaddr(np->n_net, 0);
1551 else if (isdigit(*cp)) {
1552 if ((netaddr = inet_network(cp)) == -1)
1553 return (1);
1554 inetaddr = inet_makeaddr(netaddr, 0);
1555 /*
1556 * Due to arbritrary subnet masks, you don't know how many
1557 * bits to shift the address to make it into a network,
1558 * however you do know how to make a network address into
1559 * a host with host == 0 and then compare them.
1560 * (What a pest)
1561 */
1562 if (!maskflg) {
1563 setnetent(0);
1564 while (np = getnetent()) {
1565 inetaddr2 = inet_makeaddr(np->n_net, 0);
1566 if (inetaddr2.s_addr == inetaddr.s_addr)
1567 break;
1568 }
1569 endnetent();
1570 }
1571 } else
1572 return (1);
1573 if (maskflg)
1574 net->nt_mask = inetaddr.s_addr;
1575 else {
1576 if (np)
1577 name = np->n_name;
1578 else
1579 name = inet_ntoa(inetaddr);
1580 net->nt_name = (char *)malloc(strlen(name) + 1);
9c1ead23 1581 if (net->nt_name == (char *)NULL)
e2d13e81
KM
1582 out_of_mem();
1583 strcpy(net->nt_name, name);
1584 net->nt_net = inetaddr.s_addr;
1585 }
1586 return (0);
1587}
2faf3d0a 1588
e3ab21d9
KM
1589/*
1590 * Parse out the next white space separated field
1591 */
2faf3d0a 1592void
e3ab21d9
KM
1593nextfield(cp, endcp)
1594 char **cp;
1595 char **endcp;
1596{
9c1ead23 1597 char *p;
e3ab21d9
KM
1598
1599 p = *cp;
1600 while (*p == ' ' || *p == '\t')
1601 p++;
e2d13e81 1602 if (*p == '\n' || *p == '\0')
e3ab21d9 1603 *cp = *endcp = p;
e2d13e81
KM
1604 else {
1605 *cp = p++;
1606 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
1607 p++;
1608 *endcp = p;
e3ab21d9 1609 }
e3ab21d9 1610}
c2282441
KM
1611
1612/*
e2d13e81
KM
1613 * Get an exports file line. Skip over blank lines and handle line
1614 * continuations.
c2282441 1615 */
9c1ead23 1616int
e2d13e81 1617get_line()
c2282441 1618{
9c1ead23
JSP
1619 char *p, *cp;
1620 int len;
e2d13e81 1621 int totlen, cont_line;
e4fde528 1622
e2d13e81
KM
1623 /*
1624 * Loop around ignoring blank lines and getting all continuation lines.
1625 */
1626 p = line;
1627 totlen = 0;
1628 do {
1629 if (fgets(p, LINESIZ - totlen, exp_file) == NULL)
1630 return (0);
1631 len = strlen(p);
1632 cp = p + len - 1;
1633 cont_line = 0;
1634 while (cp >= p &&
1635 (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
1636 if (*cp == '\\')
1637 cont_line = 1;
1638 cp--;
1639 len--;
1640 }
1641 *++cp = '\0';
1642 if (len > 0) {
1643 totlen += len;
1644 if (totlen >= LINESIZ) {
1645 syslog(LOG_ERR, "Exports line too long");
1646 exit(2);
1647 }
1648 p = cp;
1649 }
1650 } while (totlen == 0 || cont_line);
1651 return (1);
e4fde528
KM
1652}
1653
2faf3d0a
KM
1654/*
1655 * Parse a description of a credential.
1656 */
9c1ead23 1657void
2faf3d0a
KM
1658parsecred(namelist, cr)
1659 char *namelist;
9c1ead23 1660 struct ucred *cr;
2faf3d0a 1661{
9c1ead23
JSP
1662 char *name;
1663 int cnt;
2faf3d0a
KM
1664 char *names;
1665 struct passwd *pw;
1666 struct group *gr;
1667 int ngroups, groups[NGROUPS + 1];
1668
1669 /*
1670 * Set up the unpriviledged user.
1671 */
1672 cr->cr_ref = 1;
1673 cr->cr_uid = -2;
1674 cr->cr_groups[0] = -2;
1675 cr->cr_ngroups = 1;
1676 /*
1677 * Get the user's password table entry.
1678 */
1679 names = strsep(&namelist, " \t\n");
1680 name = strsep(&names, ":");
1681 if (isdigit(*name) || *name == '-')
1682 pw = getpwuid(atoi(name));
1683 else
1684 pw = getpwnam(name);
1685 /*
1686 * Credentials specified as those of a user.
1687 */
1688 if (names == NULL) {
1689 if (pw == NULL) {
9c1ead23 1690 syslog(LOG_ERR, "Unknown user: %s", name);
2faf3d0a
KM
1691 return;
1692 }
1693 cr->cr_uid = pw->pw_uid;
1694 ngroups = NGROUPS + 1;
1695 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
9c1ead23 1696 syslog(LOG_ERR, "Too many groups");
2faf3d0a
KM
1697 /*
1698 * Convert from int's to gid_t's and compress out duplicate
1699 */
1700 cr->cr_ngroups = ngroups - 1;
1701 cr->cr_groups[0] = groups[0];
1702 for (cnt = 2; cnt < ngroups; cnt++)
1703 cr->cr_groups[cnt - 1] = groups[cnt];
1704 return;
1705 }
1706 /*
1707 * Explicit credential specified as a colon separated list:
1708 * uid:gid:gid:...
1709 */
1710 if (pw != NULL)
1711 cr->cr_uid = pw->pw_uid;
1712 else if (isdigit(*name) || *name == '-')
1713 cr->cr_uid = atoi(name);
1714 else {
9c1ead23 1715 syslog(LOG_ERR, "Unknown user: %s", name);
2faf3d0a
KM
1716 return;
1717 }
1718 cr->cr_ngroups = 0;
1719 while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
1720 name = strsep(&names, ":");
1721 if (isdigit(*name) || *name == '-') {
1722 cr->cr_groups[cr->cr_ngroups++] = atoi(name);
1723 } else {
1724 if ((gr = getgrnam(name)) == NULL) {
9c1ead23 1725 syslog(LOG_ERR, "Unknown group: %s", name);
2faf3d0a
KM
1726 continue;
1727 }
1728 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
1729 }
1730 }
1731 if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
9c1ead23 1732 syslog(LOG_ERR, "Too many groups");
2faf3d0a
KM
1733}
1734
e4fde528
KM
1735#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
1736/*
1737 * Routines that maintain the remote mounttab
1738 */
2faf3d0a
KM
1739void
1740get_mountlist()
e4fde528 1741{
9c1ead23
JSP
1742 struct mountlist *mlp, **mlpp;
1743 char *eos, *dirp;
e4fde528
KM
1744 int len;
1745 char str[STRSIZ];
1746 FILE *mlfile;
1747
0fe25249 1748 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
2faf3d0a 1749 syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST);
e4fde528
KM
1750 return;
1751 }
1752 mlpp = &mlhead;
1753 while (fgets(str, STRSIZ, mlfile) != NULL) {
1754 if ((dirp = index(str, '\t')) == NULL &&
1755 (dirp = index(str, ' ')) == NULL)
1756 continue;
1757 mlp = (struct mountlist *)malloc(sizeof (*mlp));
1758 len = dirp-str;
1759 if (len > RPCMNT_NAMELEN)
1760 len = RPCMNT_NAMELEN;
1761 bcopy(str, mlp->ml_host, len);
1762 mlp->ml_host[len] = '\0';
1763 while (*dirp == '\t' || *dirp == ' ')
1764 dirp++;
1765 if ((eos = index(dirp, '\t')) == NULL &&
1766 (eos = index(dirp, ' ')) == NULL &&
1767 (eos = index(dirp, '\n')) == NULL)
1768 len = strlen(dirp);
1769 else
1770 len = eos-dirp;
1771 if (len > RPCMNT_PATHLEN)
1772 len = RPCMNT_PATHLEN;
1773 bcopy(dirp, mlp->ml_dirp, len);
1774 mlp->ml_dirp[len] = '\0';
9c1ead23 1775 mlp->ml_next = (struct mountlist *)NULL;
e4fde528
KM
1776 *mlpp = mlp;
1777 mlpp = &mlp->ml_next;
1778 }
1779 fclose(mlfile);
1780}
1781
2faf3d0a
KM
1782void
1783del_mlist(hostp, dirp)
9c1ead23 1784 char *hostp, *dirp;
e4fde528 1785{
9c1ead23 1786 struct mountlist *mlp, **mlpp;
0fe25249 1787 struct mountlist *mlp2;
e4fde528
KM
1788 FILE *mlfile;
1789 int fnd = 0;
1790
1791 mlpp = &mlhead;
1792 mlp = mlhead;
1793 while (mlp) {
1794 if (!strcmp(mlp->ml_host, hostp) &&
1795 (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
1796 fnd = 1;
0fe25249
KM
1797 mlp2 = mlp;
1798 *mlpp = mlp = mlp->ml_next;
1799 free((caddr_t)mlp2);
1800 } else {
1801 mlpp = &mlp->ml_next;
1802 mlp = mlp->ml_next;
e4fde528 1803 }
e4fde528
KM
1804 }
1805 if (fnd) {
1806 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
e2d13e81 1807 syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST);
e4fde528
KM
1808 return;
1809 }
1810 mlp = mlhead;
1811 while (mlp) {
1812 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
1813 mlp = mlp->ml_next;
c2282441 1814 }
e4fde528
KM
1815 fclose(mlfile);
1816 }
1817}
1818
2faf3d0a
KM
1819void
1820add_mlist(hostp, dirp)
9c1ead23 1821 char *hostp, *dirp;
e4fde528 1822{
9c1ead23 1823 struct mountlist *mlp, **mlpp;
e4fde528
KM
1824 FILE *mlfile;
1825
1826 mlpp = &mlhead;
1827 mlp = mlhead;
1828 while (mlp) {
1829 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
1830 return;
1831 mlpp = &mlp->ml_next;
1832 mlp = mlp->ml_next;
1833 }
1834 mlp = (struct mountlist *)malloc(sizeof (*mlp));
1835 strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
1836 mlp->ml_host[RPCMNT_NAMELEN] = '\0';
1837 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
1838 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
9c1ead23 1839 mlp->ml_next = (struct mountlist *)NULL;
e4fde528
KM
1840 *mlpp = mlp;
1841 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
e2d13e81 1842 syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST);
e4fde528
KM
1843 return;
1844 }
1845 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
1846 fclose(mlfile);
1847}
1848
1849/*
1850 * This function is called via. SIGTERM when the system is going down.
1851 * It sends a broadcast RPCMNT_UMNTALL.
1852 */
04b79a9c 1853void
e4fde528
KM
1854send_umntall()
1855{
1856 (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
1857 xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
2faf3d0a 1858 exit(0);
e4fde528
KM
1859}
1860
9c1ead23 1861int
e4fde528
KM
1862umntall_each(resultsp, raddr)
1863 caddr_t resultsp;
1864 struct sockaddr_in *raddr;
1865{
1866 return (1);
1867}
1868
2faf3d0a
KM
1869/*
1870 * Free up a group list.
1871 */
1872void
1873free_grp(grp)
9c1ead23 1874 struct grouplist *grp;
2faf3d0a 1875{
9c1ead23 1876 char **addrp;
2faf3d0a 1877
e2d13e81 1878 if (grp->gr_type == GT_HOST) {
0fe25249
KM
1879 if (grp->gr_ptr.gt_hostent->h_name) {
1880 addrp = grp->gr_ptr.gt_hostent->h_addr_list;
1881 while (addrp && *addrp)
1882 free(*addrp++);
1883 free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
1884 free(grp->gr_ptr.gt_hostent->h_name);
1885 }
2faf3d0a 1886 free((caddr_t)grp->gr_ptr.gt_hostent);
e2d13e81
KM
1887 } else if (grp->gr_type == GT_NET) {
1888 if (grp->gr_ptr.gt_net.nt_name)
1889 free(grp->gr_ptr.gt_net.nt_name);
2faf3d0a
KM
1890 }
1891#ifdef ISO
e2d13e81 1892 else if (grp->gr_type == GT_ISO)
2faf3d0a
KM
1893 free((caddr_t)grp->gr_ptr.gt_isoaddr);
1894#endif
1895 free((caddr_t)grp);
1896}
1897
44b35601
KM
1898#ifdef DEBUG
1899void
1900SYSLOG(int pri, const char *fmt, ...)
1901{
1902 va_list ap;
1903
1904 va_start(ap, fmt);
1905 vfprintf(stderr, fmt, ap);
1906 va_end(ap);
1907}
1908#endif /* DEBUG */
e2d13e81
KM
1909
1910/*
1911 * Check options for consistency.
1912 */
9c1ead23 1913int
e2d13e81
KM
1914check_options(dp)
1915 struct dirlist *dp;
1916{
1917
9c1ead23 1918 if (dp == (struct dirlist *)NULL)
e2d13e81
KM
1919 return (1);
1920 if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) ||
1921 (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) ||
1922 (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) {
1923 syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive");
1924 return (1);
1925 }
1926 if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
1927 syslog(LOG_ERR, "-mask requires -net");
1928 return (1);
1929 }
1930 if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) {
1931 syslog(LOG_ERR, "-net and -iso mutually exclusive");
1932 return (1);
1933 }
1934 if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
1935 syslog(LOG_ERR, "-alldir has multiple directories");
1936 return (1);
1937 }
1938 return (0);
1939}
aab9c17c
KB
1940
1941/*
1942 * Check an absolute directory path for any symbolic links. Return true
1943 * if no symbolic links are found.
1944 */
1945int
1946check_dirpath(dirp)
9c1ead23 1947 char *dirp;
aab9c17c 1948{
9c1ead23 1949 char *cp;
aab9c17c
KB
1950 int ret = 1;
1951 struct stat sb;
1952
1953 cp = dirp + 1;
1954 while (*cp && ret) {
1955 if (*cp == '/') {
1956 *cp = '\0';
f16c958f 1957 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
aab9c17c
KB
1958 ret = 0;
1959 *cp = '/';
1960 }
1961 cp++;
1962 }
f16c958f 1963 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
aab9c17c
KB
1964 ret = 0;
1965 return (ret);
1966}