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.

3422 lines
108 KiB

  1. /*++
  2. Copyright (c) 1999, Microsoft Corporation
  3. Module Name:
  4. elprotocol.c
  5. Abstract:
  6. This module implements functions related to EAPOL
  7. protocol
  8. Revision History:
  9. sachins, Apr 30 2000, Created
  10. --*/
  11. #include "pcheapol.h"
  12. #pragma hdrstop
  13. //
  14. // ElProcessReceivedPacket
  15. //
  16. // Description:
  17. //
  18. // Function called to process data received from the NDISUIO driver.
  19. // The EAPOL packet is extracted and further processing is done.
  20. //
  21. //
  22. // Arguments:
  23. // pvContext - Context buffer which is a pointer to EAPOL_BUFFER structure
  24. //
  25. // Return Values:
  26. //
  27. DWORD
  28. WINAPI
  29. ElProcessReceivedPacket (
  30. IN PVOID pvContext
  31. )
  32. {
  33. EAPOL_PCB *pPCB = NULL;
  34. EAPOL_BUFFER *pEapolBuffer = NULL;
  35. DWORD dwLength = 0;
  36. ETH_HEADER *pEthHdr = NULL;
  37. EAPOL_PACKET *pEapolPkt = NULL;
  38. DWORD dw8021PSize = 0;
  39. PPP_EAP_PACKET *pEapPkt = NULL;
  40. BYTE *pBuffer;
  41. BOOLEAN ReqId = FALSE; // EAPOL state machine local variables
  42. BOOLEAN ReqAuth = FALSE;
  43. BOOLEAN EapSuccess = FALSE;
  44. BOOLEAN EapFail = FALSE;
  45. BOOLEAN RxKey = FALSE;
  46. GUID DeviceGuid;
  47. DWORD dwRetCode = NO_ERROR;
  48. if (pvContext == NULL)
  49. {
  50. TRACE0 (EAPOL, "ProcessReceivedPacket: Critical error, Context is NULL");
  51. return 0;
  52. }
  53. pEapolBuffer = (EAPOL_BUFFER *)pvContext;
  54. pPCB = (EAPOL_PCB *)pEapolBuffer->pvContext;
  55. dwLength = pEapolBuffer->dwBytesTransferred;
  56. pBuffer = (BYTE *)pEapolBuffer->pBuffer;
  57. TRACE1 (EAPOL, "ProcessReceivedPacket entered, length = %ld", dwLength);
  58. ElParsePacket (pBuffer, dwLength, TRUE);
  59. ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
  60. do
  61. {
  62. // The Port was verified to be active before the workitem
  63. // was queued. But do a double-check
  64. // Validate packet length
  65. // Should be atleast ETH_HEADER and first 4 required bytes of
  66. // EAPOL_PACKET
  67. if (dwLength < (sizeof(ETH_HEADER) + 4))
  68. {
  69. TRACE2 (EAPOL, "ProcessReceivedPacket: Packet length %ld is less than minimum required %d. Ignoring packet",
  70. dwLength, (sizeof(ETH_HEADER) + 4));
  71. dwRetCode = ERROR_INVALID_PACKET_LENGTH_OR_ID;
  72. break;
  73. }
  74. // If the source address is same as the local MAC address, it is a
  75. // multicast packet copy sent out being received
  76. pEthHdr = (ETH_HEADER *)pBuffer;
  77. if ((memcmp ((BYTE *)pEthHdr->bSrcAddr,
  78. (BYTE *)pPCB->bSrcMacAddr,
  79. SIZE_MAC_ADDR)) == 0)
  80. {
  81. TRACE0 (EAPOL, "ProcessReceivedPacket: Src MAC address of packet matches local address. Ignoring packet");
  82. dwRetCode = ERROR_INVALID_ADDRESS;
  83. break;
  84. }
  85. // Verify if the packet contains a 802.1P tag. If so, skip the 4 bytes
  86. // after the src+dest mac addresses
  87. if ((WireToHostFormat16(pBuffer + sizeof(ETH_HEADER)) == EAPOL_8021P_TAG_TYPE))
  88. {
  89. pEapolPkt = (EAPOL_PACKET *)(pBuffer + sizeof(ETH_HEADER) + 4);
  90. dw8021PSize = 4;
  91. }
  92. else
  93. {
  94. pEapolPkt = (EAPOL_PACKET *)(pBuffer + sizeof(ETH_HEADER));
  95. }
  96. // Validate Ethernet type in the incoming packet
  97. // It should be the same as the one defined for the
  98. // current port
  99. if (memcmp ((BYTE *)pEapolPkt->EthernetType, (BYTE *)pPCB->bEtherType,
  100. SIZE_ETHERNET_TYPE) != 0)
  101. {
  102. TRACE0 (EAPOL, "ProcessReceivedPacket: Packet Ethernet type does not match expected type. Ignoring packet");
  103. TRACE0 (EAPOL, "Incoming:");
  104. EAPOL_DUMPBA ((BYTE *)pEapolPkt->EthernetType, SIZE_ETHERNET_TYPE);
  105. TRACE0 (EAPOL, "Expected:");
  106. EAPOL_DUMPBA ((BYTE *)pPCB->bEtherType, SIZE_ETHERNET_TYPE);
  107. dwRetCode = ERROR_INVALID_PACKET_LENGTH_OR_ID;
  108. break;
  109. }
  110. // EAPOL packet type should be valid
  111. if ((pEapolPkt->PacketType != EAP_Packet) &&
  112. (pEapolPkt->PacketType != EAPOL_Start) &&
  113. (pEapolPkt->PacketType != EAPOL_Logoff) &&
  114. (pEapolPkt->PacketType != EAPOL_Key))
  115. {
  116. TRACE1 (EAPOL, "ProcessReceivedPacket: Invalid EAPOL packet type %d. Ignoring packet",
  117. pEapolPkt->PacketType);
  118. dwRetCode = ERROR_INVALID_PACKET;
  119. break;
  120. }
  121. if ((WireToHostFormat16(pEapolPkt->PacketBodyLength) > (MAX_PACKET_SIZE - (SIZE_ETHERNET_CRC + sizeof(ETH_HEADER) + dw8021PSize + FIELD_OFFSET (EAPOL_PACKET, PacketBody)))))
  122. // ||
  123. // (WireToHostFormat16(pEapolPkt->PacketBodyLength) != (dwLength - (sizeof(ETH_HEADER) + dw8021PSize + FIELD_OFFSET (EAPOL_PACKET, PacketBody)))))
  124. {
  125. TRACE3 (EAPOL, "ProcessReceivedPacket: Invalid length in EAPOL packet (%ld), Max length (%ld), Exact length (%ld), Ignoring packet",
  126. WireToHostFormat16(pEapolPkt->PacketBodyLength),
  127. (MAX_PACKET_SIZE - (SIZE_ETHERNET_CRC + sizeof(ETH_HEADER) + dw8021PSize + FIELD_OFFSET (EAPOL_PACKET, PacketBody))),
  128. (dwLength - (sizeof(ETH_HEADER) + dw8021PSize + FIELD_OFFSET (EAPOL_PACKET, PacketBody)))
  129. );
  130. dwRetCode = ERROR_INVALID_PACKET;
  131. break;
  132. }
  133. // Determine the value of local EAPOL state variables
  134. if (pEapolPkt->PacketType == EAP_Packet)
  135. {
  136. TRACE0 (EAPOL, "ProcessReceivedPacket: EAP_Packet");
  137. // Validate length of packet for EAP
  138. // Should be atleast (ETH_HEADER+EAPOL_PACKET)
  139. if (dwLength < (sizeof (ETH_HEADER) + dw8021PSize + FIELD_OFFSET (EAPOL_PACKET, PacketBody) + FIELD_OFFSET(PPP_EAP_PACKET, Data)))
  140. {
  141. TRACE1 (EAPOL, "ProcessReceivedPacket: Invalid length of EAP packet %d. Ignoring packet",
  142. dwLength);
  143. dwRetCode = ERROR_INVALID_PACKET;
  144. break;
  145. }
  146. pEapPkt = (PPP_EAP_PACKET *)pEapolPkt->PacketBody;
  147. if (WireToHostFormat16(pEapolPkt->PacketBodyLength) != WireToHostFormat16 (pEapPkt->Length))
  148. {
  149. TRACE2 (EAPOL, "ProcessReceivedPacket: Invalid length in EAPOL packet (%ld) not matching EAP length (%ld), Ignoring packet",
  150. WireToHostFormat16(pEapolPkt->PacketBodyLength),
  151. WireToHostFormat16 (pEapPkt->Length));
  152. dwRetCode = ERROR_INVALID_PACKET;
  153. break;
  154. }
  155. if (pEapPkt->Code == EAPCODE_Request)
  156. {
  157. // Validate length of packet for EAP-Request packet
  158. // Should be atleast (ETH_HEADER+EAPOL_PACKET-1+PPP_EAP_PACKET)
  159. if (dwLength < (sizeof (ETH_HEADER) + sizeof(EAPOL_PACKET)-1
  160. + sizeof (PPP_EAP_PACKET)))
  161. {
  162. TRACE1 (EAPOL, "ProcessReceivedPacket: Invalid length of EAP Request packet %d. Ignoring packet",
  163. dwLength);
  164. dwRetCode = ERROR_INVALID_PACKET;
  165. break;
  166. }
  167. if (pEapPkt->Data[0] == EAPTYPE_Identity)
  168. {
  169. pPCB->fIsRemoteEndEAPOLAware = TRUE;
  170. switch (pPCB->dwSupplicantMode)
  171. {
  172. case SUPPLICANT_MODE_0:
  173. case SUPPLICANT_MODE_1:
  174. // ignore
  175. break;
  176. case SUPPLICANT_MODE_2:
  177. case SUPPLICANT_MODE_3:
  178. pPCB->fEAPOLTransmissionFlag = TRUE;
  179. break;
  180. }
  181. ReqId = TRUE;
  182. }
  183. else
  184. {
  185. ReqAuth = TRUE;
  186. }
  187. }
  188. else if (pEapPkt->Code == EAPCODE_Success)
  189. {
  190. EapSuccess = TRUE;
  191. }
  192. else if (pEapPkt->Code == EAPCODE_Failure)
  193. {
  194. EapFail = TRUE;
  195. }
  196. else
  197. {
  198. // Invalid type
  199. TRACE1 (EAPOL, "ProcessReceivedPacket: Invalid EAP packet type %d. Ignoring packet",
  200. pEapPkt->Code);
  201. dwRetCode = ERROR_INVALID_PACKET;
  202. break;
  203. }
  204. }
  205. else
  206. {
  207. TRACE0 (EAPOL, "ProcessReceivedPacket: != EAP_Packet");
  208. if (pEapolPkt->PacketType == EAPOL_Key)
  209. {
  210. TRACE0 (EAPOL, "ProcessReceivedPacket: == EAPOL_Key");
  211. RxKey = TRUE;
  212. }
  213. else
  214. {
  215. TRACE0 (EAPOL, "ProcessReceivedPacket: Invalid packet type");
  216. }
  217. }
  218. // State machine does not accept packets for inactive/disabled ports
  219. if (!EAPOL_PORT_ACTIVE(pPCB))
  220. {
  221. TRACE1 (EAPOL, "ProcessReceivedPacket: Port %ws not active",
  222. pPCB->pwszDeviceGUID);
  223. if (EAPOL_PORT_DISABLED(pPCB))
  224. {
  225. DbLogPCBEvent (DBLOG_CATEG_WARN, pPCB, EAPOL_NOT_ENABLED_PACKET_REJECTED);
  226. }
  227. break;
  228. }
  229. if (RxKey)
  230. {
  231. if ((dwRetCode = FSMKeyReceive (pPCB,
  232. pEapolPkt)) != NO_ERROR)
  233. {
  234. break;
  235. }
  236. }
  237. switch (pPCB->State)
  238. {
  239. // ReqId, ReqAuth, EapSuccess, EapFail, RxKey are inherently
  240. // mutually exclusive
  241. // No checks will be made to verify this
  242. // Also, assumption is being made that in any state, maximum
  243. // one timer may be active on the port.
  244. case EAPOLSTATE_LOGOFF:
  245. // Only a User Logon event can get the port out of
  246. // LOGOFF state
  247. TRACE0 (EAPOL, "ProcessReceivedPacket: LOGOFF state, Ignoring packet");
  248. break;
  249. case EAPOLSTATE_DISCONNECTED:
  250. // Only a Media Connect / User logon / System reset event
  251. // can get the port out of DISCONNECTED state
  252. TRACE0 (EAPOL, "ProcessReceivedPacket: DISCONNECTED state, Ignoring packet");
  253. break;
  254. case EAPOLSTATE_CONNECTING:
  255. TRACE0 (EAPOL, "ProcessReceivedPacket: EAPOLSTATE_CONNECTING");
  256. if (EapSuccess)
  257. {
  258. if (!pPCB->fLocalEAPAuthSuccess)
  259. {
  260. TRACE0 (EAPOL, "ProcessReceivedPacket: Dropping invalid EAP-Success packet");
  261. dwRetCode = ERROR_INVALID_PACKET;
  262. break;
  263. }
  264. }
  265. if (ReqId | EapSuccess | EapFail)
  266. {
  267. // Deactivate current timer
  268. RESTART_TIMER (pPCB->hTimer,
  269. INFINITE_SECONDS,
  270. "PCB",
  271. &dwRetCode);
  272. if (dwRetCode != NO_ERROR)
  273. {
  274. break;
  275. }
  276. }
  277. if (EapSuccess)
  278. {
  279. if ((dwRetCode = ElProcessEapSuccess (pPCB,
  280. pEapolPkt)) != NO_ERROR)
  281. {
  282. break;
  283. }
  284. }
  285. else
  286. if (EapFail)
  287. {
  288. if ((dwRetCode = ElProcessEapFail (pPCB,
  289. pEapolPkt)) != NO_ERROR)
  290. {
  291. break;
  292. }
  293. }
  294. else
  295. if (ReqId)
  296. {
  297. if ((dwRetCode = FSMAcquired (pPCB,
  298. pEapolPkt)) != NO_ERROR)
  299. {
  300. break;
  301. }
  302. }
  303. break;
  304. case EAPOLSTATE_ACQUIRED:
  305. TRACE0 (EAPOL, "ProcessReceivedPacket: EAPOLSTATE_ACQUIRED");
  306. if (EapSuccess)
  307. {
  308. if (!pPCB->fLocalEAPAuthSuccess)
  309. {
  310. TRACE0 (EAPOL, "ProcessReceivedPacket: Dropping invalid EAP-Success packet");
  311. dwRetCode = ERROR_INVALID_PACKET;
  312. break;
  313. }
  314. }
  315. if (ReqId | ReqAuth | EapSuccess | EapFail)
  316. {
  317. // Deactivate current timer
  318. RESTART_TIMER (pPCB->hTimer,
  319. INFINITE_SECONDS,
  320. "PCB",
  321. &dwRetCode);
  322. if (dwRetCode != NO_ERROR)
  323. {
  324. break;
  325. }
  326. // Reset EapUI state
  327. if (!ReqId)
  328. {
  329. pPCB->EapUIState &= ~EAPUISTATE_WAITING_FOR_IDENTITY;
  330. }
  331. }
  332. if (EapSuccess)
  333. {
  334. if ((dwRetCode = ElProcessEapSuccess (pPCB,
  335. pEapolPkt)) != NO_ERROR)
  336. {
  337. break;
  338. }
  339. }
  340. else
  341. if (EapFail)
  342. {
  343. if ((dwRetCode = ElProcessEapFail (pPCB,
  344. pEapolPkt)) != NO_ERROR)
  345. {
  346. break;
  347. }
  348. }
  349. else
  350. if (ReqId)
  351. {
  352. if ((dwRetCode = FSMAcquired (pPCB,
  353. pEapolPkt)) != NO_ERROR)
  354. {
  355. break;
  356. }
  357. }
  358. else
  359. if (ReqAuth)
  360. {
  361. if ((dwRetCode = FSMAuthenticating (pPCB,
  362. pEapolPkt)) != NO_ERROR)
  363. {
  364. break;
  365. }
  366. }
  367. break;
  368. case EAPOLSTATE_AUTHENTICATING:
  369. TRACE0 (EAPOL, "ProcessReceivedPacket: EAPOLSTATE_AUTHENTICATING");
  370. // Common timer deletion
  371. if (ReqAuth | ReqId | EapSuccess | EapFail)
  372. {
  373. // Deactivate current timer
  374. RESTART_TIMER (pPCB->hTimer,
  375. INFINITE_SECONDS,
  376. "PCB",
  377. &dwRetCode);
  378. if (dwRetCode != NO_ERROR)
  379. {
  380. break;
  381. }
  382. if (ReqId)
  383. {
  384. if ((dwRetCode = FSMAcquired (pPCB,
  385. pEapolPkt)) != NO_ERROR)
  386. {
  387. break;
  388. }
  389. }
  390. else
  391. {
  392. if ((dwRetCode = FSMAuthenticating (pPCB,
  393. pEapolPkt)) != NO_ERROR)
  394. {
  395. break;
  396. }
  397. }
  398. // Reset EapUI state
  399. if (!ReqAuth)
  400. {
  401. pPCB->EapUIState &= ~EAPUISTATE_WAITING_FOR_UI_RESPONSE;
  402. }
  403. }
  404. // Continue further processing
  405. if (EapSuccess | EapFail)
  406. {
  407. if (EapSuccess)
  408. {
  409. if (!pPCB->fLocalEAPAuthSuccess)
  410. {
  411. TRACE0 (EAPOL, "ProcessReceivedPacket: Dropping invalid EAP-Success packet");
  412. dwRetCode = ERROR_INVALID_PACKET;
  413. break;
  414. }
  415. }
  416. // Auth timer will have restarted in FSMAuthenticating
  417. // Deactivate the timer
  418. RESTART_TIMER (pPCB->hTimer,
  419. INFINITE_SECONDS,
  420. "PCB",
  421. &dwRetCode);
  422. if (dwRetCode != NO_ERROR)
  423. {
  424. break;
  425. }
  426. // If the packet received was a EAP-Success, go into
  427. // AUTHENTICATED state
  428. if (EapSuccess)
  429. {
  430. if ((dwRetCode = ElProcessEapSuccess (pPCB,
  431. pEapolPkt)) != NO_ERROR)
  432. {
  433. break;
  434. }
  435. }
  436. else
  437. // If the packet received was a EAP-Failure, go into
  438. // HELD state
  439. if (EapFail)
  440. {
  441. if ((dwRetCode = ElProcessEapFail (pPCB,
  442. pEapolPkt)) != NO_ERROR)
  443. {
  444. break;
  445. }
  446. }
  447. }
  448. break;
  449. case EAPOLSTATE_HELD:
  450. TRACE0 (EAPOL, "ProcessReceivedPacket: HELD state, Ignoring packet");
  451. if (ReqId)
  452. {
  453. // Deactivate current timer
  454. RESTART_TIMER (pPCB->hTimer,
  455. INFINITE_SECONDS,
  456. "PCB",
  457. &dwRetCode);
  458. if (dwRetCode != NO_ERROR)
  459. {
  460. break;
  461. }
  462. if ((dwRetCode = FSMAcquired (pPCB,
  463. pEapolPkt)) != NO_ERROR)
  464. {
  465. break;
  466. }
  467. }
  468. break;
  469. case EAPOLSTATE_AUTHENTICATED:
  470. TRACE0 (EAPOL, "ProcessReceivedPacket: STATE_AUTHENTICATED");
  471. if (ReqId)
  472. {
  473. if ((dwRetCode = FSMAcquired (pPCB,
  474. pEapolPkt)) != NO_ERROR)
  475. {
  476. break;
  477. }
  478. }
  479. else
  480. {
  481. if (EapFail)
  482. {
  483. if ((dwRetCode = ElProcessEapFail (pPCB,
  484. pEapolPkt)) != NO_ERROR)
  485. {
  486. break;
  487. }
  488. }
  489. }
  490. break;
  491. default:
  492. TRACE0 (EAPOL, "ProcessReceivedPacket: Critical Error. Invalid state, Ignoring packet");
  493. break;
  494. }
  495. } while (FALSE);
  496. if (pEapolBuffer != NULL)
  497. {
  498. FREE (pEapolBuffer);
  499. }
  500. // Post a new read request, ignoring errors
  501. if (EAPOL_PORT_DELETED(pPCB))
  502. {
  503. TRACE1 (EAPOL, "ProcessReceivedPacket: Port %ws deleted, not reposting read request",
  504. pPCB->pwszDeviceGUID);
  505. }
  506. else
  507. {
  508. TRACE1 (EAPOL, "ProcessReceivedPacket: Reposting buffer on port %ws",
  509. pPCB->pwszDeviceGUID);
  510. // ElReadFromPort creates a new context buffer, adds a ref count,
  511. // and posts the read request
  512. if ((dwRetCode = ElReadFromPort (
  513. pPCB,
  514. NULL,
  515. 0
  516. )) != NO_ERROR)
  517. {
  518. TRACE1 (EAPOL, "ProcessReceivedPacket: Critical error: ElReadFromPort error %d",
  519. dwRetCode);
  520. }
  521. }
  522. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  523. TRACE2 (EAPOL, "ProcessReceivedPacket: pPCB= %p, RefCnt = %ld",
  524. pPCB, pPCB->dwRefCount);
  525. // Dereference ref count held for the read that was just processed
  526. EAPOL_DEREFERENCE_PORT(pPCB);
  527. TRACE0 (EAPOL, "ProcessReceivedPacket exit");
  528. InterlockedDecrement (&g_lWorkerThreads);
  529. return 0;
  530. }
  531. //
  532. // FSMDisconnected
  533. //
  534. // Description:
  535. // Function called when media disconnect occurs
  536. //
  537. // Arguments:
  538. // pPCB - Pointer to PCB for the port on which media disconnect occurs
  539. //
  540. // Return values:
  541. // NO_ERROR - success
  542. // non-zero - error
  543. //
  544. DWORD
  545. FSMDisconnected (
  546. IN EAPOL_PCB *pPCB,
  547. IN EAPOL_PACKET *pEapolPkt
  548. )
  549. {
  550. DWORD dwRetCode = NO_ERROR;
  551. TRACE1 (EAPOL, "FSMDisconnected entered for port %ws", pPCB->pwszFriendlyName);
  552. do
  553. {
  554. } while (FALSE);
  555. TRACE1 (EAPOL, "Setting state DISCONNECTED for port %ws", pPCB->pwszFriendlyName);
  556. DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_STATE_TRANSITION,
  557. EAPOLStates[((pPCB->State < EAPOLSTATE_LOGOFF) || (pPCB->State > EAPOLSTATE_AUTHENTICATED))?EAPOLSTATE_UNDEFINED:pPCB->State],
  558. EAPOLStates[EAPOLSTATE_DISCONNECTED]);
  559. pPCB->State = EAPOLSTATE_DISCONNECTED;
  560. pPCB->EapUIState = 0;
  561. // Free Identity buffer
  562. if (pPCB->pszIdentity != NULL)
  563. {
  564. FREE (pPCB->pszIdentity);
  565. pPCB->pszIdentity = NULL;
  566. }
  567. // Free Password buffer
  568. if (pPCB->PasswordBlob.pbData != NULL)
  569. {
  570. FREE (pPCB->PasswordBlob.pbData);
  571. pPCB->PasswordBlob.pbData = NULL;
  572. pPCB->PasswordBlob.cbData = 0;
  573. }
  574. // Free user-specific data in the PCB
  575. if (pPCB->pCustomAuthUserData != NULL)
  576. {
  577. FREE (pPCB->pCustomAuthUserData);
  578. pPCB->pCustomAuthUserData = NULL;
  579. }
  580. // Free connection data, though it is common to all users
  581. if (pPCB->pCustomAuthConnData != NULL)
  582. {
  583. FREE (pPCB->pCustomAuthConnData);
  584. pPCB->pCustomAuthConnData = NULL;
  585. }
  586. pPCB->dwAuthFailCount = 0;
  587. pPCB->fGotUserIdentity = FALSE;
  588. if (pPCB->hUserToken != NULL)
  589. {
  590. if (!CloseHandle (pPCB->hUserToken))
  591. {
  592. dwRetCode = GetLastError ();
  593. TRACE1 (EAPOL, "FSMDisconnected: CloseHandle failed with error %ld",
  594. dwRetCode);
  595. dwRetCode = NO_ERROR;
  596. }
  597. }
  598. pPCB->hUserToken = NULL;
  599. TRACE1 (EAPOL, "FSMDisconnected completed for port %ws", pPCB->pwszFriendlyName);
  600. return dwRetCode;
  601. }
  602. //
  603. // FSMLogoff
  604. //
  605. // Description:
  606. // Function called to send out EAPOL_Logoff packet. Usually triggered by
  607. // user logging off.
  608. //
  609. // Arguments:
  610. // pPCB - Pointer to PCB for the port on which logoff packet is to be
  611. // sent out
  612. //
  613. // Return values:
  614. // NO_ERROR - success
  615. // non-zero - error
  616. //
  617. DWORD
  618. FSMLogoff (
  619. IN EAPOL_PCB *pPCB,
  620. IN EAPOL_PACKET *pDummy
  621. )
  622. {
  623. EAPOL_PACKET *pEapolPkt = NULL;
  624. BOOLEAN fAuthSendPacket = FALSE;
  625. BOOLEAN fSupplicantSendPacket = FALSE;
  626. DWORD dwRetCode = NO_ERROR;
  627. TRACE1 (EAPOL, "FSMLogoff entered for port %ws", pPCB->pwszFriendlyName);
  628. do
  629. {
  630. // End EAP session
  631. ElEapEnd (pPCB);
  632. // Send out EAPOL_Logoff conditionally
  633. if ( ((pPCB->dwSupplicantMode == SUPPLICANT_MODE_2) &&
  634. (pPCB->fEAPOLTransmissionFlag)) ||
  635. (pPCB->dwSupplicantMode == SUPPLICANT_MODE_3))
  636. {
  637. fSupplicantSendPacket = TRUE;
  638. }
  639. switch (pPCB->dwEAPOLAuthMode)
  640. {
  641. case EAPOL_AUTH_MODE_0:
  642. fAuthSendPacket = TRUE;
  643. break;
  644. case EAPOL_AUTH_MODE_1:
  645. fAuthSendPacket = FALSE;
  646. break;
  647. case EAPOL_AUTH_MODE_2:
  648. fAuthSendPacket = FALSE;
  649. break;
  650. }
  651. if ((fSupplicantSendPacket) && (fAuthSendPacket))
  652. {
  653. // Allocate new buffer
  654. pEapolPkt = (EAPOL_PACKET *) MALLOC (sizeof (EAPOL_PACKET));
  655. if (pEapolPkt == NULL)
  656. {
  657. TRACE0 (EAPOL, "FSMLogoff: Error in allocating memory for EAPOL packet");
  658. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  659. break;
  660. }
  661. // Fill in fields
  662. memcpy ((BYTE *)pEapolPkt->EthernetType,
  663. (BYTE *)pPCB->bEtherType,
  664. SIZE_ETHERNET_TYPE);
  665. pEapolPkt->ProtocolVersion = pPCB->bProtocolVersion;
  666. pEapolPkt->PacketType = EAPOL_Logoff;
  667. HostToWireFormat16 ((WORD)0, (BYTE *)pEapolPkt->PacketBodyLength);
  668. // Send packet out on the port
  669. dwRetCode = ElWriteToPort (pPCB,
  670. (CHAR *)pEapolPkt,
  671. sizeof (EAPOL_PACKET));
  672. if (dwRetCode != NO_ERROR)
  673. {
  674. TRACE1 (EAPOL, "FSMLogoff: Error in writing Logoff pkt to port %ld",
  675. dwRetCode);
  676. break;
  677. }
  678. // Mark that EAPOL_Logoff was sent out on the port
  679. pPCB->dwLogoffSent = 1;
  680. }
  681. } while (FALSE);
  682. TRACE1 (EAPOL, "Setting state LOGOFF for port %ws", pPCB->pwszFriendlyName);
  683. DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_STATE_TRANSITION,
  684. EAPOLStates[((pPCB->State < EAPOLSTATE_LOGOFF) || (pPCB->State > EAPOLSTATE_AUTHENTICATED))?EAPOLSTATE_UNDEFINED:pPCB->State],
  685. EAPOLStates[EAPOLSTATE_LOGOFF]);
  686. pPCB->State = EAPOLSTATE_LOGOFF;
  687. pPCB->EapUIState = 0;
  688. // Release user token
  689. if (pPCB->hUserToken != NULL)
  690. {
  691. if (!CloseHandle (pPCB->hUserToken))
  692. {
  693. dwRetCode = GetLastError ();
  694. TRACE1 (EAPOL, "FSMLogoff: CloseHandle failed with error %ld",
  695. dwRetCode);
  696. dwRetCode = NO_ERROR;
  697. }
  698. }
  699. pPCB->hUserToken = NULL;
  700. // Free Identity buffer
  701. if (pPCB->pszIdentity != NULL)
  702. {
  703. FREE (pPCB->pszIdentity);
  704. pPCB->pszIdentity = NULL;
  705. }
  706. // Free Password buffer
  707. if (pPCB->PasswordBlob.pbData != NULL)
  708. {
  709. FREE (pPCB->PasswordBlob.pbData);
  710. pPCB->PasswordBlob.pbData = NULL;
  711. pPCB->PasswordBlob.cbData = 0;
  712. }
  713. // Free user-specific data in the PCB
  714. if (pPCB->pCustomAuthUserData != NULL)
  715. {
  716. FREE (pPCB->pCustomAuthUserData);
  717. pPCB->pCustomAuthUserData = NULL;
  718. }
  719. pPCB->fGotUserIdentity = FALSE;
  720. if (pEapolPkt != NULL)
  721. {
  722. FREE (pEapolPkt);
  723. pEapolPkt = NULL;
  724. }
  725. TRACE1 (EAPOL, "FSMLogoff completed for port %ws", pPCB->pwszFriendlyName);
  726. return dwRetCode;
  727. }
  728. //
  729. // FSMConnecting
  730. //
  731. // Description:
  732. //
  733. // Funtion called to send out EAPOL_Start packet. If MaxStart EAPOL_Start
  734. // packets have been sent out, State Machine moves to Authenticated state
  735. //
  736. // Arguments:
  737. // pPCB - Pointer to the PCB for the port on which Start packet is
  738. // to be sent out
  739. //
  740. // Return values:
  741. // NO_ERROR - success
  742. // non-zero - error
  743. //
  744. DWORD
  745. FSMConnecting (
  746. IN EAPOL_PCB *pPCB,
  747. IN EAPOL_PACKET *pDummy
  748. )
  749. {
  750. EAPOL_PACKET *pEapolPkt = NULL;
  751. DWORD dwStartInterval = 0;
  752. GUID DeviceGuid;
  753. DWORD dwRetCode = NO_ERROR;
  754. TRACE1 (EAPOL, "FSMConnecting entered for port %ws", pPCB->pwszFriendlyName);
  755. do
  756. {
  757. // Flag that authentication has not completed in the EAP module
  758. // on the client-side.
  759. pPCB->fLocalEAPAuthSuccess = FALSE;
  760. pPCB->dwLocalEAPAuthResult = NO_ERROR;
  761. if (pPCB->State == EAPOLSTATE_CONNECTING)
  762. {
  763. // If PCB->State was Connecting earlier, increment ulStartCount
  764. // else set ulStartCount to zero
  765. // Did not receive Req/Id
  766. if ((++(pPCB->ulStartCount)) > pPCB->EapolConfig.dwmaxStart)
  767. {
  768. // Deactivate start timer
  769. RESTART_TIMER (pPCB->hTimer,
  770. INFINITE_SECONDS,
  771. "PCB",
  772. &dwRetCode);
  773. if (dwRetCode != NO_ERROR)
  774. {
  775. break;
  776. }
  777. TRACE0 (EAPOL, "FSMConnecting: Sent out maxStart with no response, Setting AUTHENTICATED state");
  778. // Sent out enough EAPOL_Starts
  779. // Go into authenticated state
  780. if ((dwRetCode = FSMAuthenticated (pPCB,
  781. pEapolPkt)) != NO_ERROR)
  782. {
  783. TRACE1 (EAPOL, "FSMConnecting: Error in FSMAuthenticated %ld",
  784. dwRetCode);
  785. break;
  786. }
  787. // No need to send out more EAPOL_Start packets
  788. // Reset start packet count
  789. pPCB->ulStartCount = 0;
  790. pPCB->fIsRemoteEndEAPOLAware = FALSE;
  791. break;
  792. }
  793. }
  794. else
  795. {
  796. pPCB->ulStartCount++;
  797. }
  798. // Initialize the address of previously associated AP
  799. // Only if the reauthentication goes through without getting
  800. // into CONNECTING state, will a IP Renew *not* be done
  801. ZeroMemory (pPCB->bPreviousDestMacAddr, SIZE_MAC_ADDR);
  802. // If user is not logged in, send out EAPOL_Start packets
  803. // at intervals of 1 second each. This is used to detect if the
  804. // interface is on a secure network or not.
  805. // If user is logged in, use the configured value for the
  806. // StartPeriod as the interval
  807. if (!g_fUserLoggedOn)
  808. {
  809. dwStartInterval = EAPOL_INIT_START_PERIOD; // 1 second
  810. }
  811. else
  812. {
  813. dwStartInterval = pPCB->EapolConfig.dwstartPeriod;
  814. }
  815. // Restart timer with startPeriod
  816. // Even if error occurs, timeout will happen
  817. // Else, we won't be able to get out of connecting state
  818. RESTART_TIMER (pPCB->hTimer,
  819. dwStartInterval,
  820. "PCB",
  821. &dwRetCode);
  822. if (dwRetCode != NO_ERROR)
  823. {
  824. TRACE1 (EAPOL, "FSMConnecting: Error in RESTART_TIMER %ld",
  825. dwRetCode);
  826. break;
  827. }
  828. // Send out EAPOL_Start conditionally
  829. if (((pPCB->dwSupplicantMode == SUPPLICANT_MODE_2) &&
  830. (pPCB->fEAPOLTransmissionFlag)) ||
  831. (pPCB->dwSupplicantMode == SUPPLICANT_MODE_3))
  832. {
  833. // Send out EAPOL_Start
  834. // Allocate new buffer
  835. pEapolPkt = (EAPOL_PACKET *) MALLOC (sizeof(EAPOL_PACKET));
  836. if (pEapolPkt == NULL)
  837. {
  838. TRACE0 (EAPOL, "FSMConnecting: Error in allocating memory for EAPOL packet");
  839. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  840. break;
  841. }
  842. memcpy ((BYTE *)pEapolPkt->EthernetType,
  843. (BYTE *)pPCB->bEtherType,
  844. SIZE_ETHERNET_TYPE);
  845. pEapolPkt->ProtocolVersion = pPCB->bProtocolVersion;
  846. pEapolPkt->PacketType = EAPOL_Start;
  847. HostToWireFormat16 ((WORD)0, (BYTE *)pEapolPkt->PacketBodyLength);
  848. // Send packet out on the port
  849. dwRetCode = ElWriteToPort (pPCB,
  850. (CHAR *)pEapolPkt,
  851. sizeof (EAPOL_PACKET));
  852. if (dwRetCode != NO_ERROR)
  853. {
  854. TRACE1 (EAPOL, "FSMConnecting: Error in writing Start Pkt to port %ld",
  855. dwRetCode);
  856. break;
  857. }
  858. }
  859. TRACE1 (EAPOL, "Setting state CONNECTING for port %ws", pPCB->pwszFriendlyName);
  860. DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_STATE_TRANSITION,
  861. EAPOLStates[((pPCB->State < EAPOLSTATE_LOGOFF) || (pPCB->State > EAPOLSTATE_AUTHENTICATED))?EAPOLSTATE_UNDEFINED:pPCB->State],
  862. EAPOLStates[EAPOLSTATE_CONNECTING]);
  863. pPCB->State = EAPOLSTATE_CONNECTING;
  864. SET_EAPOL_START_TIMER(pPCB);
  865. // Reset UI interaction state
  866. pPCB->EapUIState = 0;
  867. } while (FALSE);
  868. if (pEapolPkt != NULL)
  869. {
  870. FREE (pEapolPkt);
  871. }
  872. TRACE1 (EAPOL, "FSMConnecting completed for port %ws", pPCB->pwszFriendlyName);
  873. return dwRetCode;
  874. }
  875. //
  876. // FSMAcquired
  877. //
  878. // Description:
  879. // Function called when the port receives a EAP-Request/Identity packet.
  880. // EAP processing of the packet occurs and a EAP-Response/Identity may
  881. // be sent out by EAP if required.
  882. //
  883. //
  884. // Arguments:
  885. // pPCB - Pointer to the PCB for the port on which data is being
  886. // processed
  887. // pEapolPkt - Pointer to EAPOL packet that was received
  888. //
  889. // Return values:
  890. // NO_ERROR - success
  891. // non-zero - error
  892. //
  893. DWORD
  894. FSMAcquired (
  895. IN EAPOL_PCB *pPCB,
  896. IN EAPOL_PACKET *pEapolPkt
  897. )
  898. {
  899. DWORD dwComputerNameLen = 0;
  900. GUID DeviceGuid;
  901. DWORD dwRetCode= NO_ERROR;
  902. TRACE1 (EAPOL, "FSMAcquired entered for port %ws", pPCB->pwszFriendlyName);
  903. do
  904. {
  905. // Flag that authentication has not completed in the EAP module
  906. // on the client-side.
  907. pPCB->fLocalEAPAuthSuccess = FALSE;
  908. pPCB->dwLocalEAPAuthResult = NO_ERROR;
  909. // Restart timer with authPeriod
  910. // Even if there is error in processing, the authtimer timeout
  911. // should happen
  912. RESTART_TIMER (pPCB->hTimer,
  913. pPCB->EapolConfig.dwauthPeriod,
  914. "PCB",
  915. &dwRetCode);
  916. if (dwRetCode != NO_ERROR)
  917. {
  918. TRACE1 (EAPOL, "FSMAcquired: Error in RESTART_TIMER %ld",
  919. dwRetCode);
  920. break;
  921. }
  922. // Since an EAP Req-ID was received, reset EAPOL_Start count
  923. pPCB->ulStartCount = 0;
  924. // Flag that no EAPOL-Key transmit key was received
  925. pPCB->fTransmitKeyReceived = FALSE;
  926. // If current received EAP Id is the same the previous EAP Id
  927. // send the last EAPOL packet again
  928. if (((PPP_EAP_PACKET *)pEapolPkt->PacketBody)->Id ==
  929. pPCB->dwPreviousId)
  930. {
  931. TRACE0 (EAPOL, "FSMAcquired: Re-xmitting EAP_Packet to port");
  932. dwRetCode = ElWriteToPort (pPCB,
  933. (CHAR *)pPCB->pbPreviousEAPOLPkt,
  934. pPCB->dwSizeOfPreviousEAPOLPkt);
  935. if (dwRetCode != NO_ERROR)
  936. {
  937. TRACE1 (EAPOL, "FSMAcquired: Error in writing re-xmitted EAP_Packet to port %ld",
  938. dwRetCode);
  939. break;
  940. }
  941. }
  942. else
  943. {
  944. // Indicate to EAP-Dll to cleanup any leftovers from earlier
  945. // authentication. This is to take care of cases where errors
  946. // occured in the earlier authentication and cleanup wasn't done
  947. if ((dwRetCode = ElEapEnd (pPCB)) != NO_ERROR)
  948. {
  949. TRACE1 (EAPOL, "FSMAcquired: Error in ElEapEnd = %ld",
  950. dwRetCode);
  951. break;
  952. }
  953. // Process the EAP packet
  954. // ElEapWork will send out response if required
  955. if (( dwRetCode = ElEapWork (
  956. pPCB,
  957. (PPP_EAP_PACKET *)pEapolPkt->PacketBody
  958. )) != NO_ERROR)
  959. {
  960. // Ignore error if UI is waiting for input
  961. if (dwRetCode != ERROR_IO_PENDING)
  962. {
  963. TRACE1 (EAPOL, "FSMAcquired: Error in ElEapWork %ld",
  964. dwRetCode);
  965. break;
  966. }
  967. else
  968. {
  969. dwRetCode = NO_ERROR;
  970. }
  971. }
  972. }
  973. TRACE1 (EAPOL, "Setting state ACQUIRED for port %ws", pPCB->pwszFriendlyName);
  974. SET_EAPOL_AUTH_TIMER(pPCB);
  975. DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_STATE_TRANSITION,
  976. EAPOLStates[((pPCB->State < EAPOLSTATE_LOGOFF) || (pPCB->State > EAPOLSTATE_AUTHENTICATED))?EAPOLSTATE_UNDEFINED:pPCB->State],
  977. EAPOLStates[EAPOLSTATE_ACQUIRED]);
  978. pPCB->State = EAPOLSTATE_ACQUIRED;
  979. // ElNetmanNotify (pPCB, EAPOL_NCS_CRED_REQUIRED, NULL);
  980. } while (FALSE);
  981. TRACE1 (EAPOL, "FSMAcquired completed for port %ws", pPCB->pwszFriendlyName);
  982. return dwRetCode;
  983. }
  984. //
  985. // FSMAuthenticating
  986. //
  987. // Description:
  988. //
  989. // Function called when an non EAP-Request/Identity packet is received on the
  990. // port. EAP processing of the data occurs.
  991. //
  992. // Arguments:
  993. // pPCB - Pointer to the PCB for the port on which data is being
  994. // processed
  995. // pEapolPkt - Pointer to EAPOL packet that was received
  996. //
  997. // Return values:
  998. // NO_ERROR - success
  999. // non-zero - error
  1000. //
  1001. DWORD
  1002. FSMAuthenticating (
  1003. IN EAPOL_PCB *pPCB,
  1004. IN EAPOL_PACKET *pEapolPkt
  1005. )
  1006. {
  1007. GUID DeviceGuid;
  1008. DWORD dwRetCode = NO_ERROR;
  1009. TRACE1 (EAPOL, "FSMAuthenticating entered for port %ws", pPCB->pwszFriendlyName);
  1010. do
  1011. {
  1012. // Restart timer with authPeriod
  1013. // Even if there is error in ElEapWork, the authtimer timeout
  1014. // should happen
  1015. RESTART_TIMER (pPCB->hTimer,
  1016. pPCB->EapolConfig.dwauthPeriod,
  1017. "PCB",
  1018. &dwRetCode);
  1019. if (dwRetCode != NO_ERROR)
  1020. {
  1021. TRACE1 (EAPOL, "FSMAuthenticating: Error in RESTART_TIMER %ld",
  1022. dwRetCode);
  1023. break;
  1024. }
  1025. // If current received EAP Id is the same the previous EAP Id
  1026. // send the last EAPOL packet again
  1027. // For EAPCODE_Success and EAPCODE_Failure, the value of id field
  1028. // will not be increment, Refer to EAP RFC
  1029. if ((((PPP_EAP_PACKET *)pEapolPkt->PacketBody)->Id
  1030. == pPCB->dwPreviousId) &&
  1031. (((PPP_EAP_PACKET *)pEapolPkt->PacketBody)->Code
  1032. != EAPCODE_Success) &&
  1033. (((PPP_EAP_PACKET *)pEapolPkt->PacketBody)->Code
  1034. != EAPCODE_Failure))
  1035. {
  1036. TRACE0 (EAPOL, "FSMAuthenticating: Re-xmitting EAP_Packet to port");
  1037. dwRetCode = ElWriteToPort (pPCB,
  1038. (CHAR *)pPCB->pbPreviousEAPOLPkt,
  1039. pPCB->dwSizeOfPreviousEAPOLPkt);
  1040. if (dwRetCode != NO_ERROR)
  1041. {
  1042. TRACE1 (EAPOL, "FSMAuthenticating: Error in writing re-xmitted EAP_Packet to port = %ld",
  1043. dwRetCode);
  1044. break;
  1045. }
  1046. }
  1047. else
  1048. {
  1049. // Process the EAP packet
  1050. // ElEapWork will send out response if required
  1051. if (( dwRetCode = ElEapWork (
  1052. pPCB,
  1053. (PPP_EAP_PACKET *)pEapolPkt->PacketBody
  1054. )) != NO_ERROR)
  1055. {
  1056. TRACE1 (EAPOL, "FSMAuthenticating: Error in ElEapWork %ld",
  1057. dwRetCode);
  1058. break;
  1059. }
  1060. }
  1061. TRACE1 (EAPOL, "Setting state AUTHENTICATING for port %ws", pPCB->pwszFriendlyName);
  1062. SET_EAPOL_AUTH_TIMER(pPCB);
  1063. DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_STATE_TRANSITION,
  1064. EAPOLStates[((pPCB->State < EAPOLSTATE_LOGOFF) || (pPCB->State > EAPOLSTATE_AUTHENTICATED))?EAPOLSTATE_UNDEFINED:pPCB->State],
  1065. EAPOLStates[EAPOLSTATE_AUTHENTICATING]);
  1066. pPCB->State = EAPOLSTATE_AUTHENTICATING;
  1067. ElNetmanNotify (pPCB, EAPOL_NCS_AUTHENTICATING, NULL);
  1068. } while (FALSE);
  1069. TRACE1 (EAPOL, "FSMAuthenticating completed for port %ws", pPCB->pwszFriendlyName);
  1070. return dwRetCode;
  1071. }
  1072. //
  1073. // FSMHeld
  1074. //
  1075. // Description:
  1076. // Function called when a EAP-Failure packet is received in the
  1077. // Authenticating state. State machine is held for heldPeriod before
  1078. // re-authentication can occur.
  1079. //
  1080. // Arguments:
  1081. // pPCB - Pointer to the PCB for the port on which data is being
  1082. // processed
  1083. //
  1084. // Return values:
  1085. // NO_ERROR - success
  1086. // non-zero - error
  1087. //
  1088. DWORD
  1089. FSMHeld (
  1090. IN EAPOL_PCB *pPCB,
  1091. IN EAPOL_PACKET *pEapolPkt
  1092. )
  1093. {
  1094. DWORD dwRetCode = NO_ERROR;
  1095. TRACE1 (EAPOL, "FSMHeld entered for port %ws", pPCB->pwszFriendlyName);
  1096. do
  1097. {
  1098. TRACE1 (EAPOL, "FSMHeld: EAP authentication failed with error 0x%x",
  1099. pPCB->dwLocalEAPAuthResult);
  1100. // Delete current credentials only if there is actually an error
  1101. // in the EAP module during processing.
  1102. // Ignore EAP-Failures arising out of session time-outs on AP,
  1103. // backend, etc.
  1104. if (pPCB->dwLocalEAPAuthResult != NO_ERROR)
  1105. {
  1106. pPCB->dwAuthFailCount++;
  1107. TRACE1 (EAPOL, "Restarting Held timer with time value = %ld",
  1108. pPCB->EapolConfig.dwheldPeriod);
  1109. TRACE1 (EAPOL, "FSMHeld: Setting state HELD for port %ws",
  1110. pPCB->pwszFriendlyName);
  1111. // Free Identity buffer
  1112. if (pPCB->pszIdentity != NULL)
  1113. {
  1114. FREE (pPCB->pszIdentity);
  1115. pPCB->pszIdentity = NULL;
  1116. }
  1117. // Free Password buffer
  1118. if (pPCB->PasswordBlob.pbData != NULL)
  1119. {
  1120. FREE (pPCB->PasswordBlob.pbData);
  1121. pPCB->PasswordBlob.pbData = NULL;
  1122. pPCB->PasswordBlob.cbData = 0;
  1123. }
  1124. // Free user-specific data in the PCB
  1125. if (pPCB->pCustomAuthUserData != NULL)
  1126. {
  1127. FREE (pPCB->pCustomAuthUserData);
  1128. pPCB->pCustomAuthUserData = NULL;
  1129. }
  1130. // Free connection data
  1131. if (pPCB->pCustomAuthConnData != NULL)
  1132. {
  1133. FREE (pPCB->pCustomAuthConnData);
  1134. pPCB->pCustomAuthConnData = NULL;
  1135. }
  1136. // Delete User Data stored in registry since it is invalid
  1137. if (pPCB->pSSID != NULL)
  1138. {
  1139. if ((dwRetCode = ElDeleteEapUserInfo (
  1140. pPCB->hUserToken,
  1141. pPCB->pwszDeviceGUID,
  1142. pPCB->dwEapTypeToBeUsed,
  1143. pPCB->pSSID->SsidLength,
  1144. pPCB->pSSID->Ssid
  1145. )) != NO_ERROR)
  1146. {
  1147. TRACE1 (EAPOL, "FSMHeld: ElDeleteEapUserInfo failed with error %ld",
  1148. dwRetCode);
  1149. dwRetCode = NO_ERROR;
  1150. }
  1151. }
  1152. else
  1153. {
  1154. if ((dwRetCode = ElDeleteEapUserInfo (
  1155. pPCB->hUserToken,
  1156. pPCB->pwszDeviceGUID,
  1157. pPCB->dwEapTypeToBeUsed,
  1158. 0,
  1159. NULL
  1160. )) != NO_ERROR)
  1161. {
  1162. TRACE1 (EAPOL, "FSMHeld: ElDeleteEapUserInfo failed with error %ld",
  1163. dwRetCode);
  1164. dwRetCode = NO_ERROR;
  1165. }
  1166. }
  1167. // Since there has been an error in credentials, start afresh
  1168. // the authentication. Credentials may have changed e.g. certs
  1169. // may be renewed, MD5 credentials corrected etc.
  1170. pPCB->fGotUserIdentity = FALSE;
  1171. if (pPCB->hUserToken != NULL)
  1172. {
  1173. if (!CloseHandle (pPCB->hUserToken))
  1174. {
  1175. dwRetCode = GetLastError ();
  1176. TRACE1 (EAPOL, "FSMHeld: CloseHandle failed with error %ld",
  1177. dwRetCode);
  1178. dwRetCode = NO_ERROR;
  1179. }
  1180. }
  1181. pPCB->hUserToken = NULL;
  1182. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_EAP_AUTHENTICATION_FAILED, pPCB->dwLocalEAPAuthResult);
  1183. }
  1184. else
  1185. {
  1186. if (pPCB->State == EAPOLSTATE_ACQUIRED)
  1187. {
  1188. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_EAP_AUTHENTICATION_FAILED_ACQUIRED);
  1189. }
  1190. else
  1191. {
  1192. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_EAP_AUTHENTICATION_FAILED_DEFAULT);
  1193. }
  1194. }
  1195. DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_STATE_TRANSITION,
  1196. EAPOLStates[((pPCB->State < EAPOLSTATE_LOGOFF) || (pPCB->State > EAPOLSTATE_AUTHENTICATED))?EAPOLSTATE_UNDEFINED:pPCB->State],
  1197. EAPOLStates[EAPOLSTATE_HELD]);
  1198. pPCB->State = EAPOLSTATE_HELD;
  1199. TRACE1 (EAPOL, "FSMHeld: Port %ws set to HELD state",
  1200. pPCB->pwszDeviceGUID);
  1201. if (pPCB->dwLocalEAPAuthResult != NO_ERROR)
  1202. {
  1203. // If authfailed limit reached, go to Disconnected state
  1204. if (pPCB->dwAuthFailCount >= pPCB->dwTotalMaxAuthFailCount)
  1205. {
  1206. TRACE2 (EAPOL, "FSMHeld: Fail count (%ld) > Max fail count (%ld)",
  1207. pPCB->dwAuthFailCount, pPCB->dwTotalMaxAuthFailCount);
  1208. FSMDisconnected (pPCB, NULL);
  1209. break;
  1210. }
  1211. }
  1212. SET_EAPOL_HELD_TIMER(pPCB);
  1213. // Restart timer with heldPeriod
  1214. RESTART_TIMER (pPCB->hTimer,
  1215. pPCB->EapolConfig.dwheldPeriod,
  1216. "PCB",
  1217. &dwRetCode);
  1218. if (dwRetCode != NO_ERROR)
  1219. {
  1220. TRACE1 (EAPOL, "FSMHeld: Error in RESTART_TIMER %ld",
  1221. dwRetCode);
  1222. break;
  1223. }
  1224. } while (FALSE);
  1225. TRACE1 (EAPOL, "FSMHeld completed for port %ws", pPCB->pwszFriendlyName);
  1226. return dwRetCode;
  1227. }
  1228. //
  1229. // FSMAuthenticated
  1230. //
  1231. // Description:
  1232. //
  1233. // Function called when a EAP-Success packet is received or MaxStart
  1234. // EAPOL_Startpackets have been sent out, but no EAP-Request/Identity
  1235. // packets were received. If EAP-Success packet is request, DHCP client
  1236. // is restarted to get a new IP address.
  1237. //
  1238. // Arguments:
  1239. // pPCB - Pointer to the PCB for the port on which data is being
  1240. // processed
  1241. // pEapolPkt - Pointer to EAPOL packet that was received
  1242. //
  1243. // Return values:
  1244. // NO_ERROR - success
  1245. // non-zero - error
  1246. //
  1247. DWORD
  1248. FSMAuthenticated (
  1249. IN EAPOL_PCB *pPCB,
  1250. IN EAPOL_PACKET *pEapolPkt
  1251. )
  1252. {
  1253. DHCP_PNP_CHANGE DhcpPnpChange;
  1254. WCHAR *pwszGUIDBuffer = NULL;
  1255. BOOLEAN fReAuthenticatedWithSamePeer = FALSE;
  1256. DWORD dwRetCode = NO_ERROR;
  1257. TRACE1 (EAPOL, "FSMAuthenticated entered for port %ws",
  1258. pPCB->pwszFriendlyName);
  1259. do
  1260. {
  1261. // Shutdown earlier EAP session
  1262. ElEapEnd (pPCB);
  1263. // Call DHCP only if state machine went through authentication
  1264. // If FSM is getting AUTHENTICATED by default, don't renew address
  1265. // Also, if reauthentication is happening with same peer, namely in
  1266. // wireless, don't renew address
  1267. #if 0
  1268. if (pPCB->PhysicalMediumType == NdisPhysicalMediumWirelessLan)
  1269. {
  1270. if (!memcmp (pPCB->bDestMacAddr, pPCB->bPreviousDestMacAddr,
  1271. SIZE_MAC_ADDR))
  1272. {
  1273. fReAuthenticatedWithSamePeer = TRUE;
  1274. }
  1275. else
  1276. {
  1277. memcpy (pPCB->bPreviousDestMacAddr, pPCB->bDestMacAddr,
  1278. SIZE_MAC_ADDR);
  1279. }
  1280. }
  1281. #endif
  1282. if ((pPCB->ulStartCount < pPCB->EapolConfig.dwmaxStart) &&
  1283. (!fReAuthenticatedWithSamePeer))
  1284. {
  1285. if ((pwszGUIDBuffer = MALLOC ((wcslen(pPCB->pwszDeviceGUID) + 1)*sizeof(WCHAR))) == NULL)
  1286. {
  1287. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  1288. break;
  1289. }
  1290. wcscpy (pwszGUIDBuffer, pPCB->pwszDeviceGUID);
  1291. InterlockedIncrement (&g_lWorkerThreads);
  1292. if (!QueueUserWorkItem (
  1293. (LPTHREAD_START_ROUTINE)ElIPPnPWorker,
  1294. (PVOID)pwszGUIDBuffer,
  1295. WT_EXECUTELONGFUNCTION
  1296. ))
  1297. {
  1298. InterlockedDecrement (&g_lWorkerThreads);
  1299. FREE (pwszGUIDBuffer);
  1300. dwRetCode = GetLastError();
  1301. TRACE1 (PORT, "FSMAuthenticated: Critical error: QueueUserWorkItem failed with error %ld",
  1302. dwRetCode);
  1303. // Ignore DHCP error, it's outside 802.1X logic
  1304. dwRetCode = NO_ERROR;
  1305. }
  1306. else
  1307. {
  1308. TRACE0 (PORT, "FSMAuthenticated: Queued ElIPPnPWorker");
  1309. }
  1310. }
  1311. TRACE1 (EAPOL, "Setting state AUTHENTICATED for port %ws", pPCB->pwszFriendlyName);
  1312. DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_STATE_TRANSITION,
  1313. EAPOLStates[((pPCB->State < EAPOLSTATE_LOGOFF) || (pPCB->State > EAPOLSTATE_AUTHENTICATED))?EAPOLSTATE_UNDEFINED:pPCB->State],
  1314. EAPOLStates[EAPOLSTATE_AUTHENTICATED]);
  1315. if (pPCB->fLocalEAPAuthSuccess)
  1316. {
  1317. DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_EAP_AUTHENTICATION_SUCCEEDED);
  1318. }
  1319. else
  1320. {
  1321. DbLogPCBEvent (DBLOG_CATEG_WARN, pPCB, EAPOL_EAP_AUTHENTICATION_DEFAULT);
  1322. }
  1323. pPCB->State = EAPOLSTATE_AUTHENTICATED;
  1324. // In case of Wireless LAN ensure that there is EAPOL_Key packets
  1325. // received for transmit key
  1326. if (pPCB->PhysicalMediumType == NdisPhysicalMediumWirelessLan)
  1327. {
  1328. if ((dwRetCode = ElSetEAPOLKeyReceivedTimer (pPCB)) != NO_ERROR)
  1329. {
  1330. TRACE1 (EAPOL, "FSMAuthenticated: ElSetEAPOLKeyReceivedTimer failed with error %ld",
  1331. dwRetCode);
  1332. break;
  1333. }
  1334. }
  1335. } while (FALSE);
  1336. TRACE1 (EAPOL, "FSMAuthenticated completed for port %ws", pPCB->pwszFriendlyName);
  1337. return dwRetCode;
  1338. }
  1339. //
  1340. // FSMKeyReceive
  1341. //
  1342. // Description:
  1343. // Function called when an EAPOL-Key packet is received.
  1344. // The WEP key is decrypted and plumbed down to the NIC driver.
  1345. //
  1346. // Arguments:
  1347. // pPCB - Pointer to the PCB for the port on which data is being
  1348. // processed
  1349. // pEapolPkt - Pointer to EAPOL packet that was received
  1350. //
  1351. // Return values:
  1352. // NO_ERROR - success
  1353. // non-zero - error
  1354. //
  1355. DWORD
  1356. FSMKeyReceive (
  1357. IN EAPOL_PCB *pPCB,
  1358. IN EAPOL_PACKET *pEapolPkt
  1359. )
  1360. {
  1361. EAPOL_KEY_DESC *pKeyDesc = NULL;
  1362. DWORD dwRetCode = NO_ERROR;
  1363. TRACE1 (EAPOL, "FSMKeyReceive entered for port %ws", pPCB->pwszFriendlyName);
  1364. do
  1365. {
  1366. pKeyDesc = (EAPOL_KEY_DESC *)pEapolPkt->PacketBody;
  1367. switch (pKeyDesc->DescriptorType)
  1368. {
  1369. case EAPOL_KEY_DESC_RC4:
  1370. if ((dwRetCode = ElKeyReceiveRC4 (pPCB,
  1371. pEapolPkt)) != NO_ERROR)
  1372. {
  1373. TRACE1 (EAPOL, "FSMKeyReceive: ElKeyReceiveRC4 failed with error %ld",
  1374. dwRetCode);
  1375. }
  1376. break;
  1377. #if 0
  1378. case EAPOL_KEY_DESC_PER_STA:
  1379. if ((dwRetCode = ElKeyReceivePerSTA (pPCB,
  1380. pEapolPkt)) != NO_ERROR)
  1381. {
  1382. TRACE1 (EAPOL, "FSMKeyReceive: ElKeyReceivePerSTA failed with error %ld",
  1383. dwRetCode);
  1384. }
  1385. break;
  1386. #endif
  1387. default:
  1388. dwRetCode = ERROR_INVALID_PARAMETER;
  1389. TRACE1 (EAPOL, "FSMKeyReceive: Invalid DescriptorType (%ld)",
  1390. pKeyDesc->DescriptorType);
  1391. break;
  1392. }
  1393. }
  1394. while (FALSE);
  1395. if (dwRetCode != NO_ERROR)
  1396. {
  1397. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB,
  1398. EAPOL_ERROR_PROCESSING_EAPOL_KEY, dwRetCode);
  1399. }
  1400. TRACE1 (EAPOL, "FSMKeyReceive completed for port %ws", pPCB->pwszFriendlyName);
  1401. return dwRetCode;
  1402. }
  1403. //
  1404. // ElKeyReceiveRC4
  1405. //
  1406. // Description:
  1407. // Function called when an EAPOL-Key packet is received
  1408. // with RC4 DescriptorType
  1409. //
  1410. // Arguments:
  1411. // pPCB - Pointer to the PCB for the port on which data is being
  1412. // processed
  1413. // pEapolPkt - Pointer to EAPOL packet that was received
  1414. //
  1415. // Return values:
  1416. // NO_ERROR - success
  1417. // non-zero - error
  1418. //
  1419. DWORD
  1420. ElKeyReceiveRC4 (
  1421. IN EAPOL_PCB *pPCB,
  1422. IN EAPOL_PACKET *pEapolPkt
  1423. )
  1424. {
  1425. EAPOL_KEY_DESC *pKeyDesc = NULL;
  1426. ULONGLONG ullReplayCheck = 0;
  1427. BYTE bReplayCheck[8];
  1428. BYTE *pbMD5EapolPkt = NULL;
  1429. DWORD dwMD5EapolPktLen = 0;
  1430. DWORD dwEapPktLen = 0;
  1431. DWORD dwIndex = 0;
  1432. BYTE bHMACMD5HashBuffer[MD5DIGESTLEN];
  1433. RC4_KEYSTRUCT rc4key;
  1434. BYTE bKeyBuffer[48];
  1435. BYTE *pbKeyToBePlumbed = NULL;
  1436. DWORD dwKeyLength = 0;
  1437. NDIS_802_11_WEP *pNdisWEPKey = NULL;
  1438. BYTE *pbMPPESendKey = NULL, *pbMPPERecvKey = NULL;
  1439. DWORD dwMPPESendKeyLength = 0, dwMPPERecvKeyLength = 0;
  1440. DWORD dwRetCode = NO_ERROR;
  1441. TRACE1 (EAPOL, "ElKeyReceiveRC4 entered for port %ws", pPCB->pwszFriendlyName);
  1442. do
  1443. {
  1444. if (WireToHostFormat16 (pEapolPkt->PacketBodyLength) < FIELD_OFFSET (EAPOL_KEY_DESC, Key))
  1445. {
  1446. TRACE0 (EAPOL, "ElKeyReceiveRC4: Invalid EAPOL-Key packet");
  1447. dwRetCode = ERROR_INVALID_PACKET;
  1448. break;
  1449. }
  1450. pKeyDesc = (EAPOL_KEY_DESC *)pEapolPkt->PacketBody;
  1451. dwKeyLength = WireToHostFormat16 (pKeyDesc->KeyLength);
  1452. if (WireToHostFormat16 (pEapolPkt->PacketBodyLength) > sizeof(EAPOL_KEY_DESC))
  1453. {
  1454. if (dwKeyLength != (WireToHostFormat16 (pEapolPkt->PacketBodyLength) - FIELD_OFFSET(EAPOL_KEY_DESC, Key)))
  1455. {
  1456. TRACE1 (EAPOL, "ElKeyReceiveRC4: Invalid Key Length in packet (%ld",
  1457. dwKeyLength);
  1458. dwRetCode = ERROR_INVALID_PACKET;
  1459. break;
  1460. }
  1461. }
  1462. TRACE2 (EAPOL, "KeyLength = %ld, \n KeyIndex = %ld",
  1463. dwKeyLength,
  1464. pKeyDesc->KeyIndex
  1465. );
  1466. memcpy ((BYTE *)bReplayCheck,
  1467. (BYTE *)pKeyDesc->ReplayCounter,
  1468. 8*sizeof(BYTE));
  1469. ullReplayCheck = ((((ULONGLONG)(*((PBYTE)(bReplayCheck)+0))) << 56) +
  1470. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+1))) << 48) +
  1471. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+2))) << 40) +
  1472. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+3))) << 32) +
  1473. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+4))) << 24) +
  1474. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+5))) << 16) +
  1475. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+6))) << 8) +
  1476. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+7)))));
  1477. //
  1478. // Check validity of Key message using the ReplayCounter field
  1479. // Verify if it is in sync with the last ReplayCounter value
  1480. // received
  1481. //
  1482. // TRACE0 (EAPOL, "ElKeyReceiveRC4: Original replay counter in desc ======");
  1483. // EAPOL_DUMPBA (pKeyDesc->ReplayCounter, 8);
  1484. // TRACE0 (EAPOL, "ElKeyReceiveRC4: Converted incoming Replay counter ======= ");
  1485. // EAPOL_DUMPBA ((BYTE *)&ullReplayCheck, 8);
  1486. // TRACE0 (EAPOL, "ElKeyReceiveRC4: Last Replay counter ======= ");
  1487. // EAPOL_DUMPBA ((BYTE *)&(pPCB->ullLastReplayCounter), 8);
  1488. if (ullReplayCheck <= pPCB->ullLastReplayCounter)
  1489. {
  1490. TRACE0 (EAPOL, "ElKeyReceiveRC4: Replay counter is not in sync, something is wrong");
  1491. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_INVALID_EAPOL_KEY);
  1492. break;
  1493. }
  1494. // If valid ReplayCounter, save it in the PCB for future check
  1495. pPCB->ullLastReplayCounter = ullReplayCheck;
  1496. //
  1497. // Verify if the MD5 hash generated on the EAPOL packet,
  1498. // with Signature nulled out, is the same as the signature
  1499. // Use the MPPERecv key as the secret
  1500. //
  1501. dwEapPktLen = WireToHostFormat16 (pEapolPkt->PacketBodyLength);
  1502. dwMD5EapolPktLen = sizeof (EAPOL_PACKET) - sizeof(pEapolPkt->EthernetType) - 1 + dwEapPktLen;
  1503. if ((pbMD5EapolPkt = (BYTE *) MALLOC (dwMD5EapolPktLen)) == NULL)
  1504. {
  1505. TRACE0 (EAPOL, "ElKeyReceiveRC4: Error in MALLOC for pbMD5EapolPkt");
  1506. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  1507. break;
  1508. }
  1509. memcpy ((BYTE *)pbMD5EapolPkt, (BYTE *)pEapolPkt+sizeof(pEapolPkt->EthernetType), dwMD5EapolPktLen);
  1510. // Access the Master Send and Recv key stored locally
  1511. if ((dwRetCode = ElSecureDecodePw (
  1512. &(pPCB->MasterSecretSend),
  1513. &(pbMPPESendKey),
  1514. &dwMPPESendKeyLength
  1515. )) != NO_ERROR)
  1516. {
  1517. TRACE1 (EAPOL, "ElKeyReceiveRC4: ElSecureDecodePw failed for MasterSecretSend with error %ld",
  1518. dwRetCode);
  1519. break;
  1520. }
  1521. if ((dwRetCode = ElSecureDecodePw (
  1522. &(pPCB->MasterSecretRecv),
  1523. &(pbMPPERecvKey),
  1524. &dwMPPERecvKeyLength
  1525. )) != NO_ERROR)
  1526. {
  1527. TRACE1 (EAPOL, "ElKeyReceiveRC4: ElSecureDecodePw failed for MasterSecretRecv with error %ld",
  1528. dwRetCode);
  1529. break;
  1530. }
  1531. //
  1532. // Null out the signature in the key descriptor copy, to calculate
  1533. // the hash on the supplicant side
  1534. //
  1535. ZeroMemory ((BYTE *)(pbMD5EapolPkt
  1536. - sizeof(pEapolPkt->EthernetType) +
  1537. sizeof(EAPOL_PACKET) - 1 + // pEapolPkt->Body
  1538. sizeof(EAPOL_KEY_DESC)- // End of EAPOL_KEY_DESC
  1539. MD5DIGESTLEN-1), // Signature field
  1540. MD5DIGESTLEN);
  1541. (VOID) ElGetHMACMD5Digest (
  1542. pbMD5EapolPkt,
  1543. dwMD5EapolPktLen,
  1544. pbMPPERecvKey,
  1545. dwMPPERecvKeyLength,
  1546. bHMACMD5HashBuffer
  1547. );
  1548. // TRACE0 (EAPOL, "ElKeyReceiveRC4: MD5 Hash body ==");
  1549. // EAPOL_DUMPBA (pbMD5EapolPkt, dwMD5EapolPktLen);
  1550. // TRACE0 (EAPOL, "ElKeyReceiveRC4: MD5 Hash secret ==");
  1551. // EAPOL_DUMPBA (pbMPPERecvKey, dwMPPERecvKeyLength);
  1552. // TRACE0 (EAPOL, "ElKeyReceiveRC4: MD5 Hash generated by Supplicant");
  1553. // EAPOL_DUMPBA (bHMACMD5HashBuffer, MD5DIGESTLEN);
  1554. // TRACE0 (EAPOL, "ElKeyReceiveRC4: Signature sent in EAPOL_KEY_DESC");
  1555. // EAPOL_DUMPBA (pKeyDesc->KeySignature, MD5DIGESTLEN);
  1556. //
  1557. // Check if HMAC-MD5 hash in received packet is what is expected
  1558. //
  1559. if (memcmp (bHMACMD5HashBuffer, pKeyDesc->KeySignature, MD5DIGESTLEN) != 0)
  1560. {
  1561. TRACE0 (EAPOL, "ElKeyReceiveRC4: Signature in Key Desc does not match");
  1562. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_INVALID_EAPOL_KEY);
  1563. break;
  1564. }
  1565. //
  1566. // Decrypt the multicast WEP key if it has been provided
  1567. //
  1568. // Check if there is Key Material (5/16 bytes) at the end of
  1569. // the Key Descriptor
  1570. if (WireToHostFormat16 (pEapolPkt->PacketBodyLength) > sizeof (EAPOL_KEY_DESC))
  1571. {
  1572. memcpy ((BYTE *)bKeyBuffer, (BYTE *)pKeyDesc->Key_IV, 16);
  1573. memcpy ((BYTE *)&bKeyBuffer[16], (BYTE *)pbMPPESendKey, dwMPPESendKeyLength);
  1574. rc4_key (&rc4key, 16 + dwMPPESendKeyLength, bKeyBuffer);
  1575. rc4 (&rc4key, dwKeyLength, pKeyDesc->Key);
  1576. // TRACE0 (EAPOL, " ========= The multicast key is ============= ");
  1577. // EAPOL_DUMPBA (pKeyDesc->Key, dwKeyLength);
  1578. // Use the unencrypted key in the Key Desc as the encryption key
  1579. pbKeyToBePlumbed = pKeyDesc->Key;
  1580. }
  1581. else
  1582. {
  1583. if (dwKeyLength > dwMPPESendKeyLength)
  1584. {
  1585. TRACE1 (EAPOL, "ElKeyReceiveRC4: Invalid Key Length in packet (%ld",
  1586. dwKeyLength);
  1587. dwRetCode = ERROR_INVALID_PACKET;
  1588. break;
  1589. }
  1590. // Use the MPPESend key as the encryption key
  1591. pbKeyToBePlumbed = (BYTE *)pbMPPESendKey;
  1592. }
  1593. if ((pNdisWEPKey = MALLOC ( sizeof(NDIS_802_11_WEP)-1+dwKeyLength ))
  1594. == NULL)
  1595. {
  1596. TRACE0 (EAPOL, "ElKeyReceiveRC4: MALLOC failed for pNdisWEPKey");
  1597. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  1598. break;
  1599. }
  1600. pNdisWEPKey->Length = sizeof(NDIS_802_11_WEP) - 1 + dwKeyLength;
  1601. memcpy ((BYTE *)pNdisWEPKey->KeyMaterial, (BYTE *)pbKeyToBePlumbed,
  1602. dwKeyLength);
  1603. pNdisWEPKey->KeyLength = dwKeyLength;
  1604. // Create the long index out of the byte index got from AP
  1605. // If MSB in byte is set, set MSB in ulong format
  1606. if (pKeyDesc->KeyIndex & 0x80)
  1607. {
  1608. pNdisWEPKey->KeyIndex = 0x80000000;
  1609. }
  1610. else
  1611. {
  1612. pNdisWEPKey->KeyIndex = 0x00000000;
  1613. }
  1614. pNdisWEPKey->KeyIndex |= (pKeyDesc->KeyIndex & 0x03);
  1615. // TRACE1 (ANY, "ElKeyReceiveRC4: Key Index is %x", pNdisWEPKey->KeyIndex);
  1616. // Flag that transmit key was received
  1617. if (pKeyDesc->KeyIndex & 0x80)
  1618. {
  1619. pPCB->fTransmitKeyReceived = TRUE;
  1620. }
  1621. // Use NDISUIO to plumb the key to the driver
  1622. if ((dwRetCode = ElNdisuioSetOIDValue (
  1623. pPCB->hPort,
  1624. OID_802_11_ADD_WEP,
  1625. (BYTE *)pNdisWEPKey,
  1626. pNdisWEPKey->Length)) != NO_ERROR)
  1627. {
  1628. TRACE1 (PORT, "ElKeyReceiveRC4: ElNdisuioSetOIDValue failed with error %ld",
  1629. dwRetCode);
  1630. }
  1631. }
  1632. while (FALSE);
  1633. if (dwRetCode != NO_ERROR)
  1634. {
  1635. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB,
  1636. EAPOL_ERROR_PROCESSING_EAPOL_KEY, dwRetCode);
  1637. }
  1638. if (pbMD5EapolPkt != NULL)
  1639. {
  1640. FREE (pbMD5EapolPkt);
  1641. pbMD5EapolPkt = NULL;
  1642. }
  1643. if (pNdisWEPKey != NULL)
  1644. {
  1645. FREE (pNdisWEPKey);
  1646. pNdisWEPKey = NULL;
  1647. }
  1648. if (pbMPPESendKey != NULL)
  1649. {
  1650. FREE (pbMPPESendKey);
  1651. }
  1652. if (pbMPPERecvKey != NULL)
  1653. {
  1654. FREE (pbMPPERecvKey);
  1655. }
  1656. TRACE1 (EAPOL, "ElKeyReceiveRC4 completed for port %ws", pPCB->pwszFriendlyName);
  1657. return dwRetCode;
  1658. }
  1659. #if 0
  1660. //
  1661. // ElKeyReceivePerSTA
  1662. //
  1663. // Description:
  1664. // Function called when an EAPOL-Key packet is received
  1665. // with PerSTA DescriptorType
  1666. //
  1667. // Arguments:
  1668. // pPCB - Pointer to the PCB for the port on which data is being
  1669. // processed
  1670. // pEapolPkt - Pointer to EAPOL packet that was received
  1671. //
  1672. // Return values:
  1673. // NO_ERROR - success
  1674. // non-zero - error
  1675. //
  1676. DWORD
  1677. ElKeyReceivePerSTA (
  1678. IN EAPOL_PCB *pPCB,
  1679. IN EAPOL_PACKET *pEapolPkt
  1680. )
  1681. {
  1682. EAPOL_KEY_DESC *pKeyDesc = NULL;
  1683. ULONGLONG ullReplayCheck = 0;
  1684. BYTE bReplayCheck[8];
  1685. BYTE *pbMD5EapolPkt = NULL;
  1686. DWORD dwMD5EapolPktLen = 0;
  1687. DWORD dwEapPktLen = 0;
  1688. DWORD dwIndex = 0;
  1689. BYTE bHMACMD5HashBuffer[MD5DIGESTLEN];
  1690. RC4_KEYSTRUCT rc4key;
  1691. BYTE bKeyBuffer[48];
  1692. BYTE *pbKeyToBePlumbed = NULL;
  1693. DWORD dwRandomLength = 0;
  1694. NDIS_802_11_WEP *pNdisWEPKey = NULL;
  1695. BYTE *pbMasterSecretSend = NULL;
  1696. DWORD dwMasterSecretSendLength = 0;
  1697. BYTE *pbMasterSecretRecv = NULL;
  1698. DWORD dwMasterSecretRecvLength = 0;
  1699. BYTE *pbDynamicSendKey = NULL, *pbDynamicRecvKey = NULL;
  1700. DWORD dwDynamicKeyLength = 0;
  1701. EAPOL_KEY_MATERIAL *pEapolKeyMaterial = NULL;
  1702. PBYTE pbPaddedKeyMaterial = NULL;
  1703. BOOLEAN fIsUnicastKey = FALSE;
  1704. SESSION_KEYS OldSessionKeys = {0};
  1705. SESSION_KEYS NewSessionKeys = {0};
  1706. DWORD dwRetCode = NO_ERROR;
  1707. TRACE1 (EAPOL, "ElKeyReceivePerSTA entered for port %ws", pPCB->pwszFriendlyName);
  1708. do
  1709. {
  1710. pKeyDesc = (EAPOL_KEY_DESC *)pEapolPkt->PacketBody;
  1711. dwDynamicKeyLength = WireToHostFormat16 (pKeyDesc->KeyLength);
  1712. // TRACE2 (EAPOL, "ElKeyReceivePerSTA: KeyLength = %ld, \n KeyIndex = %0x",
  1713. // dwDynamicKeyLength,
  1714. // pKeyDesc->KeyIndex
  1715. // );
  1716. memcpy ((BYTE *)bReplayCheck,
  1717. (BYTE *)pKeyDesc->ReplayCounter,
  1718. 8*sizeof(BYTE));
  1719. ullReplayCheck = ((((ULONGLONG)(*((PBYTE)(bReplayCheck)+0))) << 56) +
  1720. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+1))) << 48) +
  1721. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+2))) << 40) +
  1722. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+3))) << 32) +
  1723. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+4))) << 24) +
  1724. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+5))) << 16) +
  1725. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+6))) << 8) +
  1726. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+7)))));
  1727. // Check validity of Key message using the ReplayCounter field
  1728. // Verify if it is in sync with the last ReplayCounter value
  1729. // received
  1730. // TRACE0 (EAPOL, "Original replay counter in desc ======");
  1731. // EAPOL_DUMPBA (pKeyDesc->ReplayCounter, 8);
  1732. // TRACE0 (EAPOL, "Converted incoming Replay counter ======= ");
  1733. // EAPOL_DUMPBA ((BYTE *)&ullReplayCheck, 8);
  1734. // TRACE0 (EAPOL, "Last Replay counter ======= ");
  1735. // EAPOL_DUMPBA ((BYTE *)&(pPCB->ullLastReplayCounter), 8);
  1736. if (ullReplayCheck <= pPCB->ullLastReplayCounter)
  1737. {
  1738. TRACE0 (EAPOL, "ElKeyReceivePerSTA: Replay counter is not in sync, something is wrong");
  1739. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_INVALID_EAPOL_KEY);
  1740. break;
  1741. }
  1742. // If valid ReplayCounter, save it in the PCB for future check
  1743. pPCB->ullLastReplayCounter = ullReplayCheck;
  1744. // Verify if the MD5 hash generated on the EAPOL packet,
  1745. // with Signature nulled out, is the same as the signature
  1746. // Use the MPPERecv key as the secret
  1747. dwEapPktLen = WireToHostFormat16 (pEapolPkt->PacketBodyLength);
  1748. dwMD5EapolPktLen = sizeof (EAPOL_PACKET) - sizeof(pEapolPkt->EthernetType) - 1 + dwEapPktLen;
  1749. if ((pbMD5EapolPkt = (BYTE *) MALLOC (dwMD5EapolPktLen)) == NULL)
  1750. {
  1751. TRACE0 (EAPOL, "ElKeyReceivePerSTA: Error in MALLOC for pbMD5EapolPkt");
  1752. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  1753. break;
  1754. }
  1755. memcpy ((BYTE *)pbMD5EapolPkt, (BYTE *)pEapolPkt+sizeof(pEapolPkt->EthernetType), dwMD5EapolPktLen);
  1756. // Query Master Secrets
  1757. if (dwRetCode = ElQueryMasterKeys (
  1758. pPCB,
  1759. &OldSessionKeys
  1760. ) != NO_ERROR)
  1761. {
  1762. TRACE1 (EAPOL, "ElKeyReceivePerSTA: ElQueryMasterKeys failed with error %ld",
  1763. dwRetCode);
  1764. break;
  1765. }
  1766. pbMasterSecretSend = OldSessionKeys.bSendKey;
  1767. pbMasterSecretRecv = OldSessionKeys.bReceiveKey;
  1768. dwMasterSecretSendLength = OldSessionKeys.dwKeyLength;
  1769. dwMasterSecretRecvLength = OldSessionKeys.dwKeyLength;
  1770. // Null out the signature in the key descriptor copy, to calculate
  1771. // the hash on the supplicant side
  1772. ZeroMemory ((BYTE *)(pbMD5EapolPkt
  1773. - sizeof(pEapolPkt->EthernetType) +
  1774. sizeof(EAPOL_PACKET) - 1 + // pEapolPkt->Body
  1775. sizeof(EAPOL_KEY_DESC)- // End of EAPOL_KEY_DESC
  1776. MD5DIGESTLEN-1), // Signature field
  1777. MD5DIGESTLEN);
  1778. (VOID) ElGetHMACMD5Digest (
  1779. pbMD5EapolPkt,
  1780. dwMD5EapolPktLen,
  1781. pbMasterSecretRecv,
  1782. dwMasterSecretRecvLength,
  1783. bHMACMD5HashBuffer
  1784. );
  1785. // TRACE0 (EAPOL, "ElKeyReceivePerSTA: MD5 Hash body ==");
  1786. // EAPOL_DUMPBA (pbMD5EapolPkt, dwMD5EapolPktLen);
  1787. // TRACE0 (EAPOL, "ElKeyReceivePerSTA: MD5 Hash secret ==");
  1788. // EAPOL_DUMPBA (pbMasterSecretRecv, dwMasterSecretRecvLength);
  1789. // TRACE0 (EAPOL, "ElKeyReceivePerSTA: MD5 Hash generated by Supplicant");
  1790. // EAPOL_DUMPBA (bHMACMD5HashBuffer, MD5DIGESTLEN);
  1791. // TRACE0 (EAPOL, "ElKeyReceivePerSTA: Signature sent in EAPOL_KEY_DESC");
  1792. // EAPOL_DUMPBA (pKeyDesc->KeySignature, MD5DIGESTLEN);
  1793. // Check if HMAC-MD5 hash in received packet is what is expected
  1794. if (memcmp (bHMACMD5HashBuffer, pKeyDesc->KeySignature, MD5DIGESTLEN) != 0)
  1795. {
  1796. TRACE0 (EAPOL, "ElKeyReceivePerSTA: Signature in Key Descriptor does not match");
  1797. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_INVALID_EAPOL_KEY);
  1798. break;
  1799. }
  1800. if (pKeyDesc->KeyIndex & 0x80)
  1801. {
  1802. fIsUnicastKey = TRUE;
  1803. }
  1804. // Decrypt the random value if it has been provided
  1805. if (WireToHostFormat16 (pEapolPkt->PacketBodyLength) > sizeof (EAPOL_KEY_DESC))
  1806. {
  1807. DWORD dwKeyMaterialLength = 0;
  1808. dwKeyMaterialLength = WireToHostFormat16 (pEapolPkt->PacketBodyLength) - FIELD_OFFSET(EAPOL_KEY_DESC, Key);
  1809. // TRACE1 (EAPOL, "ElKeyReceivePerSTA: KeyMaterialLength = %ld",
  1810. // dwKeyMaterialLength);
  1811. memcpy ((BYTE *)bKeyBuffer, (BYTE *)pKeyDesc->Key_IV, KEY_IV_LENGTH);
  1812. memcpy ((BYTE *)&bKeyBuffer[KEY_IV_LENGTH], (BYTE *)pbMasterSecretSend,
  1813. dwMasterSecretSendLength);
  1814. pEapolKeyMaterial = (PEAPOL_KEY_MATERIAL)pKeyDesc->Key;
  1815. dwRandomLength = WireToHostFormat16 (pEapolKeyMaterial->KeyMaterialLength);
  1816. if ((pbPaddedKeyMaterial = (PBYTE)MALLOC (RC4_PAD_LENGTH + dwKeyMaterialLength)) == NULL)
  1817. {
  1818. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  1819. break;
  1820. }
  1821. memcpy (pbPaddedKeyMaterial+RC4_PAD_LENGTH, pEapolKeyMaterial->KeyMaterial, dwKeyMaterialLength);
  1822. rc4_key (&rc4key, KEY_IV_LENGTH+dwMasterSecretSendLength, bKeyBuffer);
  1823. rc4 (&rc4key, dwKeyMaterialLength+RC4_PAD_LENGTH, pbPaddedKeyMaterial);
  1824. // Ignore leading padded RC4_PAD_LENGTH bytes
  1825. memcpy (pEapolKeyMaterial->KeyMaterial, pbPaddedKeyMaterial+RC4_PAD_LENGTH, dwKeyMaterialLength);
  1826. // TRACE1 (EAPOL, "ElKeyReceivePerSTA: Randomlength = %ld",
  1827. // dwRandomLength);
  1828. // TRACE0 (EAPOL, "ElKeyReceivePerSTA: ========= The random material is ============= ");
  1829. // EAPOL_DUMPBA (pEapolKeyMaterial->KeyMaterial, dwRandomLength);
  1830. }
  1831. else
  1832. {
  1833. // No random material sent
  1834. TRACE0 (EAPOL, "ElKeyReceivePerSTA: Did not find random material: Exiting");
  1835. dwRetCode = ERROR_INVALID_PARAMETER;
  1836. break;
  1837. }
  1838. if (fIsUnicastKey)
  1839. {
  1840. TRACE0 (EAPOL, "ElKeyReceivePerSTA: Received Per-STA Unicast key material Random");
  1841. // Generate dynamic keys
  1842. if (dwRetCode = GenerateDynamicKeys (
  1843. pbMasterSecretSend,
  1844. dwMasterSecretSendLength,
  1845. pEapolKeyMaterial->KeyMaterial,
  1846. dwRandomLength,
  1847. dwDynamicKeyLength,
  1848. &NewSessionKeys
  1849. ) != NO_ERROR)
  1850. {
  1851. TRACE1 (EAPOL, "ElKeyReceivePerSTA: ElGenerateDynamicKeys failed with error %ld",
  1852. dwRetCode);
  1853. break;
  1854. }
  1855. pbDynamicSendKey = NewSessionKeys.bSendKey;
  1856. pbDynamicRecvKey = NewSessionKeys.bReceiveKey;
  1857. // TRACE0 (EAPOL, "ElKeyReceivePerSTA: Derived Send Key");
  1858. // EAPOL_DUMPBA (pbDynamicSendKey, dwDynamicKeyLength);
  1859. // TRACE0 (EAPOL, "ElKeyReceivePerSTA: Derived Recv Key");
  1860. // EAPOL_DUMPBA (pbDynamicRecvKey, dwDynamicKeyLength);
  1861. // Update Master Secrets
  1862. if (dwRetCode = ElSetMasterKeys (
  1863. pPCB,
  1864. &NewSessionKeys
  1865. ) != NO_ERROR)
  1866. {
  1867. // Cannot do much about this error than proceed
  1868. TRACE1 (EAPOL, "ElKeyReceivePerSTA: ElSetMasterKeys failed with error %ld",
  1869. dwRetCode);
  1870. dwRetCode = NO_ERROR;
  1871. }
  1872. pbKeyToBePlumbed = pbDynamicSendKey;
  1873. }
  1874. else
  1875. {
  1876. TRACE0 (EAPOL, "ElKeyReceivePerSTA: Received Per-STA BROADCAST key material");
  1877. if (dwRandomLength != dwDynamicKeyLength)
  1878. {
  1879. TRACE2 (EAPOL, "ElKeyReceivePerSTA: KeyLength (%ld) != KeyMaterialLength (%ld), Inconsistent. Will consider only KeyMaterial length !",
  1880. dwDynamicKeyLength, dwRandomLength);
  1881. }
  1882. dwDynamicKeyLength = dwRandomLength;
  1883. pbKeyToBePlumbed = pEapolKeyMaterial->KeyMaterial;
  1884. }
  1885. if ((pNdisWEPKey = MALLOC ( sizeof(NDIS_802_11_WEP)-1+dwDynamicKeyLength ))
  1886. == NULL)
  1887. {
  1888. TRACE0 (EAPOL, "ElKeyReceivePerSTA: MALLOC failed for pNdisWEPKey");
  1889. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  1890. break;
  1891. }
  1892. pNdisWEPKey->Length = sizeof(NDIS_802_11_WEP) - 1 + dwDynamicKeyLength;
  1893. memcpy ((BYTE *)pNdisWEPKey->KeyMaterial, (BYTE *)pbKeyToBePlumbed,
  1894. dwDynamicKeyLength);
  1895. pNdisWEPKey->KeyLength = dwDynamicKeyLength;
  1896. // Create the long index out of the byte index got from AP
  1897. // If MSB in byte is set, set MSB in ulong format
  1898. if (pKeyDesc->KeyIndex & 0x80)
  1899. {
  1900. pNdisWEPKey->KeyIndex = 0x80000000;
  1901. }
  1902. else
  1903. {
  1904. pNdisWEPKey->KeyIndex = 0x00000000;
  1905. }
  1906. pNdisWEPKey->KeyIndex |= (pKeyDesc->KeyIndex & 0x03);
  1907. // Use NDISUIO to plumb the key to the driver
  1908. if ((dwRetCode = ElNdisuioSetOIDValue (
  1909. pPCB->hPort,
  1910. OID_802_11_ADD_WEP,
  1911. (BYTE *)pNdisWEPKey,
  1912. pNdisWEPKey->Length)) != NO_ERROR)
  1913. {
  1914. TRACE1 (PORT, "ElKeyReceivePerSTA: ElNdisuioSetOIDValue failed with error %ld",
  1915. dwRetCode);
  1916. }
  1917. }
  1918. while (FALSE);
  1919. if (dwRetCode != NO_ERROR)
  1920. {
  1921. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB,
  1922. EAPOL_ERROR_PROCESSING_EAPOL_KEY, dwRetCode);
  1923. }
  1924. if (pbMD5EapolPkt != NULL)
  1925. {
  1926. FREE (pbMD5EapolPkt);
  1927. pbMD5EapolPkt = NULL;
  1928. }
  1929. if (pNdisWEPKey != NULL)
  1930. {
  1931. FREE (pNdisWEPKey);
  1932. pNdisWEPKey = NULL;
  1933. }
  1934. if (pbPaddedKeyMaterial != NULL)
  1935. {
  1936. FREE (pbPaddedKeyMaterial);
  1937. }
  1938. TRACE1 (EAPOL, "ElKeyReceivePerSTA completed for port %ws", pPCB->pwszFriendlyName);
  1939. return dwRetCode;
  1940. }
  1941. #endif
  1942. //
  1943. // ElTimeoutCallbackRoutine
  1944. //
  1945. // Description:
  1946. //
  1947. // Function called when any timer work item queued on the global timer
  1948. // queue expires. Depending on the state in which the port is when the timer
  1949. // expires, the port moves to the next state.
  1950. //
  1951. // Arguments:
  1952. // pvContext - Pointer to context. In this case, it is pointer to a PCB
  1953. // fTimerOfWaitFired - Unused
  1954. //
  1955. // Return values:
  1956. //
  1957. VOID
  1958. ElTimeoutCallbackRoutine (
  1959. IN PVOID pvContext,
  1960. IN BOOLEAN fTimerOfWaitFired
  1961. )
  1962. {
  1963. EAPOL_PCB *pPCB;
  1964. TRACE0 (EAPOL, "ElTimeoutCallbackRoutine entered");
  1965. do
  1966. {
  1967. // Context should not be NULL
  1968. if (pvContext == NULL)
  1969. {
  1970. TRACE0 (EAPOL, "ElTimeoutCallbackRoutine: pvContext is NULL. Invalid timeout callback");
  1971. break;
  1972. }
  1973. // PCB is guaranteed to exist until all timers are fired
  1974. // Verify if Port is still active
  1975. pPCB = (EAPOL_PCB *)pvContext;
  1976. ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
  1977. if (!EAPOL_PORT_ACTIVE(pPCB))
  1978. {
  1979. // Port is not active
  1980. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  1981. TRACE1 (PORT, "ElTimeoutCallbackRoutine: Port %ws is inactive",
  1982. pPCB->pwszDeviceGUID);
  1983. break;
  1984. }
  1985. DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_STATE_TIMEOUT,
  1986. EAPOLStates[((pPCB->State < EAPOLSTATE_LOGOFF) || (pPCB->State > EAPOLSTATE_AUTHENTICATED))?EAPOLSTATE_UNDEFINED:pPCB->State]);
  1987. // Check the current state of the state machine
  1988. // We can do additional checks such as flagging which timer was fired
  1989. // and in the timeout checking if the PCB state has remained the same
  1990. // Else bail out
  1991. switch (pPCB->State)
  1992. {
  1993. case EAPOLSTATE_CONNECTING:
  1994. if (!EAPOL_START_TIMER_SET(pPCB))
  1995. {
  1996. TRACE1 (EAPOL, "ElTimeoutCallbackRoutine: Wrong timeout %ld in Connecting state", CHECK_EAPOL_TIMER(pPCB));
  1997. break;
  1998. }
  1999. pPCB->dwTimerFlags &= ~EAPOL_START_TIMER;
  2000. FSMConnecting(pPCB, NULL);
  2001. break;
  2002. case EAPOLSTATE_ACQUIRED:
  2003. if (!EAPOL_AUTH_TIMER_SET(pPCB))
  2004. {
  2005. TRACE1 (EAPOL, "ElTimeoutCallbackRoutine: Wrong timeout %ld in Acquired state", CHECK_EAPOL_TIMER(pPCB));
  2006. break;
  2007. }
  2008. pPCB->dwTimerFlags &= ~EAPOL_AUTH_TIMER;
  2009. FSMConnecting(pPCB, NULL);
  2010. break;
  2011. case EAPOLSTATE_AUTHENTICATING:
  2012. if (!EAPOL_AUTH_TIMER_SET(pPCB))
  2013. {
  2014. TRACE1 (EAPOL, "ElTimeoutCallbackRoutine: Wrong timeout %ld in Authenticating state", CHECK_EAPOL_TIMER(pPCB));
  2015. break;
  2016. }
  2017. pPCB->dwTimerFlags &= ~EAPOL_AUTH_TIMER;
  2018. FSMConnecting(pPCB, NULL);
  2019. break;
  2020. case EAPOLSTATE_AUTHENTICATED:
  2021. if (!EAPOL_TRANSMIT_KEY_TIMER_SET(pPCB))
  2022. {
  2023. TRACE1 (EAPOL, "ElTimeoutCallbackRoutine: Wrong timeout %ld in Authenticated state", CHECK_EAPOL_TIMER(pPCB));
  2024. break;
  2025. }
  2026. pPCB->dwTimerFlags &= ~EAPOL_TRANSMIT_KEY_TIMER;
  2027. ElVerifyEAPOLKeyReceived(pPCB);
  2028. break;
  2029. case EAPOLSTATE_HELD:
  2030. if (!EAPOL_HELD_TIMER_SET(pPCB))
  2031. {
  2032. TRACE1 (EAPOL, "ElTimeoutCallbackRoutine: Wrong timeout %ld in Held state", CHECK_EAPOL_TIMER(pPCB));
  2033. break;
  2034. }
  2035. // Go through logoff, since new user will be tried
  2036. // for next cycle
  2037. // Debatable !
  2038. if (!(pPCB->dwAuthFailCount % EAPOL_MAX_AUTH_FAIL_COUNT))
  2039. {
  2040. // FSMLogoff (pPCB, NULL);
  2041. }
  2042. FSMConnecting(pPCB, NULL);
  2043. break;
  2044. case EAPOLSTATE_DISCONNECTED:
  2045. TRACE0 (EAPOL, "ElTimeoutCallbackRoutine: No action in Disconnected state");
  2046. break;
  2047. case EAPOLSTATE_LOGOFF:
  2048. TRACE0 (EAPOL, "ElTimeoutCallbackRoutine: No action in Logoff state");
  2049. break;
  2050. default:
  2051. TRACE0 (EAPOL, "ElTimeoutCallbackRoutine: Critical Error. Invalid state after timer expires ");
  2052. break;
  2053. }
  2054. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  2055. } while (FALSE);
  2056. TRACE0 (EAPOL, "ElTimeoutCallbackRoutine completed");
  2057. return;
  2058. }
  2059. //
  2060. // ElEapWork
  2061. //
  2062. // Description:
  2063. //
  2064. // Function called when an EAPOL packet of type EAP_Packet is received
  2065. // The EAP packet is passed to the EAP module for processing.
  2066. // Depending on the result of the processing, a EAP Response packet
  2067. // is sent or the incoming packet is ignored.
  2068. //
  2069. // Input arguments:
  2070. // pPCB - Pointer to PCB for the port on which data is being processed
  2071. // pRecvPkt - Pointer to EAP packet in the data received from the remote end
  2072. //
  2073. // Return values:
  2074. // NO_ERROR - success
  2075. // non-zero - error
  2076. //
  2077. //
  2078. // ISSUE: Rewrite with do {} while(FALSE)
  2079. //
  2080. DWORD
  2081. ElEapWork (
  2082. IN EAPOL_PCB *pPCB,
  2083. IN PPP_EAP_PACKET *pRecvPkt
  2084. )
  2085. {
  2086. DWORD dwLength = 0;
  2087. ELEAP_RESULT EapResult;
  2088. PPP_EAP_PACKET *pSendPkt;
  2089. EAPOL_PACKET *pEapolPkt;
  2090. GUID DeviceGuid;
  2091. DWORD dwReceivedId = 0;
  2092. DWORD cbData = 0;
  2093. BYTE *pbAuthData = NULL;
  2094. DWORD dwRetCode = NO_ERROR;
  2095. //
  2096. // If the protocol has not been started yet, call ElEapBegin
  2097. //
  2098. if (!(pPCB->fEapInitialized))
  2099. {
  2100. if ((dwRetCode = ElEapBegin (pPCB)) != NO_ERROR)
  2101. {
  2102. TRACE1 (EAPOL, "ElEapWork: Error in ElEapBegin = %ld", dwRetCode);
  2103. return dwRetCode;
  2104. }
  2105. }
  2106. ZeroMemory(&EapResult, sizeof(EapResult));
  2107. // Create buffer for EAPOL + EAP and pass pointer to EAP header
  2108. pEapolPkt = (EAPOL_PACKET *) MALLOC (MAX_EAPOL_BUFFER_SIZE);
  2109. TRACE1 (EAPOL, "ElEapWork: EapolPkt created at %p", pEapolPkt);
  2110. if (pEapolPkt == NULL)
  2111. {
  2112. TRACE0 (EAPOL, "ElEapWork: Error allocating EAP buffer");
  2113. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  2114. return dwRetCode;
  2115. }
  2116. // Point to EAP header
  2117. pSendPkt = (PPP_EAP_PACKET *)((PBYTE)pEapolPkt + sizeof (EAPOL_PACKET) - 1);
  2118. if (pRecvPkt != NULL)
  2119. {
  2120. dwReceivedId = pRecvPkt->Id;
  2121. }
  2122. dwRetCode = ElEapMakeMessage (pPCB,
  2123. pRecvPkt,
  2124. pSendPkt,
  2125. MAX_EAPOL_BUFFER_SIZE
  2126. - sizeof(EAPOL_PACKET) - 1,
  2127. &EapResult
  2128. );
  2129. // Notification message for the user
  2130. if (NULL != EapResult.pszReplyMessage)
  2131. {
  2132. // Free earlier notication with the PCB
  2133. if (pPCB->pwszEapReplyMessage != NULL)
  2134. {
  2135. FREE (pPCB->pwszEapReplyMessage);
  2136. pPCB->pwszEapReplyMessage = NULL;
  2137. }
  2138. pPCB->pwszEapReplyMessage =
  2139. (WCHAR *)MALLOC ((strlen(EapResult.pszReplyMessage)+1) * sizeof(WCHAR));
  2140. if (pPCB->pwszEapReplyMessage == NULL)
  2141. {
  2142. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  2143. TRACE0 (EAPOL, "ElEapWork: MALLOC failed for pwszEapReplyMessage");
  2144. FREE (EapResult.pszReplyMessage);
  2145. FREE (pEapolPkt);
  2146. pEapolPkt = NULL;
  2147. return dwRetCode;
  2148. }
  2149. if (0 == MultiByteToWideChar (
  2150. CP_ACP,
  2151. 0,
  2152. EapResult.pszReplyMessage,
  2153. -1,
  2154. pPCB->pwszEapReplyMessage,
  2155. strlen(EapResult.pszReplyMessage)+1))
  2156. {
  2157. dwRetCode = GetLastError();
  2158. TRACE2 (EAPOL,"ElEapWork: MultiByteToWideChar(%s) failed for pwszEapReplyMessage with error (%ld)",
  2159. EapResult.pszReplyMessage,
  2160. dwRetCode);
  2161. FREE (EapResult.pszReplyMessage);
  2162. FREE (pEapolPkt);
  2163. pEapolPkt = NULL;
  2164. return dwRetCode;
  2165. }
  2166. ElNetmanNotify (pPCB, EAPOL_NCS_NOTIFICATION, NULL);
  2167. TRACE1 (EAPOL, "ElEapWork: Notified user of EAP data = %ws",
  2168. pPCB->pwszEapReplyMessage);
  2169. FREE (EapResult.pszReplyMessage);
  2170. }
  2171. if (dwRetCode != NO_ERROR)
  2172. {
  2173. switch (dwRetCode)
  2174. {
  2175. case ERROR_PPP_INVALID_PACKET:
  2176. TRACE0 (EAPOL, "ElEapWork: Silently discarding invalid auth packet");
  2177. break;
  2178. default:
  2179. TRACE1 (EAPOL, "ElEapWork: ElEapMakeMessage returned error %ld",
  2180. dwRetCode);
  2181. // NotifyCallerOfFailure (pPCB, dwRetCode);
  2182. break;
  2183. }
  2184. // Free up memory reserved for packet
  2185. FREE (pEapolPkt);
  2186. pEapolPkt = NULL;
  2187. return dwRetCode;
  2188. }
  2189. //
  2190. // Check to see if we have to save any user data
  2191. //
  2192. if (EapResult.fSaveUserData)
  2193. {
  2194. // Save to Registry
  2195. if ((dwRetCode = ElSetEapUserInfo (
  2196. pPCB->hUserToken,
  2197. pPCB->pwszDeviceGUID,
  2198. pPCB->dwEapTypeToBeUsed,
  2199. (pPCB->pSSID)?pPCB->pSSID->SsidLength:0,
  2200. (pPCB->pSSID)?pPCB->pSSID->Ssid:NULL,
  2201. EapResult.pUserData,
  2202. EapResult.dwSizeOfUserData)) != NO_ERROR)
  2203. {
  2204. TRACE1 (EAPOL, "ElEapWork: ElSetEapUserInfo failed with error = %d",
  2205. dwRetCode);
  2206. if (pEapolPkt != NULL)
  2207. {
  2208. FREE (pEapolPkt);
  2209. pEapolPkt = NULL;
  2210. }
  2211. return dwRetCode;
  2212. }
  2213. // Save to PCB context
  2214. if (pPCB->pCustomAuthUserData != NULL)
  2215. {
  2216. FREE (pPCB->pCustomAuthUserData);
  2217. pPCB->pCustomAuthUserData = NULL;
  2218. }
  2219. pPCB->pCustomAuthUserData = MALLOC (EapResult.dwSizeOfUserData + sizeof (DWORD));
  2220. if (pPCB->pCustomAuthUserData == NULL)
  2221. {
  2222. TRACE1 (EAPOL, "ElEapWork: Error in allocating memory for pCustomAuthUserData = %ld",
  2223. dwRetCode);
  2224. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  2225. return dwRetCode;
  2226. }
  2227. pPCB->pCustomAuthUserData->dwSizeOfCustomAuthData = EapResult.dwSizeOfUserData;
  2228. if ((EapResult.dwSizeOfUserData != 0) && (EapResult.pUserData != NULL))
  2229. {
  2230. memcpy ((BYTE *)pPCB->pCustomAuthUserData->pbCustomAuthData,
  2231. (BYTE *)EapResult.pUserData,
  2232. EapResult.dwSizeOfUserData);
  2233. }
  2234. TRACE0 (EAPOL, "ElEapWork: Saved EAP data for user");
  2235. }
  2236. //
  2237. // Check to see if we have to save any connection data
  2238. //
  2239. pbAuthData = EapResult.SetCustomAuthData.pConnectionData;
  2240. cbData = EapResult.SetCustomAuthData.dwSizeOfConnectionData;
  2241. if ((EapResult.fSaveConnectionData ) &&
  2242. ( 0 != cbData ) )
  2243. {
  2244. // Save to registry
  2245. if ((dwRetCode = ElSetCustomAuthData (
  2246. pPCB->pwszDeviceGUID,
  2247. pPCB->dwEapTypeToBeUsed,
  2248. (pPCB->pSSID)?pPCB->pSSID->SsidLength:0,
  2249. (pPCB->pSSID)?pPCB->pSSID->Ssid:NULL,
  2250. pbAuthData,
  2251. &cbData
  2252. )) != NO_ERROR)
  2253. {
  2254. TRACE1 ( EAPOL, "ElEapWork: ElSetCustomAuthData failed with error = %d",
  2255. dwRetCode);
  2256. FREE (pEapolPkt);
  2257. pEapolPkt = NULL;
  2258. return dwRetCode;
  2259. }
  2260. // Save to PCB context
  2261. if (pPCB->pCustomAuthConnData != NULL)
  2262. {
  2263. FREE (pPCB->pCustomAuthConnData);
  2264. pPCB->pCustomAuthConnData = NULL;
  2265. }
  2266. pPCB->pCustomAuthConnData = MALLOC (cbData + sizeof (DWORD));
  2267. if (pPCB->pCustomAuthConnData == NULL)
  2268. {
  2269. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  2270. TRACE1 (EAPOL, "ElEapWork: Error in allocating memory for pCustomAuthConnData = %ld",
  2271. dwRetCode);
  2272. return dwRetCode;
  2273. }
  2274. pPCB->pCustomAuthConnData->dwSizeOfCustomAuthData = cbData;
  2275. if ((cbData != 0) && (pbAuthData != NULL))
  2276. {
  2277. memcpy ((BYTE *)pPCB->pCustomAuthConnData->pbCustomAuthData,
  2278. (BYTE *)pbAuthData,
  2279. cbData);
  2280. }
  2281. TRACE0 (EAPOL, "ElEapWork: Saved EAP data for connection");
  2282. }
  2283. switch( EapResult.Action )
  2284. {
  2285. case ELEAP_Send:
  2286. case ELEAP_SendAndDone:
  2287. // Send out EAPOL packet
  2288. memcpy ((BYTE *)pEapolPkt->EthernetType,
  2289. (BYTE *)pPCB->bEtherType,
  2290. SIZE_ETHERNET_TYPE);
  2291. pEapolPkt->ProtocolVersion = pPCB->bProtocolVersion;
  2292. pEapolPkt->PacketType = EAP_Packet;
  2293. // The EAP packet length is in the packet returned back by
  2294. // the Dll MakeMessage
  2295. // In case of Notification and Identity Response, it is in
  2296. // EapResult.wSizeOfEapPkt
  2297. if (EapResult.wSizeOfEapPkt == 0)
  2298. {
  2299. EapResult.wSizeOfEapPkt =
  2300. WireToHostFormat16 (pSendPkt->Length);
  2301. }
  2302. HostToWireFormat16 ((WORD) EapResult.wSizeOfEapPkt,
  2303. (BYTE *)pEapolPkt->PacketBodyLength);
  2304. // Make a copy of the EAPOL packet in the PCB
  2305. // Will be used during retransmission
  2306. if (pPCB->pbPreviousEAPOLPkt != NULL)
  2307. {
  2308. FREE (pPCB->pbPreviousEAPOLPkt);
  2309. pPCB->pbPreviousEAPOLPkt = NULL;
  2310. }
  2311. pPCB->pbPreviousEAPOLPkt =
  2312. MALLOC (sizeof (EAPOL_PACKET)+EapResult.wSizeOfEapPkt-1);
  2313. if (pPCB->pbPreviousEAPOLPkt == NULL)
  2314. {
  2315. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  2316. TRACE0 (EAPOL, "ElEapWork: MALLOC failed for pbPreviousEAPOLPkt");
  2317. if (pEapolPkt != NULL)
  2318. {
  2319. FREE (pEapolPkt);
  2320. pEapolPkt = NULL;
  2321. }
  2322. return dwRetCode;
  2323. }
  2324. memcpy (pPCB->pbPreviousEAPOLPkt, pEapolPkt,
  2325. sizeof (EAPOL_PACKET)+EapResult.wSizeOfEapPkt-1);
  2326. pPCB->dwSizeOfPreviousEAPOLPkt =
  2327. sizeof (EAPOL_PACKET)+EapResult.wSizeOfEapPkt-1;
  2328. pPCB->dwPreviousId = dwReceivedId;
  2329. // Send packet out on the port
  2330. dwRetCode = ElWriteToPort (pPCB,
  2331. (CHAR *)pEapolPkt,
  2332. sizeof (EAPOL_PACKET)+EapResult.wSizeOfEapPkt-1);
  2333. if (dwRetCode != NO_ERROR)
  2334. {
  2335. TRACE1 (EAPOL, "ElEapWork: Error in writing EAP_Packet to port %ld",
  2336. dwRetCode);
  2337. if (pEapolPkt != NULL)
  2338. {
  2339. FREE (pEapolPkt);
  2340. pEapolPkt = NULL;
  2341. }
  2342. return dwRetCode;
  2343. }
  2344. if (pEapolPkt != NULL)
  2345. {
  2346. FREE (pEapolPkt);
  2347. pEapolPkt = NULL;
  2348. }
  2349. // More processing to be done?
  2350. // Supplicant side should not ever receive ELEAP_SendAndDone
  2351. // result code
  2352. if (EapResult.Action != ELEAP_SendAndDone)
  2353. {
  2354. break;
  2355. }
  2356. else
  2357. {
  2358. TRACE0 (EAPOL, "ElEapWork: ELEAP_SendAndDone wrong result received");
  2359. }
  2360. case ELEAP_Done:
  2361. // Retrieve MPPE keys from the attributes information
  2362. // returned by EAP-TLS
  2363. switch (EapResult.dwError)
  2364. {
  2365. case NO_ERROR:
  2366. TRACE0 (EAPOL, "ElEapWork: Authentication was successful");
  2367. pPCB->fLocalEAPAuthSuccess = TRUE;
  2368. //
  2369. // If authentication was successful
  2370. //
  2371. dwRetCode = ElExtractMPPESendRecvKeys (
  2372. pPCB,
  2373. EapResult.pUserAttributes,
  2374. (BYTE*)&(EapResult.abChallenge),
  2375. (BYTE*)&(EapResult.abResponse));
  2376. if (dwRetCode != NO_ERROR)
  2377. {
  2378. FREE (pEapolPkt);
  2379. //NotifyCallerOfFailure (pPcb, dwRetCode);
  2380. return dwRetCode;
  2381. }
  2382. // ISSUE:
  2383. // Do we want to retain UserAttributes
  2384. // pPCB->pAuthProtocolAttributes = EapResult.pUserAttributes;
  2385. break;
  2386. default:
  2387. if (pEapolPkt != NULL)
  2388. {
  2389. FREE (pEapolPkt);
  2390. pEapolPkt = NULL;
  2391. }
  2392. TRACE0 (EAPOL, "ElEapWork: Authentication FAILED");
  2393. pPCB->dwLocalEAPAuthResult = EapResult.dwError;
  2394. break;
  2395. }
  2396. // Free memory allocated for the packet, since no response
  2397. // is going to be sent out
  2398. if (pEapolPkt != NULL)
  2399. {
  2400. FREE (pEapolPkt);
  2401. pEapolPkt = NULL;
  2402. }
  2403. break;
  2404. case ELEAP_NoAction:
  2405. // Free memory allocated for the packet, since nothing
  2406. // is being done with it
  2407. if (pEapolPkt != NULL)
  2408. {
  2409. FREE (pEapolPkt);
  2410. pEapolPkt = NULL;
  2411. }
  2412. break;
  2413. default:
  2414. break;
  2415. }
  2416. if (pEapolPkt != NULL)
  2417. {
  2418. FREE (pEapolPkt);
  2419. pEapolPkt = NULL;
  2420. }
  2421. //
  2422. // Check to see if we have to bring up the InteractiveUI for EAP
  2423. // i.e. Server cert confirmation etc.
  2424. //
  2425. if (EapResult.fInvokeEapUI)
  2426. {
  2427. ElInvokeInteractiveUI (pPCB, &(EapResult.InvokeEapUIData));
  2428. }
  2429. return dwRetCode;
  2430. }
  2431. //
  2432. //
  2433. // ElExtractMPPESendRecvKeys
  2434. //
  2435. // Description:
  2436. // Function called if authentication was successful. The MPPE Send &
  2437. // Recv keys are extracted from the RAS_AUTH_ATTRIBUTE passed from
  2438. // the EAP DLL and stored in the PCB. The keys are used to decrypt
  2439. // the multicast WEP key and also are used for media-based encrypting.
  2440. //
  2441. // Return values
  2442. //
  2443. // NO_ERROR - Success
  2444. // Non-zero - Failure
  2445. //
  2446. DWORD
  2447. ElExtractMPPESendRecvKeys (
  2448. IN EAPOL_PCB *pPCB,
  2449. IN RAS_AUTH_ATTRIBUTE * pUserAttributes,
  2450. IN BYTE * pChallenge,
  2451. IN BYTE * pResponse
  2452. )
  2453. {
  2454. RAS_AUTH_ATTRIBUTE * pAttribute;
  2455. RAS_AUTH_ATTRIBUTE * pAttributeSendKey;
  2456. RAS_AUTH_ATTRIBUTE * pAttributeRecvKey;
  2457. DWORD dwRetCode = NO_ERROR;
  2458. DWORD dwEncryptionPolicy = 0;
  2459. DWORD dwEncryptionTypes = 0;
  2460. do
  2461. {
  2462. pAttribute = ElAuthAttributeGetVendorSpecific (
  2463. 311, 12, pUserAttributes);
  2464. pAttributeSendKey = ElAuthAttributeGetVendorSpecific ( 311, 16,
  2465. pUserAttributes);
  2466. pAttributeRecvKey = ElAuthAttributeGetVendorSpecific ( 311, 17,
  2467. pUserAttributes);
  2468. if ((pAttributeSendKey != NULL)
  2469. && (pAttributeRecvKey != NULL))
  2470. {
  2471. // Set the MS-MPPE-Send-Key and MS-MPPE-Recv-Key with
  2472. // the ethernet driver
  2473. ULONG ulSendKeyLength = 0;
  2474. ULONG ulRecvKeyLength = 0;
  2475. // Based on PPP code
  2476. ulSendKeyLength = *(((BYTE*)(pAttributeSendKey->Value))+8);
  2477. ulRecvKeyLength = *(((BYTE*)(pAttributeRecvKey->Value))+8);
  2478. // TRACE0 (EAPOL, "Send key = ");
  2479. // EAPOL_DUMPBA (((BYTE*)(pAttributeSendKey->Value))+9,
  2480. // ulSendKeyLength);
  2481. // TRACE0 (EAPOL, "Recv key = ");
  2482. // EAPOL_DUMPBA (((BYTE*)(pAttributeRecvKey->Value))+9,
  2483. // ulRecvKeyLength);
  2484. //
  2485. // Copy MPPE Send and Receive Keys into the PCB for later usage
  2486. // These keys will be used to decrypt keys sent by NAS (if any).
  2487. // Save the keys as the MasterSecret for dynamic rekeying (if any).
  2488. //
  2489. if (ulSendKeyLength != 0)
  2490. {
  2491. if (pPCB->MasterSecretSend.cbData != 0)
  2492. {
  2493. FREE (pPCB->MasterSecretSend.pbData);
  2494. pPCB->MasterSecretSend.cbData = 0;
  2495. pPCB->MasterSecretSend.pbData = NULL;
  2496. }
  2497. if ((dwRetCode = ElSecureEncodePw (
  2498. ((BYTE*)(pAttributeSendKey->Value))+9,
  2499. ulSendKeyLength,
  2500. &(pPCB->MasterSecretSend)
  2501. )) != NO_ERROR)
  2502. {
  2503. TRACE1 (EAPOL, "ElExtractMPPESendRecvKeys: ElSecureEncodePw for Master Send failed with error %ld",
  2504. dwRetCode);
  2505. break;
  2506. }
  2507. if (pPCB->MPPESendKey.cbData != 0)
  2508. {
  2509. FREE (pPCB->MPPESendKey.pbData);
  2510. pPCB->MPPESendKey.cbData = 0;
  2511. pPCB->MPPESendKey.pbData = NULL;
  2512. }
  2513. if ((dwRetCode = ElSecureEncodePw (
  2514. ((BYTE*)(pAttributeSendKey->Value))+9,
  2515. ulSendKeyLength,
  2516. &(pPCB->MPPESendKey)
  2517. )) != NO_ERROR)
  2518. {
  2519. TRACE1 (EAPOL, "ElExtractMPPESendRecvKeys: ElSecureEncodePw for MPPESend failed with error %ld",
  2520. dwRetCode);
  2521. break;
  2522. }
  2523. }
  2524. if (ulRecvKeyLength != 0)
  2525. {
  2526. if (pPCB->MasterSecretRecv.cbData != 0)
  2527. {
  2528. FREE (pPCB->MasterSecretRecv.pbData);
  2529. pPCB->MasterSecretRecv.cbData = 0;
  2530. pPCB->MasterSecretRecv.pbData = NULL;
  2531. }
  2532. if ((dwRetCode = ElSecureEncodePw (
  2533. ((BYTE*)(pAttributeRecvKey->Value))+9,
  2534. ulRecvKeyLength,
  2535. &(pPCB->MasterSecretRecv)
  2536. )) != NO_ERROR)
  2537. {
  2538. TRACE1 (EAPOL, "ElExtractMPPESendRecvKeys: ElSecureEncodePw for Master Recv failed with error %ld",
  2539. dwRetCode);
  2540. break;
  2541. }
  2542. if (pPCB->MPPERecvKey.cbData != 0)
  2543. {
  2544. FREE (pPCB->MPPERecvKey.pbData);
  2545. pPCB->MPPERecvKey.cbData = 0;
  2546. pPCB->MPPERecvKey.pbData = NULL;
  2547. }
  2548. if ((dwRetCode = ElSecureEncodePw (
  2549. ((BYTE*)(pAttributeRecvKey->Value))+9,
  2550. ulRecvKeyLength,
  2551. &(pPCB->MPPERecvKey)
  2552. )) != NO_ERROR)
  2553. {
  2554. TRACE1 (EAPOL, "ElExtractMPPESendRecvKeys: ElSecureEncodePw for MPPERecv failed with error %ld",
  2555. dwRetCode);
  2556. break;
  2557. }
  2558. }
  2559. TRACE0 (EAPOL,"MPPE-Send/Recv-Keys derived by supplicant");
  2560. }
  2561. else
  2562. {
  2563. TRACE0 (EAPOL, "ElExtractMPPESendRecvKeys: pAttributeSendKey or pAttributeRecvKey == NULL");
  2564. }
  2565. } while (FALSE);
  2566. if (dwRetCode != NO_ERROR)
  2567. {
  2568. if (pPCB->MasterSecretSend.cbData != 0)
  2569. {
  2570. FREE (pPCB->MasterSecretSend.pbData);
  2571. pPCB->MasterSecretSend.cbData = 0;
  2572. pPCB->MasterSecretSend.pbData = NULL;
  2573. }
  2574. if (pPCB->MasterSecretRecv.cbData != 0)
  2575. {
  2576. FREE (pPCB->MasterSecretRecv.pbData);
  2577. pPCB->MasterSecretRecv.cbData = 0;
  2578. pPCB->MasterSecretRecv.pbData = NULL;
  2579. }
  2580. if (pPCB->MPPESendKey.cbData != 0)
  2581. {
  2582. FREE (pPCB->MPPESendKey.pbData);
  2583. pPCB->MPPESendKey.cbData = 0;
  2584. pPCB->MPPESendKey.pbData = NULL;
  2585. }
  2586. if (pPCB->MPPERecvKey.cbData != 0)
  2587. {
  2588. FREE (pPCB->MPPERecvKey.pbData);
  2589. pPCB->MPPERecvKey.cbData = 0;
  2590. pPCB->MPPERecvKey.pbData = NULL;
  2591. }
  2592. }
  2593. return( dwRetCode );
  2594. }
  2595. //
  2596. // ElProcessEapSuccess
  2597. //
  2598. // Description:
  2599. //
  2600. // Function called when an EAP_Success is received in any state
  2601. //
  2602. // Input arguments:
  2603. // pPCB - Pointer to PCB for the port on which data is being processed
  2604. // pEapolPkt - Pointer to EAPOL packet that was received
  2605. //
  2606. // Return values:
  2607. // NO_ERROR - success
  2608. // non-zero - error
  2609. //
  2610. DWORD
  2611. ElProcessEapSuccess (
  2612. IN EAPOL_PCB *pPCB,
  2613. IN EAPOL_PACKET *pEapolPkt
  2614. )
  2615. {
  2616. EAPOL_ZC_INTF ZCData;
  2617. DWORD dwRetCode = NO_ERROR;
  2618. TRACE0 (EAPOL, "ElProcessEapSuccess: Got EAPCODE_Success");
  2619. do
  2620. {
  2621. // Indicate to EAP=Dll to cleanup completed session
  2622. if ((dwRetCode = ElEapEnd (pPCB)) != NO_ERROR)
  2623. {
  2624. TRACE1 (EAPOL, "ProcessReceivedPacket: EapSuccess: Error in ElEapEnd = %ld",
  2625. dwRetCode);
  2626. break;
  2627. }
  2628. TRACE0 (EAPOL, "ElProcessEapSuccess: Authentication successful");
  2629. // Complete remaining processing i.e. DHCP
  2630. if ((dwRetCode = FSMAuthenticated (pPCB,
  2631. pEapolPkt)) != NO_ERROR)
  2632. {
  2633. break;
  2634. }
  2635. #ifdef ZEROCONFIG_LINKED
  2636. // Indicate to WZC that authentication succeeded and
  2637. // reset the blob it stores for the current SSID
  2638. ZeroMemory ((PVOID)&ZCData, sizeof(EAPOL_ZC_INTF));
  2639. ZCData.dwAuthFailCount = 0;
  2640. ZCData.PreviousAuthenticationType = EAPOL_UNAUTHENTICATED_ACCESS;
  2641. if (pPCB->pSSID != NULL)
  2642. {
  2643. memcpy (ZCData.bSSID, pPCB->pSSID->Ssid, pPCB->pSSID->SsidLength);
  2644. ZCData.dwSizeOfSSID = pPCB->pSSID->SsidLength;
  2645. }
  2646. if ((dwRetCode = ElZeroConfigNotify (
  2647. pPCB->dwZeroConfigId,
  2648. WZCCMD_CFG_SETDATA,
  2649. pPCB->pwszDeviceGUID,
  2650. &ZCData
  2651. )) != NO_ERROR)
  2652. {
  2653. TRACE1 (EAPOL, "ElProcessEapSuccess: ElZeroConfigNotify failed with error %ld",
  2654. dwRetCode);
  2655. dwRetCode = NO_ERROR;
  2656. }
  2657. TRACE1 (EAPOL, "ElProcessEapSuccess: Called ElZeroConfigNotify with type=(%ld)",
  2658. WZCCMD_CFG_SETDATA);
  2659. #endif // ZEROCONFIG_LINKED
  2660. ElNetmanNotify (pPCB, EAPOL_NCS_AUTHENTICATION_SUCCEEDED, NULL);
  2661. }
  2662. while (FALSE);
  2663. return dwRetCode;
  2664. }
  2665. //
  2666. // ElProcessEapFail
  2667. //
  2668. // Description:
  2669. //
  2670. // Function called when an EAP_Fail is received in any state
  2671. //
  2672. // Input arguments:
  2673. // pPCB - Pointer to PCB for the port on which data is being processed
  2674. // pEapolPkt - Pointer to EAPOL packet that was received
  2675. //
  2676. // Return values:
  2677. // NO_ERROR - success
  2678. // non-zero - error
  2679. //
  2680. DWORD
  2681. ElProcessEapFail (
  2682. IN EAPOL_PCB *pPCB,
  2683. IN EAPOL_PACKET *pEapolPkt
  2684. )
  2685. {
  2686. EAPOL_ZC_INTF ZCData;
  2687. DWORD dwRetCode = NO_ERROR;
  2688. TRACE0 (EAPOL, "ElProcessEapFail: Got EAPCODE_Failure");
  2689. do
  2690. {
  2691. // Indicate to EAP-Dll to cleanup completed session
  2692. if ((dwRetCode = ElEapEnd (pPCB)) != NO_ERROR)
  2693. {
  2694. TRACE1 (EAPOL, "ElProcessEapFail: EapFail: Error in ElEapEnd = %ld",
  2695. dwRetCode);
  2696. break;
  2697. }
  2698. // Show failure balloon before notifying ZeroConfig
  2699. // ZeroConfig may require to pop-up its own balloon, and that has
  2700. // to be given preference
  2701. ElNetmanNotify (pPCB, EAPOL_NCS_AUTHENTICATION_FAILED, NULL);
  2702. #ifdef ZEROCONFIG_LINKED
  2703. // Indicate to WZC that authentication failed
  2704. ZeroMemory ((PVOID)&ZCData, sizeof(EAPOL_ZC_INTF));
  2705. ZCData.dwAuthFailCount = pPCB->dwAuthFailCount + 1;
  2706. ZCData.PreviousAuthenticationType = pPCB->PreviousAuthenticationType;
  2707. if (pPCB->pSSID != NULL)
  2708. {
  2709. memcpy (ZCData.bSSID, pPCB->pSSID->Ssid, pPCB->pSSID->SsidLength);
  2710. ZCData.dwSizeOfSSID = pPCB->pSSID->SsidLength;
  2711. }
  2712. // We notify ZC before going through held state, where fail count is
  2713. // upped. Hence, here we explicitly up it by one
  2714. if ((dwRetCode = ElZeroConfigNotify (
  2715. pPCB->dwZeroConfigId,
  2716. ((pPCB->dwAuthFailCount+1) < pPCB->dwTotalMaxAuthFailCount)?WZCCMD_CFG_NEXT:WZCCMD_CFG_DELETE,
  2717. pPCB->pwszDeviceGUID,
  2718. &ZCData
  2719. )) != NO_ERROR)
  2720. {
  2721. TRACE1 (EAPOL, "ElProcessEapFail: ElZeroConfigNotify failed with error %ld",
  2722. dwRetCode);
  2723. dwRetCode = NO_ERROR;
  2724. }
  2725. TRACE3 (EAPOL, "ElProcessEapFail: Called ElZeroConfigNotify with failcount = %ld, prevauthtype = %ld, type=(%ld)",
  2726. ZCData.dwAuthFailCount,
  2727. ZCData.PreviousAuthenticationType,
  2728. ((pPCB->dwAuthFailCount+1) < pPCB->dwTotalMaxAuthFailCount)?WZCCMD_CFG_NEXT:WZCCMD_CFG_DELETE
  2729. );
  2730. #endif // ZEROCONFIG_LINKED
  2731. if ((dwRetCode = FSMHeld (pPCB, NULL)) != NO_ERROR)
  2732. {
  2733. break;
  2734. }
  2735. }
  2736. while (FALSE);
  2737. return dwRetCode;
  2738. }
  2739. //
  2740. // ElSetEAPOLKeyReceivedTimer
  2741. //
  2742. // Description:
  2743. //
  2744. // Function called for wireless interface when it enter AUTHENTICATED state
  2745. // If no EAPOL-Key message is received for the transmit key in the meanwhile
  2746. // the association should be negated to Zero-Config
  2747. //
  2748. // Input arguments:
  2749. // pPCB - Pointer to PCB for the port which entered AUTHENTICATED state
  2750. //
  2751. // Return values:
  2752. // NO_ERROR - success
  2753. // non-zero - error
  2754. //
  2755. DWORD
  2756. ElSetEAPOLKeyReceivedTimer (
  2757. IN EAPOL_PCB *pPCB
  2758. )
  2759. {
  2760. DWORD dwRetCode = NO_ERROR;
  2761. do
  2762. {
  2763. if (pPCB->fTransmitKeyReceived)
  2764. {
  2765. TRACE0 (EAPOL, "EAPOL-Key for transmit key received before entering AUTHENTICATED state");
  2766. break;
  2767. }
  2768. RESTART_TIMER (pPCB->hTimer,
  2769. EAPOL_TRANSMIT_KEY_INTERVAL,
  2770. "PCB",
  2771. &dwRetCode);
  2772. if (dwRetCode != NO_ERROR)
  2773. {
  2774. TRACE1 (EAPOL, "ElSetEAPOLKeyReceivedTimer: Error in RESTART_TIMER %ld",
  2775. dwRetCode);
  2776. break;
  2777. }
  2778. SET_TRANSMIT_KEY_TIMER(pPCB);
  2779. }
  2780. while (FALSE);
  2781. return dwRetCode;
  2782. }
  2783. //
  2784. // ElVerifyEAPOLKeyReceived
  2785. //
  2786. // Description:
  2787. //
  2788. // Function called on timeout to verify if EAPOL-transmit key was received
  2789. // If no EAPOL-Key message is received for the transmit key in the meanwhile
  2790. // the association should be negated to Zero-Config
  2791. //
  2792. // Input arguments:
  2793. // pPCB - Pointer to PCB for the port which entered AUTHENTICATED state
  2794. //
  2795. // Return values:
  2796. // NO_ERROR - success
  2797. // non-zero - error
  2798. //
  2799. DWORD
  2800. ElVerifyEAPOLKeyReceived (
  2801. IN EAPOL_PCB *pPCB
  2802. )
  2803. {
  2804. EAPOL_ZC_INTF ZCData;
  2805. DWORD dwRetCode = NO_ERROR;
  2806. do
  2807. {
  2808. if (!pPCB->fTransmitKeyReceived)
  2809. {
  2810. TRACE1 (EAPOL, "EAPOL-Key for transmit key *NOT* received within %ld seconds in AUTHENTICATED state",
  2811. EAPOL_TRANSMIT_KEY_INTERVAL
  2812. );
  2813. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_NOT_RECEIVED_XMIT_KEY);
  2814. #ifdef ZEROCONFIG_LINKED
  2815. // Indicate to WZC that authentication didn't really complete
  2816. // since there was EAPOL-Key packet for the transmit key
  2817. // Fail the entire configuration
  2818. ZeroMemory ((PVOID)&ZCData, sizeof(EAPOL_ZC_INTF));
  2819. ZCData.dwAuthFailCount = pPCB->dwTotalMaxAuthFailCount;
  2820. pPCB->dwAuthFailCount = pPCB->dwTotalMaxAuthFailCount;
  2821. ZCData.PreviousAuthenticationType = pPCB->PreviousAuthenticationType;
  2822. if (pPCB->pSSID != NULL)
  2823. {
  2824. memcpy (ZCData.bSSID, pPCB->pSSID->Ssid, pPCB->pSSID->SsidLength);
  2825. ZCData.dwSizeOfSSID = pPCB->pSSID->SsidLength;
  2826. }
  2827. if ((dwRetCode = ElZeroConfigNotify (
  2828. pPCB->dwZeroConfigId,
  2829. ((pPCB->dwAuthFailCount) < pPCB->dwTotalMaxAuthFailCount)?WZCCMD_CFG_NEXT:WZCCMD_CFG_DELETE,
  2830. pPCB->pwszDeviceGUID,
  2831. &ZCData
  2832. )) != NO_ERROR)
  2833. {
  2834. TRACE1 (EAPOL, "ElVerifyEAPOLKeyReceived: ElZeroConfigNotify failed with error %ld",
  2835. dwRetCode);
  2836. dwRetCode = NO_ERROR;
  2837. }
  2838. TRACE3 (EAPOL, "ElVerifyEAPOLKeyReceived: Called ElZeroConfigNotify with failcount = %ld, prevauthtype = %ld, type=(%ld)",
  2839. ZCData.dwAuthFailCount,
  2840. ZCData.PreviousAuthenticationType,
  2841. ((pPCB->dwAuthFailCount+1) < pPCB->dwTotalMaxAuthFailCount)?WZCCMD_CFG_NEXT:WZCCMD_CFG_DELETE
  2842. );
  2843. // If authfailed limit reached, go to Disconnected state
  2844. if (pPCB->dwAuthFailCount >= pPCB->dwTotalMaxAuthFailCount)
  2845. {
  2846. TRACE2 (EAPOL, "ElVerifyEAPOLKeyReceived: Pushing into disconnected state: Fail count (%ld) > Max fail count (%ld)",
  2847. pPCB->dwAuthFailCount, pPCB->dwTotalMaxAuthFailCount);
  2848. FSMDisconnected (pPCB, NULL);
  2849. }
  2850. #endif // ZEROCONFIG_LINKED
  2851. }
  2852. else
  2853. {
  2854. TRACE1 (EAPOL, "EAPOL-Key for transmit key received within %ld seconds in AUTHENTICATED state",
  2855. EAPOL_TRANSMIT_KEY_INTERVAL
  2856. );
  2857. }
  2858. }
  2859. while (FALSE);
  2860. return dwRetCode;
  2861. }