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