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.
 
 
 
 
 
 

1896 lines
45 KiB

/*
Copyright (c) 1997, Microsoft Corporation, all rights reserved
Description:
Sample Extensible Authentication Protocol. Here is a graphic of the EAP
sample protocol:
Authenticator Authenticatee
------------- -------------
"Send Password"
---------------------->
EAP Request
<password>
<----------------------
EAP Response
----------------------->
Success/Failure
History:
*/
#include <windows.h>
#include <winuser.h>
#include <lmcons.h>
#include <string.h>
#include <stdlib.h>
#include <raseapif.h>
#include <raserror.h>
#include <rtutils.h>
#include <stdio.h>
#define SDEBUGGLOBALS
#define RASEAPGLOBALS
#include "eap.h"
#include "resource.h"
/*---------------------------------------------------------------------------
External entry points
---------------------------------------------------------------------------*/
/*
Notes:
RasEapGetInfo entry point called by the EAP-PPP engine by name.
*/
DWORD APIENTRY
RasEapGetInfo(
IN DWORD dwEapTypeId,
OUT PPP_EAP_INFO* pInfo
)
{
EapTrace("RasEapGetInfo");
if (dwEapTypeId != PPP_EAP_PROTOCOL_ID)
{
//
// We only support PPP_EAP_PROTOCOL_ID eap type
//
EapTrace("Type ID %d is not supported", dwEapTypeId);
return(ERROR_NOT_SUPPORTED);
}
ZeroMemory(pInfo, sizeof(PPP_EAP_INFO));
//
// Fill in the required information
//
pInfo->dwEapTypeId = PPP_EAP_PROTOCOL_ID;
pInfo->RasEapBegin = EapBegin;
pInfo->RasEapEnd = EapEnd;
pInfo->RasEapMakeMessage = EapMakeMessage;
return(NO_ERROR);
}
/*
Notes:
EapBegin entry point called by the EAP PPP engine thru the passed address.
*/
DWORD APIENTRY
EapBegin(
OUT VOID** ppWorkBuf,
IN VOID* pInfo
)
{
PPP_EAP_INPUT* pInput = (PPP_EAP_INPUT*)pInfo;
EAPCB* pwb;
EapTrace("EapBegin(%ws)", pInput->pwszIdentity);
//
// Allocate work buffer.
//
if ((pwb = (EAPCB*)LocalAlloc(LPTR, sizeof(EAPCB))) == NULL)
{
EapTrace("Not enough memory");
return(ERROR_NOT_ENOUGH_MEMORY);
}
//
// Save information passed in, will be used later
//
pwb->fFlags = pInput->fFlags;
pwb->fAuthenticator = pInput->fAuthenticator;
pwb->EapState = MYSTATE_Initial;
pwb->dwInitialPacketId = pInput->bInitialId;
if (pInput->pDataFromInteractiveUI != NULL)
{
pwb->dwSizeOfDataFromInteractiveUI =
pInput->dwSizeOfDataFromInteractiveUI;
pwb->pDataFromInteractiveUI =
LocalAlloc(LPTR, pwb->dwSizeOfDataFromInteractiveUI);
if (NULL != pwb->pDataFromInteractiveUI)
{
CopyMemory(pwb->pDataFromInteractiveUI,
pInput->pDataFromInteractiveUI,
pwb->dwSizeOfDataFromInteractiveUI);
}
}
//
// Save the identity. On the authenticatee side, this is obtained by user
// input; on the authenticator side this was obtained by the Identity
// request message.
//
WideCharToMultiByte(
CP_ACP,
0,
pInput->pwszIdentity,
-1,
pwb->aszIdentity,
UNLEN + 1,
NULL,
NULL );
//
// If we are an authenticatee, then use the password passed in
//
if (!pwb->fAuthenticator)
{
if ( (NULL != pInput->pUserData)
&& (sizeof(EAP_NAME_DIALOG) == pInput->dwSizeOfUserData))
{
WideCharToMultiByte(
CP_ACP,
0,
((EAP_NAME_DIALOG*)(pInput->pUserData))->awszPassword,
-1,
pwb->aszPassword,
PWLEN + 1,
NULL,
NULL );
}
}
//
// Register work buffer with engine.
//
*ppWorkBuf = pwb;
return(NO_ERROR);
}
/*
Notes:
EapEnd entry point called by the PPP engine thru the passed address.
See EAP interface documentation.
*/
DWORD APIENTRY
EapEnd(
IN VOID* pWorkBuf
)
{
EAPCB* pwb = (EAPCB *)pWorkBuf;
if (pwb == NULL)
{
return(NO_ERROR);
}
//
// Release all resources used by this authentication session.
//
EapTrace("EapEnd(%s)", pwb->aszIdentity);
LocalFree(pwb->pUIContext);
LocalFree(pwb->pDataFromInteractiveUI);
if (pwb->pUserAttributes != NULL)
{
//
// Free up Attributes
//
LocalFree(pwb->pUserAttributes[0].Value);
LocalFree(pwb->pUserAttributes[1].Value);
LocalFree(pwb->pUserAttributes);
}
if (pwb->pMPPEKeyAttributes != NULL)
{
//
// Free up the MPPE Key Attributes
//
LocalFree(pwb->pMPPEKeyAttributes[0].Value);
LocalFree(pwb->pMPPEKeyAttributes);
}
ZeroMemory(pwb, sizeof(EAPCB));
LocalFree(pwb);
return(NO_ERROR);
}
/*
Notes:
RasEapMakeMessage entry point called by the PPP engine thru the passed
address.
*/
DWORD APIENTRY
EapMakeMessage(
IN VOID* pWorkBuf,
IN PPP_EAP_PACKET* pReceiveBuf,
OUT PPP_EAP_PACKET* pSendBuf,
IN DWORD cbSendBuf,
OUT PPP_EAP_OUTPUT* pResult,
IN PPP_EAP_INPUT* pInput
)
{
EAPCB* pwb = (EAPCB*)pWorkBuf;
EapTrace("EapMakeMessage(%s)", pwb->aszIdentity);
//
// Call the appropriate routine to process the event.
//
if (pwb->fAuthenticator)
{
return(AuthenticatorMakeMessage(pwb,
pReceiveBuf,
pSendBuf,
cbSendBuf,
pInput,
pResult));
}
else
{
return(AuthenticateeMakeMessage(pwb,
pReceiveBuf,
pSendBuf,
cbSendBuf,
pInput,
pResult));
}
}
/*
Notes:
RasEapGetIdentity entry point called by the EAP-PPP engine by name.
*/
DWORD APIENTRY
RasEapGetIdentity(
IN DWORD dwEapTypeId,
IN HWND hwndParent,
IN DWORD dwFlags,
IN const WCHAR* pwszPhonebook,
IN const WCHAR* pwszEntry,
IN BYTE* pConnectionDataIn,
IN DWORD dwSizeOfConnectionDataIn,
IN BYTE* pUserDataIn,
IN DWORD dwSizeOfUserDataIn,
OUT BYTE** ppUserDataOut,
OUT DWORD* pdwSizeOfUserDataOut,
OUT WCHAR** ppwszIdentity
)
{
DWORD dwErr = NO_ERROR;
if ( dwFlags & RAS_EAP_FLAG_NON_INTERACTIVE )
{
dwErr = ERROR_INTERACTIVE_MODE;
goto LDone;
}
if ( dwFlags & RAS_EAP_FLAG_MACHINE_AUTH )
{
dwErr = ERROR_NOT_SUPPORTED;
goto LDone;
}
if (dwFlags & RAS_EAP_FLAG_ROUTER)
{
//
// A routing interface must have its credentials set beforehand
//
if ( (NULL == pUserDataIn)
|| (sizeof(EAP_NAME_DIALOG) != dwSizeOfUserDataIn))
{
//
// Bad saved credentials
//
EapTrace("Credentials for this interface have not been set");
dwErr = E_FAIL;
goto LDone;
}
}
else
{
//
// Ignore old values. Prompt for username and password.
//
pUserDataIn = NULL;
}
dwErr = GetIdentity(
hwndParent,
pUserDataIn,
dwSizeOfUserDataIn,
ppUserDataOut,
pdwSizeOfUserDataOut,
ppwszIdentity);
LDone:
return(dwErr);
}
/*
Notes:
RasEapInvokeConfigUI entry point called by the EAP-PPP engine by name.
*/
DWORD APIENTRY
RasEapInvokeConfigUI(
IN DWORD dwEapTypeId,
IN HWND hwndParent,
IN DWORD dwFlags,
IN BYTE* pConnectionDataIn,
IN DWORD dwSizeOfConnectionDataIn,
OUT BYTE** ppConnectionDataOut,
OUT DWORD* pdwSizeOfConnectionDataOut
)
{
DWORD dwDisplayedNumber;
WCHAR awszMessage[100];
DWORD dwErr = NO_ERROR;
*ppConnectionDataOut = NULL;
*pdwSizeOfConnectionDataOut = 0;
if ( (NULL == pConnectionDataIn)
|| (0 == dwSizeOfConnectionDataIn))
{
//
// We are configuring for the first time
//
dwDisplayedNumber = 1;
}
else
{
//
// How many times has this been configured?
//
dwDisplayedNumber = *(DWORD*)pConnectionDataIn;
}
swprintf(awszMessage, L"%5d times", dwDisplayedNumber);
MessageBox(hwndParent, awszMessage,
L"You have configured this interface...", MB_OK | MB_ICONINFORMATION);
//
// Allocate memory for the OUT parameter
//
*ppConnectionDataOut = (BYTE*)LocalAlloc(LPTR, sizeof(DWORD));
if (NULL == *ppConnectionDataOut)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
goto LDone;
}
//
// This has been configured one more time
//
dwDisplayedNumber += 1;
//
// Set the OUT parameters
//
CopyMemory(*ppConnectionDataOut, (BYTE*)&dwDisplayedNumber,
sizeof(DWORD));
*pdwSizeOfConnectionDataOut = sizeof(DWORD);
LDone:
return(dwErr);
}
/*
Notes:
RasEapInvokeInteractiveUI entry point called by the EAP-PPP engine by name.
*/
DWORD APIENTRY
RasEapInvokeInteractiveUI(
IN DWORD dwEapTypeId,
IN HWND hWndParent,
IN PBYTE pUIContextData,
IN DWORD dwSizeofUIContextData,
OUT PBYTE * ppDataFromInteractiveUI,
OUT DWORD * lpdwSizeOfDataFromInteractiveUI
)
{
EapTrace("RasEapInvokeInteractiveUI");
if (MessageBox(hWndParent,
(WCHAR*)pUIContextData,
L"EAP sample",
MB_OKCANCEL) == IDOK)
{
*lpdwSizeOfDataFromInteractiveUI = (wcslen(L"OK") + 1) * sizeof(WCHAR);
if ((*ppDataFromInteractiveUI =
LocalAlloc(LPTR, *lpdwSizeOfDataFromInteractiveUI)) == NULL)
{
return(ERROR_NOT_ENOUGH_MEMORY);
}
wcsncpy((WCHAR*)*ppDataFromInteractiveUI, L"OK", (*lpdwSizeOfDataFromInteractiveUI) - 1);
}
else
{
*ppDataFromInteractiveUI = NULL;
*lpdwSizeOfDataFromInteractiveUI = 0;
}
return(NO_ERROR);
}
/*
Notes:
RasEapFreeMemory entry point called by the EAP-PPP engine by name.
*/
DWORD APIENTRY
RasEapFreeMemory(
IN BYTE* pMemory
)
{
EapTrace("RasEapFreeMemory");
LocalFree(pMemory);
return(NO_ERROR);
}
/*---------------------------------------------------------------------------
Internal routines
---------------------------------------------------------------------------*/
/*
Notes:
Print debug information.
*/
VOID
EapTrace(
IN CHAR* Format,
...
)
{
va_list arglist;
va_start(arglist, Format);
TraceVprintfExA(g_dwEapTraceId,
0x00010000 | TRACE_USE_MASK | TRACE_USE_MSEC,
Format,
arglist);
va_end(arglist);
}
/*
Notes:
Will convert a 32 bit integer from host format to wire format.
*/
VOID
HostToWireFormat32(
IN DWORD dwHostFormat,
IN OUT PBYTE pWireFormat
)
{
*((PBYTE)(pWireFormat)+0) = (BYTE) ((DWORD)(dwHostFormat) >> 24);
*((PBYTE)(pWireFormat)+1) = (BYTE) ((DWORD)(dwHostFormat) >> 16);
*((PBYTE)(pWireFormat)+2) = (BYTE) ((DWORD)(dwHostFormat) >> 8);
*((PBYTE)(pWireFormat)+3) = (BYTE) (dwHostFormat);
}
/*
Notes:
Will convert a 16 bit integer from host format to wire format.
*/
VOID
HostToWireFormat16(
IN WORD wHostFormat,
IN OUT PBYTE pWireFormat
)
{
*((PBYTE)(pWireFormat)+0) = (BYTE) ((DWORD)(wHostFormat) >> 8);
*((PBYTE)(pWireFormat)+1) = (BYTE) (wHostFormat);
}
/*
Notes:
Will convert a 16 bit integer from wire format to host format.
*/
WORD
WireToHostFormat16(
IN PBYTE pWireFormat
)
{
WORD wHostFormat = ((*((PBYTE)(pWireFormat)+0) << 8) +
(*((PBYTE)(pWireFormat)+1)));
return(wHostFormat);
}
/*
Notes:
Authenticatee side event handler.
*/
DWORD
AuthenticateeMakeMessage(
IN EAPCB* pwb,
IN PPP_EAP_PACKET* pReceiveBuf,
OUT PPP_EAP_PACKET* pSendBuf,
IN DWORD cbSendBuf,
IN PPP_EAP_INPUT* pInput,
OUT PPP_EAP_OUTPUT* pResult
)
{
DWORD dwRetCode = NO_ERROR;
BYTE* pDataFromInteractiveUI;
DWORD dwSizeOfDataFromInteractiveUI;
EapTrace("AuthenticateeMakeMessage");
switch(pwb->EapState)
{
case MYSTATE_Initial:
if (pwb->fFlags & RAS_EAP_FLAG_ROUTER)
{
pwb->EapState = MYSTATE_WaitForRequest;
break;
}
pwb->bRecvPacketId = pReceiveBuf->Id;
if (NULL == pwb->pDataFromInteractiveUI)
{
WCHAR * pUIContextData = L"You are being authenticated by a Sample EAP";
//
// Bring up interactive UI to notify user that he/she is being
// authenticated via the sample EAP
//
pResult->fInvokeInteractiveUI = TRUE;
pResult->dwSizeOfUIContextData =
(wcslen(pUIContextData)+1) *
sizeof(WCHAR);
pResult->pUIContextData = LocalAlloc(
LPTR,
pResult->dwSizeOfUIContextData);
if (pResult->pUIContextData == NULL)
{
EapTrace("OUt of memory");
return(ERROR_NOT_ENOUGH_MEMORY);
}
wcsncpy((WCHAR*)pResult->pUIContextData,
pUIContextData,
wcslen(pUIContextData)
);
pwb->pUIContext = pResult->pUIContextData;
pwb->EapState = MYSTATE_WaitForUserOK;
break;
}
//
// Else, fall through
//
case MYSTATE_WaitForUserOK:
//
// Wait for response from user
//
if ( pInput->fDataReceivedFromInteractiveUI
|| (NULL != pwb->pDataFromInteractiveUI))
{
if (pInput->fDataReceivedFromInteractiveUI)
{
pDataFromInteractiveUI =
pInput->pDataFromInteractiveUI;
dwSizeOfDataFromInteractiveUI =
pInput->dwSizeOfDataFromInteractiveUI;
}
else
{
pDataFromInteractiveUI =
pwb->pDataFromInteractiveUI;
dwSizeOfDataFromInteractiveUI =
pwb->dwSizeOfDataFromInteractiveUI;
}
LocalFree(pwb->pUIContext);
pwb->pUIContext = NULL;
//
// If user doesn't like this, then we hangup the line
//
if (dwSizeOfDataFromInteractiveUI !=
(wcslen(L"OK")+1) * sizeof(WCHAR))
{
EapTrace("User chose to cancel");
dwRetCode = ERROR_ACCESS_DENIED;
break;
}
if (wcscmp((WCHAR*)pDataFromInteractiveUI, L"OK") != 0)
{
EapTrace("User chose to cancel");
dwRetCode = ERROR_ACCESS_DENIED;
break;
}
pwb->EapState = MYSTATE_WaitForRequest;
}
else
{
//
// Ignore all other events.
//
pResult->Action = EAPACTION_NoAction;
}
if ( !(pwb->fFlags & RAS_EAP_FLAG_8021X_AUTH ) )
{
//
// if this is a VPN client, we can rely on
// retransmission. But with wireless client
// we cannot do that.
//
break;
}
//fall thru
case MYSTATE_WaitForRequest:
if ( (pwb->fFlags & RAS_EAP_FLAG_8021X_AUTH ) )
{
//
// Build the response packet
//
MakeResponseMessage1(pwb, pSendBuf, cbSendBuf);
//
// Response packets should not be sent with any timeout
//
pResult->Action = EAPACTION_Send;
//
// We are done so we change to MYSTATE_Done
//
pwb->EapState = MYSTATE_Done;
break;
}
else if (pReceiveBuf != NULL )
{
//
// If we received a request packet from the server then we
// process it.
//
if (pReceiveBuf->Code == EAPCODE_Request)
{
//
// Build the response packet
//
MakeResponseMessage(pwb, pReceiveBuf, pSendBuf, cbSendBuf);
//
// Response packets should not be sent with any timeout
//
pResult->Action = EAPACTION_Send;
//
// We are done so we change to MYSTATE_Done
//
pwb->EapState = MYSTATE_Done;
break;
}
else
{
//
// We shouldn't get any other packet in this state so
// we simply drop this invalid packet
//
pResult->Action = EAPACTION_NoAction;
dwRetCode = ERROR_PPP_INVALID_PACKET;
break;
}
}
break;
case MYSTATE_Done:
{
if (pReceiveBuf == NULL)
{
//
// If we did not receive a packet then we check to see if
// the fSuccessPacketReceived flag is set
//
if ((pInput != NULL) && (pInput->fSuccessPacketReceived))
{
//
// We are done
//
//
// Create the MPPE Key Attribute and give it to the EAP-PPP
// engine.
//
dwRetCode = MakeMPPEKeyAttributes(pwb);
if (NO_ERROR == dwRetCode)
{
pResult->pUserAttributes = pwb->pMPPEKeyAttributes;
}
pResult->Action = EAPACTION_Done;
pwb->EapState = MYSTATE_Done;
}
else
{
//
// Otherwise we ignore this event
//
pResult->Action = EAPACTION_NoAction;
}
break;
}
if ((pReceiveBuf->Code == EAPCODE_Success) ||
(pReceiveBuf->Code == EAPCODE_Failure))
{
if (pReceiveBuf->Code == EAPCODE_Success)
{
//
// If we received success or failure, we are done, but first
// make sure the ID's match
//
//
// Create the MPPE Key Attribute and give it to the EAP-PPP
// engine.
//
dwRetCode = MakeMPPEKeyAttributes(pwb);
if (NO_ERROR == dwRetCode)
{
pResult->pUserAttributes = pwb->pMPPEKeyAttributes;
}
pResult->Action = EAPACTION_Done;
pwb->EapState = MYSTATE_Done;
}
else
{
//
// Otherwise drop the packet
//
pResult->Action = EAPACTION_NoAction;
dwRetCode = ERROR_PPP_INVALID_PACKET;
}
break;
}
else if (pReceiveBuf->Code == EAPCODE_Request)
{
//
// We must always respond to requests
//
MakeResponseMessage(pwb, pReceiveBuf, pSendBuf, cbSendBuf);
//
// Response packets should not be sent with any timeout
//
pResult->Action = EAPACTION_Send;
}
else
{
//
// Otherwise we received an illegal packet, wrong code set
// So simply drop the packet.
//
pResult->Action = EAPACTION_NoAction;
dwRetCode = ERROR_PPP_INVALID_PACKET;
}
}
}
return(dwRetCode);
}
VOID
MakeResponseMessage1(
IN EAPCB* pwb,
OUT PPP_EAP_PACKET * pSendBuf,
IN DWORD cbSendBuf
)
{
BYTE* pcbPassword;
CHAR* pchPassword;
EapTrace("MakeResponseMessage1");
(void)cbSendBuf;
//
// Fill in the password.
//
pcbPassword = pSendBuf->Data + 1;
*pcbPassword = (BYTE)strlen(pwb->aszPassword);
pchPassword = pcbPassword + 1;
strcpy(pchPassword, pwb->aszPassword);
//
// Set the response code
//
pSendBuf->Code = (BYTE)EAPCODE_Response;
//
// The Reponse packet Id MUST match the Request packet Id.
//
pSendBuf->Id = pwb->bRecvPacketId;
//
// The Success/Failure packet that we get must match the ID of the last
// response sent
//
pwb->dwIdExpected = pSendBuf->Id;
//
// Set the EAP type ID
//
pSendBuf->Data[0] = (BYTE)PPP_EAP_PROTOCOL_ID;
//
// Set the length of the packet
//
HostToWireFormat16((WORD)(PPP_EAP_PACKET_HDR_LEN+1+*pcbPassword+1),
pSendBuf->Length);
}
/*
Notes:
Builds a response packet. 'pwb' is the address of the work
buffer associated with the port.
*/
VOID
MakeResponseMessage(
IN EAPCB* pwb,
IN PPP_EAP_PACKET * pReceiveBuf,
OUT PPP_EAP_PACKET * pSendBuf,
IN DWORD cbSendBuf
)
{
BYTE* pcbPassword;
CHAR* pchPassword;
EapTrace("MakeResponseMessage");
(void)cbSendBuf;
//
// Fill in the password.
//
pcbPassword = pSendBuf->Data + 1;
*pcbPassword = (BYTE)strlen(pwb->aszPassword);
pchPassword = pcbPassword + 1;
strcpy(pchPassword, pwb->aszPassword);
//
// Set the response code
//
pSendBuf->Code = (BYTE)EAPCODE_Response;
//
// The Reponse packet Id MUST match the Request packet Id.
//
pSendBuf->Id = pReceiveBuf->Id;
//
// The Success/Failure packet that we get must match the ID of the last
// response sent
//
pwb->dwIdExpected = pSendBuf->Id;
//
// Set the EAP type ID
//
pSendBuf->Data[0] = (BYTE)PPP_EAP_PROTOCOL_ID;
//
// Set the length of the packet
//
HostToWireFormat16((WORD)(PPP_EAP_PACKET_HDR_LEN+1+*pcbPassword+1),
pSendBuf->Length);
}
/*
Notes:
Builds a result packet (Success or Failure) in caller's 'pSendBuf'
buffer. 'cbSendBuf' is the length of caller's buffer.
'dwError' indicates whether an Success or Failure should be generated,
'bId' is the Id of the Success of Failure packet.
*/
VOID
MakeResultMessage(
IN EAPCB * pwb,
IN DWORD dwError,
OUT PPP_EAP_PACKET* pSendBuf,
IN DWORD cbSendBuf
)
{
EapTrace("MakeResultMessage");
(void)cbSendBuf;
//
// If there was no error then we send a Success packet, otherwise we send
// a failure message
//
if (dwError == NO_ERROR)
{
pSendBuf->Code = EAPCODE_Success;
}
else
{
pSendBuf->Code = EAPCODE_Failure;
}
//
// The Id of a success or failure message MUST match the Id of the last
// response received from the client according to the EAP spec.
//
pSendBuf->Id = (BYTE)pwb->dwInitialPacketId;
//
// Set the length
//
HostToWireFormat16((WORD)PPP_EAP_PACKET_HDR_LEN, (PBYTE)pSendBuf->Length);
}
/*
Notes:
Will build a request packet.
*/
VOID
MakeRequestMessage(
IN EAPCB* pwb,
OUT PPP_EAP_PACKET * pSendBuf,
IN DWORD cbSendBuf
)
{
BYTE *pcbPeerMessage;
CHAR *pchPeerMessage;
EapTrace("MakeRequestMessage");
pcbPeerMessage = pSendBuf->Data + 1;
*pcbPeerMessage = (BYTE)strlen("send password");
pchPeerMessage = pcbPeerMessage + 1;
strncpy(pchPeerMessage, "send password", strlen ("send password"));
//
// Set the Request Code
//
pSendBuf->Code = EAPCODE_Request;
//
// Set the request packet identifier. Start with the Id that was give to us
//
pSendBuf->Id = (BYTE)pwb->dwInitialPacketId;
//
// Set the length
//
HostToWireFormat16((WORD)(PPP_EAP_PACKET_HDR_LEN+1+*pcbPeerMessage+1),
pSendBuf->Length);
//
// Set the EAP Type Id
//
pSendBuf->Data[0] = PPP_EAP_PROTOCOL_ID;
}
/*
Notes:
Authenticator side event handler.
*/
DWORD
AuthenticatorMakeMessage(
IN EAPCB* pwb,
IN PPP_EAP_PACKET* pReceiveBuf,
OUT PPP_EAP_PACKET* pSendBuf,
IN DWORD cbSendBuf,
IN PPP_EAP_INPUT* pInput,
OUT PPP_EAP_OUTPUT* pResult
)
{
DWORD dwRetCode = NO_ERROR;
EapTrace("AuthenticatorMakeMessage");
switch(pwb->EapState)
{
case MYSTATE_ReqSent:
if (pReceiveBuf != NULL)
{
//
// If we received a packet
//
if (pReceiveBuf->Code == EAPCODE_Response)
{
//
// If we received a response to our identity request,
// then process it. There is no need to check the Id
// here since the PPP engine will only pass on packets
// whose Id matches those set with the
// EAPACTION_SendWithTimeout action.
//
dwRetCode = GetPasswordFromResponse(pReceiveBuf,
pwb->aszPassword);
if (dwRetCode != NO_ERROR)
{
if (dwRetCode != ERROR_PPP_INVALID_PACKET)
{
//
// Fatal error, we fail the connection.
//
return(dwRetCode);
}
}
else
{
//
// Request authentication provider to authenticate
// this user.
//
dwRetCode = MakeAuthenticationAttributes(
pwb->aszIdentity,
pwb->aszPassword,
pwb);
if (dwRetCode != NO_ERROR)
{
return(dwRetCode);
}
else
{
//
// Authentication request completed successfully.
// This is an asynchronous call so we change state
// and wait for the provider to complete the
// authentication.
//
pResult->pUserAttributes = pwb->pUserAttributes;
pResult->Action = EAPACTION_Authenticate;
//
// Save Id so that we can send the correct one
// in the success/failure packet
//
pwb->dwIdExpected = pReceiveBuf->Id;
pwb->EapState =
MYSTATE_WaitForAuthenticationToComplete;
}
}
break;
}
else
{
//
// Otherwise silently drop the packet.
// We should only get requests
//
pResult->Action = EAPACTION_NoAction;
break;
}
}
break;
case MYSTATE_Initial:
//
// Create Request packet
//
MakeRequestMessage(pwb, pSendBuf, cbSendBuf);
//
// Request messages must be sent with a timeout
//
pResult->Action = EAPACTION_SendWithTimeoutInteractive;
//
// Since we have sent a request we change to the ReqSent state
// where we will wait for a response.
//
pwb->EapState = MYSTATE_ReqSent;
break;
case MYSTATE_WaitForAuthenticationToComplete:
{
if (pInput != NULL)
{
//
// Did the authentication provider complete the authentication?
//
if (pInput->fAuthenticationComplete)
{
//
// If the user failed to authenticate, save the failure
// code.
//
if (pInput->dwAuthResultCode != NO_ERROR)
{
pwb->dwResult = pInput->dwAuthResultCode;
}
pResult->Action = EAPACTION_SendAndDone;
pwb->EapState = MYSTATE_Done;
//
// fall thru to the MYSTATE_Done state where we will
// send a Success or Failure packet
//
}
}
if ((pInput == NULL) || (!pInput->fAuthenticationComplete))
{
//
// Ignore everything if authentication is not complete
//
pResult->Action = EAPACTION_NoAction;
break;
}
//
// ...fall thru to the MYSTATE_Done state where we will
// send a Success or Failure packet
//
}
case MYSTATE_Done:
{
//
// Make Success or Failure packet.
//
MakeResultMessage(pwb, pwb->dwResult, pSendBuf, cbSendBuf);
if (NO_ERROR == pwb->dwResult)
{
//
// If we made a Success packet, create the MPPE Key Attribute
// and give it to the EAP-PPP engine.
//
dwRetCode = MakeMPPEKeyAttributes(pwb);
if (NO_ERROR == dwRetCode)
{
pResult->pUserAttributes = pwb->pMPPEKeyAttributes;
}
}
pResult->Action = EAPACTION_SendAndDone;
pResult->dwAuthResultCode = pwb->dwResult;
break;
}
default:
break;
}
return(dwRetCode);
}
/*
Notes:
Fill caller's pszPassword' buffer with the password, in the request
packet.
Returns NO_ERROR if successful., or ERROR_PPP_INVALID_PACKET if the
packet is misformatted in any way.
*/
DWORD
GetPasswordFromResponse(
IN PPP_EAP_PACKET* pReceiveBuf,
OUT CHAR* pszPassword
)
{
BYTE* pcbPassword;
CHAR* pchPassword;
WORD cbPacket;
EapTrace("GetPasswordFromResponse");
cbPacket = WireToHostFormat16(pReceiveBuf->Length);
//
// Extract the password
//
if (cbPacket < (PPP_EAP_PACKET_HDR_LEN + 1 + 1))
{
EapTrace("Number of bytes in the EAP packet is only %d", cbPacket);
return(ERROR_PPP_INVALID_PACKET);
}
pcbPassword = pReceiveBuf->Data + 1;
pchPassword = pcbPassword + 1;
if (cbPacket < PPP_EAP_PACKET_HDR_LEN + 1 + 1 + *pcbPassword)
{
EapTrace("Number of characters in password is %d", *pcbPassword);
EapTrace("Number of bytes in the EAP packet is only %d", cbPacket);
return ERROR_PPP_INVALID_PACKET;
}
if ( *pcbPassword > PWLEN )
{
EapTrace ("Password length received in the packet is > PWLEN" );
return ERROR_PPP_INVALID_PACKET;
}
CopyMemory(pszPassword, pchPassword, *pcbPassword);
//
// NULL terminate the password
//
pszPassword[ *pcbPassword ] = '\0';
return(NO_ERROR);
}
/*
Notes:
Will build user attributes and send them to the authentication provider
for authentication.
*/
DWORD
MakeAuthenticationAttributes(
IN CHAR * szUserName,
IN CHAR * szPassword,
IN EAPCB * pwb
)
{
EapTrace("MakeAuthenticationAttributes");
if (pwb->pUserAttributes != NULL)
{
LocalFree(pwb->pUserAttributes[0].Value);
LocalFree(pwb->pUserAttributes[1].Value);
LocalFree(pwb->pUserAttributes);
pwb->pUserAttributes = NULL;
}
pwb->pUserAttributes = (RAS_AUTH_ATTRIBUTE *)
LocalAlloc(LPTR, sizeof (RAS_AUTH_ATTRIBUTE) * 3);
if (pwb->pUserAttributes == NULL)
{
return(GetLastError());
}
//
// for user name
//
pwb->pUserAttributes[0].raaType = raatUserName;
pwb->pUserAttributes[0].dwLength = strlen(szUserName);
pwb->pUserAttributes[0].Value = LocalAlloc(LPTR, (strlen(szUserName)+1));
if (pwb->pUserAttributes[0].Value == NULL)
{
LocalFree(pwb->pUserAttributes);
pwb->pUserAttributes = NULL;
return(GetLastError());
}
CopyMemory(pwb->pUserAttributes[0].Value,szUserName, strlen(szUserName));
//
// for password
//
pwb->pUserAttributes[1].raaType = raatUserPassword;
pwb->pUserAttributes[1].dwLength = strlen(szPassword);
pwb->pUserAttributes[1].Value = LocalAlloc(LPTR, (strlen(szPassword)+1));
if (pwb->pUserAttributes[1].Value == NULL)
{
LocalFree(pwb->pUserAttributes[0].Value);
LocalFree(pwb->pUserAttributes);
pwb->pUserAttributes = NULL;
return(GetLastError());
}
CopyMemory(pwb->pUserAttributes[1].Value,szPassword, strlen(szPassword));
//
// For Termination
//
pwb->pUserAttributes[2].raaType = raatMinimum;
pwb->pUserAttributes[2].dwLength = 0;
pwb->pUserAttributes[2].Value = NULL;
return(NO_ERROR);
}
/*
Notes:
*/
DWORD
MakeMPPEKeyAttributes(
IN EAPCB * pwb
)
{
DWORD dwErr = NO_ERROR;
DWORD dwIndex;
DWORD dwSendPattern;
DWORD dwRecvPattern;
BYTE* pByte;
EapTrace("MakeMPPEKeyAttributes");
if (NULL != pwb->pMPPEKeyAttributes)
{
//
// Free up the MPPE Key Attributes if they exist
//
LocalFree(pwb->pMPPEKeyAttributes[0].Value);
LocalFree(pwb->pMPPEKeyAttributes[1].Value);
LocalFree(pwb->pMPPEKeyAttributes);
pwb->pMPPEKeyAttributes = NULL;
}
//
// We need 3 RAS_AUTH_ATTRIBUTE structs: for MS-MPPE-Send-Key,
// MS-MPPE-Recv-Key, and termination
//
pwb->pMPPEKeyAttributes = (RAS_AUTH_ATTRIBUTE *) LocalAlloc(
LPTR, sizeof(RAS_AUTH_ATTRIBUTE) * 3);
if (NULL == pwb->pMPPEKeyAttributes)
{
dwErr = GetLastError();
goto LDone;
}
if (pwb->fAuthenticator)
{
dwSendPattern = 0xAB;
dwRecvPattern = 0xCD;
}
else
{
dwSendPattern = 0xCD;
dwRecvPattern = 0xAB;
}
//
// Bytes needed:
// 4: Vendor-Id
// 1: Vendor-Type
// 1: Vendor-Length
// 2: Salt
// 1: Key-Length
// 32: Key
// 15: Padding
// -----------------
// 56: Total
//
//
// Copy MS-MPPE-Send-Key
//
pwb->pMPPEKeyAttributes[0].Value = LocalAlloc(LPTR, 56);
if (pwb->pMPPEKeyAttributes[0].Value == NULL)
{
dwErr = GetLastError();
goto LDone;
}
pByte = pwb->pMPPEKeyAttributes[0].Value;
HostToWireFormat32(311, pByte); // Vendor-Id
pByte[4] = 16; // Vendor-Type (MS-MPPE-Send-Key)
pByte[5] = 56 - 4; // Vendor-Length (all except Vendor-Id)
// pByte[6-7] is the zero-filled salt field
pByte[8] = 32; // Key-Length
{
//
// This is just an example. Copy a real key here.
//
CopyMemory(pByte + 9, pwb->aszPassword, 32);
for (dwIndex = 0; dwIndex < 32; dwIndex++)
{
pByte[9 + dwIndex] ^= dwSendPattern;
}
}
// pByte[41-55] is the Padding (zero octets)
pwb->pMPPEKeyAttributes[0].dwLength = 56;
pwb->pMPPEKeyAttributes[0].raaType = raatVendorSpecific;
//
// Copy MS-MPPE-Recv-Key
//
pwb->pMPPEKeyAttributes[1].Value = LocalAlloc(LPTR, 56);
if (pwb->pMPPEKeyAttributes[1].Value == NULL)
{
dwErr = GetLastError();
goto LDone;
}
pByte = pwb->pMPPEKeyAttributes[1].Value;
HostToWireFormat32(311, pByte); // Vendor-Id
pByte[4] = 17; // Vendor-Type (MS-MPPE-Recv-Key)
pByte[5] = 56 - 4; // Vendor-Length (all except Vendor-Id)
// pByte[6-7] is the zero-filled salt field
pByte[8] = 32; // Key-Length
{
//
// This is just an example. Copy a real key here.
//
CopyMemory(pByte + 9, pwb->aszPassword, 32);
for (dwIndex = 0; dwIndex < 32; dwIndex++)
{
pByte[9 + dwIndex] ^= dwRecvPattern;
}
}
// pByte[41-55] is the Padding (zero octets)
pwb->pMPPEKeyAttributes[1].dwLength = 56;
pwb->pMPPEKeyAttributes[1].raaType = raatVendorSpecific;
//
// For Termination
//
pwb->pMPPEKeyAttributes[2].raaType = raatMinimum;
pwb->pMPPEKeyAttributes[2].dwLength = 0;
pwb->pMPPEKeyAttributes[2].Value = NULL;
LDone:
if (NO_ERROR != dwErr)
{
//
// If something failed, free the allocated memory
//
if (pwb->pMPPEKeyAttributes != NULL)
{
LocalFree(pwb->pMPPEKeyAttributes[0].Value);
LocalFree(pwb->pMPPEKeyAttributes[1].Value);
LocalFree(pwb->pMPPEKeyAttributes);
pwb->pMPPEKeyAttributes = NULL;
}
}
return(dwErr);
}
/*
Notes:
*/
DWORD
GetIdentity(
IN HWND hwndParent,
IN BYTE* pUserDataIn,
IN DWORD dwSizeOfUserDataIn,
OUT BYTE** ppUserDataOut,
OUT DWORD* pdwSizeOfUserDataOut,
OUT WCHAR** ppwszIdentity
)
{
EAP_NAME_DIALOG* pEapNameDialog = NULL;
WCHAR* pwszIdentity = NULL;
DWORD dwErr = NO_ERROR;
//
// Allocate memory for OUT parameters
//
pEapNameDialog = LocalAlloc(LPTR, sizeof(EAP_NAME_DIALOG));
if (NULL == pEapNameDialog)
{
EapTrace("Out of memory");
dwErr = GetLastError();
goto LDone;
}
pwszIdentity = LocalAlloc(LPTR, (UNLEN + 1) * sizeof(WCHAR));
if (NULL == pwszIdentity)
{
EapTrace("Out of memory");
dwErr = GetLastError();
goto LDone;
}
if (NULL != pUserDataIn)
{
//
// Use the saved credentials if they exist
//
CopyMemory(pEapNameDialog, pUserDataIn, sizeof(EAP_NAME_DIALOG));
}
else
{
//
// Else prompt for username and password
//
GetUsernameAndPassword(hwndParent, pEapNameDialog);
}
wcscpy(pwszIdentity, pEapNameDialog->awszIdentity);
//
// Set the OUT paramters
//
*ppUserDataOut = (BYTE*)pEapNameDialog;
*pdwSizeOfUserDataOut = sizeof(EAP_NAME_DIALOG);
*ppwszIdentity = pwszIdentity;
//
// We mustn't LocalFree OUT parameters
//
pEapNameDialog = NULL;
pwszIdentity = NULL;
LDone:
LocalFree(pEapNameDialog);
LocalFree(pwszIdentity);
return(dwErr);
}
/*---------------------------------------------------------------------------
Dialog routines
---------------------------------------------------------------------------*/
/*
Notes:
Displays the IDD_DIALOG dialog, and fills up pEapNameDialog with the
username and password.
*/
VOID
GetUsernameAndPassword(
IN HWND hwndParent,
IN EAP_NAME_DIALOG* pEapNameDialog
)
{
DialogBoxParam(
g_hInstance,
MAKEINTRESOURCE(IDD_DIALOG),
hwndParent,
UsernameDialogProc,
(LPARAM)pEapNameDialog);
}
/*
Notes:
Callback function used with the DialogBoxParam function. It processes
messages sent to the dialog box. See the DialogProc documentation in MSDN.
*/
INT_PTR CALLBACK
UsernameDialogProc(
IN HWND hWnd,
IN UINT unMsg,
IN WPARAM wParam,
IN LPARAM lParam
)
{
EAP_NAME_DIALOG* pEapNameDialog;
switch (unMsg)
{
case WM_INITDIALOG:
return(InitUsernameDialog(hWnd, lParam));
case WM_COMMAND:
pEapNameDialog = (EAP_NAME_DIALOG*)GetWindowLongPtr(hWnd, DWLP_USER);
return(UsernameCommand(pEapNameDialog, LOWORD(wParam), hWnd));
}
return(FALSE);
}
/*
Returns:
FALSE (prevent Windows from setting the default keyboard focus).
Notes:
Response to the WM_INITDIALOG message.
*/
BOOL
InitUsernameDialog(
IN HWND hWnd,
IN LPARAM lParam
)
{
HWND hWndEdit;
SetWindowLongPtr(hWnd, DWLP_USER, lParam);
return(FALSE);
}
/*
Returns:
TRUE: We prrocessed this message.
FALSE: We did not prrocess this message.
Notes:
Response to the WM_COMMAND message.
*/
BOOL
UsernameCommand(
IN EAP_NAME_DIALOG* pEapNameDialog,
IN WORD wId,
IN HWND hWndDlg
)
{
HWND hWnd;
switch(wId)
{
case IDOK:
//
// Save whatever the user typed in as the user name
//
hWnd = GetDlgItem(hWndDlg, IDC_EDIT_NAME);
GetWindowText(hWnd, pEapNameDialog->awszIdentity, UNLEN + 1);
//
// Save whatever the user typed in as the password
//
hWnd = GetDlgItem(hWndDlg, IDC_EDIT_PASSWD);
GetWindowText(hWnd, pEapNameDialog->awszPassword, PWLEN + 1);
// Fall through
case IDCANCEL:
EndDialog(hWndDlg, wId);
return(TRUE);
default:
return(FALSE);
}
}