1/*- 2 * Copyright (c) 2005 Doug Rabson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: src/lib/libgssapi/gss_import_name.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ 27 */ 28 29#include "mech_locl.h" 30 31static OM_uint32 32_gss_import_export_name(OM_uint32 *minor_status, 33 const gss_buffer_t input_name_buffer, 34 gss_name_t *output_name) 35{ 36 OM_uint32 major_status; 37 unsigned char *p = input_name_buffer->value; 38 size_t len = input_name_buffer->length; 39 size_t t; 40 gss_OID_desc mech_oid; 41 gssapi_mech_interface m; 42 struct _gss_name *name; 43 gss_name_t new_canonical_name; 44 int composite = 0; 45 46 *minor_status = 0; 47 *output_name = 0; 48 49 /* 50 * Make sure that TOK_ID is {4, 1}. 51 */ 52 if (len < 2) 53 return (GSS_S_BAD_NAME); 54 if (p[0] != 4) 55 return (GSS_S_BAD_NAME); 56 switch (p[1]) { 57 case 1: /* non-composite name */ 58 break; 59 case 2: /* composite name */ 60 composite = 1; 61 break; 62 default: 63 return (GSS_S_BAD_NAME); 64 } 65 p += 2; 66 len -= 2; 67 68 /* 69 * Get the mech length and the name length and sanity 70 * check the size of of the buffer. 71 */ 72 if (len < 2) 73 return (GSS_S_BAD_NAME); 74 t = (p[0] << 8) + p[1]; 75 p += 2; 76 len -= 2; 77 78 /* 79 * Check the DER encoded OID to make sure it agrees with the 80 * length we just decoded. 81 */ 82 if (p[0] != 6) /* 6=OID */ 83 return (GSS_S_BAD_NAME); 84 p++; 85 len--; 86 t--; 87 if (p[0] & 0x80) { 88 int digits = p[0]; 89 p++; 90 len--; 91 t--; 92 mech_oid.length = 0; 93 while (digits--) { 94 mech_oid.length = (mech_oid.length << 8) | p[0]; 95 p++; 96 len--; 97 t--; 98 } 99 } else { 100 mech_oid.length = p[0]; 101 p++; 102 len--; 103 t--; 104 } 105 if (mech_oid.length != t) 106 return (GSS_S_BAD_NAME); 107 108 mech_oid.elements = p; 109 110 if (len < t + 4) 111 return (GSS_S_BAD_NAME); 112 p += t; 113 len -= t; 114 115 t = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; 116 len -= 4; 117 118 if (!composite && len != t) 119 return (GSS_S_BAD_NAME); 120 121 m = __gss_get_mechanism(&mech_oid); 122 if (!m) 123 return (GSS_S_BAD_MECH); 124 125 /* 126 * Ask the mechanism to import the name. 127 */ 128 major_status = m->gm_import_name(minor_status, 129 input_name_buffer, GSS_C_NT_EXPORT_NAME, &new_canonical_name); 130 if (major_status != GSS_S_COMPLETE) { 131 _gss_mg_error(m, *minor_status); 132 return major_status; 133 } 134 135 /* 136 * Now we make a new name and mark it as an MN. 137 */ 138 name = _gss_create_name(new_canonical_name, m); 139 if (!name) { 140 m->gm_release_name(minor_status, &new_canonical_name); 141 return (GSS_S_FAILURE); 142 } 143 144 *output_name = (gss_name_t) name; 145 146 *minor_status = 0; 147 return (GSS_S_COMPLETE); 148} 149 150/** 151 * Import a name internal or mechanism name 152 * 153 * Type of name and their format: 154 * - GSS_C_NO_OID 155 * - GSS_C_NT_USER_NAME 156 * - GSS_C_NT_HOSTBASED_SERVICE 157 * - GSS_C_NT_EXPORT_NAME 158 * - GSS_C_NT_ANONYMOUS 159 * - GSS_KRB5_NT_PRINCIPAL_NAME 160 * 161 * For more information about @ref internalVSmechname. 162 * 163 * @param minor_status minor status code 164 * @param input_name_buffer import name buffer 165 * @param input_name_type type of the import name buffer 166 * @param output_name the resulting type, release with 167 * gss_release_name(), independent of input_name 168 * 169 * @returns a gss_error code, see gss_display_status() about printing 170 * the error code. 171 * 172 * @ingroup gssapi 173 */ 174 175GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 176gss_import_name(OM_uint32 *minor_status, 177 const gss_buffer_t input_name_buffer, 178 gss_const_OID input_name_type, 179 gss_name_t *output_name) 180{ 181 struct _gss_mechanism_name *mn; 182 gss_OID name_type = rk_UNCONST(input_name_type); 183 OM_uint32 major_status, junk; 184 struct _gss_name *name; 185 struct _gss_mech_switch *m; 186 gss_name_t rname; 187 188 *output_name = GSS_C_NO_NAME; 189 190 /* Allow empty names since that's valid (ANONYMOUS for example) */ 191 192 _gss_load_mech(); 193 194 /* 195 * Use GSS_NT_USER_NAME as default name type. 196 */ 197 if (name_type == GSS_C_NO_OID) 198 name_type = GSS_C_NT_USER_NAME; 199 200 /* 201 * If this is an exported name, we need to parse it to find 202 * the mechanism and then import it as an MN. See RFC 2743 203 * section 3.2 for a description of the format. 204 */ 205 if (gss_oid_equal(name_type, GSS_C_NT_EXPORT_NAME)) { 206 return _gss_import_export_name(minor_status, 207 input_name_buffer, output_name); 208 } 209 210 211 *minor_status = 0; 212 name = _gss_create_name(NULL, NULL); 213 if (!name) { 214 *minor_status = ENOMEM; 215 return (GSS_S_FAILURE); 216 } 217 218 HEIM_SLIST_INIT(&name->gn_mn); 219 220 major_status = _gss_copy_oid(minor_status, 221 name_type, &name->gn_type); 222 if (major_status) { 223 rname = (gss_name_t)name; 224 gss_release_name(&junk, (gss_name_t *)&rname); 225 return (GSS_S_FAILURE); 226 } 227 228 major_status = _gss_copy_buffer(minor_status, 229 input_name_buffer, &name->gn_value); 230 if (major_status) 231 goto out; 232 233 /* 234 * Walk over the mechs and import the name into a mech name 235 * for those supported this nametype. 236 */ 237 238 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 239 int present = 0; 240 241 major_status = gss_test_oid_set_member(minor_status, 242 name_type, m->gm_name_types, &present); 243 244 if (major_status || present == 0) 245 continue; 246 247 mn = malloc(sizeof(struct _gss_mechanism_name)); 248 if (!mn) { 249 *minor_status = ENOMEM; 250 major_status = GSS_S_FAILURE; 251 goto out; 252 } 253 254 major_status = (*m->gm_mech.gm_import_name)(minor_status, 255 &name->gn_value, 256 (name->gn_type.elements 257 ? &name->gn_type : GSS_C_NO_OID), 258 &mn->gmn_name); 259 if (major_status != GSS_S_COMPLETE) { 260 _gss_mg_error(&m->gm_mech, *minor_status); 261 free(mn); 262 /** 263 * If we failed to import the name in a mechanism, it will be ignored as long as its possible to import name in some other mechanism. 264 * We will catch the failure later though in gss_init_sec_context() or other function that the mechanism doesn't have name. 265 */ 266 continue; 267 } 268 269 mn->gmn_mech = &m->gm_mech; 270 mn->gmn_mech_oid = &m->gm_mech_oid; 271 HEIM_SLIST_INSERT_HEAD(&name->gn_mn, mn, gmn_link); 272 } 273 274 /** 275 * If we can't find a mechanism name for the name, we fail though. 276 */ 277 278 mn = HEIM_SLIST_FIRST(&name->gn_mn); 279 if (!mn) { 280 *minor_status = 0; 281 major_status = GSS_S_NAME_NOT_MN; 282 goto out; 283 } 284 285 *output_name = (gss_name_t) name; 286 return (GSS_S_COMPLETE); 287 288 out: 289 rname = (gss_name_t)name; 290 gss_release_name(&junk, &rname); 291 return major_status; 292} 293