Leaked source code of windows server 2003
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.

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