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.
1126 lines
40 KiB
1126 lines
40 KiB
//
|
|
|
|
|
|
// DEVNODE.C
|
|
//
|
|
#include "sigverif.h"
|
|
#include <initguid.h>
|
|
#include <devguid.h>
|
|
|
|
//
|
|
// Given the full path to a driver, add it to the file list.
|
|
//
|
|
LPFILENODE
|
|
AddDriverFileToList(
|
|
LPTSTR lpDirName,
|
|
LPTSTR lpFullPathName
|
|
)
|
|
{
|
|
DWORD Err = ERROR_SUCCESS;
|
|
LPFILENODE lpFileNode = NULL;
|
|
TCHAR szDirName[MAX_PATH];
|
|
TCHAR szFileName[MAX_PATH];
|
|
LPTSTR lpFilePart;
|
|
|
|
*szDirName = 0;
|
|
*szFileName = 0;
|
|
|
|
//
|
|
// If no directory is passed in, try to get the full path
|
|
//
|
|
if (!lpDirName || !*lpDirName) {
|
|
|
|
if (GetFullPathName(lpFullPathName, cA(szDirName), szDirName, &lpFilePart)) {
|
|
|
|
if (lpFilePart && *lpFilePart) {
|
|
|
|
if (SUCCEEDED(StringCchCopy(szFileName, cA(szFileName), lpFilePart))) {
|
|
|
|
*lpFilePart = 0;
|
|
|
|
if (lstrlen(szDirName) > 3) {
|
|
|
|
*(lpFilePart - 1) = 0;
|
|
}
|
|
} else {
|
|
*szFileName = 0;
|
|
}
|
|
}
|
|
} else {
|
|
*szDirName = 0;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Use the directory and filename that was passed in to us
|
|
// Expand out lpDirName in case there are any ".." entries
|
|
//
|
|
if (!GetFullPathName(lpDirName, cA(szDirName), szDirName, NULL)) {
|
|
//
|
|
// If we can't get the full path, then just use the one
|
|
// that was passed in. This could happen if the directory
|
|
// is missing for instance.
|
|
//
|
|
if (FAILED(StringCchCopy(szDirName, cA(szDirName), lpDirName))) {
|
|
//
|
|
// If we can't fit the directory name into our buffer then
|
|
// clear szDirName so this node won't be added to the list.
|
|
//
|
|
*szDirName = 0;
|
|
}
|
|
}
|
|
|
|
if (FAILED(StringCchCopy(szFileName, cA(szFileName), lpFullPathName))) {
|
|
//
|
|
// If we can't fit the file name into our buffer then
|
|
// clear szFileName so this node won't be added to the list.
|
|
//
|
|
*szFileName = 0;
|
|
}
|
|
}
|
|
|
|
if (*szDirName && *szFileName && !IsFileAlreadyInList(szDirName, szFileName)) {
|
|
//
|
|
// Create a filenode, based on the directory and filename
|
|
//
|
|
lpFileNode = CreateFileNode(szDirName, szFileName);
|
|
|
|
if (lpFileNode) {
|
|
|
|
InsertFileNodeIntoList(lpFileNode);
|
|
|
|
//
|
|
// Increment the total number of files we've found that meet the
|
|
// search criteria.
|
|
//
|
|
g_App.dwFiles++;
|
|
|
|
} else {
|
|
|
|
Err = GetLastError();
|
|
}
|
|
}
|
|
|
|
SetLastError(Err);
|
|
return lpFileNode;
|
|
}
|
|
|
|
BOOL
|
|
GetFullPathFromImagePath(
|
|
LPCTSTR ImagePath,
|
|
LPTSTR FullPath,
|
|
UINT FullPathLength
|
|
)
|
|
{
|
|
TCHAR OriginalCurrentDirectory[MAX_PATH];
|
|
LPTSTR pRelativeString;
|
|
LPTSTR lpFilePart;
|
|
|
|
if (!ImagePath || (ImagePath[0] == TEXT('\0'))) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// First check if the ImagePath happens to be a valid full path.
|
|
//
|
|
if (GetFileAttributes(ImagePath) != 0xFFFFFFFF) {
|
|
GetFullPathName(ImagePath, FullPathLength, FullPath, &lpFilePart);
|
|
return TRUE;
|
|
}
|
|
|
|
pRelativeString = (LPTSTR)ImagePath;
|
|
|
|
//
|
|
// If the ImagePath starts with "\SystemRoot" or "%SystemRoot%" then
|
|
// remove those values.
|
|
//
|
|
if (StrCmpNI(ImagePath, TEXT("\\SystemRoot\\"), lstrlen(TEXT("\\SystemRoot\\"))) == 0) {
|
|
pRelativeString += lstrlen(TEXT("\\SystemRoot\\"));
|
|
} else if (StrCmpNI(ImagePath, TEXT("%SystemRoot%\\"), lstrlen(TEXT("%SystemRoot%\\"))) == 0) {
|
|
pRelativeString += lstrlen(TEXT("%SystemRoot%\\"));
|
|
}
|
|
|
|
//
|
|
// At this point pRelativeString should point to the image path relative to
|
|
// the windows directory.
|
|
//
|
|
if (!GetSystemWindowsDirectory(FullPath, FullPathLength)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!GetCurrentDirectory(cA(OriginalCurrentDirectory), OriginalCurrentDirectory)) {
|
|
OriginalCurrentDirectory[0] = TEXT('\0');
|
|
}
|
|
|
|
if (!SetCurrentDirectory(FullPath)) {
|
|
return FALSE;
|
|
}
|
|
|
|
GetFullPathName(pRelativeString, FullPathLength, FullPath, &lpFilePart);
|
|
|
|
if (OriginalCurrentDirectory[0] != TEXT('\0')) {
|
|
SetCurrentDirectory(OriginalCurrentDirectory);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD
|
|
CreateFromService(
|
|
SC_HANDLE hscManager,
|
|
PCTSTR ServiceName
|
|
)
|
|
{
|
|
DWORD Err = ERROR_SUCCESS;
|
|
SC_HANDLE hscService = NULL;
|
|
DWORD BytesRequired, Size;
|
|
TCHAR FullPath[MAX_PATH];
|
|
LPQUERY_SERVICE_CONFIG pqsc;
|
|
PBYTE BufferPtr = NULL;
|
|
|
|
if (hscManager == NULL) {
|
|
//
|
|
// This should never happen.
|
|
//
|
|
goto clean0;
|
|
}
|
|
|
|
if (!ServiceName ||
|
|
(ServiceName[0] == TEXT('\0'))) {
|
|
//
|
|
// This should also never happen.
|
|
//
|
|
goto clean0;
|
|
}
|
|
|
|
hscService = OpenService(hscManager, ServiceName, GENERIC_READ);
|
|
if (NULL == hscService) {
|
|
//
|
|
// This service does not exist. We won't return an error in this case
|
|
// since if the service doesn't exist then the driver won't get
|
|
// loaded.
|
|
//
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// First, probe for buffer size
|
|
//
|
|
if (!QueryServiceConfig(hscService, NULL, 0, &BytesRequired) &&
|
|
ERROR_INSUFFICIENT_BUFFER == GetLastError()) {
|
|
|
|
BufferPtr = MALLOC(BytesRequired);
|
|
|
|
if (!BufferPtr) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean0;
|
|
}
|
|
|
|
pqsc = (LPQUERY_SERVICE_CONFIG)(PBYTE)BufferPtr;
|
|
|
|
if (QueryServiceConfig(hscService, pqsc, BytesRequired, &Size) &&
|
|
pqsc->lpBinaryPathName &&
|
|
(TEXT('\0') != pqsc->lpBinaryPathName[0])) {
|
|
//
|
|
// Make sure we have a valid full path.
|
|
//
|
|
if (GetFullPathFromImagePath(pqsc->lpBinaryPathName,
|
|
FullPath,
|
|
cA(FullPath))) {
|
|
|
|
AddDriverFileToList(NULL, FullPath);
|
|
}
|
|
}
|
|
|
|
FREE(BufferPtr);
|
|
}
|
|
|
|
clean0:
|
|
|
|
if (hscService) {
|
|
CloseServiceHandle(hscService);
|
|
hscService = NULL;
|
|
}
|
|
|
|
if (BufferPtr) {
|
|
FREE(BufferPtr);
|
|
}
|
|
|
|
return Err;
|
|
}
|
|
|
|
UINT
|
|
ScanQueueCallback(
|
|
PVOID Context,
|
|
UINT Notification,
|
|
UINT_PTR Param1,
|
|
UINT_PTR Param2
|
|
)
|
|
{
|
|
LPFILENODE lpFileNode;
|
|
TCHAR szBuffer[MAX_PATH];
|
|
LPTSTR lpFilePart;
|
|
ULONG BufCbSize;
|
|
HRESULT hr;
|
|
|
|
UNREFERENCED_PARAMETER(Param2);
|
|
|
|
if ((Notification == SPFILENOTIFY_QUEUESCAN_SIGNERINFO) &&
|
|
Param1) {
|
|
//
|
|
// Special case for printers:
|
|
// After setupapi copies files from the file queue into their destination
|
|
// location, the printer class installer moves some of these files into
|
|
// other 'special' locations. This can lead to the callback Win32Error
|
|
// returning ERROR_FILE_NOT_FOUND or ERROR_PATH_NOT_FOUND since the file
|
|
// is not present in the location where setupapi put it. So, we will
|
|
// catch this case for printers and not add the file to our list of
|
|
// files to scan. These 'special' printer files will get added later
|
|
// when we call the spooler APIs.
|
|
// Also note that we can't just skip getting the list of files for printers
|
|
// altogether since the printer class installer only moves some of the
|
|
// files that setupapi copies and not all of them.
|
|
//
|
|
if (Context &&
|
|
(IsEqualGUID((LPGUID)Context, &GUID_DEVCLASS_PRINTER)) &&
|
|
((((PFILEPATHS_SIGNERINFO)Param1)->Win32Error == ERROR_FILE_NOT_FOUND) ||
|
|
(((PFILEPATHS_SIGNERINFO)Param1)->Win32Error == ERROR_PATH_NOT_FOUND))) {
|
|
//
|
|
// Assume this was a file moved by the printer class installer. Don't
|
|
// add it to the list of files to be scanned at this time.
|
|
//
|
|
return NO_ERROR;
|
|
}
|
|
|
|
lpFileNode = AddDriverFileToList(NULL,
|
|
(LPTSTR)((PFILEPATHS_SIGNERINFO)Param1)->Target);
|
|
|
|
//
|
|
// Fill in some information into the FILENODE structure since we already
|
|
// scanned the file.
|
|
//
|
|
if (lpFileNode) {
|
|
|
|
lpFileNode->bScanned = TRUE;
|
|
lpFileNode->bSigned = (((PFILEPATHS_SIGNERINFO)Param1)->Win32Error == NO_ERROR);
|
|
|
|
if (lpFileNode->bSigned) {
|
|
|
|
if (((PFILEPATHS_SIGNERINFO)Param1)->CatalogFile) {
|
|
|
|
GetFullPathName(((PFILEPATHS_SIGNERINFO)Param1)->CatalogFile, cA(szBuffer), szBuffer, &lpFilePart);
|
|
|
|
BufCbSize = (lstrlen(lpFilePart) + 1) * sizeof(TCHAR);
|
|
lpFileNode->lpCatalog = MALLOC(BufCbSize);
|
|
|
|
if (lpFileNode->lpCatalog) {
|
|
|
|
hr = StringCbCopy(lpFileNode->lpCatalog, BufCbSize, lpFilePart);
|
|
|
|
if (FAILED(hr) && (hr != STRSAFE_E_INSUFFICIENT_BUFFER)) {
|
|
//
|
|
// If we fail for some reason other than insufficient
|
|
// buffer, then free the string and set the pointer
|
|
// to NULL, since the string is undefined.
|
|
//
|
|
FREE(lpFileNode->lpCatalog);
|
|
lpFileNode->lpCatalog = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (((PFILEPATHS_SIGNERINFO)Param1)->DigitalSigner) {
|
|
|
|
BufCbSize = (lstrlen(((PFILEPATHS_SIGNERINFO)Param1)->DigitalSigner) + 1) * sizeof(TCHAR);
|
|
lpFileNode->lpSignedBy = MALLOC(BufCbSize);
|
|
|
|
if (lpFileNode->lpSignedBy) {
|
|
|
|
hr = StringCbCopy(lpFileNode->lpSignedBy, BufCbSize, ((PFILEPATHS_SIGNERINFO)Param1)->DigitalSigner);
|
|
|
|
if (FAILED(hr) && (hr != STRSAFE_E_INSUFFICIENT_BUFFER)) {
|
|
//
|
|
// If we fail for some reason other than insufficient
|
|
// buffer, then free the string and set the pointer
|
|
// to NULL, since the string is undefined.
|
|
//
|
|
FREE(lpFileNode->lpSignedBy);
|
|
lpFileNode->lpSignedBy = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (((PFILEPATHS_SIGNERINFO)Param1)->Version) {
|
|
|
|
BufCbSize = (lstrlen(((PFILEPATHS_SIGNERINFO)Param1)->Version) + 1) * sizeof(TCHAR);
|
|
lpFileNode->lpVersion = MALLOC(BufCbSize);
|
|
|
|
if (lpFileNode->lpVersion) {
|
|
|
|
hr = StringCbCopy(lpFileNode->lpVersion, BufCbSize, ((PFILEPATHS_SIGNERINFO)Param1)->Version);
|
|
|
|
if (FAILED(hr) && (hr != STRSAFE_E_INSUFFICIENT_BUFFER)) {
|
|
//
|
|
// If we fail for some reason other than insufficient
|
|
// buffer, then free the string and set the pointer
|
|
// to NULL, since the string is undefined.
|
|
//
|
|
FREE(lpFileNode->lpVersion);
|
|
lpFileNode->lpVersion = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Get the icon (if the file isn't signed) so we can display it in the listview faster.
|
|
//
|
|
MyGetFileInfo(lpFileNode);
|
|
}
|
|
}
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
void
|
|
AddClassInstallerToList(
|
|
LPCTSTR ClassInstallerString
|
|
)
|
|
{
|
|
DWORD BufferSize;
|
|
TCHAR ModulePath[MAX_PATH];
|
|
TCHAR TempBuffer[MAX_PATH];
|
|
PTSTR StringPtr;
|
|
|
|
if ((ClassInstallerString == NULL) ||
|
|
(ClassInstallerString[0] == TEXT('\0'))) {
|
|
return;
|
|
}
|
|
|
|
if (FAILED(StringCchCopy(TempBuffer, cA(TempBuffer), ClassInstallerString))) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Class/Co-installers are always based under the %windir%\system32
|
|
// directory.
|
|
//
|
|
if (GetSystemDirectory(ModulePath, cA(ModulePath)) == 0) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Find the beginning of the entry point name, if present.
|
|
//
|
|
BufferSize = (lstrlen(TempBuffer) + 1) * sizeof(TCHAR);
|
|
for(StringPtr = TempBuffer + ((BufferSize / sizeof(TCHAR)) - 2);
|
|
StringPtr >= TempBuffer;
|
|
StringPtr--) {
|
|
|
|
if(*StringPtr == TEXT(',')) {
|
|
*(StringPtr++) = TEXT('\0');
|
|
break;
|
|
}
|
|
//
|
|
// If we hit a double-quote mark, then set the character pointer
|
|
// to the beginning of the string so we'll terminate the search.
|
|
//
|
|
if(*StringPtr == TEXT('\"')) {
|
|
StringPtr = TempBuffer;
|
|
}
|
|
}
|
|
|
|
if (pSetupConcatenatePaths(ModulePath, TempBuffer, MAX_PATH, NULL)) {
|
|
AddDriverFileToList(NULL, ModulePath);
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
BuildDriverFileList(
|
|
void
|
|
)
|
|
{
|
|
DWORD Err = ERROR_SUCCESS;
|
|
HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
|
|
SP_DEVINFO_DATA DeviceInfoData;
|
|
SP_DRVINFO_DATA DriverInfoData;
|
|
SP_DEVINSTALL_PARAMS DeviceInstallParams;
|
|
DWORD DeviceMemberIndex;
|
|
HSPFILEQ hFileQueue;
|
|
DWORD ScanResult;
|
|
DWORD Status, Problem;
|
|
SC_HANDLE hscManager = NULL;
|
|
TCHAR Buffer[MAX_PATH];
|
|
ULONG BufferSize;
|
|
DWORD dwType;
|
|
HKEY hKey = INVALID_HANDLE_VALUE, hKeyClassCoInstallers = INVALID_HANDLE_VALUE;
|
|
PTSTR pItemList = NULL, pSingleItem;
|
|
LPGUID ClassGuidList = NULL;
|
|
DWORD i, NumberClassGuids, CurrentClassGuid;
|
|
TCHAR GuidString[MAX_GUID_STRING_LEN];
|
|
|
|
//
|
|
// Build up a list of all the devices in the system.
|
|
//
|
|
hDeviceInfo = SetupDiGetClassDevs(NULL,
|
|
NULL,
|
|
NULL,
|
|
DIGCF_ALLCLASSES
|
|
);
|
|
|
|
if (hDeviceInfo == INVALID_HANDLE_VALUE) {
|
|
Err = GetLastError();
|
|
goto clean0;
|
|
}
|
|
|
|
DeviceInfoData.cbSize = sizeof(DeviceInfoData);
|
|
DeviceMemberIndex = 0;
|
|
|
|
//
|
|
// Enumerate through the list of devices and get a list of all
|
|
// the files they copy, if they are signed or not, and which catalog
|
|
// signed them.
|
|
//
|
|
while (SetupDiEnumDeviceInfo(hDeviceInfo,
|
|
DeviceMemberIndex++,
|
|
&DeviceInfoData
|
|
) &&
|
|
!g_App.bStopScan) {
|
|
|
|
//
|
|
// We will only build up a driver list for swenum phantoms. All other
|
|
// phantoms will be skipped.
|
|
//
|
|
if (CM_Get_DevNode_Status(&Status,
|
|
&Problem,
|
|
DeviceInfoData.DevInst,
|
|
0) == CR_NO_SUCH_DEVINST) {
|
|
//
|
|
// This device is a phantom, if it is not a swenum device, then
|
|
// skip it.
|
|
//
|
|
if (!SetupDiGetDeviceRegistryProperty(hDeviceInfo,
|
|
&DeviceInfoData,
|
|
SPDRP_ENUMERATOR_NAME,
|
|
NULL,
|
|
(PBYTE)Buffer,
|
|
sizeof(Buffer),
|
|
NULL) ||
|
|
(_wcsicmp(Buffer, TEXT("SW")) != 0)) {
|
|
//
|
|
// Either we couldn't get the enumerator name, or it is not
|
|
// SW.
|
|
//
|
|
continue;
|
|
}
|
|
}
|
|
|
|
DeviceInstallParams.cbSize = sizeof(DeviceInstallParams);
|
|
|
|
//
|
|
// Before we call SetupDiBuildDriverInfoList to build up a list of drivers
|
|
// for this device we first need to set the DI_FLAGSEX_INSTALLEDDRIVER flag
|
|
// (which tells the API to only include the currently installed driver in
|
|
// the list) and the DI_FLAGSEX_ALLOWEXCLUDEDRVS (allow ExcludeFromSelect
|
|
// devices in the list).
|
|
//
|
|
if (SetupDiGetDeviceInstallParams(hDeviceInfo,
|
|
&DeviceInfoData,
|
|
&DeviceInstallParams
|
|
)) {
|
|
|
|
DeviceInstallParams.FlagsEx = (DI_FLAGSEX_INSTALLEDDRIVER |
|
|
DI_FLAGSEX_ALLOWEXCLUDEDDRVS);
|
|
|
|
if (SetupDiSetDeviceInstallParams(hDeviceInfo,
|
|
&DeviceInfoData,
|
|
&DeviceInstallParams
|
|
) &&
|
|
SetupDiBuildDriverInfoList(hDeviceInfo,
|
|
&DeviceInfoData,
|
|
SPDIT_CLASSDRIVER
|
|
)) {
|
|
|
|
//
|
|
// Now we will get the one driver node that is in the list that
|
|
// was just built and make it the selected driver node.
|
|
//
|
|
DriverInfoData.cbSize = sizeof(DriverInfoData);
|
|
|
|
if (SetupDiEnumDriverInfo(hDeviceInfo,
|
|
&DeviceInfoData,
|
|
SPDIT_CLASSDRIVER,
|
|
0,
|
|
&DriverInfoData
|
|
) &&
|
|
SetupDiSetSelectedDriver(hDeviceInfo,
|
|
&DeviceInfoData,
|
|
&DriverInfoData
|
|
)) {
|
|
|
|
hFileQueue = SetupOpenFileQueue();
|
|
|
|
if (hFileQueue != INVALID_HANDLE_VALUE) {
|
|
|
|
//
|
|
// Set the FileQueue parameter to the file queue we just
|
|
// created and set the DI_NOVCP flag.
|
|
//
|
|
// The call SetupDiCallClassInstaller with DIF_INSTALLDEVICEFILES
|
|
// to build up a queue of all the files that are copied for
|
|
// this driver node.
|
|
//
|
|
DeviceInstallParams.FileQueue = hFileQueue;
|
|
DeviceInstallParams.Flags |= DI_NOVCP;
|
|
|
|
if (SetupDiSetDeviceInstallParams(hDeviceInfo,
|
|
&DeviceInfoData,
|
|
&DeviceInstallParams
|
|
) &&
|
|
SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES,
|
|
hDeviceInfo,
|
|
&DeviceInfoData
|
|
)) {
|
|
|
|
//
|
|
// Scan the file queue and have it call our callback
|
|
// function for each file in the queue.
|
|
//
|
|
SetupScanFileQueue(hFileQueue,
|
|
SPQ_SCAN_USE_CALLBACK_SIGNERINFO,
|
|
NULL,
|
|
ScanQueueCallback,
|
|
(PVOID)&(DeviceInfoData.ClassGuid),
|
|
&ScanResult
|
|
);
|
|
|
|
|
|
//
|
|
// Dereference the file queue so we can close it.
|
|
//
|
|
DeviceInstallParams.FileQueue = NULL;
|
|
DeviceInstallParams.Flags &= ~DI_NOVCP;
|
|
SetupDiSetDeviceInstallParams(hDeviceInfo,
|
|
&DeviceInfoData,
|
|
&DeviceInstallParams
|
|
);
|
|
}
|
|
|
|
SetupCloseFileQueue(hFileQueue);
|
|
}
|
|
}
|
|
|
|
SetupDiDestroyDriverInfoList(hDeviceInfo,
|
|
&DeviceInfoData,
|
|
SPDIT_CLASSDRIVER
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Enumerate through the list of devices and add any function, device
|
|
// upper/lower filters, and class upper/lower filter drivers to the list
|
|
// that aren't already in the list.
|
|
// We are doing this after we get all the files copied by the INF, because
|
|
// these files can only be validated globally, where the INF copied files
|
|
// can be validated using the catalog associated with their package.
|
|
//
|
|
hscManager = OpenSCManager(NULL, NULL, GENERIC_READ);
|
|
|
|
if (hscManager) {
|
|
DeviceInfoData.cbSize = sizeof(DeviceInfoData);
|
|
DeviceMemberIndex = 0;
|
|
while (SetupDiEnumDeviceInfo(hDeviceInfo,
|
|
DeviceMemberIndex++,
|
|
&DeviceInfoData
|
|
) &&
|
|
!g_App.bStopScan) {
|
|
//
|
|
// Only look at SWENUM phantoms
|
|
//
|
|
if (CM_Get_DevNode_Status(&Status,
|
|
&Problem,
|
|
DeviceInfoData.DevInst,
|
|
0) == CR_NO_SUCH_DEVINST) {
|
|
//
|
|
// This device is a phantom, if it is not a swenum device, then
|
|
// skip it.
|
|
//
|
|
if (!SetupDiGetDeviceRegistryProperty(hDeviceInfo,
|
|
&DeviceInfoData,
|
|
SPDRP_ENUMERATOR_NAME,
|
|
NULL,
|
|
(PBYTE)Buffer,
|
|
sizeof(Buffer),
|
|
NULL) ||
|
|
(_wcsicmp(Buffer, TEXT("SW")) != 0)) {
|
|
//
|
|
// Either we couldn't get the enumerator name, or it is not
|
|
// SW.
|
|
//
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (g_App.bStopScan) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Function driver.
|
|
//
|
|
if (SetupDiGetDeviceRegistryProperty(hDeviceInfo,
|
|
&DeviceInfoData,
|
|
SPDRP_SERVICE,
|
|
NULL,
|
|
(PBYTE)Buffer,
|
|
sizeof(Buffer),
|
|
NULL)) {
|
|
CreateFromService(hscManager, Buffer);
|
|
}
|
|
|
|
if (g_App.bStopScan) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Upper and Lower device filters
|
|
//
|
|
for (i=0; i<2; i++) {
|
|
BufferSize = 0;
|
|
SetupDiGetDeviceRegistryProperty(hDeviceInfo,
|
|
&DeviceInfoData,
|
|
i ? SPDRP_LOWERFILTERS : SPDRP_UPPERFILTERS,
|
|
NULL,
|
|
NULL,
|
|
BufferSize,
|
|
&BufferSize);
|
|
|
|
if (BufferSize > 0) {
|
|
pItemList = MALLOC(BufferSize + (2 * sizeof(TCHAR)));
|
|
|
|
if (!pItemList) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean0;
|
|
}
|
|
|
|
if (SetupDiGetDeviceRegistryProperty(hDeviceInfo,
|
|
&DeviceInfoData,
|
|
i ? SPDRP_LOWERFILTERS : SPDRP_UPPERFILTERS,
|
|
NULL,
|
|
(PBYTE)pItemList,
|
|
BufferSize,
|
|
&BufferSize)) {
|
|
for (pSingleItem=pItemList;
|
|
*pSingleItem;
|
|
pSingleItem += (lstrlen(pSingleItem) + 1)) {
|
|
|
|
CreateFromService(hscManager, pSingleItem);
|
|
}
|
|
}
|
|
|
|
FREE(pItemList);
|
|
}
|
|
}
|
|
|
|
if (g_App.bStopScan) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Device co-installers.
|
|
//
|
|
hKey = SetupDiOpenDevRegKey(hDeviceInfo,
|
|
&DeviceInfoData,
|
|
DICS_FLAG_GLOBAL,
|
|
0,
|
|
DIREG_DRV,
|
|
KEY_READ);
|
|
|
|
if (hKey != INVALID_HANDLE_VALUE) {
|
|
|
|
BufferSize = 0;
|
|
RegQueryValueEx(hKey,
|
|
REGSTR_VAL_COINSTALLERS_32,
|
|
NULL,
|
|
&dwType,
|
|
NULL,
|
|
&BufferSize);
|
|
|
|
if (BufferSize > 0) {
|
|
pItemList = MALLOC(BufferSize + (2 * sizeof(TCHAR)));
|
|
|
|
if (!pItemList) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean0;
|
|
}
|
|
|
|
dwType = REG_MULTI_SZ;
|
|
if (RegQueryValueEx(hKey,
|
|
REGSTR_VAL_COINSTALLERS_32,
|
|
NULL,
|
|
&dwType,
|
|
(PBYTE)pItemList,
|
|
&BufferSize) == ERROR_SUCCESS) {
|
|
|
|
for (pSingleItem=pItemList;
|
|
*pSingleItem;
|
|
pSingleItem += (lstrlen(pSingleItem) + 1)) {
|
|
|
|
AddClassInstallerToList(pSingleItem);
|
|
}
|
|
}
|
|
|
|
FREE(pItemList);
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
hKey = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Enumerate through the classes so we can get the class upper and
|
|
// lower filters and the class installers.
|
|
//
|
|
NumberClassGuids = 0;
|
|
SetupDiBuildClassInfoList(0, NULL, 0, &NumberClassGuids);
|
|
|
|
if (NumberClassGuids > 0) {
|
|
|
|
ClassGuidList = MALLOC(NumberClassGuids * sizeof(GUID));
|
|
|
|
if (!ClassGuidList) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean0;
|
|
}
|
|
|
|
if (SetupDiBuildClassInfoList(0, ClassGuidList, NumberClassGuids, &NumberClassGuids)) {
|
|
//
|
|
// Open the class co-installer key since we will go through that
|
|
// list while we have the class guids handy.
|
|
//
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
REGSTR_PATH_CODEVICEINSTALLERS,
|
|
0,
|
|
KEY_READ,
|
|
&hKeyClassCoInstallers) != ERROR_SUCCESS) {
|
|
hKeyClassCoInstallers = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
|
|
for (CurrentClassGuid=0; CurrentClassGuid<NumberClassGuids; CurrentClassGuid++) {
|
|
//
|
|
// Open the class key.
|
|
//
|
|
hKey = SetupDiOpenClassRegKey(&(ClassGuidList[CurrentClassGuid]),
|
|
KEY_READ);
|
|
|
|
if (hKey != INVALID_HANDLE_VALUE) {
|
|
|
|
//
|
|
// Upper and Lower class filters
|
|
//
|
|
for (i=0; i<2; i++) {
|
|
BufferSize = 0;
|
|
RegQueryValueEx(hKey,
|
|
i ? REGSTR_VAL_LOWERFILTERS : REGSTR_VAL_UPPERFILTERS,
|
|
NULL,
|
|
&dwType,
|
|
NULL,
|
|
&BufferSize);
|
|
|
|
if (BufferSize > 0) {
|
|
pItemList = MALLOC(BufferSize + (2 * sizeof(TCHAR)));
|
|
|
|
if (!pItemList) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean0;
|
|
}
|
|
|
|
dwType = REG_MULTI_SZ;
|
|
if (RegQueryValueEx(hKey,
|
|
i ? REGSTR_VAL_LOWERFILTERS : REGSTR_VAL_UPPERFILTERS,
|
|
NULL,
|
|
&dwType,
|
|
(PBYTE)pItemList,
|
|
&BufferSize) == ERROR_SUCCESS) {
|
|
|
|
for (pSingleItem=pItemList;
|
|
*pSingleItem;
|
|
pSingleItem += (lstrlen(pSingleItem) + 1)) {
|
|
|
|
CreateFromService(hscManager, pSingleItem);
|
|
}
|
|
}
|
|
|
|
FREE(pItemList);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Class installer
|
|
//
|
|
dwType = REG_SZ;
|
|
BufferSize = sizeof(Buffer);
|
|
if (RegQueryValueEx(hKey,
|
|
REGSTR_VAL_INSTALLER_32,
|
|
NULL,
|
|
&dwType,
|
|
(PBYTE)Buffer,
|
|
&BufferSize) == ERROR_SUCCESS) {
|
|
|
|
AddClassInstallerToList(Buffer);
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
hKey = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
//
|
|
// Class co-installers.
|
|
//
|
|
if (hKeyClassCoInstallers != INVALID_HANDLE_VALUE) {
|
|
if (pSetupStringFromGuid(&(ClassGuidList[CurrentClassGuid]),
|
|
GuidString,
|
|
cA(GuidString)) == ERROR_SUCCESS) {
|
|
BufferSize = 0;
|
|
RegQueryValueEx(hKeyClassCoInstallers,
|
|
GuidString,
|
|
NULL,
|
|
&dwType,
|
|
NULL,
|
|
&BufferSize);
|
|
|
|
if (BufferSize > 0) {
|
|
pItemList = MALLOC(BufferSize + (2 * sizeof(TCHAR)));
|
|
|
|
if (!pItemList) {
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean0;
|
|
}
|
|
|
|
dwType = REG_MULTI_SZ;
|
|
if (RegQueryValueEx(hKeyClassCoInstallers,
|
|
GuidString,
|
|
NULL,
|
|
&dwType,
|
|
(PBYTE)pItemList,
|
|
&BufferSize) == ERROR_SUCCESS) {
|
|
|
|
for (pSingleItem=pItemList;
|
|
*pSingleItem;
|
|
pSingleItem += (lstrlen(pSingleItem) + 1)) {
|
|
|
|
AddClassInstallerToList(pSingleItem);
|
|
}
|
|
}
|
|
|
|
FREE(pItemList);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hKeyClassCoInstallers != INVALID_HANDLE_VALUE) {
|
|
RegCloseKey(hKeyClassCoInstallers);
|
|
hKeyClassCoInstallers = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
FREE(ClassGuidList);
|
|
}
|
|
|
|
CloseServiceHandle(hscManager);
|
|
}
|
|
|
|
clean0:
|
|
if (hscManager) {
|
|
CloseServiceHandle(hscManager);
|
|
}
|
|
|
|
if (pItemList) {
|
|
FREE(pItemList);
|
|
}
|
|
|
|
if (ClassGuidList) {
|
|
FREE(ClassGuidList);
|
|
}
|
|
|
|
if (hDeviceInfo != INVALID_HANDLE_VALUE) {
|
|
SetupDiDestroyDeviceInfoList(hDeviceInfo);
|
|
}
|
|
|
|
if (hKeyClassCoInstallers != INVALID_HANDLE_VALUE) {
|
|
RegCloseKey(hKeyClassCoInstallers);
|
|
hKeyClassCoInstallers = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if (hKey != INVALID_HANDLE_VALUE) {
|
|
RegCloseKey(hKey);
|
|
hKey = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
return Err;
|
|
}
|
|
|
|
DWORD
|
|
BuildPrinterFileList(
|
|
void
|
|
)
|
|
{
|
|
DWORD Err = ERROR_SUCCESS;
|
|
BOOL bRet;
|
|
DWORD dwBytesNeeded = 0;
|
|
DWORD dwDrivers = 0;
|
|
LPBYTE lpBuffer = NULL, lpTemp = NULL;
|
|
LPTSTR lpFileName;
|
|
DRIVER_INFO_3 DriverInfo;
|
|
PDRIVER_INFO_3 lpDriverInfo;
|
|
TCHAR szBuffer[MAX_PATH];
|
|
LPFILENODE lpFileNode = NULL;
|
|
|
|
ZeroMemory(&DriverInfo, sizeof(DRIVER_INFO_3));
|
|
bRet = EnumPrinterDrivers( NULL,
|
|
SIGVERIF_PRINTER_ENV,
|
|
3,
|
|
(LPBYTE) &DriverInfo,
|
|
sizeof(DRIVER_INFO_3),
|
|
&dwBytesNeeded,
|
|
&dwDrivers);
|
|
|
|
if (!bRet && dwBytesNeeded > 0) {
|
|
|
|
lpBuffer = MALLOC(dwBytesNeeded);
|
|
|
|
//
|
|
// If we can't get any memory then just bail out of this function
|
|
//
|
|
if (!lpBuffer) {
|
|
|
|
Err = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto clean0;
|
|
}
|
|
|
|
bRet = EnumPrinterDrivers( NULL,
|
|
SIGVERIF_PRINTER_ENV,
|
|
3,
|
|
(LPBYTE) lpBuffer,
|
|
dwBytesNeeded,
|
|
&dwBytesNeeded,
|
|
&dwDrivers);
|
|
}
|
|
|
|
if (dwDrivers > 0) {
|
|
|
|
//
|
|
// By default, go into the System directory, since Win9x doesn't give full paths to drivers.
|
|
//
|
|
GetSystemDirectory(szBuffer, cA(szBuffer));
|
|
SetCurrentDirectory(szBuffer);
|
|
|
|
for (lpTemp = lpBuffer; dwDrivers > 0; dwDrivers--) {
|
|
|
|
lpDriverInfo = (PDRIVER_INFO_3) lpTemp;
|
|
|
|
if (lpDriverInfo->pName) {
|
|
|
|
if (lpDriverInfo->pDriverPath && *lpDriverInfo->pDriverPath) {
|
|
lpFileNode = AddDriverFileToList(NULL, lpDriverInfo->pDriverPath);
|
|
|
|
if (lpFileNode) {
|
|
lpFileNode->bValidateAgainstAnyOs = TRUE;
|
|
}
|
|
}
|
|
|
|
if (lpDriverInfo->pDataFile && *lpDriverInfo->pDataFile) {
|
|
lpFileNode = AddDriverFileToList(NULL, lpDriverInfo->pDataFile);
|
|
|
|
if (lpFileNode) {
|
|
lpFileNode->bValidateAgainstAnyOs = TRUE;
|
|
}
|
|
}
|
|
|
|
if (lpDriverInfo->pConfigFile && *lpDriverInfo->pConfigFile) {
|
|
lpFileNode = AddDriverFileToList(NULL, lpDriverInfo->pConfigFile);
|
|
|
|
if (lpFileNode) {
|
|
lpFileNode->bValidateAgainstAnyOs = TRUE;
|
|
}
|
|
}
|
|
|
|
if (lpDriverInfo->pHelpFile && *lpDriverInfo->pHelpFile) {
|
|
lpFileNode = AddDriverFileToList(NULL, lpDriverInfo->pHelpFile);
|
|
|
|
if (lpFileNode) {
|
|
lpFileNode->bValidateAgainstAnyOs = TRUE;
|
|
}
|
|
}
|
|
|
|
lpFileName = lpDriverInfo->pDependentFiles;
|
|
|
|
while (lpFileName && *lpFileName) {
|
|
|
|
lpFileNode = AddDriverFileToList(NULL, lpFileName);
|
|
|
|
if (lpFileNode) {
|
|
lpFileNode->bValidateAgainstAnyOs = TRUE;
|
|
}
|
|
|
|
for (;*lpFileName;lpFileName++);
|
|
lpFileName++;
|
|
}
|
|
}
|
|
|
|
lpTemp += sizeof(DRIVER_INFO_3);
|
|
}
|
|
}
|
|
|
|
clean0:
|
|
if (lpBuffer) {
|
|
|
|
FREE(lpBuffer);
|
|
}
|
|
|
|
return Err;
|
|
}
|
|
|
|
DWORD
|
|
BuildCoreFileList(
|
|
void
|
|
)
|
|
{
|
|
DWORD Err = ERROR_SUCCESS;
|
|
PROTECTED_FILE_DATA pfd;
|
|
|
|
pfd.FileNumber = 0;
|
|
|
|
while (SfcGetNextProtectedFile(NULL, &pfd)) {
|
|
|
|
if (g_App.bStopScan) {
|
|
Err = ERROR_CANCELLED;
|
|
break;
|
|
}
|
|
|
|
AddDriverFileToList(NULL, pfd.FileName);
|
|
}
|
|
|
|
//
|
|
// See if SfcGetNextProtectedFile failed from some reason other than
|
|
// ERROR_NO_MORE_FILES.
|
|
//
|
|
if ((Err == ERROR_SUCCESS) &&
|
|
(GetLastError() != ERROR_NO_MORE_FILES)) {
|
|
//
|
|
// SfcGetNextProtectedFile failed before we reached then end of the
|
|
// list of protected file list. This means we won't scan all the
|
|
// protected files, so we should fail up front!
|
|
//
|
|
Err = GetLastError();
|
|
}
|
|
|
|
return Err;
|
|
}
|