Home | History | Annotate | Download | only in mountd
      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