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