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