Path: blob/main/kerberos5/lib/libgssapi_krb5/gss_krb5.c
39476 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2005 Doug Rabson4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*/2728#include <gssapi/gssapi.h>29#include <gssapi/gssapi_krb5.h>3031/* RCSID("$Id: gss_krb5.c 21889 2007-08-09 07:43:24Z lha $"); */3233#include <krb5.h>34#include <roken.h>35#include <der.h>3637OM_uint3238gss_krb5_copy_ccache(OM_uint32 *minor_status,39gss_cred_id_t cred,40krb5_ccache out)41{42gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;43krb5_context context;44krb5_error_code kret;45krb5_ccache id;46OM_uint32 ret;47char *str;4849ret = gss_inquire_cred_by_oid(minor_status,50cred,51GSS_KRB5_COPY_CCACHE_X,52&data_set);53if (ret)54return ret;5556if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {57gss_release_buffer_set(minor_status, &data_set);58*minor_status = EINVAL;59return GSS_S_FAILURE;60}6162kret = krb5_init_context(&context);63if (kret) {64*minor_status = kret;65gss_release_buffer_set(minor_status, &data_set);66return GSS_S_FAILURE;67}6869kret = asprintf(&str, "%.*s", (int)data_set->elements[0].length,70(char *)data_set->elements[0].value);71gss_release_buffer_set(minor_status, &data_set);72if (kret == -1) {73*minor_status = ENOMEM;74return GSS_S_FAILURE;75}7677kret = krb5_cc_resolve(context, str, &id);78free(str);79if (kret) {80*minor_status = kret;81return GSS_S_FAILURE;82}8384kret = krb5_cc_copy_cache(context, id, out);85krb5_cc_close(context, id);86krb5_free_context(context);87if (kret) {88*minor_status = kret;89return GSS_S_FAILURE;90}9192return ret;93}9495OM_uint3296gss_krb5_import_cred(OM_uint32 *minor_status,97krb5_ccache id,98krb5_principal keytab_principal,99krb5_keytab keytab,100gss_cred_id_t *cred)101{102gss_buffer_desc buffer;103OM_uint32 major_status;104krb5_context context;105krb5_error_code ret;106krb5_storage *sp;107krb5_data data;108char *str;109110*cred = GSS_C_NO_CREDENTIAL;111112ret = krb5_init_context(&context);113if (ret) {114*minor_status = ret;115return GSS_S_FAILURE;116}117118sp = krb5_storage_emem();119if (sp == NULL) {120*minor_status = ENOMEM;121major_status = GSS_S_FAILURE;122goto out;123}124125if (id) {126ret = krb5_cc_get_full_name(context, id, &str);127if (ret == 0) {128ret = krb5_store_string(sp, str);129free(str);130}131} else132ret = krb5_store_string(sp, "");133if (ret) {134*minor_status = ret;135major_status = GSS_S_FAILURE;136goto out;137}138139if (keytab_principal) {140ret = krb5_unparse_name(context, keytab_principal, &str);141if (ret == 0) {142ret = krb5_store_string(sp, str);143free(str);144}145} else146krb5_store_string(sp, "");147if (ret) {148*minor_status = ret;149major_status = GSS_S_FAILURE;150goto out;151}152153154if (keytab) {155ret = krb5_kt_get_full_name(context, keytab, &str);156if (ret == 0) {157ret = krb5_store_string(sp, str);158free(str);159}160} else161krb5_store_string(sp, "");162if (ret) {163*minor_status = ret;164major_status = GSS_S_FAILURE;165goto out;166}167168ret = krb5_storage_to_data(sp, &data);169if (ret) {170*minor_status = ret;171major_status = GSS_S_FAILURE;172goto out;173}174175buffer.value = data.data;176buffer.length = data.length;177178major_status = gss_set_cred_option(minor_status,179cred,180GSS_KRB5_IMPORT_CRED_X,181&buffer);182krb5_data_free(&data);183out:184if (sp)185krb5_storage_free(sp);186krb5_free_context(context);187return major_status;188}189190OM_uint32191gsskrb5_register_acceptor_identity(const char *identity)192{193gss_buffer_desc buffer;194OM_uint32 junk;195196buffer.value = rk_UNCONST(identity);197buffer.length = strlen(identity);198199gss_set_sec_context_option(&junk, NULL,200GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X, &buffer);201202return (GSS_S_COMPLETE);203}204205OM_uint32206gsskrb5_set_dns_canonicalize(int flag)207{208gss_buffer_desc buffer;209OM_uint32 junk;210char b = (flag != 0);211212buffer.value = &b;213buffer.length = sizeof(b);214215gss_set_sec_context_option(&junk, NULL,216GSS_KRB5_SET_DNS_CANONICALIZE_X, &buffer);217218return (GSS_S_COMPLETE);219}220221222223static krb5_error_code224set_key(krb5_keyblock *keyblock, gss_krb5_lucid_key_t *key)225{226key->type = keyblock->keytype;227key->length = keyblock->keyvalue.length;228key->data = malloc(key->length);229if (key->data == NULL && key->length != 0)230return ENOMEM;231memcpy(key->data, keyblock->keyvalue.data, key->length);232return 0;233}234235static void236free_key(gss_krb5_lucid_key_t *key)237{238memset(key->data, 0, key->length);239free(key->data);240memset(key, 0, sizeof(*key));241}242243OM_uint32244gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status,245gss_ctx_id_t *context_handle,246OM_uint32 version,247void **rctx)248{249krb5_context context = NULL;250krb5_error_code ret;251gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;252OM_uint32 major_status;253gss_krb5_lucid_context_v1_t *ctx = NULL;254krb5_storage *sp = NULL;255uint32_t num;256257if (context_handle == NULL258|| *context_handle == GSS_C_NO_CONTEXT259|| version != 1)260{261ret = EINVAL;262return GSS_S_FAILURE;263}264265major_status =266gss_inquire_sec_context_by_oid (minor_status,267*context_handle,268GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X,269&data_set);270if (major_status)271return major_status;272273if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {274gss_release_buffer_set(minor_status, &data_set);275*minor_status = EINVAL;276return GSS_S_FAILURE;277}278279ret = krb5_init_context(&context);280if (ret)281goto out;282283ctx = calloc(1, sizeof(*ctx));284if (ctx == NULL) {285ret = ENOMEM;286goto out;287}288289sp = krb5_storage_from_mem(data_set->elements[0].value,290data_set->elements[0].length);291if (sp == NULL) {292ret = ENOMEM;293goto out;294}295296ret = krb5_ret_uint32(sp, &num);297if (ret) goto out;298if (num != 1) {299ret = EINVAL;300goto out;301}302ctx->version = 1;303/* initiator */304ret = krb5_ret_uint32(sp, &ctx->initiate);305if (ret) goto out;306/* endtime */307ret = krb5_ret_uint32(sp, &ctx->endtime);308if (ret) goto out;309/* send_seq */310ret = krb5_ret_uint32(sp, &num);311if (ret) goto out;312ctx->send_seq = ((uint64_t)num) << 32;313ret = krb5_ret_uint32(sp, &num);314if (ret) goto out;315ctx->send_seq |= num;316/* recv_seq */317ret = krb5_ret_uint32(sp, &num);318if (ret) goto out;319ctx->recv_seq = ((uint64_t)num) << 32;320ret = krb5_ret_uint32(sp, &num);321if (ret) goto out;322ctx->recv_seq |= num;323/* protocol */324ret = krb5_ret_uint32(sp, &ctx->protocol);325if (ret) goto out;326if (ctx->protocol == 0) {327krb5_keyblock key;328329/* sign_alg */330ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.sign_alg);331if (ret) goto out;332/* seal_alg */333ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.seal_alg);334if (ret) goto out;335/* ctx_key */336ret = krb5_ret_keyblock(sp, &key);337if (ret) goto out;338ret = set_key(&key, &ctx->rfc1964_kd.ctx_key);339krb5_free_keyblock_contents(context, &key);340if (ret) goto out;341} else if (ctx->protocol == 1) {342krb5_keyblock key;343344/* acceptor_subkey */345ret = krb5_ret_uint32(sp, &ctx->cfx_kd.have_acceptor_subkey);346if (ret) goto out;347/* ctx_key */348ret = krb5_ret_keyblock(sp, &key);349if (ret) goto out;350ret = set_key(&key, &ctx->cfx_kd.ctx_key);351krb5_free_keyblock_contents(context, &key);352if (ret) goto out;353/* acceptor_subkey */354if (ctx->cfx_kd.have_acceptor_subkey) {355ret = krb5_ret_keyblock(sp, &key);356if (ret) goto out;357ret = set_key(&key, &ctx->cfx_kd.acceptor_subkey);358krb5_free_keyblock_contents(context, &key);359if (ret) goto out;360}361} else {362ret = EINVAL;363goto out;364}365366*rctx = ctx;367368out:369gss_release_buffer_set(minor_status, &data_set);370if (sp)371krb5_storage_free(sp);372if (context)373krb5_free_context(context);374375if (ret) {376if (ctx)377gss_krb5_free_lucid_sec_context(NULL, ctx);378379*minor_status = ret;380return GSS_S_FAILURE;381}382*minor_status = 0;383return GSS_S_COMPLETE;384}385386OM_uint32387gss_krb5_free_lucid_sec_context(OM_uint32 *minor_status, void *c)388{389gss_krb5_lucid_context_v1_t *ctx = c;390391if (ctx->version != 1) {392if (minor_status)393*minor_status = 0;394return GSS_S_FAILURE;395}396397if (ctx->protocol == 0) {398free_key(&ctx->rfc1964_kd.ctx_key);399} else if (ctx->protocol == 1) {400free_key(&ctx->cfx_kd.ctx_key);401if (ctx->cfx_kd.have_acceptor_subkey)402free_key(&ctx->cfx_kd.acceptor_subkey);403}404free(ctx);405if (minor_status)406*minor_status = 0;407return GSS_S_COMPLETE;408}409410/*411*412*/413414OM_uint32415gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status,416gss_cred_id_t cred,417OM_uint32 num_enctypes,418int32_t *enctypes)419{420krb5_error_code ret;421OM_uint32 maj_status;422gss_buffer_desc buffer;423krb5_storage *sp;424krb5_data data;425int i;426427sp = krb5_storage_emem();428if (sp == NULL) {429*minor_status = ENOMEM;430maj_status = GSS_S_FAILURE;431goto out;432}433434for (i = 0; i < num_enctypes; i++) {435ret = krb5_store_int32(sp, enctypes[i]);436if (ret) {437*minor_status = ret;438maj_status = GSS_S_FAILURE;439goto out;440}441}442443ret = krb5_storage_to_data(sp, &data);444if (ret) {445*minor_status = ret;446maj_status = GSS_S_FAILURE;447goto out;448}449450buffer.value = data.data;451buffer.length = data.length;452453maj_status = gss_set_cred_option(minor_status,454&cred,455GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X,456&buffer);457krb5_data_free(&data);458out:459if (sp)460krb5_storage_free(sp);461return maj_status;462}463464/*465*466*/467468OM_uint32469gsskrb5_set_send_to_kdc(struct gsskrb5_send_to_kdc *c)470{471gss_buffer_desc buffer;472OM_uint32 junk;473474if (c) {475buffer.value = c;476buffer.length = sizeof(*c);477} else {478buffer.value = NULL;479buffer.length = 0;480}481482gss_set_sec_context_option(&junk, NULL,483GSS_KRB5_SEND_TO_KDC_X, &buffer);484485return (GSS_S_COMPLETE);486}487488/*489*490*/491492OM_uint32493gss_krb5_ccache_name(OM_uint32 *minor_status,494const char *name,495const char **out_name)496{497gss_buffer_desc buffer;498OM_uint32 junk;499500if (out_name)501*out_name = NULL;502503buffer.value = rk_UNCONST(name);504buffer.length = strlen(name);505506gss_set_sec_context_option(&junk, NULL,507GSS_KRB5_CCACHE_NAME_X, &buffer);508509return (GSS_S_COMPLETE);510}511512513/*514*515*/516517OM_uint32518gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status,519gss_ctx_id_t context_handle,520time_t *authtime)521{522gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;523OM_uint32 maj_stat;524525if (context_handle == GSS_C_NO_CONTEXT) {526*minor_status = EINVAL;527return GSS_S_FAILURE;528}529530maj_stat =531gss_inquire_sec_context_by_oid (minor_status,532context_handle,533GSS_KRB5_GET_AUTHTIME_X,534&data_set);535if (maj_stat)536return maj_stat;537538if (data_set == GSS_C_NO_BUFFER_SET) {539gss_release_buffer_set(minor_status, &data_set);540*minor_status = EINVAL;541return GSS_S_FAILURE;542}543544if (data_set->count != 1) {545gss_release_buffer_set(minor_status, &data_set);546*minor_status = EINVAL;547return GSS_S_FAILURE;548}549550if (data_set->elements[0].length != 4) {551gss_release_buffer_set(minor_status, &data_set);552*minor_status = EINVAL;553return GSS_S_FAILURE;554}555556{557unsigned char *buf = data_set->elements[0].value;558*authtime = (buf[3] <<24) | (buf[2] << 16) |559(buf[1] << 8) | (buf[0] << 0);560}561562gss_release_buffer_set(minor_status, &data_set);563564*minor_status = 0;565return GSS_S_COMPLETE;566}567568/*569*570*/571572OM_uint32573gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status,574gss_ctx_id_t context_handle,575int ad_type,576gss_buffer_t ad_data)577{578gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;579OM_uint32 maj_stat;580gss_OID_desc oid_flat;581heim_oid baseoid, oid;582size_t size;583584if (context_handle == GSS_C_NO_CONTEXT) {585*minor_status = EINVAL;586return GSS_S_FAILURE;587}588589/* All this to append an integer to an oid... */590591if (der_get_oid(GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->elements,592GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->length,593&baseoid, NULL) != 0) {594*minor_status = EINVAL;595return GSS_S_FAILURE;596}597598oid.length = baseoid.length + 1;599oid.components = calloc(oid.length, sizeof(*oid.components));600if (oid.components == NULL) {601der_free_oid(&baseoid);602603*minor_status = ENOMEM;604return GSS_S_FAILURE;605}606607memcpy(oid.components, baseoid.components,608baseoid.length * sizeof(*baseoid.components));609610der_free_oid(&baseoid);611612oid.components[oid.length - 1] = ad_type;613614oid_flat.length = der_length_oid(&oid);615oid_flat.elements = malloc(oid_flat.length);616if (oid_flat.elements == NULL) {617free(oid.components);618*minor_status = ENOMEM;619return GSS_S_FAILURE;620}621622if (der_put_oid((unsigned char *)oid_flat.elements + oid_flat.length - 1,623oid_flat.length, &oid, &size) != 0) {624free(oid.components);625free(oid_flat.elements);626*minor_status = EINVAL;627return GSS_S_FAILURE;628}629if (oid_flat.length != size)630abort();631632free(oid.components);633634/* FINALLY, we have the OID */635636maj_stat = gss_inquire_sec_context_by_oid (minor_status,637context_handle,638&oid_flat,639&data_set);640641free(oid_flat.elements);642643if (maj_stat)644return maj_stat;645646if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {647gss_release_buffer_set(minor_status, &data_set);648*minor_status = EINVAL;649return GSS_S_FAILURE;650}651652ad_data->value = malloc(data_set->elements[0].length);653if (ad_data->value == NULL) {654gss_release_buffer_set(minor_status, &data_set);655*minor_status = ENOMEM;656return GSS_S_FAILURE;657}658659ad_data->length = data_set->elements[0].length;660memcpy(ad_data->value, data_set->elements[0].value, ad_data->length);661gss_release_buffer_set(minor_status, &data_set);662663*minor_status = 0;664return GSS_S_COMPLETE;665}666667/*668*669*/670671static OM_uint32672gsskrb5_extract_key(OM_uint32 *minor_status,673gss_ctx_id_t context_handle,674const gss_OID oid,675krb5_keyblock **keyblock)676{677krb5_error_code ret;678gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;679OM_uint32 major_status;680krb5_context context = NULL;681krb5_storage *sp = NULL;682683if (context_handle == GSS_C_NO_CONTEXT) {684ret = EINVAL;685return GSS_S_FAILURE;686}687688ret = krb5_init_context(&context);689if(ret) {690*minor_status = ret;691return GSS_S_FAILURE;692}693694major_status =695gss_inquire_sec_context_by_oid (minor_status,696context_handle,697oid,698&data_set);699if (major_status)700return major_status;701702if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {703gss_release_buffer_set(minor_status, &data_set);704*minor_status = EINVAL;705return GSS_S_FAILURE;706}707708sp = krb5_storage_from_mem(data_set->elements[0].value,709data_set->elements[0].length);710if (sp == NULL) {711ret = ENOMEM;712goto out;713}714715*keyblock = calloc(1, sizeof(**keyblock));716if (keyblock == NULL) {717ret = ENOMEM;718goto out;719}720721ret = krb5_ret_keyblock(sp, *keyblock);722723out:724gss_release_buffer_set(minor_status, &data_set);725if (sp)726krb5_storage_free(sp);727if (ret && keyblock) {728krb5_free_keyblock(context, *keyblock);729*keyblock = NULL;730}731if (context)732krb5_free_context(context);733734*minor_status = ret;735if (ret)736return GSS_S_FAILURE;737738return GSS_S_COMPLETE;739}740741/*742*743*/744745OM_uint32746gsskrb5_extract_service_keyblock(OM_uint32 *minor_status,747gss_ctx_id_t context_handle,748krb5_keyblock **keyblock)749{750return gsskrb5_extract_key(minor_status,751context_handle,752GSS_KRB5_GET_SERVICE_KEYBLOCK_X,753keyblock);754}755756OM_uint32757gsskrb5_get_initiator_subkey(OM_uint32 *minor_status,758gss_ctx_id_t context_handle,759krb5_keyblock **keyblock)760{761return gsskrb5_extract_key(minor_status,762context_handle,763GSS_KRB5_GET_INITIATOR_SUBKEY_X,764keyblock);765}766767OM_uint32768gsskrb5_get_subkey(OM_uint32 *minor_status,769gss_ctx_id_t context_handle,770krb5_keyblock **keyblock)771{772return gsskrb5_extract_key(minor_status,773context_handle,774GSS_KRB5_GET_SUBKEY_X,775keyblock);776}777778OM_uint32779gsskrb5_set_default_realm(const char *realm)780{781gss_buffer_desc buffer;782OM_uint32 junk;783784buffer.value = rk_UNCONST(realm);785buffer.length = strlen(realm);786787gss_set_sec_context_option(&junk, NULL,788GSS_KRB5_SET_DEFAULT_REALM_X, &buffer);789790return (GSS_S_COMPLETE);791}792793OM_uint32794gss_krb5_get_tkt_flags(OM_uint32 *minor_status,795gss_ctx_id_t context_handle,796OM_uint32 *tkt_flags)797{798799OM_uint32 major_status;800gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;801802if (context_handle == GSS_C_NO_CONTEXT) {803*minor_status = EINVAL;804return GSS_S_FAILURE;805}806807major_status =808gss_inquire_sec_context_by_oid (minor_status,809context_handle,810GSS_KRB5_GET_TKT_FLAGS_X,811&data_set);812if (major_status)813return major_status;814815if (data_set == GSS_C_NO_BUFFER_SET ||816data_set->count != 1 ||817data_set->elements[0].length < 4) {818gss_release_buffer_set(minor_status, &data_set);819*minor_status = EINVAL;820return GSS_S_FAILURE;821}822823{824const u_char *p = data_set->elements[0].value;825*tkt_flags = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);826}827828gss_release_buffer_set(minor_status, &data_set);829return GSS_S_COMPLETE;830}831832833834