xref: /reactos/base/system/winlogon/sas.c (revision f96c39f6)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * COPYRIGHT:       See COPYING in the top level directory
3c2c66affSColin Finck  * PROJECT:         ReactOS Winlogon
4c2c66affSColin Finck  * FILE:            base/system/winlogon/sas.c
5c2c66affSColin Finck  * PURPOSE:         Secure Attention Sequence
6c2c66affSColin Finck  * PROGRAMMERS:     Thomas Weidenmueller (w3seek@users.sourceforge.net)
7c2c66affSColin Finck  *                  Herv� Poussineau (hpoussin@reactos.org)
85f033392SArnav Bhatt  *                  Arnav Bhatt (arnavbhatt288@gmail.com)
9c2c66affSColin Finck  * UPDATE HISTORY:
10c2c66affSColin Finck  *                  Created 28/03/2004
11c2c66affSColin Finck  */
12c2c66affSColin Finck 
13c2c66affSColin Finck /* INCLUDES *****************************************************************/
14c2c66affSColin Finck 
15c2c66affSColin Finck #include "winlogon.h"
16c2c66affSColin Finck 
17c2c66affSColin Finck #define WIN32_LEAN_AND_MEAN
18c2c66affSColin Finck #include <aclapi.h>
19c2c66affSColin Finck #include <mmsystem.h>
20c2c66affSColin Finck #include <userenv.h>
21c2c66affSColin Finck #include <ndk/setypes.h>
22c2c66affSColin Finck #include <ndk/sefuncs.h>
23c2c66affSColin Finck 
24c2c66affSColin Finck /* GLOBALS ******************************************************************/
25c2c66affSColin Finck 
26c2c66affSColin Finck #define WINLOGON_SAS_CLASS L"SAS Window class"
27c2c66affSColin Finck #define WINLOGON_SAS_TITLE L"SAS window"
28c2c66affSColin Finck 
29c2c66affSColin Finck #define HK_CTRL_ALT_DEL   0
30c2c66affSColin Finck #define HK_CTRL_SHIFT_ESC 1
31c2c66affSColin Finck 
32c2c66affSColin Finck // #define EWX_FLAGS_MASK  0x00000014
33c2c66affSColin Finck // #define EWX_ACTION_MASK ~EWX_FLAGS_MASK
34c2c66affSColin Finck 
35c2c66affSColin Finck // FIXME: At the moment we use this value (select the lowbyte flags and some highbytes ones).
36c2c66affSColin Finck // It should be set such that it makes winlogon accepting only valid flags.
37c2c66affSColin Finck #define EWX_ACTION_MASK 0x5C0F
38c2c66affSColin Finck 
39c2c66affSColin Finck typedef struct tagLOGOFF_SHUTDOWN_DATA
40c2c66affSColin Finck {
41c2c66affSColin Finck     UINT Flags;
42c2c66affSColin Finck     PWLSESSION Session;
43c2c66affSColin Finck } LOGOFF_SHUTDOWN_DATA, *PLOGOFF_SHUTDOWN_DATA;
44c2c66affSColin Finck 
45c2c66affSColin Finck static BOOL ExitReactOSInProgress = FALSE;
46c2c66affSColin Finck 
4702eee253SHermès Bélusca-Maïto LUID LuidNone = {0, 0};
4802eee253SHermès Bélusca-Maïto 
49c2c66affSColin Finck /* FUNCTIONS ****************************************************************/
50c2c66affSColin Finck 
51c2c66affSColin Finck static BOOL
52c2c66affSColin Finck StartTaskManager(
53c2c66affSColin Finck     IN OUT PWLSESSION Session)
54c2c66affSColin Finck {
55c2c66affSColin Finck     LPVOID lpEnvironment;
56c2c66affSColin Finck     BOOL ret;
57c2c66affSColin Finck 
58c2c66affSColin Finck     if (!Session->Gina.Functions.WlxStartApplication)
59c2c66affSColin Finck         return FALSE;
60c2c66affSColin Finck 
61c2c66affSColin Finck     if (!CreateEnvironmentBlock(
62c2c66affSColin Finck         &lpEnvironment,
63c2c66affSColin Finck         Session->UserToken,
64c2c66affSColin Finck         TRUE))
65c2c66affSColin Finck     {
66c2c66affSColin Finck         return FALSE;
67c2c66affSColin Finck     }
68c2c66affSColin Finck 
69c2c66affSColin Finck     ret = Session->Gina.Functions.WlxStartApplication(
70c2c66affSColin Finck         Session->Gina.Context,
71c2c66affSColin Finck         L"Default",
72c2c66affSColin Finck         lpEnvironment,
73c2c66affSColin Finck         L"taskmgr.exe");
74c2c66affSColin Finck 
75c2c66affSColin Finck     DestroyEnvironmentBlock(lpEnvironment);
76c2c66affSColin Finck     return ret;
77c2c66affSColin Finck }
78c2c66affSColin Finck 
79c2c66affSColin Finck static BOOL
80c2c66affSColin Finck StartUserShell(
81c2c66affSColin Finck     IN OUT PWLSESSION Session)
82c2c66affSColin Finck {
83c2c66affSColin Finck     LPVOID lpEnvironment = NULL;
84c2c66affSColin Finck     BOOLEAN Old;
85c2c66affSColin Finck     BOOL ret;
86c2c66affSColin Finck 
87c2c66affSColin Finck     /* Create environment block for the user */
88c2c66affSColin Finck     if (!CreateEnvironmentBlock(&lpEnvironment, Session->UserToken, TRUE))
89c2c66affSColin Finck     {
90c2c66affSColin Finck         WARN("WL: CreateEnvironmentBlock() failed\n");
91c2c66affSColin Finck         return FALSE;
92c2c66affSColin Finck     }
93c2c66affSColin Finck 
94c2c66affSColin Finck     /* Get privilege */
95c2c66affSColin Finck     /* FIXME: who should do it? winlogon or gina? */
96c2c66affSColin Finck     /* FIXME: reverting to lower privileges after creating user shell? */
97c2c66affSColin Finck     RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, TRUE, FALSE, &Old);
98c2c66affSColin Finck 
99c2c66affSColin Finck     ret = Session->Gina.Functions.WlxActivateUserShell(
100c2c66affSColin Finck                 Session->Gina.Context,
101c2c66affSColin Finck                 L"Default",
102c2c66affSColin Finck                 NULL, /* FIXME */
103c2c66affSColin Finck                 lpEnvironment);
104c2c66affSColin Finck 
105c2c66affSColin Finck     DestroyEnvironmentBlock(lpEnvironment);
106c2c66affSColin Finck     return ret;
107c2c66affSColin Finck }
108c2c66affSColin Finck 
109c2c66affSColin Finck 
110c2c66affSColin Finck BOOL
111c2c66affSColin Finck SetDefaultLanguage(
112c2c66affSColin Finck     IN PWLSESSION Session)
113c2c66affSColin Finck {
114c2c66affSColin Finck     BOOL ret = FALSE;
115c2c66affSColin Finck     BOOL UserProfile;
116c2c66affSColin Finck     LONG rc;
117c2c66affSColin Finck     HKEY UserKey, hKey = NULL;
118c2c66affSColin Finck     LPCWSTR SubKey, ValueName;
119c2c66affSColin Finck     DWORD dwType, dwSize;
120c2c66affSColin Finck     LPWSTR Value = NULL;
121c2c66affSColin Finck     UNICODE_STRING ValueString;
122c2c66affSColin Finck     NTSTATUS Status;
123c2c66affSColin Finck     LCID Lcid;
124c2c66affSColin Finck 
125c2c66affSColin Finck     UserProfile = (Session && Session->UserToken);
126c2c66affSColin Finck 
127c2c66affSColin Finck     if (UserProfile && !ImpersonateLoggedOnUser(Session->UserToken))
128c2c66affSColin Finck     {
129c2c66affSColin Finck         ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
130c2c66affSColin Finck         return FALSE;
131c2c66affSColin Finck         // FIXME: ... or use the default language of the system??
132c2c66affSColin Finck         // UserProfile = FALSE;
133c2c66affSColin Finck     }
134c2c66affSColin Finck 
135c2c66affSColin Finck     if (UserProfile)
136c2c66affSColin Finck     {
137c2c66affSColin Finck         rc = RegOpenCurrentUser(MAXIMUM_ALLOWED, &UserKey);
138c2c66affSColin Finck         if (rc != ERROR_SUCCESS)
139c2c66affSColin Finck         {
140c2c66affSColin Finck             TRACE("RegOpenCurrentUser() failed with error %lu\n", rc);
141c2c66affSColin Finck             goto cleanup;
142c2c66affSColin Finck         }
143c2c66affSColin Finck 
144c2c66affSColin Finck         SubKey = L"Control Panel\\International";
145c2c66affSColin Finck         ValueName = L"Locale";
146c2c66affSColin Finck     }
147c2c66affSColin Finck     else
148c2c66affSColin Finck     {
149c2c66affSColin Finck         UserKey = NULL;
150c2c66affSColin Finck         SubKey = L"System\\CurrentControlSet\\Control\\Nls\\Language";
151c2c66affSColin Finck         ValueName = L"Default";
152c2c66affSColin Finck     }
153c2c66affSColin Finck 
154c2c66affSColin Finck     rc = RegOpenKeyExW(UserKey ? UserKey : HKEY_LOCAL_MACHINE,
155c2c66affSColin Finck                        SubKey,
156c2c66affSColin Finck                        0,
157c2c66affSColin Finck                        KEY_READ,
158c2c66affSColin Finck                        &hKey);
159c2c66affSColin Finck 
160c2c66affSColin Finck     if (UserKey)
161c2c66affSColin Finck         RegCloseKey(UserKey);
162c2c66affSColin Finck 
163c2c66affSColin Finck     if (rc != ERROR_SUCCESS)
164c2c66affSColin Finck     {
165c2c66affSColin Finck         TRACE("RegOpenKeyEx() failed with error %lu\n", rc);
166c2c66affSColin Finck         goto cleanup;
167c2c66affSColin Finck     }
168c2c66affSColin Finck 
169c2c66affSColin Finck     rc = RegQueryValueExW(hKey,
170c2c66affSColin Finck                           ValueName,
171c2c66affSColin Finck                           NULL,
172c2c66affSColin Finck                           &dwType,
173c2c66affSColin Finck                           NULL,
174c2c66affSColin Finck                           &dwSize);
175c2c66affSColin Finck     if (rc != ERROR_SUCCESS)
176c2c66affSColin Finck     {
177c2c66affSColin Finck         TRACE("RegQueryValueEx() failed with error %lu\n", rc);
178c2c66affSColin Finck         goto cleanup;
179c2c66affSColin Finck     }
180c2c66affSColin Finck     else if (dwType != REG_SZ)
181c2c66affSColin Finck     {
182c2c66affSColin Finck         TRACE("Wrong type for %S\\%S registry entry (got 0x%lx, expected 0x%x)\n",
183c2c66affSColin Finck             SubKey, ValueName, dwType, REG_SZ);
184c2c66affSColin Finck         goto cleanup;
185c2c66affSColin Finck     }
186c2c66affSColin Finck 
187c2c66affSColin Finck     Value = HeapAlloc(GetProcessHeap(), 0, dwSize);
188c2c66affSColin Finck     if (!Value)
189c2c66affSColin Finck     {
190c2c66affSColin Finck         TRACE("HeapAlloc() failed\n");
191c2c66affSColin Finck         goto cleanup;
192c2c66affSColin Finck     }
193c2c66affSColin Finck     rc = RegQueryValueExW(hKey,
194c2c66affSColin Finck                           ValueName,
195c2c66affSColin Finck                           NULL,
196c2c66affSColin Finck                           NULL,
197c2c66affSColin Finck                           (LPBYTE)Value,
198c2c66affSColin Finck                           &dwSize);
199c2c66affSColin Finck     if (rc != ERROR_SUCCESS)
200c2c66affSColin Finck     {
201c2c66affSColin Finck         TRACE("RegQueryValueEx() failed with error %lu\n", rc);
202c2c66affSColin Finck         goto cleanup;
203c2c66affSColin Finck     }
204c2c66affSColin Finck 
205c2c66affSColin Finck     /* Convert Value to a Lcid */
206c2c66affSColin Finck     ValueString.Length = ValueString.MaximumLength = (USHORT)dwSize;
207c2c66affSColin Finck     ValueString.Buffer = Value;
208c2c66affSColin Finck     Status = RtlUnicodeStringToInteger(&ValueString, 16, (PULONG)&Lcid);
209c2c66affSColin Finck     if (!NT_SUCCESS(Status))
210c2c66affSColin Finck     {
211c2c66affSColin Finck         TRACE("RtlUnicodeStringToInteger() failed with status 0x%08lx\n", Status);
212c2c66affSColin Finck         goto cleanup;
213c2c66affSColin Finck     }
214c2c66affSColin Finck 
215c2c66affSColin Finck     TRACE("%s language is 0x%08lx\n",
216c2c66affSColin Finck         UserProfile ? "User" : "System", Lcid);
217c2c66affSColin Finck     Status = NtSetDefaultLocale(UserProfile, Lcid);
218c2c66affSColin Finck     if (!NT_SUCCESS(Status))
219c2c66affSColin Finck     {
220c2c66affSColin Finck         TRACE("NtSetDefaultLocale() failed with status 0x%08lx\n", Status);
221c2c66affSColin Finck         goto cleanup;
222c2c66affSColin Finck     }
223c2c66affSColin Finck 
224c2c66affSColin Finck     ret = TRUE;
225c2c66affSColin Finck 
226c2c66affSColin Finck cleanup:
227c2c66affSColin Finck     if (Value)
228c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, Value);
229c2c66affSColin Finck 
230c2c66affSColin Finck     if (hKey)
231c2c66affSColin Finck         RegCloseKey(hKey);
232c2c66affSColin Finck 
233c2c66affSColin Finck     if (UserProfile)
234c2c66affSColin Finck         RevertToSelf();
235c2c66affSColin Finck 
236c2c66affSColin Finck     return ret;
237c2c66affSColin Finck }
238c2c66affSColin Finck 
239c2c66affSColin Finck BOOL
240c2c66affSColin Finck PlaySoundRoutine(
241c2c66affSColin Finck     IN LPCWSTR FileName,
242c2c66affSColin Finck     IN UINT bLogon,
243c2c66affSColin Finck     IN UINT Flags)
244c2c66affSColin Finck {
245c2c66affSColin Finck     typedef BOOL (WINAPI *PLAYSOUNDW)(LPCWSTR,HMODULE,DWORD);
246c2c66affSColin Finck     typedef UINT (WINAPI *WAVEOUTGETNUMDEVS)(VOID);
247c2c66affSColin Finck     PLAYSOUNDW Play;
248c2c66affSColin Finck     WAVEOUTGETNUMDEVS waveOutGetNumDevs;
249c2c66affSColin Finck     UINT NumDevs;
250c2c66affSColin Finck     HMODULE hLibrary;
251c2c66affSColin Finck     BOOL Ret = FALSE;
252c2c66affSColin Finck 
253c2c66affSColin Finck     hLibrary = LoadLibraryW(L"winmm.dll");
254c2c66affSColin Finck     if (hLibrary)
255c2c66affSColin Finck     {
256c2c66affSColin Finck         waveOutGetNumDevs = (WAVEOUTGETNUMDEVS)GetProcAddress(hLibrary, "waveOutGetNumDevs");
257c2c66affSColin Finck         if (waveOutGetNumDevs)
258c2c66affSColin Finck         {
259c2c66affSColin Finck             NumDevs = waveOutGetNumDevs();
260c2c66affSColin Finck             if (!NumDevs)
261c2c66affSColin Finck             {
262c2c66affSColin Finck                 if (!bLogon)
263c2c66affSColin Finck                 {
264d811fca7SAdam Słaboń                     Beep(440, 125);
265c2c66affSColin Finck                 }
266c2c66affSColin Finck                 FreeLibrary(hLibrary);
267c2c66affSColin Finck                 return FALSE;
268c2c66affSColin Finck             }
269c2c66affSColin Finck         }
270c2c66affSColin Finck 
271c2c66affSColin Finck         Play = (PLAYSOUNDW)GetProcAddress(hLibrary, "PlaySoundW");
272c2c66affSColin Finck         if (Play)
273c2c66affSColin Finck         {
274c2c66affSColin Finck             Ret = Play(FileName, NULL, Flags);
275c2c66affSColin Finck         }
276c2c66affSColin Finck         FreeLibrary(hLibrary);
277c2c66affSColin Finck     }
278c2c66affSColin Finck 
279c2c66affSColin Finck     return Ret;
280c2c66affSColin Finck }
281c2c66affSColin Finck 
282c2c66affSColin Finck DWORD
283c2c66affSColin Finck WINAPI
284c2c66affSColin Finck PlayLogonSoundThread(
285c2c66affSColin Finck     IN LPVOID lpParameter)
286c2c66affSColin Finck {
287c2c66affSColin Finck     BYTE TokenUserBuffer[256];
288c2c66affSColin Finck     PTOKEN_USER pTokenUser = (TOKEN_USER*)TokenUserBuffer;
289c2c66affSColin Finck     ULONG Length;
290c2c66affSColin Finck     HKEY hKey;
291c2c66affSColin Finck     WCHAR wszBuffer[MAX_PATH] = {0};
292c2c66affSColin Finck     WCHAR wszDest[MAX_PATH];
293c2c66affSColin Finck     DWORD dwSize = sizeof(wszBuffer), dwType;
294c2c66affSColin Finck     SERVICE_STATUS_PROCESS Info;
295c2c66affSColin Finck     UNICODE_STRING SidString;
296c2c66affSColin Finck     NTSTATUS Status;
297c2c66affSColin Finck     ULONG Index = 0;
298c2c66affSColin Finck     SC_HANDLE hSCManager, hService;
299c2c66affSColin Finck 
300c2c66affSColin Finck     //
301c2c66affSColin Finck     // FIXME: Isn't it possible to *JUST* impersonate the current user
302c2c66affSColin Finck     // *AND* open its HKCU??
303c2c66affSColin Finck     //
304c2c66affSColin Finck 
305c2c66affSColin Finck     /* Get SID of current user */
306c2c66affSColin Finck     Status = NtQueryInformationToken((HANDLE)lpParameter,
307c2c66affSColin Finck                                      TokenUser,
308c2c66affSColin Finck                                      TokenUserBuffer,
309c2c66affSColin Finck                                      sizeof(TokenUserBuffer),
310c2c66affSColin Finck                                      &Length);
311c2c66affSColin Finck     if (!NT_SUCCESS(Status))
312c2c66affSColin Finck     {
313c2c66affSColin Finck         ERR("NtQueryInformationToken failed: %x!\n", Status);
314c2c66affSColin Finck         return 0;
315c2c66affSColin Finck     }
316c2c66affSColin Finck 
317c2c66affSColin Finck     /* Convert SID to string */
318c2c66affSColin Finck     RtlInitEmptyUnicodeString(&SidString, wszBuffer, sizeof(wszBuffer));
319c2c66affSColin Finck     Status = RtlConvertSidToUnicodeString(&SidString, pTokenUser->User.Sid, FALSE);
320c2c66affSColin Finck     if (!NT_SUCCESS(Status))
321c2c66affSColin Finck     {
322c2c66affSColin Finck         ERR("RtlConvertSidToUnicodeString failed: %x!\n", Status);
323c2c66affSColin Finck         return 0;
324c2c66affSColin Finck     }
325c2c66affSColin Finck 
326c2c66affSColin Finck     /* Build path to logon sound registry key.
327c2c66affSColin Finck        Note: We can't use HKCU here, because Winlogon is owned by SYSTEM user */
328c2c66affSColin Finck     if (FAILED(StringCbCopyW(wszBuffer + SidString.Length/sizeof(WCHAR),
329c2c66affSColin Finck                              sizeof(wszBuffer) - SidString.Length,
330c2c66affSColin Finck                              L"\\AppEvents\\Schemes\\Apps\\.Default\\WindowsLogon\\.Current")))
331c2c66affSColin Finck     {
332c2c66affSColin Finck         /* SID is too long. Should not happen. */
333c2c66affSColin Finck         ERR("StringCbCopyW failed!\n");
334c2c66affSColin Finck         return 0;
335c2c66affSColin Finck     }
336c2c66affSColin Finck 
337c2c66affSColin Finck     /* Open registry key and query sound path */
338c2c66affSColin Finck     if (RegOpenKeyExW(HKEY_USERS, wszBuffer, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
339c2c66affSColin Finck     {
340c2c66affSColin Finck         ERR("RegOpenKeyExW(%ls) failed!\n", wszBuffer);
341c2c66affSColin Finck         return 0;
342c2c66affSColin Finck     }
343c2c66affSColin Finck 
344c2c66affSColin Finck     if (RegQueryValueExW(hKey, NULL, NULL, &dwType,
345c2c66affSColin Finck                       (LPBYTE)wszBuffer, &dwSize) != ERROR_SUCCESS ||
346c2c66affSColin Finck         (dwType != REG_SZ && dwType != REG_EXPAND_SZ))
347c2c66affSColin Finck     {
348c2c66affSColin Finck         ERR("RegQueryValueExW failed!\n");
349c2c66affSColin Finck         RegCloseKey(hKey);
350c2c66affSColin Finck         return 0;
351c2c66affSColin Finck     }
352c2c66affSColin Finck 
353c2c66affSColin Finck     RegCloseKey(hKey);
354c2c66affSColin Finck 
355c2c66affSColin Finck     if (!wszBuffer[0])
356c2c66affSColin Finck     {
357c2c66affSColin Finck         /* No sound has been set */
358c2c66affSColin Finck         ERR("No sound has been set\n");
359c2c66affSColin Finck         return 0;
360c2c66affSColin Finck     }
361c2c66affSColin Finck 
362c2c66affSColin Finck     /* Expand environment variables */
363c2c66affSColin Finck     if (!ExpandEnvironmentStringsW(wszBuffer, wszDest, MAX_PATH))
364c2c66affSColin Finck     {
365c2c66affSColin Finck         ERR("ExpandEnvironmentStringsW failed!\n");
366c2c66affSColin Finck         return 0;
367c2c66affSColin Finck     }
368c2c66affSColin Finck 
369c2c66affSColin Finck     /* Open the service manager */
370c2c66affSColin Finck     hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
371c2c66affSColin Finck     if (!hSCManager)
372c2c66affSColin Finck     {
373c2c66affSColin Finck         ERR("OpenSCManager failed (%x)\n", GetLastError());
374c2c66affSColin Finck         return 0;
375c2c66affSColin Finck     }
376c2c66affSColin Finck 
377c2c66affSColin Finck     /* Open the wdmaud service */
378c2c66affSColin Finck     hService = OpenServiceW(hSCManager, L"wdmaud", GENERIC_READ);
379c2c66affSColin Finck     if (!hService)
380c2c66affSColin Finck     {
381c2c66affSColin Finck         /* The service is not installed */
382c2c66affSColin Finck         TRACE("Failed to open wdmaud service (%x)\n", GetLastError());
383c2c66affSColin Finck         CloseServiceHandle(hSCManager);
384c2c66affSColin Finck         return 0;
385c2c66affSColin Finck     }
386c2c66affSColin Finck 
387c2c66affSColin Finck     /* Wait for wdmaud to start */
388c2c66affSColin Finck     do
389c2c66affSColin Finck     {
390c2c66affSColin Finck         if (!QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&Info, sizeof(SERVICE_STATUS_PROCESS), &dwSize))
391c2c66affSColin Finck         {
392c2c66affSColin Finck             TRACE("QueryServiceStatusEx failed (%x)\n", GetLastError());
393c2c66affSColin Finck             break;
394c2c66affSColin Finck         }
395c2c66affSColin Finck 
396c2c66affSColin Finck         if (Info.dwCurrentState == SERVICE_RUNNING)
397c2c66affSColin Finck             break;
398c2c66affSColin Finck 
399c2c66affSColin Finck         Sleep(1000);
400c2c66affSColin Finck 
401c2c66affSColin Finck     } while (Index++ < 20);
402c2c66affSColin Finck 
403c2c66affSColin Finck     CloseServiceHandle(hService);
404c2c66affSColin Finck     CloseServiceHandle(hSCManager);
405c2c66affSColin Finck 
406c2c66affSColin Finck     /* If wdmaud is not running exit */
407c2c66affSColin Finck     if (Info.dwCurrentState != SERVICE_RUNNING)
408c2c66affSColin Finck     {
409c2c66affSColin Finck         WARN("wdmaud has not started!\n");
410c2c66affSColin Finck         return 0;
411c2c66affSColin Finck     }
412c2c66affSColin Finck 
413c2c66affSColin Finck     /* Sound subsystem is running. Play logon sound. */
414c2c66affSColin Finck     TRACE("Playing logon sound: %ls\n", wszDest);
415c2c66affSColin Finck     PlaySoundRoutine(wszDest, TRUE, SND_FILENAME);
416c2c66affSColin Finck     return 0;
417c2c66affSColin Finck }
418c2c66affSColin Finck 
419c2c66affSColin Finck static
420c2c66affSColin Finck VOID
421c2c66affSColin Finck PlayLogonSound(
422c2c66affSColin Finck     IN OUT PWLSESSION Session)
423c2c66affSColin Finck {
424c2c66affSColin Finck     HANDLE hThread;
425c2c66affSColin Finck 
426c2c66affSColin Finck     hThread = CreateThread(NULL, 0, PlayLogonSoundThread, (PVOID)Session->UserToken, 0, NULL);
427c2c66affSColin Finck     if (hThread)
428c2c66affSColin Finck         CloseHandle(hThread);
429c2c66affSColin Finck }
430c2c66affSColin Finck 
431c2c66affSColin Finck static
4324cf87fdbSPierre Schweitzer VOID
4334cf87fdbSPierre Schweitzer RestoreAllConnections(PWLSESSION Session)
4344cf87fdbSPierre Schweitzer {
4354cf87fdbSPierre Schweitzer     DWORD dRet;
4364cf87fdbSPierre Schweitzer     HANDLE hEnum;
4374cf87fdbSPierre Schweitzer     LPNETRESOURCE lpRes;
4384cf87fdbSPierre Schweitzer     DWORD dSize = 0x1000;
4394cf87fdbSPierre Schweitzer     DWORD dCount = -1;
4404cf87fdbSPierre Schweitzer     LPNETRESOURCE lpCur;
4414cf87fdbSPierre Schweitzer     BOOL UserProfile;
4424cf87fdbSPierre Schweitzer 
4434cf87fdbSPierre Schweitzer     UserProfile = (Session && Session->UserToken);
4444cf87fdbSPierre Schweitzer     if (!UserProfile)
4454cf87fdbSPierre Schweitzer     {
4464cf87fdbSPierre Schweitzer         return;
4474cf87fdbSPierre Schweitzer     }
4484cf87fdbSPierre Schweitzer 
4494cf87fdbSPierre Schweitzer     if (!ImpersonateLoggedOnUser(Session->UserToken))
4504cf87fdbSPierre Schweitzer     {
4514cf87fdbSPierre Schweitzer         ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
4524cf87fdbSPierre Schweitzer         return;
4534cf87fdbSPierre Schweitzer     }
4544cf87fdbSPierre Schweitzer 
4554cf87fdbSPierre Schweitzer     dRet = WNetOpenEnum(RESOURCE_REMEMBERED, RESOURCETYPE_DISK, 0, NULL, &hEnum);
4564cf87fdbSPierre Schweitzer     if (dRet != WN_SUCCESS)
4574cf87fdbSPierre Schweitzer     {
4584cf87fdbSPierre Schweitzer         ERR("Failed to open enumeration: %lu\n", dRet);
4594cf87fdbSPierre Schweitzer         goto quit;
4604cf87fdbSPierre Schweitzer     }
4614cf87fdbSPierre Schweitzer 
4624cf87fdbSPierre Schweitzer     lpRes = HeapAlloc(GetProcessHeap(), 0, dSize);
4634cf87fdbSPierre Schweitzer     if (!lpRes)
4644cf87fdbSPierre Schweitzer     {
4654cf87fdbSPierre Schweitzer         ERR("Failed to allocate memory\n");
4664cf87fdbSPierre Schweitzer         WNetCloseEnum(hEnum);
4674cf87fdbSPierre Schweitzer         goto quit;
4684cf87fdbSPierre Schweitzer     }
4694cf87fdbSPierre Schweitzer 
4704cf87fdbSPierre Schweitzer     do
4714cf87fdbSPierre Schweitzer     {
4724cf87fdbSPierre Schweitzer         dSize = 0x1000;
4734cf87fdbSPierre Schweitzer         dCount = -1;
4744cf87fdbSPierre Schweitzer 
4754cf87fdbSPierre Schweitzer         memset(lpRes, 0, dSize);
4764cf87fdbSPierre Schweitzer         dRet = WNetEnumResource(hEnum, &dCount, lpRes, &dSize);
4774cf87fdbSPierre Schweitzer         if (dRet == WN_SUCCESS || dRet == WN_MORE_DATA)
4784cf87fdbSPierre Schweitzer         {
4794cf87fdbSPierre Schweitzer             lpCur = lpRes;
4804cf87fdbSPierre Schweitzer             for (; dCount; dCount--)
4814cf87fdbSPierre Schweitzer             {
4824cf87fdbSPierre Schweitzer                 WNetAddConnection(lpCur->lpRemoteName, NULL, lpCur->lpLocalName);
4834cf87fdbSPierre Schweitzer                 lpCur++;
4844cf87fdbSPierre Schweitzer             }
4854cf87fdbSPierre Schweitzer         }
4864cf87fdbSPierre Schweitzer     } while (dRet != WN_NO_MORE_ENTRIES);
4874cf87fdbSPierre Schweitzer 
4884cf87fdbSPierre Schweitzer     HeapFree(GetProcessHeap(), 0, lpRes);
4894cf87fdbSPierre Schweitzer     WNetCloseEnum(hEnum);
4904cf87fdbSPierre Schweitzer 
4914cf87fdbSPierre Schweitzer quit:
4924cf87fdbSPierre Schweitzer     RevertToSelf();
4934cf87fdbSPierre Schweitzer }
4944cf87fdbSPierre Schweitzer 
4954cf87fdbSPierre Schweitzer static
496c2c66affSColin Finck BOOL
497c2c66affSColin Finck HandleLogon(
498c2c66affSColin Finck     IN OUT PWLSESSION Session)
499c2c66affSColin Finck {
500c2c66affSColin Finck     PROFILEINFOW ProfileInfo;
501c2c66affSColin Finck     BOOL ret = FALSE;
502c2c66affSColin Finck 
503c2c66affSColin Finck     /* Loading personal settings */
504c2c66affSColin Finck     DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_LOADINGYOURPERSONALSETTINGS);
505c2c66affSColin Finck     ProfileInfo.hProfile = INVALID_HANDLE_VALUE;
506c2c66affSColin Finck     if (0 == (Session->Options & WLX_LOGON_OPT_NO_PROFILE))
507c2c66affSColin Finck     {
508c2c66affSColin Finck         if (Session->Profile == NULL
509c2c66affSColin Finck          || (Session->Profile->dwType != WLX_PROFILE_TYPE_V1_0
510c2c66affSColin Finck           && Session->Profile->dwType != WLX_PROFILE_TYPE_V2_0))
511c2c66affSColin Finck         {
512c2c66affSColin Finck             ERR("WL: Wrong profile\n");
513c2c66affSColin Finck             goto cleanup;
514c2c66affSColin Finck         }
515c2c66affSColin Finck 
516c2c66affSColin Finck         /* Load the user profile */
517c2c66affSColin Finck         ZeroMemory(&ProfileInfo, sizeof(PROFILEINFOW));
518c2c66affSColin Finck         ProfileInfo.dwSize = sizeof(PROFILEINFOW);
519c2c66affSColin Finck         ProfileInfo.dwFlags = 0;
520c2c66affSColin Finck         ProfileInfo.lpUserName = Session->MprNotifyInfo.pszUserName;
521c2c66affSColin Finck         ProfileInfo.lpProfilePath = Session->Profile->pszProfile;
522c2c66affSColin Finck         if (Session->Profile->dwType >= WLX_PROFILE_TYPE_V2_0)
523c2c66affSColin Finck         {
524c2c66affSColin Finck             ProfileInfo.lpDefaultPath = Session->Profile->pszNetworkDefaultUserProfile;
525c2c66affSColin Finck             ProfileInfo.lpServerName = Session->Profile->pszServerName;
526c2c66affSColin Finck             ProfileInfo.lpPolicyPath = Session->Profile->pszPolicy;
527c2c66affSColin Finck         }
528c2c66affSColin Finck 
529c2c66affSColin Finck         if (!LoadUserProfileW(Session->UserToken, &ProfileInfo))
530c2c66affSColin Finck         {
531c2c66affSColin Finck             ERR("WL: LoadUserProfileW() failed\n");
532c2c66affSColin Finck             goto cleanup;
533c2c66affSColin Finck         }
534c2c66affSColin Finck     }
535c2c66affSColin Finck 
536c2c66affSColin Finck     /* Create environment block for the user */
537c2c66affSColin Finck     if (!CreateUserEnvironment(Session))
538c2c66affSColin Finck     {
539c2c66affSColin Finck         WARN("WL: SetUserEnvironment() failed\n");
540c2c66affSColin Finck         goto cleanup;
541c2c66affSColin Finck     }
542c2c66affSColin Finck 
543c2c66affSColin Finck     CallNotificationDlls(Session, LogonHandler);
544c2c66affSColin Finck 
545c2c66affSColin Finck     DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_APPLYINGYOURPERSONALSETTINGS);
546c2c66affSColin Finck     UpdatePerUserSystemParameters(0, TRUE);
547c2c66affSColin Finck 
548c2c66affSColin Finck     /* Set default user language */
549c2c66affSColin Finck     if (!SetDefaultLanguage(Session))
550c2c66affSColin Finck     {
551c2c66affSColin Finck         WARN("WL: SetDefaultLanguage() failed\n");
552c2c66affSColin Finck         goto cleanup;
553c2c66affSColin Finck     }
554c2c66affSColin Finck 
555*f96c39f6SGeorge Bișoc     /* Allow winsta and desktop access for this session */
556*f96c39f6SGeorge Bișoc     if (!AllowAccessOnSession(Session))
557*f96c39f6SGeorge Bișoc     {
558*f96c39f6SGeorge Bișoc         WARN("WL: AllowAccessOnSession() failed to give winsta & desktop access for this session\n");
559*f96c39f6SGeorge Bișoc         goto cleanup;
560*f96c39f6SGeorge Bișoc     }
56102eee253SHermès Bélusca-Maïto 
5624cf87fdbSPierre Schweitzer     /* Connect remote resources */
5634cf87fdbSPierre Schweitzer     RestoreAllConnections(Session);
5644cf87fdbSPierre Schweitzer 
565c2c66affSColin Finck     if (!StartUserShell(Session))
566c2c66affSColin Finck     {
567c2c66affSColin Finck         //WCHAR StatusMsg[256];
568c2c66affSColin Finck         WARN("WL: WlxActivateUserShell() failed\n");
569c2c66affSColin Finck         //LoadStringW(hAppInstance, IDS_FAILEDACTIVATEUSERSHELL, StatusMsg, sizeof(StatusMsg) / sizeof(StatusMsg[0]));
570c2c66affSColin Finck         //MessageBoxW(0, StatusMsg, NULL, MB_ICONERROR);
571c2c66affSColin Finck         goto cleanup;
572c2c66affSColin Finck     }
573c2c66affSColin Finck 
574c2c66affSColin Finck     CallNotificationDlls(Session, StartShellHandler);
575c2c66affSColin Finck 
576c2c66affSColin Finck     if (!InitializeScreenSaver(Session))
577c2c66affSColin Finck         WARN("WL: Failed to initialize screen saver\n");
578c2c66affSColin Finck 
579c2c66affSColin Finck     Session->hProfileInfo = ProfileInfo.hProfile;
580c2c66affSColin Finck 
58140000a17SHermès Bélusca-Maïto     /* Logon has succeeded. Play sound. */
582c2c66affSColin Finck     PlayLogonSound(Session);
583c2c66affSColin Finck 
584c2c66affSColin Finck     ret = TRUE;
585c2c66affSColin Finck 
586c2c66affSColin Finck cleanup:
587c2c66affSColin Finck     if (Session->Profile)
588c2c66affSColin Finck     {
589c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, Session->Profile->pszProfile);
590c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, Session->Profile);
591c2c66affSColin Finck     }
592c2c66affSColin Finck     Session->Profile = NULL;
593c2c66affSColin Finck     if (!ret && ProfileInfo.hProfile != INVALID_HANDLE_VALUE)
594c2c66affSColin Finck     {
595c2c66affSColin Finck         UnloadUserProfile(Session->UserToken, ProfileInfo.hProfile);
596c2c66affSColin Finck     }
597c2c66affSColin Finck     RemoveStatusMessage(Session);
598c2c66affSColin Finck     if (!ret)
599c2c66affSColin Finck     {
60002eee253SHermès Bélusca-Maïto         SetWindowStationUser(Session->InteractiveWindowStation,
60102eee253SHermès Bélusca-Maïto                              &LuidNone, NULL, 0);
602c2c66affSColin Finck         CloseHandle(Session->UserToken);
603c2c66affSColin Finck         Session->UserToken = NULL;
604c2c66affSColin Finck     }
605c2c66affSColin Finck 
606c2c66affSColin Finck     if (ret)
607c2c66affSColin Finck     {
608c2c66affSColin Finck         SwitchDesktop(Session->ApplicationDesktop);
609c2c66affSColin Finck         Session->LogonState = STATE_LOGGED_ON;
610c2c66affSColin Finck     }
611c2c66affSColin Finck 
612c2c66affSColin Finck     return ret;
613c2c66affSColin Finck }
614c2c66affSColin Finck 
615c2c66affSColin Finck 
616c2c66affSColin Finck static
617c2c66affSColin Finck DWORD
618c2c66affSColin Finck WINAPI
619c2c66affSColin Finck LogoffShutdownThread(
620c2c66affSColin Finck     LPVOID Parameter)
621c2c66affSColin Finck {
622c2c66affSColin Finck     DWORD ret = 1;
623c2c66affSColin Finck     PLOGOFF_SHUTDOWN_DATA LSData = (PLOGOFF_SHUTDOWN_DATA)Parameter;
624c2c66affSColin Finck     UINT uFlags;
625c2c66affSColin Finck 
626c2c66affSColin Finck     if (LSData->Session->UserToken != NULL &&
627c2c66affSColin Finck         !ImpersonateLoggedOnUser(LSData->Session->UserToken))
628c2c66affSColin Finck     {
629c2c66affSColin Finck         ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
630c2c66affSColin Finck         return 0;
631c2c66affSColin Finck     }
632c2c66affSColin Finck 
633c2c66affSColin Finck     // FIXME: To be really fixed: need to check what needs to be kept and what needs to be removed there.
634c2c66affSColin Finck     //
635c2c66affSColin Finck     // uFlags = EWX_INTERNAL_KILL_USER_APPS | (LSData->Flags & EWX_FLAGS_MASK) |
636c2c66affSColin Finck              // ((LSData->Flags & EWX_ACTION_MASK) == EWX_LOGOFF ? EWX_CALLER_WINLOGON_LOGOFF : 0);
637c2c66affSColin Finck 
638c2c66affSColin Finck     uFlags = EWX_CALLER_WINLOGON | (LSData->Flags & 0x0F);
639c2c66affSColin Finck 
640c2c66affSColin Finck     TRACE("In LogoffShutdownThread with uFlags == 0x%x; exit_in_progress == %s\n",
641c2c66affSColin Finck         uFlags, ExitReactOSInProgress ? "true" : "false");
642c2c66affSColin Finck 
643c2c66affSColin Finck     ExitReactOSInProgress = TRUE;
644c2c66affSColin Finck 
645c2c66affSColin Finck     /* Close processes of the interactive user */
646c2c66affSColin Finck     if (!ExitWindowsEx(uFlags, 0))
647c2c66affSColin Finck     {
648c2c66affSColin Finck         ERR("Unable to kill user apps, error %lu\n", GetLastError());
649c2c66affSColin Finck         ret = 0;
650c2c66affSColin Finck     }
651c2c66affSColin Finck 
652cbff9a30SPierre Schweitzer     /* Cancel all the user connections */
6530dedb9b4SSerge Gautherie     WNetClearConnections(NULL);
654cbff9a30SPierre Schweitzer 
655c2c66affSColin Finck     if (LSData->Session->UserToken)
656c2c66affSColin Finck         RevertToSelf();
657c2c66affSColin Finck 
658c2c66affSColin Finck     return ret;
659c2c66affSColin Finck }
660c2c66affSColin Finck 
661c2c66affSColin Finck static
662c2c66affSColin Finck DWORD
663c2c66affSColin Finck WINAPI
664c2c66affSColin Finck KillComProcesses(
665c2c66affSColin Finck     LPVOID Parameter)
666c2c66affSColin Finck {
667c2c66affSColin Finck     DWORD ret = 1;
668c2c66affSColin Finck     PLOGOFF_SHUTDOWN_DATA LSData = (PLOGOFF_SHUTDOWN_DATA)Parameter;
669c2c66affSColin Finck 
670c2c66affSColin Finck     TRACE("In KillComProcesses\n");
671c2c66affSColin Finck 
672c2c66affSColin Finck     if (LSData->Session->UserToken != NULL &&
673c2c66affSColin Finck         !ImpersonateLoggedOnUser(LSData->Session->UserToken))
674c2c66affSColin Finck     {
675c2c66affSColin Finck         ERR("ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
676c2c66affSColin Finck         return 0;
677c2c66affSColin Finck     }
678c2c66affSColin Finck 
679c2c66affSColin Finck     /* Attempt to kill remaining processes. No notifications needed. */
680c2c66affSColin Finck     if (!ExitWindowsEx(EWX_CALLER_WINLOGON | EWX_NONOTIFY | EWX_FORCE | EWX_LOGOFF, 0))
681c2c66affSColin Finck     {
682c2c66affSColin Finck         ERR("Unable to kill COM apps, error %lu\n", GetLastError());
683c2c66affSColin Finck         ret = 0;
684c2c66affSColin Finck     }
685c2c66affSColin Finck 
686c2c66affSColin Finck     if (LSData->Session->UserToken)
687c2c66affSColin Finck         RevertToSelf();
688c2c66affSColin Finck 
689c2c66affSColin Finck     return ret;
690c2c66affSColin Finck }
691c2c66affSColin Finck 
692c2c66affSColin Finck static
693c2c66affSColin Finck NTSTATUS
694c2c66affSColin Finck CreateLogoffSecurityAttributes(
695c2c66affSColin Finck     OUT PSECURITY_ATTRIBUTES* ppsa)
696c2c66affSColin Finck {
697c2c66affSColin Finck     /* The following code is not working yet and messy */
698c2c66affSColin Finck     /* Still, it gives some ideas about data types and functions involved and */
699c2c66affSColin Finck     /* required to set up a SECURITY_DESCRIPTOR for a SECURITY_ATTRIBUTES */
700c2c66affSColin Finck     /* instance for a thread, to allow that  thread to ImpersonateLoggedOnUser(). */
701c2c66affSColin Finck     /* Specifically THREAD_SET_THREAD_TOKEN is required. */
702c2c66affSColin Finck     PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
703c2c66affSColin Finck     PSECURITY_ATTRIBUTES psa = 0;
704c2c66affSColin Finck     BYTE* pMem;
705c2c66affSColin Finck     PACL pACL;
706c2c66affSColin Finck     EXPLICIT_ACCESS Access;
707c2c66affSColin Finck     PSID pEveryoneSID = NULL;
708c2c66affSColin Finck     static SID_IDENTIFIER_AUTHORITY WorldAuthority = { SECURITY_WORLD_SID_AUTHORITY };
709c2c66affSColin Finck 
710c2c66affSColin Finck     *ppsa = NULL;
711c2c66affSColin Finck 
712c2c66affSColin Finck     // Let's first try to enumerate what kind of data we need for this to ever work:
713c2c66affSColin Finck     // 1.  The Winlogon SID, to be able to give it THREAD_SET_THREAD_TOKEN.
714c2c66affSColin Finck     // 2.  The users SID (the user trying to logoff, or rather shut down the system).
715c2c66affSColin Finck     // 3.  At least two EXPLICIT_ACCESS instances:
716c2c66affSColin Finck     // 3.1 One for Winlogon itself, giving it the rights
717c2c66affSColin Finck     //     required to THREAD_SET_THREAD_TOKEN (as it's needed to successfully call
718c2c66affSColin Finck     //     ImpersonateLoggedOnUser).
719c2c66affSColin Finck     // 3.2 One for the user, to allow *that* thread to perform its work.
720c2c66affSColin Finck     // 4.  An ACL to hold the these EXPLICIT_ACCESS ACE's.
721c2c66affSColin Finck     // 5.  A SECURITY_DESCRIPTOR to hold the ACL, and finally.
722c2c66affSColin Finck     // 6.  A SECURITY_ATTRIBUTES instance to pull all of this required stuff
723c2c66affSColin Finck     //     together, to hand it to CreateThread.
724c2c66affSColin Finck     //
725c2c66affSColin Finck     // However, it seems struct LOGOFF_SHUTDOWN_DATA doesn't contain
726c2c66affSColin Finck     // these required SID's, why they'd have to be added.
727c2c66affSColin Finck     // The Winlogon's own SID should probably only be created once,
728c2c66affSColin Finck     // while the user's SID obviously must be created for each new user.
729c2c66affSColin Finck     // Might as well store it when the user logs on?
730c2c66affSColin Finck 
731c2c66affSColin Finck     if(!AllocateAndInitializeSid(&WorldAuthority,
732c2c66affSColin Finck                                  1,
733c2c66affSColin Finck                                  SECURITY_WORLD_RID,
734c2c66affSColin Finck                                  0, 0, 0, 0, 0, 0, 0,
735c2c66affSColin Finck                                  &pEveryoneSID))
736c2c66affSColin Finck     {
737c2c66affSColin Finck         ERR("Failed to initialize security descriptor for logoff thread!\n");
738c2c66affSColin Finck         return STATUS_UNSUCCESSFUL;
739c2c66affSColin Finck     }
740c2c66affSColin Finck 
741c2c66affSColin Finck     /* set up the required security attributes to be able to shut down */
742c2c66affSColin Finck     /* To save space and time, allocate a single block of memory holding */
743c2c66affSColin Finck     /* both SECURITY_ATTRIBUTES and SECURITY_DESCRIPTOR */
744c2c66affSColin Finck     pMem = HeapAlloc(GetProcessHeap(),
745c2c66affSColin Finck                      0,
746c2c66affSColin Finck                      sizeof(SECURITY_ATTRIBUTES) +
747c2c66affSColin Finck                      SECURITY_DESCRIPTOR_MIN_LENGTH +
748c2c66affSColin Finck                      sizeof(ACL));
749c2c66affSColin Finck     if (!pMem)
750c2c66affSColin Finck     {
751c2c66affSColin Finck         ERR("Failed to allocate memory for logoff security descriptor!\n");
752c2c66affSColin Finck         return STATUS_NO_MEMORY;
753c2c66affSColin Finck     }
754c2c66affSColin Finck 
755c2c66affSColin Finck     /* Note that the security descriptor needs to be in _absolute_ format, */
756c2c66affSColin Finck     /* meaning its members must be pointers to other structures, rather */
757c2c66affSColin Finck     /* than the relative format using offsets */
758c2c66affSColin Finck     psa = (PSECURITY_ATTRIBUTES)pMem;
759c2c66affSColin Finck     SecurityDescriptor = (PSECURITY_DESCRIPTOR)(pMem + sizeof(SECURITY_ATTRIBUTES));
760c2c66affSColin Finck     pACL = (PACL)(((PBYTE)SecurityDescriptor) + SECURITY_DESCRIPTOR_MIN_LENGTH);
761c2c66affSColin Finck 
762c2c66affSColin Finck     // Initialize an EXPLICIT_ACCESS structure for an ACE.
763c2c66affSColin Finck     // The ACE will allow this thread to log off (and shut down the system, currently).
764c2c66affSColin Finck     ZeroMemory(&Access, sizeof(Access));
765c2c66affSColin Finck     Access.grfAccessPermissions = THREAD_SET_THREAD_TOKEN;
766c2c66affSColin Finck     Access.grfAccessMode = SET_ACCESS; // GRANT_ACCESS?
767c2c66affSColin Finck     Access.grfInheritance = NO_INHERITANCE;
768c2c66affSColin Finck     Access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
769c2c66affSColin Finck     Access.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
770c2c66affSColin Finck     Access.Trustee.ptstrName = pEveryoneSID;
771c2c66affSColin Finck 
772c2c66affSColin Finck     if (SetEntriesInAcl(1, &Access, NULL, &pACL) != ERROR_SUCCESS)
773c2c66affSColin Finck     {
774c2c66affSColin Finck         ERR("Failed to set Access Rights for logoff thread. Logging out will most likely fail.\n");
775c2c66affSColin Finck 
776c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, pMem);
777c2c66affSColin Finck         return STATUS_UNSUCCESSFUL;
778c2c66affSColin Finck     }
779c2c66affSColin Finck 
780c2c66affSColin Finck     if (!InitializeSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION))
781c2c66affSColin Finck     {
782c2c66affSColin Finck         ERR("Failed to initialize security descriptor for logoff thread!\n");
783c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, pMem);
784c2c66affSColin Finck         return STATUS_UNSUCCESSFUL;
785c2c66affSColin Finck     }
786c2c66affSColin Finck 
787c2c66affSColin Finck     if (!SetSecurityDescriptorDacl(SecurityDescriptor,
788c2c66affSColin Finck                                    TRUE,     // bDaclPresent flag
789c2c66affSColin Finck                                    pACL,
790c2c66affSColin Finck                                    FALSE))   // not a default DACL
791c2c66affSColin Finck     {
792c2c66affSColin Finck         ERR("SetSecurityDescriptorDacl Error %lu\n", GetLastError());
793c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, pMem);
794c2c66affSColin Finck         return STATUS_UNSUCCESSFUL;
795c2c66affSColin Finck     }
796c2c66affSColin Finck 
797c2c66affSColin Finck     psa->nLength = sizeof(SECURITY_ATTRIBUTES);
798c2c66affSColin Finck     psa->lpSecurityDescriptor = SecurityDescriptor;
799c2c66affSColin Finck     psa->bInheritHandle = FALSE;
800c2c66affSColin Finck 
801c2c66affSColin Finck     *ppsa = psa;
802c2c66affSColin Finck 
803c2c66affSColin Finck     return STATUS_SUCCESS;
804c2c66affSColin Finck }
805c2c66affSColin Finck 
806c2c66affSColin Finck static
807c2c66affSColin Finck VOID
808c2c66affSColin Finck DestroyLogoffSecurityAttributes(
809c2c66affSColin Finck     IN PSECURITY_ATTRIBUTES psa)
810c2c66affSColin Finck {
811c2c66affSColin Finck     if (psa)
812c2c66affSColin Finck     {
813c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, psa);
814c2c66affSColin Finck     }
815c2c66affSColin Finck }
816c2c66affSColin Finck 
817c2c66affSColin Finck 
818c2c66affSColin Finck static
819c2c66affSColin Finck NTSTATUS
820c2c66affSColin Finck HandleLogoff(
821c2c66affSColin Finck     IN OUT PWLSESSION Session,
822c2c66affSColin Finck     IN UINT Flags)
823c2c66affSColin Finck {
824c2c66affSColin Finck     PLOGOFF_SHUTDOWN_DATA LSData;
825c2c66affSColin Finck     PSECURITY_ATTRIBUTES psa;
826c2c66affSColin Finck     HANDLE hThread;
827c2c66affSColin Finck     DWORD exitCode;
828c2c66affSColin Finck     NTSTATUS Status;
829c2c66affSColin Finck 
830c2c66affSColin Finck     /* Prepare data for logoff thread */
831c2c66affSColin Finck     LSData = HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA));
832c2c66affSColin Finck     if (!LSData)
833c2c66affSColin Finck     {
834c2c66affSColin Finck         ERR("Failed to allocate mem for thread data\n");
835c2c66affSColin Finck         return STATUS_NO_MEMORY;
836c2c66affSColin Finck     }
837c2c66affSColin Finck     LSData->Flags = Flags;
838c2c66affSColin Finck     LSData->Session = Session;
839c2c66affSColin Finck 
840c2c66affSColin Finck     Status = CreateLogoffSecurityAttributes(&psa);
841c2c66affSColin Finck     if (!NT_SUCCESS(Status))
842c2c66affSColin Finck     {
843c2c66affSColin Finck         ERR("Failed to create a required security descriptor. Status 0x%08lx\n", Status);
844c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, LSData);
845c2c66affSColin Finck         return Status;
846c2c66affSColin Finck     }
847c2c66affSColin Finck 
848c2c66affSColin Finck     /* Run logoff thread */
849c2c66affSColin Finck     hThread = CreateThread(psa, 0, LogoffShutdownThread, (LPVOID)LSData, 0, NULL);
850c2c66affSColin Finck     if (!hThread)
851c2c66affSColin Finck     {
852c2c66affSColin Finck         ERR("Unable to create logoff thread, error %lu\n", GetLastError());
853c2c66affSColin Finck         DestroyLogoffSecurityAttributes(psa);
854c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, LSData);
855c2c66affSColin Finck         return STATUS_UNSUCCESSFUL;
856c2c66affSColin Finck     }
857c2c66affSColin Finck     WaitForSingleObject(hThread, INFINITE);
858c2c66affSColin Finck     if (!GetExitCodeThread(hThread, &exitCode))
859c2c66affSColin Finck     {
860c2c66affSColin Finck         ERR("Unable to get exit code of logoff thread (error %lu)\n", GetLastError());
861c2c66affSColin Finck         CloseHandle(hThread);
862c2c66affSColin Finck         DestroyLogoffSecurityAttributes(psa);
863c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, LSData);
864c2c66affSColin Finck         return STATUS_UNSUCCESSFUL;
865c2c66affSColin Finck     }
866c2c66affSColin Finck     CloseHandle(hThread);
867c2c66affSColin Finck     if (exitCode == 0)
868c2c66affSColin Finck     {
869c2c66affSColin Finck         ERR("Logoff thread returned failure\n");
870c2c66affSColin Finck         DestroyLogoffSecurityAttributes(psa);
871c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, LSData);
872c2c66affSColin Finck         return STATUS_UNSUCCESSFUL;
873c2c66affSColin Finck     }
874c2c66affSColin Finck 
875c2c66affSColin Finck     SwitchDesktop(Session->WinlogonDesktop);
876c2c66affSColin Finck 
87702eee253SHermès Bélusca-Maïto     // TODO: Play logoff sound!
87802eee253SHermès Bélusca-Maïto 
87902eee253SHermès Bélusca-Maïto     SetWindowStationUser(Session->InteractiveWindowStation,
88002eee253SHermès Bélusca-Maïto                          &LuidNone, NULL, 0);
88102eee253SHermès Bélusca-Maïto 
882c2c66affSColin Finck     // DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_LOGGINGOFF);
883c2c66affSColin Finck 
884c2c66affSColin Finck     // FIXME: Closing network connections!
885c2c66affSColin Finck     // DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_CLOSINGNETWORKCONNECTIONS);
886c2c66affSColin Finck 
887c2c66affSColin Finck     /* Kill remaining COM apps. Only at logoff! */
888c2c66affSColin Finck     hThread = CreateThread(psa, 0, KillComProcesses, (LPVOID)LSData, 0, NULL);
889c2c66affSColin Finck     if (hThread)
890c2c66affSColin Finck     {
891c2c66affSColin Finck         WaitForSingleObject(hThread, INFINITE);
892c2c66affSColin Finck         CloseHandle(hThread);
893c2c66affSColin Finck     }
894c2c66affSColin Finck 
895c2c66affSColin Finck     /* We're done with the SECURITY_DESCRIPTOR */
896c2c66affSColin Finck     DestroyLogoffSecurityAttributes(psa);
897c2c66affSColin Finck     psa = NULL;
898c2c66affSColin Finck 
899c2c66affSColin Finck     HeapFree(GetProcessHeap(), 0, LSData);
900c2c66affSColin Finck 
901c2c66affSColin Finck     DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_SAVEYOURSETTINGS);
902c2c66affSColin Finck 
903c2c66affSColin Finck     UnloadUserProfile(Session->UserToken, Session->hProfileInfo);
904c2c66affSColin Finck 
905c2c66affSColin Finck     CallNotificationDlls(Session, LogoffHandler);
906c2c66affSColin Finck 
907c2c66affSColin Finck     CloseHandle(Session->UserToken);
908c2c66affSColin Finck     UpdatePerUserSystemParameters(0, FALSE);
909c2c66affSColin Finck     Session->LogonState = STATE_LOGGED_OFF;
910c2c66affSColin Finck     Session->UserToken = NULL;
911c2c66affSColin Finck 
912c2c66affSColin Finck     return STATUS_SUCCESS;
913c2c66affSColin Finck }
914c2c66affSColin Finck 
915c2c66affSColin Finck static
916c2c66affSColin Finck INT_PTR
917c2c66affSColin Finck CALLBACK
918c2c66affSColin Finck ShutdownComputerWindowProc(
919c2c66affSColin Finck     IN HWND hwndDlg,
920c2c66affSColin Finck     IN UINT uMsg,
921c2c66affSColin Finck     IN WPARAM wParam,
922c2c66affSColin Finck     IN LPARAM lParam)
923c2c66affSColin Finck {
924c2c66affSColin Finck     UNREFERENCED_PARAMETER(lParam);
925c2c66affSColin Finck 
926c2c66affSColin Finck     switch (uMsg)
927c2c66affSColin Finck     {
928c2c66affSColin Finck         case WM_COMMAND:
929c2c66affSColin Finck         {
930c2c66affSColin Finck             switch (LOWORD(wParam))
931c2c66affSColin Finck             {
932c2c66affSColin Finck                 case IDC_BTNSHTDOWNCOMPUTER:
933c2c66affSColin Finck                     EndDialog(hwndDlg, IDC_BTNSHTDOWNCOMPUTER);
934c2c66affSColin Finck                     return TRUE;
935c2c66affSColin Finck             }
936c2c66affSColin Finck             break;
937c2c66affSColin Finck         }
938c2c66affSColin Finck         case WM_INITDIALOG:
939c2c66affSColin Finck         {
940c2c66affSColin Finck             RemoveMenu(GetSystemMenu(hwndDlg, FALSE), SC_CLOSE, MF_BYCOMMAND);
941c2c66affSColin Finck             SetFocus(GetDlgItem(hwndDlg, IDC_BTNSHTDOWNCOMPUTER));
942c2c66affSColin Finck             return TRUE;
943c2c66affSColin Finck         }
944c2c66affSColin Finck     }
945c2c66affSColin Finck     return FALSE;
946c2c66affSColin Finck }
947c2c66affSColin Finck 
948c2c66affSColin Finck static
949c2c66affSColin Finck VOID
950c2c66affSColin Finck UninitializeSAS(
951c2c66affSColin Finck     IN OUT PWLSESSION Session)
952c2c66affSColin Finck {
953c2c66affSColin Finck     if (Session->SASWindow)
954c2c66affSColin Finck     {
955c2c66affSColin Finck         DestroyWindow(Session->SASWindow);
956c2c66affSColin Finck         Session->SASWindow = NULL;
957c2c66affSColin Finck     }
958c2c66affSColin Finck     if (Session->hEndOfScreenSaverThread)
959c2c66affSColin Finck         SetEvent(Session->hEndOfScreenSaverThread);
960c2c66affSColin Finck     UnregisterClassW(WINLOGON_SAS_CLASS, hAppInstance);
961c2c66affSColin Finck }
962c2c66affSColin Finck 
963c2c66affSColin Finck NTSTATUS
964c2c66affSColin Finck HandleShutdown(
965c2c66affSColin Finck     IN OUT PWLSESSION Session,
966c2c66affSColin Finck     IN DWORD wlxAction)
967c2c66affSColin Finck {
968c2c66affSColin Finck     PLOGOFF_SHUTDOWN_DATA LSData;
969c2c66affSColin Finck     HANDLE hThread;
970c2c66affSColin Finck     DWORD exitCode;
971c2c66affSColin Finck     BOOLEAN Old;
972c2c66affSColin Finck 
973c2c66affSColin Finck     // SwitchDesktop(Session->WinlogonDesktop);
9745f033392SArnav Bhatt 
9755f033392SArnav Bhatt     /* If the system is rebooting, show the appropriate string */
9765f033392SArnav Bhatt     if (wlxAction == WLX_SAS_ACTION_SHUTDOWN_REBOOT)
9775f033392SArnav Bhatt         DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_REACTOSISRESTARTING);
9785f033392SArnav Bhatt     else
979c2c66affSColin Finck         DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_REACTOSISSHUTTINGDOWN);
980c2c66affSColin Finck 
981c2c66affSColin Finck     /* Prepare data for shutdown thread */
982c2c66affSColin Finck     LSData = HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA));
983c2c66affSColin Finck     if (!LSData)
984c2c66affSColin Finck     {
985c2c66affSColin Finck         ERR("Failed to allocate mem for thread data\n");
986c2c66affSColin Finck         return STATUS_NO_MEMORY;
987c2c66affSColin Finck     }
988c2c66affSColin Finck     if (wlxAction == WLX_SAS_ACTION_SHUTDOWN_POWER_OFF)
989c2c66affSColin Finck         LSData->Flags = EWX_POWEROFF;
990c2c66affSColin Finck     else if (wlxAction == WLX_SAS_ACTION_SHUTDOWN_REBOOT)
991c2c66affSColin Finck         LSData->Flags = EWX_REBOOT;
992c2c66affSColin Finck     else
993c2c66affSColin Finck         LSData->Flags = EWX_SHUTDOWN;
994c2c66affSColin Finck     LSData->Session = Session;
995c2c66affSColin Finck 
996c2c66affSColin Finck     // FIXME: We may need to specify this flag to really force application kill
997c2c66affSColin Finck     // (we are shutting down ReactOS, not just logging off so no hangs, etc...
998c2c66affSColin Finck     // should be allowed).
999c2c66affSColin Finck     // LSData->Flags |= EWX_FORCE;
1000c2c66affSColin Finck 
1001c2c66affSColin Finck     /* Run shutdown thread */
1002c2c66affSColin Finck     hThread = CreateThread(NULL, 0, LogoffShutdownThread, (LPVOID)LSData, 0, NULL);
1003c2c66affSColin Finck     if (!hThread)
1004c2c66affSColin Finck     {
1005c2c66affSColin Finck         ERR("Unable to create shutdown thread, error %lu\n", GetLastError());
1006c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, LSData);
1007c2c66affSColin Finck         return STATUS_UNSUCCESSFUL;
1008c2c66affSColin Finck     }
1009c2c66affSColin Finck     WaitForSingleObject(hThread, INFINITE);
1010c2c66affSColin Finck     HeapFree(GetProcessHeap(), 0, LSData);
1011c2c66affSColin Finck     if (!GetExitCodeThread(hThread, &exitCode))
1012c2c66affSColin Finck     {
1013c2c66affSColin Finck         ERR("Unable to get exit code of shutdown thread (error %lu)\n", GetLastError());
1014c2c66affSColin Finck         CloseHandle(hThread);
1015c2c66affSColin Finck         return STATUS_UNSUCCESSFUL;
1016c2c66affSColin Finck     }
1017c2c66affSColin Finck     CloseHandle(hThread);
1018c2c66affSColin Finck     if (exitCode == 0)
1019c2c66affSColin Finck     {
1020c2c66affSColin Finck         ERR("Shutdown thread returned failure\n");
1021c2c66affSColin Finck         return STATUS_UNSUCCESSFUL;
1022c2c66affSColin Finck     }
1023c2c66affSColin Finck 
1024c2c66affSColin Finck     CallNotificationDlls(Session, ShutdownHandler);
1025c2c66affSColin Finck 
1026c2c66affSColin Finck     /* Destroy SAS window */
1027c2c66affSColin Finck     UninitializeSAS(Session);
1028c2c66affSColin Finck 
1029c2c66affSColin Finck     /* Now we can shut down NT */
1030c2c66affSColin Finck     ERR("Shutting down NT...\n");
1031c2c66affSColin Finck     RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &Old);
1032c2c66affSColin Finck     if (wlxAction == WLX_SAS_ACTION_SHUTDOWN_REBOOT)
1033c2c66affSColin Finck     {
1034c2c66affSColin Finck         NtShutdownSystem(ShutdownReboot);
1035c2c66affSColin Finck     }
1036c2c66affSColin Finck     else
1037c2c66affSColin Finck     {
1038c2c66affSColin Finck         if (FALSE)
1039c2c66affSColin Finck         {
1040c2c66affSColin Finck             /* FIXME - only show this dialog if it's a shutdown and the computer doesn't support APM */
1041c2c66affSColin Finck             DialogBox(hAppInstance, MAKEINTRESOURCE(IDD_SHUTDOWNCOMPUTER),
1042c2c66affSColin Finck                       GetDesktopWindow(), ShutdownComputerWindowProc);
1043c2c66affSColin Finck         }
1044c2c66affSColin Finck         NtShutdownSystem(ShutdownNoReboot);
1045c2c66affSColin Finck     }
1046c2c66affSColin Finck     RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, Old, FALSE, &Old);
1047c2c66affSColin Finck     return STATUS_SUCCESS;
1048c2c66affSColin Finck }
1049c2c66affSColin Finck 
1050c2c66affSColin Finck static
1051c2c66affSColin Finck VOID
1052c2c66affSColin Finck DoGenericAction(
1053c2c66affSColin Finck     IN OUT PWLSESSION Session,
1054c2c66affSColin Finck     IN DWORD wlxAction)
1055c2c66affSColin Finck {
1056c2c66affSColin Finck     switch (wlxAction)
1057c2c66affSColin Finck     {
1058c2c66affSColin Finck         case WLX_SAS_ACTION_LOGON: /* 0x01 */
1059c2c66affSColin Finck             if (Session->LogonState == STATE_LOGGED_OFF_SAS)
1060c2c66affSColin Finck             {
1061c2c66affSColin Finck                 if (!HandleLogon(Session))
1062c2c66affSColin Finck                 {
1063c2c66affSColin Finck                     Session->Gina.Functions.WlxDisplaySASNotice(Session->Gina.Context);
1064c2c66affSColin Finck                     CallNotificationDlls(Session, LogonHandler);
1065c2c66affSColin Finck                 }
1066c2c66affSColin Finck             }
1067c2c66affSColin Finck             break;
1068c2c66affSColin Finck         case WLX_SAS_ACTION_NONE: /* 0x02 */
1069c2c66affSColin Finck             if (Session->LogonState == STATE_LOGGED_OFF_SAS)
1070c2c66affSColin Finck             {
1071c2c66affSColin Finck                 Session->LogonState = STATE_LOGGED_OFF;
1072c2c66affSColin Finck                 Session->Gina.Functions.WlxDisplaySASNotice(Session->Gina.Context);
1073c2c66affSColin Finck             }
1074c2c66affSColin Finck             else if (Session->LogonState == STATE_LOGGED_ON_SAS)
1075c2c66affSColin Finck             {
1076c2c66affSColin Finck                 Session->LogonState = STATE_LOGGED_ON;
1077c2c66affSColin Finck             }
1078c2c66affSColin Finck             else if (Session->LogonState == STATE_LOCKED_SAS)
1079c2c66affSColin Finck             {
1080c2c66affSColin Finck                 Session->LogonState = STATE_LOCKED;
1081c2c66affSColin Finck                 Session->Gina.Functions.WlxDisplayLockedNotice(Session->Gina.Context);
1082c2c66affSColin Finck             }
1083c2c66affSColin Finck             break;
1084c2c66affSColin Finck         case WLX_SAS_ACTION_LOCK_WKSTA: /* 0x03 */
1085c2c66affSColin Finck             if (Session->Gina.Functions.WlxIsLockOk(Session->Gina.Context))
1086c2c66affSColin Finck             {
1087c2c66affSColin Finck                 SwitchDesktop(Session->WinlogonDesktop);
1088c2c66affSColin Finck                 Session->LogonState = STATE_LOCKED;
1089c2c66affSColin Finck                 Session->Gina.Functions.WlxDisplayLockedNotice(Session->Gina.Context);
1090c2c66affSColin Finck                 CallNotificationDlls(Session, LockHandler);
1091c2c66affSColin Finck             }
1092c2c66affSColin Finck             break;
1093c2c66affSColin Finck         case WLX_SAS_ACTION_LOGOFF: /* 0x04 */
1094c2c66affSColin Finck         case WLX_SAS_ACTION_SHUTDOWN: /* 0x05 */
1095c2c66affSColin Finck         case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF: /* 0x0a */
1096c2c66affSColin Finck         case WLX_SAS_ACTION_SHUTDOWN_REBOOT: /* 0x0b */
1097c2c66affSColin Finck             if (Session->LogonState != STATE_LOGGED_OFF)
1098c2c66affSColin Finck             {
1099c2c66affSColin Finck                 if (!Session->Gina.Functions.WlxIsLogoffOk(Session->Gina.Context))
1100c2c66affSColin Finck                     break;
1101c2c66affSColin Finck                 if (!NT_SUCCESS(HandleLogoff(Session, EWX_LOGOFF)))
1102c2c66affSColin Finck                 {
1103c2c66affSColin Finck                     RemoveStatusMessage(Session);
1104c2c66affSColin Finck                     break;
1105c2c66affSColin Finck                 }
1106c2c66affSColin Finck                 Session->Gina.Functions.WlxLogoff(Session->Gina.Context);
1107c2c66affSColin Finck             }
1108c2c66affSColin Finck             if (WLX_SHUTTINGDOWN(wlxAction))
1109c2c66affSColin Finck             {
1110c2c66affSColin Finck                 // FIXME: WlxShutdown should be done from inside HandleShutdown,
1111c2c66affSColin Finck                 // after having displayed "ReactOS is shutting down" message.
1112c2c66affSColin Finck                 Session->Gina.Functions.WlxShutdown(Session->Gina.Context, wlxAction);
1113c2c66affSColin Finck                 if (!NT_SUCCESS(HandleShutdown(Session, wlxAction)))
1114c2c66affSColin Finck                 {
1115c2c66affSColin Finck                     RemoveStatusMessage(Session);
1116c2c66affSColin Finck                     Session->Gina.Functions.WlxDisplaySASNotice(Session->Gina.Context);
1117c2c66affSColin Finck                 }
1118c2c66affSColin Finck             }
1119c2c66affSColin Finck             else
1120c2c66affSColin Finck             {
1121c2c66affSColin Finck                 RemoveStatusMessage(Session);
1122c2c66affSColin Finck                 Session->Gina.Functions.WlxDisplaySASNotice(Session->Gina.Context);
1123c2c66affSColin Finck             }
1124c2c66affSColin Finck             break;
1125c2c66affSColin Finck         case WLX_SAS_ACTION_TASKLIST: /* 0x07 */
1126c2c66affSColin Finck             SwitchDesktop(Session->ApplicationDesktop);
1127c2c66affSColin Finck             Session->LogonState = STATE_LOGGED_ON;
1128c2c66affSColin Finck             StartTaskManager(Session);
1129c2c66affSColin Finck             break;
1130c2c66affSColin Finck         case WLX_SAS_ACTION_UNLOCK_WKSTA: /* 0x08 */
1131c2c66affSColin Finck             SwitchDesktop(Session->ApplicationDesktop);
1132c2c66affSColin Finck             Session->LogonState = STATE_LOGGED_ON;
1133c2c66affSColin Finck             CallNotificationDlls(Session, UnlockHandler);
1134c2c66affSColin Finck             break;
1135c2c66affSColin Finck         default:
1136c2c66affSColin Finck             WARN("Unknown SAS action 0x%lx\n", wlxAction);
1137c2c66affSColin Finck     }
1138c2c66affSColin Finck }
1139c2c66affSColin Finck 
1140c2c66affSColin Finck static
1141c2c66affSColin Finck VOID
1142c2c66affSColin Finck DispatchSAS(
1143c2c66affSColin Finck     IN OUT PWLSESSION Session,
1144c2c66affSColin Finck     IN DWORD dwSasType)
1145c2c66affSColin Finck {
1146c2c66affSColin Finck     DWORD wlxAction = WLX_SAS_ACTION_NONE;
1147c2c66affSColin Finck     PSID LogonSid = NULL; /* FIXME */
1148c2c66affSColin Finck     BOOL bSecure = TRUE;
1149c2c66affSColin Finck 
1150c2c66affSColin Finck     switch (dwSasType)
1151c2c66affSColin Finck     {
1152c2c66affSColin Finck         case WLX_SAS_TYPE_CTRL_ALT_DEL:
1153c2c66affSColin Finck             switch (Session->LogonState)
1154c2c66affSColin Finck             {
1155c2c66affSColin Finck                 case STATE_INIT:
1156c2c66affSColin Finck                     Session->LogonState = STATE_LOGGED_OFF;
1157c2c66affSColin Finck                     Session->Gina.Functions.WlxDisplaySASNotice(Session->Gina.Context);
1158c2c66affSColin Finck                     return;
1159c2c66affSColin Finck 
1160c2c66affSColin Finck                 case STATE_LOGGED_OFF:
1161c2c66affSColin Finck                     Session->LogonState = STATE_LOGGED_OFF_SAS;
1162c2c66affSColin Finck 
116302f3cb53SEric Kohl                     CloseAllDialogWindows();
1164c2c66affSColin Finck 
1165c2c66affSColin Finck                     Session->Options = 0;
1166c2c66affSColin Finck 
1167c2c66affSColin Finck                     wlxAction = (DWORD)Session->Gina.Functions.WlxLoggedOutSAS(
1168c2c66affSColin Finck                         Session->Gina.Context,
1169c2c66affSColin Finck                         Session->SASAction,
1170c2c66affSColin Finck                         &Session->LogonId,
1171c2c66affSColin Finck                         LogonSid,
1172c2c66affSColin Finck                         &Session->Options,
1173c2c66affSColin Finck                         &Session->UserToken,
1174c2c66affSColin Finck                         &Session->MprNotifyInfo,
1175c2c66affSColin Finck                         (PVOID*)&Session->Profile);
1176c2c66affSColin Finck                     break;
1177c2c66affSColin Finck 
1178c2c66affSColin Finck                 case STATE_LOGGED_OFF_SAS:
1179c2c66affSColin Finck                     /* Ignore SAS if we are already in an SAS state */
1180c2c66affSColin Finck                     return;
1181c2c66affSColin Finck 
1182c2c66affSColin Finck                 case STATE_LOGGED_ON:
1183c2c66affSColin Finck                     Session->LogonState = STATE_LOGGED_ON_SAS;
1184c2c66affSColin Finck                     wlxAction = (DWORD)Session->Gina.Functions.WlxLoggedOnSAS(Session->Gina.Context, dwSasType, NULL);
1185c2c66affSColin Finck                     break;
1186c2c66affSColin Finck 
1187c2c66affSColin Finck                 case STATE_LOGGED_ON_SAS:
1188c2c66affSColin Finck                     /* Ignore SAS if we are already in an SAS state */
1189c2c66affSColin Finck                     return;
1190c2c66affSColin Finck 
1191c2c66affSColin Finck                 case STATE_LOCKED:
1192c2c66affSColin Finck                     Session->LogonState = STATE_LOCKED_SAS;
1193c2c66affSColin Finck 
119402f3cb53SEric Kohl                     CloseAllDialogWindows();
1195c2c66affSColin Finck 
1196c2c66affSColin Finck                     wlxAction = (DWORD)Session->Gina.Functions.WlxWkstaLockedSAS(Session->Gina.Context, dwSasType);
1197c2c66affSColin Finck                     break;
1198c2c66affSColin Finck 
1199c2c66affSColin Finck                 case STATE_LOCKED_SAS:
1200c2c66affSColin Finck                     /* Ignore SAS if we are already in an SAS state */
1201c2c66affSColin Finck                     return;
1202c2c66affSColin Finck 
1203c2c66affSColin Finck                 default:
1204c2c66affSColin Finck                     return;
1205c2c66affSColin Finck             }
1206c2c66affSColin Finck             break;
1207c2c66affSColin Finck 
1208c2c66affSColin Finck         case WLX_SAS_TYPE_TIMEOUT:
1209c2c66affSColin Finck             return;
1210c2c66affSColin Finck 
1211c2c66affSColin Finck         case WLX_SAS_TYPE_SCRNSVR_TIMEOUT:
1212c2c66affSColin Finck             if (!Session->Gina.Functions.WlxScreenSaverNotify(Session->Gina.Context, &bSecure))
1213c2c66affSColin Finck             {
1214c2c66affSColin Finck                 /* Skip start of screen saver */
1215c2c66affSColin Finck                 SetEvent(Session->hEndOfScreenSaver);
1216c2c66affSColin Finck             }
1217c2c66affSColin Finck             else
1218c2c66affSColin Finck             {
1219c2c66affSColin Finck                 StartScreenSaver(Session);
1220c2c66affSColin Finck                 if (bSecure)
1221c2c66affSColin Finck                 {
1222c2c66affSColin Finck                     wlxAction = WLX_SAS_ACTION_LOCK_WKSTA;
1223c2c66affSColin Finck //                    DoGenericAction(Session, WLX_SAS_ACTION_LOCK_WKSTA);
1224c2c66affSColin Finck                 }
1225c2c66affSColin Finck             }
1226c2c66affSColin Finck             break;
1227c2c66affSColin Finck 
1228c2c66affSColin Finck         case WLX_SAS_TYPE_SCRNSVR_ACTIVITY:
1229c2c66affSColin Finck             SetEvent(Session->hUserActivity);
1230c2c66affSColin Finck             break;
1231c2c66affSColin Finck     }
1232c2c66affSColin Finck 
1233c2c66affSColin Finck     DoGenericAction(Session, wlxAction);
1234c2c66affSColin Finck }
1235c2c66affSColin Finck 
1236c2c66affSColin Finck static
1237c2c66affSColin Finck BOOL
1238c2c66affSColin Finck RegisterHotKeys(
1239c2c66affSColin Finck     IN PWLSESSION Session,
1240c2c66affSColin Finck     IN HWND hwndSAS)
1241c2c66affSColin Finck {
1242c2c66affSColin Finck     /* Register Ctrl+Alt+Del Hotkey */
1243c2c66affSColin Finck     if (!RegisterHotKey(hwndSAS, HK_CTRL_ALT_DEL, MOD_CONTROL | MOD_ALT, VK_DELETE))
1244c2c66affSColin Finck     {
1245c2c66affSColin Finck         ERR("WL: Unable to register Ctrl+Alt+Del hotkey!\n");
1246c2c66affSColin Finck         return FALSE;
1247c2c66affSColin Finck     }
1248c2c66affSColin Finck 
1249c2c66affSColin Finck     /* Register Ctrl+Shift+Esc (optional) */
1250c2c66affSColin Finck     Session->TaskManHotkey = RegisterHotKey(hwndSAS, HK_CTRL_SHIFT_ESC, MOD_CONTROL | MOD_SHIFT, VK_ESCAPE);
1251c2c66affSColin Finck     if (!Session->TaskManHotkey)
1252c2c66affSColin Finck         WARN("WL: Warning: Unable to register Ctrl+Alt+Esc hotkey!\n");
1253c2c66affSColin Finck     return TRUE;
1254c2c66affSColin Finck }
1255c2c66affSColin Finck 
1256c2c66affSColin Finck static
1257c2c66affSColin Finck BOOL
1258c2c66affSColin Finck UnregisterHotKeys(
1259c2c66affSColin Finck     IN PWLSESSION Session,
1260c2c66affSColin Finck     IN HWND hwndSAS)
1261c2c66affSColin Finck {
1262c2c66affSColin Finck     /* Unregister hotkeys */
1263c2c66affSColin Finck     UnregisterHotKey(hwndSAS, HK_CTRL_ALT_DEL);
1264c2c66affSColin Finck 
1265c2c66affSColin Finck     if (Session->TaskManHotkey)
1266c2c66affSColin Finck         UnregisterHotKey(hwndSAS, HK_CTRL_SHIFT_ESC);
1267c2c66affSColin Finck 
1268c2c66affSColin Finck     return TRUE;
1269c2c66affSColin Finck }
1270c2c66affSColin Finck 
1271c2c66affSColin Finck BOOL
1272c2c66affSColin Finck WINAPI
1273c2c66affSColin Finck HandleMessageBeep(UINT uType)
1274c2c66affSColin Finck {
1275c2c66affSColin Finck     LPWSTR EventName;
1276c2c66affSColin Finck 
1277c2c66affSColin Finck     switch(uType)
1278c2c66affSColin Finck     {
1279c2c66affSColin Finck     case 0xFFFFFFFF:
1280c2c66affSColin Finck         EventName = NULL;
1281c2c66affSColin Finck         break;
1282c2c66affSColin Finck     case MB_OK:
1283c2c66affSColin Finck         EventName = L"SystemDefault";
1284c2c66affSColin Finck         break;
1285c2c66affSColin Finck     case MB_ICONASTERISK:
1286c2c66affSColin Finck         EventName = L"SystemAsterisk";
1287c2c66affSColin Finck         break;
1288c2c66affSColin Finck     case MB_ICONEXCLAMATION:
1289c2c66affSColin Finck         EventName = L"SystemExclamation";
1290c2c66affSColin Finck         break;
1291c2c66affSColin Finck     case MB_ICONHAND:
1292c2c66affSColin Finck         EventName = L"SystemHand";
1293c2c66affSColin Finck         break;
1294c2c66affSColin Finck     case MB_ICONQUESTION:
1295c2c66affSColin Finck         EventName = L"SystemQuestion";
1296c2c66affSColin Finck         break;
1297c2c66affSColin Finck     default:
1298c2c66affSColin Finck         WARN("Unhandled type %d\n", uType);
1299c2c66affSColin Finck         EventName = L"SystemDefault";
1300c2c66affSColin Finck     }
1301c2c66affSColin Finck 
1302c2c66affSColin Finck     return PlaySoundRoutine(EventName, FALSE, SND_ALIAS | SND_NOWAIT | SND_NOSTOP | SND_ASYNC);
1303c2c66affSColin Finck }
1304c2c66affSColin Finck 
1305c2c66affSColin Finck static
1306c2c66affSColin Finck LRESULT
1307c2c66affSColin Finck CALLBACK
1308c2c66affSColin Finck SASWindowProc(
1309c2c66affSColin Finck     IN HWND hwndDlg,
1310c2c66affSColin Finck     IN UINT uMsg,
1311c2c66affSColin Finck     IN WPARAM wParam,
1312c2c66affSColin Finck     IN LPARAM lParam)
1313c2c66affSColin Finck {
1314c2c66affSColin Finck     PWLSESSION Session = (PWLSESSION)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
1315c2c66affSColin Finck 
1316c2c66affSColin Finck     switch (uMsg)
1317c2c66affSColin Finck     {
1318c2c66affSColin Finck         case WM_HOTKEY:
1319c2c66affSColin Finck         {
1320c2c66affSColin Finck             switch (lParam)
1321c2c66affSColin Finck             {
1322c2c66affSColin Finck                 case MAKELONG(MOD_CONTROL | MOD_ALT, VK_DELETE):
1323c2c66affSColin Finck                 {
1324c2c66affSColin Finck                     TRACE("SAS: CONTROL+ALT+DELETE\n");
1325c2c66affSColin Finck                     if (!Session->Gina.UseCtrlAltDelete)
1326c2c66affSColin Finck                         break;
1327c2c66affSColin Finck                     PostMessageW(Session->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_CTRL_ALT_DEL, 0);
1328c2c66affSColin Finck                     return TRUE;
1329c2c66affSColin Finck                 }
1330c2c66affSColin Finck                 case MAKELONG(MOD_CONTROL | MOD_SHIFT, VK_ESCAPE):
1331c2c66affSColin Finck                 {
1332c2c66affSColin Finck                     TRACE("SAS: CONTROL+SHIFT+ESCAPE\n");
133346dcab7aSEric Kohl                     if (Session->LogonState == STATE_LOGGED_ON)
1334c2c66affSColin Finck                         DoGenericAction(Session, WLX_SAS_ACTION_TASKLIST);
1335c2c66affSColin Finck                     return TRUE;
1336c2c66affSColin Finck                 }
1337c2c66affSColin Finck             }
1338c2c66affSColin Finck             break;
1339c2c66affSColin Finck         }
1340c2c66affSColin Finck         case WM_CREATE:
1341c2c66affSColin Finck         {
1342c2c66affSColin Finck             /* Get the session pointer from the create data */
1343c2c66affSColin Finck             Session = (PWLSESSION)((LPCREATESTRUCT)lParam)->lpCreateParams;
1344c2c66affSColin Finck 
1345c2c66affSColin Finck             /* Save the Session pointer */
1346c2c66affSColin Finck             SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (LONG_PTR)Session);
1347c2c66affSColin Finck             if (GetSetupType())
1348c2c66affSColin Finck                 return TRUE;
1349c2c66affSColin Finck             return RegisterHotKeys(Session, hwndDlg);
1350c2c66affSColin Finck         }
1351c2c66affSColin Finck         case WM_DESTROY:
1352c2c66affSColin Finck         {
1353c2c66affSColin Finck             if (!GetSetupType())
1354c2c66affSColin Finck                 UnregisterHotKeys(Session, hwndDlg);
1355c2c66affSColin Finck             return TRUE;
1356c2c66affSColin Finck         }
1357c2c66affSColin Finck         case WM_SETTINGCHANGE:
1358c2c66affSColin Finck         {
1359c2c66affSColin Finck             UINT uiAction = (UINT)wParam;
1360c2c66affSColin Finck             if (uiAction == SPI_SETSCREENSAVETIMEOUT
1361c2c66affSColin Finck              || uiAction == SPI_SETSCREENSAVEACTIVE)
1362c2c66affSColin Finck             {
1363c2c66affSColin Finck                 SetEvent(Session->hScreenSaverParametersChanged);
1364c2c66affSColin Finck             }
1365c2c66affSColin Finck             return TRUE;
1366c2c66affSColin Finck         }
1367c2c66affSColin Finck         case WM_LOGONNOTIFY:
1368c2c66affSColin Finck         {
1369c2c66affSColin Finck             switch(wParam)
1370c2c66affSColin Finck             {
1371c2c66affSColin Finck                 case LN_MESSAGE_BEEP:
1372c2c66affSColin Finck                 {
1373c2c66affSColin Finck                     return HandleMessageBeep(lParam);
1374c2c66affSColin Finck                 }
1375c2c66affSColin Finck                 case LN_SHELL_EXITED:
1376c2c66affSColin Finck                 {
1377c2c66affSColin Finck                     /* lParam is the exit code */
13781f0fe386SEric Kohl                     if (lParam != 1 &&
13791f0fe386SEric Kohl                         Session->LogonState != STATE_LOGGED_OFF &&
13801f0fe386SEric Kohl                         Session->LogonState != STATE_LOGGED_OFF_SAS)
1381c2c66affSColin Finck                     {
1382c2c66affSColin Finck                         SetTimer(hwndDlg, 1, 1000, NULL);
1383c2c66affSColin Finck                     }
1384c2c66affSColin Finck                     break;
1385c2c66affSColin Finck                 }
1386c2c66affSColin Finck                 case LN_START_SCREENSAVE:
1387c2c66affSColin Finck                 {
1388c2c66affSColin Finck                     DispatchSAS(Session, WLX_SAS_TYPE_SCRNSVR_TIMEOUT);
1389c2c66affSColin Finck                     break;
1390c2c66affSColin Finck                 }
1391c2c66affSColin Finck                 case LN_LOCK_WORKSTATION:
1392c2c66affSColin Finck                 {
1393c2c66affSColin Finck                     DoGenericAction(Session, WLX_SAS_ACTION_LOCK_WKSTA);
1394c2c66affSColin Finck                     break;
1395c2c66affSColin Finck                 }
1396c2c66affSColin Finck                 case LN_LOGOFF:
1397c2c66affSColin Finck                 {
1398c2c66affSColin Finck                     UINT Flags = (UINT)lParam;
1399c2c66affSColin Finck                     UINT Action = Flags & EWX_ACTION_MASK;
1400c2c66affSColin Finck                     DWORD wlxAction;
1401c2c66affSColin Finck 
1402c2c66affSColin Finck                     TRACE("\tFlags : 0x%lx\n", lParam);
1403c2c66affSColin Finck 
1404c2c66affSColin Finck                     /*
1405c2c66affSColin Finck                      * Our caller (USERSRV) should have added the shutdown flag
1406c2c66affSColin Finck                      * when setting also poweroff or reboot.
1407c2c66affSColin Finck                      */
1408c2c66affSColin Finck                     if (Action & (EWX_POWEROFF | EWX_REBOOT))
1409c2c66affSColin Finck                     {
1410c2c66affSColin Finck                         if ((Action & EWX_SHUTDOWN) == 0)
1411c2c66affSColin Finck                         {
1412c2c66affSColin Finck                             ERR("Missing EWX_SHUTDOWN flag for poweroff or reboot; action 0x%x\n", Action);
1413c2c66affSColin Finck                             return STATUS_INVALID_PARAMETER;
1414c2c66affSColin Finck                         }
1415c2c66affSColin Finck 
1416c2c66affSColin Finck                         /* Now we can locally remove it for performing checks */
1417c2c66affSColin Finck                         Action &= ~EWX_SHUTDOWN;
1418c2c66affSColin Finck                     }
1419c2c66affSColin Finck 
1420c2c66affSColin Finck                     /* Check parameters */
1421c2c66affSColin Finck                     if (Action & EWX_FORCE)
1422c2c66affSColin Finck                     {
1423c2c66affSColin Finck                         // FIXME!
1424c2c66affSColin Finck                         ERR("FIXME: EWX_FORCE present for Winlogon, what to do?\n");
1425c2c66affSColin Finck                         Action &= ~EWX_FORCE;
1426c2c66affSColin Finck                     }
1427c2c66affSColin Finck                     switch (Action)
1428c2c66affSColin Finck                     {
1429c2c66affSColin Finck                         case EWX_LOGOFF:
1430c2c66affSColin Finck                             wlxAction = WLX_SAS_ACTION_LOGOFF;
1431c2c66affSColin Finck                             break;
1432c2c66affSColin Finck                         case EWX_SHUTDOWN:
1433c2c66affSColin Finck                             wlxAction = WLX_SAS_ACTION_SHUTDOWN;
1434c2c66affSColin Finck                             break;
1435c2c66affSColin Finck                         case EWX_REBOOT:
1436c2c66affSColin Finck                             wlxAction = WLX_SAS_ACTION_SHUTDOWN_REBOOT;
1437c2c66affSColin Finck                             break;
1438c2c66affSColin Finck                         case EWX_POWEROFF:
1439c2c66affSColin Finck                             wlxAction = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF;
1440c2c66affSColin Finck                             break;
1441c2c66affSColin Finck 
1442c2c66affSColin Finck                         default:
1443c2c66affSColin Finck                         {
1444c2c66affSColin Finck                             ERR("Invalid ExitWindows action 0x%x\n", Action);
1445c2c66affSColin Finck                             return STATUS_INVALID_PARAMETER;
1446c2c66affSColin Finck                         }
1447c2c66affSColin Finck                     }
1448c2c66affSColin Finck 
1449c2c66affSColin Finck                     TRACE("In LN_LOGOFF, exit_in_progress == %s\n",
1450c2c66affSColin Finck                         ExitReactOSInProgress ? "true" : "false");
1451c2c66affSColin Finck 
1452c2c66affSColin Finck                     /*
1453c2c66affSColin Finck                      * In case a parallel shutdown request is done (while we are
1454c2c66affSColin Finck                      * being to shut down) and it was not done by Winlogon itself,
1455c2c66affSColin Finck                      * then just stop here.
1456c2c66affSColin Finck                      */
1457c2c66affSColin Finck #if 0
1458c2c66affSColin Finck // This code is commented at the moment (even if it's correct) because
1459c2c66affSColin Finck // our log-offs do not really work: the shell is restarted, no app is killed
1460c2c66affSColin Finck // etc... and as a result you just get explorer opening "My Documents". And
1461c2c66affSColin Finck // if you try now a shut down, it won't work because winlogon thinks it is
1462c2c66affSColin Finck // still in the middle of a shutdown.
1463c2c66affSColin Finck // Maybe we also need to reset ExitReactOSInProgress somewhere else??
1464c2c66affSColin Finck                     if (ExitReactOSInProgress && (lParam & EWX_CALLER_WINLOGON) == 0)
1465c2c66affSColin Finck                     {
1466c2c66affSColin Finck                         break;
1467c2c66affSColin Finck                     }
1468c2c66affSColin Finck #endif
1469c2c66affSColin Finck                     /* Now do the shutdown action proper */
1470c2c66affSColin Finck                     DoGenericAction(Session, wlxAction);
1471c2c66affSColin Finck                     return 1;
1472c2c66affSColin Finck                 }
1473c2c66affSColin Finck                 case LN_LOGOFF_CANCELED:
1474c2c66affSColin Finck                 {
1475c2c66affSColin Finck                     ERR("Logoff canceled!!, before: exit_in_progress == %s, after will be false\n",
1476c2c66affSColin Finck                         ExitReactOSInProgress ? "true" : "false");
1477c2c66affSColin Finck 
1478c2c66affSColin Finck                     ExitReactOSInProgress = FALSE;
1479c2c66affSColin Finck                     return 1;
1480c2c66affSColin Finck                 }
1481c2c66affSColin Finck                 default:
1482c2c66affSColin Finck                 {
1483c2c66affSColin Finck                     ERR("WM_LOGONNOTIFY case %d is unimplemented\n", wParam);
1484c2c66affSColin Finck                 }
1485c2c66affSColin Finck             }
1486c2c66affSColin Finck             return 0;
1487c2c66affSColin Finck         }
1488c2c66affSColin Finck         case WM_TIMER:
1489c2c66affSColin Finck         {
1490c2c66affSColin Finck             if (wParam == 1)
1491c2c66affSColin Finck             {
1492c2c66affSColin Finck                 KillTimer(hwndDlg, 1);
1493c2c66affSColin Finck                 StartUserShell(Session);
1494c2c66affSColin Finck             }
1495c2c66affSColin Finck             break;
1496c2c66affSColin Finck         }
1497c2c66affSColin Finck         case WLX_WM_SAS:
1498c2c66affSColin Finck         {
1499c2c66affSColin Finck             DispatchSAS(Session, (DWORD)wParam);
1500c2c66affSColin Finck             return TRUE;
1501c2c66affSColin Finck         }
1502c2c66affSColin Finck     }
1503c2c66affSColin Finck 
1504c2c66affSColin Finck     return DefWindowProc(hwndDlg, uMsg, wParam, lParam);
1505c2c66affSColin Finck }
1506c2c66affSColin Finck 
1507c2c66affSColin Finck BOOL
1508c2c66affSColin Finck InitializeSAS(
1509c2c66affSColin Finck     IN OUT PWLSESSION Session)
1510c2c66affSColin Finck {
1511c2c66affSColin Finck     WNDCLASSEXW swc;
1512c2c66affSColin Finck     BOOL ret = FALSE;
1513c2c66affSColin Finck 
1514c2c66affSColin Finck     if (!SwitchDesktop(Session->WinlogonDesktop))
1515c2c66affSColin Finck     {
1516c2c66affSColin Finck         ERR("WL: Failed to switch to winlogon desktop\n");
1517c2c66affSColin Finck         goto cleanup;
1518c2c66affSColin Finck     }
1519c2c66affSColin Finck 
1520c2c66affSColin Finck     /* Register SAS window class */
1521c2c66affSColin Finck     swc.cbSize = sizeof(WNDCLASSEXW);
1522c2c66affSColin Finck     swc.style = CS_SAVEBITS;
1523c2c66affSColin Finck     swc.lpfnWndProc = SASWindowProc;
1524c2c66affSColin Finck     swc.cbClsExtra = 0;
1525c2c66affSColin Finck     swc.cbWndExtra = 0;
1526c2c66affSColin Finck     swc.hInstance = hAppInstance;
1527c2c66affSColin Finck     swc.hIcon = NULL;
1528c2c66affSColin Finck     swc.hCursor = NULL;
1529c2c66affSColin Finck     swc.hbrBackground = NULL;
1530c2c66affSColin Finck     swc.lpszMenuName = NULL;
1531c2c66affSColin Finck     swc.lpszClassName = WINLOGON_SAS_CLASS;
1532c2c66affSColin Finck     swc.hIconSm = NULL;
1533c2c66affSColin Finck     if (RegisterClassExW(&swc) == 0)
1534c2c66affSColin Finck     {
1535c2c66affSColin Finck         ERR("WL: Failed to register SAS window class\n");
1536c2c66affSColin Finck         goto cleanup;
1537c2c66affSColin Finck     }
1538c2c66affSColin Finck 
1539c2c66affSColin Finck     /* Create invisible SAS window */
1540c2c66affSColin Finck     Session->SASWindow = CreateWindowExW(
1541c2c66affSColin Finck         0,
1542c2c66affSColin Finck         WINLOGON_SAS_CLASS,
1543c2c66affSColin Finck         WINLOGON_SAS_TITLE,
1544c2c66affSColin Finck         WS_POPUP,
1545c2c66affSColin Finck         0, 0, 0, 0, 0, 0,
1546c2c66affSColin Finck         hAppInstance, Session);
1547c2c66affSColin Finck     if (!Session->SASWindow)
1548c2c66affSColin Finck     {
1549c2c66affSColin Finck         ERR("WL: Failed to create SAS window\n");
1550c2c66affSColin Finck         goto cleanup;
1551c2c66affSColin Finck     }
1552c2c66affSColin Finck 
1553c2c66affSColin Finck     /* Register SAS window to receive SAS notifications */
1554c2c66affSColin Finck     if (!SetLogonNotifyWindow(Session->SASWindow))
1555c2c66affSColin Finck     {
1556c2c66affSColin Finck         ERR("WL: Failed to register SAS window\n");
1557c2c66affSColin Finck         goto cleanup;
1558c2c66affSColin Finck     }
1559c2c66affSColin Finck 
1560c2c66affSColin Finck     if (!SetDefaultLanguage(NULL))
1561c2c66affSColin Finck         return FALSE;
1562c2c66affSColin Finck 
1563c2c66affSColin Finck     ret = TRUE;
1564c2c66affSColin Finck 
1565c2c66affSColin Finck cleanup:
1566c2c66affSColin Finck     if (!ret)
1567c2c66affSColin Finck         UninitializeSAS(Session);
1568c2c66affSColin Finck     return ret;
1569c2c66affSColin Finck }
1570