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
StartServicesManager(VOID)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
StartLsass(VOID)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
WaitForLsass(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 notification 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 VOID
UpdateTcpIpInformation(VOID)152 UpdateTcpIpInformation(VOID)
153 {
154 LONG lError;
155 HKEY hKey = NULL;
156 DWORD dwType, dwSize;
157 PWSTR pszBuffer;
158 WCHAR szBuffer[128] = L"";
159
160 lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
161 L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
162 0,
163 KEY_QUERY_VALUE | KEY_SET_VALUE,
164 &hKey);
165 if (lError != ERROR_SUCCESS)
166 {
167 ERR("WL: RegOpenKeyExW(\"HKLM\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters\") failed (error %lu)\n", lError);
168 return;
169 }
170
171 /*
172 * Read the "NV Hostname" value and copy it into the "Hostname" value.
173 */
174
175 pszBuffer = szBuffer;
176 dwSize = ARRAYSIZE(szBuffer);
177
178 lError = RegQueryValueExW(hKey,
179 L"NV Hostname",
180 NULL,
181 &dwType,
182 (LPBYTE)pszBuffer,
183 &dwSize);
184 if (((lError == ERROR_INSUFFICIENT_BUFFER) || (lError == ERROR_MORE_DATA)) && (dwType == REG_SZ))
185 {
186 pszBuffer = HeapAlloc(GetProcessHeap(), 0, dwSize);
187 if (pszBuffer)
188 {
189 lError = RegQueryValueExW(hKey,
190 L"NV Hostname",
191 NULL,
192 &dwType,
193 (LPBYTE)pszBuffer,
194 &dwSize);
195 }
196 else
197 {
198 ERR("WL: Could not reallocate memory for pszBuffer\n");
199 }
200 }
201 if ((lError == ERROR_SUCCESS) && (dwType == REG_SZ))
202 {
203 TRACE("NV Hostname is '%S'.\n", pszBuffer);
204
205 lError = RegSetValueExW(hKey,
206 L"Hostname",
207 0,
208 REG_SZ,
209 (LPBYTE)pszBuffer,
210 dwSize);
211 if (lError != ERROR_SUCCESS)
212 ERR("WL: RegSetValueExW(\"Hostname\") failed (error %lu)\n", lError);
213 }
214
215 /*
216 * Read the "NV Domain" value and copy it into the "Domain" value.
217 */
218
219 // pszBuffer = szBuffer;
220 // dwSize = ARRAYSIZE(szBuffer);
221
222 lError = RegQueryValueExW(hKey,
223 L"NV Domain",
224 NULL,
225 &dwType,
226 (LPBYTE)pszBuffer,
227 &dwSize);
228 if (((lError == ERROR_INSUFFICIENT_BUFFER) || (lError == ERROR_MORE_DATA)) && (dwType == REG_SZ))
229 {
230 if (pszBuffer != szBuffer)
231 {
232 PWSTR pszNewBuffer;
233 pszNewBuffer = HeapReAlloc(GetProcessHeap(), 0, pszBuffer, dwSize);
234 if (pszNewBuffer)
235 {
236 pszBuffer = pszNewBuffer;
237 }
238 else
239 {
240 HeapFree(GetProcessHeap(), 0, pszBuffer);
241 pszBuffer = NULL;
242 }
243 }
244 else
245 {
246 pszBuffer = HeapAlloc(GetProcessHeap(), 0, dwSize);
247 }
248 if (pszBuffer)
249 {
250 lError = RegQueryValueExW(hKey,
251 L"NV Domain",
252 NULL,
253 &dwType,
254 (LPBYTE)pszBuffer,
255 &dwSize);
256 }
257 else
258 {
259 ERR("WL: Could not reallocate memory for pszBuffer\n");
260 }
261 }
262 if ((lError == ERROR_SUCCESS) && (dwType == REG_SZ))
263 {
264 TRACE("NV Domain is '%S'.\n", pszBuffer);
265
266 lError = RegSetValueExW(hKey,
267 L"Domain",
268 0,
269 REG_SZ,
270 (LPBYTE)pszBuffer,
271 dwSize);
272 if (lError != ERROR_SUCCESS)
273 ERR("WL: RegSetValueExW(\"Domain\") failed (error %lu)\n", lError);
274 }
275
276 if (pszBuffer != szBuffer)
277 HeapFree(GetProcessHeap(), 0, pszBuffer);
278
279 RegCloseKey(hKey);
280 }
281
282
283 static
284 BOOL
InitKeyboardLayouts(VOID)285 InitKeyboardLayouts(VOID)
286 {
287 WCHAR wszKeyName[12], wszKLID[10];
288 DWORD dwSize = sizeof(wszKLID), dwType, i = 1;
289 HKEY hKey;
290 UINT Flags;
291 BOOL bRet = FALSE;
292
293 /* Open registry key with preloaded layouts */
294 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
295 {
296 while (TRUE)
297 {
298 /* Read values with integer names only */
299 swprintf(wszKeyName, L"%d", i++);
300 if (RegQueryValueExW(hKey, wszKeyName, NULL, &dwType, (LPBYTE)wszKLID, &dwSize) != ERROR_SUCCESS)
301 {
302 /* There is no more entries */
303 break;
304 }
305
306 /* Only REG_SZ values are valid */
307 if (dwType != REG_SZ)
308 {
309 ERR("Wrong type: %ws!\n", wszKLID);
310 continue;
311 }
312
313 /* Load keyboard layout with given locale id */
314 Flags = KLF_SUBSTITUTE_OK;
315 if (i > 1)
316 Flags |= KLF_NOTELLSHELL|KLF_REPLACELANG;
317 else // First layout
318 Flags |= KLF_ACTIVATE; // |0x40000000
319 if (!LoadKeyboardLayoutW(wszKLID, Flags))
320 {
321 ERR("LoadKeyboardLayoutW(%ws) failed!\n", wszKLID);
322 continue;
323 }
324 else
325 {
326 /* We loaded at least one layout - success */
327 bRet = TRUE;
328 }
329 }
330
331 /* Close the key now */
332 RegCloseKey(hKey);
333 }
334 else
335 WARN("RegOpenKeyExW(Keyboard Layout\\Preload) failed!\n");
336
337 if (!bRet)
338 {
339 /* If we failed, load US keyboard layout */
340 if (LoadKeyboardLayoutW(L"00000409", KLF_ACTIVATE | KLF_SUBSTITUTE_OK | KLF_REPLACELANG | KLF_SETFORPROCESS))
341 bRet = TRUE;
342 }
343
344 return bRet;
345 }
346
347
348 BOOL
DisplayStatusMessage(IN PWLSESSION Session,IN HDESK hDesktop,IN UINT ResourceId)349 DisplayStatusMessage(
350 IN PWLSESSION Session,
351 IN HDESK hDesktop,
352 IN UINT ResourceId)
353 {
354 WCHAR StatusMsg[MAX_PATH];
355
356 if (Session->Gina.Version < WLX_VERSION_1_3)
357 return TRUE;
358
359 if (Session->SuppressStatus)
360 return TRUE;
361
362 if (LoadStringW(hAppInstance, ResourceId, StatusMsg, MAX_PATH) == 0)
363 return FALSE;
364
365 return Session->Gina.Functions.WlxDisplayStatusMessage(Session->Gina.Context, hDesktop, 0, NULL, StatusMsg);
366 }
367
368
369 BOOL
RemoveStatusMessage(IN PWLSESSION Session)370 RemoveStatusMessage(
371 IN PWLSESSION Session)
372 {
373 if (Session->Gina.Version < WLX_VERSION_1_3)
374 return TRUE;
375
376 return Session->Gina.Functions.WlxRemoveStatusMessage(Session->Gina.Context);
377 }
378
379
380 static
381 INT_PTR
382 CALLBACK
GinaLoadFailedWindowProc(IN HWND hwndDlg,IN UINT uMsg,IN WPARAM wParam,IN LPARAM lParam)383 GinaLoadFailedWindowProc(
384 IN HWND hwndDlg,
385 IN UINT uMsg,
386 IN WPARAM wParam,
387 IN LPARAM lParam)
388 {
389 switch (uMsg)
390 {
391 case WM_COMMAND:
392 {
393 switch (LOWORD(wParam))
394 {
395 case IDOK:
396 EndDialog(hwndDlg, IDOK);
397 return TRUE;
398 }
399 break;
400 }
401
402 case WM_INITDIALOG:
403 {
404 int len;
405 WCHAR templateText[MAX_PATH], text[MAX_PATH];
406
407 len = GetDlgItemTextW(hwndDlg, IDC_GINALOADFAILED, templateText, MAX_PATH);
408 if (len)
409 {
410 wsprintfW(text, templateText, (LPWSTR)lParam);
411 SetDlgItemTextW(hwndDlg, IDC_GINALOADFAILED, text);
412 }
413
414 SetFocus(GetDlgItem(hwndDlg, IDOK));
415 return TRUE;
416 }
417
418 case WM_CLOSE:
419 {
420 EndDialog(hwndDlg, IDCANCEL);
421 return TRUE;
422 }
423 }
424
425 return FALSE;
426 }
427
428
429 int
430 WINAPI
WinMain(IN HINSTANCE hInstance,IN HINSTANCE hPrevInstance,IN LPSTR lpCmdLine,IN int nShowCmd)431 WinMain(
432 IN HINSTANCE hInstance,
433 IN HINSTANCE hPrevInstance,
434 IN LPSTR lpCmdLine,
435 IN int nShowCmd)
436 {
437 #if 0
438 LSA_STRING ProcessName, PackageName;
439 HANDLE LsaHandle;
440 LSA_OPERATIONAL_MODE Mode;
441 BOOLEAN Old;
442 ULONG AuthenticationPackage;
443 NTSTATUS Status;
444 #endif
445 ULONG HardErrorResponse;
446 MSG Msg;
447
448 UNREFERENCED_PARAMETER(hPrevInstance);
449 UNREFERENCED_PARAMETER(lpCmdLine);
450 UNREFERENCED_PARAMETER(nShowCmd);
451
452 hAppInstance = hInstance;
453
454 /* Make us critical */
455 RtlSetProcessIsCritical(TRUE, NULL, FALSE);
456 RtlSetThreadIsCritical(TRUE, NULL, FALSE);
457
458 /* Update the cached TCP/IP Information in the registry */
459 UpdateTcpIpInformation();
460
461 if (!RegisterLogonProcess(GetCurrentProcessId(), TRUE))
462 {
463 ERR("WL: Could not register logon process\n");
464 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
465 ExitProcess(1);
466 }
467
468 WLSession = (PWLSESSION)HeapAlloc(GetProcessHeap(), 0, sizeof(WLSESSION));
469 if (!WLSession)
470 {
471 ERR("WL: Could not allocate memory for winlogon instance\n");
472 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
473 ExitProcess(1);
474 }
475
476 ZeroMemory(WLSession, sizeof(WLSESSION));
477 WLSession->DialogTimeout = 120; /* 2 minutes */
478
479 /* Initialize the dialog tracking list */
480 InitDialogListHead();
481
482 if (!CreateWindowStationAndDesktops(WLSession))
483 {
484 ERR("WL: Could not create window station and desktops\n");
485 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
486 ExitProcess(1);
487 }
488
489 LockWorkstation(WLSession);
490
491 /* Load default keyboard layouts */
492 if (!InitKeyboardLayouts())
493 {
494 ERR("WL: Could not preload keyboard layouts\n");
495 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
496 ExitProcess(1);
497 }
498
499 if (!StartRpcServer())
500 {
501 ERR("WL: Could not start the RPC server\n");
502 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
503 ExitProcess(1);
504 }
505
506 if (!StartServicesManager())
507 {
508 ERR("WL: Could not start services.exe\n");
509 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
510 ExitProcess(1);
511 }
512
513 if (!StartLsass())
514 {
515 ERR("WL: Failed to start lsass.exe service (error %lu)\n", GetLastError());
516 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
517 ExitProcess(1);
518 }
519
520 /* Wait for the LSA server */
521 WaitForLsass();
522
523 /* Init Notifications */
524 InitNotifications();
525
526 /* Load and initialize gina */
527 if (!GinaInit(WLSession))
528 {
529 ERR("WL: Failed to initialize Gina\n");
530 // FIXME: Retrieve the real name of the GINA DLL we were trying to load.
531 // It is known only inside the GinaInit function...
532 DialogBoxParam(hAppInstance, MAKEINTRESOURCE(IDD_GINALOADFAILED), GetDesktopWindow(), GinaLoadFailedWindowProc, (LPARAM)L"msgina.dll");
533 HandleShutdown(WLSession, WLX_SAS_ACTION_SHUTDOWN_REBOOT);
534 ExitProcess(1);
535 }
536
537 DisplayStatusMessage(WLSession, WLSession->WinlogonDesktop, IDS_REACTOSISSTARTINGUP);
538
539 #if 0
540 /* Connect to NetLogon service (lsass.exe) */
541 /* Real winlogon uses "Winlogon" */
542 RtlInitUnicodeString((PUNICODE_STRING)&ProcessName, L"Winlogon");
543 Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
544 if (Status == STATUS_PORT_CONNECTION_REFUSED)
545 {
546 /* Add the 'SeTcbPrivilege' privilege and try again */
547 Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, TRUE, &Old);
548 if (!NT_SUCCESS(Status))
549 {
550 ERR("RtlAdjustPrivilege() failed with error %lu\n", LsaNtStatusToWinError(Status));
551 return 1;
552 }
553
554 Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
555 }
556
557 if (!NT_SUCCESS(Status))
558 {
559 ERR("LsaRegisterLogonProcess() failed with error %lu\n", LsaNtStatusToWinError(Status));
560 return 1;
561 }
562
563 RtlInitUnicodeString((PUNICODE_STRING)&PackageName, MICROSOFT_KERBEROS_NAME_W);
564 Status = LsaLookupAuthenticationPackage(LsaHandle, &PackageName, &AuthenticationPackage);
565 if (!NT_SUCCESS(Status))
566 {
567 ERR("LsaLookupAuthenticationPackage() failed with error %lu\n", LsaNtStatusToWinError(Status));
568 LsaDeregisterLogonProcess(LsaHandle);
569 return 1;
570 }
571 #endif
572
573 CallNotificationDlls(WLSession, StartupHandler);
574
575 /* Create a hidden window to get SAS notifications */
576 if (!InitializeSAS(WLSession))
577 {
578 ERR("WL: Failed to initialize SAS\n");
579 ExitProcess(2);
580 }
581
582 // DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_PREPARENETWORKCONNECTIONS);
583 // DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_APPLYINGCOMPUTERSETTINGS);
584
585 /* Display logged out screen */
586 WLSession->LogonState = STATE_INIT;
587 RemoveStatusMessage(WLSession);
588
589 /* Check for pending setup */
590 if (GetSetupType() != 0)
591 {
592 /* Run setup and reboot when done */
593 TRACE("WL: Setup mode detected\n");
594 RunSetup();
595 }
596 else
597 {
598 PostMessageW(WLSession->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_CTRL_ALT_DEL, 0);
599 }
600
601 (void)LoadLibraryW(L"sfc_os.dll");
602
603 /* Tell kernel that CurrentControlSet is good (needed
604 * to support Last good known configuration boot) */
605 NtInitializeRegistry(CM_BOOT_FLAG_ACCEPTED | 1);
606
607 /* Message loop for the SAS window */
608 while (GetMessageW(&Msg, WLSession->SASWindow, 0, 0))
609 {
610 TranslateMessage(&Msg);
611 DispatchMessageW(&Msg);
612 }
613
614 CleanupNotifications();
615
616 /* We never go there */
617
618 return 0;
619 }
620