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