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