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 <ndk/cmfuncs.h> 16 17 /* GLOBALS ******************************************************************/ 18 19 HINSTANCE hAppInstance; 20 PWLSESSION WLSession = NULL; 21 22 /* FUNCTIONS *****************************************************************/ 23 24 static 25 BOOL 26 StartServicesManager(VOID) 27 { 28 STARTUPINFOW StartupInfo; 29 PROCESS_INFORMATION ProcessInformation; 30 LPCWSTR ServiceString = L"services.exe"; 31 BOOL res; 32 33 /* Start the service control manager (services.exe) */ 34 ZeroMemory(&StartupInfo, sizeof(STARTUPINFOW)); 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(ServiceString, 46 NULL, 47 NULL, 48 NULL, 49 FALSE, 50 DETACHED_PROCESS, 51 NULL, 52 NULL, 53 &StartupInfo, 54 &ProcessInformation); 55 if (!res) 56 { 57 ERR("WL: Failed to execute services (error %lu)\n", GetLastError()); 58 return FALSE; 59 } 60 61 TRACE("WL: Created new process - %S\n", ServiceString); 62 63 CloseHandle(ProcessInformation.hThread); 64 CloseHandle(ProcessInformation.hProcess); 65 66 TRACE("WL: StartServicesManager() done.\n"); 67 68 return TRUE; 69 } 70 71 72 static 73 BOOL 74 StartLsass(VOID) 75 { 76 STARTUPINFOW StartupInfo; 77 PROCESS_INFORMATION ProcessInformation; 78 LPCWSTR ServiceString = L"lsass.exe"; 79 BOOL res; 80 81 /* Start the local security authority subsystem (lsass.exe) */ 82 ZeroMemory(&StartupInfo, sizeof(STARTUPINFOW)); 83 StartupInfo.cb = sizeof(StartupInfo); 84 StartupInfo.lpReserved = NULL; 85 StartupInfo.lpDesktop = NULL; 86 StartupInfo.lpTitle = NULL; 87 StartupInfo.dwFlags = 0; 88 StartupInfo.cbReserved2 = 0; 89 StartupInfo.lpReserved2 = 0; 90 91 TRACE("WL: Creating new process - %S\n", ServiceString); 92 93 res = CreateProcessW(ServiceString, 94 NULL, 95 NULL, 96 NULL, 97 FALSE, 98 DETACHED_PROCESS, 99 NULL, 100 NULL, 101 &StartupInfo, 102 &ProcessInformation); 103 104 TRACE("WL: Created new process - %S\n", ServiceString); 105 106 CloseHandle(ProcessInformation.hThread); 107 CloseHandle(ProcessInformation.hProcess); 108 109 return res; 110 } 111 112 113 static 114 VOID 115 WaitForLsass(VOID) 116 { 117 HANDLE hEvent; 118 DWORD dwError; 119 120 hEvent = CreateEventW(NULL, 121 TRUE, 122 FALSE, 123 L"LSA_RPC_SERVER_ACTIVE"); 124 if (hEvent == NULL) 125 { 126 dwError = GetLastError(); 127 TRACE("WL: Failed to create the notification event (Error %lu)\n", dwError); 128 129 if (dwError == ERROR_ALREADY_EXISTS) 130 { 131 hEvent = OpenEventW(SYNCHRONIZE, 132 FALSE, 133 L"LSA_RPC_SERVER_ACTIVE"); 134 if (hEvent == NULL) 135 { 136 ERR("WL: Could not open the notification event (Error %lu)\n", GetLastError()); 137 return; 138 } 139 } 140 } 141 142 TRACE("WL: Wait for the LSA server!\n"); 143 WaitForSingleObject(hEvent, INFINITE); 144 TRACE("WL: LSA server running!\n"); 145 146 CloseHandle(hEvent); 147 } 148 149 150 static 151 VOID 152 UpdateTcpIpInformation(VOID) 153 { 154 LONG lError; 155 HKEY hKey = NULL; 156 DWORD dwType, dwSize; 157 PWSTR pszBuffer; 158 WCHAR szBuffer[128] = L""; 159 160 lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 161 L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 162 0, 163 KEY_QUERY_VALUE | KEY_SET_VALUE, 164 &hKey); 165 if (lError != ERROR_SUCCESS) 166 { 167 ERR("WL: RegOpenKeyExW(\"HKLM\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters\") failed (error %lu)\n", lError); 168 return; 169 } 170 171 /* 172 * Read the "NV Hostname" value and copy it into the "Hostname" value. 173 */ 174 175 pszBuffer = szBuffer; 176 dwSize = ARRAYSIZE(szBuffer); 177 178 lError = RegQueryValueExW(hKey, 179 L"NV Hostname", 180 NULL, 181 &dwType, 182 (LPBYTE)pszBuffer, 183 &dwSize); 184 if (((lError == ERROR_INSUFFICIENT_BUFFER) || (lError == ERROR_MORE_DATA)) && (dwType == REG_SZ)) 185 { 186 pszBuffer = HeapAlloc(GetProcessHeap(), 0, dwSize); 187 if (pszBuffer) 188 { 189 lError = RegQueryValueExW(hKey, 190 L"NV Hostname", 191 NULL, 192 &dwType, 193 (LPBYTE)pszBuffer, 194 &dwSize); 195 } 196 else 197 { 198 ERR("WL: Could not reallocate memory for pszBuffer\n"); 199 } 200 } 201 if ((lError == ERROR_SUCCESS) && (dwType == REG_SZ)) 202 { 203 TRACE("NV Hostname is '%S'.\n", pszBuffer); 204 205 lError = RegSetValueExW(hKey, 206 L"Hostname", 207 0, 208 REG_SZ, 209 (LPBYTE)pszBuffer, 210 dwSize); 211 if (lError != ERROR_SUCCESS) 212 ERR("WL: RegSetValueExW(\"Hostname\") failed (error %lu)\n", lError); 213 } 214 215 /* 216 * Read the "NV Domain" value and copy it into the "Domain" value. 217 */ 218 219 // pszBuffer = szBuffer; 220 // dwSize = ARRAYSIZE(szBuffer); 221 222 lError = RegQueryValueExW(hKey, 223 L"NV Domain", 224 NULL, 225 &dwType, 226 (LPBYTE)pszBuffer, 227 &dwSize); 228 if (((lError == ERROR_INSUFFICIENT_BUFFER) || (lError == ERROR_MORE_DATA)) && (dwType == REG_SZ)) 229 { 230 if (pszBuffer != szBuffer) 231 { 232 PWSTR pszNewBuffer; 233 pszNewBuffer = HeapReAlloc(GetProcessHeap(), 0, pszBuffer, dwSize); 234 if (pszNewBuffer) 235 { 236 pszBuffer = pszNewBuffer; 237 } 238 else 239 { 240 HeapFree(GetProcessHeap(), 0, pszBuffer); 241 pszBuffer = NULL; 242 } 243 } 244 else 245 { 246 pszBuffer = HeapAlloc(GetProcessHeap(), 0, dwSize); 247 } 248 if (pszBuffer) 249 { 250 lError = RegQueryValueExW(hKey, 251 L"NV Domain", 252 NULL, 253 &dwType, 254 (LPBYTE)pszBuffer, 255 &dwSize); 256 } 257 else 258 { 259 ERR("WL: Could not reallocate memory for pszBuffer\n"); 260 } 261 } 262 if ((lError == ERROR_SUCCESS) && (dwType == REG_SZ)) 263 { 264 TRACE("NV Domain is '%S'.\n", pszBuffer); 265 266 lError = RegSetValueExW(hKey, 267 L"Domain", 268 0, 269 REG_SZ, 270 (LPBYTE)pszBuffer, 271 dwSize); 272 if (lError != ERROR_SUCCESS) 273 ERR("WL: RegSetValueExW(\"Domain\") failed (error %lu)\n", lError); 274 } 275 276 if (pszBuffer != szBuffer) 277 HeapFree(GetProcessHeap(), 0, pszBuffer); 278 279 RegCloseKey(hKey); 280 } 281 282 283 static 284 BOOL 285 InitKeyboardLayouts(VOID) 286 { 287 WCHAR wszKeyName[12], wszKLID[10]; 288 DWORD dwSize = sizeof(wszKLID), dwType, i = 1; 289 HKEY hKey; 290 UINT Flags; 291 BOOL bRet = FALSE; 292 293 /* Open registry key with preloaded layouts */ 294 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", 0, KEY_READ, &hKey) == ERROR_SUCCESS) 295 { 296 while (TRUE) 297 { 298 /* Read values with integer names only */ 299 swprintf(wszKeyName, L"%d", i++); 300 if (RegQueryValueExW(hKey, wszKeyName, NULL, &dwType, (LPBYTE)wszKLID, &dwSize) != ERROR_SUCCESS) 301 { 302 /* There is no more entries */ 303 break; 304 } 305 306 /* Only REG_SZ values are valid */ 307 if (dwType != REG_SZ) 308 { 309 ERR("Wrong type: %ws!\n", wszKLID); 310 continue; 311 } 312 313 /* Load keyboard layout with given locale id */ 314 Flags = KLF_SUBSTITUTE_OK; 315 if (i > 1) 316 Flags |= KLF_NOTELLSHELL|KLF_REPLACELANG; 317 else // First layout 318 Flags |= KLF_ACTIVATE; // |0x40000000 319 if (!LoadKeyboardLayoutW(wszKLID, Flags)) 320 { 321 ERR("LoadKeyboardLayoutW(%ws) failed!\n", wszKLID); 322 continue; 323 } 324 else 325 { 326 /* We loaded at least one layout - success */ 327 bRet = TRUE; 328 } 329 } 330 331 /* Close the key now */ 332 RegCloseKey(hKey); 333 } 334 else 335 WARN("RegOpenKeyExW(Keyboard Layout\\Preload) failed!\n"); 336 337 if (!bRet) 338 { 339 /* If we failed, load US keyboard layout */ 340 if (LoadKeyboardLayoutW(L"00000409", KLF_ACTIVATE | KLF_SUBSTITUTE_OK | KLF_REPLACELANG | KLF_SETFORPROCESS)) 341 bRet = TRUE; 342 } 343 344 return bRet; 345 } 346 347 348 BOOL 349 DisplayStatusMessage( 350 IN PWLSESSION Session, 351 IN HDESK hDesktop, 352 IN UINT ResourceId) 353 { 354 WCHAR StatusMsg[MAX_PATH]; 355 356 if (Session->Gina.Version < WLX_VERSION_1_3) 357 return TRUE; 358 359 if (Session->SuppressStatus) 360 return TRUE; 361 362 if (LoadStringW(hAppInstance, ResourceId, StatusMsg, MAX_PATH) == 0) 363 return FALSE; 364 365 return Session->Gina.Functions.WlxDisplayStatusMessage(Session->Gina.Context, hDesktop, 0, NULL, StatusMsg); 366 } 367 368 369 BOOL 370 RemoveStatusMessage( 371 IN PWLSESSION Session) 372 { 373 if (Session->Gina.Version < WLX_VERSION_1_3) 374 return TRUE; 375 376 return Session->Gina.Functions.WlxRemoveStatusMessage(Session->Gina.Context); 377 } 378 379 380 static 381 INT_PTR 382 CALLBACK 383 GinaLoadFailedWindowProc( 384 IN HWND hwndDlg, 385 IN UINT uMsg, 386 IN WPARAM wParam, 387 IN LPARAM lParam) 388 { 389 switch (uMsg) 390 { 391 case WM_COMMAND: 392 { 393 switch (LOWORD(wParam)) 394 { 395 case IDOK: 396 EndDialog(hwndDlg, IDOK); 397 return TRUE; 398 } 399 break; 400 } 401 402 case WM_INITDIALOG: 403 { 404 int len; 405 WCHAR templateText[MAX_PATH], text[MAX_PATH]; 406 407 len = GetDlgItemTextW(hwndDlg, IDC_GINALOADFAILED, templateText, MAX_PATH); 408 if (len) 409 { 410 wsprintfW(text, templateText, (LPWSTR)lParam); 411 SetDlgItemTextW(hwndDlg, IDC_GINALOADFAILED, text); 412 } 413 414 SetFocus(GetDlgItem(hwndDlg, IDOK)); 415 return TRUE; 416 } 417 418 case WM_CLOSE: 419 { 420 EndDialog(hwndDlg, IDCANCEL); 421 return TRUE; 422 } 423 } 424 425 return FALSE; 426 } 427 428 429 int 430 WINAPI 431 WinMain( 432 IN HINSTANCE hInstance, 433 IN HINSTANCE hPrevInstance, 434 IN LPSTR lpCmdLine, 435 IN int nShowCmd) 436 { 437 #if 0 438 LSA_STRING ProcessName, PackageName; 439 HANDLE LsaHandle; 440 LSA_OPERATIONAL_MODE Mode; 441 BOOLEAN Old; 442 ULONG AuthenticationPackage; 443 NTSTATUS Status; 444 #endif 445 ULONG HardErrorResponse; 446 MSG Msg; 447 448 UNREFERENCED_PARAMETER(hPrevInstance); 449 UNREFERENCED_PARAMETER(lpCmdLine); 450 UNREFERENCED_PARAMETER(nShowCmd); 451 452 hAppInstance = hInstance; 453 454 /* Make us critical */ 455 RtlSetProcessIsCritical(TRUE, NULL, FALSE); 456 RtlSetThreadIsCritical(TRUE, NULL, FALSE); 457 458 /* Update the cached TCP/IP Information in the registry */ 459 UpdateTcpIpInformation(); 460 461 if (!RegisterLogonProcess(GetCurrentProcessId(), TRUE)) 462 { 463 ERR("WL: Could not register logon process\n"); 464 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse); 465 ExitProcess(1); 466 } 467 468 WLSession = (PWLSESSION)HeapAlloc(GetProcessHeap(), 0, sizeof(WLSESSION)); 469 if (!WLSession) 470 { 471 ERR("WL: Could not allocate memory for winlogon instance\n"); 472 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse); 473 ExitProcess(1); 474 } 475 476 ZeroMemory(WLSession, sizeof(WLSESSION)); 477 WLSession->DialogTimeout = 120; /* 2 minutes */ 478 479 /* Initialize the dialog tracking list */ 480 InitDialogListHead(); 481 482 if (!CreateWindowStationAndDesktops(WLSession)) 483 { 484 ERR("WL: Could not create window station and desktops\n"); 485 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse); 486 ExitProcess(1); 487 } 488 489 LockWorkstation(WLSession); 490 491 /* Load default keyboard layouts */ 492 if (!InitKeyboardLayouts()) 493 { 494 ERR("WL: Could not preload keyboard layouts\n"); 495 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse); 496 ExitProcess(1); 497 } 498 499 if (!StartRpcServer()) 500 { 501 ERR("WL: Could not start the RPC server\n"); 502 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse); 503 ExitProcess(1); 504 } 505 506 if (!StartServicesManager()) 507 { 508 ERR("WL: Could not start services.exe\n"); 509 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse); 510 ExitProcess(1); 511 } 512 513 if (!StartLsass()) 514 { 515 ERR("WL: Failed to start lsass.exe service (error %lu)\n", GetLastError()); 516 NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse); 517 ExitProcess(1); 518 } 519 520 /* Wait for the LSA server */ 521 WaitForLsass(); 522 523 /* Init Notifications */ 524 InitNotifications(); 525 526 /* Load and initialize gina */ 527 if (!GinaInit(WLSession)) 528 { 529 ERR("WL: Failed to initialize Gina\n"); 530 // FIXME: Retrieve the real name of the GINA DLL we were trying to load. 531 // It is known only inside the GinaInit function... 532 DialogBoxParam(hAppInstance, MAKEINTRESOURCE(IDD_GINALOADFAILED), GetDesktopWindow(), GinaLoadFailedWindowProc, (LPARAM)L"msgina.dll"); 533 HandleShutdown(WLSession, WLX_SAS_ACTION_SHUTDOWN_REBOOT); 534 ExitProcess(1); 535 } 536 537 DisplayStatusMessage(WLSession, WLSession->WinlogonDesktop, IDS_REACTOSISSTARTINGUP); 538 539 #if 0 540 /* Connect to NetLogon service (lsass.exe) */ 541 /* Real winlogon uses "Winlogon" */ 542 RtlInitUnicodeString((PUNICODE_STRING)&ProcessName, L"Winlogon"); 543 Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode); 544 if (Status == STATUS_PORT_CONNECTION_REFUSED) 545 { 546 /* Add the 'SeTcbPrivilege' privilege and try again */ 547 Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, TRUE, &Old); 548 if (!NT_SUCCESS(Status)) 549 { 550 ERR("RtlAdjustPrivilege() failed with error %lu\n", LsaNtStatusToWinError(Status)); 551 return 1; 552 } 553 554 Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode); 555 } 556 557 if (!NT_SUCCESS(Status)) 558 { 559 ERR("LsaRegisterLogonProcess() failed with error %lu\n", LsaNtStatusToWinError(Status)); 560 return 1; 561 } 562 563 RtlInitUnicodeString((PUNICODE_STRING)&PackageName, MICROSOFT_KERBEROS_NAME_W); 564 Status = LsaLookupAuthenticationPackage(LsaHandle, &PackageName, &AuthenticationPackage); 565 if (!NT_SUCCESS(Status)) 566 { 567 ERR("LsaLookupAuthenticationPackage() failed with error %lu\n", LsaNtStatusToWinError(Status)); 568 LsaDeregisterLogonProcess(LsaHandle); 569 return 1; 570 } 571 #endif 572 573 CallNotificationDlls(WLSession, StartupHandler); 574 575 /* Create a hidden window to get SAS notifications */ 576 if (!InitializeSAS(WLSession)) 577 { 578 ERR("WL: Failed to initialize SAS\n"); 579 ExitProcess(2); 580 } 581 582 // DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_PREPARENETWORKCONNECTIONS); 583 // DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_APPLYINGCOMPUTERSETTINGS); 584 585 /* Display logged out screen */ 586 WLSession->LogonState = STATE_INIT; 587 RemoveStatusMessage(WLSession); 588 589 /* Check for pending setup */ 590 if (GetSetupType() != 0) 591 { 592 /* Run setup and reboot when done */ 593 TRACE("WL: Setup mode detected\n"); 594 RunSetup(); 595 } 596 else 597 { 598 PostMessageW(WLSession->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_CTRL_ALT_DEL, 0); 599 } 600 601 (void)LoadLibraryW(L"sfc_os.dll"); 602 603 /* Tell kernel that CurrentControlSet is good (needed 604 * to support Last good known configuration boot) */ 605 NtInitializeRegistry(CM_BOOT_FLAG_ACCEPTED | 1); 606 607 /* Message loop for the SAS window */ 608 while (GetMessageW(&Msg, WLSession->SASWindow, 0, 0)) 609 { 610 TranslateMessage(&Msg); 611 DispatchMessageW(&Msg); 612 } 613 614 CleanupNotifications(); 615 616 /* We never go there */ 617 618 return 0; 619 } 620