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
29 #include <gssapi/gssapi.h>
30 #include <gssapi/gssapi_krb5.h>
32 /* RCSID("$Id: gss_krb5.c 21889 2007-08-09 07:43:24Z lha $"); */
39 gss_krb5_copy_ccache(OM_uint32 *minor_status,
43 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
50 ret = gss_inquire_cred_by_oid(minor_status,
52 GSS_KRB5_COPY_CCACHE_X,
57 if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
58 gss_release_buffer_set(minor_status, &data_set);
59 *minor_status = EINVAL;
63 kret = krb5_init_context(&context);
66 gss_release_buffer_set(minor_status, &data_set);
70 kret = asprintf(&str, "%.*s", (int)data_set->elements[0].length,
71 (char *)data_set->elements[0].value);
72 gss_release_buffer_set(minor_status, &data_set);
74 *minor_status = ENOMEM;
78 kret = krb5_cc_resolve(context, str, &id);
85 kret = krb5_cc_copy_cache(context, id, out);
86 krb5_cc_close(context, id);
87 krb5_free_context(context);
97 gss_krb5_import_cred(OM_uint32 *minor_status,
99 krb5_principal keytab_principal,
103 gss_buffer_desc buffer;
104 OM_uint32 major_status;
105 krb5_context context;
111 *cred = GSS_C_NO_CREDENTIAL;
113 ret = krb5_init_context(&context);
116 return GSS_S_FAILURE;
119 sp = krb5_storage_emem();
121 *minor_status = ENOMEM;
122 major_status = GSS_S_FAILURE;
127 ret = krb5_cc_get_full_name(context, id, &str);
129 ret = krb5_store_string(sp, str);
133 ret = krb5_store_string(sp, "");
136 major_status = GSS_S_FAILURE;
140 if (keytab_principal) {
141 ret = krb5_unparse_name(context, keytab_principal, &str);
143 ret = krb5_store_string(sp, str);
147 krb5_store_string(sp, "");
150 major_status = GSS_S_FAILURE;
156 ret = krb5_kt_get_full_name(context, keytab, &str);
158 ret = krb5_store_string(sp, str);
162 krb5_store_string(sp, "");
165 major_status = GSS_S_FAILURE;
169 ret = krb5_storage_to_data(sp, &data);
172 major_status = GSS_S_FAILURE;
176 buffer.value = data.data;
177 buffer.length = data.length;
179 major_status = gss_set_cred_option(minor_status,
181 GSS_KRB5_IMPORT_CRED_X,
183 krb5_data_free(&data);
186 krb5_storage_free(sp);
187 krb5_free_context(context);
192 gsskrb5_register_acceptor_identity(const char *identity)
194 gss_buffer_desc buffer;
197 buffer.value = rk_UNCONST(identity);
198 buffer.length = strlen(identity);
200 gss_set_sec_context_option(&junk, NULL,
201 GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X, &buffer);
203 return (GSS_S_COMPLETE);
207 gsskrb5_set_dns_canonicalize(int flag)
209 gss_buffer_desc buffer;
211 char b = (flag != 0);
214 buffer.length = sizeof(b);
216 gss_set_sec_context_option(&junk, NULL,
217 GSS_KRB5_SET_DNS_CANONICALIZE_X, &buffer);
219 return (GSS_S_COMPLETE);
224 static krb5_error_code
225 set_key(krb5_keyblock *keyblock, gss_krb5_lucid_key_t *key)
227 key->type = keyblock->keytype;
228 key->length = keyblock->keyvalue.length;
229 key->data = malloc(key->length);
230 if (key->data == NULL && key->length != 0)
232 memcpy(key->data, keyblock->keyvalue.data, key->length);
237 free_key(gss_krb5_lucid_key_t *key)
239 memset(key->data, 0, key->length);
241 memset(key, 0, sizeof(*key));
245 gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status,
246 gss_ctx_id_t *context_handle,
250 krb5_context context = NULL;
252 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
253 OM_uint32 major_status;
254 gss_krb5_lucid_context_v1_t *ctx = NULL;
255 krb5_storage *sp = NULL;
258 if (context_handle == NULL
259 || *context_handle == GSS_C_NO_CONTEXT
263 return GSS_S_FAILURE;
267 gss_inquire_sec_context_by_oid (minor_status,
269 GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X,
274 if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
275 gss_release_buffer_set(minor_status, &data_set);
276 *minor_status = EINVAL;
277 return GSS_S_FAILURE;
280 ret = krb5_init_context(&context);
284 ctx = calloc(1, sizeof(*ctx));
290 sp = krb5_storage_from_mem(data_set->elements[0].value,
291 data_set->elements[0].length);
297 ret = krb5_ret_uint32(sp, &num);
305 ret = krb5_ret_uint32(sp, &ctx->initiate);
308 ret = krb5_ret_uint32(sp, &ctx->endtime);
311 ret = krb5_ret_uint32(sp, &num);
313 ctx->send_seq = ((uint64_t)num) << 32;
314 ret = krb5_ret_uint32(sp, &num);
316 ctx->send_seq |= num;
318 ret = krb5_ret_uint32(sp, &num);
320 ctx->recv_seq = ((uint64_t)num) << 32;
321 ret = krb5_ret_uint32(sp, &num);
323 ctx->recv_seq |= num;
325 ret = krb5_ret_uint32(sp, &ctx->protocol);
327 if (ctx->protocol == 0) {
331 ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.sign_alg);
334 ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.seal_alg);
337 ret = krb5_ret_keyblock(sp, &key);
339 ret = set_key(&key, &ctx->rfc1964_kd.ctx_key);
340 krb5_free_keyblock_contents(context, &key);
342 } else if (ctx->protocol == 1) {
345 /* acceptor_subkey */
346 ret = krb5_ret_uint32(sp, &ctx->cfx_kd.have_acceptor_subkey);
349 ret = krb5_ret_keyblock(sp, &key);
351 ret = set_key(&key, &ctx->cfx_kd.ctx_key);
352 krb5_free_keyblock_contents(context, &key);
354 /* acceptor_subkey */
355 if (ctx->cfx_kd.have_acceptor_subkey) {
356 ret = krb5_ret_keyblock(sp, &key);
358 ret = set_key(&key, &ctx->cfx_kd.acceptor_subkey);
359 krb5_free_keyblock_contents(context, &key);
370 gss_release_buffer_set(minor_status, &data_set);
372 krb5_storage_free(sp);
374 krb5_free_context(context);
378 gss_krb5_free_lucid_sec_context(NULL, ctx);
381 return GSS_S_FAILURE;
384 return GSS_S_COMPLETE;
388 gss_krb5_free_lucid_sec_context(OM_uint32 *minor_status, void *c)
390 gss_krb5_lucid_context_v1_t *ctx = c;
392 if (ctx->version != 1) {
395 return GSS_S_FAILURE;
398 if (ctx->protocol == 0) {
399 free_key(&ctx->rfc1964_kd.ctx_key);
400 } else if (ctx->protocol == 1) {
401 free_key(&ctx->cfx_kd.ctx_key);
402 if (ctx->cfx_kd.have_acceptor_subkey)
403 free_key(&ctx->cfx_kd.acceptor_subkey);
408 return GSS_S_COMPLETE;
416 gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status,
418 OM_uint32 num_enctypes,
422 OM_uint32 maj_status;
423 gss_buffer_desc buffer;
428 sp = krb5_storage_emem();
430 *minor_status = ENOMEM;
431 maj_status = GSS_S_FAILURE;
435 for (i = 0; i < num_enctypes; i++) {
436 ret = krb5_store_int32(sp, enctypes[i]);
439 maj_status = GSS_S_FAILURE;
444 ret = krb5_storage_to_data(sp, &data);
447 maj_status = GSS_S_FAILURE;
451 buffer.value = data.data;
452 buffer.length = data.length;
454 maj_status = gss_set_cred_option(minor_status,
456 GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X,
458 krb5_data_free(&data);
461 krb5_storage_free(sp);
470 gsskrb5_set_send_to_kdc(struct gsskrb5_send_to_kdc *c)
472 gss_buffer_desc buffer;
477 buffer.length = sizeof(*c);
483 gss_set_sec_context_option(&junk, NULL,
484 GSS_KRB5_SEND_TO_KDC_X, &buffer);
486 return (GSS_S_COMPLETE);
494 gss_krb5_ccache_name(OM_uint32 *minor_status,
496 const char **out_name)
498 gss_buffer_desc buffer;
504 buffer.value = rk_UNCONST(name);
505 buffer.length = strlen(name);
507 gss_set_sec_context_option(&junk, NULL,
508 GSS_KRB5_CCACHE_NAME_X, &buffer);
510 return (GSS_S_COMPLETE);
519 gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status,
520 gss_ctx_id_t context_handle,
523 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
526 if (context_handle == GSS_C_NO_CONTEXT) {
527 *minor_status = EINVAL;
528 return GSS_S_FAILURE;
532 gss_inquire_sec_context_by_oid (minor_status,
534 GSS_KRB5_GET_AUTHTIME_X,
539 if (data_set == GSS_C_NO_BUFFER_SET) {
540 gss_release_buffer_set(minor_status, &data_set);
541 *minor_status = EINVAL;
542 return GSS_S_FAILURE;
545 if (data_set->count != 1) {
546 gss_release_buffer_set(minor_status, &data_set);
547 *minor_status = EINVAL;
548 return GSS_S_FAILURE;
551 if (data_set->elements[0].length != 4) {
552 gss_release_buffer_set(minor_status, &data_set);
553 *minor_status = EINVAL;
554 return GSS_S_FAILURE;
558 unsigned char *buf = data_set->elements[0].value;
559 *authtime = (buf[3] <<24) | (buf[2] << 16) |
560 (buf[1] << 8) | (buf[0] << 0);
563 gss_release_buffer_set(minor_status, &data_set);
566 return GSS_S_COMPLETE;
574 gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
575 gss_ctx_id_t context_handle,
577 gss_buffer_t ad_data)
579 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
581 gss_OID_desc oid_flat;
582 heim_oid baseoid, oid;
585 if (context_handle == GSS_C_NO_CONTEXT) {
586 *minor_status = EINVAL;
587 return GSS_S_FAILURE;
590 /* All this to append an integer to an oid... */
592 if (der_get_oid(GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->elements,
593 GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->length,
594 &baseoid, NULL) != 0) {
595 *minor_status = EINVAL;
596 return GSS_S_FAILURE;
599 oid.length = baseoid.length + 1;
600 oid.components = calloc(oid.length, sizeof(*oid.components));
601 if (oid.components == NULL) {
602 der_free_oid(&baseoid);
604 *minor_status = ENOMEM;
605 return GSS_S_FAILURE;
608 memcpy(oid.components, baseoid.components,
609 baseoid.length * sizeof(*baseoid.components));
611 der_free_oid(&baseoid);
613 oid.components[oid.length - 1] = ad_type;
615 oid_flat.length = der_length_oid(&oid);
616 oid_flat.elements = malloc(oid_flat.length);
617 if (oid_flat.elements == NULL) {
618 free(oid.components);
619 *minor_status = ENOMEM;
620 return GSS_S_FAILURE;
623 if (der_put_oid((unsigned char *)oid_flat.elements + oid_flat.length - 1,
624 oid_flat.length, &oid, &size) != 0) {
625 free(oid.components);
626 free(oid_flat.elements);
627 *minor_status = EINVAL;
628 return GSS_S_FAILURE;
630 if (oid_flat.length != size)
633 free(oid.components);
635 /* FINALLY, we have the OID */
637 maj_stat = gss_inquire_sec_context_by_oid (minor_status,
642 free(oid_flat.elements);
647 if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
648 gss_release_buffer_set(minor_status, &data_set);
649 *minor_status = EINVAL;
650 return GSS_S_FAILURE;
653 ad_data->value = malloc(data_set->elements[0].length);
654 if (ad_data->value == NULL) {
655 gss_release_buffer_set(minor_status, &data_set);
656 *minor_status = ENOMEM;
657 return GSS_S_FAILURE;
660 ad_data->length = data_set->elements[0].length;
661 memcpy(ad_data->value, data_set->elements[0].value, ad_data->length);
662 gss_release_buffer_set(minor_status, &data_set);
665 return GSS_S_COMPLETE;
673 gsskrb5_extract_key(OM_uint32 *minor_status,
674 gss_ctx_id_t context_handle,
676 krb5_keyblock **keyblock)
679 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
680 OM_uint32 major_status;
681 krb5_context context = NULL;
682 krb5_storage *sp = NULL;
684 if (context_handle == GSS_C_NO_CONTEXT) {
686 return GSS_S_FAILURE;
689 ret = krb5_init_context(&context);
692 return GSS_S_FAILURE;
696 gss_inquire_sec_context_by_oid (minor_status,
703 if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
704 gss_release_buffer_set(minor_status, &data_set);
705 *minor_status = EINVAL;
706 return GSS_S_FAILURE;
709 sp = krb5_storage_from_mem(data_set->elements[0].value,
710 data_set->elements[0].length);
716 *keyblock = calloc(1, sizeof(**keyblock));
717 if (keyblock == NULL) {
722 ret = krb5_ret_keyblock(sp, *keyblock);
725 gss_release_buffer_set(minor_status, &data_set);
727 krb5_storage_free(sp);
728 if (ret && keyblock) {
729 krb5_free_keyblock(context, *keyblock);
733 krb5_free_context(context);
737 return GSS_S_FAILURE;
739 return GSS_S_COMPLETE;
747 gsskrb5_extract_service_keyblock(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_SERVICE_KEYBLOCK_X,
758 gsskrb5_get_initiator_subkey(OM_uint32 *minor_status,
759 gss_ctx_id_t context_handle,
760 krb5_keyblock **keyblock)
762 return gsskrb5_extract_key(minor_status,
764 GSS_KRB5_GET_INITIATOR_SUBKEY_X,
769 gsskrb5_get_subkey(OM_uint32 *minor_status,
770 gss_ctx_id_t context_handle,
771 krb5_keyblock **keyblock)
773 return gsskrb5_extract_key(minor_status,
775 GSS_KRB5_GET_SUBKEY_X,
780 gsskrb5_set_default_realm(const char *realm)
782 gss_buffer_desc buffer;
785 buffer.value = rk_UNCONST(realm);
786 buffer.length = strlen(realm);
788 gss_set_sec_context_option(&junk, NULL,
789 GSS_KRB5_SET_DEFAULT_REALM_X, &buffer);
791 return (GSS_S_COMPLETE);
795 gss_krb5_get_tkt_flags(OM_uint32 *minor_status,
796 gss_ctx_id_t context_handle,
797 OM_uint32 *tkt_flags)
800 OM_uint32 major_status;
801 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
803 if (context_handle == GSS_C_NO_CONTEXT) {
804 *minor_status = EINVAL;
805 return GSS_S_FAILURE;
809 gss_inquire_sec_context_by_oid (minor_status,
811 GSS_KRB5_GET_TKT_FLAGS_X,
816 if (data_set == GSS_C_NO_BUFFER_SET ||
817 data_set->count != 1 ||
818 data_set->elements[0].length < 4) {
819 gss_release_buffer_set(minor_status, &data_set);
820 *minor_status = EINVAL;
821 return GSS_S_FAILURE;
825 const u_char *p = data_set->elements[0].value;
826 *tkt_flags = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
829 gss_release_buffer_set(minor_status, &data_set);
830 return GSS_S_COMPLETE;