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.

4215 lines
127 KiB

  1. /*++
  2. Copyright(c) 1999-2002 Microsoft Corporation
  3. Module Name:
  4. brdggpo.c
  5. Abstract:
  6. Ethernet MAC level bridge.
  7. Group Policy code for Network Bridge.
  8. Author:
  9. Salahuddin J. Khan (sjkhan)
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. April 2002 - Original version
  14. --*/
  15. #define NDIS_MINIPORT_DRIVER
  16. #define NDIS50_MINIPORT 1
  17. #define NDIS_WDM 1
  18. #pragma warning( push, 3 )
  19. #include <ndis.h>
  20. #include <tdikrnl.h>
  21. #include <ntstatus.h>
  22. #include <wchar.h>
  23. #pragma warning( pop )
  24. #include "bridge.h"
  25. #include "brdggpo.h"
  26. #include "brdgsta.h"
  27. #include "brdgmini.h"
  28. #include "brdgprot.h"
  29. #include "brdgbuf.h"
  30. #include "brdgfwd.h"
  31. #include "brdgtbl.h"
  32. #include "brdgctl.h"
  33. #include "brdgtdi.h"
  34. // ===========================================================================
  35. //
  36. // GLOBALS
  37. //
  38. // ===========================================================================
  39. BRDG_GPO_GLOBALS g_BrdgGpoGlobals;
  40. // ===========================================================================
  41. //
  42. // CONSTANTS
  43. //
  44. // ===========================================================================
  45. const WCHAR HiveListKey[] = {L"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\CONTROL\\HIVELIST"};
  46. const WCHAR SoftwareHiveKey[] = {L"\\REGISTRY\\MACHINE\\SOFTWARE"};
  47. const WCHAR PolicyBaseKey[] = {L"\\Registry\\Machine\\SOFTWARE\\Policies\\Microsoft\\Windows"};
  48. const WCHAR NetworkPoliciesKey[] = {L"\\Registry\\Machine\\SOFTWARE\\Policies\\Microsoft\\Windows\\Network Connections"};
  49. const WCHAR GroupPolicyKey[] = {L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Group Policy"};
  50. const WCHAR BridgePolicyValue[] = {L"NC_AllowNetBridge_NLA"};
  51. const WCHAR TcpipInterfacesKey[] = {L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"};
  52. const WCHAR HistoryKey[] = {L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Group Policy\\History"};
  53. // ===========================================================================
  54. //
  55. // PRIVATE PROTOTYPES
  56. //
  57. // ===========================================================================
  58. VOID
  59. static
  60. BrdgGpoRegNotify(
  61. IN PVOID Context
  62. );
  63. NTSTATUS
  64. BrdgGpoBuildNotifyForRegKeyChange(
  65. IN PBRDG_GPO_NOTIFY_KEY Notify,
  66. IN LPWSTR Identifier,
  67. IN LPWSTR RegKeyName,
  68. IN LPWSTR RegValueName,
  69. IN PWORKER_THREAD_ROUTINE ApcRoutine,
  70. IN PVOID ApcContext,
  71. IN ULONG CompletionFilter,
  72. IN BOOLEAN WatchTree,
  73. IN PBRDG_GPO_REG_CALLBACK FunctionCallback,
  74. IN BOOLEAN Recurring,
  75. IN PBOOLEAN SuccessfulRegistration,
  76. IN PBRDG_GPO_REGISTER FunctionRegister);
  77. NTSTATUS
  78. BrdgGpoRegisterForRegKeyChange(
  79. IN PBRDG_GPO_NOTIFY_KEY Notify);
  80. NTSTATUS
  81. BrdgGpoRequestNotification(
  82. IN PBRDG_GPO_NOTIFY_KEY Notify);
  83. VOID
  84. BrdgGpoProcessNotifications(
  85. IN PVOID Context);
  86. PLIST_ENTRY
  87. BrdgGpoGetNotifyListHead();
  88. PKEVENT
  89. BrdgGpoGetNotifyEvent();
  90. PKEVENT
  91. BrdgGpoGetKillEvent();
  92. PNDIS_RW_LOCK
  93. BrdgGpoGetNotifyListLock();
  94. NTSTATUS
  95. BrdgGpoFindNotify(
  96. IN PLIST_ENTRY ListHead,
  97. IN PNDIS_RW_LOCK ListLock,
  98. IN LPWSTR Identifier,
  99. OUT PBRDG_GPO_NOTIFY_KEY* Notify
  100. );
  101. NTSTATUS
  102. BrdgGpoInitializeNotifyList(
  103. OUT PLIST_ENTRY* ListHead,
  104. OUT PNDIS_RW_LOCK* ListLock,
  105. OUT PKEVENT* WaitEvent,
  106. OUT PKEVENT* KillEvent);
  107. VOID
  108. BrdgGpoFreeNotifyList();
  109. BOOLEAN
  110. BrdgGpoAllowedToBridge();
  111. VOID
  112. BrdgGpoUpdateBridgeMode(
  113. BOOLEAN NetworkMatch);
  114. VOID
  115. BrdgGpoCheckForMatchAndUpdateMode();
  116. NTSTATUS
  117. BrdgGpoRegisterForGroupPolicyNetworkNameNotification();
  118. NTSTATUS
  119. BrdgGpoRegisterForWindowsGroupPolicyNotification();
  120. NTSTATUS
  121. BrdgGpoRegisterForNetworkConnectionsGroupPolicyNotification();
  122. NTSTATUS
  123. BrdgGpoRegisterForGroupPolicyNotification();
  124. VOID
  125. BrdgGpoRegisterForHiveListNotification();
  126. NTSTATUS
  127. BrdgGpoAllocateAndInitializeNotifyStruct(
  128. OUT PBRDG_GPO_NOTIFY_KEY* Notify);
  129. NTSTATUS
  130. BrdgGpoUpdateGroupPolicyNetworkName();
  131. VOID
  132. BrdgGpoFreeNotifyStructAndData(
  133. IN PBRDG_GPO_NOTIFY_KEY Notify);
  134. BOOLEAN
  135. BrdgGpoWaitingOnSoftwareHive();
  136. //
  137. // We need this if the regkey for Network Connections Group Policy doesn't exist yet.
  138. //
  139. VOID
  140. BrdgGpoWindowsGroupPolicyChangeCallback(
  141. IN PBRDG_GPO_NOTIFY_KEY Notify);
  142. VOID
  143. BrdgGpoNetworkConnectionsGroupPolicyChangeCallback(
  144. IN PBRDG_GPO_NOTIFY_KEY Notify);
  145. VOID
  146. BrdgGpoGroupPolicyChangeCallback(
  147. IN PBRDG_GPO_NOTIFY_KEY Notify);
  148. VOID
  149. BrdgGpoTcpipInterfacesChangeCallback(
  150. IN PBRDG_GPO_NOTIFY_KEY Notify);
  151. VOID
  152. BrdgGpoGroupPolicyNetworkNameChangeCallback(
  153. IN PBRDG_GPO_NOTIFY_KEY Notify);
  154. VOID
  155. BrdgGpoHiveListCallback(
  156. IN PBRDG_GPO_NOTIFY_KEY Notify);
  157. VOID
  158. BrdgGpoQueryNetworkConnectionsValue(
  159. IN PBRDG_GPO_NOTIFY_KEY Notify);
  160. VOID
  161. BrdgGpoQueryTcpipInterfacesValues(
  162. IN PBRDG_GPO_NOTIFY_KEY Notify);
  163. VOID
  164. BrdgGpoQueryGroupPolicyNetworkName(
  165. IN PBRDG_GPO_NOTIFY_KEY Notify);
  166. // ===========================================================================
  167. //
  168. // BRIDGE GPO IMPLEMENTATION
  169. //
  170. // ===========================================================================
  171. #ifdef ALLOC_PRAGMA
  172. #pragma alloc_text(PAGELK, BrdgGpoRegNotify)
  173. #endif
  174. NTSTATUS
  175. BrdgGpoDriverInit()
  176. /*++
  177. Routine Description:
  178. Driver load-time initialization
  179. Return Value:
  180. Status of initialization
  181. Locking Constraints:
  182. Top-level function. Assumes no locks are held by caller.
  183. --*/
  184. {
  185. NTSTATUS status;
  186. HANDLE ThreadHandle;
  187. DBGPRINT(GPO, ("BrdgGpoDriverInit\r\n"));
  188. g_BrdgGpoGlobals.GroupPolicyNetworkName.Buffer = NULL;
  189. status = BrdgGpoInitializeNetworkList();
  190. if (!NT_SUCCESS(status))
  191. {
  192. DBGPRINT(GPO, ("Unable to initialize Network List\r\n"));
  193. goto cleanup;
  194. }
  195. status = BrdgGpoInitializeNotifyList( &g_BrdgGpoGlobals.QueueInfo.NotifyList,
  196. &g_BrdgGpoGlobals.QueueInfo.NotifyListLock,
  197. &g_BrdgGpoGlobals.QueueInfo.NotifyEvent,
  198. &g_BrdgGpoGlobals.QueueInfo.KillEvent);
  199. if (!NT_SUCCESS(status))
  200. {
  201. DBGPRINT(GPO, ("Unable to initialize Notify List\r\n"));
  202. goto cleanup;
  203. }
  204. //
  205. // Since the Software hive is not up at this point, we use this to make sure we only register for
  206. // Group Policy changes once (we'll handle this in the Add Address notification, since the software
  207. // hive is up by the time this gets called. Will check with reg guys to see if there's a way to know
  208. // when the software hive is up. We'll use the timer to re-attempt the registration until it is up.
  209. //
  210. g_BrdgGpoGlobals.NotificationsThread = NULL;
  211. g_BrdgGpoGlobals.RegisteredForGroupPolicyChanges = FALSE;
  212. g_BrdgGpoGlobals.WaitingOnSoftwareHive = TRUE;
  213. // Create a thread for handling the notifications.
  214. status = PsCreateSystemThread( &ThreadHandle,
  215. THREAD_ALL_ACCESS,
  216. NULL,
  217. NULL,
  218. NULL,
  219. BrdgGpoProcessNotifications,
  220. &g_BrdgGpoGlobals.QueueInfo);
  221. if (!NT_SUCCESS(status))
  222. {
  223. DBGPRINT(GPO, ("Unable to created Notification Processing thread\r\n"));
  224. goto cleanup;
  225. }
  226. // Retrieve a pointer to the thread object and reference it so we can wait for
  227. // its termination safely.
  228. status = ObReferenceObjectByHandle( ThreadHandle, STANDARD_RIGHTS_ALL, NULL, KernelMode,
  229. &g_BrdgGpoGlobals.NotificationsThread, NULL );
  230. if (!NT_SUCCESS(status))
  231. {
  232. DBGPRINT(GPO, ("Unable to reference thread handle\r\n"));
  233. goto cleanup;
  234. }
  235. cleanup:
  236. if (!NT_SUCCESS(status))
  237. {
  238. BrdgGpoCleanup();
  239. }
  240. return status;
  241. }
  242. VOID
  243. BrdgGpoCleanup()
  244. /*++
  245. Routine Description:
  246. Driver shutdown cleanup
  247. Return Value:
  248. None
  249. Locking Constraints:
  250. Top-level function. Assumes no locks are held by caller.
  251. --*/
  252. {
  253. NTSTATUS status;
  254. PNPAGED_LOOKASIDE_LIST LookasideQueueList;
  255. LOCK_STATE LockState;
  256. PLIST_ENTRY pListEntry;
  257. PNDIS_RW_LOCK ListLock;
  258. PLIST_ENTRY ListHead;
  259. PLIST_ENTRY QueuedList;
  260. PBRDG_GPO_QUEUED_NOTIFY QueuedNotify;
  261. DBGPRINT(GPO, ("BrdgGpoCleanup\r\n"));
  262. g_BrdgGpoGlobals.ProcessingNotifications = FALSE;
  263. LookasideQueueList = ExAllocatePoolWithTag(NonPagedPool, sizeof(NPAGED_LOOKASIDE_LIST), 'gdrB');
  264. if (NULL == LookasideQueueList)
  265. {
  266. return;
  267. }
  268. QueuedList = ExAllocatePoolWithTag(NonPagedPool, sizeof(LIST_ENTRY), 'gdrB');
  269. if (NULL == QueuedList)
  270. {
  271. ExFreePool(LookasideQueueList);
  272. return;
  273. }
  274. ListHead = BrdgGpoGetNotifyListHead();
  275. ListLock = BrdgGpoGetNotifyListLock();
  276. ExInitializeNPagedLookasideList(LookasideQueueList,
  277. NULL,
  278. NULL,
  279. 0,
  280. sizeof(BRDG_GPO_QUEUED_NOTIFY),
  281. 'grbQ',
  282. 0);
  283. InitializeListHead(QueuedList);
  284. DBGPRINT(GPO, ("Acquiring Read-Write Lock and clearing list\r\n"));
  285. //
  286. // We use a temporary list to close each key, since we can't close them at
  287. // DISPATCH_LEVEL
  288. //
  289. NdisAcquireReadWriteLock(ListLock, TRUE /* Write-access */, &LockState);
  290. //
  291. // Loop through the list of notifications that we have.
  292. //
  293. for (pListEntry = ListHead->Flink; pListEntry != ListHead; pListEntry = pListEntry->Flink)
  294. {
  295. PBRDG_GPO_NOTIFY_KEY Notify;
  296. Notify = CONTAINING_RECORD(pListEntry, BRDG_GPO_NOTIFY_KEY, ListEntry);
  297. //
  298. // We're going to be shutting this down soon, so block it now
  299. // so that no-one else can increment this.
  300. //
  301. BrdgBlockWaitRef(&Notify->RefCount);
  302. //
  303. // We don't want any notifications the fire to run either.
  304. //
  305. Notify->Recurring = FALSE;
  306. QueuedNotify = ExAllocateFromNPagedLookasideList(LookasideQueueList);
  307. QueuedNotify->Notify = Notify;
  308. InsertTailList(QueuedList, &QueuedNotify->ListEntry);
  309. }
  310. while (!IsListEmpty(ListHead))
  311. {
  312. //
  313. // We'll be freeing this from our sencondary list.
  314. //
  315. pListEntry = RemoveHeadList(ListHead);
  316. }
  317. NdisReleaseReadWriteLock(ListLock, &LockState);
  318. DBGPRINT(GPO, ("Closing and Freeing Notifications\r\n"));
  319. //
  320. // We're back at PASSIVE_LEVEL so we can now do the registration for the changes.
  321. //
  322. for (pListEntry = QueuedList->Flink; pListEntry != QueuedList; pListEntry = pListEntry->Flink)
  323. {
  324. HANDLE hKey;
  325. PBRDG_GPO_NOTIFY_KEY Notify;
  326. QueuedNotify = CONTAINING_RECORD(pListEntry, BRDG_GPO_QUEUED_NOTIFY, ListEntry);
  327. Notify = QueuedNotify->Notify;
  328. DBGPRINT(GPO, ("Closing Regkey and Freeing Notification: %S\r\n", Notify->Identifier.Buffer));
  329. hKey = Notify->RegKey;
  330. Notify->RegKey = NULL;
  331. if (hKey)
  332. {
  333. ZwClose(hKey);
  334. }
  335. DBGPRINT(GPO, ("Refcount for %S \t-\t %d\r\n", Notify->Identifier.Buffer, Notify->RefCount.Refcount));
  336. //
  337. // Since we're freeing this notification, we decrement the refcount
  338. //
  339. BrdgDecrementWaitRef(&Notify->RefCount);
  340. //
  341. // This will block until the ref count is zero. Any attempts to increment the waitref will
  342. // fail.
  343. //
  344. BrdgShutdownWaitRef(&Notify->RefCount);
  345. //
  346. // We NULL these out so that the free routine below doesn't try to remove us from
  347. // the notify list.
  348. //
  349. QueuedNotify->Notify->ListEntry.Blink = NULL;
  350. QueuedNotify->Notify->ListEntry.Flink = NULL;
  351. //
  352. // Free the data associated with this struct, and the struct itself.
  353. //
  354. BrdgGpoFreeNotifyStructAndData(QueuedNotify->Notify);
  355. }
  356. //
  357. // Free the temporary list.
  358. //
  359. while (!IsListEmpty(QueuedList))
  360. {
  361. pListEntry = RemoveHeadList(QueuedList);
  362. QueuedNotify = CONTAINING_RECORD(pListEntry, BRDG_GPO_QUEUED_NOTIFY, ListEntry);
  363. ExFreeToNPagedLookasideList(LookasideQueueList, QueuedNotify);
  364. }
  365. if (g_BrdgGpoGlobals.NotificationsThread)
  366. {
  367. //
  368. // Set the Event to kill the thread so that the notifications are no longer waiting.
  369. //
  370. KeSetEvent(BrdgGpoGetKillEvent(), EVENT_INCREMENT, TRUE);
  371. status = KeWaitForSingleObject(g_BrdgGpoGlobals.NotificationsThread, Executive, KernelMode, TRUE, NULL);
  372. KeLowerIrql(0);
  373. //
  374. // De-reference the thread handle to allow the thread to be destroyed.
  375. //
  376. ObDereferenceObject(g_BrdgGpoGlobals.NotificationsThread);
  377. SAFEASSERT(NT_SUCCESS(status));
  378. }
  379. DBGPRINT(GPO, ("Freeing List structures\r\n"));
  380. ExDeleteNPagedLookasideList(LookasideQueueList);
  381. ExFreePool(LookasideQueueList);
  382. ExFreePool(QueuedList);
  383. //
  384. // Free any remaining data.
  385. //
  386. if (NULL != g_BrdgGpoGlobals.GroupPolicyNetworkName.Buffer)
  387. {
  388. ExFreePool(g_BrdgGpoGlobals.GroupPolicyNetworkName.Buffer);
  389. }
  390. status = BrdgGpoEmptyNetworkList(g_BrdgGpoGlobals.ListHeadNetworks, g_BrdgGpoGlobals.NetworkListLock);
  391. SAFEASSERT(NT_SUCCESS(status));
  392. if (g_BrdgGpoGlobals.ListHeadNetworks)
  393. {
  394. ExFreePool(g_BrdgGpoGlobals.ListHeadNetworks);
  395. }
  396. if (g_BrdgGpoGlobals.NetworkListLock)
  397. {
  398. ExFreePool(g_BrdgGpoGlobals.NetworkListLock);
  399. }
  400. BrdgGpoFreeNotifyList();
  401. DBGPRINT(GPO, ("BrdgGpoCleanup complete\r\n"));
  402. }
  403. BOOLEAN
  404. BrdgGpoWaitingOnSoftwareHive()
  405. {
  406. return g_BrdgGpoGlobals.WaitingOnSoftwareHive;
  407. }
  408. NTSTATUS
  409. BrdgGpoRegisterForAdapterAddressChangeNotification(
  410. IN LPWSTR NetworkIdentifier,
  411. IN LPWSTR RegKeyName)
  412. {
  413. NTSTATUS status;
  414. PBRDG_GPO_NOTIFY_KEY Notify;
  415. status = BrdgGpoFindNotify( BrdgGpoGetNotifyListHead(),
  416. BrdgGpoGetNotifyListLock(),
  417. NetworkIdentifier,
  418. &Notify);
  419. if (NT_SUCCESS(status) && (STATUS_OBJECT_NAME_EXISTS != status))
  420. {
  421. UNICODE_STRING RegKey;
  422. RtlInitUnicodeString(&RegKey, RegKeyName);
  423. if ((STATUS_OBJECT_NAME_EXISTS != status) && NT_SUCCESS(status))
  424. {
  425. status = BrdgGpoAllocateAndInitializeNotifyStruct(&Notify);
  426. if (NT_SUCCESS(status))
  427. {
  428. Notify->Recurring = TRUE;
  429. status = BrdgGpoBuildNotifyForRegKeyChange( Notify,
  430. NetworkIdentifier,
  431. RegKeyName,
  432. L"DhcpDomain",
  433. BrdgGpoRegNotify,
  434. (PVOID)(UINT_PTR)(unsigned int)DelayedWorkQueue,
  435. REG_NOTIFY_CHANGE_LAST_SET,
  436. FALSE,
  437. BrdgGpoTcpipInterfacesChangeCallback,
  438. TRUE,
  439. NULL,
  440. NULL);
  441. }
  442. }
  443. }
  444. if (NT_SUCCESS(status))
  445. {
  446. SAFEASSERT(Notify);
  447. status = BrdgGpoRequestNotification(Notify);
  448. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  449. {
  450. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  451. {
  452. BrdgDecrementWaitRef(&Notify->RefCount);
  453. BrdgGpoFreeNotifyStructAndData(Notify);
  454. Notify = NULL;
  455. }
  456. }
  457. else if (!NT_SUCCESS(status))
  458. {
  459. BrdgGpoFreeNotifyStructAndData(Notify);
  460. Notify = NULL;
  461. }
  462. #if DBG
  463. if (Notify)
  464. {
  465. SAFEASSERT(Notify->ListEntry.Blink && Notify->ListEntry.Flink);
  466. }
  467. #endif
  468. }
  469. return status;
  470. }
  471. NTSTATUS
  472. BrdgGpoNewAddressNotification(
  473. IN PWSTR DeviceId
  474. )
  475. /*++
  476. Routine Description:
  477. Called when a our TDI AddAddress handler receives a new IP Address.
  478. Arguments:
  479. DeviceID - GUID Identifying the adapter
  480. Return Value:
  481. NTSTATUS - Possible values include:
  482. STATUS_INSUFFICIENT_RESOURCES (not enough memory)
  483. STATUS_SUCCESS
  484. Locking Constraints:
  485. Top-level function. Assumes no locks are held by caller.
  486. --*/
  487. {
  488. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  489. DBGPRINT(GPO, ("BrdgGpoNewAddressNotification\r\n"));
  490. if (FALSE == g_BrdgGpoGlobals.RegisteredForGroupPolicyChanges)
  491. {
  492. BrdgGpoRegisterForHiveListNotification();
  493. BrdgGpoRegisterForGroupPolicyNotification();
  494. BrdgGpoRegisterForGroupPolicyNetworkNameNotification();
  495. BrdgGpoRegisterForWindowsGroupPolicyNotification();
  496. BrdgGpoRegisterForNetworkConnectionsGroupPolicyNotification();
  497. g_BrdgGpoGlobals.RegisteredForGroupPolicyChanges = TRUE;
  498. }
  499. DBGPRINT(GPO, ("Device: %S\r\n", DeviceId));
  500. if (NULL != DeviceId)
  501. {
  502. PBRDG_GPO_NETWORKS Network = NULL;
  503. UNICODE_STRING RegKey;
  504. PWCHAR NetworkIdentifier = NULL;
  505. PWCHAR RegNetworkName = NULL;
  506. PWCHAR NetworkName = NULL;
  507. ULONG NetworkNameLen = 0;
  508. PWCHAR RegString = NULL;
  509. status = ( NdisAllocateMemoryWithTag( &RegString,
  510. ((UINT)wcslen(TcpipInterfacesKey) + 1 + (UINT)wcslen(DeviceId) + 1) * sizeof(WCHAR),
  511. 'gdrB'));
  512. if (NT_SUCCESS(status))
  513. {
  514. wcscpy(RegString, TcpipInterfacesKey);
  515. wcscat(RegString, L"\\");
  516. wcsncat(RegString, DeviceId, MAX_GUID_LEN - 1);
  517. NetworkIdentifier = DeviceId;
  518. RtlInitUnicodeString(&RegKey, RegString);
  519. status = BrdgReadRegUnicode(&RegKey,
  520. L"DhcpDomain",
  521. &RegNetworkName,
  522. &NetworkNameLen);
  523. if (!NT_SUCCESS(status) || (0 == NetworkNameLen))
  524. {
  525. //
  526. // Either we didn't get a network name back, or the name is blank.
  527. // in both cases we go to the ipaddress and subnetmask to determine
  528. // the network that we're on.
  529. // We AND the two together to get this.
  530. // For example: Address: 10.251.1.3 Subnet: 255.0.0.0 gives us a
  531. // network of: 10.0.0.0
  532. //
  533. status = BrdgGpoGetCurrentNetwork(&RegKey, &RegNetworkName);
  534. }
  535. if (NT_SUCCESS(status))
  536. {
  537. ULONG NetworkNameByteLen =(ULONG) ((wcslen(RegNetworkName) + 1) * sizeof(WCHAR));
  538. //
  539. // Copy the network name from the reg into a NonPagedPool string
  540. // (since it will be accessed at DISPATCH_LEVEL)
  541. //
  542. NetworkName = ExAllocatePoolWithTag(NonPagedPool, NetworkNameByteLen, 'gdrB');
  543. if(NetworkName)
  544. {
  545. RtlZeroMemory(NetworkName, NetworkNameByteLen);
  546. RtlCopyMemory(NetworkName, RegNetworkName, NetworkNameByteLen);
  547. }
  548. //
  549. // Check if we match the current GP network.
  550. //
  551. if ((0 != g_BrdgGpoGlobals.GroupPolicyNetworkName.Length) &&
  552. (NULL != g_BrdgGpoGlobals.GroupPolicyNetworkName.Buffer))
  553. {
  554. if(_wcsicmp(g_BrdgGpoGlobals.GroupPolicyNetworkName.Buffer, NetworkName) == 0)
  555. {
  556. //
  557. // We do match the network.
  558. //
  559. BrdgGpoUpdateBridgeMode(BRDG_ON_SAME_NETWORK);
  560. }
  561. else
  562. {
  563. //
  564. // No, we're not, so look at other adapters
  565. //
  566. BrdgGpoCheckForMatchAndUpdateMode();
  567. }
  568. }
  569. else
  570. {
  571. //
  572. // We don't have a Group Policy network.
  573. //
  574. BrdgGpoUpdateBridgeMode(BRDG_ON_DIFFERENT_NETWORK);
  575. }
  576. status = BrdgGpoAllocateAndInitializeNetwork( &Network,
  577. NetworkIdentifier,
  578. RegNetworkName);
  579. if (NT_SUCCESS(status))
  580. {
  581. //
  582. // We first try to insert the Network into the list
  583. //
  584. status = BrdgGpoInsertNetwork( g_BrdgGpoGlobals.ListHeadNetworks,
  585. &Network->ListEntry,
  586. g_BrdgGpoGlobals.NetworkListLock);
  587. if (STATUS_DUPLICATE_NAME == status)
  588. {
  589. UNICODE_STRING Identifier;
  590. //
  591. // This Network already exists in the list, so we free it update the
  592. // NetworkName in the existing entry.
  593. //
  594. BrdgGpoFreeNetworkAndData(Network);
  595. Network = NULL;
  596. RtlInitUnicodeString(&Identifier, NetworkIdentifier);
  597. status = BrdgGpoUpdateNetworkName( g_BrdgGpoGlobals.ListHeadNetworks,
  598. &Identifier,
  599. NetworkName,
  600. g_BrdgGpoGlobals.NetworkListLock);
  601. }
  602. else if (!NT_SUCCESS(status))
  603. {
  604. BrdgGpoFreeNetworkAndData(Network);
  605. Network = NULL;
  606. }
  607. }
  608. //
  609. // We've made a copy of this, so let's free it.
  610. //
  611. NdisFreeMemory(RegNetworkName, NetworkNameLen, 0);
  612. }
  613. if (NetworkName)
  614. {
  615. ExFreePool(NetworkName);
  616. }
  617. if (NT_SUCCESS(status))
  618. {
  619. status = BrdgGpoRegisterForAdapterAddressChangeNotification(NetworkIdentifier,
  620. RegString);
  621. }
  622. #if DBG
  623. if (Network)
  624. {
  625. SAFEASSERT(Network->ListEntry.Blink && Network->ListEntry.Flink);
  626. }
  627. #endif
  628. NdisFreeMemory(RegString, (UINT)wcslen(RegString) + 1, 0);
  629. }
  630. }
  631. return status;
  632. }
  633. // ===========================================================================
  634. //
  635. // REGISTRY CHANGE NOTIFICATION FUNCTIONS
  636. //
  637. // ===========================================================================
  638. __forceinline
  639. PLIST_ENTRY
  640. BrdgGpoGetNotifyListHead()
  641. /*++
  642. Routine Description:
  643. Arguments:
  644. None.
  645. Return Value:
  646. Returns a pointer to the head of the Notifications List.
  647. --*/
  648. {
  649. return g_BrdgGpoGlobals.QueueInfo.NotifyList;
  650. }
  651. __forceinline
  652. PKEVENT
  653. BrdgGpoGetNotifyEvent()
  654. /*++
  655. Routine Description:
  656. Arguments:
  657. None.
  658. Return Value:
  659. Returns a pointer to the Event used for signaling the Processing
  660. Thread to start processing notification requests.
  661. --*/
  662. {
  663. return g_BrdgGpoGlobals.QueueInfo.NotifyEvent;
  664. }
  665. __forceinline
  666. PKEVENT
  667. BrdgGpoGetKillEvent()
  668. /*++
  669. Routine Description:
  670. Arguments:
  671. Return Value:
  672. Returns a pointer to the Event used for signaling the Processing
  673. Thread to exit.
  674. --*/
  675. {
  676. return g_BrdgGpoGlobals.QueueInfo.KillEvent;
  677. }
  678. __forceinline
  679. PNDIS_RW_LOCK
  680. BrdgGpoGetNotifyListLock()
  681. /*++
  682. Routine Description:
  683. Arguments:
  684. Return Value:
  685. Returns a pointer to the Read-Write lock that protects the
  686. notification request list.
  687. --*/
  688. {
  689. return g_BrdgGpoGlobals.QueueInfo.NotifyListLock;
  690. }
  691. __forceinline
  692. BOOLEAN
  693. BrdgGpoProcessingNotifications()
  694. /*++
  695. Routine Description:
  696. Arguments:
  697. Return Value:
  698. TRUE - We're still processing Notifications (ie. we're not shutting down).
  699. FALSE - We're shutting down, don't add anything else to the list.
  700. --*/
  701. {
  702. return g_BrdgGpoGlobals.ProcessingNotifications;
  703. }
  704. NTSTATUS
  705. BrdgGpoFindNotify(
  706. IN PLIST_ENTRY ListHead,
  707. IN PNDIS_RW_LOCK ListLock,
  708. IN LPWSTR Identifier,
  709. OUT PBRDG_GPO_NOTIFY_KEY* Notify
  710. )
  711. /*++
  712. Routine Description:
  713. Since we don't want to have duplicate Notifications in the list,
  714. this function is used to find an existing item if has already been added.
  715. Arguments:
  716. ListHead - Pointer to the head of a Notifications list.
  717. ListLock - Read-Write lock for protecting the list.
  718. Identifier - A unique identifier associated with the item. For NICs this is the
  719. GUID assigned to the NIC. For other items like the Group Policies,
  720. it is just a name we assign for example: "GroupPolicyNetworkName".
  721. Notify - An out param the contains either a pointer to the Notify we found,
  722. or NULL if we didn't find a matching entry.
  723. Return Value:
  724. STATUS_SUCCESS We didn't find a matching entry.
  725. STATUS_OBJECT_NAME_EXISTS We found a match, so we'll use that instead
  726. of allocating a new item.
  727. --*/
  728. {
  729. NTSTATUS status = STATUS_SUCCESS;
  730. LOCK_STATE LockState;
  731. PLIST_ENTRY pListEntry;
  732. if (NULL != Notify)
  733. {
  734. *Notify = NULL;
  735. }
  736. if (NULL == ListHead ||
  737. NULL == ListLock ||
  738. NULL == Identifier ||
  739. NULL == Notify
  740. )
  741. {
  742. return STATUS_INVALID_PARAMETER;
  743. }
  744. BrdgGpoAcquireNetworkListLock(ListLock, FALSE /* Read */, &LockState);
  745. for (pListEntry = ListHead->Flink; pListEntry != ListHead; pListEntry = pListEntry->Flink)
  746. {
  747. PBRDG_GPO_NOTIFY_KEY CurrentNotify;
  748. CurrentNotify = CONTAINING_RECORD(pListEntry, BRDG_GPO_NOTIFY_KEY, ListEntry);
  749. if ((CurrentNotify->Identifier.Buffer) &&
  750. (0 == _wcsicmp(CurrentNotify->Identifier.Buffer, Identifier)))
  751. {
  752. *Notify = CurrentNotify;
  753. status = STATUS_OBJECT_NAME_EXISTS;
  754. break;
  755. }
  756. }
  757. BrdgGpoReleaseNetworkListLock(ListLock, &LockState);
  758. return status;
  759. }
  760. NTSTATUS
  761. BrdgGpoInitializeNotifyList(
  762. OUT PLIST_ENTRY* ListHead,
  763. OUT PNDIS_RW_LOCK* ListLock,
  764. OUT PKEVENT* WaitEvent,
  765. OUT PKEVENT* KillEvent)
  766. /*++
  767. Routine Description:
  768. Initializes the Notifications List and associated objects.
  769. Arguments:
  770. ListHead - [OUT] Pointer to the list head that we'll allocate.
  771. ListLock - [OUT] Pointer to the Read-Write lock that we'll allocate.
  772. WaitEvent - [OUT] Pointer to the WaitEvent we'll allocate
  773. KillEvent - [OUT] Pointer to the KillEvent we'll allocate
  774. Return Value:
  775. STATUS_INSUFFICIENT_RESOURCES (unable to allocate everything).
  776. STATUS_INVALID_PARAMETER (we were passed a NULL pointer to a pointer).
  777. STATUS_SUCCESS (we were able to allocate everything successfully).
  778. --*/
  779. {
  780. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  781. PLIST_ENTRY pListHead;
  782. PNDIS_RW_LOCK pListLock;
  783. PKEVENT pWaitEvent;
  784. PKEVENT pKillEvent;
  785. if (NULL == ListHead ||
  786. NULL == ListLock ||
  787. NULL == WaitEvent ||
  788. NULL == KillEvent)
  789. {
  790. return STATUS_INVALID_PARAMETER;
  791. }
  792. *ListHead = NULL;
  793. *ListLock = NULL;
  794. *WaitEvent = NULL;
  795. *KillEvent = NULL;
  796. pListHead = NULL;
  797. pListLock = NULL;
  798. pWaitEvent = NULL;
  799. pKillEvent = NULL;
  800. pListHead = ExAllocatePoolWithTag(NonPagedPool, sizeof(LIST_ENTRY), 'gdrB');
  801. if (pListHead)
  802. {
  803. InitializeListHead(pListHead);
  804. pListLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(NDIS_RW_LOCK), 'gdrB');
  805. if (pListLock)
  806. {
  807. NdisInitializeReadWriteLock(pListLock);
  808. pWaitEvent = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), 'gdrB');
  809. if (pWaitEvent)
  810. {
  811. KeInitializeEvent(pWaitEvent, SynchronizationEvent, FALSE);
  812. pKillEvent = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), 'gdrB');
  813. if (pKillEvent)
  814. {
  815. KeInitializeEvent(pKillEvent, SynchronizationEvent, FALSE);
  816. *ListHead = pListHead;
  817. *ListLock = pListLock;
  818. *WaitEvent = pWaitEvent;
  819. *KillEvent = pKillEvent;
  820. g_BrdgGpoGlobals.ProcessingNotifications = TRUE;
  821. status = STATUS_SUCCESS;
  822. }
  823. }
  824. }
  825. }
  826. if (!NT_SUCCESS(status))
  827. {
  828. if (pListHead)
  829. {
  830. ExFreePool(pListHead);
  831. }
  832. if (pListLock)
  833. {
  834. ExFreePool(pListLock);
  835. }
  836. if (pWaitEvent)
  837. {
  838. ExFreePool(pWaitEvent);
  839. }
  840. if (pKillEvent)
  841. {
  842. ExFreePool(pKillEvent);
  843. }
  844. }
  845. return status;
  846. }
  847. VOID
  848. BrdgGpoFreeNotifyList()
  849. /*++
  850. Routine Description:
  851. Frees the notify list and all it's associated entries.
  852. Arguments:
  853. None.
  854. Return Value:
  855. None.
  856. --*/
  857. {
  858. if (g_BrdgGpoGlobals.QueueInfo.NotifyList)
  859. {
  860. ExFreePool(g_BrdgGpoGlobals.QueueInfo.NotifyList);
  861. g_BrdgGpoGlobals.QueueInfo.NotifyList = NULL;
  862. }
  863. if (g_BrdgGpoGlobals.QueueInfo.NotifyListLock)
  864. {
  865. ExFreePool(g_BrdgGpoGlobals.QueueInfo.NotifyListLock);
  866. g_BrdgGpoGlobals.QueueInfo.NotifyListLock = NULL;
  867. }
  868. if (g_BrdgGpoGlobals.QueueInfo.NotifyEvent)
  869. {
  870. ExFreePool(g_BrdgGpoGlobals.QueueInfo.NotifyEvent);
  871. g_BrdgGpoGlobals.QueueInfo.NotifyEvent = NULL;
  872. }
  873. if (g_BrdgGpoGlobals.QueueInfo.KillEvent)
  874. {
  875. ExFreePool(g_BrdgGpoGlobals.QueueInfo.KillEvent);
  876. g_BrdgGpoGlobals.QueueInfo.KillEvent = NULL;
  877. }
  878. }
  879. NTSTATUS
  880. BrdgGpoRequestNotification(
  881. IN PBRDG_GPO_NOTIFY_KEY Notify)
  882. /*++
  883. Routine Description:
  884. Adds the Notification request to the list and signals the processing thread
  885. to re-check the list and register for any outstanding notifications.
  886. Arguments:
  887. Notify - Notify struct that contains all the information necessary to register
  888. for registry key changes.
  889. Return Value:
  890. STATUS_SHUTDOWN_IN_PROGRESS - We're no longer processing notifications as we're
  891. shutting down.
  892. STATUS_UNSUCCESSFUL - We were unable to get a valid list or lock.
  893. STATUS_SUCCESS - We successfully notified the processing thread to
  894. request notification on this item.
  895. --*/
  896. {
  897. NTSTATUS status = STATUS_SUCCESS;
  898. PLIST_ENTRY ListHead;
  899. PNDIS_RW_LOCK ListLock;
  900. LOCK_STATE LockState;
  901. PLIST_ENTRY pListEntry;
  902. PKEVENT WaitEvent;
  903. BOOLEAN NewEntry = TRUE;
  904. BOOLEAN ShuttingDown = FALSE;
  905. ListLock = BrdgGpoGetNotifyListLock();
  906. ListHead = BrdgGpoGetNotifyListHead();
  907. if (NULL == ListLock || NULL == ListHead)
  908. {
  909. return STATUS_UNSUCCESSFUL;
  910. }
  911. NdisAcquireReadWriteLock(ListLock, TRUE /* Write */, &LockState);
  912. ShuttingDown = !BrdgGpoProcessingNotifications();
  913. for (pListEntry = ListHead->Flink; pListEntry != ListHead; pListEntry = pListEntry->Flink)
  914. {
  915. PBRDG_GPO_NOTIFY_KEY CurrentNotify;
  916. CurrentNotify = CONTAINING_RECORD(pListEntry, BRDG_GPO_NOTIFY_KEY, ListEntry);
  917. if (0 == _wcsicmp(CurrentNotify->Identifier.Buffer, Notify->Identifier.Buffer))
  918. {
  919. NewEntry = FALSE;
  920. break;
  921. }
  922. }
  923. if (!ShuttingDown)
  924. {
  925. if (NewEntry)
  926. {
  927. InsertTailList(ListHead, &Notify->ListEntry);
  928. }
  929. Notify->Modified = TRUE;
  930. }
  931. NdisReleaseReadWriteLock(ListLock, &LockState);
  932. if (ShuttingDown)
  933. {
  934. status = STATUS_SHUTDOWN_IN_PROGRESS;
  935. }
  936. else
  937. {
  938. WaitEvent = BrdgGpoGetNotifyEvent();
  939. KeSetEvent(WaitEvent, 0, FALSE);
  940. }
  941. return status;
  942. }
  943. VOID
  944. BrdgGpoProcessNotifications(
  945. IN PVOID Context)
  946. /*++
  947. Routine Description:
  948. This is the processing thread worker function that is responsible to doing
  949. all notifications that we are interested in.
  950. WARNING: Don't try to remove this thread or have it exit until you're
  951. no longer interested in notifications. The registery
  952. notifications mechanism stores the notifications information
  953. in the _ETHREAD structure, so exiting the thread loses all
  954. remaining notifications.
  955. Arguments:
  956. Context - PBRDG_GPO_THREAD_PARAMS structure that contains a pointer to the
  957. notify list, it's lock and the notify and kill events.
  958. Return Value:
  959. None.
  960. --*/
  961. {
  962. PBRDG_GPO_THREAD_PARAMS ThreadParms = (PBRDG_GPO_THREAD_PARAMS) Context;
  963. BOOLEAN Exiting = FALSE;
  964. PNDIS_RW_LOCK ListLock;
  965. PLIST_ENTRY ListHead;
  966. PVOID WaitObjects[2];
  967. PLIST_ENTRY QueuedList;
  968. PBRDG_GPO_QUEUED_NOTIFY QueuedNotify;
  969. PNPAGED_LOOKASIDE_LIST LookasideQueueList;
  970. DBGPRINT(GPO, ("Notification Processing Thread Routine Running\r\n"));
  971. //
  972. // The lookaside list and Queuedlist need to live in NonPaged Pool because we utilize them
  973. // at DISPATCH_LEVEL
  974. //
  975. LookasideQueueList = ExAllocatePoolWithTag(NonPagedPool, sizeof(NPAGED_LOOKASIDE_LIST), 'gdrB');
  976. if (NULL == LookasideQueueList)
  977. {
  978. return;
  979. }
  980. QueuedList = ExAllocatePoolWithTag(NonPagedPool, sizeof(LIST_ENTRY), 'gdrB');
  981. if (NULL == QueuedList)
  982. {
  983. ExFreePool(LookasideQueueList);
  984. return;
  985. }
  986. ExInitializeNPagedLookasideList(LookasideQueueList,
  987. NULL,
  988. NULL,
  989. 0,
  990. sizeof(BRDG_GPO_QUEUED_NOTIFY),
  991. 'grbQ',
  992. 0);
  993. InitializeListHead(QueuedList);
  994. //
  995. // We passed in the list through the context of this thread.
  996. //
  997. ListHead = ThreadParms->NotifyList;
  998. ListLock = ThreadParms->NotifyListLock;
  999. WaitObjects[0]= (PVOID)ThreadParms->NotifyEvent;
  1000. WaitObjects[1]= (PVOID)ThreadParms->KillEvent;
  1001. while (!Exiting)
  1002. {
  1003. NTSTATUS status;
  1004. LOCK_STATE LockState;
  1005. PLIST_ENTRY pListEntry;
  1006. ULONG FiredEvent;
  1007. //
  1008. // We only do this if we're still processing notifications, otherwise we're waiting on
  1009. // the kill event.
  1010. //
  1011. if (BrdgGpoProcessingNotifications())
  1012. {
  1013. //
  1014. // We use a temporary list to fire off the notifications, since we can't
  1015. // register for RegKey notifications at DISPATCH_LEVEL.
  1016. //
  1017. NdisAcquireReadWriteLock(ListLock, FALSE /* Read-only */, &LockState);
  1018. //
  1019. // Loop through the list of notifications looking for any that have changed.
  1020. //
  1021. for (pListEntry = ListHead->Flink; pListEntry != ListHead; pListEntry = pListEntry->Flink)
  1022. {
  1023. PBRDG_GPO_NOTIFY_KEY Notify;
  1024. Notify = CONTAINING_RECORD(pListEntry, BRDG_GPO_NOTIFY_KEY, ListEntry);
  1025. if (TRUE == Notify->Modified)
  1026. {
  1027. //
  1028. // We've found an item that has changed, add it to the list that we'll
  1029. // use to do the actual work from (at PASSIVE_LEVEL).
  1030. //
  1031. if (FALSE == Notify->PendingNotification)
  1032. {
  1033. //
  1034. // We double increment this. Once for the list we're adding it to and once for
  1035. // the notification. We'll decrement it again once we're completely done with it
  1036. // in our list below.
  1037. //
  1038. if (BrdgIncrementWaitRef(&Notify->RefCount))
  1039. {
  1040. if (BrdgIncrementWaitRef(&Notify->RefCount))
  1041. {
  1042. QueuedNotify = ExAllocateFromNPagedLookasideList(LookasideQueueList);
  1043. QueuedNotify->Notify = Notify;
  1044. InsertTailList(QueuedList, &QueuedNotify->ListEntry);
  1045. }
  1046. else
  1047. {
  1048. //
  1049. // Only one increment succeeded, so we re-release it so that it can be freed
  1050. // since we're probably shutting down.
  1051. //
  1052. BrdgDecrementWaitRef(&Notify->RefCount);
  1053. }
  1054. }
  1055. }
  1056. //
  1057. // We're going to handle this request so set the Modified value to FALSE
  1058. // so that we don't do anything with it if we run through the list again
  1059. // due to another item being added.
  1060. //
  1061. Notify->Modified = FALSE;
  1062. }
  1063. }
  1064. NdisReleaseReadWriteLock(ListLock, &LockState);
  1065. //
  1066. // We're back at PASSIVE_LEVEL so we can now do the registration for the changes.
  1067. //
  1068. for (pListEntry = QueuedList->Flink; pListEntry != QueuedList; pListEntry = pListEntry->Flink)
  1069. {
  1070. QueuedNotify = CONTAINING_RECORD(pListEntry, BRDG_GPO_QUEUED_NOTIFY, ListEntry);
  1071. DBGPRINT(GPO, ("Processing Notification: %S\r\n", QueuedNotify->Notify->Identifier.Buffer));
  1072. //
  1073. // Do the actual registration for the key change notification. Since we can also be
  1074. // passed in a pointer to a BOOLEAN that is used elsewhere, we set that accordingly
  1075. // if we have one.
  1076. //
  1077. DBGPRINT(GPO, ("Refcount for %S \t-\t %d\r\n", QueuedNotify->Notify->Identifier.Buffer, QueuedNotify->Notify->RefCount));
  1078. status = BrdgGpoRegisterForRegKeyChange(QueuedNotify->Notify);
  1079. if (QueuedNotify->Notify->SuccessfulRegistration)
  1080. {
  1081. *(QueuedNotify->Notify->SuccessfulRegistration) = (BOOLEAN)NT_SUCCESS(status);
  1082. BrdgGpoCheckForMatchAndUpdateMode();
  1083. if (QueuedNotify->Notify->FunctionRegister)
  1084. {
  1085. NTSTATUS tmpStatus;
  1086. tmpStatus = QueuedNotify->Notify->FunctionRegister();
  1087. DBGPRINT(GPO, ("Function returned: 0x%x\r\n", tmpStatus));
  1088. }
  1089. }
  1090. if (NT_SUCCESS(status))
  1091. {
  1092. InterlockedExchange(&QueuedNotify->Notify->PendingNotification, TRUE);
  1093. }
  1094. else
  1095. {
  1096. InterlockedExchange(&QueuedNotify->Notify->PendingNotification, FALSE);
  1097. //
  1098. // We failed the request, so decrement the refcount.
  1099. //
  1100. BrdgDecrementWaitRef(&QueuedNotify->Notify->RefCount);
  1101. }
  1102. //
  1103. // We're done with the item in the list, so decrement the refcount.
  1104. //
  1105. BrdgDecrementWaitRef(&QueuedNotify->Notify->RefCount);
  1106. }
  1107. //
  1108. // Free the temporary list.
  1109. //
  1110. while (!IsListEmpty(QueuedList))
  1111. {
  1112. pListEntry = RemoveHeadList(QueuedList);
  1113. QueuedNotify = CONTAINING_RECORD(pListEntry, BRDG_GPO_QUEUED_NOTIFY, ListEntry);
  1114. ExFreeToNPagedLookasideList(LookasideQueueList, QueuedNotify);
  1115. }
  1116. }
  1117. //
  1118. // We're done, we'll wait here until the event has fired, ie, one of the items needs to be re-registered,
  1119. // or a new item has been added to the list and we need to register for notifications.
  1120. //
  1121. status = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, Executive, KernelMode, FALSE, FALSE, NULL);
  1122. if (!NT_SUCCESS(status))
  1123. {
  1124. FiredEvent = 1L; // We're going to terminate the thread.
  1125. DBGPRINT(GPO, ("KeWaitForMultipleObjects returned an error"));
  1126. }
  1127. else
  1128. {
  1129. FiredEvent = (ULONG)status - (ULONG)STATUS_WAIT_0;
  1130. }
  1131. if (1L == FiredEvent)
  1132. {
  1133. Exiting = TRUE;
  1134. }
  1135. }
  1136. ExDeleteNPagedLookasideList(LookasideQueueList);
  1137. ExFreePool(LookasideQueueList);
  1138. ExFreePool(QueuedList);
  1139. DBGPRINT(GPO, ("Notification Processing Thread Routine Exiting\r\n"));
  1140. // We're done, kill this thread.
  1141. PsTerminateSystemThread( STATUS_SUCCESS );
  1142. }
  1143. NTSTATUS
  1144. BrdgGpoRegisterForRegKeyChange(
  1145. IN PBRDG_GPO_NOTIFY_KEY Notify)
  1146. {
  1147. NTSTATUS status;
  1148. if (!BrdgGpoProcessingNotifications())
  1149. {
  1150. return STATUS_SHUTDOWN_IN_PROGRESS;
  1151. }
  1152. //
  1153. // Call our notify worker function (this does the real request for notification).
  1154. //
  1155. status = BrdgGpoNotifyRegKeyChange( Notify,
  1156. (PIO_APC_ROUTINE)(ULONG_PTR)&Notify->RegChangeWorkItem,
  1157. Notify->WorkItemContext,
  1158. Notify->CompletionFilter,
  1159. Notify->WatchTree);
  1160. if (!NT_SUCCESS(status))
  1161. {
  1162. DBGPRINT(GPO, ("Unable to register for notification on %S. Status: 0x%x\r\n", Notify->RegKeyName.Buffer, status));
  1163. }
  1164. return status;
  1165. }
  1166. NTSTATUS
  1167. BrdgGpoBuildNotifyForRegKeyChange(
  1168. IN PBRDG_GPO_NOTIFY_KEY Notify,
  1169. IN LPWSTR Identifier,
  1170. IN LPWSTR RegKeyName,
  1171. IN LPWSTR RegValueName,
  1172. IN PWORKER_THREAD_ROUTINE ApcRoutine,
  1173. IN PVOID ApcContext,
  1174. IN ULONG CompletionFilter,
  1175. IN BOOLEAN WatchTree,
  1176. IN PBRDG_GPO_REG_CALLBACK FunctionCallback,
  1177. IN BOOLEAN Recurring,
  1178. IN PBOOLEAN SuccessfulRegistration,
  1179. IN PBRDG_GPO_REGISTER FunctionRegister
  1180. )
  1181. /*++
  1182. Routine Description:
  1183. Builds a Notify structure used for Registry Key and Value changes.
  1184. Arguments:
  1185. Notify - If ReRegister is FALSE, then this structure has simply been
  1186. initialized with some basic information. The rest will be
  1187. filled in here. If ReRegister is TRUE, then this structure
  1188. contains all the information necessary to redo the notification
  1189. request, this saves us having to pass all the data in each time.
  1190. Identifier - Identifies this Notify structure. Can be a name, or a GUID for an adapter.
  1191. RegKeyName - The Registry key that we're interesting in waiting on.
  1192. RegValueName - The Value that we need (or "Default" if we don't care about it")
  1193. ApcRoutine - The routine that we which to be notified on.
  1194. ApcContext - Information that we want to be passed back (we expect a valid Notify Struct).
  1195. CompletionFilter - What type of change we're interested in. ie. New Subkey added, or Value changed etc.
  1196. WatchTree - Do we want to what for changes on all subkeys as well.
  1197. FunctionCallback - Our own internal callback functions
  1198. Recurring - Do we want to re-do the notification once we're done handling it.
  1199. SuccessfulRegistration - A pointer to a BOOLEAN that we set if the registration is successful.
  1200. Return Value:
  1201. STATUS_SUCCESS or a specific error code.
  1202. --*/
  1203. {
  1204. NTSTATUS status = STATUS_SUCCESS;
  1205. LPWSTR lpszIdentifier = NULL;
  1206. LPWSTR lpszRegKeyName = NULL;
  1207. LPWSTR lpszRegValueName = NULL;
  1208. if (NULL == Notify ||
  1209. NULL == Identifier ||
  1210. NULL == RegKeyName ||
  1211. NULL == RegValueName ||
  1212. NULL == ApcRoutine ||
  1213. NULL == ApcContext ||
  1214. NULL == FunctionCallback
  1215. )
  1216. {
  1217. return STATUS_INVALID_PARAMETER;
  1218. }
  1219. //
  1220. // This buffer is not used by ZwNotifyChangeKey. So no need to really allocate anything for it.
  1221. //
  1222. Notify->Buffer = 0L;
  1223. Notify->BufferSize = sizeof(ULONG);
  1224. //
  1225. // We Allocate these from NonPagedPool because they're passed as part of a struct that can be used at
  1226. // DISPATCH_LEVEL
  1227. //
  1228. lpszIdentifier = ExAllocatePoolWithTag(NonPagedPool, (wcslen(Identifier) + 1) * sizeof(WCHAR), 'gdrB');
  1229. if (lpszIdentifier)
  1230. {
  1231. lpszRegKeyName = ExAllocatePoolWithTag(NonPagedPool, (wcslen(RegKeyName) + 1) * sizeof(WCHAR), 'gdrB');
  1232. if (lpszRegKeyName)
  1233. {
  1234. lpszRegValueName = ExAllocatePoolWithTag(NonPagedPool, (wcslen(RegValueName) + 1) * sizeof(WCHAR), 'gdrB');
  1235. if (lpszRegValueName)
  1236. {
  1237. BOOLEAN Success;
  1238. RtlZeroMemory(lpszIdentifier, (wcslen(Identifier) + 1) * sizeof(WCHAR));
  1239. RtlZeroMemory(lpszRegKeyName, (wcslen(RegKeyName) + 1) * sizeof(WCHAR));
  1240. RtlZeroMemory(lpszRegValueName, (wcslen(RegValueName) + 1) * sizeof(WCHAR));
  1241. //
  1242. // We need to allocate new strings because the RtlInitUnicodeString function just sets its buffer
  1243. // to the LPWSTR we pass it and these values need to be used outside the scope of these functions.
  1244. //
  1245. wcscpy(lpszIdentifier, Identifier);
  1246. wcscpy(lpszRegKeyName, RegKeyName);
  1247. wcscpy(lpszRegValueName, RegValueName);
  1248. //
  1249. // Set the strings inside our struct. This enables us to fully rebuild the information required
  1250. // for keeping track of the different keys that we need to be notified about.
  1251. //
  1252. RtlInitUnicodeString(&Notify->Identifier, lpszIdentifier);
  1253. RtlInitUnicodeString(&Notify->RegKeyName, lpszRegKeyName);
  1254. RtlInitUnicodeString(&Notify->RegValue, lpszRegValueName);
  1255. //
  1256. // Recurring will tell us if we need to re-register once a change is fired.
  1257. //
  1258. Notify->Recurring = Recurring;
  1259. //
  1260. // Rather than have the BrdgGpoRegNotify function do everything, we have seperate functions
  1261. // for each one. This also means that we don't have to keep all of them in the paged-locked
  1262. // section, since they will be called at PASSIVE_LEVEL.
  1263. //
  1264. Notify->FunctionCallback = FunctionCallback;
  1265. //
  1266. // We are using a Workitem to get called back on. We pass in the notify structure
  1267. // which has enough info to re-notify if necessary. The context is generally just
  1268. // the Deferred work queue.
  1269. //
  1270. ExInitializeWorkItem(&Notify->RegChangeWorkItem, ApcRoutine, Notify);
  1271. Notify->WorkItemContext = ApcContext;
  1272. //
  1273. // We store the WatchTree and CompletionFilter so that we can renotify needing any
  1274. // additional parameters, since we're probably ddoing this from a different thread.
  1275. //
  1276. Notify->WatchTree = WatchTree;
  1277. Notify->CompletionFilter = CompletionFilter;
  1278. //
  1279. // We set this once we have successfully registered for notification on the key of
  1280. // interest.
  1281. //
  1282. Notify->SuccessfulRegistration = SuccessfulRegistration;
  1283. //
  1284. // Increment this once so that we can decrement it in the cleanup code and have it only go to Zero then.
  1285. //
  1286. BrdgInitializeWaitRef(&Notify->RefCount, FALSE);
  1287. //
  1288. // Since we're initializing this object, there is no way that this should fail.
  1289. //
  1290. Success = BrdgIncrementWaitRef(&Notify->RefCount);
  1291. SAFEASSERT(Success);
  1292. }
  1293. else
  1294. {
  1295. status = STATUS_INSUFFICIENT_RESOURCES;
  1296. }
  1297. }
  1298. else
  1299. {
  1300. status = STATUS_INSUFFICIENT_RESOURCES;
  1301. }
  1302. }
  1303. else
  1304. {
  1305. return STATUS_INSUFFICIENT_RESOURCES;
  1306. }
  1307. if (!NT_SUCCESS(status))
  1308. {
  1309. if (lpszIdentifier)
  1310. {
  1311. ExFreePool(lpszIdentifier);
  1312. }
  1313. if (lpszRegKeyName)
  1314. {
  1315. ExFreePool(lpszRegKeyName);
  1316. }
  1317. if (lpszRegValueName)
  1318. {
  1319. ExFreePool(lpszRegValueName);
  1320. }
  1321. }
  1322. return status;
  1323. }
  1324. NTSTATUS
  1325. BrdgGpoNotifyRegKeyChange(
  1326. IN PBRDG_GPO_NOTIFY_KEY Notify,
  1327. IN PIO_APC_ROUTINE ApcRoutine,
  1328. IN PVOID ApcContext,
  1329. IN ULONG CompletionFilter,
  1330. IN BOOLEAN WatchTree)
  1331. /*++
  1332. Routine Description:
  1333. This calls ZwNotifyChangeKey to register us for notifications on individual keys.
  1334. We close the key in the callback functions because you can only listen once per handle.
  1335. Arguments:
  1336. Notify - Structure containing relevant information about the notification. Allows us to
  1337. know what values to read to get the relevant data that we need.
  1338. ApcRoutine - The routine that we which to be notified on.
  1339. ApcContext - Information that we want to be passed back (we expect a valid Notify Struct).
  1340. CompletionFilter - What type of change we're interested in. ie. New Subkey added, or Value changed etc.
  1341. WatchTree - Do we want to what for changes on all subkeys as well.
  1342. Return Value:
  1343. STATUS_SUCCESS or a specific error code.
  1344. --*/
  1345. {
  1346. OBJECT_ATTRIBUTES ObAttr;
  1347. NTSTATUS status;
  1348. InitializeObjectAttributes(&ObAttr, &Notify->RegKeyName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
  1349. status = ZwOpenKey( &Notify->RegKey,
  1350. KEY_READ | KEY_NOTIFY | KEY_WRITE,
  1351. &ObAttr);
  1352. if (NT_SUCCESS(status))
  1353. {
  1354. DBGPRINT(GPO, ("Opened Regkey successfully\r\n"));
  1355. status = ZwNotifyChangeKey( Notify->RegKey,
  1356. NULL,
  1357. ApcRoutine,
  1358. ApcContext,
  1359. &Notify->IoStatus,
  1360. CompletionFilter,
  1361. WatchTree,
  1362. &Notify->Buffer,
  1363. Notify->BufferSize,
  1364. TRUE
  1365. );
  1366. }
  1367. else
  1368. {
  1369. //
  1370. // Set it to NULL so that we don't try to close it accidentally during shutdown.
  1371. //
  1372. Notify->RegKey = NULL;
  1373. }
  1374. return status;
  1375. }
  1376. VOID
  1377. static
  1378. BrdgGpoRegNotify(
  1379. IN PVOID Context)
  1380. /*++
  1381. Routine Description:
  1382. This is the central callback function that we are notified on.
  1383. This is called on an Executive worker thread at PASSIVE_LEVEL.
  1384. Arguments:
  1385. Context - Is just our Notify structure that we passed in
  1386. to ZwNotifyChangeKey
  1387. Return Value:
  1388. None.
  1389. --*/
  1390. {
  1391. PBRDG_GPO_NOTIFY_KEY Notify = (PBRDG_GPO_NOTIFY_KEY)Context;
  1392. DBGPRINT(GPO, ("APC routine called\r\n"));
  1393. DBGPRINT(GPO, ("Current IRQL: %d\r\n", CURRENT_IRQL));
  1394. if (Notify)
  1395. {
  1396. LONG RefCount;
  1397. InterlockedExchange(&Notify->PendingNotification, FALSE);
  1398. Notify->FunctionCallback(Notify);
  1399. RefCount = Notify->RefCount.Refcount - 1;
  1400. DBGPRINT(GPO, ("Refcount for %S \t-\t %d\r\n", Notify->Identifier.Buffer, RefCount));
  1401. BrdgDecrementWaitRef(&Notify->RefCount);
  1402. }
  1403. }
  1404. NTSTATUS
  1405. BrdgGpoAllocateAndInitializeNotifyStruct(
  1406. OUT PBRDG_GPO_NOTIFY_KEY* Notify)
  1407. /*++
  1408. Routine Description:
  1409. Allocates and initializes the Notify struct to all zeros.
  1410. Arguments:
  1411. Notify - A pointer to pointer to a Notify struct that is allocated
  1412. from NonPagedPool.
  1413. Return Value:
  1414. STATUS_INSUFFICIENT_RESOURCES - Not enough memory to filfull the request.
  1415. STATUS_INVALID_PARAMETER - We were passed a NULL Pointer to pointer
  1416. to a Notify struct.
  1417. STATUS_SUCCESS - We successfully allocated space for the structure.
  1418. --*/
  1419. {
  1420. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  1421. if (NULL == Notify)
  1422. {
  1423. return STATUS_INVALID_PARAMETER;
  1424. }
  1425. //
  1426. // We allocate this from NonPagedPool because it will be accessed at DISPATCH_LEVEL
  1427. //
  1428. *Notify = ExAllocatePoolWithTag(NonPagedPool, sizeof(BRDG_GPO_NOTIFY_KEY), 'gdrB');
  1429. if (*Notify)
  1430. {
  1431. //
  1432. // Zero it out so that we don't try and free invalid strings when we free it.
  1433. //
  1434. RtlZeroMemory(*Notify, sizeof(BRDG_GPO_NOTIFY_KEY));
  1435. status = STATUS_SUCCESS;
  1436. }
  1437. return status;
  1438. }
  1439. VOID
  1440. BrdgGpoFreeNotifyStructAndData(
  1441. IN PBRDG_GPO_NOTIFY_KEY Notify)
  1442. /*++
  1443. Routine Description:
  1444. Frees all data associated with a Notify struct and then frees the struct
  1445. itself.
  1446. Note: This will not free a structure that is still in a list.
  1447. If you need to free something, use RemoveListEntry and then
  1448. set the Notify->ListEntry Blink and Flink = NULL and then call
  1449. this.
  1450. WARNING:
  1451. Since it's possible that this structure is still being used by
  1452. the a waiting registration, it's better to leave them alone until
  1453. shutdown as it's possible that a notification may be fired once
  1454. this has been freed and that will result in a system crash since
  1455. the struct will be invalid.
  1456. Arguments:
  1457. Notify - A pointer to the Notify struct to be freed.
  1458. Return Value:
  1459. None.
  1460. --*/
  1461. {
  1462. if (Notify)
  1463. {
  1464. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  1465. {
  1466. if (Notify->Identifier.Buffer)
  1467. {
  1468. ExFreePool(Notify->Identifier.Buffer);
  1469. }
  1470. if (Notify->RegKeyName.Buffer)
  1471. {
  1472. ExFreePool(Notify->RegKeyName.Buffer);
  1473. }
  1474. if (Notify->RegValue.Buffer)
  1475. {
  1476. ExFreePool(Notify->RegValue.Buffer);
  1477. }
  1478. ExFreePool(Notify);
  1479. }
  1480. else
  1481. {
  1482. if (BrdgGpoProcessingNotifications())
  1483. {
  1484. DBGPRINT(GPO, ("Attempt to free a Notify that is still in a list\r\nWhile we're still processing Notifications\r\n"));
  1485. }
  1486. }
  1487. }
  1488. }
  1489. // ===========================================================================
  1490. //
  1491. // NOTIFICATION REGISTRATION FUNCTIONS
  1492. //
  1493. // ===========================================================================
  1494. NTSTATUS
  1495. BrdgGpoRegisterForGroupPolicyNetworkNameNotification()
  1496. /*++
  1497. Routine Description:
  1498. Registers for the changes on the following registry key:
  1499. "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\History"
  1500. Arguments:
  1501. None.
  1502. Return Value:
  1503. None.
  1504. --*/
  1505. {
  1506. NTSTATUS status;
  1507. PBRDG_GPO_NOTIFY_KEY Notify = NULL;
  1508. UNICODE_STRING RegKeyName;
  1509. PWCHAR RegValue;
  1510. ULONG DataLen;
  1511. if (g_BrdgGpoGlobals.RegisteredForGroupPolicyHistoryChanges)
  1512. {
  1513. DBGPRINT(GPO, ("Already Registered for Group Policy Network Name Notification\r\n"));
  1514. return STATUS_SUCCESS;
  1515. }
  1516. DBGPRINT(GPO, ("BrdgGpoRegisterForGroupPolicyNetworkNameNotification\r\n"));
  1517. RtlInitUnicodeString(&RegKeyName, (LPWSTR) HistoryKey);
  1518. //
  1519. // Read the current value from the Registry.
  1520. //
  1521. status = BrdgReadRegUnicode(&RegKeyName,
  1522. L"NetworkName",
  1523. &RegValue,
  1524. &DataLen);
  1525. if (NT_SUCCESS(status))
  1526. {
  1527. DBGPRINT(GPO, ("Group Policy Network Name: %S\r\n", RegValue));
  1528. if (NULL != g_BrdgGpoGlobals.GroupPolicyNetworkName.Buffer)
  1529. {
  1530. ExFreePool(g_BrdgGpoGlobals.GroupPolicyNetworkName.Buffer);
  1531. }
  1532. //
  1533. // Success. Now store the value for later use.
  1534. //
  1535. RtlInitUnicodeString(&g_BrdgGpoGlobals.GroupPolicyNetworkName, RegValue);
  1536. //
  1537. // Since something changed, we'll just re-verify that we're in
  1538. // the correct bridging mode.
  1539. //
  1540. BrdgGpoCheckForMatchAndUpdateMode();
  1541. }
  1542. else
  1543. {
  1544. //
  1545. // We failed to get a value for this. It probably isn't there yet - this can happen if this
  1546. // is the first boot after joining a domain. We'll be waiting on this key so if we get one later
  1547. // we'll update this value.
  1548. //
  1549. g_BrdgGpoGlobals.GroupPolicyNetworkName.Buffer = NULL;
  1550. g_BrdgGpoGlobals.GroupPolicyNetworkName.Length = 0;
  1551. g_BrdgGpoGlobals.GroupPolicyNetworkName.MaximumLength = 0;
  1552. }
  1553. //
  1554. // We don't want to allocate these twice, so we first try to find an existing notify struct.
  1555. //
  1556. status = BrdgGpoFindNotify( BrdgGpoGetNotifyListHead(),
  1557. BrdgGpoGetNotifyListLock(),
  1558. L"GroupPolicyNetworkName",
  1559. &Notify);
  1560. if (NT_SUCCESS(status))
  1561. {
  1562. if (STATUS_OBJECT_NAME_EXISTS != status)
  1563. {
  1564. status = BrdgGpoAllocateAndInitializeNotifyStruct(&Notify);
  1565. if (NT_SUCCESS(status))
  1566. {
  1567. status = BrdgGpoBuildNotifyForRegKeyChange( Notify,
  1568. L"GroupPolicyNetworkName",
  1569. (LPWSTR)HistoryKey,
  1570. L"NetworkName",
  1571. BrdgGpoRegNotify,
  1572. (PVOID)(UINT_PTR)(unsigned int)DelayedWorkQueue,
  1573. REG_NOTIFY_CHANGE_LAST_SET,
  1574. FALSE,
  1575. BrdgGpoGroupPolicyNetworkNameChangeCallback,
  1576. TRUE,
  1577. &g_BrdgGpoGlobals.RegisteredForGroupPolicyHistoryChanges,
  1578. BrdgGpoUpdateGroupPolicyNetworkName);
  1579. }
  1580. }
  1581. if (!NT_SUCCESS(status))
  1582. {
  1583. DBGPRINT(GPO, ("Unable to Build notification on %S. Status: 0x%x\r\n", NetworkPoliciesKey, status));
  1584. BrdgGpoFreeNotifyStructAndData(Notify);
  1585. Notify = NULL;
  1586. }
  1587. else
  1588. {
  1589. SAFEASSERT(Notify);
  1590. status = BrdgGpoRequestNotification(Notify);
  1591. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  1592. {
  1593. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  1594. {
  1595. BrdgDecrementWaitRef(&Notify->RefCount);
  1596. BrdgGpoFreeNotifyStructAndData(Notify);
  1597. Notify = NULL;
  1598. }
  1599. }
  1600. else if (!NT_SUCCESS(status))
  1601. {
  1602. BrdgGpoFreeNotifyStructAndData(Notify);
  1603. Notify = NULL;
  1604. }
  1605. }
  1606. }
  1607. #if DBG
  1608. if (Notify)
  1609. {
  1610. SAFEASSERT(Notify->ListEntry.Blink && Notify->ListEntry.Flink);
  1611. }
  1612. #endif
  1613. return status;
  1614. }
  1615. NTSTATUS
  1616. BrdgGpoRegisterForGroupPolicyNotification()
  1617. /*++
  1618. Routine Description:
  1619. Registers for the changes on the following registry key:
  1620. "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy"
  1621. This is the parent to the History key and is always on a system.
  1622. If will be notified if the History Key is created in which case
  1623. we will register for notifications on that key.
  1624. Arguments:
  1625. None.
  1626. Return Value:
  1627. None.
  1628. --*/
  1629. {
  1630. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  1631. PBRDG_GPO_NOTIFY_KEY Notify = NULL;
  1632. DBGPRINT(GPO, ("BrdgGpoRegisterForGroupPolicyNotification\r\n"));
  1633. //
  1634. // We don't want to allocate these twice, so we first try to find an existing notify struct.
  1635. //
  1636. status = BrdgGpoFindNotify( BrdgGpoGetNotifyListHead(),
  1637. BrdgGpoGetNotifyListLock(),
  1638. L"GroupPolicyParent",
  1639. &Notify);
  1640. if (NT_SUCCESS(status))
  1641. {
  1642. if (STATUS_OBJECT_NAME_EXISTS != status)
  1643. {
  1644. status = BrdgGpoAllocateAndInitializeNotifyStruct(&Notify);
  1645. if (NT_SUCCESS(status))
  1646. {
  1647. status = BrdgGpoBuildNotifyForRegKeyChange( Notify,
  1648. L"GroupPolicyParent",
  1649. (LPWSTR)GroupPolicyKey,
  1650. L"Default",
  1651. BrdgGpoRegNotify,
  1652. (PVOID)(UINT_PTR)(unsigned int)DelayedWorkQueue,
  1653. REG_NOTIFY_CHANGE_NAME,
  1654. FALSE,
  1655. BrdgGpoGroupPolicyChangeCallback,
  1656. TRUE,
  1657. &g_BrdgGpoGlobals.RegisteredForGroupPolicyChanges,
  1658. BrdgGpoRegisterForGroupPolicyNetworkNameNotification);
  1659. }
  1660. }
  1661. if (!NT_SUCCESS(status))
  1662. {
  1663. DBGPRINT(GPO, ("Unable to register for notification on %S. Status: 0x%x\r\n", GroupPolicyKey, status));
  1664. BrdgGpoFreeNotifyStructAndData(Notify);
  1665. Notify = NULL;
  1666. }
  1667. else
  1668. {
  1669. SAFEASSERT(Notify);
  1670. status = BrdgGpoRequestNotification(Notify);
  1671. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  1672. {
  1673. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  1674. {
  1675. BrdgDecrementWaitRef(&Notify->RefCount);
  1676. BrdgGpoFreeNotifyStructAndData(Notify);
  1677. Notify = NULL;
  1678. }
  1679. }
  1680. else if (!NT_SUCCESS(status))
  1681. {
  1682. BrdgGpoFreeNotifyStructAndData(Notify);
  1683. Notify = NULL;
  1684. }
  1685. }
  1686. }
  1687. #if DBG
  1688. if (Notify)
  1689. {
  1690. SAFEASSERT(Notify->ListEntry.Blink && Notify->ListEntry.Flink);
  1691. }
  1692. #endif
  1693. return status;
  1694. }
  1695. NTSTATUS
  1696. BrdgGpoRegisterForWindowsGroupPolicyNotification()
  1697. /*++
  1698. Routine Description:
  1699. Registers for the changes on the following registry key:
  1700. HKLM\SOFTWARE\Policies\Microsoft\Windows
  1701. If this gets notified, then we'll attempt to wait on the
  1702. Network Connections key below this.
  1703. Arguments:
  1704. None.
  1705. Return Value:
  1706. STATUS_INSUFFICIENT_RESOURCES - Not enough memory to allocate the structure.
  1707. STATUS_SUCCESS - We were able to post the request successfully.
  1708. This doesn't mean we've successfully requested
  1709. notification though, it only means we've added it
  1710. to the Notifications list and have signaled the
  1711. processing thread to attempt a notification.
  1712. --*/
  1713. {
  1714. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  1715. PBRDG_GPO_NOTIFY_KEY Notify = NULL;
  1716. DBGPRINT(GPO, ("BrdgGpoRegisterForWindowsGroupPolicyNotification\r\n"));
  1717. //
  1718. // We don't want to allocate these twice, so we first try to find an existing notify struct.
  1719. //
  1720. status = BrdgGpoFindNotify( BrdgGpoGetNotifyListHead(),
  1721. BrdgGpoGetNotifyListLock(),
  1722. L"WindowsGroupPolicies",
  1723. &Notify);
  1724. if (NT_SUCCESS(status))
  1725. {
  1726. if (STATUS_OBJECT_NAME_EXISTS != status)
  1727. {
  1728. status = BrdgGpoAllocateAndInitializeNotifyStruct(&Notify);
  1729. if (NT_SUCCESS(status))
  1730. {
  1731. status = BrdgGpoBuildNotifyForRegKeyChange( Notify,
  1732. L"WindowsGroupPolicies",
  1733. (LPWSTR)PolicyBaseKey,
  1734. (LPWSTR)L"Default",
  1735. BrdgGpoRegNotify,
  1736. (PVOID)(UINT_PTR)(unsigned int)DelayedWorkQueue,
  1737. REG_NOTIFY_CHANGE_NAME,
  1738. FALSE,
  1739. BrdgGpoWindowsGroupPolicyChangeCallback,
  1740. TRUE,
  1741. NULL,
  1742. BrdgGpoRegisterForNetworkConnectionsGroupPolicyNotification);
  1743. }
  1744. }
  1745. if (!NT_SUCCESS(status))
  1746. {
  1747. DBGPRINT(GPO, ("Unable to register for notification on %S. Status: 0x%x\r\n", PolicyBaseKey, status));
  1748. BrdgGpoFreeNotifyStructAndData(Notify);
  1749. Notify = NULL;
  1750. }
  1751. else
  1752. {
  1753. SAFEASSERT(Notify);
  1754. status = BrdgGpoRequestNotification(Notify);
  1755. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  1756. {
  1757. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  1758. {
  1759. BrdgDecrementWaitRef(&Notify->RefCount);
  1760. BrdgGpoFreeNotifyStructAndData(Notify);
  1761. Notify = NULL;
  1762. }
  1763. }
  1764. else if (!NT_SUCCESS(status))
  1765. {
  1766. BrdgGpoFreeNotifyStructAndData(Notify);
  1767. Notify = NULL;
  1768. }
  1769. }
  1770. }
  1771. #if DBG
  1772. if (Notify)
  1773. {
  1774. SAFEASSERT(Notify->ListEntry.Blink && Notify->ListEntry.Flink);
  1775. }
  1776. #endif
  1777. return status;
  1778. }
  1779. VOID
  1780. BrdgGpoRegisterForHiveListNotification()
  1781. /*++
  1782. Routine Description:
  1783. Registers for the changes on the following registry key:
  1784. "HKLM\System\CurrentControlSet\Control\HiveList"
  1785. Each time this is fired we attempt to open the Software hive, if this
  1786. open is successful then we request notification on all the keys that
  1787. we are interested in under the software hive.
  1788. Arguments:
  1789. None.
  1790. Return Value:
  1791. None.
  1792. --*/
  1793. {
  1794. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  1795. PBRDG_GPO_NOTIFY_KEY Notify = NULL;
  1796. UNICODE_STRING Software;
  1797. OBJECT_ATTRIBUTES ObAttr;
  1798. HANDLE hKey;
  1799. DBGPRINT(GPO, ("BrdgGpoRegisterForHiveListNotification\r\n"));
  1800. //
  1801. // We attempt to open this key now in case the hives are already loaded.
  1802. //
  1803. RtlInitUnicodeString(&Software, SoftwareHiveKey);
  1804. InitializeObjectAttributes( &ObAttr,
  1805. &Software,
  1806. OBJ_CASE_INSENSITIVE,
  1807. NULL,
  1808. NULL
  1809. );
  1810. status = ZwOpenKey(&hKey, KEY_READ, &ObAttr);
  1811. if (NT_SUCCESS(status))
  1812. {
  1813. //
  1814. // The software hive is already loaded, no need to register for changes
  1815. // to this. Just attempt to register for all other changes.
  1816. //
  1817. BrdgGpoRegisterForGroupPolicyNetworkNameNotification();
  1818. BrdgGpoRegisterForWindowsGroupPolicyNotification();
  1819. BrdgGpoRegisterForGroupPolicyNotification();
  1820. //
  1821. // To avoid turning the bridge on and then off again, we set this just after
  1822. // verifying the Network Connections policy setting.
  1823. //
  1824. BrdgGpoRegisterForNetworkConnectionsGroupPolicyNotification();
  1825. g_BrdgGpoGlobals.WaitingOnSoftwareHive = FALSE;
  1826. ZwClose(hKey);
  1827. }
  1828. else
  1829. {
  1830. //
  1831. // We don't want to allocate these twice, so we first try to find an existing notify struct.
  1832. //
  1833. status = BrdgGpoFindNotify( BrdgGpoGetNotifyListHead(),
  1834. BrdgGpoGetNotifyListLock(),
  1835. L"HiveList",
  1836. &Notify);
  1837. if (NT_SUCCESS(status))
  1838. {
  1839. if (STATUS_OBJECT_NAME_EXISTS != status)
  1840. {
  1841. //
  1842. // The item doesn't exist yet, so allocate it from the NonPagedPool and
  1843. // attempt build a notification request.
  1844. //
  1845. status = BrdgGpoAllocateAndInitializeNotifyStruct(&Notify);
  1846. if (NT_SUCCESS(status))
  1847. {
  1848. status = BrdgGpoBuildNotifyForRegKeyChange( Notify,
  1849. L"HiveList",
  1850. (LPWSTR)HiveListKey,
  1851. (LPWSTR)L"Default",
  1852. BrdgGpoRegNotify,
  1853. (PVOID)(UINT_PTR)(unsigned int)DelayedWorkQueue,
  1854. REG_NOTIFY_CHANGE_LAST_SET,
  1855. FALSE,
  1856. BrdgGpoHiveListCallback,
  1857. TRUE,
  1858. NULL,
  1859. NULL);
  1860. }
  1861. }
  1862. if (!NT_SUCCESS(status))
  1863. {
  1864. DBGPRINT(GPO, ("Unable to register for notification on %S. Status: 0x%x\r\n", PolicyBaseKey, status));
  1865. BrdgGpoFreeNotifyStructAndData(Notify);
  1866. Notify = NULL;
  1867. }
  1868. else
  1869. {
  1870. SAFEASSERT(Notify);
  1871. //
  1872. // We have a valid Notify structure, post a notification request to the
  1873. // processing thread.
  1874. //
  1875. status = BrdgGpoRequestNotification(Notify);
  1876. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  1877. {
  1878. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  1879. {
  1880. BrdgDecrementWaitRef(&Notify->RefCount);
  1881. BrdgGpoFreeNotifyStructAndData(Notify);
  1882. Notify = NULL;
  1883. }
  1884. }
  1885. else if (!NT_SUCCESS(status))
  1886. {
  1887. BrdgGpoFreeNotifyStructAndData(Notify);
  1888. Notify = NULL;
  1889. }
  1890. }
  1891. }
  1892. #if DBG
  1893. if (Notify)
  1894. {
  1895. SAFEASSERT(Notify->ListEntry.Blink && Notify->ListEntry.Flink);
  1896. }
  1897. #endif
  1898. }
  1899. }
  1900. NTSTATUS
  1901. BrdgGpoRegisterForNetworkConnectionsGroupPolicyNotification()
  1902. /*++
  1903. Routine Description:
  1904. Registers for the changes on the following registry key:
  1905. "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\Network Connections"
  1906. We also read any value that may already be there and act upon it.
  1907. Arguments:
  1908. None.
  1909. Return Value:
  1910. STATUS_INSUFFICIENT_RESOURCES - Not enough memory to allocate the structure.
  1911. STATUS_SUCCESS - We were able to post the request successfully.
  1912. This doesn't mean we've successfully requested
  1913. notification though, it only means we've added it
  1914. to the Notifications list and have signaled the
  1915. processing thread to attempt a notification.
  1916. --*/
  1917. {
  1918. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  1919. PBRDG_GPO_NOTIFY_KEY Notify = NULL;
  1920. UNICODE_STRING RegKeyName;
  1921. ULONG RegValue;
  1922. if (g_BrdgGpoGlobals.RegisteredForNetworkConnectionsGroupPolicyChanges)
  1923. {
  1924. DBGPRINT(GPO, ("Already Registered for Network Connections Group Policy Notification\r\n"));
  1925. return STATUS_SUCCESS;
  1926. }
  1927. DBGPRINT(GPO, ("BrdgGpoRegisterForNetworkConnectionsGroupPolicyNotification\r\n"));
  1928. RtlInitUnicodeString(&RegKeyName, (LPWSTR)NetworkPoliciesKey);
  1929. //
  1930. // Read the current value from the Registry.
  1931. //
  1932. status = BrdgReadRegDWord( &RegKeyName,
  1933. (LPWSTR)BridgePolicyValue,
  1934. &RegValue);
  1935. if (NT_SUCCESS(status))
  1936. {
  1937. DBGPRINT(GPO, ("Bridge Policy Setting: %d\r\n", RegValue));
  1938. //
  1939. // Since something changed, we'll just re-verify that we're in
  1940. // the correct bridging mode.
  1941. //
  1942. BrdgGpoCheckForMatchAndUpdateMode();
  1943. }
  1944. //
  1945. // We don't want to allocate these twice, so we first try to find an existing notify struct.
  1946. //
  1947. status = BrdgGpoFindNotify( BrdgGpoGetNotifyListHead(),
  1948. BrdgGpoGetNotifyListLock(),
  1949. L"NetworkConnectionsGroupPolicies",
  1950. &Notify);
  1951. if (NT_SUCCESS(status))
  1952. {
  1953. if (STATUS_OBJECT_NAME_EXISTS != status)
  1954. {
  1955. status = BrdgGpoAllocateAndInitializeNotifyStruct(&Notify);
  1956. if (NT_SUCCESS(status))
  1957. {
  1958. status = BrdgGpoBuildNotifyForRegKeyChange( Notify,
  1959. L"NetworkConnectionsGroupPolicies",
  1960. (LPWSTR)NetworkPoliciesKey,
  1961. (LPWSTR)BridgePolicyValue,
  1962. BrdgGpoRegNotify,
  1963. (PVOID)(UINT_PTR)(unsigned int)DelayedWorkQueue,
  1964. REG_NOTIFY_CHANGE_LAST_SET,
  1965. FALSE,
  1966. BrdgGpoNetworkConnectionsGroupPolicyChangeCallback,
  1967. TRUE,
  1968. &g_BrdgGpoGlobals.RegisteredForNetworkConnectionsGroupPolicyChanges,
  1969. NULL);
  1970. }
  1971. }
  1972. if (!NT_SUCCESS(status))
  1973. {
  1974. DBGPRINT(GPO, ("Unable to register for notification on %S. Status: 0x%x\r\n", NetworkPoliciesKey, status));
  1975. BrdgGpoFreeNotifyStructAndData(Notify);
  1976. Notify = NULL;
  1977. }
  1978. else
  1979. {
  1980. SAFEASSERT(Notify);
  1981. status = BrdgGpoRequestNotification(Notify);
  1982. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  1983. {
  1984. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  1985. {
  1986. BrdgDecrementWaitRef(&Notify->RefCount);
  1987. BrdgGpoFreeNotifyStructAndData(Notify);
  1988. Notify = NULL;
  1989. }
  1990. }
  1991. else if (!NT_SUCCESS(status))
  1992. {
  1993. BrdgGpoFreeNotifyStructAndData(Notify);
  1994. Notify = NULL;
  1995. }
  1996. }
  1997. }
  1998. #if DBG
  1999. if (Notify)
  2000. {
  2001. SAFEASSERT(Notify->ListEntry.Blink && Notify->ListEntry.Flink);
  2002. }
  2003. #endif
  2004. return status;
  2005. }
  2006. // ===========================================================================
  2007. //
  2008. // REGISTRY CHANGE CALLBACK FUNCTIONS
  2009. //
  2010. // ===========================================================================
  2011. VOID
  2012. BrdgGpoTcpipInterfacesChangeCallback(
  2013. PBRDG_GPO_NOTIFY_KEY Notify
  2014. )
  2015. /*++
  2016. Routine Description:
  2017. Called back if the an the TcpIp interfaces key changes for
  2018. and adapter that we're interested in (any Non-NdisWan adapter).
  2019. Arguments:
  2020. Notify - Notify structure that we passed in
  2021. to ZwNotifyChangeKey
  2022. Return Value:
  2023. None.
  2024. --*/
  2025. {
  2026. NTSTATUS status;
  2027. PWCHAR RegValue;
  2028. ULONG StringLen = 0;
  2029. DBGPRINT(GPO, ("BrdgGpoTcpipInterfacesChangeCallback\r\n"));
  2030. DBGPRINT(GPO, ("Called for Key: %S re-registering.\r\n", Notify->RegKeyName.Buffer));
  2031. //
  2032. // Read the current value from the Registry.
  2033. //
  2034. status = BrdgReadRegUnicode(&Notify->RegKeyName,
  2035. Notify->RegValue.Buffer,
  2036. &RegValue,
  2037. &StringLen);
  2038. if (!NT_SUCCESS(status))
  2039. {
  2040. status = BrdgGpoGetCurrentNetwork( &Notify->RegKeyName,
  2041. &RegValue);
  2042. if (NT_SUCCESS(status))
  2043. {
  2044. StringLen = (UINT)wcslen(RegValue);
  2045. }
  2046. }
  2047. if (NT_SUCCESS(status))
  2048. {
  2049. PBRDG_GPO_NETWORKS Network;
  2050. LPWSTR NetworkName;
  2051. DBGPRINT(GPO, ("Current Network: %S\r\n", RegValue));
  2052. NetworkName = ExAllocatePoolWithTag(NonPagedPool, (StringLen + 1) * sizeof(WCHAR), 'gdrB');
  2053. if (NULL != NetworkName)
  2054. {
  2055. RtlZeroMemory(NetworkName, (StringLen + 1) * sizeof(WCHAR));
  2056. wcscpy(NetworkName, RegValue);
  2057. //
  2058. // Try to find a match for the current network identifier (generally the adapter guid)
  2059. //
  2060. status = BrdgGpoFindNetwork(g_BrdgGpoGlobals.ListHeadNetworks,
  2061. &Notify->Identifier,
  2062. g_BrdgGpoGlobals.NetworkListLock,
  2063. &Network);
  2064. if (STATUS_NOT_FOUND == status)
  2065. {
  2066. //
  2067. // No match so this is a new key (very unlikely code path).
  2068. //
  2069. status = BrdgGpoAllocateAndInitializeNetwork( &Network,
  2070. Notify->Identifier.Buffer,
  2071. NetworkName);
  2072. if (NT_SUCCESS(status))
  2073. {
  2074. status = BrdgGpoInsertNetwork( g_BrdgGpoGlobals.ListHeadNetworks,
  2075. &Network->ListEntry,
  2076. g_BrdgGpoGlobals.NetworkListLock);
  2077. if (!NT_SUCCESS(status))
  2078. {
  2079. BrdgGpoFreeNetworkAndData(Network);
  2080. Network = NULL;
  2081. }
  2082. }
  2083. }
  2084. else
  2085. {
  2086. //
  2087. // This is expected to happen most times, if not always.
  2088. //
  2089. status = BrdgGpoUpdateNetworkName( g_BrdgGpoGlobals.ListHeadNetworks,
  2090. &Notify->Identifier,
  2091. NetworkName,
  2092. g_BrdgGpoGlobals.NetworkListLock);
  2093. }
  2094. #if DBG
  2095. if (Network)
  2096. {
  2097. SAFEASSERT(Network->ListEntry.Blink && Network->ListEntry.Flink);
  2098. }
  2099. #endif
  2100. if (NetworkName)
  2101. {
  2102. ExFreePool(NetworkName);
  2103. }
  2104. NdisFreeMemory(RegValue, StringLen, 0);
  2105. }
  2106. }
  2107. else
  2108. {
  2109. //
  2110. // We change the name to NULL since the key appears to have disappeared.
  2111. //
  2112. status = BrdgGpoUpdateNetworkName( g_BrdgGpoGlobals.ListHeadNetworks,
  2113. &Notify->Identifier,
  2114. NULL,
  2115. g_BrdgGpoGlobals.NetworkListLock);
  2116. }
  2117. //
  2118. // Since something changed, we'll just re-verify that we're in
  2119. // the correct bridging mode.
  2120. //
  2121. BrdgGpoCheckForMatchAndUpdateMode();
  2122. //
  2123. // We set this to NULL if we're closing it for shutdown, since we
  2124. // shouldn't close it twices/
  2125. //
  2126. if (Notify->RegKey)
  2127. {
  2128. ZwClose(Notify->RegKey);
  2129. Notify->RegKey = NULL;
  2130. }
  2131. if (TRUE == Notify->Recurring)
  2132. {
  2133. //
  2134. // Re-register. The notify object contains enough info to do this.
  2135. //
  2136. status = BrdgGpoRequestNotification(Notify);
  2137. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  2138. {
  2139. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  2140. {
  2141. BrdgDecrementWaitRef(&Notify->RefCount);
  2142. BrdgGpoFreeNotifyStructAndData(Notify);
  2143. Notify = NULL;
  2144. }
  2145. }
  2146. else if (!NT_SUCCESS(status))
  2147. {
  2148. BrdgGpoFreeNotifyStructAndData(Notify);
  2149. Notify = NULL;
  2150. }
  2151. }
  2152. }
  2153. VOID
  2154. BrdgGpoWindowsGroupPolicyChangeCallback(
  2155. PBRDG_GPO_NOTIFY_KEY Notify
  2156. )
  2157. /*++
  2158. Routine Description:
  2159. Called back if the Windows Group Policy key changes.
  2160. We attempt to register for the Network Connections key changes
  2161. if we haven't already done so.
  2162. Arguments:
  2163. Notify - Notify structure that we passed in
  2164. to ZwNotifyChangeKey
  2165. Return Value:
  2166. None.
  2167. --*/
  2168. {
  2169. DBGPRINT(GPO, ("BrdgGpoWindowsGroupPolicyChangeCallback\r\n"));
  2170. if (!g_BrdgGpoGlobals.RegisteredForNetworkConnectionsGroupPolicyChanges)
  2171. {
  2172. BrdgGpoRegisterForNetworkConnectionsGroupPolicyNotification();
  2173. }
  2174. //
  2175. // We set this to NULL if we're closing it for shutdown, since we
  2176. // shouldn't close it twices/
  2177. //
  2178. if (Notify->RegKey)
  2179. {
  2180. ZwClose(Notify->RegKey);
  2181. Notify->RegKey = NULL;
  2182. }
  2183. if (TRUE == Notify->Recurring)
  2184. {
  2185. NTSTATUS status;
  2186. status = BrdgGpoRequestNotification(Notify);
  2187. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  2188. {
  2189. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  2190. {
  2191. BrdgDecrementWaitRef(&Notify->RefCount);
  2192. BrdgGpoFreeNotifyStructAndData(Notify);
  2193. Notify = NULL;
  2194. }
  2195. }
  2196. else if (!NT_SUCCESS(status))
  2197. {
  2198. BrdgGpoFreeNotifyStructAndData(Notify);
  2199. Notify = NULL;
  2200. }
  2201. }
  2202. }
  2203. VOID
  2204. BrdgGpoHiveListCallback(
  2205. IN PBRDG_GPO_NOTIFY_KEY Notify
  2206. )
  2207. /*++
  2208. Routine Description:
  2209. Called back if the HiveList key changes.
  2210. If it does, we attempt to open the software hive. If that succeeds then
  2211. we attempt to register for the keys that we're interested in under
  2212. the Software Hive.
  2213. Arguments:
  2214. Notify - Notify structure that we passed in
  2215. to ZwNotifyChangeKey
  2216. Return Value:
  2217. None.
  2218. --*/
  2219. {
  2220. NTSTATUS status;
  2221. UNICODE_STRING Software;
  2222. OBJECT_ATTRIBUTES ObAttr;
  2223. HANDLE hKey;
  2224. DBGPRINT(GPO, ("BrdgGpoHiveListCallback\r\n"));
  2225. RtlInitUnicodeString(&Software, SoftwareHiveKey);
  2226. InitializeObjectAttributes( &ObAttr,
  2227. &Software,
  2228. OBJ_CASE_INSENSITIVE,
  2229. NULL,
  2230. NULL
  2231. );
  2232. status = ZwOpenKey(&hKey, KEY_READ, &ObAttr);
  2233. if (NT_SUCCESS(status))
  2234. {
  2235. BrdgGpoRegisterForGroupPolicyNetworkNameNotification();
  2236. BrdgGpoRegisterForWindowsGroupPolicyNotification();
  2237. BrdgGpoRegisterForGroupPolicyNotification();
  2238. //
  2239. // To avoid turning the bridge on and then off again, we set this just after
  2240. // verifying the Network Connections policy setting.
  2241. //
  2242. BrdgGpoRegisterForNetworkConnectionsGroupPolicyNotification();
  2243. g_BrdgGpoGlobals.WaitingOnSoftwareHive = FALSE;
  2244. Notify->Recurring = FALSE;
  2245. ZwClose(hKey);
  2246. }
  2247. //
  2248. // We set this to NULL if we're closing it for shutdown, since we
  2249. // shouldn't close it twices/
  2250. //
  2251. if (Notify->RegKey)
  2252. {
  2253. ZwClose(Notify->RegKey);
  2254. Notify->RegKey = NULL;
  2255. }
  2256. if (TRUE == Notify->Recurring)
  2257. {
  2258. status = BrdgGpoRequestNotification(Notify);
  2259. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  2260. {
  2261. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  2262. {
  2263. BrdgDecrementWaitRef(&Notify->RefCount);
  2264. BrdgGpoFreeNotifyStructAndData(Notify);
  2265. Notify = NULL;
  2266. }
  2267. }
  2268. else if (!NT_SUCCESS(status))
  2269. {
  2270. BrdgGpoFreeNotifyStructAndData(Notify);
  2271. Notify = NULL;
  2272. }
  2273. }
  2274. }
  2275. VOID
  2276. BrdgGpoGroupPolicyChangeCallback(
  2277. PBRDG_GPO_NOTIFY_KEY Notify
  2278. )
  2279. /*++
  2280. Routine Description:
  2281. Called back if the Group Policy key changes.
  2282. Arguments:
  2283. Notify - Notify structure that we passed in
  2284. to ZwNotifyChangeKey
  2285. Return Value:
  2286. None.
  2287. --*/
  2288. {
  2289. DBGPRINT(GPO, ("BrdgGpoGroupPolicyChangeCallback\r\n"));
  2290. if (!g_BrdgGpoGlobals.RegisteredForGroupPolicyHistoryChanges)
  2291. {
  2292. BrdgGpoRegisterForGroupPolicyNetworkNameNotification();
  2293. }
  2294. //
  2295. // We set this to NULL if we're closing it for shutdown, since we
  2296. // shouldn't close it twice.
  2297. //
  2298. if (Notify->RegKey)
  2299. {
  2300. ZwClose(Notify->RegKey);
  2301. Notify->RegKey = NULL;
  2302. }
  2303. if (TRUE == Notify->Recurring)
  2304. {
  2305. NTSTATUS status;
  2306. status = BrdgGpoRequestNotification(Notify);
  2307. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  2308. {
  2309. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  2310. {
  2311. BrdgDecrementWaitRef(&Notify->RefCount);
  2312. BrdgGpoFreeNotifyStructAndData(Notify);
  2313. Notify = NULL;
  2314. }
  2315. }
  2316. else if (!NT_SUCCESS(status))
  2317. {
  2318. BrdgGpoFreeNotifyStructAndData(Notify);
  2319. Notify = NULL;
  2320. }
  2321. }
  2322. }
  2323. VOID
  2324. BrdgGpoNetworkConnectionsGroupPolicyChangeCallback(
  2325. PBRDG_GPO_NOTIFY_KEY Notify
  2326. )
  2327. /*++
  2328. Routine Description:
  2329. Called back if the Network Connection Policy key changes.
  2330. Arguments:
  2331. Notify - Notify structure that we passed in
  2332. to ZwNotifyChangeKey
  2333. Return Value:
  2334. None.
  2335. --*/
  2336. {
  2337. NTSTATUS status;
  2338. ULONG RegValue;
  2339. DBGPRINT(GPO, ("BrdgGpoNetworkConnectionsGroupPolicyChangeCallback\r\n"));
  2340. DBGPRINT(GPO, ("Called for Key: %S re-registering.\r\n", Notify->RegKeyName.Buffer));
  2341. status = BrdgReadRegDWord( &Notify->RegKeyName,
  2342. Notify->RegValue.Buffer,
  2343. &RegValue);
  2344. if (NT_SUCCESS(status))
  2345. {
  2346. DBGPRINT(GPO, ("Bridge Policy Setting: %d\r\n", RegValue));
  2347. }
  2348. //
  2349. // Since something changed, we'll just re-verify that we're in
  2350. // the correct bridging mode.
  2351. //
  2352. BrdgGpoCheckForMatchAndUpdateMode();
  2353. //
  2354. // We set this to NULL if we're closing it for shutdown, since we
  2355. // shouldn't close it twice.
  2356. //
  2357. if (Notify->RegKey)
  2358. {
  2359. ZwClose(Notify->RegKey);
  2360. Notify->RegKey = NULL;
  2361. }
  2362. if (TRUE == Notify->Recurring)
  2363. {
  2364. status = BrdgGpoRequestNotification(Notify);
  2365. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  2366. {
  2367. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  2368. {
  2369. BrdgDecrementWaitRef(&Notify->RefCount);
  2370. BrdgGpoFreeNotifyStructAndData(Notify);
  2371. Notify = NULL;
  2372. }
  2373. }
  2374. else if (!NT_SUCCESS(status))
  2375. {
  2376. BrdgGpoFreeNotifyStructAndData(Notify);
  2377. Notify = NULL;
  2378. }
  2379. }
  2380. }
  2381. NTSTATUS
  2382. BrdgGpoUpdateGroupPolicyNetworkName()
  2383. {
  2384. NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
  2385. PWCHAR RegValue = NULL;
  2386. LPWSTR GroupPolicyNetwork = NULL;
  2387. ULONG DataLen = 0;
  2388. UNICODE_STRING RegKeyName;
  2389. RtlInitUnicodeString(&RegKeyName, HistoryKey);
  2390. //
  2391. // Read the current value from the registry
  2392. //
  2393. status = BrdgReadRegUnicode(&RegKeyName,
  2394. L"NetworkName",
  2395. &RegValue,
  2396. &DataLen);
  2397. if (NT_SUCCESS(status))
  2398. {
  2399. DBGPRINT(GPO, ("Group Policy Network Name: %S\r\n", RegValue));
  2400. //
  2401. // Almost always checked at DISPATCH_LEVEL, so we allocate from NonPagedPool
  2402. //
  2403. GroupPolicyNetwork = ExAllocatePoolWithTag(NonPagedPool, (DataLen + 1) * sizeof(WCHAR), 'gdrB');
  2404. if (GroupPolicyNetwork)
  2405. {
  2406. if (NULL != g_BrdgGpoGlobals.GroupPolicyNetworkName.Buffer)
  2407. {
  2408. ExFreePool( g_BrdgGpoGlobals.GroupPolicyNetworkName.Buffer);
  2409. }
  2410. RtlZeroMemory(GroupPolicyNetwork, (DataLen + 1) * sizeof(WCHAR));
  2411. wcsncpy(GroupPolicyNetwork, RegValue, DataLen);
  2412. RtlInitUnicodeString(&g_BrdgGpoGlobals.GroupPolicyNetworkName, GroupPolicyNetwork);
  2413. //
  2414. // Since something changed, we'll just re-verify that we're in
  2415. // the correct bridging mode.
  2416. //
  2417. BrdgGpoCheckForMatchAndUpdateMode();
  2418. }
  2419. NdisFreeMemory(RegValue, DataLen, 0);
  2420. }
  2421. return status;
  2422. }
  2423. VOID
  2424. BrdgGpoGroupPolicyNetworkNameChangeCallback(
  2425. PBRDG_GPO_NOTIFY_KEY Notify
  2426. )
  2427. /*++
  2428. Routine Description:
  2429. Called back if the Group Policy History key changes.
  2430. Arguments:
  2431. Notify - Notify structure that we passed in
  2432. to ZwNotifyChangeKey
  2433. Return Value:
  2434. None.
  2435. --*/
  2436. {
  2437. NTSTATUS status;
  2438. //
  2439. // Read the current value from the registry
  2440. //
  2441. status = BrdgGpoUpdateGroupPolicyNetworkName();
  2442. //
  2443. // We set this to NULL if we're closing it for shutdown, since we
  2444. // shouldn't close it twice.
  2445. //
  2446. if (Notify->RegKey)
  2447. {
  2448. ZwClose(Notify->RegKey);
  2449. Notify->RegKey = NULL;
  2450. }
  2451. if (TRUE == Notify->Recurring)
  2452. {
  2453. status = BrdgGpoRequestNotification(Notify);
  2454. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  2455. {
  2456. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  2457. {
  2458. BrdgDecrementWaitRef(&Notify->RefCount);
  2459. BrdgGpoFreeNotifyStructAndData(Notify);
  2460. Notify = NULL;
  2461. }
  2462. }
  2463. else if (!NT_SUCCESS(status))
  2464. {
  2465. BrdgGpoFreeNotifyStructAndData(Notify);
  2466. Notify = NULL;
  2467. }
  2468. }
  2469. }
  2470. // ===========================================================================
  2471. //
  2472. // GROUP POLICY NETWORK VERIFICATION FUNCTIONS
  2473. //
  2474. // ===========================================================================
  2475. BOOLEAN
  2476. BrdgGpoAllowedToBridge()
  2477. /*++
  2478. Routine Description:
  2479. Checks the Network Connections policy key for the Bridge Policy setting.
  2480. Arguments:
  2481. None.
  2482. Return Value:
  2483. TRUE if we couldn't find a Policy Value, or the Value is 1.
  2484. FALSE if the policy exists and contains a value of 0.
  2485. --*/
  2486. {
  2487. NTSTATUS status;
  2488. UNICODE_STRING RegKey;
  2489. ULONG RegValue;
  2490. BOOLEAN CanBridge = TRUE; // If there is no key then we're allowed to bridge.
  2491. RtlInitUnicodeString(&RegKey, NetworkPoliciesKey);
  2492. status = BrdgReadRegDWord(&RegKey, (LPWSTR) BridgePolicyValue, &RegValue);
  2493. if (NT_SUCCESS(status))
  2494. {
  2495. if (FALSE == RegValue)
  2496. {
  2497. CanBridge = FALSE;
  2498. }
  2499. }
  2500. return CanBridge;
  2501. }
  2502. VOID
  2503. BrdgGpoUpdateBridgeMode(
  2504. BOOLEAN NetworkMatch
  2505. )
  2506. /*++
  2507. Routine Description:
  2508. Checks for a Network Match and if we're not allowed to bridge then
  2509. turns bridging off, otherwise it turns it on.
  2510. Arguments:
  2511. NetworkMatch - Do we have a match for the group policy network?
  2512. Return Value:
  2513. None.
  2514. --*/
  2515. {
  2516. //
  2517. // If we're still waiting on the software hive then
  2518. // we shouldn't do any further processing for this.
  2519. //
  2520. if (BrdgGpoWaitingOnSoftwareHive())
  2521. {
  2522. return;
  2523. }
  2524. if (NetworkMatch && !BrdgGpoAllowedToBridge())
  2525. {
  2526. BrdgFwdChangeBridging(FALSE);
  2527. }
  2528. else
  2529. {
  2530. BrdgFwdChangeBridging(TRUE);
  2531. }
  2532. }
  2533. VOID
  2534. BrdgGpoCheckForMatchAndUpdateMode()
  2535. /*++
  2536. Routine Description:
  2537. This looks for a matching network and group policy network and
  2538. attempts to update the bridging status accordingly.
  2539. Arguments:
  2540. None.
  2541. Return Value:
  2542. None.
  2543. --*/
  2544. {
  2545. NTSTATUS status;
  2546. if (NULL != g_BrdgGpoGlobals.ListHeadNetworks)
  2547. {
  2548. status = BrdgGpoMatchNetworkName( g_BrdgGpoGlobals.ListHeadNetworks,
  2549. &g_BrdgGpoGlobals.GroupPolicyNetworkName,
  2550. g_BrdgGpoGlobals.NetworkListLock);
  2551. if (BRDG_STATUS_EMPTY_LIST != status)
  2552. {
  2553. if (STATUS_SUCCESS == status)
  2554. {
  2555. //
  2556. // We found a match. Check if we're allowed to run.
  2557. //
  2558. BrdgGpoUpdateBridgeMode(BRDG_ON_SAME_NETWORK);
  2559. }
  2560. else if (STATUS_NO_MATCH == status)
  2561. {
  2562. //
  2563. // No match, but we may need to turn bridging back on.
  2564. //
  2565. BrdgGpoUpdateBridgeMode(BRDG_ON_DIFFERENT_NETWORK);
  2566. }
  2567. else
  2568. {
  2569. // We should never get here.
  2570. SAFEASSERT(FALSE);
  2571. }
  2572. }
  2573. else if (BrdgGpoAllowedToBridge())
  2574. {
  2575. BrdgFwdChangeBridging(TRUE);
  2576. }
  2577. }
  2578. }
  2579. NTSTATUS BrdgGpoGetCurrentNetwork(
  2580. IN PUNICODE_STRING RegKeyName,
  2581. OUT PWCHAR* NetworkName)
  2582. /*++
  2583. Routine Description:
  2584. Determines the current network that we are on. This either uses the DHCP Domain name,
  2585. or the IP Address ANDed with the Subnet mask.
  2586. For example: 10.251.1.3 AND 255.0.0.0 results in a network of 10.0.0.0
  2587. This routine MUST be called at IRQL = PASSIVE_LEVEL.
  2588. Arguments:
  2589. RegKeyName (IN) - The RegistryKey for the adapter we're interested in.
  2590. NetworkName (OUT) - The network we're currently one.
  2591. Return Value(s):
  2592. STATUS_SUCCESS
  2593. STATUS_INVALID_PARAMETER
  2594. STATUS_NO_IP_ADDRESSES - if we've released the only address we have.
  2595. Out of memory can also be returned.
  2596. --*/
  2597. {
  2598. NTSTATUS status;
  2599. PWCHAR lpszNetworkName = NULL;
  2600. BOOLEAN HaveNetwork = FALSE;
  2601. BOOLEAN HaveDhcpDomain = FALSE;
  2602. WCHAR BaseNetwork[MAX_IP4_STRING_LEN];
  2603. PWCHAR DhcpIPAddress = NULL;
  2604. ULONG DhcpIPAddrLen = 0;
  2605. if (!RegKeyName || !NetworkName)
  2606. {
  2607. return STATUS_INVALID_PARAMETER;
  2608. }
  2609. RtlZeroMemory(BaseNetwork, MAX_IP4_STRING_LEN * sizeof(WCHAR));
  2610. *NetworkName = NULL;
  2611. //
  2612. // We don't have a valid Network Name. Attempt to build one
  2613. // from the DhcpIPAddess and DhcpSubnetMask.
  2614. //
  2615. status = BrdgReadRegUnicode(RegKeyName,
  2616. L"DhcpIPAddress",
  2617. &DhcpIPAddress,
  2618. &DhcpIPAddrLen);
  2619. if (NT_SUCCESS(status))
  2620. {
  2621. PWCHAR DhcpSubnetMask = NULL;
  2622. ULONG DhcpSubnetMaskLen = 0;
  2623. status = BrdgReadRegUnicode(RegKeyName,
  2624. L"DhcpSubnetMask",
  2625. &DhcpSubnetMask,
  2626. &DhcpSubnetMaskLen);
  2627. if (NT_SUCCESS(status))
  2628. {
  2629. LPWSTR Terminator;
  2630. in_addr ipaddr;
  2631. in_addr subnet;
  2632. //
  2633. // We and the two values together to get the Network.
  2634. // For example: 10.251.1.3 AND 255.0.0.0 gives 10.0.0.0
  2635. //
  2636. status = BrdgTdiIpv4StringToAddress(DhcpIPAddress,
  2637. FALSE,
  2638. &Terminator,
  2639. &ipaddr);
  2640. if (NT_SUCCESS(status))
  2641. {
  2642. in_addr network;
  2643. status = BrdgTdiIpv4StringToAddress(DhcpSubnetMask,
  2644. FALSE,
  2645. &Terminator,
  2646. &subnet);
  2647. network.S_un.S_addr = ipaddr.S_un.S_addr & subnet.S_un.S_addr;
  2648. DBGPRINT(GPO,
  2649. ("in_addr = %u.%u.%u.%u\r\n",
  2650. network.S_un.S_un_b.s_b1, network.S_un.S_un_b.s_b2,
  2651. network.S_un.S_un_b.s_b3, network.S_un.S_un_b.s_b4));
  2652. //
  2653. // Do we have a valid IPaddress
  2654. //
  2655. if (0 != ipaddr.S_un.S_addr)
  2656. {
  2657. _snwprintf( BaseNetwork,
  2658. MAX_IP4_STRING_LEN,
  2659. L"%u.%u.%u.%u",
  2660. network.S_un.S_un_b.s_b1,
  2661. network.S_un.S_un_b.s_b2,
  2662. network.S_un.S_un_b.s_b3,
  2663. network.S_un.S_un_b.s_b4);
  2664. HaveNetwork = TRUE;
  2665. }
  2666. }
  2667. }
  2668. }
  2669. if (!HaveNetwork)
  2670. {
  2671. PWCHAR IPAddress = NULL;
  2672. ULONG IPAddrLen = 0;
  2673. status = BrdgReadRegUnicode(RegKeyName,
  2674. L"IPAddress",
  2675. &IPAddress,
  2676. &IPAddrLen);
  2677. if (NT_SUCCESS(status))
  2678. {
  2679. PWCHAR SubnetMask = NULL;
  2680. ULONG SubnetMaskLen = 0;
  2681. status = BrdgReadRegUnicode(RegKeyName,
  2682. L"SubnetMask",
  2683. &SubnetMask,
  2684. &SubnetMaskLen);
  2685. if (NT_SUCCESS(status))
  2686. {
  2687. LPWSTR Terminator;
  2688. in_addr ipaddr;
  2689. in_addr subnet;
  2690. //
  2691. // We and the two values together to get the Network.
  2692. // For example: 10.251.1.3 AND 255.0.0.0 gives 10.0.0.0
  2693. //
  2694. status = BrdgTdiIpv4StringToAddress(IPAddress,
  2695. FALSE,
  2696. &Terminator,
  2697. &ipaddr);
  2698. if (NT_SUCCESS(status))
  2699. {
  2700. in_addr network;
  2701. status = BrdgTdiIpv4StringToAddress(SubnetMask,
  2702. FALSE,
  2703. &Terminator,
  2704. &subnet);
  2705. network.S_un.S_addr = ipaddr.S_un.S_addr & subnet.S_un.S_addr;
  2706. DBGPRINT(GPO,
  2707. ("in_addr = %u.%u.%u.%u\r\n",
  2708. network.S_un.S_un_b.s_b1, network.S_un.S_un_b.s_b2,
  2709. network.S_un.S_un_b.s_b3, network.S_un.S_un_b.s_b4));
  2710. //
  2711. // Do we have a valid IPaddress
  2712. //
  2713. if (0 != ipaddr.S_un.S_addr)
  2714. {
  2715. _snwprintf( BaseNetwork,
  2716. MAX_IP4_STRING_LEN,
  2717. L"%u.%u.%u.%u",
  2718. network.S_un.S_un_b.s_b1,
  2719. network.S_un.S_un_b.s_b2,
  2720. network.S_un.S_un_b.s_b3,
  2721. network.S_un.S_un_b.s_b4);
  2722. HaveNetwork = TRUE;
  2723. }
  2724. }
  2725. }
  2726. }
  2727. }
  2728. if (!HaveNetwork)
  2729. {
  2730. //
  2731. // Returning this will cause us not to update the network name this
  2732. // card.
  2733. //
  2734. status = STATUS_NO_IP_ADDRESSES;
  2735. }
  2736. else if (HaveDhcpDomain)
  2737. {
  2738. *NetworkName = lpszNetworkName;
  2739. status = STATUS_SUCCESS;
  2740. }
  2741. else
  2742. {
  2743. status = NdisAllocateMemoryWithTag(NetworkName,
  2744. ((UINT)wcslen(BaseNetwork) + 1) * sizeof(WCHAR),
  2745. 'gdrB');
  2746. wcscpy(*NetworkName, BaseNetwork);
  2747. }
  2748. return status;
  2749. }
  2750. // ===========================================================================
  2751. //
  2752. // NETWORK LIST MANIPULATION FUNCTIONS
  2753. //
  2754. // ===========================================================================
  2755. NTSTATUS
  2756. BrdgGpoInitializeNetworkList()
  2757. /*++
  2758. Routine Description:
  2759. Initializes the Network List and Lock.
  2760. This can can be called at any IRQL (but since it's called from driver entry,
  2761. it will most likely be called at PASSIVE_LEVEL).
  2762. Arguments:
  2763. None.
  2764. Return Value(s):
  2765. STATUS_SUCCESS
  2766. STATUS_INSUFFICIENT_RESOURCES
  2767. --*/
  2768. {
  2769. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  2770. g_BrdgGpoGlobals.ListHeadNetworks = ExAllocatePoolWithTag(NonPagedPool, sizeof(LIST_ENTRY), 'gdrB');
  2771. if (NULL != g_BrdgGpoGlobals.ListHeadNetworks)
  2772. {
  2773. InitializeListHead(g_BrdgGpoGlobals.ListHeadNetworks);
  2774. g_BrdgGpoGlobals.NetworkListLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(NDIS_RW_LOCK), 'gdrB');
  2775. if (g_BrdgGpoGlobals.NetworkListLock)
  2776. {
  2777. NdisInitializeReadWriteLock(g_BrdgGpoGlobals.NetworkListLock);
  2778. status = STATUS_SUCCESS;
  2779. }
  2780. else
  2781. {
  2782. ExFreePool(g_BrdgGpoGlobals.ListHeadNetworks);
  2783. }
  2784. }
  2785. return status;
  2786. }
  2787. VOID
  2788. BrdgGpoUninitializeNetworkList()
  2789. /*++
  2790. Routine Description:
  2791. Frees the memory associated with the Network List.
  2792. This can be called at IRQL <= DISPATCH_LEVEL but is likely
  2793. to be called at PASSIVE_LEVEL as it's during shutdown.
  2794. Arguments:
  2795. None.
  2796. Return Value:
  2797. None.
  2798. --*/
  2799. {
  2800. ExFreePool(g_BrdgGpoGlobals.ListHeadNetworks);
  2801. ExFreePool(g_BrdgGpoGlobals.NetworkListLock);
  2802. }
  2803. VOID
  2804. BrdgGpoAcquireNetworkListLock(
  2805. IN PNDIS_RW_LOCK NetworkListLock,
  2806. IN BOOLEAN fWrite,
  2807. IN OUT PLOCK_STATE LockState
  2808. )
  2809. /*++
  2810. Routine Description:
  2811. Acquires the NetworkList read-write lock. We support a NULL Lock
  2812. as it allows us to acquire for write and then call functions that
  2813. need the lock for read without locking up the system (by
  2814. supplying NULL for the lock).
  2815. This can be called at IRQL <= DISPATCH_LEVEL
  2816. Arguments:
  2817. NetworkListLock - Read-Write Lock to be acquired.
  2818. fWrite - TRUE == Write Access, FALSE == Read Access
  2819. LockState - Opaque value used by NDIS.
  2820. Return Value:
  2821. None.
  2822. --*/
  2823. {
  2824. if (NetworkListLock)
  2825. {
  2826. NdisAcquireReadWriteLock(NetworkListLock, fWrite, LockState);
  2827. }
  2828. }
  2829. VOID
  2830. BrdgGpoReleaseNetworkListLock(
  2831. IN PNDIS_RW_LOCK NetworkListLock,
  2832. IN OUT PLOCK_STATE LockState
  2833. )
  2834. /*++
  2835. Routine Description:
  2836. Releases the NetworkList read-write lock. We support a NULL Lock
  2837. as it allows us to acquire for write and then call functions that
  2838. need the lock for read without locking up the system (by
  2839. supplying NULL for the lock).
  2840. This can be called at IRQL <= DISPATCH_LEVEL
  2841. Arguments:
  2842. NetworkListLock - Read-Write Lock to be released.
  2843. LockState - Opaque value used by NDIS.
  2844. Return Value:
  2845. None.
  2846. --*/
  2847. {
  2848. if (NetworkListLock)
  2849. {
  2850. NdisReleaseReadWriteLock(NetworkListLock, LockState);
  2851. }
  2852. }
  2853. NTSTATUS
  2854. BrdgGpoAllocateAndInitializeNetwork(
  2855. IN OUT PBRDG_GPO_NETWORKS* Network,
  2856. IN PWCHAR Identifier,
  2857. IN PWCHAR NetworkName
  2858. )
  2859. /*++
  2860. Routine Description:
  2861. Allocates the memory needed for a Network structure from the NonPaged pool
  2862. and copies the data into the structure.
  2863. Must be called at IRQL <= APC_LEVEL.
  2864. Arguments:
  2865. Network - The structure to be allocated and initialized with the data.
  2866. Identifier - The AdapterID for this network structure.
  2867. NetworkName - The current network that we are on. This can be NULL if we
  2868. haven't determined a network yet.
  2869. Return Value:
  2870. STATUS_SUCCESS
  2871. STATUS_INSUFFICIENT_RESOURCES
  2872. --*/
  2873. {
  2874. PBRDG_GPO_NETWORKS pNetwork;
  2875. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  2876. *Network = NULL;
  2877. if (!BrdgGpoProcessingNotifications())
  2878. {
  2879. return STATUS_SHUTDOWN_IN_PROGRESS;
  2880. }
  2881. //
  2882. // Everything in this struct will be used at DISPATCH_LEVEL, so all of it is
  2883. // allocated from the NonPagedPool
  2884. //
  2885. pNetwork = ExAllocatePoolWithTag(NonPagedPool, sizeof(BRDG_GPO_NETWORKS), 'gdrB');
  2886. if (NULL != pNetwork)
  2887. {
  2888. PUNICODE_STRING pIdentifier = NULL;
  2889. PUNICODE_STRING pNetworkName = NULL;
  2890. LPWSTR lpszIdentifier = NULL;
  2891. LPWSTR lpszNetworkName = NULL;
  2892. pIdentifier = ExAllocatePoolWithTag(NonPagedPool, sizeof(UNICODE_STRING), 'gdrB');
  2893. if (pIdentifier)
  2894. {
  2895. pNetworkName = ExAllocatePoolWithTag(NonPagedPool, sizeof(UNICODE_STRING), 'gdrB');
  2896. if (pNetworkName)
  2897. {
  2898. lpszIdentifier = ExAllocatePoolWithTag(NonPagedPool, (wcslen(Identifier) + 1) * sizeof(WCHAR), 'gdrB');
  2899. if (lpszIdentifier)
  2900. {
  2901. RtlZeroMemory(lpszIdentifier, wcslen(Identifier) + 1);
  2902. wcscpy(lpszIdentifier, Identifier);
  2903. //
  2904. // A NULL Network name is valid, so we only allocate it if we are passed one.
  2905. //
  2906. if (NetworkName)
  2907. {
  2908. lpszNetworkName = ExAllocatePoolWithTag(NonPagedPool, (wcslen(NetworkName) + 1) * sizeof(WCHAR), 'gdrB');
  2909. if (lpszNetworkName)
  2910. {
  2911. RtlZeroMemory(lpszNetworkName, wcslen(NetworkName) + 1);
  2912. wcscpy(lpszNetworkName, NetworkName);
  2913. }
  2914. }
  2915. //
  2916. // This is a Logical AND operation:
  2917. // Either we have both or we have neither. We can't have one and not the other, if we do
  2918. // then we didn't succeed the last allocate.
  2919. //
  2920. if ((NetworkName && lpszNetworkName) || (!NetworkName && !lpszNetworkName))
  2921. {
  2922. RtlInitUnicodeString(pIdentifier, lpszIdentifier);
  2923. //
  2924. // This may be NULL, but that's fine, since it means we'll add it when it gets written.
  2925. //
  2926. RtlInitUnicodeString(pNetworkName, lpszNetworkName);
  2927. pNetwork->Identifier = pIdentifier;
  2928. pNetwork->NetworkName = pNetworkName;
  2929. pNetwork->ListEntry.Blink = NULL;
  2930. pNetwork->ListEntry.Flink = NULL;
  2931. *Network = pNetwork;
  2932. status = STATUS_SUCCESS;
  2933. }
  2934. }
  2935. }
  2936. }
  2937. if (!NT_SUCCESS(status))
  2938. {
  2939. if (lpszIdentifier)
  2940. {
  2941. ExFreePool(lpszIdentifier);
  2942. }
  2943. if (pIdentifier)
  2944. {
  2945. ExFreePool(pIdentifier);
  2946. }
  2947. if (pNetworkName)
  2948. {
  2949. ExFreePool(pNetworkName);
  2950. }
  2951. if (pNetwork)
  2952. {
  2953. ExFreePool(pNetwork);
  2954. }
  2955. }
  2956. }
  2957. return status;
  2958. }
  2959. VOID
  2960. BrdgGpoFreeNetworkAndData(
  2961. IN PBRDG_GPO_NETWORKS Network)
  2962. /*++
  2963. Routine Description:
  2964. This frees any data associated with a particular network.
  2965. This can be called IRQL <= DISPATCH_LEVEL.
  2966. Arguments:
  2967. Network - Structure containing an ID and Network name
  2968. for an adapter.
  2969. Return Value:
  2970. None.
  2971. --*/
  2972. {
  2973. //
  2974. // First free the data associated with this entry
  2975. //
  2976. if (Network->Identifier)
  2977. {
  2978. if (Network->Identifier->Buffer)
  2979. {
  2980. ExFreePool(Network->Identifier->Buffer);
  2981. }
  2982. ExFreePool(Network->Identifier);
  2983. }
  2984. if (Network->NetworkName)
  2985. {
  2986. if (Network->NetworkName->Buffer)
  2987. {
  2988. ExFreePool(Network->NetworkName->Buffer);
  2989. }
  2990. ExFreePool(Network->NetworkName);
  2991. }
  2992. //
  2993. // Now free the structure
  2994. //
  2995. ExFreePool(Network);
  2996. }
  2997. NTSTATUS
  2998. BrdgGpoEmptyNetworkList(
  2999. IN PLIST_ENTRY NetworkList,
  3000. IN PNDIS_RW_LOCK NetworkListLock)
  3001. /*++
  3002. Routine Description:
  3003. Empties the existing list and frees all the items.
  3004. Do not acquire the list lock before calling this function.
  3005. Arguments:
  3006. NetworkList - The list of current networks.
  3007. NetworkListLock - Ndis Read Write Lock for synchronizing changes to the list.
  3008. Return Value:
  3009. STATUS_SUCCESS
  3010. --*/
  3011. {
  3012. NTSTATUS status = STATUS_SUCCESS;
  3013. LOCK_STATE LockState;
  3014. BrdgGpoAcquireNetworkListLock(NetworkListLock, TRUE /* Write-access */, &LockState);
  3015. //
  3016. // Loop through the list deleting the entries.
  3017. //
  3018. while (!IsListEmpty(NetworkList))
  3019. {
  3020. PBRDG_GPO_NETWORKS Network;
  3021. PLIST_ENTRY pListEntry;
  3022. pListEntry = RemoveHeadList(NetworkList);
  3023. Network = CONTAINING_RECORD(pListEntry, BRDG_GPO_NETWORKS, ListEntry);
  3024. BrdgGpoFreeNetworkAndData(Network);
  3025. }
  3026. BrdgGpoReleaseNetworkListLock(NetworkListLock, &LockState);
  3027. return status;
  3028. }
  3029. NTSTATUS
  3030. BrdgGpoInsertNetwork(
  3031. IN PLIST_ENTRY NetworkList,
  3032. IN PLIST_ENTRY Network,
  3033. IN PNDIS_RW_LOCK NetworkListLock)
  3034. /*++
  3035. Routine Description:
  3036. This routine is responsible for adding a new Network to the list.
  3037. If someone attempts to insert an existing item, an error is returned.
  3038. The caller is responsible for calling BrdgGpoUpdateNetworkName instead.
  3039. This routine can be called at IRQL <= DISPATCH_LEVEL.
  3040. Arguments:
  3041. NetworkList - The list of current networks.
  3042. Network - The new Network entry to add to the list.
  3043. NetworkListLock - Ndis Read Write Lock for synchronizing changes to the list.
  3044. Return Value:
  3045. STATUS_SHUTDOWN_IN_PROGRESS - We're busy shutting down, so the item was not added.
  3046. STATUS_INVALID_PARAMETER - One or more of the parameters was NULL.
  3047. STATUS_DUPLICATE_NAME - This entry already exists in the list.
  3048. STATUS_SUCCESS - We successfully added the entry to the list.
  3049. --*/
  3050. {
  3051. PBRDG_GPO_NETWORKS pNetwork = NULL;
  3052. PBRDG_GPO_NETWORKS NewNetwork = NULL;
  3053. LOCK_STATE LockState;
  3054. NTSTATUS status;
  3055. BOOLEAN ShuttingDown;
  3056. if (!NetworkList || !Network || !NetworkListLock)
  3057. {
  3058. return STATUS_INVALID_PARAMETER;
  3059. }
  3060. //
  3061. // Lock the list for update
  3062. //
  3063. BrdgGpoAcquireNetworkListLock(NetworkListLock, TRUE /* Write-access */, &LockState);
  3064. ShuttingDown = !BrdgGpoProcessingNotifications();
  3065. if (!ShuttingDown)
  3066. {
  3067. NewNetwork = CONTAINING_RECORD(Network, BRDG_GPO_NETWORKS, ListEntry);
  3068. //
  3069. // We do this to prevent us accidentally inserting a duplicate item. We grab the lock before so that
  3070. // we can't insert the same item twice.
  3071. //
  3072. status = BrdgGpoFindNetwork( NetworkList,
  3073. NewNetwork->Identifier,
  3074. NULL, // We have already grabbed the lock for Write access.
  3075. &pNetwork);
  3076. if (STATUS_NOT_FOUND == status)
  3077. {
  3078. InsertTailList(NetworkList, Network);
  3079. status = STATUS_SUCCESS;
  3080. }
  3081. else if (STATUS_SUCCESS == status)
  3082. {
  3083. status = STATUS_DUPLICATE_NAME;
  3084. }
  3085. }
  3086. else
  3087. {
  3088. status = STATUS_SHUTDOWN_IN_PROGRESS;
  3089. }
  3090. //
  3091. // Release the lock, we're done updating
  3092. //
  3093. BrdgGpoReleaseNetworkListLock(NetworkListLock, &LockState);
  3094. return status;
  3095. }
  3096. NTSTATUS
  3097. BrdgGpoDeleteNetwork(
  3098. IN PLIST_ENTRY NetworkList,
  3099. IN PUNICODE_STRING NetworkIdentifier,
  3100. IN PNDIS_RW_LOCK NetworkListLock)
  3101. /*++
  3102. Routine Description:
  3103. Deletes an existing network entry.
  3104. Arguments:
  3105. NetworkList - The list of current networks.
  3106. NetworkIdentifier - A unique identifier that identifies which Network entry to remove.
  3107. NetworkListLock - Ndis Read Write Lock for synchronizing changes to the list.
  3108. Return Value:
  3109. STATUS_NOT_FOUND - We couldn't find and entry matching the identifier.
  3110. STATUS_SUCCESS - We were able to remove the entry successfully.
  3111. */
  3112. {
  3113. PBRDG_GPO_NETWORKS pNetwork = NULL;
  3114. LOCK_STATE LockState;
  3115. NTSTATUS status = STATUS_NOT_FOUND;
  3116. //
  3117. // Lock the list for update
  3118. //
  3119. BrdgGpoAcquireNetworkListLock(NetworkListLock, TRUE /* Write-access */, &LockState);
  3120. //
  3121. // Find the entry;
  3122. //
  3123. status = BrdgGpoFindNetwork( NetworkList,
  3124. NetworkIdentifier,
  3125. NULL, // We have already grabbed the lock for Write access.
  3126. &pNetwork);
  3127. if (NT_SUCCESS(status))
  3128. {
  3129. RemoveEntryList(&pNetwork->ListEntry);
  3130. BrdgGpoFreeNetworkAndData(pNetwork);
  3131. pNetwork = NULL;
  3132. status = STATUS_SUCCESS;
  3133. }
  3134. //
  3135. // Release the lock, we're done updating
  3136. //
  3137. BrdgGpoReleaseNetworkListLock(NetworkListLock, &LockState);
  3138. return status;
  3139. }
  3140. NTSTATUS
  3141. BrdgGpoFindNetwork(
  3142. IN PLIST_ENTRY NetworkList,
  3143. IN PUNICODE_STRING NetworkIdentifier,
  3144. IN PNDIS_RW_LOCK NetworkListLock,
  3145. OUT PBRDG_GPO_NETWORKS* Network
  3146. )
  3147. /*++
  3148. Routine Description:
  3149. Finds a particular Network in the list of networks.
  3150. Arguments:
  3151. NetworkList - The list of current networks.
  3152. NetworkIdentifier - A unique identifier that identifies which Network entry to remove.
  3153. NetworkListLock - Ndis Read Write Lock for synchronizing changes to the list.
  3154. Network - The item if found, NULL otherwise.
  3155. Return Value:
  3156. STATUS_NOT_FOUND - No entry matching the identifier could be found.
  3157. STATUS_SUCCESS - The entry was successfully found.
  3158. --*/
  3159. {
  3160. PLIST_ENTRY pListEntry;
  3161. LOCK_STATE LockState;
  3162. NTSTATUS status = STATUS_NOT_FOUND;
  3163. if (!NetworkIdentifier || !Network) // We can have a NULL list lock.
  3164. {
  3165. return STATUS_INVALID_PARAMETER;
  3166. }
  3167. //
  3168. // Set the value to NULL so it isn't accidentally used by someone who doesn't realise
  3169. // that they didn't really get a record back.
  3170. //
  3171. *Network = NULL;
  3172. if (IsListEmpty(NetworkList))
  3173. {
  3174. return STATUS_NOT_FOUND;
  3175. }
  3176. //
  3177. // Lock the list for read
  3178. //
  3179. BrdgGpoAcquireNetworkListLock(NetworkListLock, FALSE /* Read-only */, &LockState);
  3180. //
  3181. // Loop through the list looking for an entry with the same identifier
  3182. //
  3183. for (pListEntry = NetworkList->Flink; pListEntry != NetworkList; pListEntry = pListEntry->Flink)
  3184. {
  3185. PBRDG_GPO_NETWORKS CurrentNetwork;
  3186. CurrentNetwork = CONTAINING_RECORD(pListEntry, BRDG_GPO_NETWORKS, ListEntry);
  3187. //
  3188. // Compare this entries network to the network name that was passed in.
  3189. //
  3190. if ((NULL != CurrentNetwork->NetworkName->Buffer) &&
  3191. (0 == _wcsicmp(CurrentNetwork->Identifier->Buffer, NetworkIdentifier->Buffer)))
  3192. {
  3193. *Network = CurrentNetwork;
  3194. status = STATUS_SUCCESS;
  3195. break;
  3196. }
  3197. }
  3198. //
  3199. // Release the lock, we're done searching
  3200. //
  3201. BrdgGpoReleaseNetworkListLock(NetworkListLock, &LockState);
  3202. return status;
  3203. }
  3204. NTSTATUS
  3205. BrdgGpoMatchNetworkName(
  3206. IN PLIST_ENTRY NetworkList,
  3207. IN PUNICODE_STRING NetworkName,
  3208. IN PNDIS_RW_LOCK NetworkListLock
  3209. )
  3210. /*++
  3211. Routine Description:
  3212. Enumerates through the list looking for a match for the supplied Network Name.
  3213. This can be called on IRQL <= DISPATCH_LEVEL
  3214. Arguments:
  3215. NetworkList - The list through which to enumerate.
  3216. NetworkName - The name to look for.
  3217. NetworkListLock - The NDIS read-write lock for the list.
  3218. Return Value:
  3219. STATUS_NO_MATCH - No match could be found.
  3220. STATUS_SUCCESS - We found a matching Network Name.
  3221. --*/
  3222. {
  3223. PLIST_ENTRY pListEntry;
  3224. LOCK_STATE LockState;
  3225. NTSTATUS status = STATUS_NO_MATCH;
  3226. if (!NetworkList || !NetworkName || !NetworkListLock)
  3227. {
  3228. return STATUS_INVALID_PARAMETER;
  3229. }
  3230. //
  3231. // Lock the list for read
  3232. //
  3233. BrdgGpoAcquireNetworkListLock(NetworkListLock, FALSE /* Read */, &LockState);
  3234. if (!IsListEmpty(NetworkList))
  3235. {
  3236. //
  3237. // Loop through the list looking for an entry with the same NetworkName
  3238. //
  3239. for (pListEntry = NetworkList->Flink; pListEntry != NetworkList; pListEntry = pListEntry->Flink)
  3240. {
  3241. PBRDG_GPO_NETWORKS CurrentNetwork;
  3242. CurrentNetwork = CONTAINING_RECORD(pListEntry, BRDG_GPO_NETWORKS, ListEntry);
  3243. //
  3244. // The network name can be empty, so we don't want to compare if this is the case.
  3245. //
  3246. if ((NULL != CurrentNetwork->NetworkName->Buffer) &&
  3247. (NULL != NetworkName->Buffer) &&
  3248. (0 == _wcsicmp(CurrentNetwork->NetworkName->Buffer, NetworkName->Buffer)))
  3249. {
  3250. status = STATUS_SUCCESS;
  3251. break;
  3252. }
  3253. }
  3254. }
  3255. else
  3256. {
  3257. status = BRDG_STATUS_EMPTY_LIST;
  3258. }
  3259. //
  3260. // Release the lock, we're done searching
  3261. //
  3262. BrdgGpoReleaseNetworkListLock(NetworkListLock, &LockState);
  3263. return status;
  3264. }
  3265. NTSTATUS
  3266. BrdgGpoUpdateNetworkName(
  3267. IN PLIST_ENTRY NetworkList,
  3268. IN PUNICODE_STRING Identifier,
  3269. IN PWCHAR NetworkName,
  3270. IN PNDIS_RW_LOCK NetworkListLock
  3271. )
  3272. /*++
  3273. Routine Description:
  3274. Finds a particular Network in the list of networks.
  3275. Arguments:
  3276. NetworkList - The list of current networks.
  3277. Identifier - A unique identifier that identifies which Network entry to update.
  3278. NetworkName - The new network name for this identifier.
  3279. NetworkListLock - Ndis Read Write Lock for synchronizing changes to the list.
  3280. Return Value:
  3281. STATUS_NOT_FOUND - No entry matching the identifier could be found.
  3282. STATUS_SUCCESS - The entry was successfully found.
  3283. --*/
  3284. {
  3285. PBRDG_GPO_NETWORKS pNetwork;
  3286. NTSTATUS status = STATUS_SUCCESS;
  3287. LOCK_STATE LockState;
  3288. PUNICODE_STRING pNetworkName = NULL;
  3289. LPWSTR lpszNetworkName = NULL;
  3290. if (!NetworkList || !Identifier || !NetworkListLock)
  3291. {
  3292. return STATUS_INVALID_PARAMETER;
  3293. }
  3294. //
  3295. // Allocate space for the new network name from NonPagedPool
  3296. // (it will be accessed from DISPATCH_LEVEL
  3297. //
  3298. pNetworkName = ExAllocatePool(NonPagedPool, sizeof(UNICODE_STRING));
  3299. if (pNetworkName)
  3300. {
  3301. RtlZeroMemory(pNetworkName, sizeof(UNICODE_STRING));
  3302. if (NetworkName)
  3303. {
  3304. lpszNetworkName = ExAllocatePoolWithTag(NonPagedPool, (wcslen(NetworkName) + 1) * sizeof(WCHAR), 'gdrB');
  3305. if (NULL == lpszNetworkName)
  3306. {
  3307. status = STATUS_INSUFFICIENT_RESOURCES;
  3308. }
  3309. else
  3310. {
  3311. wcscpy(lpszNetworkName, NetworkName);
  3312. }
  3313. }
  3314. if (NT_SUCCESS(status))
  3315. {
  3316. RtlInitUnicodeString(pNetworkName, lpszNetworkName);
  3317. }
  3318. else
  3319. {
  3320. //
  3321. // We failed to allocate the actual string, so free the PUNICODE_STRING
  3322. // as well.
  3323. //
  3324. ExFreePool(pNetworkName);
  3325. return status;
  3326. }
  3327. }
  3328. else
  3329. {
  3330. return STATUS_INSUFFICIENT_RESOURCES;
  3331. }
  3332. //
  3333. // Lock the list for update (this will pend until all readers have released the lock).
  3334. //
  3335. BrdgGpoAcquireNetworkListLock(NetworkListLock, TRUE /* Write-access */, &LockState);
  3336. //
  3337. // We pass NULL as the RW-Lock here because we've already locked it and
  3338. // we don't want this entry going away while we're still busy with it
  3339. // (which could happen between a find and an update if we locked twice).
  3340. //
  3341. status = BrdgGpoFindNetwork(NetworkList, Identifier, NULL, &pNetwork);
  3342. if (NT_SUCCESS(status))
  3343. {
  3344. //
  3345. // We first free the current networkname associated with this networkid.
  3346. //
  3347. if (pNetwork->NetworkName->Buffer)
  3348. {
  3349. ExFreePool(pNetwork->NetworkName->Buffer);
  3350. }
  3351. ExFreePool(pNetwork->NetworkName);
  3352. //
  3353. // We do this even if we were passed a NULL network name (ie. the Value/Key has been deleted).
  3354. // Since this means we're probably not on the same network or we've gone to static address and,
  3355. // GPO wise, we're not on the same network.
  3356. //
  3357. pNetwork->NetworkName = pNetworkName;
  3358. }
  3359. else
  3360. {
  3361. ExFreePool(pNetworkName);
  3362. }
  3363. //
  3364. // We're done with the update, so we can release the lock.
  3365. //
  3366. BrdgGpoReleaseNetworkListLock(NetworkListLock, &LockState);
  3367. return status;
  3368. }