static NTSTATUS HandleLogoff( IN OUT PWLSESSION Session, IN UINT Flags) { PLOGOFF_SHUTDOWN_DATA LSData; PSECURITY_ATTRIBUTES psa; HANDLE hThread; DWORD exitCode; NTSTATUS Status; /* Prepare data for logoff thread */ LSData = HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA)); if (!LSData) { ERR("Failed to allocate mem for thread data\n"); return STATUS_NO_MEMORY; } LSData->Flags = Flags; LSData->Session = Session; Status = CreateLogoffSecurityAttributes(&psa); if (!NT_SUCCESS(Status)) { ERR("Failed to create a required security descriptor. Status 0x%08lx\n", Status); HeapFree(GetProcessHeap(), 0, LSData); return Status; } /* Run logoff thread */ hThread = CreateThread(psa, 0, LogoffShutdownThread, (LPVOID)LSData, 0, NULL); if (!hThread) { ERR("Unable to create logoff thread, error %lu\n", GetLastError()); DestroyLogoffSecurityAttributes(psa); HeapFree(GetProcessHeap(), 0, LSData); return STATUS_UNSUCCESSFUL; } WaitForSingleObject(hThread, INFINITE); if (!GetExitCodeThread(hThread, &exitCode)) { ERR("Unable to get exit code of logoff thread (error %lu)\n", GetLastError()); CloseHandle(hThread); DestroyLogoffSecurityAttributes(psa); HeapFree(GetProcessHeap(), 0, LSData); return STATUS_UNSUCCESSFUL; } CloseHandle(hThread); if (exitCode == 0) { ERR("Logoff thread returned failure\n"); DestroyLogoffSecurityAttributes(psa); HeapFree(GetProcessHeap(), 0, LSData); return STATUS_UNSUCCESSFUL; } SwitchDesktop(Session->WinlogonDesktop); // TODO: Play logoff sound! SetWindowStationUser(Session->InteractiveWindowStation, &LuidNone, NULL, 0); // DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_LOGGINGOFF); // FIXME: Closing network connections! // DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_CLOSINGNETWORKCONNECTIONS); /* Kill remaining COM apps. Only at logoff! */ hThread = CreateThread(psa, 0, KillComProcesses, (LPVOID)LSData, 0, NULL); if (hThread) { WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); } /* We're done with the SECURITY_DESCRIPTOR */ DestroyLogoffSecurityAttributes(psa); psa = NULL; HeapFree(GetProcessHeap(), 0, LSData); DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_SAVEYOURSETTINGS); UnloadUserProfile(Session->UserToken, Session->hProfileInfo); CallNotificationDlls(Session, LogoffHandler); CloseHandle(Session->UserToken); UpdatePerUserSystemParameters(0, FALSE); Session->LogonState = STATE_LOGGED_OFF; Session->UserToken = NULL; return STATUS_SUCCESS; }
static BOOL HandleLogon( IN OUT PWLSESSION Session) { PROFILEINFOW ProfileInfo; BOOL ret = FALSE; /* Loading personal settings */ DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_LOADINGYOURPERSONALSETTINGS); ProfileInfo.hProfile = INVALID_HANDLE_VALUE; if (0 == (Session->Options & WLX_LOGON_OPT_NO_PROFILE)) { if (Session->Profile == NULL || (Session->Profile->dwType != WLX_PROFILE_TYPE_V1_0 && Session->Profile->dwType != WLX_PROFILE_TYPE_V2_0)) { ERR("WL: Wrong profile\n"); goto cleanup; } /* Load the user profile */ ZeroMemory(&ProfileInfo, sizeof(PROFILEINFOW)); ProfileInfo.dwSize = sizeof(PROFILEINFOW); ProfileInfo.dwFlags = 0; ProfileInfo.lpUserName = Session->MprNotifyInfo.pszUserName; ProfileInfo.lpProfilePath = Session->Profile->pszProfile; if (Session->Profile->dwType >= WLX_PROFILE_TYPE_V2_0) { ProfileInfo.lpDefaultPath = Session->Profile->pszNetworkDefaultUserProfile; ProfileInfo.lpServerName = Session->Profile->pszServerName; ProfileInfo.lpPolicyPath = Session->Profile->pszPolicy; } if (!LoadUserProfileW(Session->UserToken, &ProfileInfo)) { ERR("WL: LoadUserProfileW() failed\n"); goto cleanup; } } /* Create environment block for the user */ if (!CreateUserEnvironment(Session)) { WARN("WL: SetUserEnvironment() failed\n"); goto cleanup; } CallNotificationDlls(Session, LogonHandler); DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_APPLYINGYOURPERSONALSETTINGS); UpdatePerUserSystemParameters(0, TRUE); /* Set default user language */ if (!SetDefaultLanguage(Session)) { WARN("WL: SetDefaultLanguage() failed\n"); goto cleanup; } AllowWinstaAccess(Session); /* Connect remote resources */ RestoreAllConnections(Session); if (!StartUserShell(Session)) { //WCHAR StatusMsg[256]; WARN("WL: WlxActivateUserShell() failed\n"); //LoadStringW(hAppInstance, IDS_FAILEDACTIVATEUSERSHELL, StatusMsg, sizeof(StatusMsg) / sizeof(StatusMsg[0])); //MessageBoxW(0, StatusMsg, NULL, MB_ICONERROR); goto cleanup; } CallNotificationDlls(Session, StartShellHandler); if (!InitializeScreenSaver(Session)) WARN("WL: Failed to initialize screen saver\n"); Session->hProfileInfo = ProfileInfo.hProfile; /* Logon has succeeded. Play sound. */ PlayLogonSound(Session); ret = TRUE; cleanup: if (Session->Profile) { HeapFree(GetProcessHeap(), 0, Session->Profile->pszProfile); HeapFree(GetProcessHeap(), 0, Session->Profile); } Session->Profile = NULL; if (!ret && ProfileInfo.hProfile != INVALID_HANDLE_VALUE) { UnloadUserProfile(Session->UserToken, ProfileInfo.hProfile); } RemoveStatusMessage(Session); if (!ret) { SetWindowStationUser(Session->InteractiveWindowStation, &LuidNone, NULL, 0); CloseHandle(Session->UserToken); Session->UserToken = NULL; } if (ret) { SwitchDesktop(Session->ApplicationDesktop); Session->LogonState = STATE_LOGGED_ON; } return ret; }
static VOID DoGenericAction( IN OUT PWLSESSION Session, IN DWORD wlxAction) { switch (wlxAction) { case WLX_SAS_ACTION_LOGON: /* 0x01 */ if (Session->LogonState == STATE_LOGGED_OFF_SAS) { if (!HandleLogon(Session)) { Session->Gina.Functions.WlxDisplaySASNotice(Session->Gina.Context); CallNotificationDlls(Session, LogonHandler); } } break; case WLX_SAS_ACTION_NONE: /* 0x02 */ if (Session->LogonState == STATE_LOGGED_OFF_SAS) { Session->LogonState = STATE_LOGGED_OFF; Session->Gina.Functions.WlxDisplaySASNotice(Session->Gina.Context); } else if (Session->LogonState == STATE_LOGGED_ON_SAS) { Session->LogonState = STATE_LOGGED_ON; } else if (Session->LogonState == STATE_LOCKED_SAS) { Session->LogonState = STATE_LOCKED; Session->Gina.Functions.WlxDisplayLockedNotice(Session->Gina.Context); } break; case WLX_SAS_ACTION_LOCK_WKSTA: /* 0x03 */ if (Session->Gina.Functions.WlxIsLockOk(Session->Gina.Context)) { SwitchDesktop(Session->WinlogonDesktop); Session->LogonState = STATE_LOCKED; Session->Gina.Functions.WlxDisplayLockedNotice(Session->Gina.Context); CallNotificationDlls(Session, LockHandler); } break; case WLX_SAS_ACTION_LOGOFF: /* 0x04 */ case WLX_SAS_ACTION_SHUTDOWN: /* 0x05 */ case WLX_SAS_ACTION_SHUTDOWN_POWER_OFF: /* 0x0a */ case WLX_SAS_ACTION_SHUTDOWN_REBOOT: /* 0x0b */ if (Session->LogonState != STATE_LOGGED_OFF) { if (!Session->Gina.Functions.WlxIsLogoffOk(Session->Gina.Context)) break; if (!NT_SUCCESS(HandleLogoff(Session, EWX_LOGOFF))) { RemoveStatusMessage(Session); break; } Session->Gina.Functions.WlxLogoff(Session->Gina.Context); } if (WLX_SHUTTINGDOWN(wlxAction)) { // FIXME: WlxShutdown should be done from inside HandleShutdown, // after having displayed "ReactOS is shutting down" message. Session->Gina.Functions.WlxShutdown(Session->Gina.Context, wlxAction); if (!NT_SUCCESS(HandleShutdown(Session, wlxAction))) { RemoveStatusMessage(Session); Session->Gina.Functions.WlxDisplaySASNotice(Session->Gina.Context); } } else { RemoveStatusMessage(Session); Session->Gina.Functions.WlxDisplaySASNotice(Session->Gina.Context); } break; case WLX_SAS_ACTION_TASKLIST: /* 0x07 */ SwitchDesktop(Session->ApplicationDesktop); Session->LogonState = STATE_LOGGED_ON; StartTaskManager(Session); break; case WLX_SAS_ACTION_UNLOCK_WKSTA: /* 0x08 */ SwitchDesktop(Session->ApplicationDesktop); Session->LogonState = STATE_LOGGED_ON; CallNotificationDlls(Session, UnlockHandler); break; default: WARN("Unknown SAS action 0x%lx\n", wlxAction); } }
NTSTATUS HandleShutdown( IN OUT PWLSESSION Session, IN DWORD wlxAction) { PLOGOFF_SHUTDOWN_DATA LSData; HANDLE hThread; DWORD exitCode; BOOLEAN Old; // SwitchDesktop(Session->WinlogonDesktop); DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_REACTOSISSHUTTINGDOWN); /* Prepare data for shutdown thread */ LSData = HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA)); if (!LSData) { ERR("Failed to allocate mem for thread data\n"); return STATUS_NO_MEMORY; } if (wlxAction == WLX_SAS_ACTION_SHUTDOWN_POWER_OFF) LSData->Flags = EWX_POWEROFF; else if (wlxAction == WLX_SAS_ACTION_SHUTDOWN_REBOOT) LSData->Flags = EWX_REBOOT; else LSData->Flags = EWX_SHUTDOWN; LSData->Session = Session; // FIXME: We may need to specify this flag to really force application kill // (we are shutting down ReactOS, not just logging off so no hangs, etc... // should be allowed). // LSData->Flags |= EWX_FORCE; /* Run shutdown thread */ hThread = CreateThread(NULL, 0, LogoffShutdownThread, (LPVOID)LSData, 0, NULL); if (!hThread) { ERR("Unable to create shutdown thread, error %lu\n", GetLastError()); HeapFree(GetProcessHeap(), 0, LSData); return STATUS_UNSUCCESSFUL; } WaitForSingleObject(hThread, INFINITE); HeapFree(GetProcessHeap(), 0, LSData); if (!GetExitCodeThread(hThread, &exitCode)) { ERR("Unable to get exit code of shutdown thread (error %lu)\n", GetLastError()); CloseHandle(hThread); return STATUS_UNSUCCESSFUL; } CloseHandle(hThread); if (exitCode == 0) { ERR("Shutdown thread returned failure\n"); return STATUS_UNSUCCESSFUL; } CallNotificationDlls(Session, ShutdownHandler); /* Destroy SAS window */ UninitializeSAS(Session); /* Now we can shut down NT */ ERR("Shutting down NT...\n"); RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &Old); if (wlxAction == WLX_SAS_ACTION_SHUTDOWN_REBOOT) { NtShutdownSystem(ShutdownReboot); } else { if (FALSE) { /* FIXME - only show this dialog if it's a shutdown and the computer doesn't support APM */ DialogBox(hAppInstance, MAKEINTRESOURCE(IDD_SHUTDOWNCOMPUTER), GetDesktopWindow(), ShutdownComputerWindowProc); } NtShutdownSystem(ShutdownNoReboot); } RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, Old, FALSE, &Old); return STATUS_SUCCESS; }
VOID StartScreenSaver( IN PWLSESSION Session) { HKEY hKey = NULL, hCurrentUser = NULL; WCHAR szApplicationName[MAX_PATH]; WCHAR szCommandLine[MAX_PATH + 3]; DWORD bufferSize = sizeof(szApplicationName) - sizeof(WCHAR); DWORD dwType; STARTUPINFOW StartupInfo; PROCESS_INFORMATION ProcessInformation; HANDLE HandleArray[2]; LONG rc; DWORD Status; BOOL ret = FALSE; if (!ImpersonateLoggedOnUser(Session->UserToken)) { ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError()); goto cleanup; } rc = RegOpenCurrentUser(KEY_READ, &hCurrentUser); if (rc != ERROR_SUCCESS) { ERR("WL: RegOpenCurrentUser error %lu\n", rc); goto cleanup; } rc = RegOpenKeyExW(hCurrentUser, L"Control Panel\\Desktop", 0, KEY_QUERY_VALUE, &hKey); if (rc != ERROR_SUCCESS) { ERR("WL: RegOpenKeyEx error %lu\n", rc); goto cleanup; } rc = RegQueryValueExW(hKey, L"SCRNSAVE.EXE", 0, &dwType, (LPBYTE)szApplicationName, &bufferSize); if (rc != ERROR_SUCCESS || dwType != REG_SZ) { if (rc != ERROR_FILE_NOT_FOUND) ERR("WL: RegQueryValueEx error %lu\n", rc); goto cleanup; } if (bufferSize == 0) { ERR("WL: Buffer size is NULL!\n"); goto cleanup; } szApplicationName[bufferSize / sizeof(WCHAR)] = 0; /* Terminate the string */ if (wcslen(szApplicationName) == 0) { ERR("WL: Application Name length is zero!\n"); goto cleanup; } wsprintfW(szCommandLine, L"%s /s", szApplicationName); TRACE("WL: Executing %S\n", szCommandLine); ZeroMemory(&StartupInfo, sizeof(STARTUPINFOW)); ZeroMemory(&ProcessInformation, sizeof(PROCESS_INFORMATION)); StartupInfo.cb = sizeof(STARTUPINFOW); StartupInfo.dwFlags = STARTF_SCRNSAVER; /* FIXME: run the screen saver on the screen saver desktop */ ret = CreateProcessW(szApplicationName, szCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcessInformation); if (!ret) { ERR("WL: Unable to start %S, error %lu\n", szApplicationName, GetLastError()); goto cleanup; } CloseHandle(ProcessInformation.hThread); SystemParametersInfoW(SPI_SETSCREENSAVERRUNNING, TRUE, NULL, 0); CallNotificationDlls(Session, StartScreenSaverHandler); /* Wait the end of the process or some other activity */ ResetEvent(Session->hUserActivity); HandleArray[0] = ProcessInformation.hProcess; HandleArray[1] = Session->hUserActivity; Status = WaitForMultipleObjects(2, HandleArray, FALSE, INFINITE); if (Status == WAIT_OBJECT_0 + 1) { /* Kill the screen saver */ TerminateProcess(ProcessInformation.hProcess, 0); } SetEvent(Session->hEndOfScreenSaver); CloseHandle(ProcessInformation.hProcess); CallNotificationDlls(Session, StopScreenSaverHandler); cleanup: RevertToSelf(); if (hKey) RegCloseKey(hKey); if (hCurrentUser) RegCloseKey(hCurrentUser); if (!ret) { PostMessageW(Session->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_SCRNSVR_ACTIVITY, 0); #ifndef USE_GETLASTINPUTINFO InterlockedExchange((LONG*)&Session->LastActivity, GetTickCount()); #endif } }
int WINAPI WinMain( IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPSTR lpCmdLine, IN int nShowCmd) { #if 0 LSA_STRING ProcessName, PackageName; HANDLE LsaHandle; LSA_OPERATIONAL_MODE Mode; BOOLEAN Old; ULONG AuthenticationPackage; NTSTATUS Status; #endif ULONG HardErrorResponse; MSG Msg; UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); UNREFERENCED_PARAMETER(nShowCmd); hAppInstance = hInstance; /* Make us critical */ RtlSetProcessIsCritical(TRUE, NULL, FALSE); RtlSetThreadIsCritical(TRUE, NULL, FALSE); if (!RegisterLogonProcess(GetCurrentProcessId(), TRUE)) { ERR("WL: Could not register logon process\n"); NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse); ExitProcess(1); } WLSession = (PWLSESSION)HeapAlloc(GetProcessHeap(), 0, sizeof(WLSESSION)); if (!WLSession) { ERR("WL: Could not allocate memory for winlogon instance\n"); NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse); ExitProcess(1); } ZeroMemory(WLSession, sizeof(WLSESSION)); WLSession->DialogTimeout = 120; /* 2 minutes */ /* Initialize the dialog tracking list */ InitDialogListHead(); if (!CreateWindowStationAndDesktops(WLSession)) { ERR("WL: Could not create window station and desktops\n"); NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse); ExitProcess(1); } LockWorkstation(WLSession); /* Load default keyboard layouts */ if (!InitKeyboardLayouts()) { ERR("WL: Could not preload keyboard layouts\n"); NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse); ExitProcess(1); } if (!StartRpcServer()) { ERR("WL: Could not start the RPC server\n"); NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse); ExitProcess(1); } if (!StartServicesManager()) { ERR("WL: Could not start services.exe\n"); NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse); ExitProcess(1); } if (!StartLsass()) { ERR("WL: Failed to start lsass.exe service (error %lu)\n", GetLastError()); NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 0, 0, NULL, OptionOk, &HardErrorResponse); ExitProcess(1); } /* Wait for the LSA server */ WaitForLsass(); /* Init Notifications */ InitNotifications(); /* Load and initialize gina */ if (!GinaInit(WLSession)) { ERR("WL: Failed to initialize Gina\n"); // FIXME: Retrieve the real name of the GINA DLL we were trying to load. // It is known only inside the GinaInit function... DialogBoxParam(hAppInstance, MAKEINTRESOURCE(IDD_GINALOADFAILED), GetDesktopWindow(), GinaLoadFailedWindowProc, (LPARAM)L"msgina.dll"); HandleShutdown(WLSession, WLX_SAS_ACTION_SHUTDOWN_REBOOT); ExitProcess(1); } DisplayStatusMessage(WLSession, WLSession->WinlogonDesktop, IDS_REACTOSISSTARTINGUP); #if 0 /* Connect to NetLogon service (lsass.exe) */ /* Real winlogon uses "Winlogon" */ RtlInitUnicodeString((PUNICODE_STRING)&ProcessName, L"Winlogon"); Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode); if (Status == STATUS_PORT_CONNECTION_REFUSED) { /* Add the 'SeTcbPrivilege' privilege and try again */ Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, TRUE, &Old); if (!NT_SUCCESS(Status)) { ERR("RtlAdjustPrivilege() failed with error %lu\n", LsaNtStatusToWinError(Status)); return 1; } Status = LsaRegisterLogonProcess(&ProcessName, &LsaHandle, &Mode); } if (!NT_SUCCESS(Status)) { ERR("LsaRegisterLogonProcess() failed with error %lu\n", LsaNtStatusToWinError(Status)); return 1; } RtlInitUnicodeString((PUNICODE_STRING)&PackageName, MICROSOFT_KERBEROS_NAME_W); Status = LsaLookupAuthenticationPackage(LsaHandle, &PackageName, &AuthenticationPackage); if (!NT_SUCCESS(Status)) { ERR("LsaLookupAuthenticationPackage() failed with error %lu\n", LsaNtStatusToWinError(Status)); LsaDeregisterLogonProcess(LsaHandle); return 1; } #endif CallNotificationDlls(WLSession, StartupHandler); /* Create a hidden window to get SAS notifications */ if (!InitializeSAS(WLSession)) { ERR("WL: Failed to initialize SAS\n"); ExitProcess(2); } // DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_PREPARENETWORKCONNECTIONS); // DisplayStatusMessage(Session, Session->WinlogonDesktop, IDS_APPLYINGCOMPUTERSETTINGS); /* Display logged out screen */ WLSession->LogonState = STATE_INIT; RemoveStatusMessage(WLSession); /* Check for pending setup */ if (GetSetupType() != 0) { /* Run setup and reboot when done */ TRACE("WL: Setup mode detected\n"); RunSetup(); } else { PostMessageW(WLSession->SASWindow, WLX_WM_SAS, WLX_SAS_TYPE_CTRL_ALT_DEL, 0); } (void)LoadLibraryW(L"sfc_os.dll"); /* Tell kernel that CurrentControlSet is good (needed * to support Last good known configuration boot) */ NtInitializeRegistry(CM_BOOT_FLAG_ACCEPTED | 1); /* Message loop for the SAS window */ while (GetMessageW(&Msg, WLSession->SASWindow, 0, 0)) { TranslateMessage(&Msg); DispatchMessageW(&Msg); } CleanupNotifications(); /* We never go there */ return 0; }