a2d31221758efa67a1e1a11631abd22b922756de
[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 szMachineGPApplied[] = L"Global\\userenv: Machine Group Policy has been applied";
48
49 static CRITICAL_SECTION GPNotifyLock;
50 static PGP_NOTIFY NotificationList = NULL;
51 static GP_ACTION GPNotificationAction = gpaUpdate;
52 static HANDLE hNotificationThread = NULL;
53 static HANDLE hNotificationThreadEvent = NULL;
54 static HANDLE hLocalGPAppliedEvent = NULL;
55 static HANDLE hMachineGPAppliedEvent = NULL;
56
57 VOID
58 InitializeGPNotifications(VOID)
59 {
60 InitializeCriticalSection(&GPNotifyLock);
61 }
62
63 VOID
64 UninitializeGPNotifications(VOID)
65 {
66 EnterCriticalSection(&GPNotifyLock);
67
68 /* rundown the notification thread */
69 if (hNotificationThread != NULL)
70 {
71 ASSERT(hNotificationThreadEvent != NULL);
72
73 /* notify the thread */
74 GPNotificationAction = gpaTerminate;
75 SetEvent(hNotificationThreadEvent);
76
77 LeaveCriticalSection(&GPNotifyLock);
78
79 /* wait for the thread to terminate itself */
80 WaitForSingleObject(hNotificationThread,
81 INFINITE);
82
83 EnterCriticalSection(&GPNotifyLock);
84
85 if (hNotificationThread != NULL)
86 {
87 /* the handle should be closed by the thread,
88 just in case that didn't happen for an unknown reason */
89 CloseHandle(hNotificationThread);
90 hNotificationThread = NULL;
91 }
92 }
93
94 if (hNotificationThreadEvent != NULL)
95 {
96 CloseHandle(hNotificationThreadEvent);
97 hNotificationThreadEvent = NULL;
98 }
99
100 LeaveCriticalSection(&GPNotifyLock);
101
102 DeleteCriticalSection(&GPNotifyLock);
103 }
104
105 static VOID
106 NotifyGPEvents(IN BOOL bMachine)
107 {
108 PGP_NOTIFY Notify = NotificationList;
109
110 while (Notify != NULL)
111 {
112 if (Notify->bMachine == bMachine)
113 {
114 SetEvent(Notify->hEvent);
115 }
116
117 Notify = Notify->Next;
118 }
119 }
120
121 static DWORD WINAPI
122 GPNotificationThreadProc(IN LPVOID lpParameter)
123 {
124 HMODULE hModule;
125 DWORD WaitResult, WaitCount;
126 HANDLE WaitHandles[3];
127
128 /* reference the library so we don't screw up if the application
129 causes the DLL to unload while this thread is still running */
130 if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
131 (LPCWSTR)hInstance,
132 &hModule))
133 {
134 ASSERT(hModule == hInstance);
135
136 EnterCriticalSection(&GPNotifyLock);
137
138 ASSERT(hNotificationThreadEvent != NULL);
139 WaitHandles[0] = hNotificationThreadEvent;
140 for (;;)
141 {
142 ASSERT(hMachineGPAppliedEvent != NULL);
143
144 if (NotificationList == NULL)
145 break;
146
147 WaitCount = 2;
148 WaitHandles[1] = hMachineGPAppliedEvent;
149
150 if (hLocalGPAppliedEvent != NULL)
151 {
152 WaitHandles[2] = hLocalGPAppliedEvent;
153 WaitCount++;
154 }
155
156 LeaveCriticalSection(&GPNotifyLock);
157
158 WaitResult = WaitForMultipleObjects(WaitCount,
159 WaitHandles,
160 FALSE,
161 INFINITE);
162
163 EnterCriticalSection(&GPNotifyLock);
164
165 if (WaitResult != WAIT_FAILED)
166 {
167 if (WaitResult == WAIT_OBJECT_0)
168 {
169 ResetEvent(hNotificationThreadEvent);
170
171 if (GPNotificationAction == gpaTerminate)
172 {
173 /* terminate the thread */
174 break;
175 }
176 }
177 else if (WaitResult == WAIT_OBJECT_0 + 1 || WaitResult == WAIT_OBJECT_0 + 2)
178 {
179 /* group policies have been applied */
180 if (NotificationList != NULL)
181 {
182 NotifyGPEvents((WaitResult == WAIT_OBJECT_0 + 1));
183 }
184 }
185 else if (WaitResult == WAIT_ABANDONED_0 + 2)
186 {
187 /* In case the local group policies event was abandoned, keep watching!
188 But close the handle as it's no longer of any use. */
189 if (hLocalGPAppliedEvent != NULL)
190 {
191 CloseHandle(hLocalGPAppliedEvent);
192 hLocalGPAppliedEvent = NULL;
193 }
194 }
195 else if (WaitResult == WAIT_ABANDONED_0 || WaitResult == WAIT_ABANDONED_0 + 1)
196 {
197 /* terminate the thread if the machine group policies event was abandoned
198 or for some reason the rundown event got abandoned. */
199 break;
200 }
201 else
202 {
203 DPRINT("Unexpected wait result watching the group policy events: 0x%x\n", WaitResult);
204 ASSERT(FALSE);
205 break;
206 }
207
208 if (NotificationList == NULL)
209 break;
210 }
211 else
212 break;
213
214 }
215
216 /* cleanup handles no longer used */
217 ASSERT(hNotificationThread != NULL);
218 ASSERT(hNotificationThreadEvent != NULL);
219
220 CloseHandle(hNotificationThread);
221 CloseHandle(hNotificationThreadEvent);
222 hNotificationThread = NULL;
223 hNotificationThreadEvent = NULL;
224
225 if (hLocalGPAppliedEvent != NULL)
226 {
227 CloseHandle(hLocalGPAppliedEvent);
228 hLocalGPAppliedEvent = NULL;
229 }
230 if (hMachineGPAppliedEvent != NULL)
231 {
232 CloseHandle(hMachineGPAppliedEvent);
233 hMachineGPAppliedEvent = NULL;
234 }
235
236 LeaveCriticalSection(&GPNotifyLock);
237
238 /* dereference the library and exit */
239 FreeLibraryAndExitThread(hModule,
240 0);
241 }
242 else
243 {
244 DPRINT1("Referencing the library failed!\n");
245 }
246
247 return 1;
248 }
249
250 static HANDLE
251 CreateGPEvent(IN BOOL bMachine,
252 IN PSECURITY_DESCRIPTOR lpSecurityDescriptor)
253 {
254 HANDLE hEvent;
255 SECURITY_ATTRIBUTES SecurityAttributes;
256
257 SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
258 SecurityAttributes.lpSecurityDescriptor = lpSecurityDescriptor;
259 SecurityAttributes.bInheritHandle = FALSE;
260
261 hEvent = CreateEventW(&SecurityAttributes,
262 TRUE,
263 FALSE,
264 (bMachine ? szMachineGPApplied : szLocalGPApplied));
265
266 return hEvent;
267 }
268
269 BOOL WINAPI
270 RegisterGPNotification(IN HANDLE hEvent,
271 IN BOOL bMachine)
272 {
273 PGP_NOTIFY Notify;
274 PSECURITY_DESCRIPTOR lpSecurityDescriptor = NULL;
275 BOOL Ret = FALSE;
276
277 EnterCriticalSection(&GPNotifyLock);
278
279 /* create the thread notification event */
280 if (hNotificationThreadEvent == NULL)
281 {
282 hNotificationThreadEvent = CreateEvent(NULL,
283 TRUE,
284 FALSE,
285 NULL);
286 if (hNotificationThreadEvent == NULL)
287 {
288 goto Cleanup;
289 }
290 }
291
292 /* create or open the machine group policy event */
293 if (hMachineGPAppliedEvent == NULL)
294 {
295 lpSecurityDescriptor = CreateDefaultSecurityDescriptor();
296 if (lpSecurityDescriptor == NULL)
297 {
298 goto Cleanup;
299 }
300
301 hMachineGPAppliedEvent = CreateGPEvent(TRUE,
302 lpSecurityDescriptor);
303 if (hMachineGPAppliedEvent == NULL)
304 {
305 goto Cleanup;
306 }
307 }
308
309 /* create or open the local group policy event only if necessary */
310 if (!bMachine && hLocalGPAppliedEvent == NULL)
311 {
312 if (lpSecurityDescriptor == NULL)
313 {
314 lpSecurityDescriptor = CreateDefaultSecurityDescriptor();
315 if (lpSecurityDescriptor == NULL)
316 {
317 goto Cleanup;
318 }
319 }
320
321 hLocalGPAppliedEvent = CreateGPEvent(FALSE,
322 lpSecurityDescriptor);
323 if (hLocalGPAppliedEvent == NULL)
324 {
325 goto Cleanup;
326 }
327 }
328
329 if (hNotificationThread == NULL)
330 {
331 hNotificationThread = CreateThread(NULL,
332 0,
333 GPNotificationThreadProc,
334 NULL,
335 0,
336 NULL);
337 }
338
339 if (hNotificationThread != NULL)
340 {
341 Notify = (PGP_NOTIFY)LocalAlloc(LMEM_FIXED,
342 sizeof(GP_NOTIFY));
343 if (Notify != NULL)
344 {
345 /* add the item to the beginning of the list */
346 Notify->Next = NotificationList;
347 Notify->hEvent = hEvent;
348 Notify->bMachine = bMachine;
349
350 NotificationList = Notify;
351
352 /* notify the thread */
353 GPNotificationAction = gpaUpdate;
354 SetEvent(hNotificationThreadEvent);
355
356 Ret = TRUE;
357 }
358 }
359
360 Cleanup:
361 LeaveCriticalSection(&GPNotifyLock);
362
363 if (lpSecurityDescriptor != NULL)
364 {
365 LocalFree((HLOCAL)lpSecurityDescriptor);
366 }
367
368 /* NOTE: don't delete the events or close the handles created */
369
370 return Ret;
371 }
372
373 BOOL WINAPI
374 UnregisterGPNotification(IN HANDLE hEvent)
375 {
376 PGP_NOTIFY Notify = NULL, *NotifyLink;
377 BOOL Ret = FALSE;
378
379 EnterCriticalSection(&GPNotifyLock);
380
381 Notify = NotificationList;
382 NotifyLink = &NotificationList;
383
384 while (Notify != NULL)
385 {
386 if (Notify->hEvent == hEvent)
387 {
388 /* remove and free the item */
389 *NotifyLink = Notify->Next;
390 LocalFree((HLOCAL)Notify);
391
392 /* notify the thread */
393 if (hNotificationThread != NULL &&
394 hNotificationThreadEvent != NULL)
395 {
396 GPNotificationAction = gpaUpdate;
397 SetEvent(hNotificationThreadEvent);
398 }
399
400 Ret = TRUE;
401 break;
402 }
403
404 NotifyLink = &Notify->Next;
405 Notify = Notify->Next;
406 }
407
408 LeaveCriticalSection(&GPNotifyLock);
409
410 return Ret;
411 }