18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni *
48fae3551SRodney W. Grimes * Copyright (c) 1989, 1993
58fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved.
68fae3551SRodney W. Grimes *
78fae3551SRodney W. Grimes * This code is derived from software contributed to Berkeley by
88fae3551SRodney W. Grimes * Herb Hasler and Rick Macklem at The University of Guelph.
98fae3551SRodney W. Grimes *
108fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without
118fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions
128fae3551SRodney W. Grimes * are met:
138fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
148fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer.
158fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
168fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
178fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution.
18fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
198fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software
208fae3551SRodney W. Grimes * without specific prior written permission.
218fae3551SRodney W. Grimes *
228fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
238fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
248fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
258fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
268fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
278fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
288fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
298fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
308fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
318fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
328fae3551SRodney W. Grimes * SUCH DAMAGE.
338fae3551SRodney W. Grimes */
348fae3551SRodney W. Grimes
358fae3551SRodney W. Grimes #include <sys/param.h>
363e2d36ffSRick Macklem #include <sys/conf.h>
378360efbdSAlfred Perlstein #include <sys/fcntl.h>
3846a6b5c4SRick Macklem #include <sys/fnv_hash.h>
3991ca1a91SIan Dowse #include <sys/linker.h>
4091ca1a91SIan Dowse #include <sys/module.h>
41bcc1d071SRick Macklem #include <sys/mount.h>
42c9ac0f71SEmmanuel Vadot #include <sys/queue.h>
43bcc1d071SRick Macklem #include <sys/stat.h>
44bcc1d071SRick Macklem #include <sys/sysctl.h>
45bcc1d071SRick Macklem #include <sys/syslog.h>
468fae3551SRodney W. Grimes
478fae3551SRodney W. Grimes #include <rpc/rpc.h>
48bcb53b16SMartin Blapp #include <rpc/rpc_com.h>
498fae3551SRodney W. Grimes #include <rpc/pmap_clnt.h>
508360efbdSAlfred Perlstein #include <rpc/pmap_prot.h>
518360efbdSAlfred Perlstein #include <rpcsvc/mount.h>
52a62dc406SDoug Rabson #include <nfs/nfsproto.h>
53bcc1d071SRick Macklem #include <nfs/nfssvc.h>
5491196234SPeter Wemm #include <nfsserver/nfs.h>
558fae3551SRodney W. Grimes
56bcc1d071SRick Macklem #include <fs/nfs/nfsport.h>
57bcc1d071SRick Macklem
588fae3551SRodney W. Grimes #include <arpa/inet.h>
598fae3551SRodney W. Grimes
608fae3551SRodney W. Grimes #include <ctype.h>
6174853402SPhilippe Charnier #include <err.h>
628fae3551SRodney W. Grimes #include <errno.h>
638fae3551SRodney W. Grimes #include <grp.h>
64a032b226SPawel Jakub Dawidek #include <libutil.h>
6589fdc4e1SMike Barcroft #include <limits.h>
668fae3551SRodney W. Grimes #include <netdb.h>
678fae3551SRodney W. Grimes #include <pwd.h>
688fae3551SRodney W. Grimes #include <signal.h>
698fae3551SRodney W. Grimes #include <stdio.h>
708fae3551SRodney W. Grimes #include <stdlib.h>
718fae3551SRodney W. Grimes #include <string.h>
728fae3551SRodney W. Grimes #include <unistd.h>
737c5146daSDan Mcgregor #include <vis.h>
748fae3551SRodney W. Grimes #include "pathnames.h"
756a09faf2SCraig Rodrigues #include "mntopts.h"
768fae3551SRodney W. Grimes
778fae3551SRodney W. Grimes #ifdef DEBUG
788fae3551SRodney W. Grimes #include <stdarg.h>
798fae3551SRodney W. Grimes #endif
808fae3551SRodney W. Grimes
818fae3551SRodney W. Grimes /*
828fae3551SRodney W. Grimes * Structures for keeping the mount list and export list
838fae3551SRodney W. Grimes */
848fae3551SRodney W. Grimes struct mountlist {
850775314bSDoug Rabson char ml_host[MNTNAMLEN+1];
860775314bSDoug Rabson char ml_dirp[MNTPATHLEN+1];
871da3e8b0SEmmanuel Vadot
881da3e8b0SEmmanuel Vadot SLIST_ENTRY(mountlist) next;
898fae3551SRodney W. Grimes };
908fae3551SRodney W. Grimes
918fae3551SRodney W. Grimes struct dirlist {
928fae3551SRodney W. Grimes struct dirlist *dp_left;
938fae3551SRodney W. Grimes struct dirlist *dp_right;
948fae3551SRodney W. Grimes int dp_flag;
958fae3551SRodney W. Grimes struct hostlist *dp_hosts; /* List of hosts this dir exported to */
96380a3fcdSEmmanuel Vadot char *dp_dirp;
978fae3551SRodney W. Grimes };
988fae3551SRodney W. Grimes /* dp_flag bits */
998fae3551SRodney W. Grimes #define DP_DEFSET 0x1
100a62dc406SDoug Rabson #define DP_HOSTSET 0x2
1018fae3551SRodney W. Grimes
102cc5efddeSRick Macklem /*
103cc5efddeSRick Macklem * maproot/mapall credentials.
1042ffad162SRick Macklem * cr_smallgrps can be used for a group list up to SMALLNGROUPS in size.
1052ffad162SRick Macklem * Larger group lists are malloc'd/free'd.
106cc5efddeSRick Macklem */
1072ffad162SRick Macklem #define SMALLNGROUPS 32
108cc5efddeSRick Macklem struct expcred {
109cc5efddeSRick Macklem uid_t cr_uid;
110cc5efddeSRick Macklem int cr_ngroups;
1112ffad162SRick Macklem gid_t cr_smallgrps[SMALLNGROUPS];
1122ffad162SRick Macklem gid_t *cr_groups;
113cc5efddeSRick Macklem };
114cc5efddeSRick Macklem
1158fae3551SRodney W. Grimes struct exportlist {
1168fae3551SRodney W. Grimes struct dirlist *ex_dirl;
1178fae3551SRodney W. Grimes struct dirlist *ex_defdir;
118711d44eeSRick Macklem struct grouplist *ex_grphead;
1198fae3551SRodney W. Grimes int ex_flag;
1208fae3551SRodney W. Grimes fsid_t ex_fs;
1218fae3551SRodney W. Grimes char *ex_fsdir;
122cb3923e0SDoug Rabson char *ex_indexfile;
123cc5efddeSRick Macklem struct expcred ex_defanon;
124cc5efddeSRick Macklem uint64_t ex_defexflags;
125a9148abdSDoug Rabson int ex_numsecflavors;
126a9148abdSDoug Rabson int ex_secflavors[MAXSECFLAVORS];
127c3f86a25SRick Macklem int ex_defnumsecflavors;
128c3f86a25SRick Macklem int ex_defsecflavors[MAXSECFLAVORS];
129c9ac0f71SEmmanuel Vadot
130c9ac0f71SEmmanuel Vadot SLIST_ENTRY(exportlist) entries;
1318fae3551SRodney W. Grimes };
1328fae3551SRodney W. Grimes /* ex_flag bits */
133fefb7c39SRick Macklem #define EX_LINKED 0x01
134fefb7c39SRick Macklem #define EX_DONE 0x02
135fefb7c39SRick Macklem #define EX_DEFSET 0x04
136fefb7c39SRick Macklem #define EX_PUBLICFH 0x08
137fefb7c39SRick Macklem #define EX_ADMINWARN 0x10
1388fae3551SRodney W. Grimes
1391a9a992fSRick Macklem SLIST_HEAD(exportlisthead, exportlist);
1401a9a992fSRick Macklem
1418fae3551SRodney W. Grimes struct netmsk {
1428360efbdSAlfred Perlstein struct sockaddr_storage nt_net;
14360caaee2SIan Dowse struct sockaddr_storage nt_mask;
1448fae3551SRodney W. Grimes char *nt_name;
1458fae3551SRodney W. Grimes };
1468fae3551SRodney W. Grimes
1478fae3551SRodney W. Grimes union grouptypes {
1488360efbdSAlfred Perlstein struct addrinfo *gt_addrinfo;
1498fae3551SRodney W. Grimes struct netmsk gt_net;
1508fae3551SRodney W. Grimes };
1518fae3551SRodney W. Grimes
1528fae3551SRodney W. Grimes struct grouplist {
1538fae3551SRodney W. Grimes int gr_type;
1548fae3551SRodney W. Grimes union grouptypes gr_ptr;
1558fae3551SRodney W. Grimes struct grouplist *gr_next;
156cc5efddeSRick Macklem struct expcred gr_anon;
157cc5efddeSRick Macklem uint64_t gr_exflags;
1580f0869bcSRick Macklem int gr_flag;
159c3f86a25SRick Macklem int gr_numsecflavors;
160c3f86a25SRick Macklem int gr_secflavors[MAXSECFLAVORS];
1618fae3551SRodney W. Grimes };
1628fae3551SRodney W. Grimes /* Group types */
1638fae3551SRodney W. Grimes #define GT_NULL 0x0
1648fae3551SRodney W. Grimes #define GT_HOST 0x1
1658fae3551SRodney W. Grimes #define GT_NET 0x2
1666d359f31SIan Dowse #define GT_DEFAULT 0x3
1678b5a6d67SBill Paul #define GT_IGNORE 0x5
1688fae3551SRodney W. Grimes
1690f0869bcSRick Macklem /* Group flags */
1700f0869bcSRick Macklem #define GR_FND 0x1
1710f0869bcSRick Macklem
1728fae3551SRodney W. Grimes struct hostlist {
173a62dc406SDoug Rabson int ht_flag; /* Uses DP_xx bits */
1748fae3551SRodney W. Grimes struct grouplist *ht_grp;
1758fae3551SRodney W. Grimes struct hostlist *ht_next;
1768fae3551SRodney W. Grimes };
1778fae3551SRodney W. Grimes
178a62dc406SDoug Rabson struct fhreturn {
179a62dc406SDoug Rabson int fhr_flag;
180a62dc406SDoug Rabson int fhr_vers;
181a62dc406SDoug Rabson nfsfh_t fhr_fh;
182a9148abdSDoug Rabson int fhr_numsecflavors;
183a9148abdSDoug Rabson int *fhr_secflavors;
184a62dc406SDoug Rabson };
185a62dc406SDoug Rabson
1868fb6ad5dSRick Macklem #define GETPORT_MAXTRY 20 /* Max tries to get a port # */
1878fb6ad5dSRick Macklem
1887674d489SRick Macklem /*
1897674d489SRick Macklem * How long to delay a reload of exports when there are RPC request(s)
1907674d489SRick Macklem * to process, in usec. Must be less than 1second.
1917674d489SRick Macklem */
1927674d489SRick Macklem #define RELOADDELAY 250000
1937674d489SRick Macklem
1948fae3551SRodney W. Grimes /* Global defs */
19519c46d8cSEdward Tomasz Napierala static char *add_expdir(struct dirlist **, char *, int);
19619c46d8cSEdward Tomasz Napierala static void add_dlist(struct dirlist **, struct dirlist *,
1970f0869bcSRick Macklem struct grouplist *, int, struct exportlist *,
198cc5efddeSRick Macklem struct expcred *, uint64_t);
19919c46d8cSEdward Tomasz Napierala static void add_mlist(char *, char *);
200572b77f8SAlexander Motin static int check_path_component(const char *, char **);
201572b77f8SAlexander Motin static int check_dirpath(char *, char **);
202572b77f8SAlexander Motin static int check_statfs(const char *, struct statfs *, char **);
20319c46d8cSEdward Tomasz Napierala static int check_options(struct dirlist *);
20419c46d8cSEdward Tomasz Napierala static int checkmask(struct sockaddr *sa);
20519c46d8cSEdward Tomasz Napierala static int chk_host(struct dirlist *, struct sockaddr *, int *, int *,
20619c46d8cSEdward Tomasz Napierala int *, int **);
207b875c2e9SJosh Paetzel static char *strsep_quote(char **stringp, const char *delim);
2088fb6ad5dSRick Macklem static int create_service(struct netconfig *nconf);
2098fb6ad5dSRick Macklem static void complete_service(struct netconfig *nconf, char *port_str);
2108fb6ad5dSRick Macklem static void clearout_service(void);
21119c46d8cSEdward Tomasz Napierala static void del_mlist(char *hostp, char *dirp);
21219c46d8cSEdward Tomasz Napierala static struct dirlist *dirp_search(struct dirlist *, char *);
2130f0869bcSRick Macklem static int do_export_mount(struct exportlist *, struct statfs *);
214cc5efddeSRick Macklem static int do_mount(struct exportlist *, struct grouplist *, uint64_t,
215cc5efddeSRick Macklem struct expcred *, char *, int, struct statfs *, int, int *);
21619c46d8cSEdward Tomasz Napierala static int do_opt(char **, char **, struct exportlist *,
217cc5efddeSRick Macklem struct grouplist *, int *, uint64_t *, struct expcred *);
2181a9a992fSRick Macklem static struct exportlist *ex_search(fsid_t *, struct exportlisthead *);
21919c46d8cSEdward Tomasz Napierala static struct exportlist *get_exp(void);
22019c46d8cSEdward Tomasz Napierala static void free_dir(struct dirlist *);
22119c46d8cSEdward Tomasz Napierala static void free_exp(struct exportlist *);
22219c46d8cSEdward Tomasz Napierala static void free_grp(struct grouplist *);
22319c46d8cSEdward Tomasz Napierala static void free_host(struct hostlist *);
2240f0869bcSRick Macklem static void free_v4rootexp(void);
2250f0869bcSRick Macklem static void get_exportlist_one(int);
2260f0869bcSRick Macklem static void get_exportlist(int);
2271a9a992fSRick Macklem static void insert_exports(struct exportlist *, struct exportlisthead *);
2281a9a992fSRick Macklem static void free_exports(struct exportlisthead *);
2290f0869bcSRick Macklem static void read_exportfile(int);
2300f0869bcSRick Macklem static int compare_nmount_exportlist(struct iovec *, int, char *);
2310f0869bcSRick Macklem static int compare_export(struct exportlist *, struct exportlist *);
232cc5efddeSRick Macklem static int compare_cred(struct expcred *, struct expcred *);
2330f0869bcSRick Macklem static int compare_secflavor(int *, int *, int);
2343e08dc74SRick Macklem static void delete_export(struct iovec *, int, struct statfs *, char *);
23519c46d8cSEdward Tomasz Napierala static int get_host(char *, struct grouplist *, struct grouplist *);
23619c46d8cSEdward Tomasz Napierala static struct hostlist *get_ht(void);
23719c46d8cSEdward Tomasz Napierala static int get_line(void);
23819c46d8cSEdward Tomasz Napierala static void get_mountlist(void);
23919c46d8cSEdward Tomasz Napierala static int get_net(char *, struct netmsk *, int);
240354fce28SConrad Meyer static void getexp_err(struct exportlist *, struct grouplist *, const char *);
24119c46d8cSEdward Tomasz Napierala static struct grouplist *get_grp(void);
24219c46d8cSEdward Tomasz Napierala static void hang_dirp(struct dirlist *, struct grouplist *,
243cc5efddeSRick Macklem struct exportlist *, int, struct expcred *, uint64_t);
24419c46d8cSEdward Tomasz Napierala static void huphandler(int sig);
24519c46d8cSEdward Tomasz Napierala static int makemask(struct sockaddr_storage *ssp, int bitlen);
24619c46d8cSEdward Tomasz Napierala static void mntsrv(struct svc_req *, SVCXPRT *);
24719c46d8cSEdward Tomasz Napierala static void nextfield(char **, char **);
24819c46d8cSEdward Tomasz Napierala static void out_of_mem(void);
249cc5efddeSRick Macklem static void parsecred(char *, struct expcred *);
25019c46d8cSEdward Tomasz Napierala static int parsesec(char *, struct exportlist *);
25119c46d8cSEdward Tomasz Napierala static int put_exlist(struct dirlist *, XDR *, struct dirlist *,
25219c46d8cSEdward Tomasz Napierala int *, int);
25319c46d8cSEdward Tomasz Napierala static void *sa_rawaddr(struct sockaddr *sa, int *nbytes);
25419c46d8cSEdward Tomasz Napierala static int sacmp(struct sockaddr *sa1, struct sockaddr *sa2,
25560caaee2SIan Dowse struct sockaddr *samask);
25619c46d8cSEdward Tomasz Napierala static int scan_tree(struct dirlist *, struct sockaddr *);
25785429990SWarner Losh static void usage(void);
25819c46d8cSEdward Tomasz Napierala static int xdr_dir(XDR *, char *);
25919c46d8cSEdward Tomasz Napierala static int xdr_explist(XDR *, caddr_t);
26019c46d8cSEdward Tomasz Napierala static int xdr_explist_brief(XDR *, caddr_t);
26119c46d8cSEdward Tomasz Napierala static int xdr_explist_common(XDR *, caddr_t, int);
26219c46d8cSEdward Tomasz Napierala static int xdr_fhs(XDR *, caddr_t);
26319c46d8cSEdward Tomasz Napierala static int xdr_mlist(XDR *, caddr_t);
26419c46d8cSEdward Tomasz Napierala static void terminate(int);
265cc5efddeSRick Macklem static void cp_cred(struct expcred *, struct expcred *);
2668fae3551SRodney W. Grimes
26746a6b5c4SRick Macklem #define EXPHASH(f) (fnv_32_buf((f), sizeof(fsid_t), 0) % exphashsize)
26846a6b5c4SRick Macklem static struct exportlisthead *exphead = NULL;
2690f0869bcSRick Macklem static struct exportlisthead *oldexphead = NULL;
27046a6b5c4SRick Macklem static int exphashsize = 0;
2711a9a992fSRick Macklem static SLIST_HEAD(, mountlist) mlhead = SLIST_HEAD_INITIALIZER(&mlhead);
27219c46d8cSEdward Tomasz Napierala static char *exnames_default[2] = { _PATH_EXPORTS, NULL };
27319c46d8cSEdward Tomasz Napierala static char **exnames;
27419c46d8cSEdward Tomasz Napierala static char **hosts = NULL;
27519c46d8cSEdward Tomasz Napierala static int force_v2 = 0;
276fefb7c39SRick Macklem static int warn_admin = 1;
27719c46d8cSEdward Tomasz Napierala static int resvport_only = 1;
27819c46d8cSEdward Tomasz Napierala static int nhosts = 0;
27919c46d8cSEdward Tomasz Napierala static int dir_only = 1;
28019c46d8cSEdward Tomasz Napierala static int dolog = 0;
28124092311SRick Macklem static _Atomic(int) got_sighup = 0;
28219c46d8cSEdward Tomasz Napierala static int xcreated = 0;
283d11e3645SMatteo Riondato
28419c46d8cSEdward Tomasz Napierala static char *svcport_str = NULL;
2858fb6ad5dSRick Macklem static int mallocd_svcport = 0;
2868fb6ad5dSRick Macklem static int *sock_fd;
2878fb6ad5dSRick Macklem static int sock_fdcnt;
2888fb6ad5dSRick Macklem static int sock_fdpos;
289c548eb5cSRick Macklem static int suspend_nfsd = 0;
2907c2901b0SJoyu Liao static int nofork = 0;
2917c2901b0SJoyu Liao static int skiplocalhost = 0;
2928360efbdSAlfred Perlstein
29319c46d8cSEdward Tomasz Napierala static int opt_flags;
2948360efbdSAlfred Perlstein static int have_v6 = 1;
2958360efbdSAlfred Perlstein
29619c46d8cSEdward Tomasz Napierala static int v4root_phase = 0;
29719c46d8cSEdward Tomasz Napierala static char v4root_dirpath[PATH_MAX + 1];
2980f0869bcSRick Macklem static struct exportlist *v4root_ep = NULL;
29919c46d8cSEdward Tomasz Napierala static int has_publicfh = 0;
3000f0869bcSRick Macklem static int has_set_publicfh = 0;
301bcc1d071SRick Macklem
30219c46d8cSEdward Tomasz Napierala static struct pidfh *pfh = NULL;
30360caaee2SIan Dowse /* Bits for opt_flags above */
3048fae3551SRodney W. Grimes #define OP_MAPROOT 0x01
3058fae3551SRodney W. Grimes #define OP_MAPALL 0x02
30691196234SPeter Wemm /* 0x4 free */
3078fae3551SRodney W. Grimes #define OP_MASK 0x08
3088fae3551SRodney W. Grimes #define OP_NET 0x10
3098fae3551SRodney W. Grimes #define OP_ALLDIRS 0x40
31060caaee2SIan Dowse #define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */
311288fa14aSJoerg Wunsch #define OP_QUIET 0x100
3128360efbdSAlfred Perlstein #define OP_MASKLEN 0x200
313a9148abdSDoug Rabson #define OP_SEC 0x400
31448514c57SMike Karels #define OP_CLASSMASK 0x800 /* mask not specified, is Class A/B/C default */
3158fae3551SRodney W. Grimes
3168fae3551SRodney W. Grimes #ifdef DEBUG
31719c46d8cSEdward Tomasz Napierala static int debug = 1;
31819c46d8cSEdward Tomasz Napierala static void SYSLOG(int, const char *, ...) __printflike(2, 3);
3198fae3551SRodney W. Grimes #define syslog SYSLOG
3208fae3551SRodney W. Grimes #else
32119c46d8cSEdward Tomasz Napierala static int debug = 0;
3228fae3551SRodney W. Grimes #endif
3238fae3551SRodney W. Grimes
3248fae3551SRodney W. Grimes /*
3250f0869bcSRick Macklem * The LOGDEBUG() syslog() calls are always compiled into the daemon.
3260f0869bcSRick Macklem * To enable them, create a file at _PATH_MOUNTDDEBUG. This file can be empty.
3270f0869bcSRick Macklem * To disable the logging, just delete the file at _PATH_MOUNTDDEBUG.
3280f0869bcSRick Macklem */
3290f0869bcSRick Macklem static int logdebug = 0;
3300f0869bcSRick Macklem #define LOGDEBUG(format, ...) \
3310f0869bcSRick Macklem (logdebug ? syslog(LOG_DEBUG, format, ## __VA_ARGS__) : 0)
3320f0869bcSRick Macklem
3330f0869bcSRick Macklem /*
334b875c2e9SJosh Paetzel * Similar to strsep(), but it allows for quoted strings
335b875c2e9SJosh Paetzel * and escaped characters.
336b875c2e9SJosh Paetzel *
337b875c2e9SJosh Paetzel * It returns the string (or NULL, if *stringp is NULL),
338b875c2e9SJosh Paetzel * which is a de-quoted version of the string if necessary.
339b875c2e9SJosh Paetzel *
340b875c2e9SJosh Paetzel * It modifies *stringp in place.
341b875c2e9SJosh Paetzel */
342b875c2e9SJosh Paetzel static char *
strsep_quote(char ** stringp,const char * delim)343b875c2e9SJosh Paetzel strsep_quote(char **stringp, const char *delim)
344b875c2e9SJosh Paetzel {
345b875c2e9SJosh Paetzel char *srcptr, *dstptr, *retval;
346b875c2e9SJosh Paetzel char quot = 0;
347b875c2e9SJosh Paetzel
348b875c2e9SJosh Paetzel if (stringp == NULL || *stringp == NULL)
349b875c2e9SJosh Paetzel return (NULL);
350b875c2e9SJosh Paetzel
351b875c2e9SJosh Paetzel srcptr = dstptr = retval = *stringp;
352b875c2e9SJosh Paetzel
353b875c2e9SJosh Paetzel while (*srcptr) {
354b875c2e9SJosh Paetzel /*
355b875c2e9SJosh Paetzel * We're looking for several edge cases here.
356b875c2e9SJosh Paetzel * First: if we're in quote state (quot != 0),
357b875c2e9SJosh Paetzel * then we ignore the delim characters, but otherwise
358b875c2e9SJosh Paetzel * process as normal, unless it is the quote character.
359b875c2e9SJosh Paetzel * Second: if the current character is a backslash,
360b875c2e9SJosh Paetzel * we take the next character as-is, without checking
361b875c2e9SJosh Paetzel * for delim, quote, or backslash. Exception: if the
362b875c2e9SJosh Paetzel * next character is a NUL, that's the end of the string.
363b875c2e9SJosh Paetzel * Third: if the character is a quote character, we toggle
364b875c2e9SJosh Paetzel * quote state.
365b875c2e9SJosh Paetzel * Otherwise: check the current character for NUL, or
366b875c2e9SJosh Paetzel * being in delim, and end the string if either is true.
367b875c2e9SJosh Paetzel */
368b875c2e9SJosh Paetzel if (*srcptr == '\\') {
369b875c2e9SJosh Paetzel srcptr++;
370b875c2e9SJosh Paetzel /*
371b875c2e9SJosh Paetzel * The edge case here is if the next character
372b875c2e9SJosh Paetzel * is NUL, we want to stop processing. But if
373b875c2e9SJosh Paetzel * it's not NUL, then we simply want to copy it.
374b875c2e9SJosh Paetzel */
375b875c2e9SJosh Paetzel if (*srcptr) {
376b875c2e9SJosh Paetzel *dstptr++ = *srcptr++;
377b875c2e9SJosh Paetzel }
378b875c2e9SJosh Paetzel continue;
379b875c2e9SJosh Paetzel }
380b875c2e9SJosh Paetzel if (quot == 0 && (*srcptr == '\'' || *srcptr == '"')) {
381b875c2e9SJosh Paetzel quot = *srcptr++;
382b875c2e9SJosh Paetzel continue;
383b875c2e9SJosh Paetzel }
384b875c2e9SJosh Paetzel if (quot && *srcptr == quot) {
385b875c2e9SJosh Paetzel /* End of the quoted part */
386b875c2e9SJosh Paetzel quot = 0;
387b875c2e9SJosh Paetzel srcptr++;
388b875c2e9SJosh Paetzel continue;
389b875c2e9SJosh Paetzel }
390b875c2e9SJosh Paetzel if (!quot && strchr(delim, *srcptr))
391b875c2e9SJosh Paetzel break;
392b875c2e9SJosh Paetzel *dstptr++ = *srcptr++;
393b875c2e9SJosh Paetzel }
394b875c2e9SJosh Paetzel
395b875c2e9SJosh Paetzel *stringp = (*srcptr == '\0') ? NULL : srcptr + 1;
3964ae6e084SAlexander Motin *dstptr = 0; /* Terminate the string */
397b875c2e9SJosh Paetzel return (retval);
398b875c2e9SJosh Paetzel }
399b875c2e9SJosh Paetzel
400b875c2e9SJosh Paetzel /*
4018fae3551SRodney W. Grimes * Mountd server for NFS mount protocol as described in:
4028fae3551SRodney W. Grimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A
4038fae3551SRodney W. Grimes * The optional arguments are the exports file name
4048fae3551SRodney W. Grimes * default: _PATH_EXPORTS
4058fae3551SRodney W. Grimes * and "-n" to allow nonroot mount.
4068fae3551SRodney W. Grimes */
4078fae3551SRodney W. Grimes int
main(int argc,char ** argv)408a7a7d96cSPhilippe Charnier main(int argc, char **argv)
4098fae3551SRodney W. Grimes {
41069d65572SIan Dowse fd_set readfds;
411d11e3645SMatteo Riondato struct netconfig *nconf;
412d11e3645SMatteo Riondato char *endptr, **hosts_bak;
413d11e3645SMatteo Riondato void *nc_handle;
414a032b226SPawel Jakub Dawidek pid_t otherpid;
415d11e3645SMatteo Riondato in_port_t svcport;
416d11e3645SMatteo Riondato int c, k, s;
417bcb53b16SMartin Blapp int maxrec = RPC_MAXDATASIZE;
4188fb6ad5dSRick Macklem int attempt_cnt, port_len, port_pos, ret;
4198fb6ad5dSRick Macklem char **port_list;
4207674d489SRick Macklem uint64_t curtime, nexttime;
4217674d489SRick Macklem struct timeval tv;
4227674d489SRick Macklem struct timespec tp;
423bde6f938SRick Macklem sigset_t sig_mask, sighup_mask;
424bde6f938SRick Macklem int enable_rpcbind;
4258360efbdSAlfred Perlstein
426bde6f938SRick Macklem enable_rpcbind = 1;
42701709abfSIan Dowse /* Check that another mountd isn't already running. */
4288b28aef2SPawel Jakub Dawidek pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid);
429a032b226SPawel Jakub Dawidek if (pfh == NULL) {
430a032b226SPawel Jakub Dawidek if (errno == EEXIST)
431a032b226SPawel Jakub Dawidek errx(1, "mountd already running, pid: %d.", otherpid);
432a032b226SPawel Jakub Dawidek warn("cannot open or create pidfile");
433a032b226SPawel Jakub Dawidek }
4348360efbdSAlfred Perlstein
4358360efbdSAlfred Perlstein s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
4368360efbdSAlfred Perlstein if (s < 0)
4378360efbdSAlfred Perlstein have_v6 = 0;
4388360efbdSAlfred Perlstein else
4398360efbdSAlfred Perlstein close(s);
4408fae3551SRodney W. Grimes
4417c2901b0SJoyu Liao while ((c = getopt(argc, argv, "2Adeh:lNnp:RrSs")) != -1)
4428fae3551SRodney W. Grimes switch (c) {
4432a66cfc5SDoug Rabson case '2':
4442a66cfc5SDoug Rabson force_v2 = 1;
4452a66cfc5SDoug Rabson break;
446fefb7c39SRick Macklem case 'A':
447fefb7c39SRick Macklem warn_admin = 0;
448fefb7c39SRick Macklem break;
4492179ae1eSRick Macklem case 'e':
4502a85df8cSRick Macklem /* now a no-op, since this is the default */
451bcc1d071SRick Macklem break;
452a62dc406SDoug Rabson case 'n':
453a62dc406SDoug Rabson resvport_only = 0;
454a62dc406SDoug Rabson break;
455bde6f938SRick Macklem case 'R':
456bde6f938SRick Macklem /* Do not support Mount protocol */
457bde6f938SRick Macklem enable_rpcbind = 0;
458bde6f938SRick Macklem break;
459a62dc406SDoug Rabson case 'r':
460a62dc406SDoug Rabson dir_only = 0;
461a62dc406SDoug Rabson break;
4626444ef3bSPoul-Henning Kamp case 'd':
4636444ef3bSPoul-Henning Kamp debug = debug ? 0 : 1;
4646444ef3bSPoul-Henning Kamp break;
465f51631d7SGuido van Rooij case 'l':
466c903443aSPeter Wemm dolog = 1;
467f51631d7SGuido van Rooij break;
468c203da27SBruce M Simpson case 'p':
469c203da27SBruce M Simpson endptr = NULL;
470c203da27SBruce M Simpson svcport = (in_port_t)strtoul(optarg, &endptr, 10);
471c203da27SBruce M Simpson if (endptr == NULL || *endptr != '\0' ||
472c203da27SBruce M Simpson svcport == 0 || svcport >= IPPORT_MAX)
473c203da27SBruce M Simpson usage();
474d11e3645SMatteo Riondato svcport_str = strdup(optarg);
475d11e3645SMatteo Riondato break;
476d11e3645SMatteo Riondato case 'h':
477d11e3645SMatteo Riondato ++nhosts;
478d11e3645SMatteo Riondato hosts_bak = hosts;
479d11e3645SMatteo Riondato hosts_bak = realloc(hosts, nhosts * sizeof(char *));
480d11e3645SMatteo Riondato if (hosts_bak == NULL) {
481d11e3645SMatteo Riondato if (hosts != NULL) {
482d11e3645SMatteo Riondato for (k = 0; k < nhosts; k++)
483d11e3645SMatteo Riondato free(hosts[k]);
484d11e3645SMatteo Riondato free(hosts);
485d11e3645SMatteo Riondato out_of_mem();
486d11e3645SMatteo Riondato }
487d11e3645SMatteo Riondato }
488d11e3645SMatteo Riondato hosts = hosts_bak;
489d11e3645SMatteo Riondato hosts[nhosts - 1] = strdup(optarg);
490d11e3645SMatteo Riondato if (hosts[nhosts - 1] == NULL) {
491d11e3645SMatteo Riondato for (k = 0; k < (nhosts - 1); k++)
492d11e3645SMatteo Riondato free(hosts[k]);
493d11e3645SMatteo Riondato free(hosts);
494d11e3645SMatteo Riondato out_of_mem();
495d11e3645SMatteo Riondato }
496c203da27SBruce M Simpson break;
497c548eb5cSRick Macklem case 'S':
498c548eb5cSRick Macklem suspend_nfsd = 1;
499c548eb5cSRick Macklem break;
5007c2901b0SJoyu Liao case 'N':
5017c2901b0SJoyu Liao nofork = 1;
5027c2901b0SJoyu Liao break;
5037c2901b0SJoyu Liao case 's':
5047c2901b0SJoyu Liao skiplocalhost = 1;
5057c2901b0SJoyu Liao break;
5068fae3551SRodney W. Grimes default:
50774853402SPhilippe Charnier usage();
50880c7cc1cSPedro F. Giffuni }
509bde6f938SRick Macklem if (enable_rpcbind == 0) {
510bde6f938SRick Macklem if (svcport_str != NULL) {
511bde6f938SRick Macklem warnx("-p option not compatible with -R, ignored");
512bde6f938SRick Macklem free(svcport_str);
513bde6f938SRick Macklem svcport_str = NULL;
514bde6f938SRick Macklem }
515bde6f938SRick Macklem if (nhosts > 0) {
516bde6f938SRick Macklem warnx("-h option not compatible with -R, ignored");
517bde6f938SRick Macklem for (k = 0; k < nhosts; k++)
518bde6f938SRick Macklem free(hosts[k]);
519bde6f938SRick Macklem free(hosts);
520bde6f938SRick Macklem hosts = NULL;
521bde6f938SRick Macklem nhosts = 0;
522bde6f938SRick Macklem }
523bde6f938SRick Macklem }
524bcc1d071SRick Macklem
5257c2901b0SJoyu Liao if (nhosts == 0 && skiplocalhost != 0)
5267c2901b0SJoyu Liao warnx("-s without -h, ignored");
5277c2901b0SJoyu Liao
528bcc1d071SRick Macklem if (modfind("nfsd") < 0) {
529bcc1d071SRick Macklem /* Not present in kernel, try loading it */
530bcc1d071SRick Macklem if (kldload("nfsd") < 0 || modfind("nfsd") < 0)
531bcc1d071SRick Macklem errx(1, "NFS server is not available");
532bcc1d071SRick Macklem }
533bcc1d071SRick Macklem
5348fae3551SRodney W. Grimes argc -= optind;
5358fae3551SRodney W. Grimes argv += optind;
53696968c22SPawel Jakub Dawidek if (argc > 0)
53796968c22SPawel Jakub Dawidek exnames = argv;
53896968c22SPawel Jakub Dawidek else
53996968c22SPawel Jakub Dawidek exnames = exnames_default;
5408fae3551SRodney W. Grimes openlog("mountd", LOG_PID, LOG_DAEMON);
5418fae3551SRodney W. Grimes if (debug)
54274853402SPhilippe Charnier warnx("getting export list");
5430f0869bcSRick Macklem get_exportlist(0);
5448fae3551SRodney W. Grimes if (debug)
54574853402SPhilippe Charnier warnx("getting mount list");
5468fae3551SRodney W. Grimes get_mountlist();
5478fae3551SRodney W. Grimes if (debug)
54874853402SPhilippe Charnier warnx("here we go");
5497c2901b0SJoyu Liao if (debug == 0 && nofork == 0) {
5508fae3551SRodney W. Grimes daemon(0, 0);
5518fae3551SRodney W. Grimes signal(SIGINT, SIG_IGN);
5528fae3551SRodney W. Grimes signal(SIGQUIT, SIG_IGN);
5538fae3551SRodney W. Grimes }
55469d65572SIan Dowse signal(SIGHUP, huphandler);
5558360efbdSAlfred Perlstein signal(SIGTERM, terminate);
55609fc9dc6SCraig Rodrigues signal(SIGPIPE, SIG_IGN);
557a032b226SPawel Jakub Dawidek
558a032b226SPawel Jakub Dawidek pidfile_write(pfh);
559a032b226SPawel Jakub Dawidek
560bde6f938SRick Macklem if (enable_rpcbind != 0) {
5610775314bSDoug Rabson rpcb_unset(MOUNTPROG, MOUNTVERS, NULL);
5620775314bSDoug Rabson rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL);
563bcb53b16SMartin Blapp rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
564bcb53b16SMartin Blapp
565c6e5e158SGuido van Rooij if (!resvport_only) {
5665ebee88dSRick Macklem if (sysctlbyname("vfs.nfsd.nfs_privport", NULL, NULL,
5674a0785aaSPeter Wemm &resvport_only, sizeof(resvport_only)) != 0 &&
5684a0785aaSPeter Wemm errno != ENOENT) {
569394da4c1SGuido van Rooij syslog(LOG_ERR, "sysctl: %m");
570394da4c1SGuido van Rooij exit(1);
571394da4c1SGuido van Rooij }
572c6e5e158SGuido van Rooij }
573c203da27SBruce M Simpson
574d11e3645SMatteo Riondato /*
575d11e3645SMatteo Riondato * If no hosts were specified, add a wildcard entry to bind to
576bde6f938SRick Macklem * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added
577bde6f938SRick Macklem * to the list.
578d11e3645SMatteo Riondato */
579d11e3645SMatteo Riondato if (nhosts == 0) {
580c9e1c304SUlrich Spörlein hosts = malloc(sizeof(char *));
581d11e3645SMatteo Riondato if (hosts == NULL)
582d11e3645SMatteo Riondato out_of_mem();
583d11e3645SMatteo Riondato hosts[0] = "*";
584d11e3645SMatteo Riondato nhosts = 1;
5857c2901b0SJoyu Liao } else if (skiplocalhost == 0) {
586d11e3645SMatteo Riondato hosts_bak = hosts;
587d11e3645SMatteo Riondato if (have_v6) {
588d11e3645SMatteo Riondato hosts_bak = realloc(hosts, (nhosts + 2) *
589d11e3645SMatteo Riondato sizeof(char *));
590d11e3645SMatteo Riondato if (hosts_bak == NULL) {
591d11e3645SMatteo Riondato for (k = 0; k < nhosts; k++)
592d11e3645SMatteo Riondato free(hosts[k]);
593d11e3645SMatteo Riondato free(hosts);
594d11e3645SMatteo Riondato out_of_mem();
595c203da27SBruce M Simpson } else
596d11e3645SMatteo Riondato hosts = hosts_bak;
597d11e3645SMatteo Riondato nhosts += 2;
598d11e3645SMatteo Riondato hosts[nhosts - 2] = "::1";
599d11e3645SMatteo Riondato } else {
600bde6f938SRick Macklem hosts_bak = realloc(hosts, (nhosts + 1) *
601bde6f938SRick Macklem sizeof(char *));
602d11e3645SMatteo Riondato if (hosts_bak == NULL) {
603d11e3645SMatteo Riondato for (k = 0; k < nhosts; k++)
604d11e3645SMatteo Riondato free(hosts[k]);
605d11e3645SMatteo Riondato free(hosts);
606d11e3645SMatteo Riondato out_of_mem();
607d11e3645SMatteo Riondato } else {
608d11e3645SMatteo Riondato nhosts += 1;
609d11e3645SMatteo Riondato hosts = hosts_bak;
6108fae3551SRodney W. Grimes }
611d11e3645SMatteo Riondato }
6128360efbdSAlfred Perlstein
613d11e3645SMatteo Riondato hosts[nhosts - 1] = "127.0.0.1";
6148360efbdSAlfred Perlstein }
615bde6f938SRick Macklem }
6168360efbdSAlfred Perlstein
6178fb6ad5dSRick Macklem attempt_cnt = 1;
6188fb6ad5dSRick Macklem sock_fdcnt = 0;
6198fb6ad5dSRick Macklem sock_fd = NULL;
6208fb6ad5dSRick Macklem port_list = NULL;
6218fb6ad5dSRick Macklem port_len = 0;
622bde6f938SRick Macklem if (enable_rpcbind != 0) {
623d11e3645SMatteo Riondato nc_handle = setnetconfig();
624d11e3645SMatteo Riondato while ((nconf = getnetconfig(nc_handle))) {
625d11e3645SMatteo Riondato if (nconf->nc_flag & NC_VISIBLE) {
626d11e3645SMatteo Riondato if (have_v6 == 0 && strcmp(nconf->nc_protofmly,
627d11e3645SMatteo Riondato "inet6") == 0) {
628d11e3645SMatteo Riondato /* DO NOTHING */
6298fb6ad5dSRick Macklem } else {
6308fb6ad5dSRick Macklem ret = create_service(nconf);
6318fb6ad5dSRick Macklem if (ret == 1)
6328fb6ad5dSRick Macklem /* Ignore this call */
6338fb6ad5dSRick Macklem continue;
6348fb6ad5dSRick Macklem if (ret < 0) {
6358fb6ad5dSRick Macklem /*
636bde6f938SRick Macklem * Failed to bind port, so close
637bde6f938SRick Macklem * off all sockets created and
638bde6f938SRick Macklem * try again if the port# was
639bde6f938SRick Macklem * dynamically assigned via
640bde6f938SRick Macklem * bind(2).
6418fb6ad5dSRick Macklem */
6428fb6ad5dSRick Macklem clearout_service();
6438fb6ad5dSRick Macklem if (mallocd_svcport != 0 &&
644bde6f938SRick Macklem attempt_cnt <
645bde6f938SRick Macklem GETPORT_MAXTRY) {
6468fb6ad5dSRick Macklem free(svcport_str);
6478fb6ad5dSRick Macklem svcport_str = NULL;
6488fb6ad5dSRick Macklem mallocd_svcport = 0;
6498fb6ad5dSRick Macklem } else {
6508fb6ad5dSRick Macklem errno = EADDRINUSE;
6518fb6ad5dSRick Macklem syslog(LOG_ERR,
652bde6f938SRick Macklem "bindresvport_sa:"
653bde6f938SRick Macklem " %m");
6548fb6ad5dSRick Macklem exit(1);
6558fb6ad5dSRick Macklem }
6568fb6ad5dSRick Macklem
657bde6f938SRick Macklem /*
658bde6f938SRick Macklem * Start over at the first
659bde6f938SRick Macklem * service.
660bde6f938SRick Macklem */
6618fb6ad5dSRick Macklem free(sock_fd);
6628fb6ad5dSRick Macklem sock_fdcnt = 0;
6638fb6ad5dSRick Macklem sock_fd = NULL;
6648fb6ad5dSRick Macklem nc_handle = setnetconfig();
6658fb6ad5dSRick Macklem attempt_cnt++;
6668fb6ad5dSRick Macklem } else if (mallocd_svcport != 0 &&
6678fb6ad5dSRick Macklem attempt_cnt == GETPORT_MAXTRY) {
6688fb6ad5dSRick Macklem /*
6698fb6ad5dSRick Macklem * For the last attempt, allow
670bde6f938SRick Macklem * different port #s for each
671bde6f938SRick Macklem * nconf by saving the
672bde6f938SRick Macklem * svcport_str setting it back
673bde6f938SRick Macklem * to NULL.
6748fb6ad5dSRick Macklem */
6758fb6ad5dSRick Macklem port_list = realloc(port_list,
676bde6f938SRick Macklem (port_len + 1) *
677bde6f938SRick Macklem sizeof(char *));
6788fb6ad5dSRick Macklem if (port_list == NULL)
6798fb6ad5dSRick Macklem out_of_mem();
680bde6f938SRick Macklem port_list[port_len++] =
681bde6f938SRick Macklem svcport_str;
6828fb6ad5dSRick Macklem svcport_str = NULL;
6838fb6ad5dSRick Macklem mallocd_svcport = 0;
6848fb6ad5dSRick Macklem }
6858fb6ad5dSRick Macklem }
6868fb6ad5dSRick Macklem }
6878fb6ad5dSRick Macklem }
6888fb6ad5dSRick Macklem
6898fb6ad5dSRick Macklem /*
6908fb6ad5dSRick Macklem * Successfully bound the ports, so call complete_service() to
6918fb6ad5dSRick Macklem * do the rest of the setup on the service(s).
6928fb6ad5dSRick Macklem */
6938fb6ad5dSRick Macklem sock_fdpos = 0;
6948fb6ad5dSRick Macklem port_pos = 0;
6958fb6ad5dSRick Macklem nc_handle = setnetconfig();
6968fb6ad5dSRick Macklem while ((nconf = getnetconfig(nc_handle))) {
6978fb6ad5dSRick Macklem if (nconf->nc_flag & NC_VISIBLE) {
6988fb6ad5dSRick Macklem if (have_v6 == 0 && strcmp(nconf->nc_protofmly,
6998fb6ad5dSRick Macklem "inet6") == 0) {
7008fb6ad5dSRick Macklem /* DO NOTHING */
7018fb6ad5dSRick Macklem } else if (port_list != NULL) {
7028fb6ad5dSRick Macklem if (port_pos >= port_len) {
703bde6f938SRick Macklem syslog(LOG_ERR, "too many"
704bde6f938SRick Macklem " port#s");
7058fb6ad5dSRick Macklem exit(1);
7068fb6ad5dSRick Macklem }
707bde6f938SRick Macklem complete_service(nconf,
708bde6f938SRick Macklem port_list[port_pos++]);
709c203da27SBruce M Simpson } else
7108fb6ad5dSRick Macklem complete_service(nconf, svcport_str);
7118360efbdSAlfred Perlstein }
712d11e3645SMatteo Riondato }
713d11e3645SMatteo Riondato endnetconfig(nc_handle);
7148fb6ad5dSRick Macklem free(sock_fd);
7158fb6ad5dSRick Macklem if (port_list != NULL) {
7168fb6ad5dSRick Macklem for (port_pos = 0; port_pos < port_len; port_pos++)
7178fb6ad5dSRick Macklem free(port_list[port_pos]);
7188fb6ad5dSRick Macklem free(port_list);
7198fb6ad5dSRick Macklem }
7208360efbdSAlfred Perlstein
7218360efbdSAlfred Perlstein if (xcreated == 0) {
7228360efbdSAlfred Perlstein syslog(LOG_ERR, "could not create any services");
7232a66cfc5SDoug Rabson exit(1);
7242a66cfc5SDoug Rabson }
725bde6f938SRick Macklem }
72669d65572SIan Dowse
72769d65572SIan Dowse /* Expand svc_run() here so that we can call get_exportlist(). */
7287674d489SRick Macklem curtime = nexttime = 0;
7297674d489SRick Macklem sigemptyset(&sighup_mask);
7307674d489SRick Macklem sigaddset(&sighup_mask, SIGHUP);
73169d65572SIan Dowse for (;;) {
7327674d489SRick Macklem clock_gettime(CLOCK_MONOTONIC, &tp);
7337674d489SRick Macklem curtime = tp.tv_sec;
7347674d489SRick Macklem curtime = curtime * 1000000 + tp.tv_nsec / 1000;
735bde6f938SRick Macklem sigprocmask(SIG_BLOCK, &sighup_mask, &sig_mask);
7367674d489SRick Macklem if (got_sighup && curtime >= nexttime) {
73769d65572SIan Dowse got_sighup = 0;
7387674d489SRick Macklem sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
7397674d489SRick Macklem get_exportlist(1);
7407674d489SRick Macklem clock_gettime(CLOCK_MONOTONIC, &tp);
7417674d489SRick Macklem nexttime = tp.tv_sec;
7427674d489SRick Macklem nexttime = nexttime * 1000000 + tp.tv_nsec / 1000 +
7437674d489SRick Macklem RELOADDELAY;
7447674d489SRick Macklem } else
7457674d489SRick Macklem sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
7467674d489SRick Macklem
7477674d489SRick Macklem /*
7487674d489SRick Macklem * If a reload is pending, poll for received request(s),
7497674d489SRick Macklem * otherwise set a RELOADDELAY timeout, since a SIGHUP
7507674d489SRick Macklem * could be processed between the got_sighup test and
7517674d489SRick Macklem * the select() system call.
7527674d489SRick Macklem */
7537674d489SRick Macklem tv.tv_sec = 0;
7547674d489SRick Macklem if (got_sighup)
7557674d489SRick Macklem tv.tv_usec = 0;
7567674d489SRick Macklem else
7577674d489SRick Macklem tv.tv_usec = RELOADDELAY;
758bde6f938SRick Macklem if (enable_rpcbind != 0) {
75969d65572SIan Dowse readfds = svc_fdset;
760bde6f938SRick Macklem switch (select(svc_maxfd + 1, &readfds, NULL, NULL,
761bde6f938SRick Macklem &tv)) {
76269d65572SIan Dowse case -1:
7637674d489SRick Macklem if (errno == EINTR) {
7647674d489SRick Macklem /* Allow a reload now. */
7657674d489SRick Macklem nexttime = 0;
76669d65572SIan Dowse continue;
7677674d489SRick Macklem }
76869d65572SIan Dowse syslog(LOG_ERR, "mountd died: select: %m");
76974853402SPhilippe Charnier exit(1);
77069d65572SIan Dowse case 0:
7717674d489SRick Macklem /* Allow a reload now. */
7727674d489SRick Macklem nexttime = 0;
77369d65572SIan Dowse continue;
77469d65572SIan Dowse default:
77569d65572SIan Dowse svc_getreqset(&readfds);
77669d65572SIan Dowse }
777bde6f938SRick Macklem } else {
778bde6f938SRick Macklem /* Simply wait for a signal. */
779bde6f938SRick Macklem sigsuspend(&sig_mask);
780bde6f938SRick Macklem }
78169d65572SIan Dowse }
78274853402SPhilippe Charnier }
78374853402SPhilippe Charnier
784d11e3645SMatteo Riondato /*
785d11e3645SMatteo Riondato * This routine creates and binds sockets on the appropriate
7868fb6ad5dSRick Macklem * addresses. It gets called one time for each transport.
787afc55510SGordon Bergling * It returns 0 upon success, 1 for ignore the call and -1 to indicate
7888fb6ad5dSRick Macklem * bind failed with EADDRINUSE.
7898fb6ad5dSRick Macklem * Any file descriptors that have been created are stored in sock_fd and
7908fb6ad5dSRick Macklem * the total count of them is maintained in sock_fdcnt.
791d11e3645SMatteo Riondato */
7928fb6ad5dSRick Macklem static int
create_service(struct netconfig * nconf)793d11e3645SMatteo Riondato create_service(struct netconfig *nconf)
794d11e3645SMatteo Riondato {
795d11e3645SMatteo Riondato struct addrinfo hints, *res = NULL;
796d11e3645SMatteo Riondato struct sockaddr_in *sin;
797d11e3645SMatteo Riondato struct sockaddr_in6 *sin6;
798d11e3645SMatteo Riondato struct __rpc_sockinfo si;
799d11e3645SMatteo Riondato int aicode;
800d11e3645SMatteo Riondato int fd;
801d11e3645SMatteo Riondato int nhostsbak;
802d11e3645SMatteo Riondato int one = 1;
803d11e3645SMatteo Riondato int r;
804d11e3645SMatteo Riondato u_int32_t host_addr[4]; /* IPv4 or IPv6 */
8058fb6ad5dSRick Macklem int mallocd_res;
806d11e3645SMatteo Riondato
807d11e3645SMatteo Riondato if ((nconf->nc_semantics != NC_TPI_CLTS) &&
808d11e3645SMatteo Riondato (nconf->nc_semantics != NC_TPI_COTS) &&
809d11e3645SMatteo Riondato (nconf->nc_semantics != NC_TPI_COTS_ORD))
8108fb6ad5dSRick Macklem return (1); /* not my type */
811d11e3645SMatteo Riondato
812d11e3645SMatteo Riondato /*
813d11e3645SMatteo Riondato * XXX - using RPC library internal functions.
814d11e3645SMatteo Riondato */
815d11e3645SMatteo Riondato if (!__rpc_nconf2sockinfo(nconf, &si)) {
816d11e3645SMatteo Riondato syslog(LOG_ERR, "cannot get information for %s",
817d11e3645SMatteo Riondato nconf->nc_netid);
8188fb6ad5dSRick Macklem return (1);
819d11e3645SMatteo Riondato }
820d11e3645SMatteo Riondato
821d11e3645SMatteo Riondato /* Get mountd's address on this transport */
822d11e3645SMatteo Riondato memset(&hints, 0, sizeof hints);
823d11e3645SMatteo Riondato hints.ai_family = si.si_af;
824d11e3645SMatteo Riondato hints.ai_socktype = si.si_socktype;
825d11e3645SMatteo Riondato hints.ai_protocol = si.si_proto;
826d11e3645SMatteo Riondato
827d11e3645SMatteo Riondato /*
828d11e3645SMatteo Riondato * Bind to specific IPs if asked to
829d11e3645SMatteo Riondato */
830d11e3645SMatteo Riondato nhostsbak = nhosts;
831d11e3645SMatteo Riondato while (nhostsbak > 0) {
832d11e3645SMatteo Riondato --nhostsbak;
8338fb6ad5dSRick Macklem sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int));
8348fb6ad5dSRick Macklem if (sock_fd == NULL)
8358fb6ad5dSRick Macklem out_of_mem();
8368fb6ad5dSRick Macklem sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */
8378fb6ad5dSRick Macklem mallocd_res = 0;
8388fb6ad5dSRick Macklem
8399745de4cSRyan Stone hints.ai_flags = AI_PASSIVE;
8409745de4cSRyan Stone
841d11e3645SMatteo Riondato /*
842d11e3645SMatteo Riondato * XXX - using RPC library internal functions.
843d11e3645SMatteo Riondato */
844d11e3645SMatteo Riondato if ((fd = __rpc_nconf2fd(nconf)) < 0) {
845d11e3645SMatteo Riondato int non_fatal = 0;
846a5752d55SKevin Lo if (errno == EAFNOSUPPORT &&
847d11e3645SMatteo Riondato nconf->nc_semantics != NC_TPI_CLTS)
848d11e3645SMatteo Riondato non_fatal = 1;
849d11e3645SMatteo Riondato
850d11e3645SMatteo Riondato syslog(non_fatal ? LOG_DEBUG : LOG_ERR,
851d11e3645SMatteo Riondato "cannot create socket for %s", nconf->nc_netid);
8528fb6ad5dSRick Macklem if (non_fatal != 0)
8538fb6ad5dSRick Macklem continue;
8548fb6ad5dSRick Macklem exit(1);
855d11e3645SMatteo Riondato }
856d11e3645SMatteo Riondato
857d11e3645SMatteo Riondato switch (hints.ai_family) {
858d11e3645SMatteo Riondato case AF_INET:
859d11e3645SMatteo Riondato if (inet_pton(AF_INET, hosts[nhostsbak],
860d11e3645SMatteo Riondato host_addr) == 1) {
8618fb6ad5dSRick Macklem hints.ai_flags |= AI_NUMERICHOST;
862d11e3645SMatteo Riondato } else {
863d11e3645SMatteo Riondato /*
864d11e3645SMatteo Riondato * Skip if we have an AF_INET6 address.
865d11e3645SMatteo Riondato */
866d11e3645SMatteo Riondato if (inet_pton(AF_INET6, hosts[nhostsbak],
867d11e3645SMatteo Riondato host_addr) == 1) {
868d11e3645SMatteo Riondato close(fd);
869d11e3645SMatteo Riondato continue;
870d11e3645SMatteo Riondato }
871d11e3645SMatteo Riondato }
872d11e3645SMatteo Riondato break;
873d11e3645SMatteo Riondato case AF_INET6:
874d11e3645SMatteo Riondato if (inet_pton(AF_INET6, hosts[nhostsbak],
875d11e3645SMatteo Riondato host_addr) == 1) {
8768fb6ad5dSRick Macklem hints.ai_flags |= AI_NUMERICHOST;
877d11e3645SMatteo Riondato } else {
878d11e3645SMatteo Riondato /*
879d11e3645SMatteo Riondato * Skip if we have an AF_INET address.
880d11e3645SMatteo Riondato */
881d11e3645SMatteo Riondato if (inet_pton(AF_INET, hosts[nhostsbak],
882d11e3645SMatteo Riondato host_addr) == 1) {
883d11e3645SMatteo Riondato close(fd);
884d11e3645SMatteo Riondato continue;
885d11e3645SMatteo Riondato }
886d11e3645SMatteo Riondato }
887d11e3645SMatteo Riondato
888d11e3645SMatteo Riondato /*
889d11e3645SMatteo Riondato * We're doing host-based access checks here, so don't
890d11e3645SMatteo Riondato * allow v4-in-v6 to confuse things. The kernel will
891d11e3645SMatteo Riondato * disable it by default on NFS sockets too.
892d11e3645SMatteo Riondato */
893d11e3645SMatteo Riondato if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one,
894d11e3645SMatteo Riondato sizeof one) < 0) {
895d11e3645SMatteo Riondato syslog(LOG_ERR,
896d11e3645SMatteo Riondato "can't disable v4-in-v6 on IPv6 socket");
897d11e3645SMatteo Riondato exit(1);
898d11e3645SMatteo Riondato }
899d11e3645SMatteo Riondato break;
900d11e3645SMatteo Riondato default:
901d11e3645SMatteo Riondato break;
902d11e3645SMatteo Riondato }
903d11e3645SMatteo Riondato
904d11e3645SMatteo Riondato /*
905d11e3645SMatteo Riondato * If no hosts were specified, just bind to INADDR_ANY
906d11e3645SMatteo Riondato */
907d11e3645SMatteo Riondato if (strcmp("*", hosts[nhostsbak]) == 0) {
908d11e3645SMatteo Riondato if (svcport_str == NULL) {
909d11e3645SMatteo Riondato res = malloc(sizeof(struct addrinfo));
910d11e3645SMatteo Riondato if (res == NULL)
911d11e3645SMatteo Riondato out_of_mem();
9128fb6ad5dSRick Macklem mallocd_res = 1;
913d11e3645SMatteo Riondato res->ai_flags = hints.ai_flags;
914d11e3645SMatteo Riondato res->ai_family = hints.ai_family;
915d11e3645SMatteo Riondato res->ai_protocol = hints.ai_protocol;
916d11e3645SMatteo Riondato switch (res->ai_family) {
917d11e3645SMatteo Riondato case AF_INET:
918d11e3645SMatteo Riondato sin = malloc(sizeof(struct sockaddr_in));
919d11e3645SMatteo Riondato if (sin == NULL)
920d11e3645SMatteo Riondato out_of_mem();
921d11e3645SMatteo Riondato sin->sin_family = AF_INET;
922d11e3645SMatteo Riondato sin->sin_port = htons(0);
923d11e3645SMatteo Riondato sin->sin_addr.s_addr = htonl(INADDR_ANY);
924d11e3645SMatteo Riondato res->ai_addr = (struct sockaddr*) sin;
925d11e3645SMatteo Riondato res->ai_addrlen = (socklen_t)
9268fb6ad5dSRick Macklem sizeof(struct sockaddr_in);
927d11e3645SMatteo Riondato break;
928d11e3645SMatteo Riondato case AF_INET6:
929d11e3645SMatteo Riondato sin6 = malloc(sizeof(struct sockaddr_in6));
93089ca9145SSimon L. B. Nielsen if (sin6 == NULL)
931d11e3645SMatteo Riondato out_of_mem();
932d11e3645SMatteo Riondato sin6->sin6_family = AF_INET6;
933d11e3645SMatteo Riondato sin6->sin6_port = htons(0);
934d11e3645SMatteo Riondato sin6->sin6_addr = in6addr_any;
935d11e3645SMatteo Riondato res->ai_addr = (struct sockaddr*) sin6;
936d11e3645SMatteo Riondato res->ai_addrlen = (socklen_t)
9378fb6ad5dSRick Macklem sizeof(struct sockaddr_in6);
938d11e3645SMatteo Riondato break;
939d11e3645SMatteo Riondato default:
9408fb6ad5dSRick Macklem syslog(LOG_ERR, "bad addr fam %d",
9418fb6ad5dSRick Macklem res->ai_family);
9428fb6ad5dSRick Macklem exit(1);
943d11e3645SMatteo Riondato }
944d11e3645SMatteo Riondato } else {
945d11e3645SMatteo Riondato if ((aicode = getaddrinfo(NULL, svcport_str,
946d11e3645SMatteo Riondato &hints, &res)) != 0) {
947d11e3645SMatteo Riondato syslog(LOG_ERR,
948d11e3645SMatteo Riondato "cannot get local address for %s: %s",
949d11e3645SMatteo Riondato nconf->nc_netid,
950d11e3645SMatteo Riondato gai_strerror(aicode));
9518fb6ad5dSRick Macklem close(fd);
952d11e3645SMatteo Riondato continue;
953d11e3645SMatteo Riondato }
954d11e3645SMatteo Riondato }
955d11e3645SMatteo Riondato } else {
956d11e3645SMatteo Riondato if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
957d11e3645SMatteo Riondato &hints, &res)) != 0) {
958d11e3645SMatteo Riondato syslog(LOG_ERR,
959d11e3645SMatteo Riondato "cannot get local address for %s: %s",
960d11e3645SMatteo Riondato nconf->nc_netid, gai_strerror(aicode));
9618fb6ad5dSRick Macklem close(fd);
962d11e3645SMatteo Riondato continue;
963d11e3645SMatteo Riondato }
964d11e3645SMatteo Riondato }
965d11e3645SMatteo Riondato
9668fb6ad5dSRick Macklem /* Store the fd. */
9678fb6ad5dSRick Macklem sock_fd[sock_fdcnt - 1] = fd;
9688fb6ad5dSRick Macklem
9698fb6ad5dSRick Macklem /* Now, attempt the bind. */
970d11e3645SMatteo Riondato r = bindresvport_sa(fd, res->ai_addr);
971d11e3645SMatteo Riondato if (r != 0) {
9728fb6ad5dSRick Macklem if (errno == EADDRINUSE && mallocd_svcport != 0) {
9738fb6ad5dSRick Macklem if (mallocd_res != 0) {
9748fb6ad5dSRick Macklem free(res->ai_addr);
9758fb6ad5dSRick Macklem free(res);
9768fb6ad5dSRick Macklem } else
9778fb6ad5dSRick Macklem freeaddrinfo(res);
9788fb6ad5dSRick Macklem return (-1);
9798fb6ad5dSRick Macklem }
980d11e3645SMatteo Riondato syslog(LOG_ERR, "bindresvport_sa: %m");
981d11e3645SMatteo Riondato exit(1);
982d11e3645SMatteo Riondato }
983d11e3645SMatteo Riondato
9848fb6ad5dSRick Macklem if (svcport_str == NULL) {
9858fb6ad5dSRick Macklem svcport_str = malloc(NI_MAXSERV * sizeof(char));
9868fb6ad5dSRick Macklem if (svcport_str == NULL)
9878fb6ad5dSRick Macklem out_of_mem();
9888fb6ad5dSRick Macklem mallocd_svcport = 1;
9898fb6ad5dSRick Macklem
9908fb6ad5dSRick Macklem if (getnameinfo(res->ai_addr,
9918fb6ad5dSRick Macklem res->ai_addr->sa_len, NULL, NI_MAXHOST,
9928fb6ad5dSRick Macklem svcport_str, NI_MAXSERV * sizeof(char),
9938fb6ad5dSRick Macklem NI_NUMERICHOST | NI_NUMERICSERV))
9948fb6ad5dSRick Macklem errx(1, "Cannot get port number");
9958fb6ad5dSRick Macklem }
9968fb6ad5dSRick Macklem if (mallocd_res != 0) {
9978fb6ad5dSRick Macklem free(res->ai_addr);
9988fb6ad5dSRick Macklem free(res);
9998fb6ad5dSRick Macklem } else
10008fb6ad5dSRick Macklem freeaddrinfo(res);
10018fb6ad5dSRick Macklem res = NULL;
10028fb6ad5dSRick Macklem }
10038fb6ad5dSRick Macklem return (0);
10048fb6ad5dSRick Macklem }
10058fb6ad5dSRick Macklem
10068fb6ad5dSRick Macklem /*
10078fb6ad5dSRick Macklem * Called after all the create_service() calls have succeeded, to complete
10088fb6ad5dSRick Macklem * the setup and registration.
10098fb6ad5dSRick Macklem */
10108fb6ad5dSRick Macklem static void
complete_service(struct netconfig * nconf,char * port_str)10118fb6ad5dSRick Macklem complete_service(struct netconfig *nconf, char *port_str)
10128fb6ad5dSRick Macklem {
10138fb6ad5dSRick Macklem struct addrinfo hints, *res = NULL;
10148fb6ad5dSRick Macklem struct __rpc_sockinfo si;
10158fb6ad5dSRick Macklem struct netbuf servaddr;
10168fb6ad5dSRick Macklem SVCXPRT *transp = NULL;
10178fb6ad5dSRick Macklem int aicode, fd, nhostsbak;
10188fb6ad5dSRick Macklem int registered = 0;
10198fb6ad5dSRick Macklem
10208fb6ad5dSRick Macklem if ((nconf->nc_semantics != NC_TPI_CLTS) &&
10218fb6ad5dSRick Macklem (nconf->nc_semantics != NC_TPI_COTS) &&
10228fb6ad5dSRick Macklem (nconf->nc_semantics != NC_TPI_COTS_ORD))
10238fb6ad5dSRick Macklem return; /* not my type */
10248fb6ad5dSRick Macklem
10258fb6ad5dSRick Macklem /*
10268fb6ad5dSRick Macklem * XXX - using RPC library internal functions.
10278fb6ad5dSRick Macklem */
10288fb6ad5dSRick Macklem if (!__rpc_nconf2sockinfo(nconf, &si)) {
10298fb6ad5dSRick Macklem syslog(LOG_ERR, "cannot get information for %s",
10308fb6ad5dSRick Macklem nconf->nc_netid);
10318fb6ad5dSRick Macklem return;
10328fb6ad5dSRick Macklem }
10338fb6ad5dSRick Macklem
10348fb6ad5dSRick Macklem nhostsbak = nhosts;
10358fb6ad5dSRick Macklem while (nhostsbak > 0) {
10368fb6ad5dSRick Macklem --nhostsbak;
10378fb6ad5dSRick Macklem if (sock_fdpos >= sock_fdcnt) {
10388fb6ad5dSRick Macklem /* Should never happen. */
10398fb6ad5dSRick Macklem syslog(LOG_ERR, "Ran out of socket fd's");
10408fb6ad5dSRick Macklem return;
10418fb6ad5dSRick Macklem }
10428fb6ad5dSRick Macklem fd = sock_fd[sock_fdpos++];
10438fb6ad5dSRick Macklem if (fd < 0)
10448fb6ad5dSRick Macklem continue;
10458fb6ad5dSRick Macklem
104693840fdeSSean Eric Fagan /*
104793840fdeSSean Eric Fagan * Using -1 tells listen(2) to use
104893840fdeSSean Eric Fagan * kern.ipc.soacceptqueue for the backlog.
104993840fdeSSean Eric Fagan */
1050d11e3645SMatteo Riondato if (nconf->nc_semantics != NC_TPI_CLTS)
105193840fdeSSean Eric Fagan listen(fd, -1);
1052d11e3645SMatteo Riondato
1053d11e3645SMatteo Riondato if (nconf->nc_semantics == NC_TPI_CLTS )
1054d11e3645SMatteo Riondato transp = svc_dg_create(fd, 0, 0);
1055d11e3645SMatteo Riondato else
1056d11e3645SMatteo Riondato transp = svc_vc_create(fd, RPC_MAXDATASIZE,
1057d11e3645SMatteo Riondato RPC_MAXDATASIZE);
1058d11e3645SMatteo Riondato
1059d11e3645SMatteo Riondato if (transp != (SVCXPRT *) NULL) {
10600775314bSDoug Rabson if (!svc_reg(transp, MOUNTPROG, MOUNTVERS, mntsrv,
1061d11e3645SMatteo Riondato NULL))
1062d11e3645SMatteo Riondato syslog(LOG_ERR,
10630775314bSDoug Rabson "can't register %s MOUNTVERS service",
1064d11e3645SMatteo Riondato nconf->nc_netid);
1065d11e3645SMatteo Riondato if (!force_v2) {
10660775314bSDoug Rabson if (!svc_reg(transp, MOUNTPROG, MOUNTVERS3,
1067d11e3645SMatteo Riondato mntsrv, NULL))
1068d11e3645SMatteo Riondato syslog(LOG_ERR,
10690775314bSDoug Rabson "can't register %s MOUNTVERS3 service",
1070d11e3645SMatteo Riondato nconf->nc_netid);
1071d11e3645SMatteo Riondato }
1072d11e3645SMatteo Riondato } else
1073d11e3645SMatteo Riondato syslog(LOG_WARNING, "can't create %s services",
1074d11e3645SMatteo Riondato nconf->nc_netid);
1075d11e3645SMatteo Riondato
1076d11e3645SMatteo Riondato if (registered == 0) {
1077d11e3645SMatteo Riondato registered = 1;
1078d11e3645SMatteo Riondato memset(&hints, 0, sizeof hints);
1079d11e3645SMatteo Riondato hints.ai_flags = AI_PASSIVE;
1080d11e3645SMatteo Riondato hints.ai_family = si.si_af;
1081d11e3645SMatteo Riondato hints.ai_socktype = si.si_socktype;
1082d11e3645SMatteo Riondato hints.ai_protocol = si.si_proto;
1083d11e3645SMatteo Riondato
10848fb6ad5dSRick Macklem if ((aicode = getaddrinfo(NULL, port_str, &hints,
1085d11e3645SMatteo Riondato &res)) != 0) {
1086d11e3645SMatteo Riondato syslog(LOG_ERR, "cannot get local address: %s",
1087d11e3645SMatteo Riondato gai_strerror(aicode));
1088d11e3645SMatteo Riondato exit(1);
1089d11e3645SMatteo Riondato }
1090d11e3645SMatteo Riondato
1091d11e3645SMatteo Riondato servaddr.buf = malloc(res->ai_addrlen);
1092d11e3645SMatteo Riondato memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen);
1093d11e3645SMatteo Riondato servaddr.len = res->ai_addrlen;
1094d11e3645SMatteo Riondato
10950775314bSDoug Rabson rpcb_set(MOUNTPROG, MOUNTVERS, nconf, &servaddr);
10960775314bSDoug Rabson rpcb_set(MOUNTPROG, MOUNTVERS3, nconf, &servaddr);
1097d11e3645SMatteo Riondato
1098d11e3645SMatteo Riondato xcreated++;
1099d11e3645SMatteo Riondato freeaddrinfo(res);
1100d11e3645SMatteo Riondato }
1101d11e3645SMatteo Riondato } /* end while */
1102d11e3645SMatteo Riondato }
1103d11e3645SMatteo Riondato
11048fb6ad5dSRick Macklem /*
11058fb6ad5dSRick Macklem * Clear out sockets after a failure to bind one of them, so that the
11068fb6ad5dSRick Macklem * cycle of socket creation/binding can start anew.
11078fb6ad5dSRick Macklem */
11088fb6ad5dSRick Macklem static void
clearout_service(void)11098fb6ad5dSRick Macklem clearout_service(void)
11108fb6ad5dSRick Macklem {
11118fb6ad5dSRick Macklem int i;
11128fb6ad5dSRick Macklem
11138fb6ad5dSRick Macklem for (i = 0; i < sock_fdcnt; i++) {
11148fb6ad5dSRick Macklem if (sock_fd[i] >= 0) {
11158fb6ad5dSRick Macklem shutdown(sock_fd[i], SHUT_RDWR);
11168fb6ad5dSRick Macklem close(sock_fd[i]);
11178fb6ad5dSRick Macklem }
11188fb6ad5dSRick Macklem }
11198fb6ad5dSRick Macklem }
11208fb6ad5dSRick Macklem
112174853402SPhilippe Charnier static void
usage(void)1122a7a7d96cSPhilippe Charnier usage(void)
112374853402SPhilippe Charnier {
112474853402SPhilippe Charnier fprintf(stderr,
11257c2901b0SJoyu Liao "usage: mountd [-2] [-d] [-e] [-l] [-N] [-n] [-p <port>] [-r] [-S] "
11267c2901b0SJoyu Liao "[-s] [-h <bindip>] [export_file ...]\n");
11278fae3551SRodney W. Grimes exit(1);
11288fae3551SRodney W. Grimes }
11298fae3551SRodney W. Grimes
11308fae3551SRodney W. Grimes /*
11318fae3551SRodney W. Grimes * The mount rpc service
11328fae3551SRodney W. Grimes */
11338fae3551SRodney W. Grimes void
mntsrv(struct svc_req * rqstp,SVCXPRT * transp)1134a7a7d96cSPhilippe Charnier mntsrv(struct svc_req *rqstp, SVCXPRT *transp)
11358fae3551SRodney W. Grimes {
11368fae3551SRodney W. Grimes struct exportlist *ep;
11378fae3551SRodney W. Grimes struct dirlist *dp;
1138a62dc406SDoug Rabson struct fhreturn fhr;
11398fae3551SRodney W. Grimes struct stat stb;
11408fae3551SRodney W. Grimes struct statfs fsb;
11418360efbdSAlfred Perlstein char host[NI_MAXHOST], numerichost[NI_MAXHOST];
11428360efbdSAlfred Perlstein int lookup_failed = 1;
11438360efbdSAlfred Perlstein struct sockaddr *saddr;
1144a62dc406SDoug Rabson u_short sport;
11450775314bSDoug Rabson char rpcpath[MNTPATHLEN + 1], dirpath[MAXPATHLEN];
1146e9b21d43SBrooks Davis int defset, hostset;
1147e9b21d43SBrooks Davis long bad = 0;
1148a62dc406SDoug Rabson sigset_t sighup_mask;
1149c3f86a25SRick Macklem int numsecflavors, *secflavorsp;
11508fae3551SRodney W. Grimes
1151a62dc406SDoug Rabson sigemptyset(&sighup_mask);
1152a62dc406SDoug Rabson sigaddset(&sighup_mask, SIGHUP);
11538360efbdSAlfred Perlstein saddr = svc_getrpccaller(transp)->buf;
11548360efbdSAlfred Perlstein switch (saddr->sa_family) {
11558360efbdSAlfred Perlstein case AF_INET6:
115601709abfSIan Dowse sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port);
11578360efbdSAlfred Perlstein break;
11588360efbdSAlfred Perlstein case AF_INET:
115901709abfSIan Dowse sport = ntohs(((struct sockaddr_in *)saddr)->sin_port);
11608360efbdSAlfred Perlstein break;
11618360efbdSAlfred Perlstein default:
11628360efbdSAlfred Perlstein syslog(LOG_ERR, "request from unknown address family");
11638360efbdSAlfred Perlstein return;
11648360efbdSAlfred Perlstein }
116554ff4a6aSSean Eric Fagan switch (rqstp->rq_proc) {
116654ff4a6aSSean Eric Fagan case MOUNTPROC_MNT:
116754ff4a6aSSean Eric Fagan case MOUNTPROC_UMNT:
116854ff4a6aSSean Eric Fagan case MOUNTPROC_UMNTALL:
116954ff4a6aSSean Eric Fagan lookup_failed = getnameinfo(saddr, saddr->sa_len, host,
117054ff4a6aSSean Eric Fagan sizeof host, NULL, 0, 0);
117154ff4a6aSSean Eric Fagan }
11728360efbdSAlfred Perlstein getnameinfo(saddr, saddr->sa_len, numerichost,
11738360efbdSAlfred Perlstein sizeof numerichost, NULL, 0, NI_NUMERICHOST);
11748fae3551SRodney W. Grimes switch (rqstp->rq_proc) {
11758fae3551SRodney W. Grimes case NULLPROC:
1176389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
117774853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply");
11788fae3551SRodney W. Grimes return;
11790775314bSDoug Rabson case MOUNTPROC_MNT:
1180a62dc406SDoug Rabson if (sport >= IPPORT_RESERVED && resvport_only) {
1181f51631d7SGuido van Rooij syslog(LOG_NOTICE,
1182f51631d7SGuido van Rooij "mount request from %s from unprivileged port",
11838360efbdSAlfred Perlstein numerichost);
11848fae3551SRodney W. Grimes svcerr_weakauth(transp);
11858fae3551SRodney W. Grimes return;
11868fae3551SRodney W. Grimes }
1187389b8446SPeter Wemm if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) {
1188f51631d7SGuido van Rooij syslog(LOG_NOTICE, "undecodable mount request from %s",
11898360efbdSAlfred Perlstein numerichost);
11908fae3551SRodney W. Grimes svcerr_decode(transp);
11918fae3551SRodney W. Grimes return;
11928fae3551SRodney W. Grimes }
11938fae3551SRodney W. Grimes
11948fae3551SRodney W. Grimes /*
11958fae3551SRodney W. Grimes * Get the real pathname and make sure it is a directory
1196a62dc406SDoug Rabson * or a regular file if the -r option was specified
1197a62dc406SDoug Rabson * and it exists.
11988fae3551SRodney W. Grimes */
1199cb479b11SAlfred Perlstein if (realpath(rpcpath, dirpath) == NULL ||
12008fae3551SRodney W. Grimes stat(dirpath, &stb) < 0 ||
12018fae3551SRodney W. Grimes statfs(dirpath, &fsb) < 0) {
12028fae3551SRodney W. Grimes chdir("/"); /* Just in case realpath doesn't */
1203f51631d7SGuido van Rooij syslog(LOG_NOTICE,
120474853402SPhilippe Charnier "mount request from %s for non existent path %s",
12058360efbdSAlfred Perlstein numerichost, dirpath);
12068fae3551SRodney W. Grimes if (debug)
120774853402SPhilippe Charnier warnx("stat failed on %s", dirpath);
1208e90cdb54SGuido van Rooij bad = ENOENT; /* We will send error reply later */
12098fae3551SRodney W. Grimes }
1210b235f015SRavi Pokala if (!bad &&
1211b235f015SRavi Pokala !S_ISDIR(stb.st_mode) &&
1212b235f015SRavi Pokala (dir_only || !S_ISREG(stb.st_mode))) {
1213b235f015SRavi Pokala syslog(LOG_NOTICE,
1214b235f015SRavi Pokala "mount request from %s for non-directory path %s",
1215b235f015SRavi Pokala numerichost, dirpath);
1216b235f015SRavi Pokala if (debug)
1217b235f015SRavi Pokala warnx("mounting non-directory %s", dirpath);
1218b235f015SRavi Pokala bad = ENOTDIR; /* We will send error reply later */
1219b235f015SRavi Pokala }
12208fae3551SRodney W. Grimes
12218fae3551SRodney W. Grimes /* Check in the exports list */
1222a62dc406SDoug Rabson sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
1223b235f015SRavi Pokala if (bad)
1224b235f015SRavi Pokala ep = NULL;
1225b235f015SRavi Pokala else
122646a6b5c4SRick Macklem ep = ex_search(&fsb.f_fsid, exphead);
1227a62dc406SDoug Rabson hostset = defset = 0;
1228c3f86a25SRick Macklem if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset,
1229c3f86a25SRick Macklem &numsecflavors, &secflavorsp) ||
12308fae3551SRodney W. Grimes ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
1231c3f86a25SRick Macklem chk_host(dp, saddr, &defset, &hostset, &numsecflavors,
1232c3f86a25SRick Macklem &secflavorsp)) ||
12338fae3551SRodney W. Grimes (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
12348fae3551SRodney W. Grimes scan_tree(ep->ex_dirl, saddr) == 0))) {
1235e90cdb54SGuido van Rooij if (bad) {
1236389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_long,
1237e90cdb54SGuido van Rooij (caddr_t)&bad))
123874853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply");
1239e90cdb54SGuido van Rooij sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
1240e90cdb54SGuido van Rooij return;
1241e90cdb54SGuido van Rooij }
1242c3f86a25SRick Macklem if (hostset & DP_HOSTSET) {
1243a62dc406SDoug Rabson fhr.fhr_flag = hostset;
1244c3f86a25SRick Macklem fhr.fhr_numsecflavors = numsecflavors;
1245c3f86a25SRick Macklem fhr.fhr_secflavors = secflavorsp;
1246c3f86a25SRick Macklem } else {
1247a62dc406SDoug Rabson fhr.fhr_flag = defset;
1248c3f86a25SRick Macklem fhr.fhr_numsecflavors = ep->ex_defnumsecflavors;
1249c3f86a25SRick Macklem fhr.fhr_secflavors = ep->ex_defsecflavors;
1250c3f86a25SRick Macklem }
1251a62dc406SDoug Rabson fhr.fhr_vers = rqstp->rq_vers;
12528fae3551SRodney W. Grimes /* Get the file handle */
125387564113SPeter Wemm memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t));
1254a62dc406SDoug Rabson if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) {
12558fae3551SRodney W. Grimes bad = errno;
125674853402SPhilippe Charnier syslog(LOG_ERR, "can't get fh for %s", dirpath);
1257389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_long,
12588fae3551SRodney W. Grimes (caddr_t)&bad))
125974853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply");
1260a62dc406SDoug Rabson sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
12618fae3551SRodney W. Grimes return;
12628fae3551SRodney W. Grimes }
1263389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs,
1264389b8446SPeter Wemm (caddr_t)&fhr))
126574853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply");
12668360efbdSAlfred Perlstein if (!lookup_failed)
12678360efbdSAlfred Perlstein add_mlist(host, dirpath);
12688fae3551SRodney W. Grimes else
12698360efbdSAlfred Perlstein add_mlist(numerichost, dirpath);
12708fae3551SRodney W. Grimes if (debug)
127174853402SPhilippe Charnier warnx("mount successful");
1272c903443aSPeter Wemm if (dolog)
1273f51631d7SGuido van Rooij syslog(LOG_NOTICE,
1274f51631d7SGuido van Rooij "mount request succeeded from %s for %s",
12758360efbdSAlfred Perlstein numerichost, dirpath);
1276f51631d7SGuido van Rooij } else {
1277b235f015SRavi Pokala if (!bad)
12788fae3551SRodney W. Grimes bad = EACCES;
1279f51631d7SGuido van Rooij syslog(LOG_NOTICE,
1280f51631d7SGuido van Rooij "mount request denied from %s for %s",
12818360efbdSAlfred Perlstein numerichost, dirpath);
1282f51631d7SGuido van Rooij }
1283e90cdb54SGuido van Rooij
1284389b8446SPeter Wemm if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long,
1285389b8446SPeter Wemm (caddr_t)&bad))
128674853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply");
1287a62dc406SDoug Rabson sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
12888fae3551SRodney W. Grimes return;
12890775314bSDoug Rabson case MOUNTPROC_DUMP:
1290389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL))
129174853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply");
1292c903443aSPeter Wemm else if (dolog)
1293f51631d7SGuido van Rooij syslog(LOG_NOTICE,
1294f51631d7SGuido van Rooij "dump request succeeded from %s",
12958360efbdSAlfred Perlstein numerichost);
12968fae3551SRodney W. Grimes return;
12970775314bSDoug Rabson case MOUNTPROC_UMNT:
1298a62dc406SDoug Rabson if (sport >= IPPORT_RESERVED && resvport_only) {
1299f51631d7SGuido van Rooij syslog(LOG_NOTICE,
1300f51631d7SGuido van Rooij "umount request from %s from unprivileged port",
13018360efbdSAlfred Perlstein numerichost);
13028fae3551SRodney W. Grimes svcerr_weakauth(transp);
13038fae3551SRodney W. Grimes return;
13048fae3551SRodney W. Grimes }
1305389b8446SPeter Wemm if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) {
1306f51631d7SGuido van Rooij syslog(LOG_NOTICE, "undecodable umount request from %s",
13078360efbdSAlfred Perlstein numerichost);
13088fae3551SRodney W. Grimes svcerr_decode(transp);
13098fae3551SRodney W. Grimes return;
13108fae3551SRodney W. Grimes }
1311cb479b11SAlfred Perlstein if (realpath(rpcpath, dirpath) == NULL) {
1312cb479b11SAlfred Perlstein syslog(LOG_NOTICE, "umount request from %s "
1313cb479b11SAlfred Perlstein "for non existent path %s",
13148360efbdSAlfred Perlstein numerichost, dirpath);
1315cb479b11SAlfred Perlstein }
1316389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL))
131774853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply");
13188360efbdSAlfred Perlstein if (!lookup_failed)
131901709abfSIan Dowse del_mlist(host, dirpath);
132001709abfSIan Dowse del_mlist(numerichost, dirpath);
1321c903443aSPeter Wemm if (dolog)
1322f51631d7SGuido van Rooij syslog(LOG_NOTICE,
1323f51631d7SGuido van Rooij "umount request succeeded from %s for %s",
13248360efbdSAlfred Perlstein numerichost, dirpath);
13258fae3551SRodney W. Grimes return;
13260775314bSDoug Rabson case MOUNTPROC_UMNTALL:
1327a62dc406SDoug Rabson if (sport >= IPPORT_RESERVED && resvport_only) {
1328f51631d7SGuido van Rooij syslog(LOG_NOTICE,
1329f51631d7SGuido van Rooij "umountall request from %s from unprivileged port",
13308360efbdSAlfred Perlstein numerichost);
13318fae3551SRodney W. Grimes svcerr_weakauth(transp);
13328fae3551SRodney W. Grimes return;
13338fae3551SRodney W. Grimes }
1334389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL))
133574853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply");
13368360efbdSAlfred Perlstein if (!lookup_failed)
133701709abfSIan Dowse del_mlist(host, NULL);
133801709abfSIan Dowse del_mlist(numerichost, NULL);
1339c903443aSPeter Wemm if (dolog)
1340f51631d7SGuido van Rooij syslog(LOG_NOTICE,
1341f51631d7SGuido van Rooij "umountall request succeeded from %s",
13428360efbdSAlfred Perlstein numerichost);
13438fae3551SRodney W. Grimes return;
13440775314bSDoug Rabson case MOUNTPROC_EXPORT:
1345389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL))
1346389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief,
1347389b8446SPeter Wemm (caddr_t)NULL))
134874853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply");
1349c903443aSPeter Wemm if (dolog)
1350f51631d7SGuido van Rooij syslog(LOG_NOTICE,
1351f51631d7SGuido van Rooij "export request succeeded from %s",
13528360efbdSAlfred Perlstein numerichost);
13538fae3551SRodney W. Grimes return;
13548fae3551SRodney W. Grimes default:
13558fae3551SRodney W. Grimes svcerr_noproc(transp);
13568fae3551SRodney W. Grimes return;
13578fae3551SRodney W. Grimes }
13588fae3551SRodney W. Grimes }
13598fae3551SRodney W. Grimes
13608fae3551SRodney W. Grimes /*
13618fae3551SRodney W. Grimes * Xdr conversion for a dirpath string
13628fae3551SRodney W. Grimes */
136319c46d8cSEdward Tomasz Napierala static int
xdr_dir(XDR * xdrsp,char * dirp)1364a7a7d96cSPhilippe Charnier xdr_dir(XDR *xdrsp, char *dirp)
13658fae3551SRodney W. Grimes {
13660775314bSDoug Rabson return (xdr_string(xdrsp, &dirp, MNTPATHLEN));
13678fae3551SRodney W. Grimes }
13688fae3551SRodney W. Grimes
13698fae3551SRodney W. Grimes /*
1370a62dc406SDoug Rabson * Xdr routine to generate file handle reply
13718fae3551SRodney W. Grimes */
137219c46d8cSEdward Tomasz Napierala static int
xdr_fhs(XDR * xdrsp,caddr_t cp)1373a7a7d96cSPhilippe Charnier xdr_fhs(XDR *xdrsp, caddr_t cp)
13748fae3551SRodney W. Grimes {
13753d438ad6SDavid E. O'Brien struct fhreturn *fhrp = (struct fhreturn *)cp;
1376a62dc406SDoug Rabson u_long ok = 0, len, auth;
1377a9148abdSDoug Rabson int i;
13788fae3551SRodney W. Grimes
13798fae3551SRodney W. Grimes if (!xdr_long(xdrsp, &ok))
13808fae3551SRodney W. Grimes return (0);
1381a62dc406SDoug Rabson switch (fhrp->fhr_vers) {
1382a62dc406SDoug Rabson case 1:
1383a62dc406SDoug Rabson return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH));
1384a62dc406SDoug Rabson case 3:
1385a62dc406SDoug Rabson len = NFSX_V3FH;
1386a62dc406SDoug Rabson if (!xdr_long(xdrsp, &len))
1387a62dc406SDoug Rabson return (0);
1388a62dc406SDoug Rabson if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len))
1389a62dc406SDoug Rabson return (0);
1390a9148abdSDoug Rabson if (fhrp->fhr_numsecflavors) {
1391a9148abdSDoug Rabson if (!xdr_int(xdrsp, &fhrp->fhr_numsecflavors))
1392a9148abdSDoug Rabson return (0);
1393a9148abdSDoug Rabson for (i = 0; i < fhrp->fhr_numsecflavors; i++)
1394a9148abdSDoug Rabson if (!xdr_int(xdrsp, &fhrp->fhr_secflavors[i]))
1395a9148abdSDoug Rabson return (0);
1396a9148abdSDoug Rabson return (1);
1397a9148abdSDoug Rabson } else {
1398a9148abdSDoug Rabson auth = AUTH_SYS;
1399a62dc406SDoug Rabson len = 1;
1400a62dc406SDoug Rabson if (!xdr_long(xdrsp, &len))
1401a62dc406SDoug Rabson return (0);
1402a62dc406SDoug Rabson return (xdr_long(xdrsp, &auth));
1403a9148abdSDoug Rabson }
140480c7cc1cSPedro F. Giffuni }
1405a62dc406SDoug Rabson return (0);
14068fae3551SRodney W. Grimes }
14078fae3551SRodney W. Grimes
140819c46d8cSEdward Tomasz Napierala static int
xdr_mlist(XDR * xdrsp,caddr_t cp __unused)1409a7a7d96cSPhilippe Charnier xdr_mlist(XDR *xdrsp, caddr_t cp __unused)
14108fae3551SRodney W. Grimes {
14118fae3551SRodney W. Grimes struct mountlist *mlp;
14128fae3551SRodney W. Grimes int true = 1;
14138fae3551SRodney W. Grimes int false = 0;
14148fae3551SRodney W. Grimes char *strp;
14158fae3551SRodney W. Grimes
14161da3e8b0SEmmanuel Vadot SLIST_FOREACH(mlp, &mlhead, next) {
14178fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &true))
14188fae3551SRodney W. Grimes return (0);
14198fae3551SRodney W. Grimes strp = &mlp->ml_host[0];
14200775314bSDoug Rabson if (!xdr_string(xdrsp, &strp, MNTNAMLEN))
14218fae3551SRodney W. Grimes return (0);
14228fae3551SRodney W. Grimes strp = &mlp->ml_dirp[0];
14230775314bSDoug Rabson if (!xdr_string(xdrsp, &strp, MNTPATHLEN))
14248fae3551SRodney W. Grimes return (0);
14258fae3551SRodney W. Grimes }
14268fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &false))
14278fae3551SRodney W. Grimes return (0);
14288fae3551SRodney W. Grimes return (1);
14298fae3551SRodney W. Grimes }
14308fae3551SRodney W. Grimes
14318fae3551SRodney W. Grimes /*
14328fae3551SRodney W. Grimes * Xdr conversion for export list
14338fae3551SRodney W. Grimes */
143419c46d8cSEdward Tomasz Napierala static int
xdr_explist_common(XDR * xdrsp,caddr_t cp __unused,int brief)1435a7a7d96cSPhilippe Charnier xdr_explist_common(XDR *xdrsp, caddr_t cp __unused, int brief)
14368fae3551SRodney W. Grimes {
14378fae3551SRodney W. Grimes struct exportlist *ep;
14388fae3551SRodney W. Grimes int false = 0;
1439a62dc406SDoug Rabson int putdef;
1440a62dc406SDoug Rabson sigset_t sighup_mask;
144146a6b5c4SRick Macklem int i;
14428fae3551SRodney W. Grimes
1443a62dc406SDoug Rabson sigemptyset(&sighup_mask);
1444a62dc406SDoug Rabson sigaddset(&sighup_mask, SIGHUP);
1445a62dc406SDoug Rabson sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
1446c9ac0f71SEmmanuel Vadot
144746a6b5c4SRick Macklem for (i = 0; i < exphashsize; i++)
144846a6b5c4SRick Macklem SLIST_FOREACH(ep, &exphead[i], entries) {
14498fae3551SRodney W. Grimes putdef = 0;
145091acb349SAlfred Perlstein if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir,
145191acb349SAlfred Perlstein &putdef, brief))
14528fae3551SRodney W. Grimes goto errout;
14538fae3551SRodney W. Grimes if (ep->ex_defdir && putdef == 0 &&
145446a6b5c4SRick Macklem put_exlist(ep->ex_defdir, xdrsp, NULL,
145591acb349SAlfred Perlstein &putdef, brief))
14568fae3551SRodney W. Grimes goto errout;
14578fae3551SRodney W. Grimes }
1458a62dc406SDoug Rabson sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
14598fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &false))
14608fae3551SRodney W. Grimes return (0);
14618fae3551SRodney W. Grimes return (1);
14628fae3551SRodney W. Grimes errout:
1463a62dc406SDoug Rabson sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
14648fae3551SRodney W. Grimes return (0);
14658fae3551SRodney W. Grimes }
14668fae3551SRodney W. Grimes
14678fae3551SRodney W. Grimes /*
14688fae3551SRodney W. Grimes * Called from xdr_explist() to traverse the tree and export the
14698fae3551SRodney W. Grimes * directory paths.
14708fae3551SRodney W. Grimes */
147119c46d8cSEdward Tomasz Napierala static int
put_exlist(struct dirlist * dp,XDR * xdrsp,struct dirlist * adp,int * putdefp,int brief)1472a7a7d96cSPhilippe Charnier put_exlist(struct dirlist *dp, XDR *xdrsp, struct dirlist *adp, int *putdefp,
1473a7a7d96cSPhilippe Charnier int brief)
14748fae3551SRodney W. Grimes {
14758fae3551SRodney W. Grimes struct grouplist *grp;
14768fae3551SRodney W. Grimes struct hostlist *hp;
14778fae3551SRodney W. Grimes int true = 1;
14788fae3551SRodney W. Grimes int false = 0;
14798fae3551SRodney W. Grimes int gotalldir = 0;
14808fae3551SRodney W. Grimes char *strp;
14818fae3551SRodney W. Grimes
14828fae3551SRodney W. Grimes if (dp) {
148391acb349SAlfred Perlstein if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief))
14848fae3551SRodney W. Grimes return (1);
14858fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &true))
14868fae3551SRodney W. Grimes return (1);
14878fae3551SRodney W. Grimes strp = dp->dp_dirp;
14880775314bSDoug Rabson if (!xdr_string(xdrsp, &strp, MNTPATHLEN))
14898fae3551SRodney W. Grimes return (1);
14908fae3551SRodney W. Grimes if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) {
14918fae3551SRodney W. Grimes gotalldir = 1;
14928fae3551SRodney W. Grimes *putdefp = 1;
14938fae3551SRodney W. Grimes }
149491acb349SAlfred Perlstein if (brief) {
149591acb349SAlfred Perlstein if (!xdr_bool(xdrsp, &true))
149691acb349SAlfred Perlstein return (1);
149791acb349SAlfred Perlstein strp = "(...)";
14980775314bSDoug Rabson if (!xdr_string(xdrsp, &strp, MNTPATHLEN))
149991acb349SAlfred Perlstein return (1);
150091acb349SAlfred Perlstein } else if ((dp->dp_flag & DP_DEFSET) == 0 &&
15018fae3551SRodney W. Grimes (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) {
15028fae3551SRodney W. Grimes hp = dp->dp_hosts;
15038fae3551SRodney W. Grimes while (hp) {
15048fae3551SRodney W. Grimes grp = hp->ht_grp;
15058fae3551SRodney W. Grimes if (grp->gr_type == GT_HOST) {
15068fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &true))
15078fae3551SRodney W. Grimes return (1);
15088360efbdSAlfred Perlstein strp = grp->gr_ptr.gt_addrinfo->ai_canonname;
15098fae3551SRodney W. Grimes if (!xdr_string(xdrsp, &strp,
15100775314bSDoug Rabson MNTNAMLEN))
15118fae3551SRodney W. Grimes return (1);
15128fae3551SRodney W. Grimes } else if (grp->gr_type == GT_NET) {
15138fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &true))
15148fae3551SRodney W. Grimes return (1);
15158fae3551SRodney W. Grimes strp = grp->gr_ptr.gt_net.nt_name;
15168fae3551SRodney W. Grimes if (!xdr_string(xdrsp, &strp,
15170775314bSDoug Rabson MNTNAMLEN))
15188fae3551SRodney W. Grimes return (1);
15198fae3551SRodney W. Grimes }
15208fae3551SRodney W. Grimes hp = hp->ht_next;
15218fae3551SRodney W. Grimes if (gotalldir && hp == (struct hostlist *)NULL) {
15228fae3551SRodney W. Grimes hp = adp->dp_hosts;
15238fae3551SRodney W. Grimes gotalldir = 0;
15248fae3551SRodney W. Grimes }
15258fae3551SRodney W. Grimes }
15268fae3551SRodney W. Grimes }
15278fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &false))
15288fae3551SRodney W. Grimes return (1);
152991acb349SAlfred Perlstein if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief))
15308fae3551SRodney W. Grimes return (1);
15318fae3551SRodney W. Grimes }
15328fae3551SRodney W. Grimes return (0);
15338fae3551SRodney W. Grimes }
15348fae3551SRodney W. Grimes
153519c46d8cSEdward Tomasz Napierala static int
xdr_explist(XDR * xdrsp,caddr_t cp)1536a7a7d96cSPhilippe Charnier xdr_explist(XDR *xdrsp, caddr_t cp)
153791acb349SAlfred Perlstein {
153891acb349SAlfred Perlstein
153991acb349SAlfred Perlstein return xdr_explist_common(xdrsp, cp, 0);
154091acb349SAlfred Perlstein }
154191acb349SAlfred Perlstein
154219c46d8cSEdward Tomasz Napierala static int
xdr_explist_brief(XDR * xdrsp,caddr_t cp)1543a7a7d96cSPhilippe Charnier xdr_explist_brief(XDR *xdrsp, caddr_t cp)
154491acb349SAlfred Perlstein {
154591acb349SAlfred Perlstein
154691acb349SAlfred Perlstein return xdr_explist_common(xdrsp, cp, 1);
154791acb349SAlfred Perlstein }
154891acb349SAlfred Perlstein
154919c46d8cSEdward Tomasz Napierala static char *line;
155019c46d8cSEdward Tomasz Napierala static size_t linesize;
155119c46d8cSEdward Tomasz Napierala static FILE *exp_file;
15528fae3551SRodney W. Grimes
15538fae3551SRodney W. Grimes /*
155496968c22SPawel Jakub Dawidek * Get the export list from one, currently open file
15558fae3551SRodney W. Grimes */
155696968c22SPawel Jakub Dawidek static void
get_exportlist_one(int passno)15570f0869bcSRick Macklem get_exportlist_one(int passno)
15588fae3551SRodney W. Grimes {
1559c9ac0f71SEmmanuel Vadot struct exportlist *ep;
15600f0869bcSRick Macklem struct grouplist *grp, *tgrp, *savgrp;
15618fae3551SRodney W. Grimes struct dirlist *dirhead;
156296968c22SPawel Jakub Dawidek struct statfs fsb;
1563cc5efddeSRick Macklem struct expcred anon;
15648fae3551SRodney W. Grimes char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
1565572b77f8SAlexander Motin char *err_msg = NULL;
1566cc5efddeSRick Macklem int len, has_host, got_nondir, dirplen, netgrp;
1567cc5efddeSRick Macklem uint64_t exflags;
15687c5146daSDan Mcgregor char unvis_dir[PATH_MAX + 1];
15697c5146daSDan Mcgregor int unvis_len;
15708fae3551SRodney W. Grimes
1571bcc1d071SRick Macklem v4root_phase = 0;
15722ffad162SRick Macklem anon.cr_groups = NULL;
15738fae3551SRodney W. Grimes dirhead = (struct dirlist *)NULL;
15747c5146daSDan Mcgregor unvis_dir[0] = '\0';
15758fae3551SRodney W. Grimes while (get_line()) {
15768fae3551SRodney W. Grimes if (debug)
157774853402SPhilippe Charnier warnx("got line %s", line);
15788fae3551SRodney W. Grimes cp = line;
15798fae3551SRodney W. Grimes nextfield(&cp, &endcp);
15808fae3551SRodney W. Grimes if (*cp == '#')
15818fae3551SRodney W. Grimes goto nextline;
15828fae3551SRodney W. Grimes
15838fae3551SRodney W. Grimes /*
15848fae3551SRodney W. Grimes * Set defaults.
15858fae3551SRodney W. Grimes */
15868fae3551SRodney W. Grimes has_host = FALSE;
15872ffad162SRick Macklem anon.cr_groups = anon.cr_smallgrps;
15883e2d36ffSRick Macklem anon.cr_uid = UID_NOBODY;
1589cc5efddeSRick Macklem anon.cr_ngroups = 1;
15903e2d36ffSRick Macklem anon.cr_groups[0] = GID_NOGROUP;
15918fae3551SRodney W. Grimes exflags = MNT_EXPORTED;
15928fae3551SRodney W. Grimes got_nondir = 0;
15938fae3551SRodney W. Grimes opt_flags = 0;
15948fae3551SRodney W. Grimes ep = (struct exportlist *)NULL;
1595bcc1d071SRick Macklem dirp = NULL;
1596bcc1d071SRick Macklem
1597bcc1d071SRick Macklem /*
1598bcc1d071SRick Macklem * Handle the V4 root dir.
1599bcc1d071SRick Macklem */
1600bcc1d071SRick Macklem if (*cp == 'V' && *(cp + 1) == '4' && *(cp + 2) == ':') {
1601bcc1d071SRick Macklem /*
1602bcc1d071SRick Macklem * V4: just indicates that it is the v4 root point,
1603bcc1d071SRick Macklem * so skip over that and set v4root_phase.
1604bcc1d071SRick Macklem */
1605bcc1d071SRick Macklem if (v4root_phase > 0) {
1606bcc1d071SRick Macklem syslog(LOG_ERR, "V4:duplicate line, ignored");
1607bcc1d071SRick Macklem goto nextline;
1608bcc1d071SRick Macklem }
1609bcc1d071SRick Macklem v4root_phase = 1;
1610bcc1d071SRick Macklem cp += 3;
1611bcc1d071SRick Macklem nextfield(&cp, &endcp);
1612bcc1d071SRick Macklem }
16138fae3551SRodney W. Grimes
16148fae3551SRodney W. Grimes /*
16158fae3551SRodney W. Grimes * Create new exports list entry
16168fae3551SRodney W. Grimes */
16178fae3551SRodney W. Grimes len = endcp-cp;
16188fae3551SRodney W. Grimes tgrp = grp = get_grp();
16198fae3551SRodney W. Grimes while (len > 0) {
16200775314bSDoug Rabson if (len > MNTNAMLEN) {
1621354fce28SConrad Meyer getexp_err(ep, tgrp, "mountpoint too long");
16228fae3551SRodney W. Grimes goto nextline;
16238fae3551SRodney W. Grimes }
16248fae3551SRodney W. Grimes if (*cp == '-') {
16258fae3551SRodney W. Grimes if (ep == (struct exportlist *)NULL) {
1626354fce28SConrad Meyer getexp_err(ep, tgrp,
1627354fce28SConrad Meyer "flag before export path definition");
16288fae3551SRodney W. Grimes goto nextline;
16298fae3551SRodney W. Grimes }
16308fae3551SRodney W. Grimes if (debug)
163174853402SPhilippe Charnier warnx("doing opt %s", cp);
16328fae3551SRodney W. Grimes got_nondir = 1;
16338fae3551SRodney W. Grimes if (do_opt(&cp, &endcp, ep, grp, &has_host,
16348fae3551SRodney W. Grimes &exflags, &anon)) {
1635354fce28SConrad Meyer getexp_err(ep, tgrp, NULL);
16368fae3551SRodney W. Grimes goto nextline;
16378fae3551SRodney W. Grimes }
16388fae3551SRodney W. Grimes } else if (*cp == '/') {
16398fae3551SRodney W. Grimes savedc = *endcp;
16408fae3551SRodney W. Grimes *endcp = '\0';
16417c5146daSDan Mcgregor unvis_len = strnunvis(unvis_dir, sizeof(unvis_dir),
16427c5146daSDan Mcgregor cp);
16437c5146daSDan Mcgregor if (unvis_len <= 0) {
16447c5146daSDan Mcgregor getexp_err(ep, tgrp, "Cannot strunvis "
16457c5146daSDan Mcgregor "decode dir");
16467c5146daSDan Mcgregor goto nextline;
16477c5146daSDan Mcgregor }
1648bcc1d071SRick Macklem if (v4root_phase > 1) {
1649bcc1d071SRick Macklem if (dirp != NULL) {
1650354fce28SConrad Meyer getexp_err(ep, tgrp, "Multiple V4 dirs");
1651bcc1d071SRick Macklem goto nextline;
1652bcc1d071SRick Macklem }
1653bcc1d071SRick Macklem }
16547c5146daSDan Mcgregor if (check_dirpath(unvis_dir, &err_msg) &&
16557c5146daSDan Mcgregor check_statfs(unvis_dir, &fsb, &err_msg)) {
16569896584aSRick Macklem if ((fsb.f_flags & MNT_AUTOMOUNTED) != 0)
16579896584aSRick Macklem syslog(LOG_ERR, "Warning: exporting of "
16587c5146daSDan Mcgregor "automounted fs %s not supported",
16597c5146daSDan Mcgregor unvis_dir);
16608fae3551SRodney W. Grimes if (got_nondir) {
1661354fce28SConrad Meyer getexp_err(ep, tgrp, "dirs must be first");
16628fae3551SRodney W. Grimes goto nextline;
16638fae3551SRodney W. Grimes }
1664bcc1d071SRick Macklem if (v4root_phase == 1) {
1665bcc1d071SRick Macklem if (dirp != NULL) {
1666354fce28SConrad Meyer getexp_err(ep, tgrp, "Multiple V4 dirs");
1667bcc1d071SRick Macklem goto nextline;
1668bcc1d071SRick Macklem }
1669bcc1d071SRick Macklem if (strlen(v4root_dirpath) == 0) {
16707c5146daSDan Mcgregor strlcpy(v4root_dirpath, unvis_dir,
1671bcc1d071SRick Macklem sizeof (v4root_dirpath));
16727c5146daSDan Mcgregor } else if (strcmp(v4root_dirpath, unvis_dir)
1673bcc1d071SRick Macklem != 0) {
1674bcc1d071SRick Macklem syslog(LOG_ERR,
16757c5146daSDan Mcgregor "different V4 dirpath %s",
16767c5146daSDan Mcgregor unvis_dir);
1677354fce28SConrad Meyer getexp_err(ep, tgrp, NULL);
1678bcc1d071SRick Macklem goto nextline;
1679bcc1d071SRick Macklem }
16807c5146daSDan Mcgregor dirp = unvis_dir;
1681bcc1d071SRick Macklem v4root_phase = 2;
1682bcc1d071SRick Macklem got_nondir = 1;
1683bcc1d071SRick Macklem ep = get_exp();
1684bcc1d071SRick Macklem } else {
16858fae3551SRodney W. Grimes if (ep) {
1686245bfd34SRyan Moeller if (fsidcmp(&ep->ex_fs, &fsb.f_fsid)
1687245bfd34SRyan Moeller != 0) {
1688354fce28SConrad Meyer getexp_err(ep, tgrp,
1689354fce28SConrad Meyer "fsid mismatch");
16908fae3551SRodney W. Grimes goto nextline;
16918fae3551SRodney W. Grimes }
16928fae3551SRodney W. Grimes } else {
16938fae3551SRodney W. Grimes /*
16948fae3551SRodney W. Grimes * See if this directory is already
16958fae3551SRodney W. Grimes * in the list.
16968fae3551SRodney W. Grimes */
169746a6b5c4SRick Macklem ep = ex_search(&fsb.f_fsid, exphead);
16988fae3551SRodney W. Grimes if (ep == (struct exportlist *)NULL) {
16998fae3551SRodney W. Grimes ep = get_exp();
17008fae3551SRodney W. Grimes ep->ex_fs = fsb.f_fsid;
1701380a3fcdSEmmanuel Vadot ep->ex_fsdir = strdup(fsb.f_mntonname);
1702380a3fcdSEmmanuel Vadot if (ep->ex_fsdir == NULL)
17038fae3551SRodney W. Grimes out_of_mem();
17048fae3551SRodney W. Grimes if (debug)
1705bcc1d071SRick Macklem warnx(
1706bcc1d071SRick Macklem "making new ep fs=0x%x,0x%x",
17078fae3551SRodney W. Grimes fsb.f_fsid.val[0],
17088fae3551SRodney W. Grimes fsb.f_fsid.val[1]);
17098fae3551SRodney W. Grimes } else if (debug)
171074853402SPhilippe Charnier warnx("found ep fs=0x%x,0x%x",
17118fae3551SRodney W. Grimes fsb.f_fsid.val[0],
17128fae3551SRodney W. Grimes fsb.f_fsid.val[1]);
17138fae3551SRodney W. Grimes }
17148fae3551SRodney W. Grimes
1715fefb7c39SRick Macklem if (warn_admin != 0 &&
1716fefb7c39SRick Macklem (ep->ex_flag & EX_ADMINWARN) == 0 &&
1717fefb7c39SRick Macklem strcmp(unvis_dir, fsb.f_mntonname) !=
1718fefb7c39SRick Macklem 0) {
1719fefb7c39SRick Macklem if (debug)
1720fefb7c39SRick Macklem warnx("exporting %s exports entire "
1721fefb7c39SRick Macklem "%s file system", unvis_dir,
1722fefb7c39SRick Macklem fsb.f_mntonname);
1723fefb7c39SRick Macklem syslog(LOG_ERR, "Warning: exporting %s "
1724fefb7c39SRick Macklem "exports entire %s file system",
1725fefb7c39SRick Macklem unvis_dir, fsb.f_mntonname);
1726fefb7c39SRick Macklem ep->ex_flag |= EX_ADMINWARN;
1727fefb7c39SRick Macklem }
1728fefb7c39SRick Macklem
17298fae3551SRodney W. Grimes /*
17308fae3551SRodney W. Grimes * Add dirpath to export mount point.
17318fae3551SRodney W. Grimes */
17327c5146daSDan Mcgregor dirp = add_expdir(&dirhead, unvis_dir,
17337c5146daSDan Mcgregor unvis_len);
17347c5146daSDan Mcgregor dirplen = unvis_len;
1735bcc1d071SRick Macklem }
17368fae3551SRodney W. Grimes } else {
1737572b77f8SAlexander Motin if (err_msg != NULL) {
1738572b77f8SAlexander Motin getexp_err(ep, tgrp, err_msg);
1739572b77f8SAlexander Motin free(err_msg);
1740572b77f8SAlexander Motin err_msg = NULL;
1741572b77f8SAlexander Motin } else {
1742354fce28SConrad Meyer getexp_err(ep, tgrp,
1743572b77f8SAlexander Motin "symbolic link in export path or "
1744572b77f8SAlexander Motin "statfs failed");
1745572b77f8SAlexander Motin }
17468fae3551SRodney W. Grimes goto nextline;
17478fae3551SRodney W. Grimes }
17488fae3551SRodney W. Grimes *endcp = savedc;
17498fae3551SRodney W. Grimes } else {
17508fae3551SRodney W. Grimes savedc = *endcp;
17518fae3551SRodney W. Grimes *endcp = '\0';
17528fae3551SRodney W. Grimes got_nondir = 1;
17538fae3551SRodney W. Grimes if (ep == (struct exportlist *)NULL) {
1754354fce28SConrad Meyer getexp_err(ep, tgrp,
1755354fce28SConrad Meyer "host(s) before export path definition");
17568fae3551SRodney W. Grimes goto nextline;
17578fae3551SRodney W. Grimes }
17588fae3551SRodney W. Grimes
17598fae3551SRodney W. Grimes /*
17608fae3551SRodney W. Grimes * Get the host or netgroup.
17618fae3551SRodney W. Grimes */
17628fae3551SRodney W. Grimes setnetgrent(cp);
17638fae3551SRodney W. Grimes netgrp = getnetgrent(&hst, &usr, &dom);
17648fae3551SRodney W. Grimes do {
17658fae3551SRodney W. Grimes if (has_host) {
17668fae3551SRodney W. Grimes grp->gr_next = get_grp();
17678fae3551SRodney W. Grimes grp = grp->gr_next;
17688fae3551SRodney W. Grimes }
17698fae3551SRodney W. Grimes if (netgrp) {
17709d70a156SJoerg Wunsch if (hst == 0) {
177174853402SPhilippe Charnier syslog(LOG_ERR,
177274853402SPhilippe Charnier "null hostname in netgroup %s, skipping", cp);
177301d48801SJoerg Wunsch grp->gr_type = GT_IGNORE;
17749d70a156SJoerg Wunsch } else if (get_host(hst, grp, tgrp)) {
177574853402SPhilippe Charnier syslog(LOG_ERR,
177674853402SPhilippe Charnier "bad host %s in netgroup %s, skipping", hst, cp);
1777a968cfd8SJonathan Lemon grp->gr_type = GT_IGNORE;
17788fae3551SRodney W. Grimes }
17798b5a6d67SBill Paul } else if (get_host(cp, grp, tgrp)) {
178074853402SPhilippe Charnier syslog(LOG_ERR, "bad host %s, skipping", cp);
1781a968cfd8SJonathan Lemon grp->gr_type = GT_IGNORE;
17828fae3551SRodney W. Grimes }
17838fae3551SRodney W. Grimes has_host = TRUE;
17848fae3551SRodney W. Grimes } while (netgrp && getnetgrent(&hst, &usr, &dom));
17858fae3551SRodney W. Grimes endnetgrent();
17868fae3551SRodney W. Grimes *endcp = savedc;
17878fae3551SRodney W. Grimes }
17888fae3551SRodney W. Grimes cp = endcp;
17898fae3551SRodney W. Grimes nextfield(&cp, &endcp);
17908fae3551SRodney W. Grimes len = endcp - cp;
17918fae3551SRodney W. Grimes }
179248514c57SMike Karels if (opt_flags & OP_CLASSMASK)
179348514c57SMike Karels syslog(LOG_WARNING,
179448514c57SMike Karels "WARNING: No mask specified for %s, "
179548514c57SMike Karels "using out-of-date default",
179648514c57SMike Karels (&grp->gr_ptr.gt_net)->nt_name);
17978fae3551SRodney W. Grimes if (check_options(dirhead)) {
1798354fce28SConrad Meyer getexp_err(ep, tgrp, NULL);
17998fae3551SRodney W. Grimes goto nextline;
18008fae3551SRodney W. Grimes }
18018fae3551SRodney W. Grimes if (!has_host) {
18026d359f31SIan Dowse grp->gr_type = GT_DEFAULT;
18038fae3551SRodney W. Grimes if (debug)
180474853402SPhilippe Charnier warnx("adding a default entry");
18058fae3551SRodney W. Grimes
18068fae3551SRodney W. Grimes /*
18078fae3551SRodney W. Grimes * Don't allow a network export coincide with a list of
18088fae3551SRodney W. Grimes * host(s) on the same line.
18098fae3551SRodney W. Grimes */
18108fae3551SRodney W. Grimes } else if ((opt_flags & OP_NET) && tgrp->gr_next) {
1811354fce28SConrad Meyer getexp_err(ep, tgrp, "network/host conflict");
18128fae3551SRodney W. Grimes goto nextline;
1813a968cfd8SJonathan Lemon
1814a968cfd8SJonathan Lemon /*
1815a968cfd8SJonathan Lemon * If an export list was specified on this line, make sure
1816a968cfd8SJonathan Lemon * that we have at least one valid entry, otherwise skip it.
1817a968cfd8SJonathan Lemon */
1818a968cfd8SJonathan Lemon } else {
1819a968cfd8SJonathan Lemon grp = tgrp;
1820a968cfd8SJonathan Lemon while (grp && grp->gr_type == GT_IGNORE)
1821a968cfd8SJonathan Lemon grp = grp->gr_next;
1822a968cfd8SJonathan Lemon if (! grp) {
1823354fce28SConrad Meyer getexp_err(ep, tgrp, "no valid entries");
1824a968cfd8SJonathan Lemon goto nextline;
1825a968cfd8SJonathan Lemon }
18268fae3551SRodney W. Grimes }
18278fae3551SRodney W. Grimes
1828bcc1d071SRick Macklem if (v4root_phase == 1) {
1829354fce28SConrad Meyer getexp_err(ep, tgrp, "V4:root, no dirp, ignored");
1830bcc1d071SRick Macklem goto nextline;
1831bcc1d071SRick Macklem }
1832bcc1d071SRick Macklem
18338fae3551SRodney W. Grimes /*
18348fae3551SRodney W. Grimes * Loop through hosts, pushing the exports into the kernel.
18358fae3551SRodney W. Grimes * After loop, tgrp points to the start of the list and
18368fae3551SRodney W. Grimes * grp points to the last entry in the list.
18370f0869bcSRick Macklem * Do not do the do_mount() for passno == 1, since the
18380f0869bcSRick Macklem * second pass will do it, as required.
18398fae3551SRodney W. Grimes */
18408fae3551SRodney W. Grimes grp = tgrp;
18418fae3551SRodney W. Grimes do {
18420f0869bcSRick Macklem grp->gr_exflags = exflags;
1843cc5efddeSRick Macklem cp_cred(&grp->gr_anon, &anon);
18440f0869bcSRick Macklem if (v4root_phase == 2 && passno == 0)
18450f0869bcSRick Macklem LOGDEBUG("do_mount v4root");
18460f0869bcSRick Macklem if (passno == 0 && do_mount(ep, grp, exflags, &anon,
18470f0869bcSRick Macklem dirp, dirplen, &fsb, ep->ex_numsecflavors,
18480f0869bcSRick Macklem ep->ex_secflavors)) {
1849354fce28SConrad Meyer getexp_err(ep, tgrp, NULL);
18508fae3551SRodney W. Grimes goto nextline;
18518fae3551SRodney W. Grimes }
18528fae3551SRodney W. Grimes } while (grp->gr_next && (grp = grp->gr_next));
18538fae3551SRodney W. Grimes
18548fae3551SRodney W. Grimes /*
1855bcc1d071SRick Macklem * For V4: don't enter in mount lists.
1856bcc1d071SRick Macklem */
185773f4ccbdSRick Macklem if (v4root_phase > 0 && v4root_phase <= 2) {
185873f4ccbdSRick Macklem /*
1859c2ec1113SRick Macklem * These structures are used for the reload,
18600f0869bcSRick Macklem * so save them for that case. Otherwise, just
186173f4ccbdSRick Macklem * free them up now.
186273f4ccbdSRick Macklem */
18630f0869bcSRick Macklem if (passno == 1 && ep != NULL) {
18640f0869bcSRick Macklem savgrp = tgrp;
18650f0869bcSRick Macklem while (tgrp != NULL) {
18660f0869bcSRick Macklem /*
18670f0869bcSRick Macklem * Save the security flavors and exflags
18680f0869bcSRick Macklem * for this host set in the groups.
18690f0869bcSRick Macklem */
18700f0869bcSRick Macklem tgrp->gr_numsecflavors =
18710f0869bcSRick Macklem ep->ex_numsecflavors;
18720f0869bcSRick Macklem if (ep->ex_numsecflavors > 0)
18730f0869bcSRick Macklem memcpy(tgrp->gr_secflavors,
18740f0869bcSRick Macklem ep->ex_secflavors,
18750f0869bcSRick Macklem sizeof(ep->ex_secflavors));
18760f0869bcSRick Macklem tgrp = tgrp->gr_next;
18770f0869bcSRick Macklem }
18780f0869bcSRick Macklem if (v4root_ep == NULL) {
18790f0869bcSRick Macklem v4root_ep = ep;
18800f0869bcSRick Macklem ep = NULL; /* Don't free below. */
18810f0869bcSRick Macklem }
18820f0869bcSRick Macklem grp->gr_next = v4root_ep->ex_grphead;
18830f0869bcSRick Macklem v4root_ep->ex_grphead = savgrp;
18840f0869bcSRick Macklem }
188573f4ccbdSRick Macklem if (ep != NULL)
188673f4ccbdSRick Macklem free_exp(ep);
188773f4ccbdSRick Macklem while (tgrp != NULL) {
188873f4ccbdSRick Macklem grp = tgrp;
188973f4ccbdSRick Macklem tgrp = tgrp->gr_next;
189073f4ccbdSRick Macklem free_grp(grp);
189173f4ccbdSRick Macklem }
1892bcc1d071SRick Macklem goto nextline;
189373f4ccbdSRick Macklem }
1894bcc1d071SRick Macklem
1895bcc1d071SRick Macklem /*
18968fae3551SRodney W. Grimes * Success. Update the data structures.
18978fae3551SRodney W. Grimes */
18988fae3551SRodney W. Grimes if (has_host) {
18990f0869bcSRick Macklem hang_dirp(dirhead, tgrp, ep, opt_flags, &anon, exflags);
1900711d44eeSRick Macklem grp->gr_next = ep->ex_grphead;
1901711d44eeSRick Macklem ep->ex_grphead = tgrp;
19028fae3551SRodney W. Grimes } else {
19038fae3551SRodney W. Grimes hang_dirp(dirhead, (struct grouplist *)NULL, ep,
19040f0869bcSRick Macklem opt_flags, &anon, exflags);
19058fae3551SRodney W. Grimes free_grp(grp);
19068fae3551SRodney W. Grimes }
19078fae3551SRodney W. Grimes dirhead = (struct dirlist *)NULL;
19088fae3551SRodney W. Grimes if ((ep->ex_flag & EX_LINKED) == 0) {
190946a6b5c4SRick Macklem insert_exports(ep, exphead);
19108fae3551SRodney W. Grimes
19118fae3551SRodney W. Grimes ep->ex_flag |= EX_LINKED;
19128fae3551SRodney W. Grimes }
19138fae3551SRodney W. Grimes nextline:
1914bcc1d071SRick Macklem v4root_phase = 0;
19158fae3551SRodney W. Grimes if (dirhead) {
19168fae3551SRodney W. Grimes free_dir(dirhead);
19178fae3551SRodney W. Grimes dirhead = (struct dirlist *)NULL;
19188fae3551SRodney W. Grimes }
19192ffad162SRick Macklem if (anon.cr_groups != anon.cr_smallgrps) {
19202ffad162SRick Macklem free(anon.cr_groups);
19212ffad162SRick Macklem anon.cr_groups = NULL;
19222ffad162SRick Macklem }
19238fae3551SRodney W. Grimes }
192496968c22SPawel Jakub Dawidek }
192596968c22SPawel Jakub Dawidek
192696968c22SPawel Jakub Dawidek /*
192796968c22SPawel Jakub Dawidek * Get the export list from all specified files
192896968c22SPawel Jakub Dawidek */
192919c46d8cSEdward Tomasz Napierala static void
get_exportlist(int passno)19300f0869bcSRick Macklem get_exportlist(int passno)
193196968c22SPawel Jakub Dawidek {
193296968c22SPawel Jakub Dawidek struct export_args export;
193396968c22SPawel Jakub Dawidek struct iovec *iov;
19343e08dc74SRick Macklem struct statfs *mntbufp;
193596968c22SPawel Jakub Dawidek char errmsg[255];
193609673fc0SRick Macklem int error, i, nfs_maxvers, num;
193796968c22SPawel Jakub Dawidek int iovlen;
1938bcc1d071SRick Macklem struct nfsex_args eargs;
19390f0869bcSRick Macklem FILE *debug_file;
194009673fc0SRick Macklem size_t nfs_maxvers_size;
194196968c22SPawel Jakub Dawidek
19420f0869bcSRick Macklem if ((debug_file = fopen(_PATH_MOUNTDDEBUG, "r")) != NULL) {
19430f0869bcSRick Macklem fclose(debug_file);
19440f0869bcSRick Macklem logdebug = 1;
19450f0869bcSRick Macklem } else
19460f0869bcSRick Macklem logdebug = 0;
19470f0869bcSRick Macklem LOGDEBUG("passno=%d", passno);
1948bcc1d071SRick Macklem v4root_dirpath[0] = '\0';
19490f0869bcSRick Macklem free_v4rootexp();
19500f0869bcSRick Macklem if (passno == 1) {
19510f0869bcSRick Macklem /*
19520f0869bcSRick Macklem * Save the current lists as old ones, so that the new lists
19530f0869bcSRick Macklem * can be compared with the old ones in the 2nd pass.
19540f0869bcSRick Macklem */
19550f0869bcSRick Macklem for (i = 0; i < exphashsize; i++) {
19560f0869bcSRick Macklem SLIST_FIRST(&oldexphead[i]) = SLIST_FIRST(&exphead[i]);
19570f0869bcSRick Macklem SLIST_INIT(&exphead[i]);
19580f0869bcSRick Macklem }
19590f0869bcSRick Macklem
19600f0869bcSRick Macklem /* Note that the public fh has not yet been set. */
19610f0869bcSRick Macklem has_set_publicfh = 0;
19620f0869bcSRick Macklem
19630f0869bcSRick Macklem /* Read the export file(s) and process them */
19640f0869bcSRick Macklem read_exportfile(passno);
19650f0869bcSRick Macklem } else {
19660f0869bcSRick Macklem /*
19670f0869bcSRick Macklem * Just make the old lists empty.
19680f0869bcSRick Macklem * exphashsize == 0 for the first call, before oldexphead
19690f0869bcSRick Macklem * has been initialized-->loop won't be executed.
19700f0869bcSRick Macklem */
19710f0869bcSRick Macklem for (i = 0; i < exphashsize; i++)
19720f0869bcSRick Macklem SLIST_INIT(&oldexphead[i]);
19730f0869bcSRick Macklem }
19740f0869bcSRick Macklem
197596968c22SPawel Jakub Dawidek bzero(&export, sizeof(export));
197696968c22SPawel Jakub Dawidek export.ex_flags = MNT_DELEXPORT;
197796968c22SPawel Jakub Dawidek iov = NULL;
197896968c22SPawel Jakub Dawidek iovlen = 0;
197996968c22SPawel Jakub Dawidek bzero(errmsg, sizeof(errmsg));
198096968c22SPawel Jakub Dawidek
19810f0869bcSRick Macklem if (suspend_nfsd != 0)
19820f0869bcSRick Macklem (void)nfssvc(NFSSVC_SUSPENDNFSD, NULL);
198396968c22SPawel Jakub Dawidek /*
19840f0869bcSRick Macklem * Delete the old V4 root dir.
1985bcc1d071SRick Macklem */
1986bcc1d071SRick Macklem bzero(&eargs, sizeof (eargs));
1987bcc1d071SRick Macklem eargs.export.ex_flags = MNT_DELEXPORT;
1988cc5efddeSRick Macklem if (nfssvc(NFSSVC_V4ROOTEXPORT | NFSSVC_NEWSTRUCT, (caddr_t)&eargs) < 0 &&
1989bcc1d071SRick Macklem errno != ENOENT)
1990bcc1d071SRick Macklem syslog(LOG_ERR, "Can't delete exports for V4:");
1991bcc1d071SRick Macklem
19920f0869bcSRick Macklem build_iovec(&iov, &iovlen, "fstype", NULL, 0);
19930f0869bcSRick Macklem build_iovec(&iov, &iovlen, "fspath", NULL, 0);
19940f0869bcSRick Macklem build_iovec(&iov, &iovlen, "from", NULL, 0);
19950f0869bcSRick Macklem build_iovec(&iov, &iovlen, "update", NULL, 0);
19960f0869bcSRick Macklem build_iovec(&iov, &iovlen, "export", &export,
19970f0869bcSRick Macklem sizeof(export));
19980f0869bcSRick Macklem build_iovec(&iov, &iovlen, "errmsg", errmsg,
19990f0869bcSRick Macklem sizeof(errmsg));
20000f0869bcSRick Macklem
2001bcc1d071SRick Macklem /*
20020f0869bcSRick Macklem * For passno == 1, compare the old and new lists updating the kernel
20030f0869bcSRick Macklem * exports for any cases that have changed.
20040f0869bcSRick Macklem * This call is doing the second pass through the lists.
20050f0869bcSRick Macklem * If it fails, fall back on the bulk reload.
20060f0869bcSRick Macklem */
20070f0869bcSRick Macklem if (passno == 1 && compare_nmount_exportlist(iov, iovlen, errmsg) ==
20080f0869bcSRick Macklem 0) {
20090f0869bcSRick Macklem LOGDEBUG("compareok");
20100f0869bcSRick Macklem /* Free up the old lists. */
20110f0869bcSRick Macklem free_exports(oldexphead);
20120f0869bcSRick Macklem } else {
20130f0869bcSRick Macklem LOGDEBUG("doing passno=0");
20140f0869bcSRick Macklem /*
20150f0869bcSRick Macklem * Clear flag that notes if a public fh has been exported.
20160f0869bcSRick Macklem * It is set by do_mount() if MNT_EXPUBLIC is set for the entry.
2017bcc1d071SRick Macklem */
2018bcc1d071SRick Macklem has_publicfh = 0;
2019bcc1d071SRick Macklem
20200f0869bcSRick Macklem /* exphead == NULL if not yet allocated (first call). */
20210f0869bcSRick Macklem if (exphead != NULL) {
20220f0869bcSRick Macklem /*
20230f0869bcSRick Macklem * First, get rid of the old lists.
20240f0869bcSRick Macklem */
20250f0869bcSRick Macklem free_exports(exphead);
20260f0869bcSRick Macklem free_exports(oldexphead);
20270f0869bcSRick Macklem }
20280f0869bcSRick Macklem
2029bcc1d071SRick Macklem /*
203096968c22SPawel Jakub Dawidek * And delete exports that are in the kernel for all local
203196968c22SPawel Jakub Dawidek * filesystems.
20320f0869bcSRick Macklem * XXX: Should know how to handle all local exportable
20330f0869bcSRick Macklem * filesystems.
203496968c22SPawel Jakub Dawidek */
203596968c22SPawel Jakub Dawidek num = getmntinfo(&mntbufp, MNT_NOWAIT);
203696968c22SPawel Jakub Dawidek
203746a6b5c4SRick Macklem /* Allocate hash tables, for first call. */
203846a6b5c4SRick Macklem if (exphead == NULL) {
203946a6b5c4SRick Macklem /* Target an average linked list length of 10. */
204046a6b5c4SRick Macklem exphashsize = num / 10;
204146a6b5c4SRick Macklem if (exphashsize < 1)
204246a6b5c4SRick Macklem exphashsize = 1;
204346a6b5c4SRick Macklem else if (exphashsize > 100000)
204446a6b5c4SRick Macklem exphashsize = 100000;
204546a6b5c4SRick Macklem exphead = malloc(exphashsize * sizeof(*exphead));
20460f0869bcSRick Macklem oldexphead = malloc(exphashsize * sizeof(*oldexphead));
20470f0869bcSRick Macklem if (exphead == NULL || oldexphead == NULL)
20480f0869bcSRick Macklem errx(1, "Can't malloc hash tables");
204946a6b5c4SRick Macklem
20500f0869bcSRick Macklem for (i = 0; i < exphashsize; i++) {
205146a6b5c4SRick Macklem SLIST_INIT(&exphead[i]);
20520f0869bcSRick Macklem SLIST_INIT(&oldexphead[i]);
205346a6b5c4SRick Macklem }
205496968c22SPawel Jakub Dawidek }
205596968c22SPawel Jakub Dawidek
20563e08dc74SRick Macklem for (i = 0; i < num; i++)
20573e08dc74SRick Macklem delete_export(iov, iovlen, &mntbufp[i], errmsg);
205896968c22SPawel Jakub Dawidek
20590f0869bcSRick Macklem
20600f0869bcSRick Macklem /* Read the export file(s) and process them */
20610f0869bcSRick Macklem read_exportfile(0);
20620f0869bcSRick Macklem }
20630f0869bcSRick Macklem
206409673fc0SRick Macklem if (strlen(v4root_dirpath) == 0) {
206509673fc0SRick Macklem /* Check to see if a V4: line is needed. */
206609673fc0SRick Macklem nfs_maxvers_size = sizeof(nfs_maxvers);
206709673fc0SRick Macklem error = sysctlbyname("vfs.nfsd.server_max_nfsvers",
206809673fc0SRick Macklem &nfs_maxvers, &nfs_maxvers_size, NULL, 0);
206909673fc0SRick Macklem if (error != 0 || nfs_maxvers < NFS_VER2 || nfs_maxvers >
207009673fc0SRick Macklem NFS_VER4) {
207109673fc0SRick Macklem syslog(LOG_ERR, "sysctlbyname(vfs.nfsd."
207209673fc0SRick Macklem "server_max_nfsvers) failed, defaulting to NFSv3");
207309673fc0SRick Macklem nfs_maxvers = NFS_VER3;
207409673fc0SRick Macklem }
207509673fc0SRick Macklem if (nfs_maxvers == NFS_VER4)
207609673fc0SRick Macklem syslog(LOG_ERR, "NFSv4 requires at least one V4: line");
207709673fc0SRick Macklem }
207809673fc0SRick Macklem
207996968c22SPawel Jakub Dawidek if (iov != NULL) {
208096968c22SPawel Jakub Dawidek /* Free strings allocated by strdup() in getmntopts.c */
208196968c22SPawel Jakub Dawidek free(iov[0].iov_base); /* fstype */
208296968c22SPawel Jakub Dawidek free(iov[2].iov_base); /* fspath */
208396968c22SPawel Jakub Dawidek free(iov[4].iov_base); /* from */
208496968c22SPawel Jakub Dawidek free(iov[6].iov_base); /* update */
208596968c22SPawel Jakub Dawidek free(iov[8].iov_base); /* export */
208696968c22SPawel Jakub Dawidek free(iov[10].iov_base); /* errmsg */
208796968c22SPawel Jakub Dawidek
208896968c22SPawel Jakub Dawidek /* free iov, allocated by realloc() */
208996968c22SPawel Jakub Dawidek free(iov);
209096968c22SPawel Jakub Dawidek iovlen = 0;
209196968c22SPawel Jakub Dawidek }
209296968c22SPawel Jakub Dawidek
2093bcc1d071SRick Macklem /*
2094bcc1d071SRick Macklem * If there was no public fh, clear any previous one set.
2095bcc1d071SRick Macklem */
20960f0869bcSRick Macklem if (has_publicfh == 0) {
20970f0869bcSRick Macklem LOGDEBUG("clear public fh");
2098bcc1d071SRick Macklem (void) nfssvc(NFSSVC_NOPUBLICFH, NULL);
20990f0869bcSRick Macklem }
2100c548eb5cSRick Macklem
2101c548eb5cSRick Macklem /* Resume the nfsd. If they weren't suspended, this is harmless. */
2102c548eb5cSRick Macklem (void)nfssvc(NFSSVC_RESUMENFSD, NULL);
21030f0869bcSRick Macklem LOGDEBUG("eo get_exportlist");
210496968c22SPawel Jakub Dawidek }
21058fae3551SRodney W. Grimes
21068fae3551SRodney W. Grimes /*
21071a9a992fSRick Macklem * Insert an export entry in the appropriate list.
21081a9a992fSRick Macklem */
21091a9a992fSRick Macklem static void
insert_exports(struct exportlist * ep,struct exportlisthead * exhp)21101a9a992fSRick Macklem insert_exports(struct exportlist *ep, struct exportlisthead *exhp)
21111a9a992fSRick Macklem {
211246a6b5c4SRick Macklem uint32_t i;
21131a9a992fSRick Macklem
211446a6b5c4SRick Macklem i = EXPHASH(&ep->ex_fs);
21150f0869bcSRick Macklem LOGDEBUG("fs=%s hash=%i", ep->ex_fsdir, i);
211646a6b5c4SRick Macklem SLIST_INSERT_HEAD(&exhp[i], ep, entries);
21171a9a992fSRick Macklem }
21181a9a992fSRick Macklem
21191a9a992fSRick Macklem /*
21201a9a992fSRick Macklem * Free up the exports lists passed in as arguments.
21211a9a992fSRick Macklem */
21221a9a992fSRick Macklem static void
free_exports(struct exportlisthead * exhp)21231a9a992fSRick Macklem free_exports(struct exportlisthead *exhp)
21241a9a992fSRick Macklem {
21251a9a992fSRick Macklem struct exportlist *ep, *ep2;
212646a6b5c4SRick Macklem int i;
21271a9a992fSRick Macklem
212846a6b5c4SRick Macklem for (i = 0; i < exphashsize; i++) {
212946a6b5c4SRick Macklem SLIST_FOREACH_SAFE(ep, &exhp[i], entries, ep2) {
213046a6b5c4SRick Macklem SLIST_REMOVE(&exhp[i], ep, exportlist, entries);
21311a9a992fSRick Macklem free_exp(ep);
21321a9a992fSRick Macklem }
213346a6b5c4SRick Macklem SLIST_INIT(&exhp[i]);
213446a6b5c4SRick Macklem }
21351a9a992fSRick Macklem }
21361a9a992fSRick Macklem
21371a9a992fSRick Macklem /*
21383e08dc74SRick Macklem * Read the exports file(s) and call get_exportlist_one() for each line.
21393e08dc74SRick Macklem */
21403e08dc74SRick Macklem static void
read_exportfile(int passno)21410f0869bcSRick Macklem read_exportfile(int passno)
21423e08dc74SRick Macklem {
21433e08dc74SRick Macklem int done, i;
21443e08dc74SRick Macklem
21453e08dc74SRick Macklem /*
21463e08dc74SRick Macklem * Read in the exports file and build the list, calling
21473e08dc74SRick Macklem * nmount() as we go along to push the export rules into the kernel.
21483e08dc74SRick Macklem */
21493e08dc74SRick Macklem done = 0;
21503e08dc74SRick Macklem for (i = 0; exnames[i] != NULL; i++) {
21513e08dc74SRick Macklem if (debug)
21523e08dc74SRick Macklem warnx("reading exports from %s", exnames[i]);
21533e08dc74SRick Macklem if ((exp_file = fopen(exnames[i], "r")) == NULL) {
21543e08dc74SRick Macklem syslog(LOG_WARNING, "can't open %s", exnames[i]);
21553e08dc74SRick Macklem continue;
21563e08dc74SRick Macklem }
21570f0869bcSRick Macklem get_exportlist_one(passno);
21583e08dc74SRick Macklem fclose(exp_file);
21593e08dc74SRick Macklem done++;
21603e08dc74SRick Macklem }
21613e08dc74SRick Macklem if (done == 0) {
21623e08dc74SRick Macklem syslog(LOG_ERR, "can't open any exports file");
21633e08dc74SRick Macklem exit(2);
21643e08dc74SRick Macklem }
21653e08dc74SRick Macklem }
21663e08dc74SRick Macklem
21673e08dc74SRick Macklem /*
21680f0869bcSRick Macklem * Compare the export lists against the old ones and do nmount() operations
21690f0869bcSRick Macklem * for any cases that have changed. This avoids doing nmount() for entries
21700f0869bcSRick Macklem * that have not changed.
21710f0869bcSRick Macklem * Return 0 upon success, 1 otherwise.
21720f0869bcSRick Macklem */
21730f0869bcSRick Macklem static int
compare_nmount_exportlist(struct iovec * iov,int iovlen,char * errmsg)21740f0869bcSRick Macklem compare_nmount_exportlist(struct iovec *iov, int iovlen, char *errmsg)
21750f0869bcSRick Macklem {
21760f0869bcSRick Macklem struct exportlist *ep, *oep;
21770f0869bcSRick Macklem struct grouplist *grp;
21780f0869bcSRick Macklem struct statfs fs, ofs;
21790f0869bcSRick Macklem int i, ret;
21800f0869bcSRick Macklem
21810f0869bcSRick Macklem /*
21820f0869bcSRick Macklem * Loop through the current list and look for an entry in the old
21830f0869bcSRick Macklem * list.
21840f0869bcSRick Macklem * If found, check to see if it the same.
21850f0869bcSRick Macklem * If it is not the same, delete and re-export.
21860f0869bcSRick Macklem * Then mark it done on the old list.
21870f0869bcSRick Macklem * else (not found)
21880f0869bcSRick Macklem * export it.
21890f0869bcSRick Macklem * Any entries left in the old list after processing must have their
21900f0869bcSRick Macklem * exports deleted.
21910f0869bcSRick Macklem */
21920f0869bcSRick Macklem for (i = 0; i < exphashsize; i++)
21930f0869bcSRick Macklem SLIST_FOREACH(ep, &exphead[i], entries) {
21940f0869bcSRick Macklem LOGDEBUG("foreach ep=%s", ep->ex_fsdir);
21950f0869bcSRick Macklem oep = ex_search(&ep->ex_fs, oldexphead);
21960f0869bcSRick Macklem if (oep != NULL) {
21970f0869bcSRick Macklem /*
21980f0869bcSRick Macklem * Check the mount paths are the same.
21990f0869bcSRick Macklem * If not, return 1 so that the reload of the
22000f0869bcSRick Macklem * exports will be done in bulk, the
22010f0869bcSRick Macklem * passno == 0 way.
22020f0869bcSRick Macklem */
22030f0869bcSRick Macklem LOGDEBUG("found old exp");
22040f0869bcSRick Macklem if (strcmp(ep->ex_fsdir, oep->ex_fsdir) != 0)
22050f0869bcSRick Macklem return (1);
22060f0869bcSRick Macklem LOGDEBUG("same fsdir");
22070f0869bcSRick Macklem /*
22080f0869bcSRick Macklem * Test to see if the entry is the same.
22090f0869bcSRick Macklem * If not the same delete exports and
22100f0869bcSRick Macklem * re-export.
22110f0869bcSRick Macklem */
22120f0869bcSRick Macklem if (compare_export(ep, oep) != 0) {
22130f0869bcSRick Macklem /*
22140f0869bcSRick Macklem * Clear has_publicfh if if was set
22150f0869bcSRick Macklem * in the old exports, but only if it
22160f0869bcSRick Macklem * has not been set during processing of
22170f0869bcSRick Macklem * the exports for this pass, as
22180f0869bcSRick Macklem * indicated by has_set_publicfh.
22190f0869bcSRick Macklem */
22200f0869bcSRick Macklem if (has_set_publicfh == 0 &&
22210f0869bcSRick Macklem (oep->ex_flag & EX_PUBLICFH) != 0)
22220f0869bcSRick Macklem has_publicfh = 0;
22230f0869bcSRick Macklem
22240f0869bcSRick Macklem /* Delete and re-export. */
22250f0869bcSRick Macklem if (statfs(ep->ex_fsdir, &fs) < 0)
22260f0869bcSRick Macklem return (1);
22270f0869bcSRick Macklem delete_export(iov, iovlen, &fs, errmsg);
22280f0869bcSRick Macklem ret = do_export_mount(ep, &fs);
22290f0869bcSRick Macklem if (ret != 0)
22300f0869bcSRick Macklem return (ret);
22310f0869bcSRick Macklem }
22320f0869bcSRick Macklem oep->ex_flag |= EX_DONE;
22330f0869bcSRick Macklem LOGDEBUG("exdone");
22340f0869bcSRick Macklem } else {
22350f0869bcSRick Macklem LOGDEBUG("not found so export");
22360f0869bcSRick Macklem /* Not found, so do export. */
22370f0869bcSRick Macklem if (statfs(ep->ex_fsdir, &fs) < 0)
22380f0869bcSRick Macklem return (1);
22390f0869bcSRick Macklem ret = do_export_mount(ep, &fs);
22400f0869bcSRick Macklem if (ret != 0)
22410f0869bcSRick Macklem return (ret);
22420f0869bcSRick Macklem }
22430f0869bcSRick Macklem }
22440f0869bcSRick Macklem
22450f0869bcSRick Macklem /* Delete exports not done. */
22460f0869bcSRick Macklem for (i = 0; i < exphashsize; i++)
22470f0869bcSRick Macklem SLIST_FOREACH(oep, &oldexphead[i], entries) {
22480f0869bcSRick Macklem if ((oep->ex_flag & EX_DONE) == 0) {
22490f0869bcSRick Macklem LOGDEBUG("not done delete=%s", oep->ex_fsdir);
22500f0869bcSRick Macklem if (statfs(oep->ex_fsdir, &ofs) >= 0 &&
2251245bfd34SRyan Moeller fsidcmp(&oep->ex_fs, &ofs.f_fsid) == 0) {
22520f0869bcSRick Macklem LOGDEBUG("do delete");
22530f0869bcSRick Macklem /*
22540f0869bcSRick Macklem * Clear has_publicfh if if was set
22550f0869bcSRick Macklem * in the old exports, but only if it
22560f0869bcSRick Macklem * has not been set during processing of
22570f0869bcSRick Macklem * the exports for this pass, as
22580f0869bcSRick Macklem * indicated by has_set_publicfh.
22590f0869bcSRick Macklem */
22600f0869bcSRick Macklem if (has_set_publicfh == 0 &&
22610f0869bcSRick Macklem (oep->ex_flag & EX_PUBLICFH) != 0)
22620f0869bcSRick Macklem has_publicfh = 0;
22630f0869bcSRick Macklem
22640f0869bcSRick Macklem delete_export(iov, iovlen, &ofs,
22650f0869bcSRick Macklem errmsg);
22660f0869bcSRick Macklem }
22670f0869bcSRick Macklem }
22680f0869bcSRick Macklem }
22690f0869bcSRick Macklem
22700f0869bcSRick Macklem /* Do the V4 root exports, as required. */
22710f0869bcSRick Macklem grp = NULL;
22720f0869bcSRick Macklem if (v4root_ep != NULL)
22730f0869bcSRick Macklem grp = v4root_ep->ex_grphead;
22740f0869bcSRick Macklem v4root_phase = 2;
22750f0869bcSRick Macklem while (v4root_ep != NULL && grp != NULL) {
22760f0869bcSRick Macklem LOGDEBUG("v4root expath=%s", v4root_dirpath);
22770f0869bcSRick Macklem ret = do_mount(v4root_ep, grp, grp->gr_exflags, &grp->gr_anon,
22780f0869bcSRick Macklem v4root_dirpath, strlen(v4root_dirpath), &fs,
22790f0869bcSRick Macklem grp->gr_numsecflavors, grp->gr_secflavors);
22800f0869bcSRick Macklem if (ret != 0) {
22810f0869bcSRick Macklem v4root_phase = 0;
22820f0869bcSRick Macklem return (ret);
22830f0869bcSRick Macklem }
22840f0869bcSRick Macklem grp = grp->gr_next;
22850f0869bcSRick Macklem }
22860f0869bcSRick Macklem v4root_phase = 0;
22870f0869bcSRick Macklem free_v4rootexp();
22880f0869bcSRick Macklem return (0);
22890f0869bcSRick Macklem }
22900f0869bcSRick Macklem
22910f0869bcSRick Macklem /*
22920f0869bcSRick Macklem * Compare old and current exportlist entries for the fsid and return 0
22930f0869bcSRick Macklem * if they are the same, 1 otherwise.
22940f0869bcSRick Macklem */
22950f0869bcSRick Macklem static int
compare_export(struct exportlist * ep,struct exportlist * oep)22960f0869bcSRick Macklem compare_export(struct exportlist *ep, struct exportlist *oep)
22970f0869bcSRick Macklem {
22980f0869bcSRick Macklem struct grouplist *grp, *ogrp;
22990f0869bcSRick Macklem
23000f0869bcSRick Macklem if (strcmp(ep->ex_fsdir, oep->ex_fsdir) != 0)
23010f0869bcSRick Macklem return (1);
23020f0869bcSRick Macklem if ((ep->ex_flag & EX_DEFSET) != (oep->ex_flag & EX_DEFSET))
23030f0869bcSRick Macklem return (1);
23040f0869bcSRick Macklem if ((ep->ex_defdir != NULL && oep->ex_defdir == NULL) ||
23050f0869bcSRick Macklem (ep->ex_defdir == NULL && oep->ex_defdir != NULL))
23060f0869bcSRick Macklem return (1);
23070f0869bcSRick Macklem if (ep->ex_defdir != NULL && (ep->ex_defdir->dp_flag & DP_DEFSET) !=
23080f0869bcSRick Macklem (oep->ex_defdir->dp_flag & DP_DEFSET))
23090f0869bcSRick Macklem return (1);
23100f0869bcSRick Macklem if ((ep->ex_flag & EX_DEFSET) != 0 && (ep->ex_defnumsecflavors !=
23110f0869bcSRick Macklem oep->ex_defnumsecflavors || ep->ex_defexflags !=
23120f0869bcSRick Macklem oep->ex_defexflags || compare_cred(&ep->ex_defanon,
23130f0869bcSRick Macklem &oep->ex_defanon) != 0 || compare_secflavor(ep->ex_defsecflavors,
23140f0869bcSRick Macklem oep->ex_defsecflavors, ep->ex_defnumsecflavors) != 0))
23150f0869bcSRick Macklem return (1);
23160f0869bcSRick Macklem
23170f0869bcSRick Macklem /* Now, check all the groups. */
23180f0869bcSRick Macklem for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = ogrp->gr_next)
23190f0869bcSRick Macklem ogrp->gr_flag = 0;
23200f0869bcSRick Macklem for (grp = ep->ex_grphead; grp != NULL; grp = grp->gr_next) {
23210f0869bcSRick Macklem for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp =
23220f0869bcSRick Macklem ogrp->gr_next)
23230f0869bcSRick Macklem if ((ogrp->gr_flag & GR_FND) == 0 &&
23240f0869bcSRick Macklem grp->gr_numsecflavors == ogrp->gr_numsecflavors &&
23250f0869bcSRick Macklem grp->gr_exflags == ogrp->gr_exflags &&
23260f0869bcSRick Macklem compare_cred(&grp->gr_anon, &ogrp->gr_anon) == 0 &&
23270f0869bcSRick Macklem compare_secflavor(grp->gr_secflavors,
23280f0869bcSRick Macklem ogrp->gr_secflavors, grp->gr_numsecflavors) == 0)
23290f0869bcSRick Macklem break;
23300f0869bcSRick Macklem if (ogrp != NULL)
23310f0869bcSRick Macklem ogrp->gr_flag |= GR_FND;
23320f0869bcSRick Macklem else
23330f0869bcSRick Macklem return (1);
23340f0869bcSRick Macklem }
23350f0869bcSRick Macklem for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = ogrp->gr_next)
23360f0869bcSRick Macklem if ((ogrp->gr_flag & GR_FND) == 0)
23370f0869bcSRick Macklem return (1);
23380f0869bcSRick Macklem return (0);
23390f0869bcSRick Macklem }
23400f0869bcSRick Macklem
23410f0869bcSRick Macklem /*
23420f0869bcSRick Macklem * This algorithm compares two arrays of "n" items. It returns 0 if they are
23430f0869bcSRick Macklem * the "same" and 1 otherwise. Although suboptimal, it is always safe to
23440f0869bcSRick Macklem * return 1, which makes compare_nmount_export() reload the exports entry.
23450f0869bcSRick Macklem * "same" refers to having the same set of values in the two arrays.
23460f0869bcSRick Macklem * The arrays are in no particular order and duplicates (multiple entries
23470f0869bcSRick Macklem * in an array with the same value) is allowed.
2348c77cc846SElyes Haouas * The algorithm is inefficient, but the common case of identical arrays is
23490f0869bcSRick Macklem * handled first and "n" is normally fairly small.
23500f0869bcSRick Macklem * Since the two functions need the same algorithm but for arrays of
23510f0869bcSRick Macklem * different types (gid_t vs int), this is done as a macro.
23520f0869bcSRick Macklem */
23530f0869bcSRick Macklem #define COMPARE_ARRAYS(a1, a2, n) \
23540f0869bcSRick Macklem do { \
23550f0869bcSRick Macklem int fnd, fndarray[(n)], i, j; \
23560f0869bcSRick Macklem /* Handle common case of identical arrays. */ \
23570f0869bcSRick Macklem for (i = 0; i < (n); i++) \
23580f0869bcSRick Macklem if ((a1)[i] != (a2)[i]) \
23590f0869bcSRick Macklem break; \
23600f0869bcSRick Macklem if (i == (n)) \
23610f0869bcSRick Macklem return (0); \
23620f0869bcSRick Macklem for (i = 0; i < (n); i++) \
23630f0869bcSRick Macklem fndarray[i] = 0; \
23640f0869bcSRick Macklem for (i = 0; i < (n); i++) { \
23650f0869bcSRick Macklem fnd = 0; \
23660f0869bcSRick Macklem for (j = 0; j < (n); j++) { \
23670f0869bcSRick Macklem if ((a1)[i] == (a2)[j]) { \
23680f0869bcSRick Macklem fndarray[j] = 1; \
23690f0869bcSRick Macklem fnd = 1; \
23700f0869bcSRick Macklem } \
23710f0869bcSRick Macklem } \
23720f0869bcSRick Macklem if (fnd == 0) \
23730f0869bcSRick Macklem return (1); \
23740f0869bcSRick Macklem } \
23750f0869bcSRick Macklem for (i = 0; i < (n); i++) \
23760f0869bcSRick Macklem if (fndarray[i] == 0) \
23770f0869bcSRick Macklem return (1); \
23780f0869bcSRick Macklem return (0); \
23790f0869bcSRick Macklem } while (0)
23800f0869bcSRick Macklem
23810f0869bcSRick Macklem /*
2382cc5efddeSRick Macklem * Compare two struct expcred's. Return 0 if the same and 1 otherwise.
23830f0869bcSRick Macklem */
23840f0869bcSRick Macklem static int
compare_cred(struct expcred * cr0,struct expcred * cr1)2385cc5efddeSRick Macklem compare_cred(struct expcred *cr0, struct expcred *cr1)
23860f0869bcSRick Macklem {
23870f0869bcSRick Macklem
23880f0869bcSRick Macklem if (cr0->cr_uid != cr1->cr_uid || cr0->cr_ngroups != cr1->cr_ngroups)
23890f0869bcSRick Macklem return (1);
23900f0869bcSRick Macklem
23910f0869bcSRick Macklem COMPARE_ARRAYS(cr0->cr_groups, cr1->cr_groups, cr0->cr_ngroups);
23920f0869bcSRick Macklem }
23930f0869bcSRick Macklem
23940f0869bcSRick Macklem /*
23950f0869bcSRick Macklem * Compare two lists of security flavors. Return 0 if the same and 1 otherwise.
23960f0869bcSRick Macklem */
23970f0869bcSRick Macklem static int
compare_secflavor(int * sec1,int * sec2,int nsec)23980f0869bcSRick Macklem compare_secflavor(int *sec1, int *sec2, int nsec)
23990f0869bcSRick Macklem {
24000f0869bcSRick Macklem
24010f0869bcSRick Macklem COMPARE_ARRAYS(sec1, sec2, nsec);
24020f0869bcSRick Macklem }
24030f0869bcSRick Macklem
24040f0869bcSRick Macklem /*
24053e08dc74SRick Macklem * Delete an exports entry.
24063e08dc74SRick Macklem */
24073e08dc74SRick Macklem static void
delete_export(struct iovec * iov,int iovlen,struct statfs * fsp,char * errmsg)24083e08dc74SRick Macklem delete_export(struct iovec *iov, int iovlen, struct statfs *fsp, char *errmsg)
24093e08dc74SRick Macklem {
24103e08dc74SRick Macklem struct xvfsconf vfc;
24113e08dc74SRick Macklem
24123e08dc74SRick Macklem if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) {
24133e08dc74SRick Macklem syslog(LOG_ERR, "getvfsbyname() failed for %s",
24143e08dc74SRick Macklem fsp->f_fstypename);
24153e08dc74SRick Macklem return;
24163e08dc74SRick Macklem }
24173e08dc74SRick Macklem
24183e08dc74SRick Macklem /*
24193e08dc74SRick Macklem * We do not need to delete "export" flag from
24203e08dc74SRick Macklem * filesystems that do not have it set.
24213e08dc74SRick Macklem */
24223e08dc74SRick Macklem if (!(fsp->f_flags & MNT_EXPORTED))
24233e08dc74SRick Macklem return;
24243e08dc74SRick Macklem /*
24253e08dc74SRick Macklem * Do not delete export for network filesystem by
24263e08dc74SRick Macklem * passing "export" arg to nmount().
24273e08dc74SRick Macklem * It only makes sense to do this for local filesystems.
24283e08dc74SRick Macklem */
24293e08dc74SRick Macklem if (vfc.vfc_flags & VFCF_NETWORK)
24303e08dc74SRick Macklem return;
24313e08dc74SRick Macklem
24323e08dc74SRick Macklem iov[1].iov_base = fsp->f_fstypename;
24333e08dc74SRick Macklem iov[1].iov_len = strlen(fsp->f_fstypename) + 1;
24343e08dc74SRick Macklem iov[3].iov_base = fsp->f_mntonname;
24353e08dc74SRick Macklem iov[3].iov_len = strlen(fsp->f_mntonname) + 1;
24363e08dc74SRick Macklem iov[5].iov_base = fsp->f_mntfromname;
24373e08dc74SRick Macklem iov[5].iov_len = strlen(fsp->f_mntfromname) + 1;
24383e08dc74SRick Macklem errmsg[0] = '\0';
24393e08dc74SRick Macklem
24403e08dc74SRick Macklem /*
24413e08dc74SRick Macklem * EXDEV is returned when path exists but is not a
24423e08dc74SRick Macklem * mount point. May happens if raced with unmount.
24433e08dc74SRick Macklem */
24443e08dc74SRick Macklem if (nmount(iov, iovlen, fsp->f_flags) < 0 && errno != ENOENT &&
24453e08dc74SRick Macklem errno != ENOTSUP && errno != EXDEV) {
24463e08dc74SRick Macklem syslog(LOG_ERR,
24473e08dc74SRick Macklem "can't delete exports for %s: %m %s",
24483e08dc74SRick Macklem fsp->f_mntonname, errmsg);
24493e08dc74SRick Macklem }
24503e08dc74SRick Macklem }
24513e08dc74SRick Macklem
24523e08dc74SRick Macklem /*
24538fae3551SRodney W. Grimes * Allocate an export list element
24548fae3551SRodney W. Grimes */
245519c46d8cSEdward Tomasz Napierala static struct exportlist *
get_exp(void)2456a7a7d96cSPhilippe Charnier get_exp(void)
24578fae3551SRodney W. Grimes {
24588fae3551SRodney W. Grimes struct exportlist *ep;
24598fae3551SRodney W. Grimes
246053750151SXin LI ep = (struct exportlist *)calloc(1, sizeof (struct exportlist));
24618fae3551SRodney W. Grimes if (ep == (struct exportlist *)NULL)
24628fae3551SRodney W. Grimes out_of_mem();
24638fae3551SRodney W. Grimes return (ep);
24648fae3551SRodney W. Grimes }
24658fae3551SRodney W. Grimes
24668fae3551SRodney W. Grimes /*
24678fae3551SRodney W. Grimes * Allocate a group list element
24688fae3551SRodney W. Grimes */
246919c46d8cSEdward Tomasz Napierala static struct grouplist *
get_grp(void)2470a7a7d96cSPhilippe Charnier get_grp(void)
24718fae3551SRodney W. Grimes {
24728fae3551SRodney W. Grimes struct grouplist *gp;
24738fae3551SRodney W. Grimes
247453750151SXin LI gp = (struct grouplist *)calloc(1, sizeof (struct grouplist));
24758fae3551SRodney W. Grimes if (gp == (struct grouplist *)NULL)
24768fae3551SRodney W. Grimes out_of_mem();
24778fae3551SRodney W. Grimes return (gp);
24788fae3551SRodney W. Grimes }
24798fae3551SRodney W. Grimes
24808fae3551SRodney W. Grimes /*
24818fae3551SRodney W. Grimes * Clean up upon an error in get_exportlist().
24828fae3551SRodney W. Grimes */
248319c46d8cSEdward Tomasz Napierala static void
getexp_err(struct exportlist * ep,struct grouplist * grp,const char * reason)2484354fce28SConrad Meyer getexp_err(struct exportlist *ep, struct grouplist *grp, const char *reason)
24858fae3551SRodney W. Grimes {
24868fae3551SRodney W. Grimes struct grouplist *tgrp;
24878fae3551SRodney W. Grimes
2488354fce28SConrad Meyer if (!(opt_flags & OP_QUIET)) {
2489354fce28SConrad Meyer if (reason != NULL)
2490354fce28SConrad Meyer syslog(LOG_ERR, "bad exports list line '%s': %s", line,
2491354fce28SConrad Meyer reason);
2492354fce28SConrad Meyer else
2493354fce28SConrad Meyer syslog(LOG_ERR, "bad exports list line '%s'", line);
2494354fce28SConrad Meyer }
24958fae3551SRodney W. Grimes if (ep && (ep->ex_flag & EX_LINKED) == 0)
24968fae3551SRodney W. Grimes free_exp(ep);
24978fae3551SRodney W. Grimes while (grp) {
24988fae3551SRodney W. Grimes tgrp = grp;
24998fae3551SRodney W. Grimes grp = grp->gr_next;
25008fae3551SRodney W. Grimes free_grp(tgrp);
25018fae3551SRodney W. Grimes }
25028fae3551SRodney W. Grimes }
25038fae3551SRodney W. Grimes
25048fae3551SRodney W. Grimes /*
25058fae3551SRodney W. Grimes * Search the export list for a matching fs.
25068fae3551SRodney W. Grimes */
250719c46d8cSEdward Tomasz Napierala static struct exportlist *
ex_search(fsid_t * fsid,struct exportlisthead * exhp)25081a9a992fSRick Macklem ex_search(fsid_t *fsid, struct exportlisthead *exhp)
25098fae3551SRodney W. Grimes {
25108fae3551SRodney W. Grimes struct exportlist *ep;
251146a6b5c4SRick Macklem uint32_t i;
25128fae3551SRodney W. Grimes
251346a6b5c4SRick Macklem i = EXPHASH(fsid);
251446a6b5c4SRick Macklem SLIST_FOREACH(ep, &exhp[i], entries) {
2515245bfd34SRyan Moeller if (fsidcmp(&ep->ex_fs, fsid) == 0)
25168fae3551SRodney W. Grimes return (ep);
25178fae3551SRodney W. Grimes }
2518c9ac0f71SEmmanuel Vadot
25198fae3551SRodney W. Grimes return (ep);
25208fae3551SRodney W. Grimes }
25218fae3551SRodney W. Grimes
25228fae3551SRodney W. Grimes /*
25238fae3551SRodney W. Grimes * Add a directory path to the list.
25248fae3551SRodney W. Grimes */
252519c46d8cSEdward Tomasz Napierala static char *
add_expdir(struct dirlist ** dpp,char * cp,int len)2526a7a7d96cSPhilippe Charnier add_expdir(struct dirlist **dpp, char *cp, int len)
25278fae3551SRodney W. Grimes {
25288fae3551SRodney W. Grimes struct dirlist *dp;
25298fae3551SRodney W. Grimes
253089b859e3SEmmanuel Vadot dp = malloc(sizeof (struct dirlist));
253174853402SPhilippe Charnier if (dp == (struct dirlist *)NULL)
253274853402SPhilippe Charnier out_of_mem();
25338fae3551SRodney W. Grimes dp->dp_left = *dpp;
25348fae3551SRodney W. Grimes dp->dp_right = (struct dirlist *)NULL;
25358fae3551SRodney W. Grimes dp->dp_flag = 0;
25368fae3551SRodney W. Grimes dp->dp_hosts = (struct hostlist *)NULL;
2537380a3fcdSEmmanuel Vadot dp->dp_dirp = strndup(cp, len);
2538380a3fcdSEmmanuel Vadot if (dp->dp_dirp == NULL)
2539380a3fcdSEmmanuel Vadot out_of_mem();
25408fae3551SRodney W. Grimes *dpp = dp;
25418fae3551SRodney W. Grimes return (dp->dp_dirp);
25428fae3551SRodney W. Grimes }
25438fae3551SRodney W. Grimes
25448fae3551SRodney W. Grimes /*
25458fae3551SRodney W. Grimes * Hang the dir list element off the dirpath binary tree as required
25468fae3551SRodney W. Grimes * and update the entry for host.
25478fae3551SRodney W. Grimes */
254819c46d8cSEdward Tomasz Napierala static void
hang_dirp(struct dirlist * dp,struct grouplist * grp,struct exportlist * ep,int flags,struct expcred * anoncrp,uint64_t exflags)2549a7a7d96cSPhilippe Charnier hang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep,
2550cc5efddeSRick Macklem int flags, struct expcred *anoncrp, uint64_t exflags)
25518fae3551SRodney W. Grimes {
25528fae3551SRodney W. Grimes struct hostlist *hp;
25538fae3551SRodney W. Grimes struct dirlist *dp2;
25548fae3551SRodney W. Grimes
2555a62dc406SDoug Rabson if (flags & OP_ALLDIRS) {
25568fae3551SRodney W. Grimes if (ep->ex_defdir)
25578fae3551SRodney W. Grimes free((caddr_t)dp);
25588fae3551SRodney W. Grimes else
25598fae3551SRodney W. Grimes ep->ex_defdir = dp;
2560a62dc406SDoug Rabson if (grp == (struct grouplist *)NULL) {
25610f0869bcSRick Macklem ep->ex_flag |= EX_DEFSET;
25628fae3551SRodney W. Grimes ep->ex_defdir->dp_flag |= DP_DEFSET;
2563c3f86a25SRick Macklem /* Save the default security flavors list. */
2564c3f86a25SRick Macklem ep->ex_defnumsecflavors = ep->ex_numsecflavors;
2565c3f86a25SRick Macklem if (ep->ex_numsecflavors > 0)
2566c3f86a25SRick Macklem memcpy(ep->ex_defsecflavors, ep->ex_secflavors,
2567c3f86a25SRick Macklem sizeof(ep->ex_secflavors));
2568cc5efddeSRick Macklem cp_cred(&ep->ex_defanon, anoncrp);
25690f0869bcSRick Macklem ep->ex_defexflags = exflags;
2570a62dc406SDoug Rabson } else while (grp) {
25718fae3551SRodney W. Grimes hp = get_ht();
25728fae3551SRodney W. Grimes hp->ht_grp = grp;
25738fae3551SRodney W. Grimes hp->ht_next = ep->ex_defdir->dp_hosts;
25748fae3551SRodney W. Grimes ep->ex_defdir->dp_hosts = hp;
2575c3f86a25SRick Macklem /* Save the security flavors list for this host set. */
2576c3f86a25SRick Macklem grp->gr_numsecflavors = ep->ex_numsecflavors;
2577c3f86a25SRick Macklem if (ep->ex_numsecflavors > 0)
2578c3f86a25SRick Macklem memcpy(grp->gr_secflavors, ep->ex_secflavors,
2579c3f86a25SRick Macklem sizeof(ep->ex_secflavors));
25808fae3551SRodney W. Grimes grp = grp->gr_next;
25818fae3551SRodney W. Grimes }
25828fae3551SRodney W. Grimes } else {
25838fae3551SRodney W. Grimes
25848fae3551SRodney W. Grimes /*
258574853402SPhilippe Charnier * Loop through the directories adding them to the tree.
25868fae3551SRodney W. Grimes */
25878fae3551SRodney W. Grimes while (dp) {
25888fae3551SRodney W. Grimes dp2 = dp->dp_left;
25890f0869bcSRick Macklem add_dlist(&ep->ex_dirl, dp, grp, flags, ep, anoncrp,
25900f0869bcSRick Macklem exflags);
25918fae3551SRodney W. Grimes dp = dp2;
25928fae3551SRodney W. Grimes }
25938fae3551SRodney W. Grimes }
25948fae3551SRodney W. Grimes }
25958fae3551SRodney W. Grimes
25968fae3551SRodney W. Grimes /*
25978fae3551SRodney W. Grimes * Traverse the binary tree either updating a node that is already there
25988fae3551SRodney W. Grimes * for the new directory or adding the new node.
25998fae3551SRodney W. Grimes */
260019c46d8cSEdward Tomasz Napierala static void
add_dlist(struct dirlist ** dpp,struct dirlist * newdp,struct grouplist * grp,int flags,struct exportlist * ep,struct expcred * anoncrp,uint64_t exflags)2601a7a7d96cSPhilippe Charnier add_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp,
2602cc5efddeSRick Macklem int flags, struct exportlist *ep, struct expcred *anoncrp,
2603cc5efddeSRick Macklem uint64_t exflags)
26048fae3551SRodney W. Grimes {
26058fae3551SRodney W. Grimes struct dirlist *dp;
26068fae3551SRodney W. Grimes struct hostlist *hp;
26078fae3551SRodney W. Grimes int cmp;
26088fae3551SRodney W. Grimes
26098fae3551SRodney W. Grimes dp = *dpp;
26108fae3551SRodney W. Grimes if (dp) {
26118fae3551SRodney W. Grimes cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
26128fae3551SRodney W. Grimes if (cmp > 0) {
26130f0869bcSRick Macklem add_dlist(&dp->dp_left, newdp, grp, flags, ep, anoncrp,
26140f0869bcSRick Macklem exflags);
26158fae3551SRodney W. Grimes return;
26168fae3551SRodney W. Grimes } else if (cmp < 0) {
26170f0869bcSRick Macklem add_dlist(&dp->dp_right, newdp, grp, flags, ep, anoncrp,
26180f0869bcSRick Macklem exflags);
26198fae3551SRodney W. Grimes return;
26208fae3551SRodney W. Grimes } else
26218fae3551SRodney W. Grimes free((caddr_t)newdp);
26228fae3551SRodney W. Grimes } else {
26238fae3551SRodney W. Grimes dp = newdp;
26248fae3551SRodney W. Grimes dp->dp_left = (struct dirlist *)NULL;
26258fae3551SRodney W. Grimes *dpp = dp;
26268fae3551SRodney W. Grimes }
26278fae3551SRodney W. Grimes if (grp) {
26288fae3551SRodney W. Grimes
26298fae3551SRodney W. Grimes /*
26308fae3551SRodney W. Grimes * Hang all of the host(s) off of the directory point.
26318fae3551SRodney W. Grimes */
26328fae3551SRodney W. Grimes do {
26338fae3551SRodney W. Grimes hp = get_ht();
26348fae3551SRodney W. Grimes hp->ht_grp = grp;
26358fae3551SRodney W. Grimes hp->ht_next = dp->dp_hosts;
26368fae3551SRodney W. Grimes dp->dp_hosts = hp;
2637c3f86a25SRick Macklem /* Save the security flavors list for this host set. */
2638c3f86a25SRick Macklem grp->gr_numsecflavors = ep->ex_numsecflavors;
2639c3f86a25SRick Macklem if (ep->ex_numsecflavors > 0)
2640c3f86a25SRick Macklem memcpy(grp->gr_secflavors, ep->ex_secflavors,
2641c3f86a25SRick Macklem sizeof(ep->ex_secflavors));
26428fae3551SRodney W. Grimes grp = grp->gr_next;
26438fae3551SRodney W. Grimes } while (grp);
2644a62dc406SDoug Rabson } else {
26450f0869bcSRick Macklem ep->ex_flag |= EX_DEFSET;
26468fae3551SRodney W. Grimes dp->dp_flag |= DP_DEFSET;
2647c3f86a25SRick Macklem /* Save the default security flavors list. */
2648c3f86a25SRick Macklem ep->ex_defnumsecflavors = ep->ex_numsecflavors;
2649c3f86a25SRick Macklem if (ep->ex_numsecflavors > 0)
2650c3f86a25SRick Macklem memcpy(ep->ex_defsecflavors, ep->ex_secflavors,
2651c3f86a25SRick Macklem sizeof(ep->ex_secflavors));
2652cc5efddeSRick Macklem cp_cred(&ep->ex_defanon, anoncrp);
26530f0869bcSRick Macklem ep->ex_defexflags = exflags;
2654a62dc406SDoug Rabson }
26558fae3551SRodney W. Grimes }
26568fae3551SRodney W. Grimes
26578fae3551SRodney W. Grimes /*
26588fae3551SRodney W. Grimes * Search for a dirpath on the export point.
26598fae3551SRodney W. Grimes */
266019c46d8cSEdward Tomasz Napierala static struct dirlist *
dirp_search(struct dirlist * dp,char * dirp)2661a7a7d96cSPhilippe Charnier dirp_search(struct dirlist *dp, char *dirp)
26628fae3551SRodney W. Grimes {
26638fae3551SRodney W. Grimes int cmp;
26648fae3551SRodney W. Grimes
26658fae3551SRodney W. Grimes if (dp) {
26668360efbdSAlfred Perlstein cmp = strcmp(dp->dp_dirp, dirp);
26678fae3551SRodney W. Grimes if (cmp > 0)
26688360efbdSAlfred Perlstein return (dirp_search(dp->dp_left, dirp));
26698fae3551SRodney W. Grimes else if (cmp < 0)
26708360efbdSAlfred Perlstein return (dirp_search(dp->dp_right, dirp));
26718fae3551SRodney W. Grimes else
26728fae3551SRodney W. Grimes return (dp);
26738fae3551SRodney W. Grimes }
26748fae3551SRodney W. Grimes return (dp);
26758fae3551SRodney W. Grimes }
26768fae3551SRodney W. Grimes
26778fae3551SRodney W. Grimes /*
26788fae3551SRodney W. Grimes * Scan for a host match in a directory tree.
26798fae3551SRodney W. Grimes */
268019c46d8cSEdward Tomasz Napierala static int
chk_host(struct dirlist * dp,struct sockaddr * saddr,int * defsetp,int * hostsetp,int * numsecflavors,int ** secflavorsp)2681a7a7d96cSPhilippe Charnier chk_host(struct dirlist *dp, struct sockaddr *saddr, int *defsetp,
2682c3f86a25SRick Macklem int *hostsetp, int *numsecflavors, int **secflavorsp)
26838fae3551SRodney W. Grimes {
26848fae3551SRodney W. Grimes struct hostlist *hp;
26858fae3551SRodney W. Grimes struct grouplist *grp;
26868360efbdSAlfred Perlstein struct addrinfo *ai;
26878fae3551SRodney W. Grimes
26888fae3551SRodney W. Grimes if (dp) {
26898fae3551SRodney W. Grimes if (dp->dp_flag & DP_DEFSET)
2690a62dc406SDoug Rabson *defsetp = dp->dp_flag;
26918fae3551SRodney W. Grimes hp = dp->dp_hosts;
26928fae3551SRodney W. Grimes while (hp) {
26938fae3551SRodney W. Grimes grp = hp->ht_grp;
26948fae3551SRodney W. Grimes switch (grp->gr_type) {
26958fae3551SRodney W. Grimes case GT_HOST:
26968360efbdSAlfred Perlstein ai = grp->gr_ptr.gt_addrinfo;
26978360efbdSAlfred Perlstein for (; ai; ai = ai->ai_next) {
269860caaee2SIan Dowse if (!sacmp(ai->ai_addr, saddr, NULL)) {
26998360efbdSAlfred Perlstein *hostsetp =
27008360efbdSAlfred Perlstein (hp->ht_flag | DP_HOSTSET);
2701c3f86a25SRick Macklem if (numsecflavors != NULL) {
2702c3f86a25SRick Macklem *numsecflavors =
2703c3f86a25SRick Macklem grp->gr_numsecflavors;
2704c3f86a25SRick Macklem *secflavorsp =
2705c3f86a25SRick Macklem grp->gr_secflavors;
2706c3f86a25SRick Macklem }
27078fae3551SRodney W. Grimes return (1);
2708a62dc406SDoug Rabson }
27098fae3551SRodney W. Grimes }
27108fae3551SRodney W. Grimes break;
27118fae3551SRodney W. Grimes case GT_NET:
271260caaee2SIan Dowse if (!sacmp(saddr, (struct sockaddr *)
271360caaee2SIan Dowse &grp->gr_ptr.gt_net.nt_net,
271460caaee2SIan Dowse (struct sockaddr *)
271560caaee2SIan Dowse &grp->gr_ptr.gt_net.nt_mask)) {
2716a62dc406SDoug Rabson *hostsetp = (hp->ht_flag | DP_HOSTSET);
2717c3f86a25SRick Macklem if (numsecflavors != NULL) {
2718c3f86a25SRick Macklem *numsecflavors =
2719c3f86a25SRick Macklem grp->gr_numsecflavors;
2720c3f86a25SRick Macklem *secflavorsp =
2721c3f86a25SRick Macklem grp->gr_secflavors;
2722c3f86a25SRick Macklem }
27238fae3551SRodney W. Grimes return (1);
2724a62dc406SDoug Rabson }
27258fae3551SRodney W. Grimes break;
272660caaee2SIan Dowse }
27278fae3551SRodney W. Grimes hp = hp->ht_next;
27288fae3551SRodney W. Grimes }
27298fae3551SRodney W. Grimes }
27308fae3551SRodney W. Grimes return (0);
27318fae3551SRodney W. Grimes }
27328fae3551SRodney W. Grimes
27338fae3551SRodney W. Grimes /*
27348fae3551SRodney W. Grimes * Scan tree for a host that matches the address.
27358fae3551SRodney W. Grimes */
273619c46d8cSEdward Tomasz Napierala static int
scan_tree(struct dirlist * dp,struct sockaddr * saddr)2737a7a7d96cSPhilippe Charnier scan_tree(struct dirlist *dp, struct sockaddr *saddr)
27388fae3551SRodney W. Grimes {
2739a62dc406SDoug Rabson int defset, hostset;
27408fae3551SRodney W. Grimes
27418fae3551SRodney W. Grimes if (dp) {
27428fae3551SRodney W. Grimes if (scan_tree(dp->dp_left, saddr))
27438fae3551SRodney W. Grimes return (1);
2744c3f86a25SRick Macklem if (chk_host(dp, saddr, &defset, &hostset, NULL, NULL))
27458fae3551SRodney W. Grimes return (1);
27468fae3551SRodney W. Grimes if (scan_tree(dp->dp_right, saddr))
27478fae3551SRodney W. Grimes return (1);
27488fae3551SRodney W. Grimes }
27498fae3551SRodney W. Grimes return (0);
27508fae3551SRodney W. Grimes }
27518fae3551SRodney W. Grimes
27528fae3551SRodney W. Grimes /*
27538fae3551SRodney W. Grimes * Traverse the dirlist tree and free it up.
27548fae3551SRodney W. Grimes */
275519c46d8cSEdward Tomasz Napierala static void
free_dir(struct dirlist * dp)2756a7a7d96cSPhilippe Charnier free_dir(struct dirlist *dp)
27578fae3551SRodney W. Grimes {
27588fae3551SRodney W. Grimes
27598fae3551SRodney W. Grimes if (dp) {
27608fae3551SRodney W. Grimes free_dir(dp->dp_left);
27618fae3551SRodney W. Grimes free_dir(dp->dp_right);
27628fae3551SRodney W. Grimes free_host(dp->dp_hosts);
276392e73cccSEmmanuel Vadot free(dp->dp_dirp);
276492e73cccSEmmanuel Vadot free(dp);
27658fae3551SRodney W. Grimes }
27668fae3551SRodney W. Grimes }
27678fae3551SRodney W. Grimes
27688fae3551SRodney W. Grimes /*
2769a9148abdSDoug Rabson * Parse a colon separated list of security flavors
2770a9148abdSDoug Rabson */
277119c46d8cSEdward Tomasz Napierala static int
parsesec(char * seclist,struct exportlist * ep)2772a7a7d96cSPhilippe Charnier parsesec(char *seclist, struct exportlist *ep)
2773a9148abdSDoug Rabson {
2774a9148abdSDoug Rabson char *cp, savedc;
2775a9148abdSDoug Rabson int flavor;
2776a9148abdSDoug Rabson
2777a9148abdSDoug Rabson ep->ex_numsecflavors = 0;
2778a9148abdSDoug Rabson for (;;) {
2779a9148abdSDoug Rabson cp = strchr(seclist, ':');
2780a9148abdSDoug Rabson if (cp) {
2781a9148abdSDoug Rabson savedc = *cp;
2782a9148abdSDoug Rabson *cp = '\0';
2783a9148abdSDoug Rabson }
2784a9148abdSDoug Rabson
2785a9148abdSDoug Rabson if (!strcmp(seclist, "sys"))
2786a9148abdSDoug Rabson flavor = AUTH_SYS;
2787a9148abdSDoug Rabson else if (!strcmp(seclist, "krb5"))
2788a9148abdSDoug Rabson flavor = RPCSEC_GSS_KRB5;
2789a9148abdSDoug Rabson else if (!strcmp(seclist, "krb5i"))
2790a9148abdSDoug Rabson flavor = RPCSEC_GSS_KRB5I;
2791a9148abdSDoug Rabson else if (!strcmp(seclist, "krb5p"))
2792a9148abdSDoug Rabson flavor = RPCSEC_GSS_KRB5P;
2793a9148abdSDoug Rabson else {
2794a9148abdSDoug Rabson if (cp)
2795a9148abdSDoug Rabson *cp = savedc;
2796a9148abdSDoug Rabson syslog(LOG_ERR, "bad sec flavor: %s", seclist);
2797a9148abdSDoug Rabson return (1);
2798a9148abdSDoug Rabson }
2799a9148abdSDoug Rabson if (ep->ex_numsecflavors == MAXSECFLAVORS) {
2800a9148abdSDoug Rabson if (cp)
2801a9148abdSDoug Rabson *cp = savedc;
2802a9148abdSDoug Rabson syslog(LOG_ERR, "too many sec flavors: %s", seclist);
2803a9148abdSDoug Rabson return (1);
2804a9148abdSDoug Rabson }
2805a9148abdSDoug Rabson ep->ex_secflavors[ep->ex_numsecflavors] = flavor;
2806a9148abdSDoug Rabson ep->ex_numsecflavors++;
2807a9148abdSDoug Rabson if (cp) {
2808a9148abdSDoug Rabson *cp = savedc;
2809a9148abdSDoug Rabson seclist = cp + 1;
2810a9148abdSDoug Rabson } else {
2811a9148abdSDoug Rabson break;
2812a9148abdSDoug Rabson }
2813a9148abdSDoug Rabson }
2814a9148abdSDoug Rabson return (0);
2815a9148abdSDoug Rabson }
2816a9148abdSDoug Rabson
2817a9148abdSDoug Rabson /*
28188fae3551SRodney W. Grimes * Parse the option string and update fields.
28198fae3551SRodney W. Grimes * Option arguments may either be -<option>=<value> or
28208fae3551SRodney W. Grimes * -<option> <value>
28218fae3551SRodney W. Grimes */
282219c46d8cSEdward Tomasz Napierala static int
do_opt(char ** cpp,char ** endcpp,struct exportlist * ep,struct grouplist * grp,int * has_hostp,uint64_t * exflagsp,struct expcred * cr)2823a7a7d96cSPhilippe Charnier do_opt(char **cpp, char **endcpp, struct exportlist *ep, struct grouplist *grp,
2824cc5efddeSRick Macklem int *has_hostp, uint64_t *exflagsp, struct expcred *cr)
28258fae3551SRodney W. Grimes {
28268fae3551SRodney W. Grimes char *cpoptarg, *cpoptend;
28278fae3551SRodney W. Grimes char *cp, *endcp, *cpopt, savedc, savedc2;
2828*3df987c9SRick Macklem int allflag, usedarg, fnd_equal;
28298fae3551SRodney W. Grimes
2830cb479b11SAlfred Perlstein savedc2 = '\0';
28318fae3551SRodney W. Grimes cpopt = *cpp;
28328fae3551SRodney W. Grimes cpopt++;
28338fae3551SRodney W. Grimes cp = *endcpp;
28348fae3551SRodney W. Grimes savedc = *cp;
28358fae3551SRodney W. Grimes *cp = '\0';
28368fae3551SRodney W. Grimes while (cpopt && *cpopt) {
28378fae3551SRodney W. Grimes allflag = 1;
28388fae3551SRodney W. Grimes usedarg = -2;
2839*3df987c9SRick Macklem fnd_equal = 0;
284074853402SPhilippe Charnier if ((cpoptend = strchr(cpopt, ','))) {
28418fae3551SRodney W. Grimes *cpoptend++ = '\0';
2842*3df987c9SRick Macklem if ((cpoptarg = strchr(cpopt, '='))) {
28438fae3551SRodney W. Grimes *cpoptarg++ = '\0';
2844*3df987c9SRick Macklem fnd_equal = 1;
2845*3df987c9SRick Macklem }
28468fae3551SRodney W. Grimes } else {
2847*3df987c9SRick Macklem if ((cpoptarg = strchr(cpopt, '='))) {
28488fae3551SRodney W. Grimes *cpoptarg++ = '\0';
2849*3df987c9SRick Macklem fnd_equal = 1;
2850*3df987c9SRick Macklem } else {
28518fae3551SRodney W. Grimes *cp = savedc;
28528fae3551SRodney W. Grimes nextfield(&cp, &endcp);
28538fae3551SRodney W. Grimes **endcpp = '\0';
28548fae3551SRodney W. Grimes if (endcp > cp && *cp != '-') {
28558fae3551SRodney W. Grimes cpoptarg = cp;
28568fae3551SRodney W. Grimes savedc2 = *endcp;
28578fae3551SRodney W. Grimes *endcp = '\0';
28588fae3551SRodney W. Grimes usedarg = 0;
28598fae3551SRodney W. Grimes }
28608fae3551SRodney W. Grimes }
28618fae3551SRodney W. Grimes }
28628fae3551SRodney W. Grimes if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
2863*3df987c9SRick Macklem if (fnd_equal == 1) {
2864*3df987c9SRick Macklem syslog(LOG_ERR, "= after op: %s", cpopt);
2865*3df987c9SRick Macklem return (1);
2866*3df987c9SRick Macklem }
28678fae3551SRodney W. Grimes *exflagsp |= MNT_EXRDONLY;
28688fae3551SRodney W. Grimes } else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
28698fae3551SRodney W. Grimes !(allflag = strcmp(cpopt, "mapall")) ||
28708fae3551SRodney W. Grimes !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
28718fae3551SRodney W. Grimes usedarg++;
28728fae3551SRodney W. Grimes parsecred(cpoptarg, cr);
28738fae3551SRodney W. Grimes if (allflag == 0) {
28748fae3551SRodney W. Grimes *exflagsp |= MNT_EXPORTANON;
28758fae3551SRodney W. Grimes opt_flags |= OP_MAPALL;
28768fae3551SRodney W. Grimes } else
28778fae3551SRodney W. Grimes opt_flags |= OP_MAPROOT;
28788fae3551SRodney W. Grimes } else if (cpoptarg && (!strcmp(cpopt, "mask") ||
28798fae3551SRodney W. Grimes !strcmp(cpopt, "m"))) {
28808fae3551SRodney W. Grimes if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
288174853402SPhilippe Charnier syslog(LOG_ERR, "bad mask: %s", cpoptarg);
28828fae3551SRodney W. Grimes return (1);
28838fae3551SRodney W. Grimes }
28848fae3551SRodney W. Grimes usedarg++;
28858fae3551SRodney W. Grimes opt_flags |= OP_MASK;
28868fae3551SRodney W. Grimes } else if (cpoptarg && (!strcmp(cpopt, "network") ||
28878fae3551SRodney W. Grimes !strcmp(cpopt, "n"))) {
28888360efbdSAlfred Perlstein if (strchr(cpoptarg, '/') != NULL) {
28898360efbdSAlfred Perlstein if (debug)
28908360efbdSAlfred Perlstein fprintf(stderr, "setting OP_MASKLEN\n");
28918360efbdSAlfred Perlstein opt_flags |= OP_MASKLEN;
28928360efbdSAlfred Perlstein }
28938fae3551SRodney W. Grimes if (grp->gr_type != GT_NULL) {
289474853402SPhilippe Charnier syslog(LOG_ERR, "network/host conflict");
28958fae3551SRodney W. Grimes return (1);
28968fae3551SRodney W. Grimes } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
289774853402SPhilippe Charnier syslog(LOG_ERR, "bad net: %s", cpoptarg);
28988fae3551SRodney W. Grimes return (1);
28998fae3551SRodney W. Grimes }
29008fae3551SRodney W. Grimes grp->gr_type = GT_NET;
29018fae3551SRodney W. Grimes *has_hostp = 1;
29028fae3551SRodney W. Grimes usedarg++;
29038fae3551SRodney W. Grimes opt_flags |= OP_NET;
29048fae3551SRodney W. Grimes } else if (!strcmp(cpopt, "alldirs")) {
2905*3df987c9SRick Macklem if (fnd_equal == 1) {
2906*3df987c9SRick Macklem syslog(LOG_ERR, "= after op: %s", cpopt);
2907*3df987c9SRick Macklem return (1);
2908*3df987c9SRick Macklem }
29098fae3551SRodney W. Grimes opt_flags |= OP_ALLDIRS;
2910cb3923e0SDoug Rabson } else if (!strcmp(cpopt, "public")) {
2911*3df987c9SRick Macklem if (fnd_equal == 1) {
2912*3df987c9SRick Macklem syslog(LOG_ERR, "= after op: %s", cpopt);
2913*3df987c9SRick Macklem return (1);
2914*3df987c9SRick Macklem }
2915cb3923e0SDoug Rabson *exflagsp |= MNT_EXPUBLIC;
2916cb3923e0SDoug Rabson } else if (!strcmp(cpopt, "webnfs")) {
2917*3df987c9SRick Macklem if (fnd_equal == 1) {
2918*3df987c9SRick Macklem syslog(LOG_ERR, "= after op: %s", cpopt);
2919*3df987c9SRick Macklem return (1);
2920*3df987c9SRick Macklem }
2921cb3923e0SDoug Rabson *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON);
2922cb3923e0SDoug Rabson opt_flags |= OP_MAPALL;
2923cb3923e0SDoug Rabson } else if (cpoptarg && !strcmp(cpopt, "index")) {
2924cb3923e0SDoug Rabson ep->ex_indexfile = strdup(cpoptarg);
2925288fa14aSJoerg Wunsch } else if (!strcmp(cpopt, "quiet")) {
2926*3df987c9SRick Macklem if (fnd_equal == 1) {
2927*3df987c9SRick Macklem syslog(LOG_ERR, "= after op: %s", cpopt);
2928*3df987c9SRick Macklem return (1);
2929*3df987c9SRick Macklem }
2930288fa14aSJoerg Wunsch opt_flags |= OP_QUIET;
2931dcdc127bSSergey Kandaurov } else if (cpoptarg && !strcmp(cpopt, "sec")) {
2932a9148abdSDoug Rabson if (parsesec(cpoptarg, ep))
2933a9148abdSDoug Rabson return (1);
2934a9148abdSDoug Rabson opt_flags |= OP_SEC;
2935a9148abdSDoug Rabson usedarg++;
2936813837baSRick Macklem } else if (!strcmp(cpopt, "tls")) {
2937*3df987c9SRick Macklem if (fnd_equal == 1) {
2938*3df987c9SRick Macklem syslog(LOG_ERR, "= after op: %s", cpopt);
2939*3df987c9SRick Macklem return (1);
2940*3df987c9SRick Macklem }
2941813837baSRick Macklem *exflagsp |= MNT_EXTLS;
2942813837baSRick Macklem } else if (!strcmp(cpopt, "tlscert")) {
2943*3df987c9SRick Macklem if (fnd_equal == 1) {
2944*3df987c9SRick Macklem syslog(LOG_ERR, "= after op: %s", cpopt);
2945*3df987c9SRick Macklem return (1);
2946*3df987c9SRick Macklem }
2947813837baSRick Macklem *exflagsp |= (MNT_EXTLS | MNT_EXTLSCERT);
2948813837baSRick Macklem } else if (!strcmp(cpopt, "tlscertuser")) {
2949*3df987c9SRick Macklem if (fnd_equal == 1) {
2950*3df987c9SRick Macklem syslog(LOG_ERR, "= after op: %s", cpopt);
2951*3df987c9SRick Macklem return (1);
2952*3df987c9SRick Macklem }
2953813837baSRick Macklem *exflagsp |= (MNT_EXTLS | MNT_EXTLSCERT |
2954813837baSRick Macklem MNT_EXTLSCERTUSER);
29558fae3551SRodney W. Grimes } else {
295674853402SPhilippe Charnier syslog(LOG_ERR, "bad opt %s", cpopt);
29578fae3551SRodney W. Grimes return (1);
29588fae3551SRodney W. Grimes }
29598fae3551SRodney W. Grimes if (usedarg >= 0) {
29608fae3551SRodney W. Grimes *endcp = savedc2;
29618fae3551SRodney W. Grimes **endcpp = savedc;
29628fae3551SRodney W. Grimes if (usedarg > 0) {
29638fae3551SRodney W. Grimes *cpp = cp;
29648fae3551SRodney W. Grimes *endcpp = endcp;
29658fae3551SRodney W. Grimes }
29668fae3551SRodney W. Grimes return (0);
29678fae3551SRodney W. Grimes }
29688fae3551SRodney W. Grimes cpopt = cpoptend;
29698fae3551SRodney W. Grimes }
29708fae3551SRodney W. Grimes **endcpp = savedc;
29718fae3551SRodney W. Grimes return (0);
29728fae3551SRodney W. Grimes }
29738fae3551SRodney W. Grimes
29748fae3551SRodney W. Grimes /*
29758fae3551SRodney W. Grimes * Translate a character string to the corresponding list of network
29768fae3551SRodney W. Grimes * addresses for a hostname.
29778fae3551SRodney W. Grimes */
297819c46d8cSEdward Tomasz Napierala static int
get_host(char * cp,struct grouplist * grp,struct grouplist * tgrp)2979a7a7d96cSPhilippe Charnier get_host(char *cp, struct grouplist *grp, struct grouplist *tgrp)
29808fae3551SRodney W. Grimes {
29818b5a6d67SBill Paul struct grouplist *checkgrp;
298201709abfSIan Dowse struct addrinfo *ai, *tai, hints;
29838360efbdSAlfred Perlstein int ecode;
29848360efbdSAlfred Perlstein char host[NI_MAXHOST];
29858fae3551SRodney W. Grimes
29868360efbdSAlfred Perlstein if (grp->gr_type != GT_NULL) {
29878360efbdSAlfred Perlstein syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp);
29888fae3551SRodney W. Grimes return (1);
29898fae3551SRodney W. Grimes }
29908360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints);
29918360efbdSAlfred Perlstein hints.ai_flags = AI_CANONNAME;
29928360efbdSAlfred Perlstein hints.ai_protocol = IPPROTO_UDP;
29938360efbdSAlfred Perlstein ecode = getaddrinfo(cp, NULL, &hints, &ai);
29948360efbdSAlfred Perlstein if (ecode != 0) {
299501709abfSIan Dowse syslog(LOG_ERR,"can't get address info for host %s", cp);
29968360efbdSAlfred Perlstein return 1;
29978fae3551SRodney W. Grimes }
29988360efbdSAlfred Perlstein grp->gr_ptr.gt_addrinfo = ai;
29998360efbdSAlfred Perlstein while (ai != NULL) {
30008360efbdSAlfred Perlstein if (ai->ai_canonname == NULL) {
30018360efbdSAlfred Perlstein if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host,
30024f101318SHajimu UMEMOTO sizeof host, NULL, 0, NI_NUMERICHOST) != 0)
30038360efbdSAlfred Perlstein strlcpy(host, "?", sizeof(host));
30048360efbdSAlfred Perlstein ai->ai_canonname = strdup(host);
30058360efbdSAlfred Perlstein ai->ai_flags |= AI_CANONNAME;
30066d359f31SIan Dowse }
30078fae3551SRodney W. Grimes if (debug)
300801709abfSIan Dowse fprintf(stderr, "got host %s\n", ai->ai_canonname);
300901709abfSIan Dowse /*
301001709abfSIan Dowse * Sanity check: make sure we don't already have an entry
301101709abfSIan Dowse * for this host in the grouplist.
301201709abfSIan Dowse */
301301709abfSIan Dowse for (checkgrp = tgrp; checkgrp != NULL;
301401709abfSIan Dowse checkgrp = checkgrp->gr_next) {
301501709abfSIan Dowse if (checkgrp->gr_type != GT_HOST)
301601709abfSIan Dowse continue;
301701709abfSIan Dowse for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL;
301801709abfSIan Dowse tai = tai->ai_next) {
301960caaee2SIan Dowse if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0)
302001709abfSIan Dowse continue;
302101709abfSIan Dowse if (debug)
302201709abfSIan Dowse fprintf(stderr,
302301709abfSIan Dowse "ignoring duplicate host %s\n",
302401709abfSIan Dowse ai->ai_canonname);
302501709abfSIan Dowse grp->gr_type = GT_IGNORE;
302601709abfSIan Dowse return (0);
302701709abfSIan Dowse }
302801709abfSIan Dowse }
30298360efbdSAlfred Perlstein ai = ai->ai_next;
30308360efbdSAlfred Perlstein }
303101709abfSIan Dowse grp->gr_type = GT_HOST;
30328fae3551SRodney W. Grimes return (0);
30338fae3551SRodney W. Grimes }
30348fae3551SRodney W. Grimes
30358fae3551SRodney W. Grimes /*
30368fae3551SRodney W. Grimes * Free up an exports list component
30378fae3551SRodney W. Grimes */
303819c46d8cSEdward Tomasz Napierala static void
free_exp(struct exportlist * ep)3039a7a7d96cSPhilippe Charnier free_exp(struct exportlist *ep)
30408fae3551SRodney W. Grimes {
3041711d44eeSRick Macklem struct grouplist *grp, *tgrp;
30428fae3551SRodney W. Grimes
30438fae3551SRodney W. Grimes if (ep->ex_defdir) {
30448fae3551SRodney W. Grimes free_host(ep->ex_defdir->dp_hosts);
30458fae3551SRodney W. Grimes free((caddr_t)ep->ex_defdir);
30468fae3551SRodney W. Grimes }
30478fae3551SRodney W. Grimes if (ep->ex_fsdir)
30488fae3551SRodney W. Grimes free(ep->ex_fsdir);
3049cb3923e0SDoug Rabson if (ep->ex_indexfile)
3050cb3923e0SDoug Rabson free(ep->ex_indexfile);
30518fae3551SRodney W. Grimes free_dir(ep->ex_dirl);
3052711d44eeSRick Macklem grp = ep->ex_grphead;
3053711d44eeSRick Macklem while (grp) {
3054711d44eeSRick Macklem tgrp = grp;
3055711d44eeSRick Macklem grp = grp->gr_next;
3056711d44eeSRick Macklem free_grp(tgrp);
3057711d44eeSRick Macklem }
30582ffad162SRick Macklem if (ep->ex_defanon.cr_groups != ep->ex_defanon.cr_smallgrps)
30592ffad162SRick Macklem free(ep->ex_defanon.cr_groups);
30608fae3551SRodney W. Grimes free((caddr_t)ep);
30618fae3551SRodney W. Grimes }
30628fae3551SRodney W. Grimes
30638fae3551SRodney W. Grimes /*
30640f0869bcSRick Macklem * Free up the v4root exports.
30650f0869bcSRick Macklem */
30660f0869bcSRick Macklem static void
free_v4rootexp(void)30670f0869bcSRick Macklem free_v4rootexp(void)
30680f0869bcSRick Macklem {
30690f0869bcSRick Macklem
30700f0869bcSRick Macklem if (v4root_ep != NULL) {
30710f0869bcSRick Macklem free_exp(v4root_ep);
30720f0869bcSRick Macklem v4root_ep = NULL;
30730f0869bcSRick Macklem }
30740f0869bcSRick Macklem }
30750f0869bcSRick Macklem
30760f0869bcSRick Macklem /*
30778fae3551SRodney W. Grimes * Free hosts.
30788fae3551SRodney W. Grimes */
307919c46d8cSEdward Tomasz Napierala static void
free_host(struct hostlist * hp)3080a7a7d96cSPhilippe Charnier free_host(struct hostlist *hp)
30818fae3551SRodney W. Grimes {
30828fae3551SRodney W. Grimes struct hostlist *hp2;
30838fae3551SRodney W. Grimes
30848fae3551SRodney W. Grimes while (hp) {
30858fae3551SRodney W. Grimes hp2 = hp;
30868fae3551SRodney W. Grimes hp = hp->ht_next;
30878fae3551SRodney W. Grimes free((caddr_t)hp2);
30888fae3551SRodney W. Grimes }
30898fae3551SRodney W. Grimes }
30908fae3551SRodney W. Grimes
309119c46d8cSEdward Tomasz Napierala static struct hostlist *
get_ht(void)3092a7a7d96cSPhilippe Charnier get_ht(void)
30938fae3551SRodney W. Grimes {
30948fae3551SRodney W. Grimes struct hostlist *hp;
30958fae3551SRodney W. Grimes
30968fae3551SRodney W. Grimes hp = (struct hostlist *)malloc(sizeof (struct hostlist));
30978fae3551SRodney W. Grimes if (hp == (struct hostlist *)NULL)
30988fae3551SRodney W. Grimes out_of_mem();
30998fae3551SRodney W. Grimes hp->ht_next = (struct hostlist *)NULL;
3100a62dc406SDoug Rabson hp->ht_flag = 0;
31018fae3551SRodney W. Grimes return (hp);
31028fae3551SRodney W. Grimes }
31038fae3551SRodney W. Grimes
31048fae3551SRodney W. Grimes /*
31058fae3551SRodney W. Grimes * Out of memory, fatal
31068fae3551SRodney W. Grimes */
310719c46d8cSEdward Tomasz Napierala static void
out_of_mem(void)3108a7a7d96cSPhilippe Charnier out_of_mem(void)
31098fae3551SRodney W. Grimes {
31108fae3551SRodney W. Grimes
311174853402SPhilippe Charnier syslog(LOG_ERR, "out of memory");
31128fae3551SRodney W. Grimes exit(2);
31138fae3551SRodney W. Grimes }
31148fae3551SRodney W. Grimes
31158fae3551SRodney W. Grimes /*
31160f0869bcSRick Macklem * Call do_mount() from the struct exportlist, for each case needed.
31170f0869bcSRick Macklem */
31180f0869bcSRick Macklem static int
do_export_mount(struct exportlist * ep,struct statfs * fsp)31190f0869bcSRick Macklem do_export_mount(struct exportlist *ep, struct statfs *fsp)
31200f0869bcSRick Macklem {
31210f0869bcSRick Macklem struct grouplist *grp, defgrp;
31220f0869bcSRick Macklem int ret;
31230f0869bcSRick Macklem size_t dirlen;
31240f0869bcSRick Macklem
31250f0869bcSRick Macklem LOGDEBUG("do_export_mount=%s", ep->ex_fsdir);
31260f0869bcSRick Macklem dirlen = strlen(ep->ex_fsdir);
31270f0869bcSRick Macklem if ((ep->ex_flag & EX_DEFSET) != 0) {
31280f0869bcSRick Macklem defgrp.gr_type = GT_DEFAULT;
31290f0869bcSRick Macklem defgrp.gr_next = NULL;
31300f0869bcSRick Macklem /* We have an entry for all other hosts/nets. */
3131cc5efddeSRick Macklem LOGDEBUG("ex_defexflags=0x%jx", (uintmax_t)ep->ex_defexflags);
31320f0869bcSRick Macklem ret = do_mount(ep, &defgrp, ep->ex_defexflags, &ep->ex_defanon,
31330f0869bcSRick Macklem ep->ex_fsdir, dirlen, fsp, ep->ex_defnumsecflavors,
31340f0869bcSRick Macklem ep->ex_defsecflavors);
31350f0869bcSRick Macklem if (ret != 0)
31360f0869bcSRick Macklem return (ret);
31370f0869bcSRick Macklem }
31380f0869bcSRick Macklem
31390f0869bcSRick Macklem /* Do a mount for each group. */
31400f0869bcSRick Macklem grp = ep->ex_grphead;
31410f0869bcSRick Macklem while (grp != NULL) {
3142cc5efddeSRick Macklem LOGDEBUG("do mount gr_type=0x%x gr_exflags=0x%jx",
3143cc5efddeSRick Macklem grp->gr_type, (uintmax_t)grp->gr_exflags);
31440f0869bcSRick Macklem ret = do_mount(ep, grp, grp->gr_exflags, &grp->gr_anon,
31450f0869bcSRick Macklem ep->ex_fsdir, dirlen, fsp, grp->gr_numsecflavors,
31460f0869bcSRick Macklem grp->gr_secflavors);
31470f0869bcSRick Macklem if (ret != 0)
31480f0869bcSRick Macklem return (ret);
31490f0869bcSRick Macklem grp = grp->gr_next;
31500f0869bcSRick Macklem }
31510f0869bcSRick Macklem return (0);
31520f0869bcSRick Macklem }
31530f0869bcSRick Macklem
31540f0869bcSRick Macklem /*
31556a09faf2SCraig Rodrigues * Do the nmount() syscall with the update flag to push the export info into
31568fae3551SRodney W. Grimes * the kernel.
31578fae3551SRodney W. Grimes */
315819c46d8cSEdward Tomasz Napierala static int
do_mount(struct exportlist * ep,struct grouplist * grp,uint64_t exflags,struct expcred * anoncrp,char * dirp,int dirplen,struct statfs * fsb,int numsecflavors,int * secflavors)3159cc5efddeSRick Macklem do_mount(struct exportlist *ep, struct grouplist *grp, uint64_t exflags,
3160cc5efddeSRick Macklem struct expcred *anoncrp, char *dirp, int dirplen, struct statfs *fsb,
31610f0869bcSRick Macklem int numsecflavors, int *secflavors)
31628fae3551SRodney W. Grimes {
3163f93caef2SIan Dowse struct statfs fsb1;
31648360efbdSAlfred Perlstein struct addrinfo *ai;
316579b86807SEdward Tomasz Napierala struct export_args *eap;
31666a09faf2SCraig Rodrigues char errmsg[255];
31676a09faf2SCraig Rodrigues char *cp;
31688fae3551SRodney W. Grimes int done;
31696a09faf2SCraig Rodrigues char savedc;
31706a09faf2SCraig Rodrigues struct iovec *iov;
3171a9148abdSDoug Rabson int i, iovlen;
31726a09faf2SCraig Rodrigues int ret;
3173bcc1d071SRick Macklem struct nfsex_args nfsea;
3174bcc1d071SRick Macklem
3175bcc1d071SRick Macklem eap = &nfsea.export;
31768fae3551SRodney W. Grimes
31776a09faf2SCraig Rodrigues cp = NULL;
31786a09faf2SCraig Rodrigues savedc = '\0';
31796a09faf2SCraig Rodrigues iov = NULL;
31806a09faf2SCraig Rodrigues iovlen = 0;
31816a09faf2SCraig Rodrigues ret = 0;
318260caaee2SIan Dowse
3183bcc1d071SRick Macklem bzero(eap, sizeof (struct export_args));
31846a09faf2SCraig Rodrigues bzero(errmsg, sizeof(errmsg));
3185bcc1d071SRick Macklem eap->ex_flags = exflags;
3186cc5efddeSRick Macklem eap->ex_uid = anoncrp->cr_uid;
3187cc5efddeSRick Macklem eap->ex_ngroups = anoncrp->cr_ngroups;
3188cc5efddeSRick Macklem if (eap->ex_ngroups > 0) {
3189cc5efddeSRick Macklem eap->ex_groups = malloc(eap->ex_ngroups * sizeof(gid_t));
3190cc5efddeSRick Macklem memcpy(eap->ex_groups, anoncrp->cr_groups, eap->ex_ngroups *
3191cc5efddeSRick Macklem sizeof(gid_t));
3192cc5efddeSRick Macklem }
3193cc5efddeSRick Macklem LOGDEBUG("do_mount exflags=0x%jx", (uintmax_t)exflags);
3194bcc1d071SRick Macklem eap->ex_indexfile = ep->ex_indexfile;
31956d359f31SIan Dowse if (grp->gr_type == GT_HOST)
31968360efbdSAlfred Perlstein ai = grp->gr_ptr.gt_addrinfo;
31976d359f31SIan Dowse else
31986d359f31SIan Dowse ai = NULL;
31990f0869bcSRick Macklem eap->ex_numsecflavors = numsecflavors;
32000f0869bcSRick Macklem LOGDEBUG("do_mount numsec=%d", numsecflavors);
3201bcc1d071SRick Macklem for (i = 0; i < eap->ex_numsecflavors; i++)
32020f0869bcSRick Macklem eap->ex_secflavors[i] = secflavors[i];
3203bcc1d071SRick Macklem if (eap->ex_numsecflavors == 0) {
3204bcc1d071SRick Macklem eap->ex_numsecflavors = 1;
3205bcc1d071SRick Macklem eap->ex_secflavors[0] = AUTH_SYS;
3206a9148abdSDoug Rabson }
32078fae3551SRodney W. Grimes done = FALSE;
32086a09faf2SCraig Rodrigues
3209bcc1d071SRick Macklem if (v4root_phase == 0) {
32106a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "fstype", NULL, 0);
32116a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "fspath", NULL, 0);
32126a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "from", NULL, 0);
32136a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "update", NULL, 0);
3214bcc1d071SRick Macklem build_iovec(&iov, &iovlen, "export", eap,
3215bcc1d071SRick Macklem sizeof (struct export_args));
32166a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
3217bcc1d071SRick Macklem }
32186a09faf2SCraig Rodrigues
32198fae3551SRodney W. Grimes while (!done) {
32208fae3551SRodney W. Grimes switch (grp->gr_type) {
32218fae3551SRodney W. Grimes case GT_HOST:
32226d359f31SIan Dowse if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0)
32238360efbdSAlfred Perlstein goto skip;
3224bcc1d071SRick Macklem eap->ex_addr = ai->ai_addr;
3225bcc1d071SRick Macklem eap->ex_addrlen = ai->ai_addrlen;
3226bcc1d071SRick Macklem eap->ex_masklen = 0;
32278fae3551SRodney W. Grimes break;
32288fae3551SRodney W. Grimes case GT_NET:
322960caaee2SIan Dowse if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 &&
32308360efbdSAlfred Perlstein have_v6 == 0)
32318360efbdSAlfred Perlstein goto skip;
3232bcc1d071SRick Macklem eap->ex_addr =
323360caaee2SIan Dowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net;
3234bcc1d071SRick Macklem eap->ex_addrlen =
32356a09faf2SCraig Rodrigues ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len;
3236bcc1d071SRick Macklem eap->ex_mask =
323760caaee2SIan Dowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask;
3238bcc1d071SRick Macklem eap->ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len;
32398fae3551SRodney W. Grimes break;
32406d359f31SIan Dowse case GT_DEFAULT:
3241bcc1d071SRick Macklem eap->ex_addr = NULL;
3242bcc1d071SRick Macklem eap->ex_addrlen = 0;
3243bcc1d071SRick Macklem eap->ex_mask = NULL;
3244bcc1d071SRick Macklem eap->ex_masklen = 0;
32456d359f31SIan Dowse break;
32468b5a6d67SBill Paul case GT_IGNORE:
32476a09faf2SCraig Rodrigues ret = 0;
32486a09faf2SCraig Rodrigues goto error_exit;
32498b5a6d67SBill Paul break;
32508fae3551SRodney W. Grimes default:
325174853402SPhilippe Charnier syslog(LOG_ERR, "bad grouptype");
32528fae3551SRodney W. Grimes if (cp)
32538fae3551SRodney W. Grimes *cp = savedc;
32546a09faf2SCraig Rodrigues ret = 1;
32556a09faf2SCraig Rodrigues goto error_exit;
325680c7cc1cSPedro F. Giffuni }
32578fae3551SRodney W. Grimes
32588fae3551SRodney W. Grimes /*
3259bcc1d071SRick Macklem * For V4:, use the nfssvc() syscall, instead of mount().
3260bcc1d071SRick Macklem */
3261bcc1d071SRick Macklem if (v4root_phase == 2) {
3262bcc1d071SRick Macklem nfsea.fspec = v4root_dirpath;
3263cc5efddeSRick Macklem if (nfssvc(NFSSVC_V4ROOTEXPORT | NFSSVC_NEWSTRUCT,
3264cc5efddeSRick Macklem (caddr_t)&nfsea) < 0) {
3265bcc1d071SRick Macklem syslog(LOG_ERR, "Exporting V4: failed");
3266cc5efddeSRick Macklem ret = 2;
3267cc5efddeSRick Macklem goto error_exit;
3268bcc1d071SRick Macklem }
3269bcc1d071SRick Macklem } else {
3270bcc1d071SRick Macklem /*
32718fae3551SRodney W. Grimes * XXX:
3272bcc1d071SRick Macklem * Maybe I should just use the fsb->f_mntonname path
3273bcc1d071SRick Macklem * instead of looping back up the dirp to the mount
3274bcc1d071SRick Macklem * point??
32758fae3551SRodney W. Grimes * Also, needs to know how to export all types of local
327687564113SPeter Wemm * exportable filesystems and not just "ufs".
32778fae3551SRodney W. Grimes */
32786a09faf2SCraig Rodrigues iov[1].iov_base = fsb->f_fstypename; /* "fstype" */
32796a09faf2SCraig Rodrigues iov[1].iov_len = strlen(fsb->f_fstypename) + 1;
32806a09faf2SCraig Rodrigues iov[3].iov_base = fsb->f_mntonname; /* "fspath" */
32816a09faf2SCraig Rodrigues iov[3].iov_len = strlen(fsb->f_mntonname) + 1;
32826a09faf2SCraig Rodrigues iov[5].iov_base = fsb->f_mntfromname; /* "from" */
32836a09faf2SCraig Rodrigues iov[5].iov_len = strlen(fsb->f_mntfromname) + 1;
32844a185fa6SBryan Drewery errmsg[0] = '\0';
32856a09faf2SCraig Rodrigues
328655dd1327SCraig Rodrigues while (nmount(iov, iovlen, fsb->f_flags) < 0) {
32878fae3551SRodney W. Grimes if (cp)
32888fae3551SRodney W. Grimes *cp-- = savedc;
32898fae3551SRodney W. Grimes else
32908fae3551SRodney W. Grimes cp = dirp + dirplen - 1;
32916a09faf2SCraig Rodrigues if (opt_flags & OP_QUIET) {
32926a09faf2SCraig Rodrigues ret = 1;
32936a09faf2SCraig Rodrigues goto error_exit;
32946a09faf2SCraig Rodrigues }
32958fae3551SRodney W. Grimes if (errno == EPERM) {
329601709abfSIan Dowse if (debug)
329777909162SXin LI warnx("can't change attributes for %s: %s",
329877909162SXin LI dirp, errmsg);
32998fae3551SRodney W. Grimes syslog(LOG_ERR,
330077909162SXin LI "can't change attributes for %s: %s",
330177909162SXin LI dirp, errmsg);
33026a09faf2SCraig Rodrigues ret = 1;
33036a09faf2SCraig Rodrigues goto error_exit;
33048fae3551SRodney W. Grimes }
33058fae3551SRodney W. Grimes if (opt_flags & OP_ALLDIRS) {
3306288fa14aSJoerg Wunsch if (errno == EINVAL)
3307288fa14aSJoerg Wunsch syslog(LOG_ERR,
3308288fa14aSJoerg Wunsch "-alldirs requested but %s is not a filesystem mountpoint",
3309288fa14aSJoerg Wunsch dirp);
3310288fa14aSJoerg Wunsch else
3311288fa14aSJoerg Wunsch syslog(LOG_ERR,
3312288fa14aSJoerg Wunsch "could not remount %s: %m",
33133980ac4fSGarrett Wollman dirp);
33146a09faf2SCraig Rodrigues ret = 1;
33156a09faf2SCraig Rodrigues goto error_exit;
33168fae3551SRodney W. Grimes }
33178fae3551SRodney W. Grimes /* back up over the last component */
3318d90b3641SBrooks Davis while (cp > dirp && *cp == '/')
33198fae3551SRodney W. Grimes cp--;
3320d90b3641SBrooks Davis while (cp > dirp && *(cp - 1) != '/')
33218fae3551SRodney W. Grimes cp--;
33228fae3551SRodney W. Grimes if (cp == dirp) {
33238fae3551SRodney W. Grimes if (debug)
332474853402SPhilippe Charnier warnx("mnt unsucc");
3325bcc1d071SRick Macklem syslog(LOG_ERR, "can't export %s %s",
3326bcc1d071SRick Macklem dirp, errmsg);
33276a09faf2SCraig Rodrigues ret = 1;
33286a09faf2SCraig Rodrigues goto error_exit;
33298fae3551SRodney W. Grimes }
33308fae3551SRodney W. Grimes savedc = *cp;
33318fae3551SRodney W. Grimes *cp = '\0';
3332bcc1d071SRick Macklem /*
3333bcc1d071SRick Macklem * Check that we're still on the same
3334bcc1d071SRick Macklem * filesystem.
3335bcc1d071SRick Macklem */
3336bcc1d071SRick Macklem if (statfs(dirp, &fsb1) != 0 ||
3337245bfd34SRyan Moeller fsidcmp(&fsb1.f_fsid, &fsb->f_fsid) != 0) {
3338f93caef2SIan Dowse *cp = savedc;
3339bcc1d071SRick Macklem syslog(LOG_ERR,
3340bcc1d071SRick Macklem "can't export %s %s", dirp,
334137518a88SCraig Rodrigues errmsg);
33426a09faf2SCraig Rodrigues ret = 1;
33436a09faf2SCraig Rodrigues goto error_exit;
3344f93caef2SIan Dowse }
33458fae3551SRodney W. Grimes }
3346bcc1d071SRick Macklem }
3347bcc1d071SRick Macklem
3348bcc1d071SRick Macklem /*
3349bcc1d071SRick Macklem * For the experimental server:
3350bcc1d071SRick Macklem * If this is the public directory, get the file handle
3351bcc1d071SRick Macklem * and load it into the kernel via the nfssvc() syscall.
3352bcc1d071SRick Macklem */
335379b86807SEdward Tomasz Napierala if ((exflags & MNT_EXPUBLIC) != 0) {
3354bcc1d071SRick Macklem fhandle_t fh;
3355bcc1d071SRick Macklem char *public_name;
3356bcc1d071SRick Macklem
3357bcc1d071SRick Macklem if (eap->ex_indexfile != NULL)
3358bcc1d071SRick Macklem public_name = eap->ex_indexfile;
3359bcc1d071SRick Macklem else
3360bcc1d071SRick Macklem public_name = dirp;
3361bcc1d071SRick Macklem if (getfh(public_name, &fh) < 0)
3362bcc1d071SRick Macklem syslog(LOG_ERR,
3363bcc1d071SRick Macklem "Can't get public fh for %s", public_name);
3364bcc1d071SRick Macklem else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0)
3365bcc1d071SRick Macklem syslog(LOG_ERR,
3366bcc1d071SRick Macklem "Can't set public fh for %s", public_name);
33670f0869bcSRick Macklem else {
3368bcc1d071SRick Macklem has_publicfh = 1;
33690f0869bcSRick Macklem has_set_publicfh = 1;
33700f0869bcSRick Macklem ep->ex_flag |= EX_PUBLICFH;
33710f0869bcSRick Macklem }
3372bcc1d071SRick Macklem }
33738360efbdSAlfred Perlstein skip:
33746d359f31SIan Dowse if (ai != NULL)
33758360efbdSAlfred Perlstein ai = ai->ai_next;
33768360efbdSAlfred Perlstein if (ai == NULL)
33778fae3551SRodney W. Grimes done = TRUE;
33788fae3551SRodney W. Grimes }
33798fae3551SRodney W. Grimes if (cp)
33808fae3551SRodney W. Grimes *cp = savedc;
33816a09faf2SCraig Rodrigues error_exit:
3382cc5efddeSRick Macklem free(eap->ex_groups);
33836a09faf2SCraig Rodrigues /* free strings allocated by strdup() in getmntopts.c */
33846a09faf2SCraig Rodrigues if (iov != NULL) {
33856a09faf2SCraig Rodrigues free(iov[0].iov_base); /* fstype */
33866a09faf2SCraig Rodrigues free(iov[2].iov_base); /* fspath */
33876a09faf2SCraig Rodrigues free(iov[4].iov_base); /* from */
33886a09faf2SCraig Rodrigues free(iov[6].iov_base); /* update */
33896a09faf2SCraig Rodrigues free(iov[8].iov_base); /* export */
33906a09faf2SCraig Rodrigues free(iov[10].iov_base); /* errmsg */
33916a09faf2SCraig Rodrigues
33926a09faf2SCraig Rodrigues /* free iov, allocated by realloc() */
33936a09faf2SCraig Rodrigues free(iov);
33946a09faf2SCraig Rodrigues }
33956a09faf2SCraig Rodrigues return (ret);
33968fae3551SRodney W. Grimes }
33978fae3551SRodney W. Grimes
33988fae3551SRodney W. Grimes /*
33998fae3551SRodney W. Grimes * Translate a net address.
340060caaee2SIan Dowse *
340160caaee2SIan Dowse * If `maskflg' is nonzero, then `cp' is a netmask, not a network address.
34028fae3551SRodney W. Grimes */
340319c46d8cSEdward Tomasz Napierala static int
get_net(char * cp,struct netmsk * net,int maskflg)3404a7a7d96cSPhilippe Charnier get_net(char *cp, struct netmsk *net, int maskflg)
34058fae3551SRodney W. Grimes {
3406931c04f1SIan Dowse struct netent *np = NULL;
34078360efbdSAlfred Perlstein char *name, *p, *prefp;
340860caaee2SIan Dowse struct sockaddr_in sin;
3409931c04f1SIan Dowse struct sockaddr *sa = NULL;
34108360efbdSAlfred Perlstein struct addrinfo hints, *ai = NULL;
34118360efbdSAlfred Perlstein char netname[NI_MAXHOST];
34128360efbdSAlfred Perlstein long preflen;
34138fae3551SRodney W. Grimes
341401709abfSIan Dowse p = prefp = NULL;
34158360efbdSAlfred Perlstein if ((opt_flags & OP_MASKLEN) && !maskflg) {
34168360efbdSAlfred Perlstein p = strchr(cp, '/');
34178360efbdSAlfred Perlstein *p = '\0';
34188360efbdSAlfred Perlstein prefp = p + 1;
34198360efbdSAlfred Perlstein }
34208360efbdSAlfred Perlstein
3421931c04f1SIan Dowse /*
3422931c04f1SIan Dowse * Check for a numeric address first. We wish to avoid
3423931c04f1SIan Dowse * possible DNS lookups in getnetbyname().
3424931c04f1SIan Dowse */
3425931c04f1SIan Dowse if (isxdigit(*cp) || *cp == ':') {
34268360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints);
342760caaee2SIan Dowse /* Ensure the mask and the network have the same family. */
342860caaee2SIan Dowse if (maskflg && (opt_flags & OP_NET))
342960caaee2SIan Dowse hints.ai_family = net->nt_net.ss_family;
343060caaee2SIan Dowse else if (!maskflg && (opt_flags & OP_HAVEMASK))
343160caaee2SIan Dowse hints.ai_family = net->nt_mask.ss_family;
343260caaee2SIan Dowse else
34338360efbdSAlfred Perlstein hints.ai_family = AF_UNSPEC;
34348360efbdSAlfred Perlstein hints.ai_flags = AI_NUMERICHOST;
3435931c04f1SIan Dowse if (getaddrinfo(cp, NULL, &hints, &ai) == 0)
3436931c04f1SIan Dowse sa = ai->ai_addr;
3437931c04f1SIan Dowse if (sa != NULL && ai->ai_family == AF_INET) {
34388fae3551SRodney W. Grimes /*
343960caaee2SIan Dowse * The address in `cp' is really a network address, so
344060caaee2SIan Dowse * use inet_network() to re-interpret this correctly.
344160caaee2SIan Dowse * e.g. "127.1" means 127.1.0.0, not 127.0.0.1.
34428fae3551SRodney W. Grimes */
344360caaee2SIan Dowse bzero(&sin, sizeof sin);
34448360efbdSAlfred Perlstein sin.sin_family = AF_INET;
34458360efbdSAlfred Perlstein sin.sin_len = sizeof sin;
34468360efbdSAlfred Perlstein sin.sin_addr = inet_makeaddr(inet_network(cp), 0);
34478360efbdSAlfred Perlstein if (debug)
344860caaee2SIan Dowse fprintf(stderr, "get_net: v4 addr %s\n",
344960caaee2SIan Dowse inet_ntoa(sin.sin_addr));
34508360efbdSAlfred Perlstein sa = (struct sockaddr *)&sin;
3451931c04f1SIan Dowse }
3452931c04f1SIan Dowse }
3453931c04f1SIan Dowse if (sa == NULL && (np = getnetbyname(cp)) != NULL) {
3454931c04f1SIan Dowse bzero(&sin, sizeof sin);
3455931c04f1SIan Dowse sin.sin_family = AF_INET;
3456931c04f1SIan Dowse sin.sin_len = sizeof sin;
3457931c04f1SIan Dowse sin.sin_addr = inet_makeaddr(np->n_net, 0);
3458931c04f1SIan Dowse sa = (struct sockaddr *)&sin;
3459931c04f1SIan Dowse }
3460931c04f1SIan Dowse if (sa == NULL)
34618360efbdSAlfred Perlstein goto fail;
34628360efbdSAlfred Perlstein
346360caaee2SIan Dowse if (maskflg) {
346460caaee2SIan Dowse /* The specified sockaddr is a mask. */
346560caaee2SIan Dowse if (checkmask(sa) != 0)
34668360efbdSAlfred Perlstein goto fail;
346760caaee2SIan Dowse bcopy(sa, &net->nt_mask, sa->sa_len);
346860caaee2SIan Dowse opt_flags |= OP_HAVEMASK;
346948514c57SMike Karels opt_flags &= ~OP_CLASSMASK;
347060caaee2SIan Dowse } else {
347160caaee2SIan Dowse /* The specified sockaddr is a network address. */
347260caaee2SIan Dowse bcopy(sa, &net->nt_net, sa->sa_len);
34730f4b7baaSPaul Traina
347460caaee2SIan Dowse /* Get a network name for the export list. */
347560caaee2SIan Dowse if (np) {
347660caaee2SIan Dowse name = np->n_name;
347760caaee2SIan Dowse } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname,
34784f101318SHajimu UMEMOTO NULL, 0, NI_NUMERICHOST) == 0) {
347960caaee2SIan Dowse name = netname;
348060caaee2SIan Dowse } else {
348160caaee2SIan Dowse goto fail;
348260caaee2SIan Dowse }
348360caaee2SIan Dowse if ((net->nt_name = strdup(name)) == NULL)
348460caaee2SIan Dowse out_of_mem();
348560caaee2SIan Dowse
348660caaee2SIan Dowse /*
348760caaee2SIan Dowse * Extract a mask from either a "/<masklen>" suffix, or
348860caaee2SIan Dowse * from the class of an IPv4 address.
348960caaee2SIan Dowse */
34908360efbdSAlfred Perlstein if (opt_flags & OP_MASKLEN) {
34918360efbdSAlfred Perlstein preflen = strtol(prefp, NULL, 10);
349260caaee2SIan Dowse if (preflen < 0L || preflen == LONG_MAX)
34938360efbdSAlfred Perlstein goto fail;
349460caaee2SIan Dowse bcopy(sa, &net->nt_mask, sa->sa_len);
349560caaee2SIan Dowse if (makemask(&net->nt_mask, (int)preflen) != 0)
349660caaee2SIan Dowse goto fail;
349760caaee2SIan Dowse opt_flags |= OP_HAVEMASK;
34988360efbdSAlfred Perlstein *p = '/';
349960caaee2SIan Dowse } else if (sa->sa_family == AF_INET &&
350060caaee2SIan Dowse (opt_flags & OP_MASK) == 0) {
350160caaee2SIan Dowse in_addr_t addr;
35028360efbdSAlfred Perlstein
350360caaee2SIan Dowse addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
350460caaee2SIan Dowse if (IN_CLASSA(addr))
350560caaee2SIan Dowse preflen = 8;
350660caaee2SIan Dowse else if (IN_CLASSB(addr))
350760caaee2SIan Dowse preflen = 16;
350860caaee2SIan Dowse else if (IN_CLASSC(addr))
350960caaee2SIan Dowse preflen = 24;
351092aebdeaSMike Karels else if (IN_CLASSD(addr)) /* XXX Multicast??? */
351160caaee2SIan Dowse preflen = 28;
35128360efbdSAlfred Perlstein else
351360caaee2SIan Dowse preflen = 32; /* XXX */
351460caaee2SIan Dowse
351560caaee2SIan Dowse bcopy(sa, &net->nt_mask, sa->sa_len);
351660caaee2SIan Dowse makemask(&net->nt_mask, (int)preflen);
351748514c57SMike Karels opt_flags |= OP_HAVEMASK | OP_CLASSMASK;
351860caaee2SIan Dowse }
35198360efbdSAlfred Perlstein }
35208360efbdSAlfred Perlstein
35218360efbdSAlfred Perlstein if (ai)
35228360efbdSAlfred Perlstein freeaddrinfo(ai);
35238360efbdSAlfred Perlstein return 0;
35248360efbdSAlfred Perlstein
35258360efbdSAlfred Perlstein fail:
35268360efbdSAlfred Perlstein if (ai)
35278360efbdSAlfred Perlstein freeaddrinfo(ai);
35288360efbdSAlfred Perlstein return 1;
35298fae3551SRodney W. Grimes }
35308fae3551SRodney W. Grimes
35318fae3551SRodney W. Grimes /*
35328fae3551SRodney W. Grimes * Parse out the next white space separated field
35338fae3551SRodney W. Grimes */
353419c46d8cSEdward Tomasz Napierala static void
nextfield(char ** cp,char ** endcp)3535a7a7d96cSPhilippe Charnier nextfield(char **cp, char **endcp)
35368fae3551SRodney W. Grimes {
35378fae3551SRodney W. Grimes char *p;
3538eb1f7f43SAlexander Motin char quot = 0;
35398fae3551SRodney W. Grimes
35408fae3551SRodney W. Grimes p = *cp;
35418fae3551SRodney W. Grimes while (*p == ' ' || *p == '\t')
35428fae3551SRodney W. Grimes p++;
3543eb1f7f43SAlexander Motin *cp = p;
3544eb1f7f43SAlexander Motin while (*p != '\0') {
3545eb1f7f43SAlexander Motin if (quot) {
3546eb1f7f43SAlexander Motin if (*p == quot)
3547eb1f7f43SAlexander Motin quot = 0;
3548eb1f7f43SAlexander Motin } else {
3549eb1f7f43SAlexander Motin if (*p == '\\' && *(p + 1) != '\0')
35508fae3551SRodney W. Grimes p++;
3551eb1f7f43SAlexander Motin else if (*p == '\'' || *p == '"')
3552eb1f7f43SAlexander Motin quot = *p;
3553eb1f7f43SAlexander Motin else if (*p == ' ' || *p == '\t')
3554eb1f7f43SAlexander Motin break;
35558fae3551SRodney W. Grimes }
3556eb1f7f43SAlexander Motin p++;
3557eb1f7f43SAlexander Motin };
3558eb1f7f43SAlexander Motin *endcp = p;
35598fae3551SRodney W. Grimes }
35608fae3551SRodney W. Grimes
35618fae3551SRodney W. Grimes /*
35628fae3551SRodney W. Grimes * Get an exports file line. Skip over blank lines and handle line
35638fae3551SRodney W. Grimes * continuations.
35648fae3551SRodney W. Grimes */
356519c46d8cSEdward Tomasz Napierala static int
get_line(void)3566a7a7d96cSPhilippe Charnier get_line(void)
35678fae3551SRodney W. Grimes {
35688fae3551SRodney W. Grimes char *p, *cp;
356991ca1a91SIan Dowse size_t len;
35708fae3551SRodney W. Grimes int totlen, cont_line;
35718fae3551SRodney W. Grimes
35728fae3551SRodney W. Grimes /*
35738fae3551SRodney W. Grimes * Loop around ignoring blank lines and getting all continuation lines.
35748fae3551SRodney W. Grimes */
35758fae3551SRodney W. Grimes p = line;
35768fae3551SRodney W. Grimes totlen = 0;
35778fae3551SRodney W. Grimes do {
357891ca1a91SIan Dowse if ((p = fgetln(exp_file, &len)) == NULL)
35798fae3551SRodney W. Grimes return (0);
35808fae3551SRodney W. Grimes cp = p + len - 1;
35818fae3551SRodney W. Grimes cont_line = 0;
35828fae3551SRodney W. Grimes while (cp >= p &&
35838fae3551SRodney W. Grimes (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
35848fae3551SRodney W. Grimes if (*cp == '\\')
35858fae3551SRodney W. Grimes cont_line = 1;
35868fae3551SRodney W. Grimes cp--;
35878fae3551SRodney W. Grimes len--;
35888fae3551SRodney W. Grimes }
3589376f8390SDima Dorfman if (cont_line) {
3590376f8390SDima Dorfman *++cp = ' ';
3591376f8390SDima Dorfman len++;
3592376f8390SDima Dorfman }
359391ca1a91SIan Dowse if (linesize < len + totlen + 1) {
359491ca1a91SIan Dowse linesize = len + totlen + 1;
359591ca1a91SIan Dowse line = realloc(line, linesize);
359691ca1a91SIan Dowse if (line == NULL)
359791ca1a91SIan Dowse out_of_mem();
359891ca1a91SIan Dowse }
359991ca1a91SIan Dowse memcpy(line + totlen, p, len);
36008fae3551SRodney W. Grimes totlen += len;
360191ca1a91SIan Dowse line[totlen] = '\0';
36028fae3551SRodney W. Grimes } while (totlen == 0 || cont_line);
36038fae3551SRodney W. Grimes return (1);
36048fae3551SRodney W. Grimes }
36058fae3551SRodney W. Grimes
36068fae3551SRodney W. Grimes /*
36078fae3551SRodney W. Grimes * Parse a description of a credential.
36088fae3551SRodney W. Grimes */
360919c46d8cSEdward Tomasz Napierala static void
parsecred(char * namelist,struct expcred * cr)3610cc5efddeSRick Macklem parsecred(char *namelist, struct expcred *cr)
36118fae3551SRodney W. Grimes {
36128fae3551SRodney W. Grimes char *name;
36132ffad162SRick Macklem int inpos;
36148fae3551SRodney W. Grimes char *names;
36158fae3551SRodney W. Grimes struct passwd *pw;
36168fae3551SRodney W. Grimes struct group *gr;
36172ffad162SRick Macklem gid_t groups[NGROUPS_MAX + 1];
36182ffad162SRick Macklem int ngroups;
3619f4bf849bSRick Macklem unsigned long name_ul;
3620f4bf849bSRick Macklem char *end = NULL;
36218fae3551SRodney W. Grimes
36228fae3551SRodney W. Grimes /*
362374853402SPhilippe Charnier * Set up the unprivileged user.
36248fae3551SRodney W. Grimes */
36252ffad162SRick Macklem cr->cr_groups = cr->cr_smallgrps;
36263e2d36ffSRick Macklem cr->cr_uid = UID_NOBODY;
36273e2d36ffSRick Macklem cr->cr_groups[0] = GID_NOGROUP;
36288fae3551SRodney W. Grimes cr->cr_ngroups = 1;
36298fae3551SRodney W. Grimes /*
36308fae3551SRodney W. Grimes * Get the user's password table entry.
36318fae3551SRodney W. Grimes */
3632eb1f7f43SAlexander Motin names = namelist;
3633eb1f7f43SAlexander Motin name = strsep_quote(&names, ":");
3634b875c2e9SJosh Paetzel /* Bug? name could be NULL here */
3635f4bf849bSRick Macklem name_ul = strtoul(name, &end, 10);
3636f4bf849bSRick Macklem if (*end != '\0' || end == name)
36378fae3551SRodney W. Grimes pw = getpwnam(name);
3638f4bf849bSRick Macklem else
3639f4bf849bSRick Macklem pw = getpwuid((uid_t)name_ul);
36408fae3551SRodney W. Grimes /*
36418fae3551SRodney W. Grimes * Credentials specified as those of a user.
36428fae3551SRodney W. Grimes */
36438fae3551SRodney W. Grimes if (names == NULL) {
36448fae3551SRodney W. Grimes if (pw == NULL) {
364574853402SPhilippe Charnier syslog(LOG_ERR, "unknown user: %s", name);
36468fae3551SRodney W. Grimes return;
36478fae3551SRodney W. Grimes }
36488fae3551SRodney W. Grimes cr->cr_uid = pw->pw_uid;
36492ffad162SRick Macklem ngroups = NGROUPS_MAX + 1;
36502ffad162SRick Macklem if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) {
365174853402SPhilippe Charnier syslog(LOG_ERR, "too many groups");
36522ffad162SRick Macklem ngroups = NGROUPS_MAX + 1;
3653020d6f96SAndriy Gapon }
3654020d6f96SAndriy Gapon
36558fae3551SRodney W. Grimes /*
3656950cc395SStefan Farfeleder * Compress out duplicate.
36578fae3551SRodney W. Grimes */
36582ffad162SRick Macklem if (ngroups > 1 && groups[0] == groups[1]) {
36592ffad162SRick Macklem ngroups--;
36602ffad162SRick Macklem inpos = 2;
3661f4bf849bSRick Macklem } else {
36622ffad162SRick Macklem inpos = 1;
3663f4bf849bSRick Macklem }
36642ffad162SRick Macklem if (ngroups > NGROUPS_MAX)
36652ffad162SRick Macklem ngroups = NGROUPS_MAX;
36662ffad162SRick Macklem if (ngroups > SMALLNGROUPS)
36672ffad162SRick Macklem cr->cr_groups = malloc(ngroups * sizeof(gid_t));
36682ffad162SRick Macklem cr->cr_ngroups = ngroups;
36692ffad162SRick Macklem cr->cr_groups[0] = groups[0];
36702ffad162SRick Macklem memcpy(&cr->cr_groups[1], &groups[inpos], (ngroups - 1) *
36712ffad162SRick Macklem sizeof(gid_t));
36728fae3551SRodney W. Grimes return;
36738fae3551SRodney W. Grimes }
36748fae3551SRodney W. Grimes /*
36758fae3551SRodney W. Grimes * Explicit credential specified as a colon separated list:
36768fae3551SRodney W. Grimes * uid:gid:gid:...
36778fae3551SRodney W. Grimes */
3678f4bf849bSRick Macklem if (pw != NULL) {
36798fae3551SRodney W. Grimes cr->cr_uid = pw->pw_uid;
3680f4bf849bSRick Macklem } else if (*end != '\0' || end == name) {
368174853402SPhilippe Charnier syslog(LOG_ERR, "unknown user: %s", name);
36828fae3551SRodney W. Grimes return;
3683f4bf849bSRick Macklem } else {
3684f4bf849bSRick Macklem cr->cr_uid = name_ul;
36858fae3551SRodney W. Grimes }
36868fae3551SRodney W. Grimes cr->cr_ngroups = 0;
3687cc5efddeSRick Macklem while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS_MAX) {
3688eb1f7f43SAlexander Motin name = strsep_quote(&names, ":");
3689f4bf849bSRick Macklem name_ul = strtoul(name, &end, 10);
3690f4bf849bSRick Macklem if (*end != '\0' || end == name) {
36918fae3551SRodney W. Grimes if ((gr = getgrnam(name)) == NULL) {
369274853402SPhilippe Charnier syslog(LOG_ERR, "unknown group: %s", name);
36938fae3551SRodney W. Grimes continue;
36948fae3551SRodney W. Grimes }
36952ffad162SRick Macklem groups[cr->cr_ngroups++] = gr->gr_gid;
3696f4bf849bSRick Macklem } else {
3697f4bf849bSRick Macklem groups[cr->cr_ngroups++] = name_ul;
36988fae3551SRodney W. Grimes }
36998fae3551SRodney W. Grimes }
3700cc5efddeSRick Macklem if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS_MAX)
370174853402SPhilippe Charnier syslog(LOG_ERR, "too many groups");
37022ffad162SRick Macklem if (cr->cr_ngroups > SMALLNGROUPS)
37032ffad162SRick Macklem cr->cr_groups = malloc(cr->cr_ngroups * sizeof(gid_t));
37042ffad162SRick Macklem memcpy(cr->cr_groups, groups, cr->cr_ngroups * sizeof(gid_t));
37058fae3551SRodney W. Grimes }
37068fae3551SRodney W. Grimes
37070775314bSDoug Rabson #define STRSIZ (MNTNAMLEN+MNTPATHLEN+50)
37088fae3551SRodney W. Grimes /*
37098fae3551SRodney W. Grimes * Routines that maintain the remote mounttab
37108fae3551SRodney W. Grimes */
371119c46d8cSEdward Tomasz Napierala static void
get_mountlist(void)3712a7a7d96cSPhilippe Charnier get_mountlist(void)
37138fae3551SRodney W. Grimes {
37141da3e8b0SEmmanuel Vadot struct mountlist *mlp;
371587564113SPeter Wemm char *host, *dirp, *cp;
37168fae3551SRodney W. Grimes char str[STRSIZ];
37178fae3551SRodney W. Grimes FILE *mlfile;
37188fae3551SRodney W. Grimes
37198fae3551SRodney W. Grimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
372039539916SBill Fumerola if (errno == ENOENT)
372139539916SBill Fumerola return;
372239539916SBill Fumerola else {
372374853402SPhilippe Charnier syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST);
37248fae3551SRodney W. Grimes return;
37258fae3551SRodney W. Grimes }
372639539916SBill Fumerola }
37278fae3551SRodney W. Grimes while (fgets(str, STRSIZ, mlfile) != NULL) {
372887564113SPeter Wemm cp = str;
372987564113SPeter Wemm host = strsep(&cp, " \t\n");
373087564113SPeter Wemm dirp = strsep(&cp, " \t\n");
373187564113SPeter Wemm if (host == NULL || dirp == NULL)
37328fae3551SRodney W. Grimes continue;
37338fae3551SRodney W. Grimes mlp = (struct mountlist *)malloc(sizeof (*mlp));
373474853402SPhilippe Charnier if (mlp == (struct mountlist *)NULL)
373574853402SPhilippe Charnier out_of_mem();
37360775314bSDoug Rabson strncpy(mlp->ml_host, host, MNTNAMLEN);
37370775314bSDoug Rabson mlp->ml_host[MNTNAMLEN] = '\0';
37380775314bSDoug Rabson strncpy(mlp->ml_dirp, dirp, MNTPATHLEN);
37390775314bSDoug Rabson mlp->ml_dirp[MNTPATHLEN] = '\0';
37401da3e8b0SEmmanuel Vadot
37411da3e8b0SEmmanuel Vadot SLIST_INSERT_HEAD(&mlhead, mlp, next);
37428fae3551SRodney W. Grimes }
37438fae3551SRodney W. Grimes fclose(mlfile);
37448fae3551SRodney W. Grimes }
37458fae3551SRodney W. Grimes
374619c46d8cSEdward Tomasz Napierala static void
del_mlist(char * hostp,char * dirp)374701709abfSIan Dowse del_mlist(char *hostp, char *dirp)
37488fae3551SRodney W. Grimes {
37491da3e8b0SEmmanuel Vadot struct mountlist *mlp, *mlp2;
37508fae3551SRodney W. Grimes FILE *mlfile;
37518fae3551SRodney W. Grimes int fnd = 0;
37528fae3551SRodney W. Grimes
37531da3e8b0SEmmanuel Vadot SLIST_FOREACH_SAFE(mlp, &mlhead, next, mlp2) {
37548fae3551SRodney W. Grimes if (!strcmp(mlp->ml_host, hostp) &&
37558fae3551SRodney W. Grimes (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
37568fae3551SRodney W. Grimes fnd = 1;
37571da3e8b0SEmmanuel Vadot SLIST_REMOVE(&mlhead, mlp, mountlist, next);
37581da3e8b0SEmmanuel Vadot free((caddr_t)mlp);
37598fae3551SRodney W. Grimes }
37608fae3551SRodney W. Grimes }
37618fae3551SRodney W. Grimes if (fnd) {
37628fae3551SRodney W. Grimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
376374853402SPhilippe Charnier syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST);
37648fae3551SRodney W. Grimes return;
37658fae3551SRodney W. Grimes }
37661da3e8b0SEmmanuel Vadot SLIST_FOREACH(mlp, &mlhead, next) {
37678fae3551SRodney W. Grimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
37688fae3551SRodney W. Grimes }
37698fae3551SRodney W. Grimes fclose(mlfile);
37708fae3551SRodney W. Grimes }
37718fae3551SRodney W. Grimes }
37728fae3551SRodney W. Grimes
377319c46d8cSEdward Tomasz Napierala static void
add_mlist(char * hostp,char * dirp)3774a7a7d96cSPhilippe Charnier add_mlist(char *hostp, char *dirp)
37758fae3551SRodney W. Grimes {
37761da3e8b0SEmmanuel Vadot struct mountlist *mlp;
37778fae3551SRodney W. Grimes FILE *mlfile;
37788fae3551SRodney W. Grimes
37791da3e8b0SEmmanuel Vadot SLIST_FOREACH(mlp, &mlhead, next) {
37808fae3551SRodney W. Grimes if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
37818fae3551SRodney W. Grimes return;
37828fae3551SRodney W. Grimes }
37831da3e8b0SEmmanuel Vadot
37848fae3551SRodney W. Grimes mlp = (struct mountlist *)malloc(sizeof (*mlp));
378574853402SPhilippe Charnier if (mlp == (struct mountlist *)NULL)
378674853402SPhilippe Charnier out_of_mem();
37870775314bSDoug Rabson strncpy(mlp->ml_host, hostp, MNTNAMLEN);
37880775314bSDoug Rabson mlp->ml_host[MNTNAMLEN] = '\0';
37890775314bSDoug Rabson strncpy(mlp->ml_dirp, dirp, MNTPATHLEN);
37900775314bSDoug Rabson mlp->ml_dirp[MNTPATHLEN] = '\0';
37911da3e8b0SEmmanuel Vadot SLIST_INSERT_HEAD(&mlhead, mlp, next);
37928fae3551SRodney W. Grimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
379374853402SPhilippe Charnier syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST);
37948fae3551SRodney W. Grimes return;
37958fae3551SRodney W. Grimes }
37968fae3551SRodney W. Grimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
37978fae3551SRodney W. Grimes fclose(mlfile);
37988fae3551SRodney W. Grimes }
37998fae3551SRodney W. Grimes
38008fae3551SRodney W. Grimes /*
38018fae3551SRodney W. Grimes * Free up a group list.
38028fae3551SRodney W. Grimes */
380319c46d8cSEdward Tomasz Napierala static void
free_grp(struct grouplist * grp)3804a7a7d96cSPhilippe Charnier free_grp(struct grouplist *grp)
38058fae3551SRodney W. Grimes {
38068fae3551SRodney W. Grimes if (grp->gr_type == GT_HOST) {
38078360efbdSAlfred Perlstein if (grp->gr_ptr.gt_addrinfo != NULL)
38088360efbdSAlfred Perlstein freeaddrinfo(grp->gr_ptr.gt_addrinfo);
38098fae3551SRodney W. Grimes } else if (grp->gr_type == GT_NET) {
38108fae3551SRodney W. Grimes if (grp->gr_ptr.gt_net.nt_name)
38118fae3551SRodney W. Grimes free(grp->gr_ptr.gt_net.nt_name);
38128fae3551SRodney W. Grimes }
38132ffad162SRick Macklem if (grp->gr_anon.cr_groups != grp->gr_anon.cr_smallgrps)
38142ffad162SRick Macklem free(grp->gr_anon.cr_groups);
38158fae3551SRodney W. Grimes free((caddr_t)grp);
38168fae3551SRodney W. Grimes }
38178fae3551SRodney W. Grimes
38188fae3551SRodney W. Grimes #ifdef DEBUG
381919c46d8cSEdward Tomasz Napierala static void
SYSLOG(int pri,const char * fmt,...)38208fae3551SRodney W. Grimes SYSLOG(int pri, const char *fmt, ...)
38218fae3551SRodney W. Grimes {
38228fae3551SRodney W. Grimes va_list ap;
38238fae3551SRodney W. Grimes
38248fae3551SRodney W. Grimes va_start(ap, fmt);
38258fae3551SRodney W. Grimes vfprintf(stderr, fmt, ap);
38268fae3551SRodney W. Grimes va_end(ap);
38278fae3551SRodney W. Grimes }
38288fae3551SRodney W. Grimes #endif /* DEBUG */
38298fae3551SRodney W. Grimes
38308fae3551SRodney W. Grimes /*
38318fae3551SRodney W. Grimes * Check options for consistency.
38328fae3551SRodney W. Grimes */
383319c46d8cSEdward Tomasz Napierala static int
check_options(struct dirlist * dp)3834a7a7d96cSPhilippe Charnier check_options(struct dirlist *dp)
38358fae3551SRodney W. Grimes {
38368fae3551SRodney W. Grimes
3837bcc1d071SRick Macklem if (v4root_phase == 0 && dp == NULL)
38388fae3551SRodney W. Grimes return (1);
383991196234SPeter Wemm if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) {
384091196234SPeter Wemm syslog(LOG_ERR, "-mapall and -maproot mutually exclusive");
38418fae3551SRodney W. Grimes return (1);
38428fae3551SRodney W. Grimes }
38438fae3551SRodney W. Grimes if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
384460caaee2SIan Dowse syslog(LOG_ERR, "-mask requires -network");
384560caaee2SIan Dowse return (1);
384660caaee2SIan Dowse }
384760caaee2SIan Dowse if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) {
384860caaee2SIan Dowse syslog(LOG_ERR, "-network requires mask specification");
384960caaee2SIan Dowse return (1);
385060caaee2SIan Dowse }
385160caaee2SIan Dowse if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) {
385260caaee2SIan Dowse syslog(LOG_ERR, "-mask and /masklen are mutually exclusive");
38538fae3551SRodney W. Grimes return (1);
38548fae3551SRodney W. Grimes }
3855bcc1d071SRick Macklem if (v4root_phase > 0 &&
3856bcc1d071SRick Macklem (opt_flags &
3857bcc1d071SRick Macklem ~(OP_SEC | OP_MASK | OP_NET | OP_HAVEMASK | OP_MASKLEN)) != 0) {
3858bcc1d071SRick Macklem syslog(LOG_ERR,"only -sec,-net,-mask options allowed on V4:");
3859bcc1d071SRick Macklem return (1);
3860bcc1d071SRick Macklem }
386156cfc5edSRick Macklem if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
386256cfc5edSRick Macklem syslog(LOG_ERR, "-alldirs has multiple directories");
386356cfc5edSRick Macklem return (1);
386456cfc5edSRick Macklem }
38658fae3551SRodney W. Grimes return (0);
38668fae3551SRodney W. Grimes }
38678fae3551SRodney W. Grimes
386819c46d8cSEdward Tomasz Napierala static int
check_path_component(const char * path,char ** err)3869572b77f8SAlexander Motin check_path_component(const char *path, char **err)
38708fae3551SRodney W. Grimes {
38718fae3551SRodney W. Grimes struct stat sb;
38728fae3551SRodney W. Grimes
3873572b77f8SAlexander Motin if (lstat(path, &sb)) {
3874572b77f8SAlexander Motin asprintf(err, "%s: lstat() failed: %s.\n",
3875572b77f8SAlexander Motin path, strerror(errno));
3876572b77f8SAlexander Motin return (0);
3877572b77f8SAlexander Motin }
3878572b77f8SAlexander Motin
3879572b77f8SAlexander Motin switch (sb.st_mode & S_IFMT) {
3880572b77f8SAlexander Motin case S_IFDIR:
3881572b77f8SAlexander Motin return (1);
3882572b77f8SAlexander Motin case S_IFLNK:
3883572b77f8SAlexander Motin asprintf(err, "%s: path is a symbolic link.\n", path);
3884572b77f8SAlexander Motin break;
3885572b77f8SAlexander Motin case S_IFREG:
3886572b77f8SAlexander Motin asprintf(err, "%s: path is a file rather than a directory.\n",
3887572b77f8SAlexander Motin path);
3888572b77f8SAlexander Motin break;
3889572b77f8SAlexander Motin default:
3890572b77f8SAlexander Motin asprintf(err, "%s: path is not a directory.\n", path);
3891572b77f8SAlexander Motin }
3892572b77f8SAlexander Motin
3893572b77f8SAlexander Motin return (0);
3894572b77f8SAlexander Motin }
3895572b77f8SAlexander Motin
3896572b77f8SAlexander Motin /*
3897572b77f8SAlexander Motin * Check each path component for the presence of symbolic links. Return true
3898572b77f8SAlexander Motin */
3899572b77f8SAlexander Motin static int
check_dirpath(char * dirp,char ** err)3900572b77f8SAlexander Motin check_dirpath(char *dirp, char **err)
3901572b77f8SAlexander Motin {
3902572b77f8SAlexander Motin char *cp;
3903572b77f8SAlexander Motin
39048fae3551SRodney W. Grimes cp = dirp + 1;
3905572b77f8SAlexander Motin while (*cp) {
39068fae3551SRodney W. Grimes if (*cp == '/') {
39078fae3551SRodney W. Grimes *cp = '\0';
3908572b77f8SAlexander Motin
3909572b77f8SAlexander Motin if (!check_path_component(dirp, err)) {
3910572b77f8SAlexander Motin *cp = '/';
3911572b77f8SAlexander Motin return (0);
3912572b77f8SAlexander Motin }
3913572b77f8SAlexander Motin
39148fae3551SRodney W. Grimes *cp = '/';
39158fae3551SRodney W. Grimes }
39168fae3551SRodney W. Grimes cp++;
39178fae3551SRodney W. Grimes }
3918572b77f8SAlexander Motin
3919572b77f8SAlexander Motin if (!check_path_component(dirp, err))
3920572b77f8SAlexander Motin return (0);
3921572b77f8SAlexander Motin
3922572b77f8SAlexander Motin return (1);
3923572b77f8SAlexander Motin }
3924572b77f8SAlexander Motin
3925572b77f8SAlexander Motin /*
3926572b77f8SAlexander Motin * Populate statfs information. Return true on success.
3927572b77f8SAlexander Motin */
3928572b77f8SAlexander Motin static int
check_statfs(const char * dirp,struct statfs * fsb,char ** err)3929572b77f8SAlexander Motin check_statfs(const char *dirp, struct statfs *fsb, char **err)
3930572b77f8SAlexander Motin {
3931572b77f8SAlexander Motin if (statfs(dirp, fsb)) {
3932572b77f8SAlexander Motin asprintf(err, "%s: statfs() failed: %s\n", dirp,
3933572b77f8SAlexander Motin strerror(errno));
3934572b77f8SAlexander Motin return (0);
3935572b77f8SAlexander Motin }
3936572b77f8SAlexander Motin
3937572b77f8SAlexander Motin return (1);
39388fae3551SRodney W. Grimes }
3939a62dc406SDoug Rabson
394060caaee2SIan Dowse /*
394160caaee2SIan Dowse * Make a netmask according to the specified prefix length. The ss_family
394260caaee2SIan Dowse * and other non-address fields must be initialised before calling this.
394360caaee2SIan Dowse */
394419c46d8cSEdward Tomasz Napierala static int
makemask(struct sockaddr_storage * ssp,int bitlen)394560caaee2SIan Dowse makemask(struct sockaddr_storage *ssp, int bitlen)
39468360efbdSAlfred Perlstein {
394760caaee2SIan Dowse u_char *p;
394860caaee2SIan Dowse int bits, i, len;
39498360efbdSAlfred Perlstein
395060caaee2SIan Dowse if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL)
395160caaee2SIan Dowse return (-1);
395289fdc4e1SMike Barcroft if (bitlen > len * CHAR_BIT)
395360caaee2SIan Dowse return (-1);
39548360efbdSAlfred Perlstein
395560caaee2SIan Dowse for (i = 0; i < len; i++) {
3956a175f065SMarcelo Araujo bits = MIN(CHAR_BIT, bitlen);
395758202d89SRuslan Ermilov *p++ = (u_char)~0 << (CHAR_BIT - bits);
395860caaee2SIan Dowse bitlen -= bits;
39598360efbdSAlfred Perlstein }
39608360efbdSAlfred Perlstein return 0;
39618360efbdSAlfred Perlstein }
39628360efbdSAlfred Perlstein
396360caaee2SIan Dowse /*
396460caaee2SIan Dowse * Check that the sockaddr is a valid netmask. Returns 0 if the mask
396560caaee2SIan Dowse * is acceptable (i.e. of the form 1...10....0).
396660caaee2SIan Dowse */
396719c46d8cSEdward Tomasz Napierala static int
checkmask(struct sockaddr * sa)396860caaee2SIan Dowse checkmask(struct sockaddr *sa)
39698360efbdSAlfred Perlstein {
397060caaee2SIan Dowse u_char *mask;
397160caaee2SIan Dowse int i, len;
397260caaee2SIan Dowse
397360caaee2SIan Dowse if ((mask = sa_rawaddr(sa, &len)) == NULL)
397460caaee2SIan Dowse return (-1);
397560caaee2SIan Dowse
397660caaee2SIan Dowse for (i = 0; i < len; i++)
397760caaee2SIan Dowse if (mask[i] != 0xff)
397860caaee2SIan Dowse break;
397960caaee2SIan Dowse if (i < len) {
398060caaee2SIan Dowse if (~mask[i] & (u_char)(~mask[i] + 1))
398160caaee2SIan Dowse return (-1);
398260caaee2SIan Dowse i++;
398360caaee2SIan Dowse }
398460caaee2SIan Dowse for (; i < len; i++)
398560caaee2SIan Dowse if (mask[i] != 0)
398660caaee2SIan Dowse return (-1);
398760caaee2SIan Dowse return (0);
398860caaee2SIan Dowse }
398960caaee2SIan Dowse
399060caaee2SIan Dowse /*
399160caaee2SIan Dowse * Compare two sockaddrs according to a specified mask. Return zero if
399260caaee2SIan Dowse * `sa1' matches `sa2' when filtered by the netmask in `samask'.
39933df5ecacSUlrich Spörlein * If samask is NULL, perform a full comparison.
399460caaee2SIan Dowse */
399519c46d8cSEdward Tomasz Napierala static int
sacmp(struct sockaddr * sa1,struct sockaddr * sa2,struct sockaddr * samask)399660caaee2SIan Dowse sacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask)
399760caaee2SIan Dowse {
399860caaee2SIan Dowse unsigned char *p1, *p2, *mask;
399960caaee2SIan Dowse int len, i;
400060caaee2SIan Dowse
400160caaee2SIan Dowse if (sa1->sa_family != sa2->sa_family ||
400260caaee2SIan Dowse (p1 = sa_rawaddr(sa1, &len)) == NULL ||
400360caaee2SIan Dowse (p2 = sa_rawaddr(sa2, NULL)) == NULL)
400460caaee2SIan Dowse return (1);
400560caaee2SIan Dowse
400660caaee2SIan Dowse switch (sa1->sa_family) {
400760caaee2SIan Dowse case AF_INET6:
400860caaee2SIan Dowse if (((struct sockaddr_in6 *)sa1)->sin6_scope_id !=
400960caaee2SIan Dowse ((struct sockaddr_in6 *)sa2)->sin6_scope_id)
401060caaee2SIan Dowse return (1);
401160caaee2SIan Dowse break;
401260caaee2SIan Dowse }
401360caaee2SIan Dowse
401460caaee2SIan Dowse /* Simple binary comparison if no mask specified. */
401560caaee2SIan Dowse if (samask == NULL)
401660caaee2SIan Dowse return (memcmp(p1, p2, len));
401760caaee2SIan Dowse
401860caaee2SIan Dowse /* Set up the mask, and do a mask-based comparison. */
401960caaee2SIan Dowse if (sa1->sa_family != samask->sa_family ||
402060caaee2SIan Dowse (mask = sa_rawaddr(samask, NULL)) == NULL)
402160caaee2SIan Dowse return (1);
402260caaee2SIan Dowse
402360caaee2SIan Dowse for (i = 0; i < len; i++)
402460caaee2SIan Dowse if ((p1[i] & mask[i]) != (p2[i] & mask[i]))
402560caaee2SIan Dowse return (1);
402660caaee2SIan Dowse return (0);
402760caaee2SIan Dowse }
402860caaee2SIan Dowse
402960caaee2SIan Dowse /*
403060caaee2SIan Dowse * Return a pointer to the part of the sockaddr that contains the
403160caaee2SIan Dowse * raw address, and set *nbytes to its length in bytes. Returns
403260caaee2SIan Dowse * NULL if the address family is unknown.
403360caaee2SIan Dowse */
403419c46d8cSEdward Tomasz Napierala static void *
sa_rawaddr(struct sockaddr * sa,int * nbytes)403560caaee2SIan Dowse sa_rawaddr(struct sockaddr *sa, int *nbytes) {
403660caaee2SIan Dowse void *p;
403760caaee2SIan Dowse int len;
40388360efbdSAlfred Perlstein
40398360efbdSAlfred Perlstein switch (sa->sa_family) {
40408360efbdSAlfred Perlstein case AF_INET:
404160caaee2SIan Dowse len = sizeof(((struct sockaddr_in *)sa)->sin_addr);
404260caaee2SIan Dowse p = &((struct sockaddr_in *)sa)->sin_addr;
40438360efbdSAlfred Perlstein break;
40448360efbdSAlfred Perlstein case AF_INET6:
404560caaee2SIan Dowse len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr);
404660caaee2SIan Dowse p = &((struct sockaddr_in6 *)sa)->sin6_addr;
40478360efbdSAlfred Perlstein break;
40488360efbdSAlfred Perlstein default:
404960caaee2SIan Dowse p = NULL;
405060caaee2SIan Dowse len = 0;
40518360efbdSAlfred Perlstein }
40528360efbdSAlfred Perlstein
405360caaee2SIan Dowse if (nbytes != NULL)
405460caaee2SIan Dowse *nbytes = len;
405560caaee2SIan Dowse return (p);
40568360efbdSAlfred Perlstein }
40578360efbdSAlfred Perlstein
405819c46d8cSEdward Tomasz Napierala static void
huphandler(int sig __unused)4059a7a7d96cSPhilippe Charnier huphandler(int sig __unused)
406069d65572SIan Dowse {
406119c46d8cSEdward Tomasz Napierala
406269d65572SIan Dowse got_sighup = 1;
406369d65572SIan Dowse }
406469d65572SIan Dowse
406519c46d8cSEdward Tomasz Napierala static void
terminate(int sig __unused)406619c46d8cSEdward Tomasz Napierala terminate(int sig __unused)
40678360efbdSAlfred Perlstein {
4068a032b226SPawel Jakub Dawidek pidfile_remove(pfh);
40690775314bSDoug Rabson rpcb_unset(MOUNTPROG, MOUNTVERS, NULL);
40700775314bSDoug Rabson rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL);
40718360efbdSAlfred Perlstein exit (0);
40728360efbdSAlfred Perlstein }
4073cc5efddeSRick Macklem
4074cc5efddeSRick Macklem static void
cp_cred(struct expcred * outcr,struct expcred * incr)4075cc5efddeSRick Macklem cp_cred(struct expcred *outcr, struct expcred *incr)
4076cc5efddeSRick Macklem {
4077cc5efddeSRick Macklem
4078cc5efddeSRick Macklem outcr->cr_uid = incr->cr_uid;
4079cc5efddeSRick Macklem outcr->cr_ngroups = incr->cr_ngroups;
40802ffad162SRick Macklem if (outcr->cr_ngroups > SMALLNGROUPS)
40812ffad162SRick Macklem outcr->cr_groups = malloc(outcr->cr_ngroups * sizeof(gid_t));
40822ffad162SRick Macklem else
40832ffad162SRick Macklem outcr->cr_groups = outcr->cr_smallgrps;
4084cc5efddeSRick Macklem memcpy(outcr->cr_groups, incr->cr_groups, incr->cr_ngroups *
4085cc5efddeSRick Macklem sizeof(gid_t));
4086cc5efddeSRick Macklem }
4087