diff options
Diffstat (limited to 'api/adapter_win7.h')
-rw-r--r-- | api/adapter_win7.h | 351 |
1 files changed, 351 insertions, 0 deletions
diff --git a/api/adapter_win7.h b/api/adapter_win7.h new file mode 100644 index 0000000..affbd09 --- /dev/null +++ b/api/adapter_win7.h @@ -0,0 +1,351 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved. + */ + +static const DEVPROPKEY DEVPKEY_Wintun_OwningProcess = { + { 0x3361c968, 0x2f2e, 0x4660, { 0xb4, 0x7e, 0x69, 0x9c, 0xdc, 0x4c, 0x32, 0xb9 } }, + DEVPROPID_FIRST_USABLE + 3 +}; + +typedef struct _OWNING_PROCESS +{ + DWORD ProcessId; + FILETIME CreationTime; +} OWNING_PROCESS; + +_Must_inspect_result_ +static _Return_type_success_(return != FALSE) +BOOL +WaitForInterfaceWin7(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _In_ LPCWSTR DevInstanceId) +{ + ULONG Status, Number; + DWORD ValType, Zero; + WCHAR *FileName = NULL; + HKEY Key = INVALID_HANDLE_VALUE; + HANDLE FileHandle = INVALID_HANDLE_VALUE; + BOOLEAN Ret = FALSE; + for (DWORD Tries = 0; Tries < 1500; ++Tries) + { + if (Tries) + Sleep(10); + if (Key == INVALID_HANDLE_VALUE) + Key = SetupDiOpenDevRegKey(DevInfo, DevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE); + if (!FileName) + FileName = AdapterGetDeviceObjectFileName(DevInstanceId); + if (FileName && FileHandle == INVALID_HANDLE_VALUE) + FileHandle = CreateFileW( + FileName, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + 0, + NULL); + Zero = 0; + if (FileName && FileHandle != INVALID_HANDLE_VALUE && Key != INVALID_HANDLE_VALUE && Key && + RegQueryValueExW(Key, L"NetCfgInstanceId", NULL, &ValType, NULL, &Zero) != ERROR_MORE_DATA && + CM_Get_DevNode_Status(&Status, &Number, DevInfoData->DevInst, 0) == CR_SUCCESS && + !(Status & DN_HAS_PROBLEM) && !Number) + { + Ret = TRUE; + break; + } + } + if (Key != INVALID_HANDLE_VALUE && Key) + RegCloseKey(Key); + if (FileHandle != INVALID_HANDLE_VALUE) + CloseHandle(FileHandle); + Free(FileName); + return Ret; +} + +_Must_inspect_result_ +static _Return_type_success_(return != FALSE) +BOOL +CreateAdapterWin7(_Inout_ WINTUN_ADAPTER *Adapter, _In_z_ LPCWSTR Name, _In_z_ LPCWSTR TunnelTypeName) +{ + 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 cleanup; + } + SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; + +#ifdef MAYBE_WOW64 + if (NativeMachine != IMAGE_FILE_PROCESS) + { + if (!CreateInstanceWin7ViaRundll32(Adapter->DevInstanceID)) + { + LastError = LOG_LAST_ERROR(L"Failed to create device instance"); + goto cleanup; + } + if (!SetupDiOpenDeviceInfoW(DevInfo, Adapter->DevInstanceID, NULL, DIOD_INHERIT_CLASSDRVS, &DevInfoData)) + { + LastError = GetLastError(); + goto cleanupDevInfo; + } + goto resumeAfterInstance; + } +#endif + + if (!SetupDiCreateDeviceInfoW( + DevInfo, WINTUN_HWID, &GUID_DEVCLASS_NET, TunnelTypeName, NULL, DICD_GENERATE_ID, &DevInfoData)) + { + LastError = LOG_LAST_ERROR(L"Failed to create new device information element"); + goto cleanupDevInfo; + } + SP_DEVINSTALL_PARAMS_W DevInstallParams = { .cbSize = sizeof(DevInstallParams) }; + if (!SetupDiGetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams)) + { + LastError = LOG_LAST_ERROR(L"Failed to retrieve adapter device installation parameters"); + goto cleanupDevInfo; + } + DevInstallParams.Flags |= DI_QUIETINSTALL; + if (!SetupDiSetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams)) + { + LastError = LOG_LAST_ERROR(L"Failed to set adapter device installation parameters"); + goto cleanupDevInfo; + } + if (!SetupDiSetSelectedDevice(DevInfo, &DevInfoData)) + { + LastError = LOG_LAST_ERROR(L"Failed to select adapter device"); + 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; + } + SP_DRVINFO_DATA_W DrvInfoData = { .cbSize = sizeof(SP_DRVINFO_DATA_W) }; + if (!SetupDiEnumDriverInfoW(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER, 0, &DrvInfoData) || + !SetupDiSetSelectedDriverW(DevInfo, &DevInfoData, &DrvInfoData)) + { + LastError = LOG_ERROR(ERROR_DRIVER_INSTALL_BLOCKED, L"Failed to select a driver"); + goto cleanupDriverInfo; + } + + if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, DevInfo, &DevInfoData)) + { + LastError = LOG_LAST_ERROR(L"Failed to register adapter device"); + goto cleanupDevInfo; + } + if (!SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS, DevInfo, &DevInfoData)) + LOG_LAST_ERROR(L"Failed to register adapter coinstallers"); + if (!SetupDiCallClassInstaller(DIF_INSTALLINTERFACES, DevInfo, &DevInfoData)) + LOG_LAST_ERROR(L"Failed to install adapter interfaces"); + if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICE, DevInfo, &DevInfoData)) + { + LastError = LOG_LAST_ERROR(L"Failed to install adapter device"); + goto cleanupDevice; + } + +#ifdef MAYBE_WOW64 +resumeAfterInstance:; +#endif + + OWNING_PROCESS OwningProcess = { .ProcessId = GetCurrentProcessId() }; + FILETIME Unused; + if (!GetProcessTimes(GetCurrentProcess(), &OwningProcess.CreationTime, &Unused, &Unused, &Unused)) + { + LastError = LOG_LAST_ERROR(L"Failed to get process creation time"); + goto cleanupDevice; + } + + if (!SetupDiSetDeviceRegistryPropertyW( + DevInfo, + &DevInfoData, + SPDRP_FRIENDLYNAME, + (PBYTE)TunnelTypeName, + (DWORD)((wcslen(TunnelTypeName) + 1) * sizeof(TunnelTypeName[0]))) || + !SetupDiSetDeviceRegistryPropertyW( + DevInfo, + &DevInfoData, + SPDRP_DEVICEDESC, + (PBYTE)TunnelTypeName, + (DWORD)((wcslen(TunnelTypeName) + 1) * sizeof(TunnelTypeName[0]))) || + !SetupDiSetDevicePropertyW( + DevInfo, + &DevInfoData, + &DEVPKEY_Wintun_Name, + DEVPROP_TYPE_STRING, + (PBYTE)Name, + (DWORD)((wcslen(Name) + 1) * sizeof(Name[0])), + 0) || + !SetupDiSetDevicePropertyW( + DevInfo, + &DevInfoData, + &DEVPKEY_Wintun_OwningProcess, + DEVPROP_TYPE_BINARY, + (PBYTE)&OwningProcess, + sizeof(OwningProcess), + 0)) + { + LastError = LOG_LAST_ERROR(L"Failed to set device properties"); + goto cleanupDevice; + } + + DWORD RequiredChars = _countof(Adapter->DevInstanceID); + if (!SetupDiGetDeviceInstanceIdW(DevInfo, &DevInfoData, Adapter->DevInstanceID, RequiredChars, &RequiredChars)) + { + LastError = LOG_LAST_ERROR(L"Failed to get adapter instance ID"); + goto cleanupDevice; + } + + if (!WaitForInterfaceWin7(DevInfo, &DevInfoData, Adapter->DevInstanceID)) + { + DEVPROPTYPE PropertyType = 0; + INT32 ProblemCode = 0; + if (!SetupDiGetDevicePropertyW( + DevInfo, + &DevInfoData, + &DEVPKEY_Device_ProblemCode, + &PropertyType, + (PBYTE)&ProblemCode, + sizeof(ProblemCode), + NULL, + 0) || + (PropertyType != DEVPROP_TYPE_INT32 && PropertyType != DEVPROP_TYPE_UINT32)) + ProblemCode = 0; + LastError = LOG_ERROR( + ERROR_DEVICE_REINITIALIZATION_NEEDED, L"Failed to setup adapter (problem code: 0x%x)", ProblemCode); + goto cleanupDevice; + } + +cleanupDevice: + if (LastError != ERROR_SUCCESS) + AdapterRemoveInstance(DevInfo, &DevInfoData); +cleanupDriverInfo: + SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER); +cleanupDevInfo: + SetupDiDestroyDeviceInfoList(DevInfo); +cleanup: + return RET_ERROR(TRUE, LastError); +} + +static VOID +CreateAdapterPostWin7(_Inout_ WINTUN_ADAPTER *Adapter, _In_z_ LPCWSTR TunnelTypeName) +{ + SetupDiSetDeviceRegistryPropertyW( + Adapter->DevInfo, + &Adapter->DevInfoData, + SPDRP_FRIENDLYNAME, + (PBYTE)TunnelTypeName, + (DWORD)((wcslen(TunnelTypeName) + 1) * sizeof(TunnelTypeName[0]))); + SetupDiSetDeviceRegistryPropertyW( + Adapter->DevInfo, + &Adapter->DevInfoData, + SPDRP_DEVICEDESC, + (PBYTE)TunnelTypeName, + (DWORD)((wcslen(TunnelTypeName) + 1) * sizeof(TunnelTypeName[0]))); +} + +static BOOL +ProcessIsStale(_In_ OWNING_PROCESS *OwningProcess) +{ + HANDLE Process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, OwningProcess->ProcessId); + if (!Process) + return TRUE; + FILETIME CreationTime, Unused; + BOOL Ret = GetProcessTimes(Process, &CreationTime, &Unused, &Unused, &Unused); + CloseHandle(Process); + if (!Ret) + return FALSE; + return !!memcmp(&CreationTime, &OwningProcess->CreationTime, sizeof(CreationTime)); +} + +VOID AdapterCleanupOrphanedDevicesWin7(VOID) +{ + HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, WINTUN_ENUMERATOR, NULL, 0, NULL, NULL, NULL); + if (DevInfo == INVALID_HANDLE_VALUE) + { + if (GetLastError() != ERROR_INVALID_DATA) + LOG_LAST_ERROR(L"Failed to get adapters"); + return; + } + + SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; + for (DWORD EnumIndex = 0;; ++EnumIndex) + { + if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData)) + { + if (GetLastError() == ERROR_NO_MORE_ITEMS) + break; + continue; + } + + OWNING_PROCESS OwningProcess; + DEVPROPTYPE PropType; + if (SetupDiGetDevicePropertyW( + DevInfo, + &DevInfoData, + &DEVPKEY_Wintun_OwningProcess, + &PropType, + (PBYTE)&OwningProcess, + sizeof(OwningProcess), + NULL, + 0) && + PropType == DEVPROP_TYPE_BINARY && !ProcessIsStale(&OwningProcess)) + continue; + + WCHAR Name[MAX_ADAPTER_NAME] = L"<unknown>"; + SetupDiGetDevicePropertyW( + DevInfo, + &DevInfoData, + &DEVPKEY_Wintun_Name, + &PropType, + (PBYTE)Name, + MAX_ADAPTER_NAME * sizeof(Name[0]), + NULL, + 0); + if (!AdapterRemoveInstance(DevInfo, &DevInfoData)) + { + LOG_LAST_ERROR(L"Failed to remove orphaned adapter \"%s\"", Name); + continue; + } + LOG(WINTUN_LOG_INFO, L"Removed orphaned adapter \"%s\"", Name); + } + SetupDiDestroyDeviceInfoList(DevInfo); +} + +VOID AdapterCleanupLegacyDevices(VOID) +{ + HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, L"ROOT\\NET", NULL, 0, NULL, NULL, NULL); + if (DevInfo == INVALID_HANDLE_VALUE) + return; + SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) }; + for (DWORD EnumIndex = 0;; ++EnumIndex) + { + if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData)) + { + if (GetLastError() == ERROR_NO_MORE_ITEMS) + break; + continue; + } + WCHAR HardwareIDs[0x400] = { 0 }; + DWORD ValueType, Size = sizeof(HardwareIDs) - sizeof(HardwareIDs[0]); + if (!SetupDiGetDeviceRegistryPropertyW( + DevInfo, &DevInfoData, SPDRP_HARDWAREID, &ValueType, (PBYTE)HardwareIDs, Size, &Size) || + Size > sizeof(HardwareIDs) - sizeof(HardwareIDs[0])) + continue; + Size /= sizeof(HardwareIDs[0]); + for (WCHAR *P = HardwareIDs; P < HardwareIDs + Size; P += wcslen(P) + 1) + { + if (!_wcsicmp(P, WINTUN_HWID)) + { + AdapterRemoveInstance(DevInfo, &DevInfoData); + break; + } + } + } + SetupDiDestroyDeviceInfoList(DevInfo); +}
\ No newline at end of file |