fbd4b8a6e347c7f6c941247648949b06c015908b
[moonshot.git] / moonshot / 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     gss_name_t name = GSS_C_NO_NAME;
343     gss_OID mechanismUsed = GSS_C_NO_OID;
344
345     GSSEAP_KRB_INIT(&krbContext);
346
347     p = (unsigned char *)nameBuffer->value;
348     remain = nameBuffer->length;
349
350     if (flags & EXPORT_NAME_FLAG_OID) {
351         gss_OID_desc mech;
352         enum gss_eap_token_type tokType;
353         uint16_t wireTokType;
354
355         /* TOK_ID || MECH_OID_LEN || MECH_OID */
356         if (remain < 6) {
357             *minor = GSSEAP_BAD_NAME_TOKEN;
358             return GSS_S_BAD_NAME;
359         }
360
361         if (flags & EXPORT_NAME_FLAG_COMPOSITE)
362             tokType = TOK_TYPE_EXPORT_NAME_COMPOSITE;
363         else
364             tokType = TOK_TYPE_EXPORT_NAME;
365
366         /* TOK_ID */
367         wireTokType = load_uint16_be(p);
368
369         if ((flags & EXPORT_NAME_FLAG_ALLOW_COMPOSITE) &&
370             wireTokType == TOK_TYPE_EXPORT_NAME_COMPOSITE) {
371             tokType = TOK_TYPE_EXPORT_NAME_COMPOSITE;
372             flags |= EXPORT_NAME_FLAG_COMPOSITE;
373         }
374
375         if (wireTokType != tokType) {
376             *minor = GSSEAP_WRONG_TOK_ID;
377             return GSS_S_BAD_NAME;
378         }
379         UPDATE_REMAIN(2);
380
381         /* MECH_OID_LEN */
382         len = load_uint16_be(p);
383         if (len < 2) {
384             *minor = GSSEAP_BAD_NAME_TOKEN;
385             return GSS_S_BAD_NAME;
386         }
387         UPDATE_REMAIN(2);
388
389         /* MECH_OID */
390         if (p[0] != 0x06) {
391             *minor = GSSEAP_BAD_NAME_TOKEN;
392             return GSS_S_BAD_NAME;
393         }
394
395         mech.length = p[1];
396         mech.elements = &p[2];
397
398         CHECK_REMAIN(mech.length);
399
400         major = gssEapCanonicalizeOid(minor,
401                                       &mech,
402                                       OID_FLAG_FAMILY_MECH_VALID |
403                                         OID_FLAG_MAP_FAMILY_MECH_TO_NULL,
404                                       &mechanismUsed);
405         if (GSS_ERROR(major))
406             goto cleanup;
407
408         UPDATE_REMAIN(2 + mech.length);
409     }
410
411     /* NAME_LEN */
412     CHECK_REMAIN(4);
413     len = load_uint32_be(p);
414     UPDATE_REMAIN(4);
415
416     /* NAME */
417     CHECK_REMAIN(len);
418     buf.length = len;
419     buf.value = p;
420     UPDATE_REMAIN(len);
421
422     major = importEapNameFlags(minor, &buf, 0, &name);
423     if (GSS_ERROR(major))
424         goto cleanup;
425
426     name->mechanismUsed = mechanismUsed;
427     mechanismUsed = GSS_C_NO_OID;
428
429     if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
430         gss_buffer_desc buf;
431
432         buf.length = remain;
433         buf.value = p;
434
435         major = gssEapImportAttrContext(minor, &buf, name);
436         if (GSS_ERROR(major))
437             goto cleanup;
438     }
439
440     major = GSS_S_COMPLETE;
441     *minor = 0;
442
443 cleanup:
444     if (GSS_ERROR(major)) {
445         gssEapReleaseOid(&tmpMinor, &mechanismUsed);
446         gssEapReleaseName(&tmpMinor, &name);
447     } else {
448         *pName = name;
449     }
450
451     return major;
452 }
453
454 static OM_uint32
455 importExportName(OM_uint32 *minor,
456                  const gss_buffer_t nameBuffer,
457                  gss_name_t *name)
458 {
459     return gssEapImportNameInternal(minor, nameBuffer, name,
460                                     EXPORT_NAME_FLAG_OID |
461                                     EXPORT_NAME_FLAG_ALLOW_COMPOSITE);
462 }
463
464 #ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT
465 static OM_uint32
466 importCompositeExportName(OM_uint32 *minor,
467                           const gss_buffer_t nameBuffer,
468                           gss_name_t *name)
469 {
470     return gssEapImportNameInternal(minor, nameBuffer, name,
471                                     EXPORT_NAME_FLAG_OID |
472                                     EXPORT_NAME_FLAG_COMPOSITE);
473 }
474 #endif
475
476 struct gss_eap_name_import_provider {
477     gss_const_OID oid;
478     OM_uint32 (*import)(OM_uint32 *, const gss_buffer_t, gss_name_t *);
479 };
480
481 OM_uint32
482 gssEapImportName(OM_uint32 *minor,
483                  const gss_buffer_t nameBuffer,
484                  const gss_OID nameType,
485                  const gss_OID mechType,
486                  gss_name_t *pName)
487 {
488     struct gss_eap_name_import_provider nameTypes[] = {
489         { GSS_EAP_NT_EAP_NAME,              importEapName               },
490         { GSS_C_NT_USER_NAME,               importUserName              },
491         { GSS_C_NT_HOSTBASED_SERVICE,       importServiceName           },
492         { GSS_C_NT_HOSTBASED_SERVICE_X,     importServiceName           },
493         { GSS_C_NT_ANONYMOUS,               importAnonymousName         },
494         { GSS_C_NT_EXPORT_NAME,             importExportName            },
495         { GSS_KRB5_NT_PRINCIPAL_NAME,       importUserName              },
496 #ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT
497         { GSS_C_NT_COMPOSITE_EXPORT,        importCompositeExportName   },
498 #endif
499     };
500     size_t i;
501     OM_uint32 major = GSS_S_BAD_NAMETYPE;
502     OM_uint32 tmpMinor;
503     gss_name_t name = GSS_C_NO_NAME;
504
505     for (i = 0; i < sizeof(nameTypes) / sizeof(nameTypes[0]); i++) {
506         if (oidEqual(nameTypes[i].oid,
507                      nameType == GSS_C_NO_OID ? GSS_EAP_NT_EAP_NAME : nameType)) {
508             major = nameTypes[i].import(minor, nameBuffer, &name);
509             break;
510         }
511     }
512
513     if (major == GSS_S_COMPLETE &&
514         mechType != GSS_C_NO_OID) {
515         assert(gssEapIsConcreteMechanismOid(mechType));
516         assert(name->mechanismUsed == GSS_C_NO_OID);
517
518         major = gssEapCanonicalizeOid(minor, mechType, 0, &name->mechanismUsed);
519     }
520
521     if (GSS_ERROR(major))
522         gssEapReleaseName(&tmpMinor, &name);
523     else
524         *pName = name;
525
526     return major;
527 }
528
529 OM_uint32
530 gssEapExportName(OM_uint32 *minor,
531                  const gss_name_t name,
532                  gss_buffer_t exportedName)
533 {
534     return gssEapExportNameInternal(minor, name, exportedName,
535                                     EXPORT_NAME_FLAG_OID);
536 }
537
538 OM_uint32
539 gssEapExportNameInternal(OM_uint32 *minor,
540                          const gss_name_t name,
541                          gss_buffer_t exportedName,
542                          OM_uint32 flags)
543 {
544     OM_uint32 major = GSS_S_FAILURE, tmpMinor;
545     gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
546     size_t exportedNameLen;
547     unsigned char *p;
548     gss_buffer_desc attrs = GSS_C_EMPTY_BUFFER;
549     gss_OID mech;
550
551     exportedName->length = 0;
552     exportedName->value = NULL;
553
554     if (name->mechanismUsed != GSS_C_NO_OID)
555         mech = name->mechanismUsed;
556     else
557         mech = GSS_EAP_MECHANISM;
558
559     major = gssEapDisplayName(minor, name, &nameBuf, NULL);
560     if (GSS_ERROR(major))
561         goto cleanup;
562
563     exportedNameLen = 0;
564     if (flags & EXPORT_NAME_FLAG_OID) {
565         exportedNameLen += 6 + mech->length;
566     }
567     exportedNameLen += 4 + nameBuf.length;
568     if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
569         major = gssEapExportAttrContext(minor, name, &attrs);
570         if (GSS_ERROR(major))
571             goto cleanup;
572         exportedNameLen += attrs.length;
573     }
574
575     exportedName->value = GSSEAP_MALLOC(exportedNameLen);
576     if (exportedName->value == NULL) {
577         major = GSS_S_FAILURE;
578         *minor = ENOMEM;
579         goto cleanup;
580     }
581     exportedName->length = exportedNameLen;
582
583     p = (unsigned char *)exportedName->value;
584
585     if (flags & EXPORT_NAME_FLAG_OID) {
586         /* TOK | MECH_OID_LEN */
587         store_uint16_be((flags & EXPORT_NAME_FLAG_COMPOSITE)
588                         ? TOK_TYPE_EXPORT_NAME_COMPOSITE
589                         : TOK_TYPE_EXPORT_NAME,
590                         p);
591         p += 2;
592         store_uint16_be(mech->length + 2, p);
593         p += 2;
594
595         /* MECH_OID */
596         *p++ = 0x06;
597         *p++ = mech->length & 0xff;
598         memcpy(p, mech->elements, mech->length);
599         p += mech->length;
600     }
601
602     /* NAME_LEN */
603     store_uint32_be(nameBuf.length, p);
604     p += 4;
605
606     /* NAME */
607     memcpy(p, nameBuf.value, nameBuf.length);
608     p += nameBuf.length;
609
610     if (flags & EXPORT_NAME_FLAG_COMPOSITE) {
611         memcpy(p, attrs.value, attrs.length);
612         p += attrs.length;
613     }
614
615     assert(p == (unsigned char *)exportedName->value + exportedNameLen);
616
617     major = GSS_S_COMPLETE;
618     *minor = 0;
619
620 cleanup:
621     gss_release_buffer(&tmpMinor, &attrs);
622     gss_release_buffer(&tmpMinor, &nameBuf);
623     if (GSS_ERROR(major))
624         gss_release_buffer(&tmpMinor, exportedName);
625
626     return major;
627 }
628
629 OM_uint32
630 gssEapCanonicalizeName(OM_uint32 *minor,
631                        const gss_name_t input_name,
632                        const gss_OID mech_type,
633                        gss_name_t *dest_name)
634 {
635     OM_uint32 major, tmpMinor;
636     krb5_context krbContext;
637     gss_name_t name;
638     gss_OID mech_used;
639
640     if (input_name == GSS_C_NO_NAME) {
641         *minor = EINVAL;
642         return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
643     }
644
645     GSSEAP_KRB_INIT(&krbContext);
646
647     major = gssEapAllocName(minor, &name);
648     if (GSS_ERROR(major)) {
649         return major;
650     }
651
652     if (mech_type != GSS_C_NO_OID)
653         mech_used = mech_type;
654     else
655         mech_used = input_name->mechanismUsed;
656
657     major = gssEapCanonicalizeOid(minor,
658                                   mech_used,
659                                   OID_FLAG_NULL_VALID,
660                                   &name->mechanismUsed);
661     if (GSS_ERROR(major))
662         goto cleanup;
663
664     name->flags = input_name->flags;
665
666     *minor = krb5_copy_principal(krbContext, input_name->krbPrincipal,
667                                  &name->krbPrincipal);
668     if (*minor != 0) {
669         major = GSS_S_FAILURE;
670         goto cleanup;
671     }
672
673     if (input_name->attrCtx != NULL) {
674         major = gssEapDuplicateAttrContext(minor, input_name, name);
675         if (GSS_ERROR(major))
676             goto cleanup;
677     }
678
679     *dest_name = name;
680
681 cleanup:
682     if (GSS_ERROR(major)) {
683         gssEapReleaseName(&tmpMinor, &name);
684     }
685
686     return major;
687 }
688
689 OM_uint32
690 gssEapDuplicateName(OM_uint32 *minor,
691                     const gss_name_t input_name,
692                     gss_name_t *dest_name)
693 {
694     return gssEapCanonicalizeName(minor, input_name,
695                                   GSS_C_NO_OID, dest_name);
696 }
697
698 OM_uint32
699 gssEapDisplayName(OM_uint32 *minor,
700                   gss_name_t name,
701                   gss_buffer_t output_name_buffer,
702                   gss_OID *output_name_type)
703 {
704     OM_uint32 major;
705     krb5_context krbContext;
706     char *krbName;
707     gss_OID name_type;
708     int flags = 0;
709
710     GSSEAP_KRB_INIT(&krbContext);
711
712     output_name_buffer->length = 0;
713     output_name_buffer->value = NULL;
714
715     if (name == GSS_C_NO_NAME) {
716         *minor = EINVAL;
717         return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME;
718     }
719
720     /*
721      * According to draft-ietf-abfab-gss-eap-01, when the realm is
722      * absent the trailing '@' is not included.
723      */
724 #ifdef HAVE_HEIMDAL_VERSION
725     if (KRB_PRINC_REALM(name->krbPrincipal) == NULL ||
726         KRB_PRINC_REALM(name->krbPrincipal)[0] == '\0')
727 #else
728     if (KRB_PRINC_REALM(name->krbPrincipal)->length == 0)
729 #endif
730         flags |= KRB5_PRINCIPAL_UNPARSE_NO_REALM;
731
732     *minor = krb5_unparse_name_flags(krbContext, name->krbPrincipal,
733                                      flags, &krbName);
734     if (*minor != 0) {
735         return GSS_S_FAILURE;
736     }
737
738     major = makeStringBuffer(minor, krbName, output_name_buffer);
739     if (GSS_ERROR(major)) {
740         krb5_free_unparsed_name(krbContext, krbName);
741         return major;
742     }
743
744     krb5_free_unparsed_name(krbContext, krbName);
745
746     if (output_name_buffer->length == 0) {
747         name_type = GSS_C_NT_ANONYMOUS;
748     } else if (name->flags & NAME_FLAG_NAI) {
749         name_type = GSS_C_NT_USER_NAME;
750     } else {
751         name_type = GSS_EAP_NT_EAP_NAME;
752     }
753
754     if (output_name_type != NULL)
755         *output_name_type = name_type;
756
757     return GSS_S_COMPLETE;
758 }
759
760 OM_uint32
761 gssEapCompareName(OM_uint32 *minor,
762                   gss_name_t name1,
763                   gss_name_t name2,
764                   int *name_equal)
765 {
766     krb5_context krbContext;
767
768     *minor = 0;
769
770     if (name1 == GSS_C_NO_NAME && name2 == GSS_C_NO_NAME) {
771         *name_equal = 1;
772     } else if (name1 != GSS_C_NO_NAME && name2 != GSS_C_NO_NAME) {
773         GSSEAP_KRB_INIT(&krbContext);
774
775         /* krbPrincipal is immutable, so lock not required */
776         *name_equal = krb5_principal_compare(krbContext,
777                                              name1->krbPrincipal,
778                                              name2->krbPrincipal);
779     }
780
781     return GSS_S_COMPLETE;
782 }