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 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
30 * $Id: svc_auth_gssapi.c,v 1.19 1994/10/27 12:38:51 jik Exp $
34 * Server side handling of RPCSEC_GSS flavor.
42 #include <gssapi/gssapi.h>
43 #include <gssapi/gssapi_ext.h>
45 #include <rpc/rpcsec_defs.h>
53 * Sequence window definitions.
55 #define SEQ_ARR_SIZE 4
56 #define SEQ_WIN (SEQ_ARR_SIZE*32)
57 #define SEQ_HI_BIT 0x80000000
61 #define SEQ_MAX 0x80000000
64 /* cache retransmit data */
65 typedef struct _retrans_entry
{
67 rpc_gss_init_res result
;
68 struct _retrans_entry
*next
, *prev
;
72 * Server side RPCSEC_GSS context information.
74 typedef struct _svc_rpc_gss_data
{
75 struct _svc_rpc_gss_data
*next
, *prev
;
76 struct _svc_rpc_gss_data
*lru_next
, *lru_prev
;
79 gss_name_t client_name
;
80 gss_cred_id_t server_creds
;
83 uint_t seq_bits
[SEQ_ARR_SIZE
];
86 bool_t done_docallback
;
88 rpc_gss_rawcred_t raw_cred
;
89 rpc_gss_ucred_t u_cred
;
97 retrans_entry
*retrans_data
;
101 * Data structures used for LRU based context management.
106 static svc_rpc_gss_data
*clients
[HASHMOD
];
107 static svc_rpc_gss_data
*lru_first
, *lru_last
;
108 static int num_gss_contexts
= 0;
109 static int max_gss_contexts
= 128;
110 static int sweep_interval
= 10;
111 static int last_swept
= 0;
112 static uint_t max_lifetime
= GSS_C_INDEFINITE
;
113 static int init_lifetime
= 0;
114 static uint_t gid_timeout
= 43200; /* 43200 secs = 12 hours */
117 * lock used with context/lru variables
119 static mutex_t ctx_mutex
= DEFAULTMUTEX
;
122 * server credential management data and structures
124 typedef struct svc_creds_list_s
{
125 struct svc_creds_list_s
*next
;
133 mutex_t refresh_mutex
;
137 static svc_creds_list_t
*svc_creds_list
;
138 static int svc_creds_count
= 0;
141 * lock used with server credential variables list
143 * server cred list locking guidelines:
144 * - Writer's lock holder has exclusive access to the list
145 * - Reader's lock holder(s) must also lock (refresh_mutex) each node
146 * before accessing that node's elements (ie. cred)
148 static rwlock_t cred_lock
= DEFAULTRWLOCK
;
151 * server callback list
153 typedef struct cblist_s
{
154 struct cblist_s
*next
;
155 rpc_gss_callback_t cb
;
158 cblist_t
*cblist
= NULL
;
161 * lock used with callback variables
163 static mutex_t cb_mutex
= DEFAULTMUTEX
;
166 * forward declarations
168 static bool_t
svc_rpc_gss_wrap();
169 static bool_t
svc_rpc_gss_unwrap();
170 static svc_rpc_gss_data
*create_client();
171 static svc_rpc_gss_data
*get_client();
172 static svc_rpc_gss_data
*find_client();
173 static void destroy_client();
174 static void sweep_clients();
175 static void drop_lru_client();
176 static void insert_client();
177 static bool_t
check_verf();
178 static bool_t
rpc_gss_refresh_svc_cred();
179 static bool_t
set_response_verf();
180 static void retrans_add(svc_rpc_gss_data
*, uint32_t,
182 static void retrans_del(struct _svc_rpc_gss_data
*);
186 * server side wrap/unwrap routines
188 struct svc_auth_ops svc_rpc_gss_ops
= {
194 * Fetch server side authentication structure.
196 extern SVCAUTH
*__svc_get_svcauth();
199 * Cleanup routine for destroying context, called after service
200 * procedure is executed, for MT safeness.
202 extern void *__svc_set_proc_cleanup_cb();
203 static void (*old_cleanup_cb
)() = NULL
;
204 static bool_t cleanup_cb_set
= FALSE
;
207 ctx_cleanup(SVCXPRT
*xprt
)
209 svc_rpc_gss_data
*cl
;
212 if (old_cleanup_cb
!= NULL
)
213 (*old_cleanup_cb
)(xprt
);
216 * First check if current context needs to be cleaned up.
218 svcauth
= __svc_get_svcauth(xprt
);
220 if ((cl
= (svc_rpc_gss_data
*)svcauth
->svc_ah_private
) != NULL
) {
221 mutex_lock(&cl
->clm
);
222 if (--cl
->ref_cnt
== 0 && cl
->stale
) {
223 mutex_unlock(&cl
->clm
);
224 mutex_lock(&ctx_mutex
);
226 mutex_unlock(&ctx_mutex
);
228 mutex_unlock(&cl
->clm
);
232 * Check for other expired contexts.
234 if ((time(0) - last_swept
) > sweep_interval
) {
235 mutex_lock(&ctx_mutex
);
237 * Check again, in case some other thread got in.
239 if ((time(0) - last_swept
) > sweep_interval
)
241 mutex_unlock(&ctx_mutex
);
246 * Set server parameters.
249 __rpc_gss_set_server_parms(int init_cred_lifetime
, int max_cred_lifetime
,
253 * Ignore parameters unless greater than zero.
255 mutex_lock(&ctx_mutex
);
257 max_gss_contexts
= cache_size
;
258 if (max_cred_lifetime
> 0)
259 max_lifetime
= (uint_t
)max_cred_lifetime
;
260 if (init_cred_lifetime
> 0)
261 init_lifetime
= init_cred_lifetime
;
262 mutex_unlock(&ctx_mutex
);
266 * Shift the array arr of length arrlen right by nbits bits.
269 shift_bits(uint_t
*arr
, int arrlen
, int nbits
)
275 * If the number of bits to be shifted exceeds SEQ_WIN, just
276 * zero out the array.
278 if (nbits
< SEQ_WIN
) {
279 for (i
= 0; i
< nbits
; i
++) {
281 for (j
= 0; j
< arrlen
; j
++) {
282 lo
= arr
[j
] & SEQ_LO_BIT
;
285 arr
[j
] |= SEQ_HI_BIT
;
290 for (j
= 0; j
< arrlen
; j
++)
296 * Check that the received sequence number seq_num is valid.
299 check_seq(svc_rpc_gss_data
*cl
, uint_t seq_num
, bool_t
*kill_context
)
305 * If it exceeds the maximum, kill context.
307 if (seq_num
>= SEQ_MAX
) {
308 *kill_context
= TRUE
;
313 * If greater than the last seen sequence number, just shift
314 * the sequence window so that it starts at the new sequence
315 * number and extends downwards by SEQ_WIN.
317 if (seq_num
> cl
->seq_num
) {
318 shift_bits(cl
->seq_bits
, SEQ_ARR_SIZE
, seq_num
- cl
->seq_num
);
319 cl
->seq_bits
[0] |= SEQ_HI_BIT
;
320 cl
->seq_num
= seq_num
;
325 * If it is outside the sequence window, return failure.
327 i
= cl
->seq_num
- seq_num
;
332 * If within sequence window, set the bit corresponding to it
333 * if not already seen; if already seen, return failure.
335 j
= SEQ_MASK
- (i
& SEQ_MASK
);
336 bit
= j
> 0 ? (1 << j
) : 1;
338 if (cl
->seq_bits
[i
] & bit
)
340 cl
->seq_bits
[i
] |= bit
;
345 * Convert a name in gss exported type to rpc_gss_principal_t type.
348 __rpc_gss_make_principal(rpc_gss_principal_t
*principal
, gss_buffer_desc
*name
)
353 plen
= RNDUP(name
->length
) + sizeof (int);
354 (*principal
) = (rpc_gss_principal_t
)malloc(plen
);
355 if ((*principal
) == NULL
)
357 bzero((caddr_t
)(*principal
), plen
);
358 (*principal
)->len
= RNDUP(name
->length
);
359 s
= (*principal
)->name
;
360 memcpy(s
, name
->value
, name
->length
);
365 * Convert a name in internal form to the exported type.
368 set_client_principal(gss_name_t g_name
, rpc_gss_principal_t
*r_name
)
370 gss_buffer_desc name
;
371 OM_uint32 major
, minor
;
374 major
= gss_export_name(&minor
, g_name
, &name
);
375 if (major
!= GSS_S_COMPLETE
)
377 ret
= __rpc_gss_make_principal(r_name
, &name
);
378 (void) gss_release_buffer(&minor
, &name
);
383 * Set server callback.
386 __rpc_gss_set_callback(rpc_gss_callback_t
*cb
)
390 if (cb
->callback
== NULL
)
392 if ((cbl
= (cblist_t
*)malloc(sizeof (*cbl
))) == NULL
)
395 mutex_lock(&cb_mutex
);
398 mutex_unlock(&cb_mutex
);
403 * Locate callback (if specified) and call server. Release any
404 * delegated credentials unless passed to server and the server
405 * accepts the context. If a callback is not specified, accept
406 * the incoming context.
409 do_callback(struct svc_req
*req
, svc_rpc_gss_data
*client_data
)
412 bool_t ret
= TRUE
, found
= FALSE
;
416 mutex_lock(&cb_mutex
);
417 for (cbl
= cblist
; cbl
!= NULL
; cbl
= cbl
->next
) {
418 if (req
->rq_prog
!= cbl
->cb
.program
||
419 req
->rq_vers
!= cbl
->cb
.version
)
423 lock
.raw_cred
= &client_data
->raw_cred
;
424 ret
= (*cbl
->cb
.callback
)(req
, client_data
->deleg
,
425 client_data
->context
, &lock
, &client_data
->cookie
);
427 client_data
->locked
= lock
.locked
;
428 client_data
->deleg
= GSS_C_NO_CREDENTIAL
;
433 if (client_data
->deleg
!= GSS_C_NO_CREDENTIAL
) {
434 (void) gss_release_cred(&minor
, &client_data
->deleg
);
435 client_data
->deleg
= GSS_C_NO_CREDENTIAL
;
438 mutex_unlock(&cb_mutex
);
443 * Return caller credentials.
446 __rpc_gss_getcred(struct svc_req
*req
, rpc_gss_rawcred_t
**rcred
,
447 rpc_gss_ucred_t
**ucred
, void **cookie
)
450 svc_rpc_gss_data
*client_data
;
451 svc_rpc_gss_parms_t
*gss_parms
;
457 svcauth
= __svc_get_svcauth(req
->rq_xprt
);
459 client_data
= (svc_rpc_gss_data
*)svcauth
->svc_ah_private
;
460 gss_parms
= &svcauth
->svc_gss_parms
;
462 mutex_lock(&client_data
->clm
);
465 svcauth
->raw_cred
= client_data
->raw_cred
;
466 svcauth
->raw_cred
.service
= gss_parms
->service
;
467 svcauth
->raw_cred
.qop
= __rpc_gss_num_to_qop(
468 svcauth
->raw_cred
.mechanism
, gss_parms
->qop_rcvd
);
469 *rcred
= &svcauth
->raw_cred
;
472 if (!client_data
->u_cred_set
) {
474 * Double check making sure ucred is not set
475 * after acquiring the lock.
477 if (!client_data
->u_cred_set
) {
478 if (!__rpc_gss_mech_to_oid(
479 (*rcred
)->mechanism
, &oid
)) {
480 fprintf(stderr
, dgettext(TEXT_DOMAIN
,
481 "mech_to_oid failed in "
485 status
= gsscred_name_to_unix_cred(
486 client_data
->client_name
, oid
,
487 &client_data
->u_cred
.uid
,
488 &client_data
->u_cred
.gid
,
489 &client_data
->u_cred
.gidlist
,
491 if (status
== GSS_S_COMPLETE
) {
492 client_data
->u_cred_set
= TRUE
;
493 client_data
->u_cred
.gidlen
=
495 gettimeofday(&now
, NULL
);
496 client_data
->time_secs_set
=
498 *ucred
= &client_data
->u_cred
;
506 * check if they have expired.
508 gettimeofday(&now
, NULL
);
509 if ((now
.tv_sec
- client_data
->time_secs_set
)
512 status
= gss_get_group_info(
513 client_data
->u_cred
.uid
,
514 &client_data
->u_cred
.gid
,
515 &client_data
->u_cred
.gidlist
,
517 if (status
== GSS_S_COMPLETE
) {
518 client_data
->u_cred
.gidlen
=
520 gettimeofday(&now
, NULL
);
521 client_data
->time_secs_set
= now
.tv_sec
;
522 *ucred
= &client_data
->u_cred
;
524 client_data
->u_cred_set
= FALSE
;
529 *ucred
= &client_data
->u_cred
;
533 *cookie
= client_data
->cookie
;
535 mutex_unlock(&client_data
->clm
);
541 * Server side authentication for RPCSEC_GSS.
545 __svcrpcsec_gss(struct svc_req
*rqst
, struct rpc_msg
*msg
, bool_t
*no_dispatch
)
549 rpc_gss_init_arg call_arg
;
550 rpc_gss_init_res call_res
, *retrans_result
;
551 gss_buffer_desc output_token
;
552 OM_uint32 gssstat
, minor_stat
, time_rec
, ret_flags
;
553 struct opaque_auth
*cred
;
554 svc_rpc_gss_data
*client_data
;
556 svc_creds_list_t
*sc
;
558 svc_rpc_gss_parms_t
*gss_parms
;
559 gss_OID mech_type
= GSS_C_NULL_OID
;
562 * Initialize response verifier to NULL verifier. If
563 * necessary, this will be changed later.
565 rqst
->rq_xprt
->xp_verf
.oa_flavor
= AUTH_NONE
;
566 rqst
->rq_xprt
->xp_verf
.oa_base
= NULL
;
567 rqst
->rq_xprt
->xp_verf
.oa_length
= 0;
569 * Need to null out results to start with.
571 memset((char *)&call_res
, 0, sizeof (call_res
));
574 * Pull out and check credential and verifier.
576 cred
= &msg
->rm_call
.cb_cred
;
577 if (cred
->oa_length
== 0) {
578 return (AUTH_BADCRED
);
581 xdrmem_create(&xdrs
, cred
->oa_base
, cred
->oa_length
, XDR_DECODE
);
583 memset((char *)&creds
, 0, sizeof (creds
));
584 if (!__xdr_rpc_gss_creds(&xdrs
, &creds
)) {
592 * If this is a control message and proc is GSSAPI_INIT, then
593 * create a client handle for this client. Otherwise, look up
594 * the existing handle.
596 if (creds
.gss_proc
== RPCSEC_GSS_INIT
) {
597 if (creds
.ctx_handle
.length
!= 0) {
601 if ((client_data
= create_client()) == NULL
) {
607 * Only verify values for service parameter when proc
608 * not RPCSEC_GSS_INIT or RPCSEC_GSS_CONTINUE_INIT.
609 * RFC2203 says contents for sequence and service args
610 * are undefined for creation procs.
612 * Note: only need to check for *CONTINUE_INIT here because
613 * if() clause already checked for RPCSEC_GSS_INIT
615 if (creds
.gss_proc
!= RPCSEC_GSS_CONTINUE_INIT
) {
616 switch (creds
.service
) {
617 case rpc_gss_svc_none
:
618 case rpc_gss_svc_integrity
:
619 case rpc_gss_svc_privacy
:
626 if (creds
.ctx_handle
.length
== 0) {
630 if ((client_data
= get_client(&creds
.ctx_handle
)) == NULL
) {
631 ret
= RPCSEC_GSS_NOCRED
;
637 * lock the client data until it's safe; if it's already stale,
638 * no more processing is possible
640 mutex_lock(&client_data
->clm
);
641 if (client_data
->stale
) {
642 ret
= RPCSEC_GSS_NOCRED
;
647 * Any response we send will use ctx_handle, so set it now;
648 * also set seq_window since this won't change.
650 call_res
.ctx_handle
.length
= sizeof (client_data
->key
);
651 call_res
.ctx_handle
.value
= (char *)&client_data
->key
;
652 call_res
.seq_window
= SEQ_WIN
;
655 * Set the appropriate wrap/unwrap routine for RPCSEC_GSS.
657 svcauth
= __svc_get_svcauth(rqst
->rq_xprt
);
658 svcauth
->svc_ah_ops
= svc_rpc_gss_ops
;
659 svcauth
->svc_ah_private
= (caddr_t
)client_data
;
662 * Keep copy of parameters we'll need for response, for the
663 * sake of reentrancy (we don't want to look in the context
664 * data because when we are sending a response, another
665 * request may have come in.
667 gss_parms
= &svcauth
->svc_gss_parms
;
668 gss_parms
->established
= client_data
->established
;
669 gss_parms
->service
= creds
.service
;
670 gss_parms
->qop_rcvd
= (uint_t
)client_data
->qop
;
671 gss_parms
->context
= (void *)client_data
->context
;
672 gss_parms
->seq_num
= creds
.seq_num
;
674 if (!client_data
->established
) {
675 if (creds
.gss_proc
== RPCSEC_GSS_DATA
) {
676 ret
= RPCSEC_GSS_FAILED
;
677 client_data
->stale
= TRUE
;
682 * If the context is not established, then only GSSAPI_INIT
683 * and _CONTINUE requests are valid.
685 if (creds
.gss_proc
!= RPCSEC_GSS_INIT
&& creds
.gss_proc
!=
686 RPCSEC_GSS_CONTINUE_INIT
) {
687 ret
= RPCSEC_GSS_FAILED
;
688 client_data
->stale
= TRUE
;
693 * call is for us, deserialize arguments
695 memset(&call_arg
, 0, sizeof (call_arg
));
696 if (!svc_getargs(rqst
->rq_xprt
, __xdr_rpc_gss_init_arg
,
697 (caddr_t
)&call_arg
)) {
698 ret
= RPCSEC_GSS_FAILED
;
699 client_data
->stale
= TRUE
;
703 gssstat
= GSS_S_FAILURE
;
705 rw_rdlock(&cred_lock
);
707 * set next sc to point to the server cred
708 * if the client_data contains server_creds
710 for (sc
= svc_creds_list
; sc
!= NULL
; sc
= sc
->next
) {
711 if (rqst
->rq_prog
!= sc
->program
||
712 rqst
->rq_vers
!= sc
->version
)
715 mutex_lock(&sc
->refresh_mutex
);
716 gssstat
= gss_accept_sec_context(&minor_stat
,
717 &client_data
->context
,
720 GSS_C_NO_CHANNEL_BINDINGS
,
721 &client_data
->client_name
,
728 if (gssstat
== GSS_S_CREDENTIALS_EXPIRED
) {
729 if (rpc_gss_refresh_svc_cred(sc
)) {
730 gssstat
= gss_accept_sec_context(
732 &client_data
->context
,
735 GSS_C_NO_CHANNEL_BINDINGS
,
736 &client_data
->client_name
,
742 mutex_unlock(&sc
->refresh_mutex
);
745 mutex_unlock(&sc
->refresh_mutex
);
746 gssstat
= GSS_S_NO_CRED
;
751 mutex_unlock(&sc
->refresh_mutex
);
753 if (gssstat
== GSS_S_COMPLETE
) {
755 * Server_creds was right - set it. Also
756 * set the raw and unix credentials at this
757 * point. This saves a lot of computation
758 * later when credentials are retrieved.
761 * XXX server_creds will prob be stale
762 * after rpc_gss_refresh_svc_cred(), but
763 * it appears not to ever be referenced
766 mutex_lock(&sc
->refresh_mutex
);
767 client_data
->server_creds
= sc
->cred
;
768 client_data
->raw_cred
.version
= creds
.version
;
769 client_data
->raw_cred
.service
= creds
.service
;
770 client_data
->raw_cred
.svc_principal
=
772 mutex_unlock(&sc
->refresh_mutex
);
774 if ((client_data
->raw_cred
.mechanism
775 = __rpc_gss_oid_to_mech(mech_type
))
777 gssstat
= GSS_S_FAILURE
;
778 (void) gss_release_buffer(&minor_stat
,
780 } else if (!set_client_principal(client_data
->
781 client_name
, &client_data
->
782 raw_cred
.client_principal
)) {
783 gssstat
= GSS_S_FAILURE
;
784 (void) gss_release_buffer(&minor_stat
,
790 if (gssstat
== GSS_S_CONTINUE_NEEDED
) {
792 * XXX server_creds will prob be stale
793 * after rpc_gss_refresh_svc_cred(), but
794 * it appears not to ever be referenced
797 mutex_lock(&sc
->refresh_mutex
);
798 client_data
->server_creds
= sc
->cred
;
799 mutex_unlock(&sc
->refresh_mutex
);
804 rw_unlock(&cred_lock
);
806 call_res
.gss_major
= gssstat
;
807 call_res
.gss_minor
= minor_stat
;
809 xdr_free(__xdr_rpc_gss_init_arg
, (caddr_t
)&call_arg
);
811 if (gssstat
!= GSS_S_COMPLETE
&&
812 gssstat
!= GSS_S_CONTINUE_NEEDED
) {
814 * We have a failure - send response and delete
815 * the context. Don't dispatch. Set ctx_handle
816 * to NULL and seq_window to 0.
818 call_res
.ctx_handle
.length
= 0;
819 call_res
.ctx_handle
.value
= NULL
;
820 call_res
.seq_window
= 0;
822 svc_sendreply(rqst
->rq_xprt
, __xdr_rpc_gss_init_res
,
826 client_data
->stale
= TRUE
;
831 * This step succeeded. Send a response, along with
832 * a token if there's one. Don't dispatch.
834 if (output_token
.length
!= 0) {
835 GSS_COPY_BUFFER(call_res
.token
, output_token
);
839 * set response verifier: checksum of SEQ_WIN
841 if (gssstat
== GSS_S_COMPLETE
) {
842 if (!set_response_verf(rqst
, msg
, client_data
,
844 ret
= RPCSEC_GSS_FAILED
;
845 client_data
->stale
= TRUE
;
846 (void) gss_release_buffer(&minor_stat
,
852 svc_sendreply(rqst
->rq_xprt
, __xdr_rpc_gss_init_res
,
855 * Cache last response in case it is lost and the client
856 * retries on an established context.
858 (void) retrans_add(client_data
, msg
->rm_xid
, &call_res
);
860 (void) gss_release_buffer(&minor_stat
, &output_token
);
863 * If appropriate, set established to TRUE *after* sending
864 * response (otherwise, the client will receive the final
867 if (gssstat
== GSS_S_COMPLETE
) {
869 * Context is established. Set expiry time for
870 * context (the minimum of time_rec and max_lifetime).
872 client_data
->seq_num
= 1;
873 if (time_rec
== GSS_C_INDEFINITE
) {
874 if (max_lifetime
!= GSS_C_INDEFINITE
) {
875 client_data
->expiration
=
876 max_lifetime
+ time(0);
878 client_data
->expiration
=
881 } else if (max_lifetime
== GSS_C_INDEFINITE
||
882 max_lifetime
> time_rec
) {
883 client_data
->expiration
= time_rec
+ time(0);
885 client_data
->expiration
= max_lifetime
+
888 client_data
->established
= TRUE
;
892 if ((creds
.gss_proc
!= RPCSEC_GSS_DATA
) &&
893 (creds
.gss_proc
!= RPCSEC_GSS_DESTROY
)) {
895 switch (creds
.gss_proc
) {
897 case RPCSEC_GSS_CONTINUE_INIT
:
899 * This is an established context. Continue to
900 * satisfy retried continue init requests out of
901 * the retransmit cache. Throw away any that
902 * don't have a matching xid or the cach is
903 * empty. Delete the retransmit cache once the
904 * client sends a data request.
906 if (client_data
->retrans_data
&&
907 (client_data
->retrans_data
->xid
==
911 &client_data
->retrans_data
->result
;
912 if (set_response_verf(rqst
, msg
,
913 client_data
, (uint_t
)
914 retrans_result
->seq_window
)) {
916 gss_parms
->established
= FALSE
;
917 svc_sendreply(rqst
->rq_xprt
,
918 __xdr_rpc_gss_init_res
,
919 (caddr_t
)retrans_result
);
927 syslog(LOG_ERR
, "_svcrpcsec_gss: non-data "
928 "request on an established context");
935 * Once the context is established and there is no more
936 * retransmission of last continue init request, it is safe
937 * to delete the retransmit cache entry.
939 if (client_data
->retrans_data
)
940 retrans_del(client_data
);
943 * Context is already established. Check verifier, and
944 * note parameters we will need for response in gss_parms.
946 if (!check_verf(msg
, client_data
->context
,
947 &gss_parms
->qop_rcvd
)) {
948 ret
= RPCSEC_GSS_NOCRED
;
952 * Check and invoke callback if necessary.
954 if (!client_data
->done_docallback
) {
955 client_data
->done_docallback
= TRUE
;
956 client_data
->qop
= gss_parms
->qop_rcvd
;
957 client_data
->raw_cred
.qop
= __rpc_gss_num_to_qop(
958 client_data
->raw_cred
.mechanism
,
959 gss_parms
->qop_rcvd
);
960 client_data
->raw_cred
.service
= creds
.service
;
961 if (!do_callback(rqst
, client_data
)) {
963 client_data
->stale
= TRUE
;
969 * If the context was locked, make sure that the client
970 * has not changed QOP.
972 if (client_data
->locked
&&
973 gss_parms
->qop_rcvd
!= client_data
->qop
) {
979 * Validate sequence number.
981 if (!check_seq(client_data
, creds
.seq_num
,
982 &client_data
->stale
)) {
983 if (client_data
->stale
)
984 ret
= RPCSEC_GSS_FAILED
;
987 * Operational error, drop packet silently.
988 * The client will recover after timing out,
989 * assuming this is a client error and not
990 * a relpay attack. Don't dispatch.
999 * set response verifier
1001 if (!set_response_verf(rqst
, msg
, client_data
, creds
.seq_num
)) {
1002 ret
= RPCSEC_GSS_FAILED
;
1003 client_data
->stale
= TRUE
;
1008 * If this is a control message RPCSEC_GSS_DESTROY, process
1009 * the call; otherwise, return AUTH_OK so it will be
1010 * dispatched to the application server.
1012 if (creds
.gss_proc
== RPCSEC_GSS_DESTROY
) {
1013 svc_sendreply(rqst
->rq_xprt
, xdr_void
, NULL
);
1014 *no_dispatch
= TRUE
;
1015 client_data
->stale
= TRUE
;
1019 * This should be an RPCSEC_GSS_DATA request.
1020 * If context is locked, make sure that the client
1021 * has not changed the security service.
1023 if (client_data
->locked
&&
1024 client_data
->raw_cred
.service
!= creds
.service
) {
1030 * Set client credentials to raw credential
1031 * structure in context. This is okay, since
1032 * this will not change during the lifetime of
1033 * the context (so it's MT safe).
1035 rqst
->rq_clntcred
= (char *)&client_data
->raw_cred
;
1043 if (creds
.ctx_handle
.length
!= 0)
1044 xdr_free(__xdr_rpc_gss_creds
, (caddr_t
)&creds
);
1045 mutex_unlock(&client_data
->clm
);
1048 mutex_unlock(&client_data
->clm
);
1053 if (creds
.ctx_handle
.length
!= 0)
1054 xdr_free(__xdr_rpc_gss_creds
, (caddr_t
)&creds
);
1059 * Check verifier. The verifier is the checksum of the RPC header
1060 * upto and including the credentials field.
1063 check_verf(struct rpc_msg
*msg
, gss_ctx_id_t context
, int *qop_state
)
1067 struct opaque_auth
*oa
;
1069 gss_buffer_desc msg_buf
;
1070 gss_buffer_desc tok_buf
;
1071 OM_uint32 gssstat
, minor_stat
;
1074 * We have to reconstruct the RPC header from the previously
1075 * parsed information, since we haven't kept the header intact.
1078 oa
= &msg
->rm_call
.cb_cred
;
1079 if (oa
->oa_length
> MAX_AUTH_BYTES
)
1082 /* 8 XDR units from the IXDR macro calls. */
1083 if (sizeof (hdr
) < (8 * BYTES_PER_XDR_UNIT
+ RNDUP(oa
->oa_length
)))
1087 IXDR_PUT_U_INT32(buf
, msg
->rm_xid
);
1088 IXDR_PUT_ENUM(buf
, msg
->rm_direction
);
1089 IXDR_PUT_U_INT32(buf
, msg
->rm_call
.cb_rpcvers
);
1090 IXDR_PUT_U_INT32(buf
, msg
->rm_call
.cb_prog
);
1091 IXDR_PUT_U_INT32(buf
, msg
->rm_call
.cb_vers
);
1092 IXDR_PUT_U_INT32(buf
, msg
->rm_call
.cb_proc
);
1093 IXDR_PUT_ENUM(buf
, oa
->oa_flavor
);
1094 IXDR_PUT_U_INT32(buf
, oa
->oa_length
);
1095 if (oa
->oa_length
) {
1096 len
= RNDUP(oa
->oa_length
);
1098 buf
+= len
/ sizeof (int);
1100 (void) memcpy((caddr_t
)tmp
, oa
->oa_base
, oa
->oa_length
);
1102 len
= ((char *)buf
) - (char *)hdr
;
1103 msg_buf
.length
= len
;
1104 msg_buf
.value
= (char *)hdr
;
1105 oa
= &msg
->rm_call
.cb_verf
;
1106 tok_buf
.length
= oa
->oa_length
;
1107 tok_buf
.value
= oa
->oa_base
;
1109 gssstat
= gss_verify(&minor_stat
, context
, &msg_buf
, &tok_buf
,
1111 if (gssstat
!= GSS_S_COMPLETE
)
1117 * Set response verifier. This is the checksum of the given number.
1118 * (e.g. sequence number or sequence window)
1121 set_response_verf(struct svc_req
*rqst
, struct rpc_msg
*msg
,
1122 svc_rpc_gss_data
*cl
, uint_t num
)
1125 gss_buffer_desc in_buf
, out_buf
;
1128 num_net
= (uint_t
)htonl(num
);
1129 in_buf
.length
= sizeof (num
);
1130 in_buf
.value
= (char *)&num_net
;
1131 if (gss_sign(&minor
, cl
->context
, cl
->qop
, &in_buf
,
1132 &out_buf
) != GSS_S_COMPLETE
)
1134 rqst
->rq_xprt
->xp_verf
.oa_flavor
= RPCSEC_GSS
;
1135 rqst
->rq_xprt
->xp_verf
.oa_base
= msg
->rm_call
.cb_verf
.oa_base
;
1136 rqst
->rq_xprt
->xp_verf
.oa_length
= out_buf
.length
;
1137 memcpy(rqst
->rq_xprt
->xp_verf
.oa_base
, out_buf
.value
,
1139 (void) gss_release_buffer(&minor
, &out_buf
);
1144 * Create client context.
1146 static svc_rpc_gss_data
*
1149 svc_rpc_gss_data
*client_data
;
1150 static uint_t key
= 1;
1152 client_data
= (svc_rpc_gss_data
*) malloc(sizeof (*client_data
));
1153 if (client_data
== NULL
)
1155 memset((char *)client_data
, 0, sizeof (*client_data
));
1158 * set up client data structure
1160 client_data
->established
= FALSE
;
1161 client_data
->locked
= FALSE
;
1162 client_data
->u_cred_set
= FALSE
;
1163 client_data
->context
= GSS_C_NO_CONTEXT
;
1164 client_data
->expiration
= init_lifetime
+ time(0);
1165 client_data
->ref_cnt
= 1;
1166 client_data
->qop
= GSS_C_QOP_DEFAULT
;
1167 client_data
->done_docallback
= FALSE
;
1168 client_data
->stale
= FALSE
;
1169 client_data
->time_secs_set
= 0;
1170 client_data
->retrans_data
= NULL
;
1171 mutex_init(&client_data
->clm
, USYNC_THREAD
, NULL
);
1173 * Check totals. If we've hit the limit, we destroy a context
1174 * based on LRU method.
1176 mutex_lock(&ctx_mutex
);
1177 if (num_gss_contexts
>= max_gss_contexts
) {
1179 * now try on LRU basis
1182 if (num_gss_contexts
>= max_gss_contexts
) {
1183 mutex_unlock(&ctx_mutex
);
1184 free((char *)client_data
);
1190 * The client context handle is a 32-bit key (unsigned int).
1191 * The key is incremented until there is no duplicate for it.
1194 client_data
->key
= key
++;
1195 if (find_client(client_data
->key
) == NULL
) {
1196 insert_client(client_data
);
1198 * Set cleanup callback if we haven't.
1200 if (!cleanup_cb_set
) {
1202 (void (*)()) __svc_set_proc_cleanup_cb(
1203 (void *)ctx_cleanup
);
1204 cleanup_cb_set
= TRUE
;
1206 mutex_unlock(&ctx_mutex
);
1207 return (client_data
);
1214 * Insert client context into hash list and LRU list.
1217 insert_client(svc_rpc_gss_data
*client_data
)
1219 svc_rpc_gss_data
*cl
;
1220 int index
= (client_data
->key
& HASHMASK
);
1222 client_data
->prev
= NULL
;
1223 cl
= clients
[index
];
1224 if ((client_data
->next
= cl
) != NULL
)
1225 cl
->prev
= client_data
;
1226 clients
[index
] = client_data
;
1228 client_data
->lru_prev
= NULL
;
1229 if ((client_data
->lru_next
= lru_first
) != NULL
)
1230 lru_first
->lru_prev
= client_data
;
1232 lru_last
= client_data
;
1233 lru_first
= client_data
;
1239 * Fetch a client, given the client context handle. Move it to the
1240 * top of the LRU list since this is the most recently used context.
1242 static svc_rpc_gss_data
*
1243 get_client(gss_buffer_t ctx_handle
)
1245 uint_t key
= *(uint_t
*)ctx_handle
->value
;
1246 svc_rpc_gss_data
*cl
;
1248 mutex_lock(&ctx_mutex
);
1249 if ((cl
= find_client(key
)) != NULL
) {
1250 mutex_lock(&cl
->clm
);
1252 mutex_unlock(&cl
->clm
);
1253 mutex_unlock(&ctx_mutex
);
1257 mutex_unlock(&cl
->clm
);
1258 if (cl
!= lru_first
) {
1259 cl
->lru_prev
->lru_next
= cl
->lru_next
;
1260 if (cl
->lru_next
!= NULL
)
1261 cl
->lru_next
->lru_prev
= cl
->lru_prev
;
1263 lru_last
= cl
->lru_prev
;
1264 cl
->lru_prev
= NULL
;
1265 cl
->lru_next
= lru_first
;
1266 lru_first
->lru_prev
= cl
;
1270 mutex_unlock(&ctx_mutex
);
1275 * Given the client context handle, find the context corresponding to it.
1276 * Don't change its LRU state since it may not be used.
1278 static svc_rpc_gss_data
*
1279 find_client(uint_t key
)
1281 int index
= (key
& HASHMASK
);
1282 svc_rpc_gss_data
*cl
;
1284 for (cl
= clients
[index
]; cl
!= NULL
; cl
= cl
->next
) {
1292 * Destroy a client context.
1295 destroy_client(svc_rpc_gss_data
*client_data
)
1298 int index
= (client_data
->key
& HASHMASK
);
1301 * remove from hash list
1303 if (client_data
->prev
== NULL
)
1304 clients
[index
] = client_data
->next
;
1306 client_data
->prev
->next
= client_data
->next
;
1307 if (client_data
->next
!= NULL
)
1308 client_data
->next
->prev
= client_data
->prev
;
1311 * remove from LRU list
1313 if (client_data
->lru_prev
== NULL
)
1314 lru_first
= client_data
->lru_next
;
1316 client_data
->lru_prev
->lru_next
= client_data
->lru_next
;
1317 if (client_data
->lru_next
!= NULL
)
1318 client_data
->lru_next
->lru_prev
= client_data
->lru_prev
;
1320 lru_last
= client_data
->lru_prev
;
1323 * If there is a GSS context, clean up GSS state.
1325 if (client_data
->context
!= GSS_C_NO_CONTEXT
) {
1326 (void) gss_delete_sec_context(&minor
, &client_data
->context
,
1328 if (client_data
->client_name
) {
1329 (void) gss_release_name(&minor
,
1330 &client_data
->client_name
);
1332 free(client_data
->raw_cred
.client_principal
);
1333 free(client_data
->u_cred
.gidlist
);
1334 if (client_data
->deleg
!= GSS_C_NO_CREDENTIAL
)
1335 (void) gss_release_cred(&minor
, &client_data
->deleg
);
1338 if (client_data
->retrans_data
!= NULL
)
1339 retrans_del(client_data
);
1346 * Check for expired client contexts.
1351 svc_rpc_gss_data
*cl
, *next
;
1354 for (index
= 0; index
< HASHMOD
; index
++) {
1355 cl
= clients
[index
];
1358 mutex_lock(&cl
->clm
);
1359 if ((cl
->expiration
!= GSS_C_INDEFINITE
&&
1360 cl
->expiration
<= time(0)) || cl
->stale
) {
1362 if (cl
->ref_cnt
== 0) {
1363 mutex_unlock(&cl
->clm
);
1366 mutex_unlock(&cl
->clm
);
1368 mutex_unlock(&cl
->clm
);
1372 last_swept
= time(0);
1376 * Drop the least recently used client context, if possible.
1379 drop_lru_client(void)
1381 mutex_lock(&lru_last
->clm
);
1382 lru_last
->stale
= TRUE
;
1383 mutex_unlock(&lru_last
->clm
);
1384 if (lru_last
->ref_cnt
== 0)
1385 destroy_client(lru_last
);
1391 * find service credentials
1392 * return cred if found,
1396 find_svc_cred(char *service_name
, uint_t program
, uint_t version
)
1399 svc_creds_list_t
*sc
;
1401 if (!svc_creds_list
)
1404 for (sc
= svc_creds_list
; sc
!= NULL
; sc
= sc
->next
) {
1405 if (program
!= sc
->program
|| version
!= sc
->version
)
1408 if (strcmp(service_name
, sc
->server_name
) != 0)
1416 * Set the server principal name.
1419 __rpc_gss_set_svc_name(char *server_name
, char *mech
, OM_uint32 req_time
,
1420 uint_t program
, uint_t version
)
1423 svc_creds_list_t
*svc_cred
;
1425 gss_OID_set_desc oid_set_desc
;
1426 gss_OID_set oid_set
;
1428 OM_uint32 major
, minor
;
1429 gss_buffer_desc name_buf
;
1431 if (!__rpc_gss_mech_to_oid(mech
, &mechanism
)) {
1435 name_buf
.value
= server_name
;
1436 name_buf
.length
= strlen(server_name
);
1437 major
= gss_import_name(&minor
, &name_buf
,
1438 (gss_OID
) GSS_C_NT_HOSTBASED_SERVICE
, &name
);
1439 if (major
!= GSS_S_COMPLETE
) {
1443 /* Check if there is already an entry in the svc_creds_list. */
1444 rw_wrlock(&cred_lock
);
1445 if (svc_cred
= find_svc_cred(server_name
, program
, version
)) {
1447 major
= gss_add_cred(&minor
, svc_cred
->cred
, name
,
1448 mechanism
, GSS_C_ACCEPT
, 0, req_time
, NULL
,
1449 &oid_set
, NULL
, &ret_time
);
1450 (void) gss_release_name(&minor
, &name
);
1451 if (major
== GSS_S_COMPLETE
) {
1453 * Successfully added the mech to the cred handle
1454 * free the existing oid_set in svc_cred
1456 gss_release_oid_set(&minor
, &svc_cred
->oid_set
);
1457 svc_cred
->oid_set
= oid_set
;
1458 rw_unlock(&cred_lock
);
1460 } else if (major
== GSS_S_DUPLICATE_ELEMENT
) {
1461 rw_unlock(&cred_lock
);
1463 } else if (major
== GSS_S_CREDENTIALS_EXPIRED
) {
1464 if (rpc_gss_refresh_svc_cred(svc_cred
)) {
1465 rw_unlock(&cred_lock
);
1468 rw_unlock(&cred_lock
);
1472 rw_unlock(&cred_lock
);
1476 svc_cred
= (svc_creds_list_t
*)malloc(sizeof (*svc_cred
));
1477 if (svc_cred
== NULL
) {
1478 (void) gss_release_name(&minor
, &name
);
1479 rw_unlock(&cred_lock
);
1482 oid_set_desc
.count
= 1;
1483 oid_set_desc
.elements
= mechanism
;
1484 major
= gss_acquire_cred(&minor
, name
, req_time
, &oid_set_desc
,
1485 GSS_C_ACCEPT
, &svc_cred
->cred
, &oid_set
, &ret_time
);
1487 if (major
!= GSS_S_COMPLETE
) {
1488 (void) gss_release_name(&minor
, &name
);
1490 rw_unlock(&cred_lock
);
1494 svc_cred
->name
= name
;
1495 svc_cred
->program
= program
;
1496 svc_cred
->version
= version
;
1497 svc_cred
->req_time
= req_time
;
1498 svc_cred
->oid_set
= oid_set
;
1499 svc_cred
->server_name
= strdup(server_name
);
1500 if (svc_cred
->server_name
== NULL
) {
1501 (void) gss_release_name(&minor
, &name
);
1502 free((char *)svc_cred
);
1503 rw_unlock(&cred_lock
);
1506 mutex_init(&svc_cred
->refresh_mutex
, USYNC_THREAD
, NULL
);
1508 svc_cred
->next
= svc_creds_list
;
1509 svc_creds_list
= svc_cred
;
1511 rw_unlock(&cred_lock
);
1517 * Refresh server credentials.
1520 rpc_gss_refresh_svc_cred(svc_creds_list_t
*svc_cred
)
1522 OM_uint32 major
, minor
;
1523 gss_OID_set oid_set
;
1526 (void) gss_release_cred(&minor
, &svc_cred
->cred
);
1527 svc_cred
->cred
= GSS_C_NO_CREDENTIAL
;
1528 major
= gss_acquire_cred(&minor
, svc_cred
->name
, svc_cred
->req_time
,
1529 svc_cred
->oid_set
, GSS_C_ACCEPT
, &svc_cred
->cred
, &oid_set
,
1531 if (major
!= GSS_S_COMPLETE
) {
1534 gss_release_oid_set(&minor
, &svc_cred
->oid_set
);
1535 svc_cred
->oid_set
= oid_set
;
1540 * Encrypt the serialized arguments from xdr_func applied to xdr_ptr
1541 * and write the result to xdrs.
1544 svc_rpc_gss_wrap(SVCAUTH
*auth
, XDR
*out_xdrs
, bool_t (*xdr_func
)(),
1547 svc_rpc_gss_parms_t
*gss_parms
= &auth
->svc_gss_parms
;
1550 * If context is not established, or if neither integrity nor
1551 * privacy service is used, don't wrap - just XDR encode.
1552 * Otherwise, wrap data using service and QOP parameters.
1554 if (!gss_parms
->established
|| gss_parms
->service
== rpc_gss_svc_none
)
1555 return ((*xdr_func
)(out_xdrs
, xdr_ptr
));
1557 return (__rpc_gss_wrap_data(gss_parms
->service
,
1558 (OM_uint32
)gss_parms
->qop_rcvd
,
1559 (gss_ctx_id_t
)gss_parms
->context
,
1561 out_xdrs
, xdr_func
, xdr_ptr
));
1565 * Decrypt the serialized arguments and XDR decode them.
1568 svc_rpc_gss_unwrap(SVCAUTH
*auth
, XDR
*in_xdrs
, bool_t (*xdr_func
)(),
1571 svc_rpc_gss_parms_t
*gss_parms
= &auth
->svc_gss_parms
;
1574 * If context is not established, or if neither integrity nor
1575 * privacy service is used, don't unwrap - just XDR decode.
1576 * Otherwise, unwrap data.
1578 if (!gss_parms
->established
|| gss_parms
->service
== rpc_gss_svc_none
)
1579 return ((*xdr_func
)(in_xdrs
, xdr_ptr
));
1581 return (__rpc_gss_unwrap_data(gss_parms
->service
,
1582 (gss_ctx_id_t
)gss_parms
->context
,
1584 gss_parms
->qop_rcvd
,
1585 in_xdrs
, xdr_func
, xdr_ptr
));
1589 __rpc_gss_svc_max_data_length(struct svc_req
*req
, int max_tp_unit_len
)
1592 svc_rpc_gss_parms_t
*gss_parms
;
1594 svcauth
= __svc_get_svcauth(req
->rq_xprt
);
1595 gss_parms
= &svcauth
->svc_gss_parms
;
1597 if (!gss_parms
->established
|| max_tp_unit_len
<= 0)
1600 return (__find_max_data_length(gss_parms
->service
,
1601 (gss_ctx_id_t
)gss_parms
->context
,
1602 gss_parms
->qop_rcvd
, max_tp_unit_len
));
1606 * Add retransmit entry to the context cache entry for a new xid.
1607 * If there is already an entry, delete it before adding the new one.
1609 static void retrans_add(svc_rpc_gss_data
*client
, uint32_t xid
,
1610 rpc_gss_init_res
*result
)
1612 retrans_entry
*rdata
;
1614 if (client
->retrans_data
&& client
->retrans_data
->xid
== xid
)
1617 rdata
= (retrans_entry
*) malloc(sizeof (*rdata
));
1622 rdata
->result
= *result
;
1624 if (result
->token
.length
!= 0) {
1625 GSS_DUP_BUFFER(rdata
->result
.token
, result
->token
);
1628 if (client
->retrans_data
)
1629 retrans_del(client
);
1631 client
->retrans_data
= rdata
;
1635 * Delete the retransmit data from the context cache entry.
1637 static void retrans_del(svc_rpc_gss_data
*client
)
1639 retrans_entry
*rdata
;
1640 OM_uint32 minor_stat
;
1642 if (client
->retrans_data
== NULL
)
1645 rdata
= client
->retrans_data
;
1646 if (rdata
->result
.token
.length
!= 0) {
1647 (void) gss_release_buffer(&minor_stat
, &rdata
->result
.token
);
1650 free((caddr_t
)rdata
);
1651 client
->retrans_data
= NULL
;