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
26LPCWSTR service_instance = L"";
27static wchar_t win_sys_path[MAX_PATH];
28
29static DWORD
30GetRegString(HKEY key, LPCWSTR value, LPWSTR data, DWORD size, LPCWSTR default_value)
31{
32 LONG status = RegGetValue(key, NULL, value, RRF_RT_REG_SZ, NULL, (LPBYTE)data, &size);
33
34 if (status == ERROR_FILE_NOT_FOUND && default_value)
35 {
36 size_t len = size / sizeof(data[0]);
37 if (swprintf(data, len, default_value))
38 {
39 status = ERROR_SUCCESS;
40 }
41 }
42
43 if (status != ERROR_SUCCESS)
44 {
45 SetLastError(status);
46 return MsgToEventLog(
48 L"Error querying registry value: HKLM\\SOFTWARE\\" _L(PACKAGE_NAME) L"%ls\\%ls",
49 service_instance, value);
50 }
51
52 return ERROR_SUCCESS;
53}
54
55
56DWORD
58{
59 WCHAR reg_path[256];
60 WCHAR priority[64];
61 WCHAR append[2];
62 DWORD error;
63 HKEY key;
64 WCHAR install_path[MAX_PATH];
65 WCHAR default_value[MAX_PATH];
66
67 swprintf(reg_path, _countof(reg_path), L"SOFTWARE\\" _L(PACKAGE_NAME) L"%ls", service_instance);
68
69 LONG status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, reg_path, 0, KEY_READ, &key);
70 if (status != ERROR_SUCCESS)
71 {
72 SetLastError(status);
73 return MsgToEventLog(M_SYSERR, L"Could not open Registry key HKLM\\%ls not found",
74 reg_path);
75 }
76
77 /* The default value of REG_KEY is the install path */
78 status = GetRegString(key, NULL, install_path, sizeof(install_path), NULL);
79 if (status != ERROR_SUCCESS)
80 {
81 error = status;
82 goto out;
83 }
84
85 swprintf(default_value, _countof(default_value), L"%ls\\bin\\openvpn.exe", install_path);
86 error = GetRegString(key, L"exe_path", s->exe_path, sizeof(s->exe_path), default_value);
87 if (error != ERROR_SUCCESS)
88 {
89 goto out;
90 }
91
92 swprintf(default_value, _countof(default_value), L"%ls\\config", install_path);
93 error = GetRegString(key, L"config_dir", s->config_dir, sizeof(s->config_dir), default_value);
94 if (error != ERROR_SUCCESS)
95 {
96 goto out;
97 }
98
99 swprintf(default_value, _countof(default_value), L"%ls\\bin", install_path);
100 error = GetRegString(key, L"bin_dir", s->bin_dir, sizeof(s->bin_dir), default_value);
101 if (error != ERROR_SUCCESS)
102 {
103 goto out;
104 }
105
106 error = GetRegString(key, L"config_ext", s->ext_string, sizeof(s->ext_string), L".ovpn");
107 if (error != ERROR_SUCCESS)
108 {
109 goto out;
110 }
111
112 swprintf(default_value, _countof(default_value), L"%ls\\log", install_path);
113 error = GetRegString(key, L"log_dir", s->log_dir, sizeof(s->log_dir), default_value);
114 if (error != ERROR_SUCCESS)
115 {
116 goto out;
117 }
118
119 error = GetRegString(key, L"priority", priority, sizeof(priority), L"NORMAL_PRIORITY_CLASS");
120 if (error != ERROR_SUCCESS)
121 {
122 goto out;
123 }
124
125 error = GetRegString(key, L"log_append", append, sizeof(append), L"0");
126 if (error != ERROR_SUCCESS)
127 {
128 goto out;
129 }
130
131 /* read if present, else use default */
132 error = GetRegString(key, L"ovpn_admin_group", s->ovpn_admin_group, sizeof(s->ovpn_admin_group),
134 if (error != ERROR_SUCCESS)
135 {
136 goto out;
137 }
138
139 error = GetRegString(key, L"ovpn_service_user", s->ovpn_service_user,
141 if (error != ERROR_SUCCESS)
142 {
143 goto out;
144 }
145
146 /* set process priority */
147 if (!_wcsicmp(priority, L"IDLE_PRIORITY_CLASS"))
148 {
149 s->priority = IDLE_PRIORITY_CLASS;
150 }
151 else if (!_wcsicmp(priority, L"BELOW_NORMAL_PRIORITY_CLASS"))
152 {
153 s->priority = BELOW_NORMAL_PRIORITY_CLASS;
154 }
155 else if (!_wcsicmp(priority, L"NORMAL_PRIORITY_CLASS"))
156 {
157 s->priority = NORMAL_PRIORITY_CLASS;
158 }
159 else if (!_wcsicmp(priority, L"ABOVE_NORMAL_PRIORITY_CLASS"))
160 {
161 s->priority = ABOVE_NORMAL_PRIORITY_CLASS;
162 }
163 else if (!_wcsicmp(priority, L"HIGH_PRIORITY_CLASS"))
164 {
165 s->priority = HIGH_PRIORITY_CLASS;
166 }
167 else
168 {
169 SetLastError(ERROR_INVALID_DATA);
170 error = MsgToEventLog(M_SYSERR, L"Unknown priority name: %ls", priority);
171 goto out;
172 }
173
174 /* set log file append/truncate flag */
175 if (append[0] == L'0')
176 {
177 s->append = FALSE;
178 }
179 else if (append[0] == L'1')
180 {
181 s->append = TRUE;
182 }
183 else
184 {
185 SetLastError(ERROR_INVALID_DATA);
186 error = MsgToEventLog(M_ERR, L"Log file append flag (given as '%ls') must be '0' or '1'",
187 append);
188 goto out;
189 }
190
191out:
192 RegCloseKey(key);
193 return error;
194}
195
196
197LPCWSTR
199{
200 DWORD error;
201 static WCHAR buf[256];
202 DWORD len;
203 LPWSTR tmp = NULL;
204
205 error = GetLastError();
206 len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
207 | FORMAT_MESSAGE_ARGUMENT_ARRAY,
208 NULL, error, LANG_NEUTRAL, tmp, 0, NULL);
209
210 if (len == 0 || (long)_countof(buf) < (long)len + 14)
211 {
212 buf[0] = L'\0';
213 }
214 else
215 {
216 tmp[wcslen(tmp) - 2] = L'\0'; /* remove CR/LF characters */
217 swprintf(buf, _countof(buf), L"%ls (0x%x)", tmp, error);
218 }
219
220 if (tmp)
221 {
222 LocalFree(tmp);
223 }
224
225 return buf;
226}
227
228
229DWORD
230MsgToEventLog(DWORD flags, LPCWSTR format, ...)
231{
232 HANDLE hEventSource;
233 WCHAR msg[2][256];
234 DWORD error = 0;
235 LPCWSTR err_msg = L"";
236 va_list arglist;
237
238 if (flags & MSG_FLAGS_SYS_CODE)
239 {
240 error = GetLastError();
241 err_msg = GetLastErrorText();
242 }
243
244 hEventSource = RegisterEventSource(NULL, APPNAME);
245 if (hEventSource != NULL)
246 {
247 swprintf(msg[0], _countof(msg[0]), L"%ls%ls%ls: %ls", APPNAME, service_instance,
248 (flags & MSG_FLAGS_ERROR) ? L" error" : L"", err_msg);
249
250 va_start(arglist, format);
251 vswprintf(msg[1], _countof(msg[1]), format, arglist);
252 va_end(arglist);
253
254 const WCHAR *mesg[] = { msg[0], msg[1] };
255 ReportEvent(hEventSource,
256 flags & MSG_FLAGS_ERROR ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE, 0, 0,
257 NULL, 2, 0, mesg, NULL);
258 DeregisterEventSource(hEventSource);
259 }
260
261 return error;
262}
263
264wchar_t *
265utf8to16_size(const char *utf8, int size)
266{
267 int n = MultiByteToWideChar(CP_UTF8, 0, utf8, size, NULL, 0);
268 wchar_t *utf16 = malloc(n * sizeof(wchar_t));
269 if (!utf16)
270 {
271 return NULL;
272 }
273 MultiByteToWideChar(CP_UTF8, 0, utf8, size, utf16, n);
274 return utf16;
275}
276
277const wchar_t *
279{
280 const wchar_t *default_sys_path = L"C:\\Windows\\system32";
281
282 if (!GetSystemDirectoryW(win_sys_path, _countof(win_sys_path)))
283 {
284 wcscpy_s(win_sys_path, _countof(win_sys_path), default_sys_path);
285 win_sys_path[_countof(win_sys_path) - 1] = L'\0';
286 }
287
288 return win_sys_path;
289}
const wchar_t * get_win_sys_path(void)
Definition common.c:278
wchar_t * utf8to16_size(const char *utf8, int size)
Convert a UTF-8 string to UTF-16.
Definition common.c:265
static DWORD GetRegString(HKEY key, LPCWSTR value, LPWSTR data, DWORD size, LPCWSTR default_value)
Definition common.c:30
DWORD MsgToEventLog(DWORD flags, LPCWSTR format,...)
Definition common.c:230
LPCWSTR service_instance
Definition common.c:26
DWORD GetOpenvpnSettings(settings_t *s)
Definition common.c:57
static wchar_t win_sys_path[MAX_PATH]
Definition common.c:27
LPCWSTR GetLastErrorText(void)
Definition common.c:198
static SERVICE_STATUS status
Definition interactive.c:51
#define M_ERR
Definition error.h:104
#define msg(flags,...)
Definition error.h:150
#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