gss_LTLIBRARIES = libmech_eap.la
-libmech_eap_la_CPPFLAGS = -DBUILD_GSSEAP_LIB
+libmech_eap_la_CPPFLAGS = -DBUILD_GSSEAP_LIB -DSYSCONFDIR=\"${sysconfdir}\"
libmech_eap_la_CFLAGS = -g -Wall -fno-strict-aliasing \
@EAP_CFLAGS@ @KRB5_CFLAGS@ @TARGET_CFLAGS@
libmech_eap_la_CXXFLAGS = -g -Wall \
libmech_eap_la_LDFLAGS = -export-symbols mech_eap.exports -version-info 0:0:0 \
-no-undefined \
@EAP_LDFLAGS@ @KRB5_LDFLAGS@ @TARGET_LDFLAGS@
-libmech_eap_la_LIBADD = @EAP_LIBS@ @KRB5_LIBS@ @SHIBSP_LIBS@ @SHIBRESOLVER_LIBS@
+libmech_eap_la_LIBADD = @EAP_LIBS@ @KRB5_LIBS@ @SHIBSP_LIBS@ @SHIBRESOLVER_LIBS@ -lfreeradius-client
libmech_eap_la_SOURCES = \
accept_sec_context.c \
#include "gssapiP_eap.h"
-#ifdef BUILTIN_EAP
-#define EAP_KEY_AVAILABLE(ctx) ((ctx)->acceptorCtx.eapPolInterface->eapKeyAvailable)
-#define EAP_KEY_DATA(ctx) ((ctx)->acceptorCtx.eapPolInterface->eapKeyData)
-#define EAP_KEY_LENGTH(ctx) ((ctx)->acceptorCtx.eapPolInterface->eapKeyDataLen)
-#else
-#define EAP_KEY_AVAILABLE(ctx) 0
-#define EAP_KEY_DATA(ctx) NULL
-#define EAP_KEY_LENGTH(ctx) 0
-#endif /* BUILTIN_EAP */
-
+/*
+ * Mark a context as ready for cryptographic operations
+ */
static OM_uint32
-acceptReady(OM_uint32 *minor, gss_ctx_id_t ctx);
-
-#ifdef BUILTIN_EAP
-#define EAP_MAX_METHODS 8
-
-#define EAP_TTLS_AUTH_PAP 1
-#define EAP_TTLS_AUTH_CHAP 2
-#define EAP_TTLS_AUTH_MSCHAP 4
-#define EAP_TTLS_AUTH_MSCHAPV2 8
-
-struct eap_user {
- struct {
- int vendor;
- u32 method;
- } methods[EAP_MAX_METHODS];
- u8 *password;
- size_t password_len;
- int password_hash; /* whether password is hashed with
- * nt_password_hash() */
- int phase2;
- int force_version;
- int ttls_auth; /* bitfield of
- * EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */
-};
+acceptReady(OM_uint32 *minor, gss_ctx_id_t ctx, gss_cred_id_t cred)
+{
+ OM_uint32 major;
+ VALUE_PAIR *vp;
+ gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
-struct eap_eapol_interface {
- /* Lower layer to full authenticator variables */
- Boolean eapResp; /* shared with EAPOL Backend Authentication */
- struct wpabuf *eapRespData;
- Boolean portEnabled;
- int retransWhile;
- Boolean eapRestart; /* shared with EAPOL Authenticator PAE */
- int eapSRTT;
- int eapRTTVAR;
-
- /* Full authenticator to lower layer variables */
- Boolean eapReq; /* shared with EAPOL Backend Authentication */
- Boolean eapNoReq; /* shared with EAPOL Backend Authentication */
- Boolean eapSuccess;
- Boolean eapFail;
- Boolean eapTimeout;
- struct wpabuf *eapReqData;
- u8 *eapKeyData;
- size_t eapKeyDataLen;
- Boolean eapKeyAvailable; /* called keyAvailable in IEEE 802.1X-2004 */
-
- /* AAA interface to full authenticator variables */
- Boolean aaaEapReq;
- Boolean aaaEapNoReq;
- Boolean aaaSuccess;
- Boolean aaaFail;
- struct wpabuf *aaaEapReqData;
- u8 *aaaEapKeyData;
- size_t aaaEapKeyDataLen;
- Boolean aaaEapKeyAvailable;
- int aaaMethodTimeout;
-
- /* Full authenticator to AAA interface variables */
- Boolean aaaEapResp;
- struct wpabuf *aaaEapRespData;
- /* aaaIdentity -> eap_get_identity() */
- Boolean aaaTimeout;
-};
+ /* Cache encryption type derived from selected mechanism OID */
+ major = gssEapOidToEnctype(minor, ctx->mechanismUsed,
+ &ctx->encryptionType);
+ if (GSS_ERROR(major))
+ return major;
-#define eapol_callbacks SERVER_eapol_callbacks
+ vp = rc_avpair_get(ctx->acceptorCtx.avps, PW_USER_NAME, 0);
+ if (vp != NULL) {
+ nameBuf.length = vp->lvalue;
+ nameBuf.value = vp->strvalue;
+ } else if (ctx->initiatorName == GSS_C_NO_NAME) {
+ ctx->gssFlags |= GSS_C_ANON_FLAG;
+ }
-struct eapol_callbacks {
- int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
- int phase2, struct eap_user *user);
- const char * (*get_eap_req_id_text)(void *ctx, size_t *len);
-};
+ if (nameBuf.length != 0 || ctx->initiatorName == GSS_C_NO_NAME) {
+ major = gssEapImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
+ &ctx->initiatorName);
+ if (GSS_ERROR(major))
+ return major;
+ }
-#define eap_config SERVER_eap_config
-
-struct eap_config {
- void *ssl_ctx;
- void *msg_ctx;
- void *eap_sim_db_priv;
- Boolean backend_auth;
- int eap_server;
- u8 *pac_opaque_encr_key;
- u8 *eap_fast_a_id;
- size_t eap_fast_a_id_len;
- char *eap_fast_a_id_info;
- int eap_fast_prov;
- int pac_key_lifetime;
- int pac_key_refresh_time;
- int eap_sim_aka_result_ind;
- int tnc;
- struct wps_context *wps;
- const struct wpabuf *assoc_wps_ie;
- const u8 *peer_addr;
- int fragment_size;
-};
+ ctx->initiatorName->attrCtx = gssEapCreateAttrContext(cred, ctx);
+
+ vp = rc_avpair_get(ctx->acceptorCtx.avps,
+ RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY,
+ RADIUS_VENDOR_ID_MICROSOFT);
+ if (ctx->encryptionType != ENCTYPE_NULL && vp != NULL) {
+ major = gssEapDeriveRfc3961Key(minor,
+ (unsigned char *)vp->strvalue,
+ vp->lvalue,
+ ctx->encryptionType,
+ &ctx->rfc3961Key);
+ if (GSS_ERROR(major))
+ return major;
-struct eap_sm * eap_server_sm_init(void *eapol_ctx,
- struct eapol_callbacks *eapol_cb,
- struct eap_config *eap_conf);
-void eap_server_sm_deinit(struct eap_sm *sm);
-int eap_server_sm_step(struct eap_sm *sm);
-void eap_sm_notify_cached(struct eap_sm *sm);
-void eap_sm_pending_cb(struct eap_sm *sm);
-int eap_sm_method_pending(struct eap_sm *sm);
-const u8 * eap_get_identity(struct eap_sm *sm, size_t *len);
-struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm);
+ major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
+ &ctx->checksumType);
+ if (GSS_ERROR(major))
+ return major;
+ } else {
+ /*
+ * draft-howlett-eap-gss says that integrity/confidentialty should
+ * always be advertised as available, but if we have no keying
+ * material it seems confusing to the caller to advertise this.
+ */
+ ctx->gssFlags &= ~(GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
+ ctx->encryptionType = ENCTYPE_NULL;
+ }
+
+ major = sequenceInit(minor,
+ &ctx->seqState, ctx->recvSeq,
+ ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
+ ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
+ TRUE);
+ if (GSS_ERROR(major))
+ return major;
-#include <eap_server/eap_i.h>
+ return GSS_S_COMPLETE;
+}
static OM_uint32
-initTls(OM_uint32 *minor,
- gss_ctx_id_t ctx)
+eapGssSmAcceptIdentity(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_cred_id_t cred,
+ gss_buffer_t inputToken,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t outputToken)
{
- struct tls_config tconf;
- struct tls_connection_params tparams;
+ OM_uint32 major;
+ union {
+ struct eap_hdr pdu;
+ unsigned char data[5];
+ } pkt;
+ gss_buffer_desc pktBuffer;
- memset(&tconf, 0, sizeof(tconf));
- ctx->acceptorCtx.tlsContext = tls_init(&tconf);
- if (ctx->acceptorCtx.tlsContext == NULL)
- return GSS_S_FAILURE;
+ if (inputToken != GSS_C_NO_BUFFER && inputToken->length != 0)
+ return GSS_S_DEFECTIVE_TOKEN;
- memset(&tparams, 0, sizeof(tparams));
- tparams.ca_cert = "ca.pem";
- tparams.client_cert = "server.pem";
- tparams.private_key = "server-key.pem";
+ assert(ctx->acceptorCtx.radHandle == NULL);
- if (tls_global_set_params(ctx->acceptorCtx.tlsContext, &tparams)) {
- return GSS_S_FAILURE;
- }
+ major = gssEapRadiusAllocHandle(minor, cred, &ctx->acceptorCtx.radHandle);
+ if (GSS_ERROR(major))
+ return major;
- if (tls_global_set_verify(ctx->acceptorCtx.tlsContext, 0)) {
- return GSS_S_FAILURE;
+ if (ctx->acceptorName == GSS_C_NO_NAME &&
+ cred != GSS_C_NO_CREDENTIAL &&
+ cred->name != GSS_C_NO_NAME) {
+ major = gss_duplicate_name(minor, cred->name, &ctx->acceptorName);
+ if (GSS_ERROR(major))
+ return major;
}
- return GSS_S_COMPLETE;
+ pkt.pdu.code = EAP_CODE_REQUEST;
+ pkt.pdu.identifier = 0;
+ pkt.pdu.length = htons(sizeof(pkt.data));
+ pkt.data[4] = EAP_TYPE_IDENTITY;
+
+ pktBuffer.length = sizeof(pkt.data);
+ pktBuffer.value = pkt.data;
+
+ major = duplicateBuffer(minor, &pktBuffer, outputToken);
+ if (GSS_ERROR(major))
+ return major;
+
+ ctx->state = EAP_STATE_AUTHENTICATE;
+
+ return GSS_S_CONTINUE_NEEDED;
}
-static int
-serverGetEapUser(void *ctx,
- const unsigned char *identity,
- size_t identityLength,
- int phase2,
- struct eap_user *user)
+static OM_uint32
+importInitiatorIdentity(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_buffer_t inputToken,
+ gss_buffer_t nameBuf)
{
- gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx;
- OM_uint32 major, minor;
- gss_buffer_desc buf;
-
- memset(user, 0, sizeof(*user));
+ OM_uint32 major, tmpMinor;
+ struct eap_hdr *pdu = (struct eap_hdr *)inputToken->value;
+ unsigned char *pos = (unsigned char *)(pdu + 1);
+ gss_name_t name;
- buf.length = identityLength;
- buf.value = (void *)identity;
+ assert(pdu->code == EAP_CODE_RESPONSE);
+ assert(pos[0] == EAP_TYPE_IDENTITY);
- if (phase2 == 0) {
- user->methods[0].vendor = EAP_VENDOR_IETF;
- user->methods[0].method = EAP_TYPE_PEAP;
- return 0;
- }
+ nameBuf->value = pos + 1;
+ nameBuf->length = inputToken->length - sizeof(*pdu) - 1;
- major = gssEapImportName(&minor, &buf, GSS_C_NT_USER_NAME,
- &gssCtx->initiatorName);
+ major = gssEapImportName(minor, nameBuf, GSS_C_NT_USER_NAME, &name);
if (GSS_ERROR(major))
- return -1;
-
- /*
- * OK, obviously there is no real security here, this is simply
- * for testing the token exchange; this code will be completely
- * replaced with libradius once that library is available.
- */
- user->methods[0].vendor = EAP_VENDOR_IETF;
- user->methods[0].method = EAP_TYPE_MSCHAPV2;
- user->password = (unsigned char *)strdup("foo");
- user->password_len = 3;
-
- gssCtx->initiatorName->attrCtx = gssEapCreateAttrContext(NULL, gssCtx);
- if (gssCtx->initiatorName->attrCtx != NULL)
- gssCtx->initiatorName->flags |= NAME_FLAG_COMPOSITE;
-
- return 0;
-}
+ return major;
-static const char *
-serverGetEapReqIdText(void *ctx,
- size_t *len)
-{
- *len = 0;
- return NULL;
+ gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
+ ctx->initiatorName = name;
+
+ return GSS_S_COMPLETE;
}
static OM_uint32
gss_channel_bindings_t chanBindings,
gss_buffer_t outputToken)
{
- OM_uint32 major;
- OM_uint32 tmpMinor, tmpMajor;
+ OM_uint32 major, tmpMinor;
int code;
- struct wpabuf respData;
- static struct eapol_callbacks cb = { serverGetEapUser, serverGetEapReqIdText };
- if (ctx->acceptorCtx.eap == NULL) {
- struct eap_config eapConfig;
+ 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;
+
+ pdu = (struct eap_hdr *)inputToken->value;
+ pos = (unsigned char *)(pdu + 1);
+
+ if (inputToken->length > sizeof(*pdu) &&
+ pdu->code == EAP_CODE_RESPONSE &&
+ pos[0] == EAP_TYPE_IDENTITY) {
+ major = importInitiatorIdentity(minor, ctx, inputToken, &nameBuf);
+ if (GSS_ERROR(major))
+ goto cleanup;
- major = initTls(minor, ctx);
+ major = addAvpFromBuffer(minor, rh, &send, PW_USER_NAME, &nameBuf);
if (GSS_ERROR(major))
goto cleanup;
+ }
- memset(&eapConfig, 0, sizeof(eapConfig));
- eapConfig.eap_server = 1;
- eapConfig.ssl_ctx = ctx->acceptorCtx.tlsContext;
+ major = addAvpFromBuffer(minor, rh, &send, PW_EAP_MESSAGE, inputToken);
+ if (GSS_ERROR(major))
+ goto cleanup;
- ctx->acceptorCtx.eap = eap_server_sm_init(ctx, &cb, &eapConfig);
- if (ctx->acceptorCtx.eap == NULL) {
- major = GSS_S_FAILURE;
+ if (ctx->acceptorCtx.lastStatus == CHALLENGE_RC) {
+ major = addAvpFromBuffer(minor, rh, &send, PW_STATE,
+ &ctx->acceptorCtx.state);
+ if (GSS_ERROR(major))
goto cleanup;
- }
- ctx->acceptorCtx.eapPolInterface = eap_get_interface(ctx->acceptorCtx.eap);
- ctx->acceptorCtx.eapPolInterface->portEnabled = TRUE;
- ctx->acceptorCtx.eapPolInterface->eapRestart = TRUE;
+ gss_release_buffer(&tmpMinor, &ctx->acceptorCtx.state);
}
- if (ctx->acceptorName == GSS_C_NO_NAME &&
- cred != GSS_C_NO_CREDENTIAL &&
- cred->name != GSS_C_NO_NAME) {
- major = gss_duplicate_name(minor, cred->name, &ctx->acceptorName);
- if (GSS_ERROR(major))
- goto cleanup;
+ code = rc_auth(rh, 0, send, &received, msgBuffer);
+ switch (code) {
+ case OK_RC:
+ case CHALLENGE_RC:
+ major = GSS_S_CONTINUE_NEEDED;
+ break;
+ case TIMEOUT_RC:
+ major = GSS_S_UNAVAILABLE;
+ break;
+ case REJECT_RC:
+ major = GSS_S_DEFECTIVE_CREDENTIAL;
+ break;
+ default:
+ major = GSS_S_FAILURE;
+ goto cleanup;
}
- wpabuf_set(&respData, inputToken->value, inputToken->length);
- ctx->acceptorCtx.eapPolInterface->eapRespData = &respData;
- ctx->acceptorCtx.eapPolInterface->eapResp = TRUE;
+ if (GSS_ERROR(major))
+ goto cleanup;
- code = eap_server_sm_step(ctx->acceptorCtx.eap);
+ ctx->acceptorCtx.lastStatus = code;
- if (ctx->acceptorCtx.eapPolInterface->eapReq) {
- ctx->acceptorCtx.eapPolInterface->eapReq = 0;
- major = GSS_S_CONTINUE_NEEDED;
- }
+ major = getBufferFromAvps(minor, received, PW_EAP_MESSAGE,
+ outputToken, TRUE);
+ if ((major == GSS_S_UNAVAILABLE && code != OK_RC) ||
+ GSS_ERROR(major))
+ goto cleanup;
- if (ctx->acceptorCtx.eapPolInterface->eapSuccess) {
- ctx->acceptorCtx.eapPolInterface->eapSuccess = 0;
- major = acceptReady(minor, ctx);
+ if (code == CHALLENGE_RC) {
+ major = getBufferFromAvps(minor, received, PW_STATE,
+ &ctx->acceptorCtx.state, TRUE);
+ if (major != GSS_S_UNAVAILABLE && GSS_ERROR(major))
+ goto cleanup;
+ } else {
+ ctx->acceptorCtx.avps = received;
+ received = NULL;
+
+ major = acceptReady(minor, ctx, cred);
if (GSS_ERROR(major))
goto cleanup;
ctx->state = EAP_STATE_GSS_CHANNEL_BINDINGS;
- major = GSS_S_CONTINUE_NEEDED;
- } else if (ctx->acceptorCtx.eapPolInterface->eapFail) {
- ctx->acceptorCtx.eapPolInterface->eapFail = 0;
- major = GSS_S_FAILURE;
- } else if (code == 0) {
- major = GSS_S_FAILURE;
}
- if (ctx->acceptorCtx.eapPolInterface->eapReqData != NULL) {
- gss_buffer_desc buf;
-
- buf.length = wpabuf_len(ctx->acceptorCtx.eapPolInterface->eapReqData);
- buf.value = (void *)wpabuf_head(ctx->acceptorCtx.eapPolInterface->eapReqData);
-
- tmpMajor = duplicateBuffer(&tmpMinor, &buf, outputToken);
- if (GSS_ERROR(tmpMajor)) {
- major = tmpMajor;
- *minor = tmpMinor;
- goto cleanup;
- }
- }
+ major = GSS_S_CONTINUE_NEEDED;
cleanup:
- ctx->acceptorCtx.eapPolInterface->eapRespData = NULL;
+ if (received != NULL)
+ rc_avpair_free(received);
return major;
}
-#else
-static OM_uint32
-eapGssSmAcceptAuthenticate(OM_uint32 *minor,
- gss_ctx_id_t ctx,
- gss_cred_id_t cred,
- gss_buffer_t inputToken,
- gss_channel_bindings_t chanBindings,
- gss_buffer_t outputToken)
-{
- OM_uint32 major, tmpMinor;
-
-cleanup:
- return major;
-}
-#endif /* BUILTIN_EAP */
static OM_uint32
eapGssSmAcceptGssChannelBindings(OM_uint32 *minor,
gss_channel_bindings_t chanBindings,
gss_buffer_t outputToken)
{
- OM_uint32 major, tmpMinor;
+ OM_uint32 major;
gss_iov_buffer_desc iov[2];
outputToken->length = 0;
gss_channel_bindings_t,
gss_buffer_t);
} eapGssAcceptorSm[] = {
+ { TOK_TYPE_EAP_RESP, TOK_TYPE_EAP_REQ, eapGssSmAcceptIdentity },
{ TOK_TYPE_EAP_RESP, TOK_TYPE_EAP_REQ, eapGssSmAcceptAuthenticate },
-#if 0
- { TOK_TYPE_EAP_RESP, TOK_TYPE_EAP_REQ, NULL },
- { TOK_TYPE_EAP_RESP, TOK_TYPE_EAP_REQ, NULL },
-#endif
{ TOK_TYPE_GSS_CB, TOK_TYPE_NONE, eapGssSmAcceptGssChannelBindings },
{ TOK_TYPE_NONE, TOK_TYPE_NONE, eapGssSmAcceptEstablished },
};
return major;
}
-/*
- * Mark a context as ready for cryptographic operations
- */
-static OM_uint32
-acceptReady(OM_uint32 *minor, gss_ctx_id_t ctx)
-{
- OM_uint32 major;
-
- /* Cache encryption type derived from selected mechanism OID */
- major = gssEapOidToEnctype(minor, ctx->mechanismUsed, &ctx->encryptionType);
- if (GSS_ERROR(major))
- return major;
-
- if (ctx->encryptionType != ENCTYPE_NULL &&
- EAP_KEY_AVAILABLE(ctx)) {
- major = gssEapDeriveRfc3961Key(minor,
- EAP_KEY_DATA(ctx),
- EAP_KEY_LENGTH(ctx),
- ctx->encryptionType,
- &ctx->rfc3961Key);
- if (GSS_ERROR(major))
- return major;
-
- major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
- &ctx->checksumType);
- if (GSS_ERROR(major))
- return major;
- } else {
- /*
- * draft-howlett-eap-gss says that integrity/confidentialty should
- * always be advertised as available, but if we have no keying
- * material it seems confusing to the caller to advertise this.
- */
- ctx->gssFlags &= ~(GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
- }
-
- major = sequenceInit(minor,
- &ctx->seqState, ctx->recvSeq,
- ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
- ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
- TRUE);
- if (GSS_ERROR(major))
- return major;
-
- return GSS_S_COMPLETE;
-}
gss_ctx_id_t ctx,
gss_buffer_t token)
{
- token->length = 0;
- token->value = NULL;
-
- /*
- * The format of this token awaits definition by libradius.
- */
- return GSS_S_COMPLETE;
+ return duplicateBuffer(minor, &ctx->acceptorCtx.state, token);
}
static OM_uint32
#ifndef _GSSAPIP_EAP_H_
#define _GSSAPIP_EAP_H_ 1
-#define BUILTIN_EAP 1
-
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <gssapi/gssapi.h>
#include <gssapi/gssapi_ext.h>
#include "gssapi_eap.h"
-#include "util.h"
/* Kerberos includes */
#include <krb5.h>
#include <wpabuf.h>
#endif
+#include <freeradius-client.h>
+#include <freeradius/radius.h>
+
+#include "util.h"
+
/* These name flags are informative and not actually used by anything yet */
#define NAME_FLAG_NAI 0x00000001
#define NAME_FLAG_SERVICE 0x00000002
gss_buffer_desc password;
gss_OID_set mechanisms;
time_t expiryTime;
+ char *radiusConfigFile;
};
#define CTX_FLAG_INITIATOR 0x00000001
#define CTX_IS_INITIATOR(ctx) (((ctx)->flags & CTX_FLAG_INITIATOR) != 0)
enum gss_eap_state {
- EAP_STATE_AUTHENTICATE = 0,
-#if 0
- EAP_STATE_KEY_TRANSPORT,
- EAP_STATE_SECURE_ASSOCIATION,
-#endif
+ EAP_STATE_IDENTITY = 0,
+ EAP_STATE_AUTHENTICATE,
EAP_STATE_GSS_CHANNEL_BINDINGS,
EAP_STATE_ESTABLISHED
};
};
struct gss_eap_acceptor_ctx {
-#if defined(BUILTIN_EAP) && !defined(__cplusplus)
- struct eap_eapol_interface *eapPolInterface;
- void *tlsContext;
- struct eap_sm *eap;
-#endif
+ rc_handle *radHandle;
+ int lastStatus;
+ VALUE_PAIR *avps;
+ gss_buffer_desc state;
};
struct gss_ctx_id_struct {
/* name type */
extern gss_OID GSS_EAP_NT_PRINCIPAL_NAME;
+/* set credential option for acceptor configuration file */
+extern gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE;
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
size_t *pRemain,
gss_ctx_id_t ctx)
{
+ OM_uint32 major;
unsigned char *p = *pBuf;
size_t remain = *pRemain;
gss_buffer_desc buf;
*minor = ERANGE;
return GSS_S_DEFECTIVE_TOKEN;
}
-
buf.length = load_uint32_be(p);
- if (buf.length != 0) {
- *minor = EINVAL;
+ if (remain < buf.length) {
+ *minor = ERANGE;
return GSS_S_DEFECTIVE_TOKEN;
+
}
+ buf.value = &p[4];
+
+ major = duplicateBuffer(minor, &buf, &ctx->acceptorCtx.state);
+ if (GSS_ERROR(major))
+ return major;
+
+ *pBuf += 4 + buf.length;
+ *pRemain -= 4 + buf.length;
- *minor = 0;
return GSS_S_COMPLETE;
}
remain -= 16;
/* Validate state */
- if (ctx->state < EAP_STATE_AUTHENTICATE ||
+ if (ctx->state < EAP_STATE_IDENTITY ||
ctx->state > EAP_STATE_ESTABLISHED)
return GSS_S_DEFECTIVE_TOKEN;
static OM_uint32
peerConfigInit(OM_uint32 *minor,
gss_cred_id_t cred,
- gss_ctx_id_t ctx,
- int loadConfig)
+ gss_ctx_id_t ctx)
{
krb5_context krbContext;
struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig;
GSSEAP_KRB_INIT(&krbContext);
- if (loadConfig) {
- eapPeerConfig->fragment_size = 1024;
- wpa_debug_level = 0;
- }
+ eapPeerConfig->fragment_size = 1024;
+ wpa_debug_level = 0;
code = krb5_unparse_name(krbContext, cred->name->krbPrincipal, &identity);
if (code != 0) {
OM_uint32 major;
const unsigned char *key;
size_t keyLength;
+ krb5_enctype encryptionType;
+ int gotKey = 0;
/* Cache encryption type derived from selected mechanism OID */
- major = gssEapOidToEnctype(minor, ctx->mechanismUsed, &ctx->encryptionType);
+ major = gssEapOidToEnctype(minor, ctx->mechanismUsed, &encryptionType);
if (GSS_ERROR(major))
return major;
- if (ctx->encryptionType != ENCTYPE_NULL &&
+ if (encryptionType != ENCTYPE_NULL &&
eap_key_available(ctx->initiatorCtx.eap)) {
key = eap_get_eapKeyData(ctx->initiatorCtx.eap, &keyLength);
- major = gssEapDeriveRfc3961Key(minor, key, keyLength,
- ctx->encryptionType, &ctx->rfc3961Key);
- if (GSS_ERROR(major))
- return major;
+ if (keyLength >= EAP_EMSK_LEN) {
+ major = gssEapDeriveRfc3961Key(minor,
+ &key[EAP_EMSK_LEN / 2],
+ EAP_EMSK_LEN / 2,
+ encryptionType,
+ &ctx->rfc3961Key);
+ if (GSS_ERROR(major))
+ return major;
+
+ major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
+ &ctx->checksumType);
+ if (GSS_ERROR(major))
+ return major;
+ gotKey++;
+ }
+ }
- major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
- &ctx->checksumType);
- if (GSS_ERROR(major))
- return major;
+ if (gotKey) {
+ ctx->encryptionType = encryptionType;
} else {
/*
* draft-howlett-eap-gss says that integrity/confidentialty should
}
static OM_uint32
+eapGssSmInitIdentity(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ gss_name_t target,
+ gss_OID mech,
+ OM_uint32 reqFlags,
+ OM_uint32 timeReq,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t inputToken,
+ gss_buffer_t outputToken)
+{
+ time_t now;
+ OM_uint32 major;
+ int initialContextToken;
+
+ initialContextToken = (inputToken == GSS_C_NO_BUFFER ||
+ inputToken->length == 0);
+ if (!initialContextToken)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ time(&now);
+ if (timeReq == 0 || timeReq == GSS_C_INDEFINITE)
+ ctx->expiryTime = 0;
+ else
+ ctx->expiryTime = now + timeReq;
+
+ major = gss_duplicate_name(minor, cred->name, &ctx->initiatorName);
+ if (GSS_ERROR(major))
+ return major;
+
+ major = gss_duplicate_name(minor, target, &ctx->acceptorName);
+ if (GSS_ERROR(major))
+ return major;
+
+ if (mech == GSS_C_NULL_OID || oidEqual(mech, GSS_EAP_MECHANISM)) {
+ major = gssEapDefaultMech(minor, &ctx->mechanismUsed);
+ } else if (gssEapIsConcreteMechanismOid(mech)) {
+ if (!gssEapInternalizeOid(mech, &ctx->mechanismUsed))
+ major = duplicateOid(minor, mech, &ctx->mechanismUsed);
+ } else {
+ major = GSS_S_BAD_MECH;
+ }
+ if (GSS_ERROR(major))
+ return major;
+
+ /* If credentials were provided, check they're usable with this mech */
+ if (!gssEapCredAvailable(cred, ctx->mechanismUsed))
+ return GSS_S_BAD_MECH;
+
+ ctx->state = EAP_STATE_AUTHENTICATE;
+
+ return GSS_S_CONTINUE_NEEDED;
+}
+
+static struct wpabuf emptyWpaBuffer;
+
+static OM_uint32
eapGssSmInitAuthenticate(OM_uint32 *minor,
gss_cred_id_t cred,
gss_ctx_id_t ctx,
gss_buffer_t outputToken)
{
OM_uint32 major;
- OM_uint32 tmpMajor, tmpMinor;
- time_t now;
- int initialContextToken = 0, code;
- gss_buffer_desc respBuf = GSS_C_EMPTY_BUFFER;
+ OM_uint32 tmpMinor;
+ int code;
+ struct wpabuf *resp = NULL;
+ int initialContextToken;
initialContextToken = (inputToken == GSS_C_NO_BUFFER ||
inputToken->length == 0);
- major = peerConfigInit(minor, cred, ctx, initialContextToken);
+ major = peerConfigInit(minor, cred, ctx);
if (GSS_ERROR(major))
goto cleanup;
- if (initialContextToken) {
+ if (ctx->initiatorCtx.eap == NULL) {
struct eap_config eapConfig;
memset(&eapConfig, 0, sizeof(eapConfig));
- ctx->flags |= CTX_FLAG_EAP_PORT_ENABLED;
ctx->initiatorCtx.eap = eap_peer_sm_init(ctx,
&gssEapPolicyCallbacks,
ctx,
&eapConfig);
-
- time(&now);
- if (timeReq == 0 || timeReq == GSS_C_INDEFINITE)
- ctx->expiryTime = 0;
- else
- ctx->expiryTime = now + timeReq;
-
- major = gss_duplicate_name(minor, cred->name, &ctx->initiatorName);
- if (GSS_ERROR(major))
- goto cleanup;
-
- major = gss_duplicate_name(minor, target, &ctx->acceptorName);
- if (GSS_ERROR(major))
- goto cleanup;
-
- if (mech == GSS_C_NULL_OID || oidEqual(mech, GSS_EAP_MECHANISM)) {
- major = gssEapDefaultMech(minor, &ctx->mechanismUsed);
- } else if (gssEapIsConcreteMechanismOid(mech)) {
- if (!gssEapInternalizeOid(mech, &ctx->mechanismUsed))
- major = duplicateOid(minor, mech, &ctx->mechanismUsed);
- } else {
- major = GSS_S_BAD_MECH;
- }
- if (GSS_ERROR(major))
- goto cleanup;
-
- /* If credentials were provided, check they're usable with this mech */
- if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) {
- major = GSS_S_BAD_MECH;
+ if (ctx->initiatorCtx.eap == NULL) {
+ major = GSS_S_FAILURE;
goto cleanup;
}
- respBuf.value = ""; /* emit empty inner token */
- major = GSS_S_CONTINUE_NEEDED;
- goto cleanup;
- } else {
- ctx->flags |= CTX_FLAG_EAP_REQ; /* we have a Request from the acceptor */
+ ctx->flags |= CTX_FLAG_EAP_RESTART | CTX_FLAG_EAP_PORT_ENABLED;
}
+ ctx->flags |= CTX_FLAG_EAP_REQ; /* we have a Request from the acceptor */
+
wpabuf_set(&ctx->initiatorCtx.reqData,
inputToken->value, inputToken->length);
code = eap_peer_sm_step(ctx->initiatorCtx.eap);
if (ctx->flags & CTX_FLAG_EAP_RESP) {
- struct wpabuf *resp;
-
ctx->flags &= ~(CTX_FLAG_EAP_RESP);
resp = eap_get_eapRespData(ctx->initiatorCtx.eap);
- if (resp != NULL) {
- respBuf.length = wpabuf_len(resp);
- respBuf.value = (void *)wpabuf_head(resp);
- }
} else if (ctx->flags & CTX_FLAG_EAP_SUCCESS) {
major = initReady(minor, ctx);
if (GSS_ERROR(major))
ctx->state = EAP_STATE_GSS_CHANNEL_BINDINGS;
} else if (ctx->flags & CTX_FLAG_EAP_FAIL) {
major = GSS_S_DEFECTIVE_CREDENTIAL;
- } else if (code == 0) {
- major = GSS_S_FAILURE;
+ } else if (code == 0 && initialContextToken) {
+ resp = &emptyWpaBuffer;
+ major = GSS_S_CONTINUE_NEEDED;
+ } else {
+ major = GSS_S_DEFECTIVE_TOKEN;
}
cleanup:
- if (respBuf.value != NULL) {
+ if (resp != NULL) {
OM_uint32 tmpMajor;
+ gss_buffer_desc respBuf;
assert(major == GSS_S_CONTINUE_NEEDED);
+ respBuf.length = wpabuf_len(resp);
+ respBuf.value = (void *)wpabuf_head(resp);
+
tmpMajor = duplicateBuffer(&tmpMinor, &respBuf, outputToken);
if (GSS_ERROR(tmpMajor)) {
major = tmpMajor;
return major;
}
-#if 0
-static OM_uint32
-eapGssSmInitKeyTransport(OM_uint32 *minor,
- gss_cred_id_t cred,
- gss_ctx_id_t ctx,
- gss_name_t target,
- gss_OID mech,
- OM_uint32 reqFlags,
- OM_uint32 timeReq,
- gss_channel_bindings_t chanBindings,
- gss_buffer_t inputToken,
- gss_buffer_t outputToken)
-{
- GSSEAP_NOT_IMPLEMENTED;
-}
-
-static OM_uint32
-eapGssSmInitSecureAssoc(OM_uint32 *minor,
- gss_cred_id_t cred,
- gss_ctx_id_t ctx,
- gss_name_t target,
- gss_OID mech,
- OM_uint32 reqFlags,
- OM_uint32 timeReq,
- gss_channel_bindings_t chanBindings,
- gss_buffer_t inputToken,
- gss_buffer_t outputToken)
-{
- GSSEAP_NOT_IMPLEMENTED;
-}
-#endif
-
static OM_uint32
eapGssSmInitGssChannelBindings(OM_uint32 *minor,
gss_cred_id_t cred,
gss_buffer_t inputToken,
gss_buffer_t outputToken)
{
- OM_uint32 major, tmpMinor;
+ OM_uint32 major;
gss_iov_buffer_desc iov[2];
gss_buffer_desc buf;
gss_buffer_t,
gss_buffer_t);
} eapGssInitiatorSm[] = {
+ { TOK_TYPE_NONE, TOK_TYPE_EAP_RESP, eapGssSmInitIdentity },
{ TOK_TYPE_EAP_REQ, TOK_TYPE_EAP_RESP, eapGssSmInitAuthenticate },
-#if 0
- { TOK_TYPE_EAP_REQ, TOK_TYPE_EAP_RESP, eapGssSmInitKeyTransport },
- { TOK_TYPE_EAP_REQ, TOK_TYPE_EAP_RESP, eapGssSmInitSecureAssoc },
-#endif
{ TOK_TYPE_NONE, TOK_TYPE_GSS_CB, eapGssSmInitGssChannelBindings },
{ TOK_TYPE_NONE, TOK_TYPE_NONE, eapGssSmInitEstablished },
};
GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM
GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM
GSS_EAP_NT_PRINCIPAL_NAME
+GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE
gssspi_acquire_cred_with_password
#include "gssapiP_eap.h"
+static OM_uint32
+setCredRadiusConfigFile(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ const gss_OID oid,
+ const gss_buffer_t buffer)
+{
+ OM_uint32 major;
+ gss_buffer_desc configFileBuffer = GSS_C_EMPTY_BUFFER;
+
+ if (buffer != GSS_C_NO_BUFFER && buffer->length != 0) {
+ major = duplicateBuffer(minor, buffer, &configFileBuffer);
+ if (GSS_ERROR(major))
+ return major;
+ }
+
+ if (cred->radiusConfigFile != NULL)
+ free(cred->radiusConfigFile);
+
+ cred->radiusConfigFile = (char *)configFileBuffer.value;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
static struct {
gss_OID_desc oid;
- OM_uint32 (*setOption)(OM_uint32 *, gss_cred_id_t *pCred,
+ OM_uint32 (*setOption)(OM_uint32 *, gss_cred_id_t cred,
const gss_OID, const gss_buffer_t);
} setCredOps[] = {
+ /* 1.3.6.1.4.1.5322.21.3.3.1 */
+ {
+ { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x15\x03\x03\x01" },
+ setCredRadiusConfigFile,
+ },
};
+gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE = &setCredOps[0].oid;
+
OM_uint32
gssspi_set_cred_option(OM_uint32 *minor,
gss_cred_id_t cred,
for (i = 0; i < sizeof(setCredOps) / sizeof(setCredOps[0]); i++) {
if (oidEqual(&setCredOps[i].oid, desired_object)) {
- major = (*setCredOps[i].setOption)(minor, &cred,
+ major = (*setCredOps[i].setOption)(minor, cred,
desired_object, value);
break;
}
return GSS_S_FAILURE;
}
- ctx->state = EAP_STATE_AUTHENTICATE;
+ ctx->state = EAP_STATE_IDENTITY;
/*
* Integrity, confidentiality, sequencing and replay detection are
static void
releaseAcceptorContext(struct gss_eap_acceptor_ctx *ctx)
{
-#ifdef BUILTIN_EAP
- eap_server_sm_deinit(ctx->eap);
- if (ctx->tlsContext != NULL)
- tls_deinit(ctx->tlsContext);
-#endif
+ OM_uint32 tmpMinor;
+
+ if (ctx->avps != NULL)
+ rc_avpair_free(ctx->avps);
+ if (ctx->radHandle != NULL)
+ rc_config_free(ctx->radHandle);
+
+ gss_release_buffer(&tmpMinor, &ctx->state);
}
OM_uint32
GSSEAP_FREE(cred->password.value);
}
+ if (cred->radiusConfigFile != NULL)
+ free(cred->radiusConfigFile);
+
GSSEAP_MUTEX_DESTROY(&cred->mutex);
memset(cred, 0, sizeof(*cred));
GSSEAP_FREE(cred);
OM_uint32 major, tmpMinor;
gss_cred_id_t cred;
+ /* XXX TODO validate with changed set_cred_option API */
*pCred = GSS_C_NO_CREDENTIAL;
major = gssEapAllocCred(minor, &cred);
unsigned char constant[4 + sizeof("rfc4121-gss-eap") - 1], *p;
ssize_t i, remain;
+ assert(encryptionType != ENCTYPE_NULL);
+
memset(pKey, 0, sizeof(*pKey));
GSSEAP_KRB_INIT(&krbContext);
t.data = NULL;
t.length = 0;
+ prfOut.data = NULL;
+ prfOut.length = 0;
+
code = krb5_c_keylengths(krbContext, encryptionType,
&randomLength, &keyLength);
if (code != 0)
GSSEAP_KRB_INIT(&krbContext);
- major = bufferToString(minor, nameBuffer, &nameString);
- if (GSS_ERROR(major))
- return major;
+ if (nameBuffer == GSS_C_NO_BUFFER) {
+ *minor = krb5_copy_principal(krbContext,
+ krb5_anonymous_principal(), &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;
+ *minor = krb5_parse_name(krbContext, nameString, &krbPrinc);
+ if (*minor != 0) {
+ GSSEAP_FREE(nameString);
+ return GSS_S_FAILURE;
+ }
}
major = krbPrincipalToName(minor, &krbPrinc, pName);
#include "gssapiP_eap.h"
+VALUE_PAIR *
+gss_eap_radius_attr_provider::copyAvps(const VALUE_PAIR *src)
+{
+ const VALUE_PAIR *vp;
+ VALUE_PAIR *dst = NULL, **pDst = &dst;
+
+ for (vp = src; vp != NULL; vp = vp->next) {
+ VALUE_PAIR *vp2;
+
+ vp2 = (VALUE_PAIR *)GSSEAP_CALLOC(1, sizeof(*vp2));
+ if (vp2 == NULL) {
+ rc_avpair_free(dst);
+ return NULL;
+ }
+ memcpy(vp2, vp, sizeof(*vp));
+ vp2->next = NULL;
+ *pDst = vp2;
+ pDst = &vp2->next;
+ }
+
+ return dst;
+}
+
gss_eap_radius_attr_provider::gss_eap_radius_attr_provider(void)
{
+ m_rh = NULL;
+ m_avps = NULL;
m_authenticated = false;
}
gss_eap_radius_attr_provider::~gss_eap_radius_attr_provider(void)
{
+ if (m_rh != NULL)
+ rc_config_free(m_rh);
+ if (m_avps != NULL)
+ rc_avpair_free(m_avps);
+}
+
+bool
+gss_eap_radius_attr_provider::initFromGssCred(const gss_cred_id_t cred)
+{
+ OM_uint32 minor;
+
+ return !GSS_ERROR(gssEapRadiusAllocHandle(&minor, cred, &m_rh));
}
bool
gss_eap_radius_attr_provider::initFromExistingContext(const gss_eap_attr_ctx *manager,
const gss_eap_attr_provider *ctx)
{
+ const gss_eap_radius_attr_provider *radius;
+
if (!gss_eap_attr_provider::initFromExistingContext(manager, ctx))
return false;
+ if (!initFromGssCred(GSS_C_NO_CREDENTIAL))
+ return false;
+
+ radius = static_cast<const gss_eap_radius_attr_provider *>(ctx);
+ if (radius->m_avps != NULL) {
+ m_avps = copyAvps(radius->getAvps());
+ }
+
return true;
}
if (!gss_eap_attr_provider::initFromGssContext(manager, gssCred, gssCtx))
return false;
+ if (!initFromGssCred(gssCred))
+ return false;
+
+ if (gssCtx != GSS_C_NO_CONTEXT) {
+ if (gssCtx->acceptorCtx.avps != NULL) {
+ m_avps = copyAvps(gssCtx->acceptorCtx.avps);
+ if (m_avps == NULL)
+ return false;
+ }
+ }
+
return true;
}
+static bool
+alreadyAddedAttributeP(std::vector <std::string> &attrs, VALUE_PAIR *vp)
+{
+ for (std::vector<std::string>::const_iterator a = attrs.begin();
+ a != attrs.end();
+ ++a) {
+ if (strcmp(vp->name, (*a).c_str()) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+static bool
+isSecretAttributeP(int attrid, int vendor)
+{
+ bool ret = false;
+
+ switch (vendor) {
+ case RADIUS_VENDOR_ID_MICROSOFT:
+ switch (attrid) {
+ case RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY:
+ case RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY:
+ ret = true;
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+
+ return ret;
+}
+
bool
gss_eap_radius_attr_provider::getAttributeTypes(gss_eap_attr_enumeration_cb addAttribute, void *data) const
{
+ VALUE_PAIR *vp;
+ std::vector <std::string> seen;
+
+ for (vp = m_avps; vp != NULL; vp = vp->next) {
+ gss_buffer_desc attribute;
+
+ if (isSecretAttributeP(ATTRID(vp->attribute), VENDOR(vp->attribute)))
+ continue;
+
+ if (alreadyAddedAttributeP(seen, vp))
+ continue;
+
+ attribute.value = (void *)vp->name;
+ attribute.length = strlen(vp->name);
+
+ if (!addAttribute(this, &attribute, data))
+ return false;
+
+ seen.push_back(std::string(vp->name));
+ }
+
return true;
}
gss_buffer_t display_value,
int *more) const
{
- return false;
+ OM_uint32 tmpMinor;
+ gss_buffer_desc strAttr = GSS_C_EMPTY_BUFFER;
+ DICT_ATTR *d;
+ int attrid;
+ char *s;
+
+ /* XXX vendor */
+
+ duplicateBuffer(*attr, &strAttr);
+ s = (char *)strAttr.value;
+
+ if (isdigit(((char *)strAttr.value)[0])) {
+ attrid = strtoul(s, NULL, 10);
+ } else {
+ d = rc_dict_findattr(m_rh, (char *)s);
+ if (d == NULL) {
+ gss_release_buffer(&tmpMinor, &strAttr);
+ return false;
+ }
+ attrid = d->value;
+ }
+
+ gss_release_buffer(&tmpMinor, &strAttr);
+
+ return getAttribute(attrid, authenticated, complete,
+ value, display_value, more);
+}
+
+static bool
+isPrintableAttributeP(VALUE_PAIR *vp)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof(vp->strvalue); i++) {
+ if (!isprint(vp->strvalue[i]))
+ return false;
+ }
+
+ return true;
}
bool
-gss_eap_radius_attr_provider::getAttribute(unsigned int attr,
+gss_eap_radius_attr_provider::getAttribute(int attrid,
+ int vendor,
int *authenticated,
int *complete,
gss_buffer_t value,
gss_buffer_t display_value,
int *more) const
{
- return false;
+ OM_uint32 tmpMinor;
+ VALUE_PAIR *vp;
+ int i = *more;
+ int max = 0;
+ char name[NAME_LENGTH + 1];
+ char displayString[AUTH_STRING_LEN + 1];
+ gss_buffer_desc valueBuf = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc displayBuf = GSS_C_EMPTY_BUFFER;
+
+ *more = 0;
+
+ if (isSecretAttributeP(attrid, vendor))
+ return false;
+
+ vp = rc_avpair_get(m_avps, attrid, vendor);
+ if (vp == NULL)
+ return false;
+
+ if (i == -1)
+ i = 0;
+
+ do {
+ if (i == max)
+ break;
+
+ max++;
+ } while ((vp = rc_avpair_get(vp->next, attrid, vendor)) != NULL);
+
+ if (i > max)
+ return false;
+
+ if (vp->type == PW_TYPE_STRING) {
+ valueBuf.value = (void *)vp->strvalue;
+ valueBuf.length = vp->lvalue;
+ } else {
+ valueBuf.value = (void *)&vp->lvalue;
+ valueBuf.length = 4;
+ }
+
+ if (value != GSS_C_NO_BUFFER)
+ duplicateBuffer(valueBuf, value);
+
+ if (display_value != GSS_C_NO_BUFFER &&
+ isPrintableAttributeP(vp)) {
+ if (rc_avpair_tostr(m_rh, vp, name, NAME_LENGTH,
+ displayString, AUTH_STRING_LEN) != 0) {
+ gss_release_buffer(&tmpMinor, value);
+ return false;
+ }
+
+ displayBuf.value = (void *)displayString;
+ displayBuf.length = strlen(displayString);
+
+ duplicateBuffer(displayBuf, display_value);
+ }
+
+ if (authenticated != NULL)
+ *authenticated = m_authenticated;
+ if (complete != NULL)
+ *complete = true;
+
+ if (max > i)
+ *more = i;
+
+ return true;
+}
+
+bool
+gss_eap_radius_attr_provider::getAttribute(int attrid,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more) const
+{
+
+ return getAttribute(ATTRID(attrid), VENDOR(attrid),
+ authenticated, complete,
+ value, display_value, more);
}
gss_any_t
gss_eap_radius_attr_provider::mapToAny(int authenticated,
gss_buffer_t type_id) const
{
- return (gss_any_t)NULL;
+ if (authenticated && !m_authenticated)
+ return (gss_any_t)NULL;
+
+ return (gss_any_t)copyAvps(m_avps);
}
void
gss_eap_radius_attr_provider::releaseAnyNameMapping(gss_buffer_t type_id,
gss_any_t input) const
{
+ rc_avpair_free((VALUE_PAIR *)input);
}
void
if (!gss_eap_attr_provider::initFromBuffer(ctx, buffer))
return false;
+ if (!initFromGssCred(GSS_C_NO_CREDENTIAL))
+ return false;
+
return true;
}
}
OM_uint32
+addAvpFromBuffer(OM_uint32 *minor,
+ rc_handle *rh,
+ VALUE_PAIR **vp,
+ int type,
+ gss_buffer_t buffer)
+{
+ if (rc_avpair_add(rh, vp, type, buffer->value, buffer->length, 0) == NULL) {
+ return GSS_S_FAILURE;
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+getBufferFromAvps(OM_uint32 *minor,
+ VALUE_PAIR *vps,
+ int type,
+ gss_buffer_t buffer,
+ int concat)
+{
+ VALUE_PAIR *vp;
+ unsigned char *p;
+
+ buffer->length = 0;
+ buffer->value = NULL;
+
+ vp = rc_avpair_get(vps, type, 0);
+ if (vp == NULL)
+ return GSS_S_UNAVAILABLE;
+
+ do {
+ buffer->length += vp->lvalue;
+ } while (concat && (vp = rc_avpair_get(vp->next, type, 0)) != NULL);
+
+ buffer->value = GSSEAP_MALLOC(buffer->length);
+ if (buffer->value == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ p = (unsigned char *)buffer->value;
+
+ for (vp = rc_avpair_get(vps, type, 0);
+ concat && vp != NULL;
+ vp = rc_avpair_get(vp->next, type, 0)) {
+ memcpy(p, vp->strvalue, vp->lvalue);
+ p += vp->lvalue;
+ }
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
gssEapRadiusAttrProviderInit(OM_uint32 *minor)
{
return gss_eap_radius_attr_provider::init()
gss_eap_radius_attr_provider::finalize();
return GSS_S_COMPLETE;
}
+
+OM_uint32
+gssEapRadiusAllocHandle(OM_uint32 *minor,
+ const gss_cred_id_t cred,
+ rc_handle **pHandle)
+{
+ rc_handle *rh;
+ const char *config = RC_CONFIG_FILE;
+
+ *pHandle = NULL;
+
+ if (cred != GSS_C_NO_CREDENTIAL && cred->radiusConfigFile != NULL)
+ config = cred->radiusConfigFile;
+
+ rh = rc_read_config((char *)config);
+ if (rh == NULL) {
+ *minor = errno;
+ rc_config_free(rh);
+ return GSS_S_FAILURE;
+ }
+
+ if (rc_read_dictionary(rh, rc_conf_str(rh, (char *)"dictionary")) != 0) {
+ *minor = errno;
+ return GSS_S_FAILURE;
+ }
+
+ *pHandle = rh;
+ return GSS_S_COMPLETE;
+}
bool initFromBuffer(const gss_eap_attr_ctx *ctx,
const gss_buffer_t buffer);
- bool getAttribute(unsigned int attribute,
+ bool getAttribute(int attribute,
+ int *authenticated,
+ int *complete,
+ gss_buffer_t value,
+ gss_buffer_t display_value,
+ int *more) const;
+ bool getAttribute(int attribute,
+ int vendor,
int *authenticated,
int *complete,
gss_buffer_t value,
static gss_eap_attr_provider *createAttrContext(void);
private:
+ bool initFromGssCred(const gss_cred_id_t cred);
+ static VALUE_PAIR *copyAvps(const VALUE_PAIR *in);
+ const VALUE_PAIR *getAvps(void) const {
+ return m_avps;
+ }
+
+ rc_handle *m_rh;
+ VALUE_PAIR *m_avps;
bool m_authenticated;
};
extern "C" {
#endif
+OM_uint32
+addAvpFromBuffer(OM_uint32 *minor,
+ rc_handle *rh,
+ VALUE_PAIR **vp,
+ int type,
+ gss_buffer_t buffer);
+
+OM_uint32
+getBufferFromAvps(OM_uint32 *minor,
+ VALUE_PAIR *vps,
+ int type,
+ gss_buffer_t buffer,
+ int concat);
+
OM_uint32 gssEapRadiusAttrProviderInit(OM_uint32 *minor);
OM_uint32 gssEapRadiusAttrProviderFinalize(OM_uint32 *minor);
+OM_uint32
+gssEapRadiusAllocHandle(OM_uint32 *minor,
+ const gss_cred_id_t cred,
+ rc_handle **pHandle);
+
+#define RC_CONFIG_FILE SYSCONFDIR "/radiusclient/radiusclient.conf"
+
+/* RFC 2548 - Microsoft Vendor-specific RADIUS Attributes */
+#define RADIUS_VENDOR_ID_MICROSOFT 311
+
+enum { RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY = 16,
+ RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY = 17
+};
+
#ifdef __cplusplus
}
#endif
gss_eap_saml_assertion_provider::mapToAny(int authenticated,
gss_buffer_t type_id) const
{
+ if (authenticated && !m_authenticated)
+ return (gss_any_t)NULL;
+
return (gss_any_t)m_assertion;
}
* limitations under the License.
*/
-#include "gssapiP_eap.h"
-
#include <shibsp/exceptions.h>
#include <shibsp/attribute/SimpleAttribute.h>
#include <shibsp/handler/AssertionConsumerService.h>
#include <shibresolver/resolver.h>
+#include "gssapiP_eap.h"
+
using namespace shibsp;
using namespace shibresolver;
using namespace opensaml::saml2md;
{
gss_any_t output;
+ if (authenticated && !m_authenticated)
+ return (gss_any_t)NULL;
+
vector <Attribute *>v = duplicateAttributes(m_attributes);
output = (gss_any_t)new vector <Attribute *>(v);