d3884794d5d81780bd0bd157d5790ec3ce8792c5
[reactos.git] / reactos / 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 static BOOL
271 InitKeyboardLayouts()
272 {
273 WCHAR wszKeyName[12], wszKLID[10];
274 DWORD dwSize = sizeof(wszKLID), dwType, i;
275 HKEY hKey;
276 UINT Flags;
277 BOOL bRet = FALSE;
278
279 /* Open registry key with preloaded layouts */
280 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
281 {
282 ERR("RegOpenKeyExW failed!\n");
283 return FALSE;
284 }
285
286 i = 1;
287 while(TRUE)
288 {
289 /* Read values with integer names only */
290 swprintf(wszKeyName, L"%d", i);
291 if (RegQueryValueExW(hKey, wszKeyName, NULL, &dwType, (LPBYTE)wszKLID, &dwSize) != ERROR_SUCCESS)
292 {
293 /* If we loaded at least one layout and there is no more
294 registry values return TRUE */
295 if (i > 1)
296 bRet = TRUE;
297 break;
298 }
299
300 /* Only REG_SZ values are valid */
301 if (dwType != REG_SZ)
302 {
303 ERR("Wrong type!\n");
304 break;
305 }
306
307 /* Load keyboard layout with given locale id */
308 Flags = KLF_SUBSTITUTE_OK;
309 if (i > 1)
310 Flags |= KLF_NOTELLSHELL|KLF_REPLACELANG;
311 else // First layout
312 Flags |= KLF_ACTIVATE; // |0x40000000
313 if (!LoadKeyboardLayoutW(wszKLID, Flags))
314 {
315 ERR("LoadKeyboardLayoutW failed!\n");
316 break;
317 }
318
319 /* Move to the next entry */
320 ++i;
321 }
322
323 /* Close the key now */
324 RegCloseKey(hKey);
325
326 return bRet;
327 }
328
329 BOOL
330 DisplayStatusMessage(
331 IN PWLSESSION Session,
332 IN HDESK hDesktop,
333 IN UINT ResourceId)
334 {
335 WCHAR StatusMsg[MAX_PATH];
336
337 if (Session->Gina.Version < WLX_VERSION_1_3)
338 return TRUE;
339
340 if (Session->SuppressStatus)
341 return TRUE;
342
343 if (LoadStringW(hAppInstance, ResourceId, StatusMsg, MAX_PATH) == 0)
344 return FALSE;
345
346 return Session->Gina.Functions.WlxDisplayStatusMessage(Session->Gina.Context, hDesktop, 0, NULL, StatusMsg);
347 }
348
349 BOOL
350 RemoveStatusMessage(
351 IN PWLSESSION Session)
352 {
353 if (Session->Gina.Version < WLX_VERSION_1_3)
354 return TRUE;
355
356 return Session->Gina.Functions.WlxRemoveStatusMessage(Session->Gina.Context);
357 }
358
359 static INT_PTR CALLBACK
360 GinaLoadFailedWindowProc(
361 IN HWND hwndDlg,
362 IN UINT uMsg,
363 IN WPARAM wParam,
364 IN LPARAM lParam)
365 {
366 switch (uMsg)
367 {
368 case WM_COMMAND:
369 {
370 switch (LOWORD(wParam))
371 {
372 case IDOK:
373 EndDialog(hwndDlg, IDOK);
374 return TRUE;
375 }
376 break;
377 }
378 case WM_INITDIALOG:
379 {
380 int len;
381 WCHAR templateText[MAX_PATH], text[MAX_PATH];
382
383 len = GetDlgItemTextW(hwndDlg, IDC_GINALOADFAILED, templateText, MAX_PATH);
384 if (len)
385 {
386 wsprintfW(text, templateText, (LPWSTR)lParam);
387 SetDlgItemTextW(hwndDlg, IDC_GINALOADFAILED, text);
388 }
389 SetFocus(GetDlgItem(hwndDlg, IDOK));
390 return TRUE;
391 }
392 case WM_CLOSE:
393 {
394 EndDialog(hwndDlg, IDCANCEL);
395 return TRUE;
396 }
397 }
398
399 return FALSE;
400 }
401
402 int WINAPI
403 WinMain(
404 IN HINSTANCE hInstance,
405 IN HINSTANCE hPrevInstance,
406 IN LPSTR lpCmdLine,
407 IN int nShowCmd)
408 {
409 #if 0
410 LSA_STRING ProcessName, PackageName;
411 HANDLE LsaHandle;
412 LSA_OPERATIONAL_MODE Mode;
413 BOOLEAN Old;
414 ULONG AuthenticationPackage;
415 NTSTATUS Status;
416 #endif
417 ULONG HardErrorResponse;
418 MSG Msg;
419 HANDLE hThread;
420
421 UNREFERENCED_PARAMETER(hPrevInstance);
422 UNREFERENCED_PARAMETER(lpCmdLine);
423 UNREFERENCED_PARAMETER(nShowCmd);
424
425 hAppInstance = hInstance;
426
427 if (!RegisterLogonProcess(GetCurrentProcessId(), TRUE))
428 {
429 ERR("WL: Could not register logon process\n");
430 NtShutdownSystem(ShutdownNoReboot);
431 ExitProcess(0);
432 }
433
434 WLSession = (PWLSESSION)HeapAlloc(GetProcessHeap(), 0, sizeof(WLSESSION));
435 if (!WLSession)
436 {
437 ERR("WL: Could not allocate memory for winlogon instance\n");
438 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
439 ExitProcess(1);
440 }
441 ZeroMemory(WLSession, sizeof(WLSESSION));
442 WLSession->DialogTimeout = 120; /* 2 minutes */
443
444 if (!CreateWindowStationAndDesktops(WLSession))
445 {
446 ERR("WL: Could not create window station and desktops\n");
447 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
448 ExitProcess(1);
449 }
450 LockWorkstation(WLSession);
451
452 /* Load default keyboard layouts */
453 if (!InitKeyboardLayouts())
454 {
455 ERR("WL: Could not preload keyboard layouts\n");
456 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
457 ExitProcess(1);
458 }
459
460 if (!StartServicesManager())
461 {
462 ERR("WL: Could not start services.exe\n");
463 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse);
464 ExitProcess(1);
465 }
466
467 if (!StartLsass())
468 {
469 ERR("WL: Failed to start lsass.exe service (error %lu)\n", GetLastError());
470 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, 0, OptionOk, &HardErrorResponse);
471 ExitProcess(1);
472 }
473
474 /* Load and initialize gina */
475 if (!GinaInit(WLSession))
476 {
477 ERR("WL: Failed to initialize Gina\n");
478 DialogBoxParam(hAppInstance, MAKEINTRESOURCE(IDD_GINALOADFAILED), GetDesktopWindow(), GinaLoadFailedWindowProc, (LPARAM)L"");
479 HandleShutdown(WLSession, WLX_SAS_ACTION_SHUTDOWN_REBOOT);
480 ExitProcess(1);
481 }
482
483 DisplayStatusMessage(WLSession, WLSession->WinlogonDesktop, IDS_REACTOSISSTARTINGUP);
484
485
486 /* Wait for the LSA server */
487 WaitForLsass();
488
489 #if 0
490 /* Connect to NetLogon service (lsass.exe) */
491 /* Real winlogon uses "Winlogon" */
492 RtlInitUnicodeString((PUNICODE_STRING)&ProcessName, L"Winlogon");
493 Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
494 if (Status == STATUS_PORT_CONNECTION_REFUSED)
495 {
496 /* Add the 'SeTcbPrivilege' privilege and try again */
497 Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, TRUE, &Old);
498 if (!NT_SUCCESS(Status))
499 {
500 ERR("RtlAdjustPrivilege() failed with error %lu\n", LsaNtStatusToWinError(Status));
501 return 1;
502 }
503 Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode);
504 }
505 if (!NT_SUCCESS(Status))
506 {
507 ERR("LsaRegisterLogonProcess() failed with error %lu\n", LsaNtStatusToWinError(Status));
508 return 1;
509 }
510
511 RtlInitUnicodeString((PUNICODE_STRING)&PackageName, MICROSOFT_KERBEROS_NAME_W);
512 Status = LsaLookupAuthenticationPackage(LsaHandle, &PackageName, &AuthenticationPackage);
513 if (!NT_SUCCESS(Status))
514 {
515 ERR("LsaLookupAuthenticationPackage() failed with error %lu\n", LsaNtStatusToWinError(Status));
516 LsaDeregisterLogonProcess(LsaHandle);
517 return 1;
518 }
519 #endif
520
521 /* Create a hidden window to get SAS notifications */
522 if (!InitializeSAS(WLSession))
523 {
524 ERR("WL: Failed to initialize SAS\n");
525 ExitProcess(2);
526 }
527
528 //DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_PREPARENETWORKCONNECTIONS);
529 //DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_APPLYINGCOMPUTERSETTINGS);
530
531 /* Display logged out screen */
532 WLSession->LogonStatus = WKSTA_IS_LOGGED_OFF;
533 RemoveStatusMessage(WLSession);
534
535 /* Check for pending setup */
536 if (GetSetupType() != 0)
537 {
538 TRACE("WL: Setup mode detected\n");
539
540 /* Run setup and reboot when done */
541 SwitchDesktop(WLSession->ApplicationDesktop);
542 RunSetup();
543 }
544 else
545 PostMessageW(WLSession->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_TIMEOUT, 0);
546
547 /* Play logon sound */
548 hThread = CreateThread(NULL, 0, PlayLogonSoundThread, NULL, 0, NULL);
549 if (hThread)
550 {
551 CloseHandle(hThread);
552 }
553
554 /* Tell kernel that CurrentControlSet is good (needed
555 * to support Last good known configuration boot) */
556 NtInitializeRegistry(CM_BOOT_FLAG_ACCEPTED | 1);
557
558 /* Message loop for the SAS window */
559 while (GetMessageW(&Msg, WLSession->SASWindow, 0, 0))
560 {
561 TranslateMessage(&Msg);
562 DispatchMessageW(&Msg);
563 }
564
565 /* We never go there */
566
567 return 0;
568 }