/*++ 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 #include #include // alloca #include // net api definitions #include // service names #include //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; }