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]
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.
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>
42 #include <rpc/rpcsec_defs.h>
43 #include <sys/debug.h>
44 #include <sys/cmn_err.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();
53 static void rpc_gss_destroy_pvt();
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();
63 #include <sys/promif.h>
66 static struct auth_ops rpc_gss_ops
= {
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
;
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
{
121 time_t ref_time
; /* the time referenced previously */
122 time_t ctx_expired_time
; /* when the context will be expired */
124 struct ga_cache_entry
*next
;
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
;
137 int ga_cache_reclaim
;
139 #define NOT_DEAD(ptr) ASSERT((((intptr_t)(ptr)) != 0xdeadbeef))
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.
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;
181 gssauth_zone_fini(zoneid_t zoneid
, void *unused
)
183 struct ga_cache_entry
*p
, *prev
, *next
;
187 rw_enter(&ga_cache_table_lock
, RW_WRITER
);
189 for (i
= 0; i
< GSSAUTH_TABLESIZE
; i
++) {
191 for (p
= ga_cache_table
[i
]; p
; p
= 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
>
203 if ((p
->ref_time
+ rpc_gss_cache_time
<=
205 RPCGSS_LOG0(2, "gssauth_cache_"
206 "reclaim: in_use\n");
212 if (p
->zoneid
!= zoneid
) {
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
);
224 ga_cache_table
[i
] = next
;
226 NOT_DEAD(prev
->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.
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
,
260 rpc_gss_OID mechanism
,
261 rpc_gss_service_t service_type
,
263 rpc_gss_options_req_t
*options_req
,
264 rpc_gss_options_ret_t
*options_ret
,
269 struct ga_cache_entry
**head
, *current
, *new, *prev
;
272 rpc_gss_options_ret_t opt_ret
;
274 uid_t uid
= crgetuid(cr
);
275 zoneid_t zoneid
= getzoneid();
284 if (HASH(cache_key
, uid
) < 0) {
285 prom_printf("cache_key %p, cr %p\n", cache_key
, (void *)cr
);
290 * Get a valid gss auth handle from the cache table.
291 * If auth in cache is invalid and not in use, destroy it.
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
)];
301 for (current
= *head
; current
; current
= current
->next
) {
304 if ((cache_key
== current
->cache_key
) &&
305 (uid
== current
->uid
) && (zoneid
== current
->zoneid
) &&
307 current
->in_use
= TRUE
;
308 current
->ref_time
= gethrestime_sec();
309 ap
= AUTH_PRIVATE(current
->auth
);
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");
319 *head
= current
->next
;
321 prev
->next
= current
->next
;
323 rpc_gss_destroy(current
->auth
);
324 kmem_cache_free(ga_cache_handle
, (void *) current
);
327 auth
= current
->auth
;
334 rw_exit(&ga_cache_table_lock
);
337 * If no valid gss auth handle can be found in the cache, create
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
);
348 RPCGSS_LOG(2, "rpc_gss_secget: new auth %p\n",
350 new = kmem_cache_alloc(ga_cache_handle
, KM_NOSLEEP
);
354 new->cache_key
= cache_key
;
356 new->zoneid
= zoneid
;
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
;
363 new->ctx_expired_time
= GSS_C_INDEFINITE
;
366 rw_enter(&ga_cache_table_lock
, RW_WRITER
);
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
);
387 * rpc_gss_secfree will destroy a rpcsec_gss context only if
388 * the auth handle is not in the cache table.
391 rpc_gss_secfree(AUTH
*auth
)
393 struct ga_cache_entry
*next
, *cur
;
397 * Check the cache table to find the auth.
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
) {
406 if (cur
->auth
== auth
) {
407 ASSERT(cur
->in_use
== TRUE
);
409 rw_exit(&ga_cache_table_lock
);
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 */
435 OM_uint32 minor_stat
;
436 gss_name_t target_name
;
439 gss_buffer_desc input_name
;
441 rpc_gss_data
*ap
= NULL
;
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
) {
455 "rpc_gss_seccreate: unable to import gss name\n");
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");
468 kmem_free((char *)auth
, sizeof (*auth
));
469 (void) gss_release_name(&minor_stat
, &target_name
);
473 bzero((char *)ap
, sizeof (*ap
));
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
;
482 ap
->my_cred
= GSS_C_NO_CREDENTIAL
;
483 ap
->req_flags
= GSS_C_MUTUAL_FLAG
;
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
;
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
);
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
);
543 * Private interface to create a context. This is the interface
544 * that's invoked when the context has to be refreshed.
547 rpc_gss_seccreate_pvt(gssstat
, minor_stat
, auth
, ap
, desired_mech_type
,
548 actual_mech_type
, ret_flags
, time_rec
, cr
, isrefresh
)
550 OM_uint32
*minor_stat
;
553 gss_OID desired_mech_type
;
554 gss_OID
*actual_mech_type
;
560 CLIENT
*clnt
= ap
->clnt
;
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;
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
;
583 ap
->gss_proc
= RPCSEC_GSS_INIT
;
586 * should not change clnt->cl_auth at this time, so save
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
;
599 *gssstat
= kgss_init_sec_context(minor_stat
,
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");
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;
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
,
657 if (callstat
== RPC_SUCCESS
) {
660 call_res
.gss_major
== GSS_S_FAILURE
) {
662 clock_t one_sec
= drv_usectohz(1000000);
667 * Pause a little and try again.
670 if (clnt
->cl_nosignal
== TRUE
) {
673 if (delay_sig(one_sec
)) {
683 if (callstat
== RPC_TIMEDOUT
) {
688 if (callstat
== RPC_XPRTFAILED
) {
693 if (callstat
== RPC_INTR
) {
698 if (callstat
== RPC_INPROGRESS
) {
702 clnt_geterr(clnt
, &rpcerr
);
703 error
= rpcerr
.re_errno
;
707 (void) CLNT_CONTROL(clnt
, CLSET_XID
, (char *)&oldxid
);
709 (void) gss_release_buffer(minor_stat
, &call_arg
);
711 if (callstat
!= RPC_SUCCESS
) {
713 "rpc_gss_seccreate_pvt: clnt_call failed %d\n",
719 * we have results - note that these need to be freed
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
);
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");
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
)) {
749 "rpc_gss_seccreate_pvt: ctx_handle not the same\n");
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");
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");
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
);
783 * results were okay.. continue if necessary
785 if (*gssstat
== GSS_S_CONTINUE_NEEDED
) {
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
795 *gssstat
= kgss_export_sec_context(minor_stat
, ap
->context
,
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",
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
,
806 "rpcsec_gss_secreate_pvt:gss_export_sec_context");
807 (void) kgss_delete_sec_context(minor_stat
,
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
,
820 *gssstat
= kgss_import_sec_context(minor_stat
, &process_token
,
823 if (*gssstat
== GSS_S_COMPLETE
) {
824 (void) gss_release_buffer(minor_stat
, &process_token
);
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
,
831 (void) gss_release_buffer(minor_stat
, &process_token
);
838 * Validate the sequence window - RFC 2203 section 5.2.3.1
840 if (!validate_seqwin(ap
)) {
846 * Done! Security context creation is successful.
847 * Ready for exchanging data.
849 ap
->established
= TRUE
;
851 ap
->gss_proc
= RPCSEC_GSS_DATA
;
854 clnt
->cl_auth
= save_auth
; /* restore cl_auth */
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
867 if (isrefresh
&& (error
== ETIMEDOUT
|| error
== ECONNRESET
)) {
871 if (ap
->context
!= NULL
) {
872 rpc_gss_free_pvt(auth
);
875 return (error
? error
: EACCES
);
879 * Marshall credentials.
882 marshall_creds(ap
, xdrs
, cred_buf_len
)
887 rpc_gss_creds ag_creds
;
889 struct opaque_auth creds
;
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
;
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
,
910 if (!__xdr_rpc_gss_creds(&cred_xdrs
, &ag_creds
)) {
911 kmem_free(cred_buf
, MAX_AUTH_BYTES
);
912 XDR_DESTROY(&cred_xdrs
);
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
);
926 kmem_free(cred_buf
, cred_buf_len
);
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.
937 marshall_verf(ap
, xdrs
, buf
)
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
;
948 * If context is not established yet, use NULL verifier.
950 if (!ap
->established
) {
951 verf
.oa_flavor
= AUTH_NONE
;
954 return (xdr_opaque_auth(xdrs
, &verf
));
957 verf
.oa_flavor
= RPCSEC_GSS
;
958 in_buf
.length
= xdr_getpos(xdrs
);
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
) {
966 "marshall_verf: kgss_sign failed GSS Major %x Minor %x\n",
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
);
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.
984 validate_seqwin(rpc_gss_data
*ap
)
987 OM_uint32 major
= 0, minor
= 0;
988 gss_buffer_desc msg_buf
, tok_buf
;
991 ASSERT(ap
->verifier
);
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
,
1001 if (major
!= GSS_S_COMPLETE
) {
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
);
1013 * Validate RPC response verifier from server. The response verifier
1014 * is the checksum of the request sequence number.
1017 rpc_gss_validate(auth
, verf
)
1019 struct opaque_auth
*verf
;
1021 rpc_gss_data
*ap
= AUTH_PRIVATE(auth
);
1023 OM_uint32 major
, minor
;
1024 gss_buffer_desc msg_buf
, tok_buf
;
1028 * If context is not established yet, save the verifier for
1029 * validating the sequence window later at the end of context
1032 if (!ap
->established
) {
1033 if (ap
->verifier
== NULL
) {
1034 ap
->verifier
= kmem_zalloc(sizeof (struct opaque_auth
),
1036 if (verf
->oa_length
> 0)
1037 ap
->verifier
->oa_base
= kmem_zalloc(verf
->oa_length
,
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
,
1046 ap
->verifier
->oa_length
= verf
->oa_length
;
1047 bcopy(verf
->oa_base
, ap
->verifier
->oa_base
, verf
->oa_length
);
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
,
1058 if (major
!= GSS_S_COMPLETE
) {
1060 "rpc_gss_validate: kgss_verify failed GSS Major %x Minor %x\n",
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.
1073 rpc_gss_refresh(auth
, msg
, cr
)
1075 struct rpc_msg
*msg
;
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
;
1083 OM_uint32 gssstat
, minor_stat
;
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
1095 if (msg
->rjcted_rply
.rj_why
== RPCSEC_GSS_NOCRED
||
1096 msg
->rjcted_rply
.rj_why
== RPCSEC_GSS_FAILED
||
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
;
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
1118 if (!ap
->established
) {
1121 "rpc_gss_refresh: context was not established\n");
1126 est_sav
= ap
->established
;
1127 sn_sav
= ap
->seq_num
;
1128 proc_sav
= ap
->gss_proc
;
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);
1140 "rpc_gss_refresh: auth %p refreshed\n", (void *)auth
);
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
,
1157 * Restore the original value for the caller to
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
;
1171 RPCGSS_LOG(1, "rpc_gss_refresh: can't refresh this "
1172 "auth, error=%d\n", error
);
1176 RPCGSS_LOG0(1, "rpc_gss_refresh: don't refresh");
1180 if (ctx_sav
!= NULL
) {
1181 (void) kgss_delete_sec_context(&minor_stat
,
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.
1195 rpc_gss_destroy(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).
1216 rpc_gss_free_pvt(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
);
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
,
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
;
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.
1282 rpc_gss_destroy_pvt(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) {
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
);
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
1316 rpc_gss_wrap(auth
, buf
, buflen
, out_xdrs
, xdr_func
, xdr_ptr
)
1318 char *buf
; /* encoded header */
1319 /* has been changed to u_int in the user land */
1320 uint_t buflen
; /* encoded header length */
1325 rpc_gss_data
*ap
= AUTH_PRIVATE(auth
);
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.
1343 RPCGSS_LOG0(1, "rpc_gss_wrap: reject an invalid context\n");
1348 * If context is established, bump up sequence number.
1350 if (ap
->established
)
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
) +
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");
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");
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");
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");
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.
1416 rpc_gss_unwrap(auth
, in_xdrs
, xdr_func
, xdr_ptr
)
1419 bool_t (*xdr_func
)();
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
,
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
;
1447 zoneid_t zoneid
= getzoneid();
1451 * Check the cache table against the uid and the
1454 rw_enter(&ga_cache_table_lock
, RW_WRITER
);
1455 for (i
= 0; i
< GSSAUTH_TABLESIZE
; i
++) {
1457 for (cur
= ga_cache_table
[i
]; cur
; cur
= 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
)) {
1466 RPCGSS_LOG(2, "rpc_gss_revauth:invalid "
1467 "auth %p\n", (void *)cur
->auth
);
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
,
1477 ga_cache_table
[i
] = next
;
1480 NOT_DEAD(prev
->next
);
1487 rw_exit(&ga_cache_table_lock
);
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.
1501 rpc_gss_secpurge(void *cache_key
)
1503 struct ga_cache_entry
*next
, *prev
, *cur
;
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
++) {
1512 for (cur
= ga_cache_table
[i
]; cur
; cur
= 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
);
1523 ga_cache_table
[i
] = next
;
1525 NOT_DEAD(prev
->next
);
1533 rw_exit(&ga_cache_table_lock
);
1537 * Function: rpc_gss_nextverf. Not used.
1545 * Function: rpc_gss_marshall - no op routine.
1546 * rpc_gss_wrap() is doing the marshalling.
1550 rpc_gss_marshall(auth
, xdrs
)
1558 * Set service defaults.
1559 * Not supported yet.
1563 rpc_gss_set_defaults(auth
, service
, qop
)
1565 rpc_gss_service_t service
;
1573 rpc_gss_max_data_length(AUTH
*rpcgss_handle
, int max_tp_unit_len
)
1579 rpc_gss_get_service_type(AUTH
*auth
)
1581 rpc_gss_data
*ap
= AUTH_PRIVATE(auth
);
1583 return (ap
->service
);