Check if logoff succeeded before continuing
[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;
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 EVENT_ALL_ACCESS, //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 0
106 if (!StartServiceW(hService, 0, NULL))
107 goto cleanup;
108 #endif
109
110 ret = TRUE;
111
112 cleanup:
113 if (hService)
114 CloseServiceHandle(hService);
115 if (hSCManager)
116 CloseServiceHandle(hSCManager);
117 return ret;
118 }
119
120 static BOOL
121 StartLsass(VOID)
122 {
123 HANDLE LsassInitEvent;
124
125 LsassInitEvent = CreateEventW(
126 NULL,
127 TRUE,
128 FALSE,
129 L"Global\\SECURITY_SERVICES_STARTED");
130 if (!LsassInitEvent)
131 {
132 ERR("WL: Failed to create lsass notification event (error %lu)\n", GetLastError());
133 return FALSE;
134 }
135
136 /* Start the local security authority subsystem (Netlogon service) */
137 if (!StartCustomService(L"Netlogon"))
138 {
139 ERR("WL: Failed to start NetLogon service (error %lu)\n", GetLastError());
140 return FALSE;
141 }
142
143 #if 0
144 WaitForSingleObject(LsassInitEvent, INFINITE);
145 #endif
146 CloseHandle(LsassInitEvent);
147
148 return TRUE;
149 }
150
151 #if 0
152 static BOOL
153 OpenRegistryKey(
154 OUT HKEY *WinLogonKey)
155 {
156 return ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
157 L"SOFTWARE\\ReactOS\\Windows NT\\CurrentVersion\\WinLogon",
158 0,
159 KEY_QUERY_VALUE,
160 WinLogonKey);
161 }
162 #endif
163
164 #if 0
165 static BOOL
166 StartProcess(
167 IN PWCHAR ValueName)
168 {
169 BOOL StartIt;
170 HKEY WinLogonKey;
171 DWORD Type;
172 DWORD Size;
173 DWORD StartValue;
174
175 StartIt = TRUE;
176 if (OpenRegistryKey(&WinLogonKey))
177 {
178 Size = sizeof(DWORD);
179 if (ERROR_SUCCESS == RegQueryValueEx(WinLogonKey,
180 ValueName,
181 NULL,
182 &Type,
183 (LPBYTE) &StartValue,
184 &Size))
185 {
186 if (REG_DWORD == Type)
187 {
188 StartIt = (0 != StartValue);
189 }
190 }
191 RegCloseKey(WinLogonKey);
192 }
193
194 return StartIt;
195 }
196 #endif
197
198 /*
199 static BOOL RestartShell(
200 IN OUT PWLSESSION Session)
201 {
202 HKEY WinLogonKey;
203 DWORD Type, Size, Value;
204
205 if(OpenRegistryKey(&WinLogonKey))
206 {
207 Size = sizeof(DWORD);
208 if(ERROR_SUCCESS == RegQueryValueEx(WinLogonKey,
209 L"AutoRestartShell",
210 NULL,
211 &Type,
212 (LPBYTE)&Value,
213 &Size))
214 {
215 if(Type == REG_DWORD)
216 {
217 RegCloseKey(WinLogonKey);
218 return (Value != 0);
219 }
220 }
221 RegCloseKey(WinLogonKey);
222 }
223 return FALSE;
224 }
225 */
226
227 #if 0
228 static PWCHAR
229 GetUserInit(
230 OUT WCHAR *CommandLine,
231 IN DWORD BufferLength)
232 {
233 HKEY WinLogonKey;
234 BOOL GotCommandLine;
235 DWORD Type;
236 DWORD Size;
237 WCHAR Shell[_MAX_PATH];
238
239 GotCommandLine = FALSE;
240 if (OpenRegistryKey(&WinLogonKey))
241 {
242 Size = MAX_PATH;
243 if (ERROR_SUCCESS == RegQueryValueEx(WinLogonKey,
244 L"UserInit",
245 NULL,
246 &Type,
247 (LPBYTE) Shell,
248 &Size))
249 {
250 if (REG_EXPAND_SZ == Type)
251 {
252 ExpandEnvironmentStrings(Shell, CommandLine, _MAX_PATH);
253 GotCommandLine = TRUE;
254 }
255 else if (REG_SZ == Type)
256 {
257 wcscpy(CommandLine, Shell);
258 GotCommandLine = TRUE;
259 }
260 }
261 RegCloseKey(WinLogonKey);
262 }
263
264 if (! GotCommandLine)
265 {
266 GetSystemDirectory(CommandLine, MAX_PATH - 15);
267 wcscat(CommandLine, L"\\userinit.exe");
268 }
269
270 return CommandLine;
271 }
272
273 #endif
274
275 BOOL
276 DisplayStatusMessage(
277 IN PWLSESSION Session,
278 IN HDESK hDesktop,
279 IN UINT ResourceId)
280 {
281 WCHAR StatusMsg[MAX_PATH];
282
283 if (Session->Gina.Version < WLX_VERSION_1_3)
284 return TRUE;
285
286 if (Session->SuppressStatus)
287 return TRUE;
288
289 if (LoadStringW(hAppInstance, ResourceId, StatusMsg, MAX_PATH) == 0)
290 return FALSE;
291
292 return Session->Gina.Functions.WlxDisplayStatusMessage(Session->Gina.Context, hDesktop, 0, NULL, StatusMsg);
293 }
294
295 BOOL
296 RemoveStatusMessage(
297 IN PWLSESSION Session)
298 {
299 if (Session->Gina.Version < WLX_VERSION_1_3)
300 return TRUE;
301
302 return Session->Gina.Functions.WlxRemoveStatusMessage(Session->Gina.Context);
303 }
304
305 static INT_PTR CALLBACK
306 GinaLoadFailedWindowProc(
307 IN HWND hwndDlg,
308 IN UINT uMsg,
309 IN WPARAM wParam,
310 IN LPARAM lParam)
311 {
312 switch (uMsg)
313 {
314 case WM_COMMAND:
315 {
316 switch (LOWORD(wParam))
317 {
318 case IDOK:
319 EndDialog(hwndDlg, IDOK);
320 return TRUE;
321 }
322 break;
323 }
324 case WM_INITDIALOG:
325 {
326 int len;
327 WCHAR templateText[MAX_PATH], text[MAX_PATH];
328
329 len = GetDlgItemTextW(hwndDlg, IDC_GINALOADFAILED, templateText, MAX_PATH);
330 if (len)
331 {
332 wsprintfW(text, templateText, (LPWSTR)lParam);
333 SetDlgItemTextW(hwndDlg, IDC_GINALOADFAILED, text);
334 }
335 SetFocus(GetDlgItem(hwndDlg, IDOK));
336 return TRUE;
337 }
338 case WM_CLOSE:
339 {
340 EndDialog(hwndDlg, IDCANCEL);
341 return TRUE;
342 }
343 }
344
345 return FALSE;
346 }
347
348 int WINAPI
349 WinMain(
350 IN HINSTANCE hInstance,
351 IN HINSTANCE hPrevInstance,
352 IN LPSTR lpCmdLine,
353 IN int nShowCmd)
354 {
355 #if 0
356 LSA_STRING ProcessName, PackageName;
357 HANDLE LsaHandle;
358 LSA_OPERATIONAL_MODE Mode;
359 BOOLEAN Old;
360 ULONG AuthenticationPackage;
361 NTSTATUS Status;
362 #endif
363 MSG Msg;
364
365 hAppInstance = hInstance;
366
367 if (!RegisterLogonProcess(GetCurrentProcessId(), TRUE))
368 {
369 ERR("WL: Could not register logon process\n");
370 HandleShutdown(NULL, WLX_SAS_ACTION_SHUTDOWN_POWER_OFF);
371 NtShutdownSystem(ShutdownNoReboot);
372 ExitProcess(0);
373 return 0;
374 }
375
376 WLSession = (PWLSESSION)HeapAlloc(GetProcessHeap(), 0, sizeof(WLSESSION));
377 ZeroMemory(WLSession, sizeof(WLSESSION));
378 if (!WLSession)
379 {
380 ERR("WL: Could not allocate memory for winlogon instance\n");
381 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, 0, 0, 0);
382 ExitProcess(1);
383 return 1;
384 }
385 WLSession->DialogTimeout = 120; /* 2 minutes */
386
387 if (!CreateWindowStationAndDesktops(WLSession))
388 {
389 ERR("WL: Could not create window station and desktops\n");
390 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, 0, 0, 0);
391 ExitProcess(1);
392 return 1;
393 }
394 LockWorkstation(WLSession);
395
396 if (!StartServicesManager())
397 {
398 ERR("WL: Could not start services.exe\n");
399 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, 0, 0, 0);
400 ExitProcess(1);
401 return 1;
402 }
403
404 /* Check for pending setup */
405 if (GetSetupType() != 0)
406 {
407 TRACE("WL: Setup mode detected\n");
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 return 0;
416 }
417
418 if (!StartLsass())
419 {
420 DPRINT1("WL: Failed to start lsass.exe service (error %lu)\n", GetLastError());
421 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, 0, 0, 0);
422 ExitProcess(1);
423 return 1;
424 }
425
426 /* Load and initialize gina */
427 if (!GinaInit(WLSession))
428 {
429 ERR("WL: Failed to initialize Gina\n");
430 DialogBoxParam(hAppInstance, MAKEINTRESOURCE(IDD_GINALOADFAILED), 0, GinaLoadFailedWindowProc, (LPARAM)L"");
431 HandleShutdown(WLSession, WLX_SAS_ACTION_SHUTDOWN_REBOOT);
432 ExitProcess(1);
433 return 1;
434 }
435
436 DisplayStatusMessage(WLSession, WLSession->WinlogonDesktop, IDS_REACTOSISSTARTINGUP);
437
438 #if 0
439 /* Connect to NetLogon service (lsass.exe) */
440 /* Real winlogon uses "Winlogon" */
441 RtlInitUnicodeString((PUNICODE_STRING)&ProcessName, L"Winlogon");
442 Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
443 if (Status == STATUS_PORT_CONNECTION_REFUSED)
444 {
445 /* Add the 'SeTcbPrivilege' privilege and try again */
446 Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, TRUE, &Old);
447 if (!NT_SUCCESS(Status))
448 {
449 ERR("RtlAdjustPrivilege() failed with error %lu\n", LsaNtStatusToWinError(Status));
450 return 1;
451 }
452 Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
453 }
454 if (!NT_SUCCESS(Status))
455 {
456 ERR("LsaRegisterLogonProcess() failed with error %lu\n", LsaNtStatusToWinError(Status));
457 return 1;
458 }
459
460 RtlInitUnicodeString((PUNICODE_STRING)&PackageName, MICROSOFT_KERBEROS_NAME_W);
461 Status = LsaLookupAuthenticationPackage(LsaHandle, &PackageName, &AuthenticationPackage);
462 if (!NT_SUCCESS(Status))
463 {
464 ERR("LsaLookupAuthenticationPackage() failed with error %lu\n", LsaNtStatusToWinError(Status));
465 LsaDeregisterLogonProcess(LsaHandle);
466 return 1;
467 }
468 #endif
469
470 /* Create a hidden window to get SAS notifications */
471 if (!InitializeSAS(WLSession))
472 {
473 ERR("WL: Failed to initialize SAS\n");
474 ExitProcess(2);
475 return 2;
476 }
477
478 //DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_PREPARENETWORKCONNECTIONS);
479 //DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_APPLYINGCOMPUTERSETTINGS);
480
481 /* Display logged out screen */
482 WLSession->LogonStatus = WKSTA_IS_LOGGED_OFF;
483 RemoveStatusMessage(WLSession);
484 DispatchSAS(WLSession, WLX_SAS_TYPE_TIMEOUT);
485
486 /* Message loop for the SAS window */
487 while (GetMessage(&Msg, WLSession->SASWindow, 0, 0))
488 {
489 TranslateMessage(&Msg);
490 DispatchMessage(&Msg);
491 }
492
493 /* We never go there */
494
495 return 0;
496 }