xref: /reactos/base/system/winlogon/winlogon.c (revision 02e84521)
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 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 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         /* Run setup and reboot when done */
457         TRACE("WL: Setup mode detected\n");
458         RunSetup();
459     }
460     else
461     {
462         PostMessageW(WLSession->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_CTRL_ALT_DEL, 0);
463     }
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 }
484