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.
1318 lines
34 KiB
1318 lines
34 KiB
/********************************************************************/
|
|
/** Copyright(c) 1985-1998 Microsoft Corporation. **/
|
|
/********************************************************************/
|
|
|
|
//***
|
|
//
|
|
// Filename: radclnt.c
|
|
//
|
|
// Description: Main module of the RADIUS client
|
|
//
|
|
// History: Feb 11,1998 NarenG Created original version.
|
|
//
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#include <windows.h>
|
|
#include <lmcons.h>
|
|
#include <lmapibuf.h>
|
|
#include <lmaccess.h>
|
|
#include <raserror.h>
|
|
#include <time.h>
|
|
#include <string.h>
|
|
#include <rasauth.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <rtutils.h>
|
|
#include <mprlog.h>
|
|
#include <mprerror.h>
|
|
#define INCL_RASAUTHATTRIBUTES
|
|
#define INCL_HOSTWIRE
|
|
#include <ppputil.h>
|
|
#include "hmacmd5.h"
|
|
#include "md5.h"
|
|
#define ALLOCATE_GLOBALS
|
|
#include "radclnt.h"
|
|
|
|
|
|
//
|
|
// Perfmon Counters
|
|
//
|
|
|
|
#pragma data_seg(".shdat")
|
|
LONG g_cAuthReqSent = 0; // Auth Requests Sent
|
|
LONG g_cAuthReqFailed = 0; // Auth Requests Failed
|
|
LONG g_cAuthReqSucceded = 0; // Auth Requests Succeded
|
|
LONG g_cAuthReqTimeout = 0; // Auth Requests timeouts
|
|
LONG g_cAcctReqSent = 0; // Acct Requests Sent
|
|
LONG g_cAcctBadPack = 0; // Acct Bad packets
|
|
LONG g_cAcctReqSucceded = 0; // Acct Requests Succeded
|
|
LONG g_cAcctReqTimeout = 0; // Acct Requests timeouts
|
|
LONG g_cAuthBadPack = 0; // Auth Bad packets
|
|
|
|
#pragma data_seg()
|
|
|
|
//**
|
|
//
|
|
// Call: RasAuthProviderInitialize
|
|
//
|
|
// Returns: NO_ERROR - Success
|
|
// Non-zero returns - Failure
|
|
//
|
|
// Description: Initialize all global parameters here.
|
|
// Called up each process only once.
|
|
// Each RAS_AuthInitialize should be matched with RAS_AuthTerminate
|
|
//
|
|
DWORD APIENTRY
|
|
RasAuthProviderInitialize(
|
|
IN RAS_AUTH_ATTRIBUTE * pServerAttributes,
|
|
IN HANDLE hLogEvents,
|
|
IN DWORD dwLoggingLevel
|
|
)
|
|
{
|
|
WSADATA WSAData;
|
|
DWORD dwErrorCode = NO_ERROR;
|
|
|
|
do
|
|
{
|
|
if ( g_dwTraceID == INVALID_TRACEID )
|
|
{
|
|
g_dwTraceID = TraceRegister( TEXT("RADIUS") );
|
|
}
|
|
|
|
if ( g_hLogEvents == INVALID_HANDLE_VALUE )
|
|
{
|
|
g_hLogEvents = RouterLogRegister( TEXT("RemoteAccess") );
|
|
}
|
|
|
|
//
|
|
// Init Winsock
|
|
//
|
|
|
|
if ( !fWinsockInitialized )
|
|
{
|
|
dwErrorCode = WSAStartup(MAKEWORD(1, 1), &WSAData);
|
|
|
|
if ( dwErrorCode != ERROR_SUCCESS )
|
|
{
|
|
break;
|
|
}
|
|
|
|
fWinsockInitialized = TRUE;
|
|
}
|
|
|
|
//
|
|
// Init Crypto
|
|
//
|
|
|
|
if ( !g_hCryptProv )
|
|
{
|
|
if (!CryptAcquireContext(
|
|
&g_hCryptProv,
|
|
0,
|
|
0,
|
|
PROV_RSA_FULL,
|
|
CRYPT_VERIFYCONTEXT
|
|
))
|
|
{
|
|
dwErrorCode = GetLastError();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( g_AuthServerListHead.Flink == NULL )
|
|
{
|
|
//
|
|
// Load global list of RADIUS servers
|
|
//
|
|
|
|
InitializeRadiusServerList( TRUE );
|
|
}
|
|
|
|
dwErrorCode = LoadRadiusServers( TRUE );
|
|
|
|
if ( dwErrorCode != ERROR_SUCCESS )
|
|
{
|
|
break;
|
|
}
|
|
|
|
}while( FALSE );
|
|
|
|
if ( dwErrorCode != NO_ERROR )
|
|
{
|
|
RasAuthProviderTerminate();
|
|
}
|
|
|
|
return( dwErrorCode );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: RasAuthProviderTerminate
|
|
//
|
|
// Returns: NO_ERROR - Success
|
|
// Non-zero returns - Failure
|
|
//
|
|
// Description: Cleanup for entire process
|
|
// Called once per process
|
|
//
|
|
DWORD APIENTRY
|
|
RasAuthProviderTerminate(
|
|
VOID
|
|
)
|
|
{
|
|
if ( g_AuthServerListHead.Flink != NULL )
|
|
{
|
|
FreeRadiusServerList( TRUE );
|
|
}
|
|
|
|
if ( fWinsockInitialized )
|
|
{
|
|
WSACleanup();
|
|
|
|
fWinsockInitialized = FALSE;
|
|
}
|
|
|
|
if ( g_dwTraceID != INVALID_TRACEID )
|
|
{
|
|
TraceDeregister( g_dwTraceID );
|
|
|
|
g_dwTraceID = INVALID_TRACEID;
|
|
}
|
|
|
|
if ( !g_hCryptProv )
|
|
{
|
|
CryptReleaseContext(g_hCryptProv, 0);
|
|
g_hCryptProv = 0;
|
|
}
|
|
|
|
if ( g_hLogEvents != INVALID_HANDLE_VALUE )
|
|
{
|
|
RouterLogDeregister( g_hLogEvents );
|
|
|
|
g_hLogEvents = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
return( NO_ERROR );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: RasAuthProviderFreeAttributes
|
|
//
|
|
// Returns: NO_ERROR - Success
|
|
// Non-zero returns - Failure
|
|
//
|
|
// Description:
|
|
//
|
|
DWORD APIENTRY
|
|
RasAuthProviderFreeAttributes(
|
|
IN RAS_AUTH_ATTRIBUTE * pAttributes
|
|
)
|
|
{
|
|
RasAuthAttributeDestroy( pAttributes );
|
|
|
|
return( NO_ERROR );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: RasAuthProviderAuthenticateUser
|
|
//
|
|
// Returns: NO_ERROR - Success
|
|
// Non-zero returns - Failure
|
|
//
|
|
// Description: Takes a list of radius attributes and tries to authenticate
|
|
// with a radius server.
|
|
// INPUT: Array of RADIUS attributes RAS_AUTH_ATTRIBUTE[]
|
|
// OUTPUT: Header packet followed by array of RADIUS attributes
|
|
// RAS_AUTH_ATTRIBUTE[]
|
|
//
|
|
DWORD APIENTRY
|
|
RasAuthProviderAuthenticateUser(
|
|
IN RAS_AUTH_ATTRIBUTE * prgInAttributes,
|
|
OUT RAS_AUTH_ATTRIBUTE ** pprgOutAttributes,
|
|
OUT DWORD * lpdwResultCode
|
|
)
|
|
{
|
|
DWORD dwError = NO_ERROR;
|
|
BYTE bCode;
|
|
BOOL fEapMessageReceived;
|
|
|
|
RADIUS_TRACE("RasAuthenticateUser called");
|
|
|
|
do
|
|
{
|
|
if (lpdwResultCode == NULL)
|
|
{
|
|
dwError = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
bCode = ptAccessRequest;
|
|
|
|
if ((dwError = SendData2ServerWRetry( prgInAttributes,
|
|
pprgOutAttributes,
|
|
&bCode,
|
|
atInvalid,
|
|
&fEapMessageReceived )
|
|
) == NO_ERROR )
|
|
{
|
|
switch (bCode)
|
|
{
|
|
case ptAccessAccept:
|
|
|
|
InterlockedIncrement( &g_cAuthReqSucceded );
|
|
|
|
*lpdwResultCode = ERROR_SUCCESS;
|
|
|
|
break;
|
|
|
|
case ptAccessChallenge:
|
|
|
|
if ( fEapMessageReceived )
|
|
{
|
|
*lpdwResultCode = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
*lpdwResultCode = ERROR_AUTHENTICATION_FAILURE;
|
|
}
|
|
|
|
break;
|
|
|
|
case ptAccessReject:
|
|
|
|
InterlockedIncrement(&g_cAuthReqFailed);
|
|
|
|
*lpdwResultCode = ERROR_AUTHENTICATION_FAILURE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
InterlockedIncrement(&g_cAuthBadPack);
|
|
|
|
*lpdwResultCode = ERROR_AUTHENTICATION_FAILURE;
|
|
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( dwError == ERROR_INVALID_RADIUS_RESPONSE )
|
|
{
|
|
InterlockedIncrement(&g_cAuthBadPack);
|
|
}
|
|
}
|
|
|
|
}while( FALSE );
|
|
|
|
return( dwError );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: RasAuthConfigChangeNotification
|
|
//
|
|
// Returns: NO_ERROR - Success
|
|
// Non-zero returns - Failure
|
|
//
|
|
// Description: Reloads config information dynamically
|
|
//
|
|
DWORD APIENTRY
|
|
RasAuthConfigChangeNotification(
|
|
IN DWORD dwLoggingLevel
|
|
)
|
|
{
|
|
DWORD dwError = NO_ERROR;
|
|
|
|
RADIUS_TRACE("RasAuthConfigChangeNotification called");
|
|
|
|
return( ReloadConfig( TRUE ) );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: RasAcctProviderInitialize
|
|
//
|
|
// Returns: NO_ERROR - Success
|
|
// Non-zero returns - Failure
|
|
//
|
|
// Description: Do nothing since all the work is done by
|
|
// RasAuthProviderInitialize
|
|
//
|
|
DWORD APIENTRY
|
|
RasAcctProviderInitialize(
|
|
IN RAS_AUTH_ATTRIBUTE * pServerAttributes,
|
|
IN HANDLE hLogEvents,
|
|
IN DWORD dwLoggingLevel
|
|
)
|
|
{
|
|
WSADATA WSAData;
|
|
DWORD dwErrorCode = NO_ERROR;
|
|
|
|
do
|
|
{
|
|
if ( g_dwTraceID == INVALID_TRACEID )
|
|
{
|
|
g_dwTraceID = TraceRegister( TEXT("RADIUS") );
|
|
}
|
|
|
|
if ( g_hLogEvents == INVALID_HANDLE_VALUE )
|
|
{
|
|
g_hLogEvents = RouterLogRegister( TEXT("RemoteAccess") );
|
|
}
|
|
|
|
//
|
|
// Init Winsock
|
|
//
|
|
|
|
if ( !fWinsockInitialized )
|
|
{
|
|
dwErrorCode = WSAStartup(MAKEWORD(1, 1), &WSAData);
|
|
|
|
if ( dwErrorCode != ERROR_SUCCESS )
|
|
{
|
|
break;
|
|
}
|
|
|
|
fWinsockInitialized = TRUE;
|
|
}
|
|
|
|
//
|
|
// Load global list of RADIUS servers
|
|
//
|
|
|
|
if ( g_AcctServerListHead.Flink == NULL )
|
|
{
|
|
InitializeRadiusServerList( FALSE );
|
|
}
|
|
|
|
//
|
|
// Make a copy of the Server attributes
|
|
//
|
|
|
|
g_pServerAttributes = RasAuthAttributeCopy( pServerAttributes );
|
|
|
|
if ( g_pServerAttributes == NULL )
|
|
{
|
|
dwErrorCode = GetLastError();
|
|
|
|
break;
|
|
}
|
|
|
|
dwErrorCode = LoadRadiusServers( FALSE );
|
|
|
|
if ( dwErrorCode != ERROR_SUCCESS )
|
|
{
|
|
break;
|
|
}
|
|
|
|
}while( FALSE );
|
|
|
|
if ( dwErrorCode != ERROR_SUCCESS )
|
|
{
|
|
RasAuthProviderTerminate();
|
|
}
|
|
|
|
return( dwErrorCode );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: RasAcctProviderTerminate
|
|
//
|
|
// Returns: NO_ERROR - Success
|
|
// Non-zero returns - Failure
|
|
//
|
|
// Description: Do nothing since all the work is done by
|
|
// RasAuthProviderTerminate
|
|
//
|
|
DWORD APIENTRY
|
|
RasAcctProviderTerminate(
|
|
VOID
|
|
)
|
|
{
|
|
if ( g_AcctServerListHead.Flink != NULL )
|
|
{
|
|
FreeRadiusServerList( FALSE );
|
|
}
|
|
|
|
if ( fWinsockInitialized )
|
|
{
|
|
WSACleanup();
|
|
|
|
fWinsockInitialized = FALSE;
|
|
}
|
|
|
|
if ( g_pServerAttributes != NULL )
|
|
{
|
|
RasAuthAttributeDestroy( g_pServerAttributes );
|
|
|
|
g_pServerAttributes = NULL;
|
|
}
|
|
|
|
if ( g_dwTraceID != INVALID_TRACEID )
|
|
{
|
|
TraceDeregister( g_dwTraceID );
|
|
|
|
g_dwTraceID = INVALID_TRACEID;
|
|
}
|
|
|
|
if ( g_hLogEvents != INVALID_HANDLE_VALUE )
|
|
{
|
|
RouterLogDeregister( g_hLogEvents );
|
|
|
|
g_hLogEvents = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
return( NO_ERROR );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: RasAcctProviderFreeAttributes
|
|
//
|
|
// Returns: NO_ERROR - Success
|
|
// Non-zero returns - Failure
|
|
//
|
|
// Description:
|
|
//
|
|
DWORD APIENTRY
|
|
RasAcctProviderFreeAttributes(
|
|
IN RAS_AUTH_ATTRIBUTE * pAttributes
|
|
)
|
|
{
|
|
RasAuthAttributeDestroy( pAttributes );
|
|
|
|
return( NO_ERROR );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: RasAcctProviderStartAccounting
|
|
//
|
|
// Returns: NO_ERROR - Success
|
|
// Non-zero returns - Failure
|
|
//
|
|
// Description:
|
|
//
|
|
DWORD APIENTRY
|
|
RasAcctProviderStartAccounting(
|
|
IN RAS_AUTH_ATTRIBUTE *prgInAttributes,
|
|
OUT RAS_AUTH_ATTRIBUTE **pprgOutAttributes
|
|
)
|
|
{
|
|
DWORD dwError = NO_ERROR;
|
|
BYTE bCode;
|
|
BOOL fEapMessageReceived;
|
|
|
|
RADIUS_TRACE("RasStartAccounting called");
|
|
|
|
do
|
|
{
|
|
bCode = ptAccountingRequest;
|
|
|
|
if ((dwError = SendData2ServerWRetry( prgInAttributes,
|
|
pprgOutAttributes,
|
|
&bCode,
|
|
atStart,
|
|
&fEapMessageReceived )
|
|
) == NO_ERROR )
|
|
{
|
|
if (bCode == ptAccountingResponse)
|
|
{
|
|
InterlockedIncrement(&g_cAcctReqSucceded);
|
|
}
|
|
else
|
|
{
|
|
InterlockedIncrement(&g_cAcctBadPack);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( dwError == ERROR_INVALID_RADIUS_RESPONSE )
|
|
{
|
|
InterlockedIncrement(&g_cAcctBadPack);
|
|
}
|
|
}
|
|
|
|
}while( FALSE );
|
|
|
|
return( dwError );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: RasAcctProviderStopAccounting
|
|
//
|
|
// Returns: NO_ERROR - Success
|
|
// Non-zero returns - Failure
|
|
//
|
|
// Description:
|
|
//
|
|
DWORD APIENTRY
|
|
RasAcctProviderStopAccounting(
|
|
IN RAS_AUTH_ATTRIBUTE *prgInAttributes,
|
|
OUT RAS_AUTH_ATTRIBUTE **pprgOutAttributes
|
|
)
|
|
{
|
|
DWORD dwError = NO_ERROR;
|
|
BYTE bCode;
|
|
BOOL fEapMessageReceived;
|
|
|
|
RADIUS_TRACE("RasStopAccounting called");
|
|
|
|
do
|
|
{
|
|
bCode = ptAccountingRequest;
|
|
|
|
if ((dwError = SendData2ServerWRetry( prgInAttributes,
|
|
pprgOutAttributes,
|
|
&bCode,
|
|
atStop,
|
|
&fEapMessageReceived)
|
|
) == NO_ERROR )
|
|
{
|
|
if (bCode == ptAccountingResponse)
|
|
{
|
|
InterlockedIncrement(&g_cAcctReqSucceded);
|
|
}
|
|
else
|
|
{
|
|
InterlockedIncrement(&g_cAcctBadPack);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( dwError == ERROR_INVALID_RADIUS_RESPONSE )
|
|
{
|
|
InterlockedIncrement(&g_cAcctBadPack);
|
|
}
|
|
}
|
|
|
|
}while( FALSE );
|
|
|
|
return( dwError );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: RasAcctProviderInterimAccounting
|
|
//
|
|
// Returns: NO_ERROR - Success
|
|
// Non-zero returns - Failure
|
|
//
|
|
// Description:
|
|
//
|
|
DWORD APIENTRY
|
|
RasAcctProviderInterimAccounting(
|
|
IN RAS_AUTH_ATTRIBUTE *prgInAttributes,
|
|
OUT RAS_AUTH_ATTRIBUTE **pprgOutAttributes
|
|
)
|
|
{
|
|
DWORD dwError = NO_ERROR;
|
|
BYTE bCode;
|
|
BOOL fEapMessageReceived;
|
|
|
|
RADIUS_TRACE("RasInterimAccounting called");
|
|
|
|
do
|
|
{
|
|
bCode = ptAccountingRequest;
|
|
|
|
if ((dwError = SendData2ServerWRetry( prgInAttributes,
|
|
pprgOutAttributes,
|
|
&bCode,
|
|
atInterimUpdate,
|
|
&fEapMessageReceived ))
|
|
== NO_ERROR )
|
|
{
|
|
if ( bCode == ptAccountingResponse )
|
|
{
|
|
InterlockedIncrement( &g_cAcctReqSucceded );
|
|
}
|
|
else
|
|
{
|
|
InterlockedIncrement( &g_cAcctBadPack );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( dwError == ERROR_INVALID_RADIUS_RESPONSE )
|
|
{
|
|
InterlockedIncrement( &g_cAcctBadPack );
|
|
}
|
|
}
|
|
|
|
}while( FALSE );
|
|
|
|
return( dwError );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: RasAcctConfigChangeNotification
|
|
//
|
|
// Returns: NO_ERROR - Success
|
|
// Non-zero returns - Failure
|
|
//
|
|
// Description: Reloads config information dynamically
|
|
//
|
|
DWORD APIENTRY
|
|
RasAcctConfigChangeNotification(
|
|
IN DWORD dwLoggingLevel
|
|
)
|
|
{
|
|
DWORD dwError = NO_ERROR;
|
|
|
|
RADIUS_TRACE("RasAcctConfigChangeNotification called");
|
|
|
|
return( ReloadConfig( FALSE ) );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: SendData2Server
|
|
//
|
|
// Returns: NO_ERROR - Success
|
|
// Non-zero returns - Failure
|
|
//
|
|
// Description: Will do the real work of sending the Access/Accounting Request
|
|
// packets to the server and receive the reponse back
|
|
//
|
|
DWORD
|
|
SendData2Server(
|
|
IN PRAS_AUTH_ATTRIBUTE prgInAttributes,
|
|
OUT PRAS_AUTH_ATTRIBUTE * pprgOutAttributes,
|
|
IN BYTE * pbCode,
|
|
IN BYTE bSubCode,
|
|
IN LONG lPacketID,
|
|
IN DWORD dwRetryCount,
|
|
OUT BOOL * pfEapMessageReceived
|
|
)
|
|
{
|
|
SOCKET SockServer = INVALID_SOCKET;
|
|
DWORD dwError = NO_ERROR;
|
|
DWORD dwExtError = 0;
|
|
DWORD dwNumAttributes = 0;
|
|
|
|
do
|
|
{
|
|
BYTE szSendBuffer[MAXBUFFERSIZE];
|
|
BYTE szRecvBuffer[MAXBUFFERSIZE];
|
|
RADIUS_PACKETHEADER UNALIGNED * pSendHeader = NULL;
|
|
RADIUS_PACKETHEADER UNALIGNED * pRecvHeader = NULL;
|
|
BYTE UNALIGNED * pSignature = NULL;
|
|
BYTE UNALIGNED * prgBuffer = NULL;
|
|
INT AttrLength = 0;
|
|
PRAS_AUTH_ATTRIBUTE pAttribute = NULL;
|
|
RADIUS_ATTRIBUTE UNALIGNED * pRadiusAttribute;
|
|
fd_set fdsSocketRead;
|
|
RADIUSSERVER RadiusServer;
|
|
MD5_CTX MD5c;
|
|
DWORD dwLength = 0;
|
|
|
|
if (prgInAttributes == NULL || pprgOutAttributes == NULL)
|
|
{
|
|
dwError = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
*pprgOutAttributes = NULL;
|
|
|
|
//
|
|
// Pick a RADIUS server
|
|
//
|
|
|
|
if ( ChooseRadiusServer( &RadiusServer,
|
|
(*pbCode == ptAccessRequest )
|
|
? FALSE
|
|
: TRUE,
|
|
lPacketID ) == NULL )
|
|
{
|
|
dwError = ERROR_NO_RADIUS_SERVERS;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set packet type to Access-Request
|
|
//
|
|
|
|
pSendHeader = (PRADIUS_PACKETHEADER)szSendBuffer;
|
|
pSendHeader->bCode = *pbCode;
|
|
pSendHeader->bIdentifier = RadiusServer.bIdentifier;
|
|
pSendHeader->wLength = sizeof(RADIUS_PACKETHEADER);
|
|
|
|
//
|
|
// Set the request authenticator to a random value
|
|
//
|
|
//Bugid:507955 - need to do CryptGenRandom to get the Authenticator
|
|
|
|
if (!CryptGenRandom(
|
|
g_hCryptProv,
|
|
MAX_AUTHENTICATOR,
|
|
pSendHeader->rgAuthenticator
|
|
))
|
|
{
|
|
dwError = GetLastError();
|
|
break;
|
|
}
|
|
|
|
#if 0
|
|
srand( (unsigned)time( NULL ) );
|
|
|
|
*((WORD*)(pSendHeader->rgAuthenticator)) = (WORD)rand();
|
|
*((WORD*)(pSendHeader->rgAuthenticator+2)) = (WORD)rand();
|
|
*((WORD*)(pSendHeader->rgAuthenticator+4)) = (WORD)rand();
|
|
*((WORD*)(pSendHeader->rgAuthenticator+6)) = (WORD)rand();
|
|
*((WORD*)(pSendHeader->rgAuthenticator+8)) = (WORD)rand();
|
|
*((WORD*)(pSendHeader->rgAuthenticator+10)) = (WORD)rand();
|
|
*((WORD*)(pSendHeader->rgAuthenticator+12)) = (WORD)rand();
|
|
*((WORD*)(pSendHeader->rgAuthenticator+14)) = (WORD)rand();
|
|
#endif
|
|
//
|
|
// Find length of all attribute values
|
|
//
|
|
|
|
pAttribute = prgInAttributes;
|
|
|
|
prgBuffer = (PBYTE) (pSendHeader + 1);
|
|
|
|
//
|
|
// Convert Attributes to RADIUS format
|
|
//
|
|
|
|
dwError = Router2Radius( prgInAttributes,
|
|
(RADIUS_ATTRIBUTE *) prgBuffer,
|
|
&RadiusServer,
|
|
pSendHeader,
|
|
bSubCode,
|
|
dwRetryCount,
|
|
&pSignature,
|
|
&dwLength );
|
|
|
|
if ( dwError != NO_ERROR )
|
|
{
|
|
break;
|
|
}
|
|
|
|
pSendHeader->wLength += (WORD)dwLength;
|
|
|
|
//
|
|
// Convert length to network order
|
|
//
|
|
|
|
pSendHeader->wLength = htons( pSendHeader->wLength );
|
|
|
|
//
|
|
// set encryption block for accounting packets
|
|
//
|
|
|
|
if ( pSendHeader->bCode == ptAccountingRequest )
|
|
{
|
|
RadiusServer.IPAddress.sin_port =
|
|
htons((SHORT)RadiusServer.AcctPort);
|
|
|
|
ZeroMemory( pSendHeader->rgAuthenticator,
|
|
sizeof(pSendHeader->rgAuthenticator));
|
|
|
|
MD5Init( &MD5c );
|
|
|
|
MD5Update( &MD5c, szSendBuffer, ntohs(pSendHeader->wLength ));
|
|
|
|
MD5Update( &MD5c,
|
|
(PBYTE) RadiusServer.szSecret,
|
|
RadiusServer.cbSecret);
|
|
|
|
MD5Final(&MD5c);
|
|
|
|
CopyMemory( pSendHeader->rgAuthenticator,
|
|
MD5c.digest,
|
|
sizeof(pSendHeader->rgAuthenticator));
|
|
}
|
|
else
|
|
{
|
|
RadiusServer.IPAddress.sin_port =
|
|
htons((SHORT) RadiusServer.AuthPort);
|
|
}
|
|
|
|
//
|
|
// If a Signature field is present we need to sign it
|
|
//
|
|
|
|
if ( pSignature != NULL )
|
|
{
|
|
HmacContext HmacMD5c;
|
|
BYTE MD5d[MD5_LEN];
|
|
|
|
HmacMD5Init( &HmacMD5c,
|
|
(PBYTE) RadiusServer.szSecret,
|
|
RadiusServer.cbSecret);
|
|
|
|
HmacMD5Update( &HmacMD5c,
|
|
szSendBuffer,
|
|
ntohs(pSendHeader->wLength) );
|
|
|
|
HmacMD5Final( MD5d, &HmacMD5c );
|
|
|
|
CopyMemory( (pSignature+2), MD5d, 16 );
|
|
}
|
|
|
|
//
|
|
// Create a Datagram socket
|
|
//
|
|
|
|
SockServer = socket( AF_INET, SOCK_DGRAM, 0 );
|
|
|
|
if ( SockServer == INVALID_SOCKET )
|
|
{
|
|
dwError = WSAGetLastError();
|
|
RADIUS_TRACE1("Socket failed with error %d", dwError );
|
|
break;
|
|
}
|
|
|
|
if ( RadiusServer.nboNASIPAddress != INADDR_NONE )
|
|
{
|
|
if ( bind( SockServer,
|
|
(PSOCKADDR)&RadiusServer.NASIPAddress,
|
|
sizeof(RadiusServer.NASIPAddress) ) == SOCKET_ERROR )
|
|
{
|
|
dwError = WSAGetLastError();
|
|
RADIUS_TRACE1("Bind failed with error %d", dwError );
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( connect( SockServer,
|
|
(PSOCKADDR)&RadiusServer.IPAddress,
|
|
sizeof(RadiusServer.IPAddress) ) == SOCKET_ERROR )
|
|
{
|
|
dwError = WSAGetLastError();
|
|
RADIUS_TRACE1("Connect failed with error %d", dwError );
|
|
break;
|
|
}
|
|
|
|
RADIUS_TRACE("Sending packet to radius server");
|
|
|
|
TraceSendPacket( szSendBuffer, ntohs( pSendHeader->wLength ) );
|
|
|
|
//
|
|
// Send packet if server doesn't respond within a give amount of time.
|
|
//
|
|
|
|
if ( send( SockServer,
|
|
(PCSTR)szSendBuffer,
|
|
ntohs(pSendHeader->wLength), 0) == SOCKET_ERROR )
|
|
{
|
|
dwError = GetLastError();
|
|
|
|
break;
|
|
}
|
|
|
|
FD_ZERO(&fdsSocketRead);
|
|
FD_SET(SockServer, &fdsSocketRead);
|
|
|
|
if ( select( 0, &fdsSocketRead, NULL, NULL,
|
|
RadiusServer.Timeout.tv_sec == 0
|
|
? NULL
|
|
: &RadiusServer.Timeout ) < 1 )
|
|
{
|
|
//
|
|
// Server didn't respond to any of the requests.
|
|
// time to quit asking
|
|
//
|
|
|
|
ValidateRadiusServer(
|
|
&RadiusServer,
|
|
FALSE,
|
|
!( pSendHeader->bCode == ptAccountingRequest ) );
|
|
|
|
RADIUS_TRACE("Timeout: Radius server did not respond");
|
|
|
|
dwError = ERROR_AUTH_SERVER_TIMEOUT;
|
|
|
|
break;
|
|
}
|
|
|
|
AttrLength = recv( SockServer, (PSTR)szRecvBuffer, MAXBUFFERSIZE, 0 );
|
|
|
|
if ( AttrLength == SOCKET_ERROR )
|
|
{
|
|
//
|
|
// A response from the machine that the server is not
|
|
// running at the designated port.
|
|
//
|
|
|
|
ValidateRadiusServer( &RadiusServer,
|
|
FALSE,
|
|
!(pSendHeader->bCode == ptAccountingRequest));
|
|
|
|
RADIUS_TRACE( "Radius server not running at specifed IPaddr/port");
|
|
|
|
dwError = ERROR_AUTH_SERVER_TIMEOUT;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Response received from server. First update the score for
|
|
// this server
|
|
//
|
|
|
|
ValidateRadiusServer( &RadiusServer,
|
|
TRUE,
|
|
!( pSendHeader->bCode == ptAccountingRequest ));
|
|
|
|
pRecvHeader = (PRADIUS_PACKETHEADER) szRecvBuffer;
|
|
|
|
RADIUS_TRACE("Received packet from radius server");
|
|
TraceRecvPacket(szRecvBuffer, ntohs(pRecvHeader->wLength));
|
|
|
|
dwError = VerifyPacketIntegrity( AttrLength,
|
|
pRecvHeader,
|
|
pSendHeader,
|
|
&RadiusServer,
|
|
pRecvHeader->bCode,
|
|
&dwExtError,
|
|
&dwNumAttributes );
|
|
|
|
if ( dwError == NO_ERROR )
|
|
{
|
|
//
|
|
// Convert to Router attribute format
|
|
//
|
|
|
|
dwError = Radius2Router(
|
|
pRecvHeader,
|
|
&RadiusServer,
|
|
(PBYTE)(pSendHeader->rgAuthenticator),
|
|
dwNumAttributes,
|
|
&dwExtError,
|
|
pprgOutAttributes,
|
|
pfEapMessageReceived );
|
|
}
|
|
|
|
if ( dwError == ERROR_INVALID_RADIUS_RESPONSE )
|
|
{
|
|
LPWSTR auditstrp[2];
|
|
auditstrp[0] = RadiusServer.wszName;
|
|
|
|
RadiusLogWarningString( ROUTERLOG_INVALID_RADIUS_RESPONSE,
|
|
1, auditstrp, dwExtError, 1 );
|
|
|
|
dwError = ERROR_AUTH_SERVER_TIMEOUT;
|
|
}
|
|
else
|
|
{
|
|
*pbCode = pRecvHeader->bCode;
|
|
}
|
|
|
|
} while( FALSE );
|
|
|
|
if ( SockServer != INVALID_SOCKET )
|
|
{
|
|
closesocket( SockServer );
|
|
}
|
|
|
|
return( dwError );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: VerifyPacketIntegrity
|
|
//
|
|
// Returns: NO_ERROR - Success
|
|
// Non-zero returns - Failure
|
|
//
|
|
// Description:
|
|
//
|
|
DWORD
|
|
VerifyPacketIntegrity(
|
|
IN DWORD cbPacketLength,
|
|
IN RADIUS_PACKETHEADER UNALIGNED * pRecvHeader,
|
|
IN RADIUS_PACKETHEADER UNALIGNED * pSendHeader,
|
|
IN RADIUSSERVER * pRadiusServer,
|
|
IN BYTE bCode,
|
|
OUT DWORD * pdwExtError,
|
|
OUT DWORD * lpdwNumAttributes
|
|
)
|
|
{
|
|
MD5_CTX MD5c;
|
|
RADIUS_ATTRIBUTE UNALIGNED * prgRadiusWalker;
|
|
LONG cbLengthOfRadiusAttributes;
|
|
LONG cbLength;
|
|
|
|
*pdwExtError = 0;
|
|
*lpdwNumAttributes = 0;
|
|
|
|
if ( ( cbPacketLength < 20 ) ||
|
|
( ntohs( pRecvHeader->wLength ) != cbPacketLength ) ||
|
|
( pRecvHeader->bIdentifier != pSendHeader->bIdentifier ) )
|
|
{
|
|
RADIUS_TRACE("Recvd packet with invalid length/Id from server");
|
|
|
|
*pdwExtError = ERROR_INVALID_PACKET_LENGTH_OR_ID;
|
|
|
|
return( ERROR_INVALID_RADIUS_RESPONSE );
|
|
}
|
|
|
|
//
|
|
// Convert length from network order
|
|
//
|
|
|
|
cbLength = ntohs( pRecvHeader->wLength ) - sizeof( RADIUS_PACKETHEADER );
|
|
|
|
cbLengthOfRadiusAttributes = cbLength;
|
|
|
|
prgRadiusWalker = (PRADIUS_ATTRIBUTE)(pRecvHeader + 1);
|
|
|
|
//
|
|
// Count the number of attributes to determine the size of the out
|
|
// parameters table. The length of each attribute has to be at least 2.
|
|
//
|
|
|
|
while ( cbLengthOfRadiusAttributes > 1 )
|
|
{
|
|
(*lpdwNumAttributes)++;
|
|
|
|
if ( prgRadiusWalker->bLength < 2 )
|
|
{
|
|
RADIUS_TRACE("Recvd packet with attribute of length less than 2");
|
|
|
|
*pdwExtError = ERROR_INVALID_ATTRIBUTE_LENGTH;
|
|
|
|
return( ERROR_INVALID_RADIUS_RESPONSE );
|
|
}
|
|
|
|
if ( prgRadiusWalker->bLength > cbLengthOfRadiusAttributes )
|
|
{
|
|
RADIUS_TRACE("Recvd packet with attribute with illegal length ");
|
|
|
|
*pdwExtError = ERROR_INVALID_ATTRIBUTE_LENGTH;
|
|
|
|
return( ERROR_INVALID_RADIUS_RESPONSE );
|
|
}
|
|
|
|
//
|
|
// If this is Microsoft VSA then validate it and findout how many
|
|
// subattributes there are
|
|
//
|
|
|
|
if ( ( prgRadiusWalker->bType == raatVendorSpecific ) &&
|
|
( prgRadiusWalker->bLength > 6 ) &&
|
|
( WireToHostFormat32( (PBYTE)(prgRadiusWalker+1) ) == 311 ) )
|
|
{
|
|
PBYTE pVSAWalker = (PBYTE)(prgRadiusWalker+1)+4;
|
|
DWORD cbVSALength = prgRadiusWalker->bLength -
|
|
sizeof( RADIUS_ATTRIBUTE ) - 4;
|
|
|
|
(*lpdwNumAttributes)--;
|
|
|
|
while( cbVSALength > 1 )
|
|
{
|
|
(*lpdwNumAttributes)++;
|
|
|
|
if ( *(pVSAWalker+1) < 2 )
|
|
{
|
|
RADIUS_TRACE("VSA attribute has incorrect length");
|
|
|
|
*pdwExtError = ERROR_INVALID_ATTRIBUTE_LENGTH;
|
|
|
|
return( ERROR_INVALID_RADIUS_RESPONSE );
|
|
}
|
|
|
|
if ( *(pVSAWalker+1) > cbVSALength )
|
|
{
|
|
RADIUS_TRACE("VSA attribute has incorrect length");
|
|
|
|
*pdwExtError = ERROR_INVALID_ATTRIBUTE_LENGTH;
|
|
|
|
return( ERROR_INVALID_RADIUS_RESPONSE );
|
|
}
|
|
|
|
cbVSALength -= *(pVSAWalker+1);
|
|
pVSAWalker += *(pVSAWalker+1);
|
|
}
|
|
|
|
if ( cbVSALength != 0 )
|
|
{
|
|
RADIUS_TRACE("VSA attribute has incorrect length");
|
|
|
|
*pdwExtError = ERROR_INVALID_ATTRIBUTE_LENGTH;
|
|
|
|
return( ERROR_INVALID_RADIUS_RESPONSE );
|
|
}
|
|
}
|
|
|
|
cbLengthOfRadiusAttributes -= prgRadiusWalker->bLength;
|
|
|
|
prgRadiusWalker = (PRADIUS_ATTRIBUTE)
|
|
(((PBYTE)prgRadiusWalker)+prgRadiusWalker->bLength);
|
|
}
|
|
|
|
if ( cbLengthOfRadiusAttributes != 0 )
|
|
{
|
|
RADIUS_TRACE("Received invalid packet from radius server");
|
|
|
|
*pdwExtError = ERROR_INVALID_PACKET;
|
|
|
|
return( ERROR_INVALID_RADIUS_RESPONSE );
|
|
}
|
|
|
|
RADIUS_TRACE1("Total number of Radius attributes returned = %d",
|
|
*lpdwNumAttributes );
|
|
|
|
switch( bCode )
|
|
{
|
|
case ptAccessReject:
|
|
case ptAccessAccept:
|
|
case ptAccessChallenge:
|
|
case ptAccountingResponse:
|
|
|
|
//
|
|
// Validate response authenticator with request authenticator
|
|
//
|
|
|
|
MD5Init( &MD5c );
|
|
|
|
//
|
|
// Code+Id+Length of Response
|
|
//
|
|
|
|
MD5Update( &MD5c, (PBYTE)pRecvHeader, 4 );
|
|
|
|
//
|
|
// Request authenticator
|
|
//
|
|
|
|
MD5Update( &MD5c, (PBYTE)(pSendHeader->rgAuthenticator), 16 );
|
|
|
|
//
|
|
// Response attributes
|
|
//
|
|
|
|
MD5Update( &MD5c,
|
|
(PBYTE)(pRecvHeader+1),
|
|
ntohs(pRecvHeader->wLength)-sizeof(RADIUS_PACKETHEADER));
|
|
|
|
//
|
|
// Shared secret
|
|
//
|
|
|
|
MD5Update( &MD5c,
|
|
(PBYTE)(pRadiusServer->szSecret),
|
|
pRadiusServer->cbSecret );
|
|
|
|
MD5Final(&MD5c);
|
|
|
|
//
|
|
// This must match the Response Authenticator
|
|
//
|
|
|
|
if ( memcmp( MD5c.digest, pRecvHeader->rgAuthenticator, 16 ) != 0 )
|
|
{
|
|
RADIUS_TRACE("Authenticator does not match.");
|
|
|
|
*pdwExtError = ERROR_AUTHENTICATOR_MISMATCH;
|
|
|
|
return( ERROR_INVALID_RADIUS_RESPONSE );
|
|
}
|
|
|
|
break;
|
|
|
|
case ptStatusServer:
|
|
case ptStatusClient:
|
|
case ptAcctStatusType:
|
|
default:
|
|
|
|
RADIUS_TRACE("Received invalid packet from radius server");
|
|
|
|
*pdwExtError = ERROR_INVALID_PACKET;
|
|
|
|
return( ERROR_INVALID_RADIUS_RESPONSE );
|
|
|
|
break;
|
|
}
|
|
|
|
return( NO_ERROR );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: SendData2ServerWRetry
|
|
//
|
|
// Returns: NO_ERROR - Success
|
|
// Non-zero returns - Failure
|
|
//
|
|
// Description:
|
|
//
|
|
DWORD
|
|
SendData2ServerWRetry(
|
|
IN PRAS_AUTH_ATTRIBUTE prgInAttributes,
|
|
OUT PRAS_AUTH_ATTRIBUTE *pprgOutAttributes,
|
|
OUT BYTE * pbCode,
|
|
IN BYTE bSubCode,
|
|
OUT BOOL * pfEapMessageReceived
|
|
)
|
|
{
|
|
DWORD dwError = NO_ERROR;
|
|
DWORD dwRetryCount = 0;
|
|
DWORD cRetries = ( bSubCode == atInvalid)
|
|
? g_cAuthRetries
|
|
: g_cAcctRetries;
|
|
LONG lPacketID;
|
|
|
|
InterlockedIncrement( &g_lPacketID );
|
|
|
|
lPacketID = InterlockedExchange( &g_lPacketID, g_lPacketID );
|
|
|
|
while( cRetries-- > 0 )
|
|
{
|
|
switch( *pbCode )
|
|
{
|
|
case ptAccountingRequest:
|
|
InterlockedIncrement( &g_cAcctReqSent );
|
|
break;
|
|
|
|
case ptAccessRequest:
|
|
InterlockedIncrement( &g_cAuthReqSent );
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
dwError = SendData2Server( prgInAttributes,
|
|
pprgOutAttributes,
|
|
pbCode,
|
|
bSubCode,
|
|
lPacketID,
|
|
dwRetryCount++,
|
|
pfEapMessageReceived );
|
|
|
|
if ( dwError != ERROR_AUTH_SERVER_TIMEOUT )
|
|
{
|
|
break;
|
|
}
|
|
|
|
switch( *pbCode )
|
|
{
|
|
case ptAccountingRequest:
|
|
InterlockedIncrement( &g_cAcctReqTimeout );
|
|
break;
|
|
|
|
case ptAccessRequest:
|
|
InterlockedIncrement( &g_cAuthReqTimeout );
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return( dwError );
|
|
}
|