Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3431 lines
113 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 (pPCB, 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. BOOLEAN fValidEAPFailure = FALSE;
  1095. DWORD dwRetCode = NO_ERROR;
  1096. TRACE1 (EAPOL, "FSMHeld entered for port %ws", pPCB->pwszFriendlyName);
  1097. do
  1098. {
  1099. TRACE1 (EAPOL, "FSMHeld: EAP authentication failed with error 0x%x",
  1100. pPCB->dwLocalEAPAuthResult);
  1101. // Delete current credentials only if there is actually an error
  1102. // in the EAP module during processing.
  1103. // Ignore EAP-Failures arising out of session time-outs on AP,
  1104. // backend, etc.
  1105. // There is an exception though. In ACQUIRED state, EAP module has
  1106. // not been invoked. dwLocalEAPAuthResult will be set to NO_ERROR
  1107. // It is possible though that the EAP-Identity may be invalid
  1108. // In this case, it will be considered an error, though there is
  1109. // no explicit error for the EAP module.
  1110. if ((pPCB->dwLocalEAPAuthResult != NO_ERROR) ||
  1111. (pPCB->State == EAPOLSTATE_ACQUIRED))
  1112. {
  1113. fValidEAPFailure = TRUE;
  1114. }
  1115. if (fValidEAPFailure)
  1116. {
  1117. pPCB->dwAuthFailCount++;
  1118. TRACE1 (EAPOL, "Restarting Held timer with time value = %ld",
  1119. pPCB->EapolConfig.dwheldPeriod);
  1120. TRACE1 (EAPOL, "FSMHeld: Setting state HELD for port %ws",
  1121. pPCB->pwszFriendlyName);
  1122. // Free Identity buffer
  1123. if (pPCB->pszIdentity != NULL)
  1124. {
  1125. FREE (pPCB->pszIdentity);
  1126. pPCB->pszIdentity = NULL;
  1127. }
  1128. // Free Password buffer
  1129. if (pPCB->PasswordBlob.pbData != NULL)
  1130. {
  1131. FREE (pPCB->PasswordBlob.pbData);
  1132. pPCB->PasswordBlob.pbData = NULL;
  1133. pPCB->PasswordBlob.cbData = 0;
  1134. }
  1135. // Free user-specific data in the PCB
  1136. if (pPCB->pCustomAuthUserData != NULL)
  1137. {
  1138. FREE (pPCB->pCustomAuthUserData);
  1139. pPCB->pCustomAuthUserData = NULL;
  1140. }
  1141. // Free connection data
  1142. if (pPCB->pCustomAuthConnData != NULL)
  1143. {
  1144. FREE (pPCB->pCustomAuthConnData);
  1145. pPCB->pCustomAuthConnData = NULL;
  1146. }
  1147. // Delete User Data stored in registry since it is invalid
  1148. if (pPCB->pSSID != NULL)
  1149. {
  1150. if ((dwRetCode = ElDeleteEapUserInfo (
  1151. pPCB->hUserToken,
  1152. pPCB->pwszDeviceGUID,
  1153. pPCB->dwEapTypeToBeUsed,
  1154. pPCB->pSSID->SsidLength,
  1155. pPCB->pSSID->Ssid
  1156. )) != NO_ERROR)
  1157. {
  1158. TRACE1 (EAPOL, "FSMHeld: ElDeleteEapUserInfo failed with error %ld",
  1159. dwRetCode);
  1160. dwRetCode = NO_ERROR;
  1161. }
  1162. }
  1163. else
  1164. {
  1165. if ((dwRetCode = ElDeleteEapUserInfo (
  1166. pPCB->hUserToken,
  1167. pPCB->pwszDeviceGUID,
  1168. pPCB->dwEapTypeToBeUsed,
  1169. 0,
  1170. NULL
  1171. )) != NO_ERROR)
  1172. {
  1173. TRACE1 (EAPOL, "FSMHeld: ElDeleteEapUserInfo failed with error %ld",
  1174. dwRetCode);
  1175. dwRetCode = NO_ERROR;
  1176. }
  1177. }
  1178. // Since there has been an error in credentials, start afresh
  1179. // the authentication. Credentials may have changed e.g. certs
  1180. // may be renewed, MD5 credentials corrected etc.
  1181. pPCB->fGotUserIdentity = FALSE;
  1182. if (pPCB->hUserToken != NULL)
  1183. {
  1184. if (!CloseHandle (pPCB->hUserToken))
  1185. {
  1186. dwRetCode = GetLastError ();
  1187. TRACE1 (EAPOL, "FSMHeld: CloseHandle failed with error %ld",
  1188. dwRetCode);
  1189. dwRetCode = NO_ERROR;
  1190. }
  1191. }
  1192. pPCB->hUserToken = NULL;
  1193. if (pPCB->State == EAPOLSTATE_ACQUIRED)
  1194. {
  1195. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_EAP_AUTHENTICATION_FAILED_ACQUIRED);
  1196. }
  1197. else
  1198. {
  1199. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_EAP_AUTHENTICATION_FAILED, pPCB->dwLocalEAPAuthResult);
  1200. }
  1201. }
  1202. else
  1203. {
  1204. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_EAP_AUTHENTICATION_FAILED_DEFAULT);
  1205. }
  1206. DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_STATE_TRANSITION,
  1207. EAPOLStates[((pPCB->State < EAPOLSTATE_LOGOFF) || (pPCB->State > EAPOLSTATE_AUTHENTICATED))?EAPOLSTATE_UNDEFINED:pPCB->State],
  1208. EAPOLStates[EAPOLSTATE_HELD]);
  1209. pPCB->State = EAPOLSTATE_HELD;
  1210. TRACE1 (EAPOL, "FSMHeld: Port %ws set to HELD state",
  1211. pPCB->pwszDeviceGUID);
  1212. if (fValidEAPFailure)
  1213. {
  1214. // If authfailed limit reached, go to Disconnected state
  1215. if (pPCB->dwAuthFailCount >= pPCB->dwTotalMaxAuthFailCount)
  1216. {
  1217. TRACE2 (EAPOL, "FSMHeld: Fail count (%ld) > Max fail count (%ld)",
  1218. pPCB->dwAuthFailCount, pPCB->dwTotalMaxAuthFailCount);
  1219. FSMDisconnected (pPCB, NULL);
  1220. break;
  1221. }
  1222. }
  1223. SET_EAPOL_HELD_TIMER(pPCB);
  1224. // Restart timer with heldPeriod
  1225. RESTART_TIMER (pPCB->hTimer,
  1226. pPCB->EapolConfig.dwheldPeriod,
  1227. "PCB",
  1228. &dwRetCode);
  1229. if (dwRetCode != NO_ERROR)
  1230. {
  1231. TRACE1 (EAPOL, "FSMHeld: Error in RESTART_TIMER %ld",
  1232. dwRetCode);
  1233. break;
  1234. }
  1235. } while (FALSE);
  1236. TRACE1 (EAPOL, "FSMHeld completed for port %ws", pPCB->pwszFriendlyName);
  1237. return dwRetCode;
  1238. }
  1239. //
  1240. // FSMAuthenticated
  1241. //
  1242. // Description:
  1243. //
  1244. // Function called when a EAP-Success packet is received or MaxStart
  1245. // EAPOL_Startpackets have been sent out, but no EAP-Request/Identity
  1246. // packets were received. If EAP-Success packet is request, DHCP client
  1247. // is restarted to get a new IP address.
  1248. //
  1249. // Arguments:
  1250. // pPCB - Pointer to the PCB for the port on which data is being
  1251. // processed
  1252. // pEapolPkt - Pointer to EAPOL packet that was received
  1253. //
  1254. // Return values:
  1255. // NO_ERROR - success
  1256. // non-zero - error
  1257. //
  1258. DWORD
  1259. FSMAuthenticated (
  1260. IN EAPOL_PCB *pPCB,
  1261. IN EAPOL_PACKET *pEapolPkt
  1262. )
  1263. {
  1264. DHCP_PNP_CHANGE DhcpPnpChange;
  1265. WCHAR *pwszGUIDBuffer = NULL;
  1266. BOOLEAN fReAuthenticatedWithSamePeer = FALSE;
  1267. DWORD dwRetCode = NO_ERROR;
  1268. TRACE1 (EAPOL, "FSMAuthenticated entered for port %ws",
  1269. pPCB->pwszFriendlyName);
  1270. do
  1271. {
  1272. // Shutdown earlier EAP session
  1273. ElEapEnd (pPCB);
  1274. // Call DHCP only if state machine went through authentication
  1275. // If FSM is getting AUTHENTICATED by default, don't renew address
  1276. // Also, if reauthentication is happening with same peer, namely in
  1277. // wireless, don't renew address
  1278. #if 0
  1279. if (pPCB->PhysicalMediumType == NdisPhysicalMediumWirelessLan)
  1280. {
  1281. if (!memcmp (pPCB->bDestMacAddr, pPCB->bPreviousDestMacAddr,
  1282. SIZE_MAC_ADDR))
  1283. {
  1284. fReAuthenticatedWithSamePeer = TRUE;
  1285. }
  1286. else
  1287. {
  1288. memcpy (pPCB->bPreviousDestMacAddr, pPCB->bDestMacAddr,
  1289. SIZE_MAC_ADDR);
  1290. }
  1291. }
  1292. #endif
  1293. if ((pPCB->ulStartCount < pPCB->EapolConfig.dwmaxStart) &&
  1294. (!fReAuthenticatedWithSamePeer))
  1295. {
  1296. if ((pwszGUIDBuffer = MALLOC ((wcslen(pPCB->pwszDeviceGUID) + 1)*sizeof(WCHAR))) == NULL)
  1297. {
  1298. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  1299. break;
  1300. }
  1301. wcscpy (pwszGUIDBuffer, pPCB->pwszDeviceGUID);
  1302. InterlockedIncrement (&g_lWorkerThreads);
  1303. if (!QueueUserWorkItem (
  1304. (LPTHREAD_START_ROUTINE)ElIPPnPWorker,
  1305. (PVOID)pwszGUIDBuffer,
  1306. WT_EXECUTELONGFUNCTION
  1307. ))
  1308. {
  1309. InterlockedDecrement (&g_lWorkerThreads);
  1310. FREE (pwszGUIDBuffer);
  1311. dwRetCode = GetLastError();
  1312. TRACE1 (PORT, "FSMAuthenticated: Critical error: QueueUserWorkItem failed with error %ld",
  1313. dwRetCode);
  1314. // Ignore DHCP error, it's outside 802.1X logic
  1315. dwRetCode = NO_ERROR;
  1316. }
  1317. else
  1318. {
  1319. TRACE0 (PORT, "FSMAuthenticated: Queued ElIPPnPWorker");
  1320. }
  1321. }
  1322. TRACE1 (EAPOL, "Setting state AUTHENTICATED for port %ws", pPCB->pwszFriendlyName);
  1323. DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_STATE_TRANSITION,
  1324. EAPOLStates[((pPCB->State < EAPOLSTATE_LOGOFF) || (pPCB->State > EAPOLSTATE_AUTHENTICATED))?EAPOLSTATE_UNDEFINED:pPCB->State],
  1325. EAPOLStates[EAPOLSTATE_AUTHENTICATED]);
  1326. if (pPCB->fLocalEAPAuthSuccess)
  1327. {
  1328. DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_EAP_AUTHENTICATION_SUCCEEDED);
  1329. }
  1330. else
  1331. {
  1332. DbLogPCBEvent (DBLOG_CATEG_WARN, pPCB, EAPOL_EAP_AUTHENTICATION_DEFAULT);
  1333. }
  1334. pPCB->State = EAPOLSTATE_AUTHENTICATED;
  1335. // In case of Wireless LAN ensure that there is EAPOL_Key packets
  1336. // received for transmit key
  1337. if (pPCB->PhysicalMediumType == NdisPhysicalMediumWirelessLan)
  1338. {
  1339. if ((dwRetCode = ElSetEAPOLKeyReceivedTimer (pPCB)) != NO_ERROR)
  1340. {
  1341. TRACE1 (EAPOL, "FSMAuthenticated: ElSetEAPOLKeyReceivedTimer failed with error %ld",
  1342. dwRetCode);
  1343. break;
  1344. }
  1345. }
  1346. } while (FALSE);
  1347. TRACE1 (EAPOL, "FSMAuthenticated completed for port %ws", pPCB->pwszFriendlyName);
  1348. return dwRetCode;
  1349. }
  1350. //
  1351. // FSMKeyReceive
  1352. //
  1353. // Description:
  1354. // Function called when an EAPOL-Key packet is received.
  1355. // The WEP key is decrypted and plumbed down to the NIC driver.
  1356. //
  1357. // Arguments:
  1358. // pPCB - Pointer to the PCB for the port on which data is being
  1359. // processed
  1360. // pEapolPkt - Pointer to EAPOL packet that was received
  1361. //
  1362. // Return values:
  1363. // NO_ERROR - success
  1364. // non-zero - error
  1365. //
  1366. DWORD
  1367. FSMKeyReceive (
  1368. IN EAPOL_PCB *pPCB,
  1369. IN EAPOL_PACKET *pEapolPkt
  1370. )
  1371. {
  1372. EAPOL_KEY_DESC *pKeyDesc = NULL;
  1373. DWORD dwRetCode = NO_ERROR;
  1374. TRACE1 (EAPOL, "FSMKeyReceive entered for port %ws", pPCB->pwszFriendlyName);
  1375. do
  1376. {
  1377. pKeyDesc = (EAPOL_KEY_DESC *)pEapolPkt->PacketBody;
  1378. switch (pKeyDesc->DescriptorType)
  1379. {
  1380. case EAPOL_KEY_DESC_RC4:
  1381. if ((dwRetCode = ElKeyReceiveRC4 (pPCB,
  1382. pEapolPkt)) != NO_ERROR)
  1383. {
  1384. TRACE1 (EAPOL, "FSMKeyReceive: ElKeyReceiveRC4 failed with error %ld",
  1385. dwRetCode);
  1386. }
  1387. break;
  1388. #if 0
  1389. case EAPOL_KEY_DESC_PER_STA:
  1390. if ((dwRetCode = ElKeyReceivePerSTA (pPCB,
  1391. pEapolPkt)) != NO_ERROR)
  1392. {
  1393. TRACE1 (EAPOL, "FSMKeyReceive: ElKeyReceivePerSTA failed with error %ld",
  1394. dwRetCode);
  1395. }
  1396. break;
  1397. #endif
  1398. default:
  1399. dwRetCode = ERROR_INVALID_PARAMETER;
  1400. TRACE1 (EAPOL, "FSMKeyReceive: Invalid DescriptorType (%ld)",
  1401. pKeyDesc->DescriptorType);
  1402. break;
  1403. }
  1404. }
  1405. while (FALSE);
  1406. if (dwRetCode != NO_ERROR)
  1407. {
  1408. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB,
  1409. EAPOL_ERROR_PROCESSING_EAPOL_KEY, dwRetCode);
  1410. }
  1411. TRACE1 (EAPOL, "FSMKeyReceive completed for port %ws", pPCB->pwszFriendlyName);
  1412. return dwRetCode;
  1413. }
  1414. //
  1415. // ElKeyReceiveRC4
  1416. //
  1417. // Description:
  1418. // Function called when an EAPOL-Key packet is received
  1419. // with RC4 DescriptorType
  1420. //
  1421. // Arguments:
  1422. // pPCB - Pointer to the PCB for the port on which data is being
  1423. // processed
  1424. // pEapolPkt - Pointer to EAPOL packet that was received
  1425. //
  1426. // Return values:
  1427. // NO_ERROR - success
  1428. // non-zero - error
  1429. //
  1430. DWORD
  1431. ElKeyReceiveRC4 (
  1432. IN EAPOL_PCB *pPCB,
  1433. IN EAPOL_PACKET *pEapolPkt
  1434. )
  1435. {
  1436. EAPOL_KEY_DESC *pKeyDesc = NULL;
  1437. ULONGLONG ullReplayCheck = 0;
  1438. BYTE bReplayCheck[8];
  1439. BYTE *pbMD5EapolPkt = NULL;
  1440. DWORD dwMD5EapolPktLen = 0;
  1441. DWORD dwEapPktLen = 0;
  1442. DWORD dwIndex = 0;
  1443. BYTE bHMACMD5HashBuffer[MD5DIGESTLEN];
  1444. RC4_KEYSTRUCT rc4key;
  1445. BYTE bKeyBuffer[48];
  1446. BYTE *pbKeyToBePlumbed = NULL;
  1447. DWORD dwKeyLength = 0;
  1448. NDIS_802_11_WEP *pNdisWEPKey = NULL;
  1449. BYTE *pbMPPESendKey = NULL, *pbMPPERecvKey = NULL;
  1450. DWORD dwMPPESendKeyLength = 0, dwMPPERecvKeyLength = 0;
  1451. DWORD dwRetCode = NO_ERROR;
  1452. TRACE1 (EAPOL, "ElKeyReceiveRC4 entered for port %ws", pPCB->pwszFriendlyName);
  1453. do
  1454. {
  1455. if (WireToHostFormat16 (pEapolPkt->PacketBodyLength) < FIELD_OFFSET (EAPOL_KEY_DESC, Key))
  1456. {
  1457. TRACE0 (EAPOL, "ElKeyReceiveRC4: Invalid EAPOL-Key packet");
  1458. dwRetCode = ERROR_INVALID_PACKET;
  1459. break;
  1460. }
  1461. pKeyDesc = (EAPOL_KEY_DESC *)pEapolPkt->PacketBody;
  1462. dwKeyLength = WireToHostFormat16 (pKeyDesc->KeyLength);
  1463. if (WireToHostFormat16 (pEapolPkt->PacketBodyLength) > sizeof(EAPOL_KEY_DESC))
  1464. {
  1465. if (dwKeyLength != (WireToHostFormat16 (pEapolPkt->PacketBodyLength) - FIELD_OFFSET(EAPOL_KEY_DESC, Key)))
  1466. {
  1467. TRACE1 (EAPOL, "ElKeyReceiveRC4: Invalid Key Length in packet (%ld",
  1468. dwKeyLength);
  1469. dwRetCode = ERROR_INVALID_PACKET;
  1470. break;
  1471. }
  1472. }
  1473. TRACE2 (EAPOL, "KeyLength = %ld, \n KeyIndex = %ld",
  1474. dwKeyLength,
  1475. pKeyDesc->KeyIndex
  1476. );
  1477. memcpy ((BYTE *)bReplayCheck,
  1478. (BYTE *)pKeyDesc->ReplayCounter,
  1479. 8*sizeof(BYTE));
  1480. ullReplayCheck = ((((ULONGLONG)(*((PBYTE)(bReplayCheck)+0))) << 56) +
  1481. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+1))) << 48) +
  1482. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+2))) << 40) +
  1483. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+3))) << 32) +
  1484. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+4))) << 24) +
  1485. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+5))) << 16) +
  1486. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+6))) << 8) +
  1487. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+7)))));
  1488. //
  1489. // Check validity of Key message using the ReplayCounter field
  1490. // Verify if it is in sync with the last ReplayCounter value
  1491. // received
  1492. //
  1493. // TRACE0 (EAPOL, "ElKeyReceiveRC4: Original replay counter in desc ======");
  1494. // EAPOL_DUMPBA (pKeyDesc->ReplayCounter, 8);
  1495. // TRACE0 (EAPOL, "ElKeyReceiveRC4: Converted incoming Replay counter ======= ");
  1496. // EAPOL_DUMPBA ((BYTE *)&ullReplayCheck, 8);
  1497. // TRACE0 (EAPOL, "ElKeyReceiveRC4: Last Replay counter ======= ");
  1498. // EAPOL_DUMPBA ((BYTE *)&(pPCB->ullLastReplayCounter), 8);
  1499. if (ullReplayCheck <= pPCB->ullLastReplayCounter)
  1500. {
  1501. TRACE0 (EAPOL, "ElKeyReceiveRC4: Replay counter is not in sync, something is wrong");
  1502. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_INVALID_EAPOL_KEY);
  1503. break;
  1504. }
  1505. // If valid ReplayCounter, save it in the PCB for future check
  1506. pPCB->ullLastReplayCounter = ullReplayCheck;
  1507. //
  1508. // Verify if the MD5 hash generated on the EAPOL packet,
  1509. // with Signature nulled out, is the same as the signature
  1510. // Use the MPPERecv key as the secret
  1511. //
  1512. dwEapPktLen = WireToHostFormat16 (pEapolPkt->PacketBodyLength);
  1513. dwMD5EapolPktLen = sizeof (EAPOL_PACKET) - sizeof(pEapolPkt->EthernetType) - 1 + dwEapPktLen;
  1514. if ((pbMD5EapolPkt = (BYTE *) MALLOC (dwMD5EapolPktLen)) == NULL)
  1515. {
  1516. TRACE0 (EAPOL, "ElKeyReceiveRC4: Error in MALLOC for pbMD5EapolPkt");
  1517. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  1518. break;
  1519. }
  1520. memcpy ((BYTE *)pbMD5EapolPkt, (BYTE *)pEapolPkt+sizeof(pEapolPkt->EthernetType), dwMD5EapolPktLen);
  1521. // Access the Master Send and Recv key stored locally
  1522. if ((dwRetCode = ElSecureDecodePw (
  1523. &(pPCB->MasterSecretSend),
  1524. &(pbMPPESendKey),
  1525. &dwMPPESendKeyLength
  1526. )) != NO_ERROR)
  1527. {
  1528. TRACE1 (EAPOL, "ElKeyReceiveRC4: ElSecureDecodePw failed for MasterSecretSend with error %ld",
  1529. dwRetCode);
  1530. break;
  1531. }
  1532. if ((dwRetCode = ElSecureDecodePw (
  1533. &(pPCB->MasterSecretRecv),
  1534. &(pbMPPERecvKey),
  1535. &dwMPPERecvKeyLength
  1536. )) != NO_ERROR)
  1537. {
  1538. TRACE1 (EAPOL, "ElKeyReceiveRC4: ElSecureDecodePw failed for MasterSecretRecv with error %ld",
  1539. dwRetCode);
  1540. break;
  1541. }
  1542. //
  1543. // Null out the signature in the key descriptor copy, to calculate
  1544. // the hash on the supplicant side
  1545. //
  1546. ZeroMemory ((BYTE *)(pbMD5EapolPkt
  1547. - sizeof(pEapolPkt->EthernetType) +
  1548. sizeof(EAPOL_PACKET) - 1 + // pEapolPkt->Body
  1549. sizeof(EAPOL_KEY_DESC)- // End of EAPOL_KEY_DESC
  1550. MD5DIGESTLEN-1), // Signature field
  1551. MD5DIGESTLEN);
  1552. (VOID) ElGetHMACMD5Digest (
  1553. pbMD5EapolPkt,
  1554. dwMD5EapolPktLen,
  1555. pbMPPERecvKey,
  1556. dwMPPERecvKeyLength,
  1557. bHMACMD5HashBuffer
  1558. );
  1559. // TRACE0 (EAPOL, "ElKeyReceiveRC4: MD5 Hash body ==");
  1560. // EAPOL_DUMPBA (pbMD5EapolPkt, dwMD5EapolPktLen);
  1561. // TRACE0 (EAPOL, "ElKeyReceiveRC4: MD5 Hash secret ==");
  1562. // EAPOL_DUMPBA (pbMPPERecvKey, dwMPPERecvKeyLength);
  1563. // TRACE0 (EAPOL, "ElKeyReceiveRC4: MD5 Hash generated by Supplicant");
  1564. // EAPOL_DUMPBA (bHMACMD5HashBuffer, MD5DIGESTLEN);
  1565. // TRACE0 (EAPOL, "ElKeyReceiveRC4: Signature sent in EAPOL_KEY_DESC");
  1566. // EAPOL_DUMPBA (pKeyDesc->KeySignature, MD5DIGESTLEN);
  1567. //
  1568. // Check if HMAC-MD5 hash in received packet is what is expected
  1569. //
  1570. if (memcmp (bHMACMD5HashBuffer, pKeyDesc->KeySignature, MD5DIGESTLEN) != 0)
  1571. {
  1572. TRACE0 (EAPOL, "ElKeyReceiveRC4: Signature in Key Desc does not match");
  1573. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_INVALID_EAPOL_KEY);
  1574. break;
  1575. }
  1576. //
  1577. // Decrypt the multicast WEP key if it has been provided
  1578. //
  1579. // Check if there is Key Material (5/16 bytes) at the end of
  1580. // the Key Descriptor
  1581. if (WireToHostFormat16 (pEapolPkt->PacketBodyLength) > sizeof (EAPOL_KEY_DESC))
  1582. {
  1583. memcpy ((BYTE *)bKeyBuffer, (BYTE *)pKeyDesc->Key_IV, 16);
  1584. memcpy ((BYTE *)&bKeyBuffer[16], (BYTE *)pbMPPESendKey, dwMPPESendKeyLength);
  1585. rc4_key (&rc4key, 16 + dwMPPESendKeyLength, bKeyBuffer);
  1586. rc4 (&rc4key, dwKeyLength, pKeyDesc->Key);
  1587. // TRACE0 (EAPOL, " ========= The multicast key is ============= ");
  1588. // EAPOL_DUMPBA (pKeyDesc->Key, dwKeyLength);
  1589. // Use the unencrypted key in the Key Desc as the encryption key
  1590. pbKeyToBePlumbed = pKeyDesc->Key;
  1591. }
  1592. else
  1593. {
  1594. if (dwKeyLength > dwMPPESendKeyLength)
  1595. {
  1596. TRACE1 (EAPOL, "ElKeyReceiveRC4: Invalid Key Length in packet (%ld",
  1597. dwKeyLength);
  1598. dwRetCode = ERROR_INVALID_PACKET;
  1599. break;
  1600. }
  1601. // Use the MPPESend key as the encryption key
  1602. pbKeyToBePlumbed = (BYTE *)pbMPPESendKey;
  1603. }
  1604. if ((pNdisWEPKey = MALLOC ( sizeof(NDIS_802_11_WEP)-1+dwKeyLength ))
  1605. == NULL)
  1606. {
  1607. TRACE0 (EAPOL, "ElKeyReceiveRC4: MALLOC failed for pNdisWEPKey");
  1608. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  1609. break;
  1610. }
  1611. pNdisWEPKey->Length = sizeof(NDIS_802_11_WEP) - 1 + dwKeyLength;
  1612. memcpy ((BYTE *)pNdisWEPKey->KeyMaterial, (BYTE *)pbKeyToBePlumbed,
  1613. dwKeyLength);
  1614. pNdisWEPKey->KeyLength = dwKeyLength;
  1615. // Create the long index out of the byte index got from AP
  1616. // If MSB in byte is set, set MSB in ulong format
  1617. if (pKeyDesc->KeyIndex & 0x80)
  1618. {
  1619. pNdisWEPKey->KeyIndex = 0x80000000;
  1620. }
  1621. else
  1622. {
  1623. pNdisWEPKey->KeyIndex = 0x00000000;
  1624. }
  1625. pNdisWEPKey->KeyIndex |= (pKeyDesc->KeyIndex & 0x03);
  1626. // TRACE1 (ANY, "ElKeyReceiveRC4: Key Index is %x", pNdisWEPKey->KeyIndex);
  1627. // Flag that transmit key was received
  1628. if (pKeyDesc->KeyIndex & 0x80)
  1629. {
  1630. pPCB->fTransmitKeyReceived = TRUE;
  1631. }
  1632. // Use NDISUIO to plumb the key to the driver
  1633. if ((dwRetCode = ElNdisuioSetOIDValue (
  1634. pPCB->hPort,
  1635. OID_802_11_ADD_WEP,
  1636. (BYTE *)pNdisWEPKey,
  1637. pNdisWEPKey->Length)) != NO_ERROR)
  1638. {
  1639. TRACE1 (PORT, "ElKeyReceiveRC4: ElNdisuioSetOIDValue failed with error %ld",
  1640. dwRetCode);
  1641. }
  1642. }
  1643. while (FALSE);
  1644. if (dwRetCode != NO_ERROR)
  1645. {
  1646. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB,
  1647. EAPOL_ERROR_PROCESSING_EAPOL_KEY, dwRetCode);
  1648. }
  1649. if (pbMD5EapolPkt != NULL)
  1650. {
  1651. FREE (pbMD5EapolPkt);
  1652. pbMD5EapolPkt = NULL;
  1653. }
  1654. if (pNdisWEPKey != NULL)
  1655. {
  1656. FREE (pNdisWEPKey);
  1657. pNdisWEPKey = NULL;
  1658. }
  1659. if (pbMPPESendKey != NULL)
  1660. {
  1661. FREE (pbMPPESendKey);
  1662. }
  1663. if (pbMPPERecvKey != NULL)
  1664. {
  1665. FREE (pbMPPERecvKey);
  1666. }
  1667. TRACE1 (EAPOL, "ElKeyReceiveRC4 completed for port %ws", pPCB->pwszFriendlyName);
  1668. return dwRetCode;
  1669. }
  1670. #if 0
  1671. //
  1672. // ElKeyReceivePerSTA
  1673. //
  1674. // Description:
  1675. // Function called when an EAPOL-Key packet is received
  1676. // with PerSTA DescriptorType
  1677. //
  1678. // Arguments:
  1679. // pPCB - Pointer to the PCB for the port on which data is being
  1680. // processed
  1681. // pEapolPkt - Pointer to EAPOL packet that was received
  1682. //
  1683. // Return values:
  1684. // NO_ERROR - success
  1685. // non-zero - error
  1686. //
  1687. DWORD
  1688. ElKeyReceivePerSTA (
  1689. IN EAPOL_PCB *pPCB,
  1690. IN EAPOL_PACKET *pEapolPkt
  1691. )
  1692. {
  1693. EAPOL_KEY_DESC *pKeyDesc = NULL;
  1694. ULONGLONG ullReplayCheck = 0;
  1695. BYTE bReplayCheck[8];
  1696. BYTE *pbMD5EapolPkt = NULL;
  1697. DWORD dwMD5EapolPktLen = 0;
  1698. DWORD dwEapPktLen = 0;
  1699. DWORD dwIndex = 0;
  1700. BYTE bHMACMD5HashBuffer[MD5DIGESTLEN];
  1701. RC4_KEYSTRUCT rc4key;
  1702. BYTE bKeyBuffer[48];
  1703. BYTE *pbKeyToBePlumbed = NULL;
  1704. DWORD dwRandomLength = 0;
  1705. NDIS_802_11_WEP *pNdisWEPKey = NULL;
  1706. BYTE *pbMasterSecretSend = NULL;
  1707. DWORD dwMasterSecretSendLength = 0;
  1708. BYTE *pbMasterSecretRecv = NULL;
  1709. DWORD dwMasterSecretRecvLength = 0;
  1710. BYTE *pbDynamicSendKey = NULL, *pbDynamicRecvKey = NULL;
  1711. DWORD dwDynamicKeyLength = 0;
  1712. EAPOL_KEY_MATERIAL *pEapolKeyMaterial = NULL;
  1713. PBYTE pbPaddedKeyMaterial = NULL;
  1714. BOOLEAN fIsUnicastKey = FALSE;
  1715. SESSION_KEYS OldSessionKeys = {0};
  1716. SESSION_KEYS NewSessionKeys = {0};
  1717. DWORD dwRetCode = NO_ERROR;
  1718. TRACE1 (EAPOL, "ElKeyReceivePerSTA entered for port %ws", pPCB->pwszFriendlyName);
  1719. do
  1720. {
  1721. pKeyDesc = (EAPOL_KEY_DESC *)pEapolPkt->PacketBody;
  1722. dwDynamicKeyLength = WireToHostFormat16 (pKeyDesc->KeyLength);
  1723. // TRACE2 (EAPOL, "ElKeyReceivePerSTA: KeyLength = %ld, \n KeyIndex = %0x",
  1724. // dwDynamicKeyLength,
  1725. // pKeyDesc->KeyIndex
  1726. // );
  1727. memcpy ((BYTE *)bReplayCheck,
  1728. (BYTE *)pKeyDesc->ReplayCounter,
  1729. 8*sizeof(BYTE));
  1730. ullReplayCheck = ((((ULONGLONG)(*((PBYTE)(bReplayCheck)+0))) << 56) +
  1731. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+1))) << 48) +
  1732. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+2))) << 40) +
  1733. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+3))) << 32) +
  1734. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+4))) << 24) +
  1735. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+5))) << 16) +
  1736. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+6))) << 8) +
  1737. (((ULONGLONG)(*((PBYTE)(bReplayCheck)+7)))));
  1738. // Check validity of Key message using the ReplayCounter field
  1739. // Verify if it is in sync with the last ReplayCounter value
  1740. // received
  1741. // TRACE0 (EAPOL, "Original replay counter in desc ======");
  1742. // EAPOL_DUMPBA (pKeyDesc->ReplayCounter, 8);
  1743. // TRACE0 (EAPOL, "Converted incoming Replay counter ======= ");
  1744. // EAPOL_DUMPBA ((BYTE *)&ullReplayCheck, 8);
  1745. // TRACE0 (EAPOL, "Last Replay counter ======= ");
  1746. // EAPOL_DUMPBA ((BYTE *)&(pPCB->ullLastReplayCounter), 8);
  1747. if (ullReplayCheck <= pPCB->ullLastReplayCounter)
  1748. {
  1749. TRACE0 (EAPOL, "ElKeyReceivePerSTA: Replay counter is not in sync, something is wrong");
  1750. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_INVALID_EAPOL_KEY);
  1751. break;
  1752. }
  1753. // If valid ReplayCounter, save it in the PCB for future check
  1754. pPCB->ullLastReplayCounter = ullReplayCheck;
  1755. // Verify if the MD5 hash generated on the EAPOL packet,
  1756. // with Signature nulled out, is the same as the signature
  1757. // Use the MPPERecv key as the secret
  1758. dwEapPktLen = WireToHostFormat16 (pEapolPkt->PacketBodyLength);
  1759. dwMD5EapolPktLen = sizeof (EAPOL_PACKET) - sizeof(pEapolPkt->EthernetType) - 1 + dwEapPktLen;
  1760. if ((pbMD5EapolPkt = (BYTE *) MALLOC (dwMD5EapolPktLen)) == NULL)
  1761. {
  1762. TRACE0 (EAPOL, "ElKeyReceivePerSTA: Error in MALLOC for pbMD5EapolPkt");
  1763. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  1764. break;
  1765. }
  1766. memcpy ((BYTE *)pbMD5EapolPkt, (BYTE *)pEapolPkt+sizeof(pEapolPkt->EthernetType), dwMD5EapolPktLen);
  1767. // Query Master Secrets
  1768. if (dwRetCode = ElQueryMasterKeys (
  1769. pPCB,
  1770. &OldSessionKeys
  1771. ) != NO_ERROR)
  1772. {
  1773. TRACE1 (EAPOL, "ElKeyReceivePerSTA: ElQueryMasterKeys failed with error %ld",
  1774. dwRetCode);
  1775. break;
  1776. }
  1777. pbMasterSecretSend = OldSessionKeys.bSendKey;
  1778. pbMasterSecretRecv = OldSessionKeys.bReceiveKey;
  1779. dwMasterSecretSendLength = OldSessionKeys.dwKeyLength;
  1780. dwMasterSecretRecvLength = OldSessionKeys.dwKeyLength;
  1781. // Null out the signature in the key descriptor copy, to calculate
  1782. // the hash on the supplicant side
  1783. ZeroMemory ((BYTE *)(pbMD5EapolPkt
  1784. - sizeof(pEapolPkt->EthernetType) +
  1785. sizeof(EAPOL_PACKET) - 1 + // pEapolPkt->Body
  1786. sizeof(EAPOL_KEY_DESC)- // End of EAPOL_KEY_DESC
  1787. MD5DIGESTLEN-1), // Signature field
  1788. MD5DIGESTLEN);
  1789. (VOID) ElGetHMACMD5Digest (
  1790. pbMD5EapolPkt,
  1791. dwMD5EapolPktLen,
  1792. pbMasterSecretRecv,
  1793. dwMasterSecretRecvLength,
  1794. bHMACMD5HashBuffer
  1795. );
  1796. // TRACE0 (EAPOL, "ElKeyReceivePerSTA: MD5 Hash body ==");
  1797. // EAPOL_DUMPBA (pbMD5EapolPkt, dwMD5EapolPktLen);
  1798. // TRACE0 (EAPOL, "ElKeyReceivePerSTA: MD5 Hash secret ==");
  1799. // EAPOL_DUMPBA (pbMasterSecretRecv, dwMasterSecretRecvLength);
  1800. // TRACE0 (EAPOL, "ElKeyReceivePerSTA: MD5 Hash generated by Supplicant");
  1801. // EAPOL_DUMPBA (bHMACMD5HashBuffer, MD5DIGESTLEN);
  1802. // TRACE0 (EAPOL, "ElKeyReceivePerSTA: Signature sent in EAPOL_KEY_DESC");
  1803. // EAPOL_DUMPBA (pKeyDesc->KeySignature, MD5DIGESTLEN);
  1804. // Check if HMAC-MD5 hash in received packet is what is expected
  1805. if (memcmp (bHMACMD5HashBuffer, pKeyDesc->KeySignature, MD5DIGESTLEN) != 0)
  1806. {
  1807. TRACE0 (EAPOL, "ElKeyReceivePerSTA: Signature in Key Descriptor does not match");
  1808. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_INVALID_EAPOL_KEY);
  1809. break;
  1810. }
  1811. if (pKeyDesc->KeyIndex & 0x80)
  1812. {
  1813. fIsUnicastKey = TRUE;
  1814. }
  1815. // Decrypt the random value if it has been provided
  1816. if (WireToHostFormat16 (pEapolPkt->PacketBodyLength) > sizeof (EAPOL_KEY_DESC))
  1817. {
  1818. DWORD dwKeyMaterialLength = 0;
  1819. dwKeyMaterialLength = WireToHostFormat16 (pEapolPkt->PacketBodyLength) - FIELD_OFFSET(EAPOL_KEY_DESC, Key);
  1820. // TRACE1 (EAPOL, "ElKeyReceivePerSTA: KeyMaterialLength = %ld",
  1821. // dwKeyMaterialLength);
  1822. memcpy ((BYTE *)bKeyBuffer, (BYTE *)pKeyDesc->Key_IV, KEY_IV_LENGTH);
  1823. memcpy ((BYTE *)&bKeyBuffer[KEY_IV_LENGTH], (BYTE *)pbMasterSecretSend,
  1824. dwMasterSecretSendLength);
  1825. pEapolKeyMaterial = (PEAPOL_KEY_MATERIAL)pKeyDesc->Key;
  1826. dwRandomLength = WireToHostFormat16 (pEapolKeyMaterial->KeyMaterialLength);
  1827. if ((pbPaddedKeyMaterial = (PBYTE)MALLOC (RC4_PAD_LENGTH + dwKeyMaterialLength)) == NULL)
  1828. {
  1829. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  1830. break;
  1831. }
  1832. memcpy (pbPaddedKeyMaterial+RC4_PAD_LENGTH, pEapolKeyMaterial->KeyMaterial, dwKeyMaterialLength);
  1833. rc4_key (&rc4key, KEY_IV_LENGTH+dwMasterSecretSendLength, bKeyBuffer);
  1834. rc4 (&rc4key, dwKeyMaterialLength+RC4_PAD_LENGTH, pbPaddedKeyMaterial);
  1835. // Ignore leading padded RC4_PAD_LENGTH bytes
  1836. memcpy (pEapolKeyMaterial->KeyMaterial, pbPaddedKeyMaterial+RC4_PAD_LENGTH, dwKeyMaterialLength);
  1837. // TRACE1 (EAPOL, "ElKeyReceivePerSTA: Randomlength = %ld",
  1838. // dwRandomLength);
  1839. // TRACE0 (EAPOL, "ElKeyReceivePerSTA: ========= The random material is ============= ");
  1840. // EAPOL_DUMPBA (pEapolKeyMaterial->KeyMaterial, dwRandomLength);
  1841. }
  1842. else
  1843. {
  1844. // No random material sent
  1845. TRACE0 (EAPOL, "ElKeyReceivePerSTA: Did not find random material: Exiting");
  1846. dwRetCode = ERROR_INVALID_PARAMETER;
  1847. break;
  1848. }
  1849. if (fIsUnicastKey)
  1850. {
  1851. TRACE0 (EAPOL, "ElKeyReceivePerSTA: Received Per-STA Unicast key material Random");
  1852. // Generate dynamic keys
  1853. if (dwRetCode = GenerateDynamicKeys (
  1854. pbMasterSecretSend,
  1855. dwMasterSecretSendLength,
  1856. pEapolKeyMaterial->KeyMaterial,
  1857. dwRandomLength,
  1858. dwDynamicKeyLength,
  1859. &NewSessionKeys
  1860. ) != NO_ERROR)
  1861. {
  1862. TRACE1 (EAPOL, "ElKeyReceivePerSTA: ElGenerateDynamicKeys failed with error %ld",
  1863. dwRetCode);
  1864. break;
  1865. }
  1866. pbDynamicSendKey = NewSessionKeys.bSendKey;
  1867. pbDynamicRecvKey = NewSessionKeys.bReceiveKey;
  1868. // TRACE0 (EAPOL, "ElKeyReceivePerSTA: Derived Send Key");
  1869. // EAPOL_DUMPBA (pbDynamicSendKey, dwDynamicKeyLength);
  1870. // TRACE0 (EAPOL, "ElKeyReceivePerSTA: Derived Recv Key");
  1871. // EAPOL_DUMPBA (pbDynamicRecvKey, dwDynamicKeyLength);
  1872. // Update Master Secrets
  1873. if (dwRetCode = ElSetMasterKeys (
  1874. pPCB,
  1875. &NewSessionKeys
  1876. ) != NO_ERROR)
  1877. {
  1878. // Cannot do much about this error than proceed
  1879. TRACE1 (EAPOL, "ElKeyReceivePerSTA: ElSetMasterKeys failed with error %ld",
  1880. dwRetCode);
  1881. dwRetCode = NO_ERROR;
  1882. }
  1883. pbKeyToBePlumbed = pbDynamicSendKey;
  1884. }
  1885. else
  1886. {
  1887. TRACE0 (EAPOL, "ElKeyReceivePerSTA: Received Per-STA BROADCAST key material");
  1888. if (dwRandomLength != dwDynamicKeyLength)
  1889. {
  1890. TRACE2 (EAPOL, "ElKeyReceivePerSTA: KeyLength (%ld) != KeyMaterialLength (%ld), Inconsistent. Will consider only KeyMaterial length !",
  1891. dwDynamicKeyLength, dwRandomLength);
  1892. }
  1893. dwDynamicKeyLength = dwRandomLength;
  1894. pbKeyToBePlumbed = pEapolKeyMaterial->KeyMaterial;
  1895. }
  1896. if ((pNdisWEPKey = MALLOC ( sizeof(NDIS_802_11_WEP)-1+dwDynamicKeyLength ))
  1897. == NULL)
  1898. {
  1899. TRACE0 (EAPOL, "ElKeyReceivePerSTA: MALLOC failed for pNdisWEPKey");
  1900. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  1901. break;
  1902. }
  1903. pNdisWEPKey->Length = sizeof(NDIS_802_11_WEP) - 1 + dwDynamicKeyLength;
  1904. memcpy ((BYTE *)pNdisWEPKey->KeyMaterial, (BYTE *)pbKeyToBePlumbed,
  1905. dwDynamicKeyLength);
  1906. pNdisWEPKey->KeyLength = dwDynamicKeyLength;
  1907. // Create the long index out of the byte index got from AP
  1908. // If MSB in byte is set, set MSB in ulong format
  1909. if (pKeyDesc->KeyIndex & 0x80)
  1910. {
  1911. pNdisWEPKey->KeyIndex = 0x80000000;
  1912. }
  1913. else
  1914. {
  1915. pNdisWEPKey->KeyIndex = 0x00000000;
  1916. }
  1917. pNdisWEPKey->KeyIndex |= (pKeyDesc->KeyIndex & 0x03);
  1918. // Use NDISUIO to plumb the key to the driver
  1919. if ((dwRetCode = ElNdisuioSetOIDValue (
  1920. pPCB->hPort,
  1921. OID_802_11_ADD_WEP,
  1922. (BYTE *)pNdisWEPKey,
  1923. pNdisWEPKey->Length)) != NO_ERROR)
  1924. {
  1925. TRACE1 (PORT, "ElKeyReceivePerSTA: ElNdisuioSetOIDValue failed with error %ld",
  1926. dwRetCode);
  1927. }
  1928. }
  1929. while (FALSE);
  1930. if (dwRetCode != NO_ERROR)
  1931. {
  1932. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB,
  1933. EAPOL_ERROR_PROCESSING_EAPOL_KEY, dwRetCode);
  1934. }
  1935. if (pbMD5EapolPkt != NULL)
  1936. {
  1937. FREE (pbMD5EapolPkt);
  1938. pbMD5EapolPkt = NULL;
  1939. }
  1940. if (pNdisWEPKey != NULL)
  1941. {
  1942. FREE (pNdisWEPKey);
  1943. pNdisWEPKey = NULL;
  1944. }
  1945. if (pbPaddedKeyMaterial != NULL)
  1946. {
  1947. FREE (pbPaddedKeyMaterial);
  1948. }
  1949. TRACE1 (EAPOL, "ElKeyReceivePerSTA completed for port %ws", pPCB->pwszFriendlyName);
  1950. return dwRetCode;
  1951. }
  1952. #endif
  1953. //
  1954. // ElTimeoutCallbackRoutine
  1955. //
  1956. // Description:
  1957. //
  1958. // Function called when any timer work item queued on the global timer
  1959. // queue expires. Depending on the state in which the port is when the timer
  1960. // expires, the port moves to the next state.
  1961. //
  1962. // Arguments:
  1963. // pvContext - Pointer to context. In this case, it is pointer to a PCB
  1964. // fTimerOfWaitFired - Unused
  1965. //
  1966. // Return values:
  1967. //
  1968. VOID
  1969. ElTimeoutCallbackRoutine (
  1970. IN PVOID pvContext,
  1971. IN BOOLEAN fTimerOfWaitFired
  1972. )
  1973. {
  1974. EAPOL_PCB *pPCB;
  1975. TRACE0 (EAPOL, "ElTimeoutCallbackRoutine entered");
  1976. do
  1977. {
  1978. // Context should not be NULL
  1979. if (pvContext == NULL)
  1980. {
  1981. TRACE0 (EAPOL, "ElTimeoutCallbackRoutine: pvContext is NULL. Invalid timeout callback");
  1982. break;
  1983. }
  1984. // PCB is guaranteed to exist until all timers are fired
  1985. // Verify if Port is still active
  1986. pPCB = (EAPOL_PCB *)pvContext;
  1987. ACQUIRE_WRITE_LOCK (&(pPCB->rwLock));
  1988. if (!EAPOL_PORT_ACTIVE(pPCB))
  1989. {
  1990. // Port is not active
  1991. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  1992. TRACE1 (PORT, "ElTimeoutCallbackRoutine: Port %ws is inactive",
  1993. pPCB->pwszDeviceGUID);
  1994. break;
  1995. }
  1996. DbLogPCBEvent (DBLOG_CATEG_INFO, pPCB, EAPOL_STATE_TIMEOUT,
  1997. EAPOLStates[((pPCB->State < EAPOLSTATE_LOGOFF) || (pPCB->State > EAPOLSTATE_AUTHENTICATED))?EAPOLSTATE_UNDEFINED:pPCB->State]);
  1998. // Check the current state of the state machine
  1999. // We can do additional checks such as flagging which timer was fired
  2000. // and in the timeout checking if the PCB state has remained the same
  2001. // Else bail out
  2002. switch (pPCB->State)
  2003. {
  2004. case EAPOLSTATE_CONNECTING:
  2005. if (!EAPOL_START_TIMER_SET(pPCB))
  2006. {
  2007. TRACE1 (EAPOL, "ElTimeoutCallbackRoutine: Wrong timeout %ld in Connecting state", CHECK_EAPOL_TIMER(pPCB));
  2008. break;
  2009. }
  2010. pPCB->dwTimerFlags &= ~EAPOL_START_TIMER;
  2011. FSMConnecting(pPCB, NULL);
  2012. break;
  2013. case EAPOLSTATE_ACQUIRED:
  2014. if (!EAPOL_AUTH_TIMER_SET(pPCB))
  2015. {
  2016. TRACE1 (EAPOL, "ElTimeoutCallbackRoutine: Wrong timeout %ld in Acquired state", CHECK_EAPOL_TIMER(pPCB));
  2017. break;
  2018. }
  2019. pPCB->dwTimerFlags &= ~EAPOL_AUTH_TIMER;
  2020. FSMConnecting(pPCB, NULL);
  2021. break;
  2022. case EAPOLSTATE_AUTHENTICATING:
  2023. if (!EAPOL_AUTH_TIMER_SET(pPCB))
  2024. {
  2025. TRACE1 (EAPOL, "ElTimeoutCallbackRoutine: Wrong timeout %ld in Authenticating state", CHECK_EAPOL_TIMER(pPCB));
  2026. break;
  2027. }
  2028. pPCB->dwTimerFlags &= ~EAPOL_AUTH_TIMER;
  2029. FSMConnecting(pPCB, NULL);
  2030. break;
  2031. case EAPOLSTATE_AUTHENTICATED:
  2032. if (!EAPOL_TRANSMIT_KEY_TIMER_SET(pPCB))
  2033. {
  2034. TRACE1 (EAPOL, "ElTimeoutCallbackRoutine: Wrong timeout %ld in Authenticated state", CHECK_EAPOL_TIMER(pPCB));
  2035. break;
  2036. }
  2037. pPCB->dwTimerFlags &= ~EAPOL_TRANSMIT_KEY_TIMER;
  2038. ElVerifyEAPOLKeyReceived(pPCB);
  2039. break;
  2040. case EAPOLSTATE_HELD:
  2041. if (!EAPOL_HELD_TIMER_SET(pPCB))
  2042. {
  2043. TRACE1 (EAPOL, "ElTimeoutCallbackRoutine: Wrong timeout %ld in Held state", CHECK_EAPOL_TIMER(pPCB));
  2044. break;
  2045. }
  2046. // Go through logoff, since new user will be tried
  2047. // for next cycle
  2048. // Debatable !
  2049. if (!(pPCB->dwAuthFailCount % EAPOL_MAX_AUTH_FAIL_COUNT))
  2050. {
  2051. // FSMLogoff (pPCB, NULL);
  2052. }
  2053. FSMConnecting(pPCB, NULL);
  2054. break;
  2055. case EAPOLSTATE_DISCONNECTED:
  2056. TRACE0 (EAPOL, "ElTimeoutCallbackRoutine: No action in Disconnected state");
  2057. break;
  2058. case EAPOLSTATE_LOGOFF:
  2059. TRACE0 (EAPOL, "ElTimeoutCallbackRoutine: No action in Logoff state");
  2060. break;
  2061. default:
  2062. TRACE0 (EAPOL, "ElTimeoutCallbackRoutine: Critical Error. Invalid state after timer expires ");
  2063. break;
  2064. }
  2065. RELEASE_WRITE_LOCK (&(pPCB->rwLock));
  2066. } while (FALSE);
  2067. TRACE0 (EAPOL, "ElTimeoutCallbackRoutine completed");
  2068. return;
  2069. }
  2070. //
  2071. // ElEapWork
  2072. //
  2073. // Description:
  2074. //
  2075. // Function called when an EAPOL packet of type EAP_Packet is received
  2076. // The EAP packet is passed to the EAP module for processing.
  2077. // Depending on the result of the processing, a EAP Response packet
  2078. // is sent or the incoming packet is ignored.
  2079. //
  2080. // Input arguments:
  2081. // pPCB - Pointer to PCB for the port on which data is being processed
  2082. // pRecvPkt - Pointer to EAP packet in the data received from the remote end
  2083. //
  2084. // Return values:
  2085. // NO_ERROR - success
  2086. // non-zero - error
  2087. //
  2088. //
  2089. // ISSUE: Rewrite with do {} while(FALSE)
  2090. //
  2091. DWORD
  2092. ElEapWork (
  2093. IN EAPOL_PCB *pPCB,
  2094. IN PPP_EAP_PACKET *pRecvPkt
  2095. )
  2096. {
  2097. DWORD dwLength = 0;
  2098. ELEAP_RESULT EapResult;
  2099. PPP_EAP_PACKET *pSendPkt;
  2100. EAPOL_PACKET *pEapolPkt;
  2101. GUID DeviceGuid;
  2102. DWORD dwReceivedId = 0;
  2103. DWORD cbData = 0;
  2104. BYTE *pbAuthData = NULL;
  2105. DWORD dwRetCode = NO_ERROR;
  2106. //
  2107. // If the protocol has not been started yet, call ElEapBegin
  2108. //
  2109. if (!(pPCB->fEapInitialized))
  2110. {
  2111. if ((dwRetCode = ElEapBegin (pPCB)) != NO_ERROR)
  2112. {
  2113. TRACE1 (EAPOL, "ElEapWork: Error in ElEapBegin = %ld", dwRetCode);
  2114. return dwRetCode;
  2115. }
  2116. }
  2117. ZeroMemory(&EapResult, sizeof(EapResult));
  2118. // Create buffer for EAPOL + EAP and pass pointer to EAP header
  2119. pEapolPkt = (EAPOL_PACKET *) MALLOC (MAX_EAPOL_BUFFER_SIZE);
  2120. TRACE1 (EAPOL, "ElEapWork: EapolPkt created at %p", pEapolPkt);
  2121. if (pEapolPkt == NULL)
  2122. {
  2123. TRACE0 (EAPOL, "ElEapWork: Error allocating EAP buffer");
  2124. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  2125. return dwRetCode;
  2126. }
  2127. // Point to EAP header
  2128. pSendPkt = (PPP_EAP_PACKET *)((PBYTE)pEapolPkt + sizeof (EAPOL_PACKET) - 1);
  2129. if (pRecvPkt != NULL)
  2130. {
  2131. dwReceivedId = pRecvPkt->Id;
  2132. }
  2133. dwRetCode = ElEapMakeMessage (pPCB,
  2134. pRecvPkt,
  2135. pSendPkt,
  2136. MAX_EAPOL_BUFFER_SIZE
  2137. - sizeof(EAPOL_PACKET) - 1,
  2138. &EapResult
  2139. );
  2140. // Notification message for the user
  2141. if (NULL != EapResult.pszReplyMessage)
  2142. {
  2143. // Free earlier notication with the PCB
  2144. if (pPCB->pwszEapReplyMessage != NULL)
  2145. {
  2146. FREE (pPCB->pwszEapReplyMessage);
  2147. pPCB->pwszEapReplyMessage = NULL;
  2148. }
  2149. pPCB->pwszEapReplyMessage =
  2150. (WCHAR *)MALLOC ((strlen(EapResult.pszReplyMessage)+1) * sizeof(WCHAR));
  2151. if (pPCB->pwszEapReplyMessage == NULL)
  2152. {
  2153. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  2154. TRACE0 (EAPOL, "ElEapWork: MALLOC failed for pwszEapReplyMessage");
  2155. FREE (EapResult.pszReplyMessage);
  2156. FREE (pEapolPkt);
  2157. pEapolPkt = NULL;
  2158. return dwRetCode;
  2159. }
  2160. if (0 == MultiByteToWideChar (
  2161. CP_ACP,
  2162. 0,
  2163. EapResult.pszReplyMessage,
  2164. -1,
  2165. pPCB->pwszEapReplyMessage,
  2166. strlen(EapResult.pszReplyMessage)+1))
  2167. {
  2168. dwRetCode = GetLastError();
  2169. TRACE2 (EAPOL,"ElEapWork: MultiByteToWideChar(%s) failed for pwszEapReplyMessage with error (%ld)",
  2170. EapResult.pszReplyMessage,
  2171. dwRetCode);
  2172. FREE (EapResult.pszReplyMessage);
  2173. FREE (pEapolPkt);
  2174. pEapolPkt = NULL;
  2175. return dwRetCode;
  2176. }
  2177. ElNetmanNotify (pPCB, EAPOL_NCS_NOTIFICATION, NULL);
  2178. TRACE1 (EAPOL, "ElEapWork: Notified user of EAP data = %ws",
  2179. pPCB->pwszEapReplyMessage);
  2180. FREE (EapResult.pszReplyMessage);
  2181. }
  2182. if (dwRetCode != NO_ERROR)
  2183. {
  2184. switch (dwRetCode)
  2185. {
  2186. case ERROR_PPP_INVALID_PACKET:
  2187. TRACE0 (EAPOL, "ElEapWork: Silently discarding invalid auth packet");
  2188. break;
  2189. default:
  2190. TRACE1 (EAPOL, "ElEapWork: ElEapMakeMessage returned error %ld",
  2191. dwRetCode);
  2192. // NotifyCallerOfFailure (pPCB, dwRetCode);
  2193. break;
  2194. }
  2195. // Free up memory reserved for packet
  2196. FREE (pEapolPkt);
  2197. pEapolPkt = NULL;
  2198. return dwRetCode;
  2199. }
  2200. //
  2201. // Check to see if we have to save any user data
  2202. //
  2203. if (EapResult.fSaveUserData)
  2204. {
  2205. // Save to Registry
  2206. if ((dwRetCode = ElSetEapUserInfo (
  2207. pPCB->hUserToken,
  2208. pPCB->pwszDeviceGUID,
  2209. pPCB->dwEapTypeToBeUsed,
  2210. (pPCB->pSSID)?pPCB->pSSID->SsidLength:0,
  2211. (pPCB->pSSID)?pPCB->pSSID->Ssid:NULL,
  2212. EapResult.pUserData,
  2213. EapResult.dwSizeOfUserData)) != NO_ERROR)
  2214. {
  2215. TRACE1 (EAPOL, "ElEapWork: ElSetEapUserInfo failed with error = %d",
  2216. dwRetCode);
  2217. if (pEapolPkt != NULL)
  2218. {
  2219. FREE (pEapolPkt);
  2220. pEapolPkt = NULL;
  2221. }
  2222. return dwRetCode;
  2223. }
  2224. // Save to PCB context
  2225. if (pPCB->pCustomAuthUserData != NULL)
  2226. {
  2227. FREE (pPCB->pCustomAuthUserData);
  2228. pPCB->pCustomAuthUserData = NULL;
  2229. }
  2230. pPCB->pCustomAuthUserData = MALLOC (EapResult.dwSizeOfUserData + sizeof (DWORD));
  2231. if (pPCB->pCustomAuthUserData == NULL)
  2232. {
  2233. TRACE1 (EAPOL, "ElEapWork: Error in allocating memory for pCustomAuthUserData = %ld",
  2234. dwRetCode);
  2235. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  2236. return dwRetCode;
  2237. }
  2238. pPCB->pCustomAuthUserData->dwSizeOfCustomAuthData = EapResult.dwSizeOfUserData;
  2239. if ((EapResult.dwSizeOfUserData != 0) && (EapResult.pUserData != NULL))
  2240. {
  2241. memcpy ((BYTE *)pPCB->pCustomAuthUserData->pbCustomAuthData,
  2242. (BYTE *)EapResult.pUserData,
  2243. EapResult.dwSizeOfUserData);
  2244. }
  2245. TRACE0 (EAPOL, "ElEapWork: Saved EAP data for user");
  2246. }
  2247. //
  2248. // Check to see if we have to save any connection data
  2249. //
  2250. pbAuthData = EapResult.SetCustomAuthData.pConnectionData;
  2251. cbData = EapResult.SetCustomAuthData.dwSizeOfConnectionData;
  2252. if ((EapResult.fSaveConnectionData ) &&
  2253. ( 0 != cbData ) )
  2254. {
  2255. // Save to registry
  2256. if ((dwRetCode = ElSetCustomAuthData (
  2257. pPCB->pwszDeviceGUID,
  2258. pPCB->dwEapTypeToBeUsed,
  2259. (pPCB->pSSID)?pPCB->pSSID->SsidLength:0,
  2260. (pPCB->pSSID)?pPCB->pSSID->Ssid:NULL,
  2261. pbAuthData,
  2262. &cbData
  2263. )) != NO_ERROR)
  2264. {
  2265. TRACE1 ( EAPOL, "ElEapWork: ElSetCustomAuthData failed with error = %d",
  2266. dwRetCode);
  2267. FREE (pEapolPkt);
  2268. pEapolPkt = NULL;
  2269. return dwRetCode;
  2270. }
  2271. // Save to PCB context
  2272. if (pPCB->pCustomAuthConnData != NULL)
  2273. {
  2274. FREE (pPCB->pCustomAuthConnData);
  2275. pPCB->pCustomAuthConnData = NULL;
  2276. }
  2277. pPCB->pCustomAuthConnData = MALLOC (cbData + sizeof (DWORD));
  2278. if (pPCB->pCustomAuthConnData == NULL)
  2279. {
  2280. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  2281. TRACE1 (EAPOL, "ElEapWork: Error in allocating memory for pCustomAuthConnData = %ld",
  2282. dwRetCode);
  2283. return dwRetCode;
  2284. }
  2285. pPCB->pCustomAuthConnData->dwSizeOfCustomAuthData = cbData;
  2286. if ((cbData != 0) && (pbAuthData != NULL))
  2287. {
  2288. memcpy ((BYTE *)pPCB->pCustomAuthConnData->pbCustomAuthData,
  2289. (BYTE *)pbAuthData,
  2290. cbData);
  2291. }
  2292. TRACE0 (EAPOL, "ElEapWork: Saved EAP data for connection");
  2293. }
  2294. switch( EapResult.Action )
  2295. {
  2296. case ELEAP_Send:
  2297. case ELEAP_SendAndDone:
  2298. // Send out EAPOL packet
  2299. memcpy ((BYTE *)pEapolPkt->EthernetType,
  2300. (BYTE *)pPCB->bEtherType,
  2301. SIZE_ETHERNET_TYPE);
  2302. pEapolPkt->ProtocolVersion = pPCB->bProtocolVersion;
  2303. pEapolPkt->PacketType = EAP_Packet;
  2304. // The EAP packet length is in the packet returned back by
  2305. // the Dll MakeMessage
  2306. // In case of Notification and Identity Response, it is in
  2307. // EapResult.wSizeOfEapPkt
  2308. if (EapResult.wSizeOfEapPkt == 0)
  2309. {
  2310. EapResult.wSizeOfEapPkt =
  2311. WireToHostFormat16 (pSendPkt->Length);
  2312. }
  2313. HostToWireFormat16 ((WORD) EapResult.wSizeOfEapPkt,
  2314. (BYTE *)pEapolPkt->PacketBodyLength);
  2315. // Make a copy of the EAPOL packet in the PCB
  2316. // Will be used during retransmission
  2317. if (pPCB->pbPreviousEAPOLPkt != NULL)
  2318. {
  2319. FREE (pPCB->pbPreviousEAPOLPkt);
  2320. pPCB->pbPreviousEAPOLPkt = NULL;
  2321. }
  2322. pPCB->pbPreviousEAPOLPkt =
  2323. MALLOC (sizeof (EAPOL_PACKET)+EapResult.wSizeOfEapPkt-1);
  2324. if (pPCB->pbPreviousEAPOLPkt == NULL)
  2325. {
  2326. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  2327. TRACE0 (EAPOL, "ElEapWork: MALLOC failed for pbPreviousEAPOLPkt");
  2328. if (pEapolPkt != NULL)
  2329. {
  2330. FREE (pEapolPkt);
  2331. pEapolPkt = NULL;
  2332. }
  2333. return dwRetCode;
  2334. }
  2335. memcpy (pPCB->pbPreviousEAPOLPkt, pEapolPkt,
  2336. sizeof (EAPOL_PACKET)+EapResult.wSizeOfEapPkt-1);
  2337. pPCB->dwSizeOfPreviousEAPOLPkt =
  2338. sizeof (EAPOL_PACKET)+EapResult.wSizeOfEapPkt-1;
  2339. pPCB->dwPreviousId = dwReceivedId;
  2340. // Send packet out on the port
  2341. dwRetCode = ElWriteToPort (pPCB,
  2342. (CHAR *)pEapolPkt,
  2343. sizeof (EAPOL_PACKET)+EapResult.wSizeOfEapPkt-1);
  2344. if (dwRetCode != NO_ERROR)
  2345. {
  2346. TRACE1 (EAPOL, "ElEapWork: Error in writing EAP_Packet to port %ld",
  2347. dwRetCode);
  2348. if (pEapolPkt != NULL)
  2349. {
  2350. FREE (pEapolPkt);
  2351. pEapolPkt = NULL;
  2352. }
  2353. return dwRetCode;
  2354. }
  2355. if (pEapolPkt != NULL)
  2356. {
  2357. FREE (pEapolPkt);
  2358. pEapolPkt = NULL;
  2359. }
  2360. // More processing to be done?
  2361. // Supplicant side should not ever receive ELEAP_SendAndDone
  2362. // result code
  2363. if (EapResult.Action != ELEAP_SendAndDone)
  2364. {
  2365. break;
  2366. }
  2367. else
  2368. {
  2369. TRACE0 (EAPOL, "ElEapWork: ELEAP_SendAndDone wrong result received");
  2370. }
  2371. case ELEAP_Done:
  2372. // Retrieve MPPE keys from the attributes information
  2373. // returned by EAP-TLS
  2374. switch (EapResult.dwError)
  2375. {
  2376. case NO_ERROR:
  2377. TRACE0 (EAPOL, "ElEapWork: Authentication was successful");
  2378. pPCB->fLocalEAPAuthSuccess = TRUE;
  2379. //
  2380. // If authentication was successful
  2381. //
  2382. dwRetCode = ElExtractMPPESendRecvKeys (
  2383. pPCB,
  2384. EapResult.pUserAttributes,
  2385. (BYTE*)&(EapResult.abChallenge),
  2386. (BYTE*)&(EapResult.abResponse));
  2387. if (dwRetCode != NO_ERROR)
  2388. {
  2389. FREE (pEapolPkt);
  2390. //NotifyCallerOfFailure (pPcb, dwRetCode);
  2391. return dwRetCode;
  2392. }
  2393. // ISSUE:
  2394. // Do we want to retain UserAttributes
  2395. // pPCB->pAuthProtocolAttributes = EapResult.pUserAttributes;
  2396. break;
  2397. default:
  2398. if (pEapolPkt != NULL)
  2399. {
  2400. FREE (pEapolPkt);
  2401. pEapolPkt = NULL;
  2402. }
  2403. TRACE0 (EAPOL, "ElEapWork: Authentication FAILED");
  2404. pPCB->dwLocalEAPAuthResult = EapResult.dwError;
  2405. break;
  2406. }
  2407. // Free memory allocated for the packet, since no response
  2408. // is going to be sent out
  2409. if (pEapolPkt != NULL)
  2410. {
  2411. FREE (pEapolPkt);
  2412. pEapolPkt = NULL;
  2413. }
  2414. break;
  2415. case ELEAP_NoAction:
  2416. // Free memory allocated for the packet, since nothing
  2417. // is being done with it
  2418. if (pEapolPkt != NULL)
  2419. {
  2420. FREE (pEapolPkt);
  2421. pEapolPkt = NULL;
  2422. }
  2423. break;
  2424. default:
  2425. break;
  2426. }
  2427. if (pEapolPkt != NULL)
  2428. {
  2429. FREE (pEapolPkt);
  2430. pEapolPkt = NULL;
  2431. }
  2432. //
  2433. // Check to see if we have to bring up the InteractiveUI for EAP
  2434. // i.e. Server cert confirmation etc.
  2435. //
  2436. if (EapResult.fInvokeEapUI)
  2437. {
  2438. ElInvokeInteractiveUI (pPCB, &(EapResult.InvokeEapUIData));
  2439. }
  2440. return dwRetCode;
  2441. }
  2442. //
  2443. //
  2444. // ElExtractMPPESendRecvKeys
  2445. //
  2446. // Description:
  2447. // Function called if authentication was successful. The MPPE Send &
  2448. // Recv keys are extracted from the RAS_AUTH_ATTRIBUTE passed from
  2449. // the EAP DLL and stored in the PCB. The keys are used to decrypt
  2450. // the multicast WEP key and also are used for media-based encrypting.
  2451. //
  2452. // Return values
  2453. //
  2454. // NO_ERROR - Success
  2455. // Non-zero - Failure
  2456. //
  2457. DWORD
  2458. ElExtractMPPESendRecvKeys (
  2459. IN EAPOL_PCB *pPCB,
  2460. IN RAS_AUTH_ATTRIBUTE * pUserAttributes,
  2461. IN BYTE * pChallenge,
  2462. IN BYTE * pResponse
  2463. )
  2464. {
  2465. RAS_AUTH_ATTRIBUTE * pAttribute;
  2466. RAS_AUTH_ATTRIBUTE * pAttributeSendKey;
  2467. RAS_AUTH_ATTRIBUTE * pAttributeRecvKey;
  2468. DWORD dwRetCode = NO_ERROR;
  2469. DWORD dwEncryptionPolicy = 0;
  2470. DWORD dwEncryptionTypes = 0;
  2471. do
  2472. {
  2473. pAttribute = ElAuthAttributeGetVendorSpecific (
  2474. 311, 12, pUserAttributes);
  2475. pAttributeSendKey = ElAuthAttributeGetVendorSpecific ( 311, 16,
  2476. pUserAttributes);
  2477. pAttributeRecvKey = ElAuthAttributeGetVendorSpecific ( 311, 17,
  2478. pUserAttributes);
  2479. if ((pAttributeSendKey != NULL)
  2480. && (pAttributeRecvKey != NULL))
  2481. {
  2482. // Set the MS-MPPE-Send-Key and MS-MPPE-Recv-Key with
  2483. // the ethernet driver
  2484. ULONG ulSendKeyLength = 0;
  2485. ULONG ulRecvKeyLength = 0;
  2486. // Based on PPP code
  2487. ulSendKeyLength = *(((BYTE*)(pAttributeSendKey->Value))+8);
  2488. ulRecvKeyLength = *(((BYTE*)(pAttributeRecvKey->Value))+8);
  2489. // TRACE0 (EAPOL, "Send key = ");
  2490. // EAPOL_DUMPBA (((BYTE*)(pAttributeSendKey->Value))+9,
  2491. // ulSendKeyLength);
  2492. // TRACE0 (EAPOL, "Recv key = ");
  2493. // EAPOL_DUMPBA (((BYTE*)(pAttributeRecvKey->Value))+9,
  2494. // ulRecvKeyLength);
  2495. //
  2496. // Copy MPPE Send and Receive Keys into the PCB for later usage
  2497. // These keys will be used to decrypt keys sent by NAS (if any).
  2498. // Save the keys as the MasterSecret for dynamic rekeying (if any).
  2499. //
  2500. if (ulSendKeyLength != 0)
  2501. {
  2502. if (pPCB->MasterSecretSend.cbData != 0)
  2503. {
  2504. FREE (pPCB->MasterSecretSend.pbData);
  2505. pPCB->MasterSecretSend.cbData = 0;
  2506. pPCB->MasterSecretSend.pbData = NULL;
  2507. }
  2508. if ((dwRetCode = ElSecureEncodePw (
  2509. ((BYTE*)(pAttributeSendKey->Value))+9,
  2510. ulSendKeyLength,
  2511. &(pPCB->MasterSecretSend)
  2512. )) != NO_ERROR)
  2513. {
  2514. TRACE1 (EAPOL, "ElExtractMPPESendRecvKeys: ElSecureEncodePw for Master Send failed with error %ld",
  2515. dwRetCode);
  2516. break;
  2517. }
  2518. if (pPCB->MPPESendKey.cbData != 0)
  2519. {
  2520. FREE (pPCB->MPPESendKey.pbData);
  2521. pPCB->MPPESendKey.cbData = 0;
  2522. pPCB->MPPESendKey.pbData = NULL;
  2523. }
  2524. if ((dwRetCode = ElSecureEncodePw (
  2525. ((BYTE*)(pAttributeSendKey->Value))+9,
  2526. ulSendKeyLength,
  2527. &(pPCB->MPPESendKey)
  2528. )) != NO_ERROR)
  2529. {
  2530. TRACE1 (EAPOL, "ElExtractMPPESendRecvKeys: ElSecureEncodePw for MPPESend failed with error %ld",
  2531. dwRetCode);
  2532. break;
  2533. }
  2534. }
  2535. if (ulRecvKeyLength != 0)
  2536. {
  2537. if (pPCB->MasterSecretRecv.cbData != 0)
  2538. {
  2539. FREE (pPCB->MasterSecretRecv.pbData);
  2540. pPCB->MasterSecretRecv.cbData = 0;
  2541. pPCB->MasterSecretRecv.pbData = NULL;
  2542. }
  2543. if ((dwRetCode = ElSecureEncodePw (
  2544. ((BYTE*)(pAttributeRecvKey->Value))+9,
  2545. ulRecvKeyLength,
  2546. &(pPCB->MasterSecretRecv)
  2547. )) != NO_ERROR)
  2548. {
  2549. TRACE1 (EAPOL, "ElExtractMPPESendRecvKeys: ElSecureEncodePw for Master Recv failed with error %ld",
  2550. dwRetCode);
  2551. break;
  2552. }
  2553. if (pPCB->MPPERecvKey.cbData != 0)
  2554. {
  2555. FREE (pPCB->MPPERecvKey.pbData);
  2556. pPCB->MPPERecvKey.cbData = 0;
  2557. pPCB->MPPERecvKey.pbData = NULL;
  2558. }
  2559. if ((dwRetCode = ElSecureEncodePw (
  2560. ((BYTE*)(pAttributeRecvKey->Value))+9,
  2561. ulRecvKeyLength,
  2562. &(pPCB->MPPERecvKey)
  2563. )) != NO_ERROR)
  2564. {
  2565. TRACE1 (EAPOL, "ElExtractMPPESendRecvKeys: ElSecureEncodePw for MPPERecv failed with error %ld",
  2566. dwRetCode);
  2567. break;
  2568. }
  2569. }
  2570. TRACE0 (EAPOL,"MPPE-Send/Recv-Keys derived by supplicant");
  2571. }
  2572. else
  2573. {
  2574. TRACE0 (EAPOL, "ElExtractMPPESendRecvKeys: pAttributeSendKey or pAttributeRecvKey == NULL");
  2575. }
  2576. } while (FALSE);
  2577. if (dwRetCode != NO_ERROR)
  2578. {
  2579. if (pPCB->MasterSecretSend.cbData != 0)
  2580. {
  2581. FREE (pPCB->MasterSecretSend.pbData);
  2582. pPCB->MasterSecretSend.cbData = 0;
  2583. pPCB->MasterSecretSend.pbData = NULL;
  2584. }
  2585. if (pPCB->MasterSecretRecv.cbData != 0)
  2586. {
  2587. FREE (pPCB->MasterSecretRecv.pbData);
  2588. pPCB->MasterSecretRecv.cbData = 0;
  2589. pPCB->MasterSecretRecv.pbData = NULL;
  2590. }
  2591. if (pPCB->MPPESendKey.cbData != 0)
  2592. {
  2593. FREE (pPCB->MPPESendKey.pbData);
  2594. pPCB->MPPESendKey.cbData = 0;
  2595. pPCB->MPPESendKey.pbData = NULL;
  2596. }
  2597. if (pPCB->MPPERecvKey.cbData != 0)
  2598. {
  2599. FREE (pPCB->MPPERecvKey.pbData);
  2600. pPCB->MPPERecvKey.cbData = 0;
  2601. pPCB->MPPERecvKey.pbData = NULL;
  2602. }
  2603. }
  2604. return( dwRetCode );
  2605. }
  2606. //
  2607. // ElProcessEapSuccess
  2608. //
  2609. // Description:
  2610. //
  2611. // Function called when an EAP_Success is received in any state
  2612. //
  2613. // Input arguments:
  2614. // pPCB - Pointer to PCB for the port on which data is being processed
  2615. // pEapolPkt - Pointer to EAPOL packet that was received
  2616. //
  2617. // Return values:
  2618. // NO_ERROR - success
  2619. // non-zero - error
  2620. //
  2621. DWORD
  2622. ElProcessEapSuccess (
  2623. IN EAPOL_PCB *pPCB,
  2624. IN EAPOL_PACKET *pEapolPkt
  2625. )
  2626. {
  2627. EAPOL_ZC_INTF ZCData;
  2628. DWORD dwRetCode = NO_ERROR;
  2629. TRACE0 (EAPOL, "ElProcessEapSuccess: Got EAPCODE_Success");
  2630. do
  2631. {
  2632. // Indicate to EAP=Dll to cleanup completed session
  2633. if ((dwRetCode = ElEapEnd (pPCB)) != NO_ERROR)
  2634. {
  2635. TRACE1 (EAPOL, "ProcessReceivedPacket: EapSuccess: Error in ElEapEnd = %ld",
  2636. dwRetCode);
  2637. break;
  2638. }
  2639. TRACE0 (EAPOL, "ElProcessEapSuccess: Authentication successful");
  2640. // Complete remaining processing i.e. DHCP
  2641. if ((dwRetCode = FSMAuthenticated (pPCB,
  2642. pEapolPkt)) != NO_ERROR)
  2643. {
  2644. break;
  2645. }
  2646. #ifdef ZEROCONFIG_LINKED
  2647. // Indicate to WZC that authentication succeeded and
  2648. // reset the blob it stores for the current SSID
  2649. ZeroMemory ((PVOID)&ZCData, sizeof(EAPOL_ZC_INTF));
  2650. ZCData.dwAuthFailCount = 0;
  2651. ZCData.PreviousAuthenticationType = EAPOL_UNAUTHENTICATED_ACCESS;
  2652. if (pPCB->pSSID != NULL)
  2653. {
  2654. memcpy (ZCData.bSSID, pPCB->pSSID->Ssid, pPCB->pSSID->SsidLength);
  2655. ZCData.dwSizeOfSSID = pPCB->pSSID->SsidLength;
  2656. }
  2657. if ((dwRetCode = ElZeroConfigNotify (
  2658. pPCB->dwZeroConfigId,
  2659. WZCCMD_CFG_SETDATA,
  2660. pPCB->pwszDeviceGUID,
  2661. &ZCData
  2662. )) != NO_ERROR)
  2663. {
  2664. TRACE1 (EAPOL, "ElProcessEapSuccess: ElZeroConfigNotify failed with error %ld",
  2665. dwRetCode);
  2666. dwRetCode = NO_ERROR;
  2667. }
  2668. TRACE1 (EAPOL, "ElProcessEapSuccess: Called ElZeroConfigNotify with type=(%ld)",
  2669. WZCCMD_CFG_SETDATA);
  2670. #endif // ZEROCONFIG_LINKED
  2671. ElNetmanNotify (pPCB, EAPOL_NCS_AUTHENTICATION_SUCCEEDED, NULL);
  2672. }
  2673. while (FALSE);
  2674. return dwRetCode;
  2675. }
  2676. //
  2677. // ElProcessEapFail
  2678. //
  2679. // Description:
  2680. //
  2681. // Function called when an EAP_Fail is received in any state
  2682. //
  2683. // Input arguments:
  2684. // pPCB - Pointer to PCB for the port on which data is being processed
  2685. // pEapolPkt - Pointer to EAPOL packet that was received
  2686. //
  2687. // Return values:
  2688. // NO_ERROR - success
  2689. // non-zero - error
  2690. //
  2691. DWORD
  2692. ElProcessEapFail (
  2693. IN EAPOL_PCB *pPCB,
  2694. IN EAPOL_PACKET *pEapolPkt
  2695. )
  2696. {
  2697. EAPOL_ZC_INTF ZCData;
  2698. DWORD dwRetCode = NO_ERROR;
  2699. TRACE0 (EAPOL, "ElProcessEapFail: Got EAPCODE_Failure");
  2700. do
  2701. {
  2702. // Indicate to EAP-Dll to cleanup completed session
  2703. if ((dwRetCode = ElEapEnd (pPCB)) != NO_ERROR)
  2704. {
  2705. TRACE1 (EAPOL, "ElProcessEapFail: EapFail: Error in ElEapEnd = %ld",
  2706. dwRetCode);
  2707. break;
  2708. }
  2709. // Show failure balloon before notifying ZeroConfig
  2710. // ZeroConfig may require to pop-up its own balloon, and that has
  2711. // to be given preference
  2712. ElNetmanNotify (pPCB, EAPOL_NCS_AUTHENTICATION_FAILED, NULL);
  2713. #ifdef ZEROCONFIG_LINKED
  2714. // Indicate to WZC that authentication failed
  2715. ZeroMemory ((PVOID)&ZCData, sizeof(EAPOL_ZC_INTF));
  2716. ZCData.dwAuthFailCount = pPCB->dwAuthFailCount + 1;
  2717. ZCData.PreviousAuthenticationType = pPCB->PreviousAuthenticationType;
  2718. if (pPCB->pSSID != NULL)
  2719. {
  2720. memcpy (ZCData.bSSID, pPCB->pSSID->Ssid, pPCB->pSSID->SsidLength);
  2721. ZCData.dwSizeOfSSID = pPCB->pSSID->SsidLength;
  2722. }
  2723. // We notify ZC before going through held state, where fail count is
  2724. // upped. Hence, here we explicitly up it by one
  2725. if ((dwRetCode = ElZeroConfigNotify (
  2726. pPCB->dwZeroConfigId,
  2727. ((pPCB->dwAuthFailCount+1) < pPCB->dwTotalMaxAuthFailCount)?WZCCMD_CFG_NEXT:WZCCMD_CFG_DELETE,
  2728. pPCB->pwszDeviceGUID,
  2729. &ZCData
  2730. )) != NO_ERROR)
  2731. {
  2732. TRACE1 (EAPOL, "ElProcessEapFail: ElZeroConfigNotify failed with error %ld",
  2733. dwRetCode);
  2734. dwRetCode = NO_ERROR;
  2735. }
  2736. TRACE3 (EAPOL, "ElProcessEapFail: Called ElZeroConfigNotify with failcount = %ld, prevauthtype = %ld, type=(%ld)",
  2737. ZCData.dwAuthFailCount,
  2738. ZCData.PreviousAuthenticationType,
  2739. ((pPCB->dwAuthFailCount+1) < pPCB->dwTotalMaxAuthFailCount)?WZCCMD_CFG_NEXT:WZCCMD_CFG_DELETE
  2740. );
  2741. #endif // ZEROCONFIG_LINKED
  2742. if ((dwRetCode = FSMHeld (pPCB, NULL)) != NO_ERROR)
  2743. {
  2744. break;
  2745. }
  2746. }
  2747. while (FALSE);
  2748. return dwRetCode;
  2749. }
  2750. //
  2751. // ElSetEAPOLKeyReceivedTimer
  2752. //
  2753. // Description:
  2754. //
  2755. // Function called for wireless interface when it enter AUTHENTICATED state
  2756. // If no EAPOL-Key message is received for the transmit key in the meanwhile
  2757. // the association should be negated to Zero-Config
  2758. //
  2759. // Input arguments:
  2760. // pPCB - Pointer to PCB for the port which entered AUTHENTICATED state
  2761. //
  2762. // Return values:
  2763. // NO_ERROR - success
  2764. // non-zero - error
  2765. //
  2766. DWORD
  2767. ElSetEAPOLKeyReceivedTimer (
  2768. IN EAPOL_PCB *pPCB
  2769. )
  2770. {
  2771. DWORD dwRetCode = NO_ERROR;
  2772. do
  2773. {
  2774. if (pPCB->fTransmitKeyReceived)
  2775. {
  2776. TRACE0 (EAPOL, "EAPOL-Key for transmit key received before entering AUTHENTICATED state");
  2777. break;
  2778. }
  2779. RESTART_TIMER (pPCB->hTimer,
  2780. EAPOL_TRANSMIT_KEY_INTERVAL,
  2781. "PCB",
  2782. &dwRetCode);
  2783. if (dwRetCode != NO_ERROR)
  2784. {
  2785. TRACE1 (EAPOL, "ElSetEAPOLKeyReceivedTimer: Error in RESTART_TIMER %ld",
  2786. dwRetCode);
  2787. break;
  2788. }
  2789. SET_TRANSMIT_KEY_TIMER(pPCB);
  2790. }
  2791. while (FALSE);
  2792. return dwRetCode;
  2793. }
  2794. //
  2795. // ElVerifyEAPOLKeyReceived
  2796. //
  2797. // Description:
  2798. //
  2799. // Function called on timeout to verify if EAPOL-transmit key was received
  2800. // If no EAPOL-Key message is received for the transmit key in the meanwhile
  2801. // the association should be negated to Zero-Config
  2802. //
  2803. // Input arguments:
  2804. // pPCB - Pointer to PCB for the port which entered AUTHENTICATED state
  2805. //
  2806. // Return values:
  2807. // NO_ERROR - success
  2808. // non-zero - error
  2809. //
  2810. DWORD
  2811. ElVerifyEAPOLKeyReceived (
  2812. IN EAPOL_PCB *pPCB
  2813. )
  2814. {
  2815. EAPOL_ZC_INTF ZCData;
  2816. DWORD dwRetCode = NO_ERROR;
  2817. do
  2818. {
  2819. if (!pPCB->fTransmitKeyReceived)
  2820. {
  2821. TRACE1 (EAPOL, "EAPOL-Key for transmit key *NOT* received within %ld seconds in AUTHENTICATED state",
  2822. EAPOL_TRANSMIT_KEY_INTERVAL
  2823. );
  2824. DbLogPCBEvent (DBLOG_CATEG_ERR, pPCB, EAPOL_NOT_RECEIVED_XMIT_KEY);
  2825. #ifdef ZEROCONFIG_LINKED
  2826. // Indicate to WZC that authentication didn't really complete
  2827. // since there was EAPOL-Key packet for the transmit key
  2828. // Fail the entire configuration
  2829. ZeroMemory ((PVOID)&ZCData, sizeof(EAPOL_ZC_INTF));
  2830. ZCData.dwAuthFailCount = pPCB->dwTotalMaxAuthFailCount;
  2831. pPCB->dwAuthFailCount = pPCB->dwTotalMaxAuthFailCount;
  2832. ZCData.PreviousAuthenticationType = pPCB->PreviousAuthenticationType;
  2833. if (pPCB->pSSID != NULL)
  2834. {
  2835. memcpy (ZCData.bSSID, pPCB->pSSID->Ssid, pPCB->pSSID->SsidLength);
  2836. ZCData.dwSizeOfSSID = pPCB->pSSID->SsidLength;
  2837. }
  2838. if ((dwRetCode = ElZeroConfigNotify (
  2839. pPCB->dwZeroConfigId,
  2840. ((pPCB->dwAuthFailCount) < pPCB->dwTotalMaxAuthFailCount)?WZCCMD_CFG_NEXT:WZCCMD_CFG_DELETE,
  2841. pPCB->pwszDeviceGUID,
  2842. &ZCData
  2843. )) != NO_ERROR)
  2844. {
  2845. TRACE1 (EAPOL, "ElVerifyEAPOLKeyReceived: ElZeroConfigNotify failed with error %ld",
  2846. dwRetCode);
  2847. dwRetCode = NO_ERROR;
  2848. }
  2849. TRACE3 (EAPOL, "ElVerifyEAPOLKeyReceived: Called ElZeroConfigNotify with failcount = %ld, prevauthtype = %ld, type=(%ld)",
  2850. ZCData.dwAuthFailCount,
  2851. ZCData.PreviousAuthenticationType,
  2852. ((pPCB->dwAuthFailCount+1) < pPCB->dwTotalMaxAuthFailCount)?WZCCMD_CFG_NEXT:WZCCMD_CFG_DELETE
  2853. );
  2854. // If authfailed limit reached, go to Disconnected state
  2855. if (pPCB->dwAuthFailCount >= pPCB->dwTotalMaxAuthFailCount)
  2856. {
  2857. TRACE2 (EAPOL, "ElVerifyEAPOLKeyReceived: Pushing into disconnected state: Fail count (%ld) > Max fail count (%ld)",
  2858. pPCB->dwAuthFailCount, pPCB->dwTotalMaxAuthFailCount);
  2859. FSMDisconnected (pPCB, NULL);
  2860. }
  2861. #endif // ZEROCONFIG_LINKED
  2862. }
  2863. else
  2864. {
  2865. TRACE1 (EAPOL, "EAPOL-Key for transmit key received within %ld seconds in AUTHENTICATED state",
  2866. EAPOL_TRANSMIT_KEY_INTERVAL
  2867. );
  2868. }
  2869. }
  2870. while (FALSE);
  2871. return dwRetCode;
  2872. }