Simon Rozman 542d20fccb Update Copyright year
Signed-off-by: Simon Rozman <simon@rozman.si>
2020-01-03 12:13:42 +01:00

671 lines
20 KiB
C++

/*
Copyright 1991-2020 Amebis
Copyright 2016 GÉANT
This file is part of WinStd.
Setup 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.
Setup 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 Setup. If not, see <http://www.gnu.org/licenses/>.
*/
///
/// \defgroup WinStdEAPAPI Extensible Authentication Protocol API
/// Integrates WinStd classes with Microsoft EAP API
///
#include "Common.h"
#include <Windows.h>
#include <eaphostpeerconfigapis.h>
#include <eaptypes.h> // Must include after <Windows.h>
#include <memory>
namespace winstd
{
enum eap_type_t;
struct WINSTD_API EapHostPeerFreeMemory_delete;
struct WINSTD_API EapHostPeerFreeRuntimeMemory_delete;
struct WINSTD_API EapHostPeerFreeErrorMemory_delete;
struct WINSTD_API EapHostPeerFreeEapError_delete;
class WINSTD_API WINSTD_NOVTABLE eap_attr;
class WINSTD_API WINSTD_NOVTABLE eap_method_prop;
class WINSTD_API eap_packet;
class WINSTD_API WINSTD_NOVTABLE eap_method_info_array;
class WINSTD_API eap_runtime_error;
/// \addtogroup WinStdEAPAPI
/// @{
///
/// EapHost BLOB wrapper class
///
typedef std::unique_ptr<BYTE[], EapHostPeerFreeMemory_delete> WINSTD_API eap_blob;
///
/// EapHost BLOB wrapper class
///
typedef std::unique_ptr<BYTE[], EapHostPeerFreeRuntimeMemory_delete> WINSTD_API eap_blob_runtime;
///
/// EAP_ERROR wrapper class
///
typedef std::unique_ptr<EAP_ERROR, EapHostPeerFreeErrorMemory_delete> WINSTD_API eap_error;
///
/// EAP_ERROR wrapper class
///
typedef std::unique_ptr<EAP_ERROR, EapHostPeerFreeEapError_delete> WINSTD_API eap_error_runtime;
/// @}
}
/// \addtogroup WinStdEAPAPI
/// @{
///
/// Are EAP method types equal?
///
/// \param[in] a First EAP method type
/// \param[in] b Second EAP method type
///
/// \returns
/// - Non zero when \p a is equal to \p b;
/// - Zero otherwise.
///
inline bool operator==(_In_ const EAP_METHOD_TYPE &a, _In_ const EAP_METHOD_TYPE &b);
///
/// Are EAP method types non-equal?
///
/// \param[in] a First EAP method type
/// \param[in] b Second EAP method type
///
/// \returns
/// - Non zero when \p a is not equal to \p b;
/// - Zero otherwise.
///
inline bool operator!=(_In_ const EAP_METHOD_TYPE &a, _In_ const EAP_METHOD_TYPE &b);
/// @}
#pragma once
#include <EapHostPeerTypes.h>
#include <eapmethodtypes.h>
#include <eappapis.h>
#include <WinSock2.h>
namespace winstd
{
/// \addtogroup WinStdEAPAPI
/// @{
///
/// EAP method numbers
///
/// \sa [Extensible Authentication Protocol (EAP) Registry (Chapter: Method Types)](https://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml#eap-numbers-4)
///
#pragma warning(suppress: 4480)
enum eap_type_t : unsigned char {
eap_type_undefined = 0, ///< Undefined EAP type
eap_type_identity = 1, ///< Identity
eap_type_notification = 2, ///< Notification
eap_type_nak = 3, ///< Legacy Nak
eap_type_md5_challenge = 4, ///< MD5-Challenge
eap_type_otp = 5, ///< One-Time Password (OTP)
eap_type_gtc = 6, ///< Generic Token Card (GTC)
eap_type_tls = 13, ///< EAP-TLS
eap_type_ttls = 21, ///< EAP-TTLS
eap_type_peap = 25, ///< EAP-PEAP
eap_type_mschapv2 = 26, ///< EAP-MSCHAPv2
eap_type_gtcp = 128 + eap_type_gtc, ///< EAP-GTC using a password
eap_type_legacy_pap = 192, ///< PAP (Not actually an EAP method; Moved to the Unassigned area)
eap_type_legacy_mschapv2 = 193, ///< MSCHAPv2 (Not actually an EAP method; Moved to the Unassigned area)
eap_type_start = 1, ///< Start of EAP methods
eap_type_end = 192, ///< End of EAP methods (non-inclusive)
eap_type_noneap_start = 192, ///< Start of non-EAP methods
eap_type_noneap_end = 254, ///< End of non-EAP methods (non-inclusive)
};
///
/// Deleter for unique_ptr using EapHostPeerFreeMemory
///
struct WINSTD_API EapHostPeerFreeMemory_delete
{
///
/// Default constructor
///
EapHostPeerFreeMemory_delete() {}
///
/// Delete a pointer
///
/// \sa [EapHostPeerFreeMemory function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363558.aspx)
///
template <class _T>
void operator()(_T *_Ptr) const
{
EapHostPeerFreeMemory((BYTE*)_Ptr);
}
};
///
/// Deleter for unique_ptr using EapHostPeerFreeRuntimeMemory
///
struct WINSTD_API EapHostPeerFreeRuntimeMemory_delete
{
///
/// Default constructor
///
EapHostPeerFreeRuntimeMemory_delete() {}
///
/// Delete a pointer
///
template <class _T>
void operator()(_T *_Ptr) const
{
EapHostPeerFreeRuntimeMemory((BYTE*)_Ptr);
}
};
///
/// Deleter for unique_ptr to EAP_ERROR using EapHostPeerFreeErrorMemory
///
struct WINSTD_API EapHostPeerFreeErrorMemory_delete
{
///
/// Default constructor
///
EapHostPeerFreeErrorMemory_delete() {}
///
/// Delete a pointer
///
/// \sa [EapHostPeerFreeErrorMemory function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363557.aspx)
///
void operator()(EAP_ERROR *_Ptr) const
{
EapHostPeerFreeErrorMemory(_Ptr);
}
};
///
/// Deleter for unique_ptr to EAP_ERROR using EapHostPeerFreeEapError
///
struct WINSTD_API EapHostPeerFreeEapError_delete
{
///
/// Default constructor
///
EapHostPeerFreeEapError_delete() {}
///
/// Delete a pointer
///
/// \sa [EapHostPeerFreeEapError function](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363556.aspx)
///
void operator()(EAP_ERROR *_Ptr) const
{
EapHostPeerFreeEapError(_Ptr);
}
};
///
/// EAP_ATTRIBUTE wrapper class
///
class WINSTD_API WINSTD_NOVTABLE eap_attr : public EAP_ATTRIBUTE
{
public:
///
/// Initializes a new EAP attribute set to eatReserved.
///
inline eap_attr()
{
eaType = eatReserved;
dwLength = 0;
pValue = NULL;
}
///
/// Copies an existing EAP attribute.
///
inline eap_attr(_In_ const EAP_ATTRIBUTE &a)
{
eaType = a.eaType;
dwLength = a.dwLength;
if (a.dwLength) {
pValue = new BYTE[a.dwLength];
assert(pValue);
memcpy(pValue, a.pValue, a.dwLength);
} else
pValue = NULL;
}
///
/// Moves an existing EAP attribute.
///
inline eap_attr(_Inout_ eap_attr &&a) noexcept
{
eaType = a.eaType;
dwLength = a.dwLength;
if (a.dwLength) {
pValue = a.pValue;
a.dwLength = 0;
a.pValue = NULL;
} else
pValue = NULL;
}
///
/// Destroys the EAP attribute.
///
~eap_attr();
///
/// Copies an existing EAP attribute.
///
inline eap_attr& operator=(_In_ const EAP_ATTRIBUTE &a)
{
if (this != &a) {
eaType = a.eaType;
dwLength = a.dwLength;
if (a.dwLength) {
BYTE *pValueNew = new BYTE[a.dwLength];
if (pValueNew) {
if (pValue)
delete [] pValue;
memcpy(pValueNew, a.pValue, a.dwLength);
pValue = pValueNew;
} else
assert(0); // Could not allocate memory
} else
pValue = NULL;
}
return *this;
}
///
/// Moves an existing EAP attribute.
///
inline eap_attr& operator=(_Inout_ eap_attr &&a) noexcept
{
if (this != &a) {
eaType = a.eaType;
dwLength = a.dwLength;
if (pValue)
delete [] pValue;
if (a.dwLength) {
pValue = a.pValue;
a.dwLength = 0;
a.pValue = NULL;
} else
pValue = NULL;
}
return *this;
}
///
/// Creates MS-MPPE-Send-Key or MS-MPPE-Recv-Key
///
/// \sa [RADIUS Vendor-Specific](https://tools.ietf.org/html/rfc2865#section-5.26)
/// \sa [MS-MPPE-Send-Key](https://tools.ietf.org/html/rfc2548#section-2.4.2)
/// \sa [MS-MPPE-Recv-Key](https://tools.ietf.org/html/rfc2548#section-2.4.3)
///
void create_ms_mppe_key(_In_ BYTE bVendorType, _In_count_(nKeySize) LPCBYTE pbKey, _In_ BYTE nKeySize);
public:
static const EAP_ATTRIBUTE blank; ///< Blank EAP attribute
};
///
/// EAP_METHOD_PROPERTY wrapper class
///
class WINSTD_API WINSTD_NOVTABLE eap_method_prop : public EAP_METHOD_PROPERTY
{
public:
///
/// Constructs a BOOL method property
///
/// \param[in] type EAP method property type
/// \param[in] value Property value
///
inline eap_method_prop(_In_ EAP_METHOD_PROPERTY_TYPE type, _In_ BOOL value)
{
eapMethodPropertyType = type;
eapMethodPropertyValueType = empvtBool;
eapMethodPropertyValue.empvBool.length = sizeof(BOOL);
eapMethodPropertyValue.empvBool.value = value;
}
///
/// Constructs a DWORD method property
///
/// \param[in] type EAP method property type
/// \param[in] value Property value
///
inline eap_method_prop(_In_ EAP_METHOD_PROPERTY_TYPE type, _In_ DWORD value)
{
eapMethodPropertyType = type;
eapMethodPropertyValueType = empvtDword;
eapMethodPropertyValue.empvDword.length = sizeof(DWORD);
eapMethodPropertyValue.empvDword.value = value;
}
///
/// Constructs a Unicode string method property
///
/// \param[in] type EAP method property type
/// \param[in] value Property value
///
inline eap_method_prop(_In_ EAP_METHOD_PROPERTY_TYPE type, _In_z_ LPCWSTR value)
{
eapMethodPropertyType = type;
eapMethodPropertyValueType = empvtString;
eapMethodPropertyValue.empvString.length = (DWORD)(sizeof(WCHAR)*(wcslen(value) + 1));
eapMethodPropertyValue.empvString.value = (BYTE*)value;
}
};
///
/// EapPacket wrapper class
///
class WINSTD_API eap_packet : public dplhandle<EapPacket*, NULL>
{
DPLHANDLE_IMPL(eap_packet, NULL)
public:
///
/// Destroys the EAP packet.
///
virtual ~eap_packet();
///
/// Create new EAP packet
///
/// \param[in] code EAP code (one of EapCode enum values)
/// \param[in] id Packet ID
/// \param[in] size Total packet size in bytes, including header. Must be at least 4B.
///
/// \note Packet data (beyond first 4B) is not initialized.
///
/// \return
/// - true when creation succeeds;
/// - false when creation fails. For extended error information, call `GetLastError()`.
///
inline bool create(_In_ EapCode code, _In_ BYTE id, _In_ WORD size)
{
assert(size >= 4); // EAP packets must contain at least Code, Id, and Length fields: 4B.
handle_type h = (handle_type)HeapAlloc(GetProcessHeap(), 0, size);
if (h != NULL) {
h->Code = (BYTE) code ;
h->Id = id ;
*(WORD*)h->Length = htons(size);
attach(h);
return true;
} else {
SetLastError(ERROR_OUTOFMEMORY);
return false;
}
}
///
/// Returns total EAP packet size in bytes.
///
inline WORD size() const
{
return m_h != NULL ? ntohs(*(WORD*)m_h->Length) : 0;
}
protected:
///
/// Destroys the EAP packet.
///
virtual void free_internal();
///
/// Duplicates the EAP packet.
///
virtual handle_type duplicate_internal(_In_ handle_type h) const;
};
///
/// EAP_METHOD_INFO_ARRAY wrapper class
///
class WINSTD_API WINSTD_NOVTABLE eap_method_info_array : public EAP_METHOD_INFO_ARRAY
{
WINSTD_NONCOPYABLE(eap_method_info_array)
public:
///
/// Constructs an empty array
///
inline eap_method_info_array()
{
dwNumberOfMethods = 0;
pEapMethods = NULL;
}
///
/// Move constructor
///
/// \param[inout] other A rvalue reference of another object
///
inline eap_method_info_array(_Inout_ eap_method_info_array &&other) noexcept
{
dwNumberOfMethods = other.dwNumberOfMethods;
pEapMethods = other.pEapMethods;
other.dwNumberOfMethods = 0;
other.pEapMethods = NULL;
}
///
/// Destructor
///
~eap_method_info_array();
///
/// Move assignment
///
/// \param[inout] other A rvalue reference of another object
///
inline eap_method_info_array& operator=(_Inout_ eap_method_info_array &&other) noexcept
{
if (this != std::addressof(other)) {
if (pEapMethods)
free_internal();
dwNumberOfMethods = other.dwNumberOfMethods;
pEapMethods = other.pEapMethods;
other.dwNumberOfMethods = 0;
other.pEapMethods = NULL;
}
return *this;
}
protected:
/// \cond internal
void free_internal();
static void free_internal(_In_ EAP_METHOD_INFO *pMethodInfo);
/// \endcond
};
/// @}
///
/// \defgroup WinStdExceptions Exceptions
/// Additional exceptions
///
/// @{
///
/// EapHost runtime error
///
/// \sa [EAP_ERROR structure](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363699.aspx)
///
class WINSTD_API eap_runtime_error : public win_runtime_error
{
public:
///
/// Constructs an exception
///
/// \param[in] err EapHost error descriptor
/// \param[in] msg Error message
///
inline eap_runtime_error(_In_ const EAP_ERROR &err, _In_ const std::string& msg) :
m_type (err.type ),
m_reason (err.dwReasonCode ),
m_root_cause_id (err.rootCauseGuid ),
m_root_cause_desc(err.pRootCauseString ),
m_repair_id (err.repairGuid ),
m_repair_desc (err.pRepairString ),
m_help_link_id (err.helpLinkGuid ),
win_runtime_error(err.dwWinError, msg.c_str())
{
}
///
/// Constructs an exception
///
/// \param[in] err EapHost error descriptor
/// \param[in] msg Error message
///
inline eap_runtime_error(_In_ const EAP_ERROR &err, _In_opt_z_ const char *msg = nullptr) :
m_type (err.type ),
m_reason (err.dwReasonCode ),
m_root_cause_id (err.rootCauseGuid ),
m_root_cause_desc(err.pRootCauseString),
m_repair_id (err.repairGuid ),
m_repair_desc (err.pRepairString ),
m_help_link_id (err.helpLinkGuid ),
win_runtime_error(err.dwWinError, msg )
{
}
///
/// Returns EAP method type
///
inline const EAP_METHOD_TYPE& type() const
{
return m_type;
}
///
/// Returns the reason code for error
///
inline DWORD reason() const
{
return m_reason;
}
///
/// Returns root cause ID
///
inline const GUID& root_cause_id() const
{
return m_root_cause_id;
}
///
/// Returns root cause ID
///
inline const wchar_t* root_cause() const
{
return m_root_cause_desc.c_str();
}
///
/// Returns repair ID
///
inline const GUID& repair_id() const
{
return m_repair_id;
}
///
/// Returns root cause ID
///
inline const wchar_t* repair() const
{
return m_repair_desc.c_str();
}
///
/// Returns help_link ID
///
inline const GUID& help_link_id() const
{
return m_help_link_id;
}
protected:
EAP_METHOD_TYPE m_type; ///< Structure that identifies the EAP method that raised the error
DWORD m_reason; ///< The reason code for the error
GUID m_root_cause_id; ///< A unique ID that identifies cause of error in EAPHost
std::wstring m_root_cause_desc; ///< A localized and readable string that describes the root cause of the error
GUID m_repair_id; ///< A unique ID that maps to a localizable string that identifies the repair action that can be taken to fix the reported error
std::wstring m_repair_desc; ///< A localized and readable string that describes the possible repair action
GUID m_help_link_id; ///< A unique ID that maps to a localizable string that specifies an URL for a page that contains additional information about an error or repair message
};
/// @}
}
inline bool operator==(_In_ const EAP_METHOD_TYPE &a, _In_ const EAP_METHOD_TYPE &b)
{
return
a.eapType.type == b.eapType.type &&
a.eapType.dwVendorId == b.eapType.dwVendorId &&
a.eapType.dwVendorType == b.eapType.dwVendorType &&
a.dwAuthorId == a.dwAuthorId;
}
inline bool operator!=(_In_ const EAP_METHOD_TYPE &a, _In_ const EAP_METHOD_TYPE &b)
{
return !operator==(a, b);
}