aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/installer/customactions.c
diff options
context:
space:
mode:
Diffstat (limited to 'installer/customactions.c')
-rw-r--r--installer/customactions.c357
1 files changed, 269 insertions, 88 deletions
diff --git a/installer/customactions.c b/installer/customactions.c
index 496d80b1..d3078a31 100644
--- a/installer/customactions.c
+++ b/installer/customactions.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
/*
- * Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
+ * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
*/
#include <windows.h>
@@ -17,7 +17,7 @@
#define MANAGER_SERVICE_NAME TEXT("WireGuardManager")
#define TUNNEL_SERVICE_PREFIX TEXT("WireGuardTunnel$")
-enum log_level { LOG_LEVEL_INFO, LOG_LEVEL_WARN, LOG_LEVEL_ERR };
+enum log_level { LOG_LEVEL_INFO, LOG_LEVEL_WARN, LOG_LEVEL_ERR, LOG_LEVEL_MSIERR };
static void log_messagef(MSIHANDLE installer, enum log_level level, const TCHAR *format, ...)
{
@@ -49,6 +49,10 @@ static void log_messagef(MSIHANDLE installer, enum log_level level, const TCHAR
template = TEXT("WireGuard error: [1]");
type = INSTALLMESSAGE_ERROR;
break;
+ case LOG_LEVEL_MSIERR:
+ template = TEXT("[1]");
+ type = INSTALLMESSAGE_ERROR;
+ break;
default:
goto out;
}
@@ -78,6 +82,46 @@ static void log_errorf(MSIHANDLE installer, enum log_level level, DWORD error_co
LocalFree(system_message);
}
+__declspec(dllexport) UINT __stdcall CheckWow64(MSIHANDLE installer)
+{
+ UINT ret = ERROR_SUCCESS;
+ bool is_com_initialized = SUCCEEDED(CoInitialize(NULL));
+ HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
+ BOOL(WINAPI *IsWow64Process2)(HANDLE hProcess, USHORT *pProcessMachine, USHORT *pNativeMachine);
+ USHORT process_machine, native_machine;
+ BOOL is_wow64_process;
+
+ if (!kernel32) {
+ ret = GetLastError();
+ log_errorf(installer, LOG_LEVEL_ERR, ret, TEXT("Failed to get kernel32.dll handle"));
+ goto out;
+ }
+ *(FARPROC *)&IsWow64Process2 = GetProcAddress(kernel32, "IsWow64Process2");
+ if (IsWow64Process2) {
+ if (!IsWow64Process2(GetCurrentProcess(), &process_machine, &native_machine)) {
+ ret = GetLastError();
+ log_errorf(installer, LOG_LEVEL_ERR, ret, TEXT("Failed to determine Wow64 status from IsWow64Process2"));
+ goto out;
+ }
+ if (process_machine == IMAGE_FILE_MACHINE_UNKNOWN)
+ goto out;
+ } else {
+ if (!IsWow64Process(GetCurrentProcess(), &is_wow64_process)) {
+ ret = GetLastError();
+ log_errorf(installer, LOG_LEVEL_ERR, ret, TEXT("Failed to determine Wow64 status from IsWow64Process"));
+ goto out;
+ }
+ if (!is_wow64_process)
+ goto out;
+ }
+ log_messagef(installer, LOG_LEVEL_MSIERR, TEXT("You must use the native version of WireGuard on this computer."));
+ ret = ERROR_INSTALL_FAILURE;
+out:
+ if (is_com_initialized)
+ CoUninitialize();
+ return ret;
+}
+
static UINT insert_service_control(MSIHANDLE installer, MSIHANDLE view, const TCHAR *service_name, bool start)
{
static unsigned int index = 0;
@@ -126,62 +170,6 @@ out:
return ret;
}
-static bool remove_directory_recursive(MSIHANDLE installer, TCHAR path[MAX_PATH], unsigned int max_depth)
-{
- HANDLE find_handle;
- WIN32_FIND_DATA find_data;
- TCHAR *path_end;
-
- if (!max_depth) {
- log_messagef(installer, LOG_LEVEL_WARN, TEXT("Too many levels of nesting at \"%1\""), path);
- return false;
- }
-
- path_end = path + _tcsnlen(path, MAX_PATH);
- if (!PathAppend(path, TEXT("*.*"))) {
- log_errorf(installer, LOG_LEVEL_WARN, GetLastError(), TEXT("PathAppend(\"%1\", \"*.*\") failed"), path);
- return false;
- }
- find_handle = FindFirstFileEx(path, FindExInfoBasic, &find_data, FindExSearchNameMatch, NULL, 0);
- if (find_handle == INVALID_HANDLE_VALUE) {
- log_errorf(installer, LOG_LEVEL_WARN, GetLastError(), TEXT("FindFirstFileEx(\"%1\") failed"), path);
- return false;
- }
- do {
- if (find_data.cFileName[0] == TEXT('.') && (find_data.cFileName[1] == TEXT('\0') || (find_data.cFileName[1] == TEXT('.') && find_data.cFileName[2] == TEXT('\0'))))
- continue;
-
- path_end[0] = TEXT('\0');
- if (!PathAppend(path, find_data.cFileName)) {
- log_errorf(installer, LOG_LEVEL_WARN, GetLastError(), TEXT("PathAppend(\"%1\", \"%2\") failed"), path, find_data.cFileName);
- continue;
- }
-
- if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- remove_directory_recursive(installer, path, max_depth - 1);
- continue;
- }
-
- if ((find_data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) && !SetFileAttributes(path, find_data.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
- log_errorf(installer, LOG_LEVEL_WARN, GetLastError(), TEXT("SetFileAttributes(\"%1\") failed"), path);
-
- if (DeleteFile(path))
- log_messagef(installer, LOG_LEVEL_INFO, TEXT("Deleted \"%1\""), path);
- else
- log_errorf(installer, LOG_LEVEL_WARN, GetLastError(), TEXT("DeleteFile(\"%1\") failed"), path);
- } while (FindNextFile(find_handle, &find_data));
- FindClose(find_handle);
-
- path_end[0] = TEXT('\0');
- if (RemoveDirectory(path)) {
- log_messagef(installer, LOG_LEVEL_INFO, TEXT("Removed \"%1\""), path);
- return true;
- } else {
- log_errorf(installer, LOG_LEVEL_WARN, GetLastError(), TEXT("RemoveDirectory(\"%1\") failed"), path);
- return false;
- }
-}
-
__declspec(dllexport) UINT __stdcall EvaluateWireGuardServices(MSIHANDLE installer)
{
UINT ret = ERROR_INSTALL_FAILURE;
@@ -255,27 +243,82 @@ out:
return ret == ERROR_SUCCESS ? ret : ERROR_INSTALL_FAILURE;
}
-__declspec(dllexport) UINT __stdcall RemoveConfigFolder(MSIHANDLE installer)
+__declspec(dllexport) UINT __stdcall LaunchApplicationAndAbort(MSIHANDLE installer)
{
- LSTATUS ret;
+ UINT ret = ERROR_INSTALL_FAILURE;
TCHAR path[MAX_PATH];
+ DWORD path_len = _countof(path);
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si = { .cb = sizeof(STARTUPINFO) };
+
+ ret = MsiGetProperty(installer, TEXT("WireGuardFolder"), path, &path_len);
+ if (ret != ERROR_SUCCESS) {
+ log_errorf(installer, LOG_LEVEL_WARN, ret, TEXT("MsiGetProperty(\"WireGuardFolder\") failed"));
+ goto out;
+ }
+ if (!path[0] || !PathAppend(path, TEXT("wireguard.exe")))
+ goto out;
+ log_messagef(installer, LOG_LEVEL_INFO, TEXT("Launching %1"), path);
+ if (!CreateProcess(path, TEXT("wireguard"), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
+ log_errorf(installer, LOG_LEVEL_WARN, GetLastError(), TEXT("Failed to create \"%1\" process"), path);
+ goto out;
+ }
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+out:
+ return ERROR_INSTALL_USEREXIT;
+}
+
+__declspec(dllexport) UINT __stdcall EvaluateWireGuardComponents(MSIHANDLE installer)
+{
+ UINT ret = ERROR_INSTALL_FAILURE;
bool is_com_initialized = SUCCEEDED(CoInitialize(NULL));
+ INSTALLSTATE component_installed, component_action;
+ TCHAR path[MAX_PATH];
+ DWORD path_len = _countof(path);
- ret = SHRegGetPath(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\S-1-5-18"),
- TEXT("ProfileImagePath"), path, 0);
+ ret = MsiGetComponentState(installer, TEXT("WireGuardExecutable"), &component_installed, &component_action);
if (ret != ERROR_SUCCESS) {
- log_errorf(installer, LOG_LEVEL_WARN, ret, TEXT("SHRegGetPath failed"));
+ log_errorf(installer, LOG_LEVEL_ERR, ret, TEXT("MsiGetComponentState(\"WireGuardExecutable\") failed"));
goto out;
}
- if (!PathAppend(path, TEXT("AppData\\Local\\WireGuard"))) {
- log_errorf(installer, LOG_LEVEL_WARN, GetLastError(), TEXT("PathAppend(\"%1\", \"AppData\\Local\\WireGuard\") failed"), path);
+ ret = MsiGetProperty(installer, TEXT("WireGuardFolder"), path, &path_len);
+ if (ret != ERROR_SUCCESS) {
+ log_errorf(installer, LOG_LEVEL_ERR, ret, TEXT("MsiGetProperty(\"WireGuardFolder\") failed"));
goto out;
}
- remove_directory_recursive(installer, path, 10);
+
+ if (component_action >= INSTALLSTATE_LOCAL) {
+ /* WireGuardExecutable component shall be installed. */
+ ret = MsiSetProperty(installer, TEXT("KillWireGuardProcesses"), path);
+ if (ret != ERROR_SUCCESS) {
+ log_errorf(installer, LOG_LEVEL_ERR, ret, TEXT("MsiSetProperty(\"KillWireGuardProcesses\") failed"));
+ goto out;
+ }
+ } else if (component_action >= INSTALLSTATE_REMOVED) {
+ /* WireGuardExecutable component shall be uninstalled. */
+ ret = MsiSetProperty(installer, TEXT("KillWireGuardProcesses"), path);
+ if (ret != ERROR_SUCCESS) {
+ log_errorf(installer, LOG_LEVEL_ERR, ret, TEXT("MsiSetProperty(\"KillWireGuardProcesses\") failed"));
+ goto out;
+ }
+ ret = MsiSetProperty(installer, TEXT("RemoveConfigFolder"), path);
+ if (ret != ERROR_SUCCESS) {
+ log_errorf(installer, LOG_LEVEL_ERR, ret, TEXT("MsiSetProperty(\"RemoveConfigFolder\") failed"));
+ goto out;
+ }
+ ret = MsiSetProperty(installer, TEXT("RemoveAdapters"), path);
+ if (ret != ERROR_SUCCESS) {
+ log_errorf(installer, LOG_LEVEL_ERR, ret, TEXT("MsiSetProperty(\"RemoveAdapters\") failed"));
+ goto out;
+ }
+ }
+ ret = ERROR_SUCCESS;
+
out:
if (is_com_initialized)
CoUninitialize();
- return ERROR_SUCCESS;
+ return ret == ERROR_SUCCESS ? ret : ERROR_INSTALL_FAILURE;
}
struct file_id { DWORD volume, index_high, index_low; };
@@ -299,36 +342,30 @@ static bool calculate_file_id(const TCHAR *path, struct file_id *id)
return true;
}
-static bool calculate_known_file_id(const KNOWNFOLDERID *known_folder, const TCHAR *file, struct file_id *id)
-{
- TCHAR *folder_path, process_path[MAX_PATH + 1];
- bool ret = false;
-
- if (SHGetKnownFolderPath(known_folder, KF_FLAG_DEFAULT, NULL, &folder_path) == S_OK) {
- if (PathCombine(process_path, folder_path, file)) {
- if (calculate_file_id(process_path, id))
- ret = true;
- }
- CoTaskMemFree(folder_path);
- }
- return ret;
-}
-
__declspec(dllexport) UINT __stdcall KillWireGuardProcesses(MSIHANDLE installer)
{
HANDLE snapshot, process;
PROCESSENTRY32 entry = { .dwSize = sizeof(PROCESSENTRY32) };
- TCHAR process_path[MAX_PATH + 1];
- DWORD process_path_len;
+ TCHAR process_path[MAX_PATH], executable[MAX_PATH];
+ DWORD process_path_len = _countof(process_path);
struct file_id file_ids[3], file_id;
size_t file_ids_len = 0;
bool is_com_initialized = SUCCEEDED(CoInitialize(NULL));
+ LSTATUS mret;
- if (calculate_known_file_id(&FOLDERID_System, TEXT("wg.exe"), &file_ids[file_ids_len]))
- ++file_ids_len;
- if (calculate_known_file_id(&FOLDERID_SystemX86, TEXT("wg.exe"), &file_ids[file_ids_len]))
+ mret = MsiGetProperty(installer, TEXT("CustomActionData"), process_path, &process_path_len);
+ if (mret != ERROR_SUCCESS) {
+ log_errorf(installer, LOG_LEVEL_WARN, mret, TEXT("MsiGetProperty(\"CustomActionData\") failed"));
+ goto out;
+ }
+ if (!process_path[0])
+ goto out;
+
+ log_messagef(installer, LOG_LEVEL_INFO, TEXT("Detecting running processes"));
+
+ if (PathCombine(executable, process_path, TEXT("wg.exe")) && calculate_file_id(executable, &file_ids[file_ids_len]))
++file_ids_len;
- if (calculate_known_file_id(&FOLDERID_ProgramFiles, TEXT("WireGuard\\wireguard.exe"), &file_ids[file_ids_len]))
+ if (PathCombine(executable, process_path, TEXT("wireguard.exe")) && calculate_file_id(executable, &file_ids[file_ids_len]))
++file_ids_len;
if (!file_ids_len)
goto out;
@@ -371,3 +408,147 @@ out:
CoUninitialize();
return ERROR_SUCCESS;
}
+
+static bool remove_directory_recursive(MSIHANDLE installer, TCHAR path[MAX_PATH], unsigned int max_depth)
+{
+ HANDLE find_handle;
+ WIN32_FIND_DATA find_data;
+ TCHAR *path_end;
+
+ if (!max_depth) {
+ log_messagef(installer, LOG_LEVEL_WARN, TEXT("Too many levels of nesting at \"%1\""), path);
+ return false;
+ }
+
+ path_end = path + _tcsnlen(path, MAX_PATH);
+ if (!PathAppend(path, TEXT("*.*"))) {
+ log_errorf(installer, LOG_LEVEL_WARN, GetLastError(), TEXT("PathAppend(\"%1\", \"*.*\") failed"), path);
+ return false;
+ }
+ find_handle = FindFirstFileEx(path, FindExInfoBasic, &find_data, FindExSearchNameMatch, NULL, 0);
+ if (find_handle == INVALID_HANDLE_VALUE) {
+ log_errorf(installer, LOG_LEVEL_WARN, GetLastError(), TEXT("FindFirstFileEx(\"%1\") failed"), path);
+ return false;
+ }
+ do {
+ if (find_data.cFileName[0] == TEXT('.') && (find_data.cFileName[1] == TEXT('\0') || (find_data.cFileName[1] == TEXT('.') && find_data.cFileName[2] == TEXT('\0'))))
+ continue;
+
+ path_end[0] = TEXT('\0');
+ if (!PathAppend(path, find_data.cFileName)) {
+ log_errorf(installer, LOG_LEVEL_WARN, GetLastError(), TEXT("PathAppend(\"%1\", \"%2\") failed"), path, find_data.cFileName);
+ continue;
+ }
+
+ if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ remove_directory_recursive(installer, path, max_depth - 1);
+ continue;
+ }
+
+ if ((find_data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) && !SetFileAttributes(path, find_data.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY))
+ log_errorf(installer, LOG_LEVEL_WARN, GetLastError(), TEXT("SetFileAttributes(\"%1\") failed"), path);
+
+ if (DeleteFile(path))
+ log_messagef(installer, LOG_LEVEL_INFO, TEXT("Deleted \"%1\""), path);
+ else
+ log_errorf(installer, LOG_LEVEL_WARN, GetLastError(), TEXT("DeleteFile(\"%1\") failed"), path);
+ } while (FindNextFile(find_handle, &find_data));
+ FindClose(find_handle);
+
+ path_end[0] = TEXT('\0');
+ if (RemoveDirectory(path)) {
+ log_messagef(installer, LOG_LEVEL_INFO, TEXT("Removed \"%1\""), path);
+ return true;
+ } else {
+ log_errorf(installer, LOG_LEVEL_WARN, GetLastError(), TEXT("RemoveDirectory(\"%1\") failed"), path);
+ return false;
+ }
+}
+
+__declspec(dllexport) UINT __stdcall RemoveConfigFolder(MSIHANDLE installer)
+{
+ LSTATUS ret;
+ TCHAR path[MAX_PATH];
+ DWORD path_len = _countof(path);
+ bool is_com_initialized = SUCCEEDED(CoInitialize(NULL));
+
+ ret = MsiGetProperty(installer, TEXT("CustomActionData"), path, &path_len);
+ if (ret != ERROR_SUCCESS) {
+ log_errorf(installer, LOG_LEVEL_WARN, ret, TEXT("MsiGetProperty(\"CustomActionData\") failed"));
+ goto out;
+ }
+ if (!path[0] || !PathAppend(path, TEXT("Data")))
+ goto out;
+ remove_directory_recursive(installer, path, 10);
+ RegDeleteKey(HKEY_LOCAL_MACHINE, TEXT("Software\\WireGuard")); // Assumes no WOW.
+out:
+ if (is_com_initialized)
+ CoUninitialize();
+ return ERROR_SUCCESS;
+}
+
+__declspec(dllexport) UINT __stdcall RemoveAdapters(MSIHANDLE installer)
+{
+ UINT ret;
+ bool is_com_initialized = SUCCEEDED(CoInitialize(NULL));
+ TCHAR path[MAX_PATH];
+ DWORD path_len = _countof(path);
+ HANDLE pipe;
+ char buf[0x200];
+ DWORD offset = 0, size_read;
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si = {
+ .cb = sizeof(STARTUPINFO),
+ .dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES,
+ .wShowWindow = SW_HIDE
+ };
+
+ ret = MsiGetProperty(installer, TEXT("CustomActionData"), path, &path_len);
+ if (ret != ERROR_SUCCESS) {
+ log_errorf(installer, LOG_LEVEL_WARN, ret, TEXT("MsiGetProperty(\"CustomActionData\") failed"));
+ goto out;
+ }
+ if (!path[0] || !PathAppend(path, TEXT("wireguard.exe")))
+ goto out;
+
+ if (!CreatePipe(&pipe, &si.hStdOutput, NULL, 0)) {
+ log_errorf(installer, LOG_LEVEL_WARN, GetLastError(), TEXT("CreatePipe failed"));
+ goto out;
+ }
+ if (!SetHandleInformation(si.hStdOutput, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) {
+ log_errorf(installer, LOG_LEVEL_WARN, GetLastError(), TEXT("SetHandleInformation failed"));
+ goto cleanup_pipe_w;
+ }
+ if (!CreateProcess(path, TEXT("wireguard /removedriver"), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
+ log_errorf(installer, LOG_LEVEL_WARN, GetLastError(), TEXT("Failed to create \"%1\" process"), path);
+ goto cleanup_pipe_w;
+ }
+ CloseHandle(si.hStdOutput);
+ buf[sizeof(buf) - 1] = '\0';
+ while (ReadFile(pipe, buf + offset, sizeof(buf) - offset - 1, &size_read, NULL)) {
+ char *nl;
+ buf[offset + size_read] = '\0';
+ nl = strchr(buf, '\n');
+ if (!nl) {
+ offset = size_read;
+ continue;
+ }
+ nl[0] = '\0';
+ log_messagef(installer, LOG_LEVEL_INFO, TEXT("%1!hs!"), buf);
+ offset = strlen(&nl[1]);
+ memmove(buf, &nl[1], offset);
+ }
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ goto cleanup_pipe_r;
+
+cleanup_pipe_w:
+ CloseHandle(si.hStdOutput);
+cleanup_pipe_r:
+ CloseHandle(pipe);
+out:
+ if (is_com_initialized)
+ CoUninitialize();
+ return ERROR_SUCCESS;
+}