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
);
60 IN OUT PWLSESSION Session
)
62 LPVOID lpEnvironment
= NULL
;
66 /* Create environment block for the user */
67 if (!CreateEnvironmentBlock(&lpEnvironment
, Session
->UserToken
, TRUE
))
69 WARN("WL: CreateEnvironmentBlock() failed\n");
74 /* FIXME: who should do it? winlogon or gina? */
75 /* FIXME: reverting to lower privileges after creating user shell? */
76 RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
78 ret
= Session
->Gina
.Functions
.WlxActivateUserShell(
79 Session
->Gina
.Context
,
84 DestroyEnvironmentBlock(lpEnvironment
);
100 UNICODE_STRING ValueString
;
107 BaseKey
= HKEY_CURRENT_USER
;
108 SubKey
= L
"Control Panel\\International";
109 ValueName
= L
"Locale";
113 BaseKey
= HKEY_LOCAL_MACHINE
;
114 SubKey
= L
"System\\CurrentControlSet\\Control\\Nls\\Language";
115 ValueName
= L
"Default";
124 if (rc
!= ERROR_SUCCESS
)
126 TRACE("RegOpenKeyEx() failed with error %lu\n", rc
);
129 rc
= RegQueryValueExW(
136 if (rc
!= ERROR_SUCCESS
)
138 TRACE("RegQueryValueEx() failed with error %lu\n", rc
);
141 else if (dwType
!= REG_SZ
)
143 TRACE("Wrong type for %S\\%S registry entry (got 0x%lx, expected 0x%x)\n",
144 SubKey
, ValueName
, dwType
, REG_SZ
);
148 Value
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
151 TRACE("HeapAlloc() failed\n");
154 rc
= RegQueryValueExW(
161 if (rc
!= ERROR_SUCCESS
)
163 TRACE("RegQueryValueEx() failed with error %lu\n", rc
);
167 /* Convert Value to a Lcid */
168 ValueString
.Length
= ValueString
.MaximumLength
= (USHORT
)dwSize
;
169 ValueString
.Buffer
= Value
;
170 Status
= RtlUnicodeStringToInteger(&ValueString
, 16, (PULONG
)&Lcid
);
171 if (!NT_SUCCESS(Status
))
173 TRACE("RtlUnicodeStringToInteger() failed with status 0x%08lx\n", Status
);
177 TRACE("%s language is 0x%08lx\n",
178 UserProfile
? "User" : "System", Lcid
);
179 Status
= NtSetDefaultLocale(UserProfile
, Lcid
);
180 if (!NT_SUCCESS(Status
))
182 TRACE("NtSetDefaultLocale() failed with status 0x%08lx\n", Status
);
192 HeapFree(GetProcessHeap(), 0, Value
);
198 IN OUT PWLSESSION Session
)
200 PROFILEINFOW ProfileInfo
;
203 /* Loading personal settings */
204 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_LOADINGYOURPERSONALSETTINGS
);
205 ProfileInfo
.hProfile
= INVALID_HANDLE_VALUE
;
206 if (0 == (Session
->Options
& WLX_LOGON_OPT_NO_PROFILE
))
208 if (Session
->Profile
== NULL
209 || (Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V1_0
210 && Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V2_0
))
212 ERR("WL: Wrong profile\n");
216 /* Load the user profile */
217 ZeroMemory(&ProfileInfo
, sizeof(PROFILEINFOW
));
218 ProfileInfo
.dwSize
= sizeof(PROFILEINFOW
);
219 ProfileInfo
.dwFlags
= 0;
220 ProfileInfo
.lpUserName
= Session
->MprNotifyInfo
.pszUserName
;
221 ProfileInfo
.lpProfilePath
= Session
->Profile
->pszProfile
;
222 if (Session
->Profile
->dwType
>= WLX_PROFILE_TYPE_V2_0
)
224 ProfileInfo
.lpDefaultPath
= Session
->Profile
->pszNetworkDefaultUserProfile
;
225 ProfileInfo
.lpServerName
= Session
->Profile
->pszServerName
;
226 ProfileInfo
.lpPolicyPath
= Session
->Profile
->pszPolicy
;
229 if (!LoadUserProfileW(Session
->UserToken
, &ProfileInfo
))
231 ERR("WL: LoadUserProfileW() failed\n");
236 /* Create environment block for the user */
237 if (!CreateUserEnvironment(Session
))
239 WARN("WL: SetUserEnvironment() failed\n");
243 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_APPLYINGYOURPERSONALSETTINGS
);
244 UpdatePerUserSystemParameters(0, TRUE
);
246 /* Set default language */
247 if (!SetDefaultLanguage(TRUE
))
249 WARN("WL: SetDefaultLanguage() failed\n");
253 if (!StartUserShell(Session
))
255 //WCHAR StatusMsg[256];
256 WARN("WL: WlxActivateUserShell() failed\n");
257 //LoadStringW(hAppInstance, IDS_FAILEDACTIVATEUSERSHELL, StatusMsg, sizeof(StatusMsg));
258 //MessageBoxW(0, StatusMsg, NULL, MB_ICONERROR);
262 if (!InitializeScreenSaver(Session
))
263 WARN("WL: Failed to initialize screen saver\n");
265 Session
->hProfileInfo
= ProfileInfo
.hProfile
;
269 if (Session
->Profile
)
271 HeapFree(GetProcessHeap(), 0, Session
->Profile
->pszProfile
);
272 HeapFree(GetProcessHeap(), 0, Session
->Profile
);
274 Session
->Profile
= NULL
;
276 && ProfileInfo
.hProfile
!= INVALID_HANDLE_VALUE
)
278 UnloadUserProfile(WLSession
->UserToken
, ProfileInfo
.hProfile
);
280 RemoveStatusMessage(Session
);
283 CloseHandle(Session
->UserToken
);
284 Session
->UserToken
= NULL
;
289 #define EWX_ACTION_MASK 0xffffffeb
290 #define EWX_FLAGS_MASK 0x00000014
292 typedef struct tagLOGOFF_SHUTDOWN_DATA
296 } LOGOFF_SHUTDOWN_DATA
, *PLOGOFF_SHUTDOWN_DATA
;
299 LogoffShutdownThread(LPVOID Parameter
)
301 PLOGOFF_SHUTDOWN_DATA LSData
= (PLOGOFF_SHUTDOWN_DATA
)Parameter
;
303 if (LSData
->Session
->UserToken
!= NULL
&& !ImpersonateLoggedOnUser(LSData
->Session
->UserToken
))
305 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
309 /* Close processes of the interactive user */
311 EWX_INTERNAL_KILL_USER_APPS
| (LSData
->Flags
& EWX_FLAGS_MASK
) |
312 (EWX_LOGOFF
== (LSData
->Flags
& EWX_ACTION_MASK
) ? EWX_INTERNAL_FLAG_LOGOFF
: 0),
315 ERR("Unable to kill user apps, error %lu\n", GetLastError());
320 /* FIXME: Call ExitWindowsEx() to terminate COM processes */
322 if (LSData
->Session
->UserToken
)
330 CreateLogoffSecurityAttributes(
331 OUT PSECURITY_ATTRIBUTES
* ppsa
)
333 /* The following code is not working yet and messy */
334 /* Still, it gives some ideas about data types and functions involved and */
335 /* required to set up a SECURITY_DESCRIPTOR for a SECURITY_ATTRIBUTES */
336 /* instance for a thread, to allow that thread to ImpersonateLoggedOnUser(). */
337 /* Specifically THREAD_SET_THREAD_TOKEN is required. */
338 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
339 PSECURITY_ATTRIBUTES psa
= 0;
342 EXPLICIT_ACCESS Access
;
343 PSID pEveryoneSID
= NULL
;
344 static SID_IDENTIFIER_AUTHORITY WorldAuthority
= { SECURITY_WORLD_SID_AUTHORITY
};
348 // Let's first try to enumerate what kind of data we need for this to ever work:
349 // 1. The Winlogon SID, to be able to give it THREAD_SET_THREAD_TOKEN.
350 // 2. The users SID (the user trying to logoff, or rather shut down the system).
351 // 3. At least two EXPLICIT_ACCESS instances:
352 // 3.1 One for Winlogon itself, giving it the rights
353 // required to THREAD_SET_THREAD_TOKEN (as it's needed to successfully call
354 // ImpersonateLoggedOnUser).
355 // 3.2 One for the user, to allow *that* thread to perform its work.
356 // 4. An ACL to hold the these EXPLICIT_ACCESS ACE's.
357 // 5. A SECURITY_DESCRIPTOR to hold the ACL, and finally.
358 // 6. A SECURITY_ATTRIBUTES instance to pull all of this required stuff
359 // together, to hand it to CreateThread.
361 // However, it seems struct LOGOFF_SHUTDOWN_DATA doesn't contain
362 // these required SID's, why they'd have to be added.
363 // The Winlogon's own SID should probably only be created once,
364 // while the user's SID obviously must be created for each new user.
365 // Might as well store it when the user logs on?
367 if(!AllocateAndInitializeSid(&WorldAuthority
,
373 ERR("Failed to initialize security descriptor for logoff thread!\n");
374 return STATUS_UNSUCCESSFUL
;
377 /* set up the required security attributes to be able to shut down */
378 /* To save space and time, allocate a single block of memory holding */
379 /* both SECURITY_ATTRIBUTES and SECURITY_DESCRIPTOR */
380 pMem
= HeapAlloc(GetProcessHeap(),
382 sizeof(SECURITY_ATTRIBUTES
) +
383 SECURITY_DESCRIPTOR_MIN_LENGTH
+
387 ERR("Failed to allocate memory for logoff security descriptor!\n");
388 return STATUS_NO_MEMORY
;
391 /* Note that the security descriptor needs to be in _absolute_ format, */
392 /* meaning its members must be pointers to other structures, rather */
393 /* than the relative format using offsets */
394 psa
= (PSECURITY_ATTRIBUTES
)pMem
;
395 SecurityDescriptor
= (PSECURITY_DESCRIPTOR
)(pMem
+ sizeof(SECURITY_ATTRIBUTES
));
396 pACL
= (PACL
)(((PBYTE
)SecurityDescriptor
) + SECURITY_DESCRIPTOR_MIN_LENGTH
);
398 // Initialize an EXPLICIT_ACCESS structure for an ACE.
399 // The ACE will allow this thread to log off (and shut down the system, currently).
400 ZeroMemory(&Access
, sizeof(Access
));
401 Access
.grfAccessPermissions
= THREAD_SET_THREAD_TOKEN
;
402 Access
.grfAccessMode
= SET_ACCESS
; // GRANT_ACCESS?
403 Access
.grfInheritance
= NO_INHERITANCE
;
404 Access
.Trustee
.TrusteeForm
= TRUSTEE_IS_SID
;
405 Access
.Trustee
.TrusteeType
= TRUSTEE_IS_WELL_KNOWN_GROUP
;
406 Access
.Trustee
.ptstrName
= pEveryoneSID
;
408 if (SetEntriesInAcl(1, &Access
, NULL
, &pACL
) != ERROR_SUCCESS
)
410 ERR("Failed to set Access Rights for logoff thread. Logging out will most likely fail.\n");
412 HeapFree(GetProcessHeap(), 0, pMem
);
413 return STATUS_UNSUCCESSFUL
;
416 if (!InitializeSecurityDescriptor(SecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
))
418 ERR("Failed to initialize security descriptor for logoff thread!\n");
419 HeapFree(GetProcessHeap(), 0, pMem
);
420 return STATUS_UNSUCCESSFUL
;
423 if (!SetSecurityDescriptorDacl(SecurityDescriptor
,
424 TRUE
, // bDaclPresent flag
426 FALSE
)) // not a default DACL
428 ERR("SetSecurityDescriptorDacl Error %lu\n", GetLastError());
429 HeapFree(GetProcessHeap(), 0, pMem
);
430 return STATUS_UNSUCCESSFUL
;
433 psa
->nLength
= sizeof(SECURITY_ATTRIBUTES
);
434 psa
->lpSecurityDescriptor
= SecurityDescriptor
;
435 psa
->bInheritHandle
= FALSE
;
439 return STATUS_SUCCESS
;
443 DestroyLogoffSecurityAttributes(
444 IN PSECURITY_ATTRIBUTES psa
)
448 HeapFree(GetProcessHeap(), 0, psa
);
455 IN OUT PWLSESSION Session
,
458 PLOGOFF_SHUTDOWN_DATA LSData
;
459 PSECURITY_ATTRIBUTES psa
;
464 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_SAVEYOURSETTINGS
);
466 /* Prepare data for logoff thread */
467 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
470 ERR("Failed to allocate mem for thread data\n");
471 return STATUS_NO_MEMORY
;
473 LSData
->Flags
= Flags
;
474 LSData
->Session
= Session
;
476 Status
= CreateLogoffSecurityAttributes(&psa
);
477 if (!NT_SUCCESS(Status
))
479 ERR("Failed to create a required security descriptor. Status 0x%08lx\n", Status
);
480 HeapFree(GetProcessHeap(), 0, LSData
);
484 /* Run logoff thread */
485 hThread
= CreateThread(psa
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
487 /* we're done with the SECURITY_DESCRIPTOR */
488 DestroyLogoffSecurityAttributes(psa
);
493 ERR("Unable to create logoff thread, error %lu\n", GetLastError());
494 HeapFree(GetProcessHeap(), 0, LSData
);
495 return STATUS_UNSUCCESSFUL
;
497 WaitForSingleObject(hThread
, INFINITE
);
498 HeapFree(GetProcessHeap(), 0, LSData
);
499 if (!GetExitCodeThread(hThread
, &exitCode
))
501 ERR("Unable to get exit code of logoff thread (error %lu)\n", GetLastError());
502 CloseHandle(hThread
);
503 return STATUS_UNSUCCESSFUL
;
505 CloseHandle(hThread
);
508 ERR("Logoff thread returned failure\n");
509 return STATUS_UNSUCCESSFUL
;
512 UnloadUserProfile(Session
->UserToken
, Session
->hProfileInfo
);
513 CloseHandle(Session
->UserToken
);
514 UpdatePerUserSystemParameters(0, FALSE
);
515 Session
->LogonStatus
= WKSTA_IS_LOGGED_OFF
;
516 Session
->UserToken
= NULL
;
517 return STATUS_SUCCESS
;
520 static INT_PTR CALLBACK
521 ShutdownComputerWindowProc(
527 UNREFERENCED_PARAMETER(lParam
);
533 switch (LOWORD(wParam
))
535 case IDC_BTNSHTDOWNCOMPUTER
:
536 EndDialog(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
);
543 RemoveMenu(GetSystemMenu(hwndDlg
, FALSE
), SC_CLOSE
, MF_BYCOMMAND
);
544 SetFocus(GetDlgItem(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
));
553 IN OUT PWLSESSION Session
)
555 if (Session
->SASWindow
)
557 DestroyWindow(Session
->SASWindow
);
558 Session
->SASWindow
= NULL
;
560 if (Session
->hEndOfScreenSaverThread
)
561 SetEvent(Session
->hEndOfScreenSaverThread
);
562 UnregisterClassW(WINLOGON_SAS_CLASS
, hAppInstance
);
567 IN OUT PWLSESSION Session
,
570 PLOGOFF_SHUTDOWN_DATA LSData
;
574 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_REACTOSISSHUTTINGDOWN
);
576 /* Prepare data for shutdown thread */
577 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
580 ERR("Failed to allocate mem for thread data\n");
581 return STATUS_NO_MEMORY
;
583 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
)
584 LSData
->Flags
= EWX_POWEROFF
;
585 else if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
586 LSData
->Flags
= EWX_REBOOT
;
588 LSData
->Flags
= EWX_SHUTDOWN
;
589 LSData
->Session
= Session
;
591 /* Run shutdown thread */
592 hThread
= CreateThread(NULL
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
595 ERR("Unable to create shutdown thread, error %lu\n", GetLastError());
596 HeapFree(GetProcessHeap(), 0, LSData
);
597 return STATUS_UNSUCCESSFUL
;
599 WaitForSingleObject(hThread
, INFINITE
);
600 HeapFree(GetProcessHeap(), 0, LSData
);
601 if (!GetExitCodeThread(hThread
, &exitCode
))
603 ERR("Unable to get exit code of shutdown thread (error %lu)\n", GetLastError());
604 CloseHandle(hThread
);
605 return STATUS_UNSUCCESSFUL
;
607 CloseHandle(hThread
);
610 ERR("Shutdown thread returned failure\n");
611 return STATUS_UNSUCCESSFUL
;
614 /* Destroy SAS window */
615 UninitializeSAS(Session
);
617 FIXME("FIXME: Call SMSS API #1\n");
618 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
619 NtShutdownSystem(ShutdownReboot
);
624 /* FIXME - only show this dialog if it's a shutdown and the computer doesn't support APM */
625 DialogBox(hAppInstance
, MAKEINTRESOURCE(IDD_SHUTDOWNCOMPUTER
), GetDesktopWindow(), ShutdownComputerWindowProc
);
627 NtShutdownSystem(ShutdownNoReboot
);
629 return STATUS_SUCCESS
;
634 IN OUT PWLSESSION Session
,
639 case WLX_SAS_ACTION_LOGON
: /* 0x01 */
640 if (HandleLogon(Session
))
642 SwitchDesktop(Session
->ApplicationDesktop
);
643 Session
->LogonStatus
= WKSTA_IS_LOGGED_ON
;
646 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
648 case WLX_SAS_ACTION_NONE
: /* 0x02 */
650 case WLX_SAS_ACTION_LOCK_WKSTA
: /* 0x03 */
651 if (Session
->Gina
.Functions
.WlxIsLockOk(Session
->Gina
.Context
))
653 SwitchDesktop(WLSession
->WinlogonDesktop
);
654 Session
->LogonStatus
= WKSTA_IS_LOCKED
;
655 Session
->Gina
.Functions
.WlxDisplayLockedNotice(Session
->Gina
.Context
);
658 case WLX_SAS_ACTION_LOGOFF
: /* 0x04 */
659 case WLX_SAS_ACTION_SHUTDOWN
: /* 0x05 */
660 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
: /* 0x0a */
661 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
: /* 0x0b */
662 if (Session
->LogonStatus
!= WKSTA_IS_LOGGED_OFF
)
664 if (!Session
->Gina
.Functions
.WlxIsLogoffOk(Session
->Gina
.Context
))
666 SwitchDesktop(WLSession
->WinlogonDesktop
);
667 Session
->Gina
.Functions
.WlxLogoff(Session
->Gina
.Context
);
668 if (!NT_SUCCESS(HandleLogoff(Session
, EWX_LOGOFF
)))
670 RemoveStatusMessage(Session
);
674 if (WLX_SHUTTINGDOWN(wlxAction
))
676 Session
->Gina
.Functions
.WlxShutdown(Session
->Gina
.Context
, wlxAction
);
677 if (!NT_SUCCESS(HandleShutdown(Session
, wlxAction
)))
679 RemoveStatusMessage(Session
);
680 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
685 RemoveStatusMessage(Session
);
686 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
689 case WLX_SAS_ACTION_TASKLIST
: /* 0x07 */
690 SwitchDesktop(WLSession
->ApplicationDesktop
);
691 StartTaskManager(Session
);
693 case WLX_SAS_ACTION_UNLOCK_WKSTA
: /* 0x08 */
694 SwitchDesktop(WLSession
->ApplicationDesktop
);
695 Session
->LogonStatus
= WKSTA_IS_LOGGED_ON
;
698 WARN("Unknown SAS action 0x%lx\n", wlxAction
);
704 IN OUT PWLSESSION Session
,
707 DWORD wlxAction
= WLX_SAS_ACTION_NONE
;
709 if (Session
->LogonStatus
== WKSTA_IS_LOGGED_ON
)
710 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOnSAS(Session
->Gina
.Context
, dwSasType
, NULL
);
711 else if (Session
->LogonStatus
== WKSTA_IS_LOCKED
)
712 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxWkstaLockedSAS(Session
->Gina
.Context
, dwSasType
);
715 /* Display a new dialog (if necessary) */
718 case WLX_SAS_TYPE_TIMEOUT
: /* 0x00 */
720 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
725 PSID LogonSid
= NULL
; /* FIXME */
727 Session
->Options
= 0;
729 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOutSAS(
730 Session
->Gina
.Context
,
736 &Session
->MprNotifyInfo
,
737 (PVOID
*)&Session
->Profile
);
743 if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_TIMEOUT
)
746 if (!Session
->Gina
.Functions
.WlxScreenSaverNotify(Session
->Gina
.Context
, &bSecure
))
748 /* Skip start of screen saver */
749 SetEvent(Session
->hEndOfScreenSaver
);
754 DoGenericAction(Session
, WLX_SAS_ACTION_LOCK_WKSTA
);
755 StartScreenSaver(Session
);
758 else if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_ACTIVITY
)
759 SetEvent(Session
->hUserActivity
);
761 DoGenericAction(Session
, wlxAction
);
766 IN PWLSESSION Session
,
769 /* Register Ctrl+Alt+Del Hotkey */
770 if (!RegisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
, MOD_CONTROL
| MOD_ALT
, VK_DELETE
))
772 ERR("WL: Unable to register Ctrl+Alt+Del hotkey!\n");
776 /* Register Ctrl+Shift+Esc (optional) */
777 Session
->TaskManHotkey
= RegisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
, MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
);
778 if (!Session
->TaskManHotkey
)
779 WARN("WL: Warning: Unable to register Ctrl+Alt+Esc hotkey!\n");
785 IN PWLSESSION Session
,
788 /* Unregister hotkeys */
789 UnregisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
);
791 if (Session
->TaskManHotkey
)
792 UnregisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
);
798 CheckForShutdownPrivilege(
799 IN DWORD RequestingProcessId
)
804 PPRIVILEGE_SET PrivSet
;
806 TRACE("CheckForShutdownPrivilege()\n");
808 Process
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, RequestingProcessId
);
811 WARN("OpenProcess() failed with error %lu\n", GetLastError());
812 return STATUS_INVALID_HANDLE
;
814 if (!OpenProcessToken(Process
, TOKEN_QUERY
, &Token
))
816 WARN("OpenProcessToken() failed with error %lu\n", GetLastError());
817 CloseHandle(Process
);
818 return STATUS_INVALID_HANDLE
;
820 CloseHandle(Process
);
821 PrivSet
= HeapAlloc(GetProcessHeap(), 0, sizeof(PRIVILEGE_SET
) + sizeof(LUID_AND_ATTRIBUTES
));
824 ERR("Failed to allocate mem for privilege set\n");
826 return STATUS_NO_MEMORY
;
828 PrivSet
->PrivilegeCount
= 1;
829 PrivSet
->Control
= PRIVILEGE_SET_ALL_NECESSARY
;
830 if (!LookupPrivilegeValue(NULL
, SE_SHUTDOWN_NAME
, &PrivSet
->Privilege
[0].Luid
))
832 WARN("LookupPrivilegeValue() failed with error %lu\n", GetLastError());
833 HeapFree(GetProcessHeap(), 0, PrivSet
);
835 return STATUS_UNSUCCESSFUL
;
837 if (!PrivilegeCheck(Token
, PrivSet
, &CheckResult
))
839 WARN("PrivilegeCheck() failed with error %lu\n", GetLastError());
840 HeapFree(GetProcessHeap(), 0, PrivSet
);
842 return STATUS_ACCESS_DENIED
;
844 HeapFree(GetProcessHeap(), 0, PrivSet
);
849 WARN("SE_SHUTDOWN privilege not enabled\n");
850 return STATUS_ACCESS_DENIED
;
852 return STATUS_SUCCESS
;
857 HandleMessageBeep(UINT uType
)
867 EventName
= L
"SystemDefault";
869 case MB_ICONASTERISK
:
870 EventName
= L
"SystemAsterisk";
872 case MB_ICONEXCLAMATION
:
873 EventName
= L
"SystemExclamation";
876 EventName
= L
"SystemHand";
878 case MB_ICONQUESTION
:
879 EventName
= L
"SystemQuestion";
882 WARN("Unhandled type %d\n", uType
);
883 EventName
= L
"SystemDefault";
886 return PlaySoundRoutine(EventName
, FALSE
, SND_ALIAS
| SND_NOWAIT
| SND_NOSTOP
| SND_ASYNC
);
889 static LRESULT CALLBACK
896 PWLSESSION Session
= (PWLSESSION
)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
904 case MAKELONG(MOD_CONTROL
| MOD_ALT
, VK_DELETE
):
906 TRACE("SAS: CONTROL+ALT+DELETE\n");
907 if (!Session
->Gina
.UseCtrlAltDelete
)
909 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_CTRL_ALT_DEL
, 0);
912 case MAKELONG(MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
):
914 TRACE("SAS: CONTROL+SHIFT+ESCAPE\n");
915 DoGenericAction(Session
, WLX_SAS_ACTION_TASKLIST
);
923 /* Get the session pointer from the create data */
924 Session
= (PWLSESSION
)((LPCREATESTRUCT
)lParam
)->lpCreateParams
;
926 /* Save the Session pointer */
927 SetWindowLongPtrW(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)Session
);
930 return RegisterHotKeys(Session
, hwndDlg
);
935 UnregisterHotKeys(Session
, hwndDlg
);
938 case WM_SETTINGCHANGE
:
940 UINT uiAction
= (UINT
)wParam
;
941 if (uiAction
== SPI_SETSCREENSAVETIMEOUT
942 || uiAction
== SPI_SETSCREENSAVEACTIVE
)
944 SetEvent(Session
->hScreenSaverParametersChanged
);
952 case LN_MESSAGE_BEEP
:
954 return HandleMessageBeep(lParam
);
956 case LN_SHELL_EXITED
:
958 /* lParam is the exit code */
961 SetTimer(hwndDlg
, 1, 1000, NULL
);
967 ERR("WM_LOGONNOTIFY case %d is unimplemented\n", wParam
);
976 KillTimer(hwndDlg
, 1);
977 StartUserShell(Session
);
983 DispatchSAS(Session
, (DWORD
)wParam
);
986 case PM_WINLOGON_EXITWINDOWS
:
988 UINT Flags
= (UINT
)lParam
;
989 UINT Action
= Flags
& EWX_ACTION_MASK
;
992 /* Check parameters */
995 case EWX_LOGOFF
: wlxAction
= WLX_SAS_ACTION_LOGOFF
; break;
996 case EWX_SHUTDOWN
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN
; break;
997 case EWX_REBOOT
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_REBOOT
; break;
998 case EWX_POWEROFF
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
; break;
1001 ERR("Invalid ExitWindows action 0x%x\n", Action
);
1002 return STATUS_INVALID_PARAMETER
;
1006 if (WLX_SHUTTINGDOWN(wlxAction
))
1008 NTSTATUS Status
= CheckForShutdownPrivilege((DWORD
)wParam
);
1009 if (!NT_SUCCESS(Status
))
1012 DoGenericAction(Session
, wlxAction
);
1017 return DefWindowProc(hwndDlg
, uMsg
, wParam
, lParam
);
1022 IN OUT PWLSESSION Session
)
1027 if (!SwitchDesktop(Session
->WinlogonDesktop
))
1029 ERR("WL: Failed to switch to winlogon desktop\n");
1033 /* Register SAS window class */
1034 swc
.cbSize
= sizeof(WNDCLASSEXW
);
1035 swc
.style
= CS_SAVEBITS
;
1036 swc
.lpfnWndProc
= SASWindowProc
;
1039 swc
.hInstance
= hAppInstance
;
1042 swc
.hbrBackground
= NULL
;
1043 swc
.lpszMenuName
= NULL
;
1044 swc
.lpszClassName
= WINLOGON_SAS_CLASS
;
1046 if (RegisterClassExW(&swc
) == 0)
1048 ERR("WL: Failed to register SAS window class\n");
1052 /* Create invisible SAS window */
1053 Session
->SASWindow
= CreateWindowExW(
1059 hAppInstance
, Session
);
1060 if (!Session
->SASWindow
)
1062 ERR("WL: Failed to create SAS window\n");
1066 /* Register SAS window to receive SAS notifications */
1067 if (!SetLogonNotifyWindow(Session
->SASWindow
, Session
->InteractiveWindowStation
))
1069 ERR("WL: Failed to register SAS window\n");
1073 if (!SetDefaultLanguage(FALSE
))
1080 UninitializeSAS(Session
);