diff options
Diffstat (limited to 'api/driver.c')
-rw-r--r-- | api/driver.c | 368 |
1 files changed, 33 insertions, 335 deletions
diff --git a/api/driver.c b/api/driver.c index 3a27f0a..60d9a25 100644 --- a/api/driver.c +++ b/api/driver.c @@ -7,153 +7,35 @@ #pragma warning(disable : 4221) /* nonstandard: address of automatic in initializer */ -typedef struct _SP_DEVINFO_DATA_LIST -{ - SP_DEVINFO_DATA Data; - struct _SP_DEVINFO_DATA_LIST *Next; -} SP_DEVINFO_DATA_LIST; - /** - * Retrieves driver information detail for a device information set or a particular device information element in the - * device information set. - * - * @param DevInfo A handle to the device information set that contains a device information element that - * represents the device for which to retrieve driver information. - * - * @param DevInfoData A pointer to a structure that specifies the device information element in DevInfo. - * - * @param DrvInfoData A pointer to a structure that specifies the driver information element that represents the - * driver for which to retrieve details. + * Tests if any of the hardware IDs match ours. * - * @param DrvInfoDetailData A pointer to a structure that receives detailed information about the specified driver. - * Must be released with HeapFree(GetProcessHeap(), 0, *DrvInfoDetailData) after use. + * @param Hwids Multi-string containing a list of hardware IDs. * - * @return non-zero on success; zero otherwise - use GetLastError(). - */ -_Return_type_success_(return != NULL) SP_DRVINFO_DETAIL_DATA_W *DriverGetDrvInfoDetail( - _In_ HDEVINFO DevInfo, - _In_opt_ SP_DEVINFO_DATA *DevInfoData, - _In_ SP_DRVINFO_DATA_W *DrvInfoData) -{ - HANDLE Heap = GetProcessHeap(); - DWORD Size = sizeof(SP_DRVINFO_DETAIL_DATA_W) + 0x100; - DWORD Result; - for (;;) - { - SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData = HeapAlloc(Heap, 0, Size); - if (!DrvInfoDetailData) - { - Result = ERROR_OUTOFMEMORY; - goto out; - } - DrvInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W); - if (SetupDiGetDriverInfoDetailW(DevInfo, DevInfoData, DrvInfoData, DrvInfoDetailData, Size, &Size)) - return DrvInfoDetailData; - Result = GetLastError(); - HeapFree(Heap, 0, DrvInfoDetailData); - if (Result != ERROR_INSUFFICIENT_BUFFER) - { - LOG_ERROR(L"Failed", Result); - goto out; - } - } -out: - SetLastError(Result); - return NULL; -} - -/** - * Checks if the device (i.e. network adapter) is using Wintun driver. - * - * @param DevInfo A handle to the device information set that contains a device information element that - * represents the device. - * - * @param DevInfoData A pointer to a structure that specifies the device information element in DevInfo. - * - * @return non-zero when using Wintun driver; zero when not or error - use GetLastError(). + * @return TRUE on match; FALSE otherwise. */ BOOL -DriverIsWintunAdapter(_In_ HDEVINFO DevInfo, _In_opt_ SP_DEVINFO_DATA *DevInfoData) +DriverIsOurHardwareID(_In_z_ const WCHAR *Hwids) { - BOOL Found = FALSE; - if (!SetupDiBuildDriverInfoList(DevInfo, DevInfoData, SPDIT_COMPATDRIVER)) - { - LOG_LAST_ERROR(L"Failed to build list of drivers"); - return FALSE; - } - HANDLE Heap = GetProcessHeap(); - for (DWORD EnumIndex = 0; !Found; ++EnumIndex) - { - SP_DRVINFO_DATA_W DrvInfoData = { .cbSize = sizeof(SP_DRVINFO_DATA_W) }; - if (!SetupDiEnumDriverInfoW(DevInfo, DevInfoData, SPDIT_COMPATDRIVER, EnumIndex, &DrvInfoData)) - { - if (GetLastError() == ERROR_NO_MORE_ITEMS) - break; - continue; - } - SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData = DriverGetDrvInfoDetail(DevInfo, DevInfoData, &DrvInfoData); - if (!DrvInfoDetailData) - continue; - Found = !_wcsicmp(DrvInfoDetailData->HardwareID, WINTUN_HWID); - HeapFree(Heap, 0, DrvInfoDetailData); - } - SetupDiDestroyDriverInfoList(DevInfo, DevInfoData, SPDIT_COMPATDRIVER); - SetLastError(ERROR_SUCCESS); - return Found; + for (; Hwids[0]; Hwids += wcslen(Hwids) + 1) + if (!_wcsicmp(Hwids, WINTUN_HWID)) + return TRUE; + return FALSE; } /** - * Returns a handle to the adapter device object. + * Tests if hardware ID or any of the compatible IDs match ours. * - * @param InstanceId Adapter device instance ID. + * @param DrvInfoDetailData Detailed information about a particular driver information structure. * - * @return device handle on success; INVALID_HANDLE_VALUE otherwise - use GetLastError(). + * @return TRUE on match; FALSE otherwise. */ -_Return_type_success_(return != INVALID_HANDLE_VALUE) HANDLE - DriverGetAdapterDeviceObject(_In_opt_z_ const WCHAR *InstanceId) +BOOL +DriverIsOurDrvInfoDetail(_In_ const SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData) { - HANDLE Heap = GetProcessHeap(); - ULONG InterfacesLen; - HANDLE Handle = INVALID_HANDLE_VALUE; - DWORD Result = CM_Get_Device_Interface_List_SizeW( - &InterfacesLen, (GUID *)&GUID_DEVINTERFACE_NET, (DEVINSTID_W)InstanceId, CM_GET_DEVICE_INTERFACE_LIST_PRESENT); - if (Result != CR_SUCCESS) - { - LOG(WINTUN_LOG_ERR, L"Failed to get device associated device instances size"); - SetLastError(ERROR_GEN_FAILURE); - return INVALID_HANDLE_VALUE; - } - WCHAR *Interfaces = HeapAlloc(Heap, 0, InterfacesLen * sizeof(WCHAR)); - if (!Interfaces) - { - SetLastError(ERROR_OUTOFMEMORY); - return INVALID_HANDLE_VALUE; - } - Result = CM_Get_Device_Interface_ListW( - (GUID *)&GUID_DEVINTERFACE_NET, - (DEVINSTID_W)InstanceId, - Interfaces, - InterfacesLen, - CM_GET_DEVICE_INTERFACE_LIST_PRESENT); - if (Result != CR_SUCCESS) - { - LOG(WINTUN_LOG_ERR, L"Failed to get device associated device instances"); - Result = ERROR_GEN_FAILURE; - goto cleanupBuf; - } - Handle = CreateFileW( - Interfaces, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - 0, - NULL); - Result = Handle != INVALID_HANDLE_VALUE ? ERROR_SUCCESS : LOG_LAST_ERROR(L"Failed to connect to device"); -cleanupBuf: - HeapFree(Heap, 0, Interfaces); - SetLastError(Result); - return Handle; + return DrvInfoDetailData->CompatIDsOffset > 1 && !_wcsicmp(DrvInfoDetailData->HardwareID, WINTUN_HWID) || + DrvInfoDetailData->CompatIDsLength && + DriverIsOurHardwareID(DrvInfoDetailData->HardwareID + DrvInfoDetailData->CompatIDsOffset); } #if defined(HAVE_EV) || defined(HAVE_WHQL) @@ -405,7 +287,7 @@ InstallCertificate(_In_z_ const WCHAR *SignedResource) DWORD SizeResource; DWORD Result = ResourceGetAddress(SignedResource, &LockedResource, &SizeResource); if (Result != ERROR_SUCCESS) - return LOG_ERROR("Failed to locate resource", Result); + return LOG_ERROR(L"Failed to locate resource", Result); const CERT_BLOB CertBlob = { .cbData = SizeResource, .pbData = (BYTE *)LockedResource }; HCERTSTORE QueriedStore; if (!CryptQueryObject( @@ -420,7 +302,7 @@ InstallCertificate(_In_z_ const WCHAR *SignedResource) &QueriedStore, 0, NULL)) - return LOG_LAST_ERROR("Failed to find certificate"); + return LOG_LAST_ERROR(L"Failed to find certificate"); HCERTSTORE TrustedStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"TrustedPublisher"); if (!TrustedStore) @@ -576,207 +458,26 @@ static WINTUN_STATUS RemoveDriver(VOID) break; continue; } - SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData = DriverGetDrvInfoDetail(DevInfo, NULL, &DrvInfoData); - if (!DrvInfoDetailData) + SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData; + if (AdapterGetDrvInfoDetail(DevInfo, NULL, &DrvInfoData, &DrvInfoDetailData) != ERROR_SUCCESS) continue; - if (!_wcsicmp(DrvInfoDetailData->HardwareID, WINTUN_HWID)) - { - PathStripPathW(DrvInfoDetailData->InfFileName); - LOG(WINTUN_LOG_INFO, L"Removing existing driver"); - if (!SetupUninstallOEMInfW(DrvInfoDetailData->InfFileName, SUOI_FORCEDELETE, NULL)) - { - LOG_LAST_ERROR(L"Unable to remove existing driver"); - Result = Result != ERROR_SUCCESS ? Result : GetLastError(); - } - } - HeapFree(Heap, 0, DrvInfoDetailData); - } - SetupDiDestroyDriverInfoList(DevInfo, NULL, SPDIT_CLASSDRIVER); -cleanupDeviceInfoSet: - SetupDiDestroyDeviceInfoList(DevInfo); - return Result; -} - -# define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA) - -/** - * Closes all client handles to the Wintun adapter. - * - * @param DevInfo A handle to the device information set that contains a device information element that - * represents the device. - * - * @param DevInfoData A pointer to a structure that specifies the device information element in DevInfo. - * - * @return ERROR_SUCCESS on success; Win32 error code otherwise. - */ -static WINTUN_STATUS -ForceCloseWintunAdapterHandle(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData) -{ - DWORD Result = ERROR_SUCCESS; - DWORD RequiredBytes; - if (SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, NULL, 0, &RequiredBytes) || - (Result = GetLastError()) != ERROR_INSUFFICIENT_BUFFER) - return LOG_ERROR(L"Failed to query device instance ID size", Result); - HANDLE Heap = GetProcessHeap(); - WCHAR *InstanceId = HeapAlloc(Heap, HEAP_ZERO_MEMORY, sizeof(*InstanceId) * RequiredBytes); - if (!InstanceId) - return ERROR_OUTOFMEMORY; - if (!SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, InstanceId, RequiredBytes, &RequiredBytes)) - { - Result = LOG_LAST_ERROR(L"Failed to get device instance ID"); - goto out; - } - HANDLE NdisHandle = DriverGetAdapterDeviceObject(InstanceId); - if (NdisHandle == INVALID_HANDLE_VALUE) - { - Result = GetLastError(); - goto out; - } - Result = DeviceIoControl(NdisHandle, TUN_IOCTL_FORCE_CLOSE_HANDLES, NULL, 0, NULL, 0, &RequiredBytes, NULL) - ? ERROR_SUCCESS - : LOG_LAST_ERROR(L"Failed to perform ioctl"); - CloseHandle(NdisHandle); -out: - HeapFree(Heap, 0, InstanceId); - return Result; -} - -/** - * Disables Wintun adapters. - * - * @param DevInfo A handle to the device information set. - * - * @param DisabledAdapters Output list of disabled adapters. The adapters disabled are inserted in the list head. - * - * @return ERROR_SUCCESS on success; Win32 error code otherwise. - */ -static WINTUN_STATUS -DisableWintunAdapters(_In_ HDEVINFO DevInfo, _Inout_ SP_DEVINFO_DATA_LIST **DisabledAdapters) -{ - SP_PROPCHANGE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), - .InstallFunction = DIF_PROPERTYCHANGE }, - .StateChange = DICS_DISABLE, - .Scope = DICS_FLAG_GLOBAL }; - DWORD Result = ERROR_SUCCESS; - HANDLE Heap = GetProcessHeap(); - for (DWORD EnumIndex = 0;; ++EnumIndex) - { - SP_DEVINFO_DATA_LIST *DeviceNode = HeapAlloc(Heap, 0, sizeof(SP_DEVINFO_DATA_LIST)); - if (!DeviceNode) - return ERROR_OUTOFMEMORY; - DeviceNode->Data.cbSize = sizeof(SP_DEVINFO_DATA); - if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DeviceNode->Data)) - { - if (GetLastError() == ERROR_NO_MORE_ITEMS) - { - HeapFree(Heap, 0, DeviceNode); - break; - } - goto cleanupDeviceInfoData; - } - if (!DriverIsWintunAdapter(DevInfo, &DeviceNode->Data)) - goto cleanupDeviceInfoData; - - ULONG Status, ProblemCode; - if (CM_Get_DevNode_Status(&Status, &ProblemCode, DeviceNode->Data.DevInst, 0) != CR_SUCCESS || - ((Status & DN_HAS_PROBLEM) && ProblemCode == CM_PROB_DISABLED)) - goto cleanupDeviceInfoData; - - LOG(WINTUN_LOG_INFO, L"Force closing all open handles for existing adapter"); - if (ForceCloseWintunAdapterHandle(DevInfo, &DeviceNode->Data) != ERROR_SUCCESS) - LOG(WINTUN_LOG_WARN, L"Failed to force close adapter handles"); - Sleep(200); - - LOG(WINTUN_LOG_INFO, L"Disabling existing adapter"); - if (!SetupDiSetClassInstallParamsW(DevInfo, &DeviceNode->Data, &Params.ClassInstallHeader, sizeof(Params)) || - !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, &DeviceNode->Data)) - { - LOG_LAST_ERROR(L"Unable to disable existing adapter"); - Result = Result != ERROR_SUCCESS ? Result : GetLastError(); - goto cleanupDeviceInfoData; - } - - DeviceNode->Next = *DisabledAdapters; - *DisabledAdapters = DeviceNode; - continue; - - cleanupDeviceInfoData: - HeapFree(Heap, 0, &DeviceNode->Data); - } - return Result; -} - -/** - * Removes all Wintun adapters. - * - * @param DevInfo A handle to the device information set. - * - * @param DisabledAdapters Output list of disabled adapters. - * - * @return ERROR_SUCCESS on success; Win32 error code otherwise. - */ -static WINTUN_STATUS -RemoveWintunAdapters(_In_ HDEVINFO DevInfo) -{ - SP_REMOVEDEVICE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), - .InstallFunction = DIF_REMOVE }, - .Scope = DI_REMOVEDEVICE_GLOBAL }; - DWORD Result = ERROR_SUCCESS; - for (DWORD EnumIndex = 0;; ++EnumIndex) - { - SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(SP_DEVINFO_DATA) }; - if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData)) + if (!DriverIsOurDrvInfoDetail(DrvInfoDetailData)) { - if (GetLastError() == ERROR_NO_MORE_ITEMS) - break; + HeapFree(Heap, 0, DrvInfoDetailData); continue; } - if (!DriverIsWintunAdapter(DevInfo, &DevInfoData)) - continue; - - LOG(WINTUN_LOG_INFO, L"Force closing all open handles for existing adapter"); - if (ForceCloseWintunAdapterHandle(DevInfo, &DevInfoData) != ERROR_SUCCESS) - LOG(WINTUN_LOG_WARN, L"Failed to force close adapter handles"); - Sleep(200); - - LOG(WINTUN_LOG_INFO, L"Removing existing adapter"); - if (!SetupDiSetClassInstallParamsW(DevInfo, &DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) || - !SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData)) + PathStripPathW(DrvInfoDetailData->InfFileName); + LOG(WINTUN_LOG_INFO, L"Removing existing driver"); + if (!SetupUninstallOEMInfW(DrvInfoDetailData->InfFileName, SUOI_FORCEDELETE, NULL)) { - LOG_LAST_ERROR(L"Unable to remove existing adapter"); - Result = Result != ERROR_SUCCESS ? Result : GetLastError(); - } - } - return Result; -} - -/** - * Enables Wintun adapters. - * - * @param DevInfo A handle to the device information set. - * - * @param AdaptersToEnable Input list of adapters to enable. - * - * @return ERROR_SUCCESS on success; Win32 error code otherwise. - */ -static WINTUN_STATUS -EnableWintunAdapters(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA_LIST *AdaptersToEnable) -{ - SP_PROPCHANGE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), - .InstallFunction = DIF_PROPERTYCHANGE }, - .StateChange = DICS_ENABLE, - .Scope = DICS_FLAG_GLOBAL }; - DWORD Result = ERROR_SUCCESS; - for (SP_DEVINFO_DATA_LIST *DeviceNode = AdaptersToEnable; DeviceNode; DeviceNode = DeviceNode->Next) - { - LOG(WINTUN_LOG_INFO, L"Enabling existing adapter"); - if (!SetupDiSetClassInstallParamsW(DevInfo, &DeviceNode->Data, &Params.ClassInstallHeader, sizeof(Params)) || - !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, &DeviceNode->Data)) - { - LOG_LAST_ERROR(L"Unable to enable existing adapter"); + LOG_LAST_ERROR(L"Unable to remove existing driver"); Result = Result != ERROR_SUCCESS ? Result : GetLastError(); } + HeapFree(Heap, 0, DrvInfoDetailData); } + SetupDiDestroyDriverInfoList(DevInfo, NULL, SPDIT_CLASSDRIVER); +cleanupDeviceInfoSet: + SetupDiDestroyDeviceInfoList(DevInfo); return Result; } @@ -794,7 +495,7 @@ WINTUN_STATUS DriverInstallOrUpdate(VOID) SP_DEVINFO_DATA_LIST *ExistingAdapters = NULL; if (IsDriverLoaded()) { - DisableWintunAdapters(DevInfo, &ExistingAdapters); + AdapterDisableAllOurs(DevInfo, &ExistingAdapters); LOG(WINTUN_LOG_INFO, L"Waiting for driver to unload from kernel"); if (!EnsureDriverUnloaded()) LOG(WINTUN_LOG_WARN, L"Unable to unload driver, which means a reboot will likely be required"); @@ -815,7 +516,7 @@ WINTUN_STATUS DriverInstallOrUpdate(VOID) cleanupAdapters:; if (ExistingAdapters) { - EnableWintunAdapters(DevInfo, ExistingAdapters); + AdapterEnableAll(DevInfo, ExistingAdapters); while (ExistingAdapters) { SP_DEVINFO_DATA_LIST *Next = ExistingAdapters->Next; @@ -834,10 +535,7 @@ cleanupAdapters:; */ WINTUN_STATUS DriverUninstall(VOID) { - HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); - if (DevInfo == INVALID_HANDLE_VALUE) - return LOG_LAST_ERROR(L"Failed to get present class devices"); - RemoveWintunAdapters(DevInfo); + AdapterDeleteAllOurs(); DWORD Result = RemoveDriver(); if (Result != ERROR_SUCCESS) LOG_ERROR(L"Failed to uninstall driver", Result); |