windows-nt/Source/XPSP1/NT/ds/security/dsrole/server/services.c

1300 lines
34 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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_DEMANDSTART,
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[] =
{
{
SERVICE_RPCLOCATOR,
DSROLEP_SERVICE_AUTOSTART,
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_AUTOSTART,
DSROLEP_SERVICE_DEMANDSTART,
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;
}
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 ( FLAG_ON( Flags, DSROLEP_SERVICES_START ) ) {
Operation |= DSROLEP_SERVICE_START;
} else if ( FLAG_ON( Flags, DSROLEP_SERVICES_STOP ) ) {
Operation |= DSROLEP_SERVICE_STOP;
}
//
// 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 );
ServiceConfig = (LPQUERY_SERVICE_CONFIG) alloca( Size );
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 ( 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 ));
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 -
DependencySize +
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;
}