Skip to content

Commit

Permalink
Introduce tapctl.exe utility and openvpnmsica.dll MSI CA
Browse files Browse the repository at this point in the history
The tapctl.exe utility is a future replacement for the devcon.exe/
tapinstall.exe utility. While this utility does not offer TAP driver
installation or upgrading, its purpose is to manipulate TAP virtual
network interfaces on Windows. In the long term, its code could be
integrated into openvpn.exe with `--mktun` and `--rmtun`.

The openvpnmsica.dll provides additional MSI custom actions for TUN/TAP
interface creation on install. The interface creation is customizable
using the `TAPInterface` MSI table and is fully compliant with MSI's
deffered processing, commit and rollback. Detailed instruction and
documentation is to be published when MSI packaging completed.

Those utilities were placed into openvpn repository to join the
established compile-sign-package OpenVPN workflow.

Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <20181010192337.6984-1-simon@rozman.si>
URL: https://www.mail-archive.com/search?l=mid&q=20181010192337.6984-1-simon@rozman.si

Signed-off-by: Gert Doering <gert@greenie.muc.de>
  • Loading branch information
rozmansi authored and cron2 committed Jan 17, 2019
1 parent 1000d5e commit ce68686
Show file tree
Hide file tree
Showing 30 changed files with 5,100 additions and 2 deletions.
2 changes: 2 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1399,10 +1399,12 @@ AC_CONFIG_FILES([
src/Makefile
src/compat/Makefile
src/openvpn/Makefile
src/openvpnmsica/Makefile
src/openvpnserv/Makefile
src/plugins/Makefile
src/plugins/auth-pam/Makefile
src/plugins/down-root/Makefile
src/tapctl/Makefile
tests/Makefile
tests/unit_tests/Makefile
tests/unit_tests/example_test/Makefile
Expand Down
20 changes: 20 additions & 0 deletions openvpn.sln
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msvc-generate", "build\msvc
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "compat", "src\compat\compat.vcxproj", "{4B2E2719-E661-45D7-9203-F6F456B22F19}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tapctl", "src\tapctl\tapctl.vcxproj", "{A06436E7-D576-490D-8BA0-0751D920334A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openvpnmsica", "src\openvpnmsica\openvpnmsica.vcxproj", "{D41AA9D6-B818-476E-992E-0E16EB86BEE2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Expand Down Expand Up @@ -51,6 +55,22 @@ Global
{4B2E2719-E661-45D7-9203-F6F456B22F19}.Release|Win32.Build.0 = Release|Win32
{4B2E2719-E661-45D7-9203-F6F456B22F19}.Release|x64.ActiveCfg = Release|x64
{4B2E2719-E661-45D7-9203-F6F456B22F19}.Release|x64.Build.0 = Release|x64
{A06436E7-D576-490D-8BA0-0751D920334A}.Debug|Win32.ActiveCfg = Debug|Win32
{A06436E7-D576-490D-8BA0-0751D920334A}.Debug|Win32.Build.0 = Debug|Win32
{A06436E7-D576-490D-8BA0-0751D920334A}.Debug|x64.ActiveCfg = Debug|x64
{A06436E7-D576-490D-8BA0-0751D920334A}.Debug|x64.Build.0 = Debug|x64
{A06436E7-D576-490D-8BA0-0751D920334A}.Release|Win32.ActiveCfg = Release|Win32
{A06436E7-D576-490D-8BA0-0751D920334A}.Release|Win32.Build.0 = Release|Win32
{A06436E7-D576-490D-8BA0-0751D920334A}.Release|x64.ActiveCfg = Release|x64
{A06436E7-D576-490D-8BA0-0751D920334A}.Release|x64.Build.0 = Release|x64
{D41AA9D6-B818-476E-992E-0E16EB86BEE2}.Debug|Win32.ActiveCfg = Debug|Win32
{D41AA9D6-B818-476E-992E-0E16EB86BEE2}.Debug|Win32.Build.0 = Debug|Win32
{D41AA9D6-B818-476E-992E-0E16EB86BEE2}.Debug|x64.ActiveCfg = Debug|x64
{D41AA9D6-B818-476E-992E-0E16EB86BEE2}.Debug|x64.Build.0 = Debug|x64
{D41AA9D6-B818-476E-992E-0E16EB86BEE2}.Release|Win32.ActiveCfg = Release|Win32
{D41AA9D6-B818-476E-992E-0E16EB86BEE2}.Release|Win32.Build.0 = Release|Win32
{D41AA9D6-B818-476E-992E-0E16EB86BEE2}.Release|x64.ActiveCfg = Release|x64
{D41AA9D6-B818-476E-992E-0E16EB86BEE2}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
2 changes: 1 addition & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
MAINTAINERCLEANFILES = \
$(srcdir)/Makefile.in

SUBDIRS = compat openvpn openvpnserv plugins
SUBDIRS = compat openvpn openvpnmsica openvpnserv plugins tapctl
5 changes: 4 additions & 1 deletion src/compat/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ MAINTAINERCLEANFILES = \

EXTRA_DIST = \
compat.vcxproj \
compat.vcxproj.filters
compat.vcxproj.filters \
PropertySheet.props \
Debug.props \
Release.props

noinst_LTLIBRARIES = libcompat.la

Expand Down
55 changes: 55 additions & 0 deletions src/openvpnmsica/Makefile.am
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#
# openvpnmsica -- Custom Action DLL to provide OpenVPN-specific support to MSI packages
#
# Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
# Copyright (C) 2018 Simon Rozman <simon@rozman.si>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#

include $(top_srcdir)/build/ltrc.inc

MAINTAINERCLEANFILES = $(srcdir)/Makefile.in

EXTRA_DIST = \
openvpnmsica.vcxproj \
openvpnmsica.vcxproj.filters \
openvpnmsica.props \
openvpnmsica-Debug.props \
openvpnmsica-Release.props

AM_CPPFLAGS = \
-I$(top_srcdir)/include -I$(top_srcdir)/src/compat

AM_CFLAGS = \
$(TAP_CFLAGS)

if WIN32
lib_LTLIBRARIES = libopenvpnmsica.la
libopenvpnmsica_la_CFLAGS = \
-municode -D_UNICODE \
-UNTDDI_VERSION -U_WIN32_WINNT \
-D_WIN32_WINNT=_WIN32_WINNT_VISTA
libopenvpnmsica_la_LDFLAGS = -ladvapi32 -lole32 -lmsi -lsetupapi -lshlwapi -no-undefined -avoid-version
endif

libopenvpnmsica_la_SOURCES = \
dllmain.c \
msiex.c msiex.h \
msica_op.c msica_op.h \
openvpnmsica.c openvpnmsica.h \
$(top_srcdir)/src/tapctl/basic.h \
$(top_srcdir)/src/tapctl/error.c $(top_srcdir)/src/tapctl/error.h \
$(top_srcdir)/src/tapctl/tap.c $(top_srcdir)/src/tapctl/tap.h \
openvpnmsica_resources.rc
179 changes: 179 additions & 0 deletions src/openvpnmsica/dllmain.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/*
* openvpnmsica -- Custom Action DLL to provide OpenVPN-specific support to MSI packages
*
* Copyright (C) 2018 Simon Rozman <simon@rozman.si>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#elif defined(_MSC_VER)
#include <config-msvc.h>
#endif

#include "openvpnmsica.h"
#include "../tapctl/error.h"

#include <windows.h>
#include <msi.h>
#include <msiquery.h>
#ifdef _MSC_VER
#pragma comment(lib, "msi.lib")
#endif
#include <stdio.h>
#include <tchar.h>


DWORD openvpnmsica_tlsidx_session = TLS_OUT_OF_INDEXES;


/**
* DLL entry point
*/
BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD dwReason,
_In_ LPVOID lpReserved)
{
UNREFERENCED_PARAMETER(hinstDLL);
UNREFERENCED_PARAMETER(lpReserved);

switch (dwReason)
{
case DLL_PROCESS_ATTACH:
/* Allocate TLS index. */
openvpnmsica_tlsidx_session = TlsAlloc();
if (openvpnmsica_tlsidx_session == TLS_OUT_OF_INDEXES)
return FALSE;
/* Fall through. */

case DLL_THREAD_ATTACH:
{
/* Create TLS data. */
struct openvpnmsica_tls_data *s = (struct openvpnmsica_tls_data*)malloc(sizeof(struct openvpnmsica_tls_data));
memset(s, 0, sizeof(struct openvpnmsica_tls_data));
TlsSetValue(openvpnmsica_tlsidx_session, s);
break;
}

case DLL_PROCESS_DETACH:
if (openvpnmsica_tlsidx_session != TLS_OUT_OF_INDEXES)
{
/* Free TLS data and TLS index. */
free(TlsGetValue(openvpnmsica_tlsidx_session));
TlsFree(openvpnmsica_tlsidx_session);
}
break;

case DLL_THREAD_DETACH:
/* Free TLS data. */
free(TlsGetValue(openvpnmsica_tlsidx_session));
break;
}

return TRUE;
}


bool
dont_mute(unsigned int flags)
{
UNREFERENCED_PARAMETER(flags);

return true;
}


void
x_msg_va(const unsigned int flags, const char *format, va_list arglist)
{
/* Secure last error before it is overridden. */
DWORD dwResult = (flags & M_ERRNO) != 0 ? GetLastError() : ERROR_SUCCESS;

struct openvpnmsica_tls_data *s = (struct openvpnmsica_tls_data *)TlsGetValue(openvpnmsica_tlsidx_session);
if (s->hInstall == 0)
{
/* No MSI session, no fun. */
return;
}

/* Prepare the message record. The record will contain up to four fields. */
MSIHANDLE hRecordProg = MsiCreateRecord(4);

{
/* Field 2: The message string. */
char szBufStack[128];
int iResultLen = vsnprintf(szBufStack, _countof(szBufStack), format, arglist);
if (iResultLen < _countof(szBufStack))
{
/* Use from stack. */
MsiRecordSetStringA(hRecordProg, 2, szBufStack);
}
else
{
/* Allocate on heap and retry. */
char *szMessage = (char*)malloc(++iResultLen * sizeof(char));
vsnprintf(szMessage, iResultLen, format, arglist);
MsiRecordSetStringA(hRecordProg, 2, szMessage);
free(szMessage);
}
}

if ((flags & M_ERRNO) == 0)
{
/* Field 1: MSI Error Code */
MsiRecordSetInteger(hRecordProg, 1, ERROR_MSICA);
}
else
{
/* Field 1: MSI Error Code */
MsiRecordSetInteger(hRecordProg, 1, ERROR_MSICA_ERRNO);

/* Field 3: The Windows error number. */
MsiRecordSetInteger(hRecordProg, 3, dwResult);

/* Field 4: The Windows error description. */
LPTSTR szErrMessage = NULL;
if (FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
0,
dwResult,
0,
(LPTSTR)&szErrMessage,
0,
NULL) && szErrMessage)
{
/* Trim trailing whitespace. Set terminator after the last non-whitespace character. This prevents excessive trailing line breaks. */
for (size_t i = 0, i_last = 0; ; i++)
{
if (szErrMessage[i])
{
if (!_istspace(szErrMessage[i]))
i_last = i + 1;
}
else
{
szErrMessage[i_last] = 0;
break;
}
}
MsiRecordSetString(hRecordProg, 4, szErrMessage);
LocalFree(szErrMessage);
}
}

MsiProcessMessage(s->hInstall, INSTALLMESSAGE_ERROR, hRecordProg);
MsiCloseHandle(hRecordProg);
}
Loading

0 comments on commit ce68686

Please sign in to comment.