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 /* GLOBALS ******************************************************************/
18 #define WINLOGON_SAS_CLASS L"SAS Window class"
19 #define WINLOGON_SAS_TITLE L"SAS window"
21 #define HK_CTRL_ALT_DEL 0
22 #define HK_CTRL_SHIFT_ESC 1
24 #define EWX_ACTION_MASK 0xffffffeb
25 #define EWX_FLAGS_MASK 0x00000014
27 typedef struct tagLOGOFF_SHUTDOWN_DATA
31 } LOGOFF_SHUTDOWN_DATA
, *PLOGOFF_SHUTDOWN_DATA
;
33 /* FUNCTIONS ****************************************************************/
37 IN OUT PWLSESSION Session
)
42 if (!Session
->Gina
.Functions
.WlxStartApplication
)
45 if (!CreateEnvironmentBlock(
53 ret
= Session
->Gina
.Functions
.WlxStartApplication(
54 Session
->Gina
.Context
,
59 DestroyEnvironmentBlock(lpEnvironment
);
65 IN OUT PWLSESSION Session
)
67 LPVOID lpEnvironment
= NULL
;
71 /* Create environment block for the user */
72 if (!CreateEnvironmentBlock(&lpEnvironment
, Session
->UserToken
, TRUE
))
74 WARN("WL: CreateEnvironmentBlock() failed\n");
79 /* FIXME: who should do it? winlogon or gina? */
80 /* FIXME: reverting to lower privileges after creating user shell? */
81 RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
83 ret
= Session
->Gina
.Functions
.WlxActivateUserShell(
84 Session
->Gina
.Context
,
89 DestroyEnvironmentBlock(lpEnvironment
);
103 DWORD dwType
, dwSize
;
105 UNICODE_STRING ValueString
;
112 BaseKey
= HKEY_CURRENT_USER
;
113 SubKey
= L
"Control Panel\\International";
114 ValueName
= L
"Locale";
118 BaseKey
= HKEY_LOCAL_MACHINE
;
119 SubKey
= L
"System\\CurrentControlSet\\Control\\Nls\\Language";
120 ValueName
= L
"Default";
129 if (rc
!= ERROR_SUCCESS
)
131 TRACE("RegOpenKeyEx() failed with error %lu\n", rc
);
134 rc
= RegQueryValueExW(
141 if (rc
!= ERROR_SUCCESS
)
143 TRACE("RegQueryValueEx() failed with error %lu\n", rc
);
146 else if (dwType
!= REG_SZ
)
148 TRACE("Wrong type for %S\\%S registry entry (got 0x%lx, expected 0x%x)\n",
149 SubKey
, ValueName
, dwType
, REG_SZ
);
153 Value
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
156 TRACE("HeapAlloc() failed\n");
159 rc
= RegQueryValueExW(
166 if (rc
!= ERROR_SUCCESS
)
168 TRACE("RegQueryValueEx() failed with error %lu\n", rc
);
172 /* Convert Value to a Lcid */
173 ValueString
.Length
= ValueString
.MaximumLength
= (USHORT
)dwSize
;
174 ValueString
.Buffer
= Value
;
175 Status
= RtlUnicodeStringToInteger(&ValueString
, 16, (PULONG
)&Lcid
);
176 if (!NT_SUCCESS(Status
))
178 TRACE("RtlUnicodeStringToInteger() failed with status 0x%08lx\n", Status
);
182 TRACE("%s language is 0x%08lx\n",
183 UserProfile
? "User" : "System", Lcid
);
184 Status
= NtSetDefaultLocale(UserProfile
, Lcid
);
185 if (!NT_SUCCESS(Status
))
187 TRACE("NtSetDefaultLocale() failed with status 0x%08lx\n", Status
);
197 HeapFree(GetProcessHeap(), 0, Value
);
207 typedef BOOL (WINAPI
*PLAYSOUNDW
)(LPCWSTR
,HMODULE
,DWORD
);
208 typedef UINT (WINAPI
*WAVEOUTGETNUMDEVS
)(VOID
);
210 WAVEOUTGETNUMDEVS waveOutGetNumDevs
;
215 hLibrary
= LoadLibraryW(L
"winmm.dll");
218 waveOutGetNumDevs
= (WAVEOUTGETNUMDEVS
)GetProcAddress(hLibrary
, "waveOutGetNumDevs");
219 if (waveOutGetNumDevs
)
221 NumDevs
= waveOutGetNumDevs();
228 FreeLibrary(hLibrary
);
233 Play
= (PLAYSOUNDW
)GetProcAddress(hLibrary
, "PlaySoundW");
236 Ret
= Play(FileName
, NULL
, Flags
);
238 FreeLibrary(hLibrary
);
246 PlayLogonSoundThread(
247 IN LPVOID lpParameter
)
249 BYTE TokenUserBuffer
[256];
250 PTOKEN_USER pTokenUser
= (TOKEN_USER
*)TokenUserBuffer
;
253 WCHAR wszBuffer
[MAX_PATH
] = {0};
254 WCHAR wszDest
[MAX_PATH
];
255 DWORD dwSize
= sizeof(wszBuffer
), dwType
;
256 SERVICE_STATUS_PROCESS Info
;
257 UNICODE_STRING SidString
;
260 SC_HANDLE hSCManager
, hService
;
262 /* Get SID of current user */
263 Status
= NtQueryInformationToken((HANDLE
)lpParameter
,
266 sizeof(TokenUserBuffer
),
268 if (!NT_SUCCESS(Status
))
270 ERR("NtQueryInformationToken failed: %x!\n", Status
);
274 /* Convert SID to string */
275 RtlInitEmptyUnicodeString(&SidString
, wszBuffer
, sizeof(wszBuffer
));
276 Status
= RtlConvertSidToUnicodeString(&SidString
, pTokenUser
->User
.Sid
, FALSE
);
277 if (!NT_SUCCESS(Status
))
279 ERR("RtlConvertSidToUnicodeString failed: %x!\n", Status
);
283 /* Build path to logon sound registry key.
284 Note: We can't use HKCU here, because Winlogon is owned by SYSTEM user */
285 if (FAILED(StringCbCopyW(wszBuffer
+ SidString
.Length
/sizeof(WCHAR
),
286 sizeof(wszBuffer
) - SidString
.Length
,
287 L
"\\AppEvents\\Schemes\\Apps\\.Default\\WindowsLogon\\.Current")))
289 /* SID is too long. Should not happen. */
290 ERR("StringCbCopyW failed!\n");
294 /* Open registry key and query sound path */
295 if (RegOpenKeyExW(HKEY_USERS
, wszBuffer
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
297 ERR("RegOpenKeyExW(%ls) failed!\n", wszBuffer
);
301 if (RegQueryValueExW(hKey
, NULL
, NULL
, &dwType
,
302 (LPBYTE
)wszBuffer
, &dwSize
) != ERROR_SUCCESS
||
303 (dwType
!= REG_SZ
&& dwType
!= REG_EXPAND_SZ
))
305 ERR("RegQueryValueExW failed!\n");
314 /* No sound has been set */
315 ERR("No sound has been set\n");
319 /* Expand environment variables */
320 if (!ExpandEnvironmentStringsW(wszBuffer
, wszDest
, MAX_PATH
))
322 ERR("ExpandEnvironmentStringsW failed!\n");
326 /* Open service manager */
327 hSCManager
= OpenSCManager(NULL
, NULL
, SC_MANAGER_CONNECT
);
330 ERR("OpenSCManager failed (%x)\n", GetLastError());
334 /* Open wdmaud service */
335 hService
= OpenServiceW(hSCManager
, L
"wdmaud", GENERIC_READ
);
338 /* Sound is not installed */
339 TRACE("Failed to open wdmaud service (%x)\n", GetLastError());
340 CloseServiceHandle(hSCManager
);
344 /* Wait for wdmaud start */
347 if (!QueryServiceStatusEx(hService
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&Info
, sizeof(SERVICE_STATUS_PROCESS
), &dwSize
))
349 TRACE("QueryServiceStatusEx failed (%x)\n", GetLastError());
353 if (Info
.dwCurrentState
== SERVICE_RUNNING
)
358 } while (Index
++ < 20);
360 CloseServiceHandle(hService
);
361 CloseServiceHandle(hSCManager
);
363 /* If wdmaud is not running exit */
364 if (Info
.dwCurrentState
!= SERVICE_RUNNING
)
366 WARN("wdmaud has not started!\n");
370 /* Sound subsystem is running. Play logon sound. */
371 TRACE("Playing logon sound: %ls\n", wszDest
);
372 PlaySoundRoutine(wszDest
, TRUE
, SND_FILENAME
);
379 IN OUT PWLSESSION Session
)
383 hThread
= CreateThread(NULL
, 0, PlayLogonSoundThread
, (PVOID
)Session
->UserToken
, 0, NULL
);
385 CloseHandle(hThread
);
391 IN OUT PWLSESSION Session
)
393 PROFILEINFOW ProfileInfo
;
396 /* Loading personal settings */
397 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_LOADINGYOURPERSONALSETTINGS
);
398 ProfileInfo
.hProfile
= INVALID_HANDLE_VALUE
;
399 if (0 == (Session
->Options
& WLX_LOGON_OPT_NO_PROFILE
))
401 if (Session
->Profile
== NULL
402 || (Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V1_0
403 && Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V2_0
))
405 ERR("WL: Wrong profile\n");
409 /* Load the user profile */
410 ZeroMemory(&ProfileInfo
, sizeof(PROFILEINFOW
));
411 ProfileInfo
.dwSize
= sizeof(PROFILEINFOW
);
412 ProfileInfo
.dwFlags
= 0;
413 ProfileInfo
.lpUserName
= Session
->MprNotifyInfo
.pszUserName
;
414 ProfileInfo
.lpProfilePath
= Session
->Profile
->pszProfile
;
415 if (Session
->Profile
->dwType
>= WLX_PROFILE_TYPE_V2_0
)
417 ProfileInfo
.lpDefaultPath
= Session
->Profile
->pszNetworkDefaultUserProfile
;
418 ProfileInfo
.lpServerName
= Session
->Profile
->pszServerName
;
419 ProfileInfo
.lpPolicyPath
= Session
->Profile
->pszPolicy
;
422 if (!LoadUserProfileW(Session
->UserToken
, &ProfileInfo
))
424 ERR("WL: LoadUserProfileW() failed\n");
429 /* Create environment block for the user */
430 if (!CreateUserEnvironment(Session
))
432 WARN("WL: SetUserEnvironment() failed\n");
436 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_APPLYINGYOURPERSONALSETTINGS
);
437 UpdatePerUserSystemParameters(0, TRUE
);
439 /* Set default language */
440 if (!SetDefaultLanguage(TRUE
))
442 WARN("WL: SetDefaultLanguage() failed\n");
446 if (!StartUserShell(Session
))
448 //WCHAR StatusMsg[256];
449 WARN("WL: WlxActivateUserShell() failed\n");
450 //LoadStringW(hAppInstance, IDS_FAILEDACTIVATEUSERSHELL, StatusMsg, sizeof(StatusMsg) / sizeof(StatusMsg[0]));
451 //MessageBoxW(0, StatusMsg, NULL, MB_ICONERROR);
455 if (!InitializeScreenSaver(Session
))
456 WARN("WL: Failed to initialize screen saver\n");
458 Session
->hProfileInfo
= ProfileInfo
.hProfile
;
460 /* Logon has successed. Play sound. */
461 PlayLogonSound(Session
);
466 if (Session
->Profile
)
468 HeapFree(GetProcessHeap(), 0, Session
->Profile
->pszProfile
);
469 HeapFree(GetProcessHeap(), 0, Session
->Profile
);
471 Session
->Profile
= NULL
;
473 && ProfileInfo
.hProfile
!= INVALID_HANDLE_VALUE
)
475 UnloadUserProfile(WLSession
->UserToken
, ProfileInfo
.hProfile
);
477 RemoveStatusMessage(Session
);
480 CloseHandle(Session
->UserToken
);
481 Session
->UserToken
= NULL
;
490 LogoffShutdownThread(
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
)
523 CreateLogoffSecurityAttributes(
524 OUT PSECURITY_ATTRIBUTES
* ppsa
)
526 /* The following code is not working yet and messy */
527 /* Still, it gives some ideas about data types and functions involved and */
528 /* required to set up a SECURITY_DESCRIPTOR for a SECURITY_ATTRIBUTES */
529 /* instance for a thread, to allow that thread to ImpersonateLoggedOnUser(). */
530 /* Specifically THREAD_SET_THREAD_TOKEN is required. */
531 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
532 PSECURITY_ATTRIBUTES psa
= 0;
535 EXPLICIT_ACCESS Access
;
536 PSID pEveryoneSID
= NULL
;
537 static SID_IDENTIFIER_AUTHORITY WorldAuthority
= { SECURITY_WORLD_SID_AUTHORITY
};
541 // Let's first try to enumerate what kind of data we need for this to ever work:
542 // 1. The Winlogon SID, to be able to give it THREAD_SET_THREAD_TOKEN.
543 // 2. The users SID (the user trying to logoff, or rather shut down the system).
544 // 3. At least two EXPLICIT_ACCESS instances:
545 // 3.1 One for Winlogon itself, giving it the rights
546 // required to THREAD_SET_THREAD_TOKEN (as it's needed to successfully call
547 // ImpersonateLoggedOnUser).
548 // 3.2 One for the user, to allow *that* thread to perform its work.
549 // 4. An ACL to hold the these EXPLICIT_ACCESS ACE's.
550 // 5. A SECURITY_DESCRIPTOR to hold the ACL, and finally.
551 // 6. A SECURITY_ATTRIBUTES instance to pull all of this required stuff
552 // together, to hand it to CreateThread.
554 // However, it seems struct LOGOFF_SHUTDOWN_DATA doesn't contain
555 // these required SID's, why they'd have to be added.
556 // The Winlogon's own SID should probably only be created once,
557 // while the user's SID obviously must be created for each new user.
558 // Might as well store it when the user logs on?
560 if(!AllocateAndInitializeSid(&WorldAuthority
,
566 ERR("Failed to initialize security descriptor for logoff thread!\n");
567 return STATUS_UNSUCCESSFUL
;
570 /* set up the required security attributes to be able to shut down */
571 /* To save space and time, allocate a single block of memory holding */
572 /* both SECURITY_ATTRIBUTES and SECURITY_DESCRIPTOR */
573 pMem
= HeapAlloc(GetProcessHeap(),
575 sizeof(SECURITY_ATTRIBUTES
) +
576 SECURITY_DESCRIPTOR_MIN_LENGTH
+
580 ERR("Failed to allocate memory for logoff security descriptor!\n");
581 return STATUS_NO_MEMORY
;
584 /* Note that the security descriptor needs to be in _absolute_ format, */
585 /* meaning its members must be pointers to other structures, rather */
586 /* than the relative format using offsets */
587 psa
= (PSECURITY_ATTRIBUTES
)pMem
;
588 SecurityDescriptor
= (PSECURITY_DESCRIPTOR
)(pMem
+ sizeof(SECURITY_ATTRIBUTES
));
589 pACL
= (PACL
)(((PBYTE
)SecurityDescriptor
) + SECURITY_DESCRIPTOR_MIN_LENGTH
);
591 // Initialize an EXPLICIT_ACCESS structure for an ACE.
592 // The ACE will allow this thread to log off (and shut down the system, currently).
593 ZeroMemory(&Access
, sizeof(Access
));
594 Access
.grfAccessPermissions
= THREAD_SET_THREAD_TOKEN
;
595 Access
.grfAccessMode
= SET_ACCESS
; // GRANT_ACCESS?
596 Access
.grfInheritance
= NO_INHERITANCE
;
597 Access
.Trustee
.TrusteeForm
= TRUSTEE_IS_SID
;
598 Access
.Trustee
.TrusteeType
= TRUSTEE_IS_WELL_KNOWN_GROUP
;
599 Access
.Trustee
.ptstrName
= pEveryoneSID
;
601 if (SetEntriesInAcl(1, &Access
, NULL
, &pACL
) != ERROR_SUCCESS
)
603 ERR("Failed to set Access Rights for logoff thread. Logging out will most likely fail.\n");
605 HeapFree(GetProcessHeap(), 0, pMem
);
606 return STATUS_UNSUCCESSFUL
;
609 if (!InitializeSecurityDescriptor(SecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
))
611 ERR("Failed to initialize security descriptor for logoff thread!\n");
612 HeapFree(GetProcessHeap(), 0, pMem
);
613 return STATUS_UNSUCCESSFUL
;
616 if (!SetSecurityDescriptorDacl(SecurityDescriptor
,
617 TRUE
, // bDaclPresent flag
619 FALSE
)) // not a default DACL
621 ERR("SetSecurityDescriptorDacl Error %lu\n", GetLastError());
622 HeapFree(GetProcessHeap(), 0, pMem
);
623 return STATUS_UNSUCCESSFUL
;
626 psa
->nLength
= sizeof(SECURITY_ATTRIBUTES
);
627 psa
->lpSecurityDescriptor
= SecurityDescriptor
;
628 psa
->bInheritHandle
= FALSE
;
632 return STATUS_SUCCESS
;
637 DestroyLogoffSecurityAttributes(
638 IN PSECURITY_ATTRIBUTES psa
)
642 HeapFree(GetProcessHeap(), 0, psa
);
650 IN OUT PWLSESSION Session
,
653 PLOGOFF_SHUTDOWN_DATA LSData
;
654 PSECURITY_ATTRIBUTES psa
;
659 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_SAVEYOURSETTINGS
);
661 /* Prepare data for logoff thread */
662 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
665 ERR("Failed to allocate mem for thread data\n");
666 return STATUS_NO_MEMORY
;
668 LSData
->Flags
= Flags
;
669 LSData
->Session
= Session
;
671 Status
= CreateLogoffSecurityAttributes(&psa
);
672 if (!NT_SUCCESS(Status
))
674 ERR("Failed to create a required security descriptor. Status 0x%08lx\n", Status
);
675 HeapFree(GetProcessHeap(), 0, LSData
);
679 /* Run logoff thread */
680 hThread
= CreateThread(psa
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
682 /* we're done with the SECURITY_DESCRIPTOR */
683 DestroyLogoffSecurityAttributes(psa
);
688 ERR("Unable to create logoff thread, error %lu\n", GetLastError());
689 HeapFree(GetProcessHeap(), 0, LSData
);
690 return STATUS_UNSUCCESSFUL
;
692 WaitForSingleObject(hThread
, INFINITE
);
693 HeapFree(GetProcessHeap(), 0, LSData
);
694 if (!GetExitCodeThread(hThread
, &exitCode
))
696 ERR("Unable to get exit code of logoff thread (error %lu)\n", GetLastError());
697 CloseHandle(hThread
);
698 return STATUS_UNSUCCESSFUL
;
700 CloseHandle(hThread
);
703 ERR("Logoff thread returned failure\n");
704 return STATUS_UNSUCCESSFUL
;
707 UnloadUserProfile(Session
->UserToken
, Session
->hProfileInfo
);
708 CloseHandle(Session
->UserToken
);
709 UpdatePerUserSystemParameters(0, FALSE
);
710 Session
->LogonState
= STATE_LOGGED_OFF
;
711 Session
->UserToken
= NULL
;
712 return STATUS_SUCCESS
;
718 ShutdownComputerWindowProc(
724 UNREFERENCED_PARAMETER(lParam
);
730 switch (LOWORD(wParam
))
732 case IDC_BTNSHTDOWNCOMPUTER
:
733 EndDialog(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
);
740 RemoveMenu(GetSystemMenu(hwndDlg
, FALSE
), SC_CLOSE
, MF_BYCOMMAND
);
741 SetFocus(GetDlgItem(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
));
751 IN OUT PWLSESSION Session
)
753 if (Session
->SASWindow
)
755 DestroyWindow(Session
->SASWindow
);
756 Session
->SASWindow
= NULL
;
758 if (Session
->hEndOfScreenSaverThread
)
759 SetEvent(Session
->hEndOfScreenSaverThread
);
760 UnregisterClassW(WINLOGON_SAS_CLASS
, hAppInstance
);
765 IN OUT PWLSESSION Session
,
768 PLOGOFF_SHUTDOWN_DATA LSData
;
772 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_REACTOSISSHUTTINGDOWN
);
774 /* Prepare data for shutdown thread */
775 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
778 ERR("Failed to allocate mem for thread data\n");
779 return STATUS_NO_MEMORY
;
781 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
)
782 LSData
->Flags
= EWX_POWEROFF
;
783 else if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
784 LSData
->Flags
= EWX_REBOOT
;
786 LSData
->Flags
= EWX_SHUTDOWN
;
787 LSData
->Session
= Session
;
789 /* Run shutdown thread */
790 hThread
= CreateThread(NULL
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
793 ERR("Unable to create shutdown thread, error %lu\n", GetLastError());
794 HeapFree(GetProcessHeap(), 0, LSData
);
795 return STATUS_UNSUCCESSFUL
;
797 WaitForSingleObject(hThread
, INFINITE
);
798 HeapFree(GetProcessHeap(), 0, LSData
);
799 if (!GetExitCodeThread(hThread
, &exitCode
))
801 ERR("Unable to get exit code of shutdown thread (error %lu)\n", GetLastError());
802 CloseHandle(hThread
);
803 return STATUS_UNSUCCESSFUL
;
805 CloseHandle(hThread
);
808 ERR("Shutdown thread returned failure\n");
809 return STATUS_UNSUCCESSFUL
;
812 /* Destroy SAS window */
813 UninitializeSAS(Session
);
815 FIXME("FIXME: Call SMSS API #1\n");
816 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
817 NtShutdownSystem(ShutdownReboot
);
822 /* FIXME - only show this dialog if it's a shutdown and the computer doesn't support APM */
823 DialogBox(hAppInstance
, MAKEINTRESOURCE(IDD_SHUTDOWNCOMPUTER
), GetDesktopWindow(), ShutdownComputerWindowProc
);
825 NtShutdownSystem(ShutdownNoReboot
);
827 return STATUS_SUCCESS
;
833 IN OUT PWLSESSION Session
,
838 case WLX_SAS_ACTION_LOGON
: /* 0x01 */
839 if (HandleLogon(Session
))
841 SwitchDesktop(Session
->ApplicationDesktop
);
842 Session
->LogonState
= STATE_LOGGED_ON
;
845 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
847 case WLX_SAS_ACTION_NONE
: /* 0x02 */
849 case WLX_SAS_ACTION_LOCK_WKSTA
: /* 0x03 */
850 if (Session
->Gina
.Functions
.WlxIsLockOk(Session
->Gina
.Context
))
852 SwitchDesktop(WLSession
->WinlogonDesktop
);
853 Session
->LogonState
= STATE_LOCKED
;
854 Session
->Gina
.Functions
.WlxDisplayLockedNotice(Session
->Gina
.Context
);
857 case WLX_SAS_ACTION_LOGOFF
: /* 0x04 */
858 case WLX_SAS_ACTION_SHUTDOWN
: /* 0x05 */
859 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
: /* 0x0a */
860 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
: /* 0x0b */
861 if (Session
->LogonState
!= STATE_LOGGED_OFF
)
863 if (!Session
->Gina
.Functions
.WlxIsLogoffOk(Session
->Gina
.Context
))
865 SwitchDesktop(WLSession
->WinlogonDesktop
);
866 Session
->Gina
.Functions
.WlxLogoff(Session
->Gina
.Context
);
867 if (!NT_SUCCESS(HandleLogoff(Session
, EWX_LOGOFF
)))
869 RemoveStatusMessage(Session
);
873 if (WLX_SHUTTINGDOWN(wlxAction
))
875 Session
->Gina
.Functions
.WlxShutdown(Session
->Gina
.Context
, wlxAction
);
876 if (!NT_SUCCESS(HandleShutdown(Session
, wlxAction
)))
878 RemoveStatusMessage(Session
);
879 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
884 RemoveStatusMessage(Session
);
885 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
888 case WLX_SAS_ACTION_TASKLIST
: /* 0x07 */
889 SwitchDesktop(WLSession
->ApplicationDesktop
);
890 StartTaskManager(Session
);
892 case WLX_SAS_ACTION_UNLOCK_WKSTA
: /* 0x08 */
893 SwitchDesktop(WLSession
->ApplicationDesktop
);
894 Session
->LogonState
= STATE_LOGGED_ON
;
897 WARN("Unknown SAS action 0x%lx\n", wlxAction
);
904 IN OUT PWLSESSION Session
,
907 DWORD wlxAction
= WLX_SAS_ACTION_NONE
;
909 if (Session
->LogonState
== STATE_LOGGED_ON
)
910 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOnSAS(Session
->Gina
.Context
, dwSasType
, NULL
);
911 else if (Session
->LogonState
== STATE_LOCKED
)
912 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxWkstaLockedSAS(Session
->Gina
.Context
, dwSasType
);
915 /* Display a new dialog (if necessary) */
918 case WLX_SAS_TYPE_TIMEOUT
: /* 0x00 */
920 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
925 PSID LogonSid
= NULL
; /* FIXME */
927 Session
->Options
= 0;
929 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOutSAS(
930 Session
->Gina
.Context
,
936 &Session
->MprNotifyInfo
,
937 (PVOID
*)&Session
->Profile
);
943 if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_TIMEOUT
)
946 if (!Session
->Gina
.Functions
.WlxScreenSaverNotify(Session
->Gina
.Context
, &bSecure
))
948 /* Skip start of screen saver */
949 SetEvent(Session
->hEndOfScreenSaver
);
953 StartScreenSaver(Session
);
955 DoGenericAction(Session
, WLX_SAS_ACTION_LOCK_WKSTA
);
958 else if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_ACTIVITY
)
959 SetEvent(Session
->hUserActivity
);
961 DoGenericAction(Session
, wlxAction
);
967 IN PWLSESSION Session
,
970 /* Register Ctrl+Alt+Del Hotkey */
971 if (!RegisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
, MOD_CONTROL
| MOD_ALT
, VK_DELETE
))
973 ERR("WL: Unable to register Ctrl+Alt+Del hotkey!\n");
977 /* Register Ctrl+Shift+Esc (optional) */
978 Session
->TaskManHotkey
= RegisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
, MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
);
979 if (!Session
->TaskManHotkey
)
980 WARN("WL: Warning: Unable to register Ctrl+Alt+Esc hotkey!\n");
987 IN PWLSESSION Session
,
990 /* Unregister hotkeys */
991 UnregisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
);
993 if (Session
->TaskManHotkey
)
994 UnregisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
);
1001 CheckForShutdownPrivilege(
1002 IN DWORD RequestingProcessId
)
1007 PPRIVILEGE_SET PrivSet
;
1009 TRACE("CheckForShutdownPrivilege()\n");
1011 Process
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, RequestingProcessId
);
1014 WARN("OpenProcess() failed with error %lu\n", GetLastError());
1015 return STATUS_INVALID_HANDLE
;
1017 if (!OpenProcessToken(Process
, TOKEN_QUERY
, &Token
))
1019 WARN("OpenProcessToken() failed with error %lu\n", GetLastError());
1020 CloseHandle(Process
);
1021 return STATUS_INVALID_HANDLE
;
1023 CloseHandle(Process
);
1024 PrivSet
= HeapAlloc(GetProcessHeap(), 0, sizeof(PRIVILEGE_SET
) + sizeof(LUID_AND_ATTRIBUTES
));
1027 ERR("Failed to allocate mem for privilege set\n");
1029 return STATUS_NO_MEMORY
;
1031 PrivSet
->PrivilegeCount
= 1;
1032 PrivSet
->Control
= PRIVILEGE_SET_ALL_NECESSARY
;
1033 if (!LookupPrivilegeValue(NULL
, SE_SHUTDOWN_NAME
, &PrivSet
->Privilege
[0].Luid
))
1035 WARN("LookupPrivilegeValue() failed with error %lu\n", GetLastError());
1036 HeapFree(GetProcessHeap(), 0, PrivSet
);
1038 return STATUS_UNSUCCESSFUL
;
1040 if (!PrivilegeCheck(Token
, PrivSet
, &CheckResult
))
1042 WARN("PrivilegeCheck() failed with error %lu\n", GetLastError());
1043 HeapFree(GetProcessHeap(), 0, PrivSet
);
1045 return STATUS_ACCESS_DENIED
;
1047 HeapFree(GetProcessHeap(), 0, PrivSet
);
1052 WARN("SE_SHUTDOWN privilege not enabled\n");
1053 return STATUS_ACCESS_DENIED
;
1055 return STATUS_SUCCESS
;
1060 HandleMessageBeep(UINT uType
)
1070 EventName
= L
"SystemDefault";
1072 case MB_ICONASTERISK
:
1073 EventName
= L
"SystemAsterisk";
1075 case MB_ICONEXCLAMATION
:
1076 EventName
= L
"SystemExclamation";
1079 EventName
= L
"SystemHand";
1081 case MB_ICONQUESTION
:
1082 EventName
= L
"SystemQuestion";
1085 WARN("Unhandled type %d\n", uType
);
1086 EventName
= L
"SystemDefault";
1089 return PlaySoundRoutine(EventName
, FALSE
, SND_ALIAS
| SND_NOWAIT
| SND_NOSTOP
| SND_ASYNC
);
1101 PWLSESSION Session
= (PWLSESSION
)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
1109 case MAKELONG(MOD_CONTROL
| MOD_ALT
, VK_DELETE
):
1111 TRACE("SAS: CONTROL+ALT+DELETE\n");
1112 if (!Session
->Gina
.UseCtrlAltDelete
)
1114 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_CTRL_ALT_DEL
, 0);
1117 case MAKELONG(MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
):
1119 TRACE("SAS: CONTROL+SHIFT+ESCAPE\n");
1120 DoGenericAction(Session
, WLX_SAS_ACTION_TASKLIST
);
1128 /* Get the session pointer from the create data */
1129 Session
= (PWLSESSION
)((LPCREATESTRUCT
)lParam
)->lpCreateParams
;
1131 /* Save the Session pointer */
1132 SetWindowLongPtrW(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)Session
);
1135 return RegisterHotKeys(Session
, hwndDlg
);
1139 if (!GetSetupType())
1140 UnregisterHotKeys(Session
, hwndDlg
);
1143 case WM_SETTINGCHANGE
:
1145 UINT uiAction
= (UINT
)wParam
;
1146 if (uiAction
== SPI_SETSCREENSAVETIMEOUT
1147 || uiAction
== SPI_SETSCREENSAVEACTIVE
)
1149 SetEvent(Session
->hScreenSaverParametersChanged
);
1153 case WM_LOGONNOTIFY
:
1157 case LN_MESSAGE_BEEP
:
1159 return HandleMessageBeep(lParam
);
1161 case LN_SHELL_EXITED
:
1163 /* lParam is the exit code */
1166 SetTimer(hwndDlg
, 1, 1000, NULL
);
1170 case LN_START_SCREENSAVE
:
1172 DispatchSAS(Session
, WLX_SAS_TYPE_SCRNSVR_TIMEOUT
);
1175 case LN_LOCK_WORKSTATION
:
1177 DoGenericAction(Session
, WLX_SAS_ACTION_LOCK_WKSTA
);
1182 ERR("WM_LOGONNOTIFY case %d is unimplemented\n", wParam
);
1191 KillTimer(hwndDlg
, 1);
1192 StartUserShell(Session
);
1198 DispatchSAS(Session
, (DWORD
)wParam
);
1201 case PM_WINLOGON_EXITWINDOWS
:
1203 UINT Flags
= (UINT
)lParam
;
1204 UINT Action
= Flags
& EWX_ACTION_MASK
;
1207 /* Check parameters */
1210 case EWX_LOGOFF
: wlxAction
= WLX_SAS_ACTION_LOGOFF
; break;
1211 case EWX_SHUTDOWN
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN
; break;
1212 case EWX_REBOOT
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_REBOOT
; break;
1213 case EWX_POWEROFF
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
; break;
1216 ERR("Invalid ExitWindows action 0x%x\n", Action
);
1217 return STATUS_INVALID_PARAMETER
;
1221 if (WLX_SHUTTINGDOWN(wlxAction
))
1223 NTSTATUS Status
= CheckForShutdownPrivilege((DWORD
)wParam
);
1224 if (!NT_SUCCESS(Status
))
1227 DoGenericAction(Session
, wlxAction
);
1232 return DefWindowProc(hwndDlg
, uMsg
, wParam
, lParam
);
1237 IN OUT PWLSESSION Session
)
1242 if (!SwitchDesktop(Session
->WinlogonDesktop
))
1244 ERR("WL: Failed to switch to winlogon desktop\n");
1248 /* Register SAS window class */
1249 swc
.cbSize
= sizeof(WNDCLASSEXW
);
1250 swc
.style
= CS_SAVEBITS
;
1251 swc
.lpfnWndProc
= SASWindowProc
;
1254 swc
.hInstance
= hAppInstance
;
1257 swc
.hbrBackground
= NULL
;
1258 swc
.lpszMenuName
= NULL
;
1259 swc
.lpszClassName
= WINLOGON_SAS_CLASS
;
1261 if (RegisterClassExW(&swc
) == 0)
1263 ERR("WL: Failed to register SAS window class\n");
1267 /* Create invisible SAS window */
1268 Session
->SASWindow
= CreateWindowExW(
1274 hAppInstance
, Session
);
1275 if (!Session
->SASWindow
)
1277 ERR("WL: Failed to create SAS window\n");
1281 /* Register SAS window to receive SAS notifications */
1282 if (!SetLogonNotifyWindow(Session
->SASWindow
, Session
->InteractiveWindowStation
))
1284 ERR("WL: Failed to register SAS window\n");
1288 if (!SetDefaultLanguage(FALSE
))
1295 UninitializeSAS(Session
);