Merge illumos-gate
[unleashed.git] / usr / src / uts / common / rpc / sec_gss / rpcsec_gss.c
blobcc8e6ba6bcac99af655dd4c8b991b7110f178192
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Copyright (c) 2018, Joyent, Inc.
31 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
33 * $Header:
34 * /afs/gza.com/product/secure/rel-eng/src/1.1/rpc/RCS/auth_gssapi.c,v
35 * 1.14 1995/03/22 22:07:55 jik Exp $
38 #include <sys/systm.h>
39 #include <sys/types.h>
40 #include <gssapi/gssapi.h>
41 #include <rpc/rpc.h>
42 #include <rpc/rpcsec_defs.h>
43 #include <sys/debug.h>
44 #include <sys/cmn_err.h>
45 #include <sys/ddi.h>
47 static void rpc_gss_nextverf();
48 static bool_t rpc_gss_marshall();
49 static bool_t rpc_gss_validate();
50 static bool_t rpc_gss_refresh();
51 static void rpc_gss_destroy();
52 #if 0
53 static void rpc_gss_destroy_pvt();
54 #endif
55 static void rpc_gss_free_pvt();
56 static int rpc_gss_seccreate_pvt();
57 static bool_t rpc_gss_wrap();
58 static bool_t rpc_gss_unwrap();
59 static bool_t validate_seqwin();
62 #ifdef DEBUG
63 #include <sys/promif.h>
64 #endif
66 static struct auth_ops rpc_gss_ops = {
67 rpc_gss_nextverf,
68 rpc_gss_marshall,
69 rpc_gss_validate,
70 rpc_gss_refresh,
71 rpc_gss_destroy,
72 rpc_gss_wrap,
73 rpc_gss_unwrap,
77 * Private data for RPCSEC_GSS.
79 typedef struct _rpc_gss_data {
80 bool_t established; /* TRUE when established */
81 CLIENT *clnt; /* associated client handle */
82 int version; /* RPCSEC version */
83 gss_ctx_id_t context; /* GSS context id */
84 gss_buffer_desc ctx_handle; /* RPCSEC GSS context handle */
85 uint_t seq_num; /* last sequence number rcvd */
86 gss_cred_id_t my_cred; /* caller's GSS credentials */
87 OM_uint32 qop; /* requested QOP */
88 rpc_gss_service_t service; /* requested service */
89 uint_t gss_proc; /* GSS control procedure */
90 gss_name_t target_name; /* target server */
91 int req_flags; /* GSS request bits */
92 gss_OID mech_type; /* GSS mechanism */
93 OM_uint32 time_req; /* requested cred lifetime */
94 bool_t invalid; /* can't use this any more */
95 OM_uint32 seq_window; /* server sequence window */
96 struct opaque_auth *verifier; /* rpc reply verifier saved for */
97 /* validating the sequence window */
98 gss_channel_bindings_t icb;
99 } rpc_gss_data;
100 #define AUTH_PRIVATE(auth) ((rpc_gss_data *)auth->ah_private)
102 #define INTERRUPT_OK 1 /* allow interrupt */
105 * RPCSEC_GSS auth cache definitions.
108 /* The table size must be a power of two. */
109 #define GSSAUTH_TABLESIZE 16
110 #define HASH(keynum, uid_num) \
111 ((((intptr_t)(keynum)) ^ ((int)uid_num)) & (GSSAUTH_TABLESIZE - 1))
114 * gss auth cache entry.
116 typedef struct ga_cache_entry {
117 void *cache_key;
118 uid_t uid;
119 zoneid_t zoneid;
120 bool_t in_use;
121 time_t ref_time; /* the time referenced previously */
122 time_t ctx_expired_time; /* when the context will be expired */
123 AUTH *auth;
124 struct ga_cache_entry *next;
125 } *ga_cache_list;
127 struct ga_cache_entry *ga_cache_table[GSSAUTH_TABLESIZE];
128 static krwlock_t ga_cache_table_lock;
129 static struct kmem_cache *ga_cache_handle;
130 static void gssauth_cache_reclaim(void *);
132 static void gssauth_zone_fini(zoneid_t, void *);
133 static zone_key_t gssauth_zone_key;
135 int ga_cache_hit;
136 int ga_cache_miss;
137 int ga_cache_reclaim;
139 #define NOT_DEAD(ptr) ASSERT((((intptr_t)(ptr)) != 0xdeadbeef))
141 void
142 gssauth_init(void)
145 * Initialize gss auth cache table lock
147 rw_init(&ga_cache_table_lock, NULL, RW_DEFAULT, NULL);
150 * Allocate gss auth cache handle
152 ga_cache_handle = kmem_cache_create("ga_cache_handle",
153 sizeof (struct ga_cache_entry), 0, NULL, NULL,
154 gssauth_cache_reclaim, NULL, NULL, 0);
155 zone_key_create(&gssauth_zone_key, NULL, NULL, gssauth_zone_fini);
159 * Destroy the structures previously initialized in gssauth_init()
160 * This routine is called by _init() if mod_install() failed.
162 void
163 gssauth_fini(void)
165 (void) zone_key_delete(gssauth_zone_key);
166 kmem_cache_destroy(ga_cache_handle);
167 rw_destroy(&ga_cache_table_lock);
171 * This is a cleanup routine to release cached entries when a zone is being
172 * destroyed. The code is also used when kmem calls us to free up memory, at
173 * which point ``zoneid'' will be ALL_ZONES. We don't honor the cache timeout
174 * when the zone is going away, since the zoneid (and all associated cached
175 * entries) are invalid.
177 time_t rpc_gss_cache_time = 60 * 60;
179 /* ARGSUSED */
180 static void
181 gssauth_zone_fini(zoneid_t zoneid, void *unused)
183 struct ga_cache_entry *p, *prev, *next;
184 int i;
185 time_t now;
187 rw_enter(&ga_cache_table_lock, RW_WRITER);
189 for (i = 0; i < GSSAUTH_TABLESIZE; i++) {
190 prev = NULL;
191 for (p = ga_cache_table[i]; p; p = next) {
192 NOT_DEAD(p->next);
193 next = p->next;
194 NOT_DEAD(next);
195 if (zoneid == ALL_ZONES) { /* kmem callback */
197 * Free entries that have not been
198 * used for rpc_gss_cache_time seconds.
200 now = gethrestime_sec();
201 if ((p->ref_time + rpc_gss_cache_time >
202 now) || p->in_use) {
203 if ((p->ref_time + rpc_gss_cache_time <=
204 now) && p->in_use) {
205 RPCGSS_LOG0(2, "gssauth_cache_"
206 "reclaim: in_use\n");
208 prev = p;
209 continue;
211 } else {
212 if (p->zoneid != zoneid) {
213 prev = p;
214 continue;
216 ASSERT(!p->in_use);
219 RPCGSS_LOG(2, "gssauth_cache_reclaim: destroy auth "
220 "%p\n", (void *)p->auth);
221 rpc_gss_destroy(p->auth);
222 kmem_cache_free(ga_cache_handle, (void *)p);
223 if (prev == NULL) {
224 ga_cache_table[i] = next;
225 } else {
226 NOT_DEAD(prev->next);
227 prev->next = next;
232 rw_exit(&ga_cache_table_lock);
237 * Called by the kernel memory allocator when
238 * memory is low. Free unused cache entries.
239 * If that's not enough, the VM system will
240 * call again for some more.
242 /*ARGSUSED*/
243 static void
244 gssauth_cache_reclaim(void *cdrarg)
246 gssauth_zone_fini(ALL_ZONES, NULL);
249 #define NOT_NULL(ptr) ASSERT(ptr)
250 #define IS_ALIGNED(ptr) ASSERT((((intptr_t)(ptr)) & 3) == 0)
253 * Get the client gss security service handle.
254 * If it is in the cache table, get it, otherwise, create
255 * a new one by calling rpc_gss_seccreate().
258 rpc_gss_secget(CLIENT *clnt,
259 char *principal,
260 rpc_gss_OID mechanism,
261 rpc_gss_service_t service_type,
262 uint_t qop,
263 rpc_gss_options_req_t *options_req,
264 rpc_gss_options_ret_t *options_ret,
265 void *cache_key,
266 cred_t *cr,
267 AUTH **retauth)
269 struct ga_cache_entry **head, *current, *new, *prev;
270 AUTH *auth = NULL;
271 rpc_gss_data *ap;
272 rpc_gss_options_ret_t opt_ret;
273 int status = 0;
274 uid_t uid = crgetuid(cr);
275 zoneid_t zoneid = getzoneid();
277 if (retauth == NULL)
278 return (EINVAL);
279 *retauth = NULL;
281 NOT_NULL(cr);
282 IS_ALIGNED(cr);
283 #ifdef DEBUG
284 if (HASH(cache_key, uid) < 0) {
285 prom_printf("cache_key %p, cr %p\n", cache_key, (void *)cr);
287 #endif
290 * Get a valid gss auth handle from the cache table.
291 * If auth in cache is invalid and not in use, destroy it.
293 prev = NULL;
294 rw_enter(&ga_cache_table_lock, RW_WRITER);
296 ASSERT(HASH(cache_key, uid) >= 0);
297 head = &ga_cache_table[HASH(cache_key, uid)];
298 NOT_NULL(head);
299 IS_ALIGNED(head);
301 for (current = *head; current; current = current->next) {
302 NOT_NULL(current);
303 IS_ALIGNED(current);
304 if ((cache_key == current->cache_key) &&
305 (uid == current->uid) && (zoneid == current->zoneid) &&
306 !current->in_use) {
307 current->in_use = TRUE;
308 current->ref_time = gethrestime_sec();
309 ap = AUTH_PRIVATE(current->auth);
310 ap->clnt = clnt;
311 ga_cache_hit++;
312 if (ap->invalid ||
313 ((current->ctx_expired_time != GSS_C_INDEFINITE) &&
314 (gethrestime_sec() >=
315 current->ctx_expired_time))) {
316 RPCGSS_LOG0(1, "NOTICE: rpc_gss_secget: time to "
317 "refresh the auth\n");
318 if (prev == NULL) {
319 *head = current->next;
320 } else {
321 prev->next = current->next;
323 rpc_gss_destroy(current->auth);
324 kmem_cache_free(ga_cache_handle, (void *) current);
325 auth = NULL;
326 } else {
327 auth = current->auth;
329 break;
330 } else {
331 prev = current;
334 rw_exit(&ga_cache_table_lock);
337 * If no valid gss auth handle can be found in the cache, create
338 * a new one.
340 if (!auth) {
341 ga_cache_miss++;
342 if (options_ret == NULL)
343 options_ret = &opt_ret;
345 status = rpc_gss_seccreate(clnt, principal, mechanism,
346 service_type, qop, options_req, options_ret, cr, &auth);
347 if (status == 0) {
348 RPCGSS_LOG(2, "rpc_gss_secget: new auth %p\n",
349 (void *)auth);
350 new = kmem_cache_alloc(ga_cache_handle, KM_NOSLEEP);
351 IS_ALIGNED(new);
352 NOT_DEAD(new);
353 if (new) {
354 new->cache_key = cache_key;
355 new->uid = uid;
356 new->zoneid = zoneid;
357 new->in_use = TRUE;
358 new->ref_time = gethrestime_sec();
359 if (options_ret->time_ret != GSS_C_INDEFINITE) {
360 new->ctx_expired_time = new->ref_time +
361 options_ret->time_ret;
362 } else {
363 new->ctx_expired_time = GSS_C_INDEFINITE;
365 new->auth = auth;
366 rw_enter(&ga_cache_table_lock, RW_WRITER);
367 NOT_DEAD(*head);
368 NOT_DEAD(new->next);
369 new->next = *head;
370 *head = new;
371 rw_exit(&ga_cache_table_lock);
373 /* done with opt_ret */
374 if (options_ret == &opt_ret) {
375 kgss_free_oid((gss_OID) opt_ret.actual_mechanism);
380 *retauth = auth;
381 return (status);
387 * rpc_gss_secfree will destroy a rpcsec_gss context only if
388 * the auth handle is not in the cache table.
390 void
391 rpc_gss_secfree(AUTH *auth)
393 struct ga_cache_entry *next, *cur;
394 int i;
397 * Check the cache table to find the auth.
398 * Marked it unused.
400 rw_enter(&ga_cache_table_lock, RW_WRITER);
401 for (i = 0; i < GSSAUTH_TABLESIZE; i++) {
402 for (cur = ga_cache_table[i]; cur; cur = next) {
403 NOT_DEAD(cur);
404 next = cur->next;
405 NOT_DEAD(next);
406 if (cur->auth == auth) {
407 ASSERT(cur->in_use == TRUE);
408 cur->in_use = FALSE;
409 rw_exit(&ga_cache_table_lock);
410 return;
414 rw_exit(&ga_cache_table_lock);
415 RPCGSS_LOG(2, "rpc_gss_secfree: destroy auth %p\n", (void *)auth);
416 rpc_gss_destroy(auth);
421 * Create a gss security service context.
424 rpc_gss_seccreate(CLIENT *clnt,
425 char *principal, /* target service@server */
426 rpc_gss_OID mechanism, /* security mechanism */
427 rpc_gss_service_t service_type, /* security service */
428 uint_t qop, /* requested QOP */
429 rpc_gss_options_req_t *options_req, /* requested options */
430 rpc_gss_options_ret_t *options_ret, /* returned options */
431 cred_t *cr, /* client's unix cred */
432 AUTH **retauth) /* auth handle */
434 OM_uint32 gssstat;
435 OM_uint32 minor_stat;
436 gss_name_t target_name;
437 int ret_flags;
438 OM_uint32 time_rec;
439 gss_buffer_desc input_name;
440 AUTH *auth = NULL;
441 rpc_gss_data *ap = NULL;
442 int error;
445 * convert name to GSS internal type
447 input_name.value = principal;
448 input_name.length = strlen(principal);
450 gssstat = gss_import_name(&minor_stat, &input_name,
451 (gss_OID)GSS_C_NT_HOSTBASED_SERVICE, &target_name);
453 if (gssstat != GSS_S_COMPLETE) {
454 RPCGSS_LOG0(1,
455 "rpc_gss_seccreate: unable to import gss name\n");
456 return (ENOMEM);
460 * Create AUTH handle. Save the necessary interface information
461 * so that the client can refresh the handle later if needed.
463 if ((auth = (AUTH *) kmem_alloc(sizeof (*auth), KM_SLEEP)) != NULL)
464 ap = (rpc_gss_data *) kmem_alloc(sizeof (*ap), KM_SLEEP);
465 if (auth == NULL || ap == NULL) {
466 RPCGSS_LOG0(1, "rpc_gss_seccreate: out of memory\n");
467 if (auth != NULL)
468 kmem_free((char *)auth, sizeof (*auth));
469 (void) gss_release_name(&minor_stat, &target_name);
470 return (ENOMEM);
473 bzero((char *)ap, sizeof (*ap));
474 ap->clnt = clnt;
475 ap->version = RPCSEC_GSS_VERSION;
476 if (options_req != NULL) {
477 ap->my_cred = options_req->my_cred;
478 ap->req_flags = options_req->req_flags;
479 ap->time_req = options_req->time_req;
480 ap->icb = options_req->input_channel_bindings;
481 } else {
482 ap->my_cred = GSS_C_NO_CREDENTIAL;
483 ap->req_flags = GSS_C_MUTUAL_FLAG;
484 ap->time_req = 0;
485 ap->icb = GSS_C_NO_CHANNEL_BINDINGS;
487 if ((ap->service = service_type) == rpc_gss_svc_default)
488 ap->service = rpc_gss_svc_integrity;
489 ap->qop = qop;
490 ap->target_name = target_name;
493 * Now invoke the real interface that sets up the context from
494 * the information stashed away in the private data.
496 if (error = rpc_gss_seccreate_pvt(&gssstat, &minor_stat, auth, ap,
497 mechanism, &ap->mech_type, &ret_flags, &time_rec, cr, 0)) {
498 if (ap->target_name) {
499 (void) gss_release_name(&minor_stat, &ap->target_name);
501 kmem_free((char *)ap, sizeof (*ap));
502 kmem_free((char *)auth, sizeof (*auth));
503 RPCGSS_LOG(1, "rpc_gss_seccreate: init context failed"
504 " errno=%d\n", error);
505 return (error);
509 * Make sure that the requested service is supported. In all
510 * cases, integrity service must be available.
512 if ((ap->service == rpc_gss_svc_privacy &&
513 !(ret_flags & GSS_C_CONF_FLAG)) ||
514 !(ret_flags & GSS_C_INTEG_FLAG)) {
515 rpc_gss_destroy(auth);
516 RPCGSS_LOG0(1, "rpc_gss_seccreate: service not supported\n");
517 return (EPROTONOSUPPORT);
521 * return option values if requested
523 if (options_ret != NULL) {
524 options_ret->major_status = gssstat;
525 options_ret->minor_status = minor_stat;
526 options_ret->rpcsec_version = ap->version;
527 options_ret->ret_flags = ret_flags;
528 options_ret->time_ret = time_rec;
529 options_ret->gss_context = ap->context;
531 * Caller's responsibility to free this.
533 NOT_NULL(ap->mech_type);
534 __rpc_gss_dup_oid(ap->mech_type,
535 (gss_OID *)&options_ret->actual_mechanism);
538 *retauth = auth;
539 return (0);
543 * Private interface to create a context. This is the interface
544 * that's invoked when the context has to be refreshed.
546 static int
547 rpc_gss_seccreate_pvt(gssstat, minor_stat, auth, ap, desired_mech_type,
548 actual_mech_type, ret_flags, time_rec, cr, isrefresh)
549 OM_uint32 *gssstat;
550 OM_uint32 *minor_stat;
551 AUTH *auth;
552 rpc_gss_data *ap;
553 gss_OID desired_mech_type;
554 gss_OID *actual_mech_type;
555 int *ret_flags;
556 OM_uint32 *time_rec;
557 cred_t *cr;
558 int isrefresh;
560 CLIENT *clnt = ap->clnt;
561 AUTH *save_auth;
562 enum clnt_stat callstat;
563 rpc_gss_init_arg call_arg;
564 rpc_gss_init_res call_res;
565 gss_buffer_desc *input_token_p, input_token, process_token;
566 int free_results = 0;
567 k_sigset_t smask;
568 int error = 0;
571 * (re)initialize AUTH handle and private data.
573 bzero((char *)auth, sizeof (*auth));
574 auth->ah_ops = &rpc_gss_ops;
575 auth->ah_private = (caddr_t)ap;
576 auth->ah_cred.oa_flavor = RPCSEC_GSS;
578 ap->established = FALSE;
579 ap->ctx_handle.length = 0;
580 ap->ctx_handle.value = NULL;
581 ap->context = NULL;
582 ap->seq_num = 0;
583 ap->gss_proc = RPCSEC_GSS_INIT;
586 * should not change clnt->cl_auth at this time, so save
587 * old handle
589 save_auth = clnt->cl_auth;
590 clnt->cl_auth = auth;
593 * set state for starting context setup
595 bzero((char *)&call_arg, sizeof (call_arg));
596 input_token_p = GSS_C_NO_BUFFER;
598 next_token:
599 *gssstat = kgss_init_sec_context(minor_stat,
600 ap->my_cred,
601 &ap->context,
602 ap->target_name,
603 desired_mech_type,
604 ap->req_flags,
605 ap->time_req,
606 NULL,
607 input_token_p,
608 actual_mech_type,
609 &call_arg,
610 ret_flags,
611 time_rec,
612 crgetuid(cr));
614 if (input_token_p != GSS_C_NO_BUFFER) {
615 OM_uint32 minor_stat2;
617 (void) gss_release_buffer(&minor_stat2, input_token_p);
618 input_token_p = GSS_C_NO_BUFFER;
621 if (*gssstat != GSS_S_COMPLETE && *gssstat != GSS_S_CONTINUE_NEEDED) {
622 rpc_gss_display_status(*gssstat, *minor_stat,
623 desired_mech_type, crgetuid(cr),
624 "rpcsec_gss_secreate_pvt:gss_init_sec_context");
625 error = EACCES;
626 goto cleanup;
630 * if we got a token, pass it on
632 if (call_arg.length != 0) {
633 struct timeval timeout = {30, 0};
634 int rpcsec_retry = isrefresh ?
635 RPCSEC_GSS_REFRESH_ATTEMPTS : 1;
636 uint32_t oldxid;
637 uint32_t zeroxid = 0;
639 bzero((char *)&call_res, sizeof (call_res));
641 (void) CLNT_CONTROL(clnt, CLGET_XID, (char *)&oldxid);
642 (void) CLNT_CONTROL(clnt, CLSET_XID, (char *)&zeroxid);
645 while (rpcsec_retry > 0) {
646 struct rpc_err rpcerr;
648 sigintr(&smask, INTERRUPT_OK);
650 callstat = clnt_call(clnt, NULLPROC,
651 __xdr_rpc_gss_init_arg, (caddr_t)&call_arg,
652 __xdr_rpc_gss_init_res, (caddr_t)&call_res,
653 timeout);
655 sigunintr(&smask);
657 if (callstat == RPC_SUCCESS) {
658 error = 0;
659 if (isrefresh &&
660 call_res.gss_major == GSS_S_FAILURE) {
662 clock_t one_sec = drv_usectohz(1000000);
664 rpcsec_retry--;
667 * Pause a little and try again.
670 if (clnt->cl_nosignal == TRUE) {
671 delay(one_sec);
672 } else {
673 if (delay_sig(one_sec)) {
674 error = EINTR;
675 break;
678 continue;
680 break;
683 if (callstat == RPC_TIMEDOUT) {
684 error = ETIMEDOUT;
685 break;
688 if (callstat == RPC_XPRTFAILED) {
689 error = ECONNRESET;
690 break;
693 if (callstat == RPC_INTR) {
694 error = EINTR;
695 break;
698 if (callstat == RPC_INPROGRESS) {
699 continue;
702 clnt_geterr(clnt, &rpcerr);
703 error = rpcerr.re_errno;
704 break;
707 (void) CLNT_CONTROL(clnt, CLSET_XID, (char *)&oldxid);
709 (void) gss_release_buffer(minor_stat, &call_arg);
711 if (callstat != RPC_SUCCESS) {
712 RPCGSS_LOG(1,
713 "rpc_gss_seccreate_pvt: clnt_call failed %d\n",
714 callstat);
715 goto cleanup;
719 * we have results - note that these need to be freed
721 free_results = 1;
723 if ((call_res.gss_major != GSS_S_COMPLETE) &&
724 (call_res.gss_major != GSS_S_CONTINUE_NEEDED)) {
725 RPCGSS_LOG1(1, "rpc_gss_seccreate_pvt: "
726 "call_res gss_major %x, gss_minor %x\n",
727 call_res.gss_major, call_res.gss_minor);
728 error = EACCES;
729 goto cleanup;
732 ap->gss_proc = RPCSEC_GSS_CONTINUE_INIT;
735 * check for ctx_handle
737 if (ap->ctx_handle.length == 0) {
738 if (call_res.ctx_handle.length == 0) {
739 RPCGSS_LOG0(1, "rpc_gss_seccreate_pvt: zero "
740 "length handle in response\n");
741 error = EACCES;
742 goto cleanup;
744 GSS_DUP_BUFFER(ap->ctx_handle,
745 call_res.ctx_handle);
746 } else if (!GSS_BUFFERS_EQUAL(ap->ctx_handle,
747 call_res.ctx_handle)) {
748 RPCGSS_LOG0(1,
749 "rpc_gss_seccreate_pvt: ctx_handle not the same\n");
750 error = EACCES;
751 goto cleanup;
755 * check for token
757 if (call_res.token.length != 0) {
758 if (*gssstat == GSS_S_COMPLETE) {
759 RPCGSS_LOG0(1, "rpc_gss_seccreate_pvt: non "
760 "zero length token in response, but "
761 "gsstat == GSS_S_COMPLETE\n");
762 error = EACCES;
763 goto cleanup;
765 GSS_DUP_BUFFER(input_token, call_res.token);
766 input_token_p = &input_token;
768 } else if (*gssstat != GSS_S_COMPLETE) {
769 RPCGSS_LOG0(1, "rpc_gss_seccreate_pvt:zero length "
770 "token in response, but "
771 "gsstat != GSS_S_COMPLETE\n");
772 error = EACCES;
773 goto cleanup;
776 /* save the sequence window value; validate later */
777 ap->seq_window = call_res.seq_window;
778 xdr_free(__xdr_rpc_gss_init_res, (caddr_t)&call_res);
779 free_results = 0;
783 * results were okay.. continue if necessary
785 if (*gssstat == GSS_S_CONTINUE_NEEDED) {
786 goto next_token;
790 * Context is established. Now use kgss_export_sec_context and
791 * kgss_import_sec_context to transfer the context from the user
792 * land to kernel if the mechanism specific kernel module is
793 * available.
795 *gssstat = kgss_export_sec_context(minor_stat, ap->context,
796 &process_token);
797 if (*gssstat == GSS_S_NAME_NOT_MN) {
798 RPCGSS_LOG(2, "rpc_gss_seccreate_pvt: export_sec_context "
799 "Kernel Module unavailable gssstat = 0x%x\n",
800 *gssstat);
801 goto done;
802 } else if (*gssstat != GSS_S_COMPLETE) {
803 (void) rpc_gss_display_status(*gssstat, *minor_stat,
804 isrefresh ? GSS_C_NULL_OID : *actual_mech_type,
805 crgetuid(cr),
806 "rpcsec_gss_secreate_pvt:gss_export_sec_context");
807 (void) kgss_delete_sec_context(minor_stat,
808 &ap->context, NULL);
809 error = EACCES;
810 goto cleanup;
811 } else if (process_token.length == 0) {
812 RPCGSS_LOG0(1, "rpc_gss_seccreate_pvt:zero length "
813 "token in response for export_sec_context, but "
814 "gsstat == GSS_S_COMPLETE\n");
815 (void) kgss_delete_sec_context(minor_stat,
816 &ap->context, NULL);
817 error = EACCES;
818 goto cleanup;
819 } else
820 *gssstat = kgss_import_sec_context(minor_stat, &process_token,
821 ap->context);
823 if (*gssstat == GSS_S_COMPLETE) {
824 (void) gss_release_buffer(minor_stat, &process_token);
825 } else {
826 rpc_gss_display_status(*gssstat, *minor_stat,
827 desired_mech_type, crgetuid(cr),
828 "rpcsec_gss_secreate_pvt:gss_import_sec_context");
829 (void) kgss_delete_sec_context(minor_stat,
830 &ap->context, NULL);
831 (void) gss_release_buffer(minor_stat, &process_token);
832 error = EACCES;
833 goto cleanup;
836 done:
838 * Validate the sequence window - RFC 2203 section 5.2.3.1
840 if (!validate_seqwin(ap)) {
841 error = EACCES;
842 goto cleanup;
846 * Done! Security context creation is successful.
847 * Ready for exchanging data.
849 ap->established = TRUE;
850 ap->seq_num = 1;
851 ap->gss_proc = RPCSEC_GSS_DATA;
852 ap->invalid = FALSE;
854 clnt->cl_auth = save_auth; /* restore cl_auth */
856 return (0);
858 cleanup:
859 if (free_results)
860 xdr_free(__xdr_rpc_gss_init_res, (caddr_t)&call_res);
861 clnt->cl_auth = save_auth; /* restore cl_auth */
864 * If need to retry for AUTH_REFRESH, do not cleanup the
865 * auth private data.
867 if (isrefresh && (error == ETIMEDOUT || error == ECONNRESET)) {
868 return (error);
871 if (ap->context != NULL) {
872 rpc_gss_free_pvt(auth);
875 return (error? error : EACCES);
879 * Marshall credentials.
881 static bool_t
882 marshall_creds(ap, xdrs, cred_buf_len)
883 rpc_gss_data *ap;
884 XDR *xdrs;
885 uint_t cred_buf_len;
887 rpc_gss_creds ag_creds;
888 char *cred_buf;
889 struct opaque_auth creds;
890 XDR cred_xdrs;
892 ag_creds.version = ap->version;
893 ag_creds.gss_proc = ap->gss_proc;
894 ag_creds.seq_num = ap->seq_num;
895 ag_creds.service = ap->service;
898 * If context has not been set up yet, use NULL handle.
900 if (ap->ctx_handle.length > 0)
901 ag_creds.ctx_handle = ap->ctx_handle;
902 else {
903 ag_creds.ctx_handle.length = 0;
904 ag_creds.ctx_handle.value = NULL;
907 cred_buf = kmem_alloc(cred_buf_len, KM_SLEEP);
908 xdrmem_create(&cred_xdrs, (caddr_t)cred_buf, cred_buf_len,
909 XDR_ENCODE);
910 if (!__xdr_rpc_gss_creds(&cred_xdrs, &ag_creds)) {
911 kmem_free(cred_buf, MAX_AUTH_BYTES);
912 XDR_DESTROY(&cred_xdrs);
913 return (FALSE);
916 creds.oa_flavor = RPCSEC_GSS;
917 creds.oa_base = cred_buf;
918 creds.oa_length = xdr_getpos(&cred_xdrs);
919 XDR_DESTROY(&cred_xdrs);
921 if (!xdr_opaque_auth(xdrs, &creds)) {
922 kmem_free(cred_buf, cred_buf_len);
923 return (FALSE);
926 kmem_free(cred_buf, cred_buf_len);
927 return (TRUE);
931 * Marshall verifier. The verifier is the checksum of the RPC header
932 * up to and including the credential field. The XDR handle that's
933 * passed in has the header up to and including the credential field
934 * encoded. A pointer to the transmit buffer is also passed in.
936 static bool_t
937 marshall_verf(ap, xdrs, buf)
938 rpc_gss_data *ap;
939 XDR *xdrs; /* send XDR */
940 char *buf; /* pointer of send buffer */
942 struct opaque_auth verf;
943 OM_uint32 major, minor;
944 gss_buffer_desc in_buf, out_buf;
945 bool_t ret = FALSE;
948 * If context is not established yet, use NULL verifier.
950 if (!ap->established) {
951 verf.oa_flavor = AUTH_NONE;
952 verf.oa_base = NULL;
953 verf.oa_length = 0;
954 return (xdr_opaque_auth(xdrs, &verf));
957 verf.oa_flavor = RPCSEC_GSS;
958 in_buf.length = xdr_getpos(xdrs);
959 in_buf.value = buf;
960 if ((major = kgss_sign(&minor, ap->context, ap->qop, &in_buf,
961 &out_buf)) != GSS_S_COMPLETE) {
962 if (major == GSS_S_CONTEXT_EXPIRED) {
963 ap->invalid = TRUE;
965 RPCGSS_LOG1(1,
966 "marshall_verf: kgss_sign failed GSS Major %x Minor %x\n",
967 major, minor);
968 return (FALSE);
970 verf.oa_base = out_buf.value;
971 verf.oa_length = out_buf.length;
972 ret = xdr_opaque_auth(xdrs, &verf);
973 (void) gss_release_buffer(&minor, &out_buf);
975 return (ret);
979 * Validate sequence window upon a successful RPCSEC_GSS INIT session.
980 * The sequence window sent back by the server should be verifiable by
981 * the verifier which is a checksum of the sequence window.
983 static bool_t
984 validate_seqwin(rpc_gss_data *ap)
986 uint_t seq_win_net;
987 OM_uint32 major = 0, minor = 0;
988 gss_buffer_desc msg_buf, tok_buf;
989 int qop_state = 0;
991 ASSERT(ap->verifier);
992 ASSERT(ap->context);
993 seq_win_net = (uint_t)htonl(ap->seq_window);
994 msg_buf.length = sizeof (seq_win_net);
995 msg_buf.value = (char *)&seq_win_net;
996 tok_buf.length = ap->verifier->oa_length;
997 tok_buf.value = ap->verifier->oa_base;
998 major = kgss_verify(&minor, ap->context, &msg_buf, &tok_buf,
999 &qop_state);
1001 if (major != GSS_S_COMPLETE) {
1002 RPCGSS_LOG1(1,
1003 "validate_seqwin: kgss_verify failed GSS Major "
1004 "%x Minor %x\n", major, minor);
1005 RPCGSS_LOG1(1, "seq_window %d, verf len %d ", ap->seq_window,
1006 ap->verifier->oa_length);
1007 return (FALSE);
1009 return (TRUE);
1013 * Validate RPC response verifier from server. The response verifier
1014 * is the checksum of the request sequence number.
1016 static bool_t
1017 rpc_gss_validate(auth, verf)
1018 AUTH *auth;
1019 struct opaque_auth *verf;
1021 rpc_gss_data *ap = AUTH_PRIVATE(auth);
1022 uint_t seq_num_net;
1023 OM_uint32 major, minor;
1024 gss_buffer_desc msg_buf, tok_buf;
1025 int qop_state;
1028 * If context is not established yet, save the verifier for
1029 * validating the sequence window later at the end of context
1030 * creation session.
1032 if (!ap->established) {
1033 if (ap->verifier == NULL) {
1034 ap->verifier = kmem_zalloc(sizeof (struct opaque_auth),
1035 KM_SLEEP);
1036 if (verf->oa_length > 0)
1037 ap->verifier->oa_base = kmem_zalloc(verf->oa_length,
1038 KM_SLEEP);
1039 } else {
1040 if (ap->verifier->oa_length > 0)
1041 kmem_free(ap->verifier->oa_base, ap->verifier->oa_length);
1042 if (verf->oa_length > 0)
1043 ap->verifier->oa_base = kmem_zalloc(verf->oa_length,
1044 KM_SLEEP);
1046 ap->verifier->oa_length = verf->oa_length;
1047 bcopy(verf->oa_base, ap->verifier->oa_base, verf->oa_length);
1048 return (TRUE);
1051 seq_num_net = (uint_t)htonl(ap->seq_num);
1052 msg_buf.length = sizeof (seq_num_net);
1053 msg_buf.value = (char *)&seq_num_net;
1054 tok_buf.length = verf->oa_length;
1055 tok_buf.value = verf->oa_base;
1056 major = kgss_verify(&minor, ap->context, &msg_buf, &tok_buf,
1057 &qop_state);
1058 if (major != GSS_S_COMPLETE) {
1059 RPCGSS_LOG1(1,
1060 "rpc_gss_validate: kgss_verify failed GSS Major %x Minor %x\n",
1061 major, minor);
1062 return (FALSE);
1064 return (TRUE);
1068 * Refresh client context. This is necessary sometimes because the
1069 * server will ocassionally destroy contexts based on LRU method, or
1070 * because of expired credentials.
1072 static bool_t
1073 rpc_gss_refresh(auth, msg, cr)
1074 AUTH *auth;
1075 struct rpc_msg *msg;
1076 cred_t *cr;
1078 rpc_gss_data *ap = AUTH_PRIVATE(auth);
1079 gss_ctx_id_t ctx_sav = NULL;
1080 gss_buffer_desc ctx_hdle_sav = {0, NULL};
1081 uint_t sn_sav, proc_sav;
1082 bool_t est_sav;
1083 OM_uint32 gssstat, minor_stat;
1084 int error;
1087 * The context needs to be recreated only when the error status
1088 * returned from the server is one of the following:
1089 * RPCSEC_GSS_NOCRED and RPCSEC_GSS_FAILED
1090 * The existing context should not be destroyed unless the above
1091 * error status codes are received or if the context has not
1092 * been set up.
1095 if (msg->rjcted_rply.rj_why == RPCSEC_GSS_NOCRED ||
1096 msg->rjcted_rply.rj_why == RPCSEC_GSS_FAILED ||
1097 !ap->established) {
1099 * Destroy the context if necessary. Use the same memory
1100 * for the new context since we've already passed a pointer
1101 * to it to the user.
1103 if (ap->context != NULL) {
1104 ctx_sav = ap->context;
1105 ap->context = NULL;
1107 if (ap->ctx_handle.length != 0) {
1108 ctx_hdle_sav.length = ap->ctx_handle.length;
1109 ctx_hdle_sav.value = ap->ctx_handle.value;
1110 ap->ctx_handle.length = 0;
1111 ap->ctx_handle.value = NULL;
1115 * If the context was not already established, don't try to
1116 * recreate it.
1118 if (!ap->established) {
1119 ap->invalid = TRUE;
1120 RPCGSS_LOG0(1,
1121 "rpc_gss_refresh: context was not established\n");
1122 error = EINVAL;
1123 goto out;
1126 est_sav = ap->established;
1127 sn_sav = ap->seq_num;
1128 proc_sav = ap->gss_proc;
1131 * Recreate context.
1133 error = rpc_gss_seccreate_pvt(&gssstat, &minor_stat, auth,
1134 ap, ap->mech_type, (gss_OID *)NULL, NULL,
1135 (OM_uint32 *)NULL, cr, 1);
1137 switch (error) {
1138 case 0:
1139 RPCGSS_LOG(1,
1140 "rpc_gss_refresh: auth %p refreshed\n", (void *)auth);
1141 goto out;
1143 case ETIMEDOUT:
1144 case ECONNRESET:
1145 RPCGSS_LOG0(1, "rpc_gss_refresh: try again\n");
1147 if (ap->context != NULL) {
1148 (void) kgss_delete_sec_context(&minor_stat,
1149 &ap->context, NULL);
1151 if (ap->ctx_handle.length != 0) {
1152 (void) gss_release_buffer(&minor_stat,
1153 &ap->ctx_handle);
1157 * Restore the original value for the caller to
1158 * try again later.
1160 ap->context = ctx_sav;
1161 ap->ctx_handle.length = ctx_hdle_sav.length;
1162 ap->ctx_handle.value = ctx_hdle_sav.value;
1163 ap->established = est_sav;
1164 ap->seq_num = sn_sav;
1165 ap->gss_proc = proc_sav;
1167 return (FALSE);
1169 default:
1170 ap->invalid = TRUE;
1171 RPCGSS_LOG(1, "rpc_gss_refresh: can't refresh this "
1172 "auth, error=%d\n", error);
1173 goto out;
1176 RPCGSS_LOG0(1, "rpc_gss_refresh: don't refresh");
1177 return (FALSE);
1179 out:
1180 if (ctx_sav != NULL) {
1181 (void) kgss_delete_sec_context(&minor_stat,
1182 &ctx_sav, NULL);
1184 if (ctx_hdle_sav.length != 0) {
1185 (void) gss_release_buffer(&minor_stat, &ctx_hdle_sav);
1188 return (error == 0);
1192 * Destroy a context.
1194 static void
1195 rpc_gss_destroy(auth)
1196 AUTH *auth;
1198 rpc_gss_data *ap = AUTH_PRIVATE(auth);
1201 * XXX Currently, we do not ping the server (rpc_gss_destroy_pvt)
1202 * to destroy the context in the server cache.
1203 * We assume there is a good LRU/aging mechanism for the
1204 * context cache on the server side.
1206 rpc_gss_free_pvt(auth);
1207 kmem_free((char *)ap, sizeof (*ap));
1208 kmem_free(auth, sizeof (*auth));
1212 * Private interface to free memory allocated in the rpcsec_gss private
1213 * data structure (rpc_gss_data).
1215 static void
1216 rpc_gss_free_pvt(auth)
1217 AUTH *auth;
1219 OM_uint32 minor_stat;
1220 rpc_gss_data *ap = AUTH_PRIVATE(auth);
1222 if (ap->ctx_handle.length != 0) {
1223 (void) gss_release_buffer(&minor_stat, &ap->ctx_handle);
1224 ap->ctx_handle.length = 0;
1225 ap->ctx_handle.value = NULL;
1229 * Destroy local GSS context.
1231 if (ap->context != NULL) {
1232 (void) kgss_delete_sec_context(&minor_stat, &ap->context, NULL);
1233 ap->context = NULL;
1237 * Looks like we need to release default credentials if we use it.
1238 * Non-default creds need to be released by user.
1240 if (ap->my_cred == GSS_C_NO_CREDENTIAL)
1241 (void) kgss_release_cred(&minor_stat, &ap->my_cred,
1242 crgetuid(CRED()));
1245 * Release any internal name structures.
1247 if (ap->target_name != NULL) {
1248 (void) gss_release_name(&minor_stat, &ap->target_name);
1249 ap->target_name = NULL;
1253 * Free mech_type oid structure.
1255 if (ap->mech_type != NULL) {
1256 kgss_free_oid(ap->mech_type);
1257 ap->mech_type = NULL;
1261 * Free the verifier saved for sequence window checking.
1263 if (ap->verifier != NULL) {
1264 if (ap->verifier->oa_length > 0) {
1265 kmem_free(ap->verifier->oa_base, ap->verifier->oa_length);
1267 kmem_free(ap->verifier, sizeof (struct opaque_auth));
1268 ap->verifier = NULL;
1272 #if 0
1274 * XXX this function is not used right now.
1275 * There is a client handle issue needs to be resolved.
1277 * This is a private interface which will destroy a context
1278 * without freeing up the memory used by it. We need to do this when
1279 * a refresh fails, for example, so the user will still have a handle.
1281 static void
1282 rpc_gss_destroy_pvt(auth)
1283 AUTH *auth;
1285 struct timeval timeout;
1286 rpc_gss_data *ap = AUTH_PRIVATE(auth);
1289 * If we have a server context id, inform server that we are
1290 * destroying the context.
1292 if (ap->ctx_handle.length != 0) {
1293 uint32_t oldxid;
1294 uint32_t zeroxid = 0;
1296 ap->gss_proc = RPCSEC_GSS_DESTROY;
1297 timeout.tv_sec = 10;
1298 timeout.tv_usec = 0;
1299 (void) CLNT_CONTROL(ap->clnt, CLGET_XID, (char *)&oldxid);
1300 (void) CLNT_CONTROL(ap->clnt, CLSET_XID, (char *)&zeroxid);
1301 (void) clnt_call(ap->clnt, NULLPROC, xdr_void, NULL,
1302 xdr_void, NULL, timeout);
1303 (void) CLNT_CONTROL(ap->clnt, CLSET_XID, (char *)&oldxid);
1306 rpc_gss_free_pvt(auth);
1308 #endif
1311 * Wrap client side data. The encoded header is passed in through
1312 * buf and buflen. The header is up to but not including the
1313 * credential field.
1315 bool_t
1316 rpc_gss_wrap(auth, buf, buflen, out_xdrs, xdr_func, xdr_ptr)
1317 AUTH *auth;
1318 char *buf; /* encoded header */
1319 /* has been changed to u_int in the user land */
1320 uint_t buflen; /* encoded header length */
1321 XDR *out_xdrs;
1322 xdrproc_t xdr_func;
1323 caddr_t xdr_ptr;
1325 rpc_gss_data *ap = AUTH_PRIVATE(auth);
1326 XDR xdrs;
1327 char *tmp_buf;
1328 uint_t xdr_buf_len, cred_buf_len;
1331 * Here is how MAX_SIGNED_LEN is estimated.
1332 * Signing a 48 bytes buffer using des_cbc_md5 would end up with
1333 * a buffer length 33 (padded data + 16 bytes of seq_num/checksum).
1334 * Current known max seq_num/checksum size is 24 bytes.
1335 * 88 is derived from RNDUP(33+(24-16)) * 2.
1337 #define MAX_SIGNED_LEN 88
1340 * Reject an invalid context.
1342 if (ap->invalid) {
1343 RPCGSS_LOG0(1, "rpc_gss_wrap: reject an invalid context\n");
1344 return (FALSE);
1348 * If context is established, bump up sequence number.
1350 if (ap->established)
1351 ap->seq_num++;
1354 * Create the header in a temporary XDR context and buffer
1355 * before putting it out.
1357 cred_buf_len = RNDUP(sizeof (ap->version) + sizeof (ap->gss_proc) +
1358 sizeof (ap->seq_num) + sizeof (ap->service) +
1359 sizeof (ap->ctx_handle) + ap->ctx_handle.length);
1361 xdr_buf_len = buflen + cred_buf_len + sizeof (struct opaque_auth) +
1362 MAX_SIGNED_LEN;
1363 tmp_buf = kmem_alloc(xdr_buf_len, KM_SLEEP);
1364 xdrmem_create(&xdrs, tmp_buf, xdr_buf_len, XDR_ENCODE);
1365 if (!XDR_PUTBYTES(&xdrs, buf, buflen)) {
1366 kmem_free(tmp_buf, xdr_buf_len);
1367 RPCGSS_LOG0(1, "rpc_gss_wrap: xdr putbytes failed\n");
1368 return (FALSE);
1372 * create cred field
1374 if (!marshall_creds(ap, &xdrs, cred_buf_len)) {
1375 kmem_free(tmp_buf, xdr_buf_len);
1376 RPCGSS_LOG0(1, "rpc_gss_wrap: marshall_creds failed\n");
1377 return (FALSE);
1381 * create verifier
1383 if (!marshall_verf(ap, &xdrs, tmp_buf)) {
1384 kmem_free(tmp_buf, xdr_buf_len);
1385 RPCGSS_LOG0(1, "rpc_gss_wrap: marshall_verf failed\n");
1386 return (FALSE);
1390 * write out header and destroy temp structures
1392 if (!XDR_PUTBYTES(out_xdrs, tmp_buf, XDR_GETPOS(&xdrs))) {
1393 kmem_free(tmp_buf, xdr_buf_len);
1394 RPCGSS_LOG0(1, "rpc_gss_wrap: write out header failed\n");
1395 return (FALSE);
1397 XDR_DESTROY(&xdrs);
1398 kmem_free(tmp_buf, xdr_buf_len);
1401 * If context is not established, or if neither integrity
1402 * nor privacy is used, just XDR encode data.
1404 if (!ap->established || ap->service == rpc_gss_svc_none) {
1405 return ((*xdr_func)(out_xdrs, xdr_ptr));
1408 return (__rpc_gss_wrap_data(ap->service, ap->qop, ap->context,
1409 ap->seq_num, out_xdrs, xdr_func, xdr_ptr));
1413 * Unwrap received data.
1415 bool_t
1416 rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr)
1417 AUTH *auth;
1418 XDR *in_xdrs;
1419 bool_t (*xdr_func)();
1420 caddr_t xdr_ptr;
1422 rpc_gss_data *ap = AUTH_PRIVATE(auth);
1425 * If context is not established, of if neither integrity
1426 * nor privacy is used, just XDR encode data.
1428 if (!ap->established || ap->service == rpc_gss_svc_none)
1429 return ((*xdr_func)(in_xdrs, xdr_ptr));
1431 return (__rpc_gss_unwrap_data(ap->service,
1432 ap->context,
1433 ap->seq_num,
1434 ap->qop,
1435 in_xdrs, xdr_func, xdr_ptr));
1439 * Revoke an GSSAPI based security credentials
1440 * from the cache table.
1443 rpc_gss_revauth(uid_t uid, rpc_gss_OID mech)
1445 struct ga_cache_entry *next, *prev, *cur;
1446 rpc_gss_data *ap;
1447 zoneid_t zoneid = getzoneid();
1448 int i;
1451 * Check the cache table against the uid and the
1452 * mechanism type.
1454 rw_enter(&ga_cache_table_lock, RW_WRITER);
1455 for (i = 0; i < GSSAUTH_TABLESIZE; i++) {
1456 prev = NULL;
1457 for (cur = ga_cache_table[i]; cur; cur = next) {
1458 NOT_DEAD(cur);
1459 next = cur->next;
1460 NOT_DEAD(next);
1461 ap = AUTH_PRIVATE(cur->auth);
1462 if (__rpc_gss_oids_equal(ap->mech_type,
1463 (gss_OID) mech) && (cur->uid == uid) &&
1464 (cur->zoneid == zoneid)) {
1465 if (cur->in_use) {
1466 RPCGSS_LOG(2, "rpc_gss_revauth:invalid "
1467 "auth %p\n", (void *)cur->auth);
1468 ap->invalid = TRUE;
1469 } else {
1470 RPCGSS_LOG(2, "rpc_gss_revauth:destroy "
1471 "auth %p\n", (void *)cur->auth);
1472 rpc_gss_destroy(cur->auth);
1473 kmem_cache_free(ga_cache_handle,
1474 (void *)cur);
1476 if (prev == NULL) {
1477 ga_cache_table[i] = next;
1478 } else {
1479 prev->next = next;
1480 NOT_DEAD(prev->next);
1482 } else {
1483 prev = cur;
1487 rw_exit(&ga_cache_table_lock);
1489 return (0);
1494 * Delete all the entries indexed by the cache_key.
1496 * For example, the cache_key used for NFS is the address of the
1497 * security entry for each mount point. When the file system is unmounted,
1498 * all the cache entries indexed by this key should be deleted.
1500 void
1501 rpc_gss_secpurge(void *cache_key)
1503 struct ga_cache_entry *next, *prev, *cur;
1504 int i;
1507 * Check the cache table against the cache_key.
1509 rw_enter(&ga_cache_table_lock, RW_WRITER);
1510 for (i = 0; i < GSSAUTH_TABLESIZE; i++) {
1511 prev = NULL;
1512 for (cur = ga_cache_table[i]; cur; cur = next) {
1513 NOT_DEAD(cur);
1514 next = cur->next;
1515 NOT_DEAD(next);
1516 if (cache_key == cur->cache_key) {
1517 RPCGSS_LOG(2, "rpc_gss_secpurge: destroy auth "
1518 "%p\n", (void *)cur->auth);
1519 if (cur->in_use == FALSE)
1520 rpc_gss_destroy(cur->auth);
1521 kmem_cache_free(ga_cache_handle, (void *)cur);
1522 if (prev == NULL) {
1523 ga_cache_table[i] = next;
1524 } else {
1525 NOT_DEAD(prev->next);
1526 prev->next = next;
1528 } else {
1529 prev = cur;
1533 rw_exit(&ga_cache_table_lock);
1537 * Function: rpc_gss_nextverf. Not used.
1539 static void
1540 rpc_gss_nextverf()
1545 * Function: rpc_gss_marshall - no op routine.
1546 * rpc_gss_wrap() is doing the marshalling.
1548 /*ARGSUSED*/
1549 static bool_t
1550 rpc_gss_marshall(auth, xdrs)
1551 AUTH *auth;
1552 XDR *xdrs;
1554 return (TRUE);
1558 * Set service defaults.
1559 * Not supported yet.
1561 /* ARGSUSED */
1562 bool_t
1563 rpc_gss_set_defaults(auth, service, qop)
1564 AUTH *auth;
1565 rpc_gss_service_t service;
1566 uint_t qop;
1568 return (FALSE);
1571 /* ARGSUSED */
1573 rpc_gss_max_data_length(AUTH *rpcgss_handle, int max_tp_unit_len)
1575 return (0);
1578 rpc_gss_service_t
1579 rpc_gss_get_service_type(AUTH *auth)
1581 rpc_gss_data *ap = AUTH_PRIVATE(auth);
1583 return (ap->service);