[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 if (!CreateWindowStationAndDesktops(WLSession))
338 {
339 ERR("WL: Could not create window station and desktops\n");
340 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
341 ExitProcess(1);
342 }
343
344 LockWorkstation(WLSession);
345
346 /* Load default keyboard layouts */
347 if (!InitKeyboardLayouts())
348 {
349 ERR("WL: Could not preload keyboard layouts\n");
350 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
351 ExitProcess(1);
352 }
353
354 if (!StartServicesManager())
355 {
356 ERR("WL: Could not start services.exe\n");
357 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
358 ExitProcess(1);
359 }
360
361 if (!StartLsass())
362 {
363 ERR("WL: Failed to start lsass.exe service (error %lu)\n", GetLastError());
364 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, 0, OptionOk, &HardErrorResponse);
365 ExitProcess(1);
366 }
367
368 /* Wait for the LSA server */
369 WaitForLsass();
370
371 /* Load and initialize gina */
372 if (!GinaInit(WLSession))
373 {
374 ERR("WL: Failed to initialize Gina\n");
375 DialogBoxParam(hAppInstance, MAKEINTRESOURCE(IDD_GINALOADFAILED), GetDesktopWindow(), GinaLoadFailedWindowProc, (LPARAM)L"");
376 HandleShutdown(WLSession, WLX_SAS_ACTION_SHUTDOWN_REBOOT);
377 ExitProcess(1);
378 }
379
380 DisplayStatusMessage(WLSession, WLSession->WinlogonDesktop, IDS_REACTOSISSTARTINGUP);
381
382 #if 0
383 /* Connect to NetLogon service (lsass.exe) */
384 /* Real winlogon uses "Winlogon" */
385 RtlInitUnicodeString((PUNICODE_STRING)&ProcessName, L"Winlogon");
386 Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
387 if (Status == STATUS_PORT_CONNECTION_REFUSED)
388 {
389 /* Add the 'SeTcbPrivilege' privilege and try again */
390 Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, TRUE, &Old);
391 if (!NT_SUCCESS(Status))
392 {
393 ERR("RtlAdjustPrivilege() failed with error %lu\n", LsaNtStatusToWinError(Status));
394 return 1;
395 }
396
397 Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
398 }
399
400 if (!NT_SUCCESS(Status))
401 {
402 ERR("LsaRegisterLogonProcess() failed with error %lu\n", LsaNtStatusToWinError(Status));
403 return 1;
404 }
405
406 RtlInitUnicodeString((PUNICODE_STRING)&PackageName, MICROSOFT_KERBEROS_NAME_W);
407 Status = LsaLookupAuthenticationPackage(LsaHandle, &PackageName, &AuthenticationPackage);
408 if (!NT_SUCCESS(Status))
409 {
410 ERR("LsaLookupAuthenticationPackage() failed with error %lu\n", LsaNtStatusToWinError(Status));
411 LsaDeregisterLogonProcess(LsaHandle);
412 return 1;
413 }
414 #endif
415
416 /* Create a hidden window to get SAS notifications */
417 if (!InitializeSAS(WLSession))
418 {
419 ERR("WL: Failed to initialize SAS\n");
420 ExitProcess(2);
421 }
422
423 //DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_PREPARENETWORKCONNECTIONS);
424 //DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_APPLYINGCOMPUTERSETTINGS);
425
426 /* Display logged out screen */
427 WLSession->LogonState = STATE_LOGGED_OFF;
428 RemoveStatusMessage(WLSession);
429
430 /* Check for pending setup */
431 if (GetSetupType() != 0)
432 {
433 TRACE("WL: Setup mode detected\n");
434
435 /* Run setup and reboot when done */
436 SwitchDesktop(WLSession->ApplicationDesktop);
437 RunSetup();
438 }
439 else
440 PostMessageW(WLSession->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_TIMEOUT, 0);
441
442 /* Tell kernel that CurrentControlSet is good (needed
443 * to support Last good known configuration boot) */
444 NtInitializeRegistry(CM_BOOT_FLAG_ACCEPTED | 1);
445
446 /* Message loop for the SAS window */
447 while (GetMessageW(&Msg, WLSession->SASWindow, 0, 0))
448 {
449 TranslateMessage(&Msg);
450 DispatchMessageW(&Msg);
451 }
452
453 /* We never go there */
454
455 return 0;
456 }