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