Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1386 lines
37 KiB

  1. /*++
  2. Copyright (c) 2000, Microsoft Corporation
  3. Module Name:
  4. eltrace.c
  5. Abstract:
  6. Routines for database logging
  7. Revision History:
  8. sachins, September 05 2001, Created
  9. --*/
  10. #include "pcheapol.h"
  11. #pragma hdrstop
  12. #define WZCSVC_DLL_PATH L"%SystemRoot%\\system32\\wzcsvc.dll"
  13. WCHAR *EAPOLStates[] =
  14. {
  15. L"LOGOFF",
  16. L"DISCONNECTED",
  17. L"CONNECTING",
  18. L"ACQUIRED",
  19. L"AUTHENTICATING",
  20. L"HELD",
  21. L"AUTHENTICATED",
  22. L"UNDEFINED"
  23. };
  24. WCHAR *EAPOLAuthTypes[] =
  25. {
  26. L"Guest",
  27. L"User",
  28. L"Machine"
  29. };
  30. WCHAR *EAPOLPacketTypes[] =
  31. {
  32. L"EAP-Packet",
  33. L"EAPOL-Start",
  34. L"EAPOL-Logoff",
  35. L"EAPOL-Key",
  36. L"Undefined"
  37. };
  38. WCHAR *EAPOLEAPPacketTypes[] =
  39. {
  40. L"", // "0" is undefined EAP Type
  41. L"EAP-Request",
  42. L"EAP-Response",
  43. L"EAP-Success",
  44. L"EAP-Failure"
  45. };
  46. DWORD
  47. DbFormatEAPOLEventVA (
  48. WCHAR *pwszMessage,
  49. DWORD dwEventId,
  50. ...
  51. )
  52. {
  53. va_list argList;
  54. DWORD dwRetCode = NO_ERROR;
  55. do
  56. {
  57. va_start (argList, dwEventId);
  58. if ((dwRetCode = DbFormatEAPOLEvent (
  59. pwszMessage,
  60. dwEventId,
  61. &argList)) != NO_ERROR)
  62. {
  63. TRACE1 (ANY, "DbFormatEAPOLEventVA: DbFormatEAPOLEvent failed with error %ld", dwRetCode);
  64. break;
  65. }
  66. }
  67. while (FALSE);
  68. return dwRetCode;
  69. };
  70. DWORD
  71. DbFormatEAPOLEvent (
  72. WCHAR *pwszMessage,
  73. DWORD dwEventId,
  74. va_list *pargList
  75. )
  76. {
  77. HMODULE hDll = NULL;
  78. DWORD dwRetCode = NO_ERROR;
  79. do
  80. {
  81. hDll = g_hInstance;
  82. if (FormatMessage (
  83. FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_MAX_WIDTH_MASK,
  84. WZCGetSPResModule(),
  85. dwEventId,
  86. 0,
  87. pwszMessage,
  88. MAX_WMESG_SIZE,
  89. pargList) == 0)
  90. {
  91. dwRetCode = GetLastError();
  92. TRACE1 (ANY, "DbFormatEAPOLEvent: FormatMessage failed with error %ld", dwRetCode);
  93. break;
  94. }
  95. }
  96. while (FALSE);
  97. return dwRetCode;
  98. };
  99. DWORD
  100. DbLogPCBEvent (
  101. DWORD dwCategory,
  102. EAPOL_PCB *pPCB,
  103. DWORD dwEventId,
  104. ...
  105. )
  106. {
  107. WCHAR wszMessage[MAX_WMESG_SIZE];
  108. WCHAR wszContext[MAX_WMESG_SIZE];
  109. WCHAR wszSrcAddr[3*SIZE_MAC_ADDR];
  110. WCHAR wszDstAddr[3*SIZE_MAC_ADDR];
  111. WCHAR wsSSID[MAX_SSID_LEN+1];
  112. va_list argList;
  113. WZC_DB_RECORD dbrecord;
  114. HMODULE hDll = NULL;
  115. DWORD dwRetCode = NO_ERROR;
  116. do
  117. {
  118. BOOL bLogEnabled;
  119. EnterCriticalSection(&g_wzcInternalCtxt.csContext);
  120. bLogEnabled = ((g_wzcInternalCtxt.wzcContext.dwFlags & WZC_CTXT_LOGGING_ON) != 0);
  121. LeaveCriticalSection(&g_wzcInternalCtxt.csContext);
  122. // If the database is not opened or the logging functionality is disabled,
  123. // do not record any thing
  124. if (!bLogEnabled || !IsDBOpened())
  125. break;
  126. va_start (argList, dwEventId);
  127. ZeroMemory ((PVOID)wszMessage, MAX_WMESG_SIZE*sizeof(WCHAR));
  128. ZeroMemory ((PVOID)wszContext, MAX_WMESG_SIZE*sizeof(WCHAR));
  129. ZeroMemory ((PVOID)wszSrcAddr,3*SIZE_MAC_ADDR*sizeof(WCHAR));
  130. ZeroMemory ((PVOID)wszDstAddr,3*SIZE_MAC_ADDR*sizeof(WCHAR));
  131. if ((dwRetCode = DbFormatEAPOLEvent (
  132. wszMessage,
  133. dwEventId,
  134. &argList
  135. )) != NO_ERROR)
  136. {
  137. TRACE1 (ANY, "DbLogPCBEvent: DbFormatEAPOLEvent failed with error %ld", dwRetCode);
  138. break;
  139. }
  140. ZeroMemory ((PVOID)&dbrecord, sizeof(WZC_DB_RECORD));
  141. dbrecord.componentid = DBLOG_COMPID_EAPOL;
  142. dbrecord.category = dwCategory;
  143. dbrecord.message.pData = (PBYTE)wszMessage;
  144. dbrecord.message.dwDataLen = (wcslen(wszMessage) + 1)*sizeof(WCHAR);
  145. dbrecord.localmac.pData = (PBYTE)wszSrcAddr;
  146. dbrecord.localmac.dwDataLen = 3*SIZE_MAC_ADDR*sizeof(WCHAR);
  147. dbrecord.remotemac.pData = (PBYTE)wszDstAddr;
  148. dbrecord.remotemac.dwDataLen = 3*SIZE_MAC_ADDR*sizeof(WCHAR);
  149. dbrecord.ssid.pData = NULL;
  150. dbrecord.ssid.dwDataLen = 0;
  151. dbrecord.context.pData = NULL;
  152. dbrecord.context.dwDataLen = 0;
  153. if (pPCB != NULL)
  154. {
  155. if ((dwRetCode = ElFormatPCBContext (
  156. pPCB,
  157. wszContext
  158. )) != NO_ERROR)
  159. {
  160. TRACE1 (ANY, "DbLogPCBEvent: ElFormatPCBContext failed with error %ld", dwRetCode);
  161. break;
  162. }
  163. dbrecord.context.pData = (CHAR *)wszContext;
  164. dbrecord.context.dwDataLen = (wcslen(wszContext) + 1)*sizeof(WCHAR);
  165. MACADDR_BYTE_TO_WSTR(pPCB->bSrcMacAddr, wszSrcAddr);
  166. MACADDR_BYTE_TO_WSTR(pPCB->bDestMacAddr, wszDstAddr);
  167. // Append the network-name / SSID
  168. if (pPCB->pSSID != NULL)
  169. {
  170. ZeroMemory ((PVOID)wsSSID, (MAX_SSID_LEN+1)*sizeof(WCHAR));
  171. if (0 == MultiByteToWideChar (
  172. CP_ACP,
  173. 0,
  174. pPCB->pSSID->Ssid,
  175. pPCB->pSSID->SsidLength,
  176. wsSSID,
  177. MAX_SSID_LEN+1))
  178. {
  179. dwRetCode = GetLastError();
  180. TRACE1 (ANY, "DbLogPCBEvent: MultiByteToWideChar failed with error %ld",
  181. dwRetCode);
  182. break;
  183. }
  184. dbrecord.ssid.pData = (PBYTE)wsSSID;
  185. dbrecord.ssid.dwDataLen = (pPCB->pSSID->SsidLength+1)*sizeof(WCHAR);
  186. }
  187. }
  188. // Create a new record
  189. if ((dwRetCode = AddWZCDbLogRecord(NULL, 0, &dbrecord, NULL)) != NO_ERROR)
  190. {
  191. TRACE1 (ANY, "DbLogPCBEvent: AppMonAppendRecord failed with error %ld",
  192. dwRetCode);
  193. }
  194. }
  195. while (FALSE);
  196. if (hDll != NULL)
  197. {
  198. FreeLibrary(hDll);
  199. }
  200. return dwRetCode;
  201. }
  202. //
  203. // ElParsePacket
  204. //
  205. // Description:
  206. //
  207. // Function called to parse an ethernet 802.1X packet
  208. //
  209. // Arguments:
  210. // pbPkt - pointer to packet
  211. // dwLength - packet length
  212. // fReceived - Y=>Received packet, N=>Sending packet
  213. //
  214. // Return Values:
  215. //
  216. DWORD
  217. ElParsePacket (
  218. IN PBYTE pbPkt,
  219. IN DWORD dwLength,
  220. IN BOOLEAN fReceived
  221. )
  222. {
  223. EAPOL_BUFFER *pEapolBuffer = NULL;
  224. ETH_HEADER *pEthHdr = NULL;
  225. EAPOL_PACKET *pEapolPkt = NULL;
  226. PPP_EAP_PACKET *pEapPkt = NULL;
  227. BYTE *pBuffer = NULL;
  228. BOOLEAN ReqId = FALSE; // EAPOL state machine local variables
  229. DWORD i, j;
  230. WCHAR wszSrcAddr[3*SIZE_MAC_ADDR];
  231. WCHAR wszDstAddr[3*SIZE_MAC_ADDR];
  232. DWORD dwRetCode = NO_ERROR;
  233. pBuffer = (BYTE *)pbPkt;
  234. do
  235. {
  236. // Validate packet length
  237. // Should be atleast ETH_HEADER and first 4 required bytes of
  238. // EAPOL_PACKET
  239. if (dwLength < (sizeof(ETH_HEADER) + 4))
  240. {
  241. break;
  242. }
  243. // If the source address is same as the local MAC address, it is a
  244. // multicast packet copy sent out being received
  245. pEthHdr = (ETH_HEADER *)pBuffer;
  246. ZeroMemory (wszSrcAddr,3*SIZE_MAC_ADDR*sizeof(WCHAR));
  247. ZeroMemory (wszDstAddr,3*SIZE_MAC_ADDR*sizeof(WCHAR));
  248. MACADDR_BYTE_TO_WSTR (pEthHdr->bSrcAddr, wszSrcAddr);
  249. MACADDR_BYTE_TO_WSTR (pEthHdr->bDstAddr, wszDstAddr);
  250. // Verify if the packet contains a 802.1P tag. If so, skip the 4 bytes
  251. // after the src+dest mac addresses
  252. if ((WireToHostFormat16(pBuffer + sizeof(ETH_HEADER)) == EAPOL_8021P_TAG_TYPE))
  253. {
  254. pEapolPkt = (EAPOL_PACKET *)(pBuffer + sizeof(ETH_HEADER) + 4);
  255. }
  256. else
  257. {
  258. pEapolPkt = (EAPOL_PACKET *)(pBuffer + sizeof(ETH_HEADER));
  259. }
  260. // EAPOL packet type should be valid
  261. if ((pEapolPkt->PacketType != EAP_Packet) &&
  262. (pEapolPkt->PacketType != EAPOL_Start) &&
  263. (pEapolPkt->PacketType != EAPOL_Logoff) &&
  264. (pEapolPkt->PacketType != EAPOL_Key))
  265. {
  266. break;
  267. }
  268. // Determine the value of local EAPOL state variables
  269. if (pEapolPkt->PacketType == EAP_Packet)
  270. {
  271. // Validate length of packet for EAP
  272. // Should be atleast (ETH_HEADER+EAPOL_PACKET)
  273. if (dwLength < (sizeof (ETH_HEADER) + sizeof (EAPOL_PACKET)))
  274. {
  275. TRACE1 (EAPOL, "ProcessReceivedPacket: Invalid length of EAP packet %d. Ignoring packet",
  276. dwLength);
  277. dwRetCode = ERROR_INVALID_PACKET_LENGTH_OR_ID;
  278. break;
  279. }
  280. pEapPkt = (PPP_EAP_PACKET *)pEapolPkt->PacketBody;
  281. if ((pEapPkt->Code == EAPCODE_Request) ||
  282. (pEapPkt->Code == EAPCODE_Response))
  283. {
  284. // Validate length of packet for EAP-Request packet
  285. // Should be atleast (ETH_HEADER+EAPOL_PACKET-1+PPP_EAP_PACKET)
  286. if (dwLength < (sizeof (ETH_HEADER) + sizeof(EAPOL_PACKET)-1
  287. + sizeof (PPP_EAP_PACKET)))
  288. {
  289. dwRetCode = ERROR_INVALID_PACKET_LENGTH_OR_ID;
  290. break;
  291. }
  292. if (pEapPkt->Data[0] == EAPTYPE_Identity)
  293. {
  294. ReqId = TRUE;
  295. }
  296. }
  297. else if ((pEapPkt->Code == EAPCODE_Success) ||
  298. (pEapPkt->Code == EAPCODE_Failure))
  299. {
  300. }
  301. else
  302. {
  303. // Invalid type
  304. dwRetCode = ERROR_INVALID_PACKET;
  305. break;
  306. }
  307. DbLogPCBEvent (
  308. DBLOG_CATEG_PACKET,
  309. NULL,
  310. EAPOL_PROCESS_PACKET_EAPOL_EAP,
  311. fReceived?L"Received":L"Sent",
  312. wszDstAddr,
  313. wszSrcAddr,
  314. EAPOLPacketTypes[pEapolPkt->PacketType],
  315. WireToHostFormat16(pEapolPkt->PacketBodyLength),
  316. EAPOLEAPPacketTypes[(DWORD)pEapPkt->Code],
  317. pEapPkt->Id,
  318. WireToHostFormat16(pEapPkt->Length),
  319. ReqId?L"[Identity]":L""
  320. );
  321. }
  322. else
  323. {
  324. DbLogPCBEvent (
  325. DBLOG_CATEG_PACKET,
  326. NULL,
  327. EAPOL_PROCESS_PACKET_EAPOL,
  328. fReceived?L"Received":L"Sent",
  329. wszDstAddr,
  330. wszSrcAddr,
  331. EAPOLPacketTypes[pEapolPkt->PacketType]
  332. );
  333. }
  334. }
  335. while (FALSE);
  336. return 0;
  337. }
  338. //
  339. // ElFormatPCBContext
  340. //
  341. // Description:
  342. //
  343. // Function called to format PCB context details
  344. //
  345. // Arguments:
  346. // pPCB - Pointer to PCB
  347. // pwszContext - Context buffer
  348. //
  349. // Return Values:
  350. //
  351. DWORD
  352. ElFormatPCBContext (
  353. IN EAPOL_PCB *pPCB,
  354. IN OUT WCHAR *pwszContext
  355. )
  356. {
  357. DWORD i, j;
  358. DWORD dwRetCode = NO_ERROR;
  359. do
  360. {
  361. if ((dwRetCode = DbFormatEAPOLEventVA (
  362. pwszContext,
  363. EAPOL_STATE_DETAILS,
  364. pPCB->pszIdentity?pPCB->pszIdentity:NULL,
  365. EAPOLStates[((pPCB->State < EAPOLSTATE_LOGOFF) || (pPCB->State > EAPOLSTATE_AUTHENTICATED))?EAPOLSTATE_UNDEFINED:pPCB->State],
  366. EAPOLAuthTypes[pPCB->PreviousAuthenticationType],
  367. pPCB->dwEAPOLAuthMode,
  368. pPCB->dwEapTypeToBeUsed,
  369. pPCB->dwAuthFailCount)) != NO_ERROR)
  370. {
  371. break;
  372. }
  373. }
  374. while (FALSE);
  375. return dwRetCode;
  376. }
  377. //
  378. // fFileTimeToStr
  379. //
  380. // Description:
  381. //
  382. // Converts FileTime to a printable form in *ppwszTime. If the function returns
  383. // TRUE, the caller must ultimately call LocalFree(*ppwszTime).
  384. //
  385. // Arguments:
  386. // pPCB - Pointer to PCB
  387. //
  388. // Return Values:
  389. // TRUE: Success
  390. // FALSE: Failure
  391. BOOL
  392. fFileTimeToStr (
  393. IN FILETIME FileTime,
  394. OUT WCHAR** ppwszTime
  395. )
  396. {
  397. SYSTEMTIME SystemTime;
  398. FILETIME LocalTime;
  399. int nBytesDate;
  400. int nBytesTime;
  401. WCHAR* pwszTemp = NULL;
  402. BOOL fRet = FALSE;
  403. RTASSERT(NULL != ppwszTime);
  404. if (!FileTimeToLocalFileTime(&FileTime, &LocalTime))
  405. {
  406. EapolTrace ("FileTimeToLocalFileTime(%d %d) failed and returned %d",
  407. FileTime.dwLowDateTime, FileTime.dwHighDateTime,
  408. GetLastError());
  409. goto LDone;
  410. }
  411. if (!FileTimeToSystemTime(&LocalTime, &SystemTime))
  412. {
  413. EapolTrace ("FileTimeToSystemTime(%d %d) failed and returned %d",
  414. LocalTime.dwLowDateTime, LocalTime.dwHighDateTime,
  415. GetLastError());
  416. goto LDone;
  417. }
  418. nBytesDate = GetDateFormat(LOCALE_USER_DEFAULT, 0, &SystemTime, NULL,
  419. NULL, 0);
  420. if (0 == nBytesDate)
  421. {
  422. EapolTrace ("GetDateFormat(%d %d %d %d %d %d %d %d) failed and "
  423. "returned %d",
  424. SystemTime.wYear, SystemTime.wMonth, SystemTime.wDayOfWeek,
  425. SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute,
  426. SystemTime.wSecond, SystemTime.wMilliseconds,
  427. GetLastError());
  428. goto LDone;
  429. }
  430. nBytesTime = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &SystemTime, NULL,
  431. NULL, 0);
  432. if (0 == nBytesTime)
  433. {
  434. EapolTrace ("GetTimeFormat(%d %d %d %d %d %d %d %d) failed and "
  435. "returned %d",
  436. SystemTime.wYear, SystemTime.wMonth, SystemTime.wDayOfWeek,
  437. SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute,
  438. SystemTime.wSecond, SystemTime.wMilliseconds,
  439. GetLastError());
  440. goto LDone;
  441. }
  442. pwszTemp = LocalAlloc(LPTR, (nBytesDate + nBytesTime)*sizeof(WCHAR));
  443. if (NULL == pwszTemp)
  444. {
  445. EapolTrace ("LocalAlloc failed and returned %d", GetLastError());
  446. goto LDone;
  447. }
  448. if (0 == GetDateFormat(LOCALE_USER_DEFAULT, 0, &SystemTime, NULL,
  449. pwszTemp, nBytesDate))
  450. {
  451. EapolTrace ("GetDateFormat(%d %d %d %d %d %d %d %d) failed and "
  452. "returned %d",
  453. SystemTime.wYear, SystemTime.wMonth, SystemTime.wDayOfWeek,
  454. SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute,
  455. SystemTime.wSecond, SystemTime.wMilliseconds,
  456. GetLastError());
  457. goto LDone;
  458. }
  459. pwszTemp[nBytesDate - 1] = L' ';
  460. if (0 == GetTimeFormat(LOCALE_USER_DEFAULT, 0, &SystemTime, NULL,
  461. pwszTemp + nBytesDate, nBytesTime))
  462. {
  463. EapolTrace ("GetTimeFormat(%d %d %d %d %d %d %d %d) failed and "
  464. "returned %d",
  465. SystemTime.wYear, SystemTime.wMonth, SystemTime.wDayOfWeek,
  466. SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute,
  467. SystemTime.wSecond, SystemTime.wMilliseconds,
  468. GetLastError());
  469. goto LDone;
  470. }
  471. *ppwszTime = pwszTemp;
  472. pwszTemp = NULL;
  473. fRet = TRUE;
  474. LDone:
  475. LocalFree(pwszTemp);
  476. return(fRet);
  477. }
  478. //
  479. // fByteToStr
  480. //
  481. // Description:
  482. //
  483. // Converts Byte stream to a printable form in *ppwszTime.
  484. // If the function returns TRUE, the caller must ultimately call
  485. // LocalFree(*ppwszStr).
  486. //
  487. // Arguments:
  488. // pPCB - Pointer to PCB
  489. //
  490. // Return Values:
  491. // TRUE: Success
  492. // FALSE: Failure
  493. BOOL
  494. fByteToStr (
  495. IN DWORD dwSizeOfData,
  496. IN PBYTE pbData,
  497. OUT WCHAR** ppwszStr
  498. )
  499. {
  500. PWCHAR pwszTemp = NULL;
  501. DWORD i = 0, j = 0;
  502. BOOLEAN fResult = FALSE;
  503. do
  504. {
  505. if ((pwszTemp = LocalAlloc (LPTR, (dwSizeOfData*2 + 1)*sizeof(WCHAR)))
  506. == NULL)
  507. break;
  508. for (i=0; i<dwSizeOfData; i++)
  509. {
  510. BYTE nHex;
  511. nHex = (pbData[i] & 0xf0) >> 4;
  512. pwszTemp[j++] = HEX2WCHAR(nHex);
  513. nHex = (pbData[i] & 0x0f);
  514. pwszTemp[j++] = HEX2WCHAR(nHex);
  515. }
  516. pwszTemp[j] = L'\0';
  517. *ppwszStr = pwszTemp;
  518. pwszTemp = NULL;
  519. fResult = TRUE;
  520. }
  521. while (FALSE);
  522. if (pwszTemp != NULL)
  523. {
  524. LocalFree (pwszTemp);
  525. }
  526. return fResult;
  527. }
  528. //
  529. // fSerialNumberByteToStr
  530. //
  531. // Description:
  532. //
  533. // Converts Byte stream to a printable form in *ppwszTime.
  534. // If the function returns TRUE, the caller must ultimately call
  535. // LocalFree(*ppwszStr).
  536. //
  537. // Arguments:
  538. // pPCB - Pointer to PCB
  539. //
  540. // Return Values:
  541. // TRUE: Success
  542. // FALSE: Failure
  543. BOOL
  544. fSerialNumberByteToStr (
  545. IN DWORD dwSizeOfData,
  546. IN PBYTE pbData,
  547. OUT WCHAR** ppwszStr
  548. )
  549. {
  550. PWCHAR pwszTemp = NULL;
  551. INT i = 0, j = 0;
  552. BOOLEAN fResult = FALSE;
  553. do
  554. {
  555. if ((pwszTemp = LocalAlloc (LPTR, (dwSizeOfData*2 + 1)*sizeof(WCHAR)))
  556. == NULL)
  557. break;
  558. for (i=(dwSizeOfData-1); i>=0; i--)
  559. {
  560. BYTE nHex;
  561. nHex = (pbData[i] & 0xf0) >> 4;
  562. pwszTemp[j++] = HEX2WCHAR(nHex);
  563. nHex = (pbData[i] & 0x0f);
  564. pwszTemp[j++] = HEX2WCHAR(nHex);
  565. }
  566. pwszTemp[j] = L'\0';
  567. *ppwszStr = pwszTemp;
  568. pwszTemp = NULL;
  569. fResult = TRUE;
  570. }
  571. while (FALSE);
  572. if (pwszTemp != NULL)
  573. {
  574. LocalFree (pwszTemp);
  575. }
  576. return fResult;
  577. }
  578. //
  579. // Gets the name in the cert pointed to by pCertContext, and converts
  580. // it to a printable form in *ppwszName. If the function returns TRUE,
  581. // the caller must ultimately call LocalFree(*ppwszName).
  582. //
  583. BOOL
  584. FUserCertToStr(
  585. IN PCCERT_CONTEXT pCertContext,
  586. OUT WCHAR** ppwszName
  587. )
  588. {
  589. DWORD dwExtensionIndex;
  590. DWORD dwAltEntryIndex;
  591. CERT_EXTENSION* pCertExtension;
  592. CERT_ALT_NAME_INFO* pCertAltNameInfo;
  593. CERT_ALT_NAME_ENTRY* pCertAltNameEntry;
  594. CERT_NAME_VALUE* pCertNameValue;
  595. DWORD dwCertAltNameInfoSize;
  596. DWORD dwCertNameValueSize;
  597. WCHAR* pwszName = NULL;
  598. BOOL fExitOuterFor;
  599. BOOL fExitInnerFor;
  600. BOOL fRet = FALSE;
  601. // See if cert has UPN in AltSubjectName->otherName
  602. fExitOuterFor = FALSE;
  603. for (dwExtensionIndex = 0;
  604. dwExtensionIndex < pCertContext->pCertInfo->cExtension;
  605. dwExtensionIndex++)
  606. {
  607. pCertAltNameInfo = NULL;
  608. pCertExtension = pCertContext->pCertInfo->rgExtension+dwExtensionIndex;
  609. if (strcmp(pCertExtension->pszObjId, szOID_SUBJECT_ALT_NAME2) != 0)
  610. {
  611. goto LOuterForEnd;
  612. }
  613. dwCertAltNameInfoSize = 0;
  614. if (!CryptDecodeObjectEx(
  615. pCertContext->dwCertEncodingType,
  616. X509_ALTERNATE_NAME,
  617. pCertExtension->Value.pbData,
  618. pCertExtension->Value.cbData,
  619. CRYPT_DECODE_ALLOC_FLAG,
  620. NULL,
  621. (VOID*)&pCertAltNameInfo,
  622. &dwCertAltNameInfoSize))
  623. {
  624. goto LOuterForEnd;
  625. }
  626. fExitInnerFor = FALSE;
  627. for (dwAltEntryIndex = 0;
  628. dwAltEntryIndex < pCertAltNameInfo->cAltEntry;
  629. dwAltEntryIndex++)
  630. {
  631. pCertNameValue = NULL;
  632. pCertAltNameEntry = pCertAltNameInfo->rgAltEntry + dwAltEntryIndex;
  633. if ( (CERT_ALT_NAME_OTHER_NAME !=
  634. pCertAltNameEntry->dwAltNameChoice)
  635. || (NULL == pCertAltNameEntry->pOtherName)
  636. || (0 != strcmp(szOID_NT_PRINCIPAL_NAME,
  637. pCertAltNameEntry->pOtherName->pszObjId)))
  638. {
  639. goto LInnerForEnd;
  640. }
  641. // We found a UPN!
  642. dwCertNameValueSize = 0;
  643. if (!CryptDecodeObjectEx(
  644. pCertContext->dwCertEncodingType,
  645. X509_UNICODE_ANY_STRING,
  646. pCertAltNameEntry->pOtherName->Value.pbData,
  647. pCertAltNameEntry->pOtherName->Value.cbData,
  648. CRYPT_DECODE_ALLOC_FLAG,
  649. NULL,
  650. (VOID*)&pCertNameValue,
  651. &dwCertNameValueSize))
  652. {
  653. goto LInnerForEnd;
  654. }
  655. // One extra char for the terminating NULL.
  656. pwszName = LocalAlloc(LPTR, pCertNameValue->Value.cbData +
  657. sizeof(WCHAR));
  658. if (NULL == pwszName)
  659. {
  660. EapolTrace ("LocalAlloc failed and returned %d",
  661. GetLastError());
  662. fExitInnerFor = TRUE;
  663. fExitOuterFor = TRUE;
  664. goto LInnerForEnd;
  665. }
  666. CopyMemory(pwszName, pCertNameValue->Value.pbData,
  667. pCertNameValue->Value.cbData);
  668. *ppwszName = pwszName;
  669. pwszName = NULL;
  670. fRet = TRUE;
  671. fExitInnerFor = TRUE;
  672. fExitOuterFor = TRUE;
  673. LInnerForEnd:
  674. LocalFree(pCertNameValue);
  675. if (fExitInnerFor)
  676. {
  677. break;
  678. }
  679. }
  680. LOuterForEnd:
  681. LocalFree(pCertAltNameInfo);
  682. if (fExitOuterFor)
  683. {
  684. break;
  685. }
  686. }
  687. LocalFree(pwszName);
  688. return(fRet);
  689. }
  690. //
  691. // Special function for getting the DNS machine name from the
  692. // machine auth certificate
  693. //
  694. BOOL
  695. FMachineAuthCertToStr
  696. (
  697. IN PCCERT_CONTEXT pCertContext,
  698. OUT WCHAR ** ppwszName
  699. )
  700. {
  701. DWORD dwExtensionIndex;
  702. DWORD dwAltEntryIndex;
  703. CERT_EXTENSION* pCertExtension;
  704. CERT_ALT_NAME_INFO* pCertAltNameInfo;
  705. CERT_ALT_NAME_ENTRY* pCertAltNameEntry;
  706. DWORD dwCertAltNameInfoSize;
  707. WCHAR* pwszName = NULL;
  708. BOOL fExitOuterFor;
  709. BOOL fExitInnerFor;
  710. BOOL fRet = FALSE;
  711. // See if cert has UPN in AltSubjectName->otherName
  712. fExitOuterFor = FALSE;
  713. for (dwExtensionIndex = 0;
  714. dwExtensionIndex < pCertContext->pCertInfo->cExtension;
  715. dwExtensionIndex++)
  716. {
  717. pCertAltNameInfo = NULL;
  718. pCertExtension = pCertContext->pCertInfo->rgExtension+dwExtensionIndex;
  719. if (strcmp(pCertExtension->pszObjId, szOID_SUBJECT_ALT_NAME2) != 0)
  720. {
  721. goto LOuterForEnd;
  722. }
  723. dwCertAltNameInfoSize = 0;
  724. if (!CryptDecodeObjectEx(
  725. pCertContext->dwCertEncodingType,
  726. X509_ALTERNATE_NAME,
  727. pCertExtension->Value.pbData,
  728. pCertExtension->Value.cbData,
  729. CRYPT_DECODE_ALLOC_FLAG,
  730. NULL,
  731. (VOID*)&pCertAltNameInfo,
  732. &dwCertAltNameInfoSize))
  733. {
  734. goto LOuterForEnd;
  735. }
  736. fExitInnerFor = FALSE;
  737. for (dwAltEntryIndex = 0;
  738. dwAltEntryIndex < pCertAltNameInfo->cAltEntry;
  739. dwAltEntryIndex++)
  740. {
  741. pCertAltNameEntry = pCertAltNameInfo->rgAltEntry + dwAltEntryIndex;
  742. if ( (CERT_ALT_NAME_DNS_NAME !=
  743. pCertAltNameEntry->dwAltNameChoice)
  744. || (NULL == pCertAltNameEntry->pwszDNSName)
  745. )
  746. {
  747. goto LInnerForEnd;
  748. }
  749. // We found the DNS Name!
  750. // One extra char for the terminating NULL.
  751. pwszName = LocalAlloc(LPTR, wcslen( pCertAltNameEntry->pwszDNSName ) * sizeof(WCHAR) +
  752. sizeof(WCHAR));
  753. if (NULL == pwszName)
  754. {
  755. EapolTrace ("LocalAlloc failed and returned %d",
  756. GetLastError());
  757. fExitInnerFor = TRUE;
  758. fExitOuterFor = TRUE;
  759. goto LInnerForEnd;
  760. }
  761. wcscpy (pwszName, pCertAltNameEntry->pwszDNSName );
  762. *ppwszName = pwszName;
  763. pwszName = NULL;
  764. fRet = TRUE;
  765. fExitInnerFor = TRUE;
  766. fExitOuterFor = TRUE;
  767. LInnerForEnd:
  768. if (fExitInnerFor)
  769. {
  770. break;
  771. }
  772. }
  773. LOuterForEnd:
  774. LocalFree(pCertAltNameInfo);
  775. if (fExitOuterFor)
  776. {
  777. break;
  778. }
  779. }
  780. LocalFree(pwszName);
  781. return(fRet);
  782. }
  783. //
  784. // Gets the name in the cert pointed to by pCertContext, and converts it
  785. // to a printable form in *ppwszName. If the function returns TRUE, the
  786. // caller must ultimately call LocalFree(*ppwszName).
  787. //
  788. BOOL
  789. FOtherCertToStr(
  790. IN PCCERT_CONTEXT pCertContext,
  791. IN DWORD fFlags,
  792. OUT WCHAR** ppwszName
  793. )
  794. {
  795. WCHAR* pwszTemp = NULL;
  796. DWORD dwSize;
  797. BOOL fRet = FALSE;
  798. RTASSERT(NULL != ppwszName);
  799. // Fetch Machine UPN
  800. if (fFlags == 0)
  801. {
  802. if (FMachineAuthCertToStr(pCertContext, &pwszTemp))
  803. {
  804. *ppwszName = pwszTemp;
  805. pwszTemp = NULL;
  806. fRet = TRUE;
  807. goto LDone;
  808. }
  809. }
  810. dwSize = CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE,
  811. fFlags, NULL, NULL, 0);
  812. // dwSize is the number of characters, including the terminating NULL.
  813. if (dwSize <= 1)
  814. {
  815. EapolTrace ("CertGetNameString failed.");
  816. goto LDone;
  817. }
  818. pwszTemp = LocalAlloc(LPTR, dwSize*sizeof(WCHAR));
  819. if (NULL == pwszTemp)
  820. {
  821. EapolTrace ("LocalAlloc failed and returned %d", GetLastError());
  822. goto LDone;
  823. }
  824. dwSize = CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE,
  825. fFlags, NULL, pwszTemp, dwSize);
  826. if (dwSize <= 1)
  827. {
  828. EapolTrace ("CertGetNameString failed.");
  829. goto LDone;
  830. }
  831. *ppwszName = pwszTemp;
  832. pwszTemp = NULL;
  833. fRet = TRUE;
  834. LDone:
  835. LocalFree(pwszTemp);
  836. return(fRet);
  837. }
  838. //
  839. // Gets the name in the cert pointed to by pCertContext, and converts it
  840. // to a printable form in *ppwszName. If the function returns TRUE, the
  841. // caller must ultimately call LocalFree(*ppwszName).
  842. //
  843. BOOL
  844. FCertToStr(
  845. IN PCCERT_CONTEXT pCertContext,
  846. IN DWORD fFlags,
  847. IN BOOL fMachineCert,
  848. OUT WCHAR** ppwszName
  849. )
  850. {
  851. if (!fMachineCert)
  852. {
  853. if (FUserCertToStr(pCertContext, ppwszName))
  854. {
  855. return(TRUE);
  856. }
  857. }
  858. return(FOtherCertToStr(pCertContext, fFlags, ppwszName));
  859. }
  860. //
  861. // Stores the friendly name of the cert pointed to by pCertContext in
  862. // *ppwszName. If the function returns TRUE, the caller must ultimately
  863. // call LocalFree(*ppwszName).
  864. //
  865. BOOL
  866. FGetFriendlyName(
  867. IN PCCERT_CONTEXT pCertContext,
  868. OUT WCHAR** ppwszName
  869. )
  870. {
  871. WCHAR* pwszName = NULL;
  872. DWORD dwBytes;
  873. BOOL fRet = FALSE;
  874. RTASSERT(NULL != ppwszName);
  875. if (!CertGetCertificateContextProperty(pCertContext,
  876. CERT_FRIENDLY_NAME_PROP_ID, NULL, &dwBytes))
  877. {
  878. // If there is no Friendly Name property, don't print an error stmt.
  879. fRet = TRUE;
  880. goto LDone;
  881. }
  882. pwszName = LocalAlloc(LPTR, dwBytes);
  883. if (NULL == pwszName)
  884. {
  885. EapolTrace ("LocalAlloc failed and returned %d", GetLastError());
  886. goto LDone;
  887. }
  888. if (!CertGetCertificateContextProperty(pCertContext,
  889. CERT_FRIENDLY_NAME_PROP_ID, pwszName, &dwBytes))
  890. {
  891. EapolTrace ("CertGetCertificateContextProperty failed and "
  892. "returned 0x%x", GetLastError());
  893. goto LDone;
  894. }
  895. *ppwszName = pwszName;
  896. pwszName = NULL;
  897. fRet = TRUE;
  898. LDone:
  899. LocalFree(pwszName);
  900. return(fRet);
  901. }
  902. //
  903. // Get EKU Usage Blob out of the certificate Context
  904. //
  905. BOOL FGetEKUUsage (
  906. IN PCCERT_CONTEXT pCertContext,
  907. IN PEAPOL_CERT_NODE pNode
  908. )
  909. {
  910. BOOL fRet = FALSE;
  911. DWORD dwBytes = 0;
  912. PCERT_ENHKEY_USAGE pUsage = NULL;
  913. DWORD dwOidLength = 0;
  914. DWORD dwIndex = 0;
  915. DWORD dwErr = ERROR_SUCCESS;
  916. EapolTrace ("FGetEKUUsage");
  917. if (!CertGetEnhancedKeyUsage(pCertContext, 0, NULL, &dwBytes))
  918. {
  919. dwErr = GetLastError();
  920. if (CRYPT_E_NOT_FOUND == dwErr)
  921. {
  922. EapolTrace ("No usage in cert");
  923. fRet = TRUE;
  924. goto LDone;
  925. }
  926. EapolTrace ("FGetEKUUsage failed and returned 0x%x", dwErr);
  927. goto LDone;
  928. }
  929. pUsage = LocalAlloc(LPTR, dwBytes);
  930. if (NULL == pUsage)
  931. {
  932. dwErr = GetLastError();
  933. EapolTrace ("LocalAlloc failed and returned %d", dwErr);
  934. goto LDone;
  935. }
  936. if (!CertGetEnhancedKeyUsage(pCertContext, 0, pUsage, &dwBytes))
  937. {
  938. dwErr = GetLastError();
  939. EapolTrace ("FGetEKUUsage failed and returned 0x%x", dwErr);
  940. goto LDone;
  941. }
  942. for (dwIndex = 0; dwIndex < pUsage->cUsageIdentifier; dwIndex++)
  943. {
  944. PCCRYPT_OID_INFO pInfo;
  945. if ((pInfo = CryptFindOIDInfo (
  946. CRYPT_OID_INFO_OID_KEY,
  947. (void *) pUsage->rgpszUsageIdentifier[dwIndex],
  948. 0)) != NULL)
  949. {
  950. dwOidLength += (wcslen(pInfo->pwszName)+3)*sizeof(WCHAR);
  951. }
  952. }
  953. pNode->pwszEKUUsage = LocalAlloc (LPTR, (dwOidLength+sizeof(WCHAR)));
  954. for (dwIndex = 0; dwIndex < pUsage->cUsageIdentifier; dwIndex++)
  955. {
  956. PCCRYPT_OID_INFO pInfo;
  957. if ((pInfo = CryptFindOIDInfo (
  958. CRYPT_OID_INFO_OID_KEY,
  959. (void *) pUsage->rgpszUsageIdentifier[dwIndex],
  960. 0)) != NULL)
  961. {
  962. EapolTrace ("EKU: %ws", pInfo->pwszName);
  963. if (dwIndex != 0)
  964. wcscat (pNode->pwszEKUUsage, L", ");
  965. wcscat (pNode->pwszEKUUsage, pInfo->pwszName);
  966. }
  967. }
  968. EapolTrace ("EKUUsage: %ws", pNode->pwszEKUUsage);
  969. fRet = TRUE;
  970. LDone:
  971. if (pUsage != NULL)
  972. {
  973. LocalFree (pUsage);
  974. }
  975. return fRet;
  976. }
  977. //
  978. // ElLogCertificateDetails
  979. //
  980. // Description:
  981. //
  982. // Function called to display certificate contents
  983. //
  984. // Arguments:
  985. // pPCB - Pointer to PCB
  986. //
  987. // Return Values:
  988. //
  989. DWORD
  990. ElLogCertificateDetails (
  991. IN EAPOL_PCB *pPCB
  992. )
  993. {
  994. EAPTLS_USER_PROPERTIES *pUserProp = NULL;
  995. HCERTSTORE hCertStore = NULL;
  996. PCCERT_CONTEXT pCert = NULL;
  997. CRYPT_HASH_BLOB HashBlob;
  998. DWORD dwVersion = 0;
  999. EAPOL_CERT_NODE *pNode = NULL;
  1000. BYTE rgbHash[MAX_HASH_LEN];
  1001. DWORD cbHash = MAX_HASH_LEN;
  1002. BOOLEAN fRevertToSelf = FALSE;
  1003. PCERT_ENHKEY_USAGE pUsageInternal = NULL;
  1004. DWORD dwRetCode = NO_ERROR;
  1005. do
  1006. {
  1007. if (pPCB->pCustomAuthUserData == NULL)
  1008. {
  1009. EapolTrace ("Cannot log Cert detail, since NULL user properties");
  1010. break;
  1011. }
  1012. pUserProp = (EAPTLS_USER_PROPERTIES *)pPCB->pCustomAuthUserData->pbCustomAuthData;
  1013. if (pPCB->hUserToken)
  1014. {
  1015. if (!ImpersonateLoggedOnUser (pPCB->hUserToken))
  1016. {
  1017. dwRetCode = GetLastError();
  1018. EapolTrace ("ElLogCertificateDetails: ImpersonateLoggedOnUser failed with error %ld",
  1019. dwRetCode);
  1020. break;
  1021. }
  1022. fRevertToSelf = TRUE;
  1023. }
  1024. hCertStore = CertOpenStore (
  1025. CERT_STORE_PROV_SYSTEM,
  1026. 0,
  1027. 0,
  1028. CERT_STORE_READONLY_FLAG |
  1029. ((pPCB->PreviousAuthenticationType == EAPOL_MACHINE_AUTHENTICATION)? CERT_SYSTEM_STORE_LOCAL_MACHINE : CERT_SYSTEM_STORE_CURRENT_USER),
  1030. L"MY"
  1031. );
  1032. if (hCertStore == NULL)
  1033. {
  1034. dwRetCode = GetLastError();
  1035. EapolTrace ("CertOpenStore failed with error %ld", dwRetCode);
  1036. break;
  1037. }
  1038. HashBlob.cbData = pUserProp->Hash.cbHash;
  1039. HashBlob.pbData = pUserProp->Hash.pbHash;
  1040. pCert = CertFindCertificateInStore (
  1041. hCertStore,
  1042. X509_ASN_ENCODING,
  1043. 0,
  1044. CERT_FIND_HASH,
  1045. &HashBlob,
  1046. NULL
  1047. );
  1048. if (pCert == NULL)
  1049. {
  1050. dwRetCode = GetLastError();
  1051. EapolTrace ("CertFindCertificateInStore failed with error %ld",
  1052. dwRetCode);
  1053. break;
  1054. }
  1055. if (fRevertToSelf)
  1056. {
  1057. fRevertToSelf = FALSE;
  1058. if (!RevertToSelf())
  1059. {
  1060. dwRetCode = GetLastError();
  1061. EapolTrace ("ElLogCertificateDetails: Error in RevertToSelf = %ld",
  1062. dwRetCode);
  1063. dwRetCode = ERROR_BAD_IMPERSONATION_LEVEL;
  1064. break;
  1065. }
  1066. }
  1067. pNode = LocalAlloc(LPTR, sizeof(EAPOL_CERT_NODE));
  1068. if (pNode == NULL)
  1069. {
  1070. dwRetCode = GetLastError ();
  1071. break;
  1072. }
  1073. if (!CertGetCertificateContextProperty (
  1074. pCert,
  1075. CERT_SHA1_HASH_PROP_ID,
  1076. rgbHash,
  1077. &cbHash
  1078. ))
  1079. {
  1080. dwRetCode = GetLastError();
  1081. EapolTrace ("CertGetCertificateContextProperty failed with error %ld");
  1082. break;
  1083. }
  1084. if ((!fByteToStr (sizeof(DWORD), (PBYTE)&(pCert->pCertInfo->dwVersion),
  1085. &(pNode->pwszVersion))) ||
  1086. (!fSerialNumberByteToStr (pCert->pCertInfo->SerialNumber.cbData,
  1087. pCert->pCertInfo->SerialNumber.pbData,
  1088. &(pNode->pwszSerialNumber))) ||
  1089. (!fFileTimeToStr (pCert->pCertInfo->NotAfter,
  1090. &(pNode->pwszValidTo))) ||
  1091. (!fFileTimeToStr (pCert->pCertInfo->NotBefore,
  1092. &(pNode->pwszValidFrom))) ||
  1093. (!fByteToStr (cbHash, rgbHash, &(pNode->pwszThumbprint))) ||
  1094. (!FCertToStr (pCert, 0, ((pPCB->PreviousAuthenticationType == EAPOL_MACHINE_AUTHENTICATION)? TRUE: FALSE), &(pNode->pwszDisplayName))) ||
  1095. (!FCertToStr (pCert, CERT_NAME_ISSUER_FLAG, TRUE, &(pNode->pwszIssuer))) ||
  1096. (!FGetFriendlyName(pCert, &(pNode->pwszFriendlyName)))
  1097. || (!FGetEKUUsage (pCert, pNode)))
  1098. {
  1099. EapolTrace ("ElLogCertificateDetails: An internal string convert function failed");
  1100. // break;
  1101. }
  1102. DbLogPCBEvent (
  1103. DBLOG_CATEG_INFO,
  1104. pPCB,
  1105. EAPOL_CERTIFICATE_DETAILS,
  1106. EAPOLAuthTypes[pPCB->PreviousAuthenticationType],
  1107. pNode->pwszVersion,
  1108. pNode->pwszSerialNumber,
  1109. pNode->pwszIssuer,
  1110. pNode->pwszFriendlyName,
  1111. pNode->pwszDisplayName,
  1112. pNode->pwszEKUUsage,
  1113. pNode->pwszValidFrom,
  1114. pNode->pwszValidTo,
  1115. pNode->pwszThumbprint
  1116. );
  1117. }
  1118. while (FALSE);
  1119. if (pCert)
  1120. CertFreeCertificateContext (pCert);
  1121. if (hCertStore)
  1122. CertCloseStore (hCertStore, 0);
  1123. if (fRevertToSelf)
  1124. {
  1125. if (!RevertToSelf())
  1126. {
  1127. dwRetCode = GetLastError();
  1128. EapolTrace ("ElLogCertificateDetails: Error in RevertToSelf = %ld",
  1129. dwRetCode);
  1130. dwRetCode = ERROR_BAD_IMPERSONATION_LEVEL;
  1131. fRevertToSelf = FALSE;
  1132. }
  1133. }
  1134. if (pNode)
  1135. {
  1136. LocalFree(pNode->pwszVersion);
  1137. LocalFree(pNode->pwszSerialNumber);
  1138. LocalFree(pNode->pwszIssuer);
  1139. LocalFree(pNode->pwszFriendlyName);
  1140. LocalFree(pNode->pwszDisplayName);
  1141. LocalFree(pNode->pwszEKUUsage);
  1142. LocalFree(pNode->pwszValidFrom);
  1143. LocalFree(pNode->pwszValidTo);
  1144. LocalFree(pNode->pwszThumbprint);
  1145. LocalFree(pNode);
  1146. }
  1147. return dwRetCode;
  1148. }
  1149. //
  1150. // General tracing function
  1151. //
  1152. VOID
  1153. EapolTrace(
  1154. IN CHAR* Format,
  1155. ...
  1156. )
  1157. {
  1158. va_list arglist;
  1159. va_start(arglist, Format);
  1160. if (TRACEID != INVALID_TRACEID)
  1161. TraceVprintfExA(TRACEID,
  1162. ((DWORD)0xFFFF0000 | TRACE_USE_MASK),
  1163. Format,
  1164. arglist);
  1165. va_end(arglist);
  1166. }