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