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