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.

230 lines
5.4 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) Microsoft Corp. All rights reserved.
  4. //
  5. // SYNOPSIS
  6. //
  7. // Defines the class EAPFSM.
  8. //
  9. ///////////////////////////////////////////////////////////////////////////////
  10. #include "ias.h"
  11. #include "iasutil.h"
  12. #include "eapfsm.h"
  13. EAPType* EAPFSM::onBegin() throw ()
  14. {
  15. return types.front();
  16. }
  17. void EAPFSM::onDllEvent(
  18. PPP_EAP_ACTION action,
  19. const PPP_EAP_PACKET& sendPkt
  20. ) throw ()
  21. {
  22. switch (action)
  23. {
  24. case EAPACTION_NoAction:
  25. {
  26. lastSendCode = 0;
  27. break;
  28. }
  29. case EAPACTION_Done:
  30. case EAPACTION_SendAndDone:
  31. {
  32. state = STATE_DONE;
  33. break;
  34. }
  35. case EAPACTION_Send:
  36. case EAPACTION_SendWithTimeout:
  37. case EAPACTION_SendWithTimeoutInteractive:
  38. {
  39. lastSendCode = sendPkt.Code;
  40. lastSendId = sendPkt.Id;
  41. break;
  42. }
  43. }
  44. }
  45. EAPFSM::Action EAPFSM::onReceiveEvent(
  46. const PPP_EAP_PACKET& recvPkt,
  47. EAPType*& newType
  48. ) throw ()
  49. {
  50. // Default is to discard.
  51. Action action = DISCARD;
  52. // And type doesn't change.
  53. newType = 0;
  54. switch (state)
  55. {
  56. case STATE_INITIAL:
  57. {
  58. // In the initial state we only accept Response/Identity.
  59. if ((recvPkt.Code == EAPCODE_Response) && (recvPkt.Data[0] == 1))
  60. {
  61. action = MAKE_MESSAGE;
  62. state = STATE_NEGOTIATING;
  63. }
  64. break;
  65. }
  66. case STATE_NEGOTIATING:
  67. {
  68. if (isRepeat(recvPkt))
  69. {
  70. action = REPLAY_LAST;
  71. break;
  72. }
  73. if (!isExpected(recvPkt))
  74. {
  75. action = DISCARD;
  76. break;
  77. }
  78. // In the negotiating state, NAK's are allowed.
  79. if (recvPkt.Data[0] == 3)
  80. {
  81. // Did the client propose a type?
  82. BYTE proposal =
  83. (IASExtractWORD(recvPkt.Length) > 5) ? recvPkt.Data[1] : 0;
  84. // Select a new type.
  85. action = selectNewType(proposal, newType);
  86. }
  87. else if (recvPkt.Data[0] == eapType)
  88. {
  89. // Once the client agrees to our type; he's locked in.
  90. action = MAKE_MESSAGE;
  91. state = STATE_ACTIVE;
  92. }
  93. else
  94. {
  95. action = FAIL_NEGOTIATE;
  96. state = STATE_DONE;
  97. }
  98. break;
  99. }
  100. case STATE_ACTIVE:
  101. {
  102. if (recvPkt.Code == EAPCODE_Request)
  103. {
  104. action = MAKE_MESSAGE;
  105. }
  106. else if (recvPkt.Data[0] == 3)
  107. {
  108. action = DISCARD;
  109. }
  110. else if (isRepeat(recvPkt))
  111. {
  112. action = REPLAY_LAST;
  113. }
  114. else if (isExpected(recvPkt))
  115. {
  116. action = MAKE_MESSAGE;
  117. }
  118. break;
  119. }
  120. case STATE_DONE:
  121. {
  122. // The session is over, so all we do is replay repeats.
  123. if (isRepeat(recvPkt))
  124. {
  125. action = REPLAY_LAST;
  126. }
  127. }
  128. }
  129. // If the packet made it through our filters, then we count it as the
  130. // last received.
  131. if (action == MAKE_MESSAGE)
  132. {
  133. lastRecvCode = recvPkt.Code;
  134. lastRecvId = recvPkt.Id;
  135. lastRecvType = recvPkt.Data[0];
  136. }
  137. return action;
  138. }
  139. inline BOOL EAPFSM::isExpected(const PPP_EAP_PACKET& recvPkt) const throw ()
  140. {
  141. return (lastSendCode == EAPCODE_Request) &&
  142. (recvPkt.Code == EAPCODE_Response) &&
  143. (recvPkt.Id == lastSendId);
  144. }
  145. inline BOOL EAPFSM::isRepeat(const PPP_EAP_PACKET& recvPkt) const throw ()
  146. {
  147. return (recvPkt.Code == lastRecvCode) &&
  148. (recvPkt.Id == lastRecvId) &&
  149. (recvPkt.Data[0] == lastRecvType);
  150. }
  151. EAPFSM::Action EAPFSM::selectNewType(
  152. BYTE proposal,
  153. EAPType*& newType
  154. ) throw ()
  155. {
  156. // The peer NAK'd our previous offer, so he's not allowed to use it
  157. // again.
  158. types.erase(types.begin());
  159. if (proposal != 0)
  160. {
  161. IASTracePrintf("EAP NAK; proposed type = %hd", proposal);
  162. // Find the proposed type in the list of allowed types.
  163. for (std::vector<EAPType*>::iterator i = types.begin();
  164. i != types.end();
  165. ++i)
  166. {
  167. if ((*i)->dwEapTypeId == proposal)
  168. {
  169. IASTraceString("Accepting proposed type.");
  170. // change the current type
  171. newType = *i;
  172. eapType = newType->dwEapTypeId;
  173. // change the state to active: any NAK received now will fail
  174. state = STATE_ACTIVE;
  175. return MAKE_MESSAGE;
  176. }
  177. }
  178. }
  179. else
  180. {
  181. IASTraceString("EAP NAK; no type proposed");
  182. }
  183. // If the server list is empty, then nothing else can be negotiated.
  184. if (types.empty())
  185. {
  186. IASTraceString("EAP negotiation failed; no types remaining.");
  187. state = STATE_DONE;
  188. return FAIL_NEGOTIATE;
  189. }
  190. // negotiate the next one from the server's list
  191. newType = types.front();
  192. eapType = newType->dwEapTypeId;
  193. IASTracePrintf("EAP authenticator offering type %hd", eapType);
  194. return MAKE_MESSAGE;
  195. }