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