- Synchronize up to trunk's revision r57864.
[reactos.git] / base / system / winlogon / winlogon.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Winlogon
4 * FILE: base/system/winlogon/winlogon.c
5 * PURPOSE: Logon
6 * PROGRAMMERS: Thomas Weidenmueller (w3seek@users.sourceforge.net)
7 * Filip Navara
8 * Hervé Poussineau (hpoussin@reactos.org)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include "winlogon.h"
14
15 #include <wine/debug.h>
16
17 WINE_DEFAULT_DEBUG_CHANNEL(winlogon);
18
19 /* GLOBALS ******************************************************************/
20
21 HINSTANCE hAppInstance;
22 PWLSESSION WLSession = NULL;
23
24 /* FUNCTIONS *****************************************************************/
25
26 static BOOL
27 StartServicesManager(VOID)
28 {
29 STARTUPINFOW StartupInfo;
30 PROCESS_INFORMATION ProcessInformation;
31 LPCWSTR ServiceString = L"services.exe";
32 BOOL res;
33
34 /* Start the service control manager (services.exe) */
35 ZeroMemory(&StartupInfo, sizeof(STARTUPINFOW));
36 StartupInfo.cb = sizeof(StartupInfo);
37 StartupInfo.lpReserved = NULL;
38 StartupInfo.lpDesktop = NULL;
39 StartupInfo.lpTitle = NULL;
40 StartupInfo.dwFlags = 0;
41 StartupInfo.cbReserved2 = 0;
42 StartupInfo.lpReserved2 = 0;
43
44 TRACE("WL: Creating new process - %S\n", ServiceString);
45
46 res = CreateProcessW(
47 ServiceString,
48 NULL,
49 NULL,
50 NULL,
51 FALSE,
52 DETACHED_PROCESS,
53 NULL,
54 NULL,
55 &StartupInfo,
56 &ProcessInformation);
57 if (!res)
58 {
59 ERR("WL: Failed to execute services (error %lu)\n", GetLastError());
60 return FALSE;
61 }
62
63 TRACE("WL: Created new process - %S\n", ServiceString);
64
65 CloseHandle(ProcessInformation.hThread);
66 CloseHandle(ProcessInformation.hProcess);
67
68 TRACE("WL: StartServicesManager() done.\n");
69
70 return TRUE;
71 }
72
73
74 static BOOL
75 StartLsass(VOID)
76 {
77 STARTUPINFOW StartupInfo;
78 PROCESS_INFORMATION ProcessInformation;
79 LPCWSTR ServiceString = L"lsass.exe";
80 BOOL res;
81
82 /* Start the local security authority subsystem (lsass.exe) */
83 ZeroMemory(&StartupInfo, sizeof(STARTUPINFOW));
84 StartupInfo.cb = sizeof(StartupInfo);
85 StartupInfo.lpReserved = NULL;
86 StartupInfo.lpDesktop = NULL;
87 StartupInfo.lpTitle = NULL;
88 StartupInfo.dwFlags = 0;
89 StartupInfo.cbReserved2 = 0;
90 StartupInfo.lpReserved2 = 0;
91
92 TRACE("WL: Creating new process - %S\n", ServiceString);
93
94 res = CreateProcessW(
95 ServiceString,
96 NULL,
97 NULL,
98 NULL,
99 FALSE,
100 DETACHED_PROCESS,
101 NULL,
102 NULL,
103 &StartupInfo,
104 &ProcessInformation);
105
106 TRACE("WL: Created new process - %S\n", ServiceString);
107
108 CloseHandle(ProcessInformation.hThread);
109 CloseHandle(ProcessInformation.hProcess);
110
111 return res;
112 }
113
114
115 static VOID
116 WaitForLsass(VOID)
117 {
118 HANDLE hEvent;
119 DWORD dwError;
120
121 hEvent = CreateEventW(NULL,
122 TRUE,
123 FALSE,
124 L"LSA_RPC_SERVER_ACTIVE");
125 if (hEvent == NULL)
126 {
127 dwError = GetLastError();
128 TRACE("WL: Failed to create the notication event (Error %lu)\n", dwError);
129
130 if (dwError == ERROR_ALREADY_EXISTS)
131 {
132 hEvent = OpenEventW(SYNCHRONIZE,
133 FALSE,
134 L"LSA_RPC_SERVER_ACTIVE");
135 if (hEvent == NULL)
136 {
137 ERR("WL: Could not open the notification event (Error %lu)\n", GetLastError());
138 return;
139 }
140 }
141 }
142
143 TRACE("WL: Wait for the LSA server!\n");
144 WaitForSingleObject(hEvent, INFINITE);
145 TRACE("WL: LSA server running!\n");
146
147 CloseHandle(hEvent);
148 }
149
150
151 static BOOL
152 InitKeyboardLayouts()
153 {
154 WCHAR wszKeyName[12], wszKLID[10];
155 DWORD dwSize = sizeof(wszKLID), dwType, i = 1;
156 HKEY hKey;
157 UINT Flags;
158 BOOL bRet = FALSE;
159
160 /* Open registry key with preloaded layouts */
161 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
162 {
163 while(TRUE)
164 {
165 /* Read values with integer names only */
166 swprintf(wszKeyName, L"%d", i++);
167 if (RegQueryValueExW(hKey, wszKeyName, NULL, &dwType, (LPBYTE)wszKLID, &dwSize) != ERROR_SUCCESS)
168 {
169 /* There is no more entries */
170 break;
171 }
172
173 /* Only REG_SZ values are valid */
174 if (dwType != REG_SZ)
175 {
176 ERR("Wrong type: %ws!\n", wszKLID);
177 continue;
178 }
179
180 /* Load keyboard layout with given locale id */
181 Flags = KLF_SUBSTITUTE_OK;
182 if (i > 1)
183 Flags |= KLF_NOTELLSHELL|KLF_REPLACELANG;
184 else // First layout
185 Flags |= KLF_ACTIVATE; // |0x40000000
186 if (!LoadKeyboardLayoutW(wszKLID, Flags))
187 {
188 ERR("LoadKeyboardLayoutW(%ws) failed!\n", wszKLID);
189 continue;
190 }
191 else
192 {
193 /* We loaded at least one layout - success */
194 bRet = TRUE;
195 }
196 }
197
198 /* Close the key now */
199 RegCloseKey(hKey);
200 }
201 else
202 WARN("RegOpenKeyExW(Keyboard Layout\\Preload) failed!\n");
203
204 if (!bRet)
205 {
206 /* If we failed, load US keyboard layout */
207 if (LoadKeyboardLayoutW(L"00000409", 0x04090409))
208 bRet = TRUE;
209 }
210
211 return bRet;
212 }
213
214
215 BOOL
216 DisplayStatusMessage(
217 IN PWLSESSION Session,
218 IN HDESK hDesktop,
219 IN UINT ResourceId)
220 {
221 WCHAR StatusMsg[MAX_PATH];
222
223 if (Session->Gina.Version < WLX_VERSION_1_3)
224 return TRUE;
225
226 if (Session->SuppressStatus)
227 return TRUE;
228
229 if (LoadStringW(hAppInstance, ResourceId, StatusMsg, MAX_PATH) == 0)
230 return FALSE;
231
232 return Session->Gina.Functions.WlxDisplayStatusMessage(Session->Gina.Context, hDesktop, 0, NULL, StatusMsg);
233 }
234
235 BOOL
236 RemoveStatusMessage(
237 IN PWLSESSION Session)
238 {
239 if (Session->Gina.Version < WLX_VERSION_1_3)
240 return TRUE;
241
242 return Session->Gina.Functions.WlxRemoveStatusMessage(Session->Gina.Context);
243 }
244
245 static INT_PTR CALLBACK
246 GinaLoadFailedWindowProc(
247 IN HWND hwndDlg,
248 IN UINT uMsg,
249 IN WPARAM wParam,
250 IN LPARAM lParam)
251 {
252 switch (uMsg)
253 {
254 case WM_COMMAND:
255 {
256 switch (LOWORD(wParam))
257 {
258 case IDOK:
259 EndDialog(hwndDlg, IDOK);
260 return TRUE;
261 }
262 break;
263 }
264 case WM_INITDIALOG:
265 {
266 int len;
267 WCHAR templateText[MAX_PATH], text[MAX_PATH];
268
269 len = GetDlgItemTextW(hwndDlg, IDC_GINALOADFAILED, templateText, MAX_PATH);
270 if (len)
271 {
272 wsprintfW(text, templateText, (LPWSTR)lParam);
273 SetDlgItemTextW(hwndDlg, IDC_GINALOADFAILED, text);
274 }
275 SetFocus(GetDlgItem(hwndDlg, IDOK));
276 return TRUE;
277 }
278 case WM_CLOSE:
279 {
280 EndDialog(hwndDlg, IDCANCEL);
281 return TRUE;
282 }
283 }
284
285 return FALSE;
286 }
287
288 int WINAPI
289 WinMain(
290 IN HINSTANCE hInstance,
291 IN HINSTANCE hPrevInstance,
292 IN LPSTR lpCmdLine,
293 IN int nShowCmd)
294 {
295 #if 0
296 LSA_STRING ProcessName, PackageName;
297 HANDLE LsaHandle;
298 LSA_OPERATIONAL_MODE Mode;
299 BOOLEAN Old;
300 ULONG AuthenticationPackage;
301 NTSTATUS Status;
302 #endif
303 ULONG HardErrorResponse;
304 MSG Msg;
305
306 UNREFERENCED_PARAMETER(hPrevInstance);
307 UNREFERENCED_PARAMETER(lpCmdLine);
308 UNREFERENCED_PARAMETER(nShowCmd);
309
310 hAppInstance = hInstance;
311
312 if (!RegisterLogonProcess(GetCurrentProcessId(), TRUE))
313 {
314 ERR("WL: Could not register logon process\n");
315 NtShutdownSystem(ShutdownNoReboot);
316 ExitProcess(0);
317 }
318
319 WLSession = (PWLSESSION)HeapAlloc(GetProcessHeap(), 0, sizeof(WLSESSION));
320 if (!WLSession)
321 {
322 ERR("WL: Could not allocate memory for winlogon instance\n");
323 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
324 ExitProcess(1);
325 }
326 ZeroMemory(WLSession, sizeof(WLSESSION));
327 WLSession->DialogTimeout = 120; /* 2 minutes */
328
329 if (!CreateWindowStationAndDesktops(WLSession))
330 {
331 ERR("WL: Could not create window station and desktops\n");
332 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
333 ExitProcess(1);
334 }
335 LockWorkstation(WLSession);
336
337 /* Load default keyboard layouts */
338 if (!InitKeyboardLayouts())
339 {
340 ERR("WL: Could not preload keyboard layouts\n");
341 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
342 ExitProcess(1);
343 }
344
345 if (!StartServicesManager())
346 {
347 ERR("WL: Could not start services.exe\n");
348 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
349 ExitProcess(1);
350 }
351
352 if (!StartLsass())
353 {
354 ERR("WL: Failed to start lsass.exe service (error %lu)\n", GetLastError());
355 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, 0, OptionOk, &HardErrorResponse);
356 ExitProcess(1);
357 }
358
359 /* Load and initialize gina */
360 if (!GinaInit(WLSession))
361 {
362 ERR("WL: Failed to initialize Gina\n");
363 DialogBoxParam(hAppInstance, MAKEINTRESOURCE(IDD_GINALOADFAILED), GetDesktopWindow(), GinaLoadFailedWindowProc, (LPARAM)L"");
364 HandleShutdown(WLSession, WLX_SAS_ACTION_SHUTDOWN_REBOOT);
365 ExitProcess(1);
366 }
367
368 DisplayStatusMessage(WLSession, WLSession->WinlogonDesktop, IDS_REACTOSISSTARTINGUP);
369
370
371 /* Wait for the LSA server */
372 WaitForLsass();
373
374 #if 0
375 /* Connect to NetLogon service (lsass.exe) */
376 /* Real winlogon uses "Winlogon" */
377 RtlInitUnicodeString((PUNICODE_STRING)&ProcessName, L"Winlogon");
378 Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
379 if (Status == STATUS_PORT_CONNECTION_REFUSED)
380 {
381 /* Add the 'SeTcbPrivilege' privilege and try again */
382 Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, TRUE, &Old);
383 if (!NT_SUCCESS(Status))
384 {
385 ERR("RtlAdjustPrivilege() failed with error %lu\n", LsaNtStatusToWinError(Status));
386 return 1;
387 }
388 Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
389 }
390 if (!NT_SUCCESS(Status))
391 {
392 ERR("LsaRegisterLogonProcess() failed with error %lu\n", LsaNtStatusToWinError(Status));
393 return 1;
394 }
395
396 RtlInitUnicodeString((PUNICODE_STRING)&PackageName, MICROSOFT_KERBEROS_NAME_W);
397 Status = LsaLookupAuthenticationPackage(LsaHandle, &PackageName, &AuthenticationPackage);
398 if (!NT_SUCCESS(Status))
399 {
400 ERR("LsaLookupAuthenticationPackage() failed with error %lu\n", LsaNtStatusToWinError(Status));
401 LsaDeregisterLogonProcess(LsaHandle);
402 return 1;
403 }
404 #endif
405
406 /* Create a hidden window to get SAS notifications */
407 if (!InitializeSAS(WLSession))
408 {
409 ERR("WL: Failed to initialize SAS\n");
410 ExitProcess(2);
411 }
412
413 //DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_PREPARENETWORKCONNECTIONS);
414 //DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_APPLYINGCOMPUTERSETTINGS);
415
416 /* Display logged out screen */
417 WLSession->LogonStatus = WKSTA_IS_LOGGED_OFF;
418 RemoveStatusMessage(WLSession);
419
420 /* Check for pending setup */
421 if (GetSetupType() != 0)
422 {
423 TRACE("WL: Setup mode detected\n");
424
425 /* Run setup and reboot when done */
426 SwitchDesktop(WLSession->ApplicationDesktop);
427 RunSetup();
428 }
429 else
430 PostMessageW(WLSession->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_TIMEOUT, 0);
431
432 /* Tell kernel that CurrentControlSet is good (needed
433 * to support Last good known configuration boot) */
434 NtInitializeRegistry(CM_BOOT_FLAG_ACCEPTED | 1);
435
436 /* Message loop for the SAS window */
437 while (GetMessageW(&Msg, WLSession->SASWindow, 0, 0))
438 {
439 TranslateMessage(&Msg);
440 DispatchMessageW(&Msg);
441 }
442
443 /* We never go there */
444
445 return 0;
446 }