|
|
// SCEAgent.cpp : Implementation of CSCEAgent
#include "stdafx.h"
#include "SSRTE.h"
#include "SCEAgent.h"
#include "ntsecapi.h"
#include "secedit.h"
/////////////////////////////////////////////////////////////////////////////
// CSCEAgent
static LPCWSTR g_pwszTempDBName = L"5ac90887-f869-4cb6-ae96-892e939a90ad.sdb";
void CSCEAgent::Cleanup()
/*++
Routine Description:
Name:
CSCEAgent::Cleanup
Functionality: Private helper to reduce duplicate code. Cleanup any resources that we might hold on.
Virtual: None. Arguments:
None
Return Value:
None.
Notes:
--*/
{ if (m_headServiceList != NULL) { PSERVICE_NODE tempNode = m_headServiceList; PSERVICE_NODE tempNodeNext = NULL;
do { tempNodeNext = tempNode->Next;
if (tempNode->Name) { LocalFree(tempNode->Name); }
LocalFree(tempNode); tempNode = tempNodeNext;
} while ( tempNode != NULL );
m_headServiceList = NULL; } }
STDMETHODIMP CSCEAgent::Configure ( IN BSTR bstrTemplate, IN LONG lAreaMask, IN BSTR OPTIONAL bstrLogFile )
/*++
Routine Description:
Name:
CSCEAgent::Configure
Functionality: this is to expose the SCE's configure capability to scripting
Virtual: Yes. Arguments:
bstrTemplate - The template path the configure is based on.
lAreaMask - The areas this configure will be run.
bstrLogFile - The log file path
Return Value:
None.
Notes:
1. We should really be passing in AREA_ALL for the area mask parameter But that requires the caller to use a DWORD flag 65535 in script, which is odd. So, we opt to ignore the mask at this point. Meaning we will always use AREA_ALL.
--*/
{
if (bstrTemplate == NULL) { return E_INVALIDARG; }
//
// process options
//
DWORD dwOption = SCE_OVERWRITE_DB;
if (bstrLogFile == NULL || *bstrLogFile == L'\0') { dwOption |= SCE_DISABLE_LOG; } else { dwOption |= SCE_VERBOSE_LOG; }
//
// According to Vishnu, SCE will configure an INF file.
//
CComBSTR bstrTempDBFile(bstrTemplate);
bstrTempDBFile += g_pwszTempDBName;
if (bstrTempDBFile.m_str != NULL) { SCESTATUS rc = ::SceConfigureSystem( NULL, bstrTemplate, bstrTempDBFile, bstrLogFile, dwOption, lAreaMask, NULL, NULL, NULL );
::DeleteFile(bstrTempDBFile);
//
// we can opt to not to delete the database, but leaving it there will
// create confusions
//
return SceStatusToHRESULT(rc); } else { return E_OUTOFMEMORY; } }
STDMETHODIMP CSCEAgent::CreateRollbackTemplate ( IN BSTR bstrTemplatePath, IN BSTR bstrRollbackPath, IN BSTR bstrLogFilePath )
/*++
Routine Description:
Name:
CSCEAgent::CreateRollbackTemplate
Functionality: this is to expose the SCE's rollback tempalte creation capability to scripting
Virtual: Yes. Arguments:
bstrTemplatePath - The template path this rollback will be based on.
bstrRollbackPath - The rollback template that will be created
bstrLogFilePath - The logfile path
Return Value:
None.
Notes:
1. I believe this log file path can be optional. Need to check with JinHuang
--*/
{ if (bstrTemplatePath == NULL || bstrRollbackPath == NULL) { return E_INVALIDARG; }
DWORD dwWarning = 0; SCESTATUS rc = ::SceGenerateRollback( NULL, bstrTemplatePath, bstrRollbackPath, bstrLogFilePath, SCE_VERBOSE_LOG, AREA_ALL, &dwWarning );
//
// $undone:shawnwu, how should I use the dwWarning?
//
return SceStatusToHRESULT(rc);
}
//
// UpdateServiceList is authored by VishnuP. Please send comments or
// questions to him.
//
STDMETHODIMP CSCEAgent::UpdateServiceList ( IN BSTR bstrServiceName, IN BSTR bstrStartupType ) { if (bstrServiceName == NULL || bstrStartupType == NULL ) { return E_INVALIDARG; }
DWORD dwStartupType;
if (0 == _wcsicmp(bstrStartupType, L"automatic")) { dwStartupType = 2; } else if (0 == _wcsicmp(bstrStartupType, L"manual")) { dwStartupType = 3; } else if (0 == _wcsicmp(bstrStartupType, L"disabled")) { dwStartupType = 4; } else { return E_INVALIDARG; }
PSERVICE_NODE NewNode = NULL;
NewNode = (PSERVICE_NODE)LocalAlloc(LMEM_ZEROINIT, sizeof(SERVICE_NODE) ); if (NewNode == NULL) { return E_OUTOFMEMORY; } int iSvcNameLen = wcslen(bstrServiceName) + 1; NewNode->Name = (PWSTR)LocalAlloc( LMEM_ZEROINIT, iSvcNameLen * sizeof(WCHAR) ); if (NewNode->Name == NULL) { LocalFree(NewNode); return E_OUTOFMEMORY; }
wcsncpy(NewNode->Name, bstrServiceName, iSvcNameLen);
NewNode->dwStartupType = dwStartupType; NewNode->Next = m_headServiceList; m_headServiceList = NewNode;
return S_OK;
}
//
// CreateServicesCfgRbkTemplates is authored by VishnuP. Please send comments or
// questions to him.
//
STDMETHODIMP CSCEAgent::CreateServicesCfgRbkTemplates ( IN BSTR bstrTemplatePath, IN BSTR bstrRollbackPath, IN BSTR bstrLogFilePath ) { UNREFERENCED_PARAMETER(bstrLogFilePath);
if (bstrTemplatePath == NULL || bstrRollbackPath == NULL) { return E_INVALIDARG; }
DWORD dwNumServices = 0; SC_HANDLE hScm = NULL; DWORD rc = ERROR_SUCCESS; LPENUM_SERVICE_STATUS_PROCESS pInfo = NULL; DWORD *aSCMListStartupTypes = NULL; DWORD *aSCMListStartupTypesCfg = NULL; SCESVC_CONFIGURATION_INFO ServiceInfo; ServiceInfo.Count = dwNumServices; ServiceInfo.Lines = NULL;
//
// Connect to the service controller.
//
hScm = OpenSCManager( NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE); if (hScm == NULL) {
rc = GetLastError(); goto CleanUp; }
DWORD cbInfo = 0;
DWORD dwResume = 0;
if ((!EnumServicesStatusEx( hScm, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, &cbInfo, &dwNumServices, &dwResume, NULL)) && ERROR_MORE_DATA == GetLastError()) {
pInfo = (LPENUM_SERVICE_STATUS_PROCESS)LocalAlloc(LMEM_ZEROINIT, cbInfo);
if (pInfo == NULL) { rc = ERROR_NOT_ENOUGH_MEMORY; goto CleanUp; }
}
else { rc = GetLastError(); goto CleanUp; }
if (!EnumServicesStatusEx( hScm, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, (LPBYTE)pInfo, cbInfo, &cbInfo, &dwNumServices, &dwResume, NULL)) {
rc = GetLastError();
goto CleanUp; }
//
// get the startup type for each service
//
aSCMListStartupTypes = (DWORD *) LocalAlloc ( LMEM_ZEROINIT, sizeof(DWORD) * dwNumServices ); if (aSCMListStartupTypes == NULL) { rc = ERROR_NOT_ENOUGH_MEMORY; goto CleanUp; }
aSCMListStartupTypesCfg = (DWORD *) LocalAlloc ( LMEM_ZEROINIT, sizeof(DWORD) * dwNumServices ); if (aSCMListStartupTypes == NULL) { rc = ERROR_NOT_ENOUGH_MEMORY; goto CleanUp; }
for (DWORD ServiceIndex=0; ServiceIndex < dwNumServices; ServiceIndex++ ) {
SC_HANDLE hService = NULL; DWORD BytesNeeded = 0; LPQUERY_SERVICE_CONFIG pConfig = NULL; hService = OpenService( hScm, pInfo[ServiceIndex].lpServiceName, SERVICE_QUERY_CONFIG); if (hService == NULL) { rc = GetLastError(); goto CleanUp; }
if ( !QueryServiceConfig( hService, NULL, 0, &BytesNeeded ) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) { rc = GetLastError(); if (hService) { CloseServiceHandle(hService); hService = NULL; } goto CleanUp; }
pConfig = (LPQUERY_SERVICE_CONFIG)LocalAlloc(LMEM_ZEROINIT, BytesNeeded); if ( pConfig == NULL ) {
rc = ERROR_NOT_ENOUGH_MEMORY; if (hService) { CloseServiceHandle(hService); hService = NULL; } goto CleanUp; } //
// the real query of config
//
if ( !QueryServiceConfig( hService, pConfig, BytesNeeded, &BytesNeeded ) ) { rc = GetLastError(); if (hService) { CloseServiceHandle(hService); hService = NULL; }
if (pConfig) { LocalFree(pConfig); pConfig = NULL; } goto CleanUp; }
aSCMListStartupTypes[ServiceIndex] = (BYTE)(pConfig->dwStartType);
if (hService) { CloseServiceHandle(hService); hService = NULL; }
if (pConfig) { LocalFree(pConfig); pConfig = NULL; } }
//
// configure all startup types for manual and automatic and the rest as disabled
//
//
// first generate the rollback (basically a system snapshot - could be optimized)
//
//
// Prepare SCE structure for generating a configuration template
//
WCHAR ppSceTemplateTypeFormat[10][10] = { L"2,\"\"", L"3,\"\"", L"4,\"\"" };
DWORD dwAllocSize = sizeof(SCESVC_CONFIGURATION_LINE) * dwNumServices; ServiceInfo.Lines = (PSCESVC_CONFIGURATION_LINE) LocalAlloc( LMEM_ZEROINIT, dwAllocSize ); if (ServiceInfo.Lines == NULL) { rc = ERROR_NOT_ENOUGH_MEMORY; goto CleanUp; }
for (DWORD ServiceIndex=0; ServiceIndex < dwNumServices; ServiceIndex++ ) { ServiceInfo.Lines[ServiceIndex].Key = pInfo[ServiceIndex].lpServiceName; ServiceInfo.Lines[ServiceIndex].Value = ppSceTemplateTypeFormat[aSCMListStartupTypes[ServiceIndex] - 2]; ServiceInfo.Lines[ServiceIndex].ValueLen = sizeof(ppSceTemplateTypeFormat[aSCMListStartupTypes[ServiceIndex] - 2]); }
rc = ::SceSvcSetInformationTemplate( bstrRollbackPath, szServiceGeneral, TRUE, &ServiceInfo ); BOOL bFoundService;
for (DWORD ServiceIndex=0; ServiceIndex < dwNumServices; ServiceIndex++ ) { bFoundService = FALSE; for (PSERVICE_NODE tempNode = m_headServiceList; tempNode != NULL; tempNode = tempNode->Next ) { if (_wcsicmp (tempNode->Name, pInfo[ServiceIndex].lpServiceName) == 0) { aSCMListStartupTypesCfg[ServiceIndex] = tempNode->dwStartupType; bFoundService = TRUE; } } if (bFoundService == FALSE) { //
// stop services that are not found
//
aSCMListStartupTypesCfg[ServiceIndex] = 4; } }
for (DWORD ServiceIndex=0; ServiceIndex < dwNumServices; ServiceIndex++ ) { ServiceInfo.Lines[ServiceIndex].Value = ppSceTemplateTypeFormat[aSCMListStartupTypesCfg[ServiceIndex] - 2]; ServiceInfo.Lines[ServiceIndex].ValueLen = sizeof(ppSceTemplateTypeFormat[aSCMListStartupTypesCfg[ServiceIndex] - 2]); }
rc = ::SceSvcSetInformationTemplate( bstrTemplatePath, szServiceGeneral, TRUE, &ServiceInfo );
CleanUp: if (hScm) CloseServiceHandle(hScm);
if (pInfo) LocalFree(pInfo);
if (aSCMListStartupTypes) LocalFree (aSCMListStartupTypes); if (aSCMListStartupTypesCfg) LocalFree (aSCMListStartupTypesCfg); if (ServiceInfo.Lines) LocalFree(ServiceInfo.Lines);
//
// after we create the templates, we will clean them up
//
Cleanup();
return rc;
}
HRESULT SceStatusToHRESULT ( IN SCESTATUS SceStatus )
/*++
Routine Description:
Name:
SceStatusToHRESULT
Functionality: converts SCESTATUS error code to dos error defined in winerror.h
Virtual: N/A. Arguments:
none.
Return Value:
HRESULT.
Notes:
--*/
{ switch(SceStatus) {
case SCESTATUS_SUCCESS: return HRESULT_FROM_WIN32(NO_ERROR);
case SCESTATUS_OTHER_ERROR: return HRESULT_FROM_WIN32(ERROR_EXTENDED_ERROR);
case SCESTATUS_INVALID_PARAMETER: return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
case SCESTATUS_RECORD_NOT_FOUND: return HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
case SCESTATUS_NO_MAPPING: return HRESULT_FROM_WIN32(ERROR_NONE_MAPPED);
case SCESTATUS_TRUST_FAIL: return HRESULT_FROM_WIN32(ERROR_TRUSTED_DOMAIN_FAILURE);
case SCESTATUS_INVALID_DATA: return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
case SCESTATUS_OBJECT_EXIST: return HRESULT_FROM_WIN32(ERROR_FILE_EXISTS);
case SCESTATUS_BUFFER_TOO_SMALL: return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
case SCESTATUS_PROFILE_NOT_FOUND: return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
case SCESTATUS_BAD_FORMAT: return HRESULT_FROM_WIN32(ERROR_BAD_FORMAT);
case SCESTATUS_NOT_ENOUGH_RESOURCE: return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
case SCESTATUS_ACCESS_DENIED: return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
case SCESTATUS_CANT_DELETE: return HRESULT_FROM_WIN32(ERROR_CURRENT_DIRECTORY);
case SCESTATUS_PREFIX_OVERFLOW: return HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
case SCESTATUS_ALREADY_RUNNING: return HRESULT_FROM_WIN32(ERROR_SERVICE_ALREADY_RUNNING); case SCESTATUS_SERVICE_NOT_SUPPORT: return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
case SCESTATUS_MOD_NOT_FOUND: return HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND);
case SCESTATUS_EXCEPTION_IN_SERVER: return HRESULT_FROM_WIN32(ERROR_EXCEPTION_IN_SERVICE);
default: return HRESULT_FROM_WIN32(ERROR_EXTENDED_ERROR); } }
|