719 lines
19 KiB
C++
719 lines
19 KiB
C++
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Copyright (c) 1998, Microsoft Corp. All rights reserved.
|
||
|
//
|
||
|
// FILE
|
||
|
//
|
||
|
// EAPSession.cpp
|
||
|
//
|
||
|
// SYNOPSIS
|
||
|
//
|
||
|
// This file defines the class EAPSession.
|
||
|
//
|
||
|
// MODIFICATION HISTORY
|
||
|
//
|
||
|
// 01/15/1998 Original version.
|
||
|
// 06/02/1998 Pass NT4-Account-Name for the identity.
|
||
|
// 06/12/1998 Changed put_Response to SetResponse.
|
||
|
// 07/29/1998 Preserve all attributes added by pipeline.
|
||
|
// 08/27/1998 Use new EAPFSM class.
|
||
|
// 10/09/1998 Preserve order when saving profile attributes.
|
||
|
// 10/13/1998 Add maxPacketLength property.
|
||
|
// 10/24/1998 Account lockout support.
|
||
|
// 11/13/1998 Pass event log handle to RasEapBegin.
|
||
|
// 11/24/1998 Don't accept a Framed-MTU of less than 64 bytes.
|
||
|
// 02/03/1999 Change NP-Authentication-Type to 5.
|
||
|
// 02/13/1999 MPPE keys are returned as type 26.
|
||
|
// 05/04/1999 New error codes.
|
||
|
// 05/11/1999 Fix RADIUS encryption.
|
||
|
// 05/20/1999 Identity is now a Unicode string.
|
||
|
// 02/17/2000 Key encryption is now handled by the protocol.
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#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>
|
||
|
|
||
|
// 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;
|
||
|
|
||
|
request.RemoveAttributesByType(1, &(i->pAttribute->dwId));
|
||
|
}
|
||
|
|
||
|
//////////
|
||
|
// Add them to the request.
|
||
|
//////////
|
||
|
|
||
|
iasAttrs.store(request);
|
||
|
}
|
||
|
|
||
|
//////////
|
||
|
// Performs NT-SAM PAP and MD5-CHAP authentication based on RAS attributes.
|
||
|
//////////
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
AuthenticateUser(
|
||
|
IAS_STRING& account,
|
||
|
RAS_AUTH_ATTRIBUTE* pInAttributes
|
||
|
) throw ()
|
||
|
{
|
||
|
//////////
|
||
|
// Check the input parameters.
|
||
|
//////////
|
||
|
if (!pInAttributes) { return NO_ERROR; }
|
||
|
|
||
|
//////////
|
||
|
// Get the NT-SAM userName and domain.
|
||
|
//////////
|
||
|
|
||
|
PCWSTR userName, domain;
|
||
|
EXTRACT_SAM_IDENTITY(account, domain, userName);
|
||
|
|
||
|
//////////
|
||
|
// 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);
|
||
|
|
||
|
HANDLE token;
|
||
|
status = IASLogonCHAP(
|
||
|
userName,
|
||
|
domain,
|
||
|
challengeID,
|
||
|
(PBYTE)(rasMD5CHAPChallenge->Value),
|
||
|
rasMD5CHAPChallenge->dwLength,
|
||
|
chapPassword,
|
||
|
&token
|
||
|
);
|
||
|
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);
|
||
|
|
||
|
HANDLE token;
|
||
|
status = IASLogonPAP(
|
||
|
userName,
|
||
|
domain,
|
||
|
userPwd,
|
||
|
&token
|
||
|
);
|
||
|
CloseHandle(token);
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
//////////
|
||
|
// Updates the AccountLockout database.
|
||
|
//////////
|
||
|
VOID
|
||
|
WINAPI
|
||
|
UpdateAcccountLockoutDB(
|
||
|
IAS_STRING& account,
|
||
|
DWORD authResult
|
||
|
) throw ()
|
||
|
{
|
||
|
// Get the NT-SAM userName and domain.
|
||
|
PCWSTR userName, domain;
|
||
|
EXTRACT_SAM_IDENTITY(account, domain, userName);
|
||
|
|
||
|
// 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, const EAPType& eapType)
|
||
|
: id((DWORD)InterlockedIncrement(&theNextID)),
|
||
|
type(eapType),
|
||
|
account(accountName),
|
||
|
state(EAPState::createAttribute(id), false),
|
||
|
fsm((BYTE)eapType.dwEapTypeId),
|
||
|
maxPacketLength(FRAMED_MTU_DEFAULT - FRAME_HEADER_LENGTH),
|
||
|
workBuffer(NULL),
|
||
|
sendPacket(NULL)
|
||
|
{ }
|
||
|
|
||
|
EAPSession::~EAPSession() throw ()
|
||
|
{
|
||
|
delete[] sendPacket;
|
||
|
if (workBuffer) { type.RasEapEnd(workBuffer); }
|
||
|
}
|
||
|
|
||
|
IASREQUESTSTATUS EAPSession::begin(
|
||
|
IASRequest& request,
|
||
|
PPPP_EAP_PACKET recvPacket
|
||
|
)
|
||
|
{
|
||
|
//////////
|
||
|
// Get all the attributes from the request.
|
||
|
//////////
|
||
|
|
||
|
USES_IAS_STACK_VECTOR();
|
||
|
IASAttributeVectorOnStack(all, request, 0);
|
||
|
all.load(request, 0, NULL);
|
||
|
|
||
|
//////////
|
||
|
// Scan for the Framed-MTU attribute and compute the profile size.
|
||
|
//////////
|
||
|
|
||
|
DWORD profileSize = 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->dwFlags & IAS_RECVD_FROM_PROTOCOL))
|
||
|
{
|
||
|
++profileSize;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////
|
||
|
// Save and remove the profile attributes.
|
||
|
//////////
|
||
|
|
||
|
profile.reserve(profileSize);
|
||
|
|
||
|
for (i = all.begin(); i != all.end(); ++i)
|
||
|
{
|
||
|
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.
|
||
|
//////////
|
||
|
|
||
|
PRAS_AUTH_ATTRIBUTE ras = IAS_STACK_NEW(RAS_AUTH_ATTRIBUTE, all.size() + 1);
|
||
|
EAPTranslator::translate(ras, all, IAS_RECVD_FROM_CLIENT);
|
||
|
|
||
|
//////////
|
||
|
// Initialize the EAPInput struct.
|
||
|
//////////
|
||
|
|
||
|
EAPInput eapInput;
|
||
|
eapInput.fAuthenticator = TRUE;
|
||
|
eapInput.pUserAttributes = ras;
|
||
|
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.
|
||
|
//////////
|
||
|
|
||
|
DWORD error = type.RasEapBegin(&workBuffer, &eapInput);
|
||
|
|
||
|
if (error != NO_ERROR)
|
||
|
{
|
||
|
IASTraceFailure("RasEapBegin", error);
|
||
|
|
||
|
request.SetResponse(IAS_RESPONSE_DISCARD_PACKET, IAS_INTERNAL_ERROR);
|
||
|
return IAS_REQUEST_STATUS_ABORT;
|
||
|
}
|
||
|
|
||
|
//////////
|
||
|
// 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.
|
||
|
switch (fsm.onReceiveEvent(*recvPacket))
|
||
|
{
|
||
|
case EAPFSM::MAKE_MESSAGE:
|
||
|
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.");
|
||
|
request.SetResponse(IAS_RESPONSE_ACCESS_REJECT,
|
||
|
IAS_UNSUPPORTED_AUTH_TYPE);
|
||
|
return IAS_REQUEST_STATUS_HANDLED;
|
||
|
|
||
|
case EAPFSM::DISCARD:
|
||
|
IASTraceString("EAP-Message is unexpected. Discarding packet.");
|
||
|
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;
|
||
|
|
||
|
error = type.RasEapMakeMessage(
|
||
|
workBuffer,
|
||
|
recvPacket,
|
||
|
tmpPacket,
|
||
|
maxPacketLength,
|
||
|
&eapOutput,
|
||
|
NULL
|
||
|
);
|
||
|
if (error != NO_ERROR)
|
||
|
{
|
||
|
IASTraceFailure("RasEapMakeMessage", error);
|
||
|
request.SetResponse(IAS_RESPONSE_DISCARD_PACKET, IAS_INTERNAL_ERROR);
|
||
|
return IAS_REQUEST_STATUS_ABORT;
|
||
|
}
|
||
|
|
||
|
while (eapOutput.Action == EAPACTION_Authenticate)
|
||
|
{
|
||
|
IASTraceString("EAP DLL invoked default authenticator.");
|
||
|
|
||
|
// Authenticate the user.
|
||
|
DWORD authResult = AuthenticateUser(
|
||
|
account->Value.String,
|
||
|
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 = type.RasEapMakeMessage(
|
||
|
workBuffer,
|
||
|
NULL,
|
||
|
tmpPacket,
|
||
|
maxPacketLength,
|
||
|
&eapOutput,
|
||
|
&authInput
|
||
|
);
|
||
|
if (error != NO_ERROR)
|
||
|
{
|
||
|
IASTraceFailure("RasEapMakeMessage", error);
|
||
|
request.SetResponse(IAS_RESPONSE_DISCARD_PACKET, IAS_INTERNAL_ERROR);
|
||
|
return IAS_REQUEST_STATUS_ABORT;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//////////
|
||
|
// 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:
|
||
|
{
|
||
|
// Update the account lockout database.
|
||
|
UpdateAcccountLockoutDB(
|
||
|
account->Value.String,
|
||
|
eapOutput.dwAuthResultCode
|
||
|
);
|
||
|
|
||
|
// Add the profile first, so that the EAP DLL can override it.
|
||
|
profile.store(request);
|
||
|
|
||
|
DWORD flags = eapOutput.dwAuthResultCode ? IAS_INCLUDE_IN_REJECT
|
||
|
: IAS_INCLUDE_IN_ACCEPT;
|
||
|
|
||
|
InjectRASAttributes(request, eapOutput.pUserAttributes, flags);
|
||
|
|
||
|
if (eapOutput.dwAuthResultCode == NO_ERROR)
|
||
|
{
|
||
|
IASTraceString("EAP authentication succeeded.");
|
||
|
|
||
|
type.getFriendlyName().store(request);
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT EAPSession::initialize() throw ()
|
||
|
{
|
||
|
std::_Lockit _Lk;
|
||
|
|
||
|
if (theRefCount == 0)
|
||
|
{
|
||
|
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 ()
|
||
|
{
|
||
|
std::_Lockit _Lk;
|
||
|
|
||
|
if (--theRefCount == 0)
|
||
|
{
|
||
|
DeregisterEventSource(theRASEventLog);
|
||
|
DeregisterEventSource(theIASEventLog);
|
||
|
theInteractiveTimeout.release();
|
||
|
theNormalTimeout.release();
|
||
|
}
|
||
|
}
|