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