380 lines
10 KiB
C
380 lines
10 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1998 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
eventlog.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Implementation of event logging.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Wesley Witt (wesw) 18-Dec-1998
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
Andrew Ritz (andrewr) 7-Jul-1999
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "sfcp.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
|
||
|
typedef BOOL (WINAPI *PPSETUPLOGSFCERROR)(PCWSTR,DWORD);
|
||
|
|
||
|
//
|
||
|
// global handle to eventlog
|
||
|
//
|
||
|
HANDLE hEventSrc;
|
||
|
|
||
|
//
|
||
|
// pointer to gui-setup eventlog function
|
||
|
//
|
||
|
PPSETUPLOGSFCERROR pSetuplogSfcError;
|
||
|
|
||
|
BOOL
|
||
|
pSfcGetSetuplogSfcError(
|
||
|
VOID
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Routine retreives a function pointer to the error logging entrypoint in
|
||
|
syssetup.dll
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE for success, FALSE for failure.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
HMODULE hMod;
|
||
|
|
||
|
if (NULL == pSetuplogSfcError) {
|
||
|
hMod = GetModuleHandle( L"syssetup.dll" );
|
||
|
|
||
|
if (hMod) {
|
||
|
pSetuplogSfcError = (PPSETUPLOGSFCERROR)SfcGetProcAddress( hMod, "pSetuplogSfcError" );
|
||
|
} else {
|
||
|
DebugPrint1(LVL_MINIMAL, L"GetModuleHandle on syssetup.dll failed, ec=0x%08x",GetLastError());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pSetuplogSfcError != NULL;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
SfcReportEvent(
|
||
|
IN ULONG EventId,
|
||
|
IN PCWSTR FileName,
|
||
|
IN PCOMPLETE_VALIDATION_DATA ImageValData,
|
||
|
IN DWORD LastError OPTIONAL
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Routine logs an event into the eventlog. Also contains a hack for logging
|
||
|
data into the GUI-setup error log as well. we typically log unsigned files
|
||
|
or the user tht cancelled the replacement of the signed files.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
EventId - id of the eventlog error
|
||
|
FileName - null terminated unicode string indicating the file that was
|
||
|
unsigned, etc.
|
||
|
ImageValData - pointer to file data for unsigned file
|
||
|
LastError - contains an optional last error code for logging
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE for success, FALSE for failure.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PFILE_VERSION_INFO FileVer;
|
||
|
WCHAR SysVer[64];
|
||
|
WCHAR BadVer[64];
|
||
|
PCWSTR s[3];
|
||
|
WORD Count = 0;
|
||
|
WCHAR LastErrorText[MAX_PATH];
|
||
|
PVOID ErrText = NULL;
|
||
|
WORD wEventType;
|
||
|
|
||
|
//
|
||
|
// if we're in gui-mode setup, we take a special path to log into
|
||
|
// gui-setup's logfile instead of the eventlog
|
||
|
//
|
||
|
if (SFCDisable == SFC_DISABLE_SETUP) {
|
||
|
if(!pSfcGetSetuplogSfcError()) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
switch (EventId){
|
||
|
|
||
|
case MSG_DLL_CHANGE: //fall through
|
||
|
case MSG_SCAN_FOUND_BAD_FILE:
|
||
|
pSetuplogSfcError( FileName,0 );
|
||
|
break;
|
||
|
|
||
|
case MSG_COPY_CANCEL_NOUI:
|
||
|
case MSG_RESTORE_FAILURE:
|
||
|
pSetuplogSfcError( FileName, 1 );
|
||
|
break;
|
||
|
|
||
|
case MSG_CACHE_COPY_ERROR:
|
||
|
pSetuplogSfcError( FileName, 2 );
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
DebugPrint1(
|
||
|
LVL_MINIMAL,
|
||
|
L"unexpected EventId 0x%08x in GUI Setup, ",
|
||
|
EventId);
|
||
|
|
||
|
return FALSE;
|
||
|
//ASSERT( FALSE && L"Unexpected EventId in SfcReportEvent");
|
||
|
}
|
||
|
|
||
|
return(TRUE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// we're outside of GUI-setup so we really want to log to the eventlog
|
||
|
//
|
||
|
|
||
|
if (EventId == 0) {
|
||
|
ASSERT( FALSE && L"Unexpected EventId in SfcReportEvent");
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// if we don't have a handle to the eventlog, create one.
|
||
|
//
|
||
|
if (hEventSrc == NULL) {
|
||
|
hEventSrc = RegisterEventSource( NULL, L"Windows File Protection" );
|
||
|
if (hEventSrc == NULL) {
|
||
|
DebugPrint1(LVL_MINIMAL, L"RegisterEventSource failed, ec=0x%08x",GetLastError());
|
||
|
return(FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ASSERT(hEventSrc != NULL);
|
||
|
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// pick out the appropriate message to log
|
||
|
// the default event type is "information"
|
||
|
//
|
||
|
wEventType = EVENTLOG_INFORMATION_TYPE;
|
||
|
|
||
|
switch (EventId) {
|
||
|
case MSG_DLL_CHANGE:
|
||
|
ASSERT(FileName != NULL);
|
||
|
s[0] = FileName;
|
||
|
|
||
|
//
|
||
|
// we prefer a message that is most informative message with
|
||
|
// version information for both dlls to the least informative
|
||
|
// message with no version information
|
||
|
//
|
||
|
//
|
||
|
if (ImageValData->New.DllVersion && ImageValData->Original.DllVersion) {
|
||
|
FileVer = (PFILE_VERSION_INFO)&ImageValData->New.DllVersion;
|
||
|
swprintf( SysVer, L"%d.%d.%d.%d", FileVer->VersionHigh, FileVer->VersionLow, FileVer->BuildNumber, FileVer->Revision );
|
||
|
FileVer = (PFILE_VERSION_INFO)&ImageValData->Original.DllVersion;
|
||
|
swprintf( BadVer, L"%d.%d.%d.%d", FileVer->VersionHigh, FileVer->VersionLow, FileVer->BuildNumber, FileVer->Revision );
|
||
|
s[1] = BadVer;
|
||
|
s[2] = SysVer;
|
||
|
Count = 3;
|
||
|
EventId = MSG_DLL_CHANGE2;
|
||
|
} else if (ImageValData->New.DllVersion) {
|
||
|
FileVer = (PFILE_VERSION_INFO)&ImageValData->New.DllVersion;
|
||
|
swprintf( SysVer, L"%d.%d.%d.%d", FileVer->VersionHigh, FileVer->VersionLow, FileVer->BuildNumber, FileVer->Revision );
|
||
|
s[1] = SysVer;
|
||
|
Count = 2;
|
||
|
EventId = MSG_DLL_CHANGE3;
|
||
|
} else if (ImageValData->Original.DllVersion) {
|
||
|
FileVer = (PFILE_VERSION_INFO)&ImageValData->Original.DllVersion;
|
||
|
swprintf( BadVer, L"%d.%d.%d.%d", FileVer->VersionHigh, FileVer->VersionLow, FileVer->BuildNumber, FileVer->Revision );
|
||
|
s[1] = BadVer;
|
||
|
Count = 2;
|
||
|
EventId = MSG_DLL_CHANGE;
|
||
|
} else {
|
||
|
//
|
||
|
// we have to protect some things without version information,
|
||
|
// so we just log an error that doesn't mention version
|
||
|
// information. If we stop protecting files like this, this
|
||
|
// should be an assert in prerelease versions of the code
|
||
|
//
|
||
|
Count = 1;
|
||
|
EventId = MSG_DLL_CHANGE_NOVERSION;
|
||
|
DebugPrint1( LVL_MINIMAL, L"TskTsk...the protected OS file %ws does not have any version information", FileName);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case MSG_SCAN_FOUND_BAD_FILE:
|
||
|
ASSERT(FileName != NULL);
|
||
|
s[0] = FileName;
|
||
|
|
||
|
//
|
||
|
// if we found a bad file, we only want the version of the restored file
|
||
|
//
|
||
|
if (ImageValData->New.DllVersion) {
|
||
|
FileVer = (PFILE_VERSION_INFO)&ImageValData->New.DllVersion;
|
||
|
swprintf( SysVer, L"%d.%d.%d.%d", FileVer->VersionHigh, FileVer->VersionLow, FileVer->BuildNumber, FileVer->Revision );
|
||
|
s[1] = SysVer;
|
||
|
Count = 2;
|
||
|
} else {
|
||
|
DebugPrint1( LVL_MINIMAL, L"TskTsk...the protected OS file %ws does not have any version information", FileName);
|
||
|
EventId = MSG_SCAN_FOUND_BAD_FILE_NOVERSION;
|
||
|
Count = 1;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case MSG_RESTORE_FAILURE:
|
||
|
Count = 3;
|
||
|
s[0] = FileName;
|
||
|
s[1] = BadVer;
|
||
|
s[2] = (PCWSTR)LastErrorText;
|
||
|
|
||
|
if (ImageValData->Original.DllVersion) {
|
||
|
FileVer = (PFILE_VERSION_INFO)&ImageValData->Original.DllVersion;
|
||
|
swprintf( BadVer,
|
||
|
L"%d.%d.%d.%d",
|
||
|
FileVer->VersionHigh,
|
||
|
FileVer->VersionLow,
|
||
|
FileVer->BuildNumber,
|
||
|
FileVer->Revision );
|
||
|
} else {
|
||
|
LoadString( SfcInstanceHandle,IDS_UNKNOWN,BadVer,UnicodeChars(BadVer));
|
||
|
}
|
||
|
|
||
|
|
||
|
break;
|
||
|
|
||
|
case MSG_CACHE_COPY_ERROR:
|
||
|
Count = 2;
|
||
|
s[0] = FileName;
|
||
|
s[1] = (PCWSTR)LastErrorText;
|
||
|
break;
|
||
|
|
||
|
case MSG_COPY_CANCEL_NOUI:
|
||
|
//fall through
|
||
|
case MSG_COPY_CANCEL:
|
||
|
Count = 3;
|
||
|
s[0] = FileName;
|
||
|
s[1] = LoggedOnUserName;
|
||
|
s[2] = BadVer;
|
||
|
|
||
|
if (ImageValData->Original.DllVersion) {
|
||
|
FileVer = (PFILE_VERSION_INFO)&ImageValData->Original.DllVersion;
|
||
|
swprintf( BadVer,
|
||
|
L"%d.%d.%d.%d",
|
||
|
FileVer->VersionHigh,
|
||
|
FileVer->VersionLow,
|
||
|
FileVer->BuildNumber,
|
||
|
FileVer->Revision );
|
||
|
} else {
|
||
|
LoadString( SfcInstanceHandle,IDS_UNKNOWN,BadVer,UnicodeChars(BadVer));
|
||
|
}
|
||
|
|
||
|
|
||
|
break;
|
||
|
|
||
|
case MSG_DLL_NOVALIDATION_TERMINATION:
|
||
|
wEventType = EVENTLOG_WARNING_TYPE;
|
||
|
s[0] = FileName;
|
||
|
Count = 1;
|
||
|
break;
|
||
|
|
||
|
case MSG_RESTORE_FAILURE_MAX_RETRIES:
|
||
|
s[0] = FileName;
|
||
|
Count = 1;
|
||
|
break;
|
||
|
|
||
|
case MSG_SCAN_STARTED:
|
||
|
Count = 0;
|
||
|
break;
|
||
|
|
||
|
case MSG_SCAN_COMPLETED:
|
||
|
Count = 0;
|
||
|
break;
|
||
|
|
||
|
case MSG_SCAN_CANCELLED:
|
||
|
s[0] = LoggedOnUserName;
|
||
|
Count = 1;
|
||
|
break;
|
||
|
|
||
|
case MSG_DISABLE:
|
||
|
Count = 0;
|
||
|
break;
|
||
|
|
||
|
case MSG_DLLCACHE_INVALID:
|
||
|
Count = 0;
|
||
|
break;
|
||
|
|
||
|
case MSG_SXS_INITIALIZATION_FAILED:
|
||
|
Count = 1;
|
||
|
s[0] = LastErrorText;
|
||
|
break;
|
||
|
|
||
|
|
||
|
case MSG_INITIALIZATION_FAILED:
|
||
|
Count = 1;
|
||
|
s[0] = LastErrorText;
|
||
|
break;
|
||
|
|
||
|
case MSG_CATALOG_RESTORE_FAILURE:
|
||
|
Count = 2;
|
||
|
s[0] = FileName;
|
||
|
s[1] = LastErrorText;
|
||
|
break;
|
||
|
default:
|
||
|
ASSERT( FALSE && L"Unknown EventId in SfcReportEvent");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return ReportEvent(
|
||
|
hEventSrc,
|
||
|
wEventType,
|
||
|
0,
|
||
|
EventId,
|
||
|
NULL,
|
||
|
Count,
|
||
|
0,
|
||
|
s,
|
||
|
NULL
|
||
|
);
|
||
|
}
|