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)
12 /* INCLUDES *****************************************************************/
16 #include <wine/debug.h>
18 WINE_DEFAULT_DEBUG_CHANNEL(winlogon
);
20 /* GLOBALS ******************************************************************/
22 #define WINLOGON_SAS_CLASS L"SAS Window class"
23 #define WINLOGON_SAS_TITLE L"SAS window"
25 #define HK_CTRL_ALT_DEL 0
26 #define HK_CTRL_SHIFT_ESC 1
28 extern BOOL WINAPI
SetLogonNotifyWindow(HWND Wnd
, HWINSTA WinSta
);
30 /* FUNCTIONS ****************************************************************/
34 IN OUT PWLSESSION Session
)
39 if (!Session
->Gina
.Functions
.WlxStartApplication
)
42 if (!CreateEnvironmentBlock(
50 ret
= Session
->Gina
.Functions
.WlxStartApplication(
51 Session
->Gina
.Context
,
56 DestroyEnvironmentBlock(lpEnvironment
);
71 UNICODE_STRING ValueString
;
78 BaseKey
= HKEY_CURRENT_USER
;
79 SubKey
= L
"Control Panel\\International";
80 ValueName
= L
"Locale";
84 BaseKey
= HKEY_LOCAL_MACHINE
;
85 SubKey
= L
"System\\CurrentControlSet\\Control\\Nls\\Language";
86 ValueName
= L
"Default";
95 if (rc
!= ERROR_SUCCESS
)
97 TRACE("RegOpenKeyEx() failed with error %lu\n", rc
);
100 rc
= RegQueryValueExW(
107 if (rc
!= ERROR_SUCCESS
)
109 TRACE("RegQueryValueEx() failed with error %lu\n", rc
);
112 else if (dwType
!= REG_SZ
)
114 TRACE("Wrong type for %S\\%S registry entry (got 0x%lx, expected 0x%x)\n",
115 SubKey
, ValueName
, dwType
, REG_SZ
);
119 Value
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
122 TRACE("HeapAlloc() failed\n");
125 rc
= RegQueryValueExW(
132 if (rc
!= ERROR_SUCCESS
)
134 TRACE("RegQueryValueEx() failed with error %lu\n", rc
);
138 /* Convert Value to a Lcid */
139 ValueString
.Length
= ValueString
.MaximumLength
= (USHORT
)dwSize
;
140 ValueString
.Buffer
= Value
;
141 Status
= RtlUnicodeStringToInteger(&ValueString
, 16, (PULONG
)&Lcid
);
142 if (!NT_SUCCESS(Status
))
144 TRACE("RtlUnicodeStringToInteger() failed with status 0x%08lx\n", Status
);
148 TRACE("%s language is 0x%08lx\n",
149 UserProfile
? "User" : "System", Lcid
);
150 Status
= NtSetDefaultLocale(UserProfile
, Lcid
);
151 if (!NT_SUCCESS(Status
))
153 TRACE("NtSetDefaultLocale() failed with status 0x%08lx\n", Status
);
163 HeapFree(GetProcessHeap(), 0, Value
);
169 IN OUT PWLSESSION Session
)
171 PROFILEINFOW ProfileInfo
;
172 LPVOID lpEnvironment
= NULL
;
176 /* Loading personal settings */
177 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_LOADINGYOURPERSONALSETTINGS
);
178 ProfileInfo
.hProfile
= INVALID_HANDLE_VALUE
;
179 if (0 == (Session
->Options
& WLX_LOGON_OPT_NO_PROFILE
))
181 if (Session
->Profile
== NULL
182 || (Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V1_0
183 && Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V2_0
))
185 ERR("WL: Wrong profile\n");
189 /* Load the user profile */
190 ZeroMemory(&ProfileInfo
, sizeof(PROFILEINFOW
));
191 ProfileInfo
.dwSize
= sizeof(PROFILEINFOW
);
192 ProfileInfo
.dwFlags
= 0;
193 ProfileInfo
.lpUserName
= Session
->MprNotifyInfo
.pszUserName
;
194 ProfileInfo
.lpProfilePath
= Session
->Profile
->pszProfile
;
195 if (Session
->Profile
->dwType
>= WLX_PROFILE_TYPE_V2_0
)
197 ProfileInfo
.lpDefaultPath
= Session
->Profile
->pszNetworkDefaultUserProfile
;
198 ProfileInfo
.lpServerName
= Session
->Profile
->pszServerName
;
199 ProfileInfo
.lpPolicyPath
= Session
->Profile
->pszPolicy
;
202 if (!LoadUserProfileW(Session
->UserToken
, &ProfileInfo
))
204 ERR("WL: LoadUserProfileW() failed\n");
209 /* Create environment block for the user */
210 if (!CreateEnvironmentBlock(
215 WARN("WL: CreateEnvironmentBlock() failed\n");
218 /* FIXME: Append variables of Session->Profile->pszEnvironment */
220 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_APPLYINGYOURPERSONALSETTINGS
);
221 UpdatePerUserSystemParameters(0, TRUE
);
223 /* Set default language */
224 if (!SetDefaultLanguage(TRUE
))
226 WARN("WL: SetDefaultLanguage() failed\n");
231 /* FIXME: who should do it? winlogon or gina? */
232 /* FIXME: reverting to lower privileges after creating user shell? */
233 RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
235 if (!Session
->Gina
.Functions
.WlxActivateUserShell(
236 Session
->Gina
.Context
,
241 //WCHAR StatusMsg[256];
242 WARN("WL: WlxActivateUserShell() failed\n");
243 //LoadStringW(hAppInstance, IDS_FAILEDACTIVATEUSERSHELL, StatusMsg, sizeof(StatusMsg));
244 //MessageBoxW(0, StatusMsg, NULL, MB_ICONERROR);
248 if (!InitializeScreenSaver(Session
))
249 WARN("WL: Failed to initialize screen saver\n");
251 Session
->hProfileInfo
= ProfileInfo
.hProfile
;
255 if (Session
->Profile
)
257 HeapFree(GetProcessHeap(), 0, Session
->Profile
->pszProfile
);
258 HeapFree(GetProcessHeap(), 0, Session
->Profile
);
260 Session
->Profile
= NULL
;
262 && ProfileInfo
.hProfile
!= INVALID_HANDLE_VALUE
)
264 UnloadUserProfile(WLSession
->UserToken
, ProfileInfo
.hProfile
);
267 DestroyEnvironmentBlock(lpEnvironment
);
268 RemoveStatusMessage(Session
);
271 CloseHandle(Session
->UserToken
);
272 Session
->UserToken
= NULL
;
277 #define EWX_ACTION_MASK 0xffffffeb
278 #define EWX_FLAGS_MASK 0x00000014
280 typedef struct tagLOGOFF_SHUTDOWN_DATA
284 } LOGOFF_SHUTDOWN_DATA
, *PLOGOFF_SHUTDOWN_DATA
;
287 LogoffShutdownThread(LPVOID Parameter
)
289 PLOGOFF_SHUTDOWN_DATA LSData
= (PLOGOFF_SHUTDOWN_DATA
)Parameter
;
291 if (LSData
->Session
->UserToken
!= NULL
&& !ImpersonateLoggedOnUser(LSData
->Session
->UserToken
))
293 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
297 /* Close processes of the interactive user */
299 EWX_INTERNAL_KILL_USER_APPS
| (LSData
->Flags
& EWX_FLAGS_MASK
) |
300 (EWX_LOGOFF
== (LSData
->Flags
& EWX_ACTION_MASK
) ? EWX_INTERNAL_FLAG_LOGOFF
: 0),
303 ERR("Unable to kill user apps, error %lu\n", GetLastError());
308 /* FIXME: Call ExitWindowsEx() to terminate COM processes */
310 if (LSData
->Session
->UserToken
)
318 CreateLogoffSecurityAttributes(
319 OUT PSECURITY_ATTRIBUTES
* ppsa
)
321 /* The following code is not working yet and messy */
322 /* Still, it gives some ideas about data types and functions involved and */
323 /* required to set up a SECURITY_DESCRIPTOR for a SECURITY_ATTRIBUTES */
324 /* instance for a thread, to allow that thread to ImpersonateLoggedOnUser(). */
325 /* Specifically THREAD_SET_THREAD_TOKEN is required. */
326 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
327 PSECURITY_ATTRIBUTES psa
= 0;
330 EXPLICIT_ACCESS Access
;
331 PSID pEveryoneSID
= NULL
;
332 static SID_IDENTIFIER_AUTHORITY WorldAuthority
= { SECURITY_WORLD_SID_AUTHORITY
};
336 // Let's first try to enumerate what kind of data we need for this to ever work:
337 // 1. The Winlogon SID, to be able to give it THREAD_SET_THREAD_TOKEN.
338 // 2. The users SID (the user trying to logoff, or rather shut down the system).
339 // 3. At least two EXPLICIT_ACCESS instances:
340 // 3.1 One for Winlogon itself, giving it the rights
341 // required to THREAD_SET_THREAD_TOKEN (as it's needed to successfully call
342 // ImpersonateLoggedOnUser).
343 // 3.2 One for the user, to allow *that* thread to perform its work.
344 // 4. An ACL to hold the these EXPLICIT_ACCESS ACE's.
345 // 5. A SECURITY_DESCRIPTOR to hold the ACL, and finally.
346 // 6. A SECURITY_ATTRIBUTES instance to pull all of this required stuff
347 // together, to hand it to CreateThread.
349 // However, it seems struct LOGOFF_SHUTDOWN_DATA doesn't contain
350 // these required SID's, why they'd have to be added.
351 // The Winlogon's own SID should probably only be created once,
352 // while the user's SID obviously must be created for each new user.
353 // Might as well store it when the user logs on?
355 if(!AllocateAndInitializeSid(&WorldAuthority
,
361 ERR("Failed to initialize security descriptor for logoff thread!\n");
362 return STATUS_UNSUCCESSFUL
;
365 /* set up the required security attributes to be able to shut down */
366 /* To save space and time, allocate a single block of memory holding */
367 /* both SECURITY_ATTRIBUTES and SECURITY_DESCRIPTOR */
368 pMem
= HeapAlloc(GetProcessHeap(),
370 sizeof(SECURITY_ATTRIBUTES
) +
371 SECURITY_DESCRIPTOR_MIN_LENGTH
+
375 ERR("Failed to allocate memory for logoff security descriptor!\n");
376 return STATUS_NO_MEMORY
;
379 /* Note that the security descriptor needs to be in _absolute_ format, */
380 /* meaning its members must be pointers to other structures, rather */
381 /* than the relative format using offsets */
382 psa
= (PSECURITY_ATTRIBUTES
)pMem
;
383 SecurityDescriptor
= (PSECURITY_DESCRIPTOR
)(pMem
+ sizeof(SECURITY_ATTRIBUTES
));
384 pACL
= (PACL
)(((PBYTE
)SecurityDescriptor
) + SECURITY_DESCRIPTOR_MIN_LENGTH
);
386 // Initialize an EXPLICIT_ACCESS structure for an ACE.
387 // The ACE will allow this thread to log off (and shut down the system, currently).
388 ZeroMemory(&Access
, sizeof(Access
));
389 Access
.grfAccessPermissions
= THREAD_SET_THREAD_TOKEN
;
390 Access
.grfAccessMode
= SET_ACCESS
; // GRANT_ACCESS?
391 Access
.grfInheritance
= NO_INHERITANCE
;
392 Access
.Trustee
.TrusteeForm
= TRUSTEE_IS_SID
;
393 Access
.Trustee
.TrusteeType
= TRUSTEE_IS_WELL_KNOWN_GROUP
;
394 Access
.Trustee
.ptstrName
= pEveryoneSID
;
396 if (SetEntriesInAcl(1, &Access
, NULL
, &pACL
) != ERROR_SUCCESS
)
398 ERR("Failed to set Access Rights for logoff thread. Logging out will most likely fail.\n");
400 HeapFree(GetProcessHeap(), 0, pMem
);
401 return STATUS_UNSUCCESSFUL
;
404 if (!InitializeSecurityDescriptor(SecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
))
406 ERR("Failed to initialize security descriptor for logoff thread!\n");
407 HeapFree(GetProcessHeap(), 0, pMem
);
408 return STATUS_UNSUCCESSFUL
;
411 if (!SetSecurityDescriptorDacl(SecurityDescriptor
,
412 TRUE
, // bDaclPresent flag
414 FALSE
)) // not a default DACL
416 ERR("SetSecurityDescriptorDacl Error %lu\n", GetLastError());
417 HeapFree(GetProcessHeap(), 0, pMem
);
418 return STATUS_UNSUCCESSFUL
;
421 psa
->nLength
= sizeof(SECURITY_ATTRIBUTES
);
422 psa
->lpSecurityDescriptor
= SecurityDescriptor
;
423 psa
->bInheritHandle
= FALSE
;
427 return STATUS_SUCCESS
;
431 DestroyLogoffSecurityAttributes(
432 IN PSECURITY_ATTRIBUTES psa
)
436 HeapFree(GetProcessHeap(), 0, psa
);
443 IN OUT PWLSESSION Session
,
446 PLOGOFF_SHUTDOWN_DATA LSData
;
447 PSECURITY_ATTRIBUTES psa
;
452 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_SAVEYOURSETTINGS
);
454 /* Prepare data for logoff thread */
455 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
458 ERR("Failed to allocate mem for thread data\n");
459 return STATUS_NO_MEMORY
;
461 LSData
->Flags
= Flags
;
462 LSData
->Session
= Session
;
464 Status
= CreateLogoffSecurityAttributes(&psa
);
465 if (!NT_SUCCESS(Status
))
467 ERR("Failed to create a required security descriptor. Status 0x%08lx\n", Status
);
468 HeapFree(GetProcessHeap(), 0, LSData
);
472 /* Run logoff thread */
473 hThread
= CreateThread(psa
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
475 /* we're done with the SECURITY_DESCRIPTOR */
476 DestroyLogoffSecurityAttributes(psa
);
481 ERR("Unable to create logoff thread, error %lu\n", GetLastError());
482 HeapFree(GetProcessHeap(), 0, LSData
);
483 return STATUS_UNSUCCESSFUL
;
485 WaitForSingleObject(hThread
, INFINITE
);
486 HeapFree(GetProcessHeap(), 0, LSData
);
487 if (!GetExitCodeThread(hThread
, &exitCode
))
489 ERR("Unable to get exit code of logoff thread (error %lu)\n", GetLastError());
490 CloseHandle(hThread
);
491 return STATUS_UNSUCCESSFUL
;
493 CloseHandle(hThread
);
496 ERR("Logoff thread returned failure\n");
497 return STATUS_UNSUCCESSFUL
;
500 UnloadUserProfile(Session
->UserToken
, Session
->hProfileInfo
);
501 CloseHandle(Session
->UserToken
);
502 UpdatePerUserSystemParameters(0, FALSE
);
503 Session
->LogonStatus
= WKSTA_IS_LOGGED_OFF
;
504 Session
->UserToken
= NULL
;
505 return STATUS_SUCCESS
;
509 ShutdownComputerWindowProc(
515 UNREFERENCED_PARAMETER(lParam
);
521 switch (LOWORD(wParam
))
523 case IDC_BTNSHTDOWNCOMPUTER
:
524 EndDialog(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
);
531 RemoveMenu(GetSystemMenu(hwndDlg
, FALSE
), SC_CLOSE
, MF_BYCOMMAND
);
532 SetFocus(GetDlgItem(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
));
541 IN OUT PWLSESSION Session
)
543 if (Session
->SASWindow
)
545 DestroyWindow(Session
->SASWindow
);
546 Session
->SASWindow
= NULL
;
548 if (Session
->hEndOfScreenSaverThread
)
549 SetEvent(Session
->hEndOfScreenSaverThread
);
550 UnregisterClassW(WINLOGON_SAS_CLASS
, hAppInstance
);
555 IN OUT PWLSESSION Session
,
558 PLOGOFF_SHUTDOWN_DATA LSData
;
562 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_REACTOSISSHUTTINGDOWN
);
564 /* Prepare data for shutdown thread */
565 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
568 ERR("Failed to allocate mem for thread data\n");
569 return STATUS_NO_MEMORY
;
571 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
)
572 LSData
->Flags
= EWX_POWEROFF
;
573 else if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
574 LSData
->Flags
= EWX_REBOOT
;
576 LSData
->Flags
= EWX_SHUTDOWN
;
577 LSData
->Session
= Session
;
579 /* Run shutdown thread */
580 hThread
= CreateThread(NULL
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
583 ERR("Unable to create shutdown thread, error %lu\n", GetLastError());
584 HeapFree(GetProcessHeap(), 0, LSData
);
585 return STATUS_UNSUCCESSFUL
;
587 WaitForSingleObject(hThread
, INFINITE
);
588 HeapFree(GetProcessHeap(), 0, LSData
);
589 if (!GetExitCodeThread(hThread
, &exitCode
))
591 ERR("Unable to get exit code of shutdown thread (error %lu)\n", GetLastError());
592 CloseHandle(hThread
);
593 return STATUS_UNSUCCESSFUL
;
595 CloseHandle(hThread
);
598 ERR("Shutdown thread returned failure\n");
599 return STATUS_UNSUCCESSFUL
;
602 /* Destroy SAS window */
603 UninitializeSAS(Session
);
605 FIXME("FIXME: Call SMSS API #1\n");
606 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
607 NtShutdownSystem(ShutdownReboot
);
612 /* FIXME - only show this dialog if it's a shutdown and the computer doesn't support APM */
613 DialogBox(hAppInstance
, MAKEINTRESOURCE(IDD_SHUTDOWNCOMPUTER
), GetDesktopWindow(), ShutdownComputerWindowProc
);
615 NtShutdownSystem(ShutdownNoReboot
);
617 return STATUS_SUCCESS
;
622 IN OUT PWLSESSION Session
,
627 case WLX_SAS_ACTION_LOGON
: /* 0x01 */
628 if (HandleLogon(Session
))
630 SwitchDesktop(Session
->ApplicationDesktop
);
631 Session
->LogonStatus
= WKSTA_IS_LOGGED_ON
;
634 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
636 case WLX_SAS_ACTION_NONE
: /* 0x02 */
638 case WLX_SAS_ACTION_LOCK_WKSTA
: /* 0x03 */
639 if (Session
->Gina
.Functions
.WlxIsLockOk(Session
->Gina
.Context
))
641 SwitchDesktop(WLSession
->WinlogonDesktop
);
642 Session
->LogonStatus
= WKSTA_IS_LOCKED
;
643 Session
->Gina
.Functions
.WlxDisplayLockedNotice(Session
->Gina
.Context
);
646 case WLX_SAS_ACTION_LOGOFF
: /* 0x04 */
647 case WLX_SAS_ACTION_SHUTDOWN
: /* 0x05 */
648 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
: /* 0x0a */
649 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
: /* 0x0b */
650 if (Session
->LogonStatus
!= WKSTA_IS_LOGGED_OFF
)
652 if (!Session
->Gina
.Functions
.WlxIsLogoffOk(Session
->Gina
.Context
))
654 SwitchDesktop(WLSession
->WinlogonDesktop
);
655 Session
->Gina
.Functions
.WlxLogoff(Session
->Gina
.Context
);
656 if (!NT_SUCCESS(HandleLogoff(Session
, EWX_LOGOFF
)))
658 RemoveStatusMessage(Session
);
662 if (WLX_SHUTTINGDOWN(wlxAction
))
664 Session
->Gina
.Functions
.WlxShutdown(Session
->Gina
.Context
, wlxAction
);
665 if (!NT_SUCCESS(HandleShutdown(Session
, wlxAction
)))
667 RemoveStatusMessage(Session
);
668 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
673 RemoveStatusMessage(Session
);
674 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
677 case WLX_SAS_ACTION_TASKLIST
: /* 0x07 */
678 SwitchDesktop(WLSession
->ApplicationDesktop
);
679 StartTaskManager(Session
);
681 case WLX_SAS_ACTION_UNLOCK_WKSTA
: /* 0x08 */
682 SwitchDesktop(WLSession
->ApplicationDesktop
);
683 Session
->LogonStatus
= WKSTA_IS_LOGGED_ON
;
686 WARN("Unknown SAS action 0x%lx\n", wlxAction
);
692 IN OUT PWLSESSION Session
,
695 DWORD wlxAction
= WLX_SAS_ACTION_NONE
;
697 if (Session
->LogonStatus
== WKSTA_IS_LOGGED_ON
)
698 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOnSAS(Session
->Gina
.Context
, dwSasType
, NULL
);
699 else if (Session
->LogonStatus
== WKSTA_IS_LOCKED
)
700 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxWkstaLockedSAS(Session
->Gina
.Context
, dwSasType
);
703 /* Display a new dialog (if necessary) */
706 case WLX_SAS_TYPE_TIMEOUT
: /* 0x00 */
708 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
713 PSID LogonSid
= NULL
; /* FIXME */
715 Session
->Options
= 0;
717 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOutSAS(
718 Session
->Gina
.Context
,
724 &Session
->MprNotifyInfo
,
725 (PVOID
*)&Session
->Profile
);
731 if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_TIMEOUT
)
734 if (!Session
->Gina
.Functions
.WlxScreenSaverNotify(Session
->Gina
.Context
, &bSecure
))
736 /* Skip start of screen saver */
737 SetEvent(Session
->hEndOfScreenSaver
);
742 DoGenericAction(Session
, WLX_SAS_ACTION_LOCK_WKSTA
);
743 StartScreenSaver(Session
);
746 else if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_ACTIVITY
)
747 SetEvent(Session
->hUserActivity
);
749 DoGenericAction(Session
, wlxAction
);
754 IN PWLSESSION Session
,
757 /* Register Ctrl+Alt+Del Hotkey */
758 if (!RegisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
, MOD_CONTROL
| MOD_ALT
, VK_DELETE
))
760 ERR("WL: Unable to register Ctrl+Alt+Del hotkey!\n");
764 /* Register Ctrl+Shift+Esc (optional) */
765 Session
->TaskManHotkey
= RegisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
, MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
);
766 if (!Session
->TaskManHotkey
)
767 WARN("WL: Warning: Unable to register Ctrl+Alt+Esc hotkey!\n");
773 IN PWLSESSION Session
,
776 /* Unregister hotkeys */
777 UnregisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
);
779 if (Session
->TaskManHotkey
)
780 UnregisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
);
786 CheckForShutdownPrivilege(
787 IN DWORD RequestingProcessId
)
792 PPRIVILEGE_SET PrivSet
;
794 TRACE("CheckForShutdownPrivilege()\n");
796 Process
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, RequestingProcessId
);
799 WARN("OpenProcess() failed with error %lu\n", GetLastError());
800 return STATUS_INVALID_HANDLE
;
802 if (!OpenProcessToken(Process
, TOKEN_QUERY
, &Token
))
804 WARN("OpenProcessToken() failed with error %lu\n", GetLastError());
805 CloseHandle(Process
);
806 return STATUS_INVALID_HANDLE
;
808 CloseHandle(Process
);
809 PrivSet
= HeapAlloc(GetProcessHeap(), 0, sizeof(PRIVILEGE_SET
) + sizeof(LUID_AND_ATTRIBUTES
));
812 ERR("Failed to allocate mem for privilege set\n");
814 return STATUS_NO_MEMORY
;
816 PrivSet
->PrivilegeCount
= 1;
817 PrivSet
->Control
= PRIVILEGE_SET_ALL_NECESSARY
;
818 if (!LookupPrivilegeValue(NULL
, SE_SHUTDOWN_NAME
, &PrivSet
->Privilege
[0].Luid
))
820 WARN("LookupPrivilegeValue() failed with error %lu\n", GetLastError());
821 HeapFree(GetProcessHeap(), 0, PrivSet
);
823 return STATUS_UNSUCCESSFUL
;
825 if (!PrivilegeCheck(Token
, PrivSet
, &CheckResult
))
827 WARN("PrivilegeCheck() failed with error %lu\n", GetLastError());
828 HeapFree(GetProcessHeap(), 0, PrivSet
);
830 return STATUS_ACCESS_DENIED
;
832 HeapFree(GetProcessHeap(), 0, PrivSet
);
837 WARN("SE_SHUTDOWN privilege not enabled\n");
838 return STATUS_ACCESS_DENIED
;
840 return STATUS_SUCCESS
;
843 static LRESULT CALLBACK
850 PWLSESSION Session
= (PWLSESSION
)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
858 case MAKELONG(MOD_CONTROL
| MOD_ALT
, VK_DELETE
):
860 TRACE("SAS: CONTROL+ALT+DELETE\n");
861 if (!Session
->Gina
.UseCtrlAltDelete
)
863 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_CTRL_ALT_DEL
, 0);
866 case MAKELONG(MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
):
868 TRACE("SAS: CONTROL+SHIFT+ESCAPE\n");
869 DoGenericAction(Session
, WLX_SAS_ACTION_TASKLIST
);
877 /* Get the session pointer from the create data */
878 Session
= (PWLSESSION
)((LPCREATESTRUCT
)lParam
)->lpCreateParams
;
880 /* Save the Session pointer */
881 SetWindowLongPtrW(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)Session
);
884 return RegisterHotKeys(Session
, hwndDlg
);
889 UnregisterHotKeys(Session
, hwndDlg
);
892 case WM_SETTINGCHANGE
:
894 UINT uiAction
= (UINT
)wParam
;
895 if (uiAction
== SPI_SETSCREENSAVETIMEOUT
896 || uiAction
== SPI_SETSCREENSAVEACTIVE
)
898 SetEvent(Session
->hScreenSaverParametersChanged
);
904 DispatchSAS(Session
, (DWORD
)wParam
);
907 case PM_WINLOGON_EXITWINDOWS
:
909 UINT Flags
= (UINT
)lParam
;
910 UINT Action
= Flags
& EWX_ACTION_MASK
;
913 /* Check parameters */
916 case EWX_LOGOFF
: wlxAction
= WLX_SAS_ACTION_LOGOFF
; break;
917 case EWX_SHUTDOWN
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN
; break;
918 case EWX_REBOOT
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_REBOOT
; break;
919 case EWX_POWEROFF
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
; break;
922 ERR("Invalid ExitWindows action 0x%x\n", Action
);
923 return STATUS_INVALID_PARAMETER
;
927 if (WLX_SHUTTINGDOWN(wlxAction
))
929 NTSTATUS Status
= CheckForShutdownPrivilege((DWORD
)wParam
);
930 if (!NT_SUCCESS(Status
))
933 DoGenericAction(Session
, wlxAction
);
938 return DefWindowProc(hwndDlg
, uMsg
, wParam
, lParam
);
943 IN OUT PWLSESSION Session
)
948 if (!SwitchDesktop(Session
->WinlogonDesktop
))
950 ERR("WL: Failed to switch to winlogon desktop\n");
954 /* Register SAS window class */
955 swc
.cbSize
= sizeof(WNDCLASSEXW
);
956 swc
.style
= CS_SAVEBITS
;
957 swc
.lpfnWndProc
= SASWindowProc
;
960 swc
.hInstance
= hAppInstance
;
963 swc
.hbrBackground
= NULL
;
964 swc
.lpszMenuName
= NULL
;
965 swc
.lpszClassName
= WINLOGON_SAS_CLASS
;
967 if (RegisterClassExW(&swc
) == 0)
969 ERR("WL: Failed to register SAS window class\n");
973 /* Create invisible SAS window */
974 Session
->SASWindow
= CreateWindowExW(
980 hAppInstance
, Session
);
981 if (!Session
->SASWindow
)
983 ERR("WL: Failed to create SAS window\n");
987 /* Register SAS window to receive SAS notifications */
988 if (!SetLogonNotifyWindow(Session
->SASWindow
, Session
->InteractiveWindowStation
))
990 ERR("WL: Failed to register SAS window\n");
994 if (!SetDefaultLanguage(FALSE
))
1001 UninitializeSAS(Session
);