2 * Copyright (c) 2005 Doug Rabson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/lib/libgssapi/gss_krb5.c,v 1.1 2005/12/29 14:40:20 dfr Exp $
29 #include "mech_locl.h"
30 #include "krb5/gsskrb5_locl.h"
31 RCSID("$Id: gss_krb5.c,v 1.13 2006/10/20 22:05:02 lha Exp $");
38 gss_krb5_copy_ccache(OM_uint32
*minor_status
,
42 gss_buffer_set_t data_set
= GSS_C_NO_BUFFER_SET
;
49 ret
= gss_inquire_cred_by_oid(minor_status
,
51 GSS_KRB5_COPY_CCACHE_X
,
56 if (data_set
== GSS_C_NO_BUFFER_SET
|| data_set
->count
!= 1) {
57 gss_release_buffer_set(minor_status
, &data_set
);
58 *minor_status
= EINVAL
;
62 kret
= krb5_init_context(&context
);
65 gss_release_buffer_set(minor_status
, &data_set
);
69 kret
= asprintf(&str
, "%.*s", (int)data_set
->elements
[0].length
,
70 (char *)data_set
->elements
[0].value
);
71 gss_release_buffer_set(minor_status
, &data_set
);
73 *minor_status
= ENOMEM
;
77 kret
= krb5_cc_resolve(context
, str
, &id
);
84 kret
= krb5_cc_copy_cache(context
, id
, out
);
85 krb5_cc_close(context
, id
);
86 krb5_free_context(context
);
96 gss_krb5_import_cred(OM_uint32
*minor_status
,
98 krb5_principal keytab_principal
,
102 gss_buffer_desc buffer
;
103 OM_uint32 major_status
;
104 krb5_context context
;
110 *cred
= GSS_C_NO_CREDENTIAL
;
112 ret
= krb5_init_context(&context
);
115 return GSS_S_FAILURE
;
118 sp
= krb5_storage_emem();
120 *minor_status
= ENOMEM
;
121 major_status
= GSS_S_FAILURE
;
126 ret
= krb5_cc_get_full_name(context
, id
, &str
);
128 ret
= krb5_store_string(sp
, str
);
132 ret
= krb5_store_string(sp
, "");
135 major_status
= GSS_S_FAILURE
;
139 if (keytab_principal
) {
140 ret
= krb5_unparse_name(context
, keytab_principal
, &str
);
142 ret
= krb5_store_string(sp
, str
);
146 krb5_store_string(sp
, "");
149 major_status
= GSS_S_FAILURE
;
155 ret
= krb5_kt_get_full_name(context
, keytab
, &str
);
157 ret
= krb5_store_string(sp
, str
);
161 krb5_store_string(sp
, "");
164 major_status
= GSS_S_FAILURE
;
168 krb5_storage_to_data(sp
, &data
);
170 buffer
.value
= data
.data
;
171 buffer
.length
= data
.length
;
173 major_status
= gss_set_cred_option(minor_status
,
175 GSS_KRB5_IMPORT_CRED_X
,
177 krb5_data_free(&data
);
180 krb5_storage_free(sp
);
181 krb5_free_context(context
);
186 gsskrb5_register_acceptor_identity(const char *identity
)
188 struct _gss_mech_switch
*m
;
189 gss_buffer_desc buffer
;
194 buffer
.value
= rk_UNCONST(identity
);
195 buffer
.length
= strlen(identity
);
197 SLIST_FOREACH(m
, &_gss_mechs
, gm_link
) {
198 if (m
->gm_mech
.gm_set_sec_context_option
== NULL
)
200 m
->gm_mech
.gm_set_sec_context_option(&junk
, NULL
,
201 GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X
, &buffer
);
204 return (GSS_S_COMPLETE
);
208 gsskrb5_set_dns_canonicalize(int flag
)
210 struct _gss_mech_switch
*m
;
211 gss_buffer_desc buffer
;
213 char b
= (flag
!= 0);
218 buffer
.length
= sizeof(b
);
220 SLIST_FOREACH(m
, &_gss_mechs
, gm_link
) {
221 if (m
->gm_mech
.gm_set_sec_context_option
== NULL
)
223 m
->gm_mech
.gm_set_sec_context_option(&junk
, NULL
,
224 GSS_KRB5_SET_DNS_CANONICALIZE_X
, &buffer
);
227 return (GSS_S_COMPLETE
);
232 static krb5_error_code
233 set_key(krb5_keyblock
*keyblock
, gss_krb5_lucid_key_t
*key
)
235 key
->type
= keyblock
->keytype
;
236 key
->length
= keyblock
->keyvalue
.length
;
237 key
->data
= malloc(key
->length
);
238 if (key
->data
== NULL
&& key
->length
!= 0)
240 memcpy(key
->data
, keyblock
->keyvalue
.data
, key
->length
);
245 free_key(gss_krb5_lucid_key_t
*key
)
247 memset(key
->data
, 0, key
->length
);
249 memset(key
, 0, sizeof(*key
));
254 gss_krb5_export_lucid_sec_context(OM_uint32
*minor_status
,
255 gss_ctx_id_t
*context_handle
,
259 krb5_context context
= NULL
;
261 gss_buffer_set_t data_set
= GSS_C_NO_BUFFER_SET
;
262 OM_uint32 major_status
;
263 gss_krb5_lucid_context_v1_t
*ctx
= NULL
;
264 krb5_storage
*sp
= NULL
;
267 if (context_handle
== NULL
|| *context_handle
== GSS_C_NO_CONTEXT
|| version
!= 1) {
269 return GSS_S_FAILURE
;
273 gss_inquire_sec_context_by_oid (minor_status
,
275 GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X
,
280 if (data_set
== GSS_C_NO_BUFFER_SET
|| data_set
->count
!= 1) {
281 gss_release_buffer_set(minor_status
, &data_set
);
282 *minor_status
= EINVAL
;
283 return GSS_S_FAILURE
;
286 ret
= krb5_init_context(&context
);
290 ctx
= calloc(1, sizeof(*ctx
));
296 sp
= krb5_storage_from_mem(data_set
->elements
[0].value
,
297 data_set
->elements
[0].length
);
303 ret
= krb5_ret_uint32(sp
, &num
);
311 ret
= krb5_ret_uint32(sp
, &ctx
->initiate
);
314 ret
= krb5_ret_uint32(sp
, &ctx
->endtime
);
317 ret
= krb5_ret_uint32(sp
, &num
);
319 ctx
->send_seq
= ((uint64_t)num
) << 32;
320 ret
= krb5_ret_uint32(sp
, &num
);
322 ctx
->send_seq
|= num
;
324 ret
= krb5_ret_uint32(sp
, &num
);
326 ctx
->recv_seq
= ((uint64_t)num
) << 32;
327 ret
= krb5_ret_uint32(sp
, &num
);
329 ctx
->recv_seq
|= num
;
331 ret
= krb5_ret_uint32(sp
, &ctx
->protocol
);
333 if (ctx
->protocol
== 0) {
337 ret
= krb5_ret_uint32(sp
, &ctx
->rfc1964_kd
.sign_alg
);
340 ret
= krb5_ret_uint32(sp
, &ctx
->rfc1964_kd
.seal_alg
);
343 ret
= krb5_ret_keyblock(sp
, &key
);
345 ret
= set_key(&key
, &ctx
->rfc1964_kd
.ctx_key
);
346 krb5_free_keyblock_contents(context
, &key
);
348 } else if (ctx
->protocol
== 1) {
351 /* acceptor_subkey */
352 ret
= krb5_ret_uint32(sp
, &ctx
->cfx_kd
.have_acceptor_subkey
);
355 ret
= krb5_ret_keyblock(sp
, &key
);
357 ret
= set_key(&key
, &ctx
->cfx_kd
.ctx_key
);
358 krb5_free_keyblock_contents(context
, &key
);
360 /* acceptor_subkey */
361 if (ctx
->cfx_kd
.have_acceptor_subkey
) {
362 ret
= krb5_ret_keyblock(sp
, &key
);
364 ret
= set_key(&key
, &ctx
->cfx_kd
.acceptor_subkey
);
365 krb5_free_keyblock_contents(context
, &key
);
376 gss_release_buffer_set(minor_status
, &data_set
);
378 krb5_storage_free(sp
);
380 krb5_free_context(context
);
384 gss_krb5_free_lucid_sec_context(NULL
, ctx
);
387 return GSS_S_FAILURE
;
390 return GSS_S_COMPLETE
;
394 gss_krb5_free_lucid_sec_context(OM_uint32
*minor_status
, void *c
)
396 gss_krb5_lucid_context_v1_t
*ctx
= c
;
398 if (ctx
->version
!= 1) {
401 return GSS_S_FAILURE
;
404 if (ctx
->protocol
== 0) {
405 free_key(&ctx
->rfc1964_kd
.ctx_key
);
406 } else if (ctx
->protocol
== 1) {
407 free_key(&ctx
->cfx_kd
.ctx_key
);
408 if (ctx
->cfx_kd
.have_acceptor_subkey
)
409 free_key(&ctx
->cfx_kd
.acceptor_subkey
);
414 return GSS_S_COMPLETE
;
418 gsskrb5_set_send_to_kdc(struct gsskrb5_send_to_kdc
*c
)
420 struct _gss_mech_switch
*m
;
421 gss_buffer_desc buffer
;
428 buffer
.length
= sizeof(*c
);
434 SLIST_FOREACH(m
, &_gss_mechs
, gm_link
) {
435 if (m
->gm_mech
.gm_set_sec_context_option
== NULL
)
437 m
->gm_mech
.gm_set_sec_context_option(&junk
, NULL
,
438 GSS_KRB5_SEND_TO_KDC_X
, &buffer
);
441 return (GSS_S_COMPLETE
);
445 gsskrb5_extract_authtime_from_sec_context(OM_uint32
*minor_status
,
446 gss_ctx_id_t context_handle
,
449 gss_buffer_set_t data_set
= GSS_C_NO_BUFFER_SET
;
454 if (context_handle
== GSS_C_NO_CONTEXT
) {
455 _gsskrb5_set_status("no context handle");
456 *minor_status
= EINVAL
;
457 return GSS_S_FAILURE
;
461 gss_inquire_sec_context_by_oid (minor_status
,
463 GSS_KRB5_GET_AUTHTIME_X
,
468 if (data_set
== GSS_C_NO_BUFFER_SET
) {
469 _gsskrb5_set_status("no buffers returned");
470 gss_release_buffer_set(minor_status
, &data_set
);
471 *minor_status
= EINVAL
;
472 return GSS_S_FAILURE
;
475 if (data_set
->count
!= 1) {
476 _gsskrb5_set_status("%d != 1 buffers returned", data_set
->count
);
477 gss_release_buffer_set(minor_status
, &data_set
);
478 *minor_status
= EINVAL
;
479 return GSS_S_FAILURE
;
482 if (data_set
->elements
[0].length
!= 4) {
483 gss_release_buffer_set(minor_status
, &data_set
);
484 _gsskrb5_set_status("Error extracting authtime from security context: only got %d < 4 bytes",
485 data_set
->elements
[0].length
);
486 *minor_status
= EINVAL
;
487 return GSS_S_FAILURE
;
490 ret
= _gsskrb5_decode_om_uint32(data_set
->elements
[0].value
, &time32
);
492 gss_release_buffer_set(minor_status
, &data_set
);
494 return GSS_S_FAILURE
;
498 gss_release_buffer_set(minor_status
, &data_set
);
501 return GSS_S_COMPLETE
;
505 gsskrb5_extract_authz_data_from_sec_context(OM_uint32
*minor_status
,
506 gss_ctx_id_t context_handle
,
508 gss_buffer_t ad_data
)
510 gss_buffer_set_t data_set
= GSS_C_NO_BUFFER_SET
;
512 gss_OID_desc authz_oid_flat
;
514 heim_oid new_authz_oid
;
517 if (context_handle
== GSS_C_NO_CONTEXT
) {
518 *minor_status
= EINVAL
;
519 return GSS_S_FAILURE
;
522 /* All this to append an integer to an oid... */
524 if (der_get_oid(GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X
->elements
,
525 GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X
->length
,
526 &authz_oid
, NULL
) != 0) {
527 *minor_status
= EINVAL
;
528 return GSS_S_FAILURE
;
531 new_authz_oid
.length
= authz_oid
.length
+ 1;
532 new_authz_oid
.components
= malloc(new_authz_oid
.length
* sizeof(*new_authz_oid
.components
));
533 if (!new_authz_oid
.components
) {
534 free(authz_oid
.components
);
536 *minor_status
= ENOMEM
;
537 return GSS_S_FAILURE
;
540 memcpy(new_authz_oid
.components
, authz_oid
.components
,
541 authz_oid
.length
* sizeof(*authz_oid
.components
));
543 free(authz_oid
.components
);
545 new_authz_oid
.components
[new_authz_oid
.length
- 1] = ad_type
;
547 authz_oid_flat
.length
= der_length_oid(&new_authz_oid
);
548 authz_oid_flat
.elements
= malloc(authz_oid_flat
.length
);
550 if (!authz_oid_flat
.elements
) {
551 free(new_authz_oid
.components
);
553 *minor_status
= ENOMEM
;
554 return GSS_S_FAILURE
;
557 if (der_put_oid((unsigned char *)authz_oid_flat
.elements
+ authz_oid_flat
.length
- 1,
558 authz_oid_flat
.length
,
559 &new_authz_oid
, &size
) != 0) {
560 free(new_authz_oid
.components
);
562 *minor_status
= EINVAL
;
563 return GSS_S_FAILURE
;
566 free(new_authz_oid
.components
);
568 /* FINALLY, we have the OID */
571 gss_inquire_sec_context_by_oid (minor_status
,
576 free(authz_oid_flat
.elements
);
581 if (data_set
== GSS_C_NO_BUFFER_SET
|| data_set
->count
!= 1) {
582 gss_release_buffer_set(minor_status
, &data_set
);
583 *minor_status
= EINVAL
;
584 return GSS_S_FAILURE
;
587 ad_data
->value
= malloc(data_set
->elements
[0].length
);
588 if (ad_data
->value
== NULL
) {
589 gss_release_buffer_set(minor_status
, &data_set
);
590 *minor_status
= ENOMEM
;
591 return GSS_S_FAILURE
;
594 ad_data
->length
= data_set
->elements
[0].length
;
595 memcpy(ad_data
->value
, data_set
->elements
[0].value
, ad_data
->length
);
596 gss_release_buffer_set(minor_status
, &data_set
);
599 return GSS_S_COMPLETE
;
603 gsskrb5_extract_key(OM_uint32
*minor_status
,
604 gss_ctx_id_t context_handle
,
606 krb5_keyblock
**keyblock
)
609 gss_buffer_set_t data_set
= GSS_C_NO_BUFFER_SET
;
610 OM_uint32 major_status
;
611 krb5_storage
*sp
= NULL
;
613 ret
= _gsskrb5_init();
616 return GSS_S_FAILURE
;
619 if (context_handle
== GSS_C_NO_CONTEXT
) {
620 _gsskrb5_set_status("no context handle");
621 *minor_status
= EINVAL
;
622 return GSS_S_FAILURE
;
626 gss_inquire_sec_context_by_oid (minor_status
,
633 if (data_set
== GSS_C_NO_BUFFER_SET
) {
634 _gsskrb5_set_status("no buffers returned");
635 gss_release_buffer_set(minor_status
, &data_set
);
636 *minor_status
= EINVAL
;
637 return GSS_S_FAILURE
;
640 if (data_set
->count
!= 1) {
641 _gsskrb5_set_status("%d != 1 buffers returned", data_set
->count
);
642 gss_release_buffer_set(minor_status
, &data_set
);
643 *minor_status
= EINVAL
;
644 return GSS_S_FAILURE
;
647 sp
= krb5_storage_from_mem(data_set
->elements
[0].value
,
648 data_set
->elements
[0].length
);
654 *keyblock
= calloc(1, sizeof(**keyblock
));
655 if (keyblock
== NULL
) {
660 ret
= krb5_ret_keyblock(sp
, *keyblock
);
663 gss_release_buffer_set(minor_status
, &data_set
);
665 krb5_storage_free(sp
);
667 _gsskrb5_set_error_string();
669 krb5_free_keyblock(_gsskrb5_context
, *keyblock
);
673 return GSS_S_FAILURE
;
676 return GSS_S_COMPLETE
;
680 gsskrb5_extract_service_keyblock(OM_uint32
*minor_status
,
681 gss_ctx_id_t context_handle
,
682 krb5_keyblock
**keyblock
)
684 return gsskrb5_extract_key(minor_status
,
686 GSS_KRB5_GET_SERVICE_KEYBLOCK_X
,
691 gsskrb5_get_initiator_subkey(OM_uint32
*minor_status
,
692 gss_ctx_id_t context_handle
,
693 krb5_keyblock
**keyblock
)
695 return gsskrb5_extract_key(minor_status
,
697 GSS_KRB5_GET_INITIATOR_SUBKEY_X
,
702 gsskrb5_get_subkey(OM_uint32
*minor_status
,
703 gss_ctx_id_t context_handle
,
704 krb5_keyblock
**keyblock
)
706 return gsskrb5_extract_key(minor_status
,
708 GSS_KRB5_GET_ACCEPTOR_SUBKEY_X
,