Merge remote-tracking branch 'origin/radius-new-client-pkcs12'
[mech_eap.git] / mech_eap / util_cred.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 /*
34  * Utility routines for credential handles.
35  */
36
37 #include "gssapiP_eap.h"
38
39 #ifdef WIN32
40 # include <shlobj.h>     /* may need to use ShFolder.h instead */
41 # include <stdio.h>
42 #else
43 # include <pwd.h>
44 #endif
45
46 OM_uint32
47 gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred)
48 {
49     OM_uint32 tmpMinor;
50     gss_cred_id_t cred;
51
52     *pCred = GSS_C_NO_CREDENTIAL;
53
54     cred = (gss_cred_id_t)GSSEAP_CALLOC(1, sizeof(*cred));
55     if (cred == NULL) {
56         *minor = ENOMEM;
57         return GSS_S_FAILURE;
58     }
59
60     if (GSSEAP_MUTEX_INIT(&cred->mutex) != 0) {
61         *minor = GSSEAP_GET_LAST_ERROR();
62         gssEapReleaseCred(&tmpMinor, &cred);
63         return GSS_S_FAILURE;
64     }
65
66     *pCred = cred;
67
68     *minor = 0;
69     return GSS_S_COMPLETE;
70 }
71
72 static void
73 zeroAndReleasePassword(gss_buffer_t password)
74 {
75     if (password->value != NULL) {
76         memset(password->value, 0, password->length);
77         GSSEAP_FREE(password->value);
78     }
79
80     password->value = NULL;
81     password->length = 0;
82 }
83
84 OM_uint32
85 gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred)
86 {
87     OM_uint32 tmpMinor;
88     gss_cred_id_t cred = *pCred;
89     krb5_context krbContext = NULL;
90
91     if (cred == GSS_C_NO_CREDENTIAL) {
92         return GSS_S_COMPLETE;
93     }
94
95     GSSEAP_KRB_INIT(&krbContext);
96
97     gssEapReleaseName(&tmpMinor, &cred->name);
98     gssEapReleaseName(&tmpMinor, &cred->target);
99
100     zeroAndReleasePassword(&cred->password);
101
102     gss_release_buffer(&tmpMinor, &cred->radiusConfigFile);
103     gss_release_buffer(&tmpMinor, &cred->radiusConfigStanza);
104     gss_release_buffer(&tmpMinor, &cred->caCertificate);
105     gss_release_buffer(&tmpMinor, &cred->subjectNameConstraint);
106     gss_release_buffer(&tmpMinor, &cred->subjectAltNameConstraint);
107
108 #ifdef GSSEAP_ENABLE_REAUTH
109     if (cred->krbCredCache != NULL) {
110         if (cred->flags & CRED_FLAG_DEFAULT_CCACHE)
111             krb5_cc_close(krbContext, cred->krbCredCache);
112         else
113             krb5_cc_destroy(krbContext, cred->krbCredCache);
114     }
115     if (cred->reauthCred != GSS_C_NO_CREDENTIAL)
116         gssReleaseCred(&tmpMinor, &cred->reauthCred);
117 #endif
118
119     GSSEAP_MUTEX_DESTROY(&cred->mutex);
120     memset(cred, 0, sizeof(*cred));
121     GSSEAP_FREE(cred);
122     *pCred = NULL;
123
124     *minor = 0;
125     return GSS_S_COMPLETE;
126 }
127
128 static OM_uint32
129 readStaticIdentityFile(OM_uint32 *minor,
130                        gss_buffer_t defaultIdentity,
131                        gss_buffer_t defaultPassword)
132 {
133     OM_uint32 major, tmpMinor;
134     FILE *fp = NULL;
135     char buf[BUFSIZ];
136     char *ccacheName;
137     int i = 0;
138 #ifndef WIN32
139     struct passwd *pw = NULL, pwd;
140     char pwbuf[BUFSIZ];
141 #endif
142
143     defaultIdentity->length = 0;
144     defaultIdentity->value = NULL;
145
146     if (defaultPassword != GSS_C_NO_BUFFER) {
147         defaultPassword->length = 0;
148         defaultPassword->value = NULL;
149     }
150
151     ccacheName = getenv("GSSEAP_IDENTITY");
152     if (ccacheName == NULL) {
153 #ifdef WIN32
154         TCHAR szPath[MAX_PATH];
155
156         if (!SUCCEEDED(SHGetFolderPath(NULL,
157                                        CSIDL_APPDATA, /* |CSIDL_FLAG_CREATE */
158                                        NULL, /* User access token */
159                                        0,    /* SHGFP_TYPE_CURRENT */
160                                        szPath))) {
161             major = GSS_S_CRED_UNAVAIL;
162             *minor = GSSEAP_GET_LAST_ERROR(); /* XXX */
163             goto cleanup;
164         }
165
166         snprintf(buf, sizeof(buf), "%s/.gss_eap_id", szPath);
167 #else
168         if (getpwuid_r(getuid(), &pwd, pwbuf, sizeof(pwbuf), &pw) != 0 ||
169             pw == NULL || pw->pw_dir == NULL) {
170             major = GSS_S_CRED_UNAVAIL;
171             *minor = GSSEAP_GET_LAST_ERROR();
172             goto cleanup;
173         }
174
175         snprintf(buf, sizeof(buf), "%s/.gss_eap_id", pw->pw_dir);
176 #endif /* WIN32 */
177         ccacheName = buf;
178     }
179
180     fp = fopen(ccacheName, "r");
181     if (fp == NULL) {
182         major = GSS_S_CRED_UNAVAIL;
183         *minor = GSSEAP_NO_DEFAULT_CRED;
184         goto cleanup;
185     }
186
187     while (fgets(buf, sizeof(buf), fp) != NULL) {
188         gss_buffer_desc src, *dst;
189
190         src.length = strlen(buf);
191         src.value = buf;
192
193         if (src.length == 0)
194             break;
195
196         if (buf[src.length - 1] == '\n') {
197             buf[src.length - 1] = '\0';
198             if (--src.length == 0)
199                 break;
200         }
201
202         if (i == 0)
203             dst = defaultIdentity;
204         else if (i == 1)
205             dst = defaultPassword;
206         else
207             break;
208
209         if (dst != GSS_C_NO_BUFFER) {
210             major = duplicateBuffer(minor, &src, dst);
211             if (GSS_ERROR(major))
212                 goto cleanup;
213         }
214
215         i++;
216     }
217
218     if (defaultIdentity->length == 0) {
219         major = GSS_S_CRED_UNAVAIL;
220         *minor = GSSEAP_NO_DEFAULT_CRED;
221         goto cleanup;
222     }
223
224     major = GSS_S_COMPLETE;
225     *minor = 0;
226
227 cleanup:
228     if (fp != NULL)
229         fclose(fp);
230
231     if (GSS_ERROR(major)) {
232         gss_release_buffer(&tmpMinor, defaultIdentity);
233         zeroAndReleasePassword(defaultPassword);
234     }
235
236     memset(buf, 0, sizeof(buf));
237
238     return major;
239 }
240
241 gss_OID
242 gssEapPrimaryMechForCred(gss_cred_id_t cred)
243 {
244     gss_OID credMech = GSS_C_NO_OID;
245
246     if (cred != GSS_C_NO_CREDENTIAL &&
247         cred->mechanisms != GSS_C_NO_OID_SET &&
248         cred->mechanisms->count == 1)
249         credMech = &cred->mechanisms->elements[0];
250
251     return credMech;
252 }
253
254 OM_uint32
255 gssEapAcquireCred(OM_uint32 *minor,
256                   const gss_name_t desiredName,
257                   OM_uint32 timeReq GSSEAP_UNUSED,
258                   const gss_OID_set desiredMechs,
259                   int credUsage,
260                   gss_cred_id_t *pCred,
261                   gss_OID_set *pActualMechs,
262                   OM_uint32 *timeRec)
263 {
264     OM_uint32 major, tmpMinor;
265     gss_cred_id_t cred;
266
267     /* XXX TODO validate with changed set_cred_option API */
268     *pCred = GSS_C_NO_CREDENTIAL;
269
270     major = gssEapAllocCred(minor, &cred);
271     if (GSS_ERROR(major))
272         goto cleanup;
273
274     switch (credUsage) {
275     case GSS_C_BOTH:
276         cred->flags |= CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT;
277         break;
278     case GSS_C_INITIATE:
279         cred->flags |= CRED_FLAG_INITIATE;
280         break;
281     case GSS_C_ACCEPT:
282         cred->flags |= CRED_FLAG_ACCEPT;
283         break;
284     default:
285         major = GSS_S_FAILURE;
286         *minor = GSSEAP_BAD_USAGE;
287         goto cleanup;
288         break;
289     }
290
291     major = gssEapValidateMechs(minor, desiredMechs);
292     if (GSS_ERROR(major))
293         goto cleanup;
294
295     major = duplicateOidSet(minor, desiredMechs, &cred->mechanisms);
296     if (GSS_ERROR(major))
297         goto cleanup;
298
299     if (desiredName != GSS_C_NO_NAME) {
300         GSSEAP_MUTEX_LOCK(&desiredName->mutex);
301
302         major = gssEapDuplicateName(minor, desiredName, &cred->name);
303         if (GSS_ERROR(major)) {
304             GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
305             goto cleanup;
306         }
307
308         GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
309     }
310
311 #ifdef GSSEAP_ENABLE_ACCEPTOR
312     if (cred->flags & CRED_FLAG_ACCEPT) {
313         struct rs_context *radContext;
314
315         major = gssEapCreateRadiusContext(minor, cred, &radContext);
316         if (GSS_ERROR(major))
317             goto cleanup;
318
319         rs_context_destroy(radContext);
320     }
321 #endif
322
323     if (pActualMechs != NULL) {
324         major = duplicateOidSet(minor, cred->mechanisms, pActualMechs);
325         if (GSS_ERROR(major))
326             goto cleanup;
327     }
328
329     if (timeRec != NULL)
330         *timeRec = GSS_C_INDEFINITE;
331
332     *pCred = cred;
333
334     major = GSS_S_COMPLETE;
335     *minor = 0;
336
337 cleanup:
338     if (GSS_ERROR(major))
339         gssEapReleaseCred(&tmpMinor, &cred);
340
341     return major;
342 }
343
344 /*
345  * Return TRUE if cred available for mechanism. Caller need no acquire
346  * lock because mechanisms list is immutable.
347  */
348 int
349 gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech)
350 {
351     OM_uint32 minor;
352     int present = 0;
353
354     GSSEAP_ASSERT(mech != GSS_C_NO_OID);
355
356     if (cred == GSS_C_NO_CREDENTIAL || cred->mechanisms == GSS_C_NO_OID_SET)
357         return TRUE;
358
359     gss_test_oid_set_member(&minor, mech, cred->mechanisms, &present);
360
361     return present;
362 }
363
364 static OM_uint32
365 staticIdentityFileResolveDefaultIdentity(OM_uint32 *minor,
366                                          const gss_cred_id_t cred,
367                                          gss_name_t *pName)
368 {
369     OM_uint32 major, tmpMinor;
370     gss_OID nameMech = gssEapPrimaryMechForCred(cred);
371     gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
372
373     *pName = GSS_C_NO_NAME;
374
375     major = readStaticIdentityFile(minor, &defaultIdentity, GSS_C_NO_BUFFER);
376     if (major == GSS_S_COMPLETE) {
377         major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
378                                  nameMech, pName);
379     }
380
381     gss_release_buffer(&tmpMinor, &defaultIdentity);
382
383     return major;
384 }
385
386 static OM_uint32
387 gssEapResolveCredIdentity(OM_uint32 *minor,
388                           gss_cred_id_t cred)
389 {
390     OM_uint32 major;
391     gss_OID nameMech = gssEapPrimaryMechForCred(cred);
392
393     if (cred->name != GSS_C_NO_NAME) {
394         *minor = 0;
395         return GSS_S_COMPLETE;
396     }
397
398     if (cred->flags & CRED_FLAG_ACCEPT) {
399         gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
400         char serviceName[5 + MAXHOSTNAMELEN];
401
402         /* default host-based service is host@localhost */
403         memcpy(serviceName, "host@", 5);
404         if (gethostname(&serviceName[5], MAXHOSTNAMELEN) != 0) {
405             *minor = GSSEAP_NO_HOSTNAME;
406             return GSS_S_FAILURE;
407         }
408
409         nameBuf.value = serviceName;
410         nameBuf.length = strlen((char *)nameBuf.value);
411
412         major = gssEapImportName(minor, &nameBuf, GSS_C_NT_HOSTBASED_SERVICE,
413                                  nameMech, &cred->name);
414         if (GSS_ERROR(major))
415             return major;
416     } else if (cred->flags & CRED_FLAG_INITIATE) {
417 #ifdef HAVE_MOONSHOT_GET_IDENTITY
418         major = libMoonshotResolveDefaultIdentity(minor, cred, &cred->name);
419         if (major == GSS_S_CRED_UNAVAIL)
420 #endif
421             major = staticIdentityFileResolveDefaultIdentity(minor, cred, &cred->name);
422         if (major != GSS_S_CRED_UNAVAIL)
423             return major;
424     }
425
426     *minor = 0;
427     return GSS_S_COMPLETE;
428 }
429
430 OM_uint32
431 gssEapInquireCred(OM_uint32 *minor,
432                   gss_cred_id_t cred,
433                   gss_name_t *name,
434                   OM_uint32 *pLifetime,
435                   gss_cred_usage_t *cred_usage,
436                   gss_OID_set *mechanisms)
437 {
438     OM_uint32 major;
439     time_t now, lifetime;
440
441     if (name != NULL) {
442         major = gssEapResolveCredIdentity(minor, cred);
443         if (GSS_ERROR(major))
444             goto cleanup;
445
446         if (cred->name != GSS_C_NO_NAME) {
447             major = gssEapDuplicateName(minor, cred->name, name);
448             if (GSS_ERROR(major))
449                 goto cleanup;
450         } else
451             *name = GSS_C_NO_NAME;
452     }
453
454     if (cred_usage != NULL) {
455         OM_uint32 flags = (cred->flags & (CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT));
456
457         switch (flags) {
458         case CRED_FLAG_INITIATE:
459             *cred_usage = GSS_C_INITIATE;
460             break;
461         case CRED_FLAG_ACCEPT:
462             *cred_usage = GSS_C_ACCEPT;
463             break;
464         default:
465             *cred_usage = GSS_C_BOTH;
466             break;
467         }
468     }
469
470     if (mechanisms != NULL) {
471         if (cred->mechanisms != GSS_C_NO_OID_SET)
472             major = duplicateOidSet(minor, cred->mechanisms, mechanisms);
473         else
474             major = gssEapIndicateMechs(minor, mechanisms);
475         if (GSS_ERROR(major))
476             goto cleanup;
477     }
478
479     if (cred->expiryTime == 0) {
480         lifetime = GSS_C_INDEFINITE;
481     } else  {
482         now = time(NULL);
483         lifetime = now - cred->expiryTime;
484         if (lifetime < 0)
485             lifetime = 0;
486     }
487
488     if (pLifetime != NULL) {
489         *pLifetime = lifetime;
490     }
491
492     if (lifetime == 0) {
493         major = GSS_S_CREDENTIALS_EXPIRED;
494         *minor = GSSEAP_CRED_EXPIRED;
495         goto cleanup;
496     }
497
498     major = GSS_S_COMPLETE;
499     *minor = 0;
500
501 cleanup:
502     return major;
503 }
504
505 OM_uint32
506 gssEapSetCredPassword(OM_uint32 *minor,
507                       gss_cred_id_t cred,
508                       const gss_buffer_t password)
509 {
510     OM_uint32 major, tmpMinor;
511     gss_buffer_desc newPassword = GSS_C_EMPTY_BUFFER;
512
513     if (cred->flags & CRED_FLAG_RESOLVED) {
514         major = GSS_S_FAILURE;
515         *minor = GSSEAP_CRED_RESOLVED;
516         goto cleanup;
517     }
518
519     if (password != GSS_C_NO_BUFFER) {
520         major = duplicateBuffer(minor, password, &newPassword);
521         if (GSS_ERROR(major))
522             goto cleanup;
523
524         cred->flags |= CRED_FLAG_PASSWORD;
525     } else {
526         cred->flags &= ~(CRED_FLAG_PASSWORD);
527     }
528
529     gss_release_buffer(&tmpMinor, &cred->password);
530     cred->password = newPassword;
531
532     major = GSS_S_COMPLETE;
533     *minor = 0;
534
535 cleanup:
536     return major;
537 }
538
539 OM_uint32
540 gssEapSetCredService(OM_uint32 *minor,
541                      gss_cred_id_t cred,
542                      const gss_name_t target)
543 {
544     OM_uint32 major, tmpMinor;
545     gss_name_t newTarget = GSS_C_NO_NAME;
546
547     if (cred->flags & CRED_FLAG_RESOLVED) {
548         major = GSS_S_FAILURE;
549         *minor = GSSEAP_CRED_RESOLVED;
550         goto cleanup;
551     }
552
553     if (target != GSS_C_NO_NAME) {
554         major = gssEapDuplicateName(minor, target, &newTarget);
555         if (GSS_ERROR(major))
556             goto cleanup;
557
558         cred->flags |= CRED_FLAG_TARGET;
559     } else {
560         cred->flags &= ~(CRED_FLAG_TARGET);
561     }
562
563     gssEapReleaseName(&tmpMinor, &cred->target);
564     cred->target = newTarget;
565
566     major = GSS_S_COMPLETE;
567     *minor = 0;
568
569 cleanup:
570     return major;
571 }
572
573 static OM_uint32
574 gssEapDuplicateCred(OM_uint32 *minor,
575                     const gss_cred_id_t src,
576                     gss_cred_id_t *pDst)
577 {
578     OM_uint32 major, tmpMinor;
579     gss_cred_id_t dst = GSS_C_NO_CREDENTIAL;
580
581     *pDst = GSS_C_NO_CREDENTIAL;
582
583     major = gssEapAllocCred(minor, &dst);
584     if (GSS_ERROR(major))
585         goto cleanup;
586
587     dst->flags = src->flags;
588
589     if (src->name != GSS_C_NO_NAME) {
590         major = gssEapDuplicateName(minor, src->name, &dst->name);
591         if (GSS_ERROR(major))
592             goto cleanup;
593     }
594
595     if (src->target != GSS_C_NO_NAME) {
596         major = gssEapDuplicateName(minor, src->target, &dst->target);
597         if (GSS_ERROR(major))
598             goto cleanup;
599     }
600
601     if (src->password.value != NULL) {
602         major = duplicateBuffer(minor, &src->password, &dst->password);
603         if (GSS_ERROR(major))
604             goto cleanup;
605     }
606
607     major = duplicateOidSet(minor, src->mechanisms, &dst->mechanisms);
608     if (GSS_ERROR(major))
609         goto cleanup;
610
611     dst->expiryTime = src->expiryTime;
612
613     if (src->radiusConfigFile.value != NULL)
614         duplicateBufferOrCleanup(&src->radiusConfigFile, &dst->radiusConfigFile);
615     if (src->radiusConfigStanza.value != NULL)
616         duplicateBufferOrCleanup(&src->radiusConfigStanza, &dst->radiusConfigStanza);
617     if (src->caCertificate.value != NULL)
618         duplicateBufferOrCleanup(&src->caCertificate, &dst->caCertificate);
619     if (src->subjectNameConstraint.value != NULL)
620         duplicateBufferOrCleanup(&src->subjectNameConstraint, &dst->subjectNameConstraint);
621     if (src->subjectAltNameConstraint.value != NULL)
622         duplicateBufferOrCleanup(&src->subjectAltNameConstraint, &dst->subjectAltNameConstraint);
623
624 #ifdef GSSEAP_ENABLE_REAUTH
625     /* XXX krbCredCache, reauthCred */
626 #endif
627
628     *pDst = dst;
629     dst = GSS_C_NO_CREDENTIAL;
630
631     major = GSS_S_COMPLETE;
632     *minor = 0;
633
634 cleanup:
635     gssEapReleaseCred(&tmpMinor, &dst);
636
637     return major;
638 }
639
640 static OM_uint32
641 staticIdentityFileResolveInitiatorCred(OM_uint32 *minor, gss_cred_id_t cred)
642 {
643     OM_uint32 major, tmpMinor;
644     gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
645     gss_name_t defaultIdentityName = GSS_C_NO_NAME;
646     gss_buffer_desc defaultPassword = GSS_C_EMPTY_BUFFER;
647     int isDefaultIdentity = FALSE;
648
649     major = readStaticIdentityFile(minor, &defaultIdentity, &defaultPassword);
650     if (GSS_ERROR(major))
651         goto cleanup;
652
653     major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
654                              gssEapPrimaryMechForCred(cred), &defaultIdentityName);
655     if (GSS_ERROR(major))
656         goto cleanup;
657
658     if (defaultIdentityName == GSS_C_NO_NAME) {
659         if (cred->name == GSS_C_NO_NAME) {
660             major = GSS_S_CRED_UNAVAIL;
661             *minor = GSSEAP_NO_DEFAULT_IDENTITY;
662             goto cleanup;
663         }
664     } else {
665         if (cred->name == GSS_C_NO_NAME) {
666             cred->name = defaultIdentityName;
667             defaultIdentityName = GSS_C_NO_NAME;
668             isDefaultIdentity = TRUE;
669         } else {
670             major = gssEapCompareName(minor, cred->name,
671                                       defaultIdentityName, &isDefaultIdentity);
672             if (GSS_ERROR(major))
673                 goto cleanup;
674         }
675     }
676
677     if (isDefaultIdentity &&
678         (cred->flags & CRED_FLAG_PASSWORD) == 0) {
679         major = gssEapSetCredPassword(minor, cred, &defaultPassword);
680         if (GSS_ERROR(major))
681             goto cleanup;
682     }
683
684 cleanup:
685     gssEapReleaseName(&tmpMinor, &defaultIdentityName);
686     zeroAndReleasePassword(&defaultPassword);
687     gss_release_buffer(&tmpMinor, &defaultIdentity);
688
689     return major;
690 }
691
692 OM_uint32
693 gssEapResolveInitiatorCred(OM_uint32 *minor,
694                            const gss_cred_id_t cred,
695                            const gss_name_t targetName
696 #ifndef HAVE_MOONSHOT_GET_IDENTITY
697                                                        GSSEAP_UNUSED
698 #endif
699                            ,
700                            gss_cred_id_t *pResolvedCred)
701 {
702     OM_uint32 major, tmpMinor;
703     gss_cred_id_t resolvedCred = GSS_C_NO_CREDENTIAL;
704
705     if (cred == GSS_C_NO_CREDENTIAL) {
706         major = gssEapAcquireCred(minor,
707                                   GSS_C_NO_NAME,
708                                   GSS_C_INDEFINITE,
709                                   GSS_C_NO_OID_SET,
710                                   GSS_C_INITIATE,
711                                   &resolvedCred,
712                                   NULL,
713                                   NULL);
714         if (GSS_ERROR(major))
715             goto cleanup;
716     } else {
717         if ((cred->flags & CRED_FLAG_INITIATE) == 0) {
718             major = GSS_S_NO_CRED;
719             *minor = GSSEAP_CRED_USAGE_MISMATCH;
720             goto cleanup;
721         }
722
723         major = gssEapDuplicateCred(minor, cred, &resolvedCred);
724         if (GSS_ERROR(major))
725             goto cleanup;
726     }
727
728     if ((resolvedCred->flags & CRED_FLAG_RESOLVED) == 0) {
729 #ifdef HAVE_MOONSHOT_GET_IDENTITY
730         major = libMoonshotResolveInitiatorCred(minor, resolvedCred, targetName);
731         if (major == GSS_S_CRED_UNAVAIL)
732 #endif
733             major = staticIdentityFileResolveInitiatorCred(minor, resolvedCred);
734         if (GSS_ERROR(major) && major != GSS_S_CRED_UNAVAIL)
735             goto cleanup;
736
737         /* If we have a caller-supplied password, the credential is resolved. */
738         if ((resolvedCred->flags & CRED_FLAG_PASSWORD) == 0) {
739             major = GSS_S_CRED_UNAVAIL;
740             *minor = GSSEAP_NO_DEFAULT_CRED;
741             goto cleanup;
742         }
743
744         resolvedCred->flags |= CRED_FLAG_RESOLVED;
745     }
746
747     *pResolvedCred = resolvedCred;
748     resolvedCred = GSS_C_NO_CREDENTIAL;
749
750     major = GSS_S_COMPLETE;
751     *minor = 0;
752
753 cleanup:
754     gssEapReleaseCred(&tmpMinor, &resolvedCred);
755
756     return major;
757 }