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