method_eapmsg: Let inner method handle EAP-Identity packets

With EapHost inner method, this is a must.

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman 2020-01-20 13:12:31 +01:00
parent b2edd74270
commit 1290d83b9d
3 changed files with 22 additions and 35 deletions

View File

@ -131,10 +131,9 @@ namespace eap
/// Constructs a method /// Constructs a method
/// ///
/// \param[in] mod Module to use for global services /// \param[in] mod Module to use for global services
/// \param[in] identity User identity
/// \param[in] inner Inner method /// \param[in] inner Inner method
/// ///
method_eapmsg(_In_ module &mod, _In_ const wchar_t *identity, _In_ method *inner); method_eapmsg(_In_ module &mod, _In_ method *inner);
/// \name Session management /// \name Session management
/// @{ /// @{
@ -161,8 +160,6 @@ namespace eap
/// @} /// @}
protected: protected:
std::wstring m_identity; ///< User identity
/// ///
/// Communication phase /// Communication phase
/// ///

View File

@ -163,8 +163,7 @@ void eap::method_defrag::get_response_packet(
// eap::method_eapmsg // eap::method_eapmsg
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
eap::method_eapmsg::method_eapmsg(_In_ module &mod, _In_ const wchar_t *identity, _In_ method *inner) : eap::method_eapmsg::method_eapmsg(_In_ module &mod, _In_ method *inner) :
m_identity(identity),
m_phase(phase_t::unknown), m_phase(phase_t::unknown),
method_tunnel(mod, inner) method_tunnel(mod, inner)
{ {
@ -196,27 +195,17 @@ EapPeerMethodResponseAction eap::method_eapmsg::process_request_packet(
_In_ DWORD dwReceivedPacketSize) _In_ DWORD dwReceivedPacketSize)
{ {
switch (m_phase) { switch (m_phase) {
case phase_t::identity: { case phase_t::identity:
// Convert identity to UTF-8.
sanitizing_string identity_utf8;
WideCharToMultiByte(CP_UTF8, 0, m_identity, identity_utf8, NULL, NULL);
// Build EAP-Response/Identity packet. // Build EAP-Response/Identity packet.
auto size_identity = identity_utf8.length(), size_packet = size_identity + sizeof(EapPacket); EapPacket hdr_req;
assert(size_packet <= MAXWORD); // Packets spanning over 64kB are not supported. hdr_req.Code = EapCodeRequest;
eap_packet pck; hdr_req.Id = 0;
if (!pck.create(EapCodeResponse, 0, (WORD)size_packet)) *reinterpret_cast<unsigned short*>(hdr_req.Length) = htons(sizeof(EapPacket));
throw win_runtime_error(__FUNCTION__ " EapPacket creation failed."); hdr_req.Data[0] = (BYTE)eap_type_t::identity;
pck->Data[0] = (BYTE)eap_type_t::identity;
memcpy(pck->Data + 1, identity_utf8.data(), size_identity);
// Diameter AVP (EAP-Message=79)
m_packet_res.clear();
diameter_avp_append(79, diameter_avp_flag_mandatory, (const EapPacket*)pck, (unsigned int)size_packet, m_packet_res);
m_phase = phase_t::finished; m_phase = phase_t::finished;
return EapPeerMethodResponseActionSend; m_packet_res.clear();
} return method_tunnel::process_request_packet(&hdr_req, sizeof(EapPacket));
case phase_t::finished: { case phase_t::finished: {
EapPeerMethodResponseAction action = EapPeerMethodResponseActionNone; EapPeerMethodResponseAction action = EapPeerMethodResponseActionNone;
@ -271,16 +260,15 @@ void eap::method_eapmsg::get_response_packet(
_In_opt_ DWORD size_max) _In_opt_ DWORD size_max)
{ {
if (m_packet_res.empty()) { if (m_packet_res.empty()) {
assert(size_max >= sizeof(diameter_avp_header)); // We should be able to respond with at least Diameter AVP header.
if (size_max > 0xffffff) size_max = 0xffffff; // Diameter AVP maximum size is 16MB. if (size_max > 0xffffff) size_max = 0xffffff; // Diameter AVP maximum size is 16MB.
// Get data from underlying method. // Get data from underlying method.
assert(size_max >= sizeof(diameter_avp_header)); // We should be able to respond with at least Diameter AVP header.
method_tunnel::get_response_packet(packet, size_max - sizeof(diameter_avp_header)); method_tunnel::get_response_packet(packet, size_max - sizeof(diameter_avp_header));
// Prepare EAP-Message Diameter AVP header. // Prepare EAP-Message Diameter AVP header.
diameter_avp_header hdr; diameter_avp_header hdr;
*reinterpret_cast<unsigned int*>(hdr.code) = htonl(79); *reinterpret_cast<unsigned int*>(hdr.code) = htonl(79); // EAP-Message=79
hdr.flags = diameter_avp_flag_mandatory; hdr.flags = diameter_avp_flag_mandatory;
size_t size_packet = packet.size() + sizeof(diameter_avp_header); size_t size_packet = packet.size() + sizeof(diameter_avp_header);
assert(size_packet <= 0xffffff); // Packets spanning over 16MB are not supported. assert(size_packet <= 0xffffff); // Packets spanning over 16MB are not supported.
@ -292,10 +280,12 @@ void eap::method_eapmsg::get_response_packet(
// Add padding. // Add padding.
packet.insert(packet.end(), (unsigned int)((4 - size_packet) % 4), 0); packet.insert(packet.end(), (unsigned int)((4 - size_packet) % 4), 0);
} else { } else {
if (m_packet_res.size() > size_max) // We have a response packet ready.
throw invalid_argument(string_printf(__FUNCTION__ " This method does not support packet fragmentation, but the data size is too big to fit in one packet (packet: %zu, maximum: %u).", m_packet_res.size(), size_max)); size_t size_packet = m_packet_res.size();
if (size_packet > size_max)
throw invalid_argument(string_printf(__FUNCTION__ " This method does not support packet fragmentation, but the data size is too big to fit in one packet (packet: %zu, maximum: %u).", size_packet, size_max));
packet.assign(m_packet_res.begin(), m_packet_res.end()); packet.assign(m_packet_res.cbegin(), m_packet_res.cend());
} }
} }

View File

@ -673,8 +673,8 @@ eap::config_method* eap::peer_ttls::make_config_method()
eap::method* eap::peer_ttls::make_method(_In_ config_method_tls_tunnel &cfg, _In_ credentials_tls_tunnel &cred) eap::method* eap::peer_ttls::make_method(_In_ config_method_tls_tunnel &cfg, _In_ credentials_tls_tunnel &cred)
{ {
unique_ptr<method> meth_inner; unique_ptr<method> meth_inner;
auto cfg_inner = cfg.m_inner.get(); auto cfg_inner = cfg.m_inner.get();
auto cred_inner = cred.m_inner.get(); auto cred_inner = cred.m_inner.get();
assert(cfg_inner); assert(cfg_inner);
switch (cfg_inner->get_method_id()) { switch (cfg_inner->get_method_id()) {
@ -690,14 +690,14 @@ eap::method* eap::peer_ttls::make_method(_In_ config_method_tls_tunnel &cfg, _In
case eap_type_t::mschapv2: case eap_type_t::mschapv2:
meth_inner.reset( meth_inner.reset(
new method_eapmsg (*this, cred_inner->get_identity().c_str(), new method_eapmsg (*this,
new method_eap (*this, eap_type_t::mschapv2, *cred_inner, new method_eap (*this, eap_type_t::mschapv2, *cred_inner,
new method_mschapv2(*this, dynamic_cast<config_method_mschapv2&>(*cfg_inner), dynamic_cast<credentials_pass&>(*cred_inner))))); new method_mschapv2(*this, dynamic_cast<config_method_mschapv2&>(*cfg_inner), dynamic_cast<credentials_pass&>(*cred_inner)))));
break; break;
case eap_type_t::gtc: case eap_type_t::gtc:
meth_inner.reset( meth_inner.reset(
new method_eapmsg(*this, cred_inner->get_identity().c_str(), new method_eapmsg(*this,
new method_eap (*this, eap_type_t::gtc, *cred_inner, new method_eap (*this, eap_type_t::gtc, *cred_inner,
new method_gtc (*this, dynamic_cast<config_method_eapgtc&>(*cfg_inner), dynamic_cast<credentials&>(*cred_inner))))); new method_gtc (*this, dynamic_cast<config_method_eapgtc&>(*cfg_inner), dynamic_cast<credentials&>(*cred_inner)))));
break; break;
@ -705,7 +705,7 @@ eap::method* eap::peer_ttls::make_method(_In_ config_method_tls_tunnel &cfg, _In
#if EAP_INNER_EAPHOST #if EAP_INNER_EAPHOST
case eap_type_t::undefined: case eap_type_t::undefined:
meth_inner.reset( meth_inner.reset(
new method_eapmsg (*this, cred_inner->get_identity().c_str(), new method_eapmsg (*this,
new method_eaphost(*this, dynamic_cast<config_method_eaphost&>(*cfg_inner), dynamic_cast<credentials_eaphost&>(*cred_inner)))); new method_eaphost(*this, dynamic_cast<config_method_eaphost&>(*cfg_inner), dynamic_cast<credentials_eaphost&>(*cred_inner))));
break; break;
#endif #endif