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 } 603