Deleted Added
full compact
mountd.c (150214) mountd.c (158857)
1/*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Herb Hasler and Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#ifndef lint
34static const char copyright[] =
35"@(#) Copyright (c) 1989, 1993\n\
36 The Regents of the University of California. All rights reserved.\n";
37#endif /*not lint*/
38
39#if 0
40#ifndef lint
41static char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95";
42#endif /*not lint*/
43#endif
44
45#include <sys/cdefs.h>
1/*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Herb Hasler and Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#ifndef lint
34static const char copyright[] =
35"@(#) Copyright (c) 1989, 1993\n\
36 The Regents of the University of California. All rights reserved.\n";
37#endif /*not lint*/
38
39#if 0
40#ifndef lint
41static char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95";
42#endif /*not lint*/
43#endif
44
45#include <sys/cdefs.h>
46__FBSDID("$FreeBSD: head/usr.sbin/mountd/mountd.c 150214 2005-09-16 11:24:28Z pjd $");
46__FBSDID("$FreeBSD: head/usr.sbin/mountd/mountd.c 158857 2006-05-23 17:10:17Z rodrigc $");
47
48#include <sys/param.h>
49#include <sys/mount.h>
50#include <sys/fcntl.h>
51#include <sys/stat.h>
52#include <sys/syslog.h>
53#include <sys/sysctl.h>
54#include <sys/linker.h>
55#include <sys/module.h>
56
57#include <rpc/rpc.h>
58#include <rpc/rpc_com.h>
59#include <rpc/pmap_clnt.h>
60#include <rpc/pmap_prot.h>
61#include <rpcsvc/mount.h>
62#include <nfs/rpcv2.h>
63#include <nfs/nfsproto.h>
64#include <nfsserver/nfs.h>
47
48#include <sys/param.h>
49#include <sys/mount.h>
50#include <sys/fcntl.h>
51#include <sys/stat.h>
52#include <sys/syslog.h>
53#include <sys/sysctl.h>
54#include <sys/linker.h>
55#include <sys/module.h>
56
57#include <rpc/rpc.h>
58#include <rpc/rpc_com.h>
59#include <rpc/pmap_clnt.h>
60#include <rpc/pmap_prot.h>
61#include <rpcsvc/mount.h>
62#include <nfs/rpcv2.h>
63#include <nfs/nfsproto.h>
64#include <nfsserver/nfs.h>
65#include <ufs/ufs/ufsmount.h>
66#include <fs/msdosfs/msdosfsmount.h>
67#include <fs/ntfs/ntfsmount.h>
68#include <isofs/cd9660/cd9660_mount.h> /* XXX need isofs in include */
69
70#include <arpa/inet.h>
71
72#include <ctype.h>
73#include <err.h>
74#include <errno.h>
75#include <grp.h>
76#include <libutil.h>
77#include <limits.h>
78#include <netdb.h>
79#include <pwd.h>
80#include <signal.h>
81#include <stdio.h>
82#include <stdlib.h>
83#include <string.h>
84#include <unistd.h>
85#include "pathnames.h"
65
66#include <arpa/inet.h>
67
68#include <ctype.h>
69#include <err.h>
70#include <errno.h>
71#include <grp.h>
72#include <libutil.h>
73#include <limits.h>
74#include <netdb.h>
75#include <pwd.h>
76#include <signal.h>
77#include <stdio.h>
78#include <stdlib.h>
79#include <string.h>
80#include <unistd.h>
81#include "pathnames.h"
82#include "mntopts.h"
86
87#ifdef DEBUG
88#include <stdarg.h>
89#endif
90
91/*
92 * Structures for keeping the mount list and export list
93 */
94struct mountlist {
95 struct mountlist *ml_next;
96 char ml_host[RPCMNT_NAMELEN+1];
97 char ml_dirp[RPCMNT_PATHLEN+1];
98};
99
100struct dirlist {
101 struct dirlist *dp_left;
102 struct dirlist *dp_right;
103 int dp_flag;
104 struct hostlist *dp_hosts; /* List of hosts this dir exported to */
105 char dp_dirp[1]; /* Actually malloc'd to size of dir */
106};
107/* dp_flag bits */
108#define DP_DEFSET 0x1
109#define DP_HOSTSET 0x2
110
111struct exportlist {
112 struct exportlist *ex_next;
113 struct dirlist *ex_dirl;
114 struct dirlist *ex_defdir;
115 int ex_flag;
116 fsid_t ex_fs;
117 char *ex_fsdir;
118 char *ex_indexfile;
119};
120/* ex_flag bits */
121#define EX_LINKED 0x1
122
123struct netmsk {
124 struct sockaddr_storage nt_net;
125 struct sockaddr_storage nt_mask;
126 char *nt_name;
127};
128
129union grouptypes {
130 struct addrinfo *gt_addrinfo;
131 struct netmsk gt_net;
132};
133
134struct grouplist {
135 int gr_type;
136 union grouptypes gr_ptr;
137 struct grouplist *gr_next;
138};
139/* Group types */
140#define GT_NULL 0x0
141#define GT_HOST 0x1
142#define GT_NET 0x2
143#define GT_DEFAULT 0x3
144#define GT_IGNORE 0x5
145
146struct hostlist {
147 int ht_flag; /* Uses DP_xx bits */
148 struct grouplist *ht_grp;
149 struct hostlist *ht_next;
150};
151
152struct fhreturn {
153 int fhr_flag;
154 int fhr_vers;
155 nfsfh_t fhr_fh;
156};
157
158/* Global defs */
159char *add_expdir(struct dirlist **, char *, int);
160void add_dlist(struct dirlist **, struct dirlist *,
161 struct grouplist *, int);
162void add_mlist(char *, char *);
163int check_dirpath(char *);
164int check_options(struct dirlist *);
165int checkmask(struct sockaddr *sa);
166int chk_host(struct dirlist *, struct sockaddr *, int *, int *);
167void del_mlist(char *hostp, char *dirp);
168struct dirlist *dirp_search(struct dirlist *, char *);
169int do_mount(struct exportlist *, struct grouplist *, int,
170 struct xucred *, char *, int, struct statfs *);
171int do_opt(char **, char **, struct exportlist *, struct grouplist *,
172 int *, int *, struct xucred *);
173struct exportlist *ex_search(fsid_t *);
174struct exportlist *get_exp(void);
175void free_dir(struct dirlist *);
176void free_exp(struct exportlist *);
177void free_grp(struct grouplist *);
178void free_host(struct hostlist *);
179void get_exportlist(void);
180int get_host(char *, struct grouplist *, struct grouplist *);
181struct hostlist *get_ht(void);
182int get_line(void);
183void get_mountlist(void);
184int get_net(char *, struct netmsk *, int);
185void getexp_err(struct exportlist *, struct grouplist *);
186struct grouplist *get_grp(void);
187void hang_dirp(struct dirlist *, struct grouplist *,
188 struct exportlist *, int);
189void huphandler(int sig);
190int makemask(struct sockaddr_storage *ssp, int bitlen);
191void mntsrv(struct svc_req *, SVCXPRT *);
192void nextfield(char **, char **);
193void out_of_mem(void);
194void parsecred(char *, struct xucred *);
195int put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int);
196void *sa_rawaddr(struct sockaddr *sa, int *nbytes);
197int sacmp(struct sockaddr *sa1, struct sockaddr *sa2,
198 struct sockaddr *samask);
199int scan_tree(struct dirlist *, struct sockaddr *);
200static void usage(void);
201int xdr_dir(XDR *, char *);
202int xdr_explist(XDR *, caddr_t);
203int xdr_explist_brief(XDR *, caddr_t);
204int xdr_fhs(XDR *, caddr_t);
205int xdr_mlist(XDR *, caddr_t);
206void terminate(int);
207
208struct exportlist *exphead;
209struct mountlist *mlhead;
210struct grouplist *grphead;
211char exname[MAXPATHLEN];
212struct xucred def_anon = {
213 XUCRED_VERSION,
214 (uid_t)-2,
215 1,
216 { (gid_t)-2 },
217 NULL
218};
219int force_v2 = 0;
220int resvport_only = 1;
221int dir_only = 1;
222int dolog = 0;
223int got_sighup = 0;
224
225int opt_flags;
226static int have_v6 = 1;
227
228struct pidfh *pfh = NULL;
229/* Bits for opt_flags above */
230#define OP_MAPROOT 0x01
231#define OP_MAPALL 0x02
232/* 0x4 free */
233#define OP_MASK 0x08
234#define OP_NET 0x10
235#define OP_ALLDIRS 0x40
236#define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */
237#define OP_QUIET 0x100
238#define OP_MASKLEN 0x200
239
240#ifdef DEBUG
241int debug = 1;
242void SYSLOG(int, const char *, ...) __printflike(2, 3);
243#define syslog SYSLOG
244#else
245int debug = 0;
246#endif
247
248/*
249 * Mountd server for NFS mount protocol as described in:
250 * NFS: Network File System Protocol Specification, RFC1094, Appendix A
251 * The optional arguments are the exports file name
252 * default: _PATH_EXPORTS
253 * and "-n" to allow nonroot mount.
254 */
255int
256main(argc, argv)
257 int argc;
258 char **argv;
259{
260 fd_set readfds;
261 struct sockaddr_in sin;
262 struct sockaddr_in6 sin6;
263 char *endptr;
264 SVCXPRT *udptransp, *tcptransp, *udp6transp, *tcp6transp;
265 struct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf;
266 pid_t otherpid;
267 int udpsock, tcpsock, udp6sock, tcp6sock;
268 int xcreated = 0, s;
269 int maxrec = RPC_MAXDATASIZE;
270 int one = 1;
271 int c, r;
272 in_port_t svcport = 0;
273
274 udp6conf = tcp6conf = NULL;
275 udp6sock = tcp6sock = 0;
276
277 /* Check that another mountd isn't already running. */
278 pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid);
279 if (pfh == NULL) {
280 if (errno == EEXIST)
281 errx(1, "mountd already running, pid: %d.", otherpid);
282 warn("cannot open or create pidfile");
283 }
284
285 s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
286 if (s < 0)
287 have_v6 = 0;
288 else
289 close(s);
290 if (modfind("nfsserver") < 0) {
291 /* Not present in kernel, try loading it */
292 if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0)
293 errx(1, "NFS server is not available or loadable");
294 }
295
296 while ((c = getopt(argc, argv, "2dlnp:r")) != -1)
297 switch (c) {
298 case '2':
299 force_v2 = 1;
300 break;
301 case 'n':
302 resvport_only = 0;
303 break;
304 case 'r':
305 dir_only = 0;
306 break;
307 case 'd':
308 debug = debug ? 0 : 1;
309 break;
310 case 'l':
311 dolog = 1;
312 break;
313 case 'p':
314 endptr = NULL;
315 svcport = (in_port_t)strtoul(optarg, &endptr, 10);
316 if (endptr == NULL || *endptr != '\0' ||
317 svcport == 0 || svcport >= IPPORT_MAX)
318 usage();
319 break;
320 default:
321 usage();
322 };
323 argc -= optind;
324 argv += optind;
325 grphead = (struct grouplist *)NULL;
326 exphead = (struct exportlist *)NULL;
327 mlhead = (struct mountlist *)NULL;
328 if (argc == 1) {
329 strncpy(exname, *argv, MAXPATHLEN-1);
330 exname[MAXPATHLEN-1] = '\0';
331 } else
332 strcpy(exname, _PATH_EXPORTS);
333 openlog("mountd", LOG_PID, LOG_DAEMON);
334 if (debug)
335 warnx("getting export list");
336 get_exportlist();
337 if (debug)
338 warnx("getting mount list");
339 get_mountlist();
340 if (debug)
341 warnx("here we go");
342 if (debug == 0) {
343 daemon(0, 0);
344 signal(SIGINT, SIG_IGN);
345 signal(SIGQUIT, SIG_IGN);
346 }
347 signal(SIGHUP, huphandler);
348 signal(SIGTERM, terminate);
349
350 pidfile_write(pfh);
351
352 rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL);
353 rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL);
354 udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
355 tcpsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
356 udpconf = getnetconfigent("udp");
357 tcpconf = getnetconfigent("tcp");
358
359 rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
360
361 if (!have_v6)
362 goto skip_v6;
363 udp6sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
364 tcp6sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
365 /*
366 * We're doing host-based access checks here, so don't allow
367 * v4-in-v6 to confuse things. The kernel will disable it
368 * by default on NFS sockets too.
369 */
370 if (udp6sock != -1 && setsockopt(udp6sock, IPPROTO_IPV6,
371 IPV6_V6ONLY, &one, sizeof one) < 0) {
372 syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket");
373 exit(1);
374 }
375 if (tcp6sock != -1 && setsockopt(tcp6sock, IPPROTO_IPV6,
376 IPV6_V6ONLY, &one, sizeof one) < 0) {
377 syslog(LOG_ERR, "can't disable v4-in-v6 on TCP socket");
378 exit(1);
379 }
380 udp6conf = getnetconfigent("udp6");
381 tcp6conf = getnetconfigent("tcp6");
382
383skip_v6:
384 if (!resvport_only) {
385 if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL,
386 &resvport_only, sizeof(resvport_only)) != 0 &&
387 errno != ENOENT) {
388 syslog(LOG_ERR, "sysctl: %m");
389 exit(1);
390 }
391 }
392 if (svcport != 0) {
393 bzero(&sin, sizeof(struct sockaddr_in));
394 sin.sin_len = sizeof(struct sockaddr_in);
395 sin.sin_family = AF_INET;
396 sin.sin_port = htons(svcport);
397
398 bzero(&sin6, sizeof(struct sockaddr_in6));
399 sin6.sin6_len = sizeof(struct sockaddr_in6);
400 sin6.sin6_family = AF_INET6;
401 sin6.sin6_port = htons(svcport);
402 }
403 if (udpsock != -1 && udpconf != NULL) {
404 if (svcport != 0) {
405 r = bindresvport(udpsock, &sin);
406 if (r != 0) {
407 syslog(LOG_ERR, "bindresvport: %m");
408 exit(1);
409 }
410 } else
411 (void)bindresvport(udpsock, NULL);
412 udptransp = svc_dg_create(udpsock, 0, 0);
413 if (udptransp != NULL) {
414 if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER1,
415 mntsrv, udpconf))
416 syslog(LOG_WARNING, "can't register UDP RPCMNT_VER1 service");
417 else
418 xcreated++;
419 if (!force_v2) {
420 if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER3,
421 mntsrv, udpconf))
422 syslog(LOG_WARNING, "can't register UDP RPCMNT_VER3 service");
423 else
424 xcreated++;
425 }
426 } else
427 syslog(LOG_WARNING, "can't create UDP services");
428
429 }
430 if (tcpsock != -1 && tcpconf != NULL) {
431 if (svcport != 0) {
432 r = bindresvport(tcpsock, &sin);
433 if (r != 0) {
434 syslog(LOG_ERR, "bindresvport: %m");
435 exit(1);
436 }
437 } else
438 (void)bindresvport(tcpsock, NULL);
439 listen(tcpsock, SOMAXCONN);
440 tcptransp = svc_vc_create(tcpsock, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
441 if (tcptransp != NULL) {
442 if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER1,
443 mntsrv, tcpconf))
444 syslog(LOG_WARNING, "can't register TCP RPCMNT_VER1 service");
445 else
446 xcreated++;
447 if (!force_v2) {
448 if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER3,
449 mntsrv, tcpconf))
450 syslog(LOG_WARNING, "can't register TCP RPCMNT_VER3 service");
451 else
452 xcreated++;
453 }
454 } else
455 syslog(LOG_WARNING, "can't create TCP service");
456
457 }
458 if (have_v6 && udp6sock != -1 && udp6conf != NULL) {
459 if (svcport != 0) {
460 r = bindresvport_sa(udp6sock,
461 (struct sockaddr *)&sin6);
462 if (r != 0) {
463 syslog(LOG_ERR, "bindresvport_sa: %m");
464 exit(1);
465 }
466 } else
467 (void)bindresvport_sa(udp6sock, NULL);
468 udp6transp = svc_dg_create(udp6sock, 0, 0);
469 if (udp6transp != NULL) {
470 if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER1,
471 mntsrv, udp6conf))
472 syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER1 service");
473 else
474 xcreated++;
475 if (!force_v2) {
476 if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER3,
477 mntsrv, udp6conf))
478 syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER3 service");
479 else
480 xcreated++;
481 }
482 } else
483 syslog(LOG_WARNING, "can't create UDP6 service");
484
485 }
486 if (have_v6 && tcp6sock != -1 && tcp6conf != NULL) {
487 if (svcport != 0) {
488 r = bindresvport_sa(tcp6sock,
489 (struct sockaddr *)&sin6);
490 if (r != 0) {
491 syslog(LOG_ERR, "bindresvport_sa: %m");
492 exit(1);
493 }
494 } else
495 (void)bindresvport_sa(tcp6sock, NULL);
496 listen(tcp6sock, SOMAXCONN);
497 tcp6transp = svc_vc_create(tcp6sock, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
498 if (tcp6transp != NULL) {
499 if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER1,
500 mntsrv, tcp6conf))
501 syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER1 service");
502 else
503 xcreated++;
504 if (!force_v2) {
505 if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER3,
506 mntsrv, tcp6conf))
507 syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER3 service");
508 else
509 xcreated++;
510 }
511 } else
512 syslog(LOG_WARNING, "can't create TCP6 service");
513
514 }
515 if (xcreated == 0) {
516 syslog(LOG_ERR, "could not create any services");
517 exit(1);
518 }
519
520 /* Expand svc_run() here so that we can call get_exportlist(). */
521 for (;;) {
522 if (got_sighup) {
523 get_exportlist();
524 got_sighup = 0;
525 }
526 readfds = svc_fdset;
527 switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) {
528 case -1:
529 if (errno == EINTR)
530 continue;
531 syslog(LOG_ERR, "mountd died: select: %m");
532 exit(1);
533 case 0:
534 continue;
535 default:
536 svc_getreqset(&readfds);
537 }
538 }
539}
540
541static void
542usage()
543{
544 fprintf(stderr,
545 "usage: mountd [-2] [-d] [-l] [-n] [-p <port>] [-r] "
546 "[export_file]\n");
547 exit(1);
548}
549
550/*
551 * The mount rpc service
552 */
553void
554mntsrv(rqstp, transp)
555 struct svc_req *rqstp;
556 SVCXPRT *transp;
557{
558 struct exportlist *ep;
559 struct dirlist *dp;
560 struct fhreturn fhr;
561 struct stat stb;
562 struct statfs fsb;
563 char host[NI_MAXHOST], numerichost[NI_MAXHOST];
564 int lookup_failed = 1;
565 struct sockaddr *saddr;
566 u_short sport;
567 char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN];
568 int bad = 0, defset, hostset;
569 sigset_t sighup_mask;
570
571 sigemptyset(&sighup_mask);
572 sigaddset(&sighup_mask, SIGHUP);
573 saddr = svc_getrpccaller(transp)->buf;
574 switch (saddr->sa_family) {
575 case AF_INET6:
576 sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port);
577 break;
578 case AF_INET:
579 sport = ntohs(((struct sockaddr_in *)saddr)->sin_port);
580 break;
581 default:
582 syslog(LOG_ERR, "request from unknown address family");
583 return;
584 }
585 lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host,
586 NULL, 0, 0);
587 getnameinfo(saddr, saddr->sa_len, numerichost,
588 sizeof numerichost, NULL, 0, NI_NUMERICHOST);
589 switch (rqstp->rq_proc) {
590 case NULLPROC:
591 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
592 syslog(LOG_ERR, "can't send reply");
593 return;
594 case RPCMNT_MOUNT:
595 if (sport >= IPPORT_RESERVED && resvport_only) {
596 syslog(LOG_NOTICE,
597 "mount request from %s from unprivileged port",
598 numerichost);
599 svcerr_weakauth(transp);
600 return;
601 }
602 if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) {
603 syslog(LOG_NOTICE, "undecodable mount request from %s",
604 numerichost);
605 svcerr_decode(transp);
606 return;
607 }
608
609 /*
610 * Get the real pathname and make sure it is a directory
611 * or a regular file if the -r option was specified
612 * and it exists.
613 */
614 if (realpath(rpcpath, dirpath) == NULL ||
615 stat(dirpath, &stb) < 0 ||
616 (!S_ISDIR(stb.st_mode) &&
617 (dir_only || !S_ISREG(stb.st_mode))) ||
618 statfs(dirpath, &fsb) < 0) {
619 chdir("/"); /* Just in case realpath doesn't */
620 syslog(LOG_NOTICE,
621 "mount request from %s for non existent path %s",
622 numerichost, dirpath);
623 if (debug)
624 warnx("stat failed on %s", dirpath);
625 bad = ENOENT; /* We will send error reply later */
626 }
627
628 /* Check in the exports list */
629 sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
630 ep = ex_search(&fsb.f_fsid);
631 hostset = defset = 0;
632 if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) ||
633 ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
634 chk_host(dp, saddr, &defset, &hostset)) ||
635 (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
636 scan_tree(ep->ex_dirl, saddr) == 0))) {
637 if (bad) {
638 if (!svc_sendreply(transp, (xdrproc_t)xdr_long,
639 (caddr_t)&bad))
640 syslog(LOG_ERR, "can't send reply");
641 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
642 return;
643 }
644 if (hostset & DP_HOSTSET)
645 fhr.fhr_flag = hostset;
646 else
647 fhr.fhr_flag = defset;
648 fhr.fhr_vers = rqstp->rq_vers;
649 /* Get the file handle */
650 memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t));
651 if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) {
652 bad = errno;
653 syslog(LOG_ERR, "can't get fh for %s", dirpath);
654 if (!svc_sendreply(transp, (xdrproc_t)xdr_long,
655 (caddr_t)&bad))
656 syslog(LOG_ERR, "can't send reply");
657 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
658 return;
659 }
660 if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs,
661 (caddr_t)&fhr))
662 syslog(LOG_ERR, "can't send reply");
663 if (!lookup_failed)
664 add_mlist(host, dirpath);
665 else
666 add_mlist(numerichost, dirpath);
667 if (debug)
668 warnx("mount successful");
669 if (dolog)
670 syslog(LOG_NOTICE,
671 "mount request succeeded from %s for %s",
672 numerichost, dirpath);
673 } else {
674 bad = EACCES;
675 syslog(LOG_NOTICE,
676 "mount request denied from %s for %s",
677 numerichost, dirpath);
678 }
679
680 if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long,
681 (caddr_t)&bad))
682 syslog(LOG_ERR, "can't send reply");
683 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
684 return;
685 case RPCMNT_DUMP:
686 if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL))
687 syslog(LOG_ERR, "can't send reply");
688 else if (dolog)
689 syslog(LOG_NOTICE,
690 "dump request succeeded from %s",
691 numerichost);
692 return;
693 case RPCMNT_UMOUNT:
694 if (sport >= IPPORT_RESERVED && resvport_only) {
695 syslog(LOG_NOTICE,
696 "umount request from %s from unprivileged port",
697 numerichost);
698 svcerr_weakauth(transp);
699 return;
700 }
701 if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) {
702 syslog(LOG_NOTICE, "undecodable umount request from %s",
703 numerichost);
704 svcerr_decode(transp);
705 return;
706 }
707 if (realpath(rpcpath, dirpath) == NULL) {
708 syslog(LOG_NOTICE, "umount request from %s "
709 "for non existent path %s",
710 numerichost, dirpath);
711 }
712 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL))
713 syslog(LOG_ERR, "can't send reply");
714 if (!lookup_failed)
715 del_mlist(host, dirpath);
716 del_mlist(numerichost, dirpath);
717 if (dolog)
718 syslog(LOG_NOTICE,
719 "umount request succeeded from %s for %s",
720 numerichost, dirpath);
721 return;
722 case RPCMNT_UMNTALL:
723 if (sport >= IPPORT_RESERVED && resvport_only) {
724 syslog(LOG_NOTICE,
725 "umountall request from %s from unprivileged port",
726 numerichost);
727 svcerr_weakauth(transp);
728 return;
729 }
730 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL))
731 syslog(LOG_ERR, "can't send reply");
732 if (!lookup_failed)
733 del_mlist(host, NULL);
734 del_mlist(numerichost, NULL);
735 if (dolog)
736 syslog(LOG_NOTICE,
737 "umountall request succeeded from %s",
738 numerichost);
739 return;
740 case RPCMNT_EXPORT:
741 if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL))
742 if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief,
743 (caddr_t)NULL))
744 syslog(LOG_ERR, "can't send reply");
745 if (dolog)
746 syslog(LOG_NOTICE,
747 "export request succeeded from %s",
748 numerichost);
749 return;
750 default:
751 svcerr_noproc(transp);
752 return;
753 }
754}
755
756/*
757 * Xdr conversion for a dirpath string
758 */
759int
760xdr_dir(xdrsp, dirp)
761 XDR *xdrsp;
762 char *dirp;
763{
764 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
765}
766
767/*
768 * Xdr routine to generate file handle reply
769 */
770int
771xdr_fhs(xdrsp, cp)
772 XDR *xdrsp;
773 caddr_t cp;
774{
775 struct fhreturn *fhrp = (struct fhreturn *)cp;
776 u_long ok = 0, len, auth;
777
778 if (!xdr_long(xdrsp, &ok))
779 return (0);
780 switch (fhrp->fhr_vers) {
781 case 1:
782 return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH));
783 case 3:
784 len = NFSX_V3FH;
785 if (!xdr_long(xdrsp, &len))
786 return (0);
787 if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len))
788 return (0);
789 auth = RPCAUTH_UNIX;
790 len = 1;
791 if (!xdr_long(xdrsp, &len))
792 return (0);
793 return (xdr_long(xdrsp, &auth));
794 };
795 return (0);
796}
797
798int
799xdr_mlist(xdrsp, cp)
800 XDR *xdrsp;
801 caddr_t cp;
802{
803 struct mountlist *mlp;
804 int true = 1;
805 int false = 0;
806 char *strp;
807
808 mlp = mlhead;
809 while (mlp) {
810 if (!xdr_bool(xdrsp, &true))
811 return (0);
812 strp = &mlp->ml_host[0];
813 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
814 return (0);
815 strp = &mlp->ml_dirp[0];
816 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
817 return (0);
818 mlp = mlp->ml_next;
819 }
820 if (!xdr_bool(xdrsp, &false))
821 return (0);
822 return (1);
823}
824
825/*
826 * Xdr conversion for export list
827 */
828int
829xdr_explist_common(xdrsp, cp, brief)
830 XDR *xdrsp;
831 caddr_t cp;
832 int brief;
833{
834 struct exportlist *ep;
835 int false = 0;
836 int putdef;
837 sigset_t sighup_mask;
838
839 sigemptyset(&sighup_mask);
840 sigaddset(&sighup_mask, SIGHUP);
841 sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
842 ep = exphead;
843 while (ep) {
844 putdef = 0;
845 if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir,
846 &putdef, brief))
847 goto errout;
848 if (ep->ex_defdir && putdef == 0 &&
849 put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL,
850 &putdef, brief))
851 goto errout;
852 ep = ep->ex_next;
853 }
854 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
855 if (!xdr_bool(xdrsp, &false))
856 return (0);
857 return (1);
858errout:
859 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
860 return (0);
861}
862
863/*
864 * Called from xdr_explist() to traverse the tree and export the
865 * directory paths.
866 */
867int
868put_exlist(dp, xdrsp, adp, putdefp, brief)
869 struct dirlist *dp;
870 XDR *xdrsp;
871 struct dirlist *adp;
872 int *putdefp;
873 int brief;
874{
875 struct grouplist *grp;
876 struct hostlist *hp;
877 int true = 1;
878 int false = 0;
879 int gotalldir = 0;
880 char *strp;
881
882 if (dp) {
883 if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief))
884 return (1);
885 if (!xdr_bool(xdrsp, &true))
886 return (1);
887 strp = dp->dp_dirp;
888 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
889 return (1);
890 if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) {
891 gotalldir = 1;
892 *putdefp = 1;
893 }
894 if (brief) {
895 if (!xdr_bool(xdrsp, &true))
896 return (1);
897 strp = "(...)";
898 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
899 return (1);
900 } else if ((dp->dp_flag & DP_DEFSET) == 0 &&
901 (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) {
902 hp = dp->dp_hosts;
903 while (hp) {
904 grp = hp->ht_grp;
905 if (grp->gr_type == GT_HOST) {
906 if (!xdr_bool(xdrsp, &true))
907 return (1);
908 strp = grp->gr_ptr.gt_addrinfo->ai_canonname;
909 if (!xdr_string(xdrsp, &strp,
910 RPCMNT_NAMELEN))
911 return (1);
912 } else if (grp->gr_type == GT_NET) {
913 if (!xdr_bool(xdrsp, &true))
914 return (1);
915 strp = grp->gr_ptr.gt_net.nt_name;
916 if (!xdr_string(xdrsp, &strp,
917 RPCMNT_NAMELEN))
918 return (1);
919 }
920 hp = hp->ht_next;
921 if (gotalldir && hp == (struct hostlist *)NULL) {
922 hp = adp->dp_hosts;
923 gotalldir = 0;
924 }
925 }
926 }
927 if (!xdr_bool(xdrsp, &false))
928 return (1);
929 if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief))
930 return (1);
931 }
932 return (0);
933}
934
935int
936xdr_explist(xdrsp, cp)
937 XDR *xdrsp;
938 caddr_t cp;
939{
940
941 return xdr_explist_common(xdrsp, cp, 0);
942}
943
944int
945xdr_explist_brief(xdrsp, cp)
946 XDR *xdrsp;
947 caddr_t cp;
948{
949
950 return xdr_explist_common(xdrsp, cp, 1);
951}
952
953char *line;
954int linesize;
955FILE *exp_file;
956
957/*
958 * Get the export list
959 */
960void
961get_exportlist()
962{
963 struct exportlist *ep, *ep2;
964 struct grouplist *grp, *tgrp;
965 struct exportlist **epp;
83
84#ifdef DEBUG
85#include <stdarg.h>
86#endif
87
88/*
89 * Structures for keeping the mount list and export list
90 */
91struct mountlist {
92 struct mountlist *ml_next;
93 char ml_host[RPCMNT_NAMELEN+1];
94 char ml_dirp[RPCMNT_PATHLEN+1];
95};
96
97struct dirlist {
98 struct dirlist *dp_left;
99 struct dirlist *dp_right;
100 int dp_flag;
101 struct hostlist *dp_hosts; /* List of hosts this dir exported to */
102 char dp_dirp[1]; /* Actually malloc'd to size of dir */
103};
104/* dp_flag bits */
105#define DP_DEFSET 0x1
106#define DP_HOSTSET 0x2
107
108struct exportlist {
109 struct exportlist *ex_next;
110 struct dirlist *ex_dirl;
111 struct dirlist *ex_defdir;
112 int ex_flag;
113 fsid_t ex_fs;
114 char *ex_fsdir;
115 char *ex_indexfile;
116};
117/* ex_flag bits */
118#define EX_LINKED 0x1
119
120struct netmsk {
121 struct sockaddr_storage nt_net;
122 struct sockaddr_storage nt_mask;
123 char *nt_name;
124};
125
126union grouptypes {
127 struct addrinfo *gt_addrinfo;
128 struct netmsk gt_net;
129};
130
131struct grouplist {
132 int gr_type;
133 union grouptypes gr_ptr;
134 struct grouplist *gr_next;
135};
136/* Group types */
137#define GT_NULL 0x0
138#define GT_HOST 0x1
139#define GT_NET 0x2
140#define GT_DEFAULT 0x3
141#define GT_IGNORE 0x5
142
143struct hostlist {
144 int ht_flag; /* Uses DP_xx bits */
145 struct grouplist *ht_grp;
146 struct hostlist *ht_next;
147};
148
149struct fhreturn {
150 int fhr_flag;
151 int fhr_vers;
152 nfsfh_t fhr_fh;
153};
154
155/* Global defs */
156char *add_expdir(struct dirlist **, char *, int);
157void add_dlist(struct dirlist **, struct dirlist *,
158 struct grouplist *, int);
159void add_mlist(char *, char *);
160int check_dirpath(char *);
161int check_options(struct dirlist *);
162int checkmask(struct sockaddr *sa);
163int chk_host(struct dirlist *, struct sockaddr *, int *, int *);
164void del_mlist(char *hostp, char *dirp);
165struct dirlist *dirp_search(struct dirlist *, char *);
166int do_mount(struct exportlist *, struct grouplist *, int,
167 struct xucred *, char *, int, struct statfs *);
168int do_opt(char **, char **, struct exportlist *, struct grouplist *,
169 int *, int *, struct xucred *);
170struct exportlist *ex_search(fsid_t *);
171struct exportlist *get_exp(void);
172void free_dir(struct dirlist *);
173void free_exp(struct exportlist *);
174void free_grp(struct grouplist *);
175void free_host(struct hostlist *);
176void get_exportlist(void);
177int get_host(char *, struct grouplist *, struct grouplist *);
178struct hostlist *get_ht(void);
179int get_line(void);
180void get_mountlist(void);
181int get_net(char *, struct netmsk *, int);
182void getexp_err(struct exportlist *, struct grouplist *);
183struct grouplist *get_grp(void);
184void hang_dirp(struct dirlist *, struct grouplist *,
185 struct exportlist *, int);
186void huphandler(int sig);
187int makemask(struct sockaddr_storage *ssp, int bitlen);
188void mntsrv(struct svc_req *, SVCXPRT *);
189void nextfield(char **, char **);
190void out_of_mem(void);
191void parsecred(char *, struct xucred *);
192int put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int);
193void *sa_rawaddr(struct sockaddr *sa, int *nbytes);
194int sacmp(struct sockaddr *sa1, struct sockaddr *sa2,
195 struct sockaddr *samask);
196int scan_tree(struct dirlist *, struct sockaddr *);
197static void usage(void);
198int xdr_dir(XDR *, char *);
199int xdr_explist(XDR *, caddr_t);
200int xdr_explist_brief(XDR *, caddr_t);
201int xdr_fhs(XDR *, caddr_t);
202int xdr_mlist(XDR *, caddr_t);
203void terminate(int);
204
205struct exportlist *exphead;
206struct mountlist *mlhead;
207struct grouplist *grphead;
208char exname[MAXPATHLEN];
209struct xucred def_anon = {
210 XUCRED_VERSION,
211 (uid_t)-2,
212 1,
213 { (gid_t)-2 },
214 NULL
215};
216int force_v2 = 0;
217int resvport_only = 1;
218int dir_only = 1;
219int dolog = 0;
220int got_sighup = 0;
221
222int opt_flags;
223static int have_v6 = 1;
224
225struct pidfh *pfh = NULL;
226/* Bits for opt_flags above */
227#define OP_MAPROOT 0x01
228#define OP_MAPALL 0x02
229/* 0x4 free */
230#define OP_MASK 0x08
231#define OP_NET 0x10
232#define OP_ALLDIRS 0x40
233#define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */
234#define OP_QUIET 0x100
235#define OP_MASKLEN 0x200
236
237#ifdef DEBUG
238int debug = 1;
239void SYSLOG(int, const char *, ...) __printflike(2, 3);
240#define syslog SYSLOG
241#else
242int debug = 0;
243#endif
244
245/*
246 * Mountd server for NFS mount protocol as described in:
247 * NFS: Network File System Protocol Specification, RFC1094, Appendix A
248 * The optional arguments are the exports file name
249 * default: _PATH_EXPORTS
250 * and "-n" to allow nonroot mount.
251 */
252int
253main(argc, argv)
254 int argc;
255 char **argv;
256{
257 fd_set readfds;
258 struct sockaddr_in sin;
259 struct sockaddr_in6 sin6;
260 char *endptr;
261 SVCXPRT *udptransp, *tcptransp, *udp6transp, *tcp6transp;
262 struct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf;
263 pid_t otherpid;
264 int udpsock, tcpsock, udp6sock, tcp6sock;
265 int xcreated = 0, s;
266 int maxrec = RPC_MAXDATASIZE;
267 int one = 1;
268 int c, r;
269 in_port_t svcport = 0;
270
271 udp6conf = tcp6conf = NULL;
272 udp6sock = tcp6sock = 0;
273
274 /* Check that another mountd isn't already running. */
275 pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid);
276 if (pfh == NULL) {
277 if (errno == EEXIST)
278 errx(1, "mountd already running, pid: %d.", otherpid);
279 warn("cannot open or create pidfile");
280 }
281
282 s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
283 if (s < 0)
284 have_v6 = 0;
285 else
286 close(s);
287 if (modfind("nfsserver") < 0) {
288 /* Not present in kernel, try loading it */
289 if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0)
290 errx(1, "NFS server is not available or loadable");
291 }
292
293 while ((c = getopt(argc, argv, "2dlnp:r")) != -1)
294 switch (c) {
295 case '2':
296 force_v2 = 1;
297 break;
298 case 'n':
299 resvport_only = 0;
300 break;
301 case 'r':
302 dir_only = 0;
303 break;
304 case 'd':
305 debug = debug ? 0 : 1;
306 break;
307 case 'l':
308 dolog = 1;
309 break;
310 case 'p':
311 endptr = NULL;
312 svcport = (in_port_t)strtoul(optarg, &endptr, 10);
313 if (endptr == NULL || *endptr != '\0' ||
314 svcport == 0 || svcport >= IPPORT_MAX)
315 usage();
316 break;
317 default:
318 usage();
319 };
320 argc -= optind;
321 argv += optind;
322 grphead = (struct grouplist *)NULL;
323 exphead = (struct exportlist *)NULL;
324 mlhead = (struct mountlist *)NULL;
325 if (argc == 1) {
326 strncpy(exname, *argv, MAXPATHLEN-1);
327 exname[MAXPATHLEN-1] = '\0';
328 } else
329 strcpy(exname, _PATH_EXPORTS);
330 openlog("mountd", LOG_PID, LOG_DAEMON);
331 if (debug)
332 warnx("getting export list");
333 get_exportlist();
334 if (debug)
335 warnx("getting mount list");
336 get_mountlist();
337 if (debug)
338 warnx("here we go");
339 if (debug == 0) {
340 daemon(0, 0);
341 signal(SIGINT, SIG_IGN);
342 signal(SIGQUIT, SIG_IGN);
343 }
344 signal(SIGHUP, huphandler);
345 signal(SIGTERM, terminate);
346
347 pidfile_write(pfh);
348
349 rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL);
350 rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL);
351 udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
352 tcpsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
353 udpconf = getnetconfigent("udp");
354 tcpconf = getnetconfigent("tcp");
355
356 rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
357
358 if (!have_v6)
359 goto skip_v6;
360 udp6sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
361 tcp6sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
362 /*
363 * We're doing host-based access checks here, so don't allow
364 * v4-in-v6 to confuse things. The kernel will disable it
365 * by default on NFS sockets too.
366 */
367 if (udp6sock != -1 && setsockopt(udp6sock, IPPROTO_IPV6,
368 IPV6_V6ONLY, &one, sizeof one) < 0) {
369 syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket");
370 exit(1);
371 }
372 if (tcp6sock != -1 && setsockopt(tcp6sock, IPPROTO_IPV6,
373 IPV6_V6ONLY, &one, sizeof one) < 0) {
374 syslog(LOG_ERR, "can't disable v4-in-v6 on TCP socket");
375 exit(1);
376 }
377 udp6conf = getnetconfigent("udp6");
378 tcp6conf = getnetconfigent("tcp6");
379
380skip_v6:
381 if (!resvport_only) {
382 if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL,
383 &resvport_only, sizeof(resvport_only)) != 0 &&
384 errno != ENOENT) {
385 syslog(LOG_ERR, "sysctl: %m");
386 exit(1);
387 }
388 }
389 if (svcport != 0) {
390 bzero(&sin, sizeof(struct sockaddr_in));
391 sin.sin_len = sizeof(struct sockaddr_in);
392 sin.sin_family = AF_INET;
393 sin.sin_port = htons(svcport);
394
395 bzero(&sin6, sizeof(struct sockaddr_in6));
396 sin6.sin6_len = sizeof(struct sockaddr_in6);
397 sin6.sin6_family = AF_INET6;
398 sin6.sin6_port = htons(svcport);
399 }
400 if (udpsock != -1 && udpconf != NULL) {
401 if (svcport != 0) {
402 r = bindresvport(udpsock, &sin);
403 if (r != 0) {
404 syslog(LOG_ERR, "bindresvport: %m");
405 exit(1);
406 }
407 } else
408 (void)bindresvport(udpsock, NULL);
409 udptransp = svc_dg_create(udpsock, 0, 0);
410 if (udptransp != NULL) {
411 if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER1,
412 mntsrv, udpconf))
413 syslog(LOG_WARNING, "can't register UDP RPCMNT_VER1 service");
414 else
415 xcreated++;
416 if (!force_v2) {
417 if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER3,
418 mntsrv, udpconf))
419 syslog(LOG_WARNING, "can't register UDP RPCMNT_VER3 service");
420 else
421 xcreated++;
422 }
423 } else
424 syslog(LOG_WARNING, "can't create UDP services");
425
426 }
427 if (tcpsock != -1 && tcpconf != NULL) {
428 if (svcport != 0) {
429 r = bindresvport(tcpsock, &sin);
430 if (r != 0) {
431 syslog(LOG_ERR, "bindresvport: %m");
432 exit(1);
433 }
434 } else
435 (void)bindresvport(tcpsock, NULL);
436 listen(tcpsock, SOMAXCONN);
437 tcptransp = svc_vc_create(tcpsock, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
438 if (tcptransp != NULL) {
439 if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER1,
440 mntsrv, tcpconf))
441 syslog(LOG_WARNING, "can't register TCP RPCMNT_VER1 service");
442 else
443 xcreated++;
444 if (!force_v2) {
445 if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER3,
446 mntsrv, tcpconf))
447 syslog(LOG_WARNING, "can't register TCP RPCMNT_VER3 service");
448 else
449 xcreated++;
450 }
451 } else
452 syslog(LOG_WARNING, "can't create TCP service");
453
454 }
455 if (have_v6 && udp6sock != -1 && udp6conf != NULL) {
456 if (svcport != 0) {
457 r = bindresvport_sa(udp6sock,
458 (struct sockaddr *)&sin6);
459 if (r != 0) {
460 syslog(LOG_ERR, "bindresvport_sa: %m");
461 exit(1);
462 }
463 } else
464 (void)bindresvport_sa(udp6sock, NULL);
465 udp6transp = svc_dg_create(udp6sock, 0, 0);
466 if (udp6transp != NULL) {
467 if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER1,
468 mntsrv, udp6conf))
469 syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER1 service");
470 else
471 xcreated++;
472 if (!force_v2) {
473 if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER3,
474 mntsrv, udp6conf))
475 syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER3 service");
476 else
477 xcreated++;
478 }
479 } else
480 syslog(LOG_WARNING, "can't create UDP6 service");
481
482 }
483 if (have_v6 && tcp6sock != -1 && tcp6conf != NULL) {
484 if (svcport != 0) {
485 r = bindresvport_sa(tcp6sock,
486 (struct sockaddr *)&sin6);
487 if (r != 0) {
488 syslog(LOG_ERR, "bindresvport_sa: %m");
489 exit(1);
490 }
491 } else
492 (void)bindresvport_sa(tcp6sock, NULL);
493 listen(tcp6sock, SOMAXCONN);
494 tcp6transp = svc_vc_create(tcp6sock, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
495 if (tcp6transp != NULL) {
496 if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER1,
497 mntsrv, tcp6conf))
498 syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER1 service");
499 else
500 xcreated++;
501 if (!force_v2) {
502 if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER3,
503 mntsrv, tcp6conf))
504 syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER3 service");
505 else
506 xcreated++;
507 }
508 } else
509 syslog(LOG_WARNING, "can't create TCP6 service");
510
511 }
512 if (xcreated == 0) {
513 syslog(LOG_ERR, "could not create any services");
514 exit(1);
515 }
516
517 /* Expand svc_run() here so that we can call get_exportlist(). */
518 for (;;) {
519 if (got_sighup) {
520 get_exportlist();
521 got_sighup = 0;
522 }
523 readfds = svc_fdset;
524 switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) {
525 case -1:
526 if (errno == EINTR)
527 continue;
528 syslog(LOG_ERR, "mountd died: select: %m");
529 exit(1);
530 case 0:
531 continue;
532 default:
533 svc_getreqset(&readfds);
534 }
535 }
536}
537
538static void
539usage()
540{
541 fprintf(stderr,
542 "usage: mountd [-2] [-d] [-l] [-n] [-p <port>] [-r] "
543 "[export_file]\n");
544 exit(1);
545}
546
547/*
548 * The mount rpc service
549 */
550void
551mntsrv(rqstp, transp)
552 struct svc_req *rqstp;
553 SVCXPRT *transp;
554{
555 struct exportlist *ep;
556 struct dirlist *dp;
557 struct fhreturn fhr;
558 struct stat stb;
559 struct statfs fsb;
560 char host[NI_MAXHOST], numerichost[NI_MAXHOST];
561 int lookup_failed = 1;
562 struct sockaddr *saddr;
563 u_short sport;
564 char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN];
565 int bad = 0, defset, hostset;
566 sigset_t sighup_mask;
567
568 sigemptyset(&sighup_mask);
569 sigaddset(&sighup_mask, SIGHUP);
570 saddr = svc_getrpccaller(transp)->buf;
571 switch (saddr->sa_family) {
572 case AF_INET6:
573 sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port);
574 break;
575 case AF_INET:
576 sport = ntohs(((struct sockaddr_in *)saddr)->sin_port);
577 break;
578 default:
579 syslog(LOG_ERR, "request from unknown address family");
580 return;
581 }
582 lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host,
583 NULL, 0, 0);
584 getnameinfo(saddr, saddr->sa_len, numerichost,
585 sizeof numerichost, NULL, 0, NI_NUMERICHOST);
586 switch (rqstp->rq_proc) {
587 case NULLPROC:
588 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
589 syslog(LOG_ERR, "can't send reply");
590 return;
591 case RPCMNT_MOUNT:
592 if (sport >= IPPORT_RESERVED && resvport_only) {
593 syslog(LOG_NOTICE,
594 "mount request from %s from unprivileged port",
595 numerichost);
596 svcerr_weakauth(transp);
597 return;
598 }
599 if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) {
600 syslog(LOG_NOTICE, "undecodable mount request from %s",
601 numerichost);
602 svcerr_decode(transp);
603 return;
604 }
605
606 /*
607 * Get the real pathname and make sure it is a directory
608 * or a regular file if the -r option was specified
609 * and it exists.
610 */
611 if (realpath(rpcpath, dirpath) == NULL ||
612 stat(dirpath, &stb) < 0 ||
613 (!S_ISDIR(stb.st_mode) &&
614 (dir_only || !S_ISREG(stb.st_mode))) ||
615 statfs(dirpath, &fsb) < 0) {
616 chdir("/"); /* Just in case realpath doesn't */
617 syslog(LOG_NOTICE,
618 "mount request from %s for non existent path %s",
619 numerichost, dirpath);
620 if (debug)
621 warnx("stat failed on %s", dirpath);
622 bad = ENOENT; /* We will send error reply later */
623 }
624
625 /* Check in the exports list */
626 sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
627 ep = ex_search(&fsb.f_fsid);
628 hostset = defset = 0;
629 if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) ||
630 ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
631 chk_host(dp, saddr, &defset, &hostset)) ||
632 (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
633 scan_tree(ep->ex_dirl, saddr) == 0))) {
634 if (bad) {
635 if (!svc_sendreply(transp, (xdrproc_t)xdr_long,
636 (caddr_t)&bad))
637 syslog(LOG_ERR, "can't send reply");
638 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
639 return;
640 }
641 if (hostset & DP_HOSTSET)
642 fhr.fhr_flag = hostset;
643 else
644 fhr.fhr_flag = defset;
645 fhr.fhr_vers = rqstp->rq_vers;
646 /* Get the file handle */
647 memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t));
648 if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) {
649 bad = errno;
650 syslog(LOG_ERR, "can't get fh for %s", dirpath);
651 if (!svc_sendreply(transp, (xdrproc_t)xdr_long,
652 (caddr_t)&bad))
653 syslog(LOG_ERR, "can't send reply");
654 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
655 return;
656 }
657 if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs,
658 (caddr_t)&fhr))
659 syslog(LOG_ERR, "can't send reply");
660 if (!lookup_failed)
661 add_mlist(host, dirpath);
662 else
663 add_mlist(numerichost, dirpath);
664 if (debug)
665 warnx("mount successful");
666 if (dolog)
667 syslog(LOG_NOTICE,
668 "mount request succeeded from %s for %s",
669 numerichost, dirpath);
670 } else {
671 bad = EACCES;
672 syslog(LOG_NOTICE,
673 "mount request denied from %s for %s",
674 numerichost, dirpath);
675 }
676
677 if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long,
678 (caddr_t)&bad))
679 syslog(LOG_ERR, "can't send reply");
680 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
681 return;
682 case RPCMNT_DUMP:
683 if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL))
684 syslog(LOG_ERR, "can't send reply");
685 else if (dolog)
686 syslog(LOG_NOTICE,
687 "dump request succeeded from %s",
688 numerichost);
689 return;
690 case RPCMNT_UMOUNT:
691 if (sport >= IPPORT_RESERVED && resvport_only) {
692 syslog(LOG_NOTICE,
693 "umount request from %s from unprivileged port",
694 numerichost);
695 svcerr_weakauth(transp);
696 return;
697 }
698 if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) {
699 syslog(LOG_NOTICE, "undecodable umount request from %s",
700 numerichost);
701 svcerr_decode(transp);
702 return;
703 }
704 if (realpath(rpcpath, dirpath) == NULL) {
705 syslog(LOG_NOTICE, "umount request from %s "
706 "for non existent path %s",
707 numerichost, dirpath);
708 }
709 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL))
710 syslog(LOG_ERR, "can't send reply");
711 if (!lookup_failed)
712 del_mlist(host, dirpath);
713 del_mlist(numerichost, dirpath);
714 if (dolog)
715 syslog(LOG_NOTICE,
716 "umount request succeeded from %s for %s",
717 numerichost, dirpath);
718 return;
719 case RPCMNT_UMNTALL:
720 if (sport >= IPPORT_RESERVED && resvport_only) {
721 syslog(LOG_NOTICE,
722 "umountall request from %s from unprivileged port",
723 numerichost);
724 svcerr_weakauth(transp);
725 return;
726 }
727 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL))
728 syslog(LOG_ERR, "can't send reply");
729 if (!lookup_failed)
730 del_mlist(host, NULL);
731 del_mlist(numerichost, NULL);
732 if (dolog)
733 syslog(LOG_NOTICE,
734 "umountall request succeeded from %s",
735 numerichost);
736 return;
737 case RPCMNT_EXPORT:
738 if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL))
739 if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief,
740 (caddr_t)NULL))
741 syslog(LOG_ERR, "can't send reply");
742 if (dolog)
743 syslog(LOG_NOTICE,
744 "export request succeeded from %s",
745 numerichost);
746 return;
747 default:
748 svcerr_noproc(transp);
749 return;
750 }
751}
752
753/*
754 * Xdr conversion for a dirpath string
755 */
756int
757xdr_dir(xdrsp, dirp)
758 XDR *xdrsp;
759 char *dirp;
760{
761 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
762}
763
764/*
765 * Xdr routine to generate file handle reply
766 */
767int
768xdr_fhs(xdrsp, cp)
769 XDR *xdrsp;
770 caddr_t cp;
771{
772 struct fhreturn *fhrp = (struct fhreturn *)cp;
773 u_long ok = 0, len, auth;
774
775 if (!xdr_long(xdrsp, &ok))
776 return (0);
777 switch (fhrp->fhr_vers) {
778 case 1:
779 return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH));
780 case 3:
781 len = NFSX_V3FH;
782 if (!xdr_long(xdrsp, &len))
783 return (0);
784 if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len))
785 return (0);
786 auth = RPCAUTH_UNIX;
787 len = 1;
788 if (!xdr_long(xdrsp, &len))
789 return (0);
790 return (xdr_long(xdrsp, &auth));
791 };
792 return (0);
793}
794
795int
796xdr_mlist(xdrsp, cp)
797 XDR *xdrsp;
798 caddr_t cp;
799{
800 struct mountlist *mlp;
801 int true = 1;
802 int false = 0;
803 char *strp;
804
805 mlp = mlhead;
806 while (mlp) {
807 if (!xdr_bool(xdrsp, &true))
808 return (0);
809 strp = &mlp->ml_host[0];
810 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
811 return (0);
812 strp = &mlp->ml_dirp[0];
813 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
814 return (0);
815 mlp = mlp->ml_next;
816 }
817 if (!xdr_bool(xdrsp, &false))
818 return (0);
819 return (1);
820}
821
822/*
823 * Xdr conversion for export list
824 */
825int
826xdr_explist_common(xdrsp, cp, brief)
827 XDR *xdrsp;
828 caddr_t cp;
829 int brief;
830{
831 struct exportlist *ep;
832 int false = 0;
833 int putdef;
834 sigset_t sighup_mask;
835
836 sigemptyset(&sighup_mask);
837 sigaddset(&sighup_mask, SIGHUP);
838 sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
839 ep = exphead;
840 while (ep) {
841 putdef = 0;
842 if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir,
843 &putdef, brief))
844 goto errout;
845 if (ep->ex_defdir && putdef == 0 &&
846 put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL,
847 &putdef, brief))
848 goto errout;
849 ep = ep->ex_next;
850 }
851 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
852 if (!xdr_bool(xdrsp, &false))
853 return (0);
854 return (1);
855errout:
856 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
857 return (0);
858}
859
860/*
861 * Called from xdr_explist() to traverse the tree and export the
862 * directory paths.
863 */
864int
865put_exlist(dp, xdrsp, adp, putdefp, brief)
866 struct dirlist *dp;
867 XDR *xdrsp;
868 struct dirlist *adp;
869 int *putdefp;
870 int brief;
871{
872 struct grouplist *grp;
873 struct hostlist *hp;
874 int true = 1;
875 int false = 0;
876 int gotalldir = 0;
877 char *strp;
878
879 if (dp) {
880 if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief))
881 return (1);
882 if (!xdr_bool(xdrsp, &true))
883 return (1);
884 strp = dp->dp_dirp;
885 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
886 return (1);
887 if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) {
888 gotalldir = 1;
889 *putdefp = 1;
890 }
891 if (brief) {
892 if (!xdr_bool(xdrsp, &true))
893 return (1);
894 strp = "(...)";
895 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
896 return (1);
897 } else if ((dp->dp_flag & DP_DEFSET) == 0 &&
898 (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) {
899 hp = dp->dp_hosts;
900 while (hp) {
901 grp = hp->ht_grp;
902 if (grp->gr_type == GT_HOST) {
903 if (!xdr_bool(xdrsp, &true))
904 return (1);
905 strp = grp->gr_ptr.gt_addrinfo->ai_canonname;
906 if (!xdr_string(xdrsp, &strp,
907 RPCMNT_NAMELEN))
908 return (1);
909 } else if (grp->gr_type == GT_NET) {
910 if (!xdr_bool(xdrsp, &true))
911 return (1);
912 strp = grp->gr_ptr.gt_net.nt_name;
913 if (!xdr_string(xdrsp, &strp,
914 RPCMNT_NAMELEN))
915 return (1);
916 }
917 hp = hp->ht_next;
918 if (gotalldir && hp == (struct hostlist *)NULL) {
919 hp = adp->dp_hosts;
920 gotalldir = 0;
921 }
922 }
923 }
924 if (!xdr_bool(xdrsp, &false))
925 return (1);
926 if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief))
927 return (1);
928 }
929 return (0);
930}
931
932int
933xdr_explist(xdrsp, cp)
934 XDR *xdrsp;
935 caddr_t cp;
936{
937
938 return xdr_explist_common(xdrsp, cp, 0);
939}
940
941int
942xdr_explist_brief(xdrsp, cp)
943 XDR *xdrsp;
944 caddr_t cp;
945{
946
947 return xdr_explist_common(xdrsp, cp, 1);
948}
949
950char *line;
951int linesize;
952FILE *exp_file;
953
954/*
955 * Get the export list
956 */
957void
958get_exportlist()
959{
960 struct exportlist *ep, *ep2;
961 struct grouplist *grp, *tgrp;
962 struct exportlist **epp;
963 struct export_args export;
966 struct dirlist *dirhead;
964 struct dirlist *dirhead;
965 struct iovec *iov;
967 struct statfs fsb, *fsp;
968 struct xucred anon;
969 char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
966 struct statfs fsb, *fsp;
967 struct xucred anon;
968 char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
969 char errmsg[255];
970 int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp;
970 int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp;
971 int iovlen;
971
972
973 bzero(&export, sizeof(export));
974 export.ex_flags = MNT_DELEXPORT;
972 dirp = NULL;
973 dirplen = 0;
975 dirp = NULL;
976 dirplen = 0;
977 iov = NULL;
978 iovlen = 0;
979 bzero(errmsg, sizeof(errmsg));
974
975 /*
976 * First, get rid of the old list
977 */
978 ep = exphead;
979 while (ep) {
980 ep2 = ep;
981 ep = ep->ex_next;
982 free_exp(ep2);
983 }
984 exphead = (struct exportlist *)NULL;
985
986 grp = grphead;
987 while (grp) {
988 tgrp = grp;
989 grp = grp->gr_next;
990 free_grp(tgrp);
991 }
992 grphead = (struct grouplist *)NULL;
993
994 /*
995 * And delete exports that are in the kernel for all local
996 * filesystems.
997 * XXX: Should know how to handle all local exportable filesystems
998 * instead of just "ufs".
999 */
1000 num = getmntinfo(&fsp, MNT_NOWAIT);
980
981 /*
982 * First, get rid of the old list
983 */
984 ep = exphead;
985 while (ep) {
986 ep2 = ep;
987 ep = ep->ex_next;
988 free_exp(ep2);
989 }
990 exphead = (struct exportlist *)NULL;
991
992 grp = grphead;
993 while (grp) {
994 tgrp = grp;
995 grp = grp->gr_next;
996 free_grp(tgrp);
997 }
998 grphead = (struct grouplist *)NULL;
999
1000 /*
1001 * And delete exports that are in the kernel for all local
1002 * filesystems.
1003 * XXX: Should know how to handle all local exportable filesystems
1004 * instead of just "ufs".
1005 */
1006 num = getmntinfo(&fsp, MNT_NOWAIT);
1007
1008 if (num > 0) {
1009 build_iovec(&iov, &iovlen, "fstype", NULL, 0);
1010 build_iovec(&iov, &iovlen, "fspath", NULL, 0);
1011 build_iovec(&iov, &iovlen, "from", NULL, 0);
1012 build_iovec(&iov, &iovlen, "update", NULL, 0);
1013 build_iovec(&iov, &iovlen, "export", &export, sizeof(export));
1014 build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
1015 }
1016
1001 for (i = 0; i < num; i++) {
1017 for (i = 0; i < num; i++) {
1002 union {
1003 struct ufs_args ua;
1004 struct iso_args ia;
1005 struct msdosfs_args da;
1006 struct ntfs_args na;
1007 } targs;
1008
1009 if (!strcmp(fsp->f_fstypename, "ufs") ||
1010 !strcmp(fsp->f_fstypename, "msdosfs") ||
1011 !strcmp(fsp->f_fstypename, "ntfs") ||
1012 !strcmp(fsp->f_fstypename, "cd9660")) {
1018
1019 if (!strcmp(fsp->f_fstypename, "ufs") ||
1020 !strcmp(fsp->f_fstypename, "msdosfs") ||
1021 !strcmp(fsp->f_fstypename, "ntfs") ||
1022 !strcmp(fsp->f_fstypename, "cd9660")) {
1013 bzero(&targs, sizeof targs);
1014 targs.ua.fspec = NULL;
1015 targs.ua.export.ex_flags = MNT_DELEXPORT;
1016 if (mount(fsp->f_fstypename, fsp->f_mntonname,
1017 fsp->f_flags | MNT_UPDATE, (caddr_t)&targs) < 0 &&
1018 errno != ENOENT)
1023 iov[1].iov_base = fsp->f_fstypename;
1024 iov[1].iov_len = strlen(fsp->f_fstypename) + 1;
1025 iov[3].iov_base = fsp->f_mntonname;
1026 iov[3].iov_len = strlen(fsp->f_mntonname) + 1;
1027 iov[5].iov_base = fsp->f_mntfromname;
1028 iov[5].iov_len = strlen(fsp->f_mntfromname) + 1;
1029
1030 /*
1031 * Kick out MNT_ROOTFS. It should not be passed from
1032 * userland to kernel. It should only be used
1033 * internally in the kernel.
1034 */
1035 if (fsp->f_flags & MNT_ROOTFS) {
1036 fsp->f_flags &= ~MNT_ROOTFS;
1037 }
1038
1039 if (nmount(iov, iovlen, fsp->f_flags) < 0 &&
1040 errno != ENOENT) {
1019 syslog(LOG_ERR,
1041 syslog(LOG_ERR,
1020 "can't delete exports for %s: %m",
1021 fsp->f_mntonname);
1042 "can't delete exports for %s: %m %s",
1043 fsp->f_mntonname, errmsg);
1044 }
1022 }
1023 fsp++;
1024 }
1025
1045 }
1046 fsp++;
1047 }
1048
1049 if (iov != NULL) {
1050 /* Free strings allocated by strdup() in getmntopts.c */
1051 free(iov[0].iov_base); /* fstype */
1052 free(iov[2].iov_base); /* fspath */
1053 free(iov[4].iov_base); /* from */
1054 free(iov[6].iov_base); /* update */
1055 free(iov[8].iov_base); /* export */
1056 free(iov[10].iov_base); /* errmsg */
1057
1058 /* free iov, allocated by realloc() */
1059 free(iov);
1060 iovlen = 0;
1061 }
1062
1026 /*
1027 * Read in the exports file and build the list, calling
1063 /*
1064 * Read in the exports file and build the list, calling
1028 * mount() as we go along to push the export rules into the kernel.
1065 * nmount() as we go along to push the export rules into the kernel.
1029 */
1030 if ((exp_file = fopen(exname, "r")) == NULL) {
1031 syslog(LOG_ERR, "can't open %s", exname);
1032 exit(2);
1033 }
1034 dirhead = (struct dirlist *)NULL;
1035 while (get_line()) {
1036 if (debug)
1037 warnx("got line %s", line);
1038 cp = line;
1039 nextfield(&cp, &endcp);
1040 if (*cp == '#')
1041 goto nextline;
1042
1043 /*
1044 * Set defaults.
1045 */
1046 has_host = FALSE;
1047 anon = def_anon;
1048 exflags = MNT_EXPORTED;
1049 got_nondir = 0;
1050 opt_flags = 0;
1051 ep = (struct exportlist *)NULL;
1052
1053 /*
1054 * Create new exports list entry
1055 */
1056 len = endcp-cp;
1057 tgrp = grp = get_grp();
1058 while (len > 0) {
1059 if (len > RPCMNT_NAMELEN) {
1060 getexp_err(ep, tgrp);
1061 goto nextline;
1062 }
1063 if (*cp == '-') {
1064 if (ep == (struct exportlist *)NULL) {
1065 getexp_err(ep, tgrp);
1066 goto nextline;
1067 }
1068 if (debug)
1069 warnx("doing opt %s", cp);
1070 got_nondir = 1;
1071 if (do_opt(&cp, &endcp, ep, grp, &has_host,
1072 &exflags, &anon)) {
1073 getexp_err(ep, tgrp);
1074 goto nextline;
1075 }
1076 } else if (*cp == '/') {
1077 savedc = *endcp;
1078 *endcp = '\0';
1079 if (check_dirpath(cp) &&
1080 statfs(cp, &fsb) >= 0) {
1081 if (got_nondir) {
1082 syslog(LOG_ERR, "dirs must be first");
1083 getexp_err(ep, tgrp);
1084 goto nextline;
1085 }
1086 if (ep) {
1087 if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] ||
1088 ep->ex_fs.val[1] != fsb.f_fsid.val[1]) {
1089 getexp_err(ep, tgrp);
1090 goto nextline;
1091 }
1092 } else {
1093 /*
1094 * See if this directory is already
1095 * in the list.
1096 */
1097 ep = ex_search(&fsb.f_fsid);
1098 if (ep == (struct exportlist *)NULL) {
1099 ep = get_exp();
1100 ep->ex_fs = fsb.f_fsid;
1101 ep->ex_fsdir = (char *)
1102 malloc(strlen(fsb.f_mntonname) + 1);
1103 if (ep->ex_fsdir)
1104 strcpy(ep->ex_fsdir,
1105 fsb.f_mntonname);
1106 else
1107 out_of_mem();
1108 if (debug)
1109 warnx("making new ep fs=0x%x,0x%x",
1110 fsb.f_fsid.val[0],
1111 fsb.f_fsid.val[1]);
1112 } else if (debug)
1113 warnx("found ep fs=0x%x,0x%x",
1114 fsb.f_fsid.val[0],
1115 fsb.f_fsid.val[1]);
1116 }
1117
1118 /*
1119 * Add dirpath to export mount point.
1120 */
1121 dirp = add_expdir(&dirhead, cp, len);
1122 dirplen = len;
1123 } else {
1124 getexp_err(ep, tgrp);
1125 goto nextline;
1126 }
1127 *endcp = savedc;
1128 } else {
1129 savedc = *endcp;
1130 *endcp = '\0';
1131 got_nondir = 1;
1132 if (ep == (struct exportlist *)NULL) {
1133 getexp_err(ep, tgrp);
1134 goto nextline;
1135 }
1136
1137 /*
1138 * Get the host or netgroup.
1139 */
1140 setnetgrent(cp);
1141 netgrp = getnetgrent(&hst, &usr, &dom);
1142 do {
1143 if (has_host) {
1144 grp->gr_next = get_grp();
1145 grp = grp->gr_next;
1146 }
1147 if (netgrp) {
1148 if (hst == 0) {
1149 syslog(LOG_ERR,
1150 "null hostname in netgroup %s, skipping", cp);
1151 grp->gr_type = GT_IGNORE;
1152 } else if (get_host(hst, grp, tgrp)) {
1153 syslog(LOG_ERR,
1154 "bad host %s in netgroup %s, skipping", hst, cp);
1155 grp->gr_type = GT_IGNORE;
1156 }
1157 } else if (get_host(cp, grp, tgrp)) {
1158 syslog(LOG_ERR, "bad host %s, skipping", cp);
1159 grp->gr_type = GT_IGNORE;
1160 }
1161 has_host = TRUE;
1162 } while (netgrp && getnetgrent(&hst, &usr, &dom));
1163 endnetgrent();
1164 *endcp = savedc;
1165 }
1166 cp = endcp;
1167 nextfield(&cp, &endcp);
1168 len = endcp - cp;
1169 }
1170 if (check_options(dirhead)) {
1171 getexp_err(ep, tgrp);
1172 goto nextline;
1173 }
1174 if (!has_host) {
1175 grp->gr_type = GT_DEFAULT;
1176 if (debug)
1177 warnx("adding a default entry");
1178
1179 /*
1180 * Don't allow a network export coincide with a list of
1181 * host(s) on the same line.
1182 */
1183 } else if ((opt_flags & OP_NET) && tgrp->gr_next) {
1184 syslog(LOG_ERR, "network/host conflict");
1185 getexp_err(ep, tgrp);
1186 goto nextline;
1187
1188 /*
1189 * If an export list was specified on this line, make sure
1190 * that we have at least one valid entry, otherwise skip it.
1191 */
1192 } else {
1193 grp = tgrp;
1194 while (grp && grp->gr_type == GT_IGNORE)
1195 grp = grp->gr_next;
1196 if (! grp) {
1197 getexp_err(ep, tgrp);
1198 goto nextline;
1199 }
1200 }
1201
1202 /*
1203 * Loop through hosts, pushing the exports into the kernel.
1204 * After loop, tgrp points to the start of the list and
1205 * grp points to the last entry in the list.
1206 */
1207 grp = tgrp;
1208 do {
1209 if (do_mount(ep, grp, exflags, &anon, dirp, dirplen,
1210 &fsb)) {
1211 getexp_err(ep, tgrp);
1212 goto nextline;
1213 }
1214 } while (grp->gr_next && (grp = grp->gr_next));
1215
1216 /*
1217 * Success. Update the data structures.
1218 */
1219 if (has_host) {
1220 hang_dirp(dirhead, tgrp, ep, opt_flags);
1221 grp->gr_next = grphead;
1222 grphead = tgrp;
1223 } else {
1224 hang_dirp(dirhead, (struct grouplist *)NULL, ep,
1225 opt_flags);
1226 free_grp(grp);
1227 }
1228 dirhead = (struct dirlist *)NULL;
1229 if ((ep->ex_flag & EX_LINKED) == 0) {
1230 ep2 = exphead;
1231 epp = &exphead;
1232
1233 /*
1234 * Insert in the list in alphabetical order.
1235 */
1236 while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
1237 epp = &ep2->ex_next;
1238 ep2 = ep2->ex_next;
1239 }
1240 if (ep2)
1241 ep->ex_next = ep2;
1242 *epp = ep;
1243 ep->ex_flag |= EX_LINKED;
1244 }
1245nextline:
1246 if (dirhead) {
1247 free_dir(dirhead);
1248 dirhead = (struct dirlist *)NULL;
1249 }
1250 }
1251 fclose(exp_file);
1252}
1253
1254/*
1255 * Allocate an export list element
1256 */
1257struct exportlist *
1258get_exp()
1259{
1260 struct exportlist *ep;
1261
1262 ep = (struct exportlist *)malloc(sizeof (struct exportlist));
1263 if (ep == (struct exportlist *)NULL)
1264 out_of_mem();
1265 memset(ep, 0, sizeof(struct exportlist));
1266 return (ep);
1267}
1268
1269/*
1270 * Allocate a group list element
1271 */
1272struct grouplist *
1273get_grp()
1274{
1275 struct grouplist *gp;
1276
1277 gp = (struct grouplist *)malloc(sizeof (struct grouplist));
1278 if (gp == (struct grouplist *)NULL)
1279 out_of_mem();
1280 memset(gp, 0, sizeof(struct grouplist));
1281 return (gp);
1282}
1283
1284/*
1285 * Clean up upon an error in get_exportlist().
1286 */
1287void
1288getexp_err(ep, grp)
1289 struct exportlist *ep;
1290 struct grouplist *grp;
1291{
1292 struct grouplist *tgrp;
1293
1294 if (!(opt_flags & OP_QUIET))
1295 syslog(LOG_ERR, "bad exports list line %s", line);
1296 if (ep && (ep->ex_flag & EX_LINKED) == 0)
1297 free_exp(ep);
1298 while (grp) {
1299 tgrp = grp;
1300 grp = grp->gr_next;
1301 free_grp(tgrp);
1302 }
1303}
1304
1305/*
1306 * Search the export list for a matching fs.
1307 */
1308struct exportlist *
1309ex_search(fsid)
1310 fsid_t *fsid;
1311{
1312 struct exportlist *ep;
1313
1314 ep = exphead;
1315 while (ep) {
1316 if (ep->ex_fs.val[0] == fsid->val[0] &&
1317 ep->ex_fs.val[1] == fsid->val[1])
1318 return (ep);
1319 ep = ep->ex_next;
1320 }
1321 return (ep);
1322}
1323
1324/*
1325 * Add a directory path to the list.
1326 */
1327char *
1328add_expdir(dpp, cp, len)
1329 struct dirlist **dpp;
1330 char *cp;
1331 int len;
1332{
1333 struct dirlist *dp;
1334
1335 dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
1336 if (dp == (struct dirlist *)NULL)
1337 out_of_mem();
1338 dp->dp_left = *dpp;
1339 dp->dp_right = (struct dirlist *)NULL;
1340 dp->dp_flag = 0;
1341 dp->dp_hosts = (struct hostlist *)NULL;
1342 strcpy(dp->dp_dirp, cp);
1343 *dpp = dp;
1344 return (dp->dp_dirp);
1345}
1346
1347/*
1348 * Hang the dir list element off the dirpath binary tree as required
1349 * and update the entry for host.
1350 */
1351void
1352hang_dirp(dp, grp, ep, flags)
1353 struct dirlist *dp;
1354 struct grouplist *grp;
1355 struct exportlist *ep;
1356 int flags;
1357{
1358 struct hostlist *hp;
1359 struct dirlist *dp2;
1360
1361 if (flags & OP_ALLDIRS) {
1362 if (ep->ex_defdir)
1363 free((caddr_t)dp);
1364 else
1365 ep->ex_defdir = dp;
1366 if (grp == (struct grouplist *)NULL) {
1367 ep->ex_defdir->dp_flag |= DP_DEFSET;
1368 } else while (grp) {
1369 hp = get_ht();
1370 hp->ht_grp = grp;
1371 hp->ht_next = ep->ex_defdir->dp_hosts;
1372 ep->ex_defdir->dp_hosts = hp;
1373 grp = grp->gr_next;
1374 }
1375 } else {
1376
1377 /*
1378 * Loop through the directories adding them to the tree.
1379 */
1380 while (dp) {
1381 dp2 = dp->dp_left;
1382 add_dlist(&ep->ex_dirl, dp, grp, flags);
1383 dp = dp2;
1384 }
1385 }
1386}
1387
1388/*
1389 * Traverse the binary tree either updating a node that is already there
1390 * for the new directory or adding the new node.
1391 */
1392void
1393add_dlist(dpp, newdp, grp, flags)
1394 struct dirlist **dpp;
1395 struct dirlist *newdp;
1396 struct grouplist *grp;
1397 int flags;
1398{
1399 struct dirlist *dp;
1400 struct hostlist *hp;
1401 int cmp;
1402
1403 dp = *dpp;
1404 if (dp) {
1405 cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
1406 if (cmp > 0) {
1407 add_dlist(&dp->dp_left, newdp, grp, flags);
1408 return;
1409 } else if (cmp < 0) {
1410 add_dlist(&dp->dp_right, newdp, grp, flags);
1411 return;
1412 } else
1413 free((caddr_t)newdp);
1414 } else {
1415 dp = newdp;
1416 dp->dp_left = (struct dirlist *)NULL;
1417 *dpp = dp;
1418 }
1419 if (grp) {
1420
1421 /*
1422 * Hang all of the host(s) off of the directory point.
1423 */
1424 do {
1425 hp = get_ht();
1426 hp->ht_grp = grp;
1427 hp->ht_next = dp->dp_hosts;
1428 dp->dp_hosts = hp;
1429 grp = grp->gr_next;
1430 } while (grp);
1431 } else {
1432 dp->dp_flag |= DP_DEFSET;
1433 }
1434}
1435
1436/*
1437 * Search for a dirpath on the export point.
1438 */
1439struct dirlist *
1440dirp_search(dp, dirp)
1441 struct dirlist *dp;
1442 char *dirp;
1443{
1444 int cmp;
1445
1446 if (dp) {
1447 cmp = strcmp(dp->dp_dirp, dirp);
1448 if (cmp > 0)
1449 return (dirp_search(dp->dp_left, dirp));
1450 else if (cmp < 0)
1451 return (dirp_search(dp->dp_right, dirp));
1452 else
1453 return (dp);
1454 }
1455 return (dp);
1456}
1457
1458/*
1459 * Scan for a host match in a directory tree.
1460 */
1461int
1462chk_host(dp, saddr, defsetp, hostsetp)
1463 struct dirlist *dp;
1464 struct sockaddr *saddr;
1465 int *defsetp;
1466 int *hostsetp;
1467{
1468 struct hostlist *hp;
1469 struct grouplist *grp;
1470 struct addrinfo *ai;
1471
1472 if (dp) {
1473 if (dp->dp_flag & DP_DEFSET)
1474 *defsetp = dp->dp_flag;
1475 hp = dp->dp_hosts;
1476 while (hp) {
1477 grp = hp->ht_grp;
1478 switch (grp->gr_type) {
1479 case GT_HOST:
1480 ai = grp->gr_ptr.gt_addrinfo;
1481 for (; ai; ai = ai->ai_next) {
1482 if (!sacmp(ai->ai_addr, saddr, NULL)) {
1483 *hostsetp =
1484 (hp->ht_flag | DP_HOSTSET);
1485 return (1);
1486 }
1487 }
1488 break;
1489 case GT_NET:
1490 if (!sacmp(saddr, (struct sockaddr *)
1491 &grp->gr_ptr.gt_net.nt_net,
1492 (struct sockaddr *)
1493 &grp->gr_ptr.gt_net.nt_mask)) {
1494 *hostsetp = (hp->ht_flag | DP_HOSTSET);
1495 return (1);
1496 }
1497 break;
1498 }
1499 hp = hp->ht_next;
1500 }
1501 }
1502 return (0);
1503}
1504
1505/*
1506 * Scan tree for a host that matches the address.
1507 */
1508int
1509scan_tree(dp, saddr)
1510 struct dirlist *dp;
1511 struct sockaddr *saddr;
1512{
1513 int defset, hostset;
1514
1515 if (dp) {
1516 if (scan_tree(dp->dp_left, saddr))
1517 return (1);
1518 if (chk_host(dp, saddr, &defset, &hostset))
1519 return (1);
1520 if (scan_tree(dp->dp_right, saddr))
1521 return (1);
1522 }
1523 return (0);
1524}
1525
1526/*
1527 * Traverse the dirlist tree and free it up.
1528 */
1529void
1530free_dir(dp)
1531 struct dirlist *dp;
1532{
1533
1534 if (dp) {
1535 free_dir(dp->dp_left);
1536 free_dir(dp->dp_right);
1537 free_host(dp->dp_hosts);
1538 free((caddr_t)dp);
1539 }
1540}
1541
1542/*
1543 * Parse the option string and update fields.
1544 * Option arguments may either be -<option>=<value> or
1545 * -<option> <value>
1546 */
1547int
1548do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
1549 char **cpp, **endcpp;
1550 struct exportlist *ep;
1551 struct grouplist *grp;
1552 int *has_hostp;
1553 int *exflagsp;
1554 struct xucred *cr;
1555{
1556 char *cpoptarg, *cpoptend;
1557 char *cp, *endcp, *cpopt, savedc, savedc2;
1558 int allflag, usedarg;
1559
1560 savedc2 = '\0';
1561 cpopt = *cpp;
1562 cpopt++;
1563 cp = *endcpp;
1564 savedc = *cp;
1565 *cp = '\0';
1566 while (cpopt && *cpopt) {
1567 allflag = 1;
1568 usedarg = -2;
1569 if ((cpoptend = strchr(cpopt, ','))) {
1570 *cpoptend++ = '\0';
1571 if ((cpoptarg = strchr(cpopt, '=')))
1572 *cpoptarg++ = '\0';
1573 } else {
1574 if ((cpoptarg = strchr(cpopt, '=')))
1575 *cpoptarg++ = '\0';
1576 else {
1577 *cp = savedc;
1578 nextfield(&cp, &endcp);
1579 **endcpp = '\0';
1580 if (endcp > cp && *cp != '-') {
1581 cpoptarg = cp;
1582 savedc2 = *endcp;
1583 *endcp = '\0';
1584 usedarg = 0;
1585 }
1586 }
1587 }
1588 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
1589 *exflagsp |= MNT_EXRDONLY;
1590 } else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
1591 !(allflag = strcmp(cpopt, "mapall")) ||
1592 !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
1593 usedarg++;
1594 parsecred(cpoptarg, cr);
1595 if (allflag == 0) {
1596 *exflagsp |= MNT_EXPORTANON;
1597 opt_flags |= OP_MAPALL;
1598 } else
1599 opt_flags |= OP_MAPROOT;
1600 } else if (cpoptarg && (!strcmp(cpopt, "mask") ||
1601 !strcmp(cpopt, "m"))) {
1602 if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
1603 syslog(LOG_ERR, "bad mask: %s", cpoptarg);
1604 return (1);
1605 }
1606 usedarg++;
1607 opt_flags |= OP_MASK;
1608 } else if (cpoptarg && (!strcmp(cpopt, "network") ||
1609 !strcmp(cpopt, "n"))) {
1610 if (strchr(cpoptarg, '/') != NULL) {
1611 if (debug)
1612 fprintf(stderr, "setting OP_MASKLEN\n");
1613 opt_flags |= OP_MASKLEN;
1614 }
1615 if (grp->gr_type != GT_NULL) {
1616 syslog(LOG_ERR, "network/host conflict");
1617 return (1);
1618 } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
1619 syslog(LOG_ERR, "bad net: %s", cpoptarg);
1620 return (1);
1621 }
1622 grp->gr_type = GT_NET;
1623 *has_hostp = 1;
1624 usedarg++;
1625 opt_flags |= OP_NET;
1626 } else if (!strcmp(cpopt, "alldirs")) {
1627 opt_flags |= OP_ALLDIRS;
1628 } else if (!strcmp(cpopt, "public")) {
1629 *exflagsp |= MNT_EXPUBLIC;
1630 } else if (!strcmp(cpopt, "webnfs")) {
1631 *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON);
1632 opt_flags |= OP_MAPALL;
1633 } else if (cpoptarg && !strcmp(cpopt, "index")) {
1634 ep->ex_indexfile = strdup(cpoptarg);
1635 } else if (!strcmp(cpopt, "quiet")) {
1636 opt_flags |= OP_QUIET;
1637 } else {
1638 syslog(LOG_ERR, "bad opt %s", cpopt);
1639 return (1);
1640 }
1641 if (usedarg >= 0) {
1642 *endcp = savedc2;
1643 **endcpp = savedc;
1644 if (usedarg > 0) {
1645 *cpp = cp;
1646 *endcpp = endcp;
1647 }
1648 return (0);
1649 }
1650 cpopt = cpoptend;
1651 }
1652 **endcpp = savedc;
1653 return (0);
1654}
1655
1656/*
1657 * Translate a character string to the corresponding list of network
1658 * addresses for a hostname.
1659 */
1660int
1661get_host(cp, grp, tgrp)
1662 char *cp;
1663 struct grouplist *grp;
1664 struct grouplist *tgrp;
1665{
1666 struct grouplist *checkgrp;
1667 struct addrinfo *ai, *tai, hints;
1668 int ecode;
1669 char host[NI_MAXHOST];
1670
1671 if (grp->gr_type != GT_NULL) {
1672 syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp);
1673 return (1);
1674 }
1675 memset(&hints, 0, sizeof hints);
1676 hints.ai_flags = AI_CANONNAME;
1677 hints.ai_protocol = IPPROTO_UDP;
1678 ecode = getaddrinfo(cp, NULL, &hints, &ai);
1679 if (ecode != 0) {
1680 syslog(LOG_ERR,"can't get address info for host %s", cp);
1681 return 1;
1682 }
1683 grp->gr_ptr.gt_addrinfo = ai;
1684 while (ai != NULL) {
1685 if (ai->ai_canonname == NULL) {
1686 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host,
1687 sizeof host, NULL, 0, NI_NUMERICHOST) != 0)
1688 strlcpy(host, "?", sizeof(host));
1689 ai->ai_canonname = strdup(host);
1690 ai->ai_flags |= AI_CANONNAME;
1691 }
1692 if (debug)
1693 fprintf(stderr, "got host %s\n", ai->ai_canonname);
1694 /*
1695 * Sanity check: make sure we don't already have an entry
1696 * for this host in the grouplist.
1697 */
1698 for (checkgrp = tgrp; checkgrp != NULL;
1699 checkgrp = checkgrp->gr_next) {
1700 if (checkgrp->gr_type != GT_HOST)
1701 continue;
1702 for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL;
1703 tai = tai->ai_next) {
1704 if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0)
1705 continue;
1706 if (debug)
1707 fprintf(stderr,
1708 "ignoring duplicate host %s\n",
1709 ai->ai_canonname);
1710 grp->gr_type = GT_IGNORE;
1711 return (0);
1712 }
1713 }
1714 ai = ai->ai_next;
1715 }
1716 grp->gr_type = GT_HOST;
1717 return (0);
1718}
1719
1720/*
1721 * Free up an exports list component
1722 */
1723void
1724free_exp(ep)
1725 struct exportlist *ep;
1726{
1727
1728 if (ep->ex_defdir) {
1729 free_host(ep->ex_defdir->dp_hosts);
1730 free((caddr_t)ep->ex_defdir);
1731 }
1732 if (ep->ex_fsdir)
1733 free(ep->ex_fsdir);
1734 if (ep->ex_indexfile)
1735 free(ep->ex_indexfile);
1736 free_dir(ep->ex_dirl);
1737 free((caddr_t)ep);
1738}
1739
1740/*
1741 * Free hosts.
1742 */
1743void
1744free_host(hp)
1745 struct hostlist *hp;
1746{
1747 struct hostlist *hp2;
1748
1749 while (hp) {
1750 hp2 = hp;
1751 hp = hp->ht_next;
1752 free((caddr_t)hp2);
1753 }
1754}
1755
1756struct hostlist *
1757get_ht()
1758{
1759 struct hostlist *hp;
1760
1761 hp = (struct hostlist *)malloc(sizeof (struct hostlist));
1762 if (hp == (struct hostlist *)NULL)
1763 out_of_mem();
1764 hp->ht_next = (struct hostlist *)NULL;
1765 hp->ht_flag = 0;
1766 return (hp);
1767}
1768
1769/*
1770 * Out of memory, fatal
1771 */
1772void
1773out_of_mem()
1774{
1775
1776 syslog(LOG_ERR, "out of memory");
1777 exit(2);
1778}
1779
1780/*
1066 */
1067 if ((exp_file = fopen(exname, "r")) == NULL) {
1068 syslog(LOG_ERR, "can't open %s", exname);
1069 exit(2);
1070 }
1071 dirhead = (struct dirlist *)NULL;
1072 while (get_line()) {
1073 if (debug)
1074 warnx("got line %s", line);
1075 cp = line;
1076 nextfield(&cp, &endcp);
1077 if (*cp == '#')
1078 goto nextline;
1079
1080 /*
1081 * Set defaults.
1082 */
1083 has_host = FALSE;
1084 anon = def_anon;
1085 exflags = MNT_EXPORTED;
1086 got_nondir = 0;
1087 opt_flags = 0;
1088 ep = (struct exportlist *)NULL;
1089
1090 /*
1091 * Create new exports list entry
1092 */
1093 len = endcp-cp;
1094 tgrp = grp = get_grp();
1095 while (len > 0) {
1096 if (len > RPCMNT_NAMELEN) {
1097 getexp_err(ep, tgrp);
1098 goto nextline;
1099 }
1100 if (*cp == '-') {
1101 if (ep == (struct exportlist *)NULL) {
1102 getexp_err(ep, tgrp);
1103 goto nextline;
1104 }
1105 if (debug)
1106 warnx("doing opt %s", cp);
1107 got_nondir = 1;
1108 if (do_opt(&cp, &endcp, ep, grp, &has_host,
1109 &exflags, &anon)) {
1110 getexp_err(ep, tgrp);
1111 goto nextline;
1112 }
1113 } else if (*cp == '/') {
1114 savedc = *endcp;
1115 *endcp = '\0';
1116 if (check_dirpath(cp) &&
1117 statfs(cp, &fsb) >= 0) {
1118 if (got_nondir) {
1119 syslog(LOG_ERR, "dirs must be first");
1120 getexp_err(ep, tgrp);
1121 goto nextline;
1122 }
1123 if (ep) {
1124 if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] ||
1125 ep->ex_fs.val[1] != fsb.f_fsid.val[1]) {
1126 getexp_err(ep, tgrp);
1127 goto nextline;
1128 }
1129 } else {
1130 /*
1131 * See if this directory is already
1132 * in the list.
1133 */
1134 ep = ex_search(&fsb.f_fsid);
1135 if (ep == (struct exportlist *)NULL) {
1136 ep = get_exp();
1137 ep->ex_fs = fsb.f_fsid;
1138 ep->ex_fsdir = (char *)
1139 malloc(strlen(fsb.f_mntonname) + 1);
1140 if (ep->ex_fsdir)
1141 strcpy(ep->ex_fsdir,
1142 fsb.f_mntonname);
1143 else
1144 out_of_mem();
1145 if (debug)
1146 warnx("making new ep fs=0x%x,0x%x",
1147 fsb.f_fsid.val[0],
1148 fsb.f_fsid.val[1]);
1149 } else if (debug)
1150 warnx("found ep fs=0x%x,0x%x",
1151 fsb.f_fsid.val[0],
1152 fsb.f_fsid.val[1]);
1153 }
1154
1155 /*
1156 * Add dirpath to export mount point.
1157 */
1158 dirp = add_expdir(&dirhead, cp, len);
1159 dirplen = len;
1160 } else {
1161 getexp_err(ep, tgrp);
1162 goto nextline;
1163 }
1164 *endcp = savedc;
1165 } else {
1166 savedc = *endcp;
1167 *endcp = '\0';
1168 got_nondir = 1;
1169 if (ep == (struct exportlist *)NULL) {
1170 getexp_err(ep, tgrp);
1171 goto nextline;
1172 }
1173
1174 /*
1175 * Get the host or netgroup.
1176 */
1177 setnetgrent(cp);
1178 netgrp = getnetgrent(&hst, &usr, &dom);
1179 do {
1180 if (has_host) {
1181 grp->gr_next = get_grp();
1182 grp = grp->gr_next;
1183 }
1184 if (netgrp) {
1185 if (hst == 0) {
1186 syslog(LOG_ERR,
1187 "null hostname in netgroup %s, skipping", cp);
1188 grp->gr_type = GT_IGNORE;
1189 } else if (get_host(hst, grp, tgrp)) {
1190 syslog(LOG_ERR,
1191 "bad host %s in netgroup %s, skipping", hst, cp);
1192 grp->gr_type = GT_IGNORE;
1193 }
1194 } else if (get_host(cp, grp, tgrp)) {
1195 syslog(LOG_ERR, "bad host %s, skipping", cp);
1196 grp->gr_type = GT_IGNORE;
1197 }
1198 has_host = TRUE;
1199 } while (netgrp && getnetgrent(&hst, &usr, &dom));
1200 endnetgrent();
1201 *endcp = savedc;
1202 }
1203 cp = endcp;
1204 nextfield(&cp, &endcp);
1205 len = endcp - cp;
1206 }
1207 if (check_options(dirhead)) {
1208 getexp_err(ep, tgrp);
1209 goto nextline;
1210 }
1211 if (!has_host) {
1212 grp->gr_type = GT_DEFAULT;
1213 if (debug)
1214 warnx("adding a default entry");
1215
1216 /*
1217 * Don't allow a network export coincide with a list of
1218 * host(s) on the same line.
1219 */
1220 } else if ((opt_flags & OP_NET) && tgrp->gr_next) {
1221 syslog(LOG_ERR, "network/host conflict");
1222 getexp_err(ep, tgrp);
1223 goto nextline;
1224
1225 /*
1226 * If an export list was specified on this line, make sure
1227 * that we have at least one valid entry, otherwise skip it.
1228 */
1229 } else {
1230 grp = tgrp;
1231 while (grp && grp->gr_type == GT_IGNORE)
1232 grp = grp->gr_next;
1233 if (! grp) {
1234 getexp_err(ep, tgrp);
1235 goto nextline;
1236 }
1237 }
1238
1239 /*
1240 * Loop through hosts, pushing the exports into the kernel.
1241 * After loop, tgrp points to the start of the list and
1242 * grp points to the last entry in the list.
1243 */
1244 grp = tgrp;
1245 do {
1246 if (do_mount(ep, grp, exflags, &anon, dirp, dirplen,
1247 &fsb)) {
1248 getexp_err(ep, tgrp);
1249 goto nextline;
1250 }
1251 } while (grp->gr_next && (grp = grp->gr_next));
1252
1253 /*
1254 * Success. Update the data structures.
1255 */
1256 if (has_host) {
1257 hang_dirp(dirhead, tgrp, ep, opt_flags);
1258 grp->gr_next = grphead;
1259 grphead = tgrp;
1260 } else {
1261 hang_dirp(dirhead, (struct grouplist *)NULL, ep,
1262 opt_flags);
1263 free_grp(grp);
1264 }
1265 dirhead = (struct dirlist *)NULL;
1266 if ((ep->ex_flag & EX_LINKED) == 0) {
1267 ep2 = exphead;
1268 epp = &exphead;
1269
1270 /*
1271 * Insert in the list in alphabetical order.
1272 */
1273 while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
1274 epp = &ep2->ex_next;
1275 ep2 = ep2->ex_next;
1276 }
1277 if (ep2)
1278 ep->ex_next = ep2;
1279 *epp = ep;
1280 ep->ex_flag |= EX_LINKED;
1281 }
1282nextline:
1283 if (dirhead) {
1284 free_dir(dirhead);
1285 dirhead = (struct dirlist *)NULL;
1286 }
1287 }
1288 fclose(exp_file);
1289}
1290
1291/*
1292 * Allocate an export list element
1293 */
1294struct exportlist *
1295get_exp()
1296{
1297 struct exportlist *ep;
1298
1299 ep = (struct exportlist *)malloc(sizeof (struct exportlist));
1300 if (ep == (struct exportlist *)NULL)
1301 out_of_mem();
1302 memset(ep, 0, sizeof(struct exportlist));
1303 return (ep);
1304}
1305
1306/*
1307 * Allocate a group list element
1308 */
1309struct grouplist *
1310get_grp()
1311{
1312 struct grouplist *gp;
1313
1314 gp = (struct grouplist *)malloc(sizeof (struct grouplist));
1315 if (gp == (struct grouplist *)NULL)
1316 out_of_mem();
1317 memset(gp, 0, sizeof(struct grouplist));
1318 return (gp);
1319}
1320
1321/*
1322 * Clean up upon an error in get_exportlist().
1323 */
1324void
1325getexp_err(ep, grp)
1326 struct exportlist *ep;
1327 struct grouplist *grp;
1328{
1329 struct grouplist *tgrp;
1330
1331 if (!(opt_flags & OP_QUIET))
1332 syslog(LOG_ERR, "bad exports list line %s", line);
1333 if (ep && (ep->ex_flag & EX_LINKED) == 0)
1334 free_exp(ep);
1335 while (grp) {
1336 tgrp = grp;
1337 grp = grp->gr_next;
1338 free_grp(tgrp);
1339 }
1340}
1341
1342/*
1343 * Search the export list for a matching fs.
1344 */
1345struct exportlist *
1346ex_search(fsid)
1347 fsid_t *fsid;
1348{
1349 struct exportlist *ep;
1350
1351 ep = exphead;
1352 while (ep) {
1353 if (ep->ex_fs.val[0] == fsid->val[0] &&
1354 ep->ex_fs.val[1] == fsid->val[1])
1355 return (ep);
1356 ep = ep->ex_next;
1357 }
1358 return (ep);
1359}
1360
1361/*
1362 * Add a directory path to the list.
1363 */
1364char *
1365add_expdir(dpp, cp, len)
1366 struct dirlist **dpp;
1367 char *cp;
1368 int len;
1369{
1370 struct dirlist *dp;
1371
1372 dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
1373 if (dp == (struct dirlist *)NULL)
1374 out_of_mem();
1375 dp->dp_left = *dpp;
1376 dp->dp_right = (struct dirlist *)NULL;
1377 dp->dp_flag = 0;
1378 dp->dp_hosts = (struct hostlist *)NULL;
1379 strcpy(dp->dp_dirp, cp);
1380 *dpp = dp;
1381 return (dp->dp_dirp);
1382}
1383
1384/*
1385 * Hang the dir list element off the dirpath binary tree as required
1386 * and update the entry for host.
1387 */
1388void
1389hang_dirp(dp, grp, ep, flags)
1390 struct dirlist *dp;
1391 struct grouplist *grp;
1392 struct exportlist *ep;
1393 int flags;
1394{
1395 struct hostlist *hp;
1396 struct dirlist *dp2;
1397
1398 if (flags & OP_ALLDIRS) {
1399 if (ep->ex_defdir)
1400 free((caddr_t)dp);
1401 else
1402 ep->ex_defdir = dp;
1403 if (grp == (struct grouplist *)NULL) {
1404 ep->ex_defdir->dp_flag |= DP_DEFSET;
1405 } else while (grp) {
1406 hp = get_ht();
1407 hp->ht_grp = grp;
1408 hp->ht_next = ep->ex_defdir->dp_hosts;
1409 ep->ex_defdir->dp_hosts = hp;
1410 grp = grp->gr_next;
1411 }
1412 } else {
1413
1414 /*
1415 * Loop through the directories adding them to the tree.
1416 */
1417 while (dp) {
1418 dp2 = dp->dp_left;
1419 add_dlist(&ep->ex_dirl, dp, grp, flags);
1420 dp = dp2;
1421 }
1422 }
1423}
1424
1425/*
1426 * Traverse the binary tree either updating a node that is already there
1427 * for the new directory or adding the new node.
1428 */
1429void
1430add_dlist(dpp, newdp, grp, flags)
1431 struct dirlist **dpp;
1432 struct dirlist *newdp;
1433 struct grouplist *grp;
1434 int flags;
1435{
1436 struct dirlist *dp;
1437 struct hostlist *hp;
1438 int cmp;
1439
1440 dp = *dpp;
1441 if (dp) {
1442 cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
1443 if (cmp > 0) {
1444 add_dlist(&dp->dp_left, newdp, grp, flags);
1445 return;
1446 } else if (cmp < 0) {
1447 add_dlist(&dp->dp_right, newdp, grp, flags);
1448 return;
1449 } else
1450 free((caddr_t)newdp);
1451 } else {
1452 dp = newdp;
1453 dp->dp_left = (struct dirlist *)NULL;
1454 *dpp = dp;
1455 }
1456 if (grp) {
1457
1458 /*
1459 * Hang all of the host(s) off of the directory point.
1460 */
1461 do {
1462 hp = get_ht();
1463 hp->ht_grp = grp;
1464 hp->ht_next = dp->dp_hosts;
1465 dp->dp_hosts = hp;
1466 grp = grp->gr_next;
1467 } while (grp);
1468 } else {
1469 dp->dp_flag |= DP_DEFSET;
1470 }
1471}
1472
1473/*
1474 * Search for a dirpath on the export point.
1475 */
1476struct dirlist *
1477dirp_search(dp, dirp)
1478 struct dirlist *dp;
1479 char *dirp;
1480{
1481 int cmp;
1482
1483 if (dp) {
1484 cmp = strcmp(dp->dp_dirp, dirp);
1485 if (cmp > 0)
1486 return (dirp_search(dp->dp_left, dirp));
1487 else if (cmp < 0)
1488 return (dirp_search(dp->dp_right, dirp));
1489 else
1490 return (dp);
1491 }
1492 return (dp);
1493}
1494
1495/*
1496 * Scan for a host match in a directory tree.
1497 */
1498int
1499chk_host(dp, saddr, defsetp, hostsetp)
1500 struct dirlist *dp;
1501 struct sockaddr *saddr;
1502 int *defsetp;
1503 int *hostsetp;
1504{
1505 struct hostlist *hp;
1506 struct grouplist *grp;
1507 struct addrinfo *ai;
1508
1509 if (dp) {
1510 if (dp->dp_flag & DP_DEFSET)
1511 *defsetp = dp->dp_flag;
1512 hp = dp->dp_hosts;
1513 while (hp) {
1514 grp = hp->ht_grp;
1515 switch (grp->gr_type) {
1516 case GT_HOST:
1517 ai = grp->gr_ptr.gt_addrinfo;
1518 for (; ai; ai = ai->ai_next) {
1519 if (!sacmp(ai->ai_addr, saddr, NULL)) {
1520 *hostsetp =
1521 (hp->ht_flag | DP_HOSTSET);
1522 return (1);
1523 }
1524 }
1525 break;
1526 case GT_NET:
1527 if (!sacmp(saddr, (struct sockaddr *)
1528 &grp->gr_ptr.gt_net.nt_net,
1529 (struct sockaddr *)
1530 &grp->gr_ptr.gt_net.nt_mask)) {
1531 *hostsetp = (hp->ht_flag | DP_HOSTSET);
1532 return (1);
1533 }
1534 break;
1535 }
1536 hp = hp->ht_next;
1537 }
1538 }
1539 return (0);
1540}
1541
1542/*
1543 * Scan tree for a host that matches the address.
1544 */
1545int
1546scan_tree(dp, saddr)
1547 struct dirlist *dp;
1548 struct sockaddr *saddr;
1549{
1550 int defset, hostset;
1551
1552 if (dp) {
1553 if (scan_tree(dp->dp_left, saddr))
1554 return (1);
1555 if (chk_host(dp, saddr, &defset, &hostset))
1556 return (1);
1557 if (scan_tree(dp->dp_right, saddr))
1558 return (1);
1559 }
1560 return (0);
1561}
1562
1563/*
1564 * Traverse the dirlist tree and free it up.
1565 */
1566void
1567free_dir(dp)
1568 struct dirlist *dp;
1569{
1570
1571 if (dp) {
1572 free_dir(dp->dp_left);
1573 free_dir(dp->dp_right);
1574 free_host(dp->dp_hosts);
1575 free((caddr_t)dp);
1576 }
1577}
1578
1579/*
1580 * Parse the option string and update fields.
1581 * Option arguments may either be -<option>=<value> or
1582 * -<option> <value>
1583 */
1584int
1585do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
1586 char **cpp, **endcpp;
1587 struct exportlist *ep;
1588 struct grouplist *grp;
1589 int *has_hostp;
1590 int *exflagsp;
1591 struct xucred *cr;
1592{
1593 char *cpoptarg, *cpoptend;
1594 char *cp, *endcp, *cpopt, savedc, savedc2;
1595 int allflag, usedarg;
1596
1597 savedc2 = '\0';
1598 cpopt = *cpp;
1599 cpopt++;
1600 cp = *endcpp;
1601 savedc = *cp;
1602 *cp = '\0';
1603 while (cpopt && *cpopt) {
1604 allflag = 1;
1605 usedarg = -2;
1606 if ((cpoptend = strchr(cpopt, ','))) {
1607 *cpoptend++ = '\0';
1608 if ((cpoptarg = strchr(cpopt, '=')))
1609 *cpoptarg++ = '\0';
1610 } else {
1611 if ((cpoptarg = strchr(cpopt, '=')))
1612 *cpoptarg++ = '\0';
1613 else {
1614 *cp = savedc;
1615 nextfield(&cp, &endcp);
1616 **endcpp = '\0';
1617 if (endcp > cp && *cp != '-') {
1618 cpoptarg = cp;
1619 savedc2 = *endcp;
1620 *endcp = '\0';
1621 usedarg = 0;
1622 }
1623 }
1624 }
1625 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
1626 *exflagsp |= MNT_EXRDONLY;
1627 } else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
1628 !(allflag = strcmp(cpopt, "mapall")) ||
1629 !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
1630 usedarg++;
1631 parsecred(cpoptarg, cr);
1632 if (allflag == 0) {
1633 *exflagsp |= MNT_EXPORTANON;
1634 opt_flags |= OP_MAPALL;
1635 } else
1636 opt_flags |= OP_MAPROOT;
1637 } else if (cpoptarg && (!strcmp(cpopt, "mask") ||
1638 !strcmp(cpopt, "m"))) {
1639 if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
1640 syslog(LOG_ERR, "bad mask: %s", cpoptarg);
1641 return (1);
1642 }
1643 usedarg++;
1644 opt_flags |= OP_MASK;
1645 } else if (cpoptarg && (!strcmp(cpopt, "network") ||
1646 !strcmp(cpopt, "n"))) {
1647 if (strchr(cpoptarg, '/') != NULL) {
1648 if (debug)
1649 fprintf(stderr, "setting OP_MASKLEN\n");
1650 opt_flags |= OP_MASKLEN;
1651 }
1652 if (grp->gr_type != GT_NULL) {
1653 syslog(LOG_ERR, "network/host conflict");
1654 return (1);
1655 } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
1656 syslog(LOG_ERR, "bad net: %s", cpoptarg);
1657 return (1);
1658 }
1659 grp->gr_type = GT_NET;
1660 *has_hostp = 1;
1661 usedarg++;
1662 opt_flags |= OP_NET;
1663 } else if (!strcmp(cpopt, "alldirs")) {
1664 opt_flags |= OP_ALLDIRS;
1665 } else if (!strcmp(cpopt, "public")) {
1666 *exflagsp |= MNT_EXPUBLIC;
1667 } else if (!strcmp(cpopt, "webnfs")) {
1668 *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON);
1669 opt_flags |= OP_MAPALL;
1670 } else if (cpoptarg && !strcmp(cpopt, "index")) {
1671 ep->ex_indexfile = strdup(cpoptarg);
1672 } else if (!strcmp(cpopt, "quiet")) {
1673 opt_flags |= OP_QUIET;
1674 } else {
1675 syslog(LOG_ERR, "bad opt %s", cpopt);
1676 return (1);
1677 }
1678 if (usedarg >= 0) {
1679 *endcp = savedc2;
1680 **endcpp = savedc;
1681 if (usedarg > 0) {
1682 *cpp = cp;
1683 *endcpp = endcp;
1684 }
1685 return (0);
1686 }
1687 cpopt = cpoptend;
1688 }
1689 **endcpp = savedc;
1690 return (0);
1691}
1692
1693/*
1694 * Translate a character string to the corresponding list of network
1695 * addresses for a hostname.
1696 */
1697int
1698get_host(cp, grp, tgrp)
1699 char *cp;
1700 struct grouplist *grp;
1701 struct grouplist *tgrp;
1702{
1703 struct grouplist *checkgrp;
1704 struct addrinfo *ai, *tai, hints;
1705 int ecode;
1706 char host[NI_MAXHOST];
1707
1708 if (grp->gr_type != GT_NULL) {
1709 syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp);
1710 return (1);
1711 }
1712 memset(&hints, 0, sizeof hints);
1713 hints.ai_flags = AI_CANONNAME;
1714 hints.ai_protocol = IPPROTO_UDP;
1715 ecode = getaddrinfo(cp, NULL, &hints, &ai);
1716 if (ecode != 0) {
1717 syslog(LOG_ERR,"can't get address info for host %s", cp);
1718 return 1;
1719 }
1720 grp->gr_ptr.gt_addrinfo = ai;
1721 while (ai != NULL) {
1722 if (ai->ai_canonname == NULL) {
1723 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host,
1724 sizeof host, NULL, 0, NI_NUMERICHOST) != 0)
1725 strlcpy(host, "?", sizeof(host));
1726 ai->ai_canonname = strdup(host);
1727 ai->ai_flags |= AI_CANONNAME;
1728 }
1729 if (debug)
1730 fprintf(stderr, "got host %s\n", ai->ai_canonname);
1731 /*
1732 * Sanity check: make sure we don't already have an entry
1733 * for this host in the grouplist.
1734 */
1735 for (checkgrp = tgrp; checkgrp != NULL;
1736 checkgrp = checkgrp->gr_next) {
1737 if (checkgrp->gr_type != GT_HOST)
1738 continue;
1739 for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL;
1740 tai = tai->ai_next) {
1741 if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0)
1742 continue;
1743 if (debug)
1744 fprintf(stderr,
1745 "ignoring duplicate host %s\n",
1746 ai->ai_canonname);
1747 grp->gr_type = GT_IGNORE;
1748 return (0);
1749 }
1750 }
1751 ai = ai->ai_next;
1752 }
1753 grp->gr_type = GT_HOST;
1754 return (0);
1755}
1756
1757/*
1758 * Free up an exports list component
1759 */
1760void
1761free_exp(ep)
1762 struct exportlist *ep;
1763{
1764
1765 if (ep->ex_defdir) {
1766 free_host(ep->ex_defdir->dp_hosts);
1767 free((caddr_t)ep->ex_defdir);
1768 }
1769 if (ep->ex_fsdir)
1770 free(ep->ex_fsdir);
1771 if (ep->ex_indexfile)
1772 free(ep->ex_indexfile);
1773 free_dir(ep->ex_dirl);
1774 free((caddr_t)ep);
1775}
1776
1777/*
1778 * Free hosts.
1779 */
1780void
1781free_host(hp)
1782 struct hostlist *hp;
1783{
1784 struct hostlist *hp2;
1785
1786 while (hp) {
1787 hp2 = hp;
1788 hp = hp->ht_next;
1789 free((caddr_t)hp2);
1790 }
1791}
1792
1793struct hostlist *
1794get_ht()
1795{
1796 struct hostlist *hp;
1797
1798 hp = (struct hostlist *)malloc(sizeof (struct hostlist));
1799 if (hp == (struct hostlist *)NULL)
1800 out_of_mem();
1801 hp->ht_next = (struct hostlist *)NULL;
1802 hp->ht_flag = 0;
1803 return (hp);
1804}
1805
1806/*
1807 * Out of memory, fatal
1808 */
1809void
1810out_of_mem()
1811{
1812
1813 syslog(LOG_ERR, "out of memory");
1814 exit(2);
1815}
1816
1817/*
1781 * Do the mount syscall with the update flag to push the export info into
1818 * Do the nmount() syscall with the update flag to push the export info into
1782 * the kernel.
1783 */
1784int
1819 * the kernel.
1820 */
1821int
1785do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
1786 struct exportlist *ep;
1787 struct grouplist *grp;
1788 int exflags;
1789 struct xucred *anoncrp;
1790 char *dirp;
1791 int dirplen;
1792 struct statfs *fsb;
1822do_mount(struct exportlist *ep, struct grouplist *grp, int exflags,
1823 struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb)
1793{
1794 struct statfs fsb1;
1795 struct addrinfo *ai;
1824{
1825 struct statfs fsb1;
1826 struct addrinfo *ai;
1796 struct export_args *eap;
1797 char *cp = NULL;
1827 struct export_args eap;
1828 char errmsg[255];
1829 char *cp;
1798 int done;
1830 int done;
1799 char savedc = '\0';
1800 union {
1801 struct ufs_args ua;
1802 struct iso_args ia;
1803 struct msdosfs_args da;
1804 struct ntfs_args na;
1805 } args;
1831 char savedc;
1832 struct iovec *iov;
1833 int iovlen;
1834 int ret;
1806
1835
1807 bzero(&args, sizeof args);
1808 /* XXX, we assume that all xx_args look like ufs_args. */
1809 args.ua.fspec = 0;
1810 eap = &args.ua.export;
1836 cp = NULL;
1837 savedc = '\0';
1838 iov = NULL;
1839 iovlen = 0;
1840 ret = 0;
1811
1841
1812 eap->ex_flags = exflags;
1813 eap->ex_anon = *anoncrp;
1814 eap->ex_indexfile = ep->ex_indexfile;
1842 bzero(&eap, sizeof(eap));
1843 bzero(errmsg, sizeof(errmsg));
1844 eap.ex_flags = exflags;
1845 eap.ex_anon = *anoncrp;
1846 eap.ex_indexfile = ep->ex_indexfile;
1815 if (grp->gr_type == GT_HOST)
1816 ai = grp->gr_ptr.gt_addrinfo;
1817 else
1818 ai = NULL;
1819 done = FALSE;
1847 if (grp->gr_type == GT_HOST)
1848 ai = grp->gr_ptr.gt_addrinfo;
1849 else
1850 ai = NULL;
1851 done = FALSE;
1852
1853 build_iovec(&iov, &iovlen, "fstype", NULL, 0);
1854 build_iovec(&iov, &iovlen, "fspath", NULL, 0);
1855 build_iovec(&iov, &iovlen, "from", NULL, 0);
1856 build_iovec(&iov, &iovlen, "update", NULL, 0);
1857 build_iovec(&iov, &iovlen, "export", &eap, sizeof(eap));
1858 build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
1859
1820 while (!done) {
1821 switch (grp->gr_type) {
1822 case GT_HOST:
1823 if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0)
1824 goto skip;
1860 while (!done) {
1861 switch (grp->gr_type) {
1862 case GT_HOST:
1863 if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0)
1864 goto skip;
1825 eap->ex_addr = ai->ai_addr;
1826 eap->ex_addrlen = ai->ai_addrlen;
1827 eap->ex_masklen = 0;
1865 eap.ex_addr = ai->ai_addr;
1866 eap.ex_addrlen = ai->ai_addrlen;
1867 eap.ex_masklen = 0;
1828 break;
1829 case GT_NET:
1830 if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 &&
1831 have_v6 == 0)
1832 goto skip;
1868 break;
1869 case GT_NET:
1870 if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 &&
1871 have_v6 == 0)
1872 goto skip;
1833 eap->ex_addr =
1873 eap.ex_addr =
1834 (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net;
1874 (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net;
1835 eap->ex_addrlen = args.ua.export.ex_addr->sa_len;
1836 eap->ex_mask =
1875 eap.ex_addrlen =
1876 ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len;
1877 eap.ex_mask =
1837 (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask;
1878 (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask;
1838 eap->ex_masklen = args.ua.export.ex_mask->sa_len;
1879 eap.ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len;
1839 break;
1840 case GT_DEFAULT:
1880 break;
1881 case GT_DEFAULT:
1841 eap->ex_addr = NULL;
1842 eap->ex_addrlen = 0;
1843 eap->ex_mask = NULL;
1844 eap->ex_masklen = 0;
1882 eap.ex_addr = NULL;
1883 eap.ex_addrlen = 0;
1884 eap.ex_mask = NULL;
1885 eap.ex_masklen = 0;
1845 break;
1846 case GT_IGNORE:
1886 break;
1887 case GT_IGNORE:
1847 return(0);
1888 ret = 0;
1889 goto error_exit;
1848 break;
1849 default:
1850 syslog(LOG_ERR, "bad grouptype");
1851 if (cp)
1852 *cp = savedc;
1890 break;
1891 default:
1892 syslog(LOG_ERR, "bad grouptype");
1893 if (cp)
1894 *cp = savedc;
1853 return (1);
1895 ret = 1;
1896 goto error_exit;
1854 };
1855
1856 /*
1857 * XXX:
1858 * Maybe I should just use the fsb->f_mntonname path instead
1859 * of looping back up the dirp to the mount point??
1860 * Also, needs to know how to export all types of local
1861 * exportable filesystems and not just "ufs".
1862 */
1897 };
1898
1899 /*
1900 * XXX:
1901 * Maybe I should just use the fsb->f_mntonname path instead
1902 * of looping back up the dirp to the mount point??
1903 * Also, needs to know how to export all types of local
1904 * exportable filesystems and not just "ufs".
1905 */
1863 while (mount(fsb->f_fstypename, dirp,
1864 fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
1906 iov[1].iov_base = fsb->f_fstypename; /* "fstype" */
1907 iov[1].iov_len = strlen(fsb->f_fstypename) + 1;
1908 iov[3].iov_base = fsb->f_mntonname; /* "fspath" */
1909 iov[3].iov_len = strlen(fsb->f_mntonname) + 1;
1910 iov[5].iov_base = fsb->f_mntfromname; /* "from" */
1911 iov[5].iov_len = strlen(fsb->f_mntfromname) + 1;
1912
1913 while (nmount(iov, iovlen, 0) < 0) {
1865 if (cp)
1866 *cp-- = savedc;
1867 else
1868 cp = dirp + dirplen - 1;
1914 if (cp)
1915 *cp-- = savedc;
1916 else
1917 cp = dirp + dirplen - 1;
1869 if (opt_flags & OP_QUIET)
1870 return (1);
1918 if (opt_flags & OP_QUIET) {
1919 ret = 1;
1920 goto error_exit;
1921 }
1871 if (errno == EPERM) {
1872 if (debug)
1873 warnx("can't change attributes for %s",
1874 dirp);
1875 syslog(LOG_ERR,
1876 "can't change attributes for %s", dirp);
1922 if (errno == EPERM) {
1923 if (debug)
1924 warnx("can't change attributes for %s",
1925 dirp);
1926 syslog(LOG_ERR,
1927 "can't change attributes for %s", dirp);
1877 return (1);
1928 ret = 1;
1929 goto error_exit;
1878 }
1879 if (opt_flags & OP_ALLDIRS) {
1880 if (errno == EINVAL)
1881 syslog(LOG_ERR,
1882 "-alldirs requested but %s is not a filesystem mountpoint",
1883 dirp);
1884 else
1885 syslog(LOG_ERR,
1886 "could not remount %s: %m",
1887 dirp);
1930 }
1931 if (opt_flags & OP_ALLDIRS) {
1932 if (errno == EINVAL)
1933 syslog(LOG_ERR,
1934 "-alldirs requested but %s is not a filesystem mountpoint",
1935 dirp);
1936 else
1937 syslog(LOG_ERR,
1938 "could not remount %s: %m",
1939 dirp);
1888 return (1);
1940 ret = 1;
1941 goto error_exit;
1889 }
1890 /* back up over the last component */
1891 while (*cp == '/' && cp > dirp)
1892 cp--;
1893 while (*(cp - 1) != '/' && cp > dirp)
1894 cp--;
1895 if (cp == dirp) {
1896 if (debug)
1897 warnx("mnt unsucc");
1898 syslog(LOG_ERR, "can't export %s", dirp);
1942 }
1943 /* back up over the last component */
1944 while (*cp == '/' && cp > dirp)
1945 cp--;
1946 while (*(cp - 1) != '/' && cp > dirp)
1947 cp--;
1948 if (cp == dirp) {
1949 if (debug)
1950 warnx("mnt unsucc");
1951 syslog(LOG_ERR, "can't export %s", dirp);
1899 return (1);
1952 ret = 1;
1953 goto error_exit;
1900 }
1901 savedc = *cp;
1902 *cp = '\0';
1903 /* Check that we're still on the same filesystem. */
1904 if (statfs(dirp, &fsb1) != 0 || bcmp(&fsb1.f_fsid,
1905 &fsb->f_fsid, sizeof(fsb1.f_fsid)) != 0) {
1906 *cp = savedc;
1907 syslog(LOG_ERR, "can't export %s", dirp);
1954 }
1955 savedc = *cp;
1956 *cp = '\0';
1957 /* Check that we're still on the same filesystem. */
1958 if (statfs(dirp, &fsb1) != 0 || bcmp(&fsb1.f_fsid,
1959 &fsb->f_fsid, sizeof(fsb1.f_fsid)) != 0) {
1960 *cp = savedc;
1961 syslog(LOG_ERR, "can't export %s", dirp);
1908 return (1);
1962 ret = 1;
1963 goto error_exit;
1909 }
1910 }
1911skip:
1912 if (ai != NULL)
1913 ai = ai->ai_next;
1914 if (ai == NULL)
1915 done = TRUE;
1916 }
1917 if (cp)
1918 *cp = savedc;
1964 }
1965 }
1966skip:
1967 if (ai != NULL)
1968 ai = ai->ai_next;
1969 if (ai == NULL)
1970 done = TRUE;
1971 }
1972 if (cp)
1973 *cp = savedc;
1919 return (0);
1974error_exit:
1975 /* free strings allocated by strdup() in getmntopts.c */
1976 if (iov != NULL) {
1977 free(iov[0].iov_base); /* fstype */
1978 free(iov[2].iov_base); /* fspath */
1979 free(iov[4].iov_base); /* from */
1980 free(iov[6].iov_base); /* update */
1981 free(iov[8].iov_base); /* export */
1982 free(iov[10].iov_base); /* errmsg */
1983
1984 /* free iov, allocated by realloc() */
1985 free(iov);
1986 }
1987 return (ret);
1920}
1921
1922/*
1923 * Translate a net address.
1924 *
1925 * If `maskflg' is nonzero, then `cp' is a netmask, not a network address.
1926 */
1927int
1928get_net(cp, net, maskflg)
1929 char *cp;
1930 struct netmsk *net;
1931 int maskflg;
1932{
1933 struct netent *np = NULL;
1934 char *name, *p, *prefp;
1935 struct sockaddr_in sin;
1936 struct sockaddr *sa = NULL;
1937 struct addrinfo hints, *ai = NULL;
1938 char netname[NI_MAXHOST];
1939 long preflen;
1940
1941 p = prefp = NULL;
1942 if ((opt_flags & OP_MASKLEN) && !maskflg) {
1943 p = strchr(cp, '/');
1944 *p = '\0';
1945 prefp = p + 1;
1946 }
1947
1948 /*
1949 * Check for a numeric address first. We wish to avoid
1950 * possible DNS lookups in getnetbyname().
1951 */
1952 if (isxdigit(*cp) || *cp == ':') {
1953 memset(&hints, 0, sizeof hints);
1954 /* Ensure the mask and the network have the same family. */
1955 if (maskflg && (opt_flags & OP_NET))
1956 hints.ai_family = net->nt_net.ss_family;
1957 else if (!maskflg && (opt_flags & OP_HAVEMASK))
1958 hints.ai_family = net->nt_mask.ss_family;
1959 else
1960 hints.ai_family = AF_UNSPEC;
1961 hints.ai_flags = AI_NUMERICHOST;
1962 if (getaddrinfo(cp, NULL, &hints, &ai) == 0)
1963 sa = ai->ai_addr;
1964 if (sa != NULL && ai->ai_family == AF_INET) {
1965 /*
1966 * The address in `cp' is really a network address, so
1967 * use inet_network() to re-interpret this correctly.
1968 * e.g. "127.1" means 127.1.0.0, not 127.0.0.1.
1969 */
1970 bzero(&sin, sizeof sin);
1971 sin.sin_family = AF_INET;
1972 sin.sin_len = sizeof sin;
1973 sin.sin_addr = inet_makeaddr(inet_network(cp), 0);
1974 if (debug)
1975 fprintf(stderr, "get_net: v4 addr %s\n",
1976 inet_ntoa(sin.sin_addr));
1977 sa = (struct sockaddr *)&sin;
1978 }
1979 }
1980 if (sa == NULL && (np = getnetbyname(cp)) != NULL) {
1981 bzero(&sin, sizeof sin);
1982 sin.sin_family = AF_INET;
1983 sin.sin_len = sizeof sin;
1984 sin.sin_addr = inet_makeaddr(np->n_net, 0);
1985 sa = (struct sockaddr *)&sin;
1986 }
1987 if (sa == NULL)
1988 goto fail;
1989
1990 if (maskflg) {
1991 /* The specified sockaddr is a mask. */
1992 if (checkmask(sa) != 0)
1993 goto fail;
1994 bcopy(sa, &net->nt_mask, sa->sa_len);
1995 opt_flags |= OP_HAVEMASK;
1996 } else {
1997 /* The specified sockaddr is a network address. */
1998 bcopy(sa, &net->nt_net, sa->sa_len);
1999
2000 /* Get a network name for the export list. */
2001 if (np) {
2002 name = np->n_name;
2003 } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname,
2004 NULL, 0, NI_NUMERICHOST) == 0) {
2005 name = netname;
2006 } else {
2007 goto fail;
2008 }
2009 if ((net->nt_name = strdup(name)) == NULL)
2010 out_of_mem();
2011
2012 /*
2013 * Extract a mask from either a "/<masklen>" suffix, or
2014 * from the class of an IPv4 address.
2015 */
2016 if (opt_flags & OP_MASKLEN) {
2017 preflen = strtol(prefp, NULL, 10);
2018 if (preflen < 0L || preflen == LONG_MAX)
2019 goto fail;
2020 bcopy(sa, &net->nt_mask, sa->sa_len);
2021 if (makemask(&net->nt_mask, (int)preflen) != 0)
2022 goto fail;
2023 opt_flags |= OP_HAVEMASK;
2024 *p = '/';
2025 } else if (sa->sa_family == AF_INET &&
2026 (opt_flags & OP_MASK) == 0) {
2027 in_addr_t addr;
2028
2029 addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
2030 if (IN_CLASSA(addr))
2031 preflen = 8;
2032 else if (IN_CLASSB(addr))
2033 preflen = 16;
2034 else if (IN_CLASSC(addr))
2035 preflen = 24;
2036 else if (IN_CLASSD(addr))
2037 preflen = 28;
2038 else
2039 preflen = 32; /* XXX */
2040
2041 bcopy(sa, &net->nt_mask, sa->sa_len);
2042 makemask(&net->nt_mask, (int)preflen);
2043 opt_flags |= OP_HAVEMASK;
2044 }
2045 }
2046
2047 if (ai)
2048 freeaddrinfo(ai);
2049 return 0;
2050
2051fail:
2052 if (ai)
2053 freeaddrinfo(ai);
2054 return 1;
2055}
2056
2057/*
2058 * Parse out the next white space separated field
2059 */
2060void
2061nextfield(cp, endcp)
2062 char **cp;
2063 char **endcp;
2064{
2065 char *p;
2066
2067 p = *cp;
2068 while (*p == ' ' || *p == '\t')
2069 p++;
2070 if (*p == '\n' || *p == '\0')
2071 *cp = *endcp = p;
2072 else {
2073 *cp = p++;
2074 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
2075 p++;
2076 *endcp = p;
2077 }
2078}
2079
2080/*
2081 * Get an exports file line. Skip over blank lines and handle line
2082 * continuations.
2083 */
2084int
2085get_line()
2086{
2087 char *p, *cp;
2088 size_t len;
2089 int totlen, cont_line;
2090
2091 /*
2092 * Loop around ignoring blank lines and getting all continuation lines.
2093 */
2094 p = line;
2095 totlen = 0;
2096 do {
2097 if ((p = fgetln(exp_file, &len)) == NULL)
2098 return (0);
2099 cp = p + len - 1;
2100 cont_line = 0;
2101 while (cp >= p &&
2102 (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
2103 if (*cp == '\\')
2104 cont_line = 1;
2105 cp--;
2106 len--;
2107 }
2108 if (cont_line) {
2109 *++cp = ' ';
2110 len++;
2111 }
2112 if (linesize < len + totlen + 1) {
2113 linesize = len + totlen + 1;
2114 line = realloc(line, linesize);
2115 if (line == NULL)
2116 out_of_mem();
2117 }
2118 memcpy(line + totlen, p, len);
2119 totlen += len;
2120 line[totlen] = '\0';
2121 } while (totlen == 0 || cont_line);
2122 return (1);
2123}
2124
2125/*
2126 * Parse a description of a credential.
2127 */
2128void
2129parsecred(namelist, cr)
2130 char *namelist;
2131 struct xucred *cr;
2132{
2133 char *name;
2134 int cnt;
2135 char *names;
2136 struct passwd *pw;
2137 struct group *gr;
2138 gid_t groups[NGROUPS + 1];
2139 int ngroups;
2140
2141 cr->cr_version = XUCRED_VERSION;
2142 /*
2143 * Set up the unprivileged user.
2144 */
2145 cr->cr_uid = -2;
2146 cr->cr_groups[0] = -2;
2147 cr->cr_ngroups = 1;
2148 /*
2149 * Get the user's password table entry.
2150 */
2151 names = strsep(&namelist, " \t\n");
2152 name = strsep(&names, ":");
2153 if (isdigit(*name) || *name == '-')
2154 pw = getpwuid(atoi(name));
2155 else
2156 pw = getpwnam(name);
2157 /*
2158 * Credentials specified as those of a user.
2159 */
2160 if (names == NULL) {
2161 if (pw == NULL) {
2162 syslog(LOG_ERR, "unknown user: %s", name);
2163 return;
2164 }
2165 cr->cr_uid = pw->pw_uid;
2166 ngroups = NGROUPS + 1;
2167 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
2168 syslog(LOG_ERR, "too many groups");
2169 /*
2170 * Compress out duplicate.
2171 */
2172 cr->cr_ngroups = ngroups - 1;
2173 cr->cr_groups[0] = groups[0];
2174 for (cnt = 2; cnt < ngroups; cnt++)
2175 cr->cr_groups[cnt - 1] = groups[cnt];
2176 return;
2177 }
2178 /*
2179 * Explicit credential specified as a colon separated list:
2180 * uid:gid:gid:...
2181 */
2182 if (pw != NULL)
2183 cr->cr_uid = pw->pw_uid;
2184 else if (isdigit(*name) || *name == '-')
2185 cr->cr_uid = atoi(name);
2186 else {
2187 syslog(LOG_ERR, "unknown user: %s", name);
2188 return;
2189 }
2190 cr->cr_ngroups = 0;
2191 while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
2192 name = strsep(&names, ":");
2193 if (isdigit(*name) || *name == '-') {
2194 cr->cr_groups[cr->cr_ngroups++] = atoi(name);
2195 } else {
2196 if ((gr = getgrnam(name)) == NULL) {
2197 syslog(LOG_ERR, "unknown group: %s", name);
2198 continue;
2199 }
2200 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
2201 }
2202 }
2203 if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
2204 syslog(LOG_ERR, "too many groups");
2205}
2206
2207#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
2208/*
2209 * Routines that maintain the remote mounttab
2210 */
2211void
2212get_mountlist()
2213{
2214 struct mountlist *mlp, **mlpp;
2215 char *host, *dirp, *cp;
2216 char str[STRSIZ];
2217 FILE *mlfile;
2218
2219 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
2220 if (errno == ENOENT)
2221 return;
2222 else {
2223 syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST);
2224 return;
2225 }
2226 }
2227 mlpp = &mlhead;
2228 while (fgets(str, STRSIZ, mlfile) != NULL) {
2229 cp = str;
2230 host = strsep(&cp, " \t\n");
2231 dirp = strsep(&cp, " \t\n");
2232 if (host == NULL || dirp == NULL)
2233 continue;
2234 mlp = (struct mountlist *)malloc(sizeof (*mlp));
2235 if (mlp == (struct mountlist *)NULL)
2236 out_of_mem();
2237 strncpy(mlp->ml_host, host, RPCMNT_NAMELEN);
2238 mlp->ml_host[RPCMNT_NAMELEN] = '\0';
2239 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
2240 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
2241 mlp->ml_next = (struct mountlist *)NULL;
2242 *mlpp = mlp;
2243 mlpp = &mlp->ml_next;
2244 }
2245 fclose(mlfile);
2246}
2247
2248void
2249del_mlist(char *hostp, char *dirp)
2250{
2251 struct mountlist *mlp, **mlpp;
2252 struct mountlist *mlp2;
2253 FILE *mlfile;
2254 int fnd = 0;
2255
2256 mlpp = &mlhead;
2257 mlp = mlhead;
2258 while (mlp) {
2259 if (!strcmp(mlp->ml_host, hostp) &&
2260 (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
2261 fnd = 1;
2262 mlp2 = mlp;
2263 *mlpp = mlp = mlp->ml_next;
2264 free((caddr_t)mlp2);
2265 } else {
2266 mlpp = &mlp->ml_next;
2267 mlp = mlp->ml_next;
2268 }
2269 }
2270 if (fnd) {
2271 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
2272 syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST);
2273 return;
2274 }
2275 mlp = mlhead;
2276 while (mlp) {
2277 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
2278 mlp = mlp->ml_next;
2279 }
2280 fclose(mlfile);
2281 }
2282}
2283
2284void
2285add_mlist(hostp, dirp)
2286 char *hostp, *dirp;
2287{
2288 struct mountlist *mlp, **mlpp;
2289 FILE *mlfile;
2290
2291 mlpp = &mlhead;
2292 mlp = mlhead;
2293 while (mlp) {
2294 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
2295 return;
2296 mlpp = &mlp->ml_next;
2297 mlp = mlp->ml_next;
2298 }
2299 mlp = (struct mountlist *)malloc(sizeof (*mlp));
2300 if (mlp == (struct mountlist *)NULL)
2301 out_of_mem();
2302 strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
2303 mlp->ml_host[RPCMNT_NAMELEN] = '\0';
2304 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
2305 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
2306 mlp->ml_next = (struct mountlist *)NULL;
2307 *mlpp = mlp;
2308 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
2309 syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST);
2310 return;
2311 }
2312 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
2313 fclose(mlfile);
2314}
2315
2316/*
2317 * Free up a group list.
2318 */
2319void
2320free_grp(grp)
2321 struct grouplist *grp;
2322{
2323 if (grp->gr_type == GT_HOST) {
2324 if (grp->gr_ptr.gt_addrinfo != NULL)
2325 freeaddrinfo(grp->gr_ptr.gt_addrinfo);
2326 } else if (grp->gr_type == GT_NET) {
2327 if (grp->gr_ptr.gt_net.nt_name)
2328 free(grp->gr_ptr.gt_net.nt_name);
2329 }
2330 free((caddr_t)grp);
2331}
2332
2333#ifdef DEBUG
2334void
2335SYSLOG(int pri, const char *fmt, ...)
2336{
2337 va_list ap;
2338
2339 va_start(ap, fmt);
2340 vfprintf(stderr, fmt, ap);
2341 va_end(ap);
2342}
2343#endif /* DEBUG */
2344
2345/*
2346 * Check options for consistency.
2347 */
2348int
2349check_options(dp)
2350 struct dirlist *dp;
2351{
2352
2353 if (dp == (struct dirlist *)NULL)
2354 return (1);
2355 if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) {
2356 syslog(LOG_ERR, "-mapall and -maproot mutually exclusive");
2357 return (1);
2358 }
2359 if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
2360 syslog(LOG_ERR, "-mask requires -network");
2361 return (1);
2362 }
2363 if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) {
2364 syslog(LOG_ERR, "-network requires mask specification");
2365 return (1);
2366 }
2367 if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) {
2368 syslog(LOG_ERR, "-mask and /masklen are mutually exclusive");
2369 return (1);
2370 }
2371 if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
2372 syslog(LOG_ERR, "-alldirs has multiple directories");
2373 return (1);
2374 }
2375 return (0);
2376}
2377
2378/*
2379 * Check an absolute directory path for any symbolic links. Return true
2380 */
2381int
2382check_dirpath(dirp)
2383 char *dirp;
2384{
2385 char *cp;
2386 int ret = 1;
2387 struct stat sb;
2388
2389 cp = dirp + 1;
2390 while (*cp && ret) {
2391 if (*cp == '/') {
2392 *cp = '\0';
2393 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
2394 ret = 0;
2395 *cp = '/';
2396 }
2397 cp++;
2398 }
2399 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
2400 ret = 0;
2401 return (ret);
2402}
2403
2404/*
2405 * Make a netmask according to the specified prefix length. The ss_family
2406 * and other non-address fields must be initialised before calling this.
2407 */
2408int
2409makemask(struct sockaddr_storage *ssp, int bitlen)
2410{
2411 u_char *p;
2412 int bits, i, len;
2413
2414 if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL)
2415 return (-1);
2416 if (bitlen > len * CHAR_BIT)
2417 return (-1);
2418
2419 for (i = 0; i < len; i++) {
2420 bits = (bitlen > CHAR_BIT) ? CHAR_BIT : bitlen;
2421 *p++ = (1 << bits) - 1;
2422 bitlen -= bits;
2423 }
2424 return 0;
2425}
2426
2427/*
2428 * Check that the sockaddr is a valid netmask. Returns 0 if the mask
2429 * is acceptable (i.e. of the form 1...10....0).
2430 */
2431int
2432checkmask(struct sockaddr *sa)
2433{
2434 u_char *mask;
2435 int i, len;
2436
2437 if ((mask = sa_rawaddr(sa, &len)) == NULL)
2438 return (-1);
2439
2440 for (i = 0; i < len; i++)
2441 if (mask[i] != 0xff)
2442 break;
2443 if (i < len) {
2444 if (~mask[i] & (u_char)(~mask[i] + 1))
2445 return (-1);
2446 i++;
2447 }
2448 for (; i < len; i++)
2449 if (mask[i] != 0)
2450 return (-1);
2451 return (0);
2452}
2453
2454/*
2455 * Compare two sockaddrs according to a specified mask. Return zero if
2456 * `sa1' matches `sa2' when filtered by the netmask in `samask'.
2457 * If samask is NULL, perform a full comparision.
2458 */
2459int
2460sacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask)
2461{
2462 unsigned char *p1, *p2, *mask;
2463 int len, i;
2464
2465 if (sa1->sa_family != sa2->sa_family ||
2466 (p1 = sa_rawaddr(sa1, &len)) == NULL ||
2467 (p2 = sa_rawaddr(sa2, NULL)) == NULL)
2468 return (1);
2469
2470 switch (sa1->sa_family) {
2471 case AF_INET6:
2472 if (((struct sockaddr_in6 *)sa1)->sin6_scope_id !=
2473 ((struct sockaddr_in6 *)sa2)->sin6_scope_id)
2474 return (1);
2475 break;
2476 }
2477
2478 /* Simple binary comparison if no mask specified. */
2479 if (samask == NULL)
2480 return (memcmp(p1, p2, len));
2481
2482 /* Set up the mask, and do a mask-based comparison. */
2483 if (sa1->sa_family != samask->sa_family ||
2484 (mask = sa_rawaddr(samask, NULL)) == NULL)
2485 return (1);
2486
2487 for (i = 0; i < len; i++)
2488 if ((p1[i] & mask[i]) != (p2[i] & mask[i]))
2489 return (1);
2490 return (0);
2491}
2492
2493/*
2494 * Return a pointer to the part of the sockaddr that contains the
2495 * raw address, and set *nbytes to its length in bytes. Returns
2496 * NULL if the address family is unknown.
2497 */
2498void *
2499sa_rawaddr(struct sockaddr *sa, int *nbytes) {
2500 void *p;
2501 int len;
2502
2503 switch (sa->sa_family) {
2504 case AF_INET:
2505 len = sizeof(((struct sockaddr_in *)sa)->sin_addr);
2506 p = &((struct sockaddr_in *)sa)->sin_addr;
2507 break;
2508 case AF_INET6:
2509 len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr);
2510 p = &((struct sockaddr_in6 *)sa)->sin6_addr;
2511 break;
2512 default:
2513 p = NULL;
2514 len = 0;
2515 }
2516
2517 if (nbytes != NULL)
2518 *nbytes = len;
2519 return (p);
2520}
2521
2522void
2523huphandler(int sig)
2524{
2525 got_sighup = 1;
2526}
2527
2528void terminate(sig)
2529int sig;
2530{
2531 pidfile_remove(pfh);
2532 rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL);
2533 rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL);
2534 exit (0);
2535}
1988}
1989
1990/*
1991 * Translate a net address.
1992 *
1993 * If `maskflg' is nonzero, then `cp' is a netmask, not a network address.
1994 */
1995int
1996get_net(cp, net, maskflg)
1997 char *cp;
1998 struct netmsk *net;
1999 int maskflg;
2000{
2001 struct netent *np = NULL;
2002 char *name, *p, *prefp;
2003 struct sockaddr_in sin;
2004 struct sockaddr *sa = NULL;
2005 struct addrinfo hints, *ai = NULL;
2006 char netname[NI_MAXHOST];
2007 long preflen;
2008
2009 p = prefp = NULL;
2010 if ((opt_flags & OP_MASKLEN) && !maskflg) {
2011 p = strchr(cp, '/');
2012 *p = '\0';
2013 prefp = p + 1;
2014 }
2015
2016 /*
2017 * Check for a numeric address first. We wish to avoid
2018 * possible DNS lookups in getnetbyname().
2019 */
2020 if (isxdigit(*cp) || *cp == ':') {
2021 memset(&hints, 0, sizeof hints);
2022 /* Ensure the mask and the network have the same family. */
2023 if (maskflg && (opt_flags & OP_NET))
2024 hints.ai_family = net->nt_net.ss_family;
2025 else if (!maskflg && (opt_flags & OP_HAVEMASK))
2026 hints.ai_family = net->nt_mask.ss_family;
2027 else
2028 hints.ai_family = AF_UNSPEC;
2029 hints.ai_flags = AI_NUMERICHOST;
2030 if (getaddrinfo(cp, NULL, &hints, &ai) == 0)
2031 sa = ai->ai_addr;
2032 if (sa != NULL && ai->ai_family == AF_INET) {
2033 /*
2034 * The address in `cp' is really a network address, so
2035 * use inet_network() to re-interpret this correctly.
2036 * e.g. "127.1" means 127.1.0.0, not 127.0.0.1.
2037 */
2038 bzero(&sin, sizeof sin);
2039 sin.sin_family = AF_INET;
2040 sin.sin_len = sizeof sin;
2041 sin.sin_addr = inet_makeaddr(inet_network(cp), 0);
2042 if (debug)
2043 fprintf(stderr, "get_net: v4 addr %s\n",
2044 inet_ntoa(sin.sin_addr));
2045 sa = (struct sockaddr *)&sin;
2046 }
2047 }
2048 if (sa == NULL && (np = getnetbyname(cp)) != NULL) {
2049 bzero(&sin, sizeof sin);
2050 sin.sin_family = AF_INET;
2051 sin.sin_len = sizeof sin;
2052 sin.sin_addr = inet_makeaddr(np->n_net, 0);
2053 sa = (struct sockaddr *)&sin;
2054 }
2055 if (sa == NULL)
2056 goto fail;
2057
2058 if (maskflg) {
2059 /* The specified sockaddr is a mask. */
2060 if (checkmask(sa) != 0)
2061 goto fail;
2062 bcopy(sa, &net->nt_mask, sa->sa_len);
2063 opt_flags |= OP_HAVEMASK;
2064 } else {
2065 /* The specified sockaddr is a network address. */
2066 bcopy(sa, &net->nt_net, sa->sa_len);
2067
2068 /* Get a network name for the export list. */
2069 if (np) {
2070 name = np->n_name;
2071 } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname,
2072 NULL, 0, NI_NUMERICHOST) == 0) {
2073 name = netname;
2074 } else {
2075 goto fail;
2076 }
2077 if ((net->nt_name = strdup(name)) == NULL)
2078 out_of_mem();
2079
2080 /*
2081 * Extract a mask from either a "/<masklen>" suffix, or
2082 * from the class of an IPv4 address.
2083 */
2084 if (opt_flags & OP_MASKLEN) {
2085 preflen = strtol(prefp, NULL, 10);
2086 if (preflen < 0L || preflen == LONG_MAX)
2087 goto fail;
2088 bcopy(sa, &net->nt_mask, sa->sa_len);
2089 if (makemask(&net->nt_mask, (int)preflen) != 0)
2090 goto fail;
2091 opt_flags |= OP_HAVEMASK;
2092 *p = '/';
2093 } else if (sa->sa_family == AF_INET &&
2094 (opt_flags & OP_MASK) == 0) {
2095 in_addr_t addr;
2096
2097 addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
2098 if (IN_CLASSA(addr))
2099 preflen = 8;
2100 else if (IN_CLASSB(addr))
2101 preflen = 16;
2102 else if (IN_CLASSC(addr))
2103 preflen = 24;
2104 else if (IN_CLASSD(addr))
2105 preflen = 28;
2106 else
2107 preflen = 32; /* XXX */
2108
2109 bcopy(sa, &net->nt_mask, sa->sa_len);
2110 makemask(&net->nt_mask, (int)preflen);
2111 opt_flags |= OP_HAVEMASK;
2112 }
2113 }
2114
2115 if (ai)
2116 freeaddrinfo(ai);
2117 return 0;
2118
2119fail:
2120 if (ai)
2121 freeaddrinfo(ai);
2122 return 1;
2123}
2124
2125/*
2126 * Parse out the next white space separated field
2127 */
2128void
2129nextfield(cp, endcp)
2130 char **cp;
2131 char **endcp;
2132{
2133 char *p;
2134
2135 p = *cp;
2136 while (*p == ' ' || *p == '\t')
2137 p++;
2138 if (*p == '\n' || *p == '\0')
2139 *cp = *endcp = p;
2140 else {
2141 *cp = p++;
2142 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
2143 p++;
2144 *endcp = p;
2145 }
2146}
2147
2148/*
2149 * Get an exports file line. Skip over blank lines and handle line
2150 * continuations.
2151 */
2152int
2153get_line()
2154{
2155 char *p, *cp;
2156 size_t len;
2157 int totlen, cont_line;
2158
2159 /*
2160 * Loop around ignoring blank lines and getting all continuation lines.
2161 */
2162 p = line;
2163 totlen = 0;
2164 do {
2165 if ((p = fgetln(exp_file, &len)) == NULL)
2166 return (0);
2167 cp = p + len - 1;
2168 cont_line = 0;
2169 while (cp >= p &&
2170 (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
2171 if (*cp == '\\')
2172 cont_line = 1;
2173 cp--;
2174 len--;
2175 }
2176 if (cont_line) {
2177 *++cp = ' ';
2178 len++;
2179 }
2180 if (linesize < len + totlen + 1) {
2181 linesize = len + totlen + 1;
2182 line = realloc(line, linesize);
2183 if (line == NULL)
2184 out_of_mem();
2185 }
2186 memcpy(line + totlen, p, len);
2187 totlen += len;
2188 line[totlen] = '\0';
2189 } while (totlen == 0 || cont_line);
2190 return (1);
2191}
2192
2193/*
2194 * Parse a description of a credential.
2195 */
2196void
2197parsecred(namelist, cr)
2198 char *namelist;
2199 struct xucred *cr;
2200{
2201 char *name;
2202 int cnt;
2203 char *names;
2204 struct passwd *pw;
2205 struct group *gr;
2206 gid_t groups[NGROUPS + 1];
2207 int ngroups;
2208
2209 cr->cr_version = XUCRED_VERSION;
2210 /*
2211 * Set up the unprivileged user.
2212 */
2213 cr->cr_uid = -2;
2214 cr->cr_groups[0] = -2;
2215 cr->cr_ngroups = 1;
2216 /*
2217 * Get the user's password table entry.
2218 */
2219 names = strsep(&namelist, " \t\n");
2220 name = strsep(&names, ":");
2221 if (isdigit(*name) || *name == '-')
2222 pw = getpwuid(atoi(name));
2223 else
2224 pw = getpwnam(name);
2225 /*
2226 * Credentials specified as those of a user.
2227 */
2228 if (names == NULL) {
2229 if (pw == NULL) {
2230 syslog(LOG_ERR, "unknown user: %s", name);
2231 return;
2232 }
2233 cr->cr_uid = pw->pw_uid;
2234 ngroups = NGROUPS + 1;
2235 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
2236 syslog(LOG_ERR, "too many groups");
2237 /*
2238 * Compress out duplicate.
2239 */
2240 cr->cr_ngroups = ngroups - 1;
2241 cr->cr_groups[0] = groups[0];
2242 for (cnt = 2; cnt < ngroups; cnt++)
2243 cr->cr_groups[cnt - 1] = groups[cnt];
2244 return;
2245 }
2246 /*
2247 * Explicit credential specified as a colon separated list:
2248 * uid:gid:gid:...
2249 */
2250 if (pw != NULL)
2251 cr->cr_uid = pw->pw_uid;
2252 else if (isdigit(*name) || *name == '-')
2253 cr->cr_uid = atoi(name);
2254 else {
2255 syslog(LOG_ERR, "unknown user: %s", name);
2256 return;
2257 }
2258 cr->cr_ngroups = 0;
2259 while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
2260 name = strsep(&names, ":");
2261 if (isdigit(*name) || *name == '-') {
2262 cr->cr_groups[cr->cr_ngroups++] = atoi(name);
2263 } else {
2264 if ((gr = getgrnam(name)) == NULL) {
2265 syslog(LOG_ERR, "unknown group: %s", name);
2266 continue;
2267 }
2268 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
2269 }
2270 }
2271 if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
2272 syslog(LOG_ERR, "too many groups");
2273}
2274
2275#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
2276/*
2277 * Routines that maintain the remote mounttab
2278 */
2279void
2280get_mountlist()
2281{
2282 struct mountlist *mlp, **mlpp;
2283 char *host, *dirp, *cp;
2284 char str[STRSIZ];
2285 FILE *mlfile;
2286
2287 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
2288 if (errno == ENOENT)
2289 return;
2290 else {
2291 syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST);
2292 return;
2293 }
2294 }
2295 mlpp = &mlhead;
2296 while (fgets(str, STRSIZ, mlfile) != NULL) {
2297 cp = str;
2298 host = strsep(&cp, " \t\n");
2299 dirp = strsep(&cp, " \t\n");
2300 if (host == NULL || dirp == NULL)
2301 continue;
2302 mlp = (struct mountlist *)malloc(sizeof (*mlp));
2303 if (mlp == (struct mountlist *)NULL)
2304 out_of_mem();
2305 strncpy(mlp->ml_host, host, RPCMNT_NAMELEN);
2306 mlp->ml_host[RPCMNT_NAMELEN] = '\0';
2307 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
2308 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
2309 mlp->ml_next = (struct mountlist *)NULL;
2310 *mlpp = mlp;
2311 mlpp = &mlp->ml_next;
2312 }
2313 fclose(mlfile);
2314}
2315
2316void
2317del_mlist(char *hostp, char *dirp)
2318{
2319 struct mountlist *mlp, **mlpp;
2320 struct mountlist *mlp2;
2321 FILE *mlfile;
2322 int fnd = 0;
2323
2324 mlpp = &mlhead;
2325 mlp = mlhead;
2326 while (mlp) {
2327 if (!strcmp(mlp->ml_host, hostp) &&
2328 (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
2329 fnd = 1;
2330 mlp2 = mlp;
2331 *mlpp = mlp = mlp->ml_next;
2332 free((caddr_t)mlp2);
2333 } else {
2334 mlpp = &mlp->ml_next;
2335 mlp = mlp->ml_next;
2336 }
2337 }
2338 if (fnd) {
2339 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
2340 syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST);
2341 return;
2342 }
2343 mlp = mlhead;
2344 while (mlp) {
2345 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
2346 mlp = mlp->ml_next;
2347 }
2348 fclose(mlfile);
2349 }
2350}
2351
2352void
2353add_mlist(hostp, dirp)
2354 char *hostp, *dirp;
2355{
2356 struct mountlist *mlp, **mlpp;
2357 FILE *mlfile;
2358
2359 mlpp = &mlhead;
2360 mlp = mlhead;
2361 while (mlp) {
2362 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
2363 return;
2364 mlpp = &mlp->ml_next;
2365 mlp = mlp->ml_next;
2366 }
2367 mlp = (struct mountlist *)malloc(sizeof (*mlp));
2368 if (mlp == (struct mountlist *)NULL)
2369 out_of_mem();
2370 strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
2371 mlp->ml_host[RPCMNT_NAMELEN] = '\0';
2372 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
2373 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
2374 mlp->ml_next = (struct mountlist *)NULL;
2375 *mlpp = mlp;
2376 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
2377 syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST);
2378 return;
2379 }
2380 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
2381 fclose(mlfile);
2382}
2383
2384/*
2385 * Free up a group list.
2386 */
2387void
2388free_grp(grp)
2389 struct grouplist *grp;
2390{
2391 if (grp->gr_type == GT_HOST) {
2392 if (grp->gr_ptr.gt_addrinfo != NULL)
2393 freeaddrinfo(grp->gr_ptr.gt_addrinfo);
2394 } else if (grp->gr_type == GT_NET) {
2395 if (grp->gr_ptr.gt_net.nt_name)
2396 free(grp->gr_ptr.gt_net.nt_name);
2397 }
2398 free((caddr_t)grp);
2399}
2400
2401#ifdef DEBUG
2402void
2403SYSLOG(int pri, const char *fmt, ...)
2404{
2405 va_list ap;
2406
2407 va_start(ap, fmt);
2408 vfprintf(stderr, fmt, ap);
2409 va_end(ap);
2410}
2411#endif /* DEBUG */
2412
2413/*
2414 * Check options for consistency.
2415 */
2416int
2417check_options(dp)
2418 struct dirlist *dp;
2419{
2420
2421 if (dp == (struct dirlist *)NULL)
2422 return (1);
2423 if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) {
2424 syslog(LOG_ERR, "-mapall and -maproot mutually exclusive");
2425 return (1);
2426 }
2427 if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
2428 syslog(LOG_ERR, "-mask requires -network");
2429 return (1);
2430 }
2431 if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) {
2432 syslog(LOG_ERR, "-network requires mask specification");
2433 return (1);
2434 }
2435 if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) {
2436 syslog(LOG_ERR, "-mask and /masklen are mutually exclusive");
2437 return (1);
2438 }
2439 if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
2440 syslog(LOG_ERR, "-alldirs has multiple directories");
2441 return (1);
2442 }
2443 return (0);
2444}
2445
2446/*
2447 * Check an absolute directory path for any symbolic links. Return true
2448 */
2449int
2450check_dirpath(dirp)
2451 char *dirp;
2452{
2453 char *cp;
2454 int ret = 1;
2455 struct stat sb;
2456
2457 cp = dirp + 1;
2458 while (*cp && ret) {
2459 if (*cp == '/') {
2460 *cp = '\0';
2461 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
2462 ret = 0;
2463 *cp = '/';
2464 }
2465 cp++;
2466 }
2467 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
2468 ret = 0;
2469 return (ret);
2470}
2471
2472/*
2473 * Make a netmask according to the specified prefix length. The ss_family
2474 * and other non-address fields must be initialised before calling this.
2475 */
2476int
2477makemask(struct sockaddr_storage *ssp, int bitlen)
2478{
2479 u_char *p;
2480 int bits, i, len;
2481
2482 if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL)
2483 return (-1);
2484 if (bitlen > len * CHAR_BIT)
2485 return (-1);
2486
2487 for (i = 0; i < len; i++) {
2488 bits = (bitlen > CHAR_BIT) ? CHAR_BIT : bitlen;
2489 *p++ = (1 << bits) - 1;
2490 bitlen -= bits;
2491 }
2492 return 0;
2493}
2494
2495/*
2496 * Check that the sockaddr is a valid netmask. Returns 0 if the mask
2497 * is acceptable (i.e. of the form 1...10....0).
2498 */
2499int
2500checkmask(struct sockaddr *sa)
2501{
2502 u_char *mask;
2503 int i, len;
2504
2505 if ((mask = sa_rawaddr(sa, &len)) == NULL)
2506 return (-1);
2507
2508 for (i = 0; i < len; i++)
2509 if (mask[i] != 0xff)
2510 break;
2511 if (i < len) {
2512 if (~mask[i] & (u_char)(~mask[i] + 1))
2513 return (-1);
2514 i++;
2515 }
2516 for (; i < len; i++)
2517 if (mask[i] != 0)
2518 return (-1);
2519 return (0);
2520}
2521
2522/*
2523 * Compare two sockaddrs according to a specified mask. Return zero if
2524 * `sa1' matches `sa2' when filtered by the netmask in `samask'.
2525 * If samask is NULL, perform a full comparision.
2526 */
2527int
2528sacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask)
2529{
2530 unsigned char *p1, *p2, *mask;
2531 int len, i;
2532
2533 if (sa1->sa_family != sa2->sa_family ||
2534 (p1 = sa_rawaddr(sa1, &len)) == NULL ||
2535 (p2 = sa_rawaddr(sa2, NULL)) == NULL)
2536 return (1);
2537
2538 switch (sa1->sa_family) {
2539 case AF_INET6:
2540 if (((struct sockaddr_in6 *)sa1)->sin6_scope_id !=
2541 ((struct sockaddr_in6 *)sa2)->sin6_scope_id)
2542 return (1);
2543 break;
2544 }
2545
2546 /* Simple binary comparison if no mask specified. */
2547 if (samask == NULL)
2548 return (memcmp(p1, p2, len));
2549
2550 /* Set up the mask, and do a mask-based comparison. */
2551 if (sa1->sa_family != samask->sa_family ||
2552 (mask = sa_rawaddr(samask, NULL)) == NULL)
2553 return (1);
2554
2555 for (i = 0; i < len; i++)
2556 if ((p1[i] & mask[i]) != (p2[i] & mask[i]))
2557 return (1);
2558 return (0);
2559}
2560
2561/*
2562 * Return a pointer to the part of the sockaddr that contains the
2563 * raw address, and set *nbytes to its length in bytes. Returns
2564 * NULL if the address family is unknown.
2565 */
2566void *
2567sa_rawaddr(struct sockaddr *sa, int *nbytes) {
2568 void *p;
2569 int len;
2570
2571 switch (sa->sa_family) {
2572 case AF_INET:
2573 len = sizeof(((struct sockaddr_in *)sa)->sin_addr);
2574 p = &((struct sockaddr_in *)sa)->sin_addr;
2575 break;
2576 case AF_INET6:
2577 len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr);
2578 p = &((struct sockaddr_in6 *)sa)->sin6_addr;
2579 break;
2580 default:
2581 p = NULL;
2582 len = 0;
2583 }
2584
2585 if (nbytes != NULL)
2586 *nbytes = len;
2587 return (p);
2588}
2589
2590void
2591huphandler(int sig)
2592{
2593 got_sighup = 1;
2594}
2595
2596void terminate(sig)
2597int sig;
2598{
2599 pidfile_remove(pfh);
2600 rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL);
2601 rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL);
2602 exit (0);
2603}