/*
- * Copyright (c) 2010, JANET(UK)
+ * Copyright (c) 2011, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* SUCH DAMAGE.
*/
+/*
+ * Utility routines for credential handles.
+ */
+
#include "gssapiP_eap.h"
+#include <pwd.h>
+
OM_uint32
gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred)
{
if (cred->radiusConfigFile != NULL)
GSSEAP_FREE(cred->radiusConfigFile);
-
- if (cred->krbCredCache != NULL)
- krb5_cc_destroy(krbContext, cred->krbCredCache);
+ if (cred->radiusConfigStanza != NULL)
+ GSSEAP_FREE(cred->radiusConfigStanza);
+
+#ifdef GSSEAP_ENABLE_REAUTH
+ if (cred->krbCredCache != NULL) {
+ if (cred->flags & CRED_FLAG_DEFAULT_CCACHE)
+ krb5_cc_close(krbContext, cred->krbCredCache);
+ else
+ krb5_cc_destroy(krbContext, cred->krbCredCache);
+ }
if (cred->krbCred != GSS_C_NO_CREDENTIAL)
gssReleaseCred(&tmpMinor, &cred->krbCred);
+#endif
GSSEAP_MUTEX_DESTROY(&cred->mutex);
memset(cred, 0, sizeof(*cred));
return GSS_S_COMPLETE;
}
+static OM_uint32
+readDefaultIdentityAndCreds(OM_uint32 *minor,
+ gss_buffer_t defaultIdentity,
+ gss_buffer_t defaultCreds)
+{
+ OM_uint32 major, tmpMinor;
+ FILE *fp = NULL;
+ char pwbuf[BUFSIZ], buf[BUFSIZ];
+ char *ccacheName;
+ struct passwd *pw = NULL, pwd;
+
+ defaultIdentity->length = 0;
+ defaultIdentity->value = NULL;
+
+ defaultCreds->length = 0;
+ defaultCreds->value = NULL;
+
+ ccacheName = getenv("GSSEAP_IDENTITY");
+ if (ccacheName == NULL) {
+ if (getpwuid_r(getuid(), &pwd, pwbuf, sizeof(pwbuf), &pw) != 0 ||
+ pw == NULL || pw->pw_dir == NULL) {
+ major = GSS_S_CRED_UNAVAIL;
+ *minor = errno;
+ goto cleanup;
+ }
+
+ snprintf(buf, sizeof(buf), "%s/.gss_eap_id", pw->pw_dir);
+ ccacheName = buf;
+ }
+
+ fp = fopen(ccacheName, "r");
+ if (fp == NULL) {
+ major = GSS_S_CRED_UNAVAIL;
+ *minor = GSSEAP_NO_DEFAULT_CRED;
+ goto cleanup;
+ }
+
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ gss_buffer_desc src, *dst;
+
+ src.length = strlen(buf);
+ src.value = buf;
+
+ if (src.length == 0)
+ break;
+
+ if (buf[src.length - 1] == '\n') {
+ buf[src.length - 1] = '\0';
+ if (--src.length == 0)
+ break;
+ }
+
+ if (defaultIdentity->value == NULL)
+ dst = defaultIdentity;
+ else if (defaultCreds->value == NULL)
+ dst = defaultCreds;
+ else
+ break;
+
+ major = duplicateBuffer(minor, &src, dst);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+
+ if (defaultIdentity->length == 0) {
+ major = GSS_S_CRED_UNAVAIL;
+ *minor = GSSEAP_NO_DEFAULT_CRED;
+ goto cleanup;
+ }
+
+ major = GSS_S_COMPLETE;
+ *minor = 0;
+
+cleanup:
+ if (fp != NULL)
+ fclose(fp);
+
+ if (GSS_ERROR(major)) {
+ gss_release_buffer(&tmpMinor, defaultIdentity);
+ gss_release_buffer(&tmpMinor, defaultCreds);
+ }
+
+ return major;
+}
+
OM_uint32
gssEapAcquireCred(OM_uint32 *minor,
const gss_name_t desiredName,
const gss_buffer_t password,
- OM_uint32 timeReq,
+ OM_uint32 timeReq GSSEAP_UNUSED,
const gss_OID_set desiredMechs,
int credUsage,
gss_cred_id_t *pCred,
{
OM_uint32 major, tmpMinor;
gss_cred_id_t cred;
+ gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER;
+ gss_name_t defaultIdentityName = GSS_C_NO_NAME;
+ gss_buffer_desc defaultCreds = GSS_C_EMPTY_BUFFER;
+ gss_OID nameMech = GSS_C_NO_OID;
/* XXX TODO validate with changed set_cred_option API */
*pCred = GSS_C_NO_CREDENTIAL;
break;
default:
major = GSS_S_FAILURE;
+ *minor = GSSEAP_BAD_USAGE;
goto cleanup;
break;
}
+ major = gssEapValidateMechs(minor, desiredMechs);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ major = duplicateOidSet(minor, desiredMechs, &cred->mechanisms);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ if (cred->mechanisms != GSS_C_NO_OID_SET &&
+ cred->mechanisms->count == 1)
+ nameMech = &cred->mechanisms->elements[0];
+
+ if (cred->flags & CRED_FLAG_INITIATE) {
+ major = readDefaultIdentityAndCreds(minor, &defaultIdentity, &defaultCreds);
+ if (major == GSS_S_COMPLETE) {
+ major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME,
+ nameMech, &defaultIdentityName);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ } else if (major != GSS_S_CRED_UNAVAIL)
+ goto cleanup;
+ }
+
if (desiredName != GSS_C_NO_NAME) {
+ GSSEAP_MUTEX_LOCK(&desiredName->mutex);
+
major = gssEapDuplicateName(minor, desiredName, &cred->name);
- if (GSS_ERROR(major))
+ if (GSS_ERROR(major)) {
+ GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
goto cleanup;
- } else {
- if (cred->flags & CRED_FLAG_INITIATE) {
- gss_buffer_desc buf;
+ }
+
+ GSSEAP_MUTEX_UNLOCK(&desiredName->mutex);
- buf.value = getlogin(); /* XXX */
- buf.length = strlen((char *)buf.value);
+ if (defaultIdentityName != GSS_C_NO_NAME) {
+ int nameEqual;
- major = gssEapImportName(minor, &buf,
- GSS_C_NT_USER_NAME, &cred->name);
+ major = gssEapCompareName(minor, desiredName,
+ defaultIdentityName, &nameEqual);
if (GSS_ERROR(major))
goto cleanup;
+ else if (nameEqual)
+ cred->flags |= CRED_FLAG_DEFAULT_IDENTITY;
}
+ } else {
+ if (cred->flags & CRED_FLAG_ACCEPT) {
+ gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
+ char serviceName[5 + MAXHOSTNAMELEN];
+
+ /* default host-based service is host@localhost */
+ memcpy(serviceName, "host@", 5);
+ if (gethostname(&serviceName[5], MAXHOSTNAMELEN) != 0) {
+ major = GSS_S_FAILURE;
+ *minor = GSSEAP_NO_HOSTNAME;
+ goto cleanup;
+ }
+ nameBuf.value = serviceName;
+ nameBuf.length = strlen((char *)nameBuf.value);
+
+ major = gssEapImportName(minor, &nameBuf, GSS_C_NT_HOSTBASED_SERVICE,
+ nameMech, &cred->name);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ } else if (cred->flags & CRED_FLAG_INITIATE) {
+ if (defaultIdentityName == GSS_C_NO_NAME) {
+ major = GSS_S_CRED_UNAVAIL;
+ *minor = GSSEAP_NO_DEFAULT_IDENTITY;
+ goto cleanup;
+ }
+
+ cred->name = defaultIdentityName;
+ defaultIdentityName = GSS_C_NO_NAME;
+ }
cred->flags |= CRED_FLAG_DEFAULT_IDENTITY;
}
+ assert(cred->name != GSS_C_NO_NAME);
+
if (password != GSS_C_NO_BUFFER) {
major = duplicateBuffer(minor, password, &cred->password);
if (GSS_ERROR(major))
goto cleanup;
cred->flags |= CRED_FLAG_PASSWORD;
- }
+ } else if (defaultCreds.value != NULL &&
+ (cred->flags & CRED_FLAG_DEFAULT_IDENTITY)) {
+ cred->password = defaultCreds;
- major = gssEapValidateMechs(minor, desiredMechs);
- if (GSS_ERROR(major))
- goto cleanup;
+ defaultCreds.length = 0;
+ defaultCreds.value = NULL;
- major = duplicateOidSet(minor, desiredMechs, &cred->mechanisms);
- if (GSS_ERROR(major))
+ cred->flags |= CRED_FLAG_PASSWORD;
+ } else if (cred->flags & CRED_FLAG_INITIATE) {
+ /*
+ * OK, here we need to ask the supplicant if we have creds or it
+ * will acquire them, so GS2 can know whether to prompt for a
+ * password or not.
+ */
+#if 0
+ && !gssEapCanReauthP(cred, GSS_C_NO_NAME, timeReq)
+#endif
+ major = GSS_S_CRED_UNAVAIL;
+ *minor = GSSEAP_NO_DEFAULT_CRED;
goto cleanup;
+ }
if (pActualMechs != NULL) {
major = duplicateOidSet(minor, cred->mechanisms, pActualMechs);
*timeRec = GSS_C_INDEFINITE;
*pCred = cred;
+
major = GSS_S_COMPLETE;
+ *minor = 0;
cleanup:
if (GSS_ERROR(major))
gssEapReleaseCred(&tmpMinor, &cred);
+ gssEapReleaseName(&tmpMinor, &defaultIdentityName);
+ gss_release_buffer(&tmpMinor, &defaultIdentity);
+ if (defaultCreds.value != NULL) {
+ memset(defaultCreds.value, 0, defaultCreds.length);
+ gss_release_buffer(&tmpMinor, &defaultCreds);
+ }
return major;
}
+/*
+ * Return TRUE if cred available for mechanism. Caller need no acquire
+ * lock because mechanisms list is immutable.
+ */
int
gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech)
{