summaryrefslogtreecommitdiff
path: root/src/libcharon/plugins/eap_mschapv2
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/plugins/eap_mschapv2')
-rw-r--r--src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c115
1 files changed, 88 insertions, 27 deletions
diff --git a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c
index f7f39f984..16978f486 100644
--- a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c
+++ b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Tobias Brunner
+ * Copyright (C) 2009-2015 Tobias Brunner
* Copyright (C) 2010 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -81,6 +81,21 @@ struct private_eap_mschapv2_t
* Number of retries
*/
int retries;
+
+ /**
+ * Provide EAP-Identity
+ */
+ auth_cfg_t *auth;
+
+ /**
+ * Current state
+ */
+ enum {
+ S_EXPECT_CHALLENGE,
+ S_EXPECT_RESPONSE,
+ S_EXPECT_SUCCESS,
+ S_DONE,
+ } state;
};
/**
@@ -628,6 +643,7 @@ METHOD(eap_method_t, initiate_server, status_t,
memcpy(cha->name, name, sizeof(MSCHAPV2_HOST_NAME) - 1);
*out = eap_payload_create_data(chunk_create((void*) eap, len));
+ this->state = S_EXPECT_RESPONSE;
return NEED_MORE;
}
@@ -747,6 +763,7 @@ static status_t process_peer_challenge(private_eap_mschapv2_t *this,
memcpy(res->name, userid.ptr, userid.len);
*out = eap_payload_create_data(chunk_create((void*) eap, len));
+ this->state = S_EXPECT_SUCCESS;
return NEED_MORE;
}
@@ -829,6 +846,7 @@ static status_t process_peer_success(private_eap_mschapv2_t *this,
*out = eap_payload_create_data(chunk_create((void*) eap, len));
status = NEED_MORE;
+ this->state = S_DONE;
error:
chunk_free(&auth_string);
@@ -922,6 +940,7 @@ static status_t process_peer_failure(private_eap_mschapv2_t *this,
*/
status = FAILED;
+ this->state = S_DONE;
error:
chunk_free(&challenge);
@@ -946,26 +965,38 @@ METHOD(eap_method_t, process_peer, status_t,
eap = (eap_mschapv2_header_t*)data.ptr;
+ switch (this->state)
+ {
+ case S_EXPECT_CHALLENGE:
+ if (eap->opcode == MSCHAPV2_CHALLENGE)
+ {
+ return process_peer_challenge(this, in, out);
+ }
+ break;
+ case S_EXPECT_SUCCESS:
+ switch (eap->opcode)
+ {
+ case MSCHAPV2_SUCCESS:
+ return process_peer_success(this, in, out);
+ case MSCHAPV2_FAILURE:
+ return process_peer_failure(this, in, out);
+ }
+ break;
+ default:
+ break;
+ }
switch (eap->opcode)
{
case MSCHAPV2_CHALLENGE:
- {
- return process_peer_challenge(this, in, out);
- }
case MSCHAPV2_SUCCESS:
- {
- return process_peer_success(this, in, out);
- }
case MSCHAPV2_FAILURE:
- {
- return process_peer_failure(this, in, out);
- }
+ DBG1(DBG_IKE, "received unexpected EAP-MS-CHAPv2 message with "
+ "OpCode (%N)!", mschapv2_opcode_names, eap->opcode);
+ break;
default:
- {
DBG1(DBG_IKE, "EAP-MS-CHAPv2 received packet with unsupported "
"OpCode (%N)!", mschapv2_opcode_names, eap->opcode);
break;
- }
}
return FAILED;
}
@@ -1027,6 +1058,8 @@ static status_t process_server_retry(private_eap_mschapv2_t *this,
/* delay the response for some time to make brute-force attacks harder */
sleep(RETRY_DELAY);
+ /* since the error is retryable the state does not change, we still
+ * expect an MSCHAPV2_RESPONSE from the peer */
return NEED_MORE;
}
@@ -1058,7 +1091,10 @@ static status_t process_server_response(private_eap_mschapv2_t *this,
name_len = min(data.len - RESPONSE_PAYLOAD_LEN, 255);
snprintf(buf, sizeof(buf), "%.*s", name_len, res->name);
userid = identification_create_from_string(buf);
- DBG2(DBG_IKE, "EAP-MS-CHAPv2 username: '%Y'", userid);
+ if (!userid->equals(userid, this->peer))
+ {
+ DBG1(DBG_IKE, "EAP-MS-CHAPv2 username: '%Y'", userid);
+ }
/* userid can only be destroyed after the last use of username */
username = extract_username(userid->get_encoding(userid));
@@ -1084,7 +1120,6 @@ static status_t process_server_response(private_eap_mschapv2_t *this,
chunk_clear(&nt_hash);
return FAILED;
}
- userid->destroy(userid);
chunk_clear(&nt_hash);
if (memeq_const(res->response.nt_response, this->nt_response.ptr,
@@ -1109,9 +1144,12 @@ static status_t process_server_response(private_eap_mschapv2_t *this,
chunk_free(&hex);
memcpy(eap->data, msg, AUTH_RESPONSE_LEN + sizeof(SUCCESS_MESSAGE));
*out = eap_payload_create_data(chunk_create((void*) eap, len));
+
+ this->auth->add(this->auth, AUTH_RULE_EAP_IDENTITY, userid);
+ this->state = S_EXPECT_SUCCESS;
return NEED_MORE;
}
-
+ userid->destroy(userid);
return process_server_retry(this, out);
}
@@ -1137,26 +1175,39 @@ METHOD(eap_method_t, process_server, status_t,
eap = (eap_mschapv2_header_t*)data.ptr;
+ switch (this->state)
+ {
+ case S_EXPECT_RESPONSE:
+ if (eap->opcode == MSCHAPV2_RESPONSE)
+ {
+ return process_server_response(this, in, out);
+ }
+ break;
+ case S_EXPECT_SUCCESS:
+ if (eap->opcode == MSCHAPV2_SUCCESS &&
+ this->msk.ptr)
+ {
+ return SUCCESS;
+ }
+ break;
+ default:
+ break;
+ }
switch (eap->opcode)
{
- case MSCHAPV2_RESPONSE:
- {
- return process_server_response(this, in, out);
- }
- case MSCHAPV2_SUCCESS:
- {
- return SUCCESS;
- }
case MSCHAPV2_FAILURE:
- {
+ /* the client may abort the authentication by sending us a failure
+ * in any state */
return FAILED;
- }
+ case MSCHAPV2_RESPONSE:
+ case MSCHAPV2_SUCCESS:
+ DBG1(DBG_IKE, "received unexpected EAP-MS-CHAPv2 message with "
+ "OpCode (%N)!", mschapv2_opcode_names, eap->opcode);
+ break;
default:
- {
DBG1(DBG_IKE, "EAP-MS-CHAPv2 received packet with unsupported "
"OpCode (%N)!", mschapv2_opcode_names, eap->opcode);
break;
- }
}
return FAILED;
}
@@ -1197,11 +1248,18 @@ METHOD(eap_method_t, is_mutual, bool,
return FALSE;
}
+METHOD(eap_method_t, get_auth, auth_cfg_t*,
+ private_eap_mschapv2_t *this)
+{
+ return this->auth;
+}
+
METHOD(eap_method_t, destroy, void,
private_eap_mschapv2_t *this)
{
this->peer->destroy(this->peer);
this->server->destroy(this->server);
+ this->auth->destroy(this->auth);
chunk_free(&this->challenge);
chunk_free(&this->nt_response);
chunk_free(&this->auth_response);
@@ -1224,11 +1282,14 @@ static private_eap_mschapv2_t *eap_mschapv2_create_generic(identification_t *ser
.get_msk = _get_msk,
.get_identifier = _get_identifier,
.set_identifier = _set_identifier,
+ .get_auth = _get_auth,
.destroy = _destroy,
},
},
.peer = peer->clone(peer),
.server = server->clone(server),
+ .auth = auth_cfg_create(),
+ .state = S_EXPECT_CHALLENGE,
);
return this;