aboutsummaryrefslogtreecommitdiffstats
path: root/api
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2020-11-03 12:27:42 +0100
committerJason A. Donenfeld <Jason@zx2c4.com>2020-11-03 12:27:42 +0100
commit7dede73406a970e910516ca9e5ea8a0f82945ae3 (patch)
tree6466c752da664bdc698d82c9d056d4aba725b52e /api
parentapi: move _L macro where it belongs (diff)
downloadwintun-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.c41
-rw-r--r--api/adapter.h4
-rw-r--r--api/exports.def2
-rw-r--r--api/rundll32.c11
-rw-r--r--api/rundll32.h14
-rw-r--r--api/wintun.h13
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.