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