aboutsummaryrefslogtreecommitdiffstats
path: root/installer/installation.c
diff options
context:
space:
mode:
Diffstat (limited to 'installer/installation.c')
-rw-r--r--installer/installation.c654
1 files changed, 654 insertions, 0 deletions
diff --git a/installer/installation.c b/installer/installation.c
new file mode 100644
index 0000000..b0644a4
--- /dev/null
+++ b/installer/installation.c
@@ -0,0 +1,654 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2019 WireGuard LLC. All Rights Reserved.
+ */
+
+#include "installation.h"
+#include <Windows.h>
+#include <NTSecAPI.h>
+#include <SetupAPI.h>
+#include <newdev.h>
+#include <Shlwapi.h>
+#include <Psapi.h>
+#include <sddl.h>
+#include <devguid.h>
+#include <ndisguid.h>
+#include <cfgmgr32.h>
+#include <WinCrypt.h>
+#include <tchar.h>
+#include <stdio.h>
+
+#pragma warning(disable : 4100) /* unreferenced formal parameter */
+#pragma warning(disable : 4204) /* nonstandard: non-constant aggregate initializer */
+#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;
+
+static VOID
+NopLogger(_In_ LOGGER_LEVEL Level, _In_ const TCHAR *LogLine)
+{
+}
+
+static LoggerFunction Logger = NopLogger;
+
+VOID
+SetLogger(_In_ LoggerFunction NewLogger)
+{
+ Logger = NewLogger;
+}
+
+static VOID
+PrintError(_In_ LOGGER_LEVEL Level, _In_ const TCHAR *Prefix)
+{
+ DWORD ErrorCode = GetLastError();
+ TCHAR *SystemMessage = NULL, *FormattedMessage = NULL;
+ FormatMessage(
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ NULL,
+ HRESULT_FROM_SETUPAPI(ErrorCode),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (VOID *)&SystemMessage,
+ 0,
+ NULL);
+ FormatMessage(
+ FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY |
+ FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ SystemMessage ? TEXT("%1: %3(Code 0x%2!08X!)") : TEXT("%1: Code 0x%2!08X!"),
+ 0,
+ 0,
+ (VOID *)&FormattedMessage,
+ 0,
+ (va_list *)(DWORD_PTR[]){ (DWORD_PTR)Prefix, (DWORD_PTR)ErrorCode, (DWORD_PTR)SystemMessage });
+ if (FormattedMessage)
+ Logger(Level, FormattedMessage);
+ LocalFree(FormattedMessage);
+ LocalFree(SystemMessage);
+}
+
+HINSTANCE ResourceModule;
+
+static BOOL IsWintunLoaded(VOID)
+{
+ DWORD RequiredSize = 0, CurrentSize = 0;
+ VOID **Drivers = NULL;
+ BOOL Found = FALSE;
+ for (;;)
+ {
+ if (!EnumDeviceDrivers(Drivers, CurrentSize, &RequiredSize))
+ goto out;
+ if (CurrentSize == RequiredSize)
+ break;
+ free(Drivers);
+ Drivers = malloc(RequiredSize);
+ if (!Drivers)
+ goto out;
+ CurrentSize = RequiredSize;
+ }
+ TCHAR MaybeWintun[11];
+ for (DWORD i = CurrentSize / sizeof(Drivers[0]); i-- > 0;)
+ {
+ if (GetDeviceDriverBaseName(Drivers[i], MaybeWintun, _countof(MaybeWintun)) == 10 &&
+ !_tcsicmp(MaybeWintun, TEXT("wintun.sys")))
+ {
+ Found = TRUE;
+ goto out;
+ }
+ }
+out:
+ free(Drivers);
+ return Found;
+}
+
+static BOOL EnsureWintunUnloaded(VOID)
+{
+ BOOL Loaded;
+ for (int i = 0; (Loaded = IsWintunLoaded()) != 0 && i < 300; ++i)
+ Sleep(50);
+ return !Loaded;
+}
+
+static BOOL
+CopyResource(
+ _In_ const TCHAR *DestinationPath,
+ _In_opt_ SECURITY_ATTRIBUTES *SecurityAttributes,
+ _In_ const TCHAR *ResourceName)
+{
+ HRSRC FoundResource = FindResource(ResourceModule, ResourceName, RT_RCDATA);
+ if (!FoundResource)
+ return FALSE;
+ DWORD SizeResource = SizeofResource(ResourceModule, FoundResource);
+ if (!SizeResource)
+ return FALSE;
+ HGLOBAL LoadedResource = LoadResource(ResourceModule, FoundResource);
+ if (!LoadedResource)
+ return FALSE;
+ LPVOID LockedResource = LockResource(LoadedResource);
+ if (!LockedResource)
+ return FALSE;
+ HANDLE DestinationHandle = CreateFile(
+ DestinationPath,
+ GENERIC_WRITE,
+ 0,
+ SecurityAttributes,
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_TEMPORARY,
+ NULL);
+ if (DestinationHandle == INVALID_HANDLE_VALUE)
+ return FALSE;
+ DWORD BytesWritten;
+ BOOL Ret =
+ WriteFile(DestinationHandle, LockedResource, SizeResource, &BytesWritten, NULL) && BytesWritten == SizeResource;
+ CloseHandle(DestinationHandle);
+ return Ret;
+}
+
+static BOOL
+InstallWintunCertificate(const TCHAR *SignedResource)
+{
+ DWORD LastError = ERROR_SUCCESS;
+ Logger(LOG_INFO, TEXT("Trusting code signing certificate"));
+ BOOL Ret = TRUE;
+ HRSRC FoundResource = FindResource(ResourceModule, SignedResource, RT_RCDATA);
+ if (!FoundResource)
+ return FALSE;
+ DWORD SizeResource = SizeofResource(ResourceModule, FoundResource);
+ if (!SizeResource)
+ return FALSE;
+ HGLOBAL LoadedResource = LoadResource(ResourceModule, FoundResource);
+ if (!LoadedResource)
+ return FALSE;
+ LPVOID LockedResource = LockResource(LoadedResource);
+ if (!LockedResource)
+ return FALSE;
+ const CERT_BLOB CertBlob = { .cbData = SizeResource, .pbData = LockedResource };
+ HCERTSTORE QueriedStore;
+ if (!CryptQueryObject(
+ CERT_QUERY_OBJECT_BLOB,
+ &CertBlob,
+ CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
+ CERT_QUERY_FORMAT_FLAG_ALL,
+ 0,
+ 0,
+ 0,
+ 0,
+ &QueriedStore,
+ 0,
+ NULL))
+ return FALSE;
+ HCERTSTORE TrustedStore =
+ CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, TEXT("TrustedPublisher"));
+ if (!TrustedStore)
+ {
+ LastError = GetLastError();
+ goto cleanupQueriedStore;
+ }
+ LPSTR CodeSigningOid[] = { szOID_PKIX_KP_CODE_SIGNING };
+ CERT_ENHKEY_USAGE EnhancedUsage = { .cUsageIdentifier = 1, .rgpszUsageIdentifier = CodeSigningOid };
+ for (const CERT_CONTEXT *CertContext = NULL; (CertContext = CertFindCertificateInStore(
+ QueriedStore,
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
+ CERT_FIND_ENHKEY_USAGE,
+ &EnhancedUsage,
+ CertContext)) != NULL;)
+ {
+ CERT_EXTENSION *Ext = CertFindExtension(
+ szOID_BASIC_CONSTRAINTS2, CertContext->pCertInfo->cExtension, CertContext->pCertInfo->rgExtension);
+ CERT_BASIC_CONSTRAINTS2_INFO Constraints;
+ DWORD Size = sizeof(Constraints);
+ if (Ext &&
+ CryptDecodeObjectEx(
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ szOID_BASIC_CONSTRAINTS2,
+ Ext->Value.pbData,
+ Ext->Value.cbData,
+ 0,
+ NULL,
+ &Constraints,
+ &Size) &&
+ !Constraints.fCA)
+ Ret &= CertAddCertificateContextToStore(TrustedStore, CertContext, CERT_STORE_ADD_REPLACE_EXISTING, NULL);
+ if (!Ret)
+ LastError = LastError ? LastError : GetLastError();
+ }
+ CertCloseStore(TrustedStore, 0);
+cleanupQueriedStore:
+ CertCloseStore(QueriedStore, 0);
+ SetLastError(LastError);
+ return Ret;
+}
+
+/* We can't use RtlGetVersion, because appcompat's aclayers.dll shims it to report Vista
+ * when run from MSI context. So, we instead use the undocumented RtlGetNtVersionNumbers.
+ *
+ * Another way would be reading from the PEB directly:
+ * ((DWORD *)NtCurrentTeb()->ProcessEnvironmentBlock)[sizeof(void *) == 8 ? 70 : 41]
+ * Or just read from KUSER_SHARED_DATA the same way on 32-bit and 64-bit:
+ * *(DWORD *)0x7FFE026C
+ */
+extern VOID NTAPI
+RtlGetNtVersionNumbers(_Out_opt_ DWORD *MajorVersion, _Out_opt_ DWORD *MinorVersion, _Out_opt_ DWORD *BuildNumber);
+
+static BOOL
+InstallWintun(BOOL UpdateExisting)
+{
+ DWORD LastError = ERROR_SUCCESS;
+ TCHAR WindowsDirectory[MAX_PATH];
+ if (!GetWindowsDirectory(WindowsDirectory, _countof(WindowsDirectory)))
+ return FALSE;
+ TCHAR WindowsTempDirectory[MAX_PATH];
+ if (!PathCombine(WindowsTempDirectory, WindowsDirectory, TEXT("Temp")))
+ return FALSE;
+ UCHAR RandomBytes[32] = { 0 };
+#pragma warning(suppress : 6387)
+ if (!RtlGenRandom(RandomBytes, sizeof(RandomBytes)))
+ return FALSE;
+ TCHAR RandomSubDirectory[sizeof(RandomBytes) * 2 + 1];
+ for (int i = 0; i < sizeof(RandomBytes); ++i)
+ _stprintf_s(&RandomSubDirectory[i * 2], 3, TEXT("%02x"), RandomBytes[i]);
+ TCHAR RandomTempSubDirectory[MAX_PATH];
+ if (!PathCombine(RandomTempSubDirectory, WindowsTempDirectory, RandomSubDirectory))
+ return FALSE;
+ SECURITY_ATTRIBUTES SecurityAttributes = { .nLength = sizeof(SecurityAttributes) };
+ if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
+ TEXT("O:SYD:P(A;;GA;;;SY)"), SDDL_REVISION_1, &SecurityAttributes.lpSecurityDescriptor, NULL))
+ return FALSE;
+ BOOL Ret = CreateDirectory(RandomTempSubDirectory, &SecurityAttributes);
+ if (!Ret)
+ goto cleanupFree;
+
+ TCHAR CatPath[MAX_PATH] = { 0 };
+ if (!PathCombine(CatPath, RandomTempSubDirectory, TEXT("wintun.cat")))
+ goto cleanupFree;
+ TCHAR SysPath[MAX_PATH] = { 0 };
+ if (!PathCombine(SysPath, RandomTempSubDirectory, TEXT("wintun.sys")))
+ goto cleanupFree;
+ TCHAR InfPath[MAX_PATH] = { 0 };
+ if (!PathCombine(InfPath, RandomTempSubDirectory, TEXT("wintun.inf")))
+ goto cleanupFree;
+
+ BOOL UseWHQL = FALSE;
+#ifdef HAVE_WHQL
+ DWORD MajorVersion;
+ RtlGetNtVersionNumbers(&MajorVersion, NULL, NULL);
+ UseWHQL = MajorVersion >= 10;
+#endif
+ if (!UseWHQL && !InstallWintunCertificate(TEXT("wintun.sys")))
+ PrintError(LOG_WARN, TEXT("Unable to install code signing certificate"));
+
+ Logger(LOG_INFO, TEXT("Copying resources to temporary path"));
+ Ret = CopyResource(CatPath, &SecurityAttributes, UseWHQL ? TEXT("wintun-whql.cat") : TEXT("wintun.cat")) &&
+ CopyResource(SysPath, &SecurityAttributes, UseWHQL ? TEXT("wintun-whql.sys") : TEXT("wintun.sys")) &&
+ CopyResource(InfPath, &SecurityAttributes, UseWHQL ? TEXT("wintun-whql.inf") : TEXT("wintun.inf"));
+ if (!Ret)
+ goto cleanupDelete;
+
+ Logger(LOG_INFO, TEXT("Installing driver"));
+ Ret = SetupCopyOEMInf(InfPath, NULL, SPOST_PATH, 0, NULL, 0, NULL, NULL);
+ BOOL RebootRequired = FALSE;
+ if (UpdateExisting &&
+ !UpdateDriverForPlugAndPlayDevices(
+ NULL, TEXT("Wintun"), InfPath, INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE, &RebootRequired))
+ PrintError(LOG_WARN, TEXT("Could not update existing adapters"));
+ if (RebootRequired)
+ Logger(LOG_WARN, TEXT("A reboot might be required, which really should not be the case"));
+
+cleanupDelete:
+ LastError = LastError ? LastError : GetLastError();
+ DeleteFile(CatPath);
+ DeleteFile(SysPath);
+ DeleteFile(InfPath);
+ RemoveDirectory(RandomTempSubDirectory);
+cleanupFree:
+ LastError = LastError ? LastError : GetLastError();
+ LocalFree(SecurityAttributes.lpSecurityDescriptor);
+ SetLastError(LastError);
+ return Ret;
+}
+
+static BOOL RemoveWintun(VOID)
+{
+ BOOL Ret = FALSE;
+ HDEVINFO DeviceInfoSet = SetupDiGetClassDevs(&GUID_DEVCLASS_NET, NULL, NULL, 0);
+ if (!DeviceInfoSet)
+ return FALSE;
+ if (!SetupDiBuildDriverInfoList(DeviceInfoSet, NULL, SPDIT_CLASSDRIVER))
+ goto cleanupDeviceInfoSet;
+ Ret = TRUE;
+ for (DWORD EnumIndex = 0;; ++EnumIndex)
+ {
+ SP_DRVINFO_DATA DriverInfo = { .cbSize = sizeof(DriverInfo) };
+ if (!SetupDiEnumDriverInfo(DeviceInfoSet, NULL, SPDIT_CLASSDRIVER, EnumIndex, &DriverInfo))
+ {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ break;
+ goto cleanupDriverInfoList;
+ }
+ DWORD RequiredSize;
+ if (SetupDiGetDriverInfoDetail(DeviceInfoSet, NULL, &DriverInfo, NULL, 0, &RequiredSize) ||
+ GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ goto cleanupDriverInfoList;
+ PSP_DRVINFO_DETAIL_DATA DriverDetail = calloc(1, RequiredSize);
+ if (!DriverDetail)
+ goto cleanupDriverInfoList;
+ DriverDetail->cbSize = sizeof(*DriverDetail);
+ if (!SetupDiGetDriverInfoDetail(DeviceInfoSet, NULL, &DriverInfo, DriverDetail, RequiredSize, &RequiredSize))
+ {
+ free(DriverDetail);
+ goto cleanupDriverInfoList;
+ }
+ if (!_tcsicmp(DriverDetail->HardwareID, TEXT("wintun")))
+ {
+ PathStripPath(DriverDetail->InfFileName);
+ Logger(LOG_INFO, TEXT("Removing existing driver"));
+ if (!SetupUninstallOEMInf(DriverDetail->InfFileName, SUOI_FORCEDELETE, NULL))
+ {
+ PrintError(LOG_ERR, TEXT("Unable to remove existing driver"));
+ Ret = FALSE;
+ }
+ }
+ free(DriverDetail);
+ }
+
+cleanupDriverInfoList:
+ SetupDiDestroyDriverInfoList(DeviceInfoSet, NULL, SPDIT_CLASSDRIVER);
+cleanupDeviceInfoSet:
+ SetupDiDestroyDeviceInfoList(DeviceInfoSet);
+ return Ret;
+}
+
+static BOOL
+IsWintunAdapter(_In_ HDEVINFO DeviceInfoSet, _Inout_ SP_DEVINFO_DATA *DeviceInfo)
+{
+ BOOL Found = FALSE;
+ if (!SetupDiBuildDriverInfoList(DeviceInfoSet, DeviceInfo, SPDIT_COMPATDRIVER))
+ return FALSE;
+ for (DWORD EnumIndex = 0;; ++EnumIndex)
+ {
+ SP_DRVINFO_DATA DriverInfo = { .cbSize = sizeof(SP_DRVINFO_DATA) };
+ if (!SetupDiEnumDriverInfo(DeviceInfoSet, DeviceInfo, SPDIT_COMPATDRIVER, EnumIndex, &DriverInfo))
+ {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ break;
+ continue;
+ }
+ DWORD RequiredSize;
+ if (SetupDiGetDriverInfoDetail(DeviceInfoSet, DeviceInfo, &DriverInfo, NULL, 0, &RequiredSize) ||
+ GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ continue;
+ PSP_DRVINFO_DETAIL_DATA DriverDetail = calloc(1, RequiredSize);
+ if (!DriverDetail)
+ continue;
+ DriverDetail->cbSize = sizeof(*DriverDetail);
+ if (SetupDiGetDriverInfoDetail(
+ DeviceInfoSet, DeviceInfo, &DriverInfo, DriverDetail, RequiredSize, &RequiredSize) &&
+ !_tcsicmp(DriverDetail->HardwareID, TEXT("wintun")))
+ {
+ free(DriverDetail);
+ Found = TRUE;
+ break;
+ }
+ free(DriverDetail);
+ }
+ SetupDiDestroyDriverInfoList(DeviceInfoSet, DeviceInfo, SPDIT_COMPATDRIVER);
+ return Found;
+}
+
+#define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA)
+
+static BOOL
+ForceCloseWintunAdapterHandle(_In_ HDEVINFO DeviceInfoSet, _In_ SP_DEVINFO_DATA *DeviceInfo)
+{
+ DWORD RequiredBytes;
+ if (SetupDiGetDeviceInstanceId(DeviceInfoSet, DeviceInfo, NULL, 0, &RequiredBytes) ||
+ GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ return FALSE;
+ TCHAR *InstanceId = calloc(sizeof(*InstanceId), RequiredBytes);
+ if (!InstanceId)
+ return FALSE;
+ if (!SetupDiGetDeviceInstanceId(DeviceInfoSet, DeviceInfo, InstanceId, RequiredBytes, &RequiredBytes))
+ return FALSE;
+ TCHAR *InterfaceList = NULL;
+ for (;;)
+ {
+ free(InterfaceList);
+ if (CM_Get_Device_Interface_List_Size(
+ &RequiredBytes, (LPGUID)&GUID_DEVINTERFACE_NET, InstanceId, CM_GET_DEVICE_INTERFACE_LIST_PRESENT) !=
+ CR_SUCCESS)
+ return FALSE;
+ InterfaceList = calloc(sizeof(*InterfaceList), RequiredBytes);
+ if (!InterfaceList)
+ return FALSE;
+ CONFIGRET Ret = CM_Get_Device_Interface_List(
+ (LPGUID)&GUID_DEVINTERFACE_NET,
+ InstanceId,
+ InterfaceList,
+ RequiredBytes,
+ CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
+ if (Ret == CR_SUCCESS)
+ break;
+ if (Ret != CR_BUFFER_SMALL)
+ return FALSE;
+ }
+
+ HANDLE NdisHandle = CreateFile(
+ InterfaceList,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+ free(InterfaceList);
+ if (NdisHandle == INVALID_HANDLE_VALUE)
+ return FALSE;
+ BOOL Ret = DeviceIoControl(NdisHandle, TUN_IOCTL_FORCE_CLOSE_HANDLES, NULL, 0, NULL, 0, &RequiredBytes, NULL);
+ DWORD LastError = GetLastError();
+ CloseHandle(NdisHandle);
+ SetLastError(LastError);
+ return Ret;
+}
+
+static BOOL
+DisableWintunAdapters(_In_ HDEVINFO DeviceInfoSet, _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 };
+ BOOL Ret = TRUE;
+ DWORD LastError = ERROR_SUCCESS;
+ for (DWORD EnumIndex = 0;; ++EnumIndex)
+ {
+ SP_DEVINFO_DATA_LIST *DeviceNode = malloc(sizeof(SP_DEVINFO_DATA_LIST));
+ if (!DeviceNode)
+ return FALSE;
+ DeviceNode->Data.cbSize = sizeof(SP_DEVINFO_DATA);
+ if (!SetupDiEnumDeviceInfo(DeviceInfoSet, EnumIndex, &DeviceNode->Data))
+ {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ {
+ free(DeviceNode);
+ break;
+ }
+ goto cleanupDeviceInfoData;
+ }
+ if (!IsWintunAdapter(DeviceInfoSet, &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;
+
+ Logger(LOG_INFO, TEXT("Force closing all open handles for existing adapter"));
+ if (!ForceCloseWintunAdapterHandle(DeviceInfoSet, &DeviceNode->Data))
+ PrintError(LOG_WARN, TEXT("Failed to force close adapter handles"));
+ Sleep(200);
+
+ Logger(LOG_INFO, TEXT("Disabling existing adapter"));
+ if (!SetupDiSetClassInstallParams(
+ DeviceInfoSet, &DeviceNode->Data, &Params.ClassInstallHeader, sizeof(Params)) ||
+ !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DeviceInfoSet, &DeviceNode->Data))
+ {
+ PrintError(LOG_WARN, TEXT("Unable to disable existing adapter"));
+ LastError = LastError ? LastError : GetLastError();
+ Ret = FALSE;
+ goto cleanupDeviceInfoData;
+ }
+
+ DeviceNode->Next = *DisabledAdapters;
+ *DisabledAdapters = DeviceNode;
+ continue;
+
+ cleanupDeviceInfoData:
+ free(&DeviceNode->Data);
+ }
+ SetLastError(LastError);
+ return Ret;
+}
+
+static BOOL
+RemoveWintunAdapters(_In_ HDEVINFO DeviceInfoSet)
+{
+ SP_REMOVEDEVICE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
+ .InstallFunction = DIF_REMOVE },
+ .Scope = DI_REMOVEDEVICE_GLOBAL };
+ BOOL Ret = TRUE;
+ DWORD LastError = ERROR_SUCCESS;
+ for (DWORD EnumIndex = 0;; ++EnumIndex)
+ {
+ SP_DEVINFO_DATA DeviceInfo = { .cbSize = sizeof(SP_DEVINFO_DATA) };
+ if (!SetupDiEnumDeviceInfo(DeviceInfoSet, EnumIndex, &DeviceInfo))
+ {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ break;
+ continue;
+ }
+ if (!IsWintunAdapter(DeviceInfoSet, &DeviceInfo))
+ continue;
+
+ Logger(LOG_INFO, TEXT("Force closing all open handles for existing adapter"));
+ if (!ForceCloseWintunAdapterHandle(DeviceInfoSet, &DeviceInfo))
+ PrintError(LOG_WARN, TEXT("Failed to force close adapter handles"));
+ Sleep(200);
+
+ Logger(LOG_INFO, TEXT("Removing existing adapter"));
+ if (!SetupDiSetClassInstallParams(DeviceInfoSet, &DeviceInfo, &Params.ClassInstallHeader, sizeof(Params)) ||
+ !SetupDiCallClassInstaller(DIF_REMOVE, DeviceInfoSet, &DeviceInfo))
+ {
+ PrintError(LOG_WARN, TEXT("Unable to remove existing adapter"));
+ LastError = LastError ? LastError : GetLastError();
+ Ret = FALSE;
+ }
+ }
+ SetLastError(LastError);
+ return Ret;
+}
+
+static BOOL
+EnableWintunAdapters(_In_ HDEVINFO DeviceInfoSet, _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 };
+ BOOL Ret = TRUE;
+ DWORD LastError = ERROR_SUCCESS;
+
+ for (SP_DEVINFO_DATA_LIST *DeviceNode = AdaptersToEnable; DeviceNode; DeviceNode = DeviceNode->Next)
+ {
+ Logger(LOG_INFO, TEXT("Enabling existing adapter"));
+ if (!SetupDiSetClassInstallParams(
+ DeviceInfoSet, &DeviceNode->Data, &Params.ClassInstallHeader, sizeof(Params)) ||
+ !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DeviceInfoSet, &DeviceNode->Data))
+ {
+ LastError = LastError ? LastError : GetLastError();
+ PrintError(LOG_WARN, TEXT("Unable to enable existing adapter"));
+ Ret = FALSE;
+ }
+ }
+ SetLastError(LastError);
+ return Ret;
+}
+
+BOOL InstallOrUpdate(VOID)
+{
+ BOOL Ret = FALSE;
+ HDEVINFO DeviceInfoSet = SetupDiGetClassDevsEx(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL);
+ if (DeviceInfoSet == INVALID_HANDLE_VALUE)
+ {
+ PrintError(LOG_ERR, TEXT("Failed to get present class devices"));
+ return FALSE;
+ }
+ SP_DEVINFO_DATA_LIST *ExistingAdapters = NULL;
+ if (IsWintunLoaded())
+ {
+ DisableWintunAdapters(DeviceInfoSet, &ExistingAdapters);
+ Logger(LOG_INFO, TEXT("Waiting for driver to unload from kernel"));
+ if (!EnsureWintunUnloaded())
+ Logger(LOG_WARN, TEXT("Unable to unload driver, which means a reboot will likely be required"));
+ }
+ if (!RemoveWintun())
+ {
+ PrintError(LOG_ERR, TEXT("Failed to uninstall old drivers"));
+ goto cleanupAdapters;
+ }
+ if (!InstallWintun(!!ExistingAdapters))
+ {
+ PrintError(LOG_ERR, TEXT("Failed to install driver"));
+ goto cleanupAdapters;
+ }
+ Logger(LOG_INFO, TEXT("Installation successful"));
+ Ret = TRUE;
+
+cleanupAdapters:
+ if (ExistingAdapters)
+ {
+ EnableWintunAdapters(DeviceInfoSet, ExistingAdapters);
+ while (ExistingAdapters)
+ {
+ SP_DEVINFO_DATA_LIST *Next = ExistingAdapters->Next;
+ free(ExistingAdapters);
+ ExistingAdapters = Next;
+ }
+ }
+ SetupDiDestroyDeviceInfoList(DeviceInfoSet);
+ return Ret;
+}
+
+BOOL Uninstall(VOID)
+{
+ HDEVINFO DeviceInfoSet = SetupDiGetClassDevsEx(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL);
+ if (DeviceInfoSet == INVALID_HANDLE_VALUE)
+ {
+ PrintError(LOG_ERR, TEXT("Failed to get present class devices"));
+ return FALSE;
+ }
+ RemoveWintunAdapters(DeviceInfoSet);
+ BOOL Ret = RemoveWintun();
+ if (!Ret)
+ PrintError(LOG_ERR, TEXT("Failed to uninstall driver"));
+ else
+ Logger(LOG_INFO, TEXT("Uninstallation successful"));
+ return Ret;
+}
+
+BOOL APIENTRY
+DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved)
+{
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ ResourceModule = hinstDLL;
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+} \ No newline at end of file