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