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