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