You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1054 lines
33 KiB
1054 lines
33 KiB
/*++
|
|
|
|
Copyright (c) 1997-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
intrnldp.c
|
|
|
|
Abstract:
|
|
|
|
Implements WMI internal data provider
|
|
|
|
Author:
|
|
|
|
21-Feb-1998 AlanWar
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "wmiump.h"
|
|
#include "wmidata.h"
|
|
#include <cfgmgr32.h>
|
|
|
|
#define INSTANCE_INFO_GUID_INDEX 0
|
|
#define ENUMERATE_GUIDS_GUID_INDEX 1
|
|
#define DEFAULT_GUID_COUNT 100
|
|
|
|
GUID EtwpInternalGuidList[] =
|
|
{
|
|
INSTANCE_INFO_GUID,
|
|
ENUMERATE_GUIDS_GUID
|
|
};
|
|
|
|
#define EtwpInternalGuidCount (sizeof(EtwpInternalGuidList) / sizeof(GUID))
|
|
|
|
PWCHAR GuidToWString(
|
|
PWCHAR s,
|
|
LPGUID piid
|
|
)
|
|
{
|
|
swprintf(s, (L"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"),
|
|
piid->Data1, piid->Data2,
|
|
piid->Data3,
|
|
piid->Data4[0], piid->Data4[1],
|
|
piid->Data4[2], piid->Data4[3],
|
|
piid->Data4[4], piid->Data4[5],
|
|
piid->Data4[6], piid->Data4[7]);
|
|
|
|
return(s);
|
|
}
|
|
|
|
ULONG EtwpFindGuid(
|
|
LPGUID Guid
|
|
)
|
|
{
|
|
ULONG i;
|
|
|
|
for (i = 0; i < EtwpInternalGuidCount; i++)
|
|
{
|
|
if (memcmp(Guid, &EtwpInternalGuidList[i], sizeof(GUID)) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return(i);
|
|
}
|
|
|
|
typedef
|
|
DWORD
|
|
(*PCMGETDEVNODEREGISTRYPROPERTYW)(
|
|
IN DEVINST dnDevInst,
|
|
IN ULONG ulProperty,
|
|
OUT PULONG pulRegDataType, OPTIONAL
|
|
OUT PVOID Buffer, OPTIONAL
|
|
IN OUT PULONG pulLength,
|
|
IN ULONG ulFlags
|
|
);
|
|
typedef
|
|
DWORD
|
|
(*PCMLOCATEDEVNODEW)(
|
|
OUT PDEVINST pdnDevInst,
|
|
IN DEVINSTID_W pDeviceID, OPTIONAL
|
|
IN ULONG ulFlags
|
|
);
|
|
|
|
typedef
|
|
DWORD
|
|
(*PCMLOCATEDEVNODEA)(
|
|
OUT PDEVINST pdnDevInst,
|
|
IN DEVINSTID_A pDeviceID, OPTIONAL
|
|
IN ULONG ulFlags
|
|
);
|
|
#ifdef UNICODE
|
|
#define PCMLOCATEDEVNODE PCMLOCATEDEVNODEW
|
|
#else
|
|
#define PCMLOCATEDEVNODE PCMLOCATEDEVNODEA
|
|
#endif
|
|
|
|
|
|
void EtwpGetDevInstProperty(
|
|
IN DEVINST DevInst,
|
|
IN ULONG Property,
|
|
IN OUT PBOOLEAN BufferFull,
|
|
IN OUT PUCHAR *OutBuffer,
|
|
IN OUT PULONG BufferLeft,
|
|
IN OUT PULONG BufferNeeded,
|
|
IN PCMGETDEVNODEREGISTRYPROPERTYW CMGetDevNodeRegistryProperty
|
|
)
|
|
{
|
|
PWCHAR WCharPtr;
|
|
PUCHAR PropertyBuffer;
|
|
ULONG PropertyBufferLength;
|
|
ULONG Type;
|
|
ULONG Status;
|
|
ULONG BufferUsed;
|
|
ULONG Size;
|
|
#ifdef MEMPHIS
|
|
ULONG PropertyBufferLengthAnsi;
|
|
PCHAR PropertyBufferAnsi;
|
|
CHAR AnsiBuffer[MAX_PATH];
|
|
#endif
|
|
|
|
#ifdef MEMPHIS
|
|
PropertyBufferAnsi = AnsiBuffer;
|
|
PropertyBufferLengthAnsi = sizeof(AnsiBuffer);
|
|
Status = (*CMGetDevNodeRegistryProperty)(DevInst,
|
|
Property,
|
|
&Type,
|
|
PropertyBufferAnsi,
|
|
&PropertyBufferLengthAnsi,
|
|
0);
|
|
if (Status == CR_BUFFER_SMALL)
|
|
{
|
|
PropertyBufferAnsi = EtwpAlloc(PropertyBufferLengthAnsi);
|
|
if (PropertyBufferAnsi != NULL)
|
|
{
|
|
Status = (*CMGetDevNodeRegistryProperty)(DevInst,
|
|
Property,
|
|
&Type,
|
|
PropertyBufferAnsi,
|
|
&PropertyBufferLengthAnsi,
|
|
0);
|
|
} else {
|
|
Status = CR_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
|
|
if (Status == CR_SUCCESS)
|
|
{
|
|
if (UnicodeSizeForAnsiString(PropertyBufferAnsi,
|
|
&Size) != ERROR_SUCCESS)
|
|
{
|
|
Status = CR_FAILURE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if ((*BufferFull) || (*BufferLeft == 0))
|
|
{
|
|
PropertyBufferLength = 0;
|
|
PropertyBuffer = NULL;
|
|
} else {
|
|
PropertyBufferLength = *BufferLeft - sizeof(USHORT);
|
|
PropertyBuffer = *OutBuffer + sizeof(USHORT);
|
|
}
|
|
|
|
#ifdef MEMPHIS
|
|
if (Status == CR_SUCCESS)
|
|
{
|
|
if (PropertyBufferLength >= Size)
|
|
{
|
|
if (AnsiToUnicode(PropertyBufferAnsi,
|
|
(PWCHAR *)&PropertyBuffer) != ERROR_SUCCESS)
|
|
{
|
|
Status = CR_FAILURE;
|
|
}
|
|
} else {
|
|
Status = CR_BUFFER_SMALL;
|
|
}
|
|
PropertyBufferLength = Size;
|
|
}
|
|
|
|
if (PropertyBufferAnsi != AnsiBuffer)
|
|
{
|
|
EtwpFree(PropertyBufferAnsi);
|
|
}
|
|
#else
|
|
Status = (*CMGetDevNodeRegistryProperty)(DevInst,
|
|
Property,
|
|
&Type,
|
|
PropertyBuffer,
|
|
&PropertyBufferLength,
|
|
0);
|
|
#endif
|
|
|
|
BufferUsed = PropertyBufferLength + sizeof(USHORT);
|
|
if (Status == CR_SUCCESS)
|
|
{
|
|
PropertyBuffer -= sizeof(USHORT);
|
|
*((PUSHORT)PropertyBuffer) = (USHORT)PropertyBufferLength;
|
|
*BufferLeft -= BufferUsed;
|
|
*OutBuffer += BufferUsed;
|
|
*BufferNeeded += BufferUsed;
|
|
} else if (Status == CR_BUFFER_SMALL) {
|
|
*BufferNeeded += BufferUsed;
|
|
*BufferFull = TRUE;
|
|
} else {
|
|
*BufferNeeded += 2;
|
|
if ((! *BufferFull) && (*BufferLeft >= sizeof(USHORT)))
|
|
{
|
|
PropertyBuffer -= sizeof(USHORT);
|
|
*((PUSHORT)PropertyBuffer) = 0;
|
|
*BufferLeft -= sizeof(USHORT);
|
|
*OutBuffer += sizeof(USHORT);
|
|
} else {
|
|
*BufferFull = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
ULONG EtwpGetDevInstInfo(
|
|
PWCHAR DevInstName,
|
|
ULONG MaxSize,
|
|
PUCHAR OutBuffer,
|
|
ULONG *RetSize,
|
|
PCMLOCATEDEVNODE CMLocateDevNode,
|
|
PCMGETDEVNODEREGISTRYPROPERTYW CMGetDevNodeRegistryProperty
|
|
)
|
|
{
|
|
PUCHAR Buffer;
|
|
DEVINST DevInst;
|
|
ULONG Status;
|
|
ULONG BufferNeeded;
|
|
ULONG BufferLeft;
|
|
BOOLEAN BufferFull;
|
|
PWCHAR WCharPtr;
|
|
#ifdef MEMPHIS
|
|
PCHAR AnsiDevInstName;
|
|
#endif
|
|
|
|
// TODO: Memphis string translations
|
|
|
|
#ifdef MEMPHIS
|
|
AnsiDevInstName = NULL;
|
|
Status = UnicodeToAnsi(DevInstName,
|
|
&AnsiDevInstName,
|
|
NULL);
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = (*CMLocateDevNode)(&DevInst,
|
|
AnsiDevInstName,
|
|
CM_LOCATE_DEVNODE_NORMAL);
|
|
EtwpFree(AnsiDevInstName);
|
|
}
|
|
#else
|
|
Status = (*CMLocateDevNode)(&DevInst,
|
|
DevInstName,
|
|
CM_LOCATE_DEVNODE_NORMAL);
|
|
#endif
|
|
if (Status == CR_SUCCESS)
|
|
{
|
|
BufferFull = (MaxSize == 0);
|
|
BufferNeeded = 0;
|
|
BufferLeft = MaxSize;
|
|
|
|
WCharPtr = (PWCHAR)OutBuffer;
|
|
|
|
EtwpGetDevInstProperty(DevInst,
|
|
CM_DRP_FRIENDLYNAME,
|
|
&BufferFull,
|
|
&((PUCHAR)WCharPtr),
|
|
&BufferLeft,
|
|
&BufferNeeded,
|
|
CMGetDevNodeRegistryProperty);
|
|
|
|
EtwpGetDevInstProperty(DevInst,
|
|
CM_DRP_DEVICEDESC,
|
|
&BufferFull,
|
|
&((PUCHAR)WCharPtr),
|
|
&BufferLeft,
|
|
&BufferNeeded,
|
|
CMGetDevNodeRegistryProperty);
|
|
|
|
EtwpGetDevInstProperty(DevInst,
|
|
CM_DRP_LOCATION_INFORMATION,
|
|
&BufferFull,
|
|
&((PUCHAR)WCharPtr),
|
|
&BufferLeft,
|
|
&BufferNeeded,
|
|
CMGetDevNodeRegistryProperty);
|
|
|
|
EtwpGetDevInstProperty(DevInst,
|
|
CM_DRP_MFG,
|
|
&BufferFull,
|
|
&((PUCHAR)WCharPtr),
|
|
&BufferLeft,
|
|
&BufferNeeded,
|
|
CMGetDevNodeRegistryProperty);
|
|
|
|
EtwpGetDevInstProperty(DevInst,
|
|
CM_DRP_SERVICE,
|
|
&BufferFull,
|
|
&((PUCHAR)WCharPtr),
|
|
&BufferLeft,
|
|
&BufferNeeded,
|
|
CMGetDevNodeRegistryProperty);
|
|
|
|
Status = BufferFull ? ERROR_INSUFFICIENT_BUFFER : ERROR_SUCCESS;
|
|
*RetSize = BufferNeeded;
|
|
} else {
|
|
Status = ERROR_INVALID_DATA;
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
PWCHAR EtwpCountedToSzAndTrim(
|
|
PWCHAR InNamePtr,
|
|
PWCHAR OutNameBuffer,
|
|
ULONG OutNameSizeInBytes,
|
|
BOOLEAN Trim
|
|
)
|
|
{
|
|
PWCHAR WCharPtr, DevInstName;
|
|
ULONG DevInstNameLength;
|
|
ULONG i;
|
|
|
|
WCharPtr = InNamePtr;
|
|
DevInstNameLength = *WCharPtr++;
|
|
|
|
if (DevInstNameLength >= OutNameSizeInBytes)
|
|
{
|
|
DevInstName = EtwpAlloc( DevInstNameLength + sizeof(USHORT));
|
|
} else {
|
|
DevInstName = OutNameBuffer;
|
|
}
|
|
|
|
if (DevInstName != NULL)
|
|
{
|
|
memcpy(DevInstName, WCharPtr, DevInstNameLength);
|
|
DevInstNameLength /= sizeof(WCHAR);
|
|
DevInstName[DevInstNameLength--] = UNICODE_NULL;
|
|
|
|
if (Trim)
|
|
{
|
|
//
|
|
// Trim off the final _xxx from the Instance name to convert it to
|
|
// the Device Instance Name
|
|
WCharPtr = DevInstName + DevInstNameLength;
|
|
i = DevInstNameLength;
|
|
while ((*WCharPtr != L'_') && (i-- != 0))
|
|
{
|
|
WCharPtr--;
|
|
}
|
|
*WCharPtr = UNICODE_NULL;
|
|
}
|
|
}
|
|
|
|
return(DevInstName);
|
|
}
|
|
|
|
ULONG EtwpQuerySingleInstanceInfo(
|
|
PWNODE_SINGLE_INSTANCE Wnode,
|
|
ULONG MaxWnodeSize,
|
|
PVOID OutBuffer,
|
|
ULONG *RetWnodeSize,
|
|
PCMLOCATEDEVNODE CMLocateDevNode,
|
|
PCMGETDEVNODEREGISTRYPROPERTYW CMGetDevNodeRegistryProperty
|
|
)
|
|
{
|
|
WCHAR DevInstBuffer[MAX_PATH];
|
|
PWCHAR WCharPtr;
|
|
PWCHAR DevInstName;
|
|
ULONG DevInstNameLength;
|
|
ULONG i;
|
|
ULONG BufferSize;
|
|
ULONG MaxBufferSize;
|
|
ULONG WnodeNeeded;
|
|
PUCHAR Buffer;
|
|
ULONG Status;
|
|
|
|
EtwpAssert(! (Wnode->WnodeHeader.Flags & WNODE_FLAG_STATIC_INSTANCE_NAMES));
|
|
EtwpAssert(Wnode->OffsetInstanceName < Wnode->WnodeHeader.BufferSize);
|
|
EtwpAssert(Wnode->DataBlockOffset <= MaxWnodeSize);
|
|
|
|
WCharPtr = (PWCHAR)((PUCHAR)Wnode + Wnode->OffsetInstanceName);
|
|
DevInstName = EtwpCountedToSzAndTrim(WCharPtr,
|
|
DevInstBuffer,
|
|
MAX_PATH * sizeof(WCHAR),
|
|
TRUE);
|
|
|
|
if (DevInstName != NULL)
|
|
{
|
|
Buffer = (PUCHAR)OffsetToPtr(Wnode, Wnode->DataBlockOffset);
|
|
MaxBufferSize = MaxWnodeSize - Wnode->DataBlockOffset;
|
|
|
|
BufferSize = 0;
|
|
Status = EtwpGetDevInstInfo(DevInstName,
|
|
MaxBufferSize,
|
|
Buffer,
|
|
&BufferSize,
|
|
CMLocateDevNode,
|
|
CMGetDevNodeRegistryProperty);
|
|
|
|
WnodeNeeded = Wnode->DataBlockOffset + BufferSize;
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
WmiInsertTimestamp((PWNODE_HEADER)Wnode);
|
|
Wnode->WnodeHeader.BufferSize = WnodeNeeded;
|
|
Wnode->SizeDataBlock = BufferSize;
|
|
*RetWnodeSize = WnodeNeeded;
|
|
} else if (Status == ERROR_INSUFFICIENT_BUFFER) {
|
|
EtwpAssert(MaxWnodeSize > sizeof(WNODE_TOO_SMALL));
|
|
|
|
Wnode->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
|
|
((PWNODE_TOO_SMALL)Wnode)->SizeNeeded = WnodeNeeded;
|
|
Wnode->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
|
|
*RetWnodeSize = sizeof(WNODE_TOO_SMALL);
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
|
|
if (DevInstName != DevInstBuffer)
|
|
{
|
|
EtwpFree(DevInstName);
|
|
}
|
|
} else {
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
GUID PnPDeviceIdGuid = DATA_PROVIDER_PNPID_GUID;
|
|
|
|
ULONG EtwpComputeInstanceCount(
|
|
PWNODE_ALL_DATA WAD,
|
|
ULONG WnodeSize,
|
|
PULONG InstanceCount
|
|
)
|
|
{
|
|
ULONG Linkage;
|
|
ULONG Count = 0;
|
|
|
|
do
|
|
{
|
|
Linkage = WAD->WnodeHeader.Linkage;
|
|
|
|
if (Linkage > WnodeSize)
|
|
{
|
|
EtwpDebugPrint(("WMI: Badly formed Wnode %x\n", WAD));
|
|
EtwpAssert(FALSE);
|
|
return(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
Count += WAD->InstanceCount;
|
|
|
|
WnodeSize -= Linkage;
|
|
WAD = (PWNODE_ALL_DATA)OffsetToPtr(WAD, WAD->WnodeHeader.Linkage);
|
|
} while (Linkage != 0);
|
|
|
|
*InstanceCount = Count;
|
|
return(ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
ULONG EtwpQueryAllInstanceInfo(
|
|
PWNODE_ALL_DATA OutWAD,
|
|
ULONG MaxWnodeSize,
|
|
PVOID OutBuffer,
|
|
ULONG *RetSize,
|
|
PCMLOCATEDEVNODE CMLocateDevNode,
|
|
PCMGETDEVNODEREGISTRYPROPERTYW CMGetDevNodeRegistryProperty
|
|
)
|
|
{
|
|
|
|
ULONG Status;
|
|
PWNODE_ALL_DATA PnPIdWAD;
|
|
WMIHANDLE PnPIdHandle;
|
|
ULONG Size, Retries;
|
|
ULONG InstanceCount;
|
|
POFFSETINSTANCEDATAANDLENGTH OutOffsetNameLenPtr;
|
|
ULONG OutOffsetInstanceNameOffsets;
|
|
PULONG OutOffsetInstanceNameOffsetsPtr;
|
|
ULONG OutSizeNeeded, OutInstanceCounter = 0;
|
|
BOOLEAN OutIsFull = FALSE;
|
|
ULONG OutNameOffset;
|
|
ULONG OutNameSizeNeeded;
|
|
ULONG OutSizeLeft;
|
|
ULONG OutDataSize;
|
|
PWCHAR OutNamePtr;
|
|
PWNODE_ALL_DATA InWAD;
|
|
BOOLEAN IsFixedSize;
|
|
PWCHAR InNamePtr;
|
|
PWCHAR InPnPIdPtr;
|
|
ULONG FixedNameSize;
|
|
ULONG i;
|
|
PWCHAR DevInstName;
|
|
WCHAR DevInstBuffer[MAX_PATH];
|
|
POFFSETINSTANCEDATAANDLENGTH InOffsetNameLenPtr;
|
|
PUCHAR Buffer;
|
|
ULONG Linkage;
|
|
PULONG InOffsetInstanceNamePtr;
|
|
PWNODE_TOO_SMALL WTS;
|
|
ULONG OutDataOffset;
|
|
|
|
//
|
|
// Obtain the complete list of device instance ids
|
|
//
|
|
Status = WmiOpenBlock(&PnPDeviceIdGuid, WMIGUID_QUERY, &PnPIdHandle);
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Size = 0x1000;
|
|
Retries = 0;
|
|
PnPIdWAD = NULL;
|
|
do
|
|
{
|
|
if (PnPIdWAD != NULL)
|
|
{
|
|
EtwpFree(PnPIdWAD);
|
|
}
|
|
|
|
PnPIdWAD = (PWNODE_ALL_DATA)EtwpAlloc(Size);
|
|
|
|
if (PnPIdWAD != NULL)
|
|
{
|
|
Status = WmiQueryAllDataW(PnPIdHandle,
|
|
&Size,
|
|
PnPIdWAD);
|
|
} else {
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
} while ((Status == ERROR_INSUFFICIENT_BUFFER) &&
|
|
(Retries++ < 5));
|
|
|
|
if (Status == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
EtwpAssert(FALSE);
|
|
Status = ERROR_WMI_DP_NOT_FOUND;
|
|
}
|
|
|
|
WmiCloseBlock(PnPIdHandle);
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = EtwpComputeInstanceCount(PnPIdWAD,
|
|
Size,
|
|
&InstanceCount);
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
|
|
//
|
|
// Prepare output WNODE
|
|
OutOffsetNameLenPtr = OutWAD->OffsetInstanceDataAndLength;
|
|
|
|
OutOffsetInstanceNameOffsets = sizeof(WNODE_ALL_DATA) +
|
|
(InstanceCount * sizeof(OFFSETINSTANCEDATAANDLENGTH));
|
|
OutOffsetInstanceNameOffsetsPtr = (PULONG)OffsetToPtr(OutWAD,
|
|
OutOffsetInstanceNameOffsets);
|
|
|
|
OutSizeNeeded = ((OutOffsetInstanceNameOffsets +
|
|
(InstanceCount * sizeof(ULONG))) + 7) & ~7;
|
|
|
|
|
|
EtwpDebugPrint(("WMI: Basic OutSizeNeeded = 0x%x\n", OutSizeNeeded));
|
|
|
|
//
|
|
// Loop over all device instance ids returned and build
|
|
// output wnode
|
|
|
|
InWAD = PnPIdWAD;
|
|
do
|
|
{
|
|
//
|
|
// Get Instance and device instance id from input wnode
|
|
InOffsetInstanceNamePtr = (PULONG)OffsetToPtr(InWAD,
|
|
InWAD->OffsetInstanceNameOffsets);
|
|
|
|
// TODO: Validate InOffsetInstanceNamePtr
|
|
|
|
if (InWAD->WnodeHeader.Flags & WNODE_FLAG_FIXED_INSTANCE_SIZE)
|
|
{
|
|
IsFixedSize = TRUE;
|
|
InPnPIdPtr = (PWCHAR)OffsetToPtr(InWAD,
|
|
InWAD->DataBlockOffset);
|
|
FixedNameSize = (InWAD->FixedInstanceSize + 7) & ~7;
|
|
} else {
|
|
IsFixedSize = FALSE;
|
|
InOffsetNameLenPtr = InWAD->OffsetInstanceDataAndLength;
|
|
}
|
|
|
|
for (i = 0; i < InWAD->InstanceCount; i++)
|
|
{
|
|
if (! IsFixedSize)
|
|
{
|
|
InPnPIdPtr = (PWCHAR)OffsetToPtr(InWAD,
|
|
InOffsetNameLenPtr[i].OffsetInstanceData);
|
|
}
|
|
|
|
InNamePtr = (PWCHAR)OffsetToPtr(InWAD,
|
|
InOffsetInstanceNamePtr[i]);
|
|
|
|
//
|
|
// TODO: Validate InNamePtr and InPnPIdPtr
|
|
if (FALSE)
|
|
{
|
|
//
|
|
// If we hit a bad instance name then we throw out the
|
|
// entire wnode
|
|
EtwpDebugPrint(("WMI: Badly formed instance name %x\n",
|
|
InNamePtr));
|
|
EtwpAssert(FALSE);
|
|
break;
|
|
}
|
|
|
|
DevInstName = EtwpCountedToSzAndTrim(InPnPIdPtr,
|
|
DevInstBuffer,
|
|
MAX_PATH * sizeof(WCHAR),
|
|
FALSE);
|
|
|
|
if (DevInstName != NULL)
|
|
{
|
|
EtwpDebugPrint(("WMI: Processing %ws\n", DevInstName));
|
|
|
|
|
|
//
|
|
// Compute size and location of the output instance name
|
|
// It needs to start on a word boundry and end on a 8 byte
|
|
// boundry
|
|
OutNameOffset = (OutSizeNeeded+1) & ~1;
|
|
OutNameSizeNeeded = OutNameOffset - OutSizeNeeded;
|
|
OutNameSizeNeeded += *InNamePtr + sizeof(USHORT);
|
|
OutNameSizeNeeded = ((OutNameOffset + OutNameSizeNeeded + 7) & ~7) - OutNameOffset;
|
|
|
|
EtwpDebugPrint(("WMI: OutNameSizeNeeded = 0x%x\n", OutNameSizeNeeded));
|
|
OutDataOffset = OutSizeNeeded + OutNameSizeNeeded;
|
|
if ((OutIsFull) ||
|
|
(OutDataOffset > MaxWnodeSize))
|
|
{
|
|
EtwpDebugPrint((" WMI: OutIsFull\n"));
|
|
Buffer = NULL;
|
|
OutSizeLeft = 0;
|
|
OutIsFull = TRUE;
|
|
} else {
|
|
Buffer = (PUCHAR)OffsetToPtr(OutWAD,
|
|
OutDataOffset);
|
|
OutSizeLeft = MaxWnodeSize - OutDataOffset;
|
|
EtwpDebugPrint((" WMI: Out Not Full, OutSizeLeft = 0x%x at 0x%x\n", OutSizeLeft, OutDataOffset));
|
|
}
|
|
|
|
//
|
|
// Now that we have the name, lets get the vital info
|
|
Status = EtwpGetDevInstInfo(DevInstName,
|
|
OutSizeLeft,
|
|
Buffer,
|
|
&OutDataSize,
|
|
CMLocateDevNode,
|
|
CMGetDevNodeRegistryProperty);
|
|
|
|
EtwpDebugPrint((" WMI: GetInfo -> %d, OutDataSize 0x%x\n", Status, OutDataSize));
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// We were able to get all of the data so fill in the
|
|
// instance name
|
|
OutNamePtr = (PWCHAR)OffsetToPtr(OutWAD,
|
|
OutNameOffset);
|
|
*OutOffsetInstanceNameOffsetsPtr++ = OutNameOffset;
|
|
*OutNamePtr++ = *InNamePtr;
|
|
memcpy(OutNamePtr, InNamePtr+1, *InNamePtr);
|
|
|
|
//
|
|
// Now fill in the output data
|
|
OutOffsetNameLenPtr[OutInstanceCounter].OffsetInstanceData = OutDataOffset;
|
|
OutOffsetNameLenPtr[OutInstanceCounter].LengthInstanceData = OutDataSize;
|
|
OutInstanceCounter++;
|
|
} else if (Status == ERROR_INSUFFICIENT_BUFFER) {
|
|
OutIsFull = TRUE;
|
|
OutInstanceCounter++;
|
|
} else {
|
|
OutNameSizeNeeded = 0;
|
|
OutDataSize = 0;
|
|
}
|
|
|
|
OutSizeNeeded += (OutNameSizeNeeded + OutDataSize);
|
|
EtwpDebugPrint((" WMI: OutSizeNeeded = 0x%x\n", OutSizeNeeded));
|
|
|
|
if (DevInstName != DevInstBuffer)
|
|
{
|
|
EtwpFree(DevInstName);
|
|
}
|
|
} else {
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
if (IsFixedSize)
|
|
{
|
|
InPnPIdPtr = (PWCHAR)((PUCHAR)InPnPIdPtr + FixedNameSize);
|
|
}
|
|
}
|
|
|
|
Linkage = InWAD->WnodeHeader.Linkage;
|
|
InWAD = (PWNODE_ALL_DATA)OffsetToPtr(InWAD,
|
|
InWAD->WnodeHeader.Linkage);
|
|
} while (Linkage != 0);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Output wnode post processing. If not enough room then return a
|
|
// WNODE_TOO_SMALL, otherwise fill in WNODE_ALL_DATA fields
|
|
if ((OutInstanceCounter > 0) || (Status == ERROR_SUCCESS))
|
|
{
|
|
if (OutIsFull)
|
|
{
|
|
WTS = (PWNODE_TOO_SMALL)OutWAD;
|
|
WTS->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
|
|
WTS->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
|
|
WTS->SizeNeeded = OutSizeNeeded;
|
|
*RetSize = sizeof(WNODE_TOO_SMALL);
|
|
} else {
|
|
OutWAD->WnodeHeader.BufferSize = OutSizeNeeded;
|
|
OutWAD->InstanceCount = OutInstanceCounter;
|
|
OutWAD->OffsetInstanceNameOffsets = OutOffsetInstanceNameOffsets;
|
|
*RetSize = OutSizeNeeded;
|
|
}
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
#ifdef MEMPHIS
|
|
#define CFGMGRDLL TEXT("cfgmgr32.dll")
|
|
#else
|
|
#define CFGMGRDLL TEXT("setupapi.dll")
|
|
#endif
|
|
|
|
ULONG EtwpQueryInstanceInfo(
|
|
ULONG ActionCode,
|
|
PWNODE_HEADER Wnode,
|
|
ULONG MaxWnodeSize,
|
|
PVOID OutBuffer,
|
|
ULONG *RetSize
|
|
)
|
|
{
|
|
HMODULE CfgMgr32ModuleHandle;
|
|
PCMGETDEVNODEREGISTRYPROPERTYW CMGetDevNodeRegistryProperty;
|
|
PCMLOCATEDEVNODE CMLocateDevNode;
|
|
ULONG Status;
|
|
|
|
//
|
|
// Ensure this is a request we support
|
|
if ((ActionCode != WmiGetSingleInstance) &&
|
|
(ActionCode != WmiGetAllData))
|
|
{
|
|
return(ERROR_INVALID_FUNCTION);
|
|
}
|
|
|
|
//
|
|
// First we try to demand load cfgmgr32.dll
|
|
CfgMgr32ModuleHandle = LoadLibrary(CFGMGRDLL);
|
|
if (CfgMgr32ModuleHandle != NULL)
|
|
{
|
|
#ifdef MEMPHIS
|
|
CMLocateDevNode = (PCMLOCATEDEVNODEA)GetProcAddress(CfgMgr32ModuleHandle,
|
|
"CM_Locate_DevNodeA");
|
|
#else
|
|
CMLocateDevNode = (PCMLOCATEDEVNODEW)GetProcAddress(CfgMgr32ModuleHandle,
|
|
"CM_Locate_DevNodeW");
|
|
#endif
|
|
CMGetDevNodeRegistryProperty = (PCMGETDEVNODEREGISTRYPROPERTYW)
|
|
GetProcAddress(CfgMgr32ModuleHandle,
|
|
#ifdef MEMPHIS
|
|
"CM_Get_DevNode_Registry_PropertyA");
|
|
#else
|
|
"CM_Get_DevNode_Registry_PropertyW");
|
|
#endif
|
|
if ((CMLocateDevNode == NULL) ||
|
|
(CMGetDevNodeRegistryProperty == NULL))
|
|
{
|
|
FreeLibrary(CfgMgr32ModuleHandle);
|
|
EtwpDebugPrint(("WMI: Couldn't get CfgMgr32 prog addresses %d\n",
|
|
GetLastError()));
|
|
return(GetLastError());
|
|
}
|
|
} else {
|
|
EtwpDebugPrint(("WMI: Couldn't load CfgMgr32 %d\n",
|
|
GetLastError()));
|
|
return(GetLastError());
|
|
}
|
|
|
|
if (ActionCode == WmiGetSingleInstance)
|
|
{
|
|
Status = EtwpQuerySingleInstanceInfo((PWNODE_SINGLE_INSTANCE)Wnode,
|
|
MaxWnodeSize,
|
|
OutBuffer,
|
|
RetSize,
|
|
CMLocateDevNode,
|
|
CMGetDevNodeRegistryProperty);
|
|
} else if (ActionCode == WmiGetAllData) {
|
|
Status = EtwpQueryAllInstanceInfo((PWNODE_ALL_DATA)Wnode,
|
|
MaxWnodeSize,
|
|
OutBuffer,
|
|
RetSize,
|
|
CMLocateDevNode,
|
|
CMGetDevNodeRegistryProperty);
|
|
} else {
|
|
EtwpAssert(FALSE);
|
|
}
|
|
|
|
FreeLibrary(CfgMgr32ModuleHandle);
|
|
return(Status);
|
|
}
|
|
|
|
ULONG
|
|
EtwpEnumRegGuids(
|
|
PWMIGUIDLISTINFO *pGuidInfo
|
|
)
|
|
{
|
|
ULONG Status = ERROR_SUCCESS;
|
|
ULONG MaxGuidCount = 0;
|
|
PWMIGUIDLISTINFO GuidInfo;
|
|
ULONG RetSize;
|
|
ULONG GuidInfoSize;
|
|
|
|
MaxGuidCount = DEFAULT_GUID_COUNT;
|
|
retry:
|
|
GuidInfoSize = FIELD_OFFSET(WMIGUIDLISTINFO, GuidList) +
|
|
MaxGuidCount * sizeof(WMIGUIDPROPERTIES);
|
|
|
|
GuidInfo = (PWMIGUIDLISTINFO)EtwpAlloc(GuidInfoSize);
|
|
|
|
if (GuidInfo == NULL)
|
|
{
|
|
return (ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
RtlZeroMemory(GuidInfo, GuidInfoSize);
|
|
|
|
Status = EtwpSendWmiKMRequest(NULL,
|
|
IOCTL_WMI_ENUMERATE_GUIDS_AND_PROPERTIES,
|
|
GuidInfo,
|
|
GuidInfoSize,
|
|
GuidInfo,
|
|
GuidInfoSize,
|
|
&RetSize,
|
|
NULL);
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
if ((RetSize < FIELD_OFFSET(WMIGUIDLISTINFO, GuidList)) ||
|
|
(RetSize < (FIELD_OFFSET(WMIGUIDLISTINFO, GuidList) +
|
|
GuidInfo->ReturnedGuidCount * sizeof(WMIGUIDPROPERTIES))))
|
|
{
|
|
//
|
|
// WMI KM returned to us a bad size which should not happen
|
|
//
|
|
Status = ERROR_WMI_DP_FAILED;
|
|
EtwpAssert(FALSE);
|
|
EtwpFree(GuidInfo);
|
|
} else {
|
|
|
|
//
|
|
// If RPC was successful, then build a WMI DataBlock with the data
|
|
//
|
|
|
|
if (GuidInfo->TotalGuidCount > GuidInfo->ReturnedGuidCount) {
|
|
MaxGuidCount = GuidInfo->TotalGuidCount;
|
|
EtwpFree(GuidInfo);
|
|
goto retry;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the call was successful, return the pointers and the caller
|
|
// must free the storage.
|
|
//
|
|
|
|
*pGuidInfo = GuidInfo;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
ULONG
|
|
EtwpEnumerateGuids(
|
|
PWNODE_ALL_DATA Wnode,
|
|
ULONG MaxWnodeSize,
|
|
PVOID OutBuffer,
|
|
ULONG *RetSize)
|
|
{
|
|
ULONG Status = ERROR_SUCCESS;
|
|
PWMIGUIDLISTINFO GuidInfo = NULL;
|
|
ULONG ReturnGuidCount = 0;
|
|
|
|
Status = EtwpEnumRegGuids(&GuidInfo);
|
|
|
|
if (Status == ERROR_SUCCESS) {
|
|
|
|
PWMIGUIDPROPERTIES pGuidProperties = GuidInfo->GuidList;
|
|
LPGUID pGuid;
|
|
WCHAR s[256];
|
|
ULONG InstanceNameOffset;
|
|
ULONG i;
|
|
ULONG InstanceDataSize = sizeof(WMIGUIDPROPERTIES) -
|
|
FIELD_OFFSET(WMIGUIDPROPERTIES, GuidType);
|
|
ULONG FixedInstanceSizeWithPadding = (InstanceDataSize+7) & ~7;
|
|
USHORT GuidStringSize = 76;
|
|
ULONG SizeNeeded;
|
|
PUCHAR BytePtr;
|
|
PULONG UlongPtr;
|
|
PUCHAR NamePtr;
|
|
ULONG DataBlockOffset;
|
|
|
|
EtwpAssert(GuidInfo->ReturnedGuidCount == GuidInfo->TotalGuidCount);
|
|
ReturnGuidCount = GuidInfo->ReturnedGuidCount;
|
|
SizeNeeded = sizeof(WNODE_ALL_DATA) +
|
|
ReturnGuidCount * (FixedInstanceSizeWithPadding +
|
|
GuidStringSize +
|
|
sizeof(ULONG) +
|
|
sizeof(WCHAR));
|
|
|
|
if (MaxWnodeSize < SizeNeeded) {
|
|
//
|
|
// Build WNODE_TOO_SMALL
|
|
//
|
|
|
|
EtwpAssert(MaxWnodeSize > sizeof(WNODE_TOO_SMALL));
|
|
|
|
Wnode->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL;
|
|
((PWNODE_TOO_SMALL)Wnode)->SizeNeeded = SizeNeeded;
|
|
Wnode->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL);
|
|
*RetSize = sizeof(WNODE_TOO_SMALL);
|
|
EtwpFree(GuidInfo);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
Wnode->InstanceCount = ReturnGuidCount;
|
|
Wnode->FixedInstanceSize = InstanceDataSize;
|
|
Wnode->WnodeHeader.Flags |= WNODE_FLAG_FIXED_INSTANCE_SIZE;
|
|
|
|
DataBlockOffset = sizeof(WNODE_ALL_DATA);
|
|
|
|
//
|
|
// pad out to an 8 byte boundary.
|
|
//
|
|
DataBlockOffset = (DataBlockOffset + 7) & ~7;
|
|
|
|
Wnode->DataBlockOffset = DataBlockOffset;
|
|
|
|
BytePtr = (PUCHAR)((PUCHAR)Wnode + DataBlockOffset);
|
|
|
|
|
|
InstanceNameOffset = DataBlockOffset +
|
|
(ReturnGuidCount * FixedInstanceSizeWithPadding);
|
|
Wnode->OffsetInstanceNameOffsets = InstanceNameOffset;
|
|
|
|
UlongPtr = (PULONG)((PUCHAR)Wnode + InstanceNameOffset);
|
|
|
|
NamePtr = (PUCHAR)UlongPtr;
|
|
NamePtr = (PUCHAR)((PUCHAR)NamePtr + (ReturnGuidCount * sizeof(ULONG)));
|
|
|
|
for (i=0; i < ReturnGuidCount; i++) {
|
|
//
|
|
// Copy the fixed instance datablock
|
|
//
|
|
RtlCopyMemory(BytePtr,
|
|
&pGuidProperties->GuidType,
|
|
Wnode->FixedInstanceSize);
|
|
BytePtr += FixedInstanceSizeWithPadding;
|
|
|
|
//
|
|
// Set the Offset to InstanceName
|
|
//
|
|
*UlongPtr++ = (ULONG)((PCHAR)NamePtr - (PCHAR)Wnode);
|
|
//
|
|
// Copy over the Instance Name
|
|
//
|
|
*((USHORT *)NamePtr) = GuidStringSize;
|
|
NamePtr += sizeof(USHORT);
|
|
GuidToWString(s, &pGuidProperties->Guid);
|
|
RtlCopyMemory(NamePtr, s, GuidStringSize);
|
|
NamePtr += GuidStringSize;
|
|
|
|
pGuidProperties++;
|
|
}
|
|
WmiInsertTimestamp((PWNODE_HEADER)Wnode);
|
|
*RetSize = SizeNeeded;
|
|
Wnode->WnodeHeader.BufferSize = SizeNeeded;
|
|
|
|
EtwpFree(GuidInfo);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
ULONG EtwpInternalProvider(
|
|
ULONG ActionCode,
|
|
PWNODE_HEADER Wnode,
|
|
ULONG MaxWnodeSize,
|
|
PVOID OutBuffer,
|
|
ULONG *RetSize
|
|
)
|
|
{
|
|
ULONG GuidIndex;
|
|
ULONG Status;
|
|
|
|
EtwpAssert((PVOID)Wnode == OutBuffer);
|
|
|
|
GuidIndex = EtwpFindGuid(&Wnode->Guid);
|
|
|
|
switch(GuidIndex)
|
|
{
|
|
case INSTANCE_INFO_GUID_INDEX:
|
|
{
|
|
Status = EtwpQueryInstanceInfo(ActionCode,
|
|
Wnode,
|
|
MaxWnodeSize,
|
|
OutBuffer,
|
|
RetSize);
|
|
break;
|
|
}
|
|
|
|
case ENUMERATE_GUIDS_GUID_INDEX:
|
|
{
|
|
//
|
|
//
|
|
// Need an RPC call to the server to get the desired data.
|
|
//
|
|
if (ActionCode == WmiGetAllData)
|
|
Status = EtwpEnumerateGuids((PWNODE_ALL_DATA)Wnode,
|
|
MaxWnodeSize,
|
|
OutBuffer,
|
|
RetSize);
|
|
else
|
|
Status = ERROR_INVALID_FUNCTION;
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
Status = ERROR_WMI_GUID_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|