26219343000ae405e2fe715d5dbf595d6ee3e6b8
[reactos.git] / reactos / 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 <ndk/cmfuncs.h>
16
17 /* GLOBALS ******************************************************************/
18
19 HINSTANCE hAppInstance;
20 PWLSESSION WLSession = NULL;
21
22 /* FUNCTIONS *****************************************************************/
23
24 static
25 BOOL
26 StartServicesManager(VOID)
27 {
28 STARTUPINFOW StartupInfo;
29 PROCESS_INFORMATION ProcessInformation;
30 LPCWSTR ServiceString = L"services.exe";
31 BOOL res;
32
33 /* Start the service control manager (services.exe) */
34 ZeroMemory(&StartupInfo, sizeof(STARTUPINFOW));
35 StartupInfo.cb = sizeof(StartupInfo);
36 StartupInfo.lpReserved = NULL;
37 StartupInfo.lpDesktop = NULL;
38 StartupInfo.lpTitle = NULL;
39 StartupInfo.dwFlags = 0;
40 StartupInfo.cbReserved2 = 0;
41 StartupInfo.lpReserved2 = 0;
42
43 TRACE("WL: Creating new process - %S\n", ServiceString);
44
45 res = CreateProcessW(ServiceString,
46 NULL,
47 NULL,
48 NULL,
49 FALSE,
50 DETACHED_PROCESS,
51 NULL,
52 NULL,
53 &StartupInfo,
54 &ProcessInformation);
55 if (!res)
56 {
57 ERR("WL: Failed to execute services (error %lu)\n", GetLastError());
58 return FALSE;
59 }
60
61 TRACE("WL: Created new process - %S\n", ServiceString);
62
63 CloseHandle(ProcessInformation.hThread);
64 CloseHandle(ProcessInformation.hProcess);
65
66 TRACE("WL: StartServicesManager() done.\n");
67
68 return TRUE;
69 }
70
71
72 static
73 BOOL
74 StartLsass(VOID)
75 {
76 STARTUPINFOW StartupInfo;
77 PROCESS_INFORMATION ProcessInformation;
78 LPCWSTR ServiceString = L"lsass.exe";
79 BOOL res;
80
81 /* Start the local security authority subsystem (lsass.exe) */
82 ZeroMemory(&StartupInfo, sizeof(STARTUPINFOW));
83 StartupInfo.cb = sizeof(StartupInfo);
84 StartupInfo.lpReserved = NULL;
85 StartupInfo.lpDesktop = NULL;
86 StartupInfo.lpTitle = NULL;
87 StartupInfo.dwFlags = 0;
88 StartupInfo.cbReserved2 = 0;
89 StartupInfo.lpReserved2 = 0;
90
91 TRACE("WL: Creating new process - %S\n", ServiceString);
92
93 res = CreateProcessW(ServiceString,
94 NULL,
95 NULL,
96 NULL,
97 FALSE,
98 DETACHED_PROCESS,
99 NULL,
100 NULL,
101 &StartupInfo,
102 &ProcessInformation);
103
104 TRACE("WL: Created new process - %S\n", ServiceString);
105
106 CloseHandle(ProcessInformation.hThread);
107 CloseHandle(ProcessInformation.hProcess);
108
109 return res;
110 }
111
112
113 static
114 VOID
115 WaitForLsass(VOID)
116 {
117 HANDLE hEvent;
118 DWORD dwError;
119
120 hEvent = CreateEventW(NULL,
121 TRUE,
122 FALSE,
123 L"LSA_RPC_SERVER_ACTIVE");
124 if (hEvent == NULL)
125 {
126 dwError = GetLastError();
127 TRACE("WL: Failed to create the notication event (Error %lu)\n", dwError);
128
129 if (dwError == ERROR_ALREADY_EXISTS)
130 {
131 hEvent = OpenEventW(SYNCHRONIZE,
132 FALSE,
133 L"LSA_RPC_SERVER_ACTIVE");
134 if (hEvent == NULL)
135 {
136 ERR("WL: Could not open the notification event (Error %lu)\n", GetLastError());
137 return;
138 }
139 }
140 }
141
142 TRACE("WL: Wait for the LSA server!\n");
143 WaitForSingleObject(hEvent, INFINITE);
144 TRACE("WL: LSA server running!\n");
145
146 CloseHandle(hEvent);
147 }
148
149
150 static
151 BOOL
152 InitKeyboardLayouts(VOID)
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
236 BOOL
237 RemoveStatusMessage(
238 IN PWLSESSION Session)
239 {
240 if (Session->Gina.Version < WLX_VERSION_1_3)
241 return TRUE;
242
243 return Session->Gina.Functions.WlxRemoveStatusMessage(Session->Gina.Context);
244 }
245
246
247 static
248 INT_PTR
249 CALLBACK
250 GinaLoadFailedWindowProc(
251 IN HWND hwndDlg,
252 IN UINT uMsg,
253 IN WPARAM wParam,
254 IN LPARAM lParam)
255 {
256 switch (uMsg)
257 {
258 case WM_COMMAND:
259 {
260 switch (LOWORD(wParam))
261 {
262 case IDOK:
263 EndDialog(hwndDlg, IDOK);
264 return TRUE;
265 }
266 break;
267 }
268
269 case WM_INITDIALOG:
270 {
271 int len;
272 WCHAR templateText[MAX_PATH], text[MAX_PATH];
273
274 len = GetDlgItemTextW(hwndDlg, IDC_GINALOADFAILED, templateText, MAX_PATH);
275 if (len)
276 {
277 wsprintfW(text, templateText, (LPWSTR)lParam);
278 SetDlgItemTextW(hwndDlg, IDC_GINALOADFAILED, text);
279 }
280
281 SetFocus(GetDlgItem(hwndDlg, IDOK));
282 return TRUE;
283 }
284
285 case WM_CLOSE:
286 {
287 EndDialog(hwndDlg, IDCANCEL);
288 return TRUE;
289 }
290 }
291
292 return FALSE;
293 }
294
295
296 int
297 WINAPI
298 WinMain(
299 IN HINSTANCE hInstance,
300 IN HINSTANCE hPrevInstance,
301 IN LPSTR lpCmdLine,
302 IN int nShowCmd)
303 {
304 #if 0
305 LSA_STRING ProcessName, PackageName;
306 HANDLE LsaHandle;
307 LSA_OPERATIONAL_MODE Mode;
308 BOOLEAN Old;
309 ULONG AuthenticationPackage;
310 NTSTATUS Status;
311 #endif
312 ULONG HardErrorResponse;
313 MSG Msg;
314
315 UNREFERENCED_PARAMETER(hPrevInstance);
316 UNREFERENCED_PARAMETER(lpCmdLine);
317 UNREFERENCED_PARAMETER(nShowCmd);
318
319 hAppInstance = hInstance;
320
321 /* Make us critical */
322 RtlSetProcessIsCritical(TRUE, NULL, FALSE);
323 RtlSetThreadIsCritical(TRUE, NULL, FALSE);
324
325 if (!RegisterLogonProcess(GetCurrentProcessId(), TRUE))
326 {
327 ERR("WL: Could not register logon process\n");
328 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
329 ExitProcess(1);
330 }
331
332 WLSession = (PWLSESSION)HeapAlloc(GetProcessHeap(), 0, sizeof(WLSESSION));
333 if (!WLSession)
334 {
335 ERR("WL: Could not allocate memory for winlogon instance\n");
336 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
337 ExitProcess(1);
338 }
339
340 ZeroMemory(WLSession, sizeof(WLSESSION));
341 WLSession->DialogTimeout = 120; /* 2 minutes */
342
343 /* Initialize the dialog tracking list */
344 InitDialogListHead();
345
346 if (!CreateWindowStationAndDesktops(WLSession))
347 {
348 ERR("WL: Could not create window station and desktops\n");
349 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
350 ExitProcess(1);
351 }
352
353 LockWorkstation(WLSession);
354
355 /* Load default keyboard layouts */
356 if (!InitKeyboardLayouts())
357 {
358 ERR("WL: Could not preload keyboard layouts\n");
359 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
360 ExitProcess(1);
361 }
362
363 if (!StartRpcServer())
364 {
365 ERR("WL: Could not start the RPC server\n");
366 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
367 ExitProcess(1);
368 }
369
370 if (!StartServicesManager())
371 {
372 ERR("WL: Could not start services.exe\n");
373 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
374 ExitProcess(1);
375 }
376
377 if (!StartLsass())
378 {
379 ERR("WL: Failed to start lsass.exe service (error %lu)\n", GetLastError());
380 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
381 ExitProcess(1);
382 }
383
384 /* Wait for the LSA server */
385 WaitForLsass();
386
387 /* Init Notifications */
388 InitNotifications();
389
390 /* Load and initialize gina */
391 if (!GinaInit(WLSession))
392 {
393 ERR("WL: Failed to initialize Gina\n");
394 // FIXME: Retrieve the real name of the GINA DLL we were trying to load.
395 // It is known only inside the GinaInit function...
396 DialogBoxParam(hAppInstance, MAKEINTRESOURCE(IDD_GINALOADFAILED), GetDesktopWindow(), GinaLoadFailedWindowProc, (LPARAM)L"msgina.dll");
397 HandleShutdown(WLSession, WLX_SAS_ACTION_SHUTDOWN_REBOOT);
398 ExitProcess(1);
399 }
400
401 DisplayStatusMessage(WLSession, WLSession->WinlogonDesktop, IDS_REACTOSISSTARTINGUP);
402
403 #if 0
404 /* Connect to NetLogon service (lsass.exe) */
405 /* Real winlogon uses "Winlogon" */
406 RtlInitUnicodeString((PUNICODE_STRING)&ProcessName, L"Winlogon");
407 Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
408 if (Status == STATUS_PORT_CONNECTION_REFUSED)
409 {
410 /* Add the 'SeTcbPrivilege' privilege and try again */
411 Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, TRUE, &Old);
412 if (!NT_SUCCESS(Status))
413 {
414 ERR("RtlAdjustPrivilege() failed with error %lu\n", LsaNtStatusToWinError(Status));
415 return 1;
416 }
417
418 Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
419 }
420
421 if (!NT_SUCCESS(Status))
422 {
423 ERR("LsaRegisterLogonProcess() failed with error %lu\n", LsaNtStatusToWinError(Status));
424 return 1;
425 }
426
427 RtlInitUnicodeString((PUNICODE_STRING)&PackageName, MICROSOFT_KERBEROS_NAME_W);
428 Status = LsaLookupAuthenticationPackage(LsaHandle, &PackageName, &AuthenticationPackage);
429 if (!NT_SUCCESS(Status))
430 {
431 ERR("LsaLookupAuthenticationPackage() failed with error %lu\n", LsaNtStatusToWinError(Status));
432 LsaDeregisterLogonProcess(LsaHandle);
433 return 1;
434 }
435 #endif
436
437 CallNotificationDlls(WLSession, StartupHandler);
438
439 /* Create a hidden window to get SAS notifications */
440 if (!InitializeSAS(WLSession))
441 {
442 ERR("WL: Failed to initialize SAS\n");
443 ExitProcess(2);
444 }
445
446 // DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_PREPARENETWORKCONNECTIONS);
447 // DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_APPLYINGCOMPUTERSETTINGS);
448
449 /* Display logged out screen */
450 WLSession->LogonState = STATE_INIT;
451 RemoveStatusMessage(WLSession);
452
453 /* Check for pending setup */
454 if (GetSetupType() != 0)
455 {
456 TRACE("WL: Setup mode detected\n");
457
458 /* Run setup and reboot when done */
459 SwitchDesktop(WLSession->ApplicationDesktop);
460 RunSetup();
461 }
462 else
463 PostMessageW(WLSession->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_CTRL_ALT_DEL, 0);
464
465 (void)LoadLibraryW(L"sfc_os.dll");
466
467 /* Tell kernel that CurrentControlSet is good (needed
468 * to support Last good known configuration boot) */
469 NtInitializeRegistry(CM_BOOT_FLAG_ACCEPTED | 1);
470
471 /* Message loop for the SAS window */
472 while (GetMessageW(&Msg, WLSession->SASWindow, 0, 0))
473 {
474 TranslateMessage(&Msg);
475 DispatchMessageW(&Msg);
476 }
477
478 CleanupNotifications();
479
480 /* We never go there */
481
482 return 0;
483 }