OpenVPN
common.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2011-2025 Heiko Hund <heiko.hund@sophos.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, see <https://www.gnu.org/licenses/>.
21 */
22
23#include "service.h"
24#include "validate.h"
25#include "eventmsg.h"
26
27LPCWSTR service_instance = L"";
28static wchar_t win_sys_path[MAX_PATH];
29
30static DWORD
31GetRegString(HKEY key, LPCWSTR value, LPWSTR data, DWORD size, LPCWSTR default_value)
32{
33 LONG status = RegGetValue(key, NULL, value, RRF_RT_REG_SZ, NULL, (LPBYTE)data, &size);
34
35 if (status == ERROR_FILE_NOT_FOUND && default_value)
36 {
37 size_t len = size / sizeof(data[0]);
38 if (swprintf(data, len, default_value))
39 {
40 status = ERROR_SUCCESS;
41 }
42 }
43
44 if (status != ERROR_SUCCESS)
45 {
46 SetLastError(status);
47 return MsgToEventLog(
49 L"Error querying registry value: HKLM\\SOFTWARE\\" _L(PACKAGE_NAME) L"%ls\\%ls",
50 service_instance, value);
51 }
52
53 return ERROR_SUCCESS;
54}
55
56
57DWORD
59{
60 WCHAR reg_path[256];
61 WCHAR priority[64];
62 WCHAR append[2];
63 DWORD error;
64 HKEY key;
65 WCHAR install_path[MAX_PATH];
66 WCHAR default_value[MAX_PATH];
67
68 swprintf(reg_path, _countof(reg_path), L"SOFTWARE\\" _L(PACKAGE_NAME) L"%ls", service_instance);
69
70 LONG status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, reg_path, 0, KEY_READ, &key);
71 if (status != ERROR_SUCCESS)
72 {
73 SetLastError(status);
74 return MsgToEventLog(M_SYSERR, L"Could not open Registry key HKLM\\%ls not found",
75 reg_path);
76 }
77
78 /* The default value of REG_KEY is the install path */
79 status = GetRegString(key, NULL, install_path, sizeof(install_path), NULL);
80 if (status != ERROR_SUCCESS)
81 {
82 error = status;
83 goto out;
84 }
85
86 swprintf(default_value, _countof(default_value), L"%ls\\bin\\openvpn.exe", install_path);
87 error = GetRegString(key, L"exe_path", s->exe_path, sizeof(s->exe_path), default_value);
88 if (error != ERROR_SUCCESS)
89 {
90 goto out;
91 }
92
93 swprintf(default_value, _countof(default_value), L"%ls\\config", install_path);
94 error = GetRegString(key, L"config_dir", s->config_dir, sizeof(s->config_dir), default_value);
95 if (error != ERROR_SUCCESS)
96 {
97 goto out;
98 }
99
100 swprintf(default_value, _countof(default_value), L"%ls\\bin", install_path);
101 error = GetRegString(key, L"bin_dir", s->bin_dir, sizeof(s->bin_dir), default_value);
102 if (error != ERROR_SUCCESS)
103 {
104 goto out;
105 }
106
107 error = GetRegString(key, L"config_ext", s->ext_string, sizeof(s->ext_string), L".ovpn");
108 if (error != ERROR_SUCCESS)
109 {
110 goto out;
111 }
112
113 swprintf(default_value, _countof(default_value), L"%ls\\log", install_path);
114 error = GetRegString(key, L"log_dir", s->log_dir, sizeof(s->log_dir), default_value);
115 if (error != ERROR_SUCCESS)
116 {
117 goto out;
118 }
119
120 error = GetRegString(key, L"priority", priority, sizeof(priority), L"NORMAL_PRIORITY_CLASS");
121 if (error != ERROR_SUCCESS)
122 {
123 goto out;
124 }
125
126 error = GetRegString(key, L"log_append", append, sizeof(append), L"0");
127 if (error != ERROR_SUCCESS)
128 {
129 goto out;
130 }
131
132 /* read if present, else use default */
133 error = GetRegString(key, L"ovpn_admin_group", s->ovpn_admin_group, sizeof(s->ovpn_admin_group),
135 if (error != ERROR_SUCCESS)
136 {
137 goto out;
138 }
139
140 error = GetRegString(key, L"ovpn_service_user", s->ovpn_service_user,
142 if (error != ERROR_SUCCESS)
143 {
144 goto out;
145 }
146
147 /* set process priority */
148 if (!_wcsicmp(priority, L"IDLE_PRIORITY_CLASS"))
149 {
150 s->priority = IDLE_PRIORITY_CLASS;
151 }
152 else if (!_wcsicmp(priority, L"BELOW_NORMAL_PRIORITY_CLASS"))
153 {
154 s->priority = BELOW_NORMAL_PRIORITY_CLASS;
155 }
156 else if (!_wcsicmp(priority, L"NORMAL_PRIORITY_CLASS"))
157 {
158 s->priority = NORMAL_PRIORITY_CLASS;
159 }
160 else if (!_wcsicmp(priority, L"ABOVE_NORMAL_PRIORITY_CLASS"))
161 {
162 s->priority = ABOVE_NORMAL_PRIORITY_CLASS;
163 }
164 else if (!_wcsicmp(priority, L"HIGH_PRIORITY_CLASS"))
165 {
166 s->priority = HIGH_PRIORITY_CLASS;
167 }
168 else
169 {
170 SetLastError(ERROR_INVALID_DATA);
171 error = MsgToEventLog(M_SYSERR, L"Unknown priority name: %ls", priority);
172 goto out;
173 }
174
175 /* set log file append/truncate flag */
176 if (append[0] == L'0')
177 {
178 s->append = FALSE;
179 }
180 else if (append[0] == L'1')
181 {
182 s->append = TRUE;
183 }
184 else
185 {
186 SetLastError(ERROR_INVALID_DATA);
187 error = MsgToEventLog(M_ERR, L"Log file append flag (given as '%ls') must be '0' or '1'",
188 append);
189 goto out;
190 }
191
192out:
193 RegCloseKey(key);
194 return error;
195}
196
197
198LPCWSTR
200{
201 DWORD error;
202 static WCHAR buf[256];
203 DWORD len;
204 LPWSTR tmp = NULL;
205
206 error = GetLastError();
207 len = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
208 | FORMAT_MESSAGE_IGNORE_INSERTS,
209 NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&tmp, 0, NULL);
210
211 if (!len || !tmp)
212 {
213 swprintf(buf, _countof(buf), L"Unknown error (0x%lx)", error);
214 if (tmp)
215 {
216 LocalFree(tmp);
217 }
218 return buf;
219 }
220
221 /* trim trailing CR / LF / spaces safely */
222 while (len && (tmp[len - 1] == L'\r' || tmp[len - 1] == L'\n' || tmp[len - 1] == L' '))
223 {
224 tmp[--len] = L'\0';
225 }
226
227 swprintf(buf, _countof(buf), L"%ls (0x%lx)", tmp, error);
228
229 LocalFree(tmp);
230 return buf;
231}
232
233
234DWORD
235MsgToEventLog(DWORD flags, LPCWSTR format, ...)
236{
237 HANDLE hEventSource;
238 WCHAR msg[2][256];
239 DWORD error = 0;
240 LPCWSTR err_msg = L"";
241 va_list arglist;
242
243 if (flags & MSG_FLAGS_SYS_CODE)
244 {
245 error = GetLastError();
246 err_msg = GetLastErrorText();
247 }
248
249 hEventSource = RegisterEventSource(NULL, APPNAME);
250 if (hEventSource != NULL)
251 {
252 swprintf(msg[0], _countof(msg[0]), L"%ls%ls%ls: %ls", APPNAME, service_instance,
253 (flags & MSG_FLAGS_ERROR) ? L" error" : L"", err_msg);
254
255 va_start(arglist, format);
256 vswprintf(msg[1], _countof(msg[1]), format, arglist);
257 va_end(arglist);
258
259 const WCHAR *mesg[] = { msg[0], msg[1] };
260 ReportEvent(hEventSource,
261 flags & MSG_FLAGS_ERROR ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
262 0,
263 EVT_TEXT_2,
264 NULL,
265 2,
266 0,
267 mesg,
268 NULL);
269 DeregisterEventSource(hEventSource);
270 }
271
272 return error;
273}
274
275wchar_t *
276utf8to16_size(const char *utf8, int size)
277{
278 int n = MultiByteToWideChar(CP_UTF8, 0, utf8, size, NULL, 0);
279 wchar_t *utf16 = malloc(n * sizeof(wchar_t));
280 if (!utf16)
281 {
282 return NULL;
283 }
284 MultiByteToWideChar(CP_UTF8, 0, utf8, size, utf16, n);
285 return utf16;
286}
287
288const wchar_t *
290{
291 const wchar_t *default_sys_path = L"C:\\Windows\\system32";
292
293 if (!GetSystemDirectoryW(win_sys_path, _countof(win_sys_path)))
294 {
295 wcscpy_s(win_sys_path, _countof(win_sys_path), default_sys_path);
296 win_sys_path[_countof(win_sys_path) - 1] = L'\0';
297 }
298
299 return win_sys_path;
300}
const wchar_t * get_win_sys_path(void)
Definition common.c:289
wchar_t * utf8to16_size(const char *utf8, int size)
Convert a UTF-8 string to UTF-16.
Definition common.c:276
static DWORD GetRegString(HKEY key, LPCWSTR value, LPWSTR data, DWORD size, LPCWSTR default_value)
Definition common.c:31
DWORD MsgToEventLog(DWORD flags, LPCWSTR format,...)
Definition common.c:235
LPCWSTR service_instance
Definition common.c:27
DWORD GetOpenvpnSettings(settings_t *s)
Definition common.c:58
static wchar_t win_sys_path[MAX_PATH]
Definition common.c:28
LPCWSTR GetLastErrorText(void)
Definition common.c:199
#define PACKAGE_NAME
Definition config.h:492
static SERVICE_STATUS status
Definition interactive.c:51
#define M_ERR
Definition error.h:106
#define msg(flags,...)
Definition error.h:152
#define APPNAME
Definition service.h:36
#define M_SYSERR
Definition service.h:45
#define MSG_FLAGS_SYS_CODE
Definition service.h:43
#define MSG_FLAGS_ERROR
Definition service.h:42
Container for unidirectional cipher and HMAC key material.
Definition crypto.h:152
BOOL append
Definition service.h:74
WCHAR ext_string[16]
Definition service.h:69
WCHAR ovpn_admin_group[MAX_NAME]
Definition service.h:71
WCHAR bin_dir[MAX_PATH]
Definition service.h:68
WCHAR ovpn_service_user[MAX_NAME]
Definition service.h:72
WCHAR log_dir[MAX_PATH]
Definition service.h:70
WCHAR config_dir[MAX_PATH]
Definition service.h:67
DWORD priority
Definition service.h:73
WCHAR exe_path[MAX_PATH]
Definition service.h:66
#define _L(q)
Definition basic.h:38
#define OVPN_SERVICE_USER
Definition validate.h:33
#define OVPN_ADMIN_GROUP
Definition validate.h:31