Path: blob/main/crypto/heimdal/lib/gssapi/krb5/acquire_cred.c
34923 views
/*1* Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan2* (Royal Institute of Technology, Stockholm, Sweden).3* All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8*9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11*12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* 3. Neither the name of the Institute nor the names of its contributors17* may be used to endorse or promote products derived from this software18* without specific prior written permission.19*20* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND21* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE23* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE24* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL25* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS26* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)27* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT28* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY29* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF30* SUCH DAMAGE.31*/3233#include "gsskrb5_locl.h"3435OM_uint3236__gsskrb5_ccache_lifetime(OM_uint32 *minor_status,37krb5_context context,38krb5_ccache id,39krb5_principal principal,40OM_uint32 *lifetime)41{42krb5_creds in_cred, out_cred;43krb5_const_realm realm;44krb5_error_code kret;4546memset(&in_cred, 0, sizeof(in_cred));47in_cred.client = principal;4849realm = krb5_principal_get_realm(context, principal);50if (realm == NULL) {51_gsskrb5_clear_status ();52*minor_status = KRB5_PRINC_NOMATCH; /* XXX */53return GSS_S_FAILURE;54}5556kret = krb5_make_principal(context, &in_cred.server,57realm, KRB5_TGS_NAME, realm, NULL);58if (kret) {59*minor_status = kret;60return GSS_S_FAILURE;61}6263kret = krb5_cc_retrieve_cred(context, id, 0, &in_cred, &out_cred);64krb5_free_principal(context, in_cred.server);65if (kret) {66*minor_status = 0;67*lifetime = 0;68return GSS_S_COMPLETE;69}7071*lifetime = out_cred.times.endtime;72krb5_free_cred_contents(context, &out_cred);7374return GSS_S_COMPLETE;75}7677787980static krb5_error_code81get_keytab(krb5_context context, krb5_keytab *keytab)82{83krb5_error_code kret;8485HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);8687if (_gsskrb5_keytab != NULL) {88char *name = NULL;8990kret = krb5_kt_get_full_name(context, _gsskrb5_keytab, &name);91if (kret == 0) {92kret = krb5_kt_resolve(context, name, keytab);93krb5_xfree(name);94}95} else96kret = krb5_kt_default(context, keytab);9798HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);99100return (kret);101}102103static OM_uint32 acquire_initiator_cred104(OM_uint32 * minor_status,105krb5_context context,106gss_const_OID credential_type,107const void *credential_data,108const gss_name_t desired_name,109OM_uint32 time_req,110gss_const_OID desired_mech,111gss_cred_usage_t cred_usage,112gsskrb5_cred handle113)114{115OM_uint32 ret;116krb5_creds cred;117krb5_principal def_princ;118krb5_get_init_creds_opt *opt;119krb5_ccache ccache;120krb5_keytab keytab;121krb5_error_code kret;122123keytab = NULL;124ccache = NULL;125def_princ = NULL;126ret = GSS_S_FAILURE;127memset(&cred, 0, sizeof(cred));128129/*130* If we have a preferred principal, lets try to find it in all131* caches, otherwise, fall back to default cache, ignore all132* errors while searching.133*/134135if (credential_type != GSS_C_NO_OID &&136!gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) {137kret = KRB5_NOCREDS_SUPPLIED; /* XXX */138goto end;139}140141if (handle->principal) {142kret = krb5_cc_cache_match (context,143handle->principal,144&ccache);145if (kret == 0) {146ret = GSS_S_COMPLETE;147goto found;148}149}150151if (ccache == NULL) {152kret = krb5_cc_default(context, &ccache);153if (kret)154goto end;155}156kret = krb5_cc_get_principal(context, ccache, &def_princ);157if (kret != 0) {158/* we'll try to use a keytab below */159krb5_cc_close(context, ccache);160def_princ = NULL;161kret = 0;162} else if (handle->principal == NULL) {163kret = krb5_copy_principal(context, def_princ, &handle->principal);164if (kret)165goto end;166} else if (handle->principal != NULL &&167krb5_principal_compare(context, handle->principal,168def_princ) == FALSE) {169krb5_free_principal(context, def_princ);170def_princ = NULL;171krb5_cc_close(context, ccache);172ccache = NULL;173}174if (def_princ == NULL) {175/* We have no existing credentials cache,176* so attempt to get a TGT using a keytab.177*/178if (handle->principal == NULL) {179kret = krb5_get_default_principal(context, &handle->principal);180if (kret)181goto end;182}183kret = krb5_get_init_creds_opt_alloc(context, &opt);184if (kret)185goto end;186if (credential_type != GSS_C_NO_OID &&187gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) {188gss_buffer_t password = (gss_buffer_t)credential_data;189190/* XXX are we requiring password to be NUL terminated? */191192kret = krb5_get_init_creds_password(context, &cred,193handle->principal,194password->value,195NULL, NULL, 0, NULL, opt);196} else {197kret = get_keytab(context, &keytab);198if (kret) {199krb5_get_init_creds_opt_free(context, opt);200goto end;201}202kret = krb5_get_init_creds_keytab(context, &cred,203handle->principal, keytab,2040, NULL, opt);205}206krb5_get_init_creds_opt_free(context, opt);207if (kret)208goto end;209kret = krb5_cc_new_unique(context, krb5_cc_type_memory,210NULL, &ccache);211if (kret)212goto end;213kret = krb5_cc_initialize(context, ccache, cred.client);214if (kret) {215krb5_cc_destroy(context, ccache);216goto end;217}218kret = krb5_cc_store_cred(context, ccache, &cred);219if (kret) {220krb5_cc_destroy(context, ccache);221goto end;222}223handle->lifetime = cred.times.endtime;224handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;225} else {226227ret = __gsskrb5_ccache_lifetime(minor_status,228context,229ccache,230handle->principal,231&handle->lifetime);232if (ret != GSS_S_COMPLETE) {233krb5_cc_close(context, ccache);234goto end;235}236kret = 0;237}238found:239handle->ccache = ccache;240ret = GSS_S_COMPLETE;241242end:243if (cred.client != NULL)244krb5_free_cred_contents(context, &cred);245if (def_princ != NULL)246krb5_free_principal(context, def_princ);247if (keytab != NULL)248krb5_kt_close(context, keytab);249if (ret != GSS_S_COMPLETE && kret != 0)250*minor_status = kret;251return (ret);252}253254static OM_uint32 acquire_acceptor_cred255(OM_uint32 * minor_status,256krb5_context context,257gss_const_OID credential_type,258const void *credential_data,259const gss_name_t desired_name,260OM_uint32 time_req,261gss_const_OID desired_mech,262gss_cred_usage_t cred_usage,263gsskrb5_cred handle264)265{266OM_uint32 ret;267krb5_error_code kret;268269ret = GSS_S_FAILURE;270271if (credential_type != GSS_C_NO_OID) {272kret = EINVAL;273goto end;274}275276kret = get_keytab(context, &handle->keytab);277if (kret)278goto end;279280/* check that the requested principal exists in the keytab */281if (handle->principal) {282krb5_keytab_entry entry;283284kret = krb5_kt_get_entry(context, handle->keytab,285handle->principal, 0, 0, &entry);286if (kret)287goto end;288krb5_kt_free_entry(context, &entry);289ret = GSS_S_COMPLETE;290} else {291/*292* Check if there is at least one entry in the keytab before293* declaring it as an useful keytab.294*/295krb5_keytab_entry tmp;296krb5_kt_cursor c;297298kret = krb5_kt_start_seq_get (context, handle->keytab, &c);299if (kret)300goto end;301if (krb5_kt_next_entry(context, handle->keytab, &tmp, &c) == 0) {302krb5_kt_free_entry(context, &tmp);303ret = GSS_S_COMPLETE; /* ok found one entry */304}305krb5_kt_end_seq_get (context, handle->keytab, &c);306}307end:308if (ret != GSS_S_COMPLETE) {309if (handle->keytab != NULL)310krb5_kt_close(context, handle->keytab);311if (kret != 0) {312*minor_status = kret;313}314}315return (ret);316}317318OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred319(OM_uint32 * minor_status,320const gss_name_t desired_name,321OM_uint32 time_req,322const gss_OID_set desired_mechs,323gss_cred_usage_t cred_usage,324gss_cred_id_t * output_cred_handle,325gss_OID_set * actual_mechs,326OM_uint32 * time_rec327)328{329OM_uint32 ret;330331if (desired_mechs) {332int present = 0;333334ret = gss_test_oid_set_member(minor_status, GSS_KRB5_MECHANISM,335desired_mechs, &present);336if (ret)337return ret;338if (!present) {339*minor_status = 0;340return GSS_S_BAD_MECH;341}342}343344ret = _gsskrb5_acquire_cred_ext(minor_status,345desired_name,346GSS_C_NO_OID,347NULL,348time_req,349GSS_KRB5_MECHANISM,350cred_usage,351output_cred_handle);352if (ret)353return ret;354355356ret = _gsskrb5_inquire_cred(minor_status, *output_cred_handle,357NULL, time_rec, NULL, actual_mechs);358if (ret) {359OM_uint32 tmp;360_gsskrb5_release_cred(&tmp, output_cred_handle);361}362363return ret;364}365366OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_ext367(OM_uint32 * minor_status,368const gss_name_t desired_name,369gss_const_OID credential_type,370const void *credential_data,371OM_uint32 time_req,372gss_const_OID desired_mech,373gss_cred_usage_t cred_usage,374gss_cred_id_t * output_cred_handle375)376{377krb5_context context;378gsskrb5_cred handle;379OM_uint32 ret;380381cred_usage &= GSS_C_OPTION_MASK;382383if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) {384*minor_status = GSS_KRB5_S_G_BAD_USAGE;385return GSS_S_FAILURE;386}387388GSSAPI_KRB5_INIT(&context);389390*output_cred_handle = NULL;391392handle = calloc(1, sizeof(*handle));393if (handle == NULL) {394*minor_status = ENOMEM;395return (GSS_S_FAILURE);396}397398HEIMDAL_MUTEX_init(&handle->cred_id_mutex);399400if (desired_name != GSS_C_NO_NAME) {401ret = _gsskrb5_canon_name(minor_status, context, 1, NULL,402desired_name, &handle->principal);403if (ret) {404HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);405free(handle);406return ret;407}408}409if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) {410ret = acquire_initiator_cred(minor_status, context,411credential_type, credential_data,412desired_name, time_req,413desired_mech, cred_usage, handle);414if (ret != GSS_S_COMPLETE) {415HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);416krb5_free_principal(context, handle->principal);417free(handle);418return (ret);419}420}421if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) {422ret = acquire_acceptor_cred(minor_status, context,423credential_type, credential_data,424desired_name, time_req,425desired_mech, cred_usage, handle);426if (ret != GSS_S_COMPLETE) {427HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);428krb5_free_principal(context, handle->principal);429free(handle);430return (ret);431}432}433ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms);434if (ret == GSS_S_COMPLETE)435ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,436&handle->mechanisms);437if (ret != GSS_S_COMPLETE) {438if (handle->mechanisms != NULL)439gss_release_oid_set(NULL, &handle->mechanisms);440HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);441krb5_free_principal(context, handle->principal);442free(handle);443return (ret);444}445handle->usage = cred_usage;446*minor_status = 0;447*output_cred_handle = (gss_cred_id_t)handle;448return (GSS_S_COMPLETE);449}450451452