2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Winlogon
4 * FILE: base/system/winlogon/sas.c
5 * PURPOSE: Secure Attention Sequence
6 * PROGRAMMERS: Thomas Weidenmueller (w3seek@users.sourceforge.net)
7 * Hervé Poussineau (hpoussin@reactos.org)
12 /* INCLUDES *****************************************************************/
16 #include <wine/debug.h>
18 WINE_DEFAULT_DEBUG_CHANNEL(winlogon
);
20 /* GLOBALS ******************************************************************/
22 #define WINLOGON_SAS_CLASS L"SAS Window class"
23 #define WINLOGON_SAS_TITLE L"SAS window"
25 #define HK_CTRL_ALT_DEL 0
26 #define HK_CTRL_SHIFT_ESC 1
28 extern BOOL WINAPI
SetLogonNotifyWindow(HWND Wnd
, HWINSTA WinSta
);
30 /* FUNCTIONS ****************************************************************/
34 IN OUT PWLSESSION Session
)
39 if (!Session
->Gina
.Functions
.WlxStartApplication
)
42 if (!CreateEnvironmentBlock(
50 ret
= Session
->Gina
.Functions
.WlxStartApplication(
51 Session
->Gina
.Context
,
56 DestroyEnvironmentBlock(lpEnvironment
);
71 UNICODE_STRING ValueString
;
78 BaseKey
= HKEY_CURRENT_USER
;
79 SubKey
= L
"Control Panel\\International";
80 ValueName
= L
"Locale";
84 BaseKey
= HKEY_LOCAL_MACHINE
;
85 SubKey
= L
"System\\CurrentControlSet\\Control\\Nls\\Language";
86 ValueName
= L
"Default";
95 if (rc
!= ERROR_SUCCESS
)
97 TRACE("RegOpenKeyEx() failed with error %lu\n", rc
);
100 rc
= RegQueryValueExW(
107 if (rc
!= ERROR_SUCCESS
)
109 TRACE("RegQueryValueEx() failed with error %lu\n", rc
);
112 else if (dwType
!= REG_SZ
)
114 TRACE("Wrong type for %S\\%S registry entry (got 0x%lx, expected 0x%x)\n",
115 SubKey
, ValueName
, dwType
, REG_SZ
);
119 Value
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
122 TRACE("HeapAlloc() failed\n");
125 rc
= RegQueryValueExW(
132 if (rc
!= ERROR_SUCCESS
)
134 TRACE("RegQueryValueEx() failed with error %lu\n", rc
);
138 /* Convert Value to a Lcid */
139 ValueString
.Length
= ValueString
.MaximumLength
= (USHORT
)dwSize
;
140 ValueString
.Buffer
= Value
;
141 Status
= RtlUnicodeStringToInteger(&ValueString
, 16, (PULONG
)&Lcid
);
142 if (!NT_SUCCESS(Status
))
144 TRACE("RtlUnicodeStringToInteger() failed with status 0x%08lx\n", Status
);
148 TRACE("%s language is 0x%08lx\n",
149 UserProfile
? "User" : "System", Lcid
);
150 Status
= NtSetDefaultLocale(UserProfile
, Lcid
);
151 if (!NT_SUCCESS(Status
))
153 TRACE("NtSetDefaultLocale() failed with status 0x%08lx\n", Status
);
163 HeapFree(GetProcessHeap(), 0, Value
);
169 IN OUT PWLSESSION Session
)
171 PROFILEINFOW ProfileInfo
;
172 LPVOID lpEnvironment
= NULL
;
173 LPWSTR lpFullEnv
= NULL
;
175 SIZE_T EnvBlockSize
= 0, ProfileSize
= 0;
179 /* Loading personal settings */
180 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_LOADINGYOURPERSONALSETTINGS
);
181 ProfileInfo
.hProfile
= INVALID_HANDLE_VALUE
;
182 if (0 == (Session
->Options
& WLX_LOGON_OPT_NO_PROFILE
))
184 if (Session
->Profile
== NULL
185 || (Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V1_0
186 && Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V2_0
))
188 ERR("WL: Wrong profile\n");
192 /* Load the user profile */
193 ZeroMemory(&ProfileInfo
, sizeof(PROFILEINFOW
));
194 ProfileInfo
.dwSize
= sizeof(PROFILEINFOW
);
195 ProfileInfo
.dwFlags
= 0;
196 ProfileInfo
.lpUserName
= Session
->MprNotifyInfo
.pszUserName
;
197 ProfileInfo
.lpProfilePath
= Session
->Profile
->pszProfile
;
198 if (Session
->Profile
->dwType
>= WLX_PROFILE_TYPE_V2_0
)
200 ProfileInfo
.lpDefaultPath
= Session
->Profile
->pszNetworkDefaultUserProfile
;
201 ProfileInfo
.lpServerName
= Session
->Profile
->pszServerName
;
202 ProfileInfo
.lpPolicyPath
= Session
->Profile
->pszPolicy
;
205 if (!LoadUserProfileW(Session
->UserToken
, &ProfileInfo
))
207 ERR("WL: LoadUserProfileW() failed\n");
212 /* Create environment block for the user */
213 if (!CreateEnvironmentBlock(
218 WARN("WL: CreateEnvironmentBlock() failed\n");
222 if (Session
->Profile
->dwType
== WLX_PROFILE_TYPE_V2_0
&& Session
->Profile
->pszEnvironment
)
224 /* Count required size for full environment */
225 wstr
= (LPCWSTR
)lpEnvironment
;
226 while (*wstr
!= UNICODE_NULL
)
228 SIZE_T size
= wcslen(wstr
) + 1;
230 EnvBlockSize
+= size
;
232 wstr
= Session
->Profile
->pszEnvironment
;
233 while (*wstr
!= UNICODE_NULL
)
235 SIZE_T size
= wcslen(wstr
) + 1;
240 /* Allocate enough memory */
241 lpFullEnv
= HeapAlloc(GetProcessHeap
, 0, (EnvBlockSize
+ ProfileSize
+ 1) * sizeof(WCHAR
));
244 TRACE("HeapAlloc() failed\n");
248 /* Fill user environment block */
252 EnvBlockSize
* sizeof(WCHAR
));
254 &lpFullEnv
[EnvBlockSize
],
255 Session
->Profile
->pszEnvironment
,
256 ProfileSize
* sizeof(WCHAR
));
257 lpFullEnv
[EnvBlockSize
+ ProfileSize
] = UNICODE_NULL
;
261 lpFullEnv
= (LPWSTR
)lpEnvironment
;
264 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_APPLYINGYOURPERSONALSETTINGS
);
265 UpdatePerUserSystemParameters(0, TRUE
);
267 /* Set default language */
268 if (!SetDefaultLanguage(TRUE
))
270 WARN("WL: SetDefaultLanguage() failed\n");
275 /* FIXME: who should do it? winlogon or gina? */
276 /* FIXME: reverting to lower privileges after creating user shell? */
277 RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
279 if (!Session
->Gina
.Functions
.WlxActivateUserShell(
280 Session
->Gina
.Context
,
285 //WCHAR StatusMsg[256];
286 WARN("WL: WlxActivateUserShell() failed\n");
287 //LoadStringW(hAppInstance, IDS_FAILEDACTIVATEUSERSHELL, StatusMsg, sizeof(StatusMsg));
288 //MessageBoxW(0, StatusMsg, NULL, MB_ICONERROR);
292 if (!InitializeScreenSaver(Session
))
293 WARN("WL: Failed to initialize screen saver\n");
295 Session
->hProfileInfo
= ProfileInfo
.hProfile
;
299 if (Session
->Profile
)
301 HeapFree(GetProcessHeap(), 0, Session
->Profile
->pszProfile
);
302 HeapFree(GetProcessHeap(), 0, Session
->Profile
);
304 Session
->Profile
= NULL
;
306 && ProfileInfo
.hProfile
!= INVALID_HANDLE_VALUE
)
308 UnloadUserProfile(WLSession
->UserToken
, ProfileInfo
.hProfile
);
310 if (lpFullEnv
!= lpEnvironment
)
311 HeapFree(GetProcessHeap(), 0, lpFullEnv
);
313 DestroyEnvironmentBlock(lpEnvironment
);
314 RemoveStatusMessage(Session
);
317 CloseHandle(Session
->UserToken
);
318 Session
->UserToken
= NULL
;
323 #define EWX_ACTION_MASK 0xffffffeb
324 #define EWX_FLAGS_MASK 0x00000014
326 typedef struct tagLOGOFF_SHUTDOWN_DATA
330 } LOGOFF_SHUTDOWN_DATA
, *PLOGOFF_SHUTDOWN_DATA
;
333 LogoffShutdownThread(LPVOID Parameter
)
335 PLOGOFF_SHUTDOWN_DATA LSData
= (PLOGOFF_SHUTDOWN_DATA
)Parameter
;
337 if (LSData
->Session
->UserToken
!= NULL
&& !ImpersonateLoggedOnUser(LSData
->Session
->UserToken
))
339 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
343 /* Close processes of the interactive user */
345 EWX_INTERNAL_KILL_USER_APPS
| (LSData
->Flags
& EWX_FLAGS_MASK
) |
346 (EWX_LOGOFF
== (LSData
->Flags
& EWX_ACTION_MASK
) ? EWX_INTERNAL_FLAG_LOGOFF
: 0),
349 ERR("Unable to kill user apps, error %lu\n", GetLastError());
354 /* FIXME: Call ExitWindowsEx() to terminate COM processes */
356 if (LSData
->Session
->UserToken
)
364 CreateLogoffSecurityAttributes(
365 OUT PSECURITY_ATTRIBUTES
* ppsa
)
367 /* The following code is not working yet and messy */
368 /* Still, it gives some ideas about data types and functions involved and */
369 /* required to set up a SECURITY_DESCRIPTOR for a SECURITY_ATTRIBUTES */
370 /* instance for a thread, to allow that thread to ImpersonateLoggedOnUser(). */
371 /* Specifically THREAD_SET_THREAD_TOKEN is required. */
372 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
373 PSECURITY_ATTRIBUTES psa
= 0;
376 EXPLICIT_ACCESS Access
;
377 PSID pEveryoneSID
= NULL
;
378 static SID_IDENTIFIER_AUTHORITY WorldAuthority
= { SECURITY_WORLD_SID_AUTHORITY
};
382 // Let's first try to enumerate what kind of data we need for this to ever work:
383 // 1. The Winlogon SID, to be able to give it THREAD_SET_THREAD_TOKEN.
384 // 2. The users SID (the user trying to logoff, or rather shut down the system).
385 // 3. At least two EXPLICIT_ACCESS instances:
386 // 3.1 One for Winlogon itself, giving it the rights
387 // required to THREAD_SET_THREAD_TOKEN (as it's needed to successfully call
388 // ImpersonateLoggedOnUser).
389 // 3.2 One for the user, to allow *that* thread to perform its work.
390 // 4. An ACL to hold the these EXPLICIT_ACCESS ACE's.
391 // 5. A SECURITY_DESCRIPTOR to hold the ACL, and finally.
392 // 6. A SECURITY_ATTRIBUTES instance to pull all of this required stuff
393 // together, to hand it to CreateThread.
395 // However, it seems struct LOGOFF_SHUTDOWN_DATA doesn't contain
396 // these required SID's, why they'd have to be added.
397 // The Winlogon's own SID should probably only be created once,
398 // while the user's SID obviously must be created for each new user.
399 // Might as well store it when the user logs on?
401 if(!AllocateAndInitializeSid(&WorldAuthority
,
407 ERR("Failed to initialize security descriptor for logoff thread!\n");
408 return STATUS_UNSUCCESSFUL
;
411 /* set up the required security attributes to be able to shut down */
412 /* To save space and time, allocate a single block of memory holding */
413 /* both SECURITY_ATTRIBUTES and SECURITY_DESCRIPTOR */
414 pMem
= HeapAlloc(GetProcessHeap(),
416 sizeof(SECURITY_ATTRIBUTES
) +
417 SECURITY_DESCRIPTOR_MIN_LENGTH
+
421 ERR("Failed to allocate memory for logoff security descriptor!\n");
422 return STATUS_NO_MEMORY
;
425 /* Note that the security descriptor needs to be in _absolute_ format, */
426 /* meaning its members must be pointers to other structures, rather */
427 /* than the relative format using offsets */
428 psa
= (PSECURITY_ATTRIBUTES
)pMem
;
429 SecurityDescriptor
= (PSECURITY_DESCRIPTOR
)(pMem
+ sizeof(SECURITY_ATTRIBUTES
));
430 pACL
= (PACL
)(((PBYTE
)SecurityDescriptor
) + SECURITY_DESCRIPTOR_MIN_LENGTH
);
432 // Initialize an EXPLICIT_ACCESS structure for an ACE.
433 // The ACE will allow this thread to log off (and shut down the system, currently).
434 ZeroMemory(&Access
, sizeof(Access
));
435 Access
.grfAccessPermissions
= THREAD_SET_THREAD_TOKEN
;
436 Access
.grfAccessMode
= SET_ACCESS
; // GRANT_ACCESS?
437 Access
.grfInheritance
= NO_INHERITANCE
;
438 Access
.Trustee
.TrusteeForm
= TRUSTEE_IS_SID
;
439 Access
.Trustee
.TrusteeType
= TRUSTEE_IS_WELL_KNOWN_GROUP
;
440 Access
.Trustee
.ptstrName
= pEveryoneSID
;
442 if (SetEntriesInAcl(1, &Access
, NULL
, &pACL
) != ERROR_SUCCESS
)
444 ERR("Failed to set Access Rights for logoff thread. Logging out will most likely fail.\n");
446 HeapFree(GetProcessHeap(), 0, pMem
);
447 return STATUS_UNSUCCESSFUL
;
450 if (!InitializeSecurityDescriptor(SecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
))
452 ERR("Failed to initialize security descriptor for logoff thread!\n");
453 HeapFree(GetProcessHeap(), 0, pMem
);
454 return STATUS_UNSUCCESSFUL
;
457 if (!SetSecurityDescriptorDacl(SecurityDescriptor
,
458 TRUE
, // bDaclPresent flag
460 FALSE
)) // not a default DACL
462 ERR("SetSecurityDescriptorDacl Error %lu\n", GetLastError());
463 HeapFree(GetProcessHeap(), 0, pMem
);
464 return STATUS_UNSUCCESSFUL
;
467 psa
->nLength
= sizeof(SECURITY_ATTRIBUTES
);
468 psa
->lpSecurityDescriptor
= SecurityDescriptor
;
469 psa
->bInheritHandle
= FALSE
;
473 return STATUS_SUCCESS
;
477 DestroyLogoffSecurityAttributes(
478 IN PSECURITY_ATTRIBUTES psa
)
482 HeapFree(GetProcessHeap(), 0, psa
);
489 IN OUT PWLSESSION Session
,
492 PLOGOFF_SHUTDOWN_DATA LSData
;
493 PSECURITY_ATTRIBUTES psa
;
498 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_SAVEYOURSETTINGS
);
500 /* Prepare data for logoff thread */
501 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
504 ERR("Failed to allocate mem for thread data\n");
505 return STATUS_NO_MEMORY
;
507 LSData
->Flags
= Flags
;
508 LSData
->Session
= Session
;
510 Status
= CreateLogoffSecurityAttributes(&psa
);
511 if (!NT_SUCCESS(Status
))
513 ERR("Failed to create a required security descriptor. Status 0x%08lx\n", Status
);
514 HeapFree(GetProcessHeap(), 0, LSData
);
518 /* Run logoff thread */
519 hThread
= CreateThread(psa
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
521 /* we're done with the SECURITY_DESCRIPTOR */
522 DestroyLogoffSecurityAttributes(psa
);
527 ERR("Unable to create logoff thread, error %lu\n", GetLastError());
528 HeapFree(GetProcessHeap(), 0, LSData
);
529 return STATUS_UNSUCCESSFUL
;
531 WaitForSingleObject(hThread
, INFINITE
);
532 HeapFree(GetProcessHeap(), 0, LSData
);
533 if (!GetExitCodeThread(hThread
, &exitCode
))
535 ERR("Unable to get exit code of logoff thread (error %lu)\n", GetLastError());
536 CloseHandle(hThread
);
537 return STATUS_UNSUCCESSFUL
;
539 CloseHandle(hThread
);
542 ERR("Logoff thread returned failure\n");
543 return STATUS_UNSUCCESSFUL
;
546 UnloadUserProfile(Session
->UserToken
, Session
->hProfileInfo
);
547 CloseHandle(Session
->UserToken
);
548 UpdatePerUserSystemParameters(0, FALSE
);
549 Session
->LogonStatus
= WKSTA_IS_LOGGED_OFF
;
550 Session
->UserToken
= NULL
;
551 return STATUS_SUCCESS
;
554 static INT_PTR CALLBACK
555 ShutdownComputerWindowProc(
561 UNREFERENCED_PARAMETER(lParam
);
567 switch (LOWORD(wParam
))
569 case IDC_BTNSHTDOWNCOMPUTER
:
570 EndDialog(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
);
577 RemoveMenu(GetSystemMenu(hwndDlg
, FALSE
), SC_CLOSE
, MF_BYCOMMAND
);
578 SetFocus(GetDlgItem(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
));
587 IN OUT PWLSESSION Session
)
589 if (Session
->SASWindow
)
591 DestroyWindow(Session
->SASWindow
);
592 Session
->SASWindow
= NULL
;
594 if (Session
->hEndOfScreenSaverThread
)
595 SetEvent(Session
->hEndOfScreenSaverThread
);
596 UnregisterClassW(WINLOGON_SAS_CLASS
, hAppInstance
);
601 IN OUT PWLSESSION Session
,
604 PLOGOFF_SHUTDOWN_DATA LSData
;
608 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_REACTOSISSHUTTINGDOWN
);
610 /* Prepare data for shutdown thread */
611 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
614 ERR("Failed to allocate mem for thread data\n");
615 return STATUS_NO_MEMORY
;
617 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
)
618 LSData
->Flags
= EWX_POWEROFF
;
619 else if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
620 LSData
->Flags
= EWX_REBOOT
;
622 LSData
->Flags
= EWX_SHUTDOWN
;
623 LSData
->Session
= Session
;
625 /* Run shutdown thread */
626 hThread
= CreateThread(NULL
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
629 ERR("Unable to create shutdown thread, error %lu\n", GetLastError());
630 HeapFree(GetProcessHeap(), 0, LSData
);
631 return STATUS_UNSUCCESSFUL
;
633 WaitForSingleObject(hThread
, INFINITE
);
634 HeapFree(GetProcessHeap(), 0, LSData
);
635 if (!GetExitCodeThread(hThread
, &exitCode
))
637 ERR("Unable to get exit code of shutdown thread (error %lu)\n", GetLastError());
638 CloseHandle(hThread
);
639 return STATUS_UNSUCCESSFUL
;
641 CloseHandle(hThread
);
644 ERR("Shutdown thread returned failure\n");
645 return STATUS_UNSUCCESSFUL
;
648 /* Destroy SAS window */
649 UninitializeSAS(Session
);
651 FIXME("FIXME: Call SMSS API #1\n");
652 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
653 NtShutdownSystem(ShutdownReboot
);
658 /* FIXME - only show this dialog if it's a shutdown and the computer doesn't support APM */
659 DialogBox(hAppInstance
, MAKEINTRESOURCE(IDD_SHUTDOWNCOMPUTER
), GetDesktopWindow(), ShutdownComputerWindowProc
);
661 NtShutdownSystem(ShutdownNoReboot
);
663 return STATUS_SUCCESS
;
668 IN OUT PWLSESSION Session
,
673 case WLX_SAS_ACTION_LOGON
: /* 0x01 */
674 if (HandleLogon(Session
))
676 SwitchDesktop(Session
->ApplicationDesktop
);
677 Session
->LogonStatus
= WKSTA_IS_LOGGED_ON
;
680 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
682 case WLX_SAS_ACTION_NONE
: /* 0x02 */
684 case WLX_SAS_ACTION_LOCK_WKSTA
: /* 0x03 */
685 if (Session
->Gina
.Functions
.WlxIsLockOk(Session
->Gina
.Context
))
687 SwitchDesktop(WLSession
->WinlogonDesktop
);
688 Session
->LogonStatus
= WKSTA_IS_LOCKED
;
689 Session
->Gina
.Functions
.WlxDisplayLockedNotice(Session
->Gina
.Context
);
692 case WLX_SAS_ACTION_LOGOFF
: /* 0x04 */
693 case WLX_SAS_ACTION_SHUTDOWN
: /* 0x05 */
694 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
: /* 0x0a */
695 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
: /* 0x0b */
696 if (Session
->LogonStatus
!= WKSTA_IS_LOGGED_OFF
)
698 if (!Session
->Gina
.Functions
.WlxIsLogoffOk(Session
->Gina
.Context
))
700 SwitchDesktop(WLSession
->WinlogonDesktop
);
701 Session
->Gina
.Functions
.WlxLogoff(Session
->Gina
.Context
);
702 if (!NT_SUCCESS(HandleLogoff(Session
, EWX_LOGOFF
)))
704 RemoveStatusMessage(Session
);
708 if (WLX_SHUTTINGDOWN(wlxAction
))
710 Session
->Gina
.Functions
.WlxShutdown(Session
->Gina
.Context
, wlxAction
);
711 if (!NT_SUCCESS(HandleShutdown(Session
, wlxAction
)))
713 RemoveStatusMessage(Session
);
714 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
719 RemoveStatusMessage(Session
);
720 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
723 case WLX_SAS_ACTION_TASKLIST
: /* 0x07 */
724 SwitchDesktop(WLSession
->ApplicationDesktop
);
725 StartTaskManager(Session
);
727 case WLX_SAS_ACTION_UNLOCK_WKSTA
: /* 0x08 */
728 SwitchDesktop(WLSession
->ApplicationDesktop
);
729 Session
->LogonStatus
= WKSTA_IS_LOGGED_ON
;
732 WARN("Unknown SAS action 0x%lx\n", wlxAction
);
738 IN OUT PWLSESSION Session
,
741 DWORD wlxAction
= WLX_SAS_ACTION_NONE
;
743 if (Session
->LogonStatus
== WKSTA_IS_LOGGED_ON
)
744 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOnSAS(Session
->Gina
.Context
, dwSasType
, NULL
);
745 else if (Session
->LogonStatus
== WKSTA_IS_LOCKED
)
746 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxWkstaLockedSAS(Session
->Gina
.Context
, dwSasType
);
749 /* Display a new dialog (if necessary) */
752 case WLX_SAS_TYPE_TIMEOUT
: /* 0x00 */
754 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
759 PSID LogonSid
= NULL
; /* FIXME */
761 Session
->Options
= 0;
763 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOutSAS(
764 Session
->Gina
.Context
,
770 &Session
->MprNotifyInfo
,
771 (PVOID
*)&Session
->Profile
);
777 if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_TIMEOUT
)
780 if (!Session
->Gina
.Functions
.WlxScreenSaverNotify(Session
->Gina
.Context
, &bSecure
))
782 /* Skip start of screen saver */
783 SetEvent(Session
->hEndOfScreenSaver
);
788 DoGenericAction(Session
, WLX_SAS_ACTION_LOCK_WKSTA
);
789 StartScreenSaver(Session
);
792 else if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_ACTIVITY
)
793 SetEvent(Session
->hUserActivity
);
795 DoGenericAction(Session
, wlxAction
);
800 IN PWLSESSION Session
,
803 /* Register Ctrl+Alt+Del Hotkey */
804 if (!RegisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
, MOD_CONTROL
| MOD_ALT
, VK_DELETE
))
806 ERR("WL: Unable to register Ctrl+Alt+Del hotkey!\n");
810 /* Register Ctrl+Shift+Esc (optional) */
811 Session
->TaskManHotkey
= RegisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
, MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
);
812 if (!Session
->TaskManHotkey
)
813 WARN("WL: Warning: Unable to register Ctrl+Alt+Esc hotkey!\n");
819 IN PWLSESSION Session
,
822 /* Unregister hotkeys */
823 UnregisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
);
825 if (Session
->TaskManHotkey
)
826 UnregisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
);
832 CheckForShutdownPrivilege(
833 IN DWORD RequestingProcessId
)
838 PPRIVILEGE_SET PrivSet
;
840 TRACE("CheckForShutdownPrivilege()\n");
842 Process
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, RequestingProcessId
);
845 WARN("OpenProcess() failed with error %lu\n", GetLastError());
846 return STATUS_INVALID_HANDLE
;
848 if (!OpenProcessToken(Process
, TOKEN_QUERY
, &Token
))
850 WARN("OpenProcessToken() failed with error %lu\n", GetLastError());
851 CloseHandle(Process
);
852 return STATUS_INVALID_HANDLE
;
854 CloseHandle(Process
);
855 PrivSet
= HeapAlloc(GetProcessHeap(), 0, sizeof(PRIVILEGE_SET
) + sizeof(LUID_AND_ATTRIBUTES
));
858 ERR("Failed to allocate mem for privilege set\n");
860 return STATUS_NO_MEMORY
;
862 PrivSet
->PrivilegeCount
= 1;
863 PrivSet
->Control
= PRIVILEGE_SET_ALL_NECESSARY
;
864 if (!LookupPrivilegeValue(NULL
, SE_SHUTDOWN_NAME
, &PrivSet
->Privilege
[0].Luid
))
866 WARN("LookupPrivilegeValue() failed with error %lu\n", GetLastError());
867 HeapFree(GetProcessHeap(), 0, PrivSet
);
869 return STATUS_UNSUCCESSFUL
;
871 if (!PrivilegeCheck(Token
, PrivSet
, &CheckResult
))
873 WARN("PrivilegeCheck() failed with error %lu\n", GetLastError());
874 HeapFree(GetProcessHeap(), 0, PrivSet
);
876 return STATUS_ACCESS_DENIED
;
878 HeapFree(GetProcessHeap(), 0, PrivSet
);
883 WARN("SE_SHUTDOWN privilege not enabled\n");
884 return STATUS_ACCESS_DENIED
;
886 return STATUS_SUCCESS
;
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
);
950 DispatchSAS(Session
, (DWORD
)wParam
);
953 case PM_WINLOGON_EXITWINDOWS
:
955 UINT Flags
= (UINT
)lParam
;
956 UINT Action
= Flags
& EWX_ACTION_MASK
;
959 /* Check parameters */
962 case EWX_LOGOFF
: wlxAction
= WLX_SAS_ACTION_LOGOFF
; break;
963 case EWX_SHUTDOWN
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN
; break;
964 case EWX_REBOOT
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_REBOOT
; break;
965 case EWX_POWEROFF
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
; break;
968 ERR("Invalid ExitWindows action 0x%x\n", Action
);
969 return STATUS_INVALID_PARAMETER
;
973 if (WLX_SHUTTINGDOWN(wlxAction
))
975 NTSTATUS Status
= CheckForShutdownPrivilege((DWORD
)wParam
);
976 if (!NT_SUCCESS(Status
))
979 DoGenericAction(Session
, wlxAction
);
984 return DefWindowProc(hwndDlg
, uMsg
, wParam
, lParam
);
989 IN OUT PWLSESSION Session
)
994 if (!SwitchDesktop(Session
->WinlogonDesktop
))
996 ERR("WL: Failed to switch to winlogon desktop\n");
1000 /* Register SAS window class */
1001 swc
.cbSize
= sizeof(WNDCLASSEXW
);
1002 swc
.style
= CS_SAVEBITS
;
1003 swc
.lpfnWndProc
= SASWindowProc
;
1006 swc
.hInstance
= hAppInstance
;
1009 swc
.hbrBackground
= NULL
;
1010 swc
.lpszMenuName
= NULL
;
1011 swc
.lpszClassName
= WINLOGON_SAS_CLASS
;
1013 if (RegisterClassExW(&swc
) == 0)
1015 ERR("WL: Failed to register SAS window class\n");
1019 /* Create invisible SAS window */
1020 Session
->SASWindow
= CreateWindowExW(
1026 hAppInstance
, Session
);
1027 if (!Session
->SASWindow
)
1029 ERR("WL: Failed to create SAS window\n");
1033 /* Register SAS window to receive SAS notifications */
1034 if (!SetLogonNotifyWindow(Session
->SASWindow
, Session
->InteractiveWindowStation
))
1036 ERR("WL: Failed to register SAS window\n");
1040 if (!SetDefaultLanguage(FALSE
))
1047 UninitializeSAS(Session
);