windows-nt/Source/XPSP1/NT/base/subsys/sm/sfc/exe/sfc.c
2020-09-26 16:20:57 +08:00

818 lines
17 KiB
C

/*++
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);
}