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