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