897 lines
27 KiB
C
897 lines
27 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1997-1999 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
krnlmode.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
WMI interface to Kernel mode data providers
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
16-Jan-1997 AlanWar
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "wmiump.h"
|
|||
|
|
|||
|
extern HANDLE WmipKMHandle;
|
|||
|
|
|||
|
PTCHAR WmipRegistryToImagePath(
|
|||
|
PTCHAR ImagePath,
|
|||
|
PTCHAR RegistryPath,
|
|||
|
UINT_PTR ProviderId
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will determine the location of the device driver's image file
|
|||
|
from its registry path
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
RegistryPath is a pointer to the driver's registry path
|
|||
|
|
|||
|
ImagePath is buffer of length MAX_PATH and returns the image path
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
pointer to Image path of driver or NULL if image path is unavailable
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
#define SystemRoot TEXT("\\SystemRoot\\")
|
|||
|
#ifdef MEMPHIS
|
|||
|
#define SystemRootDirectory TEXT("%WinDir%\\")
|
|||
|
#else
|
|||
|
#define SystemRootDirectory TEXT("%SystemRoot%\\")
|
|||
|
#endif
|
|||
|
#define SystemRootCharSize (( sizeof(SystemRoot) / sizeof(WCHAR) ) - 1)
|
|||
|
|
|||
|
#define DriversDirectory TEXT("\\System32\\Drivers\\")
|
|||
|
#define NdisDriversDirectory TEXT("\\System\\")
|
|||
|
|
|||
|
#define QuestionPrefix TEXT("\\??\\")
|
|||
|
#define QuestionPrefixSize (( sizeof(QuestionPrefix) / sizeof(WCHAR) ) - 1)
|
|||
|
|
|||
|
#define RegistryPrefix TEXT("\\Registry")
|
|||
|
HKEY RegKey;
|
|||
|
PTCHAR ImagePathPtr = NULL;
|
|||
|
ULONG ValueType;
|
|||
|
ULONG Size;
|
|||
|
TCHAR Buffer[MAX_PATH];
|
|||
|
TCHAR Buffer2[MAX_PATH];
|
|||
|
TCHAR FullRegistryPath[MAX_PATH];
|
|||
|
PTCHAR DriverName;
|
|||
|
ULONG Len;
|
|||
|
BOOLEAN DefaultImageName;
|
|||
|
PTCHAR DriversDirectoryPath;
|
|||
|
|
|||
|
// CONSIDER: Do some grovelling around directories in case we don't find
|
|||
|
// the image.
|
|||
|
|
|||
|
#ifdef MEMPHIS
|
|||
|
//
|
|||
|
// On memphis the registry path could point to two places
|
|||
|
// \Registry\Machine\System\CurrentControlSet\Services\Driver (Legacy)
|
|||
|
// System\CurrentControlSet\Services\Class\USB\0001
|
|||
|
|
|||
|
|
|||
|
if (_tcsnicmp(RegistryPath, RegistryPrefix, sizeof(RegistryPrefix)-1) != 0)
|
|||
|
{
|
|||
|
//
|
|||
|
// This is a non legacy type registry path.
|
|||
|
if (RegOpenKey(HKEY_LOCAL_MACHINE,
|
|||
|
RegistryPath,
|
|||
|
&RegKey) == ERROR_SUCCESS)
|
|||
|
{
|
|||
|
DriverName = Buffer2;
|
|||
|
Size = MAX_PATH * sizeof(WCHAR);
|
|||
|
|
|||
|
if (RegQueryValueEx(RegKey,
|
|||
|
TEXT("NTMPDriver"),
|
|||
|
NULL,
|
|||
|
&ValueType,
|
|||
|
DriverName,
|
|||
|
&Size) == ERROR_SUCCESS)
|
|||
|
{
|
|||
|
DriversDirectoryPath = DriversDirectory;
|
|||
|
} else if (RegQueryValueEx(RegKey,
|
|||
|
TEXT("DeviceVxDs"),
|
|||
|
NULL,
|
|||
|
&ValueType,
|
|||
|
DriverName,
|
|||
|
&Size) == ERROR_SUCCESS)
|
|||
|
{
|
|||
|
DriversDirectoryPath = NdisDriversDirectory;
|
|||
|
} else {
|
|||
|
DriversDirectoryPath = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if ((DriversDirectoryPath != NULL) && (ValueType == REG_SZ))
|
|||
|
{
|
|||
|
Size = GetWindowsDirectory(Buffer, MAX_PATH);
|
|||
|
if ((Size != 0) &&
|
|||
|
(Size <= (MAX_PATH - _tcslen(DriverName) - sizeof(DriversDirectory) - 1)))
|
|||
|
{
|
|||
|
if (Buffer[Size-1] == TEXT('\\'))
|
|||
|
{
|
|||
|
Buffer[Size-1] = 0;
|
|||
|
}
|
|||
|
_tcscpy(ImagePath, Buffer);
|
|||
|
_tcscat(ImagePath, DriversDirectoryPath);
|
|||
|
_tcscat(ImagePath, DriverName);
|
|||
|
ImagePathPtr = ImagePath;
|
|||
|
RegCloseKey(RegKey);
|
|||
|
return(ImagePathPtr);
|
|||
|
}
|
|||
|
}
|
|||
|
RegCloseKey(RegKey);
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Get the driver file name or the MOF image path from the KM
|
|||
|
// registry path. Here are the rules:
|
|||
|
//
|
|||
|
// 1. First check the MofImagePath value in the registry in case the
|
|||
|
// mof resource is in a different file from the driver.
|
|||
|
// 2. Next check the ImagePath value since the mof resource is assumed
|
|||
|
// to be part of the driver image.
|
|||
|
// 3. If no MofImagePath or ImagePath values then assume the mof resource
|
|||
|
// is in the driver file and compose the driver file name as
|
|||
|
// %SystemRoot%\System32\driver.sys.
|
|||
|
// 4. If MofImagePath or ImagePath was specified then
|
|||
|
// - Check first char for % or second character for :, or prefix
|
|||
|
// of \??\ and if so use ExpandEnvironmentStrings
|
|||
|
// - Check first part of path for \SystemRoot\, if so rebuild string
|
|||
|
// as %SystemRoot%\ and use ExpandEnvironementStrings
|
|||
|
// - Assume format D below and prepend %SystemRoot%\ and use
|
|||
|
// ExpandEnvironmentStrings
|
|||
|
|
|||
|
// If MofImagePath or ImagePath value is present and it is a REG_EXPAND_SZ
|
|||
|
// then it is used to locate the file that holds the mof resource. It
|
|||
|
// can be in one of the following formats:
|
|||
|
// Format A - %SystemRoot%\System32\Foo.Dll
|
|||
|
// Format B -C:\WINNT\SYSTEM32\Drivers\Foo.SYS
|
|||
|
// Format C - \SystemRoot\System32\Drivers\Foo.SYS
|
|||
|
// Format D - System32\Drivers\Foo.Sys
|
|||
|
// Format E - \??\c:\foo.sys
|
|||
|
|
|||
|
|
|||
|
Len = _tcslen(RegistryPath);
|
|||
|
|
|||
|
if (Len > 0)
|
|||
|
{
|
|||
|
DriverName = RegistryPath + Len;
|
|||
|
while ((*(--DriverName) != '\\') && (--Len > 0)) ;
|
|||
|
}
|
|||
|
|
|||
|
if (Len == 0)
|
|||
|
{
|
|||
|
WmipReportEventLog(EVENT_WMI_INVALID_REGPATH,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
sizeof(UINT_PTR),
|
|||
|
&ProviderId,
|
|||
|
1,
|
|||
|
RegistryPath);
|
|||
|
WmipDebugPrint(("WMI: Badly formed registry path %ws\n", RegistryPath));
|
|||
|
return(NULL);
|
|||
|
}
|
|||
|
|
|||
|
DriverName++;
|
|||
|
|
|||
|
_tcscpy(FullRegistryPath, TEXT("System\\CurrentControlSet\\Services\\"));
|
|||
|
_tcscat(FullRegistryPath, DriverName);
|
|||
|
DefaultImageName = TRUE;
|
|||
|
if (RegOpenKey(HKEY_LOCAL_MACHINE,
|
|||
|
FullRegistryPath,
|
|||
|
&RegKey) == ERROR_SUCCESS)
|
|||
|
{
|
|||
|
Size = MAX_PATH * sizeof(WCHAR);
|
|||
|
if (RegQueryValueEx(RegKey,
|
|||
|
TEXT("MofImagePath"),
|
|||
|
NULL,
|
|||
|
&ValueType,
|
|||
|
(PBYTE)ImagePath,
|
|||
|
&Size) == ERROR_SUCCESS)
|
|||
|
{
|
|||
|
DefaultImageName = FALSE;
|
|||
|
} else {
|
|||
|
Size = MAX_PATH * sizeof(WCHAR);
|
|||
|
if (RegQueryValueEx(RegKey,
|
|||
|
TEXT("ImagePath"),
|
|||
|
NULL,
|
|||
|
&ValueType,
|
|||
|
(PBYTE)ImagePath,
|
|||
|
&Size) == ERROR_SUCCESS)
|
|||
|
{
|
|||
|
DefaultImageName = FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
RegCloseKey(RegKey);
|
|||
|
}
|
|||
|
|
|||
|
if ((DefaultImageName) ||
|
|||
|
((ValueType != REG_EXPAND_SZ) && (ValueType != REG_SZ)) ||
|
|||
|
(Size < (2 * sizeof(WCHAR))))
|
|||
|
{
|
|||
|
//
|
|||
|
// No special ImagePath or MofImagePath so assume image file is
|
|||
|
// %SystemRoot%\System32\Drivers\Driver.Sys
|
|||
|
#ifdef MEMPHIS
|
|||
|
_tcscpy(Buffer, TEXT("%WinDir%\\System32\\Drivers\\"));
|
|||
|
#else
|
|||
|
_tcscpy(Buffer, TEXT("%SystemRoot%\\System32\\Drivers\\"));
|
|||
|
#endif
|
|||
|
_tcscat(Buffer, DriverName);
|
|||
|
_tcscat(Buffer, TEXT(".SYS"));
|
|||
|
} else {
|
|||
|
if (_tcsnicmp(ImagePath,
|
|||
|
SystemRoot,
|
|||
|
SystemRootCharSize) == 0)
|
|||
|
{
|
|||
|
//
|
|||
|
// Looks like format C
|
|||
|
_tcscpy(Buffer, SystemRootDirectory);
|
|||
|
_tcscat(Buffer, &ImagePath[SystemRootCharSize]);
|
|||
|
} else if ((*ImagePath == '%') ||
|
|||
|
( (Size > 3*sizeof(WCHAR)) && ImagePath[1] == TEXT(':')) )
|
|||
|
{
|
|||
|
//
|
|||
|
// Looks like format B or format A
|
|||
|
_tcscpy(Buffer, ImagePath);
|
|||
|
} else if (_tcsnicmp(ImagePath,
|
|||
|
QuestionPrefix,
|
|||
|
QuestionPrefixSize) == 0)
|
|||
|
{
|
|||
|
//
|
|||
|
// Looks like format E
|
|||
|
_tcscpy(Buffer, ImagePath+QuestionPrefixSize);
|
|||
|
} else {
|
|||
|
//
|
|||
|
// Assume format D
|
|||
|
_tcscpy(Buffer, SystemRootDirectory);
|
|||
|
_tcscat(Buffer, ImagePath);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Size = ExpandEnvironmentStrings(Buffer,
|
|||
|
ImagePath,
|
|||
|
MAX_PATH);
|
|||
|
|
|||
|
#ifdef MEMPHIS
|
|||
|
WmipDebugPrint(("WMI: %s has mof in %s\n",
|
|||
|
DriverName, ImagePath));
|
|||
|
#else
|
|||
|
WmipDebugPrint(("WMI: %ws has mof in %ws\n",
|
|||
|
DriverName, ImagePath));
|
|||
|
#endif
|
|||
|
|
|||
|
return(ImagePath);
|
|||
|
}
|
|||
|
|
|||
|
ULONG WmipGetKmRegInfo(
|
|||
|
HANDLE WmiKMHandle,
|
|||
|
PKMREGINFO KMRegInfo,
|
|||
|
BOOLEAN UpdateInfo,
|
|||
|
PBYTE *RegistrationInfo,
|
|||
|
ULONG RegInfoSize,
|
|||
|
ULONG *RetSize
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine calls into the wmi device to query for new or updated
|
|||
|
registration information.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
WmiKMHandle is the WMI kernel mode service device handle
|
|||
|
|
|||
|
KMRegInfo is a pointer to the KM registration info
|
|||
|
|
|||
|
UpdateInfo is TRUE if caller is looking for update information or
|
|||
|
FALSE if caller is looking for new registration information.
|
|||
|
|
|||
|
*RegistrationInfo on entry has a buffer that can be filled with registration
|
|||
|
information. If this buffer is not large enough then a new buffer
|
|||
|
is allocated and is returned in *RegInfo
|
|||
|
|
|||
|
RegInfoSize has the number of bytes available in *RegInfo on entry
|
|||
|
|
|||
|
*RetSize returns with the number of bytes returned from the IOCTL
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ERROR_SUCCESS or an error code
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
OVERLAPPED Overlapped;
|
|||
|
BOOL IoctlSuccess;
|
|||
|
PBYTE RegInfo = *RegistrationInfo;
|
|||
|
ULONG Status;
|
|||
|
ULONG RetryCount = 0;
|
|||
|
|
|||
|
Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|||
|
if (Overlapped.hEvent == NULL)
|
|||
|
{
|
|||
|
Status = GetLastError();
|
|||
|
WmipDebugPrint(("WMI: Couldn't create event for RegInfo IOCTL %d\n",
|
|||
|
Status));
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
KMRegInfo->Flags = UpdateInfo ? REGENTRY_FLAG_UPDREGINFO :
|
|||
|
REGENTRY_FLAG_NEWREGINFO;
|
|||
|
do
|
|||
|
{
|
|||
|
IoctlSuccess = DeviceIoControl(WmiKMHandle,
|
|||
|
IOCTL_WMI_GET_REGINFO,
|
|||
|
KMRegInfo,
|
|||
|
sizeof(KMREGINFO),
|
|||
|
RegInfo,
|
|||
|
RegInfoSize,
|
|||
|
RetSize,
|
|||
|
&Overlapped);
|
|||
|
if (GetLastError() == ERROR_IO_PENDING)
|
|||
|
{
|
|||
|
IoctlSuccess = GetOverlappedResult(WmiKMHandle,
|
|||
|
&Overlapped,
|
|||
|
RetSize,
|
|||
|
TRUE);
|
|||
|
}
|
|||
|
if (IoctlSuccess)
|
|||
|
{
|
|||
|
Status = ERROR_SUCCESS;
|
|||
|
if (*RetSize == sizeof(ULONG))
|
|||
|
{
|
|||
|
RegInfoSize = *((ULONG *)RegInfo);
|
|||
|
if (RegInfo != *RegistrationInfo)
|
|||
|
{
|
|||
|
WmipFree(RegInfo);
|
|||
|
}
|
|||
|
|
|||
|
RegInfo = WmipAlloc(RegInfoSize);
|
|||
|
if (RegInfo == NULL)
|
|||
|
{
|
|||
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
Status = GetLastError();
|
|||
|
}
|
|||
|
} while (( (Status == ERROR_SUCCESS) &&
|
|||
|
(*RetSize == sizeof(ULONG)) &&
|
|||
|
(RetryCount++ < 4) ) ||
|
|||
|
(Status == ERROR_WMI_TRY_AGAIN));
|
|||
|
|
|||
|
if ((Status == ERROR_SUCCESS) && (*RetSize == sizeof(ULONG)))
|
|||
|
{
|
|||
|
Status = ERROR_INSUFFICIENT_BUFFER;
|
|||
|
}
|
|||
|
|
|||
|
*RegistrationInfo = RegInfo;
|
|||
|
|
|||
|
CloseHandle(Overlapped.hEvent);
|
|||
|
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
void WmipUpdateKm(
|
|||
|
HANDLE WmiKMHandle,
|
|||
|
PKMREGINFO KMRegInfo
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will query the KM data provider for its registration info
|
|||
|
and then call to register it in the WMI data structures.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
WmiKMHandle is the WMI kernel mode service device handle
|
|||
|
|
|||
|
KMRegInfo is a pointer to the KM registration info
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
BYTE RegInfoBuffer[INITIALREGINFOSIZE];
|
|||
|
PBYTE RegInfo;
|
|||
|
PBYTE RegInfoBase;
|
|||
|
ULONG_PTR ProviderId;
|
|||
|
WCHAR *RegistryPathPtr;
|
|||
|
TCHAR *ImagePathPtr;
|
|||
|
WCHAR RegistryPath[MAX_PATH];
|
|||
|
TCHAR ImagePath[MAX_PATH];
|
|||
|
PWMIREGINFOW WmiRegInfo;
|
|||
|
ULONG RegistryPathSize;
|
|||
|
ULONG Status;
|
|||
|
ULONG RegistryPathOffset;
|
|||
|
#ifdef MEMPHIS
|
|||
|
PCHAR RegistryPathAnsi;
|
|||
|
#endif
|
|||
|
ULONG RetSizeLeft;
|
|||
|
ULONG RetSize;
|
|||
|
|
|||
|
RegInfo = RegInfoBuffer;
|
|||
|
Status = WmipGetKmRegInfo(WmiKMHandle,
|
|||
|
KMRegInfo,
|
|||
|
TRUE,
|
|||
|
&RegInfo,
|
|||
|
INITIALREGINFOSIZE,
|
|||
|
&RetSize);
|
|||
|
|
|||
|
RegInfoBase = RegInfo;
|
|||
|
if (Status == ERROR_SUCCESS)
|
|||
|
{
|
|||
|
ProviderId = KMRegInfo->ProviderId;
|
|||
|
RetSizeLeft = RetSize;
|
|||
|
do
|
|||
|
{
|
|||
|
WmiRegInfo = (PWMIREGINFOW)RegInfo;
|
|||
|
if (WmiRegInfo->BufferSize > RetSizeLeft)
|
|||
|
{
|
|||
|
//
|
|||
|
// If there not enough room left in the buffer for what the
|
|||
|
// driver says is there then reject the buffer
|
|||
|
WmipDebugPrint(("WMI: Invalid buffer size for registration info\n"));
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
WmipUpdateDataSource(ProviderId,
|
|||
|
WmiRegInfo,
|
|||
|
RetSizeLeft);
|
|||
|
|
|||
|
if (WmiRegInfo->NextWmiRegInfo > RetSizeLeft)
|
|||
|
{
|
|||
|
WmipDebugPrint(("WMI: NextWmiRegInfo pointer is out of range\n"));
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
RegInfo += WmiRegInfo->NextWmiRegInfo;
|
|||
|
RetSizeLeft -= WmiRegInfo->NextWmiRegInfo;
|
|||
|
|
|||
|
} while (WmiRegInfo->NextWmiRegInfo != 0);
|
|||
|
}
|
|||
|
|
|||
|
Cleanup:
|
|||
|
if ((RegInfoBase != NULL) && (RegInfoBase != RegInfoBuffer))
|
|||
|
{
|
|||
|
WmipFree(RegInfoBase);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void WmipRegisterKm(
|
|||
|
HANDLE WmiKMHandle,
|
|||
|
PKMREGINFO KMRegInfo
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will query the KM data provider for its registration info
|
|||
|
and then call to register it in the WMI data structures.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
WmiKMHandle is the WMI kernel mode service device handle
|
|||
|
|
|||
|
KMRegInfo is a pointer to the KM registration info
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
BYTE RegInfoBuffer[INITIALREGINFOSIZE];
|
|||
|
PBYTE RegInfo;
|
|||
|
PBYTE RegInfoBase;
|
|||
|
ULONG_PTR ProviderId;
|
|||
|
WCHAR *RegistryPathPtr;
|
|||
|
TCHAR *ImagePathPtr;
|
|||
|
WCHAR RegistryPath[MAX_PATH];
|
|||
|
TCHAR ImagePath[MAX_PATH];
|
|||
|
PWMIREGINFOW WmiRegInfo;
|
|||
|
ULONG RegistryPathSize;
|
|||
|
ULONG Status;
|
|||
|
ULONG RegistryPathOffset;
|
|||
|
#ifdef MEMPHIS
|
|||
|
PCHAR RegistryPathAnsi;
|
|||
|
#endif
|
|||
|
ULONG RetSizeLeft;
|
|||
|
ULONG RetSize;
|
|||
|
|
|||
|
RegInfo = RegInfoBuffer;
|
|||
|
Status = WmipGetKmRegInfo(WmiKMHandle,
|
|||
|
KMRegInfo,
|
|||
|
FALSE,
|
|||
|
&RegInfo,
|
|||
|
INITIALREGINFOSIZE,
|
|||
|
&RetSize);
|
|||
|
|
|||
|
RegInfoBase = RegInfo;
|
|||
|
if (Status == ERROR_SUCCESS)
|
|||
|
{
|
|||
|
ProviderId = KMRegInfo->ProviderId;
|
|||
|
RetSizeLeft = RetSize;
|
|||
|
do
|
|||
|
{
|
|||
|
WmiRegInfo = (PWMIREGINFOW)RegInfo;
|
|||
|
if (WmiRegInfo->BufferSize > RetSizeLeft)
|
|||
|
{
|
|||
|
//
|
|||
|
// If there not enough room left in the buffer for what the
|
|||
|
// driver says is there then reject the buffer
|
|||
|
WmipDebugPrint(("WMI: Invalid buffer size for registration info\n"));
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
ImagePathPtr = NULL;
|
|||
|
RegistryPathOffset = WmiRegInfo->RegistryPath;
|
|||
|
|
|||
|
if (RegistryPathOffset > RetSize)
|
|||
|
{
|
|||
|
WmipDebugPrint(("WMI: Bogus KM RegInfo for %x\n",
|
|||
|
KMRegInfo->ProviderId));
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
if (RegistryPathOffset != 0)
|
|||
|
{
|
|||
|
RegistryPathPtr = (PWCHAR)OffsetToPtr(RegInfo, WmiRegInfo->RegistryPath);
|
|||
|
RegistryPathSize = *RegistryPathPtr;
|
|||
|
if (WmipValidateCountedString(RegistryPathPtr))
|
|||
|
{
|
|||
|
if ((RegistryPathSize < sizeof(RegistryPath)) &&
|
|||
|
(RegistryPathSize != 0))
|
|||
|
{
|
|||
|
RegistryPathSize /= sizeof(WCHAR);
|
|||
|
wcsncpy(RegistryPath, RegistryPathPtr+1, RegistryPathSize);
|
|||
|
RegistryPath[RegistryPathSize] = UNICODE_NULL;
|
|||
|
#ifdef MEMPHIS
|
|||
|
RegistryPathAnsi = NULL;
|
|||
|
Status = UnicodeToAnsi(RegistryPath,
|
|||
|
&RegistryPathAnsi,
|
|||
|
NULL);
|
|||
|
if (Status != ERROR_SUCCESS)
|
|||
|
{
|
|||
|
WmipDebugPrint(("WMI: Error converting Registrypath to ansi\n"));
|
|||
|
}
|
|||
|
ImagePathPtr = WmipRegistryToImagePath(
|
|||
|
ImagePath,
|
|||
|
RegistryPathAnsi,
|
|||
|
ProviderId);
|
|||
|
if (RegistryPathAnsi != NULL)
|
|||
|
{
|
|||
|
WmipFree(RegistryPathAnsi);
|
|||
|
}
|
|||
|
#else
|
|||
|
ImagePathPtr = WmipRegistryToImagePath(
|
|||
|
ImagePath,
|
|||
|
RegistryPath,
|
|||
|
ProviderId);
|
|||
|
#endif
|
|||
|
} else {
|
|||
|
WmipReportEventLog(EVENT_WMI_INVALID_REGPATH,
|
|||
|
EVENTLOG_WARNING_TYPE,
|
|||
|
0,
|
|||
|
sizeof(UINT_PTR),
|
|||
|
&ProviderId,
|
|||
|
1,
|
|||
|
RegistryPathPtr);
|
|||
|
WmipDebugPrint(("WMI: Specified registry path is empty or too long %x\n",
|
|||
|
RegistryPathPtr));
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
WmipAddDataSource(NULL,
|
|||
|
0,
|
|||
|
0,
|
|||
|
ImagePathPtr,
|
|||
|
WmiRegInfo,
|
|||
|
RetSizeLeft,
|
|||
|
&ProviderId,
|
|||
|
FALSE);
|
|||
|
|
|||
|
if (WmiRegInfo->NextWmiRegInfo > RetSizeLeft)
|
|||
|
{
|
|||
|
WmipDebugPrint(("WMI: NextWmiRegInfo pointer is out of range\n"));
|
|||
|
goto Cleanup;
|
|||
|
}
|
|||
|
|
|||
|
RegInfo += WmiRegInfo->NextWmiRegInfo;
|
|||
|
RetSizeLeft -= WmiRegInfo->NextWmiRegInfo;
|
|||
|
|
|||
|
} while (WmiRegInfo->NextWmiRegInfo != 0);
|
|||
|
} else {
|
|||
|
// Put something in eventlog
|
|||
|
}
|
|||
|
|
|||
|
Cleanup:
|
|||
|
if ((RegInfoBase != NULL) && (RegInfoBase != RegInfoBuffer))
|
|||
|
{
|
|||
|
WmipFree(RegInfoBase);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ULONG WmipInitializeKM(
|
|||
|
HANDLE *WmiKMHandle
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Initialize access to kernel mode. Open the service device and query for
|
|||
|
all registered KM drivers then query each driver for its registration
|
|||
|
info and then try to register each driver in the user mode cache.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
WmiKMHandle is the WMI kernel mode service device handle
|
|||
|
|
|||
|
KMRegInfo is a pointer to the KM registration info
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
ULONG Status;
|
|||
|
KMREGINFO KmRegInfoStatic[1];
|
|||
|
PKMREGINFO KmRegInfo = KmRegInfoStatic;
|
|||
|
ULONG KmRegInfoSize, KmRegInfoCount;
|
|||
|
BOOL IoctlSuccess;
|
|||
|
ULONG RetSize;
|
|||
|
OVERLAPPED Overlapped;
|
|||
|
|
|||
|
//
|
|||
|
// Open up the WMI service device
|
|||
|
*WmiKMHandle = CreateFile(
|
|||
|
WMIServiceDeviceName,
|
|||
|
GENERIC_READ | GENERIC_WRITE,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
OPEN_EXISTING,
|
|||
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
|
|||
|
NULL
|
|||
|
);
|
|||
|
Status = GetLastError();
|
|||
|
|
|||
|
Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|||
|
if (Overlapped.hEvent == NULL)
|
|||
|
{
|
|||
|
return(GetLastError());
|
|||
|
}
|
|||
|
|
|||
|
KmRegInfoSize = sizeof(KmRegInfoStatic);
|
|||
|
if (*WmiKMHandle != (HANDLE)-1)
|
|||
|
{
|
|||
|
//
|
|||
|
// Loop querying the WMI device for registration info until we hit
|
|||
|
// upon the right number of KMREGINFO
|
|||
|
do
|
|||
|
{
|
|||
|
IoctlSuccess = DeviceIoControl(*WmiKMHandle,
|
|||
|
IOCTL_WMI_GET_ALL_REGISTRANT,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
KmRegInfo,
|
|||
|
KmRegInfoSize,
|
|||
|
&RetSize,
|
|||
|
&Overlapped);
|
|||
|
if (GetLastError() == ERROR_IO_PENDING)
|
|||
|
{
|
|||
|
IoctlSuccess = GetOverlappedResult(*WmiKMHandle,
|
|||
|
&Overlapped,
|
|||
|
&RetSize,
|
|||
|
TRUE);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If this succeeds, but only returns a ULONG then our buffer was
|
|||
|
// too small and the ULONG has the size that we need
|
|||
|
if (IoctlSuccess && (RetSize == sizeof(ULONG)))
|
|||
|
{
|
|||
|
KmRegInfoSize = *((ULONG *)KmRegInfo);
|
|||
|
if (KmRegInfo != KmRegInfoStatic)
|
|||
|
{
|
|||
|
WmipFree(KmRegInfo);
|
|||
|
}
|
|||
|
KmRegInfo = WmipAlloc(KmRegInfoSize);
|
|||
|
if (KmRegInfo == NULL)
|
|||
|
{
|
|||
|
WmipDebugPrint(("WMI: Couldn't alloc memory for KmRegInfo\n"));
|
|||
|
CloseHandle(Overlapped.hEvent);
|
|||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
}
|
|||
|
} else {
|
|||
|
break;
|
|||
|
}
|
|||
|
} while (TRUE);
|
|||
|
|
|||
|
if (IoctlSuccess)
|
|||
|
{
|
|||
|
//
|
|||
|
// We have got the registration list, so process all of the
|
|||
|
// registered drivers
|
|||
|
KmRegInfoCount = RetSize / sizeof(KMREGINFO);
|
|||
|
|
|||
|
for (i = 0; i < KmRegInfoCount; i++)
|
|||
|
{
|
|||
|
WmipAssert(KmRegInfo[i].ProviderId != 0);
|
|||
|
WmipRegisterKm(*WmiKMHandle, &KmRegInfo[i]);
|
|||
|
}
|
|||
|
|
|||
|
Status = ERROR_SUCCESS;
|
|||
|
|
|||
|
} else {
|
|||
|
Status = GetLastError();
|
|||
|
WmipDebugPrint(("WMI: IOCTL_WMI_GET_ALL_REGISTRANT failed %x\n", Status));
|
|||
|
CloseHandle(*WmiKMHandle);
|
|||
|
*WmiKMHandle = (HANDLE)-1;
|
|||
|
}
|
|||
|
|
|||
|
if (KmRegInfo != KmRegInfoStatic)
|
|||
|
{
|
|||
|
WmipFree(KmRegInfo);
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
WmipReportEventLog(EVENT_WMI_CANT_OPEN_DEVICE,
|
|||
|
EVENTLOG_ERROR_TYPE,
|
|||
|
0,
|
|||
|
sizeof(ULONG),
|
|||
|
&Status,
|
|||
|
0);
|
|||
|
WmipDebugPrint(("WMI: open service device failed %x\n", Status));
|
|||
|
}
|
|||
|
|
|||
|
CloseHandle(Overlapped.hEvent);
|
|||
|
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
void WmipKMNonEventNotification(
|
|||
|
HANDLE WmiKMHandle,
|
|||
|
PWNODE_HEADER Wnode
|
|||
|
)
|
|||
|
{
|
|||
|
PKMREGINFO KMRegInfo;
|
|||
|
|
|||
|
//
|
|||
|
// Is the buffer size correct ?
|
|||
|
//
|
|||
|
if (Wnode->BufferSize == INTERNALNOTIFICATIONSIZE)
|
|||
|
{
|
|||
|
//
|
|||
|
// Make sure that correct notification type bits are set and only
|
|||
|
// those bits are set
|
|||
|
//
|
|||
|
WmipAssert((Wnode->Version &
|
|||
|
NOTIFICATIONSLOT_MASK_NOTIFICATIONTYPES) != 0);
|
|||
|
WmipAssert((Wnode->Version &
|
|||
|
~NOTIFICATIONSLOT_MASK_NOTIFICATIONTYPES) == 0)
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Registration notifications need to handled in a specific order.
|
|||
|
// RegistrationDelete is always handled first and any other are
|
|||
|
// ignored. If a device is unregistering we can ignore any updates.
|
|||
|
// A RegistrationAdd is handled before a RegistrationUpdate.
|
|||
|
//
|
|||
|
KMRegInfo = (PKMREGINFO)((PCHAR)Wnode + sizeof(WNODE_HEADER));
|
|||
|
if (Wnode->Version & RegistrationDelete)
|
|||
|
{
|
|||
|
WmipRemoveDataSource(KMRegInfo->ProviderId);
|
|||
|
} else {
|
|||
|
if (Wnode->Version & RegistrationAdd)
|
|||
|
{
|
|||
|
WmipRegisterKm(WmiKMHandle, KMRegInfo);
|
|||
|
}
|
|||
|
|
|||
|
if (Wnode->Version & RegistrationUpdate)
|
|||
|
{
|
|||
|
WmipUpdateKm(WmiKMHandle, KMRegInfo);
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
WmipDebugPrint(("WMI: Invalid non event notification buffer %x\n",
|
|||
|
Wnode));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#ifndef MEMPHIS
|
|||
|
|
|||
|
|
|||
|
ULONG WmipSendWmiKMRequest(
|
|||
|
ULONG Ioctl,
|
|||
|
PVOID Buffer,
|
|||
|
ULONG InBufferSize,
|
|||
|
PVOID OutBuffer,
|
|||
|
ULONG MaxBufferSize,
|
|||
|
ULONG *ReturnSize
|
|||
|
)
|
|||
|
/*+++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine does the work of sending WMI requests to the WMI kernel
|
|||
|
mode service device. Any retry errors returned by the WMI device are
|
|||
|
handled in this routine.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Ioctl is the IOCTL code to send to the WMI device
|
|||
|
Buffer is the input and output buffer for the call to the WMI device
|
|||
|
InBufferSize is the size of the buffer passed to the device
|
|||
|
MaxBufferSize is the maximum number of bytes that can be written
|
|||
|
into the buffer
|
|||
|
*ReturnSize on return has the actual number of bytes written in buffer
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ERROR_SUCCESS or an error code
|
|||
|
---*/
|
|||
|
{
|
|||
|
OVERLAPPED Overlapped;
|
|||
|
ULONG Status;
|
|||
|
BOOL IoctlSuccess;
|
|||
|
|
|||
|
WmipAssert(WmipKMHandle != NULL);
|
|||
|
|
|||
|
Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|||
|
if (Overlapped.hEvent == NULL)
|
|||
|
{
|
|||
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
do
|
|||
|
{
|
|||
|
IoctlSuccess = DeviceIoControl(WmipKMHandle,
|
|||
|
Ioctl,
|
|||
|
Buffer,
|
|||
|
InBufferSize,
|
|||
|
OutBuffer,
|
|||
|
MaxBufferSize,
|
|||
|
ReturnSize,
|
|||
|
&Overlapped);
|
|||
|
|
|||
|
if (GetLastError() == ERROR_IO_PENDING)
|
|||
|
{
|
|||
|
IoctlSuccess = GetOverlappedResult(WmipKMHandle,
|
|||
|
&Overlapped,
|
|||
|
ReturnSize,
|
|||
|
TRUE);
|
|||
|
}
|
|||
|
|
|||
|
if (! IoctlSuccess)
|
|||
|
{
|
|||
|
Status = GetLastError();
|
|||
|
} else {
|
|||
|
Status = ERROR_SUCCESS;
|
|||
|
}
|
|||
|
} while (Status == ERROR_WMI_TRY_AGAIN);
|
|||
|
|
|||
|
CloseHandle(Overlapped.hEvent);
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
|