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