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