aboutsummaryrefslogtreecommitdiffstats
path: root/setupapihost
diff options
context:
space:
mode:
Diffstat (limited to 'setupapihost')
-rw-r--r--setupapihost/host.c184
-rw-r--r--setupapihost/host_win7.h102
-rw-r--r--setupapihost/setupapihost.vcxproj37
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>