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