From: Phil Mayers
Date: Fri, 8 Oct 2010 10:01:40 +0000 (+0200)
Subject: Added SoH functionality to the PEAP module
X-Git-Tag: release_3_0_0_beta0~1205
X-Git-Url: http://www.project-moonshot.org/gitweb/?p=freeradius.git;a=commitdiff_plain;h=2023c9f3d4df8c7160485b36dcfd23faf7cfca80
Added SoH functionality to the PEAP module
---
diff --git a/raddb/eap.conf b/raddb/eap.conf
index b34acbe..998b1b5 100644
--- a/raddb/eap.conf
+++ b/raddb/eap.conf
@@ -538,6 +538,18 @@
# outer requests.
#
virtual_server = "inner-tunnel"
+
+ # This option enables support for MS-SoH
+ # see doc/SoH.txt for more info.
+ # It is disabled by default.
+ #
+ # soh = yes
+
+ #
+ # The SoH reply will be turned into a request which
+ # can be sent to a specific virtual server:
+ #
+ # soh_virtual_server = "soh-server"
}
#
diff --git a/src/modules/rlm_eap/types/rlm_eap_peap/eap_peap.h b/src/modules/rlm_eap/types/rlm_eap_peap/eap_peap.h
index d09fb24..3ad3a33 100644
--- a/src/modules/rlm_eap/types/rlm_eap_peap/eap_peap.h
+++ b/src/modules/rlm_eap/types/rlm_eap_peap/eap_peap.h
@@ -27,6 +27,7 @@
RCSIDH(eap_peap_h, "$Id$")
#include "eap_tls.h"
+#include
typedef struct peap_tunnel_t {
VALUE_PAIR *username;
@@ -39,6 +40,9 @@ typedef struct peap_tunnel_t {
int use_tunneled_reply;
int proxy_tunneled_request_as_eap;
const char *virtual_server;
+ int soh;
+ const char *soh_virtual_server;
+ VALUE_PAIR *soh_reply_vps;
int session_resumption_state;
} peap_tunnel_t;
@@ -49,6 +53,7 @@ typedef struct peap_tunnel_t {
#define PEAP_STATUS_INNER_IDENTITY_REQ_SENT 4
#define PEAP_STATUS_PHASE2_INIT 5
#define PEAP_STATUS_PHASE2 6
+#define PEAP_STATUS_WAIT_FOR_SOH_RESPONSE 7
#define PEAP_RESUMPTION_NO (0)
#define PEAP_RESUMPTION_YES (1)
diff --git a/src/modules/rlm_eap/types/rlm_eap_peap/peap.c b/src/modules/rlm_eap/types/rlm_eap_peap/peap.c
index ff13ef3..9d4d81c 100644
--- a/src/modules/rlm_eap/types/rlm_eap_peap/peap.c
+++ b/src/modules/rlm_eap/types/rlm_eap_peap/peap.c
@@ -117,6 +117,92 @@ static int eappeap_identity(EAP_HANDLER *handler, tls_session_t *tls_session)
return 1;
}
+/*
+ * Send an MS SoH request
+ */
+static int eappeap_soh(EAP_HANDLER *handler, tls_session_t *tls_session)
+{
+ uint8_t tlv_packet[20];
+
+ tlv_packet[0] = 254; /* extended type */
+
+ tlv_packet[1] = 0;
+ tlv_packet[2] = 0x01; /* ms vendor */
+ tlv_packet[3] = 0x37;
+
+ tlv_packet[4] = 0; /* ms soh eap */
+ tlv_packet[5] = 0;
+ tlv_packet[6] = 0;
+ tlv_packet[7] = 0x21;
+
+ tlv_packet[8] = 0; /* vendor-spec tlv */
+ tlv_packet[9] = 7;
+
+ tlv_packet[10] = 0;
+ tlv_packet[11] = 8; /* payload len */
+
+ tlv_packet[12] = 0; /* ms vendor */
+ tlv_packet[13] = 0;
+ tlv_packet[14] = 0x01;
+ tlv_packet[15] = 0x37;
+
+ tlv_packet[16] = 0;
+ tlv_packet[17] = 2;
+ tlv_packet[18] = 0;
+ tlv_packet[19] = 0;
+
+ (tls_session->record_plus)(&tls_session->clean_in, tlv_packet, 20);
+ tls_handshake_send(handler->request, tls_session);
+ return 1;
+}
+
+static VALUE_PAIR* eapsoh_verify(REQUEST *request, const uint8_t *data, unsigned int data_len) {
+
+ VALUE_PAIR *vp;
+ uint8_t eap_type_base;
+ uint32_t eap_vendor;
+ uint32_t eap_type;
+ int rv;
+
+ vp = pairmake("SoH-Supported", "no", T_OP_EQ);
+ if (data && data[0] == PW_EAP_NAK) {
+ RDEBUG("SoH - client NAKed");
+ goto done;
+ }
+
+ if (!data || data_len < 8) {
+ RDEBUG("SoH - eap payload too short");
+ goto done;
+ }
+
+ eap_type_base = *data++;
+ if (eap_type_base != 254) {
+ RDEBUG("SoH - response is not extended EAP: %i", eap_type_base);
+ goto done;
+ }
+
+ eap_vendor = soh_pull_be_24(data); data += 3;
+ if (eap_vendor != 0x137) {
+ RDEBUG("SoH - extended eap vendor %08x is not Microsoft", eap_vendor);
+ goto done;
+ }
+
+ eap_type = soh_pull_be_32(data); data += 4;
+ if (eap_type != 0x21) {
+ RDEBUG("SoH - response eap type %08x is not EAP-SoH", eap_type);
+ goto done;
+ }
+
+
+ rv = soh_verify(request, vp, data, data_len - 8);
+ if (rv<0) {
+ RDEBUG("SoH - error decoding payload");
+ } else {
+ vp->vp_integer = 1;
+ }
+done:
+ return vp;
+}
/*
* Verify the tunneled EAP message.
@@ -601,6 +687,8 @@ static const char *peap_state(peap_tunnel_t *t)
switch (t->status) {
case PEAP_STATUS_TUNNEL_ESTABLISHED:
return "TUNNEL ESTABLISHED";
+ case PEAP_STATUS_WAIT_FOR_SOH_RESPONSE:
+ return "WAITING FOR SOH RESPONSE";
case PEAP_STATUS_INNER_IDENTITY_REQ_SENT:
return "WAITING FOR INNER IDENTITY";
case PEAP_STATUS_SENT_TLV_SUCCESS:
@@ -675,7 +763,12 @@ int eappeap_process(EAP_HANDLER *handler, tls_session_t *tls_session)
if (SSL_session_reused(tls_session->ssl)) {
RDEBUG2("Skipping Phase2 because of session resumption");
t->session_resumption_state = PEAP_RESUMPTION_YES;
-
+ if (t->soh) {
+ t->status = PEAP_STATUS_WAIT_FOR_SOH_RESPONSE;
+ RDEBUG2("Requesting SoH from client");
+ eappeap_soh(handler, tls_session);
+ return RLM_MODULE_HANDLED;
+ }
/* we're good, send success TLV */
t->status = PEAP_STATUS_SENT_TLV_SUCCESS;
eappeap_success(handler, tls_session);
@@ -710,10 +803,54 @@ int eappeap_process(EAP_HANDLER *handler, tls_session_t *tls_session)
t->username->length = data_len - 1;
t->username->vp_strvalue[t->username->length] = 0;
RDEBUG("Got inner identity '%s'", t->username->vp_strvalue);
-
+ if (t->soh) {
+ t->status = PEAP_STATUS_WAIT_FOR_SOH_RESPONSE;
+ RDEBUG2("Requesting SoH from client");
+ eappeap_soh(handler, tls_session);
+ return RLM_MODULE_HANDLED;
+ }
+ t->status = PEAP_STATUS_PHASE2_INIT;
+ break;
+
+ case PEAP_STATUS_WAIT_FOR_SOH_RESPONSE:
+ fake = request_alloc_fake(request);
+ rad_assert(fake->packet->vps == NULL);
+ fake->packet->vps = eapsoh_verify(request, data, data_len);
+ setup_fake_request(request, fake, t);
+
+ if (t->soh_virtual_server) {
+ fake->server = t->soh_virtual_server;
+ }
+ RDEBUG("Sending SoH request to server %s", fake->server ? fake->server : "NULL");
+ debug_pair_list(fake->packet->vps);
+ rad_authenticate(fake);
+ RDEBUG("Got SoH reply");
+ debug_pair_list(fake->reply->vps);
+
+ if (fake->reply->code != PW_AUTHENTICATION_ACK) {
+ RDEBUG2("SoH was rejected");
+ request_free(&fake);
+ t->status = PEAP_STATUS_SENT_TLV_FAILURE;
+ eappeap_failure(handler, tls_session);
+ return RLM_MODULE_HANDLED;
+ }
+
+ /* save the SoH VPs */
+ t->soh_reply_vps = fake->reply->vps;
+ fake->reply->vps = NULL;
+ request_free(&fake);
+
+ if (t->session_resumption_state == PEAP_RESUMPTION_YES) {
+ /* we're good, send success TLV */
+ t->status = PEAP_STATUS_SENT_TLV_SUCCESS;
+ eappeap_success(handler, tls_session);
+ return RLM_MODULE_HANDLED;
+ }
+
t->status = PEAP_STATUS_PHASE2_INIT;
break;
+
/*
* If we authenticated the user, then it's OK.
*/
diff --git a/src/modules/rlm_eap/types/rlm_eap_peap/rlm_eap_peap.c b/src/modules/rlm_eap/types/rlm_eap_peap/rlm_eap_peap.c
index 9b4ed41..cb460ac 100644
--- a/src/modules/rlm_eap/types/rlm_eap_peap/rlm_eap_peap.c
+++ b/src/modules/rlm_eap/types/rlm_eap_peap/rlm_eap_peap.c
@@ -58,6 +58,12 @@ typedef struct rlm_eap_peap_t {
* Virtual server for inner tunnel session.
*/
char *virtual_server;
+
+ /*
+ * Do we do SoH request?
+ */
+ int soh;
+ char *soh_virtual_server;
} rlm_eap_peap_t;
@@ -79,6 +85,12 @@ static CONF_PARSER module_config[] = {
{ "virtual_server", PW_TYPE_STRING_PTR,
offsetof(rlm_eap_peap_t, virtual_server), NULL, NULL },
+ { "soh", PW_TYPE_BOOLEAN,
+ offsetof(rlm_eap_peap_t, soh), NULL, "no" },
+
+ { "soh_virtual_server", PW_TYPE_STRING_PTR,
+ offsetof(rlm_eap_peap_t, soh_virtual_server), NULL, NULL },
+
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
@@ -146,6 +158,7 @@ static void peap_free(void *p)
pairfree(&t->username);
pairfree(&t->state);
pairfree(&t->accept_vps);
+ pairfree(&t->soh_reply_vps);
free(t);
}
@@ -168,6 +181,8 @@ static peap_tunnel_t *peap_alloc(rlm_eap_peap_t *inst)
t->proxy_tunneled_request_as_eap = inst->proxy_tunneled_request_as_eap;
#endif
t->virtual_server = inst->virtual_server;
+ t->soh = inst->soh;
+ t->soh_virtual_server = inst->soh_virtual_server;
t->session_resumption_state = PEAP_RESUMPTION_MAYBE;
return t;
@@ -273,6 +288,12 @@ static int eappeap_authenticate(void *arg, EAP_HANDLER *handler)
* our Access-Accept.
*/
peap = tls_session->opaque;
+ if (peap->soh_reply_vps) {
+ RDEBUG2("Using saved attributes from the SoH reply");
+ debug_pair_list(peap->soh_reply_vps);
+ pairadd(&handler->request->reply->vps, peap->soh_reply_vps);
+ peap->soh_reply_vps = NULL;
+ }
if (peap->accept_vps) {
RDEBUG2("Using saved attributes from the original Access-Accept");
debug_pair_list(peap->accept_vps);