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 static BOOL inScrn
= FALSE
;
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
);
62 IN OUT PWLSESSION Session
)
64 LPVOID lpEnvironment
= NULL
;
68 /* Create environment block for the user */
69 if (!CreateEnvironmentBlock(&lpEnvironment
, Session
->UserToken
, TRUE
))
71 WARN("WL: CreateEnvironmentBlock() failed\n");
76 /* FIXME: who should do it? winlogon or gina? */
77 /* FIXME: reverting to lower privileges after creating user shell? */
78 RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
80 ret
= Session
->Gina
.Functions
.WlxActivateUserShell(
81 Session
->Gina
.Context
,
86 DestroyEnvironmentBlock(lpEnvironment
);
100 DWORD dwType
, dwSize
;
102 UNICODE_STRING ValueString
;
109 BaseKey
= HKEY_CURRENT_USER
;
110 SubKey
= L
"Control Panel\\International";
111 ValueName
= L
"Locale";
115 BaseKey
= HKEY_LOCAL_MACHINE
;
116 SubKey
= L
"System\\CurrentControlSet\\Control\\Nls\\Language";
117 ValueName
= L
"Default";
126 if (rc
!= ERROR_SUCCESS
)
128 TRACE("RegOpenKeyEx() failed with error %lu\n", rc
);
131 rc
= RegQueryValueExW(
138 if (rc
!= ERROR_SUCCESS
)
140 TRACE("RegQueryValueEx() failed with error %lu\n", rc
);
143 else if (dwType
!= REG_SZ
)
145 TRACE("Wrong type for %S\\%S registry entry (got 0x%lx, expected 0x%x)\n",
146 SubKey
, ValueName
, dwType
, REG_SZ
);
150 Value
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
153 TRACE("HeapAlloc() failed\n");
156 rc
= RegQueryValueExW(
163 if (rc
!= ERROR_SUCCESS
)
165 TRACE("RegQueryValueEx() failed with error %lu\n", rc
);
169 /* Convert Value to a Lcid */
170 ValueString
.Length
= ValueString
.MaximumLength
= (USHORT
)dwSize
;
171 ValueString
.Buffer
= Value
;
172 Status
= RtlUnicodeStringToInteger(&ValueString
, 16, (PULONG
)&Lcid
);
173 if (!NT_SUCCESS(Status
))
175 TRACE("RtlUnicodeStringToInteger() failed with status 0x%08lx\n", Status
);
179 TRACE("%s language is 0x%08lx\n",
180 UserProfile
? "User" : "System", Lcid
);
181 Status
= NtSetDefaultLocale(UserProfile
, Lcid
);
182 if (!NT_SUCCESS(Status
))
184 TRACE("NtSetDefaultLocale() failed with status 0x%08lx\n", Status
);
194 HeapFree(GetProcessHeap(), 0, Value
);
204 typedef BOOL (WINAPI
*PLAYSOUNDW
)(LPCWSTR
,HMODULE
,DWORD
);
205 typedef UINT (WINAPI
*WAVEOUTGETNUMDEVS
)(VOID
);
207 WAVEOUTGETNUMDEVS waveOutGetNumDevs
;
212 hLibrary
= LoadLibraryW(L
"winmm.dll");
215 waveOutGetNumDevs
= (WAVEOUTGETNUMDEVS
)GetProcAddress(hLibrary
, "waveOutGetNumDevs");
216 if (waveOutGetNumDevs
)
218 NumDevs
= waveOutGetNumDevs();
225 FreeLibrary(hLibrary
);
230 Play
= (PLAYSOUNDW
)GetProcAddress(hLibrary
, "PlaySoundW");
233 Ret
= Play(FileName
, NULL
, Flags
);
235 FreeLibrary(hLibrary
);
243 PlayLogonSoundThread(
244 IN LPVOID lpParameter
)
246 BYTE TokenUserBuffer
[256];
247 PTOKEN_USER pTokenUser
= (TOKEN_USER
*)TokenUserBuffer
;
250 WCHAR wszBuffer
[MAX_PATH
] = {0};
251 WCHAR wszDest
[MAX_PATH
];
252 DWORD dwSize
= sizeof(wszBuffer
), dwType
;
253 SERVICE_STATUS_PROCESS Info
;
254 UNICODE_STRING SidString
;
257 SC_HANDLE hSCManager
, hService
;
259 /* Get SID of current user */
260 Status
= NtQueryInformationToken((HANDLE
)lpParameter
,
263 sizeof(TokenUserBuffer
),
265 if (!NT_SUCCESS(Status
))
267 ERR("NtQueryInformationToken failed: %x!\n", Status
);
271 /* Convert SID to string */
272 RtlInitEmptyUnicodeString(&SidString
, wszBuffer
, sizeof(wszBuffer
));
273 Status
= RtlConvertSidToUnicodeString(&SidString
, pTokenUser
->User
.Sid
, FALSE
);
274 if (!NT_SUCCESS(Status
))
276 ERR("RtlConvertSidToUnicodeString failed: %x!\n", Status
);
280 /* Build path to logon sound registry key.
281 Note: We can't use HKCU here, because Winlogon is owned by SYSTEM user */
282 if (FAILED(StringCbCopyW(wszBuffer
+ SidString
.Length
/sizeof(WCHAR
),
283 sizeof(wszBuffer
) - SidString
.Length
,
284 L
"\\AppEvents\\Schemes\\Apps\\.Default\\WindowsLogon\\.Current")))
286 /* SID is too long. Should not happen. */
287 ERR("StringCbCopyW failed!\n");
291 /* Open registry key and query sound path */
292 if (RegOpenKeyExW(HKEY_USERS
, wszBuffer
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
294 ERR("RegOpenKeyExW(%ls) failed!\n", wszBuffer
);
298 if (RegQueryValueExW(hKey
, NULL
, NULL
, &dwType
,
299 (LPBYTE
)wszBuffer
, &dwSize
) != ERROR_SUCCESS
||
300 (dwType
!= REG_SZ
&& dwType
!= REG_EXPAND_SZ
))
302 ERR("RegQueryValueExW failed!\n");
311 /* No sound has been set */
312 ERR("No sound has been set\n");
316 /* Expand environment variables */
317 if (!ExpandEnvironmentStringsW(wszBuffer
, wszDest
, MAX_PATH
))
319 ERR("ExpandEnvironmentStringsW failed!\n");
323 /* Open service manager */
324 hSCManager
= OpenSCManager(NULL
, NULL
, SC_MANAGER_CONNECT
);
327 ERR("OpenSCManager failed (%x)\n", GetLastError());
331 /* Open wdmaud service */
332 hService
= OpenServiceW(hSCManager
, L
"wdmaud", GENERIC_READ
);
335 /* Sound is not installed */
336 TRACE("Failed to open wdmaud service (%x)\n", GetLastError());
337 CloseServiceHandle(hSCManager
);
341 /* Wait for wdmaud start */
344 if (!QueryServiceStatusEx(hService
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&Info
, sizeof(SERVICE_STATUS_PROCESS
), &dwSize
))
346 TRACE("QueryServiceStatusEx failed (%x)\n", GetLastError());
350 if (Info
.dwCurrentState
== SERVICE_RUNNING
)
355 } while (Index
++ < 20);
357 CloseServiceHandle(hService
);
358 CloseServiceHandle(hSCManager
);
360 /* If wdmaud is not running exit */
361 if (Info
.dwCurrentState
!= SERVICE_RUNNING
)
363 WARN("wdmaud has not started!\n");
367 /* Sound subsystem is running. Play logon sound. */
368 TRACE("Playing logon sound: %ls\n", wszDest
);
369 PlaySoundRoutine(wszDest
, TRUE
, SND_FILENAME
);
375 IN OUT PWLSESSION Session
)
379 hThread
= CreateThread(NULL
, 0, PlayLogonSoundThread
, (PVOID
)Session
->UserToken
, 0, NULL
);
381 CloseHandle(hThread
);
386 IN OUT PWLSESSION Session
)
388 PROFILEINFOW ProfileInfo
;
391 /* Loading personal settings */
392 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_LOADINGYOURPERSONALSETTINGS
);
393 ProfileInfo
.hProfile
= INVALID_HANDLE_VALUE
;
394 if (0 == (Session
->Options
& WLX_LOGON_OPT_NO_PROFILE
))
396 if (Session
->Profile
== NULL
397 || (Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V1_0
398 && Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V2_0
))
400 ERR("WL: Wrong profile\n");
404 /* Load the user profile */
405 ZeroMemory(&ProfileInfo
, sizeof(PROFILEINFOW
));
406 ProfileInfo
.dwSize
= sizeof(PROFILEINFOW
);
407 ProfileInfo
.dwFlags
= 0;
408 ProfileInfo
.lpUserName
= Session
->MprNotifyInfo
.pszUserName
;
409 ProfileInfo
.lpProfilePath
= Session
->Profile
->pszProfile
;
410 if (Session
->Profile
->dwType
>= WLX_PROFILE_TYPE_V2_0
)
412 ProfileInfo
.lpDefaultPath
= Session
->Profile
->pszNetworkDefaultUserProfile
;
413 ProfileInfo
.lpServerName
= Session
->Profile
->pszServerName
;
414 ProfileInfo
.lpPolicyPath
= Session
->Profile
->pszPolicy
;
417 if (!LoadUserProfileW(Session
->UserToken
, &ProfileInfo
))
419 ERR("WL: LoadUserProfileW() failed\n");
424 /* Create environment block for the user */
425 if (!CreateUserEnvironment(Session
))
427 WARN("WL: SetUserEnvironment() failed\n");
431 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_APPLYINGYOURPERSONALSETTINGS
);
432 UpdatePerUserSystemParameters(0, TRUE
);
434 /* Set default language */
435 if (!SetDefaultLanguage(TRUE
))
437 WARN("WL: SetDefaultLanguage() failed\n");
441 if (!StartUserShell(Session
))
443 //WCHAR StatusMsg[256];
444 WARN("WL: WlxActivateUserShell() failed\n");
445 //LoadStringW(hAppInstance, IDS_FAILEDACTIVATEUSERSHELL, StatusMsg, sizeof(StatusMsg));
446 //MessageBoxW(0, StatusMsg, NULL, MB_ICONERROR);
450 if (!InitializeScreenSaver(Session
))
451 WARN("WL: Failed to initialize screen saver\n");
453 Session
->hProfileInfo
= ProfileInfo
.hProfile
;
455 /* Logon has successed. Play sound. */
456 PlayLogonSound(Session
);
461 if (Session
->Profile
)
463 HeapFree(GetProcessHeap(), 0, Session
->Profile
->pszProfile
);
464 HeapFree(GetProcessHeap(), 0, Session
->Profile
);
466 Session
->Profile
= NULL
;
468 && ProfileInfo
.hProfile
!= INVALID_HANDLE_VALUE
)
470 UnloadUserProfile(WLSession
->UserToken
, ProfileInfo
.hProfile
);
472 RemoveStatusMessage(Session
);
475 CloseHandle(Session
->UserToken
);
476 Session
->UserToken
= NULL
;
481 #define EWX_ACTION_MASK 0xffffffeb
482 #define EWX_FLAGS_MASK 0x00000014
484 typedef struct tagLOGOFF_SHUTDOWN_DATA
488 } LOGOFF_SHUTDOWN_DATA
, *PLOGOFF_SHUTDOWN_DATA
;
491 LogoffShutdownThread(LPVOID Parameter
)
493 PLOGOFF_SHUTDOWN_DATA LSData
= (PLOGOFF_SHUTDOWN_DATA
)Parameter
;
495 if (LSData
->Session
->UserToken
!= NULL
&& !ImpersonateLoggedOnUser(LSData
->Session
->UserToken
))
497 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
501 /* Close processes of the interactive user */
503 EWX_INTERNAL_KILL_USER_APPS
| (LSData
->Flags
& EWX_FLAGS_MASK
) |
504 (EWX_LOGOFF
== (LSData
->Flags
& EWX_ACTION_MASK
) ? EWX_INTERNAL_FLAG_LOGOFF
: 0),
507 ERR("Unable to kill user apps, error %lu\n", GetLastError());
512 /* FIXME: Call ExitWindowsEx() to terminate COM processes */
514 if (LSData
->Session
->UserToken
)
522 CreateLogoffSecurityAttributes(
523 OUT PSECURITY_ATTRIBUTES
* ppsa
)
525 /* The following code is not working yet and messy */
526 /* Still, it gives some ideas about data types and functions involved and */
527 /* required to set up a SECURITY_DESCRIPTOR for a SECURITY_ATTRIBUTES */
528 /* instance for a thread, to allow that thread to ImpersonateLoggedOnUser(). */
529 /* Specifically THREAD_SET_THREAD_TOKEN is required. */
530 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
531 PSECURITY_ATTRIBUTES psa
= 0;
534 EXPLICIT_ACCESS Access
;
535 PSID pEveryoneSID
= NULL
;
536 static SID_IDENTIFIER_AUTHORITY WorldAuthority
= { SECURITY_WORLD_SID_AUTHORITY
};
540 // Let's first try to enumerate what kind of data we need for this to ever work:
541 // 1. The Winlogon SID, to be able to give it THREAD_SET_THREAD_TOKEN.
542 // 2. The users SID (the user trying to logoff, or rather shut down the system).
543 // 3. At least two EXPLICIT_ACCESS instances:
544 // 3.1 One for Winlogon itself, giving it the rights
545 // required to THREAD_SET_THREAD_TOKEN (as it's needed to successfully call
546 // ImpersonateLoggedOnUser).
547 // 3.2 One for the user, to allow *that* thread to perform its work.
548 // 4. An ACL to hold the these EXPLICIT_ACCESS ACE's.
549 // 5. A SECURITY_DESCRIPTOR to hold the ACL, and finally.
550 // 6. A SECURITY_ATTRIBUTES instance to pull all of this required stuff
551 // together, to hand it to CreateThread.
553 // However, it seems struct LOGOFF_SHUTDOWN_DATA doesn't contain
554 // these required SID's, why they'd have to be added.
555 // The Winlogon's own SID should probably only be created once,
556 // while the user's SID obviously must be created for each new user.
557 // Might as well store it when the user logs on?
559 if(!AllocateAndInitializeSid(&WorldAuthority
,
565 ERR("Failed to initialize security descriptor for logoff thread!\n");
566 return STATUS_UNSUCCESSFUL
;
569 /* set up the required security attributes to be able to shut down */
570 /* To save space and time, allocate a single block of memory holding */
571 /* both SECURITY_ATTRIBUTES and SECURITY_DESCRIPTOR */
572 pMem
= HeapAlloc(GetProcessHeap(),
574 sizeof(SECURITY_ATTRIBUTES
) +
575 SECURITY_DESCRIPTOR_MIN_LENGTH
+
579 ERR("Failed to allocate memory for logoff security descriptor!\n");
580 return STATUS_NO_MEMORY
;
583 /* Note that the security descriptor needs to be in _absolute_ format, */
584 /* meaning its members must be pointers to other structures, rather */
585 /* than the relative format using offsets */
586 psa
= (PSECURITY_ATTRIBUTES
)pMem
;
587 SecurityDescriptor
= (PSECURITY_DESCRIPTOR
)(pMem
+ sizeof(SECURITY_ATTRIBUTES
));
588 pACL
= (PACL
)(((PBYTE
)SecurityDescriptor
) + SECURITY_DESCRIPTOR_MIN_LENGTH
);
590 // Initialize an EXPLICIT_ACCESS structure for an ACE.
591 // The ACE will allow this thread to log off (and shut down the system, currently).
592 ZeroMemory(&Access
, sizeof(Access
));
593 Access
.grfAccessPermissions
= THREAD_SET_THREAD_TOKEN
;
594 Access
.grfAccessMode
= SET_ACCESS
; // GRANT_ACCESS?
595 Access
.grfInheritance
= NO_INHERITANCE
;
596 Access
.Trustee
.TrusteeForm
= TRUSTEE_IS_SID
;
597 Access
.Trustee
.TrusteeType
= TRUSTEE_IS_WELL_KNOWN_GROUP
;
598 Access
.Trustee
.ptstrName
= pEveryoneSID
;
600 if (SetEntriesInAcl(1, &Access
, NULL
, &pACL
) != ERROR_SUCCESS
)
602 ERR("Failed to set Access Rights for logoff thread. Logging out will most likely fail.\n");
604 HeapFree(GetProcessHeap(), 0, pMem
);
605 return STATUS_UNSUCCESSFUL
;
608 if (!InitializeSecurityDescriptor(SecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
))
610 ERR("Failed to initialize security descriptor for logoff thread!\n");
611 HeapFree(GetProcessHeap(), 0, pMem
);
612 return STATUS_UNSUCCESSFUL
;
615 if (!SetSecurityDescriptorDacl(SecurityDescriptor
,
616 TRUE
, // bDaclPresent flag
618 FALSE
)) // not a default DACL
620 ERR("SetSecurityDescriptorDacl Error %lu\n", GetLastError());
621 HeapFree(GetProcessHeap(), 0, pMem
);
622 return STATUS_UNSUCCESSFUL
;
625 psa
->nLength
= sizeof(SECURITY_ATTRIBUTES
);
626 psa
->lpSecurityDescriptor
= SecurityDescriptor
;
627 psa
->bInheritHandle
= FALSE
;
631 return STATUS_SUCCESS
;
635 DestroyLogoffSecurityAttributes(
636 IN PSECURITY_ATTRIBUTES psa
)
640 HeapFree(GetProcessHeap(), 0, psa
);
647 IN OUT PWLSESSION Session
,
650 PLOGOFF_SHUTDOWN_DATA LSData
;
651 PSECURITY_ATTRIBUTES psa
;
656 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_SAVEYOURSETTINGS
);
658 /* Prepare data for logoff thread */
659 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
662 ERR("Failed to allocate mem for thread data\n");
663 return STATUS_NO_MEMORY
;
665 LSData
->Flags
= Flags
;
666 LSData
->Session
= Session
;
668 Status
= CreateLogoffSecurityAttributes(&psa
);
669 if (!NT_SUCCESS(Status
))
671 ERR("Failed to create a required security descriptor. Status 0x%08lx\n", Status
);
672 HeapFree(GetProcessHeap(), 0, LSData
);
676 /* Run logoff thread */
677 hThread
= CreateThread(psa
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
679 /* we're done with the SECURITY_DESCRIPTOR */
680 DestroyLogoffSecurityAttributes(psa
);
685 ERR("Unable to create logoff thread, error %lu\n", GetLastError());
686 HeapFree(GetProcessHeap(), 0, LSData
);
687 return STATUS_UNSUCCESSFUL
;
689 WaitForSingleObject(hThread
, INFINITE
);
690 HeapFree(GetProcessHeap(), 0, LSData
);
691 if (!GetExitCodeThread(hThread
, &exitCode
))
693 ERR("Unable to get exit code of logoff thread (error %lu)\n", GetLastError());
694 CloseHandle(hThread
);
695 return STATUS_UNSUCCESSFUL
;
697 CloseHandle(hThread
);
700 ERR("Logoff thread returned failure\n");
701 return STATUS_UNSUCCESSFUL
;
704 UnloadUserProfile(Session
->UserToken
, Session
->hProfileInfo
);
705 CloseHandle(Session
->UserToken
);
706 UpdatePerUserSystemParameters(0, FALSE
);
707 Session
->LogonStatus
= WKSTA_IS_LOGGED_OFF
;
708 Session
->UserToken
= NULL
;
709 return STATUS_SUCCESS
;
712 static INT_PTR CALLBACK
713 ShutdownComputerWindowProc(
719 UNREFERENCED_PARAMETER(lParam
);
725 switch (LOWORD(wParam
))
727 case IDC_BTNSHTDOWNCOMPUTER
:
728 EndDialog(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
);
735 RemoveMenu(GetSystemMenu(hwndDlg
, FALSE
), SC_CLOSE
, MF_BYCOMMAND
);
736 SetFocus(GetDlgItem(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
));
745 IN OUT PWLSESSION Session
)
747 if (Session
->SASWindow
)
749 DestroyWindow(Session
->SASWindow
);
750 Session
->SASWindow
= NULL
;
752 if (Session
->hEndOfScreenSaverThread
)
753 SetEvent(Session
->hEndOfScreenSaverThread
);
754 UnregisterClassW(WINLOGON_SAS_CLASS
, hAppInstance
);
759 IN OUT PWLSESSION Session
,
762 PLOGOFF_SHUTDOWN_DATA LSData
;
766 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_REACTOSISSHUTTINGDOWN
);
768 /* Prepare data for shutdown thread */
769 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
772 ERR("Failed to allocate mem for thread data\n");
773 return STATUS_NO_MEMORY
;
775 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
)
776 LSData
->Flags
= EWX_POWEROFF
;
777 else if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
778 LSData
->Flags
= EWX_REBOOT
;
780 LSData
->Flags
= EWX_SHUTDOWN
;
781 LSData
->Session
= Session
;
783 /* Run shutdown thread */
784 hThread
= CreateThread(NULL
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
787 ERR("Unable to create shutdown thread, error %lu\n", GetLastError());
788 HeapFree(GetProcessHeap(), 0, LSData
);
789 return STATUS_UNSUCCESSFUL
;
791 WaitForSingleObject(hThread
, INFINITE
);
792 HeapFree(GetProcessHeap(), 0, LSData
);
793 if (!GetExitCodeThread(hThread
, &exitCode
))
795 ERR("Unable to get exit code of shutdown thread (error %lu)\n", GetLastError());
796 CloseHandle(hThread
);
797 return STATUS_UNSUCCESSFUL
;
799 CloseHandle(hThread
);
802 ERR("Shutdown thread returned failure\n");
803 return STATUS_UNSUCCESSFUL
;
806 /* Destroy SAS window */
807 UninitializeSAS(Session
);
809 FIXME("FIXME: Call SMSS API #1\n");
810 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
811 NtShutdownSystem(ShutdownReboot
);
816 /* FIXME - only show this dialog if it's a shutdown and the computer doesn't support APM */
817 DialogBox(hAppInstance
, MAKEINTRESOURCE(IDD_SHUTDOWNCOMPUTER
), GetDesktopWindow(), ShutdownComputerWindowProc
);
819 NtShutdownSystem(ShutdownNoReboot
);
821 return STATUS_SUCCESS
;
826 IN OUT PWLSESSION Session
,
831 case WLX_SAS_ACTION_LOGON
: /* 0x01 */
832 if (HandleLogon(Session
))
834 SwitchDesktop(Session
->ApplicationDesktop
);
835 Session
->LogonStatus
= WKSTA_IS_LOGGED_ON
;
838 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
840 case WLX_SAS_ACTION_NONE
: /* 0x02 */
842 case WLX_SAS_ACTION_LOCK_WKSTA
: /* 0x03 */
843 if (Session
->Gina
.Functions
.WlxIsLockOk(Session
->Gina
.Context
))
845 SwitchDesktop(WLSession
->WinlogonDesktop
);
846 Session
->LogonStatus
= WKSTA_IS_LOCKED
;
847 Session
->Gina
.Functions
.WlxDisplayLockedNotice(Session
->Gina
.Context
);
850 case WLX_SAS_ACTION_LOGOFF
: /* 0x04 */
851 case WLX_SAS_ACTION_SHUTDOWN
: /* 0x05 */
852 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
: /* 0x0a */
853 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
: /* 0x0b */
854 if (Session
->LogonStatus
!= WKSTA_IS_LOGGED_OFF
)
856 if (!Session
->Gina
.Functions
.WlxIsLogoffOk(Session
->Gina
.Context
))
858 SwitchDesktop(WLSession
->WinlogonDesktop
);
859 Session
->Gina
.Functions
.WlxLogoff(Session
->Gina
.Context
);
860 if (!NT_SUCCESS(HandleLogoff(Session
, EWX_LOGOFF
)))
862 RemoveStatusMessage(Session
);
866 if (WLX_SHUTTINGDOWN(wlxAction
))
868 Session
->Gina
.Functions
.WlxShutdown(Session
->Gina
.Context
, wlxAction
);
869 if (!NT_SUCCESS(HandleShutdown(Session
, wlxAction
)))
871 RemoveStatusMessage(Session
);
872 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
877 RemoveStatusMessage(Session
);
878 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
881 case WLX_SAS_ACTION_TASKLIST
: /* 0x07 */
882 SwitchDesktop(WLSession
->ApplicationDesktop
);
883 StartTaskManager(Session
);
885 case WLX_SAS_ACTION_UNLOCK_WKSTA
: /* 0x08 */
886 SwitchDesktop(WLSession
->ApplicationDesktop
);
887 Session
->LogonStatus
= WKSTA_IS_LOGGED_ON
;
890 WARN("Unknown SAS action 0x%lx\n", wlxAction
);
896 IN OUT PWLSESSION Session
,
899 DWORD wlxAction
= WLX_SAS_ACTION_NONE
;
901 if (Session
->LogonStatus
== WKSTA_IS_LOGGED_ON
)
902 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOnSAS(Session
->Gina
.Context
, dwSasType
, NULL
);
903 else if (Session
->LogonStatus
== WKSTA_IS_LOCKED
)
904 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxWkstaLockedSAS(Session
->Gina
.Context
, dwSasType
);
907 /* Display a new dialog (if necessary) */
910 case WLX_SAS_TYPE_TIMEOUT
: /* 0x00 */
912 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
917 PSID LogonSid
= NULL
; /* FIXME */
919 Session
->Options
= 0;
921 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOutSAS(
922 Session
->Gina
.Context
,
928 &Session
->MprNotifyInfo
,
929 (PVOID
*)&Session
->Profile
);
935 if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_TIMEOUT
)
938 if (!Session
->Gina
.Functions
.WlxScreenSaverNotify(Session
->Gina
.Context
, &bSecure
))
940 /* Skip start of screen saver */
941 SetEvent(Session
->hEndOfScreenSaver
);
946 DoGenericAction(Session
, WLX_SAS_ACTION_LOCK_WKSTA
);
947 StartScreenSaver(Session
);
950 else if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_ACTIVITY
)
951 SetEvent(Session
->hUserActivity
);
953 DoGenericAction(Session
, wlxAction
);
958 IN PWLSESSION Session
,
961 /* Register Ctrl+Alt+Del Hotkey */
962 if (!RegisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
, MOD_CONTROL
| MOD_ALT
, VK_DELETE
))
964 ERR("WL: Unable to register Ctrl+Alt+Del hotkey!\n");
968 /* Register Ctrl+Shift+Esc (optional) */
969 Session
->TaskManHotkey
= RegisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
, MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
);
970 if (!Session
->TaskManHotkey
)
971 WARN("WL: Warning: Unable to register Ctrl+Alt+Esc hotkey!\n");
977 IN PWLSESSION Session
,
980 /* Unregister hotkeys */
981 UnregisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
);
983 if (Session
->TaskManHotkey
)
984 UnregisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
);
990 CheckForShutdownPrivilege(
991 IN DWORD RequestingProcessId
)
996 PPRIVILEGE_SET PrivSet
;
998 TRACE("CheckForShutdownPrivilege()\n");
1000 Process
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, RequestingProcessId
);
1003 WARN("OpenProcess() failed with error %lu\n", GetLastError());
1004 return STATUS_INVALID_HANDLE
;
1006 if (!OpenProcessToken(Process
, TOKEN_QUERY
, &Token
))
1008 WARN("OpenProcessToken() failed with error %lu\n", GetLastError());
1009 CloseHandle(Process
);
1010 return STATUS_INVALID_HANDLE
;
1012 CloseHandle(Process
);
1013 PrivSet
= HeapAlloc(GetProcessHeap(), 0, sizeof(PRIVILEGE_SET
) + sizeof(LUID_AND_ATTRIBUTES
));
1016 ERR("Failed to allocate mem for privilege set\n");
1018 return STATUS_NO_MEMORY
;
1020 PrivSet
->PrivilegeCount
= 1;
1021 PrivSet
->Control
= PRIVILEGE_SET_ALL_NECESSARY
;
1022 if (!LookupPrivilegeValue(NULL
, SE_SHUTDOWN_NAME
, &PrivSet
->Privilege
[0].Luid
))
1024 WARN("LookupPrivilegeValue() failed with error %lu\n", GetLastError());
1025 HeapFree(GetProcessHeap(), 0, PrivSet
);
1027 return STATUS_UNSUCCESSFUL
;
1029 if (!PrivilegeCheck(Token
, PrivSet
, &CheckResult
))
1031 WARN("PrivilegeCheck() failed with error %lu\n", GetLastError());
1032 HeapFree(GetProcessHeap(), 0, PrivSet
);
1034 return STATUS_ACCESS_DENIED
;
1036 HeapFree(GetProcessHeap(), 0, PrivSet
);
1041 WARN("SE_SHUTDOWN privilege not enabled\n");
1042 return STATUS_ACCESS_DENIED
;
1044 return STATUS_SUCCESS
;
1049 HandleMessageBeep(UINT uType
)
1059 EventName
= L
"SystemDefault";
1061 case MB_ICONASTERISK
:
1062 EventName
= L
"SystemAsterisk";
1064 case MB_ICONEXCLAMATION
:
1065 EventName
= L
"SystemExclamation";
1068 EventName
= L
"SystemHand";
1070 case MB_ICONQUESTION
:
1071 EventName
= L
"SystemQuestion";
1074 WARN("Unhandled type %d\n", uType
);
1075 EventName
= L
"SystemDefault";
1078 return PlaySoundRoutine(EventName
, FALSE
, SND_ALIAS
| SND_NOWAIT
| SND_NOSTOP
| SND_ASYNC
);
1081 static LRESULT CALLBACK
1088 PWLSESSION Session
= (PWLSESSION
)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
1096 case MAKELONG(MOD_CONTROL
| MOD_ALT
, VK_DELETE
):
1098 TRACE("SAS: CONTROL+ALT+DELETE\n");
1099 if (!Session
->Gina
.UseCtrlAltDelete
)
1101 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_CTRL_ALT_DEL
, 0);
1104 case MAKELONG(MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
):
1106 TRACE("SAS: CONTROL+SHIFT+ESCAPE\n");
1107 DoGenericAction(Session
, WLX_SAS_ACTION_TASKLIST
);
1115 /* Get the session pointer from the create data */
1116 Session
= (PWLSESSION
)((LPCREATESTRUCT
)lParam
)->lpCreateParams
;
1118 /* Save the Session pointer */
1119 SetWindowLongPtrW(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)Session
);
1122 return RegisterHotKeys(Session
, hwndDlg
);
1126 if (!GetSetupType())
1127 UnregisterHotKeys(Session
, hwndDlg
);
1130 case WM_SETTINGCHANGE
:
1132 UINT uiAction
= (UINT
)wParam
;
1133 if (uiAction
== SPI_SETSCREENSAVETIMEOUT
1134 || uiAction
== SPI_SETSCREENSAVEACTIVE
)
1136 SetEvent(Session
->hScreenSaverParametersChanged
);
1140 case WM_LOGONNOTIFY
:
1144 case LN_MESSAGE_BEEP
:
1146 return HandleMessageBeep(lParam
);
1148 case LN_SHELL_EXITED
:
1150 /* lParam is the exit code */
1153 SetTimer(hwndDlg
, 1, 1000, NULL
);
1157 case LN_START_SCREENSAVE
:
1159 BOOL bSecure
= FALSE
;
1166 // lParam 1 == Secure
1169 if (Session
->Gina
.Functions
.WlxScreenSaverNotify(Session
->Gina
.Context
, &bSecure
))
1171 if (bSecure
) DoGenericAction(Session
, WLX_SAS_ACTION_LOCK_WKSTA
);
1175 StartScreenSaver(Session
);
1181 ERR("WM_LOGONNOTIFY case %d is unimplemented\n", wParam
);
1190 KillTimer(hwndDlg
, 1);
1191 StartUserShell(Session
);
1197 DispatchSAS(Session
, (DWORD
)wParam
);
1200 case PM_WINLOGON_EXITWINDOWS
:
1202 UINT Flags
= (UINT
)lParam
;
1203 UINT Action
= Flags
& EWX_ACTION_MASK
;
1206 /* Check parameters */
1209 case EWX_LOGOFF
: wlxAction
= WLX_SAS_ACTION_LOGOFF
; break;
1210 case EWX_SHUTDOWN
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN
; break;
1211 case EWX_REBOOT
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_REBOOT
; break;
1212 case EWX_POWEROFF
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
; break;
1215 ERR("Invalid ExitWindows action 0x%x\n", Action
);
1216 return STATUS_INVALID_PARAMETER
;
1220 if (WLX_SHUTTINGDOWN(wlxAction
))
1222 NTSTATUS Status
= CheckForShutdownPrivilege((DWORD
)wParam
);
1223 if (!NT_SUCCESS(Status
))
1226 DoGenericAction(Session
, wlxAction
);
1231 return DefWindowProc(hwndDlg
, uMsg
, wParam
, lParam
);
1236 IN OUT PWLSESSION Session
)
1241 if (!SwitchDesktop(Session
->WinlogonDesktop
))
1243 ERR("WL: Failed to switch to winlogon desktop\n");
1247 /* Register SAS window class */
1248 swc
.cbSize
= sizeof(WNDCLASSEXW
);
1249 swc
.style
= CS_SAVEBITS
;
1250 swc
.lpfnWndProc
= SASWindowProc
;
1253 swc
.hInstance
= hAppInstance
;
1256 swc
.hbrBackground
= NULL
;
1257 swc
.lpszMenuName
= NULL
;
1258 swc
.lpszClassName
= WINLOGON_SAS_CLASS
;
1260 if (RegisterClassExW(&swc
) == 0)
1262 ERR("WL: Failed to register SAS window class\n");
1266 /* Create invisible SAS window */
1267 Session
->SASWindow
= CreateWindowExW(
1273 hAppInstance
, Session
);
1274 if (!Session
->SASWindow
)
1276 ERR("WL: Failed to create SAS window\n");
1280 /* Register SAS window to receive SAS notifications */
1281 if (!SetLogonNotifyWindow(Session
->SASWindow
, Session
->InteractiveWindowStation
))
1283 ERR("WL: Failed to register SAS window\n");
1287 if (!SetDefaultLanguage(FALSE
))
1294 UninitializeSAS(Session
);