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"
42 gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred)
47 *pCred = GSS_C_NO_CREDENTIAL;
49 cred = (gss_cred_id_t)GSSEAP_CALLOC(1, sizeof(*cred));
55 if (GSSEAP_MUTEX_INIT(&cred->mutex) != 0) {
57 gssEapReleaseCred(&tmpMinor, &cred);
64 return GSS_S_COMPLETE;
68 zeroAndReleasePassword(gss_buffer_t password)
70 if (password->value != NULL) {
71 memset(password->value, 0, password->length);
72 GSSEAP_FREE(password->value);
75 password->value = NULL;
80 gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred)
83 gss_cred_id_t cred = *pCred;
84 krb5_context krbContext = NULL;
86 if (cred == GSS_C_NO_CREDENTIAL) {
87 return GSS_S_COMPLETE;
90 GSSEAP_KRB_INIT(&krbContext);
92 gssEapReleaseName(&tmpMinor, &cred->name);
93 gssEapReleaseName(&tmpMinor, &cred->target);
95 zeroAndReleasePassword(&cred->password);
97 gss_release_buffer(&tmpMinor, &cred->radiusConfigFile);
98 gss_release_buffer(&tmpMinor, &cred->radiusConfigStanza);
99 gss_release_buffer(&tmpMinor, &cred->caCertificate);
100 gss_release_buffer(&tmpMinor, &cred->subjectNameConstraint);
101 gss_release_buffer(&tmpMinor, &cred->subjectAltNameConstraint);
103 #ifdef GSSEAP_ENABLE_REAUTH
104 if (cred->krbCredCache != NULL) {
105 if (cred->flags & CRED_FLAG_DEFAULT_CCACHE)
106 krb5_cc_close(krbContext, cred->krbCredCache);
108 krb5_cc_destroy(krbContext, cred->krbCredCache);
110 if (cred->reauthCred != GSS_C_NO_CREDENTIAL)
111 gssReleaseCred(&tmpMinor, &cred->reauthCred);
114 GSSEAP_MUTEX_DESTROY(&cred->mutex);
115 memset(cred, 0, sizeof(*cred));
120 return GSS_S_COMPLETE;
124 readStaticIdentityFile(OM_uint32 *minor,
125 gss_buffer_t defaultIdentity,
126 gss_buffer_t defaultPassword)
128 OM_uint32 major, tmpMinor;
130 char pwbuf[BUFSIZ], buf[BUFSIZ];
132 struct passwd *pw = NULL, pwd;
135 defaultIdentity->length = 0;
136 defaultIdentity->value = NULL;
138 if (defaultPassword != GSS_C_NO_BUFFER) {
139 defaultPassword->length = 0;
140 defaultPassword->value = NULL;
143 ccacheName = getenv("GSSEAP_IDENTITY");
144 if (ccacheName == NULL) {
145 if (getpwuid_r(getuid(), &pwd, pwbuf, sizeof(pwbuf), &pw) != 0 ||
146 pw == NULL || pw->pw_dir == NULL) {
147 major = GSS_S_CRED_UNAVAIL;
152 snprintf(buf, sizeof(buf), "%s/.gss_eap_id", pw->pw_dir);
156 fp = fopen(ccacheName, "r");
158 major = GSS_S_CRED_UNAVAIL;
159 *minor = GSSEAP_NO_DEFAULT_CRED;
163 while (fgets(buf, sizeof(buf), fp) != NULL) {
164 gss_buffer_desc src, *dst;
166 src.length = strlen(buf);
172 if (buf[src.length - 1] == '\n') {
173 buf[src.length - 1] = '\0';
174 if (--src.length == 0)
179 dst = defaultIdentity;
181 dst = defaultPassword;
185 if (dst != GSS_C_NO_BUFFER) {
186 major = duplicateBuffer(minor, &src, dst);
187 if (GSS_ERROR(major))
194 if (defaultIdentity->length == 0) {
195 major = GSS_S_CRED_UNAVAIL;
196 *minor = GSSEAP_NO_DEFAULT_CRED;
200 major = GSS_S_COMPLETE;
207 if (GSS_ERROR(major)) {
208 gss_release_buffer(&tmpMinor, defaultIdentity);
209 zeroAndReleasePassword(defaultPassword);
212 memset(buf, 0, sizeof(buf));
218 gssEapPrimaryMechForCred(gss_cred_id_t cred)
220 gss_OID nameMech = GSS_C_NO_OID;
222 if (cred->mechanisms != GSS_C_NO_OID_SET &&
223 cred->mechanisms->count == 1)
224 nameMech = &cred->mechanisms->elements[0];
230 gssEapAcquireCred(OM_uint32 *minor,
231 const gss_name_t desiredName,
232 OM_uint32 timeReq GSSEAP_UNUSED,
233 const gss_OID_set desiredMechs,
235 gss_cred_id_t *pCred,
236 gss_OID_set *pActualMechs,
239 OM_uint32 major, tmpMinor;
242 /* XXX TODO validate with changed set_cred_option API */
243 *pCred = GSS_C_NO_CREDENTIAL;
245 major = gssEapAllocCred(minor, &cred);
246 if (GSS_ERROR(major))
251 cred->flags |= CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT;
254 cred->flags |= CRED_FLAG_INITIATE;
257 cred->flags |= CRED_FLAG_ACCEPT;
260 major = GSS_S_FAILURE;
261 *minor = GSSEAP_BAD_USAGE;
266 major = gssEapValidateMechs(minor, desiredMechs);
267 if (GSS_ERROR(major))
270 major = duplicateOidSet(minor, desiredMechs, &cred->mechanisms);
271 if (GSS_ERROR(major))
274 if (desiredName != GSS_C_NO_NAME) {
275 GSSEAP_MUTEX_LOCK(&desiredName->mutex);
277 major = gssEapDuplicateName(minor, desiredName, &cred->name);
278 if (GSS_ERROR(major)) {
279 GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
283 GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
286 if (pActualMechs != NULL) {
287 major = duplicateOidSet(minor, cred->mechanisms, pActualMechs);
288 if (GSS_ERROR(major))
293 *timeRec = GSS_C_INDEFINITE;
297 major = GSS_S_COMPLETE;
301 if (GSS_ERROR(major))
302 gssEapReleaseCred(&tmpMinor, &cred);
308 * Return TRUE if cred available for mechanism. Caller need no acquire
309 * lock because mechanisms list is immutable.
312 gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech)
317 assert(mech != GSS_C_NO_OID);
319 if (cred == GSS_C_NO_CREDENTIAL || cred->mechanisms == GSS_C_NO_OID_SET)
322 gss_test_oid_set_member(&minor, mech, cred->mechanisms, &present);
328 staticIdentityFileResolveDefaultIdentity(OM_uint32 *minor,
329 const gss_cred_id_t cred,
332 OM_uint32 major, tmpMinor;
333 gss_OID nameMech = gssEapPrimaryMechForCred(cred);
334 gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
336 *pName = GSS_C_NO_NAME;
338 major = readStaticIdentityFile(minor, &defaultIdentity, GSS_C_NO_BUFFER);
339 if (major == GSS_S_COMPLETE) {
340 major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
344 gss_release_buffer(&tmpMinor, &defaultIdentity);
350 gssEapResolveCredIdentity(OM_uint32 *minor,
354 gss_OID nameMech = gssEapPrimaryMechForCred(cred);
356 if (cred->name != GSS_C_NO_NAME) {
358 return GSS_S_COMPLETE;
361 if (cred->flags & CRED_FLAG_ACCEPT) {
362 gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
363 char serviceName[5 + MAXHOSTNAMELEN];
365 /* default host-based service is host@localhost */
366 memcpy(serviceName, "host@", 5);
367 if (gethostname(&serviceName[5], MAXHOSTNAMELEN) != 0) {
368 *minor = GSSEAP_NO_HOSTNAME;
369 return GSS_S_FAILURE;
372 nameBuf.value = serviceName;
373 nameBuf.length = strlen((char *)nameBuf.value);
375 major = gssEapImportName(minor, &nameBuf, GSS_C_NT_HOSTBASED_SERVICE,
376 nameMech, &cred->name);
377 if (GSS_ERROR(major))
379 } else if (cred->flags & CRED_FLAG_INITIATE) {
380 #ifdef HAVE_MOONSHOT_GET_IDENTITY
381 major = libMoonshotResolveDefaultIdentity(minor, cred, &cred->name);
382 if (major == GSS_S_CRED_UNAVAIL)
384 major = staticIdentityFileResolveDefaultIdentity(minor, cred, &cred->name);
385 if (major != GSS_S_CRED_UNAVAIL)
390 return GSS_S_COMPLETE;
394 gssEapInquireCred(OM_uint32 *minor,
397 OM_uint32 *pLifetime,
398 gss_cred_usage_t *cred_usage,
399 gss_OID_set *mechanisms)
402 time_t now, lifetime;
405 major = gssEapResolveCredIdentity(minor, cred);
406 if (GSS_ERROR(major))
409 if (cred->name != GSS_C_NO_NAME) {
410 major = gssEapDuplicateName(minor, cred->name, name);
411 if (GSS_ERROR(major))
414 *name = GSS_C_NO_NAME;
417 if (cred_usage != NULL) {
418 OM_uint32 flags = (cred->flags & (CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT));
421 case CRED_FLAG_INITIATE:
422 *cred_usage = GSS_C_INITIATE;
424 case CRED_FLAG_ACCEPT:
425 *cred_usage = GSS_C_ACCEPT;
428 *cred_usage = GSS_C_BOTH;
433 if (mechanisms != NULL) {
434 if (cred->mechanisms != GSS_C_NO_OID_SET)
435 major = duplicateOidSet(minor, cred->mechanisms, mechanisms);
437 major = gssEapIndicateMechs(minor, mechanisms);
438 if (GSS_ERROR(major))
442 if (cred->expiryTime == 0) {
443 lifetime = GSS_C_INDEFINITE;
446 lifetime = now - cred->expiryTime;
451 if (pLifetime != NULL) {
452 *pLifetime = lifetime;
456 major = GSS_S_CREDENTIALS_EXPIRED;
457 *minor = GSSEAP_CRED_EXPIRED;
461 major = GSS_S_COMPLETE;
469 gssEapSetCredPassword(OM_uint32 *minor,
471 const gss_buffer_t password)
473 OM_uint32 major, tmpMinor;
474 gss_buffer_desc newPassword = GSS_C_EMPTY_BUFFER;
476 if (cred->flags & CRED_FLAG_RESOLVED) {
477 major = GSS_S_FAILURE;
478 *minor = GSSEAP_CRED_RESOLVED;
482 if (password != GSS_C_NO_BUFFER) {
483 major = duplicateBuffer(minor, password, &newPassword);
484 if (GSS_ERROR(major))
487 cred->flags |= CRED_FLAG_PASSWORD;
489 cred->flags &= ~(CRED_FLAG_PASSWORD);
492 gss_release_buffer(&tmpMinor, &cred->password);
493 cred->password = newPassword;
495 major = GSS_S_COMPLETE;
503 gssEapDuplicateCred(OM_uint32 *minor,
504 const gss_cred_id_t src,
507 OM_uint32 major, tmpMinor;
508 gss_cred_id_t dst = GSS_C_NO_CREDENTIAL;
510 *pDst = GSS_C_NO_CREDENTIAL;
512 major = gssEapAllocCred(minor, &dst);
513 if (GSS_ERROR(major))
516 dst->flags = src->flags;
518 if (src->name != GSS_C_NO_NAME) {
519 major = gssEapDuplicateName(minor, src->name, &dst->name);
520 if (GSS_ERROR(major))
524 if (src->target != GSS_C_NO_NAME) {
525 major = gssEapDuplicateName(minor, src->target, &dst->target);
526 if (GSS_ERROR(major))
530 if (src->password.value != NULL) {
531 major = duplicateBuffer(minor, &src->password, &dst->password);
532 if (GSS_ERROR(major))
536 major = duplicateOidSet(minor, src->mechanisms, &dst->mechanisms);
537 if (GSS_ERROR(major))
540 dst->expiryTime = src->expiryTime;
542 if (src->radiusConfigFile.value != NULL)
543 duplicateBufferOrCleanup(&src->radiusConfigFile, &dst->radiusConfigFile);
544 if (src->radiusConfigStanza.value != NULL)
545 duplicateBufferOrCleanup(&src->radiusConfigStanza, &dst->radiusConfigStanza);
546 if (src->caCertificate.value != NULL)
547 duplicateBufferOrCleanup(&src->caCertificate, &dst->caCertificate);
548 if (src->subjectNameConstraint.value != NULL)
549 duplicateBufferOrCleanup(&src->subjectNameConstraint, &dst->subjectNameConstraint);
550 if (src->subjectAltNameConstraint.value != NULL)
551 duplicateBufferOrCleanup(&src->subjectAltNameConstraint, &dst->subjectAltNameConstraint);
553 #ifdef GSSEAP_ENABLE_REAUTH
554 /* XXX krbCredCache, reauthCred */
558 dst = GSS_C_NO_CREDENTIAL;
560 major = GSS_S_COMPLETE;
564 gssEapReleaseCred(&tmpMinor, &dst);
570 staticIdentityFileResolveInitiatorCred(OM_uint32 *minor, gss_cred_id_t cred)
572 OM_uint32 major, tmpMinor;
573 gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
574 gss_name_t defaultIdentityName = GSS_C_NO_NAME;
575 gss_buffer_desc defaultPassword = GSS_C_EMPTY_BUFFER;
576 int isDefaultIdentity = FALSE;
578 major = readStaticIdentityFile(minor, &defaultIdentity, &defaultPassword);
579 if (GSS_ERROR(major))
582 major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
583 gssEapPrimaryMechForCred(cred), &defaultIdentityName);
584 if (GSS_ERROR(major))
587 if (defaultIdentityName == GSS_C_NO_NAME) {
588 if (cred->name == GSS_C_NO_NAME) {
589 major = GSS_S_CRED_UNAVAIL;
590 *minor = GSSEAP_NO_DEFAULT_IDENTITY;
594 if (cred->name == GSS_C_NO_NAME) {
595 cred->name = defaultIdentityName;
596 defaultIdentityName = GSS_C_NO_NAME;
597 isDefaultIdentity = TRUE;
599 major = gssEapCompareName(minor, cred->name,
600 defaultIdentityName, &isDefaultIdentity);
601 if (GSS_ERROR(major))
606 if (isDefaultIdentity &&
607 (cred->flags & CRED_FLAG_PASSWORD) == 0) {
608 major = gssEapSetCredPassword(minor, cred, &defaultPassword);
609 if (GSS_ERROR(major))
614 gssEapReleaseName(&tmpMinor, &defaultIdentityName);
615 zeroAndReleasePassword(&defaultPassword);
616 gss_release_buffer(&tmpMinor, &defaultIdentity);
622 gssEapResolveInitiatorCred(OM_uint32 *minor,
623 const gss_cred_id_t cred,
624 const gss_name_t targetName
625 #ifndef HAVE_MOONSHOT_GET_IDENTITY
629 gss_cred_id_t *pResolvedCred)
631 OM_uint32 major, tmpMinor;
632 gss_cred_id_t resolvedCred = GSS_C_NO_CREDENTIAL;
634 if (cred == GSS_C_NO_CREDENTIAL) {
635 major = gssEapAcquireCred(minor,
643 if (GSS_ERROR(major))
646 if ((cred->flags & CRED_FLAG_INITIATE) == 0) {
647 major = GSS_S_NO_CRED;
648 *minor = GSSEAP_CRED_USAGE_MISMATCH;
652 major = gssEapDuplicateCred(minor, cred, &resolvedCred);
653 if (GSS_ERROR(major))
657 if ((resolvedCred->flags & CRED_FLAG_RESOLVED) == 0) {
658 #ifdef HAVE_MOONSHOT_GET_IDENTITY
659 major = libMoonshotResolveInitiatorCred(minor, resolvedCred, targetName);
660 if (major == GSS_S_CRED_UNAVAIL)
662 major = staticIdentityFileResolveInitiatorCred(minor, resolvedCred);
663 if (GSS_ERROR(major))
666 if ((resolvedCred->flags & CRED_FLAG_PASSWORD) == 0) {
667 major = GSS_S_CRED_UNAVAIL;
668 *minor = GSSEAP_NO_DEFAULT_CRED;
672 resolvedCred->flags |= CRED_FLAG_RESOLVED;
675 *pResolvedCred = resolvedCred;
676 resolvedCred = GSS_C_NO_CREDENTIAL;
678 major = GSS_S_COMPLETE;
682 gssEapReleaseCred(&tmpMinor, &resolvedCred);