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 
27 LPCTSTR service_instance = TEXT("");
28 static wchar_t win_sys_path[MAX_PATH];
29 
30 static DWORD
31 GetRegString(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\\" PACKAGE_NAME "%ls\\%ls"), service_instance, value);
49  }
50 
51  return ERROR_SUCCESS;
52 }
53 
54 
55 DWORD
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\\" PACKAGE_NAME "%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,
128  sizeof(s->ovpn_admin_group), 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 
177 out:
178  RegCloseKey(key);
179  return error;
180 }
181 
182 
183 LPCTSTR
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 
214 DWORD
215 MsgToEventLog(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 
250 /* Convert a utf8 string to utf16. Caller should free the result */
251 wchar_t *
252 utf8to16(const char *utf8)
253 {
254  int n = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
255  wchar_t *utf16 = malloc(n * sizeof(wchar_t));
256  if (!utf16)
257  {
258  return NULL;
259  }
260  MultiByteToWideChar(CP_UTF8, 0, utf8, -1, utf16, n);
261  return utf16;
262 }
263 
264 const wchar_t *
266 {
267  const wchar_t *default_sys_path = L"C:\\Windows\\system32";
268 
269  if (!GetSystemDirectoryW(win_sys_path, _countof(win_sys_path)))
270  {
271  wcscpy_s(win_sys_path, _countof(win_sys_path), default_sys_path);
272  win_sys_path[_countof(win_sys_path) - 1] = L'\0';
273  }
274 
275  return win_sys_path;
276 }
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:215
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:184
M_ERR
#define M_ERR
Definition: error.h:105
settings_t
Definition: service.h:67
get_win_sys_path
const wchar_t * get_win_sys_path(void)
Definition: common.c:265
M_SYSERR
#define M_SYSERR
Definition: service.h:50
status
static SERVICE_STATUS status
Definition: interactive.c:53
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:252
GetRegString
static DWORD GetRegString(HKEY key, LPCTSTR value, LPTSTR data, DWORD size, LPCTSTR default_value)
Definition: common.c:31
OVPN_ADMIN_GROUP
#define OVPN_ADMIN_GROUP
Definition: validate.h:32
GetOpenvpnSettings
DWORD GetOpenvpnSettings(settings_t *s)
Definition: common.c:56
msg
#define msg(flags,...)
Definition: error.h:144
settings_t::log_dir
TCHAR log_dir[MAX_PATH]
Definition: service.h:71