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