windows-nt/Source/XPSP1/NT/base/wmi/dll/logapi.c
2020-09-26 16:20:57 +08:00

3474 lines
114 KiB
C

/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
logapi.c
Abstract:
WMI logger api set. The routines here will need to appear like they
are system calls. They are necessary to do the necessary error checking
and do most of the legwork that can be done outside the kernel. The
kernel portion will subsequently only deal with the actual logging
and tracing.
Author:
28-May-1997 JeePang
Revision History:
--*/
#ifndef MEMPHIS
#ifdef DBG
#include <stdio.h> // only for fprintf
#endif
#include <nt.h>
#include <ntrtl.h> // for ntutrl.h
#include <nturtl.h> // for RTL_CRITICAL_SECTION in winbase.h/wtypes.h
#include <wtypes.h> // for LPGUID in wmium.h
#include <ntverp.h>
#include "wmiump.h"
#include "evntrace.h"
#include "tracelib.h"
#define MAXSTR 1024
#define MAXINST 0XFFFFFFFF
#define TRACE_RETRY_COUNT 5
#define TRACE_HEADER_FULL (TRACE_HEADER_FLAG | TRACE_HEADER_EVENT_TRACE \
| (TRACE_HEADER_TYPE_FULL_HEADER << 16))
#define TRACE_HEADER_INSTANCE (TRACE_HEADER_FLAG | TRACE_HEADER_EVENT_TRACE \
| (TRACE_HEADER_TYPE_INSTANCE << 16))
ULONG WmipIsBBTOn = 0;
//
// This guid is used by RegisterTraceGuids when register a tracelog
// provider. Any ACLs for controlling registration should be placed on
// this guid. Note that since the kernel will created unnamed guid
// objects, multiple tracelog providers can register without issue.
//
// {DF8480A1-7492-4f45-AB78-1084642581FB}
GUID RegisterReservedGuid = { 0xdf8480a1, 0x7492, 0x4f45, 0xab, 0x78, 0x10, 0x84, 0x64, 0x25, 0x81, 0xfb };
//
// Local Data Structures Used
//
typedef struct _TRACE_REG_PACKET {
ULONG RegistrationCookie;
ULONG Reserved;
} TRACE_REG_PACKET, *PTRACE_REG_PACKET;
HANDLE WmipDeviceHandle = NULL;
VOID
WmipCopyInfoToProperties(
IN PWMI_LOGGER_INFORMATION Info,
IN PEVENT_TRACE_PROPERTIES Properties
);
VOID
WmipCopyPropertiesToInfo(
IN PEVENT_TRACE_PROPERTIES Properties,
IN PWMI_LOGGER_INFORMATION Info
);
NTSTATUS
WmipTraceUmMessage(
IN ULONG Size,
IN ULONG64 LoggerHandle,
IN ULONG MessageFlags,
IN LPGUID MessageGuid,
IN USHORT MessageNumber,
va_list MessageArgList
);
VOID
WmipFixupLoggerStrings(
PWMI_LOGGER_INFORMATION LoggerInfo
);
ULONG
WmipCheckForEnoughFreeSpace(
PWCHAR FullLogFileName,
ULONG FullLogFileNameLen,
ULONG MaxFileSizeSpecified,
ULONG AppendMode
);
VOID
WmipFixupLoggerStrings(
PWMI_LOGGER_INFORMATION LoggerInfo
)
{
ULONG Offset = sizeof(WMI_LOGGER_INFORMATION);
ULONG LoggerInfoSize;
if (LoggerInfo == NULL)
return;
LoggerInfoSize = LoggerInfo->Wnode.BufferSize;
if (LoggerInfoSize <= Offset)
return;
//
// Fixup LoggerName first
//
if (LoggerInfo->LoggerName.Length > 0) {
LoggerInfo->LoggerName.Buffer = (PWCHAR) ((PUCHAR)LoggerInfo + Offset);
Offset += LoggerInfo->LoggerName.MaximumLength;
}
if (LoggerInfoSize <= Offset)
return;
if (LoggerInfo->LogFileName.Length > 0) {
LoggerInfo->LogFileName.Buffer = (PWCHAR)((PUCHAR)LoggerInfo + Offset);
Offset += LoggerInfo->LogFileName.MaximumLength;
}
#ifdef DBG
WmipAssert(LoggerInfoSize >= Offset);
#endif
}
ULONG
WmipCheckForEnoughFreeSpace(
PWCHAR FullLogFileName,
ULONG FullLogFileNameLen,
ULONG MaxFileSizeSpecified,
ULONG AppendMode
)
{
ULONG NeededSpace = MaxFileSizeSpecified;
ULONG SizeNeeded;
UINT ReturnedSizeNeeded;
PWCHAR strLogFileDir = NULL;
WCHAR strSystemDir[MAX_PATH];
if (NeededSpace && AppendMode) {
ULONG Status;
WIN32_FILE_ATTRIBUTE_DATA FileAttributes;
ULONGLONG ExistingFileSize;
ULONG ExistingFileSizeInMBytes;
if (GetFileAttributesExW(FullLogFileName,
GetFileExInfoStandard,
(LPVOID)(&FileAttributes))) {
ExistingFileSize = (((ULONGLONG)FileAttributes.nFileSizeHigh) << 32)
+ FileAttributes.nFileSizeLow;
ExistingFileSizeInMBytes = (ULONG)(ExistingFileSize / (1024 * 1024));
if (ExistingFileSizeInMBytes >= NeededSpace) {
return ERROR_DISK_FULL;
}
else {
NeededSpace -= ExistingFileSizeInMBytes;
}
}
else { // GetFileAttributesExW() failed
Status = GetLastError();
// If the file is not found, advapi32.dll treats
// the case as EVENT_TRACE_FILE_MODE_NEWFILE
// So, we will let it go here.
if (ERROR_FILE_NOT_FOUND != Status) {
return Status;
}
}
}
ReturnedSizeNeeded = GetSystemDirectoryW(strSystemDir, MAX_PATH);
if (ReturnedSizeNeeded == 0) {
return GetLastError();
}
if (ReturnedSizeNeeded < 2 || FullLogFileNameLen < 2) {
// This really cannot happen.
return ERROR_INVALID_PARAMETER;
}
if (FullLogFileName[1] == L':' && strSystemDir[1] == L':') {
if (!_wcsnicmp(FullLogFileName, strSystemDir, 1)) {
NeededSpace += 200;
}
}
// Check for space only when we have to
if (NeededSpace) {
int i;
ULARGE_INTEGER FreeBytesAvailable, TotalNumberOfBytes;
ULONG FreeMegaBytes;
strLogFileDir = WmipAlloc((FullLogFileNameLen + 1) * sizeof(WCHAR));
if (strLogFileDir == NULL) {
return ERROR_OUTOFMEMORY;
}
wcsncpy(strLogFileDir, FullLogFileName, FullLogFileNameLen);
for (i = FullLogFileNameLen - 1; i >= 0; i--) {
if (strLogFileDir[i] == L'\\' || strLogFileDir[i] == L'/') {
strLogFileDir[i] = '\0';
break;
}
}
if (i < 0) {
// This really cannot happen.
WmipFree(strLogFileDir);
strLogFileDir = NULL;
}
// it also works with network paths
if (GetDiskFreeSpaceExW(strLogFileDir,
&FreeBytesAvailable,
&TotalNumberOfBytes,
NULL)) {
FreeMegaBytes = (ULONG)(FreeBytesAvailable.QuadPart / (1024 *1024));
WmipFree(strLogFileDir);
if (FreeMegaBytes < NeededSpace) {
return ERROR_DISK_FULL;
}
}
else {
WmipFree(strLogFileDir);
return GetLastError();
}
}
return ERROR_SUCCESS;
}
ULONG
WMIAPI
StartTraceA(
OUT PTRACEHANDLE LoggerHandle,
IN LPCSTR LoggerName,
IN OUT PEVENT_TRACE_PROPERTIES Properties
)
/*++
Routine Description:
This is the ANSI version routine to start a logger.
The caller must pass in a pointer to accept the returned logger handle,
and must provide a valid logger name.
Arguments:
LoggerHandle The handle to the logger to be returned.
LoggerName A unique name for the logger
Properties Logger properties. If the caller wishes to use WMI's
defaults, all the numeric values must be set to 0.
Furthermore, the LoggerName and LogFileName fields
within must point to sufficient storage for the names
to be returned.
Return Value:
The status of performing the action requested.
--*/
{
NTSTATUS Status;
ULONG ErrorCode;
PWMI_LOGGER_INFORMATION LoggerInfo = NULL;
ANSI_STRING AnsiString;
ULONG IsLogFile;
LPSTR CapturedName;
ULONG SizeNeeded;
ULONG LogFileNameLen, LoggerNameLen;
PCHAR LogFileName;
PTRACE_ENABLE_FLAG_EXTENSION FlagExt = NULL;
PCHAR Buffer=NULL;
PCHAR FullPathName=NULL;
ULONG FullPathNameSize = MAXSTR;
WmipInitProcessHeap();
// first check to make sure that arguments passed are alright
//
if (Properties == NULL || LoggerHandle == NULL) {
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
if (LoggerName == NULL) {
return WmipSetDosError(ERROR_INVALID_NAME);
}
IsLogFile = TRUE;
LogFileNameLen = 0;
LoggerNameLen = 0;
LogFileName = NULL;
try {
// LoggerName is a Mandatory Parameter. Must provide space for it.
//
LoggerNameLen = strlen(LoggerName);
SizeNeeded = sizeof (EVENT_TRACE_PROPERTIES) + LoggerNameLen + 1;
//
// Rules for Kernel Logger Identification
// 1. If the logger name is "NT Kernel Logger", it is the kernel logger, and
// the System GUID is copied as well.
// 2. If the GUID is equal to the System GUID, but not the name, reject the session.
//
if (!strcmp(LoggerName, KERNEL_LOGGER_NAMEA)) {
Properties->Wnode.Guid = SystemTraceControlGuid;
}
else if (IsEqualGUID(&Properties->Wnode.Guid, &SystemTraceControlGuid)) {
// LoggerName is not "NT Kernel Logger", but Guid is
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
// If the caller supplied loggername and LogFileName offsets
// make sure they are in range.
//
if (Properties->LoggerNameOffset > 0)
if ((Properties->LoggerNameOffset < sizeof (EVENT_TRACE_PROPERTIES))
|| (Properties->LoggerNameOffset > Properties->Wnode.BufferSize))
return WmipSetDosError(ERROR_INVALID_PARAMETER);
if (Properties->LogFileNameOffset > 0) {
ULONG RetValue;
if ((Properties->LogFileNameOffset < sizeof(EVENT_TRACE_PROPERTIES))
|| (Properties->LogFileNameOffset > Properties->Wnode.BufferSize))
return WmipSetDosError(ERROR_INVALID_PARAMETER);
LogFileName = ((PCHAR)Properties + Properties->LogFileNameOffset );
SizeNeeded += sizeof (LogFileName);
Retry:
FullPathName = WmipAlloc(FullPathNameSize);
if (FullPathName == NULL) {
return WmipSetDosError(ERROR_OUTOFMEMORY);
}
RetValue = GetFullPathName(LogFileName, FullPathNameSize, FullPathName, NULL);
if (RetValue != 0) {
if (RetValue > FullPathNameSize) {
WmipFree(FullPathName);
FullPathNameSize = RetValue;
goto Retry;
}
else {
LogFileName = FullPathName;
}
}
LogFileNameLen = strlen(LogFileName);
if (LogFileNameLen == 0)
IsLogFile = FALSE;
}
else
IsLogFile = FALSE;
//
// Check to see if there is room in the Properties structure
// to return both the InstanceName (LoggerName) and the LogFileName
//
if (Properties->Wnode.BufferSize < SizeNeeded) {
ErrorCode = ERROR_BAD_LENGTH;
goto Cleanup;
}
CapturedName = (LPSTR) LoggerName;
LoggerNameLen = strlen(CapturedName);
if (LoggerNameLen <= 0) {
ErrorCode = ERROR_INVALID_NAME;
goto Cleanup;
}
if (!(Properties->LogFileMode & EVENT_TRACE_REAL_TIME_MODE)) {
if (!IsLogFile) {
ErrorCode = ERROR_BAD_PATHNAME;
goto Cleanup;
}
}
if ((Properties->LogFileMode & EVENT_TRACE_REAL_TIME_MODE) &&
(Properties->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) ) {
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
if (Properties->LogFileMode & EVENT_TRACE_FILE_MODE_APPEND) {
if ( (Properties->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR)
|| (Properties->LogFileMode & EVENT_TRACE_REAL_TIME_MODE)) {
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
}
if (Properties->LogFileMode & EVENT_TRACE_FILE_MODE_PREALLOCATE) {
if ( (Properties->MaximumFileSize == 0)
|| (Properties->LogFileMode & EVENT_TRACE_FILE_MODE_NEWFILE)
|| (!IsLogFile)) {
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
}
//
// Relogger is supported only with Private Logger
//
if (Properties->LogFileMode & EVENT_TRACE_RELOG_MODE) {
if (!(Properties->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE)
|| (Properties->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR)
|| (Properties->LogFileMode & EVENT_TRACE_FILE_MODE_NEWFILE)
|| (Properties->LogFileMode & EVENT_TRACE_FILE_MODE_APPEND) ) {
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
}
if (Properties->LogFileMode & EVENT_TRACE_FILE_MODE_NEWFILE) {
if ((Properties->MaximumFileSize == 0) ||
(Properties->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR) ||
(IsLogFile != TRUE)
){
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
//
// Check to see if there a %d Pattern in the LogFileName
//
Buffer = WmipAlloc((LogFileNameLen+64) * sizeof(CHAR) );
if (Buffer == NULL) {
ErrorCode = ERROR_OUTOFMEMORY;
goto Cleanup;
}
sprintf(Buffer, LogFileName, 1);
if (RtlEqualMemory(LogFileName, Buffer, LogFileNameLen) ) {
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
}
// For UserMode logger the LoggerName and LogFileName must be
// passed in as offsets.
//
SizeNeeded = sizeof(WMI_LOGGER_INFORMATION) +
(LoggerNameLen + 1) * sizeof(WCHAR) +
(LogFileNameLen + 1) * sizeof(WCHAR);
if (Properties->EnableFlags & EVENT_TRACE_FLAG_EXTENSION) {
FlagExt = (PTRACE_ENABLE_FLAG_EXTENSION) &Properties->EnableFlags;
if ((FlagExt->Length == 0) || (FlagExt->Offset == 0))
return WmipSetDosError(ERROR_INVALID_PARAMETER);
SizeNeeded += FlagExt->Length * sizeof(ULONG);
}
SizeNeeded = (SizeNeeded +7) & ~7;
LoggerInfo = WmipAlloc(SizeNeeded);
if (LoggerInfo == NULL) {
ErrorCode = ERROR_OUTOFMEMORY;
goto Cleanup;
}
RtlZeroMemory(LoggerInfo, SizeNeeded);
// at this point, we need to prepare WMI_LOGGER_INFORMATION
// which requires Ansi strings to be converted to UNICODE_STRING
//
*LoggerHandle = 0;
WmipCopyPropertiesToInfo(
(PEVENT_TRACE_PROPERTIES) Properties,
LoggerInfo);
//
// If we are relogging, the caller passes in the number of processors
// for the Private logger to use via the ProviderId field in Wnode
//
LoggerInfo->NumberOfProcessors = Properties->Wnode.ProviderId;
LoggerInfo->Wnode.ProviderId = 0;
RtlInitAnsiString(&AnsiString, CapturedName);
LoggerInfo->LoggerName.MaximumLength =
(USHORT) (sizeof(WCHAR) * (LoggerNameLen + 1));
LoggerInfo->LoggerName.Buffer =
(LPWSTR) ( ((PUCHAR) LoggerInfo)
+ sizeof(WMI_LOGGER_INFORMATION));
Status = RtlAnsiStringToUnicodeString(
&LoggerInfo->LoggerName,
&AnsiString, FALSE);
if (!NT_SUCCESS(Status)) {
ErrorCode = WmipNtStatusToDosError(Status);
goto Cleanup;
}
if (IsLogFile) {
LoggerInfo->LogFileName.MaximumLength =
(USHORT) (sizeof(WCHAR) * (LogFileNameLen + 1));
LoggerInfo->LogFileName.Buffer =
(LPWSTR) ( ((PUCHAR) LoggerInfo)
+ sizeof(WMI_LOGGER_INFORMATION)
+ LoggerInfo->LoggerName.MaximumLength);
RtlInitAnsiString(&AnsiString, LogFileName);
Status = RtlAnsiStringToUnicodeString(
&LoggerInfo->LogFileName,
&AnsiString, FALSE);
if (!NT_SUCCESS(Status)) {
ErrorCode = WmipNtStatusToDosError(Status);
goto Cleanup;
}
Status = WmipCheckForEnoughFreeSpace(LoggerInfo->LogFileName.Buffer,
LogFileNameLen,
Properties->MaximumFileSize,
(Properties->LogFileMode & EVENT_TRACE_FILE_MODE_APPEND));
if (Status != ERROR_SUCCESS) {
ErrorCode = Status;
goto Cleanup;
}
}
LoggerInfo->Wnode.BufferSize = SizeNeeded;
LoggerInfo->Wnode.Flags |= WNODE_FLAG_TRACED_GUID;
if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_EXTENSION) {
PTRACE_ENABLE_FLAG_EXTENSION tFlagExt;
ULONG Offset;
tFlagExt = (PTRACE_ENABLE_FLAG_EXTENSION) &LoggerInfo->EnableFlags;
Offset = SizeNeeded - (FlagExt->Length * sizeof(ULONG));
tFlagExt->Offset = (USHORT) Offset;
RtlCopyMemory(
(PCHAR) LoggerInfo + Offset,
(PCHAR) Properties + FlagExt->Offset,
FlagExt->Length * sizeof(ULONG) );
}
ErrorCode = WmipStartLogger(LoggerInfo);
if (ErrorCode == ERROR_SUCCESS) {
ULONG AvailableLength, RequiredLength;
PCHAR pLoggerName, pLogFileName;
WmipCopyInfoToProperties(
LoggerInfo,
(PEVENT_TRACE_PROPERTIES)Properties);
if (Properties->LoggerNameOffset == 0) {
Properties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
}
pLoggerName = (PCHAR)((PCHAR)Properties +
Properties->LoggerNameOffset );
if (Properties->LoggerNameOffset > Properties->LogFileNameOffset )
AvailableLength = Properties->Wnode.BufferSize -
Properties->LoggerNameOffset;
else
AvailableLength = Properties->LogFileNameOffset -
Properties->LoggerNameOffset;
RequiredLength = strlen(CapturedName) + 1;
if (RequiredLength <= AvailableLength) {
strcpy(pLoggerName, CapturedName);
}
*LoggerHandle = LoggerInfo->Wnode.HistoricalContext;
//
// If there is room copy fullpath name
//
if (Properties->LogFileNameOffset > Properties->LoggerNameOffset )
AvailableLength = Properties->Wnode.BufferSize -
Properties->LogFileNameOffset;
else
AvailableLength = Properties->LoggerNameOffset -
Properties->LogFileNameOffset;
if ( (LogFileNameLen > 0) && (AvailableLength >= LogFileNameLen) ) {
pLogFileName = (PCHAR)((PCHAR)Properties +
Properties->LogFileNameOffset );
strcpy(pLogFileName, LogFileName);
}
}
}
except (EXCEPTION_EXECUTE_HANDLER) {
ErrorCode = WmipNtStatusToDosError( GetExceptionCode() );
}
Cleanup:
if (LoggerInfo != NULL)
WmipFree(LoggerInfo);
if (FullPathName != NULL)
WmipFree(FullPathName);
if (Buffer != NULL)
WmipFree(Buffer);
return WmipSetDosError(ErrorCode);
}
ULONG
WMIAPI
StartTraceW(
OUT PTRACEHANDLE LoggerHandle,
IN LPCWSTR LoggerName,
IN OUT PEVENT_TRACE_PROPERTIES Properties
)
/*++
Routine Description:
This is the Unicode version routine to start a logger.
The caller must pass in a pointer to accept the returned logger handle,
and must provide a valid logger name.
Arguments:
LoggerHandle The handle to the logger to be returned.
LoggerName A unique name for the logger
Properties Logger properties. If the caller wishes to use WMI's
defaults, all the numeric values must be set to 0.
Furthermore, the LoggerName and LogFileName fields
within must point to sufficient storage for the names
to be returned.
Return Value:
The status of performing the action requested.
--*/
{
ULONG ErrorCode;
PWMI_LOGGER_INFORMATION LoggerInfo = NULL;
ULONG IsLogFile;
LPWSTR CapturedName;
ULONG SizeNeeded;
USHORT LogFileNameLen, LoggerNameLen;
PWCHAR LogFileName;
PTRACE_ENABLE_FLAG_EXTENSION FlagExt = NULL;
PWCHAR Buffer = NULL;
PWCHAR FullPathName = NULL;
ULONG FullPathNameSize = MAXSTR;
ULONG RetValue;
ULONG RelogPropSize = 0;
WmipInitProcessHeap();
// first check to make sure that arguments passed are alright
//
if (Properties == NULL || LoggerHandle == NULL) {
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
if (LoggerName == NULL) {
return WmipSetDosError(ERROR_INVALID_NAME);
}
IsLogFile = TRUE;
LogFileNameLen = 0;
LoggerNameLen = 0;
LogFileName = NULL;
try {
// LoggerName is a Mandatory Parameter. Must provide space for it.
//
CapturedName = (LPWSTR) LoggerName;
LoggerNameLen = (USHORT) wcslen(CapturedName);
SizeNeeded = sizeof (EVENT_TRACE_PROPERTIES) + (LoggerNameLen + 1) * sizeof(WCHAR);
//
// Rules for Kernel Logger Identification
// 1. If the logger name is "NT Kernel Logger", it is the kernel logger, and
// the System GUID is copied as well.
// 2. If the GUID is equal to the System GUID, but not the name, reject the session.
//
if (!wcscmp(LoggerName, KERNEL_LOGGER_NAMEW)) {
Properties->Wnode.Guid = SystemTraceControlGuid;
}
else if (IsEqualGUID(&Properties->Wnode.Guid, &SystemTraceControlGuid)) {
// LoggerName is not "NT Kernel Logger", but Guid is
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
// If the caller supplied loggername and LogFileName offsets
// make sure they are in range.
//
if (Properties->LoggerNameOffset > 0)
if ((Properties->LoggerNameOffset < sizeof(EVENT_TRACE_PROPERTIES))
|| (Properties->LoggerNameOffset > Properties->Wnode.BufferSize))
return WmipSetDosError(ERROR_INVALID_PARAMETER);
if (Properties->LogFileNameOffset > 0) {
if ((Properties->LogFileNameOffset < sizeof(EVENT_TRACE_PROPERTIES))
|| (Properties->LogFileNameOffset > Properties->Wnode.BufferSize))
return WmipSetDosError(ERROR_INVALID_PARAMETER);
LogFileName = (PWCHAR)((char*)Properties +
Properties->LogFileNameOffset);
SizeNeeded += (wcslen(LogFileName) +1) * sizeof(WCHAR);
Retry:
FullPathName = WmipAlloc(FullPathNameSize * sizeof(WCHAR));
if (FullPathName == NULL) {
return WmipSetDosError(ERROR_OUTOFMEMORY);
}
RetValue = GetFullPathNameW(LogFileName, FullPathNameSize, FullPathName,NULL);
if (RetValue != 0) {
if (RetValue > FullPathNameSize) {
WmipFree(FullPathName);
FullPathNameSize = RetValue;
goto Retry;
}
else {
LogFileName = FullPathName;
}
}
LogFileNameLen = (USHORT) wcslen(LogFileName);
if (LogFileNameLen <= 0)
IsLogFile = FALSE;
}
else
IsLogFile = FALSE;
//
// Check to see if there is room for both LogFileName and
// LoggerName (InstanceName) to be returned
//
if (Properties->Wnode.BufferSize < SizeNeeded) {
ErrorCode = ERROR_BAD_LENGTH;
goto Cleanup;
}
LoggerNameLen = (USHORT) wcslen(CapturedName);
if (LoggerNameLen <= 0) {
ErrorCode = ERROR_INVALID_NAME;
goto Cleanup;
}
if (!(Properties->LogFileMode & EVENT_TRACE_REAL_TIME_MODE)) {
if (!IsLogFile) {
ErrorCode = ERROR_BAD_PATHNAME;
goto Cleanup;
}
}
if ((Properties->LogFileMode & EVENT_TRACE_REAL_TIME_MODE) &&
(Properties->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) ) {
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
if (Properties->LogFileMode & EVENT_TRACE_FILE_MODE_APPEND) {
if ( (Properties->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR)
|| (Properties->LogFileMode & EVENT_TRACE_REAL_TIME_MODE)) {
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
}
if (Properties->LogFileMode & EVENT_TRACE_FILE_MODE_PREALLOCATE) {
if ( (Properties->MaximumFileSize == 0)
|| (Properties->LogFileMode & EVENT_TRACE_FILE_MODE_NEWFILE)
|| (!IsLogFile)) {
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
}
//
// Relogger is supported only with Private Logger
//
if (Properties->LogFileMode & EVENT_TRACE_RELOG_MODE) {
if (!(Properties->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE)
|| (Properties->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR)
|| (Properties->LogFileMode & EVENT_TRACE_FILE_MODE_NEWFILE)
|| (Properties->LogFileMode & EVENT_TRACE_FILE_MODE_APPEND) ) {
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
}
if (Properties->LogFileMode & EVENT_TRACE_FILE_MODE_NEWFILE) {
if ((Properties->MaximumFileSize == 0) ||
(Properties->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR) ||
(IsLogFile != TRUE)
){
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
//
// Check to see if there a %d Pattern in the LogFileName
//
Buffer = WmipAlloc((LogFileNameLen+64) * sizeof(WCHAR) );
if (Buffer == NULL) {
ErrorCode = ERROR_OUTOFMEMORY;
goto Cleanup;
}
swprintf(Buffer, LogFileName, 1);
if (RtlEqualMemory(LogFileName, Buffer, LogFileNameLen * sizeof(WCHAR))) {
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
}
SizeNeeded = sizeof(WMI_LOGGER_INFORMATION) +
(LoggerNameLen +1) * sizeof(WCHAR) +
(LogFileNameLen + 1) * sizeof(WCHAR);
if (Properties->EnableFlags & EVENT_TRACE_FLAG_EXTENSION) {
FlagExt = (PTRACE_ENABLE_FLAG_EXTENSION) &Properties->EnableFlags;
if ((FlagExt->Length == 0) || (FlagExt->Offset == 0)) {
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
SizeNeeded += FlagExt->Length * sizeof(ULONG);
}
//
// If RELOG mode, then pass on the LOGFILE_HEADER from old logfile
// appended to the LOGGER_INFORMATION
//
if (Properties->LogFileMode & EVENT_TRACE_RELOG_MODE) {
PSYSTEM_TRACE_HEADER pSysHeader;
pSysHeader = (PSYSTEM_TRACE_HEADER) ((PUCHAR)Properties + sizeof(EVENT_TRACE_PROPERTIES) );
RelogPropSize = pSysHeader->Packet.Size;
SizeNeeded += RelogPropSize;
}
SizeNeeded = (SizeNeeded +7) & ~7;
LoggerInfo = WmipAlloc(SizeNeeded);
if (LoggerInfo == NULL) {
ErrorCode = ERROR_OUTOFMEMORY;
goto Cleanup;
}
RtlZeroMemory(LoggerInfo, SizeNeeded);
// at this point, we need to prepare WMI_LOGGER_INFORMATION
// which requires wide char strings to be converted to UNICODE_STRING
//
*LoggerHandle = 0;
WmipCopyPropertiesToInfo(Properties, LoggerInfo);
//
// If we are relogging, the caller passes in the number of processors
// for the Private logger to use via the ProviderId field in Wnode
//
LoggerInfo->NumberOfProcessors = Properties->Wnode.ProviderId;
LoggerInfo->Wnode.ProviderId = 0;
LoggerInfo->LoggerName.MaximumLength =
sizeof(WCHAR) * (LoggerNameLen + 1);
LoggerInfo->LoggerName.Length =
sizeof(WCHAR) * LoggerNameLen;
LoggerInfo->LoggerName.Buffer = (PWCHAR)
(((PUCHAR) LoggerInfo) + sizeof(WMI_LOGGER_INFORMATION));
wcsncpy(LoggerInfo->LoggerName.Buffer, LoggerName, LoggerNameLen);
if (IsLogFile) {
ULONG Status;
LoggerInfo->LogFileName.MaximumLength =
sizeof(WCHAR) * (LogFileNameLen + 1);
LoggerInfo->LogFileName.Length =
sizeof(WCHAR) * LogFileNameLen;
LoggerInfo->LogFileName.Buffer = (PWCHAR)
(((PUCHAR) LoggerInfo) + sizeof(WMI_LOGGER_INFORMATION)
+ LoggerInfo->LoggerName.MaximumLength);
wcsncpy(LoggerInfo->LogFileName.Buffer,
LogFileName,
LogFileNameLen);
Status = WmipCheckForEnoughFreeSpace(LoggerInfo->LogFileName.Buffer,
LogFileNameLen,
Properties->MaximumFileSize,
(Properties->LogFileMode & EVENT_TRACE_FILE_MODE_APPEND));
if (Status != ERROR_SUCCESS) {
ErrorCode = Status;
goto Cleanup;
}
}
LoggerInfo->Wnode.BufferSize = SizeNeeded;
LoggerInfo->Wnode.Flags |= WNODE_FLAG_TRACED_GUID;
if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_EXTENSION) {
PTRACE_ENABLE_FLAG_EXTENSION tFlagExt;
ULONG Offset;
tFlagExt = (PTRACE_ENABLE_FLAG_EXTENSION) &LoggerInfo->EnableFlags;
Offset = SizeNeeded - (FlagExt->Length * sizeof(ULONG));
tFlagExt->Offset = (USHORT) Offset;
RtlCopyMemory(
(PCHAR) LoggerInfo + Offset,
(PCHAR) Properties + FlagExt->Offset,
FlagExt->Length * sizeof(ULONG) );
}
if ( (Properties->LogFileMode & EVENT_TRACE_RELOG_MODE) &&
(RelogPropSize > 0) ) {
PSYSTEM_TRACE_HEADER pRelog, pSysHeader;
PTRACE_LOGFILE_HEADER Relog;
pRelog = (PSYSTEM_TRACE_HEADER) ( ((PUCHAR) LoggerInfo) +
sizeof(WMI_LOGGER_INFORMATION) +
LoggerInfo->LoggerName.MaximumLength +
LoggerInfo->LogFileName.MaximumLength);
pSysHeader = (PSYSTEM_TRACE_HEADER) ( (PUCHAR)Properties + sizeof(EVENT_TRACE_PROPERTIES) );
RtlCopyMemory(pRelog, pSysHeader, RelogPropSize);
}
ErrorCode = WmipStartLogger(LoggerInfo);
if (ErrorCode == ERROR_SUCCESS) {
ULONG AvailableLength, RequiredLength;
PWCHAR pLoggerName;
PWCHAR pLogFileName;
WmipCopyInfoToProperties(LoggerInfo, Properties);
if (Properties->LoggerNameOffset > 0) {
Properties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
}
pLoggerName = (PWCHAR)((PCHAR)Properties +
Properties->LoggerNameOffset );
if (Properties->LoggerNameOffset > Properties->LogFileNameOffset )
AvailableLength = Properties->Wnode.BufferSize -
Properties->LoggerNameOffset;
else
AvailableLength = Properties->LogFileNameOffset -
Properties->LoggerNameOffset;
RequiredLength = (wcslen(CapturedName) + 1) * sizeof(WCHAR);
if (RequiredLength <= AvailableLength) {
wcscpy(pLoggerName, CapturedName);
}
*LoggerHandle = LoggerInfo->Wnode.HistoricalContext;
//
// If there is room for FullPath name, return it
// TODO: Do the same for ANSI code...
//
if (Properties->LogFileNameOffset > Properties->LoggerNameOffset )
AvailableLength = Properties->Wnode.BufferSize -
Properties->LogFileNameOffset;
else
AvailableLength = Properties->LoggerNameOffset -
Properties->LogFileNameOffset;
RequiredLength = LoggerInfo->LogFileName.Length;
pLogFileName = (PWCHAR)((PCHAR)Properties +
Properties->LogFileNameOffset );
if ( (RequiredLength > 0) && (RequiredLength <= AvailableLength) ) {
wcsncpy(pLogFileName, LoggerInfo->LogFileName.Buffer, LogFileNameLen);
pLogFileName[LogFileNameLen] = L'\0';
}
}
}
except (EXCEPTION_EXECUTE_HANDLER) {
ErrorCode = WmipNtStatusToDosError( GetExceptionCode() );
}
Cleanup:
if (LoggerInfo != NULL)
WmipFree(LoggerInfo);
if (FullPathName != NULL)
WmipFree(FullPathName);
if (Buffer != NULL)
WmipFree(Buffer);
return WmipSetDosError(ErrorCode);
}
ULONG
WMIAPI
ControlTraceA(
IN TRACEHANDLE LoggerHandle,
IN LPCSTR LoggerName,
IN OUT PEVENT_TRACE_PROPERTIES Properties,
IN ULONG Control
)
/*++
Routine Description:
This is the ANSI version routine to control and query an existing logger.
The caller must pass in either a valid handle, or a logger name to
reference the logger instance. If both are given, the logger name will
be used.
Arguments:
LoggerHandle The handle to the logger instance.
LoggerName A instance name for the logger
Properties Logger properties to be returned to the caller.
Control This can be one of the following:
EVENT_TRACE_CONTROL_QUERY - to query the logger
EVENT_TRACE_CONTROL_STOP - to stop the logger
EVENT_TRACE_CONTROL_UPDATE - to update the logger
EVENT_TRACE_CONTROL_FLUSH - to flush the logger
Return Value:
The status of performing the action requested.
--*/
{
NTSTATUS Status;
ULONG ErrorCode;
BOOLEAN IsKernelTrace = FALSE;
PWMI_LOGGER_INFORMATION LoggerInfo = NULL;
PWCHAR strLoggerName = NULL;
PWCHAR strLogFileName = NULL;
ULONG sizeNeeded = 0;
PCHAR FullPathName = NULL;
ULONG LoggerNameLen = MAXSTR;
ULONG LogFileNameLen = MAXSTR;
ULONG FullPathNameSize = MAXSTR;
ULONG RetValue;
WmipInitProcessHeap();
if (Properties == NULL) {
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
try {
if (Properties->Wnode.BufferSize < sizeof(EVENT_TRACE_PROPERTIES) ) {
ErrorCode = ERROR_BAD_LENGTH;
goto Cleanup;
}
//
// If the caller supplied loggername and LogFileName offsets
// make sure they are in range.
//
if (Properties->LoggerNameOffset > 0) {
if ((Properties->LoggerNameOffset < sizeof(EVENT_TRACE_PROPERTIES))
|| (Properties->LoggerNameOffset > Properties->Wnode.BufferSize))
{
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
}
if (Properties->LogFileNameOffset > 0) {
if ((Properties->LogFileNameOffset < sizeof(EVENT_TRACE_PROPERTIES))
|| (Properties->LogFileNameOffset > Properties->Wnode.BufferSize))
{
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
}
if (LoggerName != NULL) {
LoggerNameLen = strlen(LoggerName) + 1;
//
// Rules for Kernel Logger Identification when a string is given instead of handle
// 1. If the logger name is "NT Kernel Logger", it is the kernel logger, and
// the System GUID is copied as well.
// 2. If the GUID is equal to the System GUID, but not the name, reject the session.
// 3. If the logger name is null or of size 0, and the GUID is equal to the System
// GUID, let it proceed as the kernel logger.
//
if (!strcmp(LoggerName, KERNEL_LOGGER_NAMEA)) {
Properties->Wnode.Guid = SystemTraceControlGuid;
}
else if (IsEqualGUID(&Properties->Wnode.Guid, &SystemTraceControlGuid)) {
// LoggerName is not "NT Kernel Logger", but Guid is
if (strlen(LoggerName) > 0) {
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
}
}
if (IsEqualGUID(&Properties->Wnode.Guid, &SystemTraceControlGuid)) {
IsKernelTrace = TRUE;
}
if ((LoggerHandle == 0) && (!IsKernelTrace)) {
if ((LoggerName == NULL) || (strlen(LoggerName) <= 0)) {
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
}
}
except (EXCEPTION_EXECUTE_HANDLER) {
ErrorCode = ERROR_NOACCESS;
goto Cleanup;
}
RetryFull:
// Extra 32 bytes for UMlogger to append instance name to logfilename.
LogFileNameLen += 16;
sizeNeeded = sizeof(WMI_LOGGER_INFORMATION) + (LoggerNameLen + LogFileNameLen) * sizeof(WCHAR);
sizeNeeded = (sizeNeeded +7) & ~7;
LoggerInfo = (PWMI_LOGGER_INFORMATION) WmipAlloc(sizeNeeded);
if (LoggerInfo == NULL) {
ErrorCode = ERROR_OUTOFMEMORY;
goto Cleanup;
}
RtlZeroMemory(LoggerInfo, sizeNeeded);
strLoggerName = (PWCHAR) ( ((PUCHAR) LoggerInfo)
+ sizeof(WMI_LOGGER_INFORMATION));
WmipInitString(&LoggerInfo->LoggerName,
strLoggerName,
LoggerNameLen * sizeof(WCHAR));
strLogFileName = (PWCHAR) ( ((PUCHAR) LoggerInfo)
+ sizeof(WMI_LOGGER_INFORMATION)
+ LoggerNameLen * sizeof(WCHAR));
WmipInitString(&LoggerInfo->LogFileName,
strLogFileName,
LogFileNameLen * sizeof(WCHAR));
// Look for logger name first
//
try {
if (LoggerName != NULL) {
if (strlen(LoggerName) > 0) {
ANSI_STRING AnsiString;
RtlInitAnsiString(&AnsiString, LoggerName);
Status = RtlAnsiStringToUnicodeString(
&LoggerInfo->LoggerName, &AnsiString, FALSE);
if (!NT_SUCCESS(Status)) {
ErrorCode = WmipNtStatusToDosError(Status);
goto Cleanup;
}
}
}
LoggerInfo->LogFileName.Buffer = (PWCHAR)
(((PCHAR) LoggerInfo) + sizeof(WMI_LOGGER_INFORMATION)
+ LoggerInfo->LoggerName.MaximumLength);
if (Properties->LogFileNameOffset >= sizeof(EVENT_TRACE_PROPERTIES)) {
ULONG lenLogFileName;
PCHAR strLogFileName;
strLogFileName = (PCHAR) ( ((PCHAR) Properties)
+ Properties->LogFileNameOffset);
Retry:
FullPathName = WmipAlloc(FullPathNameSize);
if (FullPathName == NULL) {
ErrorCode = ERROR_OUTOFMEMORY;
goto Cleanup;
}
RetValue = GetFullPathName(strLogFileName, FullPathNameSize, FullPathName, NULL);
if (RetValue != 0) {
if (RetValue > FullPathNameSize) {
WmipFree(FullPathName);
FullPathNameSize = RetValue;
goto Retry;
}
else {
strLogFileName = FullPathName;
}
}
lenLogFileName = strlen(strLogFileName);
if (lenLogFileName > 0) {
ANSI_STRING ansiLogFileName;
RtlInitAnsiString(& ansiLogFileName, strLogFileName);
LoggerInfo->LogFileName.MaximumLength =
sizeof(WCHAR) * ((USHORT) (lenLogFileName + 1));
Status = RtlAnsiStringToUnicodeString(
& LoggerInfo->LogFileName, & ansiLogFileName, FALSE);
if (!NT_SUCCESS(Status)) {
ErrorCode = WmipNtStatusToDosError(Status);
goto Cleanup;
}
}
}
// stuff the loggerhandle in Wnode
LoggerInfo->Wnode.HistoricalContext = LoggerHandle;
LoggerInfo->LogFileMode = Properties->LogFileMode;
LoggerInfo->Wnode.BufferSize = sizeNeeded;
LoggerInfo->Wnode.Flags |= WNODE_FLAG_TRACED_GUID;
//
// For Private Loggers the Guid is required to determine the provider
//
LoggerInfo->Wnode.Guid = Properties->Wnode.Guid;
switch (Control) {
case EVENT_TRACE_CONTROL_QUERY :
ErrorCode = WmipQueryLogger(LoggerInfo, FALSE);
break;
case EVENT_TRACE_CONTROL_STOP :
ErrorCode = WmipStopLogger(LoggerInfo);
break;
case EVENT_TRACE_CONTROL_UPDATE :
WmipCopyPropertiesToInfo((PEVENT_TRACE_PROPERTIES) Properties,
LoggerInfo);
LoggerInfo->Wnode.HistoricalContext = LoggerHandle;
ErrorCode = WmipQueryLogger(LoggerInfo, TRUE);
break;
case EVENT_TRACE_CONTROL_FLUSH :
ErrorCode = WmipFlushLogger(LoggerInfo);
break;
default :
ErrorCode = ERROR_INVALID_PARAMETER;
}
//
// The Kernel call could fail with ERROR_MORE_DATA and we need to retry
// with sufficient buffer space for the two strings. The size required
// is returned in the MaximuumLength field.
//
if (ErrorCode == ERROR_MORE_DATA) {
LogFileNameLen = LoggerInfo->LogFileName.MaximumLength / sizeof(WCHAR);
LoggerNameLen = LoggerInfo->LoggerName.MaximumLength / sizeof(WCHAR);
if (LoggerInfo != NULL) {
WmipFree(LoggerInfo);
LoggerInfo = NULL;
}
if (FullPathName != NULL) {
WmipFree(FullPathName);
FullPathName = NULL;
}
goto RetryFull;
}
if (ErrorCode == ERROR_SUCCESS) {
ANSI_STRING String;
PCHAR pLoggerName, pLogFileName;
ULONG BytesAvailable;
ULONG Length = 0;
//
// need to convert the strings back
//
WmipCopyInfoToProperties(
LoggerInfo,
(PEVENT_TRACE_PROPERTIES)Properties);
WmipFixupLoggerStrings(LoggerInfo);
if (Properties->LoggerNameOffset == 0)
Properties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
if (Properties->LoggerNameOffset > Properties->LogFileNameOffset)
BytesAvailable = Properties->Wnode.BufferSize -
Properties->LoggerNameOffset;
else
BytesAvailable = Properties->LogFileNameOffset -
Properties->LoggerNameOffset;
Status = RtlUnicodeStringToAnsiString(
&String, &LoggerInfo->LoggerName, TRUE);
if (NT_SUCCESS(Status)) {
Length = String.Length;
if (BytesAvailable < (Length + sizeof(CHAR)) ) {
PWNODE_TOO_SMALL WnodeSmall = (PWNODE_TOO_SMALL) Properties;
WnodeSmall->SizeNeeded = sizeof(EVENT_TRACE_PROPERTIES) + Length
+ LoggerInfo->LogFileName.Length + 2 * sizeof(CHAR);
WnodeSmall->WnodeHeader.Flags |= WNODE_FLAG_TOO_SMALL;
ErrorCode = ERROR_MORE_DATA;
goto Cleanup;
}
else {
pLoggerName = (PCHAR) ((PCHAR)Properties +
Properties->LoggerNameOffset);
RtlZeroMemory(pLoggerName, BytesAvailable);
if (Length > 0) {
strncpy(pLoggerName, String.Buffer, Length);
}
}
RtlFreeAnsiString(&String);
ErrorCode = RtlNtStatusToDosError(Status);
}
if (Properties->LogFileNameOffset == 0) {
Properties->LogFileNameOffset = Properties->LoggerNameOffset +
Length;
}
if (Properties->LogFileNameOffset > Properties->LoggerNameOffset)
BytesAvailable = Properties->Wnode.BufferSize -
Properties->LogFileNameOffset;
else
BytesAvailable = Properties->LoggerNameOffset -
Properties->LogFileNameOffset;
Status = RtlUnicodeStringToAnsiString(
&String, &LoggerInfo->LogFileName, TRUE);
if (NT_SUCCESS(Status)) {
Length = String.Length;
if (BytesAvailable < (Length + sizeof(CHAR)) ) {
PWNODE_TOO_SMALL WnodeSmall = (PWNODE_TOO_SMALL) Properties;
WnodeSmall->SizeNeeded = (Properties->Wnode.BufferSize - BytesAvailable) + Length + sizeof(CHAR);
WnodeSmall->WnodeHeader.Flags |= WNODE_FLAG_TOO_SMALL;
ErrorCode = ERROR_MORE_DATA;
}
else {
pLogFileName = (PCHAR) ((PCHAR)Properties +
Properties->LogFileNameOffset);
RtlZeroMemory(pLogFileName, BytesAvailable);
strncpy(pLogFileName, String.Buffer, Length );
}
RtlFreeAnsiString(&String);
ErrorCode = RtlNtStatusToDosError(Status);
}
}
}
except (EXCEPTION_EXECUTE_HANDLER) {
ErrorCode = WmipNtStatusToDosError(GetExceptionCode());
}
Cleanup:
if (LoggerInfo != NULL)
WmipFree(LoggerInfo);
if (FullPathName != NULL)
WmipFree(FullPathName);
return WmipSetDosError(ErrorCode);
}
ULONG
WMIAPI
ControlTraceW(
IN TRACEHANDLE LoggerHandle,
IN LPCWSTR LoggerName,
IN OUT PEVENT_TRACE_PROPERTIES Properties,
IN ULONG Control
)
/*++
Routine Description:
This is the ANSI version routine to control and query an existing logger.
The caller must pass in either a valid handle, or a logger name to
reference the logger instance. If both are given, the logger name will
be used.
Arguments:
LoggerHandle The handle to the logger instance.
LoggerName A instance name for the logger
Properties Logger properties to be returned to the caller.
Control This can be one of the following:
EVENT_TRACE_CONTROL_QUERY - to query the logger
EVENT_TRACE_CONTROL_STOP - to stop the logger
EVENT_TRACE_CONTROL_UPDATE - to update the logger
EVENT_TRACE_CONTROL_FLUSH - to flush the logger
Return Value:
The status of performing the action requested.
--*/
{
ULONG ErrorCode;
BOOLEAN IsKernelTrace = FALSE;
PWMI_LOGGER_INFORMATION LoggerInfo = NULL;
PWCHAR strLoggerName = NULL;
PWCHAR strLogFileName = NULL;
ULONG sizeNeeded = 0;
PWCHAR FullPathName = NULL;
ULONG LoggerNameLen = MAXSTR;
ULONG LogFileNameLen = MAXSTR;
ULONG RetValue;
WmipInitProcessHeap();
if (Properties == NULL) {
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
try {
if (Properties->Wnode.BufferSize < sizeof(EVENT_TRACE_PROPERTIES) ) {
ErrorCode = ERROR_BAD_LENGTH;
goto Cleanup;
}
//
// If the caller supplied loggername and LogFileName offsets
// make sure they are in range.
//
if (Properties->LoggerNameOffset > 0) {
if ((Properties->LoggerNameOffset < sizeof (EVENT_TRACE_PROPERTIES))
|| (Properties->LoggerNameOffset > Properties->Wnode.BufferSize)) {
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
}
if (Properties->LogFileNameOffset > 0) {
if ((Properties->LogFileNameOffset < sizeof(EVENT_TRACE_PROPERTIES))
|| (Properties->LogFileNameOffset > Properties->Wnode.BufferSize))
{
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
}
if (LoggerName != NULL) {
LoggerNameLen = wcslen(LoggerName) + 1;
//
// Rules for Kernel Logger Identification when a string is given instead of handle
// 1. If the logger name is "NT Kernel Logger", it is the kernel logger, and
// the System GUID is copied as well.
// 2. If the GUID is equal to the System GUID, but not the name, reject the session.
// 3. If the logger name is null or of size 0, and the GUID is equal to the System
// GUID, let it proceed as the kernel logger.
//
if (!wcscmp(LoggerName, KERNEL_LOGGER_NAMEW)) {
Properties->Wnode.Guid = SystemTraceControlGuid;
}
else if (IsEqualGUID(&Properties->Wnode.Guid, &SystemTraceControlGuid)) {
// LoggerName is not "NT Kernel Logger", but Guid is
if (wcslen(LoggerName) > 0) {
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
}
}
if (IsEqualGUID(&Properties->Wnode.Guid, &SystemTraceControlGuid)) {
IsKernelTrace = TRUE;
}
if ((LoggerHandle == 0) && (!IsKernelTrace)) {
if ((LoggerName == NULL) || (wcslen(LoggerName) <= 0)) {
ErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
}
}
except (EXCEPTION_EXECUTE_HANDLER) {
ErrorCode = ERROR_NOACCESS;
goto Cleanup;
}
RetryFull:
//
// Add an extra 16 characters to the LogFileName since the UMLogger
// could munge the name to add the PIDs at the end.
//
LogFileNameLen += 16;
sizeNeeded = sizeof(WMI_LOGGER_INFORMATION) + (LoggerNameLen + LogFileNameLen) * sizeof(WCHAR);
sizeNeeded = (sizeNeeded +7) & ~7;
LoggerInfo = (PWMI_LOGGER_INFORMATION) WmipAlloc(sizeNeeded);
if (LoggerInfo == NULL) {
ErrorCode = ERROR_OUTOFMEMORY;
goto Cleanup;
}
RtlZeroMemory(LoggerInfo, sizeNeeded);
strLoggerName = (PWCHAR) ( ((PUCHAR) LoggerInfo)
+ sizeof(WMI_LOGGER_INFORMATION));
WmipInitString(&LoggerInfo->LoggerName,
strLoggerName,
LoggerNameLen * sizeof(WCHAR));
strLogFileName = (PWCHAR) ( ((PUCHAR) LoggerInfo)
+ sizeof(WMI_LOGGER_INFORMATION)
+ LoggerNameLen * sizeof(WCHAR));
WmipInitString(&LoggerInfo->LogFileName,
strLogFileName,
LogFileNameLen * sizeof(WCHAR));
try {
if (LoggerName != NULL) {
if (wcslen(LoggerName) > 0) {
wcscpy(strLoggerName, (PWCHAR) LoggerName);
RtlInitUnicodeString(&LoggerInfo->LoggerName, strLoggerName);
}
}
if (Properties->LogFileNameOffset >= sizeof(EVENT_TRACE_PROPERTIES)) {
ULONG lenLogFileName;
PWCHAR strLogFileName;
ULONG FullPathNameSize = MAXSTR;
strLogFileName = (PWCHAR) ( ((PCHAR) Properties)
+ Properties->LogFileNameOffset);
Retry:
FullPathName = WmipAlloc(FullPathNameSize * sizeof(WCHAR));
if (FullPathName == NULL) {
ErrorCode = ERROR_OUTOFMEMORY;
goto Cleanup;
}
RetValue = GetFullPathNameW(strLogFileName, FullPathNameSize, FullPathName, NULL);
if (RetValue != 0) {
if (RetValue > FullPathNameSize) {
WmipFree(FullPathName);
FullPathNameSize = RetValue;
goto Retry;
}
else {
strLogFileName = FullPathName;
}
}
lenLogFileName = wcslen(strLogFileName);
LoggerInfo->LogFileName.Buffer = (PWCHAR)
(((PCHAR) LoggerInfo) + sizeof(WMI_LOGGER_INFORMATION)
+ LoggerInfo->LoggerName.MaximumLength);
if (lenLogFileName > 0) {
LoggerInfo->LogFileName.MaximumLength =
sizeof(WCHAR) * ((USHORT) (lenLogFileName + 1));
LoggerInfo->LogFileName.Length =
sizeof(WCHAR) * ((USHORT) (lenLogFileName));
wcsncpy(LoggerInfo->LogFileName.Buffer,
strLogFileName,
lenLogFileName);
}
else {
LoggerInfo->LogFileName.Length = 0;
LoggerInfo->LogFileName.MaximumLength = MAXSTR * sizeof(WCHAR);
}
}
LoggerInfo->LogFileMode = Properties->LogFileMode;
LoggerInfo->Wnode.HistoricalContext = LoggerHandle;
LoggerInfo->Wnode.BufferSize = sizeNeeded;
LoggerInfo->Wnode.Flags |= WNODE_FLAG_TRACED_GUID;
//
// For Private Loggers, the Guid must be supplied
//
LoggerInfo->Wnode.Guid = Properties->Wnode.Guid;
switch (Control) {
case EVENT_TRACE_CONTROL_QUERY :
ErrorCode = WmipQueryLogger(LoggerInfo, FALSE);
break;
case EVENT_TRACE_CONTROL_STOP :
ErrorCode = WmipStopLogger(LoggerInfo);
break;
case EVENT_TRACE_CONTROL_UPDATE :
WmipCopyPropertiesToInfo(Properties, LoggerInfo);
LoggerInfo->Wnode.HistoricalContext = LoggerHandle;
ErrorCode = WmipQueryLogger(LoggerInfo, TRUE);
break;
case EVENT_TRACE_CONTROL_FLUSH :
ErrorCode = WmipFlushLogger(LoggerInfo);
break;
default :
ErrorCode = ERROR_INVALID_PARAMETER;
}
//
// The Kernel call could fail with ERROR_MORE_DATA and we need to retry
// with sufficient buffer space for the two strings. The size required
// is returned in the MaximuumLength field.
//
if (ErrorCode == ERROR_MORE_DATA) {
LogFileNameLen = LoggerInfo->LogFileName.MaximumLength / sizeof(WCHAR);
LoggerNameLen = LoggerInfo->LoggerName.MaximumLength / sizeof(WCHAR);
if (LoggerInfo != NULL) {
WmipFree(LoggerInfo);
LoggerInfo = NULL;
}
if (FullPathName != NULL) {
WmipFree(FullPathName);
FullPathName = NULL;
}
goto RetryFull;
}
if (ErrorCode == ERROR_SUCCESS) {
ULONG Length = 0;
ULONG BytesAvailable = 0;
PWCHAR pLoggerName, pLogFileName;
WmipCopyInfoToProperties(LoggerInfo, Properties);
WmipFixupLoggerStrings(LoggerInfo);
if (Properties->LoggerNameOffset == 0)
Properties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
if (Properties->LoggerNameOffset > Properties->LogFileNameOffset )
BytesAvailable = Properties->Wnode.BufferSize -
Properties->LoggerNameOffset;
else
BytesAvailable = Properties->LogFileNameOffset -
Properties->LoggerNameOffset;
Length = LoggerInfo->LoggerName.Length;
if (Length > 0) {
if (BytesAvailable < (Length + sizeof(WCHAR) )) {
PWNODE_TOO_SMALL WnodeSmall = (PWNODE_TOO_SMALL) Properties;
WnodeSmall->SizeNeeded = sizeof(EVENT_TRACE_PROPERTIES) +
Length + LoggerInfo->LogFileName.Length + 2 * sizeof(WCHAR);
WnodeSmall->WnodeHeader.Flags |= WNODE_FLAG_TOO_SMALL;
Length = BytesAvailable - sizeof(WCHAR);
ErrorCode = ERROR_MORE_DATA;
goto Cleanup;
}
else {
pLoggerName = (PWCHAR) ((PCHAR)Properties +
Properties->LoggerNameOffset);
wcsncpy(pLoggerName, LoggerInfo->LoggerName.Buffer, Length/2 );
}
}
if (Properties->LogFileNameOffset == 0) {
Properties->LogFileNameOffset = Properties->LoggerNameOffset +
Length;
}
if (Properties->LogFileNameOffset > Properties->LoggerNameOffset )
BytesAvailable = Properties->Wnode.BufferSize -
Properties->LogFileNameOffset;
else
BytesAvailable = Properties->LoggerNameOffset -
Properties->LogFileNameOffset;
//
// Check for space to return LogFileName.
//
Length = LoggerInfo->LogFileName.Length;
if (Length > 0) {
if (BytesAvailable < (Length + sizeof(WCHAR)) ) {
PWNODE_TOO_SMALL WnodeSmall = (PWNODE_TOO_SMALL) Properties;
WnodeSmall->SizeNeeded = sizeof(EVENT_TRACE_PROPERTIES) +
Length + LoggerInfo->LogFileName.Length + 2 * sizeof(WCHAR);
WnodeSmall->WnodeHeader.Flags |= WNODE_FLAG_TOO_SMALL;
Length = BytesAvailable - sizeof(WCHAR);
ErrorCode = ERROR_MORE_DATA;
}
else {
pLogFileName = (PWCHAR) ((PCHAR)Properties +
Properties->LogFileNameOffset);
RtlZeroMemory(pLogFileName, BytesAvailable);
wcsncpy(pLogFileName,
LoggerInfo->LogFileName.Buffer, Length/2 );
}
}
}
}
except (EXCEPTION_EXECUTE_HANDLER) {
ErrorCode = WmipNtStatusToDosError(GetExceptionCode());
}
Cleanup:
if (LoggerInfo != NULL)
WmipFree(LoggerInfo);
if (FullPathName != NULL)
WmipFree(FullPathName);
return WmipSetDosError(ErrorCode);
}
ULONG
WMIAPI
EnableTrace(
IN ULONG Enable,
IN ULONG EnableFlag,
IN ULONG EnableLevel,
IN LPCGUID ControlGuid,
IN TRACEHANDLE TraceHandle
)
{
ULONG status;
PTRACE_ENABLE_CONTEXT pTraceHandle = (PTRACE_ENABLE_CONTEXT)&TraceHandle;
PWMI_LOGGER_INFORMATION pLoggerInfo;
ULONG Flags;
GUID Guid;
BOOLEAN IsKernelTrace = FALSE;
ULONG SizeNeeded = 0;
ULONG RetryCount = 1;
WmipInitProcessHeap();
// We only accept T/F for Enable code. In future, we really should take
// enumerated request codes. Declaring the Enable as ULONG instead
// of BOOLEAN should give us room for expansion.
if ( (ControlGuid == NULL)
|| (EnableLevel > 255)
|| ((Enable != TRUE) && (Enable != FALSE)) ) {
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
try {
Guid = *ControlGuid;
}
except (EXCEPTION_EXECUTE_HANDLER) {
return WmipSetDosError(ERROR_NOACCESS);
}
//
// Check to see the Heap and CritSec Guid
//
if( IsEqualGUID(&HeapGuid,&Guid)
|| IsEqualGUID(&CritSecGuid,&Guid)
){
WMITRACEENABLEDISABLEINFO TraceEnableInfo;
ULONG ReturnSize;
TraceEnableInfo.Guid = Guid;
TraceEnableInfo.Enable = (BOOLEAN)Enable;
status = WmipSendWmiKMRequest(NULL,
IOCTL_WMI_ENABLE_DISABLE_TRACELOG,
&TraceEnableInfo,
sizeof(WMITRACEENABLEDISABLEINFO),
NULL,
0,
&ReturnSize,
NULL);
return WmipSetDosError(status);
}
//
// Check to see if this is a valid TraceHandle or not by query
//
SizeNeeded = sizeof(WMI_LOGGER_INFORMATION) + 2 * MAXSTR;
Retry:
SizeNeeded = (SizeNeeded +7) & ~7;
pLoggerInfo = WmipAlloc(SizeNeeded);
if (pLoggerInfo == NULL) {
return WmipSetDosError(ERROR_OUTOFMEMORY);
}
RtlZeroMemory(pLoggerInfo, SizeNeeded);
pLoggerInfo->Wnode.HistoricalContext = TraceHandle;
if (IsEqualGUID(&Guid, &SystemTraceControlGuid)) {
WmiSetLoggerId(KERNEL_LOGGER_ID, &pLoggerInfo->Wnode.HistoricalContext);
IsKernelTrace = TRUE;
}
else {
// Validate TraceHandle is in range
pLoggerInfo->Wnode.HistoricalContext = TraceHandle;
}
pLoggerInfo->Wnode.BufferSize = SizeNeeded;
pLoggerInfo->Wnode.Flags |= WNODE_FLAG_TRACED_GUID;
//
// For PRIVATE logger, We need the Guid to determine the Provider
//
pLoggerInfo->Wnode.Guid = Guid;
status = WmipQueryLogger(pLoggerInfo, FALSE);
if (status != ERROR_SUCCESS) {
WmipFree(pLoggerInfo);
if ((status == ERROR_MORE_DATA) &&
(pTraceHandle->InternalFlag & EVENT_TRACE_INTERNAL_FLAG_PRIVATE)) {
SizeNeeded = RetryCount * (sizeof(WMI_LOGGER_INFORMATION)
+ 2 * MAXSTR);
if (RetryCount++ > TRACE_RETRY_COUNT)
return WmipSetDosError(status);
goto Retry;
}
return WmipSetDosError(status);
}
if (IsKernelTrace) {
Flags = pLoggerInfo->EnableFlags;
//
// If Enabling, we need to pass down the final state of the flags
// ie., the old flags plus the new flags.
// If disabling, we need to pass down the only the flags that
// are already turned on and being turned off now.
//
if (Enable) {
Flags |= EnableFlag;
}
else {
Flags &= EnableFlag;
}
//
// At this point if the Flags are 0, then no change is being
// requested.
//
if (Flags) {
pLoggerInfo->EnableFlags = Flags;
status = WmipQueryLogger(pLoggerInfo, TRUE);
}
WmipFree(pLoggerInfo);
return WmipSetDosError(status);
}
else {
WmipFree(pLoggerInfo);
pTraceHandle->Level = (UCHAR)EnableLevel;
}
pTraceHandle->EnableFlags = EnableFlag;
//
// This is done from the Control Process which can call this API for
// any known Guid. The service must maintain the information about
// whether the Guid is a valid Trace Guid or not.
//
if (TraceHandle == (TRACEHANDLE)0) {
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
try {
status = WmipNotificationRegistration(
&Guid,
(UCHAR)Enable,
(NOTIFICATIONCALLBACK) 0x0,
0,
TraceHandle,
NOTIFICATION_TRACE_FLAG, FALSE);
if (status != ERROR_SUCCESS)
return WmipSetDosError(status);
}
except (EXCEPTION_EXECUTE_HANDLER) {
return WmipSetDosError(ERROR_NOACCESS);
}
return WmipSetDosError(status);
}
ULONG
WmipTraceEvent(
IN TRACEHANDLE LoggerHandle,
IN PWNODE_HEADER Wnode
)
{
NTSTATUS NtStatus;
IO_STATUS_BLOCK IoStatus;
PULONG TraceMarker;
ULONG Size;
PEVENT_TRACE_HEADER EventTrace = (PEVENT_TRACE_HEADER)Wnode;
USHORT LoggerId;
PTRACE_ENABLE_CONTEXT pContext = (PTRACE_ENABLE_CONTEXT)&LoggerHandle;
Wnode->HistoricalContext = LoggerHandle;
if ( (pContext->InternalFlag & EVENT_TRACE_INTERNAL_FLAG_PRIVATE) && (WmipIsBBTOn == 0) ) {
goto UmOnly;
}
Size = EventTrace->Size;
//
// Now the LoggerHandle is expected to be filled in by the caller.
// But check to see if it has a valid value.
//
LoggerId = WmiGetLoggerId(LoggerHandle);
if ((LoggerId == 0) || (LoggerId == KERNEL_LOGGER_ID)) {
return ERROR_INVALID_HANDLE;
}
if (WmipIsBBTOn) {
WmiSetLoggerId(WMI_GLOBAL_LOGGER_ID, &Wnode->HistoricalContext);
}
NtStatus = NtTraceEvent(NULL,
ETW_NT_FLAGS_TRACE_HEADER,
sizeof(WNODE_HEADER),
Wnode);
return WmipNtStatusToDosError( NtStatus );
UmOnly:
return WmiTraceUmEvent(Wnode);
}
ULONG
WMIAPI
TraceEvent(
IN TRACEHANDLE LoggerHandle,
IN PEVENT_TRACE_HEADER EventTrace
)
{
ULONG Status, SavedMarker;
PULONG TraceMarker;
ULONG Size;
ULONGLONG SavedGuidPtr;
BOOLEAN RestoreSavedGuidPtr = FALSE;
// PWNODE_HEADER Wnode = (PWNODE_HEADER) EventTrace;
ULONG Flags;
WmipInitProcessHeap();
if (EventTrace == NULL ) {
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
try {
TraceMarker = (PULONG) EventTrace;
SavedMarker = *TraceMarker;
Flags = EventTrace->Flags;
EventTrace->Flags |= WNODE_FLAG_TRACED_GUID;
Size = EventTrace->Size;
if (Size < sizeof(EVENT_TRACE_HEADER)) {
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
*TraceMarker = 0;
EventTrace->Size = (USHORT)Size;
*TraceMarker |= TRACE_HEADER_FULL;
if (EventTrace->Flags & WNODE_FLAG_USE_GUID_PTR) {
RestoreSavedGuidPtr = TRUE;
SavedGuidPtr = EventTrace->GuidPtr;
}
Status = WmipTraceEvent(LoggerHandle, (PWNODE_HEADER) EventTrace);
*TraceMarker = SavedMarker;
EventTrace->Flags = Flags;
if (RestoreSavedGuidPtr) {
EventTrace->GuidPtr = SavedGuidPtr;
}
}
except (EXCEPTION_EXECUTE_HANDLER) {
Status = WmipNtStatusToDosError( GetExceptionCode() );
}
return WmipSetDosError(Status);
}
ULONG
WMIAPI
TraceEventInstance(
IN TRACEHANDLE LoggerHandle,
IN PEVENT_INSTANCE_HEADER EventTrace,
IN PEVENT_INSTANCE_INFO pInstInfo,
IN PEVENT_INSTANCE_INFO pParentInstInfo
)
{
PULONG TraceMarker;
PGUIDMAPENTRY GuidMapEntry;
ULONG Size, SavedMarker;
ULONG Flags;
// PWNODE_HEADER Wnode = (PWNODE_HEADER) EventTrace;
PEVENT_INSTANCE_HEADER InstanceHeader= (PEVENT_INSTANCE_HEADER) EventTrace;
ULONG Status;
WmipInitProcessHeap();
if ((EventTrace == NULL ) || (pInstInfo == NULL)) {
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
try {
Flags = EventTrace->Flags;
TraceMarker = (PULONG) EventTrace;
SavedMarker = *TraceMarker;
Flags |= WNODE_FLAG_TRACED_GUID;
Size = EventTrace->Size;
if (Size < sizeof(EVENT_INSTANCE_HEADER)) {
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
GuidMapEntry = (PGUIDMAPENTRY) pInstInfo->RegHandle;
if (GuidMapEntry == NULL) {
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
*TraceMarker = 0;
EventTrace->Size = (USHORT)Size;
*TraceMarker |= TRACE_HEADER_INSTANCE;
//
// With EVENT_INSTANCE_HEADER we don't want the logger
// to try to dereference the GuidPtr since it is
// just a hash value for the Guid and not really a LPGUID.
//
if (EventTrace->Flags & WNODE_FLAG_USE_GUID_PTR) {
EventTrace->Flags &= ~WNODE_FLAG_USE_GUID_PTR;
}
InstanceHeader->InstanceId = pInstInfo->InstanceId;
InstanceHeader->RegHandle= GuidMapEntry->GuidMap.GuidMapHandle;
if (pParentInstInfo != NULL) {
GuidMapEntry = (PGUIDMAPENTRY) pParentInstInfo->RegHandle;
if (GuidMapEntry == NULL) {
*TraceMarker = SavedMarker;
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
InstanceHeader->ParentInstanceId =
pParentInstInfo->InstanceId;
InstanceHeader->ParentRegHandle =
GuidMapEntry->GuidMap.GuidMapHandle;
}
Status = WmipTraceEvent(LoggerHandle, (PWNODE_HEADER) EventTrace);
EventTrace->Flags = Flags;
*TraceMarker = SavedMarker;
}
except (EXCEPTION_EXECUTE_HANDLER) {
Status = WmipNtStatusToDosError( GetExceptionCode() );
}
return WmipSetDosError(Status);
}
ULONG
WMIAPI
RegisterTraceGuidsW(
IN WMIDPREQUEST RequestAddress,
IN PVOID RequestContext,
IN LPCGUID ControlGuid,
IN ULONG GuidCount,
IN PTRACE_GUID_REGISTRATION GuidReg,
IN LPCWSTR MofImagePath,
IN LPCWSTR MofResourceName,
IN PTRACEHANDLE RegistrationHandle
)
{
GUID Guid;
ULONG SizeNeeded, StringPos, StringSize, WmiRegSize;
PWMIREGINFOW pWmiRegInfo;
PTRACE_GUID_REGISTRATION GuidRegPtr;
PWMIREGGUIDW WmiRegGuidPtr;
PWCHAR StringPtr;
PGUIDMAPENTRY pGuidMapEntry, pControlGMEntry;
PTRACEGUIDMAP GuidMapHandle = NULL, TraceGuidMap = NULL;
PTRACE_REG_INFO pTraceRegInfo = NULL;
PTRACE_REG_PACKET RegPacket;
TRACEHANDLE LoggerContext = 0;
HANDLE InProgressEvent = NULL, TraceCtxHandle;
ULONG RegistrationCookie;
ULONG Status;
ULONG i;
WmipInitProcessHeap();
if ((RequestAddress == NULL) ||
(RegistrationHandle == NULL) ||
(GuidCount <= 0) ||
(GuidReg == NULL) ||
(ControlGuid == NULL) ||
(GuidCount > WMIMAXREGGUIDCOUNT) )
{
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
try {
Guid = *ControlGuid;
}
except (EXCEPTION_EXECUTE_HANDLER) {
return WmipSetDosError(WmipNtStatusToDosError(GetExceptionCode()));
}
//
// Allocate temporary space (WMIREGINFO and TRACEGUIDMAP).
//
//
// Get size for WMIREGINFO for controlGuid + GuidCount.
//
GuidCount++;
StringPos = sizeof(WMIREGINFOW) + GuidCount * sizeof(WMIREGGUIDW);
WmiRegSize = StringPos;
if (MofImagePath == NULL) {
MofImagePath = L"";
}
if (MofResourceName != NULL) {
WmiRegSize += (wcslen(MofResourceName) + 2) * sizeof(WCHAR);
}
WmiRegSize += (wcslen(MofImagePath) + 2) * sizeof(WCHAR);
WmiRegSize = (WmiRegSize + 7) & ~7;
SizeNeeded = WmiRegSize;
//
// Get size for the storage for the GUIDMAPHANDLE structure
//
SizeNeeded += sizeof(TRACEGUIDMAP) * GuidCount;
pWmiRegInfo = WmipAlloc(SizeNeeded);
if (pWmiRegInfo != NULL) // Temporary space allocation succeeded
{
// Zero memory before losng SizeNeeded
RtlZeroMemory(pWmiRegInfo, SizeNeeded);
//
// Allocate space for persistent (non-temporary) structures (List for GuidMapEntrys and TraceRegInfo)
//
//
// Get size for pControlGMEntry
//
SizeNeeded = sizeof(GUIDMAPENTRY);
//
// Get size for pTraceRegInfo
//
SizeNeeded += sizeof(TRACE_REG_INFO);
//
// Get size for Guid Map Entries
//
SizeNeeded += sizeof(GUIDMAPENTRY) * GuidCount;
pControlGMEntry = WmipAlloc(SizeNeeded);
if (pControlGMEntry != NULL) // Persistent space allocation succeeded.
{
// Zero memory before losng SizeNeeded
RtlZeroMemory(pControlGMEntry, SizeNeeded);
//
// Initialize WmiRegInfo
//
pWmiRegInfo->BufferSize = WmiRegSize;
pWmiRegInfo->GuidCount = GuidCount;
WmiRegGuidPtr = &pWmiRegInfo->WmiRegGuid[0];
WmiRegGuidPtr->Flags |= WMIREG_FLAG_TRACED_GUID;
WmiRegGuidPtr->Flags |= WMIREG_FLAG_TRACE_CONTROL_GUID;
try {
*RegistrationHandle = (TRACEHANDLE) 0;
WmiRegGuidPtr->Guid = Guid;
for (i = 1; i < GuidCount; i++) {
WmiRegGuidPtr = &pWmiRegInfo->WmiRegGuid[i];
WmiRegGuidPtr->Flags |= WMIREG_FLAG_TRACED_GUID;
GuidRegPtr = &GuidReg[i-1];
WmiRegGuidPtr->Guid = *GuidRegPtr->Guid;
}
}
except (EXCEPTION_EXECUTE_HANDLER) {
WmipFree(pWmiRegInfo);
WmipFree(pControlGMEntry);
return WmipSetDosError(WmipNtStatusToDosError(GetExceptionCode()));
}
// Copy MOF resource path and name into WmiRegInfo
if (MofResourceName != NULL) {
pWmiRegInfo->MofResourceName = StringPos;
StringPtr = (PWCHAR)OffsetToPtr(pWmiRegInfo, StringPos);
Status = WmipCopyStringToCountedUnicode(MofResourceName,
StringPtr,
&StringSize,
FALSE);
StringPos += StringSize;
WmipAssert(StringPos <= WmiRegSize);
}
if (MofImagePath != NULL) {
pWmiRegInfo->RegistryPath = StringPos;
StringPtr = (PWCHAR)OffsetToPtr(pWmiRegInfo, StringPos);
Status = WmipCopyStringToCountedUnicode(MofImagePath,
StringPtr,
&StringSize,
FALSE);
StringPos += StringSize;
WmipAssert(StringPos <= WmiRegSize);
}
//
// Assign pointer to Guid Map Handle (no initialization needed here)
//
GuidMapHandle = (PTRACEGUIDMAP)((PUCHAR)pWmiRegInfo + WmiRegSize);
//
// Initialize pControlGMEntry
//
InitializeListHead(&pControlGMEntry->Entry);
//
// Initialize TraceRegInfo
//
pTraceRegInfo = (PTRACE_REG_INFO)((PUCHAR)pControlGMEntry + sizeof(GUIDMAPENTRY));
pControlGMEntry->pControlGuidData = pTraceRegInfo;
pTraceRegInfo->NotifyRoutine = RequestAddress;
//
// Initialize the list of Guid Map Entries.
//
pGuidMapEntry = (PGUIDMAPENTRY)((PUCHAR)pTraceRegInfo + sizeof(TRACE_REG_INFO));
for (i=1; i < GuidCount; i++) {
InsertTailList(&pControlGMEntry->Entry, &pGuidMapEntry->Entry);
pGuidMapEntry = (PGUIDMAPENTRY)((PUCHAR)pGuidMapEntry + sizeof(GUIDMAPENTRY));
}
//
// Manual reset, Initially not signalled
//
InProgressEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (InProgressEvent != NULL) // CreateEvent succeeded
{
pTraceRegInfo->InProgressEvent = InProgressEvent;
//
// Allocate Registration Cookie
//
RegistrationCookie = WmipAllocateCookie(pControlGMEntry,
RequestContext,
(LPGUID)&Guid);
if (RegistrationCookie != 0) // Cookie allocation succeeded
{
pTraceRegInfo->RegistrationCookie = RegistrationCookie;
#ifdef DBG
WmipDebugPrint(("WMI TRACE REG: AllocateCookie %d Callback %X\n",
RegistrationCookie, RequestAddress));
#endif
}
else // Cookie allocation failed
{
pTraceRegInfo->InProgressEvent = NULL;
NtClose(InProgressEvent);
WmipFree(pWmiRegInfo);
WmipFree(pControlGMEntry);
return WmipSetDosError(ERROR_NOT_ENOUGH_MEMORY);
}
}
else // CreateEvent failed
{
WmipFree(pWmiRegInfo);
WmipFree(pControlGMEntry);
return WmipSetDosError(ERROR_OBJECT_NOT_FOUND);
}
}
else // Persistent space allocation failed
{
WmipFree(pWmiRegInfo);
return WmipSetDosError(ERROR_NOT_ENOUGH_MEMORY);
}
}
else // Temporary space allocation failed
{
return WmipSetDosError(ERROR_NOT_ENOUGH_MEMORY);
}
Status = WmipRegisterGuids(&RegisterReservedGuid,
RegistrationCookie,
pWmiRegInfo,
GuidCount,
&GuidMapHandle,
&LoggerContext,
&TraceCtxHandle);
if (Status == ERROR_SUCCESS) // Call to Kernel succeeded
{
TraceGuidMap = &GuidMapHandle[0];
pControlGMEntry->GuidMap = *TraceGuidMap;
pTraceRegInfo->TraceCtxHandle = TraceCtxHandle;
try
{
PLIST_ENTRY Head, Next;
RegPacket = (PTRACE_REG_PACKET)RegistrationHandle;
RegPacket->RegistrationCookie = RegistrationCookie;
Head = &pControlGMEntry->Entry;
Next = Head->Flink;
for (i = 1; ((i < GuidCount) && (Head != Next)); i++) {
pGuidMapEntry = CONTAINING_RECORD(Next, GUIDMAPENTRY,Entry);
Next = Next->Flink;
pGuidMapEntry->InstanceId = 0;
TraceGuidMap = &GuidMapHandle[i];
pGuidMapEntry->GuidMap = *TraceGuidMap;
GuidRegPtr = &GuidReg[i-1];
GuidRegPtr->RegHandle = pGuidMapEntry;
}
}
except (EXCEPTION_EXECUTE_HANDLER) {
Status = WmipNtStatusToDosError(GetExceptionCode());
}
if (Status == ERROR_SUCCESS) // Guid Map Entry List initialization succeeded
{
//
// Place the registration handle on the list of handles to
// wait for notifications from
//
Status = WmipAddHandleToEventPump(&Guid,
(PVOID)TraceCtxHandle, // Needed for UM Logger to Reply
0,
0,
TraceCtxHandle);
if (Status == ERROR_SUCCESS && LoggerContext) // Adding handle to pump succeeded
{
//
// We will make the Enable/Disable notification here.
//
WNODE_HEADER Wnode;
PTRACE_ENABLE_CONTEXT pContext = (PTRACE_ENABLE_CONTEXT)&LoggerContext;
ULONG InOutSize;
BOOLEAN DeliverNotification = TRUE;
RtlZeroMemory(&Wnode, sizeof(Wnode));
Wnode.BufferSize = sizeof(Wnode);
Wnode.HistoricalContext = LoggerContext;
Wnode.Guid = Guid;
if (pContext->InternalFlag &
EVENT_TRACE_INTERNAL_FLAG_PRIVATE) {
// Before Delivering this Notification
// make sure that the Process Private logger
// is running.
pTraceRegInfo->EnabledState = TRUE;
if (!WmipIsPrivateLoggerOn()) {
DeliverNotification = FALSE;
}
}
if (DeliverNotification) {
try {
InOutSize = Wnode.BufferSize;
Status = (RequestAddress)(WMI_ENABLE_EVENTS,
RequestContext,
&InOutSize,
&Wnode);
} except (EXCEPTION_EXECUTE_HANDLER) {
#if DBG
Status = GetExceptionCode();
WmipDebugPrint(("WMI: Enable Call caused exception%d\n",
Status));
#endif
Status = ERROR_WMI_DP_FAILED;
}
}
}
}
if (Status != ERROR_SUCCESS) // One of the three failed: Enable, Adding handle to a pump, or Guid Map Entry List initialization
{
NtSetEvent(InProgressEvent, NULL);
pTraceRegInfo->InProgressEvent = NULL;
NtClose(InProgressEvent);
WmipFree(pWmiRegInfo);
UnregisterTraceGuids(*RegistrationHandle);
*RegistrationHandle = 0;
return (WmipSetDosError(Status));
}
}
else // Call to Kernel failed
{
// Cannot call UnregisterTraceGuids() so we need to clean up here
NtSetEvent(InProgressEvent, NULL);
pTraceRegInfo->InProgressEvent = NULL;
NtClose(InProgressEvent);
WmipFree(pWmiRegInfo);
WmipFree(pControlGMEntry);
WmipFreeCookie(RegistrationCookie);
return (WmipSetDosError(Status));
}
NtSetEvent(InProgressEvent, NULL);
pTraceRegInfo->InProgressEvent = NULL;
NtClose(InProgressEvent);
WmipFree(pWmiRegInfo);
return (WmipSetDosError(Status));
}
ULONG
WMIAPI
RegisterTraceGuidsA(
IN WMIDPREQUEST RequestAddress,
IN PVOID RequestContext,
IN LPCGUID ControlGuid,
IN ULONG GuidCount,
IN PTRACE_GUID_REGISTRATION GuidReg,
IN LPCSTR MofImagePath,
IN LPCSTR MofResourceName,
IN PTRACEHANDLE RegistrationHandle
)
/*++
Routine Description:
ANSI thunk to RegisterTraceGuidsW
--*/
{
LPWSTR MofImagePathUnicode = NULL;
LPWSTR MofResourceNameUnicode = NULL;
ULONG Status;
WmipInitProcessHeap();
if ((RequestAddress == NULL) ||
(RegistrationHandle == NULL) ||
(GuidCount <= 0) ||
(GuidReg == NULL) ||
(ControlGuid == NULL) ||
(GuidCount > WMIMAXREGGUIDCOUNT) )
{
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
Status = AnsiToUnicode(MofImagePath, &MofImagePathUnicode);
if (Status == ERROR_SUCCESS) {
if (MofResourceName) {
Status = AnsiToUnicode(MofResourceName, &MofResourceNameUnicode);
}
if (Status == ERROR_SUCCESS) {
Status = RegisterTraceGuidsW(RequestAddress,
RequestContext,
ControlGuid,
GuidCount,
GuidReg,
MofImagePathUnicode,
MofResourceNameUnicode,
RegistrationHandle
);
if (MofResourceNameUnicode) {
WmipFree(MofResourceNameUnicode);
}
}
if (MofImagePathUnicode) {
WmipFree(MofImagePathUnicode);
}
}
return(Status);
}
ULONG
WMIAPI
UnregisterTraceGuids(
IN TRACEHANDLE RegistrationHandle
)
{
// First check if the handle belongs to a Trace Control Guid.
// Then UnRegister all the regular trace guids controlled by
// this control guid and free up the storage allocated to maintain
// the TRACEGUIDMAPENTRY structures.
// Get to the real Registration Handle, stashed away in
// in the internal structures and pass it onto the call.
PGUIDMAPENTRY pControlGMEntry, GuidMapBase;
WMIHANDLE WmiRegistrationHandle;
PLIST_ENTRY Next, Head;
ULONG Status;
PVOID RequestContext;
PTRACE_REG_INFO pTraceRegInfo = NULL;
PTRACE_REG_PACKET RegPacket;
GUID ControlGuid;
ULONG64 LoggerContext = 0;
WMIDPREQUEST RequestAddress;
WmipInitProcessHeap();
if (RegistrationHandle == 0) {
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
RegPacket = (PTRACE_REG_PACKET)&RegistrationHandle;
if (!WmipLookupCookie(RegPacket->RegistrationCookie,
NULL,
&pControlGMEntry,
&RequestContext) ){
WmipDebugPrint(("WMI: LOOKUP COOKIE FAILED\n"));
return(ERROR_INVALID_PARAMETER);
}
try {
if (pControlGMEntry->pControlGuidData == NULL) {
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
//
// Free the Registration Cookie
//
pTraceRegInfo = pControlGMEntry->pControlGuidData;
RequestAddress = pTraceRegInfo->NotifyRoutine;
WmipGetGuidInCookie(pTraceRegInfo->RegistrationCookie, &ControlGuid);
WmipFreeCookie(pTraceRegInfo->RegistrationCookie);
WmiRegistrationHandle = (WMIHANDLE)pTraceRegInfo->TraceCtxHandle;
if (WmiRegistrationHandle == NULL) {
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
Status = WmiUnregisterGuids(WmiRegistrationHandle,
&ControlGuid,
&LoggerContext);
//
// All the TraceGuidMapEntry structures are cleaned up when
// WmipFree(pControlGMEntry) is called.
//
//
// Check to see if we need to fire the Disable callback
// before freeing the TraceRegInfo
//
if ((Status == ERROR_SUCCESS) && LoggerContext) {
WNODE_HEADER Wnode;
ULONG InOutSize = sizeof(Wnode);
RtlZeroMemory(&Wnode, sizeof(Wnode));
Wnode.BufferSize = sizeof(Wnode);
Wnode.HistoricalContext = LoggerContext;
Wnode.Guid = ControlGuid;
Status = (RequestAddress)(WMI_DISABLE_EVENTS,
RequestContext,
&InOutSize,
&Wnode);
}
// This will clear all the space allocated (refer to RegisterTraceGuids())
WmipFree(pControlGMEntry);
} except (EXCEPTION_EXECUTE_HANDLER) {
Status = WmipNtStatusToDosError(GetExceptionCode());
#ifdef DBG
WmipDebugPrint(("WMI: Exception in UnRegisterTraceGuids Bad handle\n"));
#endif
}
RegistrationHandle = 0;
return WmipSetDosError(Status);
}
ULONG
WmipQueryAllUmTraceW(
OUT PEVENT_TRACE_PROPERTIES * PropertyArray,
IN BOOLEAN fEnabledOnly,
IN ULONG PropertyArrayCount,
OUT PULONG LoggerCount)
{
PWMI_LOGGER_INFORMATION pLoggerInfo;
PWMI_LOGGER_INFORMATION pLoggerInfoCurrent;
ULONG LoggerInfoSize;
ULONG SizeUsed;
ULONG SizeNeeded = 0;
ULONG Length;
ULONG lenLoggerName;
ULONG lenLogFileName;
ULONG Offset = 0;
ULONG i = * LoggerCount;
ULONG status;
PWCHAR strSrcW;
PWCHAR strDestW;
LoggerInfoSize = (PropertyArrayCount - i)
* ( sizeof(WMI_LOGGER_INFORMATION)
+ 2 * MAXSTR * sizeof(WCHAR));
LoggerInfoSize = (LoggerInfoSize +7) & ~7;
pLoggerInfo = (PWMI_LOGGER_INFORMATION) WmipAlloc(LoggerInfoSize);
if (pLoggerInfo == NULL) {
status = ERROR_OUTOFMEMORY;
goto Cleanup;
}
RtlZeroMemory(pLoggerInfo, LoggerInfoSize);
Length = sizeof(WMI_LOGGER_INFORMATION);
WmipInitString(& pLoggerInfo->LoggerName,
(PWCHAR) ((PUCHAR) pLoggerInfo + Length),
MAXSTR * sizeof(WCHAR));
Length += MAXSTR * sizeof(WCHAR);
WmipInitString(& pLoggerInfo->LogFileName,
(PWCHAR) ((PUCHAR) pLoggerInfo + Length),
MAXSTR * sizeof(WCHAR));
SizeUsed = pLoggerInfo->Wnode.BufferSize = LoggerInfoSize;
status = WmipSendUmLogRequest(
(fEnabledOnly) ? (TRACELOG_QUERYENABLED) : (TRACELOG_QUERYALL),
pLoggerInfo
);
if (status != ERROR_SUCCESS)
goto Cleanup;
while (i < PropertyArrayCount && Offset < SizeUsed) {
PTRACE_ENABLE_CONTEXT pContext;
pLoggerInfoCurrent = (PWMI_LOGGER_INFORMATION)
(((PUCHAR) pLoggerInfo) + Offset);
pContext = (PTRACE_ENABLE_CONTEXT)
& pLoggerInfoCurrent->Wnode.HistoricalContext;
pContext->InternalFlag |= EVENT_TRACE_INTERNAL_FLAG_PRIVATE;
lenLoggerName = pLoggerInfoCurrent->LoggerName.Length / sizeof(WCHAR);
if (lenLoggerName >= MAXSTR)
lenLoggerName = MAXSTR - 1;
lenLogFileName = pLoggerInfoCurrent->LogFileName.Length / sizeof(WCHAR);
if (lenLogFileName >= MAXSTR)
lenLogFileName = MAXSTR - 1;
Length = sizeof(EVENT_TRACE_PROPERTIES)
+ sizeof(WCHAR) * (lenLoggerName + 1)
+ sizeof(WCHAR) * (lenLogFileName + 1);
if (PropertyArray[i]->Wnode.BufferSize >= Length) {
WmipCopyInfoToProperties(pLoggerInfoCurrent, PropertyArray[i]);
strSrcW = (PWCHAR) ( ((PUCHAR) pLoggerInfoCurrent)
+ sizeof(WMI_LOGGER_INFORMATION));
if (lenLoggerName > 0) {
if (PropertyArray[i]->LoggerNameOffset == 0) {
PropertyArray[i]->LoggerNameOffset =
sizeof(EVENT_TRACE_PROPERTIES);
}
strDestW = (PWCHAR) ( ((PUCHAR) PropertyArray[i])
+ PropertyArray[i]->LoggerNameOffset);
wcsncpy(strDestW, strSrcW, lenLoggerName);
strDestW[lenLoggerName] = 0;
}
strSrcW = (PWCHAR) (((PUCHAR) pLoggerInfoCurrent)
+ sizeof(WMI_LOGGER_INFORMATION)
+ pLoggerInfoCurrent->LoggerName.MaximumLength);
if (lenLogFileName > 0) {
if (PropertyArray[i]->LogFileNameOffset == 0) {
PropertyArray[i]->LogFileNameOffset =
PropertyArray[i]->LoggerNameOffset
+ sizeof(WCHAR) * (lenLoggerName + 1);
}
strDestW = (PWCHAR) ( ((PUCHAR) PropertyArray[i])
+ PropertyArray[i]->LogFileNameOffset);
wcsncpy(strDestW, strSrcW, lenLogFileName);
strDestW[lenLogFileName] = 0;
}
}
Offset = Offset
+ sizeof(WMI_LOGGER_INFORMATION)
+ pLoggerInfoCurrent->LogFileName.MaximumLength
+ pLoggerInfoCurrent->LoggerName.MaximumLength;
i ++;
}
* LoggerCount = i;
status = (* LoggerCount > PropertyArrayCount)
? ERROR_MORE_DATA : ERROR_SUCCESS;
Cleanup:
if (pLoggerInfo)
WmipFree(pLoggerInfo);
return WmipSetDosError(status);
}
ULONG
WMIAPI
QueryAllTracesW(
OUT PEVENT_TRACE_PROPERTIES *PropertyArray,
IN ULONG PropertyArrayCount,
OUT PULONG LoggerCount
)
{
ULONG i, status;
ULONG returnCount = 0;
EVENT_TRACE_PROPERTIES LoggerInfo;
PEVENT_TRACE_PROPERTIES pLoggerInfo;
WmipInitProcessHeap();
if ((LoggerCount == NULL)
|| (PropertyArrayCount > MAXLOGGERS)
|| (PropertyArray == NULL)
|| (PropertyArrayCount == 0))
return ERROR_INVALID_PARAMETER;
if (*PropertyArray == NULL)
return ERROR_INVALID_PARAMETER;
try {
*LoggerCount = 0;
for (i=0; i<MAXLOGGERS; i++) {
if (returnCount < PropertyArrayCount) {
pLoggerInfo = PropertyArray[returnCount];
}
else {
pLoggerInfo = &LoggerInfo;
RtlZeroMemory(pLoggerInfo, sizeof(EVENT_TRACE_PROPERTIES));
pLoggerInfo->Wnode.BufferSize = sizeof(EVENT_TRACE_PROPERTIES);
}
WmiSetLoggerId(i, &pLoggerInfo->Wnode.HistoricalContext);
status = ControlTraceW(
(TRACEHANDLE)pLoggerInfo->Wnode.HistoricalContext,
NULL,
pLoggerInfo,
EVENT_TRACE_CONTROL_QUERY);
if (status == ERROR_SUCCESS)
returnCount++;
}
*LoggerCount = returnCount;
status = WmipQueryAllUmTraceW(PropertyArray,
FALSE,
PropertyArrayCount,
LoggerCount);
}
except (EXCEPTION_EXECUTE_HANDLER) {
return WmipSetDosError(ERROR_NOACCESS);
}
if (returnCount > PropertyArrayCount)
return ERROR_MORE_DATA;
else
return ERROR_SUCCESS;
}
ULONG
WmipQueryAllUmTraceA(
OUT PEVENT_TRACE_PROPERTIES * PropertyArray,
IN BOOLEAN fEnabledOnly,
IN ULONG PropertyArrayCount,
OUT PULONG LoggerCount)
{
PWMI_LOGGER_INFORMATION pLoggerInfo;
PWMI_LOGGER_INFORMATION pLoggerInfoCurrent;
ULONG LoggerInfoSize;
ULONG SizeUsed;
ULONG SizeNeeded = 0;
ULONG Length;
ULONG lenLoggerName;
ULONG lenLogFileName;
ULONG Offset = 0;
ULONG i = * LoggerCount;
ULONG status;
ANSI_STRING strBufferA;
PUCHAR strDestA;
LoggerInfoSize = (PropertyArrayCount - i)
* ( sizeof(WMI_LOGGER_INFORMATION)
+ 2 * MAXSTR * sizeof(WCHAR));
LoggerInfoSize = (LoggerInfoSize +7) & ~7;
pLoggerInfo = (PWMI_LOGGER_INFORMATION) WmipAlloc(LoggerInfoSize);
if (pLoggerInfo == NULL) {
status = ERROR_OUTOFMEMORY;
goto Cleanup;
}
RtlZeroMemory(pLoggerInfo, LoggerInfoSize);
Length = sizeof(WMI_LOGGER_INFORMATION);
WmipInitString(& pLoggerInfo->LoggerName,
(PWCHAR) ((PUCHAR) pLoggerInfo + Length),
MAXSTR * sizeof(WCHAR));
Length += MAXSTR * sizeof(WCHAR);
WmipInitString(& pLoggerInfo->LogFileName,
(PWCHAR) ((PUCHAR) pLoggerInfo + Length),
MAXSTR * sizeof(WCHAR));
SizeUsed = pLoggerInfo->Wnode.BufferSize = LoggerInfoSize;
//
// TODO: Provide SizeNeeded case
//
status = WmipSendUmLogRequest(
(fEnabledOnly) ? (TRACELOG_QUERYENABLED)
: (TRACELOG_QUERYALL),
pLoggerInfo
);
if (status != ERROR_SUCCESS)
goto Cleanup;
while (i < PropertyArrayCount && Offset < SizeUsed) {
PTRACE_ENABLE_CONTEXT pContext;
pLoggerInfoCurrent = (PWMI_LOGGER_INFORMATION)
(((PUCHAR) pLoggerInfo) + Offset);
pContext = (PTRACE_ENABLE_CONTEXT)
& pLoggerInfoCurrent->Wnode.HistoricalContext;
pContext->InternalFlag |= EVENT_TRACE_INTERNAL_FLAG_PRIVATE;
lenLoggerName = pLoggerInfoCurrent->LoggerName.Length / sizeof(WCHAR);
if (lenLoggerName >= MAXSTR)
lenLoggerName = MAXSTR - 1;
lenLogFileName = pLoggerInfoCurrent->LogFileName.Length / sizeof(WCHAR);
if (lenLogFileName >= MAXSTR)
lenLogFileName = MAXSTR - 1;
Length = sizeof(EVENT_TRACE_PROPERTIES)
+ sizeof(CHAR) * (lenLoggerName + 1)
+ sizeof(CHAR) * (lenLogFileName + 1);
if (PropertyArray[i]->Wnode.BufferSize >= Length) {
WmipCopyInfoToProperties(pLoggerInfoCurrent, PropertyArray[i]);
if (lenLoggerName > 0) {
pLoggerInfoCurrent->LoggerName.Buffer = (PWCHAR)
( ((PUCHAR) pLoggerInfoCurrent)
+ sizeof(WMI_LOGGER_INFORMATION));
status = RtlUnicodeStringToAnsiString(& strBufferA,
& pLoggerInfoCurrent->LoggerName, TRUE);
if (NT_SUCCESS(status)) {
if (PropertyArray[i]->LoggerNameOffset == 0) {
PropertyArray[i]->LoggerNameOffset =
sizeof(EVENT_TRACE_PROPERTIES);
}
strDestA = (PCHAR) ( ((PUCHAR) PropertyArray[i])
+ PropertyArray[i]->LoggerNameOffset);
strcpy(strDestA, strBufferA.Buffer);
RtlFreeAnsiString(& strBufferA);
}
strDestA[lenLoggerName] = 0;
}
if (lenLogFileName > 0) {
pLoggerInfoCurrent->LogFileName.Buffer = (PWCHAR)
( ((PUCHAR) pLoggerInfoCurrent)
+ sizeof(WMI_LOGGER_INFORMATION)
+ pLoggerInfoCurrent->LoggerName.MaximumLength);
status = RtlUnicodeStringToAnsiString(& strBufferA,
& pLoggerInfoCurrent->LogFileName, TRUE);
if (NT_SUCCESS(status)) {
if (PropertyArray[i]->LogFileNameOffset == 0) {
PropertyArray[i]->LogFileNameOffset =
sizeof(EVENT_TRACE_PROPERTIES)
+ sizeof(CHAR) * (lenLoggerName + 1);
}
strDestA = (PCHAR) ( ((PUCHAR) PropertyArray[i])
+ PropertyArray[i]->LogFileNameOffset);
strcpy(strDestA, strBufferA.Buffer);
RtlFreeAnsiString(& strBufferA);
}
strDestA[lenLogFileName] = 0;
}
}
Offset = Offset
+ sizeof(WMI_LOGGER_INFORMATION)
+ pLoggerInfoCurrent->LogFileName.MaximumLength
+ pLoggerInfoCurrent->LoggerName.MaximumLength;
i ++;
}
* LoggerCount = i;
status = (* LoggerCount > PropertyArrayCount)
? ERROR_MORE_DATA : ERROR_SUCCESS;
Cleanup:
if (pLoggerInfo)
WmipFree(pLoggerInfo);
return WmipSetDosError(status);
}
ULONG
WMIAPI
QueryAllTracesA(
OUT PEVENT_TRACE_PROPERTIES *PropertyArray,
IN ULONG PropertyArrayCount,
OUT PULONG LoggerCount
)
{
ULONG i, status;
ULONG returnCount = 0;
EVENT_TRACE_PROPERTIES LoggerInfo;
PEVENT_TRACE_PROPERTIES pLoggerInfo;
WmipInitProcessHeap();
if ((LoggerCount == NULL)
|| (PropertyArrayCount > MAXLOGGERS)
|| (PropertyArray == NULL)
|| (PropertyArrayCount == 0))
return ERROR_INVALID_PARAMETER;
if (*PropertyArray == NULL)
return ERROR_INVALID_PARAMETER;
try {
*LoggerCount = 0;
for (i=0; i<MAXLOGGERS; i++) {
if (returnCount < PropertyArrayCount)
pLoggerInfo = PropertyArray[returnCount];
else {
pLoggerInfo = &LoggerInfo;
RtlZeroMemory(pLoggerInfo, sizeof(EVENT_TRACE_PROPERTIES));
pLoggerInfo->Wnode.BufferSize = sizeof(EVENT_TRACE_PROPERTIES);
}
WmiSetLoggerId(i, &pLoggerInfo->Wnode.HistoricalContext);
status = ControlTraceA(
(TRACEHANDLE)pLoggerInfo->Wnode.HistoricalContext,
NULL,
pLoggerInfo,
EVENT_TRACE_CONTROL_QUERY);
if (status == ERROR_SUCCESS)
returnCount++;
}
*LoggerCount = returnCount;
status = WmipQueryAllUmTraceA(PropertyArray,
FALSE,
PropertyArrayCount,
LoggerCount);
}
except (EXCEPTION_EXECUTE_HANDLER) {
return WmipSetDosError(ERROR_NOACCESS);
}
if (returnCount > PropertyArrayCount)
return ERROR_MORE_DATA;
else
return ERROR_SUCCESS;
}
TRACEHANDLE
WMIAPI
GetTraceLoggerHandle(
IN PVOID Buffer
)
{
TRACEHANDLE LoggerHandle = (TRACEHANDLE) INVALID_HANDLE_VALUE;
USHORT LoggerId;
WmipInitProcessHeap();
if (Buffer == NULL) {
WmipSetDosError(ERROR_INVALID_PARAMETER);
return LoggerHandle;
}
try {
if (((PWNODE_HEADER)Buffer)->BufferSize < sizeof(WNODE_HEADER)) {
WmipSetDosError(ERROR_BAD_LENGTH);
return LoggerHandle;
}
LoggerHandle = (TRACEHANDLE)((PWNODE_HEADER)Buffer)->HistoricalContext;
}
except (EXCEPTION_EXECUTE_HANDLER) {
WmipSetDosError(ERROR_NOACCESS);
return (TRACEHANDLE) INVALID_HANDLE_VALUE;
}
LoggerId = WmiGetLoggerId(LoggerHandle);
if ((LoggerId >= MAXLOGGERS) && (LoggerId != KERNEL_LOGGER_ID))
{
WmipSetDosError(ERROR_INVALID_HANDLE);
LoggerHandle = (TRACEHANDLE) INVALID_HANDLE_VALUE;
}
return LoggerHandle;
}
UCHAR
WMIAPI
GetTraceEnableLevel(
IN TRACEHANDLE LoggerHandle
)
{
UCHAR Level;
USHORT LoggerId;
WmipInitProcessHeap();
LoggerId = WmiGetLoggerId(LoggerHandle);
if (((LoggerId >= MAXLOGGERS) && (LoggerId != KERNEL_LOGGER_ID))
|| (LoggerHandle == (TRACEHANDLE) NULL))
{
WmipSetDosError(ERROR_INVALID_HANDLE);
return 0;
}
Level = WmiGetLoggerEnableLevel(LoggerHandle);
return Level;
}
ULONG
WMIAPI
GetTraceEnableFlags(
IN TRACEHANDLE LoggerHandle
)
{
ULONG Flags;
USHORT LoggerId;
WmipInitProcessHeap();
LoggerId = WmiGetLoggerId(LoggerHandle);
if (((LoggerId >= MAXLOGGERS) && (LoggerId != KERNEL_LOGGER_ID))
|| (LoggerHandle == (TRACEHANDLE) NULL))
{
WmipSetDosError(ERROR_INVALID_HANDLE);
return 0;
}
Flags = WmiGetLoggerEnableFlags(LoggerHandle);
return Flags;
}
ULONG
WMIAPI
CreateTraceInstanceId(
IN PVOID RegHandle,
IN OUT PEVENT_INSTANCE_INFO pInst
)
/*++
Routine Description:
This call takes the Registration Handle for a traced GUID and fills in the
instanceId in the EVENT_INSTANCE_INFO structure provided by the caller.
Arguments:
RegHandle Registration Handle for the Guid.
pInst Pointer to the Instance information
Return Value:
The status of performing the action requested.
--*/
{
PGUIDMAPENTRY GuidMapEntry;
WmipInitProcessHeap();
if ((RegHandle == NULL) || (pInst == NULL)) {
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
try {
pInst->RegHandle = RegHandle;
GuidMapEntry = (PGUIDMAPENTRY) RegHandle;
if (GuidMapEntry->InstanceId >= MAXINST) {
InterlockedCompareExchange(&GuidMapEntry->InstanceId, MAXINST, 0);
}
pInst->InstanceId = InterlockedIncrement(&GuidMapEntry->InstanceId);
}
except (EXCEPTION_EXECUTE_HANDLER) {
return WmipSetDosError(WmipNtStatusToDosError(GetExceptionCode()));
}
return ERROR_SUCCESS;
}
ULONG
WMIAPI
EnumerateTraceGuids(
IN OUT PTRACE_GUID_PROPERTIES *GuidPropertiesArray,
IN ULONG PropertyArrayCount,
OUT PULONG GuidCount
)
/*++
Routine Description:
This call returns all the registered trace control guids
with their current status.
Arguments:
GuidPropertiesArray Points to buffers to write trace control guid properties
PropertyArrayCount Size of the array provided
GuidCount Number of GUIDs written in the Array. If the
Array was smaller than the required size, GuidCount
returns the size needed.
Return Value:
The status of performing the action requested.
--*/
{
ULONG Status;
PWMIGUIDLISTINFO pGuidListInfo;
ULONG i, j;
WmipInitProcessHeap();
try {
if ( (GuidPropertiesArray == NULL) || (*GuidPropertiesArray == NULL) ){
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
for (i=0; i < PropertyArrayCount; i++) {
if (GuidPropertiesArray[i] == NULL) {
return WmipSetDosError(ERROR_INVALID_PARAMETER);
}
}
}
except (EXCEPTION_EXECUTE_HANDLER) {
Status = WmipNtStatusToDosError( GetExceptionCode() );
return WmipSetDosError(Status);
}
Status = WmipEnumRegGuids(&pGuidListInfo);
if (Status == ERROR_SUCCESS) {
try {
PWMIGUIDPROPERTIES pGuidProperties = pGuidListInfo->GuidList;
ULONG i, j = 0;
for (i=0; i < pGuidListInfo->ReturnedGuidCount; i++) {
if (pGuidProperties->GuidType == 0) { // Trace Control Guid
if (j >= PropertyArrayCount) {
Status = ERROR_MORE_DATA;
}
else {
RtlCopyMemory(GuidPropertiesArray[j],
pGuidProperties,
sizeof(WMIGUIDPROPERTIES)
);
}
j++;
}
pGuidProperties++;
}
*GuidCount = j;
}
except (EXCEPTION_EXECUTE_HANDLER) {
Status = WmipNtStatusToDosError( GetExceptionCode() );
}
WmipFree(pGuidListInfo);
}
return WmipSetDosError(Status);
}
// Stub APIs
ULONG
WMIAPI
QueryTraceA(
IN TRACEHANDLE TraceHandle,
IN LPCSTR InstanceName,
IN OUT PEVENT_TRACE_PROPERTIES Properties
)
{
return ControlTraceA(
TraceHandle, InstanceName, Properties, EVENT_TRACE_CONTROL_QUERY);
}
ULONG
WMIAPI
QueryTraceW(
IN TRACEHANDLE TraceHandle,
IN LPCWSTR InstanceName,
IN OUT PEVENT_TRACE_PROPERTIES Properties
)
{
return ControlTraceW(
TraceHandle, InstanceName, Properties, EVENT_TRACE_CONTROL_QUERY);
}
ULONG
WMIAPI
StopTraceA(
IN TRACEHANDLE TraceHandle,
IN LPCSTR InstanceName,
IN OUT PEVENT_TRACE_PROPERTIES Properties
)
{
return ControlTraceA(
TraceHandle, InstanceName, Properties, EVENT_TRACE_CONTROL_STOP);
}
ULONG
WMIAPI
StopTraceW(
IN TRACEHANDLE TraceHandle,
IN LPCWSTR InstanceName,
IN OUT PEVENT_TRACE_PROPERTIES Properties
)
{
return ControlTraceW(
TraceHandle, InstanceName, Properties, EVENT_TRACE_CONTROL_STOP);
}
ULONG
WMIAPI
UpdateTraceA(
IN TRACEHANDLE TraceHandle,
IN LPCSTR InstanceName,
IN OUT PEVENT_TRACE_PROPERTIES Properties
)
{
return
ControlTraceA(
TraceHandle, InstanceName, Properties, EVENT_TRACE_CONTROL_UPDATE);
}
ULONG
WMIAPI
UpdateTraceW(
IN TRACEHANDLE TraceHandle,
IN LPCWSTR InstanceName,
IN OUT PEVENT_TRACE_PROPERTIES Properties
)
{
return
ControlTraceW(
TraceHandle, InstanceName, Properties, EVENT_TRACE_CONTROL_UPDATE);
}
ULONG
WMIAPI
FlushTraceA(
IN TRACEHANDLE TraceHandle,
IN LPCSTR InstanceName,
IN OUT PEVENT_TRACE_PROPERTIES Properties
)
{
return ControlTraceA(
TraceHandle, InstanceName, Properties, EVENT_TRACE_CONTROL_FLUSH);
}
ULONG
WMIAPI
FlushTraceW(
IN TRACEHANDLE TraceHandle,
IN LPCWSTR InstanceName,
IN OUT PEVENT_TRACE_PROPERTIES Properties
)
{
return ControlTraceW(
TraceHandle, InstanceName, Properties, EVENT_TRACE_CONTROL_FLUSH);
}
ULONG
WmipTraceMessage(
IN TRACEHANDLE LoggerHandle,
IN ULONG MessageFlags,
IN LPGUID MessageGuid,
IN USHORT MessageNumber,
IN va_list ArgList
)
{
NTSTATUS NtStatus;
IO_STATUS_BLOCK IoStatus;
PULONG TraceMarker;
ULONG Size;
ULONG Flags;
ULONG dataBytes, argCount ;
BOOLEAN UserModeOnly = FALSE;
USHORT LoggerId;
PTRACE_ENABLE_CONTEXT pContext = (PTRACE_ENABLE_CONTEXT)&LoggerHandle;
va_list ap ;
PMESSAGE_TRACE_USER pMessage = NULL ;
try {
//
// Determine the number bytes to follow header
//
dataBytes = 0 ; // For Count of Bytes
argCount = 0 ; // For Count of Arguments
{ // Allocation Block
PCHAR source;
ap = ArgList ;
while ((source = va_arg (ap, PVOID)) != NULL) {
size_t elemBytes;
elemBytes = va_arg (ap, size_t);
dataBytes += elemBytes;
argCount++ ;
}
} // end of allocation block
if (pContext->InternalFlag & EVENT_TRACE_INTERNAL_FLAG_PRIVATE){
UserModeOnly = TRUE;
goto UmOnly;
}
//
// Now the LoggerHandle is expected to be filled in by the caller.
// But check to see if it has a valid value.
//
LoggerId = WmiGetLoggerId(LoggerHandle);
if ((LoggerId == 0) || (LoggerId == KERNEL_LOGGER_ID)) {
return ERROR_INVALID_HANDLE;
}
Size = dataBytes + sizeof(MESSAGE_TRACE_USER) ;
if (Size > TRACE_MESSAGE_MAXIMUM_SIZE) {
SetLastError(ERROR_BUFFER_OVERFLOW);
return(ERROR_BUFFER_OVERFLOW);
}
pMessage = (PMESSAGE_TRACE_USER)WmipAlloc(Size);
if (pMessage == NULL)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return(ERROR_NOT_ENOUGH_MEMORY);
}
pMessage->MessageHeader.Marker = TRACE_MESSAGE | TRACE_HEADER_FLAG ;
//
// Fill in Header.
//
pMessage->MessageFlags = MessageFlags ;
pMessage->MessageHeader.Packet.MessageNumber = MessageNumber ;
pMessage->LoggerHandle = (ULONG64)LoggerHandle ;
// GUID ? or CompnentID ?
if (MessageFlags&TRACE_MESSAGE_COMPONENTID) {
RtlCopyMemory(&pMessage->MessageGuid,MessageGuid,sizeof(ULONG)) ;
} else if (MessageFlags&TRACE_MESSAGE_GUID) { // Can't have both
RtlCopyMemory(&pMessage->MessageGuid,MessageGuid,sizeof(GUID));
}
pMessage->DataSize = dataBytes ;
//
// Now Copy in the Data.
//
{ // Allocation Block
va_list ap;
PCHAR dest = (PCHAR)&pMessage->Data ;
PCHAR source;
ap = ArgList ;
while ((source = va_arg (ap, PVOID)) != NULL) {
size_t elemBytes;
elemBytes = va_arg (ap, size_t);
RtlCopyMemory (dest, source, elemBytes);
dest += elemBytes;
}
} // Allocation Block
}
except (EXCEPTION_EXECUTE_HANDLER) {
if (pMessage != NULL) {
WmipFree(pMessage);
}
return WmipNtStatusToDosError( GetExceptionCode() );
}
NtStatus = NtTraceEvent((HANDLE)LoggerHandle,
ETW_NT_FLAGS_TRACE_MESSAGE,
Size,
pMessage);
UmOnly:
try {
if (UserModeOnly) {
NtStatus = WmipTraceUmMessage(dataBytes,
(ULONG64)LoggerHandle,
MessageFlags,
MessageGuid,
MessageNumber,
ArgList);
}
}
except (EXCEPTION_EXECUTE_HANDLER) {
return WmipNtStatusToDosError(GetExceptionCode());
}
if (pMessage != NULL) {
WmipFree(pMessage);
}
return WmipNtStatusToDosError( NtStatus );
}
ULONG
WMIAPI
TraceMessage(
IN TRACEHANDLE LoggerHandle,
IN ULONG MessageFlags,
IN LPGUID MessageGuid,
IN USHORT MessageNumber,
...
)
/*++
Routine Description:
This routine is used by WMI data providers to trace events.
It expects the user to pass in the handle to the logger.
Also, the user cannot ask to log something that is larger than
the buffer size (minus buffer header).
Arguments:
// IN TRACEHANDLE LoggerHandle - LoggerHandle obtained earlier
// IN USHORT MessageFlags, - Flags which both control what standard values are logged and
// also included in the message header to control decoding
// IN PGUID MessageGuid, - Pointer to the message GUID of this set of messages or if
// TRACE_COMPONENTID is set the actual compnent ID
// IN USHORT MessageNumber, - The type of message being logged, associates it with the
// appropriate format string
// ... - List of arguments to be processed with the format string
// these are stored as pairs of
// PVOID - ptr to argument
// ULONG - size of argument
// and terminated by a pointer to NULL, length of zero pair.
Return Value:
Status
--*/
{
ULONG Status ;
va_list ArgList ;
WmipInitProcessHeap();
try {
va_start(ArgList,MessageNumber);
Status = WmipTraceMessage(LoggerHandle, MessageFlags, MessageGuid, MessageNumber, ArgList);
}
except (EXCEPTION_EXECUTE_HANDLER) {
Status = WmipNtStatusToDosError( GetExceptionCode() );
}
return WmipSetDosError(Status);
}
ULONG
WMIAPI
TraceMessageVa(
IN TRACEHANDLE LoggerHandle,
IN ULONG MessageFlags,
IN LPGUID MessageGuid,
IN USHORT MessageNumber,
IN va_list MessageArgList
)
// The Va version of TraceMessage
{
ULONG Status ;
WmipInitProcessHeap();
try {
Status = WmipTraceMessage(LoggerHandle, MessageFlags, MessageGuid, MessageNumber, MessageArgList);
}
except (EXCEPTION_EXECUTE_HANDLER) {
Status = WmipNtStatusToDosError( GetExceptionCode() );
}
return WmipSetDosError(Status);
}
#endif