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 (!CreateUserEnvironment(Session
))
212 WARN("WL: SetUserEnvironment() failed\n");
216 /* Create environment block for the user */
217 if (!CreateEnvironmentBlock(&lpEnvironment
, Session
->UserToken
, TRUE
))
219 WARN("WL: CreateEnvironmentBlock() failed\n");
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
)
324 /* The following code is not working yet and messy */
325 /* Still, it gives some ideas about data types and functions involved and */
326 /* required to set up a SECURITY_DESCRIPTOR for a SECURITY_ATTRIBUTES */
327 /* instance for a thread, to allow that thread to ImpersonateLoggedOnUser(). */
328 /* Specifically THREAD_SET_THREAD_TOKEN is required. */
329 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
330 PSECURITY_ATTRIBUTES psa
= 0;
333 EXPLICIT_ACCESS Access
;
334 PSID pEveryoneSID
= NULL
;
335 static SID_IDENTIFIER_AUTHORITY WorldAuthority
= { SECURITY_WORLD_SID_AUTHORITY
};
339 // Let's first try to enumerate what kind of data we need for this to ever work:
340 // 1. The Winlogon SID, to be able to give it THREAD_SET_THREAD_TOKEN.
341 // 2. The users SID (the user trying to logoff, or rather shut down the system).
342 // 3. At least two EXPLICIT_ACCESS instances:
343 // 3.1 One for Winlogon itself, giving it the rights
344 // required to THREAD_SET_THREAD_TOKEN (as it's needed to successfully call
345 // ImpersonateLoggedOnUser).
346 // 3.2 One for the user, to allow *that* thread to perform its work.
347 // 4. An ACL to hold the these EXPLICIT_ACCESS ACE's.
348 // 5. A SECURITY_DESCRIPTOR to hold the ACL, and finally.
349 // 6. A SECURITY_ATTRIBUTES instance to pull all of this required stuff
350 // together, to hand it to CreateThread.
352 // However, it seems struct LOGOFF_SHUTDOWN_DATA doesn't contain
353 // these required SID's, why they'd have to be added.
354 // The Winlogon's own SID should probably only be created once,
355 // while the user's SID obviously must be created for each new user.
356 // Might as well store it when the user logs on?
358 if(!AllocateAndInitializeSid(&WorldAuthority
,
364 ERR("Failed to initialize security descriptor for logoff thread!\n");
365 return STATUS_UNSUCCESSFUL
;
368 /* set up the required security attributes to be able to shut down */
369 /* To save space and time, allocate a single block of memory holding */
370 /* both SECURITY_ATTRIBUTES and SECURITY_DESCRIPTOR */
371 pMem
= HeapAlloc(GetProcessHeap(),
373 sizeof(SECURITY_ATTRIBUTES
) +
374 SECURITY_DESCRIPTOR_MIN_LENGTH
+
378 ERR("Failed to allocate memory for logoff security descriptor!\n");
379 return STATUS_NO_MEMORY
;
382 /* Note that the security descriptor needs to be in _absolute_ format, */
383 /* meaning its members must be pointers to other structures, rather */
384 /* than the relative format using offsets */
385 psa
= (PSECURITY_ATTRIBUTES
)pMem
;
386 SecurityDescriptor
= (PSECURITY_DESCRIPTOR
)(pMem
+ sizeof(SECURITY_ATTRIBUTES
));
387 pACL
= (PACL
)(((PBYTE
)SecurityDescriptor
) + SECURITY_DESCRIPTOR_MIN_LENGTH
);
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(&Access
, sizeof(Access
));
392 Access
.grfAccessPermissions
= THREAD_SET_THREAD_TOKEN
;
393 Access
.grfAccessMode
= SET_ACCESS
; // GRANT_ACCESS?
394 Access
.grfInheritance
= NO_INHERITANCE
;
395 Access
.Trustee
.TrusteeForm
= TRUSTEE_IS_SID
;
396 Access
.Trustee
.TrusteeType
= TRUSTEE_IS_WELL_KNOWN_GROUP
;
397 Access
.Trustee
.ptstrName
= pEveryoneSID
;
399 if (SetEntriesInAcl(1, &Access
, NULL
, &pACL
) != ERROR_SUCCESS
)
401 ERR("Failed to set Access Rights for logoff thread. Logging out will most likely fail.\n");
403 HeapFree(GetProcessHeap(), 0, pMem
);
404 return STATUS_UNSUCCESSFUL
;
407 if (!InitializeSecurityDescriptor(SecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
))
409 ERR("Failed to initialize security descriptor for logoff thread!\n");
410 HeapFree(GetProcessHeap(), 0, pMem
);
411 return STATUS_UNSUCCESSFUL
;
414 if (!SetSecurityDescriptorDacl(SecurityDescriptor
,
415 TRUE
, // bDaclPresent flag
417 FALSE
)) // not a default DACL
419 ERR("SetSecurityDescriptorDacl Error %lu\n", GetLastError());
420 HeapFree(GetProcessHeap(), 0, pMem
);
421 return STATUS_UNSUCCESSFUL
;
424 psa
->nLength
= sizeof(SECURITY_ATTRIBUTES
);
425 psa
->lpSecurityDescriptor
= SecurityDescriptor
;
426 psa
->bInheritHandle
= FALSE
;
430 return STATUS_SUCCESS
;
434 DestroyLogoffSecurityAttributes(
435 IN PSECURITY_ATTRIBUTES psa
)
439 HeapFree(GetProcessHeap(), 0, psa
);
446 IN OUT PWLSESSION Session
,
449 PLOGOFF_SHUTDOWN_DATA LSData
;
450 PSECURITY_ATTRIBUTES psa
;
455 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_SAVEYOURSETTINGS
);
457 /* Prepare data for logoff thread */
458 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
461 ERR("Failed to allocate mem for thread data\n");
462 return STATUS_NO_MEMORY
;
464 LSData
->Flags
= Flags
;
465 LSData
->Session
= Session
;
467 Status
= CreateLogoffSecurityAttributes(&psa
);
468 if (!NT_SUCCESS(Status
))
470 ERR("Failed to create a required security descriptor. Status 0x%08lx\n", Status
);
471 HeapFree(GetProcessHeap(), 0, LSData
);
475 /* Run logoff thread */
476 hThread
= CreateThread(psa
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
478 /* we're done with the SECURITY_DESCRIPTOR */
479 DestroyLogoffSecurityAttributes(psa
);
484 ERR("Unable to create logoff thread, error %lu\n", GetLastError());
485 HeapFree(GetProcessHeap(), 0, LSData
);
486 return STATUS_UNSUCCESSFUL
;
488 WaitForSingleObject(hThread
, INFINITE
);
489 HeapFree(GetProcessHeap(), 0, LSData
);
490 if (!GetExitCodeThread(hThread
, &exitCode
))
492 ERR("Unable to get exit code of logoff thread (error %lu)\n", GetLastError());
493 CloseHandle(hThread
);
494 return STATUS_UNSUCCESSFUL
;
496 CloseHandle(hThread
);
499 ERR("Logoff thread returned failure\n");
500 return STATUS_UNSUCCESSFUL
;
503 UnloadUserProfile(Session
->UserToken
, Session
->hProfileInfo
);
504 CloseHandle(Session
->UserToken
);
505 UpdatePerUserSystemParameters(0, FALSE
);
506 Session
->LogonStatus
= WKSTA_IS_LOGGED_OFF
;
507 Session
->UserToken
= NULL
;
508 return STATUS_SUCCESS
;
511 static INT_PTR CALLBACK
512 ShutdownComputerWindowProc(
518 UNREFERENCED_PARAMETER(lParam
);
524 switch (LOWORD(wParam
))
526 case IDC_BTNSHTDOWNCOMPUTER
:
527 EndDialog(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
);
534 RemoveMenu(GetSystemMenu(hwndDlg
, FALSE
), SC_CLOSE
, MF_BYCOMMAND
);
535 SetFocus(GetDlgItem(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
));
544 IN OUT PWLSESSION Session
)
546 if (Session
->SASWindow
)
548 DestroyWindow(Session
->SASWindow
);
549 Session
->SASWindow
= NULL
;
551 if (Session
->hEndOfScreenSaverThread
)
552 SetEvent(Session
->hEndOfScreenSaverThread
);
553 UnregisterClassW(WINLOGON_SAS_CLASS
, hAppInstance
);
558 IN OUT PWLSESSION Session
,
561 PLOGOFF_SHUTDOWN_DATA LSData
;
565 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_REACTOSISSHUTTINGDOWN
);
567 /* Prepare data for shutdown thread */
568 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
571 ERR("Failed to allocate mem for thread data\n");
572 return STATUS_NO_MEMORY
;
574 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
)
575 LSData
->Flags
= EWX_POWEROFF
;
576 else if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
577 LSData
->Flags
= EWX_REBOOT
;
579 LSData
->Flags
= EWX_SHUTDOWN
;
580 LSData
->Session
= Session
;
582 /* Run shutdown thread */
583 hThread
= CreateThread(NULL
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
586 ERR("Unable to create shutdown thread, error %lu\n", GetLastError());
587 HeapFree(GetProcessHeap(), 0, LSData
);
588 return STATUS_UNSUCCESSFUL
;
590 WaitForSingleObject(hThread
, INFINITE
);
591 HeapFree(GetProcessHeap(), 0, LSData
);
592 if (!GetExitCodeThread(hThread
, &exitCode
))
594 ERR("Unable to get exit code of shutdown thread (error %lu)\n", GetLastError());
595 CloseHandle(hThread
);
596 return STATUS_UNSUCCESSFUL
;
598 CloseHandle(hThread
);
601 ERR("Shutdown thread returned failure\n");
602 return STATUS_UNSUCCESSFUL
;
605 /* Destroy SAS window */
606 UninitializeSAS(Session
);
608 FIXME("FIXME: Call SMSS API #1\n");
609 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
610 NtShutdownSystem(ShutdownReboot
);
615 /* FIXME - only show this dialog if it's a shutdown and the computer doesn't support APM */
616 DialogBox(hAppInstance
, MAKEINTRESOURCE(IDD_SHUTDOWNCOMPUTER
), GetDesktopWindow(), ShutdownComputerWindowProc
);
618 NtShutdownSystem(ShutdownNoReboot
);
620 return STATUS_SUCCESS
;
625 IN OUT PWLSESSION Session
,
630 case WLX_SAS_ACTION_LOGON
: /* 0x01 */
631 if (HandleLogon(Session
))
633 SwitchDesktop(Session
->ApplicationDesktop
);
634 Session
->LogonStatus
= WKSTA_IS_LOGGED_ON
;
637 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
639 case WLX_SAS_ACTION_NONE
: /* 0x02 */
641 case WLX_SAS_ACTION_LOCK_WKSTA
: /* 0x03 */
642 if (Session
->Gina
.Functions
.WlxIsLockOk(Session
->Gina
.Context
))
644 SwitchDesktop(WLSession
->WinlogonDesktop
);
645 Session
->LogonStatus
= WKSTA_IS_LOCKED
;
646 Session
->Gina
.Functions
.WlxDisplayLockedNotice(Session
->Gina
.Context
);
649 case WLX_SAS_ACTION_LOGOFF
: /* 0x04 */
650 case WLX_SAS_ACTION_SHUTDOWN
: /* 0x05 */
651 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
: /* 0x0a */
652 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
: /* 0x0b */
653 if (Session
->LogonStatus
!= WKSTA_IS_LOGGED_OFF
)
655 if (!Session
->Gina
.Functions
.WlxIsLogoffOk(Session
->Gina
.Context
))
657 SwitchDesktop(WLSession
->WinlogonDesktop
);
658 Session
->Gina
.Functions
.WlxLogoff(Session
->Gina
.Context
);
659 if (!NT_SUCCESS(HandleLogoff(Session
, EWX_LOGOFF
)))
661 RemoveStatusMessage(Session
);
665 if (WLX_SHUTTINGDOWN(wlxAction
))
667 Session
->Gina
.Functions
.WlxShutdown(Session
->Gina
.Context
, wlxAction
);
668 if (!NT_SUCCESS(HandleShutdown(Session
, wlxAction
)))
670 RemoveStatusMessage(Session
);
671 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
676 RemoveStatusMessage(Session
);
677 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
680 case WLX_SAS_ACTION_TASKLIST
: /* 0x07 */
681 SwitchDesktop(WLSession
->ApplicationDesktop
);
682 StartTaskManager(Session
);
684 case WLX_SAS_ACTION_UNLOCK_WKSTA
: /* 0x08 */
685 SwitchDesktop(WLSession
->ApplicationDesktop
);
686 Session
->LogonStatus
= WKSTA_IS_LOGGED_ON
;
689 WARN("Unknown SAS action 0x%lx\n", wlxAction
);
695 IN OUT PWLSESSION Session
,
698 DWORD wlxAction
= WLX_SAS_ACTION_NONE
;
700 if (Session
->LogonStatus
== WKSTA_IS_LOGGED_ON
)
701 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOnSAS(Session
->Gina
.Context
, dwSasType
, NULL
);
702 else if (Session
->LogonStatus
== WKSTA_IS_LOCKED
)
703 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxWkstaLockedSAS(Session
->Gina
.Context
, dwSasType
);
706 /* Display a new dialog (if necessary) */
709 case WLX_SAS_TYPE_TIMEOUT
: /* 0x00 */
711 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
716 PSID LogonSid
= NULL
; /* FIXME */
718 Session
->Options
= 0;
720 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOutSAS(
721 Session
->Gina
.Context
,
727 &Session
->MprNotifyInfo
,
728 (PVOID
*)&Session
->Profile
);
734 if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_TIMEOUT
)
737 if (!Session
->Gina
.Functions
.WlxScreenSaverNotify(Session
->Gina
.Context
, &bSecure
))
739 /* Skip start of screen saver */
740 SetEvent(Session
->hEndOfScreenSaver
);
745 DoGenericAction(Session
, WLX_SAS_ACTION_LOCK_WKSTA
);
746 StartScreenSaver(Session
);
749 else if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_ACTIVITY
)
750 SetEvent(Session
->hUserActivity
);
752 DoGenericAction(Session
, wlxAction
);
757 IN PWLSESSION Session
,
760 /* Register Ctrl+Alt+Del Hotkey */
761 if (!RegisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
, MOD_CONTROL
| MOD_ALT
, VK_DELETE
))
763 ERR("WL: Unable to register Ctrl+Alt+Del hotkey!\n");
767 /* Register Ctrl+Shift+Esc (optional) */
768 Session
->TaskManHotkey
= RegisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
, MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
);
769 if (!Session
->TaskManHotkey
)
770 WARN("WL: Warning: Unable to register Ctrl+Alt+Esc hotkey!\n");
776 IN PWLSESSION Session
,
779 /* Unregister hotkeys */
780 UnregisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
);
782 if (Session
->TaskManHotkey
)
783 UnregisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
);
789 CheckForShutdownPrivilege(
790 IN DWORD RequestingProcessId
)
795 PPRIVILEGE_SET PrivSet
;
797 TRACE("CheckForShutdownPrivilege()\n");
799 Process
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, RequestingProcessId
);
802 WARN("OpenProcess() failed with error %lu\n", GetLastError());
803 return STATUS_INVALID_HANDLE
;
805 if (!OpenProcessToken(Process
, TOKEN_QUERY
, &Token
))
807 WARN("OpenProcessToken() failed with error %lu\n", GetLastError());
808 CloseHandle(Process
);
809 return STATUS_INVALID_HANDLE
;
811 CloseHandle(Process
);
812 PrivSet
= HeapAlloc(GetProcessHeap(), 0, sizeof(PRIVILEGE_SET
) + sizeof(LUID_AND_ATTRIBUTES
));
815 ERR("Failed to allocate mem for privilege set\n");
817 return STATUS_NO_MEMORY
;
819 PrivSet
->PrivilegeCount
= 1;
820 PrivSet
->Control
= PRIVILEGE_SET_ALL_NECESSARY
;
821 if (!LookupPrivilegeValue(NULL
, SE_SHUTDOWN_NAME
, &PrivSet
->Privilege
[0].Luid
))
823 WARN("LookupPrivilegeValue() failed with error %lu\n", GetLastError());
824 HeapFree(GetProcessHeap(), 0, PrivSet
);
826 return STATUS_UNSUCCESSFUL
;
828 if (!PrivilegeCheck(Token
, PrivSet
, &CheckResult
))
830 WARN("PrivilegeCheck() failed with error %lu\n", GetLastError());
831 HeapFree(GetProcessHeap(), 0, PrivSet
);
833 return STATUS_ACCESS_DENIED
;
835 HeapFree(GetProcessHeap(), 0, PrivSet
);
840 WARN("SE_SHUTDOWN privilege not enabled\n");
841 return STATUS_ACCESS_DENIED
;
843 return STATUS_SUCCESS
;
846 static LRESULT CALLBACK
853 PWLSESSION Session
= (PWLSESSION
)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
861 case MAKELONG(MOD_CONTROL
| MOD_ALT
, VK_DELETE
):
863 TRACE("SAS: CONTROL+ALT+DELETE\n");
864 if (!Session
->Gina
.UseCtrlAltDelete
)
866 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_CTRL_ALT_DEL
, 0);
869 case MAKELONG(MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
):
871 TRACE("SAS: CONTROL+SHIFT+ESCAPE\n");
872 DoGenericAction(Session
, WLX_SAS_ACTION_TASKLIST
);
880 /* Get the session pointer from the create data */
881 Session
= (PWLSESSION
)((LPCREATESTRUCT
)lParam
)->lpCreateParams
;
883 /* Save the Session pointer */
884 SetWindowLongPtrW(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)Session
);
887 return RegisterHotKeys(Session
, hwndDlg
);
892 UnregisterHotKeys(Session
, hwndDlg
);
895 case WM_SETTINGCHANGE
:
897 UINT uiAction
= (UINT
)wParam
;
898 if (uiAction
== SPI_SETSCREENSAVETIMEOUT
899 || uiAction
== SPI_SETSCREENSAVEACTIVE
)
901 SetEvent(Session
->hScreenSaverParametersChanged
);
907 DispatchSAS(Session
, (DWORD
)wParam
);
910 case PM_WINLOGON_EXITWINDOWS
:
912 UINT Flags
= (UINT
)lParam
;
913 UINT Action
= Flags
& EWX_ACTION_MASK
;
916 /* Check parameters */
919 case EWX_LOGOFF
: wlxAction
= WLX_SAS_ACTION_LOGOFF
; break;
920 case EWX_SHUTDOWN
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN
; break;
921 case EWX_REBOOT
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_REBOOT
; break;
922 case EWX_POWEROFF
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
; break;
925 ERR("Invalid ExitWindows action 0x%x\n", Action
);
926 return STATUS_INVALID_PARAMETER
;
930 if (WLX_SHUTTINGDOWN(wlxAction
))
932 NTSTATUS Status
= CheckForShutdownPrivilege((DWORD
)wParam
);
933 if (!NT_SUCCESS(Status
))
936 DoGenericAction(Session
, wlxAction
);
941 return DefWindowProc(hwndDlg
, uMsg
, wParam
, lParam
);
946 IN OUT PWLSESSION Session
)
951 if (!SwitchDesktop(Session
->WinlogonDesktop
))
953 ERR("WL: Failed to switch to winlogon desktop\n");
957 /* Register SAS window class */
958 swc
.cbSize
= sizeof(WNDCLASSEXW
);
959 swc
.style
= CS_SAVEBITS
;
960 swc
.lpfnWndProc
= SASWindowProc
;
963 swc
.hInstance
= hAppInstance
;
966 swc
.hbrBackground
= NULL
;
967 swc
.lpszMenuName
= NULL
;
968 swc
.lpszClassName
= WINLOGON_SAS_CLASS
;
970 if (RegisterClassExW(&swc
) == 0)
972 ERR("WL: Failed to register SAS window class\n");
976 /* Create invisible SAS window */
977 Session
->SASWindow
= CreateWindowExW(
983 hAppInstance
, Session
);
984 if (!Session
->SASWindow
)
986 ERR("WL: Failed to create SAS window\n");
990 /* Register SAS window to receive SAS notifications */
991 if (!SetLogonNotifyWindow(Session
->SASWindow
, Session
->InteractiveWindowStation
))
993 ERR("WL: Failed to register SAS window\n");
997 if (!SetDefaultLanguage(FALSE
))
1004 UninitializeSAS(Session
);