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