diff options
Diffstat (limited to 'installer/installation.c')
-rw-r--r-- | installer/installation.c | 654 |
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 |