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 RCSID("$Id: gss_krb5.c,v 1.21 2006/11/10 00:57:27 lha Exp $");
37 gss_krb5_copy_ccache(OM_uint32
*minor_status
,
41 gss_buffer_set_t data_set
= GSS_C_NO_BUFFER_SET
;
48 ret
= gss_inquire_cred_by_oid(minor_status
,
50 GSS_KRB5_COPY_CCACHE_X
,
55 if (data_set
== GSS_C_NO_BUFFER_SET
|| data_set
->count
!= 1) {
56 gss_release_buffer_set(minor_status
, &data_set
);
57 *minor_status
= EINVAL
;
61 kret
= krb5_init_context(&context
);
64 gss_release_buffer_set(minor_status
, &data_set
);
68 kret
= asprintf(&str
, "%.*s", (int)data_set
->elements
[0].length
,
69 (char *)data_set
->elements
[0].value
);
70 gss_release_buffer_set(minor_status
, &data_set
);
72 *minor_status
= ENOMEM
;
76 kret
= krb5_cc_resolve(context
, str
, &id
);
83 kret
= krb5_cc_copy_cache(context
, id
, out
);
84 krb5_cc_close(context
, id
);
85 krb5_free_context(context
);
95 gss_krb5_import_cred(OM_uint32
*minor_status
,
97 krb5_principal keytab_principal
,
101 gss_buffer_desc buffer
;
102 OM_uint32 major_status
;
103 krb5_context context
;
109 *cred
= GSS_C_NO_CREDENTIAL
;
111 ret
= krb5_init_context(&context
);
114 return GSS_S_FAILURE
;
117 sp
= krb5_storage_emem();
119 *minor_status
= ENOMEM
;
120 major_status
= GSS_S_FAILURE
;
125 ret
= krb5_cc_get_full_name(context
, id
, &str
);
127 ret
= krb5_store_string(sp
, str
);
131 ret
= krb5_store_string(sp
, "");
134 major_status
= GSS_S_FAILURE
;
138 if (keytab_principal
) {
139 ret
= krb5_unparse_name(context
, keytab_principal
, &str
);
141 ret
= krb5_store_string(sp
, str
);
145 krb5_store_string(sp
, "");
148 major_status
= GSS_S_FAILURE
;
154 ret
= krb5_kt_get_full_name(context
, keytab
, &str
);
156 ret
= krb5_store_string(sp
, str
);
160 krb5_store_string(sp
, "");
163 major_status
= GSS_S_FAILURE
;
167 krb5_storage_to_data(sp
, &data
);
169 buffer
.value
= data
.data
;
170 buffer
.length
= data
.length
;
172 major_status
= gss_set_cred_option(minor_status
,
174 GSS_KRB5_IMPORT_CRED_X
,
176 krb5_data_free(&data
);
179 krb5_storage_free(sp
);
180 krb5_free_context(context
);
185 gsskrb5_register_acceptor_identity(const char *identity
)
187 struct _gss_mech_switch
*m
;
188 gss_buffer_desc buffer
;
193 buffer
.value
= rk_UNCONST(identity
);
194 buffer
.length
= strlen(identity
);
196 SLIST_FOREACH(m
, &_gss_mechs
, gm_link
) {
197 if (m
->gm_mech
.gm_set_sec_context_option
== NULL
)
199 m
->gm_mech
.gm_set_sec_context_option(&junk
, NULL
,
200 GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X
, &buffer
);
203 return (GSS_S_COMPLETE
);
207 gsskrb5_set_dns_canonicalize(int flag
)
209 struct _gss_mech_switch
*m
;
210 gss_buffer_desc buffer
;
212 char b
= (flag
!= 0);
217 buffer
.length
= sizeof(b
);
219 SLIST_FOREACH(m
, &_gss_mechs
, gm_link
) {
220 if (m
->gm_mech
.gm_set_sec_context_option
== NULL
)
222 m
->gm_mech
.gm_set_sec_context_option(&junk
, NULL
,
223 GSS_KRB5_SET_DNS_CANONICALIZE_X
, &buffer
);
226 return (GSS_S_COMPLETE
);
231 static krb5_error_code
232 set_key(krb5_keyblock
*keyblock
, gss_krb5_lucid_key_t
*key
)
234 key
->type
= keyblock
->keytype
;
235 key
->length
= keyblock
->keyvalue
.length
;
236 key
->data
= malloc(key
->length
);
237 if (key
->data
== NULL
&& key
->length
!= 0)
239 memcpy(key
->data
, keyblock
->keyvalue
.data
, key
->length
);
244 free_key(gss_krb5_lucid_key_t
*key
)
246 memset(key
->data
, 0, key
->length
);
248 memset(key
, 0, sizeof(*key
));
253 gss_krb5_export_lucid_sec_context(OM_uint32
*minor_status
,
254 gss_ctx_id_t
*context_handle
,
258 krb5_context context
= NULL
;
260 gss_buffer_set_t data_set
= GSS_C_NO_BUFFER_SET
;
261 OM_uint32 major_status
;
262 gss_krb5_lucid_context_v1_t
*ctx
= NULL
;
263 krb5_storage
*sp
= NULL
;
266 if (context_handle
== NULL
267 || *context_handle
== GSS_C_NO_CONTEXT
271 return GSS_S_FAILURE
;
275 gss_inquire_sec_context_by_oid (minor_status
,
277 GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X
,
282 if (data_set
== GSS_C_NO_BUFFER_SET
|| data_set
->count
!= 1) {
283 gss_release_buffer_set(minor_status
, &data_set
);
284 *minor_status
= EINVAL
;
285 return GSS_S_FAILURE
;
288 ret
= krb5_init_context(&context
);
292 ctx
= calloc(1, sizeof(*ctx
));
298 sp
= krb5_storage_from_mem(data_set
->elements
[0].value
,
299 data_set
->elements
[0].length
);
305 ret
= krb5_ret_uint32(sp
, &num
);
313 ret
= krb5_ret_uint32(sp
, &ctx
->initiate
);
316 ret
= krb5_ret_uint32(sp
, &ctx
->endtime
);
319 ret
= krb5_ret_uint32(sp
, &num
);
321 ctx
->send_seq
= ((uint64_t)num
) << 32;
322 ret
= krb5_ret_uint32(sp
, &num
);
324 ctx
->send_seq
|= num
;
326 ret
= krb5_ret_uint32(sp
, &num
);
328 ctx
->recv_seq
= ((uint64_t)num
) << 32;
329 ret
= krb5_ret_uint32(sp
, &num
);
331 ctx
->recv_seq
|= num
;
333 ret
= krb5_ret_uint32(sp
, &ctx
->protocol
);
335 if (ctx
->protocol
== 0) {
339 ret
= krb5_ret_uint32(sp
, &ctx
->rfc1964_kd
.sign_alg
);
342 ret
= krb5_ret_uint32(sp
, &ctx
->rfc1964_kd
.seal_alg
);
345 ret
= krb5_ret_keyblock(sp
, &key
);
347 ret
= set_key(&key
, &ctx
->rfc1964_kd
.ctx_key
);
348 krb5_free_keyblock_contents(context
, &key
);
350 } else if (ctx
->protocol
== 1) {
353 /* acceptor_subkey */
354 ret
= krb5_ret_uint32(sp
, &ctx
->cfx_kd
.have_acceptor_subkey
);
357 ret
= krb5_ret_keyblock(sp
, &key
);
359 ret
= set_key(&key
, &ctx
->cfx_kd
.ctx_key
);
360 krb5_free_keyblock_contents(context
, &key
);
362 /* acceptor_subkey */
363 if (ctx
->cfx_kd
.have_acceptor_subkey
) {
364 ret
= krb5_ret_keyblock(sp
, &key
);
366 ret
= set_key(&key
, &ctx
->cfx_kd
.acceptor_subkey
);
367 krb5_free_keyblock_contents(context
, &key
);
378 gss_release_buffer_set(minor_status
, &data_set
);
380 krb5_storage_free(sp
);
382 krb5_free_context(context
);
386 gss_krb5_free_lucid_sec_context(NULL
, ctx
);
389 return GSS_S_FAILURE
;
392 return GSS_S_COMPLETE
;
396 gss_krb5_free_lucid_sec_context(OM_uint32
*minor_status
, void *c
)
398 gss_krb5_lucid_context_v1_t
*ctx
= c
;
400 if (ctx
->version
!= 1) {
403 return GSS_S_FAILURE
;
406 if (ctx
->protocol
== 0) {
407 free_key(&ctx
->rfc1964_kd
.ctx_key
);
408 } else if (ctx
->protocol
== 1) {
409 free_key(&ctx
->cfx_kd
.ctx_key
);
410 if (ctx
->cfx_kd
.have_acceptor_subkey
)
411 free_key(&ctx
->cfx_kd
.acceptor_subkey
);
416 return GSS_S_COMPLETE
;
424 gss_krb5_set_allowable_enctypes(OM_uint32
*min_status
,
426 OM_uint32 num_enctypes
,
429 OM_uint32 maj_status
;
430 gss_buffer_desc buffer
;
434 sp
= krb5_storage_emem();
436 *min_status
= ENOMEM
;
437 maj_status
= GSS_S_FAILURE
;
442 krb5_store_int32(sp
, *enctypes
);
446 krb5_storage_to_data(sp
, &data
);
448 buffer
.value
= data
.data
;
449 buffer
.length
= data
.length
;
451 maj_status
= gss_set_cred_option(min_status
,
453 GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X
,
457 krb5_storage_free(sp
);
466 gsskrb5_set_send_to_kdc(struct gsskrb5_send_to_kdc
*c
)
468 struct _gss_mech_switch
*m
;
469 gss_buffer_desc buffer
;
476 buffer
.length
= sizeof(*c
);
482 SLIST_FOREACH(m
, &_gss_mechs
, gm_link
) {
483 if (m
->gm_mech
.gm_set_sec_context_option
== NULL
)
485 m
->gm_mech
.gm_set_sec_context_option(&junk
, NULL
,
486 GSS_KRB5_SEND_TO_KDC_X
, &buffer
);
489 return (GSS_S_COMPLETE
);
497 gsskrb5_extract_authtime_from_sec_context(OM_uint32
*minor_status
,
498 gss_ctx_id_t context_handle
,
501 gss_buffer_set_t data_set
= GSS_C_NO_BUFFER_SET
;
504 if (context_handle
== GSS_C_NO_CONTEXT
) {
505 *minor_status
= EINVAL
;
506 return GSS_S_FAILURE
;
510 gss_inquire_sec_context_by_oid (minor_status
,
512 GSS_KRB5_GET_AUTHTIME_X
,
517 if (data_set
== GSS_C_NO_BUFFER_SET
) {
518 gss_release_buffer_set(minor_status
, &data_set
);
519 *minor_status
= EINVAL
;
520 return GSS_S_FAILURE
;
523 if (data_set
->count
!= 1) {
524 gss_release_buffer_set(minor_status
, &data_set
);
525 *minor_status
= EINVAL
;
526 return GSS_S_FAILURE
;
529 if (data_set
->elements
[0].length
!= 4) {
530 gss_release_buffer_set(minor_status
, &data_set
);
531 *minor_status
= EINVAL
;
532 return GSS_S_FAILURE
;
536 unsigned char *buf
= data_set
->elements
[0].value
;
537 *authtime
= (buf
[3] <<24) | (buf
[2] << 16) |
538 (buf
[1] << 8) | (buf
[0] << 0);
541 gss_release_buffer_set(minor_status
, &data_set
);
544 return GSS_S_COMPLETE
;
552 gsskrb5_extract_authz_data_from_sec_context(OM_uint32
*minor_status
,
553 gss_ctx_id_t context_handle
,
555 gss_buffer_t ad_data
)
557 gss_buffer_set_t data_set
= GSS_C_NO_BUFFER_SET
;
559 gss_OID_desc oid_flat
;
560 heim_oid baseoid
, oid
;
563 if (context_handle
== GSS_C_NO_CONTEXT
) {
564 *minor_status
= EINVAL
;
565 return GSS_S_FAILURE
;
568 /* All this to append an integer to an oid... */
570 if (der_get_oid(GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X
->elements
,
571 GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X
->length
,
572 &baseoid
, NULL
) != 0) {
573 *minor_status
= EINVAL
;
574 return GSS_S_FAILURE
;
577 oid
.length
= baseoid
.length
+ 1;
578 oid
.components
= calloc(oid
.length
, sizeof(*oid
.components
));
579 if (oid
.components
== NULL
) {
580 der_free_oid(&baseoid
);
582 *minor_status
= ENOMEM
;
583 return GSS_S_FAILURE
;
586 memcpy(oid
.components
, baseoid
.components
,
587 baseoid
.length
* sizeof(*baseoid
.components
));
589 der_free_oid(&baseoid
);
591 oid
.components
[oid
.length
- 1] = ad_type
;
593 oid_flat
.length
= der_length_oid(&oid
);
594 oid_flat
.elements
= malloc(oid_flat
.length
);
595 if (oid_flat
.elements
== NULL
) {
596 free(oid
.components
);
597 *minor_status
= ENOMEM
;
598 return GSS_S_FAILURE
;
601 if (der_put_oid((unsigned char *)oid_flat
.elements
+ oid_flat
.length
- 1,
602 oid_flat
.length
, &oid
, &size
) != 0) {
603 free(oid
.components
);
605 *minor_status
= EINVAL
;
606 return GSS_S_FAILURE
;
608 if (oid_flat
.length
!= size
)
611 free(oid
.components
);
613 /* FINALLY, we have the OID */
615 maj_stat
= gss_inquire_sec_context_by_oid (minor_status
,
620 free(oid_flat
.elements
);
625 if (data_set
== GSS_C_NO_BUFFER_SET
|| data_set
->count
!= 1) {
626 gss_release_buffer_set(minor_status
, &data_set
);
627 *minor_status
= EINVAL
;
628 return GSS_S_FAILURE
;
631 ad_data
->value
= malloc(data_set
->elements
[0].length
);
632 if (ad_data
->value
== NULL
) {
633 gss_release_buffer_set(minor_status
, &data_set
);
634 *minor_status
= ENOMEM
;
635 return GSS_S_FAILURE
;
638 ad_data
->length
= data_set
->elements
[0].length
;
639 memcpy(ad_data
->value
, data_set
->elements
[0].value
, ad_data
->length
);
640 gss_release_buffer_set(minor_status
, &data_set
);
643 return GSS_S_COMPLETE
;
651 gsskrb5_extract_key(OM_uint32
*minor_status
,
652 gss_ctx_id_t context_handle
,
654 krb5_keyblock
**keyblock
)
657 gss_buffer_set_t data_set
= GSS_C_NO_BUFFER_SET
;
658 OM_uint32 major_status
;
659 krb5_context context
= NULL
;
660 krb5_storage
*sp
= NULL
;
662 if (context_handle
== GSS_C_NO_CONTEXT
) {
664 return GSS_S_FAILURE
;
667 ret
= krb5_init_context(&context
);
670 return GSS_S_FAILURE
;
674 gss_inquire_sec_context_by_oid (minor_status
,
681 if (data_set
== GSS_C_NO_BUFFER_SET
|| data_set
->count
!= 1) {
682 gss_release_buffer_set(minor_status
, &data_set
);
683 *minor_status
= EINVAL
;
684 return GSS_S_FAILURE
;
687 sp
= krb5_storage_from_mem(data_set
->elements
[0].value
,
688 data_set
->elements
[0].length
);
694 *keyblock
= calloc(1, sizeof(**keyblock
));
695 if (keyblock
== NULL
) {
700 ret
= krb5_ret_keyblock(sp
, *keyblock
);
703 gss_release_buffer_set(minor_status
, &data_set
);
705 krb5_storage_free(sp
);
706 if (ret
&& keyblock
) {
707 krb5_free_keyblock(context
, *keyblock
);
711 krb5_free_context(context
);
715 return GSS_S_FAILURE
;
717 return GSS_S_COMPLETE
;
725 gsskrb5_extract_service_keyblock(OM_uint32
*minor_status
,
726 gss_ctx_id_t context_handle
,
727 krb5_keyblock
**keyblock
)
729 return gsskrb5_extract_key(minor_status
,
731 GSS_KRB5_GET_SERVICE_KEYBLOCK_X
,
736 gsskrb5_get_initiator_subkey(OM_uint32
*minor_status
,
737 gss_ctx_id_t context_handle
,
738 krb5_keyblock
**keyblock
)
740 return gsskrb5_extract_key(minor_status
,
742 GSS_KRB5_GET_INITIATOR_SUBKEY_X
,
747 gsskrb5_get_subkey(OM_uint32
*minor_status
,
748 gss_ctx_id_t context_handle
,
749 krb5_keyblock
**keyblock
)
751 return gsskrb5_extract_key(minor_status
,
753 GSS_KRB5_GET_SUBKEY_X
,
758 gsskrb5_set_default_realm(const char *realm
)
760 struct _gss_mech_switch
*m
;
761 gss_buffer_desc buffer
;
766 buffer
.value
= rk_UNCONST(realm
);
767 buffer
.length
= strlen(realm
);
769 SLIST_FOREACH(m
, &_gss_mechs
, gm_link
) {
770 if (m
->gm_mech
.gm_set_sec_context_option
== NULL
)
772 m
->gm_mech
.gm_set_sec_context_option(&junk
, NULL
,
773 GSS_KRB5_SET_DEFAULT_REALM_X
, &buffer
);
776 return (GSS_S_COMPLETE
);