- Move NCI generated files to arch-specific directories
[reactos.git] / reactos / base / system / winlogon / winlogon.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Winlogon
4 * FILE: services/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 #include "winlogon.h"
13
14 //#define YDEBUG
15 #include <wine/debug.h>
16
17 /* GLOBALS ******************************************************************/
18
19 HINSTANCE hAppInstance;
20 PWLSESSION WLSession = NULL;
21
22 /* FUNCTIONS *****************************************************************/
23
24 static BOOL
25 StartServicesManager(VOID)
26 {
27 HANDLE ServicesInitEvent = NULL;
28 STARTUPINFOW StartupInfo;
29 PROCESS_INFORMATION ProcessInformation;
30 DWORD Count;
31 LPCWSTR ServiceString = L"services.exe";
32 BOOL res;
33
34 /* Start the service control manager (services.exe) */
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(
46 ServiceString,
47 NULL,
48 NULL,
49 NULL,
50 FALSE,
51 DETACHED_PROCESS,
52 NULL,
53 NULL,
54 &StartupInfo,
55 &ProcessInformation);
56 if (!res)
57 {
58 ERR("WL: Failed to execute services (error %lu)\n", GetLastError());
59 return FALSE;
60 }
61
62 /* Wait for event creation (by SCM) for max. 20 seconds */
63 for (Count = 0; Count < 20; Count++)
64 {
65 Sleep(1000);
66
67 TRACE("WL: Attempting to open event \"SvcctrlStartEvent_A3725DX\"\n");
68 ServicesInitEvent = OpenEventW(
69 SYNCHRONIZE,
70 FALSE,
71 L"SvcctrlStartEvent_A3725DX");
72 if (ServicesInitEvent)
73 break;
74 }
75
76 if (!ServicesInitEvent)
77 {
78 ERR("WL: Failed to open event \"SvcctrlStartEvent_A3725DX\"\n");
79 return FALSE;
80 }
81
82 /* Wait for event signalization */
83 WaitForSingleObject(ServicesInitEvent, INFINITE);
84 CloseHandle(ServicesInitEvent);
85 TRACE("WL: StartServicesManager() done.\n");
86
87 return TRUE;
88 }
89
90 static BOOL
91 StartCustomService(
92 IN LPCWSTR ServiceName)
93 {
94 SC_HANDLE hSCManager = NULL;
95 SC_HANDLE hService = NULL;
96 BOOL ret = FALSE;
97
98 hSCManager = OpenSCManager(NULL, NULL, 0);
99 if (!hSCManager)
100 goto cleanup;
101
102 hService = OpenServiceW(hSCManager, ServiceName, SERVICE_START);
103 if (!hService)
104 goto cleanup;
105 if (!StartServiceW(hService, 0, NULL))
106 goto cleanup;
107
108 ret = TRUE;
109
110 cleanup:
111 if (hService)
112 CloseServiceHandle(hService);
113 if (hSCManager)
114 CloseServiceHandle(hSCManager);
115 return ret;
116 }
117
118 static BOOL
119 StartLsass(VOID)
120 {
121 HANDLE LsassInitEvent;
122
123 LsassInitEvent = CreateEventW(
124 NULL,
125 TRUE,
126 FALSE,
127 L"Global\\SECURITY_SERVICES_STARTED");
128 if (!LsassInitEvent)
129 {
130 ERR("WL: Failed to create lsass notification event (error %lu)\n", GetLastError());
131 return FALSE;
132 }
133
134 /* Start the local security authority subsystem (Netlogon service) */
135 if (!StartCustomService(L"Netlogon"))
136 {
137 ERR("WL: Failed to start NetLogon service (error %lu)\n", GetLastError());
138 return FALSE;
139 }
140
141 WaitForSingleObject(LsassInitEvent, INFINITE);
142 CloseHandle(LsassInitEvent);
143
144 return TRUE;
145 }
146
147 #if 0
148 static BOOL
149 OpenRegistryKey(
150 OUT HKEY *WinLogonKey)
151 {
152 return ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
153 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon",
154 0,
155 KEY_QUERY_VALUE,
156 WinLogonKey);
157 }
158 #endif
159
160 #if 0
161 static BOOL
162 StartProcess(
163 IN PWCHAR ValueName)
164 {
165 BOOL StartIt;
166 HKEY WinLogonKey;
167 DWORD Type;
168 DWORD Size;
169 DWORD StartValue;
170
171 StartIt = TRUE;
172 if (OpenRegistryKey(&WinLogonKey))
173 {
174 Size = sizeof(DWORD);
175 if (ERROR_SUCCESS == RegQueryValueEx(WinLogonKey,
176 ValueName,
177 NULL,
178 &Type,
179 (LPBYTE) &StartValue,
180 &Size))
181 {
182 if (REG_DWORD == Type)
183 {
184 StartIt = (0 != StartValue);
185 }
186 }
187 RegCloseKey(WinLogonKey);
188 }
189
190 return StartIt;
191 }
192 #endif
193
194 /*
195 static BOOL RestartShell(
196 IN OUT PWLSESSION Session)
197 {
198 HKEY WinLogonKey;
199 DWORD Type, Size, Value;
200
201 if(OpenRegistryKey(&WinLogonKey))
202 {
203 Size = sizeof(DWORD);
204 if(ERROR_SUCCESS == RegQueryValueEx(WinLogonKey,
205 L"AutoRestartShell",
206 NULL,
207 &Type,
208 (LPBYTE)&Value,
209 &Size))
210 {
211 if(Type == REG_DWORD)
212 {
213 RegCloseKey(WinLogonKey);
214 return (Value != 0);
215 }
216 }
217 RegCloseKey(WinLogonKey);
218 }
219 return FALSE;
220 }
221 */
222
223 #if 0
224 static PWCHAR
225 GetUserInit(
226 OUT WCHAR *CommandLine,
227 IN DWORD BufferLength)
228 {
229 HKEY WinLogonKey;
230 BOOL GotCommandLine;
231 DWORD Type;
232 DWORD Size;
233 WCHAR Shell[_MAX_PATH];
234
235 GotCommandLine = FALSE;
236 if (OpenRegistryKey(&WinLogonKey))
237 {
238 Size = MAX_PATH;
239 if (ERROR_SUCCESS == RegQueryValueEx(WinLogonKey,
240 L"UserInit",
241 NULL,
242 &Type,
243 (LPBYTE) Shell,
244 &Size))
245 {
246 if (REG_EXPAND_SZ == Type)
247 {
248 ExpandEnvironmentStrings(Shell, CommandLine, _MAX_PATH);
249 GotCommandLine = TRUE;
250 }
251 else if (REG_SZ == Type)
252 {
253 wcscpy(CommandLine, Shell);
254 GotCommandLine = TRUE;
255 }
256 }
257 RegCloseKey(WinLogonKey);
258 }
259
260 if (! GotCommandLine)
261 {
262 GetSystemDirectory(CommandLine, MAX_PATH - 15);
263 wcscat(CommandLine, L"\\userinit.exe");
264 }
265
266 return CommandLine;
267 }
268
269 #endif
270
271 BOOL
272 DisplayStatusMessage(
273 IN PWLSESSION Session,
274 IN HDESK hDesktop,
275 IN UINT ResourceId)
276 {
277 WCHAR StatusMsg[MAX_PATH];
278
279 if (Session->Gina.Version < WLX_VERSION_1_3)
280 return TRUE;
281
282 if (Session->SuppressStatus)
283 return TRUE;
284
285 if (LoadStringW(hAppInstance, ResourceId, StatusMsg, MAX_PATH) == 0)
286 return FALSE;
287
288 return Session->Gina.Functions.WlxDisplayStatusMessage(Session->Gina.Context, hDesktop, 0, NULL, StatusMsg);
289 }
290
291 BOOL
292 RemoveStatusMessage(
293 IN PWLSESSION Session)
294 {
295 if (Session->Gina.Version < WLX_VERSION_1_3)
296 return TRUE;
297
298 return Session->Gina.Functions.WlxRemoveStatusMessage(Session->Gina.Context);
299 }
300
301 static BOOL CALLBACK
302 GinaLoadFailedWindowProc(
303 IN HWND hwndDlg,
304 IN UINT uMsg,
305 IN WPARAM wParam,
306 IN LPARAM lParam)
307 {
308 switch (uMsg)
309 {
310 case WM_COMMAND:
311 {
312 switch (LOWORD(wParam))
313 {
314 case IDOK:
315 EndDialog(hwndDlg, IDOK);
316 return TRUE;
317 }
318 break;
319 }
320 case WM_INITDIALOG:
321 {
322 int len;
323 WCHAR templateText[MAX_PATH], text[MAX_PATH];
324
325 len = GetDlgItemTextW(hwndDlg, IDC_GINALOADFAILED, templateText, MAX_PATH);
326 if (len)
327 {
328 wsprintfW(text, templateText, (LPWSTR)lParam);
329 SetDlgItemTextW(hwndDlg, IDC_GINALOADFAILED, text);
330 }
331 SetFocus(GetDlgItem(hwndDlg, IDOK));
332 return TRUE;
333 }
334 case WM_CLOSE:
335 {
336 EndDialog(hwndDlg, IDCANCEL);
337 return TRUE;
338 }
339 }
340
341 return FALSE;
342 }
343
344 int WINAPI
345 WinMain(
346 IN HINSTANCE hInstance,
347 IN HINSTANCE hPrevInstance,
348 IN LPSTR lpCmdLine,
349 IN int nShowCmd)
350 {
351 #if 0
352 LSA_STRING ProcessName, PackageName;
353 HANDLE LsaHandle;
354 LSA_OPERATIONAL_MODE Mode;
355 BOOLEAN Old;
356 ULONG AuthenticationPackage;
357 NTSTATUS Status;
358 #endif
359 ULONG HardErrorResponse;
360 MSG Msg;
361
362 UNREFERENCED_PARAMETER(hPrevInstance);
363 UNREFERENCED_PARAMETER(lpCmdLine);
364 UNREFERENCED_PARAMETER(nShowCmd);
365
366 hAppInstance = hInstance;
367
368 if (!RegisterLogonProcess(GetCurrentProcessId(), TRUE))
369 {
370 ERR("WL: Could not register logon process\n");
371 HandleShutdown(NULL, WLX_SAS_ACTION_SHUTDOWN_POWER_OFF);
372 NtShutdownSystem(ShutdownNoReboot);
373 ExitProcess(0);
374 }
375
376 WLSession = (PWLSESSION)HeapAlloc(GetProcessHeap(), 0, sizeof(WLSESSION));
377 if (!WLSession)
378 {
379 ERR("WL: Could not allocate memory for winlogon instance\n");
380 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
381 ExitProcess(1);
382 }
383 ZeroMemory(WLSession, sizeof(WLSESSION));
384 WLSession->DialogTimeout = 120; /* 2 minutes */
385
386 if (!CreateWindowStationAndDesktops(WLSession))
387 {
388 ERR("WL: Could not create window station and desktops\n");
389 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
390 ExitProcess(1);
391 }
392 LockWorkstation(WLSession);
393
394 if (!StartServicesManager())
395 {
396 ERR("WL: Could not start services.exe\n");
397 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
398 ExitProcess(1);
399 }
400
401 /* Check for pending setup */
402 if (GetSetupType() != 0)
403 {
404 TRACE("WL: Setup mode detected\n");
405
406 /* Set locale */
407 SetDefaultLanguage(FALSE);
408
409 /* Run setup and reboot when done */
410 SwitchDesktop(WLSession->ApplicationDesktop);
411 RunSetup();
412
413 HandleShutdown(WLSession, WLX_SAS_ACTION_SHUTDOWN_REBOOT);
414 ExitProcess(0);
415 }
416
417 if (!StartLsass())
418 {
419 DPRINT1("WL: Failed to start lsass.exe service (error %lu)\n", GetLastError());
420 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, 0, OptionOk, &HardErrorResponse);
421 ExitProcess(1);
422 }
423
424 /* Load and initialize gina */
425 if (!GinaInit(WLSession))
426 {
427 ERR("WL: Failed to initialize Gina\n");
428 DialogBoxParam(hAppInstance, MAKEINTRESOURCE(IDD_GINALOADFAILED), GetDesktopWindow(), GinaLoadFailedWindowProc, (LPARAM)L"");
429 HandleShutdown(WLSession, WLX_SAS_ACTION_SHUTDOWN_REBOOT);
430 ExitProcess(1);
431 }
432
433 DisplayStatusMessage(WLSession, WLSession->WinlogonDesktop, IDS_REACTOSISSTARTINGUP);
434
435 #if 0
436 /* Connect to NetLogon service (lsass.exe) */
437 /* Real winlogon uses "Winlogon" */
438 RtlInitUnicodeString((PUNICODE_STRING)&ProcessName, L"Winlogon");
439 Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
440 if (Status == STATUS_PORT_CONNECTION_REFUSED)
441 {
442 /* Add the 'SeTcbPrivilege' privilege and try again */
443 Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, TRUE, &Old);
444 if (!NT_SUCCESS(Status))
445 {
446 ERR("RtlAdjustPrivilege() failed with error %lu\n", LsaNtStatusToWinError(Status));
447 return 1;
448 }
449 Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
450 }
451 if (!NT_SUCCESS(Status))
452 {
453 ERR("LsaRegisterLogonProcess() failed with error %lu\n", LsaNtStatusToWinError(Status));
454 return 1;
455 }
456
457 RtlInitUnicodeString((PUNICODE_STRING)&PackageName, MICROSOFT_KERBEROS_NAME_W);
458 Status = LsaLookupAuthenticationPackage(LsaHandle, &PackageName, &AuthenticationPackage);
459 if (!NT_SUCCESS(Status))
460 {
461 ERR("LsaLookupAuthenticationPackage() failed with error %lu\n", LsaNtStatusToWinError(Status));
462 LsaDeregisterLogonProcess(LsaHandle);
463 return 1;
464 }
465 #endif
466
467 /* Create a hidden window to get SAS notifications */
468 if (!InitializeSAS(WLSession))
469 {
470 ERR("WL: Failed to initialize SAS\n");
471 ExitProcess(2);
472 }
473
474 //DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_PREPARENETWORKCONNECTIONS);
475 //DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_APPLYINGCOMPUTERSETTINGS);
476
477 /* Display logged out screen */
478 WLSession->LogonStatus = WKSTA_IS_LOGGED_OFF;
479 RemoveStatusMessage(WLSession);
480 PostMessageW(WLSession->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_TIMEOUT, 0);
481
482 /* Message loop for the SAS window */
483 while (GetMessageW(&Msg, WLSession->SASWindow, 0, 0))
484 {
485 TranslateMessage(&Msg);
486 DispatchMessageW(&Msg);
487 }
488
489 /* We never go there */
490
491 return 0;
492 }