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