From patchwork Wed May 19 23:37:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lev Stipakov X-Patchwork-Id: 1821 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director9.mail.ord1d.rsapps.net ([172.28.255.1]) by backend30.mail.ord1d.rsapps.net with LMTP id IN0TJikupmDmQgAAIUCqbw (envelope-from ) for ; Thu, 20 May 2021 05:38:49 -0400 Received: from proxy6.mail.ord1c.rsapps.net ([172.28.255.1]) by director9.mail.ord1d.rsapps.net with LMTP id cDO+JSkupmBbeAAAalYnBA (envelope-from ) for ; Thu, 20 May 2021 05:38:49 -0400 Received: from smtp19.gate.ord1c ([172.28.255.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy6.mail.ord1c.rsapps.net with LMTPS id EwGoJSkupmBifwAA9sKXow (envelope-from ) for ; Thu, 20 May 2021 05:38:49 -0400 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO X-Virus-Scanned: OK X-Orig-To: openvpnslackdevel@openvpn.net X-Originating-Ip: [216.105.38.7] Authentication-Results: smtp19.gate.ord1c.rsapps.net; iprev=pass policy.iprev="216.105.38.7"; spf=pass smtp.mailfrom="openvpn-devel-bounces@lists.sourceforge.net" smtp.helo="lists.sourceforge.net"; dkim=fail (signature verification failed) header.d=sourceforge.net; dkim=fail (signature verification failed) header.d=sf.net; dkim=fail (signature verification failed) header.d=gmail.com; dmarc=fail (p=none; dis=none) header.from=gmail.com X-Suspicious-Flag: YES X-Classification-ID: 2ddedfbe-b94f-11eb-841e-bc305bf036e4-1-1 Received: from [216.105.38.7] ([216.105.38.7:55878] helo=lists.sourceforge.net) by smtp19.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 7E/27-17724-92E26A06; Thu, 20 May 2021 05:38:49 -0400 Received: from [127.0.0.1] (helo=sfs-ml-4.v29.lw.sourceforge.com) by sfs-ml-4.v29.lw.sourceforge.com with esmtp (Exim 4.90_1) (envelope-from ) id 1ljf7d-0006JR-Kd; Thu, 20 May 2021 09:37:41 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ljf7b-0006JJ-Te for openvpn-devel@lists.sourceforge.net; Thu, 20 May 2021 09:37:39 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To: MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=G5gwJyNiCicFhq7gA2fmSVNtxgew45uX5ek9AXfbVAE=; b=Gydtuw/p4RN8f+4gzmAMvUpinh 1xEp7TN55RD+6DXzAZGwFRSrtULCc94se9q2iE+9SGZXBsRl57k1ZptuTEY+EiOOYjheQGVWFZgMb 1cItRIrYTqa1zVexaG6xYvnqP94XQ1e4wWZpvK+YUf76dVo7I7cHv9FU999MA6mZHXwI=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:MIME-Version: Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=G5gwJyNiCicFhq7gA2fmSVNtxgew45uX5ek9AXfbVAE=; b=iFryMeFPqsG03P5Os3G41pcACw A75H0bCAm2MrTF6gCvxF8j5QErmPPQvCHf93CDB+3taKFoSOUcIe/LtRG4fkSjT9u8NegknEy2vrh 5DsR6SrMZlTS4T5pw13es/67o1QAV+z+0BmLBPImfMGSkZQo0kq8AUEdf5oa6stnfR5o=; Received: from mail-lj1-f180.google.com ([209.85.208.180]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.92.2) id 1ljf7U-00GHnq-1w for openvpn-devel@lists.sourceforge.net; Thu, 20 May 2021 09:37:42 +0000 Received: by mail-lj1-f180.google.com with SMTP id e2so12592336ljk.4 for ; Thu, 20 May 2021 02:37:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=G5gwJyNiCicFhq7gA2fmSVNtxgew45uX5ek9AXfbVAE=; b=Uku7YKh6jDJfFGhH/B+EAqzEYZTQSOst8vDjhpThanUrN2S9cHTB16zx/69KM+cz+2 WWshw6RN/YX6sGzPKtt5VxdmDany01mZoV8OXkOGrMGSljjvpdQwx+/i7ys6MA398gvp q1VMXToobf+tT+sX4NyWxQFTBWkKYIz22qQo0I2WDYvvTdt0nHGdfJdyzkI/ez5QiMt7 YlYf5FaHxdOXnCuP4m/nRo0GTDOZnLa8jLvkiiVTQ1rjrwFaBX/xzUpO74/eKMVY9OEW O6ghHGWwQjmzUNIJGOtGQ87ZWyZ703+wtRDPepCPhh7V1E/Lt6BGFhCsAbybQMlDA7ia yscg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=G5gwJyNiCicFhq7gA2fmSVNtxgew45uX5ek9AXfbVAE=; b=XA19tXsC8jvhOpQKTqzCSliF9VE7MBvUV6CIvOMcJqsRCGmPA47m/ko8Krtwc7bYx1 CwF8ylqweORZlAPCZ6nztN6batgr4ig5/GVSeQyLsIZz+/9HKK3EKW89koP1hLjiF253 PbWASFR9KzYU2LcSlvsp8Dvzkgn5cMLCjukmoFti1SOT7TFkSWvh/kwzmTRFxz4D/q3G Kt24l98g3I2NJwfjJdfb1zJlJW60+7gUeB0Mc2H0PIbz3TuKz82zuUiMW3mjamDAIIGh /4O1p+7pUCWruKjbezWmPxorYo3+Xe9ffjiCegKU8VxCWmerussKlUk/0kyith55fiwx oMwg== X-Gm-Message-State: AOAM530iia7wt9EJgK/pGOlDCYqXUUA7LVeGaUrA+TaysOE55dthNYpi SgdZ+O9FRj+v++Vkc7U6LZ0SkEhu2eDAVYx/ X-Google-Smtp-Source: ABdhPJwFghLi7tBTgiBwF3fPR5vBgN6z52jOda8Vwt9RKuJQ0dduHWIr0CEIG5rVAujLm3LrtNLLNA== X-Received: by 2002:a2e:580d:: with SMTP id m13mr2481631ljb.31.1621503444860; Thu, 20 May 2021 02:37:24 -0700 (PDT) Received: from LAPTOP-4L3N7KFS.localdomain (stipakov.fi. [128.199.52.117]) by smtp.gmail.com with ESMTPSA id m22sm213316ljp.92.2021.05.20.02.37.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 May 2021 02:37:24 -0700 (PDT) From: Lev Stipakov To: openvpn-devel@lists.sourceforge.net Date: Thu, 20 May 2021 12:37:00 +0300 Message-Id: <20210520093700.133-1-lstipakov@gmail.com> X-Mailer: git-send-email 2.17.1 X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.0 URIBL_BLOCKED ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [URIs: openvpn.net] 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (lstipakov[at]gmail.com) -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [209.85.208.180 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [209.85.208.180 listed in wl.mailspike.net] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-Headers-End: 1ljf7U-00GHnq-1w Subject: [Openvpn-devel] [PATCH] openvpnmsica: add ovpn-dco custom actions X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Lev Stipakov MIME-Version: 1.0 Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox From: Lev Stipakov Add two custom actions to service ovpn-dco driver installation. - EvaluateDriver Runs under user privileges. Determines what action (install/uninstall) should be performed on ovpn-dco component. - ProcessDriver Runs under SYSTEM privileges. Performs driver (un)installation. During uninstall, all existing adapters with given hwid (ovpn-dco) are removed. The logic is inspired by custom actions from tap-windows6 installer (https://github.com/OpenVPN/tap-windows6/tree/master/msm). Signed-off-by: Lev Stipakov --- src/openvpnmsica/Makefile.am | 2 +- src/openvpnmsica/openvpnmsica.c | 348 ++++++++++++++++++++++++++++++++ src/openvpnmsica/openvpnmsica.h | 30 +++ 3 files changed, 379 insertions(+), 1 deletion(-) diff --git a/src/openvpnmsica/Makefile.am b/src/openvpnmsica/Makefile.am index 9d18854a..a5d9c170 100644 --- a/src/openvpnmsica/Makefile.am +++ b/src/openvpnmsica/Makefile.am @@ -42,7 +42,7 @@ libopenvpnmsica_la_CFLAGS = \ -UNTDDI_VERSION -U_WIN32_WINNT \ -D_WIN32_WINNT=_WIN32_WINNT_VISTA \ -Wl,--kill-at -libopenvpnmsica_la_LDFLAGS = -ladvapi32 -lole32 -lmsi -lsetupapi -liphlpapi -lshell32 -lshlwapi -lversion -no-undefined -avoid-version +libopenvpnmsica_la_LDFLAGS = -ladvapi32 -lole32 -lmsi -lsetupapi -liphlpapi -lshell32 -lshlwapi -lversion -lnewdev -no-undefined -avoid-version endif libopenvpnmsica_la_SOURCES = \ diff --git a/src/openvpnmsica/openvpnmsica.c b/src/openvpnmsica/openvpnmsica.c index 96652117..5e58b08e 100644 --- a/src/openvpnmsica/openvpnmsica.c +++ b/src/openvpnmsica/openvpnmsica.c @@ -43,6 +43,10 @@ #include #include #include +#include +#include +#include +#include #ifdef _MSC_VER #pragma comment(lib, "advapi32.lib") @@ -60,6 +64,12 @@ #define MSICA_ADAPTER_TICK_SIZE (16*1024) /** Amount of tick space to reserve for one TAP/TUN adapter creation/deletition. */ #define FILE_NEED_REBOOT L".ovpn_need_reboot" +#define CMP_OVPN_DCO_INF_GUID L"{4BE20469-2292-4AE2-B953-49AA0DA4165E}" +#define ACTION_ADD_DRIVER L"AddDriver" +#define ACTION_DELETE_DRIVER L"DeleteDriver" +#define ACTION_NOOP L"Noop" +#define FILE_OVPN_DCO_INF L"ovpn-dco.inf" +#define OVPN_DCO_HWID L"ovpn-dco" /** * Joins an argument sequence and sets it to the MSI property. @@ -422,6 +432,11 @@ FindSystemInfo(_In_ MSIHANDLE hInstall) TEXT("Wintun") TEXT("\0"), TEXT("WINTUNADAPTERS"), TEXT("ACTIVEWINTUNADAPTERS")); + find_adapters( + hInstall, + TEXT("ovpn-dco") TEXT("\0"), + TEXT("OVPNDCOAPTERS"), + TEXT("ACTIVEOVPNDCOADAPTERS")); if (bIsCoInitialized) { @@ -1295,3 +1310,336 @@ CheckAndScheduleReboot(_In_ MSIHANDLE hInstall) } return ret; } + +static BOOL +IsInstalling(_In_ INSTALLSTATE InstallState, _In_ INSTALLSTATE ActionState) +{ + return INSTALLSTATE_LOCAL == ActionState || INSTALLSTATE_SOURCE == ActionState || + (INSTALLSTATE_DEFAULT == ActionState && + (INSTALLSTATE_LOCAL == InstallState || INSTALLSTATE_SOURCE == InstallState)); +} + +static BOOL +IsReInstalling(_In_ INSTALLSTATE InstallState, _In_ INSTALLSTATE ActionState) +{ + return (INSTALLSTATE_LOCAL == ActionState || INSTALLSTATE_SOURCE == ActionState || + INSTALLSTATE_DEFAULT == ActionState) && + (INSTALLSTATE_LOCAL == InstallState || INSTALLSTATE_SOURCE == InstallState); +} + +static BOOL +IsUninstalling(_In_ INSTALLSTATE InstallState, _In_ INSTALLSTATE ActionState) +{ + return (INSTALLSTATE_ABSENT == ActionState || INSTALLSTATE_REMOVED == ActionState) && + (INSTALLSTATE_LOCAL == InstallState || INSTALLSTATE_SOURCE == InstallState); +} + +static UINT +GetComponentNameById(_In_ MSIHANDLE hInstall, _In_ LPCTSTR componentId, _Out_ LPTSTR name, DWORD len) +{ + UINT ret = 0; + MSIHANDLE record = 0; + MSIHANDLE view = 0; + + name[len - 1] = '\0'; + + /* Open MSI database. */ + MSIHANDLE db = MsiGetActiveDatabase(hInstall); + if (db == 0) + { + msg(M_NONFATAL, "%s: MsiGetActiveDatabase failed", __FUNCTION__); + ret = ERROR_INVALID_HANDLE; + goto cleanup; + } + + TCHAR cmd[0x400]; + _stprintf_s(cmd, _countof(cmd), L"SELECT `Component` FROM `Component` WHERE `ComponentId` = '%s'", componentId); + + ret = MsiDatabaseOpenView(db, cmd, &view); + if (ret != ERROR_SUCCESS) + { + goto cleanup; + } + + ret = MsiViewExecute(view, 0); + if (ret != ERROR_SUCCESS) + { + goto cleanup; + } + + ret = MsiViewFetch(view, &record); + if (ret != ERROR_SUCCESS) + { + goto cleanup; + } + + ret = MsiRecordGetString(record, 1, name, &len); + if (ret != ERROR_SUCCESS) + { + goto cleanup; + } + +cleanup: + MsiCloseHandle(view); + MsiCloseHandle(record); + MsiCloseHandle(db); + + return ret; +} + +UINT __stdcall +EvaluateDriver(_In_ MSIHANDLE hInstall) +{ +#ifdef _MSC_VER +#pragma comment(linker, DLLEXP_EXPORT) +#endif + + debug_popup(TEXT(__FUNCTION__)); + + UINT ret; + BOOL bIsCoInitialized = SUCCEEDED(CoInitialize(NULL)); + + OPENVPNMSICA_SAVE_MSI_SESSION(hInstall); + + WCHAR componentName[0x400]; + ret = GetComponentNameById(hInstall, CMP_OVPN_DCO_INF_GUID, componentName, _countof(componentName)); + if (ret != ERROR_SUCCESS) + { + goto cleanup; + } + + INSTALLSTATE InstallState, ActionState; + ret = MsiGetComponentState(hInstall, componentName, &InstallState, &ActionState); + if (ret != ERROR_SUCCESS) + { + goto cleanup; + } + + /* get user-specific temp path, to where we create reboot indication file */ + WCHAR tempPath[MAX_PATH]; + GetTempPath(MAX_PATH, tempPath); + + WCHAR pathToInf[MAX_PATH]; + DWORD pathLen = _countof(pathToInf); + ret = MsiGetProperty(hInstall, L"OVPNDCO", pathToInf, &pathLen); + if (ret != ERROR_SUCCESS) + { + goto cleanup; + } + + TCHAR action[0x400]; + if ((IsReInstalling(InstallState, ActionState) || IsInstalling(InstallState, ActionState))) + { + _stprintf_s(action, _countof(action), L"%s|%s%s|%s", ACTION_ADD_DRIVER, pathToInf, FILE_OVPN_DCO_INF, tempPath); + } + else if (IsUninstalling(InstallState, ActionState)) + { + _stprintf_s(action, _countof(action), L"%s|%s%s|%s", ACTION_DELETE_DRIVER, pathToInf, FILE_OVPN_DCO_INF, tempPath); + } + else + { + _stprintf_s(action, _countof(action), L"%s||", ACTION_NOOP); + } + + ret = MsiSetProperty(hInstall, L"OvpnDcoProcess", action); + +cleanup: + if (bIsCoInitialized) + { + CoUninitialize(); + } + return ret; +} + +static BOOL +GetPublishedDriverName(_In_z_ LPCWSTR hwid, _Out_writes_z_(len) LPWSTR publishedName, _In_ DWORD len) +{ + wcscpy_s(publishedName, len, L""); + + HDEVINFO devInfoSet = SetupDiGetClassDevs(&GUID_DEVCLASS_NET, NULL, NULL, 0); + if (!devInfoSet) + { + return FALSE; + } + BOOL res = FALSE; + if (!SetupDiBuildDriverInfoList(devInfoSet, NULL, SPDIT_CLASSDRIVER)) + { + goto cleanupDeviceInfoSet; + } + for (DWORD idx = 0;; ++idx) + { + SP_DRVINFO_DATA drvInfo = { .cbSize = sizeof(drvInfo) }; + if (!SetupDiEnumDriverInfo(devInfoSet, NULL, SPDIT_CLASSDRIVER, idx, &drvInfo)) + { + if (GetLastError() == ERROR_NO_MORE_ITEMS) + { + break; + } + goto cleanupDriverInfoList; + } + DWORD size; + if (SetupDiGetDriverInfoDetail(devInfoSet, NULL, &drvInfo, NULL, 0, &size) || GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + goto cleanupDriverInfoList; + } + PSP_DRVINFO_DETAIL_DATA drvDetails = calloc(1, size); + if (!drvDetails) + { + goto cleanupDriverInfoList; + } + drvDetails->cbSize = sizeof(*drvDetails); + if (!SetupDiGetDriverInfoDetail(devInfoSet, NULL, &drvInfo, drvDetails, size, &size)) + { + free(drvDetails); + goto cleanupDriverInfoList; + } + if (_tcscmp(hwid, drvDetails->HardwareID) == 0) + { + PathStripPath(drvDetails->InfFileName); + _tcscpy_s(publishedName, len, drvDetails->InfFileName); + res = TRUE; + break; + } + free(drvDetails); + } + +cleanupDriverInfoList: + SetupDiDestroyDriverInfoList(devInfoSet, NULL, SPDIT_CLASSDRIVER); +cleanupDeviceInfoSet: + SetupDiDestroyDeviceInfoList(devInfoSet); + return res; +} + +static void +DeleteDriver(_In_z_ LPCWSTR pathToTmp) +{ + /* get list of adapters for hwid */ + struct tap_adapter_node* pAdapterList = NULL; + DWORD ret = tap_list_adapters(NULL, OVPN_DCO_HWID, &pAdapterList); + if (ret != ERROR_SUCCESS) + { + msg(M_NONFATAL, "%s", "Failed to get adapter list: %d", __FUNCTION__, ret); + } + + /* delete all adapters */ + BOOL rebootRequired = FALSE; + for (struct tap_adapter_node* pAdapter = pAdapterList; pAdapter != NULL; pAdapter = pAdapter->pNext) + { + BOOL rebootForOneAdapter = FALSE; + tap_delete_adapter(NULL, &pAdapter->guid, &rebootForOneAdapter); + rebootRequired |= rebootForOneAdapter; + } + + /* delete driver */ + WCHAR publishedName[MAX_PATH] = { 0 }; + if (GetPublishedDriverName(OVPN_DCO_HWID, publishedName, _countof(publishedName))) + { + if (!SetupUninstallOEMInf(publishedName, 0, NULL)) + { + msg(M_NONFATAL | M_ERRNO, "%s: SetupUninstallOEMInf(\"%" PRIsLPTSTR "\") failed", __FUNCTION__, publishedName); + } + } + else + { + msg(M_NONFATAL | M_ERRNO, "%s: GetPublishedDriverName(\"%" PRIsLPTSTR "\") failed", __FUNCTION__, OVPN_DCO_HWID); + } + + if (rebootRequired) + { + CreateRebootFile(pathToTmp); + } + + ret = ERROR_SUCCESS; +} + +static UINT +AddDriver(_In_z_ LPCWSTR pathToInf, _In_z_ LPCWSTR pathToTmp) +{ + /* copy driver to driver store */ + if (!SetupCopyOEMInf(pathToInf, NULL, SPOST_PATH, 0, NULL, 0, NULL, NULL)) + { + msg(M_NONFATAL | M_ERRNO, "%s: SetupCopyOEMInf(\"%" PRIsLPTSTR "\") failed", __FUNCTION__, pathToInf); + return GetLastError(); + } + + /* update driver for existing devices (if any) */ + BOOL rebootRequired = FALSE; + if (!UpdateDriverForPlugAndPlayDevices(NULL, OVPN_DCO_HWID, pathToInf, INSTALLFLAG_NONINTERACTIVE | INSTALLFLAG_FORCE, &rebootRequired)) + { + /* ERROR_NO_SUCH_DEVINST means that no devices exist, which is normal case - device (adapter) is created at later stage */ + if (GetLastError() != ERROR_NO_SUCH_DEVINST) + { + msg(M_NONFATAL | M_ERRNO, "%s: UpdateDriverForPlugAndPlayDevices(\"%" PRIsLPTSTR "\", \"%" PRIsLPTSTR "\") failed", __FUNCTION__, OVPN_DCO_HWID, pathToInf); + return GetLastError(); + } + } + if (rebootRequired) + { + CreateRebootFile(pathToTmp); + } + + return ERROR_SUCCESS; +} + +UINT __stdcall +ProcessDriver(_In_ MSIHANDLE hInstall) +{ +#ifdef _MSC_VER +#pragma comment(linker, DLLEXP_EXPORT) +#endif + + debug_popup(TEXT(__FUNCTION__)); + + UINT ret = 0; + BOOL bIsCoInitialized = SUCCEEDED(CoInitialize(NULL)); + + OPENVPNMSICA_SAVE_MSI_SESSION(hInstall); + + LPTSTR customData = NULL; + ret = msi_get_string(hInstall, L"CustomActionData", &customData); + if (ret != ERROR_SUCCESS) + { + goto cleanup; + } + + int i = 0; + WCHAR action[0x400] = { 0 }; + WCHAR pathToInf[MAX_PATH] = { 0 }; + WCHAR pathToTmp[MAX_PATH] = { 0 }; + + WCHAR* pos = NULL; + WCHAR* token = wcstok_s(customData, L"|", &pos); + /* action|path_to_inf_file|path_to_tmp_dir */ + while (token) + { + switch (i++) + { + case 0: + wcscpy_s(action, _countof(action), token); + break; + case 1: + wcscpy_s(pathToInf, _countof(pathToInf), token); + break; + case 2: + wcscpy_s(pathToTmp, _countof(pathToTmp), token); + break; + } + token = wcstok_s(NULL, L"|", &pos); + } + + if (wcscmp(action, ACTION_ADD_DRIVER) == 0) + { + AddDriver(pathToInf, pathToTmp); + } + else if (wcscmp(action, ACTION_DELETE_DRIVER) == 0) + { + DeleteDriver(pathToTmp); + } + +cleanup: + if (bIsCoInitialized) + { + CoUninitialize(); + } + return ret; +} \ No newline at end of file diff --git a/src/openvpnmsica/openvpnmsica.h b/src/openvpnmsica/openvpnmsica.h index 5af68470..f82af4a4 100644 --- a/src/openvpnmsica/openvpnmsica.h +++ b/src/openvpnmsica/openvpnmsica.h @@ -88,6 +88,10 @@ extern "C" { * with semicolon delimited list of all installed adapter GUIDs and active adapter GUIDs * respectively. * + * - Finds existing ovpn-dco adapters and set OVPNDCOADAPTERS and ACTIVEOVPNDCOADAPTERS properties + * with semicolon delimited list of all installed adapter GUIDs and active adapter GUIDs + * respectively. + * * @param hInstall Handle to the installation provided to the DLL custom action * * @return ERROR_SUCCESS on success; An error code otherwise @@ -147,6 +151,32 @@ DLLEXP_DECL UINT __stdcall ProcessDeferredAction(_In_ MSIHANDLE hInstall); +/** + * Check what operation shall be performed on ovpn-dco driver + * and set data value (path to inf and user temp dir) for ProcessDriver action. + * + * @param hInstall Handle to the installation provided to the DLL custom action + * + * @return ERROR_SUCCESS on success; An error code otherwise + * See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa368072.aspx + */ +DLLEXP_DECL UINT __stdcall +EvaluateDriver(_In_ MSIHANDLE hInstall); + + +/** + * Install or uninstall ovpn-dco driver, removing all adapters using that driver. + * If reboot is required, creates reboot indication file in user's temp directory + * + * @param hInstall Handle to the installation provided to the DLL custom action + * + * @return ERROR_SUCCESS on success; An error code otherwise + * See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa368072.aspx + */ +DLLEXP_DECL UINT __stdcall +ProcessDriver(_In_ MSIHANDLE hInstall); + + /** * Schedule reboot after installation if reboot * indication file is found in user's temp directory