1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
25 * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
26 */
27
28/*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
29/*	  All Rights Reserved  	*/
30
31/*
32 * Portions of this source code were derived from Berkeley 4.3 BSD
33 * under license from the Regents of the University of California.
34 */
35
36#include <stdio.h>
37#include <stdio_ext.h>
38#include <stdlib.h>
39#include <ctype.h>
40#include <sys/types.h>
41#include <string.h>
42#include <syslog.h>
43#include <sys/param.h>
44#include <rpc/rpc.h>
45#include <sys/stat.h>
46#include <netconfig.h>
47#include <netdir.h>
48#include <sys/file.h>
49#include <sys/time.h>
50#include <sys/errno.h>
51#include <rpcsvc/mount.h>
52#include <sys/pathconf.h>
53#include <sys/systeminfo.h>
54#include <sys/utsname.h>
55#include <sys/wait.h>
56#include <sys/resource.h>
57#include <signal.h>
58#include <locale.h>
59#include <unistd.h>
60#include <errno.h>
61#include <sys/socket.h>
62#include <netinet/in.h>
63#include <arpa/inet.h>
64#include <netdb.h>
65#include <thread.h>
66#include <assert.h>
67#include <priv_utils.h>
68#include <nfs/auth.h>
69#include <nfs/nfssys.h>
70#include <nfs/nfs.h>
71#include <nfs/nfs_sec.h>
72#include <rpcsvc/daemon_utils.h>
73#include <deflt.h>
74#include "../../fslib.h"
75#include <sharefs/share.h>
76#include <sharefs/sharetab.h>
77#include "../lib/sharetab.h"
78#include "mountd.h"
79#include <tsol/label.h>
80#include <sys/tsol/label_macro.h>
81#include <libtsnet.h>
82#include <sys/sdt.h>
83#include <libscf.h>
84#include <limits.h>
85#include <sys/nvpair.h>
86#include <attr.h>
87#include "smfcfg.h"
88#include <pwd.h>
89#include <grp.h>
90#include <alloca.h>
91
92extern int daemonize_init(void);
93extern void daemonize_fini(int);
94
95extern int _nfssys(int, void *);
96
97struct sh_list *share_list;
98
99rwlock_t sharetab_lock;		/* lock to protect the cached sharetab */
100static mutex_t mnttab_lock;	/* prevent concurrent mnttab readers */
101
102static mutex_t logging_queue_lock;
103static cond_t logging_queue_cv;
104
105static share_t *find_lofsentry(char *, int *);
106static int getclientsflavors_old(share_t *, struct cln *, int *);
107static int getclientsflavors_new(share_t *, struct cln *, int *);
108static int check_client_old(share_t *, struct cln *, int, uid_t, gid_t, uint_t,
109    gid_t *, uid_t *, gid_t *, uint_t *, gid_t **);
110static int check_client_new(share_t *, struct cln *, int, uid_t, gid_t, uint_t,
111    gid_t *, uid_t *, gid_t *i, uint_t *, gid_t **);
112static void mnt(struct svc_req *, SVCXPRT *);
113static void mnt_pathconf(struct svc_req *);
114static int mount(struct svc_req *r);
115static void sh_free(struct sh_list *);
116static void umount(struct svc_req *);
117static void umountall(struct svc_req *);
118static int newopts(char *);
119static tsol_tpent_t *get_client_template(struct sockaddr *);
120
121static int debug;
122static int verbose;
123static int rejecting;
124static int mount_vers_min = MOUNTVERS;
125static int mount_vers_max = MOUNTVERS3;
126static int mountd_port = 0;
127
128extern void nfscmd_func(void *, char *, size_t, door_desc_t *, uint_t);
129
130thread_t	nfsauth_thread;
131thread_t	cmd_thread;
132thread_t	logging_thread;
133
134typedef struct logging_data {
135	char			*ld_host;
136	char			*ld_path;
137	char			*ld_rpath;
138	int			ld_status;
139	char			*ld_netid;
140	struct netbuf		*ld_nb;
141	struct logging_data	*ld_next;
142} logging_data;
143
144static logging_data *logging_head = NULL;
145static logging_data *logging_tail = NULL;
146
147/*
148 * Our copy of some system variables obtained using sysconf(3c)
149 */
150static long ngroups_max;	/* _SC_NGROUPS_MAX */
151static long pw_size;		/* _SC_GETPW_R_SIZE_MAX */
152
153/* ARGSUSED */
154static void *
155nfsauth_svc(void *arg)
156{
157	int	doorfd = -1;
158	uint_t	darg;
159#ifdef DEBUG
160	int	dfd;
161#endif
162
163	if ((doorfd = door_create(nfsauth_func, NULL,
164	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
165		syslog(LOG_ERR, "Unable to create door: %m\n");
166		exit(10);
167	}
168
169#ifdef DEBUG
170	/*
171	 * Create a file system path for the door
172	 */
173	if ((dfd = open(MOUNTD_DOOR, O_RDWR|O_CREAT|O_TRUNC,
174	    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) {
175		syslog(LOG_ERR, "Unable to open %s: %m\n", MOUNTD_DOOR);
176		(void) close(doorfd);
177		exit(11);
178	}
179
180	/*
181	 * Clean up any stale namespace associations
182	 */
183	(void) fdetach(MOUNTD_DOOR);
184
185	/*
186	 * Register in namespace to pass to the kernel to door_ki_open
187	 */
188	if (fattach(doorfd, MOUNTD_DOOR) == -1) {
189		syslog(LOG_ERR, "Unable to fattach door: %m\n");
190		(void) close(dfd);
191		(void) close(doorfd);
192		exit(12);
193	}
194	(void) close(dfd);
195#endif
196
197	/*
198	 * Must pass the doorfd down to the kernel.
199	 */
200	darg = doorfd;
201	(void) _nfssys(MOUNTD_ARGS, &darg);
202
203	/*
204	 * Wait for incoming calls
205	 */
206	/*CONSTCOND*/
207	for (;;)
208		(void) pause();
209
210	/*NOTREACHED*/
211	syslog(LOG_ERR, gettext("Door server exited"));
212	return (NULL);
213}
214
215/*
216 * NFS command service thread code for setup and handling of the
217 * nfs_cmd requests for character set conversion and other future
218 * events.
219 */
220
221static void *
222cmd_svc(void *arg)
223{
224	int	doorfd = -1;
225	uint_t	darg;
226
227	if ((doorfd = door_create(nfscmd_func, NULL,
228	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
229		syslog(LOG_ERR, "Unable to create cmd door: %m\n");
230		exit(10);
231	}
232
233	/*
234	 * Must pass the doorfd down to the kernel.
235	 */
236	darg = doorfd;
237	(void) _nfssys(NFSCMD_ARGS, &darg);
238
239	/*
240	 * Wait for incoming calls
241	 */
242	/*CONSTCOND*/
243	for (;;)
244		(void) pause();
245
246	/*NOTREACHED*/
247	syslog(LOG_ERR, gettext("Cmd door server exited"));
248	return (NULL);
249}
250
251static void
252free_logging_data(logging_data *lq)
253{
254	if (lq != NULL) {
255		free(lq->ld_host);
256		free(lq->ld_netid);
257
258		if (lq->ld_nb != NULL) {
259			free(lq->ld_nb->buf);
260			free(lq->ld_nb);
261		}
262
263		free(lq->ld_path);
264		free(lq->ld_rpath);
265
266		free(lq);
267	}
268}
269
270static logging_data *
271remove_head_of_queue(void)
272{
273	logging_data    *lq;
274
275	/*
276	 * Pull it off the queue.
277	 */
278	lq = logging_head;
279	if (lq) {
280		logging_head = lq->ld_next;
281
282		/*
283		 * Drained it.
284		 */
285		if (logging_head == NULL) {
286			logging_tail = NULL;
287		}
288	}
289
290	return (lq);
291}
292
293static void
294do_logging_queue(logging_data *lq)
295{
296	int		cleared = 0;
297	char		*host;
298
299	while (lq) {
300		struct cln cln;
301
302		if (lq->ld_host == NULL) {
303			DTRACE_PROBE(mountd, name_by_lazy);
304			cln_init_lazy(&cln, lq->ld_netid, lq->ld_nb);
305			host = cln_gethost(&cln);
306		} else
307			host = lq->ld_host;
308
309		audit_mountd_mount(host, lq->ld_path, lq->ld_status); /* BSM */
310
311		/* add entry to mount list */
312		if (lq->ld_rpath)
313			mntlist_new(host, lq->ld_rpath);
314
315		if (lq->ld_host == NULL)
316			cln_fini(&cln);
317
318		free_logging_data(lq);
319		cleared++;
320
321		(void) mutex_lock(&logging_queue_lock);
322		lq = remove_head_of_queue();
323		(void) mutex_unlock(&logging_queue_lock);
324	}
325
326	DTRACE_PROBE1(mountd, logging_cleared, cleared);
327}
328
329static void *
330logging_svc(void *arg)
331{
332	logging_data	*lq;
333
334	for (;;) {
335		(void) mutex_lock(&logging_queue_lock);
336		while (logging_head == NULL) {
337			(void) cond_wait(&logging_queue_cv,
338			    &logging_queue_lock);
339		}
340
341		lq = remove_head_of_queue();
342		(void) mutex_unlock(&logging_queue_lock);
343
344		do_logging_queue(lq);
345	}
346
347	/*NOTREACHED*/
348	syslog(LOG_ERR, gettext("Logging server exited"));
349	return (NULL);
350}
351
352static int
353convert_int(int *val, char *str)
354{
355	long lval;
356
357	if (str == NULL || !isdigit(*str))
358		return (-1);
359
360	lval = strtol(str, &str, 10);
361	if (*str != '\0' || lval > INT_MAX)
362		return (-2);
363
364	*val = (int)lval;
365	return (0);
366}
367
368/*
369 * This function is called for each configured network type to
370 * bind and register our RPC service programs.
371 *
372 * On TCP or UDP, we may want to bind MOUNTPROG on a specific port
373 * (when mountd_port is specified) in which case we'll use the
374 * variant of svc_tp_create() that lets us pass a bind address.
375 */
376static void
377md_svc_tp_create(struct netconfig *nconf)
378{
379	char port_str[8];
380	struct nd_hostserv hs;
381	struct nd_addrlist *al = NULL;
382	SVCXPRT *xprt = NULL;
383	rpcvers_t vers;
384
385	vers = mount_vers_max;
386
387	/*
388	 * If mountd_port is set and this is an inet transport,
389	 * bind this service on the specified port.  The TLI way
390	 * to create such a bind address is netdir_getbyname()
391	 * with the special "host" HOST_SELF_BIND.  This builds
392	 * an all-zeros IP address with the specified port.
393	 */
394	if (mountd_port != 0 &&
395	    (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
396	    strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
397		int err;
398
399		snprintf(port_str, sizeof (port_str), "%u",
400		    (unsigned short)mountd_port);
401
402		hs.h_host = HOST_SELF_BIND;
403		hs.h_serv = port_str;
404		err = netdir_getbyname((struct netconfig *)nconf, &hs, &al);
405		if (err == 0 && al != NULL) {
406			xprt = svc_tp_create_addr(mnt, MOUNTPROG, vers,
407			    nconf, al->n_addrs);
408			netdir_free(al, ND_ADDRLIST);
409		}
410		if (xprt == NULL) {
411			syslog(LOG_ERR, "mountd: unable to create "
412			    "(MOUNTD,%d) on transport %s (port %d)",
413			    vers, nconf->nc_netid, mountd_port);
414		}
415		/* fall-back to default bind */
416	}
417	if (xprt == NULL) {
418		/*
419		 * Had mountd_port=0, or non-inet transport,
420		 * or the bind to a specific port failed.
421		 * Do a default bind.
422		 */
423		xprt = svc_tp_create(mnt, MOUNTPROG, vers, nconf);
424	}
425	if (xprt == NULL) {
426		syslog(LOG_ERR, "mountd: unable to create "
427		    "(MOUNTD,%d) on transport %s",
428		    vers, nconf->nc_netid);
429		return;
430	}
431
432	/*
433	 * Register additional versions on this transport.
434	 */
435	while (--vers >= mount_vers_min) {
436		if (!svc_reg(xprt, MOUNTPROG, vers, mnt, nconf)) {
437			(void) syslog(LOG_ERR, "mountd: "
438			    "failed to register vers %d on %s",
439			    vers, nconf->nc_netid);
440		}
441	}
442}
443
444int
445main(int argc, char *argv[])
446{
447	int	pid;
448	int	c;
449	int	rpc_svc_fdunlim = 1;
450	int	rpc_svc_mode = RPC_SVC_MT_AUTO;
451	int	maxrecsz = RPC_MAXDATASIZE;
452	bool_t	exclbind = TRUE;
453	bool_t	can_do_mlp;
454	long	thr_flags = (THR_NEW_LWP|THR_DAEMON);
455	char defval[4];
456	int defvers, ret, bufsz;
457	struct rlimit rl;
458	int listen_backlog = 0;
459	int max_threads = 0;
460	int tmp;
461	struct netconfig *nconf;
462	NCONF_HANDLE *nc;
463
464	int	pipe_fd = -1;
465
466	/*
467	 * Mountd requires uid 0 for:
468	 *	/etc/rmtab updates (we could chown it to daemon)
469	 *	/etc/dfs/dfstab reading (it wants to lock out share which
470	 *		doesn't do any locking before first truncate;
471	 *		NFS share does; should use fcntl locking instead)
472	 *	Needed privileges:
473	 *		auditing
474	 *		nfs syscall
475	 *		file dac search (so it can stat all files)
476	 *	Optional privileges:
477	 *		MLP
478	 */
479	can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
480	if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, -1, -1,
481	    PRIV_SYS_NFS, PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH,
482	    PRIV_NET_PRIVADDR,
483	    can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
484		(void) fprintf(stderr,
485		    "%s: must be run with sufficient privileges\n",
486		    argv[0]);
487		exit(1);
488	}
489
490	if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
491		syslog(LOG_ERR, "getrlimit failed");
492	} else {
493		rl.rlim_cur = rl.rlim_max;
494		if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
495			syslog(LOG_ERR, "setrlimit failed");
496	}
497
498	(void) enable_extended_FILE_stdio(-1, -1);
499
500	ret = nfs_smf_get_iprop("mountd_max_threads", &max_threads,
501	    DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
502	if (ret != SA_OK) {
503		syslog(LOG_ERR, "Reading of mountd_max_threads from SMF "
504		    "failed, using default value");
505	}
506
507	ret = nfs_smf_get_iprop("mountd_port", &mountd_port,
508	    DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
509	if (ret != SA_OK) {
510		syslog(LOG_ERR, "Reading of mountd_port from SMF "
511		    "failed, using default value");
512	}
513
514	while ((c = getopt(argc, argv, "dvrm:p:")) != EOF) {
515		switch (c) {
516		case 'd':
517			debug++;
518			break;
519		case 'v':
520			verbose++;
521			break;
522		case 'r':
523			rejecting = 1;
524			break;
525		case 'm':
526			if (convert_int(&tmp, optarg) != 0 || tmp < 1) {
527				(void) fprintf(stderr, "%s: invalid "
528				    "max_threads option, using defaults\n",
529				    argv[0]);
530				break;
531			}
532			max_threads = tmp;
533			break;
534		case 'p':
535			if (convert_int(&tmp, optarg) != 0 || tmp < 1 ||
536			    tmp > UINT16_MAX) {
537				(void) fprintf(stderr, "%s: invalid port "
538				    "number\n", argv[0]);
539				break;
540			}
541			mountd_port = tmp;
542			break;
543		default:
544			fprintf(stderr, "usage: mountd [-v] [-r]\n");
545			exit(1);
546		}
547	}
548
549	/*
550	 * Read in the NFS version values from config file.
551	 */
552	bufsz = 4;
553	ret = nfs_smf_get_prop("server_versmin", defval, DEFAULT_INSTANCE,
554	    SCF_TYPE_INTEGER, NFSD, &bufsz);
555	if (ret == SA_OK) {
556		errno = 0;
557		defvers = strtol(defval, (char **)NULL, 10);
558		if (errno == 0) {
559			mount_vers_min = defvers;
560			/*
561			 * special because NFSv2 is
562			 * supported by mount v1 & v2
563			 */
564			if (defvers == NFS_VERSION)
565				mount_vers_min = MOUNTVERS;
566		}
567	}
568
569	bufsz = 4;
570	ret = nfs_smf_get_prop("server_versmax", defval, DEFAULT_INSTANCE,
571	    SCF_TYPE_INTEGER, NFSD, &bufsz);
572	if (ret == SA_OK) {
573		errno = 0;
574		defvers = strtol(defval, (char **)NULL, 10);
575		if (errno == 0) {
576			mount_vers_max = defvers;
577		}
578	}
579
580	ret = nfs_smf_get_iprop("mountd_listen_backlog", &listen_backlog,
581	    DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
582	if (ret != SA_OK) {
583		syslog(LOG_ERR, "Reading of mountd_listen_backlog from SMF "
584		    "failed, using default value");
585	}
586
587	/*
588	 * Sanity check versions,
589	 * even though we may get versions > MOUNTVERS3, we still need
590	 * to start nfsauth service, so continue on regardless of values.
591	 */
592	if (mount_vers_max > MOUNTVERS3)
593		mount_vers_max = MOUNTVERS3;
594	if (mount_vers_min > mount_vers_max) {
595		fprintf(stderr, "server_versmin > server_versmax\n");
596		mount_vers_max = mount_vers_min;
597	}
598	(void) setlocale(LC_ALL, "");
599	(void) rwlock_init(&sharetab_lock, USYNC_THREAD, NULL);
600	(void) mutex_init(&mnttab_lock, USYNC_THREAD, NULL);
601	(void) mutex_init(&logging_queue_lock, USYNC_THREAD, NULL);
602	(void) cond_init(&logging_queue_cv, USYNC_THREAD, NULL);
603
604	netgroup_init();
605
606#if !defined(TEXT_DOMAIN)
607#define	TEXT_DOMAIN "SYS_TEST"
608#endif
609	(void) textdomain(TEXT_DOMAIN);
610
611	/* Don't drop core if the NFS module isn't loaded. */
612	(void) signal(SIGSYS, SIG_IGN);
613
614	if (!debug)
615		pipe_fd = daemonize_init();
616
617	/*
618	 * If we coredump it'll be in /core
619	 */
620	if (chdir("/") < 0)
621		fprintf(stderr, "chdir /: %s\n", strerror(errno));
622
623	if (!debug)
624		openlog("mountd", LOG_PID, LOG_DAEMON);
625
626	/*
627	 * establish our lock on the lock file and write our pid to it.
628	 * exit if some other process holds the lock, or if there's any
629	 * error in writing/locking the file.
630	 */
631	pid = _enter_daemon_lock(MOUNTD);
632	switch (pid) {
633	case 0:
634		break;
635	case -1:
636		fprintf(stderr, "error locking for %s: %s\n", MOUNTD,
637		    strerror(errno));
638		exit(2);
639	default:
640		/* daemon was already running */
641		exit(0);
642	}
643
644	audit_mountd_setup();	/* BSM */
645
646	/*
647	 * Get required system variables
648	 */
649	if ((ngroups_max = sysconf(_SC_NGROUPS_MAX)) == -1) {
650		syslog(LOG_ERR, "Unable to get _SC_NGROUPS_MAX");
651		exit(1);
652	}
653	if ((pw_size = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) {
654		syslog(LOG_ERR, "Unable to get _SC_GETPW_R_SIZE_MAX");
655		exit(1);
656	}
657
658	/*
659	 * Set number of file descriptors to unlimited
660	 */
661	if (!rpc_control(RPC_SVC_USE_POLLFD, &rpc_svc_fdunlim)) {
662		syslog(LOG_INFO, "unable to set number of FDs to unlimited");
663	}
664
665	/*
666	 * Tell RPC that we want automatic thread mode.
667	 * A new thread will be spawned for each request.
668	 */
669	if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) {
670		fprintf(stderr, "unable to set automatic MT mode\n");
671		exit(1);
672	}
673
674	/*
675	 * Enable non-blocking mode and maximum record size checks for
676	 * connection oriented transports.
677	 */
678	if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) {
679		fprintf(stderr, "unable to set RPC max record size\n");
680	}
681
682	/*
683	 * Prevent our non-priv udp and tcp ports bound w/wildcard addr
684	 * from being hijacked by a bind to a more specific addr.
685	 */
686	if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) {
687		fprintf(stderr, "warning: unable to set udp/tcp EXCLBIND\n");
688	}
689
690	/*
691	 * Set the maximum number of outstanding connection
692	 * indications (listen backlog) to the value specified.
693	 */
694	if (listen_backlog > 0 && !rpc_control(__RPC_SVC_LSTNBKLOG_SET,
695	    &listen_backlog)) {
696		fprintf(stderr, "unable to set listen backlog\n");
697		exit(1);
698	}
699
700	/*
701	 * If max_threads was specified, then set the
702	 * maximum number of threads to the value specified.
703	 */
704	if (max_threads > 0 && !rpc_control(RPC_SVC_THRMAX_SET, &max_threads)) {
705		fprintf(stderr, "unable to set max_threads\n");
706		exit(1);
707	}
708
709	if (mountd_port < 0 || mountd_port > UINT16_MAX) {
710		fprintf(stderr, "unable to use specified port\n");
711		exit(1);
712	}
713
714	/*
715	 * Make sure to unregister any previous versions in case the
716	 * user is reconfiguring the server in interesting ways.
717	 */
718	svc_unreg(MOUNTPROG, MOUNTVERS);
719	svc_unreg(MOUNTPROG, MOUNTVERS_POSIX);
720	svc_unreg(MOUNTPROG, MOUNTVERS3);
721
722	/*
723	 * Create the nfsauth thread with same signal disposition
724	 * as the main thread. We need to create a separate thread
725	 * since mountd() will be both an RPC server (for remote
726	 * traffic) _and_ a doors server (for kernel upcalls).
727	 */
728	if (thr_create(NULL, 0, nfsauth_svc, 0, thr_flags, &nfsauth_thread)) {
729		fprintf(stderr,
730		    gettext("Failed to create NFSAUTH svc thread\n"));
731		exit(2);
732	}
733
734	/*
735	 * Create the cmd service thread with same signal disposition
736	 * as the main thread. We need to create a separate thread
737	 * since mountd() will be both an RPC server (for remote
738	 * traffic) _and_ a doors server (for kernel upcalls).
739	 */
740	if (thr_create(NULL, 0, cmd_svc, 0, thr_flags, &cmd_thread)) {
741		syslog(LOG_ERR, gettext("Failed to create CMD svc thread"));
742		exit(2);
743	}
744
745	/*
746	 * Create an additional thread to service the rmtab and
747	 * audit_mountd_mount logging for mount requests. Use the same
748	 * signal disposition as the main thread. We create
749	 * a separate thread to allow the mount request threads to
750	 * clear as soon as possible.
751	 */
752	if (thr_create(NULL, 0, logging_svc, 0, thr_flags, &logging_thread)) {
753		syslog(LOG_ERR, gettext("Failed to create LOGGING svc thread"));
754		exit(2);
755	}
756
757	/*
758	 * Enumerate network transports and create service listeners
759	 * as appropriate for each.
760	 */
761	if ((nc = setnetconfig()) == NULL) {
762		syslog(LOG_ERR, "setnetconfig failed: %m");
763		return (-1);
764	}
765	while ((nconf = getnetconfig(nc)) != NULL) {
766		/*
767		 * Skip things like tpi_raw, invisible...
768		 */
769		if ((nconf->nc_flag & NC_VISIBLE) == 0)
770			continue;
771		if (nconf->nc_semantics != NC_TPI_CLTS &&
772		    nconf->nc_semantics != NC_TPI_COTS &&
773		    nconf->nc_semantics != NC_TPI_COTS_ORD)
774			continue;
775
776		md_svc_tp_create(nconf);
777	}
778	(void) endnetconfig(nc);
779
780	/*
781	 * Start serving
782	 */
783	rmtab_load();
784
785	daemonize_fini(pipe_fd);
786
787	/* Get rid of the most dangerous basic privileges. */
788	__fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_INFO, PRIV_PROC_SESSION,
789	    (char *)NULL);
790
791	svc_run();
792	syslog(LOG_ERR, "Error: svc_run shouldn't have returned");
793	abort();
794
795	/* NOTREACHED */
796	return (0);
797}
798
799/*
800 * Server procedure switch routine
801 */
802void
803mnt(struct svc_req *rqstp, SVCXPRT *transp)
804{
805	switch (rqstp->rq_proc) {
806	case NULLPROC:
807		errno = 0;
808		if (!svc_sendreply(transp, xdr_void, (char *)0))
809			log_cant_reply(transp);
810		return;
811
812	case MOUNTPROC_MNT:
813		(void) mount(rqstp);
814		return;
815
816	case MOUNTPROC_DUMP:
817		mntlist_send(transp);
818		return;
819
820	case MOUNTPROC_UMNT:
821		umount(rqstp);
822		return;
823
824	case MOUNTPROC_UMNTALL:
825		umountall(rqstp);
826		return;
827
828	case MOUNTPROC_EXPORT:
829	case MOUNTPROC_EXPORTALL:
830		export(rqstp);
831		return;
832
833	case MOUNTPROC_PATHCONF:
834		if (rqstp->rq_vers == MOUNTVERS_POSIX)
835			mnt_pathconf(rqstp);
836		else
837			svcerr_noproc(transp);
838		return;
839
840	default:
841		svcerr_noproc(transp);
842		return;
843	}
844}
845
846void
847log_cant_reply_cln(struct cln *cln)
848{
849	int saverrno;
850	char *host;
851
852	saverrno = errno;	/* save error code */
853
854	host = cln_gethost(cln);
855	if (host == NULL)
856		return;
857
858	errno = saverrno;
859	if (errno == 0)
860		syslog(LOG_ERR, "couldn't send reply to %s", host);
861	else
862		syslog(LOG_ERR, "couldn't send reply to %s: %m", host);
863}
864
865void
866log_cant_reply(SVCXPRT *transp)
867{
868	int saverrno;
869	struct cln cln;
870
871	saverrno = errno;	/* save error code */
872	cln_init(&cln, transp);
873	errno = saverrno;
874
875	log_cant_reply_cln(&cln);
876
877	cln_fini(&cln);
878}
879
880/*
881 * Answer pathconf questions for the mount point fs
882 */
883static void
884mnt_pathconf(struct svc_req *rqstp)
885{
886	SVCXPRT *transp;
887	struct pathcnf p;
888	char *path, rpath[MAXPATHLEN];
889	struct stat st;
890
891	transp = rqstp->rq_xprt;
892	path = NULL;
893	(void) memset((caddr_t)&p, 0, sizeof (p));
894
895	if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
896		svcerr_decode(transp);
897		return;
898	}
899	if (lstat(path, &st) < 0) {
900		_PC_SET(_PC_ERROR, p.pc_mask);
901		goto done;
902	}
903	/*
904	 * Get a path without symbolic links.
905	 */
906	if (realpath(path, rpath) == NULL) {
907		syslog(LOG_DEBUG,
908		    "mount request: realpath failed on %s: %m",
909		    path);
910		_PC_SET(_PC_ERROR, p.pc_mask);
911		goto done;
912	}
913	(void) memset((caddr_t)&p, 0, sizeof (p));
914	/*
915	 * can't ask about devices over NFS
916	 */
917	_PC_SET(_PC_MAX_CANON, p.pc_mask);
918	_PC_SET(_PC_MAX_INPUT, p.pc_mask);
919	_PC_SET(_PC_PIPE_BUF, p.pc_mask);
920	_PC_SET(_PC_VDISABLE, p.pc_mask);
921
922	errno = 0;
923	p.pc_link_max = pathconf(rpath, _PC_LINK_MAX);
924	if (errno)
925		_PC_SET(_PC_LINK_MAX, p.pc_mask);
926	p.pc_name_max = pathconf(rpath, _PC_NAME_MAX);
927	if (errno)
928		_PC_SET(_PC_NAME_MAX, p.pc_mask);
929	p.pc_path_max = pathconf(rpath, _PC_PATH_MAX);
930	if (errno)
931		_PC_SET(_PC_PATH_MAX, p.pc_mask);
932	if (pathconf(rpath, _PC_NO_TRUNC) == 1)
933		_PC_SET(_PC_NO_TRUNC, p.pc_mask);
934	if (pathconf(rpath, _PC_CHOWN_RESTRICTED) == 1)
935		_PC_SET(_PC_CHOWN_RESTRICTED, p.pc_mask);
936
937done:
938	errno = 0;
939	if (!svc_sendreply(transp, xdr_ppathcnf, (char *)&p))
940		log_cant_reply(transp);
941	if (path != NULL)
942		svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
943}
944
945/*
946 * If the rootmount (export) option is specified, the all mount requests for
947 * subdirectories return EACCES.
948 */
949static int
950checkrootmount(share_t *sh, char *rpath)
951{
952	char *val;
953
954	if ((val = getshareopt(sh->sh_opts, SHOPT_NOSUB)) != NULL) {
955		free(val);
956		if (strcmp(sh->sh_path, rpath) != 0)
957			return (0);
958		else
959			return (1);
960	} else
961		return (1);
962}
963
964#define	MAX_FLAVORS	128
965
966/*
967 * Return only EACCES if client does not have access
968 *  to this directory.
969 * "If the server exports only /a/b, an attempt to
970 *  mount a/b/c will fail with ENOENT if the directory
971 *  does not exist"... However, if the client
972 *  does not have access to /a/b, an attacker can
973 *  determine whether the directory exists.
974 * This routine checks either existence of the file or
975 * existence of the file name entry in the mount table.
976 * If the file exists and there is no file name entry,
977 * the error returned should be EACCES.
978 * If the file does not exist, it must be determined
979 * whether the client has access to a parent
980 * directory.  If the client has access to a parent
981 * directory, the error returned should be ENOENT,
982 * otherwise EACCES.
983 */
984static int
985mount_enoent_error(struct cln *cln, char *path, char *rpath, int *flavor_list)
986{
987	char *checkpath, *dp;
988	share_t *sh = NULL;
989	int realpath_error = ENOENT, reply_error = EACCES, lofs_tried = 0;
990	int flavor_count;
991
992	checkpath = strdup(path);
993	if (checkpath == NULL) {
994		syslog(LOG_ERR, "mount_enoent: no memory");
995		return (EACCES);
996	}
997
998	/* CONSTCOND */
999	while (1) {
1000		if (sh) {
1001			sharefree(sh);
1002			sh = NULL;
1003		}
1004
1005		if ((sh = findentry(rpath)) == NULL &&
1006		    (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) {
1007			/*
1008			 * There is no file name entry.
1009			 * If the file (with symbolic links resolved) exists,
1010			 * the error returned should be EACCES.
1011			 */
1012			if (realpath_error == 0)
1013				break;
1014		} else if (checkrootmount(sh, rpath) == 0) {
1015			/*
1016			 * This is a "nosub" only export, in which case,
1017			 * mounting subdirectories isn't allowed.
1018			 * If the file (with symbolic links resolved) exists,
1019			 * the error returned should be EACCES.
1020			 */
1021			if (realpath_error == 0)
1022				break;
1023		} else {
1024			/*
1025			 * Check permissions in mount table.
1026			 */
1027			if (newopts(sh->sh_opts))
1028				flavor_count = getclientsflavors_new(sh, cln,
1029				    flavor_list);
1030			else
1031				flavor_count = getclientsflavors_old(sh, cln,
1032				    flavor_list);
1033			if (flavor_count != 0) {
1034				/*
1035				 * Found entry in table and
1036				 * client has correct permissions.
1037				 */
1038				reply_error = ENOENT;
1039				break;
1040			}
1041		}
1042
1043		/*
1044		 * Check all parent directories.
1045		 */
1046		dp = strrchr(checkpath, '/');
1047		if (dp == NULL)
1048			break;
1049		*dp = '\0';
1050		if (strlen(checkpath) == 0)
1051			break;
1052		/*
1053		 * Get the real path (no symbolic links in it)
1054		 */
1055		if (realpath(checkpath, rpath) == NULL) {
1056			if (errno != ENOENT)
1057				break;
1058		} else {
1059			realpath_error = 0;
1060		}
1061	}
1062
1063	if (sh)
1064		sharefree(sh);
1065	free(checkpath);
1066	return (reply_error);
1067}
1068
1069/*
1070 * We need to inform the caller whether or not we were
1071 * able to add a node to the queue. If we are not, then
1072 * it is up to the caller to go ahead and log the data.
1073 */
1074static int
1075enqueue_logging_data(char *host, SVCXPRT *transp, char *path,
1076    char *rpath, int status, int error)
1077{
1078	logging_data	*lq;
1079	struct netbuf	*nb;
1080
1081	lq = (logging_data *)calloc(1, sizeof (logging_data));
1082	if (lq == NULL)
1083		goto cleanup;
1084
1085	/*
1086	 * We might not yet have the host...
1087	 */
1088	if (host) {
1089		DTRACE_PROBE1(mountd, log_host, host);
1090		lq->ld_host = strdup(host);
1091		if (lq->ld_host == NULL)
1092			goto cleanup;
1093	} else {
1094		DTRACE_PROBE(mountd, log_no_host);
1095
1096		lq->ld_netid = strdup(transp->xp_netid);
1097		if (lq->ld_netid == NULL)
1098			goto cleanup;
1099
1100		lq->ld_nb = calloc(1, sizeof (struct netbuf));
1101		if (lq->ld_nb == NULL)
1102			goto cleanup;
1103
1104		nb = svc_getrpccaller(transp);
1105		if (nb == NULL) {
1106			DTRACE_PROBE(mountd, e__nb__enqueue);
1107			goto cleanup;
1108		}
1109
1110		DTRACE_PROBE(mountd, nb_set_enqueue);
1111
1112		lq->ld_nb->maxlen = nb->maxlen;
1113		lq->ld_nb->len = nb->len;
1114
1115		lq->ld_nb->buf = malloc(lq->ld_nb->len);
1116		if (lq->ld_nb->buf == NULL)
1117			goto cleanup;
1118
1119		bcopy(nb->buf, lq->ld_nb->buf, lq->ld_nb->len);
1120	}
1121
1122	lq->ld_path = strdup(path);
1123	if (lq->ld_path == NULL)
1124		goto cleanup;
1125
1126	if (!error) {
1127		lq->ld_rpath = strdup(rpath);
1128		if (lq->ld_rpath == NULL)
1129			goto cleanup;
1130	}
1131
1132	lq->ld_status = status;
1133
1134	/*
1135	 * Add to the tail of the logging queue.
1136	 */
1137	(void) mutex_lock(&logging_queue_lock);
1138	if (logging_tail == NULL) {
1139		logging_tail = logging_head = lq;
1140	} else {
1141		logging_tail->ld_next = lq;
1142		logging_tail = lq;
1143	}
1144	(void) cond_signal(&logging_queue_cv);
1145	(void) mutex_unlock(&logging_queue_lock);
1146
1147	return (TRUE);
1148
1149cleanup:
1150
1151	free_logging_data(lq);
1152
1153	return (FALSE);
1154}
1155
1156
1157#define	CLN_CLNAMES	(1 << 0)
1158#define	CLN_HOST	(1 << 1)
1159
1160static void
1161cln_init_common(struct cln *cln, SVCXPRT *transp, char *netid,
1162    struct netbuf *nbuf)
1163{
1164	if ((cln->transp = transp) != NULL) {
1165		assert(netid == NULL && nbuf == NULL);
1166		cln->netid = transp->xp_netid;
1167		cln->nbuf = svc_getrpccaller(transp);
1168	} else {
1169		cln->netid = netid;
1170		cln->nbuf = nbuf;
1171	}
1172
1173	cln->nconf = NULL;
1174	cln->clnames = NULL;
1175	cln->host = NULL;
1176
1177	cln->flags = 0;
1178}
1179
1180void
1181cln_init(struct cln *cln, SVCXPRT *transp)
1182{
1183	cln_init_common(cln, transp, NULL, NULL);
1184}
1185
1186void
1187cln_init_lazy(struct cln *cln, char *netid, struct netbuf *nbuf)
1188{
1189	cln_init_common(cln, NULL, netid, nbuf);
1190}
1191
1192void
1193cln_fini(struct cln *cln)
1194{
1195	if (cln->nconf != NULL)
1196		freenetconfigent(cln->nconf);
1197
1198	if (cln->clnames != NULL)
1199		netdir_free(cln->clnames, ND_HOSTSERVLIST);
1200
1201	free(cln->host);
1202}
1203
1204struct netbuf *
1205cln_getnbuf(struct cln *cln)
1206{
1207	return (cln->nbuf);
1208}
1209
1210struct nd_hostservlist *
1211cln_getclientsnames(struct cln *cln)
1212{
1213	if ((cln->flags & CLN_CLNAMES) == 0) {
1214		/*
1215		 * nconf is not needed if we do not have nbuf (see
1216		 * cln_gethost() too), so we check for nbuf and in a case it is
1217		 * NULL we do not try to get nconf.
1218		 */
1219		if (cln->netid != NULL && cln->nbuf != NULL) {
1220			cln->nconf = getnetconfigent(cln->netid);
1221			if (cln->nconf == NULL)
1222				syslog(LOG_ERR, "%s: getnetconfigent failed",
1223				    cln->netid);
1224		}
1225
1226		if (cln->nconf != NULL && cln->nbuf != NULL)
1227			(void) __netdir_getbyaddr_nosrv(cln->nconf,
1228			    &cln->clnames, cln->nbuf);
1229
1230		cln->flags |= CLN_CLNAMES;
1231	}
1232
1233	return (cln->clnames);
1234}
1235
1236/*
1237 * Return B_TRUE if the host is already available at no cost
1238 */
1239boolean_t
1240cln_havehost(struct cln *cln)
1241{
1242	return ((cln->flags & (CLN_CLNAMES | CLN_HOST)) != 0);
1243}
1244
1245char *
1246cln_gethost(struct cln *cln)
1247{
1248	if (cln_getclientsnames(cln) != NULL)
1249		return (cln->clnames->h_hostservs[0].h_host);
1250
1251	if ((cln->flags & CLN_HOST) == 0) {
1252		if (cln->nconf == NULL || cln->nbuf == NULL) {
1253			cln->host = strdup("(anon)");
1254		} else {
1255			char host[MAXIPADDRLEN];
1256
1257			if (strcmp(cln->nconf->nc_protofmly, NC_INET) == 0) {
1258				struct sockaddr_in *sa;
1259
1260				/* LINTED pointer alignment */
1261				sa = (struct sockaddr_in *)(cln->nbuf->buf);
1262				(void) inet_ntoa_r(sa->sin_addr, host);
1263
1264				cln->host = strdup(host);
1265			} else if (strcmp(cln->nconf->nc_protofmly,
1266			    NC_INET6) == 0) {
1267				struct sockaddr_in6 *sa;
1268
1269				/* LINTED pointer alignment */
1270				sa = (struct sockaddr_in6 *)(cln->nbuf->buf);
1271				(void) inet_ntop(AF_INET6,
1272				    sa->sin6_addr.s6_addr,
1273				    host, INET6_ADDRSTRLEN);
1274
1275				cln->host = strdup(host);
1276			} else {
1277				syslog(LOG_ERR, gettext("Client's address is "
1278				    "neither IPv4 nor IPv6"));
1279
1280				cln->host = strdup("(anon)");
1281			}
1282		}
1283
1284		cln->flags |= CLN_HOST;
1285	}
1286
1287	return (cln->host);
1288}
1289
1290/*
1291 * Check mount requests, add to mounted list if ok
1292 */
1293static int
1294mount(struct svc_req *rqstp)
1295{
1296	SVCXPRT *transp;
1297	int version, vers;
1298	struct fhstatus fhs;
1299	struct mountres3 mountres3;
1300	char fh[FHSIZE3];
1301	int len = FHSIZE3;
1302	char *path, rpath[MAXPATHLEN];
1303	share_t *sh = NULL;
1304	struct cln cln;
1305	char *host = NULL;
1306	int error = 0, lofs_tried = 0, enqueued;
1307	int flavor_list[MAX_FLAVORS];
1308	int flavor_count;
1309	ucred_t	*uc = NULL;
1310
1311	int audit_status;
1312
1313	transp = rqstp->rq_xprt;
1314	version = rqstp->rq_vers;
1315	path = NULL;
1316
1317	if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
1318		svcerr_decode(transp);
1319		return (EACCES);
1320	}
1321
1322	cln_init(&cln, transp);
1323
1324	/*
1325	 * Put off getting the name for the client until we
1326	 * need it. This is a performance gain. If we are logging,
1327	 * then we don't care about performance and might as well
1328	 * get the host name now in case we need to spit out an
1329	 * error message.
1330	 */
1331	if (verbose) {
1332		DTRACE_PROBE(mountd, name_by_verbose);
1333		if ((host = cln_gethost(&cln)) == NULL) {
1334			/*
1335			 * We failed to get a name for the client, even
1336			 * 'anon', probably because we ran out of memory.
1337			 * In this situation it doesn't make sense to
1338			 * allow the mount to succeed.
1339			 */
1340			error = EACCES;
1341			goto reply;
1342		}
1343	}
1344
1345	/*
1346	 * If the version being used is less than the minimum version,
1347	 * the filehandle translation should not be provided to the
1348	 * client.
1349	 */
1350	if (rejecting || version < mount_vers_min) {
1351		if (verbose)
1352			syslog(LOG_NOTICE, "Rejected mount: %s for %s",
1353			    host, path);
1354		error = EACCES;
1355		goto reply;
1356	}
1357
1358	/*
1359	 * Trusted Extension doesn't support nfsv2. nfsv2 client
1360	 * uses MOUNT protocol v1 and v2. To prevent circumventing
1361	 * TX label policy via using nfsv2 client, reject a mount
1362	 * request with version less than 3 and log an error.
1363	 */
1364	if (is_system_labeled()) {
1365		if (version < 3) {
1366			if (verbose)
1367				syslog(LOG_ERR,
1368				    "Rejected mount: TX doesn't support NFSv2");
1369			error = EACCES;
1370			goto reply;
1371		}
1372	}
1373
1374	/*
1375	 * Get the real path (no symbolic links in it)
1376	 */
1377	if (realpath(path, rpath) == NULL) {
1378		error = errno;
1379		if (verbose)
1380			syslog(LOG_ERR,
1381			    "mount request: realpath: %s: %m", path);
1382		if (error == ENOENT)
1383			error = mount_enoent_error(&cln, path, rpath,
1384			    flavor_list);
1385		goto reply;
1386	}
1387
1388	if ((sh = findentry(rpath)) == NULL &&
1389	    (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) {
1390		error = EACCES;
1391		goto reply;
1392	}
1393
1394	/*
1395	 * Check if this is a "nosub" only export, in which case, mounting
1396	 * subdirectories isn't allowed. Bug 1184573.
1397	 */
1398	if (checkrootmount(sh, rpath) == 0) {
1399		error = EACCES;
1400		goto reply;
1401	}
1402
1403	if (newopts(sh->sh_opts))
1404		flavor_count = getclientsflavors_new(sh, &cln, flavor_list);
1405	else
1406		flavor_count = getclientsflavors_old(sh, &cln, flavor_list);
1407
1408	if (flavor_count == 0) {
1409		error = EACCES;
1410		goto reply;
1411	}
1412
1413	/*
1414	 * Check MAC policy here. The server side policy should be
1415	 * consistent with client side mount policy, i.e.
1416	 * - we disallow an admin_low unlabeled client to mount
1417	 * - we disallow mount from a lower labeled client.
1418	 */
1419	if (is_system_labeled()) {
1420		m_label_t *clabel = NULL;
1421		m_label_t *slabel = NULL;
1422		m_label_t admin_low;
1423
1424		if (svc_getcallerucred(rqstp->rq_xprt, &uc) != 0) {
1425			syslog(LOG_ERR,
1426			    "mount request: Failed to get caller's ucred : %m");
1427			error = EACCES;
1428			goto reply;
1429		}
1430		if ((clabel = ucred_getlabel(uc)) == NULL) {
1431			syslog(LOG_ERR,
1432			    "mount request: can't get client label from ucred");
1433			error = EACCES;
1434			goto reply;
1435		}
1436
1437		bsllow(&admin_low);
1438		if (blequal(&admin_low, clabel)) {
1439			struct sockaddr *ca;
1440			tsol_tpent_t	*tp;
1441
1442			ca = (struct sockaddr *)(void *)svc_getrpccaller(
1443			    rqstp->rq_xprt)->buf;
1444			if (ca == NULL) {
1445				error = EACCES;
1446				goto reply;
1447			}
1448			/*
1449			 * get trusted network template associated
1450			 * with the client.
1451			 */
1452			tp = get_client_template(ca);
1453			if (tp == NULL || tp->host_type != SUN_CIPSO) {
1454				if (tp != NULL)
1455					tsol_freetpent(tp);
1456				error = EACCES;
1457				goto reply;
1458			}
1459			tsol_freetpent(tp);
1460		} else {
1461			if ((slabel = m_label_alloc(MAC_LABEL)) == NULL) {
1462				error = EACCES;
1463				goto reply;
1464			}
1465
1466			if (getlabel(rpath, slabel) != 0) {
1467				m_label_free(slabel);
1468				error = EACCES;
1469				goto reply;
1470			}
1471
1472			if (!bldominates(clabel, slabel)) {
1473				m_label_free(slabel);
1474				error = EACCES;
1475				goto reply;
1476			}
1477			m_label_free(slabel);
1478		}
1479	}
1480
1481	/*
1482	 * Now get the filehandle.
1483	 *
1484	 * NFS V2 clients get a 32 byte filehandle.
1485	 * NFS V3 clients get a 32 or 64 byte filehandle, depending on
1486	 * the embedded FIDs.
1487	 */
1488	vers = (version == MOUNTVERS3) ? NFS_V3 : NFS_VERSION;
1489
1490	/* LINTED pointer alignment */
1491	while (nfs_getfh(rpath, vers, &len, fh) < 0) {
1492		if (errno == EINVAL &&
1493		    (sh = find_lofsentry(rpath, &lofs_tried)) != NULL) {
1494			errno = 0;
1495			continue;
1496		}
1497		error = errno == EINVAL ? EACCES : errno;
1498		syslog(LOG_DEBUG, "mount request: getfh failed on %s: %m",
1499		    path);
1500		break;
1501	}
1502
1503	if (version == MOUNTVERS3) {
1504		mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len = len;
1505		mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val = fh;
1506	} else {
1507		bcopy(fh, &fhs.fhstatus_u.fhs_fhandle, NFS_FHSIZE);
1508	}
1509
1510reply:
1511	if (uc != NULL)
1512		ucred_free(uc);
1513
1514	switch (version) {
1515	case MOUNTVERS:
1516	case MOUNTVERS_POSIX:
1517		if (error == EINVAL)
1518			fhs.fhs_status = NFSERR_ACCES;
1519		else if (error == EREMOTE)
1520			fhs.fhs_status = NFSERR_REMOTE;
1521		else
1522			fhs.fhs_status = error;
1523
1524		if (!svc_sendreply(transp, xdr_fhstatus, (char *)&fhs))
1525			log_cant_reply_cln(&cln);
1526
1527		audit_status = fhs.fhs_status;
1528		break;
1529
1530	case MOUNTVERS3:
1531		if (!error) {
1532		mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val =
1533		    flavor_list;
1534		mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len =
1535		    flavor_count;
1536
1537		} else if (error == ENAMETOOLONG)
1538			error = MNT3ERR_NAMETOOLONG;
1539
1540		mountres3.fhs_status = error;
1541		if (!svc_sendreply(transp, xdr_mountres3, (char *)&mountres3))
1542			log_cant_reply_cln(&cln);
1543
1544		audit_status = mountres3.fhs_status;
1545		break;
1546	}
1547
1548	if (cln_havehost(&cln))
1549		host = cln_gethost(&cln);
1550
1551	if (verbose)
1552		syslog(LOG_NOTICE, "MOUNT: %s %s %s",
1553		    (host == NULL) ? "unknown host" : host,
1554		    error ? "denied" : "mounted", path);
1555
1556	/*
1557	 * If we can not create a queue entry, go ahead and do it
1558	 * in the context of this thread.
1559	 */
1560	enqueued = enqueue_logging_data(host, transp, path, rpath,
1561	    audit_status, error);
1562	if (enqueued == FALSE) {
1563		if (host == NULL) {
1564			DTRACE_PROBE(mountd, name_by_in_thread);
1565			host = cln_gethost(&cln);
1566		}
1567
1568		DTRACE_PROBE(mountd, logged_in_thread);
1569		audit_mountd_mount(host, path, audit_status); /* BSM */
1570		if (!error)
1571			mntlist_new(host, rpath); /* add entry to mount list */
1572	}
1573
1574	if (path != NULL)
1575		svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
1576
1577	if (sh)
1578		sharefree(sh);
1579
1580	cln_fini(&cln);
1581
1582	return (error);
1583}
1584
1585/*
1586 * Determine whether two paths are within the same file system.
1587 * Returns nonzero (true) if paths are the same, zero (false) if
1588 * they are different.  If an error occurs, return false.
1589 *
1590 * Use the actual FSID if it's available (via getattrat()); otherwise,
1591 * fall back on st_dev.
1592 *
1593 * With ZFS snapshots, st_dev differs from the regular file system
1594 * versus the snapshot.  But the fsid is the same throughout.  Thus
1595 * the fsid is a better test.
1596 */
1597static int
1598same_file_system(const char *path1, const char *path2)
1599{
1600	uint64_t fsid1, fsid2;
1601	struct stat64 st1, st2;
1602	nvlist_t *nvl1 = NULL;
1603	nvlist_t *nvl2 = NULL;
1604
1605	if ((getattrat(AT_FDCWD, XATTR_VIEW_READONLY, path1, &nvl1) == 0) &&
1606	    (getattrat(AT_FDCWD, XATTR_VIEW_READONLY, path2, &nvl2) == 0) &&
1607	    (nvlist_lookup_uint64(nvl1, A_FSID, &fsid1) == 0) &&
1608	    (nvlist_lookup_uint64(nvl2, A_FSID, &fsid2) == 0)) {
1609		nvlist_free(nvl1);
1610		nvlist_free(nvl2);
1611		/*
1612		 * We have found fsid's for both paths.
1613		 */
1614
1615		if (fsid1 == fsid2)
1616			return (B_TRUE);
1617
1618		return (B_FALSE);
1619	}
1620
1621	nvlist_free(nvl1);
1622	nvlist_free(nvl2);
1623
1624	/*
1625	 * We were unable to find fsid's for at least one of the paths.
1626	 * fall back on st_dev.
1627	 */
1628
1629	if (stat64(path1, &st1) < 0) {
1630		syslog(LOG_NOTICE, "%s: %m", path1);
1631		return (B_FALSE);
1632	}
1633	if (stat64(path2, &st2) < 0) {
1634		syslog(LOG_NOTICE, "%s: %m", path2);
1635		return (B_FALSE);
1636	}
1637
1638	if (st1.st_dev == st2.st_dev)
1639		return (B_TRUE);
1640
1641	return (B_FALSE);
1642}
1643
1644share_t *
1645findentry(char *path)
1646{
1647	share_t *sh = NULL;
1648	struct sh_list *shp;
1649	char *p1, *p2;
1650
1651	check_sharetab();
1652
1653	(void) rw_rdlock(&sharetab_lock);
1654
1655	for (shp = share_list; shp; shp = shp->shl_next) {
1656		sh = shp->shl_sh;
1657		for (p1 = sh->sh_path, p2 = path; *p1 == *p2; p1++, p2++)
1658			if (*p1 == '\0')
1659				goto done;	/* exact match */
1660
1661		/*
1662		 * Now compare the pathnames for three cases:
1663		 *
1664		 * Parent: /export/foo		(no trailing slash on parent)
1665		 * Child:  /export/foo/bar
1666		 *
1667		 * Parent: /export/foo/		(trailing slash on parent)
1668		 * Child:  /export/foo/bar
1669		 *
1670		 * Parent: /export/foo/		(no trailing slash on child)
1671		 * Child:  /export/foo
1672		 */
1673		if ((*p1 == '\0' && *p2 == '/') ||
1674		    (*p1 == '\0' && *(p1-1) == '/') ||
1675		    (*p2 == '\0' && *p1 == '/' && *(p1+1) == '\0')) {
1676			/*
1677			 * We have a subdirectory.  Test whether the
1678			 * subdirectory is in the same file system.
1679			 */
1680			if (same_file_system(path, sh->sh_path))
1681				goto done;
1682		}
1683	}
1684done:
1685	sh = shp ? sharedup(sh) : NULL;
1686
1687	(void) rw_unlock(&sharetab_lock);
1688
1689	return (sh);
1690}
1691
1692
1693static int
1694is_substring(char **mntp, char **path)
1695{
1696	char *p1 = *mntp, *p2 = *path;
1697
1698	if (*p1 == '\0' && *p2 == '\0') /* exact match */
1699		return (1);
1700	else if (*p1 == '\0' && *p2 == '/')
1701		return (1);
1702	else if (*p1 == '\0' && *(p1-1) == '/') {
1703		*path = --p2; /* we need the slash in p2 */
1704		return (1);
1705	} else if (*p2 == '\0') {
1706		while (*p1 == '/')
1707			p1++;
1708		if (*p1 == '\0') /* exact match */
1709			return (1);
1710	}
1711	return (0);
1712}
1713
1714/*
1715 * find_lofsentry() searches for the real path which this requested LOFS path
1716 * (rpath) shadows. If found, it will return the sharetab entry of
1717 * the real path that corresponds to the LOFS path.
1718 * We first search mnttab to see if the requested path is an automounted
1719 * path. If it is an automounted path, it will trigger the mount by stat()ing
1720 * the requested path. Note that it is important to check that this path is
1721 * actually an automounted path, otherwise we would stat() a path which may
1722 * turn out to be NFS and block indefinitely on a dead server. The automounter
1723 * times-out if the server is dead, so there's no risk of hanging this
1724 * thread waiting for stat().
1725 * After the mount has been triggered (if necessary), we look for a
1726 * mountpoint of type LOFS (by searching /etc/mnttab again) which
1727 * is a substring of the rpath. If found, we construct a new path by
1728 * concatenating the mnt_special and the remaining of rpath, call findentry()
1729 * to make sure the 'real path' is shared.
1730 */
1731static share_t *
1732find_lofsentry(char *rpath, int *done_flag)
1733{
1734	struct stat r_stbuf;
1735	mntlist_t *ml, *mntl, *mntpnt = NULL;
1736	share_t *retcode = NULL;
1737	char tmp_path[MAXPATHLEN];
1738	int mntpnt_len = 0, tmp;
1739	char *p1, *p2;
1740
1741	if ((*done_flag)++)
1742		return (retcode);
1743
1744	/*
1745	 * While fsgetmntlist() uses lockf() to
1746	 * lock the mnttab before reading it in,
1747	 * the lock ignores threads in the same process.
1748	 * Read in the mnttab with the protection of a mutex.
1749	 */
1750	(void) mutex_lock(&mnttab_lock);
1751	mntl = fsgetmntlist();
1752	(void) mutex_unlock(&mnttab_lock);
1753
1754	/*
1755	 * Obtain the mountpoint for the requested path.
1756	 */
1757	for (ml = mntl; ml; ml = ml->mntl_next) {
1758		for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath;
1759		    *p1 == *p2 && *p1; p1++, p2++)
1760			;
1761		if (is_substring(&p1, &p2) &&
1762		    (tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len) {
1763			mntpnt = ml;
1764			mntpnt_len = tmp;
1765		}
1766	}
1767
1768	/*
1769	 * If the path needs to be autoFS mounted, trigger the mount by
1770	 * stat()ing it. This is determined by checking whether the
1771	 * mountpoint we just found is of type autofs.
1772	 */
1773	if (mntpnt != NULL &&
1774	    strcmp(mntpnt->mntl_mnt->mnt_fstype, "autofs") == 0) {
1775		/*
1776		 * The requested path is a substring of an autoFS filesystem.
1777		 * Trigger the mount.
1778		 */
1779		if (stat(rpath, &r_stbuf) < 0) {
1780			if (verbose)
1781				syslog(LOG_NOTICE, "%s: %m", rpath);
1782			goto done;
1783		}
1784		if ((r_stbuf.st_mode & S_IFMT) == S_IFDIR) {
1785			/*
1786			 * The requested path is a directory, stat(2) it
1787			 * again with a trailing '.' to force the autoFS
1788			 * module to trigger the mount of indirect
1789			 * automount entries, such as /net/jurassic/.
1790			 */
1791			if (strlen(rpath) + 2 > MAXPATHLEN) {
1792				if (verbose) {
1793					syslog(LOG_NOTICE,
1794					    "%s/.: exceeds MAXPATHLEN %d",
1795					    rpath, MAXPATHLEN);
1796				}
1797				goto done;
1798			}
1799			(void) strcpy(tmp_path, rpath);
1800			(void) strcat(tmp_path, "/.");
1801
1802			if (stat(tmp_path, &r_stbuf) < 0) {
1803				if (verbose)
1804					syslog(LOG_NOTICE, "%s: %m", tmp_path);
1805				goto done;
1806			}
1807		}
1808
1809		/*
1810		 * The mount has been triggered, re-read mnttab to pick up
1811		 * the changes made by autoFS.
1812		 */
1813		fsfreemntlist(mntl);
1814		(void) mutex_lock(&mnttab_lock);
1815		mntl = fsgetmntlist();
1816		(void) mutex_unlock(&mnttab_lock);
1817	}
1818
1819	/*
1820	 * The autoFS mountpoint has been triggered if necessary,
1821	 * now search mnttab again to determine if the requested path
1822	 * is an LOFS mount of a shared path.
1823	 */
1824	mntpnt_len = 0;
1825	for (ml = mntl; ml; ml = ml->mntl_next) {
1826		if (strcmp(ml->mntl_mnt->mnt_fstype, "lofs"))
1827			continue;
1828
1829		for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath;
1830		    *p1 == *p2 && *p1; p1++, p2++)
1831			;
1832
1833		if (is_substring(&p1, &p2) &&
1834		    ((tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len)) {
1835			mntpnt_len = tmp;
1836
1837			if ((strlen(ml->mntl_mnt->mnt_special) + strlen(p2)) >
1838			    MAXPATHLEN) {
1839				if (verbose) {
1840					syslog(LOG_NOTICE, "%s%s: exceeds %d",
1841					    ml->mntl_mnt->mnt_special, p2,
1842					    MAXPATHLEN);
1843				}
1844				if (retcode)
1845					sharefree(retcode);
1846				retcode = NULL;
1847				goto done;
1848			}
1849
1850			(void) strcpy(tmp_path, ml->mntl_mnt->mnt_special);
1851			(void) strcat(tmp_path, p2);
1852			if (retcode)
1853				sharefree(retcode);
1854			retcode = findentry(tmp_path);
1855		}
1856	}
1857
1858	if (retcode) {
1859		assert(strlen(tmp_path) > 0);
1860		(void) strcpy(rpath, tmp_path);
1861	}
1862
1863done:
1864	fsfreemntlist(mntl);
1865	return (retcode);
1866}
1867
1868/*
1869 * Determine whether an access list grants rights to a particular host.
1870 * We match on aliases of the hostname as well as on the canonical name.
1871 * Names in the access list may be either hosts or netgroups;  they're
1872 * not distinguished syntactically.  We check for hosts first because
1873 * it's cheaper, then try netgroups.
1874 *
1875 * Return values:
1876 *  1 - access is granted
1877 *  0 - access is denied
1878 * -1 - an error occured
1879 */
1880int
1881in_access_list(struct cln *cln,
1882    char *access_list)	/* N.B. we clobber this "input" parameter */
1883{
1884	char addr[INET_ADDRSTRLEN];
1885	char buff[256];
1886	int nentries = 0;
1887	char *cstr = access_list;
1888	char *gr = access_list;
1889	int i;
1890	int response;
1891	int ret;
1892	struct netbuf *pnb;
1893	struct nd_hostservlist *clnames = NULL;
1894
1895	/* If no access list - then it's unrestricted */
1896	if (access_list == NULL || *access_list == '\0')
1897		return (1);
1898
1899	if ((pnb = cln_getnbuf(cln)) == NULL)
1900		return (-1);
1901
1902	for (;;) {
1903		if ((cstr = strpbrk(cstr, "[:")) != NULL) {
1904			if (*cstr == ':') {
1905				*cstr = '\0';
1906			} else {
1907				assert(*cstr == '[');
1908				cstr = strchr(cstr + 1, ']');
1909				if (cstr == NULL)
1910					return (-1);
1911				cstr++;
1912				continue;
1913			}
1914		}
1915
1916		/*
1917		 * If the list name has a '-' prepended then a match of
1918		 * the following name implies failure instead of success.
1919		 */
1920		if (*gr == '-') {
1921			response = 0;
1922			gr++;
1923		} else {
1924			response = 1;
1925		}
1926
1927		/*
1928		 * First check if we have '@' entry, as it doesn't
1929		 * require client hostname.
1930		 */
1931		if (*gr == '@') {
1932			gr++;
1933
1934			/* Netname support */
1935			if (!isdigit(*gr) && *gr != '[') {
1936				struct netent n, *np;
1937
1938				if ((np = getnetbyname_r(gr, &n, buff,
1939				    sizeof (buff))) != NULL &&
1940				    np->n_net != 0) {
1941					while ((np->n_net & 0xFF000000u) == 0)
1942						np->n_net <<= 8;
1943					np->n_net = htonl(np->n_net);
1944					if (inet_ntop(AF_INET, &np->n_net, addr,
1945					    INET_ADDRSTRLEN) == NULL)
1946						break;
1947					ret = inet_matchaddr(pnb->buf, addr);
1948					if (ret == -1) {
1949						if (errno == EINVAL) {
1950							syslog(LOG_WARNING,
1951							    "invalid access "
1952							    "list entry: %s",
1953							    addr);
1954						}
1955						return (-1);
1956					} else if (ret == 1) {
1957						return (response);
1958					}
1959				}
1960			} else {
1961				ret = inet_matchaddr(pnb->buf, gr);
1962				if (ret == -1) {
1963					if (errno == EINVAL) {
1964						syslog(LOG_WARNING,
1965						    "invalid access list "
1966						    "entry: %s", gr);
1967					}
1968					return (-1);
1969				} else if (ret == 1) {
1970					return (response);
1971				}
1972			}
1973
1974			goto next;
1975		}
1976
1977		/*
1978		 * No other checks can be performed if client address
1979		 * can't be resolved.
1980		 */
1981		if ((clnames = cln_getclientsnames(cln)) == NULL)
1982			goto next;
1983
1984		/* Otherwise loop through all client hostname aliases */
1985		for (i = 0; i < clnames->h_cnt; i++) {
1986			char *host = clnames->h_hostservs[i].h_host;
1987
1988			/*
1989			 * If the list name begins with a dot then
1990			 * do a domain name suffix comparison.
1991			 * A single dot matches any name with no
1992			 * suffix.
1993			 */
1994			if (*gr == '.') {
1995				if (*(gr + 1) == '\0') {  /* single dot */
1996					if (strchr(host, '.') == NULL)
1997						return (response);
1998				} else {
1999					int off = strlen(host) - strlen(gr);
2000					if (off > 0 &&
2001					    strcasecmp(host + off, gr) == 0) {
2002						return (response);
2003					}
2004				}
2005			} else {
2006				/* Just do a hostname match */
2007				if (strcasecmp(gr, host) == 0)
2008					return (response);
2009			}
2010		}
2011
2012		nentries++;
2013
2014next:
2015		if (cstr == NULL)
2016			break;
2017
2018		gr = ++cstr;
2019	}
2020
2021	if (clnames == NULL)
2022		return (0);
2023
2024	return (netgroup_check(clnames, access_list, nentries));
2025}
2026
2027
2028static char *optlist[] = {
2029#define	OPT_RO		0
2030	SHOPT_RO,
2031#define	OPT_RW		1
2032	SHOPT_RW,
2033#define	OPT_ROOT	2
2034	SHOPT_ROOT,
2035#define	OPT_SECURE	3
2036	SHOPT_SECURE,
2037#define	OPT_ANON	4
2038	SHOPT_ANON,
2039#define	OPT_WINDOW	5
2040	SHOPT_WINDOW,
2041#define	OPT_NOSUID	6
2042	SHOPT_NOSUID,
2043#define	OPT_ACLOK	7
2044	SHOPT_ACLOK,
2045#define	OPT_SEC		8
2046	SHOPT_SEC,
2047#define	OPT_NONE	9
2048	SHOPT_NONE,
2049#define	OPT_UIDMAP	10
2050	SHOPT_UIDMAP,
2051#define	OPT_GIDMAP	11
2052	SHOPT_GIDMAP,
2053	NULL
2054};
2055
2056static int
2057map_flavor(char *str)
2058{
2059	seconfig_t sec;
2060
2061	if (nfs_getseconfig_byname(str, &sec))
2062		return (-1);
2063
2064	return (sec.sc_nfsnum);
2065}
2066
2067/*
2068 * If the option string contains a "sec="
2069 * option, then use new option syntax.
2070 */
2071static int
2072newopts(char *opts)
2073{
2074	char *head, *p, *val;
2075
2076	if (!opts || *opts == '\0')
2077		return (0);
2078
2079	head = strdup(opts);
2080	if (head == NULL) {
2081		syslog(LOG_ERR, "opts: no memory");
2082		return (0);
2083	}
2084
2085	p = head;
2086	while (*p) {
2087		if (getsubopt(&p, optlist, &val) == OPT_SEC) {
2088			free(head);
2089			return (1);
2090		}
2091	}
2092
2093	free(head);
2094	return (0);
2095}
2096
2097/*
2098 * Given an export and the clients hostname(s)
2099 * determine the security flavors that this
2100 * client is permitted to use.
2101 *
2102 * This routine is called only for "old" syntax, i.e.
2103 * only one security flavor is allowed.  So we need
2104 * to determine two things: the particular flavor,
2105 * and whether the client is allowed to use this
2106 * flavor, i.e. is in the access list.
2107 *
2108 * Note that if there is no access list, then the
2109 * default is that access is granted.
2110 */
2111static int
2112getclientsflavors_old(share_t *sh, struct cln *cln, int *flavors)
2113{
2114	char *opts, *p, *val;
2115	boolean_t ok = B_FALSE;
2116	int defaultaccess = 1;
2117	boolean_t reject = B_FALSE;
2118
2119	opts = strdup(sh->sh_opts);
2120	if (opts == NULL) {
2121		syslog(LOG_ERR, "getclientsflavors: no memory");
2122		return (0);
2123	}
2124
2125	flavors[0] = AUTH_SYS;
2126	p = opts;
2127
2128	while (*p) {
2129
2130		switch (getsubopt(&p, optlist, &val)) {
2131		case OPT_SECURE:
2132			flavors[0] = AUTH_DES;
2133			break;
2134
2135		case OPT_RO:
2136		case OPT_RW:
2137			defaultaccess = 0;
2138			if (in_access_list(cln, val) > 0)
2139				ok = B_TRUE;
2140			break;
2141
2142		case OPT_NONE:
2143			defaultaccess = 0;
2144			if (in_access_list(cln, val) > 0)
2145				reject = B_TRUE;
2146		}
2147	}
2148
2149	free(opts);
2150
2151	/* none takes precedence over everything else */
2152	if (reject)
2153		ok = B_FALSE;
2154
2155	return (defaultaccess || ok);
2156}
2157
2158/*
2159 * Given an export and the clients hostname(s)
2160 * determine the security flavors that this
2161 * client is permitted to use.
2162 *
2163 * This is somewhat more complicated than the "old"
2164 * routine because the options may contain multiple
2165 * security flavors (sec=) each with its own access
2166 * lists.  So a client could be granted access based
2167 * on a number of security flavors.  Note that the
2168 * type of access might not always be the same, the
2169 * client may get readonly access with one flavor
2170 * and readwrite with another, however the client
2171 * is not told this detail, it gets only the list
2172 * of flavors, and only if the client is using
2173 * version 3 of the mount protocol.
2174 */
2175static int
2176getclientsflavors_new(share_t *sh, struct cln *cln, int *flavors)
2177{
2178	char *opts, *p, *val;
2179	char *lasts;
2180	char *f;
2181	boolean_t defaultaccess = B_TRUE;	/* default access is rw */
2182	boolean_t access_ok = B_FALSE;
2183	int count, c;
2184	boolean_t reject = B_FALSE;
2185
2186	opts = strdup(sh->sh_opts);
2187	if (opts == NULL) {
2188		syslog(LOG_ERR, "getclientsflavors: no memory");
2189		return (0);
2190	}
2191
2192	p = opts;
2193	count = c = 0;
2194
2195	while (*p) {
2196		switch (getsubopt(&p, optlist, &val)) {
2197		case OPT_SEC:
2198			if (reject)
2199				access_ok = B_FALSE;
2200
2201			/*
2202			 * Before a new sec=xxx option, check if we need
2203			 * to move the c index back to the previous count.
2204			 */
2205			if (!defaultaccess && !access_ok) {
2206				c = count;
2207			}
2208
2209			/* get all the sec=f1[:f2] flavors */
2210			while ((f = strtok_r(val, ":", &lasts)) != NULL) {
2211				flavors[c++] = map_flavor(f);
2212				val = NULL;
2213			}
2214
2215			/* for a new sec=xxx option, default is rw access */
2216			defaultaccess = B_TRUE;
2217			access_ok = B_FALSE;
2218			reject = B_FALSE;
2219			break;
2220
2221		case OPT_RO:
2222		case OPT_RW:
2223			defaultaccess = B_FALSE;
2224			if (in_access_list(cln, val) > 0)
2225				access_ok = B_TRUE;
2226			break;
2227
2228		case OPT_NONE:
2229			defaultaccess = B_FALSE;
2230			if (in_access_list(cln, val) > 0)
2231				reject = B_TRUE; /* none overides rw/ro */
2232			break;
2233		}
2234	}
2235
2236	if (reject)
2237		access_ok = B_FALSE;
2238
2239	if (!defaultaccess && !access_ok)
2240		c = count;
2241
2242	free(opts);
2243
2244	return (c);
2245}
2246
2247/*
2248 * This is a tricky piece of code that parses the
2249 * share options looking for a match on the auth
2250 * flavor that the client is using. If it finds
2251 * a match, then the client is given ro, rw, or
2252 * no access depending whether it is in the access
2253 * list.  There is a special case for "secure"
2254 * flavor.  Other flavors are values of the new "sec=" option.
2255 */
2256int
2257check_client(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
2258    gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
2259    gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
2260{
2261	if (newopts(sh->sh_opts))
2262		return (check_client_new(sh, cln, flavor, clnt_uid, clnt_gid,
2263		    clnt_ngids, clnt_gids, srv_uid, srv_gid, srv_ngids,
2264		    srv_gids));
2265	else
2266		return (check_client_old(sh, cln, flavor, clnt_uid, clnt_gid,
2267		    clnt_ngids, clnt_gids, srv_uid, srv_gid, srv_ngids,
2268		    srv_gids));
2269}
2270
2271extern int _getgroupsbymember(const char *, gid_t[], int, int);
2272
2273/*
2274 * Get supplemental groups for uid
2275 */
2276static int
2277getusergroups(uid_t uid, uint_t *ngrps, gid_t **grps)
2278{
2279	struct passwd pwd;
2280	char *pwbuf = alloca(pw_size);
2281	gid_t *tmpgrps = alloca(ngroups_max * sizeof (gid_t));
2282	int tmpngrps;
2283
2284	if (getpwuid_r(uid, &pwd, pwbuf, pw_size) == NULL)
2285		return (-1);
2286
2287	tmpgrps[0] = pwd.pw_gid;
2288
2289	tmpngrps = _getgroupsbymember(pwd.pw_name, tmpgrps, ngroups_max, 1);
2290	if (tmpngrps <= 0) {
2291		syslog(LOG_WARNING,
2292		    "getusergroups(): Unable to get groups for user %s",
2293		    pwd.pw_name);
2294
2295		return (-1);
2296	}
2297
2298	*grps = malloc(tmpngrps * sizeof (gid_t));
2299	if (*grps == NULL) {
2300		syslog(LOG_ERR,
2301		    "getusergroups(): Memory allocation failed: %m");
2302
2303		return (-1);
2304	}
2305
2306	*ngrps = tmpngrps;
2307	(void) memcpy(*grps, tmpgrps, tmpngrps * sizeof (gid_t));
2308
2309	return (0);
2310}
2311
2312/*
2313 * is_a_number(number)
2314 *
2315 * is the string a number in one of the forms we want to use?
2316 */
2317
2318static int
2319is_a_number(char *number)
2320{
2321	int ret = 1;
2322	int hex = 0;
2323
2324	if (strncmp(number, "0x", 2) == 0) {
2325		number += 2;
2326		hex = 1;
2327	} else if (*number == '-') {
2328		number++; /* skip the minus */
2329	}
2330	while (ret == 1 && *number != '\0') {
2331		if (hex) {
2332			ret = isxdigit(*number++);
2333		} else {
2334			ret = isdigit(*number++);
2335		}
2336	}
2337	return (ret);
2338}
2339
2340static boolean_t
2341get_uid(char *value, uid_t *uid)
2342{
2343	if (!is_a_number(value)) {
2344		struct passwd *pw;
2345		/*
2346		 * in this case it would have to be a
2347		 * user name
2348		 */
2349		pw = getpwnam(value);
2350		if (pw == NULL)
2351			return (B_FALSE);
2352		*uid = pw->pw_uid;
2353		endpwent();
2354	} else {
2355		uint64_t intval;
2356		intval = strtoull(value, NULL, 0);
2357		if (intval > UID_MAX && intval != -1)
2358			return (B_FALSE);
2359		*uid = (uid_t)intval;
2360	}
2361
2362	return (B_TRUE);
2363}
2364
2365static boolean_t
2366get_gid(char *value, gid_t *gid)
2367{
2368	if (!is_a_number(value)) {
2369		struct group *gr;
2370		/*
2371		 * in this case it would have to be a
2372		 * group name
2373		 */
2374		gr = getgrnam(value);
2375		if (gr == NULL)
2376			return (B_FALSE);
2377		*gid = gr->gr_gid;
2378		endgrent();
2379	} else {
2380		uint64_t intval;
2381		intval = strtoull(value, NULL, 0);
2382		if (intval > UID_MAX && intval != -1)
2383			return (B_FALSE);
2384		*gid = (gid_t)intval;
2385	}
2386
2387	return (B_TRUE);
2388}
2389
2390static int
2391check_client_old(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
2392    gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
2393    gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
2394{
2395	char *opts, *p, *val;
2396	int match;	/* Set when a flavor is matched */
2397	int perm = 0;	/* Set when "ro", "rw" or "root" is matched */
2398	int list = 0;	/* Set when "ro", "rw" is found */
2399	int ro_val = 0;	/* Set if ro option is 'ro=' */
2400	int rw_val = 0;	/* Set if rw option is 'rw=' */
2401
2402	boolean_t map_deny = B_FALSE;
2403
2404	opts = strdup(sh->sh_opts);
2405	if (opts == NULL) {
2406		syslog(LOG_ERR, "check_client: no memory");
2407		return (0);
2408	}
2409
2410	/*
2411	 * If client provided 16 supplemental groups with AUTH_SYS, lookup
2412	 * locally for all of them
2413	 */
2414	if (flavor == AUTH_SYS && clnt_ngids == NGRPS && ngroups_max > NGRPS)
2415		if (getusergroups(clnt_uid, srv_ngids, srv_gids) == 0)
2416			perm |= NFSAUTH_GROUPS;
2417
2418	p = opts;
2419	match = AUTH_UNIX;
2420
2421	while (*p) {
2422		switch (getsubopt(&p, optlist, &val)) {
2423
2424		case OPT_SECURE:
2425			match = AUTH_DES;
2426
2427			if (perm & NFSAUTH_GROUPS) {
2428				free(*srv_gids);
2429				*srv_ngids = 0;
2430				*srv_gids = NULL;
2431				perm &= ~NFSAUTH_GROUPS;
2432			}
2433
2434			break;
2435
2436		case OPT_RO:
2437			list++;
2438			if (val != NULL)
2439				ro_val++;
2440			if (in_access_list(cln, val) > 0)
2441				perm |= NFSAUTH_RO;
2442			break;
2443
2444		case OPT_RW:
2445			list++;
2446			if (val != NULL)
2447				rw_val++;
2448			if (in_access_list(cln, val) > 0)
2449				perm |= NFSAUTH_RW;
2450			break;
2451
2452		case OPT_ROOT:
2453			/*
2454			 * Check if the client is in
2455			 * the root list. Only valid
2456			 * for AUTH_SYS.
2457			 */
2458			if (flavor != AUTH_SYS)
2459				break;
2460
2461			if (val == NULL || *val == '\0')
2462				break;
2463
2464			if (clnt_uid != 0)
2465				break;
2466
2467			if (in_access_list(cln, val) > 0) {
2468				perm |= NFSAUTH_ROOT;
2469				perm |= NFSAUTH_UIDMAP | NFSAUTH_GIDMAP;
2470				map_deny = B_FALSE;
2471
2472				if (perm & NFSAUTH_GROUPS) {
2473					free(*srv_gids);
2474					*srv_ngids = 0;
2475					*srv_gids = NULL;
2476					perm &= ~NFSAUTH_GROUPS;
2477				}
2478			}
2479			break;
2480
2481		case OPT_NONE:
2482			/*
2483			 * Check if the client should have no access
2484			 * to this share at all. This option behaves
2485			 * more like "root" than either "rw" or "ro".
2486			 */
2487			if (in_access_list(cln, val) > 0)
2488				perm |= NFSAUTH_DENIED;
2489			break;
2490
2491		case OPT_UIDMAP: {
2492			char *c;
2493			char *n;
2494
2495			/*
2496			 * The uidmap is supported for AUTH_SYS only.
2497			 */
2498			if (flavor != AUTH_SYS)
2499				break;
2500
2501			if (perm & NFSAUTH_UIDMAP || map_deny)
2502				break;
2503
2504			for (c = val; c != NULL; c = n) {
2505				char *s;
2506				char *al;
2507				uid_t srv;
2508
2509				n = strchr(c, '~');
2510				if (n != NULL)
2511					*n++ = '\0';
2512
2513				s = strchr(c, ':');
2514				if (s != NULL) {
2515					*s++ = '\0';
2516					al = strchr(s, ':');
2517					if (al != NULL)
2518						*al++ = '\0';
2519				}
2520
2521				if (s == NULL || al == NULL)
2522					continue;
2523
2524				if (*c == '\0') {
2525					if (clnt_uid != (uid_t)-1)
2526						continue;
2527				} else if (strcmp(c, "*") != 0) {
2528					uid_t clnt;
2529
2530					if (!get_uid(c, &clnt))
2531						continue;
2532
2533					if (clnt_uid != clnt)
2534						continue;
2535				}
2536
2537				if (*s == '\0')
2538					srv = UID_NOBODY;
2539				else if (!get_uid(s, &srv))
2540					continue;
2541				else if (srv == (uid_t)-1) {
2542					map_deny = B_TRUE;
2543					break;
2544				}
2545
2546				if (in_access_list(cln, al) > 0) {
2547					*srv_uid = srv;
2548					perm |= NFSAUTH_UIDMAP;
2549
2550					if (perm & NFSAUTH_GROUPS) {
2551						free(*srv_gids);
2552						*srv_ngids = 0;
2553						*srv_gids = NULL;
2554						perm &= ~NFSAUTH_GROUPS;
2555					}
2556
2557					break;
2558				}
2559			}
2560
2561			break;
2562		}
2563
2564		case OPT_GIDMAP: {
2565			char *c;
2566			char *n;
2567
2568			/*
2569			 * The gidmap is supported for AUTH_SYS only.
2570			 */
2571			if (flavor != AUTH_SYS)
2572				break;
2573
2574			if (perm & NFSAUTH_GIDMAP || map_deny)
2575				break;
2576
2577			for (c = val; c != NULL; c = n) {
2578				char *s;
2579				char *al;
2580				gid_t srv;
2581
2582				n = strchr(c, '~');
2583				if (n != NULL)
2584					*n++ = '\0';
2585
2586				s = strchr(c, ':');
2587				if (s != NULL) {
2588					*s++ = '\0';
2589					al = strchr(s, ':');
2590					if (al != NULL)
2591						*al++ = '\0';
2592				}
2593
2594				if (s == NULL || al == NULL)
2595					break;
2596
2597				if (*c == '\0') {
2598					if (clnt_gid != (gid_t)-1)
2599						continue;
2600				} else if (strcmp(c, "*") != 0) {
2601					gid_t clnt;
2602
2603					if (!get_gid(c, &clnt))
2604						continue;
2605
2606					if (clnt_gid != clnt)
2607						continue;
2608				}
2609
2610				if (*s == '\0')
2611					srv = UID_NOBODY;
2612				else if (!get_gid(s, &srv))
2613					continue;
2614				else if (srv == (gid_t)-1) {
2615					map_deny = B_TRUE;
2616					break;
2617				}
2618
2619				if (in_access_list(cln, al) > 0) {
2620					*srv_gid = srv;
2621					perm |= NFSAUTH_GIDMAP;
2622
2623					if (perm & NFSAUTH_GROUPS) {
2624						free(*srv_gids);
2625						*srv_ngids = 0;
2626						*srv_gids = NULL;
2627						perm &= ~NFSAUTH_GROUPS;
2628					}
2629
2630					break;
2631				}
2632			}
2633
2634			break;
2635		}
2636
2637		default:
2638			break;
2639		}
2640	}
2641
2642	free(opts);
2643
2644	if (perm & NFSAUTH_ROOT) {
2645		*srv_uid = 0;
2646		*srv_gid = 0;
2647	}
2648
2649	if (map_deny)
2650		perm |= NFSAUTH_DENIED;
2651
2652	if (!(perm & NFSAUTH_UIDMAP))
2653		*srv_uid = clnt_uid;
2654	if (!(perm & NFSAUTH_GIDMAP))
2655		*srv_gid = clnt_gid;
2656
2657	if (flavor != match || perm & NFSAUTH_DENIED)
2658		return (NFSAUTH_DENIED);
2659
2660	if (list) {
2661		/*
2662		 * If the client doesn't match an "ro" or "rw"
2663		 * list then set no access.
2664		 */
2665		if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0)
2666			perm |= NFSAUTH_DENIED;
2667	} else {
2668		/*
2669		 * The client matched a flavor entry that
2670		 * has no explicit "rw" or "ro" determination.
2671		 * Default it to "rw".
2672		 */
2673		perm |= NFSAUTH_RW;
2674	}
2675
2676	/*
2677	 * The client may show up in both ro= and rw=
2678	 * lists.  If so, then turn off the RO access
2679	 * bit leaving RW access.
2680	 */
2681	if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) {
2682		/*
2683		 * Logically cover all permutations of rw=,ro=.
2684		 * In the case where, rw,ro=<host> we would like
2685		 * to remove RW access for the host.  In all other cases
2686		 * RW wins the precedence battle.
2687		 */
2688		if (!rw_val && ro_val) {
2689			perm &= ~(NFSAUTH_RW);
2690		} else {
2691			perm &= ~(NFSAUTH_RO);
2692		}
2693	}
2694
2695	return (perm);
2696}
2697
2698/*
2699 * Check if the client has access by using a flavor different from
2700 * the given "flavor". If "flavor" is not in the flavor list,
2701 * return TRUE to indicate that this "flavor" is a wrong sec.
2702 */
2703static bool_t
2704is_wrongsec(share_t *sh, struct cln *cln, int flavor)
2705{
2706	int flavor_list[MAX_FLAVORS];
2707	int flavor_count, i;
2708
2709	/* get the flavor list that the client has access with */
2710	flavor_count = getclientsflavors_new(sh, cln, flavor_list);
2711
2712	if (flavor_count == 0)
2713		return (FALSE);
2714
2715	/*
2716	 * Check if the given "flavor" is in the flavor_list.
2717	 */
2718	for (i = 0; i < flavor_count; i++) {
2719		if (flavor == flavor_list[i])
2720			return (FALSE);
2721	}
2722
2723	/*
2724	 * If "flavor" is not in the flavor_list, return TRUE to indicate
2725	 * that the client should have access by using a security flavor
2726	 * different from this "flavor".
2727	 */
2728	return (TRUE);
2729}
2730
2731/*
2732 * Given an export and the client's hostname, we
2733 * check the security options to see whether the
2734 * client is allowed to use the given security flavor.
2735 *
2736 * The strategy is to proceed through the options looking
2737 * for a flavor match, then pay attention to the ro, rw,
2738 * and root options.
2739 *
2740 * Note that an entry may list several flavors in a
2741 * single entry, e.g.
2742 *
2743 *   sec=krb5,rw=clnt1:clnt2,ro,sec=sys,ro
2744 *
2745 */
2746
2747static int
2748check_client_new(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
2749    gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
2750    gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
2751{
2752	char *opts, *p, *val;
2753	char *lasts;
2754	char *f;
2755	int match = 0;	/* Set when a flavor is matched */
2756	int perm = 0;	/* Set when "ro", "rw" or "root" is matched */
2757	int list = 0;	/* Set when "ro", "rw" is found */
2758	int ro_val = 0;	/* Set if ro option is 'ro=' */
2759	int rw_val = 0;	/* Set if rw option is 'rw=' */
2760
2761	boolean_t map_deny = B_FALSE;
2762
2763	opts = strdup(sh->sh_opts);
2764	if (opts == NULL) {
2765		syslog(LOG_ERR, "check_client: no memory");
2766		return (0);
2767	}
2768
2769	/*
2770	 * If client provided 16 supplemental groups with AUTH_SYS, lookup
2771	 * locally for all of them
2772	 */
2773	if (flavor == AUTH_SYS && clnt_ngids == NGRPS && ngroups_max > NGRPS)
2774		if (getusergroups(clnt_uid, srv_ngids, srv_gids) == 0)
2775			perm |= NFSAUTH_GROUPS;
2776
2777	p = opts;
2778
2779	while (*p) {
2780		switch (getsubopt(&p, optlist, &val)) {
2781
2782		case OPT_SEC:
2783			if (match)
2784				goto done;
2785
2786			while ((f = strtok_r(val, ":", &lasts))
2787			    != NULL) {
2788				if (flavor == map_flavor(f)) {
2789					match = 1;
2790					break;
2791				}
2792				val = NULL;
2793			}
2794			break;
2795
2796		case OPT_RO:
2797			if (!match)
2798				break;
2799
2800			list++;
2801			if (val != NULL)
2802				ro_val++;
2803			if (in_access_list(cln, val) > 0)
2804				perm |= NFSAUTH_RO;
2805			break;
2806
2807		case OPT_RW:
2808			if (!match)
2809				break;
2810
2811			list++;
2812			if (val != NULL)
2813				rw_val++;
2814			if (in_access_list(cln, val) > 0)
2815				perm |= NFSAUTH_RW;
2816			break;
2817
2818		case OPT_ROOT:
2819			/*
2820			 * Check if the client is in
2821			 * the root list. Only valid
2822			 * for AUTH_SYS.
2823			 */
2824			if (flavor != AUTH_SYS)
2825				break;
2826
2827			if (!match)
2828				break;
2829
2830			if (val == NULL || *val == '\0')
2831				break;
2832
2833			if (clnt_uid != 0)
2834				break;
2835
2836			if (in_access_list(cln, val) > 0) {
2837				perm |= NFSAUTH_ROOT;
2838				perm |= NFSAUTH_UIDMAP | NFSAUTH_GIDMAP;
2839				map_deny = B_FALSE;
2840
2841				if (perm & NFSAUTH_GROUPS) {
2842					free(*srv_gids);
2843					*srv_gids = NULL;
2844					*srv_ngids = 0;
2845					perm &= ~NFSAUTH_GROUPS;
2846				}
2847			}
2848			break;
2849
2850		case OPT_NONE:
2851			/*
2852			 * Check if the client should have no access
2853			 * to this share at all. This option behaves
2854			 * more like "root" than either "rw" or "ro".
2855			 */
2856			if (in_access_list(cln, val) > 0)
2857				perm |= NFSAUTH_DENIED;
2858			break;
2859
2860		case OPT_UIDMAP: {
2861			char *c;
2862			char *n;
2863
2864			/*
2865			 * The uidmap is supported for AUTH_SYS only.
2866			 */
2867			if (flavor != AUTH_SYS)
2868				break;
2869
2870			if (!match || perm & NFSAUTH_UIDMAP || map_deny)
2871				break;
2872
2873			for (c = val; c != NULL; c = n) {
2874				char *s;
2875				char *al;
2876				uid_t srv;
2877
2878				n = strchr(c, '~');
2879				if (n != NULL)
2880					*n++ = '\0';
2881
2882				s = strchr(c, ':');
2883				if (s != NULL) {
2884					*s++ = '\0';
2885					al = strchr(s, ':');
2886					if (al != NULL)
2887						*al++ = '\0';
2888				}
2889
2890				if (s == NULL || al == NULL)
2891					continue;
2892
2893				if (*c == '\0') {
2894					if (clnt_uid != (uid_t)-1)
2895						continue;
2896				} else if (strcmp(c, "*") != 0) {
2897					uid_t clnt;
2898
2899					if (!get_uid(c, &clnt))
2900						continue;
2901
2902					if (clnt_uid != clnt)
2903						continue;
2904				}
2905
2906				if (*s == '\0')
2907					srv = UID_NOBODY;
2908				else if (!get_uid(s, &srv))
2909					continue;
2910				else if (srv == (uid_t)-1) {
2911					map_deny = B_TRUE;
2912					break;
2913				}
2914
2915				if (in_access_list(cln, al) > 0) {
2916					*srv_uid = srv;
2917					perm |= NFSAUTH_UIDMAP;
2918
2919					if (perm & NFSAUTH_GROUPS) {
2920						free(*srv_gids);
2921						*srv_gids = NULL;
2922						*srv_ngids = 0;
2923						perm &= ~NFSAUTH_GROUPS;
2924					}
2925
2926					break;
2927				}
2928			}
2929
2930			break;
2931		}
2932
2933		case OPT_GIDMAP: {
2934			char *c;
2935			char *n;
2936
2937			/*
2938			 * The gidmap is supported for AUTH_SYS only.
2939			 */
2940			if (flavor != AUTH_SYS)
2941				break;
2942
2943			if (!match || perm & NFSAUTH_GIDMAP || map_deny)
2944				break;
2945
2946			for (c = val; c != NULL; c = n) {
2947				char *s;
2948				char *al;
2949				gid_t srv;
2950
2951				n = strchr(c, '~');
2952				if (n != NULL)
2953					*n++ = '\0';
2954
2955				s = strchr(c, ':');
2956				if (s != NULL) {
2957					*s++ = '\0';
2958					al = strchr(s, ':');
2959					if (al != NULL)
2960						*al++ = '\0';
2961				}
2962
2963				if (s == NULL || al == NULL)
2964					break;
2965
2966				if (*c == '\0') {
2967					if (clnt_gid != (gid_t)-1)
2968						continue;
2969				} else if (strcmp(c, "*") != 0) {
2970					gid_t clnt;
2971
2972					if (!get_gid(c, &clnt))
2973						continue;
2974
2975					if (clnt_gid != clnt)
2976						continue;
2977				}
2978
2979				if (*s == '\0')
2980					srv = UID_NOBODY;
2981				else if (!get_gid(s, &srv))
2982					continue;
2983				else if (srv == (gid_t)-1) {
2984					map_deny = B_TRUE;
2985					break;
2986				}
2987
2988				if (in_access_list(cln, al) > 0) {
2989					*srv_gid = srv;
2990					perm |= NFSAUTH_GIDMAP;
2991
2992					if (perm & NFSAUTH_GROUPS) {
2993						free(*srv_gids);
2994						*srv_gids = NULL;
2995						*srv_ngids = 0;
2996						perm &= ~NFSAUTH_GROUPS;
2997					}
2998
2999					break;
3000				}
3001			}
3002
3003			break;
3004		}
3005
3006		default:
3007			break;
3008		}
3009	}
3010
3011done:
3012	if (perm & NFSAUTH_ROOT) {
3013		*srv_uid = 0;
3014		*srv_gid = 0;
3015	}
3016
3017	if (map_deny)
3018		perm |= NFSAUTH_DENIED;
3019
3020	if (!(perm & NFSAUTH_UIDMAP))
3021		*srv_uid = clnt_uid;
3022	if (!(perm & NFSAUTH_GIDMAP))
3023		*srv_gid = clnt_gid;
3024
3025	/*
3026	 * If no match then set the perm accordingly
3027	 */
3028	if (!match || perm & NFSAUTH_DENIED) {
3029		free(opts);
3030		return (NFSAUTH_DENIED);
3031	}
3032
3033	if (list) {
3034		/*
3035		 * If the client doesn't match an "ro" or "rw" list then
3036		 * check if it may have access by using a different flavor.
3037		 * If so, return NFSAUTH_WRONGSEC.
3038		 * If not, return NFSAUTH_DENIED.
3039		 */
3040		if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) {
3041			if (is_wrongsec(sh, cln, flavor))
3042				perm |= NFSAUTH_WRONGSEC;
3043			else
3044				perm |= NFSAUTH_DENIED;
3045		}
3046	} else {
3047		/*
3048		 * The client matched a flavor entry that
3049		 * has no explicit "rw" or "ro" determination.
3050		 * Make sure it defaults to "rw".
3051		 */
3052		perm |= NFSAUTH_RW;
3053	}
3054
3055	/*
3056	 * The client may show up in both ro= and rw=
3057	 * lists.  If so, then turn off the RO access
3058	 * bit leaving RW access.
3059	 */
3060	if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) {
3061		/*
3062		 * Logically cover all permutations of rw=,ro=.
3063		 * In the case where, rw,ro=<host> we would like
3064		 * to remove RW access for the host.  In all other cases
3065		 * RW wins the precedence battle.
3066		 */
3067		if (!rw_val && ro_val) {
3068			perm &= ~(NFSAUTH_RW);
3069		} else {
3070			perm &= ~(NFSAUTH_RO);
3071		}
3072	}
3073
3074	free(opts);
3075
3076	return (perm);
3077}
3078
3079void
3080check_sharetab()
3081{
3082	FILE *f;
3083	struct stat st;
3084	static timestruc_t last_sharetab_time;
3085	timestruc_t prev_sharetab_time;
3086	share_t *sh;
3087	struct sh_list *shp, *shp_prev;
3088	int res, c = 0;
3089
3090	/*
3091	 *  read in /etc/dfs/sharetab if it has changed
3092	 */
3093	if (stat(SHARETAB, &st) != 0) {
3094		syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB);
3095		return;
3096	}
3097
3098	if (st.st_mtim.tv_sec == last_sharetab_time.tv_sec &&
3099	    st.st_mtim.tv_nsec == last_sharetab_time.tv_nsec) {
3100		/*
3101		 * No change.
3102		 */
3103		return;
3104	}
3105
3106	/*
3107	 * Remember the mod time, then after getting the
3108	 * write lock check again.  If another thread
3109	 * already did the update, then there's no
3110	 * work to do.
3111	 */
3112	prev_sharetab_time = last_sharetab_time;
3113
3114	(void) rw_wrlock(&sharetab_lock);
3115
3116	if (prev_sharetab_time.tv_sec != last_sharetab_time.tv_sec ||
3117	    prev_sharetab_time.tv_nsec != last_sharetab_time.tv_nsec) {
3118		(void) rw_unlock(&sharetab_lock);
3119		return;
3120	}
3121
3122	/*
3123	 * Note that since the sharetab is now in memory
3124	 * and a snapshot is taken, we no longer have to
3125	 * lock the file.
3126	 */
3127	f = fopen(SHARETAB, "r");
3128	if (f == NULL) {
3129		syslog(LOG_ERR, "Cannot open %s: %m", SHARETAB);
3130		(void) rw_unlock(&sharetab_lock);
3131		return;
3132	}
3133
3134	/*
3135	 * Once we are sure /etc/dfs/sharetab has been
3136	 * modified, flush netgroup cache entries.
3137	 */
3138	netgrp_cache_flush();
3139
3140	sh_free(share_list);			/* free old list */
3141	share_list = NULL;
3142
3143	while ((res = getshare(f, &sh)) > 0) {
3144		c++;
3145		if (strcmp(sh->sh_fstype, "nfs") != 0)
3146			continue;
3147
3148		shp = malloc(sizeof (*shp));
3149		if (shp == NULL)
3150			goto alloc_failed;
3151		if (share_list == NULL)
3152			share_list = shp;
3153		else
3154			/* LINTED not used before set */
3155			shp_prev->shl_next = shp;
3156		shp_prev = shp;
3157		shp->shl_next = NULL;
3158		shp->shl_sh = sharedup(sh);
3159		if (shp->shl_sh == NULL)
3160			goto alloc_failed;
3161	}
3162
3163	if (res < 0)
3164		syslog(LOG_ERR, "%s: invalid at line %d\n",
3165		    SHARETAB, c + 1);
3166
3167	if (stat(SHARETAB, &st) != 0) {
3168		syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB);
3169		(void) fclose(f);
3170		(void) rw_unlock(&sharetab_lock);
3171		return;
3172	}
3173
3174	last_sharetab_time = st.st_mtim;
3175	(void) fclose(f);
3176	(void) rw_unlock(&sharetab_lock);
3177
3178	return;
3179
3180alloc_failed:
3181
3182	syslog(LOG_ERR, "check_sharetab: no memory");
3183	sh_free(share_list);
3184	share_list = NULL;
3185	(void) fclose(f);
3186	(void) rw_unlock(&sharetab_lock);
3187}
3188
3189static void
3190sh_free(struct sh_list *shp)
3191{
3192	struct sh_list *next;
3193
3194	while (shp) {
3195		sharefree(shp->shl_sh);
3196		next = shp->shl_next;
3197		free(shp);
3198		shp = next;
3199	}
3200}
3201
3202
3203/*
3204 * Remove an entry from mounted list
3205 */
3206static void
3207umount(struct svc_req *rqstp)
3208{
3209	char *host, *path, *remove_path;
3210	char rpath[MAXPATHLEN];
3211	SVCXPRT *transp;
3212	struct cln cln;
3213
3214	transp = rqstp->rq_xprt;
3215	path = NULL;
3216	if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
3217		svcerr_decode(transp);
3218		return;
3219	}
3220
3221	cln_init(&cln, transp);
3222
3223	errno = 0;
3224	if (!svc_sendreply(transp, xdr_void, (char *)NULL))
3225		log_cant_reply_cln(&cln);
3226
3227	host = cln_gethost(&cln);
3228	if (host == NULL) {
3229		/*
3230		 * Without the hostname we can't do audit or delete
3231		 * this host from the mount entries.
3232		 */
3233		svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
3234		return;
3235	}
3236
3237	if (verbose)
3238		syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path);
3239
3240	audit_mountd_umount(host, path);
3241
3242	remove_path = rpath;	/* assume we will use the cannonical path */
3243	if (realpath(path, rpath) == NULL) {
3244		if (verbose)
3245			syslog(LOG_WARNING, "UNMOUNT: realpath: %s: %m ", path);
3246		remove_path = path;	/* use path provided instead */
3247	}
3248
3249	mntlist_delete(host, remove_path);	/* remove from mount list */
3250
3251	cln_fini(&cln);
3252
3253	svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
3254}
3255
3256/*
3257 * Remove all entries for one machine from mounted list
3258 */
3259static void
3260umountall(struct svc_req *rqstp)
3261{
3262	SVCXPRT *transp;
3263	char *host;
3264	struct cln cln;
3265
3266	transp = rqstp->rq_xprt;
3267	if (!svc_getargs(transp, xdr_void, NULL)) {
3268		svcerr_decode(transp);
3269		return;
3270	}
3271	/*
3272	 * We assume that this call is asynchronous and made via rpcbind
3273	 * callit routine.  Therefore return control immediately. The error
3274	 * causes rpcbind to remain silent, as opposed to every machine
3275	 * on the net blasting the requester with a response.
3276	 */
3277	svcerr_systemerr(transp);
3278
3279	cln_init(&cln, transp);
3280
3281	host = cln_gethost(&cln);
3282	if (host == NULL) {
3283		/* Can't do anything without the name of the client */
3284		return;
3285	}
3286
3287	/*
3288	 * Remove all hosts entries from mount list
3289	 */
3290	mntlist_delete_all(host);
3291
3292	if (verbose)
3293		syslog(LOG_NOTICE, "UNMOUNTALL: from %s", host);
3294
3295	cln_fini(&cln);
3296}
3297
3298void *
3299exmalloc(size_t size)
3300{
3301	void *ret;
3302
3303	if ((ret = malloc(size)) == NULL) {
3304		syslog(LOG_ERR, "Out of memory");
3305		exit(1);
3306	}
3307	return (ret);
3308}
3309
3310static tsol_tpent_t *
3311get_client_template(struct sockaddr *sock)
3312{
3313	in_addr_t	v4client;
3314	in6_addr_t	v6client;
3315	char		v4_addr[INET_ADDRSTRLEN];
3316	char		v6_addr[INET6_ADDRSTRLEN];
3317	tsol_rhent_t	*rh;
3318	tsol_tpent_t	*tp;
3319
3320	switch (sock->sa_family) {
3321	case AF_INET:
3322		v4client = ((struct sockaddr_in *)(void *)sock)->
3323		    sin_addr.s_addr;
3324		if (inet_ntop(AF_INET, &v4client, v4_addr, INET_ADDRSTRLEN) ==
3325		    NULL)
3326			return (NULL);
3327		rh = tsol_getrhbyaddr(v4_addr, sizeof (v4_addr), AF_INET);
3328		if (rh == NULL)
3329			return (NULL);
3330		tp = tsol_gettpbyname(rh->rh_template);
3331		tsol_freerhent(rh);
3332		return (tp);
3333		break;
3334	case AF_INET6:
3335		v6client = ((struct sockaddr_in6 *)(void *)sock)->sin6_addr;
3336		if (inet_ntop(AF_INET6, &v6client, v6_addr, INET6_ADDRSTRLEN) ==
3337		    NULL)
3338			return (NULL);
3339		rh = tsol_getrhbyaddr(v6_addr, sizeof (v6_addr), AF_INET6);
3340		if (rh == NULL)
3341			return (NULL);
3342		tp = tsol_gettpbyname(rh->rh_template);
3343		tsol_freerhent(rh);
3344		return (tp);
3345		break;
3346	default:
3347		return (NULL);
3348	}
3349}
3350