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