/*++ Copyright (c) 1998 Microsoft Corporation Module Name: dirscan.c Abstract: Implementation of directory scanner. Author: Wesley Witt (wesw) 18-Dec-1998 Revision History: Andrew Ritz (andrewr) 7-Jul-1999 : added comments --*/ #include "sfcp.h" #pragma hdrstop NTSTATUS SfcDoScan( IN PSCAN_PARAMS ScanParams ) /*++ Routine Description: Scan the set of protected DLLs and compare them with the cached versions. If any are different, copy the correct one back. Arguments: ScanParams - pointer to SCAN_PARAMS structure indicating scanning behavior (such as whether to display UI or not) Return Value: NTSTATUS code of any fatal error. --*/ { NTSTATUS StatusPopulate, StatusSxsScan, rStatus; StatusPopulate = SfcPopulateCache( ScanParams->ProgressWindow, TRUE, ScanParams->AllowUI, NULL ) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; StatusSxsScan = SfcDoForcedSxsScan( ScanParams->ProgressWindow, TRUE, ScanParams->AllowUI ); // Figure out which of these two failed. We really do need to do both, rather than // just returning after a check of the SfcPopulateCache call. if ( !NT_SUCCESS( StatusPopulate ) ) { rStatus = StatusPopulate; DebugPrint1( LVL_MINIMAL, L"Failed scanning SFC: 0x%08x\n", rStatus ); } else if ( !NT_SUCCESS( StatusSxsScan ) ) { rStatus = StatusSxsScan; DebugPrint1( LVL_MINIMAL, L"Failed scanning SxS: 0x%08x\n", rStatus ); } else { rStatus = STATUS_SUCCESS; } return rStatus; } INT_PTR CALLBACK ProgressDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { UNREFERENCED_PARAMETER( lParam ); if (uMsg == WM_INITDIALOG) { if (hEventScanCancel == NULL) { EnableWindow( GetDlgItem(hwndDlg,IDCANCEL), FALSE ); } CenterDialog( hwndDlg ); ShowWindow( hwndDlg, SW_SHOWNORMAL ); UpdateWindow( hwndDlg ); SetForegroundWindow( hwndDlg ); return TRUE; } if (uMsg == WM_COMMAND && LOWORD(wParam) == IDCANCEL) { SetEvent( hEventScanCancel ); EndDialog( hwndDlg, 0 ); } return FALSE; } NTSTATUS SfcScanProtectedDlls( PSCAN_PARAMS ScanParams ) /*++ Routine Description: Thread routine to scan for protected dlls on the system. The routine creates a dialog so the user can tell what's going on (if requested) and then calls into the main scanning routine. Arguments: ScanParams - pointer to SCAN_PARAMS structure indicating scanning behavior (such as whether to display UI or not) Return Value: NTSTATUS code indicating outcome. --*/ { NTSTATUS Status = STATUS_SUCCESS; HWND hDlg = NULL; #if 0 HDESK hDesk = NULL; #endif HANDLE hThread; ASSERT( ScanParams != NULL ); // // make sure we only kick off one of these at a time // if (ScanInProgress) { if (ScanParams->FreeMemory) { MemFree( ScanParams ); } return(ERROR_IO_PENDING); } // // if the system is configured to show UI progress and we don't // have a progress window, then we need to create a new thread // to do the scan as well as a progress dialog. // if (SfcQueryRegDwordWithAlternate(REGKEY_POLICY, REGKEY_WINLOGON, REGVAL_SFCSHOWPROGRESS, 1) && ScanParams->ProgressWindow == NULL && 0 == m_gulAfterRestore) { // // if the user isn't logged in, we need to wait for them to do so // before thinking about creating a dialog // if (!UserLoggedOn) { Status = NtWaitForSingleObject(hEventLogon,TRUE,NULL); if (!NT_SUCCESS(Status)) { DebugPrint1(LVL_MINIMAL, L"Failed waiting for the logon event, ec=0x%08x",Status); } } // // we need access to the user's desktop now that they're logged in // #if 0 hDesk = OpenInputDesktop( 0, FALSE, MAXIMUM_ALLOWED ); if ( hDesk ) { SetThreadDesktop( hDesk ); CloseDesktop( hDesk ); } else { DebugPrint1(LVL_MINIMAL, L"OpenInputDesktop failed, ec=0x%08x",GetLastError()); } #else SetThreadDesktop( hUserDesktop ); #endif // // create an event so the user can cancel the scan // // (note that we should only have one scan going on at any given // time or our cancel object can get out of sync) // ASSERT( hEventScanCancel == NULL ); ASSERT( hEventScanCancelComplete == NULL); hEventScanCancel = CreateEvent( NULL, FALSE, FALSE, NULL ); hEventScanCancelComplete = CreateEvent( NULL, FALSE, FALSE, NULL ); // // create the dialog the user will see UI in // hDlg = CreateDialog( SfcInstanceHandle, MAKEINTRESOURCE(IDD_PROGRESS), NULL, ProgressDialogProc ); if (hDlg) { // // scale the progress dialog (we assume that it takes the same // amount of time to scan each file in the system) // ScanParams->ProgressWindow = GetDlgItem( hDlg, IDC_PROGRESS ); SendMessage( ScanParams->ProgressWindow, PBM_SETRANGE, 0, MAKELPARAM(0,SfcProtectedDllCount) ); SendMessage( ScanParams->ProgressWindow, PBM_SETPOS, 0, 0 ); SendMessage( ScanParams->ProgressWindow, PBM_SETSTEP, 1, 0 ); // // create a thread to do the work so we can pump messages in this // thread that already has access to the desktop // hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)SfcDoScan, ScanParams, 0, NULL ); if (hThread) { MSG msg; while(1) { // // pump messages until the "worker" thread goes away or the // dialog ends // if (WAIT_OBJECT_0+1 == MsgWaitForMultipleObjects( 1, &hThread, FALSE, INFINITE, QS_ALLEVENTS )) { while (PeekMessage( &msg, NULL, 0, 0, PM_REMOVE )) { if (!IsDialogMessage( hDlg, &msg )) { TranslateMessage (&msg); DispatchMessage (&msg); } } } else { break; } } CloseHandle( hThread ); EndDialog( hDlg, 0 ); } else { // // CreateThread failed... kill the dialog and try to do it // synchronously // EndDialog( hDlg, 0 ); SfcDoScan( ScanParams ); } } else { // // CreateDialog failed... just try to do it synchronously // SfcDoScan( ScanParams ); } // // cleanup // if (hEventScanCancel) { CloseHandle( hEventScanCancel ); hEventScanCancel = NULL; } if (hEventScanCancelComplete) { CloseHandle( hEventScanCancelComplete ); hEventScanCancelComplete = NULL; } } else { // // no UI to be shown, just do this synchronously // SfcDoScan( ScanParams ); } if (ScanParams->FreeMemory) { MemFree( ScanParams ); } return Status; } NTSTATUS SfcDoForcedSxsScan( IN HWND hwDialogProgress, IN BOOL bValidate, IN BOOL bAllowUI ) { NTSTATUS Status; Status = SfcLoadSxsProtection(); if ( !NT_SUCCESS( Status ) ) { return Status; } ASSERT( SxsScanForcedFunc != NULL ); if ( !SxsScanForcedFunc( hwDialogProgress, bValidate, bAllowUI ) ) { return STATUS_SUCCESS; } else return STATUS_NO_MEMORY; }