GEANTLink/lib/PAP/src/Method.cpp
Simon Rozman 6f92e82598 WinStd: Update
Signed-off-by: Simon Rozman <simon@rozman.si>
2022-02-03 13:03:59 +01:00

107 lines
3.9 KiB
C++

/*
SPDX-License-Identifier: GPL-3.0-or-later
Copyright © 2015-2022 Amebis
Copyright © 2016 GÉANT
*/
#include "PCH.h"
using namespace std;
using namespace winstd;
//////////////////////////////////////////////////////////////////////
// eap::method_pap_diameter
//////////////////////////////////////////////////////////////////////
eap::method_pap_diameter::method_pap_diameter(_In_ module &mod, _In_ config_method_pap &cfg, _In_ credentials_pass &cred) :
m_cfg(cfg),
m_cred(cred),
m_phase(phase_t::unknown),
method(mod)
{
}
void eap::method_pap_diameter::begin_session(
_In_ DWORD dwFlags,
_In_ const EapAttributes *pAttributeArray,
_In_ HANDLE hTokenImpersonateUser,
_In_opt_ DWORD dwMaxSendPacketSize)
{
method::begin_session(dwFlags, pAttributeArray, hTokenImpersonateUser, dwMaxSendPacketSize);
// Presume authentication will fail with generic protocol failure. (Pesimist!!!)
// We will reset once we get get_result(Success) call.
m_cfg.m_last_status = config_method::status_t::auth_failed;
m_cfg.m_last_msg.clear();
m_phase = phase_t::init;
}
EapPeerMethodResponseAction eap::method_pap_diameter::process_request_packet(
_In_bytecount_(dwReceivedPacketSize) const void *pReceivedPacket,
_In_ DWORD dwReceivedPacketSize)
{
UNREFERENCED_PARAMETER(pReceivedPacket);
UNREFERENCED_PARAMETER(dwReceivedPacketSize);
switch (m_phase) {
case phase_t::init: {
m_module.log_event(&EAPMETHOD_METHOD_HANDSHAKE_START2, event_data((unsigned int)eap_type_t::legacy_pap), blank_event_data);
// Convert username and password to UTF-8.
sanitizing_string identity_utf8, password_utf8;
WideCharToMultiByte(CP_UTF8, 0, m_cred.m_identity, identity_utf8, NULL, NULL);
WideCharToMultiByte(CP_UTF8, 0, m_cred.m_password, password_utf8, NULL, NULL);
// PAP passwords must be padded to 16B boundary according to RFC 5281. Will not add random extra padding here, as length obfuscation should be done by outer transport layers.
size_t padding_password_ex = (16 - password_utf8.length()) % 16;
password_utf8.append(padding_password_ex, 0);
// Diameter AVP (User-Name=1, User-Password=2)
m_packet_res.clear();
diameter_avp_append(1, diameter_avp_flag_mandatory, identity_utf8.data(), (unsigned int)identity_utf8.size(), m_packet_res);
diameter_avp_append(2, diameter_avp_flag_mandatory, password_utf8.data(), (unsigned int)password_utf8.size(), m_packet_res);
m_phase = phase_t::finished;
m_cfg.m_last_status = config_method::status_t::cred_invalid; // Blame credentials if we fail beyond this point.
return EapPeerMethodResponseActionSend;
}
case phase_t::finished:
return EapPeerMethodResponseActionNone;
default:
throw invalid_argument(string_printf(__FUNCTION__ " Unknown phase (phase %u).", m_phase));
}
}
void eap::method_pap_diameter::get_response_packet(
_Out_ sanitizing_blob &packet,
_In_opt_ DWORD size_max)
{
if (m_packet_res.size() > 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).", m_packet_res.size(), size_max));
packet.assign(m_packet_res.begin(), m_packet_res.end());
}
void eap::method_pap_diameter::get_result(
_In_ EapPeerMethodResultReason reason,
_Inout_ EapPeerMethodResult *pResult)
{
assert(pResult);
method::get_result(reason, pResult);
if (reason == EapPeerMethodResultSuccess)
m_cfg.m_last_status = config_method::status_t::success;
// Ask EAP host to save the configuration (connection data).
pResult->fSaveConnectionData = TRUE;
}