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