fixed a memory leak in EnterCriticalPolicySection()
[reactos.git] / reactos / lib / userenv / gpolicy.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2006 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS system libraries
22 * FILE: lib/userenv/gpolicy.c
23 * PURPOSE: Group policy functions
24 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
25 */
26
27 #include <precomp.h>
28
29 #define NDEBUG
30 #include <debug.h>
31
32
33 typedef struct _GP_NOTIFY
34 {
35 struct _GP_NOTIFY *Next;
36 HANDLE hEvent;
37 BOOL bMachine;
38 } GP_NOTIFY, *PGP_NOTIFY;
39
40 typedef enum
41 {
42 gpaUpdate = 0,
43 gpaTerminate
44 } GP_ACTION;
45
46 static const WCHAR szLocalGPApplied[] = L"userenv: User Group Policy has been applied";
47 static const WCHAR szLocalGPMutex[] = L"userenv: user policy mutex";
48 static const WCHAR szLocalGPRefreshEvent[] = L"userenv: user policy refresh event";
49 static const WCHAR szLocalGPForceRefreshEvent[] = L"userenv: user policy force refresh event";
50 static const WCHAR szMachineGPApplied[] = L"Global\\userenv: Machine Group Policy has been applied";
51 static const WCHAR szMachineGPMutex[] = L"Global\\userenv: machine policy mutex";
52 static const WCHAR szMachineGPRefreshEvent[] = L"Global\\userenv: machine policy refresh event";
53 static const WCHAR szMachineGPForceRefreshEvent[] = L"Global\\userenv: machine policy force refresh event";
54
55 static CRITICAL_SECTION GPNotifyLock;
56 static PGP_NOTIFY NotificationList = NULL;
57 static GP_ACTION GPNotificationAction = gpaUpdate;
58 static HANDLE hNotificationThread = NULL;
59 static HANDLE hNotificationThreadEvent = NULL;
60 static HANDLE hLocalGPAppliedEvent = NULL;
61 static HANDLE hMachineGPAppliedEvent = NULL;
62
63 VOID
64 InitializeGPNotifications(VOID)
65 {
66 InitializeCriticalSection(&GPNotifyLock);
67 }
68
69 VOID
70 UninitializeGPNotifications(VOID)
71 {
72 EnterCriticalSection(&GPNotifyLock);
73
74 /* rundown the notification thread */
75 if (hNotificationThread != NULL)
76 {
77 ASSERT(hNotificationThreadEvent != NULL);
78
79 /* notify the thread */
80 GPNotificationAction = gpaTerminate;
81 SetEvent(hNotificationThreadEvent);
82
83 LeaveCriticalSection(&GPNotifyLock);
84
85 /* wait for the thread to terminate itself */
86 WaitForSingleObject(hNotificationThread,
87 INFINITE);
88
89 EnterCriticalSection(&GPNotifyLock);
90
91 if (hNotificationThread != NULL)
92 {
93 /* the handle should be closed by the thread,
94 just in case that didn't happen for an unknown reason */
95 CloseHandle(hNotificationThread);
96 hNotificationThread = NULL;
97 }
98 }
99
100 if (hNotificationThreadEvent != NULL)
101 {
102 CloseHandle(hNotificationThreadEvent);
103 hNotificationThreadEvent = NULL;
104 }
105
106 LeaveCriticalSection(&GPNotifyLock);
107
108 DeleteCriticalSection(&GPNotifyLock);
109 }
110
111 static VOID
112 NotifyGPEvents(IN BOOL bMachine)
113 {
114 PGP_NOTIFY Notify = NotificationList;
115
116 while (Notify != NULL)
117 {
118 if (Notify->bMachine == bMachine)
119 {
120 SetEvent(Notify->hEvent);
121 }
122
123 Notify = Notify->Next;
124 }
125 }
126
127 static DWORD WINAPI
128 GPNotificationThreadProc(IN LPVOID lpParameter)
129 {
130 HMODULE hModule;
131 DWORD WaitResult, WaitCount;
132 HANDLE WaitHandles[3];
133
134 /* reference the library so we don't screw up if the application
135 causes the DLL to unload while this thread is still running */
136 if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
137 (LPCWSTR)hInstance,
138 &hModule))
139 {
140 ASSERT(hModule == hInstance);
141
142 EnterCriticalSection(&GPNotifyLock);
143
144 ASSERT(hNotificationThreadEvent != NULL);
145 WaitHandles[0] = hNotificationThreadEvent;
146 for (;;)
147 {
148 ASSERT(hMachineGPAppliedEvent != NULL);
149
150 if (NotificationList == NULL)
151 break;
152
153 WaitCount = 2;
154 WaitHandles[1] = hMachineGPAppliedEvent;
155
156 if (hLocalGPAppliedEvent != NULL)
157 {
158 WaitHandles[2] = hLocalGPAppliedEvent;
159 WaitCount++;
160 }
161
162 LeaveCriticalSection(&GPNotifyLock);
163
164 WaitResult = WaitForMultipleObjects(WaitCount,
165 WaitHandles,
166 FALSE,
167 INFINITE);
168
169 EnterCriticalSection(&GPNotifyLock);
170
171 if (WaitResult != WAIT_FAILED)
172 {
173 if (WaitResult == WAIT_OBJECT_0)
174 {
175 ResetEvent(hNotificationThreadEvent);
176
177 if (GPNotificationAction == gpaTerminate)
178 {
179 /* terminate the thread */
180 break;
181 }
182 }
183 else if (WaitResult == WAIT_OBJECT_0 + 1 || WaitResult == WAIT_OBJECT_0 + 2)
184 {
185 /* group policies have been applied */
186 if (NotificationList != NULL)
187 {
188 NotifyGPEvents((WaitResult == WAIT_OBJECT_0 + 1));
189 }
190 }
191 else if (WaitResult == WAIT_ABANDONED_0 + 2)
192 {
193 /* In case the local group policies event was abandoned, keep watching!
194 But close the handle as it's no longer of any use. */
195 if (hLocalGPAppliedEvent != NULL)
196 {
197 CloseHandle(hLocalGPAppliedEvent);
198 hLocalGPAppliedEvent = NULL;
199 }
200 }
201 else if (WaitResult == WAIT_ABANDONED_0 || WaitResult == WAIT_ABANDONED_0 + 1)
202 {
203 /* terminate the thread if the machine group policies event was abandoned
204 or for some reason the rundown event got abandoned. */
205 break;
206 }
207 else
208 {
209 DPRINT("Unexpected wait result watching the group policy events: 0x%x\n", WaitResult);
210 ASSERT(FALSE);
211 break;
212 }
213
214 if (NotificationList == NULL)
215 break;
216 }
217 else
218 break;
219
220 }
221
222 /* cleanup handles no longer used */
223 ASSERT(hNotificationThread != NULL);
224 ASSERT(hNotificationThreadEvent != NULL);
225
226 CloseHandle(hNotificationThread);
227 CloseHandle(hNotificationThreadEvent);
228 hNotificationThread = NULL;
229 hNotificationThreadEvent = NULL;
230
231 if (hLocalGPAppliedEvent != NULL)
232 {
233 CloseHandle(hLocalGPAppliedEvent);
234 hLocalGPAppliedEvent = NULL;
235 }
236 if (hMachineGPAppliedEvent != NULL)
237 {
238 CloseHandle(hMachineGPAppliedEvent);
239 hMachineGPAppliedEvent = NULL;
240 }
241
242 LeaveCriticalSection(&GPNotifyLock);
243
244 /* dereference the library and exit */
245 FreeLibraryAndExitThread(hModule,
246 0);
247 }
248 else
249 {
250 DPRINT1("Referencing the library failed!\n");
251 }
252
253 return 1;
254 }
255
256 static HANDLE
257 CreateGPEvent(IN BOOL bMachine,
258 IN PSECURITY_DESCRIPTOR lpSecurityDescriptor)
259 {
260 HANDLE hEvent;
261 SECURITY_ATTRIBUTES SecurityAttributes;
262
263 SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
264 SecurityAttributes.lpSecurityDescriptor = lpSecurityDescriptor;
265 SecurityAttributes.bInheritHandle = FALSE;
266
267 hEvent = CreateEventW(&SecurityAttributes,
268 TRUE,
269 FALSE,
270 (bMachine ? szMachineGPApplied : szLocalGPApplied));
271
272 return hEvent;
273 }
274
275 BOOL WINAPI
276 RegisterGPNotification(IN HANDLE hEvent,
277 IN BOOL bMachine)
278 {
279 PGP_NOTIFY Notify;
280 PSECURITY_DESCRIPTOR lpSecurityDescriptor = NULL;
281 BOOL Ret = FALSE;
282
283 EnterCriticalSection(&GPNotifyLock);
284
285 /* create the thread notification event */
286 if (hNotificationThreadEvent == NULL)
287 {
288 hNotificationThreadEvent = CreateEvent(NULL,
289 TRUE,
290 FALSE,
291 NULL);
292 if (hNotificationThreadEvent == NULL)
293 {
294 goto Cleanup;
295 }
296 }
297
298 /* create or open the machine group policy event */
299 if (hMachineGPAppliedEvent == NULL)
300 {
301 lpSecurityDescriptor = CreateDefaultSecurityDescriptor();
302 if (lpSecurityDescriptor == NULL)
303 {
304 goto Cleanup;
305 }
306
307 hMachineGPAppliedEvent = CreateGPEvent(TRUE,
308 lpSecurityDescriptor);
309 if (hMachineGPAppliedEvent == NULL)
310 {
311 goto Cleanup;
312 }
313 }
314
315 /* create or open the local group policy event only if necessary */
316 if (!bMachine && hLocalGPAppliedEvent == NULL)
317 {
318 if (lpSecurityDescriptor == NULL)
319 {
320 lpSecurityDescriptor = CreateDefaultSecurityDescriptor();
321 if (lpSecurityDescriptor == NULL)
322 {
323 goto Cleanup;
324 }
325 }
326
327 hLocalGPAppliedEvent = CreateGPEvent(FALSE,
328 lpSecurityDescriptor);
329 if (hLocalGPAppliedEvent == NULL)
330 {
331 goto Cleanup;
332 }
333 }
334
335 if (hNotificationThread == NULL)
336 {
337 hNotificationThread = CreateThread(NULL,
338 0,
339 GPNotificationThreadProc,
340 NULL,
341 0,
342 NULL);
343 }
344
345 if (hNotificationThread != NULL)
346 {
347 Notify = (PGP_NOTIFY)LocalAlloc(LMEM_FIXED,
348 sizeof(GP_NOTIFY));
349 if (Notify != NULL)
350 {
351 /* add the item to the beginning of the list */
352 Notify->Next = NotificationList;
353 Notify->hEvent = hEvent;
354 Notify->bMachine = bMachine;
355
356 NotificationList = Notify;
357
358 /* notify the thread */
359 GPNotificationAction = gpaUpdate;
360 SetEvent(hNotificationThreadEvent);
361
362 Ret = TRUE;
363 }
364 }
365
366 Cleanup:
367 LeaveCriticalSection(&GPNotifyLock);
368
369 if (lpSecurityDescriptor != NULL)
370 {
371 LocalFree((HLOCAL)lpSecurityDescriptor);
372 }
373
374 /* NOTE: don't delete the events or close the handles created */
375
376 return Ret;
377 }
378
379 BOOL WINAPI
380 UnregisterGPNotification(IN HANDLE hEvent)
381 {
382 PGP_NOTIFY Notify = NULL, *NotifyLink;
383 BOOL Ret = FALSE;
384
385 EnterCriticalSection(&GPNotifyLock);
386
387 Notify = NotificationList;
388 NotifyLink = &NotificationList;
389
390 while (Notify != NULL)
391 {
392 if (Notify->hEvent == hEvent)
393 {
394 /* remove and free the item */
395 *NotifyLink = Notify->Next;
396 LocalFree((HLOCAL)Notify);
397
398 /* notify the thread */
399 if (hNotificationThread != NULL &&
400 hNotificationThreadEvent != NULL)
401 {
402 GPNotificationAction = gpaUpdate;
403 SetEvent(hNotificationThreadEvent);
404 }
405
406 Ret = TRUE;
407 break;
408 }
409
410 NotifyLink = &Notify->Next;
411 Notify = Notify->Next;
412 }
413
414 LeaveCriticalSection(&GPNotifyLock);
415
416 return Ret;
417 }
418
419 BOOL WINAPI
420 RefreshPolicy(IN BOOL bMachine)
421 {
422 HANDLE hEvent;
423 BOOL Ret = TRUE;
424
425 hEvent = OpenEventW(EVENT_MODIFY_STATE,
426 FALSE,
427 (bMachine ? szMachineGPRefreshEvent : szLocalGPRefreshEvent));
428 if (hEvent != NULL)
429 {
430 Ret = SetEvent(hEvent);
431 CloseHandle(hEvent);
432 }
433
434 /* return TRUE even if the mutex doesn't exist! */
435 return Ret;
436 }
437
438 BOOL WINAPI
439 RefreshPolicyEx(IN BOOL bMachine,
440 IN DWORD dwOptions)
441 {
442 if (dwOptions & ~RP_FORCE)
443 {
444 SetLastError(ERROR_INVALID_PARAMETER);
445 return FALSE;
446 }
447
448 if (dwOptions & RP_FORCE)
449 {
450 HANDLE hEvent;
451 BOOL Ret = TRUE;
452
453 hEvent = OpenEventW(EVENT_MODIFY_STATE,
454 FALSE,
455 (bMachine ? szMachineGPForceRefreshEvent : szLocalGPForceRefreshEvent));
456 if (hEvent != NULL)
457 {
458 Ret = SetEvent(hEvent);
459 CloseHandle(hEvent);
460 }
461
462 /* return TRUE even if the mutex doesn't exist! */
463 return Ret;
464 }
465 else
466 {
467 return RefreshPolicy(bMachine);
468 }
469 }
470
471 HANDLE WINAPI
472 EnterCriticalPolicySection(IN BOOL bMachine)
473 {
474 SECURITY_ATTRIBUTES SecurityAttributes;
475 PSECURITY_DESCRIPTOR lpSecurityDescriptor;
476 HANDLE hSection;
477
478 /* create or open the mutex */
479 lpSecurityDescriptor = CreateDefaultSecurityDescriptor();
480 if (lpSecurityDescriptor != NULL)
481 {
482 SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
483 SecurityAttributes.lpSecurityDescriptor = lpSecurityDescriptor;
484 SecurityAttributes.bInheritHandle = FALSE;
485
486 hSection = CreateMutexW(&SecurityAttributes,
487 FALSE,
488 (bMachine ? szMachineGPMutex : szLocalGPMutex));
489
490 LocalFree((HLOCAL)lpSecurityDescriptor);
491
492 if (hSection != NULL)
493 {
494 /* wait up to 10 seconds */
495 if (WaitForSingleObject(hSection,
496 60000) != WAIT_FAILED)
497 {
498 return hSection;
499 }
500
501 CloseHandle(hSection);
502 }
503 }
504
505 return NULL;
506 }
507
508 BOOL WINAPI
509 LeaveCriticalPolicySection(IN HANDLE hSection)
510 {
511 BOOL Ret;
512
513 if (hSection == NULL)
514 {
515 SetLastError(ERROR_INVALID_PARAMETER);
516 return FALSE;
517 }
518
519 Ret = ReleaseMutex(hSection);
520 CloseHandle(hSection);
521
522 return Ret;
523 }