Revert "remember to duplicate clientCertificate"
[mech_eap.orig] / 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     gss_release_buffer(&tmpMinor, &cred->privateKey);
108     gss_release_buffer(&tmpMinor, &cred->clientCertificate);
109
110 #ifdef GSSEAP_ENABLE_REAUTH
111     if (cred->krbCredCache != NULL) {
112         if (cred->flags & CRED_FLAG_DEFAULT_CCACHE)
113             krb5_cc_close(krbContext, cred->krbCredCache);
114         else
115             krb5_cc_destroy(krbContext, cred->krbCredCache);
116     }
117     if (cred->reauthCred != GSS_C_NO_CREDENTIAL)
118         gssReleaseCred(&tmpMinor, &cred->reauthCred);
119 #endif
120
121     GSSEAP_MUTEX_DESTROY(&cred->mutex);
122     memset(cred, 0, sizeof(*cred));
123     GSSEAP_FREE(cred);
124     *pCred = NULL;
125
126     *minor = 0;
127     return GSS_S_COMPLETE;
128 }
129
130 static OM_uint32
131 readStaticIdentityFile(OM_uint32 *minor,
132                        gss_buffer_t defaultIdentity,
133                        gss_buffer_t defaultPassword,
134                        gss_buffer_t defaultPrivateKey)
135 {
136     OM_uint32 major, tmpMinor;
137     FILE *fp = NULL;
138     char buf[BUFSIZ];
139     char *ccacheName;
140     int i = 0;
141 #ifndef WIN32
142     struct passwd *pw = NULL, pwd;
143     char pwbuf[BUFSIZ];
144 #endif
145
146     defaultIdentity->length = 0;
147     defaultIdentity->value = NULL;
148
149     if (defaultPassword != GSS_C_NO_BUFFER) {
150         defaultPassword->length = 0;
151         defaultPassword->value = NULL;
152     }
153
154     if (defaultPrivateKey != GSS_C_NO_BUFFER) {
155         defaultPrivateKey->length = 0;
156         defaultPrivateKey->value = NULL;
157     }
158
159     ccacheName = getenv("GSSEAP_IDENTITY");
160     if (ccacheName == NULL) {
161 #ifdef WIN32
162         TCHAR szPath[MAX_PATH];
163
164         if (!SUCCEEDED(SHGetFolderPath(NULL,
165                                        CSIDL_APPDATA, /* |CSIDL_FLAG_CREATE */
166                                        NULL, /* User access token */
167                                        0,    /* SHGFP_TYPE_CURRENT */
168                                        szPath))) {
169             major = GSS_S_CRED_UNAVAIL;
170             *minor = GSSEAP_GET_LAST_ERROR(); /* XXX */
171             goto cleanup;
172         }
173
174         snprintf(buf, sizeof(buf), "%s/.gss_eap_id", szPath);
175 #else
176         if (getpwuid_r(getuid(), &pwd, pwbuf, sizeof(pwbuf), &pw) != 0 ||
177             pw == NULL || pw->pw_dir == NULL) {
178             major = GSS_S_CRED_UNAVAIL;
179             *minor = GSSEAP_GET_LAST_ERROR();
180             goto cleanup;
181         }
182
183         snprintf(buf, sizeof(buf), "%s/.gss_eap_id", pw->pw_dir);
184 #endif /* WIN32 */
185         ccacheName = buf;
186     }
187
188     fp = fopen(ccacheName, "r");
189     if (fp == NULL) {
190         major = GSS_S_CRED_UNAVAIL;
191         *minor = GSSEAP_NO_DEFAULT_CRED;
192         goto cleanup;
193     }
194
195     while (fgets(buf, sizeof(buf), fp) != NULL) {
196         gss_buffer_desc src, *dst;
197
198         src.length = strlen(buf);
199         src.value = buf;
200
201         if (src.length == 0)
202             break;
203
204         if (buf[src.length - 1] == '\n') {
205             buf[src.length - 1] = '\0';
206             if (--src.length == 0)
207                 break;
208         }
209
210         if (i == 0)
211             dst = defaultIdentity;
212         else if (i == 1)
213             dst = defaultPassword;
214         else if (i == 2)
215             dst = defaultPrivateKey;
216         else
217             break;
218
219         if (dst != GSS_C_NO_BUFFER) {
220             major = duplicateBuffer(minor, &src, dst);
221             if (GSS_ERROR(major))
222                 goto cleanup;
223         }
224
225         i++;
226     }
227
228     if (defaultIdentity->length == 0) {
229         major = GSS_S_CRED_UNAVAIL;
230         *minor = GSSEAP_NO_DEFAULT_CRED;
231         goto cleanup;
232     }
233
234     major = GSS_S_COMPLETE;
235     *minor = 0;
236
237 cleanup:
238     if (fp != NULL)
239         fclose(fp);
240
241     if (GSS_ERROR(major)) {
242         gss_release_buffer(&tmpMinor, defaultIdentity);
243         zeroAndReleasePassword(defaultPassword);
244         gss_release_buffer(&tmpMinor, defaultPrivateKey);
245     }
246
247     memset(buf, 0, sizeof(buf));
248
249     return major;
250 }
251
252 gss_OID
253 gssEapPrimaryMechForCred(gss_cred_id_t cred)
254 {
255     gss_OID nameMech = GSS_C_NO_OID;
256
257     if (cred->mechanisms != GSS_C_NO_OID_SET &&
258         cred->mechanisms->count == 1)
259         nameMech = &cred->mechanisms->elements[0];
260
261     return nameMech;
262 }
263
264 OM_uint32
265 gssEapAcquireCred(OM_uint32 *minor,
266                   const gss_name_t desiredName,
267                   OM_uint32 timeReq GSSEAP_UNUSED,
268                   const gss_OID_set desiredMechs,
269                   int credUsage,
270                   gss_cred_id_t *pCred,
271                   gss_OID_set *pActualMechs,
272                   OM_uint32 *timeRec)
273 {
274     OM_uint32 major, tmpMinor;
275     gss_cred_id_t cred;
276
277     /* XXX TODO validate with changed set_cred_option API */
278     *pCred = GSS_C_NO_CREDENTIAL;
279
280     major = gssEapAllocCred(minor, &cred);
281     if (GSS_ERROR(major))
282         goto cleanup;
283
284     switch (credUsage) {
285     case GSS_C_BOTH:
286         cred->flags |= CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT;
287         break;
288     case GSS_C_INITIATE:
289         cred->flags |= CRED_FLAG_INITIATE;
290         break;
291     case GSS_C_ACCEPT:
292         cred->flags |= CRED_FLAG_ACCEPT;
293         break;
294     default:
295         major = GSS_S_FAILURE;
296         *minor = GSSEAP_BAD_USAGE;
297         goto cleanup;
298         break;
299     }
300
301     major = gssEapValidateMechs(minor, desiredMechs);
302     if (GSS_ERROR(major))
303         goto cleanup;
304
305     major = duplicateOidSet(minor, desiredMechs, &cred->mechanisms);
306     if (GSS_ERROR(major))
307         goto cleanup;
308
309     if (desiredName != GSS_C_NO_NAME) {
310         GSSEAP_MUTEX_LOCK(&desiredName->mutex);
311
312         major = gssEapDuplicateName(minor, desiredName, &cred->name);
313         if (GSS_ERROR(major)) {
314             GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
315             goto cleanup;
316         }
317
318         GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
319     }
320
321 #ifdef GSSEAP_ENABLE_ACCEPTOR
322     if (cred->flags & CRED_FLAG_ACCEPT) {
323         struct rs_context *radContext;
324
325         major = gssEapCreateRadiusContext(minor, cred, &radContext);
326         if (GSS_ERROR(major))
327             goto cleanup;
328
329         rs_context_destroy(radContext);
330     }
331 #endif
332
333     if (pActualMechs != NULL) {
334         major = duplicateOidSet(minor, cred->mechanisms, pActualMechs);
335         if (GSS_ERROR(major))
336             goto cleanup;
337     }
338
339     if (timeRec != NULL)
340         *timeRec = GSS_C_INDEFINITE;
341
342     *pCred = cred;
343
344     major = GSS_S_COMPLETE;
345     *minor = 0;
346
347 cleanup:
348     if (GSS_ERROR(major))
349         gssEapReleaseCred(&tmpMinor, &cred);
350
351     return major;
352 }
353
354 /*
355  * Return TRUE if cred available for mechanism. Caller need no acquire
356  * lock because mechanisms list is immutable.
357  */
358 int
359 gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech)
360 {
361     OM_uint32 minor;
362     int present = 0;
363
364     GSSEAP_ASSERT(mech != GSS_C_NO_OID);
365
366     if (cred == GSS_C_NO_CREDENTIAL || cred->mechanisms == GSS_C_NO_OID_SET)
367         return TRUE;
368
369     gss_test_oid_set_member(&minor, mech, cred->mechanisms, &present);
370
371     return present;
372 }
373
374 static OM_uint32
375 staticIdentityFileResolveDefaultIdentity(OM_uint32 *minor,
376                                          const gss_cred_id_t cred,
377                                          gss_name_t *pName)
378 {
379     OM_uint32 major, tmpMinor;
380     gss_OID nameMech = gssEapPrimaryMechForCred(cred);
381     gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
382
383     *pName = GSS_C_NO_NAME;
384
385     major = readStaticIdentityFile(minor, &defaultIdentity,
386                                    GSS_C_NO_BUFFER, GSS_C_NO_BUFFER);
387     if (major == GSS_S_COMPLETE) {
388         major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
389                                  nameMech, pName);
390     }
391
392     gss_release_buffer(&tmpMinor, &defaultIdentity);
393
394     return major;
395 }
396
397 static OM_uint32
398 gssEapResolveCredIdentity(OM_uint32 *minor,
399                           gss_cred_id_t cred)
400 {
401     OM_uint32 major;
402     gss_OID nameMech = gssEapPrimaryMechForCred(cred);
403
404     if (cred->name != GSS_C_NO_NAME) {
405         *minor = 0;
406         return GSS_S_COMPLETE;
407     }
408
409     if (cred->flags & CRED_FLAG_ACCEPT) {
410         gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
411         char serviceName[5 + MAXHOSTNAMELEN];
412
413         /* default host-based service is host@localhost */
414         memcpy(serviceName, "host@", 5);
415         if (gethostname(&serviceName[5], MAXHOSTNAMELEN) != 0) {
416             *minor = GSSEAP_NO_HOSTNAME;
417             return GSS_S_FAILURE;
418         }
419
420         nameBuf.value = serviceName;
421         nameBuf.length = strlen((char *)nameBuf.value);
422
423         major = gssEapImportName(minor, &nameBuf, GSS_C_NT_HOSTBASED_SERVICE,
424                                  nameMech, &cred->name);
425         if (GSS_ERROR(major))
426             return major;
427     } else if (cred->flags & CRED_FLAG_INITIATE) {
428 #ifdef HAVE_MOONSHOT_GET_IDENTITY
429         major = libMoonshotResolveDefaultIdentity(minor, cred, &cred->name);
430         if (major == GSS_S_CRED_UNAVAIL)
431 #endif
432             major = staticIdentityFileResolveDefaultIdentity(minor, cred, &cred->name);
433         if (major != GSS_S_CRED_UNAVAIL)
434             return major;
435     }
436
437     *minor = 0;
438     return GSS_S_COMPLETE;
439 }
440
441 OM_uint32
442 gssEapInquireCred(OM_uint32 *minor,
443                   gss_cred_id_t cred,
444                   gss_name_t *name,
445                   OM_uint32 *pLifetime,
446                   gss_cred_usage_t *cred_usage,
447                   gss_OID_set *mechanisms)
448 {
449     OM_uint32 major;
450     time_t now, lifetime;
451
452     if (name != NULL) {
453         major = gssEapResolveCredIdentity(minor, cred);
454         if (GSS_ERROR(major))
455             goto cleanup;
456
457         if (cred->name != GSS_C_NO_NAME) {
458             major = gssEapDuplicateName(minor, cred->name, name);
459             if (GSS_ERROR(major))
460                 goto cleanup;
461         } else
462             *name = GSS_C_NO_NAME;
463     }
464
465     if (cred_usage != NULL) {
466         OM_uint32 flags = (cred->flags & (CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT));
467
468         switch (flags) {
469         case CRED_FLAG_INITIATE:
470             *cred_usage = GSS_C_INITIATE;
471             break;
472         case CRED_FLAG_ACCEPT:
473             *cred_usage = GSS_C_ACCEPT;
474             break;
475         default:
476             *cred_usage = GSS_C_BOTH;
477             break;
478         }
479     }
480
481     if (mechanisms != NULL) {
482         if (cred->mechanisms != GSS_C_NO_OID_SET)
483             major = duplicateOidSet(minor, cred->mechanisms, mechanisms);
484         else
485             major = gssEapIndicateMechs(minor, mechanisms);
486         if (GSS_ERROR(major))
487             goto cleanup;
488     }
489
490     if (cred->expiryTime == 0) {
491         lifetime = GSS_C_INDEFINITE;
492     } else  {
493         now = time(NULL);
494         lifetime = now - cred->expiryTime;
495         if (lifetime < 0)
496             lifetime = 0;
497     }
498
499     if (pLifetime != NULL) {
500         *pLifetime = lifetime;
501     }
502
503     if (lifetime == 0) {
504         major = GSS_S_CREDENTIALS_EXPIRED;
505         *minor = GSSEAP_CRED_EXPIRED;
506         goto cleanup;
507     }
508
509     major = GSS_S_COMPLETE;
510     *minor = 0;
511
512 cleanup:
513     return major;
514 }
515
516 OM_uint32
517 gssEapSetCredPassword(OM_uint32 *minor,
518                       gss_cred_id_t cred,
519                       const gss_buffer_t password)
520 {
521     OM_uint32 major, tmpMinor;
522     gss_buffer_desc newPassword = GSS_C_EMPTY_BUFFER;
523
524     if (cred->flags & CRED_FLAG_RESOLVED) {
525         major = GSS_S_FAILURE;
526         *minor = GSSEAP_CRED_RESOLVED;
527         goto cleanup;
528     }
529
530     if (password != GSS_C_NO_BUFFER) {
531         major = duplicateBuffer(minor, password, &newPassword);
532         if (GSS_ERROR(major))
533             goto cleanup;
534
535         cred->flags |= CRED_FLAG_PASSWORD;
536     } else {
537         cred->flags &= ~(CRED_FLAG_PASSWORD);
538     }
539
540     gss_release_buffer(&tmpMinor, &cred->password);
541     cred->password = newPassword;
542
543     major = GSS_S_COMPLETE;
544     *minor = 0;
545
546 cleanup:
547     return major;
548 }
549
550 /*
551  * Currently only the privateKey path is exposed to the application
552  * (via gss_set_cred_option() or the third line in ~/.gss_eap_id).
553  * At some point in the future we may add support for setting the
554  * client certificate separately.
555  */
556 OM_uint32
557 gssEapSetCredClientCertificate(OM_uint32 *minor,
558                               gss_cred_id_t cred,
559                               const gss_buffer_t clientCert,
560                               const gss_buffer_t privateKey)
561 {
562     OM_uint32 major, tmpMinor;
563     gss_buffer_desc newClientCert = GSS_C_EMPTY_BUFFER;
564     gss_buffer_desc newPrivateKey = GSS_C_EMPTY_BUFFER;
565
566     if (cred->flags & CRED_FLAG_RESOLVED) {
567         major = GSS_S_FAILURE;
568         *minor = GSSEAP_CRED_RESOLVED;
569         goto cleanup;
570     }
571
572     if (clientCert == GSS_C_NO_BUFFER &&
573         privateKey == GSS_C_NO_BUFFER) {
574         cred->flags &= ~(CRED_FLAG_CERTIFICATE);
575         major = GSS_S_COMPLETE;
576         *minor = 0;
577         goto cleanup;
578     }
579
580     if (clientCert != GSS_C_NO_BUFFER) {
581         major = duplicateBuffer(minor, clientCert, &newClientCert);
582         if (GSS_ERROR(major))
583             goto cleanup;
584     }
585
586     if (privateKey != GSS_C_NO_BUFFER) {
587         major = duplicateBuffer(minor, privateKey, &newPrivateKey);
588         if (GSS_ERROR(major))
589             goto cleanup;
590     }
591
592     cred->flags |= CRED_FLAG_CERTIFICATE;
593
594     gss_release_buffer(&tmpMinor, &cred->clientCertificate);
595     cred->clientCertificate = newClientCert;
596
597     gss_release_buffer(&tmpMinor, &cred->privateKey);
598     cred->privateKey = newPrivateKey;
599
600     major = GSS_S_COMPLETE;
601     *minor = 0;
602
603 cleanup:
604     if (GSS_ERROR(major)) {
605         gss_release_buffer(&tmpMinor, &newClientCert);
606         gss_release_buffer(&tmpMinor, &newPrivateKey);
607     }
608
609     return major;
610 }
611
612 OM_uint32
613 gssEapSetCredService(OM_uint32 *minor,
614                      gss_cred_id_t cred,
615                      const gss_name_t target)
616 {
617     OM_uint32 major, tmpMinor;
618     gss_name_t newTarget = GSS_C_NO_NAME;
619
620     if (cred->flags & CRED_FLAG_RESOLVED) {
621         major = GSS_S_FAILURE;
622         *minor = GSSEAP_CRED_RESOLVED;
623         goto cleanup;
624     }
625
626     if (target != GSS_C_NO_NAME) {
627         major = gssEapDuplicateName(minor, target, &newTarget);
628         if (GSS_ERROR(major))
629             goto cleanup;
630
631         cred->flags |= CRED_FLAG_TARGET;
632     } else {
633         cred->flags &= ~(CRED_FLAG_TARGET);
634     }
635
636     gssEapReleaseName(&tmpMinor, &cred->target);
637     cred->target = newTarget;
638
639     major = GSS_S_COMPLETE;
640     *minor = 0;
641
642 cleanup:
643     return major;
644 }
645
646 static OM_uint32
647 gssEapDuplicateCred(OM_uint32 *minor,
648                     const gss_cred_id_t src,
649                     gss_cred_id_t *pDst)
650 {
651     OM_uint32 major, tmpMinor;
652     gss_cred_id_t dst = GSS_C_NO_CREDENTIAL;
653
654     *pDst = GSS_C_NO_CREDENTIAL;
655
656     major = gssEapAllocCred(minor, &dst);
657     if (GSS_ERROR(major))
658         goto cleanup;
659
660     dst->flags = src->flags;
661
662     if (src->name != GSS_C_NO_NAME) {
663         major = gssEapDuplicateName(minor, src->name, &dst->name);
664         if (GSS_ERROR(major))
665             goto cleanup;
666     }
667
668     if (src->target != GSS_C_NO_NAME) {
669         major = gssEapDuplicateName(minor, src->target, &dst->target);
670         if (GSS_ERROR(major))
671             goto cleanup;
672     }
673
674     if (src->password.value != NULL) {
675         major = duplicateBuffer(minor, &src->password, &dst->password);
676         if (GSS_ERROR(major))
677             goto cleanup;
678     }
679
680     major = duplicateOidSet(minor, src->mechanisms, &dst->mechanisms);
681     if (GSS_ERROR(major))
682         goto cleanup;
683
684     dst->expiryTime = src->expiryTime;
685
686     if (src->radiusConfigFile.value != NULL)
687         duplicateBufferOrCleanup(&src->radiusConfigFile, &dst->radiusConfigFile);
688     if (src->radiusConfigStanza.value != NULL)
689         duplicateBufferOrCleanup(&src->radiusConfigStanza, &dst->radiusConfigStanza);
690     if (src->caCertificate.value != NULL)
691         duplicateBufferOrCleanup(&src->caCertificate, &dst->caCertificate);
692     if (src->subjectNameConstraint.value != NULL)
693         duplicateBufferOrCleanup(&src->subjectNameConstraint, &dst->subjectNameConstraint);
694     if (src->subjectAltNameConstraint.value != NULL)
695         duplicateBufferOrCleanup(&src->subjectAltNameConstraint, &dst->subjectAltNameConstraint);
696     if (src->privateKey.value != NULL)
697         duplicateBufferOrCleanup(&src->privateKey, &dst->privateKey);
698
699 #ifdef GSSEAP_ENABLE_REAUTH
700     /* XXX krbCredCache, reauthCred */
701 #endif
702
703     *pDst = dst;
704     dst = GSS_C_NO_CREDENTIAL;
705
706     major = GSS_S_COMPLETE;
707     *minor = 0;
708
709 cleanup:
710     gssEapReleaseCred(&tmpMinor, &dst);
711
712     return major;
713 }
714
715 static OM_uint32
716 staticIdentityFileResolveInitiatorCred(OM_uint32 *minor, gss_cred_id_t cred)
717 {
718     OM_uint32 major, tmpMinor;
719     gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
720     gss_name_t defaultIdentityName = GSS_C_NO_NAME;
721     gss_buffer_desc defaultPassword = GSS_C_EMPTY_BUFFER;
722     gss_buffer_desc defaultPrivateKey = GSS_C_EMPTY_BUFFER;
723     int isDefaultIdentity = FALSE;
724
725     major = readStaticIdentityFile(minor, &defaultIdentity,
726                                    &defaultPassword, &defaultPrivateKey);
727     if (GSS_ERROR(major))
728         goto cleanup;
729
730     major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
731                              gssEapPrimaryMechForCred(cred), &defaultIdentityName);
732     if (GSS_ERROR(major))
733         goto cleanup;
734
735     if (defaultIdentityName == GSS_C_NO_NAME) {
736         if (cred->name == GSS_C_NO_NAME) {
737             major = GSS_S_CRED_UNAVAIL;
738             *minor = GSSEAP_NO_DEFAULT_IDENTITY;
739             goto cleanup;
740         }
741     } else {
742         if (cred->name == GSS_C_NO_NAME) {
743             cred->name = defaultIdentityName;
744             defaultIdentityName = GSS_C_NO_NAME;
745             isDefaultIdentity = TRUE;
746         } else {
747             major = gssEapCompareName(minor, cred->name,
748                                       defaultIdentityName, &isDefaultIdentity);
749             if (GSS_ERROR(major))
750                 goto cleanup;
751         }
752     }
753
754     if (isDefaultIdentity) {
755         if (defaultPrivateKey.length != 0) {
756             major = gssEapSetCredClientCertificate(minor, cred, GSS_C_NO_BUFFER,
757                                                   &defaultPrivateKey);
758             if (GSS_ERROR(major))
759                 goto cleanup;
760         }
761
762         if ((cred->flags & CRED_FLAG_PASSWORD) == 0) {
763             major = gssEapSetCredPassword(minor, cred, &defaultPassword);
764             if (GSS_ERROR(major))
765                 goto cleanup;
766         }
767     }
768
769 cleanup:
770     gssEapReleaseName(&tmpMinor, &defaultIdentityName);
771     zeroAndReleasePassword(&defaultPassword);
772     gss_release_buffer(&tmpMinor, &defaultIdentity);
773     gss_release_buffer(&tmpMinor, &defaultPrivateKey);
774
775     return major;
776 }
777
778 OM_uint32
779 gssEapResolveInitiatorCred(OM_uint32 *minor,
780                            const gss_cred_id_t cred,
781                            const gss_name_t targetName
782 #ifndef HAVE_MOONSHOT_GET_IDENTITY
783                                                        GSSEAP_UNUSED
784 #endif
785                            ,
786                            gss_cred_id_t *pResolvedCred)
787 {
788     OM_uint32 major, tmpMinor;
789     gss_cred_id_t resolvedCred = GSS_C_NO_CREDENTIAL;
790
791     if (cred == GSS_C_NO_CREDENTIAL) {
792         major = gssEapAcquireCred(minor,
793                                   GSS_C_NO_NAME,
794                                   GSS_C_INDEFINITE,
795                                   GSS_C_NO_OID_SET,
796                                   GSS_C_INITIATE,
797                                   &resolvedCred,
798                                   NULL,
799                                   NULL);
800         if (GSS_ERROR(major))
801             goto cleanup;
802     } else {
803         if ((cred->flags & CRED_FLAG_INITIATE) == 0) {
804             major = GSS_S_NO_CRED;
805             *minor = GSSEAP_CRED_USAGE_MISMATCH;
806             goto cleanup;
807         }
808
809         major = gssEapDuplicateCred(minor, cred, &resolvedCred);
810         if (GSS_ERROR(major))
811             goto cleanup;
812     }
813
814     if ((resolvedCred->flags & CRED_FLAG_RESOLVED) == 0) {
815 #ifdef HAVE_MOONSHOT_GET_IDENTITY
816         major = libMoonshotResolveInitiatorCred(minor, resolvedCred, targetName);
817         if (major == GSS_S_CRED_UNAVAIL)
818 #endif
819             major = staticIdentityFileResolveInitiatorCred(minor, resolvedCred);
820         if (GSS_ERROR(major) && major != GSS_S_CRED_UNAVAIL)
821             goto cleanup;
822
823         /* If we have a caller-supplied password, the credential is resolved. */
824         if ((resolvedCred->flags &
825              (CRED_FLAG_PASSWORD | CRED_FLAG_CERTIFICATE)) == 0) {
826             major = GSS_S_CRED_UNAVAIL;
827             *minor = GSSEAP_NO_DEFAULT_CRED;
828             goto cleanup;
829         }
830
831         resolvedCred->flags |= CRED_FLAG_RESOLVED;
832     }
833
834     *pResolvedCred = resolvedCred;
835     resolvedCred = GSS_C_NO_CREDENTIAL;
836
837     major = GSS_S_COMPLETE;
838     *minor = 0;
839
840 cleanup:
841     gssEapReleaseCred(&tmpMinor, &resolvedCred);
842
843     return major;
844 }