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 */
72 static int clnt_authdes_cachesz = 64;
73
74 static uint_t authdes_win = 5*60; /* 5 minutes -- should be mount option */
75
76 struct kmem_cache *authkern_cache;
77
78 struct kmem_cache *authnone_cache;
79
80 struct kmem_cache *authloopback_cache;
81
82 static 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;
89 static int nextdesvictim;
90 static kmutex_t desauthtab_lock; /* Lock to protect DES auth cache */
91
92 /* RPC stuff */
93 kmutex_t authdes_ops_lock; /* auth_ops initialization in authdes_ops() */
94
95 static void purge_authtab(struct sec_data *);
96
97 /* Zone stuff */
98 zone_key_t auth_zone_key;
99
100 /*
101 * Load RPCSEC_GSS specific data from user space to kernel space.
102 */
103 /*ARGSUSED*/
104 static int
gss_clnt_loadinfo(caddr_t usrdata,caddr_t * kdata,model_t model)105 gss_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*/
159 int
dh_k4_clnt_loadinfo(caddr_t usrdata,caddr_t * kdata,model_t model)160 dh_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 */
303 void
dh_k4_clnt_freeinfo(caddr_t cdata)304 dh_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 */
329 int
sec_clnt_loadinfo(struct sec_data * in,struct sec_data ** out,model_t model)330 sec_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 */
396 void
sec_clnt_freeinfo(struct sec_data * secdata)397 sec_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 */
434 int
sec_clnt_geth(CLIENT * client,struct sec_data * secdata,cred_t * cr,AUTH ** ap)435 sec_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
613 void
sec_clnt_freeh(AUTH * auth)614 sec_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 */
660 void
revoke_key(AUTH * auth,int newkey)661 revoke_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*/
695 int
sec_clnt_revoke(int rpcflavor,uid_t uid,cred_t * cr,void * mechanism,model_t model)696 sec_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 */
780 void
purge_authtab(struct sec_data * secdata)781 purge_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
810 void
sec_subrinit(void)811 sec_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 */
831 void
sec_subrfini(void)832 sec_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