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