X-Git-Url: http://www.project-moonshot.org/gitweb/?p=mech_eap.git;a=blobdiff_plain;f=util_name.c;h=d365f9852927611a4352ff1efc7287544855c1ef;hp=be7f4cb05d8bf7ad8ddcb5ff24f96b4c21a18774;hb=ae79fdae047f980d01b2b4e84ccea52e24d8c7a0;hpb=899e578a598e3be50fdf3e7cc1ef033e60d4067a diff --git a/util_name.c b/util_name.c index be7f4cb..d365f98 100644 --- a/util_name.c +++ b/util_name.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 @@ -53,11 +53,15 @@ * or implied warranty. */ +/* + * Name utility routines. + */ + #include "gssapiP_eap.h" static gss_OID_desc gssEapNtPrincipalName = { - /* 1.3.6.1.4.1.5322.21.2.1 */ - 10, "\x2B\x06\x01\x04\x01\xA9\x4A\x15\x02\x01" + /* 1.3.6.1.4.1.5322.22.2.1 */ + 10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x02\x01" }; gss_OID GSS_EAP_NT_PRINCIPAL_NAME = &gssEapNtPrincipalName; @@ -94,6 +98,8 @@ gssEapReleaseName(OM_uint32 *minor, gss_name_t *pName) krb5_context krbContext = NULL; OM_uint32 tmpMinor; + *minor = 0; + if (pName == NULL) { return GSS_S_COMPLETE; } @@ -106,14 +112,12 @@ gssEapReleaseName(OM_uint32 *minor, gss_name_t *pName) GSSEAP_KRB_INIT(&krbContext); krb5_free_principal(krbContext, name->krbPrincipal); - samlReleaseAttrContext(&tmpMinor, name); - radiusReleaseAttrContext(&tmpMinor, name); + gssEapReleaseAttrContext(&tmpMinor, name); GSSEAP_MUTEX_DESTROY(&name->mutex); GSSEAP_FREE(name); *pName = NULL; - *minor = 0; return GSS_S_COMPLETE; } @@ -132,10 +136,10 @@ krbPrincipalToName(OM_uint32 *minor, name->krbPrincipal = *principal; *principal = NULL; - if (name->krbPrincipal->length == 1) { - name->flags |= NAME_FLAG_NAI; - } else { + if (KRB_PRINC_LENGTH(name->krbPrincipal) > 1) { name->flags |= NAME_FLAG_SERVICE; + } else { + name->flags |= NAME_FLAG_NAI; } *pName = name; @@ -149,7 +153,7 @@ importServiceName(OM_uint32 *minor, const gss_buffer_t nameBuffer, gss_name_t *pName) { - OM_uint32 major, tmpMinor; + OM_uint32 major; krb5_context krbContext; krb5_principal krbPrinc; char *service, *host; @@ -164,13 +168,13 @@ importServiceName(OM_uint32 *minor, if (host != NULL) { *host = '\0'; host++; - } + } /* XXX this is probably NOT what we want to be doing */ - *minor = krb5_sname_to_principal(krbContext, host, service, - KRB5_NT_SRV_HST, &krbPrinc); - if (*minor != 0) { + if (krb5_sname_to_principal(krbContext, host, service, + KRB5_NT_SRV_HST, &krbPrinc) != 0) { GSSEAP_FREE(service); + *minor = GSSEAP_BAD_SERVICE_NAME; return GSS_S_FAILURE; } @@ -188,21 +192,28 @@ importUserName(OM_uint32 *minor, const gss_buffer_t nameBuffer, gss_name_t *pName) { - OM_uint32 major, tmpMinor; + OM_uint32 major; krb5_context krbContext; krb5_principal krbPrinc; char *nameString; GSSEAP_KRB_INIT(&krbContext); - major = bufferToString(minor, nameBuffer, &nameString); - if (GSS_ERROR(major)) - return major; - - *minor = krb5_parse_name(krbContext, nameString, &krbPrinc); - if (*minor != 0) { - GSSEAP_FREE(nameString); - return GSS_S_FAILURE; + if (nameBuffer == GSS_C_NO_BUFFER) { + *minor = krb5_copy_principal(krbContext, + krbAnonymousPrincipal(), &krbPrinc); + if (*minor != 0) + return GSS_S_FAILURE; + } else { + major = bufferToString(minor, nameBuffer, &nameString); + if (GSS_ERROR(major)) + return major; + + *minor = krb5_parse_name(krbContext, nameString, &krbPrinc); + if (*minor != 0) { + GSSEAP_FREE(nameString); + return GSS_S_FAILURE; + } } major = krbPrincipalToName(minor, &krbPrinc, pName); @@ -215,65 +226,95 @@ importUserName(OM_uint32 *minor, } static OM_uint32 -importExportedName(OM_uint32 *minor, - const gss_buffer_t nameBuffer, - gss_name_t *pName) +importAnonymousName(OM_uint32 *minor, + const gss_buffer_t nameBuffer GSSEAP_UNUSED, + gss_name_t *pName) { - OM_uint32 major, tmpMinor; + OM_uint32 major; krb5_context krbContext; - unsigned char *p; - size_t len, remain; - gss_buffer_desc buf; - enum gss_eap_token_type tok_type; - gss_name_t name = GSS_C_NO_NAME; + krb5_principal krbPrinc; GSSEAP_KRB_INIT(&krbContext); - p = (unsigned char *)nameBuffer->value; - remain = nameBuffer->length; + *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); + } - if (remain < 6 + GSS_EAP_MECHANISM->length + 4) - return GSS_S_BAD_NAME; + return major; +} #define UPDATE_REMAIN(n) do { \ p += (n); \ remain -= (n); \ } while (0) - /* TOK_ID */ - tok_type = load_uint16_be(p); - if (tok_type != TOK_TYPE_EXPORT_NAME && - tok_type != TOK_TYPE_EXPORT_NAME_COMPOSITE) - return GSS_S_BAD_NAME; - UPDATE_REMAIN(2); - - /* MECH_OID_LEN */ - len = load_uint16_be(p); - if (len != 2 + GSS_EAP_MECHANISM->length) - return GSS_S_BAD_NAME; - UPDATE_REMAIN(2); - - /* MECH_OID */ - if (p[0] != 0x06) - return GSS_S_BAD_NAME; - if (p[1] != GSS_EAP_MECHANISM->length) - return GSS_S_BAD_MECH; - if (memcmp(&p[2], GSS_EAP_MECHANISM->elements, GSS_EAP_MECHANISM->length)) - return GSS_S_BAD_MECH; - UPDATE_REMAIN(2 + GSS_EAP_MECHANISM->length); - - /* NAME_LEN */ - len = load_uint32_be(p); - UPDATE_REMAIN(4); - #define CHECK_REMAIN(n) do { \ if (remain < (n)) { \ - *minor = ERANGE; \ major = GSS_S_BAD_NAME; \ + *minor = GSSEAP_TOK_TRUNC; \ goto cleanup; \ } \ } while (0) +OM_uint32 +gssEapImportNameInternal(OM_uint32 *minor, + const gss_buffer_t nameBuffer, + gss_name_t *pName, + unsigned int flags) +{ + OM_uint32 major, tmpMinor; + krb5_context krbContext; + unsigned char *p; + size_t len, remain; + gss_buffer_desc buf; + enum gss_eap_token_type tokType; + gss_name_t name = GSS_C_NO_NAME; + + GSSEAP_KRB_INIT(&krbContext); + + p = (unsigned char *)nameBuffer->value; + remain = nameBuffer->length; + + if (flags & EXPORT_NAME_FLAG_OID) { + if (remain < 6 + GSS_EAP_MECHANISM->length + 4) + return GSS_S_BAD_NAME; + + if (flags & EXPORT_NAME_FLAG_COMPOSITE) + tokType = TOK_TYPE_EXPORT_NAME_COMPOSITE; + else + tokType = TOK_TYPE_EXPORT_NAME; + + /* TOK_ID */ + if (load_uint16_be(p) != tokType) + return GSS_S_BAD_NAME; + UPDATE_REMAIN(2); + + /* MECH_OID_LEN */ + len = load_uint16_be(p); + if (len != 2 + GSS_EAP_MECHANISM->length) + return GSS_S_BAD_NAME; + UPDATE_REMAIN(2); + + /* MECH_OID */ + if (p[0] != 0x06) + return GSS_S_BAD_NAME; + if (p[1] != GSS_EAP_MECHANISM->length) + return GSS_S_BAD_MECH; + if (memcmp(&p[2], GSS_EAP_MECHANISM->elements, GSS_EAP_MECHANISM->length)) + return GSS_S_BAD_MECH; + UPDATE_REMAIN(2 + GSS_EAP_MECHANISM->length); + } + + /* NAME_LEN */ + len = load_uint32_be(p); + UPDATE_REMAIN(4); + /* NAME */ CHECK_REMAIN(len); buf.length = len; @@ -284,43 +325,19 @@ importExportedName(OM_uint32 *minor, if (GSS_ERROR(major)) goto cleanup; - if (tok_type == TOK_TYPE_EXPORT_NAME_COMPOSITE) { + if (flags & EXPORT_NAME_FLAG_COMPOSITE) { gss_buffer_desc buf; - CHECK_REMAIN(4); - name->flags = load_uint32_be(p); - UPDATE_REMAIN(4); - - if (name->flags & NAME_FLAG_RADIUS_ATTRIBUTES) { - CHECK_REMAIN(4); - buf.length = load_uint32_be(p); - UPDATE_REMAIN(4); + buf.length = remain; + buf.value = p; - CHECK_REMAIN(buf.length); - buf.value = p; - UPDATE_REMAIN(buf.length); - - major = radiusImportAttrContext(minor, &buf, name); - if (GSS_ERROR(major)) - goto cleanup; - } - - if (name->flags & NAME_FLAG_SAML_ATTRIBUTES) { - CHECK_REMAIN(4); - buf.length = load_uint32_be(p); - UPDATE_REMAIN(4); - - CHECK_REMAIN(buf.length); - buf.value = p; - UPDATE_REMAIN(buf.length); - - major = samlImportAttrContext(minor, &buf, name); - if (GSS_ERROR(major)) - goto cleanup; - } + major = gssEapImportAttrContext(minor, &buf, name); + if (GSS_ERROR(major)) + goto cleanup; } major = GSS_S_COMPLETE; + *minor = 0; cleanup: if (GSS_ERROR(major)) @@ -331,58 +348,90 @@ cleanup: return major; } +static OM_uint32 +importExportName(OM_uint32 *minor, + const gss_buffer_t nameBuffer, + gss_name_t *name) +{ + return gssEapImportNameInternal(minor, nameBuffer, name, + EXPORT_NAME_FLAG_OID); +} + +#ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT +static OM_uint32 +importCompositeExportName(OM_uint32 *minor, + const gss_buffer_t nameBuffer, + gss_name_t *name) +{ + return gssEapImportNameInternal(minor, nameBuffer, name, + EXPORT_NAME_FLAG_OID | + EXPORT_NAME_FLAG_COMPOSITE); +} +#endif + +struct gss_eap_name_import_provider { + gss_OID oid; + OM_uint32 (*import)(OM_uint32 *, const gss_buffer_t, gss_name_t *); +}; + OM_uint32 gssEapImportName(OM_uint32 *minor, const gss_buffer_t nameBuffer, gss_OID nameType, gss_name_t *name) { - OM_uint32 major, tmpMinor; + struct gss_eap_name_import_provider nameTypes[] = { + { GSS_C_NT_USER_NAME, importUserName }, + { GSS_EAP_NT_PRINCIPAL_NAME, importUserName }, + { GSS_C_NT_HOSTBASED_SERVICE, importServiceName }, + { GSS_C_NT_HOSTBASED_SERVICE_X, importServiceName }, + { GSS_C_NT_ANONYMOUS, importAnonymousName }, + { GSS_C_NT_EXPORT_NAME, importExportName }, +#ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT + { GSS_C_NT_COMPOSITE_EXPORT, importCompositeExportName }, +#endif + }; + size_t i; *name = GSS_C_NO_NAME; - if (nameType == GSS_C_NULL_OID || - oidEqual(nameType, GSS_C_NT_USER_NAME) || - oidEqual(nameType, GSS_EAP_NT_PRINCIPAL_NAME)) - major = importUserName(minor, nameBuffer, name); - else if (oidEqual(nameType, GSS_C_NT_HOSTBASED_SERVICE) || - oidEqual(nameType, GSS_C_NT_HOSTBASED_SERVICE_X)) - major = importServiceName(minor, nameBuffer, name); - else if (oidEqual(nameType, GSS_C_NT_EXPORT_NAME)) - major = importExportedName(minor, nameBuffer, name); - else - major = GSS_S_BAD_NAMETYPE; + if (nameType == GSS_C_NO_OID) + nameType = nameTypes[0].oid; - if (GSS_ERROR(major)) - gssEapReleaseName(&tmpMinor, name); + for (i = 0; i < sizeof(nameTypes) / sizeof(nameTypes[0]); i++) { + if (oidEqual(nameTypes[i].oid, nameType)) + return nameTypes[i].import(minor, nameBuffer, name); + } - return major; + return GSS_S_BAD_NAMETYPE; } OM_uint32 gssEapExportName(OM_uint32 *minor, const gss_name_t name, - gss_buffer_t exportedName, - int composite) + gss_buffer_t exportedName) +{ + return gssEapExportNameInternal(minor, name, exportedName, + EXPORT_NAME_FLAG_OID); +} + +OM_uint32 +gssEapExportNameInternal(OM_uint32 *minor, + const gss_name_t name, + gss_buffer_t exportedName, + unsigned int flags) { OM_uint32 major = GSS_S_FAILURE, tmpMinor; krb5_context krbContext; char *krbName = NULL; - size_t krbNameLen; + size_t krbNameLen, exportedNameLen; unsigned char *p; - gss_buffer_desc radius, saml; - - radius.length = 0; - radius.value = NULL; - - saml.length = 0; - saml.value = NULL; + gss_buffer_desc attrs = GSS_C_EMPTY_BUFFER; exportedName->length = 0; exportedName->value = NULL; GSSEAP_KRB_INIT(&krbContext); - GSSEAP_MUTEX_LOCK(&name->mutex); *minor = krb5_unparse_name(krbContext, name->krbPrincipal, &krbName); if (*minor != 0) { @@ -391,46 +440,44 @@ gssEapExportName(OM_uint32 *minor, } krbNameLen = strlen(krbName); - exportedName->length = 6 + GSS_EAP_MECHANISM->length + 4 + krbNameLen; - if (composite) { - exportedName->length += 4; - - if (name->flags & NAME_FLAG_RADIUS_ATTRIBUTES) { - major = radiusExportAttrContext(minor, name, &radius); - if (GSS_ERROR(major)) - goto cleanup; - exportedName->length += 4 + radius.length; - } - if (name->flags & NAME_FLAG_SAML_ATTRIBUTES) { - major = samlExportAttrContext(minor, name, &saml); - if (GSS_ERROR(major)) - goto cleanup; - exportedName->length += 4 + saml.length; - } + exportedNameLen = 0; + if (flags & EXPORT_NAME_FLAG_OID) { + exportedNameLen += 6 + GSS_EAP_MECHANISM->length; + } + exportedNameLen += 4 + krbNameLen; + if (flags & EXPORT_NAME_FLAG_COMPOSITE) { + major = gssEapExportAttrContext(minor, name, &attrs); + if (GSS_ERROR(major)) + goto cleanup; + exportedNameLen += attrs.length; } - exportedName->value = GSSEAP_MALLOC(exportedName->length); + exportedName->value = GSSEAP_MALLOC(exportedNameLen); if (exportedName->value == NULL) { major = GSS_S_FAILURE; *minor = ENOMEM; goto cleanup; } + exportedName->length = exportedNameLen; - /* TOK | MECH_OID_LEN */ p = (unsigned char *)exportedName->value; - store_uint16_be(composite + + if (flags & EXPORT_NAME_FLAG_OID) { + /* TOK | MECH_OID_LEN */ + store_uint16_be((flags & EXPORT_NAME_FLAG_COMPOSITE) ? TOK_TYPE_EXPORT_NAME_COMPOSITE : TOK_TYPE_EXPORT_NAME, - p); - p += 2; - store_uint16_be(GSS_EAP_MECHANISM->length + 2, p); - p += 2; - - /* MECH_OID */ - *p++ = 0x06; - *p++ = GSS_EAP_MECHANISM->length & 0xff; - memcpy(p, GSS_EAP_MECHANISM->elements, GSS_EAP_MECHANISM->length); - p += GSS_EAP_MECHANISM->length; + p); + p += 2; + store_uint16_be(GSS_EAP_MECHANISM->length + 2, p); + p += 2; + + /* MECH_OID */ + *p++ = 0x06; + *p++ = GSS_EAP_MECHANISM->length & 0xff; + memcpy(p, GSS_EAP_MECHANISM->elements, GSS_EAP_MECHANISM->length); + p += GSS_EAP_MECHANISM->length; + } /* NAME_LEN */ store_uint32_be(krbNameLen, p); @@ -440,29 +487,18 @@ gssEapExportName(OM_uint32 *minor, memcpy(p, krbName, krbNameLen); p += krbNameLen; - if (composite) { - store_uint32_be(name->flags, p); - p += 4; - - if (name->flags & NAME_FLAG_RADIUS_ATTRIBUTES) { - store_uint32_be(radius.length, p); - memcpy(&p[4], radius.value, radius.length); - p += 4 + radius.length; - } - if (name->flags & NAME_FLAG_SAML_ATTRIBUTES) { - store_uint32_be(saml.length, p); - memcpy(&p[4], saml.value, saml.length); - p += 4 + saml.length; - } + if (flags & EXPORT_NAME_FLAG_COMPOSITE) { + memcpy(p, attrs.value, attrs.length); + p += attrs.length; } - *minor = 0; + assert(p == (unsigned char *)exportedName->value + exportedNameLen); + major = GSS_S_COMPLETE; + *minor = 0; cleanup: - GSSEAP_MUTEX_UNLOCK(&name->mutex); - gss_release_buffer(&tmpMinor, &saml); - gss_release_buffer(&tmpMinor, &radius); + gss_release_buffer(&tmpMinor, &attrs); if (GSS_ERROR(major)) gss_release_buffer(&tmpMinor, exportedName); krb5_free_unparsed_name(krbContext, krbName); @@ -470,121 +506,96 @@ cleanup: return major; } -static gss_buffer_desc attributePrefixes[] = { - { - /* ATTR_TYPE_NONE */ - 0, - NULL, - }, - { - /* ATTR_TYPE_SAML_AAA_ASSERTION */ - sizeof("urn:ietf:params:gss-eap:saml-aaa-assertion"), - "urn:ietf:params:gss-eap:saml-aaa-assertion" - }, - { - /* ATTR_TYPE_SAML_ATTR */ - sizeof("urn:ietf:params:gss-eap:saml-attr"), - "urn:ietf:params:gss-eap:saml-attr" - }, - { - /* ATTR_TYPE_RADIUS_AVP */ - sizeof("urn:ietf:params:gss-eap:radius-avp"), - "urn:ietf:params:gss-eap:radius-avp", - } -}; - -enum gss_eap_attribute_type -gssEapAttributePrefixToType(const gss_buffer_t prefix) +OM_uint32 +gssEapDuplicateName(OM_uint32 *minor, + const gss_name_t input_name, + gss_name_t *dest_name) { - enum gss_eap_attribute_type i; - - for (i = ATTR_TYPE_SAML_AAA_ASSERTION; - i < sizeof(attributePrefixes) / sizeof(attributePrefixes[0]); - i++) - { - if (bufferEqual(&attributePrefixes[i], prefix)) - return i; + OM_uint32 major, tmpMinor; + krb5_context krbContext; + gss_name_t name; + + if (input_name == GSS_C_NO_NAME) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; } - return ATTR_TYPE_NONE; -} + GSSEAP_KRB_INIT(&krbContext); -gss_buffer_t -gssEapAttributeTypeToPrefix(enum gss_eap_attribute_type type) -{ - if (type <= ATTR_TYPE_NONE || - type > ATTR_TYPE_RADIUS_AVP) - return GSS_C_NO_BUFFER; + major = gssEapAllocName(minor, &name); + if (GSS_ERROR(major)) { + return major; + } - return &attributePrefixes[type]; -} + name->flags = input_name->flags; -OM_uint32 -decomposeAttributeName(OM_uint32 *minor, - const gss_buffer_t attribute, - gss_buffer_t prefix, - gss_buffer_t suffix) -{ - char *p = NULL; - int i; + *minor = krb5_copy_principal(krbContext, input_name->krbPrincipal, + &name->krbPrincipal); + if (*minor != 0) { + major = GSS_S_FAILURE; + goto cleanup; + } - for (i = 0; i < attribute->length; i++) { - if (((char *)attribute->value)[i] == ' ') { - p = (char *)attribute->value + i + 1; - break; - } + if (input_name->attrCtx != NULL) { + major = gssEapDuplicateAttrContext(minor, input_name, name); + if (GSS_ERROR(major)) + goto cleanup; } - prefix->value = attribute->value; - prefix->length = i; + *dest_name = name; - if (p != NULL && *p != '\0') { - suffix->length = attribute->length - 1 - prefix->length; - suffix->value = p; - } else { - suffix->length = 0; - suffix->value = NULL; +cleanup: + if (GSS_ERROR(major)) { + gssEapReleaseName(&tmpMinor, &name); } - *minor = 0; - return GSS_S_COMPLETE; + return major; } OM_uint32 -composeAttributeName(OM_uint32 *minor, - const gss_buffer_t prefix, - const gss_buffer_t suffix, - gss_buffer_t attribute) +gssEapDisplayName(OM_uint32 *minor, + gss_name_t name, + gss_buffer_t output_name_buffer, + gss_OID *output_name_type) { - size_t len = 0; - char *p; + OM_uint32 major; + krb5_context krbContext; + char *krbName; + gss_OID name_type; - attribute->length = 0; - attribute->value = NULL; + GSSEAP_KRB_INIT(&krbContext); - if (prefix == GSS_C_NO_BUFFER || prefix->length == 0) - return GSS_S_COMPLETE; + output_name_buffer->length = 0; + output_name_buffer->value = NULL; - len = prefix->length; - if (suffix != NULL) { - len += 1 + suffix->length; + if (name == GSS_C_NO_NAME) { + *minor = EINVAL; + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME; } - p = attribute->value = GSSEAP_MALLOC(len + 1); - if (attribute->value == NULL) { - *minor = ENOMEM; + *minor = krb5_unparse_name(krbContext, name->krbPrincipal, &krbName); + if (*minor != 0) { return GSS_S_FAILURE; } - attribute->length = len; - memcpy(p, prefix->value, prefix->length); - if (suffix != NULL) { - p[prefix->length] = ' '; - memcpy(p + prefix->length + 1, suffix->value, suffix->length); + major = makeStringBuffer(minor, krbName, output_name_buffer); + if (GSS_ERROR(major)) { + krb5_free_unparsed_name(krbContext, krbName); + return major; } - p[attribute->length] = '\0'; + krb5_free_unparsed_name(krbContext, krbName); + + if (KRB_PRINC_TYPE(name->krbPrincipal) == KRB5_NT_WELLKNOWN && + krb5_principal_compare(krbContext, + name->krbPrincipal, krbAnonymousPrincipal())) { + name_type = GSS_C_NT_ANONYMOUS; + } else { + name_type = GSS_EAP_NT_PRINCIPAL_NAME; + } + + if (output_name_type != NULL) + *output_name_type = name_type; - *minor = 0; return GSS_S_COMPLETE; }