xref: /titanic_52/usr/src/cmd/fs.d/nfs/mountd/mountd.c (revision aab83bb83be7342f6cfccaed8d5fe0b2f404855d)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
527242a7cSthurlow  * Common Development and Distribution License (the "License").
627242a7cSthurlow  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
2089621fe1SMarcel Telka  */
2189621fe1SMarcel Telka 
2289621fe1SMarcel Telka /*
2354d34259SMarcel Telka  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
2489621fe1SMarcel Telka  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
287c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley 4.3 BSD
327c478bd9Sstevel@tonic-gate  * under license from the Regents of the University of California.
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include <stdio.h>
3697adda44SMarcel Telka #include <stdio_ext.h>
377c478bd9Sstevel@tonic-gate #include <stdlib.h>
387c478bd9Sstevel@tonic-gate #include <ctype.h>
397c478bd9Sstevel@tonic-gate #include <sys/types.h>
407c478bd9Sstevel@tonic-gate #include <string.h>
417c478bd9Sstevel@tonic-gate #include <syslog.h>
427c478bd9Sstevel@tonic-gate #include <sys/param.h>
437c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
447c478bd9Sstevel@tonic-gate #include <sys/stat.h>
457c478bd9Sstevel@tonic-gate #include <netconfig.h>
467c478bd9Sstevel@tonic-gate #include <netdir.h>
477c478bd9Sstevel@tonic-gate #include <sys/file.h>
487c478bd9Sstevel@tonic-gate #include <sys/time.h>
497c478bd9Sstevel@tonic-gate #include <sys/errno.h>
507c478bd9Sstevel@tonic-gate #include <rpcsvc/mount.h>
517c478bd9Sstevel@tonic-gate #include <sys/pathconf.h>
527c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
537c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
54250a0733Sth199096 #include <sys/wait.h>
5597adda44SMarcel Telka #include <sys/resource.h>
567c478bd9Sstevel@tonic-gate #include <signal.h>
577c478bd9Sstevel@tonic-gate #include <locale.h>
587c478bd9Sstevel@tonic-gate #include <unistd.h>
597c478bd9Sstevel@tonic-gate #include <errno.h>
607c478bd9Sstevel@tonic-gate #include <sys/socket.h>
617c478bd9Sstevel@tonic-gate #include <netinet/in.h>
627c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
637c478bd9Sstevel@tonic-gate #include <netdb.h>
647c478bd9Sstevel@tonic-gate #include <thread.h>
657c478bd9Sstevel@tonic-gate #include <assert.h>
667c478bd9Sstevel@tonic-gate #include <priv_utils.h>
671cc55349Srmesta #include <nfs/auth.h>
681cc55349Srmesta #include <nfs/nfssys.h>
697c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
707c478bd9Sstevel@tonic-gate #include <nfs/nfs_sec.h>
717c478bd9Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h>
727c478bd9Sstevel@tonic-gate #include <deflt.h>
737c478bd9Sstevel@tonic-gate #include "../../fslib.h"
74a237e38eSth199096 #include <sharefs/share.h>
75a237e38eSth199096 #include <sharefs/sharetab.h>
767c478bd9Sstevel@tonic-gate #include "../lib/sharetab.h"
777c478bd9Sstevel@tonic-gate #include "mountd.h"
7803986916Sjarrett #include <tsol/label.h>
7903986916Sjarrett #include <sys/tsol/label_macro.h>
8003986916Sjarrett #include <libtsnet.h>
814a508a79SThomas Haynes #include <sys/sdt.h>
82dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <libscf.h>
83dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include <limits.h>
846b086bafSSam Falkner #include <sys/nvpair.h>
856b086bafSSam Falkner #include <attr.h>
86dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States #include "smfcfg.h"
875cb0d679SMarcel Telka #include <pwd.h>
885cb0d679SMarcel Telka #include <grp.h>
8989621fe1SMarcel Telka #include <alloca.h>
907c478bd9Sstevel@tonic-gate 
91250a0733Sth199096 extern int daemonize_init(void);
9254d34259SMarcel Telka extern void daemonize_fini(int);
9354d34259SMarcel Telka 
9454d34259SMarcel Telka extern int _nfssys(int, void *);
95250a0733Sth199096 
967c478bd9Sstevel@tonic-gate struct sh_list *share_list;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate rwlock_t sharetab_lock;		/* lock to protect the cached sharetab */
997c478bd9Sstevel@tonic-gate static mutex_t mnttab_lock;	/* prevent concurrent mnttab readers */
1007c478bd9Sstevel@tonic-gate 
1014a508a79SThomas Haynes static mutex_t logging_queue_lock;
1024a508a79SThomas Haynes static cond_t logging_queue_cv;
1034a508a79SThomas Haynes 
1044a508a79SThomas Haynes static share_t *find_lofsentry(char *, int *);
105*a9685eaaSMarcel Telka static int getclientsflavors_old(share_t *, struct cln *, int *);
106*a9685eaaSMarcel Telka static int getclientsflavors_new(share_t *, struct cln *, int *);
107*a9685eaaSMarcel Telka static int check_client_old(share_t *, struct cln *, int, uid_t, gid_t, uint_t,
108*a9685eaaSMarcel Telka     gid_t *, uid_t *, gid_t *, uint_t *, gid_t **);
109*a9685eaaSMarcel Telka static int check_client_new(share_t *, struct cln *, int, uid_t, gid_t, uint_t,
110*a9685eaaSMarcel Telka     gid_t *, uid_t *, gid_t *i, uint_t *, gid_t **);
1117c478bd9Sstevel@tonic-gate static void mnt(struct svc_req *, SVCXPRT *);
1127c478bd9Sstevel@tonic-gate static void mnt_pathconf(struct svc_req *);
1134a508a79SThomas Haynes static int mount(struct svc_req *r);
1147c478bd9Sstevel@tonic-gate static void sh_free(struct sh_list *);
1157c478bd9Sstevel@tonic-gate static void umount(struct svc_req *);
1167c478bd9Sstevel@tonic-gate static void umountall(struct svc_req *);
1177c478bd9Sstevel@tonic-gate static int newopts(char *);
11803986916Sjarrett static tsol_tpent_t *get_client_template(struct sockaddr *);
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate static int verbose;
1217c478bd9Sstevel@tonic-gate static int rejecting;
1227c478bd9Sstevel@tonic-gate static int mount_vers_min = MOUNTVERS;
1237c478bd9Sstevel@tonic-gate static int mount_vers_max = MOUNTVERS3;
1247c478bd9Sstevel@tonic-gate 
125b89a8333Snatalie li - Sun Microsystems - Irvine United States extern void nfscmd_func(void *, char *, size_t, door_desc_t *, uint_t);
126b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1271cc55349Srmesta thread_t	nfsauth_thread;
128b89a8333Snatalie li - Sun Microsystems - Irvine United States thread_t	cmd_thread;
1294a508a79SThomas Haynes thread_t	logging_thread;
1304a508a79SThomas Haynes 
1314a508a79SThomas Haynes typedef struct logging_data {
1324a508a79SThomas Haynes 	char			*ld_host;
1334a508a79SThomas Haynes 	char			*ld_path;
1344a508a79SThomas Haynes 	char			*ld_rpath;
1354a508a79SThomas Haynes 	int			ld_status;
1364a508a79SThomas Haynes 	char			*ld_netid;
1374a508a79SThomas Haynes 	struct netbuf		*ld_nb;
1384a508a79SThomas Haynes 	struct logging_data	*ld_next;
1394a508a79SThomas Haynes } logging_data;
1404a508a79SThomas Haynes 
1414a508a79SThomas Haynes static logging_data *logging_head = NULL;
1424a508a79SThomas Haynes static logging_data *logging_tail = NULL;
1431cc55349Srmesta 
14489621fe1SMarcel Telka /*
14589621fe1SMarcel Telka  * Our copy of some system variables obtained using sysconf(3c)
14689621fe1SMarcel Telka  */
14789621fe1SMarcel Telka static long ngroups_max;	/* _SC_NGROUPS_MAX */
14889621fe1SMarcel Telka static long pw_size;		/* _SC_GETPW_R_SIZE_MAX */
14989621fe1SMarcel Telka 
1501cc55349Srmesta /* ARGSUSED */
1511cc55349Srmesta static void *
1521cc55349Srmesta nfsauth_svc(void *arg)
1531cc55349Srmesta {
1541cc55349Srmesta 	int	doorfd = -1;
1551cc55349Srmesta 	uint_t	darg;
1561cc55349Srmesta #ifdef DEBUG
1571cc55349Srmesta 	int	dfd;
1581cc55349Srmesta #endif
1591cc55349Srmesta 
1601cc55349Srmesta 	if ((doorfd = door_create(nfsauth_func, NULL,
1611cc55349Srmesta 	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
1621cc55349Srmesta 		syslog(LOG_ERR, "Unable to create door: %m\n");
1631cc55349Srmesta 		exit(10);
1641cc55349Srmesta 	}
1651cc55349Srmesta 
1661cc55349Srmesta #ifdef DEBUG
1671cc55349Srmesta 	/*
1681cc55349Srmesta 	 * Create a file system path for the door
1691cc55349Srmesta 	 */
1701cc55349Srmesta 	if ((dfd = open(MOUNTD_DOOR, O_RDWR|O_CREAT|O_TRUNC,
1711cc55349Srmesta 	    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) {
1721cc55349Srmesta 		syslog(LOG_ERR, "Unable to open %s: %m\n", MOUNTD_DOOR);
1731cc55349Srmesta 		(void) close(doorfd);
1741cc55349Srmesta 		exit(11);
1751cc55349Srmesta 	}
1761cc55349Srmesta 
1771cc55349Srmesta 	/*
1781cc55349Srmesta 	 * Clean up any stale namespace associations
1791cc55349Srmesta 	 */
1801cc55349Srmesta 	(void) fdetach(MOUNTD_DOOR);
1811cc55349Srmesta 
1821cc55349Srmesta 	/*
1831cc55349Srmesta 	 * Register in namespace to pass to the kernel to door_ki_open
1841cc55349Srmesta 	 */
1851cc55349Srmesta 	if (fattach(doorfd, MOUNTD_DOOR) == -1) {
1861cc55349Srmesta 		syslog(LOG_ERR, "Unable to fattach door: %m\n");
1871cc55349Srmesta 		(void) close(dfd);
1881cc55349Srmesta 		(void) close(doorfd);
1891cc55349Srmesta 		exit(12);
1901cc55349Srmesta 	}
1911cc55349Srmesta 	(void) close(dfd);
1921cc55349Srmesta #endif
1931cc55349Srmesta 
1941cc55349Srmesta 	/*
1951cc55349Srmesta 	 * Must pass the doorfd down to the kernel.
1961cc55349Srmesta 	 */
1971cc55349Srmesta 	darg = doorfd;
1981cc55349Srmesta 	(void) _nfssys(MOUNTD_ARGS, &darg);
1991cc55349Srmesta 
2001cc55349Srmesta 	/*
2011cc55349Srmesta 	 * Wait for incoming calls
2021cc55349Srmesta 	 */
2031cc55349Srmesta 	/*CONSTCOND*/
2041cc55349Srmesta 	for (;;)
2051cc55349Srmesta 		(void) pause();
2061cc55349Srmesta 
2071cc55349Srmesta 	/*NOTREACHED*/
2081cc55349Srmesta 	syslog(LOG_ERR, gettext("Door server exited"));
2091cc55349Srmesta 	return (NULL);
2101cc55349Srmesta }
2111cc55349Srmesta 
212b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
213b89a8333Snatalie li - Sun Microsystems - Irvine United States  * NFS command service thread code for setup and handling of the
214b89a8333Snatalie li - Sun Microsystems - Irvine United States  * nfs_cmd requests for character set conversion and other future
215b89a8333Snatalie li - Sun Microsystems - Irvine United States  * events.
216b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
217b89a8333Snatalie li - Sun Microsystems - Irvine United States 
218b89a8333Snatalie li - Sun Microsystems - Irvine United States static void *
219b89a8333Snatalie li - Sun Microsystems - Irvine United States cmd_svc(void *arg)
220b89a8333Snatalie li - Sun Microsystems - Irvine United States {
221b89a8333Snatalie li - Sun Microsystems - Irvine United States 	int	doorfd = -1;
222b89a8333Snatalie li - Sun Microsystems - Irvine United States 	uint_t	darg;
223b89a8333Snatalie li - Sun Microsystems - Irvine United States 
224b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if ((doorfd = door_create(nfscmd_func, NULL,
225b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
226b89a8333Snatalie li - Sun Microsystems - Irvine United States 		syslog(LOG_ERR, "Unable to create cmd door: %m\n");
227b89a8333Snatalie li - Sun Microsystems - Irvine United States 		exit(10);
228b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
229b89a8333Snatalie li - Sun Microsystems - Irvine United States 
230b89a8333Snatalie li - Sun Microsystems - Irvine United States 	/*
231b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * Must pass the doorfd down to the kernel.
232b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 */
233b89a8333Snatalie li - Sun Microsystems - Irvine United States 	darg = doorfd;
234b89a8333Snatalie li - Sun Microsystems - Irvine United States 	(void) _nfssys(NFSCMD_ARGS, &darg);
235b89a8333Snatalie li - Sun Microsystems - Irvine United States 
236b89a8333Snatalie li - Sun Microsystems - Irvine United States 	/*
237b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * Wait for incoming calls
238b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 */
239b89a8333Snatalie li - Sun Microsystems - Irvine United States 	/*CONSTCOND*/
240b89a8333Snatalie li - Sun Microsystems - Irvine United States 	for (;;)
241b89a8333Snatalie li - Sun Microsystems - Irvine United States 		(void) pause();
242b89a8333Snatalie li - Sun Microsystems - Irvine United States 
243b89a8333Snatalie li - Sun Microsystems - Irvine United States 	/*NOTREACHED*/
244b89a8333Snatalie li - Sun Microsystems - Irvine United States 	syslog(LOG_ERR, gettext("Cmd door server exited"));
245b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (NULL);
246b89a8333Snatalie li - Sun Microsystems - Irvine United States }
247250a0733Sth199096 
2484a508a79SThomas Haynes static void
2494a508a79SThomas Haynes free_logging_data(logging_data *lq)
2504a508a79SThomas Haynes {
2514a508a79SThomas Haynes 	if (lq != NULL) {
2524a508a79SThomas Haynes 		free(lq->ld_host);
2534a508a79SThomas Haynes 		free(lq->ld_netid);
2544a508a79SThomas Haynes 
2554a508a79SThomas Haynes 		if (lq->ld_nb != NULL) {
2564a508a79SThomas Haynes 			free(lq->ld_nb->buf);
2574a508a79SThomas Haynes 			free(lq->ld_nb);
2584a508a79SThomas Haynes 		}
2594a508a79SThomas Haynes 
2604a508a79SThomas Haynes 		free(lq->ld_path);
2614a508a79SThomas Haynes 		free(lq->ld_rpath);
2624a508a79SThomas Haynes 
2634a508a79SThomas Haynes 		free(lq);
2644a508a79SThomas Haynes 	}
2654a508a79SThomas Haynes }
2664a508a79SThomas Haynes 
2674a508a79SThomas Haynes static logging_data *
2684a508a79SThomas Haynes remove_head_of_queue(void)
2694a508a79SThomas Haynes {
2704a508a79SThomas Haynes 	logging_data    *lq;
2714a508a79SThomas Haynes 
2724a508a79SThomas Haynes 	/*
2734a508a79SThomas Haynes 	 * Pull it off the queue.
2744a508a79SThomas Haynes 	 */
2754a508a79SThomas Haynes 	lq = logging_head;
2764a508a79SThomas Haynes 	if (lq) {
2774a508a79SThomas Haynes 		logging_head = lq->ld_next;
2784a508a79SThomas Haynes 
2794a508a79SThomas Haynes 		/*
2804a508a79SThomas Haynes 		 * Drained it.
2814a508a79SThomas Haynes 		 */
2824a508a79SThomas Haynes 		if (logging_head == NULL) {
2834a508a79SThomas Haynes 			logging_tail = NULL;
2844a508a79SThomas Haynes 		}
2854a508a79SThomas Haynes 	}
2864a508a79SThomas Haynes 
2874a508a79SThomas Haynes 	return (lq);
2884a508a79SThomas Haynes }
2894a508a79SThomas Haynes 
2904a508a79SThomas Haynes static void
2914a508a79SThomas Haynes do_logging_queue(logging_data *lq)
2924a508a79SThomas Haynes {
2934a508a79SThomas Haynes 	int		cleared = 0;
2944a508a79SThomas Haynes 	char		*host;
2954a508a79SThomas Haynes 
2964a508a79SThomas Haynes 	while (lq) {
297*a9685eaaSMarcel Telka 		struct cln cln;
298*a9685eaaSMarcel Telka 
2994a508a79SThomas Haynes 		if (lq->ld_host == NULL) {
3004a508a79SThomas Haynes 			DTRACE_PROBE(mountd, name_by_lazy);
301*a9685eaaSMarcel Telka 			cln_init_lazy(&cln, lq->ld_netid, lq->ld_nb);
302*a9685eaaSMarcel Telka 			host = cln_gethost(&cln);
3034a508a79SThomas Haynes 		} else
3044a508a79SThomas Haynes 			host = lq->ld_host;
3054a508a79SThomas Haynes 
3064a508a79SThomas Haynes 		audit_mountd_mount(host, lq->ld_path, lq->ld_status); /* BSM */
3074a508a79SThomas Haynes 
3084a508a79SThomas Haynes 		/* add entry to mount list */
3094a508a79SThomas Haynes 		if (lq->ld_rpath)
3104a508a79SThomas Haynes 			mntlist_new(host, lq->ld_rpath);
3114a508a79SThomas Haynes 
312*a9685eaaSMarcel Telka 		if (lq->ld_host == NULL)
313*a9685eaaSMarcel Telka 			cln_fini(&cln);
314d383eb7aSMarcel Telka 
315c596e866SMarcel Telka 		free_logging_data(lq);
316c596e866SMarcel Telka 		cleared++;
3174a508a79SThomas Haynes 
3184a508a79SThomas Haynes 		(void) mutex_lock(&logging_queue_lock);
3194a508a79SThomas Haynes 		lq = remove_head_of_queue();
3204a508a79SThomas Haynes 		(void) mutex_unlock(&logging_queue_lock);
3214a508a79SThomas Haynes 	}
3224a508a79SThomas Haynes 
3234a508a79SThomas Haynes 	DTRACE_PROBE1(mountd, logging_cleared, cleared);
3244a508a79SThomas Haynes }
3254a508a79SThomas Haynes 
3264a508a79SThomas Haynes static void *
3274a508a79SThomas Haynes logging_svc(void *arg)
3284a508a79SThomas Haynes {
3294a508a79SThomas Haynes 	logging_data	*lq;
3304a508a79SThomas Haynes 
3314a508a79SThomas Haynes 	for (;;) {
3324a508a79SThomas Haynes 		(void) mutex_lock(&logging_queue_lock);
3334a508a79SThomas Haynes 		while (logging_head == NULL) {
3344a508a79SThomas Haynes 			(void) cond_wait(&logging_queue_cv,
3354a508a79SThomas Haynes 			    &logging_queue_lock);
3364a508a79SThomas Haynes 		}
3374a508a79SThomas Haynes 
3384a508a79SThomas Haynes 		lq = remove_head_of_queue();
3394a508a79SThomas Haynes 		(void) mutex_unlock(&logging_queue_lock);
3404a508a79SThomas Haynes 
3414a508a79SThomas Haynes 		do_logging_queue(lq);
3424a508a79SThomas Haynes 	}
3434a508a79SThomas Haynes 
3444a508a79SThomas Haynes 	/*NOTREACHED*/
3454a508a79SThomas Haynes 	syslog(LOG_ERR, gettext("Logging server exited"));
3464a508a79SThomas Haynes 	return (NULL);
3474a508a79SThomas Haynes }
3484a508a79SThomas Haynes 
349361f55a5SMarcel Telka static int
350361f55a5SMarcel Telka convert_int(int *val, char *str)
351361f55a5SMarcel Telka {
352361f55a5SMarcel Telka 	long lval;
353361f55a5SMarcel Telka 
354361f55a5SMarcel Telka 	if (str == NULL || !isdigit(*str))
355361f55a5SMarcel Telka 		return (-1);
356361f55a5SMarcel Telka 
357361f55a5SMarcel Telka 	lval = strtol(str, &str, 10);
358361f55a5SMarcel Telka 	if (*str != '\0' || lval > INT_MAX)
359361f55a5SMarcel Telka 		return (-2);
360361f55a5SMarcel Telka 
361361f55a5SMarcel Telka 	*val = (int)lval;
362361f55a5SMarcel Telka 	return (0);
363361f55a5SMarcel Telka }
364361f55a5SMarcel Telka 
36511606941Sjwahlig int
36611606941Sjwahlig main(int argc, char *argv[])
3677c478bd9Sstevel@tonic-gate {
3687c478bd9Sstevel@tonic-gate 	int	pid;
3697c478bd9Sstevel@tonic-gate 	int	c;
3702f416683SMarcel Telka 	int	rpc_svc_fdunlim = 1;
3717c478bd9Sstevel@tonic-gate 	int	rpc_svc_mode = RPC_SVC_MT_AUTO;
3727c478bd9Sstevel@tonic-gate 	int	maxrecsz = RPC_MAXDATASIZE;
3737c478bd9Sstevel@tonic-gate 	bool_t	exclbind = TRUE;
37445916cd2Sjpk 	bool_t	can_do_mlp;
3751cc55349Srmesta 	long	thr_flags = (THR_NEW_LWP|THR_DAEMON);
376dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	char defval[4];
377dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	int defvers, ret, bufsz;
37897adda44SMarcel Telka 	struct rlimit rl;
379361f55a5SMarcel Telka 	int listen_backlog = 0;
380361f55a5SMarcel Telka 	int max_threads = 0;
381361f55a5SMarcel Telka 	int tmp;
3827c478bd9Sstevel@tonic-gate 
383250a0733Sth199096 	int	pipe_fd = -1;
384250a0733Sth199096 
3857c478bd9Sstevel@tonic-gate 	/*
3867c478bd9Sstevel@tonic-gate 	 * Mountd requires uid 0 for:
3877c478bd9Sstevel@tonic-gate 	 *	/etc/rmtab updates (we could chown it to daemon)
3887c478bd9Sstevel@tonic-gate 	 *	/etc/dfs/dfstab reading (it wants to lock out share which
3897c478bd9Sstevel@tonic-gate 	 *		doesn't do any locking before first truncate;
3907c478bd9Sstevel@tonic-gate 	 *		NFS share does; should use fcntl locking instead)
3917c478bd9Sstevel@tonic-gate 	 *	Needed privileges:
3927c478bd9Sstevel@tonic-gate 	 *		auditing
3937c478bd9Sstevel@tonic-gate 	 *		nfs syscall
3947c478bd9Sstevel@tonic-gate 	 *		file dac search (so it can stat all files)
39545916cd2Sjpk 	 *	Optional privileges:
39645916cd2Sjpk 	 *		MLP
3977c478bd9Sstevel@tonic-gate 	 */
39845916cd2Sjpk 	can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
3997c478bd9Sstevel@tonic-gate 	if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, -1, -1,
4007c478bd9Sstevel@tonic-gate 	    PRIV_SYS_NFS, PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH,
40145916cd2Sjpk 	    can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
4027c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
403250a0733Sth199096 		    "%s: must be run with sufficient privileges\n",
4047c478bd9Sstevel@tonic-gate 		    argv[0]);
4057c478bd9Sstevel@tonic-gate 		exit(1);
4067c478bd9Sstevel@tonic-gate 	}
4077c478bd9Sstevel@tonic-gate 
40897adda44SMarcel Telka 	if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
40997adda44SMarcel Telka 		syslog(LOG_ERR, "getrlimit failed");
41097adda44SMarcel Telka 	} else {
41197adda44SMarcel Telka 		rl.rlim_cur = rl.rlim_max;
41297adda44SMarcel Telka 		if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
41397adda44SMarcel Telka 			syslog(LOG_ERR, "setrlimit failed");
41497adda44SMarcel Telka 	}
41597adda44SMarcel Telka 
41697adda44SMarcel Telka 	(void) enable_extended_FILE_stdio(-1, -1);
41797adda44SMarcel Telka 
418361f55a5SMarcel Telka 	ret = nfs_smf_get_iprop("mountd_max_threads", &max_threads,
419361f55a5SMarcel Telka 	    DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
420361f55a5SMarcel Telka 	if (ret != SA_OK) {
421361f55a5SMarcel Telka 		syslog(LOG_ERR, "Reading of mountd_max_threads from SMF "
422361f55a5SMarcel Telka 		    "failed, using default value");
423361f55a5SMarcel Telka 	}
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "vrm:")) != EOF) {
4267c478bd9Sstevel@tonic-gate 		switch (c) {
4277c478bd9Sstevel@tonic-gate 		case 'v':
4287c478bd9Sstevel@tonic-gate 			verbose++;
4297c478bd9Sstevel@tonic-gate 			break;
4307c478bd9Sstevel@tonic-gate 		case 'r':
4317c478bd9Sstevel@tonic-gate 			rejecting = 1;
4327c478bd9Sstevel@tonic-gate 			break;
4337c478bd9Sstevel@tonic-gate 		case 'm':
434361f55a5SMarcel Telka 			if (convert_int(&tmp, optarg) != 0 || tmp < 1) {
435361f55a5SMarcel Telka 				(void) fprintf(stderr, "%s: invalid "
436361f55a5SMarcel Telka 				    "max_threads option, using defaults\n",
4377c478bd9Sstevel@tonic-gate 				    argv[0]);
4387c478bd9Sstevel@tonic-gate 				break;
4397c478bd9Sstevel@tonic-gate 			}
440361f55a5SMarcel Telka 			max_threads = tmp;
441361f55a5SMarcel Telka 			break;
442361f55a5SMarcel Telka 		default:
443361f55a5SMarcel Telka 			fprintf(stderr, "usage: mountd [-v] [-r]\n");
444361f55a5SMarcel Telka 			exit(1);
445361f55a5SMarcel Telka 		}
4467c478bd9Sstevel@tonic-gate 	}
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	/*
4497c478bd9Sstevel@tonic-gate 	 * Read in the NFS version values from config file.
4507c478bd9Sstevel@tonic-gate 	 */
451dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	bufsz = 4;
452dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	ret = nfs_smf_get_prop("server_versmin", defval, DEFAULT_INSTANCE,
453dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	    SCF_TYPE_INTEGER, NFSD, &bufsz);
454dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	if (ret == SA_OK) {
4557c478bd9Sstevel@tonic-gate 		errno = 0;
4567c478bd9Sstevel@tonic-gate 		defvers = strtol(defval, (char **)NULL, 10);
4577c478bd9Sstevel@tonic-gate 		if (errno == 0) {
4587c478bd9Sstevel@tonic-gate 			mount_vers_min = defvers;
4597c478bd9Sstevel@tonic-gate 			/*
4607c478bd9Sstevel@tonic-gate 			 * special because NFSv2 is
4617c478bd9Sstevel@tonic-gate 			 * supported by mount v1 & v2
4627c478bd9Sstevel@tonic-gate 			 */
4637c478bd9Sstevel@tonic-gate 			if (defvers == NFS_VERSION)
4647c478bd9Sstevel@tonic-gate 				mount_vers_min = MOUNTVERS;
4657c478bd9Sstevel@tonic-gate 		}
4667c478bd9Sstevel@tonic-gate 	}
467dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 
468dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	bufsz = 4;
469dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	ret = nfs_smf_get_prop("server_versmax", defval, DEFAULT_INSTANCE,
470dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	    SCF_TYPE_INTEGER, NFSD, &bufsz);
471dd51520eSPavan Mettu - Oracle Corporation - Menlo Park United States 	if (ret == SA_OK) {
4727c478bd9Sstevel@tonic-gate 		errno = 0;
4737c478bd9Sstevel@tonic-gate 		defvers = strtol(defval, (char **)NULL, 10);
4747c478bd9Sstevel@tonic-gate 		if (errno == 0) {
4757c478bd9Sstevel@tonic-gate 			mount_vers_max = defvers;
4767c478bd9Sstevel@tonic-gate 		}
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate 
479361f55a5SMarcel Telka 	ret = nfs_smf_get_iprop("mountd_listen_backlog", &listen_backlog,
480361f55a5SMarcel Telka 	    DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
481361f55a5SMarcel Telka 	if (ret != SA_OK) {
482361f55a5SMarcel Telka 		syslog(LOG_ERR, "Reading of mountd_listen_backlog from SMF "
483361f55a5SMarcel Telka 		    "failed, using default value");
484361f55a5SMarcel Telka 	}
485361f55a5SMarcel Telka 
4867c478bd9Sstevel@tonic-gate 	/*
4877c478bd9Sstevel@tonic-gate 	 * Sanity check versions,
4887c478bd9Sstevel@tonic-gate 	 * even though we may get versions > MOUNTVERS3, we still need
4897c478bd9Sstevel@tonic-gate 	 * to start nfsauth service, so continue on regardless of values.
4907c478bd9Sstevel@tonic-gate 	 */
4917c478bd9Sstevel@tonic-gate 	if (mount_vers_min > mount_vers_max) {
492361f55a5SMarcel Telka 		fprintf(stderr, "server_versmin > server_versmax\n");
4937c478bd9Sstevel@tonic-gate 		mount_vers_max = mount_vers_min;
4947c478bd9Sstevel@tonic-gate 	}
4957c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
4967c478bd9Sstevel@tonic-gate 	(void) rwlock_init(&sharetab_lock, USYNC_THREAD, NULL);
4977c478bd9Sstevel@tonic-gate 	(void) mutex_init(&mnttab_lock, USYNC_THREAD, NULL);
4984a508a79SThomas Haynes 	(void) mutex_init(&logging_queue_lock, USYNC_THREAD, NULL);
4994a508a79SThomas Haynes 	(void) cond_init(&logging_queue_cv, USYNC_THREAD, NULL);
5004a508a79SThomas Haynes 
5017c478bd9Sstevel@tonic-gate 	netgroup_init();
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
5047c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
5057c478bd9Sstevel@tonic-gate #endif
5067c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	/* Don't drop core if the NFS module isn't loaded. */
5097c478bd9Sstevel@tonic-gate 	(void) signal(SIGSYS, SIG_IGN);
5107c478bd9Sstevel@tonic-gate 
511250a0733Sth199096 	pipe_fd = daemonize_init();
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	/*
5147c478bd9Sstevel@tonic-gate 	 * If we coredump it'll be in /core
5157c478bd9Sstevel@tonic-gate 	 */
5167c478bd9Sstevel@tonic-gate 	if (chdir("/") < 0)
517361f55a5SMarcel Telka 		fprintf(stderr, "chdir /: %s\n", strerror(errno));
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	openlog("mountd", LOG_PID, LOG_DAEMON);
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	/*
5227c478bd9Sstevel@tonic-gate 	 * establish our lock on the lock file and write our pid to it.
5237c478bd9Sstevel@tonic-gate 	 * exit if some other process holds the lock, or if there's any
5247c478bd9Sstevel@tonic-gate 	 * error in writing/locking the file.
5257c478bd9Sstevel@tonic-gate 	 */
5267c478bd9Sstevel@tonic-gate 	pid = _enter_daemon_lock(MOUNTD);
5277c478bd9Sstevel@tonic-gate 	switch (pid) {
5287c478bd9Sstevel@tonic-gate 	case 0:
5297c478bd9Sstevel@tonic-gate 		break;
5307c478bd9Sstevel@tonic-gate 	case -1:
531361f55a5SMarcel Telka 		fprintf(stderr, "error locking for %s: %s\n", MOUNTD,
5327c478bd9Sstevel@tonic-gate 		    strerror(errno));
5337c478bd9Sstevel@tonic-gate 		exit(2);
5347c478bd9Sstevel@tonic-gate 	default:
5357c478bd9Sstevel@tonic-gate 		/* daemon was already running */
5367c478bd9Sstevel@tonic-gate 		exit(0);
5377c478bd9Sstevel@tonic-gate 	}
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	audit_mountd_setup();	/* BSM */
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	/*
54289621fe1SMarcel Telka 	 * Get required system variables
54389621fe1SMarcel Telka 	 */
54489621fe1SMarcel Telka 	if ((ngroups_max = sysconf(_SC_NGROUPS_MAX)) == -1) {
54589621fe1SMarcel Telka 		syslog(LOG_ERR, "Unable to get _SC_NGROUPS_MAX");
54689621fe1SMarcel Telka 		exit(1);
54789621fe1SMarcel Telka 	}
54889621fe1SMarcel Telka 	if ((pw_size = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) {
54989621fe1SMarcel Telka 		syslog(LOG_ERR, "Unable to get _SC_GETPW_R_SIZE_MAX");
55089621fe1SMarcel Telka 		exit(1);
55189621fe1SMarcel Telka 	}
55289621fe1SMarcel Telka 
55389621fe1SMarcel Telka 	/*
5542f416683SMarcel Telka 	 * Set number of file descriptors to unlimited
5552f416683SMarcel Telka 	 */
5562f416683SMarcel Telka 	if (!rpc_control(RPC_SVC_USE_POLLFD, &rpc_svc_fdunlim)) {
5572f416683SMarcel Telka 		syslog(LOG_INFO, "unable to set number of FDs to unlimited");
5582f416683SMarcel Telka 	}
5592f416683SMarcel Telka 
5602f416683SMarcel Telka 	/*
5617c478bd9Sstevel@tonic-gate 	 * Tell RPC that we want automatic thread mode.
5627c478bd9Sstevel@tonic-gate 	 * A new thread will be spawned for each request.
5637c478bd9Sstevel@tonic-gate 	 */
5647c478bd9Sstevel@tonic-gate 	if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) {
565361f55a5SMarcel Telka 		fprintf(stderr, "unable to set automatic MT mode\n");
5667c478bd9Sstevel@tonic-gate 		exit(1);
5677c478bd9Sstevel@tonic-gate 	}
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	/*
5707c478bd9Sstevel@tonic-gate 	 * Enable non-blocking mode and maximum record size checks for
5717c478bd9Sstevel@tonic-gate 	 * connection oriented transports.
5727c478bd9Sstevel@tonic-gate 	 */
5737c478bd9Sstevel@tonic-gate 	if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) {
574361f55a5SMarcel Telka 		fprintf(stderr, "unable to set RPC max record size\n");
5757c478bd9Sstevel@tonic-gate 	}
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	/*
5787c478bd9Sstevel@tonic-gate 	 * Prevent our non-priv udp and tcp ports bound w/wildcard addr
5797c478bd9Sstevel@tonic-gate 	 * from being hijacked by a bind to a more specific addr.
5807c478bd9Sstevel@tonic-gate 	 */
5817c478bd9Sstevel@tonic-gate 	if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) {
582361f55a5SMarcel Telka 		fprintf(stderr, "warning: unable to set udp/tcp EXCLBIND\n");
5837c478bd9Sstevel@tonic-gate 	}
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	/*
586361f55a5SMarcel Telka 	 * Set the maximum number of outstanding connection
587361f55a5SMarcel Telka 	 * indications (listen backlog) to the value specified.
588361f55a5SMarcel Telka 	 */
589361f55a5SMarcel Telka 	if (listen_backlog > 0 && !rpc_control(__RPC_SVC_LSTNBKLOG_SET,
590361f55a5SMarcel Telka 	    &listen_backlog)) {
591361f55a5SMarcel Telka 		fprintf(stderr, "unable to set listen backlog\n");
592361f55a5SMarcel Telka 		exit(1);
593361f55a5SMarcel Telka 	}
594361f55a5SMarcel Telka 
595361f55a5SMarcel Telka 	/*
596361f55a5SMarcel Telka 	 * If max_threads was specified, then set the
5977c478bd9Sstevel@tonic-gate 	 * maximum number of threads to the value specified.
5987c478bd9Sstevel@tonic-gate 	 */
599361f55a5SMarcel Telka 	if (max_threads > 0 && !rpc_control(RPC_SVC_THRMAX_SET, &max_threads)) {
600361f55a5SMarcel Telka 		fprintf(stderr, "unable to set max_threads\n");
6017c478bd9Sstevel@tonic-gate 		exit(1);
6027c478bd9Sstevel@tonic-gate 	}
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	/*
6057c478bd9Sstevel@tonic-gate 	 * Make sure to unregister any previous versions in case the
6067c478bd9Sstevel@tonic-gate 	 * user is reconfiguring the server in interesting ways.
6077c478bd9Sstevel@tonic-gate 	 */
6087c478bd9Sstevel@tonic-gate 	svc_unreg(MOUNTPROG, MOUNTVERS);
6097c478bd9Sstevel@tonic-gate 	svc_unreg(MOUNTPROG, MOUNTVERS_POSIX);
6107c478bd9Sstevel@tonic-gate 	svc_unreg(MOUNTPROG, MOUNTVERS3);
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	/*
6131cc55349Srmesta 	 * Create the nfsauth thread with same signal disposition
6141cc55349Srmesta 	 * as the main thread. We need to create a separate thread
6151cc55349Srmesta 	 * since mountd() will be both an RPC server (for remote
6161cc55349Srmesta 	 * traffic) _and_ a doors server (for kernel upcalls).
6177c478bd9Sstevel@tonic-gate 	 */
6181cc55349Srmesta 	if (thr_create(NULL, 0, nfsauth_svc, 0, thr_flags, &nfsauth_thread)) {
619361f55a5SMarcel Telka 		fprintf(stderr,
620361f55a5SMarcel Telka 		    gettext("Failed to create NFSAUTH svc thread\n"));
6211cc55349Srmesta 		exit(2);
6227c478bd9Sstevel@tonic-gate 	}
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	/*
625b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * Create the cmd service thread with same signal disposition
626b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * as the main thread. We need to create a separate thread
627b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * since mountd() will be both an RPC server (for remote
628b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * traffic) _and_ a doors server (for kernel upcalls).
629b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 */
630b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (thr_create(NULL, 0, cmd_svc, 0, thr_flags, &cmd_thread)) {
631b89a8333Snatalie li - Sun Microsystems - Irvine United States 		syslog(LOG_ERR, gettext("Failed to create CMD svc thread"));
632b89a8333Snatalie li - Sun Microsystems - Irvine United States 		exit(2);
633b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
634b89a8333Snatalie li - Sun Microsystems - Irvine United States 
635b89a8333Snatalie li - Sun Microsystems - Irvine United States 	/*
6364a508a79SThomas Haynes 	 * Create an additional thread to service the rmtab and
6374a508a79SThomas Haynes 	 * audit_mountd_mount logging for mount requests. Use the same
6384a508a79SThomas Haynes 	 * signal disposition as the main thread. We create
6394a508a79SThomas Haynes 	 * a separate thread to allow the mount request threads to
6404a508a79SThomas Haynes 	 * clear as soon as possible.
6414a508a79SThomas Haynes 	 */
6424a508a79SThomas Haynes 	if (thr_create(NULL, 0, logging_svc, 0, thr_flags, &logging_thread)) {
6434a508a79SThomas Haynes 		syslog(LOG_ERR, gettext("Failed to create LOGGING svc thread"));
6444a508a79SThomas Haynes 		exit(2);
6454a508a79SThomas Haynes 	}
6464a508a79SThomas Haynes 
6474a508a79SThomas Haynes 	/*
6487c478bd9Sstevel@tonic-gate 	 * Create datagram and connection oriented services
6497c478bd9Sstevel@tonic-gate 	 */
6507c478bd9Sstevel@tonic-gate 	if (mount_vers_max >= MOUNTVERS) {
6517c478bd9Sstevel@tonic-gate 		if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "datagram_v") == 0) {
652250a0733Sth199096 			fprintf(stderr,
653361f55a5SMarcel Telka 			    "couldn't register datagram_v MOUNTVERS\n");
6547c478bd9Sstevel@tonic-gate 			exit(1);
6557c478bd9Sstevel@tonic-gate 		}
6567c478bd9Sstevel@tonic-gate 		if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "circuit_v") == 0) {
657250a0733Sth199096 			fprintf(stderr,
658361f55a5SMarcel Telka 			    "couldn't register circuit_v MOUNTVERS\n");
6597c478bd9Sstevel@tonic-gate 			exit(1);
6607c478bd9Sstevel@tonic-gate 		}
6617c478bd9Sstevel@tonic-gate 	}
6624a508a79SThomas Haynes 
6637c478bd9Sstevel@tonic-gate 	if (mount_vers_max >= MOUNTVERS_POSIX) {
6647c478bd9Sstevel@tonic-gate 		if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX,
6657c478bd9Sstevel@tonic-gate 		    "datagram_v") == 0) {
666250a0733Sth199096 			fprintf(stderr,
667361f55a5SMarcel Telka 			    "couldn't register datagram_v MOUNTVERS_POSIX\n");
6687c478bd9Sstevel@tonic-gate 			exit(1);
6697c478bd9Sstevel@tonic-gate 		}
6707c478bd9Sstevel@tonic-gate 		if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX,
6717c478bd9Sstevel@tonic-gate 		    "circuit_v") == 0) {
672250a0733Sth199096 			fprintf(stderr,
673361f55a5SMarcel Telka 			    "couldn't register circuit_v MOUNTVERS_POSIX\n");
6747c478bd9Sstevel@tonic-gate 			exit(1);
6757c478bd9Sstevel@tonic-gate 		}
6767c478bd9Sstevel@tonic-gate 	}
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	if (mount_vers_max >= MOUNTVERS3) {
6797c478bd9Sstevel@tonic-gate 		if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "datagram_v") == 0) {
680250a0733Sth199096 			fprintf(stderr,
681361f55a5SMarcel Telka 			    "couldn't register datagram_v MOUNTVERS3\n");
6827c478bd9Sstevel@tonic-gate 			exit(1);
6837c478bd9Sstevel@tonic-gate 		}
6847c478bd9Sstevel@tonic-gate 		if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "circuit_v") == 0) {
685250a0733Sth199096 			fprintf(stderr,
686361f55a5SMarcel Telka 			    "couldn't register circuit_v MOUNTVERS3\n");
6877c478bd9Sstevel@tonic-gate 			exit(1);
6887c478bd9Sstevel@tonic-gate 		}
6897c478bd9Sstevel@tonic-gate 	}
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	/*
6927c478bd9Sstevel@tonic-gate 	 * Start serving
6937c478bd9Sstevel@tonic-gate 	 */
6947c478bd9Sstevel@tonic-gate 	rmtab_load();
695250a0733Sth199096 
696250a0733Sth199096 	daemonize_fini(pipe_fd);
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	/* Get rid of the most dangerous basic privileges. */
6997c478bd9Sstevel@tonic-gate 	__fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_INFO, PRIV_PROC_SESSION,
7007c478bd9Sstevel@tonic-gate 	    (char *)NULL);
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	svc_run();
7037c478bd9Sstevel@tonic-gate 	syslog(LOG_ERR, "Error: svc_run shouldn't have returned");
7047c478bd9Sstevel@tonic-gate 	abort();
705250a0733Sth199096 
7067c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
70711606941Sjwahlig 	return (0);
7087c478bd9Sstevel@tonic-gate }
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate /*
7117c478bd9Sstevel@tonic-gate  * Server procedure switch routine
7127c478bd9Sstevel@tonic-gate  */
7137c478bd9Sstevel@tonic-gate void
7147c478bd9Sstevel@tonic-gate mnt(struct svc_req *rqstp, SVCXPRT *transp)
7157c478bd9Sstevel@tonic-gate {
7167c478bd9Sstevel@tonic-gate 	switch (rqstp->rq_proc) {
7177c478bd9Sstevel@tonic-gate 	case NULLPROC:
7187c478bd9Sstevel@tonic-gate 		errno = 0;
7197c478bd9Sstevel@tonic-gate 		if (!svc_sendreply(transp, xdr_void, (char *)0))
7207c478bd9Sstevel@tonic-gate 			log_cant_reply(transp);
7217c478bd9Sstevel@tonic-gate 		return;
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 	case MOUNTPROC_MNT:
7244a508a79SThomas Haynes 		(void) mount(rqstp);
7257c478bd9Sstevel@tonic-gate 		return;
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 	case MOUNTPROC_DUMP:
7287c478bd9Sstevel@tonic-gate 		mntlist_send(transp);
7297c478bd9Sstevel@tonic-gate 		return;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	case MOUNTPROC_UMNT:
7327c478bd9Sstevel@tonic-gate 		umount(rqstp);
7337c478bd9Sstevel@tonic-gate 		return;
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	case MOUNTPROC_UMNTALL:
7367c478bd9Sstevel@tonic-gate 		umountall(rqstp);
7377c478bd9Sstevel@tonic-gate 		return;
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 	case MOUNTPROC_EXPORT:
7407c478bd9Sstevel@tonic-gate 	case MOUNTPROC_EXPORTALL:
7417c478bd9Sstevel@tonic-gate 		export(rqstp);
7427c478bd9Sstevel@tonic-gate 		return;
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	case MOUNTPROC_PATHCONF:
7457c478bd9Sstevel@tonic-gate 		if (rqstp->rq_vers == MOUNTVERS_POSIX)
7467c478bd9Sstevel@tonic-gate 			mnt_pathconf(rqstp);
7477c478bd9Sstevel@tonic-gate 		else
7487c478bd9Sstevel@tonic-gate 			svcerr_noproc(transp);
7497c478bd9Sstevel@tonic-gate 		return;
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	default:
7527c478bd9Sstevel@tonic-gate 		svcerr_noproc(transp);
7537c478bd9Sstevel@tonic-gate 		return;
7547c478bd9Sstevel@tonic-gate 	}
7557c478bd9Sstevel@tonic-gate }
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate void
758*a9685eaaSMarcel Telka log_cant_reply_cln(struct cln *cln)
7597c478bd9Sstevel@tonic-gate {
7607c478bd9Sstevel@tonic-gate 	int saverrno;
76154d34259SMarcel Telka 	char *host;
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	saverrno = errno;	/* save error code */
764*a9685eaaSMarcel Telka 
765*a9685eaaSMarcel Telka 	host = cln_gethost(cln);
766*a9685eaaSMarcel Telka 	if (host == NULL)
7677c478bd9Sstevel@tonic-gate 		return;
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	errno = saverrno;
7707c478bd9Sstevel@tonic-gate 	if (errno == 0)
7717c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "couldn't send reply to %s", host);
7727c478bd9Sstevel@tonic-gate 	else
7737c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "couldn't send reply to %s: %m", host);
774*a9685eaaSMarcel Telka }
7757c478bd9Sstevel@tonic-gate 
776*a9685eaaSMarcel Telka void
777*a9685eaaSMarcel Telka log_cant_reply(SVCXPRT *transp)
778*a9685eaaSMarcel Telka {
779*a9685eaaSMarcel Telka 	int saverrno;
780*a9685eaaSMarcel Telka 	struct cln cln;
781*a9685eaaSMarcel Telka 
782*a9685eaaSMarcel Telka 	saverrno = errno;	/* save error code */
783*a9685eaaSMarcel Telka 	cln_init(&cln, transp);
784*a9685eaaSMarcel Telka 	errno = saverrno;
785*a9685eaaSMarcel Telka 
786*a9685eaaSMarcel Telka 	log_cant_reply_cln(&cln);
787*a9685eaaSMarcel Telka 
788*a9685eaaSMarcel Telka 	cln_fini(&cln);
7897c478bd9Sstevel@tonic-gate }
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate /*
7927c478bd9Sstevel@tonic-gate  * Answer pathconf questions for the mount point fs
7937c478bd9Sstevel@tonic-gate  */
7947c478bd9Sstevel@tonic-gate static void
7957c478bd9Sstevel@tonic-gate mnt_pathconf(struct svc_req *rqstp)
7967c478bd9Sstevel@tonic-gate {
7977c478bd9Sstevel@tonic-gate 	SVCXPRT *transp;
7987c478bd9Sstevel@tonic-gate 	struct pathcnf p;
7997c478bd9Sstevel@tonic-gate 	char *path, rpath[MAXPATHLEN];
8007c478bd9Sstevel@tonic-gate 	struct stat st;
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	transp = rqstp->rq_xprt;
8037c478bd9Sstevel@tonic-gate 	path = NULL;
8047c478bd9Sstevel@tonic-gate 	(void) memset((caddr_t)&p, 0, sizeof (p));
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
8077c478bd9Sstevel@tonic-gate 		svcerr_decode(transp);
8087c478bd9Sstevel@tonic-gate 		return;
8097c478bd9Sstevel@tonic-gate 	}
8107c478bd9Sstevel@tonic-gate 	if (lstat(path, &st) < 0) {
8117c478bd9Sstevel@tonic-gate 		_PC_SET(_PC_ERROR, p.pc_mask);
8127c478bd9Sstevel@tonic-gate 		goto done;
8137c478bd9Sstevel@tonic-gate 	}
8147c478bd9Sstevel@tonic-gate 	/*
8157c478bd9Sstevel@tonic-gate 	 * Get a path without symbolic links.
8167c478bd9Sstevel@tonic-gate 	 */
8177c478bd9Sstevel@tonic-gate 	if (realpath(path, rpath) == NULL) {
8187c478bd9Sstevel@tonic-gate 		syslog(LOG_DEBUG,
8197c478bd9Sstevel@tonic-gate 		    "mount request: realpath failed on %s: %m",
8207c478bd9Sstevel@tonic-gate 		    path);
8217c478bd9Sstevel@tonic-gate 		_PC_SET(_PC_ERROR, p.pc_mask);
8227c478bd9Sstevel@tonic-gate 		goto done;
8237c478bd9Sstevel@tonic-gate 	}
8247c478bd9Sstevel@tonic-gate 	(void) memset((caddr_t)&p, 0, sizeof (p));
8257c478bd9Sstevel@tonic-gate 	/*
8267c478bd9Sstevel@tonic-gate 	 * can't ask about devices over NFS
8277c478bd9Sstevel@tonic-gate 	 */
8287c478bd9Sstevel@tonic-gate 	_PC_SET(_PC_MAX_CANON, p.pc_mask);
8297c478bd9Sstevel@tonic-gate 	_PC_SET(_PC_MAX_INPUT, p.pc_mask);
8307c478bd9Sstevel@tonic-gate 	_PC_SET(_PC_PIPE_BUF, p.pc_mask);
8317c478bd9Sstevel@tonic-gate 	_PC_SET(_PC_VDISABLE, p.pc_mask);
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 	errno = 0;
8347c478bd9Sstevel@tonic-gate 	p.pc_link_max = pathconf(rpath, _PC_LINK_MAX);
8357c478bd9Sstevel@tonic-gate 	if (errno)
8367c478bd9Sstevel@tonic-gate 		_PC_SET(_PC_LINK_MAX, p.pc_mask);
8377c478bd9Sstevel@tonic-gate 	p.pc_name_max = pathconf(rpath, _PC_NAME_MAX);
8387c478bd9Sstevel@tonic-gate 	if (errno)
8397c478bd9Sstevel@tonic-gate 		_PC_SET(_PC_NAME_MAX, p.pc_mask);
8407c478bd9Sstevel@tonic-gate 	p.pc_path_max = pathconf(rpath, _PC_PATH_MAX);
8417c478bd9Sstevel@tonic-gate 	if (errno)
8427c478bd9Sstevel@tonic-gate 		_PC_SET(_PC_PATH_MAX, p.pc_mask);
8437c478bd9Sstevel@tonic-gate 	if (pathconf(rpath, _PC_NO_TRUNC) == 1)
8447c478bd9Sstevel@tonic-gate 		_PC_SET(_PC_NO_TRUNC, p.pc_mask);
8457c478bd9Sstevel@tonic-gate 	if (pathconf(rpath, _PC_CHOWN_RESTRICTED) == 1)
8467c478bd9Sstevel@tonic-gate 		_PC_SET(_PC_CHOWN_RESTRICTED, p.pc_mask);
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate done:
8497c478bd9Sstevel@tonic-gate 	errno = 0;
8507c478bd9Sstevel@tonic-gate 	if (!svc_sendreply(transp, xdr_ppathcnf, (char *)&p))
8517c478bd9Sstevel@tonic-gate 		log_cant_reply(transp);
8527c478bd9Sstevel@tonic-gate 	if (path != NULL)
8537c478bd9Sstevel@tonic-gate 		svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
8547c478bd9Sstevel@tonic-gate }
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate /*
8577c478bd9Sstevel@tonic-gate  * If the rootmount (export) option is specified, the all mount requests for
8587c478bd9Sstevel@tonic-gate  * subdirectories return EACCES.
8597c478bd9Sstevel@tonic-gate  */
8607c478bd9Sstevel@tonic-gate static int
8614a508a79SThomas Haynes checkrootmount(share_t *sh, char *rpath)
8627c478bd9Sstevel@tonic-gate {
8637c478bd9Sstevel@tonic-gate 	char *val;
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 	if ((val = getshareopt(sh->sh_opts, SHOPT_NOSUB)) != NULL) {
8667c478bd9Sstevel@tonic-gate 		free(val);
8677c478bd9Sstevel@tonic-gate 		if (strcmp(sh->sh_path, rpath) != 0)
8687c478bd9Sstevel@tonic-gate 			return (0);
8697c478bd9Sstevel@tonic-gate 		else
8707c478bd9Sstevel@tonic-gate 			return (1);
8717c478bd9Sstevel@tonic-gate 	} else
8727c478bd9Sstevel@tonic-gate 		return (1);
8737c478bd9Sstevel@tonic-gate }
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate #define	MAX_FLAVORS	128
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate /*
8787c478bd9Sstevel@tonic-gate  * Return only EACCES if client does not have access
8797c478bd9Sstevel@tonic-gate  *  to this directory.
8807c478bd9Sstevel@tonic-gate  * "If the server exports only /a/b, an attempt to
8817c478bd9Sstevel@tonic-gate  *  mount a/b/c will fail with ENOENT if the directory
8827c478bd9Sstevel@tonic-gate  *  does not exist"... However, if the client
8837c478bd9Sstevel@tonic-gate  *  does not have access to /a/b, an attacker can
8847c478bd9Sstevel@tonic-gate  *  determine whether the directory exists.
8857c478bd9Sstevel@tonic-gate  * This routine checks either existence of the file or
8867c478bd9Sstevel@tonic-gate  * existence of the file name entry in the mount table.
8877c478bd9Sstevel@tonic-gate  * If the file exists and there is no file name entry,
8887c478bd9Sstevel@tonic-gate  * the error returned should be EACCES.
8897c478bd9Sstevel@tonic-gate  * If the file does not exist, it must be determined
8907c478bd9Sstevel@tonic-gate  * whether the client has access to a parent
8917c478bd9Sstevel@tonic-gate  * directory.  If the client has access to a parent
8927c478bd9Sstevel@tonic-gate  * directory, the error returned should be ENOENT,
8937c478bd9Sstevel@tonic-gate  * otherwise EACCES.
8947c478bd9Sstevel@tonic-gate  */
8957c478bd9Sstevel@tonic-gate static int
896*a9685eaaSMarcel Telka mount_enoent_error(struct cln *cln, char *path, char *rpath, int *flavor_list)
8977c478bd9Sstevel@tonic-gate {
8987c478bd9Sstevel@tonic-gate 	char *checkpath, *dp;
8994a508a79SThomas Haynes 	share_t *sh = NULL;
9007c478bd9Sstevel@tonic-gate 	int realpath_error = ENOENT, reply_error = EACCES, lofs_tried = 0;
9017c478bd9Sstevel@tonic-gate 	int flavor_count;
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	checkpath = strdup(path);
9047c478bd9Sstevel@tonic-gate 	if (checkpath == NULL) {
9057c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "mount_enoent: no memory");
9067c478bd9Sstevel@tonic-gate 		return (EACCES);
9077c478bd9Sstevel@tonic-gate 	}
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 	/* CONSTCOND */
9107c478bd9Sstevel@tonic-gate 	while (1) {
9117c478bd9Sstevel@tonic-gate 		if (sh) {
9127c478bd9Sstevel@tonic-gate 			sharefree(sh);
9137c478bd9Sstevel@tonic-gate 			sh = NULL;
9147c478bd9Sstevel@tonic-gate 		}
9154a508a79SThomas Haynes 
9167c478bd9Sstevel@tonic-gate 		if ((sh = findentry(rpath)) == NULL &&
9177c478bd9Sstevel@tonic-gate 		    (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) {
9187c478bd9Sstevel@tonic-gate 			/*
9197c478bd9Sstevel@tonic-gate 			 * There is no file name entry.
9207c478bd9Sstevel@tonic-gate 			 * If the file (with symbolic links resolved) exists,
9217c478bd9Sstevel@tonic-gate 			 * the error returned should be EACCES.
9227c478bd9Sstevel@tonic-gate 			 */
9237c478bd9Sstevel@tonic-gate 			if (realpath_error == 0)
9247c478bd9Sstevel@tonic-gate 				break;
9257c478bd9Sstevel@tonic-gate 		} else if (checkrootmount(sh, rpath) == 0) {
9267c478bd9Sstevel@tonic-gate 			/*
9277c478bd9Sstevel@tonic-gate 			 * This is a "nosub" only export, in which case,
9287c478bd9Sstevel@tonic-gate 			 * mounting subdirectories isn't allowed.
9297c478bd9Sstevel@tonic-gate 			 * If the file (with symbolic links resolved) exists,
9307c478bd9Sstevel@tonic-gate 			 * the error returned should be EACCES.
9317c478bd9Sstevel@tonic-gate 			 */
9327c478bd9Sstevel@tonic-gate 			if (realpath_error == 0)
9337c478bd9Sstevel@tonic-gate 				break;
9347c478bd9Sstevel@tonic-gate 		} else {
9357c478bd9Sstevel@tonic-gate 			/*
9367c478bd9Sstevel@tonic-gate 			 * Check permissions in mount table.
9377c478bd9Sstevel@tonic-gate 			 */
9387c478bd9Sstevel@tonic-gate 			if (newopts(sh->sh_opts))
939*a9685eaaSMarcel Telka 				flavor_count = getclientsflavors_new(sh, cln,
940*a9685eaaSMarcel Telka 				    flavor_list);
9417c478bd9Sstevel@tonic-gate 			else
942*a9685eaaSMarcel Telka 				flavor_count = getclientsflavors_old(sh, cln,
943*a9685eaaSMarcel Telka 				    flavor_list);
9447c478bd9Sstevel@tonic-gate 			if (flavor_count != 0) {
9457c478bd9Sstevel@tonic-gate 				/*
9467c478bd9Sstevel@tonic-gate 				 * Found entry in table and
9477c478bd9Sstevel@tonic-gate 				 * client has correct permissions.
9487c478bd9Sstevel@tonic-gate 				 */
9497c478bd9Sstevel@tonic-gate 				reply_error = ENOENT;
9507c478bd9Sstevel@tonic-gate 				break;
9517c478bd9Sstevel@tonic-gate 			}
9527c478bd9Sstevel@tonic-gate 		}
9534a508a79SThomas Haynes 
9547c478bd9Sstevel@tonic-gate 		/*
9557c478bd9Sstevel@tonic-gate 		 * Check all parent directories.
9567c478bd9Sstevel@tonic-gate 		 */
9577c478bd9Sstevel@tonic-gate 		dp = strrchr(checkpath, '/');
9587c478bd9Sstevel@tonic-gate 		if (dp == NULL)
9597c478bd9Sstevel@tonic-gate 			break;
9607c478bd9Sstevel@tonic-gate 		*dp = '\0';
9617c478bd9Sstevel@tonic-gate 		if (strlen(checkpath) == 0)
9627c478bd9Sstevel@tonic-gate 			break;
9637c478bd9Sstevel@tonic-gate 		/*
9647c478bd9Sstevel@tonic-gate 		 * Get the real path (no symbolic links in it)
9657c478bd9Sstevel@tonic-gate 		 */
9667c478bd9Sstevel@tonic-gate 		if (realpath(checkpath, rpath) == NULL) {
9677c478bd9Sstevel@tonic-gate 			if (errno != ENOENT)
9687c478bd9Sstevel@tonic-gate 				break;
9697c478bd9Sstevel@tonic-gate 		} else {
9707c478bd9Sstevel@tonic-gate 			realpath_error = 0;
9717c478bd9Sstevel@tonic-gate 		}
9727c478bd9Sstevel@tonic-gate 	}
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 	if (sh)
9757c478bd9Sstevel@tonic-gate 		sharefree(sh);
9767c478bd9Sstevel@tonic-gate 	free(checkpath);
9777c478bd9Sstevel@tonic-gate 	return (reply_error);
9787c478bd9Sstevel@tonic-gate }
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate /*
9814a508a79SThomas Haynes  * We need to inform the caller whether or not we were
9824a508a79SThomas Haynes  * able to add a node to the queue. If we are not, then
9834a508a79SThomas Haynes  * it is up to the caller to go ahead and log the data.
9844a508a79SThomas Haynes  */
9854a508a79SThomas Haynes static int
9864a508a79SThomas Haynes enqueue_logging_data(char *host, SVCXPRT *transp, char *path,
9874a508a79SThomas Haynes     char *rpath, int status, int error)
9884a508a79SThomas Haynes {
9894a508a79SThomas Haynes 	logging_data	*lq;
9904a508a79SThomas Haynes 	struct netbuf	*nb;
9914a508a79SThomas Haynes 
9924a508a79SThomas Haynes 	lq = (logging_data *)calloc(1, sizeof (logging_data));
9934a508a79SThomas Haynes 	if (lq == NULL)
9944a508a79SThomas Haynes 		goto cleanup;
9954a508a79SThomas Haynes 
9964a508a79SThomas Haynes 	/*
9974a508a79SThomas Haynes 	 * We might not yet have the host...
9984a508a79SThomas Haynes 	 */
9994a508a79SThomas Haynes 	if (host) {
10004a508a79SThomas Haynes 		DTRACE_PROBE1(mountd, log_host, host);
10014a508a79SThomas Haynes 		lq->ld_host = strdup(host);
10024a508a79SThomas Haynes 		if (lq->ld_host == NULL)
10034a508a79SThomas Haynes 			goto cleanup;
10044a508a79SThomas Haynes 	} else {
10054a508a79SThomas Haynes 		DTRACE_PROBE(mountd, log_no_host);
10064a508a79SThomas Haynes 
10074a508a79SThomas Haynes 		lq->ld_netid = strdup(transp->xp_netid);
10084a508a79SThomas Haynes 		if (lq->ld_netid == NULL)
10094a508a79SThomas Haynes 			goto cleanup;
10104a508a79SThomas Haynes 
10114a508a79SThomas Haynes 		lq->ld_nb = calloc(1, sizeof (struct netbuf));
10124a508a79SThomas Haynes 		if (lq->ld_nb == NULL)
10134a508a79SThomas Haynes 			goto cleanup;
10144a508a79SThomas Haynes 
10154a508a79SThomas Haynes 		nb = svc_getrpccaller(transp);
10164a508a79SThomas Haynes 		if (nb == NULL) {
10174a508a79SThomas Haynes 			DTRACE_PROBE(mountd, e__nb__enqueue);
10184a508a79SThomas Haynes 			goto cleanup;
10194a508a79SThomas Haynes 		}
10204a508a79SThomas Haynes 
10214a508a79SThomas Haynes 		DTRACE_PROBE(mountd, nb_set_enqueue);
10224a508a79SThomas Haynes 
10234a508a79SThomas Haynes 		lq->ld_nb->maxlen = nb->maxlen;
10244a508a79SThomas Haynes 		lq->ld_nb->len = nb->len;
10254a508a79SThomas Haynes 
10264a508a79SThomas Haynes 		lq->ld_nb->buf = malloc(lq->ld_nb->len);
10274a508a79SThomas Haynes 		if (lq->ld_nb->buf == NULL)
10284a508a79SThomas Haynes 			goto cleanup;
10294a508a79SThomas Haynes 
10304a508a79SThomas Haynes 		bcopy(nb->buf, lq->ld_nb->buf, lq->ld_nb->len);
10314a508a79SThomas Haynes 	}
10324a508a79SThomas Haynes 
10334a508a79SThomas Haynes 	lq->ld_path = strdup(path);
10344a508a79SThomas Haynes 	if (lq->ld_path == NULL)
10354a508a79SThomas Haynes 		goto cleanup;
10364a508a79SThomas Haynes 
10374a508a79SThomas Haynes 	if (!error) {
10384a508a79SThomas Haynes 		lq->ld_rpath = strdup(rpath);
10394a508a79SThomas Haynes 		if (lq->ld_rpath == NULL)
10404a508a79SThomas Haynes 			goto cleanup;
10414a508a79SThomas Haynes 	}
10424a508a79SThomas Haynes 
10434a508a79SThomas Haynes 	lq->ld_status = status;
10444a508a79SThomas Haynes 
10454a508a79SThomas Haynes 	/*
10464a508a79SThomas Haynes 	 * Add to the tail of the logging queue.
10474a508a79SThomas Haynes 	 */
10484a508a79SThomas Haynes 	(void) mutex_lock(&logging_queue_lock);
10494a508a79SThomas Haynes 	if (logging_tail == NULL) {
10504a508a79SThomas Haynes 		logging_tail = logging_head = lq;
10514a508a79SThomas Haynes 	} else {
10524a508a79SThomas Haynes 		logging_tail->ld_next = lq;
10534a508a79SThomas Haynes 		logging_tail = lq;
10544a508a79SThomas Haynes 	}
10554a508a79SThomas Haynes 	(void) cond_signal(&logging_queue_cv);
10564a508a79SThomas Haynes 	(void) mutex_unlock(&logging_queue_lock);
10574a508a79SThomas Haynes 
10584a508a79SThomas Haynes 	return (TRUE);
10594a508a79SThomas Haynes 
10604a508a79SThomas Haynes cleanup:
10614a508a79SThomas Haynes 
10624a508a79SThomas Haynes 	free_logging_data(lq);
10634a508a79SThomas Haynes 
10644a508a79SThomas Haynes 	return (FALSE);
10654a508a79SThomas Haynes }
10664a508a79SThomas Haynes 
1067*a9685eaaSMarcel Telka 
1068*a9685eaaSMarcel Telka #define	CLN_CLNAMES	(1 << 0)
1069*a9685eaaSMarcel Telka #define	CLN_HOST	(1 << 1)
1070*a9685eaaSMarcel Telka 
1071*a9685eaaSMarcel Telka static void
1072*a9685eaaSMarcel Telka cln_init_common(struct cln *cln, SVCXPRT *transp, char *netid,
1073*a9685eaaSMarcel Telka     struct netbuf *nbuf)
1074*a9685eaaSMarcel Telka {
1075*a9685eaaSMarcel Telka 	if ((cln->transp = transp) != NULL) {
1076*a9685eaaSMarcel Telka 		assert(netid == NULL && nbuf == NULL);
1077*a9685eaaSMarcel Telka 		cln->netid = transp->xp_netid;
1078*a9685eaaSMarcel Telka 		cln->nbuf = svc_getrpccaller(transp);
1079*a9685eaaSMarcel Telka 	} else {
1080*a9685eaaSMarcel Telka 		cln->netid = netid;
1081*a9685eaaSMarcel Telka 		cln->nbuf = nbuf;
1082*a9685eaaSMarcel Telka 	}
1083*a9685eaaSMarcel Telka 
1084*a9685eaaSMarcel Telka 	cln->nconf = NULL;
1085*a9685eaaSMarcel Telka 	cln->clnames = NULL;
1086*a9685eaaSMarcel Telka 	cln->host = NULL;
1087*a9685eaaSMarcel Telka 
1088*a9685eaaSMarcel Telka 	cln->flags = 0;
1089*a9685eaaSMarcel Telka }
1090*a9685eaaSMarcel Telka 
1091*a9685eaaSMarcel Telka void
1092*a9685eaaSMarcel Telka cln_init(struct cln *cln, SVCXPRT *transp)
1093*a9685eaaSMarcel Telka {
1094*a9685eaaSMarcel Telka 	cln_init_common(cln, transp, NULL, NULL);
1095*a9685eaaSMarcel Telka }
1096*a9685eaaSMarcel Telka 
1097*a9685eaaSMarcel Telka void
1098*a9685eaaSMarcel Telka cln_init_lazy(struct cln *cln, char *netid, struct netbuf *nbuf)
1099*a9685eaaSMarcel Telka {
1100*a9685eaaSMarcel Telka 	cln_init_common(cln, NULL, netid, nbuf);
1101*a9685eaaSMarcel Telka }
1102*a9685eaaSMarcel Telka 
1103*a9685eaaSMarcel Telka void
1104*a9685eaaSMarcel Telka cln_fini(struct cln *cln)
1105*a9685eaaSMarcel Telka {
1106*a9685eaaSMarcel Telka 	if (cln->nconf != NULL)
1107*a9685eaaSMarcel Telka 		freenetconfigent(cln->nconf);
1108*a9685eaaSMarcel Telka 
1109*a9685eaaSMarcel Telka 	if (cln->clnames != NULL)
1110*a9685eaaSMarcel Telka 		netdir_free(cln->clnames, ND_HOSTSERVLIST);
1111*a9685eaaSMarcel Telka 
1112*a9685eaaSMarcel Telka 	free(cln->host);
1113*a9685eaaSMarcel Telka }
1114*a9685eaaSMarcel Telka 
1115*a9685eaaSMarcel Telka struct netbuf *
1116*a9685eaaSMarcel Telka cln_getnbuf(struct cln *cln)
1117*a9685eaaSMarcel Telka {
1118*a9685eaaSMarcel Telka 	return (cln->nbuf);
1119*a9685eaaSMarcel Telka }
1120*a9685eaaSMarcel Telka 
1121*a9685eaaSMarcel Telka struct nd_hostservlist *
1122*a9685eaaSMarcel Telka cln_getclientsnames(struct cln *cln)
1123*a9685eaaSMarcel Telka {
1124*a9685eaaSMarcel Telka 	if ((cln->flags & CLN_CLNAMES) == 0) {
1125*a9685eaaSMarcel Telka 		/*
1126*a9685eaaSMarcel Telka 		 * nconf is not needed if we do not have nbuf (see
1127*a9685eaaSMarcel Telka 		 * cln_gethost() too), so we check for nbuf and in a case it is
1128*a9685eaaSMarcel Telka 		 * NULL we do not try to get nconf.
1129*a9685eaaSMarcel Telka 		 */
1130*a9685eaaSMarcel Telka 		if (cln->netid != NULL && cln->nbuf != NULL) {
1131*a9685eaaSMarcel Telka 			cln->nconf = getnetconfigent(cln->netid);
1132*a9685eaaSMarcel Telka 			if (cln->nconf == NULL)
1133*a9685eaaSMarcel Telka 				syslog(LOG_ERR, "%s: getnetconfigent failed",
1134*a9685eaaSMarcel Telka 				    cln->netid);
1135*a9685eaaSMarcel Telka 		}
1136*a9685eaaSMarcel Telka 
1137*a9685eaaSMarcel Telka 		if (cln->nconf != NULL && cln->nbuf != NULL)
1138*a9685eaaSMarcel Telka 			(void) __netdir_getbyaddr_nosrv(cln->nconf,
1139*a9685eaaSMarcel Telka 			    &cln->clnames, cln->nbuf);
1140*a9685eaaSMarcel Telka 
1141*a9685eaaSMarcel Telka 		cln->flags |= CLN_CLNAMES;
1142*a9685eaaSMarcel Telka 	}
1143*a9685eaaSMarcel Telka 
1144*a9685eaaSMarcel Telka 	return (cln->clnames);
1145*a9685eaaSMarcel Telka }
1146*a9685eaaSMarcel Telka 
1147*a9685eaaSMarcel Telka /*
1148*a9685eaaSMarcel Telka  * Return B_TRUE if the host is already available at no cost
1149*a9685eaaSMarcel Telka  */
1150*a9685eaaSMarcel Telka boolean_t
1151*a9685eaaSMarcel Telka cln_havehost(struct cln *cln)
1152*a9685eaaSMarcel Telka {
1153*a9685eaaSMarcel Telka 	return ((cln->flags & (CLN_CLNAMES | CLN_HOST)) != 0);
1154*a9685eaaSMarcel Telka }
1155*a9685eaaSMarcel Telka 
1156*a9685eaaSMarcel Telka char *
1157*a9685eaaSMarcel Telka cln_gethost(struct cln *cln)
1158*a9685eaaSMarcel Telka {
1159*a9685eaaSMarcel Telka 	if (cln_getclientsnames(cln) != NULL)
1160*a9685eaaSMarcel Telka 		return (cln->clnames->h_hostservs[0].h_host);
1161*a9685eaaSMarcel Telka 
1162*a9685eaaSMarcel Telka 	if ((cln->flags & CLN_HOST) == 0) {
1163*a9685eaaSMarcel Telka 		if (cln->nconf == NULL || cln->nbuf == NULL) {
1164*a9685eaaSMarcel Telka 			cln->host = strdup("(anon)");
1165*a9685eaaSMarcel Telka 		} else {
1166*a9685eaaSMarcel Telka 			char host[MAXIPADDRLEN];
1167*a9685eaaSMarcel Telka 
1168*a9685eaaSMarcel Telka 			if (strcmp(cln->nconf->nc_protofmly, NC_INET) == 0) {
1169*a9685eaaSMarcel Telka 				struct sockaddr_in *sa;
1170*a9685eaaSMarcel Telka 
1171*a9685eaaSMarcel Telka 				/* LINTED pointer alignment */
1172*a9685eaaSMarcel Telka 				sa = (struct sockaddr_in *)(cln->nbuf->buf);
1173*a9685eaaSMarcel Telka 				(void) inet_ntoa_r(sa->sin_addr, host);
1174*a9685eaaSMarcel Telka 
1175*a9685eaaSMarcel Telka 				cln->host = strdup(host);
1176*a9685eaaSMarcel Telka 			} else if (strcmp(cln->nconf->nc_protofmly,
1177*a9685eaaSMarcel Telka 			    NC_INET6) == 0) {
1178*a9685eaaSMarcel Telka 				struct sockaddr_in6 *sa;
1179*a9685eaaSMarcel Telka 
1180*a9685eaaSMarcel Telka 				/* LINTED pointer alignment */
1181*a9685eaaSMarcel Telka 				sa = (struct sockaddr_in6 *)(cln->nbuf->buf);
1182*a9685eaaSMarcel Telka 				(void) inet_ntop(AF_INET6,
1183*a9685eaaSMarcel Telka 				    sa->sin6_addr.s6_addr,
1184*a9685eaaSMarcel Telka 				    host, INET6_ADDRSTRLEN);
1185*a9685eaaSMarcel Telka 
1186*a9685eaaSMarcel Telka 				cln->host = strdup(host);
1187*a9685eaaSMarcel Telka 			} else {
1188*a9685eaaSMarcel Telka 				syslog(LOG_ERR, gettext("Client's address is "
1189*a9685eaaSMarcel Telka 				    "neither IPv4 nor IPv6"));
1190*a9685eaaSMarcel Telka 
1191*a9685eaaSMarcel Telka 				cln->host = strdup("(anon)");
1192*a9685eaaSMarcel Telka 			}
1193*a9685eaaSMarcel Telka 		}
1194*a9685eaaSMarcel Telka 
1195*a9685eaaSMarcel Telka 		cln->flags |= CLN_HOST;
1196*a9685eaaSMarcel Telka 	}
1197*a9685eaaSMarcel Telka 
1198*a9685eaaSMarcel Telka 	return (cln->host);
1199*a9685eaaSMarcel Telka }
1200*a9685eaaSMarcel Telka 
12014a508a79SThomas Haynes /*
12027c478bd9Sstevel@tonic-gate  * Check mount requests, add to mounted list if ok
12037c478bd9Sstevel@tonic-gate  */
12044a508a79SThomas Haynes static int
12057c478bd9Sstevel@tonic-gate mount(struct svc_req *rqstp)
12067c478bd9Sstevel@tonic-gate {
12077c478bd9Sstevel@tonic-gate 	SVCXPRT *transp;
120827242a7cSthurlow 	int version, vers;
12097c478bd9Sstevel@tonic-gate 	struct fhstatus fhs;
12107c478bd9Sstevel@tonic-gate 	struct mountres3 mountres3;
121127242a7cSthurlow 	char fh[FHSIZE3];
121227242a7cSthurlow 	int len = FHSIZE3;
12137c478bd9Sstevel@tonic-gate 	char *path, rpath[MAXPATHLEN];
12144a508a79SThomas Haynes 	share_t *sh = NULL;
1215*a9685eaaSMarcel Telka 	struct cln cln;
12167c478bd9Sstevel@tonic-gate 	char *host = NULL;
12174a508a79SThomas Haynes 	int error = 0, lofs_tried = 0, enqueued;
12187c478bd9Sstevel@tonic-gate 	int flavor_list[MAX_FLAVORS];
12197c478bd9Sstevel@tonic-gate 	int flavor_count;
122003986916Sjarrett 	ucred_t	*uc = NULL;
12217c478bd9Sstevel@tonic-gate 
12224a508a79SThomas Haynes 	int audit_status;
12234a508a79SThomas Haynes 
12247c478bd9Sstevel@tonic-gate 	transp = rqstp->rq_xprt;
12257c478bd9Sstevel@tonic-gate 	version = rqstp->rq_vers;
12267c478bd9Sstevel@tonic-gate 	path = NULL;
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate 	if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
12297c478bd9Sstevel@tonic-gate 		svcerr_decode(transp);
12304a508a79SThomas Haynes 		return (EACCES);
12317c478bd9Sstevel@tonic-gate 	}
12327c478bd9Sstevel@tonic-gate 
1233*a9685eaaSMarcel Telka 	cln_init(&cln, transp);
1234*a9685eaaSMarcel Telka 
12354a508a79SThomas Haynes 	/*
12364a508a79SThomas Haynes 	 * Put off getting the name for the client until we
12374a508a79SThomas Haynes 	 * need it. This is a performance gain. If we are logging,
12384a508a79SThomas Haynes 	 * then we don't care about performance and might as well
12394a508a79SThomas Haynes 	 * get the host name now in case we need to spit out an
12404a508a79SThomas Haynes 	 * error message.
12414a508a79SThomas Haynes 	 */
12424a508a79SThomas Haynes 	if (verbose) {
12434a508a79SThomas Haynes 		DTRACE_PROBE(mountd, name_by_verbose);
1244*a9685eaaSMarcel Telka 		if ((host = cln_gethost(&cln)) == NULL) {
12457c478bd9Sstevel@tonic-gate 			/*
12464a508a79SThomas Haynes 			 * We failed to get a name for the client, even
12474a508a79SThomas Haynes 			 * 'anon', probably because we ran out of memory.
12484a508a79SThomas Haynes 			 * In this situation it doesn't make sense to
12494a508a79SThomas Haynes 			 * allow the mount to succeed.
12507c478bd9Sstevel@tonic-gate 			 */
12517c478bd9Sstevel@tonic-gate 			error = EACCES;
12527c478bd9Sstevel@tonic-gate 			goto reply;
12537c478bd9Sstevel@tonic-gate 		}
12544a508a79SThomas Haynes 	}
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	/*
12577c478bd9Sstevel@tonic-gate 	 * If the version being used is less than the minimum version,
12587c478bd9Sstevel@tonic-gate 	 * the filehandle translation should not be provided to the
12597c478bd9Sstevel@tonic-gate 	 * client.
12607c478bd9Sstevel@tonic-gate 	 */
12617c478bd9Sstevel@tonic-gate 	if (rejecting || version < mount_vers_min) {
12627c478bd9Sstevel@tonic-gate 		if (verbose)
12637c478bd9Sstevel@tonic-gate 			syslog(LOG_NOTICE, "Rejected mount: %s for %s",
12647c478bd9Sstevel@tonic-gate 			    host, path);
12657c478bd9Sstevel@tonic-gate 		error = EACCES;
12667c478bd9Sstevel@tonic-gate 		goto reply;
12677c478bd9Sstevel@tonic-gate 	}
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 	/*
127003986916Sjarrett 	 * Trusted Extension doesn't support nfsv2. nfsv2 client
127103986916Sjarrett 	 * uses MOUNT protocol v1 and v2. To prevent circumventing
127203986916Sjarrett 	 * TX label policy via using nfsv2 client, reject a mount
127303986916Sjarrett 	 * request with version less than 3 and log an error.
127445916cd2Sjpk 	 */
127545916cd2Sjpk 	if (is_system_labeled()) {
127603986916Sjarrett 		if (version < 3) {
127703986916Sjarrett 			if (verbose)
127845916cd2Sjpk 				syslog(LOG_ERR,
127903986916Sjarrett 				    "Rejected mount: TX doesn't support NFSv2");
128045916cd2Sjpk 			error = EACCES;
128145916cd2Sjpk 			goto reply;
128245916cd2Sjpk 		}
128303986916Sjarrett 	}
128445916cd2Sjpk 
128545916cd2Sjpk 	/*
12867c478bd9Sstevel@tonic-gate 	 * Get the real path (no symbolic links in it)
12877c478bd9Sstevel@tonic-gate 	 */
12887c478bd9Sstevel@tonic-gate 	if (realpath(path, rpath) == NULL) {
12897c478bd9Sstevel@tonic-gate 		error = errno;
12907c478bd9Sstevel@tonic-gate 		if (verbose)
12917c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR,
12927c478bd9Sstevel@tonic-gate 			    "mount request: realpath: %s: %m", path);
12937c478bd9Sstevel@tonic-gate 		if (error == ENOENT)
1294*a9685eaaSMarcel Telka 			error = mount_enoent_error(&cln, path, rpath,
1295*a9685eaaSMarcel Telka 			    flavor_list);
12967c478bd9Sstevel@tonic-gate 		goto reply;
12977c478bd9Sstevel@tonic-gate 	}
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 	if ((sh = findentry(rpath)) == NULL &&
13007c478bd9Sstevel@tonic-gate 	    (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) {
13017c478bd9Sstevel@tonic-gate 		error = EACCES;
13027c478bd9Sstevel@tonic-gate 		goto reply;
13037c478bd9Sstevel@tonic-gate 	}
13047c478bd9Sstevel@tonic-gate 
13057c478bd9Sstevel@tonic-gate 	/*
13067c478bd9Sstevel@tonic-gate 	 * Check if this is a "nosub" only export, in which case, mounting
13077c478bd9Sstevel@tonic-gate 	 * subdirectories isn't allowed. Bug 1184573.
13087c478bd9Sstevel@tonic-gate 	 */
13097c478bd9Sstevel@tonic-gate 	if (checkrootmount(sh, rpath) == 0) {
13107c478bd9Sstevel@tonic-gate 		error = EACCES;
13117c478bd9Sstevel@tonic-gate 		goto reply;
13127c478bd9Sstevel@tonic-gate 	}
13137c478bd9Sstevel@tonic-gate 
13147c478bd9Sstevel@tonic-gate 	if (newopts(sh->sh_opts))
1315*a9685eaaSMarcel Telka 		flavor_count = getclientsflavors_new(sh, &cln, flavor_list);
13167c478bd9Sstevel@tonic-gate 	else
1317*a9685eaaSMarcel Telka 		flavor_count = getclientsflavors_old(sh, &cln, flavor_list);
13184a508a79SThomas Haynes 
13197c478bd9Sstevel@tonic-gate 	if (flavor_count == 0) {
13207c478bd9Sstevel@tonic-gate 		error = EACCES;
13217c478bd9Sstevel@tonic-gate 		goto reply;
13227c478bd9Sstevel@tonic-gate 	}
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 	/*
132503986916Sjarrett 	 * Check MAC policy here. The server side policy should be
132603986916Sjarrett 	 * consistent with client side mount policy, i.e.
132703986916Sjarrett 	 * - we disallow an admin_low unlabeled client to mount
132803986916Sjarrett 	 * - we disallow mount from a lower labeled client.
132903986916Sjarrett 	 */
133003986916Sjarrett 	if (is_system_labeled()) {
133103986916Sjarrett 		m_label_t *clabel = NULL;
133203986916Sjarrett 		m_label_t *slabel = NULL;
133303986916Sjarrett 		m_label_t admin_low;
133403986916Sjarrett 
133503986916Sjarrett 		if (svc_getcallerucred(rqstp->rq_xprt, &uc) != 0) {
133603986916Sjarrett 			syslog(LOG_ERR,
133703986916Sjarrett 			    "mount request: Failed to get caller's ucred : %m");
133803986916Sjarrett 			error = EACCES;
133903986916Sjarrett 			goto reply;
134003986916Sjarrett 		}
134103986916Sjarrett 		if ((clabel = ucred_getlabel(uc)) == NULL) {
134203986916Sjarrett 			syslog(LOG_ERR,
134303986916Sjarrett 			    "mount request: can't get client label from ucred");
134403986916Sjarrett 			error = EACCES;
134503986916Sjarrett 			goto reply;
134603986916Sjarrett 		}
134703986916Sjarrett 
134803986916Sjarrett 		bsllow(&admin_low);
134903986916Sjarrett 		if (blequal(&admin_low, clabel)) {
135003986916Sjarrett 			struct sockaddr *ca;
135103986916Sjarrett 			tsol_tpent_t	*tp;
135203986916Sjarrett 
135303986916Sjarrett 			ca = (struct sockaddr *)(void *)svc_getrpccaller(
135403986916Sjarrett 			    rqstp->rq_xprt)->buf;
135503986916Sjarrett 			if (ca == NULL) {
135603986916Sjarrett 				error = EACCES;
135703986916Sjarrett 				goto reply;
135803986916Sjarrett 			}
135903986916Sjarrett 			/*
136003986916Sjarrett 			 * get trusted network template associated
136103986916Sjarrett 			 * with the client.
136203986916Sjarrett 			 */
136303986916Sjarrett 			tp = get_client_template(ca);
136403986916Sjarrett 			if (tp == NULL || tp->host_type != SUN_CIPSO) {
136503986916Sjarrett 				if (tp != NULL)
136603986916Sjarrett 					tsol_freetpent(tp);
136703986916Sjarrett 				error = EACCES;
136803986916Sjarrett 				goto reply;
136903986916Sjarrett 			}
137003986916Sjarrett 			tsol_freetpent(tp);
137103986916Sjarrett 		} else {
137203986916Sjarrett 			if ((slabel = m_label_alloc(MAC_LABEL)) == NULL) {
137303986916Sjarrett 				error = EACCES;
137403986916Sjarrett 				goto reply;
137503986916Sjarrett 			}
137603986916Sjarrett 
137703986916Sjarrett 			if (getlabel(rpath, slabel) != 0) {
137803986916Sjarrett 				m_label_free(slabel);
137903986916Sjarrett 				error = EACCES;
138003986916Sjarrett 				goto reply;
138103986916Sjarrett 			}
138203986916Sjarrett 
138303986916Sjarrett 			if (!bldominates(clabel, slabel)) {
138403986916Sjarrett 				m_label_free(slabel);
138503986916Sjarrett 				error = EACCES;
138603986916Sjarrett 				goto reply;
138703986916Sjarrett 			}
138803986916Sjarrett 			m_label_free(slabel);
138903986916Sjarrett 		}
139003986916Sjarrett 	}
139103986916Sjarrett 
139203986916Sjarrett 	/*
13937c478bd9Sstevel@tonic-gate 	 * Now get the filehandle.
13947c478bd9Sstevel@tonic-gate 	 *
139527242a7cSthurlow 	 * NFS V2 clients get a 32 byte filehandle.
139627242a7cSthurlow 	 * NFS V3 clients get a 32 or 64 byte filehandle, depending on
139727242a7cSthurlow 	 * the embedded FIDs.
13987c478bd9Sstevel@tonic-gate 	 */
139927242a7cSthurlow 	vers = (version == MOUNTVERS3) ? NFS_V3 : NFS_VERSION;
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 	/* LINTED pointer alignment */
140227242a7cSthurlow 	while (nfs_getfh(rpath, vers, &len, fh) < 0) {
14037c478bd9Sstevel@tonic-gate 		if (errno == EINVAL &&
14047c478bd9Sstevel@tonic-gate 		    (sh = find_lofsentry(rpath, &lofs_tried)) != NULL) {
14057c478bd9Sstevel@tonic-gate 			errno = 0;
14067c478bd9Sstevel@tonic-gate 			continue;
14077c478bd9Sstevel@tonic-gate 		}
14087c478bd9Sstevel@tonic-gate 		error = errno == EINVAL ? EACCES : errno;
14097c478bd9Sstevel@tonic-gate 		syslog(LOG_DEBUG, "mount request: getfh failed on %s: %m",
14107c478bd9Sstevel@tonic-gate 		    path);
14117c478bd9Sstevel@tonic-gate 		break;
14127c478bd9Sstevel@tonic-gate 	}
14137c478bd9Sstevel@tonic-gate 
141427242a7cSthurlow 	if (version == MOUNTVERS3) {
141527242a7cSthurlow 		mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len = len;
141627242a7cSthurlow 		mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val = fh;
141727242a7cSthurlow 	} else {
141827242a7cSthurlow 		bcopy(fh, &fhs.fhstatus_u.fhs_fhandle, NFS_FHSIZE);
141927242a7cSthurlow 	}
142027242a7cSthurlow 
14217c478bd9Sstevel@tonic-gate reply:
142203986916Sjarrett 	if (uc != NULL)
142303986916Sjarrett 		ucred_free(uc);
14244a508a79SThomas Haynes 
14257c478bd9Sstevel@tonic-gate 	switch (version) {
14267c478bd9Sstevel@tonic-gate 	case MOUNTVERS:
14277c478bd9Sstevel@tonic-gate 	case MOUNTVERS_POSIX:
14287c478bd9Sstevel@tonic-gate 		if (error == EINVAL)
14297c478bd9Sstevel@tonic-gate 			fhs.fhs_status = NFSERR_ACCES;
14307c478bd9Sstevel@tonic-gate 		else if (error == EREMOTE)
14317c478bd9Sstevel@tonic-gate 			fhs.fhs_status = NFSERR_REMOTE;
14327c478bd9Sstevel@tonic-gate 		else
14337c478bd9Sstevel@tonic-gate 			fhs.fhs_status = error;
14344a508a79SThomas Haynes 
14357c478bd9Sstevel@tonic-gate 		if (!svc_sendreply(transp, xdr_fhstatus, (char *)&fhs))
1436*a9685eaaSMarcel Telka 			log_cant_reply_cln(&cln);
14374a508a79SThomas Haynes 
14384a508a79SThomas Haynes 		audit_status = fhs.fhs_status;
14397c478bd9Sstevel@tonic-gate 		break;
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 	case MOUNTVERS3:
14427c478bd9Sstevel@tonic-gate 		if (!error) {
14437c478bd9Sstevel@tonic-gate 		mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val =
14447c478bd9Sstevel@tonic-gate 		    flavor_list;
14457c478bd9Sstevel@tonic-gate 		mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len =
14467c478bd9Sstevel@tonic-gate 		    flavor_count;
14477c478bd9Sstevel@tonic-gate 
14487c478bd9Sstevel@tonic-gate 		} else if (error == ENAMETOOLONG)
14497c478bd9Sstevel@tonic-gate 			error = MNT3ERR_NAMETOOLONG;
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 		mountres3.fhs_status = error;
14527c478bd9Sstevel@tonic-gate 		if (!svc_sendreply(transp, xdr_mountres3, (char *)&mountres3))
1453*a9685eaaSMarcel Telka 			log_cant_reply_cln(&cln);
14547c478bd9Sstevel@tonic-gate 
14554a508a79SThomas Haynes 		audit_status = mountres3.fhs_status;
14567c478bd9Sstevel@tonic-gate 		break;
14577c478bd9Sstevel@tonic-gate 	}
14587c478bd9Sstevel@tonic-gate 
1459*a9685eaaSMarcel Telka 	if (cln_havehost(&cln))
1460*a9685eaaSMarcel Telka 		host = cln_gethost(&cln);
1461*a9685eaaSMarcel Telka 
14627c478bd9Sstevel@tonic-gate 	if (verbose)
14637c478bd9Sstevel@tonic-gate 		syslog(LOG_NOTICE, "MOUNT: %s %s %s",
14647c478bd9Sstevel@tonic-gate 		    (host == NULL) ? "unknown host" : host,
14657c478bd9Sstevel@tonic-gate 		    error ? "denied" : "mounted", path);
14667c478bd9Sstevel@tonic-gate 
14674a508a79SThomas Haynes 	/*
14684a508a79SThomas Haynes 	 * If we can not create a queue entry, go ahead and do it
14694a508a79SThomas Haynes 	 * in the context of this thread.
14704a508a79SThomas Haynes 	 */
14714a508a79SThomas Haynes 	enqueued = enqueue_logging_data(host, transp, path, rpath,
14724a508a79SThomas Haynes 	    audit_status, error);
14734a508a79SThomas Haynes 	if (enqueued == FALSE) {
14744a508a79SThomas Haynes 		if (host == NULL) {
14754a508a79SThomas Haynes 			DTRACE_PROBE(mountd, name_by_in_thread);
1476*a9685eaaSMarcel Telka 			host = cln_gethost(&cln);
14774a508a79SThomas Haynes 		}
14784a508a79SThomas Haynes 
14794a508a79SThomas Haynes 		DTRACE_PROBE(mountd, logged_in_thread);
14804a508a79SThomas Haynes 		audit_mountd_mount(host, path, audit_status); /* BSM */
14814a508a79SThomas Haynes 		if (!error)
14824a508a79SThomas Haynes 			mntlist_new(host, rpath); /* add entry to mount list */
14834a508a79SThomas Haynes 	}
14844a508a79SThomas Haynes 
14857c478bd9Sstevel@tonic-gate 	if (path != NULL)
14867c478bd9Sstevel@tonic-gate 		svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate 	if (sh)
14897c478bd9Sstevel@tonic-gate 		sharefree(sh);
1490*a9685eaaSMarcel Telka 
1491*a9685eaaSMarcel Telka 	cln_fini(&cln);
14924a508a79SThomas Haynes 
14934a508a79SThomas Haynes 	return (error);
14947c478bd9Sstevel@tonic-gate }
14957c478bd9Sstevel@tonic-gate 
14966b086bafSSam Falkner /*
14976b086bafSSam Falkner  * Determine whether two paths are within the same file system.
14986b086bafSSam Falkner  * Returns nonzero (true) if paths are the same, zero (false) if
14996b086bafSSam Falkner  * they are different.  If an error occurs, return false.
15006b086bafSSam Falkner  *
15016b086bafSSam Falkner  * Use the actual FSID if it's available (via getattrat()); otherwise,
15026b086bafSSam Falkner  * fall back on st_dev.
15036b086bafSSam Falkner  *
15046b086bafSSam Falkner  * With ZFS snapshots, st_dev differs from the regular file system
15056b086bafSSam Falkner  * versus the snapshot.  But the fsid is the same throughout.  Thus
15066b086bafSSam Falkner  * the fsid is a better test.
15076b086bafSSam Falkner  */
15086b086bafSSam Falkner static int
15096b086bafSSam Falkner same_file_system(const char *path1, const char *path2)
15106b086bafSSam Falkner {
15116b086bafSSam Falkner 	uint64_t fsid1, fsid2;
15126b086bafSSam Falkner 	struct stat64 st1, st2;
15136b086bafSSam Falkner 	nvlist_t *nvl1 = NULL;
15146b086bafSSam Falkner 	nvlist_t *nvl2 = NULL;
15156b086bafSSam Falkner 
15166b086bafSSam Falkner 	if ((getattrat(AT_FDCWD, XATTR_VIEW_READONLY, path1, &nvl1) == 0) &&
15176b086bafSSam Falkner 	    (getattrat(AT_FDCWD, XATTR_VIEW_READONLY, path2, &nvl2) == 0) &&
15186b086bafSSam Falkner 	    (nvlist_lookup_uint64(nvl1, A_FSID, &fsid1) == 0) &&
15196b086bafSSam Falkner 	    (nvlist_lookup_uint64(nvl2, A_FSID, &fsid2) == 0)) {
15206b086bafSSam Falkner 		nvlist_free(nvl1);
15216b086bafSSam Falkner 		nvlist_free(nvl2);
15226b086bafSSam Falkner 		/*
15236b086bafSSam Falkner 		 * We have found fsid's for both paths.
15246b086bafSSam Falkner 		 */
15256b086bafSSam Falkner 
15266b086bafSSam Falkner 		if (fsid1 == fsid2)
15276b086bafSSam Falkner 			return (B_TRUE);
15286b086bafSSam Falkner 
15296b086bafSSam Falkner 		return (B_FALSE);
15306b086bafSSam Falkner 	}
15316b086bafSSam Falkner 
15326b086bafSSam Falkner 	nvlist_free(nvl1);
15336b086bafSSam Falkner 	nvlist_free(nvl2);
15346b086bafSSam Falkner 
15356b086bafSSam Falkner 	/*
15366b086bafSSam Falkner 	 * We were unable to find fsid's for at least one of the paths.
15376b086bafSSam Falkner 	 * fall back on st_dev.
15386b086bafSSam Falkner 	 */
15396b086bafSSam Falkner 
15406b086bafSSam Falkner 	if (stat64(path1, &st1) < 0) {
15416b086bafSSam Falkner 		syslog(LOG_NOTICE, "%s: %m", path1);
15426b086bafSSam Falkner 		return (B_FALSE);
15436b086bafSSam Falkner 	}
15446b086bafSSam Falkner 	if (stat64(path2, &st2) < 0) {
15456b086bafSSam Falkner 		syslog(LOG_NOTICE, "%s: %m", path2);
15466b086bafSSam Falkner 		return (B_FALSE);
15476b086bafSSam Falkner 	}
15486b086bafSSam Falkner 
15496b086bafSSam Falkner 	if (st1.st_dev == st2.st_dev)
15506b086bafSSam Falkner 		return (B_TRUE);
15516b086bafSSam Falkner 
15526b086bafSSam Falkner 	return (B_FALSE);
15536b086bafSSam Falkner }
15546b086bafSSam Falkner 
15554a508a79SThomas Haynes share_t *
15567c478bd9Sstevel@tonic-gate findentry(char *path)
15577c478bd9Sstevel@tonic-gate {
15584a508a79SThomas Haynes 	share_t *sh = NULL;
15597c478bd9Sstevel@tonic-gate 	struct sh_list *shp;
156054d34259SMarcel Telka 	char *p1, *p2;
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate 	check_sharetab();
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate 	(void) rw_rdlock(&sharetab_lock);
15657c478bd9Sstevel@tonic-gate 
15667c478bd9Sstevel@tonic-gate 	for (shp = share_list; shp; shp = shp->shl_next) {
15677c478bd9Sstevel@tonic-gate 		sh = shp->shl_sh;
15687c478bd9Sstevel@tonic-gate 		for (p1 = sh->sh_path, p2 = path; *p1 == *p2; p1++, p2++)
15697c478bd9Sstevel@tonic-gate 			if (*p1 == '\0')
15707c478bd9Sstevel@tonic-gate 				goto done;	/* exact match */
15717c478bd9Sstevel@tonic-gate 
15727c478bd9Sstevel@tonic-gate 		/*
15737c478bd9Sstevel@tonic-gate 		 * Now compare the pathnames for three cases:
15747c478bd9Sstevel@tonic-gate 		 *
15757c478bd9Sstevel@tonic-gate 		 * Parent: /export/foo		(no trailing slash on parent)
15767c478bd9Sstevel@tonic-gate 		 * Child:  /export/foo/bar
15777c478bd9Sstevel@tonic-gate 		 *
15787c478bd9Sstevel@tonic-gate 		 * Parent: /export/foo/		(trailing slash on parent)
15797c478bd9Sstevel@tonic-gate 		 * Child:  /export/foo/bar
15807c478bd9Sstevel@tonic-gate 		 *
15817c478bd9Sstevel@tonic-gate 		 * Parent: /export/foo/		(no trailing slash on child)
15827c478bd9Sstevel@tonic-gate 		 * Child:  /export/foo
15837c478bd9Sstevel@tonic-gate 		 */
15847c478bd9Sstevel@tonic-gate 		if ((*p1 == '\0' && *p2 == '/') ||
15857c478bd9Sstevel@tonic-gate 		    (*p1 == '\0' && *(p1-1) == '/') ||
15867c478bd9Sstevel@tonic-gate 		    (*p2 == '\0' && *p1 == '/' && *(p1+1) == '\0')) {
15877c478bd9Sstevel@tonic-gate 			/*
15886b086bafSSam Falkner 			 * We have a subdirectory.  Test whether the
15896b086bafSSam Falkner 			 * subdirectory is in the same file system.
15907c478bd9Sstevel@tonic-gate 			 */
15916b086bafSSam Falkner 			if (same_file_system(path, sh->sh_path))
15927c478bd9Sstevel@tonic-gate 				goto done;
15937c478bd9Sstevel@tonic-gate 		}
15947c478bd9Sstevel@tonic-gate 	}
15957c478bd9Sstevel@tonic-gate done:
15967c478bd9Sstevel@tonic-gate 	sh = shp ? sharedup(sh) : NULL;
15977c478bd9Sstevel@tonic-gate 
15987c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&sharetab_lock);
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 	return (sh);
16017c478bd9Sstevel@tonic-gate }
16027c478bd9Sstevel@tonic-gate 
16037c478bd9Sstevel@tonic-gate 
16047c478bd9Sstevel@tonic-gate static int
16057c478bd9Sstevel@tonic-gate is_substring(char **mntp, char **path)
16067c478bd9Sstevel@tonic-gate {
16077c478bd9Sstevel@tonic-gate 	char *p1 = *mntp, *p2 = *path;
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 	if (*p1 == '\0' && *p2 == '\0') /* exact match */
16107c478bd9Sstevel@tonic-gate 		return (1);
16117c478bd9Sstevel@tonic-gate 	else if (*p1 == '\0' && *p2 == '/')
16127c478bd9Sstevel@tonic-gate 		return (1);
16137c478bd9Sstevel@tonic-gate 	else if (*p1 == '\0' && *(p1-1) == '/') {
16147c478bd9Sstevel@tonic-gate 		*path = --p2; /* we need the slash in p2 */
16157c478bd9Sstevel@tonic-gate 		return (1);
16167c478bd9Sstevel@tonic-gate 	} else if (*p2 == '\0') {
16177c478bd9Sstevel@tonic-gate 		while (*p1 == '/')
16187c478bd9Sstevel@tonic-gate 			p1++;
16197c478bd9Sstevel@tonic-gate 		if (*p1 == '\0') /* exact match */
16207c478bd9Sstevel@tonic-gate 			return (1);
16217c478bd9Sstevel@tonic-gate 	}
16227c478bd9Sstevel@tonic-gate 	return (0);
16237c478bd9Sstevel@tonic-gate }
16247c478bd9Sstevel@tonic-gate 
16257c478bd9Sstevel@tonic-gate /*
16267c478bd9Sstevel@tonic-gate  * find_lofsentry() searches for the real path which this requested LOFS path
16277c478bd9Sstevel@tonic-gate  * (rpath) shadows. If found, it will return the sharetab entry of
16287c478bd9Sstevel@tonic-gate  * the real path that corresponds to the LOFS path.
16297c478bd9Sstevel@tonic-gate  * We first search mnttab to see if the requested path is an automounted
16307c478bd9Sstevel@tonic-gate  * path. If it is an automounted path, it will trigger the mount by stat()ing
16317c478bd9Sstevel@tonic-gate  * the requested path. Note that it is important to check that this path is
16327c478bd9Sstevel@tonic-gate  * actually an automounted path, otherwise we would stat() a path which may
16337c478bd9Sstevel@tonic-gate  * turn out to be NFS and block indefinitely on a dead server. The automounter
16347c478bd9Sstevel@tonic-gate  * times-out if the server is dead, so there's no risk of hanging this
16357c478bd9Sstevel@tonic-gate  * thread waiting for stat().
16367c478bd9Sstevel@tonic-gate  * After the mount has been triggered (if necessary), we look for a
16377c478bd9Sstevel@tonic-gate  * mountpoint of type LOFS (by searching /etc/mnttab again) which
16387c478bd9Sstevel@tonic-gate  * is a substring of the rpath. If found, we construct a new path by
16397c478bd9Sstevel@tonic-gate  * concatenating the mnt_special and the remaining of rpath, call findentry()
16407c478bd9Sstevel@tonic-gate  * to make sure the 'real path' is shared.
16417c478bd9Sstevel@tonic-gate  */
16424a508a79SThomas Haynes static share_t *
16437c478bd9Sstevel@tonic-gate find_lofsentry(char *rpath, int *done_flag)
16447c478bd9Sstevel@tonic-gate {
16457c478bd9Sstevel@tonic-gate 	struct stat r_stbuf;
16467c478bd9Sstevel@tonic-gate 	mntlist_t *ml, *mntl, *mntpnt = NULL;
16474a508a79SThomas Haynes 	share_t *retcode = NULL;
16487c478bd9Sstevel@tonic-gate 	char tmp_path[MAXPATHLEN];
16497c478bd9Sstevel@tonic-gate 	int mntpnt_len = 0, tmp;
16507c478bd9Sstevel@tonic-gate 	char *p1, *p2;
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate 	if ((*done_flag)++)
16537c478bd9Sstevel@tonic-gate 		return (retcode);
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 	/*
16567c478bd9Sstevel@tonic-gate 	 * While fsgetmntlist() uses lockf() to
16577c478bd9Sstevel@tonic-gate 	 * lock the mnttab before reading it in,
16587c478bd9Sstevel@tonic-gate 	 * the lock ignores threads in the same process.
16597c478bd9Sstevel@tonic-gate 	 * Read in the mnttab with the protection of a mutex.
16607c478bd9Sstevel@tonic-gate 	 */
16617c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&mnttab_lock);
16627c478bd9Sstevel@tonic-gate 	mntl = fsgetmntlist();
16637c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&mnttab_lock);
16647c478bd9Sstevel@tonic-gate 
16657c478bd9Sstevel@tonic-gate 	/*
16667c478bd9Sstevel@tonic-gate 	 * Obtain the mountpoint for the requested path.
16677c478bd9Sstevel@tonic-gate 	 */
16687c478bd9Sstevel@tonic-gate 	for (ml = mntl; ml; ml = ml->mntl_next) {
16697c478bd9Sstevel@tonic-gate 		for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath;
1670250a0733Sth199096 		    *p1 == *p2 && *p1; p1++, p2++)
1671250a0733Sth199096 			;
16727c478bd9Sstevel@tonic-gate 		if (is_substring(&p1, &p2) &&
16737c478bd9Sstevel@tonic-gate 		    (tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len) {
16747c478bd9Sstevel@tonic-gate 			mntpnt = ml;
16757c478bd9Sstevel@tonic-gate 			mntpnt_len = tmp;
16767c478bd9Sstevel@tonic-gate 		}
16777c478bd9Sstevel@tonic-gate 	}
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 	/*
16807c478bd9Sstevel@tonic-gate 	 * If the path needs to be autoFS mounted, trigger the mount by
16817c478bd9Sstevel@tonic-gate 	 * stat()ing it. This is determined by checking whether the
16827c478bd9Sstevel@tonic-gate 	 * mountpoint we just found is of type autofs.
16837c478bd9Sstevel@tonic-gate 	 */
16847c478bd9Sstevel@tonic-gate 	if (mntpnt != NULL &&
16857c478bd9Sstevel@tonic-gate 	    strcmp(mntpnt->mntl_mnt->mnt_fstype, "autofs") == 0) {
16867c478bd9Sstevel@tonic-gate 		/*
16877c478bd9Sstevel@tonic-gate 		 * The requested path is a substring of an autoFS filesystem.
16887c478bd9Sstevel@tonic-gate 		 * Trigger the mount.
16897c478bd9Sstevel@tonic-gate 		 */
16907c478bd9Sstevel@tonic-gate 		if (stat(rpath, &r_stbuf) < 0) {
16917c478bd9Sstevel@tonic-gate 			if (verbose)
16927c478bd9Sstevel@tonic-gate 				syslog(LOG_NOTICE, "%s: %m", rpath);
16937c478bd9Sstevel@tonic-gate 			goto done;
16947c478bd9Sstevel@tonic-gate 		}
16957c478bd9Sstevel@tonic-gate 		if ((r_stbuf.st_mode & S_IFMT) == S_IFDIR) {
16967c478bd9Sstevel@tonic-gate 			/*
16977c478bd9Sstevel@tonic-gate 			 * The requested path is a directory, stat(2) it
16987c478bd9Sstevel@tonic-gate 			 * again with a trailing '.' to force the autoFS
16997c478bd9Sstevel@tonic-gate 			 * module to trigger the mount of indirect
17007c478bd9Sstevel@tonic-gate 			 * automount entries, such as /net/jurassic/.
17017c478bd9Sstevel@tonic-gate 			 */
17027c478bd9Sstevel@tonic-gate 			if (strlen(rpath) + 2 > MAXPATHLEN) {
17037c478bd9Sstevel@tonic-gate 				if (verbose) {
17047c478bd9Sstevel@tonic-gate 					syslog(LOG_NOTICE,
17057c478bd9Sstevel@tonic-gate 					    "%s/.: exceeds MAXPATHLEN %d",
17067c478bd9Sstevel@tonic-gate 					    rpath, MAXPATHLEN);
17077c478bd9Sstevel@tonic-gate 				}
17087c478bd9Sstevel@tonic-gate 				goto done;
17097c478bd9Sstevel@tonic-gate 			}
17107c478bd9Sstevel@tonic-gate 			(void) strcpy(tmp_path, rpath);
17117c478bd9Sstevel@tonic-gate 			(void) strcat(tmp_path, "/.");
17127c478bd9Sstevel@tonic-gate 
17137c478bd9Sstevel@tonic-gate 			if (stat(tmp_path, &r_stbuf) < 0) {
17147c478bd9Sstevel@tonic-gate 				if (verbose)
17157c478bd9Sstevel@tonic-gate 					syslog(LOG_NOTICE, "%s: %m", tmp_path);
17167c478bd9Sstevel@tonic-gate 				goto done;
17177c478bd9Sstevel@tonic-gate 			}
17187c478bd9Sstevel@tonic-gate 		}
17194a508a79SThomas Haynes 
17207c478bd9Sstevel@tonic-gate 		/*
17217c478bd9Sstevel@tonic-gate 		 * The mount has been triggered, re-read mnttab to pick up
17227c478bd9Sstevel@tonic-gate 		 * the changes made by autoFS.
17237c478bd9Sstevel@tonic-gate 		 */
17247c478bd9Sstevel@tonic-gate 		fsfreemntlist(mntl);
17257c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&mnttab_lock);
17267c478bd9Sstevel@tonic-gate 		mntl = fsgetmntlist();
17277c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&mnttab_lock);
17287c478bd9Sstevel@tonic-gate 	}
17297c478bd9Sstevel@tonic-gate 
17307c478bd9Sstevel@tonic-gate 	/*
17317c478bd9Sstevel@tonic-gate 	 * The autoFS mountpoint has been triggered if necessary,
17327c478bd9Sstevel@tonic-gate 	 * now search mnttab again to determine if the requested path
17337c478bd9Sstevel@tonic-gate 	 * is an LOFS mount of a shared path.
17347c478bd9Sstevel@tonic-gate 	 */
17357c478bd9Sstevel@tonic-gate 	mntpnt_len = 0;
17367c478bd9Sstevel@tonic-gate 	for (ml = mntl; ml; ml = ml->mntl_next) {
17377c478bd9Sstevel@tonic-gate 		if (strcmp(ml->mntl_mnt->mnt_fstype, "lofs"))
17387c478bd9Sstevel@tonic-gate 			continue;
17397c478bd9Sstevel@tonic-gate 
17407c478bd9Sstevel@tonic-gate 		for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath;
1741250a0733Sth199096 		    *p1 == *p2 && *p1; p1++, p2++)
1742250a0733Sth199096 			;
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 		if (is_substring(&p1, &p2) &&
17457c478bd9Sstevel@tonic-gate 		    ((tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len)) {
17467c478bd9Sstevel@tonic-gate 			mntpnt_len = tmp;
17477c478bd9Sstevel@tonic-gate 
17487c478bd9Sstevel@tonic-gate 			if ((strlen(ml->mntl_mnt->mnt_special) + strlen(p2)) >
17497c478bd9Sstevel@tonic-gate 			    MAXPATHLEN) {
17507c478bd9Sstevel@tonic-gate 				if (verbose) {
17517c478bd9Sstevel@tonic-gate 					syslog(LOG_NOTICE, "%s%s: exceeds %d",
17527c478bd9Sstevel@tonic-gate 					    ml->mntl_mnt->mnt_special, p2,
17537c478bd9Sstevel@tonic-gate 					    MAXPATHLEN);
17547c478bd9Sstevel@tonic-gate 				}
17557c478bd9Sstevel@tonic-gate 				if (retcode)
17567c478bd9Sstevel@tonic-gate 					sharefree(retcode);
17577c478bd9Sstevel@tonic-gate 				retcode = NULL;
17587c478bd9Sstevel@tonic-gate 				goto done;
17597c478bd9Sstevel@tonic-gate 			}
17607c478bd9Sstevel@tonic-gate 
17617c478bd9Sstevel@tonic-gate 			(void) strcpy(tmp_path, ml->mntl_mnt->mnt_special);
17627c478bd9Sstevel@tonic-gate 			(void) strcat(tmp_path, p2);
17637c478bd9Sstevel@tonic-gate 			if (retcode)
17647c478bd9Sstevel@tonic-gate 				sharefree(retcode);
17657c478bd9Sstevel@tonic-gate 			retcode = findentry(tmp_path);
17667c478bd9Sstevel@tonic-gate 		}
17677c478bd9Sstevel@tonic-gate 	}
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 	if (retcode) {
17707c478bd9Sstevel@tonic-gate 		assert(strlen(tmp_path) > 0);
17717c478bd9Sstevel@tonic-gate 		(void) strcpy(rpath, tmp_path);
17727c478bd9Sstevel@tonic-gate 	}
17737c478bd9Sstevel@tonic-gate 
17747c478bd9Sstevel@tonic-gate done:
17757c478bd9Sstevel@tonic-gate 	fsfreemntlist(mntl);
17767c478bd9Sstevel@tonic-gate 	return (retcode);
17777c478bd9Sstevel@tonic-gate }
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate /*
17807c478bd9Sstevel@tonic-gate  * Determine whether an access list grants rights to a particular host.
17817c478bd9Sstevel@tonic-gate  * We match on aliases of the hostname as well as on the canonical name.
17827c478bd9Sstevel@tonic-gate  * Names in the access list may be either hosts or netgroups;  they're
17837c478bd9Sstevel@tonic-gate  * not distinguished syntactically.  We check for hosts first because
17849b241b4eSYuri Pankov  * it's cheaper, then try netgroups.
1785d34083bdSJan Kryl  *
1786*a9685eaaSMarcel Telka  * Return values:
1787*a9685eaaSMarcel Telka  *  1 - access is granted
1788*a9685eaaSMarcel Telka  *  0 - access is denied
1789*a9685eaaSMarcel Telka  * -1 - an error occured
17907c478bd9Sstevel@tonic-gate  */
179111606941Sjwahlig int
1792*a9685eaaSMarcel Telka in_access_list(struct cln *cln,
17937c478bd9Sstevel@tonic-gate     char *access_list)	/* N.B. we clobber this "input" parameter */
17947c478bd9Sstevel@tonic-gate {
17959b241b4eSYuri Pankov 	char addr[INET_ADDRSTRLEN];
17969b241b4eSYuri Pankov 	char buff[256];
17979b241b4eSYuri Pankov 	int nentries = 0;
17989b241b4eSYuri Pankov 	char *cstr = access_list;
17999b241b4eSYuri Pankov 	char *gr = access_list;
18007c478bd9Sstevel@tonic-gate 	int i;
18017c478bd9Sstevel@tonic-gate 	int response;
1802*a9685eaaSMarcel Telka 	struct netbuf *pnb;
1803*a9685eaaSMarcel Telka 	struct nd_hostservlist *clnames = NULL;
18044a508a79SThomas Haynes 
18059b241b4eSYuri Pankov 	/* If no access list - then it's unrestricted */
18067c478bd9Sstevel@tonic-gate 	if (access_list == NULL || *access_list == '\0')
18077c478bd9Sstevel@tonic-gate 		return (1);
18087c478bd9Sstevel@tonic-gate 
1809*a9685eaaSMarcel Telka 	if ((pnb = cln_getnbuf(cln)) == NULL)
1810*a9685eaaSMarcel Telka 		return (-1);
18119b241b4eSYuri Pankov 
18129b241b4eSYuri Pankov 	for (;;) {
1813*a9685eaaSMarcel Telka 		if ((cstr = strpbrk(cstr, "[:")) != NULL) {
1814*a9685eaaSMarcel Telka 			if (*cstr == ':') {
18159b241b4eSYuri Pankov 				*cstr = '\0';
1816*a9685eaaSMarcel Telka 			} else {
1817*a9685eaaSMarcel Telka 				assert(*cstr == '[');
1818*a9685eaaSMarcel Telka 				cstr = strchr(cstr + 1, ']');
1819*a9685eaaSMarcel Telka 				if (cstr == NULL)
1820*a9685eaaSMarcel Telka 					return (-1);
1821*a9685eaaSMarcel Telka 				cstr++;
1822*a9685eaaSMarcel Telka 				continue;
18239b241b4eSYuri Pankov 			}
18249b241b4eSYuri Pankov 		}
18257c478bd9Sstevel@tonic-gate 
18267c478bd9Sstevel@tonic-gate 		/*
18279b241b4eSYuri Pankov 		 * If the list name has a '-' prepended then a match of
18289b241b4eSYuri Pankov 		 * the following name implies failure instead of success.
18297c478bd9Sstevel@tonic-gate 		 */
18307c478bd9Sstevel@tonic-gate 		if (*gr == '-') {
18317c478bd9Sstevel@tonic-gate 			response = 0;
18327c478bd9Sstevel@tonic-gate 			gr++;
18339b241b4eSYuri Pankov 		} else {
18347c478bd9Sstevel@tonic-gate 			response = 1;
1835d34083bdSJan Kryl 		}
1836d34083bdSJan Kryl 
18379b241b4eSYuri Pankov 		/*
18389b241b4eSYuri Pankov 		 * First check if we have '@' entry, as it doesn't
18399b241b4eSYuri Pankov 		 * require client hostname.
18409b241b4eSYuri Pankov 		 */
18419b241b4eSYuri Pankov 		if (*gr == '@') {
18429b241b4eSYuri Pankov 			gr++;
18439b241b4eSYuri Pankov 
18449b241b4eSYuri Pankov 			/* Netname support */
18459b241b4eSYuri Pankov 			if (!isdigit(*gr) && *gr != '[') {
1846*a9685eaaSMarcel Telka 				struct netent n, *np;
1847*a9685eaaSMarcel Telka 
18489b241b4eSYuri Pankov 				if ((np = getnetbyname_r(gr, &n, buff,
18499b241b4eSYuri Pankov 				    sizeof (buff))) != NULL &&
18509b241b4eSYuri Pankov 				    np->n_net != 0) {
18519b241b4eSYuri Pankov 					while ((np->n_net & 0xFF000000u) == 0)
18529b241b4eSYuri Pankov 						np->n_net <<= 8;
18539b241b4eSYuri Pankov 					np->n_net = htonl(np->n_net);
18549b241b4eSYuri Pankov 					if (inet_ntop(AF_INET, &np->n_net, addr,
18559b241b4eSYuri Pankov 					    INET_ADDRSTRLEN) == NULL)
18569b241b4eSYuri Pankov 						break;
1857*a9685eaaSMarcel Telka 					if (inet_matchaddr(pnb->buf, addr))
18584a508a79SThomas Haynes 						return (response);
18599b241b4eSYuri Pankov 				}
18609b241b4eSYuri Pankov 			} else {
1861*a9685eaaSMarcel Telka 				if (inet_matchaddr(pnb->buf, gr))
18629b241b4eSYuri Pankov 					return (response);
18639b241b4eSYuri Pankov 			}
18649b241b4eSYuri Pankov 
1865*a9685eaaSMarcel Telka 			goto next;
18664a508a79SThomas Haynes 		}
18674a508a79SThomas Haynes 
18684a508a79SThomas Haynes 		/*
18699b241b4eSYuri Pankov 		 * No other checks can be performed if client address
18709b241b4eSYuri Pankov 		 * can't be resolved.
18714a508a79SThomas Haynes 		 */
1872*a9685eaaSMarcel Telka 		if ((clnames = cln_getclientsnames(cln)) == NULL)
1873*a9685eaaSMarcel Telka 			goto next;
18744a508a79SThomas Haynes 
18759b241b4eSYuri Pankov 		/* Otherwise loop through all client hostname aliases */
18767c478bd9Sstevel@tonic-gate 		for (i = 0; i < clnames->h_cnt; i++) {
1877*a9685eaaSMarcel Telka 			char *host = clnames->h_hostservs[i].h_host;
18787c478bd9Sstevel@tonic-gate 
18797c478bd9Sstevel@tonic-gate 			/*
18807c478bd9Sstevel@tonic-gate 			 * If the list name begins with a dot then
18817c478bd9Sstevel@tonic-gate 			 * do a domain name suffix comparison.
18827c478bd9Sstevel@tonic-gate 			 * A single dot matches any name with no
18837c478bd9Sstevel@tonic-gate 			 * suffix.
18847c478bd9Sstevel@tonic-gate 			 */
18857c478bd9Sstevel@tonic-gate 			if (*gr == '.') {
18867c478bd9Sstevel@tonic-gate 				if (*(gr + 1) == '\0') {  /* single dot */
18877c478bd9Sstevel@tonic-gate 					if (strchr(host, '.') == NULL)
18887c478bd9Sstevel@tonic-gate 						return (response);
18897c478bd9Sstevel@tonic-gate 				} else {
1890*a9685eaaSMarcel Telka 					int off = strlen(host) - strlen(gr);
18917c478bd9Sstevel@tonic-gate 					if (off > 0 &&
18927c478bd9Sstevel@tonic-gate 					    strcasecmp(host + off, gr) == 0) {
18937c478bd9Sstevel@tonic-gate 						return (response);
18947c478bd9Sstevel@tonic-gate 					}
18957c478bd9Sstevel@tonic-gate 				}
18969b241b4eSYuri Pankov 			} else {
18979b241b4eSYuri Pankov 				/* Just do a hostname match */
18989b241b4eSYuri Pankov 				if (strcasecmp(gr, host) == 0)
18999b241b4eSYuri Pankov 					return (response);
19007c478bd9Sstevel@tonic-gate 			}
19017c478bd9Sstevel@tonic-gate 		}
19027c478bd9Sstevel@tonic-gate 
19037c478bd9Sstevel@tonic-gate 		nentries++;
19047c478bd9Sstevel@tonic-gate 
1905*a9685eaaSMarcel Telka next:
19069b241b4eSYuri Pankov 		if (cstr == NULL)
19077c478bd9Sstevel@tonic-gate 			break;
19089b241b4eSYuri Pankov 
19099b241b4eSYuri Pankov 		gr = ++cstr;
19107c478bd9Sstevel@tonic-gate 	}
19119b241b4eSYuri Pankov 
19129b241b4eSYuri Pankov 	if (clnames == NULL)
19137c478bd9Sstevel@tonic-gate 		return (0);
19147c478bd9Sstevel@tonic-gate 
19159b241b4eSYuri Pankov 	return (netgroup_check(clnames, access_list, nentries));
19167c478bd9Sstevel@tonic-gate }
19177c478bd9Sstevel@tonic-gate 
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate static char *optlist[] = {
19207c478bd9Sstevel@tonic-gate #define	OPT_RO		0
19217c478bd9Sstevel@tonic-gate 	SHOPT_RO,
19227c478bd9Sstevel@tonic-gate #define	OPT_RW		1
19237c478bd9Sstevel@tonic-gate 	SHOPT_RW,
19247c478bd9Sstevel@tonic-gate #define	OPT_ROOT	2
19257c478bd9Sstevel@tonic-gate 	SHOPT_ROOT,
19267c478bd9Sstevel@tonic-gate #define	OPT_SECURE	3
19277c478bd9Sstevel@tonic-gate 	SHOPT_SECURE,
19287c478bd9Sstevel@tonic-gate #define	OPT_ANON	4
19297c478bd9Sstevel@tonic-gate 	SHOPT_ANON,
19307c478bd9Sstevel@tonic-gate #define	OPT_WINDOW	5
19317c478bd9Sstevel@tonic-gate 	SHOPT_WINDOW,
19327c478bd9Sstevel@tonic-gate #define	OPT_NOSUID	6
19337c478bd9Sstevel@tonic-gate 	SHOPT_NOSUID,
19347c478bd9Sstevel@tonic-gate #define	OPT_ACLOK	7
19357c478bd9Sstevel@tonic-gate 	SHOPT_ACLOK,
19367c478bd9Sstevel@tonic-gate #define	OPT_SEC		8
19377c478bd9Sstevel@tonic-gate 	SHOPT_SEC,
1938b89a8333Snatalie li - Sun Microsystems - Irvine United States #define	OPT_NONE	9
1939b89a8333Snatalie li - Sun Microsystems - Irvine United States 	SHOPT_NONE,
19405cb0d679SMarcel Telka #define	OPT_UIDMAP	10
19415cb0d679SMarcel Telka 	SHOPT_UIDMAP,
19425cb0d679SMarcel Telka #define	OPT_GIDMAP	11
19435cb0d679SMarcel Telka 	SHOPT_GIDMAP,
19447c478bd9Sstevel@tonic-gate 	NULL
19457c478bd9Sstevel@tonic-gate };
19467c478bd9Sstevel@tonic-gate 
19477c478bd9Sstevel@tonic-gate static int
19487c478bd9Sstevel@tonic-gate map_flavor(char *str)
19497c478bd9Sstevel@tonic-gate {
19507c478bd9Sstevel@tonic-gate 	seconfig_t sec;
19517c478bd9Sstevel@tonic-gate 
19527c478bd9Sstevel@tonic-gate 	if (nfs_getseconfig_byname(str, &sec))
19537c478bd9Sstevel@tonic-gate 		return (-1);
19547c478bd9Sstevel@tonic-gate 
19557c478bd9Sstevel@tonic-gate 	return (sec.sc_nfsnum);
19567c478bd9Sstevel@tonic-gate }
19577c478bd9Sstevel@tonic-gate 
19587c478bd9Sstevel@tonic-gate /*
19597c478bd9Sstevel@tonic-gate  * If the option string contains a "sec="
19607c478bd9Sstevel@tonic-gate  * option, then use new option syntax.
19617c478bd9Sstevel@tonic-gate  */
19627c478bd9Sstevel@tonic-gate static int
19637c478bd9Sstevel@tonic-gate newopts(char *opts)
19647c478bd9Sstevel@tonic-gate {
19657c478bd9Sstevel@tonic-gate 	char *head, *p, *val;
19667c478bd9Sstevel@tonic-gate 
19677c478bd9Sstevel@tonic-gate 	if (!opts || *opts == '\0')
19687c478bd9Sstevel@tonic-gate 		return (0);
19697c478bd9Sstevel@tonic-gate 
19707c478bd9Sstevel@tonic-gate 	head = strdup(opts);
19717c478bd9Sstevel@tonic-gate 	if (head == NULL) {
19727c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "opts: no memory");
19737c478bd9Sstevel@tonic-gate 		return (0);
19747c478bd9Sstevel@tonic-gate 	}
19757c478bd9Sstevel@tonic-gate 
19767c478bd9Sstevel@tonic-gate 	p = head;
19777c478bd9Sstevel@tonic-gate 	while (*p) {
19787c478bd9Sstevel@tonic-gate 		if (getsubopt(&p, optlist, &val) == OPT_SEC) {
19797c478bd9Sstevel@tonic-gate 			free(head);
19807c478bd9Sstevel@tonic-gate 			return (1);
19817c478bd9Sstevel@tonic-gate 		}
19827c478bd9Sstevel@tonic-gate 	}
19837c478bd9Sstevel@tonic-gate 
19847c478bd9Sstevel@tonic-gate 	free(head);
19857c478bd9Sstevel@tonic-gate 	return (0);
19867c478bd9Sstevel@tonic-gate }
19877c478bd9Sstevel@tonic-gate 
19887c478bd9Sstevel@tonic-gate /*
19897c478bd9Sstevel@tonic-gate  * Given an export and the clients hostname(s)
19907c478bd9Sstevel@tonic-gate  * determine the security flavors that this
19917c478bd9Sstevel@tonic-gate  * client is permitted to use.
19927c478bd9Sstevel@tonic-gate  *
19937c478bd9Sstevel@tonic-gate  * This routine is called only for "old" syntax, i.e.
19947c478bd9Sstevel@tonic-gate  * only one security flavor is allowed.  So we need
19957c478bd9Sstevel@tonic-gate  * to determine two things: the particular flavor,
19967c478bd9Sstevel@tonic-gate  * and whether the client is allowed to use this
19977c478bd9Sstevel@tonic-gate  * flavor, i.e. is in the access list.
19987c478bd9Sstevel@tonic-gate  *
19997c478bd9Sstevel@tonic-gate  * Note that if there is no access list, then the
20007c478bd9Sstevel@tonic-gate  * default is that access is granted.
20017c478bd9Sstevel@tonic-gate  */
20027c478bd9Sstevel@tonic-gate static int
2003*a9685eaaSMarcel Telka getclientsflavors_old(share_t *sh, struct cln *cln, int *flavors)
20047c478bd9Sstevel@tonic-gate {
20057c478bd9Sstevel@tonic-gate 	char *opts, *p, *val;
2006b89a8333Snatalie li - Sun Microsystems - Irvine United States 	boolean_t ok = B_FALSE;
20077c478bd9Sstevel@tonic-gate 	int defaultaccess = 1;
2008b89a8333Snatalie li - Sun Microsystems - Irvine United States 	boolean_t reject = B_FALSE;
20097c478bd9Sstevel@tonic-gate 
20107c478bd9Sstevel@tonic-gate 	opts = strdup(sh->sh_opts);
20117c478bd9Sstevel@tonic-gate 	if (opts == NULL) {
20127c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "getclientsflavors: no memory");
20137c478bd9Sstevel@tonic-gate 		return (0);
20147c478bd9Sstevel@tonic-gate 	}
20157c478bd9Sstevel@tonic-gate 
20167c478bd9Sstevel@tonic-gate 	flavors[0] = AUTH_SYS;
20177c478bd9Sstevel@tonic-gate 	p = opts;
20187c478bd9Sstevel@tonic-gate 
20197c478bd9Sstevel@tonic-gate 	while (*p) {
20207c478bd9Sstevel@tonic-gate 
20217c478bd9Sstevel@tonic-gate 		switch (getsubopt(&p, optlist, &val)) {
20227c478bd9Sstevel@tonic-gate 		case OPT_SECURE:
20237c478bd9Sstevel@tonic-gate 			flavors[0] = AUTH_DES;
20247c478bd9Sstevel@tonic-gate 			break;
20257c478bd9Sstevel@tonic-gate 
20267c478bd9Sstevel@tonic-gate 		case OPT_RO:
20277c478bd9Sstevel@tonic-gate 		case OPT_RW:
20287c478bd9Sstevel@tonic-gate 			defaultaccess = 0;
2029*a9685eaaSMarcel Telka 			if (in_access_list(cln, val) > 0)
2030*a9685eaaSMarcel Telka 				ok = B_TRUE;
20317c478bd9Sstevel@tonic-gate 			break;
2032b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2033b89a8333Snatalie li - Sun Microsystems - Irvine United States 		case OPT_NONE:
2034b89a8333Snatalie li - Sun Microsystems - Irvine United States 			defaultaccess = 0;
2035*a9685eaaSMarcel Telka 			if (in_access_list(cln, val) > 0)
2036b89a8333Snatalie li - Sun Microsystems - Irvine United States 				reject = B_TRUE;
20377c478bd9Sstevel@tonic-gate 		}
20387c478bd9Sstevel@tonic-gate 	}
20397c478bd9Sstevel@tonic-gate 
20407c478bd9Sstevel@tonic-gate 	free(opts);
20417c478bd9Sstevel@tonic-gate 
2042b89a8333Snatalie li - Sun Microsystems - Irvine United States 	/* none takes precedence over everything else */
2043b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (reject)
2044*a9685eaaSMarcel Telka 		ok = B_FALSE;
2045b89a8333Snatalie li - Sun Microsystems - Irvine United States 
20467c478bd9Sstevel@tonic-gate 	return (defaultaccess || ok);
20477c478bd9Sstevel@tonic-gate }
20487c478bd9Sstevel@tonic-gate 
20497c478bd9Sstevel@tonic-gate /*
20507c478bd9Sstevel@tonic-gate  * Given an export and the clients hostname(s)
20517c478bd9Sstevel@tonic-gate  * determine the security flavors that this
20527c478bd9Sstevel@tonic-gate  * client is permitted to use.
20537c478bd9Sstevel@tonic-gate  *
20547c478bd9Sstevel@tonic-gate  * This is somewhat more complicated than the "old"
20557c478bd9Sstevel@tonic-gate  * routine because the options may contain multiple
20567c478bd9Sstevel@tonic-gate  * security flavors (sec=) each with its own access
20577c478bd9Sstevel@tonic-gate  * lists.  So a client could be granted access based
20587c478bd9Sstevel@tonic-gate  * on a number of security flavors.  Note that the
20597c478bd9Sstevel@tonic-gate  * type of access might not always be the same, the
20607c478bd9Sstevel@tonic-gate  * client may get readonly access with one flavor
20617c478bd9Sstevel@tonic-gate  * and readwrite with another, however the client
20627c478bd9Sstevel@tonic-gate  * is not told this detail, it gets only the list
20637c478bd9Sstevel@tonic-gate  * of flavors, and only if the client is using
20647c478bd9Sstevel@tonic-gate  * version 3 of the mount protocol.
20657c478bd9Sstevel@tonic-gate  */
20667c478bd9Sstevel@tonic-gate static int
2067*a9685eaaSMarcel Telka getclientsflavors_new(share_t *sh, struct cln *cln, int *flavors)
20687c478bd9Sstevel@tonic-gate {
20697c478bd9Sstevel@tonic-gate 	char *opts, *p, *val;
20707c478bd9Sstevel@tonic-gate 	char *lasts;
20717c478bd9Sstevel@tonic-gate 	char *f;
2072*a9685eaaSMarcel Telka 	boolean_t defaultaccess = B_TRUE;	/* default access is rw */
2073*a9685eaaSMarcel Telka 	boolean_t access_ok = B_FALSE;
2074cf7e209dSIgor Kozhukhov 	int count, c;
2075b89a8333Snatalie li - Sun Microsystems - Irvine United States 	boolean_t reject = B_FALSE;
20767c478bd9Sstevel@tonic-gate 
20777c478bd9Sstevel@tonic-gate 	opts = strdup(sh->sh_opts);
20787c478bd9Sstevel@tonic-gate 	if (opts == NULL) {
20797c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "getclientsflavors: no memory");
20807c478bd9Sstevel@tonic-gate 		return (0);
20817c478bd9Sstevel@tonic-gate 	}
20827c478bd9Sstevel@tonic-gate 
20837c478bd9Sstevel@tonic-gate 	p = opts;
2084cf7e209dSIgor Kozhukhov 	count = c = 0;
20857c478bd9Sstevel@tonic-gate 
20867c478bd9Sstevel@tonic-gate 	while (*p) {
20877c478bd9Sstevel@tonic-gate 		switch (getsubopt(&p, optlist, &val)) {
20887c478bd9Sstevel@tonic-gate 		case OPT_SEC:
2089*a9685eaaSMarcel Telka 			if (reject)
2090*a9685eaaSMarcel Telka 				access_ok = B_FALSE;
2091*a9685eaaSMarcel Telka 
20927c478bd9Sstevel@tonic-gate 			/*
20937c478bd9Sstevel@tonic-gate 			 * Before a new sec=xxx option, check if we need
20947c478bd9Sstevel@tonic-gate 			 * to move the c index back to the previous count.
20957c478bd9Sstevel@tonic-gate 			 */
2096*a9685eaaSMarcel Telka 			if (!defaultaccess && !access_ok) {
20977c478bd9Sstevel@tonic-gate 				c = count;
20987c478bd9Sstevel@tonic-gate 			}
20997c478bd9Sstevel@tonic-gate 
21007c478bd9Sstevel@tonic-gate 			/* get all the sec=f1[:f2] flavors */
2101*a9685eaaSMarcel Telka 			while ((f = strtok_r(val, ":", &lasts)) != NULL) {
21027c478bd9Sstevel@tonic-gate 				flavors[c++] = map_flavor(f);
21037c478bd9Sstevel@tonic-gate 				val = NULL;
21047c478bd9Sstevel@tonic-gate 			}
21054a508a79SThomas Haynes 
21067c478bd9Sstevel@tonic-gate 			/* for a new sec=xxx option, default is rw access */
2107*a9685eaaSMarcel Telka 			defaultaccess = B_TRUE;
2108*a9685eaaSMarcel Telka 			access_ok = B_FALSE;
2109*a9685eaaSMarcel Telka 			reject = B_FALSE;
21107c478bd9Sstevel@tonic-gate 			break;
21117c478bd9Sstevel@tonic-gate 
21127c478bd9Sstevel@tonic-gate 		case OPT_RO:
21137c478bd9Sstevel@tonic-gate 		case OPT_RW:
2114*a9685eaaSMarcel Telka 			defaultaccess = B_FALSE;
2115*a9685eaaSMarcel Telka 			if (in_access_list(cln, val) > 0)
2116b89a8333Snatalie li - Sun Microsystems - Irvine United States 				access_ok = B_TRUE;
21177c478bd9Sstevel@tonic-gate 			break;
2118b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2119b89a8333Snatalie li - Sun Microsystems - Irvine United States 		case OPT_NONE:
2120*a9685eaaSMarcel Telka 			defaultaccess = B_FALSE;
2121*a9685eaaSMarcel Telka 			if (in_access_list(cln, val) > 0)
2122b89a8333Snatalie li - Sun Microsystems - Irvine United States 				reject = B_TRUE; /* none overides rw/ro */
2123b89a8333Snatalie li - Sun Microsystems - Irvine United States 			break;
21247c478bd9Sstevel@tonic-gate 		}
21257c478bd9Sstevel@tonic-gate 	}
21267c478bd9Sstevel@tonic-gate 
2127b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (reject)
2128b89a8333Snatalie li - Sun Microsystems - Irvine United States 		access_ok = B_FALSE;
2129b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2130*a9685eaaSMarcel Telka 	if (!defaultaccess && !access_ok)
21317c478bd9Sstevel@tonic-gate 		c = count;
2132b89a8333Snatalie li - Sun Microsystems - Irvine United States 
21337c478bd9Sstevel@tonic-gate 	free(opts);
21347c478bd9Sstevel@tonic-gate 
21357c478bd9Sstevel@tonic-gate 	return (c);
21367c478bd9Sstevel@tonic-gate }
21377c478bd9Sstevel@tonic-gate 
21387c478bd9Sstevel@tonic-gate /*
21397c478bd9Sstevel@tonic-gate  * This is a tricky piece of code that parses the
21407c478bd9Sstevel@tonic-gate  * share options looking for a match on the auth
21417c478bd9Sstevel@tonic-gate  * flavor that the client is using. If it finds
21427c478bd9Sstevel@tonic-gate  * a match, then the client is given ro, rw, or
21437c478bd9Sstevel@tonic-gate  * no access depending whether it is in the access
21447c478bd9Sstevel@tonic-gate  * list.  There is a special case for "secure"
21457c478bd9Sstevel@tonic-gate  * flavor.  Other flavors are values of the new "sec=" option.
21467c478bd9Sstevel@tonic-gate  */
21477c478bd9Sstevel@tonic-gate int
2148*a9685eaaSMarcel Telka check_client(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
2149*a9685eaaSMarcel Telka     gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
2150*a9685eaaSMarcel Telka     gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
21517c478bd9Sstevel@tonic-gate {
21527c478bd9Sstevel@tonic-gate 	if (newopts(sh->sh_opts))
2153*a9685eaaSMarcel Telka 		return (check_client_new(sh, cln, flavor, clnt_uid, clnt_gid,
2154*a9685eaaSMarcel Telka 		    clnt_ngids, clnt_gids, srv_uid, srv_gid, srv_ngids,
2155*a9685eaaSMarcel Telka 		    srv_gids));
21567c478bd9Sstevel@tonic-gate 	else
2157*a9685eaaSMarcel Telka 		return (check_client_old(sh, cln, flavor, clnt_uid, clnt_gid,
2158*a9685eaaSMarcel Telka 		    clnt_ngids, clnt_gids, srv_uid, srv_gid, srv_ngids,
2159*a9685eaaSMarcel Telka 		    srv_gids));
216089621fe1SMarcel Telka }
216189621fe1SMarcel Telka 
216289621fe1SMarcel Telka extern int _getgroupsbymember(const char *, gid_t[], int, int);
216389621fe1SMarcel Telka 
216489621fe1SMarcel Telka /*
216589621fe1SMarcel Telka  * Get supplemental groups for uid
216689621fe1SMarcel Telka  */
216789621fe1SMarcel Telka static int
216889621fe1SMarcel Telka getusergroups(uid_t uid, uint_t *ngrps, gid_t **grps)
216989621fe1SMarcel Telka {
217089621fe1SMarcel Telka 	struct passwd pwd;
217189621fe1SMarcel Telka 	char *pwbuf = alloca(pw_size);
217289621fe1SMarcel Telka 	gid_t *tmpgrps = alloca(ngroups_max * sizeof (gid_t));
217389621fe1SMarcel Telka 	int tmpngrps;
217489621fe1SMarcel Telka 
217589621fe1SMarcel Telka 	if (getpwuid_r(uid, &pwd, pwbuf, pw_size) == NULL)
217689621fe1SMarcel Telka 		return (-1);
217789621fe1SMarcel Telka 
217889621fe1SMarcel Telka 	tmpgrps[0] = pwd.pw_gid;
217989621fe1SMarcel Telka 
218089621fe1SMarcel Telka 	tmpngrps = _getgroupsbymember(pwd.pw_name, tmpgrps, ngroups_max, 1);
218189621fe1SMarcel Telka 	if (tmpngrps <= 0) {
218289621fe1SMarcel Telka 		syslog(LOG_WARNING,
218389621fe1SMarcel Telka 		    "getusergroups(): Unable to get groups for user %s",
218489621fe1SMarcel Telka 		    pwd.pw_name);
218589621fe1SMarcel Telka 
218689621fe1SMarcel Telka 		return (-1);
218789621fe1SMarcel Telka 	}
218889621fe1SMarcel Telka 
218989621fe1SMarcel Telka 	*grps = malloc(tmpngrps * sizeof (gid_t));
219089621fe1SMarcel Telka 	if (*grps == NULL) {
219189621fe1SMarcel Telka 		syslog(LOG_ERR,
219289621fe1SMarcel Telka 		    "getusergroups(): Memory allocation failed: %m");
219389621fe1SMarcel Telka 
219489621fe1SMarcel Telka 		return (-1);
219589621fe1SMarcel Telka 	}
219689621fe1SMarcel Telka 
219789621fe1SMarcel Telka 	*ngrps = tmpngrps;
219889621fe1SMarcel Telka 	(void) memcpy(*grps, tmpgrps, tmpngrps * sizeof (gid_t));
219989621fe1SMarcel Telka 
220089621fe1SMarcel Telka 	return (0);
22015cb0d679SMarcel Telka }
22025cb0d679SMarcel Telka 
22035cb0d679SMarcel Telka /*
22045cb0d679SMarcel Telka  * is_a_number(number)
22055cb0d679SMarcel Telka  *
22065cb0d679SMarcel Telka  * is the string a number in one of the forms we want to use?
22075cb0d679SMarcel Telka  */
22085cb0d679SMarcel Telka 
22095cb0d679SMarcel Telka static int
22105cb0d679SMarcel Telka is_a_number(char *number)
22115cb0d679SMarcel Telka {
22125cb0d679SMarcel Telka 	int ret = 1;
22135cb0d679SMarcel Telka 	int hex = 0;
22145cb0d679SMarcel Telka 
22155cb0d679SMarcel Telka 	if (strncmp(number, "0x", 2) == 0) {
22165cb0d679SMarcel Telka 		number += 2;
22175cb0d679SMarcel Telka 		hex = 1;
22185cb0d679SMarcel Telka 	} else if (*number == '-') {
22195cb0d679SMarcel Telka 		number++; /* skip the minus */
22205cb0d679SMarcel Telka 	}
22215cb0d679SMarcel Telka 	while (ret == 1 && *number != '\0') {
22225cb0d679SMarcel Telka 		if (hex) {
22235cb0d679SMarcel Telka 			ret = isxdigit(*number++);
22245cb0d679SMarcel Telka 		} else {
22255cb0d679SMarcel Telka 			ret = isdigit(*number++);
22265cb0d679SMarcel Telka 		}
22275cb0d679SMarcel Telka 	}
22285cb0d679SMarcel Telka 	return (ret);
22295cb0d679SMarcel Telka }
22305cb0d679SMarcel Telka 
22315cb0d679SMarcel Telka static boolean_t
22325cb0d679SMarcel Telka get_uid(char *value, uid_t *uid)
22335cb0d679SMarcel Telka {
22345cb0d679SMarcel Telka 	if (!is_a_number(value)) {
22355cb0d679SMarcel Telka 		struct passwd *pw;
22365cb0d679SMarcel Telka 		/*
22375cb0d679SMarcel Telka 		 * in this case it would have to be a
22385cb0d679SMarcel Telka 		 * user name
22395cb0d679SMarcel Telka 		 */
22405cb0d679SMarcel Telka 		pw = getpwnam(value);
22415cb0d679SMarcel Telka 		if (pw == NULL)
22425cb0d679SMarcel Telka 			return (B_FALSE);
22435cb0d679SMarcel Telka 		*uid = pw->pw_uid;
22445cb0d679SMarcel Telka 		endpwent();
22455cb0d679SMarcel Telka 	} else {
22465cb0d679SMarcel Telka 		uint64_t intval;
22475cb0d679SMarcel Telka 		intval = strtoull(value, NULL, 0);
22485cb0d679SMarcel Telka 		if (intval > UID_MAX && intval != -1)
22495cb0d679SMarcel Telka 			return (B_FALSE);
22505cb0d679SMarcel Telka 		*uid = (uid_t)intval;
22515cb0d679SMarcel Telka 	}
22525cb0d679SMarcel Telka 
22535cb0d679SMarcel Telka 	return (B_TRUE);
22545cb0d679SMarcel Telka }
22555cb0d679SMarcel Telka 
22565cb0d679SMarcel Telka static boolean_t
22575cb0d679SMarcel Telka get_gid(char *value, gid_t *gid)
22585cb0d679SMarcel Telka {
22595cb0d679SMarcel Telka 	if (!is_a_number(value)) {
22605cb0d679SMarcel Telka 		struct group *gr;
22615cb0d679SMarcel Telka 		/*
22625cb0d679SMarcel Telka 		 * in this case it would have to be a
22635cb0d679SMarcel Telka 		 * group name
22645cb0d679SMarcel Telka 		 */
22655cb0d679SMarcel Telka 		gr = getgrnam(value);
22665cb0d679SMarcel Telka 		if (gr == NULL)
22675cb0d679SMarcel Telka 			return (B_FALSE);
22685cb0d679SMarcel Telka 		*gid = gr->gr_gid;
22695cb0d679SMarcel Telka 		endgrent();
22705cb0d679SMarcel Telka 	} else {
22715cb0d679SMarcel Telka 		uint64_t intval;
22725cb0d679SMarcel Telka 		intval = strtoull(value, NULL, 0);
22735cb0d679SMarcel Telka 		if (intval > UID_MAX && intval != -1)
22745cb0d679SMarcel Telka 			return (B_FALSE);
22755cb0d679SMarcel Telka 		*gid = (gid_t)intval;
22765cb0d679SMarcel Telka 	}
22775cb0d679SMarcel Telka 
22785cb0d679SMarcel Telka 	return (B_TRUE);
22797c478bd9Sstevel@tonic-gate }
22807c478bd9Sstevel@tonic-gate 
22817c478bd9Sstevel@tonic-gate static int
2282*a9685eaaSMarcel Telka check_client_old(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
228389621fe1SMarcel Telka     gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
228489621fe1SMarcel Telka     gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
22857c478bd9Sstevel@tonic-gate {
22867c478bd9Sstevel@tonic-gate 	char *opts, *p, *val;
22877c478bd9Sstevel@tonic-gate 	int match;	/* Set when a flavor is matched */
22887c478bd9Sstevel@tonic-gate 	int perm = 0;	/* Set when "ro", "rw" or "root" is matched */
22897c478bd9Sstevel@tonic-gate 	int list = 0;	/* Set when "ro", "rw" is found */
22907c478bd9Sstevel@tonic-gate 	int ro_val = 0;	/* Set if ro option is 'ro=' */
22917c478bd9Sstevel@tonic-gate 	int rw_val = 0;	/* Set if rw option is 'rw=' */
22925cb0d679SMarcel Telka 
22935cb0d679SMarcel Telka 	boolean_t map_deny = B_FALSE;
22947c478bd9Sstevel@tonic-gate 
22957c478bd9Sstevel@tonic-gate 	opts = strdup(sh->sh_opts);
22967c478bd9Sstevel@tonic-gate 	if (opts == NULL) {
22977c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "check_client: no memory");
22987c478bd9Sstevel@tonic-gate 		return (0);
22997c478bd9Sstevel@tonic-gate 	}
23007c478bd9Sstevel@tonic-gate 
230189621fe1SMarcel Telka 	/*
230289621fe1SMarcel Telka 	 * If client provided 16 supplemental groups with AUTH_SYS, lookup
230389621fe1SMarcel Telka 	 * locally for all of them
230489621fe1SMarcel Telka 	 */
230589621fe1SMarcel Telka 	if (flavor == AUTH_SYS && clnt_ngids == NGRPS && ngroups_max > NGRPS)
230689621fe1SMarcel Telka 		if (getusergroups(clnt_uid, srv_ngids, srv_gids) == 0)
230789621fe1SMarcel Telka 			perm |= NFSAUTH_GROUPS;
230889621fe1SMarcel Telka 
23097c478bd9Sstevel@tonic-gate 	p = opts;
23107c478bd9Sstevel@tonic-gate 	match = AUTH_UNIX;
23117c478bd9Sstevel@tonic-gate 
23127c478bd9Sstevel@tonic-gate 	while (*p) {
23137c478bd9Sstevel@tonic-gate 		switch (getsubopt(&p, optlist, &val)) {
23147c478bd9Sstevel@tonic-gate 
23157c478bd9Sstevel@tonic-gate 		case OPT_SECURE:
23167c478bd9Sstevel@tonic-gate 			match = AUTH_DES;
231789621fe1SMarcel Telka 
231889621fe1SMarcel Telka 			if (perm & NFSAUTH_GROUPS) {
231989621fe1SMarcel Telka 				free(*srv_gids);
232089621fe1SMarcel Telka 				*srv_ngids = 0;
232189621fe1SMarcel Telka 				*srv_gids = NULL;
232289621fe1SMarcel Telka 				perm &= ~NFSAUTH_GROUPS;
232389621fe1SMarcel Telka 			}
232489621fe1SMarcel Telka 
23257c478bd9Sstevel@tonic-gate 			break;
23267c478bd9Sstevel@tonic-gate 
23277c478bd9Sstevel@tonic-gate 		case OPT_RO:
23287c478bd9Sstevel@tonic-gate 			list++;
23295cb0d679SMarcel Telka 			if (val != NULL)
23305cb0d679SMarcel Telka 				ro_val++;
2331*a9685eaaSMarcel Telka 			if (in_access_list(cln, val) > 0)
23327c478bd9Sstevel@tonic-gate 				perm |= NFSAUTH_RO;
23337c478bd9Sstevel@tonic-gate 			break;
23347c478bd9Sstevel@tonic-gate 
23357c478bd9Sstevel@tonic-gate 		case OPT_RW:
23367c478bd9Sstevel@tonic-gate 			list++;
23375cb0d679SMarcel Telka 			if (val != NULL)
23385cb0d679SMarcel Telka 				rw_val++;
2339*a9685eaaSMarcel Telka 			if (in_access_list(cln, val) > 0)
23407c478bd9Sstevel@tonic-gate 				perm |= NFSAUTH_RW;
23417c478bd9Sstevel@tonic-gate 			break;
23427c478bd9Sstevel@tonic-gate 
23437c478bd9Sstevel@tonic-gate 		case OPT_ROOT:
23447c478bd9Sstevel@tonic-gate 			/*
23457c478bd9Sstevel@tonic-gate 			 * Check if the client is in
23467c478bd9Sstevel@tonic-gate 			 * the root list. Only valid
23477c478bd9Sstevel@tonic-gate 			 * for AUTH_SYS.
23487c478bd9Sstevel@tonic-gate 			 */
23497c478bd9Sstevel@tonic-gate 			if (flavor != AUTH_SYS)
23507c478bd9Sstevel@tonic-gate 				break;
23517c478bd9Sstevel@tonic-gate 
23527c478bd9Sstevel@tonic-gate 			if (val == NULL || *val == '\0')
23537c478bd9Sstevel@tonic-gate 				break;
23547c478bd9Sstevel@tonic-gate 
23555cb0d679SMarcel Telka 			if (clnt_uid != 0)
23565cb0d679SMarcel Telka 				break;
23575cb0d679SMarcel Telka 
2358*a9685eaaSMarcel Telka 			if (in_access_list(cln, val) > 0) {
23597c478bd9Sstevel@tonic-gate 				perm |= NFSAUTH_ROOT;
23605cb0d679SMarcel Telka 				perm |= NFSAUTH_UIDMAP | NFSAUTH_GIDMAP;
23615cb0d679SMarcel Telka 				map_deny = B_FALSE;
236289621fe1SMarcel Telka 
236389621fe1SMarcel Telka 				if (perm & NFSAUTH_GROUPS) {
236489621fe1SMarcel Telka 					free(*srv_gids);
236589621fe1SMarcel Telka 					*srv_ngids = 0;
236689621fe1SMarcel Telka 					*srv_gids = NULL;
236789621fe1SMarcel Telka 					perm &= ~NFSAUTH_GROUPS;
236889621fe1SMarcel Telka 				}
23695cb0d679SMarcel Telka 			}
23707c478bd9Sstevel@tonic-gate 			break;
2371b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2372b89a8333Snatalie li - Sun Microsystems - Irvine United States 		case OPT_NONE:
2373b89a8333Snatalie li - Sun Microsystems - Irvine United States 			/*
2374b89a8333Snatalie li - Sun Microsystems - Irvine United States 			 * Check if the client should have no access
2375b89a8333Snatalie li - Sun Microsystems - Irvine United States 			 * to this share at all. This option behaves
2376b89a8333Snatalie li - Sun Microsystems - Irvine United States 			 * more like "root" than either "rw" or "ro".
2377b89a8333Snatalie li - Sun Microsystems - Irvine United States 			 */
2378*a9685eaaSMarcel Telka 			if (in_access_list(cln, val) > 0)
23795cb0d679SMarcel Telka 				perm |= NFSAUTH_DENIED;
23805cb0d679SMarcel Telka 			break;
23815cb0d679SMarcel Telka 
23825cb0d679SMarcel Telka 		case OPT_UIDMAP: {
23835cb0d679SMarcel Telka 			char *c;
23845cb0d679SMarcel Telka 			char *n;
23855cb0d679SMarcel Telka 
23865cb0d679SMarcel Telka 			/*
23875cb0d679SMarcel Telka 			 * The uidmap is supported for AUTH_SYS only.
23885cb0d679SMarcel Telka 			 */
23895cb0d679SMarcel Telka 			if (flavor != AUTH_SYS)
23905cb0d679SMarcel Telka 				break;
23915cb0d679SMarcel Telka 
23925cb0d679SMarcel Telka 			if (perm & NFSAUTH_UIDMAP || map_deny)
23935cb0d679SMarcel Telka 				break;
23945cb0d679SMarcel Telka 
23955cb0d679SMarcel Telka 			for (c = val; c != NULL; c = n) {
23965cb0d679SMarcel Telka 				char *s;
23975cb0d679SMarcel Telka 				char *al;
23985cb0d679SMarcel Telka 				uid_t srv;
23995cb0d679SMarcel Telka 
24005cb0d679SMarcel Telka 				n = strchr(c, '~');
24015cb0d679SMarcel Telka 				if (n != NULL)
24025cb0d679SMarcel Telka 					*n++ = '\0';
24035cb0d679SMarcel Telka 
24045cb0d679SMarcel Telka 				s = strchr(c, ':');
24055cb0d679SMarcel Telka 				if (s != NULL) {
24065cb0d679SMarcel Telka 					*s++ = '\0';
24075cb0d679SMarcel Telka 					al = strchr(s, ':');
24085cb0d679SMarcel Telka 					if (al != NULL)
24095cb0d679SMarcel Telka 						*al++ = '\0';
24105cb0d679SMarcel Telka 				}
24115cb0d679SMarcel Telka 
24125cb0d679SMarcel Telka 				if (s == NULL || al == NULL)
24135cb0d679SMarcel Telka 					continue;
24145cb0d679SMarcel Telka 
24155cb0d679SMarcel Telka 				if (*c == '\0') {
24165cb0d679SMarcel Telka 					if (clnt_uid != (uid_t)-1)
24175cb0d679SMarcel Telka 						continue;
24185cb0d679SMarcel Telka 				} else if (strcmp(c, "*") != 0) {
24195cb0d679SMarcel Telka 					uid_t clnt;
24205cb0d679SMarcel Telka 
24215cb0d679SMarcel Telka 					if (!get_uid(c, &clnt))
24225cb0d679SMarcel Telka 						continue;
24235cb0d679SMarcel Telka 
24245cb0d679SMarcel Telka 					if (clnt_uid != clnt)
24255cb0d679SMarcel Telka 						continue;
24265cb0d679SMarcel Telka 				}
24275cb0d679SMarcel Telka 
24285cb0d679SMarcel Telka 				if (*s == '\0')
24295cb0d679SMarcel Telka 					srv = UID_NOBODY;
24305cb0d679SMarcel Telka 				else if (!get_uid(s, &srv))
24315cb0d679SMarcel Telka 					continue;
24325cb0d679SMarcel Telka 				else if (srv == (uid_t)-1) {
24335cb0d679SMarcel Telka 					map_deny = B_TRUE;
24345cb0d679SMarcel Telka 					break;
24355cb0d679SMarcel Telka 				}
24365cb0d679SMarcel Telka 
2437*a9685eaaSMarcel Telka 				if (in_access_list(cln, al) > 0) {
24385cb0d679SMarcel Telka 					*srv_uid = srv;
24395cb0d679SMarcel Telka 					perm |= NFSAUTH_UIDMAP;
244089621fe1SMarcel Telka 
244189621fe1SMarcel Telka 					if (perm & NFSAUTH_GROUPS) {
244289621fe1SMarcel Telka 						free(*srv_gids);
244389621fe1SMarcel Telka 						*srv_ngids = 0;
244489621fe1SMarcel Telka 						*srv_gids = NULL;
244589621fe1SMarcel Telka 						perm &= ~NFSAUTH_GROUPS;
244689621fe1SMarcel Telka 					}
244789621fe1SMarcel Telka 
24485cb0d679SMarcel Telka 					break;
24495cb0d679SMarcel Telka 				}
24505cb0d679SMarcel Telka 			}
24515cb0d679SMarcel Telka 
24525cb0d679SMarcel Telka 			break;
24535cb0d679SMarcel Telka 		}
24545cb0d679SMarcel Telka 
24555cb0d679SMarcel Telka 		case OPT_GIDMAP: {
24565cb0d679SMarcel Telka 			char *c;
24575cb0d679SMarcel Telka 			char *n;
24585cb0d679SMarcel Telka 
24595cb0d679SMarcel Telka 			/*
24605cb0d679SMarcel Telka 			 * The gidmap is supported for AUTH_SYS only.
24615cb0d679SMarcel Telka 			 */
24625cb0d679SMarcel Telka 			if (flavor != AUTH_SYS)
24635cb0d679SMarcel Telka 				break;
24645cb0d679SMarcel Telka 
24655cb0d679SMarcel Telka 			if (perm & NFSAUTH_GIDMAP || map_deny)
24665cb0d679SMarcel Telka 				break;
24675cb0d679SMarcel Telka 
24685cb0d679SMarcel Telka 			for (c = val; c != NULL; c = n) {
24695cb0d679SMarcel Telka 				char *s;
24705cb0d679SMarcel Telka 				char *al;
24715cb0d679SMarcel Telka 				gid_t srv;
24725cb0d679SMarcel Telka 
24735cb0d679SMarcel Telka 				n = strchr(c, '~');
24745cb0d679SMarcel Telka 				if (n != NULL)
24755cb0d679SMarcel Telka 					*n++ = '\0';
24765cb0d679SMarcel Telka 
24775cb0d679SMarcel Telka 				s = strchr(c, ':');
24785cb0d679SMarcel Telka 				if (s != NULL) {
24795cb0d679SMarcel Telka 					*s++ = '\0';
24805cb0d679SMarcel Telka 					al = strchr(s, ':');
24815cb0d679SMarcel Telka 					if (al != NULL)
24825cb0d679SMarcel Telka 						*al++ = '\0';
24835cb0d679SMarcel Telka 				}
24845cb0d679SMarcel Telka 
24855cb0d679SMarcel Telka 				if (s == NULL || al == NULL)
24865cb0d679SMarcel Telka 					break;
24875cb0d679SMarcel Telka 
24885cb0d679SMarcel Telka 				if (*c == '\0') {
24895cb0d679SMarcel Telka 					if (clnt_gid != (gid_t)-1)
24905cb0d679SMarcel Telka 						continue;
24915cb0d679SMarcel Telka 				} else if (strcmp(c, "*") != 0) {
24925cb0d679SMarcel Telka 					gid_t clnt;
24935cb0d679SMarcel Telka 
24945cb0d679SMarcel Telka 					if (!get_gid(c, &clnt))
24955cb0d679SMarcel Telka 						continue;
24965cb0d679SMarcel Telka 
24975cb0d679SMarcel Telka 					if (clnt_gid != clnt)
24985cb0d679SMarcel Telka 						continue;
24995cb0d679SMarcel Telka 				}
25005cb0d679SMarcel Telka 
25015cb0d679SMarcel Telka 				if (*s == '\0')
25025cb0d679SMarcel Telka 					srv = UID_NOBODY;
25035cb0d679SMarcel Telka 				else if (!get_gid(s, &srv))
25045cb0d679SMarcel Telka 					continue;
25055cb0d679SMarcel Telka 				else if (srv == (gid_t)-1) {
25065cb0d679SMarcel Telka 					map_deny = B_TRUE;
25075cb0d679SMarcel Telka 					break;
25085cb0d679SMarcel Telka 				}
25095cb0d679SMarcel Telka 
2510*a9685eaaSMarcel Telka 				if (in_access_list(cln, al) > 0) {
25115cb0d679SMarcel Telka 					*srv_gid = srv;
25125cb0d679SMarcel Telka 					perm |= NFSAUTH_GIDMAP;
251389621fe1SMarcel Telka 
251489621fe1SMarcel Telka 					if (perm & NFSAUTH_GROUPS) {
251589621fe1SMarcel Telka 						free(*srv_gids);
251689621fe1SMarcel Telka 						*srv_ngids = 0;
251789621fe1SMarcel Telka 						*srv_gids = NULL;
251889621fe1SMarcel Telka 						perm &= ~NFSAUTH_GROUPS;
251989621fe1SMarcel Telka 					}
252089621fe1SMarcel Telka 
25215cb0d679SMarcel Telka 					break;
25225cb0d679SMarcel Telka 				}
25235cb0d679SMarcel Telka 			}
25245cb0d679SMarcel Telka 
25255cb0d679SMarcel Telka 			break;
25265cb0d679SMarcel Telka 		}
25275cb0d679SMarcel Telka 
25285cb0d679SMarcel Telka 		default:
2529b89a8333Snatalie li - Sun Microsystems - Irvine United States 			break;
25307c478bd9Sstevel@tonic-gate 		}
25317c478bd9Sstevel@tonic-gate 	}
25327c478bd9Sstevel@tonic-gate 
25337c478bd9Sstevel@tonic-gate 	free(opts);
25347c478bd9Sstevel@tonic-gate 
25355cb0d679SMarcel Telka 	if (perm & NFSAUTH_ROOT) {
25365cb0d679SMarcel Telka 		*srv_uid = 0;
25375cb0d679SMarcel Telka 		*srv_gid = 0;
25385cb0d679SMarcel Telka 	}
25395cb0d679SMarcel Telka 
25405cb0d679SMarcel Telka 	if (map_deny)
25415cb0d679SMarcel Telka 		perm |= NFSAUTH_DENIED;
25425cb0d679SMarcel Telka 
25435cb0d679SMarcel Telka 	if (!(perm & NFSAUTH_UIDMAP))
25445cb0d679SMarcel Telka 		*srv_uid = clnt_uid;
25455cb0d679SMarcel Telka 	if (!(perm & NFSAUTH_GIDMAP))
25465cb0d679SMarcel Telka 		*srv_gid = clnt_gid;
25475cb0d679SMarcel Telka 
25485cb0d679SMarcel Telka 	if (flavor != match || perm & NFSAUTH_DENIED)
25497c478bd9Sstevel@tonic-gate 		return (NFSAUTH_DENIED);
25507c478bd9Sstevel@tonic-gate 
25517c478bd9Sstevel@tonic-gate 	if (list) {
25527c478bd9Sstevel@tonic-gate 		/*
25537c478bd9Sstevel@tonic-gate 		 * If the client doesn't match an "ro" or "rw"
25547c478bd9Sstevel@tonic-gate 		 * list then set no access.
25557c478bd9Sstevel@tonic-gate 		 */
25567c478bd9Sstevel@tonic-gate 		if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0)
25577c478bd9Sstevel@tonic-gate 			perm |= NFSAUTH_DENIED;
25587c478bd9Sstevel@tonic-gate 	} else {
25597c478bd9Sstevel@tonic-gate 		/*
25607c478bd9Sstevel@tonic-gate 		 * The client matched a flavor entry that
25617c478bd9Sstevel@tonic-gate 		 * has no explicit "rw" or "ro" determination.
25627c478bd9Sstevel@tonic-gate 		 * Default it to "rw".
25637c478bd9Sstevel@tonic-gate 		 */
25647c478bd9Sstevel@tonic-gate 		perm |= NFSAUTH_RW;
25657c478bd9Sstevel@tonic-gate 	}
25667c478bd9Sstevel@tonic-gate 
25677c478bd9Sstevel@tonic-gate 	/*
25687c478bd9Sstevel@tonic-gate 	 * The client may show up in both ro= and rw=
25697c478bd9Sstevel@tonic-gate 	 * lists.  If so, then turn off the RO access
25707c478bd9Sstevel@tonic-gate 	 * bit leaving RW access.
25717c478bd9Sstevel@tonic-gate 	 */
25727c478bd9Sstevel@tonic-gate 	if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) {
25737c478bd9Sstevel@tonic-gate 		/*
25747c478bd9Sstevel@tonic-gate 		 * Logically cover all permutations of rw=,ro=.
25757c478bd9Sstevel@tonic-gate 		 * In the case where, rw,ro=<host> we would like
25767c478bd9Sstevel@tonic-gate 		 * to remove RW access for the host.  In all other cases
25777c478bd9Sstevel@tonic-gate 		 * RW wins the precedence battle.
25787c478bd9Sstevel@tonic-gate 		 */
25797c478bd9Sstevel@tonic-gate 		if (!rw_val && ro_val) {
25807c478bd9Sstevel@tonic-gate 			perm &= ~(NFSAUTH_RW);
25817c478bd9Sstevel@tonic-gate 		} else {
25827c478bd9Sstevel@tonic-gate 			perm &= ~(NFSAUTH_RO);
25837c478bd9Sstevel@tonic-gate 		}
25847c478bd9Sstevel@tonic-gate 	}
25857c478bd9Sstevel@tonic-gate 
25867c478bd9Sstevel@tonic-gate 	return (perm);
25877c478bd9Sstevel@tonic-gate }
25887c478bd9Sstevel@tonic-gate 
25897c478bd9Sstevel@tonic-gate /*
25907c478bd9Sstevel@tonic-gate  * Check if the client has access by using a flavor different from
25917c478bd9Sstevel@tonic-gate  * the given "flavor". If "flavor" is not in the flavor list,
25927c478bd9Sstevel@tonic-gate  * return TRUE to indicate that this "flavor" is a wrong sec.
25937c478bd9Sstevel@tonic-gate  */
25947c478bd9Sstevel@tonic-gate static bool_t
2595*a9685eaaSMarcel Telka is_wrongsec(share_t *sh, struct cln *cln, int flavor)
25967c478bd9Sstevel@tonic-gate {
25977c478bd9Sstevel@tonic-gate 	int flavor_list[MAX_FLAVORS];
25987c478bd9Sstevel@tonic-gate 	int flavor_count, i;
25997c478bd9Sstevel@tonic-gate 
26007c478bd9Sstevel@tonic-gate 	/* get the flavor list that the client has access with */
2601*a9685eaaSMarcel Telka 	flavor_count = getclientsflavors_new(sh, cln, flavor_list);
26027c478bd9Sstevel@tonic-gate 
26037c478bd9Sstevel@tonic-gate 	if (flavor_count == 0)
26047c478bd9Sstevel@tonic-gate 		return (FALSE);
26057c478bd9Sstevel@tonic-gate 
26067c478bd9Sstevel@tonic-gate 	/*
26077c478bd9Sstevel@tonic-gate 	 * Check if the given "flavor" is in the flavor_list.
26087c478bd9Sstevel@tonic-gate 	 */
26097c478bd9Sstevel@tonic-gate 	for (i = 0; i < flavor_count; i++) {
26107c478bd9Sstevel@tonic-gate 		if (flavor == flavor_list[i])
26117c478bd9Sstevel@tonic-gate 			return (FALSE);
26127c478bd9Sstevel@tonic-gate 	}
26137c478bd9Sstevel@tonic-gate 
26147c478bd9Sstevel@tonic-gate 	/*
26157c478bd9Sstevel@tonic-gate 	 * If "flavor" is not in the flavor_list, return TRUE to indicate
26167c478bd9Sstevel@tonic-gate 	 * that the client should have access by using a security flavor
26177c478bd9Sstevel@tonic-gate 	 * different from this "flavor".
26187c478bd9Sstevel@tonic-gate 	 */
26197c478bd9Sstevel@tonic-gate 	return (TRUE);
26207c478bd9Sstevel@tonic-gate }
26217c478bd9Sstevel@tonic-gate 
26227c478bd9Sstevel@tonic-gate /*
26237c478bd9Sstevel@tonic-gate  * Given an export and the client's hostname, we
26247c478bd9Sstevel@tonic-gate  * check the security options to see whether the
26257c478bd9Sstevel@tonic-gate  * client is allowed to use the given security flavor.
26267c478bd9Sstevel@tonic-gate  *
26277c478bd9Sstevel@tonic-gate  * The strategy is to proceed through the options looking
26287c478bd9Sstevel@tonic-gate  * for a flavor match, then pay attention to the ro, rw,
26297c478bd9Sstevel@tonic-gate  * and root options.
26307c478bd9Sstevel@tonic-gate  *
26317c478bd9Sstevel@tonic-gate  * Note that an entry may list several flavors in a
26327c478bd9Sstevel@tonic-gate  * single entry, e.g.
26337c478bd9Sstevel@tonic-gate  *
26347c478bd9Sstevel@tonic-gate  *   sec=krb5,rw=clnt1:clnt2,ro,sec=sys,ro
26357c478bd9Sstevel@tonic-gate  *
26367c478bd9Sstevel@tonic-gate  */
26377c478bd9Sstevel@tonic-gate 
26387c478bd9Sstevel@tonic-gate static int
2639*a9685eaaSMarcel Telka check_client_new(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
264089621fe1SMarcel Telka     gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
264189621fe1SMarcel Telka     gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
26427c478bd9Sstevel@tonic-gate {
26437c478bd9Sstevel@tonic-gate 	char *opts, *p, *val;
26447c478bd9Sstevel@tonic-gate 	char *lasts;
26457c478bd9Sstevel@tonic-gate 	char *f;
26467c478bd9Sstevel@tonic-gate 	int match = 0;	/* Set when a flavor is matched */
26477c478bd9Sstevel@tonic-gate 	int perm = 0;	/* Set when "ro", "rw" or "root" is matched */
26487c478bd9Sstevel@tonic-gate 	int list = 0;	/* Set when "ro", "rw" is found */
26497c478bd9Sstevel@tonic-gate 	int ro_val = 0;	/* Set if ro option is 'ro=' */
26507c478bd9Sstevel@tonic-gate 	int rw_val = 0;	/* Set if rw option is 'rw=' */
26515cb0d679SMarcel Telka 
26525cb0d679SMarcel Telka 	boolean_t map_deny = B_FALSE;
26537c478bd9Sstevel@tonic-gate 
26547c478bd9Sstevel@tonic-gate 	opts = strdup(sh->sh_opts);
26557c478bd9Sstevel@tonic-gate 	if (opts == NULL) {
26567c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "check_client: no memory");
26577c478bd9Sstevel@tonic-gate 		return (0);
26587c478bd9Sstevel@tonic-gate 	}
26597c478bd9Sstevel@tonic-gate 
266089621fe1SMarcel Telka 	/*
266189621fe1SMarcel Telka 	 * If client provided 16 supplemental groups with AUTH_SYS, lookup
266289621fe1SMarcel Telka 	 * locally for all of them
266389621fe1SMarcel Telka 	 */
266489621fe1SMarcel Telka 	if (flavor == AUTH_SYS && clnt_ngids == NGRPS && ngroups_max > NGRPS)
266589621fe1SMarcel Telka 		if (getusergroups(clnt_uid, srv_ngids, srv_gids) == 0)
266689621fe1SMarcel Telka 			perm |= NFSAUTH_GROUPS;
266789621fe1SMarcel Telka 
26687c478bd9Sstevel@tonic-gate 	p = opts;
26697c478bd9Sstevel@tonic-gate 
26707c478bd9Sstevel@tonic-gate 	while (*p) {
26717c478bd9Sstevel@tonic-gate 		switch (getsubopt(&p, optlist, &val)) {
26727c478bd9Sstevel@tonic-gate 
26737c478bd9Sstevel@tonic-gate 		case OPT_SEC:
26747c478bd9Sstevel@tonic-gate 			if (match)
26757c478bd9Sstevel@tonic-gate 				goto done;
26767c478bd9Sstevel@tonic-gate 
26777c478bd9Sstevel@tonic-gate 			while ((f = strtok_r(val, ":", &lasts))
26787c478bd9Sstevel@tonic-gate 			    != NULL) {
26797c478bd9Sstevel@tonic-gate 				if (flavor == map_flavor(f)) {
26807c478bd9Sstevel@tonic-gate 					match = 1;
26817c478bd9Sstevel@tonic-gate 					break;
26827c478bd9Sstevel@tonic-gate 				}
26837c478bd9Sstevel@tonic-gate 				val = NULL;
26847c478bd9Sstevel@tonic-gate 			}
26857c478bd9Sstevel@tonic-gate 			break;
26867c478bd9Sstevel@tonic-gate 
26877c478bd9Sstevel@tonic-gate 		case OPT_RO:
26887c478bd9Sstevel@tonic-gate 			if (!match)
26897c478bd9Sstevel@tonic-gate 				break;
26907c478bd9Sstevel@tonic-gate 
26917c478bd9Sstevel@tonic-gate 			list++;
26925cb0d679SMarcel Telka 			if (val != NULL)
26935cb0d679SMarcel Telka 				ro_val++;
2694*a9685eaaSMarcel Telka 			if (in_access_list(cln, val) > 0)
26957c478bd9Sstevel@tonic-gate 				perm |= NFSAUTH_RO;
26967c478bd9Sstevel@tonic-gate 			break;
26977c478bd9Sstevel@tonic-gate 
26987c478bd9Sstevel@tonic-gate 		case OPT_RW:
26997c478bd9Sstevel@tonic-gate 			if (!match)
27007c478bd9Sstevel@tonic-gate 				break;
27017c478bd9Sstevel@tonic-gate 
27027c478bd9Sstevel@tonic-gate 			list++;
27035cb0d679SMarcel Telka 			if (val != NULL)
27045cb0d679SMarcel Telka 				rw_val++;
2705*a9685eaaSMarcel Telka 			if (in_access_list(cln, val) > 0)
27067c478bd9Sstevel@tonic-gate 				perm |= NFSAUTH_RW;
27077c478bd9Sstevel@tonic-gate 			break;
27087c478bd9Sstevel@tonic-gate 
27097c478bd9Sstevel@tonic-gate 		case OPT_ROOT:
27107c478bd9Sstevel@tonic-gate 			/*
27117c478bd9Sstevel@tonic-gate 			 * Check if the client is in
27127c478bd9Sstevel@tonic-gate 			 * the root list. Only valid
27137c478bd9Sstevel@tonic-gate 			 * for AUTH_SYS.
27147c478bd9Sstevel@tonic-gate 			 */
27157c478bd9Sstevel@tonic-gate 			if (flavor != AUTH_SYS)
27167c478bd9Sstevel@tonic-gate 				break;
27177c478bd9Sstevel@tonic-gate 
27187c478bd9Sstevel@tonic-gate 			if (!match)
27197c478bd9Sstevel@tonic-gate 				break;
27207c478bd9Sstevel@tonic-gate 
27217c478bd9Sstevel@tonic-gate 			if (val == NULL || *val == '\0')
27227c478bd9Sstevel@tonic-gate 				break;
27237c478bd9Sstevel@tonic-gate 
27245cb0d679SMarcel Telka 			if (clnt_uid != 0)
27255cb0d679SMarcel Telka 				break;
27265cb0d679SMarcel Telka 
2727*a9685eaaSMarcel Telka 			if (in_access_list(cln, val) > 0) {
27287c478bd9Sstevel@tonic-gate 				perm |= NFSAUTH_ROOT;
27295cb0d679SMarcel Telka 				perm |= NFSAUTH_UIDMAP | NFSAUTH_GIDMAP;
27305cb0d679SMarcel Telka 				map_deny = B_FALSE;
273189621fe1SMarcel Telka 
273289621fe1SMarcel Telka 				if (perm & NFSAUTH_GROUPS) {
273389621fe1SMarcel Telka 					free(*srv_gids);
273489621fe1SMarcel Telka 					*srv_gids = NULL;
273589621fe1SMarcel Telka 					*srv_ngids = 0;
273689621fe1SMarcel Telka 					perm &= ~NFSAUTH_GROUPS;
273789621fe1SMarcel Telka 				}
27385cb0d679SMarcel Telka 			}
27397c478bd9Sstevel@tonic-gate 			break;
2740b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2741b89a8333Snatalie li - Sun Microsystems - Irvine United States 		case OPT_NONE:
2742b89a8333Snatalie li - Sun Microsystems - Irvine United States 			/*
2743b89a8333Snatalie li - Sun Microsystems - Irvine United States 			 * Check if the client should have no access
2744b89a8333Snatalie li - Sun Microsystems - Irvine United States 			 * to this share at all. This option behaves
2745b89a8333Snatalie li - Sun Microsystems - Irvine United States 			 * more like "root" than either "rw" or "ro".
2746b89a8333Snatalie li - Sun Microsystems - Irvine United States 			 */
2747*a9685eaaSMarcel Telka 			if (in_access_list(cln, val) > 0)
2748b89a8333Snatalie li - Sun Microsystems - Irvine United States 				perm |= NFSAUTH_DENIED;
2749b89a8333Snatalie li - Sun Microsystems - Irvine United States 			break;
27505cb0d679SMarcel Telka 
27515cb0d679SMarcel Telka 		case OPT_UIDMAP: {
27525cb0d679SMarcel Telka 			char *c;
27535cb0d679SMarcel Telka 			char *n;
27545cb0d679SMarcel Telka 
27555cb0d679SMarcel Telka 			/*
27565cb0d679SMarcel Telka 			 * The uidmap is supported for AUTH_SYS only.
27575cb0d679SMarcel Telka 			 */
27585cb0d679SMarcel Telka 			if (flavor != AUTH_SYS)
27595cb0d679SMarcel Telka 				break;
27605cb0d679SMarcel Telka 
27615cb0d679SMarcel Telka 			if (!match || perm & NFSAUTH_UIDMAP || map_deny)
27625cb0d679SMarcel Telka 				break;
27635cb0d679SMarcel Telka 
27645cb0d679SMarcel Telka 			for (c = val; c != NULL; c = n) {
27655cb0d679SMarcel Telka 				char *s;
27665cb0d679SMarcel Telka 				char *al;
27675cb0d679SMarcel Telka 				uid_t srv;
27685cb0d679SMarcel Telka 
27695cb0d679SMarcel Telka 				n = strchr(c, '~');
27705cb0d679SMarcel Telka 				if (n != NULL)
27715cb0d679SMarcel Telka 					*n++ = '\0';
27725cb0d679SMarcel Telka 
27735cb0d679SMarcel Telka 				s = strchr(c, ':');
27745cb0d679SMarcel Telka 				if (s != NULL) {
27755cb0d679SMarcel Telka 					*s++ = '\0';
27765cb0d679SMarcel Telka 					al = strchr(s, ':');
27775cb0d679SMarcel Telka 					if (al != NULL)
27785cb0d679SMarcel Telka 						*al++ = '\0';
27795cb0d679SMarcel Telka 				}
27805cb0d679SMarcel Telka 
27815cb0d679SMarcel Telka 				if (s == NULL || al == NULL)
27825cb0d679SMarcel Telka 					continue;
27835cb0d679SMarcel Telka 
27845cb0d679SMarcel Telka 				if (*c == '\0') {
27855cb0d679SMarcel Telka 					if (clnt_uid != (uid_t)-1)
27865cb0d679SMarcel Telka 						continue;
27875cb0d679SMarcel Telka 				} else if (strcmp(c, "*") != 0) {
27885cb0d679SMarcel Telka 					uid_t clnt;
27895cb0d679SMarcel Telka 
27905cb0d679SMarcel Telka 					if (!get_uid(c, &clnt))
27915cb0d679SMarcel Telka 						continue;
27925cb0d679SMarcel Telka 
27935cb0d679SMarcel Telka 					if (clnt_uid != clnt)
27945cb0d679SMarcel Telka 						continue;
27955cb0d679SMarcel Telka 				}
27965cb0d679SMarcel Telka 
27975cb0d679SMarcel Telka 				if (*s == '\0')
27985cb0d679SMarcel Telka 					srv = UID_NOBODY;
27995cb0d679SMarcel Telka 				else if (!get_uid(s, &srv))
28005cb0d679SMarcel Telka 					continue;
28015cb0d679SMarcel Telka 				else if (srv == (uid_t)-1) {
28025cb0d679SMarcel Telka 					map_deny = B_TRUE;
28035cb0d679SMarcel Telka 					break;
28045cb0d679SMarcel Telka 				}
28055cb0d679SMarcel Telka 
2806*a9685eaaSMarcel Telka 				if (in_access_list(cln, al) > 0) {
28075cb0d679SMarcel Telka 					*srv_uid = srv;
28085cb0d679SMarcel Telka 					perm |= NFSAUTH_UIDMAP;
280989621fe1SMarcel Telka 
281089621fe1SMarcel Telka 					if (perm & NFSAUTH_GROUPS) {
281189621fe1SMarcel Telka 						free(*srv_gids);
281289621fe1SMarcel Telka 						*srv_gids = NULL;
281389621fe1SMarcel Telka 						*srv_ngids = 0;
281489621fe1SMarcel Telka 						perm &= ~NFSAUTH_GROUPS;
281589621fe1SMarcel Telka 					}
281689621fe1SMarcel Telka 
28175cb0d679SMarcel Telka 					break;
28185cb0d679SMarcel Telka 				}
28195cb0d679SMarcel Telka 			}
28205cb0d679SMarcel Telka 
28215cb0d679SMarcel Telka 			break;
28225cb0d679SMarcel Telka 		}
28235cb0d679SMarcel Telka 
28245cb0d679SMarcel Telka 		case OPT_GIDMAP: {
28255cb0d679SMarcel Telka 			char *c;
28265cb0d679SMarcel Telka 			char *n;
28275cb0d679SMarcel Telka 
28285cb0d679SMarcel Telka 			/*
28295cb0d679SMarcel Telka 			 * The gidmap is supported for AUTH_SYS only.
28305cb0d679SMarcel Telka 			 */
28315cb0d679SMarcel Telka 			if (flavor != AUTH_SYS)
28325cb0d679SMarcel Telka 				break;
28335cb0d679SMarcel Telka 
28345cb0d679SMarcel Telka 			if (!match || perm & NFSAUTH_GIDMAP || map_deny)
28355cb0d679SMarcel Telka 				break;
28365cb0d679SMarcel Telka 
28375cb0d679SMarcel Telka 			for (c = val; c != NULL; c = n) {
28385cb0d679SMarcel Telka 				char *s;
28395cb0d679SMarcel Telka 				char *al;
28405cb0d679SMarcel Telka 				gid_t srv;
28415cb0d679SMarcel Telka 
28425cb0d679SMarcel Telka 				n = strchr(c, '~');
28435cb0d679SMarcel Telka 				if (n != NULL)
28445cb0d679SMarcel Telka 					*n++ = '\0';
28455cb0d679SMarcel Telka 
28465cb0d679SMarcel Telka 				s = strchr(c, ':');
28475cb0d679SMarcel Telka 				if (s != NULL) {
28485cb0d679SMarcel Telka 					*s++ = '\0';
28495cb0d679SMarcel Telka 					al = strchr(s, ':');
28505cb0d679SMarcel Telka 					if (al != NULL)
28515cb0d679SMarcel Telka 						*al++ = '\0';
28525cb0d679SMarcel Telka 				}
28535cb0d679SMarcel Telka 
28545cb0d679SMarcel Telka 				if (s == NULL || al == NULL)
28555cb0d679SMarcel Telka 					break;
28565cb0d679SMarcel Telka 
28575cb0d679SMarcel Telka 				if (*c == '\0') {
28585cb0d679SMarcel Telka 					if (clnt_gid != (gid_t)-1)
28595cb0d679SMarcel Telka 						continue;
28605cb0d679SMarcel Telka 				} else if (strcmp(c, "*") != 0) {
28615cb0d679SMarcel Telka 					gid_t clnt;
28625cb0d679SMarcel Telka 
28635cb0d679SMarcel Telka 					if (!get_gid(c, &clnt))
28645cb0d679SMarcel Telka 						continue;
28655cb0d679SMarcel Telka 
28665cb0d679SMarcel Telka 					if (clnt_gid != clnt)
28675cb0d679SMarcel Telka 						continue;
28685cb0d679SMarcel Telka 				}
28695cb0d679SMarcel Telka 
28705cb0d679SMarcel Telka 				if (*s == '\0')
28715cb0d679SMarcel Telka 					srv = UID_NOBODY;
28725cb0d679SMarcel Telka 				else if (!get_gid(s, &srv))
28735cb0d679SMarcel Telka 					continue;
28745cb0d679SMarcel Telka 				else if (srv == (gid_t)-1) {
28755cb0d679SMarcel Telka 					map_deny = B_TRUE;
28765cb0d679SMarcel Telka 					break;
28775cb0d679SMarcel Telka 				}
28785cb0d679SMarcel Telka 
2879*a9685eaaSMarcel Telka 				if (in_access_list(cln, al) > 0) {
28805cb0d679SMarcel Telka 					*srv_gid = srv;
28815cb0d679SMarcel Telka 					perm |= NFSAUTH_GIDMAP;
288289621fe1SMarcel Telka 
288389621fe1SMarcel Telka 					if (perm & NFSAUTH_GROUPS) {
288489621fe1SMarcel Telka 						free(*srv_gids);
288589621fe1SMarcel Telka 						*srv_gids = NULL;
288689621fe1SMarcel Telka 						*srv_ngids = 0;
288789621fe1SMarcel Telka 						perm &= ~NFSAUTH_GROUPS;
288889621fe1SMarcel Telka 					}
288989621fe1SMarcel Telka 
28905cb0d679SMarcel Telka 					break;
28915cb0d679SMarcel Telka 				}
28925cb0d679SMarcel Telka 			}
28935cb0d679SMarcel Telka 
28945cb0d679SMarcel Telka 			break;
28955cb0d679SMarcel Telka 		}
28965cb0d679SMarcel Telka 
28975cb0d679SMarcel Telka 		default:
28985cb0d679SMarcel Telka 			break;
28997c478bd9Sstevel@tonic-gate 		}
29007c478bd9Sstevel@tonic-gate 	}
29017c478bd9Sstevel@tonic-gate 
29027c478bd9Sstevel@tonic-gate done:
29035cb0d679SMarcel Telka 	if (perm & NFSAUTH_ROOT) {
29045cb0d679SMarcel Telka 		*srv_uid = 0;
29055cb0d679SMarcel Telka 		*srv_gid = 0;
29065cb0d679SMarcel Telka 	}
29075cb0d679SMarcel Telka 
29085cb0d679SMarcel Telka 	if (map_deny)
29095cb0d679SMarcel Telka 		perm |= NFSAUTH_DENIED;
29105cb0d679SMarcel Telka 
29115cb0d679SMarcel Telka 	if (!(perm & NFSAUTH_UIDMAP))
29125cb0d679SMarcel Telka 		*srv_uid = clnt_uid;
29135cb0d679SMarcel Telka 	if (!(perm & NFSAUTH_GIDMAP))
29145cb0d679SMarcel Telka 		*srv_gid = clnt_gid;
29155cb0d679SMarcel Telka 
29167c478bd9Sstevel@tonic-gate 	/*
29177c478bd9Sstevel@tonic-gate 	 * If no match then set the perm accordingly
29187c478bd9Sstevel@tonic-gate 	 */
29195cb0d679SMarcel Telka 	if (!match || perm & NFSAUTH_DENIED) {
29205cb0d679SMarcel Telka 		free(opts);
29217c478bd9Sstevel@tonic-gate 		return (NFSAUTH_DENIED);
29225cb0d679SMarcel Telka 	}
29237c478bd9Sstevel@tonic-gate 
29247c478bd9Sstevel@tonic-gate 	if (list) {
29257c478bd9Sstevel@tonic-gate 		/*
29267c478bd9Sstevel@tonic-gate 		 * If the client doesn't match an "ro" or "rw" list then
29277c478bd9Sstevel@tonic-gate 		 * check if it may have access by using a different flavor.
29287c478bd9Sstevel@tonic-gate 		 * If so, return NFSAUTH_WRONGSEC.
29297c478bd9Sstevel@tonic-gate 		 * If not, return NFSAUTH_DENIED.
29307c478bd9Sstevel@tonic-gate 		 */
29317c478bd9Sstevel@tonic-gate 		if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) {
2932*a9685eaaSMarcel Telka 			if (is_wrongsec(sh, cln, flavor))
29337c478bd9Sstevel@tonic-gate 				perm |= NFSAUTH_WRONGSEC;
29347c478bd9Sstevel@tonic-gate 			else
29357c478bd9Sstevel@tonic-gate 				perm |= NFSAUTH_DENIED;
29367c478bd9Sstevel@tonic-gate 		}
29377c478bd9Sstevel@tonic-gate 	} else {
29387c478bd9Sstevel@tonic-gate 		/*
29397c478bd9Sstevel@tonic-gate 		 * The client matched a flavor entry that
29407c478bd9Sstevel@tonic-gate 		 * has no explicit "rw" or "ro" determination.
29417c478bd9Sstevel@tonic-gate 		 * Make sure it defaults to "rw".
29427c478bd9Sstevel@tonic-gate 		 */
29437c478bd9Sstevel@tonic-gate 		perm |= NFSAUTH_RW;
29447c478bd9Sstevel@tonic-gate 	}
29457c478bd9Sstevel@tonic-gate 
29467c478bd9Sstevel@tonic-gate 	/*
29477c478bd9Sstevel@tonic-gate 	 * The client may show up in both ro= and rw=
29487c478bd9Sstevel@tonic-gate 	 * lists.  If so, then turn off the RO access
29497c478bd9Sstevel@tonic-gate 	 * bit leaving RW access.
29507c478bd9Sstevel@tonic-gate 	 */
29517c478bd9Sstevel@tonic-gate 	if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) {
29527c478bd9Sstevel@tonic-gate 		/*
29537c478bd9Sstevel@tonic-gate 		 * Logically cover all permutations of rw=,ro=.
29547c478bd9Sstevel@tonic-gate 		 * In the case where, rw,ro=<host> we would like
29557c478bd9Sstevel@tonic-gate 		 * to remove RW access for the host.  In all other cases
29567c478bd9Sstevel@tonic-gate 		 * RW wins the precedence battle.
29577c478bd9Sstevel@tonic-gate 		 */
29587c478bd9Sstevel@tonic-gate 		if (!rw_val && ro_val) {
29597c478bd9Sstevel@tonic-gate 			perm &= ~(NFSAUTH_RW);
29607c478bd9Sstevel@tonic-gate 		} else {
29617c478bd9Sstevel@tonic-gate 			perm &= ~(NFSAUTH_RO);
29627c478bd9Sstevel@tonic-gate 		}
29637c478bd9Sstevel@tonic-gate 	}
29647c478bd9Sstevel@tonic-gate 
29657c478bd9Sstevel@tonic-gate 	free(opts);
29667c478bd9Sstevel@tonic-gate 
29677c478bd9Sstevel@tonic-gate 	return (perm);
29687c478bd9Sstevel@tonic-gate }
29697c478bd9Sstevel@tonic-gate 
29707c478bd9Sstevel@tonic-gate void
29717c478bd9Sstevel@tonic-gate check_sharetab()
29727c478bd9Sstevel@tonic-gate {
29737c478bd9Sstevel@tonic-gate 	FILE *f;
29747c478bd9Sstevel@tonic-gate 	struct stat st;
29757c478bd9Sstevel@tonic-gate 	static timestruc_t last_sharetab_time;
29767c478bd9Sstevel@tonic-gate 	timestruc_t prev_sharetab_time;
29774a508a79SThomas Haynes 	share_t *sh;
29787c478bd9Sstevel@tonic-gate 	struct sh_list *shp, *shp_prev;
29797c478bd9Sstevel@tonic-gate 	int res, c = 0;
29807c478bd9Sstevel@tonic-gate 
29817c478bd9Sstevel@tonic-gate 	/*
29827c478bd9Sstevel@tonic-gate 	 *  read in /etc/dfs/sharetab if it has changed
29837c478bd9Sstevel@tonic-gate 	 */
29847c478bd9Sstevel@tonic-gate 	if (stat(SHARETAB, &st) != 0) {
29857c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB);
29867c478bd9Sstevel@tonic-gate 		return;
29877c478bd9Sstevel@tonic-gate 	}
29887c478bd9Sstevel@tonic-gate 
29897c478bd9Sstevel@tonic-gate 	if (st.st_mtim.tv_sec == last_sharetab_time.tv_sec &&
29907c478bd9Sstevel@tonic-gate 	    st.st_mtim.tv_nsec == last_sharetab_time.tv_nsec) {
29917c478bd9Sstevel@tonic-gate 		/*
29927c478bd9Sstevel@tonic-gate 		 * No change.
29937c478bd9Sstevel@tonic-gate 		 */
29947c478bd9Sstevel@tonic-gate 		return;
29957c478bd9Sstevel@tonic-gate 	}
29967c478bd9Sstevel@tonic-gate 
29977c478bd9Sstevel@tonic-gate 	/*
29987c478bd9Sstevel@tonic-gate 	 * Remember the mod time, then after getting the
29997c478bd9Sstevel@tonic-gate 	 * write lock check again.  If another thread
30007c478bd9Sstevel@tonic-gate 	 * already did the update, then there's no
30017c478bd9Sstevel@tonic-gate 	 * work to do.
30027c478bd9Sstevel@tonic-gate 	 */
30037c478bd9Sstevel@tonic-gate 	prev_sharetab_time = last_sharetab_time;
30047c478bd9Sstevel@tonic-gate 
30057c478bd9Sstevel@tonic-gate 	(void) rw_wrlock(&sharetab_lock);
30067c478bd9Sstevel@tonic-gate 
30077c478bd9Sstevel@tonic-gate 	if (prev_sharetab_time.tv_sec != last_sharetab_time.tv_sec ||
30087c478bd9Sstevel@tonic-gate 	    prev_sharetab_time.tv_nsec != last_sharetab_time.tv_nsec) {
30097c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&sharetab_lock);
30107c478bd9Sstevel@tonic-gate 		return;
30117c478bd9Sstevel@tonic-gate 	}
30127c478bd9Sstevel@tonic-gate 
3013a237e38eSth199096 	/*
3014a237e38eSth199096 	 * Note that since the sharetab is now in memory
3015a237e38eSth199096 	 * and a snapshot is taken, we no longer have to
3016a237e38eSth199096 	 * lock the file.
3017a237e38eSth199096 	 */
3018a237e38eSth199096 	f = fopen(SHARETAB, "r");
30197c478bd9Sstevel@tonic-gate 	if (f == NULL) {
30207c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "Cannot open %s: %m", SHARETAB);
30217c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&sharetab_lock);
30227c478bd9Sstevel@tonic-gate 		return;
30237c478bd9Sstevel@tonic-gate 	}
30247c478bd9Sstevel@tonic-gate 
30257c478bd9Sstevel@tonic-gate 	/*
30267c478bd9Sstevel@tonic-gate 	 * Once we are sure /etc/dfs/sharetab has been
30277c478bd9Sstevel@tonic-gate 	 * modified, flush netgroup cache entries.
30287c478bd9Sstevel@tonic-gate 	 */
30297c478bd9Sstevel@tonic-gate 	netgrp_cache_flush();
30307c478bd9Sstevel@tonic-gate 
30317c478bd9Sstevel@tonic-gate 	sh_free(share_list);			/* free old list */
30327c478bd9Sstevel@tonic-gate 	share_list = NULL;
30337c478bd9Sstevel@tonic-gate 
30347c478bd9Sstevel@tonic-gate 	while ((res = getshare(f, &sh)) > 0) {
30357c478bd9Sstevel@tonic-gate 		c++;
30367c478bd9Sstevel@tonic-gate 		if (strcmp(sh->sh_fstype, "nfs") != 0)
30377c478bd9Sstevel@tonic-gate 			continue;
30387c478bd9Sstevel@tonic-gate 
30397c478bd9Sstevel@tonic-gate 		shp = malloc(sizeof (*shp));
30407c478bd9Sstevel@tonic-gate 		if (shp == NULL)
30417c478bd9Sstevel@tonic-gate 			goto alloc_failed;
30427c478bd9Sstevel@tonic-gate 		if (share_list == NULL)
30437c478bd9Sstevel@tonic-gate 			share_list = shp;
30447c478bd9Sstevel@tonic-gate 		else
30457c478bd9Sstevel@tonic-gate 			/* LINTED not used before set */
30467c478bd9Sstevel@tonic-gate 			shp_prev->shl_next = shp;
30477c478bd9Sstevel@tonic-gate 		shp_prev = shp;
30487c478bd9Sstevel@tonic-gate 		shp->shl_next = NULL;
30497c478bd9Sstevel@tonic-gate 		shp->shl_sh = sharedup(sh);
30507c478bd9Sstevel@tonic-gate 		if (shp->shl_sh == NULL)
30517c478bd9Sstevel@tonic-gate 			goto alloc_failed;
30527c478bd9Sstevel@tonic-gate 	}
30534a508a79SThomas Haynes 
30547c478bd9Sstevel@tonic-gate 	if (res < 0)
30557c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "%s: invalid at line %d\n",
30567c478bd9Sstevel@tonic-gate 		    SHARETAB, c + 1);
30577c478bd9Sstevel@tonic-gate 
30587c478bd9Sstevel@tonic-gate 	if (stat(SHARETAB, &st) != 0) {
30597c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB);
306062a1b812Sth199096 		(void) fclose(f);
30617c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&sharetab_lock);
30627c478bd9Sstevel@tonic-gate 		return;
30637c478bd9Sstevel@tonic-gate 	}
30644a508a79SThomas Haynes 
30657c478bd9Sstevel@tonic-gate 	last_sharetab_time = st.st_mtim;
30667c478bd9Sstevel@tonic-gate 	(void) fclose(f);
30677c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&sharetab_lock);
30684a508a79SThomas Haynes 
30697c478bd9Sstevel@tonic-gate 	return;
30707c478bd9Sstevel@tonic-gate 
30717c478bd9Sstevel@tonic-gate alloc_failed:
30724a508a79SThomas Haynes 
30737c478bd9Sstevel@tonic-gate 	syslog(LOG_ERR, "check_sharetab: no memory");
30747c478bd9Sstevel@tonic-gate 	sh_free(share_list);
30757c478bd9Sstevel@tonic-gate 	share_list = NULL;
30767c478bd9Sstevel@tonic-gate 	(void) fclose(f);
30777c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&sharetab_lock);
30787c478bd9Sstevel@tonic-gate }
30797c478bd9Sstevel@tonic-gate 
30807c478bd9Sstevel@tonic-gate static void
30817c478bd9Sstevel@tonic-gate sh_free(struct sh_list *shp)
30827c478bd9Sstevel@tonic-gate {
308354d34259SMarcel Telka 	struct sh_list *next;
30847c478bd9Sstevel@tonic-gate 
30857c478bd9Sstevel@tonic-gate 	while (shp) {
30867c478bd9Sstevel@tonic-gate 		sharefree(shp->shl_sh);
30877c478bd9Sstevel@tonic-gate 		next = shp->shl_next;
30887c478bd9Sstevel@tonic-gate 		free(shp);
30897c478bd9Sstevel@tonic-gate 		shp = next;
30907c478bd9Sstevel@tonic-gate 	}
30917c478bd9Sstevel@tonic-gate }
30927c478bd9Sstevel@tonic-gate 
30937c478bd9Sstevel@tonic-gate 
30947c478bd9Sstevel@tonic-gate /*
30957c478bd9Sstevel@tonic-gate  * Remove an entry from mounted list
30967c478bd9Sstevel@tonic-gate  */
30977c478bd9Sstevel@tonic-gate static void
30987c478bd9Sstevel@tonic-gate umount(struct svc_req *rqstp)
30997c478bd9Sstevel@tonic-gate {
31007c478bd9Sstevel@tonic-gate 	char *host, *path, *remove_path;
31017c478bd9Sstevel@tonic-gate 	char rpath[MAXPATHLEN];
31027c478bd9Sstevel@tonic-gate 	SVCXPRT *transp;
3103*a9685eaaSMarcel Telka 	struct cln cln;
31047c478bd9Sstevel@tonic-gate 
31057c478bd9Sstevel@tonic-gate 	transp = rqstp->rq_xprt;
31067c478bd9Sstevel@tonic-gate 	path = NULL;
31077c478bd9Sstevel@tonic-gate 	if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
31087c478bd9Sstevel@tonic-gate 		svcerr_decode(transp);
31097c478bd9Sstevel@tonic-gate 		return;
31107c478bd9Sstevel@tonic-gate 	}
3111*a9685eaaSMarcel Telka 
3112*a9685eaaSMarcel Telka 	cln_init(&cln, transp);
3113*a9685eaaSMarcel Telka 
31147c478bd9Sstevel@tonic-gate 	errno = 0;
31157c478bd9Sstevel@tonic-gate 	if (!svc_sendreply(transp, xdr_void, (char *)NULL))
3116*a9685eaaSMarcel Telka 		log_cant_reply_cln(&cln);
31177c478bd9Sstevel@tonic-gate 
3118*a9685eaaSMarcel Telka 	host = cln_gethost(&cln);
3119*a9685eaaSMarcel Telka 	if (host == NULL) {
31207c478bd9Sstevel@tonic-gate 		/*
31217c478bd9Sstevel@tonic-gate 		 * Without the hostname we can't do audit or delete
31227c478bd9Sstevel@tonic-gate 		 * this host from the mount entries.
31237c478bd9Sstevel@tonic-gate 		 */
31247c478bd9Sstevel@tonic-gate 		svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
31257c478bd9Sstevel@tonic-gate 		return;
31267c478bd9Sstevel@tonic-gate 	}
31277c478bd9Sstevel@tonic-gate 
31287c478bd9Sstevel@tonic-gate 	if (verbose)
31297c478bd9Sstevel@tonic-gate 		syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path);
31307c478bd9Sstevel@tonic-gate 
31317c478bd9Sstevel@tonic-gate 	audit_mountd_umount(host, path);
31327c478bd9Sstevel@tonic-gate 
31337c478bd9Sstevel@tonic-gate 	remove_path = rpath;	/* assume we will use the cannonical path */
31347c478bd9Sstevel@tonic-gate 	if (realpath(path, rpath) == NULL) {
31357c478bd9Sstevel@tonic-gate 		if (verbose)
31367c478bd9Sstevel@tonic-gate 			syslog(LOG_WARNING, "UNMOUNT: realpath: %s: %m ", path);
31377c478bd9Sstevel@tonic-gate 		remove_path = path;	/* use path provided instead */
31387c478bd9Sstevel@tonic-gate 	}
31397c478bd9Sstevel@tonic-gate 
31407c478bd9Sstevel@tonic-gate 	mntlist_delete(host, remove_path);	/* remove from mount list */
31417c478bd9Sstevel@tonic-gate 
3142*a9685eaaSMarcel Telka 	cln_fini(&cln);
3143*a9685eaaSMarcel Telka 
31447c478bd9Sstevel@tonic-gate 	svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
31457c478bd9Sstevel@tonic-gate }
31467c478bd9Sstevel@tonic-gate 
31477c478bd9Sstevel@tonic-gate /*
31487c478bd9Sstevel@tonic-gate  * Remove all entries for one machine from mounted list
31497c478bd9Sstevel@tonic-gate  */
31507c478bd9Sstevel@tonic-gate static void
31517c478bd9Sstevel@tonic-gate umountall(struct svc_req *rqstp)
31527c478bd9Sstevel@tonic-gate {
31537c478bd9Sstevel@tonic-gate 	SVCXPRT *transp;
31547c478bd9Sstevel@tonic-gate 	char *host;
3155*a9685eaaSMarcel Telka 	struct cln cln;
31567c478bd9Sstevel@tonic-gate 
31577c478bd9Sstevel@tonic-gate 	transp = rqstp->rq_xprt;
31587c478bd9Sstevel@tonic-gate 	if (!svc_getargs(transp, xdr_void, NULL)) {
31597c478bd9Sstevel@tonic-gate 		svcerr_decode(transp);
31607c478bd9Sstevel@tonic-gate 		return;
31617c478bd9Sstevel@tonic-gate 	}
31627c478bd9Sstevel@tonic-gate 	/*
31637c478bd9Sstevel@tonic-gate 	 * We assume that this call is asynchronous and made via rpcbind
31647c478bd9Sstevel@tonic-gate 	 * callit routine.  Therefore return control immediately. The error
31657c478bd9Sstevel@tonic-gate 	 * causes rpcbind to remain silent, as opposed to every machine
31667c478bd9Sstevel@tonic-gate 	 * on the net blasting the requester with a response.
31677c478bd9Sstevel@tonic-gate 	 */
31687c478bd9Sstevel@tonic-gate 	svcerr_systemerr(transp);
3169*a9685eaaSMarcel Telka 
3170*a9685eaaSMarcel Telka 	cln_init(&cln, transp);
3171*a9685eaaSMarcel Telka 
3172*a9685eaaSMarcel Telka 	host = cln_gethost(&cln);
3173*a9685eaaSMarcel Telka 	if (host == NULL) {
31747c478bd9Sstevel@tonic-gate 		/* Can't do anything without the name of the client */
31757c478bd9Sstevel@tonic-gate 		return;
31767c478bd9Sstevel@tonic-gate 	}
31777c478bd9Sstevel@tonic-gate 
31787c478bd9Sstevel@tonic-gate 	/*
31797c478bd9Sstevel@tonic-gate 	 * Remove all hosts entries from mount list
31807c478bd9Sstevel@tonic-gate 	 */
31817c478bd9Sstevel@tonic-gate 	mntlist_delete_all(host);
31827c478bd9Sstevel@tonic-gate 
31837c478bd9Sstevel@tonic-gate 	if (verbose)
31847c478bd9Sstevel@tonic-gate 		syslog(LOG_NOTICE, "UNMOUNTALL: from %s", host);
31857c478bd9Sstevel@tonic-gate 
3186*a9685eaaSMarcel Telka 	cln_fini(&cln);
31877c478bd9Sstevel@tonic-gate }
31887c478bd9Sstevel@tonic-gate 
31897c478bd9Sstevel@tonic-gate void *
31907c478bd9Sstevel@tonic-gate exmalloc(size_t size)
31917c478bd9Sstevel@tonic-gate {
31927c478bd9Sstevel@tonic-gate 	void *ret;
31937c478bd9Sstevel@tonic-gate 
31947c478bd9Sstevel@tonic-gate 	if ((ret = malloc(size)) == NULL) {
31957c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "Out of memory");
31967c478bd9Sstevel@tonic-gate 		exit(1);
31977c478bd9Sstevel@tonic-gate 	}
31987c478bd9Sstevel@tonic-gate 	return (ret);
31997c478bd9Sstevel@tonic-gate }
32007c478bd9Sstevel@tonic-gate 
320103986916Sjarrett static tsol_tpent_t *
320203986916Sjarrett get_client_template(struct sockaddr *sock)
320303986916Sjarrett {
320403986916Sjarrett 	in_addr_t	v4client;
320503986916Sjarrett 	in6_addr_t	v6client;
320603986916Sjarrett 	char		v4_addr[INET_ADDRSTRLEN];
320703986916Sjarrett 	char		v6_addr[INET6_ADDRSTRLEN];
320803986916Sjarrett 	tsol_rhent_t	*rh;
320903986916Sjarrett 	tsol_tpent_t	*tp;
321003986916Sjarrett 
321103986916Sjarrett 	switch (sock->sa_family) {
321203986916Sjarrett 	case AF_INET:
321303986916Sjarrett 		v4client = ((struct sockaddr_in *)(void *)sock)->
321403986916Sjarrett 		    sin_addr.s_addr;
321503986916Sjarrett 		if (inet_ntop(AF_INET, &v4client, v4_addr, INET_ADDRSTRLEN) ==
321603986916Sjarrett 		    NULL)
321703986916Sjarrett 			return (NULL);
321803986916Sjarrett 		rh = tsol_getrhbyaddr(v4_addr, sizeof (v4_addr), AF_INET);
321903986916Sjarrett 		if (rh == NULL)
322003986916Sjarrett 			return (NULL);
322103986916Sjarrett 		tp = tsol_gettpbyname(rh->rh_template);
322203986916Sjarrett 		tsol_freerhent(rh);
322303986916Sjarrett 		return (tp);
322403986916Sjarrett 		break;
322503986916Sjarrett 	case AF_INET6:
322603986916Sjarrett 		v6client = ((struct sockaddr_in6 *)(void *)sock)->sin6_addr;
322703986916Sjarrett 		if (inet_ntop(AF_INET6, &v6client, v6_addr, INET6_ADDRSTRLEN) ==
322803986916Sjarrett 		    NULL)
322903986916Sjarrett 			return (NULL);
323003986916Sjarrett 		rh = tsol_getrhbyaddr(v6_addr, sizeof (v6_addr), AF_INET6);
323103986916Sjarrett 		if (rh == NULL)
323203986916Sjarrett 			return (NULL);
323303986916Sjarrett 		tp = tsol_gettpbyname(rh->rh_template);
323403986916Sjarrett 		tsol_freerhent(rh);
323503986916Sjarrett 		return (tp);
323603986916Sjarrett 		break;
323703986916Sjarrett 	default:
323803986916Sjarrett 		return (NULL);
323903986916Sjarrett 	}
324003986916Sjarrett }
3241