xref: /illumos-gate/usr/src/uts/common/rpc/sec/sec_clnt.c (revision 52056d7b)
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
5b9238976Sth  * Common Development and Distribution License (the "License").
6b9238976Sth  * 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
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #include <sys/param.h>
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/systm.h>
287c478bd9Sstevel@tonic-gate #include <sys/cred.h>
297c478bd9Sstevel@tonic-gate #include <sys/proc.h>
307c478bd9Sstevel@tonic-gate #include <sys/user.h>
317c478bd9Sstevel@tonic-gate #include <sys/time.h>
327c478bd9Sstevel@tonic-gate #include <sys/buf.h>
337c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
347c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
357c478bd9Sstevel@tonic-gate #include <sys/socket.h>
367c478bd9Sstevel@tonic-gate #include <sys/stat.h>
377c478bd9Sstevel@tonic-gate #include <sys/uio.h>
387c478bd9Sstevel@tonic-gate #include <sys/tiuser.h>
397c478bd9Sstevel@tonic-gate #include <sys/swap.h>
407c478bd9Sstevel@tonic-gate #include <sys/errno.h>
417c478bd9Sstevel@tonic-gate #include <sys/debug.h>
427c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
437c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
447c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
457c478bd9Sstevel@tonic-gate #include <sys/vtrace.h>
467c478bd9Sstevel@tonic-gate #include <sys/session.h>
477c478bd9Sstevel@tonic-gate #include <sys/dnlc.h>
487c478bd9Sstevel@tonic-gate #include <sys/bitmap.h>
497c478bd9Sstevel@tonic-gate #include <sys/thread.h>
507c478bd9Sstevel@tonic-gate #include <sys/policy.h>
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #include <netinet/in.h>
537c478bd9Sstevel@tonic-gate #include <rpc/types.h>
547c478bd9Sstevel@tonic-gate #include <rpc/xdr.h>
557c478bd9Sstevel@tonic-gate #include <rpc/auth.h>
567c478bd9Sstevel@tonic-gate #include <rpc/auth_des.h>	/* for authdes_create() */
577c478bd9Sstevel@tonic-gate #include <rpc/clnt.h>
587c478bd9Sstevel@tonic-gate #include <rpc/rpcsec_gss.h>
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate #define	MAXCLIENTS	16
61*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States 
62*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States /*
63*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States  * Currently there is no maximum length defined withing the gss
64*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States  * specification. Because of security issues the maximum gss
65*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States  * authentication length is checked to be under the MAXAUTHLEN
66*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States  * defined below. The value was chosen because it will be a safe
67*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States  * maximum value for some time.  Currently lengths are generally
68*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States  * under the 16 byte length
69*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States  */
70*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States #define	MINAUTHLEN	1	/* minimum gss authentication length */
71*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States #define	MAXAUTHLEN	65535	/* maximum gss authentication length */
727c478bd9Sstevel@tonic-gate static int clnt_authdes_cachesz = 64;
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate static uint_t authdes_win = 5*60;  /* 5 minutes -- should be mount option */
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate struct kmem_cache *authkern_cache;
777c478bd9Sstevel@tonic-gate 
7833f285aeSVallish Vaidyeshwara struct kmem_cache *authnone_cache;
7933f285aeSVallish Vaidyeshwara 
807c478bd9Sstevel@tonic-gate struct kmem_cache *authloopback_cache;
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate static struct desauthent {
837c478bd9Sstevel@tonic-gate 	struct	sec_data *da_data;
847c478bd9Sstevel@tonic-gate 	uid_t da_uid;
857c478bd9Sstevel@tonic-gate 	zoneid_t da_zoneid;
867c478bd9Sstevel@tonic-gate 	short da_inuse;
877c478bd9Sstevel@tonic-gate 	AUTH *da_auth;
887c478bd9Sstevel@tonic-gate } *desauthtab;
897c478bd9Sstevel@tonic-gate static int nextdesvictim;
907c478bd9Sstevel@tonic-gate static kmutex_t desauthtab_lock;	/* Lock to protect DES auth cache */
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /* RPC stuff */
937c478bd9Sstevel@tonic-gate kmutex_t authdes_ops_lock;   /* auth_ops initialization in authdes_ops() */
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate static void  purge_authtab(struct sec_data *);
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate /* Zone stuff */
987c478bd9Sstevel@tonic-gate zone_key_t auth_zone_key;
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate /*
1017c478bd9Sstevel@tonic-gate  *  Load RPCSEC_GSS specific data from user space to kernel space.
1027c478bd9Sstevel@tonic-gate  */
1037c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1047c478bd9Sstevel@tonic-gate static int
gss_clnt_loadinfo(caddr_t usrdata,caddr_t * kdata,model_t model)1057c478bd9Sstevel@tonic-gate gss_clnt_loadinfo(caddr_t usrdata, caddr_t *kdata, model_t model)
1067c478bd9Sstevel@tonic-gate {
1077c478bd9Sstevel@tonic-gate 	struct gss_clnt_data *data;
1087c478bd9Sstevel@tonic-gate 	caddr_t	elements;
1097c478bd9Sstevel@tonic-gate 	int error = 0;
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	/* map opaque data to gss specific structure */
1127c478bd9Sstevel@tonic-gate 	data = kmem_alloc(sizeof (*data), KM_SLEEP);
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1157c478bd9Sstevel@tonic-gate 	if (model != DATAMODEL_NATIVE) {
1167c478bd9Sstevel@tonic-gate 		struct gss_clnt_data32 gd32;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 		if (copyin(usrdata, &gd32, sizeof (gd32)) == -1) {
1197c478bd9Sstevel@tonic-gate 			error = EFAULT;
1207c478bd9Sstevel@tonic-gate 		} else {
1217c478bd9Sstevel@tonic-gate 			data->mechanism.length = gd32.mechanism.length;
1227c478bd9Sstevel@tonic-gate 			data->mechanism.elements =
123b9238976Sth 			    (caddr_t)(uintptr_t)gd32.mechanism.elements;
1247c478bd9Sstevel@tonic-gate 			data->service = gd32.service;
1257c478bd9Sstevel@tonic-gate 			bcopy(gd32.uname, data->uname, sizeof (gd32.uname));
1267c478bd9Sstevel@tonic-gate 			bcopy(gd32.inst, data->inst, sizeof (gd32.inst));
1277c478bd9Sstevel@tonic-gate 			bcopy(gd32.realm, data->realm, sizeof (gd32.realm));
1287c478bd9Sstevel@tonic-gate 			data->qop = gd32.qop;
1297c478bd9Sstevel@tonic-gate 		}
1307c478bd9Sstevel@tonic-gate 	} else
1317c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
1327c478bd9Sstevel@tonic-gate 	if (copyin(usrdata, data, sizeof (*data)))
1337c478bd9Sstevel@tonic-gate 		error = EFAULT;
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	if (error == 0) {
136*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States 		if (data->mechanism.length >= MINAUTHLEN &&
137*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States 		    data->mechanism.length <= MAXAUTHLEN) {
1387c478bd9Sstevel@tonic-gate 			elements = kmem_alloc(data->mechanism.length, KM_SLEEP);
1397c478bd9Sstevel@tonic-gate 			if (!(copyin(data->mechanism.elements, elements,
1407c478bd9Sstevel@tonic-gate 			    data->mechanism.length))) {
1417c478bd9Sstevel@tonic-gate 				data->mechanism.elements = elements;
1427c478bd9Sstevel@tonic-gate 				*kdata = (caddr_t)data;
1437c478bd9Sstevel@tonic-gate 				return (0);
144*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States 			}
145*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States 			kmem_free(elements, data->mechanism.length);
1467c478bd9Sstevel@tonic-gate 		}
1477c478bd9Sstevel@tonic-gate 	}
148*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States 	*kdata = NULL;
149*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States 	kmem_free(data, sizeof (*data));
150*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States 
1517c478bd9Sstevel@tonic-gate 	return (EFAULT);
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate /*
1567c478bd9Sstevel@tonic-gate  *  Load AUTH_DES specific data from user space to kernel space.
1577c478bd9Sstevel@tonic-gate  */
1587c478bd9Sstevel@tonic-gate /*ARGSUSED2*/
1597c478bd9Sstevel@tonic-gate int
dh_k4_clnt_loadinfo(caddr_t usrdata,caddr_t * kdata,model_t model)1607c478bd9Sstevel@tonic-gate dh_k4_clnt_loadinfo(caddr_t usrdata, caddr_t *kdata, model_t model)
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate 	size_t nlen;
1637c478bd9Sstevel@tonic-gate 	int error = 0;
1647c478bd9Sstevel@tonic-gate 	char *userbufptr;
1657c478bd9Sstevel@tonic-gate 	dh_k4_clntdata_t *data;
1667c478bd9Sstevel@tonic-gate 	char netname[MAXNETNAMELEN+1];
1677c478bd9Sstevel@tonic-gate 	struct netbuf *syncaddr;
1687c478bd9Sstevel@tonic-gate 	struct knetconfig *knconf;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	/* map opaque data to des specific strucutre */
1717c478bd9Sstevel@tonic-gate 	data = kmem_alloc(sizeof (*data), KM_SLEEP);
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1747c478bd9Sstevel@tonic-gate 	if (model != DATAMODEL_NATIVE) {
1757c478bd9Sstevel@tonic-gate 		struct des_clnt_data32 data32;
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 		if (copyin(usrdata, &data32, sizeof (data32)) == -1) {
1787c478bd9Sstevel@tonic-gate 			error = EFAULT;
1797c478bd9Sstevel@tonic-gate 		} else {
1807c478bd9Sstevel@tonic-gate 			data->syncaddr.maxlen = data32.syncaddr.maxlen;
1817c478bd9Sstevel@tonic-gate 			data->syncaddr.len = data32.syncaddr.len;
1827c478bd9Sstevel@tonic-gate 			data->syncaddr.buf =
1837c478bd9Sstevel@tonic-gate 			    (caddr_t)(uintptr_t)data32.syncaddr.buf;
1847c478bd9Sstevel@tonic-gate 			data->knconf =
1857c478bd9Sstevel@tonic-gate 			    (struct knetconfig *)(uintptr_t)data32.knconf;
1867c478bd9Sstevel@tonic-gate 			data->netname = (caddr_t)(uintptr_t)data32.netname;
1877c478bd9Sstevel@tonic-gate 			data->netnamelen = data32.netnamelen;
1887c478bd9Sstevel@tonic-gate 		}
1897c478bd9Sstevel@tonic-gate 	} else
1907c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
1917c478bd9Sstevel@tonic-gate 	if (copyin(usrdata, data, sizeof (*data)))
1927c478bd9Sstevel@tonic-gate 		error = EFAULT;
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	if (error == 0) {
1957c478bd9Sstevel@tonic-gate 		syncaddr = &data->syncaddr;
196*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States 		if (syncaddr->len < MINAUTHLEN || syncaddr->len > MAXAUTHLEN)
1977c478bd9Sstevel@tonic-gate 			error = EINVAL;
1987c478bd9Sstevel@tonic-gate 		else {
1997c478bd9Sstevel@tonic-gate 			userbufptr = syncaddr->buf;
200*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States 			syncaddr->buf = kmem_alloc(syncaddr->len, KM_SLEEP);
2017c478bd9Sstevel@tonic-gate 			syncaddr->maxlen = syncaddr->len;
2027c478bd9Sstevel@tonic-gate 			if (copyin(userbufptr, syncaddr->buf, syncaddr->len)) {
2037c478bd9Sstevel@tonic-gate 				kmem_free(syncaddr->buf, syncaddr->len);
2047c478bd9Sstevel@tonic-gate 				syncaddr->buf = NULL;
2057c478bd9Sstevel@tonic-gate 				error = EFAULT;
2067c478bd9Sstevel@tonic-gate 			} else {
2077c478bd9Sstevel@tonic-gate 				(void) copyinstr(data->netname, netname,
2087c478bd9Sstevel@tonic-gate 				    sizeof (netname), &nlen);
2097c478bd9Sstevel@tonic-gate 				if (nlen != 0) {
2107c478bd9Sstevel@tonic-gate 					data->netname =
2117c478bd9Sstevel@tonic-gate 					    kmem_alloc(nlen, KM_SLEEP);
2127c478bd9Sstevel@tonic-gate 					bcopy(netname, data->netname, nlen);
2137c478bd9Sstevel@tonic-gate 					data->netnamelen = (int)nlen;
2147c478bd9Sstevel@tonic-gate 				}
2157c478bd9Sstevel@tonic-gate 			}
2167c478bd9Sstevel@tonic-gate 		}
2177c478bd9Sstevel@tonic-gate 	}
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	if (!error) {
2207c478bd9Sstevel@tonic-gate 		/*
2217c478bd9Sstevel@tonic-gate 		 * Allocate space for a knetconfig structure and
2227c478bd9Sstevel@tonic-gate 		 * its strings and copy in from user-land.
2237c478bd9Sstevel@tonic-gate 		 */
2247c478bd9Sstevel@tonic-gate 		knconf = kmem_alloc(sizeof (*knconf), KM_SLEEP);
2257c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
2267c478bd9Sstevel@tonic-gate 		if (model != DATAMODEL_NATIVE) {
2277c478bd9Sstevel@tonic-gate 			struct knetconfig32 knconf32;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 			if (copyin(data->knconf, &knconf32,
2307c478bd9Sstevel@tonic-gate 			    sizeof (knconf32)) == -1) {
2317c478bd9Sstevel@tonic-gate 				kmem_free(knconf, sizeof (*knconf));
2327c478bd9Sstevel@tonic-gate 				kmem_free(syncaddr->buf, syncaddr->len);
2337c478bd9Sstevel@tonic-gate 				syncaddr->buf = NULL;
2347c478bd9Sstevel@tonic-gate 				kmem_free(data->netname, nlen);
2357c478bd9Sstevel@tonic-gate 				error = EFAULT;
2367c478bd9Sstevel@tonic-gate 			} else {
2377c478bd9Sstevel@tonic-gate 				knconf->knc_semantics = knconf32.knc_semantics;
2387c478bd9Sstevel@tonic-gate 				knconf->knc_protofmly =
2397c478bd9Sstevel@tonic-gate 				    (caddr_t)(uintptr_t)knconf32.knc_protofmly;
2407c478bd9Sstevel@tonic-gate 				knconf->knc_proto =
2417c478bd9Sstevel@tonic-gate 				    (caddr_t)(uintptr_t)knconf32.knc_proto;
2427c478bd9Sstevel@tonic-gate 				knconf->knc_rdev = expldev(knconf32.knc_rdev);
2437c478bd9Sstevel@tonic-gate 			}
2447c478bd9Sstevel@tonic-gate 		} else
2457c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
2467c478bd9Sstevel@tonic-gate 		if (copyin(data->knconf, knconf, sizeof (*knconf))) {
2477c478bd9Sstevel@tonic-gate 			kmem_free(knconf, sizeof (*knconf));
2487c478bd9Sstevel@tonic-gate 			kmem_free(syncaddr->buf, syncaddr->len);
2497c478bd9Sstevel@tonic-gate 			syncaddr->buf = NULL;
2507c478bd9Sstevel@tonic-gate 			kmem_free(data->netname, nlen);
2517c478bd9Sstevel@tonic-gate 			error = EFAULT;
2527c478bd9Sstevel@tonic-gate 		}
2537c478bd9Sstevel@tonic-gate 	}
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	if (!error) {
2567c478bd9Sstevel@tonic-gate 		size_t nmoved_tmp;
2577c478bd9Sstevel@tonic-gate 		char *p, *pf;
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 		pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
2607c478bd9Sstevel@tonic-gate 		p = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
2617c478bd9Sstevel@tonic-gate 		error = copyinstr(knconf->knc_protofmly, pf,
2627c478bd9Sstevel@tonic-gate 		    KNC_STRSIZE, &nmoved_tmp);
2637c478bd9Sstevel@tonic-gate 		if (error) {
2647c478bd9Sstevel@tonic-gate 			kmem_free(pf, KNC_STRSIZE);
2657c478bd9Sstevel@tonic-gate 			kmem_free(p, KNC_STRSIZE);
2667c478bd9Sstevel@tonic-gate 			kmem_free(knconf, sizeof (*knconf));
2677c478bd9Sstevel@tonic-gate 			kmem_free(syncaddr->buf, syncaddr->len);
2687c478bd9Sstevel@tonic-gate 			kmem_free(data->netname, nlen);
2697c478bd9Sstevel@tonic-gate 		}
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 		if (!error) {
2727c478bd9Sstevel@tonic-gate 			error = copyinstr(knconf->knc_proto,
2737c478bd9Sstevel@tonic-gate 			    p, KNC_STRSIZE, &nmoved_tmp);
2747c478bd9Sstevel@tonic-gate 			if (error) {
2757c478bd9Sstevel@tonic-gate 				kmem_free(pf, KNC_STRSIZE);
2767c478bd9Sstevel@tonic-gate 				kmem_free(p, KNC_STRSIZE);
2777c478bd9Sstevel@tonic-gate 				kmem_free(knconf, sizeof (*knconf));
2787c478bd9Sstevel@tonic-gate 				kmem_free(syncaddr->buf, syncaddr->len);
2797c478bd9Sstevel@tonic-gate 				kmem_free(data->netname, nlen);
2807c478bd9Sstevel@tonic-gate 			}
2817c478bd9Sstevel@tonic-gate 		}
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 		if (!error) {
2847c478bd9Sstevel@tonic-gate 			knconf->knc_protofmly = pf;
2857c478bd9Sstevel@tonic-gate 			knconf->knc_proto = p;
2867c478bd9Sstevel@tonic-gate 		}
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	if (error) {
2907c478bd9Sstevel@tonic-gate 		*kdata = NULL;
2917c478bd9Sstevel@tonic-gate 		kmem_free(data, sizeof (*data));
2927c478bd9Sstevel@tonic-gate 		return (error);
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	data->knconf = knconf;
2967c478bd9Sstevel@tonic-gate 	*kdata = (caddr_t)data;
2977c478bd9Sstevel@tonic-gate 	return (0);
2987c478bd9Sstevel@tonic-gate }
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate /*
3017c478bd9Sstevel@tonic-gate  *  Free up AUTH_DES specific data.
3027c478bd9Sstevel@tonic-gate  */
3037c478bd9Sstevel@tonic-gate void
dh_k4_clnt_freeinfo(caddr_t cdata)3047c478bd9Sstevel@tonic-gate dh_k4_clnt_freeinfo(caddr_t cdata)
3057c478bd9Sstevel@tonic-gate {
3067c478bd9Sstevel@tonic-gate 	dh_k4_clntdata_t *data;
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	data = (dh_k4_clntdata_t *)cdata;
3097c478bd9Sstevel@tonic-gate 	if (data->netnamelen > 0) {
3107c478bd9Sstevel@tonic-gate 		kmem_free(data->netname, data->netnamelen);
3117c478bd9Sstevel@tonic-gate 	}
3127c478bd9Sstevel@tonic-gate 	if (data->syncaddr.buf != NULL) {
3137c478bd9Sstevel@tonic-gate 		kmem_free(data->syncaddr.buf, data->syncaddr.len);
3147c478bd9Sstevel@tonic-gate 	}
3157c478bd9Sstevel@tonic-gate 	if (data->knconf != NULL) {
3167c478bd9Sstevel@tonic-gate 		kmem_free(data->knconf->knc_protofmly, KNC_STRSIZE);
3177c478bd9Sstevel@tonic-gate 		kmem_free(data->knconf->knc_proto, KNC_STRSIZE);
3187c478bd9Sstevel@tonic-gate 		kmem_free(data->knconf, sizeof (*data->knconf));
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	kmem_free(data, sizeof (*data));
3227c478bd9Sstevel@tonic-gate }
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate /*
3257c478bd9Sstevel@tonic-gate  *  Load application auth related data from user land to kernel.
3267c478bd9Sstevel@tonic-gate  *  Map opaque data field to dh_k4_clntdata_t for AUTH_DES
3277c478bd9Sstevel@tonic-gate  *
3287c478bd9Sstevel@tonic-gate  */
3297c478bd9Sstevel@tonic-gate int
sec_clnt_loadinfo(struct sec_data * in,struct sec_data ** out,model_t model)3307c478bd9Sstevel@tonic-gate sec_clnt_loadinfo(struct sec_data *in, struct sec_data **out, model_t model)
3317c478bd9Sstevel@tonic-gate {
3327c478bd9Sstevel@tonic-gate 	struct	sec_data	*secdata;
3337c478bd9Sstevel@tonic-gate 	int	error = 0;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	secdata = kmem_alloc(sizeof (*secdata), KM_SLEEP);
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
3387c478bd9Sstevel@tonic-gate 	if (model != DATAMODEL_NATIVE) {
3397c478bd9Sstevel@tonic-gate 		struct sec_data32 sd32;
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 		if (copyin(in, &sd32, sizeof (sd32)) == -1) {
3427c478bd9Sstevel@tonic-gate 			error = EFAULT;
3437c478bd9Sstevel@tonic-gate 		} else {
3447c478bd9Sstevel@tonic-gate 			secdata->secmod = sd32.secmod;
3457c478bd9Sstevel@tonic-gate 			secdata->rpcflavor = sd32.rpcflavor;
3467c478bd9Sstevel@tonic-gate 			secdata->uid = sd32.uid;
3477c478bd9Sstevel@tonic-gate 			secdata->flags = sd32.flags;
3487c478bd9Sstevel@tonic-gate 			secdata->data = (caddr_t)(uintptr_t)sd32.data;
3497c478bd9Sstevel@tonic-gate 		}
3507c478bd9Sstevel@tonic-gate 	} else
3517c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	if (copyin(in, secdata, sizeof (*secdata)) == -1) {
3547c478bd9Sstevel@tonic-gate 		error = EFAULT;
3557c478bd9Sstevel@tonic-gate 	}
3567c478bd9Sstevel@tonic-gate 	/*
3577c478bd9Sstevel@tonic-gate 	 * Copy in opaque data field per flavor.
3587c478bd9Sstevel@tonic-gate 	 */
3597c478bd9Sstevel@tonic-gate 	if (!error) {
3607c478bd9Sstevel@tonic-gate 		switch (secdata->rpcflavor) {
3617c478bd9Sstevel@tonic-gate 		case AUTH_NONE:
3627c478bd9Sstevel@tonic-gate 		case AUTH_UNIX:
3637c478bd9Sstevel@tonic-gate 		case AUTH_LOOPBACK:
3647c478bd9Sstevel@tonic-gate 			break;
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 		case AUTH_DES:
3677c478bd9Sstevel@tonic-gate 			error = dh_k4_clnt_loadinfo(secdata->data,
3687c478bd9Sstevel@tonic-gate 			    &secdata->data, model);
3697c478bd9Sstevel@tonic-gate 			break;
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 		case RPCSEC_GSS:
3727c478bd9Sstevel@tonic-gate 			error = gss_clnt_loadinfo(secdata->data,
3737c478bd9Sstevel@tonic-gate 			    &secdata->data, model);
3747c478bd9Sstevel@tonic-gate 			break;
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 		default:
3777c478bd9Sstevel@tonic-gate 			error = EINVAL;
3787c478bd9Sstevel@tonic-gate 			break;
3797c478bd9Sstevel@tonic-gate 		}
3807c478bd9Sstevel@tonic-gate 	}
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	if (!error) {
3837c478bd9Sstevel@tonic-gate 		*out = secdata;
3847c478bd9Sstevel@tonic-gate 	} else {
3857c478bd9Sstevel@tonic-gate 		kmem_free(secdata, sizeof (*secdata));
3867c478bd9Sstevel@tonic-gate 		*out = (struct sec_data *)NULL;
3877c478bd9Sstevel@tonic-gate 	}
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	return (error);
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate /*
3937c478bd9Sstevel@tonic-gate  * Null the sec_data index in the cache table, and
3947c478bd9Sstevel@tonic-gate  * free the memory allocated by sec_clnt_loadinfo.
3957c478bd9Sstevel@tonic-gate  */
3967c478bd9Sstevel@tonic-gate void
sec_clnt_freeinfo(struct sec_data * secdata)3977c478bd9Sstevel@tonic-gate sec_clnt_freeinfo(struct sec_data *secdata)
3987c478bd9Sstevel@tonic-gate {
3997c478bd9Sstevel@tonic-gate 	switch (secdata->rpcflavor) {
4007c478bd9Sstevel@tonic-gate 	case AUTH_DES:
4017c478bd9Sstevel@tonic-gate 		purge_authtab(secdata);
4027c478bd9Sstevel@tonic-gate 		if (secdata->data)
4037c478bd9Sstevel@tonic-gate 			dh_k4_clnt_freeinfo(secdata->data);
4047c478bd9Sstevel@tonic-gate 		break;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	case RPCSEC_GSS:
4077c478bd9Sstevel@tonic-gate 		rpc_gss_secpurge((void *)secdata);
4087c478bd9Sstevel@tonic-gate 		if (secdata->data) {
4097c478bd9Sstevel@tonic-gate 			gss_clntdata_t *gss_data;
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 			gss_data = (gss_clntdata_t *)secdata->data;
4127c478bd9Sstevel@tonic-gate 			if (gss_data->mechanism.elements) {
4137c478bd9Sstevel@tonic-gate 				kmem_free(gss_data->mechanism.elements,
4147c478bd9Sstevel@tonic-gate 				    gss_data->mechanism.length);
4157c478bd9Sstevel@tonic-gate 			}
4167c478bd9Sstevel@tonic-gate 			kmem_free(secdata->data, sizeof (gss_clntdata_t));
4177c478bd9Sstevel@tonic-gate 		}
4187c478bd9Sstevel@tonic-gate 		break;
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	case AUTH_NONE:
4217c478bd9Sstevel@tonic-gate 	case AUTH_UNIX:
4227c478bd9Sstevel@tonic-gate 	case AUTH_LOOPBACK:
4237c478bd9Sstevel@tonic-gate 	default:
4247c478bd9Sstevel@tonic-gate 		break;
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate 	kmem_free(secdata, sizeof (*secdata));
4277c478bd9Sstevel@tonic-gate }
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate /*
4307c478bd9Sstevel@tonic-gate  *  Get an AUTH handle for a RPC client based on the given sec_data.
4317c478bd9Sstevel@tonic-gate  *  If an AUTH handle exists for the same sec_data, use that AUTH handle,
4327c478bd9Sstevel@tonic-gate  *  otherwise create a new one.
4337c478bd9Sstevel@tonic-gate  */
4347c478bd9Sstevel@tonic-gate int
sec_clnt_geth(CLIENT * client,struct sec_data * secdata,cred_t * cr,AUTH ** ap)4357c478bd9Sstevel@tonic-gate sec_clnt_geth(CLIENT *client, struct sec_data *secdata, cred_t *cr, AUTH **ap)
4367c478bd9Sstevel@tonic-gate {
4377c478bd9Sstevel@tonic-gate 	int i;
4387c478bd9Sstevel@tonic-gate 	struct desauthent *da;
4397c478bd9Sstevel@tonic-gate 	int authflavor;
4407c478bd9Sstevel@tonic-gate 	cred_t *savecred;
4417c478bd9Sstevel@tonic-gate 	int stat;			/* return (errno) status */
4427c478bd9Sstevel@tonic-gate 	char gss_svc_name[MAX_GSS_NAME];
4437c478bd9Sstevel@tonic-gate 	dh_k4_clntdata_t	*desdata;
4447c478bd9Sstevel@tonic-gate 	AUTH *auth;
4457c478bd9Sstevel@tonic-gate 	gss_clntdata_t *gssdata;
4467c478bd9Sstevel@tonic-gate 	zoneid_t zoneid = getzoneid();
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	if ((client == NULL) || (secdata == NULL) || (ap == NULL))
4497c478bd9Sstevel@tonic-gate 		return (EINVAL);
4507c478bd9Sstevel@tonic-gate 	*ap = (AUTH *)NULL;
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	authflavor = secdata->rpcflavor;
4537c478bd9Sstevel@tonic-gate 	for (;;) {
454b9238976Sth 		int nlen;
455b9238976Sth 		char *netname;
456b9238976Sth 
4577c478bd9Sstevel@tonic-gate 		switch (authflavor) {
4587c478bd9Sstevel@tonic-gate 		case AUTH_NONE:
45933f285aeSVallish Vaidyeshwara 			*ap = (AUTH *) authnone_create();
46033f285aeSVallish Vaidyeshwara 			return ((*ap != NULL) ? 0 : EINTR);
46133f285aeSVallish Vaidyeshwara 
4627c478bd9Sstevel@tonic-gate 		case AUTH_UNIX:
4637c478bd9Sstevel@tonic-gate 			*ap = (AUTH *) authkern_create();
4647c478bd9Sstevel@tonic-gate 			return ((*ap != NULL) ? 0 : EINTR);
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 		case AUTH_LOOPBACK:
4677c478bd9Sstevel@tonic-gate 			*ap = (AUTH *) authloopback_create();
4687c478bd9Sstevel@tonic-gate 			return ((*ap != NULL) ? 0 : EINTR);
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 		case AUTH_DES:
4717c478bd9Sstevel@tonic-gate 			mutex_enter(&desauthtab_lock);
4727c478bd9Sstevel@tonic-gate 			if (desauthtab == NULL) {
4737c478bd9Sstevel@tonic-gate 				desauthtab = kmem_zalloc(clnt_authdes_cachesz *
4747c478bd9Sstevel@tonic-gate 				    sizeof (struct desauthent), KM_SLEEP);
4757c478bd9Sstevel@tonic-gate 			}
4767c478bd9Sstevel@tonic-gate 			for (da = desauthtab;
4777c478bd9Sstevel@tonic-gate 			    da < &desauthtab[clnt_authdes_cachesz];
4787c478bd9Sstevel@tonic-gate 			    da++) {
4797c478bd9Sstevel@tonic-gate 				if (da->da_data == secdata &&
4807c478bd9Sstevel@tonic-gate 				    da->da_uid == crgetuid(cr) &&
4817c478bd9Sstevel@tonic-gate 				    da->da_zoneid == zoneid &&
4827c478bd9Sstevel@tonic-gate 				    !da->da_inuse &&
4837c478bd9Sstevel@tonic-gate 				    da->da_auth != NULL) {
4847c478bd9Sstevel@tonic-gate 					da->da_inuse = 1;
4857c478bd9Sstevel@tonic-gate 					mutex_exit(&desauthtab_lock);
4867c478bd9Sstevel@tonic-gate 					*ap = da->da_auth;
4877c478bd9Sstevel@tonic-gate 					return (0);
4887c478bd9Sstevel@tonic-gate 				}
4897c478bd9Sstevel@tonic-gate 			}
4907c478bd9Sstevel@tonic-gate 			mutex_exit(&desauthtab_lock);
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 			/*
4937c478bd9Sstevel@tonic-gate 			 *  A better way would be to have a cred paramater to
4947c478bd9Sstevel@tonic-gate 			 *  authdes_create.
4957c478bd9Sstevel@tonic-gate 			 */
4967c478bd9Sstevel@tonic-gate 			savecred = curthread->t_cred;
4977c478bd9Sstevel@tonic-gate 			curthread->t_cred = cr;
498b9238976Sth 
499b9238976Sth 			/*
500b9238976Sth 			 * Note that authdes_create() expects a
501b9238976Sth 			 * NUL-terminated string for netname, but
502b9238976Sth 			 * dh_k4_clntdata_t gives us netname & netnamelen.
503b9238976Sth 			 *
504b9238976Sth 			 * We must create a string for authdes_create();
505b9238976Sth 			 * the latter takes a copy of it, so we may
506b9238976Sth 			 * immediately free it.
507b9238976Sth 			 */
5087c478bd9Sstevel@tonic-gate 			desdata = (dh_k4_clntdata_t *)secdata->data;
509b9238976Sth 			nlen = desdata->netnamelen;
510b9238976Sth 			/* must be NUL-terminated */
511b9238976Sth 			netname = kmem_zalloc(nlen + 1, KM_SLEEP);
512b9238976Sth 			bcopy(desdata->netname, netname, nlen);
513b9238976Sth 			stat = authdes_create(netname, authdes_win,
514b9238976Sth 			    &desdata->syncaddr, desdata->knconf,
515b9238976Sth 			    (des_block *)NULL,
516b9238976Sth 			    (secdata->flags & AUTH_F_RPCTIMESYNC) ? 1 : 0,
517b9238976Sth 			    &auth);
518b9238976Sth 			kmem_free(netname, nlen + 1);
519b9238976Sth 
5207c478bd9Sstevel@tonic-gate 			curthread->t_cred = savecred;
5217c478bd9Sstevel@tonic-gate 			*ap = auth;
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 			if (stat != 0) {
5247c478bd9Sstevel@tonic-gate 				/*
5257c478bd9Sstevel@tonic-gate 				 *  If AUTH_F_TRYNONE is on, try again
5267c478bd9Sstevel@tonic-gate 				 *  with AUTH_NONE.  See bug 1180236.
5277c478bd9Sstevel@tonic-gate 				 */
5287c478bd9Sstevel@tonic-gate 				if (secdata->flags & AUTH_F_TRYNONE) {
5297c478bd9Sstevel@tonic-gate 					authflavor = AUTH_NONE;
5307c478bd9Sstevel@tonic-gate 					continue;
5317c478bd9Sstevel@tonic-gate 				} else
5327c478bd9Sstevel@tonic-gate 					return (stat);
5337c478bd9Sstevel@tonic-gate 			}
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 			i = clnt_authdes_cachesz;
5367c478bd9Sstevel@tonic-gate 			mutex_enter(&desauthtab_lock);
5377c478bd9Sstevel@tonic-gate 			do {
5387c478bd9Sstevel@tonic-gate 				da = &desauthtab[nextdesvictim++];
5397c478bd9Sstevel@tonic-gate 				nextdesvictim %= clnt_authdes_cachesz;
5407c478bd9Sstevel@tonic-gate 			} while (da->da_inuse && --i > 0);
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 			if (da->da_inuse) {
5437c478bd9Sstevel@tonic-gate 				mutex_exit(&desauthtab_lock);
5447c478bd9Sstevel@tonic-gate 				/* overflow of des auths */
5457c478bd9Sstevel@tonic-gate 				return (stat);
5467c478bd9Sstevel@tonic-gate 			}
5477c478bd9Sstevel@tonic-gate 			da->da_inuse = 1;
5487c478bd9Sstevel@tonic-gate 			mutex_exit(&desauthtab_lock);
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 			if (da->da_auth != NULL)
5517c478bd9Sstevel@tonic-gate 				auth_destroy(da->da_auth);
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 			da->da_auth = auth;
5547c478bd9Sstevel@tonic-gate 			da->da_uid = crgetuid(cr);
5557c478bd9Sstevel@tonic-gate 			da->da_zoneid = zoneid;
5567c478bd9Sstevel@tonic-gate 			da->da_data = secdata;
5577c478bd9Sstevel@tonic-gate 			return (stat);
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 		case RPCSEC_GSS:
5607c478bd9Sstevel@tonic-gate 			/*
5617c478bd9Sstevel@tonic-gate 			 *  For RPCSEC_GSS, cache is done in rpc_gss_secget().
5627c478bd9Sstevel@tonic-gate 			 *  For every rpc_gss_secget(),  it should have
5637c478bd9Sstevel@tonic-gate 			 *  a corresponding rpc_gss_secfree() call.
5647c478bd9Sstevel@tonic-gate 			 */
5657c478bd9Sstevel@tonic-gate 			gssdata = (gss_clntdata_t *)secdata->data;
5667c478bd9Sstevel@tonic-gate 			(void) sprintf(gss_svc_name, "%s@%s", gssdata->uname,
5677c478bd9Sstevel@tonic-gate 			    gssdata->inst);
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 			stat = rpc_gss_secget(client, gss_svc_name,
5707c478bd9Sstevel@tonic-gate 			    &gssdata->mechanism,
5717c478bd9Sstevel@tonic-gate 			    gssdata->service,
5727c478bd9Sstevel@tonic-gate 			    gssdata->qop,
5737c478bd9Sstevel@tonic-gate 			    NULL, NULL,
5747c478bd9Sstevel@tonic-gate 			    (caddr_t)secdata, cr, &auth);
5757c478bd9Sstevel@tonic-gate 			*ap = auth;
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 			/* success */
5787c478bd9Sstevel@tonic-gate 			if (stat == 0)
5797c478bd9Sstevel@tonic-gate 				return (stat);
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 			/*
5827c478bd9Sstevel@tonic-gate 			 * let the caller retry if connection timedout
5837c478bd9Sstevel@tonic-gate 			 * or reset.
5847c478bd9Sstevel@tonic-gate 			 */
5857c478bd9Sstevel@tonic-gate 			if (stat == ETIMEDOUT || stat == ECONNRESET)
5867c478bd9Sstevel@tonic-gate 				return (stat);
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 			/*
5897c478bd9Sstevel@tonic-gate 			 *  If AUTH_F_TRYNONE is on, try again
5907c478bd9Sstevel@tonic-gate 			 *  with AUTH_NONE.  See bug 1180236.
5917c478bd9Sstevel@tonic-gate 			 */
5927c478bd9Sstevel@tonic-gate 			if (secdata->flags & AUTH_F_TRYNONE) {
5937c478bd9Sstevel@tonic-gate 				authflavor = AUTH_NONE;
5947c478bd9Sstevel@tonic-gate 				continue;
5957c478bd9Sstevel@tonic-gate 			}
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 			RPCLOG(1, "sec_clnt_geth: rpc_gss_secget"
598b9238976Sth 			    " failed with %d", stat);
5997c478bd9Sstevel@tonic-gate 			return (stat);
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 		default:
6027c478bd9Sstevel@tonic-gate 			/*
6037c478bd9Sstevel@tonic-gate 			 * auth create must have failed, try AUTH_NONE
6047c478bd9Sstevel@tonic-gate 			 * (this relies on AUTH_NONE never failing)
6057c478bd9Sstevel@tonic-gate 			 */
6067c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "sec_clnt_geth: unknown "
6077c478bd9Sstevel@tonic-gate 			    "authflavor %d, trying AUTH_NONE", authflavor);
6087c478bd9Sstevel@tonic-gate 			authflavor = AUTH_NONE;
6097c478bd9Sstevel@tonic-gate 		}
6107c478bd9Sstevel@tonic-gate 	}
6117c478bd9Sstevel@tonic-gate }
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate void
sec_clnt_freeh(AUTH * auth)6147c478bd9Sstevel@tonic-gate sec_clnt_freeh(AUTH *auth)
6157c478bd9Sstevel@tonic-gate {
6167c478bd9Sstevel@tonic-gate 	struct desauthent *da;
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	switch (auth->ah_cred.oa_flavor) {
6197c478bd9Sstevel@tonic-gate 	case AUTH_NONE: /* XXX: do real AUTH_NONE */
6207c478bd9Sstevel@tonic-gate 	case AUTH_UNIX:
6217c478bd9Sstevel@tonic-gate 	case AUTH_LOOPBACK:
6227c478bd9Sstevel@tonic-gate 		auth_destroy(auth);	/* was overflow */
6237c478bd9Sstevel@tonic-gate 		break;
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	case AUTH_DES:
6267c478bd9Sstevel@tonic-gate 		mutex_enter(&desauthtab_lock);
6277c478bd9Sstevel@tonic-gate 		if (desauthtab != NULL) {
628b9238976Sth 			for (da = desauthtab;
629b9238976Sth 			    da < &desauthtab[clnt_authdes_cachesz]; da++) {
630b9238976Sth 				if (da->da_auth == auth) {
631b9238976Sth 					da->da_inuse = 0;
632b9238976Sth 					mutex_exit(&desauthtab_lock);
633b9238976Sth 					return;
634b9238976Sth 				}
6357c478bd9Sstevel@tonic-gate 			}
6367c478bd9Sstevel@tonic-gate 		}
6377c478bd9Sstevel@tonic-gate 		mutex_exit(&desauthtab_lock);
6387c478bd9Sstevel@tonic-gate 		auth_destroy(auth);	/* was overflow */
6397c478bd9Sstevel@tonic-gate 		break;
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	case RPCSEC_GSS:
6427c478bd9Sstevel@tonic-gate 		(void) rpc_gss_secfree(auth);
6437c478bd9Sstevel@tonic-gate 		break;
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	default:
6467c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "sec_clnt_freeh: unknown authflavor %d",
647b9238976Sth 		    auth->ah_cred.oa_flavor);
6487c478bd9Sstevel@tonic-gate 		break;
6497c478bd9Sstevel@tonic-gate 	}
6507c478bd9Sstevel@tonic-gate }
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate /*
6537c478bd9Sstevel@tonic-gate  *  Revoke the authentication key in the given AUTH handle by setting
6547c478bd9Sstevel@tonic-gate  *  it to NULL.  If newkey is true, then generate a new key instead of
6557c478bd9Sstevel@tonic-gate  *  nulling out the old one.  This is necessary for AUTH_DES because
6567c478bd9Sstevel@tonic-gate  *  the new key will be used next time the user does a keylogin.  If
6577c478bd9Sstevel@tonic-gate  *  the zero'd key is used as actual key, then it cannot be revoked
6587c478bd9Sstevel@tonic-gate  *  again!
6597c478bd9Sstevel@tonic-gate  */
6607c478bd9Sstevel@tonic-gate void
revoke_key(AUTH * auth,int newkey)6617c478bd9Sstevel@tonic-gate revoke_key(AUTH *auth, int newkey)
6627c478bd9Sstevel@tonic-gate {
6637c478bd9Sstevel@tonic-gate 	if (auth == NULL)
6647c478bd9Sstevel@tonic-gate 		return;
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	if (newkey) {
6677c478bd9Sstevel@tonic-gate 		if (key_gendes(&auth->ah_key) != RPC_SUCCESS) {
6687c478bd9Sstevel@tonic-gate 			/* failed to get new key, munge the old one */
6697c478bd9Sstevel@tonic-gate 			auth->ah_key.key.high ^= auth->ah_key.key.low;
6707c478bd9Sstevel@tonic-gate 			auth->ah_key.key.low  += auth->ah_key.key.high;
6717c478bd9Sstevel@tonic-gate 		}
6727c478bd9Sstevel@tonic-gate 	} else {
6737c478bd9Sstevel@tonic-gate 		/* null out old key */
6747c478bd9Sstevel@tonic-gate 		auth->ah_key.key.high = 0;
6757c478bd9Sstevel@tonic-gate 		auth->ah_key.key.low  = 0;
6767c478bd9Sstevel@tonic-gate 	}
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate /*
6807c478bd9Sstevel@tonic-gate  *  Revoke all rpc credentials (of the selected auth type) for the given uid
6817c478bd9Sstevel@tonic-gate  *  from the auth cache.  Must be root to do this if the requested uid is not
6827c478bd9Sstevel@tonic-gate  *  the effective uid of the requestor.
6837c478bd9Sstevel@tonic-gate  *
6847c478bd9Sstevel@tonic-gate  *  Called from nfssys() for backward compatibility, and also
6857c478bd9Sstevel@tonic-gate  *  called from krpc_sys().
6867c478bd9Sstevel@tonic-gate  *
6877c478bd9Sstevel@tonic-gate  *  AUTH_DES does not refer to the "mechanism" information.
6887c478bd9Sstevel@tonic-gate  *  RPCSEC_GSS requires the "mechanism" input.
6897c478bd9Sstevel@tonic-gate  *  The input argument, mechanism, is a user-space address and needs
6907c478bd9Sstevel@tonic-gate  *  to be copied into the kernel address space.
6917c478bd9Sstevel@tonic-gate  *
6927c478bd9Sstevel@tonic-gate  *  Returns error number.
6937c478bd9Sstevel@tonic-gate  */
6947c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6957c478bd9Sstevel@tonic-gate int
sec_clnt_revoke(int rpcflavor,uid_t uid,cred_t * cr,void * mechanism,model_t model)6967c478bd9Sstevel@tonic-gate sec_clnt_revoke(int rpcflavor, uid_t uid, cred_t *cr, void *mechanism,
6977c478bd9Sstevel@tonic-gate 						model_t model)
6987c478bd9Sstevel@tonic-gate {
6997c478bd9Sstevel@tonic-gate 	struct desauthent *da;
7007c478bd9Sstevel@tonic-gate 	int error = 0;
7017c478bd9Sstevel@tonic-gate 	zoneid_t zoneid = getzoneid();
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	if (uid != crgetuid(cr) && secpolicy_nfs(cr) != 0)
7047c478bd9Sstevel@tonic-gate 		return (EPERM);
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	switch (rpcflavor) {
7077c478bd9Sstevel@tonic-gate 	case AUTH_DES:
7087c478bd9Sstevel@tonic-gate 		mutex_enter(&desauthtab_lock);
7097c478bd9Sstevel@tonic-gate 		if (desauthtab != NULL) {
710b9238976Sth 			for (da = desauthtab;
711b9238976Sth 			    da < &desauthtab[clnt_authdes_cachesz]; da++) {
712b9238976Sth 				if (uid == da->da_uid &&
713b9238976Sth 				    zoneid == da->da_zoneid)
714b9238976Sth 					revoke_key(da->da_auth, 1);
715b9238976Sth 			}
7167c478bd9Sstevel@tonic-gate 		}
7177c478bd9Sstevel@tonic-gate 		mutex_exit(&desauthtab_lock);
7187c478bd9Sstevel@tonic-gate 		return (0);
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	case RPCSEC_GSS: {
7217c478bd9Sstevel@tonic-gate 		rpc_gss_OID	mech;
7227c478bd9Sstevel@tonic-gate 		caddr_t		elements;
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 		if (!mechanism)
7257c478bd9Sstevel@tonic-gate 			return (EINVAL);
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 		/* copyin the gss mechanism type */
7287c478bd9Sstevel@tonic-gate 		mech = kmem_alloc(sizeof (rpc_gss_OID_desc), KM_SLEEP);
7297c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
7307c478bd9Sstevel@tonic-gate 		if (model != DATAMODEL_NATIVE) {
7317c478bd9Sstevel@tonic-gate 			gss_OID_desc32 mech32;
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 			if (copyin(mechanism, &mech32,
7347c478bd9Sstevel@tonic-gate 			    sizeof (gss_OID_desc32))) {
7357c478bd9Sstevel@tonic-gate 				kmem_free(mech, sizeof (rpc_gss_OID_desc));
7367c478bd9Sstevel@tonic-gate 				return (EFAULT);
7377c478bd9Sstevel@tonic-gate 			}
7387c478bd9Sstevel@tonic-gate 			mech->length = mech32.length;
7397c478bd9Sstevel@tonic-gate 			mech->elements = (caddr_t)(uintptr_t)mech32.elements;
7407c478bd9Sstevel@tonic-gate 		} else
7417c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
7427c478bd9Sstevel@tonic-gate 		if (copyin(mechanism, mech, sizeof (rpc_gss_OID_desc))) {
7437c478bd9Sstevel@tonic-gate 			kmem_free(mech, sizeof (rpc_gss_OID_desc));
7447c478bd9Sstevel@tonic-gate 			return (EFAULT);
7457c478bd9Sstevel@tonic-gate 		}
7467c478bd9Sstevel@tonic-gate 
747*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States 		if (mech->length < MINAUTHLEN ||
748*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States 		    mech->length > MAXAUTHLEN) {
749*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States 			kmem_free(mech, sizeof (rpc_gss_OID_desc));
750*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States 			return (EINVAL);
751*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States 		}
752*52056d7bSM Pavan kumar - Sun Microsystems - Menlo Park United States 
7537c478bd9Sstevel@tonic-gate 		elements = kmem_alloc(mech->length, KM_SLEEP);
7547c478bd9Sstevel@tonic-gate 		if (copyin(mech->elements, elements, mech->length)) {
7557c478bd9Sstevel@tonic-gate 			kmem_free(elements, mech->length);
7567c478bd9Sstevel@tonic-gate 			kmem_free(mech, sizeof (rpc_gss_OID_desc));
7577c478bd9Sstevel@tonic-gate 			return (EFAULT);
7587c478bd9Sstevel@tonic-gate 		}
7597c478bd9Sstevel@tonic-gate 		mech->elements = elements;
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 		error = rpc_gss_revauth(uid, mech);
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 		kmem_free(elements, mech->length);
7647c478bd9Sstevel@tonic-gate 		kmem_free(mech, sizeof (rpc_gss_OID_desc));
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 		return (error);
7677c478bd9Sstevel@tonic-gate 	}
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	default:
7707c478bd9Sstevel@tonic-gate 		/* not an auth type with cached creds */
7717c478bd9Sstevel@tonic-gate 		return (EINVAL);
7727c478bd9Sstevel@tonic-gate 	}
7737c478bd9Sstevel@tonic-gate }
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate /*
7767c478bd9Sstevel@tonic-gate  *  Since sec_data is the index for the client auth handles
7777c478bd9Sstevel@tonic-gate  *  cache table,  whenever the sec_data is freed, the index needs
7787c478bd9Sstevel@tonic-gate  *  to be nulled.
7797c478bd9Sstevel@tonic-gate  */
7807c478bd9Sstevel@tonic-gate void
purge_authtab(struct sec_data * secdata)7817c478bd9Sstevel@tonic-gate purge_authtab(struct sec_data *secdata)
7827c478bd9Sstevel@tonic-gate {
7837c478bd9Sstevel@tonic-gate 	struct desauthent *da;
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 	switch (secdata->rpcflavor) {
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	case AUTH_DES:
7887c478bd9Sstevel@tonic-gate 		mutex_enter(&desauthtab_lock);
7897c478bd9Sstevel@tonic-gate 		if (desauthtab != NULL) {
790b9238976Sth 			for (da = desauthtab;
791b9238976Sth 			    da < &desauthtab[clnt_authdes_cachesz]; da++) {
792b9238976Sth 				if (da->da_data == secdata) {
793b9238976Sth 					da->da_data = NULL;
794b9238976Sth 					da->da_inuse = 0;
795b9238976Sth 				}
7967c478bd9Sstevel@tonic-gate 			}
7977c478bd9Sstevel@tonic-gate 		}
7987c478bd9Sstevel@tonic-gate 		mutex_exit(&desauthtab_lock);
7997c478bd9Sstevel@tonic-gate 		return;
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	case RPCSEC_GSS:
8027c478bd9Sstevel@tonic-gate 		rpc_gss_secpurge((void *)secdata);
8037c478bd9Sstevel@tonic-gate 		return;
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 	default:
8067c478bd9Sstevel@tonic-gate 		return;
8077c478bd9Sstevel@tonic-gate 	}
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate void
sec_subrinit(void)8117c478bd9Sstevel@tonic-gate sec_subrinit(void)
8127c478bd9Sstevel@tonic-gate {
8137c478bd9Sstevel@tonic-gate 	authkern_cache = kmem_cache_create("authkern_cache",
8147c478bd9Sstevel@tonic-gate 	    sizeof (AUTH), 0, authkern_init, NULL, NULL, NULL, NULL, 0);
81533f285aeSVallish Vaidyeshwara 	authnone_cache = kmem_cache_create("authnone_cache",
81633f285aeSVallish Vaidyeshwara 	    sizeof (AUTH), 0, authnone_init, NULL, NULL, NULL, NULL, 0);
8177c478bd9Sstevel@tonic-gate 	authloopback_cache = kmem_cache_create("authloopback_cache",
8187c478bd9Sstevel@tonic-gate 	    sizeof (AUTH), 0, authloopback_init, NULL, NULL, NULL, NULL, 0);
8197c478bd9Sstevel@tonic-gate 	mutex_init(&desauthtab_lock, NULL, MUTEX_DEFAULT, NULL);
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 	/* RPC stuff */
8227c478bd9Sstevel@tonic-gate 	mutex_init(&authdes_ops_lock, NULL, MUTEX_DEFAULT, NULL);
8237c478bd9Sstevel@tonic-gate 	zone_key_create(&auth_zone_key, auth_zone_init, NULL, auth_zone_fini);
8247c478bd9Sstevel@tonic-gate }
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate /*
8277c478bd9Sstevel@tonic-gate  * Destroys the caches and mutexes previously allocated and initialized
8287c478bd9Sstevel@tonic-gate  * in sec_subrinit().
8297c478bd9Sstevel@tonic-gate  * This routine is called by _init() if mod_install() failed.
8307c478bd9Sstevel@tonic-gate  */
8317c478bd9Sstevel@tonic-gate void
sec_subrfini(void)8327c478bd9Sstevel@tonic-gate sec_subrfini(void)
8337c478bd9Sstevel@tonic-gate {
8347c478bd9Sstevel@tonic-gate 	mutex_destroy(&desauthtab_lock);
8357c478bd9Sstevel@tonic-gate 	kmem_cache_destroy(authkern_cache);
83633f285aeSVallish Vaidyeshwara 	kmem_cache_destroy(authnone_cache);
8377c478bd9Sstevel@tonic-gate 	kmem_cache_destroy(authloopback_cache);
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	/* RPC stuff */
8407c478bd9Sstevel@tonic-gate 	mutex_destroy(&authdes_ops_lock);
8417c478bd9Sstevel@tonic-gate 	(void) zone_key_delete(auth_zone_key);
8427c478bd9Sstevel@tonic-gate }
843