if (inputToken != GSS_C_NO_BUFFER && inputToken->length != 0)
return GSS_S_DEFECTIVE_TOKEN;
- assert(ctx->acceptorCtx.radHandle == NULL);
-
- major = gssEapRadiusAllocHandle(minor, cred, &ctx->acceptorCtx.radHandle);
- if (GSS_ERROR(major))
- return major;
-
assert(ctx->acceptorName == GSS_C_NO_NAME);
if (cred != GSS_C_NO_CREDENTIAL && cred->name != GSS_C_NO_NAME) {
gss_buffer_desc nameBuf;
krb5_context krbContext = NULL;
krb5_principal krbPrinc;
+ rc_handle *rh = ctx->acceptorCtx.radHandle;
+
+ assert(rh != NULL);
/* Awaits further specification */
if (ctx->acceptorName == GSS_C_NO_NAME)
/* Acceptor-Service-Name */
krbDataToGssBuffer(krb5_princ_component(krbContext, krbPrinc, 0), &nameBuf);
- major = addAvpFromBuffer(minor, ctx->acceptorCtx.radHandle, avps,
+ major = addAvpFromBuffer(minor, rh, avps,
VENDOR_ATTR_GSS_ACCEPTOR_SERVICE_NAME,
VENDOR_ID_UKERNA,
&nameBuf);
/* Acceptor-Host-Name */
krbDataToGssBuffer(krb5_princ_component(krbContext, krbPrinc, 1), &nameBuf);
- major = addAvpFromBuffer(minor, ctx->acceptorCtx.radHandle, avps,
+ major = addAvpFromBuffer(minor, rh, avps,
VENDOR_ATTR_GSS_ACCEPTOR_HOST_NAME,
VENDOR_ID_UKERNA,
&nameBuf);
nameBuf.value = ssi;
nameBuf.length = strlen(ssi);
- major = addAvpFromBuffer(minor, ctx->acceptorCtx.radHandle, avps,
+ major = addAvpFromBuffer(minor, rh, avps,
VENDOR_ATTR_GSS_ACCEPTOR_SERVICE_SPECIFIC,
VENDOR_ID_UKERNA,
&nameBuf);
krbDataToGssBuffer(krb5_princ_realm(krbContext, krbPrinc), &nameBuf);
if (nameBuf.length != 0) {
/* Acceptor-Realm-Name */
- major = addAvpFromBuffer(minor, ctx->acceptorCtx.radHandle, avps,
+ major = addAvpFromBuffer(minor, rh, avps,
VENDOR_ATTR_GSS_ACCEPTOR_REALM_NAME,
VENDOR_ID_UKERNA,
&nameBuf);
gss_buffer_t outputToken)
{
OM_uint32 major, tmpMinor;
+ rc_handle *rh;
int code;
VALUE_PAIR *send = NULL;
VALUE_PAIR *received = NULL;
- rc_handle *rh = ctx->acceptorCtx.radHandle;
char msgBuffer[4096];
struct eap_hdr *pdu;
unsigned char *pos;
gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
+ if (ctx->acceptorCtx.radHandle == NULL) {
+ /* May be NULL from an imported partial context */
+ major = gssEapRadiusAllocHandle(minor, cred, ctx);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+
+ rh = ctx->acceptorCtx.radHandle;
+
pdu = (struct eap_hdr *)inputToken->value;
pos = (unsigned char *)(pdu + 1);
if (GSS_ERROR(major))
goto cleanup;
- if (ctx->acceptorCtx.lastStatus == CHALLENGE_RC) {
+ if (ctx->acceptorCtx.state.length != 0) {
major = addAvpFromBuffer(minor, rh, &send, PW_STATE, 0,
&ctx->acceptorCtx.state);
if (GSS_ERROR(major))
if (GSS_ERROR(major))
goto cleanup;
- ctx->acceptorCtx.lastStatus = code;
-
major = getBufferFromAvps(minor, received, PW_EAP_MESSAGE, 0,
outputToken, TRUE);
if ((major == GSS_S_UNAVAILABLE && code != OK_RC) ||
gss_ctx_id_t ctx,
OM_uint32 *time_rec)
{
- OM_uint32 major = GSS_S_NO_CONTEXT;
+ OM_uint32 major;
if (ctx == GSS_C_NO_CONTEXT) {
*minor = EINVAL;
GSSEAP_MUTEX_LOCK(&ctx->mutex);
- if (CTX_IS_ESTABLISHED(ctx)) {
- major = gssEapContextTime(minor, ctx, time_rec);
+ if (!CTX_IS_ESTABLISHED(ctx)) {
+ major = GSS_S_NO_CONTEXT;
+ goto cleanup;
}
+ major = gssEapContextTime(minor, ctx, time_rec);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+cleanup:
GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
return major;
gss_ctx_id_t ctx,
gss_buffer_t token)
{
- /* XXX we also need to serialise the current server name */
- return duplicateBuffer(minor, &ctx->acceptorCtx.state, token);
+ OM_uint32 major, tmpMinor;
+ size_t length, serverLen;
+ unsigned char *p;
+
+ if (ctx->acceptorCtx.radServer != NULL)
+ serverLen = strlen(ctx->acceptorCtx.radServer);
+ else
+ serverLen = 0;
+
+ length = 4 + serverLen + 4 + ctx->acceptorCtx.state.length;
+
+ token->value = GSSEAP_MALLOC(length);
+ if (token->value == NULL) {
+ *minor = ENOMEM;
+ major = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ token->length = length;
+
+ p = (unsigned char *)token->value;
+
+ store_uint32_be(serverLen, p);
+ p += 4;
+ if (serverLen != 0) {
+ memcpy(p, ctx->acceptorCtx.radServer, serverLen);
+ p += serverLen;
+ }
+
+ store_uint32_be(ctx->acceptorCtx.state.length, p);
+ p += 4;
+ if (ctx->acceptorCtx.state.length != 0) {
+ memcpy(p, ctx->acceptorCtx.state.value,
+ ctx->acceptorCtx.state.length);
+ p += ctx->acceptorCtx.state.length;
+ }
+
+ assert(p == (unsigned char *)token->value + token->length);
+
+cleanup:
+ if (GSS_ERROR(major))
+ gss_release_buffer(&tmpMinor, token);
+
+ return major;
}
static OM_uint32
struct gss_eap_acceptor_ctx {
rc_handle *radHandle;
- int lastStatus;
- VALUE_PAIR *avps;
+ char *radServer;
gss_buffer_desc state;
+ VALUE_PAIR *avps;
};
struct gss_ctx_id_struct {
#include "gssapiP_eap.h"
+#define UPDATE_REMAIN(n) do { \
+ p += (n); \
+ remain -= (n); \
+ } while (0)
+
+#define CHECK_REMAIN(n) do { \
+ if (remain < (n)) { \
+ *minor = ERANGE; \
+ return GSS_S_DEFECTIVE_TOKEN; \
+ } \
+ } while (0)
+
static OM_uint32
gssEapImportPartialContext(OM_uint32 *minor,
unsigned char **pBuf,
unsigned char *p = *pBuf;
size_t remain = *pRemain;
gss_buffer_desc buf;
+ size_t serverLen;
- /* XXX we also need to deserialise the current server name */
+ /* Selected RADIUS server */
+ CHECK_REMAIN(4);
+ serverLen = load_uint32_be(p);
+ UPDATE_REMAIN(4);
- if (remain < 4) {
- *minor = ERANGE;
- return GSS_S_DEFECTIVE_TOKEN;
+ if (serverLen != 0) {
+ CHECK_REMAIN(serverLen);
+
+ ctx->acceptorCtx.radServer = GSSEAP_MALLOC(serverLen + 1);
+ if (ctx->acceptorCtx.radServer == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+ memcpy(ctx->acceptorCtx.radServer, p, serverLen);
+ ctx->acceptorCtx.radServer[serverLen] = '\0';
+
+ UPDATE_REMAIN(serverLen);
}
+
+ /* RADIUS state blob */
+ CHECK_REMAIN(4);
buf.length = load_uint32_be(p);
+ UPDATE_REMAIN(4);
- if (remain < buf.length) {
- *minor = ERANGE;
- return GSS_S_DEFECTIVE_TOKEN;
+ if (buf.length != 0) {
+ CHECK_REMAIN(buf.length);
- }
- buf.value = &p[4];
+ buf.value = p;
- major = duplicateBuffer(minor, &buf, &ctx->acceptorCtx.state);
- if (GSS_ERROR(major))
- return major;
+ major = duplicateBuffer(minor, &buf, &ctx->acceptorCtx.state);
+ if (GSS_ERROR(major))
+ return major;
+
+ UPDATE_REMAIN(buf.length);
+ }
- *pBuf += 4 + buf.length;
- *pRemain -= 4 + buf.length;
+ *pBuf = p;
+ *pRemain = remain;
return GSS_S_COMPLETE;
}
OM_uint32 major, tmpMinor;
if (ctx == GSS_C_NO_CONTEXT) {
- *mionr = EINVAL;
+ *minor = EINVAL;
return GSS_S_NO_CONTEXT;
}
rc_config_free(ctx->radHandle);
gss_release_buffer(&tmpMinor, &ctx->state);
+ if (ctx->radServer != NULL)
+ GSSEAP_FREE(ctx->radServer);
}
OM_uint32
(void *)"urn:x-radius:"
};
-static bool
+static int
radiusAllocHandle(const char *configFile,
rc_handle **pHandle)
{
rc_handle *rh;
+ int ret;
*pHandle = NULL;
rh = rc_read_config((char *)configFile);
if (rh == NULL) {
rc_config_free(rh);
- return false;
+ return -1;
}
- if (rc_read_dictionary(rh, rc_conf_str(rh, (char *)"dictionary")) != 0) {
+ ret = rc_read_dictionary(rh, rc_conf_str(rh, (char *)"dictionary"));
+ if (ret != 0) {
rc_config_free(rh);
- return false;
+ return ret;
}
*pHandle = rh;
- return true;
+ return 0;
}
VALUE_PAIR *
{
m_configFile.assign(configFile);
- return radiusAllocHandle(m_configFile.c_str(), &m_rh);
+ return (radiusAllocHandle(m_configFile.c_str(), &m_rh) == 0);
}
bool
OM_uint32
gssEapRadiusAllocHandle(OM_uint32 *minor,
const gss_cred_id_t cred,
- rc_handle **pHandle)
+ gss_ctx_id_t ctx)
{
const char *configFile = NULL;
- *pHandle = NULL;
+ assert(ctx->acceptorCtx.radHandle == NULL);
if (cred != GSS_C_NO_CREDENTIAL && cred->radiusConfigFile != NULL)
configFile = cred->radiusConfigFile;
- if (!radiusAllocHandle(configFile, pHandle))
+ if (radiusAllocHandle(configFile, &ctx->acceptorCtx.radHandle) != 0)
return GSS_S_FAILURE;
+ /* XXX TODO allocate connection handle */
+
+ /* XXX TODO select based on acceptorCtx.radServer */
+
return GSS_S_COMPLETE;
}
OM_uint32
gssEapRadiusAllocHandle(OM_uint32 *minor,
const gss_cred_id_t cred,
- rc_handle **pHandle);
+ gss_ctx_id_t ctx);
#define RC_CONFIG_FILE SYSCONFDIR "/radiusclient/radiusclient.conf"