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 static BOOL inScrn
= FALSE
;
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
);
62 IN OUT PWLSESSION Session
)
64 LPVOID lpEnvironment
= NULL
;
68 /* Create environment block for the user */
69 if (!CreateEnvironmentBlock(&lpEnvironment
, Session
->UserToken
, TRUE
))
71 WARN("WL: CreateEnvironmentBlock() failed\n");
76 /* FIXME: who should do it? winlogon or gina? */
77 /* FIXME: reverting to lower privileges after creating user shell? */
78 RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
80 ret
= Session
->Gina
.Functions
.WlxActivateUserShell(
81 Session
->Gina
.Context
,
86 DestroyEnvironmentBlock(lpEnvironment
);
100 DWORD dwType
, dwSize
;
102 UNICODE_STRING ValueString
;
109 BaseKey
= HKEY_CURRENT_USER
;
110 SubKey
= L
"Control Panel\\International";
111 ValueName
= L
"Locale";
115 BaseKey
= HKEY_LOCAL_MACHINE
;
116 SubKey
= L
"System\\CurrentControlSet\\Control\\Nls\\Language";
117 ValueName
= L
"Default";
126 if (rc
!= ERROR_SUCCESS
)
128 TRACE("RegOpenKeyEx() failed with error %lu\n", rc
);
131 rc
= RegQueryValueExW(
138 if (rc
!= ERROR_SUCCESS
)
140 TRACE("RegQueryValueEx() failed with error %lu\n", rc
);
143 else if (dwType
!= REG_SZ
)
145 TRACE("Wrong type for %S\\%S registry entry (got 0x%lx, expected 0x%x)\n",
146 SubKey
, ValueName
, dwType
, REG_SZ
);
150 Value
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
153 TRACE("HeapAlloc() failed\n");
156 rc
= RegQueryValueExW(
163 if (rc
!= ERROR_SUCCESS
)
165 TRACE("RegQueryValueEx() failed with error %lu\n", rc
);
169 /* Convert Value to a Lcid */
170 ValueString
.Length
= ValueString
.MaximumLength
= (USHORT
)dwSize
;
171 ValueString
.Buffer
= Value
;
172 Status
= RtlUnicodeStringToInteger(&ValueString
, 16, (PULONG
)&Lcid
);
173 if (!NT_SUCCESS(Status
))
175 TRACE("RtlUnicodeStringToInteger() failed with status 0x%08lx\n", Status
);
179 TRACE("%s language is 0x%08lx\n",
180 UserProfile
? "User" : "System", Lcid
);
181 Status
= NtSetDefaultLocale(UserProfile
, Lcid
);
182 if (!NT_SUCCESS(Status
))
184 TRACE("NtSetDefaultLocale() failed with status 0x%08lx\n", Status
);
194 HeapFree(GetProcessHeap(), 0, Value
);
200 IN OUT PWLSESSION Session
)
202 PROFILEINFOW ProfileInfo
;
205 /* Loading personal settings */
206 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_LOADINGYOURPERSONALSETTINGS
);
207 ProfileInfo
.hProfile
= INVALID_HANDLE_VALUE
;
208 if (0 == (Session
->Options
& WLX_LOGON_OPT_NO_PROFILE
))
210 if (Session
->Profile
== NULL
211 || (Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V1_0
212 && Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V2_0
))
214 ERR("WL: Wrong profile\n");
218 /* Load the user profile */
219 ZeroMemory(&ProfileInfo
, sizeof(PROFILEINFOW
));
220 ProfileInfo
.dwSize
= sizeof(PROFILEINFOW
);
221 ProfileInfo
.dwFlags
= 0;
222 ProfileInfo
.lpUserName
= Session
->MprNotifyInfo
.pszUserName
;
223 ProfileInfo
.lpProfilePath
= Session
->Profile
->pszProfile
;
224 if (Session
->Profile
->dwType
>= WLX_PROFILE_TYPE_V2_0
)
226 ProfileInfo
.lpDefaultPath
= Session
->Profile
->pszNetworkDefaultUserProfile
;
227 ProfileInfo
.lpServerName
= Session
->Profile
->pszServerName
;
228 ProfileInfo
.lpPolicyPath
= Session
->Profile
->pszPolicy
;
231 if (!LoadUserProfileW(Session
->UserToken
, &ProfileInfo
))
233 ERR("WL: LoadUserProfileW() failed\n");
238 /* Create environment block for the user */
239 if (!CreateUserEnvironment(Session
))
241 WARN("WL: SetUserEnvironment() failed\n");
245 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_APPLYINGYOURPERSONALSETTINGS
);
246 UpdatePerUserSystemParameters(0, TRUE
);
248 /* Set default language */
249 if (!SetDefaultLanguage(TRUE
))
251 WARN("WL: SetDefaultLanguage() failed\n");
255 if (!StartUserShell(Session
))
257 //WCHAR StatusMsg[256];
258 WARN("WL: WlxActivateUserShell() failed\n");
259 //LoadStringW(hAppInstance, IDS_FAILEDACTIVATEUSERSHELL, StatusMsg, sizeof(StatusMsg));
260 //MessageBoxW(0, StatusMsg, NULL, MB_ICONERROR);
264 if (!InitializeScreenSaver(Session
))
265 WARN("WL: Failed to initialize screen saver\n");
267 Session
->hProfileInfo
= ProfileInfo
.hProfile
;
271 if (Session
->Profile
)
273 HeapFree(GetProcessHeap(), 0, Session
->Profile
->pszProfile
);
274 HeapFree(GetProcessHeap(), 0, Session
->Profile
);
276 Session
->Profile
= NULL
;
278 && ProfileInfo
.hProfile
!= INVALID_HANDLE_VALUE
)
280 UnloadUserProfile(WLSession
->UserToken
, ProfileInfo
.hProfile
);
282 RemoveStatusMessage(Session
);
285 CloseHandle(Session
->UserToken
);
286 Session
->UserToken
= NULL
;
291 #define EWX_ACTION_MASK 0xffffffeb
292 #define EWX_FLAGS_MASK 0x00000014
294 typedef struct tagLOGOFF_SHUTDOWN_DATA
298 } LOGOFF_SHUTDOWN_DATA
, *PLOGOFF_SHUTDOWN_DATA
;
301 LogoffShutdownThread(LPVOID Parameter
)
303 PLOGOFF_SHUTDOWN_DATA LSData
= (PLOGOFF_SHUTDOWN_DATA
)Parameter
;
305 if (LSData
->Session
->UserToken
!= NULL
&& !ImpersonateLoggedOnUser(LSData
->Session
->UserToken
))
307 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
311 /* Close processes of the interactive user */
313 EWX_INTERNAL_KILL_USER_APPS
| (LSData
->Flags
& EWX_FLAGS_MASK
) |
314 (EWX_LOGOFF
== (LSData
->Flags
& EWX_ACTION_MASK
) ? EWX_INTERNAL_FLAG_LOGOFF
: 0),
317 ERR("Unable to kill user apps, error %lu\n", GetLastError());
322 /* FIXME: Call ExitWindowsEx() to terminate COM processes */
324 if (LSData
->Session
->UserToken
)
332 CreateLogoffSecurityAttributes(
333 OUT PSECURITY_ATTRIBUTES
* ppsa
)
335 /* The following code is not working yet and messy */
336 /* Still, it gives some ideas about data types and functions involved and */
337 /* required to set up a SECURITY_DESCRIPTOR for a SECURITY_ATTRIBUTES */
338 /* instance for a thread, to allow that thread to ImpersonateLoggedOnUser(). */
339 /* Specifically THREAD_SET_THREAD_TOKEN is required. */
340 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
341 PSECURITY_ATTRIBUTES psa
= 0;
344 EXPLICIT_ACCESS Access
;
345 PSID pEveryoneSID
= NULL
;
346 static SID_IDENTIFIER_AUTHORITY WorldAuthority
= { SECURITY_WORLD_SID_AUTHORITY
};
350 // Let's first try to enumerate what kind of data we need for this to ever work:
351 // 1. The Winlogon SID, to be able to give it THREAD_SET_THREAD_TOKEN.
352 // 2. The users SID (the user trying to logoff, or rather shut down the system).
353 // 3. At least two EXPLICIT_ACCESS instances:
354 // 3.1 One for Winlogon itself, giving it the rights
355 // required to THREAD_SET_THREAD_TOKEN (as it's needed to successfully call
356 // ImpersonateLoggedOnUser).
357 // 3.2 One for the user, to allow *that* thread to perform its work.
358 // 4. An ACL to hold the these EXPLICIT_ACCESS ACE's.
359 // 5. A SECURITY_DESCRIPTOR to hold the ACL, and finally.
360 // 6. A SECURITY_ATTRIBUTES instance to pull all of this required stuff
361 // together, to hand it to CreateThread.
363 // However, it seems struct LOGOFF_SHUTDOWN_DATA doesn't contain
364 // these required SID's, why they'd have to be added.
365 // The Winlogon's own SID should probably only be created once,
366 // while the user's SID obviously must be created for each new user.
367 // Might as well store it when the user logs on?
369 if(!AllocateAndInitializeSid(&WorldAuthority
,
375 ERR("Failed to initialize security descriptor for logoff thread!\n");
376 return STATUS_UNSUCCESSFUL
;
379 /* set up the required security attributes to be able to shut down */
380 /* To save space and time, allocate a single block of memory holding */
381 /* both SECURITY_ATTRIBUTES and SECURITY_DESCRIPTOR */
382 pMem
= HeapAlloc(GetProcessHeap(),
384 sizeof(SECURITY_ATTRIBUTES
) +
385 SECURITY_DESCRIPTOR_MIN_LENGTH
+
389 ERR("Failed to allocate memory for logoff security descriptor!\n");
390 return STATUS_NO_MEMORY
;
393 /* Note that the security descriptor needs to be in _absolute_ format, */
394 /* meaning its members must be pointers to other structures, rather */
395 /* than the relative format using offsets */
396 psa
= (PSECURITY_ATTRIBUTES
)pMem
;
397 SecurityDescriptor
= (PSECURITY_DESCRIPTOR
)(pMem
+ sizeof(SECURITY_ATTRIBUTES
));
398 pACL
= (PACL
)(((PBYTE
)SecurityDescriptor
) + SECURITY_DESCRIPTOR_MIN_LENGTH
);
400 // Initialize an EXPLICIT_ACCESS structure for an ACE.
401 // The ACE will allow this thread to log off (and shut down the system, currently).
402 ZeroMemory(&Access
, sizeof(Access
));
403 Access
.grfAccessPermissions
= THREAD_SET_THREAD_TOKEN
;
404 Access
.grfAccessMode
= SET_ACCESS
; // GRANT_ACCESS?
405 Access
.grfInheritance
= NO_INHERITANCE
;
406 Access
.Trustee
.TrusteeForm
= TRUSTEE_IS_SID
;
407 Access
.Trustee
.TrusteeType
= TRUSTEE_IS_WELL_KNOWN_GROUP
;
408 Access
.Trustee
.ptstrName
= pEveryoneSID
;
410 if (SetEntriesInAcl(1, &Access
, NULL
, &pACL
) != ERROR_SUCCESS
)
412 ERR("Failed to set Access Rights for logoff thread. Logging out will most likely fail.\n");
414 HeapFree(GetProcessHeap(), 0, pMem
);
415 return STATUS_UNSUCCESSFUL
;
418 if (!InitializeSecurityDescriptor(SecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
))
420 ERR("Failed to initialize security descriptor for logoff thread!\n");
421 HeapFree(GetProcessHeap(), 0, pMem
);
422 return STATUS_UNSUCCESSFUL
;
425 if (!SetSecurityDescriptorDacl(SecurityDescriptor
,
426 TRUE
, // bDaclPresent flag
428 FALSE
)) // not a default DACL
430 ERR("SetSecurityDescriptorDacl Error %lu\n", GetLastError());
431 HeapFree(GetProcessHeap(), 0, pMem
);
432 return STATUS_UNSUCCESSFUL
;
435 psa
->nLength
= sizeof(SECURITY_ATTRIBUTES
);
436 psa
->lpSecurityDescriptor
= SecurityDescriptor
;
437 psa
->bInheritHandle
= FALSE
;
441 return STATUS_SUCCESS
;
445 DestroyLogoffSecurityAttributes(
446 IN PSECURITY_ATTRIBUTES psa
)
450 HeapFree(GetProcessHeap(), 0, psa
);
457 IN OUT PWLSESSION Session
,
460 PLOGOFF_SHUTDOWN_DATA LSData
;
461 PSECURITY_ATTRIBUTES psa
;
466 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_SAVEYOURSETTINGS
);
468 /* Prepare data for logoff thread */
469 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
472 ERR("Failed to allocate mem for thread data\n");
473 return STATUS_NO_MEMORY
;
475 LSData
->Flags
= Flags
;
476 LSData
->Session
= Session
;
478 Status
= CreateLogoffSecurityAttributes(&psa
);
479 if (!NT_SUCCESS(Status
))
481 ERR("Failed to create a required security descriptor. Status 0x%08lx\n", Status
);
482 HeapFree(GetProcessHeap(), 0, LSData
);
486 /* Run logoff thread */
487 hThread
= CreateThread(psa
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
489 /* we're done with the SECURITY_DESCRIPTOR */
490 DestroyLogoffSecurityAttributes(psa
);
495 ERR("Unable to create logoff thread, error %lu\n", GetLastError());
496 HeapFree(GetProcessHeap(), 0, LSData
);
497 return STATUS_UNSUCCESSFUL
;
499 WaitForSingleObject(hThread
, INFINITE
);
500 HeapFree(GetProcessHeap(), 0, LSData
);
501 if (!GetExitCodeThread(hThread
, &exitCode
))
503 ERR("Unable to get exit code of logoff thread (error %lu)\n", GetLastError());
504 CloseHandle(hThread
);
505 return STATUS_UNSUCCESSFUL
;
507 CloseHandle(hThread
);
510 ERR("Logoff thread returned failure\n");
511 return STATUS_UNSUCCESSFUL
;
514 UnloadUserProfile(Session
->UserToken
, Session
->hProfileInfo
);
515 CloseHandle(Session
->UserToken
);
516 UpdatePerUserSystemParameters(0, FALSE
);
517 Session
->LogonStatus
= WKSTA_IS_LOGGED_OFF
;
518 Session
->UserToken
= NULL
;
519 return STATUS_SUCCESS
;
522 static INT_PTR CALLBACK
523 ShutdownComputerWindowProc(
529 UNREFERENCED_PARAMETER(lParam
);
535 switch (LOWORD(wParam
))
537 case IDC_BTNSHTDOWNCOMPUTER
:
538 EndDialog(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
);
545 RemoveMenu(GetSystemMenu(hwndDlg
, FALSE
), SC_CLOSE
, MF_BYCOMMAND
);
546 SetFocus(GetDlgItem(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
));
555 IN OUT PWLSESSION Session
)
557 if (Session
->SASWindow
)
559 DestroyWindow(Session
->SASWindow
);
560 Session
->SASWindow
= NULL
;
562 if (Session
->hEndOfScreenSaverThread
)
563 SetEvent(Session
->hEndOfScreenSaverThread
);
564 UnregisterClassW(WINLOGON_SAS_CLASS
, hAppInstance
);
569 IN OUT PWLSESSION Session
,
572 PLOGOFF_SHUTDOWN_DATA LSData
;
576 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_REACTOSISSHUTTINGDOWN
);
578 /* Prepare data for shutdown thread */
579 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
582 ERR("Failed to allocate mem for thread data\n");
583 return STATUS_NO_MEMORY
;
585 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
)
586 LSData
->Flags
= EWX_POWEROFF
;
587 else if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
588 LSData
->Flags
= EWX_REBOOT
;
590 LSData
->Flags
= EWX_SHUTDOWN
;
591 LSData
->Session
= Session
;
593 /* Run shutdown thread */
594 hThread
= CreateThread(NULL
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
597 ERR("Unable to create shutdown thread, error %lu\n", GetLastError());
598 HeapFree(GetProcessHeap(), 0, LSData
);
599 return STATUS_UNSUCCESSFUL
;
601 WaitForSingleObject(hThread
, INFINITE
);
602 HeapFree(GetProcessHeap(), 0, LSData
);
603 if (!GetExitCodeThread(hThread
, &exitCode
))
605 ERR("Unable to get exit code of shutdown thread (error %lu)\n", GetLastError());
606 CloseHandle(hThread
);
607 return STATUS_UNSUCCESSFUL
;
609 CloseHandle(hThread
);
612 ERR("Shutdown thread returned failure\n");
613 return STATUS_UNSUCCESSFUL
;
616 /* Destroy SAS window */
617 UninitializeSAS(Session
);
619 FIXME("FIXME: Call SMSS API #1\n");
620 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
621 NtShutdownSystem(ShutdownReboot
);
626 /* FIXME - only show this dialog if it's a shutdown and the computer doesn't support APM */
627 DialogBox(hAppInstance
, MAKEINTRESOURCE(IDD_SHUTDOWNCOMPUTER
), GetDesktopWindow(), ShutdownComputerWindowProc
);
629 NtShutdownSystem(ShutdownNoReboot
);
631 return STATUS_SUCCESS
;
636 IN OUT PWLSESSION Session
,
641 case WLX_SAS_ACTION_LOGON
: /* 0x01 */
642 if (HandleLogon(Session
))
644 SwitchDesktop(Session
->ApplicationDesktop
);
645 Session
->LogonStatus
= WKSTA_IS_LOGGED_ON
;
648 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
650 case WLX_SAS_ACTION_NONE
: /* 0x02 */
652 case WLX_SAS_ACTION_LOCK_WKSTA
: /* 0x03 */
653 if (Session
->Gina
.Functions
.WlxIsLockOk(Session
->Gina
.Context
))
655 SwitchDesktop(WLSession
->WinlogonDesktop
);
656 Session
->LogonStatus
= WKSTA_IS_LOCKED
;
657 Session
->Gina
.Functions
.WlxDisplayLockedNotice(Session
->Gina
.Context
);
660 case WLX_SAS_ACTION_LOGOFF
: /* 0x04 */
661 case WLX_SAS_ACTION_SHUTDOWN
: /* 0x05 */
662 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
: /* 0x0a */
663 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
: /* 0x0b */
664 if (Session
->LogonStatus
!= WKSTA_IS_LOGGED_OFF
)
666 if (!Session
->Gina
.Functions
.WlxIsLogoffOk(Session
->Gina
.Context
))
668 SwitchDesktop(WLSession
->WinlogonDesktop
);
669 Session
->Gina
.Functions
.WlxLogoff(Session
->Gina
.Context
);
670 if (!NT_SUCCESS(HandleLogoff(Session
, EWX_LOGOFF
)))
672 RemoveStatusMessage(Session
);
676 if (WLX_SHUTTINGDOWN(wlxAction
))
678 Session
->Gina
.Functions
.WlxShutdown(Session
->Gina
.Context
, wlxAction
);
679 if (!NT_SUCCESS(HandleShutdown(Session
, wlxAction
)))
681 RemoveStatusMessage(Session
);
682 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
687 RemoveStatusMessage(Session
);
688 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
691 case WLX_SAS_ACTION_TASKLIST
: /* 0x07 */
692 SwitchDesktop(WLSession
->ApplicationDesktop
);
693 StartTaskManager(Session
);
695 case WLX_SAS_ACTION_UNLOCK_WKSTA
: /* 0x08 */
696 SwitchDesktop(WLSession
->ApplicationDesktop
);
697 Session
->LogonStatus
= WKSTA_IS_LOGGED_ON
;
700 WARN("Unknown SAS action 0x%lx\n", wlxAction
);
706 IN OUT PWLSESSION Session
,
709 DWORD wlxAction
= WLX_SAS_ACTION_NONE
;
711 if (Session
->LogonStatus
== WKSTA_IS_LOGGED_ON
)
712 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOnSAS(Session
->Gina
.Context
, dwSasType
, NULL
);
713 else if (Session
->LogonStatus
== WKSTA_IS_LOCKED
)
714 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxWkstaLockedSAS(Session
->Gina
.Context
, dwSasType
);
717 /* Display a new dialog (if necessary) */
720 case WLX_SAS_TYPE_TIMEOUT
: /* 0x00 */
722 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
727 PSID LogonSid
= NULL
; /* FIXME */
729 Session
->Options
= 0;
731 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOutSAS(
732 Session
->Gina
.Context
,
738 &Session
->MprNotifyInfo
,
739 (PVOID
*)&Session
->Profile
);
745 if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_TIMEOUT
)
748 if (!Session
->Gina
.Functions
.WlxScreenSaverNotify(Session
->Gina
.Context
, &bSecure
))
750 /* Skip start of screen saver */
751 SetEvent(Session
->hEndOfScreenSaver
);
756 DoGenericAction(Session
, WLX_SAS_ACTION_LOCK_WKSTA
);
757 StartScreenSaver(Session
);
760 else if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_ACTIVITY
)
761 SetEvent(Session
->hUserActivity
);
763 DoGenericAction(Session
, wlxAction
);
768 IN PWLSESSION Session
,
771 /* Register Ctrl+Alt+Del Hotkey */
772 if (!RegisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
, MOD_CONTROL
| MOD_ALT
, VK_DELETE
))
774 ERR("WL: Unable to register Ctrl+Alt+Del hotkey!\n");
778 /* Register Ctrl+Shift+Esc (optional) */
779 Session
->TaskManHotkey
= RegisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
, MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
);
780 if (!Session
->TaskManHotkey
)
781 WARN("WL: Warning: Unable to register Ctrl+Alt+Esc hotkey!\n");
787 IN PWLSESSION Session
,
790 /* Unregister hotkeys */
791 UnregisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
);
793 if (Session
->TaskManHotkey
)
794 UnregisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
);
800 CheckForShutdownPrivilege(
801 IN DWORD RequestingProcessId
)
806 PPRIVILEGE_SET PrivSet
;
808 TRACE("CheckForShutdownPrivilege()\n");
810 Process
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, RequestingProcessId
);
813 WARN("OpenProcess() failed with error %lu\n", GetLastError());
814 return STATUS_INVALID_HANDLE
;
816 if (!OpenProcessToken(Process
, TOKEN_QUERY
, &Token
))
818 WARN("OpenProcessToken() failed with error %lu\n", GetLastError());
819 CloseHandle(Process
);
820 return STATUS_INVALID_HANDLE
;
822 CloseHandle(Process
);
823 PrivSet
= HeapAlloc(GetProcessHeap(), 0, sizeof(PRIVILEGE_SET
) + sizeof(LUID_AND_ATTRIBUTES
));
826 ERR("Failed to allocate mem for privilege set\n");
828 return STATUS_NO_MEMORY
;
830 PrivSet
->PrivilegeCount
= 1;
831 PrivSet
->Control
= PRIVILEGE_SET_ALL_NECESSARY
;
832 if (!LookupPrivilegeValue(NULL
, SE_SHUTDOWN_NAME
, &PrivSet
->Privilege
[0].Luid
))
834 WARN("LookupPrivilegeValue() failed with error %lu\n", GetLastError());
835 HeapFree(GetProcessHeap(), 0, PrivSet
);
837 return STATUS_UNSUCCESSFUL
;
839 if (!PrivilegeCheck(Token
, PrivSet
, &CheckResult
))
841 WARN("PrivilegeCheck() failed with error %lu\n", GetLastError());
842 HeapFree(GetProcessHeap(), 0, PrivSet
);
844 return STATUS_ACCESS_DENIED
;
846 HeapFree(GetProcessHeap(), 0, PrivSet
);
851 WARN("SE_SHUTDOWN privilege not enabled\n");
852 return STATUS_ACCESS_DENIED
;
854 return STATUS_SUCCESS
;
859 HandleMessageBeep(UINT uType
)
869 EventName
= L
"SystemDefault";
871 case MB_ICONASTERISK
:
872 EventName
= L
"SystemAsterisk";
874 case MB_ICONEXCLAMATION
:
875 EventName
= L
"SystemExclamation";
878 EventName
= L
"SystemHand";
880 case MB_ICONQUESTION
:
881 EventName
= L
"SystemQuestion";
884 WARN("Unhandled type %d\n", uType
);
885 EventName
= L
"SystemDefault";
888 return PlaySoundRoutine(EventName
, FALSE
, SND_ALIAS
| SND_NOWAIT
| SND_NOSTOP
| SND_ASYNC
);
891 static LRESULT CALLBACK
898 PWLSESSION Session
= (PWLSESSION
)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
906 case MAKELONG(MOD_CONTROL
| MOD_ALT
, VK_DELETE
):
908 TRACE("SAS: CONTROL+ALT+DELETE\n");
909 if (!Session
->Gina
.UseCtrlAltDelete
)
911 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_CTRL_ALT_DEL
, 0);
914 case MAKELONG(MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
):
916 TRACE("SAS: CONTROL+SHIFT+ESCAPE\n");
917 DoGenericAction(Session
, WLX_SAS_ACTION_TASKLIST
);
925 /* Get the session pointer from the create data */
926 Session
= (PWLSESSION
)((LPCREATESTRUCT
)lParam
)->lpCreateParams
;
928 /* Save the Session pointer */
929 SetWindowLongPtrW(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)Session
);
932 return RegisterHotKeys(Session
, hwndDlg
);
937 UnregisterHotKeys(Session
, hwndDlg
);
940 case WM_SETTINGCHANGE
:
942 UINT uiAction
= (UINT
)wParam
;
943 if (uiAction
== SPI_SETSCREENSAVETIMEOUT
944 || uiAction
== SPI_SETSCREENSAVEACTIVE
)
946 SetEvent(Session
->hScreenSaverParametersChanged
);
954 case LN_MESSAGE_BEEP
:
956 return HandleMessageBeep(lParam
);
958 case LN_SHELL_EXITED
:
960 /* lParam is the exit code */
963 SetTimer(hwndDlg
, 1, 1000, NULL
);
967 case LN_START_SCREENSAVE
:
969 BOOL bSecure
= FALSE
;
976 // lParam 1 == Secure
979 if (Session
->Gina
.Functions
.WlxScreenSaverNotify(Session
->Gina
.Context
, &bSecure
))
981 if (bSecure
) DoGenericAction(Session
, WLX_SAS_ACTION_LOCK_WKSTA
);
985 StartScreenSaver(Session
);
991 ERR("WM_LOGONNOTIFY case %d is unimplemented\n", wParam
);
1000 KillTimer(hwndDlg
, 1);
1001 StartUserShell(Session
);
1007 DispatchSAS(Session
, (DWORD
)wParam
);
1010 case PM_WINLOGON_EXITWINDOWS
:
1012 UINT Flags
= (UINT
)lParam
;
1013 UINT Action
= Flags
& EWX_ACTION_MASK
;
1016 /* Check parameters */
1019 case EWX_LOGOFF
: wlxAction
= WLX_SAS_ACTION_LOGOFF
; break;
1020 case EWX_SHUTDOWN
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN
; break;
1021 case EWX_REBOOT
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_REBOOT
; break;
1022 case EWX_POWEROFF
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
; break;
1025 ERR("Invalid ExitWindows action 0x%x\n", Action
);
1026 return STATUS_INVALID_PARAMETER
;
1030 if (WLX_SHUTTINGDOWN(wlxAction
))
1032 NTSTATUS Status
= CheckForShutdownPrivilege((DWORD
)wParam
);
1033 if (!NT_SUCCESS(Status
))
1036 DoGenericAction(Session
, wlxAction
);
1041 return DefWindowProc(hwndDlg
, uMsg
, wParam
, lParam
);
1046 IN OUT PWLSESSION Session
)
1051 if (!SwitchDesktop(Session
->WinlogonDesktop
))
1053 ERR("WL: Failed to switch to winlogon desktop\n");
1057 /* Register SAS window class */
1058 swc
.cbSize
= sizeof(WNDCLASSEXW
);
1059 swc
.style
= CS_SAVEBITS
;
1060 swc
.lpfnWndProc
= SASWindowProc
;
1063 swc
.hInstance
= hAppInstance
;
1066 swc
.hbrBackground
= NULL
;
1067 swc
.lpszMenuName
= NULL
;
1068 swc
.lpszClassName
= WINLOGON_SAS_CLASS
;
1070 if (RegisterClassExW(&swc
) == 0)
1072 ERR("WL: Failed to register SAS window class\n");
1076 /* Create invisible SAS window */
1077 Session
->SASWindow
= CreateWindowExW(
1083 hAppInstance
, Session
);
1084 if (!Session
->SASWindow
)
1086 ERR("WL: Failed to create SAS window\n");
1090 /* Register SAS window to receive SAS notifications */
1091 if (!SetLogonNotifyWindow(Session
->SASWindow
, Session
->InteractiveWindowStation
))
1093 ERR("WL: Failed to register SAS window\n");
1097 if (!SetDefaultLanguage(FALSE
))
1104 UninitializeSAS(Session
);