windows-nt/Source/XPSP1/NT/net/config/netcfg/engine/util.cpp
2020-09-26 16:20:57 +08:00

628 lines
15 KiB
C++

#include <pch.h>
#pragma hdrstop
#include "comp.h"
#include "nccom.h"
#include "ncperms.h"
#include "ncreg.h"
#include "ncsetup.h"
#include "util.h"
VOID
CreateInstanceKeyPath (
NETCLASS Class,
const GUID& InstanceGuid,
PWSTR pszPath)
{
PCWSTR pszNetworkSubtreePath;
Assert (pszPath);
pszNetworkSubtreePath = MAP_NETCLASS_TO_NETWORK_SUBTREE[Class];
AssertSz (pszNetworkSubtreePath,
"This class does not use the network subtree.");
wcscpy (pszPath, pszNetworkSubtreePath);
wcscat (pszPath, L"\\");
INT cch = StringFromGUID2 (
InstanceGuid,
pszPath + wcslen(pszPath),
c_cchGuidWithTerm);
Assert (c_cchGuidWithTerm == cch);
}
HRESULT
HrOpenDeviceInfo (
IN NETCLASS Class,
IN PCWSTR pszPnpId,
OUT HDEVINFO* phdiOut,
OUT SP_DEVINFO_DATA* pdeidOut)
{
HRESULT hr;
Assert (FIsEnumerated(Class));
Assert (pszPnpId && *pszPnpId);
Assert (phdiOut);
Assert (pdeidOut);
hr = HrSetupDiCreateDeviceInfoList (
NULL,
NULL,
phdiOut);
if (S_OK == hr)
{
hr = HrSetupDiOpenDeviceInfo (
*phdiOut,
pszPnpId,
NULL,
0,
pdeidOut);
// On failure, cleanup the hdevinfo.
//
if (S_OK != hr)
{
SetupDiDestroyDeviceInfoList (*phdiOut);
*phdiOut = NULL;
}
}
TraceHr (ttidError, FAL, hr, SPAPI_E_NO_SUCH_DEVINST == hr,
"HrOpenDeviceInfo (%S)", pszPnpId);
return hr;
}
HRESULT
HrOpenComponentInstanceKey (
IN NETCLASS Class,
IN const GUID& InstanceGuid, OPTIONAL
IN PCWSTR pszPnpId, OPTIONAL
IN REGSAM samDesired,
OUT HKEY* phkey,
OUT HDEVINFO* phdiOut OPTIONAL,
OUT SP_DEVINFO_DATA* pdeidOut OPTIONAL)
{
HRESULT hr;
WCHAR szInstanceKeyPath [_MAX_PATH];
Assert (FIsValidNetClass(Class));
Assert (FImplies(FIsConsideredNetClass(Class), pszPnpId && *pszPnpId));
Assert (phkey);
Assert ((phdiOut && pdeidOut) || (!phdiOut && !pdeidOut));
*phkey = NULL;
if (phdiOut)
{
*phdiOut = NULL;
}
// Non-enumerated components have there instance key under the Network
// tree.
//
if (!FIsEnumerated (Class))
{
CreateInstanceKeyPath(Class, InstanceGuid, szInstanceKeyPath);
hr = HrRegOpenKeyEx (
HKEY_LOCAL_MACHINE,
szInstanceKeyPath,
samDesired,
phkey);
TraceHr (ttidError, FAL, hr, FALSE, "HrOpenInstanceKey (%S)",
szInstanceKeyPath);
}
// For enumerated components, we get the instance key from PnP.
//
else
{
Assert (pszPnpId);
HDEVINFO hdi;
SP_DEVINFO_DATA deid;
SP_DEVINFO_DATA* pdeid;
pdeid = (pdeidOut) ? pdeidOut : &deid;
hr = HrOpenDeviceInfo (Class, pszPnpId, &hdi, pdeid);
if (S_OK == hr)
{
hr = HrSetupDiOpenDevRegKey (
hdi,
pdeid,
DICS_FLAG_GLOBAL,
0,
DIREG_DRV,
samDesired,
phkey);
if (S_OK == hr)
{
if (phdiOut)
{
*phdiOut = hdi;
}
}
// On error, or if the caller doesn't want the HDEVINFO, free it.
//
if (!phdiOut || (S_OK != hr))
{
SetupDiDestroyDeviceInfoList (hdi);
}
}
else if ((SPAPI_E_NO_SUCH_DEVINST == hr) && (KEY_READ == samDesired))
{
// The instance key may not exist for the case when the
// class installer is called to remove an enumerated
// component and then notifies us to remove its bindings.
// For this case, the class installer has created a
// temporary key under the Network subtree that we can use
// to read a limited set of the data (namely LowerRange and
// UpperRange) we'll need to finish off the removal.
//
// We only do this for KEY_READ since there is no point in
// allowing anyone else to write to this key. This prevents
// HrCreateLinkageKey in particular from trying to write
// to this key.
//
wcscpy (szInstanceKeyPath,
c_szTempNetcfgStorageForUninstalledEnumeratedComponent);
INT cch = StringFromGUID2 (
InstanceGuid,
szInstanceKeyPath + wcslen(szInstanceKeyPath),
c_cchGuidWithTerm);
Assert (c_cchGuidWithTerm == cch);
hr = HrRegOpenKeyEx (
HKEY_LOCAL_MACHINE,
szInstanceKeyPath,
KEY_READ,
phkey);
if (S_OK != hr)
{
hr = SPAPI_E_NO_SUCH_DEVINST;
}
}
TraceHr (ttidError, FAL, hr,
(SPAPI_E_NO_SUCH_DEVINST == hr),
"HrOpenInstanceKey (%S)", pszPnpId);
}
return hr;
}
HRESULT
HrOpenNetworkKey (
IN REGSAM samDesired,
OUT HKEY* phkey)
{
HRESULT hr;
hr = HrRegOpenKeyEx (
HKEY_LOCAL_MACHINE,
L"System\\CurrentControlSet\\Control\\Network",
samDesired,
phkey);
TraceHr (ttidError, FAL, hr, FALSE, "HrOpenNetworkKey");
return hr;
}
HRESULT
HrRegCreateKeyWithWorldAccess (
HKEY hkey,
PCWSTR pszSubkey,
DWORD dwOptions,
REGSAM samDesired,
PHKEY phkey,
LPDWORD pdwDisposition)
{
HRESULT hr;
SECURITY_ATTRIBUTES sa = {0};
PSECURITY_DESCRIPTOR pSd;
// Create the correct descriptor. If this fails, we'll still
// create the key, it's just that if a service running as
// localsystem is creating this key, and a user process tries
// to open it, it will fail.
//
hr = HrAllocateSecurityDescriptorAllowAccessToWorld (&pSd);
if (S_OK == hr)
{
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = pSd;
sa.bInheritHandle = FALSE;
}
else
{
Assert (!pSd);
TraceHr (ttidError, FAL, hr, FALSE,
"HrAllocateSecurityDescriptorAllowAccessToWorld "
"failed in HrRegCreateKeyWithWorldAccess");
}
hr = HrRegCreateKeyEx (
hkey,
pszSubkey,
dwOptions,
samDesired,
(pSd) ? &sa : NULL,
phkey,
pdwDisposition);
MemFree (pSd);
TraceHr (ttidError, FAL, hr, FALSE, "HrRegCreateKeyWithWorldAccess");
return hr;
}
PWSTR
GetNextStringToken (
IN OUT PWSTR pszString,
IN PCWSTR pszDelims,
OUT PWSTR* ppszNextToken)
{
const WCHAR* pchDelim;
PWSTR pszToken;
Assert (pszDelims);
Assert (ppszNextToken);
// If pszString is NULL, continue with the previous string.
//
if (!pszString)
{
pszString = *ppszNextToken;
Assert (pszString);
}
// Find the beginning of the token by skipping over the leading
// delimiters. Note that there is no token if and only if this loop
// sets pszString to point to the terminating NULL.
//
while (*pszString)
{
pchDelim = pszDelims;
while (*pchDelim && (*pchDelim != *pszString))
{
pchDelim++;
}
if (!*pchDelim)
{
// Current string character is not a delimiter, so it must
// be part of the token. Break the loop and go find the
// whole token.
//
break;
}
pszString++;
}
pszToken = pszString;
// Find the end of the token. If it is not the end of the string,
// put a NULL there.
//
while (*pszString)
{
pchDelim = pszDelims;
while (*pchDelim && (*pchDelim != *pszString))
{
pchDelim++;
}
if (*pchDelim)
{
// Found a delimiter so this ends the token. Advance
// pszString so that we'll set *ppszNextToken for next time.
//
*pszString = 0;
pszString++;
break;
}
pszString++;
}
// Remember where we left off for the next token.
//
*ppszNextToken = pszString;
// Return the token if we found it.
//
if (pszToken == pszString)
{
return NULL;
}
else
{
return pszToken;
}
}
#define GetNextCommaSeparatedToken(pStart, pEnd, cch) \
pStart = pEnd; \
while (*pStart && (*pStart == L' ' || *pStart == L',')) \
{ \
pStart++; \
} \
\
pEnd = pStart; \
while (*pEnd && *pEnd != L' ' && *pEnd != L',') \
{ \
pEnd++; \
} \
\
cch = pEnd - pStart;
BOOL
FSubstringMatch (
PCTSTR pStr1,
PCTSTR pStr2,
const WCHAR** ppStart,
ULONG* pcch)
{
const WCHAR* p1Start;
const WCHAR* p1End;
const WCHAR* p2Start;
const WCHAR* p2End;
ULONG cch1;
ULONG cch2;
if (ppStart)
{
*ppStart = NULL;
}
if (pcch)
{
*pcch = NULL;
}
p1End = pStr1;
while (1)
{
GetNextCommaSeparatedToken(p1Start, p1End, cch1);
if (!cch1)
{
break;
}
p2End = pStr2;
while (1)
{
GetNextCommaSeparatedToken(p2Start, p2End, cch2);
if (!cch2)
{
break;
}
if (cch1 == cch2)
{
if (0 == memcmp(p1Start, p2Start, cch1 * sizeof(WCHAR)))
{
if (ppStart)
{
*ppStart = p1Start;
}
if (pcch)
{
*pcch = cch1;
}
return TRUE;
}
}
}
}
return FALSE;
}
VOID
SignalNetworkProviderLoaded (
VOID)
{
HANDLE Event;
UNICODE_STRING EventName;
OBJECT_ATTRIBUTES EventAttr;
NTSTATUS Status;
RtlInitUnicodeString (
&EventName,
L"\\Security\\NetworkProviderLoad");
InitializeObjectAttributes (
&EventAttr,
&EventName,
OBJ_CASE_INSENSITIVE,
NULL, NULL);
Status = NtOpenEvent (
&Event,
EVENT_QUERY_STATE | EVENT_MODIFY_STATE | SYNCHRONIZE,
&EventAttr);
if (NT_SUCCESS(Status))
{
SetEvent (Event);
CloseHandle (Event);
}
else
{
ULONG Win32Error;
Win32Error = RtlNtStatusToDosError(Status);
SetLastError(Win32Error);
TraceHr (ttidError, FAL, HrFromLastWin32Error(), FALSE,
"SignalNetworkProviderLoaded");
}
}
BOOL
CDynamicBuffer::FGrowBuffer (
ULONG cbGrow)
{
PBYTE pbNew;
// If it hasn't been set, use a default of 4096.
if (!m_cbGranularity)
{
m_cbGranularity = 4096;
}
if (cbGrow % m_cbGranularity)
{
cbGrow = (cbGrow + m_cbGranularity) - (cbGrow % m_cbGranularity);
}
pbNew = (PBYTE)MemAlloc (m_cbAllocated + cbGrow);
if (pbNew)
{
#ifdef ENABLETRACE
if (m_pbBuffer)
{
TraceTag (ttidDefault, "Dynamic buffer grown. New size = %d.",
m_cbAllocated + cbGrow);
}
#endif
CopyMemory (pbNew, m_pbBuffer, m_cbConsumed);
MemFree (m_pbBuffer);
m_pbBuffer = pbNew;
m_cbAllocated += cbGrow;
}
return !!pbNew;
}
HRESULT
CDynamicBuffer::HrReserveBytes (
ULONG cbReserve)
{
if (cbReserve > m_cbAllocated)
{
return (FGrowBuffer(cbReserve)) ? S_OK : E_OUTOFMEMORY;
}
return S_OK;
}
HRESULT
CDynamicBuffer::HrCopyBytes (
const BYTE* pbSrc,
ULONG cbSrc)
{
Assert (pbSrc);
Assert (m_cbAllocated >= m_cbConsumed);
if (cbSrc > m_cbAllocated - m_cbConsumed)
{
if (!FGrowBuffer (cbSrc))
{
return E_OUTOFMEMORY;
}
}
CopyMemory (m_pbBuffer + m_cbConsumed, pbSrc, cbSrc);
m_cbConsumed += cbSrc;
return S_OK;
}
HRESULT
CDynamicBuffer::HrCopyString (
PCWSTR pszSrc)
{
ULONG cbSrc;
cbSrc = CbOfSzAndTermSafe(pszSrc);
return HrCopyBytes ((const BYTE*)pszSrc, cbSrc);
}
BOOL
FIsFilterDevice (HDEVINFO hdi, PSP_DEVINFO_DATA pdeid)
{
WCHAR szFilterInfId[_MAX_PATH];
BOOL fIsFilterDevice = FALSE;
HKEY hkeyInstance;
HRESULT hr;
// Open the device's driver key.
//
hr = HrSetupDiOpenDevRegKey (
hdi, pdeid,
DICS_FLAG_GLOBAL, 0, DIREG_DRV,
KEY_READ, &hkeyInstance);
if (S_OK == hr)
{
// Get the filterinfid value. If present, then
// this device is a filter device.
//
DWORD cbFilterInfId = sizeof(szFilterInfId);
hr = HrRegQuerySzBuffer (
hkeyInstance,
L"FilterInfId",
szFilterInfId,
&cbFilterInfId);
if (S_OK == hr)
{
fIsFilterDevice = TRUE;
}
RegCloseKey (hkeyInstance);
}
return fIsFilterDevice;
}
VOID
AddOrRemoveDontExposeLowerCharacteristicIfNeeded (
IN OUT CComponent* pComponent)
{
ASSERT (pComponent);
// Special case: NCF_DONTEXPOSELOWER
// SPX has erroneously set this characteristic. It's not really
// needed as nothing binds with SPX. Having it set means that
// two components above IPX have this characteristic set. (NWNB
// is the other. The code to generate bindpaths by recursing
// the stack table is only setup to handle at most one component
// with this characteristic per pass. Turning it off for SPX
// solves this in the simplest way.
//
// Furthermore, enforce that only IPX and NWNB have this
// characteristic set..
//
//
if ((0 == wcscmp(L"ms_nwnb", pComponent->m_pszInfId)) ||
(0 == wcscmp(L"ms_nwipx", pComponent->m_pszInfId)))
{
pComponent->m_dwCharacter |= NCF_DONTEXPOSELOWER;
}
else
{
pComponent->m_dwCharacter &= ~NCF_DONTEXPOSELOWER;
}
// End Special case
}