//+--------------------------------------------------------------------------- // // 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 #include #include "nmbase.h" #include #include #include #include #include #include #include "ipnathlp.h" #include "ncmisc.h" #include "ipifcons.h" #include "conman.h" #include "eventq.h" GUID g_WsMobilityServiceClassGuid = NLA_SERVICE_CLASS_GUID; static const WCHAR c_szHomenetService[] = L"SharedAccess"; extern CGroupPolicyNetworkLocationAwareness* g_pGPNLA; bool operator == (const GPNLAPAIR& rpair1, const GPNLAPAIR& rpair2) { return IsEqualGUID(rpair1.first, rpair2.first) == TRUE; } LONG CGroupPolicyNetworkLocationAwareness::m_lBusyWithReconfigure = 0; //+--------------------------------------------------------------------------- // // Member: CGroupPolicyNetworkLocationAwareness::CGroupPolicyNetworkLocationAwareness // // Purpose: CGroupPolicyNetworkLocationAwareness constructor // // Arguments: // (none) // // Returns: none // // Author: ckotze 20 Feb 2001 // // Notes: // CGroupPolicyNetworkLocationAwareness::CGroupPolicyNetworkLocationAwareness() throw() { TraceFileFunc(ttidGPNLA); 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; } //+--------------------------------------------------------------------------- // // Member: CGroupPolicyNetworkLocationAwareness::~CGroupPolicyNetworkLocationAwareness // // Purpose: CGroupPolicyNetworkLocationAwareness destructor // // Arguments: // (none) // // Returns: none // // Author: ckotze 20 Feb 2001 // // Notes: // CGroupPolicyNetworkLocationAwareness::~CGroupPolicyNetworkLocationAwareness() throw() { TraceFileFunc(ttidGPNLA); } //+--------------------------------------------------------------------------- // // 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(); if (SUCCEEDED(hr)) { return hr; } } UnregisterGPNotification(m_hEventGP); } 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: Previously configured to: %s", dwDomainMember ? "TRUE" : "FALSE"); } TraceTag(ttidGPNLA, "Leaving IsJoinedToDomain"); return static_cast(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() throw() { 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, and is currently // connected or trying to connect to a network. for (GPNLAITER iter = m_listAdapters.begin(); iter != m_listAdapters.end(); iter++) { LPCSTR pStr = NULL; nlapair = *iter; TraceTag(ttidGPNLA, "Network Name: %S", nlapair.second.strNetworkName.c_str()); 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(); } } TraceTag(ttidGPNLA, "IsSameNetworkAsGroupPolicies. Matches: %s", fNetworkMatch ? "TRUE" : "FALSE"); 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() throw() { 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() throw() { 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 [in] WSA Control Flags // // Returns: HRESULT indicating success/failure. // // Author: sjkhan 20 Feb 2001 // // Notes: // HRESULT CGroupPolicyNetworkLocationAwareness::LookupServiceBegin(IN DWORD dwControlFlags) { TraceFileFunc(ttidGPNLA); 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(IN DWORD dwControlFlags, IN OUT LPDWORD lpdwBufferLength, OUT LPWSAQUERYSET lpqsResults) { TraceFileFunc(ttidGPNLA); 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() { TraceFileFunc(ttidGPNLA); 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(IN CONMAN_EVENTTYPE cmEventType, IN LPCGUID pguidAdapter, IN NETCON_STATUS ncsStatus) { TraceFileFunc(ttidGPNLA); 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, 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() { TraceFileFunc(ttidGPNLA); 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(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(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)); lstrcpynW(strAdapter, wqsResult->lpszServiceInstanceName, celems(strAdapter)); // 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.c_str()); 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: static // VOID NTAPI CGroupPolicyNetworkLocationAwareness::EventHandler(IN LPVOID pContext, IN BOOLEAN fTimerFired) throw() { TraceFileFunc(ttidGPNLA); CGroupPolicyNetworkLocationAwareness* pGPNLA = reinterpret_cast(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) { TraceFileFunc(ttidGPNLA); 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: // pVoid [in] The CGroupPolicyNetworkLocationAwareness context // // Returns: nothing // // Author: sjkhan 05 Feb 2002 // // Notes: static // DWORD WINAPI CGroupPolicyNetworkLocationAwareness::ShutdownNlaHandler(IN PVOID pThis) { TraceFileFunc(ttidGPNLA); CGroupPolicyNetworkLocationAwareness* pGPNLA = reinterpret_cast(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: CGroupPolicyNetworkLocationAwareness::ReconfigureHomeNet // // Purpose: Change Homenet Configuration // // Arguments: // (none) // // Returns: HRESULT indicating success of failure // // Author: sjkhan 09 Dec 2000 // // Notes: // // // // HRESULT CGroupPolicyNetworkLocationAwareness::ReconfigureHomeNet(BOOL fWaitUntilRunningOrStopped) { TraceFileFunc(ttidGPNLA); 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, c_szHomenetService, 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_POLICY, &ServiceStatus); if (!fRet) { DWORD dwErr = GetLastError(); TraceError("Error sending IPNATHLP_CONTROL_UPDATE_POLICY to SharedAccess service", 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; }