Support for libradius
[mech_eap.git] / 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;
-}