Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

501 lines
15 KiB

  1. //*************************************************************
  2. //
  3. // Group Policy Notification
  4. //
  5. // Microsoft Confidential
  6. // Copyright (c) Microsoft Corporation 1997-1998
  7. // All rights reserved
  8. //
  9. // Notes: There is a small window where notifications
  10. // can be lost. If while processing an eMonitor workitem
  11. // a policy event is Pulsed then that notification will
  12. // be lost. This window can be closed by using two threads.
  13. //
  14. // History: 28-Sep-98 SitaramR Created
  15. //
  16. //*************************************************************
  17. #include "gphdr.h"
  18. //
  19. // Work items for notification thread
  20. //
  21. enum EWorkType { eMonitor, // Monitor events
  22. eTerminate }; // Stop monitoring
  23. //
  24. // Entry in list of registered events
  25. //
  26. typedef struct _GPNOTIFINFO
  27. {
  28. HANDLE hEvent; // Event to be signaled
  29. BOOL bMachine; // Machine policy notifcation ?
  30. struct _GPNOTIFINFO * pNext; // Singly linked list ptr
  31. } GPNOTIFINFO;
  32. typedef struct _GPNOTIFICATION
  33. {
  34. HMODULE hModule; // Module handle to userenv.dll
  35. HANDLE hThread; // Notification thread
  36. HANDLE hThreadEvent; // For signaling notification thread (Ordering of fields is important)
  37. HANDLE hMachEvent; // Event signaled by machine policy change
  38. HANDLE hUserEvent; // Event signaled by user policy change
  39. enum EWorkType eWorkType; // Work descrpition for notification thread
  40. GPNOTIFINFO * pNotifList; // List of registered events
  41. } GPNOTIFICATION;
  42. GPNOTIFICATION g_Notif = { NULL,
  43. NULL,
  44. NULL,
  45. NULL,
  46. NULL,
  47. eMonitor,
  48. NULL };
  49. CRITICAL_SECTION g_NotifyCS; // Lock
  50. //
  51. // Forward decls
  52. //
  53. DWORD WINAPI NotificationThread();
  54. void NotifyEvents( BOOL bMachine );
  55. //*************************************************************
  56. //
  57. // InitNotifSupport, ShutdownNotifSupport
  58. //
  59. // Purpose: Initialization and cleanup routines
  60. //
  61. //*************************************************************
  62. DWORD InitializeNotifySupport()
  63. {
  64. __try
  65. {
  66. InitializeCriticalSection( &g_NotifyCS );
  67. return ERROR_SUCCESS;
  68. }
  69. __except( EXCEPTION_EXECUTE_HANDLER )
  70. {
  71. return ERROR_OUTOFMEMORY;
  72. }
  73. }
  74. void ShutdownNotifySupport()
  75. {
  76. BOOL fWait = FALSE;
  77. DWORD dwResult;
  78. {
  79. EnterCriticalSection( &g_NotifyCS );
  80. if ( g_Notif.hThread != NULL )
  81. {
  82. //
  83. // Set up terminate workitem and then signal thread
  84. //
  85. fWait = TRUE;
  86. g_Notif.eWorkType = eTerminate;
  87. if (!SetEvent( g_Notif.hThreadEvent )) {
  88. // dll is going away. this is the best that we can do.
  89. DebugMsg((DM_WARNING, TEXT("ShutdownNotifySupport: SetEvent failed with %d. abandoning thread"),
  90. GetLastError()));
  91. fWait = FALSE;
  92. }
  93. }
  94. LeaveCriticalSection( &g_NotifyCS );
  95. }
  96. if ( fWait )
  97. WaitForSingleObject( g_Notif.hThread, INFINITE );
  98. {
  99. EnterCriticalSection( &g_NotifyCS );
  100. //
  101. // Close all opened handles
  102. //
  103. if ( g_Notif.hThread != NULL )
  104. CloseHandle( g_Notif.hThread );
  105. if ( g_Notif.hThreadEvent != NULL )
  106. CloseHandle( g_Notif.hThreadEvent );
  107. if ( g_Notif.hUserEvent != NULL )
  108. CloseHandle( g_Notif.hUserEvent );
  109. if ( g_Notif.hMachEvent != NULL )
  110. CloseHandle( g_Notif.hMachEvent );
  111. LeaveCriticalSection( &g_NotifyCS );
  112. }
  113. DeleteCriticalSection( &g_NotifyCS );
  114. }
  115. //*************************************************************
  116. //
  117. // RegisterGPNotification
  118. //
  119. // Purpose: Registers for a group policy change notification
  120. //
  121. // Parameters: hEvent - Event to be notified
  122. // bMachine - If true, then register for
  123. // machine policy notification, else
  124. // user policy notification
  125. //
  126. // Returns: True if successful
  127. // False if error occurs
  128. //
  129. //*************************************************************
  130. BOOL WINAPI RegisterGPNotification( IN HANDLE hEvent, IN BOOL bMachine )
  131. {
  132. BOOL bResult = FALSE;
  133. BOOL bNotifyThread = FALSE;
  134. GPNOTIFINFO *pNotifInfo = NULL;
  135. //
  136. // Validate input as much as possible
  137. //
  138. if ( NULL == hEvent )
  139. {
  140. return ERROR_INVALID_PARAMETER;
  141. }
  142. EnterCriticalSection( &g_NotifyCS );
  143. //
  144. // Create events and thread as needed
  145. //
  146. if ( g_Notif.hThreadEvent == NULL )
  147. {
  148. g_Notif.hThreadEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  149. if ( g_Notif.hThreadEvent == NULL )
  150. goto Exit;
  151. }
  152. if ( g_Notif.hMachEvent == NULL )
  153. {
  154. g_Notif.hMachEvent = OpenEvent (SYNCHRONIZE, FALSE, MACHINE_POLICY_APPLIED_EVENT);
  155. if ( g_Notif.hMachEvent == NULL ) {
  156. DebugMsg((DM_WARNING, TEXT("RegisterGPNotification: CreateEvent failed with %d"),
  157. GetLastError()));
  158. goto Exit;
  159. }
  160. bNotifyThread = TRUE;
  161. }
  162. if ( !bMachine && g_Notif.hUserEvent == NULL )
  163. {
  164. g_Notif.hUserEvent = OpenEvent (SYNCHRONIZE, FALSE, USER_POLICY_APPLIED_EVENT);
  165. if ( g_Notif.hUserEvent == NULL ) {
  166. DebugMsg((DM_WARNING, TEXT("RegisterGPNotification: CreateEvent failed with %d"),
  167. GetLastError()));
  168. goto Exit;
  169. }
  170. bNotifyThread = TRUE;
  171. }
  172. if ( g_Notif.hThread == NULL )
  173. {
  174. // RAID 717164: Previously, the created thread would call LoadLibrary( "userenv.dll" ) once it
  175. // spins up, thereby permanently locking the dll from unloading because the thread would never
  176. // go away (except when DllMain(DLL_PROCESS_DETACH) is called, which will not happen as the
  177. // thread has a refcount to the library - catch 22).
  178. // With this bug, there is a possibility that DllMain(DLL_PROCESS_DETACH) can get called before
  179. // the created thread reaches our routine. In this case, the created thread would wait on the
  180. // loader lock critical section, but we know that NT locks the loader lock before calling
  181. // DllMain. Therefor, in ShutdownNotifySupport called from DllMain(DLL_PROCESS_DETACH), this
  182. // thread is waiting for the created thread to stop, but the created thread is locked waiting
  183. // for the critical section held by the thread waiting for it - DEADLOCK!
  184. // So, the solution with the smallest impact to stability is simply to keep the status quo
  185. // mentioned above (the catch 22), but ensure that it also happens in the deadlock case above,
  186. // thereby avoiding the deadlock and fixing the bug.
  187. // How do we do that? By permanently pinning the Dll from ever dynamically unloading BEFORE we
  188. // spin up this thread.
  189. GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_PIN, TEXT("userenv.dll"), &(g_Notif.hModule) );
  190. DWORD dwThreadId;
  191. g_Notif.hThread = CreateThread( NULL,
  192. 0,
  193. (LPTHREAD_START_ROUTINE) NotificationThread,
  194. 0,
  195. 0,
  196. &dwThreadId );
  197. if ( g_Notif.hThread == NULL ) {
  198. DebugMsg((DM_WARNING, TEXT("RegisterGPNotification: CreateThread failed with %d"),
  199. GetLastError()));
  200. goto Exit;
  201. }
  202. bNotifyThread = TRUE;
  203. }
  204. if ( bNotifyThread )
  205. {
  206. //
  207. // Notify thread that there is a new workitem, possibly
  208. // user event has been added.
  209. //
  210. g_Notif.eWorkType = eMonitor;
  211. if (!SetEvent( g_Notif.hThreadEvent )) {
  212. DebugMsg((DM_WARNING, TEXT("RegisterGPNotification: SetEvent failed with %d"),
  213. GetLastError()));
  214. goto Exit;
  215. }
  216. }
  217. //
  218. // Add event to beginning of list
  219. //
  220. pNotifInfo = (GPNOTIFINFO *) LocalAlloc( LPTR, sizeof(GPNOTIFINFO) );
  221. if ( pNotifInfo == NULL ) {
  222. DebugMsg((DM_WARNING, TEXT("RegisterGPNotification: LocalAlloc failed with %d"),
  223. GetLastError()));
  224. goto Exit;
  225. }
  226. pNotifInfo->hEvent = hEvent;
  227. pNotifInfo->bMachine = bMachine;
  228. pNotifInfo->pNext = g_Notif.pNotifList;
  229. g_Notif.pNotifList = pNotifInfo;
  230. bResult = TRUE;
  231. Exit:
  232. LeaveCriticalSection( &g_NotifyCS );
  233. return bResult;
  234. }
  235. //*************************************************************
  236. //
  237. // UnregisterGPNotification
  238. //
  239. // Purpose: Removes registration for a group policy change notification
  240. //
  241. // Parameters: hEvent - Event to be removed
  242. //
  243. // Return: True if successful
  244. // False if error occurs
  245. //
  246. //*************************************************************
  247. BOOL WINAPI UnregisterGPNotification( IN HANDLE hEvent )
  248. {
  249. BOOL bFound = FALSE;
  250. GPNOTIFINFO *pTrailPtr = NULL;
  251. GPNOTIFINFO *pCurPtr = NULL;
  252. EnterCriticalSection( &g_NotifyCS );
  253. pCurPtr = g_Notif.pNotifList;
  254. while ( pCurPtr != NULL )
  255. {
  256. if ( pCurPtr->hEvent == hEvent )
  257. {
  258. //
  259. // Found match, so delete entry
  260. //
  261. if ( pTrailPtr == NULL )
  262. {
  263. //
  264. // First elem of list matched
  265. //
  266. g_Notif.pNotifList = pCurPtr->pNext;
  267. }
  268. else
  269. pTrailPtr->pNext = pCurPtr->pNext;
  270. LocalFree( pCurPtr );
  271. bFound = TRUE;
  272. break;
  273. }
  274. //
  275. // Advance down the list
  276. //
  277. pTrailPtr = pCurPtr;
  278. pCurPtr = pCurPtr->pNext;
  279. }
  280. LeaveCriticalSection( &g_NotifyCS );
  281. return bFound;
  282. }
  283. //*************************************************************
  284. //
  285. // CGPNotification::NotificationThread
  286. //
  287. // Purpose: Separate thread for notifications
  288. //
  289. // Returns: 0
  290. //
  291. //*************************************************************
  292. DWORD WINAPI NotificationThread()
  293. {
  294. DWORD cEvents = 2;
  295. BOOL fShutdown = FALSE;
  296. HINSTANCE hInst = LoadLibrary (TEXT("userenv.dll"));
  297. {
  298. EnterCriticalSection( &g_NotifyCS );
  299. //
  300. // The event fields in g_Notif are ordered as hThreadEvent,
  301. // hMachEvent and finally hUserEvent. The first two events have
  302. // to be successfully created in order for this thread to run
  303. // (see asserts). If the user event has been successfully created
  304. // then that too is monitored.
  305. //
  306. DmAssert( g_Notif.hThreadEvent != NULL && g_Notif.hMachEvent != NULL );
  307. if ( g_Notif.hUserEvent != NULL )
  308. cEvents = 3;
  309. LeaveCriticalSection( &g_NotifyCS );
  310. }
  311. while ( !fShutdown )
  312. {
  313. DWORD dwResult = WaitForMultipleObjects( cEvents,
  314. &g_Notif.hThreadEvent,
  315. FALSE,
  316. INFINITE );
  317. EnterCriticalSection( &g_NotifyCS );
  318. if ( dwResult == WAIT_FAILED )
  319. {
  320. DebugMsg((DM_WARNING, TEXT("GPNotification: WaitforMultipleObjects failed")));
  321. fShutdown = TRUE;
  322. }
  323. else if ( dwResult == WAIT_OBJECT_0 )
  324. {
  325. if (!ResetEvent( g_Notif.hThreadEvent )) {
  326. DebugMsg((DM_WARNING, TEXT("GPNotification: ResetEvent failed with error %d"), GetLastError()));
  327. fShutdown = TRUE;
  328. }
  329. else
  330. {
  331. if ( g_Notif.eWorkType == eMonitor )
  332. {
  333. //
  334. // Start monitoring user events too
  335. //
  336. if ( g_Notif.hUserEvent != NULL )
  337. cEvents = 3;
  338. }
  339. else {
  340. fShutdown = TRUE;
  341. }
  342. }
  343. }
  344. else if ( dwResult == WAIT_OBJECT_0 + 1 || dwResult == WAIT_OBJECT_0 + 2 )
  345. {
  346. BOOL bMachine = (dwResult == WAIT_OBJECT_0 + 1);
  347. NotifyEvents( bMachine );
  348. if ( g_Notif.pNotifList == NULL )
  349. fShutdown = TRUE;
  350. }
  351. else
  352. {
  353. if ( dwResult == WAIT_ABANDONED_0 || dwResult == WAIT_ABANDONED_0 + 1 )
  354. fShutdown = TRUE;
  355. else
  356. {
  357. CloseHandle( g_Notif.hUserEvent );
  358. g_Notif.hUserEvent = NULL;
  359. cEvents = 2;
  360. }
  361. }
  362. if ( fShutdown )
  363. {
  364. //
  365. // Close all handles and thread
  366. //
  367. CloseHandle( g_Notif.hThreadEvent );
  368. g_Notif.hThreadEvent = NULL;
  369. if ( g_Notif.hMachEvent != NULL )
  370. {
  371. CloseHandle( g_Notif.hMachEvent );
  372. g_Notif.hMachEvent = NULL;
  373. }
  374. if ( g_Notif.hUserEvent != NULL )
  375. {
  376. CloseHandle( g_Notif.hUserEvent );
  377. g_Notif.hUserEvent = NULL;
  378. }
  379. CloseHandle( g_Notif.hThread );
  380. g_Notif.hThread = NULL;
  381. }
  382. LeaveCriticalSection( &g_NotifyCS );
  383. }
  384. if ( hInst != NULL )
  385. FreeLibraryAndExitThread (hInst, 0);
  386. return 0;
  387. }
  388. //*************************************************************
  389. //
  390. // NotifyEvents
  391. //
  392. // Purpose: Notifies registered events
  393. //
  394. // Parameters: bMachine - Is this a machine policy change ?
  395. //
  396. //*************************************************************
  397. void NotifyEvents( BOOL bMachine )
  398. {
  399. GPNOTIFINFO *pNotifInfo = NULL;
  400. pNotifInfo = g_Notif.pNotifList;
  401. while ( pNotifInfo != NULL )
  402. {
  403. if ( pNotifInfo->bMachine == bMachine )
  404. {
  405. (void)SetEvent( pNotifInfo->hEvent );
  406. // multiple events are registered. move to the next event in case of errors.
  407. }
  408. pNotifInfo = pNotifInfo->pNext;
  409. }
  410. }