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