|
|
/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
sfc.c
Abstract:
code file for system file checker utilty program
Revision History:
Andrew Ritz (andrewr) 2-Jul-1999 : Added comments
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include <sfcapip.h>
#include <sfcapi.h>
#include <locale.h>
#include "msg.h"
BOOL IsUserAdmin( VOID );
int __cdecl My_wprintf( const wchar_t *format, ... );
int __cdecl My_fwprintf( FILE *str, const wchar_t *format, ... );
int __cdecl My_vfwprintf( FILE *str, const wchar_t *format, va_list argptr );
#define DLLCACHE_DIR_DEFAULT L"%SystemRoot%\\system32\\DllCache"
#define SFC_REGISTRY_KEY L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"
#define SFC_DLLCACHE_VALUE L"SFCDllCacheDir"
#define SFC_SCAN_VALUE L"SFCScan"
#define SFC_DISABLE_VALUE L"SFCDisable"
#define SFC_QUOTA_VALUE L"SFCQuota"
typedef enum _SFCACTION { ScanOnce, ScanNow, ScanBoot, RevertScan, PurgeCacheNow, SetCache } SFCACTION;
DWORD SfcQueryRegDword( LPWSTR KeyName, LPWSTR ValueName ) /*++
Routine Description:
Registry wrapper function. Retreives the DWORD value at the specified key. Only handles values under HKLM. Arguments:
KeyName - Keyname that the specified value lives under. ValueName - ValueName we want to query.
Return Value:
The DWORD value at the specifed location or 0 on failure. If the call fails, GetLastError() returns something other than ERROR_SUCESS.
--*/ { HKEY hKey; DWORD val; DWORD sz = sizeof(DWORD); long rslt;
rslt = RegOpenKey( HKEY_LOCAL_MACHINE, KeyName, &hKey ); if (rslt != ERROR_SUCCESS) { val = 0; goto e0; }
rslt = RegQueryValueEx( hKey, ValueName, NULL, NULL, (LPBYTE)&val, &sz ); if (rslt != ERROR_SUCCESS) { val = 0; }
RegCloseKey( hKey ); e0: SetLastError( rslt ); return(val); }
PWSTR SfcQueryRegString( LPWSTR KeyName, LPWSTR ValueName ) /*++
Routine Description:
Registry wrapper function. Retreives the string value at the specified key. Only handles values under HKLM. Arguments:
KeyName - Keyname that the specified value lives under. ValueName - ValueName we want to query.
Return Value:
The string value at the specifed location or NULL on failure. If the function fails, call GetLastError() to get the extended error code.
--*/ { HKEY hKey; DWORD size = 0; PWSTR val; long rslt;
rslt = RegOpenKey( HKEY_LOCAL_MACHINE, KeyName, &hKey ); if (rslt != ERROR_SUCCESS) { val = NULL; goto e0; }
rslt = RegQueryValueEx( hKey, ValueName, NULL, NULL, NULL, &size ); if (rslt != ERROR_SUCCESS) { val = NULL; goto e1; }
val = malloc( size+ sizeof(WCHAR) ); if (val == NULL) { rslt = ERROR_NOT_ENOUGH_MEMORY; goto e1; }
rslt = RegQueryValueEx( hKey, ValueName, NULL, NULL, (LPBYTE)val, &size ); if (rslt != ERROR_SUCCESS) { free( val ); val = NULL; }
e1: RegCloseKey( hKey ); e0: SetLastError( rslt ); return val; }
DWORD SfcWriteRegDword( LPWSTR KeyName, LPWSTR ValueName, ULONG Value ) /*++
Routine Description:
Registry wrapper function. Writes the DWORD value at the specified key. Only handles values under HKLM. Arguments:
KeyName - Keyname that the specified value lives under. ValueName - ValueName we want to query. Value - value to be set
Return Value:
WIN32 error code indicating outcome (ERROR_SUCCESS on success).
--*/ { HKEY hKey; DWORD retval; long rslt;
rslt = RegOpenKey( HKEY_LOCAL_MACHINE, KeyName, &hKey ); if (rslt != ERROR_SUCCESS) { retval = rslt; goto e0; }
rslt = RegSetValueEx( hKey, ValueName, 0, REG_DWORD, (LPBYTE)&Value, sizeof(DWORD) ); retval = rslt;
RegCloseKey( hKey ); e0: SetLastError( rslt ); return( retval ); }
DWORD SfcWriteRegString( LPWSTR KeyName, LPWSTR ValueName, PWSTR Value ) /*++
Routine Description:
Registry wrapper function. Writes the string value at the specified key. Only handles values under HKLM. Arguments:
KeyName - Keyname that the specified value lives under. ValueName - ValueName we want to query. Value - value to be set
Return Value:
WIN32 error code indicating outcome (ERROR_SUCCESS on success).
--*/ { HKEY hKey; DWORD retval; long rslt;
rslt = RegOpenKey( HKEY_LOCAL_MACHINE, KeyName, &hKey ); if (rslt != ERROR_SUCCESS) { retval = rslt; goto e0; }
rslt = RegSetValueEx( hKey, ValueName, 0, REG_SZ, (LPBYTE)Value, (wcslen(Value)+1)*sizeof(WCHAR) ); retval = rslt;
RegCloseKey( hKey ); e0: SetLastError( rslt ); return( retval ); }
/***
* My_wprintf(format) - print formatted data * * Prints Unicode formatted string to console window using WriteConsoleW. * Note: This My_wprintf() is used to workaround the problem in c-runtime * which looks up LC_CTYPE even for Unicode string. * */
int __cdecl My_wprintf( const wchar_t *format, ... )
{ DWORD cchWChar;
va_list args; va_start( args, format );
cchWChar = My_vfwprintf(stdout, format, args);
va_end(args);
return cchWChar; }
/***
* My_fwprintf(stream, format) - print formatted data * * Prints Unicode formatted string to console window using WriteConsoleW. * Note: This My_fwprintf() is used to workaround the problem in c-runtime * which looks up LC_CTYPE even for Unicode string. * */
int __cdecl My_fwprintf( FILE *str, const wchar_t *format, ... )
{ DWORD cchWChar;
va_list args; va_start( args, format );
cchWChar = My_vfwprintf(str, format, args);
va_end(args);
return cchWChar; }
int __cdecl My_vfwprintf( FILE *str, const wchar_t *format, va_list argptr )
{ HANDLE hOut;
if (str == stderr) { hOut = GetStdHandle(STD_ERROR_HANDLE); } else { hOut = GetStdHandle(STD_OUTPUT_HANDLE); }
if ((GetFileType(hOut) & ~FILE_TYPE_REMOTE) == FILE_TYPE_CHAR) { DWORD cchWChar; WCHAR szBufferMessage[1024];
vswprintf( szBufferMessage, format, argptr ); cchWChar = wcslen(szBufferMessage); WriteConsoleW(hOut, szBufferMessage, cchWChar, &cchWChar, NULL); return cchWChar; }
return vfwprintf(str, format, argptr); }
void PrintMessage( DWORD MsgId, DWORD LastError, PCWSTR FileName, BOOL bStdOut ) /*++
Routine Description:
Output the specified message id to specified output. Arguments:
MsgId - resource message id of message to be output LastError - error code FileName - filename to be logged, if specified bStdOut - TRUE indicates the message goes to stdout, else stderr Return Value:
None.
--*/ { WCHAR buf[2048]; WCHAR LastErrorText[200]; PVOID ErrText;
PVOID Array[3];
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, LastError, 0, (PWSTR) &ErrText, 0, NULL );
if (ErrText) { wsprintf(LastErrorText,L"0x%08x [%ws]",LastError,ErrText); LocalFree( ErrText ); } else { wsprintf(LastErrorText,L"0x%08x",LastError); }
Array[0] = (PVOID)LastErrorText; Array[1] = (PVOID)FileName; Array[2] = NULL;
FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, MsgId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, sizeof(buf) / sizeof(WCHAR), (va_list *)Array );
My_fwprintf( bStdOut ? stdout : stderr, L"%ws", buf ); }
void Usage( void ) /*++
Routine Description:
Display's usage for program to stdout. Arguments:
None.
Return Value:
None.
--*/ { PrintMessage( MSG_USAGE, 0, NULL, FALSE ); }
BOOL DoAction( SFCACTION SfcAction, DWORD CacheSize ) /*++
Routine Description:
take the specified action based on input parameter Arguments:
SfcAction - enumerated type illustrating action CacheSize - only used for SetCache action, specifies cache size
Return Value:
TRUE on success, FALSE on failure.
--*/
{ HANDLE RpcHandle; DWORD errcode; BOOL retval; switch( SfcAction ) { case ScanOnce: //
// connect to SFC RPC server and telling it to scan once.
//
RpcHandle = SfcConnectToServer( NULL ); if (RpcHandle) { errcode = SfcInitiateScan( RpcHandle, SFC_SCAN_ONCE ); retval = (errcode == ERROR_SUCCESS); SfcClose( RpcHandle ); } else { retval = FALSE; errcode = GetLastError(); }
if (errcode != ERROR_SUCCESS) { PrintMessage( MSG_SET_FAIL, errcode, NULL, FALSE ); retval = FALSE; } else { //
// requires a reboot
//
PrintMessage( MSG_REBOOT, 0, NULL, TRUE ); retval = TRUE; } break; case ScanBoot: //
// connect to SFC RPC server and telling it to scan every boot.
//
RpcHandle = SfcConnectToServer( NULL ); if (RpcHandle) { errcode = SfcInitiateScan( RpcHandle, SFC_SCAN_ALWAYS ); retval = (errcode == ERROR_SUCCESS); SfcClose( RpcHandle ); } else { retval = FALSE; errcode = GetLastError(); }
if (errcode != ERROR_SUCCESS) { PrintMessage( MSG_SET_FAIL, errcode, NULL, FALSE ); retval = FALSE; } else { //
// requires a reboot
//
PrintMessage( MSG_REBOOT, 0, NULL, TRUE ); retval = TRUE; } break; case ScanNow: //
// scan immediately by connecting to SFC RPC server
// and telling it to scan now.
//
RpcHandle = SfcConnectToServer( NULL ); if (RpcHandle) { //
// scanwhen argument is ignored.
//
errcode = SfcInitiateScan( RpcHandle, SFC_SCAN_IMMEDIATE ); retval = (errcode == ERROR_SUCCESS); SfcClose( RpcHandle ); } else { retval = FALSE; errcode = GetLastError(); }
if (!retval) { PrintMessage(MSG_SCAN_FAIL, errcode, NULL, FALSE); } break; case RevertScan: //
// connect to SFC RPC server and telling it to scan normally.
//
RpcHandle = SfcConnectToServer( NULL ); if (RpcHandle) { errcode = SfcInitiateScan( RpcHandle, SFC_SCAN_NORMAL); retval = (errcode == ERROR_SUCCESS); SfcClose( RpcHandle ); } else { retval = FALSE; errcode = GetLastError(); }
if (errcode != ERROR_SUCCESS) { PrintMessage( MSG_SET_FAIL, errcode, NULL, FALSE ); retval = FALSE; } else { //
// requires a reboot
//
PrintMessage( MSG_REBOOT, 0, NULL, TRUE ); retval = TRUE; } break; case SetCache: //
// connect to SFC RPC server and tell it to set the cache size.
//
RpcHandle = SfcConnectToServer( NULL ); if (RpcHandle) { errcode = SfcCli_SetCacheSize( RpcHandle, CacheSize ); retval = (errcode == ERROR_SUCCESS); SfcClose( RpcHandle ); } else { retval = FALSE; errcode = GetLastError(); }
if (errcode != ERROR_SUCCESS) { PrintMessage( MSG_SET_FAIL, errcode, NULL, FALSE ); retval = FALSE; } else { //
// print success message
//
PrintMessage( MSG_SUCCESS, 0, NULL, TRUE ); retval = TRUE; }
break; case PurgeCacheNow: //
// remove all files from the cache
//
//
// connect to SFC RPC server and tell it to purge the cache
//
RpcHandle = SfcConnectToServer( NULL ); if (RpcHandle) { errcode = SfcCli_PurgeCache( RpcHandle ); retval = (errcode == ERROR_SUCCESS); SfcClose( RpcHandle ); } else { retval = FALSE; errcode = GetLastError(); }
if (!retval) { PrintMessage(MSG_PURGE_FAIL, errcode, NULL, FALSE); } else { PrintMessage(MSG_SUCCESS, 0, NULL, FALSE); } break; default: //
// should never get here!
//
ASSERT(FALSE); retval = FALSE; }
return(retval); }
int __cdecl wmain( int argc, WCHAR *argv[] ) /*++
Routine Description:
program entrypoint Arguments:
argc - number of arguments argv - pointer to argument array
Return Value:
0 indicates success, 1 failure.
--*/ { int i; DWORD val; PWSTR s; SFCACTION SfcAction;
setlocale(LC_ALL, ".OCP");
//
// only an administrator logged on to session 0 (console) is allowed to run this app
//
if (!IsUserAdmin() || !ProcessIdToSessionId(GetCurrentProcessId(), &val) || val != 0) { PrintMessage( MSG_ADMIN, 0, NULL, FALSE ); return 1; } //
// parse args
//
if (argc == 1) { Usage(); return 1; }
val = 0; for (i=1; i<argc; i++) { s = argv[i]; //
// support '-' and '/' as synonyms
//
if (*s != L'-' && *s != L'/') { Usage(); return 1; } s += 1; if (_wcsicmp( s, L"SCANONCE" ) == 0) { SfcAction = ScanOnce; } else if (_wcsicmp( s, L"SCANBOOT" ) == 0) { SfcAction = ScanBoot; } else if (_wcsicmp( s, L"SCANNOW" ) == 0) { SfcAction = ScanNow; } else if (_wcsicmp( s, L"REVERT" ) == 0) { SfcAction = RevertScan; } else if (_wcsnicmp( s, L"CACHESIZE=", 10 ) == 0) { SfcAction = SetCache; val = wcstoul( s+10, NULL, 0 ); } else if (_wcsicmp( s, L"PURGECACHE" ) == 0) { SfcAction = PurgeCacheNow; } else { Usage(); return 1; } }
//
// do the specified action
//
if (DoAction(SfcAction,val)) { return 0; }
return 1; }
BOOL IsUserAdmin( VOID )
/*++
Routine Description:
This routine returns TRUE if the caller's process is a member of the Administrators local group.
Caller is NOT expected to be impersonating anyone and IS expected to be able to open their own process and process token.
Arguments:
None.
Return Value:
TRUE - Caller has Administrators local group.
FALSE - Caller does not have Administrators local group.
--*/
{ BOOL b; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; PSID AdministratorsGroup;
b = AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdministratorsGroup );
if(b) { if (!CheckTokenMembership( NULL, AdministratorsGroup, &b)) { b = FALSE; }
FreeSid(AdministratorsGroup);
} return(b); }
|