windows-nt/Source/XPSP1/NT/net/config/netman/conman/gpnla.cpp
2020-09-26 16:20:57 +08:00

1157 lines
39 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 2001.
//
// File: G P N L A . C P P
//
// Contents: Class for Handling NLA Changes that affect Group Policies
//
// Notes:
//
// Author: sjkhan 20 Feb 2001
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "trace.h"
#include "gpnla.h"
#include <winsock2.h>
#include <mswsock.h>
#include "nmbase.h"
#include <userenv.h>
#include <userenvp.h>
#include <ncstl.h>
#include <ncstlstr.h>
#include <stlalgor.h>
#include <lancmn.h>
#include <lm.h>
#include <ipnathlp.h>
#include "ncmisc.h"
#include "ipifcons.h"
#include "ncexcept.h"
#include "conman.h"
GUID g_WsMobilityServiceClassGuid = NLA_SERVICE_CLASS_GUID;
extern CGroupPolicyNetworkLocationAwareness* g_pGPNLA;
bool operator == (const GPNLAPAIR& rpair1, const GPNLAPAIR& rpair2)
{
return IsEqualGUID(rpair1.first, rpair2.first) == TRUE;
}
LONG CGroupPolicyNetworkLocationAwareness::m_lBusyWithReconfigure = 0;
CGroupPolicyNetworkLocationAwareness::CGroupPolicyNetworkLocationAwareness()
{
m_fSameNetwork = FALSE;
m_fShutdown = FALSE;
m_lRefCount = 0;
m_fErrorShutdown = FALSE;
m_hGPWait = INVALID_HANDLE_VALUE;
m_hNLAWait = INVALID_HANDLE_VALUE;
m_lBusyWithReconfigure = 0;
}
CGroupPolicyNetworkLocationAwareness::~CGroupPolicyNetworkLocationAwareness()
{
}
//+---------------------------------------------------------------------------
//
// Member: CGroupPolicyNetworkLocationAwareness::Initialize
//
// Purpose: To initialize the different components required for detecting
// changes to the network and creating the different
// synchronization objects required.
// Arguments:
// (none)
//
// Returns: HRESULT indicating SUCCESS or FAILURE
//
// Author: sjkhan 20 Feb 2001
//
// Notes:
//
HRESULT CGroupPolicyNetworkLocationAwareness::Initialize()
{
HRESULT hr;
TraceTag(ttidGPNLA, "Initializing Group Policy Handler");
InitializeCriticalSection(&m_csList);
// Init Winsock
if (ERROR_SUCCESS == WSAStartup(MAKEWORD(2, 2), &m_wsaData))
{
m_hEventNLA = CreateEvent(NULL, FALSE, FALSE, NULL);
if (m_hEventNLA)
{
m_hEventExit = CreateEvent(NULL, FALSE, FALSE, NULL);
if (m_hEventExit)
{
m_hEventGP = CreateEvent(NULL, FALSE, FALSE, NULL);
if (m_hEventGP)
{
hr = RegisterWait();
if (SUCCEEDED(hr))
{
if (RegisterGPNotification(m_hEventGP, TRUE))
{
ZeroMemory(&m_wsaCompletion,sizeof(m_wsaCompletion));
ZeroMemory(&m_wsaOverlapped,sizeof(m_wsaOverlapped));
m_wsaOverlapped.hEvent = m_hEventNLA;
m_wsaCompletion.Type = NSP_NOTIFY_EVENT;
m_wsaCompletion.Parameters.Event.lpOverlapped = &m_wsaOverlapped;
ZeroMemory(&m_wqsRestrictions, sizeof(m_wqsRestrictions));
m_wqsRestrictions.dwSize = sizeof(m_wqsRestrictions);
m_wqsRestrictions.lpServiceClassId = &g_WsMobilityServiceClassGuid;
m_wqsRestrictions.dwNameSpace = NS_NLA;
hr = LookupServiceBegin(LUP_NOCONTAINERS);
if (SUCCEEDED(hr))
{
// Loop through once and get all the data to begin with.
hr = EnumChanges();
}
return hr;
}
else
{
hr = HrFromLastWin32Error();
DeregisterWait();
}
}
CloseHandle(m_hEventGP);
}
else
{
hr = HrFromLastWin32Error();
}
}
else
{
hr = HrFromLastWin32Error();
}
CloseHandle(m_hEventExit);
}
else
{
hr = HrFromLastWin32Error();
}
CloseHandle(m_hEventNLA);
}
else
{
int nError;
nError = WSAGetLastError();
hr = HRESULT_FROM_WIN32(nError);
}
TraceError("CGroupPolicyNetworkLocationAwareness::Initialize failed", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CGroupPolicyNetworkLocationAwareness::Uninitialize
//
// Purpose: This is used to ensure that no threads are currently running
// when they should be stopped. If the refcount is >0 then it
// waits for the last busy thread to terminate and set the event
// marking its termination so that shutdown can proceed.
// Arguments:
// (none)
//
// Returns: HRESULT indicating success/failure.
//
// Author: sjkhan 20 Feb 2001
//
// Notes:
//
HRESULT CGroupPolicyNetworkLocationAwareness::Uninitialize()
{
HRESULT hr = S_OK;
DWORD dwRet = WAIT_OBJECT_0;
int nCount = 0;
TraceTag(ttidGPNLA, "Unitializing Group Policy Handler");
m_fShutdown = TRUE;
Unreference();
// LookupServiceEnd should cause an event to fire which will make us exit (unless NLA was already stopped).
hr = LookupServiceEnd();
if ((0 != m_lRefCount) && SUCCEEDED(hr) && !m_fErrorShutdown)
{
dwRet = WaitForSingleObject(m_hEventExit, 30000L);
}
do
{
hr = DeregisterWait();
if (SUCCEEDED(hr))
{
break;
}
} while ((nCount++ < 3) && FAILED(hr));
TraceError("DeregisterWait returned", hr);
if (SUCCEEDED(hr))
{
CloseHandle(m_hEventExit);
CloseHandle(m_hEventNLA);
DeleteCriticalSection(&m_csList);
WSACleanup();
}
TraceTag(ttidGPNLA, "NLA was uninitialized");
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CGroupPolicyNetworkLocationAwareness::RegisterWait
//
// Purpose: Registers the Wait Object so that we don't require any threads
// of our own.
// Arguments:
// (none)
//
// Returns: HRESULT indicating success/failure.
//
// Author: sjkhan 20 Feb 2001
//
// Notes:
//
HRESULT CGroupPolicyNetworkLocationAwareness::RegisterWait()
{
TraceFileFunc(ttidGPNLA);
HRESULT hr = S_OK;
NTSTATUS Status;
Reference(); // Make sure that we're referenced so that we don't accidentally kill the service while it's still busy.
Status = RtlRegisterWait(&m_hNLAWait, m_hEventNLA, &CGroupPolicyNetworkLocationAwareness::EventHandler, this, INFINITE, WT_EXECUTEINLONGTHREAD);
if (!NT_SUCCESS(Status))
{
m_hNLAWait = INVALID_HANDLE_VALUE;
hr = HRESULT_FROM_NT(Status);
}
else
{
Status = RtlRegisterWait(&m_hGPWait, m_hEventGP, &CGroupPolicyNetworkLocationAwareness::GroupPolicyChange, this, INFINITE, WT_EXECUTEINLONGTHREAD);
if (!NT_SUCCESS(Status))
{
hr = HRESULT_FROM_NT(Status);
RtlDeregisterWaitEx(m_hNLAWait, INVALID_HANDLE_VALUE);
m_hGPWait = INVALID_HANDLE_VALUE;
m_hNLAWait = INVALID_HANDLE_VALUE;
}
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CGroupPolicyNetworkLocationAwareness::DeregisterWait
//
// Purpose: Deregisters the wait so that we can shutdown and not have
// any new threads spawned.
// Arguments:
// (none)
//
// Returns: HRESULT indicating success/failure.
//
// Author: sjkhan 20 Feb 2001
//
// Notes:
//
HRESULT CGroupPolicyNetworkLocationAwareness::DeregisterWait()
{
TraceFileFunc(ttidGPNLA);
HRESULT hr,hr1,hr2 = S_OK;
NTSTATUS Status1, Status2;
if (INVALID_HANDLE_VALUE != m_hNLAWait)
{
Status1 = RtlDeregisterWaitEx(m_hNLAWait, INVALID_HANDLE_VALUE);
if (!NT_SUCCESS(Status1))
{
hr1 = HRESULT_FROM_NT(Status1);
}
if (INVALID_HANDLE_VALUE != m_hGPWait)
{
Status2 = RtlDeregisterWaitEx(m_hGPWait, INVALID_HANDLE_VALUE);
if (!NT_SUCCESS(Status2))
{
hr2 = HRESULT_FROM_NT(Status2);
}
}
if (FAILED(hr1))
{
hr = hr1;
}
else if (FAILED(hr2))
{
hr = hr2;
}
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CGroupPolicyNetworkLocationAwareness::IsJoinedToDomain
//
// Purpose: Checks to see if this machine belongs to an NT Domain
//
// Arguments:
// (none)
//
// Returns: BOOL. TRUE = Joined to a Domain, FALSE = not...
//
// Author: sjkhan 29 Jan 2002
//
// Notes:
//
BOOL CGroupPolicyNetworkLocationAwareness::IsJoinedToDomain()
{
static DWORD dwDomainMember = 0xffffffff; // Unconfigured
TraceTag(ttidGPNLA, "Entering IsJoinedToDomain");
if (0xffffffff == dwDomainMember)
{
dwDomainMember = FALSE;
LPWSTR pszDomain;
NETSETUP_JOIN_STATUS njs = NetSetupUnknownStatus;
if (NERR_Success == NetGetJoinInformation(NULL, &pszDomain, &njs))
{
NetApiBufferFree(pszDomain);
if (NetSetupDomainName == njs)
{
dwDomainMember = TRUE;
TraceTag(ttidGPNLA, "We're on a domain (NLA policies apply)");
}
else
{
TraceTag(ttidGPNLA, "We're not on a domain (No NLA policies will apply)");
}
}
else
{
TraceTag(ttidGPNLA, "We're not on a domain (No NLA policies will apply)");
}
}
else
{
TraceTag(ttidGPNLA, "IsJoinedToDomain: We're already configured...");
}
TraceTag(ttidGPNLA, "Leaving IsJoinedToDomain");
return static_cast<BOOL>(dwDomainMember);
}
//+---------------------------------------------------------------------------
//
// Member: CGroupPolicyNetworkLocationAwareness::IsSameNetworkAsGroupPolicies
//
// Purpose: Used to determine our current network location with respect to
// the network from which the Group Policies came from.
//
// Arguments:
// (none)
//
// Returns: BOOL.
//
// Author: sjkhan 20 Feb 2001
//
// Notes:
//
BOOL CGroupPolicyNetworkLocationAwareness::IsSameNetworkAsGroupPolicies()
{
BOOL fNetworkMatch = FALSE; // Assume we are on a different network.
WCHAR pszName[256] = {0};
DWORD dwSize = 256;
DWORD dwErr;
TraceTag(ttidGPNLA, "Entering IsSameNetworkAsGroupPolicies");
// Get the network Name.
dwErr = GetGroupPolicyNetworkName(pszName, &dwSize);
TraceTag(ttidGPNLA, "NetworkName: %S", pszName);
if (ERROR_SUCCESS == dwErr)
{
if (IsJoinedToDomain())
{
CExceptionSafeLock esLock(&m_csList); // Protecting list
GPNLAPAIR nlapair;
// We need to look at all of the adapters to check that at least 1
// is on the same network from which the Group Policies came.
for (GPNLAITER iter = m_listAdapters.begin(); iter != m_listAdapters.end(); iter++)
{
LPCSTR pStr = NULL;
nlapair = *iter;
TraceTag(ttidGPNLA, "Network Name: %S", nlapair.second.strNetworkName);
TraceTag(ttidGPNLA, "Network Status: %s", DbgNcs(nlapair.second.ncsStatus));
if (
(nlapair.second.strNetworkName == pszName)
&&
(
(NCS_CONNECTED == nlapair.second.ncsStatus) ||
(NCS_AUTHENTICATING == nlapair.second.ncsStatus) ||
(NCS_AUTHENTICATION_SUCCEEDED == nlapair.second.ncsStatus) ||
(NCS_AUTHENTICATION_FAILED == nlapair.second.ncsStatus) ||
(NCS_CREDENTIALS_REQUIRED == nlapair.second.ncsStatus)
)
)
{
// Yes, we're still on the network so we need to enforce group policies.
fNetworkMatch = TRUE;
}
}
}
else
{
TraceTag(ttidGPNLA, "We're not on a domain, exiting...");
}
if (fNetworkMatch != m_fSameNetwork)
{
LanEventNotify (REFRESH_ALL, NULL, NULL, NULL);
m_fSameNetwork = fNetworkMatch;
ReconfigureHomeNet();
}
}
return fNetworkMatch;
}
//+---------------------------------------------------------------------------
//
// Member: CGroupPolicyNetworkLocationAwareness::Reference
//
// Purpose: Increments our reference count.
//
// Arguments:
// (none)
//
// Returns: The current Refcount (note this may not be 100% accurate,
// but will never be 0 unless we're really shutting down).
//
// Author: sjkhan 20 Feb 2001
//
// Notes:
//
LONG CGroupPolicyNetworkLocationAwareness::Reference()
{
InterlockedIncrement(&m_lRefCount);
TraceTag(ttidGPNLA, "Reference() - Count: %d", m_lRefCount);
return m_lRefCount;
}
//+---------------------------------------------------------------------------
//
// Member: CGroupPolicyNetworkLocationAwareness::Unreference
//
// Purpose: Decrements our reference countand sets and event if it reaches
// zero and we're shutting down.
//
// Arguments:
// (none)
//
// Returns: The current Refcount (note this may not be 100% accurate,
// but will never be 0 unless we're really shutting down).
//
// Author: sjkhan 20 Feb 2001
//
// Notes:
//
LONG CGroupPolicyNetworkLocationAwareness::Unreference()
{
if ((0 == InterlockedDecrement(&m_lRefCount)) && m_fShutdown)
{
SetEvent(m_hEventExit);
}
TraceTag(ttidGPNLA, "Unreference() - Count: %d", m_lRefCount);
return m_lRefCount;
}
//+---------------------------------------------------------------------------
//
// Member: CGroupPolicyNetworkLocationAwareness::LookupServiceBegin
//
// Purpose: Wraps the WSA function using our class members.
//
// Arguments:
// DWORD dwControlFlags - WSA Control Flags
//
// Returns: HRESULT indicating success/failure.
//
// Author: sjkhan 20 Feb 2001
//
// Notes:
//
HRESULT CGroupPolicyNetworkLocationAwareness::LookupServiceBegin(DWORD dwControlFlags)
{
HRESULT hr = S_OK;
if (SOCKET_ERROR == WSALookupServiceBegin(&m_wqsRestrictions, dwControlFlags, &m_hQuery))
{
int nError;
nError = WSAGetLastError();
hr = HRESULT_FROM_WIN32(nError);
TraceError("WSALookupServiceBegin() failed", hr);
m_hQuery = NULL;
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CGroupPolicyNetworkLocationAwareness::LookupServiceNext
//
// Purpose: Wraps the WSA function using our class members.
//
// Arguments:
// DWORD dwControlFlags [in] - WSA Control Flags
// LPDWORD lpdwBufferLength [in/out] - Buffer Length sent/required.
// LPWSAQUERYSET lpqsResults [out] - Actual Query Results.
//
// Returns: HRESULT indicating success/failure.
//
// Author: sjkhan 20 Feb 2001
//
// Notes:
//
HRESULT CGroupPolicyNetworkLocationAwareness::LookupServiceNext(DWORD dwControlFlags, LPDWORD lpdwBufferLength, LPWSAQUERYSET lpqsResults)
{
HRESULT hr = S_OK;
int nError;
INT nRet = WSALookupServiceNext(m_hQuery, dwControlFlags, lpdwBufferLength, lpqsResults);
if (SOCKET_ERROR == nRet)
{
BOOL fTraceError;
nError = WSAGetLastError();
hr = HRESULT_FROM_WIN32(nError);
fTraceError = (!lpqsResults || (hr == HRESULT_FROM_WIN32(WSA_E_NO_MORE))) ? TRUE : FALSE;
TraceErrorOptional("LookupServiceNext", hr, fTraceError);
}
TraceTag(ttidGPNLA, "LookupServiceNext terminated with %x", nRet);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CGroupPolicyNetworkLocationAwareness::LookupServiceEnd
//
// Purpose: Wraps the WSA function using our class members.
//
// Arguments:
// (none)
//
// Returns: HRESULT indicating success/failure.
//
// Author: sjkhan 20 Feb 2001
//
// Notes:
//
HRESULT CGroupPolicyNetworkLocationAwareness::LookupServiceEnd()
{
HRESULT hr = S_OK;
int nError;
if (SOCKET_ERROR == WSALookupServiceEnd(m_hQuery))
{
nError = WSAGetLastError();
hr = HRESULT_FROM_WIN32(nError);
}
m_hQuery = NULL;
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CGroupPolicyNetworkLocationAwareness::QueueEvent
//
// Purpose: Queue's an event to notify netshell of a change.
//
// Arguments:
// CONMAN_EVENTTYPE cmEventType [in] - Type of Event.
// LPGUID pguidAdapter [in] - Guid for the adapter.
// NETCON_STATUS ncsStatus [in] - Status for Connection.
//
// Returns: HRESULT.
//
// Author: sjkhan 20 Feb 2001
//
// Notes:
//
HRESULT CGroupPolicyNetworkLocationAwareness::QueueEvent(CONMAN_EVENTTYPE cmEventType, LPGUID pguidAdapter, NETCON_STATUS ncsStatus)
{
HRESULT hr = S_OK;
if ( (CONNECTION_STATUS_CHANGE == cmEventType) ||
(CONNECTION_ADDRESS_CHANGE == cmEventType) )
{
CONMAN_EVENT* pEvent = new CONMAN_EVENT;
if (pEvent)
{
ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
pEvent->Type = cmEventType;
pEvent->guidId = *pguidAdapter;
pEvent->Status = ncsStatus;
pEvent->ConnectionManager = CONMAN_LAN;
if (NCS_HARDWARE_NOT_PRESENT == ncsStatus) // Not too useful for LAN connections. We can delete the device instead.
{
// This will happen during PnP undock.
TraceTag(ttidGPNLA, "Sending delete for NCS_HARDWARE_NOT_PRESENT instead");
pEvent->Type = CONNECTION_DELETED;
}
if (!QueueUserWorkItemInThread(LanEventWorkItem, reinterpret_cast<PVOID>(pEvent), EVENTMGR_CONMAN))
{
FreeConmanEvent(pEvent);
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
else
{
hr = E_INVALIDARG;
}
TraceHr(ttidError, FAL, hr, FALSE, "CGroupPolicyNetworkLocationAwareness::QueueEvent");
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CGroupPolicyNetworkLocationAwareness::EnumChanges
//
// Purpose: Enumerates all the changes that have occurred to the network.
//
// Arguments:
// (none)
//
// Returns: HRESULT indicating success or failure.
//
// Author: sjkhan 20 Feb 2001
//
// Notes: This will re-increment the reference count if m_fShutdown is not set.
// Doesn't allow it to go to Zero though.
//
HRESULT CGroupPolicyNetworkLocationAwareness::EnumChanges()
{
HRESULT hr = S_OK;
BOOL fRet = FALSE;
BOOL fNoNetwork = TRUE;
BOOL fNetworkMatch = FALSE;
PWSAQUERYSET wqsResult = NULL;
DWORD dwLen;
WCHAR pszName[256] = {0};
DWORD dwSize = 256;
TraceTag(ttidGPNLA, "Entering EnumChanges");
BOOL bDomainMember = IsJoinedToDomain();
if (!m_hQuery)
{
// For some reason we didn't get this ealier.
// Possibly TCP/IP wasn't installed. We can add this now and
// it will have the desired effect.
LookupServiceBegin(LUP_NOCONTAINERS);
}
if (!m_hQuery)
{
return E_UNEXPECTED;
}
while (fRet == FALSE)
{
dwLen = 0;
// Do call twice, first to get dwSize of buffer for second call
hr = LookupServiceNext(0, &dwLen, NULL);
if (FAILED(hr) && hr != HRESULT_FROM_WIN32(WSA_E_NO_MORE) && hr != HRESULT_FROM_WIN32(WSAEFAULT))
{
TraceError("LookupServiceNext", hr);
fRet = FALSE;
break;
}
wqsResult = reinterpret_cast<PWSAQUERYSET>(new BYTE[dwLen]);
if (!wqsResult)
{
hr = HrFromLastWin32Error();
TraceError("Error: malloc() failed", hr);
fRet = TRUE;
break;
}
if (S_OK == (hr = LookupServiceNext(0, &dwLen, wqsResult)))
{
fNoNetwork = FALSE;
if (wqsResult->lpBlob != NULL)
{
NLA_BLOB *blob = reinterpret_cast<NLA_BLOB *>(wqsResult->lpBlob->pBlobData);
int next;
do
{
// We are looking for the blob containing the network GUID
if (blob->header.type == NLA_INTERFACE)
{
WCHAR strAdapter[MAX_PATH];
DWORD dwErr;
ZeroMemory(strAdapter, MAX_PATH * sizeof(WCHAR));
wcscpy(strAdapter, wqsResult->lpszServiceInstanceName);
// Get the network Name. We ignore failure since we still need to know other details.
dwErr = GetGroupPolicyNetworkName(pszName, &dwSize);
// matching pszName and interface type is ATM/LAN etc, but not RAS
if(blob->data.interfaceData.dwType != IF_TYPE_PPP && blob->data.interfaceData.dwType != IF_TYPE_SLIP)
{
CExceptionSafeLock esLock(&m_csList); // Protecting list
GUID guidAdapter;
WCHAR strAdapterGuid[39];
GPNLAPAIR nlapair;
GPNLAITER iter;
NETCON_STATUS ncsStatus;
ZeroMemory(strAdapterGuid, 39 * sizeof(WCHAR));
TraceTag(ttidGPNLA, "AdapterName: %s", blob->data.interfaceData.adapterName);
mbstowcs(strAdapterGuid, blob->data.interfaceData.adapterName, 39);
CLSIDFromString(strAdapterGuid, &guidAdapter);
nlapair.first = guidAdapter;
iter = find(m_listAdapters.begin(), m_listAdapters.end(), nlapair);
if (iter == m_listAdapters.end())
{
// We didn't find the adapter in the list that we currently have.
// So we need to add it to the list.
hr = HrGetPnpDeviceStatus(&guidAdapter, &ncsStatus);
nlapair.second.strNetworkName = strAdapter;
nlapair.second.ncsStatus = ncsStatus;
if (SUCCEEDED(hr))
{
// If we got a valid status, we go ahead and add the adapter to
// the list.
m_listAdapters.insert(m_listAdapters.begin(), nlapair);
}
// Send the initial address status info:
QueueEvent(CONNECTION_STATUS_CHANGE, &guidAdapter, ncsStatus);
QueueEvent(CONNECTION_ADDRESS_CHANGE, &guidAdapter, ncsStatus);
}
else
{
// We found the adapter, so update its status.
GPNLAPAIR& rnlapair = *iter;
if (rnlapair.second.strNetworkName != strAdapter)
{
rnlapair.second.strNetworkName = strAdapter;
}
hr = HrGetPnpDeviceStatus(&guidAdapter, &ncsStatus);
if (SUCCEEDED(hr))
{
if (ncsStatus != rnlapair.second.ncsStatus)
{
// The status is different so we need to send an event to the connections folder.
rnlapair.second.ncsStatus = ncsStatus;
}
// [Deon] We need to always send this as we don't really know what the current
// status of the adapter is. We only know the NLA part.
//
// If we make the above check it could happen somebody else moves the address over
// to NCS_INVALID_ADDRESS and then we don't send the NCS_CONNECTED once it changes.
QueueEvent(CONNECTION_STATUS_CHANGE, &guidAdapter, ncsStatus);
QueueEvent(CONNECTION_ADDRESS_CHANGE, &guidAdapter, ncsStatus);
}
}
if (strAdapter != pszName)
{
// If this adapter is not on the same network, then we need to look at all others and
// ensure that at least 1 is on the same network from which the Group Policies came.
for (GPNLAITER iter = m_listAdapters.begin(); iter != m_listAdapters.end(); iter++)
{
LPCSTR pStr = NULL;
nlapair = *iter;
TraceTag(ttidGPNLA, "Network Name: %S", nlapair.second.strNetworkName);
TraceTag(ttidGPNLA, "Network Status: %s", DbgNcs(nlapair.second.ncsStatus));
if (nlapair.second.strNetworkName == pszName)
{
// Yes, we're still on the network so we need to enforce group policies.
fNetworkMatch = TRUE;
}
}
}
if (fNetworkMatch)
{
break;
}
}
}
// There may be multiple blobs for each interface so make sure we find them all
next = blob->header.nextOffset;
blob = (NLA_BLOB *)(((char *)blob) + next);
} while(next != 0);
}
else
{
TraceTag(ttidGPNLA, "Blob is NULL");
fRet = TRUE;
}
free(wqsResult);
wqsResult = NULL;
}
else
{
if (hr != HRESULT_FROM_WIN32(WSA_E_NO_MORE))
{
TraceError("LookupServiceNext failed\n", hr);
fRet = FALSE;
}
free(wqsResult);
break;
}
}
BOOL fFireRefreshAll = FALSE;
if (bDomainMember)
{
if (!fNoNetwork)
{ // We have a Network
if (fNetworkMatch)
{
// Enforce Policies.
if (!m_fSameNetwork)
{
// We are changing the network - we need to refresh all the connectoids in the folder to
// update their icons to reflect policy.
fFireRefreshAll = TRUE;
m_fSameNetwork = TRUE;
}
TraceTag(ttidGPNLA, "Network Match");
}
else
{
// Removed Policy Enforcement.
if (m_fSameNetwork)
{
// We are changing the network - we need to refresh all the connectoids in the folder to
// update their icons to reflect policy.
fFireRefreshAll = TRUE;
m_fSameNetwork = FALSE;
}
TraceTag(ttidGPNLA, "Network does not Match");
}
ReconfigureHomeNet();
}
else
{
// No Networks so don't do anything.
}
}
else // Member of a workgroup
{
m_fSameNetwork = FALSE;
ReconfigureHomeNet();
}
if (HRESULT_FROM_WIN32(WSA_E_NO_MORE) == hr)
{
hr = S_OK;
}
DWORD cbOutBuffer;
if (!m_fShutdown)
{
Reference();
// Wait for Network Change
WSANSPIoctl(m_hQuery, SIO_NSP_NOTIFY_CHANGE,
NULL, 0, NULL, 0, &cbOutBuffer,
&m_wsaCompletion);
if (fFireRefreshAll)
{
LanEventNotify (REFRESH_ALL, NULL, NULL, NULL);
}
}
TraceTag(ttidGPNLA, "Exiting EnumChanges");
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CGroupPolicyNetworkLocationAwareness::EventHandler
//
// Purpose: Called when NLA changes occur.
//
// Arguments:
// LPVOID pContext - generally the "this" pointer.
// BOOLEAN fTimerFired - if this happened because of a timer or the event
// getting set. Since we specify INFINITE, this is
// not going to get fired by the timer.
// Returns: nothing
//
// Author: sjkhan 20 Feb 2001
//
// Notes:
//
VOID NTAPI CGroupPolicyNetworkLocationAwareness::EventHandler(IN LPVOID pContext, IN BOOLEAN fTimerFired)
{
CGroupPolicyNetworkLocationAwareness* pGPNLA = reinterpret_cast<CGroupPolicyNetworkLocationAwareness*>(pContext);
DWORD dwBytes;
BOOL bSucceeded = GetOverlappedResult(pGPNLA->m_hQuery, &pGPNLA->m_wsaOverlapped, &dwBytes, FALSE);
if (!bSucceeded)
{
TraceError("GetOverlappedResult failed", HrFromLastWin32Error());
}
if (FALSE == fTimerFired && !pGPNLA->m_fShutdown && bSucceeded)
{
pGPNLA->EnumChanges();
}
pGPNLA->Unreference();
if (!bSucceeded)
{
pGPNLA->m_fErrorShutdown = TRUE;
QueueUserWorkItem(ShutdownNlaHandler, pContext, WT_EXECUTEINLONGTHREAD);
}
}
//+---------------------------------------------------------------------------
//
// Member: CGroupPolicyNetworkLocationAwareness::GroupPolicyChange
//
// Purpose: Called when Machine Group Policy changes occur.
//
// Arguments:
// LPVOID pContext - generally the "this" pointer.
// BOOLEAN fTimerFired - if this happened because of a timer or the event
// getting set. Since we specify INFINITE, this is
// not going to get fired by the timer.
// Returns: nothing
//
// Author: sjkhan 05 Feb 2002
//
// Notes:
//
VOID NTAPI CGroupPolicyNetworkLocationAwareness::GroupPolicyChange(IN LPVOID pContext, IN BOOLEAN fTimerFired)
{
TraceTag(ttidGPNLA, "GroupPolicyChange called");
ReconfigureHomeNet(TRUE);
LanEventNotify(REFRESH_ALL, NULL, NULL, NULL);
}
//+---------------------------------------------------------------------------
//
// Member: CGroupPolicyNetworkLocationAwareness::ShutdownNlaHandler
//
// Purpose: Shutdown Nla handler, because Nla service is toast.
//
// Arguments:
//
//
// Returns: nothing
//
// Author: sjkhan 05 Feb 2002
//
// Notes:
//
DWORD WINAPI CGroupPolicyNetworkLocationAwareness::ShutdownNlaHandler(PVOID pThis)
{
TraceFileFunc(ttidGPNLA);
CGroupPolicyNetworkLocationAwareness* pGPNLA =
reinterpret_cast<CGroupPolicyNetworkLocationAwareness*>(InterlockedExchangePointer( (PVOID volatile *) &g_pGPNLA, NULL));
if (pGPNLA)
{
Assert(pGPNLA == pThis); // Making the assumption that the context is always g_pGPNLA, since I'm clearing g_pGPNLA.
pGPNLA->Uninitialize();
delete pGPNLA;
}
return 0;
}
//+---------------------------------------------------------------------------
//
// Function: ReconfigureHomeNet
//
// Purpose: Change Homenet Configuration
//
// Arguments:
// fWaitUntilRunningOrStopped - if the caller should wait for the
// service to start, or to fail starting
// and stop.
//
// Returns: HRESULT indicating success of failure
//
// Author: sjkhan 09 Dec 2000
//
// Notes:
//
//
//
//
HRESULT CGroupPolicyNetworkLocationAwareness::ReconfigureHomeNet(BOOL fWaitUntilRunningOrStopped)
{
SC_HANDLE hscManager;
SC_HANDLE hService;
SERVICE_STATUS ServiceStatus;
if (0 != InterlockedExchange(&m_lBusyWithReconfigure, 1L))
{
return S_FALSE;
}
TraceTag(ttidGPNLA, "Entering ReconfigureHomeNet");
hscManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
if (hscManager)
{
TraceTag(ttidGPNLA, "Attempting to open service");
hService = OpenService(hscManager, L"SharedAccess", SERVICE_QUERY_STATUS | SERVICE_USER_DEFINED_CONTROL);
if (hService)
{
DWORD dwCount = 0;
SERVICE_STATUS SvcStatus = {0};
BOOL fRet;
if (fWaitUntilRunningOrStopped)
{
do
{
if (!QueryServiceStatus(hService, &SvcStatus))
{
break;
}
if (SERVICE_START_PENDING == SvcStatus.dwCurrentState)
{
TraceTag(ttidGPNLA, "Service is still starting. Waiting 5 seconds.");
Sleep(5000); // Sleep 5 seconds;
}
} while ((SERVICE_START_PENDING == SvcStatus.dwCurrentState) && ++dwCount <= 6);
}
if (!fWaitUntilRunningOrStopped || (SERVICE_RUNNING == SvcStatus.dwCurrentState))
{
fRet = ControlService(hService, IPNATHLP_CONTROL_UPDATE_CONNECTION, &ServiceStatus);
if (!fRet)
{
DWORD dwErr = GetLastError();
TraceError("Control Service returned: 0x%x", HRESULT_FROM_WIN32(dwErr));
}
else
{
TraceTag(ttidGPNLA, "Requested Reconfiguration check from ICF/ICS");
}
}
CloseServiceHandle(hService);
}
else
{
TraceTag(ttidGPNLA, "Could not open service");
}
CloseServiceHandle(hscManager);
}
TraceTag(ttidGPNLA, "Leaving ReconfigureHomeNet");
InterlockedExchange(&m_lBusyWithReconfigure, 0L);
return S_OK;
}