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 /* FUNCTIONS ****************************************************************/
32 IN OUT PWLSESSION Session
)
37 if (!Session
->Gina
.Functions
.WlxStartApplication
)
40 if (!CreateEnvironmentBlock(
48 ret
= Session
->Gina
.Functions
.WlxStartApplication(
49 Session
->Gina
.Context
,
54 DestroyEnvironmentBlock(lpEnvironment
);
69 UNICODE_STRING ValueString
;
76 BaseKey
= HKEY_CURRENT_USER
;
77 SubKey
= L
"Control Panel\\International";
78 ValueName
= L
"Locale";
82 BaseKey
= HKEY_LOCAL_MACHINE
;
83 SubKey
= L
"System\\CurrentControlSet\\Control\\Nls\\Language";
84 ValueName
= L
"Default";
93 if (rc
!= ERROR_SUCCESS
)
95 TRACE("RegOpenKeyEx() failed with error %lu\n", rc
);
98 rc
= RegQueryValueExW(
105 if (rc
!= ERROR_SUCCESS
)
107 TRACE("RegQueryValueEx() failed with error %lu\n", rc
);
110 else if (dwType
!= REG_SZ
)
112 TRACE("Wrong type for %S\\%S registry entry (got 0x%lx, expected 0x%x)\n",
113 SubKey
, ValueName
, dwType
, REG_SZ
);
117 Value
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
120 TRACE("HeapAlloc() failed\n");
123 rc
= RegQueryValueExW(
130 if (rc
!= ERROR_SUCCESS
)
132 TRACE("RegQueryValueEx() failed with error %lu\n", rc
);
136 /* Convert Value to a Lcid */
137 ValueString
.Length
= ValueString
.MaximumLength
= (USHORT
)dwSize
;
138 ValueString
.Buffer
= Value
;
139 Status
= RtlUnicodeStringToInteger(&ValueString
, 16, (PULONG
)&Lcid
);
140 if (!NT_SUCCESS(Status
))
142 TRACE("RtlUnicodeStringToInteger() failed with status 0x%08lx\n", Status
);
146 TRACE("%s language is 0x%08lx\n",
147 UserProfile
? "User" : "System", Lcid
);
148 Status
= NtSetDefaultLocale(UserProfile
, Lcid
);
149 if (!NT_SUCCESS(Status
))
151 TRACE("NtSetDefaultLocale() failed with status 0x%08lx\n", Status
);
161 HeapFree(GetProcessHeap(), 0, Value
);
167 IN OUT PWLSESSION Session
)
169 PROFILEINFOW ProfileInfo
;
170 LPVOID lpEnvironment
= NULL
;
174 /* Loading personal settings */
175 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_LOADINGYOURPERSONALSETTINGS
);
176 ProfileInfo
.hProfile
= INVALID_HANDLE_VALUE
;
177 if (0 == (Session
->Options
& WLX_LOGON_OPT_NO_PROFILE
))
179 if (Session
->Profile
== NULL
180 || (Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V1_0
181 && Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V2_0
))
183 ERR("WL: Wrong profile\n");
187 /* Load the user profile */
188 ZeroMemory(&ProfileInfo
, sizeof(PROFILEINFOW
));
189 ProfileInfo
.dwSize
= sizeof(PROFILEINFOW
);
190 ProfileInfo
.dwFlags
= 0;
191 ProfileInfo
.lpUserName
= Session
->MprNotifyInfo
.pszUserName
;
192 ProfileInfo
.lpProfilePath
= Session
->Profile
->pszProfile
;
193 if (Session
->Profile
->dwType
>= WLX_PROFILE_TYPE_V2_0
)
195 ProfileInfo
.lpDefaultPath
= Session
->Profile
->pszNetworkDefaultUserProfile
;
196 ProfileInfo
.lpServerName
= Session
->Profile
->pszServerName
;
197 ProfileInfo
.lpPolicyPath
= Session
->Profile
->pszPolicy
;
200 if (!LoadUserProfileW(Session
->UserToken
, &ProfileInfo
))
202 ERR("WL: LoadUserProfileW() failed\n");
207 /* Create environment block for the user */
208 if (!CreateUserEnvironment(Session
))
210 WARN("WL: SetUserEnvironment() failed\n");
214 /* Create environment block for the user */
215 if (!CreateEnvironmentBlock(&lpEnvironment
, Session
->UserToken
, TRUE
))
217 WARN("WL: CreateEnvironmentBlock() failed\n");
221 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_APPLYINGYOURPERSONALSETTINGS
);
222 UpdatePerUserSystemParameters(0, TRUE
);
224 /* Set default language */
225 if (!SetDefaultLanguage(TRUE
))
227 WARN("WL: SetDefaultLanguage() failed\n");
232 /* FIXME: who should do it? winlogon or gina? */
233 /* FIXME: reverting to lower privileges after creating user shell? */
234 RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
236 if (!Session
->Gina
.Functions
.WlxActivateUserShell(
237 Session
->Gina
.Context
,
242 //WCHAR StatusMsg[256];
243 WARN("WL: WlxActivateUserShell() failed\n");
244 //LoadStringW(hAppInstance, IDS_FAILEDACTIVATEUSERSHELL, StatusMsg, sizeof(StatusMsg));
245 //MessageBoxW(0, StatusMsg, NULL, MB_ICONERROR);
249 if (!InitializeScreenSaver(Session
))
250 WARN("WL: Failed to initialize screen saver\n");
252 Session
->hProfileInfo
= ProfileInfo
.hProfile
;
256 if (Session
->Profile
)
258 HeapFree(GetProcessHeap(), 0, Session
->Profile
->pszProfile
);
259 HeapFree(GetProcessHeap(), 0, Session
->Profile
);
261 Session
->Profile
= NULL
;
263 && ProfileInfo
.hProfile
!= INVALID_HANDLE_VALUE
)
265 UnloadUserProfile(WLSession
->UserToken
, ProfileInfo
.hProfile
);
268 DestroyEnvironmentBlock(lpEnvironment
);
269 RemoveStatusMessage(Session
);
272 CloseHandle(Session
->UserToken
);
273 Session
->UserToken
= NULL
;
278 #define EWX_ACTION_MASK 0xffffffeb
279 #define EWX_FLAGS_MASK 0x00000014
281 typedef struct tagLOGOFF_SHUTDOWN_DATA
285 } LOGOFF_SHUTDOWN_DATA
, *PLOGOFF_SHUTDOWN_DATA
;
288 LogoffShutdownThread(LPVOID Parameter
)
290 PLOGOFF_SHUTDOWN_DATA LSData
= (PLOGOFF_SHUTDOWN_DATA
)Parameter
;
292 if (LSData
->Session
->UserToken
!= NULL
&& !ImpersonateLoggedOnUser(LSData
->Session
->UserToken
))
294 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
298 /* Close processes of the interactive user */
300 EWX_INTERNAL_KILL_USER_APPS
| (LSData
->Flags
& EWX_FLAGS_MASK
) |
301 (EWX_LOGOFF
== (LSData
->Flags
& EWX_ACTION_MASK
) ? EWX_INTERNAL_FLAG_LOGOFF
: 0),
304 ERR("Unable to kill user apps, error %lu\n", GetLastError());
309 /* FIXME: Call ExitWindowsEx() to terminate COM processes */
311 if (LSData
->Session
->UserToken
)
319 CreateLogoffSecurityAttributes(
320 OUT PSECURITY_ATTRIBUTES
* ppsa
)
322 /* The following code is not working yet and messy */
323 /* Still, it gives some ideas about data types and functions involved and */
324 /* required to set up a SECURITY_DESCRIPTOR for a SECURITY_ATTRIBUTES */
325 /* instance for a thread, to allow that thread to ImpersonateLoggedOnUser(). */
326 /* Specifically THREAD_SET_THREAD_TOKEN is required. */
327 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
328 PSECURITY_ATTRIBUTES psa
= 0;
331 EXPLICIT_ACCESS Access
;
332 PSID pEveryoneSID
= NULL
;
333 static SID_IDENTIFIER_AUTHORITY WorldAuthority
= { SECURITY_WORLD_SID_AUTHORITY
};
337 // Let's first try to enumerate what kind of data we need for this to ever work:
338 // 1. The Winlogon SID, to be able to give it THREAD_SET_THREAD_TOKEN.
339 // 2. The users SID (the user trying to logoff, or rather shut down the system).
340 // 3. At least two EXPLICIT_ACCESS instances:
341 // 3.1 One for Winlogon itself, giving it the rights
342 // required to THREAD_SET_THREAD_TOKEN (as it's needed to successfully call
343 // ImpersonateLoggedOnUser).
344 // 3.2 One for the user, to allow *that* thread to perform its work.
345 // 4. An ACL to hold the these EXPLICIT_ACCESS ACE's.
346 // 5. A SECURITY_DESCRIPTOR to hold the ACL, and finally.
347 // 6. A SECURITY_ATTRIBUTES instance to pull all of this required stuff
348 // together, to hand it to CreateThread.
350 // However, it seems struct LOGOFF_SHUTDOWN_DATA doesn't contain
351 // these required SID's, why they'd have to be added.
352 // The Winlogon's own SID should probably only be created once,
353 // while the user's SID obviously must be created for each new user.
354 // Might as well store it when the user logs on?
356 if(!AllocateAndInitializeSid(&WorldAuthority
,
362 ERR("Failed to initialize security descriptor for logoff thread!\n");
363 return STATUS_UNSUCCESSFUL
;
366 /* set up the required security attributes to be able to shut down */
367 /* To save space and time, allocate a single block of memory holding */
368 /* both SECURITY_ATTRIBUTES and SECURITY_DESCRIPTOR */
369 pMem
= HeapAlloc(GetProcessHeap(),
371 sizeof(SECURITY_ATTRIBUTES
) +
372 SECURITY_DESCRIPTOR_MIN_LENGTH
+
376 ERR("Failed to allocate memory for logoff security descriptor!\n");
377 return STATUS_NO_MEMORY
;
380 /* Note that the security descriptor needs to be in _absolute_ format, */
381 /* meaning its members must be pointers to other structures, rather */
382 /* than the relative format using offsets */
383 psa
= (PSECURITY_ATTRIBUTES
)pMem
;
384 SecurityDescriptor
= (PSECURITY_DESCRIPTOR
)(pMem
+ sizeof(SECURITY_ATTRIBUTES
));
385 pACL
= (PACL
)(((PBYTE
)SecurityDescriptor
) + SECURITY_DESCRIPTOR_MIN_LENGTH
);
387 // Initialize an EXPLICIT_ACCESS structure for an ACE.
388 // The ACE will allow this thread to log off (and shut down the system, currently).
389 ZeroMemory(&Access
, sizeof(Access
));
390 Access
.grfAccessPermissions
= THREAD_SET_THREAD_TOKEN
;
391 Access
.grfAccessMode
= SET_ACCESS
; // GRANT_ACCESS?
392 Access
.grfInheritance
= NO_INHERITANCE
;
393 Access
.Trustee
.TrusteeForm
= TRUSTEE_IS_SID
;
394 Access
.Trustee
.TrusteeType
= TRUSTEE_IS_WELL_KNOWN_GROUP
;
395 Access
.Trustee
.ptstrName
= pEveryoneSID
;
397 if (SetEntriesInAcl(1, &Access
, NULL
, &pACL
) != ERROR_SUCCESS
)
399 ERR("Failed to set Access Rights for logoff thread. Logging out will most likely fail.\n");
401 HeapFree(GetProcessHeap(), 0, pMem
);
402 return STATUS_UNSUCCESSFUL
;
405 if (!InitializeSecurityDescriptor(SecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
))
407 ERR("Failed to initialize security descriptor for logoff thread!\n");
408 HeapFree(GetProcessHeap(), 0, pMem
);
409 return STATUS_UNSUCCESSFUL
;
412 if (!SetSecurityDescriptorDacl(SecurityDescriptor
,
413 TRUE
, // bDaclPresent flag
415 FALSE
)) // not a default DACL
417 ERR("SetSecurityDescriptorDacl Error %lu\n", GetLastError());
418 HeapFree(GetProcessHeap(), 0, pMem
);
419 return STATUS_UNSUCCESSFUL
;
422 psa
->nLength
= sizeof(SECURITY_ATTRIBUTES
);
423 psa
->lpSecurityDescriptor
= SecurityDescriptor
;
424 psa
->bInheritHandle
= FALSE
;
428 return STATUS_SUCCESS
;
432 DestroyLogoffSecurityAttributes(
433 IN PSECURITY_ATTRIBUTES psa
)
437 HeapFree(GetProcessHeap(), 0, psa
);
444 IN OUT PWLSESSION Session
,
447 PLOGOFF_SHUTDOWN_DATA LSData
;
448 PSECURITY_ATTRIBUTES psa
;
453 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_SAVEYOURSETTINGS
);
455 /* Prepare data for logoff thread */
456 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
459 ERR("Failed to allocate mem for thread data\n");
460 return STATUS_NO_MEMORY
;
462 LSData
->Flags
= Flags
;
463 LSData
->Session
= Session
;
465 Status
= CreateLogoffSecurityAttributes(&psa
);
466 if (!NT_SUCCESS(Status
))
468 ERR("Failed to create a required security descriptor. Status 0x%08lx\n", Status
);
469 HeapFree(GetProcessHeap(), 0, LSData
);
473 /* Run logoff thread */
474 hThread
= CreateThread(psa
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
476 /* we're done with the SECURITY_DESCRIPTOR */
477 DestroyLogoffSecurityAttributes(psa
);
482 ERR("Unable to create logoff thread, error %lu\n", GetLastError());
483 HeapFree(GetProcessHeap(), 0, LSData
);
484 return STATUS_UNSUCCESSFUL
;
486 WaitForSingleObject(hThread
, INFINITE
);
487 HeapFree(GetProcessHeap(), 0, LSData
);
488 if (!GetExitCodeThread(hThread
, &exitCode
))
490 ERR("Unable to get exit code of logoff thread (error %lu)\n", GetLastError());
491 CloseHandle(hThread
);
492 return STATUS_UNSUCCESSFUL
;
494 CloseHandle(hThread
);
497 ERR("Logoff thread returned failure\n");
498 return STATUS_UNSUCCESSFUL
;
501 UnloadUserProfile(Session
->UserToken
, Session
->hProfileInfo
);
502 CloseHandle(Session
->UserToken
);
503 UpdatePerUserSystemParameters(0, FALSE
);
504 Session
->LogonStatus
= WKSTA_IS_LOGGED_OFF
;
505 Session
->UserToken
= NULL
;
506 return STATUS_SUCCESS
;
509 static INT_PTR CALLBACK
510 ShutdownComputerWindowProc(
516 UNREFERENCED_PARAMETER(lParam
);
522 switch (LOWORD(wParam
))
524 case IDC_BTNSHTDOWNCOMPUTER
:
525 EndDialog(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
);
532 RemoveMenu(GetSystemMenu(hwndDlg
, FALSE
), SC_CLOSE
, MF_BYCOMMAND
);
533 SetFocus(GetDlgItem(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
));
542 IN OUT PWLSESSION Session
)
544 if (Session
->SASWindow
)
546 DestroyWindow(Session
->SASWindow
);
547 Session
->SASWindow
= NULL
;
549 if (Session
->hEndOfScreenSaverThread
)
550 SetEvent(Session
->hEndOfScreenSaverThread
);
551 UnregisterClassW(WINLOGON_SAS_CLASS
, hAppInstance
);
556 IN OUT PWLSESSION Session
,
559 PLOGOFF_SHUTDOWN_DATA LSData
;
563 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_REACTOSISSHUTTINGDOWN
);
565 /* Prepare data for shutdown thread */
566 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
569 ERR("Failed to allocate mem for thread data\n");
570 return STATUS_NO_MEMORY
;
572 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
)
573 LSData
->Flags
= EWX_POWEROFF
;
574 else if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
575 LSData
->Flags
= EWX_REBOOT
;
577 LSData
->Flags
= EWX_SHUTDOWN
;
578 LSData
->Session
= Session
;
580 /* Run shutdown thread */
581 hThread
= CreateThread(NULL
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
584 ERR("Unable to create shutdown thread, error %lu\n", GetLastError());
585 HeapFree(GetProcessHeap(), 0, LSData
);
586 return STATUS_UNSUCCESSFUL
;
588 WaitForSingleObject(hThread
, INFINITE
);
589 HeapFree(GetProcessHeap(), 0, LSData
);
590 if (!GetExitCodeThread(hThread
, &exitCode
))
592 ERR("Unable to get exit code of shutdown thread (error %lu)\n", GetLastError());
593 CloseHandle(hThread
);
594 return STATUS_UNSUCCESSFUL
;
596 CloseHandle(hThread
);
599 ERR("Shutdown thread returned failure\n");
600 return STATUS_UNSUCCESSFUL
;
603 /* Destroy SAS window */
604 UninitializeSAS(Session
);
606 FIXME("FIXME: Call SMSS API #1\n");
607 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
608 NtShutdownSystem(ShutdownReboot
);
613 /* FIXME - only show this dialog if it's a shutdown and the computer doesn't support APM */
614 DialogBox(hAppInstance
, MAKEINTRESOURCE(IDD_SHUTDOWNCOMPUTER
), GetDesktopWindow(), ShutdownComputerWindowProc
);
616 NtShutdownSystem(ShutdownNoReboot
);
618 return STATUS_SUCCESS
;
623 IN OUT PWLSESSION Session
,
628 case WLX_SAS_ACTION_LOGON
: /* 0x01 */
629 if (HandleLogon(Session
))
631 SwitchDesktop(Session
->ApplicationDesktop
);
632 Session
->LogonStatus
= WKSTA_IS_LOGGED_ON
;
635 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
637 case WLX_SAS_ACTION_NONE
: /* 0x02 */
639 case WLX_SAS_ACTION_LOCK_WKSTA
: /* 0x03 */
640 if (Session
->Gina
.Functions
.WlxIsLockOk(Session
->Gina
.Context
))
642 SwitchDesktop(WLSession
->WinlogonDesktop
);
643 Session
->LogonStatus
= WKSTA_IS_LOCKED
;
644 Session
->Gina
.Functions
.WlxDisplayLockedNotice(Session
->Gina
.Context
);
647 case WLX_SAS_ACTION_LOGOFF
: /* 0x04 */
648 case WLX_SAS_ACTION_SHUTDOWN
: /* 0x05 */
649 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
: /* 0x0a */
650 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
: /* 0x0b */
651 if (Session
->LogonStatus
!= WKSTA_IS_LOGGED_OFF
)
653 if (!Session
->Gina
.Functions
.WlxIsLogoffOk(Session
->Gina
.Context
))
655 SwitchDesktop(WLSession
->WinlogonDesktop
);
656 Session
->Gina
.Functions
.WlxLogoff(Session
->Gina
.Context
);
657 if (!NT_SUCCESS(HandleLogoff(Session
, EWX_LOGOFF
)))
659 RemoveStatusMessage(Session
);
663 if (WLX_SHUTTINGDOWN(wlxAction
))
665 Session
->Gina
.Functions
.WlxShutdown(Session
->Gina
.Context
, wlxAction
);
666 if (!NT_SUCCESS(HandleShutdown(Session
, wlxAction
)))
668 RemoveStatusMessage(Session
);
669 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
674 RemoveStatusMessage(Session
);
675 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
678 case WLX_SAS_ACTION_TASKLIST
: /* 0x07 */
679 SwitchDesktop(WLSession
->ApplicationDesktop
);
680 StartTaskManager(Session
);
682 case WLX_SAS_ACTION_UNLOCK_WKSTA
: /* 0x08 */
683 SwitchDesktop(WLSession
->ApplicationDesktop
);
684 Session
->LogonStatus
= WKSTA_IS_LOGGED_ON
;
687 WARN("Unknown SAS action 0x%lx\n", wlxAction
);
693 IN OUT PWLSESSION Session
,
696 DWORD wlxAction
= WLX_SAS_ACTION_NONE
;
698 if (Session
->LogonStatus
== WKSTA_IS_LOGGED_ON
)
699 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOnSAS(Session
->Gina
.Context
, dwSasType
, NULL
);
700 else if (Session
->LogonStatus
== WKSTA_IS_LOCKED
)
701 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxWkstaLockedSAS(Session
->Gina
.Context
, dwSasType
);
704 /* Display a new dialog (if necessary) */
707 case WLX_SAS_TYPE_TIMEOUT
: /* 0x00 */
709 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
714 PSID LogonSid
= NULL
; /* FIXME */
716 Session
->Options
= 0;
718 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOutSAS(
719 Session
->Gina
.Context
,
725 &Session
->MprNotifyInfo
,
726 (PVOID
*)&Session
->Profile
);
732 if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_TIMEOUT
)
735 if (!Session
->Gina
.Functions
.WlxScreenSaverNotify(Session
->Gina
.Context
, &bSecure
))
737 /* Skip start of screen saver */
738 SetEvent(Session
->hEndOfScreenSaver
);
743 DoGenericAction(Session
, WLX_SAS_ACTION_LOCK_WKSTA
);
744 StartScreenSaver(Session
);
747 else if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_ACTIVITY
)
748 SetEvent(Session
->hUserActivity
);
750 DoGenericAction(Session
, wlxAction
);
755 IN PWLSESSION Session
,
758 /* Register Ctrl+Alt+Del Hotkey */
759 if (!RegisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
, MOD_CONTROL
| MOD_ALT
, VK_DELETE
))
761 ERR("WL: Unable to register Ctrl+Alt+Del hotkey!\n");
765 /* Register Ctrl+Shift+Esc (optional) */
766 Session
->TaskManHotkey
= RegisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
, MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
);
767 if (!Session
->TaskManHotkey
)
768 WARN("WL: Warning: Unable to register Ctrl+Alt+Esc hotkey!\n");
774 IN PWLSESSION Session
,
777 /* Unregister hotkeys */
778 UnregisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
);
780 if (Session
->TaskManHotkey
)
781 UnregisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
);
787 CheckForShutdownPrivilege(
788 IN DWORD RequestingProcessId
)
793 PPRIVILEGE_SET PrivSet
;
795 TRACE("CheckForShutdownPrivilege()\n");
797 Process
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, RequestingProcessId
);
800 WARN("OpenProcess() failed with error %lu\n", GetLastError());
801 return STATUS_INVALID_HANDLE
;
803 if (!OpenProcessToken(Process
, TOKEN_QUERY
, &Token
))
805 WARN("OpenProcessToken() failed with error %lu\n", GetLastError());
806 CloseHandle(Process
);
807 return STATUS_INVALID_HANDLE
;
809 CloseHandle(Process
);
810 PrivSet
= HeapAlloc(GetProcessHeap(), 0, sizeof(PRIVILEGE_SET
) + sizeof(LUID_AND_ATTRIBUTES
));
813 ERR("Failed to allocate mem for privilege set\n");
815 return STATUS_NO_MEMORY
;
817 PrivSet
->PrivilegeCount
= 1;
818 PrivSet
->Control
= PRIVILEGE_SET_ALL_NECESSARY
;
819 if (!LookupPrivilegeValue(NULL
, SE_SHUTDOWN_NAME
, &PrivSet
->Privilege
[0].Luid
))
821 WARN("LookupPrivilegeValue() failed with error %lu\n", GetLastError());
822 HeapFree(GetProcessHeap(), 0, PrivSet
);
824 return STATUS_UNSUCCESSFUL
;
826 if (!PrivilegeCheck(Token
, PrivSet
, &CheckResult
))
828 WARN("PrivilegeCheck() failed with error %lu\n", GetLastError());
829 HeapFree(GetProcessHeap(), 0, PrivSet
);
831 return STATUS_ACCESS_DENIED
;
833 HeapFree(GetProcessHeap(), 0, PrivSet
);
838 WARN("SE_SHUTDOWN privilege not enabled\n");
839 return STATUS_ACCESS_DENIED
;
841 return STATUS_SUCCESS
;
846 HandleMessageBeep(UINT uType
)
856 EventName
= L
"SystemDefault";
858 case MB_ICONASTERISK
:
859 EventName
= L
"SystemAsterisk";
861 case MB_ICONEXCLAMATION
:
862 EventName
= L
"SystemExclamation";
865 EventName
= L
"SystemHand";
867 case MB_ICONQUESTION
:
868 EventName
= L
"SystemQuestion";
871 WARN("Unhandled type %d\n", uType
);
872 EventName
= L
"SystemDefault";
875 return PlaySoundRoutine(EventName
, FALSE
, SND_ALIAS
| SND_NOWAIT
| SND_NOSTOP
| SND_ASYNC
);
878 static LRESULT CALLBACK
885 PWLSESSION Session
= (PWLSESSION
)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
893 case MAKELONG(MOD_CONTROL
| MOD_ALT
, VK_DELETE
):
895 TRACE("SAS: CONTROL+ALT+DELETE\n");
896 if (!Session
->Gina
.UseCtrlAltDelete
)
898 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_CTRL_ALT_DEL
, 0);
901 case MAKELONG(MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
):
903 TRACE("SAS: CONTROL+SHIFT+ESCAPE\n");
904 DoGenericAction(Session
, WLX_SAS_ACTION_TASKLIST
);
912 /* Get the session pointer from the create data */
913 Session
= (PWLSESSION
)((LPCREATESTRUCT
)lParam
)->lpCreateParams
;
915 /* Save the Session pointer */
916 SetWindowLongPtrW(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)Session
);
919 return RegisterHotKeys(Session
, hwndDlg
);
924 UnregisterHotKeys(Session
, hwndDlg
);
927 case WM_SETTINGCHANGE
:
929 UINT uiAction
= (UINT
)wParam
;
930 if (uiAction
== SPI_SETSCREENSAVETIMEOUT
931 || uiAction
== SPI_SETSCREENSAVEACTIVE
)
933 SetEvent(Session
->hScreenSaverParametersChanged
);
941 case LN_MESSAGE_BEEP
:
943 return HandleMessageBeep(lParam
);
947 ERR("WM_LOGONNOTIFY case %d is unimplemented\n", wParam
);
954 DispatchSAS(Session
, (DWORD
)wParam
);
957 case PM_WINLOGON_EXITWINDOWS
:
959 UINT Flags
= (UINT
)lParam
;
960 UINT Action
= Flags
& EWX_ACTION_MASK
;
963 /* Check parameters */
966 case EWX_LOGOFF
: wlxAction
= WLX_SAS_ACTION_LOGOFF
; break;
967 case EWX_SHUTDOWN
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN
; break;
968 case EWX_REBOOT
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_REBOOT
; break;
969 case EWX_POWEROFF
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
; break;
972 ERR("Invalid ExitWindows action 0x%x\n", Action
);
973 return STATUS_INVALID_PARAMETER
;
977 if (WLX_SHUTTINGDOWN(wlxAction
))
979 NTSTATUS Status
= CheckForShutdownPrivilege((DWORD
)wParam
);
980 if (!NT_SUCCESS(Status
))
983 DoGenericAction(Session
, wlxAction
);
988 return DefWindowProc(hwndDlg
, uMsg
, wParam
, lParam
);
993 IN OUT PWLSESSION Session
)
998 if (!SwitchDesktop(Session
->WinlogonDesktop
))
1000 ERR("WL: Failed to switch to winlogon desktop\n");
1004 /* Register SAS window class */
1005 swc
.cbSize
= sizeof(WNDCLASSEXW
);
1006 swc
.style
= CS_SAVEBITS
;
1007 swc
.lpfnWndProc
= SASWindowProc
;
1010 swc
.hInstance
= hAppInstance
;
1013 swc
.hbrBackground
= NULL
;
1014 swc
.lpszMenuName
= NULL
;
1015 swc
.lpszClassName
= WINLOGON_SAS_CLASS
;
1017 if (RegisterClassExW(&swc
) == 0)
1019 ERR("WL: Failed to register SAS window class\n");
1023 /* Create invisible SAS window */
1024 Session
->SASWindow
= CreateWindowExW(
1030 hAppInstance
, Session
);
1031 if (!Session
->SASWindow
)
1033 ERR("WL: Failed to create SAS window\n");
1037 /* Register SAS window to receive SAS notifications */
1038 if (!SetLogonNotifyWindow(Session
->SASWindow
, Session
->InteractiveWindowStation
))
1040 ERR("WL: Failed to register SAS window\n");
1044 if (!SetDefaultLanguage(FALSE
))
1051 UninitializeSAS(Session
);