View | Details | Raw Unified | Return to bug 237860 | Differences between
and this patch

Collapse All | Expand All

(-)usr.sbin/mountd/mountd.c (-141 / +685 lines)
Lines 49-54 __FBSDID("$FreeBSD: head/usr.sbin/mountd Link Here
49
49
50
#include <sys/param.h>
50
#include <sys/param.h>
51
#include <sys/fcntl.h>
51
#include <sys/fcntl.h>
52
#include <sys/fnv_hash.h>
52
#include <sys/linker.h>
53
#include <sys/linker.h>
53
#include <sys/module.h>
54
#include <sys/module.h>
54
#include <sys/mount.h>
55
#include <sys/mount.h>
Lines 114-123 struct dirlist { Link Here
114
struct exportlist {
115
struct exportlist {
115
	struct dirlist	*ex_dirl;
116
	struct dirlist	*ex_dirl;
116
	struct dirlist	*ex_defdir;
117
	struct dirlist	*ex_defdir;
118
	struct grouplist *ex_grphead;
117
	int		ex_flag;
119
	int		ex_flag;
118
	fsid_t		ex_fs;
120
	fsid_t		ex_fs;
119
	char		*ex_fsdir;
121
	char		*ex_fsdir;
120
	char		*ex_indexfile;
122
	char		*ex_indexfile;
123
	struct xucred	ex_defanon;
124
	int		ex_defexflags;
121
	int		ex_numsecflavors;
125
	int		ex_numsecflavors;
122
	int		ex_secflavors[MAXSECFLAVORS];
126
	int		ex_secflavors[MAXSECFLAVORS];
123
	int		ex_defnumsecflavors;
127
	int		ex_defnumsecflavors;
Lines 127-132 struct exportlist { Link Here
127
};
131
};
128
/* ex_flag bits */
132
/* ex_flag bits */
129
#define	EX_LINKED	0x1
133
#define	EX_LINKED	0x1
134
#define	EX_DONE		0x2
135
#define	EX_DEFSET	0x4
136
#define	EX_PUBLICFH	0x8
137
138
SLIST_HEAD(exportlisthead, exportlist);
130
139
131
struct netmsk {
140
struct netmsk {
132
	struct sockaddr_storage nt_net;
141
	struct sockaddr_storage nt_net;
Lines 143-148 struct grouplist { Link Here
143
	int gr_type;
152
	int gr_type;
144
	union grouptypes gr_ptr;
153
	union grouptypes gr_ptr;
145
	struct grouplist *gr_next;
154
	struct grouplist *gr_next;
155
	struct xucred gr_anon;
156
	int gr_exflags;
157
	int gr_flag;
146
	int gr_numsecflavors;
158
	int gr_numsecflavors;
147
	int gr_secflavors[MAXSECFLAVORS];
159
	int gr_secflavors[MAXSECFLAVORS];
148
};
160
};
Lines 153-158 struct grouplist { Link Here
153
#define	GT_DEFAULT	0x3
165
#define	GT_DEFAULT	0x3
154
#define GT_IGNORE	0x5
166
#define GT_IGNORE	0x5
155
167
168
/* Group flags */
169
#define	GR_FND		0x1
170
156
struct hostlist {
171
struct hostlist {
157
	int		 ht_flag;	/* Uses DP_xx bits */
172
	int		 ht_flag;	/* Uses DP_xx bits */
158
	struct grouplist *ht_grp;
173
	struct grouplist *ht_grp;
Lines 172-178 struct fhreturn { Link Here
172
/* Global defs */
187
/* Global defs */
173
static char	*add_expdir(struct dirlist **, char *, int);
188
static char	*add_expdir(struct dirlist **, char *, int);
174
static void	add_dlist(struct dirlist **, struct dirlist *,
189
static void	add_dlist(struct dirlist **, struct dirlist *,
175
		    struct grouplist *, int, struct exportlist *);
190
		    struct grouplist *, int, struct exportlist *,
191
		    struct xucred *, int);
176
static void	add_mlist(char *, char *);
192
static void	add_mlist(char *, char *);
177
static int	check_dirpath(char *);
193
static int	check_dirpath(char *);
178
static int	check_options(struct dirlist *);
194
static int	check_options(struct dirlist *);
Lines 185-201 static void complete_service(struct netc Link Here
185
static void	clearout_service(void);
201
static void	clearout_service(void);
186
static void	del_mlist(char *hostp, char *dirp);
202
static void	del_mlist(char *hostp, char *dirp);
187
static struct dirlist	*dirp_search(struct dirlist *, char *);
203
static struct dirlist	*dirp_search(struct dirlist *, char *);
204
static int	do_export_mount(struct exportlist *, struct statfs *);
188
static int	do_mount(struct exportlist *, struct grouplist *, int,
205
static int	do_mount(struct exportlist *, struct grouplist *, int,
189
		    struct xucred *, char *, int, struct statfs *);
206
		    struct xucred *, char *, int, struct statfs *, int, int *);
190
static int	do_opt(char **, char **, struct exportlist *,
207
static int	do_opt(char **, char **, struct exportlist *,
191
		    struct grouplist *, int *, int *, struct xucred *);
208
		    struct grouplist *, int *, int *, struct xucred *);
192
static struct exportlist	*ex_search(fsid_t *);
209
static struct exportlist	*ex_search(fsid_t *, struct exportlisthead *);
193
static struct exportlist	*get_exp(void);
210
static struct exportlist	*get_exp(void);
194
static void	free_dir(struct dirlist *);
211
static void	free_dir(struct dirlist *);
195
static void	free_exp(struct exportlist *);
212
static void	free_exp(struct exportlist *);
196
static void	free_grp(struct grouplist *);
213
static void	free_grp(struct grouplist *);
197
static void	free_host(struct hostlist *);
214
static void	free_host(struct hostlist *);
198
static void	get_exportlist(void);
215
static void	free_v4rootexp(void);
216
static void	get_exportlist_one(int);
217
static void	get_exportlist(int);
218
static void	insert_exports(struct exportlist *, struct exportlisthead *);
219
static void	free_exports(struct exportlisthead *);
220
static void	read_exportfile(int);
221
static int	compare_nmount_exportlist(struct iovec *, int, char *);
222
static int	compare_export(struct exportlist *, struct exportlist *);
223
static int	compare_cred(struct xucred *, struct xucred *);
224
static int	compare_secflavor(int *, int *, int);
225
static void	delete_export(struct iovec *, int, struct statfs *, char *);
199
static int	get_host(char *, struct grouplist *, struct grouplist *);
226
static int	get_host(char *, struct grouplist *, struct grouplist *);
200
static struct hostlist *get_ht(void);
227
static struct hostlist *get_ht(void);
201
static int	get_line(void);
228
static int	get_line(void);
Lines 204-210 static int get_net(char *, struct netmsk Link Here
204
static void	getexp_err(struct exportlist *, struct grouplist *, const char *);
231
static void	getexp_err(struct exportlist *, struct grouplist *, const char *);
205
static struct grouplist	*get_grp(void);
232
static struct grouplist	*get_grp(void);
206
static void	hang_dirp(struct dirlist *, struct grouplist *,
233
static void	hang_dirp(struct dirlist *, struct grouplist *,
207
				struct exportlist *, int);
234
		    struct exportlist *, int, struct xucred *, int);
208
static void	huphandler(int sig);
235
static void	huphandler(int sig);
209
static int	makemask(struct sockaddr_storage *ssp, int bitlen);
236
static int	makemask(struct sockaddr_storage *ssp, int bitlen);
210
static void	mntsrv(struct svc_req *, SVCXPRT *);
237
static void	mntsrv(struct svc_req *, SVCXPRT *);
Lines 227-235 static int xdr_fhs(XDR *, caddr_t); Link Here
227
static int	xdr_mlist(XDR *, caddr_t);
254
static int	xdr_mlist(XDR *, caddr_t);
228
static void	terminate(int);
255
static void	terminate(int);
229
256
230
static SLIST_HEAD(, exportlist) exphead = SLIST_HEAD_INITIALIZER(exphead);
257
#define	EXPHASH(f)	(fnv_32_buf((f), sizeof(fsid_t), 0) % exphashsize)
231
static SLIST_HEAD(, mountlist) mlhead = SLIST_HEAD_INITIALIZER(mlhead);
258
static struct exportlisthead *exphead = NULL;
232
static struct grouplist *grphead;
259
static struct exportlisthead *oldexphead = NULL;
260
static int exphashsize = 0;
261
static SLIST_HEAD(, mountlist) mlhead = SLIST_HEAD_INITIALIZER(&mlhead);
233
static char *exnames_default[2] = { _PATH_EXPORTS, NULL };
262
static char *exnames_default[2] = { _PATH_EXPORTS, NULL };
234
static char **exnames;
263
static char **exnames;
235
static char **hosts = NULL;
264
static char **hosts = NULL;
Lines 260-266 static int have_v6 = 1; Link Here
260
289
261
static int v4root_phase = 0;
290
static int v4root_phase = 0;
262
static char v4root_dirpath[PATH_MAX + 1];
291
static char v4root_dirpath[PATH_MAX + 1];
292
static struct exportlist *v4root_ep = NULL;
263
static int has_publicfh = 0;
293
static int has_publicfh = 0;
294
static int has_set_publicfh = 0;
264
295
265
static struct pidfh *pfh = NULL;
296
static struct pidfh *pfh = NULL;
266
/* Bits for opt_flags above */
297
/* Bits for opt_flags above */
Lines 284-289 static int debug = 0; Link Here
284
#endif
315
#endif
285
316
286
/*
317
/*
318
 * The LOGDEBUG() syslog() calls are always compiled into the daemon.
319
 * To enable them, create a file at _PATH_MOUNTDDEBUG. This file can be empty.
320
 * To disable the logging, just delete the file at _PATH_MOUNTDDEBUG.
321
 */
322
static int logdebug = 0;
323
#define	LOGDEBUG(format, ...)						\
324
    (logdebug ? syslog(LOG_DEBUG, format, ## __VA_ARGS__) : 0)
325
326
/*
287
 * Similar to strsep(), but it allows for quoted strings
327
 * Similar to strsep(), but it allows for quoted strings
288
 * and escaped characters.
328
 * and escaped characters.
289
 *
329
 *
Lines 368-376 main(int argc, char **argv) Link Here
368
	in_port_t svcport;
408
	in_port_t svcport;
369
	int c, k, s;
409
	int c, k, s;
370
	int maxrec = RPC_MAXDATASIZE;
410
	int maxrec = RPC_MAXDATASIZE;
371
	int attempt_cnt, port_len, port_pos, ret;
411
	int attempt_cnt, passno, port_len, port_pos, ret;
372
	char **port_list;
412
	char **port_list;
373
413
414
	passno = 0;
374
	/* Check that another mountd isn't already running. */
415
	/* Check that another mountd isn't already running. */
375
	pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid);
416
	pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid);
376
	if (pfh == NULL) {
417
	if (pfh == NULL) {
Lines 385-391 main(int argc, char **argv) Link Here
385
	else
426
	else
386
		close(s);
427
		close(s);
387
428
388
	while ((c = getopt(argc, argv, "2deh:lnp:rS")) != -1)
429
	while ((c = getopt(argc, argv, "2deh:Ilnp:rS")) != -1)
389
		switch (c) {
430
		switch (c) {
390
		case '2':
431
		case '2':
391
			force_v2 = 1;
432
			force_v2 = 1;
Lines 437-442 main(int argc, char **argv) Link Here
437
		case 'S':
478
		case 'S':
438
			suspend_nfsd = 1;
479
			suspend_nfsd = 1;
439
			break;
480
			break;
481
		case 'I':
482
			passno = 1;
483
			break;
440
		default:
484
		default:
441
			usage();
485
			usage();
442
		}
486
		}
Lines 449-455 main(int argc, char **argv) Link Here
449
493
450
	argc -= optind;
494
	argc -= optind;
451
	argv += optind;
495
	argv += optind;
452
	grphead = (struct grouplist *)NULL;
453
	if (argc > 0)
496
	if (argc > 0)
454
		exnames = argv;
497
		exnames = argv;
455
	else
498
	else
Lines 457-463 main(int argc, char **argv) Link Here
457
	openlog("mountd", LOG_PID, LOG_DAEMON);
500
	openlog("mountd", LOG_PID, LOG_DAEMON);
458
	if (debug)
501
	if (debug)
459
		warnx("getting export list");
502
		warnx("getting export list");
460
	get_exportlist();
503
	get_exportlist(0);
461
	if (debug)
504
	if (debug)
462
		warnx("getting mount list");
505
		warnx("getting mount list");
463
	get_mountlist();
506
	get_mountlist();
Lines 628-634 main(int argc, char **argv) Link Here
628
	/* Expand svc_run() here so that we can call get_exportlist(). */
671
	/* Expand svc_run() here so that we can call get_exportlist(). */
629
	for (;;) {
672
	for (;;) {
630
		if (got_sighup) {
673
		if (got_sighup) {
631
			get_exportlist();
674
			get_exportlist(passno);
632
			got_sighup = 0;
675
			got_sighup = 0;
633
		}
676
		}
634
		readfds = svc_fdset;
677
		readfds = svc_fdset;
Lines 1087-1093 mntsrv(struct svc_req *rqstp, SVCXPRT *t Link Here
1087
		if (bad)
1130
		if (bad)
1088
			ep = NULL;
1131
			ep = NULL;
1089
		else
1132
		else
1090
			ep = ex_search(&fsb.f_fsid);
1133
			ep = ex_search(&fsb.f_fsid, exphead);
1091
		hostset = defset = 0;
1134
		hostset = defset = 0;
1092
		if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset,
1135
		if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset,
1093
		    &numsecflavors, &secflavorsp) ||
1136
		    &numsecflavors, &secflavorsp) ||
Lines 1302-1322 xdr_explist_common(XDR *xdrsp, caddr_t c Link Here
1302
	int false = 0;
1345
	int false = 0;
1303
	int putdef;
1346
	int putdef;
1304
	sigset_t sighup_mask;
1347
	sigset_t sighup_mask;
1348
	int i;
1305
1349
1306
	sigemptyset(&sighup_mask);
1350
	sigemptyset(&sighup_mask);
1307
	sigaddset(&sighup_mask, SIGHUP);
1351
	sigaddset(&sighup_mask, SIGHUP);
1308
	sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
1352
	sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
1309
1353
1310
	SLIST_FOREACH(ep, &exphead, entries) {
1354
	for (i = 0; i < exphashsize; i++)
1311
		putdef = 0;
1355
		SLIST_FOREACH(ep, &exphead[i], entries) {
1312
		if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir,
1356
			putdef = 0;
1313
			       &putdef, brief))
1357
			if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir,
1314
			goto errout;
1358
				       &putdef, brief))
1315
		if (ep->ex_defdir && putdef == 0 &&
1359
				goto errout;
1316
			put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL,
1360
			if (ep->ex_defdir && putdef == 0 &&
1317
			&putdef, brief))
1361
				put_exlist(ep->ex_defdir, xdrsp, NULL,
1318
			goto errout;
1362
				&putdef, brief))
1319
	}
1363
				goto errout;
1364
		}
1320
	sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
1365
	sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
1321
	if (!xdr_bool(xdrsp, &false))
1366
	if (!xdr_bool(xdrsp, &false))
1322
		return (0);
1367
		return (0);
Lines 1416-1425 static FILE *exp_file; Link Here
1416
 * Get the export list from one, currently open file
1461
 * Get the export list from one, currently open file
1417
 */
1462
 */
1418
static void
1463
static void
1419
get_exportlist_one(void)
1464
get_exportlist_one(int passno)
1420
{
1465
{
1421
	struct exportlist *ep;
1466
	struct exportlist *ep;
1422
	struct grouplist *grp, *tgrp;
1467
	struct grouplist *grp, *tgrp, *savgrp;
1423
	struct dirlist *dirhead;
1468
	struct dirlist *dirhead;
1424
	struct statfs fsb;
1469
	struct statfs fsb;
1425
	struct xucred anon;
1470
	struct xucred anon;
Lines 1540-1546 get_exportlist_one(void) Link Here
1540
					 * See if this directory is already
1585
					 * See if this directory is already
1541
					 * in the list.
1586
					 * in the list.
1542
					 */
1587
					 */
1543
					ep = ex_search(&fsb.f_fsid);
1588
					ep = ex_search(&fsb.f_fsid, exphead);
1544
					if (ep == (struct exportlist *)NULL) {
1589
					if (ep == (struct exportlist *)NULL) {
1545
					    ep = get_exp();
1590
					    ep = get_exp();
1546
					    ep->ex_fs = fsb.f_fsid;
1591
					    ep->ex_fs = fsb.f_fsid;
Lines 1653-1663 get_exportlist_one(void) Link Here
1653
		 * Loop through hosts, pushing the exports into the kernel.
1698
		 * Loop through hosts, pushing the exports into the kernel.
1654
		 * After loop, tgrp points to the start of the list and
1699
		 * After loop, tgrp points to the start of the list and
1655
		 * grp points to the last entry in the list.
1700
		 * grp points to the last entry in the list.
1701
		 * Do not do the do_mount() for passno == 1, since the
1702
		 * second pass will do it, as required.
1656
		 */
1703
		 */
1657
		grp = tgrp;
1704
		grp = tgrp;
1658
		do {
1705
		do {
1659
			if (do_mount(ep, grp, exflags, &anon, dirp, dirplen,
1706
			grp->gr_exflags = exflags;
1660
			    &fsb)) {
1707
			grp->gr_anon = anon;
1708
			if (v4root_phase == 2 && passno == 0)
1709
				LOGDEBUG("do_mount v4root");
1710
			if (passno == 0 && do_mount(ep, grp, exflags, &anon,
1711
			    dirp, dirplen, &fsb, ep->ex_numsecflavors,
1712
			    ep->ex_secflavors)) {
1661
				getexp_err(ep, tgrp, NULL);
1713
				getexp_err(ep, tgrp, NULL);
1662
				goto nextline;
1714
				goto nextline;
1663
			}
1715
			}
Lines 1668-1676 get_exportlist_one(void) Link Here
1668
		 */
1720
		 */
1669
		if (v4root_phase > 0 && v4root_phase <= 2) {
1721
		if (v4root_phase > 0 && v4root_phase <= 2) {
1670
			/*
1722
			/*
1671
			 * Since these structures aren't used by mountd,
1723
			 * These structures are used for the "-I" reload,
1724
			 * so save them for that case.  Otherwise, just
1672
			 * free them up now.
1725
			 * free them up now.
1673
			 */
1726
			 */
1727
			if (passno == 1 && ep != NULL) {
1728
				savgrp = tgrp;
1729
				while (tgrp != NULL) {
1730
					/*
1731
					 * Save the security flavors and exflags
1732
					 * for this host set in the groups.
1733
					 */
1734
					tgrp->gr_numsecflavors =
1735
					    ep->ex_numsecflavors;
1736
					if (ep->ex_numsecflavors > 0)
1737
						memcpy(tgrp->gr_secflavors,
1738
						    ep->ex_secflavors,
1739
						    sizeof(ep->ex_secflavors));
1740
					tgrp = tgrp->gr_next;
1741
				}
1742
				if (v4root_ep == NULL) {
1743
					v4root_ep = ep;
1744
					ep = NULL;	/* Don't free below. */
1745
				}
1746
				grp->gr_next = v4root_ep->ex_grphead;
1747
				v4root_ep->ex_grphead = savgrp;
1748
			}
1674
			if (ep != NULL)
1749
			if (ep != NULL)
1675
				free_exp(ep);
1750
				free_exp(ep);
1676
			while (tgrp != NULL) {
1751
			while (tgrp != NULL) {
Lines 1685-1701 get_exportlist_one(void) Link Here
1685
		 * Success. Update the data structures.
1760
		 * Success. Update the data structures.
1686
		 */
1761
		 */
1687
		if (has_host) {
1762
		if (has_host) {
1688
			hang_dirp(dirhead, tgrp, ep, opt_flags);
1763
			hang_dirp(dirhead, tgrp, ep, opt_flags, &anon, exflags);
1689
			grp->gr_next = grphead;
1764
			grp->gr_next = ep->ex_grphead;
1690
			grphead = tgrp;
1765
			ep->ex_grphead = tgrp;
1691
		} else {
1766
		} else {
1692
			hang_dirp(dirhead, (struct grouplist *)NULL, ep,
1767
			hang_dirp(dirhead, (struct grouplist *)NULL, ep,
1693
				opt_flags);
1768
				opt_flags, &anon, exflags);
1694
			free_grp(grp);
1769
			free_grp(grp);
1695
		}
1770
		}
1696
		dirhead = (struct dirlist *)NULL;
1771
		dirhead = (struct dirlist *)NULL;
1697
		if ((ep->ex_flag & EX_LINKED) == 0) {
1772
		if ((ep->ex_flag & EX_LINKED) == 0) {
1698
			SLIST_INSERT_HEAD(&exphead, ep, entries);
1773
			insert_exports(ep, exphead);
1699
1774
1700
			ep->ex_flag |= EX_LINKED;
1775
			ep->ex_flag |= EX_LINKED;
1701
		}
1776
		}
Lines 1712-1758 nextline: Link Here
1712
 * Get the export list from all specified files
1787
 * Get the export list from all specified files
1713
 */
1788
 */
1714
static void
1789
static void
1715
get_exportlist(void)
1790
get_exportlist(int passno)
1716
{
1791
{
1717
	struct exportlist *ep, *ep2;
1718
	struct grouplist *grp, *tgrp;
1719
	struct export_args export;
1792
	struct export_args export;
1720
	struct iovec *iov;
1793
	struct iovec *iov;
1721
	struct statfs *fsp, *mntbufp;
1794
	struct statfs *mntbufp;
1722
	struct xvfsconf vfc;
1723
	char errmsg[255];
1795
	char errmsg[255];
1724
	int num, i;
1796
	int num, i;
1725
	int iovlen;
1797
	int iovlen;
1726
	int done;
1727
	struct nfsex_args eargs;
1798
	struct nfsex_args eargs;
1799
	FILE *debug_file;
1728
1800
1729
	if (suspend_nfsd != 0)
1801
	if ((debug_file = fopen(_PATH_MOUNTDDEBUG, "r")) != NULL) {
1730
		(void)nfssvc(NFSSVC_SUSPENDNFSD, NULL);
1802
		fclose(debug_file);
1803
		logdebug = 1;
1804
	} else
1805
		logdebug = 0;
1806
	LOGDEBUG("passno=%d", passno);
1731
	v4root_dirpath[0] = '\0';
1807
	v4root_dirpath[0] = '\0';
1808
	free_v4rootexp();
1809
	if (passno == 1) {
1810
		/*
1811
		 * Save the current lists as old ones, so that the new lists
1812
		 * can be compared with the old ones in the 2nd pass.
1813
		 */
1814
		for (i = 0; i < exphashsize; i++) {
1815
			SLIST_FIRST(&oldexphead[i]) = SLIST_FIRST(&exphead[i]);
1816
			SLIST_INIT(&exphead[i]);
1817
		}
1818
1819
		/* Note that the public fh has not yet been set. */
1820
		has_set_publicfh = 0;
1821
1822
		/* Read the export file(s) and process them */
1823
		read_exportfile(passno);
1824
	} else {
1825
		/*
1826
		 * Just make the old lists empty.
1827
		 * exphashsize == 0 for the first call, before oldexphead
1828
		 * has been initialized-->loop won't be executed.
1829
		 */
1830
		for (i = 0; i < exphashsize; i++)
1831
			SLIST_INIT(&oldexphead[i]);
1832
	}
1833
1732
	bzero(&export, sizeof(export));
1834
	bzero(&export, sizeof(export));
1733
	export.ex_flags = MNT_DELEXPORT;
1835
	export.ex_flags = MNT_DELEXPORT;
1734
	iov = NULL;
1836
	iov = NULL;
1735
	iovlen = 0;
1837
	iovlen = 0;
1736
	bzero(errmsg, sizeof(errmsg));
1838
	bzero(errmsg, sizeof(errmsg));
1737
1839
1840
	if (suspend_nfsd != 0)
1841
		(void)nfssvc(NFSSVC_SUSPENDNFSD, NULL);
1738
	/*
1842
	/*
1739
	 * First, get rid of the old list
1843
	 * Delete the old V4 root dir.
1740
	 */
1741
	SLIST_FOREACH_SAFE(ep, &exphead, entries, ep2) {
1742
		SLIST_REMOVE(&exphead, ep, exportlist, entries);
1743
		free_exp(ep);
1744
	}
1745
1746
	grp = grphead;
1747
	while (grp) {
1748
		tgrp = grp;
1749
		grp = grp->gr_next;
1750
		free_grp(tgrp);
1751
	}
1752
	grphead = (struct grouplist *)NULL;
1753
1754
	/*
1755
	 * and the old V4 root dir.
1756
	 */
1844
	 */
1757
	bzero(&eargs, sizeof (eargs));
1845
	bzero(&eargs, sizeof (eargs));
1758
	eargs.export.ex_flags = MNT_DELEXPORT;
1846
	eargs.export.ex_flags = MNT_DELEXPORT;
Lines 1760-1826 get_exportlist(void) Link Here
1760
	    errno != ENOENT)
1848
	    errno != ENOENT)
1761
		syslog(LOG_ERR, "Can't delete exports for V4:");
1849
		syslog(LOG_ERR, "Can't delete exports for V4:");
1762
1850
1763
	/*
1851
	build_iovec(&iov, &iovlen, "fstype", NULL, 0);
1764
	 * and clear flag that notes if a public fh has been exported.
1852
	build_iovec(&iov, &iovlen, "fspath", NULL, 0);
1765
	 */
1853
	build_iovec(&iov, &iovlen, "from", NULL, 0);
1766
	has_publicfh = 0;
1854
	build_iovec(&iov, &iovlen, "update", NULL, 0);
1855
	build_iovec(&iov, &iovlen, "export", &export,
1856
	    sizeof(export));
1857
	build_iovec(&iov, &iovlen, "errmsg", errmsg,
1858
	    sizeof(errmsg));
1767
1859
1768
	/*
1860
	/*
1769
	 * And delete exports that are in the kernel for all local
1861
	 * For passno == 1, compare the old and new lists updating the kernel
1770
	 * filesystems.
1862
	 * exports for any cases that have changed.
1771
	 * XXX: Should know how to handle all local exportable filesystems.
1863
	 * This call is doing the second pass through the lists.
1864
	 * If it fails, fall back on the bulk reload.
1772
	 */
1865
	 */
1773
	num = getmntinfo(&mntbufp, MNT_NOWAIT);
1866
	if (passno == 1 && compare_nmount_exportlist(iov, iovlen, errmsg) ==
1774
1867
	    0) {
1775
	if (num > 0) {
1868
		LOGDEBUG("compareok");
1776
		build_iovec(&iov, &iovlen, "fstype", NULL, 0);
1869
		/* Free up the old lists. */
1777
		build_iovec(&iov, &iovlen, "fspath", NULL, 0);
1870
		free_exports(oldexphead);
1778
		build_iovec(&iov, &iovlen, "from", NULL, 0);
1871
	} else {
1779
		build_iovec(&iov, &iovlen, "update", NULL, 0);
1872
		LOGDEBUG("doing passno=0");
1780
		build_iovec(&iov, &iovlen, "export", &export, sizeof(export));
1873
		/*
1781
		build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
1874
		 * Clear flag that notes if a public fh has been exported.
1782
	}
1875
		 * It is set by do_mount() if MNT_EXPUBLIC is set for the entry.
1876
		 */
1877
		has_publicfh = 0;
1783
1878
1784
	for (i = 0; i < num; i++) {
1879
		/* exphead == NULL if not yet allocated (first call). */
1785
		fsp = &mntbufp[i];
1880
		if (exphead != NULL) {
1786
		if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) {
1881
			/*
1787
			syslog(LOG_ERR, "getvfsbyname() failed for %s",
1882
			 * First, get rid of the old lists.
1788
			    fsp->f_fstypename);
1883
			 */
1789
			continue;
1884
			free_exports(exphead);
1885
			free_exports(oldexphead);
1790
		}
1886
		}
1791
1887
1792
		/*
1888
		/*
1793
		 * We do not need to delete "export" flag from
1889
		 * And delete exports that are in the kernel for all local
1794
		 * filesystems that do not have it set.
1890
		 * filesystems.
1795
		 */
1891
		 * XXX: Should know how to handle all local exportable
1796
		if (!(fsp->f_flags & MNT_EXPORTED))
1892
		 * filesystems.
1797
		    continue;
1893
		 */
1798
		/*
1894
		num = getmntinfo(&mntbufp, MNT_NOWAIT);
1799
		 * Do not delete export for network filesystem by
1895
1800
		 * passing "export" arg to nmount().
1896
		/* Allocate hash tables, for first call. */
1801
		 * It only makes sense to do this for local filesystems.
1897
		if (exphead == NULL) {
1802
		 */
1898
			/* Target an average linked list length of 10. */
1803
		if (vfc.vfc_flags & VFCF_NETWORK)
1899
			exphashsize = num / 10;
1804
			continue;
1900
			if (exphashsize < 1)
1805
1901
				exphashsize = 1;
1806
		iov[1].iov_base = fsp->f_fstypename;
1902
			else if (exphashsize > 100000)
1807
		iov[1].iov_len = strlen(fsp->f_fstypename) + 1;
1903
				exphashsize = 100000;
1808
		iov[3].iov_base = fsp->f_mntonname;
1904
			exphead = malloc(exphashsize * sizeof(*exphead));
1809
		iov[3].iov_len = strlen(fsp->f_mntonname) + 1;
1905
			oldexphead = malloc(exphashsize * sizeof(*oldexphead));
1810
		iov[5].iov_base = fsp->f_mntfromname;
1906
			if (exphead == NULL || oldexphead == NULL)
1811
		iov[5].iov_len = strlen(fsp->f_mntfromname) + 1;
1907
				errx(1, "Can't malloc hash tables");
1812
		errmsg[0] = '\0';
1908
1813
1909
			for (i = 0; i < exphashsize; i++) {
1814
		/*
1910
				SLIST_INIT(&exphead[i]);
1815
		 * EXDEV is returned when path exists but is not a
1911
				SLIST_INIT(&oldexphead[i]);
1816
		 * mount point.  May happens if raced with unmount.
1912
			}
1817
		 */
1818
		if (nmount(iov, iovlen, fsp->f_flags) < 0 &&
1819
		    errno != ENOENT && errno != ENOTSUP && errno != EXDEV) {
1820
			syslog(LOG_ERR,
1821
			    "can't delete exports for %s: %m %s",
1822
			    fsp->f_mntonname, errmsg);
1823
		}
1913
		}
1914
	
1915
		for (i = 0; i < num; i++)
1916
			delete_export(iov, iovlen, &mntbufp[i], errmsg);
1917
1918
1919
		/* Read the export file(s) and process them */
1920
		read_exportfile(0);
1824
	}
1921
	}
1825
1922
1826
	if (iov != NULL) {
1923
	if (iov != NULL) {
Lines 1838-1843 get_exportlist(void) Link Here
1838
	}
1935
	}
1839
1936
1840
	/*
1937
	/*
1938
	 * If there was no public fh, clear any previous one set.
1939
	 */
1940
	if (has_publicfh == 0) {
1941
		LOGDEBUG("clear public fh");
1942
		(void) nfssvc(NFSSVC_NOPUBLICFH, NULL);
1943
	}
1944
1945
	/* Resume the nfsd. If they weren't suspended, this is harmless. */
1946
	(void)nfssvc(NFSSVC_RESUMENFSD, NULL);
1947
	LOGDEBUG("eo get_exportlist");
1948
}
1949
1950
/*
1951
 * Insert an export entry in the appropriate list.
1952
 */
1953
static void
1954
insert_exports(struct exportlist *ep, struct exportlisthead *exhp)
1955
{
1956
	uint32_t i;
1957
1958
	i = EXPHASH(&ep->ex_fs);
1959
	LOGDEBUG("fs=%s hash=%i", ep->ex_fsdir, i);
1960
	SLIST_INSERT_HEAD(&exhp[i], ep, entries);
1961
}
1962
1963
/*
1964
 * Free up the exports lists passed in as arguments.
1965
 */
1966
static void
1967
free_exports(struct exportlisthead *exhp)
1968
{
1969
	struct exportlist *ep, *ep2;
1970
	int i;
1971
1972
	for (i = 0; i < exphashsize; i++) {
1973
		SLIST_FOREACH_SAFE(ep, &exhp[i], entries, ep2) {
1974
			SLIST_REMOVE(&exhp[i], ep, exportlist, entries);
1975
			free_exp(ep);
1976
		}
1977
		SLIST_INIT(&exhp[i]);
1978
	}
1979
}
1980
1981
/*
1982
 * Read the exports file(s) and call get_exportlist_one() for each line.
1983
 */
1984
static void
1985
read_exportfile(int passno)
1986
{
1987
	int done, i;
1988
1989
	/*
1841
	 * Read in the exports file and build the list, calling
1990
	 * Read in the exports file and build the list, calling
1842
	 * nmount() as we go along to push the export rules into the kernel.
1991
	 * nmount() as we go along to push the export rules into the kernel.
1843
	 */
1992
	 */
Lines 1849-1855 get_exportlist(void) Link Here
1849
			syslog(LOG_WARNING, "can't open %s", exnames[i]);
1998
			syslog(LOG_WARNING, "can't open %s", exnames[i]);
1850
			continue;
1999
			continue;
1851
		}
2000
		}
1852
		get_exportlist_one();
2001
		get_exportlist_one(passno);
1853
		fclose(exp_file);
2002
		fclose(exp_file);
1854
		done++;
2003
		done++;
1855
	}
2004
	}
Lines 1857-1871 get_exportlist(void) Link Here
1857
		syslog(LOG_ERR, "can't open any exports file");
2006
		syslog(LOG_ERR, "can't open any exports file");
1858
		exit(2);
2007
		exit(2);
1859
	}
2008
	}
2009
}
2010
2011
/*
2012
 * Compare the export lists against the old ones and do nmount() operations
2013
 * for any cases that have changed.  This avoids doing nmount() for entries
2014
 * that have not changed.
2015
 * Return 0 upon success, 1 otherwise.
2016
 */
2017
static int
2018
compare_nmount_exportlist(struct iovec *iov, int iovlen, char *errmsg)
2019
{
2020
	struct exportlist *ep, *oep;
2021
	struct grouplist *grp;
2022
	struct statfs fs, ofs;
2023
	int i, ret;
1860
2024
1861
	/*
2025
	/*
1862
	 * If there was no public fh, clear any previous one set.
2026
	 * Loop through the current list and look for an entry in the old
2027
	 * list.
2028
	 * If found, check to see if it the same.
2029
	 *        If it is not the same, delete and re-export.
2030
	 *        Then mark it done on the old list.
2031
	 * else (not found)
2032
	 *        export it.
2033
	 * Any entries left in the old list after processing must have their
2034
	 * exports deleted.
1863
	 */
2035
	 */
1864
	if (has_publicfh == 0)
2036
	for (i = 0; i < exphashsize; i++)
1865
		(void) nfssvc(NFSSVC_NOPUBLICFH, NULL);
2037
		SLIST_FOREACH(ep, &exphead[i], entries) {
2038
			LOGDEBUG("foreach ep=%s", ep->ex_fsdir);
2039
			oep = ex_search(&ep->ex_fs, oldexphead);
2040
			if (oep != NULL) {
2041
				/*
2042
				 * Check the mount paths are the same.
2043
				 * If not, return 1 so that the reload of the
2044
				 * exports will be done in bulk, the
2045
				 * passno == 0 way.
2046
				 */
2047
				LOGDEBUG("found old exp");
2048
				if (strcmp(ep->ex_fsdir, oep->ex_fsdir) != 0)
2049
					return (1);
2050
				LOGDEBUG("same fsdir");
2051
				/*
2052
				 * Test to see if the entry is the same.
2053
				 * If not the same delete exports and
2054
				 * re-export.
2055
				 */
2056
				if (compare_export(ep, oep) != 0) {
2057
					/*
2058
					 * Clear has_publicfh if if was set
2059
					 * in the old exports, but only if it
2060
					 * has not been set during processing of
2061
					 * the exports for this pass, as
2062
					 * indicated by has_set_publicfh.
2063
					 */
2064
					if (has_set_publicfh == 0 &&
2065
					    (oep->ex_flag & EX_PUBLICFH) != 0)
2066
						has_publicfh = 0;
1866
2067
1867
	/* Resume the nfsd. If they weren't suspended, this is harmless. */
2068
					/* Delete and re-export. */
1868
	(void)nfssvc(NFSSVC_RESUMENFSD, NULL);
2069
					if (statfs(ep->ex_fsdir, &fs) < 0)
2070
						return (1);
2071
					delete_export(iov, iovlen, &fs, errmsg);
2072
					ret = do_export_mount(ep, &fs);
2073
					if (ret != 0)
2074
						return (ret);
2075
				}
2076
				oep->ex_flag |= EX_DONE;
2077
				LOGDEBUG("exdone");
2078
			} else {
2079
				LOGDEBUG("not found so export");
2080
				/* Not found, so do export. */
2081
				if (statfs(ep->ex_fsdir, &fs) < 0)
2082
					return (1);
2083
				ret = do_export_mount(ep, &fs);
2084
				if (ret != 0)
2085
					return (ret);
2086
			}
2087
		}
2088
2089
	/* Delete exports not done. */
2090
	for (i = 0; i < exphashsize; i++)
2091
		SLIST_FOREACH(oep, &oldexphead[i], entries) {
2092
			if ((oep->ex_flag & EX_DONE) == 0) {
2093
				LOGDEBUG("not done delete=%s", oep->ex_fsdir);
2094
				if (statfs(oep->ex_fsdir, &ofs) >= 0 &&
2095
				    oep->ex_fs.val[0] == ofs.f_fsid.val[0] &&
2096
				    oep->ex_fs.val[1] == ofs.f_fsid.val[1]) {
2097
					LOGDEBUG("do delete");
2098
					/*
2099
					 * Clear has_publicfh if if was set
2100
					 * in the old exports, but only if it
2101
					 * has not been set during processing of
2102
					 * the exports for this pass, as
2103
					 * indicated by has_set_publicfh.
2104
					 */
2105
					if (has_set_publicfh == 0 &&
2106
					    (oep->ex_flag & EX_PUBLICFH) != 0)
2107
						has_publicfh = 0;
2108
2109
					delete_export(iov, iovlen, &ofs,
2110
					    errmsg);
2111
				}
2112
			}
2113
		}
2114
2115
	/* Do the V4 root exports, as required. */
2116
	grp = NULL;
2117
	if (v4root_ep != NULL)
2118
		grp = v4root_ep->ex_grphead;
2119
	v4root_phase = 2;
2120
	while (v4root_ep != NULL && grp != NULL) {
2121
		LOGDEBUG("v4root expath=%s", v4root_dirpath);
2122
		ret = do_mount(v4root_ep, grp, grp->gr_exflags, &grp->gr_anon,
2123
		    v4root_dirpath, strlen(v4root_dirpath), &fs,
2124
		    grp->gr_numsecflavors, grp->gr_secflavors);
2125
		if (ret != 0) {
2126
			v4root_phase = 0;
2127
			return (ret);
2128
		}
2129
		grp = grp->gr_next;
2130
	}
2131
	v4root_phase = 0;
2132
	free_v4rootexp();
2133
	return (0);
2134
}
2135
2136
/*
2137
 * Compare old and current exportlist entries for the fsid and return 0
2138
 * if they are the same, 1 otherwise.
2139
 */
2140
static int
2141
compare_export(struct exportlist *ep, struct exportlist *oep)
2142
{
2143
	struct grouplist *grp, *ogrp;
2144
2145
	if (strcmp(ep->ex_fsdir, oep->ex_fsdir) != 0)
2146
		return (1);
2147
	if ((ep->ex_flag & EX_DEFSET) != (oep->ex_flag & EX_DEFSET))
2148
		return (1);
2149
	if ((ep->ex_defdir != NULL && oep->ex_defdir == NULL) ||
2150
	    (ep->ex_defdir == NULL && oep->ex_defdir != NULL))
2151
		return (1);
2152
	if (ep->ex_defdir != NULL && (ep->ex_defdir->dp_flag & DP_DEFSET) !=
2153
	    (oep->ex_defdir->dp_flag & DP_DEFSET))
2154
		return (1);
2155
	if ((ep->ex_flag & EX_DEFSET) != 0 && (ep->ex_defnumsecflavors !=
2156
	    oep->ex_defnumsecflavors || ep->ex_defexflags !=
2157
	    oep->ex_defexflags || compare_cred(&ep->ex_defanon,
2158
	    &oep->ex_defanon) != 0 || compare_secflavor(ep->ex_defsecflavors,
2159
	    oep->ex_defsecflavors, ep->ex_defnumsecflavors) != 0))
2160
		return (1);
2161
2162
	/* Now, check all the groups. */
2163
	for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = ogrp->gr_next)
2164
		ogrp->gr_flag = 0;
2165
	for (grp = ep->ex_grphead; grp != NULL; grp = grp->gr_next) {
2166
		for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp =
2167
		    ogrp->gr_next)
2168
			if ((ogrp->gr_flag & GR_FND) == 0 &&
2169
			    grp->gr_numsecflavors == ogrp->gr_numsecflavors &&
2170
			    grp->gr_exflags == ogrp->gr_exflags &&
2171
			    compare_cred(&grp->gr_anon, &ogrp->gr_anon) == 0 &&
2172
			    compare_secflavor(grp->gr_secflavors,
2173
			    ogrp->gr_secflavors, grp->gr_numsecflavors) == 0)
2174
				break;
2175
		if (ogrp != NULL)
2176
			ogrp->gr_flag |= GR_FND;
2177
		else
2178
			return (1);
2179
	}
2180
	for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = ogrp->gr_next)
2181
		if ((ogrp->gr_flag & GR_FND) == 0)
2182
			return (1);
2183
	return (0);
2184
}
2185
2186
/*
2187
 * Compare to struct xucred's.  Return 0 if the same and 1 otherwise.
2188
 */
2189
static int
2190
compare_cred(struct xucred *cr0, struct xucred *cr1)
2191
{
2192
	int fnd, grp_fnd[XU_NGROUPS], i, j;
2193
2194
	if (cr0->cr_uid != cr1->cr_uid || cr0->cr_ngroups != cr1->cr_ngroups)
2195
		return (1);
2196
2197
	/* Handle common cases. */
2198
	if (cr0->cr_ngroups == 0)
2199
		return (0);
2200
	if (cr0->cr_ngroups == 1) {
2201
		if (cr0->cr_groups[0] == cr1->cr_groups[0])
2202
			return (0);
2203
		return (1);
2204
	}
2205
	if (memcmp(cr0->cr_groups, cr1->cr_groups, sizeof(*cr0->cr_groups) *
2206
	    cr0->cr_ngroups) == 0)
2207
		return (0);
2208
2209
	for (i = 0; i < cr0->cr_ngroups; i++)
2210
		grp_fnd[i] = 0;
2211
	/*
2212
	 * Search through the old and new groups lists, noting matches.
2213
	 * Since there is no ordering and duplicates can exist in the lists,
2214
	 * the algorithm is inefficient.  However cr_ngroups is small and
2215
	 * the common cases are handled above.
2216
	 */
2217
	for (i = 0; i < cr0->cr_ngroups; i++) {
2218
		fnd = 0;
2219
		for (j = 0; j < cr0->cr_ngroups; j++) {
2220
			if (cr0->cr_groups[i] == cr1->cr_groups[j]) {
2221
				grp_fnd[j] = 1;
2222
				fnd = 1;
2223
			}
2224
		}
2225
		if (fnd == 0)
2226
			return (1);
2227
	}
2228
	for (i = 0; i < cr0->cr_ngroups; i++)
2229
		if (grp_fnd[i] == 0)
2230
			return (1);
2231
	return (0);
2232
}
2233
2234
/*
2235
 * Compare two lists of security flavors.  Return 0 if the same and 1 otherwise.
2236
 * This is almost identical to compare_cred(), but I didn't factor out
2237
 * the algorithm, since compare_cred() may need to change if/when more than
2238
 * XU_NGROUPS groups are supported.
2239
 */
2240
static int
2241
compare_secflavor(int *sec1, int *sec2, int nsec)
2242
{
2243
	int fnd, sec_fnd[MAXSECFLAVORS], i, j;
2244
2245
	/* Handle common cases first. */
2246
	if (nsec == 0)
2247
		return (0);
2248
	if (nsec == 1) {
2249
		if (sec1[0] == sec2[0])
2250
			return (0);
2251
		return (1);
2252
	}
2253
	if (memcmp(sec1, sec2, sizeof(*sec1) * nsec) == 0)
2254
		return (0);
2255
2256
	for (i = 0; i < nsec; i++)
2257
		sec_fnd[i] = 0;
2258
	/*
2259
	 * Search the new group list starting at the same position in the
2260
	 * Search through the old and new secflavors lists, noting matches.
2261
	 * Since there is no ordering and duplicates can exist in the lists,
2262
	 * the algorithm is inefficient.  However nsec is small and
2263
	 * the common cases are handled above.
2264
	 */
2265
	for (i = 0; i < nsec; i++) {
2266
		fnd = 0;
2267
		for (j = 0; j < nsec; j++) {
2268
			if (sec1[i] == sec2[j]) {
2269
				sec_fnd[j] = 1;
2270
				fnd = 1;
2271
			}
2272
		}
2273
		if (fnd == 0)
2274
			return (1);
2275
	}
2276
	for (i = 0; i < nsec; i++)
2277
		if (sec_fnd[i] == 0)
2278
			return (1);
2279
	return (0);
2280
}
2281
2282
/*
2283
 * Delete an exports entry.
2284
 */
2285
static void
2286
delete_export(struct iovec *iov, int iovlen, struct statfs *fsp, char *errmsg)
2287
{
2288
	struct xvfsconf vfc;
2289
2290
	if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) {
2291
		syslog(LOG_ERR, "getvfsbyname() failed for %s",
2292
		    fsp->f_fstypename);
2293
		return;
2294
	}
2295
	
2296
	/*
2297
	 * We do not need to delete "export" flag from
2298
	 * filesystems that do not have it set.
2299
	 */
2300
	if (!(fsp->f_flags & MNT_EXPORTED))
2301
		return;
2302
	/*
2303
	 * Do not delete export for network filesystem by
2304
	 * passing "export" arg to nmount().
2305
	 * It only makes sense to do this for local filesystems.
2306
	 */
2307
	if (vfc.vfc_flags & VFCF_NETWORK)
2308
		return;
2309
	
2310
	iov[1].iov_base = fsp->f_fstypename;
2311
	iov[1].iov_len = strlen(fsp->f_fstypename) + 1;
2312
	iov[3].iov_base = fsp->f_mntonname;
2313
	iov[3].iov_len = strlen(fsp->f_mntonname) + 1;
2314
	iov[5].iov_base = fsp->f_mntfromname;
2315
	iov[5].iov_len = strlen(fsp->f_mntfromname) + 1;
2316
	errmsg[0] = '\0';
2317
	
2318
	/*
2319
	 * EXDEV is returned when path exists but is not a
2320
	 * mount point.  May happens if raced with unmount.
2321
	 */
2322
	if (nmount(iov, iovlen, fsp->f_flags) < 0 && errno != ENOENT &&
2323
	    errno != ENOTSUP && errno != EXDEV) {
2324
		syslog(LOG_ERR,
2325
		    "can't delete exports for %s: %m %s",
2326
		    fsp->f_mntonname, errmsg);
2327
	}
1869
}
2328
}
1870
2329
1871
/*
2330
/*
Lines 1924-1934 getexp_err(struct exportlist *ep, struct Link Here
1924
 * Search the export list for a matching fs.
2383
 * Search the export list for a matching fs.
1925
 */
2384
 */
1926
static struct exportlist *
2385
static struct exportlist *
1927
ex_search(fsid_t *fsid)
2386
ex_search(fsid_t *fsid, struct exportlisthead *exhp)
1928
{
2387
{
1929
	struct exportlist *ep;
2388
	struct exportlist *ep;
2389
	uint32_t i;
1930
2390
1931
	SLIST_FOREACH(ep, &exphead, entries) {
2391
	i = EXPHASH(fsid);
2392
	SLIST_FOREACH(ep, &exhp[i], entries) {
1932
		if (ep->ex_fs.val[0] == fsid->val[0] &&
2393
		if (ep->ex_fs.val[0] == fsid->val[0] &&
1933
		    ep->ex_fs.val[1] == fsid->val[1])
2394
		    ep->ex_fs.val[1] == fsid->val[1])
1934
			return (ep);
2395
			return (ep);
Lines 1965-1971 add_expdir(struct dirlist **dpp, char *c Link Here
1965
 */
2426
 */
1966
static void
2427
static void
1967
hang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep,
2428
hang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep,
1968
	int flags)
2429
	int flags, struct xucred *anoncrp, int exflags)
1969
{
2430
{
1970
	struct hostlist *hp;
2431
	struct hostlist *hp;
1971
	struct dirlist *dp2;
2432
	struct dirlist *dp2;
Lines 1976-1987 hang_dirp(struct dirlist *dp, struct gro Link Here
1976
		else
2437
		else
1977
			ep->ex_defdir = dp;
2438
			ep->ex_defdir = dp;
1978
		if (grp == (struct grouplist *)NULL) {
2439
		if (grp == (struct grouplist *)NULL) {
2440
			ep->ex_flag |= EX_DEFSET;
1979
			ep->ex_defdir->dp_flag |= DP_DEFSET;
2441
			ep->ex_defdir->dp_flag |= DP_DEFSET;
1980
			/* Save the default security flavors list. */
2442
			/* Save the default security flavors list. */
1981
			ep->ex_defnumsecflavors = ep->ex_numsecflavors;
2443
			ep->ex_defnumsecflavors = ep->ex_numsecflavors;
1982
			if (ep->ex_numsecflavors > 0)
2444
			if (ep->ex_numsecflavors > 0)
1983
				memcpy(ep->ex_defsecflavors, ep->ex_secflavors,
2445
				memcpy(ep->ex_defsecflavors, ep->ex_secflavors,
1984
				    sizeof(ep->ex_secflavors));
2446
				    sizeof(ep->ex_secflavors));
2447
			ep->ex_defanon = *anoncrp;
2448
			ep->ex_defexflags = exflags;
1985
		} else while (grp) {
2449
		} else while (grp) {
1986
			hp = get_ht();
2450
			hp = get_ht();
1987
			hp->ht_grp = grp;
2451
			hp->ht_grp = grp;
Lines 2001-2007 hang_dirp(struct dirlist *dp, struct gro Link Here
2001
		 */
2465
		 */
2002
		while (dp) {
2466
		while (dp) {
2003
			dp2 = dp->dp_left;
2467
			dp2 = dp->dp_left;
2004
			add_dlist(&ep->ex_dirl, dp, grp, flags, ep);
2468
			add_dlist(&ep->ex_dirl, dp, grp, flags, ep, anoncrp,
2469
			    exflags);
2005
			dp = dp2;
2470
			dp = dp2;
2006
		}
2471
		}
2007
	}
2472
	}
Lines 2013-2019 hang_dirp(struct dirlist *dp, struct gro Link Here
2013
 */
2478
 */
2014
static void
2479
static void
2015
add_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp,
2480
add_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp,
2016
	int flags, struct exportlist *ep)
2481
	int flags, struct exportlist *ep, struct xucred *anoncrp, int exflags)
2017
{
2482
{
2018
	struct dirlist *dp;
2483
	struct dirlist *dp;
2019
	struct hostlist *hp;
2484
	struct hostlist *hp;
Lines 2023-2032 add_dlist(struct dirlist **dpp, struct d Link Here
2023
	if (dp) {
2488
	if (dp) {
2024
		cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
2489
		cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
2025
		if (cmp > 0) {
2490
		if (cmp > 0) {
2026
			add_dlist(&dp->dp_left, newdp, grp, flags, ep);
2491
			add_dlist(&dp->dp_left, newdp, grp, flags, ep, anoncrp,
2492
			    exflags);
2027
			return;
2493
			return;
2028
		} else if (cmp < 0) {
2494
		} else if (cmp < 0) {
2029
			add_dlist(&dp->dp_right, newdp, grp, flags, ep);
2495
			add_dlist(&dp->dp_right, newdp, grp, flags, ep, anoncrp,
2496
			    exflags);
2030
			return;
2497
			return;
2031
		} else
2498
		} else
2032
			free((caddr_t)newdp);
2499
			free((caddr_t)newdp);
Lines 2053-2064 add_dlist(struct dirlist **dpp, struct d Link Here
2053
			grp = grp->gr_next;
2520
			grp = grp->gr_next;
2054
		} while (grp);
2521
		} while (grp);
2055
	} else {
2522
	} else {
2523
		ep->ex_flag |= EX_DEFSET;
2056
		dp->dp_flag |= DP_DEFSET;
2524
		dp->dp_flag |= DP_DEFSET;
2057
		/* Save the default security flavors list. */
2525
		/* Save the default security flavors list. */
2058
		ep->ex_defnumsecflavors = ep->ex_numsecflavors;
2526
		ep->ex_defnumsecflavors = ep->ex_numsecflavors;
2059
		if (ep->ex_numsecflavors > 0)
2527
		if (ep->ex_numsecflavors > 0)
2060
			memcpy(ep->ex_defsecflavors, ep->ex_secflavors,
2528
			memcpy(ep->ex_defsecflavors, ep->ex_secflavors,
2061
			    sizeof(ep->ex_secflavors));
2529
			    sizeof(ep->ex_secflavors));
2530
		ep->ex_defanon = *anoncrp;
2531
		ep->ex_defexflags = exflags;
2062
	}
2532
	}
2063
}
2533
}
2064
2534
Lines 2403-2408 get_host(char *cp, struct grouplist *grp Link Here
2403
static void
2873
static void
2404
free_exp(struct exportlist *ep)
2874
free_exp(struct exportlist *ep)
2405
{
2875
{
2876
	struct grouplist *grp, *tgrp;
2406
2877
2407
	if (ep->ex_defdir) {
2878
	if (ep->ex_defdir) {
2408
		free_host(ep->ex_defdir->dp_hosts);
2879
		free_host(ep->ex_defdir->dp_hosts);
Lines 2413-2422 free_exp(struct exportlist *ep) Link Here
2413
	if (ep->ex_indexfile)
2884
	if (ep->ex_indexfile)
2414
		free(ep->ex_indexfile);
2885
		free(ep->ex_indexfile);
2415
	free_dir(ep->ex_dirl);
2886
	free_dir(ep->ex_dirl);
2887
	grp = ep->ex_grphead;
2888
	while (grp) {
2889
		tgrp = grp;
2890
		grp = grp->gr_next;
2891
		free_grp(tgrp);
2892
	}
2416
	free((caddr_t)ep);
2893
	free((caddr_t)ep);
2417
}
2894
}
2418
2895
2419
/*
2896
/*
2897
 * Free up the v4root exports.
2898
 */
2899
static void
2900
free_v4rootexp(void)
2901
{
2902
2903
	if (v4root_ep != NULL) {
2904
		free_exp(v4root_ep);
2905
		v4root_ep = NULL;
2906
	}
2907
}
2908
2909
/*
2420
 * Free hosts.
2910
 * Free hosts.
2421
 */
2911
 */
2422
static void
2912
static void
Lines 2456-2467 out_of_mem(void) Link Here
2456
}
2946
}
2457
2947
2458
/*
2948
/*
2949
 * Call do_mount() from the struct exportlist, for each case needed.
2950
 */
2951
static int
2952
do_export_mount(struct exportlist *ep, struct statfs *fsp)
2953
{
2954
	struct grouplist *grp, defgrp;
2955
	int ret;
2956
	size_t dirlen;
2957
2958
	LOGDEBUG("do_export_mount=%s", ep->ex_fsdir);
2959
	dirlen = strlen(ep->ex_fsdir);
2960
	if ((ep->ex_flag & EX_DEFSET) != 0) {
2961
		defgrp.gr_type = GT_DEFAULT;
2962
		defgrp.gr_next = NULL;
2963
		/* We have an entry for all other hosts/nets. */
2964
		LOGDEBUG("ex_defexflags=0x%x", ep->ex_defexflags);
2965
		ret = do_mount(ep, &defgrp, ep->ex_defexflags, &ep->ex_defanon,
2966
		    ep->ex_fsdir, dirlen, fsp, ep->ex_defnumsecflavors,
2967
		    ep->ex_defsecflavors);
2968
		if (ret != 0)
2969
			return (ret);
2970
	}
2971
2972
	/* Do a mount for each group. */
2973
	grp = ep->ex_grphead;
2974
	while (grp != NULL) {
2975
		LOGDEBUG("do mount gr_type=0x%x gr_exflags=0x%x",
2976
		    grp->gr_type, grp->gr_exflags);
2977
		ret = do_mount(ep, grp, grp->gr_exflags, &grp->gr_anon,
2978
		    ep->ex_fsdir, dirlen, fsp, grp->gr_numsecflavors,
2979
		    grp->gr_secflavors);
2980
		if (ret != 0)
2981
			return (ret);
2982
		grp = grp->gr_next;
2983
	}
2984
	return (0);
2985
}
2986
2987
/*
2459
 * Do the nmount() syscall with the update flag to push the export info into
2988
 * Do the nmount() syscall with the update flag to push the export info into
2460
 * the kernel.
2989
 * the kernel.
2461
 */
2990
 */
2462
static int
2991
static int
2463
do_mount(struct exportlist *ep, struct grouplist *grp, int exflags,
2992
do_mount(struct exportlist *ep, struct grouplist *grp, int exflags,
2464
    struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb)
2993
    struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb,
2994
    int numsecflavors, int *secflavors)
2465
{
2995
{
2466
	struct statfs fsb1;
2996
	struct statfs fsb1;
2467
	struct addrinfo *ai;
2997
	struct addrinfo *ai;
Lines 2487-2500 do_mount(struct exportlist *ep, struct g Link Here
2487
	bzero(errmsg, sizeof(errmsg));
3017
	bzero(errmsg, sizeof(errmsg));
2488
	eap->ex_flags = exflags;
3018
	eap->ex_flags = exflags;
2489
	eap->ex_anon = *anoncrp;
3019
	eap->ex_anon = *anoncrp;
3020
	LOGDEBUG("do_mount exflags=0x%x", exflags);
2490
	eap->ex_indexfile = ep->ex_indexfile;
3021
	eap->ex_indexfile = ep->ex_indexfile;
2491
	if (grp->gr_type == GT_HOST)
3022
	if (grp->gr_type == GT_HOST)
2492
		ai = grp->gr_ptr.gt_addrinfo;
3023
		ai = grp->gr_ptr.gt_addrinfo;
2493
	else
3024
	else
2494
		ai = NULL;
3025
		ai = NULL;
2495
	eap->ex_numsecflavors = ep->ex_numsecflavors;
3026
	eap->ex_numsecflavors = numsecflavors;
3027
	LOGDEBUG("do_mount numsec=%d", numsecflavors);
2496
	for (i = 0; i < eap->ex_numsecflavors; i++)
3028
	for (i = 0; i < eap->ex_numsecflavors; i++)
2497
		eap->ex_secflavors[i] = ep->ex_secflavors[i];
3029
		eap->ex_secflavors[i] = secflavors[i];
2498
	if (eap->ex_numsecflavors == 0) {
3030
	if (eap->ex_numsecflavors == 0) {
2499
		eap->ex_numsecflavors = 1;
3031
		eap->ex_numsecflavors = 1;
2500
		eap->ex_secflavors[0] = AUTH_SYS;
3032
		eap->ex_secflavors[0] = AUTH_SYS;
Lines 2658-2665 do_mount(struct exportlist *ep, struct g Link Here
2658
			else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0)
3190
			else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0)
2659
				syslog(LOG_ERR,
3191
				syslog(LOG_ERR,
2660
				    "Can't set public fh for %s", public_name);
3192
				    "Can't set public fh for %s", public_name);
2661
			else
3193
			else {
2662
				has_publicfh = 1;
3194
				has_publicfh = 1;
3195
				has_set_publicfh = 1;
3196
				ep->ex_flag |= EX_PUBLICFH;
3197
			}
2663
		}
3198
		}
2664
skip:
3199
skip:
2665
		if (ai != NULL)
3200
		if (ai != NULL)
Lines 2824-2841 static void Link Here
2824
nextfield(char **cp, char **endcp)
3359
nextfield(char **cp, char **endcp)
2825
{
3360
{
2826
	char *p;
3361
	char *p;
3362
	char quot = 0;
2827
3363
2828
	p = *cp;
3364
	p = *cp;
2829
	while (*p == ' ' || *p == '\t')
3365
	while (*p == ' ' || *p == '\t')
2830
		p++;
3366
		p++;
2831
	if (*p == '\n' || *p == '\0')
3367
	*cp = p;
2832
		*cp = *endcp = p;
3368
	while (*p != '\0') {
2833
	else {
3369
		if (quot) {
2834
		*cp = p++;
3370
			if (*p == quot)
2835
		while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
3371
				quot = 0;
2836
			p++;
3372
		} else {
2837
		*endcp = p;
3373
			if (*p == '\\' && *(p + 1) != '\0')
2838
	}
3374
				p++;
3375
			else if (*p == '\'' || *p == '"')
3376
				quot = *p;
3377
			else if (*p == ' ' || *p == '\t')
3378
				break;
3379
		}
3380
		p++;
3381
	};
3382
	*endcp = p;
2839
}
3383
}
2840
3384
2841
/*
3385
/*
Lines 2907-2914 parsecred(char *namelist, struct xucred Link Here
2907
	/*
3451
	/*
2908
	 * Get the user's password table entry.
3452
	 * Get the user's password table entry.
2909
	 */
3453
	 */
2910
	names = strsep_quote(&namelist, " \t\n");
3454
	names = namelist;
2911
	name = strsep(&names, ":");
3455
	name = strsep_quote(&names, ":");
2912
	/* Bug?  name could be NULL here */
3456
	/* Bug?  name could be NULL here */
2913
	if (isdigit(*name) || *name == '-')
3457
	if (isdigit(*name) || *name == '-')
2914
		pw = getpwuid(atoi(name));
3458
		pw = getpwuid(atoi(name));
Lines 2952-2958 parsecred(char *namelist, struct xucred Link Here
2952
	}
3496
	}
2953
	cr->cr_ngroups = 0;
3497
	cr->cr_ngroups = 0;
2954
	while (names != NULL && *names != '\0' && cr->cr_ngroups < XU_NGROUPS) {
3498
	while (names != NULL && *names != '\0' && cr->cr_ngroups < XU_NGROUPS) {
2955
		name = strsep(&names, ":");
3499
		name = strsep_quote(&names, ":");
2956
		if (isdigit(*name) || *name == '-') {
3500
		if (isdigit(*name) || *name == '-') {
2957
			cr->cr_groups[cr->cr_ngroups++] = atoi(name);
3501
			cr->cr_groups[cr->cr_ngroups++] = atoi(name);
2958
		} else {
3502
		} else {
(-)usr.sbin/mountd/pathnames.h (+1 lines)
Lines 36-38 Link Here
36
#define	_PATH_EXPORTS		"/etc/exports"
36
#define	_PATH_EXPORTS		"/etc/exports"
37
#define	_PATH_RMOUNTLIST	"/var/db/mountdtab"
37
#define	_PATH_RMOUNTLIST	"/var/db/mountdtab"
38
#define _PATH_MOUNTDPID		"/var/run/mountd.pid"
38
#define _PATH_MOUNTDPID		"/var/run/mountd.pid"
39
#define	_PATH_MOUNTDDEBUG	"/var/log/mountd.debug"
(-)usr.sbin/mountd/mountd.8 (-2 / +12 lines)
Lines 28-34 Link Here
28
.\"     @(#)mountd.8	8.4 (Berkeley) 4/28/95
28
.\"     @(#)mountd.8	8.4 (Berkeley) 4/28/95
29
.\" $FreeBSD: head/usr.sbin/mountd/mountd.8 314436 2017-02-28 23:42:47Z imp $
29
.\" $FreeBSD: head/usr.sbin/mountd/mountd.8 314436 2017-02-28 23:42:47Z imp $
30
.\"
30
.\"
31
.Dd October 24, 2016
31
.Dd May 22, 2019
32
.Dt MOUNTD 8
32
.Dt MOUNTD 8
33
.Os
33
.Os
34
.Sh NAME
34
.Sh NAME
Lines 38-44 Link Here
38
mount requests
38
mount requests
39
.Sh SYNOPSIS
39
.Sh SYNOPSIS
40
.Nm
40
.Nm
41
.Op Fl 2delnrS
41
.Op Fl 2deIlnrS
42
.Op Fl h Ar bindip
42
.Op Fl h Ar bindip
43
.Op Fl p Ar port
43
.Op Fl p Ar port
44
.Op Ar exportsfile ...
44
.Op Ar exportsfile ...
Lines 87-92 will automatically add Link Here
87
and if IPv6 is enabled,
87
and if IPv6 is enabled,
88
.Li ::1
88
.Li ::1
89
to the list.
89
to the list.
90
.It Fl I
91
Make a reload of the exports file(s) be done via a comparison between the
92
current and new exports entries, only doing system calls to update the kernel
93
exports for cases that have changed.
94
This can reduce the number of system calls being done significantly for
95
a large number of exported file systems, when only a small number of changes
96
to the exports have been made.
97
For a server with 10,000 exported file systems, this can reduce the duration
98
during which the nfsd threads are suspended during the reload from seconds
99
to milliseconds.
90
.It Fl l
100
.It Fl l
91
Cause all succeeded
101
Cause all succeeded
92
.Nm
102
.Nm

Return to bug 237860