windows-nt/Source/XPSP1/NT/net/layer2svc/eapol/service/eltrace.c
2020-09-26 16:20:57 +08:00

1387 lines
37 KiB
C

/*++
Copyright (c) 2000, Microsoft Corporation
Module Name:
eltrace.c
Abstract:
Routines for database logging
Revision History:
sachins, September 05 2001, Created
--*/
#include "pcheapol.h"
#pragma hdrstop
#define WZCSVC_DLL_PATH L"%SystemRoot%\\system32\\wzcsvc.dll"
WCHAR *EAPOLStates[] =
{
L"LOGOFF",
L"DISCONNECTED",
L"CONNECTING",
L"ACQUIRED",
L"AUTHENTICATING",
L"HELD",
L"AUTHENTICATED",
L"UNDEFINED"
};
WCHAR *EAPOLAuthTypes[] =
{
L"Guest",
L"User",
L"Machine"
};
WCHAR *EAPOLPacketTypes[] =
{
L"EAP-Packet",
L"EAPOL-Start",
L"EAPOL-Logoff",
L"EAPOL-Key",
L"Undefined"
};
WCHAR *EAPOLEAPPacketTypes[] =
{
L"", // "0" is undefined EAP Type
L"EAP-Request",
L"EAP-Response",
L"EAP-Success",
L"EAP-Failure"
};
DWORD
DbFormatEAPOLEventVA (
WCHAR *pwszMessage,
DWORD dwEventId,
...
)
{
va_list argList;
DWORD dwRetCode = NO_ERROR;
do
{
va_start (argList, dwEventId);
if ((dwRetCode = DbFormatEAPOLEvent (
pwszMessage,
dwEventId,
&argList)) != NO_ERROR)
{
TRACE1 (ANY, "DbFormatEAPOLEventVA: DbFormatEAPOLEvent failed with error %ld", dwRetCode);
break;
}
}
while (FALSE);
return dwRetCode;
};
DWORD
DbFormatEAPOLEvent (
WCHAR *pwszMessage,
DWORD dwEventId,
va_list *pargList
)
{
HMODULE hDll = NULL;
DWORD dwRetCode = NO_ERROR;
do
{
hDll = g_hInstance;
if (FormatMessage (
FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_MAX_WIDTH_MASK,
WZCGetSPResModule(),
dwEventId,
0,
pwszMessage,
MAX_WMESG_SIZE,
pargList) == 0)
{
dwRetCode = GetLastError();
TRACE1 (ANY, "DbFormatEAPOLEvent: FormatMessage failed with error %ld", dwRetCode);
break;
}
}
while (FALSE);
return dwRetCode;
};
DWORD
DbLogPCBEvent (
DWORD dwCategory,
EAPOL_PCB *pPCB,
DWORD dwEventId,
...
)
{
WCHAR wszMessage[MAX_WMESG_SIZE];
WCHAR wszContext[MAX_WMESG_SIZE];
WCHAR wszSrcAddr[3*SIZE_MAC_ADDR];
WCHAR wszDstAddr[3*SIZE_MAC_ADDR];
WCHAR wsSSID[MAX_SSID_LEN+1];
va_list argList;
WZC_DB_RECORD dbrecord;
HMODULE hDll = NULL;
DWORD dwRetCode = NO_ERROR;
do
{
BOOL bLogEnabled;
EnterCriticalSection(&g_wzcInternalCtxt.csContext);
bLogEnabled = ((g_wzcInternalCtxt.wzcContext.dwFlags & WZC_CTXT_LOGGING_ON) != 0);
LeaveCriticalSection(&g_wzcInternalCtxt.csContext);
// If the database is not opened or the logging functionality is disabled,
// do not record any thing
if (!bLogEnabled || !IsDBOpened())
break;
va_start (argList, dwEventId);
ZeroMemory ((PVOID)wszMessage, MAX_WMESG_SIZE*sizeof(WCHAR));
ZeroMemory ((PVOID)wszContext, MAX_WMESG_SIZE*sizeof(WCHAR));
ZeroMemory ((PVOID)wszSrcAddr,3*SIZE_MAC_ADDR*sizeof(WCHAR));
ZeroMemory ((PVOID)wszDstAddr,3*SIZE_MAC_ADDR*sizeof(WCHAR));
if ((dwRetCode = DbFormatEAPOLEvent (
wszMessage,
dwEventId,
&argList
)) != NO_ERROR)
{
TRACE1 (ANY, "DbLogPCBEvent: DbFormatEAPOLEvent failed with error %ld", dwRetCode);
break;
}
ZeroMemory ((PVOID)&dbrecord, sizeof(WZC_DB_RECORD));
dbrecord.componentid = DBLOG_COMPID_EAPOL;
dbrecord.category = dwCategory;
dbrecord.message.pData = (PBYTE)wszMessage;
dbrecord.message.dwDataLen = (wcslen(wszMessage) + 1)*sizeof(WCHAR);
dbrecord.localmac.pData = (PBYTE)wszSrcAddr;
dbrecord.localmac.dwDataLen = 3*SIZE_MAC_ADDR*sizeof(WCHAR);
dbrecord.remotemac.pData = (PBYTE)wszDstAddr;
dbrecord.remotemac.dwDataLen = 3*SIZE_MAC_ADDR*sizeof(WCHAR);
dbrecord.ssid.pData = NULL;
dbrecord.ssid.dwDataLen = 0;
dbrecord.context.pData = NULL;
dbrecord.context.dwDataLen = 0;
if (pPCB != NULL)
{
if ((dwRetCode = ElFormatPCBContext (
pPCB,
wszContext
)) != NO_ERROR)
{
TRACE1 (ANY, "DbLogPCBEvent: ElFormatPCBContext failed with error %ld", dwRetCode);
break;
}
dbrecord.context.pData = (CHAR *)wszContext;
dbrecord.context.dwDataLen = (wcslen(wszContext) + 1)*sizeof(WCHAR);
MACADDR_BYTE_TO_WSTR(pPCB->bSrcMacAddr, wszSrcAddr);
MACADDR_BYTE_TO_WSTR(pPCB->bDestMacAddr, wszDstAddr);
// Append the network-name / SSID
if (pPCB->pSSID != NULL)
{
ZeroMemory ((PVOID)wsSSID, (MAX_SSID_LEN+1)*sizeof(WCHAR));
if (0 == MultiByteToWideChar (
CP_ACP,
0,
pPCB->pSSID->Ssid,
pPCB->pSSID->SsidLength,
wsSSID,
MAX_SSID_LEN+1))
{
dwRetCode = GetLastError();
TRACE1 (ANY, "DbLogPCBEvent: MultiByteToWideChar failed with error %ld",
dwRetCode);
break;
}
dbrecord.ssid.pData = (PBYTE)wsSSID;
dbrecord.ssid.dwDataLen = (pPCB->pSSID->SsidLength+1)*sizeof(WCHAR);
}
}
// Create a new record
if ((dwRetCode = AddWZCDbLogRecord(NULL, 0, &dbrecord, NULL)) != NO_ERROR)
{
TRACE1 (ANY, "DbLogPCBEvent: AppMonAppendRecord failed with error %ld",
dwRetCode);
}
}
while (FALSE);
if (hDll != NULL)
{
FreeLibrary(hDll);
}
return dwRetCode;
}
//
// ElParsePacket
//
// Description:
//
// Function called to parse an ethernet 802.1X packet
//
// Arguments:
// pbPkt - pointer to packet
// dwLength - packet length
// fReceived - Y=>Received packet, N=>Sending packet
//
// Return Values:
//
DWORD
ElParsePacket (
IN PBYTE pbPkt,
IN DWORD dwLength,
IN BOOLEAN fReceived
)
{
EAPOL_BUFFER *pEapolBuffer = NULL;
ETH_HEADER *pEthHdr = NULL;
EAPOL_PACKET *pEapolPkt = NULL;
PPP_EAP_PACKET *pEapPkt = NULL;
BYTE *pBuffer = NULL;
BOOLEAN ReqId = FALSE; // EAPOL state machine local variables
DWORD i, j;
WCHAR wszSrcAddr[3*SIZE_MAC_ADDR];
WCHAR wszDstAddr[3*SIZE_MAC_ADDR];
DWORD dwRetCode = NO_ERROR;
pBuffer = (BYTE *)pbPkt;
do
{
// Validate packet length
// Should be atleast ETH_HEADER and first 4 required bytes of
// EAPOL_PACKET
if (dwLength < (sizeof(ETH_HEADER) + 4))
{
break;
}
// If the source address is same as the local MAC address, it is a
// multicast packet copy sent out being received
pEthHdr = (ETH_HEADER *)pBuffer;
ZeroMemory (wszSrcAddr,3*SIZE_MAC_ADDR*sizeof(WCHAR));
ZeroMemory (wszDstAddr,3*SIZE_MAC_ADDR*sizeof(WCHAR));
MACADDR_BYTE_TO_WSTR (pEthHdr->bSrcAddr, wszSrcAddr);
MACADDR_BYTE_TO_WSTR (pEthHdr->bDstAddr, wszDstAddr);
// Verify if the packet contains a 802.1P tag. If so, skip the 4 bytes
// after the src+dest mac addresses
if ((WireToHostFormat16(pBuffer + sizeof(ETH_HEADER)) == EAPOL_8021P_TAG_TYPE))
{
pEapolPkt = (EAPOL_PACKET *)(pBuffer + sizeof(ETH_HEADER) + 4);
}
else
{
pEapolPkt = (EAPOL_PACKET *)(pBuffer + sizeof(ETH_HEADER));
}
// EAPOL packet type should be valid
if ((pEapolPkt->PacketType != EAP_Packet) &&
(pEapolPkt->PacketType != EAPOL_Start) &&
(pEapolPkt->PacketType != EAPOL_Logoff) &&
(pEapolPkt->PacketType != EAPOL_Key))
{
break;
}
// Determine the value of local EAPOL state variables
if (pEapolPkt->PacketType == EAP_Packet)
{
// Validate length of packet for EAP
// Should be atleast (ETH_HEADER+EAPOL_PACKET)
if (dwLength < (sizeof (ETH_HEADER) + sizeof (EAPOL_PACKET)))
{
TRACE1 (EAPOL, "ProcessReceivedPacket: Invalid length of EAP packet %d. Ignoring packet",
dwLength);
dwRetCode = ERROR_INVALID_PACKET_LENGTH_OR_ID;
break;
}
pEapPkt = (PPP_EAP_PACKET *)pEapolPkt->PacketBody;
if ((pEapPkt->Code == EAPCODE_Request) ||
(pEapPkt->Code == EAPCODE_Response))
{
// Validate length of packet for EAP-Request packet
// Should be atleast (ETH_HEADER+EAPOL_PACKET-1+PPP_EAP_PACKET)
if (dwLength < (sizeof (ETH_HEADER) + sizeof(EAPOL_PACKET)-1
+ sizeof (PPP_EAP_PACKET)))
{
dwRetCode = ERROR_INVALID_PACKET_LENGTH_OR_ID;
break;
}
if (pEapPkt->Data[0] == EAPTYPE_Identity)
{
ReqId = TRUE;
}
}
else if ((pEapPkt->Code == EAPCODE_Success) ||
(pEapPkt->Code == EAPCODE_Failure))
{
}
else
{
// Invalid type
dwRetCode = ERROR_INVALID_PACKET;
break;
}
DbLogPCBEvent (
DBLOG_CATEG_PACKET,
NULL,
EAPOL_PROCESS_PACKET_EAPOL_EAP,
fReceived?L"Received":L"Sent",
wszDstAddr,
wszSrcAddr,
EAPOLPacketTypes[pEapolPkt->PacketType],
WireToHostFormat16(pEapolPkt->PacketBodyLength),
EAPOLEAPPacketTypes[(DWORD)pEapPkt->Code],
pEapPkt->Id,
WireToHostFormat16(pEapPkt->Length),
ReqId?L"[Identity]":L""
);
}
else
{
DbLogPCBEvent (
DBLOG_CATEG_PACKET,
NULL,
EAPOL_PROCESS_PACKET_EAPOL,
fReceived?L"Received":L"Sent",
wszDstAddr,
wszSrcAddr,
EAPOLPacketTypes[pEapolPkt->PacketType]
);
}
}
while (FALSE);
return 0;
}
//
// ElFormatPCBContext
//
// Description:
//
// Function called to format PCB context details
//
// Arguments:
// pPCB - Pointer to PCB
// pwszContext - Context buffer
//
// Return Values:
//
DWORD
ElFormatPCBContext (
IN EAPOL_PCB *pPCB,
IN OUT WCHAR *pwszContext
)
{
DWORD i, j;
DWORD dwRetCode = NO_ERROR;
do
{
if ((dwRetCode = DbFormatEAPOLEventVA (
pwszContext,
EAPOL_STATE_DETAILS,
pPCB->pszIdentity?pPCB->pszIdentity:NULL,
EAPOLStates[((pPCB->State < EAPOLSTATE_LOGOFF) || (pPCB->State > EAPOLSTATE_AUTHENTICATED))?EAPOLSTATE_UNDEFINED:pPCB->State],
EAPOLAuthTypes[pPCB->PreviousAuthenticationType],
pPCB->dwEAPOLAuthMode,
pPCB->dwEapTypeToBeUsed,
pPCB->dwAuthFailCount)) != NO_ERROR)
{
break;
}
}
while (FALSE);
return dwRetCode;
}
//
// fFileTimeToStr
//
// Description:
//
// Converts FileTime to a printable form in *ppwszTime. If the function returns
// TRUE, the caller must ultimately call LocalFree(*ppwszTime).
//
// Arguments:
// pPCB - Pointer to PCB
//
// Return Values:
// TRUE: Success
// FALSE: Failure
BOOL
fFileTimeToStr (
IN FILETIME FileTime,
OUT WCHAR** ppwszTime
)
{
SYSTEMTIME SystemTime;
FILETIME LocalTime;
int nBytesDate;
int nBytesTime;
WCHAR* pwszTemp = NULL;
BOOL fRet = FALSE;
RTASSERT(NULL != ppwszTime);
if (!FileTimeToLocalFileTime(&FileTime, &LocalTime))
{
EapolTrace ("FileTimeToLocalFileTime(%d %d) failed and returned %d",
FileTime.dwLowDateTime, FileTime.dwHighDateTime,
GetLastError());
goto LDone;
}
if (!FileTimeToSystemTime(&LocalTime, &SystemTime))
{
EapolTrace ("FileTimeToSystemTime(%d %d) failed and returned %d",
LocalTime.dwLowDateTime, LocalTime.dwHighDateTime,
GetLastError());
goto LDone;
}
nBytesDate = GetDateFormat(LOCALE_USER_DEFAULT, 0, &SystemTime, NULL,
NULL, 0);
if (0 == nBytesDate)
{
EapolTrace ("GetDateFormat(%d %d %d %d %d %d %d %d) failed and "
"returned %d",
SystemTime.wYear, SystemTime.wMonth, SystemTime.wDayOfWeek,
SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute,
SystemTime.wSecond, SystemTime.wMilliseconds,
GetLastError());
goto LDone;
}
nBytesTime = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &SystemTime, NULL,
NULL, 0);
if (0 == nBytesTime)
{
EapolTrace ("GetTimeFormat(%d %d %d %d %d %d %d %d) failed and "
"returned %d",
SystemTime.wYear, SystemTime.wMonth, SystemTime.wDayOfWeek,
SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute,
SystemTime.wSecond, SystemTime.wMilliseconds,
GetLastError());
goto LDone;
}
pwszTemp = LocalAlloc(LPTR, (nBytesDate + nBytesTime)*sizeof(WCHAR));
if (NULL == pwszTemp)
{
EapolTrace ("LocalAlloc failed and returned %d", GetLastError());
goto LDone;
}
if (0 == GetDateFormat(LOCALE_USER_DEFAULT, 0, &SystemTime, NULL,
pwszTemp, nBytesDate))
{
EapolTrace ("GetDateFormat(%d %d %d %d %d %d %d %d) failed and "
"returned %d",
SystemTime.wYear, SystemTime.wMonth, SystemTime.wDayOfWeek,
SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute,
SystemTime.wSecond, SystemTime.wMilliseconds,
GetLastError());
goto LDone;
}
pwszTemp[nBytesDate - 1] = L' ';
if (0 == GetTimeFormat(LOCALE_USER_DEFAULT, 0, &SystemTime, NULL,
pwszTemp + nBytesDate, nBytesTime))
{
EapolTrace ("GetTimeFormat(%d %d %d %d %d %d %d %d) failed and "
"returned %d",
SystemTime.wYear, SystemTime.wMonth, SystemTime.wDayOfWeek,
SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute,
SystemTime.wSecond, SystemTime.wMilliseconds,
GetLastError());
goto LDone;
}
*ppwszTime = pwszTemp;
pwszTemp = NULL;
fRet = TRUE;
LDone:
LocalFree(pwszTemp);
return(fRet);
}
//
// fByteToStr
//
// Description:
//
// Converts Byte stream to a printable form in *ppwszTime.
// If the function returns TRUE, the caller must ultimately call
// LocalFree(*ppwszStr).
//
// Arguments:
// pPCB - Pointer to PCB
//
// Return Values:
// TRUE: Success
// FALSE: Failure
BOOL
fByteToStr (
IN DWORD dwSizeOfData,
IN PBYTE pbData,
OUT WCHAR** ppwszStr
)
{
PWCHAR pwszTemp = NULL;
DWORD i = 0, j = 0;
BOOLEAN fResult = FALSE;
do
{
if ((pwszTemp = LocalAlloc (LPTR, (dwSizeOfData*2 + 1)*sizeof(WCHAR)))
== NULL)
break;
for (i=0; i<dwSizeOfData; i++)
{
BYTE nHex;
nHex = (pbData[i] & 0xf0) >> 4;
pwszTemp[j++] = HEX2WCHAR(nHex);
nHex = (pbData[i] & 0x0f);
pwszTemp[j++] = HEX2WCHAR(nHex);
}
pwszTemp[j] = L'\0';
*ppwszStr = pwszTemp;
pwszTemp = NULL;
fResult = TRUE;
}
while (FALSE);
if (pwszTemp != NULL)
{
LocalFree (pwszTemp);
}
return fResult;
}
//
// fSerialNumberByteToStr
//
// Description:
//
// Converts Byte stream to a printable form in *ppwszTime.
// If the function returns TRUE, the caller must ultimately call
// LocalFree(*ppwszStr).
//
// Arguments:
// pPCB - Pointer to PCB
//
// Return Values:
// TRUE: Success
// FALSE: Failure
BOOL
fSerialNumberByteToStr (
IN DWORD dwSizeOfData,
IN PBYTE pbData,
OUT WCHAR** ppwszStr
)
{
PWCHAR pwszTemp = NULL;
INT i = 0, j = 0;
BOOLEAN fResult = FALSE;
do
{
if ((pwszTemp = LocalAlloc (LPTR, (dwSizeOfData*2 + 1)*sizeof(WCHAR)))
== NULL)
break;
for (i=(dwSizeOfData-1); i>=0; i--)
{
BYTE nHex;
nHex = (pbData[i] & 0xf0) >> 4;
pwszTemp[j++] = HEX2WCHAR(nHex);
nHex = (pbData[i] & 0x0f);
pwszTemp[j++] = HEX2WCHAR(nHex);
}
pwszTemp[j] = L'\0';
*ppwszStr = pwszTemp;
pwszTemp = NULL;
fResult = TRUE;
}
while (FALSE);
if (pwszTemp != NULL)
{
LocalFree (pwszTemp);
}
return fResult;
}
//
// Gets the name in the cert pointed to by pCertContext, and converts
// it to a printable form in *ppwszName. If the function returns TRUE,
// the caller must ultimately call LocalFree(*ppwszName).
//
BOOL
FUserCertToStr(
IN PCCERT_CONTEXT pCertContext,
OUT WCHAR** ppwszName
)
{
DWORD dwExtensionIndex;
DWORD dwAltEntryIndex;
CERT_EXTENSION* pCertExtension;
CERT_ALT_NAME_INFO* pCertAltNameInfo;
CERT_ALT_NAME_ENTRY* pCertAltNameEntry;
CERT_NAME_VALUE* pCertNameValue;
DWORD dwCertAltNameInfoSize;
DWORD dwCertNameValueSize;
WCHAR* pwszName = NULL;
BOOL fExitOuterFor;
BOOL fExitInnerFor;
BOOL fRet = FALSE;
// See if cert has UPN in AltSubjectName->otherName
fExitOuterFor = FALSE;
for (dwExtensionIndex = 0;
dwExtensionIndex < pCertContext->pCertInfo->cExtension;
dwExtensionIndex++)
{
pCertAltNameInfo = NULL;
pCertExtension = pCertContext->pCertInfo->rgExtension+dwExtensionIndex;
if (strcmp(pCertExtension->pszObjId, szOID_SUBJECT_ALT_NAME2) != 0)
{
goto LOuterForEnd;
}
dwCertAltNameInfoSize = 0;
if (!CryptDecodeObjectEx(
pCertContext->dwCertEncodingType,
X509_ALTERNATE_NAME,
pCertExtension->Value.pbData,
pCertExtension->Value.cbData,
CRYPT_DECODE_ALLOC_FLAG,
NULL,
(VOID*)&pCertAltNameInfo,
&dwCertAltNameInfoSize))
{
goto LOuterForEnd;
}
fExitInnerFor = FALSE;
for (dwAltEntryIndex = 0;
dwAltEntryIndex < pCertAltNameInfo->cAltEntry;
dwAltEntryIndex++)
{
pCertNameValue = NULL;
pCertAltNameEntry = pCertAltNameInfo->rgAltEntry + dwAltEntryIndex;
if ( (CERT_ALT_NAME_OTHER_NAME !=
pCertAltNameEntry->dwAltNameChoice)
|| (NULL == pCertAltNameEntry->pOtherName)
|| (0 != strcmp(szOID_NT_PRINCIPAL_NAME,
pCertAltNameEntry->pOtherName->pszObjId)))
{
goto LInnerForEnd;
}
// We found a UPN!
dwCertNameValueSize = 0;
if (!CryptDecodeObjectEx(
pCertContext->dwCertEncodingType,
X509_UNICODE_ANY_STRING,
pCertAltNameEntry->pOtherName->Value.pbData,
pCertAltNameEntry->pOtherName->Value.cbData,
CRYPT_DECODE_ALLOC_FLAG,
NULL,
(VOID*)&pCertNameValue,
&dwCertNameValueSize))
{
goto LInnerForEnd;
}
// One extra char for the terminating NULL.
pwszName = LocalAlloc(LPTR, pCertNameValue->Value.cbData +
sizeof(WCHAR));
if (NULL == pwszName)
{
EapolTrace ("LocalAlloc failed and returned %d",
GetLastError());
fExitInnerFor = TRUE;
fExitOuterFor = TRUE;
goto LInnerForEnd;
}
CopyMemory(pwszName, pCertNameValue->Value.pbData,
pCertNameValue->Value.cbData);
*ppwszName = pwszName;
pwszName = NULL;
fRet = TRUE;
fExitInnerFor = TRUE;
fExitOuterFor = TRUE;
LInnerForEnd:
LocalFree(pCertNameValue);
if (fExitInnerFor)
{
break;
}
}
LOuterForEnd:
LocalFree(pCertAltNameInfo);
if (fExitOuterFor)
{
break;
}
}
LocalFree(pwszName);
return(fRet);
}
//
// Special function for getting the DNS machine name from the
// machine auth certificate
//
BOOL
FMachineAuthCertToStr
(
IN PCCERT_CONTEXT pCertContext,
OUT WCHAR ** ppwszName
)
{
DWORD dwExtensionIndex;
DWORD dwAltEntryIndex;
CERT_EXTENSION* pCertExtension;
CERT_ALT_NAME_INFO* pCertAltNameInfo;
CERT_ALT_NAME_ENTRY* pCertAltNameEntry;
DWORD dwCertAltNameInfoSize;
WCHAR* pwszName = NULL;
BOOL fExitOuterFor;
BOOL fExitInnerFor;
BOOL fRet = FALSE;
// See if cert has UPN in AltSubjectName->otherName
fExitOuterFor = FALSE;
for (dwExtensionIndex = 0;
dwExtensionIndex < pCertContext->pCertInfo->cExtension;
dwExtensionIndex++)
{
pCertAltNameInfo = NULL;
pCertExtension = pCertContext->pCertInfo->rgExtension+dwExtensionIndex;
if (strcmp(pCertExtension->pszObjId, szOID_SUBJECT_ALT_NAME2) != 0)
{
goto LOuterForEnd;
}
dwCertAltNameInfoSize = 0;
if (!CryptDecodeObjectEx(
pCertContext->dwCertEncodingType,
X509_ALTERNATE_NAME,
pCertExtension->Value.pbData,
pCertExtension->Value.cbData,
CRYPT_DECODE_ALLOC_FLAG,
NULL,
(VOID*)&pCertAltNameInfo,
&dwCertAltNameInfoSize))
{
goto LOuterForEnd;
}
fExitInnerFor = FALSE;
for (dwAltEntryIndex = 0;
dwAltEntryIndex < pCertAltNameInfo->cAltEntry;
dwAltEntryIndex++)
{
pCertAltNameEntry = pCertAltNameInfo->rgAltEntry + dwAltEntryIndex;
if ( (CERT_ALT_NAME_DNS_NAME !=
pCertAltNameEntry->dwAltNameChoice)
|| (NULL == pCertAltNameEntry->pwszDNSName)
)
{
goto LInnerForEnd;
}
// We found the DNS Name!
// One extra char for the terminating NULL.
pwszName = LocalAlloc(LPTR, wcslen( pCertAltNameEntry->pwszDNSName ) * sizeof(WCHAR) +
sizeof(WCHAR));
if (NULL == pwszName)
{
EapolTrace ("LocalAlloc failed and returned %d",
GetLastError());
fExitInnerFor = TRUE;
fExitOuterFor = TRUE;
goto LInnerForEnd;
}
wcscpy (pwszName, pCertAltNameEntry->pwszDNSName );
*ppwszName = pwszName;
pwszName = NULL;
fRet = TRUE;
fExitInnerFor = TRUE;
fExitOuterFor = TRUE;
LInnerForEnd:
if (fExitInnerFor)
{
break;
}
}
LOuterForEnd:
LocalFree(pCertAltNameInfo);
if (fExitOuterFor)
{
break;
}
}
LocalFree(pwszName);
return(fRet);
}
//
// Gets the name in the cert pointed to by pCertContext, and converts it
// to a printable form in *ppwszName. If the function returns TRUE, the
// caller must ultimately call LocalFree(*ppwszName).
//
BOOL
FOtherCertToStr(
IN PCCERT_CONTEXT pCertContext,
IN DWORD fFlags,
OUT WCHAR** ppwszName
)
{
WCHAR* pwszTemp = NULL;
DWORD dwSize;
BOOL fRet = FALSE;
RTASSERT(NULL != ppwszName);
// Fetch Machine UPN
if (fFlags == 0)
{
if (FMachineAuthCertToStr(pCertContext, &pwszTemp))
{
*ppwszName = pwszTemp;
pwszTemp = NULL;
fRet = TRUE;
goto LDone;
}
}
dwSize = CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE,
fFlags, NULL, NULL, 0);
// dwSize is the number of characters, including the terminating NULL.
if (dwSize <= 1)
{
EapolTrace ("CertGetNameString failed.");
goto LDone;
}
pwszTemp = LocalAlloc(LPTR, dwSize*sizeof(WCHAR));
if (NULL == pwszTemp)
{
EapolTrace ("LocalAlloc failed and returned %d", GetLastError());
goto LDone;
}
dwSize = CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE,
fFlags, NULL, pwszTemp, dwSize);
if (dwSize <= 1)
{
EapolTrace ("CertGetNameString failed.");
goto LDone;
}
*ppwszName = pwszTemp;
pwszTemp = NULL;
fRet = TRUE;
LDone:
LocalFree(pwszTemp);
return(fRet);
}
//
// Gets the name in the cert pointed to by pCertContext, and converts it
// to a printable form in *ppwszName. If the function returns TRUE, the
// caller must ultimately call LocalFree(*ppwszName).
//
BOOL
FCertToStr(
IN PCCERT_CONTEXT pCertContext,
IN DWORD fFlags,
IN BOOL fMachineCert,
OUT WCHAR** ppwszName
)
{
if (!fMachineCert)
{
if (FUserCertToStr(pCertContext, ppwszName))
{
return(TRUE);
}
}
return(FOtherCertToStr(pCertContext, fFlags, ppwszName));
}
//
// Stores the friendly name of the cert pointed to by pCertContext in
// *ppwszName. If the function returns TRUE, the caller must ultimately
// call LocalFree(*ppwszName).
//
BOOL
FGetFriendlyName(
IN PCCERT_CONTEXT pCertContext,
OUT WCHAR** ppwszName
)
{
WCHAR* pwszName = NULL;
DWORD dwBytes;
BOOL fRet = FALSE;
RTASSERT(NULL != ppwszName);
if (!CertGetCertificateContextProperty(pCertContext,
CERT_FRIENDLY_NAME_PROP_ID, NULL, &dwBytes))
{
// If there is no Friendly Name property, don't print an error stmt.
fRet = TRUE;
goto LDone;
}
pwszName = LocalAlloc(LPTR, dwBytes);
if (NULL == pwszName)
{
EapolTrace ("LocalAlloc failed and returned %d", GetLastError());
goto LDone;
}
if (!CertGetCertificateContextProperty(pCertContext,
CERT_FRIENDLY_NAME_PROP_ID, pwszName, &dwBytes))
{
EapolTrace ("CertGetCertificateContextProperty failed and "
"returned 0x%x", GetLastError());
goto LDone;
}
*ppwszName = pwszName;
pwszName = NULL;
fRet = TRUE;
LDone:
LocalFree(pwszName);
return(fRet);
}
//
// Get EKU Usage Blob out of the certificate Context
//
BOOL FGetEKUUsage (
IN PCCERT_CONTEXT pCertContext,
IN PEAPOL_CERT_NODE pNode
)
{
BOOL fRet = FALSE;
DWORD dwBytes = 0;
PCERT_ENHKEY_USAGE pUsage = NULL;
DWORD dwOidLength = 0;
DWORD dwIndex = 0;
DWORD dwErr = ERROR_SUCCESS;
EapolTrace ("FGetEKUUsage");
if (!CertGetEnhancedKeyUsage(pCertContext, 0, NULL, &dwBytes))
{
dwErr = GetLastError();
if (CRYPT_E_NOT_FOUND == dwErr)
{
EapolTrace ("No usage in cert");
fRet = TRUE;
goto LDone;
}
EapolTrace ("FGetEKUUsage failed and returned 0x%x", dwErr);
goto LDone;
}
pUsage = LocalAlloc(LPTR, dwBytes);
if (NULL == pUsage)
{
dwErr = GetLastError();
EapolTrace ("LocalAlloc failed and returned %d", dwErr);
goto LDone;
}
if (!CertGetEnhancedKeyUsage(pCertContext, 0, pUsage, &dwBytes))
{
dwErr = GetLastError();
EapolTrace ("FGetEKUUsage failed and returned 0x%x", dwErr);
goto LDone;
}
for (dwIndex = 0; dwIndex < pUsage->cUsageIdentifier; dwIndex++)
{
PCCRYPT_OID_INFO pInfo;
if ((pInfo = CryptFindOIDInfo (
CRYPT_OID_INFO_OID_KEY,
(void *) pUsage->rgpszUsageIdentifier[dwIndex],
0)) != NULL)
{
dwOidLength += (wcslen(pInfo->pwszName)+3)*sizeof(WCHAR);
}
}
pNode->pwszEKUUsage = LocalAlloc (LPTR, (dwOidLength+sizeof(WCHAR)));
for (dwIndex = 0; dwIndex < pUsage->cUsageIdentifier; dwIndex++)
{
PCCRYPT_OID_INFO pInfo;
if ((pInfo = CryptFindOIDInfo (
CRYPT_OID_INFO_OID_KEY,
(void *) pUsage->rgpszUsageIdentifier[dwIndex],
0)) != NULL)
{
EapolTrace ("EKU: %ws", pInfo->pwszName);
if (dwIndex != 0)
wcscat (pNode->pwszEKUUsage, L", ");
wcscat (pNode->pwszEKUUsage, pInfo->pwszName);
}
}
EapolTrace ("EKUUsage: %ws", pNode->pwszEKUUsage);
fRet = TRUE;
LDone:
if (pUsage != NULL)
{
LocalFree (pUsage);
}
return fRet;
}
//
// ElLogCertificateDetails
//
// Description:
//
// Function called to display certificate contents
//
// Arguments:
// pPCB - Pointer to PCB
//
// Return Values:
//
DWORD
ElLogCertificateDetails (
IN EAPOL_PCB *pPCB
)
{
EAPTLS_USER_PROPERTIES *pUserProp = NULL;
HCERTSTORE hCertStore = NULL;
PCCERT_CONTEXT pCert = NULL;
CRYPT_HASH_BLOB HashBlob;
DWORD dwVersion = 0;
EAPOL_CERT_NODE *pNode = NULL;
BYTE rgbHash[MAX_HASH_LEN];
DWORD cbHash = MAX_HASH_LEN;
BOOLEAN fRevertToSelf = FALSE;
PCERT_ENHKEY_USAGE pUsageInternal = NULL;
DWORD dwRetCode = NO_ERROR;
do
{
if (pPCB->pCustomAuthUserData == NULL)
{
EapolTrace ("Cannot log Cert detail, since NULL user properties");
break;
}
pUserProp = (EAPTLS_USER_PROPERTIES *)pPCB->pCustomAuthUserData->pbCustomAuthData;
if (pPCB->hUserToken)
{
if (!ImpersonateLoggedOnUser (pPCB->hUserToken))
{
dwRetCode = GetLastError();
EapolTrace ("ElLogCertificateDetails: ImpersonateLoggedOnUser failed with error %ld",
dwRetCode);
break;
}
fRevertToSelf = TRUE;
}
hCertStore = CertOpenStore (
CERT_STORE_PROV_SYSTEM,
0,
0,
CERT_STORE_READONLY_FLAG |
((pPCB->PreviousAuthenticationType == EAPOL_MACHINE_AUTHENTICATION)? CERT_SYSTEM_STORE_LOCAL_MACHINE : CERT_SYSTEM_STORE_CURRENT_USER),
L"MY"
);
if (hCertStore == NULL)
{
dwRetCode = GetLastError();
EapolTrace ("CertOpenStore failed with error %ld", dwRetCode);
break;
}
HashBlob.cbData = pUserProp->Hash.cbHash;
HashBlob.pbData = pUserProp->Hash.pbHash;
pCert = CertFindCertificateInStore (
hCertStore,
X509_ASN_ENCODING,
0,
CERT_FIND_HASH,
&HashBlob,
NULL
);
if (pCert == NULL)
{
dwRetCode = GetLastError();
EapolTrace ("CertFindCertificateInStore failed with error %ld",
dwRetCode);
break;
}
if (fRevertToSelf)
{
fRevertToSelf = FALSE;
if (!RevertToSelf())
{
dwRetCode = GetLastError();
EapolTrace ("ElLogCertificateDetails: Error in RevertToSelf = %ld",
dwRetCode);
dwRetCode = ERROR_BAD_IMPERSONATION_LEVEL;
break;
}
}
pNode = LocalAlloc(LPTR, sizeof(EAPOL_CERT_NODE));
if (pNode == NULL)
{
dwRetCode = GetLastError ();
break;
}
if (!CertGetCertificateContextProperty (
pCert,
CERT_SHA1_HASH_PROP_ID,
rgbHash,
&cbHash
))
{
dwRetCode = GetLastError();
EapolTrace ("CertGetCertificateContextProperty failed with error %ld");
break;
}
if ((!fByteToStr (sizeof(DWORD), (PBYTE)&(pCert->pCertInfo->dwVersion),
&(pNode->pwszVersion))) ||
(!fSerialNumberByteToStr (pCert->pCertInfo->SerialNumber.cbData,
pCert->pCertInfo->SerialNumber.pbData,
&(pNode->pwszSerialNumber))) ||
(!fFileTimeToStr (pCert->pCertInfo->NotAfter,
&(pNode->pwszValidTo))) ||
(!fFileTimeToStr (pCert->pCertInfo->NotBefore,
&(pNode->pwszValidFrom))) ||
(!fByteToStr (cbHash, rgbHash, &(pNode->pwszThumbprint))) ||
(!FCertToStr (pCert, 0, ((pPCB->PreviousAuthenticationType == EAPOL_MACHINE_AUTHENTICATION)? TRUE: FALSE), &(pNode->pwszDisplayName))) ||
(!FCertToStr (pCert, CERT_NAME_ISSUER_FLAG, TRUE, &(pNode->pwszIssuer))) ||
(!FGetFriendlyName(pCert, &(pNode->pwszFriendlyName)))
|| (!FGetEKUUsage (pCert, pNode)))
{
EapolTrace ("ElLogCertificateDetails: An internal string convert function failed");
// break;
}
DbLogPCBEvent (
DBLOG_CATEG_INFO,
pPCB,
EAPOL_CERTIFICATE_DETAILS,
EAPOLAuthTypes[pPCB->PreviousAuthenticationType],
pNode->pwszVersion,
pNode->pwszSerialNumber,
pNode->pwszIssuer,
pNode->pwszFriendlyName,
pNode->pwszDisplayName,
pNode->pwszEKUUsage,
pNode->pwszValidFrom,
pNode->pwszValidTo,
pNode->pwszThumbprint
);
}
while (FALSE);
if (pCert)
CertFreeCertificateContext (pCert);
if (hCertStore)
CertCloseStore (hCertStore, 0);
if (fRevertToSelf)
{
if (!RevertToSelf())
{
dwRetCode = GetLastError();
EapolTrace ("ElLogCertificateDetails: Error in RevertToSelf = %ld",
dwRetCode);
dwRetCode = ERROR_BAD_IMPERSONATION_LEVEL;
fRevertToSelf = FALSE;
}
}
if (pNode)
{
LocalFree(pNode->pwszVersion);
LocalFree(pNode->pwszSerialNumber);
LocalFree(pNode->pwszIssuer);
LocalFree(pNode->pwszFriendlyName);
LocalFree(pNode->pwszDisplayName);
LocalFree(pNode->pwszEKUUsage);
LocalFree(pNode->pwszValidFrom);
LocalFree(pNode->pwszValidTo);
LocalFree(pNode->pwszThumbprint);
LocalFree(pNode);
}
return dwRetCode;
}
//
// General tracing function
//
VOID
EapolTrace(
IN CHAR* Format,
...
)
{
va_list arglist;
va_start(arglist, Format);
if (TRACEID != INVALID_TRACEID)
TraceVprintfExA(TRACEID,
((DWORD)0xFFFF0000 | TRACE_USE_MASK),
Format,
arglist);
va_end(arglist);
}