1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Winlogon 4 * FILE: base/system/winlogon/sas.c 5 * PURPOSE: Secure Attention Sequence 6 * PROGRAMMERS: Thomas Weidenmueller (w3seek@users.sourceforge.net) 7 * Hervé Poussineau (hpoussin@reactos.org) 8 * Arnav Bhatt (arnavbhatt288@gmail.com) 9 * UPDATE HISTORY: 10 * Created 28/03/2004 11 */ 12 13 /* INCLUDES *****************************************************************/ 14 15 #include "winlogon.h" 16 17 #define WIN32_LEAN_AND_MEAN 18 #include <aclapi.h> 19 #include <mmsystem.h> 20 #include <userenv.h> 21 #include <ndk/setypes.h> 22 #include <ndk/sefuncs.h> 23 24 /* GLOBALS ******************************************************************/ 25 26 #define WINLOGON_SAS_CLASS L"SAS Window class" 27 #define WINLOGON_SAS_TITLE L"SAS window" 28 29 #define HK_CTRL_ALT_DEL 0 30 #define HK_CTRL_SHIFT_ESC 1 31 32 // #define EWX_FLAGS_MASK 0x00000014 33 // #define EWX_ACTION_MASK ~EWX_FLAGS_MASK 34 35 // FIXME: At the moment we use this value (select the lowbyte flags and some highbytes ones). 36 // It should be set such that it makes winlogon accepting only valid flags. 37 #define EWX_ACTION_MASK 0x5C0F 38 39 typedef struct tagLOGOFF_SHUTDOWN_DATA 40 { 41 UINT Flags; 42 PWLSESSION Session; 43 } LOGOFF_SHUTDOWN_DATA, *PLOGOFF_SHUTDOWN_DATA; 44 45 static BOOL ExitReactOSInProgress = FALSE; 46 47 LUID LuidNone = {0, 0}; 48 49 /* FUNCTIONS ****************************************************************/ 50 51 static BOOL 52 StartTaskManager( 53 IN OUT PWLSESSION Session) 54 { 55 LPVOID lpEnvironment; 56 BOOL ret; 57 58 if (!Session->Gina.Functions.WlxStartApplication) 59 return FALSE; 60 61 if (!CreateEnvironmentBlock( 62 &lpEnvironment, 63 Session->UserToken, 64 TRUE)) 65 { 66 return FALSE; 67 } 68 69 ret = Session->Gina.Functions.WlxStartApplication( 70 Session->Gina.Context, 71 L"Default", 72 lpEnvironment, 73 L"taskmgr.exe"); 74 75 DestroyEnvironmentBlock(lpEnvironment); 76 return ret; 77 } 78 79 static BOOL 80 StartUserShell( 81 IN OUT PWLSESSION Session) 82 { 83 LPVOID lpEnvironment = NULL; 84 BOOLEAN Old; 85 BOOL ret; 86 87 /* Create environment block for the user */ 88 if (!CreateEnvironmentBlock(&lpEnvironment, Session->UserToken, TRUE)) 89 { 90 WARN("WL: CreateEnvironmentBlock() failed\n"); 91 return FALSE; 92 } 93 94 /* Get privilege */ 95 /* FIXME: who should do it? winlogon or gina? */ 96 /* FIXME: reverting to lower privileges after creating user shell? */ 97 RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, TRUE, FALSE, &Old); 98 99 ret = Session->Gina.Functions.WlxActivateUserShell( 100 Session->Gina.Context, 101 L"Default", 102 NULL, /* FIXME */ 103 lpEnvironment); 104 105 DestroyEnvironmentBlock(lpEnvironment); 106 return ret; 107 } 108 109 110 BOOL 111 SetDefaultLanguage( 112 IN PWLSESSION Session) 113 { 114 BOOL ret = FALSE; 115 BOOL UserProfile; 116 LONG rc; 117 HKEY UserKey, hKey = NULL; 118 LPCWSTR SubKey, ValueName; 119 DWORD dwType, dwSize; 120 LPWSTR Value = NULL; 121 UNICODE_STRING ValueString; 122 NTSTATUS Status; 123 LCID Lcid; 124 125 UserProfile = (Session && Session->UserToken); 126 127 if (UserProfile && !ImpersonateLoggedOnUser(Session->UserToken)) 128 { 129 ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError()); 130 return FALSE; 131 // FIXME: ... or use the default language of the system?? 132 // UserProfile = FALSE; 133 } 134 135 if (UserProfile) 136 { 137 rc = RegOpenCurrentUser(MAXIMUM_ALLOWED, &UserKey); 138 if (rc != ERROR_SUCCESS) 139 { 140 TRACE("RegOpenCurrentUser() failed with error %lu\n", rc); 141 goto cleanup; 142 } 143 144 SubKey = L"Control Panel\\International"; 145 ValueName = L"Locale"; 146 } 147 else 148 { 149 UserKey = NULL; 150 SubKey = L"System\\CurrentControlSet\\Control\\Nls\\Language"; 151 ValueName = L"Default"; 152 } 153 154 rc = RegOpenKeyExW(UserKey ? UserKey : HKEY_LOCAL_MACHINE, 155 SubKey, 156 0, 157 KEY_READ, 158 &hKey); 159 160 if (UserKey) 161 RegCloseKey(UserKey); 162 163 if (rc != ERROR_SUCCESS) 164 { 165 TRACE("RegOpenKeyEx() failed with error %lu\n", rc); 166 goto cleanup; 167 } 168 169 rc = RegQueryValueExW(hKey, 170 ValueName, 171 NULL, 172 &dwType, 173 NULL, 174 &dwSize); 175 if (rc != ERROR_SUCCESS) 176 { 177 TRACE("RegQueryValueEx() failed with error %lu\n", rc); 178 goto cleanup; 179 } 180 else if (dwType != REG_SZ) 181 { 182 TRACE("Wrong type for %S\\%S registry entry (got 0x%lx, expected 0x%x)\n", 183 SubKey, ValueName, dwType, REG_SZ); 184 goto cleanup; 185 } 186 187 Value = HeapAlloc(GetProcessHeap(), 0, dwSize); 188 if (!Value) 189 { 190 TRACE("HeapAlloc() failed\n"); 191 goto cleanup; 192 } 193 rc = RegQueryValueExW(hKey, 194 ValueName, 195 NULL, 196 NULL, 197 (LPBYTE)Value, 198 &dwSize); 199 if (rc != ERROR_SUCCESS) 200 { 201 TRACE("RegQueryValueEx() failed with error %lu\n", rc); 202 goto cleanup; 203 } 204 205 /* Convert Value to a Lcid */ 206 ValueString.Length = ValueString.MaximumLength = (USHORT)dwSize; 207 ValueString.Buffer = Value; 208 Status = RtlUnicodeStringToInteger(&ValueString, 16, (PULONG)&Lcid); 209 if (!NT_SUCCESS(Status)) 210 { 211 TRACE("RtlUnicodeStringToInteger() failed with status 0x%08lx\n", Status); 212 goto cleanup; 213 } 214 215 TRACE("%s language is 0x%08lx\n", 216 UserProfile ? "User" : "System", Lcid); 217 Status = NtSetDefaultLocale(UserProfile, Lcid); 218 if (!NT_SUCCESS(Status)) 219 { 220 TRACE("NtSetDefaultLocale() failed with status 0x%08lx\n", Status); 221 goto cleanup; 222 } 223 224 ret = TRUE; 225 226 cleanup: 227 if (Value) 228 HeapFree(GetProcessHeap(), 0, Value); 229 230 if (hKey) 231 RegCloseKey(hKey); 232 233 if (UserProfile) 234 RevertToSelf(); 235 236 return ret; 237 } 238 239 BOOL 240 PlaySoundRoutine( 241 IN LPCWSTR FileName, 242 IN UINT bLogon, 243 IN UINT Flags) 244 { 245 typedef BOOL (WINAPI *PLAYSOUNDW)(LPCWSTR,HMODULE,DWORD); 246 typedef UINT (WINAPI *WAVEOUTGETNUMDEVS)(VOID); 247 PLAYSOUNDW Play; 248 WAVEOUTGETNUMDEVS waveOutGetNumDevs; 249 UINT NumDevs; 250 HMODULE hLibrary; 251 BOOL Ret = FALSE; 252 253 hLibrary = LoadLibraryW(L"winmm.dll"); 254 if (!hLibrary) 255 return FALSE; 256 257 waveOutGetNumDevs = (WAVEOUTGETNUMDEVS)GetProcAddress(hLibrary, "waveOutGetNumDevs"); 258 Play = (PLAYSOUNDW)GetProcAddress(hLibrary, "PlaySoundW"); 259 260 _SEH2_TRY 261 { 262 if (waveOutGetNumDevs) 263 { 264 NumDevs = waveOutGetNumDevs(); 265 if (!NumDevs) 266 { 267 if (!bLogon) 268 Beep(440, 125); 269 _SEH2_LEAVE; 270 } 271 } 272 273 if (Play) 274 Ret = Play(FileName, NULL, Flags); 275 } 276 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 277 { 278 ERR("WL: Exception while playing sound '%S', Status 0x%08lx\n", 279 FileName ? FileName : L"(n/a)", _SEH2_GetExceptionCode()); 280 } 281 _SEH2_END; 282 283 FreeLibrary(hLibrary); 284 285 return Ret; 286 } 287 288 static 289 BOOL 290 IsFirstLogon(VOID) 291 { 292 /* FIXME: All of this is a HACK, designed specifically for PlayLogonSoundThread. 293 * Don't call IsFirstLogon multiple times inside the same function. And please 294 * note that this function is not thread-safe. */ 295 static BOOL bFirstLogon = TRUE; 296 if (bFirstLogon) 297 { 298 bFirstLogon = FALSE; 299 return TRUE; 300 } 301 return FALSE; 302 } 303 304 DWORD 305 WINAPI 306 PlayLogonSoundThread( 307 IN LPVOID lpParameter) 308 { 309 SERVICE_STATUS_PROCESS Info; 310 DWORD dwSize; 311 ULONG Index = 0; 312 SC_HANDLE hSCManager, hService; 313 314 /* Open the service manager */ 315 hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); 316 if (!hSCManager) 317 { 318 ERR("OpenSCManager failed (%x)\n", GetLastError()); 319 return 0; 320 } 321 322 /* Open the wdmaud service */ 323 hService = OpenServiceW(hSCManager, L"wdmaud", GENERIC_READ); 324 if (!hService) 325 { 326 /* The service is not installed */ 327 TRACE("Failed to open wdmaud service (%x)\n", GetLastError()); 328 CloseServiceHandle(hSCManager); 329 return 0; 330 } 331 332 /* Wait for wdmaud to start */ 333 do 334 { 335 if (!QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&Info, sizeof(SERVICE_STATUS_PROCESS), &dwSize)) 336 { 337 TRACE("QueryServiceStatusEx failed (%x)\n", GetLastError()); 338 break; 339 } 340 341 if (Info.dwCurrentState == SERVICE_RUNNING) 342 break; 343 344 Sleep(1000); 345 346 } while (Index++ < 20); 347 348 CloseServiceHandle(hService); 349 CloseServiceHandle(hSCManager); 350 351 /* If wdmaud is not running exit */ 352 if (Info.dwCurrentState != SERVICE_RUNNING) 353 { 354 WARN("wdmaud has not started!\n"); 355 return 0; 356 } 357 358 /* Sound subsystem is running. Play logon sound. */ 359 TRACE("Playing logon sound\n"); 360 if (!ImpersonateLoggedOnUser((HANDLE)lpParameter)) 361 { 362 ERR("ImpersonateLoggedOnUser failed (%x)\n", GetLastError()); 363 } 364 else 365 { 366 PlaySoundRoutine(IsFirstLogon() ? L"SystemStart" : L"WindowsLogon", 367 TRUE, 368 SND_ALIAS | SND_NODEFAULT); 369 RevertToSelf(); 370 } 371 return 0; 372 } 373 374 static 375 VOID 376 PlayLogonSound( 377 IN OUT PWLSESSION Session) 378 { 379 HANDLE hThread; 380 381 hThread = CreateThread(NULL, 0, PlayLogonSoundThread, (PVOID)Session->UserToken, 0, NULL); 382 if (hThread) 383 CloseHandle(hThread); 384 } 385 386 static 387 VOID 388 PlayLogoffShutdownSound( 389 _In_ PWLSESSION Session, 390 _In_ BOOL bShutdown) 391 { 392 if (!ImpersonateLoggedOnUser(Session->UserToken)) 393 return; 394 395 /* NOTE: Logoff and shutdown sounds play synchronously */ 396 PlaySoundRoutine(bShutdown ? L"SystemExit" : L"WindowsLogoff", 397 FALSE, 398 SND_ALIAS | SND_NODEFAULT); 399 400 RevertToSelf(); 401 } 402 403 static 404 BOOL 405 PlayEventSound( 406 _In_ PWLSESSION Session, 407 _In_ LPCWSTR EventName) 408 { 409 BOOL bRet; 410 411 if (!ImpersonateLoggedOnUser(Session->UserToken)) 412 return FALSE; 413 414 bRet = PlaySoundRoutine(EventName, FALSE, SND_ALIAS | SND_ASYNC | SND_NODEFAULT); 415 416 RevertToSelf(); 417 418 return bRet; 419 } 420 421 static 422 VOID 423 RestoreAllConnections(PWLSESSION Session) 424 { 425 DWORD dRet; 426 HANDLE hEnum; 427 LPNETRESOURCE lpRes; 428 DWORD dSize = 0x1000; 429 DWORD dCount = -1; 430 LPNETRESOURCE lpCur; 431 BOOL UserProfile; 432 433 UserProfile = (Session && Session->UserToken); 434 if (!UserProfile) 435 { 436 return; 437 } 438 439 if (!ImpersonateLoggedOnUser(Session->UserToken)) 440 { 441 ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError()); 442 return; 443 } 444 445 dRet = WNetOpenEnum(RESOURCE_REMEMBERED, RESOURCETYPE_DISK, 0, NULL, &hEnum); 446 if (dRet != WN_SUCCESS) 447 { 448 ERR("Failed to open enumeration: %lu\n", dRet); 449 goto quit; 450 } 451 452 lpRes = HeapAlloc(GetProcessHeap(), 0, dSize); 453 if (!lpRes) 454 { 455 ERR("Failed to allocate memory\n"); 456 WNetCloseEnum(hEnum); 457 goto quit; 458 } 459 460 do 461 { 462 dSize = 0x1000; 463 dCount = -1; 464 465 memset(lpRes, 0, dSize); 466 dRet = WNetEnumResource(hEnum, &dCount, lpRes, &dSize); 467 if (dRet == WN_SUCCESS || dRet == WN_MORE_DATA) 468 { 469 lpCur = lpRes; 470 for (; dCount; dCount--) 471 { 472 WNetAddConnection(lpCur->lpRemoteName, NULL, lpCur->lpLocalName); 473 lpCur++; 474 } 475 } 476 } while (dRet != WN_NO_MORE_ENTRIES); 477 478 HeapFree(GetProcessHeap(), 0, lpRes); 479 WNetCloseEnum(hEnum); 480 481 quit: 482 RevertToSelf(); 483 } 484 485 static 486 BOOL 487 HandleLogon( 488 IN OUT PWLSESSION Session) 489 { 490 PROFILEINFOW ProfileInfo; 491 BOOL ret = FALSE; 492 493 /* Loading personal settings */ 494 DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_LOADINGYOURPERSONALSETTINGS); 495 ProfileInfo.hProfile = INVALID_HANDLE_VALUE; 496 if (0 == (Session->Options & WLX_LOGON_OPT_NO_PROFILE)) 497 { 498 if (Session->Profile == NULL 499 || (Session->Profile->dwType != WLX_PROFILE_TYPE_V1_0 500 && Session->Profile->dwType != WLX_PROFILE_TYPE_V2_0)) 501 { 502 ERR("WL: Wrong profile\n"); 503 goto cleanup; 504 } 505 506 /* Load the user profile */ 507 ZeroMemory(&ProfileInfo, sizeof(PROFILEINFOW)); 508 ProfileInfo.dwSize = sizeof(PROFILEINFOW); 509 ProfileInfo.dwFlags = 0; 510 ProfileInfo.lpUserName = Session->MprNotifyInfo.pszUserName; 511 ProfileInfo.lpProfilePath = Session->Profile->pszProfile; 512 if (Session->Profile->dwType >= WLX_PROFILE_TYPE_V2_0) 513 { 514 ProfileInfo.lpDefaultPath = Session->Profile->pszNetworkDefaultUserProfile; 515 ProfileInfo.lpServerName = Session->Profile->pszServerName; 516 ProfileInfo.lpPolicyPath = Session->Profile->pszPolicy; 517 } 518 519 if (!LoadUserProfileW(Session->UserToken, &ProfileInfo)) 520 { 521 ERR("WL: LoadUserProfileW() failed\n"); 522 goto cleanup; 523 } 524 } 525 526 /* Create environment block for the user */ 527 if (!CreateUserEnvironment(Session)) 528 { 529 WARN("WL: SetUserEnvironment() failed\n"); 530 goto cleanup; 531 } 532 533 CallNotificationDlls(Session, LogonHandler); 534 535 DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_APPLYINGYOURPERSONALSETTINGS); 536 UpdatePerUserSystemParameters(0, TRUE); 537 538 /* Set default user language */ 539 if (!SetDefaultLanguage(Session)) 540 { 541 WARN("WL: SetDefaultLanguage() failed\n"); 542 goto cleanup; 543 } 544 545 /* Allow winsta and desktop access for this session */ 546 if (!AllowAccessOnSession(Session)) 547 { 548 WARN("WL: AllowAccessOnSession() failed to give winsta & desktop access for this session\n"); 549 goto cleanup; 550 } 551 552 /* Connect remote resources */ 553 RestoreAllConnections(Session); 554 555 if (!StartUserShell(Session)) 556 { 557 //WCHAR StatusMsg[256]; 558 WARN("WL: WlxActivateUserShell() failed\n"); 559 //LoadStringW(hAppInstance, IDS_FAILEDACTIVATEUSERSHELL, StatusMsg, sizeof(StatusMsg) / sizeof(StatusMsg[0])); 560 //MessageBoxW(0, StatusMsg, NULL, MB_ICONERROR); 561 goto cleanup; 562 } 563 564 CallNotificationDlls(Session, StartShellHandler); 565 566 if (!InitializeScreenSaver(Session)) 567 WARN("WL: Failed to initialize screen saver\n"); 568 569 Session->hProfileInfo = ProfileInfo.hProfile; 570 571 /* Logon has succeeded. Play sound. */ 572 PlayLogonSound(Session); 573 574 ret = TRUE; 575 576 cleanup: 577 if (Session->Profile) 578 { 579 HeapFree(GetProcessHeap(), 0, Session->Profile->pszProfile); 580 HeapFree(GetProcessHeap(), 0, Session->Profile); 581 } 582 Session->Profile = NULL; 583 if (!ret && ProfileInfo.hProfile != INVALID_HANDLE_VALUE) 584 { 585 UnloadUserProfile(Session->UserToken, ProfileInfo.hProfile); 586 } 587 RemoveStatusMessage(Session); 588 if (!ret) 589 { 590 SetWindowStationUser(Session->InteractiveWindowStation, 591 &LuidNone, NULL, 0); 592 CloseHandle(Session->UserToken); 593 Session->UserToken = NULL; 594 } 595 596 if (ret) 597 { 598 SwitchDesktop(Session->ApplicationDesktop); 599 Session->LogonState = STATE_LOGGED_ON; 600 } 601 602 return ret; 603 } 604 605 606 static 607 DWORD 608 WINAPI 609 LogoffShutdownThread( 610 LPVOID Parameter) 611 { 612 DWORD ret = 1; 613 PLOGOFF_SHUTDOWN_DATA LSData = (PLOGOFF_SHUTDOWN_DATA)Parameter; 614 UINT uFlags; 615 616 if (LSData->Session->UserToken != NULL && 617 !ImpersonateLoggedOnUser(LSData->Session->UserToken)) 618 { 619 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError()); 620 return 0; 621 } 622 623 // FIXME: To be really fixed: need to check what needs to be kept and what needs to be removed there. 624 // 625 // uFlags = EWX_INTERNAL_KILL_USER_APPS | (LSData->Flags & EWX_FLAGS_MASK) | 626 // ((LSData->Flags & EWX_ACTION_MASK) == EWX_LOGOFF ? EWX_CALLER_WINLOGON_LOGOFF : 0); 627 628 uFlags = EWX_CALLER_WINLOGON | (LSData->Flags & 0x0F); 629 630 TRACE("In LogoffShutdownThread with uFlags == 0x%x; exit_in_progress == %s\n", 631 uFlags, ExitReactOSInProgress ? "true" : "false"); 632 633 ExitReactOSInProgress = TRUE; 634 635 /* Close processes of the interactive user */ 636 if (!ExitWindowsEx(uFlags, 0)) 637 { 638 ERR("Unable to kill user apps, error %lu\n", GetLastError()); 639 ret = 0; 640 } 641 642 /* Cancel all the user connections */ 643 WNetClearConnections(NULL); 644 645 if (LSData->Session->UserToken) 646 RevertToSelf(); 647 648 return ret; 649 } 650 651 static 652 DWORD 653 WINAPI 654 KillComProcesses( 655 LPVOID Parameter) 656 { 657 DWORD ret = 1; 658 PLOGOFF_SHUTDOWN_DATA LSData = (PLOGOFF_SHUTDOWN_DATA)Parameter; 659 660 TRACE("In KillComProcesses\n"); 661 662 if (LSData->Session->UserToken != NULL && 663 !ImpersonateLoggedOnUser(LSData->Session->UserToken)) 664 { 665 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError()); 666 return 0; 667 } 668 669 /* Attempt to kill remaining processes. No notifications needed. */ 670 if (!ExitWindowsEx(EWX_CALLER_WINLOGON | EWX_NONOTIFY | EWX_FORCE | EWX_LOGOFF, 0)) 671 { 672 ERR("Unable to kill COM apps, error %lu\n", GetLastError()); 673 ret = 0; 674 } 675 676 if (LSData->Session->UserToken) 677 RevertToSelf(); 678 679 return ret; 680 } 681 682 static 683 NTSTATUS 684 CreateLogoffSecurityAttributes( 685 OUT PSECURITY_ATTRIBUTES* ppsa) 686 { 687 /* The following code is not working yet and messy */ 688 /* Still, it gives some ideas about data types and functions involved and */ 689 /* required to set up a SECURITY_DESCRIPTOR for a SECURITY_ATTRIBUTES */ 690 /* instance for a thread, to allow that thread to ImpersonateLoggedOnUser(). */ 691 /* Specifically THREAD_SET_THREAD_TOKEN is required. */ 692 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; 693 PSECURITY_ATTRIBUTES psa = 0; 694 BYTE* pMem; 695 PACL pACL; 696 EXPLICIT_ACCESS Access; 697 PSID pEveryoneSID = NULL; 698 static SID_IDENTIFIER_AUTHORITY WorldAuthority = { SECURITY_WORLD_SID_AUTHORITY }; 699 700 *ppsa = NULL; 701 702 // Let's first try to enumerate what kind of data we need for this to ever work: 703 // 1. The Winlogon SID, to be able to give it THREAD_SET_THREAD_TOKEN. 704 // 2. The users SID (the user trying to logoff, or rather shut down the system). 705 // 3. At least two EXPLICIT_ACCESS instances: 706 // 3.1 One for Winlogon itself, giving it the rights 707 // required to THREAD_SET_THREAD_TOKEN (as it's needed to successfully call 708 // ImpersonateLoggedOnUser). 709 // 3.2 One for the user, to allow *that* thread to perform its work. 710 // 4. An ACL to hold the these EXPLICIT_ACCESS ACE's. 711 // 5. A SECURITY_DESCRIPTOR to hold the ACL, and finally. 712 // 6. A SECURITY_ATTRIBUTES instance to pull all of this required stuff 713 // together, to hand it to CreateThread. 714 // 715 // However, it seems struct LOGOFF_SHUTDOWN_DATA doesn't contain 716 // these required SID's, why they'd have to be added. 717 // The Winlogon's own SID should probably only be created once, 718 // while the user's SID obviously must be created for each new user. 719 // Might as well store it when the user logs on? 720 721 if(!AllocateAndInitializeSid(&WorldAuthority, 722 1, 723 SECURITY_WORLD_RID, 724 0, 0, 0, 0, 0, 0, 0, 725 &pEveryoneSID)) 726 { 727 ERR("Failed to initialize security descriptor for logoff thread!\n"); 728 return STATUS_UNSUCCESSFUL; 729 } 730 731 /* set up the required security attributes to be able to shut down */ 732 /* To save space and time, allocate a single block of memory holding */ 733 /* both SECURITY_ATTRIBUTES and SECURITY_DESCRIPTOR */ 734 pMem = HeapAlloc(GetProcessHeap(), 735 0, 736 sizeof(SECURITY_ATTRIBUTES) + 737 SECURITY_DESCRIPTOR_MIN_LENGTH + 738 sizeof(ACL)); 739 if (!pMem) 740 { 741 ERR("Failed to allocate memory for logoff security descriptor!\n"); 742 return STATUS_NO_MEMORY; 743 } 744 745 /* Note that the security descriptor needs to be in _absolute_ format, */ 746 /* meaning its members must be pointers to other structures, rather */ 747 /* than the relative format using offsets */ 748 psa = (PSECURITY_ATTRIBUTES)pMem; 749 SecurityDescriptor = (PSECURITY_DESCRIPTOR)(pMem + sizeof(SECURITY_ATTRIBUTES)); 750 pACL = (PACL)(((PBYTE)SecurityDescriptor) + SECURITY_DESCRIPTOR_MIN_LENGTH); 751 752 // Initialize an EXPLICIT_ACCESS structure for an ACE. 753 // The ACE will allow this thread to log off (and shut down the system, currently). 754 ZeroMemory(&Access, sizeof(Access)); 755 Access.grfAccessPermissions = THREAD_SET_THREAD_TOKEN; 756 Access.grfAccessMode = SET_ACCESS; // GRANT_ACCESS? 757 Access.grfInheritance = NO_INHERITANCE; 758 Access.Trustee.TrusteeForm = TRUSTEE_IS_SID; 759 Access.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; 760 Access.Trustee.ptstrName = pEveryoneSID; 761 762 if (SetEntriesInAcl(1, &Access, NULL, &pACL) != ERROR_SUCCESS) 763 { 764 ERR("Failed to set Access Rights for logoff thread. Logging out will most likely fail.\n"); 765 766 HeapFree(GetProcessHeap(), 0, pMem); 767 return STATUS_UNSUCCESSFUL; 768 } 769 770 if (!InitializeSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION)) 771 { 772 ERR("Failed to initialize security descriptor for logoff thread!\n"); 773 HeapFree(GetProcessHeap(), 0, pMem); 774 return STATUS_UNSUCCESSFUL; 775 } 776 777 if (!SetSecurityDescriptorDacl(SecurityDescriptor, 778 TRUE, // bDaclPresent flag 779 pACL, 780 FALSE)) // not a default DACL 781 { 782 ERR("SetSecurityDescriptorDacl Error %lu\n", GetLastError()); 783 HeapFree(GetProcessHeap(), 0, pMem); 784 return STATUS_UNSUCCESSFUL; 785 } 786 787 psa->nLength = sizeof(SECURITY_ATTRIBUTES); 788 psa->lpSecurityDescriptor = SecurityDescriptor; 789 psa->bInheritHandle = FALSE; 790 791 *ppsa = psa; 792 793 return STATUS_SUCCESS; 794 } 795 796 static 797 VOID 798 DestroyLogoffSecurityAttributes( 799 IN PSECURITY_ATTRIBUTES psa) 800 { 801 if (psa) 802 { 803 HeapFree(GetProcessHeap(), 0, psa); 804 } 805 } 806 807 808 static 809 NTSTATUS 810 HandleLogoff( 811 _Inout_ PWLSESSION Session, 812 _In_ DWORD wlxAction) 813 { 814 PLOGOFF_SHUTDOWN_DATA LSData; 815 PSECURITY_ATTRIBUTES psa; 816 HANDLE hThread; 817 DWORD exitCode; 818 NTSTATUS Status; 819 820 /* Prepare data for logoff thread */ 821 LSData = HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA)); 822 if (!LSData) 823 { 824 ERR("Failed to allocate mem for thread data\n"); 825 return STATUS_NO_MEMORY; 826 } 827 828 LSData->Flags = EWX_LOGOFF; 829 if (wlxAction == WLX_SAS_ACTION_FORCE_LOGOFF) 830 { 831 LSData->Flags |= EWX_FORCE; 832 } 833 834 LSData->Session = Session; 835 836 Status = CreateLogoffSecurityAttributes(&psa); 837 if (!NT_SUCCESS(Status)) 838 { 839 ERR("Failed to create a required security descriptor. Status 0x%08lx\n", Status); 840 HeapFree(GetProcessHeap(), 0, LSData); 841 return Status; 842 } 843 844 /* Run logoff thread */ 845 hThread = CreateThread(psa, 0, LogoffShutdownThread, (LPVOID)LSData, 0, NULL); 846 if (!hThread) 847 { 848 ERR("Unable to create logoff thread, error %lu\n", GetLastError()); 849 DestroyLogoffSecurityAttributes(psa); 850 HeapFree(GetProcessHeap(), 0, LSData); 851 return STATUS_UNSUCCESSFUL; 852 } 853 WaitForSingleObject(hThread, INFINITE); 854 if (!GetExitCodeThread(hThread, &exitCode)) 855 { 856 ERR("Unable to get exit code of logoff thread (error %lu)\n", GetLastError()); 857 CloseHandle(hThread); 858 DestroyLogoffSecurityAttributes(psa); 859 HeapFree(GetProcessHeap(), 0, LSData); 860 return STATUS_UNSUCCESSFUL; 861 } 862 CloseHandle(hThread); 863 if (exitCode == 0) 864 { 865 ERR("Logoff thread returned failure\n"); 866 DestroyLogoffSecurityAttributes(psa); 867 HeapFree(GetProcessHeap(), 0, LSData); 868 return STATUS_UNSUCCESSFUL; 869 } 870 871 SwitchDesktop(Session->WinlogonDesktop); 872 873 PlayLogoffShutdownSound(Session, WLX_SHUTTINGDOWN(wlxAction)); 874 875 SetWindowStationUser(Session->InteractiveWindowStation, 876 &LuidNone, NULL, 0); 877 878 // DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_LOGGINGOFF); 879 880 // FIXME: Closing network connections! 881 // DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_CLOSINGNETWORKCONNECTIONS); 882 883 /* Kill remaining COM apps. Only at logoff! */ 884 hThread = CreateThread(psa, 0, KillComProcesses, (LPVOID)LSData, 0, NULL); 885 if (hThread) 886 { 887 WaitForSingleObject(hThread, INFINITE); 888 CloseHandle(hThread); 889 } 890 891 /* We're done with the SECURITY_DESCRIPTOR */ 892 DestroyLogoffSecurityAttributes(psa); 893 psa = NULL; 894 895 HeapFree(GetProcessHeap(), 0, LSData); 896 897 DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_SAVEYOURSETTINGS); 898 899 UnloadUserProfile(Session->UserToken, Session->hProfileInfo); 900 901 CallNotificationDlls(Session, LogoffHandler); 902 903 CloseHandle(Session->UserToken); 904 UpdatePerUserSystemParameters(0, FALSE); 905 Session->LogonState = STATE_LOGGED_OFF; 906 Session->UserToken = NULL; 907 908 return STATUS_SUCCESS; 909 } 910 911 static 912 INT_PTR 913 CALLBACK 914 ShutdownComputerWindowProc( 915 IN HWND hwndDlg, 916 IN UINT uMsg, 917 IN WPARAM wParam, 918 IN LPARAM lParam) 919 { 920 UNREFERENCED_PARAMETER(lParam); 921 922 switch (uMsg) 923 { 924 case WM_COMMAND: 925 { 926 switch (LOWORD(wParam)) 927 { 928 case IDC_BTNSHTDOWNCOMPUTER: 929 EndDialog(hwndDlg, IDC_BTNSHTDOWNCOMPUTER); 930 return TRUE; 931 } 932 break; 933 } 934 case WM_INITDIALOG: 935 { 936 RemoveMenu(GetSystemMenu(hwndDlg, FALSE), SC_CLOSE, MF_BYCOMMAND); 937 SetFocus(GetDlgItem(hwndDlg, IDC_BTNSHTDOWNCOMPUTER)); 938 return TRUE; 939 } 940 } 941 return FALSE; 942 } 943 944 static 945 VOID 946 UninitializeSAS( 947 IN OUT PWLSESSION Session) 948 { 949 if (Session->SASWindow) 950 { 951 DestroyWindow(Session->SASWindow); 952 Session->SASWindow = NULL; 953 } 954 if (Session->hEndOfScreenSaverThread) 955 SetEvent(Session->hEndOfScreenSaverThread); 956 UnregisterClassW(WINLOGON_SAS_CLASS, hAppInstance); 957 } 958 959 NTSTATUS 960 HandleShutdown( 961 IN OUT PWLSESSION Session, 962 IN DWORD wlxAction) 963 { 964 PLOGOFF_SHUTDOWN_DATA LSData; 965 HANDLE hThread; 966 DWORD exitCode; 967 BOOLEAN Old; 968 969 // SwitchDesktop(Session->WinlogonDesktop); 970 971 /* If the system is rebooting, show the appropriate string */ 972 if (wlxAction == WLX_SAS_ACTION_SHUTDOWN_REBOOT) 973 DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_REACTOSISRESTARTING); 974 else 975 DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_REACTOSISSHUTTINGDOWN); 976 977 /* Prepare data for shutdown thread */ 978 LSData = HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA)); 979 if (!LSData) 980 { 981 ERR("Failed to allocate mem for thread data\n"); 982 return STATUS_NO_MEMORY; 983 } 984 if (wlxAction == WLX_SAS_ACTION_SHUTDOWN_POWER_OFF) 985 LSData->Flags = EWX_POWEROFF; 986 else if (wlxAction == WLX_SAS_ACTION_SHUTDOWN_REBOOT) 987 LSData->Flags = EWX_REBOOT; 988 else 989 LSData->Flags = EWX_SHUTDOWN; 990 LSData->Session = Session; 991 992 // FIXME: We may need to specify this flag to really force application kill 993 // (we are shutting down ReactOS, not just logging off so no hangs, etc... 994 // should be allowed). 995 // LSData->Flags |= EWX_FORCE; 996 997 /* Run shutdown thread */ 998 hThread = CreateThread(NULL, 0, LogoffShutdownThread, (LPVOID)LSData, 0, NULL); 999 if (!hThread) 1000 { 1001 ERR("Unable to create shutdown thread, error %lu\n", GetLastError()); 1002 HeapFree(GetProcessHeap(), 0, LSData); 1003 return STATUS_UNSUCCESSFUL; 1004 } 1005 WaitForSingleObject(hThread, INFINITE); 1006 HeapFree(GetProcessHeap(), 0, LSData); 1007 if (!GetExitCodeThread(hThread, &exitCode)) 1008 { 1009 ERR("Unable to get exit code of shutdown thread (error %lu)\n", GetLastError()); 1010 CloseHandle(hThread); 1011 return STATUS_UNSUCCESSFUL; 1012 } 1013 CloseHandle(hThread); 1014 if (exitCode == 0) 1015 { 1016 ERR("Shutdown thread returned failure\n"); 1017 return STATUS_UNSUCCESSFUL; 1018 } 1019 1020 CallNotificationDlls(Session, ShutdownHandler); 1021 1022 /* Destroy SAS window */ 1023 UninitializeSAS(Session); 1024 1025 /* Now we can shut down NT */ 1026 ERR("Shutting down NT...\n"); 1027 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &Old); 1028 if (wlxAction == WLX_SAS_ACTION_SHUTDOWN_REBOOT) 1029 { 1030 NtShutdownSystem(ShutdownReboot); 1031 } 1032 else 1033 { 1034 if (FALSE) 1035 { 1036 /* FIXME - only show this dialog if it's a shutdown and the computer doesn't support APM */ 1037 DialogBox(hAppInstance, MAKEINTRESOURCE(IDD_SHUTDOWNCOMPUTER), 1038 GetDesktopWindow(), ShutdownComputerWindowProc); 1039 } 1040 NtShutdownSystem(ShutdownNoReboot); 1041 } 1042 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, Old, FALSE, &Old); 1043 return STATUS_SUCCESS; 1044 } 1045 1046 static 1047 VOID 1048 DoGenericAction( 1049 IN OUT PWLSESSION Session, 1050 IN DWORD wlxAction) 1051 { 1052 switch (wlxAction) 1053 { 1054 case WLX_SAS_ACTION_LOGON: /* 0x01 */ 1055 if (Session->LogonState == STATE_LOGGED_OFF_SAS) 1056 { 1057 if (!HandleLogon(Session)) 1058 { 1059 Session->Gina.Functions.WlxDisplaySASNotice(Session->Gina.Context); 1060 CallNotificationDlls(Session, LogonHandler); 1061 } 1062 } 1063 break; 1064 case WLX_SAS_ACTION_NONE: /* 0x02 */ 1065 if (Session->LogonState == STATE_LOGGED_OFF_SAS) 1066 { 1067 Session->LogonState = STATE_LOGGED_OFF; 1068 Session->Gina.Functions.WlxDisplaySASNotice(Session->Gina.Context); 1069 } 1070 else if (Session->LogonState == STATE_LOGGED_ON_SAS) 1071 { 1072 Session->LogonState = STATE_LOGGED_ON; 1073 } 1074 else if (Session->LogonState == STATE_LOCKED_SAS) 1075 { 1076 Session->LogonState = STATE_LOCKED; 1077 Session->Gina.Functions.WlxDisplayLockedNotice(Session->Gina.Context); 1078 } 1079 break; 1080 case WLX_SAS_ACTION_LOCK_WKSTA: /* 0x03 */ 1081 if (Session->Gina.Functions.WlxIsLockOk(Session->Gina.Context)) 1082 { 1083 SwitchDesktop(Session->WinlogonDesktop); 1084 Session->LogonState = STATE_LOCKED; 1085 Session->Gina.Functions.WlxDisplayLockedNotice(Session->Gina.Context); 1086 CallNotificationDlls(Session, LockHandler); 1087 } 1088 break; 1089 case WLX_SAS_ACTION_LOGOFF: /* 0x04 */ 1090 case WLX_SAS_ACTION_SHUTDOWN: /* 0x05 */ 1091 case WLX_SAS_ACTION_FORCE_LOGOFF: /* 0x09 */ 1092 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF: /* 0x0a */ 1093 case WLX_SAS_ACTION_SHUTDOWN_REBOOT: /* 0x0b */ 1094 if (Session->LogonState != STATE_LOGGED_OFF) 1095 { 1096 if (!Session->Gina.Functions.WlxIsLogoffOk(Session->Gina.Context)) 1097 break; 1098 if (!NT_SUCCESS(HandleLogoff(Session, wlxAction))) 1099 { 1100 RemoveStatusMessage(Session); 1101 break; 1102 } 1103 Session->Gina.Functions.WlxLogoff(Session->Gina.Context); 1104 } 1105 if (WLX_SHUTTINGDOWN(wlxAction)) 1106 { 1107 // FIXME: WlxShutdown should be done from inside HandleShutdown, 1108 // after having displayed "ReactOS is shutting down" message. 1109 Session->Gina.Functions.WlxShutdown(Session->Gina.Context, wlxAction); 1110 if (!NT_SUCCESS(HandleShutdown(Session, wlxAction))) 1111 { 1112 RemoveStatusMessage(Session); 1113 Session->Gina.Functions.WlxDisplaySASNotice(Session->Gina.Context); 1114 } 1115 } 1116 else 1117 { 1118 RemoveStatusMessage(Session); 1119 Session->Gina.Functions.WlxDisplaySASNotice(Session->Gina.Context); 1120 } 1121 break; 1122 case WLX_SAS_ACTION_TASKLIST: /* 0x07 */ 1123 SwitchDesktop(Session->ApplicationDesktop); 1124 Session->LogonState = STATE_LOGGED_ON; 1125 StartTaskManager(Session); 1126 break; 1127 case WLX_SAS_ACTION_UNLOCK_WKSTA: /* 0x08 */ 1128 SwitchDesktop(Session->ApplicationDesktop); 1129 Session->LogonState = STATE_LOGGED_ON; 1130 CallNotificationDlls(Session, UnlockHandler); 1131 break; 1132 default: 1133 WARN("Unknown SAS action 0x%lx\n", wlxAction); 1134 } 1135 } 1136 1137 static 1138 VOID 1139 DispatchSAS( 1140 IN OUT PWLSESSION Session, 1141 IN DWORD dwSasType) 1142 { 1143 DWORD wlxAction = WLX_SAS_ACTION_NONE; 1144 PSID LogonSid = NULL; /* FIXME */ 1145 BOOL bSecure = TRUE; 1146 1147 switch (dwSasType) 1148 { 1149 case WLX_SAS_TYPE_CTRL_ALT_DEL: 1150 switch (Session->LogonState) 1151 { 1152 case STATE_INIT: 1153 Session->LogonState = STATE_LOGGED_OFF; 1154 Session->Gina.Functions.WlxDisplaySASNotice(Session->Gina.Context); 1155 return; 1156 1157 case STATE_LOGGED_OFF: 1158 Session->LogonState = STATE_LOGGED_OFF_SAS; 1159 1160 CloseAllDialogWindows(); 1161 1162 Session->Options = 0; 1163 1164 wlxAction = (DWORD)Session->Gina.Functions.WlxLoggedOutSAS( 1165 Session->Gina.Context, 1166 Session->SASAction, 1167 &Session->LogonId, 1168 LogonSid, 1169 &Session->Options, 1170 &Session->UserToken, 1171 &Session->MprNotifyInfo, 1172 (PVOID*)&Session->Profile); 1173 break; 1174 1175 case STATE_LOGGED_OFF_SAS: 1176 /* Ignore SAS if we are already in an SAS state */ 1177 return; 1178 1179 case STATE_LOGGED_ON: 1180 Session->LogonState = STATE_LOGGED_ON_SAS; 1181 wlxAction = (DWORD)Session->Gina.Functions.WlxLoggedOnSAS(Session->Gina.Context, dwSasType, NULL); 1182 break; 1183 1184 case STATE_LOGGED_ON_SAS: 1185 /* Ignore SAS if we are already in an SAS state */ 1186 return; 1187 1188 case STATE_LOCKED: 1189 Session->LogonState = STATE_LOCKED_SAS; 1190 1191 CloseAllDialogWindows(); 1192 1193 wlxAction = (DWORD)Session->Gina.Functions.WlxWkstaLockedSAS(Session->Gina.Context, dwSasType); 1194 break; 1195 1196 case STATE_LOCKED_SAS: 1197 /* Ignore SAS if we are already in an SAS state */ 1198 return; 1199 1200 default: 1201 return; 1202 } 1203 break; 1204 1205 case WLX_SAS_TYPE_TIMEOUT: 1206 return; 1207 1208 case WLX_SAS_TYPE_SCRNSVR_TIMEOUT: 1209 if (!Session->Gina.Functions.WlxScreenSaverNotify(Session->Gina.Context, &bSecure)) 1210 { 1211 /* Skip start of screen saver */ 1212 SetEvent(Session->hEndOfScreenSaver); 1213 } 1214 else 1215 { 1216 StartScreenSaver(Session); 1217 if (bSecure) 1218 { 1219 wlxAction = WLX_SAS_ACTION_LOCK_WKSTA; 1220 // DoGenericAction(Session, WLX_SAS_ACTION_LOCK_WKSTA); 1221 } 1222 } 1223 break; 1224 1225 case WLX_SAS_TYPE_SCRNSVR_ACTIVITY: 1226 SetEvent(Session->hUserActivity); 1227 break; 1228 } 1229 1230 DoGenericAction(Session, wlxAction); 1231 } 1232 1233 static 1234 BOOL 1235 RegisterHotKeys( 1236 IN PWLSESSION Session, 1237 IN HWND hwndSAS) 1238 { 1239 /* Register Ctrl+Alt+Del Hotkey */ 1240 if (!RegisterHotKey(hwndSAS, HK_CTRL_ALT_DEL, MOD_CONTROL | MOD_ALT, VK_DELETE)) 1241 { 1242 ERR("WL: Unable to register Ctrl+Alt+Del hotkey!\n"); 1243 return FALSE; 1244 } 1245 1246 /* Register Ctrl+Shift+Esc (optional) */ 1247 Session->TaskManHotkey = RegisterHotKey(hwndSAS, HK_CTRL_SHIFT_ESC, MOD_CONTROL | MOD_SHIFT, VK_ESCAPE); 1248 if (!Session->TaskManHotkey) 1249 WARN("WL: Warning: Unable to register Ctrl+Alt+Esc hotkey!\n"); 1250 return TRUE; 1251 } 1252 1253 static 1254 BOOL 1255 UnregisterHotKeys( 1256 IN PWLSESSION Session, 1257 IN HWND hwndSAS) 1258 { 1259 /* Unregister hotkeys */ 1260 UnregisterHotKey(hwndSAS, HK_CTRL_ALT_DEL); 1261 1262 if (Session->TaskManHotkey) 1263 UnregisterHotKey(hwndSAS, HK_CTRL_SHIFT_ESC); 1264 1265 return TRUE; 1266 } 1267 1268 static 1269 BOOL 1270 HandleMessageBeep( 1271 _In_ PWLSESSION Session, 1272 _In_ UINT uType) 1273 { 1274 LPWSTR EventName; 1275 1276 switch (uType) 1277 { 1278 case 0xFFFFFFFF: 1279 EventName = NULL; 1280 break; 1281 case MB_OK: 1282 EventName = L"SystemDefault"; 1283 break; 1284 case MB_ICONASTERISK: 1285 EventName = L"SystemAsterisk"; 1286 break; 1287 case MB_ICONEXCLAMATION: 1288 EventName = L"SystemExclamation"; 1289 break; 1290 case MB_ICONHAND: 1291 EventName = L"SystemHand"; 1292 break; 1293 case MB_ICONQUESTION: 1294 EventName = L"SystemQuestion"; 1295 break; 1296 default: 1297 WARN("Unhandled type %d\n", uType); 1298 EventName = L"SystemDefault"; 1299 } 1300 1301 return PlayEventSound(Session, EventName); 1302 } 1303 1304 static 1305 LRESULT 1306 CALLBACK 1307 SASWindowProc( 1308 IN HWND hwndDlg, 1309 IN UINT uMsg, 1310 IN WPARAM wParam, 1311 IN LPARAM lParam) 1312 { 1313 PWLSESSION Session = (PWLSESSION)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 1314 1315 switch (uMsg) 1316 { 1317 case WM_HOTKEY: 1318 { 1319 switch (lParam) 1320 { 1321 case MAKELONG(MOD_CONTROL | MOD_ALT, VK_DELETE): 1322 { 1323 TRACE("SAS: CONTROL+ALT+DELETE\n"); 1324 if (!Session->Gina.UseCtrlAltDelete) 1325 break; 1326 PostMessageW(Session->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_CTRL_ALT_DEL, 0); 1327 return TRUE; 1328 } 1329 case MAKELONG(MOD_CONTROL | MOD_SHIFT, VK_ESCAPE): 1330 { 1331 TRACE("SAS: CONTROL+SHIFT+ESCAPE\n"); 1332 if (Session->LogonState == STATE_LOGGED_ON) 1333 DoGenericAction(Session, WLX_SAS_ACTION_TASKLIST); 1334 return TRUE; 1335 } 1336 } 1337 break; 1338 } 1339 case WM_CREATE: 1340 { 1341 /* Get the session pointer from the create data */ 1342 Session = (PWLSESSION)((LPCREATESTRUCT)lParam)->lpCreateParams; 1343 1344 /* Save the Session pointer */ 1345 SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (LONG_PTR)Session); 1346 if (GetSetupType()) 1347 return TRUE; 1348 return RegisterHotKeys(Session, hwndDlg); 1349 } 1350 case WM_DESTROY: 1351 { 1352 if (!GetSetupType()) 1353 UnregisterHotKeys(Session, hwndDlg); 1354 return TRUE; 1355 } 1356 case WM_SETTINGCHANGE: 1357 { 1358 UINT uiAction = (UINT)wParam; 1359 if (uiAction == SPI_SETSCREENSAVETIMEOUT 1360 || uiAction == SPI_SETSCREENSAVEACTIVE) 1361 { 1362 SetEvent(Session->hScreenSaverParametersChanged); 1363 } 1364 return TRUE; 1365 } 1366 case WM_LOGONNOTIFY: 1367 { 1368 switch(wParam) 1369 { 1370 case LN_MESSAGE_BEEP: 1371 { 1372 return HandleMessageBeep(Session, lParam); 1373 } 1374 case LN_SHELL_EXITED: 1375 { 1376 /* lParam is the exit code */ 1377 if (lParam != 1 && 1378 Session->LogonState != STATE_LOGGED_OFF && 1379 Session->LogonState != STATE_LOGGED_OFF_SAS) 1380 { 1381 SetTimer(hwndDlg, 1, 1000, NULL); 1382 } 1383 break; 1384 } 1385 case LN_START_SCREENSAVE: 1386 { 1387 DispatchSAS(Session, WLX_SAS_TYPE_SCRNSVR_TIMEOUT); 1388 break; 1389 } 1390 case LN_LOCK_WORKSTATION: 1391 { 1392 DoGenericAction(Session, WLX_SAS_ACTION_LOCK_WKSTA); 1393 break; 1394 } 1395 case LN_LOGOFF: 1396 { 1397 UINT Flags = (UINT)lParam; 1398 UINT Action = Flags & EWX_ACTION_MASK; 1399 DWORD wlxAction; 1400 1401 TRACE("\tFlags : 0x%lx\n", lParam); 1402 1403 /* 1404 * Our caller (USERSRV) should have added the shutdown flag 1405 * when setting also poweroff or reboot. 1406 */ 1407 if (Action & (EWX_POWEROFF | EWX_REBOOT)) 1408 { 1409 if ((Action & EWX_SHUTDOWN) == 0) 1410 { 1411 ERR("Missing EWX_SHUTDOWN flag for poweroff or reboot; action 0x%x\n", Action); 1412 return STATUS_INVALID_PARAMETER; 1413 } 1414 1415 /* Now we can locally remove it for performing checks */ 1416 Action &= ~EWX_SHUTDOWN; 1417 } 1418 1419 /* Check parameters */ 1420 if (Action & EWX_FORCE) 1421 { 1422 // FIXME! 1423 ERR("FIXME: EWX_FORCE present for Winlogon, what to do?\n"); 1424 Action &= ~EWX_FORCE; 1425 } 1426 switch (Action) 1427 { 1428 case EWX_LOGOFF: 1429 wlxAction = WLX_SAS_ACTION_LOGOFF; 1430 break; 1431 case EWX_SHUTDOWN: 1432 wlxAction = WLX_SAS_ACTION_SHUTDOWN; 1433 break; 1434 case EWX_REBOOT: 1435 wlxAction = WLX_SAS_ACTION_SHUTDOWN_REBOOT; 1436 break; 1437 case EWX_POWEROFF: 1438 wlxAction = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF; 1439 break; 1440 1441 default: 1442 { 1443 ERR("Invalid ExitWindows action 0x%x\n", Action); 1444 return STATUS_INVALID_PARAMETER; 1445 } 1446 } 1447 1448 TRACE("In LN_LOGOFF, exit_in_progress == %s\n", 1449 ExitReactOSInProgress ? "true" : "false"); 1450 1451 /* 1452 * In case a parallel shutdown request is done (while we are 1453 * being to shut down) and it was not done by Winlogon itself, 1454 * then just stop here. 1455 */ 1456 #if 0 1457 // This code is commented at the moment (even if it's correct) because 1458 // our log-offs do not really work: the shell is restarted, no app is killed 1459 // etc... and as a result you just get explorer opening "My Documents". And 1460 // if you try now a shut down, it won't work because winlogon thinks it is 1461 // still in the middle of a shutdown. 1462 // Maybe we also need to reset ExitReactOSInProgress somewhere else?? 1463 if (ExitReactOSInProgress && (lParam & EWX_CALLER_WINLOGON) == 0) 1464 { 1465 break; 1466 } 1467 #endif 1468 /* Now do the shutdown action proper */ 1469 DoGenericAction(Session, wlxAction); 1470 return 1; 1471 } 1472 case LN_LOGOFF_CANCELED: 1473 { 1474 ERR("Logoff canceled!!, before: exit_in_progress == %s, after will be false\n", 1475 ExitReactOSInProgress ? "true" : "false"); 1476 1477 ExitReactOSInProgress = FALSE; 1478 return 1; 1479 } 1480 default: 1481 { 1482 ERR("WM_LOGONNOTIFY case %d is unimplemented\n", wParam); 1483 } 1484 } 1485 return 0; 1486 } 1487 case WM_TIMER: 1488 { 1489 if (wParam == 1) 1490 { 1491 KillTimer(hwndDlg, 1); 1492 StartUserShell(Session); 1493 } 1494 break; 1495 } 1496 case WLX_WM_SAS: 1497 { 1498 DispatchSAS(Session, (DWORD)wParam); 1499 return TRUE; 1500 } 1501 } 1502 1503 return DefWindowProc(hwndDlg, uMsg, wParam, lParam); 1504 } 1505 1506 BOOL 1507 InitializeSAS( 1508 IN OUT PWLSESSION Session) 1509 { 1510 WNDCLASSEXW swc; 1511 BOOL ret = FALSE; 1512 1513 if (!SwitchDesktop(Session->WinlogonDesktop)) 1514 { 1515 ERR("WL: Failed to switch to winlogon desktop\n"); 1516 goto cleanup; 1517 } 1518 1519 /* Register SAS window class */ 1520 swc.cbSize = sizeof(WNDCLASSEXW); 1521 swc.style = CS_SAVEBITS; 1522 swc.lpfnWndProc = SASWindowProc; 1523 swc.cbClsExtra = 0; 1524 swc.cbWndExtra = 0; 1525 swc.hInstance = hAppInstance; 1526 swc.hIcon = NULL; 1527 swc.hCursor = NULL; 1528 swc.hbrBackground = NULL; 1529 swc.lpszMenuName = NULL; 1530 swc.lpszClassName = WINLOGON_SAS_CLASS; 1531 swc.hIconSm = NULL; 1532 if (RegisterClassExW(&swc) == 0) 1533 { 1534 ERR("WL: Failed to register SAS window class\n"); 1535 goto cleanup; 1536 } 1537 1538 /* Create invisible SAS window */ 1539 Session->SASWindow = CreateWindowExW( 1540 0, 1541 WINLOGON_SAS_CLASS, 1542 WINLOGON_SAS_TITLE, 1543 WS_POPUP, 1544 0, 0, 0, 0, 0, 0, 1545 hAppInstance, Session); 1546 if (!Session->SASWindow) 1547 { 1548 ERR("WL: Failed to create SAS window\n"); 1549 goto cleanup; 1550 } 1551 1552 /* Register SAS window to receive SAS notifications */ 1553 if (!SetLogonNotifyWindow(Session->SASWindow)) 1554 { 1555 ERR("WL: Failed to register SAS window\n"); 1556 goto cleanup; 1557 } 1558 1559 if (!SetDefaultLanguage(NULL)) 1560 return FALSE; 1561 1562 ret = TRUE; 1563 1564 cleanup: 1565 if (!ret) 1566 UninitializeSAS(Session); 1567 return ret; 1568 } 1569