1 /* $NetBSD: mountd.c,v 1.9 2015/08/21 14:19:10 christos Exp $ */
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Herb Hasler and Rick Macklem at The University of Guelph.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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
35 #include <sys/cdefs.h>
37 __COPYRIGHT("@(#) Copyright (c) 1989, 1993\
38 The Regents of the University of California. All rights reserved.");
43 static char sccsid
[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95";
45 __RCSID("$NetBSD: mountd.c,v 1.9 2015/08/21 14:19:10 christos Exp $");
49 #include <sys/param.h>
51 #include <sys/ioctl.h>
52 #include <sys/mount.h>
53 #include <sys/socket.h>
56 #include <sys/ucred.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>
65 #include <nfs/nfsmount.h>
67 #include <arpa/inet.h>
69 #include <rump/rump.h>
70 #include <rump/rump_syscalls.h>
79 #include <semaphore.h>
87 #include "pathnames.h"
90 #include <netinet6/ipsec.h>
91 #ifndef IPSEC_POLICY_IPSEC /* no ipsec support on old ipsec */
97 #include "svc_fdset.h"
102 * Structures for keeping the mount list and export list
105 struct mountlist
*ml_next
;
106 char ml_host
[RPCMNT_NAMELEN
+ 1];
107 char ml_dirp
[RPCMNT_PATHLEN
+ 1];
108 int ml_flag
;/* XXX more flags (same as dp_flag) */
112 struct dirlist
*dp_left
;
113 struct dirlist
*dp_right
;
115 struct hostlist
*dp_hosts
; /* List of hosts this dir exported to */
116 char dp_dirp
[1]; /* Actually malloc'd to size of dir */
119 #define DP_DEFSET 0x1
120 #define DP_HOSTSET 0x2
122 #define DP_NORESMNT 0x8
125 struct exportlist
*ex_next
;
126 struct dirlist
*ex_dirl
;
127 struct dirlist
*ex_defdir
;
134 #define EX_LINKED 0x1
137 struct sockaddr_storage nt_net
;
143 struct addrinfo
*gt_addrinfo
;
144 struct netmsk gt_net
;
149 union grouptypes gr_ptr
;
150 struct grouplist
*gr_next
;
158 int ht_flag
;/* Uses DP_xx bits */
159 struct grouplist
*ht_grp
;
160 struct hostlist
*ht_next
;
168 uint8_t v2
[NFSX_V2FH
];
169 uint8_t v3
[NFSX_V3FHMAX
];
174 static char *add_expdir
__P((struct dirlist
**, char *, int));
175 static void add_dlist
__P((struct dirlist
**, struct dirlist
*,
176 struct grouplist
*, int));
177 static void add_mlist
__P((char *, char *, int));
178 static int check_dirpath
__P((const char *, size_t, char *));
179 static int check_options
__P((const char *, size_t, struct dirlist
*));
180 static int chk_host
__P((struct dirlist
*, struct sockaddr
*, int *, int *));
181 static int del_mlist
__P((char *, char *, struct sockaddr
*));
182 static struct dirlist
*dirp_search
__P((struct dirlist
*, char *));
183 static int do_nfssvc
__P((const char *, size_t, struct exportlist
*,
184 struct grouplist
*, int, struct uucred
*, char *, int, struct statvfs
*));
185 static int do_opt
__P((const char *, size_t, char **, char **,
186 struct exportlist
*, struct grouplist
*, int *, int *, struct uucred
*));
187 static struct exportlist
*ex_search
__P((fsid_t
*));
188 static int parse_directory
__P((const char *, size_t, struct grouplist
*,
189 int, char *, struct exportlist
**, struct statvfs
*));
190 static int parse_host_netgroup
__P((const char *, size_t, struct exportlist
*,
191 struct grouplist
*, char *, int *, struct grouplist
**));
192 static struct exportlist
*get_exp
__P((void));
193 static void free_dir
__P((struct dirlist
*));
194 static void free_exp
__P((struct exportlist
*));
195 static void free_grp
__P((struct grouplist
*));
196 static void free_host
__P((struct hostlist
*));
197 void get_exportlist
__P((int));
198 static int get_host
__P((const char *, size_t, const char *,
199 struct grouplist
*));
200 static struct hostlist
*get_ht
__P((void));
201 static void get_mountlist
__P((void));
202 static int get_net
__P((char *, struct netmsk
*, int));
203 static void free_exp_grp
__P((struct exportlist
*, struct grouplist
*));
204 static struct grouplist
*get_grp
__P((void));
205 static void hang_dirp
__P((struct dirlist
*, struct grouplist
*,
206 struct exportlist
*, int));
207 static void mntsrv
__P((struct svc_req
*, SVCXPRT
*));
208 static void nextfield
__P((char **, char **));
209 static void parsecred
__P((char *, struct uucred
*));
210 static int put_exlist
__P((struct dirlist
*, XDR
*, struct dirlist
*, int *));
211 static int scan_tree
__P((struct dirlist
*, struct sockaddr
*));
212 static void send_umntall
__P((int));
214 static int umntall_each
__P((caddr_t
, struct sockaddr_in
*));
216 static int xdr_dir
__P((XDR
*, char *));
217 static int xdr_explist
__P((XDR
*, caddr_t
));
218 static int xdr_fhs
__P((XDR
*, caddr_t
));
219 static int xdr_mlist
__P((XDR
*, caddr_t
));
220 static int bitcmp
__P((void *, void *, int));
221 static int netpartcmp
__P((struct sockaddr
*, struct sockaddr
*, int));
222 static int sacmp
__P((struct sockaddr
*, struct sockaddr
*));
223 static int allones
__P((struct sockaddr_storage
*, int));
224 static int countones
__P((struct sockaddr
*));
225 static void bind_resv_port
__P((int, sa_family_t
, in_port_t
));
226 static void no_nfs(int);
227 static struct exportlist
*exphead
;
228 static struct mountlist
*mlhead
;
229 static struct grouplist
*grphead
;
231 static struct uucred def_anon
= {
239 static int opt_flags
;
240 static int have_v6
= 1;
241 static const int ninumeric
= NI_NUMERICHOST
;
244 #define OP_MAPROOT 0x001
245 #define OP_MAPALL 0x002
246 #define OP_KERB 0x004
247 #define OP_MASK 0x008
249 #define OP_ALLDIRS 0x040
250 #define OP_NORESPORT 0x080
251 #define OP_NORESMNT 0x100
252 #define OP_MASKLEN 0x200
254 static int debug
= 1;
256 static void SYSLOG
__P((int, const char *,...));
258 int main
__P((int, char *[]));
261 * If this is non-zero, -noresvport and -noresvmnt are implied for
264 static int noprivports
;
266 #define C2FD(_c_) ((int)(uintptr_t)(_c_))
268 rumpread(void *cookie
, char *buf
, int count
)
271 return rump_sys_read(C2FD(cookie
), buf
, count
);
275 rumpwrite(void *cookie
, const char *buf
, int count
)
278 return rump_sys_write(C2FD(cookie
), buf
, count
);
282 rumpseek(void *cookie
, off_t off
, int whence
)
285 return rump_sys_lseek(C2FD(cookie
), off
, whence
);
289 rumpclose(void *cookie
)
292 return rump_sys_close(C2FD(cookie
));
295 int __sflags(const char *, int *); /* XXX */
297 rumpfopen(const char *path
, const char *opts
)
301 __sflags(opts
, &oflags
);
302 fd
= rump_sys_open(path
, oflags
, 0777);
306 return funopen((void *)(uintptr_t)fd
,
307 rumpread
, rumpwrite
, rumpseek
, rumpclose
);
311 * Make sure mountd signal handler is executed from a thread context
312 * instead of the signal handler. This avoids the signal handler
313 * ruining our kernel context.
315 static sem_t exportsem
;
317 signal_get_exportlist(int sig
)
320 sem_post(&exportsem
);
324 exportlist_thread(void *arg
)
328 sem_wait(&exportsem
);
336 * Mountd server for NFS mount protocol as described in:
337 * NFS: Network File System Protocol Specification, RFC1094, Appendix A
338 * The optional arguments are the exports file name
339 * default: _PATH_EXPORTS
340 * "-d" to enable debugging
341 * and "-n" to allow nonroot mount.
343 void *mountd_main(void *);
345 mountd_main(void *arg
)
347 SVCXPRT
*udptransp
, *tcptransp
;
348 struct netconfig
*udpconf
, *tcpconf
;
349 int udpsock
, tcpsock
;
351 int maxrec
= RPC_MAXDATASIZE
;
352 in_port_t forcedport
= 0;
359 while ((c
= getopt(argc
, argv
, "dNnrp:" ADDOPTS
)) != -1)
363 if (ipsecsetup_test(policy
= optarg
))
364 errx(1, "Invalid ipsec policy `%s'", policy
);
368 /* A forced port "0" will dynamically allocate a port */
369 forcedport
= atoi(optarg
);
382 fprintf(stderr
, "usage: %s [-dNn]"
386 " [-p port] [exportsfile]\n", getprogname());
393 sem_init(&exportsem
, 0, 0);
394 pthread_create(&ptdummy
, NULL
, exportlist_thread
, NULL
);
399 exname
= _PATH_EXPORTS
;
400 openlog("mountd", LOG_PID
| (debug
? LOG_PERROR
: 0), LOG_DAEMON
);
401 (void)signal(SIGSYS
, no_nfs
);
404 (void)fprintf(stderr
, "Getting export list.\n");
407 (void)fprintf(stderr
, "Getting mount list.\n");
410 (void)fprintf(stderr
, "Here we go.\n");
413 (void)signal(SIGINT
, SIG_IGN
);
414 (void)signal(SIGQUIT
, SIG_IGN
);
416 (void)signal(SIGHUP
, signal_get_exportlist
);
417 (void)signal(SIGTERM
, send_umntall
);
420 rpcb_unset(RPCPROG_MNT
, RPCMNT_VER1
, NULL
);
421 rpcb_unset(RPCPROG_MNT
, RPCMNT_VER3
, NULL
);
423 udpsock
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
424 tcpsock
= socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
426 udpconf
= getnetconfigent("udp");
427 tcpconf
= getnetconfigent("tcp");
429 rpc_control(RPC_SVC_CONNMAXREC_SET
, &maxrec
);
431 if (udpsock
!= -1 && udpconf
!= NULL
) {
432 bind_resv_port(udpsock
, AF_INET
, forcedport
);
435 ipsecsetup(AF_INET
, udpsock
, policy
);
437 udptransp
= svc_dg_create(udpsock
, 0, 0);
438 if (udptransp
!= NULL
) {
439 if (!svc_reg(udptransp
, RPCPROG_MNT
, RPCMNT_VER1
,
441 !svc_reg(udptransp
, RPCPROG_MNT
, RPCMNT_VER3
,
443 syslog(LOG_WARNING
, "can't register UDP service");
449 syslog(LOG_WARNING
, "can't create UDP service");
454 if (tcpsock
!= -1 && tcpconf
!= NULL
) {
455 bind_resv_port(tcpsock
, AF_INET
, forcedport
);
458 ipsecsetup(AF_INET
, tcpsock
, policy
);
460 listen(tcpsock
, SOMAXCONN
);
461 tcptransp
= svc_vc_create(tcpsock
, RPC_MAXDATASIZE
,
463 if (tcptransp
!= NULL
) {
464 if (!svc_reg(tcptransp
, RPCPROG_MNT
, RPCMNT_VER1
,
466 !svc_reg(tcptransp
, RPCPROG_MNT
, RPCMNT_VER3
,
468 syslog(LOG_WARNING
, "can't register TCP service");
472 syslog(LOG_WARNING
, "can't create TCP service");
477 syslog(LOG_ERR
, "could not create any services");
483 syslog(LOG_ERR
, "Mountd died");
488 * The mount rpc service
491 mntsrv(rqstp
, transp
)
492 struct svc_req
*rqstp
;
495 struct exportlist
*ep
;
500 char host
[NI_MAXHOST
], numerichost
[NI_MAXHOST
];
501 int lookup_failed
= 1;
502 struct sockaddr
*saddr
;
504 char rpcpath
[RPCMNT_PATHLEN
+ 1], dpath
[MAXPATHLEN
];
506 int defset
, hostset
, ret
;
507 sigset_t sighup_mask
;
508 struct sockaddr_in6
*sin6
;
509 struct sockaddr_in
*sin
;
513 (void)sigemptyset(&sighup_mask
);
514 (void)sigaddset(&sighup_mask
, SIGHUP
);
515 saddr
= svc_getrpccaller(transp
)->buf
;
516 switch (saddr
->sa_family
) {
518 sin6
= (struct sockaddr_in6
*)saddr
;
519 sport
= ntohs(sin6
->sin6_port
);
522 sin
= (struct sockaddr_in
*)saddr
;
523 sport
= ntohs(sin
->sin_port
);
526 syslog(LOG_ERR
, "request from unknown address family");
529 lookup_failed
= getnameinfo(saddr
, saddr
->sa_len
, host
, sizeof host
,
531 if (getnameinfo(saddr
, saddr
->sa_len
, numerichost
,
532 sizeof numerichost
, NULL
, 0, ninumeric
) != 0)
533 strlcpy(numerichost
, "?", sizeof(numerichost
));
535 switch (rqstp
->rq_proc
) {
537 if (!svc_sendreply(transp
, (xdrproc_t
)xdr_void
, NULL
))
538 syslog(LOG_ERR
, "Can't send reply");
543 "got mount request from %s\n", numerichost
);
544 if (!svc_getargs(transp
, xdr_dir
, rpcpath
)) {
546 fprintf(stderr
, "-> garbage args\n");
547 svcerr_decode(transp
);
552 "-> rpcpath: %s\n", rpcpath
);
554 * Get the real pathname and make sure it is a file or
555 * directory that exists.
558 if (realpath(rpcpath
, dpath
) == 0 ||
560 strcpy(dpath
, rpcpath
);
561 if (rump_sys_stat(dpath
, &stb
) < 0 ||
562 (!S_ISDIR(stb
.st_mode
) && !S_ISREG(stb
.st_mode
)) ||
563 rump_sys_statvfs1(dpath
, &fsb
, ST_WAIT
) < 0) {
564 (void)chdir("/"); /* Just in case realpath doesn't */
566 (void)fprintf(stderr
, "-> stat failed on %s\n",
568 if (!svc_sendreply(transp
, (xdrproc_t
)xdr_long
, (caddr_t
) &bad
))
569 syslog(LOG_ERR
, "Can't send reply");
574 "-> dpath: %s\n", dpath
);
575 /* Check in the exports list */
576 (void)sigprocmask(SIG_BLOCK
, &sighup_mask
, NULL
);
577 ep
= ex_search(&fsb
.f_fsidx
);
578 hostset
= defset
= 0;
579 if (ep
&& (chk_host(ep
->ex_defdir
, saddr
, &defset
,
580 &hostset
) || ((dp
= dirp_search(ep
->ex_dirl
, dpath
)) &&
581 chk_host(dp
, saddr
, &defset
, &hostset
)) ||
582 (defset
&& scan_tree(ep
->ex_defdir
, saddr
) == 0 &&
583 scan_tree(ep
->ex_dirl
, saddr
) == 0))) {
584 if ((hostset
& DP_HOSTSET
) == 0) {
587 if (sport
>= IPPORT_RESERVED
&&
588 !(hostset
& DP_NORESMNT
)) {
590 "Refused mount RPC from host %s port %d",
592 svcerr_weakauth(transp
);
595 fhr
.fhr_flag
= hostset
;
596 fhr
.fhr_vers
= rqstp
->rq_vers
;
597 /* Get the file handle */
598 memset(&fhr
.fhr_fh
, 0, sizeof(fhr
.fhr_fh
)); /* for v2 */
599 fh_size
= sizeof(fhr
.fhr_fh
);
601 if (rump_sys_getfh(dpath
, &fhr
.fhr_fh
, &fh_size
) < 0) {
603 //syslog(LOG_ERR, "Can't get fh for %s %d %d", dpath, error, fh_size);
604 if (!svc_sendreply(transp
, (xdrproc_t
)xdr_long
,
606 syslog(LOG_ERR
, "Can't send reply");
609 if ((fhr
.fhr_vers
== 1 && fh_size
> NFSX_V2FH
) ||
610 fh_size
> NFSX_V3FHMAX
) {
611 bad
= EINVAL
; /* XXX */
612 if (!svc_sendreply(transp
, (xdrproc_t
)xdr_long
,
614 syslog(LOG_ERR
, "Can't send reply");
617 fhr
.fhr_fhsize
= fh_size
;
618 if (!svc_sendreply(transp
, (xdrproc_t
)xdr_fhs
, (char *) &fhr
))
619 syslog(LOG_ERR
, "Can't send reply");
621 add_mlist(host
, dpath
, hostset
);
623 add_mlist(numerichost
, dpath
, hostset
);
625 (void)fprintf(stderr
, "Mount successful.\n");
627 if (!svc_sendreply(transp
, (xdrproc_t
)xdr_long
, (caddr_t
) &bad
))
628 syslog(LOG_ERR
, "Can't send reply");
631 (void)sigprocmask(SIG_UNBLOCK
, &sighup_mask
, NULL
);
634 if (!svc_sendreply(transp
, (xdrproc_t
)xdr_mlist
, NULL
))
635 syslog(LOG_ERR
, "Can't send reply");
638 if (!svc_getargs(transp
, xdr_dir
, dpath
)) {
639 svcerr_decode(transp
);
643 ret
= del_mlist(host
, dpath
, saddr
);
644 ret
|= del_mlist(numerichost
, dpath
, saddr
);
646 svcerr_weakauth(transp
);
649 if (!svc_sendreply(transp
, (xdrproc_t
)xdr_void
, NULL
))
650 syslog(LOG_ERR
, "Can't send reply");
652 case MOUNTPROC_UMNTALL
:
654 ret
= del_mlist(host
, NULL
, saddr
);
655 ret
|= del_mlist(numerichost
, NULL
, saddr
);
657 svcerr_weakauth(transp
);
660 if (!svc_sendreply(transp
, (xdrproc_t
)xdr_void
, NULL
))
661 syslog(LOG_ERR
, "Can't send reply");
663 case MOUNTPROC_EXPORT
:
664 case MOUNTPROC_EXPORTALL
:
665 if (!svc_sendreply(transp
, (xdrproc_t
)xdr_explist
, NULL
))
666 syslog(LOG_ERR
, "Can't send reply");
671 svcerr_noproc(transp
);
677 * Xdr conversion for a dpath string
685 return (xdr_string(xdrsp
, &dirp
, RPCMNT_PATHLEN
));
689 * Xdr routine to generate file handle reply
696 struct fhreturn
*fhrp
= (struct fhreturn
*) cp
;
697 long ok
= 0, len
, auth
;
699 if (!xdr_long(xdrsp
, &ok
))
701 switch (fhrp
->fhr_vers
) {
703 return (xdr_opaque(xdrsp
, (caddr_t
)&fhrp
->fhr_fh
, NFSX_V2FH
));
705 len
= fhrp
->fhr_fhsize
;
706 if (!xdr_long(xdrsp
, &len
))
708 if (!xdr_opaque(xdrsp
, (caddr_t
)&fhrp
->fhr_fh
, len
))
710 if (fhrp
->fhr_flag
& DP_KERB
)
711 auth
= RPCAUTH_KERB4
;
715 if (!xdr_long(xdrsp
, &len
))
717 return (xdr_long(xdrsp
, &auth
));
727 struct mountlist
*mlp
;
734 if (!xdr_bool(xdrsp
, &trueval
))
736 strp
= &mlp
->ml_host
[0];
737 if (!xdr_string(xdrsp
, &strp
, RPCMNT_NAMELEN
))
739 strp
= &mlp
->ml_dirp
[0];
740 if (!xdr_string(xdrsp
, &strp
, RPCMNT_PATHLEN
))
744 if (!xdr_bool(xdrsp
, &falseval
))
750 * Xdr conversion for export list
753 xdr_explist(xdrsp
, cp
)
757 struct exportlist
*ep
;
760 sigset_t sighup_mask
;
762 (void)sigemptyset(&sighup_mask
);
763 (void)sigaddset(&sighup_mask
, SIGHUP
);
764 (void)sigprocmask(SIG_BLOCK
, &sighup_mask
, NULL
);
768 if (put_exlist(ep
->ex_dirl
, xdrsp
, ep
->ex_defdir
, &putdef
))
770 if (ep
->ex_defdir
&& putdef
== 0 &&
771 put_exlist(ep
->ex_defdir
, xdrsp
, NULL
, &putdef
))
775 (void)sigprocmask(SIG_UNBLOCK
, &sighup_mask
, NULL
);
776 if (!xdr_bool(xdrsp
, &falseval
))
780 (void)sigprocmask(SIG_UNBLOCK
, &sighup_mask
, NULL
);
785 * Called from xdr_explist() to traverse the tree and export the
786 * directory paths. Assumes SIGHUP has already been masked.
789 put_exlist(dp
, xdrsp
, adp
, putdefp
)
795 struct grouplist
*grp
;
803 if (put_exlist(dp
->dp_left
, xdrsp
, adp
, putdefp
))
805 if (!xdr_bool(xdrsp
, &trueval
))
808 if (!xdr_string(xdrsp
, &strp
, RPCMNT_PATHLEN
))
810 if (adp
&& !strcmp(dp
->dp_dirp
, adp
->dp_dirp
)) {
814 if ((dp
->dp_flag
& DP_DEFSET
) == 0 &&
815 (gotalldir
== 0 || (adp
->dp_flag
& DP_DEFSET
) == 0)) {
819 if (grp
->gr_type
== GT_HOST
) {
820 if (!xdr_bool(xdrsp
, &trueval
))
823 grp
->gr_ptr
.gt_addrinfo
->ai_canonname
;
824 if (!xdr_string(xdrsp
, &strp
,
827 } else if (grp
->gr_type
== GT_NET
) {
828 if (!xdr_bool(xdrsp
, &trueval
))
830 strp
= grp
->gr_ptr
.gt_net
.nt_name
;
831 if (!xdr_string(xdrsp
, &strp
,
836 if (gotalldir
&& hp
== NULL
) {
842 if (!xdr_bool(xdrsp
, &falseval
))
844 if (put_exlist(dp
->dp_right
, xdrsp
, adp
, putdefp
))
851 parse_host_netgroup(line
, lineno
, ep
, tgrp
, cp
, has_host
, grp
)
854 struct exportlist
*ep
;
855 struct grouplist
*tgrp
;
858 struct grouplist
**grp
;
860 const char *hst
, *usr
, *dom
;
864 syslog(LOG_ERR
, "\"%s\", line %ld: No current export",
865 line
, (unsigned long)lineno
);
869 netgrp
= getnetgrent(&hst
, &usr
, &dom
);
872 (*grp
)->gr_next
= get_grp();
873 *grp
= (*grp
)->gr_next
;
878 "\"%s\", line %ld: No host in netgroup %s",
879 line
, (unsigned long)lineno
, cp
);
882 if (get_host(line
, lineno
, hst
, *grp
))
884 } else if (get_host(line
, lineno
, cp
, *grp
))
887 } while (netgrp
&& getnetgrent(&hst
, &usr
, &dom
));
898 parse_directory(line
, lineno
, tgrp
, got_nondir
, cp
, ep
, fsp
)
901 struct grouplist
*tgrp
;
904 struct exportlist
**ep
;
907 if (!check_dirpath(line
, lineno
, cp
))
910 if (rump_sys_statvfs1(cp
, fsp
, ST_WAIT
) == -1) {
911 syslog(LOG_ERR
, "\"%s\", line %ld: statvfs for `%s' failed (%s)",
912 line
, (unsigned long)lineno
, cp
, strerror(errno
));
918 "\"%s\", line %ld: Directories must precede files",
919 line
, (unsigned long)lineno
);
923 if ((*ep
)->ex_fs
.__fsid_val
[0] != fsp
->f_fsidx
.__fsid_val
[0] ||
924 (*ep
)->ex_fs
.__fsid_val
[1] != fsp
->f_fsidx
.__fsid_val
[1]) {
926 "\"%s\", line %ld: filesystem ids disagree",
927 line
, (unsigned long)lineno
);
932 * See if this directory is already
935 *ep
= ex_search(&fsp
->f_fsidx
);
938 (*ep
)->ex_fs
= fsp
->f_fsidx
;
939 (*ep
)->ex_fsdir
= estrdup(fsp
->f_mntonname
);
941 (void)fprintf(stderr
,
942 "Making new ep fs=0x%x,0x%x\n",
943 fsp
->f_fsidx
.__fsid_val
[0], fsp
->f_fsidx
.__fsid_val
[1]);
946 (void)fprintf(stderr
,
947 "Found ep fs=0x%x,0x%x\n",
948 fsp
->f_fsidx
.__fsid_val
[0], fsp
->f_fsidx
.__fsid_val
[1]);
957 * Get the export list
964 struct exportlist
*ep
, *ep2
;
965 struct grouplist
*grp
, *tgrp
;
966 struct exportlist
**epp
;
967 struct dirlist
*dirhead
;
968 struct statvfs fsb
, *fsp
;
971 char *cp
, *endcp
, *dirp
, savedc
;
972 int has_host
, exflags
, got_nondir
, dirplen
, num
, i
;
975 size_t lineno
= 0, len
;
979 * First, get rid of the old list
1000 * And delete exports that are in the kernel for all local
1003 num
= getmntinfo(&fsp
, MNT_NOWAIT
);
1004 for (i
= 0; i
< num
; i
++) {
1005 struct mountd_exports_list mel
;
1007 /* Delete all entries from the export list. */
1008 mel
.mel_path
= fsp
->f_mntonname
;
1009 mel
.mel_nexports
= 0;
1010 if (rump_sys_nfssvc(NFSSVC_SETEXPORTSLIST
, &mel
) == -1 &&
1011 errno
!= EOPNOTSUPP
)
1012 syslog(LOG_ERR
, "Can't delete exports for %s (%s)",
1013 fsp
->f_mntonname
, strerror(errno
));
1019 * Read in the exports file and build the list, calling
1020 * mount() as we go along to push the export rules into the kernel.
1022 exname
= _PATH_EXPORTS
;
1023 if ((exp_file
= rumpfopen(exname
, "r")) == NULL
) {
1025 * Don't exit here; we can still reload the config
1029 (void)fprintf(stderr
, "Can't open %s: %s\n", exname
,
1034 while ((line
= fparseln(exp_file
, &len
, &lineno
, NULL
, 0)) != NULL
) {
1036 (void)fprintf(stderr
, "Got line %s\n", line
);
1038 nextfield(&cp
, &endcp
);
1040 goto nextline
; /* skip empty line */
1046 exflags
= MNT_EXPORTED
;
1052 opt_flags
|= OP_NORESMNT
| OP_NORESPORT
;
1053 exflags
|= MNT_EXNORESPORT
;
1057 * Create new exports list entry
1060 tgrp
= grp
= get_grp();
1062 if (len
> RPCMNT_NAMELEN
) {
1065 "\"%s\", line %ld: name `%s' is too long",
1066 line
, (unsigned long)lineno
, cp
);
1076 "\"%s\", line %ld: No current export list",
1077 line
, (unsigned long)lineno
);
1081 (void)fprintf(stderr
, "doing opt %s\n",
1084 if (do_opt(line
, lineno
, &cp
, &endcp
, ep
, grp
,
1085 &has_host
, &exflags
, &anon
))
1096 if (!parse_directory(line
, lineno
, tgrp
,
1097 got_nondir
, cp
, &ep
, &fsb
))
1100 * Add dirpath to export mount point.
1102 dirp
= add_expdir(&dirhead
, cp
, len
);
1115 if (!parse_host_netgroup(line
, lineno
, ep
,
1116 tgrp
, cp
, &has_host
, &grp
))
1126 nextfield(&cp
, &endcp
);
1129 if (check_options(line
, lineno
, dirhead
))
1133 grp
->gr_type
= GT_HOST
;
1135 (void)fprintf(stderr
,
1136 "Adding a default entry\n");
1137 /* add a default group and make the grp list NULL */
1138 ai
= emalloc(sizeof(struct addrinfo
));
1140 ai
->ai_family
= AF_INET
; /* XXXX */
1141 ai
->ai_socktype
= SOCK_DGRAM
;
1142 /* setting the length to 0 will match anything */
1144 ai
->ai_flags
= AI_CANONNAME
;
1145 ai
->ai_canonname
= estrdup("Default");
1148 grp
->gr_ptr
.gt_addrinfo
= ai
;
1150 } else if ((opt_flags
& OP_NET
) && tgrp
->gr_next
) {
1152 * Don't allow a network export coincide with a list of
1153 * host(s) on the same line.
1156 "\"%s\", line %ld: Mixed exporting of networks and hosts is disallowed",
1157 line
, (unsigned long)lineno
);
1161 * Loop through hosts, pushing the exports into the kernel.
1162 * After loop, tgrp points to the start of the list and
1163 * grp points to the last entry in the list.
1167 if (do_nfssvc(line
, lineno
, ep
, grp
, exflags
, &anon
,
1168 dirp
, dirplen
, &fsb
))
1170 } while (grp
->gr_next
&& (grp
= grp
->gr_next
));
1173 * Success. Update the data structures.
1176 hang_dirp(dirhead
, tgrp
, ep
, opt_flags
);
1177 grp
->gr_next
= grphead
;
1180 hang_dirp(dirhead
, NULL
, ep
, opt_flags
);
1185 if ((ep
->ex_flag
& EX_LINKED
) == 0) {
1190 * Insert in the list in alphabetical order.
1192 while (ep2
&& strcmp(ep2
->ex_fsdir
, ep
->ex_fsdir
) < 0) {
1193 epp
= &ep2
->ex_next
;
1199 ep
->ex_flag
|= EX_LINKED
;
1203 free_exp_grp(ep
, grp
);
1211 (void)fclose(exp_file
);
1215 * Allocate an export list element
1217 static struct exportlist
*
1220 struct exportlist
*ep
;
1222 ep
= emalloc(sizeof(struct exportlist
));
1223 (void)memset(ep
, 0, sizeof(struct exportlist
));
1228 * Allocate a group list element
1230 static struct grouplist
*
1233 struct grouplist
*gp
;
1235 gp
= emalloc(sizeof(struct grouplist
));
1236 (void)memset(gp
, 0, sizeof(struct grouplist
));
1241 * Clean up upon an error in get_exportlist().
1244 free_exp_grp(ep
, grp
)
1245 struct exportlist
*ep
;
1246 struct grouplist
*grp
;
1248 struct grouplist
*tgrp
;
1250 if (ep
&& (ep
->ex_flag
& EX_LINKED
) == 0)
1260 * Search the export list for a matching fs.
1262 static struct exportlist
*
1266 struct exportlist
*ep
;
1271 if (ep
->ex_fs
.__fsid_val
[0] == fsid
->__fsid_val
[0] &&
1272 ep
->ex_fs
.__fsid_val
[1] == fsid
->__fsid_val
[1])
1280 * Add a directory path to the list.
1283 add_expdir(dpp
, cp
, len
)
1284 struct dirlist
**dpp
;
1290 dp
= emalloc(sizeof(struct dirlist
) + len
);
1292 dp
->dp_right
= NULL
;
1294 dp
->dp_hosts
= NULL
;
1295 (void)strcpy(dp
->dp_dirp
, cp
);
1297 return (dp
->dp_dirp
);
1301 * Hang the dir list element off the dirpath binary tree as required
1302 * and update the entry for host.
1305 hang_dirp(dp
, grp
, ep
, flags
)
1307 struct grouplist
*grp
;
1308 struct exportlist
*ep
;
1311 struct hostlist
*hp
;
1312 struct dirlist
*dp2
;
1314 if (flags
& OP_ALLDIRS
) {
1320 ep
->ex_defdir
->dp_flag
|= DP_DEFSET
;
1321 if (flags
& OP_KERB
)
1322 ep
->ex_defdir
->dp_flag
|= DP_KERB
;
1323 if (flags
& OP_NORESMNT
)
1324 ep
->ex_defdir
->dp_flag
|= DP_NORESMNT
;
1328 if (flags
& OP_KERB
)
1329 hp
->ht_flag
|= DP_KERB
;
1330 if (flags
& OP_NORESMNT
)
1331 hp
->ht_flag
|= DP_NORESMNT
;
1333 hp
->ht_next
= ep
->ex_defdir
->dp_hosts
;
1334 ep
->ex_defdir
->dp_hosts
= hp
;
1340 * Loop through the directories adding them to the tree.
1344 add_dlist(&ep
->ex_dirl
, dp
, grp
, flags
);
1351 * Traverse the binary tree either updating a node that is already there
1352 * for the new directory or adding the new node.
1355 add_dlist(dpp
, newdp
, grp
, flags
)
1356 struct dirlist
**dpp
;
1357 struct dirlist
*newdp
;
1358 struct grouplist
*grp
;
1362 struct hostlist
*hp
;
1367 cmp
= strcmp(dp
->dp_dirp
, newdp
->dp_dirp
);
1369 add_dlist(&dp
->dp_left
, newdp
, grp
, flags
);
1371 } else if (cmp
< 0) {
1372 add_dlist(&dp
->dp_right
, newdp
, grp
, flags
);
1384 * Hang all of the host(s) off of the directory point.
1388 if (flags
& OP_KERB
)
1389 hp
->ht_flag
|= DP_KERB
;
1390 if (flags
& OP_NORESMNT
)
1391 hp
->ht_flag
|= DP_NORESMNT
;
1393 hp
->ht_next
= dp
->dp_hosts
;
1398 dp
->dp_flag
|= DP_DEFSET
;
1399 if (flags
& OP_KERB
)
1400 dp
->dp_flag
|= DP_KERB
;
1401 if (flags
& OP_NORESMNT
)
1402 dp
->dp_flag
|= DP_NORESMNT
;
1407 * Search for a dirpath on the export point.
1409 static struct dirlist
*
1410 dirp_search(dp
, dirp
)
1417 cmp
= strcmp(dp
->dp_dirp
, dirp
);
1419 return (dirp_search(dp
->dp_left
, dirp
));
1421 return (dirp_search(dp
->dp_right
, dirp
));
1429 * Some helper functions for netmasks. They all assume masks in network
1430 * order (big endian).
1433 bitcmp(void *dst
, void *src
, int bitlen
)
1436 u_int8_t
*p1
= dst
, *p2
= src
;
1438 int bytelen
, bitsleft
;
1440 bytelen
= bitlen
/ 8;
1441 bitsleft
= bitlen
% 8;
1444 printf("comparing:\n");
1445 for (i
= 0; i
< (bitsleft
? bytelen
+ 1 : bytelen
); i
++)
1446 printf("%02x", p1
[i
]);
1448 for (i
= 0; i
< (bitsleft
? bytelen
+ 1 : bytelen
); i
++)
1449 printf("%02x", p2
[i
]);
1453 for (i
= 0; i
< bytelen
; i
++) {
1460 for (i
= 0; i
< bitsleft
; i
++) {
1461 bitmask
= 1 << (7 - i
);
1462 if ((*p1
& bitmask
) != (*p2
& bitmask
))
1470 netpartcmp(struct sockaddr
*s1
, struct sockaddr
*s2
, int bitlen
)
1474 if (s1
->sa_family
!= s2
->sa_family
)
1477 switch (s1
->sa_family
) {
1479 src
= &((struct sockaddr_in
*)s1
)->sin_addr
;
1480 dst
= &((struct sockaddr_in
*)s2
)->sin_addr
;
1481 if (bitlen
> sizeof(((struct sockaddr_in
*)s1
)->sin_addr
) * 8)
1485 src
= &((struct sockaddr_in6
*)s1
)->sin6_addr
;
1486 dst
= &((struct sockaddr_in6
*)s2
)->sin6_addr
;
1487 if (((struct sockaddr_in6
*)s1
)->sin6_scope_id
!=
1488 ((struct sockaddr_in6
*)s2
)->sin6_scope_id
)
1490 if (bitlen
> sizeof(((struct sockaddr_in6
*)s1
)->sin6_addr
) * 8)
1497 return bitcmp(src
, dst
, bitlen
);
1501 allones(struct sockaddr_storage
*ssp
, int bitlen
)
1504 int bytelen
, bitsleft
, i
;
1507 switch (ssp
->ss_family
) {
1509 p
= (u_int8_t
*)&((struct sockaddr_in
*)ssp
)->sin_addr
;
1510 zerolen
= sizeof (((struct sockaddr_in
*)ssp
)->sin_addr
);
1513 p
= (u_int8_t
*)&((struct sockaddr_in6
*)ssp
)->sin6_addr
;
1514 zerolen
= sizeof (((struct sockaddr_in6
*)ssp
)->sin6_addr
);
1520 memset(p
, 0, zerolen
);
1522 bytelen
= bitlen
/ 8;
1523 bitsleft
= bitlen
% 8;
1525 if (bytelen
> zerolen
)
1528 for (i
= 0; i
< bytelen
; i
++)
1531 for (i
= 0; i
< bitsleft
; i
++)
1538 countones(struct sockaddr
*sa
)
1541 int i
, bits
= 0, bytelen
;
1544 switch (sa
->sa_family
) {
1546 mask
= (u_int8_t
*)&((struct sockaddr_in
*)sa
)->sin_addr
;
1550 mask
= (u_int8_t
*)&((struct sockaddr_in6
*)sa
)->sin6_addr
;
1559 for (i
= 0; i
< bytelen
; i
++, p
++) {
1561 for (bits
= 0; bits
< 8; bits
++) {
1562 if (!(*p
& (1 << (7 - bits
))))
1569 return (i
* 8 + bits
);
1573 sacmp(struct sockaddr
*sa1
, struct sockaddr
*sa2
)
1578 if (sa1
->sa_family
!= sa2
->sa_family
)
1581 switch (sa1
->sa_family
) {
1583 p1
= &((struct sockaddr_in
*)sa1
)->sin_addr
;
1584 p2
= &((struct sockaddr_in
*)sa2
)->sin_addr
;
1588 p1
= &((struct sockaddr_in6
*)sa1
)->sin6_addr
;
1589 p2
= &((struct sockaddr_in6
*)sa2
)->sin6_addr
;
1591 if (((struct sockaddr_in6
*)sa1
)->sin6_scope_id
!=
1592 ((struct sockaddr_in6
*)sa2
)->sin6_scope_id
)
1599 return memcmp(p1
, p2
, len
);
1603 * Scan for a host match in a directory tree.
1606 chk_host(dp
, saddr
, defsetp
, hostsetp
)
1608 struct sockaddr
*saddr
;
1612 struct hostlist
*hp
;
1613 struct grouplist
*grp
;
1614 struct addrinfo
*ai
;
1617 if (dp
->dp_flag
& DP_DEFSET
)
1618 *defsetp
= dp
->dp_flag
;
1622 switch (grp
->gr_type
) {
1624 ai
= grp
->gr_ptr
.gt_addrinfo
;
1625 for (; ai
; ai
= ai
->ai_next
) {
1626 if (!sacmp(ai
->ai_addr
, saddr
)) {
1628 (hp
->ht_flag
| DP_HOSTSET
);
1634 if (!netpartcmp(saddr
,
1636 &grp
->gr_ptr
.gt_net
.nt_net
,
1637 grp
->gr_ptr
.gt_net
.nt_len
)) {
1638 *hostsetp
= (hp
->ht_flag
| DP_HOSTSET
);
1650 * Scan tree for a host that matches the address.
1653 scan_tree(dp
, saddr
)
1655 struct sockaddr
*saddr
;
1657 int defset
, hostset
;
1660 if (scan_tree(dp
->dp_left
, saddr
))
1662 if (chk_host(dp
, saddr
, &defset
, &hostset
))
1664 if (scan_tree(dp
->dp_right
, saddr
))
1671 * Traverse the dirlist tree and free it up.
1679 free_dir(dp
->dp_left
);
1680 free_dir(dp
->dp_right
);
1681 free_host(dp
->dp_hosts
);
1687 * Parse the option string and update fields.
1688 * Option arguments may either be -<option>=<value> or
1692 do_opt(line
, lineno
, cpp
, endcpp
, ep
, grp
, has_hostp
, exflagsp
, cr
)
1695 char **cpp
, **endcpp
;
1696 struct exportlist
*ep
;
1697 struct grouplist
*grp
;
1702 char *cpoptarg
, *cpoptend
;
1703 char *cp
, *cpopt
, savedc
, savedc2
;
1704 char *endcp
= NULL
; /* XXX: GCC */
1705 int allflag
, usedarg
;
1712 while (cpopt
&& *cpopt
) {
1716 if ((cpoptend
= strchr(cpopt
, ',')) != NULL
) {
1718 if ((cpoptarg
= strchr(cpopt
, '=')) != NULL
)
1721 if ((cpoptarg
= strchr(cpopt
, '=')) != NULL
)
1725 nextfield(&cp
, &endcp
);
1727 if (endcp
> cp
&& *cp
!= '-') {
1735 if (!strcmp(cpopt
, "ro") || !strcmp(cpopt
, "o")) {
1736 *exflagsp
|= MNT_EXRDONLY
;
1737 } else if (cpoptarg
&& (!strcmp(cpopt
, "maproot") ||
1738 !(allflag
= strcmp(cpopt
, "mapall")) ||
1739 !strcmp(cpopt
, "root") || !strcmp(cpopt
, "r"))) {
1741 parsecred(cpoptarg
, cr
);
1743 *exflagsp
|= MNT_EXPORTANON
;
1744 opt_flags
|= OP_MAPALL
;
1746 opt_flags
|= OP_MAPROOT
;
1747 } else if (!strcmp(cpopt
, "kerb") || !strcmp(cpopt
, "k")) {
1748 *exflagsp
|= MNT_EXKERB
;
1749 opt_flags
|= OP_KERB
;
1750 } else if (cpoptarg
&& (!strcmp(cpopt
, "mask") ||
1751 !strcmp(cpopt
, "m"))) {
1752 if (get_net(cpoptarg
, &grp
->gr_ptr
.gt_net
, 1)) {
1754 "\"%s\", line %ld: Bad mask: %s",
1755 line
, (unsigned long)lineno
, cpoptarg
);
1759 opt_flags
|= OP_MASK
;
1760 } else if (cpoptarg
&& (!strcmp(cpopt
, "network") ||
1761 !strcmp(cpopt
, "n"))) {
1762 if (strchr(cpoptarg
, '/') != NULL
) {
1764 fprintf(stderr
, "setting OP_MASKLEN\n");
1765 opt_flags
|= OP_MASKLEN
;
1767 if (grp
->gr_type
!= GT_NULL
) {
1769 "\"%s\", line %ld: Network/host conflict",
1770 line
, (unsigned long)lineno
);
1772 } else if (get_net(cpoptarg
, &grp
->gr_ptr
.gt_net
, 0)) {
1774 "\"%s\", line %ld: Bad net: %s",
1775 line
, (unsigned long)lineno
, cpoptarg
);
1778 grp
->gr_type
= GT_NET
;
1781 opt_flags
|= OP_NET
;
1782 } else if (!strcmp(cpopt
, "alldirs")) {
1783 opt_flags
|= OP_ALLDIRS
;
1784 } else if (!strcmp(cpopt
, "noresvmnt")) {
1785 opt_flags
|= OP_NORESMNT
;
1786 } else if (!strcmp(cpopt
, "noresvport")) {
1787 opt_flags
|= OP_NORESPORT
;
1788 *exflagsp
|= MNT_EXNORESPORT
;
1789 } else if (!strcmp(cpopt
, "public")) {
1790 *exflagsp
|= (MNT_EXNORESPORT
| MNT_EXPUBLIC
);
1791 opt_flags
|= OP_NORESPORT
;
1792 } else if (!strcmp(cpopt
, "webnfs")) {
1793 *exflagsp
|= (MNT_EXNORESPORT
| MNT_EXPUBLIC
|
1794 MNT_EXRDONLY
| MNT_EXPORTANON
);
1795 opt_flags
|= (OP_MAPALL
| OP_NORESPORT
);
1796 } else if (cpoptarg
&& !strcmp(cpopt
, "index")) {
1797 ep
->ex_indexfile
= strdup(cpoptarg
);
1800 "\"%s\", line %ld: Bad opt %s",
1801 line
, (unsigned long)lineno
, cpopt
);
1820 * Translate a character string to the corresponding list of network
1821 * addresses for a hostname.
1824 get_host(line
, lineno
, cp
, grp
)
1828 struct grouplist
*grp
;
1830 struct addrinfo
*ai
, hints
;
1832 char host
[NI_MAXHOST
];
1834 if (grp
->gr_type
!= GT_NULL
) {
1836 "\"%s\", line %ld: Bad netgroup type for ip host %s",
1837 line
, (unsigned long)lineno
, cp
);
1840 memset(&hints
, 0, sizeof hints
);
1841 hints
.ai_flags
= AI_CANONNAME
;
1842 hints
.ai_protocol
= IPPROTO_UDP
;
1843 ecode
= getaddrinfo(cp
, NULL
, &hints
, &ai
);
1845 syslog(LOG_ERR
, "\"%s\", line %ld: can't get address info for "
1847 line
, (long)lineno
, cp
);
1850 grp
->gr_type
= GT_HOST
;
1851 grp
->gr_ptr
.gt_addrinfo
= ai
;
1852 while (ai
!= NULL
) {
1853 if (ai
->ai_canonname
== NULL
) {
1854 if (getnameinfo(ai
->ai_addr
, ai
->ai_addrlen
, host
,
1855 sizeof host
, NULL
, 0, ninumeric
) != 0)
1856 strlcpy(host
, "?", sizeof(host
));
1857 ai
->ai_canonname
= estrdup(host
);
1858 ai
->ai_flags
|= AI_CANONNAME
;
1860 ai
->ai_flags
&= ~AI_CANONNAME
;
1862 (void)fprintf(stderr
, "got host %s\n", ai
->ai_canonname
);
1869 * Free up an exports list component
1873 struct exportlist
*ep
;
1876 if (ep
->ex_defdir
) {
1877 free_host(ep
->ex_defdir
->dp_hosts
);
1878 free(ep
->ex_defdir
);
1882 if (ep
->ex_indexfile
)
1883 free(ep
->ex_indexfile
);
1884 free_dir(ep
->ex_dirl
);
1893 struct hostlist
*hp
;
1895 struct hostlist
*hp2
;
1904 static struct hostlist
*
1907 struct hostlist
*hp
;
1909 hp
= emalloc(sizeof(struct hostlist
));
1916 * Do the nfssvc syscall to push the export info into the kernel.
1919 do_nfssvc(line
, lineno
, ep
, grp
, exflags
, anoncrp
, dirp
, dirplen
, fsb
)
1922 struct exportlist
*ep
;
1923 struct grouplist
*grp
;
1925 struct uucred
*anoncrp
;
1928 struct statvfs
*fsb
;
1930 struct sockaddr
*addrp
;
1931 struct sockaddr_storage ss
;
1932 struct addrinfo
*ai
;
1935 struct export_args export
;
1937 export
.ex_flags
= exflags
;
1938 export
.ex_anon
= *anoncrp
;
1939 export
.ex_indexfile
= ep
->ex_indexfile
;
1940 if (grp
->gr_type
== GT_HOST
) {
1941 ai
= grp
->gr_ptr
.gt_addrinfo
;
1942 addrp
= ai
->ai_addr
;
1943 addrlen
= ai
->ai_addrlen
;
1946 ai
= NULL
; /* XXXGCC -Wuninitialized */
1947 addrlen
= 0; /* XXXGCC -Wuninitialized */
1951 struct mountd_exports_list mel
;
1953 switch (grp
->gr_type
) {
1955 if (addrp
!= NULL
&& addrp
->sa_family
== AF_INET6
&&
1958 export
.ex_addr
= addrp
;
1959 export
.ex_addrlen
= addrlen
;
1960 export
.ex_masklen
= 0;
1963 export
.ex_addr
= (struct sockaddr
*)
1964 &grp
->gr_ptr
.gt_net
.nt_net
;
1965 if (export
.ex_addr
->sa_family
== AF_INET6
&&
1968 export
.ex_addrlen
= export
.ex_addr
->sa_len
;
1969 memset(&ss
, 0, sizeof ss
);
1970 ss
.ss_family
= export
.ex_addr
->sa_family
;
1971 ss
.ss_len
= export
.ex_addr
->sa_len
;
1972 if (allones(&ss
, grp
->gr_ptr
.gt_net
.nt_len
) != 0) {
1974 "\"%s\", line %ld: Bad network flag",
1975 line
, (unsigned long)lineno
);
1978 export
.ex_mask
= (struct sockaddr
*)&ss
;
1979 export
.ex_masklen
= ss
.ss_len
;
1982 syslog(LOG_ERR
, "\"%s\", line %ld: Bad netgroup type",
1983 line
, (unsigned long)lineno
);
1989 * Maybe I should just use the fsb->f_mntonname path?
1992 mel
.mel_path
= dirp
;
1993 mel
.mel_nexports
= 1;
1994 mel
.mel_exports
= &export
;
1996 if (rump_sys_nfssvc(NFSSVC_SETEXPORTSLIST
, &mel
) != 0) {
1998 "\"%s\", line %ld: Can't change attributes for %s to %s (%s)",
1999 line
, (unsigned long)lineno
,
2000 dirp
, (grp
->gr_type
== GT_HOST
) ?
2001 grp
->gr_ptr
.gt_addrinfo
->ai_canonname
:
2002 (grp
->gr_type
== GT_NET
) ?
2003 grp
->gr_ptr
.gt_net
.nt_name
:
2004 "Unknown", strerror(errno
));
2013 addrp
= ai
->ai_addr
;
2014 addrlen
= ai
->ai_addrlen
;
2023 * Translate a net address.
2026 get_net(cp
, net
, maskflg
)
2032 char *thename
, *p
, *prefp
;
2033 struct sockaddr_in sin
, *sinp
;
2034 struct sockaddr
*sa
;
2035 struct addrinfo hints
, *ai
= NULL
;
2036 char netname
[NI_MAXHOST
];
2040 (void)memset(&sin
, 0, sizeof(sin
));
2041 if ((opt_flags
& OP_MASKLEN
) && !maskflg
) {
2042 p
= strchr(cp
, '/');
2046 p
= NULL
; /* XXXGCC -Wuninitialized */
2047 prefp
= NULL
; /* XXXGCC -Wuninitialized */
2050 if ((np
= getnetbyname(cp
)) != NULL
) {
2051 sin
.sin_family
= AF_INET
;
2052 sin
.sin_len
= sizeof sin
;
2053 sin
.sin_addr
= inet_makeaddr(np
->n_net
, 0);
2054 sa
= (struct sockaddr
*)&sin
;
2055 } else if (isdigit((unsigned char)*cp
)) {
2056 memset(&hints
, 0, sizeof hints
);
2057 hints
.ai_family
= AF_UNSPEC
;
2058 hints
.ai_flags
= AI_NUMERICHOST
;
2059 if (getaddrinfo(cp
, NULL
, &hints
, &ai
) != 0) {
2061 * If getaddrinfo() failed, try the inet4 network
2062 * notation with less than 3 dots.
2064 sin
.sin_family
= AF_INET
;
2065 sin
.sin_len
= sizeof sin
;
2066 sin
.sin_addr
= inet_makeaddr(inet_network(cp
),0);
2068 fprintf(stderr
, "get_net: v4 addr %x\n",
2069 sin
.sin_addr
.s_addr
);
2070 sa
= (struct sockaddr
*)&sin
;
2073 } else if (isxdigit((unsigned char)*cp
) || *cp
== ':') {
2074 memset(&hints
, 0, sizeof hints
);
2075 hints
.ai_family
= AF_UNSPEC
;
2076 hints
.ai_flags
= AI_NUMERICHOST
;
2077 if (getaddrinfo(cp
, NULL
, &hints
, &ai
) == 0)
2085 * Only allow /pref notation for v6 addresses.
2087 if (sa
->sa_family
== AF_INET6
&& (!(opt_flags
& OP_MASKLEN
) || maskflg
))
2090 ecode
= getnameinfo(sa
, sa
->sa_len
, netname
, sizeof netname
,
2091 NULL
, 0, ninumeric
);
2096 net
->nt_len
= countones(sa
);
2098 if (opt_flags
& OP_MASKLEN
) {
2100 preflen
= strtol(prefp
, NULL
, 10);
2101 if (preflen
== LONG_MIN
&& errno
== ERANGE
)
2103 net
->nt_len
= (int)preflen
;
2108 thename
= np
->n_name
;
2110 if (getnameinfo(sa
, sa
->sa_len
, netname
, sizeof netname
,
2111 NULL
, 0, ninumeric
) != 0)
2112 strlcpy(netname
, "?", sizeof(netname
));
2115 net
->nt_name
= estrdup(thename
);
2116 memcpy(&net
->nt_net
, sa
, sa
->sa_len
);
2119 if (!maskflg
&& sa
->sa_family
== AF_INET
&&
2120 !(opt_flags
& (OP_MASK
|OP_MASKLEN
))) {
2121 sinp
= (struct sockaddr_in
*)sa
;
2122 if (IN_CLASSA(sinp
->sin_addr
.s_addr
))
2124 else if (IN_CLASSB(sinp
->sin_addr
.s_addr
))
2126 else if (IN_CLASSC(sinp
->sin_addr
.s_addr
))
2128 else if (IN_CLASSD(sinp
->sin_addr
.s_addr
))
2131 net
->nt_len
= 32; /* XXX */
2145 * Parse out the next white space separated field
2148 nextfield(cp
, endcp
)
2155 while (*p
== ' ' || *p
== '\t')
2157 if (*p
== '\n' || *p
== '\0')
2161 while (*p
!= ' ' && *p
!= '\t' && *p
!= '\n' && *p
!= '\0')
2168 * Parse a description of a credential.
2171 parsecred(namelist
, cr
)
2181 gid_t grps
[NGROUPS
+ 1];
2184 * Set up the unprivileged user.
2188 * Get the user's password table entry.
2190 names
= strsep(&namelist
, " \t\n");
2191 thename
= strsep(&names
, ":");
2192 if (isdigit((unsigned char)*thename
) || *thename
== '-')
2193 pw
= getpwuid(atoi(thename
));
2195 pw
= getpwnam(thename
);
2197 * Credentials specified as those of a user.
2199 if (names
== NULL
) {
2201 syslog(LOG_ERR
, "Unknown user: %s", thename
);
2204 cr
->cr_uid
= pw
->pw_uid
;
2205 ngroups
= NGROUPS
+ 1;
2206 if (getgrouplist(pw
->pw_name
, pw
->pw_gid
, grps
, &ngroups
))
2207 syslog(LOG_ERR
, "Too many groups for user %s", thename
);
2209 * Convert from int's to gid_t's and compress out duplicate
2211 cr
->cr_ngroups
= ngroups
- 1;
2212 cr
->cr_gid
= grps
[0];
2213 for (cnt
= 1; cnt
< ngroups
; cnt
++)
2214 cr
->cr_groups
[cnt
- 1] = grps
[cnt
];
2218 * Explicit credential specified as a colon separated list:
2222 cr
->cr_uid
= pw
->pw_uid
;
2223 else if (isdigit((unsigned char)*thename
) || *thename
== '-')
2224 cr
->cr_uid
= atoi(thename
);
2226 syslog(LOG_ERR
, "Unknown user: %s", thename
);
2230 while (names
!= NULL
&& *names
!= '\0' && cr
->cr_ngroups
< NGROUPS
) {
2231 thename
= strsep(&names
, ":");
2232 if (isdigit((unsigned char)*thename
) || *thename
== '-') {
2233 cr
->cr_groups
[cr
->cr_ngroups
++] = atoi(thename
);
2235 if ((gr
= getgrnam(thename
)) == NULL
) {
2236 syslog(LOG_ERR
, "Unknown group: %s", thename
);
2239 cr
->cr_groups
[cr
->cr_ngroups
++] = gr
->gr_gid
;
2242 if (names
!= NULL
&& *names
!= '\0' && cr
->cr_ngroups
== NGROUPS
)
2243 syslog(LOG_ERR
, "Too many groups");
2246 #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
2248 * Routines that maintain the remote mounttab
2253 struct mountlist
*mlp
, **mlpp
;
2254 char *host
, *dirp
, *cp
;
2258 if ((mlfile
= rumpfopen(_PATH_RMOUNTLIST
, "r")) == NULL
) {
2259 syslog(LOG_ERR
, "Can't open %s (%s)", _PATH_RMOUNTLIST
,
2264 while (fgets(str
, STRSIZ
, mlfile
) != NULL
) {
2266 host
= strsep(&cp
, " \t\n");
2267 dirp
= strsep(&cp
, " \t\n");
2268 if (host
== NULL
|| dirp
== NULL
)
2270 mlp
= emalloc(sizeof(*mlp
));
2271 (void)strncpy(mlp
->ml_host
, host
, RPCMNT_NAMELEN
);
2272 mlp
->ml_host
[RPCMNT_NAMELEN
] = '\0';
2273 (void)strncpy(mlp
->ml_dirp
, dirp
, RPCMNT_PATHLEN
);
2274 mlp
->ml_dirp
[RPCMNT_PATHLEN
] = '\0';
2275 mlp
->ml_next
= NULL
;
2277 mlpp
= &mlp
->ml_next
;
2279 (void)fclose(mlfile
);
2283 del_mlist(hostp
, dirp
, saddr
)
2285 struct sockaddr
*saddr
;
2287 struct mountlist
*mlp
, **mlpp
;
2288 struct mountlist
*mlp2
;
2291 int fnd
= 0, ret
= 0;
2292 char host
[NI_MAXHOST
];
2294 switch (saddr
->sa_family
) {
2296 sport
= ntohs(((struct sockaddr_in6
*)saddr
)->sin6_port
);
2299 sport
= ntohs(((struct sockaddr_in
*)saddr
)->sin_port
);
2307 if (!strcmp(mlp
->ml_host
, hostp
) &&
2308 (!dirp
|| !strcmp(mlp
->ml_dirp
, dirp
))) {
2309 if (!(mlp
->ml_flag
& DP_NORESMNT
) &&
2310 sport
>= IPPORT_RESERVED
) {
2311 if (getnameinfo(saddr
, saddr
->sa_len
, host
,
2312 sizeof host
, NULL
, 0, ninumeric
) != 0)
2313 strlcpy(host
, "?", sizeof(host
));
2315 "Umount request for %s:%s from %s refused\n",
2316 mlp
->ml_host
, mlp
->ml_dirp
, host
);
2322 *mlpp
= mlp
= mlp
->ml_next
;
2326 mlpp
= &mlp
->ml_next
;
2331 if ((mlfile
= rumpfopen(_PATH_RMOUNTLIST
, "w")) == NULL
) {
2332 syslog(LOG_ERR
, "Can't update %s (%s)",
2333 _PATH_RMOUNTLIST
, strerror(errno
));
2338 (void)fprintf(mlfile
, "%s %s\n", mlp
->ml_host
,
2342 (void)fclose(mlfile
);
2348 add_mlist(hostp
, dirp
, flags
)
2352 struct mountlist
*mlp
, **mlpp
;
2358 if (!strcmp(mlp
->ml_host
, hostp
) && !strcmp(mlp
->ml_dirp
, dirp
))
2360 mlpp
= &mlp
->ml_next
;
2363 mlp
= emalloc(sizeof(*mlp
));
2364 strncpy(mlp
->ml_host
, hostp
, RPCMNT_NAMELEN
);
2365 mlp
->ml_host
[RPCMNT_NAMELEN
] = '\0';
2366 strncpy(mlp
->ml_dirp
, dirp
, RPCMNT_PATHLEN
);
2367 mlp
->ml_dirp
[RPCMNT_PATHLEN
] = '\0';
2368 mlp
->ml_flag
= flags
;
2369 mlp
->ml_next
= NULL
;
2371 if ((mlfile
= rumpfopen(_PATH_RMOUNTLIST
, "a")) == NULL
) {
2372 syslog(LOG_ERR
, "Can't update %s (%s)", _PATH_RMOUNTLIST
,
2376 (void)fprintf(mlfile
, "%s %s\n", mlp
->ml_host
, mlp
->ml_dirp
);
2377 (void)fclose(mlfile
);
2381 * This function is called via. SIGTERM when the system is going down.
2382 * It sends a broadcast RPCMNT_UMNTALL.
2390 (void)clnt_broadcast(RPCPROG_MNT
, RPCMNT_VER1
, RPCMNT_UMNTALL
,
2391 xdr_void
, NULL
, xdr_void
, NULL
, (resultproc_t
)umntall_each
);
2398 umntall_each(resultsp
, raddr
)
2400 struct sockaddr_in
*raddr
;
2407 * Free up a group list.
2411 struct grouplist
*grp
;
2414 if (grp
->gr_type
== GT_HOST
) {
2415 if (grp
->gr_ptr
.gt_addrinfo
!= NULL
)
2416 freeaddrinfo(grp
->gr_ptr
.gt_addrinfo
);
2417 } else if (grp
->gr_type
== GT_NET
) {
2418 if (grp
->gr_ptr
.gt_net
.nt_name
)
2419 free(grp
->gr_ptr
.gt_net
.nt_name
);
2426 SYSLOG(int pri
, const char *fmt
,...)
2433 vfprintf(stderr
, fmt
, ap
);
2435 vsyslog(pri
, fmt
, ap
);
2442 * Check options for consistency.
2445 check_options(line
, lineno
, dp
)
2453 "\"%s\", line %ld: missing directory list",
2454 line
, (unsigned long)lineno
);
2457 if ((opt_flags
& (OP_MAPROOT
|OP_MAPALL
)) == (OP_MAPROOT
|OP_MAPALL
) ||
2458 (opt_flags
& (OP_MAPROOT
|OP_KERB
)) == (OP_MAPROOT
|OP_KERB
) ||
2459 (opt_flags
& (OP_MAPALL
|OP_KERB
)) == (OP_MAPALL
|OP_KERB
)) {
2461 "\"%s\", line %ld: -mapall, -maproot and -kerb mutually exclusive",
2462 line
, (unsigned long)lineno
);
2465 if ((opt_flags
& OP_MASK
) && (opt_flags
& OP_NET
) == 0) {
2466 syslog(LOG_ERR
, "\"%s\", line %ld: -mask requires -net",
2467 line
, (unsigned long)lineno
);
2470 if ((opt_flags
& OP_MASK
) && (opt_flags
& OP_MASKLEN
) != 0) {
2471 syslog(LOG_ERR
, "\"%s\", line %ld: /pref and -mask mutually"
2473 line
, (unsigned long)lineno
);
2476 if ((opt_flags
& OP_ALLDIRS
) && dp
->dp_left
) {
2478 "\"%s\", line %ld: -alldirs has multiple directories",
2479 line
, (unsigned long)lineno
);
2486 * Check an absolute directory path for any symbolic links. Return true
2487 * if no symbolic links are found.
2490 check_dirpath(line
, lineno
, dirp
)
2499 for (cp
= dirp
+ 1; *cp
; cp
++) {
2502 if (rump_sys_lstat(dirp
, &sb
) == -1)
2504 if (!S_ISDIR(sb
.st_mode
))
2511 if (rump_sys_lstat(dirp
, &sb
) == -1)
2514 if (!S_ISDIR(sb
.st_mode
) && !S_ISREG(sb
.st_mode
)) {
2515 file
= " file or a";
2523 "\"%s\", line %ld: lstat for `%s' failed (%s)",
2524 line
, (unsigned long)lineno
, dirp
, strerror(errno
));
2531 "\"%s\", line %ld: `%s' is not a%s directory",
2532 line
, (unsigned long)lineno
, dirp
, file
);
2540 bind_resv_port(int sock
, sa_family_t family
, in_port_t port
)
2542 struct sockaddr
*sa
;
2543 struct sockaddr_in sasin
;
2544 struct sockaddr_in6 sasin6
;
2548 (void)memset(&sasin
, 0, sizeof(sasin
));
2549 sasin
.sin_len
= sizeof(sasin
);
2550 sasin
.sin_family
= family
;
2551 sasin
.sin_port
= htons(port
);
2552 sa
= (struct sockaddr
*)(void *)&sasin
;
2555 (void)memset(&sasin6
, 0, sizeof(sasin6
));
2556 sasin6
.sin6_len
= sizeof(sasin6
);
2557 sasin6
.sin6_family
= family
;
2558 sasin6
.sin6_port
= htons(port
);
2559 sa
= (struct sockaddr
*)(void *)&sasin6
;
2562 syslog(LOG_ERR
, "Unsupported address family %d", family
);
2565 if (bindresvport_sa(sock
, sa
) == -1)
2566 syslog(LOG_ERR
, "Cannot bind to reserved port %d (%s)", port
,
2574 syslog(LOG_ERR
, "kernel NFS support not present; exiting");