/*
- * 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.
*/
+/*
+ * Attribute provider mechanism.
+ */
+
#include "gssapiP_eap.h"
+#include <typeinfo>
#include <string>
+#include <sstream>
#include <exception>
+#include <stdexcept>
#include <new>
-static gss_eap_attr_create_factory
-gss_eap_attr_factories[ATTR_TYPE_MAX] = {
- gss_eap_radius_attr_source::createAttrContext,
- gss_eap_saml_assertion_source::createAttrContext,
- gss_eap_saml_attr_source::createAttrContext,
- gss_eap_shib_attr_source::createAttrContext
-};
+/* lazy initialisation */
+static GSSEAP_THREAD_ONCE gssEapAttrProvidersInitOnce = GSSEAP_ONCE_INITIALIZER;
+static OM_uint32 gssEapAttrProvidersInitStatus = GSS_S_UNAVAILABLE;
+
+static void
+gssEapAttrProvidersInitInternal(void)
+{
+ OM_uint32 major, minor;
+
+ assert(gssEapAttrProvidersInitStatus == GSS_S_UNAVAILABLE);
+
+ major = gssEapRadiusAttrProviderInit(&minor);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ major = gssEapSamlAttrProvidersInit(&minor);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ /* Allow Shibboleth initialization failure to be non-fatal */
+ gssEapLocalAttrProviderInit(&minor);
+
+cleanup:
+#ifdef GSSEAP_DEBUG
+ assert(major == GSS_S_COMPLETE);
+#endif
+
+ gssEapAttrProvidersInitStatus = major;
+}
+
+static OM_uint32
+gssEapAttrProvidersInit(OM_uint32 *minor)
+{
+ GSSEAP_ONCE(&gssEapAttrProvidersInitOnce, gssEapAttrProvidersInitInternal);
+
+ if (GSS_ERROR(gssEapAttrProvidersInitStatus))
+ *minor = GSSEAP_NO_ATTR_PROVIDERS;
+
+ return gssEapAttrProvidersInitStatus;
+}
+
+OM_uint32
+gssEapAttrProvidersFinalize(OM_uint32 *minor)
+{
+ OM_uint32 major = GSS_S_COMPLETE;
+
+ if (gssEapAttrProvidersInitStatus == GSS_S_COMPLETE) {
+ major = gssEapLocalAttrProviderFinalize(minor);
+ if (major == GSS_S_COMPLETE)
+ major = gssEapSamlAttrProvidersFinalize(minor);
+ if (major == GSS_S_COMPLETE)
+ major = gssEapRadiusAttrProviderFinalize(minor);
+
+ gssEapAttrProvidersInitStatus = GSS_S_UNAVAILABLE;
+ }
+
+ return major;
+}
+
+static gss_eap_attr_create_provider gssEapAttrFactories[ATTR_TYPE_MAX + 1];
+
+/*
+ * Register a provider for a particular type and prefix
+ */
+void
+gss_eap_attr_ctx::registerProvider(unsigned int type,
+ gss_eap_attr_create_provider factory)
+{
+ assert(type <= ATTR_TYPE_MAX);
+
+ assert(gssEapAttrFactories[type] == NULL);
+
+ gssEapAttrFactories[type] = factory;
+}
+
+/*
+ * Unregister a provider
+ */
+void
+gss_eap_attr_ctx::unregisterProvider(unsigned int type)
+{
+ assert(type <= ATTR_TYPE_MAX);
+
+ gssEapAttrFactories[type] = NULL;
+}
+/*
+ * Create an attribute context, that manages instances of providers
+ */
gss_eap_attr_ctx::gss_eap_attr_ctx(void)
{
- for (unsigned int i = 0; i < ATTR_TYPE_MAX; i++) {
- gss_eap_attr_source *provider;
+ m_flags = 0;
+
+ for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ gss_eap_attr_provider *provider;
- provider = (gss_eap_attr_factories[i])();
- if (provider != NULL)
- m_providers[i] = provider;
+ if (gssEapAttrFactories[i] != NULL) {
+ provider = (gssEapAttrFactories[i])();
+ } else {
+ provider = NULL;
+ }
+
+ m_providers[i] = provider;
}
}
+/*
+ * Convert an attribute prefix to a type
+ */
+unsigned int
+gss_eap_attr_ctx::attributePrefixToType(const gss_buffer_t prefix) const
+{
+ unsigned int i;
+
+ for (i = ATTR_TYPE_MIN; i < ATTR_TYPE_MAX; i++) {
+ const char *pprefix;
+
+ if (!providerEnabled(i))
+ continue;
+
+ pprefix = m_providers[i]->prefix();
+ if (pprefix == NULL)
+ continue;
+
+ if (strlen(pprefix) == prefix->length &&
+ memcmp(pprefix, prefix->value, prefix->length) == 0)
+ return i;
+ }
+
+ return ATTR_TYPE_LOCAL;
+}
+
+/*
+ * Convert a type to an attribute prefix
+ */
+gss_buffer_desc
+gss_eap_attr_ctx::attributeTypeToPrefix(unsigned int type) const
+{
+ gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
+
+ if (type < ATTR_TYPE_MIN || type >= ATTR_TYPE_MAX)
+ return prefix;
+
+ if (!providerEnabled(type))
+ return prefix;
+
+ prefix.value = (void *)m_providers[type]->prefix();
+ if (prefix.value != NULL)
+ prefix.length = strlen((char *)prefix.value);
+
+ return prefix;
+}
+
bool
-gss_eap_attr_ctx::initFromExistingContext(const gss_eap_attr_ctx *manager,
- const gss_eap_attr_source *source)
+gss_eap_attr_ctx::providerEnabled(unsigned int type) const
{
- if (!gss_eap_attr_source::initFromExistingContext(this, source))
+ if (type == ATTR_TYPE_LOCAL &&
+ (m_flags & ATTR_FLAG_DISABLE_LOCAL))
return false;
- for (unsigned int i = 0; i < ATTR_TYPE_MAX; i++) {
- gss_eap_attr_source *provider;
+ if (m_providers[type] == NULL)
+ return false;
+
+ return true;
+}
+
+void
+gss_eap_attr_ctx::releaseProvider(unsigned int type)
+{
+ delete m_providers[type];
+ m_providers[type] = NULL;
+}
+
+/*
+ * Initialize a context from an existing context.
+ */
+bool
+gss_eap_attr_ctx::initFromExistingContext(const gss_eap_attr_ctx *manager)
+{
+ bool ret = true;
+
+ m_flags = manager->m_flags;
+
+ for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ gss_eap_attr_provider *provider;
+
+ if (!providerEnabled(i)) {
+ releaseProvider(i);
+ continue;
+ }
provider = m_providers[i];
- if (provider != NULL) {
- if (!provider->initFromExistingContext(this, source))
- return false;
+
+ ret = provider->initFromExistingContext(this,
+ manager->m_providers[i]);
+ if (ret == false) {
+ releaseProvider(i);
+ break;
}
}
- return true;
+ return ret;
}
+/*
+ * Initialize a context from a GSS credential and context.
+ */
bool
-gss_eap_attr_ctx::initFromGssContext(const gss_eap_attr_ctx *manager,
- const gss_cred_id_t cred,
+gss_eap_attr_ctx::initFromGssContext(const gss_cred_id_t cred,
const gss_ctx_id_t ctx)
{
- if (!gss_eap_attr_source::initFromGssContext(this, cred, ctx))
- return false;
+ bool ret = true;
- for (unsigned int i = 0; i < ATTR_TYPE_MAX; i++) {
- gss_eap_attr_source *provider;
+ if (cred != GSS_C_NO_CREDENTIAL &&
+ (cred->flags & GSS_EAP_DISABLE_LOCAL_ATTRS_FLAG)) {
+ m_flags |= ATTR_FLAG_DISABLE_LOCAL;
+ }
+
+ for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ gss_eap_attr_provider *provider;
+
+ if (!providerEnabled(i)) {
+ releaseProvider(i);
+ continue;
+ }
provider = m_providers[i];
- if (provider != NULL) {
- if (!provider->initFromGssContext(this, cred, ctx))
- return false;
+
+ ret = provider->initFromGssContext(this, cred, ctx);
+ if (ret == false) {
+ releaseProvider(i);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+bool
+gss_eap_attr_ctx::initWithJsonObject(JSONObject &obj)
+{
+ bool ret = false;
+ bool foundSource[ATTR_TYPE_MAX + 1];
+ unsigned int type;
+
+ for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++)
+ foundSource[type] = false;
+
+ if (obj["version"].integer() != 1)
+ return false;
+
+ m_flags = obj["flags"].integer();
+
+ JSONObject sources = obj["sources"];
+
+ /* Initialize providers from serialized state */
+ for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) {
+ gss_eap_attr_provider *provider;
+ const char *key;
+
+ if (!providerEnabled(type)) {
+ releaseProvider(type);
+ continue;
+ }
+
+ provider = m_providers[type];
+ key = provider->name();
+ if (key == NULL)
+ continue;
+
+ JSONObject source = sources.get(key);
+ if (!source.isNull() &&
+ !provider->initWithJsonObject(this, source)) {
+ releaseProvider(type);
+ return false;
+ }
+
+ foundSource[type] = true;
+ }
+
+ /* Initialize remaining providers from initialized providers */
+ for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) {
+ gss_eap_attr_provider *provider;
+
+ if (foundSource[type] || !providerEnabled(type))
+ continue;
+
+ provider = m_providers[type];
+
+ ret = provider->initFromGssContext(this,
+ GSS_C_NO_CREDENTIAL,
+ GSS_C_NO_CONTEXT);
+ if (ret == false) {
+ releaseProvider(type);
+ return false;
}
}
return true;
}
-gss_eap_attr_ctx::~gss_eap_attr_ctx(void)
+JSONObject
+gss_eap_attr_ctx::jsonRepresentation(void) const
{
- for (unsigned int i = 0; i < ATTR_TYPE_MAX; i++)
- delete m_providers[i];
+ JSONObject obj, sources;
+ unsigned int i;
+
+ obj.set("version", 1);
+ obj.set("flags", m_flags);
+
+ for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ gss_eap_attr_provider *provider;
+ const char *key;
+
+ provider = m_providers[i];
+ if (provider == NULL)
+ continue; /* provider not initialised */
+
+ key = provider->name();
+ if (key == NULL)
+ continue; /* provider does not have state */
+
+ JSONObject source = provider->jsonRepresentation();
+ sources.set(key, source);
+ }
+
+ obj.set("sources", sources);
+
+ return obj;
}
+/*
+ * Initialize a context from an exported context or name token
+ */
bool
-gss_eap_attr_ctx::init(void)
+gss_eap_attr_ctx::initFromBuffer(const gss_buffer_t buffer)
{
- return gss_eap_radius_attr_source::init() &&
- gss_eap_saml_assertion_source::init() &&
- gss_eap_saml_attr_source::init() &&
- gss_eap_shib_attr_source::init();
+ OM_uint32 major, minor;
+ bool ret;
+ char *s;
+ json_error_t error;
+
+ major = bufferToString(&minor, buffer, &s);
+ if (GSS_ERROR(major))
+ return false;
+
+ JSONObject obj = JSONObject::load(s, 0, &error);
+ if (!obj.isNull()) {
+ ret = initWithJsonObject(obj);
+ } else
+ ret = false;
+
+ GSSEAP_FREE(s);
+
+ return ret;
}
-void
-gss_eap_attr_ctx::finalize(void)
+gss_eap_attr_ctx::~gss_eap_attr_ctx(void)
{
- gss_eap_shib_attr_source::finalize();
- gss_eap_saml_attr_source::finalize();
- gss_eap_saml_assertion_source::finalize();
- gss_eap_radius_attr_source::finalize();
+ for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++)
+ delete m_providers[i];
}
-gss_eap_attr_source *
+/*
+ * Locate provider for a given type
+ */
+gss_eap_attr_provider *
gss_eap_attr_ctx::getProvider(unsigned int type) const
{
+ assert(type >= ATTR_TYPE_MIN && type <= ATTR_TYPE_MAX);
return m_providers[type];
}
-gss_eap_attr_source *
-gss_eap_attr_ctx::getProvider(const gss_buffer_t prefix) const
+/*
+ * Get primary provider. Only the primary provider is serialised when
+ * gss_export_sec_context() or gss_export_name_composite() is called.
+ */
+gss_eap_attr_provider *
+gss_eap_attr_ctx::getPrimaryProvider(void) const
{
- unsigned int type;
-
- type = attributePrefixToType(prefix);
-
- return m_providers[type];
+ return m_providers[ATTR_TYPE_MIN];
}
-void
+/*
+ * Set an attribute
+ */
+bool
gss_eap_attr_ctx::setAttribute(int complete,
const gss_buffer_t attr,
const gss_buffer_t value)
{
gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
unsigned int type;
- gss_eap_attr_source *provider;
+ gss_eap_attr_provider *provider;
+ bool ret = false;
decomposeAttributeName(attr, &type, &suffix);
provider = m_providers[type];
if (provider != NULL) {
- provider->setAttribute(complete,
- (type == ATTR_TYPE_LOCAL) ? attr : &suffix,
- value);
-
+ ret = provider->setAttribute(complete,
+ (type == ATTR_TYPE_LOCAL) ? attr : &suffix,
+ value);
}
+
+ return ret;
}
-void
+/*
+ * Delete an attrbiute
+ */
+bool
gss_eap_attr_ctx::deleteAttribute(const gss_buffer_t attr)
{
gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
unsigned int type;
- gss_eap_attr_source *provider;
+ gss_eap_attr_provider *provider;
+ bool ret = false;
decomposeAttributeName(attr, &type, &suffix);
provider = m_providers[type];
if (provider != NULL) {
- provider->deleteAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix);
+ ret = provider->deleteAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix);
}
+
+ return ret;
}
+/*
+ * Enumerate attribute types with callback
+ */
bool
gss_eap_attr_ctx::getAttributeTypes(gss_eap_attr_enumeration_cb cb, void *data) const
{
bool ret = false;
size_t i;
- for (i = 0; i < ATTR_TYPE_MAX; i++) {
- gss_eap_attr_source *provider;
+ for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ gss_eap_attr_provider *provider = m_providers[i];
- provider = m_providers[i];
if (provider == NULL)
continue;
};
static bool
-addAttribute(const gss_eap_attr_source *provider,
+addAttribute(const gss_eap_attr_ctx *manager,
+ const gss_eap_attr_provider *provider GSSEAP_UNUSED,
const gss_buffer_t attribute,
void *data)
{
eap_gss_get_attr_types_args *args = (eap_gss_get_attr_types_args *)data;
- gss_buffer_t prefix = GSS_C_NO_BUFFER;
gss_buffer_desc qualified;
OM_uint32 major, minor;
if (args->type != ATTR_TYPE_LOCAL) {
- gss_eap_attr_ctx::composeAttributeName(args->type, attribute, &qualified);
+ manager->composeAttributeName(args->type, attribute, &qualified);
major = gss_add_buffer_set_member(&minor, &qualified, &args->attrs);
gss_release_buffer(&minor, &qualified);
} else {
- major = gss_add_buffer_set_member(&minor, prefix, &args->attrs);
+ major = gss_add_buffer_set_member(&minor, attribute, &args->attrs);
}
- return GSS_ERROR(major) ? false : true;
+ return GSS_ERROR(major) == false;
}
+/*
+ * Enumerate attribute types, output is buffer set
+ */
bool
gss_eap_attr_ctx::getAttributeTypes(gss_buffer_set_t *attrs)
{
unsigned int i;
major = gss_create_empty_buffer_set(&minor, attrs);
- if (GSS_ERROR(major)) {
+ if (GSS_ERROR(major))
throw new std::bad_alloc;
- return false;
- }
args.attrs = *attrs;
- for (i = 0; i < ATTR_TYPE_MAX; i++) {
- gss_eap_attr_source *provider;
+ for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ gss_eap_attr_provider *provider = m_providers[i];
args.type = i;
- provider = m_providers[i];
if (provider == NULL)
continue;
break;
}
- if (ret == false) {
+ if (ret == false)
gss_release_buffer_set(&minor, attrs);
- }
return ret;
}
+/*
+ * Get attribute with given name
+ */
bool
gss_eap_attr_ctx::getAttribute(const gss_buffer_t attr,
int *authenticated,
{
gss_buffer_desc suffix = GSS_C_EMPTY_BUFFER;
unsigned int type;
- gss_eap_attr_source *provider;
+ gss_eap_attr_provider *provider;
bool ret;
decomposeAttributeName(attr, &type, &suffix);
provider = m_providers[type];
- if (provider == NULL) {
- *more = 0;
+ if (provider == NULL)
return false;
- }
ret = provider->getAttribute(type == ATTR_TYPE_LOCAL ? attr : &suffix,
authenticated, complete,
return ret;
}
+/*
+ * Map attribute context to C++ object
+ */
gss_any_t
gss_eap_attr_ctx::mapToAny(int authenticated,
gss_buffer_t type_id) const
{
- return NULL;
+ unsigned int type;
+ gss_eap_attr_provider *provider;
+ gss_buffer_desc suffix;
+
+ decomposeAttributeName(type_id, &type, &suffix);
+
+ provider = m_providers[type];
+ if (provider == NULL)
+ return (gss_any_t)NULL;
+
+ return provider->mapToAny(authenticated, &suffix);
}
+/*
+ * Release mapped context
+ */
void
gss_eap_attr_ctx::releaseAnyNameMapping(gss_buffer_t type_id,
gss_any_t input) const
{
+ unsigned int type;
+ gss_eap_attr_provider *provider;
+ gss_buffer_desc suffix;
+
+ decomposeAttributeName(type_id, &type, &suffix);
+
+ provider = m_providers[type];
+ if (provider != NULL)
+ provider->releaseAnyNameMapping(&suffix, input);
}
+/*
+ * Export attribute context to buffer
+ */
void
gss_eap_attr_ctx::exportToBuffer(gss_buffer_t buffer) const
{
- m_providers[ATTR_TYPE_RADIUS]->exportToBuffer(buffer);
+ OM_uint32 minor;
+ char *s;
+
+ JSONObject obj = jsonRepresentation();
+
+#if 0
+ obj.dump(stdout);
+#endif
+
+ s = obj.dump(JSON_COMPACT);
+
+ if (GSS_ERROR(makeStringBuffer(&minor, s, buffer)))
+ throw new std::bad_alloc;
}
-bool
-gss_eap_attr_ctx::initFromBuffer(const gss_eap_attr_ctx *manager,
- const gss_buffer_t buffer)
+/*
+ * Return soonest expiry time of providers
+ */
+time_t
+gss_eap_attr_ctx::getExpiryTime(void) const
{
unsigned int i;
- bool ret;
+ time_t expiryTime = 0;
- ret = m_providers[ATTR_TYPE_RADIUS]->initFromBuffer(this, buffer);
- if (!ret)
- return false;
+ for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ gss_eap_attr_provider *provider = m_providers[i];
+ time_t providerExpiryTime;
- for (i = ATTR_TYPE_RADIUS + 1; i < ATTR_TYPE_MAX; i++) {
- gss_eap_attr_source *provider = m_providers[i];
+ if (provider == NULL)
+ continue;
- ret = provider->initFromGssContext(
- this, GSS_C_NO_CREDENTIAL, GSS_C_NO_CONTEXT);
- if (!ret)
- break;
+ providerExpiryTime = provider->getExpiryTime();
+ if (providerExpiryTime == 0)
+ continue;
+
+ if (expiryTime == 0 || providerExpiryTime < expiryTime)
+ expiryTime = providerExpiryTime;
}
- return ret;
+ return expiryTime;
}
+OM_uint32
+gss_eap_attr_ctx::mapException(OM_uint32 *minor, std::exception &e) const
+{
+ unsigned int i;
+ OM_uint32 major;
+
+ /* Errors we handle ourselves */
+ if (typeid(e) == typeid(std::bad_alloc)) {
+ *minor = ENOMEM;
+ goto cleanup;
+ } else if (typeid(e) == typeid(std::runtime_error)) {
+ major = GSS_S_BAD_NAME;
+ *minor = GSSEAP_BAD_ATTR_TOKEN;
+ goto cleanup;
+ } else if (this == NULL) {
+ major = GSS_S_FAILURE;
+ goto cleanup;
+ }
-/*
- * C wrappers
- */
+ /* Errors we delegate to providers */
+ major = GSS_S_CONTINUE_NEEDED;
-static OM_uint32
-mapException(OM_uint32 *minor, std::exception &e)
-{
- *minor = 0;
- return GSS_S_FAILURE;
-}
-
-static gss_buffer_desc attributePrefixes[] = {
- {
- /* ATTR_TYPE_RADIUS_AVP */
- sizeof("urn:ietf:params:gss-eap:radius-avp"),
- (void *)"urn:ietf:params:gss-eap:radius-avp",
- },
- {
- /* ATTR_TYPE_SAML_AAA_ASSERTION */
- sizeof("urn:ietf:params:gss-eap:saml-aaa-assertion"),
- (void *)"urn:ietf:params:gss-eap:saml-aaa-assertion"
- },
- {
- /* ATTR_TYPE_SAML_ATTR */
- sizeof("urn:ietf:params:gss-eap:saml-attr"),
- (void *)"urn:ietf:params:gss-eap:saml-attr"
- },
-};
+ for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ gss_eap_attr_provider *provider = m_providers[i];
-unsigned int
-gss_eap_attr_ctx::attributePrefixToType(const gss_buffer_t prefix)
-{
- unsigned int i;
+ if (provider == NULL)
+ continue;
- for (i = ATTR_TYPE_MIN;
- i < sizeof(attributePrefixes) / sizeof(attributePrefixes[0]);
- i++)
- {
- if (bufferEqual(&attributePrefixes[i], prefix))
- return i;
+ major = provider->mapException(minor, e);
+ if (major != GSS_S_CONTINUE_NEEDED)
+ break;
}
- return ATTR_TYPE_LOCAL;
-}
+ if (major == GSS_S_CONTINUE_NEEDED) {
+ *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
+ major = GSS_S_FAILURE;
+ }
-const gss_buffer_t
-gss_eap_attr_ctx::attributeTypeToPrefix(unsigned int type)
-{
- if (type < ATTR_TYPE_MIN || type >= ATTR_TYPE_LOCAL)
- return GSS_C_NO_BUFFER;
+cleanup:
+#if 0
+ /* rethrow for now for debugging */
+ throw e;
+#endif
+
+ assert(GSS_ERROR(major));
- return &attributePrefixes[type];
+ return major;
}
+/*
+ * Decompose attribute name into prefix and suffix
+ */
void
gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
gss_buffer_t prefix,
}
}
+/*
+ * Decompose attribute name into type and suffix
+ */
+void
+gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
+ unsigned int *type,
+ gss_buffer_t suffix) const
+{
+ gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
+
+ decomposeAttributeName(attribute, &prefix, suffix);
+ *type = attributePrefixToType(&prefix);
+}
+
+/*
+ * Compose attribute name from prefix, suffix; returns C++ string
+ */
std::string
gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
const gss_buffer_t suffix)
return str;
}
+/*
+ * Compose attribute name from type, suffix; returns C++ string
+ */
std::string
gss_eap_attr_ctx::composeAttributeName(unsigned int type,
const gss_buffer_t suffix)
{
- const gss_buffer_t prefix = attributeTypeToPrefix(type);
+ gss_buffer_desc prefix = attributeTypeToPrefix(type);
- return composeAttributeName(prefix, suffix);
+ return composeAttributeName(&prefix, suffix);
}
+/*
+ * Compose attribute name from prefix, suffix; returns GSS buffer
+ */
void
gss_eap_attr_ctx::composeAttributeName(const gss_buffer_t prefix,
const gss_buffer_t suffix,
}
}
-void
-gss_eap_attr_ctx::decomposeAttributeName(const gss_buffer_t attribute,
- unsigned int *type,
- gss_buffer_t suffix)
-{
- gss_buffer_desc prefix = GSS_C_EMPTY_BUFFER;
-
- decomposeAttributeName(attribute, &prefix, suffix);
- *type = attributePrefixToType(&prefix);
-}
-
+/*
+ * Compose attribute name from type, suffix; returns GSS buffer
+ */
void
gss_eap_attr_ctx::composeAttributeName(unsigned int type,
const gss_buffer_t suffix,
- gss_buffer_t attribute)
+ gss_buffer_t attribute) const
{
- gss_buffer_t prefix = attributeTypeToPrefix(type);
+ gss_buffer_desc prefix = attributeTypeToPrefix(type);
- return composeAttributeName(prefix, suffix, attribute);
+ return composeAttributeName(&prefix, suffix, attribute);
}
+/*
+ * C wrappers
+ */
OM_uint32
gssEapInquireName(OM_uint32 *minor,
gss_name_t name,
gss_OID *MN_mech,
gss_buffer_set_t *attrs)
{
- if (name->attrCtx == NULL)
+ OM_uint32 major;
+
+ if (name_is_MN != NULL)
+ *name_is_MN = (name->mechanismUsed != GSS_C_NULL_OID);
+
+ if (MN_mech != NULL) {
+ major = gssEapCanonicalizeOid(minor, name->mechanismUsed,
+ OID_FLAG_NULL_VALID, MN_mech);
+ if (GSS_ERROR(major))
+ return major;
+ }
+
+ if (name->attrCtx == NULL) {
+ *minor = GSSEAP_NO_ATTR_CONTEXT;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ if (GSS_ERROR(gssEapAttrProvidersInit(minor))) {
return GSS_S_UNAVAILABLE;
+ }
try {
- if (!name->attrCtx->getAttributeTypes(attrs))
+ if (!name->attrCtx->getAttributeTypes(attrs)) {
+ *minor = GSSEAP_NO_ATTR_CONTEXT;
return GSS_S_UNAVAILABLE;
+ }
} catch (std::exception &e) {
- return mapException(minor, e);
+ return name->attrCtx->mapException(minor, e);
}
return GSS_S_COMPLETE;
gss_buffer_t display_value,
int *more)
{
- *authenticated = 0;
- *complete = 0;
-
- value->length = 0;
- value->value = NULL;
+ if (authenticated != NULL)
+ *authenticated = 0;
+ if (complete != NULL)
+ *complete = 0;
+
+ if (value != NULL) {
+ value->length = 0;
+ value->value = NULL;
+ }
if (display_value != NULL) {
display_value->length = 0;
display_value->value = NULL;
}
- *more = -1;
+ if (name->attrCtx == NULL) {
+ *minor = GSSEAP_NO_ATTR_CONTEXT;
+ return GSS_S_UNAVAILABLE;
+ }
- if (name->attrCtx == NULL)
+ if (GSS_ERROR(gssEapAttrProvidersInit(minor))) {
return GSS_S_UNAVAILABLE;
+ }
try {
if (!name->attrCtx->getAttribute(attr, authenticated, complete,
- value, display_value, more))
+ value, display_value, more)) {
+ *minor = GSSEAP_NO_SUCH_ATTR;
+ gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
+ (int)attr->length, (char *)attr->value);
return GSS_S_UNAVAILABLE;
+ }
} catch (std::exception &e) {
- return mapException(minor, e);
+ return name->attrCtx->mapException(minor, e);
}
return GSS_S_COMPLETE;
gss_name_t name,
gss_buffer_t attr)
{
- if (name->attrCtx == NULL)
+ if (name->attrCtx == NULL) {
+ *minor = GSSEAP_NO_ATTR_CONTEXT;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
return GSS_S_UNAVAILABLE;
try {
- name->attrCtx->deleteAttribute(attr);
- } catch (std::exception &ex) {
- return mapException(minor, ex);
+ if (!name->attrCtx->deleteAttribute(attr)) {
+ *minor = GSSEAP_NO_SUCH_ATTR;
+ gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
+ (int)attr->length, (char *)attr->value);
+ return GSS_S_UNAVAILABLE;
+ }
+ } catch (std::exception &e) {
+ return name->attrCtx->mapException(minor, e);
}
return GSS_S_COMPLETE;
gss_buffer_t attr,
gss_buffer_t value)
{
- if (name->attrCtx == NULL)
+ if (name->attrCtx == NULL) {
+ *minor = GSSEAP_NO_ATTR_CONTEXT;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
return GSS_S_UNAVAILABLE;
try {
- name->attrCtx->setAttribute(complete, attr, value);
- } catch (std::exception &ex) {
- return mapException(minor, ex);
+ if (!name->attrCtx->setAttribute(complete, attr, value)) {
+ *minor = GSSEAP_NO_SUCH_ATTR;
+ gssEapSaveStatusInfo(*minor, "Unknown naming attribute %.*s",
+ (int)attr->length, (char *)attr->value);
+ return GSS_S_UNAVAILABLE;
+ }
+ } catch (std::exception &e) {
+ return name->attrCtx->mapException(minor, e);
}
return GSS_S_COMPLETE;
buffer->value = NULL;
return GSS_S_COMPLETE;
- };
+ }
+
+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
+ return GSS_S_UNAVAILABLE;
try {
name->attrCtx->exportToBuffer(buffer);
} catch (std::exception &e) {
- return mapException(minor, e);
+ return name->attrCtx->mapException(minor, e);
}
return GSS_S_COMPLETE;
gss_buffer_t buffer,
gss_name_t name)
{
- if (buffer->length != 0) {
- gss_eap_attr_ctx *ctx = new gss_eap_attr_ctx;
+ gss_eap_attr_ctx *ctx = NULL;
+ assert(name->attrCtx == NULL);
+
+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
+ return GSS_S_UNAVAILABLE;
+
+ if (buffer->length != 0) {
try {
- if (!ctx->initFromBuffer(NULL, buffer)) {
+ ctx = new gss_eap_attr_ctx();
+
+ if (!ctx->initFromBuffer(buffer)) {
delete ctx;
- return GSS_S_DEFECTIVE_TOKEN;
+ *minor = GSSEAP_BAD_ATTR_TOKEN;
+ return GSS_S_BAD_NAME;
}
name->attrCtx = ctx;
} catch (std::exception &e) {
delete ctx;
- return mapException(minor, e);
+ return name->attrCtx->mapException(minor, e);
}
}
assert(out->attrCtx == NULL);
+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
+ return GSS_S_UNAVAILABLE;
+
try {
if (in->attrCtx != NULL) {
- if (!ctx->initFromExistingContext(NULL, in->attrCtx)) {
+ ctx = new gss_eap_attr_ctx();
+ if (!ctx->initFromExistingContext(in->attrCtx)) {
delete ctx;
+ *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
return GSS_S_FAILURE;
}
out->attrCtx = ctx;
}
} catch (std::exception &e) {
delete ctx;
- return mapException(minor, e);
+ return in->attrCtx->mapException(minor, e);
}
return GSS_S_COMPLETE;
gss_buffer_t type_id,
gss_any_t *output)
{
+ if (name->attrCtx == NULL) {
+ *minor = GSSEAP_NO_ATTR_CONTEXT;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
+ return GSS_S_UNAVAILABLE;
+
try {
*output = name->attrCtx->mapToAny(authenticated, type_id);
} catch (std::exception &e) {
- return mapException(minor, e);
+ return name->attrCtx->mapException(minor, e);
}
return GSS_S_COMPLETE;
gss_buffer_t type_id,
gss_any_t *input)
{
- if (name->attrCtx == NULL)
+ if (name->attrCtx == NULL) {
+ *minor = GSSEAP_NO_ATTR_CONTEXT;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ if (GSS_ERROR(gssEapAttrProvidersInit(minor)))
return GSS_S_UNAVAILABLE;
try {
name->attrCtx->releaseAnyNameMapping(type_id, *input);
*input = NULL;
} catch (std::exception &e) {
- return mapException(minor, e);
+ return name->attrCtx->mapException(minor, e);
}
return GSS_S_COMPLETE;
if (name->attrCtx != NULL)
delete name->attrCtx;
+ *minor = 0;
return GSS_S_COMPLETE;
}
+/*
+ * Public accessor for initialisng a context from a GSS context. Also
+ * sets expiry time on GSS context as a side-effect.
+ */
OM_uint32
-gssEapAttrProvidersInit(OM_uint32 *minor)
+gssEapCreateAttrContext(OM_uint32 *minor,
+ gss_cred_id_t gssCred,
+ gss_ctx_id_t gssCtx,
+ struct gss_eap_attr_ctx **pAttrContext,
+ time_t *pExpiryTime)
{
- try {
- gss_eap_attr_ctx::init();
- } catch (std::exception &e) {
- return mapException(minor, e);
- }
+ gss_eap_attr_ctx *ctx = NULL;
+ OM_uint32 major;
- return GSS_S_COMPLETE;
-}
+ assert(gssCtx != GSS_C_NO_CONTEXT);
+
+ major = gssEapAttrProvidersInit(minor);
+ if (GSS_ERROR(major))
+ return major;
+
+ *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
+ major = GSS_S_FAILURE;
-OM_uint32
-gssEapAttrProvidersFinalize(OM_uint32 *minor)
-{
try {
- gss_eap_attr_ctx::finalize();
+ *pAttrContext = ctx = new gss_eap_attr_ctx();
+ if (ctx->initFromGssContext(gssCred, gssCtx)) {
+ *minor = 0;
+ major = GSS_S_COMPLETE;
+ }
} catch (std::exception &e) {
- return mapException(minor, e);
+ if (ctx != NULL)
+ major = ctx->mapException(minor, e);
}
- return GSS_S_COMPLETE;
-}
-
-struct gss_eap_attr_ctx *
-gssEapCreateAttrContext(gss_cred_id_t gssCred,
- gss_ctx_id_t gssCtx)
-{
- gss_eap_attr_ctx *ctx;
-
- ctx = new gss_eap_attr_ctx;
- if (!ctx->initFromGssContext(NULL, gssCred, gssCtx)) {
+ if (major == GSS_S_COMPLETE) {
+ *pExpiryTime = ctx->getExpiryTime();
+ } else {
delete ctx;
- return NULL;
+ *pAttrContext = NULL;
}
- return ctx;
+ return major;
}