|
|
/*++
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); }
|