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 */
848 if (Session
->LogonState
== STATE_LOGGED_OFF
)
850 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
853 case WLX_SAS_ACTION_LOCK_WKSTA
: /* 0x03 */
854 if (Session
->Gina
.Functions
.WlxIsLockOk(Session
->Gina
.Context
))
856 SwitchDesktop(WLSession
->WinlogonDesktop
);
857 Session
->LogonState
= STATE_LOCKED
;
858 Session
->Gina
.Functions
.WlxDisplayLockedNotice(Session
->Gina
.Context
);
861 case WLX_SAS_ACTION_LOGOFF
: /* 0x04 */
862 case WLX_SAS_ACTION_SHUTDOWN
: /* 0x05 */
863 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
: /* 0x0a */
864 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
: /* 0x0b */
865 if (Session
->LogonState
!= STATE_LOGGED_OFF
)
867 if (!Session
->Gina
.Functions
.WlxIsLogoffOk(Session
->Gina
.Context
))
869 SwitchDesktop(WLSession
->WinlogonDesktop
);
870 Session
->Gina
.Functions
.WlxLogoff(Session
->Gina
.Context
);
871 if (!NT_SUCCESS(HandleLogoff(Session
, EWX_LOGOFF
)))
873 RemoveStatusMessage(Session
);
877 if (WLX_SHUTTINGDOWN(wlxAction
))
879 Session
->Gina
.Functions
.WlxShutdown(Session
->Gina
.Context
, wlxAction
);
880 if (!NT_SUCCESS(HandleShutdown(Session
, wlxAction
)))
882 RemoveStatusMessage(Session
);
883 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
888 RemoveStatusMessage(Session
);
889 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
892 case WLX_SAS_ACTION_TASKLIST
: /* 0x07 */
893 SwitchDesktop(WLSession
->ApplicationDesktop
);
894 StartTaskManager(Session
);
896 case WLX_SAS_ACTION_UNLOCK_WKSTA
: /* 0x08 */
897 SwitchDesktop(WLSession
->ApplicationDesktop
);
898 Session
->LogonState
= STATE_LOGGED_ON
;
901 WARN("Unknown SAS action 0x%lx\n", wlxAction
);
908 IN OUT PWLSESSION Session
,
911 DWORD wlxAction
= WLX_SAS_ACTION_NONE
;
913 if (Session
->LogonState
== STATE_LOGGED_ON
)
914 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOnSAS(Session
->Gina
.Context
, dwSasType
, NULL
);
915 else if (Session
->LogonState
== STATE_LOCKED
)
916 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxWkstaLockedSAS(Session
->Gina
.Context
, dwSasType
);
919 /* Display a new dialog (if necessary) */
922 case WLX_SAS_TYPE_TIMEOUT
: /* 0x00 */
924 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
929 PSID LogonSid
= NULL
; /* FIXME */
932 hwnd
= GetTopDialogWindow();
935 SendMessage(hwnd
, WM_USER
, 0, 0);
938 Session
->Options
= 0;
940 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOutSAS(
941 Session
->Gina
.Context
,
947 &Session
->MprNotifyInfo
,
948 (PVOID
*)&Session
->Profile
);
954 if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_TIMEOUT
)
957 if (!Session
->Gina
.Functions
.WlxScreenSaverNotify(Session
->Gina
.Context
, &bSecure
))
959 /* Skip start of screen saver */
960 SetEvent(Session
->hEndOfScreenSaver
);
964 StartScreenSaver(Session
);
966 DoGenericAction(Session
, WLX_SAS_ACTION_LOCK_WKSTA
);
969 else if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_ACTIVITY
)
970 SetEvent(Session
->hUserActivity
);
972 DoGenericAction(Session
, wlxAction
);
978 IN PWLSESSION Session
,
981 /* Register Ctrl+Alt+Del Hotkey */
982 if (!RegisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
, MOD_CONTROL
| MOD_ALT
, VK_DELETE
))
984 ERR("WL: Unable to register Ctrl+Alt+Del hotkey!\n");
988 /* Register Ctrl+Shift+Esc (optional) */
989 Session
->TaskManHotkey
= RegisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
, MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
);
990 if (!Session
->TaskManHotkey
)
991 WARN("WL: Warning: Unable to register Ctrl+Alt+Esc hotkey!\n");
998 IN PWLSESSION Session
,
1001 /* Unregister hotkeys */
1002 UnregisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
);
1004 if (Session
->TaskManHotkey
)
1005 UnregisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
);
1012 CheckForShutdownPrivilege(
1013 IN DWORD RequestingProcessId
)
1018 PPRIVILEGE_SET PrivSet
;
1020 TRACE("CheckForShutdownPrivilege()\n");
1022 Process
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, RequestingProcessId
);
1025 WARN("OpenProcess() failed with error %lu\n", GetLastError());
1026 return STATUS_INVALID_HANDLE
;
1028 if (!OpenProcessToken(Process
, TOKEN_QUERY
, &Token
))
1030 WARN("OpenProcessToken() failed with error %lu\n", GetLastError());
1031 CloseHandle(Process
);
1032 return STATUS_INVALID_HANDLE
;
1034 CloseHandle(Process
);
1035 PrivSet
= HeapAlloc(GetProcessHeap(), 0, sizeof(PRIVILEGE_SET
) + sizeof(LUID_AND_ATTRIBUTES
));
1038 ERR("Failed to allocate mem for privilege set\n");
1040 return STATUS_NO_MEMORY
;
1042 PrivSet
->PrivilegeCount
= 1;
1043 PrivSet
->Control
= PRIVILEGE_SET_ALL_NECESSARY
;
1044 if (!LookupPrivilegeValue(NULL
, SE_SHUTDOWN_NAME
, &PrivSet
->Privilege
[0].Luid
))
1046 WARN("LookupPrivilegeValue() failed with error %lu\n", GetLastError());
1047 HeapFree(GetProcessHeap(), 0, PrivSet
);
1049 return STATUS_UNSUCCESSFUL
;
1051 if (!PrivilegeCheck(Token
, PrivSet
, &CheckResult
))
1053 WARN("PrivilegeCheck() failed with error %lu\n", GetLastError());
1054 HeapFree(GetProcessHeap(), 0, PrivSet
);
1056 return STATUS_ACCESS_DENIED
;
1058 HeapFree(GetProcessHeap(), 0, PrivSet
);
1063 WARN("SE_SHUTDOWN privilege not enabled\n");
1064 return STATUS_ACCESS_DENIED
;
1066 return STATUS_SUCCESS
;
1071 HandleMessageBeep(UINT uType
)
1081 EventName
= L
"SystemDefault";
1083 case MB_ICONASTERISK
:
1084 EventName
= L
"SystemAsterisk";
1086 case MB_ICONEXCLAMATION
:
1087 EventName
= L
"SystemExclamation";
1090 EventName
= L
"SystemHand";
1092 case MB_ICONQUESTION
:
1093 EventName
= L
"SystemQuestion";
1096 WARN("Unhandled type %d\n", uType
);
1097 EventName
= L
"SystemDefault";
1100 return PlaySoundRoutine(EventName
, FALSE
, SND_ALIAS
| SND_NOWAIT
| SND_NOSTOP
| SND_ASYNC
);
1112 PWLSESSION Session
= (PWLSESSION
)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
1120 case MAKELONG(MOD_CONTROL
| MOD_ALT
, VK_DELETE
):
1122 TRACE("SAS: CONTROL+ALT+DELETE\n");
1123 if (!Session
->Gina
.UseCtrlAltDelete
)
1125 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_CTRL_ALT_DEL
, 0);
1128 case MAKELONG(MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
):
1130 TRACE("SAS: CONTROL+SHIFT+ESCAPE\n");
1131 DoGenericAction(Session
, WLX_SAS_ACTION_TASKLIST
);
1139 /* Get the session pointer from the create data */
1140 Session
= (PWLSESSION
)((LPCREATESTRUCT
)lParam
)->lpCreateParams
;
1142 /* Save the Session pointer */
1143 SetWindowLongPtrW(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)Session
);
1146 return RegisterHotKeys(Session
, hwndDlg
);
1150 if (!GetSetupType())
1151 UnregisterHotKeys(Session
, hwndDlg
);
1154 case WM_SETTINGCHANGE
:
1156 UINT uiAction
= (UINT
)wParam
;
1157 if (uiAction
== SPI_SETSCREENSAVETIMEOUT
1158 || uiAction
== SPI_SETSCREENSAVEACTIVE
)
1160 SetEvent(Session
->hScreenSaverParametersChanged
);
1164 case WM_LOGONNOTIFY
:
1168 case LN_MESSAGE_BEEP
:
1170 return HandleMessageBeep(lParam
);
1172 case LN_SHELL_EXITED
:
1174 /* lParam is the exit code */
1177 SetTimer(hwndDlg
, 1, 1000, NULL
);
1181 case LN_START_SCREENSAVE
:
1183 DispatchSAS(Session
, WLX_SAS_TYPE_SCRNSVR_TIMEOUT
);
1186 case LN_LOCK_WORKSTATION
:
1188 DoGenericAction(Session
, WLX_SAS_ACTION_LOCK_WKSTA
);
1193 ERR("WM_LOGONNOTIFY case %d is unimplemented\n", wParam
);
1202 KillTimer(hwndDlg
, 1);
1203 StartUserShell(Session
);
1209 DispatchSAS(Session
, (DWORD
)wParam
);
1212 case PM_WINLOGON_EXITWINDOWS
:
1214 UINT Flags
= (UINT
)lParam
;
1215 UINT Action
= Flags
& EWX_ACTION_MASK
;
1218 /* Check parameters */
1221 case EWX_LOGOFF
: wlxAction
= WLX_SAS_ACTION_LOGOFF
; break;
1222 case EWX_SHUTDOWN
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN
; break;
1223 case EWX_REBOOT
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_REBOOT
; break;
1224 case EWX_POWEROFF
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
; break;
1227 ERR("Invalid ExitWindows action 0x%x\n", Action
);
1228 return STATUS_INVALID_PARAMETER
;
1232 if (WLX_SHUTTINGDOWN(wlxAction
))
1234 NTSTATUS Status
= CheckForShutdownPrivilege((DWORD
)wParam
);
1235 if (!NT_SUCCESS(Status
))
1238 DoGenericAction(Session
, wlxAction
);
1243 return DefWindowProc(hwndDlg
, uMsg
, wParam
, lParam
);
1248 IN OUT PWLSESSION Session
)
1253 if (!SwitchDesktop(Session
->WinlogonDesktop
))
1255 ERR("WL: Failed to switch to winlogon desktop\n");
1259 /* Register SAS window class */
1260 swc
.cbSize
= sizeof(WNDCLASSEXW
);
1261 swc
.style
= CS_SAVEBITS
;
1262 swc
.lpfnWndProc
= SASWindowProc
;
1265 swc
.hInstance
= hAppInstance
;
1268 swc
.hbrBackground
= NULL
;
1269 swc
.lpszMenuName
= NULL
;
1270 swc
.lpszClassName
= WINLOGON_SAS_CLASS
;
1272 if (RegisterClassExW(&swc
) == 0)
1274 ERR("WL: Failed to register SAS window class\n");
1278 /* Create invisible SAS window */
1279 Session
->SASWindow
= CreateWindowExW(
1285 hAppInstance
, Session
);
1286 if (!Session
->SASWindow
)
1288 ERR("WL: Failed to create SAS window\n");
1292 /* Register SAS window to receive SAS notifications */
1293 if (!SetLogonNotifyWindow(Session
->SASWindow
, Session
->InteractiveWindowStation
))
1295 ERR("WL: Failed to register SAS window\n");
1299 if (!SetDefaultLanguage(FALSE
))
1306 UninitializeSAS(Session
);