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.

820 lines
22 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) Microsoft Corporation
  4. //
  5. // SYNOPSIS
  6. //
  7. // This file defines the class EAPSession.
  8. //
  9. ///////////////////////////////////////////////////////////////////////////////
  10. #include "ias.h"
  11. #include "iaslsa.h"
  12. #include "lockout.h"
  13. #include "samutil.h"
  14. #include "sdoias.h"
  15. #include "eapdnary.h"
  16. #include "eapsession.h"
  17. #include "eapstate.h"
  18. #include "eaptype.h"
  19. #include "eap.h"
  20. #include "align.h"
  21. // Default value for the Framed-MTU attribute.
  22. const DWORD FRAMED_MTU_DEFAULT = 1500;
  23. // Minimum allowed value for the Framed-MTU attribute.
  24. const DWORD FRAMED_MTU_MIN = 64;
  25. // The maximum length of the frame header. i.e. max(2,4).
  26. // 2 for the PPP header and 4 for the 802.1X header.
  27. // The length of the frame header plus the length
  28. // of the EAP packet must be less than the Framed-MTU.
  29. const DWORD FRAME_HEADER_LENGTH = 4;
  30. // Absolute maximum length of an EAP packet. We bound this to limit worst-case
  31. // memory consumption.
  32. const DWORD MAX_MAX_PACKET_LENGTH = 2048;
  33. //////////
  34. // Inject a PPP_EAP_PACKET into a request.
  35. //////////
  36. VOID
  37. WINAPI
  38. InjectPacket(
  39. IASRequest& request,
  40. const PPP_EAP_PACKET& packet
  41. )
  42. {
  43. // Get the raw buffer to be packed.
  44. const BYTE* buf = (const BYTE*)&packet;
  45. DWORD nbyte = IASExtractWORD(packet.Length);
  46. IASTracePrintf("Inserting outbound EAP-Message of length %lu.", nbyte);
  47. // Determine the maximum chunk size.
  48. DWORD chunkSize;
  49. switch (request.get_Protocol())
  50. {
  51. case IAS_PROTOCOL_RADIUS:
  52. chunkSize = 253;
  53. break;
  54. default:
  55. chunkSize = nbyte;
  56. }
  57. // Split the buffer into chunks.
  58. while (nbyte)
  59. {
  60. // Compute how many bytes of the EAP-Message to store in this attribute.
  61. DWORD length = min(nbyte, chunkSize);
  62. // Initialize the attribute fields.
  63. IASAttribute attr(true);
  64. attr.setOctetString(length, buf);
  65. attr->dwId = RADIUS_ATTRIBUTE_EAP_MESSAGE;
  66. attr->dwFlags = IAS_INCLUDE_IN_RESPONSE;
  67. // Inject the attribute into the request.
  68. attr.store(request);
  69. // Update our state.
  70. nbyte -= length;
  71. buf += length;
  72. }
  73. }
  74. //////////
  75. // Extracts the Vendor-Type field from a Microsoft VSA. Returns zero if the
  76. // attribute is not a valid Microsoft VSA.
  77. //////////
  78. BYTE
  79. WINAPI
  80. ExtractMicrosoftVendorType(
  81. const IASATTRIBUTE& attr
  82. ) throw ()
  83. {
  84. if (attr.dwId == RADIUS_ATTRIBUTE_VENDOR_SPECIFIC &&
  85. attr.Value.itType == IASTYPE_OCTET_STRING &&
  86. attr.Value.OctetString.dwLength > 6 &&
  87. !memcmp(attr.Value.OctetString.lpValue, "\x00\x00\x01\x37", 4))
  88. {
  89. return *(attr.Value.OctetString.lpValue + 4);
  90. }
  91. return (BYTE)0;
  92. }
  93. //////////
  94. // Inject an array of RAS attributes into a request.
  95. //////////
  96. VOID
  97. WINAPI
  98. InjectRASAttributes(
  99. IASRequest& request,
  100. const RAS_AUTH_ATTRIBUTE* rasAttrs,
  101. DWORD flags
  102. )
  103. {
  104. if (rasAttrs == NULL) { return; }
  105. //////////
  106. // Translate them to IAS format.
  107. //////////
  108. IASTraceString("Translating attributes returned by EAP DLL.");
  109. IASAttributeVectorWithBuffer<8> iasAttrs;
  110. EAPTranslator::translate(iasAttrs, rasAttrs);
  111. //////////
  112. // Iterate through the converted attributes to set the flags and remove any
  113. // matching attributes from the request.
  114. //////////
  115. IASAttributeVector::iterator i;
  116. for (i = iasAttrs.begin(); i != iasAttrs.end(); ++i)
  117. {
  118. IASTracePrintf("Inserting attribute %lu", i->pAttribute->dwId);
  119. i->pAttribute->dwFlags = flags;
  120. }
  121. //////////
  122. // Add them to the request.
  123. //////////
  124. iasAttrs.store(request);
  125. }
  126. //////////
  127. // Performs NT-SAM PAP and MD5-CHAP authentication based on RAS attributes.
  128. //////////
  129. DWORD
  130. WINAPI
  131. AuthenticateUser(
  132. IASATTRIBUTE& account,
  133. RAS_AUTH_ATTRIBUTE* pInAttributes
  134. )
  135. {
  136. //////////
  137. // Check the input parameters.
  138. //////////
  139. if (!pInAttributes) { return NO_ERROR; }
  140. //////////
  141. // Get the NT-SAM userName and domain.
  142. //////////
  143. // Get the NT-SAM userName and domain.
  144. SamExtractor extractor(account);
  145. PCWSTR domain = extractor.getDomain();
  146. PCWSTR userName = extractor.getUsername();
  147. //////////
  148. // Find the credentials populated by the EAP DLL.
  149. //////////
  150. PRAS_AUTH_ATTRIBUTE rasUserPassword = NULL,
  151. rasMD5CHAPPassword = NULL,
  152. rasMD5CHAPChallenge = NULL;
  153. for ( ; pInAttributes->raaType != raatMinimum; ++pInAttributes)
  154. {
  155. switch (pInAttributes->raaType)
  156. {
  157. case raatUserPassword:
  158. rasUserPassword = pInAttributes;
  159. break;
  160. case raatMD5CHAPPassword:
  161. rasMD5CHAPPassword = pInAttributes;
  162. break;
  163. case raatMD5CHAPChallenge:
  164. rasMD5CHAPChallenge = pInAttributes;
  165. break;
  166. }
  167. }
  168. DWORD status = NO_ERROR;
  169. // Is this MD5-CHAP?
  170. if (rasMD5CHAPPassword && rasMD5CHAPChallenge)
  171. {
  172. _ASSERT(rasMD5CHAPPassword->dwLength == 17);
  173. // The ID is the first byte of the password ...
  174. BYTE challengeID = *(PBYTE)(rasMD5CHAPPassword->Value);
  175. // ... and the password is the rest.
  176. PBYTE chapPassword = (PBYTE)(rasMD5CHAPPassword->Value) + 1;
  177. IASTracePrintf("Performing CHAP authentication for user %S\\%S.",
  178. domain, userName);
  179. IAS_CHAP_PROFILE profile;
  180. HANDLE token;
  181. status = IASLogonCHAP(
  182. userName,
  183. domain,
  184. challengeID,
  185. (PBYTE)(rasMD5CHAPChallenge->Value),
  186. rasMD5CHAPChallenge->dwLength,
  187. chapPassword,
  188. &token,
  189. &profile
  190. );
  191. CloseHandle(token);
  192. }
  193. // Is this PAP?
  194. else if (rasUserPassword)
  195. {
  196. // Convert to a null-terminated string.
  197. IAS_OCTET_STRING octstr = { rasUserPassword->dwLength,
  198. (PBYTE)rasUserPassword->Value };
  199. PCSTR userPwd = IAS_OCT2ANSI(octstr);
  200. IASTracePrintf("Performing PAP authentication for user %S\\%S.",
  201. domain, userName);
  202. IAS_PAP_PROFILE profile;
  203. HANDLE token;
  204. status = IASLogonPAP(
  205. userName,
  206. domain,
  207. userPwd,
  208. &token,
  209. &profile
  210. );
  211. CloseHandle(token);
  212. }
  213. return status;
  214. }
  215. //////////
  216. // Updates the AccountLockout database.
  217. //////////
  218. VOID
  219. WINAPI
  220. UpdateAccountLockoutDB(
  221. IASATTRIBUTE& account,
  222. DWORD authResult
  223. )
  224. {
  225. // Get the NT-SAM userName and domain.
  226. SamExtractor extractor(account);
  227. PCWSTR domain = extractor.getDomain();
  228. PCWSTR userName = extractor.getUsername();
  229. // Lookup the user in the lockout DB.
  230. HANDLE hAccount;
  231. AccountLockoutOpenAndQuery(userName, domain, &hAccount);
  232. // Report the result.
  233. if (authResult == NO_ERROR)
  234. {
  235. AccountLockoutUpdatePass(hAccount);
  236. }
  237. else
  238. {
  239. AccountLockoutUpdateFail(hAccount);
  240. }
  241. // Close the handle.
  242. AccountLockoutClose(hAccount);
  243. }
  244. //////////
  245. // Define the static members.
  246. //////////
  247. LONG EAPSession::theNextID = 0;
  248. LONG EAPSession::theRefCount = 0;
  249. IASAttribute EAPSession::theNormalTimeout;
  250. IASAttribute EAPSession::theInteractiveTimeout;
  251. HANDLE EAPSession::theIASEventLog;
  252. HANDLE EAPSession::theRASEventLog;
  253. EAPSession::EAPSession(
  254. const IASAttribute& accountName,
  255. std::vector<EAPType*>& eapTypes
  256. )
  257. : id((DWORD)InterlockedIncrement(&theNextID)),
  258. currentType(0),
  259. account(accountName),
  260. state(EAPState::createAttribute(id), false),
  261. fsm(eapTypes),
  262. maxPacketLength(FRAMED_MTU_DEFAULT - FRAME_HEADER_LENGTH),
  263. workBuffer(NULL),
  264. sendPacket(NULL)
  265. {
  266. eapInput.pUserAttributes = NULL;
  267. }
  268. EAPSession::~EAPSession() throw ()
  269. {
  270. clearType();
  271. delete[] sendPacket;
  272. delete[] eapInput.pUserAttributes;
  273. }
  274. IASREQUESTSTATUS EAPSession::begin(
  275. IASRequest& request,
  276. PPPP_EAP_PACKET recvPacket
  277. )
  278. {
  279. //////////
  280. // Get all the attributes from the request.
  281. //////////
  282. all.load(request);
  283. //////////
  284. // Scan for the Framed-MTU attribute and compute the profile size.
  285. //////////
  286. DWORD profileSize = 0;
  287. DWORD configSize = 0;
  288. IASAttributeVector::iterator i;
  289. for (i = all.begin(); i != all.end(); ++i)
  290. {
  291. if (i->pAttribute->dwId == RADIUS_ATTRIBUTE_FRAMED_MTU)
  292. {
  293. DWORD framedMTU = i->pAttribute->Value.Integer;
  294. // Only process valid values.
  295. if (framedMTU >= FRAMED_MTU_MIN)
  296. {
  297. // Leave room for the frame header.
  298. maxPacketLength = framedMTU - FRAME_HEADER_LENGTH;
  299. // Make sure we're within bounds.
  300. if (maxPacketLength > MAX_MAX_PACKET_LENGTH)
  301. {
  302. maxPacketLength = MAX_MAX_PACKET_LENGTH;
  303. }
  304. }
  305. IASTracePrintf("Setting max. packet length to %lu.", maxPacketLength);
  306. }
  307. if (i->pAttribute->dwId == IAS_ATTRIBUTE_EAP_CONFIG)
  308. {
  309. ++configSize;
  310. }
  311. else if (!(i->pAttribute->dwFlags & IAS_RECVD_FROM_PROTOCOL))
  312. {
  313. ++profileSize;
  314. }
  315. }
  316. //////////
  317. // Save and remove the profile and config attributes.
  318. //////////
  319. profile.reserve(profileSize);
  320. config.reserve(configSize);
  321. for (i = all.begin(); i != all.end(); ++i)
  322. {
  323. if (i->pAttribute->dwId == IAS_ATTRIBUTE_EAP_CONFIG)
  324. {
  325. config.push_back(*i);
  326. }
  327. else if (!(i->pAttribute->dwFlags & IAS_RECVD_FROM_PROTOCOL))
  328. {
  329. profile.push_back(*i);
  330. }
  331. }
  332. profile.remove(request);
  333. //////////
  334. // Convert the attributes received from the client to RAS format.
  335. //////////
  336. eapInput.pUserAttributes = new RAS_AUTH_ATTRIBUTE[all.size() + 1];
  337. EAPTranslator::translate(
  338. eapInput.pUserAttributes,
  339. all,
  340. IAS_RECVD_FROM_CLIENT
  341. );
  342. //////////
  343. // Initialize the EAPInput struct.
  344. //////////
  345. eapInput.fAuthenticator = TRUE;
  346. eapInput.bInitialId = recvPacket->Id + (BYTE)1;
  347. eapInput.pwszIdentity = account->Value.String.pszWide;
  348. switch (request.get_Protocol())
  349. {
  350. case IAS_PROTOCOL_RADIUS:
  351. eapInput.hReserved = theIASEventLog;
  352. break;
  353. case IAS_PROTOCOL_RAS:
  354. eapInput.hReserved = theRASEventLog;
  355. break;
  356. }
  357. // Begin the session with the EAP DLL.
  358. setType(fsm.onBegin());
  359. //////////
  360. // We have successfully established the session, so process the message.
  361. //////////
  362. return process(request, recvPacket);
  363. }
  364. IASREQUESTSTATUS EAPSession::process(
  365. IASRequest& request,
  366. PPPP_EAP_PACKET recvPacket
  367. )
  368. {
  369. // Trigger an event on the FSM.
  370. EAPType* newType;
  371. switch (fsm.onReceiveEvent(*recvPacket, newType))
  372. {
  373. case EAPFSM::MAKE_MESSAGE:
  374. {
  375. if (newType != 0)
  376. {
  377. setType(newType);
  378. }
  379. break;
  380. }
  381. case EAPFSM::REPLAY_LAST:
  382. {
  383. IASTraceString("EAP-Message appears to be a retransmission. "
  384. "Replaying last action.");
  385. return doAction(request);
  386. }
  387. case EAPFSM::FAIL_NEGOTIATE:
  388. {
  389. IASTraceString("EAP negotiation failed. Rejecting user.");
  390. profile.store(request);
  391. request.SetResponse(IAS_RESPONSE_ACCESS_REJECT,
  392. IAS_EAP_NEGOTIATION_FAILED);
  393. return IAS_REQUEST_STATUS_HANDLED;
  394. }
  395. case EAPFSM::DISCARD:
  396. {
  397. IASTraceString("EAP-Message is unexpected. Discarding packet.");
  398. profile.store(request);
  399. request.SetResponse(IAS_RESPONSE_DISCARD_PACKET,
  400. IAS_UNEXPECTED_REQUEST);
  401. return IAS_REQUEST_STATUS_ABORT;
  402. }
  403. }
  404. // Allocate a temporary packet to hold the response.
  405. PPPP_EAP_PACKET tmpPacket = (PPPP_EAP_PACKET)_alloca(maxPacketLength);
  406. // Clear the previous output from the DLL.
  407. eapOutput.clear();
  408. DWORD error = currentType->RasEapMakeMessage(
  409. workBuffer,
  410. recvPacket,
  411. tmpPacket,
  412. maxPacketLength,
  413. &eapOutput,
  414. NULL
  415. );
  416. if (error != NO_ERROR)
  417. {
  418. IASTraceFailure("RasEapMakeMessage", error);
  419. _com_issue_error(HRESULT_FROM_WIN32(error));
  420. }
  421. while (eapOutput.Action == EAPACTION_Authenticate)
  422. {
  423. IASTraceString("EAP DLL invoked default authenticator.");
  424. // Authenticate the user.
  425. DWORD authResult = AuthenticateUser(
  426. *account,
  427. eapOutput.pUserAttributes
  428. );
  429. //////////
  430. // Convert the profile to RAS format.
  431. //////////
  432. DWORD filter;
  433. if (authResult == NO_ERROR)
  434. {
  435. IASTraceString("Default authentication succeeded.");
  436. filter = IAS_INCLUDE_IN_ACCEPT;
  437. }
  438. else
  439. {
  440. IASTraceFailure("Default authentication", authResult);
  441. filter = IAS_INCLUDE_IN_REJECT;
  442. }
  443. PRAS_AUTH_ATTRIBUTE ras = IAS_STACK_NEW(RAS_AUTH_ATTRIBUTE,
  444. profile.size() + 1);
  445. EAPTranslator::translate(ras, profile, filter);
  446. //////////
  447. // Give the result to the EAP DLL.
  448. //////////
  449. EAPInput authInput;
  450. authInput.dwAuthResultCode = authResult;
  451. authInput.fAuthenticationComplete = TRUE;
  452. authInput.pUserAttributes = ras;
  453. eapOutput.clear();
  454. error = currentType->RasEapMakeMessage(
  455. workBuffer,
  456. NULL,
  457. tmpPacket,
  458. maxPacketLength,
  459. &eapOutput,
  460. &authInput
  461. );
  462. if (error != NO_ERROR)
  463. {
  464. IASTraceFailure("RasEapMakeMessage", error);
  465. _com_issue_error(HRESULT_FROM_WIN32(error));
  466. }
  467. }
  468. //////////
  469. // Trigger an event on the FSM.
  470. //////////
  471. fsm.onDllEvent(eapOutput.Action, *tmpPacket);
  472. // Clear the old send packet ...
  473. delete[] sendPacket;
  474. sendPacket = NULL;
  475. // ... and save the new one if available.
  476. switch (eapOutput.Action)
  477. {
  478. case EAPACTION_SendAndDone:
  479. case EAPACTION_Send:
  480. case EAPACTION_SendWithTimeout:
  481. case EAPACTION_SendWithTimeoutInteractive:
  482. {
  483. size_t length = IASExtractWORD(tmpPacket->Length);
  484. sendPacket = (PPPP_EAP_PACKET)new BYTE[length];
  485. memcpy(sendPacket, tmpPacket, length);
  486. }
  487. }
  488. //////////
  489. // Perform the requested action.
  490. //////////
  491. return doAction(request);
  492. }
  493. IASREQUESTSTATUS EAPSession::doAction(IASRequest& request)
  494. {
  495. IASTraceString("Processing output from EAP DLL.");
  496. switch (eapOutput.Action)
  497. {
  498. case EAPACTION_SendAndDone:
  499. {
  500. InjectPacket(request, *sendPacket);
  501. }
  502. case EAPACTION_Done:
  503. {
  504. // Add the profile first, so that the EAP DLL can override it.
  505. profile.store(request);
  506. // Special-case the unauthenticated access
  507. if (eapOutput.dwAuthResultCode == SEC_E_NO_CREDENTIALS)
  508. {
  509. // set the auth type to unauthenticated
  510. DWORD authID = IAS_ATTRIBUTE_AUTHENTICATION_TYPE;
  511. request.RemoveAttributesByType(1, &authID);
  512. IASAttribute authType(true);
  513. authType->dwId = IAS_ATTRIBUTE_AUTHENTICATION_TYPE;
  514. authType->Value.itType = IASTYPE_ENUM;
  515. authType->Value.Enumerator = IAS_AUTH_NONE;
  516. authType.store(request);
  517. // Load the EAP Types attributes into the vector.
  518. IASAttributeVectorWithBuffer<8> authTypes;
  519. authTypes.load(request, IAS_ATTRIBUTE_NP_AUTHENTICATION_TYPE);
  520. for (IASAttributeVector::iterator i = authTypes.begin();
  521. i != authTypes.end(); ++i)
  522. {
  523. if (i->pAttribute->Value.Integer == IAS_AUTH_NONE)
  524. {
  525. // Unauthenticated EAP access allowed
  526. IASTraceString("Unauthenticated EAP access allowed");
  527. eapOutput.dwAuthResultCode = NO_ERROR;
  528. break;
  529. }
  530. }
  531. }
  532. // Update the account lockout database.
  533. UpdateAccountLockoutDB(
  534. *account,
  535. eapOutput.dwAuthResultCode
  536. );
  537. DWORD flags = eapOutput.dwAuthResultCode ? IAS_INCLUDE_IN_REJECT
  538. : IAS_INCLUDE_IN_ACCEPT;
  539. InjectRASAttributes(request, eapOutput.pUserAttributes, flags);
  540. // store the EAP friendly name negotiated for both success and failure
  541. // if PEAP is used, store the PEAP inside type and update the
  542. // authentication type from EAP to PEAP
  543. currentType->storeNameId(request);
  544. if (eapOutput.dwAuthResultCode == NO_ERROR)
  545. {
  546. IASTraceString("EAP authentication succeeded.");
  547. request.SetResponse(IAS_RESPONSE_ACCESS_ACCEPT, S_OK);
  548. }
  549. else
  550. {
  551. IASTraceFailure("EAP authentication", eapOutput.dwAuthResultCode);
  552. HRESULT hr = IASMapWin32Error(eapOutput.dwAuthResultCode,
  553. IAS_AUTH_FAILURE);
  554. request.SetResponse(IAS_RESPONSE_ACCESS_REJECT, hr);
  555. }
  556. return IAS_REQUEST_STATUS_HANDLED;
  557. }
  558. case EAPACTION_SendWithTimeoutInteractive:
  559. case EAPACTION_SendWithTimeout:
  560. {
  561. if (eapOutput.Action == EAPACTION_SendWithTimeoutInteractive)
  562. {
  563. theInteractiveTimeout.store(request);
  564. }
  565. else
  566. {
  567. theNormalTimeout.store(request);
  568. }
  569. }
  570. case EAPACTION_Send:
  571. {
  572. InjectRASAttributes(request,
  573. eapOutput.pUserAttributes,
  574. IAS_INCLUDE_IN_CHALLENGE);
  575. InjectPacket(request, *sendPacket);
  576. state.store(request);
  577. IASTraceString("Issuing Access-Challenge.");
  578. request.SetResponse(IAS_RESPONSE_ACCESS_CHALLENGE, S_OK);
  579. break;
  580. }
  581. case EAPACTION_NoAction:
  582. default:
  583. {
  584. IASTraceString("EAP DLL returned No Action. Discarding packet.");
  585. request.SetResponse(IAS_RESPONSE_DISCARD_PACKET, IAS_INTERNAL_ERROR);
  586. }
  587. }
  588. return IAS_REQUEST_STATUS_ABORT;
  589. }
  590. extern "C"
  591. NTSYSAPI
  592. ULONG
  593. NTAPI
  594. RtlRandomEx(
  595. PULONG Seed
  596. );
  597. HRESULT EAPSession::initialize() throw ()
  598. {
  599. IASGlobalLockSentry sentry;
  600. if (theRefCount == 0)
  601. {
  602. FILETIME ft;
  603. GetSystemTimeAsFileTime(&ft);
  604. ULONG seed = (ft.dwLowDateTime ^ ft.dwHighDateTime);
  605. theNextID = RtlRandomEx(&seed);
  606. PIASATTRIBUTE attrs[2];
  607. DWORD dw = IASAttributeAlloc(2, attrs);
  608. if (dw != NO_ERROR) { return HRESULT_FROM_WIN32(dw); }
  609. theNormalTimeout.attach(attrs[0], false);
  610. theNormalTimeout->dwId = RADIUS_ATTRIBUTE_SESSION_TIMEOUT;
  611. theNormalTimeout->Value.itType = IASTYPE_INTEGER;
  612. theNormalTimeout->Value.Integer = 6;
  613. theNormalTimeout.setFlag(IAS_INCLUDE_IN_CHALLENGE);
  614. theInteractiveTimeout.attach(attrs[1], false);
  615. theInteractiveTimeout->dwId = RADIUS_ATTRIBUTE_SESSION_TIMEOUT;
  616. theInteractiveTimeout->Value.itType = IASTYPE_INTEGER;
  617. theInteractiveTimeout->Value.Integer = 30;
  618. theInteractiveTimeout.setFlag(IAS_INCLUDE_IN_CHALLENGE);
  619. theIASEventLog = RegisterEventSourceW(NULL, L"IAS");
  620. theRASEventLog = RegisterEventSourceW(NULL, L"RemoteAccess");
  621. }
  622. ++theRefCount;
  623. return S_OK;
  624. }
  625. void EAPSession::finalize() throw ()
  626. {
  627. IASGlobalLockSentry sentry;
  628. if (--theRefCount == 0)
  629. {
  630. DeregisterEventSource(theRASEventLog);
  631. DeregisterEventSource(theIASEventLog);
  632. theInteractiveTimeout.release();
  633. theNormalTimeout.release();
  634. }
  635. }
  636. void EAPSession::clearType() throw ()
  637. {
  638. if (currentType != 0)
  639. {
  640. currentType->RasEapEnd(workBuffer);
  641. currentType = 0;
  642. }
  643. }
  644. void EAPSession::setType(EAPType* newType)
  645. {
  646. // If we're switching types, we have to bump the EAP identifier.
  647. if (currentType != 0)
  648. {
  649. ++(eapInput.bInitialId);
  650. }
  651. // Try to initialize the new type.
  652. void* newWorkBuffer = 0;
  653. if (newType != 0)
  654. {
  655. eapInput.pConnectionData = 0;
  656. eapInput.dwSizeOfConnectionData = 0;
  657. // Do we have config data for this EAP type?
  658. for (IASAttributeVector::const_iterator i = config.begin();
  659. i != config.end();
  660. ++i)
  661. {
  662. const IAS_OCTET_STRING& data = i->pAttribute->Value.OctetString;
  663. if (data.lpValue[0] == newType->typeCode())
  664. {
  665. // Don't pass first byte to EAP DLL.
  666. eapInput.pConnectionData = data.lpValue + ALIGN_WORST;
  667. eapInput.dwSizeOfConnectionData = data.dwLength - ALIGN_WORST;
  668. break;
  669. }
  670. }
  671. DWORD error = newType->RasEapBegin(&newWorkBuffer, &eapInput);
  672. if (error != NO_ERROR)
  673. {
  674. IASTraceFailure("RasEapBegin", error);
  675. _com_issue_error(HRESULT_FROM_WIN32(error));
  676. }
  677. }
  678. // Success, so clear the old ...
  679. clearType();
  680. // ... and save the new.
  681. currentType = newType;
  682. workBuffer = newWorkBuffer;
  683. }