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