1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * glue routine gss_import_name 27 * 28 */ 29 30 #include <mechglueP.h> 31 #include "gssapiP_generic.h" 32 #include <stdio.h> 33 #ifdef HAVE_STDLIB_H 34 #include <stdlib.h> 35 #endif 36 #include <string.h> 37 #include <errno.h> 38 39 extern int 40 get_der_length(unsigned char **, unsigned int, unsigned int *); 41 42 /* local function to import GSS_C_EXPORT_NAME names */ 43 static OM_uint32 importExportName(OM_uint32 *, gss_union_name_t); 44 45 static OM_uint32 46 val_imp_name_args( 47 OM_uint32 *minor_status, 48 gss_buffer_t input_name_buffer, 49 gss_name_t *output_name) 50 { 51 52 /* Initialize outputs. */ 53 54 if (minor_status != NULL) 55 *minor_status = 0; 56 57 if (output_name != NULL) 58 *output_name = GSS_C_NO_NAME; 59 60 /* Validate arguments. */ 61 62 if (minor_status == NULL) 63 return (GSS_S_CALL_INACCESSIBLE_WRITE); 64 65 if (output_name == NULL) 66 return (GSS_S_CALL_INACCESSIBLE_WRITE); 67 68 if (input_name_buffer == GSS_C_NO_BUFFER) 69 return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME); 70 71 if (GSS_EMPTY_BUFFER(input_name_buffer)) 72 return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME); 73 74 return (GSS_S_COMPLETE); 75 } 76 77 OM_uint32 78 gss_import_name(minor_status, 79 input_name_buffer, 80 input_name_type, 81 output_name) 82 83 OM_uint32 *minor_status; 84 const gss_buffer_t input_name_buffer; 85 const gss_OID input_name_type; 86 gss_name_t *output_name; 87 { 88 gss_union_name_t union_name; 89 OM_uint32 major_status = GSS_S_FAILURE, tmp; 90 91 major_status = val_imp_name_args(minor_status, 92 input_name_buffer, 93 output_name); 94 if (major_status != GSS_S_COMPLETE) 95 return (major_status); 96 97 /* 98 * First create the union name struct that will hold the external 99 * name and the name type. 100 */ 101 union_name = (gss_union_name_t)malloc(sizeof (gss_union_name_desc)); 102 if (!union_name) 103 return (GSS_S_FAILURE); 104 105 union_name->mech_type = 0; 106 union_name->mech_name = 0; 107 union_name->name_type = 0; 108 union_name->external_name = 0; 109 110 /* 111 * All we do here is record the external name and name_type. 112 * When the name is actually used, the underlying gss_import_name() 113 * is called for the appropriate mechanism. The exception to this 114 * rule is when the name of GSS_C_NT_EXPORT_NAME type. If that is 115 * the case, then we make it MN in this call. 116 */ 117 major_status = gssint_create_copy_buffer(input_name_buffer, 118 &union_name->external_name, 0); 119 if (major_status != GSS_S_COMPLETE) { 120 free(union_name); 121 return (major_status); 122 } 123 124 if (input_name_type != GSS_C_NULL_OID) { 125 major_status = generic_gss_copy_oid(minor_status, 126 input_name_type, 127 &union_name->name_type); 128 if (major_status != GSS_S_COMPLETE) { 129 map_errcode(minor_status); 130 goto allocation_failure; 131 } 132 } 133 134 /* 135 * In MIT Distribution the mechanism is determined from the nametype; 136 * This is not a good idea - first mechanism that supports a given 137 * name type is picked up; later on the caller can request a 138 * different mechanism. So we don't determine the mechanism here. Now 139 * the user level and kernel level import_name routine looks similar 140 * except the kernel routine makes a copy of the nametype structure. We 141 * do however make this an MN for names of GSS_C_NT_EXPORT_NAME type. 142 */ 143 if (input_name_type != GSS_C_NULL_OID && 144 g_OID_equal(input_name_type, GSS_C_NT_EXPORT_NAME)) { 145 major_status = importExportName(minor_status, union_name); 146 if (major_status != GSS_S_COMPLETE) 147 goto allocation_failure; 148 } 149 150 *output_name = (gss_name_t)union_name; 151 return (GSS_S_COMPLETE); 152 153 allocation_failure: 154 if (union_name) { 155 if (union_name->external_name) { 156 if (union_name->external_name->value) 157 free(union_name->external_name->value); 158 free(union_name->external_name); 159 } 160 if (union_name->name_type) 161 (void) generic_gss_release_oid(&tmp, 162 &union_name->name_type); 163 if (union_name->mech_name) 164 (void) __gss_release_internal_name(minor_status, 165 union_name->mech_type, 166 &union_name->mech_name); 167 if (union_name->mech_type) 168 (void) generic_gss_release_oid(&tmp, 169 &union_name->mech_type); 170 free(union_name); 171 } 172 return (major_status); 173 } 174 175 176 /* 177 * GSS export name constants 178 */ 179 static const char *expNameTokId = "\x04\x01"; 180 static const int expNameTokIdLen = 2; 181 static const int mechOidLenLen = 2; 182 static const int nameTypeLenLen = 2; 183 184 static OM_uint32 185 importExportName(minor, unionName) 186 OM_uint32 *minor; 187 gss_union_name_t unionName; 188 { 189 gss_OID_desc mechOid; 190 gss_buffer_desc expName; 191 unsigned char *buf; 192 gss_mechanism mech; 193 OM_uint32 major, mechOidLen, nameLen, curLength; 194 unsigned int bytes; 195 196 expName.value = unionName->external_name->value; 197 expName.length = unionName->external_name->length; 198 199 curLength = expNameTokIdLen + mechOidLenLen; 200 if (expName.length < curLength) 201 return (GSS_S_DEFECTIVE_TOKEN); 202 203 buf = (unsigned char *)expName.value; 204 if (memcmp(expNameTokId, buf, expNameTokIdLen) != 0) 205 return (GSS_S_DEFECTIVE_TOKEN); 206 207 buf += expNameTokIdLen; 208 209 /* extract the mechanism oid length */ 210 mechOidLen = (*buf++ << 8); 211 mechOidLen |= (*buf++); 212 curLength += mechOidLen; 213 if (expName.length < curLength) 214 return (GSS_S_DEFECTIVE_TOKEN); 215 /* 216 * The mechOid itself is encoded in DER format, OID Tag (0x06) 217 * length and the value of mech_OID 218 */ 219 if (*buf++ != 0x06) 220 return (GSS_S_DEFECTIVE_TOKEN); 221 222 /* 223 * mechoid Length is encoded twice; once in 2 bytes as 224 * explained in RFC2743 (under mechanism independent exported 225 * name object format) and once using DER encoding 226 * 227 * We verify both lengths. 228 */ 229 230 mechOid.length = get_der_length(&buf, 231 (expName.length - curLength), &bytes); 232 mechOid.elements = (void *)buf; 233 234 /* 235 * 'bytes' is the length of the DER length, '1' is for the DER 236 * tag for OID 237 */ 238 if ((bytes + mechOid.length + 1) != mechOidLen) 239 return (GSS_S_DEFECTIVE_TOKEN); 240 241 buf += mechOid.length; 242 if ((mech = __gss_get_mechanism(&mechOid)) == NULL) 243 return (GSS_S_BAD_MECH); 244 245 if (mech->gss_import_name == NULL) 246 return (GSS_S_UNAVAILABLE); 247 248 /* 249 * we must now determine if we should unwrap the name ourselves 250 * or make the mechanism do it - we should only unwrap it 251 * if we create it; so if mech->gss_export_name == NULL, we must 252 * have created it. 253 */ 254 if (mech->gss_export_name) { 255 major = mech->gss_import_name(mech->context, minor, 256 &expName, 257 (gss_OID)GSS_C_NT_EXPORT_NAME, 258 &unionName->mech_name); 259 if (major != GSS_S_COMPLETE) 260 map_error(minor, mech); 261 else { 262 major = generic_gss_copy_oid(minor, &mechOid, 263 &unionName->mech_type); 264 if (major != GSS_S_COMPLETE) 265 map_errcode(minor); 266 } 267 return (major); 268 } 269 /* 270 * we must have exported the name - so we now need to reconstruct it 271 * and call the mechanism to create it 272 * 273 * WARNING: Older versions of __gss_export_internal_name() did 274 * not export names correctly, but now it does. In 275 * order to stay compatible with existing exported 276 * names we must support names exported the broken 277 * way. 278 * 279 * Specifically, __gss_export_internal_name() used to include 280 * the name type OID in the encoding of the exported MN. 281 * Additionally, the Kerberos V mech used to make display names 282 * that included a null terminator which was counted in the 283 * display name gss_buffer_desc. 284 */ 285 curLength += 4; /* 4 bytes for name len */ 286 if (expName.length < curLength) 287 return (GSS_S_DEFECTIVE_TOKEN); 288 289 /* next 4 bytes in the name are the name length */ 290 nameLen = (*buf++) << 24; 291 nameLen |= (*buf++ << 16); 292 nameLen |= (*buf++ << 8); 293 nameLen |= (*buf++); 294 295 /* 296 * we use < here because bad code in rpcsec_gss rounds up exported 297 * name token lengths and pads with nulls, otherwise != would be 298 * appropriate 299 */ 300 curLength += nameLen; /* this is the total length */ 301 if (expName.length < curLength) 302 return (GSS_S_DEFECTIVE_TOKEN); 303 304 /* 305 * We detect broken exported names here: they always start with 306 * a two-octet network-byte order OID length, which is always 307 * less than 256 bytes, so the first octet of the length is 308 * always '\0', which is not allowed in GSS-API display names 309 * (or never occurs in them anyways). Of course, the OID 310 * shouldn't be there, but it is. After the OID (sans DER tag 311 * and length) there's the name itself, though null-terminated; 312 * this null terminator should also not be there, but it is. 313 */ 314 if (nameLen > 0 && *buf == '\0') { 315 OM_uint32 nameTypeLen; 316 /* next two bytes are the name oid */ 317 if (nameLen < nameTypeLenLen) 318 return (GSS_S_DEFECTIVE_TOKEN); 319 320 nameLen -= nameTypeLenLen; 321 322 nameTypeLen = (*buf++) << 8; 323 nameTypeLen |= (*buf++); 324 325 if (nameLen < nameTypeLen) 326 return (GSS_S_DEFECTIVE_TOKEN); 327 328 buf += nameTypeLen; 329 nameLen -= nameTypeLen; 330 331 /* 332 * adjust for expected null terminator that should 333 * really not be there 334 */ 335 if (nameLen > 0 && *(buf + nameLen - 1) == '\0') 336 nameLen--; 337 } 338 339 /* 340 * Can a name be null? Let the mech decide. 341 * 342 * NOTE: We use GSS_C_NULL_OID as the name type when importing 343 * the unwrapped name. Presumably the exported name had, 344 * prior to being exported been obtained in such a way 345 * that it has been properly perpared ("canonicalized," in 346 * GSS-API terms) accroding to some name type; we cannot 347 * tell what that name type was now, but the name should 348 * need no further preparation other than the lowest 349 * common denominator afforded by the mech to names 350 * imported with GSS_C_NULL_OID. For the Kerberos V mech 351 * this means doing less busywork too (particularly once 352 * IDN is thrown in with Kerberos V extensions). 353 */ 354 expName.length = nameLen; 355 expName.value = nameLen ? (void *)buf : NULL; 356 major = mech->gss_import_name(mech->context, minor, &expName, 357 GSS_C_NULL_OID, &unionName->mech_name); 358 if (major != GSS_S_COMPLETE) { 359 map_error(minor, mech); 360 return (major); 361 } 362 363 major = generic_gss_copy_oid(minor, &mechOid, &unionName->mech_type); 364 if (major != GSS_S_COMPLETE) { 365 map_errcode(minor); 366 } 367 return (major); 368 } /* importExportName */ 369