/*++ Copyright (c) 1997 Microsoft Corporation Module Name: rogue.c Abstract: This module contains the rogue detection interface to DHCP for BINL server. Author: Andy Herron (andyhe) 19-Aug-1998 Environment: User Mode - Win32 Revision History: --*/ #include "binl.h" #pragma hdrstop VOID BinlRogueLoop( LPVOID Parameter ); NTSTATUS MaybeStartRogueThread ( VOID ) // // Initiate rogue thread. The gcsDHCPBINL should not be held by caller. // { DWORD Error = ERROR_SUCCESS; DWORD threadId; EnterCriticalSection(&gcsDHCPBINL); // // if we're stopping anyway or if we're already running the rogue stuff // or if the DHCP server is up, then we don't bother starting rogue // detection. // if ((BinlCurrentState == BINL_STOPPED) || (BinlGlobalHaveCalledRogueInit) || (DHCPState != DHCP_STOPPED)) { LeaveCriticalSection(&gcsDHCPBINL); return ERROR_SUCCESS; } // // Let's do rogue detection.. first create the events we need // if (BinlRogueTerminateEventHandle == NULL) { BinlRogueTerminateEventHandle = CreateEvent( NULL, FALSE, FALSE, NULL ); } if (RogueUnauthorizedHandle == NULL) { RogueUnauthorizedHandle = CreateEvent( NULL, TRUE, FALSE, NULL ); } if ( BinlRogueTerminateEventHandle == NULL || RogueUnauthorizedHandle == NULL) { Error = GetLastError(); BinlPrintDbg( (DEBUG_ROGUE, "Initialize(...) CreateEvent returned error %x for rogue\n", Error ) ); LeaveCriticalSection(&gcsDHCPBINL); return Error; } Error = DhcpRogueInit( &DhcpRogueInfo, BinlRogueTerminateEventHandle, RogueUnauthorizedHandle ); if (Error != ERROR_SUCCESS) { LeaveCriticalSection(&gcsDHCPBINL); return Error; } // // create the thread that handles the rogue detection logic in DHCP code. // BinlRogueThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)BinlRogueLoop, NULL, 0, &threadId ); if ( BinlRogueThread == NULL ) { Error = GetLastError(); BinlPrint((DEBUG_ROGUE, "Can't create rogue Thread, %ld.\n", Error)); LeaveCriticalSection(&gcsDHCPBINL); return Error; } BinlGlobalHaveCalledRogueInit = TRUE; LeaveCriticalSection(&gcsDHCPBINL); return ERROR_SUCCESS; } VOID StopRogueThread ( VOID ) // // Cleanup all rogue thread resources. // The gcsDHCPBINL should not be held by caller. // { HANDLE tempThreadHandle; tempThreadHandle = InterlockedExchangePointer( &BinlRogueThread, NULL ); if ( tempThreadHandle != NULL ) { BinlAssert( BinlRogueTerminateEventHandle != NULL ); SetEvent( BinlRogueTerminateEventHandle ); WaitForSingleObject( tempThreadHandle, THREAD_TERMINATION_TIMEOUT ); CloseHandle( tempThreadHandle ); } EnterCriticalSection(&gcsDHCPBINL); if (BinlGlobalHaveCalledRogueInit) { DhcpRogueCleanup( &DhcpRogueInfo ); BinlGlobalHaveCalledRogueInit = FALSE; } if ( BinlRogueTerminateEventHandle ) { CloseHandle( BinlRogueTerminateEventHandle ); BinlRogueTerminateEventHandle = NULL; } if ( RogueUnauthorizedHandle ) { CloseHandle( RogueUnauthorizedHandle ); RogueUnauthorizedHandle = NULL; } LeaveCriticalSection(&gcsDHCPBINL); return; } VOID HandleRogueAuthorized ( VOID ) { BOOL oldState = BinlGlobalAuthorized; BinlGlobalAuthorized = TRUE; if ((BinlGlobalAuthorized != oldState) && (BinlCurrentState != BINL_STOPPED)) { LogCurrentRogueState( FALSE ); } return; } VOID HandleRogueUnauthorized ( VOID ) { BOOL oldState = BinlGlobalAuthorized; BinlGlobalAuthorized = FALSE; if ((BinlGlobalAuthorized != oldState) && (BinlCurrentState != BINL_STOPPED)) { LogCurrentRogueState( FALSE ); } return; } VOID LogCurrentRogueState ( BOOL ResponseToMessage ) { // // If we're responding to a message and we haven't yet logged that // we're unauthorized if ((ResponseToMessage == FALSE) || ((BinlGlobalAuthorized == FALSE) && (BinlRogueLoggedState == FALSE)) ) { BinlRogueLoggedState = TRUE; BinlReportEventW( BinlGlobalAuthorized ? EVENT_ERROR_DHCP_AUTHORIZED : EVENT_ERROR_DHCP_NOT_AUTHORIZED, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, NULL ); } return; } VOID BinlRogueLoop( LPVOID Parameter ) { HANDLE Handles[3]; ULONG SecondsToSleep, SleepTime, Error; ULONG Flag; BinlPrintDbg((DEBUG_ROGUE, "BinlRogue thread has been started.\n" )); Handles[0] = BinlRogueTerminateEventHandle; Handles[1] = RogueUnauthorizedHandle; Handles[2] = BinlGlobalProcessTerminationEvent; do { SecondsToSleep = RogueDetectStateMachine(&DhcpRogueInfo); if( INFINITE == SecondsToSleep ) { SleepTime = INFINITE; } else { SleepTime = SecondsToSleep * 1000; } BinlPrintDbg( (DEBUG_ROGUE, "BinlRogue waiting %u milliseconds.\n", SleepTime )); Error = WaitForMultipleObjects(3, Handles, FALSE, SleepTime ); // // if we got anything but WAIT_TIMEOUT or RogueUnauthorized, we // break out. This is per RameshV's sample code. // if (Error == WAIT_OBJECT_0+2) { // // binl is terminating. // BinlPrintDbg((DEBUG_ROGUE, "BinlRogue thread is exiting because BINL shutting down.\n" )); return; } if (BinlRogueThread == NULL) { // // we've been terminated because DHCP has started and is doing // it's own rogue detection. // BinlPrintDbg((DEBUG_ROGUE, "BinlRogue thread is exiting because rogue thread is null.\n" )); return; } // if we ever have to do anything besides just continue when the // state machine tells us to exit, do so here. #if 0 if ((Error == WAIT_OBJECT_0+1) || (Error == WAIT_TIMEOUT)) { continue; } #endif // // supposedly the state machine resets so we should just continue. // BinlPrintDbg((DEBUG_ROGUE, "BinlRogue has error of 0x%x. sleeping a bit\n", Error )); Sleep( 1000 ); // we'll sleep to give the dhcp rogue state // machine time to reset } while ( TRUE ); } // rogue.c eof