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