|
|
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
services.c
Abstract:
Routines to manage nt service configurations for promotion and demotion
Author:
Colin Brace ColinBr March 29, 1999.
Environment:
User Mode
Revision History:
--*/ #include <setpch.h>
#include <dssetp.h>
#include <malloc.h> // alloca
#include <lmcons.h> // net api definitions
#include <lmsvc.h> // service names
#include <ismapi.h> //defines ISM_SERVICE_CONTROL_REMOVE_STOP
#include "services.h"
//
// These last 3 magic values supplied by Shirish Koti (koti) to setup up
// ras services for macintosh on a domain controller
//
#define DSROLEP_MSV10_PATH L"SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0"
#define DSROLEP_RASSFM_NAME L"Auth2"
#define DSROLEP_RASSFM_VALUE L"RASSFM"
//
// Global Data for this module
//
//
// Table based data for the intrinsic nt services
//
typedef struct _DSROLEP_SERVICE_ITEM { LPWSTR ServiceName; // name of the service to configure
ULONG ConfigureOn; // the dsrole flag to enable the service
ULONG ConfigureOff; // the dsrole flag to disable the service
ULONG RevertSettings; // the dsrole flags to use to revert settings
LPWSTR Dependencies[3]; // the dependencies the service has when enabled
} DSROLEP_SERVICE_ITEM;
//
// These are services that run on machines that are part of a domain
//
DSROLEP_SERVICE_ITEM DsRoleDomainServices[] = { { SERVICE_W32TIME, DSROLEP_SERVICE_AUTOSTART, DSROLEP_SERVICE_AUTOSTART, DSROLEP_SERVICES_INVALID, NULL, NULL, NULL }, { SERVICE_NETLOGON, DSROLEP_SERVICE_AUTOSTART, DSROLEP_SERVICE_DEMANDSTART, 0, NULL, NULL, NULL } };
ULONG DsRoleDomainServicesCount = sizeof(DsRoleDomainServices) / sizeof(DsRoleDomainServices[0]);
//
// These are servers that run on machines that are domain controllers
//
DSROLEP_SERVICE_ITEM DsRoleDomainControllerServices[] = { // This was set to AUTOSTART in W2K. In Whistler we set RPC Locator to DemandStart
// both on promotions and demotions.
{ SERVICE_RPCLOCATOR, DSROLEP_SERVICE_DEMANDSTART, DSROLEP_SERVICE_DEMANDSTART, DSROLEP_SERVICES_INVALID, NULL, NULL, NULL }, { SERVICE_ISMSERV, DSROLEP_SERVICE_AUTOSTART, DSROLEP_SERVICE_DISABLED | DSROLEP_SERVICE_STOP_ISM, DSROLEP_SERVICES_INVALID, NULL, NULL, NULL }, { SERVICE_KDC, DSROLEP_SERVICE_AUTOSTART, DSROLEP_SERVICE_DISABLED, DSROLEP_SERVICES_INVALID, NULL, NULL, NULL }, { SERVICE_TRKSVR, DSROLEP_SERVICE_NOOP, DSROLEP_SERVICE_DEMANDSTART, DSROLEP_SERVICES_INVALID, NULL, NULL, NULL }, { SERVICE_TRKWKS, DSROLEP_SERVICE_DEMANDSTART, DSROLEP_SERVICE_NOOP, DSROLEP_SERVICES_INVALID, NULL, NULL, NULL }, { SERVICE_NETLOGON, DSROLEP_SERVICE_AUTOSTART | DSROLEP_SERVICE_DEP_ADD, DSROLEP_SERVICE_AUTOSTART | DSROLEP_SERVICE_DEP_REMOVE, DSROLEP_SERVICES_INVALID, SERVICE_SERVER, NULL, NULL } };
ULONG DsRoleDomainControllerServicesCount = sizeof(DsRoleDomainControllerServices) / sizeof(DsRoleDomainControllerServices[0]);
//
// Local forwards
//
DWORD DsRolepSetRegStringValue( IN LPWSTR Path, IN LPWSTR ValueName, IN LPWSTR Value );
DWORD DsRolepConfigureGenericServices( IN DSROLEP_SERVICE_ITEM *ServiceArray, IN ULONG ServiceCount, IN ULONG Flags );
DWORD DsRolepMakeAdjustedDependencyList( IN HANDLE hSvc, IN DWORD ServiceOptions, IN LPWSTR Dependency, OUT LPWSTR *DependenyList );
DWORD DsRolepGetServiceConfig( IN SC_HANDLE hScMgr, IN LPWSTR ServiceName, IN SC_HANDLE ServiceHandle, IN LPQUERY_SERVICE_CONFIG *ServiceConfig ); //
// Small helper functions
//
DWORD DsRolepFlagsToServiceFlags( IN DWORD f ) {
if ( FLAG_ON( f, DSROLEP_SERVICE_BOOTSTART ) ) return SERVICE_BOOT_START; if ( FLAG_ON( f, DSROLEP_SERVICE_SYSTEM_START ) ) return SERVICE_SYSTEM_START; if ( FLAG_ON( f, DSROLEP_SERVICE_AUTOSTART ) ) return SERVICE_AUTO_START; if ( FLAG_ON( f, DSROLEP_SERVICE_DEMANDSTART ) ) return SERVICE_DEMAND_START; if ( FLAG_ON( f, DSROLEP_SERVICE_DISABLED ) ) return SERVICE_DISABLED; // No flag, no change
return SERVICE_NO_CHANGE; }
WCHAR* DsRolepFlagsToString( IN DWORD f ) { if ( FLAG_ON( f, DSROLEP_SERVICE_BOOTSTART ) ) return L"SERVICE_BOOT_START"; if ( FLAG_ON( f, DSROLEP_SERVICE_SYSTEM_START ) ) return L"SERVICE_SYSTEM_START"; if ( FLAG_ON( f, DSROLEP_SERVICE_AUTOSTART ) ) return L"SERVICE_AUTO_START"; if ( FLAG_ON( f, DSROLEP_SERVICE_DEMANDSTART ) ) return L"SERVICE_DEMAND_START"; if ( FLAG_ON( f, DSROLEP_SERVICE_DISABLED ) ) return L"SERVICE_DISABLED"; // No flag, no change
return L"SERVICE_NO_CHANGE"; }
DWORD DsRolepServiceFlagsToDsRolepFlags( IN DWORD f ) {
if ( f == SERVICE_BOOT_START ) return DSROLEP_SERVICE_BOOTSTART; if ( f == SERVICE_SYSTEM_START ) return DSROLEP_SERVICE_SYSTEM_START; if ( f == SERVICE_AUTO_START ) return DSROLEP_SERVICE_AUTOSTART; if ( f == SERVICE_DEMAND_START ) return DSROLEP_SERVICE_DEMANDSTART; if ( f == SERVICE_DISABLED ) return DSROLEP_SERVICE_DISABLED; if ( f == SERVICE_NO_CHANGE ) return 0;
ASSERT( FALSE && !"Unknown service start type" );
// This is safe
return DSROLEP_SERVICE_DEMANDSTART; }
//
// Exported (from this file) functions
//
DWORD DsRolepConfigureDomainControllerServices( IN DWORD Flags )
/*++
Routine Description
Parameters
Return Values
ERROR_SUCCESS if no errors; a system service error otherwise.
--*/ { DWORD WinError = ERROR_SUCCESS;
//
// Configure the registry for RASSFM service
//
if ( FLAG_ON( Flags, DSROLEP_SERVICES_ON ) ) {
WinError = DsRolepSetRegStringValue(DSROLEP_MSV10_PATH, DSROLEP_RASSFM_NAME, DSROLEP_RASSFM_VALUE);
//
// This is not fatal -- log message
//
WinError = ERROR_SUCCESS; }
//
// Configure the intrinsic nt services
//
WinError = DsRolepConfigureGenericServices( DsRoleDomainControllerServices, DsRoleDomainControllerServicesCount, Flags );
//
// No need to undo RASSFM change
//
return WinError; }
DWORD DsRolepConfigureDomainServices( DWORD Flags ) /*++
Routine Description
Parameters
Return Values
ERROR_SUCCESS if no errors; a system service error otherwise.
--*/ { DWORD WinError = ERROR_SUCCESS;
//
// Configure the intrinsic nt services
//
WinError = DsRolepConfigureGenericServices( DsRoleDomainServices, DsRoleDomainServicesCount, Flags );
return WinError; }
DWORD DsRolepStartNetlogon( VOID ) { DWORD WinError = ERROR_SUCCESS;
WinError = DsRolepConfigureService( SERVICE_NETLOGON, DSROLEP_SERVICE_START, NULL, NULL ); return WinError; }
DWORD DsRolepStopNetlogon( OUT BOOLEAN *WasRunning ) { DWORD WinError = ERROR_SUCCESS; ULONG PreviousSettings = 0;
WinError = DsRolepConfigureService( SERVICE_NETLOGON, DSROLEP_SERVICE_STOP, NULL, &PreviousSettings );
if ( (ERROR_SUCCESS == WinError) && WasRunning ) {
*WasRunning = (BOOLEAN) FLAG_ON( PreviousSettings, DSROLEP_SERVICE_START ); }
return WinError; }
//
// Local functions
//
DWORD DsRolepSetRegStringValue(LPWSTR Path, LPWSTR ValueName, LPWSTR Value) /*++
Routine Description
This routine sets Value as a REG_SZ value on the value ValueName on the key Path
Parameters
Path, a registry path relative to HKLM
ValueName, a null-terminated string
Value, a null terminated string
Return Values
ERROR_SUCCESS if no errors; a system service error otherwise.
--*/ { DWORD WinErroror = ERROR_INVALID_PARAMETER, WinErroror2; HKEY hKey;
ASSERT(Path); ASSERT(ValueName); ASSERT(Value);
if (Path && ValueName && Value) {
WinErroror = RegCreateKey(HKEY_LOCAL_MACHINE, Path, &hKey);
if (ERROR_SUCCESS == WinErroror) {
WinErroror = RegSetValueEx(hKey, ValueName, 0, // reserved
REG_SZ, (VOID*)Value, (wcslen(Value)+1)*sizeof(WCHAR));
WinErroror2 = RegCloseKey(hKey); ASSERT(ERROR_SUCCESS == WinErroror2);
}
}
DsRolepLogPrint(( DEB_TRACE, "DsRolepSetRegStringValue on %ws\\%ws to %ws returned %lu\n", Path, ValueName, Value, WinErroror ));
return WinErroror;
}
DWORD DsRolepConfigureGenericServices( IN DSROLEP_SERVICE_ITEM *ServiceArray, IN ULONG ServiceCount, IN ULONG Flags ) /*++
Routine Description:
Arguments:
Returns:
--*/ {
DWORD WinError = ERROR_SUCCESS; ULONG ServicesInstalled;
//
// Configure each service
//
for ( ServicesInstalled = 0; ServicesInstalled < ServiceCount && (WinError == ERROR_SUCCESS); ServicesInstalled++ ) {
ULONG *RevertSettings = &ServiceArray[ServicesInstalled].RevertSettings; ULONG Operation = 0;
//
// Check for cancel before contining if we are not reverting
//
if ( !FLAG_ON( Flags, DSROLEP_SERVICES_REVERT ) ) { DSROLEP_CHECK_FOR_CANCEL( WinError ); if ( ERROR_SUCCESS != WinError ) { break; } }
//
// Determine the operation flag
//
if ( FLAG_ON( Flags, DSROLEP_SERVICES_ON ) ) {
Operation |= ServiceArray[ServicesInstalled].ConfigureOn; *RevertSettings = 0;
} else if ( FLAG_ON( Flags, DSROLEP_SERVICES_OFF ) ) {
Operation |= ServiceArray[ServicesInstalled].ConfigureOff; *RevertSettings = 0;
} else if ( FLAG_ON( Flags, DSROLEP_SERVICES_REVERT ) ) {
Operation |= ServiceArray[ServicesInstalled].RevertSettings;
//
// N.B. We don't want to set the revert settings when we are
// reverting!
//
RevertSettings = NULL;
} if (Operation == DSROLEP_SERVICE_NOOP) {
continue;
} if ( FLAG_ON( Flags, DSROLEP_SERVICES_START ) ) {
Operation |= DSROLEP_SERVICE_START;
} else if ( FLAG_ON( Flags, DSROLEP_SERVICES_STOP ) ) { Operation |= DSROLEP_SERVICE_STOP; }
// If this is a forced demotion we don't want to fail on errors
// configuring the services
if ( FLAG_ON( Flags, DSROLEP_SERVICES_IGNORE_ERRORS ) ) {
Operation |= DSROLEP_SERVICE_IGNORE_ERRORS;
}
//
// Currently we don't handle more than one dependency
//
ASSERT( NULL == ServiceArray[ ServicesInstalled ].Dependencies[1] );
// We should do something
ASSERT( 0 != Operation );
//
// Configure the service
//
WinError = DsRolepConfigureService( ServiceArray[ ServicesInstalled ].ServiceName, Operation, ServiceArray[ ServicesInstalled ].Dependencies[0], RevertSettings );
}
//
// If there is an error, undo the work already done
//
if ( ERROR_SUCCESS != WinError && !FLAG_ON( Flags, DSROLEP_SERVICES_REVERT ) ) {
DWORD WinError2; ULONG i;
for ( i = 0; i < ServicesInstalled; i++ ) { //
// Configure the service
//
WinError2 = DsRolepConfigureService( ServiceArray[ i ].ServiceName, ServiceArray[ServicesInstalled].RevertSettings, ServiceArray[ i ].Dependencies[0], NULL // we don't need to know revert settings
); //
// This should succeed, though since this is the undo path it is
// not critical
//
ASSERT( ERROR_SUCCESS == WinError2 ); } }
return WinError; }
DWORD DsRolepConfigureService( IN LPWSTR ServiceName, IN ULONG ServiceOptions, IN LPWSTR Dependency OPTIONAL, OUT ULONG *RevertServiceOptions OPTIONAL ) /*++
Routine Description:
Starts, stops, or modifies the configuration of a service.
Arguments:
ServiceName - Service to configure
ServiceOptions - Stop, start, dependency add/remove, or configure
Dependency - a null terminated string identify a dependency
ServiceWasRunning - Optional. When stopping a service, the previous service state is returned here
Returns:
ERROR_SUCCESS - Success
ERROR_INVALID_PARAMETER - A bad service option was given
--*/ { DWORD WinError = ERROR_SUCCESS; SC_HANDLE hScMgr = NULL, hSvc = NULL; ULONG OpenMode = 0; LPENUM_SERVICE_STATUS DependentServices = NULL; ULONG DependSvcSize = 0, DependSvcCount = 0, i; LPWSTR NewDependencyList = NULL; DWORD NewStartType = SERVICE_NO_CHANGE; ULONG UpdateMsgId = DSROLEEVT_CONFIGURE_SERVICE;
//
// If the service doesn't stop within two minutes minute, continue on
//
ULONG AccumulatedSleepTime; ULONG MaxSleepTime = 120000;
BOOLEAN ConfigChangeRequired = FALSE; BOOLEAN RunChangeRequired = FALSE;
DWORD PreviousStartType = SERVICE_NO_CHANGE; BOOLEAN fServiceWasRunning = FALSE;
//
// Parameter checks
//
ASSERT( ! (FLAG_ON( ServiceOptions, DSROLEP_SERVICE_DEP_ADD ) && (FLAG_ON( ServiceOptions, DSROLEP_SERVICE_DEP_REMOVE ))) );
ASSERT( ! (FLAG_ON( ServiceOptions, DSROLEP_SERVICE_AUTOSTART ) && (FLAG_ON( ServiceOptions, DSROLEP_SERVICE_DISABLED ))) );
ASSERT( ! (FLAG_ON( ServiceOptions, DSROLEP_SERVICE_START ) && (FLAG_ON( ServiceOptions, DSROLEP_SERVICE_STOP ))) );
//
// Do some logic to determine the open mode of the service
//
NewStartType = DsRolepFlagsToServiceFlags( ServiceOptions );
if ( (SERVICE_NO_CHANGE != NewStartType) || FLAG_ON( ServiceOptions, DSROLEP_SERVICE_DEP_ADD ) || FLAG_ON( ServiceOptions, DSROLEP_SERVICE_DEP_REMOVE )) { ConfigChangeRequired = TRUE; }
if( ConfigChangeRequired ) {
OpenMode |= SERVICE_CHANGE_CONFIG | SERVICE_QUERY_CONFIG; }
if( FLAG_ON( ServiceOptions, DSROLEP_SERVICE_STOP ) ) {
OpenMode |= SERVICE_STOP | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_QUERY_STATUS; UpdateMsgId = DSROLEEVT_STOP_SERVICE; RunChangeRequired = TRUE; }
if ( FLAG_ON( ServiceOptions, DSROLEP_SERVICE_STOP_ISM ) ) {
OpenMode |= SERVICE_USER_DEFINED_CONTROL;
}
if( FLAG_ON( ServiceOptions, DSROLEP_SERVICE_START ) ) {
OpenMode |= SERVICE_START | SERVICE_QUERY_STATUS; UpdateMsgId = DSROLEEVT_START_SERVICE; RunChangeRequired = TRUE; } //
// Open the service control manager
//
hScMgr = OpenSCManager( NULL, SERVICES_ACTIVE_DATABASE, GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE );
if ( hScMgr == NULL ) {
WinError = GetLastError(); DsRolepLogOnFailure( WinError, DsRolepLogPrint(( DEB_TRACE, "Can't contact the service controller manager (%lu)\n", WinError )) ); goto Cleanup;
}
//
// Open the service
//
hSvc = OpenService( hScMgr, ServiceName, OpenMode );
if ( hSvc == NULL ) {
WinError = GetLastError(); DsRolepLogOnFailure( WinError, DsRolepLogPrint(( DEB_TRACE, "OpenService on %ws failed with %lu\n", ServiceName, WinError )) ); goto Cleanup; }
DSROLEP_CURRENT_OP1( UpdateMsgId, ServiceName );
//
// Determine if the service is running if we are going to be stopping or
// starting it
//
if( RunChangeRequired ) {
SERVICE_STATUS SvcStatus;
if( QueryServiceStatus( hSvc,&SvcStatus ) == FALSE ) { WinError = GetLastError(); goto Cleanup; } if ( SvcStatus.dwCurrentState == SERVICE_RUNNING ) { fServiceWasRunning = TRUE; } }
//
// Determine the current start type if we are going to be changing it
//
if ( ConfigChangeRequired ) {
LPQUERY_SERVICE_CONFIG ServiceConfig = NULL; DWORD Size = 0; BOOL fSuccess;
QueryServiceConfig( hSvc, ServiceConfig, Size, &Size );
ASSERT( GetLastError() == ERROR_INSUFFICIENT_BUFFER );
DSROLEP_ALLOCA( (PVOID)ServiceConfig, Size); if ( !ServiceConfig ) {
WinError = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup;
} fSuccess = QueryServiceConfig( hSvc, ServiceConfig, Size, &Size );
if ( !fSuccess ) { WinError = GetLastError(); goto Cleanup; }
PreviousStartType = ServiceConfig->dwStartType; }
//
// Do the config change
//
if ( ConfigChangeRequired ) {
//
// Make a new dependency list
//
if ( Dependency ) { WinError = DsRolepMakeAdjustedDependencyList( hSvc, ServiceOptions, Dependency, &NewDependencyList ); if ( ERROR_SUCCESS != WinError ) { goto Cleanup; } }
//
// Change the service with new parameters
//
if ( ChangeServiceConfig( hSvc, SERVICE_NO_CHANGE, NewStartType, SERVICE_NO_CHANGE, NULL, NULL, 0, NewDependencyList, NULL, NULL, NULL ) == FALSE ) { WinError = GetLastError(); DsRolepLogOnFailure( WinError, DsRolepLogPrint(( DEB_TRACE, "ChangeServiceConfig on %ws failed with %lu\n", ServiceName, WinError )) );
goto Cleanup; }
}
// Stop the service.
if ( FLAG_ON( ServiceOptions, DSROLEP_SERVICE_STOP ) || FLAG_ON( ServiceOptions, DSROLEP_SERVICE_STOP_ISM ) ) { SERVICE_STATUS SvcStatus; WinError = ERROR_SUCCESS; //
// Enumerate all of the dependent services first
//
if(EnumDependentServices( hSvc, SERVICE_ACTIVE, NULL, 0, &DependSvcSize, &DependSvcCount ) == FALSE ) { WinError = GetLastError(); } if ( WinError == ERROR_MORE_DATA ) { DependentServices = RtlAllocateHeap( RtlProcessHeap(), 0, DependSvcSize ); if ( DependentServices == NULL) { WinError = ERROR_OUTOFMEMORY; } else { if( EnumDependentServices( hSvc, SERVICE_ACTIVE, DependentServices, DependSvcSize, &DependSvcSize, &DependSvcCount ) == FALSE ) { WinError = GetLastError(); } else { for ( i = 0; i < DependSvcCount; i++) { DsRoleDebugOut(( DEB_TRACE, "Service %ws depends on %ws\n", DependentServices[i].lpServiceName, ServiceName )); WinError = DsRolepConfigureService( DependentServices[i].lpServiceName, DSROLEP_SERVICE_STOP, NULL, NULL );
if ( FLAG_ON( ServiceOptions, DSROLEP_SERVICE_IGNORE_ERRORS ) ) {
// We don't want to fail when the flag is set.
WinError = ERROR_SUCCESS;
} else if ( WinError != ERROR_SUCCESS ) { break; } } } RtlFreeHeap( RtlProcessHeap(), 0, DependentServices ); } } if ( WinError == ERROR_SUCCESS ) { if ( (FLAG_ON( ServiceOptions, DSROLEP_SERVICE_STOP_ISM )? ControlService( hSvc, ISM_SERVICE_CONTROL_REMOVE_STOP, &SvcStatus ): ControlService( hSvc, SERVICE_CONTROL_STOP, &SvcStatus )) == FALSE ) { WinError = GetLastError(); //
// It's not an error if the service wasn't running
//
if ( WinError == ERROR_SERVICE_NOT_ACTIVE ) { WinError = ERROR_SUCCESS; } } else { WinError = ERROR_SUCCESS; //
// Wait for the service to stop
//
AccumulatedSleepTime = 0; while ( TRUE ) { if( QueryServiceStatus( hSvc,&SvcStatus ) == FALSE ) { WinError = GetLastError(); } if ( WinError != ERROR_SUCCESS || SvcStatus.dwCurrentState == SERVICE_STOPPED) { break; }
if ( AccumulatedSleepTime < MaxSleepTime ) {
if ( 0 == SvcStatus.dwWaitHint ) {
//if we are told not to wait we will
//wait for 5 seconds anyway.
//bug # 221482
Sleep ( 5000 ); AccumulatedSleepTime += 5000;
} else {
Sleep( SvcStatus.dwWaitHint ); AccumulatedSleepTime += SvcStatus.dwWaitHint;
}
} else {
//
// Give up and return an error
//
WinError = WAIT_TIMEOUT; break; } } } DsRoleDebugOut(( DEB_TRACE, "StopService on %ws returned %lu\n", ServiceName, WinError )); } DsRolepLogOnFailure( WinError, DsRolepLogPrint(( DEB_TRACE, "StopService on %ws failed with %lu\n", ServiceName, WinError )) );
if ( ERROR_SUCCESS != WinError ) { goto Cleanup; } }
if ( FLAG_ON( ServiceOptions, DSROLEP_SERVICE_START ) ) {
//
// See about changing its state
//
if ( StartService( hSvc, 0, NULL ) == FALSE ) {
WinError = GetLastError();
} else {
WinError = ERROR_SUCCESS; }
DsRoleDebugOut(( DEB_TRACE, "StartService on %ws returned %lu\n", ServiceName, WinError )); DsRolepLogOnFailure( WinError, DsRolepLogPrint(( DEB_TRACE, "StartService on %ws failed with %lu\n", ServiceName, WinError )) );
if ( ERROR_SUCCESS != WinError ) { goto Cleanup; }
}
//
// Success! By the time we are here, we have completed the task asked
// of us, so set the Revert parameter
//
ASSERT( ERROR_SUCCESS == WinError ); if ( RevertServiceOptions ) {
*RevertServiceOptions = 0;
if( FLAG_ON( ServiceOptions, DSROLEP_SERVICE_STOP ) && fServiceWasRunning ) {
*RevertServiceOptions |= DSROLEP_SERVICE_START; } if( FLAG_ON( ServiceOptions, DSROLEP_SERVICE_START ) && !fServiceWasRunning ) {
*RevertServiceOptions |= DSROLEP_SERVICE_STOP; }
if ( PreviousStartType != SERVICE_NO_CHANGE ) { *RevertServiceOptions |= DsRolepServiceFlagsToDsRolepFlags( PreviousStartType ); }
if ( FLAG_ON( ServiceOptions, DSROLEP_SERVICE_DEP_ADD ) ) { *RevertServiceOptions |= DSROLEP_SERVICE_DEP_REMOVE; }
if ( FLAG_ON( ServiceOptions, DSROLEP_SERVICE_DEP_REMOVE ) ) { *RevertServiceOptions |= DSROLEP_SERVICE_DEP_ADD; } }
Cleanup:
if ( hSvc ) {
CloseServiceHandle( hSvc );
}
if ( hScMgr ) { CloseServiceHandle( hScMgr );
}
if ( NewDependencyList ) {
RtlFreeHeap(RtlProcessHeap(), 0, NewDependencyList); }
DsRolepLogPrint(( DEB_TRACE, "Configuring service %ws to %lu returned %lu\n", ServiceName, ServiceOptions, WinError ));
if ( FLAG_ON( ServiceOptions, DSROLEP_SERVICE_IGNORE_ERRORS ) ) {
if ( WinError != ERROR_SUCCESS ) { //log an event that states that the new start type
// couldn't be set for the service.
SpmpReportEvent( TRUE, EVENTLOG_WARNING_TYPE, DSROLERES_FAILED_CONFIGURE_SERVICE_STARTTYPE, 0, sizeof( ULONG ), &WinError, 2, DsRolepFlagsToString(ServiceOptions), ServiceName);
DSROLEP_SET_NON_FATAL_ERROR( WinError );
if ( Dependency ) {
//log an event that states that the new start type
// couldn't be set for the service.
SpmpReportEvent( TRUE, EVENTLOG_WARNING_TYPE, DSROLERES_FAILED_CONFIGURE_SERVICE_DEPENDENCY, 0, sizeof( ULONG ), &WinError, 2, ServiceName, Dependency);
}
}
//We don't fail promotion because of errors configuring services
//when this flag is set.
WinError = ERROR_SUCCESS;
}
DSROLEP_FAIL1( WinError, DSROLERES_SERVICE_CONFIGURE, ServiceName );
return( WinError ); }
DWORD DsRolepMakeAdjustedDependencyList( IN HANDLE hSvc, IN DWORD ServiceOptions, IN LPWSTR Dependency, OUT LPWSTR *NewDependencyList ) /*++
Routine Description
This function adds or removes Dependency from the service referred to by hSvc.
Parameters
hSvc, a handle to an open service
ServiceOptions, either DSROLEP_SERVICE_DEP_REMOVE or DSROLEP_SERVICE_DEP_ADD
Dependency, null terminated string
NewDependencyList, a block list of strings to freed by the caller
Return Values
ERROR_SUCCESS if no errors; a system service error otherwise.
--*/ { DWORD WinError = STATUS_SUCCESS; BOOLEAN fDone = FALSE;
WCHAR *CurrentDependency; ULONG CurrentDependencyLength;
ULONG DependencySize; ULONG DependencyListSize; ULONG NewDependencyListSize;
LPWSTR TempDependencyList = NULL; WCHAR *CurrNewList;
LPQUERY_SERVICE_CONFIG ServiceConfigInfo=NULL;
//
// Query for the existing dependencies
//
WinError = DsRolepGetServiceConfig(NULL, NULL, hSvc, &ServiceConfigInfo);
if (ERROR_SUCCESS != WinError) { goto Cleanup; }
if (FLAG_ON(ServiceOptions, DSROLEP_SERVICE_DEP_ADD)) {
// Get the size of the dependency
DependencySize = (wcslen(Dependency) + 1)*sizeof(WCHAR); // for NULL
// Get the size of the dependency list
DependencyListSize = 0; CurrentDependency = ServiceConfigInfo->lpDependencies; while (CurrentDependency && *CurrentDependency != L'\0') {
// Get the current list size
if (!_wcsicmp(CurrentDependency, Dependency)) { //
// Dependency is already here
//
break; fDone = TRUE; }
CurrentDependencyLength = wcslen(CurrentDependency) + 1; // for NULL
DependencyListSize += CurrentDependencyLength * sizeof(WCHAR);
CurrentDependency += CurrentDependencyLength;
}
if ( fDone ) {
WinError = ERROR_SUCCESS; goto Cleanup; }
// Calculate the size of the new dependency list
NewDependencyListSize = DependencyListSize + DependencySize + sizeof(WCHAR); // the whole string of strings
// NULL terminated
//
// Now allocate a space to hold the new dependency array
//
TempDependencyList = RtlAllocateHeap(RtlProcessHeap(), 0, NewDependencyListSize); if (!TempDependencyList) { WinError = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; }
RtlZeroMemory(TempDependencyList, NewDependencyListSize); RtlCopyMemory(TempDependencyList, ServiceConfigInfo->lpDependencies, DependencyListSize); RtlCopyMemory(&TempDependencyList[DependencyListSize/sizeof(WCHAR)], Dependency, DependencySize);
} else if (FLAG_ON(ServiceOptions, DSROLEP_SERVICE_DEP_REMOVE)) {
// Get the size of the dependency
DependencySize = (wcslen(Dependency) + 1)*sizeof(WCHAR); // for NULL
// Get the size of the dependency list
DependencyListSize = 0; CurrentDependency = ServiceConfigInfo->lpDependencies; while (CurrentDependency && *CurrentDependency != L'\0') {
CurrentDependencyLength = wcslen(CurrentDependency) + 1; // for NULL
DependencyListSize += CurrentDependencyLength * sizeof(WCHAR);
CurrentDependency += CurrentDependencyLength;
}
// Calculate the size of the new dependency list
NewDependencyListSize = DependencyListSize + sizeof(WCHAR); // the whole string of strings
// NULL terminated
//
// Now allocate a space to hold the new dependency array
// This is overkill, but not much.
//
TempDependencyList = RtlAllocateHeap(RtlProcessHeap(), 0, NewDependencyListSize); if (!TempDependencyList) { WinError = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; }
RtlZeroMemory(TempDependencyList, NewDependencyListSize);
CurrentDependency = ServiceConfigInfo->lpDependencies; CurrNewList = TempDependencyList;
while (CurrentDependency && *CurrentDependency != L'\0') {
CurrentDependencyLength = wcslen(CurrentDependency) + 1; // for NULL
// Get the current list size
if (!_wcsicmp(CurrentDependency, Dependency)) { //
// This is the one - don't copy it
//
} else { wcscpy(CurrNewList, CurrentDependency); CurrNewList += CurrentDependencyLength; }
CurrentDependency += CurrentDependencyLength; }
}
Cleanup:
if (WinError != ERROR_SUCCESS && TempDependencyList) { RtlFreeHeap(RtlProcessHeap(), 0, TempDependencyList); *NewDependencyList = NULL; } else { *NewDependencyList = TempDependencyList; }
if (ServiceConfigInfo) {
RtlFreeHeap(RtlProcessHeap(), 0, ServiceConfigInfo); }
return( WinError ); }
DWORD DsRolepGetServiceConfig( IN SC_HANDLE hScMgr, IN LPWSTR ServiceName, IN SC_HANDLE ServiceHandle, IN LPQUERY_SERVICE_CONFIG *ServiceConfig ) /*++
Routine Description:
Parameters:
Return Values:
ERROR_SUCCESS ERROR_NOT_ENOUGH_MEMORY
--*/ { DWORD Win32Error; SC_HANDLE hService; ULONG SizeNeeded;
#if DBG
if (!ServiceHandle) { ASSERT(ServiceName); ASSERT(hScMgr); } #endif
if (!ServiceHandle) {
hService = OpenService( hScMgr, ServiceName, SERVICE_QUERY_CONFIG ); } else {
hService = ServiceHandle;
}
if (hService) {
SizeNeeded = 0; Win32Error = ERROR_SUCCESS; if (!QueryServiceConfig(hService, NULL, 0, &SizeNeeded)) {
Win32Error = GetLastError();
} ASSERT(Win32Error == ERROR_INSUFFICIENT_BUFFER); ASSERT( SizeNeeded > 0 );
*ServiceConfig = RtlAllocateHeap(RtlProcessHeap(), 0, SizeNeeded); if (*ServiceConfig) {
Win32Error = ERROR_SUCCESS; if (!QueryServiceConfig(hService, *ServiceConfig, SizeNeeded, &SizeNeeded)) {
Win32Error = GetLastError(); }
} else {
Win32Error = ERROR_NOT_ENOUGH_MEMORY; }
if (!ServiceHandle) { CloseServiceHandle(hService); }
} else {
Win32Error = GetLastError();
}
DsRolepLogOnFailure( Win32Error, DsRolepLogPrint(( DEB_TRACE, "DsRolepGetServiceConfig on %ws failed with %lu\n", ServiceName, Win32Error )) );
return Win32Error;
}
|