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.
699 lines
17 KiB
699 lines
17 KiB
// 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);
|
|
}
|
|
}
|
|
|
|
|
|
|