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