This really needs to go in a branch. It needs heavy testing and can't coincide with...
[reactos.git] / 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 #include <wine/debug.h>
16
17 WINE_DEFAULT_DEBUG_CHANNEL(winlogon);
18
19 /* GLOBALS ******************************************************************/
20
21 HINSTANCE hAppInstance;
22 PWLSESSION WLSession = NULL;
23
24 /* FUNCTIONS *****************************************************************/
25
26 BOOL
27 PlaySoundRoutine(
28 IN LPCWSTR FileName,
29 IN UINT bLogon,
30 IN UINT Flags)
31 {
32 typedef BOOL (WINAPI *PLAYSOUNDW)(LPCWSTR,HMODULE,DWORD);
33 typedef UINT (WINAPI *WAVEOUTGETNUMDEVS)(VOID);
34 PLAYSOUNDW Play;
35 WAVEOUTGETNUMDEVS waveOutGetNumDevs;
36 UINT NumDevs;
37 HMODULE hLibrary;
38 BOOL Ret = FALSE;
39
40 hLibrary = LoadLibraryW(L"winmm.dll");
41 if (hLibrary)
42 {
43 waveOutGetNumDevs = (WAVEOUTGETNUMDEVS)GetProcAddress(hLibrary, "waveOutGetNumDevs");
44 if (waveOutGetNumDevs)
45 {
46 NumDevs = waveOutGetNumDevs();
47 if (!NumDevs)
48 {
49 if (!bLogon)
50 {
51 Beep(500, 500);
52 }
53 FreeLibrary(hLibrary);
54 return FALSE;
55 }
56 }
57
58 Play = (PLAYSOUNDW)GetProcAddress(hLibrary, "PlaySoundW");
59 if (Play)
60 {
61 Ret = Play(FileName, NULL, Flags);
62 }
63 FreeLibrary(hLibrary);
64 }
65
66 return Ret;
67 }
68
69 DWORD
70 WINAPI
71 PlayLogonSoundThread(
72 IN LPVOID lpParameter)
73 {
74 HKEY hKey;
75 WCHAR szBuffer[MAX_PATH] = {0};
76 WCHAR szDest[MAX_PATH];
77 DWORD dwSize = sizeof(szBuffer);
78 SERVICE_STATUS_PROCESS Info;
79
80 ULONG Index = 0;
81
82 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"AppEvents\\Schemes\\Apps\\.Default\\WindowsLogon\\.Current", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
83 {
84 ExitThread(0);
85 }
86
87 if (RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)szBuffer, &dwSize) != ERROR_SUCCESS)
88 {
89 RegCloseKey(hKey);
90 ExitThread(0);
91 }
92
93
94 RegCloseKey(hKey);
95
96 if (!szBuffer[0])
97 ExitThread(0);
98
99
100 szBuffer[MAX_PATH-1] = L'\0';
101 if (ExpandEnvironmentStringsW(szBuffer, szDest, MAX_PATH))
102 {
103 SC_HANDLE hSCManager, hService;
104
105 hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
106 if (!hSCManager)
107 ExitThread(0);;
108
109 hService = OpenServiceW(hSCManager, L"wdmaud", GENERIC_READ);
110 if (!hService)
111 {
112 CloseServiceHandle(hSCManager);
113 TRACE("WL: failed to open sysaudio Status %x\n", GetLastError());
114 ExitThread(0);
115 }
116
117 do
118 {
119 if (!QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&Info, sizeof(SERVICE_STATUS_PROCESS), &dwSize))
120 {
121 TRACE("WL: QueryServiceStatusEx failed %x\n", GetLastError());
122 break;
123 }
124
125 if (Info.dwCurrentState == SERVICE_RUNNING)
126 break;
127
128 Sleep(1000);
129
130 }while(Index++ < 20);
131
132 CloseServiceHandle(hService);
133 CloseServiceHandle(hSCManager);
134
135 if (Info.dwCurrentState != SERVICE_RUNNING)
136 ExitThread(0);
137
138 PlaySoundRoutine(szDest, TRUE, SND_FILENAME);
139 }
140 ExitThread(0);
141 }
142
143
144
145 static BOOL
146 StartServicesManager(VOID)
147 {
148 STARTUPINFOW StartupInfo;
149 PROCESS_INFORMATION ProcessInformation;
150 LPCWSTR ServiceString = L"services.exe";
151 BOOL res;
152
153 /* Start the service control manager (services.exe) */
154 ZeroMemory(&StartupInfo, sizeof(STARTUPINFOW));
155 StartupInfo.cb = sizeof(StartupInfo);
156 StartupInfo.lpReserved = NULL;
157 StartupInfo.lpDesktop = NULL;
158 StartupInfo.lpTitle = NULL;
159 StartupInfo.dwFlags = 0;
160 StartupInfo.cbReserved2 = 0;
161 StartupInfo.lpReserved2 = 0;
162
163 TRACE("WL: Creating new process - %S\n", ServiceString);
164
165 res = CreateProcessW(
166 ServiceString,
167 NULL,
168 NULL,
169 NULL,
170 FALSE,
171 DETACHED_PROCESS,
172 NULL,
173 NULL,
174 &StartupInfo,
175 &ProcessInformation);
176 if (!res)
177 {
178 ERR("WL: Failed to execute services (error %lu)\n", GetLastError());
179 return FALSE;
180 }
181
182 TRACE("WL: Created new process - %S\n", ServiceString);
183
184 CloseHandle(ProcessInformation.hThread);
185 CloseHandle(ProcessInformation.hProcess);
186
187 TRACE("WL: StartServicesManager() done.\n");
188
189 return TRUE;
190 }
191
192
193 static BOOL
194 StartLsass(VOID)
195 {
196 STARTUPINFOW StartupInfo;
197 PROCESS_INFORMATION ProcessInformation;
198 LPCWSTR ServiceString = L"lsass.exe";
199 BOOL res;
200
201 /* Start the local security authority subsystem (lsass.exe) */
202 ZeroMemory(&StartupInfo, sizeof(STARTUPINFOW));
203 StartupInfo.cb = sizeof(StartupInfo);
204 StartupInfo.lpReserved = NULL;
205 StartupInfo.lpDesktop = NULL;
206 StartupInfo.lpTitle = NULL;
207 StartupInfo.dwFlags = 0;
208 StartupInfo.cbReserved2 = 0;
209 StartupInfo.lpReserved2 = 0;
210
211 TRACE("WL: Creating new process - %S\n", ServiceString);
212
213 res = CreateProcessW(
214 ServiceString,
215 NULL,
216 NULL,
217 NULL,
218 FALSE,
219 DETACHED_PROCESS,
220 NULL,
221 NULL,
222 &StartupInfo,
223 &ProcessInformation);
224
225 TRACE("WL: Created new process - %S\n", ServiceString);
226
227 CloseHandle(ProcessInformation.hThread);
228 CloseHandle(ProcessInformation.hProcess);
229
230 return res;
231 }
232
233
234 static VOID
235 WaitForLsass(VOID)
236 {
237 HANDLE hEvent;
238 DWORD dwError;
239
240 hEvent = CreateEventW(NULL,
241 TRUE,
242 FALSE,
243 L"LSA_RPC_SERVER_ACTIVE");
244 if (hEvent == NULL)
245 {
246 dwError = GetLastError();
247 TRACE("WL: Failed to create the notication event (Error %lu)\n", dwError);
248
249 if (dwError == ERROR_ALREADY_EXISTS)
250 {
251 hEvent = OpenEventW(SYNCHRONIZE,
252 FALSE,
253 L"LSA_RPC_SERVER_ACTIVE");
254 if (hEvent == NULL)
255 {
256 ERR("WL: Could not open the notification event (Error %lu)\n", GetLastError());
257 return;
258 }
259 }
260 }
261
262 TRACE("WL: Wait for the LSA server!\n");
263 WaitForSingleObject(hEvent, INFINITE);
264 TRACE("WL: LSA server running!\n");
265
266 CloseHandle(hEvent);
267 }
268
269
270 BOOL
271 DisplayStatusMessage(
272 IN PWLSESSION Session,
273 IN HDESK hDesktop,
274 IN UINT ResourceId)
275 {
276 WCHAR StatusMsg[MAX_PATH];
277
278 if (Session->Gina.Version < WLX_VERSION_1_3)
279 return TRUE;
280
281 if (Session->SuppressStatus)
282 return TRUE;
283
284 if (LoadStringW(hAppInstance, ResourceId, StatusMsg, MAX_PATH) == 0)
285 return FALSE;
286
287 return Session->Gina.Functions.WlxDisplayStatusMessage(Session->Gina.Context, hDesktop, 0, NULL, StatusMsg);
288 }
289
290 BOOL
291 RemoveStatusMessage(
292 IN PWLSESSION Session)
293 {
294 if (Session->Gina.Version < WLX_VERSION_1_3)
295 return TRUE;
296
297 return Session->Gina.Functions.WlxRemoveStatusMessage(Session->Gina.Context);
298 }
299
300 static INT_PTR CALLBACK
301 GinaLoadFailedWindowProc(
302 IN HWND hwndDlg,
303 IN UINT uMsg,
304 IN WPARAM wParam,
305 IN LPARAM lParam)
306 {
307 switch (uMsg)
308 {
309 case WM_COMMAND:
310 {
311 switch (LOWORD(wParam))
312 {
313 case IDOK:
314 EndDialog(hwndDlg, IDOK);
315 return TRUE;
316 }
317 break;
318 }
319 case WM_INITDIALOG:
320 {
321 int len;
322 WCHAR templateText[MAX_PATH], text[MAX_PATH];
323
324 len = GetDlgItemTextW(hwndDlg, IDC_GINALOADFAILED, templateText, MAX_PATH);
325 if (len)
326 {
327 wsprintfW(text, templateText, (LPWSTR)lParam);
328 SetDlgItemTextW(hwndDlg, IDC_GINALOADFAILED, text);
329 }
330 SetFocus(GetDlgItem(hwndDlg, IDOK));
331 return TRUE;
332 }
333 case WM_CLOSE:
334 {
335 EndDialog(hwndDlg, IDCANCEL);
336 return TRUE;
337 }
338 }
339
340 return FALSE;
341 }
342
343 int WINAPI
344 WinMain(
345 IN HINSTANCE hInstance,
346 IN HINSTANCE hPrevInstance,
347 IN LPSTR lpCmdLine,
348 IN int nShowCmd)
349 {
350 #if 0
351 LSA_STRING ProcessName, PackageName;
352 HANDLE LsaHandle;
353 LSA_OPERATIONAL_MODE Mode;
354 BOOLEAN Old;
355 ULONG AuthenticationPackage;
356 NTSTATUS Status;
357 #endif
358 ULONG HardErrorResponse;
359 MSG Msg;
360 HANDLE hThread;
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 if (!StartLsass())
402 {
403 ERR("WL: Failed to start lsass.exe service (error %lu)\n", GetLastError());
404 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, 0, OptionOk, &HardErrorResponse);
405 ExitProcess(1);
406 }
407
408 /* Load and initialize gina */
409 if (!GinaInit(WLSession))
410 {
411 ERR("WL: Failed to initialize Gina\n");
412 DialogBoxParam(hAppInstance, MAKEINTRESOURCE(IDD_GINALOADFAILED), GetDesktopWindow(), GinaLoadFailedWindowProc, (LPARAM)L"");
413 HandleShutdown(WLSession, WLX_SAS_ACTION_SHUTDOWN_REBOOT);
414 ExitProcess(1);
415 }
416
417 DisplayStatusMessage(WLSession, WLSession->WinlogonDesktop, IDS_REACTOSISSTARTINGUP);
418
419
420 /* Wait for the LSA server */
421 WaitForLsass();
422
423 #if 0
424 /* Connect to NetLogon service (lsass.exe) */
425 /* Real winlogon uses "Winlogon" */
426 RtlInitUnicodeString((PUNICODE_STRING)&ProcessName, L"Winlogon");
427 Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
428 if (Status == STATUS_PORT_CONNECTION_REFUSED)
429 {
430 /* Add the 'SeTcbPrivilege' privilege and try again */
431 Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, TRUE, &Old);
432 if (!NT_SUCCESS(Status))
433 {
434 ERR("RtlAdjustPrivilege() failed with error %lu\n", LsaNtStatusToWinError(Status));
435 return 1;
436 }
437 Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
438 }
439 if (!NT_SUCCESS(Status))
440 {
441 ERR("LsaRegisterLogonProcess() failed with error %lu\n", LsaNtStatusToWinError(Status));
442 return 1;
443 }
444
445 RtlInitUnicodeString((PUNICODE_STRING)&PackageName, MICROSOFT_KERBEROS_NAME_W);
446 Status = LsaLookupAuthenticationPackage(LsaHandle, &PackageName, &AuthenticationPackage);
447 if (!NT_SUCCESS(Status))
448 {
449 ERR("LsaLookupAuthenticationPackage() failed with error %lu\n", LsaNtStatusToWinError(Status));
450 LsaDeregisterLogonProcess(LsaHandle);
451 return 1;
452 }
453 #endif
454
455 /* Create a hidden window to get SAS notifications */
456 if (!InitializeSAS(WLSession))
457 {
458 ERR("WL: Failed to initialize SAS\n");
459 ExitProcess(2);
460 }
461
462 //DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_PREPARENETWORKCONNECTIONS);
463 //DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_APPLYINGCOMPUTERSETTINGS);
464
465 /* Display logged out screen */
466 WLSession->LogonStatus = WKSTA_IS_LOGGED_OFF;
467 RemoveStatusMessage(WLSession);
468
469 /* Check for pending setup */
470 if (GetSetupType() != 0)
471 {
472 TRACE("WL: Setup mode detected\n");
473
474 /* Run setup and reboot when done */
475 SwitchDesktop(WLSession->ApplicationDesktop);
476 RunSetup();
477 }
478 else
479 PostMessageW(WLSession->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_TIMEOUT, 0);
480
481 /* Play logon sound */
482 hThread = CreateThread(NULL, 0, PlayLogonSoundThread, NULL, 0, NULL);
483 if (hThread)
484 {
485 CloseHandle(hThread);
486 }
487
488 /* Tell kernel that CurrentControlSet is good (needed
489 * to support Last good known configuration boot) */
490 NtInitializeRegistry(CM_BOOT_FLAG_ACCEPTED | 1);
491
492 /* Message loop for the SAS window */
493 while (GetMessageW(&Msg, WLSession->SASWindow, 0, 0))
494 {
495 TranslateMessage(&Msg);
496 DispatchMessageW(&Msg);
497 }
498
499 /* We never go there */
500
501 return 0;
502 }