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
;
173 LPWSTR lpFullEnv
= NULL
;
177 /* Loading personal settings */
178 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_LOADINGYOURPERSONALSETTINGS
);
179 ProfileInfo
.hProfile
= INVALID_HANDLE_VALUE
;
180 if (0 == (Session
->Options
& WLX_LOGON_OPT_NO_PROFILE
))
182 if (Session
->Profile
== NULL
183 || (Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V1_0
184 && Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V2_0
))
186 ERR("WL: Wrong profile\n");
190 /* Load the user profile */
191 ZeroMemory(&ProfileInfo
, sizeof(PROFILEINFOW
));
192 ProfileInfo
.dwSize
= sizeof(PROFILEINFOW
);
193 ProfileInfo
.dwFlags
= 0;
194 ProfileInfo
.lpUserName
= Session
->MprNotifyInfo
.pszUserName
;
195 ProfileInfo
.lpProfilePath
= Session
->Profile
->pszProfile
;
196 if (Session
->Profile
->dwType
>= WLX_PROFILE_TYPE_V2_0
)
198 ProfileInfo
.lpDefaultPath
= Session
->Profile
->pszNetworkDefaultUserProfile
;
199 ProfileInfo
.lpServerName
= Session
->Profile
->pszServerName
;
200 ProfileInfo
.lpPolicyPath
= Session
->Profile
->pszPolicy
;
203 if (!LoadUserProfileW(Session
->UserToken
, &ProfileInfo
))
205 ERR("WL: LoadUserProfileW() failed\n");
210 /* Create environment block for the user */
211 if (!CreateUserEnvironment(Session
, &lpEnvironment
, &lpFullEnv
))
213 WARN("WL: SetUserEnvironment() failed\n");
217 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_APPLYINGYOURPERSONALSETTINGS
);
218 UpdatePerUserSystemParameters(0, TRUE
);
220 /* Set default language */
221 if (!SetDefaultLanguage(TRUE
))
223 WARN("WL: SetDefaultLanguage() failed\n");
228 /* FIXME: who should do it? winlogon or gina? */
229 /* FIXME: reverting to lower privileges after creating user shell? */
230 RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
232 if (!Session
->Gina
.Functions
.WlxActivateUserShell(
233 Session
->Gina
.Context
,
238 //WCHAR StatusMsg[256];
239 WARN("WL: WlxActivateUserShell() failed\n");
240 //LoadStringW(hAppInstance, IDS_FAILEDACTIVATEUSERSHELL, StatusMsg, sizeof(StatusMsg));
241 //MessageBoxW(0, StatusMsg, NULL, MB_ICONERROR);
245 if (!InitializeScreenSaver(Session
))
246 WARN("WL: Failed to initialize screen saver\n");
248 Session
->hProfileInfo
= ProfileInfo
.hProfile
;
252 if (Session
->Profile
)
254 HeapFree(GetProcessHeap(), 0, Session
->Profile
->pszProfile
);
255 HeapFree(GetProcessHeap(), 0, Session
->Profile
);
257 Session
->Profile
= NULL
;
259 && ProfileInfo
.hProfile
!= INVALID_HANDLE_VALUE
)
261 UnloadUserProfile(WLSession
->UserToken
, ProfileInfo
.hProfile
);
263 if (lpFullEnv
!= lpEnvironment
)
264 HeapFree(GetProcessHeap(), 0, lpFullEnv
);
266 DestroyEnvironmentBlock(lpEnvironment
);
267 RemoveStatusMessage(Session
);
270 CloseHandle(Session
->UserToken
);
271 Session
->UserToken
= NULL
;
276 #define EWX_ACTION_MASK 0xffffffeb
277 #define EWX_FLAGS_MASK 0x00000014
279 typedef struct tagLOGOFF_SHUTDOWN_DATA
283 } LOGOFF_SHUTDOWN_DATA
, *PLOGOFF_SHUTDOWN_DATA
;
286 LogoffShutdownThread(LPVOID Parameter
)
288 PLOGOFF_SHUTDOWN_DATA LSData
= (PLOGOFF_SHUTDOWN_DATA
)Parameter
;
290 if (LSData
->Session
->UserToken
!= NULL
&& !ImpersonateLoggedOnUser(LSData
->Session
->UserToken
))
292 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
296 /* Close processes of the interactive user */
298 EWX_INTERNAL_KILL_USER_APPS
| (LSData
->Flags
& EWX_FLAGS_MASK
) |
299 (EWX_LOGOFF
== (LSData
->Flags
& EWX_ACTION_MASK
) ? EWX_INTERNAL_FLAG_LOGOFF
: 0),
302 ERR("Unable to kill user apps, error %lu\n", GetLastError());
307 /* FIXME: Call ExitWindowsEx() to terminate COM processes */
309 if (LSData
->Session
->UserToken
)
317 CreateLogoffSecurityAttributes(
318 OUT PSECURITY_ATTRIBUTES
* ppsa
)
320 /* The following code is not working yet and messy */
321 /* Still, it gives some ideas about data types and functions involved and */
322 /* required to set up a SECURITY_DESCRIPTOR for a SECURITY_ATTRIBUTES */
323 /* instance for a thread, to allow that thread to ImpersonateLoggedOnUser(). */
324 /* Specifically THREAD_SET_THREAD_TOKEN is required. */
325 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
326 PSECURITY_ATTRIBUTES psa
= 0;
329 EXPLICIT_ACCESS Access
;
330 PSID pEveryoneSID
= NULL
;
331 static SID_IDENTIFIER_AUTHORITY WorldAuthority
= { SECURITY_WORLD_SID_AUTHORITY
};
335 // Let's first try to enumerate what kind of data we need for this to ever work:
336 // 1. The Winlogon SID, to be able to give it THREAD_SET_THREAD_TOKEN.
337 // 2. The users SID (the user trying to logoff, or rather shut down the system).
338 // 3. At least two EXPLICIT_ACCESS instances:
339 // 3.1 One for Winlogon itself, giving it the rights
340 // required to THREAD_SET_THREAD_TOKEN (as it's needed to successfully call
341 // ImpersonateLoggedOnUser).
342 // 3.2 One for the user, to allow *that* thread to perform its work.
343 // 4. An ACL to hold the these EXPLICIT_ACCESS ACE's.
344 // 5. A SECURITY_DESCRIPTOR to hold the ACL, and finally.
345 // 6. A SECURITY_ATTRIBUTES instance to pull all of this required stuff
346 // together, to hand it to CreateThread.
348 // However, it seems struct LOGOFF_SHUTDOWN_DATA doesn't contain
349 // these required SID's, why they'd have to be added.
350 // The Winlogon's own SID should probably only be created once,
351 // while the user's SID obviously must be created for each new user.
352 // Might as well store it when the user logs on?
354 if(!AllocateAndInitializeSid(&WorldAuthority
,
360 ERR("Failed to initialize security descriptor for logoff thread!\n");
361 return STATUS_UNSUCCESSFUL
;
364 /* set up the required security attributes to be able to shut down */
365 /* To save space and time, allocate a single block of memory holding */
366 /* both SECURITY_ATTRIBUTES and SECURITY_DESCRIPTOR */
367 pMem
= HeapAlloc(GetProcessHeap(),
369 sizeof(SECURITY_ATTRIBUTES
) +
370 SECURITY_DESCRIPTOR_MIN_LENGTH
+
374 ERR("Failed to allocate memory for logoff security descriptor!\n");
375 return STATUS_NO_MEMORY
;
378 /* Note that the security descriptor needs to be in _absolute_ format, */
379 /* meaning its members must be pointers to other structures, rather */
380 /* than the relative format using offsets */
381 psa
= (PSECURITY_ATTRIBUTES
)pMem
;
382 SecurityDescriptor
= (PSECURITY_DESCRIPTOR
)(pMem
+ sizeof(SECURITY_ATTRIBUTES
));
383 pACL
= (PACL
)(((PBYTE
)SecurityDescriptor
) + SECURITY_DESCRIPTOR_MIN_LENGTH
);
385 // Initialize an EXPLICIT_ACCESS structure for an ACE.
386 // The ACE will allow this thread to log off (and shut down the system, currently).
387 ZeroMemory(&Access
, sizeof(Access
));
388 Access
.grfAccessPermissions
= THREAD_SET_THREAD_TOKEN
;
389 Access
.grfAccessMode
= SET_ACCESS
; // GRANT_ACCESS?
390 Access
.grfInheritance
= NO_INHERITANCE
;
391 Access
.Trustee
.TrusteeForm
= TRUSTEE_IS_SID
;
392 Access
.Trustee
.TrusteeType
= TRUSTEE_IS_WELL_KNOWN_GROUP
;
393 Access
.Trustee
.ptstrName
= pEveryoneSID
;
395 if (SetEntriesInAcl(1, &Access
, NULL
, &pACL
) != ERROR_SUCCESS
)
397 ERR("Failed to set Access Rights for logoff thread. Logging out will most likely fail.\n");
399 HeapFree(GetProcessHeap(), 0, pMem
);
400 return STATUS_UNSUCCESSFUL
;
403 if (!InitializeSecurityDescriptor(SecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
))
405 ERR("Failed to initialize security descriptor for logoff thread!\n");
406 HeapFree(GetProcessHeap(), 0, pMem
);
407 return STATUS_UNSUCCESSFUL
;
410 if (!SetSecurityDescriptorDacl(SecurityDescriptor
,
411 TRUE
, // bDaclPresent flag
413 FALSE
)) // not a default DACL
415 ERR("SetSecurityDescriptorDacl Error %lu\n", GetLastError());
416 HeapFree(GetProcessHeap(), 0, pMem
);
417 return STATUS_UNSUCCESSFUL
;
420 psa
->nLength
= sizeof(SECURITY_ATTRIBUTES
);
421 psa
->lpSecurityDescriptor
= SecurityDescriptor
;
422 psa
->bInheritHandle
= FALSE
;
426 return STATUS_SUCCESS
;
430 DestroyLogoffSecurityAttributes(
431 IN PSECURITY_ATTRIBUTES psa
)
435 HeapFree(GetProcessHeap(), 0, psa
);
442 IN OUT PWLSESSION Session
,
445 PLOGOFF_SHUTDOWN_DATA LSData
;
446 PSECURITY_ATTRIBUTES psa
;
451 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_SAVEYOURSETTINGS
);
453 /* Prepare data for logoff thread */
454 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
457 ERR("Failed to allocate mem for thread data\n");
458 return STATUS_NO_MEMORY
;
460 LSData
->Flags
= Flags
;
461 LSData
->Session
= Session
;
463 Status
= CreateLogoffSecurityAttributes(&psa
);
464 if (!NT_SUCCESS(Status
))
466 ERR("Failed to create a required security descriptor. Status 0x%08lx\n", Status
);
467 HeapFree(GetProcessHeap(), 0, LSData
);
471 /* Run logoff thread */
472 hThread
= CreateThread(psa
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
474 /* we're done with the SECURITY_DESCRIPTOR */
475 DestroyLogoffSecurityAttributes(psa
);
480 ERR("Unable to create logoff thread, error %lu\n", GetLastError());
481 HeapFree(GetProcessHeap(), 0, LSData
);
482 return STATUS_UNSUCCESSFUL
;
484 WaitForSingleObject(hThread
, INFINITE
);
485 HeapFree(GetProcessHeap(), 0, LSData
);
486 if (!GetExitCodeThread(hThread
, &exitCode
))
488 ERR("Unable to get exit code of logoff thread (error %lu)\n", GetLastError());
489 CloseHandle(hThread
);
490 return STATUS_UNSUCCESSFUL
;
492 CloseHandle(hThread
);
495 ERR("Logoff thread returned failure\n");
496 return STATUS_UNSUCCESSFUL
;
499 UnloadUserProfile(Session
->UserToken
, Session
->hProfileInfo
);
500 CloseHandle(Session
->UserToken
);
501 UpdatePerUserSystemParameters(0, FALSE
);
502 Session
->LogonStatus
= WKSTA_IS_LOGGED_OFF
;
503 Session
->UserToken
= NULL
;
504 return STATUS_SUCCESS
;
507 static INT_PTR CALLBACK
508 ShutdownComputerWindowProc(
514 UNREFERENCED_PARAMETER(lParam
);
520 switch (LOWORD(wParam
))
522 case IDC_BTNSHTDOWNCOMPUTER
:
523 EndDialog(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
);
530 RemoveMenu(GetSystemMenu(hwndDlg
, FALSE
), SC_CLOSE
, MF_BYCOMMAND
);
531 SetFocus(GetDlgItem(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
));
540 IN OUT PWLSESSION Session
)
542 if (Session
->SASWindow
)
544 DestroyWindow(Session
->SASWindow
);
545 Session
->SASWindow
= NULL
;
547 if (Session
->hEndOfScreenSaverThread
)
548 SetEvent(Session
->hEndOfScreenSaverThread
);
549 UnregisterClassW(WINLOGON_SAS_CLASS
, hAppInstance
);
554 IN OUT PWLSESSION Session
,
557 PLOGOFF_SHUTDOWN_DATA LSData
;
561 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_REACTOSISSHUTTINGDOWN
);
563 /* Prepare data for shutdown thread */
564 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
567 ERR("Failed to allocate mem for thread data\n");
568 return STATUS_NO_MEMORY
;
570 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
)
571 LSData
->Flags
= EWX_POWEROFF
;
572 else if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
573 LSData
->Flags
= EWX_REBOOT
;
575 LSData
->Flags
= EWX_SHUTDOWN
;
576 LSData
->Session
= Session
;
578 /* Run shutdown thread */
579 hThread
= CreateThread(NULL
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
582 ERR("Unable to create shutdown thread, error %lu\n", GetLastError());
583 HeapFree(GetProcessHeap(), 0, LSData
);
584 return STATUS_UNSUCCESSFUL
;
586 WaitForSingleObject(hThread
, INFINITE
);
587 HeapFree(GetProcessHeap(), 0, LSData
);
588 if (!GetExitCodeThread(hThread
, &exitCode
))
590 ERR("Unable to get exit code of shutdown thread (error %lu)\n", GetLastError());
591 CloseHandle(hThread
);
592 return STATUS_UNSUCCESSFUL
;
594 CloseHandle(hThread
);
597 ERR("Shutdown thread returned failure\n");
598 return STATUS_UNSUCCESSFUL
;
601 /* Destroy SAS window */
602 UninitializeSAS(Session
);
604 FIXME("FIXME: Call SMSS API #1\n");
605 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
606 NtShutdownSystem(ShutdownReboot
);
611 /* FIXME - only show this dialog if it's a shutdown and the computer doesn't support APM */
612 DialogBox(hAppInstance
, MAKEINTRESOURCE(IDD_SHUTDOWNCOMPUTER
), GetDesktopWindow(), ShutdownComputerWindowProc
);
614 NtShutdownSystem(ShutdownNoReboot
);
616 return STATUS_SUCCESS
;
621 IN OUT PWLSESSION Session
,
626 case WLX_SAS_ACTION_LOGON
: /* 0x01 */
627 if (HandleLogon(Session
))
629 SwitchDesktop(Session
->ApplicationDesktop
);
630 Session
->LogonStatus
= WKSTA_IS_LOGGED_ON
;
633 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
635 case WLX_SAS_ACTION_NONE
: /* 0x02 */
637 case WLX_SAS_ACTION_LOCK_WKSTA
: /* 0x03 */
638 if (Session
->Gina
.Functions
.WlxIsLockOk(Session
->Gina
.Context
))
640 SwitchDesktop(WLSession
->WinlogonDesktop
);
641 Session
->LogonStatus
= WKSTA_IS_LOCKED
;
642 Session
->Gina
.Functions
.WlxDisplayLockedNotice(Session
->Gina
.Context
);
645 case WLX_SAS_ACTION_LOGOFF
: /* 0x04 */
646 case WLX_SAS_ACTION_SHUTDOWN
: /* 0x05 */
647 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
: /* 0x0a */
648 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
: /* 0x0b */
649 if (Session
->LogonStatus
!= WKSTA_IS_LOGGED_OFF
)
651 if (!Session
->Gina
.Functions
.WlxIsLogoffOk(Session
->Gina
.Context
))
653 SwitchDesktop(WLSession
->WinlogonDesktop
);
654 Session
->Gina
.Functions
.WlxLogoff(Session
->Gina
.Context
);
655 if (!NT_SUCCESS(HandleLogoff(Session
, EWX_LOGOFF
)))
657 RemoveStatusMessage(Session
);
661 if (WLX_SHUTTINGDOWN(wlxAction
))
663 Session
->Gina
.Functions
.WlxShutdown(Session
->Gina
.Context
, wlxAction
);
664 if (!NT_SUCCESS(HandleShutdown(Session
, wlxAction
)))
666 RemoveStatusMessage(Session
);
667 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
672 RemoveStatusMessage(Session
);
673 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
676 case WLX_SAS_ACTION_TASKLIST
: /* 0x07 */
677 SwitchDesktop(WLSession
->ApplicationDesktop
);
678 StartTaskManager(Session
);
680 case WLX_SAS_ACTION_UNLOCK_WKSTA
: /* 0x08 */
681 SwitchDesktop(WLSession
->ApplicationDesktop
);
682 Session
->LogonStatus
= WKSTA_IS_LOGGED_ON
;
685 WARN("Unknown SAS action 0x%lx\n", wlxAction
);
691 IN OUT PWLSESSION Session
,
694 DWORD wlxAction
= WLX_SAS_ACTION_NONE
;
696 if (Session
->LogonStatus
== WKSTA_IS_LOGGED_ON
)
697 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOnSAS(Session
->Gina
.Context
, dwSasType
, NULL
);
698 else if (Session
->LogonStatus
== WKSTA_IS_LOCKED
)
699 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxWkstaLockedSAS(Session
->Gina
.Context
, dwSasType
);
702 /* Display a new dialog (if necessary) */
705 case WLX_SAS_TYPE_TIMEOUT
: /* 0x00 */
707 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
712 PSID LogonSid
= NULL
; /* FIXME */
714 Session
->Options
= 0;
716 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOutSAS(
717 Session
->Gina
.Context
,
723 &Session
->MprNotifyInfo
,
724 (PVOID
*)&Session
->Profile
);
730 if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_TIMEOUT
)
733 if (!Session
->Gina
.Functions
.WlxScreenSaverNotify(Session
->Gina
.Context
, &bSecure
))
735 /* Skip start of screen saver */
736 SetEvent(Session
->hEndOfScreenSaver
);
741 DoGenericAction(Session
, WLX_SAS_ACTION_LOCK_WKSTA
);
742 StartScreenSaver(Session
);
745 else if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_ACTIVITY
)
746 SetEvent(Session
->hUserActivity
);
748 DoGenericAction(Session
, wlxAction
);
753 IN PWLSESSION Session
,
756 /* Register Ctrl+Alt+Del Hotkey */
757 if (!RegisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
, MOD_CONTROL
| MOD_ALT
, VK_DELETE
))
759 ERR("WL: Unable to register Ctrl+Alt+Del hotkey!\n");
763 /* Register Ctrl+Shift+Esc (optional) */
764 Session
->TaskManHotkey
= RegisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
, MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
);
765 if (!Session
->TaskManHotkey
)
766 WARN("WL: Warning: Unable to register Ctrl+Alt+Esc hotkey!\n");
772 IN PWLSESSION Session
,
775 /* Unregister hotkeys */
776 UnregisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
);
778 if (Session
->TaskManHotkey
)
779 UnregisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
);
785 CheckForShutdownPrivilege(
786 IN DWORD RequestingProcessId
)
791 PPRIVILEGE_SET PrivSet
;
793 TRACE("CheckForShutdownPrivilege()\n");
795 Process
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, RequestingProcessId
);
798 WARN("OpenProcess() failed with error %lu\n", GetLastError());
799 return STATUS_INVALID_HANDLE
;
801 if (!OpenProcessToken(Process
, TOKEN_QUERY
, &Token
))
803 WARN("OpenProcessToken() failed with error %lu\n", GetLastError());
804 CloseHandle(Process
);
805 return STATUS_INVALID_HANDLE
;
807 CloseHandle(Process
);
808 PrivSet
= HeapAlloc(GetProcessHeap(), 0, sizeof(PRIVILEGE_SET
) + sizeof(LUID_AND_ATTRIBUTES
));
811 ERR("Failed to allocate mem for privilege set\n");
813 return STATUS_NO_MEMORY
;
815 PrivSet
->PrivilegeCount
= 1;
816 PrivSet
->Control
= PRIVILEGE_SET_ALL_NECESSARY
;
817 if (!LookupPrivilegeValue(NULL
, SE_SHUTDOWN_NAME
, &PrivSet
->Privilege
[0].Luid
))
819 WARN("LookupPrivilegeValue() failed with error %lu\n", GetLastError());
820 HeapFree(GetProcessHeap(), 0, PrivSet
);
822 return STATUS_UNSUCCESSFUL
;
824 if (!PrivilegeCheck(Token
, PrivSet
, &CheckResult
))
826 WARN("PrivilegeCheck() failed with error %lu\n", GetLastError());
827 HeapFree(GetProcessHeap(), 0, PrivSet
);
829 return STATUS_ACCESS_DENIED
;
831 HeapFree(GetProcessHeap(), 0, PrivSet
);
836 WARN("SE_SHUTDOWN privilege not enabled\n");
837 return STATUS_ACCESS_DENIED
;
839 return STATUS_SUCCESS
;
842 static LRESULT CALLBACK
849 PWLSESSION Session
= (PWLSESSION
)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
857 case MAKELONG(MOD_CONTROL
| MOD_ALT
, VK_DELETE
):
859 TRACE("SAS: CONTROL+ALT+DELETE\n");
860 if (!Session
->Gina
.UseCtrlAltDelete
)
862 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_CTRL_ALT_DEL
, 0);
865 case MAKELONG(MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
):
867 TRACE("SAS: CONTROL+SHIFT+ESCAPE\n");
868 DoGenericAction(Session
, WLX_SAS_ACTION_TASKLIST
);
876 /* Get the session pointer from the create data */
877 Session
= (PWLSESSION
)((LPCREATESTRUCT
)lParam
)->lpCreateParams
;
879 /* Save the Session pointer */
880 SetWindowLongPtrW(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)Session
);
883 return RegisterHotKeys(Session
, hwndDlg
);
888 UnregisterHotKeys(Session
, hwndDlg
);
891 case WM_SETTINGCHANGE
:
893 UINT uiAction
= (UINT
)wParam
;
894 if (uiAction
== SPI_SETSCREENSAVETIMEOUT
895 || uiAction
== SPI_SETSCREENSAVEACTIVE
)
897 SetEvent(Session
->hScreenSaverParametersChanged
);
903 DispatchSAS(Session
, (DWORD
)wParam
);
906 case PM_WINLOGON_EXITWINDOWS
:
908 UINT Flags
= (UINT
)lParam
;
909 UINT Action
= Flags
& EWX_ACTION_MASK
;
912 /* Check parameters */
915 case EWX_LOGOFF
: wlxAction
= WLX_SAS_ACTION_LOGOFF
; break;
916 case EWX_SHUTDOWN
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN
; break;
917 case EWX_REBOOT
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_REBOOT
; break;
918 case EWX_POWEROFF
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
; break;
921 ERR("Invalid ExitWindows action 0x%x\n", Action
);
922 return STATUS_INVALID_PARAMETER
;
926 if (WLX_SHUTTINGDOWN(wlxAction
))
928 NTSTATUS Status
= CheckForShutdownPrivilege((DWORD
)wParam
);
929 if (!NT_SUCCESS(Status
))
932 DoGenericAction(Session
, wlxAction
);
937 return DefWindowProc(hwndDlg
, uMsg
, wParam
, lParam
);
942 IN OUT PWLSESSION Session
)
947 if (!SwitchDesktop(Session
->WinlogonDesktop
))
949 ERR("WL: Failed to switch to winlogon desktop\n");
953 /* Register SAS window class */
954 swc
.cbSize
= sizeof(WNDCLASSEXW
);
955 swc
.style
= CS_SAVEBITS
;
956 swc
.lpfnWndProc
= SASWindowProc
;
959 swc
.hInstance
= hAppInstance
;
962 swc
.hbrBackground
= NULL
;
963 swc
.lpszMenuName
= NULL
;
964 swc
.lpszClassName
= WINLOGON_SAS_CLASS
;
966 if (RegisterClassExW(&swc
) == 0)
968 ERR("WL: Failed to register SAS window class\n");
972 /* Create invisible SAS window */
973 Session
->SASWindow
= CreateWindowExW(
979 hAppInstance
, Session
);
980 if (!Session
->SASWindow
)
982 ERR("WL: Failed to create SAS window\n");
986 /* Register SAS window to receive SAS notifications */
987 if (!SetLogonNotifyWindow(Session
->SASWindow
, Session
->InteractiveWindowStation
))
989 ERR("WL: Failed to register SAS window\n");
993 if (!SetDefaultLanguage(FALSE
))
1000 UninitializeSAS(Session
);