diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2020-11-03 12:27:42 +0100 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2020-11-03 12:27:42 +0100 |
commit | 7dede73406a970e910516ca9e5ea8a0f82945ae3 (patch) | |
tree | 6466c752da664bdc698d82c9d056d4aba725b52e /api | |
parent | api: move _L macro where it belongs (diff) | |
download | wintun-7dede73406a970e910516ca9e5ea8a0f82945ae3.tar.xz wintun-7dede73406a970e910516ca9e5ea8a0f82945ae3.zip |
api: add pool/driver removal for uninstaller semantics
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'api')
-rw-r--r-- | api/adapter.c | 41 | ||||
-rw-r--r-- | api/adapter.h | 4 | ||||
-rw-r--r-- | api/exports.def | 2 | ||||
-rw-r--r-- | api/rundll32.c | 11 | ||||
-rw-r--r-- | api/rundll32.h | 14 | ||||
-rw-r--r-- | api/wintun.h | 13 |
6 files changed, 65 insertions, 20 deletions
diff --git a/api/adapter.c b/api/adapter.c index 560f5f3..8cd244d 100644 --- a/api/adapter.c +++ b/api/adapter.c @@ -1750,12 +1750,18 @@ cleanupToken: } static WINTUN_STATUS -DeleteAllOurAdapters(void) +DeleteAllOurAdapters(_In_ WCHAR Pool[WINTUN_MAX_POOL], _Inout_ BOOL *RebootRequired) { + HANDLE Mutex = NamespaceTakePoolMutex(Pool); + if (!Mutex) + return ERROR_INVALID_HANDLE; DWORD Result = ERROR_SUCCESS; HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); if (DevInfo == INVALID_HANDLE_VALUE) + { + NamespaceReleaseMutex(Mutex); return LOG_LAST_ERROR(L"Failed to get present adapters"); + } SP_REMOVEDEVICE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), .InstallFunction = DIF_REMOVE }, .Scope = DI_REMOVEDEVICE_GLOBAL }; @@ -1772,39 +1778,58 @@ DeleteAllOurAdapters(void) BOOL IsOurs; if (IsOurAdapter(DevInfo, &DevInfoData, &IsOurs) != ERROR_SUCCESS || !IsOurs) continue; + BOOL IsMember; + Result = IsPoolMember(Pool, DevInfo, &DevInfoData, &IsMember); + if (Result != ERROR_SUCCESS) + { + LOG(WINTUN_LOG_ERR, L"Failed to get pool membership"); + break; + } + if (!IsMember) + continue; LOG(WINTUN_LOG_INFO, L"Force closing all open handles for existing adapter"); if (ForceCloseWintunAdapterHandle(DevInfo, &DevInfoData) != ERROR_SUCCESS) LOG(WINTUN_LOG_WARN, L"Failed to force close adapter handles"); LOG(WINTUN_LOG_INFO, L"Removing existing adapter"); - if (!SetupDiSetClassInstallParamsW(DevInfo, &DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) || - !SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData)) + if (SetupDiSetClassInstallParamsW(DevInfo, &DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) && + SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData)) + *RebootRequired = *RebootRequired || CheckReboot(DevInfo, &DevInfoData); + else { LOG_LAST_ERROR(L"Failed to remove existing adapter"); Result = Result != ERROR_SUCCESS ? Result : GetLastError(); } } SetupDiDestroyDeviceInfoList(DevInfo); + NamespaceReleaseMutex(Mutex); return Result; } WINTUN_STATUS WINAPI -WintunDeleteDriver(void) +WintunDeletePoolDriver(_In_z_ WCHAR Pool[WINTUN_MAX_POOL], _Out_opt_ BOOL *RebootRequired) { if (!ElevateToSystem()) return LOG_LAST_ERROR(L"Failed to impersonate SYSTEM user"); - DWORD Result = ERROR_SUCCESS; + BOOL DummyRebootRequired; + if (!RebootRequired) + RebootRequired = &DummyRebootRequired; + *RebootRequired = FALSE; + DWORD Result; if (MAYBE_WOW64 && NativeMachine != IMAGE_FILE_PROCESS) { - Result = DeleteDriverViaRundll32(); + Result = DeletePoolDriverViaRundll32(Pool, RebootRequired); RevertToSelf(); return Result; } - /* DeleteAllOurAdapters(); */ + Result = DeleteAllOurAdapters(Pool, RebootRequired); + if (Result != ERROR_SUCCESS) + goto cleanupToken; + HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex(); if (!DriverInstallationLock) { @@ -1837,7 +1862,7 @@ WintunDeleteDriver(void) if (!_wcsicmp(DriverDetail->HardwareID, WINTUN_HWID)) { LOG(WINTUN_LOG_INFO, TEXT("Removing existing driver")); - if (!SetupUninstallOEMInfW(PathFindFileNameW(DriverDetail->InfFileName), SUOI_FORCEDELETE, NULL)) + if (!SetupUninstallOEMInfW(PathFindFileNameW(DriverDetail->InfFileName), 0, NULL)) { LOG_LAST_ERROR(TEXT("Unable to remove existing driver")); Result = Result != ERROR_SUCCESS ? Result : GetLastError(); diff --git a/api/adapter.h b/api/adapter.h index d50ca09..cb64af7 100644 --- a/api/adapter.h +++ b/api/adapter.h @@ -58,7 +58,7 @@ WINTUN_STATUS WINAPI WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceCloseSessions, _Out_opt_ BOOL *RebootRequired); /** - * @copydoc WINTUN_DELETE_DRIVER_FUNC + * @copydoc WINTUN_DELETE_POOL_DRIVER_FUNC */ WINTUN_STATUS WINAPI -WintunDeleteDriver(void); +WintunDeletePoolDriver(_In_z_ WCHAR Pool[WINTUN_MAX_POOL], _Out_opt_ BOOL *RebootRequired);
\ No newline at end of file diff --git a/api/exports.def b/api/exports.def index 14706a3..dd7f9bb 100644 --- a/api/exports.def +++ b/api/exports.def @@ -3,7 +3,7 @@ EXPORTS WintunAllocateSendPacket WintunCreateAdapter WintunDeleteAdapter - WintunDeleteDriver + WintunDeletePoolDriver WintunEndSession WintunEnumAdapters WintunFreeAdapter diff --git a/api/rundll32.c b/api/rundll32.c index e41c2f1..bc07597 100644 --- a/api/rundll32.c +++ b/api/rundll32.c @@ -131,12 +131,19 @@ cleanup: Done(); } -VOID __stdcall DeleteDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) +VOID __stdcall DeletePoolDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) { # pragma EXPORT Init(); - WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X!", WintunDeleteDriver()); + if (Argc < 2) + goto cleanup; + + BOOL RebootRequired; + WINTUN_STATUS Ret = WintunDeletePoolDriver(Argv[2], &RebootRequired); + WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", Ret, RebootRequired); + +cleanup: Done(); } #endif diff --git a/api/rundll32.h b/api/rundll32.h index 51ea321..2a2400f 100644 --- a/api/rundll32.h +++ b/api/rundll32.h @@ -306,11 +306,15 @@ cleanupArgv: } static WINTUN_STATUS -DeleteDriverViaRundll32() +DeletePoolDriverViaRundll32(_In_z_ WCHAR Pool[WINTUN_MAX_POOL], _Inout_ BOOL *RebootRequired) { LOG(WINTUN_LOG_INFO, L"Spawning native process"); - WCHAR Response[8 + 1]; - DWORD Result = ExecuteRunDll32(L"DeleteDriver", Response, _countof(Response)); + + WCHAR Arguments[17 + WINTUN_MAX_POOL + 1]; + if (_snwprintf_s(Arguments, _countof(Arguments), _TRUNCATE, L"DeletePoolDriver %s", Pool) == -1) + return LOG(WINTUN_LOG_ERR, L"Command line too long"), ERROR_INVALID_PARAMETER; + WCHAR Response[8 + 1 + 8 + 1]; + DWORD Result = ExecuteRunDll32(Arguments, Response, _countof(Response)); if (Result != ERROR_SUCCESS) { LOG(WINTUN_LOG_ERR, L"Error executing worker process"); @@ -318,13 +322,15 @@ DeleteDriverViaRundll32() } int Argc; WCHAR **Argv = CommandLineToArgvW(Response, &Argc); - if (Argc < 1) + if (Argc < 2) { LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response"); Result = ERROR_INVALID_PARAMETER; goto cleanupArgv; } Result = wcstoul(Argv[0], NULL, 16); + if (wcstoul(Argv[1], NULL, 16)) + *RebootRequired = TRUE; cleanupArgv: LocalFree(Argv); return Result; diff --git a/api/wintun.h b/api/wintun.h index d6b8444..8725b00 100644 --- a/api/wintun.h +++ b/api/wintun.h @@ -33,7 +33,7 @@ typedef void *WINTUN_ADAPTER_HANDLE; * @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1 * characters. * - * @param RequestedGUID The GUID of the created network adapter, which then influences NLA generation + * @param RequestedGUID The GUID of the created network adapter, which then influences NLA generation * deterministically. If it is set to NULL, the GUID is chosen by the system at random, and hence * a new NLA entry is created for each new adapter. It is called "requested" GUID because the API * it uses is completely undocumented, and so there could be minor interesting complications with @@ -72,11 +72,18 @@ typedef WINTUN_STATUS(WINAPI *WINTUN_DELETE_ADAPTER_FUNC)( _Out_opt_ BOOL *RebootRequired); /** - * Deletes all Wintun drivers from the driver store + * Deletes all Wintun adapters in a pool and if there are no more adapters in any other pools, also removes Wintun + * from the driver store, usually called by uninstallers. + * + * @param Pool Name of the adapter pool. Zero-terminated string of up to WINTUN_MAX_POOL-1 characters. + * + * @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot. * * @return ERROR_SUCCESS on success; Win32 error code otherwise. */ -typedef WINTUN_STATUS(WINAPI *WINTUN_DELETE_DRIVER_FUNC)(void); +typedef WINTUN_STATUS(WINAPI *WINTUN_DELETE_POOL_DRIVER_FUNC)( + _In_z_ WCHAR Pool[WINTUN_MAX_POOL], + _Out_opt_ BOOL *RebootRequired); /** * Called by WintunEnumAdapters for each adapter in the pool. |