windows-nt/Source/XPSP1/NT/ds/security/protocols/schannel/lsa/events.c
2020-09-26 16:20:57 +08:00

815 lines
19 KiB
C

//+-----------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (c) Microsoft Corporation 1999
//
// File: events.c
//
// Contents: Schannel event log functions.
//
// Functions: SchInitializeEvents
// SchReportEvent
// SchShutdownEvents
//
// History: 03-05-99 jbanes Created
//
//------------------------------------------------------------------------
#include "sslp.h"
#include <lsapmsgs.h>
#include <netlib.h>
HANDLE g_hEventLog = NULL;
HANDLE g_hDiscardDupEventLog = NULL;
WCHAR EventSourceName[] = TEXT("Schannel");
#define MAX_EVENT_STRINGS 8
#define SCH_MESSAGE_FILENAME TEXT("%SystemRoot%\\system32\\lsasrv.dll")
LPWSTR pszClientString = NULL;
LPWSTR pszServerString = NULL;
NTSTATUS
SchGetMessageString(
LPVOID Resource,
DWORD Index,
LPWSTR * pRetString);
//+---------------------------------------------------------------------------
//
// Function: SchInitializeEvents
//
// Synopsis: Connects to event log service.
//
// Arguments: (none)
//
// History: 03-05-99 jbanes Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
SchInitializeEvents(void)
{
HKEY hKey;
int err;
DWORD disp;
HMODULE hResource;
//
// Create registry entries, whether event logging is currently
// enabled or not.
//
err = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
TEXT("System\\CurrentControlSet\\Services\\EventLog\\System\\Schannel"),
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hKey,
&disp);
if(err)
{
return(FALSE);
}
if (disp == REG_CREATED_NEW_KEY)
{
RegSetValueEx( hKey,
TEXT("EventMessageFile"),
0,
REG_EXPAND_SZ,
(PBYTE)SCH_MESSAGE_FILENAME,
sizeof(SCH_MESSAGE_FILENAME) );
// RegSetValueEx( hKey,
// TEXT("CategoryMessageFile"),
// 0,
// REG_EXPAND_SZ,
// (PBYTE)SCH_MESSAGE_FILENAME,
// sizeof(SCH_MESSAGE_FILENAME) );
disp = 7;
RegSetValueEx( hKey,
TEXT("TypesSupported"),
0,
REG_DWORD,
(PBYTE) &disp,
sizeof(DWORD) );
// disp = CATEGORY_MAX_CATEGORY - 1;
// RegSetValueEx( hKey,
// TEXT("CategoryCount"),
// 0,
// REG_DWORD,
// (PBYTE) &disp,
// sizeof(DWORD) );
RegFlushKey(hKey);
}
RegCloseKey(hKey);
//
// Read the event text strings from the resource file.
//
hResource = (HMODULE)LoadLibrary(TEXT("lsasrv.dll"));
if(hResource == NULL)
{
return(FALSE);
}
SchGetMessageString(hResource,
SSLEVENTTEXT_CLIENT,
&pszClientString);
SchGetMessageString(hResource,
SSLEVENTTEXT_SERVER,
&pszServerString);
FreeLibrary(hResource);
return(TRUE);
}
//+---------------------------------------------------------------------------
//
// Function: SchReportEvent
//
// Synopsis: Reports an event to the event log
//
// Arguments: [EventType] -- EventType (ERROR, WARNING, etc.)
// [EventId] -- Event ID
// [SizeOfRawData] -- Size of raw data
// [RawData] -- Raw data
// [NumberOfStrings] -- number of strings
// ... -- PWSTRs to string data
//
// History: 03-05-99 jbanes Created
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD
SchReportEvent(
IN DWORD LogLevel,
IN DWORD EventType,
IN DWORD EventId,
IN DWORD Category,
IN DWORD SizeOfRawData,
IN PVOID RawData,
IN DWORD NumberOfStrings,
...
)
{
va_list arglist;
ULONG i;
PWSTR Strings[ MAX_EVENT_STRINGS ];
PSTR StringsA[ MAX_EVENT_STRINGS ];
DWORD Status;
BOOL fDiscardDuplicates = TRUE;
BOOL fSuccess;
//
// Is this event supposed to be logged?
//
if ((g_dwEventLogging & LogLevel) == 0)
{
return ERROR_SUCCESS;
}
//
// Open the event log if necessary.
//
if(g_dwEventLogging == DEFAULT_EVENT_LOGGING_SETTING)
{
// Only log identical event once per hour.
if(g_hDiscardDupEventLog == NULL)
{
g_hDiscardDupEventLog = NetpEventlogOpen(EventSourceName, 60000*60);
if(g_hDiscardDupEventLog == NULL)
{
Status = GetLastError();
DebugLog((DEB_ERROR, "Could not open duplicate discard event log, error %d\n", Status));
return Status;
}
}
}
else
{
// Log all events.
if(g_hEventLog == NULL)
{
g_hEventLog = RegisterEventSource(NULL, EventSourceName);
if(g_hEventLog == NULL)
{
Status = GetLastError();
DebugLog((DEB_ERROR, "Could not open duplicate discard event log, error %d\n", Status));
return Status;
}
}
fDiscardDuplicates = FALSE;
}
//
// Look at the strings, if they were provided
//
va_start( arglist, NumberOfStrings );
if (NumberOfStrings > MAX_EVENT_STRINGS) {
NumberOfStrings = MAX_EVENT_STRINGS;
}
for (i=0; i<NumberOfStrings; i++)
{
Strings[ i ] = va_arg( arglist, PWSTR );
}
//
// Report the event to the eventlog service
//
if(fDiscardDuplicates)
{
fSuccess = NetpEventlogWriteEx(
g_hDiscardDupEventLog,
(WORD) EventType,
(WORD) Category,
EventId,
(WORD)NumberOfStrings,
SizeOfRawData,
Strings,
RawData);
}
else
{
fSuccess = ReportEvent(
g_hEventLog,
(WORD) EventType,
(WORD) Category,
EventId,
NULL,
(WORD)NumberOfStrings,
SizeOfRawData,
Strings,
RawData);
}
if(!fSuccess)
{
Status = GetLastError();
DebugLog((DEB_ERROR, "ReportEvent( %u ) failed - %u\n", EventId, Status));
}
else
{
Status = ERROR_SUCCESS;
}
return Status;
}
void
SchShutdownEvents(void)
{
if(g_hDiscardDupEventLog != NULL)
{
NetpEventlogClose(g_hDiscardDupEventLog);
g_hDiscardDupEventLog = NULL;
}
if(g_hEventLog != NULL)
{
DeregisterEventSource(g_hEventLog);
g_hEventLog = NULL;
}
if(pszClientString)
{
LocalFree(pszClientString);
pszClientString = NULL;
}
if(pszServerString)
{
LocalFree(pszServerString);
pszServerString = NULL;
}
}
void
LogSchannelStartedEvent(void)
{
SchReportEvent( DEB_TRACE,
EVENTLOG_INFORMATION_TYPE,
SSLEVENT_SCHANNEL_STARTED,
0,
0,
NULL,
0,
NULL );
}
void
LogGlobalAcquireContextFailedEvent(
LPWSTR pwszName,
DWORD Status)
{
WCHAR wszStatus[20];
_ltow(Status, wszStatus, 16);
SchReportEvent( DEB_ERROR,
EVENTLOG_ERROR_TYPE,
SSLEVENT_GLOBAL_ACQUIRE_CONTEXT_FAILED,
0,
0,
NULL,
2,
pwszName,
wszStatus);
}
void
LogCreateCredEvent(
DWORD dwProtocol,
PLSA_SCHANNEL_CRED pSchannelCred)
{
SchReportEvent(DEB_TRACE,
EVENTLOG_INFORMATION_TYPE,
SSLEVENT_CREATE_CRED,
0,
sizeof(SCHANNEL_CRED),
pSchannelCred,
1,
(dwProtocol & SP_PROT_SERVERS) ? pszServerString : pszClientString);
}
void
LogCredPropertiesEvent(
DWORD dwProtocol,
PCRYPT_KEY_PROV_INFO pProvInfo,
PCCERT_CONTEXT pCertContext)
{
WCHAR wszType[20];
WCHAR wszFlags[20];
LPWSTR pwszKeySpec;
if(!(g_dwEventLogging & DEB_TRACE))
{
return;
}
_ltow(pProvInfo->dwProvType, wszType, 10);
_ltow(pProvInfo->dwFlags, wszFlags, 16);
switch(pProvInfo->dwKeySpec)
{
case AT_KEYEXCHANGE:
pwszKeySpec = L"key exchange";
break;
case AT_SIGNATURE:
pwszKeySpec = L"signature";
break;
default:
pwszKeySpec = L"unknown";
}
SchReportEvent( DEB_TRACE,
EVENTLOG_INFORMATION_TYPE,
SSLEVENT_CRED_PROPERTIES,
0,
pCertContext->cbCertEncoded,
pCertContext->pbCertEncoded,
6,
(dwProtocol & SP_PROT_SERVERS) ? pszServerString : pszClientString,
pProvInfo->pwszProvName,
wszType,
pProvInfo->pwszContainerName,
pwszKeySpec,
wszFlags);
}
void
LogNoPrivateKeyEvent(
DWORD dwProtocol)
{
SchReportEvent( DEB_ERROR,
EVENTLOG_ERROR_TYPE,
SSLEVENT_NO_PRIVATE_KEY,
0,
0,
NULL,
1,
(dwProtocol & SP_PROT_SERVERS) ? pszServerString : pszClientString);
}
void
LogCredAcquireContextFailedEvent(
DWORD dwProtocol,
DWORD Status)
{
WCHAR wszStatus[20];
_ltow(Status, wszStatus, 16);
SchReportEvent( DEB_ERROR,
EVENTLOG_ERROR_TYPE,
SSLEVENT_CRED_ACQUIRE_CONTEXT_FAILED,
0,
0,
NULL,
2,
(dwProtocol & SP_PROT_SERVERS) ? pszServerString : pszClientString,
wszStatus);
}
void
LogCreateCredFailedEvent(
DWORD dwProtocol)
{
SchReportEvent(DEB_ERROR,
EVENTLOG_ERROR_TYPE,
SSLEVENT_CREATE_CRED_FAILED,
0,
0,
NULL,
1,
(dwProtocol & SP_PROT_SERVERS) ? pszServerString : pszClientString);
}
void
LogNoDefaultServerCredEvent(void)
{
SchReportEvent(DEB_ERROR,
EVENTLOG_WARNING_TYPE,
SSLEVENT_NO_DEFAULT_SERVER_CRED,
0,
0,
NULL,
0,
NULL);
}
void
LogNoCiphersSupportedEvent(void)
{
SchReportEvent(DEB_ERROR,
EVENTLOG_ERROR_TYPE,
SSLEVENT_NO_CIPHERS_SUPPORTED,
0,
0,
NULL,
0,
NULL);
}
void
LogCipherMismatchEvent(void)
{
SchReportEvent(DEB_ERROR,
EVENTLOG_ERROR_TYPE,
SSLEVENT_CIPHER_MISMATCH,
0,
0,
NULL,
0,
NULL);
}
void
LogNoClientCertFoundEvent(void)
{
SchReportEvent(DEB_WARN,
EVENTLOG_WARNING_TYPE,
SSLEVENT_NO_CLIENT_CERT_FOUND,
0,
0,
NULL,
0,
NULL);
}
void
LogBogusServerCertEvent(
PCCERT_CONTEXT pCertContext,
LPWSTR pwszServerName,
DWORD Status)
{
WCHAR wszStatus[20];
if(!(g_dwEventLogging & DEB_ERROR))
{
return;
}
switch(Status)
{
case SEC_E_CERT_EXPIRED:
SchReportEvent( DEB_ERROR,
EVENTLOG_ERROR_TYPE,
SSLEVENT_EXPIRED_SERVER_CERT,
0,
pCertContext->cbCertEncoded,
pCertContext->pbCertEncoded,
0,
NULL);
break;
case SEC_E_UNTRUSTED_ROOT:
SchReportEvent( DEB_ERROR,
EVENTLOG_ERROR_TYPE,
SSLEVENT_UNTRUSTED_SERVER_CERT,
0,
pCertContext->cbCertEncoded,
pCertContext->pbCertEncoded,
0,
NULL);
break;
case CRYPT_E_REVOKED:
SchReportEvent( DEB_ERROR,
EVENTLOG_ERROR_TYPE,
SSLEVENT_REVOKED_SERVER_CERT,
0,
pCertContext->cbCertEncoded,
pCertContext->pbCertEncoded,
0,
NULL);
break;
case SEC_E_WRONG_PRINCIPAL:
SchReportEvent( DEB_ERROR,
EVENTLOG_ERROR_TYPE,
SSLEVENT_NAME_MISMATCHED_SERVER_CERT,
0,
pCertContext->cbCertEncoded,
pCertContext->pbCertEncoded,
1,
pwszServerName);
break;
default:
_ltow(Status, wszStatus, 16);
SchReportEvent( DEB_ERROR,
EVENTLOG_ERROR_TYPE,
SSLEVENT_BOGUS_SERVER_CERT,
0,
pCertContext->cbCertEncoded,
pCertContext->pbCertEncoded,
1,
wszStatus);
}
}
void
LogBogusClientCertEvent(
PCCERT_CONTEXT pCertContext,
DWORD Status)
{
WCHAR wszStatus[20];
if(!(g_dwEventLogging & DEB_WARN))
{
return;
}
_ltow(Status, wszStatus, 16);
SchReportEvent( DEB_WARN,
EVENTLOG_WARNING_TYPE,
SSLEVENT_BOGUS_CLIENT_CERT,
0,
pCertContext->cbCertEncoded,
pCertContext->pbCertEncoded,
1,
wszStatus);
}
void
LogFastMappingFailureEvent(
PCCERT_CONTEXT pCertContext,
DWORD Status)
{
WCHAR wszStatus[20];
if(!(g_dwEventLogging & DEB_WARN))
{
return;
}
_ltow(Status, wszStatus, 16);
SchReportEvent( DEB_WARN,
EVENTLOG_WARNING_TYPE,
SSLEVENT_FAST_MAPPING_FAILURE,
0,
pCertContext->cbCertEncoded,
pCertContext->pbCertEncoded,
1,
wszStatus);
}
void
LogCertMappingFailureEvent(
DWORD Status)
{
WCHAR wszStatus[20];
if(!(g_dwEventLogging & DEB_WARN))
{
return;
}
_ltow(Status, wszStatus, 16);
SchReportEvent( DEB_WARN,
EVENTLOG_WARNING_TYPE,
SSLEVENT_CERT_MAPPING_FAILURE,
0,
0,
NULL,
1,
wszStatus);
}
void
LogHandshakeInfoEvent(
DWORD dwProtocol,
PCipherInfo pCipherInfo,
PHashInfo pHashInfo,
PKeyExchangeInfo pExchangeInfo,
DWORD dwExchangeStrength)
{
WCHAR wszCipherStrength[20];
WCHAR wszExchangeStrength[20];
LPWSTR pwszProtocol;
LPWSTR pwszCipher;
LPWSTR pwszHash;
LPWSTR pwszExchange;
if(!(g_dwEventLogging & DEB_TRACE))
{
return;
}
switch(dwProtocol)
{
case SP_PROT_PCT1_SERVER:
case SP_PROT_PCT1_CLIENT:
pwszProtocol = L"PCT";
break;
case SP_PROT_SSL2_SERVER:
case SP_PROT_SSL2_CLIENT:
pwszProtocol = L"SSL 2.0";
break;
case SP_PROT_SSL3_SERVER:
case SP_PROT_SSL3_CLIENT:
pwszProtocol = L"SSL 3.0";
break;
case SP_PROT_TLS1_SERVER:
case SP_PROT_TLS1_CLIENT:
pwszProtocol = L"TLS (SSL 3.1)";
break;
default:
pwszProtocol = L"unknown";
}
switch(pCipherInfo->aiCipher)
{
case CALG_RC4:
pwszCipher = L"RC4";
break;
case CALG_3DES:
pwszCipher = L"Triple-DES";
break;
case CALG_RC2:
pwszCipher = L"RC2";
break;
case CALG_DES:
pwszCipher = L"DES";
break;
case CALG_SKIPJACK:
pwszCipher = L"Skipjack";
break;
default:
pwszCipher = L"unknown";
}
_ltow(pCipherInfo->dwStrength, wszCipherStrength, 10);
switch(pHashInfo->aiHash)
{
case CALG_MD5:
pwszHash = L"MD5";
break;
case CALG_SHA:
pwszHash = L"SHA";
break;
default:
pwszHash = L"unknown";
}
switch(pExchangeInfo->aiExch)
{
case CALG_RSA_SIGN:
case CALG_RSA_KEYX:
pwszExchange = L"RSA";
break;
case CALG_KEA_KEYX:
pwszExchange = L"KEA";
break;
case CALG_DH_EPHEM:
pwszExchange = L"Ephemeral DH";
break;
default:
pwszExchange = L"unknown";
}
_ltow(dwExchangeStrength, wszExchangeStrength, 10);
SchReportEvent( DEB_TRACE,
EVENTLOG_INFORMATION_TYPE,
SSLEVENT_HANDSHAKE_INFO,
0,
0,
NULL,
7,
(dwProtocol & SP_PROT_SERVERS) ? pszServerString : pszClientString,
pwszProtocol,
pwszCipher,
wszCipherStrength,
pwszHash,
pwszExchange,
wszExchangeStrength);
}
NTSTATUS
SchGetMessageString(
LPVOID Resource,
DWORD Index,
LPWSTR * pRetString)
{
DWORD Length;
*pRetString = NULL;
Length = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_ALLOCATE_BUFFER,
Resource,
Index,
0, // Use caller's language
(LPWSTR)pRetString,
0,
NULL);
if(Length == 0 || *pRetString == NULL)
{
return(STATUS_RESOURCE_DATA_NOT_FOUND);
}
//
// Note that we are retrieving a message from a message file.
// This message will have a cr/lf tacked on the end of it
// (0x0d 0x0a) that we don't want to be part of our returned
// strings. However, we do need to null terminate our string
// so we will convert the 0x0d into a null terminator.
//
// Also note that FormatMessage() returns a character count,
// not a byte count. So, we have to do some adjusting to make
// the string lengths correct.
//
ASSERT(Length >= 2); // We always expect cr/lf on our strings
//
// Adjust character count
//
Length -= 1; // For the lf - we'll convert the cr.
//
// Set null terminator
//
(*pRetString)[Length - 1] = 0;
return(STATUS_SUCCESS);
}