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