Browse code

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: I9b9f38e11b06701142bdc1339d9bedf080de5f86
Signed-off-by: Lev Stipakov <lev@openvpn.net>
Acked-by: Gert Doering <gert@greenie.muc.de>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1185
Message-Id: <20250917090653.25510-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg33008.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
(backported from commit 06919a60ae61d6d88546b23b52092f742599a8ae)

Lev Stipakov authored on 2025/09/17 18:06:44
Showing 3 changed files
... ...
@@ -6,11 +6,14 @@ project(openvpnserv)
6 6
 
7 7
 add_executable(openvpnserv)
8 8
 
9
+set(MC_GEN_DIR ${CMAKE_CURRENT_BINARY_DIR}/mc)
10
+
9 11
 target_include_directories(openvpnserv PRIVATE
10 12
     ${CMAKE_CURRENT_BINARY_DIR}/../../
11 13
     ../../include/
12 14
     ../openvpn/
13 15
     ../compat/
16
+    ${MC_GEN_DIR}
14 17
     )
15 18
 target_sources(openvpnserv PRIVATE
16 19
     common.c
... ...
@@ -32,3 +35,34 @@ if (MINGW)
32 32
     target_compile_options(openvpnserv PRIVATE -municode)
33 33
     target_link_options(openvpnserv PRIVATE -municode)
34 34
 endif ()
35
+
36
+# below we generate a DLL which contains an event source for event log messages from eventmsg.mc template
37
+file(MAKE_DIRECTORY ${MC_GEN_DIR})
38
+set(MC_FILE ${CMAKE_CURRENT_SOURCE_DIR}/eventmsg.mc)
39
+
40
+find_program(MC_COMPILER NAMES mc mc.exe x86_64-w64-mingw32-windmc i686-w64-mingw32-windmc windmc)
41
+
42
+if (NOT MC_COMPILER)
43
+    message(FATAL_ERROR "No message compiler found.")
44
+endif()
45
+
46
+add_custom_command(
47
+    OUTPUT ${MC_GEN_DIR}/eventmsg.rc ${MC_GEN_DIR}/eventmsg.h
48
+    COMMAND ${MC_COMPILER} -U -h ${MC_GEN_DIR} -r ${MC_GEN_DIR} ${MC_FILE}
49
+    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/eventmsg.mc
50
+    VERBATIM
51
+    )
52
+
53
+# generate rc file for DLL and header for the service binary
54
+add_custom_target(msg_mc_gen ALL DEPENDS ${MC_GEN_DIR}/eventmsg.rc ${MC_GEN_DIR}/eventmsg.h)
55
+
56
+add_library(openvpnservmsg SHARED ${MC_GEN_DIR}/eventmsg.rc)
57
+
58
+if (MSVC)
59
+    set_target_properties(openvpnservmsg PROPERTIES LINK_FLAGS "/NOENTRY")
60
+else()
61
+    target_link_options(openvpnservmsg PRIVATE "-Wl,--no-entry")
62
+endif()
63
+
64
+add_dependencies(openvpnservmsg msg_mc_gen)
65
+add_dependencies(openvpnserv msg_mc_gen)
... ...
@@ -23,6 +23,7 @@
23 23
 
24 24
 #include "service.h"
25 25
 #include "validate.h"
26
+#include "eventmsg.h"
26 27
 
27 28
 LPCTSTR service_instance = TEXT("");
28 29
 static wchar_t win_sys_path[MAX_PATH];
... ...
@@ -219,24 +220,28 @@ GetLastErrorText()
219 219
     LPTSTR tmp = NULL;
220 220
 
221 221
     error = GetLastError();
222
-    len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
223
-                        NULL, error, LANG_NEUTRAL, tmp, 0, NULL);
222
+    len = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM| FORMAT_MESSAGE_IGNORE_INSERTS,
223
+                         NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&tmp, 0, NULL);
224 224
 
225
-    if (len == 0 || (long) _countof(buf) < (long) len + 14)
225
+    if (!len || !tmp)
226 226
     {
227
-        buf[0] = TEXT('\0');
228
-    }
229
-    else
230
-    {
231
-        tmp[wcslen(tmp) - 2] = TEXT('\0'); /* remove CR/LF characters */
232
-        openvpn_swprintf(buf, _countof(buf), TEXT("%ls (0x%x)"), tmp, error);
227
+        openvpn_swprintf(buf, _countof(buf), TEXT("Unknown error (0x%lx)"), error);
228
+        if (tmp)
229
+        {
230
+            LocalFree(tmp);
231
+        }
232
+        return buf;
233 233
     }
234 234
 
235
-    if (tmp)
235
+    /* trim trailing CR / LF / spaces safely */
236
+    while (len && (tmp[len - 1] == TEXT('\r') || tmp[len - 1] == TEXT('\n') || tmp[len - 1] == TEXT(' ')))
236 237
     {
237
-        LocalFree(tmp);
238
+        tmp[--len] = TEXT('\0');
238 239
     }
239 240
 
241
+    openvpn_swprintf(buf, _countof(buf), TEXT("%ls (0x%lx)"), tmp, error);
242
+
243
+    LocalFree(tmp);
240 244
     return buf;
241 245
 }
242 246
 
... ...
@@ -268,9 +273,15 @@ MsgToEventLog(DWORD flags, LPCTSTR format, ...)
268 268
         va_end(arglist);
269 269
 
270 270
         const TCHAR *mesg[] = { msg[0], msg[1] };
271
-        ReportEvent(hEventSource, flags & MSG_FLAGS_ERROR ?
272
-                    EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
273
-                    0, 0, NULL, 2, 0, mesg, NULL);
271
+        ReportEvent(hEventSource,
272
+                    flags & MSG_FLAGS_ERROR ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
273
+                    0,
274
+                    EVT_TEXT_2,
275
+                    NULL,
276
+                    2,
277
+                    0,
278
+                    mesg,
279
+                    NULL);
274 280
         DeregisterEventSource(hEventSource);
275 281
     }
276 282
 
277 283
new file mode 100644
... ...
@@ -0,0 +1,23 @@
0
+MessageIdTypedef=DWORD
1
+
2
+SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS
3
+    Informational=0x1:STATUS_SEVERITY_INFORMATIONAL
4
+    Warning=0x2:STATUS_SEVERITY_WARNING
5
+    Error=0x3:STATUS_SEVERITY_ERROR
6
+    )
7
+
8
+FacilityNames=(System=0x0:FACILITY_SYSTEM
9
+    Runtime=0x2:FACILITY_RUNTIME
10
+    Stubs=0x3:FACILITY_STUBS
11
+    Io=0x4:FACILITY_IO_ERROR_CODE
12
+)
13
+
14
+LanguageNames=(English=0x409:MSG00409)
15
+
16
+MessageId=0x1
17
+Severity=Error
18
+Facility=Runtime
19
+SymbolicName=EVT_TEXT_2
20
+Language=English
21
+%1%n%2
22
+.