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 31 static 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 p += 4; 117 len -= 4; 118 119 if (!composite && len != t) 120 return (GSS_S_BAD_NAME); 121 122 m = __gss_get_mechanism(&mech_oid); 123 if (!m) 124 return (GSS_S_BAD_MECH); 125 126 /* 127 * Ask the mechanism to import the name. 128 */ 129 major_status = m->gm_import_name(minor_status, 130 input_name_buffer, GSS_C_NT_EXPORT_NAME, &new_canonical_name); 131 if (major_status != GSS_S_COMPLETE) { 132 _gss_mg_error(m, major_status, *minor_status); 133 return major_status; 134 } 135 136 /* 137 * Now we make a new name and mark it as an MN. 138 */ 139 name = _gss_make_name(m, new_canonical_name); 140 if (!name) { 141 m->gm_release_name(minor_status, &new_canonical_name); 142 return (GSS_S_FAILURE); 143 } 144 145 *output_name = (gss_name_t) name; 146 147 *minor_status = 0; 148 return (GSS_S_COMPLETE); 149 } 150 151 /** 152 * Import a name internal or mechanism name 153 * 154 * Type of name and their format: 155 * - GSS_C_NO_OID 156 * - GSS_C_NT_USER_NAME 157 * - GSS_C_NT_HOSTBASED_SERVICE 158 * - GSS_C_NT_EXPORT_NAME 159 * - GSS_C_NT_ANONYMOUS 160 * - GSS_KRB5_NT_PRINCIPAL_NAME 161 * 162 * For more information about @ref internalVSmechname. 163 * 164 * @param minor_status minor status code 165 * @param input_name_buffer import name buffer 166 * @param input_name_type type of the import name buffer 167 * @param output_name the resulting type, release with 168 * gss_release_name(), independent of input_name 169 * 170 * @returns a gss_error code, see gss_display_status() about printing 171 * the error code. 172 * 173 * @ingroup gssapi 174 */ 175 176 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 177 gss_import_name(OM_uint32 *minor_status, 178 const gss_buffer_t input_name_buffer, 179 const gss_OID input_name_type, 180 gss_name_t *output_name) 181 { 182 struct _gss_mechanism_name *mn; 183 gss_OID name_type = input_name_type; 184 OM_uint32 major_status, ms; 185 struct _gss_name *name; 186 struct _gss_mech_switch *m; 187 gss_name_t rname; 188 189 *output_name = GSS_C_NO_NAME; 190 191 if (input_name_buffer->length == 0) { 192 *minor_status = 0; 193 return (GSS_S_BAD_NAME); 194 } 195 196 _gss_load_mech(); 197 198 /* 199 * Use GSS_NT_USER_NAME as default name type. 200 */ 201 if (name_type == GSS_C_NO_OID) 202 name_type = GSS_C_NT_USER_NAME; 203 204 /* 205 * If this is an exported name, we need to parse it to find 206 * the mechanism and then import it as an MN. See RFC 2743 207 * section 3.2 for a description of the format. 208 */ 209 if (gss_oid_equal(name_type, GSS_C_NT_EXPORT_NAME)) { 210 return _gss_import_export_name(minor_status, 211 input_name_buffer, output_name); 212 } 213 214 215 *minor_status = 0; 216 name = calloc(1, sizeof(struct _gss_name)); 217 if (!name) { 218 *minor_status = ENOMEM; 219 return (GSS_S_FAILURE); 220 } 221 222 HEIM_SLIST_INIT(&name->gn_mn); 223 224 major_status = _gss_copy_oid(minor_status, 225 name_type, &name->gn_type); 226 if (major_status) { 227 free(name); 228 return (GSS_S_FAILURE); 229 } 230 231 major_status = _gss_copy_buffer(minor_status, 232 input_name_buffer, &name->gn_value); 233 if (major_status) 234 goto out; 235 236 /* 237 * Walk over the mechs and import the name into a mech name 238 * for those supported this nametype. 239 */ 240 241 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 242 int present = 0; 243 244 major_status = gss_test_oid_set_member(minor_status, 245 name_type, m->gm_name_types, &present); 246 247 if (major_status || present == 0) 248 continue; 249 250 mn = malloc(sizeof(struct _gss_mechanism_name)); 251 if (!mn) { 252 *minor_status = ENOMEM; 253 major_status = GSS_S_FAILURE; 254 goto out; 255 } 256 257 major_status = (*m->gm_mech.gm_import_name)(minor_status, 258 &name->gn_value, 259 (name->gn_type.elements 260 ? &name->gn_type : GSS_C_NO_OID), 261 &mn->gmn_name); 262 if (major_status != GSS_S_COMPLETE) { 263 _gss_mg_error(&m->gm_mech, major_status, *minor_status); 264 free(mn); 265 goto out; 266 } 267 268 mn->gmn_mech = &m->gm_mech; 269 mn->gmn_mech_oid = &m->gm_mech_oid; 270 HEIM_SLIST_INSERT_HEAD(&name->gn_mn, mn, gmn_link); 271 } 272 273 /* 274 * If we can't find a mn for the name, bail out already here. 275 */ 276 277 mn = HEIM_SLIST_FIRST(&name->gn_mn); 278 if (!mn) { 279 *minor_status = 0; 280 major_status = GSS_S_NAME_NOT_MN; 281 goto out; 282 } 283 284 *output_name = (gss_name_t) name; 285 return (GSS_S_COMPLETE); 286 287 out: 288 rname = (gss_name_t)name; 289 gss_release_name(&ms, &rname); 290 return major_status; 291 } 292