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