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
820 lines
22 KiB
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) Microsoft Corporation
|
|
//
|
|
// SYNOPSIS
|
|
//
|
|
// This file defines the class EAPSession.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "ias.h"
|
|
#include "iaslsa.h"
|
|
#include "lockout.h"
|
|
#include "samutil.h"
|
|
#include "sdoias.h"
|
|
|
|
#include "eapdnary.h"
|
|
#include "eapsession.h"
|
|
#include "eapstate.h"
|
|
#include "eaptype.h"
|
|
#include "eap.h"
|
|
#include "align.h"
|
|
|
|
// Default value for the Framed-MTU attribute.
|
|
const DWORD FRAMED_MTU_DEFAULT = 1500;
|
|
|
|
// Minimum allowed value for the Framed-MTU attribute.
|
|
const DWORD FRAMED_MTU_MIN = 64;
|
|
|
|
// The maximum length of the frame header. i.e. max(2,4).
|
|
// 2 for the PPP header and 4 for the 802.1X header.
|
|
// The length of the frame header plus the length
|
|
// of the EAP packet must be less than the Framed-MTU.
|
|
const DWORD FRAME_HEADER_LENGTH = 4;
|
|
|
|
// Absolute maximum length of an EAP packet. We bound this to limit worst-case
|
|
// memory consumption.
|
|
const DWORD MAX_MAX_PACKET_LENGTH = 2048;
|
|
|
|
//////////
|
|
// Inject a PPP_EAP_PACKET into a request.
|
|
//////////
|
|
VOID
|
|
WINAPI
|
|
InjectPacket(
|
|
IASRequest& request,
|
|
const PPP_EAP_PACKET& packet
|
|
)
|
|
{
|
|
// Get the raw buffer to be packed.
|
|
const BYTE* buf = (const BYTE*)&packet;
|
|
DWORD nbyte = IASExtractWORD(packet.Length);
|
|
|
|
IASTracePrintf("Inserting outbound EAP-Message of length %lu.", nbyte);
|
|
|
|
// Determine the maximum chunk size.
|
|
DWORD chunkSize;
|
|
switch (request.get_Protocol())
|
|
{
|
|
case IAS_PROTOCOL_RADIUS:
|
|
chunkSize = 253;
|
|
break;
|
|
|
|
default:
|
|
chunkSize = nbyte;
|
|
}
|
|
|
|
// Split the buffer into chunks.
|
|
while (nbyte)
|
|
{
|
|
// Compute how many bytes of the EAP-Message to store in this attribute.
|
|
DWORD length = min(nbyte, chunkSize);
|
|
|
|
// Initialize the attribute fields.
|
|
IASAttribute attr(true);
|
|
attr.setOctetString(length, buf);
|
|
attr->dwId = RADIUS_ATTRIBUTE_EAP_MESSAGE;
|
|
attr->dwFlags = IAS_INCLUDE_IN_RESPONSE;
|
|
|
|
// Inject the attribute into the request.
|
|
attr.store(request);
|
|
|
|
// Update our state.
|
|
nbyte -= length;
|
|
buf += length;
|
|
}
|
|
}
|
|
|
|
//////////
|
|
// Extracts the Vendor-Type field from a Microsoft VSA. Returns zero if the
|
|
// attribute is not a valid Microsoft VSA.
|
|
//////////
|
|
BYTE
|
|
WINAPI
|
|
ExtractMicrosoftVendorType(
|
|
const IASATTRIBUTE& attr
|
|
) throw ()
|
|
{
|
|
if (attr.dwId == RADIUS_ATTRIBUTE_VENDOR_SPECIFIC &&
|
|
attr.Value.itType == IASTYPE_OCTET_STRING &&
|
|
attr.Value.OctetString.dwLength > 6 &&
|
|
!memcmp(attr.Value.OctetString.lpValue, "\x00\x00\x01\x37", 4))
|
|
{
|
|
return *(attr.Value.OctetString.lpValue + 4);
|
|
}
|
|
|
|
return (BYTE)0;
|
|
}
|
|
|
|
//////////
|
|
// Inject an array of RAS attributes into a request.
|
|
//////////
|
|
VOID
|
|
WINAPI
|
|
InjectRASAttributes(
|
|
IASRequest& request,
|
|
const RAS_AUTH_ATTRIBUTE* rasAttrs,
|
|
DWORD flags
|
|
)
|
|
{
|
|
if (rasAttrs == NULL) { return; }
|
|
|
|
//////////
|
|
// Translate them to IAS format.
|
|
//////////
|
|
|
|
IASTraceString("Translating attributes returned by EAP DLL.");
|
|
|
|
IASAttributeVectorWithBuffer<8> iasAttrs;
|
|
EAPTranslator::translate(iasAttrs, rasAttrs);
|
|
|
|
//////////
|
|
// Iterate through the converted attributes to set the flags and remove any
|
|
// matching attributes from the request.
|
|
//////////
|
|
|
|
IASAttributeVector::iterator i;
|
|
for (i = iasAttrs.begin(); i != iasAttrs.end(); ++i)
|
|
{
|
|
IASTracePrintf("Inserting attribute %lu", i->pAttribute->dwId);
|
|
|
|
i->pAttribute->dwFlags = flags;
|
|
}
|
|
|
|
//////////
|
|
// Add them to the request.
|
|
//////////
|
|
|
|
iasAttrs.store(request);
|
|
}
|
|
|
|
//////////
|
|
// Performs NT-SAM PAP and MD5-CHAP authentication based on RAS attributes.
|
|
//////////
|
|
DWORD
|
|
WINAPI
|
|
AuthenticateUser(
|
|
IASATTRIBUTE& account,
|
|
RAS_AUTH_ATTRIBUTE* pInAttributes
|
|
)
|
|
{
|
|
//////////
|
|
// Check the input parameters.
|
|
//////////
|
|
if (!pInAttributes) { return NO_ERROR; }
|
|
|
|
//////////
|
|
// Get the NT-SAM userName and domain.
|
|
//////////
|
|
|
|
// Get the NT-SAM userName and domain.
|
|
SamExtractor extractor(account);
|
|
PCWSTR domain = extractor.getDomain();
|
|
PCWSTR userName = extractor.getUsername();
|
|
|
|
//////////
|
|
// Find the credentials populated by the EAP DLL.
|
|
//////////
|
|
|
|
PRAS_AUTH_ATTRIBUTE rasUserPassword = NULL,
|
|
rasMD5CHAPPassword = NULL,
|
|
rasMD5CHAPChallenge = NULL;
|
|
|
|
for ( ; pInAttributes->raaType != raatMinimum; ++pInAttributes)
|
|
{
|
|
switch (pInAttributes->raaType)
|
|
{
|
|
case raatUserPassword:
|
|
rasUserPassword = pInAttributes;
|
|
break;
|
|
|
|
case raatMD5CHAPPassword:
|
|
rasMD5CHAPPassword = pInAttributes;
|
|
break;
|
|
|
|
case raatMD5CHAPChallenge:
|
|
rasMD5CHAPChallenge = pInAttributes;
|
|
break;
|
|
}
|
|
}
|
|
|
|
DWORD status = NO_ERROR;
|
|
|
|
// Is this MD5-CHAP?
|
|
if (rasMD5CHAPPassword && rasMD5CHAPChallenge)
|
|
{
|
|
_ASSERT(rasMD5CHAPPassword->dwLength == 17);
|
|
|
|
// The ID is the first byte of the password ...
|
|
BYTE challengeID = *(PBYTE)(rasMD5CHAPPassword->Value);
|
|
|
|
// ... and the password is the rest.
|
|
PBYTE chapPassword = (PBYTE)(rasMD5CHAPPassword->Value) + 1;
|
|
|
|
IASTracePrintf("Performing CHAP authentication for user %S\\%S.",
|
|
domain, userName);
|
|
|
|
IAS_CHAP_PROFILE profile;
|
|
HANDLE token;
|
|
status = IASLogonCHAP(
|
|
userName,
|
|
domain,
|
|
challengeID,
|
|
(PBYTE)(rasMD5CHAPChallenge->Value),
|
|
rasMD5CHAPChallenge->dwLength,
|
|
chapPassword,
|
|
&token,
|
|
&profile
|
|
);
|
|
CloseHandle(token);
|
|
}
|
|
|
|
// Is this PAP?
|
|
else if (rasUserPassword)
|
|
{
|
|
// Convert to a null-terminated string.
|
|
IAS_OCTET_STRING octstr = { rasUserPassword->dwLength,
|
|
(PBYTE)rasUserPassword->Value };
|
|
PCSTR userPwd = IAS_OCT2ANSI(octstr);
|
|
|
|
IASTracePrintf("Performing PAP authentication for user %S\\%S.",
|
|
domain, userName);
|
|
|
|
IAS_PAP_PROFILE profile;
|
|
HANDLE token;
|
|
status = IASLogonPAP(
|
|
userName,
|
|
domain,
|
|
userPwd,
|
|
&token,
|
|
&profile
|
|
);
|
|
CloseHandle(token);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
//////////
|
|
// Updates the AccountLockout database.
|
|
//////////
|
|
VOID
|
|
WINAPI
|
|
UpdateAccountLockoutDB(
|
|
IASATTRIBUTE& account,
|
|
DWORD authResult
|
|
)
|
|
{
|
|
// Get the NT-SAM userName and domain.
|
|
SamExtractor extractor(account);
|
|
PCWSTR domain = extractor.getDomain();
|
|
PCWSTR userName = extractor.getUsername();
|
|
|
|
// Lookup the user in the lockout DB.
|
|
HANDLE hAccount;
|
|
AccountLockoutOpenAndQuery(userName, domain, &hAccount);
|
|
|
|
// Report the result.
|
|
if (authResult == NO_ERROR)
|
|
{
|
|
AccountLockoutUpdatePass(hAccount);
|
|
}
|
|
else
|
|
{
|
|
AccountLockoutUpdateFail(hAccount);
|
|
}
|
|
|
|
// Close the handle.
|
|
AccountLockoutClose(hAccount);
|
|
}
|
|
|
|
//////////
|
|
// Define the static members.
|
|
//////////
|
|
|
|
LONG EAPSession::theNextID = 0;
|
|
LONG EAPSession::theRefCount = 0;
|
|
IASAttribute EAPSession::theNormalTimeout;
|
|
IASAttribute EAPSession::theInteractiveTimeout;
|
|
HANDLE EAPSession::theIASEventLog;
|
|
HANDLE EAPSession::theRASEventLog;
|
|
|
|
EAPSession::EAPSession(
|
|
const IASAttribute& accountName,
|
|
std::vector<EAPType*>& eapTypes
|
|
)
|
|
: id((DWORD)InterlockedIncrement(&theNextID)),
|
|
currentType(0),
|
|
account(accountName),
|
|
state(EAPState::createAttribute(id), false),
|
|
fsm(eapTypes),
|
|
maxPacketLength(FRAMED_MTU_DEFAULT - FRAME_HEADER_LENGTH),
|
|
workBuffer(NULL),
|
|
sendPacket(NULL)
|
|
{
|
|
eapInput.pUserAttributes = NULL;
|
|
}
|
|
|
|
EAPSession::~EAPSession() throw ()
|
|
{
|
|
clearType();
|
|
delete[] sendPacket;
|
|
delete[] eapInput.pUserAttributes;
|
|
}
|
|
|
|
IASREQUESTSTATUS EAPSession::begin(
|
|
IASRequest& request,
|
|
PPPP_EAP_PACKET recvPacket
|
|
)
|
|
{
|
|
//////////
|
|
// Get all the attributes from the request.
|
|
//////////
|
|
all.load(request);
|
|
|
|
//////////
|
|
// Scan for the Framed-MTU attribute and compute the profile size.
|
|
//////////
|
|
|
|
DWORD profileSize = 0;
|
|
DWORD configSize = 0;
|
|
IASAttributeVector::iterator i;
|
|
for (i = all.begin(); i != all.end(); ++i)
|
|
{
|
|
if (i->pAttribute->dwId == RADIUS_ATTRIBUTE_FRAMED_MTU)
|
|
{
|
|
DWORD framedMTU = i->pAttribute->Value.Integer;
|
|
|
|
// Only process valid values.
|
|
if (framedMTU >= FRAMED_MTU_MIN)
|
|
{
|
|
// Leave room for the frame header.
|
|
maxPacketLength = framedMTU - FRAME_HEADER_LENGTH;
|
|
|
|
// Make sure we're within bounds.
|
|
if (maxPacketLength > MAX_MAX_PACKET_LENGTH)
|
|
{
|
|
maxPacketLength = MAX_MAX_PACKET_LENGTH;
|
|
}
|
|
}
|
|
|
|
IASTracePrintf("Setting max. packet length to %lu.", maxPacketLength);
|
|
}
|
|
|
|
if (i->pAttribute->dwId == IAS_ATTRIBUTE_EAP_CONFIG)
|
|
{
|
|
++configSize;
|
|
}
|
|
else if (!(i->pAttribute->dwFlags & IAS_RECVD_FROM_PROTOCOL))
|
|
{
|
|
++profileSize;
|
|
}
|
|
}
|
|
|
|
//////////
|
|
// Save and remove the profile and config attributes.
|
|
//////////
|
|
|
|
profile.reserve(profileSize);
|
|
config.reserve(configSize);
|
|
|
|
for (i = all.begin(); i != all.end(); ++i)
|
|
{
|
|
if (i->pAttribute->dwId == IAS_ATTRIBUTE_EAP_CONFIG)
|
|
{
|
|
config.push_back(*i);
|
|
}
|
|
else if (!(i->pAttribute->dwFlags & IAS_RECVD_FROM_PROTOCOL))
|
|
{
|
|
profile.push_back(*i);
|
|
}
|
|
}
|
|
|
|
profile.remove(request);
|
|
|
|
//////////
|
|
// Convert the attributes received from the client to RAS format.
|
|
//////////
|
|
|
|
eapInput.pUserAttributes = new RAS_AUTH_ATTRIBUTE[all.size() + 1];
|
|
|
|
EAPTranslator::translate(
|
|
eapInput.pUserAttributes,
|
|
all,
|
|
IAS_RECVD_FROM_CLIENT
|
|
);
|
|
|
|
//////////
|
|
// Initialize the EAPInput struct.
|
|
//////////
|
|
|
|
eapInput.fAuthenticator = TRUE;
|
|
eapInput.bInitialId = recvPacket->Id + (BYTE)1;
|
|
eapInput.pwszIdentity = account->Value.String.pszWide;
|
|
|
|
switch (request.get_Protocol())
|
|
{
|
|
case IAS_PROTOCOL_RADIUS:
|
|
eapInput.hReserved = theIASEventLog;
|
|
break;
|
|
|
|
case IAS_PROTOCOL_RAS:
|
|
eapInput.hReserved = theRASEventLog;
|
|
break;
|
|
}
|
|
|
|
// Begin the session with the EAP DLL.
|
|
setType(fsm.onBegin());
|
|
|
|
//////////
|
|
// We have successfully established the session, so process the message.
|
|
//////////
|
|
|
|
return process(request, recvPacket);
|
|
}
|
|
|
|
IASREQUESTSTATUS EAPSession::process(
|
|
IASRequest& request,
|
|
PPPP_EAP_PACKET recvPacket
|
|
)
|
|
{
|
|
// Trigger an event on the FSM.
|
|
EAPType* newType;
|
|
switch (fsm.onReceiveEvent(*recvPacket, newType))
|
|
{
|
|
case EAPFSM::MAKE_MESSAGE:
|
|
{
|
|
if (newType != 0)
|
|
{
|
|
setType(newType);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case EAPFSM::REPLAY_LAST:
|
|
{
|
|
IASTraceString("EAP-Message appears to be a retransmission. "
|
|
"Replaying last action.");
|
|
return doAction(request);
|
|
}
|
|
|
|
case EAPFSM::FAIL_NEGOTIATE:
|
|
{
|
|
IASTraceString("EAP negotiation failed. Rejecting user.");
|
|
profile.store(request);
|
|
request.SetResponse(IAS_RESPONSE_ACCESS_REJECT,
|
|
IAS_EAP_NEGOTIATION_FAILED);
|
|
return IAS_REQUEST_STATUS_HANDLED;
|
|
}
|
|
|
|
case EAPFSM::DISCARD:
|
|
{
|
|
IASTraceString("EAP-Message is unexpected. Discarding packet.");
|
|
profile.store(request);
|
|
request.SetResponse(IAS_RESPONSE_DISCARD_PACKET,
|
|
IAS_UNEXPECTED_REQUEST);
|
|
return IAS_REQUEST_STATUS_ABORT;
|
|
}
|
|
}
|
|
|
|
// Allocate a temporary packet to hold the response.
|
|
PPPP_EAP_PACKET tmpPacket = (PPPP_EAP_PACKET)_alloca(maxPacketLength);
|
|
|
|
// Clear the previous output from the DLL.
|
|
eapOutput.clear();
|
|
|
|
DWORD error = currentType->RasEapMakeMessage(
|
|
workBuffer,
|
|
recvPacket,
|
|
tmpPacket,
|
|
maxPacketLength,
|
|
&eapOutput,
|
|
NULL
|
|
);
|
|
if (error != NO_ERROR)
|
|
{
|
|
IASTraceFailure("RasEapMakeMessage", error);
|
|
_com_issue_error(HRESULT_FROM_WIN32(error));
|
|
}
|
|
|
|
while (eapOutput.Action == EAPACTION_Authenticate)
|
|
{
|
|
IASTraceString("EAP DLL invoked default authenticator.");
|
|
|
|
// Authenticate the user.
|
|
DWORD authResult = AuthenticateUser(
|
|
*account,
|
|
eapOutput.pUserAttributes
|
|
);
|
|
|
|
//////////
|
|
// Convert the profile to RAS format.
|
|
//////////
|
|
|
|
DWORD filter;
|
|
|
|
if (authResult == NO_ERROR)
|
|
{
|
|
IASTraceString("Default authentication succeeded.");
|
|
filter = IAS_INCLUDE_IN_ACCEPT;
|
|
}
|
|
else
|
|
{
|
|
IASTraceFailure("Default authentication", authResult);
|
|
filter = IAS_INCLUDE_IN_REJECT;
|
|
}
|
|
|
|
PRAS_AUTH_ATTRIBUTE ras = IAS_STACK_NEW(RAS_AUTH_ATTRIBUTE,
|
|
profile.size() + 1);
|
|
|
|
EAPTranslator::translate(ras, profile, filter);
|
|
|
|
//////////
|
|
// Give the result to the EAP DLL.
|
|
//////////
|
|
|
|
EAPInput authInput;
|
|
authInput.dwAuthResultCode = authResult;
|
|
authInput.fAuthenticationComplete = TRUE;
|
|
authInput.pUserAttributes = ras;
|
|
|
|
eapOutput.clear();
|
|
|
|
error = currentType->RasEapMakeMessage(
|
|
workBuffer,
|
|
NULL,
|
|
tmpPacket,
|
|
maxPacketLength,
|
|
&eapOutput,
|
|
&authInput
|
|
);
|
|
if (error != NO_ERROR)
|
|
{
|
|
IASTraceFailure("RasEapMakeMessage", error);
|
|
_com_issue_error(HRESULT_FROM_WIN32(error));
|
|
}
|
|
}
|
|
|
|
//////////
|
|
// Trigger an event on the FSM.
|
|
//////////
|
|
|
|
fsm.onDllEvent(eapOutput.Action, *tmpPacket);
|
|
|
|
// Clear the old send packet ...
|
|
delete[] sendPacket;
|
|
sendPacket = NULL;
|
|
|
|
// ... and save the new one if available.
|
|
switch (eapOutput.Action)
|
|
{
|
|
case EAPACTION_SendAndDone:
|
|
case EAPACTION_Send:
|
|
case EAPACTION_SendWithTimeout:
|
|
case EAPACTION_SendWithTimeoutInteractive:
|
|
{
|
|
size_t length = IASExtractWORD(tmpPacket->Length);
|
|
sendPacket = (PPPP_EAP_PACKET)new BYTE[length];
|
|
memcpy(sendPacket, tmpPacket, length);
|
|
}
|
|
}
|
|
|
|
//////////
|
|
// Perform the requested action.
|
|
//////////
|
|
|
|
return doAction(request);
|
|
}
|
|
|
|
|
|
IASREQUESTSTATUS EAPSession::doAction(IASRequest& request)
|
|
{
|
|
IASTraceString("Processing output from EAP DLL.");
|
|
|
|
switch (eapOutput.Action)
|
|
{
|
|
case EAPACTION_SendAndDone:
|
|
{
|
|
InjectPacket(request, *sendPacket);
|
|
}
|
|
|
|
case EAPACTION_Done:
|
|
{
|
|
// Add the profile first, so that the EAP DLL can override it.
|
|
profile.store(request);
|
|
|
|
// Special-case the unauthenticated access
|
|
if (eapOutput.dwAuthResultCode == SEC_E_NO_CREDENTIALS)
|
|
{
|
|
// set the auth type to unauthenticated
|
|
DWORD authID = IAS_ATTRIBUTE_AUTHENTICATION_TYPE;
|
|
request.RemoveAttributesByType(1, &authID);
|
|
|
|
IASAttribute authType(true);
|
|
authType->dwId = IAS_ATTRIBUTE_AUTHENTICATION_TYPE;
|
|
authType->Value.itType = IASTYPE_ENUM;
|
|
authType->Value.Enumerator = IAS_AUTH_NONE;
|
|
authType.store(request);
|
|
|
|
// Load the EAP Types attributes into the vector.
|
|
IASAttributeVectorWithBuffer<8> authTypes;
|
|
authTypes.load(request, IAS_ATTRIBUTE_NP_AUTHENTICATION_TYPE);
|
|
for (IASAttributeVector::iterator i = authTypes.begin();
|
|
i != authTypes.end(); ++i)
|
|
{
|
|
if (i->pAttribute->Value.Integer == IAS_AUTH_NONE)
|
|
{
|
|
// Unauthenticated EAP access allowed
|
|
IASTraceString("Unauthenticated EAP access allowed");
|
|
eapOutput.dwAuthResultCode = NO_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update the account lockout database.
|
|
UpdateAccountLockoutDB(
|
|
*account,
|
|
eapOutput.dwAuthResultCode
|
|
);
|
|
|
|
|
|
DWORD flags = eapOutput.dwAuthResultCode ? IAS_INCLUDE_IN_REJECT
|
|
: IAS_INCLUDE_IN_ACCEPT;
|
|
|
|
InjectRASAttributes(request, eapOutput.pUserAttributes, flags);
|
|
|
|
// store the EAP friendly name negotiated for both success and failure
|
|
// if PEAP is used, store the PEAP inside type and update the
|
|
// authentication type from EAP to PEAP
|
|
currentType->storeNameId(request);
|
|
|
|
if (eapOutput.dwAuthResultCode == NO_ERROR)
|
|
{
|
|
IASTraceString("EAP authentication succeeded.");
|
|
request.SetResponse(IAS_RESPONSE_ACCESS_ACCEPT, S_OK);
|
|
}
|
|
else
|
|
{
|
|
IASTraceFailure("EAP authentication", eapOutput.dwAuthResultCode);
|
|
|
|
HRESULT hr = IASMapWin32Error(eapOutput.dwAuthResultCode,
|
|
IAS_AUTH_FAILURE);
|
|
request.SetResponse(IAS_RESPONSE_ACCESS_REJECT, hr);
|
|
}
|
|
|
|
return IAS_REQUEST_STATUS_HANDLED;
|
|
}
|
|
|
|
case EAPACTION_SendWithTimeoutInteractive:
|
|
case EAPACTION_SendWithTimeout:
|
|
{
|
|
if (eapOutput.Action == EAPACTION_SendWithTimeoutInteractive)
|
|
{
|
|
theInteractiveTimeout.store(request);
|
|
}
|
|
else
|
|
{
|
|
theNormalTimeout.store(request);
|
|
}
|
|
}
|
|
|
|
case EAPACTION_Send:
|
|
{
|
|
InjectRASAttributes(request,
|
|
eapOutput.pUserAttributes,
|
|
IAS_INCLUDE_IN_CHALLENGE);
|
|
InjectPacket(request, *sendPacket);
|
|
state.store(request);
|
|
|
|
IASTraceString("Issuing Access-Challenge.");
|
|
|
|
request.SetResponse(IAS_RESPONSE_ACCESS_CHALLENGE, S_OK);
|
|
break;
|
|
}
|
|
|
|
case EAPACTION_NoAction:
|
|
default:
|
|
{
|
|
IASTraceString("EAP DLL returned No Action. Discarding packet.");
|
|
|
|
request.SetResponse(IAS_RESPONSE_DISCARD_PACKET, IAS_INTERNAL_ERROR);
|
|
}
|
|
}
|
|
|
|
return IAS_REQUEST_STATUS_ABORT;
|
|
}
|
|
|
|
extern "C"
|
|
NTSYSAPI
|
|
ULONG
|
|
NTAPI
|
|
RtlRandomEx(
|
|
PULONG Seed
|
|
);
|
|
|
|
HRESULT EAPSession::initialize() throw ()
|
|
{
|
|
IASGlobalLockSentry sentry;
|
|
|
|
if (theRefCount == 0)
|
|
{
|
|
FILETIME ft;
|
|
GetSystemTimeAsFileTime(&ft);
|
|
ULONG seed = (ft.dwLowDateTime ^ ft.dwHighDateTime);
|
|
theNextID = RtlRandomEx(&seed);
|
|
|
|
PIASATTRIBUTE attrs[2];
|
|
DWORD dw = IASAttributeAlloc(2, attrs);
|
|
if (dw != NO_ERROR) { return HRESULT_FROM_WIN32(dw); }
|
|
|
|
theNormalTimeout.attach(attrs[0], false);
|
|
theNormalTimeout->dwId = RADIUS_ATTRIBUTE_SESSION_TIMEOUT;
|
|
theNormalTimeout->Value.itType = IASTYPE_INTEGER;
|
|
theNormalTimeout->Value.Integer = 6;
|
|
theNormalTimeout.setFlag(IAS_INCLUDE_IN_CHALLENGE);
|
|
|
|
theInteractiveTimeout.attach(attrs[1], false);
|
|
theInteractiveTimeout->dwId = RADIUS_ATTRIBUTE_SESSION_TIMEOUT;
|
|
theInteractiveTimeout->Value.itType = IASTYPE_INTEGER;
|
|
theInteractiveTimeout->Value.Integer = 30;
|
|
theInteractiveTimeout.setFlag(IAS_INCLUDE_IN_CHALLENGE);
|
|
|
|
theIASEventLog = RegisterEventSourceW(NULL, L"IAS");
|
|
theRASEventLog = RegisterEventSourceW(NULL, L"RemoteAccess");
|
|
}
|
|
|
|
++theRefCount;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void EAPSession::finalize() throw ()
|
|
{
|
|
IASGlobalLockSentry sentry;
|
|
|
|
if (--theRefCount == 0)
|
|
{
|
|
DeregisterEventSource(theRASEventLog);
|
|
DeregisterEventSource(theIASEventLog);
|
|
theInteractiveTimeout.release();
|
|
theNormalTimeout.release();
|
|
}
|
|
}
|
|
|
|
void EAPSession::clearType() throw ()
|
|
{
|
|
if (currentType != 0)
|
|
{
|
|
currentType->RasEapEnd(workBuffer);
|
|
currentType = 0;
|
|
}
|
|
}
|
|
|
|
void EAPSession::setType(EAPType* newType)
|
|
{
|
|
// If we're switching types, we have to bump the EAP identifier.
|
|
if (currentType != 0)
|
|
{
|
|
++(eapInput.bInitialId);
|
|
}
|
|
|
|
// Try to initialize the new type.
|
|
void* newWorkBuffer = 0;
|
|
if (newType != 0)
|
|
{
|
|
eapInput.pConnectionData = 0;
|
|
eapInput.dwSizeOfConnectionData = 0;
|
|
|
|
// Do we have config data for this EAP type?
|
|
for (IASAttributeVector::const_iterator i = config.begin();
|
|
i != config.end();
|
|
++i)
|
|
{
|
|
const IAS_OCTET_STRING& data = i->pAttribute->Value.OctetString;
|
|
|
|
if (data.lpValue[0] == newType->typeCode())
|
|
{
|
|
// Don't pass first byte to EAP DLL.
|
|
eapInput.pConnectionData = data.lpValue + ALIGN_WORST;
|
|
eapInput.dwSizeOfConnectionData = data.dwLength - ALIGN_WORST;
|
|
break;
|
|
}
|
|
}
|
|
|
|
DWORD error = newType->RasEapBegin(&newWorkBuffer, &eapInput);
|
|
if (error != NO_ERROR)
|
|
{
|
|
IASTraceFailure("RasEapBegin", error);
|
|
_com_issue_error(HRESULT_FROM_WIN32(error));
|
|
}
|
|
}
|
|
|
|
// Success, so clear the old ...
|
|
clearType();
|
|
|
|
// ... and save the new.
|
|
currentType = newType;
|
|
workBuffer = newWorkBuffer;
|
|
}
|