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