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.16 2006/11/07 14:41:35 lha Exp $");
34 #include "krb5/gsskrb5_locl.h"
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;
420 gsskrb5_set_send_to_kdc(struct gsskrb5_send_to_kdc *c)
422 struct _gss_mech_switch *m;
423 gss_buffer_desc buffer;
430 buffer.length = sizeof(*c);
436 SLIST_FOREACH(m, &_gss_mechs, gm_link) {
437 if (m->gm_mech.gm_set_sec_context_option == NULL)
439 m->gm_mech.gm_set_sec_context_option(&junk, NULL,
440 GSS_KRB5_SEND_TO_KDC_X, &buffer);
443 return (GSS_S_COMPLETE);
447 gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status,
448 gss_ctx_id_t context_handle,
451 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
456 if (context_handle == GSS_C_NO_CONTEXT) {
457 _gsskrb5_set_status("no context handle");
458 *minor_status = EINVAL;
459 return GSS_S_FAILURE;
463 gss_inquire_sec_context_by_oid (minor_status,
465 GSS_KRB5_GET_AUTHTIME_X,
470 if (data_set == GSS_C_NO_BUFFER_SET) {
471 _gsskrb5_set_status("no buffers returned");
472 gss_release_buffer_set(minor_status, &data_set);
473 *minor_status = EINVAL;
474 return GSS_S_FAILURE;
477 if (data_set->count != 1) {
478 _gsskrb5_set_status("%d != 1 buffers returned", data_set->count);
479 gss_release_buffer_set(minor_status, &data_set);
480 *minor_status = EINVAL;
481 return GSS_S_FAILURE;
484 if (data_set->elements[0].length != 4) {
485 gss_release_buffer_set(minor_status, &data_set);
486 _gsskrb5_set_status("Error extracting authtime from security context: only got %d < 4 bytes",
487 data_set->elements[0].length);
488 *minor_status = EINVAL;
489 return GSS_S_FAILURE;
492 ret = _gsskrb5_decode_om_uint32(data_set->elements[0].value, &time32);
494 gss_release_buffer_set(minor_status, &data_set);
496 return GSS_S_FAILURE;
500 gss_release_buffer_set(minor_status, &data_set);
503 return GSS_S_COMPLETE;
507 gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
508 gss_ctx_id_t context_handle,
510 gss_buffer_t ad_data)
512 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
514 gss_OID_desc oid_flat;
515 heim_oid baseoid, oid;
518 if (context_handle == GSS_C_NO_CONTEXT) {
519 *minor_status = EINVAL;
520 return GSS_S_FAILURE;
523 /* All this to append an integer to an oid... */
525 if (der_get_oid(GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->elements,
526 GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->length,
527 &baseoid, NULL) != 0) {
528 *minor_status = EINVAL;
529 return GSS_S_FAILURE;
532 oid.length = baseoid.length + 1;
533 oid.components = calloc(oid.length, sizeof(*oid.components));
534 if (oid.components == NULL) {
535 der_free_oid(&baseoid);
537 *minor_status = ENOMEM;
538 return GSS_S_FAILURE;
541 memcpy(oid.components, baseoid.components,
542 baseoid.length * sizeof(*baseoid.components));
544 der_free_oid(&baseoid);
546 oid.components[oid.length - 1] = ad_type;
548 oid_flat.length = der_length_oid(&oid);
549 oid_flat.elements = malloc(oid_flat.length);
550 if (oid_flat.elements == NULL) {
551 free(oid.components);
552 *minor_status = ENOMEM;
553 return GSS_S_FAILURE;
556 if (der_put_oid((unsigned char *)oid_flat.elements + oid_flat.length - 1,
557 oid_flat.length, &oid, &size) != 0) {
558 free(oid.components);
560 *minor_status = EINVAL;
561 return GSS_S_FAILURE;
563 if (oid_flat.length != size)
566 free(oid.components);
568 /* FINALLY, we have the OID */
570 maj_stat = gss_inquire_sec_context_by_oid (minor_status,
575 free(oid_flat.elements);
580 if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
581 gss_release_buffer_set(minor_status, &data_set);
582 *minor_status = EINVAL;
583 return GSS_S_FAILURE;
586 ad_data->value = malloc(data_set->elements[0].length);
587 if (ad_data->value == NULL) {
588 gss_release_buffer_set(minor_status, &data_set);
589 *minor_status = ENOMEM;
590 return GSS_S_FAILURE;
593 ad_data->length = data_set->elements[0].length;
594 memcpy(ad_data->value, data_set->elements[0].value, ad_data->length);
595 gss_release_buffer_set(minor_status, &data_set);
598 return GSS_S_COMPLETE;
602 gsskrb5_extract_key(OM_uint32 *minor_status,
603 gss_ctx_id_t context_handle,
605 krb5_keyblock **keyblock)
608 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
609 OM_uint32 major_status;
610 krb5_context context = NULL;
611 krb5_storage *sp = NULL;
613 if (context_handle == GSS_C_NO_CONTEXT) {
615 return GSS_S_FAILURE;
618 ret = krb5_init_context(&context);
621 return GSS_S_FAILURE;
625 gss_inquire_sec_context_by_oid (minor_status,
632 if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
633 gss_release_buffer_set(minor_status, &data_set);
634 *minor_status = EINVAL;
635 return GSS_S_FAILURE;
638 sp = krb5_storage_from_mem(data_set->elements[0].value,
639 data_set->elements[0].length);
645 *keyblock = calloc(1, sizeof(**keyblock));
646 if (keyblock == NULL) {
651 ret = krb5_ret_keyblock(sp, *keyblock);
654 gss_release_buffer_set(minor_status, &data_set);
656 krb5_storage_free(sp);
657 if (ret && keyblock) {
658 krb5_free_keyblock(context, *keyblock);
662 krb5_free_context(context);
666 return GSS_S_FAILURE;
668 return GSS_S_COMPLETE;
672 gsskrb5_extract_service_keyblock(OM_uint32 *minor_status,
673 gss_ctx_id_t context_handle,
674 krb5_keyblock **keyblock)
676 return gsskrb5_extract_key(minor_status,
678 GSS_KRB5_GET_SERVICE_KEYBLOCK_X,
683 gsskrb5_get_initiator_subkey(OM_uint32 *minor_status,
684 gss_ctx_id_t context_handle,
685 krb5_keyblock **keyblock)
687 return gsskrb5_extract_key(minor_status,
689 GSS_KRB5_GET_INITIATOR_SUBKEY_X,
694 gsskrb5_get_subkey(OM_uint32 *minor_status,
695 gss_ctx_id_t context_handle,
696 krb5_keyblock **keyblock)
698 return gsskrb5_extract_key(minor_status,
700 GSS_KRB5_GET_SUBKEY_X,