|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
service.cpp
Abstract:
Routines to configure/analyze general settings of services plus some helper APIs
Author:
Jin Huang (jinhuang) 25-Jun-1997
Revision History:
--*/ #include "headers.h"
#include "serverp.h"
#include "service.h"
#include "pfp.h"
//#define SCESVC_DBG 1
DWORD ScepPollOnServiceStartStop( IN BOOL bPollOnStart, IN SC_HANDLE hService );
VOID ScepStopServiceAndAncestorServices( IN SC_HANDLE hScManager, IN PWSTR pszServiceName );
SCESTATUS ScepConfigureGeneralServices( IN PSCECONTEXT hProfile, IN PSCE_SERVICES pServiceList, IN DWORD ConfigOptions ) /*
Routine Descripton:
Configure startup and security descriptor settings for the list of services passed in.
Arguments:
pServiceList - the list of services to configure
Return Value:
SCE status */ { SCESTATUS SceErr=SCESTATUS_SUCCESS; PSCE_SERVICES pNode; DWORD nServices=0; BOOL bDoneSettingSaclDacl = FALSE; NTSTATUS NtStatus = 0; SID_IDENTIFIER_AUTHORITY IdAuth=SECURITY_NT_AUTHORITY; DWORD rcSaveRsop = ERROR_SUCCESS;
PSCESECTION hSectionDomain=NULL; PSCESECTION hSectionTattoo=NULL; PSCE_SERVICES pServiceCurrent=NULL; DWORD ServiceLen=0; BOOL bIgnoreStartupType = FALSE;
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) && ScepIsSystemShutDown() ) {
return(SCESTATUS_SERVICE_NOT_SUPPORT); }
if ( pServiceList != NULL ) {
SC_HANDLE hScManager; //
// open the manager
//
hScManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS // SC_MANAGER_CONNECT |
// SC_MANAGER_QUERY_LOCK_STATUS |
// SC_MANAGER_MODIFY_BOOT_CONFIG
);
SC_HANDLE hService=NULL; DWORD rc=NO_ERROR;
if ( NULL == hScManager ) {
rc = GetLastError(); ScepLogOutput3(1, rc, SCEDLL_ERROR_OPEN, L"Service Control Manager");
ScepPostProgress(TICKS_GENERAL_SERVICES, AREA_SYSTEM_SERVICE, NULL);
return( ScepDosErrorToSceStatus(rc) ); }
LPQUERY_SERVICE_CONFIG pConfig=NULL; DWORD BytesNeeded;
//
// Adjust privilege for setting SACL
//
rc = SceAdjustPrivilege( SE_SECURITY_PRIVILEGE, TRUE, NULL );
//
// if can't adjust privilege, ignore (will error out later if SACL is requested)
//
if ( rc != NO_ERROR ) {
ScepLogOutput3(1, rc, SCEDLL_ERROR_ADJUST, L"SE_SECURITY_PRIVILEGE"); rc = NO_ERROR; }
//
// Adjust privilege for setting ownership (if required)
//
rc = SceAdjustPrivilege( SE_TAKE_OWNERSHIP_PRIVILEGE, TRUE, NULL );
//
// if can't adjust privilege, ignore (will error out later if acls need to be written)
//
if ( rc != NO_ERROR ) {
ScepLogOutput3(1, rc, SCEDLL_ERROR_ADJUST, L"SE_TAKE_OWNERSHIP_PRIVILEGE"); rc = NO_ERROR; }
//
// get AdminsSid in case need to take ownership later
//
NtStatus = RtlAllocateAndInitializeSid( &IdAuth, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdminsSid );
//
// open the policy/tattoo tables
//
if ( ConfigOptions & SCE_POLICY_TEMPLATE ) {
ScepTattooOpenPolicySections( hProfile, szServiceGeneral, &hSectionDomain, &hSectionTattoo ); }
//
// Loop through each service to set general setting
//
for ( pNode=pServiceList; pNode != NULL && rc == NO_ERROR; pNode = pNode->Next ) {
//
// to ignore startup type, the inf template will have svcname,,"SDDL"
// on import, the database gets svcname,0,"SDDL"
// so we have to ignore the startuptype of 0 for this service
//
if (pNode->Startup == 0) { bIgnoreStartupType = TRUE; }
//
// print the service name
//
if ( nServices < TICKS_GENERAL_SERVICES ) { ScepPostProgress(1, AREA_SYSTEM_SERVICE, pNode->ServiceName); nServices++; }
ScepLogOutput3(2,0, SCEDLL_SCP_CONFIGURE, pNode->ServiceName);
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) && ScepIsSystemShutDown() ) {
rc = ERROR_NOT_SUPPORTED; break; }
ServiceLen = 0; if ( (ConfigOptions & SCE_POLICY_TEMPLATE) && hSectionDomain && hSectionTattoo ) { //
// check if we need to query current setting for the service
//
ServiceLen = wcslen(pNode->ServiceName);
if ( ScepTattooIfQueryNeeded(hSectionDomain, hSectionTattoo, pNode->ServiceName, ServiceLen, NULL, NULL ) ) {
rc = ScepQueryAndAddService( hScManager, pNode->ServiceName, NULL, &pServiceCurrent ); if ( ERROR_SUCCESS != rc ) { ScepLogOutput3(1,0,SCESRV_POLICY_TATTOO_ERROR_QUERY,rc,pNode->ServiceName); rc = NO_ERROR; } else { ScepLogOutput3(3,0,SCESRV_POLICY_TATTOO_QUERY,pNode->ServiceName); } } }
bDoneSettingSaclDacl = FALSE; rcSaveRsop = ERROR_SUCCESS; //
// open the service
//
hService = OpenService( hScManager, pNode->ServiceName, SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | READ_CONTROL | WRITE_DAC | // WRITE_OWNER | owner can't be set for a service
ACCESS_SYSTEM_SECURITY );
// if access was denied, try to take ownership
// and try to open service again
if (hService == NULL && (ERROR_ACCESS_DENIED == (rc = GetLastError())) && pNode->General.pSecurityDescriptor) {
DWORD rcTakeOwnership = NO_ERROR;
if (AdminsSid) {
if ( NO_ERROR == (rcTakeOwnership = SetNamedSecurityInfo( (LPWSTR)pNode->ServiceName, SE_SERVICE, OWNER_SECURITY_INFORMATION, AdminsSid, NULL, NULL, NULL ))) {
//
// ownership changed, open service again and set SACL and DACL
// get a handle to set security
//
if ( hService = OpenService( hScManager, pNode->ServiceName, READ_CONTROL | WRITE_DAC | ACCESS_SYSTEM_SECURITY )) {
if ( SetServiceObjectSecurity( hService, pNode->SeInfo & (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION), pNode->General.pSecurityDescriptor ) ) {
bDoneSettingSaclDacl = TRUE;
CloseServiceHandle(hService); hService = NULL;
//
// re-open the service only if there are other config info
// to set (startup type).
// So when NOSTARTTYPE is set, do not need to reopen the service
//
if (FALSE == bIgnoreStartupType) {
if (!(hService = OpenService( hScManager, pNode->ServiceName, SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG )) ) {
rc = GetLastError(); } else {
//
//clear any error we have seen so far since everything has succeeded
//
rc = NO_ERROR; } }
} else { //
// shouldn't fail here unless Service Control Manager
// fails for some reason.
//
rc = GetLastError();
}
} else { //
// still fail to open the service to set DACL. this should
// not happen for admin logons since the current logon is
// one of the owner. But for normal user logon, this could
// fail (actually normal user logon should fail to set
// the owner
rc = GetLastError();
}
}
} else { //
// AdminSid failed to be initialized, get the error
//
rcTakeOwnership = RtlNtStatusToDosError(NtStatus); }
if ( NO_ERROR != rcTakeOwnership || NO_ERROR != rc ) { //
// log the error occurred in take ownership process
// reset error back to access denied so it will also be
// logged as failure to open the service
//
if (NO_ERROR != rcTakeOwnership)
ScepLogOutput3(2,rcTakeOwnership, SCEDLL_ERROR_TAKE_OWNER, (LPWSTR)pNode->ServiceName);
else
ScepLogOutput3(2, rc, SCEDLL_ERROR_OPEN, (LPWSTR)pNode->ServiceName);
rc = ERROR_ACCESS_DENIED; }
}
if ( hService != NULL ) {
if (bIgnoreStartupType == TRUE) { //
// do not configure service start type
//
if ( pNode->General.pSecurityDescriptor != NULL ) {
if ( !SetServiceObjectSecurity( hService, pNode->SeInfo & (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION), pNode->General.pSecurityDescriptor ) ) {
rc = GetLastError(); } else bDoneSettingSaclDacl = TRUE; }
} else {
//
// Phase-1 (in phase-2 the service will be started/stopped real-time)
//
//
// query the length of config
//
if ( !QueryServiceConfig( hService, NULL, 0, &BytesNeeded ) ) {
rc = GetLastError();
if ( rc == ERROR_INSUFFICIENT_BUFFER ) {
pConfig = (LPQUERY_SERVICE_CONFIG)ScepAlloc(0, BytesNeeded);
if ( pConfig != NULL ) { //
// the real query of config
//
if ( QueryServiceConfig( hService, pConfig, BytesNeeded, &BytesNeeded ) ) { rc = ERROR_SUCCESS;
//
// change pConfig->dwStartType to the new value
//
if ( pNode->Startup != (BYTE)(pConfig->dwStartType) ) { //
// configure the service startup
//
if ( !ChangeServiceConfig( hService, pConfig->dwServiceType, pNode->Startup, pConfig->dwErrorControl, pConfig->lpBinaryPathName, pConfig->lpLoadOrderGroup, NULL, pConfig->lpDependencies, NULL, NULL, pConfig->lpDisplayName ) ) {
rc = GetLastError();
} }
if ( rc == NO_ERROR && pNode->General.pSecurityDescriptor != NULL && !bDoneSettingSaclDacl) {
if ( !SetServiceObjectSecurity( hService, pNode->SeInfo & (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION), pNode->General.pSecurityDescriptor ) ) {
rc = GetLastError(); } else bDoneSettingSaclDacl = TRUE; }
} else {
rc = GetLastError();
ScepLogOutput3(3,rc, SCEDLL_ERROR_QUERY_INFO, pNode->ServiceName); }
ScepFree(pConfig); pConfig = NULL;
} else { //
// cannot allocate pConfig
//
rc = ERROR_NOT_ENOUGH_MEMORY; } } else {
ScepLogOutput3(3,rc, SCEDLL_ERROR_QUERY_INFO, pNode->ServiceName); }
} else { //
// should not fall in here
//
rc = ERROR_SUCCESS; } }
CloseServiceHandle (hService); hService = NULL;
if ( rc != NO_ERROR ) {
ScepLogOutput3(1, rc, SCEDLL_SCP_ERROR_CONFIGURE, pNode->ServiceName);
rcSaveRsop = rc;
if ( ERROR_INVALID_OWNER == rc || ERROR_INVALID_PRIMARY_GROUP == rc || ERROR_INVALID_SECURITY_DESCR == rc || ERROR_INVALID_ACL == rc || ERROR_ACCESS_DENIED == rc ) {
gWarningCode = rc; rc = NO_ERROR; } } } else { //
// cannot open the service or some error taking ownership
//
if (rc != NO_ERROR) { ScepLogOutput3(1, rc, SCEDLL_ERROR_OPEN, pNode->ServiceName); // either of setting security/startup type failed - save it for RSOP log
rcSaveRsop = (rcSaveRsop == ERROR_SUCCESS ? rc: rcSaveRsop); if ( rc == ERROR_SERVICE_DOES_NOT_EXIST ) rc = NO_ERROR; } }
if (ConfigOptions & SCE_RSOP_CALLBACK)
ScepRsopLog(SCE_RSOP_SERVICES_INFO, rcSaveRsop != NO_ERROR ? rcSaveRsop : rc, pNode->ServiceName, 0, 0);
if ( (ConfigOptions & SCE_POLICY_TEMPLATE) && hSectionDomain && hSectionTattoo ) { //
// manage the tattoo value of this one
//
ScepTattooManageOneServiceValue( hSectionDomain, hSectionTattoo, pNode->ServiceName, ServiceLen, pServiceCurrent, rc ); }
if ( pServiceCurrent ) { SceFreePSCE_SERVICES(pServiceCurrent); pServiceCurrent = NULL; }
bIgnoreStartupType = FALSE;
} if ( !(ConfigOptions & SCE_SERVICE_NO_REALTIME_ENFORCE) ) {
//
// real-time start/stop only if NOT in setup/dcpromo
// i.e. whenever SCE_SETUP_SERVICE_NOSTARTTYPE was used before
//
//
// Phase-2 (in phase-1 the startup-type was only configured but not enforced real-time)
//
for ( pNode=pServiceList; pNode != NULL ; pNode = pNode->Next ) {
if (pNode->Startup == SERVICE_DISABLED) {
//
// we should also stop the ancestor services
//
ScepStopServiceAndAncestorServices(hScManager, pNode->ServiceName);
}
else if (pNode->Startup == SERVICE_AUTO_START) {
//
// if the service type is "automatic", we should start the service
// Note: dependencies are already taken care of by SCM
//
if ( hService = OpenService( hScManager, pNode->ServiceName, SERVICE_START | SERVICE_QUERY_STATUS )) {
SERVICE_STATUS ServiceStatus;
if (!StartService(hService, 0, NULL )) { if ( ERROR_SERVICE_ALREADY_RUNNING != GetLastError() ) { ScepLogOutput3(2, GetLastError(), SCEDLL_SCP_ERROR_START, pNode->ServiceName); } }
else {
DWORD dwError;
dwError = ScepPollOnServiceStartStop( TRUE , hService );
if ( dwError != ERROR_SUCCESS ) { ScepLogOutput3(2, dwError, SCEDLL_SCP_ERROR_START, pNode->ServiceName); }
}
CloseServiceHandle (hService); hService = NULL;
} else { ScepLogOutput3(2, GetLastError(), SCEDLL_SCP_ERROR_OPENFORSTART, pNode->ServiceName); } } } }
CloseServiceHandle (hScManager);
if (AdminsSid) { RtlFreeSid(AdminsSid); AdminsSid = NULL; }
SceAdjustPrivilege( SE_TAKE_OWNERSHIP_PRIVILEGE, FALSE, NULL ); SceAdjustPrivilege( SE_SECURITY_PRIVILEGE, FALSE, NULL );
SceErr = ScepDosErrorToSceStatus(rc); }
if ( nServices < TICKS_GENERAL_SERVICES ) {
ScepPostProgress(TICKS_GENERAL_SERVICES-nServices, AREA_SYSTEM_SERVICE, NULL); }
SceJetCloseSection(&hSectionDomain, TRUE); SceJetCloseSection(&hSectionTattoo, TRUE);
return(SceErr);
}
DWORD ScepPollOnServiceStartStop( IN BOOL bPollOnStart, IN SC_HANDLE hService ) /*
Routine Descripton:
This routine polls on a service until it is really started or stopped using time-slice hints.
Arguments:
bPollOnStart - if TRUE (FALSE), polls until really started (stopped) hService - handle to service to poll on
Return Value:
win32 error code - ERROR_SUCCESS or other error */ { SERVICE_STATUS ssStatus; DWORD dwOldCheckPoint; DWORD dwStartTickCount; DWORD dwWaitTime; DWORD dwStatus = ERROR_SUCCESS; //
// Check the status until the service is no longer pending (start or stop)
//
if (!QueryServiceStatus( hService, &ssStatus) ) { dwStatus = GetLastError(); goto ExitHandler; } //
// Save the tick count and initial checkpoint.
//
dwStartTickCount = GetTickCount(); dwOldCheckPoint = ssStatus.dwCheckPoint;
//
// Poll until service has started or stopped
//
while (!((bPollOnStart && ssStatus.dwCurrentState == SERVICE_RUNNING) || (!bPollOnStart && ssStatus.dwCurrentState == SERVICE_STOPPED ))) { //
// Do not wait longer than the wait hint. A good interval is
// one tenth the wait hint, but no less than 1 second and no
// more than 10 seconds.
//
dwWaitTime = ssStatus.dwWaitHint / 10;
if( dwWaitTime < 1000 ) dwWaitTime = 1000; else if ( dwWaitTime > 10000 ) dwWaitTime = 10000;
Sleep( dwWaitTime ); //
// Check the status again.
//
if (!QueryServiceStatus( hService, &ssStatus) ) { dwStatus = GetLastError(); goto ExitHandler; }
if ( ssStatus.dwCheckPoint > dwOldCheckPoint ) { //
// The service is making progress since the checkpoint has been updated.
//
dwStartTickCount = GetTickCount(); dwOldCheckPoint = ssStatus.dwCheckPoint; } else { if(GetTickCount()-dwStartTickCount > ssStatus.dwWaitHint) { //
// No progress made within the wait hint - stop polling
//
break; } } } //
// final check on desired condition
//
if (!((bPollOnStart && ssStatus.dwCurrentState == SERVICE_RUNNING) || (!bPollOnStart && ssStatus.dwCurrentState == SERVICE_STOPPED ))) dwStatus = ERROR_SERVICE_REQUEST_TIMEOUT;
ExitHandler:
return dwStatus;
}
VOID ScepStopServiceAndAncestorServices( IN SC_HANDLE hScManager, IN PWSTR pszServiceName ) /*
Routine Description:
Stop the named service and all other services that are dependent on it.
Arguments:
hScManager - handle to the Service Control Manager pszServiceName - name of the service to be stopped
Return Value:
None: */ { SC_HANDLE hService=NULL; LPENUM_SERVICE_STATUS pArrServices = NULL; if ( hService = OpenService( hScManager, pszServiceName, SERVICE_STOP | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_QUERY_STATUS )) { //
// get an array of ancestor services, greatest-ancestor first
//
DWORD dwBufSizeSupplied = 0; DWORD dwBufSizeRequired = 0; DWORD dwNumServicesReturned = 0;
//
// first, get the required size of the array
//
if (!EnumDependentServices( hService, SERVICE_STATE_ALL, pArrServices, 0, &dwBufSizeRequired, &dwNumServicesReturned )) {
if (ERROR_MORE_DATA != GetLastError()) { ScepLogOutput3(2, GetLastError(), SCEDLL_SCP_ERROR_STOP, pszServiceName); goto ExitHandler; } }
pArrServices = (ENUM_SERVICE_STATUS *) LocalAlloc (LMEM_ZEROINIT, dwBufSizeRequired);
if (pArrServices == NULL) {
ScepLogOutput3(2, ERROR_NOT_ENOUGH_MEMORY, SCEDLL_SCP_ERROR_STOP, pszServiceName); goto ExitHandler; }
//
// second, get the array of dependent services
//
if (!EnumDependentServices( hService, SERVICE_STATE_ALL, pArrServices, dwBufSizeRequired, &dwBufSizeRequired, &dwNumServicesReturned )) {
ScepLogOutput3(2, GetLastError(), SCEDLL_SCP_ERROR_STOP, pszServiceName);
goto ExitHandler;
}
//
// first stop all the ancestor services
// if any of them fails to stop, log it and continue
//
for (DWORD dwServiceIndex = 0; dwServiceIndex < dwNumServicesReturned; dwServiceIndex++ ) {
SC_HANDLE hAncestorService = NULL;
if ( hAncestorService = OpenService( hScManager, pArrServices[dwServiceIndex].lpServiceName, SERVICE_STOP | SERVICE_QUERY_STATUS )) {
SERVICE_STATUS ServiceStatus;
if (!ControlService(hAncestorService, SERVICE_CONTROL_STOP, &ServiceStatus )) { if ( ERROR_SERVICE_NOT_ACTIVE != GetLastError() ) { ScepLogOutput3(2, GetLastError(), SCEDLL_SCP_ERROR_STOP, pArrServices[dwServiceIndex].lpServiceName); } }
else { //
// move on only if this service stopped
//
DWORD dwError;
dwError = ScepPollOnServiceStartStop( FALSE , hAncestorService );
if ( dwError != ERROR_SUCCESS ) { ScepLogOutput3(2, dwError, SCEDLL_SCP_ERROR_STOP, pArrServices[dwServiceIndex].lpServiceName); } }
CloseServiceHandle (hAncestorService); hAncestorService = NULL;
} else { ScepLogOutput3(2, GetLastError(), SCEDLL_SCP_ERROR_OPENFORSTOP, pArrServices[dwServiceIndex].lpServiceName); }
}
LocalFree ( pArrServices ); pArrServices = NULL;
//
// finally, stop the service itself
//
SERVICE_STATUS ServiceStatus;
if (!ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus )) { if ( ERROR_SERVICE_NOT_ACTIVE != GetLastError() ) { ScepLogOutput3(2, GetLastError(), SCEDLL_SCP_ERROR_STOP, pszServiceName); } } else {
DWORD dwError;
dwError = ScepPollOnServiceStartStop( FALSE , hService );
if ( dwError != ERROR_SUCCESS ) { ScepLogOutput3(2, dwError, SCEDLL_SCP_ERROR_STOP, pszServiceName); }
}
CloseServiceHandle (hService); hService = NULL;
} else { ScepLogOutput3(2, GetLastError(), SCEDLL_SCP_ERROR_OPENFORSTOP, pszServiceName); }
ExitHandler: if ( hService ) CloseServiceHandle (hService); if ( pArrServices ) LocalFree ( pArrServices );
}
SCESTATUS ScepAnalyzeGeneralServices( IN PSCECONTEXT hProfile, IN DWORD Options ) /*
Routine Description:
Analyze all available services on the current system.
The base profile (SCEP) is in hProfile
Arguments:
hProfile - the database context handle
Return Value:
SCE status */ { if ( hProfile == NULL ) {
ScepPostProgress(TICKS_GENERAL_SERVICES, AREA_SYSTEM_SERVICE, NULL);
return(SCESTATUS_INVALID_PARAMETER); }
SCESTATUS rc; PSCE_SERVICES pServiceList=NULL; DWORD nServices=0;
rc = SceEnumerateServices( &pServiceList, FALSE ); rc = ScepDosErrorToSceStatus(rc);
if ( rc == SCESTATUS_SUCCESS ) {
PSCESECTION hSectionScep=NULL, hSectionSap=NULL; //
// open the sap section. If it is not there, creates it
//
rc = ScepStartANewSection( hProfile, &hSectionSap, (Options & SCE_GENERATE_ROLLBACK) ? SCEJET_TABLE_SMP : SCEJET_TABLE_SAP, szServiceGeneral );
if ( rc == SCESTATUS_SUCCESS ) {
PSCE_SERVICES pNode = pServiceList; //
// open SCEP section. should be success always because the StartANewSection
// creates the section if it is not there
//
rc = ScepOpenSectionForName( hProfile, (Options & SCE_GENERATE_ROLLBACK) ? SCE_ENGINE_SMP : SCE_ENGINE_SCP, // SCE_ENGINE_SMP,
szServiceGeneral, &hSectionScep );
if ( rc == SCESTATUS_SUCCESS ) {
//
// analyze each service
//
PSCE_SERVICES pOneService=NULL; BOOL IsDifferent;
for ( pNode=pServiceList; pNode != NULL; pNode=pNode->Next ) {
ScepLogOutput3(2, 0, SCEDLL_SAP_ANALYZE, pNode->ServiceName);
if ( nServices < TICKS_SPECIFIC_SERVICES ) {
ScepPostProgress(1, AREA_SYSTEM_SERVICE, NULL); nServices++; }
//
// get setting from the SMP profile
//
rc = ScepGetSingleServiceSetting( hSectionScep, pNode->ServiceName, &pOneService );
if ( rc == SCESTATUS_SUCCESS ) { //
// there is a SMP entry for the service, compare and save
//
rc = ScepCompareSingleServiceSetting( pOneService, pNode, &IsDifferent );
if ( rc == SCESTATUS_SUCCESS && IsDifferent ) { //
// write the service as mismatch
//
pNode->Status = (Options & SCE_GENERATE_ROLLBACK) ? 0 : SCE_STATUS_MISMATCH; pNode->SeInfo = pOneService->SeInfo;
rc = ScepSetSingleServiceSetting( hSectionSap, pNode ); }
} else if ( rc == SCESTATUS_RECORD_NOT_FOUND ) {
//
// this service is not defined
//
if ( !(Options & SCE_GENERATE_ROLLBACK) ) { //
// save the record with not configured status
//
pNode->Status = SCE_STATUS_NOT_CONFIGURED;
rc = ScepSetSingleServiceSetting( hSectionSap, pNode ); } else { //
// ignore this one
//
rc = SCESTATUS_SUCCESS; } }
SceFreePSCE_SERVICES(pOneService); pOneService = NULL;
if ( rc != SCESTATUS_SUCCESS ) { ScepLogOutput3(1, ScepSceStatusToDosError(rc), SCEDLL_SAP_ERROR_ANALYZE, pNode->ServiceName);
if ( SCESTATUS_ACCESS_DENIED == rc ) { gWarningCode = ScepSceStatusToDosError(rc);
if ( !(Options & SCE_GENERATE_ROLLBACK) ) {
//
// raise a error status
//
pNode->Status = SCE_STATUS_ERROR_NOT_AVAILABLE;
rc = ScepSetSingleServiceSetting( hSectionSap, pNode ); } rc = SCESTATUS_SUCCESS; } else {
break; } }
}
SceJetCloseSection(&hSectionScep, TRUE); }
if ( !(Options & SCE_GENERATE_ROLLBACK ) ) {
//
// raise any error item
//
for ( PSCE_SERVICES pNodeTmp=pNode; pNodeTmp != NULL; pNodeTmp = pNodeTmp->Next ) {
pNodeTmp->Status = SCE_STATUS_ERROR_NOT_AVAILABLE;
ScepSetSingleServiceSetting( hSectionSap, pNode ); } }
SceJetCloseSection(&hSectionSap, TRUE); } if ( rc != SCESTATUS_SUCCESS ) ScepLogOutput3(1, ScepSceStatusToDosError(rc), SCEDLL_SAP_ERROR_OUT);
}
if ( nServices < TICKS_GENERAL_SERVICES ) {
ScepPostProgress(TICKS_GENERAL_SERVICES-nServices, AREA_SYSTEM_SERVICE, NULL); }
SceFreePSCE_SERVICES(pServiceList); return(rc);
}
SCESTATUS ScepGetSingleServiceSetting( IN PSCESECTION hSection, IN PWSTR ServiceName, OUT PSCE_SERVICES *pOneService ) /*
Routine Description:
Get service settings for the service from the section
Arguments:
hSection - the section handle
ServiceName - the service name
pOneService - the service settings
Return Value:
SCE status */ { if ( hSection == NULL || ServiceName == NULL || pOneService == NULL ) { return(SCESTATUS_INVALID_PARAMETER); }
SCESTATUS rc; DWORD ValueLen; //
// seek to the record and get length for name and value
//
rc = SceJetGetValue( hSection, SCEJET_EXACT_MATCH_NO_CASE, ServiceName, NULL, 0, NULL, NULL, 0, &ValueLen );
if ( rc == SCESTATUS_SUCCESS ) {
PWSTR Value=NULL;
//
// allocate memory for the service name and value string
//
Value = (PWSTR)ScepAlloc( LMEM_ZEROINIT, ValueLen+2); if ( Value != NULL ) { //
// Get the service and its value
//
rc = SceJetGetValue( hSection, SCEJET_CURRENT, NULL, NULL, 0, NULL, Value, ValueLen, &ValueLen );
if ( rc == SCESTATUS_SUCCESS ) {
Value[ValueLen/2] = L'\0';
DWORD Win32Rc=NO_ERROR; PSECURITY_DESCRIPTOR pTempSD=NULL; DWORD SDsize=0; SECURITY_INFORMATION SeInfo=0;
if ( ValueLen >= 2 && Value[1] != L'\0' ) {
//
// convert to security descriptor
//
Win32Rc = ConvertTextSecurityDescriptor( Value+1, &pTempSD, &SDsize, &SeInfo ); }
if ( Win32Rc == NO_ERROR ) {
ScepChangeAclRevision(pTempSD, ACL_REVISION);
//
// create this service node
//
*pOneService = (PSCE_SERVICES)ScepAlloc( LMEM_FIXED, sizeof(SCE_SERVICES) );
if ( *pOneService != NULL ) {
(*pOneService)->ServiceName = (PWSTR)ScepAlloc(LMEM_FIXED, (wcslen(ServiceName)+1)*sizeof(WCHAR)); if ( (*pOneService)->ServiceName != NULL ) {
wcscpy( (*pOneService)->ServiceName, ServiceName); (*pOneService)->DisplayName = NULL; (*pOneService)->Status = *((BYTE *)Value); (*pOneService)->Startup = *((BYTE *)Value+1); (*pOneService)->General.pSecurityDescriptor = pTempSD; (*pOneService)->SeInfo = SeInfo; (*pOneService)->Next = NULL;
//
// DO NOT free the following buffers
//
pTempSD = NULL;
} else { rc = SCESTATUS_NOT_ENOUGH_RESOURCE; ScepFree(*pOneService); }
} else { rc = SCESTATUS_NOT_ENOUGH_RESOURCE; } if ( pTempSD != NULL ) { ScepFree(pTempSD); }
} else { rc = ScepDosErrorToSceStatus(Win32Rc); } } ScepFree(Value);
} else rc = SCESTATUS_NOT_ENOUGH_RESOURCE; }
return(rc); }
SCESTATUS ScepCompareSingleServiceSetting( IN PSCE_SERVICES pNode1, IN PSCE_SERVICES pNode2, OUT PBOOL pIsDifferent ) /*
Routine Description:
Comare two service settings.
Arguments:
pNode1 - the first service
pNode2 - the second service
pIsDifferent - output TRUE if different
Return Value:
SCE status */ { SCESTATUS rc=SCESTATUS_SUCCESS;
//
// if Startup == 0, we should ignore comparing the startup types symmetrically
//
if ( pNode1->Startup == 0 || pNode2->Startup == 0 || pNode1->Startup == pNode2->Startup ) {
BYTE resultSD = 0; rc = ScepCompareObjectSecurity( SE_SERVICE, FALSE, pNode1->General.pSecurityDescriptor, pNode2->General.pSecurityDescriptor, pNode1->SeInfo & (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION), &resultSD ); if ( resultSD ) { *pIsDifferent = TRUE; } else *pIsDifferent = FALSE;
} else *pIsDifferent = TRUE;
return(rc); }
SCESTATUS ScepSetSingleServiceSetting( IN PSCESECTION hSection, IN PSCE_SERVICES pOneService ) /*
Routine Description:
Set service settings for the service from the section
Arguments:
hSection - the section handle
pOneService - the service settings
Return Value:
SCE status */ { if ( hSection == NULL || pOneService == NULL ) { return(SCESTATUS_INVALID_PARAMETER); }
SCESTATUS rc=SCESTATUS_SUCCESS; PWSTR SDspec=NULL; DWORD SDsize=0;
if ( (pOneService->Status != SCE_STATUS_NOT_ANALYZED) && (pOneService->Status != SCE_STATUS_ERROR_NOT_AVAILABLE) && (pOneService->General.pSecurityDescriptor != NULL) ) {
DWORD Win32Rc;
Win32Rc = ConvertSecurityDescriptorToText ( pOneService->General.pSecurityDescriptor, pOneService->SeInfo, &SDspec, &SDsize // number of w-chars
); rc = ScepDosErrorToSceStatus(Win32Rc);
}
if ( rc == SCESTATUS_SUCCESS ) {
PWSTR Value=NULL; DWORD ValueLen;
ValueLen = (SDsize+1)*sizeof(WCHAR);
Value = (PWSTR)ScepAlloc( (UINT)0, ValueLen+sizeof(WCHAR) );
if ( Value != NULL ) {
//
// The first byte is status, the second byte is startup
//
*((BYTE *)Value) = pOneService->Status;
*((BYTE *)Value+1) = pOneService->Startup;
if ( SDspec != NULL ) {
wcscpy(Value+1, SDspec); }
Value[SDsize+1] = L'\0'; //terminate this string
//
// set the value
//
rc = SceJetSetLine( hSection, pOneService->ServiceName, FALSE, Value, ValueLen, 0 );
ScepFree( Value );
switch ( pOneService->Status ) { case SCE_STATUS_ERROR_NOT_AVAILABLE: ScepLogOutput3(2, 0, SCEDLL_STATUS_ERROR, pOneService->ServiceName);
break;
case SCE_STATUS_NOT_CONFIGURED:
ScepLogOutput3(2, 0, SCEDLL_STATUS_NC, pOneService->ServiceName);
break;
case SCE_STATUS_NOT_ANALYZED:
ScepLogOutput3(2, 0, SCEDLL_STATUS_NEW, pOneService->ServiceName);
break;
default:
ScepLogOutput3(2, 0, SCEDLL_STATUS_MISMATCH, pOneService->ServiceName); break; }
} else rc = SCESTATUS_NOT_ENOUGH_RESOURCE; }
if ( SDspec != NULL ) { ScepFree( SDspec ); }
return(rc); }
SCESTATUS ScepInvokeSpecificServices( IN PSCECONTEXT hProfile, IN BOOL bConfigure, IN SCE_ATTACHMENT_TYPE aType ) /*
Routine Description:
Call each service engine for configure or analyze
Arguments:
hProfile - the profile handle
bConfigure - TRUE = to configure, FALSE=to analyze
aType - attachment type "services" or "policy"
Return Value:
SCE status */ { //
// for posting progress
//
DWORD nServices=0; AREA_INFORMATION Area=0; DWORD nMaxTicks=0;
switch(aType) { case SCE_ATTACHMENT_SERVICE: Area = AREA_SYSTEM_SERVICE; nMaxTicks = TICKS_SPECIFIC_SERVICES; break; case SCE_ATTACHMENT_POLICY: Area = AREA_SECURITY_POLICY; nMaxTicks = TICKS_SPECIFIC_POLICIES; break; }
if ( hProfile == NULL ) {
ScepPostProgress(nMaxTicks, Area, NULL);
return(SCESTATUS_INVALID_PARAMETER); } //
// call available service engines to configure specific setting
//
SCESTATUS SceErr ; PSCE_SERVICES pSvcEngineList=NULL; SCEP_HANDLE sceHandle; SCESVC_CALLBACK_INFO sceCbInfo;
SceErr = ScepEnumServiceEngines(&pSvcEngineList, aType);
if ( SceErr == SCESTATUS_SUCCESS) {
HINSTANCE hDll; PF_ConfigAnalyzeService pfTemp;
for ( PSCE_SERVICES pNode=pSvcEngineList; pNode != NULL; pNode = pNode->Next ) {
ScepLogOutput3(2, 0, SCEDLL_LOAD_ATTACHMENT, pNode->ServiceName);
if ( nServices < nMaxTicks ) {
ScepPostProgress(1, Area, pNode->ServiceName); nServices++; } //
// load the dll.
//
hDll = LoadLibrary(pNode->General.ServiceEngineName);
if ( hDll != NULL ) {
if ( bConfigure ) { //
// call SceSvcAttachmentConfig from the dll
//
pfTemp = (PF_ConfigAnalyzeService) GetProcAddress(hDll, "SceSvcAttachmentConfig") ; } else { //
// call SceSvcAttachmentAnalyze from the dll
//
pfTemp = (PF_ConfigAnalyzeService) GetProcAddress(hDll, "SceSvcAttachmentAnalyze") ;
} if ( pfTemp != NULL ) { //
// prepare the handle first
//
sceHandle.hProfile = (PVOID)hProfile; sceHandle.ServiceName = (PCWSTR)(pNode->ServiceName);
sceCbInfo.sceHandle = &sceHandle; sceCbInfo.pfQueryInfo = &SceCbQueryInfo; sceCbInfo.pfSetInfo = &SceCbSetInfo; sceCbInfo.pfFreeInfo = &SceSvcpFreeMemory; sceCbInfo.pfLogInfo = &ScepLogOutput2;
//
// call the SceSvcAttachmentConfig/Analyze from the DLL
//
__try {
SceErr = (*pfTemp)((PSCESVC_CALLBACK_INFO)&sceCbInfo);
} __except (EXCEPTION_EXECUTE_HANDLER) { SceErr = SCESTATUS_SERVICE_NOT_SUPPORT; }
} else { //
// this API is not supported
//
SceErr = SCESTATUS_SERVICE_NOT_SUPPORT; }
//
// try to free the library handle. If it fails, just leave it
// to to the process to terminate
//
FreeLibrary(hDll);
} else SceErr = SCESTATUS_SERVICE_NOT_SUPPORT;
if ( SceErr == SCESTATUS_SERVICE_NOT_SUPPORT ) { if ( bConfigure ) ScepLogOutput3(1, ScepSceStatusToDosError(SceErr), SCEDLL_SCP_NOT_SUPPORT); else ScepLogOutput3(1, ScepSceStatusToDosError(SceErr), SCEDLL_SAP_NOT_SUPPORT); SceErr = SCESTATUS_SUCCESS;
} else if ( SceErr != SCESTATUS_SUCCESS && SceErr != SCESTATUS_RECORD_NOT_FOUND ) { ScepLogOutput3(1, ScepSceStatusToDosError(SceErr), SCEDLL_ERROR_LOAD, pNode->ServiceName); }
if ( SceErr != SCESTATUS_SUCCESS && SceErr != SCESTATUS_SERVICE_NOT_SUPPORT && SceErr != SCESTATUS_RECORD_NOT_FOUND ) break; } //
// free the buffer
//
SceFreePSCE_SERVICES(pSvcEngineList);
} else if ( SceErr != SCESTATUS_SUCCESS && SceErr != SCESTATUS_PROFILE_NOT_FOUND && SceErr != SCESTATUS_RECORD_NOT_FOUND ) { ScepLogOutput3(1, ScepSceStatusToDosError(SceErr), SCEDLL_SAP_ERROR_ENUMERATE, L"services"); }
if ( SceErr == SCESTATUS_PROFILE_NOT_FOUND || SceErr == SCESTATUS_RECORD_NOT_FOUND || SceErr == SCESTATUS_SERVICE_NOT_SUPPORT ) { //
// no service engine defined
//
SceErr = SCESTATUS_SUCCESS;
}
if ( nServices < nMaxTicks ) {
ScepPostProgress(nMaxTicks-nServices, Area, NULL); }
return(SceErr); }
SCESTATUS ScepEnumServiceEngines( OUT PSCE_SERVICES *pSvcEngineList, IN SCE_ATTACHMENT_TYPE aType ) /*
Routine Description:
Query all services which has a service engine for security manager The service engine information is in the registry:
MACHINE\Software\Microsoft\Windows NT\CurrentVersion\SeCEdit
Arguments:
pSvcEngineList - the service engine list
aType - attachment type (service or policy)
Return Value:
SCE status */ { if ( pSvcEngineList == NULL ) { return(SCESTATUS_INVALID_PARAMETER); }
DWORD Win32Rc; HKEY hKey=NULL;
switch ( aType ) { case SCE_ATTACHMENT_SERVICE: Win32Rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE, SCE_ROOT_SERVICE_PATH, 0, KEY_READ, &hKey ); break; case SCE_ATTACHMENT_POLICY:
Win32Rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE, SCE_ROOT_POLICY_PATH, 0, KEY_READ, &hKey ); break; default: return SCESTATUS_INVALID_PARAMETER; }
if ( Win32Rc == ERROR_SUCCESS ) {
TCHAR Buffer[MAX_PATH]; DWORD BufSize; DWORD index = 0; DWORD EnumRc; FILETIME LastWriteTime; PWSTR BufTmp=NULL; PWSTR EngineName=NULL; DWORD RegType;
//
// enumerate all subkeys of the key
//
do { memset(Buffer, '\0', MAX_PATH*sizeof(WCHAR)); BufSize = MAX_PATH;
EnumRc = RegEnumKeyEx( hKey, index, Buffer, &BufSize, NULL, NULL, NULL, &LastWriteTime);
if ( EnumRc == ERROR_SUCCESS ) { index++; //
// get the service name, query service engine name
//
BufSize += wcslen(SCE_ROOT_SERVICE_PATH) + 1; //62;
BufTmp = (PWSTR)ScepAlloc( 0, (BufSize+1)*sizeof(WCHAR)); if ( BufTmp != NULL ) {
switch ( aType ) { case SCE_ATTACHMENT_SERVICE:
swprintf(BufTmp, L"%s\\%s", SCE_ROOT_SERVICE_PATH, Buffer);
Win32Rc = ScepRegQueryValue( HKEY_LOCAL_MACHINE, BufTmp, L"ServiceAttachmentPath", (PVOID *)&EngineName, &RegType, NULL ); break;
case SCE_ATTACHMENT_POLICY: // policies
swprintf(BufTmp, L"%s\\%s", SCE_ROOT_POLICY_PATH, Buffer);
Win32Rc = ScepRegQueryValue( HKEY_LOCAL_MACHINE, BufTmp, L"PolicyAttachmentPath", (PVOID *)&EngineName, &RegType, NULL ); break; }
if ( Win32Rc == ERROR_SUCCESS ) { //
// get the service engine name and service name
// add them to the service node
//
Win32Rc = ScepAddOneServiceToList( Buffer, // service name
NULL, 0, (PVOID)EngineName, 0, FALSE, pSvcEngineList ); //
// free the buffer if it's not added to the list
//
if ( Win32Rc != ERROR_SUCCESS && EngineName ) { ScepFree(EngineName); } EngineName = NULL;
} else if ( Win32Rc == ERROR_FILE_NOT_FOUND ) { //
// if no service engine name, ignore this service
//
Win32Rc = ERROR_SUCCESS; }
ScepFree(BufTmp); BufTmp = NULL;
} else { Win32Rc = ERROR_NOT_ENOUGH_MEMORY; }
if ( Win32Rc != ERROR_SUCCESS ) { break; } }
} while ( EnumRc != ERROR_NO_MORE_ITEMS );
RegCloseKey(hKey);
//
// remember the error code from enumeration
//
if ( EnumRc != ERROR_SUCCESS && EnumRc != ERROR_NO_MORE_ITEMS ) { if ( Win32Rc == ERROR_SUCCESS ) Win32Rc = EnumRc; }
}
if ( Win32Rc != NO_ERROR && *pSvcEngineList != NULL ) { //
// free memory allocated for the list
//
SceFreePSCE_SERVICES(*pSvcEngineList); *pSvcEngineList = NULL; }
return( ScepDosErrorToSceStatus(Win32Rc) );
}
|