Leaked source code of windows server 2003
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.

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