520 lines
18 KiB
C
520 lines
18 KiB
C
|
/* SPDX-License-Identifier: GPL-2.0
|
||
|
*
|
||
|
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
|
||
|
*/
|
||
|
|
||
|
#include <Windows.h>
|
||
|
#include <winternl.h>
|
||
|
#include <cfgmgr32.h>
|
||
|
#include <SetupAPI.h>
|
||
|
#include <devguid.h>
|
||
|
#include <ndisguid.h>
|
||
|
#include <Shlwapi.h>
|
||
|
#include <shellapi.h>
|
||
|
#include <wchar.h>
|
||
|
|
||
|
#include "driver.h"
|
||
|
#include "adapter.h"
|
||
|
#include "logger.h"
|
||
|
#include "namespace.h"
|
||
|
#include "resource.h"
|
||
|
#include "registry.h"
|
||
|
#include "ntdll.h"
|
||
|
#include "rundll32.h"
|
||
|
#include "wintun-inf.h"
|
||
|
|
||
|
#pragma warning(disable : 4221) /* nonstandard: address of automatic in initializer */
|
||
|
|
||
|
struct _SP_DEVINFO_DATA_LIST
|
||
|
{
|
||
|
SP_DEVINFO_DATA Data;
|
||
|
struct _SP_DEVINFO_DATA_LIST *Next;
|
||
|
};
|
||
|
|
||
|
static _Return_type_success_(return != FALSE)
|
||
|
BOOL
|
||
|
DisableAllOurAdapters(_In_ HDEVINFO DevInfo, _Inout_ SP_DEVINFO_DATA_LIST **DisabledAdapters)
|
||
|
{
|
||
|
DWORD LastError = ERROR_SUCCESS;
|
||
|
for (DWORD EnumIndex = 0;; ++EnumIndex)
|
||
|
{
|
||
|
SP_DEVINFO_DATA_LIST *DeviceNode = Zalloc(sizeof(*DeviceNode));
|
||
|
if (!DeviceNode)
|
||
|
return FALSE;
|
||
|
DeviceNode->Data.cbSize = sizeof(SP_DEVINFO_DATA);
|
||
|
if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DeviceNode->Data))
|
||
|
{
|
||
|
if (GetLastError() == ERROR_NO_MORE_ITEMS)
|
||
|
{
|
||
|
Free(DeviceNode);
|
||
|
break;
|
||
|
}
|
||
|
goto cleanupDeviceNode;
|
||
|
}
|
||
|
|
||
|
DEVPROPTYPE PropType;
|
||
|
WCHAR Name[MAX_ADAPTER_NAME] = L"<unknown>";
|
||
|
SetupDiGetDevicePropertyW(
|
||
|
DevInfo,
|
||
|
&DeviceNode->Data,
|
||
|
&DEVPKEY_Wintun_Name,
|
||
|
&PropType,
|
||
|
(PBYTE)Name,
|
||
|
MAX_ADAPTER_NAME * sizeof(Name[0]),
|
||
|
NULL,
|
||
|
0);
|
||
|
|
||
|
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 cleanupDeviceNode;
|
||
|
|
||
|
LOG(WINTUN_LOG_INFO, L"Disabling adapter \"%s\"", Name);
|
||
|
if (!AdapterDisableInstance(DevInfo, &DeviceNode->Data))
|
||
|
{
|
||
|
LOG_LAST_ERROR(L"Failed to disable adapter \"%s\"", Name);
|
||
|
LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError();
|
||
|
goto cleanupDeviceNode;
|
||
|
}
|
||
|
|
||
|
DeviceNode->Next = *DisabledAdapters;
|
||
|
*DisabledAdapters = DeviceNode;
|
||
|
continue;
|
||
|
|
||
|
cleanupDeviceNode:
|
||
|
Free(DeviceNode);
|
||
|
}
|
||
|
return RET_ERROR(TRUE, LastError);
|
||
|
}
|
||
|
|
||
|
static _Return_type_success_(return != FALSE)
|
||
|
BOOL
|
||
|
EnableAllOurAdapters(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA_LIST *AdaptersToEnable)
|
||
|
{
|
||
|
DWORD LastError = ERROR_SUCCESS;
|
||
|
for (SP_DEVINFO_DATA_LIST *DeviceNode = AdaptersToEnable; DeviceNode; DeviceNode = DeviceNode->Next)
|
||
|
{
|
||
|
DEVPROPTYPE PropType;
|
||
|
WCHAR Name[MAX_ADAPTER_NAME] = L"<unknown>";
|
||
|
SetupDiGetDevicePropertyW(
|
||
|
DevInfo,
|
||
|
&DeviceNode->Data,
|
||
|
&DEVPKEY_Wintun_Name,
|
||
|
&PropType,
|
||
|
(PBYTE)Name,
|
||
|
MAX_ADAPTER_NAME * sizeof(Name[0]),
|
||
|
NULL,
|
||
|
0);
|
||
|
|
||
|
LOG(WINTUN_LOG_INFO, L"Enabling adapter \"%s\"", Name);
|
||
|
if (!AdapterEnableInstance(DevInfo, &DeviceNode->Data))
|
||
|
{
|
||
|
LOG_LAST_ERROR(L"Failed to enable adapter \"%s\"", Name);
|
||
|
LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError();
|
||
|
}
|
||
|
}
|
||
|
return RET_ERROR(TRUE, LastError);
|
||
|
}
|
||
|
|
||
|
static BOOL
|
||
|
IsNewer(
|
||
|
_In_ const FILETIME *DriverDate1,
|
||
|
_In_ DWORDLONG DriverVersion1,
|
||
|
_In_ const FILETIME *DriverDate2,
|
||
|
_In_ DWORDLONG DriverVersion2)
|
||
|
{
|
||
|
if (DriverDate1->dwHighDateTime > DriverDate2->dwHighDateTime)
|
||
|
return TRUE;
|
||
|
if (DriverDate1->dwHighDateTime < DriverDate2->dwHighDateTime)
|
||
|
return FALSE;
|
||
|
|
||
|
if (DriverDate1->dwLowDateTime > DriverDate2->dwLowDateTime)
|
||
|
return TRUE;
|
||
|
if (DriverDate1->dwLowDateTime < DriverDate2->dwLowDateTime)
|
||
|
return FALSE;
|
||
|
|
||
|
if (DriverVersion1 > DriverVersion2)
|
||
|
return TRUE;
|
||
|
if (DriverVersion1 < DriverVersion2)
|
||
|
return FALSE;
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static _Return_type_success_(return != 0)
|
||
|
DWORD
|
||
|
VersionOfFile(_In_z_ LPCWSTR Filename)
|
||
|
{
|
||
|
DWORD Zero;
|
||
|
DWORD Len = GetFileVersionInfoSizeW(Filename, &Zero);
|
||
|
if (!Len)
|
||
|
{
|
||
|
LOG_LAST_ERROR(L"Failed to query %s version info size", Filename);
|
||
|
return 0;
|
||
|
}
|
||
|
VOID *VersionInfo = Alloc(Len);
|
||
|
if (!VersionInfo)
|
||
|
return 0;
|
||
|
DWORD LastError = ERROR_SUCCESS, Version = 0;
|
||
|
VS_FIXEDFILEINFO *FixedInfo;
|
||
|
UINT FixedInfoLen = sizeof(*FixedInfo);
|
||
|
if (!GetFileVersionInfoW(Filename, 0, Len, VersionInfo))
|
||
|
{
|
||
|
LastError = LOG_LAST_ERROR(L"Failed to get %s version info", Filename);
|
||
|
goto out;
|
||
|
}
|
||
|
if (!VerQueryValueW(VersionInfo, L"\\", &FixedInfo, &FixedInfoLen))
|
||
|
{
|
||
|
LastError = LOG_LAST_ERROR(L"Failed to get %s version info root", Filename);
|
||
|
goto out;
|
||
|
}
|
||
|
Version = FixedInfo->dwFileVersionMS;
|
||
|
if (!Version)
|
||
|
{
|
||
|
LOG(WINTUN_LOG_WARN, L"Determined version of %s, but was v0.0, so returning failure", Filename);
|
||
|
LastError = ERROR_VERSION_PARSE_ERROR;
|
||
|
}
|
||
|
out:
|
||
|
Free(VersionInfo);
|
||
|
return RET_ERROR(Version, LastError);
|
||
|
}
|
||
|
|
||
|
static DWORD WINAPI
|
||
|
MaybeGetRunningDriverVersion(BOOL ReturnOneIfRunningInsteadOfVersion)
|
||
|
{
|
||
|
PRTL_PROCESS_MODULES Modules;
|
||
|
ULONG BufferSize = 128 * 1024;
|
||
|
for (;;)
|
||
|
{
|
||
|
Modules = Alloc(BufferSize);
|
||
|
if (!Modules)
|
||
|
return 0;
|
||
|
NTSTATUS Status = NtQuerySystemInformation(SystemModuleInformation, Modules, BufferSize, &BufferSize);
|
||
|
if (NT_SUCCESS(Status))
|
||
|
break;
|
||
|
Free(Modules);
|
||
|
if (Status == STATUS_INFO_LENGTH_MISMATCH)
|
||
|
continue;
|
||
|
LOG(WINTUN_LOG_ERR, L"Failed to enumerate drivers (status: 0x%x)", Status);
|
||
|
SetLastError(RtlNtStatusToDosError(Status));
|
||
|
return 0;
|
||
|
}
|
||
|
DWORD LastError = ERROR_SUCCESS, Version = 0;
|
||
|
for (ULONG i = Modules->NumberOfModules; i-- > 0;)
|
||
|
{
|
||
|
LPCSTR NtPath = (LPCSTR)Modules->Modules[i].FullPathName;
|
||
|
if (!_stricmp(&NtPath[Modules->Modules[i].OffsetToFileName], "wintun.sys"))
|
||
|
{
|
||
|
if (ReturnOneIfRunningInsteadOfVersion)
|
||
|
{
|
||
|
Version = 1;
|
||
|
goto cleanupModules;
|
||
|
}
|
||
|
WCHAR FilePath[MAX_PATH * 3 + 15];
|
||
|
if (_snwprintf_s(FilePath, _countof(FilePath), _TRUNCATE, L"\\\\?\\GLOBALROOT%S", NtPath) == -1)
|
||
|
continue;
|
||
|
Version = VersionOfFile(FilePath);
|
||
|
if (!Version)
|
||
|
LastError = GetLastError();
|
||
|
goto cleanupModules;
|
||
|
}
|
||
|
}
|
||
|
LastError = ERROR_FILE_NOT_FOUND;
|
||
|
cleanupModules:
|
||
|
Free(Modules);
|
||
|
return RET_ERROR(Version, LastError);
|
||
|
}
|
||
|
|
||
|
_Use_decl_annotations_
|
||
|
DWORD WINAPI WintunGetRunningDriverVersion(VOID)
|
||
|
{
|
||
|
return MaybeGetRunningDriverVersion(FALSE);
|
||
|
}
|
||
|
|
||
|
static BOOL EnsureWintunUnloaded(VOID)
|
||
|
{
|
||
|
BOOL Loaded;
|
||
|
for (DWORD Tries = 0; Tries < 1500; ++Tries)
|
||
|
{
|
||
|
if (Tries)
|
||
|
Sleep(50);
|
||
|
Loaded = MaybeGetRunningDriverVersion(TRUE) != 0;
|
||
|
if (!Loaded)
|
||
|
break;
|
||
|
}
|
||
|
return !Loaded;
|
||
|
}
|
||
|
|
||
|
_Use_decl_annotations_
|
||
|
VOID
|
||
|
DriverInstallDeferredCleanup(HDEVINFO DevInfoExistingAdapters, SP_DEVINFO_DATA_LIST *ExistingAdapters)
|
||
|
{
|
||
|
if (ExistingAdapters)
|
||
|
{
|
||
|
EnableAllOurAdapters(DevInfoExistingAdapters, ExistingAdapters);
|
||
|
while (ExistingAdapters)
|
||
|
{
|
||
|
SP_DEVINFO_DATA_LIST *Next = ExistingAdapters->Next;
|
||
|
Free(ExistingAdapters);
|
||
|
ExistingAdapters = Next;
|
||
|
}
|
||
|
}
|
||
|
if (DevInfoExistingAdapters != INVALID_HANDLE_VALUE)
|
||
|
SetupDiDestroyDeviceInfoList(DevInfoExistingAdapters);
|
||
|
}
|
||
|
|
||
|
_Use_decl_annotations_
|
||
|
BOOL
|
||
|
DriverInstall(HDEVINFO *DevInfoExistingAdaptersForCleanup, SP_DEVINFO_DATA_LIST **ExistingAdaptersForCleanup)
|
||
|
{
|
||
|
static const FILETIME OurDriverDate = WINTUN_INF_FILETIME;
|
||
|
static const DWORDLONG OurDriverVersion = WINTUN_INF_VERSION;
|
||
|
HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex();
|
||
|
if (!DriverInstallationLock)
|
||
|
{
|
||
|
LOG(WINTUN_LOG_ERR, L"Failed to take driver installation mutex");
|
||
|
return FALSE;
|
||
|
}
|
||
|
DWORD LastError = ERROR_SUCCESS;
|
||
|
HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL);
|
||
|
if (DevInfo == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
LastError = LOG_LAST_ERROR(L"Failed to create empty device information set");
|
||
|
goto cleanupDriverInstallationLock;
|
||
|
}
|
||
|
SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
|
||
|
if (!SetupDiCreateDeviceInfoW(DevInfo, WINTUN_HWID, &GUID_DEVCLASS_NET, NULL, NULL, DICD_GENERATE_ID, &DevInfoData))
|
||
|
{
|
||
|
LastError = LOG_LAST_ERROR(L"Failed to create new device information element");
|
||
|
goto cleanupDevInfo;
|
||
|
}
|
||
|
static const WCHAR Hwids[_countof(WINTUN_HWID) + 1 /*Multi-string terminator*/] = WINTUN_HWID;
|
||
|
if (!SetupDiSetDeviceRegistryPropertyW(DevInfo, &DevInfoData, SPDRP_HARDWAREID, (const BYTE *)Hwids, sizeof(Hwids)))
|
||
|
{
|
||
|
LastError = LOG_LAST_ERROR(L"Failed to set adapter hardware ID");
|
||
|
goto cleanupDevInfo;
|
||
|
}
|
||
|
if (!SetupDiBuildDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER))
|
||
|
{
|
||
|
LastError = LOG_LAST_ERROR(L"Failed building adapter driver info list");
|
||
|
goto cleanupDevInfo;
|
||
|
}
|
||
|
FILETIME DriverDate = { 0 };
|
||
|
DWORDLONG DriverVersion = 0;
|
||
|
HDEVINFO DevInfoExistingAdapters = INVALID_HANDLE_VALUE;
|
||
|
SP_DEVINFO_DATA_LIST *ExistingAdapters = NULL;
|
||
|
for (DWORD EnumIndex = 0;; ++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;
|
||
|
}
|
||
|
if (IsNewer(&OurDriverDate, OurDriverVersion, &DrvInfoData.DriverDate, DrvInfoData.DriverVersion))
|
||
|
{
|
||
|
if (DevInfoExistingAdapters == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
DevInfoExistingAdapters = SetupDiGetClassDevsExW(
|
||
|
&GUID_DEVCLASS_NET, WINTUN_ENUMERATOR, NULL, DIGCF_PRESENT, NULL, NULL, NULL);
|
||
|
if (DevInfoExistingAdapters == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
LastError = LOG_LAST_ERROR(L"Failed to get present adapters");
|
||
|
SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER);
|
||
|
goto cleanupExistingAdapters;
|
||
|
}
|
||
|
_Analysis_assume_(DevInfoExistingAdapters != NULL);
|
||
|
DisableAllOurAdapters(DevInfoExistingAdapters, &ExistingAdapters);
|
||
|
LOG(WINTUN_LOG_INFO, L"Waiting for existing driver to unload from kernel");
|
||
|
if (!EnsureWintunUnloaded())
|
||
|
LOG(WINTUN_LOG_WARN,
|
||
|
L"Failed to unload existing driver, which means a reboot will likely be required");
|
||
|
}
|
||
|
LOG(WINTUN_LOG_INFO,
|
||
|
L"Removing existing driver %u.%u",
|
||
|
(DWORD)((DrvInfoData.DriverVersion & 0xffff000000000000) >> 48),
|
||
|
(DWORD)((DrvInfoData.DriverVersion & 0x0000ffff00000000) >> 32));
|
||
|
BYTE LargeBuffer[0x2000];
|
||
|
DWORD Size = sizeof(LargeBuffer);
|
||
|
SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData = (SP_DRVINFO_DETAIL_DATA_W *)LargeBuffer;
|
||
|
DrvInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
|
||
|
if (!SetupDiGetDriverInfoDetailW(DevInfo, &DevInfoData, &DrvInfoData, DrvInfoDetailData, Size, &Size))
|
||
|
{
|
||
|
LOG(WINTUN_LOG_WARN, L"Failed getting adapter driver info detail");
|
||
|
continue;
|
||
|
}
|
||
|
LPWSTR InfFileName = PathFindFileNameW(DrvInfoDetailData->InfFileName);
|
||
|
if (!SetupUninstallOEMInfW(InfFileName, SUOI_FORCEDELETE, NULL))
|
||
|
LOG_LAST_ERROR(L"Unable to remove existing driver %s", InfFileName);
|
||
|
continue;
|
||
|
}
|
||
|
if (!IsNewer(&DrvInfoData.DriverDate, DrvInfoData.DriverVersion, &DriverDate, DriverVersion))
|
||
|
continue;
|
||
|
DriverDate = DrvInfoData.DriverDate;
|
||
|
DriverVersion = DrvInfoData.DriverVersion;
|
||
|
}
|
||
|
SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER);
|
||
|
|
||
|
if (DriverVersion)
|
||
|
{
|
||
|
LOG(WINTUN_LOG_INFO,
|
||
|
L"Using existing driver %u.%u",
|
||
|
(DWORD)((DriverVersion & 0xffff000000000000) >> 48),
|
||
|
(DWORD)((DriverVersion & 0x0000ffff00000000) >> 32));
|
||
|
LastError = ERROR_SUCCESS;
|
||
|
goto cleanupExistingAdapters;
|
||
|
}
|
||
|
|
||
|
LOG(WINTUN_LOG_INFO,
|
||
|
L"Installing driver %u.%u",
|
||
|
(DWORD)((OurDriverVersion & 0xffff000000000000) >> 48),
|
||
|
(DWORD)((OurDriverVersion & 0x0000ffff00000000) >> 32));
|
||
|
WCHAR RandomTempSubDirectory[MAX_PATH];
|
||
|
if (!ResourceCreateTemporaryDirectory(RandomTempSubDirectory))
|
||
|
{
|
||
|
LastError = LOG_LAST_ERROR(L"Failed to create temporary folder %s", RandomTempSubDirectory);
|
||
|
goto cleanupExistingAdapters;
|
||
|
}
|
||
|
|
||
|
WCHAR CatPath[MAX_PATH] = { 0 };
|
||
|
WCHAR SysPath[MAX_PATH] = { 0 };
|
||
|
WCHAR InfPath[MAX_PATH] = { 0 };
|
||
|
if (!PathCombineW(CatPath, RandomTempSubDirectory, L"wintun.cat") ||
|
||
|
!PathCombineW(SysPath, RandomTempSubDirectory, L"wintun.sys") ||
|
||
|
!PathCombineW(InfPath, RandomTempSubDirectory, L"wintun.inf"))
|
||
|
{
|
||
|
LastError = ERROR_BUFFER_OVERFLOW;
|
||
|
goto cleanupDirectory;
|
||
|
}
|
||
|
|
||
|
WCHAR *CatSource, *SysSource, *InfSource;
|
||
|
if (NativeMachine == IMAGE_FILE_PROCESS)
|
||
|
{
|
||
|
CatSource = L"wintun.cat";
|
||
|
SysSource = L"wintun.sys";
|
||
|
InfSource = L"wintun.inf";
|
||
|
}
|
||
|
else if (NativeMachine == IMAGE_FILE_MACHINE_AMD64)
|
||
|
{
|
||
|
CatSource = L"wintun-amd64.cat";
|
||
|
SysSource = L"wintun-amd64.sys";
|
||
|
InfSource = L"wintun-amd64.inf";
|
||
|
}
|
||
|
else if (NativeMachine == IMAGE_FILE_MACHINE_ARM64)
|
||
|
{
|
||
|
CatSource = L"wintun-arm64.cat";
|
||
|
SysSource = L"wintun-arm64.sys";
|
||
|
InfSource = L"wintun-arm64.inf";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LastError = LOG_ERROR(ERROR_NOT_SUPPORTED, L"Unsupported platform 0x%x", NativeMachine);
|
||
|
goto cleanupDirectory;
|
||
|
}
|
||
|
|
||
|
LOG(WINTUN_LOG_INFO, L"Extracting driver");
|
||
|
if (!ResourceCopyToFile(CatPath, CatSource) || !ResourceCopyToFile(SysPath, SysSource) ||
|
||
|
!ResourceCopyToFile(InfPath, InfSource))
|
||
|
{
|
||
|
LastError = LOG_LAST_ERROR(L"Failed to extract driver");
|
||
|
goto cleanupDelete;
|
||
|
}
|
||
|
|
||
|
LOG(WINTUN_LOG_INFO, L"Installing driver");
|
||
|
if (!SetupCopyOEMInfW(InfPath, NULL, SPOST_NONE, 0, NULL, 0, NULL, NULL))
|
||
|
LastError = LOG_LAST_ERROR(L"Could not install driver %s to store", InfPath);
|
||
|
|
||
|
cleanupDelete:
|
||
|
DeleteFileW(CatPath);
|
||
|
DeleteFileW(SysPath);
|
||
|
DeleteFileW(InfPath);
|
||
|
cleanupDirectory:
|
||
|
RemoveDirectoryW(RandomTempSubDirectory);
|
||
|
cleanupExistingAdapters:
|
||
|
if (LastError == ERROR_SUCCESS)
|
||
|
{
|
||
|
*DevInfoExistingAdaptersForCleanup = DevInfoExistingAdapters;
|
||
|
*ExistingAdaptersForCleanup = ExistingAdapters;
|
||
|
}
|
||
|
else
|
||
|
DriverInstallDeferredCleanup(DevInfoExistingAdapters, ExistingAdapters);
|
||
|
cleanupDevInfo:
|
||
|
SetupDiDestroyDeviceInfoList(DevInfo);
|
||
|
cleanupDriverInstallationLock:
|
||
|
NamespaceReleaseMutex(DriverInstallationLock);
|
||
|
return RET_ERROR(TRUE, LastError);
|
||
|
}
|
||
|
|
||
|
_Use_decl_annotations_
|
||
|
BOOL WINAPI WintunDeleteDriver(VOID)
|
||
|
{
|
||
|
DWORD LastError = ERROR_SUCCESS;
|
||
|
|
||
|
AdapterCleanupOrphanedDevices();
|
||
|
|
||
|
HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex();
|
||
|
if (!DriverInstallationLock)
|
||
|
{
|
||
|
LastError = LOG(WINTUN_LOG_ERR, L"Failed to take driver installation mutex");
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL);
|
||
|
if (DevInfo == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
LastError = LOG_LAST_ERROR(L"Failed to create empty device information set");
|
||
|
goto cleanupDriverInstallationLock;
|
||
|
}
|
||
|
SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
|
||
|
if (!SetupDiCreateDeviceInfoW(DevInfo, WINTUN_HWID, &GUID_DEVCLASS_NET, NULL, NULL, DICD_GENERATE_ID, &DevInfoData))
|
||
|
{
|
||
|
LastError = LOG_LAST_ERROR(L"Failed to create new device information element");
|
||
|
goto cleanupDevInfo;
|
||
|
}
|
||
|
static const WCHAR Hwids[_countof(WINTUN_HWID) + 1 /*Multi-string terminator*/] = WINTUN_HWID;
|
||
|
if (!SetupDiSetDeviceRegistryPropertyW(DevInfo, &DevInfoData, SPDRP_HARDWAREID, (const BYTE *)Hwids, sizeof(Hwids)))
|
||
|
{
|
||
|
LastError = LOG_LAST_ERROR(L"Failed to set adapter hardware ID");
|
||
|
goto cleanupDevInfo;
|
||
|
}
|
||
|
if (!SetupDiBuildDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER))
|
||
|
{
|
||
|
LastError = LOG_LAST_ERROR(L"Failed building adapter driver info list");
|
||
|
goto cleanupDevInfo;
|
||
|
}
|
||
|
for (DWORD EnumIndex = 0;; ++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;
|
||
|
}
|
||
|
BYTE LargeBuffer[0x2000];
|
||
|
DWORD Size = sizeof(LargeBuffer);
|
||
|
SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData = (SP_DRVINFO_DETAIL_DATA_W *)LargeBuffer;
|
||
|
DrvInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
|
||
|
if (!SetupDiGetDriverInfoDetailW(DevInfo, &DevInfoData, &DrvInfoData, DrvInfoDetailData, Size, &Size))
|
||
|
{
|
||
|
LOG(WINTUN_LOG_WARN, L"Failed getting adapter driver info detail");
|
||
|
continue;
|
||
|
}
|
||
|
LPCWSTR Path = PathFindFileNameW(DrvInfoDetailData->InfFileName);
|
||
|
LOG(WINTUN_LOG_INFO, L"Removing driver %s", Path);
|
||
|
if (!SetupUninstallOEMInfW(Path, 0, NULL))
|
||
|
{
|
||
|
LOG_LAST_ERROR(L"Unable to remove driver %s", Path);
|
||
|
LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError();
|
||
|
}
|
||
|
}
|
||
|
SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER);
|
||
|
cleanupDevInfo:
|
||
|
SetupDiDestroyDeviceInfoList(DevInfo);
|
||
|
cleanupDriverInstallationLock:
|
||
|
NamespaceReleaseMutex(DriverInstallationLock);
|
||
|
cleanup:
|
||
|
return RET_ERROR(TRUE, LastError);
|
||
|
}
|