|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: E X P O R T S . C P P
//
// Contents: Exported functions from NETCFG.DLL
//
// Notes:
//
// Author: danielwe 5 Dec 1997
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "ncreg.h"
#include "ncsetup.h"
#include "ncsvc.h"
#define REGSTR_PATH_SVCHOST L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Svchost"
HRESULT HrPrepareForSvchostEnum ( IN PCWSTR pszService, IN OUT CServiceManager* pscm, IN OUT CService* psvc, OUT LPQUERY_SERVICE_CONFIG* ppOriginalConfig, OUT HKEY* phkeySvchost, OUT PWSTR* ppszValueNameBuffer, OUT DWORD* pcchValueNameBuffer, OUT PWSTR* ppmszValueBuffer, OUT DWORD* pcbValueBuffer) { // Initialize the output parameters.
//
*ppOriginalConfig = NULL; *phkeySvchost = NULL; *ppszValueNameBuffer = NULL; *pcchValueNameBuffer = 0; *ppmszValueBuffer = NULL; *pcbValueBuffer = 0;
const DWORD dwScmAccess = STANDARD_RIGHTS_REQUIRED | SC_MANAGER_CONNECT | SC_MANAGER_LOCK;
const DWORD dwSvcAccess = STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG;
// Open the service and lock the service database so we can change
// the service's configuration.
//
HRESULT hr = pscm->HrOpenService ( psvc, pszService, WITH_LOCK, dwScmAccess, dwSvcAccess); if (SUCCEEDED(hr)) { // Query the service's current configuration in the event we
// need to revert what we set.
//
LPQUERY_SERVICE_CONFIG pOriginalConfig; hr = psvc->HrQueryServiceConfig (&pOriginalConfig); if (SUCCEEDED(hr)) { // Open the svchost software key and query information
// about it like the length of the longest value name
// and longest value.
//
HKEY hkeySvchost; hr = HrRegOpenKeyEx ( HKEY_LOCAL_MACHINE, REGSTR_PATH_SVCHOST, KEY_READ | KEY_SET_VALUE, &hkeySvchost);
if (SUCCEEDED(hr)) { DWORD cchMaxValueNameLen; DWORD cbMaxValueLen;
LONG lr = RegQueryInfoKeyW (hkeySvchost, NULL, // lpClass
NULL, // lpcbClass
NULL, // lpReserved
NULL, // lpcSubKeys
NULL, // lpcbMaxSubKeyLen
NULL, // lpcbMaxClassLen
NULL, // lpcValues
&cchMaxValueNameLen, &cbMaxValueLen, NULL, // lpcbSecurityDescriptor
NULL // lpftLastWriteTime
); hr = HRESULT_FROM_WIN32 (lr); if (SUCCEEDED(hr)) { // Make sure the name buffer length (in bytes) is a
// multiple of sizeof(WCHAR). This is because we expect
// to use RegEnumValue which accepts and returns buffer
// size in characters. We tell it the the buffer
// capacity (in characters) is count of bytes divided
// by sizeof(WCHAR). So, to avoid any round off
// error (which would not occur in our favor) we make
// sure that the buffer size is a multiple of
// sizeof(WCHAR).
//
INT cbFraction = cbMaxValueLen % sizeof(WCHAR); if (cbFraction) { cbMaxValueLen += sizeof(WCHAR) - cbFraction; }
// Need room for the null terminator as RegQueryInfoKey
// doesn't return it.
//
cchMaxValueNameLen++;
// Allocate buffers for the longest value name and value
// data for our caller to use.
//
PWSTR pszValueNameBuffer = (PWSTR) MemAlloc (cchMaxValueNameLen * sizeof(WCHAR));
PWSTR pmszValueBuffer = (PWSTR) MemAlloc (cbMaxValueLen);
if ((pszValueNameBuffer != NULL) && (pmszValueBuffer != NULL)) { *ppOriginalConfig = pOriginalConfig; *phkeySvchost = hkeySvchost;
*ppszValueNameBuffer = pszValueNameBuffer; *pcchValueNameBuffer = cchMaxValueNameLen;
*ppmszValueBuffer = pmszValueBuffer; *pcbValueBuffer = cbMaxValueLen;
hr = S_OK; } else { hr = E_OUTOFMEMORY; } }
if (FAILED(hr)) { RegCloseKey (hkeySvchost); } }
if (FAILED(hr)) { MemFree (pOriginalConfig); } } } TraceError ("HrPrepareForSvchostEnum", hr); return hr; }
STDAPI SvchostChangeSvchostGroup ( PCWSTR pszService, PCWSTR pszNewGroup ) { Assert (pszService); Assert (pszNewGroup);
static const WCHAR c_pszBasePath [] = L"%SystemRoot%\\System32\\svchost.exe -k ";
// Validate the new group name by making sure it doesn't exceed
// MAX_PATH when combined with the base path.
//
if (!pszService || !pszNewGroup || !*pszService || !*pszNewGroup || (lstrlenW (c_pszBasePath) + lstrlenW (pszNewGroup) > MAX_PATH)) { return E_INVALIDARG; }
// Form the new image path based on the base path and the new group
// name.
//
WCHAR pszImagePath [MAX_PATH + 1]; lstrcpyW (pszImagePath, c_pszBasePath); lstrcatW (pszImagePath, pszNewGroup);
// Need to change the ImagePath of the service as well as the
// Svchost Group values. The implementation tries to ensure that
// both of these changes are made or neither of them are made.
//
// Prepare for the enumeration by setting up a few pieces of information
// first. HrPrepareForSvchostEnum sets up all of these variables.
//
// SCM is opened and locked, pszService is opened for config change.
//
CServiceManager scm; CService svc;
// pszService's current configration is obtained in the event we
// need to rollback, we'll use this info to reset the ImagePath.
//
LPQUERY_SERVICE_CONFIG pOriginalConfig;
// hkeySvcHost is opened at REGSTR_PATH_SVCHOST and is used to
// enumerate the values under it.
//
HKEY hkeySvcHost;
// These buffers are allocated so that RegEnumValue will have a place
// to store what was enumerated.
//
PWSTR pszValueNameBuffer; DWORD cchValueNameBuffer; PWSTR pmszValueBuffer; DWORD cbValueBuffer;
HRESULT hr = HrPrepareForSvchostEnum ( pszService, &scm, &svc, &pOriginalConfig, &hkeySvcHost, &pszValueNameBuffer, &cchValueNameBuffer, &pmszValueBuffer, &cbValueBuffer); if (SUCCEEDED(hr)) { // Set the new image path of the service.
//
hr = svc.HrSetImagePath (pszImagePath); if (SUCCEEDED(hr)) { // fAddNewValue will be set to FALSE if we've found an existing
// group name value.
//
BOOL fAddNewValue = TRUE; BOOL fChanged;
// Now perform the enumeration. For each value enumerated,
// make sure the service name is included in the multi-sz
// for the valuename that matches the new group name. For all
// other values, make sure the service name is not included
// in the multi-sz.
//
DWORD dwIndex = 0; do { DWORD dwType; DWORD cchValueName = cchValueNameBuffer; DWORD cbValue = cbValueBuffer;
hr = HrRegEnumValue (hkeySvcHost, dwIndex, pszValueNameBuffer, &cchValueName, &dwType, (LPBYTE)pmszValueBuffer, &cbValue);
if (SUCCEEDED(hr) && (REG_MULTI_SZ == dwType)) { // If we find a value that matches the group name,
// make sure the service is a part of the mutli-sz
// value.
//
if (0 == lstrcmpiW (pszNewGroup, pszValueNameBuffer)) { // Since we found an existing group name, we don't
// need to add a new one.
//
fAddNewValue = FALSE;
PWSTR pmszNewValue;
hr = HrAddSzToMultiSz (pszService, pmszValueBuffer, STRING_FLAG_DONT_MODIFY_IF_PRESENT | STRING_FLAG_ENSURE_AT_END, 0, &pmszNewValue, &fChanged);
if (SUCCEEDED(hr) && fChanged) { hr = HrRegSetMultiSz (hkeySvcHost, pszNewGroup, pmszNewValue);
MemFree (pmszNewValue); } }
// Otherwise, since the value does not match the group
// name, make sure the service is NOT part of the
// mutli-sz value.
//
else { RemoveSzFromMultiSz (pszService, pmszValueBuffer, STRING_FLAG_REMOVE_ALL, &fChanged);
if (fChanged) { hr = HrRegSetMultiSz (hkeySvcHost, pszValueNameBuffer, pmszValueBuffer); } } } else if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr) { hr = S_OK; break; }
dwIndex++; } while (S_OK == hr);
// If we need to add a new group name, do so.
//
if (SUCCEEDED(hr) && fAddNewValue) { // Add pszService to a empty multi-sz. This has the effect
// of creating a multi-sz from a single string.
//
PWSTR pmszNewValue;
hr = HrAddSzToMultiSz (pszService, NULL, STRING_FLAG_ENSURE_AT_END, 0, &pmszNewValue, &fChanged); if (S_OK == hr) { // We know that it should have been added, so assert
// that the multi-sz "changed".
//
Assert (fChanged);
// Add the new value by setting the multi-sz in the
// registry.
//
hr = HrRegSetMultiSz (hkeySvcHost, pszNewGroup, pmszNewValue);
MemFree (pmszNewValue); } } }
RegCloseKey (hkeySvcHost);
MemFree (pmszValueBuffer); MemFree (pszValueNameBuffer); MemFree (pOriginalConfig); } TraceError ("SvchostChangeSvchostGroup", hr); return hr; }
|