openvpnserv: Fix writing messages to the event log

There are two problems with the current implementation:

 - due to the code bug, we never display actual error message
corresponding to the Windows error code. We use
FORMAT_MESSAGE_ALLOCATE_BUFFER, in which case we must pass
a pointer to the LPTSTR, not the LPTSTR itself.

 - The error is not displayed in the "General" tab, which is very confusing.
One needs to go to the "Details" tab to see what is wrong.

This commit solves both problems. We now display a proper error
message in addition to the text provided by the service ("what went wrong").
While on it, remove trailing symbols ín a safer way.

To display the message in "General" tab, we create a registered message file
(openvpnservmsg.dll), which contains message template. Note that this requires
changes to the installer - we need to install the new DLL and
add a registry entry.

GitHub: https://github.com/OpenVPN/openvpn/issues/842

Change-Id: I423c9880def0eb479abb72bef2e8034a73cf5905
Signed-off-by: Lev Stipakov <lev@openvpn.net>
Acked-by: Selva Nair <selva.nair@gmail.com>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1188
Message-Id: <20250917090557.25414-1-gert@greenie.muc.de>
URL: https://sourceforge.net/p/openvpn/mailman/message/59234559/
Signed-off-by: Gert Doering <gert@greenie.muc.de>
This commit is contained in:
Lev Stipakov 2025-09-17 11:05:48 +02:00 committed by Gert Doering
parent 168792766d
commit 06919a60ae
3 changed files with 82 additions and 14 deletions

View file

@ -6,11 +6,14 @@ project(openvpnserv)
add_executable(openvpnserv)
set(MC_GEN_DIR ${CMAKE_CURRENT_BINARY_DIR}/mc)
target_include_directories(openvpnserv PRIVATE
${CMAKE_CURRENT_BINARY_DIR}/../../
../../include/
../openvpn/
../compat/
${MC_GEN_DIR}
)
target_sources(openvpnserv PRIVATE
common.c
@ -33,3 +36,34 @@ if (MINGW)
target_compile_options(openvpnserv PRIVATE -municode)
target_link_options(openvpnserv PRIVATE -municode)
endif ()
# below we generate a DLL which contains an event source for event log messages from eventmsg.mc template
file(MAKE_DIRECTORY ${MC_GEN_DIR})
set(MC_FILE ${CMAKE_CURRENT_SOURCE_DIR}/eventmsg.mc)
find_program(MC_COMPILER NAMES mc mc.exe x86_64-w64-mingw32-windmc i686-w64-mingw32-windmc windmc)
if (NOT MC_COMPILER)
message(FATAL_ERROR "No message compiler found.")
endif()
add_custom_command(
OUTPUT ${MC_GEN_DIR}/eventmsg.rc ${MC_GEN_DIR}/eventmsg.h
COMMAND ${MC_COMPILER} -U -h ${MC_GEN_DIR} -r ${MC_GEN_DIR} ${MC_FILE}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/eventmsg.mc
VERBATIM
)
# generate rc file for DLL and header for the service binary
add_custom_target(msg_mc_gen ALL DEPENDS ${MC_GEN_DIR}/eventmsg.rc ${MC_GEN_DIR}/eventmsg.h)
add_library(openvpnservmsg SHARED ${MC_GEN_DIR}/eventmsg.rc)
if (MSVC)
set_target_properties(openvpnservmsg PROPERTIES LINK_FLAGS "/NOENTRY")
else()
target_link_options(openvpnservmsg PRIVATE "-Wl,--no-entry")
endif()
add_dependencies(openvpnservmsg msg_mc_gen)
add_dependencies(openvpnserv msg_mc_gen)

View file

@ -22,6 +22,7 @@
#include "service.h"
#include "validate.h"
#include "eventmsg.h"
LPCWSTR service_instance = L"";
static wchar_t win_sys_path[MAX_PATH];
@ -203,25 +204,29 @@ GetLastErrorText(void)
LPWSTR tmp = NULL;
error = GetLastError();
len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL, error, LANG_NEUTRAL, tmp, 0, NULL);
len = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&tmp, 0, NULL);
if (len == 0 || (long)_countof(buf) < (long)len + 14)
if (!len || !tmp)
{
buf[0] = L'\0';
}
else
{
tmp[wcslen(tmp) - 2] = L'\0'; /* remove CR/LF characters */
swprintf(buf, _countof(buf), L"%ls (0x%x)", tmp, error);
swprintf(buf, _countof(buf), L"Unknown error (0x%lx)", error);
if (tmp)
{
LocalFree(tmp);
}
return buf;
}
if (tmp)
/* trim trailing CR / LF / spaces safely */
while (len && (tmp[len - 1] == L'\r' || tmp[len - 1] == L'\n' || tmp[len - 1] == L' '))
{
LocalFree(tmp);
tmp[--len] = L'\0';
}
swprintf(buf, _countof(buf), L"%ls (0x%lx)", tmp, error);
LocalFree(tmp);
return buf;
}
@ -253,8 +258,14 @@ MsgToEventLog(DWORD flags, LPCWSTR format, ...)
const WCHAR *mesg[] = { msg[0], msg[1] };
ReportEvent(hEventSource,
flags & MSG_FLAGS_ERROR ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE, 0, 0,
NULL, 2, 0, mesg, NULL);
flags & MSG_FLAGS_ERROR ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
0,
EVT_TEXT_2,
NULL,
2,
0,
mesg,
NULL);
DeregisterEventSource(hEventSource);
}

View file

@ -0,0 +1,23 @@
MessageIdTypedef=DWORD
SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS
Informational=0x1:STATUS_SEVERITY_INFORMATIONAL
Warning=0x2:STATUS_SEVERITY_WARNING
Error=0x3:STATUS_SEVERITY_ERROR
)
FacilityNames=(System=0x0:FACILITY_SYSTEM
Runtime=0x2:FACILITY_RUNTIME
Stubs=0x3:FACILITY_STUBS
Io=0x4:FACILITY_IO_ERROR_CODE
)
LanguageNames=(English=0x409:MSG00409)
MessageId=0x1
Severity=Error
Facility=Runtime
SymbolicName=EVT_TEXT_2
Language=English
%1%n%2
.