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

321 lines
8.3 KiB

  1. /////////////////////////////////////////////////////////////////////////////// //
  2. // FILE
  3. //
  4. // EAP.cpp
  5. //
  6. // SYNOPSIS
  7. //
  8. // This file implements the class EAP.
  9. //
  10. // MODIFICATION HISTORY
  11. //
  12. // 02/12/1998 Original version.
  13. // 05/08/1998 Do not delete sessions when they're done. Let everything
  14. // age out of the session table.
  15. // 05/15/1998 Pass received packet to EAPSession constructor.
  16. // 06/12/1998 Changed put_Response to SetResponse.
  17. // 07/06/1998 Only RAS is allowed to use EAP-TLS.
  18. // 02/09/1998 Allow EAP-TLS over RADIUS.
  19. // 05/20/1999 Identity is now a Unicode string.
  20. //
  21. ///////////////////////////////////////////////////////////////////////////////
  22. #include <ias.h>
  23. #include <iaslsa.h>
  24. #include <iastlutl.h>
  25. #include <eap.h>
  26. #include <eapdnary.h>
  27. #include <eapstate.h>
  28. #include <eaptypes.h>
  29. //////////
  30. // Define static members.
  31. //////////
  32. EAPTypes EAP::theTypes;
  33. STDMETHODIMP EAP::Initialize()
  34. {
  35. HRESULT hr;
  36. // Initialize the LSA API.
  37. DWORD error = IASLsaInitialize();
  38. if (error)
  39. {
  40. hr = HRESULT_FROM_WIN32(error);
  41. goto lsa_failed;
  42. }
  43. // Initialize the sessions.
  44. hr = EAPSession::initialize();
  45. if (FAILED(hr))
  46. {
  47. goto sessions_failed;
  48. }
  49. // Initialize the IAS <--> RAS translator.
  50. hr = EAPTranslator::initialize();
  51. if (FAILED(hr))
  52. {
  53. goto translator_failed;
  54. }
  55. // The rest can't fail.
  56. EAPState::initialize();
  57. theTypes.initialize();
  58. // Everything succeeded, so we're done.
  59. return S_OK;
  60. translator_failed:
  61. EAPSession::finalize();
  62. sessions_failed:
  63. IASLsaUninitialize();
  64. lsa_failed:
  65. return hr;
  66. }
  67. STDMETHODIMP EAP::Shutdown()
  68. {
  69. // Clear out any remaining sessions.
  70. sessions.clear();
  71. // Shutdown our sub-systems.
  72. theTypes.finalize();
  73. EAPTranslator::finalize();
  74. EAPSession::finalize();
  75. IASLsaUninitialize();
  76. return S_OK;
  77. }
  78. STDMETHODIMP EAP::PutProperty(LONG Id, VARIANT* pValue)
  79. {
  80. if (pValue == NULL) { return E_INVALIDARG; }
  81. switch (Id)
  82. {
  83. case PROPERTY_EAP_SESSION_TIMEOUT:
  84. {
  85. if (V_VT(pValue) != VT_I4) { return DISP_E_TYPEMISMATCH; }
  86. if (V_I4(pValue) <= 0) { return E_INVALIDARG; }
  87. IASTracePrintf("Setting EAP session timeout to %ld msec.", V_I4(pValue));
  88. sessions.setSessionTimeout(V_I4(pValue));
  89. break;
  90. }
  91. case PROPERTY_EAP_MAX_SESSIONS:
  92. {
  93. if (V_VT(pValue) != VT_I4) { return DISP_E_TYPEMISMATCH; }
  94. if (V_I4(pValue) <= 0) { return E_INVALIDARG; }
  95. IASTracePrintf("Setting max. EAP sessions to %ld.", V_I4(pValue));
  96. sessions.setMaxSessions(V_I4(pValue));
  97. break;
  98. }
  99. default:
  100. {
  101. return DISP_E_MEMBERNOTFOUND;
  102. }
  103. }
  104. return S_OK;
  105. }
  106. ///////////////////////////////////////////////////////////////////////////////
  107. //
  108. // METHOD
  109. //
  110. // EAP::onSyncRequest
  111. //
  112. // DESCRIPTION
  113. //
  114. // Processes a request. Note that this method does only enough work to
  115. // retrieve or create a session object. Once this has been accomplished
  116. // the main processing logic takes place inside EAPSession (q.v.).
  117. //
  118. ///////////////////////////////////////////////////////////////////////////////
  119. IASREQUESTSTATUS EAP::onSyncRequest(IRequest* pRequest) throw ()
  120. {
  121. EAPSession* session = NULL;
  122. try
  123. {
  124. IASRequest request(pRequest);
  125. //////////
  126. // Does the request contain an EAP-Message?
  127. //////////
  128. DWORD attrID = RADIUS_ATTRIBUTE_EAP_MESSAGE;
  129. IASAttributeVectorWithBuffer<16> eapMessage;
  130. if (!eapMessage.load(request, 1, &attrID))
  131. {
  132. // If not, we're not interested.
  133. return IAS_REQUEST_STATUS_CONTINUE;
  134. }
  135. IASTraceString("NT-SAM EAP handler received request.");
  136. //////////
  137. // Concatenate the RADIUS EAP-Message attributes into a single packet.
  138. //////////
  139. IASAttributeVector::iterator it;
  140. DWORD pktlen = 0;
  141. for (it = eapMessage.begin(); it != eapMessage.end(); ++it)
  142. {
  143. pktlen += it->pAttribute->Value.OctetString.dwLength;
  144. }
  145. PBYTE p = (PBYTE)_alloca(pktlen);
  146. PPPP_EAP_PACKET recvPkt = (PPPP_EAP_PACKET)p;
  147. for (it = eapMessage.begin(); it != eapMessage.end(); ++it)
  148. {
  149. memcpy(p,
  150. it->pAttribute->Value.OctetString.lpValue,
  151. it->pAttribute->Value.OctetString.dwLength);
  152. p += it->pAttribute->Value.OctetString.dwLength;
  153. }
  154. //////////
  155. // Ensure that the packet is valid.
  156. //////////
  157. if (pktlen < 5 || IASExtractWORD(recvPkt->Length) != pktlen)
  158. {
  159. IASTraceString("Assembled EAP-Message has invalid length.");
  160. request.SetResponse(IAS_RESPONSE_DISCARD_PACKET,
  161. IAS_MALFORMED_REQUEST);
  162. return IAS_REQUEST_STATUS_ABORT;
  163. }
  164. //////////
  165. // Get a session object to handle this request.
  166. //////////
  167. IASREQUESTSTATUS retval;
  168. IASAttribute state;
  169. if (state.load(request, RADIUS_ATTRIBUTE_STATE, IASTYPE_OCTET_STRING))
  170. {
  171. //////////
  172. // If the State attribute exists, this is an ongoing session.
  173. //////////
  174. EAPState& s = (EAPState&)(state->Value.OctetString);
  175. if (!s.isValid())
  176. {
  177. IASTraceString("State attribute is present, but unrecognized.");
  178. // We don't recognize this state attribute, so it must belong
  179. // to someone else.
  180. return IAS_REQUEST_STATUS_CONTINUE;
  181. }
  182. // Retrieve the object for this session ID.
  183. session = sessions.remove(s.getSessionID());
  184. if (!session)
  185. {
  186. IASTraceString("Session timed-out. Discarding packet.");
  187. // The session is already complete.
  188. request.SetResponse(IAS_RESPONSE_DISCARD_PACKET,
  189. IAS_SESSION_TIMEOUT);
  190. return IAS_REQUEST_STATUS_ABORT;
  191. }
  192. IASTracePrintf("Successfully retrieved session state for user %S.",
  193. session->getAccountName());
  194. retval = session->process(request, recvPkt);
  195. }
  196. else
  197. {
  198. IASTraceString("No State attribute present. Creating new session.");
  199. //////////
  200. // No state attribute, so this is a new session.
  201. // Does the request contain an NT4-Account-Name ?
  202. //////////
  203. IASAttribute identity;
  204. if (!identity.load(request,
  205. IAS_ATTRIBUTE_NT4_ACCOUNT_NAME,
  206. IASTYPE_STRING))
  207. {
  208. IASTraceString("SAM account name not found.");
  209. // We only handle SAM users.
  210. return IAS_REQUEST_STATUS_CONTINUE;
  211. }
  212. //////////
  213. // Find out which EAP provider to use.
  214. //////////
  215. IASAttribute eapType;
  216. if (!eapType.load(request, IAS_ATTRIBUTE_NP_ALLOWED_EAP_TYPE))
  217. {
  218. IASTraceString("EAP not authorized for this user.");
  219. // Since we don't have an EAP-Type attribute, the user is not
  220. // allowed to use EAP.
  221. request.SetResponse(IAS_RESPONSE_ACCESS_REJECT,
  222. IAS_INVALID_AUTH_TYPE);
  223. return IAS_REQUEST_STATUS_HANDLED;
  224. }
  225. //////////
  226. // Retrieve the provider for this EAP type.
  227. //////////
  228. EAPType* provider = theTypes[(BYTE)(eapType->Value.Enumerator)];
  229. if (!provider)
  230. {
  231. // We can't handle this EAP type, so reject.
  232. request.SetResponse(IAS_RESPONSE_ACCESS_REJECT,
  233. IAS_UNSUPPORTED_AUTH_TYPE);
  234. return IAS_REQUEST_STATUS_HANDLED;
  235. }
  236. session = new EAPSession(identity, *provider);
  237. IASTracePrintf("Successfully created new session for user %S.",
  238. session->getAccountName());
  239. retval = session->begin(request, recvPkt);
  240. }
  241. // Save it for later.
  242. sessions.insert(session);
  243. return retval;
  244. }
  245. catch (const _com_error& ce)
  246. {
  247. IASTraceExcept();
  248. pRequest->SetResponse(IAS_RESPONSE_DISCARD_PACKET, ce.Error());
  249. }
  250. catch (const std::bad_alloc&)
  251. {
  252. IASTraceExcept();
  253. pRequest->SetResponse(IAS_RESPONSE_DISCARD_PACKET, E_OUTOFMEMORY);
  254. }
  255. // If we have any errors, we'll delete the session.
  256. delete session;
  257. return IAS_REQUEST_STATUS_ABORT;
  258. }