1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/param.h>
30*0Sstevel@tonic-gate #include <sys/types.h>
31*0Sstevel@tonic-gate #include <sys/systm.h>
32*0Sstevel@tonic-gate #include <sys/cred.h>
33*0Sstevel@tonic-gate #include <sys/proc.h>
34*0Sstevel@tonic-gate #include <sys/user.h>
35*0Sstevel@tonic-gate #include <sys/time.h>
36*0Sstevel@tonic-gate #include <sys/buf.h>
37*0Sstevel@tonic-gate #include <sys/vfs.h>
38*0Sstevel@tonic-gate #include <sys/vnode.h>
39*0Sstevel@tonic-gate #include <sys/socket.h>
40*0Sstevel@tonic-gate #include <sys/stat.h>
41*0Sstevel@tonic-gate #include <sys/uio.h>
42*0Sstevel@tonic-gate #include <sys/tiuser.h>
43*0Sstevel@tonic-gate #include <sys/swap.h>
44*0Sstevel@tonic-gate #include <sys/errno.h>
45*0Sstevel@tonic-gate #include <sys/debug.h>
46*0Sstevel@tonic-gate #include <sys/kmem.h>
47*0Sstevel@tonic-gate #include <sys/kstat.h>
48*0Sstevel@tonic-gate #include <sys/cmn_err.h>
49*0Sstevel@tonic-gate #include <sys/vtrace.h>
50*0Sstevel@tonic-gate #include <sys/session.h>
51*0Sstevel@tonic-gate #include <sys/dnlc.h>
52*0Sstevel@tonic-gate #include <sys/bitmap.h>
53*0Sstevel@tonic-gate #include <sys/thread.h>
54*0Sstevel@tonic-gate #include <sys/policy.h>
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate #include <netinet/in.h>
57*0Sstevel@tonic-gate #include <rpc/types.h>
58*0Sstevel@tonic-gate #include <rpc/xdr.h>
59*0Sstevel@tonic-gate #include <rpc/auth.h>
60*0Sstevel@tonic-gate #include <rpc/auth_des.h>	/* for authdes_create() */
61*0Sstevel@tonic-gate #include <rpc/clnt.h>
62*0Sstevel@tonic-gate #include <rpc/rpcsec_gss.h>
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate #define	MAXCLIENTS	16
65*0Sstevel@tonic-gate static int clnt_authdes_cachesz = 64;
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate static uint_t authdes_win = 5*60;  /* 5 minutes -- should be mount option */
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate struct kmem_cache *authkern_cache;
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate struct kmem_cache *authloopback_cache;
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate static struct desauthent {
74*0Sstevel@tonic-gate 	struct	sec_data *da_data;
75*0Sstevel@tonic-gate 	uid_t da_uid;
76*0Sstevel@tonic-gate 	zoneid_t da_zoneid;
77*0Sstevel@tonic-gate 	short da_inuse;
78*0Sstevel@tonic-gate 	AUTH *da_auth;
79*0Sstevel@tonic-gate } *desauthtab;
80*0Sstevel@tonic-gate static int nextdesvictim;
81*0Sstevel@tonic-gate static kmutex_t desauthtab_lock;	/* Lock to protect DES auth cache */
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate /* RPC stuff */
84*0Sstevel@tonic-gate kmutex_t authdes_ops_lock;   /* auth_ops initialization in authdes_ops() */
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate static void  purge_authtab(struct sec_data *);
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate /* Zone stuff */
89*0Sstevel@tonic-gate zone_key_t auth_zone_key;
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate /*
92*0Sstevel@tonic-gate  *  Load RPCSEC_GSS specific data from user space to kernel space.
93*0Sstevel@tonic-gate  */
94*0Sstevel@tonic-gate /*ARGSUSED*/
95*0Sstevel@tonic-gate static int
96*0Sstevel@tonic-gate gss_clnt_loadinfo(caddr_t usrdata, caddr_t *kdata, model_t model)
97*0Sstevel@tonic-gate {
98*0Sstevel@tonic-gate 	struct gss_clnt_data *data;
99*0Sstevel@tonic-gate 	caddr_t	elements;
100*0Sstevel@tonic-gate 	int error = 0;
101*0Sstevel@tonic-gate 
102*0Sstevel@tonic-gate 	/* map opaque data to gss specific structure */
103*0Sstevel@tonic-gate 	data = kmem_alloc(sizeof (*data), KM_SLEEP);
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
106*0Sstevel@tonic-gate 	if (model != DATAMODEL_NATIVE) {
107*0Sstevel@tonic-gate 		struct gss_clnt_data32 gd32;
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 		if (copyin(usrdata, &gd32, sizeof (gd32)) == -1) {
110*0Sstevel@tonic-gate 			error = EFAULT;
111*0Sstevel@tonic-gate 		} else {
112*0Sstevel@tonic-gate 			data->mechanism.length = gd32.mechanism.length;
113*0Sstevel@tonic-gate 			data->mechanism.elements =
114*0Sstevel@tonic-gate 				(caddr_t)(uintptr_t)gd32.mechanism.elements;
115*0Sstevel@tonic-gate 			data->service = gd32.service;
116*0Sstevel@tonic-gate 			bcopy(gd32.uname, data->uname, sizeof (gd32.uname));
117*0Sstevel@tonic-gate 			bcopy(gd32.inst, data->inst, sizeof (gd32.inst));
118*0Sstevel@tonic-gate 			bcopy(gd32.realm, data->realm, sizeof (gd32.realm));
119*0Sstevel@tonic-gate 			data->qop = gd32.qop;
120*0Sstevel@tonic-gate 		}
121*0Sstevel@tonic-gate 	} else
122*0Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
123*0Sstevel@tonic-gate 	if (copyin(usrdata, data, sizeof (*data)))
124*0Sstevel@tonic-gate 		error = EFAULT;
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate 	if (error == 0) {
127*0Sstevel@tonic-gate 		if (data->mechanism.length > 0) {
128*0Sstevel@tonic-gate 			elements = kmem_alloc(data->mechanism.length, KM_SLEEP);
129*0Sstevel@tonic-gate 			if (!(copyin(data->mechanism.elements, elements,
130*0Sstevel@tonic-gate 			    data->mechanism.length))) {
131*0Sstevel@tonic-gate 				data->mechanism.elements = elements;
132*0Sstevel@tonic-gate 				*kdata = (caddr_t)data;
133*0Sstevel@tonic-gate 				return (0);
134*0Sstevel@tonic-gate 			} else
135*0Sstevel@tonic-gate 				kmem_free(elements, data->mechanism.length);
136*0Sstevel@tonic-gate 		}
137*0Sstevel@tonic-gate 	} else {
138*0Sstevel@tonic-gate 		*kdata = NULL;
139*0Sstevel@tonic-gate 		kmem_free(data, sizeof (*data));
140*0Sstevel@tonic-gate 	}
141*0Sstevel@tonic-gate 	return (EFAULT);
142*0Sstevel@tonic-gate }
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate /*
146*0Sstevel@tonic-gate  *  Load AUTH_DES specific data from user space to kernel space.
147*0Sstevel@tonic-gate  */
148*0Sstevel@tonic-gate /*ARGSUSED2*/
149*0Sstevel@tonic-gate int
150*0Sstevel@tonic-gate dh_k4_clnt_loadinfo(caddr_t usrdata, caddr_t *kdata, model_t model)
151*0Sstevel@tonic-gate {
152*0Sstevel@tonic-gate 	size_t nlen;
153*0Sstevel@tonic-gate 	int error = 0;
154*0Sstevel@tonic-gate 	char *userbufptr;
155*0Sstevel@tonic-gate 	dh_k4_clntdata_t *data;
156*0Sstevel@tonic-gate 	char netname[MAXNETNAMELEN+1];
157*0Sstevel@tonic-gate 	struct netbuf *syncaddr;
158*0Sstevel@tonic-gate 	struct knetconfig *knconf;
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate 	/* map opaque data to des specific strucutre */
161*0Sstevel@tonic-gate 	data = kmem_alloc(sizeof (*data), KM_SLEEP);
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
164*0Sstevel@tonic-gate 	if (model != DATAMODEL_NATIVE) {
165*0Sstevel@tonic-gate 		struct des_clnt_data32 data32;
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate 		if (copyin(usrdata, &data32, sizeof (data32)) == -1) {
168*0Sstevel@tonic-gate 			error = EFAULT;
169*0Sstevel@tonic-gate 		} else {
170*0Sstevel@tonic-gate 			data->syncaddr.maxlen = data32.syncaddr.maxlen;
171*0Sstevel@tonic-gate 			data->syncaddr.len = data32.syncaddr.len;
172*0Sstevel@tonic-gate 			data->syncaddr.buf =
173*0Sstevel@tonic-gate 			    (caddr_t)(uintptr_t)data32.syncaddr.buf;
174*0Sstevel@tonic-gate 			data->knconf =
175*0Sstevel@tonic-gate 			    (struct knetconfig *)(uintptr_t)data32.knconf;
176*0Sstevel@tonic-gate 			data->netname = (caddr_t)(uintptr_t)data32.netname;
177*0Sstevel@tonic-gate 			data->netnamelen = data32.netnamelen;
178*0Sstevel@tonic-gate 		}
179*0Sstevel@tonic-gate 	} else
180*0Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
181*0Sstevel@tonic-gate 	if (copyin(usrdata, data, sizeof (*data)))
182*0Sstevel@tonic-gate 		error = EFAULT;
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 	if (error == 0) {
185*0Sstevel@tonic-gate 		syncaddr = &data->syncaddr;
186*0Sstevel@tonic-gate 		if (syncaddr == NULL)
187*0Sstevel@tonic-gate 			error = EINVAL;
188*0Sstevel@tonic-gate 		else {
189*0Sstevel@tonic-gate 			userbufptr = syncaddr->buf;
190*0Sstevel@tonic-gate 			syncaddr->buf =  kmem_alloc(syncaddr->len, KM_SLEEP);
191*0Sstevel@tonic-gate 			syncaddr->maxlen = syncaddr->len;
192*0Sstevel@tonic-gate 			if (copyin(userbufptr, syncaddr->buf, syncaddr->len)) {
193*0Sstevel@tonic-gate 				kmem_free(syncaddr->buf, syncaddr->len);
194*0Sstevel@tonic-gate 				syncaddr->buf = NULL;
195*0Sstevel@tonic-gate 				error = EFAULT;
196*0Sstevel@tonic-gate 			} else {
197*0Sstevel@tonic-gate 				(void) copyinstr(data->netname, netname,
198*0Sstevel@tonic-gate 				    sizeof (netname), &nlen);
199*0Sstevel@tonic-gate 				if (nlen != 0) {
200*0Sstevel@tonic-gate 					data->netname =
201*0Sstevel@tonic-gate 					    kmem_alloc(nlen, KM_SLEEP);
202*0Sstevel@tonic-gate 					bcopy(netname, data->netname, nlen);
203*0Sstevel@tonic-gate 					data->netnamelen = (int)nlen;
204*0Sstevel@tonic-gate 				}
205*0Sstevel@tonic-gate 			}
206*0Sstevel@tonic-gate 		}
207*0Sstevel@tonic-gate 	}
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	if (!error) {
210*0Sstevel@tonic-gate 		/*
211*0Sstevel@tonic-gate 		 * Allocate space for a knetconfig structure and
212*0Sstevel@tonic-gate 		 * its strings and copy in from user-land.
213*0Sstevel@tonic-gate 		 */
214*0Sstevel@tonic-gate 		knconf = kmem_alloc(sizeof (*knconf), KM_SLEEP);
215*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
216*0Sstevel@tonic-gate 		if (model != DATAMODEL_NATIVE) {
217*0Sstevel@tonic-gate 			struct knetconfig32 knconf32;
218*0Sstevel@tonic-gate 
219*0Sstevel@tonic-gate 			if (copyin(data->knconf, &knconf32,
220*0Sstevel@tonic-gate 			    sizeof (knconf32)) == -1) {
221*0Sstevel@tonic-gate 				kmem_free(knconf, sizeof (*knconf));
222*0Sstevel@tonic-gate 				kmem_free(syncaddr->buf, syncaddr->len);
223*0Sstevel@tonic-gate 				syncaddr->buf = NULL;
224*0Sstevel@tonic-gate 				kmem_free(data->netname, nlen);
225*0Sstevel@tonic-gate 				error = EFAULT;
226*0Sstevel@tonic-gate 			} else {
227*0Sstevel@tonic-gate 				knconf->knc_semantics = knconf32.knc_semantics;
228*0Sstevel@tonic-gate 				knconf->knc_protofmly =
229*0Sstevel@tonic-gate 				    (caddr_t)(uintptr_t)knconf32.knc_protofmly;
230*0Sstevel@tonic-gate 				knconf->knc_proto =
231*0Sstevel@tonic-gate 				    (caddr_t)(uintptr_t)knconf32.knc_proto;
232*0Sstevel@tonic-gate 				knconf->knc_rdev = expldev(knconf32.knc_rdev);
233*0Sstevel@tonic-gate 			}
234*0Sstevel@tonic-gate 		} else
235*0Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
236*0Sstevel@tonic-gate 		if (copyin(data->knconf, knconf, sizeof (*knconf))) {
237*0Sstevel@tonic-gate 			kmem_free(knconf, sizeof (*knconf));
238*0Sstevel@tonic-gate 			kmem_free(syncaddr->buf, syncaddr->len);
239*0Sstevel@tonic-gate 			syncaddr->buf = NULL;
240*0Sstevel@tonic-gate 			kmem_free(data->netname, nlen);
241*0Sstevel@tonic-gate 			error = EFAULT;
242*0Sstevel@tonic-gate 		}
243*0Sstevel@tonic-gate 	}
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 	if (!error) {
246*0Sstevel@tonic-gate 		size_t nmoved_tmp;
247*0Sstevel@tonic-gate 		char *p, *pf;
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 		pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
250*0Sstevel@tonic-gate 		p = kmem_alloc(KNC_STRSIZE, KM_SLEEP);
251*0Sstevel@tonic-gate 		error = copyinstr(knconf->knc_protofmly, pf,
252*0Sstevel@tonic-gate 		    KNC_STRSIZE, &nmoved_tmp);
253*0Sstevel@tonic-gate 		if (error) {
254*0Sstevel@tonic-gate 			kmem_free(pf, KNC_STRSIZE);
255*0Sstevel@tonic-gate 			kmem_free(p, KNC_STRSIZE);
256*0Sstevel@tonic-gate 			kmem_free(knconf, sizeof (*knconf));
257*0Sstevel@tonic-gate 			kmem_free(syncaddr->buf, syncaddr->len);
258*0Sstevel@tonic-gate 			kmem_free(data->netname, nlen);
259*0Sstevel@tonic-gate 		}
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate 		if (!error) {
262*0Sstevel@tonic-gate 			error = copyinstr(knconf->knc_proto,
263*0Sstevel@tonic-gate 			    p, KNC_STRSIZE, &nmoved_tmp);
264*0Sstevel@tonic-gate 			if (error) {
265*0Sstevel@tonic-gate 				kmem_free(pf, KNC_STRSIZE);
266*0Sstevel@tonic-gate 				kmem_free(p, KNC_STRSIZE);
267*0Sstevel@tonic-gate 				kmem_free(knconf, sizeof (*knconf));
268*0Sstevel@tonic-gate 				kmem_free(syncaddr->buf, syncaddr->len);
269*0Sstevel@tonic-gate 				kmem_free(data->netname, nlen);
270*0Sstevel@tonic-gate 			}
271*0Sstevel@tonic-gate 		}
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 		if (!error) {
274*0Sstevel@tonic-gate 			knconf->knc_protofmly = pf;
275*0Sstevel@tonic-gate 			knconf->knc_proto = p;
276*0Sstevel@tonic-gate 		}
277*0Sstevel@tonic-gate 	}
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate 	if (error) {
280*0Sstevel@tonic-gate 		*kdata = NULL;
281*0Sstevel@tonic-gate 		kmem_free(data, sizeof (*data));
282*0Sstevel@tonic-gate 		return (error);
283*0Sstevel@tonic-gate 	}
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 	data->knconf = knconf;
286*0Sstevel@tonic-gate 	*kdata = (caddr_t)data;
287*0Sstevel@tonic-gate 	return (0);
288*0Sstevel@tonic-gate }
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate /*
291*0Sstevel@tonic-gate  *  Free up AUTH_DES specific data.
292*0Sstevel@tonic-gate  */
293*0Sstevel@tonic-gate void
294*0Sstevel@tonic-gate dh_k4_clnt_freeinfo(caddr_t cdata)
295*0Sstevel@tonic-gate {
296*0Sstevel@tonic-gate 	dh_k4_clntdata_t *data;
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	data = (dh_k4_clntdata_t *)cdata;
299*0Sstevel@tonic-gate 	if (data->netnamelen > 0) {
300*0Sstevel@tonic-gate 		kmem_free(data->netname, data->netnamelen);
301*0Sstevel@tonic-gate 	}
302*0Sstevel@tonic-gate 	if (data->syncaddr.buf != NULL) {
303*0Sstevel@tonic-gate 		kmem_free(data->syncaddr.buf, data->syncaddr.len);
304*0Sstevel@tonic-gate 	}
305*0Sstevel@tonic-gate 	if (data->knconf != NULL) {
306*0Sstevel@tonic-gate 		kmem_free(data->knconf->knc_protofmly, KNC_STRSIZE);
307*0Sstevel@tonic-gate 		kmem_free(data->knconf->knc_proto, KNC_STRSIZE);
308*0Sstevel@tonic-gate 		kmem_free(data->knconf, sizeof (*data->knconf));
309*0Sstevel@tonic-gate 	}
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 	kmem_free(data, sizeof (*data));
312*0Sstevel@tonic-gate }
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate /*
315*0Sstevel@tonic-gate  *  Load application auth related data from user land to kernel.
316*0Sstevel@tonic-gate  *  Map opaque data field to dh_k4_clntdata_t for AUTH_DES
317*0Sstevel@tonic-gate  *
318*0Sstevel@tonic-gate  */
319*0Sstevel@tonic-gate int
320*0Sstevel@tonic-gate sec_clnt_loadinfo(struct sec_data *in, struct sec_data **out, model_t model)
321*0Sstevel@tonic-gate {
322*0Sstevel@tonic-gate 	struct	sec_data	*secdata;
323*0Sstevel@tonic-gate 	int	error = 0;
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 	secdata = kmem_alloc(sizeof (*secdata), KM_SLEEP);
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
328*0Sstevel@tonic-gate 	if (model != DATAMODEL_NATIVE) {
329*0Sstevel@tonic-gate 		struct sec_data32 sd32;
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 		if (copyin(in, &sd32, sizeof (sd32)) == -1) {
332*0Sstevel@tonic-gate 			error = EFAULT;
333*0Sstevel@tonic-gate 		} else {
334*0Sstevel@tonic-gate 			secdata->secmod = sd32.secmod;
335*0Sstevel@tonic-gate 			secdata->rpcflavor = sd32.rpcflavor;
336*0Sstevel@tonic-gate 			secdata->uid = sd32.uid;
337*0Sstevel@tonic-gate 			secdata->flags = sd32.flags;
338*0Sstevel@tonic-gate 			secdata->data = (caddr_t)(uintptr_t)sd32.data;
339*0Sstevel@tonic-gate 		}
340*0Sstevel@tonic-gate 	} else
341*0Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 	if (copyin(in, secdata, sizeof (*secdata)) == -1) {
344*0Sstevel@tonic-gate 		error = EFAULT;
345*0Sstevel@tonic-gate 	}
346*0Sstevel@tonic-gate 	/*
347*0Sstevel@tonic-gate 	 * Copy in opaque data field per flavor.
348*0Sstevel@tonic-gate 	 */
349*0Sstevel@tonic-gate 	if (!error) {
350*0Sstevel@tonic-gate 		switch (secdata->rpcflavor) {
351*0Sstevel@tonic-gate 		case AUTH_NONE:
352*0Sstevel@tonic-gate 		case AUTH_UNIX:
353*0Sstevel@tonic-gate 		case AUTH_LOOPBACK:
354*0Sstevel@tonic-gate 			break;
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate 		case AUTH_DES:
357*0Sstevel@tonic-gate 			error = dh_k4_clnt_loadinfo(secdata->data,
358*0Sstevel@tonic-gate 			    &secdata->data, model);
359*0Sstevel@tonic-gate 			break;
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate 		case RPCSEC_GSS:
362*0Sstevel@tonic-gate 			error = gss_clnt_loadinfo(secdata->data,
363*0Sstevel@tonic-gate 			    &secdata->data, model);
364*0Sstevel@tonic-gate 			break;
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 		default:
367*0Sstevel@tonic-gate 			error = EINVAL;
368*0Sstevel@tonic-gate 			break;
369*0Sstevel@tonic-gate 		}
370*0Sstevel@tonic-gate 	}
371*0Sstevel@tonic-gate 
372*0Sstevel@tonic-gate 	if (!error) {
373*0Sstevel@tonic-gate 		*out = secdata;
374*0Sstevel@tonic-gate 	} else {
375*0Sstevel@tonic-gate 		kmem_free(secdata, sizeof (*secdata));
376*0Sstevel@tonic-gate 		*out = (struct sec_data *)NULL;
377*0Sstevel@tonic-gate 	}
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 	return (error);
380*0Sstevel@tonic-gate }
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate /*
383*0Sstevel@tonic-gate  * Null the sec_data index in the cache table, and
384*0Sstevel@tonic-gate  * free the memory allocated by sec_clnt_loadinfo.
385*0Sstevel@tonic-gate  */
386*0Sstevel@tonic-gate void
387*0Sstevel@tonic-gate sec_clnt_freeinfo(struct sec_data *secdata)
388*0Sstevel@tonic-gate {
389*0Sstevel@tonic-gate 	switch (secdata->rpcflavor) {
390*0Sstevel@tonic-gate 	case AUTH_DES:
391*0Sstevel@tonic-gate 		purge_authtab(secdata);
392*0Sstevel@tonic-gate 		if (secdata->data)
393*0Sstevel@tonic-gate 			dh_k4_clnt_freeinfo(secdata->data);
394*0Sstevel@tonic-gate 		break;
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 	case RPCSEC_GSS:
397*0Sstevel@tonic-gate 		rpc_gss_secpurge((void *)secdata);
398*0Sstevel@tonic-gate 		if (secdata->data) {
399*0Sstevel@tonic-gate 			gss_clntdata_t *gss_data;
400*0Sstevel@tonic-gate 
401*0Sstevel@tonic-gate 			gss_data = (gss_clntdata_t *)secdata->data;
402*0Sstevel@tonic-gate 			if (gss_data->mechanism.elements) {
403*0Sstevel@tonic-gate 				kmem_free(gss_data->mechanism.elements,
404*0Sstevel@tonic-gate 				    gss_data->mechanism.length);
405*0Sstevel@tonic-gate 			}
406*0Sstevel@tonic-gate 			kmem_free(secdata->data, sizeof (gss_clntdata_t));
407*0Sstevel@tonic-gate 		}
408*0Sstevel@tonic-gate 		break;
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 	case AUTH_NONE:
411*0Sstevel@tonic-gate 	case AUTH_UNIX:
412*0Sstevel@tonic-gate 	case AUTH_LOOPBACK:
413*0Sstevel@tonic-gate 	default:
414*0Sstevel@tonic-gate 		break;
415*0Sstevel@tonic-gate 	}
416*0Sstevel@tonic-gate 	kmem_free(secdata, sizeof (*secdata));
417*0Sstevel@tonic-gate }
418*0Sstevel@tonic-gate 
419*0Sstevel@tonic-gate /*
420*0Sstevel@tonic-gate  *  Get an AUTH handle for a RPC client based on the given sec_data.
421*0Sstevel@tonic-gate  *  If an AUTH handle exists for the same sec_data, use that AUTH handle,
422*0Sstevel@tonic-gate  *  otherwise create a new one.
423*0Sstevel@tonic-gate  */
424*0Sstevel@tonic-gate int
425*0Sstevel@tonic-gate sec_clnt_geth(CLIENT *client, struct sec_data *secdata, cred_t *cr, AUTH **ap)
426*0Sstevel@tonic-gate {
427*0Sstevel@tonic-gate 	int i;
428*0Sstevel@tonic-gate 	struct desauthent *da;
429*0Sstevel@tonic-gate 	int authflavor;
430*0Sstevel@tonic-gate 	cred_t *savecred;
431*0Sstevel@tonic-gate 	int stat;			/* return (errno) status */
432*0Sstevel@tonic-gate 	char gss_svc_name[MAX_GSS_NAME];
433*0Sstevel@tonic-gate 	dh_k4_clntdata_t	*desdata;
434*0Sstevel@tonic-gate 	AUTH *auth;
435*0Sstevel@tonic-gate 	gss_clntdata_t *gssdata;
436*0Sstevel@tonic-gate 	zoneid_t zoneid = getzoneid();
437*0Sstevel@tonic-gate 
438*0Sstevel@tonic-gate 	if ((client == NULL) || (secdata == NULL) || (ap == NULL))
439*0Sstevel@tonic-gate 		return (EINVAL);
440*0Sstevel@tonic-gate 	*ap = (AUTH *)NULL;
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate 	authflavor = secdata->rpcflavor;
443*0Sstevel@tonic-gate 	for (;;) {
444*0Sstevel@tonic-gate 		switch (authflavor) {
445*0Sstevel@tonic-gate 		case AUTH_NONE:
446*0Sstevel@tonic-gate 			/*
447*0Sstevel@tonic-gate 			 * XXX: should do real AUTH_NONE, instead of AUTH_UNIX
448*0Sstevel@tonic-gate 			 */
449*0Sstevel@tonic-gate 		case AUTH_UNIX:
450*0Sstevel@tonic-gate 			*ap = (AUTH *) authkern_create();
451*0Sstevel@tonic-gate 			return ((*ap != NULL) ? 0 : EINTR);
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate 		case AUTH_LOOPBACK:
454*0Sstevel@tonic-gate 			*ap = (AUTH *) authloopback_create();
455*0Sstevel@tonic-gate 			return ((*ap != NULL) ? 0 : EINTR);
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate 		case AUTH_DES:
458*0Sstevel@tonic-gate 			mutex_enter(&desauthtab_lock);
459*0Sstevel@tonic-gate 			if (desauthtab == NULL) {
460*0Sstevel@tonic-gate 				desauthtab = kmem_zalloc(clnt_authdes_cachesz *
461*0Sstevel@tonic-gate 				    sizeof (struct desauthent), KM_SLEEP);
462*0Sstevel@tonic-gate 			}
463*0Sstevel@tonic-gate 			for (da = desauthtab;
464*0Sstevel@tonic-gate 			    da < &desauthtab[clnt_authdes_cachesz];
465*0Sstevel@tonic-gate 			    da++) {
466*0Sstevel@tonic-gate 				if (da->da_data == secdata &&
467*0Sstevel@tonic-gate 				    da->da_uid == crgetuid(cr) &&
468*0Sstevel@tonic-gate 				    da->da_zoneid == zoneid &&
469*0Sstevel@tonic-gate 				    !da->da_inuse &&
470*0Sstevel@tonic-gate 				    da->da_auth != NULL) {
471*0Sstevel@tonic-gate 					da->da_inuse = 1;
472*0Sstevel@tonic-gate 					mutex_exit(&desauthtab_lock);
473*0Sstevel@tonic-gate 					*ap = da->da_auth;
474*0Sstevel@tonic-gate 					return (0);
475*0Sstevel@tonic-gate 				}
476*0Sstevel@tonic-gate 			}
477*0Sstevel@tonic-gate 			mutex_exit(&desauthtab_lock);
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate 			/*
480*0Sstevel@tonic-gate 			 *  A better way would be to have a cred paramater to
481*0Sstevel@tonic-gate 			 *  authdes_create.
482*0Sstevel@tonic-gate 			 */
483*0Sstevel@tonic-gate 			savecred = curthread->t_cred;
484*0Sstevel@tonic-gate 			curthread->t_cred = cr;
485*0Sstevel@tonic-gate 			desdata = (dh_k4_clntdata_t *)secdata->data;
486*0Sstevel@tonic-gate 			stat = authdes_create(desdata->netname, authdes_win,
487*0Sstevel@tonic-gate 				&desdata->syncaddr, desdata->knconf,
488*0Sstevel@tonic-gate 				(des_block *)NULL,
489*0Sstevel@tonic-gate 				(secdata->flags & AUTH_F_RPCTIMESYNC) ? 1 : 0,
490*0Sstevel@tonic-gate 				&auth);
491*0Sstevel@tonic-gate 			curthread->t_cred = savecred;
492*0Sstevel@tonic-gate 			*ap = auth;
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate 			if (stat != 0) {
495*0Sstevel@tonic-gate 				/*
496*0Sstevel@tonic-gate 				 *  If AUTH_F_TRYNONE is on, try again
497*0Sstevel@tonic-gate 				 *  with AUTH_NONE.  See bug 1180236.
498*0Sstevel@tonic-gate 				 */
499*0Sstevel@tonic-gate 				if (secdata->flags & AUTH_F_TRYNONE) {
500*0Sstevel@tonic-gate 					authflavor = AUTH_NONE;
501*0Sstevel@tonic-gate 					continue;
502*0Sstevel@tonic-gate 				} else
503*0Sstevel@tonic-gate 					return (stat);
504*0Sstevel@tonic-gate 			}
505*0Sstevel@tonic-gate 
506*0Sstevel@tonic-gate 			i = clnt_authdes_cachesz;
507*0Sstevel@tonic-gate 			mutex_enter(&desauthtab_lock);
508*0Sstevel@tonic-gate 			do {
509*0Sstevel@tonic-gate 				da = &desauthtab[nextdesvictim++];
510*0Sstevel@tonic-gate 				nextdesvictim %= clnt_authdes_cachesz;
511*0Sstevel@tonic-gate 			} while (da->da_inuse && --i > 0);
512*0Sstevel@tonic-gate 
513*0Sstevel@tonic-gate 			if (da->da_inuse) {
514*0Sstevel@tonic-gate 				mutex_exit(&desauthtab_lock);
515*0Sstevel@tonic-gate 				/* overflow of des auths */
516*0Sstevel@tonic-gate 				return (stat);
517*0Sstevel@tonic-gate 			}
518*0Sstevel@tonic-gate 			da->da_inuse = 1;
519*0Sstevel@tonic-gate 			mutex_exit(&desauthtab_lock);
520*0Sstevel@tonic-gate 
521*0Sstevel@tonic-gate 			if (da->da_auth != NULL)
522*0Sstevel@tonic-gate 				auth_destroy(da->da_auth);
523*0Sstevel@tonic-gate 
524*0Sstevel@tonic-gate 			da->da_auth = auth;
525*0Sstevel@tonic-gate 			da->da_uid = crgetuid(cr);
526*0Sstevel@tonic-gate 			da->da_zoneid = zoneid;
527*0Sstevel@tonic-gate 			da->da_data = secdata;
528*0Sstevel@tonic-gate 			return (stat);
529*0Sstevel@tonic-gate 
530*0Sstevel@tonic-gate 		case RPCSEC_GSS:
531*0Sstevel@tonic-gate 			/*
532*0Sstevel@tonic-gate 			 *  For RPCSEC_GSS, cache is done in rpc_gss_secget().
533*0Sstevel@tonic-gate 			 *  For every rpc_gss_secget(),  it should have
534*0Sstevel@tonic-gate 			 *  a corresponding rpc_gss_secfree() call.
535*0Sstevel@tonic-gate 			 */
536*0Sstevel@tonic-gate 			gssdata = (gss_clntdata_t *)secdata->data;
537*0Sstevel@tonic-gate 			(void) sprintf(gss_svc_name, "%s@%s", gssdata->uname,
538*0Sstevel@tonic-gate 			    gssdata->inst);
539*0Sstevel@tonic-gate 
540*0Sstevel@tonic-gate 			stat = rpc_gss_secget(client, gss_svc_name,
541*0Sstevel@tonic-gate 			    &gssdata->mechanism,
542*0Sstevel@tonic-gate 			    gssdata->service,
543*0Sstevel@tonic-gate 			    gssdata->qop,
544*0Sstevel@tonic-gate 			    NULL, NULL,
545*0Sstevel@tonic-gate 			    (caddr_t)secdata, cr, &auth);
546*0Sstevel@tonic-gate 			*ap = auth;
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate 			/* success */
549*0Sstevel@tonic-gate 			if (stat == 0)
550*0Sstevel@tonic-gate 				return (stat);
551*0Sstevel@tonic-gate 
552*0Sstevel@tonic-gate 			/*
553*0Sstevel@tonic-gate 			 * let the caller retry if connection timedout
554*0Sstevel@tonic-gate 			 * or reset.
555*0Sstevel@tonic-gate 			 */
556*0Sstevel@tonic-gate 			if (stat == ETIMEDOUT || stat == ECONNRESET)
557*0Sstevel@tonic-gate 				return (stat);
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate 			/*
560*0Sstevel@tonic-gate 			 *  If AUTH_F_TRYNONE is on, try again
561*0Sstevel@tonic-gate 			 *  with AUTH_NONE.  See bug 1180236.
562*0Sstevel@tonic-gate 			 */
563*0Sstevel@tonic-gate 			if (secdata->flags & AUTH_F_TRYNONE) {
564*0Sstevel@tonic-gate 				authflavor = AUTH_NONE;
565*0Sstevel@tonic-gate 				continue;
566*0Sstevel@tonic-gate 			}
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate 			RPCLOG(1, "sec_clnt_geth: rpc_gss_secget"
569*0Sstevel@tonic-gate 					" failed with %d", stat);
570*0Sstevel@tonic-gate 			return (stat);
571*0Sstevel@tonic-gate 
572*0Sstevel@tonic-gate 		default:
573*0Sstevel@tonic-gate 			/*
574*0Sstevel@tonic-gate 			 * auth create must have failed, try AUTH_NONE
575*0Sstevel@tonic-gate 			 * (this relies on AUTH_NONE never failing)
576*0Sstevel@tonic-gate 			 */
577*0Sstevel@tonic-gate 			cmn_err(CE_NOTE, "sec_clnt_geth: unknown "
578*0Sstevel@tonic-gate 			    "authflavor %d, trying AUTH_NONE", authflavor);
579*0Sstevel@tonic-gate 			authflavor = AUTH_NONE;
580*0Sstevel@tonic-gate 		}
581*0Sstevel@tonic-gate 	}
582*0Sstevel@tonic-gate }
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate void
585*0Sstevel@tonic-gate sec_clnt_freeh(AUTH *auth)
586*0Sstevel@tonic-gate {
587*0Sstevel@tonic-gate 	struct desauthent *da;
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 	switch (auth->ah_cred.oa_flavor) {
590*0Sstevel@tonic-gate 	case AUTH_NONE: /* XXX: do real AUTH_NONE */
591*0Sstevel@tonic-gate 	case AUTH_UNIX:
592*0Sstevel@tonic-gate 	case AUTH_LOOPBACK:
593*0Sstevel@tonic-gate 		auth_destroy(auth);	/* was overflow */
594*0Sstevel@tonic-gate 		break;
595*0Sstevel@tonic-gate 
596*0Sstevel@tonic-gate 	case AUTH_DES:
597*0Sstevel@tonic-gate 		mutex_enter(&desauthtab_lock);
598*0Sstevel@tonic-gate 		if (desauthtab != NULL) {
599*0Sstevel@tonic-gate 		    for (da = desauthtab;
600*0Sstevel@tonic-gate 			da < &desauthtab[clnt_authdes_cachesz]; da++) {
601*0Sstevel@tonic-gate 			if (da->da_auth == auth) {
602*0Sstevel@tonic-gate 				da->da_inuse = 0;
603*0Sstevel@tonic-gate 				mutex_exit(&desauthtab_lock);
604*0Sstevel@tonic-gate 				return;
605*0Sstevel@tonic-gate 			}
606*0Sstevel@tonic-gate 		    }
607*0Sstevel@tonic-gate 		}
608*0Sstevel@tonic-gate 		mutex_exit(&desauthtab_lock);
609*0Sstevel@tonic-gate 		auth_destroy(auth);	/* was overflow */
610*0Sstevel@tonic-gate 		break;
611*0Sstevel@tonic-gate 
612*0Sstevel@tonic-gate 	case RPCSEC_GSS:
613*0Sstevel@tonic-gate 		(void) rpc_gss_secfree(auth);
614*0Sstevel@tonic-gate 		break;
615*0Sstevel@tonic-gate 
616*0Sstevel@tonic-gate 	default:
617*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "sec_clnt_freeh: unknown authflavor %d",
618*0Sstevel@tonic-gate 			auth->ah_cred.oa_flavor);
619*0Sstevel@tonic-gate 		break;
620*0Sstevel@tonic-gate 	}
621*0Sstevel@tonic-gate }
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate /*
624*0Sstevel@tonic-gate  *  Revoke the authentication key in the given AUTH handle by setting
625*0Sstevel@tonic-gate  *  it to NULL.  If newkey is true, then generate a new key instead of
626*0Sstevel@tonic-gate  *  nulling out the old one.  This is necessary for AUTH_DES because
627*0Sstevel@tonic-gate  *  the new key will be used next time the user does a keylogin.  If
628*0Sstevel@tonic-gate  *  the zero'd key is used as actual key, then it cannot be revoked
629*0Sstevel@tonic-gate  *  again!
630*0Sstevel@tonic-gate  */
631*0Sstevel@tonic-gate void
632*0Sstevel@tonic-gate revoke_key(AUTH *auth, int newkey)
633*0Sstevel@tonic-gate {
634*0Sstevel@tonic-gate 	if (auth == NULL)
635*0Sstevel@tonic-gate 		return;
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate 	if (newkey) {
638*0Sstevel@tonic-gate 		if (key_gendes(&auth->ah_key) != RPC_SUCCESS) {
639*0Sstevel@tonic-gate 			/* failed to get new key, munge the old one */
640*0Sstevel@tonic-gate 			auth->ah_key.key.high ^= auth->ah_key.key.low;
641*0Sstevel@tonic-gate 			auth->ah_key.key.low  += auth->ah_key.key.high;
642*0Sstevel@tonic-gate 		}
643*0Sstevel@tonic-gate 	} else {
644*0Sstevel@tonic-gate 		/* null out old key */
645*0Sstevel@tonic-gate 		auth->ah_key.key.high = 0;
646*0Sstevel@tonic-gate 		auth->ah_key.key.low  = 0;
647*0Sstevel@tonic-gate 	}
648*0Sstevel@tonic-gate }
649*0Sstevel@tonic-gate 
650*0Sstevel@tonic-gate /*
651*0Sstevel@tonic-gate  *  Revoke all rpc credentials (of the selected auth type) for the given uid
652*0Sstevel@tonic-gate  *  from the auth cache.  Must be root to do this if the requested uid is not
653*0Sstevel@tonic-gate  *  the effective uid of the requestor.
654*0Sstevel@tonic-gate  *
655*0Sstevel@tonic-gate  *  Called from nfssys() for backward compatibility, and also
656*0Sstevel@tonic-gate  *  called from krpc_sys().
657*0Sstevel@tonic-gate  *
658*0Sstevel@tonic-gate  *  AUTH_DES does not refer to the "mechanism" information.
659*0Sstevel@tonic-gate  *  RPCSEC_GSS requires the "mechanism" input.
660*0Sstevel@tonic-gate  *  The input argument, mechanism, is a user-space address and needs
661*0Sstevel@tonic-gate  *  to be copied into the kernel address space.
662*0Sstevel@tonic-gate  *
663*0Sstevel@tonic-gate  *  Returns error number.
664*0Sstevel@tonic-gate  */
665*0Sstevel@tonic-gate /*ARGSUSED*/
666*0Sstevel@tonic-gate int
667*0Sstevel@tonic-gate sec_clnt_revoke(int rpcflavor, uid_t uid, cred_t *cr, void *mechanism,
668*0Sstevel@tonic-gate 						model_t model)
669*0Sstevel@tonic-gate {
670*0Sstevel@tonic-gate 	struct desauthent *da;
671*0Sstevel@tonic-gate 	int error = 0;
672*0Sstevel@tonic-gate 	zoneid_t zoneid = getzoneid();
673*0Sstevel@tonic-gate 
674*0Sstevel@tonic-gate 	if (uid != crgetuid(cr) && secpolicy_nfs(cr) != 0)
675*0Sstevel@tonic-gate 		return (EPERM);
676*0Sstevel@tonic-gate 
677*0Sstevel@tonic-gate 	switch (rpcflavor) {
678*0Sstevel@tonic-gate 	case AUTH_DES:
679*0Sstevel@tonic-gate 		mutex_enter(&desauthtab_lock);
680*0Sstevel@tonic-gate 		if (desauthtab != NULL) {
681*0Sstevel@tonic-gate 		    for (da = desauthtab;
682*0Sstevel@tonic-gate 			da < &desauthtab[clnt_authdes_cachesz]; da++) {
683*0Sstevel@tonic-gate 			if (uid == da->da_uid && zoneid == da->da_zoneid)
684*0Sstevel@tonic-gate 				revoke_key(da->da_auth, 1);
685*0Sstevel@tonic-gate 		    }
686*0Sstevel@tonic-gate 		}
687*0Sstevel@tonic-gate 		mutex_exit(&desauthtab_lock);
688*0Sstevel@tonic-gate 		return (0);
689*0Sstevel@tonic-gate 
690*0Sstevel@tonic-gate 	case RPCSEC_GSS: {
691*0Sstevel@tonic-gate 		rpc_gss_OID	mech;
692*0Sstevel@tonic-gate 		caddr_t		elements;
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate 		if (!mechanism)
695*0Sstevel@tonic-gate 			return (EINVAL);
696*0Sstevel@tonic-gate 
697*0Sstevel@tonic-gate 		/* copyin the gss mechanism type */
698*0Sstevel@tonic-gate 		mech = kmem_alloc(sizeof (rpc_gss_OID_desc), KM_SLEEP);
699*0Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
700*0Sstevel@tonic-gate 		if (model != DATAMODEL_NATIVE) {
701*0Sstevel@tonic-gate 			gss_OID_desc32 mech32;
702*0Sstevel@tonic-gate 
703*0Sstevel@tonic-gate 			if (copyin(mechanism, &mech32,
704*0Sstevel@tonic-gate 			    sizeof (gss_OID_desc32))) {
705*0Sstevel@tonic-gate 				kmem_free(mech, sizeof (rpc_gss_OID_desc));
706*0Sstevel@tonic-gate 				return (EFAULT);
707*0Sstevel@tonic-gate 			}
708*0Sstevel@tonic-gate 			mech->length = mech32.length;
709*0Sstevel@tonic-gate 			mech->elements = (caddr_t)(uintptr_t)mech32.elements;
710*0Sstevel@tonic-gate 		} else
711*0Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
712*0Sstevel@tonic-gate 		if (copyin(mechanism, mech, sizeof (rpc_gss_OID_desc))) {
713*0Sstevel@tonic-gate 			kmem_free(mech, sizeof (rpc_gss_OID_desc));
714*0Sstevel@tonic-gate 			return (EFAULT);
715*0Sstevel@tonic-gate 		}
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate 		elements = kmem_alloc(mech->length, KM_SLEEP);
718*0Sstevel@tonic-gate 		if (copyin(mech->elements, elements, mech->length)) {
719*0Sstevel@tonic-gate 			kmem_free(elements, mech->length);
720*0Sstevel@tonic-gate 			kmem_free(mech, sizeof (rpc_gss_OID_desc));
721*0Sstevel@tonic-gate 			return (EFAULT);
722*0Sstevel@tonic-gate 		}
723*0Sstevel@tonic-gate 		mech->elements = elements;
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate 		error = rpc_gss_revauth(uid, mech);
726*0Sstevel@tonic-gate 
727*0Sstevel@tonic-gate 		kmem_free(elements, mech->length);
728*0Sstevel@tonic-gate 		kmem_free(mech, sizeof (rpc_gss_OID_desc));
729*0Sstevel@tonic-gate 
730*0Sstevel@tonic-gate 		return (error);
731*0Sstevel@tonic-gate 	}
732*0Sstevel@tonic-gate 
733*0Sstevel@tonic-gate 	default:
734*0Sstevel@tonic-gate 		/* not an auth type with cached creds */
735*0Sstevel@tonic-gate 		return (EINVAL);
736*0Sstevel@tonic-gate 	}
737*0Sstevel@tonic-gate }
738*0Sstevel@tonic-gate 
739*0Sstevel@tonic-gate /*
740*0Sstevel@tonic-gate  *  Since sec_data is the index for the client auth handles
741*0Sstevel@tonic-gate  *  cache table,  whenever the sec_data is freed, the index needs
742*0Sstevel@tonic-gate  *  to be nulled.
743*0Sstevel@tonic-gate  */
744*0Sstevel@tonic-gate void
745*0Sstevel@tonic-gate purge_authtab(struct sec_data *secdata)
746*0Sstevel@tonic-gate {
747*0Sstevel@tonic-gate 	struct desauthent *da;
748*0Sstevel@tonic-gate 
749*0Sstevel@tonic-gate 	switch (secdata->rpcflavor) {
750*0Sstevel@tonic-gate 
751*0Sstevel@tonic-gate 	case AUTH_DES:
752*0Sstevel@tonic-gate 		mutex_enter(&desauthtab_lock);
753*0Sstevel@tonic-gate 		if (desauthtab != NULL) {
754*0Sstevel@tonic-gate 		    for (da = desauthtab;
755*0Sstevel@tonic-gate 			da < &desauthtab[clnt_authdes_cachesz]; da++) {
756*0Sstevel@tonic-gate 			if (da->da_data == secdata) {
757*0Sstevel@tonic-gate 				da->da_data = NULL;
758*0Sstevel@tonic-gate 				da->da_inuse = 0;
759*0Sstevel@tonic-gate 			}
760*0Sstevel@tonic-gate 		    }
761*0Sstevel@tonic-gate 		}
762*0Sstevel@tonic-gate 		mutex_exit(&desauthtab_lock);
763*0Sstevel@tonic-gate 		return;
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate 	case RPCSEC_GSS:
766*0Sstevel@tonic-gate 		rpc_gss_secpurge((void *)secdata);
767*0Sstevel@tonic-gate 		return;
768*0Sstevel@tonic-gate 
769*0Sstevel@tonic-gate 	default:
770*0Sstevel@tonic-gate 		return;
771*0Sstevel@tonic-gate 	}
772*0Sstevel@tonic-gate }
773*0Sstevel@tonic-gate 
774*0Sstevel@tonic-gate void
775*0Sstevel@tonic-gate sec_subrinit(void)
776*0Sstevel@tonic-gate {
777*0Sstevel@tonic-gate 	authkern_cache = kmem_cache_create("authkern_cache",
778*0Sstevel@tonic-gate 	    sizeof (AUTH), 0, authkern_init, NULL, NULL, NULL, NULL, 0);
779*0Sstevel@tonic-gate 	authloopback_cache = kmem_cache_create("authloopback_cache",
780*0Sstevel@tonic-gate 	    sizeof (AUTH), 0, authloopback_init, NULL, NULL, NULL, NULL, 0);
781*0Sstevel@tonic-gate 	mutex_init(&desauthtab_lock, NULL, MUTEX_DEFAULT, NULL);
782*0Sstevel@tonic-gate 
783*0Sstevel@tonic-gate 	/* RPC stuff */
784*0Sstevel@tonic-gate 	mutex_init(&authdes_ops_lock, NULL, MUTEX_DEFAULT, NULL);
785*0Sstevel@tonic-gate 	zone_key_create(&auth_zone_key, auth_zone_init, NULL, auth_zone_fini);
786*0Sstevel@tonic-gate }
787*0Sstevel@tonic-gate 
788*0Sstevel@tonic-gate /*
789*0Sstevel@tonic-gate  * Destroys the caches and mutexes previously allocated and initialized
790*0Sstevel@tonic-gate  * in sec_subrinit().
791*0Sstevel@tonic-gate  * This routine is called by _init() if mod_install() failed.
792*0Sstevel@tonic-gate  */
793*0Sstevel@tonic-gate void
794*0Sstevel@tonic-gate sec_subrfini(void)
795*0Sstevel@tonic-gate {
796*0Sstevel@tonic-gate 	mutex_destroy(&desauthtab_lock);
797*0Sstevel@tonic-gate 	kmem_cache_destroy(authkern_cache);
798*0Sstevel@tonic-gate 	kmem_cache_destroy(authloopback_cache);
799*0Sstevel@tonic-gate 
800*0Sstevel@tonic-gate 	/* RPC stuff */
801*0Sstevel@tonic-gate 	mutex_destroy(&authdes_ops_lock);
802*0Sstevel@tonic-gate 	(void) zone_key_delete(auth_zone_key);
803*0Sstevel@tonic-gate }
804