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