windows-nt/Source/XPSP1/NT/net/config/netman/eapol/service/svcmain.c
2020-09-26 16:20:57 +08:00

801 lines
19 KiB
C

/*++
Copyright (c) 2000, Microsoft Corporation
Module Name:
svcmain.c
Abstract:
This module contains code for starting off, shutting down and
handling device addition/removal request for the EAPOL module.
Revision History:
sachins, Apr 25 2000, Created
Notes:
EAPOL_SERVICE if defined, on compilation, a .exe version is created.
If not defined, on compilation, a .lib is created, with entry
points defined, which netman calls into.
--*/
#include "pcheapol.h"
#pragma hdrstop
#define NDISUIO_SERVICE_NAME L"NDISUIO"
#define NETMAN_SERVICE_NAME L"NETMAN"
extern
VOID
EAPOLServiceMain (
IN DWORD argc,
IN LPWSTR *lpwsServiceArgs
);
VOID
EAPOLServiceMainWorker (
IN PVOID pvContext
);
#ifdef EAPOL_SERVICE
//
// main
//
// Description: Will simply register the entry point of the EAPOL
// service with the service controller. The service controller
// will capture this thread. It will be freed only when
// the service is shutdown. At that point we will simply exit
// the process.
//
// Return values: none
//
void
_cdecl
main ( int argc, unsigned char * argv[] )
{
SERVICE_TABLE_ENTRY EapolServiceDispatchTable[2];
UNREFERENCED_PARAMETER( argc );
UNREFERENCED_PARAMETER( argv );
EapolServiceDispatchTable[0].lpServiceName = EAPOL_SERVICE_NAME;
EapolServiceDispatchTable[0].lpServiceProc = EAPOLServiceMain;
EapolServiceDispatchTable[1].lpServiceName = NULL;
EapolServiceDispatchTable[1].lpServiceProc = NULL;
if ( !StartServiceCtrlDispatcher( EapolServiceDispatchTable ) )
{
ASSERT (0);
}
ExitProcess(0);
}
//
// EAPOLAnnounceServiceStatus
//
// Description: Will simly call SetServiceStatus to inform the service
// control manager of this service's current status.
//
// Return values: none
//
VOID
EAPOLAnnounceServiceStatus (
VOID
)
{
BOOL dwRetCode;
ASSERT (g_hServiceStatus);
//
// Increment the checkpoint in a pending state:
//
switch( g_ServiceStatus.dwCurrentState )
{
case SERVICE_START_PENDING:
case SERVICE_STOP_PENDING:
g_ServiceStatus.dwCheckPoint++;
break;
default:
break;
}
dwRetCode = SetServiceStatus( g_hServiceStatus,
&g_ServiceStatus );
if ( dwRetCode == FALSE )
{
TRACE1 (INIT, "Error: SetServiceStatus returned %d\n",
GetLastError() );
}
}
#endif
//
// EAPOLCleanUp
//
// Description: Will free any allocated memory, deinitialize RPC, deinitialize
// the kernel-mode server and unload it if it was loaded.
// This could have been called due to an error on SERVICE_START
// or normal termination.
//
// Return values: none
//
VOID
EAPOLCleanUp (
IN DWORD dwError
)
{
DWORD dwIndex;
DWORD dwEventStatus = 0;
SERVICE_STATUS ServiceStatus;
DWORD dwRetCode = NO_ERROR;
if (g_hEventTerminateEAPOL == NULL)
{
return;
}
//
// Check if have already gone through EAPOLCleanUp before
// Return if so
//
if (( dwEventStatus = WaitForSingleObject (
g_hEventTerminateEAPOL,
0)) == WAIT_FAILED)
{
dwRetCode = GetLastError ();
if ( g_dwTraceId != INVALID_TRACEID )
{
TRACE1 (INIT, "EAPOLCleanUp: WaitForSingleObject failed with error %ld, Terminating cleanup",
dwRetCode);
}
// log
return;
}
if (dwEventStatus == WAIT_OBJECT_0)
{
if ( g_dwTraceId != INVALID_TRACEID )
{
TRACE0 (INIT, "EAPOLCleanUp: g_hEventTerminateEAPOL already signaled, returning");
}
return;
}
#ifdef EAPOL_SERVICE
//
// Announce that we are stopping
//
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCheckPoint = 1;
g_ServiceStatus.dwWaitHint = 200000;
EAPOLAnnounceServiceStatus();
#endif
//
// Tear down and free everything
//
//
// Set event to indicate to waiting threads to terminate
//
if ( !SetEvent (g_hEventTerminateEAPOL) )
{
dwRetCode = GetLastError();
if ( g_dwTraceId != INVALID_TRACEID )
{
TRACE1 (INIT, "EAPOLCleanUp: SetEvent for g_hEventTerminateEAPOL failed with error %ld",
dwRetCode);
}
// log
}
//
// Shutdown device related stuff
// Close handles to NDISUIO
// Shutdown EAPOL State machine
//
if ( ( dwRetCode = ElMediaDeInit()) != NO_ERROR )
{
if ( g_dwTraceId != INVALID_TRACEID )
{
TRACE1 (INIT, "Media DeInit failed with dwRetCode = %ld\n",
dwRetCode );
}
dwRetCode = NO_ERROR;
}
else
{
if ( g_dwTraceId != INVALID_TRACEID )
{
TRACE1 (INIT, "Media DeInit succeeded with dwRetCode = %ld\n",
dwRetCode );
}
}
#ifdef EAPOL_SERVICE
if ( dwError == NO_ERROR )
{
g_ServiceStatus.dwWin32ExitCode = NO_ERROR;
}
else
{
g_ServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
}
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCheckPoint = 0;
g_ServiceStatus.dwWaitHint = 0;
g_ServiceStatus.dwServiceSpecificExitCode = dwError;
EAPOLAnnounceServiceStatus();
#endif
if (!CloseHandle(g_hStopService))
{
if ( g_dwTraceId != INVALID_TRACEID )
{
TRACE1 (INIT, "EAPOLCleanup: CloseHandle failed with error %ld",
GetLastError());
}
}
//
// Shut down NDISUIO service
//
if ( g_hNDISUIOService != NULL )
{
if (!ControlService ( g_hNDISUIOService, SERVICE_CONTROL_STOP, &ServiceStatus ))
{
if ( g_dwTraceId != INVALID_TRACEID )
{
TRACE1 (INIT, "EAPOLCleanup: ControlService failed with error %ld",
GetLastError());
}
}
if (!CloseServiceHandle ( g_hNDISUIOService ))
{
if ( g_dwTraceId != INVALID_TRACEID )
{
TRACE1 (INIT, "EAPOLCleanup: CloseServiceHandle failed with error %ld",
GetLastError());
}
}
g_hNDISUIOService = NULL;
}
if ( g_hServiceCM != NULL )
{
if (!CloseServiceHandle ( g_hServiceCM ))
{
if ( g_dwTraceId != INVALID_TRACEID )
{
TRACE1 (INIT, "EAPOLCleanup: CloseServiceHandle for SCM failed with error %ld",
GetLastError());
}
}
g_hServiceCM = NULL;
}
if ( g_dwTraceId != INVALID_TRACEID )
{
TRACE1 (INIT, "EAPOLCleanup completed with error %d\n", dwError );
TraceDeregisterA( g_dwTraceId );
g_dwTraceId = INVALID_TRACEID;
}
EapolLogInformation (EAPOL_LOG_SERVICE_RUNNING, 0, NULL);
if ( g_hLogEvents != NULL)
{
EapolLogInformation (EAPOL_LOG_SERVICE_STOPPED, 0, NULL);
RouterLogDeregisterW( g_hLogEvents );
g_hLogEvents = NULL;
}
return;
}
#ifdef EAPOL_SERVICE
//
// ServiceHandlerEx
//
// Description: Will respond to control requests from the service controller.
//
// Return values: none
//
//
DWORD
ServiceHandlerEx (
IN DWORD dwControlCode,
IN DWORD dwEventType,
IN LPVOID lpEventData,
IN LPVOID lpContext
)
{
DWORD dwRetCode = NO_ERROR;
switch( dwControlCode )
{
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
if ( ( g_ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING)
||
( g_ServiceStatus.dwCurrentState == SERVICE_STOPPED ))
{
break;
}
TRACE0 (INIT, "ServiceHandlerEx: SERVICE_CONTROL_ STOP or SHUTDOWN event called");
//
// Announce that we are stopping
//
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
g_ServiceStatus.dwControlsAccepted = 0;
g_ServiceStatus.dwCheckPoint = 1;
g_ServiceStatus.dwWaitHint = 200000;
EAPOLAnnounceServiceStatus();
SetEvent( g_hStopService );
return( NO_ERROR );
break;
case SERVICE_CONTROL_DEVICEEVENT:
if ( ( g_ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING)
||
( g_ServiceStatus.dwCurrentState == SERVICE_STOPPED ))
{
break;
}
TRACE0 (INIT, "ServiceHandlerEx: SERVICE_CONTROL_DEVICEEVENT event called");
// Received notification that some LAN interface was added or deleted
if (lpEventData != NULL)
{
// Call device notification handler
if ((dwRetCode = ElDeviceNotificationHandler (
lpEventData, dwEventType)) != NO_ERROR)
{
TRACE1 (INIT, "ServiceHandlerEx: ElDeviceNotificationHandler faield with error %ld",
dwRetCode);
break;
}
}
default:
return( ERROR_CALL_NOT_IMPLEMENTED );
break;
}
return( dwRetCode );
}
#endif
//
// EAPOLServiceMain
//
// Description: This is the main procedure for the EAPOL Server Service. It
// will be called when the service is supposed to start itself.
// It will do all service wide initialization.
//
// Return values: none
//
VOID
WINAPI
EAPOLServiceMain (
IN DWORD argc, // Command line arguments. Will be ignored.
IN LPWSTR * lpwsServiceArgs
)
{
DWORD dwRetCode = NO_ERROR;
UNREFERENCED_PARAMETER( argc );
UNREFERENCED_PARAMETER( lpwsServiceArgs );
g_hEventTerminateEAPOL = NULL;
// Queue a worker item to do the heavy-duty work during initialization
// This will not hold up the main worker thread
if (!QueueUserWorkItem(
(LPTHREAD_START_ROUTINE)EAPOLServiceMainWorker,
NULL,
WT_EXECUTELONGFUNCTION))
{
dwRetCode = GetLastError();
ASSERT (0);
}
}
VOID
EAPOLServiceMainWorker (
IN PVOID pvContext
)
{
DWORD dwIndex = 0;
SC_HANDLE hServiceCM;
SC_HANDLE hNDISUIOService;
SC_HANDLE hNetManService;
LPQUERY_SERVICE_CONFIG pNetmanServiceConfig = NULL;
DWORD dwBufSize = 0, dwBytesNeeded = 0;
DWORD dwRetCode = NO_ERROR;
//
// Initialize globals
//
g_hLogEvents = NULL;
g_dwTraceId = INVALID_TRACEID;
g_hServiceCM = NULL;
g_hNDISUIOService = NULL;
g_hStopService = NULL;
g_dwModulesStarted = 0;
g_dwMachineAuthEnabled = 0;
g_hNLA_LPC_Port = NULL;
//
// Create event that will be used to indicate EAPOL shutdown
//
g_hEventTerminateEAPOL = CreateEvent( NULL, TRUE, FALSE, NULL );
if ( g_hEventTerminateEAPOL == (HANDLE)NULL )
{
dwRetCode = GetLastError ();
ASSERT (0);
EAPOLCleanUp ( dwRetCode );
return;
}
//
// Register for debug tracing via rtutils.dll
//
g_dwTraceId = TraceRegister (L"EAPOL");
if ( g_dwTraceId == INVALID_TRACEID )
{
dwRetCode = GetLastError ();
ASSERT (0);
EAPOLCleanUp ( dwRetCode );
return;
}
//
// Register for event logging via rtutils.dll
//
g_hLogEvents = RouterLogRegisterW(L"EAPOL");
if ( g_hLogEvents == NULL )
{
dwRetCode = GetLastError ();
TRACE1 (INIT, "EAPOLServiceMainWorker: RouterLogRegisterW failed with error %ld",
dwRetCode);
EAPOLCleanUp ( dwRetCode );
return;
}
#ifdef EAPOL_SERVICE
g_hServiceStatus = RegisterServiceCtrlHandlerEx(
TEXT("EAPOL"),
ServiceHandlerEx,
NULL );
if ( !g_hServiceStatus )
{
return;
}
g_ServiceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
EAPOLAnnounceServiceStatus();
#endif
//
// Start NDISUIO driver
//
if ((g_hServiceCM = OpenSCManager ( NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE ))
== NULL)
{
dwRetCode = GetLastError ();
TRACE1 (INIT, "EAPOLServiceMainWorker: OpenSCManager failed with error %ld",
dwRetCode);
EAPOLCleanUp ( dwRetCode );
return;
}
if ((g_hNDISUIOService =
OpenService ( g_hServiceCM,
NDISUIO_SERVICE_NAME,
SERVICE_START | SERVICE_STOP ))
== NULL)
{
dwRetCode = GetLastError ();
TRACE1 (INIT, "EAPOLServiceMainWorker: OpenService NdisUIO failed with error %ld",
dwRetCode);
EAPOLCleanUp ( dwRetCode );
return;
}
if (!StartService( g_hNDISUIOService, 0, NULL ))
{
dwRetCode = GetLastError ();
TRACE1 (INIT, "EAPOLServiceMainWorker: StartService failed with error %ld",
dwRetCode);
if (dwRetCode != ERROR_SERVICE_ALREADY_RUNNING)
{
EAPOLCleanUp ( dwRetCode );
return;
}
}
//
// Register for event logging via rtutils.dll
//
g_hLogEvents = RouterLogRegisterW(L"EAPOL");
if ( g_hLogEvents == NULL )
{
dwRetCode = GetLastError ();
TRACE1 (INIT, "EAPOLServiceMainWorker: RouterLogRegisterW failed with error %ld",
dwRetCode);
EAPOLCleanUp ( dwRetCode );
return;
}
#ifdef EAPOL_SERVICE
//
// Announce that we have successfully started.
//
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
g_ServiceStatus.dwCheckPoint = 0;
g_ServiceStatus.dwWaitHint = 0;
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
EAPOLAnnounceServiceStatus();
//
// Create event that will be used to shutdown the EAPOL service
//
g_hStopService = CreateEvent ( NULL, TRUE, FALSE, NULL );
if ( g_hStopService == (HANDLE)NULL )
{
dwRetCode = GetLastError ();
TRACE1 (INIT, "EAPOLServiceMainWorker: CreateEvent failed with error %ld",
dwRetCode);
EAPOLCleanUp ( dwRetCode );
return;
}
#endif
//
// Set User logged indication
//
g_fUserLoggedOn = 0;
//
// Used for detetcing MACHINE_AUTH
// Verify if netman is SERVICE_AUTO_START and set flag if machine auth
// is enabled to indicate machine authentication
//
if ((hNetManService =
OpenService ( g_hServiceCM,
NETMAN_SERVICE_NAME,
SERVICE_QUERY_CONFIG ))
== NULL)
{
dwRetCode = GetLastError ();
TRACE1 (INIT, "EAPOLServiceMainWorker: OpenService Netman failed with error %ld",
dwRetCode);
EAPOLCleanUp ( dwRetCode );
return;
}
dwBufSize = 0;
if (!QueryServiceConfig (
hNetManService,
NULL,
dwBufSize,
&dwBytesNeeded
))
{
if ((dwRetCode = GetLastError()) == ERROR_INSUFFICIENT_BUFFER)
{
pNetmanServiceConfig = (LPQUERY_SERVICE_CONFIG) MALLOC (dwBytesNeeded);
if (pNetmanServiceConfig == NULL)
{
dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
TRACE0 (INIT, "EAPOLServiceMainWorker: MALLOC failed for pNetmanServiceConfig");
if (!CloseServiceHandle (hNetManService))
{
dwRetCode = GetLastError ();
TRACE1 (INIT, "EAPOLServiceMainWorker: CloseServiceHandle Netman failed with error %ld",
dwRetCode);
}
EAPOLCleanUp ( dwRetCode );
return;
}
else
{
dwBufSize = dwBytesNeeded;
if (!QueryServiceConfig (
hNetManService,
pNetmanServiceConfig,
dwBufSize,
&dwBytesNeeded
))
{
dwRetCode = GetLastError ();
TRACE0 (INIT, "EAPOLServiceMainWorker: QueryServiceConfig failed for pNetmanServiceConfig");
if (!CloseServiceHandle (hNetManService))
{
dwRetCode = GetLastError ();
TRACE1 (INIT, "EAPOLServiceMainWorker: CloseServiceHandle Netman failed with error %ld",
dwRetCode);
}
EAPOLCleanUp ( dwRetCode );
return;
}
else
{
if (pNetmanServiceConfig->dwStartType == SERVICE_AUTO_START)
{
TRACE0 (INIT, "EAPOLServiceMainWorker: Machine auth enabled");
g_dwMachineAuthEnabled = 1;
}
else
{
TRACE0 (INIT, "EAPOLServiceMainWorker: Machine auth disabled");
}
}
}
}
else
{
TRACE1 (INIT, "EAPOLServiceMainWorker: QueryServiceConfig failed with error %ld",
dwRetCode);
if (!CloseServiceHandle (hNetManService))
{
dwRetCode = GetLastError ();
TRACE1 (INIT, "EAPOLServiceMainWorker: CloseServiceHandle Netman failed with error %ld",
dwRetCode);
}
EAPOLCleanUp ( dwRetCode );
return;
}
}
if (!CloseServiceHandle (hNetManService))
{
dwRetCode = GetLastError ();
TRACE1 (INIT, "EAPOLServiceMainWorker: CloseServiceHandle Netman failed with error %ld",
dwRetCode);
EAPOLCleanUp ( dwRetCode );
return;
}
//
// Initialize media related stuff
// Interfaces will be enumerated, handles to NDISUIO driver will be opened,
// EAPOL will be initialized
//
if ( ( dwRetCode = ElMediaInit()) != NO_ERROR )
{
TRACE1 (INIT, "Media Init failed with dwRetCode = %d\n",
dwRetCode );
EAPOLCleanUp ( dwRetCode );
return;
}
else
{
TRACE1 (INIT, "Media Init succeeded with dwRetCode = %d\n",
dwRetCode );
}
TRACE0 (INIT, "EAPOL started successfully\n" );
EapolLogInformation (EAPOL_LOG_SERVICE_STARTED, 0, NULL);
#ifdef EAPOL_SERVICE
//
// Just wait here for EAPOL service to terminate.
//
dwRetCode = WaitForSingleObject( g_hStopService, INFINITE );
if ( dwRetCode == WAIT_FAILED )
{
dwRetCode = GetLastError();
}
else
{
dwRetCode = NO_ERROR;
}
TRACE0 (INIT, "Stopping EAPOL gracefully\n" );
EAPOLCleanUp ( dwRetCode );
#endif
}