Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1156 lines
39 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 2001.
  5. //
  6. // File: G P N L A . C P P
  7. //
  8. // Contents: Class for Handling NLA Changes that affect Group Policies
  9. //
  10. // Notes:
  11. //
  12. // Author: sjkhan 20 Feb 2001
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include "trace.h"
  18. #include "gpnla.h"
  19. #include <winsock2.h>
  20. #include <mswsock.h>
  21. #include "nmbase.h"
  22. #include <userenv.h>
  23. #include <userenvp.h>
  24. #include <ncstl.h>
  25. #include <ncstlstr.h>
  26. #include <stlalgor.h>
  27. #include <lancmn.h>
  28. #include <lm.h>
  29. #include <ipnathlp.h>
  30. #include "ncmisc.h"
  31. #include "ipifcons.h"
  32. #include "ncexcept.h"
  33. #include "conman.h"
  34. GUID g_WsMobilityServiceClassGuid = NLA_SERVICE_CLASS_GUID;
  35. extern CGroupPolicyNetworkLocationAwareness* g_pGPNLA;
  36. bool operator == (const GPNLAPAIR& rpair1, const GPNLAPAIR& rpair2)
  37. {
  38. return IsEqualGUID(rpair1.first, rpair2.first) == TRUE;
  39. }
  40. LONG CGroupPolicyNetworkLocationAwareness::m_lBusyWithReconfigure = 0;
  41. CGroupPolicyNetworkLocationAwareness::CGroupPolicyNetworkLocationAwareness()
  42. {
  43. m_fSameNetwork = FALSE;
  44. m_fShutdown = FALSE;
  45. m_lRefCount = 0;
  46. m_fErrorShutdown = FALSE;
  47. m_hGPWait = INVALID_HANDLE_VALUE;
  48. m_hNLAWait = INVALID_HANDLE_VALUE;
  49. m_lBusyWithReconfigure = 0;
  50. }
  51. CGroupPolicyNetworkLocationAwareness::~CGroupPolicyNetworkLocationAwareness()
  52. {
  53. }
  54. //+---------------------------------------------------------------------------
  55. //
  56. // Member: CGroupPolicyNetworkLocationAwareness::Initialize
  57. //
  58. // Purpose: To initialize the different components required for detecting
  59. // changes to the network and creating the different
  60. // synchronization objects required.
  61. // Arguments:
  62. // (none)
  63. //
  64. // Returns: HRESULT indicating SUCCESS or FAILURE
  65. //
  66. // Author: sjkhan 20 Feb 2001
  67. //
  68. // Notes:
  69. //
  70. HRESULT CGroupPolicyNetworkLocationAwareness::Initialize()
  71. {
  72. HRESULT hr;
  73. TraceTag(ttidGPNLA, "Initializing Group Policy Handler");
  74. InitializeCriticalSection(&m_csList);
  75. // Init Winsock
  76. if (ERROR_SUCCESS == WSAStartup(MAKEWORD(2, 2), &m_wsaData))
  77. {
  78. m_hEventNLA = CreateEvent(NULL, FALSE, FALSE, NULL);
  79. if (m_hEventNLA)
  80. {
  81. m_hEventExit = CreateEvent(NULL, FALSE, FALSE, NULL);
  82. if (m_hEventExit)
  83. {
  84. m_hEventGP = CreateEvent(NULL, FALSE, FALSE, NULL);
  85. if (m_hEventGP)
  86. {
  87. hr = RegisterWait();
  88. if (SUCCEEDED(hr))
  89. {
  90. if (RegisterGPNotification(m_hEventGP, TRUE))
  91. {
  92. ZeroMemory(&m_wsaCompletion,sizeof(m_wsaCompletion));
  93. ZeroMemory(&m_wsaOverlapped,sizeof(m_wsaOverlapped));
  94. m_wsaOverlapped.hEvent = m_hEventNLA;
  95. m_wsaCompletion.Type = NSP_NOTIFY_EVENT;
  96. m_wsaCompletion.Parameters.Event.lpOverlapped = &m_wsaOverlapped;
  97. ZeroMemory(&m_wqsRestrictions, sizeof(m_wqsRestrictions));
  98. m_wqsRestrictions.dwSize = sizeof(m_wqsRestrictions);
  99. m_wqsRestrictions.lpServiceClassId = &g_WsMobilityServiceClassGuid;
  100. m_wqsRestrictions.dwNameSpace = NS_NLA;
  101. hr = LookupServiceBegin(LUP_NOCONTAINERS);
  102. if (SUCCEEDED(hr))
  103. {
  104. // Loop through once and get all the data to begin with.
  105. hr = EnumChanges();
  106. }
  107. return hr;
  108. }
  109. else
  110. {
  111. hr = HrFromLastWin32Error();
  112. DeregisterWait();
  113. }
  114. }
  115. CloseHandle(m_hEventGP);
  116. }
  117. else
  118. {
  119. hr = HrFromLastWin32Error();
  120. }
  121. }
  122. else
  123. {
  124. hr = HrFromLastWin32Error();
  125. }
  126. CloseHandle(m_hEventExit);
  127. }
  128. else
  129. {
  130. hr = HrFromLastWin32Error();
  131. }
  132. CloseHandle(m_hEventNLA);
  133. }
  134. else
  135. {
  136. int nError;
  137. nError = WSAGetLastError();
  138. hr = HRESULT_FROM_WIN32(nError);
  139. }
  140. TraceError("CGroupPolicyNetworkLocationAwareness::Initialize failed", hr);
  141. return hr;
  142. }
  143. //+---------------------------------------------------------------------------
  144. //
  145. // Member: CGroupPolicyNetworkLocationAwareness::Uninitialize
  146. //
  147. // Purpose: This is used to ensure that no threads are currently running
  148. // when they should be stopped. If the refcount is >0 then it
  149. // waits for the last busy thread to terminate and set the event
  150. // marking its termination so that shutdown can proceed.
  151. // Arguments:
  152. // (none)
  153. //
  154. // Returns: HRESULT indicating success/failure.
  155. //
  156. // Author: sjkhan 20 Feb 2001
  157. //
  158. // Notes:
  159. //
  160. HRESULT CGroupPolicyNetworkLocationAwareness::Uninitialize()
  161. {
  162. HRESULT hr = S_OK;
  163. DWORD dwRet = WAIT_OBJECT_0;
  164. int nCount = 0;
  165. TraceTag(ttidGPNLA, "Unitializing Group Policy Handler");
  166. m_fShutdown = TRUE;
  167. Unreference();
  168. // LookupServiceEnd should cause an event to fire which will make us exit (unless NLA was already stopped).
  169. hr = LookupServiceEnd();
  170. if ((0 != m_lRefCount) && SUCCEEDED(hr) && !m_fErrorShutdown)
  171. {
  172. dwRet = WaitForSingleObject(m_hEventExit, 30000L);
  173. }
  174. do
  175. {
  176. hr = DeregisterWait();
  177. if (SUCCEEDED(hr))
  178. {
  179. break;
  180. }
  181. } while ((nCount++ < 3) && FAILED(hr));
  182. TraceError("DeregisterWait returned", hr);
  183. if (SUCCEEDED(hr))
  184. {
  185. CloseHandle(m_hEventExit);
  186. CloseHandle(m_hEventNLA);
  187. DeleteCriticalSection(&m_csList);
  188. WSACleanup();
  189. }
  190. TraceTag(ttidGPNLA, "NLA was uninitialized");
  191. return hr;
  192. }
  193. //+---------------------------------------------------------------------------
  194. //
  195. // Member: CGroupPolicyNetworkLocationAwareness::RegisterWait
  196. //
  197. // Purpose: Registers the Wait Object so that we don't require any threads
  198. // of our own.
  199. // Arguments:
  200. // (none)
  201. //
  202. // Returns: HRESULT indicating success/failure.
  203. //
  204. // Author: sjkhan 20 Feb 2001
  205. //
  206. // Notes:
  207. //
  208. HRESULT CGroupPolicyNetworkLocationAwareness::RegisterWait()
  209. {
  210. TraceFileFunc(ttidGPNLA);
  211. HRESULT hr = S_OK;
  212. NTSTATUS Status;
  213. Reference(); // Make sure that we're referenced so that we don't accidentally kill the service while it's still busy.
  214. Status = RtlRegisterWait(&m_hNLAWait, m_hEventNLA, &CGroupPolicyNetworkLocationAwareness::EventHandler, this, INFINITE, WT_EXECUTEINLONGTHREAD);
  215. if (!NT_SUCCESS(Status))
  216. {
  217. m_hNLAWait = INVALID_HANDLE_VALUE;
  218. hr = HRESULT_FROM_NT(Status);
  219. }
  220. else
  221. {
  222. Status = RtlRegisterWait(&m_hGPWait, m_hEventGP, &CGroupPolicyNetworkLocationAwareness::GroupPolicyChange, this, INFINITE, WT_EXECUTEINLONGTHREAD);
  223. if (!NT_SUCCESS(Status))
  224. {
  225. hr = HRESULT_FROM_NT(Status);
  226. RtlDeregisterWaitEx(m_hNLAWait, INVALID_HANDLE_VALUE);
  227. m_hGPWait = INVALID_HANDLE_VALUE;
  228. m_hNLAWait = INVALID_HANDLE_VALUE;
  229. }
  230. }
  231. return hr;
  232. }
  233. //+---------------------------------------------------------------------------
  234. //
  235. // Member: CGroupPolicyNetworkLocationAwareness::DeregisterWait
  236. //
  237. // Purpose: Deregisters the wait so that we can shutdown and not have
  238. // any new threads spawned.
  239. // Arguments:
  240. // (none)
  241. //
  242. // Returns: HRESULT indicating success/failure.
  243. //
  244. // Author: sjkhan 20 Feb 2001
  245. //
  246. // Notes:
  247. //
  248. HRESULT CGroupPolicyNetworkLocationAwareness::DeregisterWait()
  249. {
  250. TraceFileFunc(ttidGPNLA);
  251. HRESULT hr,hr1,hr2 = S_OK;
  252. NTSTATUS Status1, Status2;
  253. if (INVALID_HANDLE_VALUE != m_hNLAWait)
  254. {
  255. Status1 = RtlDeregisterWaitEx(m_hNLAWait, INVALID_HANDLE_VALUE);
  256. if (!NT_SUCCESS(Status1))
  257. {
  258. hr1 = HRESULT_FROM_NT(Status1);
  259. }
  260. if (INVALID_HANDLE_VALUE != m_hGPWait)
  261. {
  262. Status2 = RtlDeregisterWaitEx(m_hGPWait, INVALID_HANDLE_VALUE);
  263. if (!NT_SUCCESS(Status2))
  264. {
  265. hr2 = HRESULT_FROM_NT(Status2);
  266. }
  267. }
  268. if (FAILED(hr1))
  269. {
  270. hr = hr1;
  271. }
  272. else if (FAILED(hr2))
  273. {
  274. hr = hr2;
  275. }
  276. }
  277. return hr;
  278. }
  279. //+---------------------------------------------------------------------------
  280. //
  281. // Member: CGroupPolicyNetworkLocationAwareness::IsJoinedToDomain
  282. //
  283. // Purpose: Checks to see if this machine belongs to an NT Domain
  284. //
  285. // Arguments:
  286. // (none)
  287. //
  288. // Returns: BOOL. TRUE = Joined to a Domain, FALSE = not...
  289. //
  290. // Author: sjkhan 29 Jan 2002
  291. //
  292. // Notes:
  293. //
  294. BOOL CGroupPolicyNetworkLocationAwareness::IsJoinedToDomain()
  295. {
  296. static DWORD dwDomainMember = 0xffffffff; // Unconfigured
  297. TraceTag(ttidGPNLA, "Entering IsJoinedToDomain");
  298. if (0xffffffff == dwDomainMember)
  299. {
  300. dwDomainMember = FALSE;
  301. LPWSTR pszDomain;
  302. NETSETUP_JOIN_STATUS njs = NetSetupUnknownStatus;
  303. if (NERR_Success == NetGetJoinInformation(NULL, &pszDomain, &njs))
  304. {
  305. NetApiBufferFree(pszDomain);
  306. if (NetSetupDomainName == njs)
  307. {
  308. dwDomainMember = TRUE;
  309. TraceTag(ttidGPNLA, "We're on a domain (NLA policies apply)");
  310. }
  311. else
  312. {
  313. TraceTag(ttidGPNLA, "We're not on a domain (No NLA policies will apply)");
  314. }
  315. }
  316. else
  317. {
  318. TraceTag(ttidGPNLA, "We're not on a domain (No NLA policies will apply)");
  319. }
  320. }
  321. else
  322. {
  323. TraceTag(ttidGPNLA, "IsJoinedToDomain: We're already configured...");
  324. }
  325. TraceTag(ttidGPNLA, "Leaving IsJoinedToDomain");
  326. return static_cast<BOOL>(dwDomainMember);
  327. }
  328. //+---------------------------------------------------------------------------
  329. //
  330. // Member: CGroupPolicyNetworkLocationAwareness::IsSameNetworkAsGroupPolicies
  331. //
  332. // Purpose: Used to determine our current network location with respect to
  333. // the network from which the Group Policies came from.
  334. //
  335. // Arguments:
  336. // (none)
  337. //
  338. // Returns: BOOL.
  339. //
  340. // Author: sjkhan 20 Feb 2001
  341. //
  342. // Notes:
  343. //
  344. BOOL CGroupPolicyNetworkLocationAwareness::IsSameNetworkAsGroupPolicies()
  345. {
  346. BOOL fNetworkMatch = FALSE; // Assume we are on a different network.
  347. WCHAR pszName[256] = {0};
  348. DWORD dwSize = 256;
  349. DWORD dwErr;
  350. TraceTag(ttidGPNLA, "Entering IsSameNetworkAsGroupPolicies");
  351. // Get the network Name.
  352. dwErr = GetGroupPolicyNetworkName(pszName, &dwSize);
  353. TraceTag(ttidGPNLA, "NetworkName: %S", pszName);
  354. if (ERROR_SUCCESS == dwErr)
  355. {
  356. if (IsJoinedToDomain())
  357. {
  358. CExceptionSafeLock esLock(&m_csList); // Protecting list
  359. GPNLAPAIR nlapair;
  360. // We need to look at all of the adapters to check that at least 1
  361. // is on the same network from which the Group Policies came.
  362. for (GPNLAITER iter = m_listAdapters.begin(); iter != m_listAdapters.end(); iter++)
  363. {
  364. LPCSTR pStr = NULL;
  365. nlapair = *iter;
  366. TraceTag(ttidGPNLA, "Network Name: %S", nlapair.second.strNetworkName);
  367. TraceTag(ttidGPNLA, "Network Status: %s", DbgNcs(nlapair.second.ncsStatus));
  368. if (
  369. (nlapair.second.strNetworkName == pszName)
  370. &&
  371. (
  372. (NCS_CONNECTED == nlapair.second.ncsStatus) ||
  373. (NCS_AUTHENTICATING == nlapair.second.ncsStatus) ||
  374. (NCS_AUTHENTICATION_SUCCEEDED == nlapair.second.ncsStatus) ||
  375. (NCS_AUTHENTICATION_FAILED == nlapair.second.ncsStatus) ||
  376. (NCS_CREDENTIALS_REQUIRED == nlapair.second.ncsStatus)
  377. )
  378. )
  379. {
  380. // Yes, we're still on the network so we need to enforce group policies.
  381. fNetworkMatch = TRUE;
  382. }
  383. }
  384. }
  385. else
  386. {
  387. TraceTag(ttidGPNLA, "We're not on a domain, exiting...");
  388. }
  389. if (fNetworkMatch != m_fSameNetwork)
  390. {
  391. LanEventNotify (REFRESH_ALL, NULL, NULL, NULL);
  392. m_fSameNetwork = fNetworkMatch;
  393. ReconfigureHomeNet();
  394. }
  395. }
  396. return fNetworkMatch;
  397. }
  398. //+---------------------------------------------------------------------------
  399. //
  400. // Member: CGroupPolicyNetworkLocationAwareness::Reference
  401. //
  402. // Purpose: Increments our reference count.
  403. //
  404. // Arguments:
  405. // (none)
  406. //
  407. // Returns: The current Refcount (note this may not be 100% accurate,
  408. // but will never be 0 unless we're really shutting down).
  409. //
  410. // Author: sjkhan 20 Feb 2001
  411. //
  412. // Notes:
  413. //
  414. LONG CGroupPolicyNetworkLocationAwareness::Reference()
  415. {
  416. InterlockedIncrement(&m_lRefCount);
  417. TraceTag(ttidGPNLA, "Reference() - Count: %d", m_lRefCount);
  418. return m_lRefCount;
  419. }
  420. //+---------------------------------------------------------------------------
  421. //
  422. // Member: CGroupPolicyNetworkLocationAwareness::Unreference
  423. //
  424. // Purpose: Decrements our reference countand sets and event if it reaches
  425. // zero and we're shutting down.
  426. //
  427. // Arguments:
  428. // (none)
  429. //
  430. // Returns: The current Refcount (note this may not be 100% accurate,
  431. // but will never be 0 unless we're really shutting down).
  432. //
  433. // Author: sjkhan 20 Feb 2001
  434. //
  435. // Notes:
  436. //
  437. LONG CGroupPolicyNetworkLocationAwareness::Unreference()
  438. {
  439. if ((0 == InterlockedDecrement(&m_lRefCount)) && m_fShutdown)
  440. {
  441. SetEvent(m_hEventExit);
  442. }
  443. TraceTag(ttidGPNLA, "Unreference() - Count: %d", m_lRefCount);
  444. return m_lRefCount;
  445. }
  446. //+---------------------------------------------------------------------------
  447. //
  448. // Member: CGroupPolicyNetworkLocationAwareness::LookupServiceBegin
  449. //
  450. // Purpose: Wraps the WSA function using our class members.
  451. //
  452. // Arguments:
  453. // DWORD dwControlFlags - WSA Control Flags
  454. //
  455. // Returns: HRESULT indicating success/failure.
  456. //
  457. // Author: sjkhan 20 Feb 2001
  458. //
  459. // Notes:
  460. //
  461. HRESULT CGroupPolicyNetworkLocationAwareness::LookupServiceBegin(DWORD dwControlFlags)
  462. {
  463. HRESULT hr = S_OK;
  464. if (SOCKET_ERROR == WSALookupServiceBegin(&m_wqsRestrictions, dwControlFlags, &m_hQuery))
  465. {
  466. int nError;
  467. nError = WSAGetLastError();
  468. hr = HRESULT_FROM_WIN32(nError);
  469. TraceError("WSALookupServiceBegin() failed", hr);
  470. m_hQuery = NULL;
  471. }
  472. return hr;
  473. }
  474. //+---------------------------------------------------------------------------
  475. //
  476. // Member: CGroupPolicyNetworkLocationAwareness::LookupServiceNext
  477. //
  478. // Purpose: Wraps the WSA function using our class members.
  479. //
  480. // Arguments:
  481. // DWORD dwControlFlags [in] - WSA Control Flags
  482. // LPDWORD lpdwBufferLength [in/out] - Buffer Length sent/required.
  483. // LPWSAQUERYSET lpqsResults [out] - Actual Query Results.
  484. //
  485. // Returns: HRESULT indicating success/failure.
  486. //
  487. // Author: sjkhan 20 Feb 2001
  488. //
  489. // Notes:
  490. //
  491. HRESULT CGroupPolicyNetworkLocationAwareness::LookupServiceNext(DWORD dwControlFlags, LPDWORD lpdwBufferLength, LPWSAQUERYSET lpqsResults)
  492. {
  493. HRESULT hr = S_OK;
  494. int nError;
  495. INT nRet = WSALookupServiceNext(m_hQuery, dwControlFlags, lpdwBufferLength, lpqsResults);
  496. if (SOCKET_ERROR == nRet)
  497. {
  498. BOOL fTraceError;
  499. nError = WSAGetLastError();
  500. hr = HRESULT_FROM_WIN32(nError);
  501. fTraceError = (!lpqsResults || (hr == HRESULT_FROM_WIN32(WSA_E_NO_MORE))) ? TRUE : FALSE;
  502. TraceErrorOptional("LookupServiceNext", hr, fTraceError);
  503. }
  504. TraceTag(ttidGPNLA, "LookupServiceNext terminated with %x", nRet);
  505. return hr;
  506. }
  507. //+---------------------------------------------------------------------------
  508. //
  509. // Member: CGroupPolicyNetworkLocationAwareness::LookupServiceEnd
  510. //
  511. // Purpose: Wraps the WSA function using our class members.
  512. //
  513. // Arguments:
  514. // (none)
  515. //
  516. // Returns: HRESULT indicating success/failure.
  517. //
  518. // Author: sjkhan 20 Feb 2001
  519. //
  520. // Notes:
  521. //
  522. HRESULT CGroupPolicyNetworkLocationAwareness::LookupServiceEnd()
  523. {
  524. HRESULT hr = S_OK;
  525. int nError;
  526. if (SOCKET_ERROR == WSALookupServiceEnd(m_hQuery))
  527. {
  528. nError = WSAGetLastError();
  529. hr = HRESULT_FROM_WIN32(nError);
  530. }
  531. m_hQuery = NULL;
  532. return hr;
  533. }
  534. //+---------------------------------------------------------------------------
  535. //
  536. // Member: CGroupPolicyNetworkLocationAwareness::QueueEvent
  537. //
  538. // Purpose: Queue's an event to notify netshell of a change.
  539. //
  540. // Arguments:
  541. // CONMAN_EVENTTYPE cmEventType [in] - Type of Event.
  542. // LPGUID pguidAdapter [in] - Guid for the adapter.
  543. // NETCON_STATUS ncsStatus [in] - Status for Connection.
  544. //
  545. // Returns: HRESULT.
  546. //
  547. // Author: sjkhan 20 Feb 2001
  548. //
  549. // Notes:
  550. //
  551. HRESULT CGroupPolicyNetworkLocationAwareness::QueueEvent(CONMAN_EVENTTYPE cmEventType, LPGUID pguidAdapter, NETCON_STATUS ncsStatus)
  552. {
  553. HRESULT hr = S_OK;
  554. if ( (CONNECTION_STATUS_CHANGE == cmEventType) ||
  555. (CONNECTION_ADDRESS_CHANGE == cmEventType) )
  556. {
  557. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  558. if (pEvent)
  559. {
  560. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  561. pEvent->Type = cmEventType;
  562. pEvent->guidId = *pguidAdapter;
  563. pEvent->Status = ncsStatus;
  564. pEvent->ConnectionManager = CONMAN_LAN;
  565. if (NCS_HARDWARE_NOT_PRESENT == ncsStatus) // Not too useful for LAN connections. We can delete the device instead.
  566. {
  567. // This will happen during PnP undock.
  568. TraceTag(ttidGPNLA, "Sending delete for NCS_HARDWARE_NOT_PRESENT instead");
  569. pEvent->Type = CONNECTION_DELETED;
  570. }
  571. if (!QueueUserWorkItemInThread(LanEventWorkItem, reinterpret_cast<PVOID>(pEvent), EVENTMGR_CONMAN))
  572. {
  573. FreeConmanEvent(pEvent);
  574. }
  575. }
  576. else
  577. {
  578. hr = E_OUTOFMEMORY;
  579. }
  580. }
  581. else
  582. {
  583. hr = E_INVALIDARG;
  584. }
  585. TraceHr(ttidError, FAL, hr, FALSE, "CGroupPolicyNetworkLocationAwareness::QueueEvent");
  586. return hr;
  587. }
  588. //+---------------------------------------------------------------------------
  589. //
  590. // Member: CGroupPolicyNetworkLocationAwareness::EnumChanges
  591. //
  592. // Purpose: Enumerates all the changes that have occurred to the network.
  593. //
  594. // Arguments:
  595. // (none)
  596. //
  597. // Returns: HRESULT indicating success or failure.
  598. //
  599. // Author: sjkhan 20 Feb 2001
  600. //
  601. // Notes: This will re-increment the reference count if m_fShutdown is not set.
  602. // Doesn't allow it to go to Zero though.
  603. //
  604. HRESULT CGroupPolicyNetworkLocationAwareness::EnumChanges()
  605. {
  606. HRESULT hr = S_OK;
  607. BOOL fRet = FALSE;
  608. BOOL fNoNetwork = TRUE;
  609. BOOL fNetworkMatch = FALSE;
  610. PWSAQUERYSET wqsResult = NULL;
  611. DWORD dwLen;
  612. WCHAR pszName[256] = {0};
  613. DWORD dwSize = 256;
  614. TraceTag(ttidGPNLA, "Entering EnumChanges");
  615. BOOL bDomainMember = IsJoinedToDomain();
  616. if (!m_hQuery)
  617. {
  618. // For some reason we didn't get this ealier.
  619. // Possibly TCP/IP wasn't installed. We can add this now and
  620. // it will have the desired effect.
  621. LookupServiceBegin(LUP_NOCONTAINERS);
  622. }
  623. if (!m_hQuery)
  624. {
  625. return E_UNEXPECTED;
  626. }
  627. while (fRet == FALSE)
  628. {
  629. dwLen = 0;
  630. // Do call twice, first to get dwSize of buffer for second call
  631. hr = LookupServiceNext(0, &dwLen, NULL);
  632. if (FAILED(hr) && hr != HRESULT_FROM_WIN32(WSA_E_NO_MORE) && hr != HRESULT_FROM_WIN32(WSAEFAULT))
  633. {
  634. TraceError("LookupServiceNext", hr);
  635. fRet = FALSE;
  636. break;
  637. }
  638. wqsResult = reinterpret_cast<PWSAQUERYSET>(new BYTE[dwLen]);
  639. if (!wqsResult)
  640. {
  641. hr = HrFromLastWin32Error();
  642. TraceError("Error: malloc() failed", hr);
  643. fRet = TRUE;
  644. break;
  645. }
  646. if (S_OK == (hr = LookupServiceNext(0, &dwLen, wqsResult)))
  647. {
  648. fNoNetwork = FALSE;
  649. if (wqsResult->lpBlob != NULL)
  650. {
  651. NLA_BLOB *blob = reinterpret_cast<NLA_BLOB *>(wqsResult->lpBlob->pBlobData);
  652. int next;
  653. do
  654. {
  655. // We are looking for the blob containing the network GUID
  656. if (blob->header.type == NLA_INTERFACE)
  657. {
  658. WCHAR strAdapter[MAX_PATH];
  659. DWORD dwErr;
  660. ZeroMemory(strAdapter, MAX_PATH * sizeof(WCHAR));
  661. wcscpy(strAdapter, wqsResult->lpszServiceInstanceName);
  662. // Get the network Name. We ignore failure since we still need to know other details.
  663. dwErr = GetGroupPolicyNetworkName(pszName, &dwSize);
  664. // matching pszName and interface type is ATM/LAN etc, but not RAS
  665. if(blob->data.interfaceData.dwType != IF_TYPE_PPP && blob->data.interfaceData.dwType != IF_TYPE_SLIP)
  666. {
  667. CExceptionSafeLock esLock(&m_csList); // Protecting list
  668. GUID guidAdapter;
  669. WCHAR strAdapterGuid[39];
  670. GPNLAPAIR nlapair;
  671. GPNLAITER iter;
  672. NETCON_STATUS ncsStatus;
  673. ZeroMemory(strAdapterGuid, 39 * sizeof(WCHAR));
  674. TraceTag(ttidGPNLA, "AdapterName: %s", blob->data.interfaceData.adapterName);
  675. mbstowcs(strAdapterGuid, blob->data.interfaceData.adapterName, 39);
  676. CLSIDFromString(strAdapterGuid, &guidAdapter);
  677. nlapair.first = guidAdapter;
  678. iter = find(m_listAdapters.begin(), m_listAdapters.end(), nlapair);
  679. if (iter == m_listAdapters.end())
  680. {
  681. // We didn't find the adapter in the list that we currently have.
  682. // So we need to add it to the list.
  683. hr = HrGetPnpDeviceStatus(&guidAdapter, &ncsStatus);
  684. nlapair.second.strNetworkName = strAdapter;
  685. nlapair.second.ncsStatus = ncsStatus;
  686. if (SUCCEEDED(hr))
  687. {
  688. // If we got a valid status, we go ahead and add the adapter to
  689. // the list.
  690. m_listAdapters.insert(m_listAdapters.begin(), nlapair);
  691. }
  692. // Send the initial address status info:
  693. QueueEvent(CONNECTION_STATUS_CHANGE, &guidAdapter, ncsStatus);
  694. QueueEvent(CONNECTION_ADDRESS_CHANGE, &guidAdapter, ncsStatus);
  695. }
  696. else
  697. {
  698. // We found the adapter, so update its status.
  699. GPNLAPAIR& rnlapair = *iter;
  700. if (rnlapair.second.strNetworkName != strAdapter)
  701. {
  702. rnlapair.second.strNetworkName = strAdapter;
  703. }
  704. hr = HrGetPnpDeviceStatus(&guidAdapter, &ncsStatus);
  705. if (SUCCEEDED(hr))
  706. {
  707. if (ncsStatus != rnlapair.second.ncsStatus)
  708. {
  709. // The status is different so we need to send an event to the connections folder.
  710. rnlapair.second.ncsStatus = ncsStatus;
  711. }
  712. // [Deon] We need to always send this as we don't really know what the current
  713. // status of the adapter is. We only know the NLA part.
  714. //
  715. // If we make the above check it could happen somebody else moves the address over
  716. // to NCS_INVALID_ADDRESS and then we don't send the NCS_CONNECTED once it changes.
  717. QueueEvent(CONNECTION_STATUS_CHANGE, &guidAdapter, ncsStatus);
  718. QueueEvent(CONNECTION_ADDRESS_CHANGE, &guidAdapter, ncsStatus);
  719. }
  720. }
  721. if (strAdapter != pszName)
  722. {
  723. // If this adapter is not on the same network, then we need to look at all others and
  724. // ensure that at least 1 is on the same network from which the Group Policies came.
  725. for (GPNLAITER iter = m_listAdapters.begin(); iter != m_listAdapters.end(); iter++)
  726. {
  727. LPCSTR pStr = NULL;
  728. nlapair = *iter;
  729. TraceTag(ttidGPNLA, "Network Name: %S", nlapair.second.strNetworkName);
  730. TraceTag(ttidGPNLA, "Network Status: %s", DbgNcs(nlapair.second.ncsStatus));
  731. if (nlapair.second.strNetworkName == pszName)
  732. {
  733. // Yes, we're still on the network so we need to enforce group policies.
  734. fNetworkMatch = TRUE;
  735. }
  736. }
  737. }
  738. if (fNetworkMatch)
  739. {
  740. break;
  741. }
  742. }
  743. }
  744. // There may be multiple blobs for each interface so make sure we find them all
  745. next = blob->header.nextOffset;
  746. blob = (NLA_BLOB *)(((char *)blob) + next);
  747. } while(next != 0);
  748. }
  749. else
  750. {
  751. TraceTag(ttidGPNLA, "Blob is NULL");
  752. fRet = TRUE;
  753. }
  754. free(wqsResult);
  755. wqsResult = NULL;
  756. }
  757. else
  758. {
  759. if (hr != HRESULT_FROM_WIN32(WSA_E_NO_MORE))
  760. {
  761. TraceError("LookupServiceNext failed\n", hr);
  762. fRet = FALSE;
  763. }
  764. free(wqsResult);
  765. break;
  766. }
  767. }
  768. BOOL fFireRefreshAll = FALSE;
  769. if (bDomainMember)
  770. {
  771. if (!fNoNetwork)
  772. { // We have a Network
  773. if (fNetworkMatch)
  774. {
  775. // Enforce Policies.
  776. if (!m_fSameNetwork)
  777. {
  778. // We are changing the network - we need to refresh all the connectoids in the folder to
  779. // update their icons to reflect policy.
  780. fFireRefreshAll = TRUE;
  781. m_fSameNetwork = TRUE;
  782. }
  783. TraceTag(ttidGPNLA, "Network Match");
  784. }
  785. else
  786. {
  787. // Removed Policy Enforcement.
  788. if (m_fSameNetwork)
  789. {
  790. // We are changing the network - we need to refresh all the connectoids in the folder to
  791. // update their icons to reflect policy.
  792. fFireRefreshAll = TRUE;
  793. m_fSameNetwork = FALSE;
  794. }
  795. TraceTag(ttidGPNLA, "Network does not Match");
  796. }
  797. ReconfigureHomeNet();
  798. }
  799. else
  800. {
  801. // No Networks so don't do anything.
  802. }
  803. }
  804. else // Member of a workgroup
  805. {
  806. m_fSameNetwork = FALSE;
  807. ReconfigureHomeNet();
  808. }
  809. if (HRESULT_FROM_WIN32(WSA_E_NO_MORE) == hr)
  810. {
  811. hr = S_OK;
  812. }
  813. DWORD cbOutBuffer;
  814. if (!m_fShutdown)
  815. {
  816. Reference();
  817. // Wait for Network Change
  818. WSANSPIoctl(m_hQuery, SIO_NSP_NOTIFY_CHANGE,
  819. NULL, 0, NULL, 0, &cbOutBuffer,
  820. &m_wsaCompletion);
  821. if (fFireRefreshAll)
  822. {
  823. LanEventNotify (REFRESH_ALL, NULL, NULL, NULL);
  824. }
  825. }
  826. TraceTag(ttidGPNLA, "Exiting EnumChanges");
  827. return hr;
  828. }
  829. //+---------------------------------------------------------------------------
  830. //
  831. // Member: CGroupPolicyNetworkLocationAwareness::EventHandler
  832. //
  833. // Purpose: Called when NLA changes occur.
  834. //
  835. // Arguments:
  836. // LPVOID pContext - generally the "this" pointer.
  837. // BOOLEAN fTimerFired - if this happened because of a timer or the event
  838. // getting set. Since we specify INFINITE, this is
  839. // not going to get fired by the timer.
  840. // Returns: nothing
  841. //
  842. // Author: sjkhan 20 Feb 2001
  843. //
  844. // Notes:
  845. //
  846. VOID NTAPI CGroupPolicyNetworkLocationAwareness::EventHandler(IN LPVOID pContext, IN BOOLEAN fTimerFired)
  847. {
  848. CGroupPolicyNetworkLocationAwareness* pGPNLA = reinterpret_cast<CGroupPolicyNetworkLocationAwareness*>(pContext);
  849. DWORD dwBytes;
  850. BOOL bSucceeded = GetOverlappedResult(pGPNLA->m_hQuery, &pGPNLA->m_wsaOverlapped, &dwBytes, FALSE);
  851. if (!bSucceeded)
  852. {
  853. TraceError("GetOverlappedResult failed", HrFromLastWin32Error());
  854. }
  855. if (FALSE == fTimerFired && !pGPNLA->m_fShutdown && bSucceeded)
  856. {
  857. pGPNLA->EnumChanges();
  858. }
  859. pGPNLA->Unreference();
  860. if (!bSucceeded)
  861. {
  862. pGPNLA->m_fErrorShutdown = TRUE;
  863. QueueUserWorkItem(ShutdownNlaHandler, pContext, WT_EXECUTEINLONGTHREAD);
  864. }
  865. }
  866. //+---------------------------------------------------------------------------
  867. //
  868. // Member: CGroupPolicyNetworkLocationAwareness::GroupPolicyChange
  869. //
  870. // Purpose: Called when Machine Group Policy changes occur.
  871. //
  872. // Arguments:
  873. // LPVOID pContext - generally the "this" pointer.
  874. // BOOLEAN fTimerFired - if this happened because of a timer or the event
  875. // getting set. Since we specify INFINITE, this is
  876. // not going to get fired by the timer.
  877. // Returns: nothing
  878. //
  879. // Author: sjkhan 05 Feb 2002
  880. //
  881. // Notes:
  882. //
  883. VOID NTAPI CGroupPolicyNetworkLocationAwareness::GroupPolicyChange(IN LPVOID pContext, IN BOOLEAN fTimerFired)
  884. {
  885. TraceTag(ttidGPNLA, "GroupPolicyChange called");
  886. ReconfigureHomeNet(TRUE);
  887. LanEventNotify(REFRESH_ALL, NULL, NULL, NULL);
  888. }
  889. //+---------------------------------------------------------------------------
  890. //
  891. // Member: CGroupPolicyNetworkLocationAwareness::ShutdownNlaHandler
  892. //
  893. // Purpose: Shutdown Nla handler, because Nla service is toast.
  894. //
  895. // Arguments:
  896. //
  897. //
  898. // Returns: nothing
  899. //
  900. // Author: sjkhan 05 Feb 2002
  901. //
  902. // Notes:
  903. //
  904. DWORD WINAPI CGroupPolicyNetworkLocationAwareness::ShutdownNlaHandler(PVOID pThis)
  905. {
  906. TraceFileFunc(ttidGPNLA);
  907. CGroupPolicyNetworkLocationAwareness* pGPNLA =
  908. reinterpret_cast<CGroupPolicyNetworkLocationAwareness*>(InterlockedExchangePointer( (PVOID volatile *) &g_pGPNLA, NULL));
  909. if (pGPNLA)
  910. {
  911. Assert(pGPNLA == pThis); // Making the assumption that the context is always g_pGPNLA, since I'm clearing g_pGPNLA.
  912. pGPNLA->Uninitialize();
  913. delete pGPNLA;
  914. }
  915. return 0;
  916. }
  917. //+---------------------------------------------------------------------------
  918. //
  919. // Function: ReconfigureHomeNet
  920. //
  921. // Purpose: Change Homenet Configuration
  922. //
  923. // Arguments:
  924. // fWaitUntilRunningOrStopped - if the caller should wait for the
  925. // service to start, or to fail starting
  926. // and stop.
  927. //
  928. // Returns: HRESULT indicating success of failure
  929. //
  930. // Author: sjkhan 09 Dec 2000
  931. //
  932. // Notes:
  933. //
  934. //
  935. //
  936. //
  937. HRESULT CGroupPolicyNetworkLocationAwareness::ReconfigureHomeNet(BOOL fWaitUntilRunningOrStopped)
  938. {
  939. SC_HANDLE hscManager;
  940. SC_HANDLE hService;
  941. SERVICE_STATUS ServiceStatus;
  942. if (0 != InterlockedExchange(&m_lBusyWithReconfigure, 1L))
  943. {
  944. return S_FALSE;
  945. }
  946. TraceTag(ttidGPNLA, "Entering ReconfigureHomeNet");
  947. hscManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
  948. if (hscManager)
  949. {
  950. TraceTag(ttidGPNLA, "Attempting to open service");
  951. hService = OpenService(hscManager, L"SharedAccess", SERVICE_QUERY_STATUS | SERVICE_USER_DEFINED_CONTROL);
  952. if (hService)
  953. {
  954. DWORD dwCount = 0;
  955. SERVICE_STATUS SvcStatus = {0};
  956. BOOL fRet;
  957. if (fWaitUntilRunningOrStopped)
  958. {
  959. do
  960. {
  961. if (!QueryServiceStatus(hService, &SvcStatus))
  962. {
  963. break;
  964. }
  965. if (SERVICE_START_PENDING == SvcStatus.dwCurrentState)
  966. {
  967. TraceTag(ttidGPNLA, "Service is still starting. Waiting 5 seconds.");
  968. Sleep(5000); // Sleep 5 seconds;
  969. }
  970. } while ((SERVICE_START_PENDING == SvcStatus.dwCurrentState) && ++dwCount <= 6);
  971. }
  972. if (!fWaitUntilRunningOrStopped || (SERVICE_RUNNING == SvcStatus.dwCurrentState))
  973. {
  974. fRet = ControlService(hService, IPNATHLP_CONTROL_UPDATE_CONNECTION, &ServiceStatus);
  975. if (!fRet)
  976. {
  977. DWORD dwErr = GetLastError();
  978. TraceError("Control Service returned: 0x%x", HRESULT_FROM_WIN32(dwErr));
  979. }
  980. else
  981. {
  982. TraceTag(ttidGPNLA, "Requested Reconfiguration check from ICF/ICS");
  983. }
  984. }
  985. CloseServiceHandle(hService);
  986. }
  987. else
  988. {
  989. TraceTag(ttidGPNLA, "Could not open service");
  990. }
  991. CloseServiceHandle(hscManager);
  992. }
  993. TraceTag(ttidGPNLA, "Leaving ReconfigureHomeNet");
  994. InterlockedExchange(&m_lBusyWithReconfigure, 0L);
  995. return S_OK;
  996. }