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.

343 lines
9.3 KiB

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