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