Support for libradius
authorLuke Howard <lukeh@padl.com>
Mon, 20 Sep 2010 17:39:39 +0000 (19:39 +0200)
committerLuke Howard <lukeh@padl.com>
Mon, 20 Sep 2010 17:39:39 +0000 (19:39 +0200)
Makefile.am
accept_sec_context.c
gssapiP_eap.h
init_sec_context.c
util_context.c
util_name.c

index 336354a..aa22204 100644 (file)
@@ -4,7 +4,7 @@ gssdir = $(libdir)/gss
 
 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 \
@@ -13,7 +13,7 @@ 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                    \
index 6353eea..d54fb2a 100644 (file)
 
 #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 */
-
-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} */
-};
-
-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;
-};
-
-#define eapol_callbacks     SERVER_eapol_callbacks
-
-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);
-};
-
-#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;
-};
-
-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);
-
-#include <eap_server/eap_i.h>
+#define RC_CONFIG_FILE      SYSCONFDIR "/radiusclient/radiusclient.conf"
 
+/*
+ * Mark a context as ready for cryptographic operations
+ */
 static OM_uint32
-initTls(OM_uint32 *minor,
-        gss_ctx_id_t ctx)
+acceptReady(OM_uint32 *minor, gss_ctx_id_t ctx)
 {
-    struct tls_config tconf;
-    struct tls_connection_params tparams;
-
-    memset(&tconf, 0, sizeof(tconf));
-    ctx->acceptorCtx.tlsContext = tls_init(&tconf);
-    if (ctx->acceptorCtx.tlsContext == NULL)
-        return GSS_S_FAILURE;
-
-    memset(&tparams, 0, sizeof(tparams));
-    tparams.ca_cert = "ca.pem";
-    tparams.client_cert = "server.pem";
-    tparams.private_key = "server-key.pem";
+    OM_uint32 major;
+    VALUE_PAIR *vp;
+    gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
 
-    if (tls_global_set_params(ctx->acceptorCtx.tlsContext, &tparams)) {
-        return GSS_S_FAILURE;
-    }
+    /* Cache encryption type derived from selected mechanism OID */
+    major = gssEapOidToEnctype(minor, ctx->mechanismUsed,
+                               &ctx->encryptionType);
+    if (GSS_ERROR(major))
+        return major;
 
-    if (tls_global_set_verify(ctx->acceptorCtx.tlsContext, 0)) {
-        return GSS_S_FAILURE;
+    vp = rc_avpair_get(ctx->acceptorCtx.avps, PW_USER_NAME, 0);
+    if (vp != NULL) {
+        nameBuf.length = vp->lvalue;
+        nameBuf.value = vp->strvalue;
+    } else {
+        ctx->gssFlags |= GSS_C_ANON_FLAG;
     }
 
-    return GSS_S_COMPLETE;
-}
-
-static int
-serverGetEapUser(void *ctx,
-                 const unsigned char *identity,
-                 size_t identityLength,
-                 int phase2,
-                 struct eap_user *user)
-{
-    gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx;
-    OM_uint32 major, minor;
-    gss_buffer_desc buf;
-
-    memset(user, 0, sizeof(*user));
+    major = gssEapImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
+                             &ctx->initiatorName);
+    if (GSS_ERROR(major))
+        return major;
 
-    buf.length = identityLength;
-    buf.value = (void *)identity;
+    vp = rc_avpair_get(ctx->acceptorCtx.avps, PW_MSCHAP2_SUCCESS, 0);
+    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;
 
-    if (phase2 == 0) {
-        user->methods[0].vendor = EAP_VENDOR_IETF;
-        user->methods[0].method = EAP_TYPE_PEAP;
-        return 0;
+        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 = gssEapImportName(&minor, &buf, GSS_C_NT_USER_NAME,
-                             &gssCtx->initiatorName);
+    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 -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(" ");
-    user->password_len = 1;
-
-    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;
+    return GSS_S_COMPLETE;
 }
 
 static OM_uint32
@@ -240,30 +106,26 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor,
                            gss_buffer_t outputToken)
 {
     OM_uint32 major;
-    OM_uint32 tmpMinor, tmpMajor;
+    OM_uint32 service = PW_AUTHENTICATE_ONLY;
     int code;
-    struct wpabuf respData;
-    static struct eapol_callbacks cb = { serverGetEapUser, serverGetEapReqIdText };
-    if (ctx->acceptorCtx.eap == NULL) {
-        struct eap_config eapConfig;
-
-        major = initTls(minor, ctx);
-        if (GSS_ERROR(major))
+    VALUE_PAIR *send = NULL;
+    VALUE_PAIR *received = NULL;
+    rc_handle *rh = ctx->acceptorCtx.radHandle;
+    char msgBuffer[4096];
+
+    if (rh == NULL) {
+        rh = ctx->acceptorCtx.radHandle = rc_read_config(RC_CONFIG_FILE);
+        if (rh == NULL) {
+            *minor = errno;
+            major = GSS_S_FAILURE;
             goto cleanup;
+        }
 
-        memset(&eapConfig, 0, sizeof(eapConfig));
-        eapConfig.eap_server = 1;
-        eapConfig.ssl_ctx = ctx->acceptorCtx.tlsContext;
-
-        ctx->acceptorCtx.eap = eap_server_sm_init(ctx, &cb, &eapConfig);
-        if (ctx->acceptorCtx.eap == NULL) {
+        if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0) {
+            *minor = errno;
             major = GSS_S_FAILURE;
             goto cleanup;
         }
-
-        ctx->acceptorCtx.eapPolInterface = eap_get_interface(ctx->acceptorCtx.eap);
-        ctx->acceptorCtx.eapPolInterface->portEnabled = TRUE;
-        ctx->acceptorCtx.eapPolInterface->eapRestart = TRUE;
     }
 
     if (ctx->acceptorName == GSS_C_NO_NAME &&
@@ -274,66 +136,64 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor,
             goto cleanup;
     }
 
-    wpabuf_set(&respData, inputToken->value, inputToken->length);
-    ctx->acceptorCtx.eapPolInterface->eapRespData = &respData;
-    ctx->acceptorCtx.eapPolInterface->eapResp = TRUE;
+    if (rc_avpair_add(rh, &send, PW_EAP_MESSAGE,
+                      inputToken->value, inputToken->length, 0) == NULL) {
+        *minor = ENOMEM;
+        major = GSS_S_FAILURE;
+        goto cleanup;
+    }
 
-    code = eap_server_sm_step(ctx->acceptorCtx.eap);
+    if (rc_avpair_add(rh, &send, PW_SERVICE_TYPE, &service, -1, 0) == NULL) {
+        *minor = ENOMEM;
+        major = GSS_S_FAILURE;
+        goto cleanup;
+    }
 
-    if (ctx->acceptorCtx.eapPolInterface->eapReq) {
-        ctx->acceptorCtx.eapPolInterface->eapReq = 0;
-        major = GSS_S_CONTINUE_NEEDED;
+    code = rc_auth(rh, 0, send, &received, msgBuffer);
+    if (code != 0) {
+        *minor = errno;
+        major = GSS_S_UNAVAILABLE;
+        goto cleanup;
     }
 
-    if (ctx->acceptorCtx.eapPolInterface->eapSuccess) {
-        ctx->acceptorCtx.eapPolInterface->eapSuccess = 0;
-        major = acceptReady(minor, ctx);
+    if (code == OK_RC || code == PW_ACCESS_CHALLENGE) {
+        VALUE_PAIR *eapResponse;
+        gss_buffer_desc eapBuf = GSS_C_EMPTY_BUFFER;
+
+        eapResponse = rc_avpair_get(received, PW_EAP_MESSAGE, 0);
+        if (eapResponse != NULL) {
+            eapBuf.length = eapResponse->lvalue;
+            eapBuf.value = eapResponse->strvalue;
+        }
+
+        major = duplicateBuffer(minor, &eapBuf, outputToken);
         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) {
+    } else {
         major = GSS_S_FAILURE;
+        goto cleanup;
     }
 
-    if (ctx->acceptorCtx.eapPolInterface->eapReqData != NULL) {
-        gss_buffer_desc buf;
+    if (code == OK_RC) {
+        ctx->acceptorCtx.avps = received;
+        received = NULL;
 
-        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;
+        major = acceptReady(minor, ctx);
+        if (GSS_ERROR(major))
             goto cleanup;
-        }
+
+        ctx->state = EAP_STATE_GSS_CHANNEL_BINDINGS;
+        major = GSS_S_CONTINUE_NEEDED;
     }
 
 cleanup:
-    ctx->acceptorCtx.eapPolInterface->eapRespData = NULL;
-
-    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;
+    if (received != NULL)
+        rc_avpair_free(received);
 
-cleanup:
     return major;
 }
-#endif /* BUILTIN_EAP */
 
 static OM_uint32
 eapGssSmAcceptGssChannelBindings(OM_uint32 *minor,
@@ -530,49 +390,3 @@ cleanup:
     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;
-}
index bb61a01..eef4206 100644 (file)
@@ -33,8 +33,6 @@
 #ifndef _GSSAPIP_EAP_H_
 #define _GSSAPIP_EAP_H_ 1
 
-#define BUILTIN_EAP 1
-
 #include <assert.h>
 #include <string.h>
 #include <errno.h>
 #include <wpabuf.h>
 #endif
 
+#ifdef __cplusplus
+struct rc_conf;
+typedef struct rc_conf rc_handle;
+
+struct value_pair;
+typedef struct value_pair VALUE_PAIR;
+#else
+#include <freeradius-client.h>
+#include <freeradius/radius.h>
+#endif
+
 /* These name flags are informative and not actually used by anything yet */
 #define NAME_FLAG_NAI                       0x00000001
 #define NAME_FLAG_SERVICE                   0x00000002
@@ -127,11 +136,8 @@ struct gss_eap_initiator_ctx {
 };
 
 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;
+    VALUE_PAIR *avps;
 };
 
 struct gss_ctx_id_struct {
index 8b5a0e2..9ec5e66 100644 (file)
@@ -375,7 +375,9 @@ eapGssSmInitAuthenticate(OM_uint32 *minor,
         ctx->flags &= ~(CTX_FLAG_EAP_SUCCESS);
         major = GSS_S_CONTINUE_NEEDED;
         ctx->state = EAP_STATE_GSS_CHANNEL_BINDINGS;
-    } else if ((ctx->flags & CTX_FLAG_EAP_FAIL) || code == 0) {
+    } else if (ctx->flags & CTX_FLAG_EAP_FAIL) {
+        major = GSS_S_DEFECTIVE_CREDENTIAL;
+    } else if (code == 0) {
         major = GSS_S_FAILURE;
     }
 
index 13372ea..99c9405 100644 (file)
@@ -82,11 +82,10 @@ releaseInitiatorContext(struct gss_eap_initiator_ctx *ctx)
 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
+    if (ctx->avps != NULL)
+        rc_avpair_free(ctx->avps);
+    if (ctx->radHandle != NULL)
+        rc_config_free(ctx->radHandle);
 }
 
 OM_uint32
index d45b60f..e64ebdd 100644 (file)
@@ -194,14 +194,21 @@ importUserName(OM_uint32 *minor,
 
     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);