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.
 
 
 
 
 
 

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);
}
}