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 static BOOL inScrn
= FALSE
;
28 /* FUNCTIONS ****************************************************************/
32 IN OUT PWLSESSION Session
)
37 if (!Session
->Gina
.Functions
.WlxStartApplication
)
40 if (!CreateEnvironmentBlock(
48 ret
= Session
->Gina
.Functions
.WlxStartApplication(
49 Session
->Gina
.Context
,
54 DestroyEnvironmentBlock(lpEnvironment
);
60 IN OUT PWLSESSION Session
)
62 LPVOID lpEnvironment
= NULL
;
66 /* Create environment block for the user */
67 if (!CreateEnvironmentBlock(&lpEnvironment
, Session
->UserToken
, TRUE
))
69 WARN("WL: CreateEnvironmentBlock() failed\n");
74 /* FIXME: who should do it? winlogon or gina? */
75 /* FIXME: reverting to lower privileges after creating user shell? */
76 RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
, TRUE
, FALSE
, &Old
);
78 ret
= Session
->Gina
.Functions
.WlxActivateUserShell(
79 Session
->Gina
.Context
,
84 DestroyEnvironmentBlock(lpEnvironment
);
100 UNICODE_STRING ValueString
;
107 BaseKey
= HKEY_CURRENT_USER
;
108 SubKey
= L
"Control Panel\\International";
109 ValueName
= L
"Locale";
113 BaseKey
= HKEY_LOCAL_MACHINE
;
114 SubKey
= L
"System\\CurrentControlSet\\Control\\Nls\\Language";
115 ValueName
= L
"Default";
124 if (rc
!= ERROR_SUCCESS
)
126 TRACE("RegOpenKeyEx() failed with error %lu\n", rc
);
129 rc
= RegQueryValueExW(
136 if (rc
!= ERROR_SUCCESS
)
138 TRACE("RegQueryValueEx() failed with error %lu\n", rc
);
141 else if (dwType
!= REG_SZ
)
143 TRACE("Wrong type for %S\\%S registry entry (got 0x%lx, expected 0x%x)\n",
144 SubKey
, ValueName
, dwType
, REG_SZ
);
148 Value
= HeapAlloc(GetProcessHeap(), 0, dwSize
);
151 TRACE("HeapAlloc() failed\n");
154 rc
= RegQueryValueExW(
161 if (rc
!= ERROR_SUCCESS
)
163 TRACE("RegQueryValueEx() failed with error %lu\n", rc
);
167 /* Convert Value to a Lcid */
168 ValueString
.Length
= ValueString
.MaximumLength
= (USHORT
)dwSize
;
169 ValueString
.Buffer
= Value
;
170 Status
= RtlUnicodeStringToInteger(&ValueString
, 16, (PULONG
)&Lcid
);
171 if (!NT_SUCCESS(Status
))
173 TRACE("RtlUnicodeStringToInteger() failed with status 0x%08lx\n", Status
);
177 TRACE("%s language is 0x%08lx\n",
178 UserProfile
? "User" : "System", Lcid
);
179 Status
= NtSetDefaultLocale(UserProfile
, Lcid
);
180 if (!NT_SUCCESS(Status
))
182 TRACE("NtSetDefaultLocale() failed with status 0x%08lx\n", Status
);
192 HeapFree(GetProcessHeap(), 0, Value
);
202 typedef BOOL (WINAPI
*PLAYSOUNDW
)(LPCWSTR
,HMODULE
,DWORD
);
203 typedef UINT (WINAPI
*WAVEOUTGETNUMDEVS
)(VOID
);
205 WAVEOUTGETNUMDEVS waveOutGetNumDevs
;
210 hLibrary
= LoadLibraryW(L
"winmm.dll");
213 waveOutGetNumDevs
= (WAVEOUTGETNUMDEVS
)GetProcAddress(hLibrary
, "waveOutGetNumDevs");
214 if (waveOutGetNumDevs
)
216 NumDevs
= waveOutGetNumDevs();
223 FreeLibrary(hLibrary
);
228 Play
= (PLAYSOUNDW
)GetProcAddress(hLibrary
, "PlaySoundW");
231 Ret
= Play(FileName
, NULL
, Flags
);
233 FreeLibrary(hLibrary
);
241 PlayLogonSoundThread(
242 IN LPVOID lpParameter
)
244 BYTE TokenUserBuffer
[256];
245 PTOKEN_USER pTokenUser
= (TOKEN_USER
*)TokenUserBuffer
;
248 WCHAR wszBuffer
[MAX_PATH
] = {0};
249 WCHAR wszDest
[MAX_PATH
];
250 DWORD dwSize
= sizeof(wszBuffer
), dwType
;
251 SERVICE_STATUS_PROCESS Info
;
252 UNICODE_STRING SidString
;
255 SC_HANDLE hSCManager
, hService
;
257 /* Get SID of current user */
258 Status
= NtQueryInformationToken((HANDLE
)lpParameter
,
261 sizeof(TokenUserBuffer
),
263 if (!NT_SUCCESS(Status
))
265 ERR("NtQueryInformationToken failed: %x!\n", Status
);
269 /* Convert SID to string */
270 RtlInitEmptyUnicodeString(&SidString
, wszBuffer
, sizeof(wszBuffer
));
271 Status
= RtlConvertSidToUnicodeString(&SidString
, pTokenUser
->User
.Sid
, FALSE
);
272 if (!NT_SUCCESS(Status
))
274 ERR("RtlConvertSidToUnicodeString failed: %x!\n", Status
);
278 /* Build path to logon sound registry key.
279 Note: We can't use HKCU here, because Winlogon is owned by SYSTEM user */
280 if (FAILED(StringCbCopyW(wszBuffer
+ SidString
.Length
/sizeof(WCHAR
),
281 sizeof(wszBuffer
) - SidString
.Length
,
282 L
"\\AppEvents\\Schemes\\Apps\\.Default\\WindowsLogon\\.Current")))
284 /* SID is too long. Should not happen. */
285 ERR("StringCbCopyW failed!\n");
289 /* Open registry key and query sound path */
290 if (RegOpenKeyExW(HKEY_USERS
, wszBuffer
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
292 ERR("RegOpenKeyExW(%ls) failed!\n", wszBuffer
);
296 if (RegQueryValueExW(hKey
, NULL
, NULL
, &dwType
,
297 (LPBYTE
)wszBuffer
, &dwSize
) != ERROR_SUCCESS
||
298 (dwType
!= REG_SZ
&& dwType
!= REG_EXPAND_SZ
))
300 ERR("RegQueryValueExW failed!\n");
309 /* No sound has been set */
310 ERR("No sound has been set\n");
314 /* Expand environment variables */
315 if (!ExpandEnvironmentStringsW(wszBuffer
, wszDest
, MAX_PATH
))
317 ERR("ExpandEnvironmentStringsW failed!\n");
321 /* Open service manager */
322 hSCManager
= OpenSCManager(NULL
, NULL
, SC_MANAGER_CONNECT
);
325 ERR("OpenSCManager failed (%x)\n", GetLastError());
329 /* Open wdmaud service */
330 hService
= OpenServiceW(hSCManager
, L
"wdmaud", GENERIC_READ
);
333 /* Sound is not installed */
334 TRACE("Failed to open wdmaud service (%x)\n", GetLastError());
335 CloseServiceHandle(hSCManager
);
339 /* Wait for wdmaud start */
342 if (!QueryServiceStatusEx(hService
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&Info
, sizeof(SERVICE_STATUS_PROCESS
), &dwSize
))
344 TRACE("QueryServiceStatusEx failed (%x)\n", GetLastError());
348 if (Info
.dwCurrentState
== SERVICE_RUNNING
)
353 } while (Index
++ < 20);
355 CloseServiceHandle(hService
);
356 CloseServiceHandle(hSCManager
);
358 /* If wdmaud is not running exit */
359 if (Info
.dwCurrentState
!= SERVICE_RUNNING
)
361 WARN("wdmaud has not started!\n");
365 /* Sound subsystem is running. Play logon sound. */
366 TRACE("Playing logon sound: %ls\n", wszDest
);
367 PlaySoundRoutine(wszDest
, TRUE
, SND_FILENAME
);
373 IN OUT PWLSESSION Session
)
377 hThread
= CreateThread(NULL
, 0, PlayLogonSoundThread
, (PVOID
)Session
->UserToken
, 0, NULL
);
379 CloseHandle(hThread
);
384 IN OUT PWLSESSION Session
)
386 PROFILEINFOW ProfileInfo
;
389 /* Loading personal settings */
390 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_LOADINGYOURPERSONALSETTINGS
);
391 ProfileInfo
.hProfile
= INVALID_HANDLE_VALUE
;
392 if (0 == (Session
->Options
& WLX_LOGON_OPT_NO_PROFILE
))
394 if (Session
->Profile
== NULL
395 || (Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V1_0
396 && Session
->Profile
->dwType
!= WLX_PROFILE_TYPE_V2_0
))
398 ERR("WL: Wrong profile\n");
402 /* Load the user profile */
403 ZeroMemory(&ProfileInfo
, sizeof(PROFILEINFOW
));
404 ProfileInfo
.dwSize
= sizeof(PROFILEINFOW
);
405 ProfileInfo
.dwFlags
= 0;
406 ProfileInfo
.lpUserName
= Session
->MprNotifyInfo
.pszUserName
;
407 ProfileInfo
.lpProfilePath
= Session
->Profile
->pszProfile
;
408 if (Session
->Profile
->dwType
>= WLX_PROFILE_TYPE_V2_0
)
410 ProfileInfo
.lpDefaultPath
= Session
->Profile
->pszNetworkDefaultUserProfile
;
411 ProfileInfo
.lpServerName
= Session
->Profile
->pszServerName
;
412 ProfileInfo
.lpPolicyPath
= Session
->Profile
->pszPolicy
;
415 if (!LoadUserProfileW(Session
->UserToken
, &ProfileInfo
))
417 ERR("WL: LoadUserProfileW() failed\n");
422 /* Create environment block for the user */
423 if (!CreateUserEnvironment(Session
))
425 WARN("WL: SetUserEnvironment() failed\n");
429 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_APPLYINGYOURPERSONALSETTINGS
);
430 UpdatePerUserSystemParameters(0, TRUE
);
432 /* Set default language */
433 if (!SetDefaultLanguage(TRUE
))
435 WARN("WL: SetDefaultLanguage() failed\n");
439 if (!StartUserShell(Session
))
441 //WCHAR StatusMsg[256];
442 WARN("WL: WlxActivateUserShell() failed\n");
443 //LoadStringW(hAppInstance, IDS_FAILEDACTIVATEUSERSHELL, StatusMsg, sizeof(StatusMsg));
444 //MessageBoxW(0, StatusMsg, NULL, MB_ICONERROR);
448 if (!InitializeScreenSaver(Session
))
449 WARN("WL: Failed to initialize screen saver\n");
451 Session
->hProfileInfo
= ProfileInfo
.hProfile
;
453 /* Logon has successed. Play sound. */
454 PlayLogonSound(Session
);
459 if (Session
->Profile
)
461 HeapFree(GetProcessHeap(), 0, Session
->Profile
->pszProfile
);
462 HeapFree(GetProcessHeap(), 0, Session
->Profile
);
464 Session
->Profile
= NULL
;
466 && ProfileInfo
.hProfile
!= INVALID_HANDLE_VALUE
)
468 UnloadUserProfile(WLSession
->UserToken
, ProfileInfo
.hProfile
);
470 RemoveStatusMessage(Session
);
473 CloseHandle(Session
->UserToken
);
474 Session
->UserToken
= NULL
;
479 #define EWX_ACTION_MASK 0xffffffeb
480 #define EWX_FLAGS_MASK 0x00000014
482 typedef struct tagLOGOFF_SHUTDOWN_DATA
486 } LOGOFF_SHUTDOWN_DATA
, *PLOGOFF_SHUTDOWN_DATA
;
489 LogoffShutdownThread(LPVOID Parameter
)
491 PLOGOFF_SHUTDOWN_DATA LSData
= (PLOGOFF_SHUTDOWN_DATA
)Parameter
;
493 if (LSData
->Session
->UserToken
!= NULL
&& !ImpersonateLoggedOnUser(LSData
->Session
->UserToken
))
495 ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
499 /* Close processes of the interactive user */
501 EWX_INTERNAL_KILL_USER_APPS
| (LSData
->Flags
& EWX_FLAGS_MASK
) |
502 (EWX_LOGOFF
== (LSData
->Flags
& EWX_ACTION_MASK
) ? EWX_INTERNAL_FLAG_LOGOFF
: 0),
505 ERR("Unable to kill user apps, error %lu\n", GetLastError());
510 /* FIXME: Call ExitWindowsEx() to terminate COM processes */
512 if (LSData
->Session
->UserToken
)
520 CreateLogoffSecurityAttributes(
521 OUT PSECURITY_ATTRIBUTES
* ppsa
)
523 /* The following code is not working yet and messy */
524 /* Still, it gives some ideas about data types and functions involved and */
525 /* required to set up a SECURITY_DESCRIPTOR for a SECURITY_ATTRIBUTES */
526 /* instance for a thread, to allow that thread to ImpersonateLoggedOnUser(). */
527 /* Specifically THREAD_SET_THREAD_TOKEN is required. */
528 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
529 PSECURITY_ATTRIBUTES psa
= 0;
532 EXPLICIT_ACCESS Access
;
533 PSID pEveryoneSID
= NULL
;
534 static SID_IDENTIFIER_AUTHORITY WorldAuthority
= { SECURITY_WORLD_SID_AUTHORITY
};
538 // Let's first try to enumerate what kind of data we need for this to ever work:
539 // 1. The Winlogon SID, to be able to give it THREAD_SET_THREAD_TOKEN.
540 // 2. The users SID (the user trying to logoff, or rather shut down the system).
541 // 3. At least two EXPLICIT_ACCESS instances:
542 // 3.1 One for Winlogon itself, giving it the rights
543 // required to THREAD_SET_THREAD_TOKEN (as it's needed to successfully call
544 // ImpersonateLoggedOnUser).
545 // 3.2 One for the user, to allow *that* thread to perform its work.
546 // 4. An ACL to hold the these EXPLICIT_ACCESS ACE's.
547 // 5. A SECURITY_DESCRIPTOR to hold the ACL, and finally.
548 // 6. A SECURITY_ATTRIBUTES instance to pull all of this required stuff
549 // together, to hand it to CreateThread.
551 // However, it seems struct LOGOFF_SHUTDOWN_DATA doesn't contain
552 // these required SID's, why they'd have to be added.
553 // The Winlogon's own SID should probably only be created once,
554 // while the user's SID obviously must be created for each new user.
555 // Might as well store it when the user logs on?
557 if(!AllocateAndInitializeSid(&WorldAuthority
,
563 ERR("Failed to initialize security descriptor for logoff thread!\n");
564 return STATUS_UNSUCCESSFUL
;
567 /* set up the required security attributes to be able to shut down */
568 /* To save space and time, allocate a single block of memory holding */
569 /* both SECURITY_ATTRIBUTES and SECURITY_DESCRIPTOR */
570 pMem
= HeapAlloc(GetProcessHeap(),
572 sizeof(SECURITY_ATTRIBUTES
) +
573 SECURITY_DESCRIPTOR_MIN_LENGTH
+
577 ERR("Failed to allocate memory for logoff security descriptor!\n");
578 return STATUS_NO_MEMORY
;
581 /* Note that the security descriptor needs to be in _absolute_ format, */
582 /* meaning its members must be pointers to other structures, rather */
583 /* than the relative format using offsets */
584 psa
= (PSECURITY_ATTRIBUTES
)pMem
;
585 SecurityDescriptor
= (PSECURITY_DESCRIPTOR
)(pMem
+ sizeof(SECURITY_ATTRIBUTES
));
586 pACL
= (PACL
)(((PBYTE
)SecurityDescriptor
) + SECURITY_DESCRIPTOR_MIN_LENGTH
);
588 // Initialize an EXPLICIT_ACCESS structure for an ACE.
589 // The ACE will allow this thread to log off (and shut down the system, currently).
590 ZeroMemory(&Access
, sizeof(Access
));
591 Access
.grfAccessPermissions
= THREAD_SET_THREAD_TOKEN
;
592 Access
.grfAccessMode
= SET_ACCESS
; // GRANT_ACCESS?
593 Access
.grfInheritance
= NO_INHERITANCE
;
594 Access
.Trustee
.TrusteeForm
= TRUSTEE_IS_SID
;
595 Access
.Trustee
.TrusteeType
= TRUSTEE_IS_WELL_KNOWN_GROUP
;
596 Access
.Trustee
.ptstrName
= pEveryoneSID
;
598 if (SetEntriesInAcl(1, &Access
, NULL
, &pACL
) != ERROR_SUCCESS
)
600 ERR("Failed to set Access Rights for logoff thread. Logging out will most likely fail.\n");
602 HeapFree(GetProcessHeap(), 0, pMem
);
603 return STATUS_UNSUCCESSFUL
;
606 if (!InitializeSecurityDescriptor(SecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
))
608 ERR("Failed to initialize security descriptor for logoff thread!\n");
609 HeapFree(GetProcessHeap(), 0, pMem
);
610 return STATUS_UNSUCCESSFUL
;
613 if (!SetSecurityDescriptorDacl(SecurityDescriptor
,
614 TRUE
, // bDaclPresent flag
616 FALSE
)) // not a default DACL
618 ERR("SetSecurityDescriptorDacl Error %lu\n", GetLastError());
619 HeapFree(GetProcessHeap(), 0, pMem
);
620 return STATUS_UNSUCCESSFUL
;
623 psa
->nLength
= sizeof(SECURITY_ATTRIBUTES
);
624 psa
->lpSecurityDescriptor
= SecurityDescriptor
;
625 psa
->bInheritHandle
= FALSE
;
629 return STATUS_SUCCESS
;
633 DestroyLogoffSecurityAttributes(
634 IN PSECURITY_ATTRIBUTES psa
)
638 HeapFree(GetProcessHeap(), 0, psa
);
645 IN OUT PWLSESSION Session
,
648 PLOGOFF_SHUTDOWN_DATA LSData
;
649 PSECURITY_ATTRIBUTES psa
;
654 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_SAVEYOURSETTINGS
);
656 /* Prepare data for logoff thread */
657 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
660 ERR("Failed to allocate mem for thread data\n");
661 return STATUS_NO_MEMORY
;
663 LSData
->Flags
= Flags
;
664 LSData
->Session
= Session
;
666 Status
= CreateLogoffSecurityAttributes(&psa
);
667 if (!NT_SUCCESS(Status
))
669 ERR("Failed to create a required security descriptor. Status 0x%08lx\n", Status
);
670 HeapFree(GetProcessHeap(), 0, LSData
);
674 /* Run logoff thread */
675 hThread
= CreateThread(psa
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
677 /* we're done with the SECURITY_DESCRIPTOR */
678 DestroyLogoffSecurityAttributes(psa
);
683 ERR("Unable to create logoff thread, error %lu\n", GetLastError());
684 HeapFree(GetProcessHeap(), 0, LSData
);
685 return STATUS_UNSUCCESSFUL
;
687 WaitForSingleObject(hThread
, INFINITE
);
688 HeapFree(GetProcessHeap(), 0, LSData
);
689 if (!GetExitCodeThread(hThread
, &exitCode
))
691 ERR("Unable to get exit code of logoff thread (error %lu)\n", GetLastError());
692 CloseHandle(hThread
);
693 return STATUS_UNSUCCESSFUL
;
695 CloseHandle(hThread
);
698 ERR("Logoff thread returned failure\n");
699 return STATUS_UNSUCCESSFUL
;
702 UnloadUserProfile(Session
->UserToken
, Session
->hProfileInfo
);
703 CloseHandle(Session
->UserToken
);
704 UpdatePerUserSystemParameters(0, FALSE
);
705 Session
->LogonStatus
= WKSTA_IS_LOGGED_OFF
;
706 Session
->UserToken
= NULL
;
707 return STATUS_SUCCESS
;
710 static INT_PTR CALLBACK
711 ShutdownComputerWindowProc(
717 UNREFERENCED_PARAMETER(lParam
);
723 switch (LOWORD(wParam
))
725 case IDC_BTNSHTDOWNCOMPUTER
:
726 EndDialog(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
);
733 RemoveMenu(GetSystemMenu(hwndDlg
, FALSE
), SC_CLOSE
, MF_BYCOMMAND
);
734 SetFocus(GetDlgItem(hwndDlg
, IDC_BTNSHTDOWNCOMPUTER
));
743 IN OUT PWLSESSION Session
)
745 if (Session
->SASWindow
)
747 DestroyWindow(Session
->SASWindow
);
748 Session
->SASWindow
= NULL
;
750 if (Session
->hEndOfScreenSaverThread
)
751 SetEvent(Session
->hEndOfScreenSaverThread
);
752 UnregisterClassW(WINLOGON_SAS_CLASS
, hAppInstance
);
757 IN OUT PWLSESSION Session
,
760 PLOGOFF_SHUTDOWN_DATA LSData
;
764 DisplayStatusMessage(Session
, Session
->WinlogonDesktop
, IDS_REACTOSISSHUTTINGDOWN
);
766 /* Prepare data for shutdown thread */
767 LSData
= HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA
));
770 ERR("Failed to allocate mem for thread data\n");
771 return STATUS_NO_MEMORY
;
773 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
)
774 LSData
->Flags
= EWX_POWEROFF
;
775 else if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
776 LSData
->Flags
= EWX_REBOOT
;
778 LSData
->Flags
= EWX_SHUTDOWN
;
779 LSData
->Session
= Session
;
781 /* Run shutdown thread */
782 hThread
= CreateThread(NULL
, 0, LogoffShutdownThread
, (LPVOID
)LSData
, 0, NULL
);
785 ERR("Unable to create shutdown thread, error %lu\n", GetLastError());
786 HeapFree(GetProcessHeap(), 0, LSData
);
787 return STATUS_UNSUCCESSFUL
;
789 WaitForSingleObject(hThread
, INFINITE
);
790 HeapFree(GetProcessHeap(), 0, LSData
);
791 if (!GetExitCodeThread(hThread
, &exitCode
))
793 ERR("Unable to get exit code of shutdown thread (error %lu)\n", GetLastError());
794 CloseHandle(hThread
);
795 return STATUS_UNSUCCESSFUL
;
797 CloseHandle(hThread
);
800 ERR("Shutdown thread returned failure\n");
801 return STATUS_UNSUCCESSFUL
;
804 /* Destroy SAS window */
805 UninitializeSAS(Session
);
807 FIXME("FIXME: Call SMSS API #1\n");
808 if (wlxAction
== WLX_SAS_ACTION_SHUTDOWN_REBOOT
)
809 NtShutdownSystem(ShutdownReboot
);
814 /* FIXME - only show this dialog if it's a shutdown and the computer doesn't support APM */
815 DialogBox(hAppInstance
, MAKEINTRESOURCE(IDD_SHUTDOWNCOMPUTER
), GetDesktopWindow(), ShutdownComputerWindowProc
);
817 NtShutdownSystem(ShutdownNoReboot
);
819 return STATUS_SUCCESS
;
824 IN OUT PWLSESSION Session
,
829 case WLX_SAS_ACTION_LOGON
: /* 0x01 */
830 if (HandleLogon(Session
))
832 SwitchDesktop(Session
->ApplicationDesktop
);
833 Session
->LogonStatus
= WKSTA_IS_LOGGED_ON
;
836 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
838 case WLX_SAS_ACTION_NONE
: /* 0x02 */
840 case WLX_SAS_ACTION_LOCK_WKSTA
: /* 0x03 */
841 if (Session
->Gina
.Functions
.WlxIsLockOk(Session
->Gina
.Context
))
843 SwitchDesktop(WLSession
->WinlogonDesktop
);
844 Session
->LogonStatus
= WKSTA_IS_LOCKED
;
845 Session
->Gina
.Functions
.WlxDisplayLockedNotice(Session
->Gina
.Context
);
848 case WLX_SAS_ACTION_LOGOFF
: /* 0x04 */
849 case WLX_SAS_ACTION_SHUTDOWN
: /* 0x05 */
850 case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
: /* 0x0a */
851 case WLX_SAS_ACTION_SHUTDOWN_REBOOT
: /* 0x0b */
852 if (Session
->LogonStatus
!= WKSTA_IS_LOGGED_OFF
)
854 if (!Session
->Gina
.Functions
.WlxIsLogoffOk(Session
->Gina
.Context
))
856 SwitchDesktop(WLSession
->WinlogonDesktop
);
857 Session
->Gina
.Functions
.WlxLogoff(Session
->Gina
.Context
);
858 if (!NT_SUCCESS(HandleLogoff(Session
, EWX_LOGOFF
)))
860 RemoveStatusMessage(Session
);
864 if (WLX_SHUTTINGDOWN(wlxAction
))
866 Session
->Gina
.Functions
.WlxShutdown(Session
->Gina
.Context
, wlxAction
);
867 if (!NT_SUCCESS(HandleShutdown(Session
, wlxAction
)))
869 RemoveStatusMessage(Session
);
870 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
875 RemoveStatusMessage(Session
);
876 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
879 case WLX_SAS_ACTION_TASKLIST
: /* 0x07 */
880 SwitchDesktop(WLSession
->ApplicationDesktop
);
881 StartTaskManager(Session
);
883 case WLX_SAS_ACTION_UNLOCK_WKSTA
: /* 0x08 */
884 SwitchDesktop(WLSession
->ApplicationDesktop
);
885 Session
->LogonStatus
= WKSTA_IS_LOGGED_ON
;
888 WARN("Unknown SAS action 0x%lx\n", wlxAction
);
894 IN OUT PWLSESSION Session
,
897 DWORD wlxAction
= WLX_SAS_ACTION_NONE
;
899 if (Session
->LogonStatus
== WKSTA_IS_LOGGED_ON
)
900 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOnSAS(Session
->Gina
.Context
, dwSasType
, NULL
);
901 else if (Session
->LogonStatus
== WKSTA_IS_LOCKED
)
902 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxWkstaLockedSAS(Session
->Gina
.Context
, dwSasType
);
905 /* Display a new dialog (if necessary) */
908 case WLX_SAS_TYPE_TIMEOUT
: /* 0x00 */
910 Session
->Gina
.Functions
.WlxDisplaySASNotice(Session
->Gina
.Context
);
915 PSID LogonSid
= NULL
; /* FIXME */
917 Session
->Options
= 0;
919 wlxAction
= (DWORD
)Session
->Gina
.Functions
.WlxLoggedOutSAS(
920 Session
->Gina
.Context
,
926 &Session
->MprNotifyInfo
,
927 (PVOID
*)&Session
->Profile
);
933 if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_TIMEOUT
)
936 if (!Session
->Gina
.Functions
.WlxScreenSaverNotify(Session
->Gina
.Context
, &bSecure
))
938 /* Skip start of screen saver */
939 SetEvent(Session
->hEndOfScreenSaver
);
944 DoGenericAction(Session
, WLX_SAS_ACTION_LOCK_WKSTA
);
945 StartScreenSaver(Session
);
948 else if (dwSasType
== WLX_SAS_TYPE_SCRNSVR_ACTIVITY
)
949 SetEvent(Session
->hUserActivity
);
951 DoGenericAction(Session
, wlxAction
);
956 IN PWLSESSION Session
,
959 /* Register Ctrl+Alt+Del Hotkey */
960 if (!RegisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
, MOD_CONTROL
| MOD_ALT
, VK_DELETE
))
962 ERR("WL: Unable to register Ctrl+Alt+Del hotkey!\n");
966 /* Register Ctrl+Shift+Esc (optional) */
967 Session
->TaskManHotkey
= RegisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
, MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
);
968 if (!Session
->TaskManHotkey
)
969 WARN("WL: Warning: Unable to register Ctrl+Alt+Esc hotkey!\n");
975 IN PWLSESSION Session
,
978 /* Unregister hotkeys */
979 UnregisterHotKey(hwndSAS
, HK_CTRL_ALT_DEL
);
981 if (Session
->TaskManHotkey
)
982 UnregisterHotKey(hwndSAS
, HK_CTRL_SHIFT_ESC
);
988 CheckForShutdownPrivilege(
989 IN DWORD RequestingProcessId
)
994 PPRIVILEGE_SET PrivSet
;
996 TRACE("CheckForShutdownPrivilege()\n");
998 Process
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, RequestingProcessId
);
1001 WARN("OpenProcess() failed with error %lu\n", GetLastError());
1002 return STATUS_INVALID_HANDLE
;
1004 if (!OpenProcessToken(Process
, TOKEN_QUERY
, &Token
))
1006 WARN("OpenProcessToken() failed with error %lu\n", GetLastError());
1007 CloseHandle(Process
);
1008 return STATUS_INVALID_HANDLE
;
1010 CloseHandle(Process
);
1011 PrivSet
= HeapAlloc(GetProcessHeap(), 0, sizeof(PRIVILEGE_SET
) + sizeof(LUID_AND_ATTRIBUTES
));
1014 ERR("Failed to allocate mem for privilege set\n");
1016 return STATUS_NO_MEMORY
;
1018 PrivSet
->PrivilegeCount
= 1;
1019 PrivSet
->Control
= PRIVILEGE_SET_ALL_NECESSARY
;
1020 if (!LookupPrivilegeValue(NULL
, SE_SHUTDOWN_NAME
, &PrivSet
->Privilege
[0].Luid
))
1022 WARN("LookupPrivilegeValue() failed with error %lu\n", GetLastError());
1023 HeapFree(GetProcessHeap(), 0, PrivSet
);
1025 return STATUS_UNSUCCESSFUL
;
1027 if (!PrivilegeCheck(Token
, PrivSet
, &CheckResult
))
1029 WARN("PrivilegeCheck() failed with error %lu\n", GetLastError());
1030 HeapFree(GetProcessHeap(), 0, PrivSet
);
1032 return STATUS_ACCESS_DENIED
;
1034 HeapFree(GetProcessHeap(), 0, PrivSet
);
1039 WARN("SE_SHUTDOWN privilege not enabled\n");
1040 return STATUS_ACCESS_DENIED
;
1042 return STATUS_SUCCESS
;
1047 HandleMessageBeep(UINT uType
)
1057 EventName
= L
"SystemDefault";
1059 case MB_ICONASTERISK
:
1060 EventName
= L
"SystemAsterisk";
1062 case MB_ICONEXCLAMATION
:
1063 EventName
= L
"SystemExclamation";
1066 EventName
= L
"SystemHand";
1068 case MB_ICONQUESTION
:
1069 EventName
= L
"SystemQuestion";
1072 WARN("Unhandled type %d\n", uType
);
1073 EventName
= L
"SystemDefault";
1076 return PlaySoundRoutine(EventName
, FALSE
, SND_ALIAS
| SND_NOWAIT
| SND_NOSTOP
| SND_ASYNC
);
1079 static LRESULT CALLBACK
1086 PWLSESSION Session
= (PWLSESSION
)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
1094 case MAKELONG(MOD_CONTROL
| MOD_ALT
, VK_DELETE
):
1096 TRACE("SAS: CONTROL+ALT+DELETE\n");
1097 if (!Session
->Gina
.UseCtrlAltDelete
)
1099 PostMessageW(Session
->SASWindow
, WLX_WM_SAS
, WLX_SAS_TYPE_CTRL_ALT_DEL
, 0);
1102 case MAKELONG(MOD_CONTROL
| MOD_SHIFT
, VK_ESCAPE
):
1104 TRACE("SAS: CONTROL+SHIFT+ESCAPE\n");
1105 DoGenericAction(Session
, WLX_SAS_ACTION_TASKLIST
);
1113 /* Get the session pointer from the create data */
1114 Session
= (PWLSESSION
)((LPCREATESTRUCT
)lParam
)->lpCreateParams
;
1116 /* Save the Session pointer */
1117 SetWindowLongPtrW(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)Session
);
1120 return RegisterHotKeys(Session
, hwndDlg
);
1124 if (!GetSetupType())
1125 UnregisterHotKeys(Session
, hwndDlg
);
1128 case WM_SETTINGCHANGE
:
1130 UINT uiAction
= (UINT
)wParam
;
1131 if (uiAction
== SPI_SETSCREENSAVETIMEOUT
1132 || uiAction
== SPI_SETSCREENSAVEACTIVE
)
1134 SetEvent(Session
->hScreenSaverParametersChanged
);
1138 case WM_LOGONNOTIFY
:
1142 case LN_MESSAGE_BEEP
:
1144 return HandleMessageBeep(lParam
);
1146 case LN_SHELL_EXITED
:
1148 /* lParam is the exit code */
1151 SetTimer(hwndDlg
, 1, 1000, NULL
);
1155 case LN_START_SCREENSAVE
:
1157 BOOL bSecure
= FALSE
;
1164 // lParam 1 == Secure
1167 if (Session
->Gina
.Functions
.WlxScreenSaverNotify(Session
->Gina
.Context
, &bSecure
))
1169 if (bSecure
) DoGenericAction(Session
, WLX_SAS_ACTION_LOCK_WKSTA
);
1173 StartScreenSaver(Session
);
1179 ERR("WM_LOGONNOTIFY case %d is unimplemented\n", wParam
);
1188 KillTimer(hwndDlg
, 1);
1189 StartUserShell(Session
);
1195 DispatchSAS(Session
, (DWORD
)wParam
);
1198 case PM_WINLOGON_EXITWINDOWS
:
1200 UINT Flags
= (UINT
)lParam
;
1201 UINT Action
= Flags
& EWX_ACTION_MASK
;
1204 /* Check parameters */
1207 case EWX_LOGOFF
: wlxAction
= WLX_SAS_ACTION_LOGOFF
; break;
1208 case EWX_SHUTDOWN
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN
; break;
1209 case EWX_REBOOT
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_REBOOT
; break;
1210 case EWX_POWEROFF
: wlxAction
= WLX_SAS_ACTION_SHUTDOWN_POWER_OFF
; break;
1213 ERR("Invalid ExitWindows action 0x%x\n", Action
);
1214 return STATUS_INVALID_PARAMETER
;
1218 if (WLX_SHUTTINGDOWN(wlxAction
))
1220 NTSTATUS Status
= CheckForShutdownPrivilege((DWORD
)wParam
);
1221 if (!NT_SUCCESS(Status
))
1224 DoGenericAction(Session
, wlxAction
);
1229 return DefWindowProc(hwndDlg
, uMsg
, wParam
, lParam
);
1234 IN OUT PWLSESSION Session
)
1239 if (!SwitchDesktop(Session
->WinlogonDesktop
))
1241 ERR("WL: Failed to switch to winlogon desktop\n");
1245 /* Register SAS window class */
1246 swc
.cbSize
= sizeof(WNDCLASSEXW
);
1247 swc
.style
= CS_SAVEBITS
;
1248 swc
.lpfnWndProc
= SASWindowProc
;
1251 swc
.hInstance
= hAppInstance
;
1254 swc
.hbrBackground
= NULL
;
1255 swc
.lpszMenuName
= NULL
;
1256 swc
.lpszClassName
= WINLOGON_SAS_CLASS
;
1258 if (RegisterClassExW(&swc
) == 0)
1260 ERR("WL: Failed to register SAS window class\n");
1264 /* Create invisible SAS window */
1265 Session
->SASWindow
= CreateWindowExW(
1271 hAppInstance
, Session
);
1272 if (!Session
->SASWindow
)
1274 ERR("WL: Failed to create SAS window\n");
1278 /* Register SAS window to receive SAS notifications */
1279 if (!SetLogonNotifyWindow(Session
->SASWindow
, Session
->InteractiveWindowStation
))
1281 ERR("WL: Failed to register SAS window\n");
1285 if (!SetDefaultLanguage(FALSE
))
1292 UninitializeSAS(Session
);