X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=util_name.c;h=aa19b943c7514306adf6bdea9359c0a6c19838cc;hb=refs%2Fheads%2Fvm-integration;hp=af34d67bf2f82fa15453757ee4a5da5234d56b25;hpb=62ec2817b9de6e244b9320900305ac690d0b638d;p=mech_eap.orig diff --git a/util_name.c b/util_name.c index af34d67..aa19b94 100644 --- a/util_name.c +++ b/util_name.c @@ -149,6 +149,17 @@ krbPrincipalToName(OM_uint32 *minor, return GSS_S_COMPLETE; } +static char * +gssEapGetDefaultRealm(krb5_context krbContext) +{ + char *defaultRealm = NULL; + + krb5_appdefault_string(krbContext, "eap_gss", + NULL, "default_realm", "", &defaultRealm); + + return defaultRealm; +} + static OM_uint32 importServiceName(OM_uint32 *minor, const gss_buffer_t nameBuffer, @@ -172,7 +183,7 @@ importServiceName(OM_uint32 *minor, host++; } - krb5_get_default_realm(krbContext, &realm); + realm = gssEapGetDefaultRealm(krbContext); code = krb5_build_principal(krbContext, &krbPrinc, @@ -182,9 +193,6 @@ importServiceName(OM_uint32 *minor, host, NULL); - if (realm != NULL) - krb5_free_default_realm(krbContext, realm); - if (code == 0) { KRB_PRINC_TYPE(krbPrinc) = KRB5_NT_SRV_HST; @@ -196,79 +204,118 @@ importServiceName(OM_uint32 *minor, *minor = GSSEAP_BAD_SERVICE_NAME; } + if (realm != NULL) + GSSEAP_FREE(realm); GSSEAP_FREE(service); return major; } +#define IMPORT_FLAG_DEFAULT_REALM 0x1 + +/* + * Import an EAP name, possibly appending the default GSS EAP realm, + */ static OM_uint32 -importUserName(OM_uint32 *minor, - const gss_buffer_t nameBuffer, - gss_name_t *pName) +importEapNameFlags(OM_uint32 *minor, + const gss_buffer_t nameBuffer, + OM_uint32 importFlags, + gss_name_t *pName) { OM_uint32 major; krb5_context krbContext; - krb5_principal krbPrinc; - char *nameString, *realm = NULL; - int flags = 0; + krb5_principal krbPrinc = NULL; krb5_error_code code; GSSEAP_KRB_INIT(&krbContext); - code = krb5_get_default_realm(krbContext, &realm); - if (code != 0 || realm == NULL) - flags |= KRB5_PRINCIPAL_PARSE_REQUIRE_REALM; - else - krb5_free_default_realm(krbContext, realm); - if (nameBuffer == GSS_C_NO_BUFFER) { - *minor = krb5_copy_principal(krbContext, - krbAnonymousPrincipal(), &krbPrinc); - if (*minor != 0) + code = krb5_copy_principal(krbContext, + krbAnonymousPrincipal(), &krbPrinc); + if (code != 0) { + *minor = code; return GSS_S_FAILURE; + } } else { + char *nameString; + major = bufferToString(minor, nameBuffer, &nameString); if (GSS_ERROR(major)) return major; - *minor = krb5_parse_name_flags(krbContext, nameString, flags, &krbPrinc); - if (*minor != 0) { - GSSEAP_FREE(nameString); + /* + * First, attempt to parse the name on the assumption that it includes + * a qualifying realm. This allows us to avoid accidentally appending + * the default Kerberos realm to an unqualified name. (A bug in MIT + * Kerberos prevents the default realm being set to an empty value.) + */ + code = krb5_parse_name_flags(krbContext, nameString, + KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &krbPrinc); + if (code == KRB5_PARSE_MALFORMED) { + char *defaultRealm = NULL; + int parseFlags = 0; + + /* Possibly append the default EAP realm if required */ + if (importFlags & IMPORT_FLAG_DEFAULT_REALM) + defaultRealm = gssEapGetDefaultRealm(krbContext); + + /* If no default realm, leave the realm empty in the parsed name */ + if (defaultRealm == NULL || defaultRealm[0] == '\0') + parseFlags |= KRB5_PRINCIPAL_PARSE_NO_REALM; + + code = krb5_parse_name_flags(krbContext, nameString, parseFlags, &krbPrinc); + +#ifdef HAVE_HEIMDAL_VERSION + if (code == 0 && KRB_PRINC_REALM(krbPrinc) == NULL) { + KRB_PRINC_REALM(krbPrinc) = GSSEAP_CALLOC(1, sizeof(char)); + if (KRB_PRINC_REALM(krbPrinc) == NULL) + code = ENOMEM; + } +#endif + + if (defaultRealm != NULL) + GSSEAP_FREE(defaultRealm); + } + + GSSEAP_FREE(nameString); + + if (code != 0) { + *minor = code; return GSS_S_FAILURE; } } + assert(krbPrinc != NULL); + major = krbPrincipalToName(minor, &krbPrinc, pName); - if (GSS_ERROR(major)) { + if (GSS_ERROR(major)) krb5_free_principal(krbContext, krbPrinc); - } - GSSEAP_FREE(nameString); return major; } static OM_uint32 +importEapName(OM_uint32 *minor, + const gss_buffer_t nameBuffer, + gss_name_t *pName) +{ + return importEapNameFlags(minor, nameBuffer, 0, pName); +} + +static OM_uint32 +importUserName(OM_uint32 *minor, + const gss_buffer_t nameBuffer, + gss_name_t *pName) +{ + return importEapNameFlags(minor, nameBuffer, IMPORT_FLAG_DEFAULT_REALM, pName); +} + +static OM_uint32 importAnonymousName(OM_uint32 *minor, const gss_buffer_t nameBuffer GSSEAP_UNUSED, gss_name_t *pName) { - OM_uint32 major; - krb5_context krbContext; - krb5_principal krbPrinc; - - GSSEAP_KRB_INIT(&krbContext); - - *minor = krb5_copy_principal(krbContext, krbAnonymousPrincipal(), - &krbPrinc); - if (*minor != 0) - return GSS_S_FAILURE; - - major = krbPrincipalToName(minor, &krbPrinc, pName); - if (GSS_ERROR(major)) { - krb5_free_principal(krbContext, krbPrinc); - } - - return major; + return importEapNameFlags(minor, GSS_C_NO_BUFFER, 0, pName); } #define UPDATE_REMAIN(n) do { \ @@ -358,7 +405,7 @@ gssEapImportNameInternal(OM_uint32 *minor, buf.value = p; UPDATE_REMAIN(len); - major = importUserName(minor, &buf, &name); + major = importEapNameFlags(minor, &buf, 0, &name); if (GSS_ERROR(major)) goto cleanup; @@ -424,7 +471,7 @@ gssEapImportName(OM_uint32 *minor, gss_name_t *pName) { struct gss_eap_name_import_provider nameTypes[] = { - { GSS_EAP_NT_EAP_NAME, importUserName }, + { GSS_EAP_NT_EAP_NAME, importEapName }, { GSS_C_NT_USER_NAME, importUserName }, { GSS_C_NT_HOSTBASED_SERVICE, importServiceName }, { GSS_C_NT_HOSTBASED_SERVICE_X, importServiceName }, @@ -480,9 +527,8 @@ gssEapExportNameInternal(OM_uint32 *minor, unsigned int flags) { OM_uint32 major = GSS_S_FAILURE, tmpMinor; - krb5_context krbContext; - char *krbName = NULL; - size_t krbNameLen, exportedNameLen; + gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER; + size_t exportedNameLen; unsigned char *p; gss_buffer_desc attrs = GSS_C_EMPTY_BUFFER; gss_OID mech; @@ -495,20 +541,15 @@ gssEapExportNameInternal(OM_uint32 *minor, else mech = GSS_EAP_MECHANISM; - GSSEAP_KRB_INIT(&krbContext); - - *minor = krb5_unparse_name(krbContext, name->krbPrincipal, &krbName); - if (*minor != 0) { - major = GSS_S_FAILURE; + major = gssEapDisplayName(minor, name, &nameBuf, NULL); + if (GSS_ERROR(major)) goto cleanup; - } - krbNameLen = strlen(krbName); exportedNameLen = 0; if (flags & EXPORT_NAME_FLAG_OID) { exportedNameLen += 6 + mech->length; } - exportedNameLen += 4 + krbNameLen; + exportedNameLen += 4 + nameBuf.length; if (flags & EXPORT_NAME_FLAG_COMPOSITE) { major = gssEapExportAttrContext(minor, name, &attrs); if (GSS_ERROR(major)) @@ -544,12 +585,12 @@ gssEapExportNameInternal(OM_uint32 *minor, } /* NAME_LEN */ - store_uint32_be(krbNameLen, p); + store_uint32_be(nameBuf.length, p); p += 4; /* NAME */ - memcpy(p, krbName, krbNameLen); - p += krbNameLen; + memcpy(p, nameBuf.value, nameBuf.length); + p += nameBuf.length; if (flags & EXPORT_NAME_FLAG_COMPOSITE) { memcpy(p, attrs.value, attrs.length); @@ -563,9 +604,9 @@ gssEapExportNameInternal(OM_uint32 *minor, cleanup: gss_release_buffer(&tmpMinor, &attrs); + gss_release_buffer(&tmpMinor, &nameBuf); if (GSS_ERROR(major)) gss_release_buffer(&tmpMinor, exportedName); - krb5_free_unparsed_name(krbContext, krbName); return major; } @@ -649,6 +690,7 @@ gssEapDisplayName(OM_uint32 *minor, krb5_context krbContext; char *krbName; gss_OID name_type; + int flags = 0; GSSEAP_KRB_INIT(&krbContext); @@ -660,7 +702,20 @@ gssEapDisplayName(OM_uint32 *minor, return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; } - *minor = krb5_unparse_name(krbContext, name->krbPrincipal, &krbName); + /* + * According to draft-ietf-abfab-gss-eap-01, when the realm is + * absent the trailing '@' is not included. + */ +#ifdef HAVE_HEIMDAL_VERSION + if (KRB_PRINC_REALM(name->krbPrincipal) == NULL || + KRB_PRINC_REALM(name->krbPrincipal)[0] == '\0') +#else + if (KRB_PRINC_REALM(name->krbPrincipal)->length == 0) +#endif + flags |= KRB5_PRINCIPAL_UNPARSE_NO_REALM; + + *minor = krb5_unparse_name_flags(krbContext, name->krbPrincipal, + flags, &krbName); if (*minor != 0) { return GSS_S_FAILURE; } @@ -686,3 +741,27 @@ gssEapDisplayName(OM_uint32 *minor, return GSS_S_COMPLETE; } + +OM_uint32 +gssEapCompareName(OM_uint32 *minor, + gss_name_t name1, + gss_name_t name2, + int *name_equal) +{ + krb5_context krbContext; + + *minor = 0; + + if (name1 == GSS_C_NO_NAME && name2 == GSS_C_NO_NAME) { + *name_equal = 1; + } else if (name1 != GSS_C_NO_NAME && name2 != GSS_C_NO_NAME) { + GSSEAP_KRB_INIT(&krbContext); + + /* krbPrincipal is immutable, so lock not required */ + *name_equal = krb5_principal_compare(krbContext, + name1->krbPrincipal, + name2->krbPrincipal); + } + + return GSS_S_COMPLETE; +}