xref: /reactos/dll/win32/userenv/gpolicy.c (revision c2c66aff)
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
InitializeGPNotifications(VOID)65 InitializeGPNotifications(VOID)
66 {
67     InitializeCriticalSection(&GPNotifyLock);
68 }
69 
70 VOID
UninitializeGPNotifications(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
NotifyGPEvents(IN BOOL bMachine)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
GPNotificationThreadProc(IN LPVOID lpParameter)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
CreateGPEvent(IN BOOL bMachine,IN PSECURITY_DESCRIPTOR lpSecurityDescriptor)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
RegisterGPNotification(IN HANDLE hEvent,IN BOOL bMachine)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
UnregisterGPNotification(IN HANDLE hEvent)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
RefreshPolicy(IN BOOL bMachine)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
RefreshPolicyEx(IN BOOL bMachine,IN DWORD dwOptions)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
EnterCriticalPolicySection(IN BOOL bMachine)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
LeaveCriticalPolicySection(IN HANDLE hSection)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
WaitForUserPolicyForegroundProcessing(VOID)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
WaitForMachinePolicyForegroundProcessing(VOID)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
GetAppliedGPOListA(_In_ DWORD dwFlags,_In_ LPCSTR pMachineName,_In_ PSID pSidUser,_In_ GUID * pGuidExtension,_Out_ PGROUP_POLICY_OBJECTA * ppGPOList)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
GetAppliedGPOListW(_In_ DWORD dwFlags,_In_ LPCWSTR pMachineName,_In_ PSID pSidUser,_In_ GUID * pGuidExtension,_Out_ PGROUP_POLICY_OBJECTW * ppGPOList)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 }
603