windows-nt/Source/XPSP1/NT/net/config/netcfg/dll/exports.cpp

370 lines
13 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------------
//
// 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;
}