|
|
#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
}
|