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