84478fd6478bcfaa3561f2b4c6437544e34958f1
[moonshot.git] / mech_eap / util_name.c
1 /*
2  * Copyright (c) 2011, JANET(UK)
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  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of JANET(UK) nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 /*
33  * Portions Copyright 2009 by the Massachusetts Institute of Technology.
34  * All Rights Reserved.
35  *
36  * Export of this software from the United States of America may
37  *   require a specific license from the United States Government.
38  *   It is the responsibility of any person or organization contemplating
39  *   export to obtain such a license before exporting.
40  *
41  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
42  * distribute this software and its documentation for any purpose and
43  * without fee is hereby granted, provided that the above copyright
44  * notice appear in all copies and that both that copyright notice and
45  * this permission notice appear in supporting documentation, and that
46  * the name of M.I.T. not be used in advertising or publicity pertaining
47  * to distribution of the software without specific, written prior
48  * permission.  Furthermore if you modify this software you must label
49  * your software as modified software and not distribute it in such a
50  * fashion that it might be confused with the original M.I.T. software.
51  * M.I.T. makes no representations about the suitability of
52  * this software for any purpose.  It is provided "as is" without express
53  * or implied warranty.
54  */
55
56 /*
57  * Name utility routines.
58  */
59
60 #include "gssapiP_eap.h"
61
62 static gss_OID_desc gssEapNtEapName = {
63     /* 1.3.6.1.4.1.5322.22.2.1  */
64     10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x02\x01"
65 };
66
67 gss_OID GSS_EAP_NT_EAP_NAME = &gssEapNtEapName;
68
69 OM_uint32
70 gssEapAllocName(OM_uint32 *minor, gss_name_t *pName)
71 {
72     OM_uint32 tmpMinor;
73     gss_name_t name;
74
75     *pName = GSS_C_NO_NAME;
76
77     name = (gss_name_t)GSSEAP_CALLOC(1, sizeof(*name));
78     if (name == NULL) {
79         *minor = ENOMEM;
80         return GSS_S_FAILURE;
81     }
82
83     if (GSSEAP_MUTEX_INIT(&name->mutex) != 0) {
84         *minor = errno;
85         gssEapReleaseName(&tmpMinor, &name);
86         return GSS_S_FAILURE;
87     }
88
89     *pName = name;
90
91     return GSS_S_COMPLETE;
92 }
93
94 OM_uint32
95 gssEapReleaseName(OM_uint32 *minor, gss_name_t *pName)
96 {
97     gss_name_t name;
98     krb5_context krbContext = NULL;
99     OM_uint32 tmpMinor;
100
101     *minor = 0;
102
103     if (pName == NULL) {
104         return GSS_S_COMPLETE;
105     }
106
107     name = *pName;
108     if (name == GSS_C_NO_NAME) {
109         return GSS_S_COMPLETE;
110     }
111
112     GSSEAP_KRB_INIT(&krbContext);
113     krb5_free_principal(krbContext, name->krbPrincipal);
114     gssEapReleaseOid(&tmpMinor, &name->mechanismUsed);
115
116     gssEapReleaseAttrContext(&tmpMinor, name);
117
118     GSSEAP_MUTEX_DESTROY(&name->mutex);
119     GSSEAP_FREE(name);
120     *pName = NULL;
121
122     return GSS_S_COMPLETE;
123 }
124
125 static OM_uint32
126 krbPrincipalToName(OM_uint32 *minor,
127                    krb5_principal *principal,
128                    gss_name_t *pName)
129 {
130     OM_uint32 major;
131     gss_name_t name;
132
133     major = gssEapAllocName(minor, &name);
134     if (GSS_ERROR(major))
135         return major;
136
137     name->krbPrincipal = *principal;
138     *principal = NULL;
139
140     if (KRB_PRINC_LENGTH(name->krbPrincipal) > 1) {
141         name->flags |= NAME_FLAG_SERVICE;
142     } else {
143         name->flags |= NAME_FLAG_NAI;
144     }
145
146     *pName = name;
147     *minor = 0;
148
149     return GSS_S_COMPLETE;
150 }
151
152 static char *
153 gssEapGetDefaultRealm(krb5_context krbContext)
154 {
155     char *defaultRealm = NULL;
156
157     krb5_appdefault_string(krbContext, "eap_gss",
158                            NULL, "default_realm", "", &defaultRealm);
159
160     return defaultRealm;
161 }
162
163 static OM_uint32
164 importServiceName(OM_uint32 *minor,
165                   const gss_buffer_t nameBuffer,
166                   gss_name_t *pName)
167 {
168     OM_uint32 major;
169     krb5_error_code code;
170     krb5_context krbContext;
171     krb5_principal krbPrinc;
172     char *service, *host, *realm = NULL;
173
174     GSSEAP_KRB_INIT(&krbContext);
175
176     major = bufferToString(minor, nameBuffer, &service);
177     if (GSS_ERROR(major))
178         return major;
179
180     host = strchr(service, '@');
181     if (host != NULL) {
182         *host = '\0';
183         host++;
184     }
185
186     realm = gssEapGetDefaultRealm(krbContext);
187
188     code = krb5_build_principal(krbContext,
189                                 &krbPrinc,
190                                 realm != NULL ? strlen(realm) : 0,
191                                 realm != NULL ? realm : "",
192                                 service,
193                                 host,
194                                 NULL);
195
196     if (code == 0) {
197         KRB_PRINC_TYPE(krbPrinc) = KRB5_NT_SRV_HST;
198
199         major = krbPrincipalToName(minor, &krbPrinc, pName);
200         if (GSS_ERROR(major))
201             krb5_free_principal(krbContext, krbPrinc);
202     } else {
203         major = GSS_S_FAILURE;
204         *minor = GSSEAP_BAD_SERVICE_NAME;
205     }
206
207     if (realm != NULL)
208         GSSEAP_FREE(realm);
209     GSSEAP_FREE(service);
210
211     return major;
212 }
213
214 #define IMPORT_FLAG_DEFAULT_REALM           0x1
215
216 /*
217  * Import an EAP name, possibly appending the default GSS EAP realm,
218  */
219 static OM_uint32
220 importEapNameFlags(OM_uint32 *minor,
221                    const gss_buffer_t nameBuffer,
222                    OM_uint32 importFlags,
223                    gss_name_t *pName)
224 {
225     OM_uint32 major;
226     krb5_context krbContext;
227     krb5_principal krbPrinc = NULL;
228     krb5_error_code code;
229     char *nameString;
230
231     GSSEAP_KRB_INIT(&krbContext);
232
233     if (nameBuffer == GSS_C_NO_BUFFER) {
234         nameString = "";
235         code = KRB5_PARSE_MALFORMED;
236     } else {
237         major = bufferToString(minor, nameBuffer, &nameString);
238         if (GSS_ERROR(major))
239             return major;
240
241         /*
242          * First, attempt to parse the name on the assumption that it includes
243          * a qualifying realm. This allows us to avoid accidentally appending
244          * the default Kerberos realm to an unqualified name. (A bug in MIT
245          * Kerberos prevents the default realm being set to an empty value.)
246          */
247         code = krb5_parse_name_flags(krbContext, nameString,
248                                      KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &krbPrinc);
249     }
250
251     if (code == KRB5_PARSE_MALFORMED) {
252         char *defaultRealm = NULL;
253         int parseFlags = 0;
254
255         /* Possibly append the default EAP realm if required */
256         if (importFlags & IMPORT_FLAG_DEFAULT_REALM)
257             defaultRealm = gssEapGetDefaultRealm(krbContext);
258
259         /* If no default realm, leave the realm empty in the parsed name */
260         if (defaultRealm == NULL || defaultRealm[0] == '\0')
261             parseFlags |= KRB5_PRINCIPAL_PARSE_NO_REALM;
262
263         code = krb5_parse_name_flags(krbContext, nameString, parseFlags, &krbPrinc);
264
265 #ifdef HAVE_HEIMDAL_VERSION
266         if (code == 0 && KRB_PRINC_REALM(krbPrinc) == NULL) {
267             KRB_PRINC_REALM(krbPrinc) = GSSEAP_CALLOC(1, sizeof(char));
268             if (KRB_PRINC_REALM(krbPrinc) == NULL)
269                 code = ENOMEM;
270         }
271 #endif
272
273         if (defaultRealm != NULL)
274             GSSEAP_FREE(defaultRealm);
275     }
276
277     if (nameBuffer != GSS_C_NO_BUFFER)
278         GSSEAP_FREE(nameString);
279
280     if (code != 0) {
281         *minor = code;
282         return GSS_S_FAILURE;
283     }
284
285     assert(krbPrinc != NULL);
286
287     major = krbPrincipalToName(minor, &krbPrinc, pName);
288     if (GSS_ERROR(major))
289         krb5_free_principal(krbContext, krbPrinc);
290
291     return major;
292 }
293
294 static OM_uint32
295 importEapName(OM_uint32 *minor,
296               const gss_buffer_t nameBuffer,
297               gss_name_t *pName)
298 {
299     return importEapNameFlags(minor, nameBuffer, 0, pName);
300 }
301
302 static OM_uint32
303 importUserName(OM_uint32 *minor,
304                const gss_buffer_t nameBuffer,
305                gss_name_t *pName)
306 {
307     return importEapNameFlags(minor, nameBuffer, IMPORT_FLAG_DEFAULT_REALM, pName);
308 }
309
310 static OM_uint32
311 importAnonymousName(OM_uint32 *minor,
312                     const gss_buffer_t nameBuffer GSSEAP_UNUSED,
313                     gss_name_t *pName)
314 {
315     return importEapNameFlags(minor, GSS_C_NO_BUFFER, 0, pName);
316 }
317
318 #define UPDATE_REMAIN(n)    do {            \
319         p += (n);                           \
320         remain -= (n);                      \
321     } while (0)
322
323 #define CHECK_REMAIN(n)     do {        \
324         if (remain < (n)) {             \
325             major = GSS_S_BAD_NAME;     \
326             *minor = GSSEAP_TOK_TRUNC;  \
327             goto cleanup;               \
328         }                               \
329     } while (0)
330
331 OM_uint32
332 gssEapImportNameInternal(OM_uint32 *minor,
333                          const gss_buffer_t nameBuffer,
334                          gss_name_t *pName,
335                          OM_uint32 flags)
336 {
337     OM_uint32 major, tmpMinor;
338     krb5_context krbContext;
339     unsigned char *p;
340     size_t len, remain;
341     gss_buffer_desc buf;
342     enum gss_eap_token_type tokType;
343     gss_name_t name = GSS_C_NO_NAME;
344     gss_OID mechanismUsed = GSS_C_NO_OID;
345
346     GSSEAP_KRB_INIT(&krbContext);
347
348     p = (unsigned char *)nameBuffer->value;
349     remain = nameBuffer->length;
350
351     if (flags & EXPORT_NAME_FLAG_OID) {
352         gss_OID_desc mech;
353
354         /* TOK_ID || MECH_OID_LEN || MECH_OID */
355         if (remain < 6) {
356             *minor = GSSEAP_BAD_NAME_TOKEN;
357             return GSS_S_BAD_NAME;
358         }
359
360         if (flags & EXPORT_NAME_FLAG_COMPOSITE)
361             tokType = TOK_TYPE_EXPORT_NAME_COMPOSITE;
362         else
363             tokType = TOK_TYPE_EXPORT_NAME;
364
365         /* TOK_ID */
366         if (load_uint16_be(p) != tokType) {
367             *minor = GSSEAP_WRONG_TOK_ID;
368             return GSS_S_BAD_NAME;
369         }
370         UPDATE_REMAIN(2);
371
372         /* MECH_OID_LEN */
373         len = load_uint16_be(p);
374         if (len < 2) {
375             *minor = GSSEAP_BAD_NAME_TOKEN;
376             return GSS_S_BAD_NAME;
377         }
378         UPDATE_REMAIN(2);
379
380         /* MECH_OID */
381         if (p[0] != 0x06) {
382             *minor = GSSEAP_BAD_NAME_TOKEN;
383             return GSS_S_BAD_NAME;
384         }
385
386         mech.length = p[1];
387         mech.elements = &p[2];
388
389         CHECK_REMAIN(mech.length);
390
391         major = gssEapCanonicalizeOid(minor,
392                                       &mech,
393                                       OID_FLAG_FAMILY_MECH_VALID |
394                                         OID_FLAG_MAP_FAMILY_MECH_TO_NULL,
395                                       &mechanismUsed);
396         if (GSS_ERROR(major))
397             goto cleanup;
398
399         UPDATE_REMAIN(2 + mech.length);
400     }
401
402     /* NAME_LEN */
403     CHECK_REMAIN(4);
404     len = load_uint32_be(p);
405     UPDATE_REMAIN(4);
406
407     /* NAME */
408     CHECK_REMAIN(len);
409     buf.length = len;
410     buf.value = p;
411     UPDATE_REMAIN(len);
412
413     major = importEapNameFlags(minor, &buf, 0, &name);
414     if (GSS_ERROR(major))
415         goto cleanup;
416
417     name->mechanismUsed = mechanismUsed;
418     mechanismUsed = GSS_C_NO_OID;
419
420     if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
421         gss_buffer_desc buf;
422
423         buf.length = remain;
424         buf.value = p;
425
426         major = gssEapImportAttrContext(minor, &buf, name);
427         if (GSS_ERROR(major))
428             goto cleanup;
429     }
430
431     major = GSS_S_COMPLETE;
432     *minor = 0;
433
434 cleanup:
435     if (GSS_ERROR(major)) {
436         gssEapReleaseOid(&tmpMinor, &mechanismUsed);
437         gssEapReleaseName(&tmpMinor, &name);
438     } else {
439         *pName = name;
440     }
441
442     return major;
443 }
444
445 static OM_uint32
446 importExportName(OM_uint32 *minor,
447                  const gss_buffer_t nameBuffer,
448                  gss_name_t *name)
449 {
450     return gssEapImportNameInternal(minor, nameBuffer, name,
451                                     EXPORT_NAME_FLAG_OID);
452 }
453
454 #ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT
455 static OM_uint32
456 importCompositeExportName(OM_uint32 *minor,
457                           const gss_buffer_t nameBuffer,
458                           gss_name_t *name)
459 {
460     return gssEapImportNameInternal(minor, nameBuffer, name,
461                                     EXPORT_NAME_FLAG_OID |
462                                     EXPORT_NAME_FLAG_COMPOSITE);
463 }
464 #endif
465
466 struct gss_eap_name_import_provider {
467     gss_const_OID oid;
468     OM_uint32 (*import)(OM_uint32 *, const gss_buffer_t, gss_name_t *);
469 };
470
471 OM_uint32
472 gssEapImportName(OM_uint32 *minor,
473                  const gss_buffer_t nameBuffer,
474                  const gss_OID nameType,
475                  const gss_OID mechType,
476                  gss_name_t *pName)
477 {
478     struct gss_eap_name_import_provider nameTypes[] = {
479         { GSS_EAP_NT_EAP_NAME,              importEapName               },
480         { GSS_C_NT_USER_NAME,               importUserName              },
481         { GSS_C_NT_HOSTBASED_SERVICE,       importServiceName           },
482         { GSS_C_NT_HOSTBASED_SERVICE_X,     importServiceName           },
483         { GSS_C_NT_ANONYMOUS,               importAnonymousName         },
484         { GSS_C_NT_EXPORT_NAME,             importExportName            },
485         { GSS_KRB5_NT_PRINCIPAL_NAME,       importUserName              },
486 #ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT
487         { GSS_C_NT_COMPOSITE_EXPORT,        importCompositeExportName   },
488 #endif
489     };
490     size_t i;
491     OM_uint32 major = GSS_S_BAD_NAMETYPE;
492     OM_uint32 tmpMinor;
493     gss_name_t name = GSS_C_NO_NAME;
494
495     for (i = 0; i < sizeof(nameTypes) / sizeof(nameTypes[0]); i++) {
496         if (oidEqual(nameTypes[i].oid,
497                      nameType == GSS_C_NO_OID ? GSS_EAP_NT_EAP_NAME : nameType)) {
498             major = nameTypes[i].import(minor, nameBuffer, &name);
499             break;
500         }
501     }
502
503     if (major == GSS_S_COMPLETE &&
504         mechType != GSS_C_NO_OID) {
505         assert(gssEapIsConcreteMechanismOid(mechType));
506         assert(name->mechanismUsed == GSS_C_NO_OID);
507
508         major = gssEapCanonicalizeOid(minor, mechType, 0, &name->mechanismUsed);
509     }
510
511     if (GSS_ERROR(major))
512         gssEapReleaseName(&tmpMinor, &name);
513     else
514         *pName = name;
515
516     return major;
517 }
518
519 OM_uint32
520 gssEapExportName(OM_uint32 *minor,
521                  const gss_name_t name,
522                  gss_buffer_t exportedName)
523 {
524     return gssEapExportNameInternal(minor, name, exportedName,
525                                     EXPORT_NAME_FLAG_OID);
526 }
527
528 OM_uint32
529 gssEapExportNameInternal(OM_uint32 *minor,
530                          const gss_name_t name,
531                          gss_buffer_t exportedName,
532                          OM_uint32 flags)
533 {
534     OM_uint32 major = GSS_S_FAILURE, tmpMinor;
535     gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
536     size_t exportedNameLen;
537     unsigned char *p;
538     gss_buffer_desc attrs = GSS_C_EMPTY_BUFFER;
539     gss_OID mech;
540
541     exportedName->length = 0;
542     exportedName->value = NULL;
543
544     if (name->mechanismUsed != GSS_C_NO_OID)
545         mech = name->mechanismUsed;
546     else
547         mech = GSS_EAP_MECHANISM;
548
549     major = gssEapDisplayName(minor, name, &nameBuf, NULL);
550     if (GSS_ERROR(major))
551         goto cleanup;
552
553     exportedNameLen = 0;
554     if (flags & EXPORT_NAME_FLAG_OID) {
555         exportedNameLen += 6 + mech->length;
556     }
557     exportedNameLen += 4 + nameBuf.length;
558     if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
559         major = gssEapExportAttrContext(minor, name, &attrs);
560         if (GSS_ERROR(major))
561             goto cleanup;
562         exportedNameLen += attrs.length;
563     }
564
565     exportedName->value = GSSEAP_MALLOC(exportedNameLen);
566     if (exportedName->value == NULL) {
567         major = GSS_S_FAILURE;
568         *minor = ENOMEM;
569         goto cleanup;
570     }
571     exportedName->length = exportedNameLen;
572
573     p = (unsigned char *)exportedName->value;
574
575     if (flags & EXPORT_NAME_FLAG_OID) {
576         /* TOK | MECH_OID_LEN */
577         store_uint16_be((flags & EXPORT_NAME_FLAG_COMPOSITE)
578                         ? TOK_TYPE_EXPORT_NAME_COMPOSITE
579                         : TOK_TYPE_EXPORT_NAME,
580                         p);
581         p += 2;
582         store_uint16_be(mech->length + 2, p);
583         p += 2;
584
585         /* MECH_OID */
586         *p++ = 0x06;
587         *p++ = mech->length & 0xff;
588         memcpy(p, mech->elements, mech->length);
589         p += mech->length;
590     }
591
592     /* NAME_LEN */
593     store_uint32_be(nameBuf.length, p);
594     p += 4;
595
596     /* NAME */
597     memcpy(p, nameBuf.value, nameBuf.length);
598     p += nameBuf.length;
599
600     if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
601         memcpy(p, attrs.value, attrs.length);
602         p += attrs.length;
603     }
604
605     assert(p == (unsigned char *)exportedName->value + exportedNameLen);
606
607     major = GSS_S_COMPLETE;
608     *minor = 0;
609
610 cleanup:
611     gss_release_buffer(&tmpMinor, &attrs);
612     gss_release_buffer(&tmpMinor, &nameBuf);
613     if (GSS_ERROR(major))
614         gss_release_buffer(&tmpMinor, exportedName);
615
616     return major;
617 }
618
619 OM_uint32
620 gssEapCanonicalizeName(OM_uint32 *minor,
621                        const gss_name_t input_name,
622                        const gss_OID mech_type,
623                        gss_name_t *dest_name)
624 {
625     OM_uint32 major, tmpMinor;
626     krb5_context krbContext;
627     gss_name_t name;
628     gss_OID mech_used;
629
630     if (input_name == GSS_C_NO_NAME) {
631         *minor = EINVAL;
632         return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
633     }
634
635     GSSEAP_KRB_INIT(&krbContext);
636
637     major = gssEapAllocName(minor, &name);
638     if (GSS_ERROR(major)) {
639         return major;
640     }
641
642     if (mech_type != GSS_C_NO_OID)
643         mech_used = mech_type;
644     else
645         mech_used = input_name->mechanismUsed;
646
647     major = gssEapCanonicalizeOid(minor,
648                                   mech_used,
649                                   OID_FLAG_NULL_VALID,
650                                   &name->mechanismUsed);
651     if (GSS_ERROR(major))
652         goto cleanup;
653
654     name->flags = input_name->flags;
655
656     *minor = krb5_copy_principal(krbContext, input_name->krbPrincipal,
657                                  &name->krbPrincipal);
658     if (*minor != 0) {
659         major = GSS_S_FAILURE;
660         goto cleanup;
661     }
662
663     if (input_name->attrCtx != NULL) {
664         major = gssEapDuplicateAttrContext(minor, input_name, name);
665         if (GSS_ERROR(major))
666             goto cleanup;
667     }
668
669     *dest_name = name;
670
671 cleanup:
672     if (GSS_ERROR(major)) {
673         gssEapReleaseName(&tmpMinor, &name);
674     }
675
676     return major;
677 }
678
679 OM_uint32
680 gssEapDuplicateName(OM_uint32 *minor,
681                     const gss_name_t input_name,
682                     gss_name_t *dest_name)
683 {
684     return gssEapCanonicalizeName(minor, input_name,
685                                   GSS_C_NO_OID, dest_name);
686 }
687
688 OM_uint32
689 gssEapDisplayName(OM_uint32 *minor,
690                   gss_name_t name,
691                   gss_buffer_t output_name_buffer,
692                   gss_OID *output_name_type)
693 {
694     OM_uint32 major;
695     krb5_context krbContext;
696     char *krbName;
697     gss_OID name_type;
698     int flags = 0;
699
700     GSSEAP_KRB_INIT(&krbContext);
701
702     output_name_buffer->length = 0;
703     output_name_buffer->value = NULL;
704
705     if (name == GSS_C_NO_NAME) {
706         *minor = EINVAL;
707         return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
708     }
709
710     /*
711      * According to draft-ietf-abfab-gss-eap-01, when the realm is
712      * absent the trailing '@' is not included.
713      */
714 #ifdef HAVE_HEIMDAL_VERSION
715     if (KRB_PRINC_REALM(name->krbPrincipal) == NULL ||
716         KRB_PRINC_REALM(name->krbPrincipal)[0] == '\0')
717 #else
718     if (KRB_PRINC_REALM(name->krbPrincipal)->length == 0)
719 #endif
720         flags |= KRB5_PRINCIPAL_UNPARSE_NO_REALM;
721
722     *minor = krb5_unparse_name_flags(krbContext, name->krbPrincipal,
723                                      flags, &krbName);
724     if (*minor != 0) {
725         return GSS_S_FAILURE;
726     }
727
728     major = makeStringBuffer(minor, krbName, output_name_buffer);
729     if (GSS_ERROR(major)) {
730         krb5_free_unparsed_name(krbContext, krbName);
731         return major;
732     }
733
734     krb5_free_unparsed_name(krbContext, krbName);
735
736     if (output_name_buffer->length == 0) {
737         name_type = GSS_C_NT_ANONYMOUS;
738     } else if (name->flags & NAME_FLAG_NAI) {
739         name_type = GSS_C_NT_USER_NAME;
740     } else {
741         name_type = GSS_EAP_NT_EAP_NAME;
742     }
743
744     if (output_name_type != NULL)
745         *output_name_type = name_type;
746
747     return GSS_S_COMPLETE;
748 }
749
750 OM_uint32
751 gssEapCompareName(OM_uint32 *minor,
752                   gss_name_t name1,
753                   gss_name_t name2,
754                   int *name_equal)
755 {
756     krb5_context krbContext;
757
758     *minor = 0;
759
760     if (name1 == GSS_C_NO_NAME && name2 == GSS_C_NO_NAME) {
761         *name_equal = 1;
762     } else if (name1 != GSS_C_NO_NAME && name2 != GSS_C_NO_NAME) {
763         GSSEAP_KRB_INIT(&krbContext);
764
765         /* krbPrincipal is immutable, so lock not required */
766         *name_equal = krb5_principal_compare(krbContext,
767                                              name1->krbPrincipal,
768                                              name2->krbPrincipal);
769     }
770
771     return GSS_S_COMPLETE;
772 }