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