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