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]
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
24 * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
25 * Copyright 2012 Milan Jurik. All rights reserved.
26 * Copyright 2012 Marcel Telka <marcel@telka.sk>
27 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
31 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
33 * $Id: svc_auth_gssapi.c,v 1.19 1994/10/27 12:38:51 jik Exp $
37 * Server side handling of RPCSEC_GSS flavor.
40 #include <sys/systm.h>
41 #include <sys/kstat.h>
42 #include <sys/cmn_err.h>
43 #include <sys/debug.h>
44 #include <sys/types.h>
46 #include <gssapi/gssapi.h>
47 #include <gssapi/gssapi_ext.h>
49 #include <rpc/rpcsec_defs.h>
50 #include <sys/sunddi.h>
51 #include <sys/atomic.h>
53 extern bool_t
__rpc_gss_make_principal(rpc_gss_principal_t
*, gss_buffer_t
);
56 extern void prom_printf(const char *, ...);
60 #define memcmp(a, b, l) bcmp((a), (b), (l))
65 * Sequence window definitions.
67 #define SEQ_ARR_SIZE 4
68 #define SEQ_WIN (SEQ_ARR_SIZE*32)
69 #define SEQ_HI_BIT 0x80000000
73 #define SEQ_MAX ((unsigned int)0x80000000)
76 /* cache retransmit data */
77 typedef struct _retrans_entry
{
79 rpc_gss_init_res result
;
83 * Server side RPCSEC_GSS context information.
85 typedef struct _svc_rpc_gss_data
{
86 struct _svc_rpc_gss_data
*next
, *prev
;
87 struct _svc_rpc_gss_data
*lru_next
, *lru_prev
;
90 gss_buffer_desc client_name
;
93 uint_t seq_bits
[SEQ_ARR_SIZE
];
96 bool_t done_docallback
;
98 rpc_gss_rawcred_t raw_cred
;
99 rpc_gss_ucred_t u_cred
;
105 time_t last_ref_time
;
107 retrans_entry
*retrans_data
;
111 * Data structures used for LRU based context management.
115 #define HASH(key) ((key) % svc_rpc_gss_hashmod)
116 /* Size of hash table for svc_rpc_gss_data structures */
117 #define GSS_DATA_HASH_SIZE 1024
120 * The following two defines specify a time delta that is used in
121 * sweep_clients. When the last_ref_time of a context is older than
122 * than the current time minus the delta, i.e, the context has not
123 * been referenced in the last delta seconds, we will return the
124 * context back to the cache if the ref_cnt is zero. The first delta
125 * value will be used when sweep_clients is called from
126 * svc_data_reclaim, the kmem_cache reclaim call back. We will reclaim
127 * all entries except those that are currently "active". By active we
128 * mean those that have been referenced in the last ACTIVE_DELTA
129 * seconds. If sweep_client is not being called from reclaim, then we
130 * will reclaim all entries that are "inactive". By inactive we mean
131 * those entries that have not been accessed in INACTIVE_DELTA
132 * seconds. Note we always assume that ACTIVE_DELTA is less than
133 * INACTIVE_DELTA, so that reaping entries from a reclaim operation
134 * will necessarily imply reaping all "inactive" entries and then
139 * If low on memory reap cache entries that have not been active for
140 * ACTIVE_DELTA seconds and have a ref_cnt equal to zero.
142 #define ACTIVE_DELTA 30*60 /* 30 minutes */
145 * If in sweeping contexts we find contexts with a ref_cnt equal to zero
146 * and the context has not been referenced in INACTIVE_DELTA seconds, return
147 * the entry to the cache.
149 #define INACTIVE_DELTA 8*60*60 /* 8 hours */
151 int svc_rpc_gss_hashmod
= GSS_DATA_HASH_SIZE
;
152 static svc_rpc_gss_data
**clients
;
153 static svc_rpc_gss_data
*lru_first
, *lru_last
;
154 static time_t sweep_interval
= 60*60;
155 static time_t last_swept
= 0;
156 static int num_gss_contexts
= 0;
157 static time_t svc_rpcgss_gid_timeout
= 60*60*12;
158 static kmem_cache_t
*svc_data_handle
;
159 static time_t svc_rpc_gss_active_delta
= ACTIVE_DELTA
;
160 static time_t svc_rpc_gss_inactive_delta
= INACTIVE_DELTA
;
163 * lock used with context/lru variables
165 static kmutex_t ctx_mutex
;
168 * Data structure to contain cache statistics
172 int64_t total_entries_allocated
;
174 int64_t no_returned_by_reclaim
;
175 } svc_rpc_gss_cache_stats
;
179 * lock used with server credential variables list
181 * server cred list locking guidelines:
182 * - Writer's lock holder has exclusive access to the list
184 static krwlock_t cred_lock
;
187 * server callback list
189 typedef struct rpc_gss_cblist_s
{
190 struct rpc_gss_cblist_s
*next
;
191 rpc_gss_callback_t cb
;
194 static rpc_gss_cblist_t
*rpc_gss_cblist
= NULL
;
197 * lock used with callback variables
199 static kmutex_t cb_mutex
;
202 * forward declarations
204 static bool_t
svc_rpc_gss_wrap();
205 static bool_t
svc_rpc_gss_unwrap();
206 static svc_rpc_gss_data
*create_client();
207 static svc_rpc_gss_data
*get_client();
208 static svc_rpc_gss_data
*find_client();
209 static void destroy_client();
210 static void sweep_clients(bool_t
);
211 static void insert_client();
212 static bool_t
check_verf(struct rpc_msg
*, gss_ctx_id_t
,
214 static bool_t
set_response_verf();
215 static void retrans_add(svc_rpc_gss_data
*, uint32_t,
217 static void retrans_del(svc_rpc_gss_data
*);
218 static bool_t
transfer_sec_context(svc_rpc_gss_data
*);
219 static void common_client_data_free(svc_rpc_gss_data
*);
222 * server side wrap/unwrap routines
224 struct svc_auth_ops svc_rpc_gss_ops
= {
230 typedef struct svcrpcsec_gss_taskq_arg
{
232 rpc_gss_init_arg
*rpc_call_arg
;
234 svc_rpc_gss_data
*client_data
;
236 rpc_gss_service_t cr_service
;
237 } svcrpcsec_gss_taskq_arg_t
;
239 /* gssd is single threaded, so 1 thread for the taskq is probably good/ok */
240 int rpcsec_gss_init_taskq_nthreads
= 1;
241 static ddi_taskq_t
*svcrpcsec_gss_init_taskq
= NULL
;
243 extern struct rpc_msg
*rpc_msg_dup(struct rpc_msg
*);
244 extern void rpc_msg_free(struct rpc_msg
**, int);
248 * Transport private data.
249 * Kept in xprt->xp_p2buf.
252 mblk_t
*ud_resp
; /* buffer for response */
253 mblk_t
*ud_inmp
; /* mblk chain of request */
258 svc_gss_data_create(void *buf
, void *pdata
, int kmflag
)
260 svc_rpc_gss_data
*client_data
= (svc_rpc_gss_data
*)buf
;
262 mutex_init(&client_data
->clm
, NULL
, MUTEX_DEFAULT
, NULL
);
269 svc_gss_data_destroy(void *buf
, void *pdata
)
271 svc_rpc_gss_data
*client_data
= (svc_rpc_gss_data
*)buf
;
273 mutex_destroy(&client_data
->clm
);
279 svc_gss_data_reclaim(void *pdata
)
281 mutex_enter(&ctx_mutex
);
283 svc_rpc_gss_cache_stats
.no_reclaims
++;
286 mutex_exit(&ctx_mutex
);
290 * Init stuff on the server side.
295 mutex_init(&cb_mutex
, NULL
, MUTEX_DEFAULT
, NULL
);
296 mutex_init(&ctx_mutex
, NULL
, MUTEX_DEFAULT
, NULL
);
297 rw_init(&cred_lock
, NULL
, RW_DEFAULT
, NULL
);
298 clients
= (svc_rpc_gss_data
**)
299 kmem_zalloc(svc_rpc_gss_hashmod
* sizeof (svc_rpc_gss_data
*),
301 svc_data_handle
= kmem_cache_create("rpc_gss_data_cache",
302 sizeof (svc_rpc_gss_data
), 0,
304 svc_gss_data_destroy
,
305 svc_gss_data_reclaim
,
308 if (svcrpcsec_gss_init_taskq
== NULL
) {
309 svcrpcsec_gss_init_taskq
= ddi_taskq_create(NULL
,
310 "rpcsec_gss_init_taskq", rpcsec_gss_init_taskq_nthreads
,
311 TASKQ_DEFAULTPRI
, 0);
312 if (svcrpcsec_gss_init_taskq
== NULL
)
314 "svc_gss_init: ddi_taskq_create failed");
319 * Destroy structures allocated in svc_gss_init().
320 * This routine is called by _init() if mod_install() failed.
325 mutex_destroy(&cb_mutex
);
326 mutex_destroy(&ctx_mutex
);
327 rw_destroy(&cred_lock
);
328 kmem_free(clients
, svc_rpc_gss_hashmod
* sizeof (svc_rpc_gss_data
*));
329 kmem_cache_destroy(svc_data_handle
);
333 * Cleanup routine for destroying context, called after service
334 * procedure is executed. Actually we just decrement the reference count
335 * associated with this context. If the reference count is zero and the
336 * context is marked as stale, we would then destroy the context. Additionally,
337 * we check if its been longer than sweep_interval since the last sweep_clients
338 * was run, and if so run sweep_clients to free all stale contexts with zero
339 * reference counts or contexts that are old. (Haven't been access in
340 * svc_rpc_inactive_delta seconds).
343 rpc_gss_cleanup(SVCXPRT
*clone_xprt
)
345 svc_rpc_gss_data
*cl
;
349 * First check if current context needs to be cleaned up.
350 * There might be other threads stale this client data
353 svcauth
= &clone_xprt
->xp_auth
;
354 mutex_enter(&ctx_mutex
);
355 if ((cl
= (svc_rpc_gss_data
*)svcauth
->svc_ah_private
) != NULL
) {
356 mutex_enter(&cl
->clm
);
357 ASSERT(cl
->ref_cnt
> 0);
358 if (--cl
->ref_cnt
== 0 && cl
->stale
) {
359 mutex_exit(&cl
->clm
);
361 svcauth
->svc_ah_private
= NULL
;
363 mutex_exit(&cl
->clm
);
367 * Check for other expired contexts.
369 if ((gethrestime_sec() - last_swept
) > sweep_interval
)
370 sweep_clients(FALSE
);
372 mutex_exit(&ctx_mutex
);
376 * Shift the array arr of length arrlen right by nbits bits.
379 shift_bits(uint_t
*arr
, int arrlen
, int nbits
)
385 * If the number of bits to be shifted exceeds SEQ_WIN, just
386 * zero out the array.
388 if (nbits
< SEQ_WIN
) {
389 for (i
= 0; i
< nbits
; i
++) {
391 for (j
= 0; j
< arrlen
; j
++) {
392 lo
= arr
[j
] & SEQ_LO_BIT
;
395 arr
[j
] |= SEQ_HI_BIT
;
400 for (j
= 0; j
< arrlen
; j
++)
406 * Check that the received sequence number seq_num is valid.
409 check_seq(svc_rpc_gss_data
*cl
, uint_t seq_num
, bool_t
*kill_context
)
415 * If it exceeds the maximum, kill context.
417 if (seq_num
>= SEQ_MAX
) {
418 *kill_context
= TRUE
;
419 RPCGSS_LOG0(4, "check_seq: seq_num not valid\n");
424 * If greater than the last seen sequence number, just shift
425 * the sequence window so that it starts at the new sequence
426 * number and extends downwards by SEQ_WIN.
428 if (seq_num
> cl
->seq_num
) {
429 (void) shift_bits(cl
->seq_bits
, SEQ_ARR_SIZE
,
430 (int)(seq_num
- cl
->seq_num
));
431 cl
->seq_bits
[0] |= SEQ_HI_BIT
;
432 cl
->seq_num
= seq_num
;
437 * If it is outside the sequence window, return failure.
439 i
= cl
->seq_num
- seq_num
;
441 RPCGSS_LOG0(4, "check_seq: seq_num is outside the window\n");
446 * If within sequence window, set the bit corresponding to it
447 * if not already seen; if already seen, return failure.
449 j
= SEQ_MASK
- (i
& SEQ_MASK
);
450 bit
= j
> 0 ? (1 << j
) : 1;
452 if (cl
->seq_bits
[i
] & bit
) {
453 RPCGSS_LOG0(4, "check_seq: sequence number already seen\n");
456 cl
->seq_bits
[i
] |= bit
;
461 * Set server callback.
464 rpc_gss_set_callback(rpc_gss_callback_t
*cb
)
466 rpc_gss_cblist_t
*cbl
, *tmp
;
468 if (cb
->callback
== NULL
) {
469 RPCGSS_LOG0(1, "rpc_gss_set_callback: no callback to set\n");
473 /* check if there is already an entry in the rpc_gss_cblist. */
474 mutex_enter(&cb_mutex
);
475 if (rpc_gss_cblist
) {
476 for (tmp
= rpc_gss_cblist
; tmp
!= NULL
; tmp
= tmp
->next
) {
477 if ((tmp
->cb
.callback
== cb
->callback
) &&
478 (tmp
->cb
.version
== cb
->version
) &&
479 (tmp
->cb
.program
== cb
->program
)) {
480 mutex_exit(&cb_mutex
);
486 /* Not in rpc_gss_cblist. Create a new entry. */
487 if ((cbl
= (rpc_gss_cblist_t
*)kmem_alloc(sizeof (*cbl
), KM_SLEEP
))
489 mutex_exit(&cb_mutex
);
493 cbl
->next
= rpc_gss_cblist
;
494 rpc_gss_cblist
= cbl
;
495 mutex_exit(&cb_mutex
);
500 * Locate callback (if specified) and call server. Release any
501 * delegated credentials unless passed to server and the server
502 * accepts the context. If a callback is not specified, accept
503 * the incoming context.
506 do_callback(struct svc_req
*req
, svc_rpc_gss_data
*client_data
)
508 rpc_gss_cblist_t
*cbl
;
509 bool_t ret
= TRUE
, found
= FALSE
;
512 mutex_enter(&cb_mutex
);
513 for (cbl
= rpc_gss_cblist
; cbl
!= NULL
; cbl
= cbl
->next
) {
514 if (req
->rq_prog
!= cbl
->cb
.program
||
515 req
->rq_vers
!= cbl
->cb
.version
)
519 lock
.raw_cred
= &client_data
->raw_cred
;
520 ret
= (*cbl
->cb
.callback
)(req
, client_data
->deleg
,
521 client_data
->context
, &lock
, &client_data
->cookie
);
522 req
->rq_xprt
->xp_cookie
= client_data
->cookie
;
525 client_data
->locked
= lock
.locked
;
526 client_data
->deleg
= GSS_C_NO_CREDENTIAL
;
531 if (client_data
->deleg
!= GSS_C_NO_CREDENTIAL
) {
532 (void) kgss_release_cred(&minor
, &client_data
->deleg
,
534 client_data
->deleg
= GSS_C_NO_CREDENTIAL
;
537 mutex_exit(&cb_mutex
);
542 * Get caller credentials.
545 rpc_gss_getcred(struct svc_req
*req
, rpc_gss_rawcred_t
**rcred
,
546 rpc_gss_ucred_t
**ucred
, void **cookie
)
549 svc_rpc_gss_data
*client_data
;
552 svcauth
= &req
->rq_xprt
->xp_auth
;
553 client_data
= (svc_rpc_gss_data
*)svcauth
->svc_ah_private
;
555 mutex_enter(&client_data
->clm
);
558 svcauth
->raw_cred
= client_data
->raw_cred
;
559 *rcred
= &svcauth
->raw_cred
;
562 *ucred
= &client_data
->u_cred
;
564 if (client_data
->u_cred_set
== 0 ||
565 client_data
->u_cred_set
< gethrestime_sec()) {
566 if (client_data
->u_cred_set
== 0) {
567 if ((gssstat
= kgsscred_expname_to_unix_cred(
568 &client_data
->client_name
,
569 &client_data
->u_cred
.uid
,
570 &client_data
->u_cred
.gid
,
571 &client_data
->u_cred
.gidlist
,
572 &gidlen
, crgetuid(CRED())))
574 RPCGSS_LOG(1, "rpc_gss_getcred: "
575 "kgsscred_expname_to_unix_cred "
576 "failed %x\n", gssstat
);
579 client_data
->u_cred
.gidlen
=
581 client_data
->u_cred_set
=
583 svc_rpcgss_gid_timeout
;
585 } else if (client_data
->u_cred_set
586 < gethrestime_sec()) {
587 if ((gssstat
= kgss_get_group_info(
588 client_data
->u_cred
.uid
,
589 &client_data
->u_cred
.gid
,
590 &client_data
->u_cred
.gidlist
,
591 &gidlen
, crgetuid(CRED())))
593 RPCGSS_LOG(1, "rpc_gss_getcred: "
594 "kgss_get_group_info failed %x\n",
598 client_data
->u_cred
.gidlen
=
600 client_data
->u_cred_set
=
602 svc_rpcgss_gid_timeout
;
609 *cookie
= client_data
->cookie
;
610 req
->rq_xprt
->xp_cookie
= client_data
->cookie
;
612 mutex_exit(&client_data
->clm
);
618 * Transfer the context data from the user land to the kernel.
620 bool_t
transfer_sec_context(svc_rpc_gss_data
*client_data
) {
622 gss_buffer_desc process_token
;
623 OM_uint32 gssstat
, minor
;
626 * Call kgss_export_sec_context
627 * if an error is returned log a message
628 * go to error handling
629 * Otherwise call kgss_import_sec_context to
630 * convert the token into a context
632 gssstat
= kgss_export_sec_context(&minor
, client_data
->context
,
635 * if export_sec_context returns an error we delete the
636 * context just to be safe.
638 if (gssstat
== GSS_S_NAME_NOT_MN
) {
639 RPCGSS_LOG0(4, "svc_rpcsec_gss: export sec context "
640 "Kernel mod unavailable\n");
642 } else if (gssstat
!= GSS_S_COMPLETE
) {
643 RPCGSS_LOG(1, "svc_rpcsec_gss: export sec context failed "
644 " gssstat = 0x%x\n", gssstat
);
645 (void) gss_release_buffer(&minor
, &process_token
);
646 (void) kgss_delete_sec_context(&minor
, &client_data
->context
,
650 } else if (process_token
.length
== 0) {
651 RPCGSS_LOG0(1, "svc_rpcsec_gss:zero length token in response "
652 "for export_sec_context, but "
653 "gsstat == GSS_S_COMPLETE\n");
654 (void) kgss_delete_sec_context(&minor
, &client_data
->context
,
659 gssstat
= kgss_import_sec_context(&minor
, &process_token
,
660 client_data
->context
);
661 if (gssstat
!= GSS_S_COMPLETE
) {
662 RPCGSS_LOG(1, "svc_rpcsec_gss: import sec context "
663 " failed gssstat = 0x%x\n", gssstat
);
664 (void) kgss_delete_sec_context(&minor
,
665 &client_data
->context
, NULL
);
666 (void) gss_release_buffer(&minor
, &process_token
);
670 RPCGSS_LOG0(4, "gss_import_sec_context successful\n");
671 (void) gss_release_buffer(&minor
, &process_token
);
678 * do_gss_accept is called from a taskq and does all the work for a
679 * RPCSEC_GSS_INIT call (mostly calling kgss_accept_sec_context()).
681 static enum auth_stat
684 rpc_gss_init_arg
*call_arg
,
686 svc_rpc_gss_data
*client_data
,
688 rpc_gss_service_t cr_service
)
690 rpc_gss_init_res call_res
;
691 gss_buffer_desc output_token
;
692 OM_uint32 gssstat
, minor
, minor_stat
, time_rec
;
694 gss_OID mech_type
= GSS_C_NULL_OID
;
695 int free_mech_type
= 1;
696 struct svc_req r
, *rqst
;
699 rqst
->rq_xprt
= xprt
;
702 * Initialize output_token.
704 output_token
.length
= 0;
705 output_token
.value
= NULL
;
707 bzero((char *)&call_res
, sizeof (call_res
));
709 mutex_enter(&client_data
->clm
);
710 if (client_data
->stale
) {
711 ret
= RPCSEC_GSS_NOCRED
;
712 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
717 * Any response we send will use ctx_handle, so set it now;
718 * also set seq_window since this won't change.
720 call_res
.ctx_handle
.length
= sizeof (client_data
->key
);
721 call_res
.ctx_handle
.value
= (char *)&client_data
->key
;
722 call_res
.seq_window
= SEQ_WIN
;
724 gssstat
= GSS_S_FAILURE
;
727 rw_enter(&cred_lock
, RW_READER
);
729 if (client_data
->client_name
.length
) {
730 (void) gss_release_buffer(&minor
,
731 &client_data
->client_name
);
733 gssstat
= kgss_accept_sec_context(&minor_stat
,
734 &client_data
->context
,
737 GSS_C_NO_CHANNEL_BINDINGS
,
738 &client_data
->client_name
,
743 NULL
, /* don't need a delegated cred back */
746 RPCGSS_LOG(4, "gssstat 0x%x \n", gssstat
);
748 if (gssstat
== GSS_S_COMPLETE
) {
750 * Set the raw and unix credentials at this
751 * point. This saves a lot of computation
752 * later when credentials are retrieved.
754 client_data
->raw_cred
.version
= cr_version
;
755 client_data
->raw_cred
.service
= cr_service
;
757 if (client_data
->raw_cred
.mechanism
) {
758 kgss_free_oid(client_data
->raw_cred
.mechanism
);
759 client_data
->raw_cred
.mechanism
= NULL
;
761 client_data
->raw_cred
.mechanism
= (rpc_gss_OID
) mech_type
;
763 * client_data is now responsible for freeing
764 * the data of 'mech_type'.
768 if (client_data
->raw_cred
.client_principal
) {
769 kmem_free((caddr_t
)client_data
->\
770 raw_cred
.client_principal
,
771 client_data
->raw_cred
.\
772 client_principal
->len
+ sizeof (int));
773 client_data
->raw_cred
.client_principal
= NULL
;
777 * The client_name returned from
778 * kgss_accept_sec_context() is in an
779 * exported flat format.
781 if (! __rpc_gss_make_principal(
782 &client_data
->raw_cred
.client_principal
,
783 &client_data
->client_name
)) {
784 RPCGSS_LOG0(1, "_svcrpcsec_gss: "
785 "make principal failed\n");
786 gssstat
= GSS_S_FAILURE
;
787 (void) gss_release_buffer(&minor_stat
, &output_token
);
793 call_res
.gss_major
= gssstat
;
794 call_res
.gss_minor
= minor_stat
;
796 if (gssstat
!= GSS_S_COMPLETE
&&
797 gssstat
!= GSS_S_CONTINUE_NEEDED
) {
798 call_res
.ctx_handle
.length
= 0;
799 call_res
.ctx_handle
.value
= NULL
;
800 call_res
.seq_window
= 0;
801 rpc_gss_display_status(gssstat
, minor_stat
, mech_type
,
803 "_svc_rpcsec_gss gss_accept_sec_context");
804 (void) svc_sendreply(rqst
->rq_xprt
,
805 __xdr_rpc_gss_init_res
, (caddr_t
)&call_res
);
806 client_data
->stale
= TRUE
;
812 * If appropriate, set established to TRUE *after* sending
813 * response (otherwise, the client will receive the final
816 if (gssstat
== GSS_S_COMPLETE
) {
818 * Context is established. Set expiration time
821 client_data
->seq_num
= 1;
822 if ((time_rec
== GSS_C_INDEFINITE
) || (time_rec
== 0)) {
823 client_data
->expiration
= GSS_C_INDEFINITE
;
825 client_data
->expiration
=
826 time_rec
+ gethrestime_sec();
829 if (!transfer_sec_context(client_data
)) {
830 ret
= RPCSEC_GSS_FAILED
;
831 client_data
->stale
= TRUE
;
833 "_svc_rpcsec_gss: transfer sec context failed\n");
837 client_data
->established
= TRUE
;
841 * This step succeeded. Send a response, along with
842 * a token if there's one. Don't dispatch.
845 if (output_token
.length
!= 0)
846 GSS_COPY_BUFFER(call_res
.token
, output_token
);
849 * If GSS_S_COMPLETE: set response verifier to
850 * checksum of SEQ_WIN
852 if (gssstat
== GSS_S_COMPLETE
) {
853 if (!set_response_verf(rqst
, msg
, client_data
,
855 ret
= RPCSEC_GSS_FAILED
;
856 client_data
->stale
= TRUE
;
858 "_svc_rpcsec_gss:set response verifier failed\n");
863 if (!svc_sendreply(rqst
->rq_xprt
, __xdr_rpc_gss_init_res
,
864 (caddr_t
)&call_res
)) {
865 ret
= RPCSEC_GSS_FAILED
;
866 client_data
->stale
= TRUE
;
867 RPCGSS_LOG0(1, "_svc_rpcsec_gss:send reply failed\n");
872 * Cache last response in case it is lost and the client
873 * retries on an established context.
875 (void) retrans_add(client_data
, msg
->rm_xid
, &call_res
);
876 ASSERT(client_data
->ref_cnt
> 0);
877 client_data
->ref_cnt
--;
878 mutex_exit(&client_data
->clm
);
880 (void) gss_release_buffer(&minor_stat
, &output_token
);
885 ASSERT(client_data
->ref_cnt
> 0);
886 client_data
->ref_cnt
--;
887 mutex_exit(&client_data
->clm
);
888 (void) gss_release_buffer(&minor_stat
, &output_token
);
889 if (free_mech_type
&& mech_type
)
890 kgss_free_oid(mech_type
);
896 svcrpcsec_gss_taskq_func(void *svcrpcsecgss_taskq_arg
)
898 enum auth_stat retval
;
899 svcrpcsec_gss_taskq_arg_t
*arg
= svcrpcsecgss_taskq_arg
;
901 retval
= do_gss_accept(arg
->rq_xprt
, arg
->rpc_call_arg
, arg
->msg
,
902 arg
->client_data
, arg
->cr_version
, arg
->cr_service
);
903 if (retval
!= AUTH_OK
) {
905 "svcrpcsec_gss_taskq_func: do_gss_accept fail 0x%x",
908 rpc_msg_free(&arg
->msg
, MAX_AUTH_BYTES
);
909 SVC_RELE(arg
->rq_xprt
, NULL
, FALSE
);
910 svc_clone_unlink(arg
->rq_xprt
);
911 svc_clone_free(arg
->rq_xprt
);
912 xdr_free(__xdr_rpc_gss_init_arg
, (caddr_t
)arg
->rpc_call_arg
);
913 kmem_free(arg
->rpc_call_arg
, sizeof (*arg
->rpc_call_arg
));
915 kmem_free(arg
, sizeof (*arg
));
918 static enum auth_stat
920 struct svc_req
*rqst
,
924 svc_rpc_gss_data
*c_d
) /* client data, can be NULL */
926 svc_rpc_gss_data
*client_data
;
928 svcrpcsec_gss_taskq_arg_t
*arg
;
930 if (creds
.ctx_handle
.length
!= 0) {
931 RPCGSS_LOG0(1, "_svcrpcsec_gss: ctx_handle not null\n");
936 client_data
= c_d
? c_d
: create_client();
937 if (client_data
== NULL
) {
939 "_svcrpcsec_gss: can't create a new cache entry\n");
944 mutex_enter(&client_data
->clm
);
945 if (client_data
->stale
) {
946 ret
= RPCSEC_GSS_NOCRED
;
947 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
952 * kgss_accept_sec_context()/gssd(8) can be overly time
953 * consuming so let's queue it and return asap.
955 * taskq func must free arg.
957 arg
= kmem_alloc(sizeof (*arg
), KM_SLEEP
);
959 /* taskq func must free rpc_call_arg & deserialized arguments */
960 arg
->rpc_call_arg
= kmem_zalloc(sizeof (*arg
->rpc_call_arg
), KM_SLEEP
);
962 /* deserialize arguments */
963 if (!SVC_GETARGS(rqst
->rq_xprt
, __xdr_rpc_gss_init_arg
,
964 (caddr_t
)arg
->rpc_call_arg
)) {
965 ret
= RPCSEC_GSS_FAILED
;
966 client_data
->stale
= TRUE
;
970 /* get a xprt clone for taskq thread, taskq func must free it */
971 arg
->rq_xprt
= svc_clone_init();
972 svc_clone_link(rqst
->rq_xprt
->xp_master
, arg
->rq_xprt
, rqst
->rq_xprt
);
973 arg
->rq_xprt
->xp_xid
= rqst
->rq_xprt
->xp_xid
;
976 * Increment the reference count on the rpcmod slot so that is not
977 * freed before the task has finished.
979 SVC_HOLD(arg
->rq_xprt
);
981 /* set the appropriate wrap/unwrap routine for RPCSEC_GSS */
982 arg
->rq_xprt
->xp_auth
.svc_ah_ops
= svc_rpc_gss_ops
;
983 arg
->rq_xprt
->xp_auth
.svc_ah_private
= (caddr_t
)client_data
;
985 /* get a dup of rpc msg for taskq thread */
986 arg
->msg
= rpc_msg_dup(msg
); /* taskq func must free msg dup */
988 arg
->client_data
= client_data
;
989 arg
->cr_version
= creds
.version
;
990 arg
->cr_service
= creds
.service
;
992 /* should be ok to hold clm lock as taskq will have new thread(s) */
993 ret
= ddi_taskq_dispatch(svcrpcsec_gss_init_taskq
,
994 svcrpcsec_gss_taskq_func
, arg
, DDI_SLEEP
);
995 if (ret
== DDI_FAILURE
) {
996 cmn_err(CE_NOTE
, "rpcsec_gss_init: taskq dispatch fail");
997 ret
= RPCSEC_GSS_FAILED
;
998 rpc_msg_free(&arg
->msg
, MAX_AUTH_BYTES
);
999 SVC_RELE(arg
->rq_xprt
, NULL
, FALSE
);
1000 svc_clone_unlink(arg
->rq_xprt
);
1001 svc_clone_free(arg
->rq_xprt
);
1002 kmem_free(arg
, sizeof (*arg
));
1006 mutex_exit(&client_data
->clm
);
1007 *no_dispatch
= TRUE
;
1011 ASSERT(client_data
->ref_cnt
> 0);
1012 client_data
->ref_cnt
--;
1013 mutex_exit(&client_data
->clm
);
1014 cmn_err(CE_NOTE
, "rpcsec_gss_init: error 0x%x", ret
);
1018 static enum auth_stat
1019 rpcsec_gss_continue_init(
1020 struct svc_req
*rqst
,
1021 struct rpc_msg
*msg
,
1022 rpc_gss_creds creds
,
1023 bool_t
*no_dispatch
)
1026 svc_rpc_gss_data
*client_data
;
1027 svc_rpc_gss_parms_t
*gss_parms
;
1028 rpc_gss_init_res
*retrans_result
;
1030 if (creds
.ctx_handle
.length
== 0) {
1031 RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1035 if ((client_data
= get_client(&creds
.ctx_handle
)) == NULL
) {
1036 ret
= RPCSEC_GSS_NOCRED
;
1037 RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1041 mutex_enter(&client_data
->clm
);
1042 if (client_data
->stale
) {
1043 ret
= RPCSEC_GSS_NOCRED
;
1044 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1049 * If context not established, go thru INIT code but with
1050 * this client handle.
1052 if (!client_data
->established
) {
1053 mutex_exit(&client_data
->clm
);
1054 return (rpcsec_gss_init(rqst
, msg
, creds
, no_dispatch
,
1059 * Set the appropriate wrap/unwrap routine for RPCSEC_GSS.
1061 rqst
->rq_xprt
->xp_auth
.svc_ah_ops
= svc_rpc_gss_ops
;
1062 rqst
->rq_xprt
->xp_auth
.svc_ah_private
= (caddr_t
)client_data
;
1065 * Keep copy of parameters we'll need for response, for the
1066 * sake of reentrancy (we don't want to look in the context
1067 * data because when we are sending a response, another
1068 * request may have come in).
1070 gss_parms
= &rqst
->rq_xprt
->xp_auth
.svc_gss_parms
;
1071 gss_parms
->established
= client_data
->established
;
1072 gss_parms
->service
= creds
.service
;
1073 gss_parms
->qop_rcvd
= (uint_t
)client_data
->qop
;
1074 gss_parms
->context
= (void *)client_data
->context
;
1075 gss_parms
->seq_num
= creds
.seq_num
;
1078 * This is an established context. Continue to
1079 * satisfy retried continue init requests out of
1080 * the retransmit cache. Throw away any that don't
1081 * have a matching xid or the cach is empty.
1082 * Delete the retransmit cache once the client sends
1085 if (client_data
->retrans_data
&&
1086 (client_data
->retrans_data
->xid
== msg
->rm_xid
)) {
1087 retrans_result
= &client_data
->retrans_data
->result
;
1088 if (set_response_verf(rqst
, msg
, client_data
,
1089 (uint_t
)retrans_result
->seq_window
)) {
1090 gss_parms
->established
= FALSE
;
1091 (void) svc_sendreply(rqst
->rq_xprt
,
1092 __xdr_rpc_gss_init_res
, (caddr_t
)retrans_result
);
1093 *no_dispatch
= TRUE
;
1094 ASSERT(client_data
->ref_cnt
> 0);
1095 client_data
->ref_cnt
--;
1098 mutex_exit(&client_data
->clm
);
1103 ASSERT(client_data
->ref_cnt
> 0);
1104 client_data
->ref_cnt
--;
1105 mutex_exit(&client_data
->clm
);
1109 static enum auth_stat
1111 struct svc_req
*rqst
,
1112 struct rpc_msg
*msg
,
1113 rpc_gss_creds creds
,
1114 bool_t
*no_dispatch
)
1117 svc_rpc_gss_parms_t
*gss_parms
;
1118 svc_rpc_gss_data
*client_data
;
1120 switch (creds
.service
) {
1121 case rpc_gss_svc_none
:
1122 case rpc_gss_svc_integrity
:
1123 case rpc_gss_svc_privacy
:
1126 cmn_err(CE_NOTE
, "__svcrpcsec_gss: unknown service type=0x%x",
1128 RPCGSS_LOG(1, "_svcrpcsec_gss: unknown service type: 0x%x\n",
1134 if (creds
.ctx_handle
.length
== 0) {
1135 RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1139 if ((client_data
= get_client(&creds
.ctx_handle
)) == NULL
) {
1140 ret
= RPCSEC_GSS_NOCRED
;
1141 RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1146 mutex_enter(&client_data
->clm
);
1147 if (!client_data
->established
) {
1151 if (client_data
->stale
) {
1152 ret
= RPCSEC_GSS_NOCRED
;
1153 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1158 * Once the context is established and there is no more
1159 * retransmission of last continue init request, it is safe
1160 * to delete the retransmit cache entry.
1162 if (client_data
->retrans_data
)
1163 retrans_del(client_data
);
1166 * Set the appropriate wrap/unwrap routine for RPCSEC_GSS.
1168 rqst
->rq_xprt
->xp_auth
.svc_ah_ops
= svc_rpc_gss_ops
;
1169 rqst
->rq_xprt
->xp_auth
.svc_ah_private
= (caddr_t
)client_data
;
1172 * Keep copy of parameters we'll need for response, for the
1173 * sake of reentrancy (we don't want to look in the context
1174 * data because when we are sending a response, another
1175 * request may have come in).
1177 gss_parms
= &rqst
->rq_xprt
->xp_auth
.svc_gss_parms
;
1178 gss_parms
->established
= client_data
->established
;
1179 gss_parms
->service
= creds
.service
;
1180 gss_parms
->qop_rcvd
= (uint_t
)client_data
->qop
;
1181 gss_parms
->context
= (void *)client_data
->context
;
1182 gss_parms
->seq_num
= creds
.seq_num
;
1185 * Context is already established. Check verifier, and
1186 * note parameters we will need for response in gss_parms.
1188 if (!check_verf(msg
, client_data
->context
,
1189 (int *)&gss_parms
->qop_rcvd
, client_data
->u_cred
.uid
)) {
1190 ret
= RPCSEC_GSS_NOCRED
;
1191 RPCGSS_LOG0(1, "_svcrpcsec_gss: check verf failed\n");
1196 * Check and invoke callback if necessary.
1198 if (!client_data
->done_docallback
) {
1199 client_data
->done_docallback
= TRUE
;
1200 client_data
->qop
= gss_parms
->qop_rcvd
;
1201 client_data
->raw_cred
.qop
= gss_parms
->qop_rcvd
;
1202 client_data
->raw_cred
.service
= creds
.service
;
1203 if (!do_callback(rqst
, client_data
)) {
1205 RPCGSS_LOG0(1, "_svc_rpcsec_gss:callback failed\n");
1211 * If the context was locked, make sure that the client
1212 * has not changed QOP.
1214 if (client_data
->locked
&& gss_parms
->qop_rcvd
!= client_data
->qop
) {
1216 RPCGSS_LOG0(1, "_svcrpcsec_gss: can not change qop\n");
1221 * Validate sequence number.
1223 if (!check_seq(client_data
, creds
.seq_num
, &client_data
->stale
)) {
1224 if (client_data
->stale
) {
1225 ret
= RPCSEC_GSS_FAILED
;
1227 "_svc_rpcsec_gss:check seq failed\n");
1229 RPCGSS_LOG0(4, "_svc_rpcsec_gss:check seq "
1230 "failed on good context. Ignoring "
1233 * Operational error, drop packet silently.
1234 * The client will recover after timing out,
1235 * assuming this is a client error and not
1236 * a relpay attack. Don't dispatch.
1239 *no_dispatch
= TRUE
;
1245 * set response verifier
1247 if (!set_response_verf(rqst
, msg
, client_data
, creds
.seq_num
)) {
1248 ret
= RPCSEC_GSS_FAILED
;
1249 client_data
->stale
= TRUE
;
1251 "_svc_rpcsec_gss:set response verifier failed\n");
1256 * If context is locked, make sure that the client
1257 * has not changed the security service.
1259 if (client_data
->locked
&&
1260 client_data
->raw_cred
.service
!= creds
.service
) {
1261 RPCGSS_LOG0(1, "_svc_rpcsec_gss: "
1262 "security service changed.\n");
1268 * Set client credentials to raw credential
1269 * structure in context. This is okay, since
1270 * this will not change during the lifetime of
1271 * the context (so it's MT safe).
1273 rqst
->rq_clntcred
= (char *)&client_data
->raw_cred
;
1275 mutex_exit(&client_data
->clm
);
1279 ASSERT(client_data
->ref_cnt
> 0);
1280 client_data
->ref_cnt
--;
1281 mutex_exit(&client_data
->clm
);
1286 * Note we don't have a client yet to use this routine and test it.
1288 static enum auth_stat
1290 struct svc_req
*rqst
,
1291 rpc_gss_creds creds
,
1292 bool_t
*no_dispatch
)
1294 svc_rpc_gss_data
*client_data
;
1297 if (creds
.ctx_handle
.length
== 0) {
1298 RPCGSS_LOG0(1, "_svcrpcsec_gss: no ctx_handle\n");
1302 if ((client_data
= get_client(&creds
.ctx_handle
)) == NULL
) {
1303 ret
= RPCSEC_GSS_NOCRED
;
1304 RPCGSS_LOG0(1, "_svcrpcsec_gss: no security context\n");
1308 mutex_enter(&client_data
->clm
);
1309 if (!client_data
->established
) {
1313 if (client_data
->stale
) {
1314 ret
= RPCSEC_GSS_NOCRED
;
1315 RPCGSS_LOG0(1, "_svcrpcsec_gss: client data stale\n");
1319 (void) svc_sendreply(rqst
->rq_xprt
, xdr_void
, NULL
);
1320 *no_dispatch
= TRUE
;
1321 ASSERT(client_data
->ref_cnt
> 0);
1322 client_data
->ref_cnt
--;
1323 client_data
->stale
= TRUE
;
1324 mutex_exit(&client_data
->clm
);
1328 ASSERT(client_data
->ref_cnt
> 0);
1329 client_data
->ref_cnt
--;
1330 client_data
->stale
= TRUE
;
1331 mutex_exit(&client_data
->clm
);
1336 * Server side authentication for RPCSEC_GSS.
1340 struct svc_req
*rqst
,
1341 struct rpc_msg
*msg
,
1342 bool_t
*no_dispatch
)
1345 rpc_gss_creds creds
;
1346 struct opaque_auth
*cred
;
1349 *no_dispatch
= FALSE
;
1352 * Initialize response verifier to NULL verifier. If
1353 * necessary, this will be changed later.
1355 rqst
->rq_xprt
->xp_verf
.oa_flavor
= AUTH_NONE
;
1356 rqst
->rq_xprt
->xp_verf
.oa_base
= NULL
;
1357 rqst
->rq_xprt
->xp_verf
.oa_length
= 0;
1360 * Pull out and check credential and verifier.
1362 cred
= &msg
->rm_call
.cb_cred
;
1364 if (cred
->oa_length
== 0) {
1365 RPCGSS_LOG0(1, "_svcrpcsec_gss: zero length cred\n");
1366 return (AUTH_BADCRED
);
1369 xdrmem_create(&xdrs
, cred
->oa_base
, cred
->oa_length
, XDR_DECODE
);
1370 bzero((char *)&creds
, sizeof (creds
));
1371 if (!__xdr_rpc_gss_creds(&xdrs
, &creds
)) {
1373 RPCGSS_LOG0(1, "_svcrpcsec_gss: can't decode creds\n");
1375 return (AUTH_BADCRED
);
1379 switch (creds
.gss_proc
) {
1380 case RPCSEC_GSS_INIT
:
1381 ret
= rpcsec_gss_init(rqst
, msg
, creds
, no_dispatch
, NULL
);
1383 case RPCSEC_GSS_CONTINUE_INIT
:
1384 ret
= rpcsec_gss_continue_init(rqst
, msg
, creds
, no_dispatch
);
1386 case RPCSEC_GSS_DATA
:
1387 ret
= rpcsec_gss_data(rqst
, msg
, creds
, no_dispatch
);
1389 case RPCSEC_GSS_DESTROY
:
1390 ret
= rpcsec_gss_destroy(rqst
, creds
, no_dispatch
);
1393 cmn_err(CE_NOTE
, "__svcrpcsec_gss: bad proc=%d",
1398 if (creds
.ctx_handle
.length
!= 0)
1399 xdr_free(__xdr_rpc_gss_creds
, (caddr_t
)&creds
);
1404 * Check verifier. The verifier is the checksum of the RPC header
1405 * upto and including the credentials field.
1410 check_verf(struct rpc_msg
*msg
, gss_ctx_id_t context
, int *qop_state
, uid_t uid
)
1414 struct opaque_auth
*oa
;
1416 gss_buffer_desc msg_buf
;
1417 gss_buffer_desc tok_buf
;
1418 OM_uint32 gssstat
, minor_stat
;
1421 * We have to reconstruct the RPC header from the previously
1422 * parsed information, since we haven't kept the header intact.
1425 oa
= &msg
->rm_call
.cb_cred
;
1426 if (oa
->oa_length
> MAX_AUTH_BYTES
)
1429 /* 8 XDR units from the IXDR macro calls. */
1430 if (sizeof (hdr
) < (8 * BYTES_PER_XDR_UNIT
+
1431 RNDUP(oa
->oa_length
)))
1434 IXDR_PUT_U_INT32(buf
, msg
->rm_xid
);
1435 IXDR_PUT_ENUM(buf
, msg
->rm_direction
);
1436 IXDR_PUT_U_INT32(buf
, msg
->rm_call
.cb_rpcvers
);
1437 IXDR_PUT_U_INT32(buf
, msg
->rm_call
.cb_prog
);
1438 IXDR_PUT_U_INT32(buf
, msg
->rm_call
.cb_vers
);
1439 IXDR_PUT_U_INT32(buf
, msg
->rm_call
.cb_proc
);
1440 IXDR_PUT_ENUM(buf
, oa
->oa_flavor
);
1441 IXDR_PUT_U_INT32(buf
, oa
->oa_length
);
1442 if (oa
->oa_length
) {
1443 len
= RNDUP(oa
->oa_length
);
1445 buf
+= len
/ sizeof (int);
1447 (void) bcopy(oa
->oa_base
, (caddr_t
)tmp
, oa
->oa_length
);
1449 len
= ((char *)buf
) - hdr
;
1450 msg_buf
.length
= len
;
1451 msg_buf
.value
= hdr
;
1452 oa
= &msg
->rm_call
.cb_verf
;
1453 tok_buf
.length
= oa
->oa_length
;
1454 tok_buf
.value
= oa
->oa_base
;
1456 gssstat
= kgss_verify(&minor_stat
, context
, &msg_buf
, &tok_buf
,
1458 if (gssstat
!= GSS_S_COMPLETE
) {
1459 RPCGSS_LOG(1, "check_verf: kgss_verify status 0x%x\n", gssstat
);
1461 RPCGSS_LOG(4, "check_verf: msg_buf length %d\n", len
);
1462 RPCGSS_LOG(4, "check_verf: msg_buf value 0x%x\n", *(int *)hdr
);
1463 RPCGSS_LOG(4, "check_verf: tok_buf length %ld\n",
1465 RPCGSS_LOG(4, "check_verf: tok_buf value 0x%p\n",
1466 (void *)oa
->oa_base
);
1467 RPCGSS_LOG(4, "check_verf: context 0x%p\n", (void *)context
);
1476 * Set response verifier. This is the checksum of the given number.
1477 * (e.g. sequence number or sequence window)
1480 set_response_verf(struct svc_req
*rqst
, struct rpc_msg
*msg
,
1481 svc_rpc_gss_data
*cl
, uint_t num
)
1484 gss_buffer_desc in_buf
, out_buf
;
1487 num_net
= (uint_t
)htonl(num
);
1488 in_buf
.length
= sizeof (num
);
1489 in_buf
.value
= (char *)&num_net
;
1492 if ((kgss_sign(&minor
, cl
->context
, cl
->qop
, &in_buf
, &out_buf
))
1496 rqst
->rq_xprt
->xp_verf
.oa_flavor
= RPCSEC_GSS
;
1497 rqst
->rq_xprt
->xp_verf
.oa_base
= msg
->rm_call
.cb_verf
.oa_base
;
1498 rqst
->rq_xprt
->xp_verf
.oa_length
= out_buf
.length
;
1499 bcopy(out_buf
.value
, rqst
->rq_xprt
->xp_verf
.oa_base
, out_buf
.length
);
1500 (void) gss_release_buffer(&minor
, &out_buf
);
1505 * Create client context.
1507 static svc_rpc_gss_data
*
1510 svc_rpc_gss_data
*client_data
;
1511 static uint_t key
= 1;
1513 client_data
= (svc_rpc_gss_data
*) kmem_cache_alloc(svc_data_handle
,
1515 if (client_data
== NULL
)
1519 * set up client data structure
1521 client_data
->next
= NULL
;
1522 client_data
->prev
= NULL
;
1523 client_data
->lru_next
= NULL
;
1524 client_data
->lru_prev
= NULL
;
1525 client_data
->client_name
.length
= 0;
1526 client_data
->client_name
.value
= NULL
;
1527 client_data
->seq_num
= 0;
1528 bzero(client_data
->seq_bits
, sizeof (client_data
->seq_bits
));
1529 client_data
->key
= 0;
1530 client_data
->cookie
= NULL
;
1531 bzero(&client_data
->u_cred
, sizeof (client_data
->u_cred
));
1532 client_data
->established
= FALSE
;
1533 client_data
->locked
= FALSE
;
1534 client_data
->u_cred_set
= 0;
1535 client_data
->context
= GSS_C_NO_CONTEXT
;
1536 client_data
->expiration
= GSS_C_INDEFINITE
;
1537 client_data
->deleg
= GSS_C_NO_CREDENTIAL
;
1538 client_data
->ref_cnt
= 1;
1539 client_data
->last_ref_time
= gethrestime_sec();
1540 client_data
->qop
= GSS_C_QOP_DEFAULT
;
1541 client_data
->done_docallback
= FALSE
;
1542 client_data
->stale
= FALSE
;
1543 client_data
->retrans_data
= NULL
;
1544 bzero(&client_data
->raw_cred
, sizeof (client_data
->raw_cred
));
1547 * The client context handle is a 32-bit key (unsigned int).
1548 * The key is incremented until there is no duplicate for it.
1551 svc_rpc_gss_cache_stats
.total_entries_allocated
++;
1552 mutex_enter(&ctx_mutex
);
1554 client_data
->key
= key
++;
1555 if (find_client(client_data
->key
) == NULL
) {
1556 insert_client(client_data
);
1557 mutex_exit(&ctx_mutex
);
1558 return (client_data
);
1565 * Insert client context into hash list and LRU list.
1568 insert_client(svc_rpc_gss_data
*client_data
)
1570 svc_rpc_gss_data
*cl
;
1571 int index
= HASH(client_data
->key
);
1573 ASSERT(mutex_owned(&ctx_mutex
));
1575 client_data
->prev
= NULL
;
1576 cl
= clients
[index
];
1577 if ((client_data
->next
= cl
) != NULL
)
1578 cl
->prev
= client_data
;
1579 clients
[index
] = client_data
;
1581 client_data
->lru_prev
= NULL
;
1582 if ((client_data
->lru_next
= lru_first
) != NULL
)
1583 lru_first
->lru_prev
= client_data
;
1585 lru_last
= client_data
;
1586 lru_first
= client_data
;
1592 * Fetch a client, given the client context handle. Move it to the
1593 * top of the LRU list since this is the most recently used context.
1595 static svc_rpc_gss_data
*
1596 get_client(gss_buffer_t ctx_handle
)
1598 uint_t key
= *(uint_t
*)ctx_handle
->value
;
1599 svc_rpc_gss_data
*cl
;
1601 mutex_enter(&ctx_mutex
);
1602 if ((cl
= find_client(key
)) != NULL
) {
1603 mutex_enter(&cl
->clm
);
1605 if (cl
->ref_cnt
== 0) {
1606 mutex_exit(&cl
->clm
);
1609 mutex_exit(&cl
->clm
);
1611 mutex_exit(&ctx_mutex
);
1615 cl
->last_ref_time
= gethrestime_sec();
1616 mutex_exit(&cl
->clm
);
1617 if (cl
!= lru_first
) {
1618 cl
->lru_prev
->lru_next
= cl
->lru_next
;
1619 if (cl
->lru_next
!= NULL
)
1620 cl
->lru_next
->lru_prev
= cl
->lru_prev
;
1622 lru_last
= cl
->lru_prev
;
1623 cl
->lru_prev
= NULL
;
1624 cl
->lru_next
= lru_first
;
1625 lru_first
->lru_prev
= cl
;
1629 mutex_exit(&ctx_mutex
);
1634 * Given the client context handle, find the context corresponding to it.
1635 * Don't change its LRU state since it may not be used.
1637 static svc_rpc_gss_data
*
1638 find_client(uint_t key
)
1640 int index
= HASH(key
);
1641 svc_rpc_gss_data
*cl
= NULL
;
1643 ASSERT(mutex_owned(&ctx_mutex
));
1645 for (cl
= clients
[index
]; cl
!= NULL
; cl
= cl
->next
) {
1653 * Destroy a client context.
1656 destroy_client(svc_rpc_gss_data
*client_data
)
1659 int index
= HASH(client_data
->key
);
1661 ASSERT(mutex_owned(&ctx_mutex
));
1664 * remove from hash list
1666 if (client_data
->prev
== NULL
)
1667 clients
[index
] = client_data
->next
;
1669 client_data
->prev
->next
= client_data
->next
;
1670 if (client_data
->next
!= NULL
)
1671 client_data
->next
->prev
= client_data
->prev
;
1674 * remove from LRU list
1676 if (client_data
->lru_prev
== NULL
)
1677 lru_first
= client_data
->lru_next
;
1679 client_data
->lru_prev
->lru_next
= client_data
->lru_next
;
1680 if (client_data
->lru_next
!= NULL
)
1681 client_data
->lru_next
->lru_prev
= client_data
->lru_prev
;
1683 lru_last
= client_data
->lru_prev
;
1686 * If there is a GSS context, clean up GSS state.
1688 if (client_data
->context
!= GSS_C_NO_CONTEXT
) {
1689 (void) kgss_delete_sec_context(&minor
, &client_data
->context
,
1692 common_client_data_free(client_data
);
1694 if (client_data
->deleg
!= GSS_C_NO_CREDENTIAL
) {
1695 (void) kgss_release_cred(&minor
, &client_data
->deleg
,
1700 if (client_data
->u_cred
.gidlist
!= NULL
) {
1701 kmem_free((char *)client_data
->u_cred
.gidlist
,
1702 client_data
->u_cred
.gidlen
* sizeof (gid_t
));
1703 client_data
->u_cred
.gidlist
= NULL
;
1705 if (client_data
->retrans_data
!= NULL
)
1706 retrans_del(client_data
);
1708 kmem_cache_free(svc_data_handle
, client_data
);
1713 * Check for expired and stale client contexts.
1716 sweep_clients(bool_t from_reclaim
)
1718 svc_rpc_gss_data
*cl
, *next
;
1719 time_t last_reference_needed
;
1720 time_t now
= gethrestime_sec();
1722 ASSERT(mutex_owned(&ctx_mutex
));
1724 last_reference_needed
= now
- (from_reclaim
?
1725 svc_rpc_gss_active_delta
: svc_rpc_gss_inactive_delta
);
1730 * We assume here that any manipulation of the LRU pointers
1731 * and hash bucket pointers are only done when holding the
1734 next
= cl
->lru_prev
;
1736 mutex_enter(&cl
->clm
);
1738 if ((cl
->expiration
!= GSS_C_INDEFINITE
&&
1739 cl
->expiration
<= now
) || cl
->stale
||
1740 cl
->last_ref_time
<= last_reference_needed
) {
1742 if ((cl
->expiration
!= GSS_C_INDEFINITE
&&
1743 cl
->expiration
<= now
) || cl
->stale
||
1744 (cl
->last_ref_time
<= last_reference_needed
&&
1745 cl
->ref_cnt
== 0)) {
1749 if (cl
->ref_cnt
== 0) {
1750 mutex_exit(&cl
->clm
);
1752 svc_rpc_gss_cache_stats
.
1753 no_returned_by_reclaim
++;
1756 mutex_exit(&cl
->clm
);
1758 mutex_exit(&cl
->clm
);
1760 mutex_exit(&cl
->clm
);
1765 last_swept
= gethrestime_sec();
1769 * Encrypt the serialized arguments from xdr_func applied to xdr_ptr
1770 * and write the result to xdrs.
1773 svc_rpc_gss_wrap(SVCAUTH
*auth
, XDR
*out_xdrs
, bool_t (*xdr_func
)(),
1776 svc_rpc_gss_parms_t
*gss_parms
= SVCAUTH_GSSPARMS(auth
);
1780 * If context is not established, or if neither integrity nor
1781 * privacy service is used, don't wrap - just XDR encode.
1782 * Otherwise, wrap data using service and QOP parameters.
1784 if (!gss_parms
->established
|| gss_parms
->service
== rpc_gss_svc_none
)
1785 return ((*xdr_func
)(out_xdrs
, xdr_ptr
));
1787 ret
= __rpc_gss_wrap_data(gss_parms
->service
,
1788 (OM_uint32
)gss_parms
->qop_rcvd
,
1789 (gss_ctx_id_t
)gss_parms
->context
,
1791 out_xdrs
, xdr_func
, xdr_ptr
);
1796 * Decrypt the serialized arguments and XDR decode them.
1799 svc_rpc_gss_unwrap(SVCAUTH
*auth
, XDR
*in_xdrs
, bool_t (*xdr_func
)(),
1802 svc_rpc_gss_parms_t
*gss_parms
= SVCAUTH_GSSPARMS(auth
);
1805 * If context is not established, or if neither integrity nor
1806 * privacy service is used, don't unwrap - just XDR decode.
1807 * Otherwise, unwrap data.
1809 if (!gss_parms
->established
|| gss_parms
->service
== rpc_gss_svc_none
)
1810 return ((*xdr_func
)(in_xdrs
, xdr_ptr
));
1812 return (__rpc_gss_unwrap_data(gss_parms
->service
,
1813 (gss_ctx_id_t
)gss_parms
->context
,
1815 gss_parms
->qop_rcvd
,
1816 in_xdrs
, xdr_func
, xdr_ptr
));
1822 rpc_gss_svc_max_data_length(struct svc_req
*req
, int max_tp_unit_len
)
1828 * Add retransmit entry to the context cache entry for a new xid.
1829 * If there is already an entry, delete it before adding the new one.
1831 static void retrans_add(client
, xid
, result
)
1832 svc_rpc_gss_data
*client
;
1834 rpc_gss_init_res
*result
;
1836 retrans_entry
*rdata
;
1838 if (client
->retrans_data
&& client
->retrans_data
->xid
== xid
)
1841 rdata
= kmem_zalloc(sizeof (*rdata
), KM_SLEEP
);
1847 rdata
->result
= *result
;
1849 if (result
->token
.length
!= 0) {
1850 GSS_DUP_BUFFER(rdata
->result
.token
, result
->token
);
1853 if (client
->retrans_data
)
1854 retrans_del(client
);
1856 client
->retrans_data
= rdata
;
1860 * Delete the retransmit data from the context cache entry.
1862 static void retrans_del(client
)
1863 svc_rpc_gss_data
*client
;
1865 retrans_entry
*rdata
;
1866 OM_uint32 minor_stat
;
1868 if (client
->retrans_data
== NULL
)
1871 rdata
= client
->retrans_data
;
1872 if (rdata
->result
.token
.length
!= 0) {
1873 (void) gss_release_buffer(&minor_stat
, &rdata
->result
.token
);
1876 kmem_free((caddr_t
)rdata
, sizeof (*rdata
));
1877 client
->retrans_data
= NULL
;
1881 * This function frees the following fields of svc_rpc_gss_data:
1882 * client_name, raw_cred.client_principal, raw_cred.mechanism.
1885 common_client_data_free(svc_rpc_gss_data
*client_data
)
1887 if (client_data
->client_name
.length
> 0) {
1888 (void) gss_release_buffer(NULL
, &client_data
->client_name
);
1891 if (client_data
->raw_cred
.client_principal
) {
1892 kmem_free((caddr_t
)client_data
->raw_cred
.client_principal
,
1893 client_data
->raw_cred
.client_principal
->len
+
1895 client_data
->raw_cred
.client_principal
= NULL
;
1899 * In the user GSS-API library, mechanism (mech_type returned
1900 * by gss_accept_sec_context) is static storage, however
1901 * since all the work is done for gss_accept_sec_context under
1902 * gssd, what is returned in the kernel, is a copy from the oid
1903 * obtained under from gssd, so need to free it when destroying
1907 if (client_data
->raw_cred
.mechanism
) {
1908 kgss_free_oid(client_data
->raw_cred
.mechanism
);
1909 client_data
->raw_cred
.mechanism
= NULL
;