6376c0c705fea7770535aa2ca83f89cab2ad5b31
[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 szLocalGPDoneEvent[] = L"userenv: User Policy Foreground Done Event";
51 static const WCHAR szMachineGPApplied[] = L"Global\\userenv: Machine Group Policy has been applied";
52 static const WCHAR szMachineGPMutex[] = L"Global\\userenv: machine policy mutex";
53 static const WCHAR szMachineGPRefreshEvent[] = L"Global\\userenv: machine policy refresh event";
54 static const WCHAR szMachineGPForceRefreshEvent[] = L"Global\\userenv: machine policy force refresh event";
55 static const WCHAR szMachineGPDoneEvent[] = L"Global\\userenv: Machine Policy Foreground Done Event";
56
57 static CRITICAL_SECTION GPNotifyLock;
58 static PGP_NOTIFY NotificationList = NULL;
59 static GP_ACTION GPNotificationAction = gpaUpdate;
60 static HANDLE hNotificationThread = NULL;
61 static HANDLE hNotificationThreadEvent = NULL;
62 static HANDLE hLocalGPAppliedEvent = NULL;
63 static HANDLE hMachineGPAppliedEvent = NULL;
64
65 VOID
66 InitializeGPNotifications(VOID)
67 {
68 InitializeCriticalSection(&GPNotifyLock);
69 }
70
71 VOID
72 UninitializeGPNotifications(VOID)
73 {
74 EnterCriticalSection(&GPNotifyLock);
75
76 /* rundown the notification thread */
77 if (hNotificationThread != NULL)
78 {
79 ASSERT(hNotificationThreadEvent != NULL);
80
81 /* notify the thread */
82 GPNotificationAction = gpaTerminate;
83 SetEvent(hNotificationThreadEvent);
84
85 LeaveCriticalSection(&GPNotifyLock);
86
87 /* wait for the thread to terminate itself */
88 WaitForSingleObject(hNotificationThread,
89 INFINITE);
90
91 EnterCriticalSection(&GPNotifyLock);
92
93 if (hNotificationThread != NULL)
94 {
95 /* the handle should be closed by the thread,
96 just in case that didn't happen for an unknown reason */
97 CloseHandle(hNotificationThread);
98 hNotificationThread = NULL;
99 }
100 }
101
102 if (hNotificationThreadEvent != NULL)
103 {
104 CloseHandle(hNotificationThreadEvent);
105 hNotificationThreadEvent = NULL;
106 }
107
108 LeaveCriticalSection(&GPNotifyLock);
109
110 DeleteCriticalSection(&GPNotifyLock);
111 }
112
113 static VOID
114 NotifyGPEvents(IN BOOL bMachine)
115 {
116 PGP_NOTIFY Notify = NotificationList;
117
118 while (Notify != NULL)
119 {
120 if (Notify->bMachine == bMachine)
121 {
122 SetEvent(Notify->hEvent);
123 }
124
125 Notify = Notify->Next;
126 }
127 }
128
129 static DWORD WINAPI
130 GPNotificationThreadProc(IN LPVOID lpParameter)
131 {
132 HMODULE hModule;
133 DWORD WaitResult, WaitCount;
134 HANDLE WaitHandles[3];
135
136 /* reference the library so we don't screw up if the application
137 causes the DLL to unload while this thread is still running */
138 if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
139 (LPCWSTR)hInstance,
140 &hModule))
141 {
142 ASSERT(hModule == hInstance);
143
144 EnterCriticalSection(&GPNotifyLock);
145
146 ASSERT(hNotificationThreadEvent != NULL);
147 WaitHandles[0] = hNotificationThreadEvent;
148 for (;;)
149 {
150 ASSERT(hMachineGPAppliedEvent != NULL);
151
152 if (NotificationList == NULL)
153 break;
154
155 WaitCount = 2;
156 WaitHandles[1] = hMachineGPAppliedEvent;
157
158 if (hLocalGPAppliedEvent != NULL)
159 {
160 WaitHandles[2] = hLocalGPAppliedEvent;
161 WaitCount++;
162 }
163
164 LeaveCriticalSection(&GPNotifyLock);
165
166 WaitResult = WaitForMultipleObjects(WaitCount,
167 WaitHandles,
168 FALSE,
169 INFINITE);
170
171 EnterCriticalSection(&GPNotifyLock);
172
173 if (WaitResult != WAIT_FAILED)
174 {
175 if (WaitResult == WAIT_OBJECT_0)
176 {
177 ResetEvent(hNotificationThreadEvent);
178
179 if (GPNotificationAction == gpaTerminate)
180 {
181 /* terminate the thread */
182 break;
183 }
184 }
185 else if (WaitResult == WAIT_OBJECT_0 + 1 || WaitResult == WAIT_OBJECT_0 + 2)
186 {
187 /* group policies have been applied */
188 if (NotificationList != NULL)
189 {
190 NotifyGPEvents((WaitResult == WAIT_OBJECT_0 + 1));
191 }
192 }
193 else if (WaitResult == WAIT_ABANDONED_0 + 2)
194 {
195 /* In case the local group policies event was abandoned, keep watching!
196 But close the handle as it's no longer of any use. */
197 if (hLocalGPAppliedEvent != NULL)
198 {
199 CloseHandle(hLocalGPAppliedEvent);
200 hLocalGPAppliedEvent = NULL;
201 }
202 }
203 else if (WaitResult == WAIT_ABANDONED_0 || WaitResult == WAIT_ABANDONED_0 + 1)
204 {
205 /* terminate the thread if the machine group policies event was abandoned
206 or for some reason the rundown event got abandoned. */
207 break;
208 }
209 else
210 {
211 DPRINT("Unexpected wait result watching the group policy events: 0x%x\n", WaitResult);
212 ASSERT(FALSE);
213 break;
214 }
215
216 if (NotificationList == NULL)
217 break;
218 }
219 else
220 break;
221
222 }
223
224 /* cleanup handles no longer used */
225 ASSERT(hNotificationThread != NULL);
226 ASSERT(hNotificationThreadEvent != NULL);
227
228 CloseHandle(hNotificationThread);
229 CloseHandle(hNotificationThreadEvent);
230 hNotificationThread = NULL;
231 hNotificationThreadEvent = NULL;
232
233 if (hLocalGPAppliedEvent != NULL)
234 {
235 CloseHandle(hLocalGPAppliedEvent);
236 hLocalGPAppliedEvent = NULL;
237 }
238 if (hMachineGPAppliedEvent != NULL)
239 {
240 CloseHandle(hMachineGPAppliedEvent);
241 hMachineGPAppliedEvent = NULL;
242 }
243
244 LeaveCriticalSection(&GPNotifyLock);
245
246 /* dereference the library and exit */
247 FreeLibraryAndExitThread(hModule,
248 0);
249 }
250 else
251 {
252 DPRINT1("Referencing the library failed!\n");
253 }
254
255 return 1;
256 }
257
258 static HANDLE
259 CreateGPEvent(IN BOOL bMachine,
260 IN PSECURITY_DESCRIPTOR lpSecurityDescriptor)
261 {
262 HANDLE hEvent;
263 SECURITY_ATTRIBUTES SecurityAttributes;
264
265 SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
266 SecurityAttributes.lpSecurityDescriptor = lpSecurityDescriptor;
267 SecurityAttributes.bInheritHandle = FALSE;
268
269 hEvent = CreateEventW(&SecurityAttributes,
270 TRUE,
271 FALSE,
272 (bMachine ? szMachineGPApplied : szLocalGPApplied));
273
274 return hEvent;
275 }
276
277 BOOL WINAPI
278 RegisterGPNotification(IN HANDLE hEvent,
279 IN BOOL bMachine)
280 {
281 PGP_NOTIFY Notify;
282 PSECURITY_DESCRIPTOR lpSecurityDescriptor = NULL;
283 BOOL Ret = FALSE;
284
285 EnterCriticalSection(&GPNotifyLock);
286
287 /* create the thread notification event */
288 if (hNotificationThreadEvent == NULL)
289 {
290 hNotificationThreadEvent = CreateEvent(NULL,
291 TRUE,
292 FALSE,
293 NULL);
294 if (hNotificationThreadEvent == NULL)
295 {
296 goto Cleanup;
297 }
298 }
299
300 /* create or open the machine group policy event */
301 if (hMachineGPAppliedEvent == NULL)
302 {
303 lpSecurityDescriptor = CreateDefaultSecurityDescriptor();
304 if (lpSecurityDescriptor == NULL)
305 {
306 goto Cleanup;
307 }
308
309 hMachineGPAppliedEvent = CreateGPEvent(TRUE,
310 lpSecurityDescriptor);
311 if (hMachineGPAppliedEvent == NULL)
312 {
313 goto Cleanup;
314 }
315 }
316
317 /* create or open the local group policy event only if necessary */
318 if (!bMachine && hLocalGPAppliedEvent == NULL)
319 {
320 if (lpSecurityDescriptor == NULL)
321 {
322 lpSecurityDescriptor = CreateDefaultSecurityDescriptor();
323 if (lpSecurityDescriptor == NULL)
324 {
325 goto Cleanup;
326 }
327 }
328
329 hLocalGPAppliedEvent = CreateGPEvent(FALSE,
330 lpSecurityDescriptor);
331 if (hLocalGPAppliedEvent == NULL)
332 {
333 goto Cleanup;
334 }
335 }
336
337 if (hNotificationThread == NULL)
338 {
339 hNotificationThread = CreateThread(NULL,
340 0,
341 GPNotificationThreadProc,
342 NULL,
343 0,
344 NULL);
345 }
346
347 if (hNotificationThread != NULL)
348 {
349 Notify = (PGP_NOTIFY)LocalAlloc(LMEM_FIXED,
350 sizeof(GP_NOTIFY));
351 if (Notify != NULL)
352 {
353 /* add the item to the beginning of the list */
354 Notify->Next = NotificationList;
355 Notify->hEvent = hEvent;
356 Notify->bMachine = bMachine;
357
358 NotificationList = Notify;
359
360 /* notify the thread */
361 GPNotificationAction = gpaUpdate;
362 SetEvent(hNotificationThreadEvent);
363
364 Ret = TRUE;
365 }
366 }
367
368 Cleanup:
369 LeaveCriticalSection(&GPNotifyLock);
370
371 if (lpSecurityDescriptor != NULL)
372 {
373 LocalFree((HLOCAL)lpSecurityDescriptor);
374 }
375
376 /* NOTE: don't delete the events or close the handles created */
377
378 return Ret;
379 }
380
381 BOOL WINAPI
382 UnregisterGPNotification(IN HANDLE hEvent)
383 {
384 PGP_NOTIFY Notify = NULL, *NotifyLink;
385 BOOL Ret = FALSE;
386
387 EnterCriticalSection(&GPNotifyLock);
388
389 Notify = NotificationList;
390 NotifyLink = &NotificationList;
391
392 while (Notify != NULL)
393 {
394 if (Notify->hEvent == hEvent)
395 {
396 /* remove and free the item */
397 *NotifyLink = Notify->Next;
398 LocalFree((HLOCAL)Notify);
399
400 /* notify the thread */
401 if (hNotificationThread != NULL &&
402 hNotificationThreadEvent != NULL)
403 {
404 GPNotificationAction = gpaUpdate;
405 SetEvent(hNotificationThreadEvent);
406 }
407
408 Ret = TRUE;
409 break;
410 }
411
412 NotifyLink = &Notify->Next;
413 Notify = Notify->Next;
414 }
415
416 LeaveCriticalSection(&GPNotifyLock);
417
418 return Ret;
419 }
420
421 BOOL WINAPI
422 RefreshPolicy(IN BOOL bMachine)
423 {
424 HANDLE hEvent;
425 BOOL Ret = TRUE;
426
427 hEvent = OpenEventW(EVENT_MODIFY_STATE,
428 FALSE,
429 (bMachine ? szMachineGPRefreshEvent : szLocalGPRefreshEvent));
430 if (hEvent != NULL)
431 {
432 Ret = SetEvent(hEvent);
433 CloseHandle(hEvent);
434 }
435
436 /* return TRUE even if the mutex doesn't exist! */
437 return Ret;
438 }
439
440 BOOL WINAPI
441 RefreshPolicyEx(IN BOOL bMachine,
442 IN DWORD dwOptions)
443 {
444 if (dwOptions & ~RP_FORCE)
445 {
446 SetLastError(ERROR_INVALID_PARAMETER);
447 return FALSE;
448 }
449
450 if (dwOptions & RP_FORCE)
451 {
452 HANDLE hEvent;
453 BOOL Ret = TRUE;
454
455 hEvent = OpenEventW(EVENT_MODIFY_STATE,
456 FALSE,
457 (bMachine ? szMachineGPForceRefreshEvent : szLocalGPForceRefreshEvent));
458 if (hEvent != NULL)
459 {
460 Ret = SetEvent(hEvent);
461 CloseHandle(hEvent);
462 }
463
464 /* return TRUE even if the mutex doesn't exist! */
465 return Ret;
466 }
467 else
468 {
469 return RefreshPolicy(bMachine);
470 }
471 }
472
473 HANDLE WINAPI
474 EnterCriticalPolicySection(IN BOOL bMachine)
475 {
476 SECURITY_ATTRIBUTES SecurityAttributes;
477 PSECURITY_DESCRIPTOR lpSecurityDescriptor;
478 HANDLE hSection;
479
480 /* create or open the mutex */
481 lpSecurityDescriptor = CreateDefaultSecurityDescriptor();
482 if (lpSecurityDescriptor != NULL)
483 {
484 SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
485 SecurityAttributes.lpSecurityDescriptor = lpSecurityDescriptor;
486 SecurityAttributes.bInheritHandle = FALSE;
487
488 hSection = CreateMutexW(&SecurityAttributes,
489 FALSE,
490 (bMachine ? szMachineGPMutex : szLocalGPMutex));
491
492 LocalFree((HLOCAL)lpSecurityDescriptor);
493
494 if (hSection != NULL)
495 {
496 /* wait up to 10 seconds */
497 if (WaitForSingleObject(hSection,
498 60000) != WAIT_FAILED)
499 {
500 return hSection;
501 }
502
503 CloseHandle(hSection);
504 }
505 }
506
507 return NULL;
508 }
509
510 BOOL WINAPI
511 LeaveCriticalPolicySection(IN HANDLE hSection)
512 {
513 BOOL Ret;
514
515 if (hSection == NULL)
516 {
517 SetLastError(ERROR_INVALID_PARAMETER);
518 return FALSE;
519 }
520
521 Ret = ReleaseMutex(hSection);
522 CloseHandle(hSection);
523
524 return Ret;
525 }
526
527 BOOL WINAPI
528 WaitForUserPolicyForegroundProcessing(VOID)
529 {
530 HANDLE hEvent;
531 BOOL Ret = FALSE;
532
533 hEvent = OpenEventW(SYNCHRONIZE,
534 FALSE,
535 szLocalGPDoneEvent);
536 if (hEvent != NULL)
537 {
538 Ret = WaitForSingleObject(hEvent,
539 INFINITE) != WAIT_FAILED;
540 CloseHandle(hEvent);
541 }
542
543 /* return TRUE even if the mutex doesn't exist! */
544 return Ret;
545 }
546
547 BOOL WINAPI
548 WaitForMachinePolicyForegroundProcessing(VOID)
549 {
550 HANDLE hEvent;
551 BOOL Ret = FALSE;
552
553 hEvent = OpenEventW(SYNCHRONIZE,
554 FALSE,
555 szMachineGPDoneEvent);
556 if (hEvent != NULL)
557 {
558 Ret = WaitForSingleObject(hEvent,
559 INFINITE) != WAIT_FAILED;
560 CloseHandle(hEvent);
561 }
562
563 /* return TRUE even if the mutex doesn't exist! */
564 return Ret;
565 }