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 *****************************************************************/
17 #include <wine/debug.h>
19 WINE_DEFAULT_DEBUG_CHANNEL(winlogon
);
21 /* GLOBALS ******************************************************************/
23 #define WINLOGON_SAS_CLASS L"SAS Window class"
24 #define WINLOGON_SAS_TITLE L"SAS window"
26 #define HK_CTRL_ALT_DEL 0
27 #define HK_CTRL_SHIFT_ESC 1
30 extern BOOL STDCALL
SetLogonNotifyWindow(HWND Wnd
, HWINSTA WinSta
);
33 /* FUNCTIONS ****************************************************************/
37 IN OUT PWLSESSION Session
)
42 if (!Session
->Gina
.Functions
.WlxStartApplication
)
45 if (!CreateEnvironmentBlock(
53 ret
= Session
->Gina
.Functions
.WlxStartApplication(
54 Session
->Gina
.Context
,
59 DestroyEnvironmentBlock(lpEnvironment
);
74 UNICODE_STRING ValueString
;
81 BaseKey
= HKEY_CURRENT_USER
;
82 SubKey
= L
"Control Panel\\International";
83 ValueName
= L
"Locale";
87 BaseKey
= HKEY_LOCAL_MACHINE
;
88 SubKey
= L
"System\\CurrentControlSet\\Control\\Nls\\Language";
89 ValueName
= L
"Default";
98 if (rc
!= ERROR_SUCCESS
)
100 TRACE("RegOpenKeyEx() failed with error %lu\n", rc
);
103 rc
= RegQueryValueExW(
110 if (rc
!= ERROR_SUCCESS
)
112 TRACE("RegQueryValueEx() failed with error %lu\n", rc
);
115 else if (dwType
!= REG_SZ
)
117 TRACE("Wrong type for %S\\%S registry entry (got 0x%lx, expected 0x%lx)\n",
118 SubKey
, ValueName
, dwType
, REG_SZ
);
122 Value
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
125 TRACE("HeapAlloc() failed\n");
128 rc
= RegQueryValueExW(
135 if (rc
!= ERROR_SUCCESS
)
137 TRACE("RegQueryValueEx() failed with error %lu\n", rc
);
141 /* Convert Value to a Lcid */
142 ValueString
.Length
= ValueString
.MaximumLength
= (USHORT
)dwSize
;
143 ValueString
.Buffer
= Value
;
144 Status
= RtlUnicodeStringToInteger(&ValueString
, 16, (PULONG
)&Lcid
);
145 if (!NT_SUCCESS(Status
))
147 TRACE("RtlUnicodeStringToInteger() failed with status 0x%08lx\n", Status
);
151 TRACE("%s language is 0x%08lx\n",
152 UserProfile
? "User" : "System", Lcid
);
153 Status
= NtSetDefaultLocale(UserProfile
, Lcid
);
154 if (!NT_SUCCESS(Status
))
156 TRACE("NtSetDefaultLocale() failed with status 0x%08lx\n", Status
);
166 HeapFree(GetProcessHeap(), 0, Value
);
172 IN OUT PWLSESSION Session
)
174 PROFILEINFOW ProfileInfo
;
175 LPVOID lpEnvironment
= NULL
;
179 /* Loading personal settings */
180 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_LOADINGYOURPERSONALSETTINGS
);
181 ProfileInfo
.hProfile
= INVALID_HANDLE_VALUE
;
182 if (0 == (Session
->Options
& WLX_LOGON_OPT_NO_PROFILE
))
184 if (Session
->Profile
== NULL
185 || (Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V1_0
186 && Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V2_0
))
188 ERR("WL: Wrong profile\n");
192 /* Load the user profile */
193 ZeroMemory(&ProfileInfo
, sizeof(PROFILEINFOW
));
194 ProfileInfo
.dwSize
= sizeof(PROFILEINFOW
);
195 ProfileInfo
.dwFlags
= 0;
196 ProfileInfo
.lpUserName
= Session
->MprNotifyInfo
.pszUserName
;
197 ProfileInfo
.lpProfilePath
= Session
->Profile
->pszProfile
;
198 if (Session
->Profile
->dwType
>= WLX_PROFILE_TYPE_V2_0
)
200 ProfileInfo
.lpDefaultPath
= Session
->Profile
->pszNetworkDefaultUserProfile
;
201 ProfileInfo
.lpServerName
= Session
->Profile
->pszServerName
;
202 ProfileInfo
.lpPolicyPath
= Session
->Profile
->pszPolicy
;
205 if (!LoadUserProfileW(Session
->UserToken
, &ProfileInfo
))
207 ERR("WL: LoadUserProfileW() failed\n");
212 /* Create environment block for the user */
213 if (!CreateEnvironmentBlock(
218 WARN("WL: CreateEnvironmentBlock() failed\n");
221 /* FIXME: Append variables of Session->Profile->pszEnvironment */
223 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_APPLYINGYOURPERSONALSETTINGS
);
224 UpdatePerUserSystemParameters(0, TRUE
);
226 /* Set default language */
227 if (!SetDefaultLanguage(TRUE
))
229 WARN("WL: SetDefaultLanguage() failed\n");
234 /* FIXME: who should do it? winlogon or gina? */
235 /* FIXME: reverting to lower privileges after creating user shell? */
236 RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
238 if (!Session
->Gina
.Functions
.WlxActivateUserShell(
239 Session
->Gina
.Context
,
244 //WCHAR StatusMsg[256];
245 WARN("WL: WlxActivateUserShell() failed\n");
246 //LoadStringW(hAppInstance, IDS_FAILEDACTIVATEUSERSHELL, StatusMsg, sizeof(StatusMsg));
247 //MessageBoxW(0, StatusMsg, NULL, MB_ICONERROR);
251 if (!InitializeScreenSaver(Session
))
252 WARN("WL: Failed to initialize screen saver\n");
254 Session
->hProfileInfo
= ProfileInfo
.hProfile
;
258 if (Session
->Profile
)
260 HeapFree(GetProcessHeap(), 0, Session
->Profile
->pszProfile
);
261 HeapFree(GetProcessHeap(), 0, Session
->Profile
);
263 Session
->Profile
= NULL
;
265 && ProfileInfo
.hProfile
!= INVALID_HANDLE_VALUE
)
267 UnloadUserProfile(WLSession
->UserToken
, ProfileInfo
.hProfile
);
270 DestroyEnvironmentBlock(lpEnvironment
);
271 RemoveStatusMessage(Session
);
274 CloseHandle(Session
->UserToken
);
275 Session
->UserToken
= NULL
;
280 #define EWX_ACTION_MASK 0xffffffeb
281 #define EWX_FLAGS_MASK 0x00000014
283 typedef struct tagLOGOFF_SHUTDOWN_DATA
287 } LOGOFF_SHUTDOWN_DATA
, *PLOGOFF_SHUTDOWN_DATA
;
290 LogoffShutdownThread(LPVOID Parameter
)
292 PLOGOFF_SHUTDOWN_DATA LSData
= (PLOGOFF_SHUTDOWN_DATA
)Parameter
;
294 if (LSData
->Session
->UserToken
!= NULL
&& !ImpersonateLoggedOnUser(LSData
->Session
->UserToken
))
296 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
300 /* Close processes of the interactive user */
302 EWX_INTERNAL_KILL_USER_APPS
| (LSData
->Flags
& EWX_FLAGS_MASK
) |
303 (EWX_LOGOFF
== (LSData
->Flags
& EWX_ACTION_MASK
) ? EWX_INTERNAL_FLAG_LOGOFF
: 0),
306 ERR("Unable to kill user apps, error %lu\n", GetLastError());
311 /* FIXME: Call ExitWindowsEx() to terminate COM processes */
313 if (LSData
->Session
->UserToken
)
321 CreateLogoffSecurityAttributes(
322 OUT PSECURITY_ATTRIBUTES
* ppsa
)
325 DPRINT1("CreateLogoffSecurityAttributes needs implementation!\n");
327 return STATUS_UNSUCCESSFUL
;
329 /* The following code is no only incomplete, it's a mess and uncompilable */
330 /* Still, it gives some ideas about data types and functions involved and */
331 /* required to set up a SECURITY_DESCRIPTOR for a SECURITY_ATTRIBUTES */
332 /* instance for a thread, to allow that thread to ImpersonateLoggedOnUser(). */
333 /* Specifically THREAD_SET_THREAD_TOKEN is required. */
334 PSECURITY_DESCRIPTOR psd
= 0;
335 PSECURITY_ATTRIBUTES psa
= 0;
338 EXPLICIT_ACCESS ea
[2];
342 // Let's first try to enumerate what kind of data we need for this to ever work:
343 // 1. The Winlogon SID, to be able to give it THREAD_SET_THREAD_TOKEN.
344 // 2. The users SID (the user trying to logoff, or rather shut down the system).
345 // 3. At least two EXPLICIT_ACCESS instances:
346 // 3.1 One for Winlogon itself, giving it the rights
347 // required to THREAD_SET_THREAD_TOKEN (as it's needed to successfully call
348 // ImpersonateLoggedOnUser).
349 // 3.2 One for the user, to allow *that* thread to perform its work.
350 // 4. An ACL to hold the these EXPLICIT_ACCESS ACE's.
351 // 5. A SECURITY_DESCRIPTOR to hold the ACL, and finally.
352 // 6. A SECURITY_ATTRIBUTES instance to pull all of this required stuff
353 // together, to hand it to CreateThread.
355 // However, it seems struct LOGOFF_SHUTDOWN_DATA doesn't contain
356 // these required SID's, why they'd have to be added.
357 // The Winlogon's own SID should probably only be created once,
358 // while the user's SID obviously must be created for each new user.
359 // Might as well store it when the user logs on?
361 /* set up the required security attributes to be able to shut down */
362 /* To save space and time, allocate a single block of memory holding */
363 /* both SECURITY_ATTRIBUTES and SECURITY_DESCRIPTOR */
364 pMem
= HeapAlloc(GetProcessHeap(),
366 sizeof(SECURITY_ATTRIBUTES
) +
367 SECURITY_DESCRIPTOR_MIN_LENGTH
+
371 DPRINT("Failed to allocate memory for logoff security descriptor!\n");
372 return STATUS_NO_MEMORY
;
375 /* Note that the security descriptor needs to be in _absolute_ format, */
376 /* meaning its members must be pointers to other structures, rather */
377 /* than the relative format using offsets */
378 psa
= (PSECURITY_ATTRIBUTES
)pMem
;
379 psd
= (PSECURITY_DESCRIPTOR
)(pMem
+ sizeof(SECURITY_ATTRIBUTES
));
380 pACL
= (PACL
)(((PBYTE
)psd
) + SECURITY_DESCRIPTOR_MIN_LENGTH
);
382 if (!InitializeSecurityDescriptor(psd
, SECURITY_DESCRIPTOR_REVISION
))
384 HeapFree(GetProcessHeap(), 0, pMem
);
385 DPRINT("Failed to initialize security descriptor for logoff thread!\n");
386 return STATUS_UNSUCCESSFUL
;
389 // Initialize an EXPLICIT_ACCESS structure for an ACE.
390 // The ACE will allow this thread to log off (and shut down the system, currently).
391 ZeroMemory(ea
, sizeof(ea
));
392 ea
[0].grfAccessPermissions
= THREAD_SET_THREAD_TOKEN
;
393 ea
[0].grfAccessMode
= SET_ACCESS
; // GRANT_ACCESS?
394 ea
[0].grfInheritance
= NO_INHERITANCE
;
395 ea
[0].Trustee
.TrusteeForm
= TRUSTEE_IS_SID
;
396 ea
[0].Trustee
.TrusteeType
= TRUSTEE_IS_USER
;
397 ea
[0].Trustee
.ptstrName
= (LPTSTR
) pEveryoneSID
;
399 if (!SetSecurityDescriptorDacl(pSD
,
400 TRUE
, // bDaclPresent flag
402 FALSE
)) // not a default DACL
404 DPRINT("SetSecurityDescriptorDacl Error %u\n", GetLastError());
405 HeapFree(GetProcessHeap(), 0, pMem
);
406 return STATUS_UNSUCCESSFUL
;
409 psa
->nLength
= sizeof(sa
);
410 psa
->lpSecurityDescriptor
= psd
;
411 psa
->bInheritHandle
= FALSE
;
415 return STATUS_SUCCESS
;
420 DestroyLogoffSecurityAttributes(
421 IN PSECURITY_ATTRIBUTES psa
)
425 HeapFree(GetProcessHeap(), 0, psa
);
432 IN OUT PWLSESSION Session
,
435 PLOGOFF_SHUTDOWN_DATA LSData
;
436 PSECURITY_ATTRIBUTES psa
;
441 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_SAVEYOURSETTINGS
);
443 /* Prepare data for logoff thread */
444 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
447 ERR("Failed to allocate mem for thread data\n");
448 return STATUS_NO_MEMORY
;
450 LSData
->Flags
= Flags
;
451 LSData
->Session
= Session
;
453 Status
= CreateLogoffSecurityAttributes(&psa
);
454 if (!NT_SUCCESS(Status
))
456 DPRINT("Failed to create a required security descriptor. Error 0x%08x\n", Status
);
458 DPRINT("Attempting to continue without it.\n");
460 DPRINT("Aborting logoff\n");
461 HeapFree(GetProcessHeap(), 0, LSData
);
466 /* Run logoff thread */
467 hThread
= CreateThread(psa
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
469 /* we're done with the SECURITY_DESCRIPTOR */
470 DestroyLogoffSecurityAttributes(psa
);
475 ERR("Unable to create logoff thread, error %lu\n", GetLastError());
476 HeapFree(GetProcessHeap(), 0, LSData
);
477 return STATUS_UNSUCCESSFUL
;
479 WaitForSingleObject(hThread
, INFINITE
);
480 HeapFree(GetProcessHeap(), 0, LSData
);
481 if (!GetExitCodeThread(hThread
, &exitCode
))
483 ERR("Unable to get exit code of logoff thread (error %lu)\n", GetLastError());
484 CloseHandle(hThread
);
485 return STATUS_UNSUCCESSFUL
;
487 CloseHandle(hThread
);
490 ERR("Logoff thread returned failure\n");
491 return STATUS_UNSUCCESSFUL
;
494 UnloadUserProfile(Session
->UserToken
, Session
->hProfileInfo
);
495 CloseHandle(Session
->UserToken
);
496 UpdatePerUserSystemParameters(0, FALSE
);
497 Session
->LogonStatus
= WKSTA_IS_LOGGED_OFF
;
498 Session
->UserToken
= NULL
;
499 return STATUS_SUCCESS
;
503 ShutdownComputerWindowProc(
509 UNREFERENCED_PARAMETER(lParam
);
515 switch (LOWORD(wParam
))
517 case IDC_BTNSHTDOWNCOMPUTER
:
518 EndDialog(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
);
525 RemoveMenu(GetSystemMenu(hwndDlg
, FALSE
), SC_CLOSE
, MF_BYCOMMAND
);
526 SetFocus(GetDlgItem(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
));
535 IN OUT PWLSESSION Session
)
537 if (Session
->SASWindow
)
539 DestroyWindow(Session
->SASWindow
);
540 Session
->SASWindow
= NULL
;
542 if (Session
->hEndOfScreenSaverThread
)
543 SetEvent(Session
->hEndOfScreenSaverThread
);
544 UnregisterClassW(WINLOGON_SAS_CLASS
, hAppInstance
);
549 IN OUT PWLSESSION Session
,
552 PLOGOFF_SHUTDOWN_DATA LSData
;
556 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_REACTOSISSHUTTINGDOWN
);
558 /* Prepare data for shutdown thread */
559 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
562 ERR("Failed to allocate mem for thread data\n");
563 return STATUS_NO_MEMORY
;
565 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
)
566 LSData
->Flags
= EWX_POWEROFF
;
567 else if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
568 LSData
->Flags
= EWX_REBOOT
;
570 LSData
->Flags
= EWX_SHUTDOWN
;
571 LSData
->Session
= Session
;
573 /* Run shutdown thread */
574 hThread
= CreateThread(NULL
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
577 ERR("Unable to create shutdown thread, error %lu\n", GetLastError());
578 HeapFree(GetProcessHeap(), 0, LSData
);
579 return STATUS_UNSUCCESSFUL
;
581 WaitForSingleObject(hThread
, INFINITE
);
582 HeapFree(GetProcessHeap(), 0, LSData
);
583 if (!GetExitCodeThread(hThread
, &exitCode
))
585 ERR("Unable to get exit code of shutdown thread (error %lu)\n", GetLastError());
586 CloseHandle(hThread
);
587 return STATUS_UNSUCCESSFUL
;
589 CloseHandle(hThread
);
592 ERR("Shutdown thread returned failure\n");
593 return STATUS_UNSUCCESSFUL
;
596 /* Destroy SAS window */
597 UninitializeSAS(Session
);
599 FIXME("FIXME: Call SMSS API #1\n");
600 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
601 NtShutdownSystem(ShutdownReboot
);
606 /* FIXME - only show this dialog if it's a shutdown and the computer doesn't support APM */
607 DialogBox(hAppInstance
, MAKEINTRESOURCE(IDD_SHUTDOWNCOMPUTER
), GetDesktopWindow(), ShutdownComputerWindowProc
);
609 NtShutdownSystem(ShutdownNoReboot
);
611 return STATUS_SUCCESS
;
616 IN OUT PWLSESSION Session
,
621 case WLX_SAS_ACTION_LOGON
: /* 0x01 */
622 if (HandleLogon(Session
))
624 SwitchDesktop(Session
->ApplicationDesktop
);
625 Session
->LogonStatus
= WKSTA_IS_LOGGED_ON
;
628 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
630 case WLX_SAS_ACTION_NONE
: /* 0x02 */
632 case WLX_SAS_ACTION_LOCK_WKSTA
: /* 0x03 */
633 if (Session
->Gina
.Functions
.WlxIsLockOk(Session
->Gina
.Context
))
635 SwitchDesktop(WLSession
->WinlogonDesktop
);
636 Session
->LogonStatus
= WKSTA_IS_LOCKED
;
637 Session
->Gina
.Functions
.WlxDisplayLockedNotice(Session
->Gina
.Context
);
640 case WLX_SAS_ACTION_LOGOFF
: /* 0x04 */
641 case WLX_SAS_ACTION_SHUTDOWN
: /* 0x05 */
642 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
: /* 0x0a */
643 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
: /* 0x0b */
644 if (Session
->LogonStatus
!= WKSTA_IS_LOGGED_OFF
)
646 if (!Session
->Gina
.Functions
.WlxIsLogoffOk(Session
->Gina
.Context
))
648 SwitchDesktop(WLSession
->WinlogonDesktop
);
649 Session
->Gina
.Functions
.WlxLogoff(Session
->Gina
.Context
);
650 if (!NT_SUCCESS(HandleLogoff(Session
, EWX_LOGOFF
)))
652 RemoveStatusMessage(Session
);
656 if (WLX_SHUTTINGDOWN(wlxAction
))
658 Session
->Gina
.Functions
.WlxShutdown(Session
->Gina
.Context
, wlxAction
);
659 if (!NT_SUCCESS(HandleShutdown(Session
, wlxAction
)))
661 RemoveStatusMessage(Session
);
662 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
667 RemoveStatusMessage(Session
);
668 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
671 case WLX_SAS_ACTION_TASKLIST
: /* 0x07 */
672 SwitchDesktop(WLSession
->ApplicationDesktop
);
673 StartTaskManager(Session
);
675 case WLX_SAS_ACTION_UNLOCK_WKSTA
: /* 0x08 */
676 SwitchDesktop(WLSession
->ApplicationDesktop
);
677 Session
->LogonStatus
= WKSTA_IS_LOGGED_ON
;
680 WARN("Unknown SAS action 0x%lx\n", wlxAction
);
686 IN OUT PWLSESSION Session
,
689 DWORD wlxAction
= WLX_SAS_ACTION_NONE
;
691 if (Session
->LogonStatus
== WKSTA_IS_LOGGED_ON
)
692 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOnSAS(Session
->Gina
.Context
, dwSasType
, NULL
);
693 else if (Session
->LogonStatus
== WKSTA_IS_LOCKED
)
694 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxWkstaLockedSAS(Session
->Gina
.Context
, dwSasType
);
697 /* Display a new dialog (if necessary) */
700 case WLX_SAS_TYPE_TIMEOUT
: /* 0x00 */
702 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
707 PSID LogonSid
= NULL
; /* FIXME */
709 Session
->Options
= 0;
711 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOutSAS(
712 Session
->Gina
.Context
,
718 &Session
->MprNotifyInfo
,
719 (PVOID
*)&Session
->Profile
);
725 if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_TIMEOUT
)
728 if (!Session
->Gina
.Functions
.WlxScreenSaverNotify(Session
->Gina
.Context
, &bSecure
))
730 /* Skip start of screen saver */
731 SetEvent(Session
->hEndOfScreenSaver
);
736 DoGenericAction(Session
, WLX_SAS_ACTION_LOCK_WKSTA
);
737 StartScreenSaver(Session
);
740 else if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_ACTIVITY
)
741 SetEvent(Session
->hUserActivity
);
743 DoGenericAction(Session
, wlxAction
);
748 IN PWLSESSION Session
,
751 /* Register Ctrl+Alt+Del Hotkey */
752 if (!RegisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
, MOD_CONTROL
| MOD_ALT
, VK_DELETE
))
754 ERR("WL: Unable to register Ctrl+Alt+Del hotkey!\n");
758 /* Register Ctrl+Shift+Esc (optional) */
759 Session
->TaskManHotkey
= RegisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
, MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
);
760 if (!Session
->TaskManHotkey
)
761 WARN("WL: Warning: Unable to register Ctrl+Alt+Esc hotkey!\n");
767 IN PWLSESSION Session
,
770 /* Unregister hotkeys */
771 UnregisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
);
773 if (Session
->TaskManHotkey
)
774 UnregisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
);
780 CheckForShutdownPrivilege(
781 IN DWORD RequestingProcessId
)
786 PPRIVILEGE_SET PrivSet
;
788 TRACE("CheckForShutdownPrivilege()\n");
790 Process
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, RequestingProcessId
);
793 WARN("OpenProcess() failed with error %lu\n", GetLastError());
794 return STATUS_INVALID_HANDLE
;
796 if (!OpenProcessToken(Process
, TOKEN_QUERY
, &Token
))
798 WARN("OpenProcessToken() failed with error %lu\n", GetLastError());
799 CloseHandle(Process
);
800 return STATUS_INVALID_HANDLE
;
802 CloseHandle(Process
);
803 PrivSet
= HeapAlloc(GetProcessHeap(), 0, sizeof(PRIVILEGE_SET
) + sizeof(LUID_AND_ATTRIBUTES
));
806 ERR("Failed to allocate mem for privilege set\n");
808 return STATUS_NO_MEMORY
;
810 PrivSet
->PrivilegeCount
= 1;
811 PrivSet
->Control
= PRIVILEGE_SET_ALL_NECESSARY
;
812 if (!LookupPrivilegeValue(NULL
, SE_SHUTDOWN_NAME
, &PrivSet
->Privilege
[0].Luid
))
814 WARN("LookupPrivilegeValue() failed with error %lu\n", GetLastError());
815 HeapFree(GetProcessHeap(), 0, PrivSet
);
817 return STATUS_UNSUCCESSFUL
;
819 if (!PrivilegeCheck(Token
, PrivSet
, &CheckResult
))
821 WARN("PrivilegeCheck() failed with error %lu\n", GetLastError());
822 HeapFree(GetProcessHeap(), 0, PrivSet
);
824 return STATUS_ACCESS_DENIED
;
826 HeapFree(GetProcessHeap(), 0, PrivSet
);
831 WARN("SE_SHUTDOWN privilege not enabled\n");
832 return STATUS_ACCESS_DENIED
;
834 return STATUS_SUCCESS
;
837 static LRESULT CALLBACK
844 PWLSESSION Session
= (PWLSESSION
)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
852 case MAKELONG(MOD_CONTROL
| MOD_ALT
, VK_DELETE
):
854 TRACE("SAS: CONTROL+ALT+DELETE\n");
855 if (!Session
->Gina
.UseCtrlAltDelete
)
857 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_CTRL_ALT_DEL
, 0);
860 case MAKELONG(MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
):
862 TRACE("SAS: CONTROL+SHIFT+ESCAPE\n");
863 DoGenericAction(Session
, WLX_SAS_ACTION_TASKLIST
);
871 /* Get the session pointer from the create data */
872 Session
= (PWLSESSION
)((LPCREATESTRUCT
)lParam
)->lpCreateParams
;
874 /* Save the Session pointer */
875 SetWindowLongPtrW(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)Session
);
878 return RegisterHotKeys(Session
, hwndDlg
);
883 UnregisterHotKeys(Session
, hwndDlg
);
886 case WM_SETTINGCHANGE
:
888 UINT uiAction
= (UINT
)wParam
;
889 if (uiAction
== SPI_SETSCREENSAVETIMEOUT
890 || uiAction
== SPI_SETSCREENSAVEACTIVE
)
892 SetEvent(Session
->hScreenSaverParametersChanged
);
898 DispatchSAS(Session
, (DWORD
)wParam
);
901 case PM_WINLOGON_EXITWINDOWS
:
903 UINT Flags
= (UINT
)lParam
;
904 UINT Action
= Flags
& EWX_ACTION_MASK
;
907 /* Check parameters */
910 case EWX_LOGOFF
: wlxAction
= WLX_SAS_ACTION_LOGOFF
; break;
911 case EWX_SHUTDOWN
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN
; break;
912 case EWX_REBOOT
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_REBOOT
; break;
913 case EWX_POWEROFF
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
; break;
916 ERR("Invalid ExitWindows action 0x%x\n", Action
);
917 return STATUS_INVALID_PARAMETER
;
921 if (WLX_SHUTTINGDOWN(wlxAction
))
923 NTSTATUS Status
= CheckForShutdownPrivilege((DWORD
)wParam
);
924 if (!NT_SUCCESS(Status
))
927 DoGenericAction(Session
, wlxAction
);
932 return DefWindowProc(hwndDlg
, uMsg
, wParam
, lParam
);
937 IN OUT PWLSESSION Session
)
942 if (!SwitchDesktop(Session
->WinlogonDesktop
))
944 ERR("WL: Failed to switch to winlogon desktop\n");
948 /* Register SAS window class */
949 swc
.cbSize
= sizeof(WNDCLASSEXW
);
950 swc
.style
= CS_SAVEBITS
;
951 swc
.lpfnWndProc
= SASWindowProc
;
954 swc
.hInstance
= hAppInstance
;
957 swc
.hbrBackground
= NULL
;
958 swc
.lpszMenuName
= NULL
;
959 swc
.lpszClassName
= WINLOGON_SAS_CLASS
;
961 if (RegisterClassExW(&swc
) == 0)
963 ERR("WL: Failed to register SAS window class\n");
967 /* Create invisible SAS window */
968 Session
->SASWindow
= CreateWindowExW(
974 hAppInstance
, Session
);
975 if (!Session
->SASWindow
)
977 ERR("WL: Failed to create SAS window\n");
981 /* Register SAS window to receive SAS notifications */
982 if (!SetLogonNotifyWindow(Session
->SASWindow
, Session
->InteractiveWindowStation
))
984 ERR("WL: Failed to register SAS window\n");
988 if (!SetDefaultLanguage(FALSE
))
995 UninitializeSAS(Session
);