xref: /onnv-gate/usr/src/uts/common/rpc/sec/sec_clnt.c (revision 5302:eec6aeacde6e)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*5302Sth199096  * Common Development and Distribution License (the "License").
6*5302Sth199096  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*5302Sth199096  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/param.h>
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/systm.h>
310Sstevel@tonic-gate #include <sys/cred.h>
320Sstevel@tonic-gate #include <sys/proc.h>
330Sstevel@tonic-gate #include <sys/user.h>
340Sstevel@tonic-gate #include <sys/time.h>
350Sstevel@tonic-gate #include <sys/buf.h>
360Sstevel@tonic-gate #include <sys/vfs.h>
370Sstevel@tonic-gate #include <sys/vnode.h>
380Sstevel@tonic-gate #include <sys/socket.h>
390Sstevel@tonic-gate #include <sys/stat.h>
400Sstevel@tonic-gate #include <sys/uio.h>
410Sstevel@tonic-gate #include <sys/tiuser.h>
420Sstevel@tonic-gate #include <sys/swap.h>
430Sstevel@tonic-gate #include <sys/errno.h>
440Sstevel@tonic-gate #include <sys/debug.h>
450Sstevel@tonic-gate #include <sys/kmem.h>
460Sstevel@tonic-gate #include <sys/kstat.h>
470Sstevel@tonic-gate #include <sys/cmn_err.h>
480Sstevel@tonic-gate #include <sys/vtrace.h>
490Sstevel@tonic-gate #include <sys/session.h>
500Sstevel@tonic-gate #include <sys/dnlc.h>
510Sstevel@tonic-gate #include <sys/bitmap.h>
520Sstevel@tonic-gate #include <sys/thread.h>
530Sstevel@tonic-gate #include <sys/policy.h>
540Sstevel@tonic-gate 
550Sstevel@tonic-gate #include <netinet/in.h>
560Sstevel@tonic-gate #include <rpc/types.h>
570Sstevel@tonic-gate #include <rpc/xdr.h>
580Sstevel@tonic-gate #include <rpc/auth.h>
590Sstevel@tonic-gate #include <rpc/auth_des.h>	/* for authdes_create() */
600Sstevel@tonic-gate #include <rpc/clnt.h>
610Sstevel@tonic-gate #include <rpc/rpcsec_gss.h>
620Sstevel@tonic-gate 
630Sstevel@tonic-gate #define	MAXCLIENTS	16
640Sstevel@tonic-gate static int clnt_authdes_cachesz = 64;
650Sstevel@tonic-gate 
660Sstevel@tonic-gate static uint_t authdes_win = 5*60;  /* 5 minutes -- should be mount option */
670Sstevel@tonic-gate 
680Sstevel@tonic-gate struct kmem_cache *authkern_cache;
690Sstevel@tonic-gate 
700Sstevel@tonic-gate struct kmem_cache *authloopback_cache;
710Sstevel@tonic-gate 
720Sstevel@tonic-gate static struct desauthent {
730Sstevel@tonic-gate 	struct	sec_data *da_data;
740Sstevel@tonic-gate 	uid_t da_uid;
750Sstevel@tonic-gate 	zoneid_t da_zoneid;
760Sstevel@tonic-gate 	short da_inuse;
770Sstevel@tonic-gate 	AUTH *da_auth;
780Sstevel@tonic-gate } *desauthtab;
790Sstevel@tonic-gate static int nextdesvictim;
800Sstevel@tonic-gate static kmutex_t desauthtab_lock;	/* Lock to protect DES auth cache */
810Sstevel@tonic-gate 
820Sstevel@tonic-gate /* RPC stuff */
830Sstevel@tonic-gate kmutex_t authdes_ops_lock;   /* auth_ops initialization in authdes_ops() */
840Sstevel@tonic-gate 
850Sstevel@tonic-gate static void  purge_authtab(struct sec_data *);
860Sstevel@tonic-gate 
870Sstevel@tonic-gate /* Zone stuff */
880Sstevel@tonic-gate zone_key_t auth_zone_key;
890Sstevel@tonic-gate 
900Sstevel@tonic-gate /*
910Sstevel@tonic-gate  *  Load RPCSEC_GSS specific data from user space to kernel space.
920Sstevel@tonic-gate  */
930Sstevel@tonic-gate /*ARGSUSED*/
940Sstevel@tonic-gate static int
950Sstevel@tonic-gate gss_clnt_loadinfo(caddr_t usrdata, caddr_t *kdata, model_t model)
960Sstevel@tonic-gate {
970Sstevel@tonic-gate 	struct gss_clnt_data *data;
980Sstevel@tonic-gate 	caddr_t	elements;
990Sstevel@tonic-gate 	int error = 0;
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 	/* map opaque data to gss specific structure */
1020Sstevel@tonic-gate 	data = kmem_alloc(sizeof (*data), KM_SLEEP);
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1050Sstevel@tonic-gate 	if (model != DATAMODEL_NATIVE) {
1060Sstevel@tonic-gate 		struct gss_clnt_data32 gd32;
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 		if (copyin(usrdata, &gd32, sizeof (gd32)) == -1) {
1090Sstevel@tonic-gate 			error = EFAULT;
1100Sstevel@tonic-gate 		} else {
1110Sstevel@tonic-gate 			data->mechanism.length = gd32.mechanism.length;
1120Sstevel@tonic-gate 			data->mechanism.elements =
113*5302Sth199096 			    (caddr_t)(uintptr_t)gd32.mechanism.elements;
1140Sstevel@tonic-gate 			data->service = gd32.service;
1150Sstevel@tonic-gate 			bcopy(gd32.uname, data->uname, sizeof (gd32.uname));
1160Sstevel@tonic-gate 			bcopy(gd32.inst, data->inst, sizeof (gd32.inst));
1170Sstevel@tonic-gate 			bcopy(gd32.realm, data->realm, sizeof (gd32.realm));
1180Sstevel@tonic-gate 			data->qop = gd32.qop;
1190Sstevel@tonic-gate 		}
1200Sstevel@tonic-gate 	} else
1210Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
1220Sstevel@tonic-gate 	if (copyin(usrdata, data, sizeof (*data)))
1230Sstevel@tonic-gate 		error = EFAULT;
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	if (error == 0) {
1260Sstevel@tonic-gate 		if (data->mechanism.length > 0) {
1270Sstevel@tonic-gate 			elements = kmem_alloc(data->mechanism.length, KM_SLEEP);
1280Sstevel@tonic-gate 			if (!(copyin(data->mechanism.elements, elements,
1290Sstevel@tonic-gate 			    data->mechanism.length))) {
1300Sstevel@tonic-gate 				data->mechanism.elements = elements;
1310Sstevel@tonic-gate 				*kdata = (caddr_t)data;
1320Sstevel@tonic-gate 				return (0);
1330Sstevel@tonic-gate 			} else
1340Sstevel@tonic-gate 				kmem_free(elements, data->mechanism.length);
1350Sstevel@tonic-gate 		}
1360Sstevel@tonic-gate 	} else {
1370Sstevel@tonic-gate 		*kdata = NULL;
1380Sstevel@tonic-gate 		kmem_free(data, sizeof (*data));
1390Sstevel@tonic-gate 	}
1400Sstevel@tonic-gate 	return (EFAULT);
1410Sstevel@tonic-gate }
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate /*
1450Sstevel@tonic-gate  *  Load AUTH_DES specific data from user space to kernel space.
1460Sstevel@tonic-gate  */
1470Sstevel@tonic-gate /*ARGSUSED2*/
1480Sstevel@tonic-gate int
1490Sstevel@tonic-gate dh_k4_clnt_loadinfo(caddr_t usrdata, caddr_t *kdata, model_t model)
1500Sstevel@tonic-gate {
1510Sstevel@tonic-gate 	size_t nlen;
1520Sstevel@tonic-gate 	int error = 0;
1530Sstevel@tonic-gate 	char *userbufptr;
1540Sstevel@tonic-gate 	dh_k4_clntdata_t *data;
1550Sstevel@tonic-gate 	char netname[MAXNETNAMELEN+1];
1560Sstevel@tonic-gate 	struct netbuf *syncaddr;
1570Sstevel@tonic-gate 	struct knetconfig *knconf;
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 	/* map opaque data to des specific strucutre */
1600Sstevel@tonic-gate 	data = kmem_alloc(sizeof (*data), KM_SLEEP);
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
1630Sstevel@tonic-gate 	if (model != DATAMODEL_NATIVE) {
1640Sstevel@tonic-gate 		struct des_clnt_data32 data32;
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 		if (copyin(usrdata, &data32, sizeof (data32)) == -1) {
1670Sstevel@tonic-gate 			error = EFAULT;
1680Sstevel@tonic-gate 		} else {
1690Sstevel@tonic-gate 			data->syncaddr.maxlen = data32.syncaddr.maxlen;
1700Sstevel@tonic-gate 			data->syncaddr.len = data32.syncaddr.len;
1710Sstevel@tonic-gate 			data->syncaddr.buf =
1720Sstevel@tonic-gate 			    (caddr_t)(uintptr_t)data32.syncaddr.buf;
1730Sstevel@tonic-gate 			data->knconf =
1740Sstevel@tonic-gate 			    (struct knetconfig *)(uintptr_t)data32.knconf;
1750Sstevel@tonic-gate 			data->netname = (caddr_t)(uintptr_t)data32.netname;
1760Sstevel@tonic-gate 			data->netnamelen = data32.netnamelen;
1770Sstevel@tonic-gate 		}
1780Sstevel@tonic-gate 	} else
1790Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
1800Sstevel@tonic-gate 	if (copyin(usrdata, data, sizeof (*data)))
1810Sstevel@tonic-gate 		error = EFAULT;
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	if (error == 0) {
1840Sstevel@tonic-gate 		syncaddr = &data->syncaddr;
1850Sstevel@tonic-gate 		if (syncaddr == NULL)
1860Sstevel@tonic-gate 			error = EINVAL;
1870Sstevel@tonic-gate 		else {
1880Sstevel@tonic-gate 			userbufptr = syncaddr->buf;
1890Sstevel@tonic-gate 			syncaddr->buf =  kmem_alloc(syncaddr->len, KM_SLEEP);
1900Sstevel@tonic-gate 			syncaddr->maxlen = syncaddr->len;
1910Sstevel@tonic-gate 			if (copyin(userbufptr, syncaddr->buf, syncaddr->len)) {
1920Sstevel@tonic-gate 				kmem_free(syncaddr->buf, syncaddr->len);
1930Sstevel@tonic-gate 				syncaddr->buf = NULL;
1940Sstevel@tonic-gate 				error = EFAULT;
1950Sstevel@tonic-gate 			} else {
1960Sstevel@tonic-gate 				(void) copyinstr(data->netname, netname,
1970Sstevel@tonic-gate 				    sizeof (netname), &nlen);
1980Sstevel@tonic-gate 				if (nlen != 0) {
1990Sstevel@tonic-gate 					data->netname =
2000Sstevel@tonic-gate 					    kmem_alloc(nlen, KM_SLEEP);
2010Sstevel@tonic-gate 					bcopy(netname, data->netname, nlen);
2020Sstevel@tonic-gate 					data->netnamelen = (int)nlen;
2030Sstevel@tonic-gate 				}
2040Sstevel@tonic-gate 			}
2050Sstevel@tonic-gate 		}
2060Sstevel@tonic-gate 	}
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	if (!error) {
2090Sstevel@tonic-gate 		/*
2100Sstevel@tonic-gate 		 * Allocate space for a knetconfig structure and
2110Sstevel@tonic-gate 		 * its strings and copy in from user-land.
2120Sstevel@tonic-gate 		 */
2130Sstevel@tonic-gate 		knconf = kmem_alloc(sizeof (*knconf), KM_SLEEP);
2140Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
2150Sstevel@tonic-gate 		if (model != DATAMODEL_NATIVE) {
2160Sstevel@tonic-gate 			struct knetconfig32 knconf32;
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 			if (copyin(data->knconf, &knconf32,
2190Sstevel@tonic-gate 			    sizeof (knconf32)) == -1) {
2200Sstevel@tonic-gate 				kmem_free(knconf, sizeof (*knconf));
2210Sstevel@tonic-gate 				kmem_free(syncaddr->buf, syncaddr->len);
2220Sstevel@tonic-gate 				syncaddr->buf = NULL;
2230Sstevel@tonic-gate 				kmem_free(data->netname, nlen);
2240Sstevel@tonic-gate 				error = EFAULT;
2250Sstevel@tonic-gate 			} else {
2260Sstevel@tonic-gate 				knconf->knc_semantics = knconf32.knc_semantics;
2270Sstevel@tonic-gate 				knconf->knc_protofmly =
2280Sstevel@tonic-gate 				    (caddr_t)(uintptr_t)knconf32.knc_protofmly;
2290Sstevel@tonic-gate 				knconf->knc_proto =
2300Sstevel@tonic-gate 				    (caddr_t)(uintptr_t)knconf32.knc_proto;
2310Sstevel@tonic-gate 				knconf->knc_rdev = expldev(knconf32.knc_rdev);
2320Sstevel@tonic-gate 			}
2330Sstevel@tonic-gate 		} else
2340Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
2350Sstevel@tonic-gate 		if (copyin(data->knconf, knconf, sizeof (*knconf))) {
2360Sstevel@tonic-gate 			kmem_free(knconf, sizeof (*knconf));
2370Sstevel@tonic-gate 			kmem_free(syncaddr->buf, syncaddr->len);
2380Sstevel@tonic-gate 			syncaddr->buf = NULL;
2390Sstevel@tonic-gate 			kmem_free(data->netname, nlen);
2400Sstevel@tonic-gate 			error = EFAULT;
2410Sstevel@tonic-gate 		}
2420Sstevel@tonic-gate 	}
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	if (!error) {
2450Sstevel@tonic-gate 		size_t nmoved_tmp;
2460Sstevel@tonic-gate 		char *p, *pf;
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 		pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
2490Sstevel@tonic-gate 		p = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
2500Sstevel@tonic-gate 		error = copyinstr(knconf->knc_protofmly, pf,
2510Sstevel@tonic-gate 		    KNC_STRSIZE, &nmoved_tmp);
2520Sstevel@tonic-gate 		if (error) {
2530Sstevel@tonic-gate 			kmem_free(pf, KNC_STRSIZE);
2540Sstevel@tonic-gate 			kmem_free(p, KNC_STRSIZE);
2550Sstevel@tonic-gate 			kmem_free(knconf, sizeof (*knconf));
2560Sstevel@tonic-gate 			kmem_free(syncaddr->buf, syncaddr->len);
2570Sstevel@tonic-gate 			kmem_free(data->netname, nlen);
2580Sstevel@tonic-gate 		}
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 		if (!error) {
2610Sstevel@tonic-gate 			error = copyinstr(knconf->knc_proto,
2620Sstevel@tonic-gate 			    p, KNC_STRSIZE, &nmoved_tmp);
2630Sstevel@tonic-gate 			if (error) {
2640Sstevel@tonic-gate 				kmem_free(pf, KNC_STRSIZE);
2650Sstevel@tonic-gate 				kmem_free(p, KNC_STRSIZE);
2660Sstevel@tonic-gate 				kmem_free(knconf, sizeof (*knconf));
2670Sstevel@tonic-gate 				kmem_free(syncaddr->buf, syncaddr->len);
2680Sstevel@tonic-gate 				kmem_free(data->netname, nlen);
2690Sstevel@tonic-gate 			}
2700Sstevel@tonic-gate 		}
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 		if (!error) {
2730Sstevel@tonic-gate 			knconf->knc_protofmly = pf;
2740Sstevel@tonic-gate 			knconf->knc_proto = p;
2750Sstevel@tonic-gate 		}
2760Sstevel@tonic-gate 	}
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	if (error) {
2790Sstevel@tonic-gate 		*kdata = NULL;
2800Sstevel@tonic-gate 		kmem_free(data, sizeof (*data));
2810Sstevel@tonic-gate 		return (error);
2820Sstevel@tonic-gate 	}
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	data->knconf = knconf;
2850Sstevel@tonic-gate 	*kdata = (caddr_t)data;
2860Sstevel@tonic-gate 	return (0);
2870Sstevel@tonic-gate }
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate /*
2900Sstevel@tonic-gate  *  Free up AUTH_DES specific data.
2910Sstevel@tonic-gate  */
2920Sstevel@tonic-gate void
2930Sstevel@tonic-gate dh_k4_clnt_freeinfo(caddr_t cdata)
2940Sstevel@tonic-gate {
2950Sstevel@tonic-gate 	dh_k4_clntdata_t *data;
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	data = (dh_k4_clntdata_t *)cdata;
2980Sstevel@tonic-gate 	if (data->netnamelen > 0) {
2990Sstevel@tonic-gate 		kmem_free(data->netname, data->netnamelen);
3000Sstevel@tonic-gate 	}
3010Sstevel@tonic-gate 	if (data->syncaddr.buf != NULL) {
3020Sstevel@tonic-gate 		kmem_free(data->syncaddr.buf, data->syncaddr.len);
3030Sstevel@tonic-gate 	}
3040Sstevel@tonic-gate 	if (data->knconf != NULL) {
3050Sstevel@tonic-gate 		kmem_free(data->knconf->knc_protofmly, KNC_STRSIZE);
3060Sstevel@tonic-gate 		kmem_free(data->knconf->knc_proto, KNC_STRSIZE);
3070Sstevel@tonic-gate 		kmem_free(data->knconf, sizeof (*data->knconf));
3080Sstevel@tonic-gate 	}
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	kmem_free(data, sizeof (*data));
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate /*
3140Sstevel@tonic-gate  *  Load application auth related data from user land to kernel.
3150Sstevel@tonic-gate  *  Map opaque data field to dh_k4_clntdata_t for AUTH_DES
3160Sstevel@tonic-gate  *
3170Sstevel@tonic-gate  */
3180Sstevel@tonic-gate int
3190Sstevel@tonic-gate sec_clnt_loadinfo(struct sec_data *in, struct sec_data **out, model_t model)
3200Sstevel@tonic-gate {
3210Sstevel@tonic-gate 	struct	sec_data	*secdata;
3220Sstevel@tonic-gate 	int	error = 0;
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	secdata = kmem_alloc(sizeof (*secdata), KM_SLEEP);
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
3270Sstevel@tonic-gate 	if (model != DATAMODEL_NATIVE) {
3280Sstevel@tonic-gate 		struct sec_data32 sd32;
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 		if (copyin(in, &sd32, sizeof (sd32)) == -1) {
3310Sstevel@tonic-gate 			error = EFAULT;
3320Sstevel@tonic-gate 		} else {
3330Sstevel@tonic-gate 			secdata->secmod = sd32.secmod;
3340Sstevel@tonic-gate 			secdata->rpcflavor = sd32.rpcflavor;
3350Sstevel@tonic-gate 			secdata->uid = sd32.uid;
3360Sstevel@tonic-gate 			secdata->flags = sd32.flags;
3370Sstevel@tonic-gate 			secdata->data = (caddr_t)(uintptr_t)sd32.data;
3380Sstevel@tonic-gate 		}
3390Sstevel@tonic-gate 	} else
3400Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	if (copyin(in, secdata, sizeof (*secdata)) == -1) {
3430Sstevel@tonic-gate 		error = EFAULT;
3440Sstevel@tonic-gate 	}
3450Sstevel@tonic-gate 	/*
3460Sstevel@tonic-gate 	 * Copy in opaque data field per flavor.
3470Sstevel@tonic-gate 	 */
3480Sstevel@tonic-gate 	if (!error) {
3490Sstevel@tonic-gate 		switch (secdata->rpcflavor) {
3500Sstevel@tonic-gate 		case AUTH_NONE:
3510Sstevel@tonic-gate 		case AUTH_UNIX:
3520Sstevel@tonic-gate 		case AUTH_LOOPBACK:
3530Sstevel@tonic-gate 			break;
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 		case AUTH_DES:
3560Sstevel@tonic-gate 			error = dh_k4_clnt_loadinfo(secdata->data,
3570Sstevel@tonic-gate 			    &secdata->data, model);
3580Sstevel@tonic-gate 			break;
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 		case RPCSEC_GSS:
3610Sstevel@tonic-gate 			error = gss_clnt_loadinfo(secdata->data,
3620Sstevel@tonic-gate 			    &secdata->data, model);
3630Sstevel@tonic-gate 			break;
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 		default:
3660Sstevel@tonic-gate 			error = EINVAL;
3670Sstevel@tonic-gate 			break;
3680Sstevel@tonic-gate 		}
3690Sstevel@tonic-gate 	}
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	if (!error) {
3720Sstevel@tonic-gate 		*out = secdata;
3730Sstevel@tonic-gate 	} else {
3740Sstevel@tonic-gate 		kmem_free(secdata, sizeof (*secdata));
3750Sstevel@tonic-gate 		*out = (struct sec_data *)NULL;
3760Sstevel@tonic-gate 	}
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	return (error);
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate /*
3820Sstevel@tonic-gate  * Null the sec_data index in the cache table, and
3830Sstevel@tonic-gate  * free the memory allocated by sec_clnt_loadinfo.
3840Sstevel@tonic-gate  */
3850Sstevel@tonic-gate void
3860Sstevel@tonic-gate sec_clnt_freeinfo(struct sec_data *secdata)
3870Sstevel@tonic-gate {
3880Sstevel@tonic-gate 	switch (secdata->rpcflavor) {
3890Sstevel@tonic-gate 	case AUTH_DES:
3900Sstevel@tonic-gate 		purge_authtab(secdata);
3910Sstevel@tonic-gate 		if (secdata->data)
3920Sstevel@tonic-gate 			dh_k4_clnt_freeinfo(secdata->data);
3930Sstevel@tonic-gate 		break;
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	case RPCSEC_GSS:
3960Sstevel@tonic-gate 		rpc_gss_secpurge((void *)secdata);
3970Sstevel@tonic-gate 		if (secdata->data) {
3980Sstevel@tonic-gate 			gss_clntdata_t *gss_data;
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 			gss_data = (gss_clntdata_t *)secdata->data;
4010Sstevel@tonic-gate 			if (gss_data->mechanism.elements) {
4020Sstevel@tonic-gate 				kmem_free(gss_data->mechanism.elements,
4030Sstevel@tonic-gate 				    gss_data->mechanism.length);
4040Sstevel@tonic-gate 			}
4050Sstevel@tonic-gate 			kmem_free(secdata->data, sizeof (gss_clntdata_t));
4060Sstevel@tonic-gate 		}
4070Sstevel@tonic-gate 		break;
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	case AUTH_NONE:
4100Sstevel@tonic-gate 	case AUTH_UNIX:
4110Sstevel@tonic-gate 	case AUTH_LOOPBACK:
4120Sstevel@tonic-gate 	default:
4130Sstevel@tonic-gate 		break;
4140Sstevel@tonic-gate 	}
4150Sstevel@tonic-gate 	kmem_free(secdata, sizeof (*secdata));
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate /*
4190Sstevel@tonic-gate  *  Get an AUTH handle for a RPC client based on the given sec_data.
4200Sstevel@tonic-gate  *  If an AUTH handle exists for the same sec_data, use that AUTH handle,
4210Sstevel@tonic-gate  *  otherwise create a new one.
4220Sstevel@tonic-gate  */
4230Sstevel@tonic-gate int
4240Sstevel@tonic-gate sec_clnt_geth(CLIENT *client, struct sec_data *secdata, cred_t *cr, AUTH **ap)
4250Sstevel@tonic-gate {
4260Sstevel@tonic-gate 	int i;
4270Sstevel@tonic-gate 	struct desauthent *da;
4280Sstevel@tonic-gate 	int authflavor;
4290Sstevel@tonic-gate 	cred_t *savecred;
4300Sstevel@tonic-gate 	int stat;			/* return (errno) status */
4310Sstevel@tonic-gate 	char gss_svc_name[MAX_GSS_NAME];
4320Sstevel@tonic-gate 	dh_k4_clntdata_t	*desdata;
4330Sstevel@tonic-gate 	AUTH *auth;
4340Sstevel@tonic-gate 	gss_clntdata_t *gssdata;
4350Sstevel@tonic-gate 	zoneid_t zoneid = getzoneid();
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	if ((client == NULL) || (secdata == NULL) || (ap == NULL))
4380Sstevel@tonic-gate 		return (EINVAL);
4390Sstevel@tonic-gate 	*ap = (AUTH *)NULL;
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	authflavor = secdata->rpcflavor;
4420Sstevel@tonic-gate 	for (;;) {
443*5302Sth199096 		int nlen;
444*5302Sth199096 		char *netname;
445*5302Sth199096 
4460Sstevel@tonic-gate 		switch (authflavor) {
4470Sstevel@tonic-gate 		case AUTH_NONE:
4480Sstevel@tonic-gate 			/*
4490Sstevel@tonic-gate 			 * XXX: should do real AUTH_NONE, instead of AUTH_UNIX
4500Sstevel@tonic-gate 			 */
4510Sstevel@tonic-gate 		case AUTH_UNIX:
4520Sstevel@tonic-gate 			*ap = (AUTH *) authkern_create();
4530Sstevel@tonic-gate 			return ((*ap != NULL) ? 0 : EINTR);
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 		case AUTH_LOOPBACK:
4560Sstevel@tonic-gate 			*ap = (AUTH *) authloopback_create();
4570Sstevel@tonic-gate 			return ((*ap != NULL) ? 0 : EINTR);
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 		case AUTH_DES:
4600Sstevel@tonic-gate 			mutex_enter(&desauthtab_lock);
4610Sstevel@tonic-gate 			if (desauthtab == NULL) {
4620Sstevel@tonic-gate 				desauthtab = kmem_zalloc(clnt_authdes_cachesz *
4630Sstevel@tonic-gate 				    sizeof (struct desauthent), KM_SLEEP);
4640Sstevel@tonic-gate 			}
4650Sstevel@tonic-gate 			for (da = desauthtab;
4660Sstevel@tonic-gate 			    da < &desauthtab[clnt_authdes_cachesz];
4670Sstevel@tonic-gate 			    da++) {
4680Sstevel@tonic-gate 				if (da->da_data == secdata &&
4690Sstevel@tonic-gate 				    da->da_uid == crgetuid(cr) &&
4700Sstevel@tonic-gate 				    da->da_zoneid == zoneid &&
4710Sstevel@tonic-gate 				    !da->da_inuse &&
4720Sstevel@tonic-gate 				    da->da_auth != NULL) {
4730Sstevel@tonic-gate 					da->da_inuse = 1;
4740Sstevel@tonic-gate 					mutex_exit(&desauthtab_lock);
4750Sstevel@tonic-gate 					*ap = da->da_auth;
4760Sstevel@tonic-gate 					return (0);
4770Sstevel@tonic-gate 				}
4780Sstevel@tonic-gate 			}
4790Sstevel@tonic-gate 			mutex_exit(&desauthtab_lock);
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 			/*
4820Sstevel@tonic-gate 			 *  A better way would be to have a cred paramater to
4830Sstevel@tonic-gate 			 *  authdes_create.
4840Sstevel@tonic-gate 			 */
4850Sstevel@tonic-gate 			savecred = curthread->t_cred;
4860Sstevel@tonic-gate 			curthread->t_cred = cr;
487*5302Sth199096 
488*5302Sth199096 			/*
489*5302Sth199096 			 * Note that authdes_create() expects a
490*5302Sth199096 			 * NUL-terminated string for netname, but
491*5302Sth199096 			 * dh_k4_clntdata_t gives us netname & netnamelen.
492*5302Sth199096 			 *
493*5302Sth199096 			 * We must create a string for authdes_create();
494*5302Sth199096 			 * the latter takes a copy of it, so we may
495*5302Sth199096 			 * immediately free it.
496*5302Sth199096 			 */
4970Sstevel@tonic-gate 			desdata = (dh_k4_clntdata_t *)secdata->data;
498*5302Sth199096 			nlen = desdata->netnamelen;
499*5302Sth199096 			/* must be NUL-terminated */
500*5302Sth199096 			netname = kmem_zalloc(nlen + 1, KM_SLEEP);
501*5302Sth199096 			bcopy(desdata->netname, netname, nlen);
502*5302Sth199096 			stat = authdes_create(netname, authdes_win,
503*5302Sth199096 			    &desdata->syncaddr, desdata->knconf,
504*5302Sth199096 			    (des_block *)NULL,
505*5302Sth199096 			    (secdata->flags & AUTH_F_RPCTIMESYNC) ? 1 : 0,
506*5302Sth199096 			    &auth);
507*5302Sth199096 			kmem_free(netname, nlen + 1);
508*5302Sth199096 
5090Sstevel@tonic-gate 			curthread->t_cred = savecred;
5100Sstevel@tonic-gate 			*ap = auth;
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 			if (stat != 0) {
5130Sstevel@tonic-gate 				/*
5140Sstevel@tonic-gate 				 *  If AUTH_F_TRYNONE is on, try again
5150Sstevel@tonic-gate 				 *  with AUTH_NONE.  See bug 1180236.
5160Sstevel@tonic-gate 				 */
5170Sstevel@tonic-gate 				if (secdata->flags & AUTH_F_TRYNONE) {
5180Sstevel@tonic-gate 					authflavor = AUTH_NONE;
5190Sstevel@tonic-gate 					continue;
5200Sstevel@tonic-gate 				} else
5210Sstevel@tonic-gate 					return (stat);
5220Sstevel@tonic-gate 			}
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 			i = clnt_authdes_cachesz;
5250Sstevel@tonic-gate 			mutex_enter(&desauthtab_lock);
5260Sstevel@tonic-gate 			do {
5270Sstevel@tonic-gate 				da = &desauthtab[nextdesvictim++];
5280Sstevel@tonic-gate 				nextdesvictim %= clnt_authdes_cachesz;
5290Sstevel@tonic-gate 			} while (da->da_inuse && --i > 0);
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 			if (da->da_inuse) {
5320Sstevel@tonic-gate 				mutex_exit(&desauthtab_lock);
5330Sstevel@tonic-gate 				/* overflow of des auths */
5340Sstevel@tonic-gate 				return (stat);
5350Sstevel@tonic-gate 			}
5360Sstevel@tonic-gate 			da->da_inuse = 1;
5370Sstevel@tonic-gate 			mutex_exit(&desauthtab_lock);
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 			if (da->da_auth != NULL)
5400Sstevel@tonic-gate 				auth_destroy(da->da_auth);
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 			da->da_auth = auth;
5430Sstevel@tonic-gate 			da->da_uid = crgetuid(cr);
5440Sstevel@tonic-gate 			da->da_zoneid = zoneid;
5450Sstevel@tonic-gate 			da->da_data = secdata;
5460Sstevel@tonic-gate 			return (stat);
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 		case RPCSEC_GSS:
5490Sstevel@tonic-gate 			/*
5500Sstevel@tonic-gate 			 *  For RPCSEC_GSS, cache is done in rpc_gss_secget().
5510Sstevel@tonic-gate 			 *  For every rpc_gss_secget(),  it should have
5520Sstevel@tonic-gate 			 *  a corresponding rpc_gss_secfree() call.
5530Sstevel@tonic-gate 			 */
5540Sstevel@tonic-gate 			gssdata = (gss_clntdata_t *)secdata->data;
5550Sstevel@tonic-gate 			(void) sprintf(gss_svc_name, "%s@%s", gssdata->uname,
5560Sstevel@tonic-gate 			    gssdata->inst);
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 			stat = rpc_gss_secget(client, gss_svc_name,
5590Sstevel@tonic-gate 			    &gssdata->mechanism,
5600Sstevel@tonic-gate 			    gssdata->service,
5610Sstevel@tonic-gate 			    gssdata->qop,
5620Sstevel@tonic-gate 			    NULL, NULL,
5630Sstevel@tonic-gate 			    (caddr_t)secdata, cr, &auth);
5640Sstevel@tonic-gate 			*ap = auth;
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 			/* success */
5670Sstevel@tonic-gate 			if (stat == 0)
5680Sstevel@tonic-gate 				return (stat);
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 			/*
5710Sstevel@tonic-gate 			 * let the caller retry if connection timedout
5720Sstevel@tonic-gate 			 * or reset.
5730Sstevel@tonic-gate 			 */
5740Sstevel@tonic-gate 			if (stat == ETIMEDOUT || stat == ECONNRESET)
5750Sstevel@tonic-gate 				return (stat);
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 			/*
5780Sstevel@tonic-gate 			 *  If AUTH_F_TRYNONE is on, try again
5790Sstevel@tonic-gate 			 *  with AUTH_NONE.  See bug 1180236.
5800Sstevel@tonic-gate 			 */
5810Sstevel@tonic-gate 			if (secdata->flags & AUTH_F_TRYNONE) {
5820Sstevel@tonic-gate 				authflavor = AUTH_NONE;
5830Sstevel@tonic-gate 				continue;
5840Sstevel@tonic-gate 			}
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 			RPCLOG(1, "sec_clnt_geth: rpc_gss_secget"
587*5302Sth199096 			    " failed with %d", stat);
5880Sstevel@tonic-gate 			return (stat);
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 		default:
5910Sstevel@tonic-gate 			/*
5920Sstevel@tonic-gate 			 * auth create must have failed, try AUTH_NONE
5930Sstevel@tonic-gate 			 * (this relies on AUTH_NONE never failing)
5940Sstevel@tonic-gate 			 */
5950Sstevel@tonic-gate 			cmn_err(CE_NOTE, "sec_clnt_geth: unknown "
5960Sstevel@tonic-gate 			    "authflavor %d, trying AUTH_NONE", authflavor);
5970Sstevel@tonic-gate 			authflavor = AUTH_NONE;
5980Sstevel@tonic-gate 		}
5990Sstevel@tonic-gate 	}
6000Sstevel@tonic-gate }
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate void
6030Sstevel@tonic-gate sec_clnt_freeh(AUTH *auth)
6040Sstevel@tonic-gate {
6050Sstevel@tonic-gate 	struct desauthent *da;
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	switch (auth->ah_cred.oa_flavor) {
6080Sstevel@tonic-gate 	case AUTH_NONE: /* XXX: do real AUTH_NONE */
6090Sstevel@tonic-gate 	case AUTH_UNIX:
6100Sstevel@tonic-gate 	case AUTH_LOOPBACK:
6110Sstevel@tonic-gate 		auth_destroy(auth);	/* was overflow */
6120Sstevel@tonic-gate 		break;
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	case AUTH_DES:
6150Sstevel@tonic-gate 		mutex_enter(&desauthtab_lock);
6160Sstevel@tonic-gate 		if (desauthtab != NULL) {
617*5302Sth199096 			for (da = desauthtab;
618*5302Sth199096 			    da < &desauthtab[clnt_authdes_cachesz]; da++) {
619*5302Sth199096 				if (da->da_auth == auth) {
620*5302Sth199096 					da->da_inuse = 0;
621*5302Sth199096 					mutex_exit(&desauthtab_lock);
622*5302Sth199096 					return;
623*5302Sth199096 				}
6240Sstevel@tonic-gate 			}
6250Sstevel@tonic-gate 		}
6260Sstevel@tonic-gate 		mutex_exit(&desauthtab_lock);
6270Sstevel@tonic-gate 		auth_destroy(auth);	/* was overflow */
6280Sstevel@tonic-gate 		break;
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 	case RPCSEC_GSS:
6310Sstevel@tonic-gate 		(void) rpc_gss_secfree(auth);
6320Sstevel@tonic-gate 		break;
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 	default:
6350Sstevel@tonic-gate 		cmn_err(CE_NOTE, "sec_clnt_freeh: unknown authflavor %d",
636*5302Sth199096 		    auth->ah_cred.oa_flavor);
6370Sstevel@tonic-gate 		break;
6380Sstevel@tonic-gate 	}
6390Sstevel@tonic-gate }
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate /*
6420Sstevel@tonic-gate  *  Revoke the authentication key in the given AUTH handle by setting
6430Sstevel@tonic-gate  *  it to NULL.  If newkey is true, then generate a new key instead of
6440Sstevel@tonic-gate  *  nulling out the old one.  This is necessary for AUTH_DES because
6450Sstevel@tonic-gate  *  the new key will be used next time the user does a keylogin.  If
6460Sstevel@tonic-gate  *  the zero'd key is used as actual key, then it cannot be revoked
6470Sstevel@tonic-gate  *  again!
6480Sstevel@tonic-gate  */
6490Sstevel@tonic-gate void
6500Sstevel@tonic-gate revoke_key(AUTH *auth, int newkey)
6510Sstevel@tonic-gate {
6520Sstevel@tonic-gate 	if (auth == NULL)
6530Sstevel@tonic-gate 		return;
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 	if (newkey) {
6560Sstevel@tonic-gate 		if (key_gendes(&auth->ah_key) != RPC_SUCCESS) {
6570Sstevel@tonic-gate 			/* failed to get new key, munge the old one */
6580Sstevel@tonic-gate 			auth->ah_key.key.high ^= auth->ah_key.key.low;
6590Sstevel@tonic-gate 			auth->ah_key.key.low  += auth->ah_key.key.high;
6600Sstevel@tonic-gate 		}
6610Sstevel@tonic-gate 	} else {
6620Sstevel@tonic-gate 		/* null out old key */
6630Sstevel@tonic-gate 		auth->ah_key.key.high = 0;
6640Sstevel@tonic-gate 		auth->ah_key.key.low  = 0;
6650Sstevel@tonic-gate 	}
6660Sstevel@tonic-gate }
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate /*
6690Sstevel@tonic-gate  *  Revoke all rpc credentials (of the selected auth type) for the given uid
6700Sstevel@tonic-gate  *  from the auth cache.  Must be root to do this if the requested uid is not
6710Sstevel@tonic-gate  *  the effective uid of the requestor.
6720Sstevel@tonic-gate  *
6730Sstevel@tonic-gate  *  Called from nfssys() for backward compatibility, and also
6740Sstevel@tonic-gate  *  called from krpc_sys().
6750Sstevel@tonic-gate  *
6760Sstevel@tonic-gate  *  AUTH_DES does not refer to the "mechanism" information.
6770Sstevel@tonic-gate  *  RPCSEC_GSS requires the "mechanism" input.
6780Sstevel@tonic-gate  *  The input argument, mechanism, is a user-space address and needs
6790Sstevel@tonic-gate  *  to be copied into the kernel address space.
6800Sstevel@tonic-gate  *
6810Sstevel@tonic-gate  *  Returns error number.
6820Sstevel@tonic-gate  */
6830Sstevel@tonic-gate /*ARGSUSED*/
6840Sstevel@tonic-gate int
6850Sstevel@tonic-gate sec_clnt_revoke(int rpcflavor, uid_t uid, cred_t *cr, void *mechanism,
6860Sstevel@tonic-gate 						model_t model)
6870Sstevel@tonic-gate {
6880Sstevel@tonic-gate 	struct desauthent *da;
6890Sstevel@tonic-gate 	int error = 0;
6900Sstevel@tonic-gate 	zoneid_t zoneid = getzoneid();
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	if (uid != crgetuid(cr) && secpolicy_nfs(cr) != 0)
6930Sstevel@tonic-gate 		return (EPERM);
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	switch (rpcflavor) {
6960Sstevel@tonic-gate 	case AUTH_DES:
6970Sstevel@tonic-gate 		mutex_enter(&desauthtab_lock);
6980Sstevel@tonic-gate 		if (desauthtab != NULL) {
699*5302Sth199096 			for (da = desauthtab;
700*5302Sth199096 			    da < &desauthtab[clnt_authdes_cachesz]; da++) {
701*5302Sth199096 				if (uid == da->da_uid &&
702*5302Sth199096 				    zoneid == da->da_zoneid)
703*5302Sth199096 					revoke_key(da->da_auth, 1);
704*5302Sth199096 			}
7050Sstevel@tonic-gate 		}
7060Sstevel@tonic-gate 		mutex_exit(&desauthtab_lock);
7070Sstevel@tonic-gate 		return (0);
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 	case RPCSEC_GSS: {
7100Sstevel@tonic-gate 		rpc_gss_OID	mech;
7110Sstevel@tonic-gate 		caddr_t		elements;
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 		if (!mechanism)
7140Sstevel@tonic-gate 			return (EINVAL);
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 		/* copyin the gss mechanism type */
7170Sstevel@tonic-gate 		mech = kmem_alloc(sizeof (rpc_gss_OID_desc), KM_SLEEP);
7180Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
7190Sstevel@tonic-gate 		if (model != DATAMODEL_NATIVE) {
7200Sstevel@tonic-gate 			gss_OID_desc32 mech32;
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 			if (copyin(mechanism, &mech32,
7230Sstevel@tonic-gate 			    sizeof (gss_OID_desc32))) {
7240Sstevel@tonic-gate 				kmem_free(mech, sizeof (rpc_gss_OID_desc));
7250Sstevel@tonic-gate 				return (EFAULT);
7260Sstevel@tonic-gate 			}
7270Sstevel@tonic-gate 			mech->length = mech32.length;
7280Sstevel@tonic-gate 			mech->elements = (caddr_t)(uintptr_t)mech32.elements;
7290Sstevel@tonic-gate 		} else
7300Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
7310Sstevel@tonic-gate 		if (copyin(mechanism, mech, sizeof (rpc_gss_OID_desc))) {
7320Sstevel@tonic-gate 			kmem_free(mech, sizeof (rpc_gss_OID_desc));
7330Sstevel@tonic-gate 			return (EFAULT);
7340Sstevel@tonic-gate 		}
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 		elements = kmem_alloc(mech->length, KM_SLEEP);
7370Sstevel@tonic-gate 		if (copyin(mech->elements, elements, mech->length)) {
7380Sstevel@tonic-gate 			kmem_free(elements, mech->length);
7390Sstevel@tonic-gate 			kmem_free(mech, sizeof (rpc_gss_OID_desc));
7400Sstevel@tonic-gate 			return (EFAULT);
7410Sstevel@tonic-gate 		}
7420Sstevel@tonic-gate 		mech->elements = elements;
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 		error = rpc_gss_revauth(uid, mech);
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 		kmem_free(elements, mech->length);
7470Sstevel@tonic-gate 		kmem_free(mech, sizeof (rpc_gss_OID_desc));
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 		return (error);
7500Sstevel@tonic-gate 	}
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 	default:
7530Sstevel@tonic-gate 		/* not an auth type with cached creds */
7540Sstevel@tonic-gate 		return (EINVAL);
7550Sstevel@tonic-gate 	}
7560Sstevel@tonic-gate }
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate /*
7590Sstevel@tonic-gate  *  Since sec_data is the index for the client auth handles
7600Sstevel@tonic-gate  *  cache table,  whenever the sec_data is freed, the index needs
7610Sstevel@tonic-gate  *  to be nulled.
7620Sstevel@tonic-gate  */
7630Sstevel@tonic-gate void
7640Sstevel@tonic-gate purge_authtab(struct sec_data *secdata)
7650Sstevel@tonic-gate {
7660Sstevel@tonic-gate 	struct desauthent *da;
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	switch (secdata->rpcflavor) {
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	case AUTH_DES:
7710Sstevel@tonic-gate 		mutex_enter(&desauthtab_lock);
7720Sstevel@tonic-gate 		if (desauthtab != NULL) {
773*5302Sth199096 			for (da = desauthtab;
774*5302Sth199096 			    da < &desauthtab[clnt_authdes_cachesz]; da++) {
775*5302Sth199096 				if (da->da_data == secdata) {
776*5302Sth199096 					da->da_data = NULL;
777*5302Sth199096 					da->da_inuse = 0;
778*5302Sth199096 				}
7790Sstevel@tonic-gate 			}
7800Sstevel@tonic-gate 		}
7810Sstevel@tonic-gate 		mutex_exit(&desauthtab_lock);
7820Sstevel@tonic-gate 		return;
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 	case RPCSEC_GSS:
7850Sstevel@tonic-gate 		rpc_gss_secpurge((void *)secdata);
7860Sstevel@tonic-gate 		return;
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	default:
7890Sstevel@tonic-gate 		return;
7900Sstevel@tonic-gate 	}
7910Sstevel@tonic-gate }
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate void
7940Sstevel@tonic-gate sec_subrinit(void)
7950Sstevel@tonic-gate {
7960Sstevel@tonic-gate 	authkern_cache = kmem_cache_create("authkern_cache",
7970Sstevel@tonic-gate 	    sizeof (AUTH), 0, authkern_init, NULL, NULL, NULL, NULL, 0);
7980Sstevel@tonic-gate 	authloopback_cache = kmem_cache_create("authloopback_cache",
7990Sstevel@tonic-gate 	    sizeof (AUTH), 0, authloopback_init, NULL, NULL, NULL, NULL, 0);
8000Sstevel@tonic-gate 	mutex_init(&desauthtab_lock, NULL, MUTEX_DEFAULT, NULL);
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	/* RPC stuff */
8030Sstevel@tonic-gate 	mutex_init(&authdes_ops_lock, NULL, MUTEX_DEFAULT, NULL);
8040Sstevel@tonic-gate 	zone_key_create(&auth_zone_key, auth_zone_init, NULL, auth_zone_fini);
8050Sstevel@tonic-gate }
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate /*
8080Sstevel@tonic-gate  * Destroys the caches and mutexes previously allocated and initialized
8090Sstevel@tonic-gate  * in sec_subrinit().
8100Sstevel@tonic-gate  * This routine is called by _init() if mod_install() failed.
8110Sstevel@tonic-gate  */
8120Sstevel@tonic-gate void
8130Sstevel@tonic-gate sec_subrfini(void)
8140Sstevel@tonic-gate {
8150Sstevel@tonic-gate 	mutex_destroy(&desauthtab_lock);
8160Sstevel@tonic-gate 	kmem_cache_destroy(authkern_cache);
8170Sstevel@tonic-gate 	kmem_cache_destroy(authloopback_cache);
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 	/* RPC stuff */
8200Sstevel@tonic-gate 	mutex_destroy(&authdes_ops_lock);
8210Sstevel@tonic-gate 	(void) zone_key_delete(auth_zone_key);
8220Sstevel@tonic-gate }
823