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
|
||
|