xref: /onnv-gate/usr/src/cmd/fs.d/nfs/mountd/mountd.c (revision 11211:a6230133d60c)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51610Sthurlow  * Common Development and Distribution License (the "License").
61610Sthurlow  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
213957Sth199096 
220Sstevel@tonic-gate /*
23*11211SThomas.Haynes@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
280Sstevel@tonic-gate /*	  All Rights Reserved  	*/
290Sstevel@tonic-gate 
300Sstevel@tonic-gate /*
310Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley 4.3 BSD
320Sstevel@tonic-gate  * under license from the Regents of the University of California.
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include <stdio.h>
360Sstevel@tonic-gate #include <stdlib.h>
370Sstevel@tonic-gate #include <ctype.h>
380Sstevel@tonic-gate #include <sys/types.h>
390Sstevel@tonic-gate #include <string.h>
400Sstevel@tonic-gate #include <syslog.h>
410Sstevel@tonic-gate #include <sys/param.h>
420Sstevel@tonic-gate #include <rpc/rpc.h>
430Sstevel@tonic-gate #include <sys/stat.h>
440Sstevel@tonic-gate #include <netconfig.h>
450Sstevel@tonic-gate #include <netdir.h>
460Sstevel@tonic-gate #include <sys/file.h>
470Sstevel@tonic-gate #include <sys/time.h>
480Sstevel@tonic-gate #include <sys/errno.h>
490Sstevel@tonic-gate #include <rpcsvc/mount.h>
500Sstevel@tonic-gate #include <sys/pathconf.h>
510Sstevel@tonic-gate #include <sys/systeminfo.h>
520Sstevel@tonic-gate #include <sys/utsname.h>
536859Sth199096 #include <sys/wait.h>
540Sstevel@tonic-gate #include <signal.h>
550Sstevel@tonic-gate #include <locale.h>
560Sstevel@tonic-gate #include <unistd.h>
570Sstevel@tonic-gate #include <errno.h>
580Sstevel@tonic-gate #include <sys/socket.h>
590Sstevel@tonic-gate #include <netinet/in.h>
600Sstevel@tonic-gate #include <arpa/inet.h>
610Sstevel@tonic-gate #include <netdb.h>
620Sstevel@tonic-gate #include <thread.h>
630Sstevel@tonic-gate #include <assert.h>
640Sstevel@tonic-gate #include <priv_utils.h>
652140Srmesta #include <nfs/auth.h>
662140Srmesta #include <nfs/nfssys.h>
670Sstevel@tonic-gate #include <nfs/nfs.h>
680Sstevel@tonic-gate #include <nfs/nfs_sec.h>
690Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h>
700Sstevel@tonic-gate #include <deflt.h>
710Sstevel@tonic-gate #include "../../fslib.h"
723957Sth199096 #include <sharefs/share.h>
733957Sth199096 #include <sharefs/sharetab.h>
740Sstevel@tonic-gate #include "../lib/sharetab.h"
750Sstevel@tonic-gate #include "mountd.h"
764971Sjarrett #include <tsol/label.h>
774971Sjarrett #include <sys/tsol/label_macro.h>
784971Sjarrett #include <libtsnet.h>
79*11211SThomas.Haynes@Sun.COM #include <sys/sdt.h>
800Sstevel@tonic-gate 
816859Sth199096 extern int daemonize_init(void);
826859Sth199096 extern void daemonize_fini(int fd);
836859Sth199096 
840Sstevel@tonic-gate struct sh_list *share_list;
850Sstevel@tonic-gate 
860Sstevel@tonic-gate rwlock_t sharetab_lock;		/* lock to protect the cached sharetab */
870Sstevel@tonic-gate static mutex_t mnttab_lock;	/* prevent concurrent mnttab readers */
880Sstevel@tonic-gate 
89*11211SThomas.Haynes@Sun.COM static mutex_t logging_queue_lock;
90*11211SThomas.Haynes@Sun.COM static cond_t logging_queue_cv;
91*11211SThomas.Haynes@Sun.COM 
92*11211SThomas.Haynes@Sun.COM static share_t *find_lofsentry(char *, int *);
93*11211SThomas.Haynes@Sun.COM static void getclientsnames_lazy(char *, struct netbuf **,
94*11211SThomas.Haynes@Sun.COM 	struct nd_hostservlist **);
950Sstevel@tonic-gate static void getclientsnames(SVCXPRT *, struct netbuf **,
96*11211SThomas.Haynes@Sun.COM 	struct nd_hostservlist **);
97*11211SThomas.Haynes@Sun.COM static int getclientsflavors_old(share_t *, SVCXPRT *, struct netbuf **,
98*11211SThomas.Haynes@Sun.COM 	struct nd_hostservlist **, int *);
99*11211SThomas.Haynes@Sun.COM static int getclientsflavors_new(share_t *, SVCXPRT *, struct netbuf **,
100*11211SThomas.Haynes@Sun.COM 	struct nd_hostservlist **, int *);
101*11211SThomas.Haynes@Sun.COM static int check_client_old(share_t *, SVCXPRT *, struct netbuf **,
102*11211SThomas.Haynes@Sun.COM 	struct nd_hostservlist **, int);
103*11211SThomas.Haynes@Sun.COM static int check_client_new(share_t *, SVCXPRT *, struct netbuf **,
104*11211SThomas.Haynes@Sun.COM 	struct nd_hostservlist **, int);
1050Sstevel@tonic-gate static void mnt(struct svc_req *, SVCXPRT *);
1060Sstevel@tonic-gate static void mnt_pathconf(struct svc_req *);
107*11211SThomas.Haynes@Sun.COM static int mount(struct svc_req *r);
1080Sstevel@tonic-gate static void sh_free(struct sh_list *);
1090Sstevel@tonic-gate static void umount(struct svc_req *);
1100Sstevel@tonic-gate static void umountall(struct svc_req *);
1110Sstevel@tonic-gate static int netmatch(struct netbuf *, char *);
1120Sstevel@tonic-gate static void sigexit(int);
1130Sstevel@tonic-gate static int newopts(char *);
1144971Sjarrett static tsol_tpent_t *get_client_template(struct sockaddr *);
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate static int verbose;
1170Sstevel@tonic-gate static int rejecting;
1180Sstevel@tonic-gate static int mount_vers_min = MOUNTVERS;
1190Sstevel@tonic-gate static int mount_vers_max = MOUNTVERS3;
1200Sstevel@tonic-gate 
1217961SNatalie.Li@Sun.COM /* Needs to be accessed by nfscmd.c */
122*11211SThomas.Haynes@Sun.COM int  in_access_list(SVCXPRT *, struct netbuf **,
123*11211SThomas.Haynes@Sun.COM 	struct nd_hostservlist **, char *);
1247961SNatalie.Li@Sun.COM 
1257961SNatalie.Li@Sun.COM extern void nfscmd_func(void *, char *, size_t, door_desc_t *, uint_t);
1267961SNatalie.Li@Sun.COM 
1272140Srmesta thread_t	nfsauth_thread;
1287961SNatalie.Li@Sun.COM thread_t	cmd_thread;
129*11211SThomas.Haynes@Sun.COM thread_t	logging_thread;
130*11211SThomas.Haynes@Sun.COM 
131*11211SThomas.Haynes@Sun.COM typedef struct logging_data {
132*11211SThomas.Haynes@Sun.COM 	char			*ld_host;
133*11211SThomas.Haynes@Sun.COM 	char			*ld_path;
134*11211SThomas.Haynes@Sun.COM 	char			*ld_rpath;
135*11211SThomas.Haynes@Sun.COM 	int			ld_status;
136*11211SThomas.Haynes@Sun.COM 	char			*ld_netid;
137*11211SThomas.Haynes@Sun.COM 	struct netbuf		*ld_nb;
138*11211SThomas.Haynes@Sun.COM 	struct logging_data	*ld_next;
139*11211SThomas.Haynes@Sun.COM } logging_data;
140*11211SThomas.Haynes@Sun.COM 
141*11211SThomas.Haynes@Sun.COM static logging_data *logging_head = NULL;
142*11211SThomas.Haynes@Sun.COM static logging_data *logging_tail = NULL;
1432140Srmesta 
1442140Srmesta /* ARGSUSED */
1452140Srmesta static void *
1462140Srmesta nfsauth_svc(void *arg)
1472140Srmesta {
1482140Srmesta 	int	doorfd = -1;
1492140Srmesta 	uint_t	darg;
1502140Srmesta #ifdef DEBUG
1512140Srmesta 	int	dfd;
1522140Srmesta #endif
1532140Srmesta 
1542140Srmesta 	if ((doorfd = door_create(nfsauth_func, NULL,
1552140Srmesta 	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
1562140Srmesta 		syslog(LOG_ERR, "Unable to create door: %m\n");
1572140Srmesta 		exit(10);
1582140Srmesta 	}
1592140Srmesta 
1602140Srmesta #ifdef DEBUG
1612140Srmesta 	/*
1622140Srmesta 	 * Create a file system path for the door
1632140Srmesta 	 */
1642140Srmesta 	if ((dfd = open(MOUNTD_DOOR, O_RDWR|O_CREAT|O_TRUNC,
1652140Srmesta 	    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) {
1662140Srmesta 		syslog(LOG_ERR, "Unable to open %s: %m\n", MOUNTD_DOOR);
1672140Srmesta 		(void) close(doorfd);
1682140Srmesta 		exit(11);
1692140Srmesta 	}
1702140Srmesta 
1712140Srmesta 	/*
1722140Srmesta 	 * Clean up any stale namespace associations
1732140Srmesta 	 */
1742140Srmesta 	(void) fdetach(MOUNTD_DOOR);
1752140Srmesta 
1762140Srmesta 	/*
1772140Srmesta 	 * Register in namespace to pass to the kernel to door_ki_open
1782140Srmesta 	 */
1792140Srmesta 	if (fattach(doorfd, MOUNTD_DOOR) == -1) {
1802140Srmesta 		syslog(LOG_ERR, "Unable to fattach door: %m\n");
1812140Srmesta 		(void) close(dfd);
1822140Srmesta 		(void) close(doorfd);
1832140Srmesta 		exit(12);
1842140Srmesta 	}
1852140Srmesta 	(void) close(dfd);
1862140Srmesta #endif
1872140Srmesta 
1882140Srmesta 	/*
1892140Srmesta 	 * Must pass the doorfd down to the kernel.
1902140Srmesta 	 */
1912140Srmesta 	darg = doorfd;
1922140Srmesta 	(void) _nfssys(MOUNTD_ARGS, &darg);
1932140Srmesta 
1942140Srmesta 	/*
1952140Srmesta 	 * Wait for incoming calls
1962140Srmesta 	 */
1972140Srmesta 	/*CONSTCOND*/
1982140Srmesta 	for (;;)
1992140Srmesta 		(void) pause();
2002140Srmesta 
2012140Srmesta 	/*NOTREACHED*/
2022140Srmesta 	syslog(LOG_ERR, gettext("Door server exited"));
2032140Srmesta 	return (NULL);
2042140Srmesta }
2052140Srmesta 
2067961SNatalie.Li@Sun.COM /*
2077961SNatalie.Li@Sun.COM  * NFS command service thread code for setup and handling of the
2087961SNatalie.Li@Sun.COM  * nfs_cmd requests for character set conversion and other future
2097961SNatalie.Li@Sun.COM  * events.
2107961SNatalie.Li@Sun.COM  */
2117961SNatalie.Li@Sun.COM 
2127961SNatalie.Li@Sun.COM static void *
2137961SNatalie.Li@Sun.COM cmd_svc(void *arg)
2147961SNatalie.Li@Sun.COM {
2157961SNatalie.Li@Sun.COM 	int	doorfd = -1;
2167961SNatalie.Li@Sun.COM 	uint_t	darg;
2177961SNatalie.Li@Sun.COM 
2187961SNatalie.Li@Sun.COM 	if ((doorfd = door_create(nfscmd_func, NULL,
2197961SNatalie.Li@Sun.COM 	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
2207961SNatalie.Li@Sun.COM 		syslog(LOG_ERR, "Unable to create cmd door: %m\n");
2217961SNatalie.Li@Sun.COM 		exit(10);
2227961SNatalie.Li@Sun.COM 	}
2237961SNatalie.Li@Sun.COM 
2247961SNatalie.Li@Sun.COM 	/*
2257961SNatalie.Li@Sun.COM 	 * Must pass the doorfd down to the kernel.
2267961SNatalie.Li@Sun.COM 	 */
2277961SNatalie.Li@Sun.COM 	darg = doorfd;
2287961SNatalie.Li@Sun.COM 	(void) _nfssys(NFSCMD_ARGS, &darg);
2297961SNatalie.Li@Sun.COM 
2307961SNatalie.Li@Sun.COM 	/*
2317961SNatalie.Li@Sun.COM 	 * Wait for incoming calls
2327961SNatalie.Li@Sun.COM 	 */
2337961SNatalie.Li@Sun.COM 	/*CONSTCOND*/
2347961SNatalie.Li@Sun.COM 	for (;;)
2357961SNatalie.Li@Sun.COM 		(void) pause();
2367961SNatalie.Li@Sun.COM 
2377961SNatalie.Li@Sun.COM 	/*NOTREACHED*/
2387961SNatalie.Li@Sun.COM 	syslog(LOG_ERR, gettext("Cmd door server exited"));
2397961SNatalie.Li@Sun.COM 	return (NULL);
2407961SNatalie.Li@Sun.COM }
2416859Sth199096 
242*11211SThomas.Haynes@Sun.COM static void
243*11211SThomas.Haynes@Sun.COM free_logging_data(logging_data *lq)
244*11211SThomas.Haynes@Sun.COM {
245*11211SThomas.Haynes@Sun.COM 	if (lq != NULL) {
246*11211SThomas.Haynes@Sun.COM 		free(lq->ld_host);
247*11211SThomas.Haynes@Sun.COM 		free(lq->ld_netid);
248*11211SThomas.Haynes@Sun.COM 
249*11211SThomas.Haynes@Sun.COM 		if (lq->ld_nb != NULL) {
250*11211SThomas.Haynes@Sun.COM 			free(lq->ld_nb->buf);
251*11211SThomas.Haynes@Sun.COM 			free(lq->ld_nb);
252*11211SThomas.Haynes@Sun.COM 		}
253*11211SThomas.Haynes@Sun.COM 
254*11211SThomas.Haynes@Sun.COM 		free(lq->ld_path);
255*11211SThomas.Haynes@Sun.COM 		free(lq->ld_rpath);
256*11211SThomas.Haynes@Sun.COM 
257*11211SThomas.Haynes@Sun.COM 		free(lq);
258*11211SThomas.Haynes@Sun.COM 	}
259*11211SThomas.Haynes@Sun.COM }
260*11211SThomas.Haynes@Sun.COM 
261*11211SThomas.Haynes@Sun.COM static logging_data *
262*11211SThomas.Haynes@Sun.COM remove_head_of_queue(void)
263*11211SThomas.Haynes@Sun.COM {
264*11211SThomas.Haynes@Sun.COM 	logging_data    *lq;
265*11211SThomas.Haynes@Sun.COM 
266*11211SThomas.Haynes@Sun.COM 	/*
267*11211SThomas.Haynes@Sun.COM 	 * Pull it off the queue.
268*11211SThomas.Haynes@Sun.COM 	 */
269*11211SThomas.Haynes@Sun.COM 	lq = logging_head;
270*11211SThomas.Haynes@Sun.COM 	if (lq) {
271*11211SThomas.Haynes@Sun.COM 		logging_head = lq->ld_next;
272*11211SThomas.Haynes@Sun.COM 
273*11211SThomas.Haynes@Sun.COM 		/*
274*11211SThomas.Haynes@Sun.COM 		 * Drained it.
275*11211SThomas.Haynes@Sun.COM 		 */
276*11211SThomas.Haynes@Sun.COM 		if (logging_head == NULL) {
277*11211SThomas.Haynes@Sun.COM 			logging_tail = NULL;
278*11211SThomas.Haynes@Sun.COM 		}
279*11211SThomas.Haynes@Sun.COM 	}
280*11211SThomas.Haynes@Sun.COM 
281*11211SThomas.Haynes@Sun.COM 	return (lq);
282*11211SThomas.Haynes@Sun.COM }
283*11211SThomas.Haynes@Sun.COM 
284*11211SThomas.Haynes@Sun.COM static void
285*11211SThomas.Haynes@Sun.COM do_logging_queue(logging_data *lq)
286*11211SThomas.Haynes@Sun.COM {
287*11211SThomas.Haynes@Sun.COM 	logging_data	*lq_clean = NULL;
288*11211SThomas.Haynes@Sun.COM 	int		cleared = 0;
289*11211SThomas.Haynes@Sun.COM 	char		*host;
290*11211SThomas.Haynes@Sun.COM 
291*11211SThomas.Haynes@Sun.COM 	struct nd_hostservlist	*clnames;
292*11211SThomas.Haynes@Sun.COM 
293*11211SThomas.Haynes@Sun.COM 	while (lq) {
294*11211SThomas.Haynes@Sun.COM 		if (lq->ld_host == NULL) {
295*11211SThomas.Haynes@Sun.COM 			DTRACE_PROBE(mountd, name_by_lazy);
296*11211SThomas.Haynes@Sun.COM 			getclientsnames_lazy(lq->ld_netid,
297*11211SThomas.Haynes@Sun.COM 			    &lq->ld_nb, &clnames);
298*11211SThomas.Haynes@Sun.COM 			if (clnames == NULL)
299*11211SThomas.Haynes@Sun.COM 				host = NULL;
300*11211SThomas.Haynes@Sun.COM 			else
301*11211SThomas.Haynes@Sun.COM 				host = clnames->h_hostservs[0].h_host;
302*11211SThomas.Haynes@Sun.COM 		} else
303*11211SThomas.Haynes@Sun.COM 			host = lq->ld_host;
304*11211SThomas.Haynes@Sun.COM 
305*11211SThomas.Haynes@Sun.COM 		audit_mountd_mount(host, lq->ld_path, lq->ld_status); /* BSM */
306*11211SThomas.Haynes@Sun.COM 
307*11211SThomas.Haynes@Sun.COM 		/* add entry to mount list */
308*11211SThomas.Haynes@Sun.COM 		if (lq->ld_rpath)
309*11211SThomas.Haynes@Sun.COM 			mntlist_new(host, lq->ld_rpath);
310*11211SThomas.Haynes@Sun.COM 
311*11211SThomas.Haynes@Sun.COM 		lq->ld_next = lq_clean;
312*11211SThomas.Haynes@Sun.COM 		lq_clean = lq;
313*11211SThomas.Haynes@Sun.COM 
314*11211SThomas.Haynes@Sun.COM 		(void) mutex_lock(&logging_queue_lock);
315*11211SThomas.Haynes@Sun.COM 		lq = remove_head_of_queue();
316*11211SThomas.Haynes@Sun.COM 		(void) mutex_unlock(&logging_queue_lock);
317*11211SThomas.Haynes@Sun.COM 	}
318*11211SThomas.Haynes@Sun.COM 
319*11211SThomas.Haynes@Sun.COM 	while (lq_clean) {
320*11211SThomas.Haynes@Sun.COM 		lq = lq_clean;
321*11211SThomas.Haynes@Sun.COM 		lq_clean = lq->ld_next;
322*11211SThomas.Haynes@Sun.COM 
323*11211SThomas.Haynes@Sun.COM 		free_logging_data(lq);
324*11211SThomas.Haynes@Sun.COM 		cleared++;
325*11211SThomas.Haynes@Sun.COM 	}
326*11211SThomas.Haynes@Sun.COM 
327*11211SThomas.Haynes@Sun.COM 	DTRACE_PROBE1(mountd, logging_cleared, cleared);
328*11211SThomas.Haynes@Sun.COM }
329*11211SThomas.Haynes@Sun.COM 
330*11211SThomas.Haynes@Sun.COM static void *
331*11211SThomas.Haynes@Sun.COM logging_svc(void *arg)
332*11211SThomas.Haynes@Sun.COM {
333*11211SThomas.Haynes@Sun.COM 	logging_data	*lq;
334*11211SThomas.Haynes@Sun.COM 
335*11211SThomas.Haynes@Sun.COM 	for (;;) {
336*11211SThomas.Haynes@Sun.COM 		(void) mutex_lock(&logging_queue_lock);
337*11211SThomas.Haynes@Sun.COM 		while (logging_head == NULL) {
338*11211SThomas.Haynes@Sun.COM 			(void) cond_wait(&logging_queue_cv,
339*11211SThomas.Haynes@Sun.COM 			    &logging_queue_lock);
340*11211SThomas.Haynes@Sun.COM 		}
341*11211SThomas.Haynes@Sun.COM 
342*11211SThomas.Haynes@Sun.COM 		lq = remove_head_of_queue();
343*11211SThomas.Haynes@Sun.COM 		(void) mutex_unlock(&logging_queue_lock);
344*11211SThomas.Haynes@Sun.COM 
345*11211SThomas.Haynes@Sun.COM 		do_logging_queue(lq);
346*11211SThomas.Haynes@Sun.COM 	}
347*11211SThomas.Haynes@Sun.COM 
348*11211SThomas.Haynes@Sun.COM 	/*NOTREACHED*/
349*11211SThomas.Haynes@Sun.COM 	syslog(LOG_ERR, gettext("Logging server exited"));
350*11211SThomas.Haynes@Sun.COM 	return (NULL);
351*11211SThomas.Haynes@Sun.COM }
352*11211SThomas.Haynes@Sun.COM 
353249Sjwahlig int
354249Sjwahlig main(int argc, char *argv[])
3550Sstevel@tonic-gate {
3562140Srmesta 	int	pid;
3572140Srmesta 	int	c;
3582140Srmesta 	int	rpc_svc_mode = RPC_SVC_MT_AUTO;
3592140Srmesta 	int	maxthreads;
3602140Srmesta 	int	maxrecsz = RPC_MAXDATASIZE;
3612140Srmesta 	bool_t	exclbind = TRUE;
3622140Srmesta 	bool_t	can_do_mlp;
3632140Srmesta 	long	thr_flags = (THR_NEW_LWP|THR_DAEMON);
3640Sstevel@tonic-gate 
3656859Sth199096 	int	pipe_fd = -1;
3666859Sth199096 
3670Sstevel@tonic-gate 	/*
3680Sstevel@tonic-gate 	 * Mountd requires uid 0 for:
3690Sstevel@tonic-gate 	 *	/etc/rmtab updates (we could chown it to daemon)
3700Sstevel@tonic-gate 	 *	/etc/dfs/dfstab reading (it wants to lock out share which
3710Sstevel@tonic-gate 	 *		doesn't do any locking before first truncate;
3720Sstevel@tonic-gate 	 *		NFS share does; should use fcntl locking instead)
3730Sstevel@tonic-gate 	 *	Needed privileges:
3740Sstevel@tonic-gate 	 *		auditing
3750Sstevel@tonic-gate 	 *		nfs syscall
3760Sstevel@tonic-gate 	 *		file dac search (so it can stat all files)
3771676Sjpk 	 *	Optional privileges:
3781676Sjpk 	 *		MLP
3790Sstevel@tonic-gate 	 */
3801676Sjpk 	can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
3810Sstevel@tonic-gate 	if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, -1, -1,
3821676Sjpk 	    PRIV_SYS_NFS, PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH,
3831676Sjpk 	    can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
3840Sstevel@tonic-gate 		(void) fprintf(stderr,
3856859Sth199096 		    "%s: must be run with sufficient privileges\n",
3866859Sth199096 		    argv[0]);
3870Sstevel@tonic-gate 		exit(1);
3880Sstevel@tonic-gate 	}
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	maxthreads = 0;
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "vrm:")) != EOF) {
3930Sstevel@tonic-gate 		switch (c) {
3940Sstevel@tonic-gate 		case 'v':
3950Sstevel@tonic-gate 			verbose++;
3960Sstevel@tonic-gate 			break;
3970Sstevel@tonic-gate 		case 'r':
3980Sstevel@tonic-gate 			rejecting = 1;
3990Sstevel@tonic-gate 			break;
4000Sstevel@tonic-gate 		case 'm':
4010Sstevel@tonic-gate 			maxthreads = atoi(optarg);
4020Sstevel@tonic-gate 			if (maxthreads < 1) {
4030Sstevel@tonic-gate 				(void) fprintf(stderr,
4040Sstevel@tonic-gate 	"%s: must specify positive maximum threads count, using default\n",
4056859Sth199096 				    argv[0]);
4060Sstevel@tonic-gate 				maxthreads = 0;
4070Sstevel@tonic-gate 			}
4080Sstevel@tonic-gate 			break;
4090Sstevel@tonic-gate 		}
4100Sstevel@tonic-gate 	}
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	/*
4130Sstevel@tonic-gate 	 * Read in the NFS version values from config file.
4140Sstevel@tonic-gate 	 */
4150Sstevel@tonic-gate 	if ((defopen(NFSADMIN)) == 0) {
4160Sstevel@tonic-gate 		char *defval;
4170Sstevel@tonic-gate 		int defvers;
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 		if ((defval = defread("NFS_SERVER_VERSMIN=")) != NULL) {
4200Sstevel@tonic-gate 			errno = 0;
4210Sstevel@tonic-gate 			defvers = strtol(defval, (char **)NULL, 10);
4220Sstevel@tonic-gate 			if (errno == 0) {
4230Sstevel@tonic-gate 				mount_vers_min = defvers;
4240Sstevel@tonic-gate 				/*
4250Sstevel@tonic-gate 				 * special because NFSv2 is
4260Sstevel@tonic-gate 				 * supported by mount v1 & v2
4270Sstevel@tonic-gate 				 */
4280Sstevel@tonic-gate 				if (defvers == NFS_VERSION)
4290Sstevel@tonic-gate 					mount_vers_min = MOUNTVERS;
4300Sstevel@tonic-gate 			}
4310Sstevel@tonic-gate 		}
4320Sstevel@tonic-gate 		if ((defval = defread("NFS_SERVER_VERSMAX=")) != NULL) {
4330Sstevel@tonic-gate 			errno = 0;
4340Sstevel@tonic-gate 			defvers = strtol(defval, (char **)NULL, 10);
4350Sstevel@tonic-gate 			if (errno == 0) {
4360Sstevel@tonic-gate 				mount_vers_max = defvers;
4370Sstevel@tonic-gate 			}
4380Sstevel@tonic-gate 		}
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 		/* close defaults file */
4410Sstevel@tonic-gate 		defopen(NULL);
4420Sstevel@tonic-gate 	}
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	/*
4450Sstevel@tonic-gate 	 * Sanity check versions,
4460Sstevel@tonic-gate 	 * even though we may get versions > MOUNTVERS3, we still need
4470Sstevel@tonic-gate 	 * to start nfsauth service, so continue on regardless of values.
4480Sstevel@tonic-gate 	 */
4490Sstevel@tonic-gate 	if (mount_vers_min > mount_vers_max) {
4506859Sth199096 		fprintf(stderr, "NFS_SERVER_VERSMIN > NFS_SERVER_VERSMAX");
4510Sstevel@tonic-gate 		mount_vers_max = mount_vers_min;
4520Sstevel@tonic-gate 	}
4530Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
4540Sstevel@tonic-gate 	(void) rwlock_init(&sharetab_lock, USYNC_THREAD, NULL);
4550Sstevel@tonic-gate 	(void) mutex_init(&mnttab_lock, USYNC_THREAD, NULL);
456*11211SThomas.Haynes@Sun.COM 	(void) mutex_init(&logging_queue_lock, USYNC_THREAD, NULL);
457*11211SThomas.Haynes@Sun.COM 	(void) cond_init(&logging_queue_cv, USYNC_THREAD, NULL);
458*11211SThomas.Haynes@Sun.COM 
4590Sstevel@tonic-gate 	netgroup_init();
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
4620Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
4630Sstevel@tonic-gate #endif
4640Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	/* Don't drop core if the NFS module isn't loaded. */
4670Sstevel@tonic-gate 	(void) signal(SIGSYS, SIG_IGN);
4680Sstevel@tonic-gate 
4696859Sth199096 	pipe_fd = daemonize_init();
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	/*
4720Sstevel@tonic-gate 	 * If we coredump it'll be in /core
4730Sstevel@tonic-gate 	 */
4740Sstevel@tonic-gate 	if (chdir("/") < 0)
4756859Sth199096 		fprintf(stderr, "chdir /: %s", strerror(errno));
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	openlog("mountd", LOG_PID, LOG_DAEMON);
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	/*
4800Sstevel@tonic-gate 	 * establish our lock on the lock file and write our pid to it.
4810Sstevel@tonic-gate 	 * exit if some other process holds the lock, or if there's any
4820Sstevel@tonic-gate 	 * error in writing/locking the file.
4830Sstevel@tonic-gate 	 */
4840Sstevel@tonic-gate 	pid = _enter_daemon_lock(MOUNTD);
4850Sstevel@tonic-gate 	switch (pid) {
4860Sstevel@tonic-gate 	case 0:
4870Sstevel@tonic-gate 		break;
4880Sstevel@tonic-gate 	case -1:
4896859Sth199096 		fprintf(stderr, "error locking for %s: %s", MOUNTD,
4900Sstevel@tonic-gate 		    strerror(errno));
4910Sstevel@tonic-gate 		exit(2);
4920Sstevel@tonic-gate 	default:
4930Sstevel@tonic-gate 		/* daemon was already running */
4940Sstevel@tonic-gate 		exit(0);
4950Sstevel@tonic-gate 	}
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	audit_mountd_setup();	/* BSM */
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	/*
5000Sstevel@tonic-gate 	 * Tell RPC that we want automatic thread mode.
5010Sstevel@tonic-gate 	 * A new thread will be spawned for each request.
5020Sstevel@tonic-gate 	 */
5030Sstevel@tonic-gate 	if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) {
5046859Sth199096 		fprintf(stderr, "unable to set automatic MT mode");
5050Sstevel@tonic-gate 		exit(1);
5060Sstevel@tonic-gate 	}
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	/*
5090Sstevel@tonic-gate 	 * Enable non-blocking mode and maximum record size checks for
5100Sstevel@tonic-gate 	 * connection oriented transports.
5110Sstevel@tonic-gate 	 */
5120Sstevel@tonic-gate 	if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) {
5136859Sth199096 		fprintf(stderr, "unable to set RPC max record size");
5140Sstevel@tonic-gate 	}
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	/*
5170Sstevel@tonic-gate 	 * Prevent our non-priv udp and tcp ports bound w/wildcard addr
5180Sstevel@tonic-gate 	 * from being hijacked by a bind to a more specific addr.
5190Sstevel@tonic-gate 	 */
5200Sstevel@tonic-gate 	if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) {
5216859Sth199096 		fprintf(stderr, "warning: unable to set udp/tcp EXCLBIND");
5220Sstevel@tonic-gate 	}
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	/*
5250Sstevel@tonic-gate 	 * If the -m argument was specified, then set the
5260Sstevel@tonic-gate 	 * maximum number of threads to the value specified.
5270Sstevel@tonic-gate 	 */
5280Sstevel@tonic-gate 	if (maxthreads > 0 && !rpc_control(RPC_SVC_THRMAX_SET, &maxthreads)) {
5296859Sth199096 		fprintf(stderr, "unable to set maxthreads");
5300Sstevel@tonic-gate 		exit(1);
5310Sstevel@tonic-gate 	}
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	/*
5340Sstevel@tonic-gate 	 * Make sure to unregister any previous versions in case the
5350Sstevel@tonic-gate 	 * user is reconfiguring the server in interesting ways.
5360Sstevel@tonic-gate 	 */
5370Sstevel@tonic-gate 	svc_unreg(MOUNTPROG, MOUNTVERS);
5380Sstevel@tonic-gate 	svc_unreg(MOUNTPROG, MOUNTVERS_POSIX);
5390Sstevel@tonic-gate 	svc_unreg(MOUNTPROG, MOUNTVERS3);
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	/*
5422140Srmesta 	 * Create the nfsauth thread with same signal disposition
5432140Srmesta 	 * as the main thread. We need to create a separate thread
5442140Srmesta 	 * since mountd() will be both an RPC server (for remote
5452140Srmesta 	 * traffic) _and_ a doors server (for kernel upcalls).
5460Sstevel@tonic-gate 	 */
5472140Srmesta 	if (thr_create(NULL, 0, nfsauth_svc, 0, thr_flags, &nfsauth_thread)) {
5486859Sth199096 		fprintf(stderr, gettext("Failed to create NFSAUTH svc thread"));
5492140Srmesta 		exit(2);
5500Sstevel@tonic-gate 	}
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	/*
5537961SNatalie.Li@Sun.COM 	 * Create the cmd service thread with same signal disposition
5547961SNatalie.Li@Sun.COM 	 * as the main thread. We need to create a separate thread
5557961SNatalie.Li@Sun.COM 	 * since mountd() will be both an RPC server (for remote
5567961SNatalie.Li@Sun.COM 	 * traffic) _and_ a doors server (for kernel upcalls).
5577961SNatalie.Li@Sun.COM 	 */
5587961SNatalie.Li@Sun.COM 	if (thr_create(NULL, 0, cmd_svc, 0, thr_flags, &cmd_thread)) {
5597961SNatalie.Li@Sun.COM 		syslog(LOG_ERR, gettext("Failed to create CMD svc thread"));
5607961SNatalie.Li@Sun.COM 		exit(2);
5617961SNatalie.Li@Sun.COM 	}
5627961SNatalie.Li@Sun.COM 
5637961SNatalie.Li@Sun.COM 	/*
564*11211SThomas.Haynes@Sun.COM 	 * Create an additional thread to service the rmtab and
565*11211SThomas.Haynes@Sun.COM 	 * audit_mountd_mount logging for mount requests. Use the same
566*11211SThomas.Haynes@Sun.COM 	 * signal disposition as the main thread. We create
567*11211SThomas.Haynes@Sun.COM 	 * a separate thread to allow the mount request threads to
568*11211SThomas.Haynes@Sun.COM 	 * clear as soon as possible.
569*11211SThomas.Haynes@Sun.COM 	 */
570*11211SThomas.Haynes@Sun.COM 	if (thr_create(NULL, 0, logging_svc, 0, thr_flags, &logging_thread)) {
571*11211SThomas.Haynes@Sun.COM 		syslog(LOG_ERR, gettext("Failed to create LOGGING svc thread"));
572*11211SThomas.Haynes@Sun.COM 		exit(2);
573*11211SThomas.Haynes@Sun.COM 	}
574*11211SThomas.Haynes@Sun.COM 
575*11211SThomas.Haynes@Sun.COM 	/*
5760Sstevel@tonic-gate 	 * Create datagram and connection oriented services
5770Sstevel@tonic-gate 	 */
5780Sstevel@tonic-gate 	if (mount_vers_max >= MOUNTVERS) {
5790Sstevel@tonic-gate 		if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "datagram_v") == 0) {
5806859Sth199096 			fprintf(stderr,
5816859Sth199096 			    "couldn't register datagram_v MOUNTVERS");
5820Sstevel@tonic-gate 			exit(1);
5830Sstevel@tonic-gate 		}
5840Sstevel@tonic-gate 		if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "circuit_v") == 0) {
5856859Sth199096 			fprintf(stderr,
5866859Sth199096 			    "couldn't register circuit_v MOUNTVERS");
5870Sstevel@tonic-gate 			exit(1);
5880Sstevel@tonic-gate 		}
5890Sstevel@tonic-gate 	}
590*11211SThomas.Haynes@Sun.COM 
5910Sstevel@tonic-gate 	if (mount_vers_max >= MOUNTVERS_POSIX) {
5920Sstevel@tonic-gate 		if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX,
5936859Sth199096 		    "datagram_v") == 0) {
5946859Sth199096 			fprintf(stderr,
5956859Sth199096 			    "couldn't register datagram_v MOUNTVERS_POSIX");
5960Sstevel@tonic-gate 			exit(1);
5970Sstevel@tonic-gate 		}
5980Sstevel@tonic-gate 		if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX,
5996859Sth199096 		    "circuit_v") == 0) {
6006859Sth199096 			fprintf(stderr,
6016859Sth199096 			    "couldn't register circuit_v MOUNTVERS_POSIX");
6020Sstevel@tonic-gate 			exit(1);
6030Sstevel@tonic-gate 		}
6040Sstevel@tonic-gate 	}
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 	if (mount_vers_max >= MOUNTVERS3) {
6070Sstevel@tonic-gate 		if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "datagram_v") == 0) {
6086859Sth199096 			fprintf(stderr,
6096859Sth199096 			    "couldn't register datagram_v MOUNTVERS3");
6100Sstevel@tonic-gate 			exit(1);
6110Sstevel@tonic-gate 		}
6120Sstevel@tonic-gate 		if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "circuit_v") == 0) {
6136859Sth199096 			fprintf(stderr,
6146859Sth199096 			    "couldn't register circuit_v MOUNTVERS3");
6150Sstevel@tonic-gate 			exit(1);
6160Sstevel@tonic-gate 		}
6170Sstevel@tonic-gate 	}
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	/*
6200Sstevel@tonic-gate 	 * Start serving
6210Sstevel@tonic-gate 	 */
6220Sstevel@tonic-gate 	rmtab_load();
6236859Sth199096 
6246859Sth199096 	daemonize_fini(pipe_fd);
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	/* Get rid of the most dangerous basic privileges. */
6270Sstevel@tonic-gate 	__fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_INFO, PRIV_PROC_SESSION,
6280Sstevel@tonic-gate 	    (char *)NULL);
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 	svc_run();
6310Sstevel@tonic-gate 	syslog(LOG_ERR, "Error: svc_run shouldn't have returned");
6320Sstevel@tonic-gate 	abort();
6336859Sth199096 
6340Sstevel@tonic-gate 	/* NOTREACHED */
635249Sjwahlig 	return (0);
6360Sstevel@tonic-gate }
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate /*
6390Sstevel@tonic-gate  * Server procedure switch routine
6400Sstevel@tonic-gate  */
6410Sstevel@tonic-gate void
6420Sstevel@tonic-gate mnt(struct svc_req *rqstp, SVCXPRT *transp)
6430Sstevel@tonic-gate {
6440Sstevel@tonic-gate 	switch (rqstp->rq_proc) {
6450Sstevel@tonic-gate 	case NULLPROC:
6460Sstevel@tonic-gate 		errno = 0;
6470Sstevel@tonic-gate 		if (!svc_sendreply(transp, xdr_void, (char *)0))
6480Sstevel@tonic-gate 			log_cant_reply(transp);
6490Sstevel@tonic-gate 		return;
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	case MOUNTPROC_MNT:
652*11211SThomas.Haynes@Sun.COM 		(void) mount(rqstp);
6530Sstevel@tonic-gate 		return;
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 	case MOUNTPROC_DUMP:
6560Sstevel@tonic-gate 		mntlist_send(transp);
6570Sstevel@tonic-gate 		return;
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	case MOUNTPROC_UMNT:
6600Sstevel@tonic-gate 		umount(rqstp);
6610Sstevel@tonic-gate 		return;
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	case MOUNTPROC_UMNTALL:
6640Sstevel@tonic-gate 		umountall(rqstp);
6650Sstevel@tonic-gate 		return;
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 	case MOUNTPROC_EXPORT:
6680Sstevel@tonic-gate 	case MOUNTPROC_EXPORTALL:
6690Sstevel@tonic-gate 		export(rqstp);
6700Sstevel@tonic-gate 		return;
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 	case MOUNTPROC_PATHCONF:
6730Sstevel@tonic-gate 		if (rqstp->rq_vers == MOUNTVERS_POSIX)
6740Sstevel@tonic-gate 			mnt_pathconf(rqstp);
6750Sstevel@tonic-gate 		else
6760Sstevel@tonic-gate 			svcerr_noproc(transp);
6770Sstevel@tonic-gate 		return;
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 	default:
6800Sstevel@tonic-gate 		svcerr_noproc(transp);
6810Sstevel@tonic-gate 		return;
6820Sstevel@tonic-gate 	}
6830Sstevel@tonic-gate }
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate /* Set up anonymous client */
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate struct nd_hostservlist *
6880Sstevel@tonic-gate anon_client(char *host)
6890Sstevel@tonic-gate {
6900Sstevel@tonic-gate 	struct nd_hostservlist *anon_hsl;
6910Sstevel@tonic-gate 	struct nd_hostserv *anon_hs;
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	anon_hsl = malloc(sizeof (*anon_hsl));
6940Sstevel@tonic-gate 	if (anon_hsl == NULL)
6950Sstevel@tonic-gate 		return (NULL);
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	anon_hs = malloc(sizeof (*anon_hs));
6980Sstevel@tonic-gate 	if (anon_hs == NULL) {
6990Sstevel@tonic-gate 		free(anon_hsl);
7000Sstevel@tonic-gate 		return (NULL);
7010Sstevel@tonic-gate 	}
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	if (host == NULL)
7040Sstevel@tonic-gate 		anon_hs->h_host = strdup("(anon)");
7050Sstevel@tonic-gate 	else
7060Sstevel@tonic-gate 		anon_hs->h_host = strdup(host);
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	if (anon_hs->h_host == NULL) {
7090Sstevel@tonic-gate 		free(anon_hs);
7100Sstevel@tonic-gate 		free(anon_hsl);
7110Sstevel@tonic-gate 		return (NULL);
7120Sstevel@tonic-gate 	}
7130Sstevel@tonic-gate 	anon_hs->h_serv = '\0';
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	anon_hsl->h_cnt = 1;
7160Sstevel@tonic-gate 	anon_hsl->h_hostservs = anon_hs;
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	return (anon_hsl);
7190Sstevel@tonic-gate }
7200Sstevel@tonic-gate 
721*11211SThomas.Haynes@Sun.COM static void
722*11211SThomas.Haynes@Sun.COM getclientsnames_common(struct netconfig *nconf, struct netbuf **nbuf,
7230Sstevel@tonic-gate     struct nd_hostservlist **serv)
7240Sstevel@tonic-gate {
7250Sstevel@tonic-gate 	char tmp[MAXIPADDRLEN];
7260Sstevel@tonic-gate 	char *host = NULL;
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	/*
7290Sstevel@tonic-gate 	 * Use the this API instead of the netdir_getbyaddr()
7300Sstevel@tonic-gate 	 * to avoid service lookup.
7310Sstevel@tonic-gate 	 */
7320Sstevel@tonic-gate 	if (__netdir_getbyaddr_nosrv(nconf, serv, *nbuf)) {
7330Sstevel@tonic-gate 		host = &tmp[0];
7340Sstevel@tonic-gate 		if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
7350Sstevel@tonic-gate 			struct sockaddr_in *sa;
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 			/* LINTED pointer alignment */
7380Sstevel@tonic-gate 			sa = (struct sockaddr_in *)((*nbuf)->buf);
7390Sstevel@tonic-gate 			(void) inet_ntoa_r(sa->sin_addr, tmp);
7400Sstevel@tonic-gate 		} else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
7410Sstevel@tonic-gate 			struct sockaddr_in6 *sa;
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 			/* LINTED pointer alignment */
7440Sstevel@tonic-gate 			sa = (struct sockaddr_in6 *)((*nbuf)->buf);
7450Sstevel@tonic-gate 			(void) inet_ntop(AF_INET6, sa->sin6_addr.s6_addr,
7466859Sth199096 			    tmp, INET6_ADDRSTRLEN);
7470Sstevel@tonic-gate 		}
748*11211SThomas.Haynes@Sun.COM 
7490Sstevel@tonic-gate 		*serv = anon_client(host);
750*11211SThomas.Haynes@Sun.COM 	}
751*11211SThomas.Haynes@Sun.COM }
752*11211SThomas.Haynes@Sun.COM 
753*11211SThomas.Haynes@Sun.COM /*
754*11211SThomas.Haynes@Sun.COM  * Get the client's hostname from the copy of the
755*11211SThomas.Haynes@Sun.COM  * relevant transport handle parts.
756*11211SThomas.Haynes@Sun.COM  * If the name is not available then return "(anon)".
757*11211SThomas.Haynes@Sun.COM  */
758*11211SThomas.Haynes@Sun.COM static void
759*11211SThomas.Haynes@Sun.COM getclientsnames_lazy(char *netid, struct netbuf **nbuf,
760*11211SThomas.Haynes@Sun.COM     struct nd_hostservlist **serv)
761*11211SThomas.Haynes@Sun.COM {
762*11211SThomas.Haynes@Sun.COM 	struct netconfig *nconf;
763*11211SThomas.Haynes@Sun.COM 
764*11211SThomas.Haynes@Sun.COM 	nconf = getnetconfigent(netid);
765*11211SThomas.Haynes@Sun.COM 	if (nconf == NULL) {
766*11211SThomas.Haynes@Sun.COM 		syslog(LOG_ERR, "%s: getnetconfigent failed", netid);
767*11211SThomas.Haynes@Sun.COM 		*serv = anon_client(NULL);
7680Sstevel@tonic-gate 		return;
7690Sstevel@tonic-gate 	}
770*11211SThomas.Haynes@Sun.COM 
771*11211SThomas.Haynes@Sun.COM 	getclientsnames_common(nconf, nbuf, serv);
772*11211SThomas.Haynes@Sun.COM 	freenetconfigent(nconf);
773*11211SThomas.Haynes@Sun.COM }
774*11211SThomas.Haynes@Sun.COM 
775*11211SThomas.Haynes@Sun.COM /*
776*11211SThomas.Haynes@Sun.COM  * Get the client's hostname from the transport handle.
777*11211SThomas.Haynes@Sun.COM  * If the name is not available then return "(anon)".
778*11211SThomas.Haynes@Sun.COM  */
779*11211SThomas.Haynes@Sun.COM void
780*11211SThomas.Haynes@Sun.COM getclientsnames(SVCXPRT *transp, struct netbuf **nbuf,
781*11211SThomas.Haynes@Sun.COM     struct nd_hostservlist **serv)
782*11211SThomas.Haynes@Sun.COM {
783*11211SThomas.Haynes@Sun.COM 	struct netconfig *nconf;
784*11211SThomas.Haynes@Sun.COM 
785*11211SThomas.Haynes@Sun.COM 	nconf = getnetconfigent(transp->xp_netid);
786*11211SThomas.Haynes@Sun.COM 	if (nconf == NULL) {
787*11211SThomas.Haynes@Sun.COM 		syslog(LOG_ERR, "%s: getnetconfigent failed",
788*11211SThomas.Haynes@Sun.COM 		    transp->xp_netid);
789*11211SThomas.Haynes@Sun.COM 		*serv = anon_client(NULL);
790*11211SThomas.Haynes@Sun.COM 		return;
791*11211SThomas.Haynes@Sun.COM 	}
792*11211SThomas.Haynes@Sun.COM 
793*11211SThomas.Haynes@Sun.COM 	*nbuf = svc_getrpccaller(transp);
794*11211SThomas.Haynes@Sun.COM 	if (*nbuf == NULL) {
795*11211SThomas.Haynes@Sun.COM 		freenetconfigent(nconf);
796*11211SThomas.Haynes@Sun.COM 		*serv = anon_client(NULL);
797*11211SThomas.Haynes@Sun.COM 		return;
798*11211SThomas.Haynes@Sun.COM 	}
799*11211SThomas.Haynes@Sun.COM 
800*11211SThomas.Haynes@Sun.COM 	getclientsnames_common(nconf, nbuf, serv);
8010Sstevel@tonic-gate 	freenetconfigent(nconf);
8020Sstevel@tonic-gate }
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate void
8050Sstevel@tonic-gate log_cant_reply(SVCXPRT *transp)
8060Sstevel@tonic-gate {
8070Sstevel@tonic-gate 	int saverrno;
8080Sstevel@tonic-gate 	struct nd_hostservlist *clnames = NULL;
8090Sstevel@tonic-gate 	register char *host;
8100Sstevel@tonic-gate 	struct netbuf *nb;
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	saverrno = errno;	/* save error code */
8130Sstevel@tonic-gate 	getclientsnames(transp, &nb, &clnames);
8140Sstevel@tonic-gate 	if (clnames == NULL)
8150Sstevel@tonic-gate 		return;
8160Sstevel@tonic-gate 	host = clnames->h_hostservs->h_host;
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	errno = saverrno;
8190Sstevel@tonic-gate 	if (errno == 0)
8200Sstevel@tonic-gate 		syslog(LOG_ERR, "couldn't send reply to %s", host);
8210Sstevel@tonic-gate 	else
8220Sstevel@tonic-gate 		syslog(LOG_ERR, "couldn't send reply to %s: %m", host);
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate 	netdir_free(clnames, ND_HOSTSERVLIST);
8250Sstevel@tonic-gate }
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate /*
8280Sstevel@tonic-gate  * Answer pathconf questions for the mount point fs
8290Sstevel@tonic-gate  */
8300Sstevel@tonic-gate static void
8310Sstevel@tonic-gate mnt_pathconf(struct svc_req *rqstp)
8320Sstevel@tonic-gate {
8330Sstevel@tonic-gate 	SVCXPRT *transp;
8340Sstevel@tonic-gate 	struct pathcnf p;
8350Sstevel@tonic-gate 	char *path, rpath[MAXPATHLEN];
8360Sstevel@tonic-gate 	struct stat st;
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	transp = rqstp->rq_xprt;
8390Sstevel@tonic-gate 	path = NULL;
8400Sstevel@tonic-gate 	(void) memset((caddr_t)&p, 0, sizeof (p));
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 	if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
8430Sstevel@tonic-gate 		svcerr_decode(transp);
8440Sstevel@tonic-gate 		return;
8450Sstevel@tonic-gate 	}
8460Sstevel@tonic-gate 	if (lstat(path, &st) < 0) {
8470Sstevel@tonic-gate 		_PC_SET(_PC_ERROR, p.pc_mask);
8480Sstevel@tonic-gate 		goto done;
8490Sstevel@tonic-gate 	}
8500Sstevel@tonic-gate 	/*
8510Sstevel@tonic-gate 	 * Get a path without symbolic links.
8520Sstevel@tonic-gate 	 */
8530Sstevel@tonic-gate 	if (realpath(path, rpath) == NULL) {
8540Sstevel@tonic-gate 		syslog(LOG_DEBUG,
8556859Sth199096 		    "mount request: realpath failed on %s: %m",
8566859Sth199096 		    path);
8570Sstevel@tonic-gate 		_PC_SET(_PC_ERROR, p.pc_mask);
8580Sstevel@tonic-gate 		goto done;
8590Sstevel@tonic-gate 	}
8600Sstevel@tonic-gate 	(void) memset((caddr_t)&p, 0, sizeof (p));
8610Sstevel@tonic-gate 	/*
8620Sstevel@tonic-gate 	 * can't ask about devices over NFS
8630Sstevel@tonic-gate 	 */
8640Sstevel@tonic-gate 	_PC_SET(_PC_MAX_CANON, p.pc_mask);
8650Sstevel@tonic-gate 	_PC_SET(_PC_MAX_INPUT, p.pc_mask);
8660Sstevel@tonic-gate 	_PC_SET(_PC_PIPE_BUF, p.pc_mask);
8670Sstevel@tonic-gate 	_PC_SET(_PC_VDISABLE, p.pc_mask);
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 	errno = 0;
8700Sstevel@tonic-gate 	p.pc_link_max = pathconf(rpath, _PC_LINK_MAX);
8710Sstevel@tonic-gate 	if (errno)
8720Sstevel@tonic-gate 		_PC_SET(_PC_LINK_MAX, p.pc_mask);
8730Sstevel@tonic-gate 	p.pc_name_max = pathconf(rpath, _PC_NAME_MAX);
8740Sstevel@tonic-gate 	if (errno)
8750Sstevel@tonic-gate 		_PC_SET(_PC_NAME_MAX, p.pc_mask);
8760Sstevel@tonic-gate 	p.pc_path_max = pathconf(rpath, _PC_PATH_MAX);
8770Sstevel@tonic-gate 	if (errno)
8780Sstevel@tonic-gate 		_PC_SET(_PC_PATH_MAX, p.pc_mask);
8790Sstevel@tonic-gate 	if (pathconf(rpath, _PC_NO_TRUNC) == 1)
8800Sstevel@tonic-gate 		_PC_SET(_PC_NO_TRUNC, p.pc_mask);
8810Sstevel@tonic-gate 	if (pathconf(rpath, _PC_CHOWN_RESTRICTED) == 1)
8820Sstevel@tonic-gate 		_PC_SET(_PC_CHOWN_RESTRICTED, p.pc_mask);
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate done:
8850Sstevel@tonic-gate 	errno = 0;
8860Sstevel@tonic-gate 	if (!svc_sendreply(transp, xdr_ppathcnf, (char *)&p))
8870Sstevel@tonic-gate 		log_cant_reply(transp);
8880Sstevel@tonic-gate 	if (path != NULL)
8890Sstevel@tonic-gate 		svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
8900Sstevel@tonic-gate }
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate /*
8930Sstevel@tonic-gate  * If the rootmount (export) option is specified, the all mount requests for
8940Sstevel@tonic-gate  * subdirectories return EACCES.
8950Sstevel@tonic-gate  */
8960Sstevel@tonic-gate static int
897*11211SThomas.Haynes@Sun.COM checkrootmount(share_t *sh, char *rpath)
8980Sstevel@tonic-gate {
8990Sstevel@tonic-gate 	char *val;
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	if ((val = getshareopt(sh->sh_opts, SHOPT_NOSUB)) != NULL) {
9020Sstevel@tonic-gate 		free(val);
9030Sstevel@tonic-gate 		if (strcmp(sh->sh_path, rpath) != 0)
9040Sstevel@tonic-gate 			return (0);
9050Sstevel@tonic-gate 		else
9060Sstevel@tonic-gate 			return (1);
9070Sstevel@tonic-gate 	} else
9080Sstevel@tonic-gate 		return (1);
9090Sstevel@tonic-gate }
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate #define	MAX_FLAVORS	128
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate /*
9140Sstevel@tonic-gate  * Return only EACCES if client does not have access
9150Sstevel@tonic-gate  *  to this directory.
9160Sstevel@tonic-gate  * "If the server exports only /a/b, an attempt to
9170Sstevel@tonic-gate  *  mount a/b/c will fail with ENOENT if the directory
9180Sstevel@tonic-gate  *  does not exist"... However, if the client
9190Sstevel@tonic-gate  *  does not have access to /a/b, an attacker can
9200Sstevel@tonic-gate  *  determine whether the directory exists.
9210Sstevel@tonic-gate  * This routine checks either existence of the file or
9220Sstevel@tonic-gate  * existence of the file name entry in the mount table.
9230Sstevel@tonic-gate  * If the file exists and there is no file name entry,
9240Sstevel@tonic-gate  * the error returned should be EACCES.
9250Sstevel@tonic-gate  * If the file does not exist, it must be determined
9260Sstevel@tonic-gate  * whether the client has access to a parent
9270Sstevel@tonic-gate  * directory.  If the client has access to a parent
9280Sstevel@tonic-gate  * directory, the error returned should be ENOENT,
9290Sstevel@tonic-gate  * otherwise EACCES.
9300Sstevel@tonic-gate  */
9310Sstevel@tonic-gate static int
932*11211SThomas.Haynes@Sun.COM mount_enoent_error(SVCXPRT *transp, char *path, char *rpath,
933*11211SThomas.Haynes@Sun.COM     struct nd_hostservlist **clnames, struct netbuf **nb, int *flavor_list)
9340Sstevel@tonic-gate {
9350Sstevel@tonic-gate 	char *checkpath, *dp;
936*11211SThomas.Haynes@Sun.COM 	share_t *sh = NULL;
9370Sstevel@tonic-gate 	int realpath_error = ENOENT, reply_error = EACCES, lofs_tried = 0;
9380Sstevel@tonic-gate 	int flavor_count;
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 	checkpath = strdup(path);
9410Sstevel@tonic-gate 	if (checkpath == NULL) {
9420Sstevel@tonic-gate 		syslog(LOG_ERR, "mount_enoent: no memory");
9430Sstevel@tonic-gate 		return (EACCES);
9440Sstevel@tonic-gate 	}
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 	/* CONSTCOND */
9470Sstevel@tonic-gate 	while (1) {
9480Sstevel@tonic-gate 		if (sh) {
9490Sstevel@tonic-gate 			sharefree(sh);
9500Sstevel@tonic-gate 			sh = NULL;
9510Sstevel@tonic-gate 		}
952*11211SThomas.Haynes@Sun.COM 
9530Sstevel@tonic-gate 		if ((sh = findentry(rpath)) == NULL &&
9546859Sth199096 		    (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) {
9550Sstevel@tonic-gate 			/*
9560Sstevel@tonic-gate 			 * There is no file name entry.
9570Sstevel@tonic-gate 			 * If the file (with symbolic links resolved) exists,
9580Sstevel@tonic-gate 			 * the error returned should be EACCES.
9590Sstevel@tonic-gate 			 */
9600Sstevel@tonic-gate 			if (realpath_error == 0)
9610Sstevel@tonic-gate 				break;
9620Sstevel@tonic-gate 		} else if (checkrootmount(sh, rpath) == 0) {
9630Sstevel@tonic-gate 			/*
9640Sstevel@tonic-gate 			 * This is a "nosub" only export, in which case,
9650Sstevel@tonic-gate 			 * mounting subdirectories isn't allowed.
9660Sstevel@tonic-gate 			 * If the file (with symbolic links resolved) exists,
9670Sstevel@tonic-gate 			 * the error returned should be EACCES.
9680Sstevel@tonic-gate 			 */
9690Sstevel@tonic-gate 			if (realpath_error == 0)
9700Sstevel@tonic-gate 				break;
9710Sstevel@tonic-gate 		} else {
9720Sstevel@tonic-gate 			/*
9730Sstevel@tonic-gate 			 * Check permissions in mount table.
9740Sstevel@tonic-gate 			 */
9750Sstevel@tonic-gate 			if (newopts(sh->sh_opts))
976*11211SThomas.Haynes@Sun.COM 				flavor_count = getclientsflavors_new(sh,
977*11211SThomas.Haynes@Sun.COM 				    transp, nb, clnames, flavor_list);
9780Sstevel@tonic-gate 			else
979*11211SThomas.Haynes@Sun.COM 				flavor_count = getclientsflavors_old(sh,
980*11211SThomas.Haynes@Sun.COM 				    transp, nb, clnames, flavor_list);
9810Sstevel@tonic-gate 			if (flavor_count != 0) {
9820Sstevel@tonic-gate 				/*
9830Sstevel@tonic-gate 				 * Found entry in table and
9840Sstevel@tonic-gate 				 * client has correct permissions.
9850Sstevel@tonic-gate 				 */
9860Sstevel@tonic-gate 				reply_error = ENOENT;
9870Sstevel@tonic-gate 				break;
9880Sstevel@tonic-gate 			}
9890Sstevel@tonic-gate 		}
990*11211SThomas.Haynes@Sun.COM 
9910Sstevel@tonic-gate 		/*
9920Sstevel@tonic-gate 		 * Check all parent directories.
9930Sstevel@tonic-gate 		 */
9940Sstevel@tonic-gate 		dp = strrchr(checkpath, '/');
9950Sstevel@tonic-gate 		if (dp == NULL)
9960Sstevel@tonic-gate 			break;
9970Sstevel@tonic-gate 		*dp = '\0';
9980Sstevel@tonic-gate 		if (strlen(checkpath) == 0)
9990Sstevel@tonic-gate 			break;
10000Sstevel@tonic-gate 		/*
10010Sstevel@tonic-gate 		 * Get the real path (no symbolic links in it)
10020Sstevel@tonic-gate 		 */
10030Sstevel@tonic-gate 		if (realpath(checkpath, rpath) == NULL) {
10040Sstevel@tonic-gate 			if (errno != ENOENT)
10050Sstevel@tonic-gate 				break;
10060Sstevel@tonic-gate 		} else {
10070Sstevel@tonic-gate 			realpath_error = 0;
10080Sstevel@tonic-gate 		}
10090Sstevel@tonic-gate 	}
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 	if (sh)
10120Sstevel@tonic-gate 		sharefree(sh);
10130Sstevel@tonic-gate 	free(checkpath);
10140Sstevel@tonic-gate 	return (reply_error);
10150Sstevel@tonic-gate }
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate /*
1018*11211SThomas.Haynes@Sun.COM  * We need to inform the caller whether or not we were
1019*11211SThomas.Haynes@Sun.COM  * able to add a node to the queue. If we are not, then
1020*11211SThomas.Haynes@Sun.COM  * it is up to the caller to go ahead and log the data.
1021*11211SThomas.Haynes@Sun.COM  */
1022*11211SThomas.Haynes@Sun.COM static int
1023*11211SThomas.Haynes@Sun.COM enqueue_logging_data(char *host, SVCXPRT *transp, char *path,
1024*11211SThomas.Haynes@Sun.COM     char *rpath, int status, int error)
1025*11211SThomas.Haynes@Sun.COM {
1026*11211SThomas.Haynes@Sun.COM 	logging_data	*lq;
1027*11211SThomas.Haynes@Sun.COM 	struct netbuf	*nb;
1028*11211SThomas.Haynes@Sun.COM 
1029*11211SThomas.Haynes@Sun.COM 	lq = (logging_data *)calloc(1, sizeof (logging_data));
1030*11211SThomas.Haynes@Sun.COM 	if (lq == NULL)
1031*11211SThomas.Haynes@Sun.COM 		goto cleanup;
1032*11211SThomas.Haynes@Sun.COM 
1033*11211SThomas.Haynes@Sun.COM 	/*
1034*11211SThomas.Haynes@Sun.COM 	 * We might not yet have the host...
1035*11211SThomas.Haynes@Sun.COM 	 */
1036*11211SThomas.Haynes@Sun.COM 	if (host) {
1037*11211SThomas.Haynes@Sun.COM 		DTRACE_PROBE1(mountd, log_host, host);
1038*11211SThomas.Haynes@Sun.COM 		lq->ld_host = strdup(host);
1039*11211SThomas.Haynes@Sun.COM 		if (lq->ld_host == NULL)
1040*11211SThomas.Haynes@Sun.COM 			goto cleanup;
1041*11211SThomas.Haynes@Sun.COM 	} else {
1042*11211SThomas.Haynes@Sun.COM 		DTRACE_PROBE(mountd, log_no_host);
1043*11211SThomas.Haynes@Sun.COM 
1044*11211SThomas.Haynes@Sun.COM 		lq->ld_netid = strdup(transp->xp_netid);
1045*11211SThomas.Haynes@Sun.COM 		if (lq->ld_netid == NULL)
1046*11211SThomas.Haynes@Sun.COM 			goto cleanup;
1047*11211SThomas.Haynes@Sun.COM 
1048*11211SThomas.Haynes@Sun.COM 		lq->ld_nb = calloc(1, sizeof (struct netbuf));
1049*11211SThomas.Haynes@Sun.COM 		if (lq->ld_nb == NULL)
1050*11211SThomas.Haynes@Sun.COM 			goto cleanup;
1051*11211SThomas.Haynes@Sun.COM 
1052*11211SThomas.Haynes@Sun.COM 		nb = svc_getrpccaller(transp);
1053*11211SThomas.Haynes@Sun.COM 		if (nb == NULL) {
1054*11211SThomas.Haynes@Sun.COM 			DTRACE_PROBE(mountd, e__nb__enqueue);
1055*11211SThomas.Haynes@Sun.COM 			goto cleanup;
1056*11211SThomas.Haynes@Sun.COM 		}
1057*11211SThomas.Haynes@Sun.COM 
1058*11211SThomas.Haynes@Sun.COM 		DTRACE_PROBE(mountd, nb_set_enqueue);
1059*11211SThomas.Haynes@Sun.COM 
1060*11211SThomas.Haynes@Sun.COM 		lq->ld_nb->maxlen = nb->maxlen;
1061*11211SThomas.Haynes@Sun.COM 		lq->ld_nb->len = nb->len;
1062*11211SThomas.Haynes@Sun.COM 
1063*11211SThomas.Haynes@Sun.COM 		lq->ld_nb->buf = malloc(lq->ld_nb->len);
1064*11211SThomas.Haynes@Sun.COM 		if (lq->ld_nb->buf == NULL)
1065*11211SThomas.Haynes@Sun.COM 			goto cleanup;
1066*11211SThomas.Haynes@Sun.COM 
1067*11211SThomas.Haynes@Sun.COM 		bcopy(nb->buf, lq->ld_nb->buf, lq->ld_nb->len);
1068*11211SThomas.Haynes@Sun.COM 	}
1069*11211SThomas.Haynes@Sun.COM 
1070*11211SThomas.Haynes@Sun.COM 	lq->ld_path = strdup(path);
1071*11211SThomas.Haynes@Sun.COM 	if (lq->ld_path == NULL)
1072*11211SThomas.Haynes@Sun.COM 		goto cleanup;
1073*11211SThomas.Haynes@Sun.COM 
1074*11211SThomas.Haynes@Sun.COM 	if (!error) {
1075*11211SThomas.Haynes@Sun.COM 		lq->ld_rpath = strdup(rpath);
1076*11211SThomas.Haynes@Sun.COM 		if (lq->ld_rpath == NULL)
1077*11211SThomas.Haynes@Sun.COM 			goto cleanup;
1078*11211SThomas.Haynes@Sun.COM 	}
1079*11211SThomas.Haynes@Sun.COM 
1080*11211SThomas.Haynes@Sun.COM 	lq->ld_status = status;
1081*11211SThomas.Haynes@Sun.COM 
1082*11211SThomas.Haynes@Sun.COM 	/*
1083*11211SThomas.Haynes@Sun.COM 	 * Add to the tail of the logging queue.
1084*11211SThomas.Haynes@Sun.COM 	 */
1085*11211SThomas.Haynes@Sun.COM 	(void) mutex_lock(&logging_queue_lock);
1086*11211SThomas.Haynes@Sun.COM 	if (logging_tail == NULL) {
1087*11211SThomas.Haynes@Sun.COM 		logging_tail = logging_head = lq;
1088*11211SThomas.Haynes@Sun.COM 	} else {
1089*11211SThomas.Haynes@Sun.COM 		logging_tail->ld_next = lq;
1090*11211SThomas.Haynes@Sun.COM 		logging_tail = lq;
1091*11211SThomas.Haynes@Sun.COM 	}
1092*11211SThomas.Haynes@Sun.COM 	(void) cond_signal(&logging_queue_cv);
1093*11211SThomas.Haynes@Sun.COM 	(void) mutex_unlock(&logging_queue_lock);
1094*11211SThomas.Haynes@Sun.COM 
1095*11211SThomas.Haynes@Sun.COM 	return (TRUE);
1096*11211SThomas.Haynes@Sun.COM 
1097*11211SThomas.Haynes@Sun.COM cleanup:
1098*11211SThomas.Haynes@Sun.COM 
1099*11211SThomas.Haynes@Sun.COM 	free_logging_data(lq);
1100*11211SThomas.Haynes@Sun.COM 
1101*11211SThomas.Haynes@Sun.COM 	return (FALSE);
1102*11211SThomas.Haynes@Sun.COM }
1103*11211SThomas.Haynes@Sun.COM 
1104*11211SThomas.Haynes@Sun.COM /*
11050Sstevel@tonic-gate  * Check mount requests, add to mounted list if ok
11060Sstevel@tonic-gate  */
1107*11211SThomas.Haynes@Sun.COM static int
11080Sstevel@tonic-gate mount(struct svc_req *rqstp)
11090Sstevel@tonic-gate {
11100Sstevel@tonic-gate 	SVCXPRT *transp;
11111610Sthurlow 	int version, vers;
11120Sstevel@tonic-gate 	struct fhstatus fhs;
11130Sstevel@tonic-gate 	struct mountres3 mountres3;
11141610Sthurlow 	char fh[FHSIZE3];
11151610Sthurlow 	int len = FHSIZE3;
11160Sstevel@tonic-gate 	char *path, rpath[MAXPATHLEN];
1117*11211SThomas.Haynes@Sun.COM 	share_t *sh = NULL;
11180Sstevel@tonic-gate 	struct nd_hostservlist *clnames = NULL;
11190Sstevel@tonic-gate 	char *host = NULL;
1120*11211SThomas.Haynes@Sun.COM 	int error = 0, lofs_tried = 0, enqueued;
11210Sstevel@tonic-gate 	int flavor_list[MAX_FLAVORS];
11220Sstevel@tonic-gate 	int flavor_count;
1123*11211SThomas.Haynes@Sun.COM 	struct netbuf *nb = NULL;
11244971Sjarrett 	ucred_t	*uc = NULL;
11250Sstevel@tonic-gate 
1126*11211SThomas.Haynes@Sun.COM 	int audit_status;
1127*11211SThomas.Haynes@Sun.COM 
11280Sstevel@tonic-gate 	transp = rqstp->rq_xprt;
11290Sstevel@tonic-gate 	version = rqstp->rq_vers;
11300Sstevel@tonic-gate 	path = NULL;
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
11330Sstevel@tonic-gate 		svcerr_decode(transp);
1134*11211SThomas.Haynes@Sun.COM 		return (EACCES);
11350Sstevel@tonic-gate 	}
11360Sstevel@tonic-gate 
1137*11211SThomas.Haynes@Sun.COM 	/*
1138*11211SThomas.Haynes@Sun.COM 	 * Put off getting the name for the client until we
1139*11211SThomas.Haynes@Sun.COM 	 * need it. This is a performance gain. If we are logging,
1140*11211SThomas.Haynes@Sun.COM 	 * then we don't care about performance and might as well
1141*11211SThomas.Haynes@Sun.COM 	 * get the host name now in case we need to spit out an
1142*11211SThomas.Haynes@Sun.COM 	 * error message.
1143*11211SThomas.Haynes@Sun.COM 	 */
1144*11211SThomas.Haynes@Sun.COM 	if (verbose) {
1145*11211SThomas.Haynes@Sun.COM 		DTRACE_PROBE(mountd, name_by_verbose);
1146*11211SThomas.Haynes@Sun.COM 		getclientsnames(transp, &nb, &clnames);
1147*11211SThomas.Haynes@Sun.COM 		if (clnames == NULL || nb == NULL) {
1148*11211SThomas.Haynes@Sun.COM 			/*
1149*11211SThomas.Haynes@Sun.COM 			 * We failed to get a name for the client, even
1150*11211SThomas.Haynes@Sun.COM 			 * 'anon', probably because we ran out of memory.
1151*11211SThomas.Haynes@Sun.COM 			 * In this situation it doesn't make sense to
1152*11211SThomas.Haynes@Sun.COM 			 * allow the mount to succeed.
1153*11211SThomas.Haynes@Sun.COM 			 */
1154*11211SThomas.Haynes@Sun.COM 			error = EACCES;
1155*11211SThomas.Haynes@Sun.COM 			goto reply;
1156*11211SThomas.Haynes@Sun.COM 		}
1157*11211SThomas.Haynes@Sun.COM 		host = clnames->h_hostservs[0].h_host;
11580Sstevel@tonic-gate 	}
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 	/*
11610Sstevel@tonic-gate 	 * If the version being used is less than the minimum version,
11620Sstevel@tonic-gate 	 * the filehandle translation should not be provided to the
11630Sstevel@tonic-gate 	 * client.
11640Sstevel@tonic-gate 	 */
11650Sstevel@tonic-gate 	if (rejecting || version < mount_vers_min) {
11660Sstevel@tonic-gate 		if (verbose)
11670Sstevel@tonic-gate 			syslog(LOG_NOTICE, "Rejected mount: %s for %s",
11686859Sth199096 			    host, path);
11690Sstevel@tonic-gate 		error = EACCES;
11700Sstevel@tonic-gate 		goto reply;
11710Sstevel@tonic-gate 	}
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate 	/*
11744971Sjarrett 	 * Trusted Extension doesn't support nfsv2. nfsv2 client
11754971Sjarrett 	 * uses MOUNT protocol v1 and v2. To prevent circumventing
11764971Sjarrett 	 * TX label policy via using nfsv2 client, reject a mount
11774971Sjarrett 	 * request with version less than 3 and log an error.
11781676Sjpk 	 */
11791676Sjpk 	if (is_system_labeled()) {
11804971Sjarrett 		if (version < 3) {
11814971Sjarrett 			if (verbose)
11824971Sjarrett 				syslog(LOG_ERR,
11834971Sjarrett 				    "Rejected mount: TX doesn't support NFSv2");
11844971Sjarrett 			error = EACCES;
11854971Sjarrett 			goto reply;
11864971Sjarrett 		}
11871676Sjpk 	}
11881676Sjpk 
11891676Sjpk 	/*
11900Sstevel@tonic-gate 	 * Get the real path (no symbolic links in it)
11910Sstevel@tonic-gate 	 */
11920Sstevel@tonic-gate 	if (realpath(path, rpath) == NULL) {
11930Sstevel@tonic-gate 		error = errno;
11940Sstevel@tonic-gate 		if (verbose)
11950Sstevel@tonic-gate 			syslog(LOG_ERR,
11966859Sth199096 			    "mount request: realpath: %s: %m", path);
11970Sstevel@tonic-gate 		if (error == ENOENT)
1198*11211SThomas.Haynes@Sun.COM 			error = mount_enoent_error(transp, path, rpath,
1199*11211SThomas.Haynes@Sun.COM 			    &clnames, &nb, flavor_list);
12000Sstevel@tonic-gate 		goto reply;
12010Sstevel@tonic-gate 	}
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate 	if ((sh = findentry(rpath)) == NULL &&
12046859Sth199096 	    (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) {
12050Sstevel@tonic-gate 		error = EACCES;
12060Sstevel@tonic-gate 		goto reply;
12070Sstevel@tonic-gate 	}
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 	/*
12100Sstevel@tonic-gate 	 * Check if this is a "nosub" only export, in which case, mounting
12110Sstevel@tonic-gate 	 * subdirectories isn't allowed. Bug 1184573.
12120Sstevel@tonic-gate 	 */
12130Sstevel@tonic-gate 	if (checkrootmount(sh, rpath) == 0) {
12140Sstevel@tonic-gate 		error = EACCES;
12150Sstevel@tonic-gate 		goto reply;
12160Sstevel@tonic-gate 	}
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	if (newopts(sh->sh_opts))
1219*11211SThomas.Haynes@Sun.COM 		flavor_count = getclientsflavors_new(sh, transp, &nb, &clnames,
12206859Sth199096 		    flavor_list);
12210Sstevel@tonic-gate 	else
1222*11211SThomas.Haynes@Sun.COM 		flavor_count = getclientsflavors_old(sh, transp, &nb, &clnames,
12236859Sth199096 		    flavor_list);
12240Sstevel@tonic-gate 
1225*11211SThomas.Haynes@Sun.COM 	if (clnames)
1226*11211SThomas.Haynes@Sun.COM 		host = clnames->h_hostservs[0].h_host;
1227*11211SThomas.Haynes@Sun.COM 
12280Sstevel@tonic-gate 	if (flavor_count == 0) {
12290Sstevel@tonic-gate 		error = EACCES;
12300Sstevel@tonic-gate 		goto reply;
12310Sstevel@tonic-gate 	}
12320Sstevel@tonic-gate 
12330Sstevel@tonic-gate 	/*
12344971Sjarrett 	 * Check MAC policy here. The server side policy should be
12354971Sjarrett 	 * consistent with client side mount policy, i.e.
12364971Sjarrett 	 * - we disallow an admin_low unlabeled client to mount
12374971Sjarrett 	 * - we disallow mount from a lower labeled client.
12384971Sjarrett 	 */
12394971Sjarrett 	if (is_system_labeled()) {
12404971Sjarrett 		m_label_t *clabel = NULL;
12414971Sjarrett 		m_label_t *slabel = NULL;
12424971Sjarrett 		m_label_t admin_low;
12434971Sjarrett 
12444971Sjarrett 		if (svc_getcallerucred(rqstp->rq_xprt, &uc) != 0) {
12454971Sjarrett 			syslog(LOG_ERR,
12464971Sjarrett 			    "mount request: Failed to get caller's ucred : %m");
12474971Sjarrett 			error = EACCES;
12484971Sjarrett 			goto reply;
12494971Sjarrett 		}
12504971Sjarrett 		if ((clabel = ucred_getlabel(uc)) == NULL) {
12514971Sjarrett 			syslog(LOG_ERR,
12524971Sjarrett 			    "mount request: can't get client label from ucred");
12534971Sjarrett 			error = EACCES;
12544971Sjarrett 			goto reply;
12554971Sjarrett 		}
12564971Sjarrett 
12574971Sjarrett 		bsllow(&admin_low);
12584971Sjarrett 		if (blequal(&admin_low, clabel)) {
12594971Sjarrett 			struct sockaddr *ca;
12604971Sjarrett 			tsol_tpent_t	*tp;
12614971Sjarrett 
12624971Sjarrett 			ca = (struct sockaddr *)(void *)svc_getrpccaller(
12634971Sjarrett 			    rqstp->rq_xprt)->buf;
12644971Sjarrett 			if (ca == NULL) {
12654971Sjarrett 				error = EACCES;
12664971Sjarrett 				goto reply;
12674971Sjarrett 			}
12684971Sjarrett 			/*
12694971Sjarrett 			 * get trusted network template associated
12704971Sjarrett 			 * with the client.
12714971Sjarrett 			 */
12724971Sjarrett 			tp = get_client_template(ca);
12734971Sjarrett 			if (tp == NULL || tp->host_type != SUN_CIPSO) {
12744971Sjarrett 				if (tp != NULL)
12754971Sjarrett 					tsol_freetpent(tp);
12764971Sjarrett 				error = EACCES;
12774971Sjarrett 				goto reply;
12784971Sjarrett 			}
12794971Sjarrett 			tsol_freetpent(tp);
12804971Sjarrett 		} else {
12814971Sjarrett 			if ((slabel = m_label_alloc(MAC_LABEL)) == NULL) {
12824971Sjarrett 				error = EACCES;
12834971Sjarrett 				goto reply;
12844971Sjarrett 			}
12854971Sjarrett 
12864971Sjarrett 			if (getlabel(rpath, slabel) != 0) {
12874971Sjarrett 				m_label_free(slabel);
12884971Sjarrett 				error = EACCES;
12894971Sjarrett 				goto reply;
12904971Sjarrett 			}
12914971Sjarrett 
12924971Sjarrett 			if (!bldominates(clabel, slabel)) {
12934971Sjarrett 				m_label_free(slabel);
12944971Sjarrett 				error = EACCES;
12954971Sjarrett 				goto reply;
12964971Sjarrett 			}
12974971Sjarrett 			m_label_free(slabel);
12984971Sjarrett 		}
12994971Sjarrett 	}
13004971Sjarrett 
13014971Sjarrett 	/*
13020Sstevel@tonic-gate 	 * Now get the filehandle.
13030Sstevel@tonic-gate 	 *
13041610Sthurlow 	 * NFS V2 clients get a 32 byte filehandle.
13051610Sthurlow 	 * NFS V3 clients get a 32 or 64 byte filehandle, depending on
13061610Sthurlow 	 * the embedded FIDs.
13070Sstevel@tonic-gate 	 */
13081610Sthurlow 	vers = (version == MOUNTVERS3) ? NFS_V3 : NFS_VERSION;
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate 	/* LINTED pointer alignment */
13111610Sthurlow 	while (nfs_getfh(rpath, vers, &len, fh) < 0) {
13120Sstevel@tonic-gate 		if (errno == EINVAL &&
13136859Sth199096 		    (sh = find_lofsentry(rpath, &lofs_tried)) != NULL) {
13140Sstevel@tonic-gate 			errno = 0;
13150Sstevel@tonic-gate 			continue;
13160Sstevel@tonic-gate 		}
13170Sstevel@tonic-gate 		error = errno == EINVAL ? EACCES : errno;
13180Sstevel@tonic-gate 		syslog(LOG_DEBUG, "mount request: getfh failed on %s: %m",
13196859Sth199096 		    path);
13200Sstevel@tonic-gate 		break;
13210Sstevel@tonic-gate 	}
13220Sstevel@tonic-gate 
13231610Sthurlow 	if (version == MOUNTVERS3) {
13241610Sthurlow 		mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len = len;
13251610Sthurlow 		mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val = fh;
13261610Sthurlow 	} else {
13271610Sthurlow 		bcopy(fh, &fhs.fhstatus_u.fhs_fhandle, NFS_FHSIZE);
13281610Sthurlow 	}
13291610Sthurlow 
13300Sstevel@tonic-gate reply:
13314971Sjarrett 	if (uc != NULL)
13324971Sjarrett 		ucred_free(uc);
1333*11211SThomas.Haynes@Sun.COM 
13340Sstevel@tonic-gate 	switch (version) {
13350Sstevel@tonic-gate 	case MOUNTVERS:
13360Sstevel@tonic-gate 	case MOUNTVERS_POSIX:
13370Sstevel@tonic-gate 		if (error == EINVAL)
13380Sstevel@tonic-gate 			fhs.fhs_status = NFSERR_ACCES;
13390Sstevel@tonic-gate 		else if (error == EREMOTE)
13400Sstevel@tonic-gate 			fhs.fhs_status = NFSERR_REMOTE;
13410Sstevel@tonic-gate 		else
13420Sstevel@tonic-gate 			fhs.fhs_status = error;
1343*11211SThomas.Haynes@Sun.COM 
13440Sstevel@tonic-gate 		if (!svc_sendreply(transp, xdr_fhstatus, (char *)&fhs))
13450Sstevel@tonic-gate 			log_cant_reply(transp);
1346*11211SThomas.Haynes@Sun.COM 
1347*11211SThomas.Haynes@Sun.COM 		audit_status = fhs.fhs_status;
13480Sstevel@tonic-gate 		break;
13490Sstevel@tonic-gate 
13500Sstevel@tonic-gate 	case MOUNTVERS3:
13510Sstevel@tonic-gate 		if (!error) {
13520Sstevel@tonic-gate 		mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val =
13536859Sth199096 		    flavor_list;
13540Sstevel@tonic-gate 		mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len =
13556859Sth199096 		    flavor_count;
13560Sstevel@tonic-gate 
13570Sstevel@tonic-gate 		} else if (error == ENAMETOOLONG)
13580Sstevel@tonic-gate 			error = MNT3ERR_NAMETOOLONG;
13590Sstevel@tonic-gate 
13600Sstevel@tonic-gate 		mountres3.fhs_status = error;
13610Sstevel@tonic-gate 		if (!svc_sendreply(transp, xdr_mountres3, (char *)&mountres3))
13620Sstevel@tonic-gate 			log_cant_reply(transp);
13630Sstevel@tonic-gate 
1364*11211SThomas.Haynes@Sun.COM 		audit_status = mountres3.fhs_status;
13650Sstevel@tonic-gate 		break;
13660Sstevel@tonic-gate 	}
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate 	if (verbose)
13690Sstevel@tonic-gate 		syslog(LOG_NOTICE, "MOUNT: %s %s %s",
13706859Sth199096 		    (host == NULL) ? "unknown host" : host,
13716859Sth199096 		    error ? "denied" : "mounted", path);
13720Sstevel@tonic-gate 
1373*11211SThomas.Haynes@Sun.COM 	/*
1374*11211SThomas.Haynes@Sun.COM 	 * If we can not create a queue entry, go ahead and do it
1375*11211SThomas.Haynes@Sun.COM 	 * in the context of this thread.
1376*11211SThomas.Haynes@Sun.COM 	 */
1377*11211SThomas.Haynes@Sun.COM 	enqueued = enqueue_logging_data(host, transp, path, rpath,
1378*11211SThomas.Haynes@Sun.COM 	    audit_status, error);
1379*11211SThomas.Haynes@Sun.COM 	if (enqueued == FALSE) {
1380*11211SThomas.Haynes@Sun.COM 		if (host == NULL) {
1381*11211SThomas.Haynes@Sun.COM 			DTRACE_PROBE(mountd, name_by_in_thread);
1382*11211SThomas.Haynes@Sun.COM 			getclientsnames(transp, &nb, &clnames);
1383*11211SThomas.Haynes@Sun.COM 			if (clnames != NULL)
1384*11211SThomas.Haynes@Sun.COM 				host = clnames->h_hostservs[0].h_host;
1385*11211SThomas.Haynes@Sun.COM 		}
1386*11211SThomas.Haynes@Sun.COM 
1387*11211SThomas.Haynes@Sun.COM 		DTRACE_PROBE(mountd, logged_in_thread);
1388*11211SThomas.Haynes@Sun.COM 		audit_mountd_mount(host, path, audit_status); /* BSM */
1389*11211SThomas.Haynes@Sun.COM 		if (!error)
1390*11211SThomas.Haynes@Sun.COM 			mntlist_new(host, rpath); /* add entry to mount list */
1391*11211SThomas.Haynes@Sun.COM 	}
1392*11211SThomas.Haynes@Sun.COM 
13930Sstevel@tonic-gate 	if (path != NULL)
13940Sstevel@tonic-gate 		svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
13950Sstevel@tonic-gate 
13960Sstevel@tonic-gate done:
13970Sstevel@tonic-gate 	if (sh)
13980Sstevel@tonic-gate 		sharefree(sh);
13990Sstevel@tonic-gate 	netdir_free(clnames, ND_HOSTSERVLIST);
1400*11211SThomas.Haynes@Sun.COM 
1401*11211SThomas.Haynes@Sun.COM 	return (error);
14020Sstevel@tonic-gate }
14030Sstevel@tonic-gate 
1404*11211SThomas.Haynes@Sun.COM share_t *
14050Sstevel@tonic-gate findentry(char *path)
14060Sstevel@tonic-gate {
1407*11211SThomas.Haynes@Sun.COM 	share_t *sh = NULL;
14080Sstevel@tonic-gate 	struct sh_list *shp;
14090Sstevel@tonic-gate 	register char *p1, *p2;
14100Sstevel@tonic-gate 	struct stat st1;
14110Sstevel@tonic-gate 	struct stat64 st2;
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate 	check_sharetab();
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate 	(void) rw_rdlock(&sharetab_lock);
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate 	for (shp = share_list; shp; shp = shp->shl_next) {
14180Sstevel@tonic-gate 		sh = shp->shl_sh;
14190Sstevel@tonic-gate 		for (p1 = sh->sh_path, p2 = path; *p1 == *p2; p1++, p2++)
14200Sstevel@tonic-gate 			if (*p1 == '\0')
14210Sstevel@tonic-gate 				goto done;	/* exact match */
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 		/*
14240Sstevel@tonic-gate 		 * Now compare the pathnames for three cases:
14250Sstevel@tonic-gate 		 *
14260Sstevel@tonic-gate 		 * Parent: /export/foo		(no trailing slash on parent)
14270Sstevel@tonic-gate 		 * Child:  /export/foo/bar
14280Sstevel@tonic-gate 		 *
14290Sstevel@tonic-gate 		 * Parent: /export/foo/		(trailing slash on parent)
14300Sstevel@tonic-gate 		 * Child:  /export/foo/bar
14310Sstevel@tonic-gate 		 *
14320Sstevel@tonic-gate 		 * Parent: /export/foo/		(no trailing slash on child)
14330Sstevel@tonic-gate 		 * Child:  /export/foo
14340Sstevel@tonic-gate 		 *
14350Sstevel@tonic-gate 		 * Then compare the dev_t of the parent and child to
14360Sstevel@tonic-gate 		 * make sure that they're both in the same filesystem.
14370Sstevel@tonic-gate 		 */
14380Sstevel@tonic-gate 		if ((*p1 == '\0' && *p2 == '/') ||
14390Sstevel@tonic-gate 		    (*p1 == '\0' && *(p1-1) == '/') ||
14400Sstevel@tonic-gate 		    (*p2 == '\0' && *p1 == '/' && *(p1+1) == '\0')) {
14410Sstevel@tonic-gate 			if (stat(sh->sh_path, &st1) < 0) {
14420Sstevel@tonic-gate 				if (verbose)
14430Sstevel@tonic-gate 					syslog(LOG_NOTICE, "%s: %m", p1);
14440Sstevel@tonic-gate 				shp = NULL;
14450Sstevel@tonic-gate 				goto done;
14460Sstevel@tonic-gate 			}
1447*11211SThomas.Haynes@Sun.COM 
14480Sstevel@tonic-gate 			/*
14490Sstevel@tonic-gate 			 * Use stat64 on "path" since it might be larger
14500Sstevel@tonic-gate 			 * than 2 Gb and 32 bit stat would fail EOVERFLOW
14510Sstevel@tonic-gate 			 */
14520Sstevel@tonic-gate 			if (stat64(path, &st2) < 0) {
14530Sstevel@tonic-gate 				if (verbose)
14540Sstevel@tonic-gate 					syslog(LOG_NOTICE, "%s: %m", p2);
14550Sstevel@tonic-gate 				shp = NULL;
14560Sstevel@tonic-gate 				goto done;
14570Sstevel@tonic-gate 			}
14580Sstevel@tonic-gate 			if (st1.st_dev == st2.st_dev)
14590Sstevel@tonic-gate 				goto done;
14600Sstevel@tonic-gate 		}
14610Sstevel@tonic-gate 	}
14620Sstevel@tonic-gate done:
14630Sstevel@tonic-gate 	sh = shp ? sharedup(sh) : NULL;
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate 	(void) rw_unlock(&sharetab_lock);
14660Sstevel@tonic-gate 
14670Sstevel@tonic-gate 	return (sh);
14680Sstevel@tonic-gate }
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate 
14710Sstevel@tonic-gate static int
14720Sstevel@tonic-gate is_substring(char **mntp, char **path)
14730Sstevel@tonic-gate {
14740Sstevel@tonic-gate 	char *p1 = *mntp, *p2 = *path;
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 	if (*p1 == '\0' && *p2 == '\0') /* exact match */
14770Sstevel@tonic-gate 		return (1);
14780Sstevel@tonic-gate 	else if (*p1 == '\0' && *p2 == '/')
14790Sstevel@tonic-gate 		return (1);
14800Sstevel@tonic-gate 	else if (*p1 == '\0' && *(p1-1) == '/') {
14810Sstevel@tonic-gate 		*path = --p2; /* we need the slash in p2 */
14820Sstevel@tonic-gate 		return (1);
14830Sstevel@tonic-gate 	} else if (*p2 == '\0') {
14840Sstevel@tonic-gate 		while (*p1 == '/')
14850Sstevel@tonic-gate 			p1++;
14860Sstevel@tonic-gate 		if (*p1 == '\0') /* exact match */
14870Sstevel@tonic-gate 			return (1);
14880Sstevel@tonic-gate 	}
14890Sstevel@tonic-gate 	return (0);
14900Sstevel@tonic-gate }
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate /*
14930Sstevel@tonic-gate  * find_lofsentry() searches for the real path which this requested LOFS path
14940Sstevel@tonic-gate  * (rpath) shadows. If found, it will return the sharetab entry of
14950Sstevel@tonic-gate  * the real path that corresponds to the LOFS path.
14960Sstevel@tonic-gate  * We first search mnttab to see if the requested path is an automounted
14970Sstevel@tonic-gate  * path. If it is an automounted path, it will trigger the mount by stat()ing
14980Sstevel@tonic-gate  * the requested path. Note that it is important to check that this path is
14990Sstevel@tonic-gate  * actually an automounted path, otherwise we would stat() a path which may
15000Sstevel@tonic-gate  * turn out to be NFS and block indefinitely on a dead server. The automounter
15010Sstevel@tonic-gate  * times-out if the server is dead, so there's no risk of hanging this
15020Sstevel@tonic-gate  * thread waiting for stat().
15030Sstevel@tonic-gate  * After the mount has been triggered (if necessary), we look for a
15040Sstevel@tonic-gate  * mountpoint of type LOFS (by searching /etc/mnttab again) which
15050Sstevel@tonic-gate  * is a substring of the rpath. If found, we construct a new path by
15060Sstevel@tonic-gate  * concatenating the mnt_special and the remaining of rpath, call findentry()
15070Sstevel@tonic-gate  * to make sure the 'real path' is shared.
15080Sstevel@tonic-gate  */
1509*11211SThomas.Haynes@Sun.COM static share_t *
15100Sstevel@tonic-gate find_lofsentry(char *rpath, int *done_flag)
15110Sstevel@tonic-gate {
15120Sstevel@tonic-gate 	struct stat r_stbuf;
15130Sstevel@tonic-gate 	mntlist_t *ml, *mntl, *mntpnt = NULL;
1514*11211SThomas.Haynes@Sun.COM 	share_t *retcode = NULL;
15150Sstevel@tonic-gate 	char tmp_path[MAXPATHLEN];
15160Sstevel@tonic-gate 	int mntpnt_len = 0, tmp;
15170Sstevel@tonic-gate 	char *p1, *p2;
15180Sstevel@tonic-gate 
15190Sstevel@tonic-gate 	if ((*done_flag)++)
15200Sstevel@tonic-gate 		return (retcode);
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate 	/*
15230Sstevel@tonic-gate 	 * While fsgetmntlist() uses lockf() to
15240Sstevel@tonic-gate 	 * lock the mnttab before reading it in,
15250Sstevel@tonic-gate 	 * the lock ignores threads in the same process.
15260Sstevel@tonic-gate 	 * Read in the mnttab with the protection of a mutex.
15270Sstevel@tonic-gate 	 */
15280Sstevel@tonic-gate 	(void) mutex_lock(&mnttab_lock);
15290Sstevel@tonic-gate 	mntl = fsgetmntlist();
15300Sstevel@tonic-gate 	(void) mutex_unlock(&mnttab_lock);
15310Sstevel@tonic-gate 
15320Sstevel@tonic-gate 	/*
15330Sstevel@tonic-gate 	 * Obtain the mountpoint for the requested path.
15340Sstevel@tonic-gate 	 */
15350Sstevel@tonic-gate 	for (ml = mntl; ml; ml = ml->mntl_next) {
15360Sstevel@tonic-gate 		for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath;
15376859Sth199096 		    *p1 == *p2 && *p1; p1++, p2++)
15386859Sth199096 			;
15390Sstevel@tonic-gate 		if (is_substring(&p1, &p2) &&
15400Sstevel@tonic-gate 		    (tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len) {
15410Sstevel@tonic-gate 			mntpnt = ml;
15420Sstevel@tonic-gate 			mntpnt_len = tmp;
15430Sstevel@tonic-gate 		}
15440Sstevel@tonic-gate 	}
15450Sstevel@tonic-gate 
15460Sstevel@tonic-gate 	/*
15470Sstevel@tonic-gate 	 * If the path needs to be autoFS mounted, trigger the mount by
15480Sstevel@tonic-gate 	 * stat()ing it. This is determined by checking whether the
15490Sstevel@tonic-gate 	 * mountpoint we just found is of type autofs.
15500Sstevel@tonic-gate 	 */
15510Sstevel@tonic-gate 	if (mntpnt != NULL &&
15520Sstevel@tonic-gate 	    strcmp(mntpnt->mntl_mnt->mnt_fstype, "autofs") == 0) {
15530Sstevel@tonic-gate 		/*
15540Sstevel@tonic-gate 		 * The requested path is a substring of an autoFS filesystem.
15550Sstevel@tonic-gate 		 * Trigger the mount.
15560Sstevel@tonic-gate 		 */
15570Sstevel@tonic-gate 		if (stat(rpath, &r_stbuf) < 0) {
15580Sstevel@tonic-gate 			if (verbose)
15590Sstevel@tonic-gate 				syslog(LOG_NOTICE, "%s: %m", rpath);
15600Sstevel@tonic-gate 			goto done;
15610Sstevel@tonic-gate 		}
15620Sstevel@tonic-gate 		if ((r_stbuf.st_mode & S_IFMT) == S_IFDIR) {
15630Sstevel@tonic-gate 			/*
15640Sstevel@tonic-gate 			 * The requested path is a directory, stat(2) it
15650Sstevel@tonic-gate 			 * again with a trailing '.' to force the autoFS
15660Sstevel@tonic-gate 			 * module to trigger the mount of indirect
15670Sstevel@tonic-gate 			 * automount entries, such as /net/jurassic/.
15680Sstevel@tonic-gate 			 */
15690Sstevel@tonic-gate 			if (strlen(rpath) + 2 > MAXPATHLEN) {
15700Sstevel@tonic-gate 				if (verbose) {
15710Sstevel@tonic-gate 					syslog(LOG_NOTICE,
15726859Sth199096 					    "%s/.: exceeds MAXPATHLEN %d",
15736859Sth199096 					    rpath, MAXPATHLEN);
15740Sstevel@tonic-gate 				}
15750Sstevel@tonic-gate 				goto done;
15760Sstevel@tonic-gate 			}
15770Sstevel@tonic-gate 			(void) strcpy(tmp_path, rpath);
15780Sstevel@tonic-gate 			(void) strcat(tmp_path, "/.");
15790Sstevel@tonic-gate 
15800Sstevel@tonic-gate 			if (stat(tmp_path, &r_stbuf) < 0) {
15810Sstevel@tonic-gate 				if (verbose)
15820Sstevel@tonic-gate 					syslog(LOG_NOTICE, "%s: %m", tmp_path);
15830Sstevel@tonic-gate 				goto done;
15840Sstevel@tonic-gate 			}
15850Sstevel@tonic-gate 		}
1586*11211SThomas.Haynes@Sun.COM 
15870Sstevel@tonic-gate 		/*
15880Sstevel@tonic-gate 		 * The mount has been triggered, re-read mnttab to pick up
15890Sstevel@tonic-gate 		 * the changes made by autoFS.
15900Sstevel@tonic-gate 		 */
15910Sstevel@tonic-gate 		fsfreemntlist(mntl);
15920Sstevel@tonic-gate 		(void) mutex_lock(&mnttab_lock);
15930Sstevel@tonic-gate 		mntl = fsgetmntlist();
15940Sstevel@tonic-gate 		(void) mutex_unlock(&mnttab_lock);
15950Sstevel@tonic-gate 	}
15960Sstevel@tonic-gate 
15970Sstevel@tonic-gate 	/*
15980Sstevel@tonic-gate 	 * The autoFS mountpoint has been triggered if necessary,
15990Sstevel@tonic-gate 	 * now search mnttab again to determine if the requested path
16000Sstevel@tonic-gate 	 * is an LOFS mount of a shared path.
16010Sstevel@tonic-gate 	 */
16020Sstevel@tonic-gate 	mntpnt_len = 0;
16030Sstevel@tonic-gate 	for (ml = mntl; ml; ml = ml->mntl_next) {
16040Sstevel@tonic-gate 		if (strcmp(ml->mntl_mnt->mnt_fstype, "lofs"))
16050Sstevel@tonic-gate 			continue;
16060Sstevel@tonic-gate 
16070Sstevel@tonic-gate 		for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath;
16086859Sth199096 		    *p1 == *p2 && *p1; p1++, p2++)
16096859Sth199096 			;
16100Sstevel@tonic-gate 
16110Sstevel@tonic-gate 		if (is_substring(&p1, &p2) &&
16120Sstevel@tonic-gate 		    ((tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len)) {
16130Sstevel@tonic-gate 			mntpnt_len = tmp;
16140Sstevel@tonic-gate 
16150Sstevel@tonic-gate 			if ((strlen(ml->mntl_mnt->mnt_special) + strlen(p2)) >
16160Sstevel@tonic-gate 			    MAXPATHLEN) {
16170Sstevel@tonic-gate 				if (verbose) {
16180Sstevel@tonic-gate 					syslog(LOG_NOTICE, "%s%s: exceeds %d",
16196859Sth199096 					    ml->mntl_mnt->mnt_special, p2,
16206859Sth199096 					    MAXPATHLEN);
16210Sstevel@tonic-gate 				}
16220Sstevel@tonic-gate 				if (retcode)
16230Sstevel@tonic-gate 					sharefree(retcode);
16240Sstevel@tonic-gate 				retcode = NULL;
16250Sstevel@tonic-gate 				goto done;
16260Sstevel@tonic-gate 			}
16270Sstevel@tonic-gate 
16280Sstevel@tonic-gate 			(void) strcpy(tmp_path, ml->mntl_mnt->mnt_special);
16290Sstevel@tonic-gate 			(void) strcat(tmp_path, p2);
16300Sstevel@tonic-gate 			if (retcode)
16310Sstevel@tonic-gate 				sharefree(retcode);
16320Sstevel@tonic-gate 			retcode = findentry(tmp_path);
16330Sstevel@tonic-gate 		}
16340Sstevel@tonic-gate 	}
16350Sstevel@tonic-gate 
16360Sstevel@tonic-gate 	if (retcode) {
16370Sstevel@tonic-gate 		assert(strlen(tmp_path) > 0);
16380Sstevel@tonic-gate 		(void) strcpy(rpath, tmp_path);
16390Sstevel@tonic-gate 	}
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate done:
16420Sstevel@tonic-gate 	fsfreemntlist(mntl);
16430Sstevel@tonic-gate 	return (retcode);
16440Sstevel@tonic-gate }
16450Sstevel@tonic-gate 
16460Sstevel@tonic-gate /*
16470Sstevel@tonic-gate  * Determine whether an access list grants rights to a particular host.
16480Sstevel@tonic-gate  * We match on aliases of the hostname as well as on the canonical name.
16490Sstevel@tonic-gate  * Names in the access list may be either hosts or netgroups;  they're
16500Sstevel@tonic-gate  * not distinguished syntactically.  We check for hosts first because
16510Sstevel@tonic-gate  * it's cheaper (just M*N strcmp()s), then try netgroups.
16520Sstevel@tonic-gate  */
1653249Sjwahlig int
1654*11211SThomas.Haynes@Sun.COM in_access_list(SVCXPRT *transp, struct netbuf **pnb,
1655*11211SThomas.Haynes@Sun.COM     struct nd_hostservlist **pclnames,
16560Sstevel@tonic-gate     char *access_list)	/* N.B. we clobber this "input" parameter */
16570Sstevel@tonic-gate {
16580Sstevel@tonic-gate 	int nentries;
16590Sstevel@tonic-gate 	char *gr;
16600Sstevel@tonic-gate 	char *lasts;
16610Sstevel@tonic-gate 	char *host;
16620Sstevel@tonic-gate 	int off;
16630Sstevel@tonic-gate 	int i;
16640Sstevel@tonic-gate 	int netgroup_match;
16650Sstevel@tonic-gate 	int response;
16660Sstevel@tonic-gate 
1667*11211SThomas.Haynes@Sun.COM 	bool_t lookup_names;
1668*11211SThomas.Haynes@Sun.COM 	struct nd_hostservlist *clnames;
1669*11211SThomas.Haynes@Sun.COM 
16700Sstevel@tonic-gate 	/*
16710Sstevel@tonic-gate 	 * If no access list - then it's unrestricted
16720Sstevel@tonic-gate 	 */
16730Sstevel@tonic-gate 	if (access_list == NULL || *access_list == '\0')
16740Sstevel@tonic-gate 		return (1);
16750Sstevel@tonic-gate 
1676*11211SThomas.Haynes@Sun.COM 	/*
1677*11211SThomas.Haynes@Sun.COM 	 * Just get the netbuf, avoiding the costly name
1678*11211SThomas.Haynes@Sun.COM 	 * lookup. This will suffice for access based
1679*11211SThomas.Haynes@Sun.COM 	 * soley on addresses.
1680*11211SThomas.Haynes@Sun.COM 	 */
1681*11211SThomas.Haynes@Sun.COM 	if (*pnb == NULL) {
1682*11211SThomas.Haynes@Sun.COM 		lookup_names = TRUE;
1683*11211SThomas.Haynes@Sun.COM 		*pnb = svc_getrpccaller(transp);
1684*11211SThomas.Haynes@Sun.COM 		if (*pnb == NULL)
1685*11211SThomas.Haynes@Sun.COM 			*pclnames = anon_client(NULL);
1686*11211SThomas.Haynes@Sun.COM 	} else
1687*11211SThomas.Haynes@Sun.COM 		lookup_names = FALSE;
1688*11211SThomas.Haynes@Sun.COM 
16890Sstevel@tonic-gate 	nentries = 0;
16900Sstevel@tonic-gate 
16910Sstevel@tonic-gate 	for (gr = strtok_r(access_list, ":", &lasts);
16926859Sth199096 	    gr != NULL; gr = strtok_r(NULL, ":", &lasts)) {
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate 		/*
16950Sstevel@tonic-gate 		 * If the list name has a '-' prepended
16960Sstevel@tonic-gate 		 * then a match of the following name
16970Sstevel@tonic-gate 		 * implies failure instead of success.
16980Sstevel@tonic-gate 		 */
16990Sstevel@tonic-gate 		if (*gr == '-') {
17000Sstevel@tonic-gate 			response = 0;
17010Sstevel@tonic-gate 			gr++;
17020Sstevel@tonic-gate 		} else
17030Sstevel@tonic-gate 			response = 1;
17040Sstevel@tonic-gate 
17050Sstevel@tonic-gate 		/*
1706*11211SThomas.Haynes@Sun.COM 		 * If the list name begins with an at
1707*11211SThomas.Haynes@Sun.COM 		 * sign then do a network comparison.
1708*11211SThomas.Haynes@Sun.COM 		 */
1709*11211SThomas.Haynes@Sun.COM 		if (*gr == '@') {
1710*11211SThomas.Haynes@Sun.COM 			if (netmatch(*pnb, gr + 1))
1711*11211SThomas.Haynes@Sun.COM 				return (response);
1712*11211SThomas.Haynes@Sun.COM 			continue;
1713*11211SThomas.Haynes@Sun.COM 		}
1714*11211SThomas.Haynes@Sun.COM 
1715*11211SThomas.Haynes@Sun.COM 		/*
1716*11211SThomas.Haynes@Sun.COM 		 * We need to get the host name if we haven't gotten
1717*11211SThomas.Haynes@Sun.COM 		 * it by now!
1718*11211SThomas.Haynes@Sun.COM 		 */
1719*11211SThomas.Haynes@Sun.COM 		if (lookup_names) {
1720*11211SThomas.Haynes@Sun.COM 			DTRACE_PROBE(mountd, name_by_addrlist);
1721*11211SThomas.Haynes@Sun.COM 			getclientsnames(transp, pnb, pclnames);
1722*11211SThomas.Haynes@Sun.COM 
1723*11211SThomas.Haynes@Sun.COM 			/*
1724*11211SThomas.Haynes@Sun.COM 			 * Do not grant access if we can't
1725*11211SThomas.Haynes@Sun.COM 			 * get a name!
1726*11211SThomas.Haynes@Sun.COM 			 */
1727*11211SThomas.Haynes@Sun.COM 			if (*pclnames == NULL || *pnb == NULL)
1728*11211SThomas.Haynes@Sun.COM 				return (0);
1729*11211SThomas.Haynes@Sun.COM 
1730*11211SThomas.Haynes@Sun.COM 			lookup_names = FALSE;
1731*11211SThomas.Haynes@Sun.COM 		}
1732*11211SThomas.Haynes@Sun.COM 
1733*11211SThomas.Haynes@Sun.COM 		clnames = *pclnames;
1734*11211SThomas.Haynes@Sun.COM 
1735*11211SThomas.Haynes@Sun.COM 		/*
17360Sstevel@tonic-gate 		 * The following loops through all the
17370Sstevel@tonic-gate 		 * client's aliases.  Usually it's just one name.
17380Sstevel@tonic-gate 		 */
17390Sstevel@tonic-gate 		for (i = 0; i < clnames->h_cnt; i++) {
17400Sstevel@tonic-gate 			host = clnames->h_hostservs[i].h_host;
17410Sstevel@tonic-gate 
17420Sstevel@tonic-gate 			/*
17430Sstevel@tonic-gate 			 * If the list name begins with a dot then
17440Sstevel@tonic-gate 			 * do a domain name suffix comparison.
17450Sstevel@tonic-gate 			 * A single dot matches any name with no
17460Sstevel@tonic-gate 			 * suffix.
17470Sstevel@tonic-gate 			 */
17480Sstevel@tonic-gate 			if (*gr == '.') {
17490Sstevel@tonic-gate 				if (*(gr + 1) == '\0') {  /* single dot */
17500Sstevel@tonic-gate 					if (strchr(host, '.') == NULL)
17510Sstevel@tonic-gate 						return (response);
17520Sstevel@tonic-gate 				} else {
17530Sstevel@tonic-gate 					off = strlen(host) - strlen(gr);
17540Sstevel@tonic-gate 					if (off > 0 &&
17550Sstevel@tonic-gate 					    strcasecmp(host + off, gr) == 0) {
17560Sstevel@tonic-gate 						return (response);
17570Sstevel@tonic-gate 					}
17580Sstevel@tonic-gate 				}
17590Sstevel@tonic-gate 			} else
17600Sstevel@tonic-gate 
17610Sstevel@tonic-gate 			/*
17620Sstevel@tonic-gate 			 * Just do a hostname match
17630Sstevel@tonic-gate 			 */
17640Sstevel@tonic-gate 			if (strcasecmp(gr, host) == 0) {
17650Sstevel@tonic-gate 				return (response);	/* Matched a hostname */
17660Sstevel@tonic-gate 			}
17670Sstevel@tonic-gate 		}
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate 		nentries++;
17700Sstevel@tonic-gate 	}
17710Sstevel@tonic-gate 
1772*11211SThomas.Haynes@Sun.COM 	/*
1773*11211SThomas.Haynes@Sun.COM 	 * We need to get the host name if we haven't gotten
1774*11211SThomas.Haynes@Sun.COM 	 * it by now!
1775*11211SThomas.Haynes@Sun.COM 	 */
1776*11211SThomas.Haynes@Sun.COM 	if (lookup_names) {
1777*11211SThomas.Haynes@Sun.COM 		DTRACE_PROBE(mountd, name_by_netgroup);
1778*11211SThomas.Haynes@Sun.COM 		getclientsnames(transp, pnb, pclnames);
1779*11211SThomas.Haynes@Sun.COM 
1780*11211SThomas.Haynes@Sun.COM 		/*
1781*11211SThomas.Haynes@Sun.COM 		 * Do not grant access if we can't
1782*11211SThomas.Haynes@Sun.COM 		 * get a name!
1783*11211SThomas.Haynes@Sun.COM 		 */
1784*11211SThomas.Haynes@Sun.COM 		if (*pclnames == NULL || *pnb == NULL)
1785*11211SThomas.Haynes@Sun.COM 			return (0);
1786*11211SThomas.Haynes@Sun.COM 
1787*11211SThomas.Haynes@Sun.COM 		lookup_names = FALSE;
1788*11211SThomas.Haynes@Sun.COM 	}
1789*11211SThomas.Haynes@Sun.COM 
1790*11211SThomas.Haynes@Sun.COM 	netgroup_match = netgroup_check(*pclnames, access_list, nentries);
17910Sstevel@tonic-gate 
17920Sstevel@tonic-gate 	return (netgroup_match);
17930Sstevel@tonic-gate }
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate int
17960Sstevel@tonic-gate netmatch(struct netbuf *nb, char *name)
17970Sstevel@tonic-gate {
17980Sstevel@tonic-gate 	uint_t claddr;
17990Sstevel@tonic-gate 	struct netent n, *np;
18000Sstevel@tonic-gate 	char *mp, *p;
18010Sstevel@tonic-gate 	uint_t addr, mask;
18020Sstevel@tonic-gate 	int i, bits;
18030Sstevel@tonic-gate 	char buff[256];
18040Sstevel@tonic-gate 
18050Sstevel@tonic-gate 	/*
18060Sstevel@tonic-gate 	 * Check if it's an IPv4 addr
18070Sstevel@tonic-gate 	 */
18080Sstevel@tonic-gate 	if (nb->len != sizeof (struct sockaddr_in))
18090Sstevel@tonic-gate 		return (0);
18100Sstevel@tonic-gate 
18110Sstevel@tonic-gate 	(void) memcpy(&claddr,
18126859Sth199096 	    /* LINTED pointer alignment */
18136859Sth199096 	    &((struct sockaddr_in *)nb->buf)->sin_addr.s_addr,
18146859Sth199096 	    sizeof (struct in_addr));
18150Sstevel@tonic-gate 	claddr = ntohl(claddr);
18160Sstevel@tonic-gate 
18170Sstevel@tonic-gate 	mp = strchr(name, '/');
18180Sstevel@tonic-gate 	if (mp)
18190Sstevel@tonic-gate 		*mp++ = '\0';
18200Sstevel@tonic-gate 
18210Sstevel@tonic-gate 	if (isdigit(*name)) {
18220Sstevel@tonic-gate 		/*
18230Sstevel@tonic-gate 		 * Convert a dotted IP address
18240Sstevel@tonic-gate 		 * to an IP address. The conversion
18250Sstevel@tonic-gate 		 * is not the same as that in inet_addr().
18260Sstevel@tonic-gate 		 */
18270Sstevel@tonic-gate 		p = name;
18280Sstevel@tonic-gate 		addr = 0;
18290Sstevel@tonic-gate 		for (i = 0; i < 4; i++) {
18300Sstevel@tonic-gate 			addr |= atoi(p) << ((3-i) * 8);
18310Sstevel@tonic-gate 			p = strchr(p, '.');
18320Sstevel@tonic-gate 			if (p == NULL)
18330Sstevel@tonic-gate 				break;
18340Sstevel@tonic-gate 			p++;
18350Sstevel@tonic-gate 		}
18360Sstevel@tonic-gate 	} else {
18370Sstevel@tonic-gate 		/*
18380Sstevel@tonic-gate 		 * Turn the netname into
18390Sstevel@tonic-gate 		 * an IP address.
18400Sstevel@tonic-gate 		 */
18410Sstevel@tonic-gate 		np = getnetbyname_r(name, &n, buff, sizeof (buff));
18420Sstevel@tonic-gate 		if (np == NULL) {
18430Sstevel@tonic-gate 			syslog(LOG_DEBUG, "getnetbyname_r: %s: %m", name);
18440Sstevel@tonic-gate 			return (0);
18450Sstevel@tonic-gate 		}
18460Sstevel@tonic-gate 		addr = np->n_net;
18470Sstevel@tonic-gate 	}
18480Sstevel@tonic-gate 
18490Sstevel@tonic-gate 	/*
18500Sstevel@tonic-gate 	 * If the mask is specified explicitly then
18510Sstevel@tonic-gate 	 * use that value, e.g.
18520Sstevel@tonic-gate 	 *
18530Sstevel@tonic-gate 	 *    @109.104.56/28
18540Sstevel@tonic-gate 	 *
18550Sstevel@tonic-gate 	 * otherwise assume a mask from the zero octets
18560Sstevel@tonic-gate 	 * in the least significant bits of the address, e.g.
18570Sstevel@tonic-gate 	 *
18580Sstevel@tonic-gate 	 *   @109.104  or  @109.104.0.0
18590Sstevel@tonic-gate 	 */
18600Sstevel@tonic-gate 	if (mp) {
18610Sstevel@tonic-gate 		bits = atoi(mp);
18620Sstevel@tonic-gate 		mask = bits ? ~0 << ((sizeof (struct in_addr) * NBBY) - bits)
18636859Sth199096 		    : 0;
18640Sstevel@tonic-gate 		addr &= mask;
18650Sstevel@tonic-gate 	} else {
18667997SThomas.Haynes@Sun.COM 		if ((addr & IN_CLASSA_HOST) == 0)
18677997SThomas.Haynes@Sun.COM 			mask = IN_CLASSA_NET;
18687997SThomas.Haynes@Sun.COM 		else if ((addr & IN_CLASSB_HOST) == 0)
18697997SThomas.Haynes@Sun.COM 			mask = IN_CLASSB_NET;
18707997SThomas.Haynes@Sun.COM 		else if ((addr & IN_CLASSC_HOST) == 0)
18717997SThomas.Haynes@Sun.COM 			mask = IN_CLASSC_NET;
18727997SThomas.Haynes@Sun.COM 		else
18737997SThomas.Haynes@Sun.COM 			mask = IN_CLASSE_NET;
18740Sstevel@tonic-gate 	}
18750Sstevel@tonic-gate 
18760Sstevel@tonic-gate 	return ((claddr & mask) == addr);
18770Sstevel@tonic-gate }
18780Sstevel@tonic-gate 
18790Sstevel@tonic-gate 
18800Sstevel@tonic-gate static char *optlist[] = {
18810Sstevel@tonic-gate #define	OPT_RO		0
18820Sstevel@tonic-gate 	SHOPT_RO,
18830Sstevel@tonic-gate #define	OPT_RW		1
18840Sstevel@tonic-gate 	SHOPT_RW,
18850Sstevel@tonic-gate #define	OPT_ROOT	2
18860Sstevel@tonic-gate 	SHOPT_ROOT,
18870Sstevel@tonic-gate #define	OPT_SECURE	3
18880Sstevel@tonic-gate 	SHOPT_SECURE,
18890Sstevel@tonic-gate #define	OPT_ANON	4
18900Sstevel@tonic-gate 	SHOPT_ANON,
18910Sstevel@tonic-gate #define	OPT_WINDOW	5
18920Sstevel@tonic-gate 	SHOPT_WINDOW,
18930Sstevel@tonic-gate #define	OPT_NOSUID	6
18940Sstevel@tonic-gate 	SHOPT_NOSUID,
18950Sstevel@tonic-gate #define	OPT_ACLOK	7
18960Sstevel@tonic-gate 	SHOPT_ACLOK,
18970Sstevel@tonic-gate #define	OPT_SEC		8
18980Sstevel@tonic-gate 	SHOPT_SEC,
18997961SNatalie.Li@Sun.COM #define	OPT_NONE	9
19007961SNatalie.Li@Sun.COM 	SHOPT_NONE,
19010Sstevel@tonic-gate 	NULL
19020Sstevel@tonic-gate };
19030Sstevel@tonic-gate 
19040Sstevel@tonic-gate static int
19050Sstevel@tonic-gate map_flavor(char *str)
19060Sstevel@tonic-gate {
19070Sstevel@tonic-gate 	seconfig_t sec;
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 	if (nfs_getseconfig_byname(str, &sec))
19100Sstevel@tonic-gate 		return (-1);
19110Sstevel@tonic-gate 
19120Sstevel@tonic-gate 	return (sec.sc_nfsnum);
19130Sstevel@tonic-gate }
19140Sstevel@tonic-gate 
19150Sstevel@tonic-gate /*
19160Sstevel@tonic-gate  * If the option string contains a "sec="
19170Sstevel@tonic-gate  * option, then use new option syntax.
19180Sstevel@tonic-gate  */
19190Sstevel@tonic-gate static int
19200Sstevel@tonic-gate newopts(char *opts)
19210Sstevel@tonic-gate {
19220Sstevel@tonic-gate 	char *head, *p, *val;
19230Sstevel@tonic-gate 
19240Sstevel@tonic-gate 	if (!opts || *opts == '\0')
19250Sstevel@tonic-gate 		return (0);
19260Sstevel@tonic-gate 
19270Sstevel@tonic-gate 	head = strdup(opts);
19280Sstevel@tonic-gate 	if (head == NULL) {
19290Sstevel@tonic-gate 		syslog(LOG_ERR, "opts: no memory");
19300Sstevel@tonic-gate 		return (0);
19310Sstevel@tonic-gate 	}
19320Sstevel@tonic-gate 
19330Sstevel@tonic-gate 	p = head;
19340Sstevel@tonic-gate 	while (*p) {
19350Sstevel@tonic-gate 		if (getsubopt(&p, optlist, &val) == OPT_SEC) {
19360Sstevel@tonic-gate 			free(head);
19370Sstevel@tonic-gate 			return (1);
19380Sstevel@tonic-gate 		}
19390Sstevel@tonic-gate 	}
19400Sstevel@tonic-gate 
19410Sstevel@tonic-gate 	free(head);
19420Sstevel@tonic-gate 	return (0);
19430Sstevel@tonic-gate }
19440Sstevel@tonic-gate 
19450Sstevel@tonic-gate /*
19460Sstevel@tonic-gate  * Given an export and the clients hostname(s)
19470Sstevel@tonic-gate  * determine the security flavors that this
19480Sstevel@tonic-gate  * client is permitted to use.
19490Sstevel@tonic-gate  *
19500Sstevel@tonic-gate  * This routine is called only for "old" syntax, i.e.
19510Sstevel@tonic-gate  * only one security flavor is allowed.  So we need
19520Sstevel@tonic-gate  * to determine two things: the particular flavor,
19530Sstevel@tonic-gate  * and whether the client is allowed to use this
19540Sstevel@tonic-gate  * flavor, i.e. is in the access list.
19550Sstevel@tonic-gate  *
19560Sstevel@tonic-gate  * Note that if there is no access list, then the
19570Sstevel@tonic-gate  * default is that access is granted.
19580Sstevel@tonic-gate  */
19590Sstevel@tonic-gate static int
1960*11211SThomas.Haynes@Sun.COM getclientsflavors_old(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
1961*11211SThomas.Haynes@Sun.COM     struct nd_hostservlist **clnames, int *flavors)
19620Sstevel@tonic-gate {
19630Sstevel@tonic-gate 	char *opts, *p, *val;
19647961SNatalie.Li@Sun.COM 	boolean_t ok = B_FALSE;
19650Sstevel@tonic-gate 	int defaultaccess = 1;
19667961SNatalie.Li@Sun.COM 	boolean_t reject = B_FALSE;
19670Sstevel@tonic-gate 
19680Sstevel@tonic-gate 	opts = strdup(sh->sh_opts);
19690Sstevel@tonic-gate 	if (opts == NULL) {
19700Sstevel@tonic-gate 		syslog(LOG_ERR, "getclientsflavors: no memory");
19710Sstevel@tonic-gate 		return (0);
19720Sstevel@tonic-gate 	}
19730Sstevel@tonic-gate 
19740Sstevel@tonic-gate 	flavors[0] = AUTH_SYS;
19750Sstevel@tonic-gate 	p = opts;
19760Sstevel@tonic-gate 
19770Sstevel@tonic-gate 	while (*p) {
19780Sstevel@tonic-gate 
19790Sstevel@tonic-gate 		switch (getsubopt(&p, optlist, &val)) {
19800Sstevel@tonic-gate 		case OPT_SECURE:
19810Sstevel@tonic-gate 			flavors[0] = AUTH_DES;
19820Sstevel@tonic-gate 			break;
19830Sstevel@tonic-gate 
19840Sstevel@tonic-gate 		case OPT_RO:
19850Sstevel@tonic-gate 		case OPT_RW:
19860Sstevel@tonic-gate 			defaultaccess = 0;
1987*11211SThomas.Haynes@Sun.COM 			if (in_access_list(transp, nb, clnames, val))
19880Sstevel@tonic-gate 				ok++;
19890Sstevel@tonic-gate 			break;
19907961SNatalie.Li@Sun.COM 
19917961SNatalie.Li@Sun.COM 		case OPT_NONE:
19927961SNatalie.Li@Sun.COM 			defaultaccess = 0;
1993*11211SThomas.Haynes@Sun.COM 			if (in_access_list(transp, nb, clnames, val))
19947961SNatalie.Li@Sun.COM 				reject = B_TRUE;
19950Sstevel@tonic-gate 		}
19960Sstevel@tonic-gate 	}
19970Sstevel@tonic-gate 
19980Sstevel@tonic-gate 	free(opts);
19990Sstevel@tonic-gate 
20007961SNatalie.Li@Sun.COM 	/* none takes precedence over everything else */
20017961SNatalie.Li@Sun.COM 	if (reject)
20027961SNatalie.Li@Sun.COM 		ok = B_TRUE;
20037961SNatalie.Li@Sun.COM 
20040Sstevel@tonic-gate 	return (defaultaccess || ok);
20050Sstevel@tonic-gate }
20060Sstevel@tonic-gate 
20070Sstevel@tonic-gate /*
20080Sstevel@tonic-gate  * Given an export and the clients hostname(s)
20090Sstevel@tonic-gate  * determine the security flavors that this
20100Sstevel@tonic-gate  * client is permitted to use.
20110Sstevel@tonic-gate  *
20120Sstevel@tonic-gate  * This is somewhat more complicated than the "old"
20130Sstevel@tonic-gate  * routine because the options may contain multiple
20140Sstevel@tonic-gate  * security flavors (sec=) each with its own access
20150Sstevel@tonic-gate  * lists.  So a client could be granted access based
20160Sstevel@tonic-gate  * on a number of security flavors.  Note that the
20170Sstevel@tonic-gate  * type of access might not always be the same, the
20180Sstevel@tonic-gate  * client may get readonly access with one flavor
20190Sstevel@tonic-gate  * and readwrite with another, however the client
20200Sstevel@tonic-gate  * is not told this detail, it gets only the list
20210Sstevel@tonic-gate  * of flavors, and only if the client is using
20220Sstevel@tonic-gate  * version 3 of the mount protocol.
20230Sstevel@tonic-gate  */
20240Sstevel@tonic-gate static int
2025*11211SThomas.Haynes@Sun.COM getclientsflavors_new(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
2026*11211SThomas.Haynes@Sun.COM     struct nd_hostservlist **clnames, int *flavors)
20270Sstevel@tonic-gate {
20280Sstevel@tonic-gate 	char *opts, *p, *val;
20290Sstevel@tonic-gate 	char *lasts;
20300Sstevel@tonic-gate 	char *f;
20317961SNatalie.Li@Sun.COM 	boolean_t access_ok;
20327961SNatalie.Li@Sun.COM 	int count, c, perm;
20337961SNatalie.Li@Sun.COM 	boolean_t reject = B_FALSE;
20340Sstevel@tonic-gate 
20350Sstevel@tonic-gate 	opts = strdup(sh->sh_opts);
20360Sstevel@tonic-gate 	if (opts == NULL) {
20370Sstevel@tonic-gate 		syslog(LOG_ERR, "getclientsflavors: no memory");
20380Sstevel@tonic-gate 		return (0);
20390Sstevel@tonic-gate 	}
20400Sstevel@tonic-gate 
20410Sstevel@tonic-gate 	p = opts;
20427961SNatalie.Li@Sun.COM 	perm = count = c = 0;
20430Sstevel@tonic-gate 	/* default access is rw */
20447961SNatalie.Li@Sun.COM 	access_ok = B_TRUE;
20450Sstevel@tonic-gate 
20460Sstevel@tonic-gate 	while (*p) {
20470Sstevel@tonic-gate 		switch (getsubopt(&p, optlist, &val)) {
20480Sstevel@tonic-gate 		case OPT_SEC:
20490Sstevel@tonic-gate 			/*
20500Sstevel@tonic-gate 			 * Before a new sec=xxx option, check if we need
20510Sstevel@tonic-gate 			 * to move the c index back to the previous count.
20520Sstevel@tonic-gate 			 */
20530Sstevel@tonic-gate 			if (!access_ok) {
20540Sstevel@tonic-gate 				c = count;
20550Sstevel@tonic-gate 			}
20560Sstevel@tonic-gate 
20570Sstevel@tonic-gate 			/* get all the sec=f1[:f2] flavors */
20580Sstevel@tonic-gate 			while ((f = strtok_r(val, ":", &lasts))
20596859Sth199096 			    != NULL) {
20600Sstevel@tonic-gate 				flavors[c++] = map_flavor(f);
20610Sstevel@tonic-gate 				val = NULL;
20620Sstevel@tonic-gate 			}
2063*11211SThomas.Haynes@Sun.COM 
20640Sstevel@tonic-gate 			/* for a new sec=xxx option, default is rw access */
20657961SNatalie.Li@Sun.COM 			access_ok = B_TRUE;
20660Sstevel@tonic-gate 			break;
20670Sstevel@tonic-gate 
20680Sstevel@tonic-gate 		case OPT_RO:
20690Sstevel@tonic-gate 		case OPT_RW:
2070*11211SThomas.Haynes@Sun.COM 			if (in_access_list(transp, nb, clnames, val)) {
20710Sstevel@tonic-gate 				count = c;
20727961SNatalie.Li@Sun.COM 				access_ok = B_TRUE;
20730Sstevel@tonic-gate 			} else {
20747961SNatalie.Li@Sun.COM 				access_ok = B_FALSE;
20750Sstevel@tonic-gate 			}
20760Sstevel@tonic-gate 			break;
20777961SNatalie.Li@Sun.COM 
20787961SNatalie.Li@Sun.COM 		case OPT_NONE:
2079*11211SThomas.Haynes@Sun.COM 			if (in_access_list(transp, nb, clnames, val))
20807961SNatalie.Li@Sun.COM 				reject = B_TRUE; /* none overides rw/ro */
20817961SNatalie.Li@Sun.COM 			break;
20820Sstevel@tonic-gate 		}
20830Sstevel@tonic-gate 	}
20840Sstevel@tonic-gate 
20857961SNatalie.Li@Sun.COM 	if (reject)
20867961SNatalie.Li@Sun.COM 		access_ok = B_FALSE;
20877961SNatalie.Li@Sun.COM 
20887961SNatalie.Li@Sun.COM 	if (!access_ok)
20890Sstevel@tonic-gate 		c = count;
20907961SNatalie.Li@Sun.COM 
20910Sstevel@tonic-gate 	free(opts);
20920Sstevel@tonic-gate 
20930Sstevel@tonic-gate 	return (c);
20940Sstevel@tonic-gate }
20950Sstevel@tonic-gate 
20960Sstevel@tonic-gate /*
20970Sstevel@tonic-gate  * This is a tricky piece of code that parses the
20980Sstevel@tonic-gate  * share options looking for a match on the auth
20990Sstevel@tonic-gate  * flavor that the client is using. If it finds
21000Sstevel@tonic-gate  * a match, then the client is given ro, rw, or
21010Sstevel@tonic-gate  * no access depending whether it is in the access
21020Sstevel@tonic-gate  * list.  There is a special case for "secure"
21030Sstevel@tonic-gate  * flavor.  Other flavors are values of the new "sec=" option.
21040Sstevel@tonic-gate  */
21050Sstevel@tonic-gate int
2106*11211SThomas.Haynes@Sun.COM check_client(share_t *sh, struct netbuf *nb,
21070Sstevel@tonic-gate     struct nd_hostservlist *clnames, int flavor)
21080Sstevel@tonic-gate {
21090Sstevel@tonic-gate 	if (newopts(sh->sh_opts))
2110*11211SThomas.Haynes@Sun.COM 		return (check_client_new(sh, NULL, &nb, &clnames, flavor));
21110Sstevel@tonic-gate 	else
2112*11211SThomas.Haynes@Sun.COM 		return (check_client_old(sh, NULL, &nb, &clnames, flavor));
21130Sstevel@tonic-gate }
21140Sstevel@tonic-gate 
21150Sstevel@tonic-gate static int
2116*11211SThomas.Haynes@Sun.COM check_client_old(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
2117*11211SThomas.Haynes@Sun.COM     struct nd_hostservlist **clnames, int flavor)
21180Sstevel@tonic-gate {
21190Sstevel@tonic-gate 	char *opts, *p, *val;
21200Sstevel@tonic-gate 	int match;	/* Set when a flavor is matched */
21210Sstevel@tonic-gate 	int perm = 0;	/* Set when "ro", "rw" or "root" is matched */
21220Sstevel@tonic-gate 	int list = 0;	/* Set when "ro", "rw" is found */
21230Sstevel@tonic-gate 	int ro_val = 0;	/* Set if ro option is 'ro=' */
21240Sstevel@tonic-gate 	int rw_val = 0;	/* Set if rw option is 'rw=' */
21257961SNatalie.Li@Sun.COM 	boolean_t reject = B_FALSE; /* if none= contains the host */
21260Sstevel@tonic-gate 
21270Sstevel@tonic-gate 	opts = strdup(sh->sh_opts);
21280Sstevel@tonic-gate 	if (opts == NULL) {
21290Sstevel@tonic-gate 		syslog(LOG_ERR, "check_client: no memory");
21300Sstevel@tonic-gate 		return (0);
21310Sstevel@tonic-gate 	}
21320Sstevel@tonic-gate 
21330Sstevel@tonic-gate 	p = opts;
21340Sstevel@tonic-gate 	match = AUTH_UNIX;
21350Sstevel@tonic-gate 
21360Sstevel@tonic-gate 	while (*p) {
21370Sstevel@tonic-gate 		switch (getsubopt(&p, optlist, &val)) {
21380Sstevel@tonic-gate 
21390Sstevel@tonic-gate 		case OPT_SECURE:
21400Sstevel@tonic-gate 			match = AUTH_DES;
21410Sstevel@tonic-gate 			break;
21420Sstevel@tonic-gate 
21430Sstevel@tonic-gate 		case OPT_RO:
21440Sstevel@tonic-gate 			list++;
21450Sstevel@tonic-gate 			if (val) ro_val++;
2146*11211SThomas.Haynes@Sun.COM 			if (in_access_list(transp, nb, clnames, val))
21470Sstevel@tonic-gate 				perm |= NFSAUTH_RO;
21480Sstevel@tonic-gate 			break;
21490Sstevel@tonic-gate 
21500Sstevel@tonic-gate 		case OPT_RW:
21510Sstevel@tonic-gate 			list++;
21520Sstevel@tonic-gate 			if (val) rw_val++;
2153*11211SThomas.Haynes@Sun.COM 			if (in_access_list(transp, nb, clnames, val))
21540Sstevel@tonic-gate 				perm |= NFSAUTH_RW;
21550Sstevel@tonic-gate 			break;
21560Sstevel@tonic-gate 
21570Sstevel@tonic-gate 		case OPT_ROOT:
21580Sstevel@tonic-gate 			/*
21590Sstevel@tonic-gate 			 * Check if the client is in
21600Sstevel@tonic-gate 			 * the root list. Only valid
21610Sstevel@tonic-gate 			 * for AUTH_SYS.
21620Sstevel@tonic-gate 			 */
21630Sstevel@tonic-gate 			if (flavor != AUTH_SYS)
21640Sstevel@tonic-gate 				break;
21650Sstevel@tonic-gate 
21660Sstevel@tonic-gate 			if (val == NULL || *val == '\0')
21670Sstevel@tonic-gate 				break;
21680Sstevel@tonic-gate 
2169*11211SThomas.Haynes@Sun.COM 			if (in_access_list(transp, nb, clnames, val))
21700Sstevel@tonic-gate 				perm |= NFSAUTH_ROOT;
21710Sstevel@tonic-gate 			break;
21727961SNatalie.Li@Sun.COM 
21737961SNatalie.Li@Sun.COM 		case OPT_NONE:
21747961SNatalie.Li@Sun.COM 			/*
21757961SNatalie.Li@Sun.COM 			 * Check if  the client should have no access
21767961SNatalie.Li@Sun.COM 			 * to this share at all. This option behaves
21777961SNatalie.Li@Sun.COM 			 * more like "root" than either "rw" or "ro".
21787961SNatalie.Li@Sun.COM 			 */
2179*11211SThomas.Haynes@Sun.COM 			if (in_access_list(transp, nb, clnames, val))
21807961SNatalie.Li@Sun.COM 				reject = B_TRUE;
21817961SNatalie.Li@Sun.COM 			break;
21820Sstevel@tonic-gate 		}
21830Sstevel@tonic-gate 	}
21840Sstevel@tonic-gate 
21850Sstevel@tonic-gate 	free(opts);
21860Sstevel@tonic-gate 
21877961SNatalie.Li@Sun.COM 	if (flavor != match || reject)
21880Sstevel@tonic-gate 		return (NFSAUTH_DENIED);
21890Sstevel@tonic-gate 
21900Sstevel@tonic-gate 	if (list) {
21910Sstevel@tonic-gate 		/*
21920Sstevel@tonic-gate 		 * If the client doesn't match an "ro" or "rw"
21930Sstevel@tonic-gate 		 * list then set no access.
21940Sstevel@tonic-gate 		 */
21950Sstevel@tonic-gate 		if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0)
21960Sstevel@tonic-gate 			perm |= NFSAUTH_DENIED;
21970Sstevel@tonic-gate 	} else {
21980Sstevel@tonic-gate 		/*
21990Sstevel@tonic-gate 		 * The client matched a flavor entry that
22000Sstevel@tonic-gate 		 * has no explicit "rw" or "ro" determination.
22010Sstevel@tonic-gate 		 * Default it to "rw".
22020Sstevel@tonic-gate 		 */
22030Sstevel@tonic-gate 		perm |= NFSAUTH_RW;
22040Sstevel@tonic-gate 	}
22050Sstevel@tonic-gate 
22060Sstevel@tonic-gate 
22070Sstevel@tonic-gate 	/*
22080Sstevel@tonic-gate 	 * The client may show up in both ro= and rw=
22090Sstevel@tonic-gate 	 * lists.  If so, then turn off the RO access
22100Sstevel@tonic-gate 	 * bit leaving RW access.
22110Sstevel@tonic-gate 	 */
22120Sstevel@tonic-gate 	if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) {
22130Sstevel@tonic-gate 		/*
22140Sstevel@tonic-gate 		 * Logically cover all permutations of rw=,ro=.
22150Sstevel@tonic-gate 		 * In the case where, rw,ro=<host> we would like
22160Sstevel@tonic-gate 		 * to remove RW access for the host.  In all other cases
22170Sstevel@tonic-gate 		 * RW wins the precedence battle.
22180Sstevel@tonic-gate 		 */
22190Sstevel@tonic-gate 		if (!rw_val && ro_val) {
22200Sstevel@tonic-gate 			perm &= ~(NFSAUTH_RW);
22210Sstevel@tonic-gate 		} else {
22220Sstevel@tonic-gate 			perm &= ~(NFSAUTH_RO);
22230Sstevel@tonic-gate 		}
22240Sstevel@tonic-gate 	}
22250Sstevel@tonic-gate 
22260Sstevel@tonic-gate 	return (perm);
22270Sstevel@tonic-gate }
22280Sstevel@tonic-gate 
22290Sstevel@tonic-gate /*
22300Sstevel@tonic-gate  * Check if the client has access by using a flavor different from
22310Sstevel@tonic-gate  * the given "flavor". If "flavor" is not in the flavor list,
22320Sstevel@tonic-gate  * return TRUE to indicate that this "flavor" is a wrong sec.
22330Sstevel@tonic-gate  */
22340Sstevel@tonic-gate static bool_t
2235*11211SThomas.Haynes@Sun.COM is_wrongsec(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
2236*11211SThomas.Haynes@Sun.COM 	struct nd_hostservlist **clnames, int flavor)
22370Sstevel@tonic-gate {
22380Sstevel@tonic-gate 	int flavor_list[MAX_FLAVORS];
22390Sstevel@tonic-gate 	int flavor_count, i;
22400Sstevel@tonic-gate 
22410Sstevel@tonic-gate 	/* get the flavor list that the client has access with */
2242*11211SThomas.Haynes@Sun.COM 	flavor_count = getclientsflavors_new(sh, transp, nb,
2243*11211SThomas.Haynes@Sun.COM 	    clnames, flavor_list);
22440Sstevel@tonic-gate 
22450Sstevel@tonic-gate 	if (flavor_count == 0)
22460Sstevel@tonic-gate 		return (FALSE);
22470Sstevel@tonic-gate 
22480Sstevel@tonic-gate 	/*
22490Sstevel@tonic-gate 	 * Check if the given "flavor" is in the flavor_list.
22500Sstevel@tonic-gate 	 */
22510Sstevel@tonic-gate 	for (i = 0; i < flavor_count; i++) {
22520Sstevel@tonic-gate 		if (flavor == flavor_list[i])
22530Sstevel@tonic-gate 			return (FALSE);
22540Sstevel@tonic-gate 	}
22550Sstevel@tonic-gate 
22560Sstevel@tonic-gate 	/*
22570Sstevel@tonic-gate 	 * If "flavor" is not in the flavor_list, return TRUE to indicate
22580Sstevel@tonic-gate 	 * that the client should have access by using a security flavor
22590Sstevel@tonic-gate 	 * different from this "flavor".
22600Sstevel@tonic-gate 	 */
22610Sstevel@tonic-gate 	return (TRUE);
22620Sstevel@tonic-gate }
22630Sstevel@tonic-gate 
22640Sstevel@tonic-gate /*
22650Sstevel@tonic-gate  * Given an export and the client's hostname, we
22660Sstevel@tonic-gate  * check the security options to see whether the
22670Sstevel@tonic-gate  * client is allowed to use the given security flavor.
22680Sstevel@tonic-gate  *
22690Sstevel@tonic-gate  * The strategy is to proceed through the options looking
22700Sstevel@tonic-gate  * for a flavor match, then pay attention to the ro, rw,
22710Sstevel@tonic-gate  * and root options.
22720Sstevel@tonic-gate  *
22730Sstevel@tonic-gate  * Note that an entry may list several flavors in a
22740Sstevel@tonic-gate  * single entry, e.g.
22750Sstevel@tonic-gate  *
22760Sstevel@tonic-gate  *   sec=krb5,rw=clnt1:clnt2,ro,sec=sys,ro
22770Sstevel@tonic-gate  *
22780Sstevel@tonic-gate  */
22790Sstevel@tonic-gate 
22800Sstevel@tonic-gate static int
2281*11211SThomas.Haynes@Sun.COM check_client_new(share_t *sh, SVCXPRT *transp, struct netbuf **nb,
2282*11211SThomas.Haynes@Sun.COM     struct nd_hostservlist **clnames, int flavor)
22830Sstevel@tonic-gate {
22840Sstevel@tonic-gate 	char *opts, *p, *val;
22850Sstevel@tonic-gate 	char *lasts;
22860Sstevel@tonic-gate 	char *f;
22870Sstevel@tonic-gate 	int match = 0;	/* Set when a flavor is matched */
22880Sstevel@tonic-gate 	int perm = 0;	/* Set when "ro", "rw" or "root" is matched */
22890Sstevel@tonic-gate 	int list = 0;	/* Set when "ro", "rw" is found */
22900Sstevel@tonic-gate 	int ro_val = 0;	/* Set if ro option is 'ro=' */
22910Sstevel@tonic-gate 	int rw_val = 0;	/* Set if rw option is 'rw=' */
22927961SNatalie.Li@Sun.COM 	boolean_t reject;
22930Sstevel@tonic-gate 
22940Sstevel@tonic-gate 	opts = strdup(sh->sh_opts);
22950Sstevel@tonic-gate 	if (opts == NULL) {
22960Sstevel@tonic-gate 		syslog(LOG_ERR, "check_client: no memory");
22970Sstevel@tonic-gate 		return (0);
22980Sstevel@tonic-gate 	}
22990Sstevel@tonic-gate 
23000Sstevel@tonic-gate 	p = opts;
23010Sstevel@tonic-gate 
23020Sstevel@tonic-gate 	while (*p) {
23030Sstevel@tonic-gate 		switch (getsubopt(&p, optlist, &val)) {
23040Sstevel@tonic-gate 
23050Sstevel@tonic-gate 		case OPT_SEC:
23060Sstevel@tonic-gate 			if (match)
23070Sstevel@tonic-gate 				goto done;
23080Sstevel@tonic-gate 
23090Sstevel@tonic-gate 			while ((f = strtok_r(val, ":", &lasts))
23106859Sth199096 			    != NULL) {
23110Sstevel@tonic-gate 				if (flavor == map_flavor(f)) {
23120Sstevel@tonic-gate 					match = 1;
23130Sstevel@tonic-gate 					break;
23140Sstevel@tonic-gate 				}
23150Sstevel@tonic-gate 				val = NULL;
23160Sstevel@tonic-gate 			}
23170Sstevel@tonic-gate 			break;
23180Sstevel@tonic-gate 
23190Sstevel@tonic-gate 		case OPT_RO:
23200Sstevel@tonic-gate 			if (!match)
23210Sstevel@tonic-gate 				break;
23220Sstevel@tonic-gate 
23230Sstevel@tonic-gate 			list++;
23240Sstevel@tonic-gate 			if (val) ro_val++;
2325*11211SThomas.Haynes@Sun.COM 			if (in_access_list(transp, nb, clnames, val))
23260Sstevel@tonic-gate 				perm |= NFSAUTH_RO;
23270Sstevel@tonic-gate 			break;
23280Sstevel@tonic-gate 
23290Sstevel@tonic-gate 		case OPT_RW:
23300Sstevel@tonic-gate 			if (!match)
23310Sstevel@tonic-gate 				break;
23320Sstevel@tonic-gate 
23330Sstevel@tonic-gate 			list++;
23340Sstevel@tonic-gate 			if (val) rw_val++;
2335*11211SThomas.Haynes@Sun.COM 			if (in_access_list(transp, nb, clnames, val))
23360Sstevel@tonic-gate 				perm |= NFSAUTH_RW;
23370Sstevel@tonic-gate 			break;
23380Sstevel@tonic-gate 
23390Sstevel@tonic-gate 		case OPT_ROOT:
23400Sstevel@tonic-gate 			/*
23410Sstevel@tonic-gate 			 * Check if the client is in
23420Sstevel@tonic-gate 			 * the root list. Only valid
23430Sstevel@tonic-gate 			 * for AUTH_SYS.
23440Sstevel@tonic-gate 			 */
23450Sstevel@tonic-gate 			if (flavor != AUTH_SYS)
23460Sstevel@tonic-gate 				break;
23470Sstevel@tonic-gate 
23480Sstevel@tonic-gate 			if (!match)
23490Sstevel@tonic-gate 				break;
23500Sstevel@tonic-gate 
23510Sstevel@tonic-gate 			if (val == NULL || *val == '\0')
23520Sstevel@tonic-gate 				break;
23530Sstevel@tonic-gate 
2354*11211SThomas.Haynes@Sun.COM 			if (in_access_list(transp, nb, clnames, val))
23550Sstevel@tonic-gate 				perm |= NFSAUTH_ROOT;
23560Sstevel@tonic-gate 			break;
23577961SNatalie.Li@Sun.COM 
23587961SNatalie.Li@Sun.COM 		case OPT_NONE:
23597961SNatalie.Li@Sun.COM 			/*
23607961SNatalie.Li@Sun.COM 			 * Check if  the client should have no access
23617961SNatalie.Li@Sun.COM 			 * to this share at all. This option behaves
23627961SNatalie.Li@Sun.COM 			 * more like "root" than either "rw" or "ro".
23637961SNatalie.Li@Sun.COM 			 */
2364*11211SThomas.Haynes@Sun.COM 			if (in_access_list(transp, nb, clnames, val))
23657961SNatalie.Li@Sun.COM 				perm |= NFSAUTH_DENIED;
23667961SNatalie.Li@Sun.COM 			break;
23670Sstevel@tonic-gate 		}
23680Sstevel@tonic-gate 	}
23690Sstevel@tonic-gate 
23700Sstevel@tonic-gate done:
23710Sstevel@tonic-gate 	/*
23720Sstevel@tonic-gate 	 * If no match then set the perm accordingly
23730Sstevel@tonic-gate 	 */
23747961SNatalie.Li@Sun.COM 	if (!match || perm & NFSAUTH_DENIED)
23750Sstevel@tonic-gate 		return (NFSAUTH_DENIED);
23760Sstevel@tonic-gate 
23770Sstevel@tonic-gate 	if (list) {
23780Sstevel@tonic-gate 		/*
23790Sstevel@tonic-gate 		 * If the client doesn't match an "ro" or "rw" list then
23800Sstevel@tonic-gate 		 * check if it may have access by using a different flavor.
23810Sstevel@tonic-gate 		 * If so, return NFSAUTH_WRONGSEC.
23820Sstevel@tonic-gate 		 * If not, return NFSAUTH_DENIED.
23830Sstevel@tonic-gate 		 */
23840Sstevel@tonic-gate 		if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) {
2385*11211SThomas.Haynes@Sun.COM 			if (is_wrongsec(sh, transp, nb, clnames, flavor))
23860Sstevel@tonic-gate 				perm |= NFSAUTH_WRONGSEC;
23870Sstevel@tonic-gate 			else
23880Sstevel@tonic-gate 				perm |= NFSAUTH_DENIED;
23890Sstevel@tonic-gate 		}
23900Sstevel@tonic-gate 	} else {
23910Sstevel@tonic-gate 		/*
23920Sstevel@tonic-gate 		 * The client matched a flavor entry that
23930Sstevel@tonic-gate 		 * has no explicit "rw" or "ro" determination.
23940Sstevel@tonic-gate 		 * Make sure it defaults to "rw".
23950Sstevel@tonic-gate 		 */
23960Sstevel@tonic-gate 		perm |= NFSAUTH_RW;
23970Sstevel@tonic-gate 	}
23980Sstevel@tonic-gate 
23990Sstevel@tonic-gate 	/*
24000Sstevel@tonic-gate 	 * The client may show up in both ro= and rw=
24010Sstevel@tonic-gate 	 * lists.  If so, then turn off the RO access
24020Sstevel@tonic-gate 	 * bit leaving RW access.
24030Sstevel@tonic-gate 	 */
24040Sstevel@tonic-gate 	if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) {
24050Sstevel@tonic-gate 		/*
24060Sstevel@tonic-gate 		 * Logically cover all permutations of rw=,ro=.
24070Sstevel@tonic-gate 		 * In the case where, rw,ro=<host> we would like
24080Sstevel@tonic-gate 		 * to remove RW access for the host.  In all other cases
24090Sstevel@tonic-gate 		 * RW wins the precedence battle.
24100Sstevel@tonic-gate 		 */
24110Sstevel@tonic-gate 		if (!rw_val && ro_val) {
24120Sstevel@tonic-gate 			perm &= ~(NFSAUTH_RW);
24130Sstevel@tonic-gate 		} else {
24140Sstevel@tonic-gate 			perm &= ~(NFSAUTH_RO);
24150Sstevel@tonic-gate 		}
24160Sstevel@tonic-gate 	}
24170Sstevel@tonic-gate 
24180Sstevel@tonic-gate 	free(opts);
24190Sstevel@tonic-gate 
24200Sstevel@tonic-gate 	return (perm);
24210Sstevel@tonic-gate }
24220Sstevel@tonic-gate 
24230Sstevel@tonic-gate void
24240Sstevel@tonic-gate check_sharetab()
24250Sstevel@tonic-gate {
24260Sstevel@tonic-gate 	FILE *f;
24270Sstevel@tonic-gate 	struct stat st;
24280Sstevel@tonic-gate 	static timestruc_t last_sharetab_time;
24290Sstevel@tonic-gate 	timestruc_t prev_sharetab_time;
2430*11211SThomas.Haynes@Sun.COM 	share_t *sh;
24310Sstevel@tonic-gate 	struct sh_list *shp, *shp_prev;
24320Sstevel@tonic-gate 	int res, c = 0;
24330Sstevel@tonic-gate 
24340Sstevel@tonic-gate 	/*
24350Sstevel@tonic-gate 	 *  read in /etc/dfs/sharetab if it has changed
24360Sstevel@tonic-gate 	 */
24370Sstevel@tonic-gate 	if (stat(SHARETAB, &st) != 0) {
24380Sstevel@tonic-gate 		syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB);
24390Sstevel@tonic-gate 		return;
24400Sstevel@tonic-gate 	}
24410Sstevel@tonic-gate 
24420Sstevel@tonic-gate 	if (st.st_mtim.tv_sec == last_sharetab_time.tv_sec &&
24430Sstevel@tonic-gate 	    st.st_mtim.tv_nsec == last_sharetab_time.tv_nsec) {
24440Sstevel@tonic-gate 		/*
24450Sstevel@tonic-gate 		 * No change.
24460Sstevel@tonic-gate 		 */
24470Sstevel@tonic-gate 		return;
24480Sstevel@tonic-gate 	}
24490Sstevel@tonic-gate 
24500Sstevel@tonic-gate 	/*
24510Sstevel@tonic-gate 	 * Remember the mod time, then after getting the
24520Sstevel@tonic-gate 	 * write lock check again.  If another thread
24530Sstevel@tonic-gate 	 * already did the update, then there's no
24540Sstevel@tonic-gate 	 * work to do.
24550Sstevel@tonic-gate 	 */
24560Sstevel@tonic-gate 	prev_sharetab_time = last_sharetab_time;
24570Sstevel@tonic-gate 
24580Sstevel@tonic-gate 	(void) rw_wrlock(&sharetab_lock);
24590Sstevel@tonic-gate 
24600Sstevel@tonic-gate 	if (prev_sharetab_time.tv_sec != last_sharetab_time.tv_sec ||
24610Sstevel@tonic-gate 	    prev_sharetab_time.tv_nsec != last_sharetab_time.tv_nsec) {
24620Sstevel@tonic-gate 		(void) rw_unlock(&sharetab_lock);
24630Sstevel@tonic-gate 		return;
24640Sstevel@tonic-gate 	}
24650Sstevel@tonic-gate 
24663957Sth199096 	/*
24673957Sth199096 	 * Note that since the sharetab is now in memory
24683957Sth199096 	 * and a snapshot is taken, we no longer have to
24693957Sth199096 	 * lock the file.
24703957Sth199096 	 */
24713957Sth199096 	f = fopen(SHARETAB, "r");
24720Sstevel@tonic-gate 	if (f == NULL) {
24730Sstevel@tonic-gate 		syslog(LOG_ERR, "Cannot open %s: %m", SHARETAB);
24740Sstevel@tonic-gate 		(void) rw_unlock(&sharetab_lock);
24750Sstevel@tonic-gate 		return;
24760Sstevel@tonic-gate 	}
24770Sstevel@tonic-gate 
24780Sstevel@tonic-gate 	/*
24790Sstevel@tonic-gate 	 * Once we are sure /etc/dfs/sharetab has been
24800Sstevel@tonic-gate 	 * modified, flush netgroup cache entries.
24810Sstevel@tonic-gate 	 */
24820Sstevel@tonic-gate 	netgrp_cache_flush();
24830Sstevel@tonic-gate 
24840Sstevel@tonic-gate 	sh_free(share_list);			/* free old list */
24850Sstevel@tonic-gate 	share_list = NULL;
24860Sstevel@tonic-gate 
24870Sstevel@tonic-gate 	while ((res = getshare(f, &sh)) > 0) {
24880Sstevel@tonic-gate 		c++;
24890Sstevel@tonic-gate 		if (strcmp(sh->sh_fstype, "nfs") != 0)
24900Sstevel@tonic-gate 			continue;
24910Sstevel@tonic-gate 
24920Sstevel@tonic-gate 		shp = malloc(sizeof (*shp));
24930Sstevel@tonic-gate 		if (shp == NULL)
24940Sstevel@tonic-gate 			goto alloc_failed;
24950Sstevel@tonic-gate 		if (share_list == NULL)
24960Sstevel@tonic-gate 			share_list = shp;
24970Sstevel@tonic-gate 		else
24980Sstevel@tonic-gate 			/* LINTED not used before set */
24990Sstevel@tonic-gate 			shp_prev->shl_next = shp;
25000Sstevel@tonic-gate 		shp_prev = shp;
25010Sstevel@tonic-gate 		shp->shl_next = NULL;
25020Sstevel@tonic-gate 		shp->shl_sh = sharedup(sh);
25030Sstevel@tonic-gate 		if (shp->shl_sh == NULL)
25040Sstevel@tonic-gate 			goto alloc_failed;
25050Sstevel@tonic-gate 	}
2506*11211SThomas.Haynes@Sun.COM 
25070Sstevel@tonic-gate 	if (res < 0)
25080Sstevel@tonic-gate 		syslog(LOG_ERR, "%s: invalid at line %d\n",
25096859Sth199096 		    SHARETAB, c + 1);
25100Sstevel@tonic-gate 
25110Sstevel@tonic-gate 	if (stat(SHARETAB, &st) != 0) {
25120Sstevel@tonic-gate 		syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB);
25133701Sth199096 		(void) fclose(f);
25140Sstevel@tonic-gate 		(void) rw_unlock(&sharetab_lock);
25150Sstevel@tonic-gate 		return;
25160Sstevel@tonic-gate 	}
2517*11211SThomas.Haynes@Sun.COM 
25180Sstevel@tonic-gate 	last_sharetab_time = st.st_mtim;
25190Sstevel@tonic-gate 	(void) fclose(f);
25200Sstevel@tonic-gate 	(void) rw_unlock(&sharetab_lock);
2521*11211SThomas.Haynes@Sun.COM 
25220Sstevel@tonic-gate 	return;
25230Sstevel@tonic-gate 
25240Sstevel@tonic-gate alloc_failed:
2525*11211SThomas.Haynes@Sun.COM 
25260Sstevel@tonic-gate 	syslog(LOG_ERR, "check_sharetab: no memory");
25270Sstevel@tonic-gate 	sh_free(share_list);
25280Sstevel@tonic-gate 	share_list = NULL;
25290Sstevel@tonic-gate 	(void) fclose(f);
25300Sstevel@tonic-gate 	(void) rw_unlock(&sharetab_lock);
25310Sstevel@tonic-gate }
25320Sstevel@tonic-gate 
25330Sstevel@tonic-gate static void
25340Sstevel@tonic-gate sh_free(struct sh_list *shp)
25350Sstevel@tonic-gate {
25360Sstevel@tonic-gate 	register struct sh_list *next;
25370Sstevel@tonic-gate 
25380Sstevel@tonic-gate 	while (shp) {
25390Sstevel@tonic-gate 		sharefree(shp->shl_sh);
25400Sstevel@tonic-gate 		next = shp->shl_next;
25410Sstevel@tonic-gate 		free(shp);
25420Sstevel@tonic-gate 		shp = next;
25430Sstevel@tonic-gate 	}
25440Sstevel@tonic-gate }
25450Sstevel@tonic-gate 
25460Sstevel@tonic-gate 
25470Sstevel@tonic-gate /*
25480Sstevel@tonic-gate  * Remove an entry from mounted list
25490Sstevel@tonic-gate  */
25500Sstevel@tonic-gate static void
25510Sstevel@tonic-gate umount(struct svc_req *rqstp)
25520Sstevel@tonic-gate {
25530Sstevel@tonic-gate 	char *host, *path, *remove_path;
25540Sstevel@tonic-gate 	char rpath[MAXPATHLEN];
25550Sstevel@tonic-gate 	struct nd_hostservlist *clnames = NULL;
25560Sstevel@tonic-gate 	SVCXPRT *transp;
25570Sstevel@tonic-gate 	struct netbuf *nb;
25580Sstevel@tonic-gate 
25590Sstevel@tonic-gate 	transp = rqstp->rq_xprt;
25600Sstevel@tonic-gate 	path = NULL;
25610Sstevel@tonic-gate 	if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
25620Sstevel@tonic-gate 		svcerr_decode(transp);
25630Sstevel@tonic-gate 		return;
25640Sstevel@tonic-gate 	}
25650Sstevel@tonic-gate 	errno = 0;
25660Sstevel@tonic-gate 	if (!svc_sendreply(transp, xdr_void, (char *)NULL))
25670Sstevel@tonic-gate 		log_cant_reply(transp);
25680Sstevel@tonic-gate 
25690Sstevel@tonic-gate 	getclientsnames(transp, &nb, &clnames);
25700Sstevel@tonic-gate 	if (clnames == NULL) {
25710Sstevel@tonic-gate 		/*
25720Sstevel@tonic-gate 		 * Without the hostname we can't do audit or delete
25730Sstevel@tonic-gate 		 * this host from the mount entries.
25740Sstevel@tonic-gate 		 */
25750Sstevel@tonic-gate 		svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
25760Sstevel@tonic-gate 		return;
25770Sstevel@tonic-gate 	}
25780Sstevel@tonic-gate 	host = clnames->h_hostservs[0].h_host;
25790Sstevel@tonic-gate 
25800Sstevel@tonic-gate 	if (verbose)
25810Sstevel@tonic-gate 		syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path);
25820Sstevel@tonic-gate 
25830Sstevel@tonic-gate 	audit_mountd_umount(host, path);
25840Sstevel@tonic-gate 
25850Sstevel@tonic-gate 	remove_path = rpath;	/* assume we will use the cannonical path */
25860Sstevel@tonic-gate 	if (realpath(path, rpath) == NULL) {
25870Sstevel@tonic-gate 		if (verbose)
25880Sstevel@tonic-gate 			syslog(LOG_WARNING, "UNMOUNT: realpath: %s: %m ", path);
25890Sstevel@tonic-gate 		remove_path = path;	/* use path provided instead */
25900Sstevel@tonic-gate 	}
25910Sstevel@tonic-gate 
25920Sstevel@tonic-gate 	mntlist_delete(host, remove_path);	/* remove from mount list */
25930Sstevel@tonic-gate 
25940Sstevel@tonic-gate 	svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
25950Sstevel@tonic-gate 	netdir_free(clnames, ND_HOSTSERVLIST);
25960Sstevel@tonic-gate }
25970Sstevel@tonic-gate 
25980Sstevel@tonic-gate /*
25990Sstevel@tonic-gate  * Remove all entries for one machine from mounted list
26000Sstevel@tonic-gate  */
26010Sstevel@tonic-gate static void
26020Sstevel@tonic-gate umountall(struct svc_req *rqstp)
26030Sstevel@tonic-gate {
26040Sstevel@tonic-gate 	struct nd_hostservlist *clnames = NULL;
26050Sstevel@tonic-gate 	SVCXPRT *transp;
26060Sstevel@tonic-gate 	char *host;
26070Sstevel@tonic-gate 	struct netbuf *nb;
26080Sstevel@tonic-gate 
26090Sstevel@tonic-gate 	transp = rqstp->rq_xprt;
26100Sstevel@tonic-gate 	if (!svc_getargs(transp, xdr_void, NULL)) {
26110Sstevel@tonic-gate 		svcerr_decode(transp);
26120Sstevel@tonic-gate 		return;
26130Sstevel@tonic-gate 	}
26140Sstevel@tonic-gate 	/*
26150Sstevel@tonic-gate 	 * We assume that this call is asynchronous and made via rpcbind
26160Sstevel@tonic-gate 	 * callit routine.  Therefore return control immediately. The error
26170Sstevel@tonic-gate 	 * causes rpcbind to remain silent, as opposed to every machine
26180Sstevel@tonic-gate 	 * on the net blasting the requester with a response.
26190Sstevel@tonic-gate 	 */
26200Sstevel@tonic-gate 	svcerr_systemerr(transp);
26210Sstevel@tonic-gate 	getclientsnames(transp, &nb, &clnames);
26220Sstevel@tonic-gate 	if (clnames == NULL) {
26230Sstevel@tonic-gate 		/* Can't do anything without the name of the client */
26240Sstevel@tonic-gate 		return;
26250Sstevel@tonic-gate 	}
26260Sstevel@tonic-gate 
26270Sstevel@tonic-gate 	host = clnames->h_hostservs[0].h_host;
26280Sstevel@tonic-gate 
26290Sstevel@tonic-gate 	/*
26300Sstevel@tonic-gate 	 * Remove all hosts entries from mount list
26310Sstevel@tonic-gate 	 */
26320Sstevel@tonic-gate 	mntlist_delete_all(host);
26330Sstevel@tonic-gate 
26340Sstevel@tonic-gate 	if (verbose)
26350Sstevel@tonic-gate 		syslog(LOG_NOTICE, "UNMOUNTALL: from %s", host);
26360Sstevel@tonic-gate 
26370Sstevel@tonic-gate 	netdir_free(clnames, ND_HOSTSERVLIST);
26380Sstevel@tonic-gate }
26390Sstevel@tonic-gate 
26400Sstevel@tonic-gate void *
26410Sstevel@tonic-gate exmalloc(size_t size)
26420Sstevel@tonic-gate {
26430Sstevel@tonic-gate 	void *ret;
26440Sstevel@tonic-gate 
26450Sstevel@tonic-gate 	if ((ret = malloc(size)) == NULL) {
26460Sstevel@tonic-gate 		syslog(LOG_ERR, "Out of memory");
26470Sstevel@tonic-gate 		exit(1);
26480Sstevel@tonic-gate 	}
26490Sstevel@tonic-gate 	return (ret);
26500Sstevel@tonic-gate }
26510Sstevel@tonic-gate 
26520Sstevel@tonic-gate static void
26530Sstevel@tonic-gate sigexit(int signum)
26540Sstevel@tonic-gate {
26550Sstevel@tonic-gate 
26560Sstevel@tonic-gate 	if (signum == SIGHUP)
2657199Sgt29601 		_exit(0);
2658199Sgt29601 	_exit(1);
26590Sstevel@tonic-gate }
26604971Sjarrett 
26614971Sjarrett static tsol_tpent_t *
26624971Sjarrett get_client_template(struct sockaddr *sock)
26634971Sjarrett {
26644971Sjarrett 	in_addr_t	v4client;
26654971Sjarrett 	in6_addr_t	v6client;
26664971Sjarrett 	char		v4_addr[INET_ADDRSTRLEN];
26674971Sjarrett 	char		v6_addr[INET6_ADDRSTRLEN];
26684971Sjarrett 	tsol_rhent_t	*rh;
26694971Sjarrett 	tsol_tpent_t	*tp;
26704971Sjarrett 
26714971Sjarrett 	switch (sock->sa_family) {
26724971Sjarrett 	case AF_INET:
26734971Sjarrett 		v4client = ((struct sockaddr_in *)(void *)sock)->
26744971Sjarrett 		    sin_addr.s_addr;
26754971Sjarrett 		if (inet_ntop(AF_INET, &v4client, v4_addr, INET_ADDRSTRLEN) ==
26764971Sjarrett 		    NULL)
26774971Sjarrett 			return (NULL);
26784971Sjarrett 		rh = tsol_getrhbyaddr(v4_addr, sizeof (v4_addr), AF_INET);
26794971Sjarrett 		if (rh == NULL)
26804971Sjarrett 			return (NULL);
26814971Sjarrett 		tp = tsol_gettpbyname(rh->rh_template);
26824971Sjarrett 		tsol_freerhent(rh);
26834971Sjarrett 		return (tp);
26844971Sjarrett 		break;
26854971Sjarrett 	case AF_INET6:
26864971Sjarrett 		v6client = ((struct sockaddr_in6 *)(void *)sock)->sin6_addr;
26874971Sjarrett 		if (inet_ntop(AF_INET6, &v6client, v6_addr, INET6_ADDRSTRLEN) ==
26884971Sjarrett 		    NULL)
26894971Sjarrett 			return (NULL);
26904971Sjarrett 		rh = tsol_getrhbyaddr(v6_addr, sizeof (v6_addr), AF_INET6);
26914971Sjarrett 		if (rh == NULL)
26924971Sjarrett 			return (NULL);
26934971Sjarrett 		tp = tsol_gettpbyname(rh->rh_template);
26944971Sjarrett 		tsol_freerhent(rh);
26954971Sjarrett 		return (tp);
26964971Sjarrett 		break;
26974971Sjarrett 	default:
26984971Sjarrett 		return (NULL);
26994971Sjarrett 	}
27004971Sjarrett }
2701