2
* Copyright (c) 2011, JANET(UK)
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
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.
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.
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
34
* Utility routines for credential handles.
37
#include "gssapiP_eap.h"
40
# include <shlobj.h> /* may need to use ShFolder.h instead */
47
gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred)
52
*pCred = GSS_C_NO_CREDENTIAL;
54
cred = (gss_cred_id_t)GSSEAP_CALLOC(1, sizeof(*cred));
60
if (GSSEAP_MUTEX_INIT(&cred->mutex) != 0) {
61
*minor = GSSEAP_GET_LAST_ERROR();
62
gssEapReleaseCred(&tmpMinor, &cred);
69
return GSS_S_COMPLETE;
73
zeroAndReleasePassword(gss_buffer_t password)
75
GSSEAP_ASSERT(password != GSS_C_NO_BUFFER);
77
if (password->value != NULL) {
78
memset(password->value, 0, password->length);
79
GSSEAP_FREE(password->value);
82
password->value = NULL;
87
gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred)
90
gss_cred_id_t cred = *pCred;
91
krb5_context krbContext = NULL;
93
if (cred == GSS_C_NO_CREDENTIAL) {
94
return GSS_S_COMPLETE;
97
GSSEAP_KRB_INIT(&krbContext);
99
gssEapReleaseName(&tmpMinor, &cred->name);
100
gssEapReleaseName(&tmpMinor, &cred->target);
102
zeroAndReleasePassword(&cred->password);
104
gss_release_buffer(&tmpMinor, &cred->radiusConfigFile);
105
gss_release_buffer(&tmpMinor, &cred->radiusConfigStanza);
106
gss_release_buffer(&tmpMinor, &cred->caCertificate);
107
gss_release_buffer(&tmpMinor, &cred->caCertificateBlob);
108
gss_release_buffer(&tmpMinor, &cred->subjectNameConstraint);
109
gss_release_buffer(&tmpMinor, &cred->subjectAltNameConstraint);
110
gss_release_buffer(&tmpMinor, &cred->clientCertificate);
111
gss_release_buffer(&tmpMinor, &cred->privateKey);
113
#ifdef GSSEAP_ENABLE_REAUTH
114
if (cred->krbCredCache != NULL) {
115
if (cred->flags & CRED_FLAG_DEFAULT_CCACHE)
116
krb5_cc_close(krbContext, cred->krbCredCache);
118
krb5_cc_destroy(krbContext, cred->krbCredCache);
120
if (cred->reauthCred != GSS_C_NO_CREDENTIAL)
121
gssReleaseCred(&tmpMinor, &cred->reauthCred);
124
GSSEAP_MUTEX_DESTROY(&cred->mutex);
125
memset(cred, 0, sizeof(*cred));
130
return GSS_S_COMPLETE;
134
readStaticIdentityFile(OM_uint32 *minor,
135
gss_buffer_t defaultIdentity,
136
gss_buffer_t defaultPassword)
138
OM_uint32 major, tmpMinor;
144
struct passwd *pw = NULL, pwd;
148
defaultIdentity->length = 0;
149
defaultIdentity->value = NULL;
151
if (defaultPassword != GSS_C_NO_BUFFER) {
152
defaultPassword->length = 0;
153
defaultPassword->value = NULL;
156
ccacheName = getenv("GSSEAP_IDENTITY");
157
if (ccacheName == NULL) {
159
TCHAR szPath[MAX_PATH];
161
if (!SUCCEEDED(SHGetFolderPath(NULL,
162
CSIDL_APPDATA, /* |CSIDL_FLAG_CREATE */
163
NULL, /* User access token */
164
0, /* SHGFP_TYPE_CURRENT */
166
major = GSS_S_CRED_UNAVAIL;
167
*minor = GSSEAP_GET_LAST_ERROR(); /* XXX */
171
snprintf(buf, sizeof(buf), "%s/.gss_eap_id", szPath);
173
if (getpwuid_r(getuid(), &pwd, pwbuf, sizeof(pwbuf), &pw) != 0 ||
174
pw == NULL || pw->pw_dir == NULL) {
175
major = GSS_S_CRED_UNAVAIL;
176
*minor = GSSEAP_GET_LAST_ERROR();
180
snprintf(buf, sizeof(buf), "%s/.gss_eap_id", pw->pw_dir);
185
fp = fopen(ccacheName, "r");
187
major = GSS_S_CRED_UNAVAIL;
188
*minor = GSSEAP_NO_DEFAULT_CRED;
192
while (fgets(buf, sizeof(buf), fp) != NULL) {
193
gss_buffer_desc src, *dst;
195
src.length = strlen(buf);
201
if (buf[src.length - 1] == '\n') {
202
buf[src.length - 1] = '\0';
203
if (--src.length == 0)
208
dst = defaultIdentity;
210
dst = defaultPassword;
214
if (dst != GSS_C_NO_BUFFER) {
215
major = duplicateBuffer(minor, &src, dst);
216
if (GSS_ERROR(major))
223
if (defaultIdentity->length == 0) {
224
major = GSS_S_CRED_UNAVAIL;
225
*minor = GSSEAP_NO_DEFAULT_CRED;
229
major = GSS_S_COMPLETE;
236
if (GSS_ERROR(major)) {
237
gss_release_buffer(&tmpMinor, defaultIdentity);
238
zeroAndReleasePassword(defaultPassword);
241
memset(buf, 0, sizeof(buf));
247
gssEapPrimaryMechForCred(gss_cred_id_t cred)
249
gss_OID credMech = GSS_C_NO_OID;
251
if (cred != GSS_C_NO_CREDENTIAL &&
252
cred->mechanisms != GSS_C_NO_OID_SET &&
253
cred->mechanisms->count == 1)
254
credMech = &cred->mechanisms->elements[0];
260
gssEapAcquireCred(OM_uint32 *minor,
261
const gss_name_t desiredName,
262
OM_uint32 timeReq GSSEAP_UNUSED,
263
const gss_OID_set desiredMechs,
265
gss_cred_id_t *pCred,
266
gss_OID_set *pActualMechs,
269
OM_uint32 major, tmpMinor;
272
/* XXX TODO validate with changed set_cred_option API */
273
*pCred = GSS_C_NO_CREDENTIAL;
275
major = gssEapAllocCred(minor, &cred);
276
if (GSS_ERROR(major))
281
cred->flags |= CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT;
284
cred->flags |= CRED_FLAG_INITIATE;
287
cred->flags |= CRED_FLAG_ACCEPT;
290
major = GSS_S_FAILURE;
291
*minor = GSSEAP_BAD_USAGE;
296
major = gssEapValidateMechs(minor, desiredMechs);
297
if (GSS_ERROR(major))
300
major = duplicateOidSet(minor, desiredMechs, &cred->mechanisms);
301
if (GSS_ERROR(major))
304
if (desiredName != GSS_C_NO_NAME) {
305
GSSEAP_MUTEX_LOCK(&desiredName->mutex);
307
major = gssEapDuplicateName(minor, desiredName, &cred->name);
308
if (GSS_ERROR(major)) {
309
GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
313
GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
316
#ifdef GSSEAP_ENABLE_ACCEPTOR
317
if (cred->flags & CRED_FLAG_ACCEPT) {
318
struct rs_context *radContext;
320
major = gssEapCreateRadiusContext(minor, cred, &radContext);
321
if (GSS_ERROR(major))
324
rs_context_destroy(radContext);
328
if (pActualMechs != NULL) {
329
major = duplicateOidSet(minor, cred->mechanisms, pActualMechs);
330
if (GSS_ERROR(major))
335
*timeRec = GSS_C_INDEFINITE;
339
major = GSS_S_COMPLETE;
343
if (GSS_ERROR(major))
344
gssEapReleaseCred(&tmpMinor, &cred);
350
* Return TRUE if cred available for mechanism. Caller need no acquire
351
* lock because mechanisms list is immutable.
354
gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech)
359
GSSEAP_ASSERT(mech != GSS_C_NO_OID);
361
if (cred == GSS_C_NO_CREDENTIAL || cred->mechanisms == GSS_C_NO_OID_SET)
364
gss_test_oid_set_member(&minor, mech, cred->mechanisms, &present);
370
staticIdentityFileResolveDefaultIdentity(OM_uint32 *minor,
371
const gss_cred_id_t cred,
374
OM_uint32 major, tmpMinor;
375
gss_OID nameMech = gssEapPrimaryMechForCred(cred);
376
gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
378
*pName = GSS_C_NO_NAME;
380
major = readStaticIdentityFile(minor, &defaultIdentity, GSS_C_NO_BUFFER);
381
if (major == GSS_S_COMPLETE) {
382
major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
386
gss_release_buffer(&tmpMinor, &defaultIdentity);
392
gssEapResolveCredIdentity(OM_uint32 *minor,
396
gss_OID nameMech = gssEapPrimaryMechForCred(cred);
398
if (cred->name != GSS_C_NO_NAME) {
400
return GSS_S_COMPLETE;
403
if (cred->flags & CRED_FLAG_ACCEPT) {
404
gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
405
char serviceName[5 + MAXHOSTNAMELEN];
407
/* default host-based service is host@localhost */
408
memcpy(serviceName, "host@", 5);
409
if (gethostname(&serviceName[5], MAXHOSTNAMELEN) != 0) {
410
*minor = GSSEAP_NO_HOSTNAME;
411
return GSS_S_FAILURE;
414
nameBuf.value = serviceName;
415
nameBuf.length = strlen((char *)nameBuf.value);
417
major = gssEapImportName(minor, &nameBuf, GSS_C_NT_HOSTBASED_SERVICE,
418
nameMech, &cred->name);
419
if (GSS_ERROR(major))
421
} else if (cred->flags & CRED_FLAG_INITIATE) {
422
#ifdef HAVE_MOONSHOT_GET_IDENTITY
423
major = libMoonshotResolveDefaultIdentity(minor, cred, &cred->name);
424
if (major == GSS_S_CRED_UNAVAIL)
426
major = staticIdentityFileResolveDefaultIdentity(minor, cred, &cred->name);
427
if (major != GSS_S_CRED_UNAVAIL)
432
return GSS_S_COMPLETE;
436
gssEapInquireCred(OM_uint32 *minor,
439
OM_uint32 *pLifetime,
440
gss_cred_usage_t *cred_usage,
441
gss_OID_set *mechanisms)
444
time_t now, lifetime;
447
major = gssEapResolveCredIdentity(minor, cred);
448
if (GSS_ERROR(major))
451
if (cred->name != GSS_C_NO_NAME) {
452
major = gssEapDuplicateName(minor, cred->name, name);
453
if (GSS_ERROR(major))
456
*name = GSS_C_NO_NAME;
459
if (cred_usage != NULL) {
460
OM_uint32 flags = (cred->flags & (CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT));
463
case CRED_FLAG_INITIATE:
464
*cred_usage = GSS_C_INITIATE;
466
case CRED_FLAG_ACCEPT:
467
*cred_usage = GSS_C_ACCEPT;
470
*cred_usage = GSS_C_BOTH;
475
if (mechanisms != NULL) {
476
if (cred->mechanisms != GSS_C_NO_OID_SET)
477
major = duplicateOidSet(minor, cred->mechanisms, mechanisms);
479
major = gssEapIndicateMechs(minor, mechanisms);
480
if (GSS_ERROR(major))
484
if (cred->expiryTime == 0) {
485
lifetime = GSS_C_INDEFINITE;
488
lifetime = now - cred->expiryTime;
493
if (pLifetime != NULL) {
494
*pLifetime = lifetime;
498
major = GSS_S_CREDENTIALS_EXPIRED;
499
*minor = GSSEAP_CRED_EXPIRED;
503
major = GSS_S_COMPLETE;
511
gssEapSetCredPassword(OM_uint32 *minor,
513
const gss_buffer_t password)
515
OM_uint32 major, tmpMinor;
516
gss_buffer_desc newPassword = GSS_C_EMPTY_BUFFER;
518
if (cred->flags & CRED_FLAG_RESOLVED) {
519
major = GSS_S_FAILURE;
520
*minor = GSSEAP_CRED_RESOLVED;
524
if (password != GSS_C_NO_BUFFER) {
525
major = duplicateBuffer(minor, password, &newPassword);
526
if (GSS_ERROR(major))
529
cred->flags |= CRED_FLAG_PASSWORD;
531
cred->flags &= ~(CRED_FLAG_PASSWORD);
534
gss_release_buffer(&tmpMinor, &cred->password);
535
cred->password = newPassword;
537
major = GSS_S_COMPLETE;
545
* Currently only the privateKey path is exposed to the application
546
* (via gss_set_cred_option() or the third line in ~/.gss_eap_id).
547
* At some point in the future we may add support for setting the
548
* client certificate separately.
551
gssEapSetCredClientCertificate(OM_uint32 *minor,
553
const gss_buffer_t clientCert,
554
const gss_buffer_t privateKey)
556
OM_uint32 major, tmpMinor;
557
gss_buffer_desc newClientCert = GSS_C_EMPTY_BUFFER;
558
gss_buffer_desc newPrivateKey = GSS_C_EMPTY_BUFFER;
560
if (cred->flags & CRED_FLAG_RESOLVED) {
561
major = GSS_S_FAILURE;
562
*minor = GSSEAP_CRED_RESOLVED;
566
if (clientCert == GSS_C_NO_BUFFER &&
567
privateKey == GSS_C_NO_BUFFER) {
568
cred->flags &= ~(CRED_FLAG_CERTIFICATE);
569
major = GSS_S_COMPLETE;
574
if (clientCert != GSS_C_NO_BUFFER) {
575
major = duplicateBuffer(minor, clientCert, &newClientCert);
576
if (GSS_ERROR(major))
580
if (privateKey != GSS_C_NO_BUFFER) {
581
major = duplicateBuffer(minor, privateKey, &newPrivateKey);
582
if (GSS_ERROR(major))
586
cred->flags |= CRED_FLAG_CERTIFICATE;
588
gss_release_buffer(&tmpMinor, &cred->clientCertificate);
589
cred->clientCertificate = newClientCert;
591
gss_release_buffer(&tmpMinor, &cred->privateKey);
592
cred->privateKey = newPrivateKey;
594
major = GSS_S_COMPLETE;
598
if (GSS_ERROR(major)) {
599
gss_release_buffer(&tmpMinor, &newClientCert);
600
gss_release_buffer(&tmpMinor, &newPrivateKey);
607
gssEapSetCredService(OM_uint32 *minor,
609
const gss_name_t target)
611
OM_uint32 major, tmpMinor;
612
gss_name_t newTarget = GSS_C_NO_NAME;
614
if (cred->flags & CRED_FLAG_RESOLVED) {
615
major = GSS_S_FAILURE;
616
*minor = GSSEAP_CRED_RESOLVED;
620
if (target != GSS_C_NO_NAME) {
621
major = gssEapDuplicateName(minor, target, &newTarget);
622
if (GSS_ERROR(major))
625
cred->flags |= CRED_FLAG_TARGET;
627
cred->flags &= ~(CRED_FLAG_TARGET);
630
gssEapReleaseName(&tmpMinor, &cred->target);
631
cred->target = newTarget;
633
major = GSS_S_COMPLETE;
641
gssEapDuplicateCred(OM_uint32 *minor,
642
const gss_cred_id_t src,
645
OM_uint32 major, tmpMinor;
646
gss_cred_id_t dst = GSS_C_NO_CREDENTIAL;
648
*pDst = GSS_C_NO_CREDENTIAL;
650
major = gssEapAllocCred(minor, &dst);
651
if (GSS_ERROR(major))
654
dst->flags = src->flags;
656
if (src->name != GSS_C_NO_NAME) {
657
major = gssEapDuplicateName(minor, src->name, &dst->name);
658
if (GSS_ERROR(major))
662
if (src->target != GSS_C_NO_NAME) {
663
major = gssEapDuplicateName(minor, src->target, &dst->target);
664
if (GSS_ERROR(major))
668
if (src->password.value != NULL) {
669
major = duplicateBuffer(minor, &src->password, &dst->password);
670
if (GSS_ERROR(major))
674
major = duplicateOidSet(minor, src->mechanisms, &dst->mechanisms);
675
if (GSS_ERROR(major))
678
dst->expiryTime = src->expiryTime;
680
if (src->radiusConfigFile.value != NULL)
681
duplicateBufferOrCleanup(&src->radiusConfigFile, &dst->radiusConfigFile);
682
if (src->radiusConfigStanza.value != NULL)
683
duplicateBufferOrCleanup(&src->radiusConfigStanza, &dst->radiusConfigStanza);
684
if (src->caCertificate.value != NULL)
685
duplicateBufferOrCleanup(&src->caCertificate, &dst->caCertificate);
686
if (src->caCertificateBlob.value != NULL)
687
duplicateBufferOrCleanup(&src->caCertificateBlob, &dst->caCertificateBlob);
688
if (src->subjectNameConstraint.value != NULL)
689
duplicateBufferOrCleanup(&src->subjectNameConstraint, &dst->subjectNameConstraint);
690
if (src->subjectAltNameConstraint.value != NULL)
691
duplicateBufferOrCleanup(&src->subjectAltNameConstraint, &dst->subjectAltNameConstraint);
692
if (src->clientCertificate.value != NULL)
693
duplicateBufferOrCleanup(&src->clientCertificate, &dst->clientCertificate);
694
if (src->privateKey.value != NULL)
695
duplicateBufferOrCleanup(&src->privateKey, &dst->privateKey);
697
#ifdef GSSEAP_ENABLE_REAUTH
698
/* XXX krbCredCache, reauthCred */
702
dst = GSS_C_NO_CREDENTIAL;
704
major = GSS_S_COMPLETE;
708
gssEapReleaseCred(&tmpMinor, &dst);
714
staticIdentityFileResolveInitiatorCred(OM_uint32 *minor, gss_cred_id_t cred)
716
OM_uint32 major, tmpMinor;
717
gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
718
gss_name_t defaultIdentityName = GSS_C_NO_NAME;
719
gss_buffer_desc defaultPassword = GSS_C_EMPTY_BUFFER;
720
int isDefaultIdentity = FALSE;
722
major = readStaticIdentityFile(minor, &defaultIdentity, &defaultPassword);
723
if (GSS_ERROR(major))
726
major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
727
gssEapPrimaryMechForCred(cred), &defaultIdentityName);
728
if (GSS_ERROR(major))
731
if (defaultIdentityName == GSS_C_NO_NAME) {
732
if (cred->name == GSS_C_NO_NAME) {
733
major = GSS_S_CRED_UNAVAIL;
734
*minor = GSSEAP_NO_DEFAULT_IDENTITY;
738
if (cred->name == GSS_C_NO_NAME) {
739
cred->name = defaultIdentityName;
740
defaultIdentityName = GSS_C_NO_NAME;
741
isDefaultIdentity = TRUE;
743
major = gssEapCompareName(minor, cred->name,
744
defaultIdentityName, 0,
746
if (GSS_ERROR(major))
751
if (isDefaultIdentity &&
752
(cred->flags & CRED_FLAG_PASSWORD) == 0) {
753
major = gssEapSetCredPassword(minor, cred, &defaultPassword);
754
if (GSS_ERROR(major))
759
gssEapReleaseName(&tmpMinor, &defaultIdentityName);
760
zeroAndReleasePassword(&defaultPassword);
761
gss_release_buffer(&tmpMinor, &defaultIdentity);
767
gssEapResolveInitiatorCred(OM_uint32 *minor,
768
const gss_cred_id_t cred,
769
const gss_name_t targetName
770
#ifndef HAVE_MOONSHOT_GET_IDENTITY
774
gss_cred_id_t *pResolvedCred)
776
OM_uint32 major, tmpMinor;
777
gss_cred_id_t resolvedCred = GSS_C_NO_CREDENTIAL;
779
if (cred == GSS_C_NO_CREDENTIAL) {
780
major = gssEapAcquireCred(minor,
788
if (GSS_ERROR(major))
791
if ((cred->flags & CRED_FLAG_INITIATE) == 0) {
792
major = GSS_S_NO_CRED;
793
*minor = GSSEAP_CRED_USAGE_MISMATCH;
797
major = gssEapDuplicateCred(minor, cred, &resolvedCred);
798
if (GSS_ERROR(major))
802
if ((resolvedCred->flags & CRED_FLAG_RESOLVED) == 0) {
803
#ifdef HAVE_MOONSHOT_GET_IDENTITY
804
major = libMoonshotResolveInitiatorCred(minor, resolvedCred, targetName);
805
if (major == GSS_S_CRED_UNAVAIL)
807
major = staticIdentityFileResolveInitiatorCred(minor, resolvedCred);
808
if (GSS_ERROR(major) && major != GSS_S_CRED_UNAVAIL)
811
/* If we have a caller-supplied password, the credential is resolved. */
812
if ((resolvedCred->flags &
813
(CRED_FLAG_PASSWORD | CRED_FLAG_CERTIFICATE)) == 0) {
814
major = GSS_S_CRED_UNAVAIL;
815
*minor = GSSEAP_NO_DEFAULT_CRED;
819
resolvedCred->flags |= CRED_FLAG_RESOLVED;
822
*pResolvedCred = resolvedCred;
823
resolvedCred = GSS_C_NO_CREDENTIAL;
825
major = GSS_S_COMPLETE;
829
gssEapReleaseCred(&tmpMinor, &resolvedCred);