Path: blob/main/crypto/krb5/src/lib/gssapi/mechglue/g_glue.c
39586 views
/* #pragma ident "@(#)g_glue.c 1.25 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#include "mglueP.h"25#include "k5-der.h"26#include <stdio.h>27#ifdef HAVE_STDLIB_H28#include <stdlib.h>29#endif30#include <string.h>31#include <errno.h>3233#define MSO_BIT (8*(sizeof (int) - 1)) /* Most significant octet bit */3435extern gss_mechanism *gssint_mechs_array;3637/*38* This file contains the support routines for the glue layer.39*/4041/*42* The following mechanisms do not always identify themselves43* per the GSS-API specification, when interoperating with MS44* peers. We include the OIDs here so we do not have to ilnk45* with the mechanism.46*/47static gss_OID_desc gss_ntlm_mechanism_oid_desc =48{10, (void *)"\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"};49static gss_OID_desc gss_spnego_mechanism_oid_desc =50{6, (void *)"\x2b\x06\x01\x05\x05\x02"};51static gss_OID_desc gss_krb5_mechanism_oid_desc =52{9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};5354#define NTLMSSP_SIGNATURE "NTLMSSP"5556OM_uint3257gssint_get_mech_type(gss_OID OID, gss_buffer_t token)58{59struct k5input in;60size_t tlen;6162/* Check for interoperability exceptions */63if (token->length >= sizeof(NTLMSSP_SIGNATURE) &&64memcmp(token->value, NTLMSSP_SIGNATURE,65sizeof(NTLMSSP_SIGNATURE)) == 0) {66*OID = gss_ntlm_mechanism_oid_desc;67} else if (token->length != 0 &&68((char *)token->value)[0] == 0x6E) {69/* Could be a raw AP-REQ (check for APPLICATION tag) */70*OID = gss_krb5_mechanism_oid_desc;71} else if (token->length == 0) {72*OID = gss_spnego_mechanism_oid_desc;73} else {74k5_input_init(&in, token->value, token->length);75return (g_get_token_header(&in, OID, &tlen) ? GSS_S_COMPLETE :76GSS_S_DEFECTIVE_TOKEN);77}7879return (GSS_S_COMPLETE);80}8182static OM_uint3283import_internal_attributes(OM_uint32 *minor,84gss_mechanism dmech,85gss_union_name_t sname,86gss_name_t dname)87{88OM_uint32 major, tmpMinor;89gss_mechanism smech;90gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET;91size_t i;9293if (sname->mech_name == GSS_C_NO_NAME)94return (GSS_S_UNAVAILABLE);9596smech = gssint_get_mechanism (sname->mech_type);97if (smech == NULL)98return (GSS_S_BAD_MECH);99100if (smech->gss_inquire_name == NULL ||101smech->gss_get_name_attribute == NULL)102return (GSS_S_UNAVAILABLE);103104if (dmech->gss_set_name_attribute == NULL)105return (GSS_S_UNAVAILABLE);106107major = smech->gss_inquire_name(minor, sname->mech_name,108NULL, NULL, &attrs);109if (GSS_ERROR(major) || attrs == GSS_C_NO_BUFFER_SET) {110gss_release_buffer_set(&tmpMinor, &attrs);111return (major);112}113114for (i = 0; i < attrs->count; i++) {115int more = -1;116117while (more != 0) {118gss_buffer_desc value, display_value;119int authenticated, complete;120121major = smech->gss_get_name_attribute(minor, sname->mech_name,122&attrs->elements[i],123&authenticated, &complete,124&value, &display_value,125&more);126if (GSS_ERROR(major))127continue;128129if (authenticated) {130dmech->gss_set_name_attribute(minor, dname, complete,131&attrs->elements[i], &value);132}133134gss_release_buffer(&tmpMinor, &value);135gss_release_buffer(&tmpMinor, &display_value);136}137}138139gss_release_buffer_set(&tmpMinor, &attrs);140141return (GSS_S_COMPLETE);142}143144/*145* Internal routines to get and release an internal mechanism name146*/147148OM_uint32149gssint_import_internal_name(OM_uint32 *minor_status, gss_OID mech_type,150gss_union_name_t union_name,151gss_name_t *internal_name)152{153OM_uint32 status, tmpMinor;154gss_mechanism mech;155gss_OID public_mech;156157mech = gssint_get_mechanism (mech_type);158if (mech == NULL)159return (GSS_S_BAD_MECH);160161/*162* If we are importing a name for the same mechanism, and the163* mechanism implements gss_duplicate_name, then use that.164*/165if (union_name->mech_type != GSS_C_NO_OID &&166union_name->mech_name != GSS_C_NO_NAME &&167g_OID_equal(union_name->mech_type, mech_type) &&168mech->gss_duplicate_name != NULL) {169status = mech->gss_duplicate_name(minor_status,170union_name->mech_name,171internal_name);172if (status != GSS_S_UNAVAILABLE) {173if (status != GSS_S_COMPLETE)174map_error(minor_status, mech);175return (status);176}177}178179if (mech->gssspi_import_name_by_mech) {180public_mech = gssint_get_public_oid(mech_type);181status = mech->gssspi_import_name_by_mech(minor_status, public_mech,182union_name->external_name,183union_name->name_type,184internal_name);185} else if (mech->gss_import_name) {186status = mech->gss_import_name(minor_status, union_name->external_name,187union_name->name_type, internal_name);188} else {189return (GSS_S_UNAVAILABLE);190}191192if (status == GSS_S_COMPLETE) {193/* Attempt to round-trip attributes */194(void) import_internal_attributes(&tmpMinor, mech,195union_name, *internal_name);196} else {197map_error(minor_status, mech);198}199200return (status);201}202203OM_uint32204gssint_export_internal_name(OM_uint32 *minor_status, const gss_OID mech_type,205const gss_name_t internal_name,206gss_buffer_t name_buf)207{208OM_uint32 status;209gss_mechanism mech;210gss_buffer_desc dispName;211gss_OID nameOid;212int mech_der_len = 0;213struct k5buf buf;214215mech = gssint_get_mechanism(mech_type);216if (!mech)217return (GSS_S_BAD_MECH);218219if (mech->gss_export_name) {220status = mech->gss_export_name(minor_status,221internal_name,222name_buf);223if (status != GSS_S_COMPLETE)224map_error(minor_status, mech);225return status;226}227228/*229* if we are here it is because the mechanism does not provide230* a gss_export_name so we will use our implementation. We231* do required that the mechanism define a gss_display_name.232*/233if (!mech->gss_display_name)234return (GSS_S_UNAVAILABLE);235236/*237* NOTE: RFC2743 (section 3.2) governs the format of the outer238* wrapper of exported names; the mechanisms' specs govern239* the format of the inner portion of the exported name240* and, for some (e.g., RFC1964, the Kerberos V mech), a241* generic default as implemented here will do.242*243* The outer wrapper of an exported MN is: 2-octet tok Id244* (0x0401) + 2-octet network-byte order mech OID length + mech245* oid (in DER format, including DER tag and DER length) +246* 4-octet network-byte order length of inner portion + inner247* portion.248*249* For the Kerberos V mechanism the inner portion of an exported250* MN is the display name string and ignores the name type OID251* altogether. And we hope this will be so for any future252* mechanisms also, so that factoring name export/import out of253* the mech and into libgss pays off.254*/255if ((status = mech->gss_display_name(minor_status,256internal_name,257&dispName,258&nameOid))259!= GSS_S_COMPLETE) {260map_error(minor_status, mech);261return (status);262}263264/* Allocate space and prepare a buffer. */265mech_der_len = k5_der_value_len(mech_type->length);266name_buf->length = 2 + 2 + mech_der_len + 4 + dispName.length;267name_buf->value = gssalloc_malloc(name_buf->length);268if (name_buf->value == NULL) {269name_buf->length = 0;270(void) gss_release_buffer(&status, &dispName);271return (GSS_S_FAILURE);272}273k5_buf_init_fixed(&buf, name_buf->value, name_buf->length);274275/* Assemble the name. */276k5_buf_add_len(&buf, "\x04\x01", 2);277k5_buf_add_uint16_be(&buf, mech_der_len);278k5_der_add_value(&buf, 0x06, mech_type->elements, mech_type->length);279k5_buf_add_uint32_be(&buf, dispName.length);280k5_buf_add_len(&buf, dispName.value, dispName.length);281assert(buf.len == name_buf->length);282283/* release the buffer obtained from gss_display_name */284(void) gss_release_buffer(minor_status, &dispName);285return (GSS_S_COMPLETE);286} /* gssint_export_internal_name */287288OM_uint32289gssint_display_internal_name(OM_uint32 *minor_status, gss_OID mech_type,290gss_name_t internal_name,291gss_buffer_t external_name, gss_OID *name_type)292{293OM_uint32 status;294gss_mechanism mech;295296mech = gssint_get_mechanism (mech_type);297if (mech) {298if (mech->gss_display_name) {299status = mech->gss_display_name (300minor_status,301internal_name,302external_name,303name_type);304if (status != GSS_S_COMPLETE)305map_error(minor_status, mech);306} else307status = GSS_S_UNAVAILABLE;308309return (status);310}311312return (GSS_S_BAD_MECH);313}314315OM_uint32316gssint_release_internal_name(OM_uint32 *minor_status, gss_OID mech_type,317gss_name_t *internal_name)318{319OM_uint32 status;320gss_mechanism mech;321322mech = gssint_get_mechanism (mech_type);323if (mech) {324if (mech->gss_release_name) {325status = mech->gss_release_name (326minor_status,327internal_name);328if (status != GSS_S_COMPLETE)329map_error(minor_status, mech);330} else331status = GSS_S_UNAVAILABLE;332333return (status);334}335336return (GSS_S_BAD_MECH);337}338339OM_uint32340gssint_delete_internal_sec_context(OM_uint32 *minor_status, gss_OID mech_type,341gss_ctx_id_t *internal_ctx,342gss_buffer_t output_token)343{344OM_uint32 status;345gss_mechanism mech;346347mech = gssint_get_mechanism (mech_type);348if (mech) {349if (mech->gss_delete_sec_context)350status = mech->gss_delete_sec_context (minor_status,351internal_ctx,352output_token);353else354status = GSS_S_UNAVAILABLE;355356return (status);357}358359return (GSS_S_BAD_MECH);360}361362/*363* This function converts an internal gssapi name to a union gssapi364* name. Note that internal_name should be considered "consumed" by365* this call, whether or not we return an error.366*/367OM_uint32368gssint_convert_name_to_union_name(OM_uint32 *minor_status, gss_mechanism mech,369gss_name_t internal_name,370gss_name_t *external_name)371{372OM_uint32 major_status,tmp;373gss_union_name_t union_name;374375union_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc));376if (!union_name) {377major_status = GSS_S_FAILURE;378*minor_status = ENOMEM;379map_errcode(minor_status);380goto allocation_failure;381}382union_name->mech_type = 0;383union_name->mech_name = internal_name;384union_name->name_type = 0;385union_name->external_name = 0;386387major_status = generic_gss_copy_oid(minor_status, &mech->mech_type,388&union_name->mech_type);389if (major_status != GSS_S_COMPLETE) {390map_errcode(minor_status);391goto allocation_failure;392}393394union_name->external_name =395(gss_buffer_t) malloc(sizeof(gss_buffer_desc));396if (!union_name->external_name) {397major_status = GSS_S_FAILURE;398goto allocation_failure;399}400union_name->external_name->length = 0;401union_name->external_name->value = NULL;402403major_status = mech->gss_display_name(minor_status,404internal_name,405union_name->external_name,406&union_name->name_type);407if (major_status != GSS_S_COMPLETE) {408map_error(minor_status, mech);409goto allocation_failure;410}411412union_name->loopback = union_name;413*external_name = /*(gss_name_t) CHECK */union_name;414return (GSS_S_COMPLETE);415416allocation_failure:417if (union_name) {418if (union_name->external_name) {419if (union_name->external_name->value)420free(union_name->external_name->value);421free(union_name->external_name);422}423if (union_name->name_type)424gss_release_oid(&tmp, &union_name->name_type);425if (union_name->mech_type)426gss_release_oid(&tmp, &union_name->mech_type);427free(union_name);428}429/*430* do as the top comment says - since we are now owners of431* internal_name, we must clean it up432*/433if (internal_name)434(void) gssint_release_internal_name(&tmp, &mech->mech_type,435&internal_name);436return (major_status);437}438439/*440* Glue routine for returning the mechanism-specific credential from a441* external union credential.442*/443gss_cred_id_t444gssint_get_mechanism_cred(gss_union_cred_t union_cred, gss_OID mech_type)445{446int i;447448if (union_cred == GSS_C_NO_CREDENTIAL)449return GSS_C_NO_CREDENTIAL;450451for (i=0; i < union_cred->count; i++) {452if (g_OID_equal(mech_type, &union_cred->mechs_array[i]))453return union_cred->cred_array[i];454}455return GSS_C_NO_CREDENTIAL;456}457458/*459* Routine to create and copy the gss_buffer_desc structure.460* Both space for the structure and the data is allocated.461*/462OM_uint32463gssint_create_copy_buffer(const gss_buffer_t srcBuf, gss_buffer_t *destBuf,464int addNullChar)465{466gss_buffer_t aBuf;467unsigned int len;468469if (destBuf == NULL)470return (GSS_S_CALL_INACCESSIBLE_WRITE);471472*destBuf = 0;473474aBuf = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));475if (!aBuf)476return (GSS_S_FAILURE);477478if (addNullChar)479len = srcBuf->length + 1;480else481len = srcBuf->length;482483if (!(aBuf->value = (void*)gssalloc_malloc(len))) {484free(aBuf);485return (GSS_S_FAILURE);486}487488489(void) memcpy(aBuf->value, srcBuf->value, srcBuf->length);490aBuf->length = srcBuf->length;491*destBuf = aBuf;492493/* optionally add a NULL character */494if (addNullChar)495((char *)aBuf->value)[aBuf->length] = '\0';496497return (GSS_S_COMPLETE);498} /* ****** gssint_create_copy_buffer ****** */499500OM_uint32501gssint_create_union_context(OM_uint32 *minor, gss_const_OID mech_oid,502gss_union_ctx_id_t *ctx_out)503{504OM_uint32 status;505gss_union_ctx_id_t ctx;506507*ctx_out = NULL;508509ctx = calloc(1, sizeof(*ctx));510if (ctx == NULL) {511*minor = ENOMEM;512return GSS_S_FAILURE;513}514515status = generic_gss_copy_oid(minor, mech_oid, &ctx->mech_type);516if (status != GSS_S_COMPLETE) {517free(ctx);518return status;519}520521ctx->loopback = ctx;522ctx->internal_ctx_id = GSS_C_NO_CONTEXT;523524*ctx_out = ctx;525return GSS_S_COMPLETE;526}527528529