/*
Copyright 2015-2016 Amebis
Copyright 2016 GÉANT
This file is part of GÉANTLink.
GÉANTLink is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
GÉANTLink is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GÉANTLink. If not, see .
*/
#include "StdAfx.h"
using namespace std;
using namespace winstd;
//////////////////////////////////////////////////////////////////////
// eap::method_eaphost
//////////////////////////////////////////////////////////////////////
eap::method_eaphost::method_eaphost(_In_ module &mod, _In_ config_method_eaphost &cfg, _In_ credentials_eaphost &cred) :
m_cfg(cfg),
m_cred(cred),
m_session_id(0),
method(mod)
{
}
eap::method_eaphost::method_eaphost(_Inout_ method_eaphost &&other) :
m_cfg ( other.m_cfg ),
m_cred ( other.m_cred ),
m_session_id(std::move(other.m_session_id)),
method (std::move(other ))
{
}
eap::method_eaphost& eap::method_eaphost::operator=(_Inout_ method_eaphost &&other)
{
if (this != std::addressof(other)) {
assert(std::addressof(m_cfg ) == std::addressof(other.m_cfg )); // Move method within same configuration only!
assert(std::addressof(m_cred) == std::addressof(other.m_cred)); // Move method within same credentials only!
(method&)*this = std::move(other );
m_session_id = std::move(other.m_session_id);
}
return *this;
}
void eap::method_eaphost::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_auth_failed;
m_cfg.m_last_msg.clear();
// Create EapHost peer session using available connection data (m_cfg) and user data (m_cred).
eap_error_runtime error;
DWORD dwResult = EapHostPeerBeginSession(
dwFlags,
m_cfg.get_type(),
pAttributeArray,
hTokenImpersonateUser,
(DWORD)m_cfg.m_cfg_blob.size(),
m_cfg.m_cfg_blob.data(),
(DWORD)m_cred.m_cred_blob.size(),
m_cred.m_cred_blob.data(),
dwMaxSendPacketSize,
NULL, NULL, NULL,
&m_session_id,
&error._Myptr);
if (dwResult == ERROR_SUCCESS) {
// Session succesfully created.
} else if (error)
throw eap_runtime_error(*error , __FUNCTION__ " EapHostPeerBeginSession failed.");
else
throw win_runtime_error(dwResult, __FUNCTION__ " EapHostPeerBeginSession failed.");
}
void eap::method_eaphost::end_session()
{
// End EapHost peer session.
eap_error_runtime error;
DWORD dwResult = EapHostPeerEndSession(m_session_id, &error._Myptr);
if (dwResult == ERROR_SUCCESS) {
// Session successfuly ended.
} else if (error)
throw eap_runtime_error(*error , __FUNCTION__ " EapHostPeerEndSession failed.");
else
throw win_runtime_error(dwResult, __FUNCTION__ " EapHostPeerEndSession failed.");
method::end_session();
}
EapPeerMethodResponseAction eap::method_eaphost::process_request_packet(
_In_bytecount_(dwReceivedPacketSize) const void *pReceivedPacket,
_In_ DWORD dwReceivedPacketSize)
{
assert(pReceivedPacket || dwReceivedPacketSize == 0);
// Let EapHost peer process the packet.
EapHostPeerResponseAction action;
eap_error_runtime error;
DWORD dwResult = EapHostPeerProcessReceivedPacket(
m_session_id,
dwReceivedPacketSize,
reinterpret_cast(pReceivedPacket),
&action,
&error._Myptr);
if (dwResult == ERROR_SUCCESS) {
// Packet successfuly processed.
return action_h2p(action);
} else if (error)
throw eap_runtime_error(*error , __FUNCTION__ " EapHostPeerProcessReceivedPacket failed.");
else
throw win_runtime_error(dwResult, __FUNCTION__ " EapHostPeerProcessReceivedPacket failed.");
}
void eap::method_eaphost::get_response_packet(
_Out_ sanitizing_blob &packet,
_In_opt_ DWORD size_max)
{
// Let EapHost peer prepare response packet.
eap_blob_runtime _packet;
eap_error_runtime error;
DWORD dwResult = EapHostPeerGetSendPacket(
m_session_id,
&size_max,
&_packet._Myptr,
&error._Myptr);
if (dwResult == ERROR_SUCCESS) {
// Packet successfuly prepared.
packet.assign(_packet.get(), _packet.get() + size_max);
} else if (error)
throw eap_runtime_error(*error , __FUNCTION__ " EapHostPeerGetSendPacket failed.");
else
throw win_runtime_error(dwResult, __FUNCTION__ " EapHostPeerGetSendPacket failed.");
}
void eap::method_eaphost::get_result(
_In_ EapPeerMethodResultReason reason,
_Inout_ EapPeerMethodResult *pResult)
{
// Let EapHost peer return result.
eap_error_runtime error;
EapHostPeerMethodResult result = {};
DWORD dwResult = EapHostPeerGetResult(
m_session_id,
EapHostPeerMethodResultFromMethod,
&result,
&error._Myptr);
if (dwResult == ERROR_SUCCESS) {
// Result successfuly returned.
method::get_result(reason, pResult);
pResult->dwFailureReasonCode = result.dwFailureReasonCode;
pResult->pAttribArray = result.pAttribArray;
if (result.pEapError) {
// Transfer error to our module memory space.
pResult->pEapError = m_module.make_error(result.pEapError);
EapHostPeerFreeEapError(result.pEapError);
result.pEapError = NULL;
}
if (result.fSaveConnectionData) {
// Update configuration BLOB.
m_cfg.m_cfg_blob.assign(result.pConnectionData, result.pConnectionData + result.dwSizeofConnectionData);
}
if (result.fSaveUserData) {
// Update credentials BLOB.
m_cred.m_cred_blob.assign(result.pUserData, result.pUserData + result.dwSizeofUserData);
}
if (reason == EapPeerMethodResultSuccess)
m_cfg.m_last_status = config_method::status_success;
// Always ask EAP host to save the connection data. And it will save it *only* when we report "success".
// Don't worry. EapHost is well aware of failed authentication condition.
pResult->fSaveConnectionData = TRUE;
pResult->fIsSuccess = TRUE;
} else if (error)
throw eap_runtime_error(*error , __FUNCTION__ " EapHostPeerGetResult failed.");
else
throw win_runtime_error(dwResult, __FUNCTION__ " EapHostPeerGetResult failed.");
}
void eap::method_eaphost::get_ui_context(_Out_ sanitizing_blob &context_data)
{
// Get EapHost peer UI context data.
DWORD dwUIContextDataSize;
LPBYTE pUIContextData;
eap_error_runtime error;
DWORD dwResult = EapHostPeerGetUIContext(
m_session_id,
&dwUIContextDataSize,
&pUIContextData,
&error._Myptr);
if (dwResult == ERROR_SUCCESS) {
// UI context data successfuly returned.
context_data.assign(pUIContextData, pUIContextData + dwUIContextDataSize);
// TODO: Test if EapHostPeerGetUIContext() requires us to free the buffer.
//EapHostPeerFreeMemory(pUIContextData);
} else if (error)
throw eap_runtime_error(*error , __FUNCTION__ " EapHostPeerGetUIContext failed.");
else
throw win_runtime_error(dwResult, __FUNCTION__ " EapHostPeerGetUIContext failed.");
}
EapPeerMethodResponseAction eap::method_eaphost::set_ui_context(
_In_count_(dwUIContextDataSize) const BYTE *pUIContextData,
_In_ DWORD dwUIContextDataSize)
{
// Set EapHost peer UI context data.
EapHostPeerResponseAction action;
eap_error_runtime error;
DWORD dwResult = EapHostPeerSetUIContext(
m_session_id,
dwUIContextDataSize,
pUIContextData,
&action,
&error._Myptr);
if (dwResult == ERROR_SUCCESS) {
// UI context data successfuly returned.
return action_h2p(action);
} else if (error)
throw eap_runtime_error(*error , __FUNCTION__ " EapHostPeerSetUIContext failed.");
else
throw win_runtime_error(dwResult, __FUNCTION__ " EapHostPeerSetUIContext failed.");
}
void eap::method_eaphost::get_response_attributes(_Inout_ EapAttributes *pAttribs)
{
// Get response attributes from EapHost peer.
eap_error_runtime error;
DWORD dwResult = EapHostPeerGetResponseAttributes(
m_session_id,
pAttribs,
&error._Myptr);
if (dwResult == ERROR_SUCCESS) {
// Response attributes successfuly returned.
} else if (error)
throw eap_runtime_error(*error , __FUNCTION__ " EapHostPeerGetResponseAttributes failed.");
else
throw win_runtime_error(dwResult, __FUNCTION__ " EapHostPeerGetResponseAttributes failed.");
}
EapPeerMethodResponseAction eap::method_eaphost::set_response_attributes(_In_ const EapAttributes *pAttribs)
{
// Set response attributes for EapHost peer.
EapHostPeerResponseAction action;
eap_error_runtime error;
DWORD dwResult = EapHostPeerSetResponseAttributes(
m_session_id,
pAttribs,
&action,
&error._Myptr);
if (dwResult == ERROR_SUCCESS) {
// Response attributes successfuly set.
return action_h2p(action);
} else if (error)
throw eap_runtime_error(*error , __FUNCTION__ " EapHostPeerGetResponseAttributes failed.");
else
throw win_runtime_error(dwResult, __FUNCTION__ " EapHostPeerGetResponseAttributes failed.");
}