Merge branch 'windows'
[moonshot.git] / moonshot / 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 nameMech = GSS_C_NO_OID;
245
246     if (cred->mechanisms != GSS_C_NO_OID_SET &&
247         cred->mechanisms->count == 1)
248         nameMech = &cred->mechanisms->elements[0];
249
250     return nameMech;
251 }
252
253 OM_uint32
254 gssEapAcquireCred(OM_uint32 *minor,
255                   const gss_name_t desiredName,
256                   OM_uint32 timeReq GSSEAP_UNUSED,
257                   const gss_OID_set desiredMechs,
258                   int credUsage,
259                   gss_cred_id_t *pCred,
260                   gss_OID_set *pActualMechs,
261                   OM_uint32 *timeRec)
262 {
263     OM_uint32 major, tmpMinor;
264     gss_cred_id_t cred;
265
266     /* XXX TODO validate with changed set_cred_option API */
267     *pCred = GSS_C_NO_CREDENTIAL;
268
269     major = gssEapAllocCred(minor, &cred);
270     if (GSS_ERROR(major))
271         goto cleanup;
272
273     switch (credUsage) {
274     case GSS_C_BOTH:
275         cred->flags |= CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT;
276         break;
277     case GSS_C_INITIATE:
278         cred->flags |= CRED_FLAG_INITIATE;
279         break;
280     case GSS_C_ACCEPT:
281         cred->flags |= CRED_FLAG_ACCEPT;
282         break;
283     default:
284         major = GSS_S_FAILURE;
285         *minor = GSSEAP_BAD_USAGE;
286         goto cleanup;
287         break;
288     }
289
290     major = gssEapValidateMechs(minor, desiredMechs);
291     if (GSS_ERROR(major))
292         goto cleanup;
293
294     major = duplicateOidSet(minor, desiredMechs, &cred->mechanisms);
295     if (GSS_ERROR(major))
296         goto cleanup;
297
298     if (desiredName != GSS_C_NO_NAME) {
299         GSSEAP_MUTEX_LOCK(&desiredName->mutex);
300
301         major = gssEapDuplicateName(minor, desiredName, &cred->name);
302         if (GSS_ERROR(major)) {
303             GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
304             goto cleanup;
305         }
306
307         GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
308     }
309
310     if (pActualMechs != NULL) {
311         major = duplicateOidSet(minor, cred->mechanisms, pActualMechs);
312         if (GSS_ERROR(major))
313             goto cleanup;
314     }
315
316     if (timeRec != NULL)
317         *timeRec = GSS_C_INDEFINITE;
318
319     *pCred = cred;
320
321     major = GSS_S_COMPLETE;
322     *minor = 0;
323
324 cleanup:
325     if (GSS_ERROR(major))
326         gssEapReleaseCred(&tmpMinor, &cred);
327
328     return major;
329 }
330
331 /*
332  * Return TRUE if cred available for mechanism. Caller need no acquire
333  * lock because mechanisms list is immutable.
334  */
335 int
336 gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech)
337 {
338     OM_uint32 minor;
339     int present = 0;
340
341     assert(mech != GSS_C_NO_OID);
342
343     if (cred == GSS_C_NO_CREDENTIAL || cred->mechanisms == GSS_C_NO_OID_SET)
344         return TRUE;
345
346     gss_test_oid_set_member(&minor, mech, cred->mechanisms, &present);
347
348     return present;
349 }
350
351 static OM_uint32
352 staticIdentityFileResolveDefaultIdentity(OM_uint32 *minor,
353                                          const gss_cred_id_t cred,
354                                          gss_name_t *pName)
355 {
356     OM_uint32 major, tmpMinor;
357     gss_OID nameMech = gssEapPrimaryMechForCred(cred);
358     gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
359
360     *pName = GSS_C_NO_NAME;
361
362     major = readStaticIdentityFile(minor, &defaultIdentity, GSS_C_NO_BUFFER);
363     if (major == GSS_S_COMPLETE) {
364         major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
365                                  nameMech, pName);
366     }
367
368     gss_release_buffer(&tmpMinor, &defaultIdentity);
369
370     return major;
371 }
372
373 static OM_uint32
374 gssEapResolveCredIdentity(OM_uint32 *minor,
375                           gss_cred_id_t cred)
376 {
377     OM_uint32 major;
378     gss_OID nameMech = gssEapPrimaryMechForCred(cred);
379
380     if (cred->name != GSS_C_NO_NAME) {
381         *minor = 0;
382         return GSS_S_COMPLETE;
383     }
384
385     if (cred->flags & CRED_FLAG_ACCEPT) {
386         gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
387         char serviceName[5 + MAXHOSTNAMELEN];
388
389         /* default host-based service is host@localhost */
390         memcpy(serviceName, "host@", 5);
391         if (gethostname(&serviceName[5], MAXHOSTNAMELEN) != 0) {
392             *minor = GSSEAP_NO_HOSTNAME;
393             return GSS_S_FAILURE;
394         }
395
396         nameBuf.value = serviceName;
397         nameBuf.length = strlen((char *)nameBuf.value);
398
399         major = gssEapImportName(minor, &nameBuf, GSS_C_NT_HOSTBASED_SERVICE,
400                                  nameMech, &cred->name);
401         if (GSS_ERROR(major))
402             return major;
403     } else if (cred->flags & CRED_FLAG_INITIATE) {
404 #ifdef HAVE_MOONSHOT_GET_IDENTITY
405         major = libMoonshotResolveDefaultIdentity(minor, cred, &cred->name);
406         if (major == GSS_S_CRED_UNAVAIL)
407 #endif
408             major = staticIdentityFileResolveDefaultIdentity(minor, cred, &cred->name);
409         if (major != GSS_S_CRED_UNAVAIL)
410             return major;
411     }
412
413     *minor = 0;
414     return GSS_S_COMPLETE;
415 }
416
417 OM_uint32
418 gssEapInquireCred(OM_uint32 *minor,
419                   gss_cred_id_t cred,
420                   gss_name_t *name,
421                   OM_uint32 *pLifetime,
422                   gss_cred_usage_t *cred_usage,
423                   gss_OID_set *mechanisms)
424 {
425     OM_uint32 major;
426     time_t now, lifetime;
427
428     if (name != NULL) {
429         major = gssEapResolveCredIdentity(minor, cred);
430         if (GSS_ERROR(major))
431             goto cleanup;
432
433         if (cred->name != GSS_C_NO_NAME) {
434             major = gssEapDuplicateName(minor, cred->name, name);
435             if (GSS_ERROR(major))
436                 goto cleanup;
437         } else
438             *name = GSS_C_NO_NAME;
439     }
440
441     if (cred_usage != NULL) {
442         OM_uint32 flags = (cred->flags & (CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT));
443
444         switch (flags) {
445         case CRED_FLAG_INITIATE:
446             *cred_usage = GSS_C_INITIATE;
447             break;
448         case CRED_FLAG_ACCEPT:
449             *cred_usage = GSS_C_ACCEPT;
450             break;
451         default:
452             *cred_usage = GSS_C_BOTH;
453             break;
454         }
455     }
456
457     if (mechanisms != NULL) {
458         if (cred->mechanisms != GSS_C_NO_OID_SET)
459             major = duplicateOidSet(minor, cred->mechanisms, mechanisms);
460         else
461             major = gssEapIndicateMechs(minor, mechanisms);
462         if (GSS_ERROR(major))
463             goto cleanup;
464     }
465
466     if (cred->expiryTime == 0) {
467         lifetime = GSS_C_INDEFINITE;
468     } else  {
469         now = time(NULL);
470         lifetime = now - cred->expiryTime;
471         if (lifetime < 0)
472             lifetime = 0;
473     }
474
475     if (pLifetime != NULL) {
476         *pLifetime = lifetime;
477     }
478
479     if (lifetime == 0) {
480         major = GSS_S_CREDENTIALS_EXPIRED;
481         *minor = GSSEAP_CRED_EXPIRED;
482         goto cleanup;
483     }
484
485     major = GSS_S_COMPLETE;
486     *minor = 0;
487
488 cleanup:
489     return major;
490 }
491
492 OM_uint32
493 gssEapSetCredPassword(OM_uint32 *minor,
494                       gss_cred_id_t cred,
495                       const gss_buffer_t password)
496 {
497     OM_uint32 major, tmpMinor;
498     gss_buffer_desc newPassword = GSS_C_EMPTY_BUFFER;
499
500     if (cred->flags & CRED_FLAG_RESOLVED) {
501         major = GSS_S_FAILURE;
502         *minor = GSSEAP_CRED_RESOLVED;
503         goto cleanup;
504     }
505
506     if (password != GSS_C_NO_BUFFER) {
507         major = duplicateBuffer(minor, password, &newPassword);
508         if (GSS_ERROR(major))
509             goto cleanup;
510
511         cred->flags |= CRED_FLAG_PASSWORD;
512     } else {
513         cred->flags &= ~(CRED_FLAG_PASSWORD);
514     }
515
516     gss_release_buffer(&tmpMinor, &cred->password);
517     cred->password = newPassword;
518
519     major = GSS_S_COMPLETE;
520     *minor = 0;
521
522 cleanup:
523     return major;
524 }
525
526 OM_uint32
527 gssEapSetCredService(OM_uint32 *minor,
528                      gss_cred_id_t cred,
529                      const gss_name_t target)
530 {
531     OM_uint32 major, tmpMinor;
532     gss_name_t newTarget = GSS_C_NO_NAME;
533
534     if (cred->flags & CRED_FLAG_RESOLVED) {
535         major = GSS_S_FAILURE;
536         *minor = GSSEAP_CRED_RESOLVED;
537         goto cleanup;
538     }
539
540     if (target != GSS_C_NO_NAME) {
541         major = gssEapDuplicateName(minor, target, &newTarget);
542         if (GSS_ERROR(major))
543             goto cleanup;
544     }
545
546     gssEapReleaseName(&tmpMinor, &cred->target);
547     cred->target = newTarget;
548
549     major = GSS_S_COMPLETE;
550     *minor = 0;
551
552 cleanup:
553     return major;
554 }
555
556 static OM_uint32
557 gssEapDuplicateCred(OM_uint32 *minor,
558                     const gss_cred_id_t src,
559                     gss_cred_id_t *pDst)
560 {
561     OM_uint32 major, tmpMinor;
562     gss_cred_id_t dst = GSS_C_NO_CREDENTIAL;
563
564     *pDst = GSS_C_NO_CREDENTIAL;
565
566     major = gssEapAllocCred(minor, &dst);
567     if (GSS_ERROR(major))
568         goto cleanup;
569
570     dst->flags = src->flags;
571
572     if (src->name != GSS_C_NO_NAME) {
573         major = gssEapDuplicateName(minor, src->name, &dst->name);
574         if (GSS_ERROR(major))
575             goto cleanup;
576     }
577
578     if (src->target != GSS_C_NO_NAME) {
579         major = gssEapDuplicateName(minor, src->target, &dst->target);
580         if (GSS_ERROR(major))
581             goto cleanup;
582     }
583
584     if (src->password.value != NULL) {
585         major = duplicateBuffer(minor, &src->password, &dst->password);
586         if (GSS_ERROR(major))
587             goto cleanup;
588     }
589
590     major = duplicateOidSet(minor, src->mechanisms, &dst->mechanisms);
591     if (GSS_ERROR(major))
592         goto cleanup;
593
594     dst->expiryTime = src->expiryTime;
595
596     if (src->radiusConfigFile.value != NULL)
597         duplicateBufferOrCleanup(&src->radiusConfigFile, &dst->radiusConfigFile);
598     if (src->radiusConfigStanza.value != NULL)
599         duplicateBufferOrCleanup(&src->radiusConfigStanza, &dst->radiusConfigStanza);
600     if (src->caCertificate.value != NULL)
601         duplicateBufferOrCleanup(&src->caCertificate, &dst->caCertificate);
602     if (src->subjectNameConstraint.value != NULL)
603         duplicateBufferOrCleanup(&src->subjectNameConstraint, &dst->subjectNameConstraint);
604     if (src->subjectAltNameConstraint.value != NULL)
605         duplicateBufferOrCleanup(&src->subjectAltNameConstraint, &dst->subjectAltNameConstraint);
606
607 #ifdef GSSEAP_ENABLE_REAUTH
608     /* XXX krbCredCache, reauthCred */
609 #endif
610
611     *pDst = dst;
612     dst = GSS_C_NO_CREDENTIAL;
613
614     major = GSS_S_COMPLETE;
615     *minor = 0;
616
617 cleanup:
618     gssEapReleaseCred(&tmpMinor, &dst);
619
620     return major;
621 }
622
623 static OM_uint32
624 staticIdentityFileResolveInitiatorCred(OM_uint32 *minor, gss_cred_id_t cred)
625 {
626     OM_uint32 major, tmpMinor;
627     gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
628     gss_name_t defaultIdentityName = GSS_C_NO_NAME;
629     gss_buffer_desc defaultPassword = GSS_C_EMPTY_BUFFER;
630     int isDefaultIdentity = FALSE;
631
632     major = readStaticIdentityFile(minor, &defaultIdentity, &defaultPassword);
633     if (GSS_ERROR(major))
634         goto cleanup;
635
636     major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
637                              gssEapPrimaryMechForCred(cred), &defaultIdentityName);
638     if (GSS_ERROR(major))
639         goto cleanup;
640
641     if (defaultIdentityName == GSS_C_NO_NAME) {
642         if (cred->name == GSS_C_NO_NAME) {
643             major = GSS_S_CRED_UNAVAIL;
644             *minor = GSSEAP_NO_DEFAULT_IDENTITY;
645             goto cleanup;
646         }
647     } else {
648         if (cred->name == GSS_C_NO_NAME) {
649             cred->name = defaultIdentityName;
650             defaultIdentityName = GSS_C_NO_NAME;
651             isDefaultIdentity = TRUE;
652         } else {
653             major = gssEapCompareName(minor, cred->name,
654                                       defaultIdentityName, &isDefaultIdentity);
655             if (GSS_ERROR(major))
656                 goto cleanup;
657         }
658     }
659
660     if (isDefaultIdentity &&
661         (cred->flags & CRED_FLAG_PASSWORD) == 0) {
662         major = gssEapSetCredPassword(minor, cred, &defaultPassword);
663         if (GSS_ERROR(major))
664             goto cleanup;
665     }
666
667 cleanup:
668     gssEapReleaseName(&tmpMinor, &defaultIdentityName);
669     zeroAndReleasePassword(&defaultPassword);
670     gss_release_buffer(&tmpMinor, &defaultIdentity);
671
672     return major;
673 }
674
675 OM_uint32
676 gssEapResolveInitiatorCred(OM_uint32 *minor,
677                            const gss_cred_id_t cred,
678                            const gss_name_t targetName
679 #ifndef HAVE_MOONSHOT_GET_IDENTITY
680                                                        GSSEAP_UNUSED
681 #endif
682                            ,
683                            gss_cred_id_t *pResolvedCred)
684 {
685     OM_uint32 major, tmpMinor;
686     gss_cred_id_t resolvedCred = GSS_C_NO_CREDENTIAL;
687
688     if (cred == GSS_C_NO_CREDENTIAL) {
689         major = gssEapAcquireCred(minor,
690                                   GSS_C_NO_NAME,
691                                   GSS_C_INDEFINITE,
692                                   GSS_C_NO_OID_SET,
693                                   GSS_C_INITIATE,
694                                   &resolvedCred,
695                                   NULL,
696                                   NULL);
697         if (GSS_ERROR(major))
698             goto cleanup;
699     } else {
700         if ((cred->flags & CRED_FLAG_INITIATE) == 0) {
701             major = GSS_S_NO_CRED;
702             *minor = GSSEAP_CRED_USAGE_MISMATCH;
703             goto cleanup;
704         }
705
706         major = gssEapDuplicateCred(minor, cred, &resolvedCred);
707         if (GSS_ERROR(major))
708             goto cleanup;
709     }
710
711     if ((resolvedCred->flags & CRED_FLAG_RESOLVED) == 0) {
712 #ifdef HAVE_MOONSHOT_GET_IDENTITY
713         major = libMoonshotResolveInitiatorCred(minor, resolvedCred, targetName);
714         if (major == GSS_S_CRED_UNAVAIL)
715 #endif
716             major = staticIdentityFileResolveInitiatorCred(minor, resolvedCred);
717         if (GSS_ERROR(major))
718             goto cleanup;
719
720         if ((resolvedCred->flags & CRED_FLAG_PASSWORD) == 0) {
721             major = GSS_S_CRED_UNAVAIL;
722             *minor = GSSEAP_NO_DEFAULT_CRED;
723             goto cleanup;
724         }
725
726         resolvedCred->flags |= CRED_FLAG_RESOLVED;
727     }
728
729     *pResolvedCred = resolvedCred;
730     resolvedCred = GSS_C_NO_CREDENTIAL;
731
732     major = GSS_S_COMPLETE;
733     *minor = 0;
734
735 cleanup:
736     gssEapReleaseCred(&tmpMinor, &resolvedCred);
737
738     return major;
739 }