Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1879 lines
58 KiB

/*++
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) );
}