/********************************************************************/ /** 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define INCL_RASAUTHATTRIBUTES #define INCL_HOSTWIRE #include #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 ); }