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 WINE_DEFAULT_DEBUG_CHANNEL(winlogon
);
18 /* GLOBALS ******************************************************************/
20 #define WINLOGON_SAS_CLASS L"SAS Window class"
21 #define WINLOGON_SAS_TITLE L"SAS window"
23 #define HK_CTRL_ALT_DEL 0
24 #define HK_CTRL_SHIFT_ESC 1
26 /* FUNCTIONS ****************************************************************/
30 IN OUT PWLSESSION Session
)
35 if (!Session
->Gina
.Functions
.WlxStartApplication
)
38 if (!CreateEnvironmentBlock(
46 ret
= Session
->Gina
.Functions
.WlxStartApplication(
47 Session
->Gina
.Context
,
52 DestroyEnvironmentBlock(lpEnvironment
);
58 IN OUT PWLSESSION Session
)
60 LPVOID lpEnvironment
= NULL
;
64 /* Create environment block for the user */
65 if (!CreateEnvironmentBlock(&lpEnvironment
, Session
->UserToken
, TRUE
))
67 WARN("WL: CreateEnvironmentBlock() failed\n");
72 /* FIXME: who should do it? winlogon or gina? */
73 /* FIXME: reverting to lower privileges after creating user shell? */
74 RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
76 ret
= Session
->Gina
.Functions
.WlxActivateUserShell(
77 Session
->Gina
.Context
,
82 DestroyEnvironmentBlock(lpEnvironment
);
98 UNICODE_STRING ValueString
;
105 BaseKey
= HKEY_CURRENT_USER
;
106 SubKey
= L
"Control Panel\\International";
107 ValueName
= L
"Locale";
111 BaseKey
= HKEY_LOCAL_MACHINE
;
112 SubKey
= L
"System\\CurrentControlSet\\Control\\Nls\\Language";
113 ValueName
= L
"Default";
122 if (rc
!= ERROR_SUCCESS
)
124 TRACE("RegOpenKeyEx() failed with error %lu\n", rc
);
127 rc
= RegQueryValueExW(
134 if (rc
!= ERROR_SUCCESS
)
136 TRACE("RegQueryValueEx() failed with error %lu\n", rc
);
139 else if (dwType
!= REG_SZ
)
141 TRACE("Wrong type for %S\\%S registry entry (got 0x%lx, expected 0x%x)\n",
142 SubKey
, ValueName
, dwType
, REG_SZ
);
146 Value
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
149 TRACE("HeapAlloc() failed\n");
152 rc
= RegQueryValueExW(
159 if (rc
!= ERROR_SUCCESS
)
161 TRACE("RegQueryValueEx() failed with error %lu\n", rc
);
165 /* Convert Value to a Lcid */
166 ValueString
.Length
= ValueString
.MaximumLength
= (USHORT
)dwSize
;
167 ValueString
.Buffer
= Value
;
168 Status
= RtlUnicodeStringToInteger(&ValueString
, 16, (PULONG
)&Lcid
);
169 if (!NT_SUCCESS(Status
))
171 TRACE("RtlUnicodeStringToInteger() failed with status 0x%08lx\n", Status
);
175 TRACE("%s language is 0x%08lx\n",
176 UserProfile
? "User" : "System", Lcid
);
177 Status
= NtSetDefaultLocale(UserProfile
, Lcid
);
178 if (!NT_SUCCESS(Status
))
180 TRACE("NtSetDefaultLocale() failed with status 0x%08lx\n", Status
);
190 HeapFree(GetProcessHeap(), 0, Value
);
200 typedef BOOL (WINAPI
*PLAYSOUNDW
)(LPCWSTR
,HMODULE
,DWORD
);
201 typedef UINT (WINAPI
*WAVEOUTGETNUMDEVS
)(VOID
);
203 WAVEOUTGETNUMDEVS waveOutGetNumDevs
;
208 hLibrary
= LoadLibraryW(L
"winmm.dll");
211 waveOutGetNumDevs
= (WAVEOUTGETNUMDEVS
)GetProcAddress(hLibrary
, "waveOutGetNumDevs");
212 if (waveOutGetNumDevs
)
214 NumDevs
= waveOutGetNumDevs();
221 FreeLibrary(hLibrary
);
226 Play
= (PLAYSOUNDW
)GetProcAddress(hLibrary
, "PlaySoundW");
229 Ret
= Play(FileName
, NULL
, Flags
);
231 FreeLibrary(hLibrary
);
239 PlayLogonSoundThread(
240 IN LPVOID lpParameter
)
242 BYTE TokenUserBuffer
[256];
243 PTOKEN_USER pTokenUser
= (TOKEN_USER
*)TokenUserBuffer
;
246 WCHAR wszBuffer
[MAX_PATH
] = {0};
247 WCHAR wszDest
[MAX_PATH
];
248 DWORD dwSize
= sizeof(wszBuffer
), dwType
;
249 SERVICE_STATUS_PROCESS Info
;
250 UNICODE_STRING SidString
;
253 SC_HANDLE hSCManager
, hService
;
255 /* Get SID of current user */
256 Status
= NtQueryInformationToken((HANDLE
)lpParameter
,
259 sizeof(TokenUserBuffer
),
261 if (!NT_SUCCESS(Status
))
263 ERR("NtQueryInformationToken failed: %x!\n", Status
);
267 /* Convert SID to string */
268 RtlInitEmptyUnicodeString(&SidString
, wszBuffer
, sizeof(wszBuffer
));
269 Status
= RtlConvertSidToUnicodeString(&SidString
, pTokenUser
->User
.Sid
, FALSE
);
270 if (!NT_SUCCESS(Status
))
272 ERR("RtlConvertSidToUnicodeString failed: %x!\n", Status
);
276 /* Build path to logon sound registry key.
277 Note: We can't use HKCU here, because Winlogon is owned by SYSTEM user */
278 if (FAILED(StringCbCopyW(wszBuffer
+ SidString
.Length
/sizeof(WCHAR
),
279 sizeof(wszBuffer
) - SidString
.Length
,
280 L
"\\AppEvents\\Schemes\\Apps\\.Default\\WindowsLogon\\.Current")))
282 /* SID is too long. Should not happen. */
283 ERR("StringCbCopyW failed!\n");
287 /* Open registry key and query sound path */
288 if (RegOpenKeyExW(HKEY_USERS
, wszBuffer
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
290 ERR("RegOpenKeyExW(%ls) failed!\n", wszBuffer
);
294 if (RegQueryValueExW(hKey
, NULL
, NULL
, &dwType
,
295 (LPBYTE
)wszBuffer
, &dwSize
) != ERROR_SUCCESS
||
296 (dwType
!= REG_SZ
&& dwType
!= REG_EXPAND_SZ
))
298 ERR("RegQueryValueExW failed!\n");
307 /* No sound has been set */
308 ERR("No sound has been set\n");
312 /* Expand environment variables */
313 if (!ExpandEnvironmentStringsW(wszBuffer
, wszDest
, MAX_PATH
))
315 ERR("ExpandEnvironmentStringsW failed!\n");
319 /* Open service manager */
320 hSCManager
= OpenSCManager(NULL
, NULL
, SC_MANAGER_CONNECT
);
323 ERR("OpenSCManager failed (%x)\n", GetLastError());
327 /* Open wdmaud service */
328 hService
= OpenServiceW(hSCManager
, L
"wdmaud", GENERIC_READ
);
331 /* Sound is not installed */
332 TRACE("Failed to open wdmaud service (%x)\n", GetLastError());
333 CloseServiceHandle(hSCManager
);
337 /* Wait for wdmaud start */
340 if (!QueryServiceStatusEx(hService
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&Info
, sizeof(SERVICE_STATUS_PROCESS
), &dwSize
))
342 TRACE("QueryServiceStatusEx failed (%x)\n", GetLastError());
346 if (Info
.dwCurrentState
== SERVICE_RUNNING
)
351 } while (Index
++ < 20);
353 CloseServiceHandle(hService
);
354 CloseServiceHandle(hSCManager
);
356 /* If wdmaud is not running exit */
357 if (Info
.dwCurrentState
!= SERVICE_RUNNING
)
359 WARN("wdmaud has not started!\n");
363 /* Sound subsystem is running. Play logon sound. */
364 TRACE("Playing logon sound: %ls\n", wszDest
);
365 PlaySoundRoutine(wszDest
, TRUE
, SND_FILENAME
);
371 IN OUT PWLSESSION Session
)
375 hThread
= CreateThread(NULL
, 0, PlayLogonSoundThread
, (PVOID
)Session
->UserToken
, 0, NULL
);
377 CloseHandle(hThread
);
382 IN OUT PWLSESSION Session
)
384 PROFILEINFOW ProfileInfo
;
387 /* Loading personal settings */
388 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_LOADINGYOURPERSONALSETTINGS
);
389 ProfileInfo
.hProfile
= INVALID_HANDLE_VALUE
;
390 if (0 == (Session
->Options
& WLX_LOGON_OPT_NO_PROFILE
))
392 if (Session
->Profile
== NULL
393 || (Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V1_0
394 && Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V2_0
))
396 ERR("WL: Wrong profile\n");
400 /* Load the user profile */
401 ZeroMemory(&ProfileInfo
, sizeof(PROFILEINFOW
));
402 ProfileInfo
.dwSize
= sizeof(PROFILEINFOW
);
403 ProfileInfo
.dwFlags
= 0;
404 ProfileInfo
.lpUserName
= Session
->MprNotifyInfo
.pszUserName
;
405 ProfileInfo
.lpProfilePath
= Session
->Profile
->pszProfile
;
406 if (Session
->Profile
->dwType
>= WLX_PROFILE_TYPE_V2_0
)
408 ProfileInfo
.lpDefaultPath
= Session
->Profile
->pszNetworkDefaultUserProfile
;
409 ProfileInfo
.lpServerName
= Session
->Profile
->pszServerName
;
410 ProfileInfo
.lpPolicyPath
= Session
->Profile
->pszPolicy
;
413 if (!LoadUserProfileW(Session
->UserToken
, &ProfileInfo
))
415 ERR("WL: LoadUserProfileW() failed\n");
420 /* Create environment block for the user */
421 if (!CreateUserEnvironment(Session
))
423 WARN("WL: SetUserEnvironment() failed\n");
427 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_APPLYINGYOURPERSONALSETTINGS
);
428 UpdatePerUserSystemParameters(0, TRUE
);
430 /* Set default language */
431 if (!SetDefaultLanguage(TRUE
))
433 WARN("WL: SetDefaultLanguage() failed\n");
437 if (!StartUserShell(Session
))
439 //WCHAR StatusMsg[256];
440 WARN("WL: WlxActivateUserShell() failed\n");
441 //LoadStringW(hAppInstance, IDS_FAILEDACTIVATEUSERSHELL, StatusMsg, sizeof(StatusMsg) / sizeof(StatusMsg[0]));
442 //MessageBoxW(0, StatusMsg, NULL, MB_ICONERROR);
446 if (!InitializeScreenSaver(Session
))
447 WARN("WL: Failed to initialize screen saver\n");
449 Session
->hProfileInfo
= ProfileInfo
.hProfile
;
451 /* Logon has successed. Play sound. */
452 PlayLogonSound(Session
);
457 if (Session
->Profile
)
459 HeapFree(GetProcessHeap(), 0, Session
->Profile
->pszProfile
);
460 HeapFree(GetProcessHeap(), 0, Session
->Profile
);
462 Session
->Profile
= NULL
;
464 && ProfileInfo
.hProfile
!= INVALID_HANDLE_VALUE
)
466 UnloadUserProfile(WLSession
->UserToken
, ProfileInfo
.hProfile
);
468 RemoveStatusMessage(Session
);
471 CloseHandle(Session
->UserToken
);
472 Session
->UserToken
= NULL
;
477 #define EWX_ACTION_MASK 0xffffffeb
478 #define EWX_FLAGS_MASK 0x00000014
480 typedef struct tagLOGOFF_SHUTDOWN_DATA
484 } LOGOFF_SHUTDOWN_DATA
, *PLOGOFF_SHUTDOWN_DATA
;
487 LogoffShutdownThread(LPVOID Parameter
)
489 PLOGOFF_SHUTDOWN_DATA LSData
= (PLOGOFF_SHUTDOWN_DATA
)Parameter
;
491 if (LSData
->Session
->UserToken
!= NULL
&& !ImpersonateLoggedOnUser(LSData
->Session
->UserToken
))
493 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
497 /* Close processes of the interactive user */
499 EWX_INTERNAL_KILL_USER_APPS
| (LSData
->Flags
& EWX_FLAGS_MASK
) |
500 (EWX_LOGOFF
== (LSData
->Flags
& EWX_ACTION_MASK
) ? EWX_INTERNAL_FLAG_LOGOFF
: 0),
503 ERR("Unable to kill user apps, error %lu\n", GetLastError());
508 /* FIXME: Call ExitWindowsEx() to terminate COM processes */
510 if (LSData
->Session
->UserToken
)
518 CreateLogoffSecurityAttributes(
519 OUT PSECURITY_ATTRIBUTES
* ppsa
)
521 /* The following code is not working yet and messy */
522 /* Still, it gives some ideas about data types and functions involved and */
523 /* required to set up a SECURITY_DESCRIPTOR for a SECURITY_ATTRIBUTES */
524 /* instance for a thread, to allow that thread to ImpersonateLoggedOnUser(). */
525 /* Specifically THREAD_SET_THREAD_TOKEN is required. */
526 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
527 PSECURITY_ATTRIBUTES psa
= 0;
530 EXPLICIT_ACCESS Access
;
531 PSID pEveryoneSID
= NULL
;
532 static SID_IDENTIFIER_AUTHORITY WorldAuthority
= { SECURITY_WORLD_SID_AUTHORITY
};
536 // Let's first try to enumerate what kind of data we need for this to ever work:
537 // 1. The Winlogon SID, to be able to give it THREAD_SET_THREAD_TOKEN.
538 // 2. The users SID (the user trying to logoff, or rather shut down the system).
539 // 3. At least two EXPLICIT_ACCESS instances:
540 // 3.1 One for Winlogon itself, giving it the rights
541 // required to THREAD_SET_THREAD_TOKEN (as it's needed to successfully call
542 // ImpersonateLoggedOnUser).
543 // 3.2 One for the user, to allow *that* thread to perform its work.
544 // 4. An ACL to hold the these EXPLICIT_ACCESS ACE's.
545 // 5. A SECURITY_DESCRIPTOR to hold the ACL, and finally.
546 // 6. A SECURITY_ATTRIBUTES instance to pull all of this required stuff
547 // together, to hand it to CreateThread.
549 // However, it seems struct LOGOFF_SHUTDOWN_DATA doesn't contain
550 // these required SID's, why they'd have to be added.
551 // The Winlogon's own SID should probably only be created once,
552 // while the user's SID obviously must be created for each new user.
553 // Might as well store it when the user logs on?
555 if(!AllocateAndInitializeSid(&WorldAuthority
,
561 ERR("Failed to initialize security descriptor for logoff thread!\n");
562 return STATUS_UNSUCCESSFUL
;
565 /* set up the required security attributes to be able to shut down */
566 /* To save space and time, allocate a single block of memory holding */
567 /* both SECURITY_ATTRIBUTES and SECURITY_DESCRIPTOR */
568 pMem
= HeapAlloc(GetProcessHeap(),
570 sizeof(SECURITY_ATTRIBUTES
) +
571 SECURITY_DESCRIPTOR_MIN_LENGTH
+
575 ERR("Failed to allocate memory for logoff security descriptor!\n");
576 return STATUS_NO_MEMORY
;
579 /* Note that the security descriptor needs to be in _absolute_ format, */
580 /* meaning its members must be pointers to other structures, rather */
581 /* than the relative format using offsets */
582 psa
= (PSECURITY_ATTRIBUTES
)pMem
;
583 SecurityDescriptor
= (PSECURITY_DESCRIPTOR
)(pMem
+ sizeof(SECURITY_ATTRIBUTES
));
584 pACL
= (PACL
)(((PBYTE
)SecurityDescriptor
) + SECURITY_DESCRIPTOR_MIN_LENGTH
);
586 // Initialize an EXPLICIT_ACCESS structure for an ACE.
587 // The ACE will allow this thread to log off (and shut down the system, currently).
588 ZeroMemory(&Access
, sizeof(Access
));
589 Access
.grfAccessPermissions
= THREAD_SET_THREAD_TOKEN
;
590 Access
.grfAccessMode
= SET_ACCESS
; // GRANT_ACCESS?
591 Access
.grfInheritance
= NO_INHERITANCE
;
592 Access
.Trustee
.TrusteeForm
= TRUSTEE_IS_SID
;
593 Access
.Trustee
.TrusteeType
= TRUSTEE_IS_WELL_KNOWN_GROUP
;
594 Access
.Trustee
.ptstrName
= pEveryoneSID
;
596 if (SetEntriesInAcl(1, &Access
, NULL
, &pACL
) != ERROR_SUCCESS
)
598 ERR("Failed to set Access Rights for logoff thread. Logging out will most likely fail.\n");
600 HeapFree(GetProcessHeap(), 0, pMem
);
601 return STATUS_UNSUCCESSFUL
;
604 if (!InitializeSecurityDescriptor(SecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
))
606 ERR("Failed to initialize security descriptor for logoff thread!\n");
607 HeapFree(GetProcessHeap(), 0, pMem
);
608 return STATUS_UNSUCCESSFUL
;
611 if (!SetSecurityDescriptorDacl(SecurityDescriptor
,
612 TRUE
, // bDaclPresent flag
614 FALSE
)) // not a default DACL
616 ERR("SetSecurityDescriptorDacl Error %lu\n", GetLastError());
617 HeapFree(GetProcessHeap(), 0, pMem
);
618 return STATUS_UNSUCCESSFUL
;
621 psa
->nLength
= sizeof(SECURITY_ATTRIBUTES
);
622 psa
->lpSecurityDescriptor
= SecurityDescriptor
;
623 psa
->bInheritHandle
= FALSE
;
627 return STATUS_SUCCESS
;
631 DestroyLogoffSecurityAttributes(
632 IN PSECURITY_ATTRIBUTES psa
)
636 HeapFree(GetProcessHeap(), 0, psa
);
643 IN OUT PWLSESSION Session
,
646 PLOGOFF_SHUTDOWN_DATA LSData
;
647 PSECURITY_ATTRIBUTES psa
;
652 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_SAVEYOURSETTINGS
);
654 /* Prepare data for logoff thread */
655 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
658 ERR("Failed to allocate mem for thread data\n");
659 return STATUS_NO_MEMORY
;
661 LSData
->Flags
= Flags
;
662 LSData
->Session
= Session
;
664 Status
= CreateLogoffSecurityAttributes(&psa
);
665 if (!NT_SUCCESS(Status
))
667 ERR("Failed to create a required security descriptor. Status 0x%08lx\n", Status
);
668 HeapFree(GetProcessHeap(), 0, LSData
);
672 /* Run logoff thread */
673 hThread
= CreateThread(psa
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
675 /* we're done with the SECURITY_DESCRIPTOR */
676 DestroyLogoffSecurityAttributes(psa
);
681 ERR("Unable to create logoff thread, error %lu\n", GetLastError());
682 HeapFree(GetProcessHeap(), 0, LSData
);
683 return STATUS_UNSUCCESSFUL
;
685 WaitForSingleObject(hThread
, INFINITE
);
686 HeapFree(GetProcessHeap(), 0, LSData
);
687 if (!GetExitCodeThread(hThread
, &exitCode
))
689 ERR("Unable to get exit code of logoff thread (error %lu)\n", GetLastError());
690 CloseHandle(hThread
);
691 return STATUS_UNSUCCESSFUL
;
693 CloseHandle(hThread
);
696 ERR("Logoff thread returned failure\n");
697 return STATUS_UNSUCCESSFUL
;
700 UnloadUserProfile(Session
->UserToken
, Session
->hProfileInfo
);
701 CloseHandle(Session
->UserToken
);
702 UpdatePerUserSystemParameters(0, FALSE
);
703 Session
->LogonState
= STATE_LOGGED_OFF
;
704 Session
->UserToken
= NULL
;
705 return STATUS_SUCCESS
;
708 static INT_PTR CALLBACK
709 ShutdownComputerWindowProc(
715 UNREFERENCED_PARAMETER(lParam
);
721 switch (LOWORD(wParam
))
723 case IDC_BTNSHTDOWNCOMPUTER
:
724 EndDialog(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
);
731 RemoveMenu(GetSystemMenu(hwndDlg
, FALSE
), SC_CLOSE
, MF_BYCOMMAND
);
732 SetFocus(GetDlgItem(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
));
741 IN OUT PWLSESSION Session
)
743 if (Session
->SASWindow
)
745 DestroyWindow(Session
->SASWindow
);
746 Session
->SASWindow
= NULL
;
748 if (Session
->hEndOfScreenSaverThread
)
749 SetEvent(Session
->hEndOfScreenSaverThread
);
750 UnregisterClassW(WINLOGON_SAS_CLASS
, hAppInstance
);
755 IN OUT PWLSESSION Session
,
758 PLOGOFF_SHUTDOWN_DATA LSData
;
762 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_REACTOSISSHUTTINGDOWN
);
764 /* Prepare data for shutdown thread */
765 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
768 ERR("Failed to allocate mem for thread data\n");
769 return STATUS_NO_MEMORY
;
771 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
)
772 LSData
->Flags
= EWX_POWEROFF
;
773 else if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
774 LSData
->Flags
= EWX_REBOOT
;
776 LSData
->Flags
= EWX_SHUTDOWN
;
777 LSData
->Session
= Session
;
779 /* Run shutdown thread */
780 hThread
= CreateThread(NULL
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
783 ERR("Unable to create shutdown thread, error %lu\n", GetLastError());
784 HeapFree(GetProcessHeap(), 0, LSData
);
785 return STATUS_UNSUCCESSFUL
;
787 WaitForSingleObject(hThread
, INFINITE
);
788 HeapFree(GetProcessHeap(), 0, LSData
);
789 if (!GetExitCodeThread(hThread
, &exitCode
))
791 ERR("Unable to get exit code of shutdown thread (error %lu)\n", GetLastError());
792 CloseHandle(hThread
);
793 return STATUS_UNSUCCESSFUL
;
795 CloseHandle(hThread
);
798 ERR("Shutdown thread returned failure\n");
799 return STATUS_UNSUCCESSFUL
;
802 /* Destroy SAS window */
803 UninitializeSAS(Session
);
805 FIXME("FIXME: Call SMSS API #1\n");
806 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
807 NtShutdownSystem(ShutdownReboot
);
812 /* FIXME - only show this dialog if it's a shutdown and the computer doesn't support APM */
813 DialogBox(hAppInstance
, MAKEINTRESOURCE(IDD_SHUTDOWNCOMPUTER
), GetDesktopWindow(), ShutdownComputerWindowProc
);
815 NtShutdownSystem(ShutdownNoReboot
);
817 return STATUS_SUCCESS
;
822 IN OUT PWLSESSION Session
,
827 case WLX_SAS_ACTION_LOGON
: /* 0x01 */
828 if (HandleLogon(Session
))
830 SwitchDesktop(Session
->ApplicationDesktop
);
831 Session
->LogonState
= STATE_LOGGED_ON
;
834 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
836 case WLX_SAS_ACTION_NONE
: /* 0x02 */
838 case WLX_SAS_ACTION_LOCK_WKSTA
: /* 0x03 */
839 if (Session
->Gina
.Functions
.WlxIsLockOk(Session
->Gina
.Context
))
841 SwitchDesktop(WLSession
->WinlogonDesktop
);
842 Session
->LogonState
= STATE_LOCKED
;
843 Session
->Gina
.Functions
.WlxDisplayLockedNotice(Session
->Gina
.Context
);
846 case WLX_SAS_ACTION_LOGOFF
: /* 0x04 */
847 case WLX_SAS_ACTION_SHUTDOWN
: /* 0x05 */
848 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
: /* 0x0a */
849 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
: /* 0x0b */
850 if (Session
->LogonState
!= STATE_LOGGED_OFF
)
852 if (!Session
->Gina
.Functions
.WlxIsLogoffOk(Session
->Gina
.Context
))
854 SwitchDesktop(WLSession
->WinlogonDesktop
);
855 Session
->Gina
.Functions
.WlxLogoff(Session
->Gina
.Context
);
856 if (!NT_SUCCESS(HandleLogoff(Session
, EWX_LOGOFF
)))
858 RemoveStatusMessage(Session
);
862 if (WLX_SHUTTINGDOWN(wlxAction
))
864 Session
->Gina
.Functions
.WlxShutdown(Session
->Gina
.Context
, wlxAction
);
865 if (!NT_SUCCESS(HandleShutdown(Session
, wlxAction
)))
867 RemoveStatusMessage(Session
);
868 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
873 RemoveStatusMessage(Session
);
874 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
877 case WLX_SAS_ACTION_TASKLIST
: /* 0x07 */
878 SwitchDesktop(WLSession
->ApplicationDesktop
);
879 StartTaskManager(Session
);
881 case WLX_SAS_ACTION_UNLOCK_WKSTA
: /* 0x08 */
882 SwitchDesktop(WLSession
->ApplicationDesktop
);
883 Session
->LogonState
= STATE_LOGGED_ON
;
886 WARN("Unknown SAS action 0x%lx\n", wlxAction
);
892 IN OUT PWLSESSION Session
,
895 DWORD wlxAction
= WLX_SAS_ACTION_NONE
;
897 if (Session
->LogonState
== STATE_LOGGED_ON
)
898 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOnSAS(Session
->Gina
.Context
, dwSasType
, NULL
);
899 else if (Session
->LogonState
== STATE_LOCKED
)
900 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxWkstaLockedSAS(Session
->Gina
.Context
, dwSasType
);
903 /* Display a new dialog (if necessary) */
906 case WLX_SAS_TYPE_TIMEOUT
: /* 0x00 */
908 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
913 PSID LogonSid
= NULL
; /* FIXME */
915 Session
->Options
= 0;
917 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOutSAS(
918 Session
->Gina
.Context
,
924 &Session
->MprNotifyInfo
,
925 (PVOID
*)&Session
->Profile
);
931 if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_TIMEOUT
)
934 if (!Session
->Gina
.Functions
.WlxScreenSaverNotify(Session
->Gina
.Context
, &bSecure
))
936 /* Skip start of screen saver */
937 SetEvent(Session
->hEndOfScreenSaver
);
941 StartScreenSaver(Session
);
943 DoGenericAction(Session
, WLX_SAS_ACTION_LOCK_WKSTA
);
946 else if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_ACTIVITY
)
947 SetEvent(Session
->hUserActivity
);
949 DoGenericAction(Session
, wlxAction
);
954 IN PWLSESSION Session
,
957 /* Register Ctrl+Alt+Del Hotkey */
958 if (!RegisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
, MOD_CONTROL
| MOD_ALT
, VK_DELETE
))
960 ERR("WL: Unable to register Ctrl+Alt+Del hotkey!\n");
964 /* Register Ctrl+Shift+Esc (optional) */
965 Session
->TaskManHotkey
= RegisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
, MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
);
966 if (!Session
->TaskManHotkey
)
967 WARN("WL: Warning: Unable to register Ctrl+Alt+Esc hotkey!\n");
973 IN PWLSESSION Session
,
976 /* Unregister hotkeys */
977 UnregisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
);
979 if (Session
->TaskManHotkey
)
980 UnregisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
);
986 CheckForShutdownPrivilege(
987 IN DWORD RequestingProcessId
)
992 PPRIVILEGE_SET PrivSet
;
994 TRACE("CheckForShutdownPrivilege()\n");
996 Process
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, RequestingProcessId
);
999 WARN("OpenProcess() failed with error %lu\n", GetLastError());
1000 return STATUS_INVALID_HANDLE
;
1002 if (!OpenProcessToken(Process
, TOKEN_QUERY
, &Token
))
1004 WARN("OpenProcessToken() failed with error %lu\n", GetLastError());
1005 CloseHandle(Process
);
1006 return STATUS_INVALID_HANDLE
;
1008 CloseHandle(Process
);
1009 PrivSet
= HeapAlloc(GetProcessHeap(), 0, sizeof(PRIVILEGE_SET
) + sizeof(LUID_AND_ATTRIBUTES
));
1012 ERR("Failed to allocate mem for privilege set\n");
1014 return STATUS_NO_MEMORY
;
1016 PrivSet
->PrivilegeCount
= 1;
1017 PrivSet
->Control
= PRIVILEGE_SET_ALL_NECESSARY
;
1018 if (!LookupPrivilegeValue(NULL
, SE_SHUTDOWN_NAME
, &PrivSet
->Privilege
[0].Luid
))
1020 WARN("LookupPrivilegeValue() failed with error %lu\n", GetLastError());
1021 HeapFree(GetProcessHeap(), 0, PrivSet
);
1023 return STATUS_UNSUCCESSFUL
;
1025 if (!PrivilegeCheck(Token
, PrivSet
, &CheckResult
))
1027 WARN("PrivilegeCheck() failed with error %lu\n", GetLastError());
1028 HeapFree(GetProcessHeap(), 0, PrivSet
);
1030 return STATUS_ACCESS_DENIED
;
1032 HeapFree(GetProcessHeap(), 0, PrivSet
);
1037 WARN("SE_SHUTDOWN privilege not enabled\n");
1038 return STATUS_ACCESS_DENIED
;
1040 return STATUS_SUCCESS
;
1045 HandleMessageBeep(UINT uType
)
1055 EventName
= L
"SystemDefault";
1057 case MB_ICONASTERISK
:
1058 EventName
= L
"SystemAsterisk";
1060 case MB_ICONEXCLAMATION
:
1061 EventName
= L
"SystemExclamation";
1064 EventName
= L
"SystemHand";
1066 case MB_ICONQUESTION
:
1067 EventName
= L
"SystemQuestion";
1070 WARN("Unhandled type %d\n", uType
);
1071 EventName
= L
"SystemDefault";
1074 return PlaySoundRoutine(EventName
, FALSE
, SND_ALIAS
| SND_NOWAIT
| SND_NOSTOP
| SND_ASYNC
);
1077 static LRESULT CALLBACK
1084 PWLSESSION Session
= (PWLSESSION
)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
1092 case MAKELONG(MOD_CONTROL
| MOD_ALT
, VK_DELETE
):
1094 TRACE("SAS: CONTROL+ALT+DELETE\n");
1095 if (!Session
->Gina
.UseCtrlAltDelete
)
1097 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_CTRL_ALT_DEL
, 0);
1100 case MAKELONG(MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
):
1102 TRACE("SAS: CONTROL+SHIFT+ESCAPE\n");
1103 DoGenericAction(Session
, WLX_SAS_ACTION_TASKLIST
);
1111 /* Get the session pointer from the create data */
1112 Session
= (PWLSESSION
)((LPCREATESTRUCT
)lParam
)->lpCreateParams
;
1114 /* Save the Session pointer */
1115 SetWindowLongPtrW(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)Session
);
1118 return RegisterHotKeys(Session
, hwndDlg
);
1122 if (!GetSetupType())
1123 UnregisterHotKeys(Session
, hwndDlg
);
1126 case WM_SETTINGCHANGE
:
1128 UINT uiAction
= (UINT
)wParam
;
1129 if (uiAction
== SPI_SETSCREENSAVETIMEOUT
1130 || uiAction
== SPI_SETSCREENSAVEACTIVE
)
1132 SetEvent(Session
->hScreenSaverParametersChanged
);
1136 case WM_LOGONNOTIFY
:
1140 case LN_MESSAGE_BEEP
:
1142 return HandleMessageBeep(lParam
);
1144 case LN_SHELL_EXITED
:
1146 /* lParam is the exit code */
1149 SetTimer(hwndDlg
, 1, 1000, NULL
);
1153 case LN_START_SCREENSAVE
:
1155 DispatchSAS(Session
, WLX_SAS_TYPE_SCRNSVR_TIMEOUT
);
1158 case LN_LOCK_WORKSTATION
:
1160 DoGenericAction(Session
, WLX_SAS_ACTION_LOCK_WKSTA
);
1165 ERR("WM_LOGONNOTIFY case %d is unimplemented\n", wParam
);
1174 KillTimer(hwndDlg
, 1);
1175 StartUserShell(Session
);
1181 DispatchSAS(Session
, (DWORD
)wParam
);
1184 case PM_WINLOGON_EXITWINDOWS
:
1186 UINT Flags
= (UINT
)lParam
;
1187 UINT Action
= Flags
& EWX_ACTION_MASK
;
1190 /* Check parameters */
1193 case EWX_LOGOFF
: wlxAction
= WLX_SAS_ACTION_LOGOFF
; break;
1194 case EWX_SHUTDOWN
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN
; break;
1195 case EWX_REBOOT
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_REBOOT
; break;
1196 case EWX_POWEROFF
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
; break;
1199 ERR("Invalid ExitWindows action 0x%x\n", Action
);
1200 return STATUS_INVALID_PARAMETER
;
1204 if (WLX_SHUTTINGDOWN(wlxAction
))
1206 NTSTATUS Status
= CheckForShutdownPrivilege((DWORD
)wParam
);
1207 if (!NT_SUCCESS(Status
))
1210 DoGenericAction(Session
, wlxAction
);
1215 return DefWindowProc(hwndDlg
, uMsg
, wParam
, lParam
);
1220 IN OUT PWLSESSION Session
)
1225 if (!SwitchDesktop(Session
->WinlogonDesktop
))
1227 ERR("WL: Failed to switch to winlogon desktop\n");
1231 /* Register SAS window class */
1232 swc
.cbSize
= sizeof(WNDCLASSEXW
);
1233 swc
.style
= CS_SAVEBITS
;
1234 swc
.lpfnWndProc
= SASWindowProc
;
1237 swc
.hInstance
= hAppInstance
;
1240 swc
.hbrBackground
= NULL
;
1241 swc
.lpszMenuName
= NULL
;
1242 swc
.lpszClassName
= WINLOGON_SAS_CLASS
;
1244 if (RegisterClassExW(&swc
) == 0)
1246 ERR("WL: Failed to register SAS window class\n");
1250 /* Create invisible SAS window */
1251 Session
->SASWindow
= CreateWindowExW(
1257 hAppInstance
, Session
);
1258 if (!Session
->SASWindow
)
1260 ERR("WL: Failed to create SAS window\n");
1264 /* Register SAS window to receive SAS notifications */
1265 if (!SetLogonNotifyWindow(Session
->SASWindow
, Session
->InteractiveWindowStation
))
1267 ERR("WL: Failed to register SAS window\n");
1271 if (!SetDefaultLanguage(FALSE
))
1278 UninitializeSAS(Session
);