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

4192 lines
122 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. if (BrdgIncrementWaitRef(&Notify->RefCount))
  1034. {
  1035. QueuedNotify = ExAllocateFromNPagedLookasideList(LookasideQueueList);
  1036. QueuedNotify->Notify = Notify;
  1037. InsertTailList(QueuedList, &QueuedNotify->ListEntry);
  1038. }
  1039. }
  1040. //
  1041. // We're going to handle this request so set the Modified value to FALSE
  1042. // so that we don't do anything with it if we run through the list again
  1043. // due to another item being added.
  1044. //
  1045. Notify->Modified = FALSE;
  1046. }
  1047. }
  1048. NdisReleaseReadWriteLock(ListLock, &LockState);
  1049. //
  1050. // We're back at PASSIVE_LEVEL so we can now do the registration for the changes.
  1051. //
  1052. for (pListEntry = QueuedList->Flink; pListEntry != QueuedList; pListEntry = pListEntry->Flink)
  1053. {
  1054. QueuedNotify = CONTAINING_RECORD(pListEntry, BRDG_GPO_QUEUED_NOTIFY, ListEntry);
  1055. DBGPRINT(GPO, ("Processing Notification: %S\r\n", QueuedNotify->Notify->Identifier.Buffer));
  1056. //
  1057. // Do the actual registration for the key change notification. Since we can also be
  1058. // passed in a pointer to a BOOLEAN that is used elsewhere, we set that accordingly
  1059. // if we have one.
  1060. //
  1061. DBGPRINT(GPO, ("Refcount for %S \t-\t %d\r\n", QueuedNotify->Notify->Identifier.Buffer, QueuedNotify->Notify->RefCount));
  1062. status = BrdgGpoRegisterForRegKeyChange(QueuedNotify->Notify);
  1063. if (QueuedNotify->Notify->SuccessfulRegistration)
  1064. {
  1065. *(QueuedNotify->Notify->SuccessfulRegistration) = (BOOLEAN)NT_SUCCESS(status);
  1066. BrdgGpoCheckForMatchAndUpdateMode();
  1067. if (QueuedNotify->Notify->FunctionRegister)
  1068. {
  1069. NTSTATUS tmpStatus;
  1070. tmpStatus = QueuedNotify->Notify->FunctionRegister();
  1071. DBGPRINT(GPO, ("Function returned: 0x%x\r\n", tmpStatus));
  1072. }
  1073. }
  1074. if (NT_SUCCESS(status))
  1075. {
  1076. InterlockedExchange(&QueuedNotify->Notify->PendingNotification, TRUE);
  1077. }
  1078. else
  1079. {
  1080. InterlockedExchange(&QueuedNotify->Notify->PendingNotification, FALSE);
  1081. BrdgDecrementWaitRef(&QueuedNotify->Notify->RefCount);
  1082. }
  1083. }
  1084. //
  1085. // Free the temporary list.
  1086. //
  1087. while (!IsListEmpty(QueuedList))
  1088. {
  1089. pListEntry = RemoveHeadList(QueuedList);
  1090. QueuedNotify = CONTAINING_RECORD(pListEntry, BRDG_GPO_QUEUED_NOTIFY, ListEntry);
  1091. ExFreeToNPagedLookasideList(LookasideQueueList, QueuedNotify);
  1092. }
  1093. }
  1094. //
  1095. // We're done, we'll wait here until the event has fired, ie, one of the items needs to be re-registered,
  1096. // or a new item has been added to the list and we need to register for notifications.
  1097. //
  1098. status = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, Executive, KernelMode, FALSE, FALSE, NULL);
  1099. if (!NT_SUCCESS(status))
  1100. {
  1101. FiredEvent = 1L; // We're going to terminate the thread.
  1102. DBGPRINT(GPO, ("KeWaitForMultipleObjects returned an error"));
  1103. }
  1104. else
  1105. {
  1106. FiredEvent = (ULONG)status - (ULONG)STATUS_WAIT_0;
  1107. }
  1108. if (1L == FiredEvent)
  1109. {
  1110. Exiting = TRUE;
  1111. }
  1112. }
  1113. ExDeleteNPagedLookasideList(LookasideQueueList);
  1114. ExFreePool(LookasideQueueList);
  1115. ExFreePool(QueuedList);
  1116. DBGPRINT(GPO, ("Notification Processing Thread Routine Exiting\r\n"));
  1117. // We're done, kill this thread.
  1118. PsTerminateSystemThread( STATUS_SUCCESS );
  1119. }
  1120. NTSTATUS
  1121. BrdgGpoRegisterForRegKeyChange(
  1122. IN PBRDG_GPO_NOTIFY_KEY Notify)
  1123. {
  1124. NTSTATUS status;
  1125. if (!BrdgGpoProcessingNotifications())
  1126. {
  1127. return STATUS_SHUTDOWN_IN_PROGRESS;
  1128. }
  1129. //
  1130. // Call our notify worker function (this does the real request for notification).
  1131. //
  1132. status = BrdgGpoNotifyRegKeyChange( Notify,
  1133. (PIO_APC_ROUTINE)(ULONG_PTR)&Notify->RegChangeWorkItem,
  1134. Notify->WorkItemContext,
  1135. Notify->CompletionFilter,
  1136. Notify->WatchTree);
  1137. if (!NT_SUCCESS(status))
  1138. {
  1139. DBGPRINT(GPO, ("Unable to register for notification on %S. Status: 0x%x\r\n", Notify->RegKeyName.Buffer, status));
  1140. }
  1141. return status;
  1142. }
  1143. NTSTATUS
  1144. BrdgGpoBuildNotifyForRegKeyChange(
  1145. IN PBRDG_GPO_NOTIFY_KEY Notify,
  1146. IN LPWSTR Identifier,
  1147. IN LPWSTR RegKeyName,
  1148. IN LPWSTR RegValueName,
  1149. IN PWORKER_THREAD_ROUTINE ApcRoutine,
  1150. IN PVOID ApcContext,
  1151. IN ULONG CompletionFilter,
  1152. IN BOOLEAN WatchTree,
  1153. IN PBRDG_GPO_REG_CALLBACK FunctionCallback,
  1154. IN BOOLEAN Recurring,
  1155. IN PBOOLEAN SuccessfulRegistration,
  1156. IN PBRDG_GPO_REGISTER FunctionRegister
  1157. )
  1158. /*++
  1159. Routine Description:
  1160. Builds a Notify structure used for Registry Key and Value changes.
  1161. Arguments:
  1162. Notify - If ReRegister is FALSE, then this structure has simply been
  1163. initialized with some basic information. The rest will be
  1164. filled in here. If ReRegister is TRUE, then this structure
  1165. contains all the information necessary to redo the notification
  1166. request, this saves us having to pass all the data in each time.
  1167. Identifier - Identifies this Notify structure. Can be a name, or a GUID for an adapter.
  1168. RegKeyName - The Registry key that we're interesting in waiting on.
  1169. RegValueName - The Value that we need (or "Default" if we don't care about it")
  1170. ApcRoutine - The routine that we which to be notified on.
  1171. ApcContext - Information that we want to be passed back (we expect a valid Notify Struct).
  1172. CompletionFilter - What type of change we're interested in. ie. New Subkey added, or Value changed etc.
  1173. WatchTree - Do we want to what for changes on all subkeys as well.
  1174. FunctionCallback - Our own internal callback functions
  1175. Recurring - Do we want to re-do the notification once we're done handling it.
  1176. SuccessfulRegistration - A pointer to a BOOLEAN that we set if the registration is successful.
  1177. Return Value:
  1178. STATUS_SUCCESS or a specific error code.
  1179. --*/
  1180. {
  1181. NTSTATUS status = STATUS_SUCCESS;
  1182. LPWSTR lpszIdentifier = NULL;
  1183. LPWSTR lpszRegKeyName = NULL;
  1184. LPWSTR lpszRegValueName = NULL;
  1185. if (NULL == Notify ||
  1186. NULL == Identifier ||
  1187. NULL == RegKeyName ||
  1188. NULL == RegValueName ||
  1189. NULL == ApcRoutine ||
  1190. NULL == ApcContext ||
  1191. NULL == FunctionCallback
  1192. )
  1193. {
  1194. return STATUS_INVALID_PARAMETER;
  1195. }
  1196. //
  1197. // This buffer is not used by ZwNotifyChangeKey. So no need to really allocate anything for it.
  1198. //
  1199. Notify->Buffer = 0L;
  1200. Notify->BufferSize = sizeof(ULONG);
  1201. //
  1202. // We Allocate these from NonPagedPool because they're passed as part of a struct that can be used at
  1203. // DISPATCH_LEVEL
  1204. //
  1205. lpszIdentifier = ExAllocatePoolWithTag(NonPagedPool, (wcslen(Identifier) + 1) * sizeof(WCHAR), 'gdrB');
  1206. if (lpszIdentifier)
  1207. {
  1208. lpszRegKeyName = ExAllocatePoolWithTag(NonPagedPool, (wcslen(RegKeyName) + 1) * sizeof(WCHAR), 'gdrB');
  1209. if (lpszRegKeyName)
  1210. {
  1211. lpszRegValueName = ExAllocatePoolWithTag(NonPagedPool, (wcslen(RegValueName) + 1) * sizeof(WCHAR), 'gdrB');
  1212. if (lpszRegValueName)
  1213. {
  1214. BOOLEAN Success;
  1215. RtlZeroMemory(lpszIdentifier, (wcslen(Identifier) + 1) * sizeof(WCHAR));
  1216. RtlZeroMemory(lpszRegKeyName, (wcslen(RegKeyName) + 1) * sizeof(WCHAR));
  1217. RtlZeroMemory(lpszRegValueName, (wcslen(RegValueName) + 1) * sizeof(WCHAR));
  1218. //
  1219. // We need to allocate new strings because the RtlInitUnicodeString function just sets its buffer
  1220. // to the LPWSTR we pass it and these values need to be used outside the scope of these functions.
  1221. //
  1222. wcscpy(lpszIdentifier, Identifier);
  1223. wcscpy(lpszRegKeyName, RegKeyName);
  1224. wcscpy(lpszRegValueName, RegValueName);
  1225. //
  1226. // Set the strings inside our struct. This enables us to fully rebuild the information required
  1227. // for keeping track of the different keys that we need to be notified about.
  1228. //
  1229. RtlInitUnicodeString(&Notify->Identifier, lpszIdentifier);
  1230. RtlInitUnicodeString(&Notify->RegKeyName, lpszRegKeyName);
  1231. RtlInitUnicodeString(&Notify->RegValue, lpszRegValueName);
  1232. //
  1233. // Recurring will tell us if we need to re-register once a change is fired.
  1234. //
  1235. Notify->Recurring = Recurring;
  1236. //
  1237. // Rather than have the BrdgGpoRegNotify function do everything, we have seperate functions
  1238. // for each one. This also means that we don't have to keep all of them in the paged-locked
  1239. // section, since they will be called at PASSIVE_LEVEL.
  1240. //
  1241. Notify->FunctionCallback = FunctionCallback;
  1242. //
  1243. // We are using a Workitem to get called back on. We pass in the notify structure
  1244. // which has enough info to re-notify if necessary. The context is generally just
  1245. // the Deferred work queue.
  1246. //
  1247. ExInitializeWorkItem(&Notify->RegChangeWorkItem, ApcRoutine, Notify);
  1248. Notify->WorkItemContext = ApcContext;
  1249. //
  1250. // We store the WatchTree and CompletionFilter so that we can renotify needing any
  1251. // additional parameters, since we're probably ddoing this from a different thread.
  1252. //
  1253. Notify->WatchTree = WatchTree;
  1254. Notify->CompletionFilter = CompletionFilter;
  1255. //
  1256. // We set this once we have successfully registered for notification on the key of
  1257. // interest.
  1258. //
  1259. Notify->SuccessfulRegistration = SuccessfulRegistration;
  1260. //
  1261. // Increment this once so that we can decrement it in the cleanup code and have it only go to Zero then.
  1262. //
  1263. BrdgInitializeWaitRef(&Notify->RefCount, FALSE);
  1264. //
  1265. // Since we're initializing this object, there is no way that this should fail.
  1266. //
  1267. Success = BrdgIncrementWaitRef(&Notify->RefCount);
  1268. SAFEASSERT(Success);
  1269. }
  1270. else
  1271. {
  1272. status = STATUS_INSUFFICIENT_RESOURCES;
  1273. }
  1274. }
  1275. else
  1276. {
  1277. status = STATUS_INSUFFICIENT_RESOURCES;
  1278. }
  1279. }
  1280. else
  1281. {
  1282. return STATUS_INSUFFICIENT_RESOURCES;
  1283. }
  1284. if (!NT_SUCCESS(status))
  1285. {
  1286. if (lpszIdentifier)
  1287. {
  1288. ExFreePool(lpszIdentifier);
  1289. }
  1290. if (lpszRegKeyName)
  1291. {
  1292. ExFreePool(lpszRegKeyName);
  1293. }
  1294. if (lpszRegValueName)
  1295. {
  1296. ExFreePool(lpszRegValueName);
  1297. }
  1298. }
  1299. return status;
  1300. }
  1301. NTSTATUS
  1302. BrdgGpoNotifyRegKeyChange(
  1303. IN PBRDG_GPO_NOTIFY_KEY Notify,
  1304. IN PIO_APC_ROUTINE ApcRoutine,
  1305. IN PVOID ApcContext,
  1306. IN ULONG CompletionFilter,
  1307. IN BOOLEAN WatchTree)
  1308. /*++
  1309. Routine Description:
  1310. This calls ZwNotifyChangeKey to register us for notifications on individual keys.
  1311. We close the key in the callback functions because you can only listen once per handle.
  1312. Arguments:
  1313. Notify - Structure containing relevant information about the notification. Allows us to
  1314. know what values to read to get the relevant data that we need.
  1315. ApcRoutine - The routine that we which to be notified on.
  1316. ApcContext - Information that we want to be passed back (we expect a valid Notify Struct).
  1317. CompletionFilter - What type of change we're interested in. ie. New Subkey added, or Value changed etc.
  1318. WatchTree - Do we want to what for changes on all subkeys as well.
  1319. Return Value:
  1320. STATUS_SUCCESS or a specific error code.
  1321. --*/
  1322. {
  1323. OBJECT_ATTRIBUTES ObAttr;
  1324. NTSTATUS status;
  1325. InitializeObjectAttributes(&ObAttr, &Notify->RegKeyName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
  1326. status = ZwOpenKey( &Notify->RegKey,
  1327. KEY_READ | KEY_NOTIFY | KEY_WRITE,
  1328. &ObAttr);
  1329. if (NT_SUCCESS(status))
  1330. {
  1331. DBGPRINT(GPO, ("Opened Regkey successfully\r\n"));
  1332. status = ZwNotifyChangeKey( Notify->RegKey,
  1333. NULL,
  1334. ApcRoutine,
  1335. ApcContext,
  1336. &Notify->IoStatus,
  1337. CompletionFilter,
  1338. WatchTree,
  1339. &Notify->Buffer,
  1340. Notify->BufferSize,
  1341. TRUE
  1342. );
  1343. }
  1344. else
  1345. {
  1346. //
  1347. // Set it to NULL so that we don't try to close it accidentally during shutdown.
  1348. //
  1349. Notify->RegKey = NULL;
  1350. }
  1351. return status;
  1352. }
  1353. VOID
  1354. static
  1355. BrdgGpoRegNotify(
  1356. IN PVOID Context)
  1357. /*++
  1358. Routine Description:
  1359. This is the central callback function that we are notified on.
  1360. This is called on an Executive worker thread at PASSIVE_LEVEL.
  1361. Arguments:
  1362. Context - Is just our Notify structure that we passed in
  1363. to ZwNotifyChangeKey
  1364. Return Value:
  1365. None.
  1366. --*/
  1367. {
  1368. PBRDG_GPO_NOTIFY_KEY Notify = (PBRDG_GPO_NOTIFY_KEY)Context;
  1369. DBGPRINT(GPO, ("APC routine called\r\n"));
  1370. DBGPRINT(GPO, ("Current IRQL: %d\r\n", CURRENT_IRQL));
  1371. if (Notify)
  1372. {
  1373. LONG RefCount;
  1374. InterlockedExchange(&Notify->PendingNotification, FALSE);
  1375. Notify->FunctionCallback(Notify);
  1376. RefCount = Notify->RefCount.Refcount - 1;
  1377. DBGPRINT(GPO, ("Refcount for %S \t-\t %d\r\n", Notify->Identifier.Buffer, RefCount));
  1378. BrdgDecrementWaitRef(&Notify->RefCount);
  1379. }
  1380. }
  1381. NTSTATUS
  1382. BrdgGpoAllocateAndInitializeNotifyStruct(
  1383. OUT PBRDG_GPO_NOTIFY_KEY* Notify)
  1384. /*++
  1385. Routine Description:
  1386. Allocates and initializes the Notify struct to all zeros.
  1387. Arguments:
  1388. Notify - A pointer to pointer to a Notify struct that is allocated
  1389. from NonPagedPool.
  1390. Return Value:
  1391. STATUS_INSUFFICIENT_RESOURCES - Not enough memory to filfull the request.
  1392. STATUS_INVALID_PARAMETER - We were passed a NULL Pointer to pointer
  1393. to a Notify struct.
  1394. STATUS_SUCCESS - We successfully allocated space for the structure.
  1395. --*/
  1396. {
  1397. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  1398. if (NULL == Notify)
  1399. {
  1400. return STATUS_INVALID_PARAMETER;
  1401. }
  1402. //
  1403. // We allocate this from NonPagedPool because it will be accessed at DISPATCH_LEVEL
  1404. //
  1405. *Notify = ExAllocatePoolWithTag(NonPagedPool, sizeof(BRDG_GPO_NOTIFY_KEY), 'gdrB');
  1406. if (*Notify)
  1407. {
  1408. //
  1409. // Zero it out so that we don't try and free invalid strings when we free it.
  1410. //
  1411. RtlZeroMemory(*Notify, sizeof(BRDG_GPO_NOTIFY_KEY));
  1412. status = STATUS_SUCCESS;
  1413. }
  1414. return status;
  1415. }
  1416. VOID
  1417. BrdgGpoFreeNotifyStructAndData(
  1418. IN PBRDG_GPO_NOTIFY_KEY Notify)
  1419. /*++
  1420. Routine Description:
  1421. Frees all data associated with a Notify struct and then frees the struct
  1422. itself.
  1423. Note: This will not free a structure that is still in a list.
  1424. If you need to free something, use RemoveListEntry and then
  1425. set the Notify->ListEntry Blink and Flink = NULL and then call
  1426. this.
  1427. WARNING:
  1428. Since it's possible that this structure is still being used by
  1429. the a waiting registration, it's better to leave them alone until
  1430. shutdown as it's possible that a notification may be fired once
  1431. this has been freed and that will result in a system crash since
  1432. the struct will be invalid.
  1433. Arguments:
  1434. Notify - A pointer to the Notify struct to be freed.
  1435. Return Value:
  1436. None.
  1437. --*/
  1438. {
  1439. if (Notify)
  1440. {
  1441. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  1442. {
  1443. if (Notify->Identifier.Buffer)
  1444. {
  1445. ExFreePool(Notify->Identifier.Buffer);
  1446. }
  1447. if (Notify->RegKeyName.Buffer)
  1448. {
  1449. ExFreePool(Notify->RegKeyName.Buffer);
  1450. }
  1451. if (Notify->RegValue.Buffer)
  1452. {
  1453. ExFreePool(Notify->RegValue.Buffer);
  1454. }
  1455. ExFreePool(Notify);
  1456. }
  1457. else
  1458. {
  1459. if (BrdgGpoProcessingNotifications())
  1460. {
  1461. DBGPRINT(GPO, ("Attempt to free a Notify that is still in a list\r\nWhile we're still processing Notifications\r\n"));
  1462. }
  1463. }
  1464. }
  1465. }
  1466. // ===========================================================================
  1467. //
  1468. // NOTIFICATION REGISTRATION FUNCTIONS
  1469. //
  1470. // ===========================================================================
  1471. NTSTATUS
  1472. BrdgGpoRegisterForGroupPolicyNetworkNameNotification()
  1473. /*++
  1474. Routine Description:
  1475. Registers for the changes on the following registry key:
  1476. "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\History"
  1477. Arguments:
  1478. None.
  1479. Return Value:
  1480. None.
  1481. --*/
  1482. {
  1483. NTSTATUS status;
  1484. PBRDG_GPO_NOTIFY_KEY Notify = NULL;
  1485. UNICODE_STRING RegKeyName;
  1486. PWCHAR RegValue;
  1487. ULONG DataLen;
  1488. if (g_BrdgGpoGlobals.RegisteredForGroupPolicyHistoryChanges)
  1489. {
  1490. DBGPRINT(GPO, ("Already Registered for Group Policy Network Name Notification\r\n"));
  1491. return STATUS_SUCCESS;
  1492. }
  1493. DBGPRINT(GPO, ("BrdgGpoRegisterForGroupPolicyNetworkNameNotification\r\n"));
  1494. RtlInitUnicodeString(&RegKeyName, (LPWSTR) HistoryKey);
  1495. //
  1496. // Read the current value from the Registry.
  1497. //
  1498. status = BrdgReadRegUnicode(&RegKeyName,
  1499. L"NetworkName",
  1500. &RegValue,
  1501. &DataLen);
  1502. if (NT_SUCCESS(status))
  1503. {
  1504. DBGPRINT(GPO, ("Group Policy Network Name: %S\r\n", RegValue));
  1505. if (NULL != g_BrdgGpoGlobals.GroupPolicyNetworkName.Buffer)
  1506. {
  1507. ExFreePool(g_BrdgGpoGlobals.GroupPolicyNetworkName.Buffer);
  1508. }
  1509. //
  1510. // Success. Now store the value for later use.
  1511. //
  1512. RtlInitUnicodeString(&g_BrdgGpoGlobals.GroupPolicyNetworkName, RegValue);
  1513. //
  1514. // Since something changed, we'll just re-verify that we're in
  1515. // the correct bridging mode.
  1516. //
  1517. BrdgGpoCheckForMatchAndUpdateMode();
  1518. }
  1519. else
  1520. {
  1521. //
  1522. // We failed to get a value for this. It probably isn't there yet - this can happen if this
  1523. // is the first boot after joining a domain. We'll be waiting on this key so if we get one later
  1524. // we'll update this value.
  1525. //
  1526. g_BrdgGpoGlobals.GroupPolicyNetworkName.Buffer = NULL;
  1527. g_BrdgGpoGlobals.GroupPolicyNetworkName.Length = 0;
  1528. g_BrdgGpoGlobals.GroupPolicyNetworkName.MaximumLength = 0;
  1529. }
  1530. //
  1531. // We don't want to allocate these twice, so we first try to find an existing notify struct.
  1532. //
  1533. status = BrdgGpoFindNotify( BrdgGpoGetNotifyListHead(),
  1534. BrdgGpoGetNotifyListLock(),
  1535. L"GroupPolicyNetworkName",
  1536. &Notify);
  1537. if (NT_SUCCESS(status))
  1538. {
  1539. if (STATUS_OBJECT_NAME_EXISTS != status)
  1540. {
  1541. status = BrdgGpoAllocateAndInitializeNotifyStruct(&Notify);
  1542. if (NT_SUCCESS(status))
  1543. {
  1544. status = BrdgGpoBuildNotifyForRegKeyChange( Notify,
  1545. L"GroupPolicyNetworkName",
  1546. (LPWSTR)HistoryKey,
  1547. L"NetworkName",
  1548. BrdgGpoRegNotify,
  1549. (PVOID)(UINT_PTR)(unsigned int)DelayedWorkQueue,
  1550. REG_NOTIFY_CHANGE_LAST_SET,
  1551. FALSE,
  1552. BrdgGpoGroupPolicyNetworkNameChangeCallback,
  1553. TRUE,
  1554. &g_BrdgGpoGlobals.RegisteredForGroupPolicyHistoryChanges,
  1555. BrdgGpoUpdateGroupPolicyNetworkName);
  1556. }
  1557. }
  1558. if (!NT_SUCCESS(status))
  1559. {
  1560. DBGPRINT(GPO, ("Unable to Build notification on %S. Status: 0x%x\r\n", NetworkPoliciesKey, status));
  1561. BrdgGpoFreeNotifyStructAndData(Notify);
  1562. Notify = NULL;
  1563. }
  1564. else
  1565. {
  1566. SAFEASSERT(Notify);
  1567. status = BrdgGpoRequestNotification(Notify);
  1568. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  1569. {
  1570. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  1571. {
  1572. BrdgDecrementWaitRef(&Notify->RefCount);
  1573. BrdgGpoFreeNotifyStructAndData(Notify);
  1574. Notify = NULL;
  1575. }
  1576. }
  1577. else if (!NT_SUCCESS(status))
  1578. {
  1579. BrdgGpoFreeNotifyStructAndData(Notify);
  1580. Notify = NULL;
  1581. }
  1582. }
  1583. }
  1584. #if DBG
  1585. if (Notify)
  1586. {
  1587. SAFEASSERT(Notify->ListEntry.Blink && Notify->ListEntry.Flink);
  1588. }
  1589. #endif
  1590. return status;
  1591. }
  1592. NTSTATUS
  1593. BrdgGpoRegisterForGroupPolicyNotification()
  1594. /*++
  1595. Routine Description:
  1596. Registers for the changes on the following registry key:
  1597. "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy"
  1598. This is the parent to the History key and is always on a system.
  1599. If will be notified if the History Key is created in which case
  1600. we will register for notifications on that key.
  1601. Arguments:
  1602. None.
  1603. Return Value:
  1604. None.
  1605. --*/
  1606. {
  1607. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  1608. PBRDG_GPO_NOTIFY_KEY Notify = NULL;
  1609. DBGPRINT(GPO, ("BrdgGpoRegisterForGroupPolicyNotification\r\n"));
  1610. //
  1611. // We don't want to allocate these twice, so we first try to find an existing notify struct.
  1612. //
  1613. status = BrdgGpoFindNotify( BrdgGpoGetNotifyListHead(),
  1614. BrdgGpoGetNotifyListLock(),
  1615. L"GroupPolicyParent",
  1616. &Notify);
  1617. if (NT_SUCCESS(status))
  1618. {
  1619. if (STATUS_OBJECT_NAME_EXISTS != status)
  1620. {
  1621. status = BrdgGpoAllocateAndInitializeNotifyStruct(&Notify);
  1622. if (NT_SUCCESS(status))
  1623. {
  1624. status = BrdgGpoBuildNotifyForRegKeyChange( Notify,
  1625. L"GroupPolicyParent",
  1626. (LPWSTR)GroupPolicyKey,
  1627. L"Default",
  1628. BrdgGpoRegNotify,
  1629. (PVOID)(UINT_PTR)(unsigned int)DelayedWorkQueue,
  1630. REG_NOTIFY_CHANGE_NAME,
  1631. FALSE,
  1632. BrdgGpoGroupPolicyChangeCallback,
  1633. TRUE,
  1634. &g_BrdgGpoGlobals.RegisteredForGroupPolicyChanges,
  1635. BrdgGpoRegisterForGroupPolicyNetworkNameNotification);
  1636. }
  1637. }
  1638. if (!NT_SUCCESS(status))
  1639. {
  1640. DBGPRINT(GPO, ("Unable to register for notification on %S. Status: 0x%x\r\n", GroupPolicyKey, status));
  1641. BrdgGpoFreeNotifyStructAndData(Notify);
  1642. Notify = NULL;
  1643. }
  1644. else
  1645. {
  1646. SAFEASSERT(Notify);
  1647. status = BrdgGpoRequestNotification(Notify);
  1648. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  1649. {
  1650. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  1651. {
  1652. BrdgDecrementWaitRef(&Notify->RefCount);
  1653. BrdgGpoFreeNotifyStructAndData(Notify);
  1654. Notify = NULL;
  1655. }
  1656. }
  1657. else if (!NT_SUCCESS(status))
  1658. {
  1659. BrdgGpoFreeNotifyStructAndData(Notify);
  1660. Notify = NULL;
  1661. }
  1662. }
  1663. }
  1664. #if DBG
  1665. if (Notify)
  1666. {
  1667. SAFEASSERT(Notify->ListEntry.Blink && Notify->ListEntry.Flink);
  1668. }
  1669. #endif
  1670. return status;
  1671. }
  1672. NTSTATUS
  1673. BrdgGpoRegisterForWindowsGroupPolicyNotification()
  1674. /*++
  1675. Routine Description:
  1676. Registers for the changes on the following registry key:
  1677. HKLM\SOFTWARE\Policies\Microsoft\Windows
  1678. If this gets notified, then we'll attempt to wait on the
  1679. Network Connections key below this.
  1680. Arguments:
  1681. None.
  1682. Return Value:
  1683. STATUS_INSUFFICIENT_RESOURCES - Not enough memory to allocate the structure.
  1684. STATUS_SUCCESS - We were able to post the request successfully.
  1685. This doesn't mean we've successfully requested
  1686. notification though, it only means we've added it
  1687. to the Notifications list and have signaled the
  1688. processing thread to attempt a notification.
  1689. --*/
  1690. {
  1691. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  1692. PBRDG_GPO_NOTIFY_KEY Notify = NULL;
  1693. DBGPRINT(GPO, ("BrdgGpoRegisterForWindowsGroupPolicyNotification\r\n"));
  1694. //
  1695. // We don't want to allocate these twice, so we first try to find an existing notify struct.
  1696. //
  1697. status = BrdgGpoFindNotify( BrdgGpoGetNotifyListHead(),
  1698. BrdgGpoGetNotifyListLock(),
  1699. L"WindowsGroupPolicies",
  1700. &Notify);
  1701. if (NT_SUCCESS(status))
  1702. {
  1703. if (STATUS_OBJECT_NAME_EXISTS != status)
  1704. {
  1705. status = BrdgGpoAllocateAndInitializeNotifyStruct(&Notify);
  1706. if (NT_SUCCESS(status))
  1707. {
  1708. status = BrdgGpoBuildNotifyForRegKeyChange( Notify,
  1709. L"WindowsGroupPolicies",
  1710. (LPWSTR)PolicyBaseKey,
  1711. (LPWSTR)L"Default",
  1712. BrdgGpoRegNotify,
  1713. (PVOID)(UINT_PTR)(unsigned int)DelayedWorkQueue,
  1714. REG_NOTIFY_CHANGE_NAME,
  1715. FALSE,
  1716. BrdgGpoWindowsGroupPolicyChangeCallback,
  1717. TRUE,
  1718. NULL,
  1719. BrdgGpoRegisterForNetworkConnectionsGroupPolicyNotification);
  1720. }
  1721. }
  1722. if (!NT_SUCCESS(status))
  1723. {
  1724. DBGPRINT(GPO, ("Unable to register for notification on %S. Status: 0x%x\r\n", PolicyBaseKey, status));
  1725. BrdgGpoFreeNotifyStructAndData(Notify);
  1726. Notify = NULL;
  1727. }
  1728. else
  1729. {
  1730. SAFEASSERT(Notify);
  1731. status = BrdgGpoRequestNotification(Notify);
  1732. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  1733. {
  1734. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  1735. {
  1736. BrdgDecrementWaitRef(&Notify->RefCount);
  1737. BrdgGpoFreeNotifyStructAndData(Notify);
  1738. Notify = NULL;
  1739. }
  1740. }
  1741. else if (!NT_SUCCESS(status))
  1742. {
  1743. BrdgGpoFreeNotifyStructAndData(Notify);
  1744. Notify = NULL;
  1745. }
  1746. }
  1747. }
  1748. #if DBG
  1749. if (Notify)
  1750. {
  1751. SAFEASSERT(Notify->ListEntry.Blink && Notify->ListEntry.Flink);
  1752. }
  1753. #endif
  1754. return status;
  1755. }
  1756. VOID
  1757. BrdgGpoRegisterForHiveListNotification()
  1758. /*++
  1759. Routine Description:
  1760. Registers for the changes on the following registry key:
  1761. "HKLM\System\CurrentControlSet\Control\HiveList"
  1762. Each time this is fired we attempt to open the Software hive, if this
  1763. open is successful then we request notification on all the keys that
  1764. we are interested in under the software hive.
  1765. Arguments:
  1766. None.
  1767. Return Value:
  1768. None.
  1769. --*/
  1770. {
  1771. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  1772. PBRDG_GPO_NOTIFY_KEY Notify = NULL;
  1773. UNICODE_STRING Software;
  1774. OBJECT_ATTRIBUTES ObAttr;
  1775. HANDLE hKey;
  1776. DBGPRINT(GPO, ("BrdgGpoRegisterForHiveListNotification\r\n"));
  1777. //
  1778. // We attempt to open this key now in case the hives are already loaded.
  1779. //
  1780. RtlInitUnicodeString(&Software, SoftwareHiveKey);
  1781. InitializeObjectAttributes( &ObAttr,
  1782. &Software,
  1783. OBJ_CASE_INSENSITIVE,
  1784. NULL,
  1785. NULL
  1786. );
  1787. status = ZwOpenKey(&hKey, KEY_READ, &ObAttr);
  1788. if (NT_SUCCESS(status))
  1789. {
  1790. //
  1791. // The software hive is already loaded, no need to register for changes
  1792. // to this. Just attempt to register for all other changes.
  1793. //
  1794. BrdgGpoRegisterForGroupPolicyNetworkNameNotification();
  1795. BrdgGpoRegisterForWindowsGroupPolicyNotification();
  1796. BrdgGpoRegisterForGroupPolicyNotification();
  1797. //
  1798. // To avoid turning the bridge on and then off again, we set this just after
  1799. // verifying the Network Connections policy setting.
  1800. //
  1801. BrdgGpoRegisterForNetworkConnectionsGroupPolicyNotification();
  1802. g_BrdgGpoGlobals.WaitingOnSoftwareHive = FALSE;
  1803. ZwClose(hKey);
  1804. }
  1805. else
  1806. {
  1807. //
  1808. // We don't want to allocate these twice, so we first try to find an existing notify struct.
  1809. //
  1810. status = BrdgGpoFindNotify( BrdgGpoGetNotifyListHead(),
  1811. BrdgGpoGetNotifyListLock(),
  1812. L"HiveList",
  1813. &Notify);
  1814. if (NT_SUCCESS(status))
  1815. {
  1816. if (STATUS_OBJECT_NAME_EXISTS != status)
  1817. {
  1818. //
  1819. // The item doesn't exist yet, so allocate it from the NonPagedPool and
  1820. // attempt build a notification request.
  1821. //
  1822. status = BrdgGpoAllocateAndInitializeNotifyStruct(&Notify);
  1823. if (NT_SUCCESS(status))
  1824. {
  1825. status = BrdgGpoBuildNotifyForRegKeyChange( Notify,
  1826. L"HiveList",
  1827. (LPWSTR)HiveListKey,
  1828. (LPWSTR)L"Default",
  1829. BrdgGpoRegNotify,
  1830. (PVOID)(UINT_PTR)(unsigned int)DelayedWorkQueue,
  1831. REG_NOTIFY_CHANGE_LAST_SET,
  1832. FALSE,
  1833. BrdgGpoHiveListCallback,
  1834. TRUE,
  1835. NULL,
  1836. NULL);
  1837. }
  1838. }
  1839. if (!NT_SUCCESS(status))
  1840. {
  1841. DBGPRINT(GPO, ("Unable to register for notification on %S. Status: 0x%x\r\n", PolicyBaseKey, status));
  1842. BrdgGpoFreeNotifyStructAndData(Notify);
  1843. Notify = NULL;
  1844. }
  1845. else
  1846. {
  1847. SAFEASSERT(Notify);
  1848. //
  1849. // We have a valid Notify structure, post a notification request to the
  1850. // processing thread.
  1851. //
  1852. status = BrdgGpoRequestNotification(Notify);
  1853. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  1854. {
  1855. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  1856. {
  1857. BrdgDecrementWaitRef(&Notify->RefCount);
  1858. BrdgGpoFreeNotifyStructAndData(Notify);
  1859. Notify = NULL;
  1860. }
  1861. }
  1862. else if (!NT_SUCCESS(status))
  1863. {
  1864. BrdgGpoFreeNotifyStructAndData(Notify);
  1865. Notify = NULL;
  1866. }
  1867. }
  1868. }
  1869. #if DBG
  1870. if (Notify)
  1871. {
  1872. SAFEASSERT(Notify->ListEntry.Blink && Notify->ListEntry.Flink);
  1873. }
  1874. #endif
  1875. }
  1876. }
  1877. NTSTATUS
  1878. BrdgGpoRegisterForNetworkConnectionsGroupPolicyNotification()
  1879. /*++
  1880. Routine Description:
  1881. Registers for the changes on the following registry key:
  1882. "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\Network Connections"
  1883. We also read any value that may already be there and act upon it.
  1884. Arguments:
  1885. None.
  1886. Return Value:
  1887. STATUS_INSUFFICIENT_RESOURCES - Not enough memory to allocate the structure.
  1888. STATUS_SUCCESS - We were able to post the request successfully.
  1889. This doesn't mean we've successfully requested
  1890. notification though, it only means we've added it
  1891. to the Notifications list and have signaled the
  1892. processing thread to attempt a notification.
  1893. --*/
  1894. {
  1895. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  1896. PBRDG_GPO_NOTIFY_KEY Notify = NULL;
  1897. UNICODE_STRING RegKeyName;
  1898. ULONG RegValue;
  1899. if (g_BrdgGpoGlobals.RegisteredForNetworkConnectionsGroupPolicyChanges)
  1900. {
  1901. DBGPRINT(GPO, ("Already Registered for Network Connections Group Policy Notification\r\n"));
  1902. return STATUS_SUCCESS;
  1903. }
  1904. DBGPRINT(GPO, ("BrdgGpoRegisterForNetworkConnectionsGroupPolicyNotification\r\n"));
  1905. RtlInitUnicodeString(&RegKeyName, (LPWSTR)NetworkPoliciesKey);
  1906. //
  1907. // Read the current value from the Registry.
  1908. //
  1909. status = BrdgReadRegDWord( &RegKeyName,
  1910. (LPWSTR)BridgePolicyValue,
  1911. &RegValue);
  1912. if (NT_SUCCESS(status))
  1913. {
  1914. DBGPRINT(GPO, ("Bridge Policy Setting: %d\r\n", RegValue));
  1915. //
  1916. // Since something changed, we'll just re-verify that we're in
  1917. // the correct bridging mode.
  1918. //
  1919. BrdgGpoCheckForMatchAndUpdateMode();
  1920. }
  1921. //
  1922. // We don't want to allocate these twice, so we first try to find an existing notify struct.
  1923. //
  1924. status = BrdgGpoFindNotify( BrdgGpoGetNotifyListHead(),
  1925. BrdgGpoGetNotifyListLock(),
  1926. L"NetworkConnectionsGroupPolicies",
  1927. &Notify);
  1928. if (NT_SUCCESS(status))
  1929. {
  1930. if (STATUS_OBJECT_NAME_EXISTS != status)
  1931. {
  1932. status = BrdgGpoAllocateAndInitializeNotifyStruct(&Notify);
  1933. if (NT_SUCCESS(status))
  1934. {
  1935. status = BrdgGpoBuildNotifyForRegKeyChange( Notify,
  1936. L"NetworkConnectionsGroupPolicies",
  1937. (LPWSTR)NetworkPoliciesKey,
  1938. (LPWSTR)BridgePolicyValue,
  1939. BrdgGpoRegNotify,
  1940. (PVOID)(UINT_PTR)(unsigned int)DelayedWorkQueue,
  1941. REG_NOTIFY_CHANGE_LAST_SET,
  1942. FALSE,
  1943. BrdgGpoNetworkConnectionsGroupPolicyChangeCallback,
  1944. TRUE,
  1945. &g_BrdgGpoGlobals.RegisteredForNetworkConnectionsGroupPolicyChanges,
  1946. NULL);
  1947. }
  1948. }
  1949. if (!NT_SUCCESS(status))
  1950. {
  1951. DBGPRINT(GPO, ("Unable to register for notification on %S. Status: 0x%x\r\n", NetworkPoliciesKey, status));
  1952. BrdgGpoFreeNotifyStructAndData(Notify);
  1953. Notify = NULL;
  1954. }
  1955. else
  1956. {
  1957. SAFEASSERT(Notify);
  1958. status = BrdgGpoRequestNotification(Notify);
  1959. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  1960. {
  1961. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  1962. {
  1963. BrdgDecrementWaitRef(&Notify->RefCount);
  1964. BrdgGpoFreeNotifyStructAndData(Notify);
  1965. Notify = NULL;
  1966. }
  1967. }
  1968. else if (!NT_SUCCESS(status))
  1969. {
  1970. BrdgGpoFreeNotifyStructAndData(Notify);
  1971. Notify = NULL;
  1972. }
  1973. }
  1974. }
  1975. #if DBG
  1976. if (Notify)
  1977. {
  1978. SAFEASSERT(Notify->ListEntry.Blink && Notify->ListEntry.Flink);
  1979. }
  1980. #endif
  1981. return status;
  1982. }
  1983. // ===========================================================================
  1984. //
  1985. // REGISTRY CHANGE CALLBACK FUNCTIONS
  1986. //
  1987. // ===========================================================================
  1988. VOID
  1989. BrdgGpoTcpipInterfacesChangeCallback(
  1990. PBRDG_GPO_NOTIFY_KEY Notify
  1991. )
  1992. /*++
  1993. Routine Description:
  1994. Called back if the an the TcpIp interfaces key changes for
  1995. and adapter that we're interested in (any Non-NdisWan adapter).
  1996. Arguments:
  1997. Notify - Notify structure that we passed in
  1998. to ZwNotifyChangeKey
  1999. Return Value:
  2000. None.
  2001. --*/
  2002. {
  2003. NTSTATUS status;
  2004. PWCHAR RegValue;
  2005. ULONG StringLen = 0;
  2006. DBGPRINT(GPO, ("BrdgGpoTcpipInterfacesChangeCallback\r\n"));
  2007. DBGPRINT(GPO, ("Called for Key: %S re-registering.\r\n", Notify->RegKeyName.Buffer));
  2008. //
  2009. // Read the current value from the Registry.
  2010. //
  2011. status = BrdgReadRegUnicode(&Notify->RegKeyName,
  2012. Notify->RegValue.Buffer,
  2013. &RegValue,
  2014. &StringLen);
  2015. if (!NT_SUCCESS(status))
  2016. {
  2017. status = BrdgGpoGetCurrentNetwork( &Notify->RegKeyName,
  2018. &RegValue);
  2019. if (NT_SUCCESS(status))
  2020. {
  2021. StringLen = (UINT)wcslen(RegValue);
  2022. }
  2023. }
  2024. if (NT_SUCCESS(status))
  2025. {
  2026. PBRDG_GPO_NETWORKS Network;
  2027. LPWSTR NetworkName;
  2028. DBGPRINT(GPO, ("Current Network: %S\r\n", RegValue));
  2029. NetworkName = ExAllocatePoolWithTag(NonPagedPool, (StringLen + 1) * sizeof(WCHAR), 'gdrB');
  2030. if (NULL != NetworkName)
  2031. {
  2032. RtlZeroMemory(NetworkName, (StringLen + 1) * sizeof(WCHAR));
  2033. wcscpy(NetworkName, RegValue);
  2034. //
  2035. // Try to find a match for the current network identifier (generally the adapter guid)
  2036. //
  2037. status = BrdgGpoFindNetwork(g_BrdgGpoGlobals.ListHeadNetworks,
  2038. &Notify->Identifier,
  2039. g_BrdgGpoGlobals.NetworkListLock,
  2040. &Network);
  2041. if (STATUS_NOT_FOUND == status)
  2042. {
  2043. //
  2044. // No match so this is a new key (very unlikely code path).
  2045. //
  2046. status = BrdgGpoAllocateAndInitializeNetwork( &Network,
  2047. Notify->Identifier.Buffer,
  2048. NetworkName);
  2049. if (NT_SUCCESS(status))
  2050. {
  2051. status = BrdgGpoInsertNetwork( g_BrdgGpoGlobals.ListHeadNetworks,
  2052. &Network->ListEntry,
  2053. g_BrdgGpoGlobals.NetworkListLock);
  2054. if (!NT_SUCCESS(status))
  2055. {
  2056. BrdgGpoFreeNetworkAndData(Network);
  2057. Network = NULL;
  2058. }
  2059. }
  2060. }
  2061. else
  2062. {
  2063. //
  2064. // This is expected to happen most times, if not always.
  2065. //
  2066. status = BrdgGpoUpdateNetworkName( g_BrdgGpoGlobals.ListHeadNetworks,
  2067. &Notify->Identifier,
  2068. NetworkName,
  2069. g_BrdgGpoGlobals.NetworkListLock);
  2070. }
  2071. #if DBG
  2072. if (Network)
  2073. {
  2074. SAFEASSERT(Network->ListEntry.Blink && Network->ListEntry.Flink);
  2075. }
  2076. #endif
  2077. if (NetworkName)
  2078. {
  2079. ExFreePool(NetworkName);
  2080. }
  2081. NdisFreeMemory(RegValue, StringLen, 0);
  2082. }
  2083. }
  2084. else
  2085. {
  2086. //
  2087. // We change the name to NULL since the key appears to have disappeared.
  2088. //
  2089. status = BrdgGpoUpdateNetworkName( g_BrdgGpoGlobals.ListHeadNetworks,
  2090. &Notify->Identifier,
  2091. NULL,
  2092. g_BrdgGpoGlobals.NetworkListLock);
  2093. }
  2094. //
  2095. // Since something changed, we'll just re-verify that we're in
  2096. // the correct bridging mode.
  2097. //
  2098. BrdgGpoCheckForMatchAndUpdateMode();
  2099. //
  2100. // We set this to NULL if we're closing it for shutdown, since we
  2101. // shouldn't close it twices/
  2102. //
  2103. if (Notify->RegKey)
  2104. {
  2105. ZwClose(Notify->RegKey);
  2106. Notify->RegKey = NULL;
  2107. }
  2108. if (TRUE == Notify->Recurring)
  2109. {
  2110. //
  2111. // Re-register. The notify object contains enough info to do this.
  2112. //
  2113. status = BrdgGpoRequestNotification(Notify);
  2114. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  2115. {
  2116. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  2117. {
  2118. BrdgDecrementWaitRef(&Notify->RefCount);
  2119. BrdgGpoFreeNotifyStructAndData(Notify);
  2120. Notify = NULL;
  2121. }
  2122. }
  2123. else if (!NT_SUCCESS(status))
  2124. {
  2125. BrdgGpoFreeNotifyStructAndData(Notify);
  2126. Notify = NULL;
  2127. }
  2128. }
  2129. }
  2130. VOID
  2131. BrdgGpoWindowsGroupPolicyChangeCallback(
  2132. PBRDG_GPO_NOTIFY_KEY Notify
  2133. )
  2134. /*++
  2135. Routine Description:
  2136. Called back if the Windows Group Policy key changes.
  2137. We attempt to register for the Network Connections key changes
  2138. if we haven't already done so.
  2139. Arguments:
  2140. Notify - Notify structure that we passed in
  2141. to ZwNotifyChangeKey
  2142. Return Value:
  2143. None.
  2144. --*/
  2145. {
  2146. DBGPRINT(GPO, ("BrdgGpoWindowsGroupPolicyChangeCallback\r\n"));
  2147. if (!g_BrdgGpoGlobals.RegisteredForNetworkConnectionsGroupPolicyChanges)
  2148. {
  2149. BrdgGpoRegisterForNetworkConnectionsGroupPolicyNotification();
  2150. }
  2151. //
  2152. // We set this to NULL if we're closing it for shutdown, since we
  2153. // shouldn't close it twices/
  2154. //
  2155. if (Notify->RegKey)
  2156. {
  2157. ZwClose(Notify->RegKey);
  2158. Notify->RegKey = NULL;
  2159. }
  2160. if (TRUE == Notify->Recurring)
  2161. {
  2162. NTSTATUS status;
  2163. status = BrdgGpoRequestNotification(Notify);
  2164. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  2165. {
  2166. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  2167. {
  2168. BrdgDecrementWaitRef(&Notify->RefCount);
  2169. BrdgGpoFreeNotifyStructAndData(Notify);
  2170. Notify = NULL;
  2171. }
  2172. }
  2173. else if (!NT_SUCCESS(status))
  2174. {
  2175. BrdgGpoFreeNotifyStructAndData(Notify);
  2176. Notify = NULL;
  2177. }
  2178. }
  2179. }
  2180. VOID
  2181. BrdgGpoHiveListCallback(
  2182. IN PBRDG_GPO_NOTIFY_KEY Notify
  2183. )
  2184. /*++
  2185. Routine Description:
  2186. Called back if the HiveList key changes.
  2187. If it does, we attempt to open the software hive. If that succeeds then
  2188. we attempt to register for the keys that we're interested in under
  2189. the Software Hive.
  2190. Arguments:
  2191. Notify - Notify structure that we passed in
  2192. to ZwNotifyChangeKey
  2193. Return Value:
  2194. None.
  2195. --*/
  2196. {
  2197. NTSTATUS status;
  2198. UNICODE_STRING Software;
  2199. OBJECT_ATTRIBUTES ObAttr;
  2200. HANDLE hKey;
  2201. DBGPRINT(GPO, ("BrdgGpoHiveListCallback\r\n"));
  2202. RtlInitUnicodeString(&Software, SoftwareHiveKey);
  2203. InitializeObjectAttributes( &ObAttr,
  2204. &Software,
  2205. OBJ_CASE_INSENSITIVE,
  2206. NULL,
  2207. NULL
  2208. );
  2209. status = ZwOpenKey(&hKey, KEY_READ, &ObAttr);
  2210. if (NT_SUCCESS(status))
  2211. {
  2212. BrdgGpoRegisterForGroupPolicyNetworkNameNotification();
  2213. BrdgGpoRegisterForWindowsGroupPolicyNotification();
  2214. BrdgGpoRegisterForGroupPolicyNotification();
  2215. //
  2216. // To avoid turning the bridge on and then off again, we set this just after
  2217. // verifying the Network Connections policy setting.
  2218. //
  2219. BrdgGpoRegisterForNetworkConnectionsGroupPolicyNotification();
  2220. g_BrdgGpoGlobals.WaitingOnSoftwareHive = FALSE;
  2221. Notify->Recurring = FALSE;
  2222. ZwClose(hKey);
  2223. }
  2224. //
  2225. // We set this to NULL if we're closing it for shutdown, since we
  2226. // shouldn't close it twices/
  2227. //
  2228. if (Notify->RegKey)
  2229. {
  2230. ZwClose(Notify->RegKey);
  2231. Notify->RegKey = NULL;
  2232. }
  2233. if (TRUE == Notify->Recurring)
  2234. {
  2235. status = BrdgGpoRequestNotification(Notify);
  2236. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  2237. {
  2238. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  2239. {
  2240. BrdgDecrementWaitRef(&Notify->RefCount);
  2241. BrdgGpoFreeNotifyStructAndData(Notify);
  2242. Notify = NULL;
  2243. }
  2244. }
  2245. else if (!NT_SUCCESS(status))
  2246. {
  2247. BrdgGpoFreeNotifyStructAndData(Notify);
  2248. Notify = NULL;
  2249. }
  2250. }
  2251. }
  2252. VOID
  2253. BrdgGpoGroupPolicyChangeCallback(
  2254. PBRDG_GPO_NOTIFY_KEY Notify
  2255. )
  2256. /*++
  2257. Routine Description:
  2258. Called back if the Group Policy key changes.
  2259. Arguments:
  2260. Notify - Notify structure that we passed in
  2261. to ZwNotifyChangeKey
  2262. Return Value:
  2263. None.
  2264. --*/
  2265. {
  2266. DBGPRINT(GPO, ("BrdgGpoGroupPolicyChangeCallback\r\n"));
  2267. if (!g_BrdgGpoGlobals.RegisteredForGroupPolicyHistoryChanges)
  2268. {
  2269. BrdgGpoRegisterForGroupPolicyNetworkNameNotification();
  2270. }
  2271. //
  2272. // We set this to NULL if we're closing it for shutdown, since we
  2273. // shouldn't close it twice.
  2274. //
  2275. if (Notify->RegKey)
  2276. {
  2277. ZwClose(Notify->RegKey);
  2278. Notify->RegKey = NULL;
  2279. }
  2280. if (TRUE == Notify->Recurring)
  2281. {
  2282. NTSTATUS status;
  2283. status = BrdgGpoRequestNotification(Notify);
  2284. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  2285. {
  2286. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  2287. {
  2288. BrdgDecrementWaitRef(&Notify->RefCount);
  2289. BrdgGpoFreeNotifyStructAndData(Notify);
  2290. Notify = NULL;
  2291. }
  2292. }
  2293. else if (!NT_SUCCESS(status))
  2294. {
  2295. BrdgGpoFreeNotifyStructAndData(Notify);
  2296. Notify = NULL;
  2297. }
  2298. }
  2299. }
  2300. VOID
  2301. BrdgGpoNetworkConnectionsGroupPolicyChangeCallback(
  2302. PBRDG_GPO_NOTIFY_KEY Notify
  2303. )
  2304. /*++
  2305. Routine Description:
  2306. Called back if the Network Connection Policy key changes.
  2307. Arguments:
  2308. Notify - Notify structure that we passed in
  2309. to ZwNotifyChangeKey
  2310. Return Value:
  2311. None.
  2312. --*/
  2313. {
  2314. NTSTATUS status;
  2315. ULONG RegValue;
  2316. DBGPRINT(GPO, ("BrdgGpoNetworkConnectionsGroupPolicyChangeCallback\r\n"));
  2317. DBGPRINT(GPO, ("Called for Key: %S re-registering.\r\n", Notify->RegKeyName.Buffer));
  2318. status = BrdgReadRegDWord( &Notify->RegKeyName,
  2319. Notify->RegValue.Buffer,
  2320. &RegValue);
  2321. if (NT_SUCCESS(status))
  2322. {
  2323. DBGPRINT(GPO, ("Bridge Policy Setting: %d\r\n", RegValue));
  2324. }
  2325. //
  2326. // Since something changed, we'll just re-verify that we're in
  2327. // the correct bridging mode.
  2328. //
  2329. BrdgGpoCheckForMatchAndUpdateMode();
  2330. //
  2331. // We set this to NULL if we're closing it for shutdown, since we
  2332. // shouldn't close it twice.
  2333. //
  2334. if (Notify->RegKey)
  2335. {
  2336. ZwClose(Notify->RegKey);
  2337. Notify->RegKey = NULL;
  2338. }
  2339. if (TRUE == Notify->Recurring)
  2340. {
  2341. status = BrdgGpoRequestNotification(Notify);
  2342. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  2343. {
  2344. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  2345. {
  2346. BrdgDecrementWaitRef(&Notify->RefCount);
  2347. BrdgGpoFreeNotifyStructAndData(Notify);
  2348. Notify = NULL;
  2349. }
  2350. }
  2351. else if (!NT_SUCCESS(status))
  2352. {
  2353. BrdgGpoFreeNotifyStructAndData(Notify);
  2354. Notify = NULL;
  2355. }
  2356. }
  2357. }
  2358. NTSTATUS
  2359. BrdgGpoUpdateGroupPolicyNetworkName()
  2360. {
  2361. NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND;
  2362. PWCHAR RegValue = NULL;
  2363. LPWSTR GroupPolicyNetwork = NULL;
  2364. ULONG DataLen = 0;
  2365. UNICODE_STRING RegKeyName;
  2366. RtlInitUnicodeString(&RegKeyName, HistoryKey);
  2367. //
  2368. // Read the current value from the registry
  2369. //
  2370. status = BrdgReadRegUnicode(&RegKeyName,
  2371. L"NetworkName",
  2372. &RegValue,
  2373. &DataLen);
  2374. if (NT_SUCCESS(status))
  2375. {
  2376. DBGPRINT(GPO, ("Group Policy Network Name: %S\r\n", RegValue));
  2377. //
  2378. // Almost always checked at DISPATCH_LEVEL, so we allocate from NonPagedPool
  2379. //
  2380. GroupPolicyNetwork = ExAllocatePoolWithTag(NonPagedPool, (DataLen + 1) * sizeof(WCHAR), 'gdrB');
  2381. if (GroupPolicyNetwork)
  2382. {
  2383. if (NULL != g_BrdgGpoGlobals.GroupPolicyNetworkName.Buffer)
  2384. {
  2385. ExFreePool( g_BrdgGpoGlobals.GroupPolicyNetworkName.Buffer);
  2386. }
  2387. RtlZeroMemory(GroupPolicyNetwork, (DataLen + 1) * sizeof(WCHAR));
  2388. wcsncpy(GroupPolicyNetwork, RegValue, DataLen);
  2389. RtlInitUnicodeString(&g_BrdgGpoGlobals.GroupPolicyNetworkName, GroupPolicyNetwork);
  2390. //
  2391. // Since something changed, we'll just re-verify that we're in
  2392. // the correct bridging mode.
  2393. //
  2394. BrdgGpoCheckForMatchAndUpdateMode();
  2395. }
  2396. NdisFreeMemory(RegValue, DataLen, 0);
  2397. }
  2398. return status;
  2399. }
  2400. VOID
  2401. BrdgGpoGroupPolicyNetworkNameChangeCallback(
  2402. PBRDG_GPO_NOTIFY_KEY Notify
  2403. )
  2404. /*++
  2405. Routine Description:
  2406. Called back if the Group Policy History key changes.
  2407. Arguments:
  2408. Notify - Notify structure that we passed in
  2409. to ZwNotifyChangeKey
  2410. Return Value:
  2411. None.
  2412. --*/
  2413. {
  2414. NTSTATUS status;
  2415. //
  2416. // Read the current value from the registry
  2417. //
  2418. status = BrdgGpoUpdateGroupPolicyNetworkName();
  2419. //
  2420. // We set this to NULL if we're closing it for shutdown, since we
  2421. // shouldn't close it twice.
  2422. //
  2423. if (Notify->RegKey)
  2424. {
  2425. ZwClose(Notify->RegKey);
  2426. Notify->RegKey = NULL;
  2427. }
  2428. if (TRUE == Notify->Recurring)
  2429. {
  2430. status = BrdgGpoRequestNotification(Notify);
  2431. if (STATUS_SHUTDOWN_IN_PROGRESS == status)
  2432. {
  2433. if (!Notify->ListEntry.Blink && !Notify->ListEntry.Flink)
  2434. {
  2435. BrdgDecrementWaitRef(&Notify->RefCount);
  2436. BrdgGpoFreeNotifyStructAndData(Notify);
  2437. Notify = NULL;
  2438. }
  2439. }
  2440. else if (!NT_SUCCESS(status))
  2441. {
  2442. BrdgGpoFreeNotifyStructAndData(Notify);
  2443. Notify = NULL;
  2444. }
  2445. }
  2446. }
  2447. // ===========================================================================
  2448. //
  2449. // GROUP POLICY NETWORK VERIFICATION FUNCTIONS
  2450. //
  2451. // ===========================================================================
  2452. BOOLEAN
  2453. BrdgGpoAllowedToBridge()
  2454. /*++
  2455. Routine Description:
  2456. Checks the Network Connections policy key for the Bridge Policy setting.
  2457. Arguments:
  2458. None.
  2459. Return Value:
  2460. TRUE if we couldn't find a Policy Value, or the Value is 1.
  2461. FALSE if the policy exists and contains a value of 0.
  2462. --*/
  2463. {
  2464. NTSTATUS status;
  2465. UNICODE_STRING RegKey;
  2466. ULONG RegValue;
  2467. BOOLEAN CanBridge = TRUE; // If there is no key then we're allowed to bridge.
  2468. RtlInitUnicodeString(&RegKey, NetworkPoliciesKey);
  2469. status = BrdgReadRegDWord(&RegKey, (LPWSTR) BridgePolicyValue, &RegValue);
  2470. if (NT_SUCCESS(status))
  2471. {
  2472. if (FALSE == RegValue)
  2473. {
  2474. CanBridge = FALSE;
  2475. }
  2476. }
  2477. return CanBridge;
  2478. }
  2479. VOID
  2480. BrdgGpoUpdateBridgeMode(
  2481. BOOLEAN NetworkMatch
  2482. )
  2483. /*++
  2484. Routine Description:
  2485. Checks for a Network Match and if we're not allowed to bridge then
  2486. turns bridging off, otherwise it turns it on.
  2487. Arguments:
  2488. NetworkMatch - Do we have a match for the group policy network?
  2489. Return Value:
  2490. None.
  2491. --*/
  2492. {
  2493. //
  2494. // If we're still waiting on the software hive then
  2495. // we shouldn't do any further processing for this.
  2496. //
  2497. if (BrdgGpoWaitingOnSoftwareHive())
  2498. {
  2499. return;
  2500. }
  2501. if (NetworkMatch && !BrdgGpoAllowedToBridge())
  2502. {
  2503. BrdgFwdChangeBridging(FALSE);
  2504. }
  2505. else
  2506. {
  2507. BrdgFwdChangeBridging(TRUE);
  2508. }
  2509. }
  2510. VOID
  2511. BrdgGpoCheckForMatchAndUpdateMode()
  2512. /*++
  2513. Routine Description:
  2514. This looks for a matching network and group policy network and
  2515. attempts to update the bridging status accordingly.
  2516. Arguments:
  2517. None.
  2518. Return Value:
  2519. None.
  2520. --*/
  2521. {
  2522. NTSTATUS status;
  2523. if (NULL != g_BrdgGpoGlobals.ListHeadNetworks)
  2524. {
  2525. status = BrdgGpoMatchNetworkName( g_BrdgGpoGlobals.ListHeadNetworks,
  2526. &g_BrdgGpoGlobals.GroupPolicyNetworkName,
  2527. g_BrdgGpoGlobals.NetworkListLock);
  2528. if (BRDG_STATUS_EMPTY_LIST != status)
  2529. {
  2530. if (STATUS_SUCCESS == status)
  2531. {
  2532. //
  2533. // We found a match. Check if we're allowed to run.
  2534. //
  2535. BrdgGpoUpdateBridgeMode(BRDG_ON_SAME_NETWORK);
  2536. }
  2537. else if (STATUS_NO_MATCH == status)
  2538. {
  2539. //
  2540. // No match, but we may need to turn bridging back on.
  2541. //
  2542. BrdgGpoUpdateBridgeMode(BRDG_ON_DIFFERENT_NETWORK);
  2543. }
  2544. else
  2545. {
  2546. // We should never get here.
  2547. SAFEASSERT(FALSE);
  2548. }
  2549. }
  2550. else if (BrdgGpoAllowedToBridge())
  2551. {
  2552. BrdgFwdChangeBridging(TRUE);
  2553. }
  2554. }
  2555. }
  2556. NTSTATUS BrdgGpoGetCurrentNetwork(
  2557. IN PUNICODE_STRING RegKeyName,
  2558. OUT PWCHAR* NetworkName)
  2559. /*++
  2560. Routine Description:
  2561. Determines the current network that we are on. This either uses the DHCP Domain name,
  2562. or the IP Address ANDed with the Subnet mask.
  2563. For example: 10.251.1.3 AND 255.0.0.0 results in a network of 10.0.0.0
  2564. This routine MUST be called at IRQL = PASSIVE_LEVEL.
  2565. Arguments:
  2566. RegKeyName (IN) - The RegistryKey for the adapter we're interested in.
  2567. NetworkName (OUT) - The network we're currently one.
  2568. Return Value(s):
  2569. STATUS_SUCCESS
  2570. STATUS_INVALID_PARAMETER
  2571. STATUS_NO_IP_ADDRESSES - if we've released the only address we have.
  2572. Out of memory can also be returned.
  2573. --*/
  2574. {
  2575. NTSTATUS status;
  2576. PWCHAR lpszNetworkName = NULL;
  2577. BOOLEAN HaveNetwork = FALSE;
  2578. BOOLEAN HaveDhcpDomain = FALSE;
  2579. WCHAR BaseNetwork[MAX_IP4_STRING_LEN];
  2580. PWCHAR DhcpIPAddress = NULL;
  2581. ULONG DhcpIPAddrLen = 0;
  2582. if (!RegKeyName || !NetworkName)
  2583. {
  2584. return STATUS_INVALID_PARAMETER;
  2585. }
  2586. RtlZeroMemory(BaseNetwork, MAX_IP4_STRING_LEN * sizeof(WCHAR));
  2587. *NetworkName = NULL;
  2588. //
  2589. // We don't have a valid Network Name. Attempt to build one
  2590. // from the DhcpIPAddess and DhcpSubnetMask.
  2591. //
  2592. status = BrdgReadRegUnicode(RegKeyName,
  2593. L"DhcpIPAddress",
  2594. &DhcpIPAddress,
  2595. &DhcpIPAddrLen);
  2596. if (NT_SUCCESS(status))
  2597. {
  2598. PWCHAR DhcpSubnetMask = NULL;
  2599. ULONG DhcpSubnetMaskLen = 0;
  2600. status = BrdgReadRegUnicode(RegKeyName,
  2601. L"DhcpSubnetMask",
  2602. &DhcpSubnetMask,
  2603. &DhcpSubnetMaskLen);
  2604. if (NT_SUCCESS(status))
  2605. {
  2606. LPWSTR Terminator;
  2607. in_addr ipaddr;
  2608. in_addr subnet;
  2609. //
  2610. // We and the two values together to get the Network.
  2611. // For example: 10.251.1.3 AND 255.0.0.0 gives 10.0.0.0
  2612. //
  2613. status = BrdgTdiIpv4StringToAddress(DhcpIPAddress,
  2614. FALSE,
  2615. &Terminator,
  2616. &ipaddr);
  2617. if (NT_SUCCESS(status))
  2618. {
  2619. in_addr network;
  2620. status = BrdgTdiIpv4StringToAddress(DhcpSubnetMask,
  2621. FALSE,
  2622. &Terminator,
  2623. &subnet);
  2624. network.S_un.S_addr = ipaddr.S_un.S_addr & subnet.S_un.S_addr;
  2625. DBGPRINT(GPO,
  2626. ("in_addr = %u.%u.%u.%u\r\n",
  2627. network.S_un.S_un_b.s_b1, network.S_un.S_un_b.s_b2,
  2628. network.S_un.S_un_b.s_b3, network.S_un.S_un_b.s_b4));
  2629. //
  2630. // Do we have a valid IPaddress
  2631. //
  2632. if (0 != ipaddr.S_un.S_addr)
  2633. {
  2634. _snwprintf( BaseNetwork,
  2635. MAX_IP4_STRING_LEN,
  2636. L"%u.%u.%u.%u",
  2637. network.S_un.S_un_b.s_b1,
  2638. network.S_un.S_un_b.s_b2,
  2639. network.S_un.S_un_b.s_b3,
  2640. network.S_un.S_un_b.s_b4);
  2641. HaveNetwork = TRUE;
  2642. }
  2643. }
  2644. }
  2645. }
  2646. if (!HaveNetwork)
  2647. {
  2648. PWCHAR IPAddress = NULL;
  2649. ULONG IPAddrLen = 0;
  2650. status = BrdgReadRegUnicode(RegKeyName,
  2651. L"IPAddress",
  2652. &IPAddress,
  2653. &IPAddrLen);
  2654. if (NT_SUCCESS(status))
  2655. {
  2656. PWCHAR SubnetMask = NULL;
  2657. ULONG SubnetMaskLen = 0;
  2658. status = BrdgReadRegUnicode(RegKeyName,
  2659. L"SubnetMask",
  2660. &SubnetMask,
  2661. &SubnetMaskLen);
  2662. if (NT_SUCCESS(status))
  2663. {
  2664. LPWSTR Terminator;
  2665. in_addr ipaddr;
  2666. in_addr subnet;
  2667. //
  2668. // We and the two values together to get the Network.
  2669. // For example: 10.251.1.3 AND 255.0.0.0 gives 10.0.0.0
  2670. //
  2671. status = BrdgTdiIpv4StringToAddress(IPAddress,
  2672. FALSE,
  2673. &Terminator,
  2674. &ipaddr);
  2675. if (NT_SUCCESS(status))
  2676. {
  2677. in_addr network;
  2678. status = BrdgTdiIpv4StringToAddress(SubnetMask,
  2679. FALSE,
  2680. &Terminator,
  2681. &subnet);
  2682. network.S_un.S_addr = ipaddr.S_un.S_addr & subnet.S_un.S_addr;
  2683. DBGPRINT(GPO,
  2684. ("in_addr = %u.%u.%u.%u\r\n",
  2685. network.S_un.S_un_b.s_b1, network.S_un.S_un_b.s_b2,
  2686. network.S_un.S_un_b.s_b3, network.S_un.S_un_b.s_b4));
  2687. //
  2688. // Do we have a valid IPaddress
  2689. //
  2690. if (0 != ipaddr.S_un.S_addr)
  2691. {
  2692. _snwprintf( BaseNetwork,
  2693. MAX_IP4_STRING_LEN,
  2694. L"%u.%u.%u.%u",
  2695. network.S_un.S_un_b.s_b1,
  2696. network.S_un.S_un_b.s_b2,
  2697. network.S_un.S_un_b.s_b3,
  2698. network.S_un.S_un_b.s_b4);
  2699. HaveNetwork = TRUE;
  2700. }
  2701. }
  2702. }
  2703. }
  2704. }
  2705. if (!HaveNetwork)
  2706. {
  2707. //
  2708. // Returning this will cause us not to update the network name this
  2709. // card.
  2710. //
  2711. status = STATUS_NO_IP_ADDRESSES;
  2712. }
  2713. else if (HaveDhcpDomain)
  2714. {
  2715. *NetworkName = lpszNetworkName;
  2716. status = STATUS_SUCCESS;
  2717. }
  2718. else
  2719. {
  2720. status = NdisAllocateMemoryWithTag(NetworkName,
  2721. ((UINT)wcslen(BaseNetwork) + 1) * sizeof(WCHAR),
  2722. 'gdrB');
  2723. wcscpy(*NetworkName, BaseNetwork);
  2724. }
  2725. return status;
  2726. }
  2727. // ===========================================================================
  2728. //
  2729. // NETWORK LIST MANIPULATION FUNCTIONS
  2730. //
  2731. // ===========================================================================
  2732. NTSTATUS
  2733. BrdgGpoInitializeNetworkList()
  2734. /*++
  2735. Routine Description:
  2736. Initializes the Network List and Lock.
  2737. This can can be called at any IRQL (but since it's called from driver entry,
  2738. it will most likely be called at PASSIVE_LEVEL).
  2739. Arguments:
  2740. None.
  2741. Return Value(s):
  2742. STATUS_SUCCESS
  2743. STATUS_INSUFFICIENT_RESOURCES
  2744. --*/
  2745. {
  2746. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  2747. g_BrdgGpoGlobals.ListHeadNetworks = ExAllocatePoolWithTag(NonPagedPool, sizeof(LIST_ENTRY), 'gdrB');
  2748. if (NULL != g_BrdgGpoGlobals.ListHeadNetworks)
  2749. {
  2750. InitializeListHead(g_BrdgGpoGlobals.ListHeadNetworks);
  2751. g_BrdgGpoGlobals.NetworkListLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(NDIS_RW_LOCK), 'gdrB');
  2752. if (g_BrdgGpoGlobals.NetworkListLock)
  2753. {
  2754. NdisInitializeReadWriteLock(g_BrdgGpoGlobals.NetworkListLock);
  2755. status = STATUS_SUCCESS;
  2756. }
  2757. else
  2758. {
  2759. ExFreePool(g_BrdgGpoGlobals.ListHeadNetworks);
  2760. }
  2761. }
  2762. return status;
  2763. }
  2764. VOID
  2765. BrdgGpoUninitializeNetworkList()
  2766. /*++
  2767. Routine Description:
  2768. Frees the memory associated with the Network List.
  2769. This can be called at IRQL <= DISPATCH_LEVEL but is likely
  2770. to be called at PASSIVE_LEVEL as it's during shutdown.
  2771. Arguments:
  2772. None.
  2773. Return Value:
  2774. None.
  2775. --*/
  2776. {
  2777. ExFreePool(g_BrdgGpoGlobals.ListHeadNetworks);
  2778. ExFreePool(g_BrdgGpoGlobals.NetworkListLock);
  2779. }
  2780. VOID
  2781. BrdgGpoAcquireNetworkListLock(
  2782. IN PNDIS_RW_LOCK NetworkListLock,
  2783. IN BOOLEAN fWrite,
  2784. IN OUT PLOCK_STATE LockState
  2785. )
  2786. /*++
  2787. Routine Description:
  2788. Acquires the NetworkList read-write lock. We support a NULL Lock
  2789. as it allows us to acquire for write and then call functions that
  2790. need the lock for read without locking up the system (by
  2791. supplying NULL for the lock).
  2792. This can be called at IRQL <= DISPATCH_LEVEL
  2793. Arguments:
  2794. NetworkListLock - Read-Write Lock to be acquired.
  2795. fWrite - TRUE == Write Access, FALSE == Read Access
  2796. LockState - Opaque value used by NDIS.
  2797. Return Value:
  2798. None.
  2799. --*/
  2800. {
  2801. if (NetworkListLock)
  2802. {
  2803. NdisAcquireReadWriteLock(NetworkListLock, fWrite, LockState);
  2804. }
  2805. }
  2806. VOID
  2807. BrdgGpoReleaseNetworkListLock(
  2808. IN PNDIS_RW_LOCK NetworkListLock,
  2809. IN OUT PLOCK_STATE LockState
  2810. )
  2811. /*++
  2812. Routine Description:
  2813. Releases the NetworkList read-write lock. We support a NULL Lock
  2814. as it allows us to acquire for write and then call functions that
  2815. need the lock for read without locking up the system (by
  2816. supplying NULL for the lock).
  2817. This can be called at IRQL <= DISPATCH_LEVEL
  2818. Arguments:
  2819. NetworkListLock - Read-Write Lock to be released.
  2820. LockState - Opaque value used by NDIS.
  2821. Return Value:
  2822. None.
  2823. --*/
  2824. {
  2825. if (NetworkListLock)
  2826. {
  2827. NdisReleaseReadWriteLock(NetworkListLock, LockState);
  2828. }
  2829. }
  2830. NTSTATUS
  2831. BrdgGpoAllocateAndInitializeNetwork(
  2832. IN OUT PBRDG_GPO_NETWORKS* Network,
  2833. IN PWCHAR Identifier,
  2834. IN PWCHAR NetworkName
  2835. )
  2836. /*++
  2837. Routine Description:
  2838. Allocates the memory needed for a Network structure from the NonPaged pool
  2839. and copies the data into the structure.
  2840. Must be called at IRQL <= APC_LEVEL.
  2841. Arguments:
  2842. Network - The structure to be allocated and initialized with the data.
  2843. Identifier - The AdapterID for this network structure.
  2844. NetworkName - The current network that we are on. This can be NULL if we
  2845. haven't determined a network yet.
  2846. Return Value:
  2847. STATUS_SUCCESS
  2848. STATUS_INSUFFICIENT_RESOURCES
  2849. --*/
  2850. {
  2851. PBRDG_GPO_NETWORKS pNetwork;
  2852. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  2853. *Network = NULL;
  2854. if (!BrdgGpoProcessingNotifications())
  2855. {
  2856. return STATUS_SHUTDOWN_IN_PROGRESS;
  2857. }
  2858. //
  2859. // Everything in this struct will be used at DISPATCH_LEVEL, so all of it is
  2860. // allocated from the NonPagedPool
  2861. //
  2862. pNetwork = ExAllocatePoolWithTag(NonPagedPool, sizeof(BRDG_GPO_NETWORKS), 'gdrB');
  2863. if (NULL != pNetwork)
  2864. {
  2865. PUNICODE_STRING pIdentifier = NULL;
  2866. PUNICODE_STRING pNetworkName = NULL;
  2867. LPWSTR lpszIdentifier = NULL;
  2868. LPWSTR lpszNetworkName = NULL;
  2869. pIdentifier = ExAllocatePoolWithTag(NonPagedPool, sizeof(UNICODE_STRING), 'gdrB');
  2870. if (pIdentifier)
  2871. {
  2872. pNetworkName = ExAllocatePoolWithTag(NonPagedPool, sizeof(UNICODE_STRING), 'gdrB');
  2873. if (pNetworkName)
  2874. {
  2875. lpszIdentifier = ExAllocatePoolWithTag(NonPagedPool, (wcslen(Identifier) + 1) * sizeof(WCHAR), 'gdrB');
  2876. if (lpszIdentifier)
  2877. {
  2878. RtlZeroMemory(lpszIdentifier, wcslen(Identifier) + 1);
  2879. wcscpy(lpszIdentifier, Identifier);
  2880. //
  2881. // A NULL Network name is valid, so we only allocate it if we are passed one.
  2882. //
  2883. if (NetworkName)
  2884. {
  2885. lpszNetworkName = ExAllocatePoolWithTag(NonPagedPool, (wcslen(NetworkName) + 1) * sizeof(WCHAR), 'gdrB');
  2886. if (lpszNetworkName)
  2887. {
  2888. RtlZeroMemory(lpszNetworkName, wcslen(NetworkName) + 1);
  2889. wcscpy(lpszNetworkName, NetworkName);
  2890. }
  2891. }
  2892. //
  2893. // This is a Logical AND operation:
  2894. // Either we have both or we have neither. We can't have one and not the other, if we do
  2895. // then we didn't succeed the last allocate.
  2896. //
  2897. if ((NetworkName && lpszNetworkName) || (!NetworkName && !lpszNetworkName))
  2898. {
  2899. RtlInitUnicodeString(pIdentifier, lpszIdentifier);
  2900. //
  2901. // This may be NULL, but that's fine, since it means we'll add it when it gets written.
  2902. //
  2903. RtlInitUnicodeString(pNetworkName, lpszNetworkName);
  2904. pNetwork->Identifier = pIdentifier;
  2905. pNetwork->NetworkName = pNetworkName;
  2906. pNetwork->ListEntry.Blink = NULL;
  2907. pNetwork->ListEntry.Flink = NULL;
  2908. *Network = pNetwork;
  2909. status = STATUS_SUCCESS;
  2910. }
  2911. }
  2912. }
  2913. }
  2914. if (!NT_SUCCESS(status))
  2915. {
  2916. if (lpszIdentifier)
  2917. {
  2918. ExFreePool(lpszIdentifier);
  2919. }
  2920. if (pIdentifier)
  2921. {
  2922. ExFreePool(pIdentifier);
  2923. }
  2924. if (pNetworkName)
  2925. {
  2926. ExFreePool(pNetworkName);
  2927. }
  2928. if (pNetwork)
  2929. {
  2930. ExFreePool(pNetwork);
  2931. }
  2932. }
  2933. }
  2934. return status;
  2935. }
  2936. VOID
  2937. BrdgGpoFreeNetworkAndData(
  2938. IN PBRDG_GPO_NETWORKS Network)
  2939. /*++
  2940. Routine Description:
  2941. This frees any data associated with a particular network.
  2942. This can be called IRQL <= DISPATCH_LEVEL.
  2943. Arguments:
  2944. Network - Structure containing an ID and Network name
  2945. for an adapter.
  2946. Return Value:
  2947. None.
  2948. --*/
  2949. {
  2950. //
  2951. // First free the data associated with this entry
  2952. //
  2953. if (Network->Identifier)
  2954. {
  2955. if (Network->Identifier->Buffer)
  2956. {
  2957. ExFreePool(Network->Identifier->Buffer);
  2958. }
  2959. ExFreePool(Network->Identifier);
  2960. }
  2961. if (Network->NetworkName)
  2962. {
  2963. if (Network->NetworkName->Buffer)
  2964. {
  2965. ExFreePool(Network->NetworkName->Buffer);
  2966. }
  2967. ExFreePool(Network->NetworkName);
  2968. }
  2969. //
  2970. // Now free the structure
  2971. //
  2972. ExFreePool(Network);
  2973. }
  2974. NTSTATUS
  2975. BrdgGpoEmptyNetworkList(
  2976. IN PLIST_ENTRY NetworkList,
  2977. IN PNDIS_RW_LOCK NetworkListLock)
  2978. /*++
  2979. Routine Description:
  2980. Empties the existing list and frees all the items.
  2981. Do not acquire the list lock before calling this function.
  2982. Arguments:
  2983. NetworkList - The list of current networks.
  2984. NetworkListLock - Ndis Read Write Lock for synchronizing changes to the list.
  2985. Return Value:
  2986. STATUS_SUCCESS
  2987. --*/
  2988. {
  2989. NTSTATUS status = STATUS_SUCCESS;
  2990. LOCK_STATE LockState;
  2991. BrdgGpoAcquireNetworkListLock(NetworkListLock, TRUE /* Write-access */, &LockState);
  2992. //
  2993. // Loop through the list deleting the entries.
  2994. //
  2995. while (!IsListEmpty(NetworkList))
  2996. {
  2997. PBRDG_GPO_NETWORKS Network;
  2998. PLIST_ENTRY pListEntry;
  2999. pListEntry = RemoveHeadList(NetworkList);
  3000. Network = CONTAINING_RECORD(pListEntry, BRDG_GPO_NETWORKS, ListEntry);
  3001. BrdgGpoFreeNetworkAndData(Network);
  3002. }
  3003. BrdgGpoReleaseNetworkListLock(NetworkListLock, &LockState);
  3004. return status;
  3005. }
  3006. NTSTATUS
  3007. BrdgGpoInsertNetwork(
  3008. IN PLIST_ENTRY NetworkList,
  3009. IN PLIST_ENTRY Network,
  3010. IN PNDIS_RW_LOCK NetworkListLock)
  3011. /*++
  3012. Routine Description:
  3013. This routine is responsible for adding a new Network to the list.
  3014. If someone attempts to insert an existing item, an error is returned.
  3015. The caller is responsible for calling BrdgGpoUpdateNetworkName instead.
  3016. This routine can be called at IRQL <= DISPATCH_LEVEL.
  3017. Arguments:
  3018. NetworkList - The list of current networks.
  3019. Network - The new Network entry to add to the list.
  3020. NetworkListLock - Ndis Read Write Lock for synchronizing changes to the list.
  3021. Return Value:
  3022. STATUS_SHUTDOWN_IN_PROGRESS - We're busy shutting down, so the item was not added.
  3023. STATUS_INVALID_PARAMETER - One or more of the parameters was NULL.
  3024. STATUS_DUPLICATE_NAME - This entry already exists in the list.
  3025. STATUS_SUCCESS - We successfully added the entry to the list.
  3026. --*/
  3027. {
  3028. PBRDG_GPO_NETWORKS pNetwork = NULL;
  3029. PBRDG_GPO_NETWORKS NewNetwork = NULL;
  3030. LOCK_STATE LockState;
  3031. NTSTATUS status;
  3032. BOOLEAN ShuttingDown;
  3033. if (!NetworkList || !Network || !NetworkListLock)
  3034. {
  3035. return STATUS_INVALID_PARAMETER;
  3036. }
  3037. //
  3038. // Lock the list for update
  3039. //
  3040. BrdgGpoAcquireNetworkListLock(NetworkListLock, TRUE /* Write-access */, &LockState);
  3041. ShuttingDown = !BrdgGpoProcessingNotifications();
  3042. if (!ShuttingDown)
  3043. {
  3044. NewNetwork = CONTAINING_RECORD(Network, BRDG_GPO_NETWORKS, ListEntry);
  3045. //
  3046. // We do this to prevent us accidentally inserting a duplicate item. We grab the lock before so that
  3047. // we can't insert the same item twice.
  3048. //
  3049. status = BrdgGpoFindNetwork( NetworkList,
  3050. NewNetwork->Identifier,
  3051. NULL, // We have already grabbed the lock for Write access.
  3052. &pNetwork);
  3053. if (STATUS_NOT_FOUND == status)
  3054. {
  3055. InsertTailList(NetworkList, Network);
  3056. status = STATUS_SUCCESS;
  3057. }
  3058. else if (STATUS_SUCCESS == status)
  3059. {
  3060. status = STATUS_DUPLICATE_NAME;
  3061. }
  3062. }
  3063. else
  3064. {
  3065. status = STATUS_SHUTDOWN_IN_PROGRESS;
  3066. }
  3067. //
  3068. // Release the lock, we're done updating
  3069. //
  3070. BrdgGpoReleaseNetworkListLock(NetworkListLock, &LockState);
  3071. return status;
  3072. }
  3073. NTSTATUS
  3074. BrdgGpoDeleteNetwork(
  3075. IN PLIST_ENTRY NetworkList,
  3076. IN PUNICODE_STRING NetworkIdentifier,
  3077. IN PNDIS_RW_LOCK NetworkListLock)
  3078. /*++
  3079. Routine Description:
  3080. Deletes an existing network entry.
  3081. Arguments:
  3082. NetworkList - The list of current networks.
  3083. NetworkIdentifier - A unique identifier that identifies which Network entry to remove.
  3084. NetworkListLock - Ndis Read Write Lock for synchronizing changes to the list.
  3085. Return Value:
  3086. STATUS_NOT_FOUND - We couldn't find and entry matching the identifier.
  3087. STATUS_SUCCESS - We were able to remove the entry successfully.
  3088. */
  3089. {
  3090. PBRDG_GPO_NETWORKS pNetwork = NULL;
  3091. LOCK_STATE LockState;
  3092. NTSTATUS status = STATUS_NOT_FOUND;
  3093. //
  3094. // Lock the list for update
  3095. //
  3096. BrdgGpoAcquireNetworkListLock(NetworkListLock, TRUE /* Write-access */, &LockState);
  3097. //
  3098. // Find the entry;
  3099. //
  3100. status = BrdgGpoFindNetwork( NetworkList,
  3101. NetworkIdentifier,
  3102. NULL, // We have already grabbed the lock for Write access.
  3103. &pNetwork);
  3104. if (NT_SUCCESS(status))
  3105. {
  3106. RemoveEntryList(&pNetwork->ListEntry);
  3107. BrdgGpoFreeNetworkAndData(pNetwork);
  3108. pNetwork = NULL;
  3109. status = STATUS_SUCCESS;
  3110. }
  3111. //
  3112. // Release the lock, we're done updating
  3113. //
  3114. BrdgGpoReleaseNetworkListLock(NetworkListLock, &LockState);
  3115. return status;
  3116. }
  3117. NTSTATUS
  3118. BrdgGpoFindNetwork(
  3119. IN PLIST_ENTRY NetworkList,
  3120. IN PUNICODE_STRING NetworkIdentifier,
  3121. IN PNDIS_RW_LOCK NetworkListLock,
  3122. OUT PBRDG_GPO_NETWORKS* Network
  3123. )
  3124. /*++
  3125. Routine Description:
  3126. Finds a particular Network in the list of networks.
  3127. Arguments:
  3128. NetworkList - The list of current networks.
  3129. NetworkIdentifier - A unique identifier that identifies which Network entry to remove.
  3130. NetworkListLock - Ndis Read Write Lock for synchronizing changes to the list.
  3131. Network - The item if found, NULL otherwise.
  3132. Return Value:
  3133. STATUS_NOT_FOUND - No entry matching the identifier could be found.
  3134. STATUS_SUCCESS - The entry was successfully found.
  3135. --*/
  3136. {
  3137. PLIST_ENTRY pListEntry;
  3138. LOCK_STATE LockState;
  3139. NTSTATUS status = STATUS_NOT_FOUND;
  3140. if (!NetworkIdentifier || !Network) // We can have a NULL list lock.
  3141. {
  3142. return STATUS_INVALID_PARAMETER;
  3143. }
  3144. //
  3145. // Set the value to NULL so it isn't accidentally used by someone who doesn't realise
  3146. // that they didn't really get a record back.
  3147. //
  3148. *Network = NULL;
  3149. if (IsListEmpty(NetworkList))
  3150. {
  3151. return STATUS_NOT_FOUND;
  3152. }
  3153. //
  3154. // Lock the list for read
  3155. //
  3156. BrdgGpoAcquireNetworkListLock(NetworkListLock, FALSE /* Read-only */, &LockState);
  3157. //
  3158. // Loop through the list looking for an entry with the same identifier
  3159. //
  3160. for (pListEntry = NetworkList->Flink; pListEntry != NetworkList; pListEntry = pListEntry->Flink)
  3161. {
  3162. PBRDG_GPO_NETWORKS CurrentNetwork;
  3163. CurrentNetwork = CONTAINING_RECORD(pListEntry, BRDG_GPO_NETWORKS, ListEntry);
  3164. //
  3165. // Compare this entries network to the network name that was passed in.
  3166. //
  3167. if ((NULL != CurrentNetwork->NetworkName->Buffer) &&
  3168. (0 == _wcsicmp(CurrentNetwork->Identifier->Buffer, NetworkIdentifier->Buffer)))
  3169. {
  3170. *Network = CurrentNetwork;
  3171. status = STATUS_SUCCESS;
  3172. break;
  3173. }
  3174. }
  3175. //
  3176. // Release the lock, we're done searching
  3177. //
  3178. BrdgGpoReleaseNetworkListLock(NetworkListLock, &LockState);
  3179. return status;
  3180. }
  3181. NTSTATUS
  3182. BrdgGpoMatchNetworkName(
  3183. IN PLIST_ENTRY NetworkList,
  3184. IN PUNICODE_STRING NetworkName,
  3185. IN PNDIS_RW_LOCK NetworkListLock
  3186. )
  3187. /*++
  3188. Routine Description:
  3189. Enumerates through the list looking for a match for the supplied Network Name.
  3190. This can be called on IRQL <= DISPATCH_LEVEL
  3191. Arguments:
  3192. NetworkList - The list through which to enumerate.
  3193. NetworkName - The name to look for.
  3194. NetworkListLock - The NDIS read-write lock for the list.
  3195. Return Value:
  3196. STATUS_NO_MATCH - No match could be found.
  3197. STATUS_SUCCESS - We found a matching Network Name.
  3198. --*/
  3199. {
  3200. PLIST_ENTRY pListEntry;
  3201. LOCK_STATE LockState;
  3202. NTSTATUS status = STATUS_NO_MATCH;
  3203. if (!NetworkList || !NetworkName || !NetworkListLock)
  3204. {
  3205. return STATUS_INVALID_PARAMETER;
  3206. }
  3207. //
  3208. // Lock the list for read
  3209. //
  3210. BrdgGpoAcquireNetworkListLock(NetworkListLock, FALSE /* Read */, &LockState);
  3211. if (!IsListEmpty(NetworkList))
  3212. {
  3213. //
  3214. // Loop through the list looking for an entry with the same NetworkName
  3215. //
  3216. for (pListEntry = NetworkList->Flink; pListEntry != NetworkList; pListEntry = pListEntry->Flink)
  3217. {
  3218. PBRDG_GPO_NETWORKS CurrentNetwork;
  3219. CurrentNetwork = CONTAINING_RECORD(pListEntry, BRDG_GPO_NETWORKS, ListEntry);
  3220. //
  3221. // The network name can be empty, so we don't want to compare if this is the case.
  3222. //
  3223. if ((NULL != CurrentNetwork->NetworkName->Buffer) &&
  3224. (NULL != NetworkName->Buffer) &&
  3225. (0 == _wcsicmp(CurrentNetwork->NetworkName->Buffer, NetworkName->Buffer)))
  3226. {
  3227. status = STATUS_SUCCESS;
  3228. break;
  3229. }
  3230. }
  3231. }
  3232. else
  3233. {
  3234. status = BRDG_STATUS_EMPTY_LIST;
  3235. }
  3236. //
  3237. // Release the lock, we're done searching
  3238. //
  3239. BrdgGpoReleaseNetworkListLock(NetworkListLock, &LockState);
  3240. return status;
  3241. }
  3242. NTSTATUS
  3243. BrdgGpoUpdateNetworkName(
  3244. IN PLIST_ENTRY NetworkList,
  3245. IN PUNICODE_STRING Identifier,
  3246. IN PWCHAR NetworkName,
  3247. IN PNDIS_RW_LOCK NetworkListLock
  3248. )
  3249. /*++
  3250. Routine Description:
  3251. Finds a particular Network in the list of networks.
  3252. Arguments:
  3253. NetworkList - The list of current networks.
  3254. Identifier - A unique identifier that identifies which Network entry to update.
  3255. NetworkName - The new network name for this identifier.
  3256. NetworkListLock - Ndis Read Write Lock for synchronizing changes to the list.
  3257. Return Value:
  3258. STATUS_NOT_FOUND - No entry matching the identifier could be found.
  3259. STATUS_SUCCESS - The entry was successfully found.
  3260. --*/
  3261. {
  3262. PBRDG_GPO_NETWORKS pNetwork;
  3263. NTSTATUS status = STATUS_SUCCESS;
  3264. LOCK_STATE LockState;
  3265. PUNICODE_STRING pNetworkName = NULL;
  3266. LPWSTR lpszNetworkName = NULL;
  3267. if (!NetworkList || !Identifier || !NetworkListLock)
  3268. {
  3269. return STATUS_INVALID_PARAMETER;
  3270. }
  3271. //
  3272. // Allocate space for the new network name from NonPagedPool
  3273. // (it will be accessed from DISPATCH_LEVEL
  3274. //
  3275. pNetworkName = ExAllocatePool(NonPagedPool, sizeof(UNICODE_STRING));
  3276. if (pNetworkName)
  3277. {
  3278. RtlZeroMemory(pNetworkName, sizeof(UNICODE_STRING));
  3279. if (NetworkName)
  3280. {
  3281. lpszNetworkName = ExAllocatePoolWithTag(NonPagedPool, (wcslen(NetworkName) + 1) * sizeof(WCHAR), 'gdrB');
  3282. if (NULL == lpszNetworkName)
  3283. {
  3284. status = STATUS_INSUFFICIENT_RESOURCES;
  3285. }
  3286. else
  3287. {
  3288. wcscpy(lpszNetworkName, NetworkName);
  3289. }
  3290. }
  3291. if (NT_SUCCESS(status))
  3292. {
  3293. RtlInitUnicodeString(pNetworkName, lpszNetworkName);
  3294. }
  3295. else
  3296. {
  3297. //
  3298. // We failed to allocate the actual string, so free the PUNICODE_STRING
  3299. // as well.
  3300. //
  3301. ExFreePool(pNetworkName);
  3302. return status;
  3303. }
  3304. }
  3305. else
  3306. {
  3307. return STATUS_INSUFFICIENT_RESOURCES;
  3308. }
  3309. //
  3310. // Lock the list for update (this will pend until all readers have released the lock).
  3311. //
  3312. BrdgGpoAcquireNetworkListLock(NetworkListLock, TRUE /* Write-access */, &LockState);
  3313. //
  3314. // We pass NULL as the RW-Lock here because we've already locked it and
  3315. // we don't want this entry going away while we're still busy with it
  3316. // (which could happen between a find and an update if we locked twice).
  3317. //
  3318. status = BrdgGpoFindNetwork(NetworkList, Identifier, NULL, &pNetwork);
  3319. if (NT_SUCCESS(status))
  3320. {
  3321. //
  3322. // We first free the current networkname associated with this networkid.
  3323. //
  3324. if (pNetwork->NetworkName->Buffer)
  3325. {
  3326. ExFreePool(pNetwork->NetworkName->Buffer);
  3327. }
  3328. ExFreePool(pNetwork->NetworkName);
  3329. //
  3330. // We do this even if we were passed a NULL network name (ie. the Value/Key has been deleted).
  3331. // Since this means we're probably not on the same network or we've gone to static address and,
  3332. // GPO wise, we're not on the same network.
  3333. //
  3334. pNetwork->NetworkName = pNetworkName;
  3335. }
  3336. else
  3337. {
  3338. ExFreePool(pNetworkName);
  3339. }
  3340. //
  3341. // We're done with the update, so we can release the lock.
  3342. //
  3343. BrdgGpoReleaseNetworkListLock(NetworkListLock, &LockState);
  3344. return status;
  3345. }