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-2017 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 /*
28  * These are necessary due to certain buggy implementations of (v)snprintf,
29  * that don't guarantee null termination for size > 0.
30  */
31 int
32 openvpn_vsntprintf(LPTSTR str, size_t size, LPCTSTR format, va_list arglist)
33 {
34  int len = -1;
35  if (size > 0)
36  {
37  len = _vsntprintf(str, size, format, arglist);
38  str[size - 1] = 0;
39  }
40  return (len >= 0 && len < size);
41 }
42 int
43 openvpn_sntprintf(LPTSTR str, size_t size, LPCTSTR format, ...)
44 {
45  va_list arglist;
46  int len = -1;
47  if (size > 0)
48  {
49  va_start(arglist, format);
50  len = openvpn_vsntprintf(str, size, format, arglist);
51  va_end(arglist);
52  }
53  return len;
54 }
55 
56 #define REG_KEY TEXT("SOFTWARE\\" PACKAGE_NAME)
57 
58 static DWORD
59 GetRegString(HKEY key, LPCTSTR value, LPTSTR data, DWORD size)
60 {
61  DWORD type;
62  LONG status = RegQueryValueEx(key, value, NULL, &type, (LPBYTE) data, &size);
63 
64  if (status == ERROR_SUCCESS && type != REG_SZ)
65  {
66  status = ERROR_DATATYPE_MISMATCH;
67  }
68 
69  if (status != ERROR_SUCCESS)
70  {
71  SetLastError(status);
72  return MsgToEventLog(M_SYSERR, TEXT("Error querying registry value: HKLM\\%s\\%s"), REG_KEY, value);
73  }
74 
75  return ERROR_SUCCESS;
76 }
77 
78 
79 DWORD
81 {
82  TCHAR priority[64];
83  TCHAR append[2];
84  DWORD error;
85  HKEY key;
86 
87  LONG status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_KEY, 0, KEY_READ, &key);
88  if (status != ERROR_SUCCESS)
89  {
90  SetLastError(status);
91  return MsgToEventLog(M_SYSERR, TEXT("Could not open Registry key HKLM\\%s not found"), REG_KEY);
92  }
93 
94  error = GetRegString(key, TEXT("exe_path"), s->exe_path, sizeof(s->exe_path));
95  if (error != ERROR_SUCCESS)
96  {
97  goto out;
98  }
99 
100  error = GetRegString(key, TEXT("config_dir"), s->config_dir, sizeof(s->config_dir));
101  if (error != ERROR_SUCCESS)
102  {
103  goto out;
104  }
105 
106  error = GetRegString(key, TEXT("config_ext"), s->ext_string, sizeof(s->ext_string));
107  if (error != ERROR_SUCCESS)
108  {
109  goto out;
110  }
111 
112  error = GetRegString(key, TEXT("log_dir"), s->log_dir, sizeof(s->log_dir));
113  if (error != ERROR_SUCCESS)
114  {
115  goto out;
116  }
117 
118  error = GetRegString(key, TEXT("priority"), priority, sizeof(priority));
119  if (error != ERROR_SUCCESS)
120  {
121  goto out;
122  }
123 
124  error = GetRegString(key, TEXT("log_append"), append, sizeof(append));
125  if (error != ERROR_SUCCESS)
126  {
127  goto out;
128  }
129 
130  /* read if present, else use default */
131  error = GetRegString(key, TEXT("ovpn_admin_group"), s->ovpn_admin_group, sizeof(s->ovpn_admin_group));
132  if (error != ERROR_SUCCESS)
133  {
135  error = 0; /* this error is not fatal */
136  }
137  /* set process priority */
138  if (!_tcsicmp(priority, TEXT("IDLE_PRIORITY_CLASS")))
139  {
140  s->priority = IDLE_PRIORITY_CLASS;
141  }
142  else if (!_tcsicmp(priority, TEXT("BELOW_NORMAL_PRIORITY_CLASS")))
143  {
144  s->priority = BELOW_NORMAL_PRIORITY_CLASS;
145  }
146  else if (!_tcsicmp(priority, TEXT("NORMAL_PRIORITY_CLASS")))
147  {
148  s->priority = NORMAL_PRIORITY_CLASS;
149  }
150  else if (!_tcsicmp(priority, TEXT("ABOVE_NORMAL_PRIORITY_CLASS")))
151  {
152  s->priority = ABOVE_NORMAL_PRIORITY_CLASS;
153  }
154  else if (!_tcsicmp(priority, TEXT("HIGH_PRIORITY_CLASS")))
155  {
156  s->priority = HIGH_PRIORITY_CLASS;
157  }
158  else
159  {
160  SetLastError(ERROR_INVALID_DATA);
161  error = MsgToEventLog(M_SYSERR, TEXT("Unknown priority name: %s"), priority);
162  goto out;
163  }
164 
165  /* set log file append/truncate flag */
166  if (append[0] == TEXT('0'))
167  {
168  s->append = FALSE;
169  }
170  else if (append[0] == TEXT('1'))
171  {
172  s->append = TRUE;
173  }
174  else
175  {
176  SetLastError(ERROR_INVALID_DATA);
177  error = MsgToEventLog(M_ERR, TEXT("Log file append flag (given as '%s') must be '0' or '1'"), append);
178  goto out;
179  }
180 
181 out:
182  RegCloseKey(key);
183  return error;
184 }
185 
186 
187 LPCTSTR
189 {
190  static TCHAR buf[256];
191  DWORD len;
192  LPTSTR tmp = NULL;
193 
194  len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
195  NULL, GetLastError(), LANG_NEUTRAL, (LPTSTR)&tmp, 0, NULL);
196 
197  if (len == 0 || (long) _countof(buf) < (long) len + 14)
198  {
199  buf[0] = TEXT('\0');
200  }
201  else
202  {
203  tmp[_tcslen(tmp) - 2] = TEXT('\0'); /* remove CR/LF characters */
204  openvpn_sntprintf(buf, _countof(buf), TEXT("%s (0x%x)"), tmp, GetLastError());
205  }
206 
207  if (tmp)
208  {
209  LocalFree(tmp);
210  }
211 
212  return buf;
213 }
214 
215 
216 DWORD
217 MsgToEventLog(DWORD flags, LPCTSTR format, ...)
218 {
219  HANDLE hEventSource;
220  TCHAR msg[2][256];
221  DWORD error = 0;
222  LPCTSTR err_msg = TEXT("");
223  va_list arglist;
224 
225  if (flags & MSG_FLAGS_SYS_CODE)
226  {
227  error = GetLastError();
228  err_msg = GetLastErrorText();
229  }
230 
231  hEventSource = RegisterEventSource(NULL, APPNAME);
232  if (hEventSource != NULL)
233  {
234  openvpn_sntprintf(msg[0], _countof(msg[0]),
235  TEXT("%s%s: %s"), APPNAME,
236  (flags & MSG_FLAGS_ERROR) ? TEXT(" error") : TEXT(""), err_msg);
237 
238  va_start(arglist, format);
239  openvpn_vsntprintf(msg[1], _countof(msg[1]), format, arglist);
240  va_end(arglist);
241 
242  const TCHAR *mesg[] = { msg[0], msg[1] };
243  ReportEvent(hEventSource, flags & MSG_FLAGS_ERROR ?
244  EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
245  0, 0, NULL, 2, 0, mesg, NULL);
246  DeregisterEventSource(hEventSource);
247  }
248 
249  return error;
250 }
251 
252 /* Convert a utf8 string to utf16. Caller should free the result */
253 wchar_t *
254 utf8to16(const char *utf8)
255 {
256  int n = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
257  wchar_t *utf16 = malloc(n * sizeof(wchar_t));
258  if (!utf16)
259  {
260  return NULL;
261  }
262  MultiByteToWideChar(CP_UTF8, 0, utf8, -1, utf16, n);
263  return utf16;
264 }
int openvpn_sntprintf(LPTSTR str, size_t size, LPCTSTR format,...)
Definition: common.c:43
DWORD MsgToEventLog(DWORD flags, LPCTSTR format,...)
Definition: common.c:217
TCHAR config_dir[MAX_PATH]
Definition: service.h:66
#define MSG_FLAGS_ERROR
Definition: service.h:43
TCHAR exe_path[MAX_PATH]
Definition: service.h:65
BOOL append
Definition: service.h:71
DWORD priority
Definition: service.h:70
static DWORD GetRegString(HKEY key, LPCTSTR value, LPTSTR data, DWORD size)
Definition: common.c:59
TCHAR ext_string[16]
Definition: service.h:67
#define OVPN_ADMIN_GROUP
Definition: validate.h:32
wchar_t * utf8to16(const char *utf8)
Definition: common.c:254
#define M_ERR
Definition: error.h:110
static SERVICE_STATUS status
Definition: automatic.c:47
DWORD GetOpenvpnSettings(settings_t *s)
Definition: common.c:80
LPCTSTR GetLastErrorText()
Definition: common.c:188
#define REG_KEY
Definition: common.c:56
TCHAR ovpn_admin_group[MAX_NAME]
Definition: service.h:69
#define msg
Definition: error.h:173
int openvpn_vsntprintf(LPTSTR str, size_t size, LPCTSTR format, va_list arglist)
Definition: common.c:32
#define M_SYSERR
Definition: service.h:46
TCHAR log_dir[MAX_PATH]
Definition: service.h:68
#define MSG_FLAGS_SYS_CODE
Definition: service.h:44
#define APPNAME
Definition: service.h:37
Container for unidirectional cipher and HMAC key material.
Definition: crypto.h:153