X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=util_cred.c;h=1cabdcf7a6f73ee7c1b2adc62567544e2390bace;hb=refs%2Fheads%2Fjson-name;hp=7e659f67cb8c4347393389730dd599d307e85d35;hpb=0e14ab0c812cf75456b61b7ed5e235f8a3da9b87;p=mech_eap.orig diff --git a/util_cred.c b/util_cred.c index 7e659f6..1cabdcf 100644 --- a/util_cred.c +++ b/util_cred.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, JANET(UK) + * Copyright (c) 2011, JANET(UK) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,15 +30,21 @@ * SUCH DAMAGE. */ +/* + * Utility routines for credential handles. + */ + #include "gssapiP_eap.h" +#include + OM_uint32 gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred) { OM_uint32 tmpMinor; gss_cred_id_t cred; - assert(*pCred == GSS_C_NO_CREDENTIAL); + *pCred = GSS_C_NO_CREDENTIAL; cred = (gss_cred_id_t)GSSEAP_CALLOC(1, sizeof(*cred)); if (cred == NULL) { @@ -63,11 +69,14 @@ gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred) { OM_uint32 tmpMinor; gss_cred_id_t cred = *pCred; + krb5_context krbContext = NULL; if (cred == GSS_C_NO_CREDENTIAL) { return GSS_S_COMPLETE; } + GSSEAP_KRB_INIT(&krbContext); + gssEapReleaseName(&tmpMinor, &cred->name); if (cred->password.value != NULL) { @@ -75,6 +84,22 @@ gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred) GSSEAP_FREE(cred->password.value); } + if (cred->radiusConfigFile != NULL) + GSSEAP_FREE(cred->radiusConfigFile); + 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)); GSSEAP_FREE(cred); @@ -84,11 +109,96 @@ gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred) 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, @@ -97,51 +207,140 @@ gssEapAcquireCred(OM_uint32 *minor, { 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; major = gssEapAllocCred(minor, &cred); if (GSS_ERROR(major)) goto cleanup; + switch (credUsage) { + case GSS_C_BOTH: + cred->flags |= CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT; + break; + case GSS_C_INITIATE: + cred->flags |= CRED_FLAG_INITIATE; + break; + case GSS_C_ACCEPT: + cred->flags |= CRED_FLAG_ACCEPT; + 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) { - major = gss_duplicate_name(minor, desiredName, &cred->name); - if (GSS_ERROR(major)) + GSSEAP_MUTEX_LOCK(&desiredName->mutex); + + major = gssEapDuplicateName(minor, desiredName, &cred->name); + if (GSS_ERROR(major)) { + GSSEAP_MUTEX_UNLOCK(&desiredName->mutex); goto cleanup; + } + + GSSEAP_MUTEX_UNLOCK(&desiredName->mutex); + + if (defaultIdentityName != GSS_C_NO_NAME) { + int nameEqual; + + 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)) - goto cleanup; - - switch (credUsage) { - case GSS_C_BOTH: - cred->flags |= CRED_FLAG_INITIATE | CRED_FLAG_ACCEPT; - break; - case GSS_C_INITIATE: - cred->flags |= CRED_FLAG_INITIATE; - break; - case GSS_C_ACCEPT: - cred->flags |= CRED_FLAG_ACCEPT; - break; - default: - major = GSS_S_FAILURE; + 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; - break; } if (pActualMechs != NULL) { @@ -154,11 +353,39 @@ gssEapAcquireCred(OM_uint32 *minor, *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) +{ + OM_uint32 minor; + int present = 0; + + assert(mech != GSS_C_NO_OID); + + if (cred == GSS_C_NO_CREDENTIAL || cred->mechanisms == GSS_C_NO_OID_SET) + return TRUE; + + gss_test_oid_set_member(&minor, mech, cred->mechanisms, &present); + + return present; +}