Path: blob/main/crypto/krb5/src/lib/gssapi/mechglue/g_acquire_cred.c
39586 views
/* #pragma ident "@(#)g_acquire_cred.c 1.22 04/02/23 SMI" */12/*3* Copyright 1996 by Sun Microsystems, Inc.4*5* Permission to use, copy, modify, distribute, and sell this software6* and its documentation for any purpose is hereby granted without fee,7* provided that the above copyright notice appears in all copies and8* that both that copyright notice and this permission notice appear in9* supporting documentation, and that the name of Sun Microsystems not be used10* in advertising or publicity pertaining to distribution of the software11* without specific, written prior permission. Sun Microsystems makes no12* representations about the suitability of this software for any13* purpose. It is provided "as is" without express or implied warranty.14*15* SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,16* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO17* EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR18* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF19* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR20* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR21* PERFORMANCE OF THIS SOFTWARE.22*/2324/*25* glue routine for gss_acquire_cred26*/2728#include "mglueP.h"29#include <stdio.h>30#ifdef HAVE_STDLIB_H31#include <stdlib.h>32#endif33#include <string.h>34#include <errno.h>35#include <time.h>3637static OM_uint3238val_acq_cred_args(39OM_uint32 *minor_status,40gss_name_t desired_name,41OM_uint32 time_req,42gss_OID_set desired_mechs,43int cred_usage,44gss_const_key_value_set_t cred_store,45gss_cred_id_t *output_cred_handle,46gss_OID_set *actual_mechs,47OM_uint32 *time_rec)48{4950/* Initialize outputs. */5152if (minor_status != NULL)53*minor_status = 0;5455if (output_cred_handle != NULL)56*output_cred_handle = GSS_C_NO_CREDENTIAL;5758if (actual_mechs != NULL)59*actual_mechs = GSS_C_NULL_OID_SET;6061if (time_rec != NULL)62*time_rec = 0;6364/* Validate arguments. */6566if (minor_status == NULL)67return (GSS_S_CALL_INACCESSIBLE_WRITE);6869if (output_cred_handle == NULL)70return (GSS_S_CALL_INACCESSIBLE_WRITE);7172if (cred_usage != GSS_C_ACCEPT73&& cred_usage != GSS_C_INITIATE74&& cred_usage != GSS_C_BOTH) {75if (minor_status) {76*minor_status = EINVAL;77map_errcode(minor_status);78}79return GSS_S_FAILURE;80}8182return (GSS_S_COMPLETE);83}848586OM_uint32 KRB5_CALLCONV87gss_acquire_cred(OM_uint32 *minor_status, gss_name_t desired_name,88OM_uint32 time_req, gss_OID_set desired_mechs,89int cred_usage, gss_cred_id_t *output_cred_handle,90gss_OID_set *actual_mechs, OM_uint32 *time_rec)91{92return gss_acquire_cred_from(minor_status, desired_name, time_req,93desired_mechs, cred_usage, NULL,94output_cred_handle, actual_mechs, time_rec);95}9697OM_uint32 KRB5_CALLCONV98gss_acquire_cred_from(OM_uint32 * minor_status, gss_name_t desired_name,99OM_uint32 time_req, gss_OID_set desired_mechs,100int cred_usage, gss_const_key_value_set_t cred_store,101gss_cred_id_t *output_cred_handle,102gss_OID_set *actual_mechs, OM_uint32 *time_rec)103{104OM_uint32 major = GSS_S_FAILURE, tmpMinor;105OM_uint32 first_major = GSS_S_COMPLETE, first_minor = 0;106OM_uint32 initTimeOut = 0, acceptTimeOut = 0, outTime = GSS_C_INDEFINITE;107gss_OID_set mechs = GSS_C_NO_OID_SET;108gss_OID_set_desc except_attrs;109gss_OID_desc attr_oids[2];110unsigned int i;111gss_union_cred_t creds = NULL;112113major = val_acq_cred_args(minor_status,114desired_name,115time_req,116desired_mechs,117cred_usage,118cred_store,119output_cred_handle,120actual_mechs,121time_rec);122if (major != GSS_S_COMPLETE)123goto cleanup;124125/*126* if desired_mechs equals GSS_C_NULL_OID_SET, then try to127* acquire credentials for all non-deprecated mechanisms.128*/129if (desired_mechs == GSS_C_NULL_OID_SET) {130attr_oids[0] = *GSS_C_MA_DEPRECATED;131attr_oids[1] = *GSS_C_MA_NOT_DFLT_MECH;132except_attrs.count = 2;133except_attrs.elements = attr_oids;134major = gss_indicate_mechs_by_attrs(minor_status, GSS_C_NO_OID_SET,135&except_attrs, GSS_C_NO_OID_SET,136&mechs);137if (major != GSS_S_COMPLETE)138goto cleanup;139} else140mechs = desired_mechs;141142if (mechs->count == 0) {143major = GSS_S_BAD_MECH;144goto cleanup;145}146147/* allocate the output credential structure */148creds = (gss_union_cred_t)calloc(1, sizeof (gss_union_cred_desc));149if (creds == NULL) {150major = GSS_S_FAILURE;151*minor_status = ENOMEM;152goto cleanup;153}154155creds->count = 0;156creds->loopback = creds;157158/* for each requested mech attempt to obtain a credential */159for (i = 0, major = GSS_S_UNAVAILABLE; i < mechs->count; i++) {160major = gss_add_cred_from(&tmpMinor, (gss_cred_id_t)creds,161desired_name, &mechs->elements[i],162cred_usage, time_req, time_req,163cred_store, NULL, NULL,164time_rec ? &initTimeOut : NULL,165time_rec ? &acceptTimeOut : NULL);166if (major == GSS_S_COMPLETE) {167/* update the credential's time */168if (cred_usage == GSS_C_ACCEPT) {169if (outTime > acceptTimeOut)170outTime = acceptTimeOut;171} else if (cred_usage == GSS_C_INITIATE) {172if (outTime > initTimeOut)173outTime = initTimeOut;174} else {175/*176* time_rec is the lesser of the177* init/accept times178*/179if (initTimeOut > acceptTimeOut)180outTime = (outTime > acceptTimeOut) ?181acceptTimeOut : outTime;182else183outTime = (outTime > initTimeOut) ?184initTimeOut : outTime;185}186} else if (first_major == GSS_S_COMPLETE) {187first_major = major;188first_minor = tmpMinor;189}190} /* for */191192/* If we didn't get any creds, return the error status from the first mech193* (which is often the preferred one). */194if (creds->count < 1) {195major = first_major;196*minor_status = first_minor;197goto cleanup;198}199major = GSS_S_COMPLETE;200201/*202* fill in output parameters203* setup the actual mechs output parameter204*/205if (actual_mechs != NULL) {206major = gssint_make_public_oid_set(minor_status, creds->mechs_array,207creds->count, actual_mechs);208if (GSS_ERROR(major))209goto cleanup;210}211212if (time_rec)213*time_rec = outTime;214215*output_cred_handle = (gss_cred_id_t)creds;216217cleanup:218if (GSS_ERROR(major))219gss_release_cred(&tmpMinor, (gss_cred_id_t *)&creds);220if (desired_mechs == GSS_C_NO_OID_SET)221generic_gss_release_oid_set(&tmpMinor, &mechs);222223return (major);224}225226static OM_uint32227val_add_cred_args(228OM_uint32 *minor_status,229gss_cred_id_t input_cred_handle,230gss_name_t desired_name,231gss_OID desired_mech,232gss_cred_usage_t cred_usage,233gss_const_key_value_set_t cred_store,234OM_uint32 initiator_time_req,235OM_uint32 acceptor_time_req,236gss_cred_id_t *output_cred_handle,237gss_OID_set *actual_mechs,238OM_uint32 *initiator_time_rec,239OM_uint32 *acceptor_time_rec)240{241242/* Initialize outputs. */243244if (minor_status != NULL)245*minor_status = 0;246247if (output_cred_handle != NULL)248*output_cred_handle = GSS_C_NO_CREDENTIAL;249250if (actual_mechs != NULL)251*actual_mechs = GSS_C_NO_OID_SET;252253if (acceptor_time_rec != NULL)254*acceptor_time_rec = 0;255256if (initiator_time_rec != NULL)257*initiator_time_rec = 0;258259/* Validate arguments. */260261if (minor_status == NULL)262return (GSS_S_CALL_INACCESSIBLE_WRITE);263264if (input_cred_handle == GSS_C_NO_CREDENTIAL &&265output_cred_handle == NULL)266return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);267268if (cred_usage != GSS_C_ACCEPT269&& cred_usage != GSS_C_INITIATE270&& cred_usage != GSS_C_BOTH) {271if (minor_status) {272*minor_status = EINVAL;273map_errcode(minor_status);274}275return GSS_S_FAILURE;276}277278return (GSS_S_COMPLETE);279}280281/* Copy a mechanism credential (with the mechanism given by mech_oid) as282* faithfully as possible. */283static OM_uint32284copy_mech_cred(OM_uint32 *minor_status, gss_cred_id_t cred_in,285gss_OID mech_oid, gss_cred_id_t *cred_out)286{287OM_uint32 status, tmpmin;288gss_mechanism mech;289gss_buffer_desc buf;290gss_name_t name;291OM_uint32 life;292gss_cred_usage_t usage;293gss_OID_set_desc oidset;294295mech = gssint_get_mechanism(mech_oid);296if (mech == NULL)297return (GSS_S_BAD_MECH);298if (mech->gss_export_cred != NULL && mech->gss_import_cred != NULL) {299status = mech->gss_export_cred(minor_status, cred_in, &buf);300if (status != GSS_S_COMPLETE)301return (status);302status = mech->gss_import_cred(minor_status, &buf, cred_out);303(void) gss_release_buffer(&tmpmin, &buf);304} else if (mech->gss_inquire_cred != NULL &&305mech->gss_acquire_cred != NULL) {306status = mech->gss_inquire_cred(minor_status, cred_in, &name, &life,307&usage, NULL);308if (status != GSS_S_COMPLETE)309return (status);310oidset.count = 1;311oidset.elements = gssint_get_public_oid(mech_oid);312status = mech->gss_acquire_cred(minor_status, name, life, &oidset,313usage, cred_out, NULL, NULL);314gss_release_name(&tmpmin, &name);315} else {316status = GSS_S_UNAVAILABLE;317}318return (status);319}320321/* Copy a union credential from cred_in to *cred_out. */322static OM_uint32323copy_union_cred(OM_uint32 *minor_status, gss_cred_id_t cred_in,324gss_union_cred_t *cred_out)325{326OM_uint32 status, tmpmin;327gss_union_cred_t cred = (gss_union_cred_t)cred_in;328gss_union_cred_t ncred = NULL;329gss_cred_id_t tmpcred;330int i;331332ncred = calloc(1, sizeof (*ncred));333if (ncred == NULL)334goto oom;335ncred->mechs_array = calloc(cred->count, sizeof (*ncred->mechs_array));336ncred->cred_array = calloc(cred->count, sizeof (*ncred->cred_array));337if (ncred->mechs_array == NULL || ncred->cred_array == NULL)338goto oom;339ncred->count = cred->count;340341for (i = 0; i < cred->count; i++) {342/* Copy this element's mechanism OID. */343ncred->mechs_array[i].elements = malloc(cred->mechs_array[i].length);344if (ncred->mechs_array[i].elements == NULL)345goto oom;346g_OID_copy(&ncred->mechs_array[i], &cred->mechs_array[i]);347348/* Copy this element's mechanism cred. */349status = copy_mech_cred(minor_status, cred->cred_array[i],350&cred->mechs_array[i], &ncred->cred_array[i]);351if (status != GSS_S_COMPLETE)352goto error;353}354355ncred->loopback = ncred;356*cred_out = ncred;357return GSS_S_COMPLETE;358359oom:360status = GSS_S_FAILURE;361*minor_status = ENOMEM;362error:363tmpcred = (gss_cred_id_t)ncred;364(void) gss_release_cred(&tmpmin, &tmpcred);365return status;366}367368/* V2 KRB5_CALLCONV */369OM_uint32 KRB5_CALLCONV370gss_add_cred(OM_uint32 *minor_status, gss_cred_id_t input_cred_handle,371gss_name_t desired_name, gss_OID desired_mech,372gss_cred_usage_t cred_usage, OM_uint32 initiator_time_req,373OM_uint32 acceptor_time_req, gss_cred_id_t *output_cred_handle,374gss_OID_set *actual_mechs, OM_uint32 *initiator_time_rec,375OM_uint32 *acceptor_time_rec)376{377return gss_add_cred_from(minor_status, input_cred_handle, desired_name,378desired_mech, cred_usage, initiator_time_req,379acceptor_time_req, NULL, output_cred_handle,380actual_mechs, initiator_time_rec,381acceptor_time_rec);382}383384OM_uint32 KRB5_CALLCONV385gss_add_cred_from(OM_uint32 *minor_status, gss_cred_id_t input_cred_handle,386gss_name_t desired_name, gss_OID desired_mech,387gss_cred_usage_t cred_usage, OM_uint32 initiator_time_req,388OM_uint32 acceptor_time_req,389gss_const_key_value_set_t cred_store,390gss_cred_id_t *output_cred_handle, gss_OID_set *actual_mechs,391OM_uint32 *initiator_time_rec, OM_uint32 *acceptor_time_rec)392{393OM_uint32 status, temp_minor_status;394OM_uint32 time_req, time_rec = 0, *time_recp = NULL;395gss_union_name_t union_name;396gss_union_cred_t union_cred;397gss_name_t internal_name = GSS_C_NO_NAME;398gss_name_t allocated_name = GSS_C_NO_NAME;399gss_mechanism mech;400gss_cred_id_t cred = NULL, tmpcred;401void *newptr, *oidbuf = NULL;402gss_OID_set_desc target_mechs;403gss_OID selected_mech = GSS_C_NO_OID;404405status = val_add_cred_args(minor_status,406input_cred_handle,407desired_name,408desired_mech,409cred_usage,410cred_store,411initiator_time_req,412acceptor_time_req,413output_cred_handle,414actual_mechs,415initiator_time_rec,416acceptor_time_rec);417if (status != GSS_S_COMPLETE)418return (status);419420status = gssint_select_mech_type(minor_status, desired_mech,421&selected_mech);422if (status != GSS_S_COMPLETE)423return (status);424425mech = gssint_get_mechanism(selected_mech);426if (!mech)427return GSS_S_BAD_MECH;428else if (!mech->gss_acquire_cred)429return (GSS_S_UNAVAILABLE);430431union_cred = (gss_union_cred_t)input_cred_handle;432if (union_cred != NULL &&433gssint_get_mechanism_cred(union_cred,434selected_mech) != GSS_C_NO_CREDENTIAL)435return (GSS_S_DUPLICATE_ELEMENT);436437if (union_cred == NULL) {438/* Create a new credential handle. */439union_cred = malloc(sizeof (gss_union_cred_desc));440if (union_cred == NULL)441return (GSS_S_FAILURE);442443(void) memset(union_cred, 0, sizeof (gss_union_cred_desc));444union_cred->loopback = union_cred;445} else if (output_cred_handle != NULL) {446/* Create a new credential handle with the mechanism credentials of the447* input handle plus the acquired mechanism credential. */448status = copy_union_cred(minor_status, input_cred_handle, &union_cred);449if (status != GSS_S_COMPLETE)450return (status);451}452453/* We may need to create a mechanism specific name. */454if (desired_name != GSS_C_NO_NAME) {455union_name = (gss_union_name_t)desired_name;456if (union_name->mech_type &&457g_OID_equal(union_name->mech_type, selected_mech)) {458internal_name = union_name->mech_name;459} else {460if (gssint_import_internal_name(minor_status, selected_mech,461union_name, &allocated_name) !=462GSS_S_COMPLETE) {463status = GSS_S_BAD_NAME;464goto errout;465}466internal_name = allocated_name;467}468}469470471if (cred_usage == GSS_C_ACCEPT)472time_req = acceptor_time_req;473else if (cred_usage == GSS_C_INITIATE)474time_req = initiator_time_req;475else if (cred_usage == GSS_C_BOTH)476time_req = (acceptor_time_req > initiator_time_req) ?477acceptor_time_req : initiator_time_req;478else479time_req = 0;480481target_mechs.count = 1;482target_mechs.elements = gssint_get_public_oid(selected_mech);483if (target_mechs.elements == NULL) {484status = GSS_S_FAILURE;485goto errout;486}487488if (initiator_time_rec != NULL || acceptor_time_rec != NULL)489time_recp = &time_rec;490491if (mech->gss_acquire_cred_from) {492status = mech->gss_acquire_cred_from(minor_status, internal_name,493time_req, &target_mechs,494cred_usage, cred_store, &cred,495NULL, time_recp);496} else if (cred_store == GSS_C_NO_CRED_STORE) {497status = mech->gss_acquire_cred(minor_status, internal_name, time_req,498&target_mechs, cred_usage, &cred, NULL,499time_recp);500} else {501status = GSS_S_UNAVAILABLE;502goto errout;503}504505if (status != GSS_S_COMPLETE) {506map_error(minor_status, mech);507goto errout;508}509510/* Extend the arrays in the union cred. */511512newptr = realloc(union_cred->mechs_array,513(union_cred->count + 1) * sizeof (gss_OID_desc));514if (newptr == NULL) {515status = GSS_S_FAILURE;516goto errout;517}518union_cred->mechs_array = newptr;519520newptr = realloc(union_cred->cred_array,521(union_cred->count + 1) * sizeof (gss_cred_id_t));522if (newptr == NULL) {523status = GSS_S_FAILURE;524goto errout;525}526union_cred->cred_array = newptr;527528if (acceptor_time_rec)529if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)530*acceptor_time_rec = time_rec;531if (initiator_time_rec)532if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)533*initiator_time_rec = time_rec;534535oidbuf = malloc(selected_mech->length);536if (oidbuf == NULL)537goto errout;538union_cred->mechs_array[union_cred->count].elements = oidbuf;539g_OID_copy(&union_cred->mechs_array[union_cred->count], selected_mech);540541if (actual_mechs != NULL) {542status = gssint_make_public_oid_set(minor_status,543union_cred->mechs_array,544union_cred->count + 1,545actual_mechs);546if (GSS_ERROR(status))547goto errout;548}549550union_cred->cred_array[union_cred->count] = cred;551union_cred->count++;552if (output_cred_handle != NULL)553*output_cred_handle = (gss_cred_id_t)union_cred;554555/* We're done with the internal name. Free it if we allocated it. */556557if (allocated_name)558(void) gssint_release_internal_name(&temp_minor_status,559selected_mech,560&allocated_name);561562return (GSS_S_COMPLETE);563564errout:565if (cred != NULL && mech->gss_release_cred)566mech->gss_release_cred(&temp_minor_status, &cred);567568if (allocated_name)569(void) gssint_release_internal_name(&temp_minor_status,570selected_mech,571&allocated_name);572573if (output_cred_handle != NULL && union_cred != NULL) {574tmpcred = union_cred;575(void) gss_release_cred(&temp_minor_status, &tmpcred);576}577578free(oidbuf);579580return (status);581}582583584