diff options
Diffstat (limited to 'setupapihost')
-rw-r--r-- | setupapihost/host.c | 184 | ||||
-rw-r--r-- | setupapihost/host_win7.h | 102 | ||||
-rw-r--r-- | setupapihost/setupapihost.vcxproj | 37 |
3 files changed, 323 insertions, 0 deletions
diff --git a/setupapihost/host.c b/setupapihost/host.c new file mode 100644 index 0000000..e930358 --- /dev/null +++ b/setupapihost/host.c @@ -0,0 +1,184 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved. + */ + +#include <windows.h> +#include <delayimp.h> +#include <setupapi.h> +#include <devguid.h> +#include <shellapi.h> +#include <intsafe.h> +#include <stdlib.h> + +#define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__) + +static FARPROC WINAPI +DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli) +{ + if (dliNotify != dliNotePreLoadLibrary) + return NULL; + HMODULE Library = LoadLibraryExA(pdli->szDll, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (!Library) + abort(); + return (FARPROC)Library; +} + +const PfnDliHook __pfnDliNotifyHook2 = DelayedLoadLibraryHook; + +static DWORD +WriteFormatted(_In_ DWORD StdHandle, _In_z_ LPCWSTR Template, ...) +{ + LPWSTR FormattedMessage = NULL; + DWORD Size; + va_list Arguments; + va_start(Arguments, Template); + DWORD Len = FormatMessageW( + FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, + Template, + 0, + 0, + (VOID *)&FormattedMessage, + 0, + &Arguments); + if (SUCCEEDED(DWordMult(Len, sizeof(*FormattedMessage), &Size))) + WriteFile(GetStdHandle(StdHandle), FormattedMessage, Size, &Size, NULL); + else + Size = 0; + LocalFree(FormattedMessage); + va_end(Arguments); + return Size / sizeof(*FormattedMessage); +} + +VOID __stdcall RemoveInstance(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) +{ +#pragma EXPORT + + DWORD LastError = ERROR_SUCCESS; + int Argc; + LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); + + if (Argc < 3) + goto cleanup; + WCHAR *InstanceId = Argv[2]; + + HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL); + if (DevInfo == INVALID_HANDLE_VALUE) + { + LastError = GetLastError(); + goto cleanup; + } + SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; + if (!SetupDiOpenDeviceInfoW(DevInfo, InstanceId, NULL, DIOD_INHERIT_CLASSDRVS, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + SP_REMOVEDEVICE_PARAMS RemoveDeviceParams = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), + .InstallFunction = DIF_REMOVE }, + .Scope = DI_REMOVEDEVICE_GLOBAL }; + if (!SetupDiSetClassInstallParamsW( + DevInfo, &DevInfoData, &RemoveDeviceParams.ClassInstallHeader, sizeof(RemoveDeviceParams)) || + !SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + +cleanupDevInfo: + SetupDiDestroyDeviceInfoList(DevInfo); +cleanup: + LocalFree(Argv); + + WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X!", LastError); +} + +VOID __stdcall EnableInstance(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) +{ +#pragma EXPORT + + DWORD LastError = ERROR_SUCCESS; + int Argc; + LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); + + if (Argc < 3) + goto cleanup; + WCHAR *InstanceId = Argv[2]; + + HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL); + if (DevInfo == INVALID_HANDLE_VALUE) + { + LastError = GetLastError(); + goto cleanup; + } + SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; + if (!SetupDiOpenDeviceInfoW(DevInfo, InstanceId, NULL, DIOD_INHERIT_CLASSDRVS, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + SP_PROPCHANGE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), + .InstallFunction = DIF_PROPERTYCHANGE }, + .StateChange = DICS_ENABLE, + .Scope = DICS_FLAG_GLOBAL }; + if (!SetupDiSetClassInstallParamsW(DevInfo, &DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) || + !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + +cleanupDevInfo: + SetupDiDestroyDeviceInfoList(DevInfo); +cleanup: + LocalFree(Argv); + + WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X!", LastError); +} + +VOID __stdcall DisableInstance(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) +{ +#pragma EXPORT + + DWORD LastError = ERROR_SUCCESS; + int Argc; + LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); + + if (Argc < 3) + goto cleanup; + WCHAR *InstanceId = Argv[2]; + + HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL); + if (DevInfo == INVALID_HANDLE_VALUE) + { + LastError = GetLastError(); + goto cleanup; + } + SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; + if (!SetupDiOpenDeviceInfoW(DevInfo, InstanceId, NULL, DIOD_INHERIT_CLASSDRVS, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + SP_PROPCHANGE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), + .InstallFunction = DIF_PROPERTYCHANGE }, + .StateChange = DICS_DISABLE, + .Scope = DICS_FLAG_GLOBAL }; + if (!SetupDiSetClassInstallParamsW(DevInfo, &DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) || + !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + +cleanupDevInfo: + SetupDiDestroyDeviceInfoList(DevInfo); +cleanup: + LocalFree(Argv); + + WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X!", LastError); +} + +#if NTDDI_VERSION == NTDDI_WIN7 +#include "host_win7.h" +#endif diff --git a/setupapihost/host_win7.h b/setupapihost/host_win7.h new file mode 100644 index 0000000..4e65bff --- /dev/null +++ b/setupapihost/host_win7.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved. + */ + +#include <devguid.h> + +#define MAX_INSTANCE_ID MAX_PATH /* TODO: Is MAX_PATH always enough? */ +#define WINTUN_HWID L"Wintun" + +VOID __stdcall CreateInstanceWin7(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) +{ +#pragma EXPORT + + DWORD LastError = ERROR_SUCCESS; + WCHAR InstanceId[MAX_INSTANCE_ID] = { 0 }; + + HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL); + if (DevInfo == INVALID_HANDLE_VALUE) + { + LastError = GetLastError(); + goto cleanup; + } + SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; + if (!SetupDiCreateDeviceInfoW( + DevInfo, WINTUN_HWID, &GUID_DEVCLASS_NET, NULL, NULL, DICD_GENERATE_ID, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + SP_DEVINSTALL_PARAMS_W DevInstallParams = { .cbSize = sizeof(DevInstallParams) }; + if (!SetupDiGetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + DevInstallParams.Flags |= DI_QUIETINSTALL; + if (!SetupDiSetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + if (!SetupDiSetSelectedDevice(DevInfo, &DevInfoData)) + { + LastError = GetLastError(); + 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 = GetLastError(); + goto cleanupDevInfo; + } + if (!SetupDiBuildDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + SP_DRVINFO_DATA_W DrvInfoData = { .cbSize = sizeof(SP_DRVINFO_DATA_W) }; + if (!SetupDiEnumDriverInfoW(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER, 0, &DrvInfoData) || + !SetupDiSetSelectedDriverW(DevInfo, &DevInfoData, &DrvInfoData)) + { + LastError = GetLastError(); + goto cleanupDriverInfo; + } + + if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, DevInfo, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS, DevInfo, &DevInfoData); + SetupDiCallClassInstaller(DIF_INSTALLINTERFACES, DevInfo, &DevInfoData); + if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICE, DevInfo, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevice; + } + DWORD RequiredChars = _countof(InstanceId); + if (!SetupDiGetDeviceInstanceIdW(DevInfo, &DevInfoData, InstanceId, RequiredChars, &RequiredChars)) + { + LastError = GetLastError(); + goto cleanupDevice; + } + +cleanupDevice: + if (LastError != ERROR_SUCCESS) + { + SP_REMOVEDEVICE_PARAMS RemoveDeviceParams = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), + .InstallFunction = DIF_REMOVE }, + .Scope = DI_REMOVEDEVICE_GLOBAL }; + if (SetupDiSetClassInstallParamsW( + DevInfo, &DevInfoData, &RemoveDeviceParams.ClassInstallHeader, sizeof(RemoveDeviceParams))) + SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData); + } +cleanupDriverInfo: + SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER); +cleanupDevInfo: + SetupDiDestroyDeviceInfoList(DevInfo); +cleanup: + WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!s!", LastError, LastError == ERROR_SUCCESS ? InstanceId : L"\"\""); +} diff --git a/setupapihost/setupapihost.vcxproj b/setupapihost/setupapihost.vcxproj new file mode 100644 index 0000000..147c429 --- /dev/null +++ b/setupapihost/setupapihost.vcxproj @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup Label="Globals"> + <ProjectGuid>{9911D673-CF5F-4B41-B190-807AA1BE445B}</ProjectGuid> + <RootNamespace>setupapihost</RootNamespace> + <ProjectName>setupapihost</ProjectName> + </PropertyGroup> + <PropertyGroup Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + </PropertyGroup> + <Import Project="..\wintun.props" /> + <PropertyGroup> + <TargetName>setupapihost</TargetName> + </PropertyGroup> + <ItemDefinitionGroup> + <ClCompile> + <PreprocessorDefinitions>_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <AdditionalOptions>/volatile:iso %(AdditionalOptions)</AdditionalOptions> + <DisableSpecificWarnings>4100;4201;$(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <Link> + <DelayLoadDLLs>setupapi.dll;shell32.dll</DelayLoadDLLs> + <AdditionalDependencies>Setupapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <SubSystem>Windows</SubSystem> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="host.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="host_win7.h" /> + </ItemGroup> + <Import Project="..\wintun.props.user" Condition="exists('..\wintun.props.user')" /> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets" /> +</Project> |