diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2020-11-01 01:22:32 +0100 |
---|---|---|
committer | Simon Rozman <simon@rozman.si> | 2020-11-02 09:17:47 +0100 |
commit | 9adb49e13dcbc1ec9cba7df82a2073763b7186fe (patch) | |
tree | c9e9dc4f7d68902c507757e7f97631e5bc0393d2 /api/adapter.c | |
parent | api: cleanup names (diff) | |
download | wintun-9adb49e13dcbc1ec9cba7df82a2073763b7186fe.tar.xz wintun-9adb49e13dcbc1ec9cba7df82a2073763b7186fe.zip |
api: separate out driver installation
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'api/adapter.c')
-rw-r--r-- | api/adapter.c | 287 |
1 files changed, 149 insertions, 138 deletions
diff --git a/api/adapter.c b/api/adapter.c index 292b896..9ae6608 100644 --- a/api/adapter.c +++ b/api/adapter.c @@ -1021,54 +1021,6 @@ out: return Version; } -static DWORDLONG -RunningWintunVersion(void) -{ - DWORDLONG Version = 0; - PRTL_PROCESS_MODULES Modules; - ULONG BufferSize = 128 * 1024; - for (;;) - { - Modules = HeapAlloc(ModuleHeap, 0, BufferSize); - if (!Modules) - { - LOG(WINTUN_LOG_ERR, L"Out of memory"); - return Version; - } - NTSTATUS Status = NtQuerySystemInformation(SystemModuleInformation, Modules, BufferSize, &BufferSize); - if (NT_SUCCESS(Status)) - break; - HeapFree(ModuleHeap, 0, Modules); - if (Status == STATUS_INFO_LENGTH_MISMATCH) - continue; - LOG(WINTUN_LOG_ERR, L"Failed to enumerate drivers"); - return Version; - } - for (ULONG i = Modules->NumberOfModules; i-- > 0;) - { - const char *NtPath = (const char *)Modules->Modules[i].FullPathName; - if (!_stricmp(&NtPath[Modules->Modules[i].OffsetToFileName], "wintun.sys")) - { - WCHAR FilePath[MAX_PATH * 3 + 15]; - if (_snwprintf_s(FilePath, _countof(FilePath), _TRUNCATE, L"\\\\?\\GLOBALROOT%S", NtPath) == -1) - continue; - Version = VersionOfFile(FilePath); - goto out; - } - } -out: - HeapFree(ModuleHeap, 0, Modules); - return Version; -} - -static BOOL EnsureWintunUnloaded(VOID) -{ - BOOL Loaded; - for (int i = 0; (Loaded = RunningWintunVersion() != 0) != FALSE && i < 300; ++i) - Sleep(50); - return !Loaded; -} - static WINTUN_STATUS CreateAdapter( _In_z_ const WCHAR *InfPath, @@ -1388,6 +1340,150 @@ CreateTemporaryDirectory(_Out_cap_c_(MAX_PATH) WCHAR *RandomTempSubDirectory) return ERROR_SUCCESS; } +static DWORDLONG +RunningWintunVersion(void) +{ + DWORDLONG Version = 0; + PRTL_PROCESS_MODULES Modules; + ULONG BufferSize = 128 * 1024; + for (;;) + { + Modules = HeapAlloc(ModuleHeap, 0, BufferSize); + if (!Modules) + { + LOG(WINTUN_LOG_ERR, L"Out of memory"); + return Version; + } + NTSTATUS Status = NtQuerySystemInformation(SystemModuleInformation, Modules, BufferSize, &BufferSize); + if (NT_SUCCESS(Status)) + break; + HeapFree(ModuleHeap, 0, Modules); + if (Status == STATUS_INFO_LENGTH_MISMATCH) + continue; + LOG(WINTUN_LOG_ERR, L"Failed to enumerate drivers"); + return Version; + } + for (ULONG i = Modules->NumberOfModules; i-- > 0;) + { + const char *NtPath = (const char *)Modules->Modules[i].FullPathName; + if (!_stricmp(&NtPath[Modules->Modules[i].OffsetToFileName], "wintun.sys")) + { + WCHAR FilePath[MAX_PATH * 3 + 15]; + if (_snwprintf_s(FilePath, _countof(FilePath), _TRUNCATE, L"\\\\?\\GLOBALROOT%S", NtPath) == -1) + continue; + Version = VersionOfFile(FilePath); + goto out; + } + } +out: + HeapFree(ModuleHeap, 0, Modules); + return Version; +} + +static BOOL EnsureWintunUnloaded(VOID) +{ + BOOL Loaded; + for (int i = 0; (Loaded = RunningWintunVersion() != 0) != FALSE && i < 300; ++i) + Sleep(50); + return !Loaded; +} + +static WINTUN_STATUS +InstallDriver(_Out_writes_z_(MAX_PATH) WCHAR InfStorePath[MAX_PATH], _Inout_ BOOL *RebootRequired) +{ + DWORD Result; + WCHAR RandomTempSubDirectory[MAX_PATH]; + if ((Result = CreateTemporaryDirectory(RandomTempSubDirectory)) != ERROR_SUCCESS) + return LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder"), Result; + + WCHAR CatPath[MAX_PATH] = { 0 }; + WCHAR SysPath[MAX_PATH] = { 0 }; + WCHAR InfPath[MAX_PATH] = { 0 }; + if (!PathCombineW(CatPath, RandomTempSubDirectory, L"wintun.cat") || + !PathCombineW(SysPath, RandomTempSubDirectory, L"wintun.sys") || + !PathCombineW(InfPath, RandomTempSubDirectory, L"wintun.inf")) + { + Result = ERROR_BUFFER_OVERFLOW; + goto cleanupDirectory; + } + + BOOL UseWHQL = HaveWHQL(); + if (!UseWHQL && (Result = InstallCertificate(L"wintun.cat")) != ERROR_SUCCESS) + LOG(WINTUN_LOG_WARN, L"Unable to install code signing certificate"); + + LOG(WINTUN_LOG_INFO, L"Extracting driver resources"); + if ((Result = ResourceCopyToFile(CatPath, UseWHQL ? L"wintun-whql.cat" : L"wintun.cat")) != ERROR_SUCCESS || + (Result = ResourceCopyToFile(SysPath, UseWHQL ? L"wintun-whql.sys" : L"wintun.sys")) != ERROR_SUCCESS || + (Result = ResourceCopyToFile(InfPath, UseWHQL ? L"wintun-whql.inf" : L"wintun.inf")) != ERROR_SUCCESS) + { + LOG(WINTUN_LOG_ERR, L"Failed to extract resources"); + goto cleanupDelete; + } + + DWORDLONG LoadedDriverVersion = RunningWintunVersion(); + HDEVINFO DevInfo = INVALID_HANDLE_VALUE; + SP_DEVINFO_DATA_LIST *ExistingAdapters = NULL; + if (LoadedDriverVersion) + { + DWORDLONG ProposedDriverVersion = VersionOfFile(SysPath); + if (!ProposedDriverVersion) + { + LOG(WINTUN_LOG_ERR, L"Unable to query version of driver file"); + Result = ERROR_INVALID_DATA; + goto cleanupDelete; + } + if (ProposedDriverVersion > LoadedDriverVersion) + { + DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); + if (DevInfo == INVALID_HANDLE_VALUE) + { + Result = LOG_LAST_ERROR(L"Failed to get present class devices"); + goto cleanupDelete; + } + AdapterDisableAllOurs(DevInfo, &ExistingAdapters); + LOG(WINTUN_LOG_INFO, L"Waiting for existing driver to unload from kernel"); + if (!EnsureWintunUnloaded()) + LOG(WINTUN_LOG_WARN, L"Unable to unload existing driver, which means a reboot will likely be required"); + } + } + + LOG(WINTUN_LOG_INFO, L"Installing driver"); + if (!SetupCopyOEMInfW(InfPath, NULL, SPOST_PATH, 0, InfStorePath, MAX_PATH, NULL, NULL)) + { + Result = LOG_LAST_ERROR(L"Could not install driver to store"); + goto cleanupCloseDevInfo; + } + _Analysis_assume_nullterminated_(InfStorePath); + BOOL UpdateRebootRequired = FALSE; + if (ExistingAdapters && + !UpdateDriverForPlugAndPlayDevicesW( + NULL, WINTUN_HWID, InfStorePath, INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE, &UpdateRebootRequired)) + LOG(WINTUN_LOG_WARN, L"Could not update existing adapters"); + *RebootRequired = *RebootRequired || UpdateRebootRequired; + +cleanupCloseDevInfo: + if (ExistingAdapters) + { + AdapterEnableAll(DevInfo, ExistingAdapters); + while (ExistingAdapters) + { + SP_DEVINFO_DATA_LIST *Next = ExistingAdapters->Next; + HeapFree(ModuleHeap, 0, ExistingAdapters); + ExistingAdapters = Next; + } + } + if (DevInfo != INVALID_HANDLE_VALUE) + SetupDiDestroyDeviceInfoList(DevInfo); + +cleanupDelete: + DeleteFileW(CatPath); + DeleteFileW(SysPath); + DeleteFileW(InfPath); +cleanupDirectory: + RemoveDirectoryW(RandomTempSubDirectory); + return Result; +} + #ifdef MAYBE_WOW64 typedef struct _PROCESS_STDOUT_STATE @@ -1693,105 +1789,20 @@ WintunCreateAdapter( } #endif - WCHAR RandomTempSubDirectory[MAX_PATH]; - if ((Result = CreateTemporaryDirectory(RandomTempSubDirectory)) != ERROR_SUCCESS) - { - LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder"); - goto cleanupToken; - } - - WCHAR CatPath[MAX_PATH] = { 0 }; - WCHAR SysPath[MAX_PATH] = { 0 }; - WCHAR InfPath[MAX_PATH] = { 0 }; - if (!PathCombineW(CatPath, RandomTempSubDirectory, L"wintun.cat") || - !PathCombineW(SysPath, RandomTempSubDirectory, L"wintun.sys") || - !PathCombineW(InfPath, RandomTempSubDirectory, L"wintun.inf")) - { - Result = ERROR_BUFFER_OVERFLOW; - goto cleanupDirectory; - } - - BOOL UseWHQL = HaveWHQL(); - if (!UseWHQL && (Result = InstallCertificate(L"wintun.cat")) != ERROR_SUCCESS) - LOG(WINTUN_LOG_WARN, L"Unable to install code signing certificate"); - - LOG(WINTUN_LOG_INFO, L"Copying resources to temporary path"); - if ((Result = ResourceCopyToFile(CatPath, UseWHQL ? L"wintun-whql.cat" : L"wintun.cat")) != ERROR_SUCCESS || - (Result = ResourceCopyToFile(SysPath, UseWHQL ? L"wintun-whql.sys" : L"wintun.sys")) != ERROR_SUCCESS || - (Result = ResourceCopyToFile(InfPath, UseWHQL ? L"wintun-whql.inf" : L"wintun.inf")) != ERROR_SUCCESS) - { - LOG(WINTUN_LOG_ERR, L"Failed to copy resources"); - goto cleanupDelete; - } - - DWORDLONG LoadedDriverVersion = RunningWintunVersion(); - SP_DEVINFO_DATA_LIST *ExistingAdapters = NULL; - HDEVINFO DevInfo = INVALID_HANDLE_VALUE; - if (LoadedDriverVersion) - { - DWORDLONG ProposedDriverVersion = VersionOfFile(SysPath); - if (!ProposedDriverVersion) - { - LOG(WINTUN_LOG_ERR, L"Unable to query version of sys file"); - goto cleanupDelete; - } - if (ProposedDriverVersion > LoadedDriverVersion) - { - DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); - if (DevInfo == INVALID_HANDLE_VALUE) - { - Result = LOG_LAST_ERROR(L"Failed to get present class devices"); - goto cleanupDelete; - } - AdapterDisableAllOurs(DevInfo, &ExistingAdapters); - LOG(WINTUN_LOG_INFO, L"Waiting for existing driver to unload from kernel"); - if (!EnsureWintunUnloaded()) - LOG(WINTUN_LOG_WARN, L"Unable to unload existing driver, which means a reboot will likely be required"); - } - } - - LOG(WINTUN_LOG_INFO, L"Installing driver"); WCHAR InfStorePath[MAX_PATH]; - WCHAR *InfStoreFilename; - if (!SetupCopyOEMInfW(InfPath, NULL, SPOST_PATH, 0, InfStorePath, _countof(InfStorePath), NULL, &InfStoreFilename)) + if ((Result = InstallDriver(InfStorePath, RebootRequired)) != ERROR_SUCCESS) { - Result = LOG_LAST_ERROR(L"Could not install driver to store"); - goto cleanupCloseDevInfo; + LOG(WINTUN_LOG_ERR, L"Failed to install driver"); + goto cleanupToken; } - BOOL UpdateRebootRequired = FALSE; - if (ExistingAdapters && - !UpdateDriverForPlugAndPlayDevicesW( - NULL, WINTUN_HWID, InfPath, INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE, &UpdateRebootRequired)) - LOG(WINTUN_LOG_WARN, L"Could not update existing adapters"); - *RebootRequired = *RebootRequired || UpdateRebootRequired; - Result = CreateAdapter(InfPath, Pool, Name, RequestedGUID, Adapter, RebootRequired); + Result = CreateAdapter(InfStorePath, Pool, Name, RequestedGUID, Adapter, RebootRequired); - LOG(WINTUN_LOG_INFO, L"Removing driver"); - if (!SetupUninstallOEMInfW(InfStoreFilename, SUOI_FORCEDELETE, NULL)) + if (!SetupUninstallOEMInfW(PathFindFileNameW(InfStorePath), SUOI_FORCEDELETE, NULL)) { LOG_LAST_ERROR(L"Unable to remove existing driver"); Result = Result != ERROR_SUCCESS ? Result : GetLastError(); } -cleanupCloseDevInfo: - if (ExistingAdapters) - { - AdapterEnableAll(DevInfo, ExistingAdapters); - while (ExistingAdapters) - { - SP_DEVINFO_DATA_LIST *Next = ExistingAdapters->Next; - HeapFree(ModuleHeap, 0, ExistingAdapters); - ExistingAdapters = Next; - } - } - if (DevInfo != INVALID_HANDLE_VALUE) - SetupDiDestroyDeviceInfoList(DevInfo); -cleanupDelete: - DeleteFileW(CatPath); - DeleteFileW(SysPath); - DeleteFileW(InfPath); -cleanupDirectory: - RemoveDirectoryW(RandomTempSubDirectory); cleanupToken: RevertToSelf(); return Result; |