1 /*
2 * Copyright 1999-2006 University of Chicago
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
18 /**
19 * @file import_name.c
20 * @author Sam Lang, Sam Meder
21 *
22 * $RCSfile: import_name.c,v $
23 * $Revision: 1.16.8.3 $
24 * $Date: 2008/09/24 17:42:15 $
25 */
26 #endif
27
28 static char *rcsid = "$Id: import_name.c,v 1.16.8.3 2008/09/24 17:42:15 bester Exp $";
29
30 #include "gssapi_openssl.h"
31 #include "globus_i_gsi_gss_utils.h"
32 #include "globus_gsi_gss_constants.h"
33 #include <string.h>
34 #include <stdlib.h>
35 #include <ctype.h>
36
37 static
38 OM_uint32
39 gss_l_resolve_ip(
40 OM_uint32 * minor_status,
41 gss_name_desc * name);
42
43
44 /**
45 * Import a name into a gss_name_t
46 * @ingroup globus_gsi_gssapi
47 *
48 * Creates a new gss_name_t which contains a mechanism-specific representation
49 * of the input name. GSSAPI OpenSSL implements the following name types, based
50 * on the input_name_type OID:
51 *
52 * - GSS_C_NT_ANONYMOUS (input_name_buffer is ignored)
53 * - GSS_C_NT_HOSTBASED_SERVICE (input_name_buffer contains a string
54 * "service@FQN" which will match /CN=service/FQDN)
55 * - GSS_C_NT_EXPORT_NAME (input_name_buffer contains a string with the
56 * X509_oneline representation of a name)
57 * like "/X=Y/Z=A...")
58 * - GSS_C_NO_OID or GSS_C_NT_USER_NAME (input_name_buffer contains an X.500
59 * name formatted
60 * like "/X=Y/Z=A...")
61 * - GLOBUS_GSS_C_NT_HOST_IP (input_name_buffer contains a string
62 * "FQDN/ip-address" which will match names with the FQDN or the IP address)
63 * - GLOBUS_SSS_C_NT_X509 (input buffer is an X509 struct from OpenSSL)
64 *
65 * @param minor_status
66 * Minor status
67 * @param input_name_buffer
68 * Input name buffer which is interpreted based on the @a input_name_type
69 * @param input_name_type
70 * OID of the name
71 * @param output_name_P
72 * New gss_name_t value containing the name
73 *
74 * @retval GSS_S_COMPLETE
75 * indicates that a valid name representation is
76 * output in output_name and described by the type value in
77 * output_name_type.
78 * @retval GSS_S_BAD_NAMETYPE
79 * indicates that the input_name_type is unsupported
80 * by the applicable underlying GSS-API mechanism(s), so the import
81 * operation could not be completed.
82 * @retval GSS_S_BAD_NAME
83 * indicates that the provided input_name_string is ill-formed in terms of
84 * the input_name_type, so the import operation could not be completed.
85 * @retval GSS_S_BAD_MECH
86 * indicates that the input presented for import was an exported name
87 * object and that its enclosed mechanism type was not recognized or was
88 * unsupported by the GSS-API implementation.
89 * @retval GSS_S_FAILURE
90 * indicates that the requested operation could not be performed for
91 * reasons unspecified at the GSS-API level.
92 */
93 OM_uint32
94 GSS_CALLCONV gss_import_name(
95 OM_uint32 * minor_status,
96 const gss_buffer_t input_name_buffer,
97 const gss_OID input_name_type,
98 gss_name_t * output_name_P)
99 2318 {
100 2318 OM_uint32 major_status = GSS_S_COMPLETE;
101 2318 globus_result_t local_result = GLOBUS_SUCCESS;
102 2318 gss_name_desc * output_name = NULL;
103 int length, i;
104 2318 char * name_buffer = NULL;
105 char * index;
106 static char * _function_name_ = "gss_import_name";
107
108 2318 GLOBUS_I_GSI_GSSAPI_DEBUG_ENTER;
109
110 2318 if (minor_status == NULL || input_name_buffer == NULL ||
111 output_name_P == NULL)
112 {
113 6 major_status = GSS_S_FAILURE;
114
115 6 if (minor_status != NULL)
116 {
117 4 GLOBUS_GSI_GSSAPI_OPENSSL_ERROR_RESULT(
118 minor_status,
119 GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT,
120 (_GGSL("Invalid parameter")));
121 }
122
123 6 goto out;
124 }
125
126 2312 *minor_status = (OM_uint32) GLOBUS_SUCCESS;
127
128 2312 output_name = calloc(1, sizeof(gss_name_desc));
129
130 2312 if (output_name == NULL)
131 {
132 0 GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status);
133 0 major_status = GSS_S_FAILURE;
134 0 goto out;
135 }
136
137 2312 output_name->name_oid = input_name_type;
138 2312 output_name->x509n = X509_NAME_new();
139 2312 if (output_name->x509n == NULL)
140 {
141 0 GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status);
142 0 major_status = GSS_S_FAILURE;
143 0 goto release_name_out;
144 }
145
146 2312 if(g_OID_equal(input_name_type, GSS_C_NT_ANONYMOUS))
147 {
148 ;
149 }
150 2194 else if (g_OID_equal(GSS_C_NT_HOSTBASED_SERVICE, input_name_type))
151 {
152 54 name_buffer = globus_libc_strdup(input_name_buffer->value);
153 54 if (name_buffer == NULL)
154 {
155 0 GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status);
156 0 major_status = GSS_S_FAILURE;
157 0 goto release_name_out;
158 }
159
160 54 index = strchr(name_buffer, '@');
161 54 if (index)
162 {
163 28 *index = '\0';
164 28 output_name->service_name = name_buffer;
165 28 name_buffer = NULL;
166 28 output_name->host_name = globus_libc_strdup(index+1);
167 28 if (output_name->host_name == NULL)
168 {
169 0 GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status);
170 0 major_status = GSS_S_FAILURE;
171
172 0 goto release_name_out;
173 }
174 }
175 else
176 {
177 26 output_name->host_name = name_buffer;
178 26 name_buffer = NULL;
179 }
180 54 name_buffer = globus_common_create_string(
181 "/CN=%s%s%s",
182 output_name->service_name ? output_name->service_name : "",
183 output_name->service_name ? "/" : "",
184 output_name->host_name);
185 54 if (name_buffer == NULL)
186 {
187 0 GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status);
188 0 major_status = GSS_S_FAILURE;
189
190 0 goto release_name_out;
191 }
192
193 54 local_result = globus_gsi_cert_utils_get_x509_name(
194 name_buffer,
195 strlen(name_buffer),
196 output_name->x509n);
197
198 54 free(name_buffer);
199 54 name_buffer = NULL;
200
201 54 if (local_result != GLOBUS_SUCCESS)
202 {
203 0 GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
204 minor_status, local_result,
205 GLOBUS_GSI_GSSAPI_ERROR_BAD_NAME);
206 0 major_status = GSS_S_FAILURE;
207
208 0 goto release_name_out;
209 }
210 54 output_name->x509n_oneline =
211 X509_NAME_oneline(output_name->x509n, NULL, 0);
212 54 if (output_name->x509n_oneline == NULL)
213 {
214 0 GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status);
215 0 major_status = GSS_S_FAILURE;
216
217 0 goto release_name_out;
218 }
219 }
220 2086 else if (g_OID_equal(GSS_C_NT_EXPORT_NAME, input_name_type))
221 {
222 /* Note: Does not support all name types */
223 0 output_name->name_oid = GSS_C_NO_OID;
224 0 name_buffer = input_name_buffer->value;
225
226 0 i = 0;
227 0 if (name_buffer[i++] != 0x04 || name_buffer[i++] != 0x01 ||
228 name_buffer[i++] !=
229 ((gss_mech_globus_gssapi_openssl->length+2) >> 8) ||
230 name_buffer[i++] !=
231 ((gss_mech_globus_gssapi_openssl->length+2) & 0xff) ||
232 name_buffer[i++] != 0x06 ||
233 name_buffer[i++] !=
234 (gss_mech_globus_gssapi_openssl->length & 0xff) ||
235 (memcmp(&(name_buffer[i]), gss_mech_globus_gssapi_openssl->elements,
236 gss_mech_globus_gssapi_openssl->length) != 0))
237 {
238 0 GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
239 minor_status, local_result,
240 GLOBUS_GSI_GSSAPI_ERROR_BAD_NAME);
241 0 major_status = GSS_S_BAD_NAME;
242 0 goto release_name_out;
243 }
244
245 0 i += gss_mech_globus_gssapi_openssl->length;
246 0 length = name_buffer[i++] << 24;
247 0 length += name_buffer[i++] << 16;
248 0 length += name_buffer[i++] << 8;
249 0 length += name_buffer[i++] & 0xff;
250
251 0 local_result = globus_gsi_cert_utils_get_x509_name(
252 &(name_buffer[i]),
253 length,
254 output_name->x509n);
255 0 if(local_result != GLOBUS_SUCCESS)
256 {
257 0 GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
258 minor_status, local_result,
259 GLOBUS_GSI_GSSAPI_ERROR_BAD_NAME);
260 0 major_status = GSS_S_BAD_NAME;
261 0 goto release_name_out;
262 }
263 0 output_name->x509n_oneline =
264 X509_NAME_oneline(output_name->x509n, NULL, 0);
265 0 output_name->host_name =
266 (char *) globus_i_gsi_gssapi_get_hostname(output_name);
267 }
268 2128 else if (g_OID_equal(GSS_C_NO_OID, input_name_type) ||
269 g_OID_equal(GSS_C_NT_USER_NAME, input_name_type))
270 {
271 44 output_name->user_name = globus_libc_strdup(input_name_buffer->value);
272 44 if (output_name->user_name == NULL)
273 {
274 0 GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status);
275 0 major_status = GSS_S_FAILURE;
276
277 0 goto release_name_out;
278 }
279 44 local_result = globus_gsi_cert_utils_get_x509_name(
280 output_name->user_name,
281 strlen(output_name->user_name),
282 output_name->x509n);
283 44 if(local_result != GLOBUS_SUCCESS)
284 {
285 2 GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
286 minor_status, local_result,
287 GLOBUS_GSI_GSSAPI_ERROR_BAD_NAME);
288 2 major_status = GSS_S_BAD_NAME;
289
290 2 goto release_name_out;
291 }
292 42 output_name->x509n_oneline =
293 X509_NAME_oneline(output_name->x509n, NULL, 0);
294 42 if (output_name->x509n_oneline == NULL)
295 {
296 0 GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status);
297 0 major_status = GSS_S_FAILURE;
298
299 0 goto release_name_out;
300 }
301 42 output_name->host_name =
302 (char *) globus_i_gsi_gssapi_get_hostname(output_name);
303 42 if (output_name->host_name == NULL)
304 {
305 0 GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status);
306 0 major_status = GSS_S_FAILURE;
307
308 0 goto release_name_out;
309 }
310 }
311 2094 else if (g_OID_equal(GLOBUS_GSS_C_NT_HOST_IP, input_name_type))
312 {
313 52 name_buffer = globus_libc_strdup(input_name_buffer->value);
314 52 if (name_buffer == NULL)
315 {
316 0 GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status);
317 0 major_status = GSS_S_FAILURE;
318
319 0 goto release_name_out;
320 }
321
322 52 index = strchr(name_buffer, '/');
323 52 if (index)
324 {
325 52 *index = '\0';
326 52 output_name->host_name = name_buffer;
327 52 name_buffer = NULL;
328 52 output_name->ip_address = globus_libc_strdup(index+1);
329 }
330 else
331 {
332 0 free(name_buffer);
333 0 name_buffer = NULL;
334
335 0 major_status = GSS_S_BAD_NAME;
336
337 0 GLOBUS_GSI_GSSAPI_OPENSSL_ERROR_RESULT(
338 minor_status,
339 GLOBUS_GSI_GSSAPI_ERROR_BAD_NAME,
340 (_GGSL("Bad name")));
341 }
342 52 name_buffer = globus_common_create_string(
343 "/CN=%s",
344 output_name->host_name);
345 52 if (name_buffer == NULL)
346 {
347 0 GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status);
348 0 major_status = GSS_S_FAILURE;
349
350 0 goto release_name_out;
351 }
352
353 52 local_result = globus_gsi_cert_utils_get_x509_name(
354 name_buffer,
355 strlen(name_buffer),
356 output_name->x509n);
357 52 free(name_buffer);
358 52 name_buffer = NULL;
359 52 if(local_result != GLOBUS_SUCCESS)
360 {
361 0 GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT(
362 minor_status, local_result,
363 GLOBUS_GSI_GSSAPI_ERROR_BAD_NAME);
364 0 major_status = GSS_S_BAD_NAME;
365
366 0 goto release_name_out;
367 }
368 52 output_name->x509n_oneline =
369 X509_NAME_oneline(output_name->x509n, NULL, 0);
370 52 if (output_name->x509n_oneline == NULL)
371 {
372 0 GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status);
373 0 major_status = GSS_S_FAILURE;
374
375 0 goto release_name_out;
376 }
377 52 major_status = gss_l_resolve_ip(minor_status, output_name);
378 }
379 3980 else if (g_OID_equal(GLOBUS_GSS_C_NT_X509, input_name_type))
380 {
381 X509_NAME * n;
382 1990 X509 * x509_input = input_name_buffer->value;
383 GENERAL_NAMES * subject_alt_name;
384 int idx;
385
386 /* Extract SubjectName if present */
387 1990 if ((n = X509_get_subject_name(x509_input)) != NULL)
388 {
389 1990 X509_NAME_free(output_name->x509n);
390
391 1990 output_name->x509n = X509_NAME_dup(n);
392 1990 if (output_name->x509n == NULL)
393 {
394 0 GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status);
395 0 major_status = GSS_S_FAILURE;
396
397 0 goto release_name_out;
398 }
399 1990 output_name->x509n_oneline =
400 X509_NAME_oneline(output_name->x509n, NULL, 0);
401 1990 if (output_name->x509n_oneline == NULL)
402 {
403 0 GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status);
404 0 major_status = GSS_S_FAILURE;
405
406 0 goto release_name_out;
407 }
408 1990 output_name->host_name =
409 (char *) globus_i_gsi_gssapi_get_hostname(output_name);
410 1990 if (output_name->host_name == NULL)
411 {
412 0 GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status);
413 0 major_status = GSS_S_FAILURE;
414
415 0 goto release_name_out;
416 }
417 }
418
419 /* Extract subjectAltName if present */
420 1990 idx = -1;
421 1990 for (idx = X509_get_ext_by_NID(x509_input, NID_subject_alt_name, idx);
422 4028 idx != -1;
423 48 idx = X509_get_ext_by_NID(x509_input, NID_subject_alt_name, idx))
424 {
425 X509_EXTENSION * ext_value;
426
427 48 ext_value = X509_get_ext(x509_input, idx);
428 48 if (!ext_value)
429 {
430 0 continue;
431 }
432 48 subject_alt_name = X509V3_EXT_d2i(ext_value);
433 48 if (!subject_alt_name)
434 {
435 0 continue;
436 }
437
438 48 output_name->subjectAltNames =
439 sk_GENERAL_NAME_dup(subject_alt_name);
440 48 sk_GENERAL_NAME_free(subject_alt_name);
441 48 if (output_name->subjectAltNames == NULL)
442 {
443 0 GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status);
444 0 major_status = GSS_S_FAILURE;
445
446 0 goto release_name_out;
447 }
448 }
449 }
450 else
451 {
452 0 GLOBUS_GSI_GSSAPI_ERROR_RESULT(
453 minor_status,
454 GLOBUS_GSI_GSSAPI_ERROR_BAD_NAME,
455 (_GGSL("Bad name type")));
456
457 0 major_status = GSS_S_BAD_NAMETYPE;
458
459 0 goto release_name_out;
460 }
461
462 2310 if (major_status != GSS_S_COMPLETE)
463 {
464 OM_uint32 dummy;
465 2 release_name_out:
466 2 gss_release_name(&dummy, &output_name);
467 }
468
469 2312 *output_name_P = output_name;
470
471 2318 out:
472
473 2318 GLOBUS_I_GSI_GSSAPI_DEBUG_EXIT;
474 2318 return major_status;
475 }
476 /* gss_import_name */
477
478
479 static
480 OM_uint32
481 gss_l_resolve_ip(
482 OM_uint32 * minor_status,
483 gss_name_desc * name)
484 52 {
485 char realhostname[NI_MAXHOST + 1];
486 OM_uint32 major_status;
487 52 globus_result_t result = GLOBUS_SUCCESS;
488 globus_addrinfo_t hints;
489 52 globus_addrinfo_t * addrinfo = NULL;
490 static char * _function_name_ = "gss_l_resolve_ip";
491
492 52 major_status = GSS_S_COMPLETE;
493
494 52 memset(&hints, 0, sizeof(globus_addrinfo_t));
495 52 hints.ai_family = PF_UNSPEC;
496 52 hints.ai_socktype = SOCK_STREAM;
497 52 hints.ai_protocol = 0;
498
499 /*
500 * Hostname is an ip address: do a non-canonname getaddrinfo to get
501 * the sockaddr, then getnameinfo to get the canonical hostname from that
502 * address
503 */
504 52 hints.ai_flags = GLOBUS_AI_NUMERICHOST;
505 52 result = globus_libc_getaddrinfo(name->ip_address, NULL, &hints, &addrinfo);
506
507 52 if (result == GLOBUS_SUCCESS)
508 {
509 52 if (addrinfo == NULL || addrinfo->ai_addr == NULL)
510 {
511 goto error_exit;
512 }
513
514 /*
515 * For connections to localhost, check for certificate
516 * matching our real hostname, not "localhost"
517 */
518 52 if (globus_libc_addr_is_loopback(
519 (const globus_sockaddr_t *) addrinfo->ai_addr) == GLOBUS_TRUE)
520 {
521 0 globus_libc_gethostname(
522 realhostname, sizeof(realhostname) - 1);
523 }
524 else
525 {
526 /* use GLOBUS_NI_NAMEREQD to fail if address can't be looked up?
527 * if not, realhostname will just be the same ip address
528 * we pass in */
529 52 result = globus_libc_getnameinfo(
530 (const globus_sockaddr_t *) addrinfo->ai_addr,
531 realhostname,
532 sizeof(realhostname) - 1,
533 NULL,
534 0,
535 0);
536 52 if(result != GLOBUS_SUCCESS)
537 {
538 0 goto error_exit;
539 }
540 }
541 }
542 else
543 {
544 0 goto error_exit;
545 }
546
547 52 name->ip_name = globus_libc_strdup(realhostname);
548 52 if (name->ip_name == NULL)
549 {
550 0 GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status);
551 0 major_status = GSS_S_FAILURE;
552 }
553
554 52 error_exit:
555 52 if (addrinfo != NULL)
556 {
557 52 globus_libc_freeaddrinfo(addrinfo);
558 }
559 52 return major_status;
560 }