Path: blob/main/crypto/krb5/src/lib/gssapi/mechglue/g_imp_name.c
39586 views
/* #pragma ident "@(#)g_imp_name.c 1.26 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 gss_import_name26*27*/2829#include "mglueP.h"30#include "k5-der.h"31#include <stdio.h>32#ifdef HAVE_STDLIB_H33#include <stdlib.h>34#endif35#include <string.h>36#include <errno.h>3738/* local function to import GSS_C_EXPORT_NAME names */39static OM_uint32 importExportName(OM_uint32 *, gss_union_name_t, gss_OID);4041static OM_uint3242val_imp_name_args(43OM_uint32 *minor_status,44gss_buffer_t input_name_buffer,45gss_OID input_name_type,46gss_name_t *output_name)47{4849/* Initialize outputs. */5051if (minor_status != NULL)52*minor_status = 0;5354if (output_name != NULL)55*output_name = GSS_C_NO_NAME;5657/* Validate arguments. */5859if (minor_status == NULL)60return (GSS_S_CALL_INACCESSIBLE_WRITE);6162if (output_name == NULL)63return (GSS_S_CALL_INACCESSIBLE_WRITE);6465if (input_name_buffer == GSS_C_NO_BUFFER)66return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);6768if (input_name_type == GSS_C_NO_OID ||69!g_OID_equal(input_name_type, GSS_C_NT_ANONYMOUS)) {70if (input_name_buffer->length == 0)71return (GSS_S_BAD_NAME);7273if (input_name_buffer->value == NULL)74return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);75}7677return (GSS_S_COMPLETE);78}7980static gss_buffer_desc emptyNameBuffer;8182OM_uint32 KRB5_CALLCONV83gss_import_name(OM_uint32 * minor_status, gss_buffer_t input_name_buffer,84gss_OID input_name_type, gss_name_t * output_name)85{86gss_union_name_t union_name;87OM_uint32 tmp, major_status = GSS_S_FAILURE;8889if (input_name_buffer == GSS_C_NO_BUFFER)90input_name_buffer = &emptyNameBuffer;9192major_status = val_imp_name_args(minor_status,93input_name_buffer, input_name_type,94output_name);95if (major_status != GSS_S_COMPLETE)96return (major_status);9798/*99* First create the union name struct that will hold the external100* name and the name type.101*/102union_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc));103if (!union_name)104return (GSS_S_FAILURE);105106union_name->loopback = 0;107union_name->mech_type = 0;108union_name->mech_name = 0;109union_name->name_type = 0;110union_name->external_name = 0;111112/*113* All we do here is record the external name and name_type.114* When the name is actually used, the underlying gss_import_name()115* is called for the appropriate mechanism. The exception to this116* rule is when the name of GSS_C_NT_EXPORT_NAME type. If that is117* the case, then we make it MN in this call.118*/119major_status = gssint_create_copy_buffer(input_name_buffer,120&union_name->external_name, 0);121if (major_status != GSS_S_COMPLETE) {122free(union_name);123return (major_status);124}125126if (input_name_type != GSS_C_NULL_OID) {127major_status = generic_gss_copy_oid(minor_status,128input_name_type,129&union_name->name_type);130if (major_status != GSS_S_COMPLETE) {131map_errcode(minor_status);132goto allocation_failure;133}134}135136/*137* In MIT Distribution the mechanism is determined from the nametype;138* This is not a good idea - first mechanism that supports a given139* name type is picked up; later on the caller can request a140* different mechanism. So we don't determine the mechanism here. Now141* the user level and kernel level import_name routine looks similar142* except the kernel routine makes a copy of the nametype structure. We143* do however make this an MN for names of GSS_C_NT_EXPORT_NAME type.144*/145if (input_name_type != GSS_C_NULL_OID &&146(g_OID_equal(input_name_type, GSS_C_NT_EXPORT_NAME) ||147g_OID_equal(input_name_type, GSS_C_NT_COMPOSITE_EXPORT))) {148major_status = importExportName(minor_status, union_name, input_name_type);149if (major_status != GSS_S_COMPLETE)150goto allocation_failure;151}152153union_name->loopback = union_name;154*output_name = (gss_name_t)union_name;155return (GSS_S_COMPLETE);156157allocation_failure:158if (union_name) {159if (union_name->external_name) {160if (union_name->external_name->value)161free(union_name->external_name->value);162free(union_name->external_name);163}164if (union_name->name_type)165generic_gss_release_oid(&tmp, &union_name->name_type);166if (union_name->mech_name)167gssint_release_internal_name(minor_status, union_name->mech_type,168&union_name->mech_name);169if (union_name->mech_type)170generic_gss_release_oid(&tmp, &union_name->mech_type);171free(union_name);172}173return (major_status);174}175176static OM_uint32177importExportName(OM_uint32 *minor, gss_union_name_t unionName,178gss_OID inputNameType)179{180gss_OID_desc mechOid;181gss_buffer_desc expName;182gss_mechanism mech;183OM_uint32 major, mechOidLen, nameLen;184uint8_t b2;185const uint8_t *name;186struct k5input in, oid, old_format;187188expName.value = unionName->external_name->value;189expName.length = unionName->external_name->length;190k5_input_init(&in, expName.value, expName.length);191192if (k5_input_get_byte(&in) != 0x04)193return (GSS_S_DEFECTIVE_TOKEN);194b2 = k5_input_get_byte(&in);195if (b2 != 0x01 && b2 != 0x02) /* allow composite names */196return (GSS_S_DEFECTIVE_TOKEN);197198mechOidLen = k5_input_get_uint16_be(&in);199200if (!k5_der_get_value(&in, 0x06, &oid))201return (GSS_S_DEFECTIVE_TOKEN);202/* Verify that mechOidLen is consistent with the DER OID length. */203if (mechOidLen != k5_der_value_len(oid.len))204return (GSS_S_DEFECTIVE_TOKEN);205mechOid.length = oid.len;206mechOid.elements = (uint8_t *)oid.ptr;207if ((mech = gssint_get_mechanism(&mechOid)) == NULL)208return (GSS_S_BAD_MECH);209210if (mech->gssspi_import_name_by_mech == NULL &&211mech->gss_import_name == NULL)212return (GSS_S_UNAVAILABLE);213214/*215* we must now determine if we should unwrap the name ourselves216* or make the mechanism do it - we should only unwrap it217* if we create it; so if mech->gss_export_name == NULL, we must218* have created it.219*/220if (mech->gss_export_name) {221if (mech->gssspi_import_name_by_mech) {222major = mech->gssspi_import_name_by_mech(minor, &mechOid, &expName,223inputNameType,224&unionName->mech_name);225} else {226major = mech->gss_import_name(minor, &expName, inputNameType,227&unionName->mech_name);228}229if (major != GSS_S_COMPLETE)230map_error(minor, mech);231else {232major = generic_gss_copy_oid(minor, &mechOid,233&unionName->mech_type);234if (major != GSS_S_COMPLETE)235map_errcode(minor);236}237return (major);238}239/*240* we must have exported the name - so we now need to reconstruct it241* and call the mechanism to create it242*243* WARNING: Older versions of gssint_export_internal_name() did244* not export names correctly, but now it does. In245* order to stay compatible with existing exported246* names we must support names exported the broken247* way.248*249* Specifically, gssint_export_internal_name() used to include250* the name type OID in the encoding of the exported MN.251* Additionally, the Kerberos V mech used to make display names252* that included a null terminator which was counted in the253* display name gss_buffer_desc.254*/255256/* next 4 bytes in the name are the name length */257nameLen = k5_input_get_uint32_be(&in);258name = k5_input_get_bytes(&in, nameLen);259if (name == NULL)260return (GSS_S_DEFECTIVE_TOKEN);261262/*263* We detect broken exported names here: they always start with264* a two-octet network-byte order OID length, which is always265* less than 256 bytes, so the first octet of the length is266* always '\0', which is not allowed in GSS-API display names267* (or never occurs in them anyways). Of course, the OID268* shouldn't be there, but it is. After the OID (sans DER tag269* and length) there's the name itself, though null-terminated;270* this null terminator should also not be there, but it is.271*/272if (nameLen > 0 && *name == '\0') {273OM_uint32 nameTypeLen;274275/* Skip the name type. */276k5_input_init(&old_format, name, nameLen);277nameTypeLen = k5_input_get_uint16_be(&old_format);278if (k5_input_get_bytes(&old_format, nameTypeLen) == NULL)279return (GSS_S_DEFECTIVE_TOKEN);280/* Remove a null terminator if one is present. */281if (old_format.len > 0 && old_format.ptr[old_format.len - 1] == 0)282old_format.len--;283name = old_format.ptr;284nameLen = old_format.len;285}286287/*288* Can a name be null? Let the mech decide.289*290* NOTE: We use GSS_C_NULL_OID as the name type when importing291* the unwrapped name. Presumably the exported name had,292* prior to being exported been obtained in such a way293* that it has been properly perpared ("canonicalized," in294* GSS-API terms) according to some name type; we cannot295* tell what that name type was now, but the name should296* need no further preparation other than the lowest297* common denominator afforded by the mech to names298* imported with GSS_C_NULL_OID. For the Kerberos V mech299* this means doing less busywork too (particularly once300* IDN is thrown in with Kerberos V extensions).301*/302expName.length = nameLen;303expName.value = nameLen ? (uint8_t *)name : NULL;304if (mech->gssspi_import_name_by_mech) {305major = mech->gssspi_import_name_by_mech(minor, &mechOid, &expName,306GSS_C_NULL_OID,307&unionName->mech_name);308} else {309major = mech->gss_import_name(minor, &expName,310GSS_C_NULL_OID, &unionName->mech_name);311}312if (major != GSS_S_COMPLETE) {313map_error(minor, mech);314return (major);315}316317major = generic_gss_copy_oid(minor, &mechOid, &unionName->mech_type);318if (major != GSS_S_COMPLETE) {319map_errcode(minor);320}321return major;322} /* importExportName */323324325