return ret;
}
+#define UPDATE_REMAIN(n) do { \
+ p += (n); \
+ remain -= (n); \
+ } while (0)
+
+#define CHECK_REMAIN(n) do { \
+ if (remain < (n)) { \
+ return false; \
+ } \
+ } while (0)
+
/*
* Initialize a context from an exported context or name token
*/
bool
gss_eap_attr_ctx::initFromBuffer(const gss_buffer_t buffer)
{
- bool ret;
- gss_eap_attr_provider *primaryProvider = getPrimaryProvider();
- gss_buffer_desc primaryBuf;
+ bool ret = false;
+ size_t remain = buffer->length;
+ unsigned char *p = (unsigned char *)buffer->value;
+ bool didInit[ATTR_TYPE_MAX + 1];
+ unsigned int type;
- if (buffer->length < 4)
- return false;
+ for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++)
+ didInit[type] = false;
- m_flags = load_uint32_be(buffer->value);
+ /* flags */
+ CHECK_REMAIN(4);
+ m_flags = load_uint32_be(p);
+ UPDATE_REMAIN(4);
- primaryBuf.length = buffer->length - 4;
- primaryBuf.value = (char *)buffer->value + 4;
+ while (remain) {
+ OM_uint32 type;
+ gss_buffer_desc providerToken;
+ gss_eap_attr_provider *provider;
- ret = primaryProvider->initFromBuffer(this, &primaryBuf);
- if (ret == false)
- return ret;
+ /* TLV encoding of provider type, length, value */
+ CHECK_REMAIN(4);
+ type = load_uint32_be(p);
+ UPDATE_REMAIN(4);
- for (unsigned int i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
- gss_eap_attr_provider *provider;
+ CHECK_REMAIN(4);
+ providerToken.length = load_uint32_be(p);
+ UPDATE_REMAIN(4);
- if (!providerEnabled(i)) {
- releaseProvider(i);
+ CHECK_REMAIN(providerToken.length);
+ providerToken.value = p;
+ UPDATE_REMAIN(providerToken.length);
+
+ if (type < ATTR_TYPE_MIN || type > ATTR_TYPE_MAX ||
+ didInit[type])
+ return false;
+
+ if (!providerEnabled(type)) {
+ releaseProvider(type);
continue;
}
- provider = m_providers[i];
- if (provider == primaryProvider)
+ provider = m_providers[type];
+
+ ret = provider->initFromBuffer(this, &providerToken);
+ if (ret == false) {
+ releaseProvider(type);
+ break;
+ }
+ didInit[type] = true;
+ }
+
+ /*
+ * The call the initFromGssContext methods for attribute
+ * providers that can initialize themselves from other
+ * providers.
+ */
+ for (type = ATTR_TYPE_MIN; type <= ATTR_TYPE_MAX; type++) {
+ gss_eap_attr_provider *provider;
+
+ if (didInit[type])
continue;
+ provider = m_providers[type];
+
ret = provider->initFromGssContext(this,
GSS_C_NO_CREDENTIAL,
GSS_C_NO_CONTEXT);
if (ret == false) {
- releaseProvider(i);
+ releaseProvider(type);
break;
}
}
};
static bool
-addAttribute(const gss_eap_attr_provider *provider,
+addAttribute(const gss_eap_attr_provider *provider GSSEAP_UNUSED,
const gss_buffer_t attribute,
void *data)
{
void
gss_eap_attr_ctx::exportToBuffer(gss_buffer_t buffer) const
{
- const gss_eap_attr_provider *primaryProvider = getPrimaryProvider();
- gss_buffer_desc tmp;
- unsigned char *p;
OM_uint32 tmpMinor;
+ gss_buffer_desc providerTokens[ATTR_TYPE_MAX + 1];
+ size_t length = 4; /* m_flags */
+ unsigned char *p;
+ unsigned int i;
+
+ for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ providerTokens[i].length = 0;
+ providerTokens[i].value = NULL;
+ }
+
+ for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ gss_eap_attr_provider *provider = m_providers[i];
- primaryProvider->exportToBuffer(&tmp);
+ if (provider == NULL)
+ continue;
- buffer->length = 4 + tmp.length;
- buffer->value = GSSEAP_MALLOC(buffer->length);
+ provider->exportToBuffer(&providerTokens[i]);
+
+ if (providerTokens[i].value != NULL)
+ length += 8 + providerTokens[i].length;
+ }
+
+ buffer->length = length;
+ buffer->value = GSSEAP_MALLOC(length);
if (buffer->value == NULL)
throw new std::bad_alloc;
p = (unsigned char *)buffer->value;
store_uint32_be(m_flags, p);
- memcpy(p + 4, tmp.value, tmp.length);
+ p += 4;
+
+ for (i = ATTR_TYPE_MIN; i <= ATTR_TYPE_MAX; i++) {
+ if (providerTokens[i].value == NULL)
+ continue;
- gss_release_buffer(&tmpMinor, &tmp);
+ store_uint32_be(i, p);
+ p += 4;
+ store_uint32_be(providerTokens[i].length, p);
+ p += 4;
+ memcpy(p, providerTokens[i].value, providerTokens[i].length);
+ p += providerTokens[i].length;
+
+ gss_release_buffer(&tmpMinor, &providerTokens[i]);
+ }
}
/*
gss_OID *MN_mech,
gss_buffer_set_t *attrs)
{
+ 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 (name->attrCtx != NULL)
delete name->attrCtx;
+ *minor = 0;
return GSS_S_COMPLETE;
}
struct gss_eap_attr_ctx **pAttrContext,
time_t *pExpiryTime)
{
- gss_eap_attr_ctx *ctx;
+ gss_eap_attr_ctx *ctx = NULL;
OM_uint32 major;
assert(gssCtx != GSS_C_NO_CONTEXT);
if (GSS_ERROR(major))
return major;
+ *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
+ major = GSS_S_FAILURE;
+
try {
ctx = new gss_eap_attr_ctx();
- if (!ctx->initFromGssContext(gssCred, gssCtx)) {
+ if (ctx->initFromGssContext(gssCred, gssCtx)) {
+ *minor = 0;
+ major = GSS_S_COMPLETE;
+ } else {
delete ctx;
- *minor = GSSEAP_ATTR_CONTEXT_FAILURE;
- return GSS_S_FAILURE;
}
} catch (std::exception &e) {
- major = ctx->mapException(minor, e);
- delete ctx;
- return major;
+ if (ctx != NULL)
+ major = ctx->mapException(minor, e);
}
- *pAttrContext = ctx;
- *pExpiryTime = ctx->getExpiryTime();
+ if (major == GSS_S_COMPLETE) {
+ *pAttrContext = ctx;
+ *pExpiryTime = ctx->getExpiryTime();
+ }
- *minor = 0;
- return GSS_S_COMPLETE;
+ return major;
}