Add CRED_FLAG_TARGET
[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     GSSEAP_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         cred->flags |= CRED_FLAG_TARGET;
546     } else {
547         cred->flags &= ~(CRED_FLAG_TARGET);
548     }
549
550     gssEapReleaseName(&tmpMinor, &cred->target);
551     cred->target = newTarget;
552
553     major = GSS_S_COMPLETE;
554     *minor = 0;
555
556 cleanup:
557     return major;
558 }
559
560 static OM_uint32
561 gssEapDuplicateCred(OM_uint32 *minor,
562                     const gss_cred_id_t src,
563                     gss_cred_id_t *pDst)
564 {
565     OM_uint32 major, tmpMinor;
566     gss_cred_id_t dst = GSS_C_NO_CREDENTIAL;
567
568     *pDst = GSS_C_NO_CREDENTIAL;
569
570     major = gssEapAllocCred(minor, &dst);
571     if (GSS_ERROR(major))
572         goto cleanup;
573
574     dst->flags = src->flags;
575
576     if (src->name != GSS_C_NO_NAME) {
577         major = gssEapDuplicateName(minor, src->name, &dst->name);
578         if (GSS_ERROR(major))
579             goto cleanup;
580     }
581
582     if (src->target != GSS_C_NO_NAME) {
583         major = gssEapDuplicateName(minor, src->target, &dst->target);
584         if (GSS_ERROR(major))
585             goto cleanup;
586     }
587
588     if (src->password.value != NULL) {
589         major = duplicateBuffer(minor, &src->password, &dst->password);
590         if (GSS_ERROR(major))
591             goto cleanup;
592     }
593
594     major = duplicateOidSet(minor, src->mechanisms, &dst->mechanisms);
595     if (GSS_ERROR(major))
596         goto cleanup;
597
598     dst->expiryTime = src->expiryTime;
599
600     if (src->radiusConfigFile.value != NULL)
601         duplicateBufferOrCleanup(&src->radiusConfigFile, &dst->radiusConfigFile);
602     if (src->radiusConfigStanza.value != NULL)
603         duplicateBufferOrCleanup(&src->radiusConfigStanza, &dst->radiusConfigStanza);
604     if (src->caCertificate.value != NULL)
605         duplicateBufferOrCleanup(&src->caCertificate, &dst->caCertificate);
606     if (src->subjectNameConstraint.value != NULL)
607         duplicateBufferOrCleanup(&src->subjectNameConstraint, &dst->subjectNameConstraint);
608     if (src->subjectAltNameConstraint.value != NULL)
609         duplicateBufferOrCleanup(&src->subjectAltNameConstraint, &dst->subjectAltNameConstraint);
610
611 #ifdef GSSEAP_ENABLE_REAUTH
612     /* XXX krbCredCache, reauthCred */
613 #endif
614
615     *pDst = dst;
616     dst = GSS_C_NO_CREDENTIAL;
617
618     major = GSS_S_COMPLETE;
619     *minor = 0;
620
621 cleanup:
622     gssEapReleaseCred(&tmpMinor, &dst);
623
624     return major;
625 }
626
627 static OM_uint32
628 staticIdentityFileResolveInitiatorCred(OM_uint32 *minor, gss_cred_id_t cred)
629 {
630     OM_uint32 major, tmpMinor;
631     gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
632     gss_name_t defaultIdentityName = GSS_C_NO_NAME;
633     gss_buffer_desc defaultPassword = GSS_C_EMPTY_BUFFER;
634     int isDefaultIdentity = FALSE;
635
636     major = readStaticIdentityFile(minor, &defaultIdentity, &defaultPassword);
637     if (GSS_ERROR(major))
638         goto cleanup;
639
640     major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
641                              gssEapPrimaryMechForCred(cred), &defaultIdentityName);
642     if (GSS_ERROR(major))
643         goto cleanup;
644
645     if (defaultIdentityName == GSS_C_NO_NAME) {
646         if (cred->name == GSS_C_NO_NAME) {
647             major = GSS_S_CRED_UNAVAIL;
648             *minor = GSSEAP_NO_DEFAULT_IDENTITY;
649             goto cleanup;
650         }
651     } else {
652         if (cred->name == GSS_C_NO_NAME) {
653             cred->name = defaultIdentityName;
654             defaultIdentityName = GSS_C_NO_NAME;
655             isDefaultIdentity = TRUE;
656         } else {
657             major = gssEapCompareName(minor, cred->name,
658                                       defaultIdentityName, &isDefaultIdentity);
659             if (GSS_ERROR(major))
660                 goto cleanup;
661         }
662     }
663
664     if (isDefaultIdentity &&
665         (cred->flags & CRED_FLAG_PASSWORD) == 0) {
666         major = gssEapSetCredPassword(minor, cred, &defaultPassword);
667         if (GSS_ERROR(major))
668             goto cleanup;
669     }
670
671 cleanup:
672     gssEapReleaseName(&tmpMinor, &defaultIdentityName);
673     zeroAndReleasePassword(&defaultPassword);
674     gss_release_buffer(&tmpMinor, &defaultIdentity);
675
676     return major;
677 }
678
679 OM_uint32
680 gssEapResolveInitiatorCred(OM_uint32 *minor,
681                            const gss_cred_id_t cred,
682                            const gss_name_t targetName
683 #ifndef HAVE_MOONSHOT_GET_IDENTITY
684                                                        GSSEAP_UNUSED
685 #endif
686                            ,
687                            gss_cred_id_t *pResolvedCred)
688 {
689     OM_uint32 major, tmpMinor;
690     gss_cred_id_t resolvedCred = GSS_C_NO_CREDENTIAL;
691
692     if (cred == GSS_C_NO_CREDENTIAL) {
693         major = gssEapAcquireCred(minor,
694                                   GSS_C_NO_NAME,
695                                   GSS_C_INDEFINITE,
696                                   GSS_C_NO_OID_SET,
697                                   GSS_C_INITIATE,
698                                   &resolvedCred,
699                                   NULL,
700                                   NULL);
701         if (GSS_ERROR(major))
702             goto cleanup;
703     } else {
704         if ((cred->flags & CRED_FLAG_INITIATE) == 0) {
705             major = GSS_S_NO_CRED;
706             *minor = GSSEAP_CRED_USAGE_MISMATCH;
707             goto cleanup;
708         }
709
710         major = gssEapDuplicateCred(minor, cred, &resolvedCred);
711         if (GSS_ERROR(major))
712             goto cleanup;
713     }
714
715     if ((resolvedCred->flags & CRED_FLAG_RESOLVED) == 0) {
716 #ifdef HAVE_MOONSHOT_GET_IDENTITY
717         major = libMoonshotResolveInitiatorCred(minor, resolvedCred, targetName);
718         if (major == GSS_S_CRED_UNAVAIL)
719 #endif
720             major = staticIdentityFileResolveInitiatorCred(minor, resolvedCred);
721         if (GSS_ERROR(major))
722             goto cleanup;
723
724         if ((resolvedCred->flags & CRED_FLAG_PASSWORD) == 0) {
725             major = GSS_S_CRED_UNAVAIL;
726             *minor = GSSEAP_NO_DEFAULT_CRED;
727             goto cleanup;
728         }
729
730         resolvedCred->flags |= CRED_FLAG_RESOLVED;
731     }
732
733     *pResolvedCred = resolvedCred;
734     resolvedCred = GSS_C_NO_CREDENTIAL;
735
736     major = GSS_S_COMPLETE;
737     *minor = 0;
738
739 cleanup:
740     gssEapReleaseCred(&tmpMinor, &resolvedCred);
741
742     return major;
743 }