659 lines
18 KiB
C++
659 lines
18 KiB
C++
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
|
|
// PARTICULAR PURPOSE.
|
|
|
|
//
|
|
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
|
|
#include "EapHostCommon.h"
|
|
#include "memory.h"
|
|
#include "strsafe.h"
|
|
|
|
namespace SDK_METHOD_SAMPLE_COMMON
|
|
{
|
|
|
|
/**
|
|
* Allocate space for the EAPAttributes structure that will contain specified number of EAP attributes.
|
|
*
|
|
* @param attribCount The # of Eap attributes to create.
|
|
*
|
|
* @param ppEapAttributes (input/output) A pointer to the real data buffer pointer.
|
|
* The real pointer will be set to point to the allocated memory.
|
|
*
|
|
* @return A Win32 error code, indicating success or failure.
|
|
*/
|
|
DWORD
|
|
AllocateAttributes(
|
|
IN DWORD attribCount,
|
|
IN OUT EapAttributes **ppEapAttributes
|
|
)
|
|
{
|
|
DWORD retCode = NO_ERROR;
|
|
DWORD bufLen = 0;
|
|
|
|
// Sanity Check
|
|
if (! ppEapAttributes)
|
|
{
|
|
retCode = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if(attribCount > MAX_ATTR_IN_EAP_ATTRIBUTES)
|
|
{
|
|
retCode = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Allocate Memory for the EapAttributes structure.
|
|
//
|
|
retCode = AllocateMemory(sizeof(EapAttributes), (PVOID*)ppEapAttributes);
|
|
if (retCode != NO_ERROR)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Assign the number of EAP attributes that the EapAttributes structure will contain.
|
|
//
|
|
(*ppEapAttributes)->dwNumberOfAttributes = attribCount;
|
|
|
|
//
|
|
// Allocate Memory for the EapAttribute pointer in the EapAttributes structure.
|
|
//
|
|
bufLen = sizeof(EapAttribute) * attribCount;
|
|
retCode = AllocateMemory(bufLen, (PVOID*)&((*ppEapAttributes)->pAttribs));
|
|
if (retCode != NO_ERROR)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
// AllocateMemory() initializes the buffer to NULL values.
|
|
|
|
Cleanup:
|
|
if(retCode != NO_ERROR)
|
|
FreeMemory((PVOID*)ppEapAttributes);
|
|
return retCode;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Free a EapAttributes structure.
|
|
*
|
|
* This function will walk the chain of attributes, freeing each attribute's
|
|
* Value data pointer, it will free the list's data buffer, and set the former
|
|
* data buffer pointer to point to NULL.
|
|
*
|
|
* @param ppEapAttributes (input/output) A pointer to the real data buffer
|
|
* pointer.
|
|
*
|
|
* @return A Win32 error code, indicating success or failure.
|
|
*
|
|
*/
|
|
DWORD
|
|
FreeAttributes(
|
|
IN OUT EapAttributes **ppEapAttributes
|
|
)
|
|
{
|
|
DWORD retCode = NO_ERROR;
|
|
DWORD attribCount = 0;
|
|
EapAttribute *pEapAttrib = NULL;
|
|
DWORD i = 0;
|
|
|
|
//Sanity Check
|
|
if (! ppEapAttributes)
|
|
{
|
|
retCode = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (! *ppEapAttributes)
|
|
{
|
|
// Return silently. No attribute. Nothing to free.
|
|
goto Cleanup;
|
|
}
|
|
|
|
attribCount = (*ppEapAttributes)->dwNumberOfAttributes;
|
|
|
|
//
|
|
// Free all the Value pointers in each EAP attribute.
|
|
//
|
|
for(i = 0; i < attribCount; i++)
|
|
{
|
|
pEapAttrib = &(((*ppEapAttributes)->pAttribs)[i]);
|
|
retCode = FreeMemory((PVOID*)&(pEapAttrib->pValue));
|
|
if (retCode != NO_ERROR)
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Free the (EapAttribute *) in the EapAttributes structure.
|
|
//
|
|
retCode = FreeMemory((PVOID *)&((*ppEapAttributes)->pAttribs));
|
|
if (retCode != NO_ERROR)
|
|
goto Cleanup;
|
|
|
|
//
|
|
// Free the EapAttributes structure.
|
|
//
|
|
retCode = FreeMemory((PVOID*)ppEapAttributes);
|
|
if (retCode != NO_ERROR)
|
|
goto Cleanup;
|
|
|
|
// FreeMemory sets the buffer pointer to NULL after freeing the data.
|
|
|
|
Cleanup:
|
|
return retCode;
|
|
}
|
|
|
|
|
|
/**
|
|
* Set an attribute in a pre-allocated list.
|
|
*
|
|
* This function takes the attribute list buffer from AllocateAttributes(),
|
|
* finds the first unset attribute, and sets it to contain the specified data.
|
|
* It allocates memory for the attribute's value member.
|
|
*
|
|
* @param pEapAttributes (input/output) A pointer to the real data buffer pointer.
|
|
* @param eaType New attribute's type (from eaptypes.h).
|
|
* @param dwLength New attribute's length.
|
|
* @param pValue New attribute's value.
|
|
*
|
|
* @return A Win32 error code, indicating success or failure.
|
|
*/
|
|
DWORD
|
|
AddAttribute(
|
|
IN OUT EapAttributes *pEapAttributes,
|
|
IN EapAttributeType eaType,
|
|
IN DWORD dwLength,
|
|
IN PVOID pValue
|
|
)
|
|
{
|
|
DWORD retCode = NO_ERROR;
|
|
DWORD i = 0;
|
|
EapAttribute *pEapAttrib = NULL;
|
|
|
|
//Sanity Check
|
|
if (! pEapAttributes)
|
|
{
|
|
retCode = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Find the next available (empty) attribute.
|
|
//
|
|
for (i = 0; i < pEapAttributes->dwNumberOfAttributes; i++)
|
|
{
|
|
pEapAttrib = &((pEapAttributes->pAttribs)[i]);
|
|
if (pEapAttrib->eaType == eatMinimum)
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Array bounds check -- make sure we have room for this element.
|
|
//
|
|
if (i == pEapAttributes->dwNumberOfAttributes)
|
|
{
|
|
retCode = ERROR_OUT_OF_STRUCTURES;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Fill up the attribute structure.
|
|
//
|
|
pEapAttrib->eaType = eaType;
|
|
pEapAttrib->dwLength = dwLength;
|
|
|
|
retCode = AllocateMemory(dwLength, (PVOID*)&(pEapAttrib->pValue));
|
|
if (retCode != NO_ERROR)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Copy the actual data length into the buffer.
|
|
//
|
|
CopyMemory(pEapAttrib->pValue, pValue, dwLength);
|
|
|
|
Cleanup:
|
|
return retCode;
|
|
}
|
|
|
|
|
|
/**
|
|
* Append a new attribute onto the end of an existing list (extending list).
|
|
*
|
|
* This function creates a new, larger attribute list, copies attributes
|
|
* from the original list into the new list, and adds the new attribute
|
|
* onto the end of the list.
|
|
*
|
|
*
|
|
* @param ppAttributesList (input/output) A pointer to the real attribute
|
|
* list data buffer pointer. The data will be
|
|
* copied out of this buffer, the buffer freed, and
|
|
* the pointer set to the new attribute list.
|
|
* @param eaType New attribute's type (from EapTypes.h).
|
|
* @param dwLength New attribute's length
|
|
* @param value New attribute's value.
|
|
*
|
|
* @return A Win32 error code, indicating success or failure.
|
|
*/
|
|
DWORD
|
|
AppendAttributeToList(
|
|
IN OUT EapAttributes **ppAttributesList,
|
|
IN EapAttributeType eaType,
|
|
IN DWORD dwLength,
|
|
IN PVOID value
|
|
)
|
|
{
|
|
DWORD retCode = NO_ERROR;
|
|
DWORD dwCount = 0;
|
|
DWORD attribCountOld = 0;
|
|
EapAttribute *pEapAttrib = NULL;
|
|
DWORD dwIndex = 0;
|
|
|
|
EapAttributes *pNewAttributesList = NULL;
|
|
|
|
// Sanity check.
|
|
if (! ppAttributesList)
|
|
{
|
|
retCode = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Determine how many attributes we'll need in the new list.
|
|
//
|
|
if (! *ppAttributesList)
|
|
{
|
|
attribCountOld = 0;
|
|
}
|
|
else
|
|
attribCountOld = (*ppAttributesList)->dwNumberOfAttributes;
|
|
|
|
dwCount = 1 + attribCountOld;
|
|
|
|
//
|
|
// Allocate a new attributes list, with the specified length.
|
|
//
|
|
retCode = AllocateAttributes(dwCount, &pNewAttributesList);
|
|
if (retCode != NO_ERROR)
|
|
goto Cleanup;
|
|
|
|
//
|
|
// Copy the old attributes list into the new list.
|
|
//
|
|
if (*ppAttributesList != NULL)
|
|
{
|
|
for( dwIndex = 0; dwIndex < attribCountOld; dwIndex++ )
|
|
{
|
|
pEapAttrib = &((*ppAttributesList)->pAttribs)[dwIndex];
|
|
retCode = AddAttribute(pNewAttributesList,
|
|
pEapAttrib->eaType,
|
|
pEapAttrib->dwLength,
|
|
pEapAttrib->pValue);
|
|
if (retCode != NO_ERROR)
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add the new attribute into the new list.
|
|
//
|
|
retCode = AddAttribute(pNewAttributesList, eaType, dwLength, value);
|
|
if (retCode != NO_ERROR)
|
|
goto Cleanup;
|
|
|
|
//
|
|
// Free the old list, and pass back the new list.
|
|
//
|
|
retCode = FreeAttributes(ppAttributesList);
|
|
if (retCode != NO_ERROR)
|
|
goto Cleanup;
|
|
|
|
*ppAttributesList = pNewAttributesList;
|
|
|
|
|
|
Cleanup:
|
|
if (retCode != NO_ERROR)
|
|
FreeAttributes(&pNewAttributesList);
|
|
|
|
return retCode;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Allocates EAP_ERROR structure and fills it using the input parameters.
|
|
*
|
|
* The memory will be freed by EapPeerFreeErrorMemory() or EapMethodAuthenticatorFreeErrorMemory()
|
|
* depending on who the caller of this API is.
|
|
*
|
|
* @param pEapError EAP_ERROR will be allocated at this pointer and
|
|
* populated with above input parameters.
|
|
* @param errCode Win32 error code
|
|
* @param dwReasonCode Reason Code
|
|
* @param pRootCauseGuid Root Cause GUID
|
|
* @param pRepairGuid Repair GUID
|
|
* @param pHelpLinkGuid Help Link GUID
|
|
* @param pRootCauseString String describing the root cause
|
|
* @param pRepairString String describing the repair mechanism
|
|
*
|
|
* @return A Win32 error code, indicating success or failure.
|
|
*/
|
|
DWORD AllocateandFillEapError(
|
|
IN OUT EAP_ERROR** pEapError,
|
|
IN DWORD errCode,
|
|
IN DWORD dwReasonCode,
|
|
IN LPCGUID pRootCauseGuid,
|
|
IN LPCGUID pRepairGuid,
|
|
IN LPCGUID pHelpLinkGuid,
|
|
IN _In_opt_ LPWSTR pRootCauseString,
|
|
IN _In_opt_ LPWSTR pRepairString
|
|
)
|
|
{
|
|
DWORD retCode = NO_ERROR;
|
|
|
|
//Sanity Check
|
|
if(!pEapError)
|
|
{
|
|
retCode = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for EAP_ERROR.
|
|
//
|
|
retCode = AllocateMemory(sizeof(EAP_ERROR), (PVOID *)pEapError);
|
|
if(retCode != NO_ERROR)
|
|
goto Cleanup;
|
|
|
|
ZeroMemory(*pEapError, sizeof(EAP_ERROR));
|
|
|
|
//
|
|
// Assign the Win32 Error Code
|
|
//
|
|
(*pEapError)->dwWinError = errCode;
|
|
|
|
//
|
|
// Assign the EAP_METHOD_TYPE to indicate which EAP Method send the error.
|
|
//
|
|
(*pEapError)->type.eapType.type = EAPTYPE;
|
|
(*pEapError)->type.eapType.dwVendorId = VENODR_ID;
|
|
(*pEapError)->type.eapType.dwVendorType = VENDOR_TYPE;
|
|
(*pEapError)->type.dwAuthorId = AUTHOR_ID;
|
|
|
|
//
|
|
// Assign the reason code
|
|
//
|
|
(*pEapError)->dwReasonCode = dwReasonCode;
|
|
|
|
//
|
|
// Assign the RootCause GUID
|
|
//
|
|
if(pRootCauseGuid != NULL)
|
|
memcpy(&((*pEapError)->rootCauseGuid), pRootCauseGuid, sizeof(GUID));
|
|
|
|
//
|
|
// Assign the Repair GUID
|
|
//
|
|
if(pRepairGuid != NULL)
|
|
memcpy(&((*pEapError)->repairGuid), pRepairGuid, sizeof(GUID));
|
|
|
|
//
|
|
// Assign the HelpLink GUID
|
|
//
|
|
if(pHelpLinkGuid!= NULL)
|
|
memcpy(&((*pEapError)->helpLinkGuid), pHelpLinkGuid, sizeof(GUID));
|
|
|
|
//
|
|
// Assign the Root Cause String
|
|
//
|
|
retCode = CopyWideString(pRootCauseString, &((*pEapError)->pRootCauseString));
|
|
if(retCode != NO_ERROR)
|
|
goto Cleanup;
|
|
|
|
//
|
|
// Assign the Repair String
|
|
//
|
|
retCode = CopyWideString(pRepairString, &((*pEapError)->pRepairString));
|
|
if(retCode != NO_ERROR)
|
|
goto Cleanup;
|
|
|
|
Cleanup:
|
|
if(retCode != NO_ERROR)
|
|
FreeMemory((PVOID*)pEapError);
|
|
|
|
return retCode;
|
|
}
|
|
|
|
DWORD CopyWideString(
|
|
IN _In_opt_ LPWSTR pSrcWString,
|
|
OUT _Out_ LPWSTR *pDestWString)
|
|
{
|
|
DWORD retCode = NO_ERROR;
|
|
HRESULT hr = S_OK;
|
|
size_t dwStringLength = 0;
|
|
LPWSTR pTempString = NULL;
|
|
|
|
*pDestWString = NULL;
|
|
|
|
// Nothing to copy
|
|
if(!pSrcWString)
|
|
goto Cleanup;
|
|
|
|
hr = StringCbLengthW(pSrcWString, (size_t)(STRSAFE_MAX_CCH * sizeof(wchar_t)), &dwStringLength);
|
|
if (FAILED(hr))
|
|
{
|
|
retCode = HRESULT_CODE(hr);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// StringCbLengthW - returns the length of string in bytes (excluding the null character).
|
|
// StringCbCopyW expects the length of string in bytes (including the null character).
|
|
dwStringLength += sizeof(wchar_t);
|
|
retCode = AllocateMemory((DWORD)dwStringLength, (PVOID *)&pTempString);
|
|
if(retCode != NO_ERROR)
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
hr = StringCbCopyW((LPTSTR)pTempString, dwStringLength, pSrcWString);
|
|
if (FAILED(hr))
|
|
{
|
|
retCode = HRESULT_CODE(hr);
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Set the OUT parameter
|
|
//
|
|
*pDestWString = pTempString;
|
|
|
|
Cleanup:
|
|
if((retCode != NO_ERROR) && (pTempString != NULL))
|
|
FreeMemory((PVOID *)&pTempString);
|
|
pTempString = NULL;
|
|
return retCode;
|
|
}
|
|
|
|
|
|
/**
|
|
* Convert a 32-bit integer from host format to wire format.
|
|
*
|
|
* This function reorders the bytes in a given 32-bit value, into
|
|
* from host-byte order into network-byte order.
|
|
*
|
|
* The calling function is responsible for allocating memory for the output
|
|
* value. This can come from an explicit allocation, or from an implicit
|
|
* allocation such as a reference to a local variable.
|
|
*
|
|
*
|
|
* @param dwHostFormat [in] The input value, in host-byte order.
|
|
* @param pWireFormat [out] The output value, in network-byte order.
|
|
*/
|
|
|
|
VOID
|
|
HostToWireFormat32(
|
|
IN DWORD dwHostFormat,
|
|
IN OUT PBYTE pWireFormat
|
|
)
|
|
{
|
|
*((PBYTE)(pWireFormat)+0) = (BYTE) ((DWORD)(dwHostFormat) >> 24);
|
|
*((PBYTE)(pWireFormat)+1) = (BYTE) ((DWORD)(dwHostFormat) >> 16);
|
|
*((PBYTE)(pWireFormat)+2) = (BYTE) ((DWORD)(dwHostFormat) >> 8);
|
|
*((PBYTE)(pWireFormat)+3) = (BYTE) (dwHostFormat);
|
|
}
|
|
|
|
|
|
/**
|
|
* Convert a 16-bit integer from host format to wire format.
|
|
*
|
|
* This function reorders the bytes in a given 16-bit value, into
|
|
* from host-byte order into network-byte order.
|
|
*
|
|
* The calling function is responsible for allocating memory for the output
|
|
* value. This can come from an explicit allocation, or from an implicit
|
|
* allocation such as a reference to a local variable.
|
|
*
|
|
*
|
|
* @param wHostFormat [in] The input value, in host-byte order.
|
|
* @param pWireFormat [out] The output value, in network-byte order.
|
|
*/
|
|
|
|
VOID
|
|
HostToWireFormat16(
|
|
IN WORD wHostFormat,
|
|
IN OUT PBYTE pWireFormat
|
|
)
|
|
{
|
|
*((PBYTE)(pWireFormat)+0) = (BYTE) ((DWORD)(wHostFormat) >> 8);
|
|
*((PBYTE)(pWireFormat)+1) = (BYTE) (wHostFormat);
|
|
}
|
|
|
|
|
|
/**
|
|
* Convert a 16-bit integer from wire format to host format.
|
|
*
|
|
* This function reorders the bytes in a given 16-bit value, into
|
|
* from network-byte order into host-byte order.
|
|
*
|
|
* The calling function is responsible for allocating memory for the output
|
|
* value. This can come from an explicit allocation, or from an implicit
|
|
* allocation such as a reference to a local variable.
|
|
*
|
|
*
|
|
* @param wWireFormat [in] The input value, in network-byte order.
|
|
* @param pHostFormat [out] The output value, in host-byte order.
|
|
*/
|
|
|
|
VOID
|
|
WireToHostFormat16(
|
|
IN WORD wWireFormat,
|
|
IN OUT PBYTE pHostFormat
|
|
)
|
|
{
|
|
*pHostFormat = ((*((PBYTE)(&wWireFormat)+0) << 8) +
|
|
(*((PBYTE)(&wWireFormat)+1)));
|
|
}
|
|
|
|
|
|
/// Get the current working directory and appends dllName (input param) to it.
|
|
DWORD GetFullPath(
|
|
OUT _Out_ LPWSTR &pathName,
|
|
IN OUT DWORD &pathNameLength,
|
|
IN _In_ LPWSTR dllName,
|
|
IN DWORD sizeofDllNameInBytes
|
|
)
|
|
{
|
|
DWORD retCode = ERROR_SUCCESS;
|
|
DWORD bufferLength = 0;
|
|
|
|
pathName = NULL;
|
|
|
|
// Get the length that needs to be allocated for getting the current directory.
|
|
bufferLength = GetCurrentDirectory(0, NULL);
|
|
if(!bufferLength)
|
|
{
|
|
retCode = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Buffer Length is the number of Wide Characters including the NULL character.
|
|
// We need to calculate the total number of bytes to be allocated.
|
|
bufferLength = (bufferLength - 1) * sizeof(WCHAR);
|
|
bufferLength += sizeof(WCHAR); // For the intermediate '\'
|
|
bufferLength += sizeofDllNameInBytes;
|
|
|
|
pathNameLength = bufferLength;
|
|
|
|
retCode = AllocateMemory(bufferLength, (PVOID *)&pathName);
|
|
if(retCode != ERROR_SUCCESS)
|
|
goto Cleanup;
|
|
|
|
// Actually get the directory path.
|
|
bufferLength = GetCurrentDirectory(pathNameLength, pathName);
|
|
if(bufferLength == 0)
|
|
goto Cleanup;
|
|
|
|
// Append "\"
|
|
CopyMemory(pathName + bufferLength, L"\\", sizeof(WCHAR));
|
|
|
|
// Append DllName.
|
|
CopyMemory(pathName + bufferLength + 1, dllName, sizeofDllNameInBytes);
|
|
|
|
Cleanup:
|
|
if((pathName != NULL) &&
|
|
((retCode != ERROR_SUCCESS) || (bufferLength == 0)))
|
|
FreeMemory((PVOID *)&pathName);
|
|
|
|
return retCode;
|
|
}
|
|
|
|
/**
|
|
* Report a message to the trace log.
|
|
*
|
|
* This function reports the specified message to a file in
|
|
* \c %SystemRoot%\Tracing\[TraceFileName.log], where \c TraceFileName is the
|
|
* string used in the TraceRegister() call. This tracing
|
|
* log can help when trying to debug issues on Eap Methods on clients & servers where
|
|
* physical access is not possible, or where debuggers can't be run easily
|
|
*
|
|
* @param Format [in] An output string format specification, which can
|
|
* include printf-style format values (ie, "%d").
|
|
*
|
|
* @param ... [in] A number of optional arguments, corresponding to
|
|
* the number of format specifiers in the Format
|
|
* parameter.
|
|
*/
|
|
VOID
|
|
EapTrace(
|
|
IN _In_ CHAR* Format,
|
|
...
|
|
)
|
|
{
|
|
va_list arglist;
|
|
|
|
va_start(arglist, Format);
|
|
|
|
/// The default level assigned to each trace message.
|
|
DWORD g_DefaultTraceLevel = 0x00010000;
|
|
|
|
TraceVprintfExA(g_dwEapTraceId,
|
|
g_DefaultTraceLevel | TRACE_USE_MASK | TRACE_USE_MSEC,
|
|
Format,
|
|
arglist);
|
|
|
|
va_end(arglist);
|
|
}
|
|
|
|
} // End "namespace SDK_METHOD_SAMPLE_COMMON
|