OpenVPN
interactive.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) 2012-2018 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 
25 #include "service.h"
26 
27 #include <ws2tcpip.h>
28 #include <iphlpapi.h>
29 #include <userenv.h>
30 #include <accctrl.h>
31 #include <aclapi.h>
32 #include <stdio.h>
33 #include <sddl.h>
34 #include <shellapi.h>
35 #include <mstcpip.h>
36 
37 #ifdef HAVE_VERSIONHELPERS_H
38 #include <versionhelpers.h>
39 #else
40 #include "compat-versionhelpers.h"
41 #endif
42 
43 #include "openvpn-msg.h"
44 #include "validate.h"
45 #include "block_dns.h"
46 #include "ring_buffer.h"
47 
48 #define IO_TIMEOUT 2000 /*ms*/
49 
50 #define ERROR_OPENVPN_STARTUP 0x20000000
51 #define ERROR_STARTUP_DATA 0x20000001
52 #define ERROR_MESSAGE_DATA 0x20000002
53 #define ERROR_MESSAGE_TYPE 0x20000003
54 
55 static SERVICE_STATUS_HANDLE service;
56 static SERVICE_STATUS status = { .dwServiceType = SERVICE_WIN32_SHARE_PROCESS };
57 static HANDLE exit_event = NULL;
59 static HANDLE rdns_semaphore = NULL;
60 #define RDNS_TIMEOUT 600 /* seconds to wait for the semaphore */
61 
62 #define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
63 
66  TEXT(PACKAGE_NAME "ServiceInteractive"),
67  TEXT(PACKAGE_NAME " Interactive Service"),
69  SERVICE_AUTO_START
70 };
71 
72 
73 typedef struct {
74  WCHAR *directory;
75  WCHAR *options;
76  WCHAR *std_input;
77 } STARTUP_DATA;
78 
79 
80 /* Datatype for linked lists */
81 typedef struct _list_item {
82  struct _list_item *next;
83  LPVOID data;
84 } list_item_t;
85 
86 
87 /* Datatypes for undo information */
88 typedef enum {
96 } undo_type_t;
98 
99 typedef struct {
100  HANDLE engine;
101  int index;
105 
106 typedef struct {
111  HANDLE device;
113 
114 
115 static DWORD
116 AddListItem(list_item_t **pfirst, LPVOID data)
117 {
118  list_item_t *new_item = malloc(sizeof(list_item_t));
119  if (new_item == NULL)
120  {
121  return ERROR_OUTOFMEMORY;
122  }
123 
124  new_item->next = *pfirst;
125  new_item->data = data;
126 
127  *pfirst = new_item;
128  return NO_ERROR;
129 }
130 
131 typedef BOOL (*match_fn_t) (LPVOID item, LPVOID ctx);
132 
133 static LPVOID
135 {
136  LPVOID data = NULL;
137  list_item_t **pnext;
138 
139  for (pnext = pfirst; *pnext; pnext = &(*pnext)->next)
140  {
141  list_item_t *item = *pnext;
142  if (!match(item->data, ctx))
143  {
144  continue;
145  }
146 
147  /* Found item, remove from the list and free memory */
148  *pnext = item->next;
149  data = item->data;
150  free(item);
151  break;
152  }
153  return data;
154 }
155 
156 
157 static HANDLE
158 CloseHandleEx(LPHANDLE handle)
159 {
160  if (handle && *handle && *handle != INVALID_HANDLE_VALUE)
161  {
162  CloseHandle(*handle);
163  *handle = INVALID_HANDLE_VALUE;
164  }
165  return INVALID_HANDLE_VALUE;
166 }
167 
168 static HANDLE
169 OvpnUnmapViewOfFile(LPHANDLE handle)
170 {
171  if (handle && *handle && *handle != INVALID_HANDLE_VALUE)
172  {
173  UnmapViewOfFile(*handle);
174  *handle = INVALID_HANDLE_VALUE;
175  }
176  return INVALID_HANDLE_VALUE;
177 }
178 
179 static void
181 {
182  CloseHandleEx(&ring_buffer_handles->device);
183  CloseHandleEx(&ring_buffer_handles->receive_tail_moved);
184  CloseHandleEx(&ring_buffer_handles->send_tail_moved);
185  OvpnUnmapViewOfFile(&ring_buffer_handles->send_ring_handle);
186  OvpnUnmapViewOfFile(&ring_buffer_handles->receive_ring_handle);
187 }
188 
189 static HANDLE
190 InitOverlapped(LPOVERLAPPED overlapped)
191 {
192  ZeroMemory(overlapped, sizeof(OVERLAPPED));
193  overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
194  return overlapped->hEvent;
195 }
196 
197 
198 static BOOL
199 ResetOverlapped(LPOVERLAPPED overlapped)
200 {
201  HANDLE io_event = overlapped->hEvent;
202  if (!ResetEvent(io_event))
203  {
204  return FALSE;
205  }
206  ZeroMemory(overlapped, sizeof(OVERLAPPED));
207  overlapped->hEvent = io_event;
208  return TRUE;
209 }
210 
211 
212 typedef enum {
216 } async_op_t;
217 
218 static DWORD
219 AsyncPipeOp(async_op_t op, HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
220 {
221  DWORD i;
222  BOOL success;
223  HANDLE io_event;
224  DWORD res, bytes = 0;
225  OVERLAPPED overlapped;
226  LPHANDLE handles = NULL;
227 
228  io_event = InitOverlapped(&overlapped);
229  if (!io_event)
230  {
231  goto out;
232  }
233 
234  handles = malloc((count + 1) * sizeof(HANDLE));
235  if (!handles)
236  {
237  goto out;
238  }
239 
240  if (op == write)
241  {
242  success = WriteFile(pipe, buffer, size, NULL, &overlapped);
243  }
244  else
245  {
246  success = ReadFile(pipe, buffer, size, NULL, &overlapped);
247  }
248  if (!success && GetLastError() != ERROR_IO_PENDING && GetLastError() != ERROR_MORE_DATA)
249  {
250  goto out;
251  }
252 
253  handles[0] = io_event;
254  for (i = 0; i < count; i++)
255  {
256  handles[i + 1] = events[i];
257  }
258 
259  res = WaitForMultipleObjects(count + 1, handles, FALSE,
260  op == peek ? INFINITE : IO_TIMEOUT);
261  if (res != WAIT_OBJECT_0)
262  {
263  CancelIo(pipe);
264  goto out;
265  }
266 
267  if (op == peek)
268  {
269  PeekNamedPipe(pipe, NULL, 0, NULL, &bytes, NULL);
270  }
271  else
272  {
273  GetOverlappedResult(pipe, &overlapped, &bytes, TRUE);
274  }
275 
276 out:
277  CloseHandleEx(&io_event);
278  free(handles);
279  return bytes;
280 }
281 
282 static DWORD
283 PeekNamedPipeAsync(HANDLE pipe, DWORD count, LPHANDLE events)
284 {
285  return AsyncPipeOp(peek, pipe, NULL, 0, count, events);
286 }
287 
288 static DWORD
289 ReadPipeAsync(HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
290 {
291  return AsyncPipeOp(read, pipe, buffer, size, count, events);
292 }
293 
294 static DWORD
295 WritePipeAsync(HANDLE pipe, LPVOID data, DWORD size, DWORD count, LPHANDLE events)
296 {
297  return AsyncPipeOp(write, pipe, data, size, count, events);
298 }
299 
300 static VOID
301 ReturnProcessId(HANDLE pipe, DWORD pid, DWORD count, LPHANDLE events)
302 {
303  const WCHAR msg[] = L"Process ID";
304  WCHAR buf[22 + _countof(msg)]; /* 10 chars each for error and PID and 2 for line breaks */
305 
306  /*
307  * Same format as error messages (3 line string) with error = 0 in
308  * 0x%08x format, PID on line 2 and a description "Process ID" on line 3
309  */
310  openvpn_swprintf(buf, _countof(buf), L"0x%08x\n0x%08x\n%s", 0, pid, msg);
311 
312  WritePipeAsync(pipe, buf, (DWORD)(wcslen(buf) * 2), count, events);
313 }
314 
315 static VOID
316 ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events)
317 {
318  DWORD result_len;
319  LPWSTR result = L"0xffffffff\nFormatMessage failed\nCould not return result";
320  DWORD_PTR args[] = {
321  (DWORD_PTR) error,
322  (DWORD_PTR) func,
323  (DWORD_PTR) ""
324  };
325 
326  if (error != ERROR_OPENVPN_STARTUP)
327  {
328  FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM
329  |FORMAT_MESSAGE_ALLOCATE_BUFFER
330  |FORMAT_MESSAGE_IGNORE_INSERTS,
331  0, error, 0, (LPWSTR) &args[2], 0, NULL);
332  }
333 
334  result_len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING
335  |FORMAT_MESSAGE_ALLOCATE_BUFFER
336  |FORMAT_MESSAGE_ARGUMENT_ARRAY,
337  L"0x%1!08x!\n%2!s!\n%3!s!", 0, 0,
338  (LPWSTR) &result, 0, (va_list *) args);
339 
340  WritePipeAsync(pipe, result, (DWORD)(wcslen(result) * 2), count, events);
341 #ifdef UNICODE
343 #else
344  MsgToEventLog(MSG_FLAGS_ERROR, "%S", result);
345 #endif
346 
347  if (error != ERROR_OPENVPN_STARTUP)
348  {
349  LocalFree((LPVOID) args[2]);
350  }
351  if (result_len)
352  {
353  LocalFree(result);
354  }
355 }
356 
357 
358 static VOID
359 ReturnLastError(HANDLE pipe, LPCWSTR func)
360 {
361  ReturnError(pipe, GetLastError(), func, 1, &exit_event);
362 }
363 
364 /*
365  * Validate options against a white list. Also check the config_file is
366  * inside the config_dir. The white list is defined in validate.c
367  * Returns true on success, false on error with reason set in errmsg.
368  */
369 static BOOL
370 ValidateOptions(HANDLE pipe, const WCHAR *workdir, const WCHAR *options, WCHAR *errmsg, DWORD capacity)
371 {
372  WCHAR **argv;
373  int argc;
374  BOOL ret = FALSE;
375  int i;
376  const WCHAR *msg1 = L"You have specified a config file location (%s relative to %s)"
377  L" that requires admin approval. This error may be avoided"
378  L" by adding your account to the \"%s\" group";
379 
380  const WCHAR *msg2 = L"You have specified an option (%s) that may be used"
381  L" only with admin approval. This error may be avoided"
382  L" by adding your account to the \"%s\" group";
383 
384  argv = CommandLineToArgvW(options, &argc);
385 
386  if (!argv)
387  {
388  openvpn_swprintf(errmsg, capacity,
389  L"Cannot validate options: CommandLineToArgvW failed with error = 0x%08x",
390  GetLastError());
391  goto out;
392  }
393 
394  /* Note: argv[0] is the first option */
395  if (argc < 1) /* no options */
396  {
397  ret = TRUE;
398  goto out;
399  }
400 
401  /*
402  * If only one argument, it is the config file
403  */
404  if (argc == 1)
405  {
406  WCHAR *argv_tmp[2] = { L"--config", argv[0] };
407 
408  if (!CheckOption(workdir, 2, argv_tmp, &settings))
409  {
410  openvpn_swprintf(errmsg, capacity, msg1, argv[0], workdir,
411  settings.ovpn_admin_group);
412  }
413  goto out;
414  }
415 
416  for (i = 0; i < argc; ++i)
417  {
418  if (!IsOption(argv[i]))
419  {
420  continue;
421  }
422 
423  if (!CheckOption(workdir, argc-i, &argv[i], &settings))
424  {
425  if (wcscmp(L"--config", argv[i]) == 0 && argc-i > 1)
426  {
427  openvpn_swprintf(errmsg, capacity, msg1, argv[i+1], workdir,
428  settings.ovpn_admin_group);
429  }
430  else
431  {
432  openvpn_swprintf(errmsg, capacity, msg2, argv[i],
433  settings.ovpn_admin_group);
434  }
435  goto out;
436  }
437  }
438 
439  /* all options passed */
440  ret = TRUE;
441 
442 out:
443  if (argv)
444  {
445  LocalFree(argv);
446  }
447  return ret;
448 }
449 
450 static BOOL
451 GetStartupData(HANDLE pipe, STARTUP_DATA *sud)
452 {
453  size_t size, len;
454  WCHAR *data = NULL;
455  DWORD bytes, read;
456 
457  bytes = PeekNamedPipeAsync(pipe, 1, &exit_event);
458  if (bytes == 0)
459  {
460  MsgToEventLog(M_SYSERR, TEXT("PeekNamedPipeAsync failed"));
461  ReturnLastError(pipe, L"PeekNamedPipeAsync");
462  goto err;
463  }
464 
465  size = bytes / sizeof(*data);
466  if (size == 0)
467  {
468  MsgToEventLog(M_SYSERR, TEXT("malformed startup data: 1 byte received"));
469  ReturnError(pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event);
470  goto err;
471  }
472 
473  data = malloc(bytes);
474  if (data == NULL)
475  {
476  MsgToEventLog(M_SYSERR, TEXT("malloc failed"));
477  ReturnLastError(pipe, L"malloc");
478  goto err;
479  }
480 
481  read = ReadPipeAsync(pipe, data, bytes, 1, &exit_event);
482  if (bytes != read)
483  {
484  MsgToEventLog(M_SYSERR, TEXT("ReadPipeAsync failed"));
485  ReturnLastError(pipe, L"ReadPipeAsync");
486  goto err;
487  }
488 
489  if (data[size - 1] != 0)
490  {
491  MsgToEventLog(M_ERR, TEXT("Startup data is not NULL terminated"));
492  ReturnError(pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event);
493  goto err;
494  }
495 
496  sud->directory = data;
497  len = wcslen(sud->directory) + 1;
498  size -= len;
499  if (size <= 0)
500  {
501  MsgToEventLog(M_ERR, TEXT("Startup data ends at working directory"));
502  ReturnError(pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event);
503  goto err;
504  }
505 
506  sud->options = sud->directory + len;
507  len = wcslen(sud->options) + 1;
508  size -= len;
509  if (size <= 0)
510  {
511  MsgToEventLog(M_ERR, TEXT("Startup data ends at command line options"));
512  ReturnError(pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event);
513  goto err;
514  }
515 
516  sud->std_input = sud->options + len;
517  return TRUE;
518 
519 err:
520  sud->directory = NULL; /* caller must not free() */
521  free(data);
522  return FALSE;
523 }
524 
525 
526 static VOID
528 {
529  free(sud->directory);
530 }
531 
532 
533 static SOCKADDR_INET
534 sockaddr_inet(short family, inet_address_t *addr)
535 {
536  SOCKADDR_INET sa_inet;
537  ZeroMemory(&sa_inet, sizeof(sa_inet));
538  sa_inet.si_family = family;
539  if (family == AF_INET)
540  {
541  sa_inet.Ipv4.sin_addr = addr->ipv4;
542  }
543  else if (family == AF_INET6)
544  {
545  sa_inet.Ipv6.sin6_addr = addr->ipv6;
546  }
547  return sa_inet;
548 }
549 
550 static DWORD
551 InterfaceLuid(const char *iface_name, PNET_LUID luid)
552 {
553  NETIO_STATUS status;
554  LPWSTR wide_name = utf8to16(iface_name);
555 
556  if (wide_name)
557  {
558  status = ConvertInterfaceAliasToLuid(wide_name, luid);
559  free(wide_name);
560  }
561  else
562  {
563  status = ERROR_OUTOFMEMORY;
564  }
565  return status;
566 }
567 
568 static DWORD
569 ConvertInterfaceNameToIndex(const wchar_t *ifname, NET_IFINDEX *index)
570 {
571  NET_LUID luid;
572  DWORD err;
573 
574  err = ConvertInterfaceAliasToLuid(ifname, &luid);
575  if (err == ERROR_SUCCESS)
576  {
577  err = ConvertInterfaceLuidToIndex(&luid, index);
578  }
579  if (err != ERROR_SUCCESS)
580  {
581  MsgToEventLog(M_ERR, L"Failed to find interface index for <%s>", ifname);
582  }
583  return err;
584 }
585 
586 static BOOL
587 CmpAddress(LPVOID item, LPVOID address)
588 {
589  return memcmp(item, address, sizeof(MIB_UNICASTIPADDRESS_ROW)) == 0 ? TRUE : FALSE;
590 }
591 
592 static DWORD
593 DeleteAddress(PMIB_UNICASTIPADDRESS_ROW addr_row)
594 {
595  return DeleteUnicastIpAddressEntry(addr_row);
596 }
597 
598 static DWORD
600 {
601  DWORD err;
602  PMIB_UNICASTIPADDRESS_ROW addr_row;
603  BOOL add = msg->header.type == msg_add_address;
604 
605  addr_row = malloc(sizeof(*addr_row));
606  if (addr_row == NULL)
607  {
608  return ERROR_OUTOFMEMORY;
609  }
610 
611  InitializeUnicastIpAddressEntry(addr_row);
612  addr_row->Address = sockaddr_inet(msg->family, &msg->address);
613  addr_row->OnLinkPrefixLength = (UINT8) msg->prefix_len;
614 
615  if (msg->iface.index != -1)
616  {
617  addr_row->InterfaceIndex = msg->iface.index;
618  }
619  else
620  {
621  NET_LUID luid;
622  err = InterfaceLuid(msg->iface.name, &luid);
623  if (err)
624  {
625  goto out;
626  }
627  addr_row->InterfaceLuid = luid;
628  }
629 
630  if (add)
631  {
632  err = CreateUnicastIpAddressEntry(addr_row);
633  if (err)
634  {
635  goto out;
636  }
637 
638  err = AddListItem(&(*lists)[address], addr_row);
639  if (err)
640  {
641  DeleteAddress(addr_row);
642  }
643  }
644  else
645  {
646  err = DeleteAddress(addr_row);
647  if (err)
648  {
649  goto out;
650  }
651 
652  free(RemoveListItem(&(*lists)[address], CmpAddress, addr_row));
653  }
654 
655 out:
656  if (!add || err)
657  {
658  free(addr_row);
659  }
660 
661  return err;
662 }
663 
664 static BOOL
665 CmpRoute(LPVOID item, LPVOID route)
666 {
667  return memcmp(item, route, sizeof(MIB_IPFORWARD_ROW2)) == 0 ? TRUE : FALSE;
668 }
669 
670 static DWORD
671 DeleteRoute(PMIB_IPFORWARD_ROW2 fwd_row)
672 {
673  return DeleteIpForwardEntry2(fwd_row);
674 }
675 
676 static DWORD
678 {
679  DWORD err;
680  PMIB_IPFORWARD_ROW2 fwd_row;
681  BOOL add = msg->header.type == msg_add_route;
682 
683  fwd_row = malloc(sizeof(*fwd_row));
684  if (fwd_row == NULL)
685  {
686  return ERROR_OUTOFMEMORY;
687  }
688 
689  ZeroMemory(fwd_row, sizeof(*fwd_row));
690  fwd_row->ValidLifetime = 0xffffffff;
691  fwd_row->PreferredLifetime = 0xffffffff;
692  fwd_row->Protocol = MIB_IPPROTO_NETMGMT;
693  fwd_row->Metric = msg->metric;
694  fwd_row->DestinationPrefix.Prefix = sockaddr_inet(msg->family, &msg->prefix);
695  fwd_row->DestinationPrefix.PrefixLength = (UINT8) msg->prefix_len;
696  fwd_row->NextHop = sockaddr_inet(msg->family, &msg->gateway);
697 
698  if (msg->iface.index != -1)
699  {
700  fwd_row->InterfaceIndex = msg->iface.index;
701  }
702  else if (strlen(msg->iface.name))
703  {
704  NET_LUID luid;
705  err = InterfaceLuid(msg->iface.name, &luid);
706  if (err)
707  {
708  goto out;
709  }
710  fwd_row->InterfaceLuid = luid;
711  }
712 
713  if (add)
714  {
715  err = CreateIpForwardEntry2(fwd_row);
716  if (err)
717  {
718  goto out;
719  }
720 
721  err = AddListItem(&(*lists)[route], fwd_row);
722  if (err)
723  {
724  DeleteRoute(fwd_row);
725  }
726  }
727  else
728  {
729  err = DeleteRoute(fwd_row);
730  if (err)
731  {
732  goto out;
733  }
734 
735  free(RemoveListItem(&(*lists)[route], CmpRoute, fwd_row));
736  }
737 
738 out:
739  if (!add || err)
740  {
741  free(fwd_row);
742  }
743 
744  return err;
745 }
746 
747 
748 static DWORD
750 {
751  if (msg->family == AF_INET)
752  {
753  return FlushIpNetTable(msg->iface.index);
754  }
755 
756  return FlushIpNetTable2(msg->family, msg->iface.index);
757 }
758 
759 static void
760 BlockDNSErrHandler(DWORD err, const char *msg)
761 {
762  TCHAR buf[256];
763  LPCTSTR err_str;
764 
765  if (!err)
766  {
767  return;
768  }
769 
770  err_str = TEXT("Unknown Win32 Error");
771 
772  if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM
773  | FORMAT_MESSAGE_ARGUMENT_ARRAY,
774  NULL, err, 0, buf, sizeof(buf), NULL))
775  {
776  err_str = buf;
777  }
778 
779 #ifdef UNICODE
780  MsgToEventLog(M_ERR, L"%S (status = %lu): %s", msg, err, err_str);
781 #else
782  MsgToEventLog(M_ERR, "%s (status = %lu): %s", msg, err, err_str);
783 #endif
784 
785 }
786 
787 /* Use an always-true match_fn to get the head of the list */
788 static BOOL
789 CmpEngine(LPVOID item, LPVOID any)
790 {
791  return TRUE;
792 }
793 
794 static DWORD
796 {
797  DWORD err = 0;
798  block_dns_data_t *interface_data;
799  HANDLE engine = NULL;
800  LPCWSTR exe_path;
801 
802 #ifdef UNICODE
803  exe_path = settings.exe_path;
804 #else
805  WCHAR wide_path[MAX_PATH];
806  MultiByteToWideChar(CP_UTF8, 0, settings.exe_path, MAX_PATH, wide_path, MAX_PATH);
807  exe_path = wide_path;
808 #endif
809 
810  if (msg->header.type == msg_add_block_dns)
811  {
812  err = add_block_dns_filters(&engine, msg->iface.index, exe_path, BlockDNSErrHandler);
813  if (!err)
814  {
815  interface_data = malloc(sizeof(block_dns_data_t));
816  if (!interface_data)
817  {
818  return ERROR_OUTOFMEMORY;
819  }
820  interface_data->engine = engine;
821  interface_data->index = msg->iface.index;
822  int is_auto = 0;
823  interface_data->metric_v4 = get_interface_metric(msg->iface.index,
824  AF_INET, &is_auto);
825  if (is_auto)
826  {
827  interface_data->metric_v4 = 0;
828  }
829  interface_data->metric_v6 = get_interface_metric(msg->iface.index,
830  AF_INET6, &is_auto);
831  if (is_auto)
832  {
833  interface_data->metric_v6 = 0;
834  }
835  err = AddListItem(&(*lists)[block_dns], interface_data);
836  if (!err)
837  {
838  err = set_interface_metric(msg->iface.index, AF_INET,
840  if (!err)
841  {
842  set_interface_metric(msg->iface.index, AF_INET6,
844  }
845  }
846  }
847  }
848  else
849  {
850  interface_data = RemoveListItem(&(*lists)[block_dns], CmpEngine, NULL);
851  if (interface_data)
852  {
853  engine = interface_data->engine;
854  err = delete_block_dns_filters(engine);
855  engine = NULL;
856  if (interface_data->metric_v4 >= 0)
857  {
858  set_interface_metric(msg->iface.index, AF_INET,
859  interface_data->metric_v4);
860  }
861  if (interface_data->metric_v6 >= 0)
862  {
863  set_interface_metric(msg->iface.index, AF_INET6,
864  interface_data->metric_v6);
865  }
866  free(interface_data);
867  }
868  else
869  {
870  MsgToEventLog(M_ERR, TEXT("No previous block DNS filters to delete"));
871  }
872  }
873 
874  if (err && engine)
875  {
876  delete_block_dns_filters(engine);
877  }
878 
879  return err;
880 }
881 
882 /*
883  * Execute a command and return its exit code. If timeout > 0, terminate
884  * the process if still running after timeout milliseconds. In that case
885  * the return value is the windows error code WAIT_TIMEOUT = 0x102
886  */
887 static DWORD
888 ExecCommand(const WCHAR *argv0, const WCHAR *cmdline, DWORD timeout)
889 {
890  DWORD exit_code;
891  STARTUPINFOW si;
892  PROCESS_INFORMATION pi;
893  DWORD proc_flags = CREATE_NO_WINDOW|CREATE_UNICODE_ENVIRONMENT;
894  WCHAR *cmdline_dup = NULL;
895 
896  ZeroMemory(&si, sizeof(si));
897  ZeroMemory(&pi, sizeof(pi));
898 
899  si.cb = sizeof(si);
900 
901  /* CreateProcess needs a modifiable cmdline: make a copy */
902  cmdline_dup = wcsdup(cmdline);
903  if (cmdline_dup && CreateProcessW(argv0, cmdline_dup, NULL, NULL, FALSE,
904  proc_flags, NULL, NULL, &si, &pi) )
905  {
906  WaitForSingleObject(pi.hProcess, timeout ? timeout : INFINITE);
907  if (!GetExitCodeProcess(pi.hProcess, &exit_code))
908  {
909  MsgToEventLog(M_SYSERR, TEXT("ExecCommand: Error getting exit_code:"));
910  exit_code = GetLastError();
911  }
912  else if (exit_code == STILL_ACTIVE)
913  {
914  exit_code = WAIT_TIMEOUT; /* Windows error code 0x102 */
915 
916  /* kill without impunity */
917  TerminateProcess(pi.hProcess, exit_code);
918  MsgToEventLog(M_ERR, TEXT("ExecCommand: \"%s %s\" killed after timeout"),
919  argv0, cmdline);
920  }
921  else if (exit_code)
922  {
923  MsgToEventLog(M_ERR, TEXT("ExecCommand: \"%s %s\" exited with status = %lu"),
924  argv0, cmdline, exit_code);
925  }
926  else
927  {
928  MsgToEventLog(M_INFO, TEXT("ExecCommand: \"%s %s\" completed"), argv0, cmdline);
929  }
930 
931  CloseHandle(pi.hProcess);
932  CloseHandle(pi.hThread);
933  }
934  else
935  {
936  exit_code = GetLastError();
937  MsgToEventLog(M_SYSERR, TEXT("ExecCommand: could not run \"%s %s\" :"),
938  argv0, cmdline);
939  }
940 
941  free(cmdline_dup);
942  return exit_code;
943 }
944 
945 /*
946  * Entry point for register-dns thread.
947  */
948 static DWORD WINAPI
949 RegisterDNS(LPVOID unused)
950 {
951  DWORD err;
952  size_t i;
953  DWORD timeout = RDNS_TIMEOUT * 1000; /* in milliseconds */
954 
955  /* path of ipconfig command */
956  WCHAR ipcfg[MAX_PATH];
957 
958  struct
959  {
960  WCHAR *argv0;
961  WCHAR *cmdline;
962  DWORD timeout;
963  } cmds [] = {
964  { ipcfg, L"ipconfig /flushdns", timeout },
965  { ipcfg, L"ipconfig /registerdns", timeout },
966  };
967 
968  HANDLE wait_handles[2] = {rdns_semaphore, exit_event};
969 
970  openvpn_swprintf(ipcfg, MAX_PATH, L"%s\\%s", get_win_sys_path(), L"ipconfig.exe");
971 
972  if (WaitForMultipleObjects(2, wait_handles, FALSE, timeout) == WAIT_OBJECT_0)
973  {
974  /* Semaphore locked */
975  for (i = 0; i < _countof(cmds); ++i)
976  {
977  ExecCommand(cmds[i].argv0, cmds[i].cmdline, cmds[i].timeout);
978  }
979  err = 0;
980  if (!ReleaseSemaphore(rdns_semaphore, 1, NULL) )
981  {
982  err = MsgToEventLog(M_SYSERR, TEXT("RegisterDNS: Failed to release regsiter-dns semaphore:"));
983  }
984  }
985  else
986  {
987  MsgToEventLog(M_ERR, TEXT("RegisterDNS: Failed to lock register-dns semaphore"));
988  err = ERROR_SEM_TIMEOUT; /* Windows error code 0x79 */
989  }
990  return err;
991 }
992 
993 static DWORD
995 {
996  DWORD err;
997  HANDLE thread = NULL;
998 
999  /* Delegate this job to a sub-thread */
1000  thread = CreateThread(NULL, 0, RegisterDNS, NULL, 0, NULL);
1001 
1002  /*
1003  * We don't add these thread handles to the undo list -- the thread and
1004  * processes it spawns are all supposed to terminate or timeout by themselves.
1005  */
1006  if (thread)
1007  {
1008  err = 0;
1009  CloseHandle(thread);
1010  }
1011  else
1012  {
1013  err = GetLastError();
1014  }
1015 
1016  return err;
1017 }
1018 
1028 static DWORD
1029 netsh_dns_cmd(const wchar_t *action, const wchar_t *proto, const wchar_t *if_name, const wchar_t *addr)
1030 {
1031  DWORD err = 0;
1032  int timeout = 30000; /* in msec */
1033  wchar_t argv0[MAX_PATH];
1034  wchar_t *cmdline = NULL;
1035 
1036  if (!addr)
1037  {
1038  if (wcscmp(action, L"delete") == 0)
1039  {
1040  addr = L"all";
1041  }
1042  else /* nothing to do -- return success*/
1043  {
1044  goto out;
1045  }
1046  }
1047 
1048  /* Path of netsh */
1049  swprintf(argv0, _countof(argv0), L"%s\\%s", get_win_sys_path(), L"netsh.exe");
1050  argv0[_countof(argv0) - 1] = L'\0';
1051 
1052  /* cmd template:
1053  * netsh interface $proto $action dns $if_name $addr [validate=no]
1054  */
1055  const wchar_t *fmt = L"netsh interface %s %s dns \"%s\" %s";
1056 
1057  /* max cmdline length in wchars -- include room for worst case and some */
1058  size_t ncmdline = wcslen(fmt) + wcslen(if_name) + wcslen(addr) + 32 + 1;
1059  cmdline = malloc(ncmdline*sizeof(wchar_t));
1060  if (!cmdline)
1061  {
1062  err = ERROR_OUTOFMEMORY;
1063  goto out;
1064  }
1065 
1066  openvpn_sntprintf(cmdline, ncmdline, fmt, proto, action, if_name, addr);
1067 
1068  if (IsWindows7OrGreater())
1069  {
1070  wcsncat(cmdline, L" validate=no", ncmdline - wcslen(cmdline) - 1);
1071  }
1072  err = ExecCommand(argv0, cmdline, timeout);
1073 
1074 out:
1075  free(cmdline);
1076  return err;
1077 }
1078 
1087 static DWORD
1088 wmic_nicconfig_cmd(const wchar_t *action, const NET_IFINDEX if_index,
1089  const wchar_t *data)
1090 {
1091  DWORD err = 0;
1092  wchar_t argv0[MAX_PATH];
1093  wchar_t *cmdline = NULL;
1094  int timeout = 10000; /* in msec */
1095 
1096  swprintf(argv0, _countof(argv0), L"%s\\%s", get_win_sys_path(), L"wbem\\wmic.exe");
1097  argv0[_countof(argv0) - 1] = L'\0';
1098 
1099  const wchar_t *fmt;
1100  /* comma separated list must be enclosed in parenthesis */
1101  if (data && wcschr(data, L','))
1102  {
1103  fmt = L"wmic nicconfig where (InterfaceIndex=%ld) call %s (%s)";
1104  }
1105  else
1106  {
1107  fmt = L"wmic nicconfig where (InterfaceIndex=%ld) call %s %s";
1108  }
1109 
1110  size_t ncmdline = wcslen(fmt) + 20 + wcslen(action) /* max 20 for ifindex */
1111  + (data ? wcslen(data) + 1 : 1);
1112  cmdline = malloc(ncmdline*sizeof(wchar_t));
1113  if (!cmdline)
1114  {
1115  return ERROR_OUTOFMEMORY;
1116  }
1117 
1118  openvpn_sntprintf(cmdline, ncmdline, fmt, if_index, action,
1119  data? data : L"");
1120  err = ExecCommand(argv0, cmdline, timeout);
1121 
1122  free(cmdline);
1123  return err;
1124 }
1125 
1126 /* Delete all IPv4 or IPv6 dns servers for an interface */
1127 static DWORD
1128 DeleteDNS(short family, wchar_t *if_name)
1129 {
1130  wchar_t *proto = (family == AF_INET6) ? L"ipv6" : L"ip";
1131  return netsh_dns_cmd(L"delete", proto, if_name, NULL);
1132 }
1133 
1134 /* Add an IPv4 or IPv6 dns server to an interface */
1135 static DWORD
1136 AddDNS(short family, wchar_t *if_name, wchar_t *addr)
1137 {
1138  wchar_t *proto = (family == AF_INET6) ? L"ipv6" : L"ip";
1139  return netsh_dns_cmd(L"add", proto, if_name, addr);
1140 }
1141 
1142 static BOOL
1143 CmpWString(LPVOID item, LPVOID str)
1144 {
1145  return (wcscmp(item, str) == 0) ? TRUE : FALSE;
1146 }
1147 
1156 static DWORD
1157 SetDNSDomain(const wchar_t *if_name, const char *domain, undo_lists_t *lists)
1158 {
1159  NET_IFINDEX if_index;
1160 
1161  DWORD err = ConvertInterfaceNameToIndex(if_name, &if_index);
1162  if (err != ERROR_SUCCESS)
1163  {
1164  return err;
1165  }
1166 
1167  wchar_t *wdomain = utf8to16(domain); /* utf8 to wide-char */
1168  if (!wdomain)
1169  {
1170  return ERROR_OUTOFMEMORY;
1171  }
1172 
1173  /* free undo list if previously set */
1174  if (lists)
1175  {
1176  free(RemoveListItem(&(*lists)[undo_domain], CmpWString, (void *)if_name));
1177  }
1178 
1179  err = wmic_nicconfig_cmd(L"SetDNSDomain", if_index, wdomain);
1180 
1181  /* Add to undo list if domain is non-empty */
1182  if (err == 0 && wdomain[0] && lists)
1183  {
1184  wchar_t *tmp_name = wcsdup(if_name);
1185  if (!tmp_name || AddListItem(&(*lists)[undo_domain], tmp_name))
1186  {
1187  free(tmp_name);
1188  err = ERROR_OUTOFMEMORY;
1189  }
1190  }
1191 
1192  free(wdomain);
1193  return err;
1194 }
1195 
1196 static DWORD
1198 {
1199  DWORD err = 0;
1200  wchar_t addr[46]; /* large enough to hold string representation of an ipv4 / ipv6 address */
1201  undo_type_t undo_type = (msg->family == AF_INET6) ? undo_dns4 : undo_dns6;
1202  int addr_len = msg->addr_len;
1203 
1204  /* sanity check */
1205  if (addr_len > _countof(msg->addr))
1206  {
1207  addr_len = _countof(msg->addr);
1208  }
1209 
1210  if (!msg->iface.name[0]) /* interface name is required */
1211  {
1212  return ERROR_MESSAGE_DATA;
1213  }
1214 
1215  /* use a non-const reference with limited scope to enforce null-termination of strings from client */
1216  {
1217  dns_cfg_message_t *msgptr = (dns_cfg_message_t *) msg;
1218  msgptr->iface.name[_countof(msg->iface.name)-1] = '\0';
1219  msgptr->domains[_countof(msg->domains)-1] = '\0';
1220  }
1221 
1222  wchar_t *wide_name = utf8to16(msg->iface.name); /* utf8 to wide-char */
1223  if (!wide_name)
1224  {
1225  return ERROR_OUTOFMEMORY;
1226  }
1227 
1228  /* We delete all current addresses before adding any
1229  * OR if the message type is del_dns_cfg
1230  */
1231  if (addr_len > 0 || msg->header.type == msg_del_dns_cfg)
1232  {
1233  err = DeleteDNS(msg->family, wide_name);
1234  if (err)
1235  {
1236  goto out;
1237  }
1238  free(RemoveListItem(&(*lists)[undo_type], CmpWString, wide_name));
1239  }
1240 
1241  if (msg->header.type == msg_del_dns_cfg)
1242  {
1243  if (msg->domains[0])
1244  {
1245  /* setting an empty domain removes any previous value */
1246  err = SetDNSDomain(wide_name, "", lists);
1247  }
1248  goto out; /* job done */
1249  }
1250 
1251  for (int i = 0; i < addr_len; ++i)
1252  {
1253  if (msg->family == AF_INET6)
1254  {
1255  RtlIpv6AddressToStringW(&msg->addr[i].ipv6, addr);
1256  }
1257  else
1258  {
1259  RtlIpv4AddressToStringW(&msg->addr[i].ipv4, addr);
1260  }
1261  err = AddDNS(msg->family, wide_name, addr);
1262  if (i == 0 && err)
1263  {
1264  goto out;
1265  }
1266  /* We do not check for duplicate addresses, so any error in adding
1267  * additional addresses is ignored.
1268  */
1269  }
1270 
1271  err = 0;
1272 
1273  if (msg->addr_len > 0)
1274  {
1275  wchar_t *tmp_name = wcsdup(wide_name);
1276  if (!tmp_name || AddListItem(&(*lists)[undo_type], tmp_name))
1277  {
1278  free(tmp_name);
1279  DeleteDNS(msg->family, wide_name);
1280  err = ERROR_OUTOFMEMORY;
1281  goto out;
1282  }
1283  }
1284 
1285  if (msg->domains[0])
1286  {
1287  err = SetDNSDomain(wide_name, msg->domains, lists);
1288  }
1289 
1290 out:
1291  free(wide_name);
1292  return err;
1293 }
1294 
1295 static DWORD
1297 {
1298  DWORD err = 0;
1299  DWORD timeout = 5000; /* in milli seconds */
1300  wchar_t argv0[MAX_PATH];
1301 
1302  /* Path of netsh */
1303  swprintf(argv0, _countof(argv0), L"%s\\%s", get_win_sys_path(), L"netsh.exe");
1304  argv0[_countof(argv0) - 1] = L'\0';
1305 
1306  /* cmd template:
1307  * netsh interface ipv4 set address name=$if_index source=dhcp
1308  */
1309  const wchar_t *fmt = L"netsh interface ipv4 set address name=\"%d\" source=dhcp";
1310 
1311  /* max cmdline length in wchars -- include room for if index:
1312  * 10 chars for 32 bit int in decimal and +1 for NUL
1313  */
1314  size_t ncmdline = wcslen(fmt) + 10 + 1;
1315  wchar_t *cmdline = malloc(ncmdline*sizeof(wchar_t));
1316  if (!cmdline)
1317  {
1318  err = ERROR_OUTOFMEMORY;
1319  return err;
1320  }
1321 
1322  openvpn_sntprintf(cmdline, ncmdline, fmt, dhcp->iface.index);
1323 
1324  err = ExecCommand(argv0, cmdline, timeout);
1325 
1326  /* Note: This could fail if dhcp is already enabled, so the caller
1327  * may not want to treat errors as FATAL.
1328  */
1329 
1330  free(cmdline);
1331  return err;
1332 }
1333 
1334 static DWORD
1335 OvpnDuplicateHandle(HANDLE ovpn_proc, HANDLE orig_handle, HANDLE* new_handle)
1336 {
1337  DWORD err = ERROR_SUCCESS;
1338 
1339  if (!DuplicateHandle(ovpn_proc, orig_handle, GetCurrentProcess(), new_handle, 0, FALSE, DUPLICATE_SAME_ACCESS))
1340  {
1341  err = GetLastError();
1342  MsgToEventLog(M_SYSERR, TEXT("Could not duplicate handle"));
1343  return err;
1344  }
1345 
1346  return err;
1347 }
1348 
1349 static DWORD
1350 DuplicateAndMapRing(HANDLE ovpn_proc, HANDLE orig_handle, HANDLE *new_handle, struct tun_ring **ring)
1351 {
1352  DWORD err = ERROR_SUCCESS;
1353 
1354  err = OvpnDuplicateHandle(ovpn_proc, orig_handle, new_handle);
1355  if (err != ERROR_SUCCESS)
1356  {
1357  return err;
1358  }
1359  *ring = (struct tun_ring *)MapViewOfFile(*new_handle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(struct tun_ring));
1360  if (*ring == NULL)
1361  {
1362  err = GetLastError();
1363  MsgToEventLog(M_SYSERR, TEXT("Could not map shared memory"));
1364  return err;
1365  }
1366 
1367  return err;
1368 }
1369 
1370 static DWORD
1372  ring_buffer_handles_t *ring_buffer_handles)
1373 {
1374  DWORD err = 0;
1375  struct tun_ring *send_ring;
1376  struct tun_ring *receive_ring;
1377 
1378  CloseRingBufferHandles(ring_buffer_handles);
1379 
1380  err = OvpnDuplicateHandle(ovpn_proc, rrb->device, &ring_buffer_handles->device);
1381  if (err != ERROR_SUCCESS)
1382  {
1383  return err;
1384  }
1385 
1386  err = DuplicateAndMapRing(ovpn_proc, rrb->send_ring_handle, &ring_buffer_handles->send_ring_handle, &send_ring);
1387  if (err != ERROR_SUCCESS)
1388  {
1389  return err;
1390  }
1391 
1392  err = DuplicateAndMapRing(ovpn_proc, rrb->receive_ring_handle, &ring_buffer_handles->receive_ring_handle, &receive_ring);
1393  if (err != ERROR_SUCCESS)
1394  {
1395  return err;
1396  }
1397 
1398  err = OvpnDuplicateHandle(ovpn_proc, rrb->send_tail_moved, &ring_buffer_handles->send_tail_moved);
1399  if (err != ERROR_SUCCESS)
1400  {
1401  return err;
1402  }
1403 
1404  err = OvpnDuplicateHandle(ovpn_proc, rrb->receive_tail_moved, &ring_buffer_handles->receive_tail_moved);
1405  if (err != ERROR_SUCCESS)
1406  {
1407  return err;
1408  }
1409 
1410  if (!register_ring_buffers(ring_buffer_handles->device, send_ring, receive_ring,
1411  ring_buffer_handles->send_tail_moved, ring_buffer_handles->receive_tail_moved))
1412  {
1413  err = GetLastError();
1414  MsgToEventLog(M_SYSERR, TEXT("Could not register ring buffers"));
1415  }
1416 
1417  return err;
1418 }
1419 
1420 static DWORD
1422 {
1423  DWORD err = 0;
1424  MIB_IPINTERFACE_ROW ipiface;
1425  InitializeIpInterfaceEntry(&ipiface);
1426  ipiface.Family = mtu->family;
1427  ipiface.InterfaceIndex = mtu->iface.index;
1428  err = GetIpInterfaceEntry(&ipiface);
1429  if (err != NO_ERROR)
1430  {
1431  return err;
1432  }
1433  if (mtu->family == AF_INET)
1434  {
1435  ipiface.SitePrefixLength = 0;
1436  }
1437  ipiface.NlMtu = mtu->mtu;
1438 
1439  err = SetIpInterfaceEntry(&ipiface);
1440  return err;
1441 }
1442 
1443 static VOID
1444 HandleMessage(HANDLE pipe, HANDLE ovpn_proc, ring_buffer_handles_t *ring_buffer_handles,
1445  DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists)
1446 {
1447  DWORD read;
1448  union {
1449  message_header_t header;
1452  flush_neighbors_message_t flush_neighbors;
1454  dns_cfg_message_t dns;
1457  set_mtu_message_t mtu;
1458  } msg;
1459  ack_message_t ack = {
1460  .header = {
1462  .size = sizeof(ack),
1463  .message_id = -1
1464  },
1465  .error_number = ERROR_MESSAGE_DATA
1466  };
1467 
1468  read = ReadPipeAsync(pipe, &msg, bytes, count, events);
1469  if (read != bytes || read < sizeof(msg.header) || read != msg.header.size)
1470  {
1471  goto out;
1472  }
1473 
1474  ack.header.message_id = msg.header.message_id;
1475 
1476  switch (msg.header.type)
1477  {
1478  case msg_add_address:
1479  case msg_del_address:
1480  if (msg.header.size == sizeof(msg.address))
1481  {
1482  ack.error_number = HandleAddressMessage(&msg.address, lists);
1483  }
1484  break;
1485 
1486  case msg_add_route:
1487  case msg_del_route:
1488  if (msg.header.size == sizeof(msg.route))
1489  {
1490  ack.error_number = HandleRouteMessage(&msg.route, lists);
1491  }
1492  break;
1493 
1494  case msg_flush_neighbors:
1495  if (msg.header.size == sizeof(msg.flush_neighbors))
1496  {
1497  ack.error_number = HandleFlushNeighborsMessage(&msg.flush_neighbors);
1498  }
1499  break;
1500 
1501  case msg_add_block_dns:
1502  case msg_del_block_dns:
1503  if (msg.header.size == sizeof(msg.block_dns))
1504  {
1505  ack.error_number = HandleBlockDNSMessage(&msg.block_dns, lists);
1506  }
1507  break;
1508 
1509  case msg_register_dns:
1511  break;
1512 
1513  case msg_add_dns_cfg:
1514  case msg_del_dns_cfg:
1515  ack.error_number = HandleDNSConfigMessage(&msg.dns, lists);
1516  break;
1517 
1518  case msg_enable_dhcp:
1519  if (msg.header.size == sizeof(msg.dhcp))
1520  {
1522  }
1523  break;
1524 
1526  if (msg.header.size == sizeof(msg.rrb))
1527  {
1528  ack.error_number = HandleRegisterRingBuffers(&msg.rrb, ovpn_proc, ring_buffer_handles);
1529  }
1530  break;
1531 
1532  case msg_set_mtu:
1533  if (msg.header.size == sizeof(msg.mtu))
1534  {
1535  ack.error_number = HandleMTUMessage(&msg.mtu);
1536  }
1537  break;
1538 
1539  default:
1541  MsgToEventLog(MSG_FLAGS_ERROR, TEXT("Unknown message type %d"), msg.header.type);
1542  break;
1543  }
1544 
1545 out:
1546  WritePipeAsync(pipe, &ack, sizeof(ack), count, events);
1547 }
1548 
1549 
1550 static VOID
1552 {
1553  undo_type_t type;
1554  block_dns_data_t *interface_data;
1555  for (type = 0; type < _undo_type_max; type++)
1556  {
1557  list_item_t **pnext = &(*lists)[type];
1558  while (*pnext)
1559  {
1560  list_item_t *item = *pnext;
1561  switch (type)
1562  {
1563  case address:
1564  DeleteAddress(item->data);
1565  break;
1566 
1567  case route:
1568  DeleteRoute(item->data);
1569  break;
1570 
1571  case undo_dns4:
1572  DeleteDNS(AF_INET, item->data);
1573  break;
1574 
1575  case undo_dns6:
1576  DeleteDNS(AF_INET6, item->data);
1577  break;
1578 
1579  case undo_domain:
1580  SetDNSDomain(item->data, "", NULL);
1581  break;
1582 
1583  case block_dns:
1584  interface_data = (block_dns_data_t *)(item->data);
1585  delete_block_dns_filters(interface_data->engine);
1586  if (interface_data->metric_v4 >= 0)
1587  {
1588  set_interface_metric(interface_data->index, AF_INET,
1589  interface_data->metric_v4);
1590  }
1591  if (interface_data->metric_v6 >= 0)
1592  {
1593  set_interface_metric(interface_data->index, AF_INET6,
1594  interface_data->metric_v6);
1595  }
1596  break;
1597  }
1598 
1599  /* Remove from the list and free memory */
1600  *pnext = item->next;
1601  free(item->data);
1602  free(item);
1603  }
1604  }
1605 }
1606 
1607 static DWORD WINAPI
1608 RunOpenvpn(LPVOID p)
1609 {
1610  HANDLE pipe = p;
1611  HANDLE ovpn_pipe = NULL, svc_pipe = NULL;
1612  PTOKEN_USER svc_user = NULL, ovpn_user = NULL;
1613  HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL;
1614  HANDLE stdin_read = NULL, stdin_write = NULL;
1615  HANDLE stdout_write = NULL;
1616  DWORD pipe_mode, len, exit_code = 0;
1617  STARTUP_DATA sud = { 0, 0, 0 };
1618  STARTUPINFOW startup_info;
1619  PROCESS_INFORMATION proc_info;
1620  LPVOID user_env = NULL;
1621  TCHAR ovpn_pipe_name[256]; /* The entire pipe name string can be up to 256 characters long according to MSDN. */
1622  LPCWSTR exe_path;
1623  WCHAR *cmdline = NULL;
1624  size_t cmdline_size;
1625  undo_lists_t undo_lists;
1626  ring_buffer_handles_t ring_buffer_handles;
1627  WCHAR errmsg[512] = L"";
1628 
1629  SECURITY_ATTRIBUTES inheritable = {
1630  .nLength = sizeof(inheritable),
1631  .lpSecurityDescriptor = NULL,
1632  .bInheritHandle = TRUE
1633  };
1634 
1635  PACL ovpn_dacl;
1636  EXPLICIT_ACCESS ea[2];
1637  SECURITY_DESCRIPTOR ovpn_sd;
1638  SECURITY_ATTRIBUTES ovpn_sa = {
1639  .nLength = sizeof(ovpn_sa),
1640  .lpSecurityDescriptor = &ovpn_sd,
1641  .bInheritHandle = FALSE
1642  };
1643 
1644  ZeroMemory(&ea, sizeof(ea));
1645  ZeroMemory(&startup_info, sizeof(startup_info));
1646  ZeroMemory(&undo_lists, sizeof(undo_lists));
1647  ZeroMemory(&proc_info, sizeof(proc_info));
1648  ZeroMemory(&ring_buffer_handles, sizeof(ring_buffer_handles));
1649 
1650  if (!GetStartupData(pipe, &sud))
1651  {
1652  goto out;
1653  }
1654 
1655  if (!InitializeSecurityDescriptor(&ovpn_sd, SECURITY_DESCRIPTOR_REVISION))
1656  {
1657  ReturnLastError(pipe, L"InitializeSecurityDescriptor");
1658  goto out;
1659  }
1660 
1661  /* Get SID of user the service is running under */
1662  if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &svc_token))
1663  {
1664  ReturnLastError(pipe, L"OpenProcessToken");
1665  goto out;
1666  }
1667  len = 0;
1668  while (!GetTokenInformation(svc_token, TokenUser, svc_user, len, &len))
1669  {
1670  if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1671  {
1672  ReturnLastError(pipe, L"GetTokenInformation (service token)");
1673  goto out;
1674  }
1675  free(svc_user);
1676  svc_user = malloc(len);
1677  if (svc_user == NULL)
1678  {
1679  ReturnLastError(pipe, L"malloc (service token user)");
1680  goto out;
1681  }
1682  }
1683  if (!IsValidSid(svc_user->User.Sid))
1684  {
1685  ReturnLastError(pipe, L"IsValidSid (service token user)");
1686  goto out;
1687  }
1688 
1689  if (!ImpersonateNamedPipeClient(pipe))
1690  {
1691  ReturnLastError(pipe, L"ImpersonateNamedPipeClient");
1692  goto out;
1693  }
1694  if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &imp_token))
1695  {
1696  ReturnLastError(pipe, L"OpenThreadToken");
1697  goto out;
1698  }
1699  len = 0;
1700  while (!GetTokenInformation(imp_token, TokenUser, ovpn_user, len, &len))
1701  {
1702  if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1703  {
1704  ReturnLastError(pipe, L"GetTokenInformation (impersonation token)");
1705  goto out;
1706  }
1707  free(ovpn_user);
1708  ovpn_user = malloc(len);
1709  if (ovpn_user == NULL)
1710  {
1711  ReturnLastError(pipe, L"malloc (impersonation token user)");
1712  goto out;
1713  }
1714  }
1715  if (!IsValidSid(ovpn_user->User.Sid))
1716  {
1717  ReturnLastError(pipe, L"IsValidSid (impersonation token user)");
1718  goto out;
1719  }
1720 
1721  /*
1722  * Only authorized users are allowed to use any command line options or
1723  * have the config file in locations other than the global config directory.
1724  *
1725  * Check options are white-listed and config is in the global directory
1726  * OR user is authorized to run any config.
1727  */
1728  if (!ValidateOptions(pipe, sud.directory, sud.options, errmsg, _countof(errmsg))
1729  && !IsAuthorizedUser(ovpn_user->User.Sid, imp_token, settings.ovpn_admin_group))
1730  {
1731  ReturnError(pipe, ERROR_STARTUP_DATA, errmsg, 1, &exit_event);
1732  goto out;
1733  }
1734 
1735  /* OpenVPN process DACL entry for access by service and user */
1736  ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
1737  ea[0].grfAccessMode = SET_ACCESS;
1738  ea[0].grfInheritance = NO_INHERITANCE;
1739  ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
1740  ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
1741  ea[0].Trustee.ptstrName = (LPTSTR) svc_user->User.Sid;
1742  ea[1].grfAccessPermissions = READ_CONTROL | SYNCHRONIZE | PROCESS_VM_READ
1743  |SYNCHRONIZE | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION;
1744  ea[1].grfAccessMode = SET_ACCESS;
1745  ea[1].grfInheritance = NO_INHERITANCE;
1746  ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
1747  ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
1748  ea[1].Trustee.ptstrName = (LPTSTR) ovpn_user->User.Sid;
1749 
1750  /* Set owner and DACL of OpenVPN security descriptor */
1751  if (!SetSecurityDescriptorOwner(&ovpn_sd, svc_user->User.Sid, FALSE))
1752  {
1753  ReturnLastError(pipe, L"SetSecurityDescriptorOwner");
1754  goto out;
1755  }
1756  if (SetEntriesInAcl(2, ea, NULL, &ovpn_dacl) != ERROR_SUCCESS)
1757  {
1758  ReturnLastError(pipe, L"SetEntriesInAcl");
1759  goto out;
1760  }
1761  if (!SetSecurityDescriptorDacl(&ovpn_sd, TRUE, ovpn_dacl, FALSE))
1762  {
1763  ReturnLastError(pipe, L"SetSecurityDescriptorDacl");
1764  goto out;
1765  }
1766 
1767  /* Create primary token from impersonation token */
1768  if (!DuplicateTokenEx(imp_token, TOKEN_ALL_ACCESS, NULL, 0, TokenPrimary, &pri_token))
1769  {
1770  ReturnLastError(pipe, L"DuplicateTokenEx");
1771  goto out;
1772  }
1773 
1774  /* use /dev/null for stdout of openvpn (client should use --log for output) */
1775  stdout_write = CreateFile(_T("NUL"), GENERIC_WRITE, FILE_SHARE_WRITE,
1776  &inheritable, OPEN_EXISTING, 0, NULL);
1777  if (stdout_write == INVALID_HANDLE_VALUE)
1778  {
1779  ReturnLastError(pipe, L"CreateFile for stdout");
1780  goto out;
1781  }
1782 
1783  if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0)
1784  || !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0))
1785  {
1786  ReturnLastError(pipe, L"CreatePipe");
1787  goto out;
1788  }
1789 
1790  openvpn_sntprintf(ovpn_pipe_name, _countof(ovpn_pipe_name),
1791  TEXT("\\\\.\\pipe\\" PACKAGE "%s\\service_%lu"), service_instance, GetCurrentThreadId());
1792  ovpn_pipe = CreateNamedPipe(ovpn_pipe_name,
1793  PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
1794  PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 128, 128, 0, NULL);
1795  if (ovpn_pipe == INVALID_HANDLE_VALUE)
1796  {
1797  ReturnLastError(pipe, L"CreateNamedPipe");
1798  goto out;
1799  }
1800 
1801  svc_pipe = CreateFile(ovpn_pipe_name, GENERIC_READ | GENERIC_WRITE, 0,
1802  &inheritable, OPEN_EXISTING, 0, NULL);
1803  if (svc_pipe == INVALID_HANDLE_VALUE)
1804  {
1805  ReturnLastError(pipe, L"CreateFile");
1806  goto out;
1807  }
1808 
1809  pipe_mode = PIPE_READMODE_MESSAGE;
1810  if (!SetNamedPipeHandleState(svc_pipe, &pipe_mode, NULL, NULL))
1811  {
1812  ReturnLastError(pipe, L"SetNamedPipeHandleState");
1813  goto out;
1814  }
1815 
1816  cmdline_size = wcslen(sud.options) + 128;
1817  cmdline = malloc(cmdline_size * sizeof(*cmdline));
1818  if (cmdline == NULL)
1819  {
1820  ReturnLastError(pipe, L"malloc");
1821  goto out;
1822  }
1823  openvpn_sntprintf(cmdline, cmdline_size, L"openvpn %s --msg-channel %lu",
1824  sud.options, svc_pipe);
1825 
1826  if (!CreateEnvironmentBlock(&user_env, imp_token, FALSE))
1827  {
1828  ReturnLastError(pipe, L"CreateEnvironmentBlock");
1829  goto out;
1830  }
1831 
1832  startup_info.cb = sizeof(startup_info);
1833  startup_info.lpDesktop = L"winsta0\\default";
1834  startup_info.dwFlags = STARTF_USESTDHANDLES;
1835  startup_info.hStdInput = stdin_read;
1836  startup_info.hStdOutput = stdout_write;
1837  startup_info.hStdError = stdout_write;
1838 
1839 #ifdef UNICODE
1840  exe_path = settings.exe_path;
1841 #else
1842  WCHAR wide_path[MAX_PATH];
1843  MultiByteToWideChar(CP_UTF8, 0, settings.exe_path, MAX_PATH, wide_path, MAX_PATH);
1844  exe_path = wide_path;
1845 #endif
1846 
1847  /* TODO: make sure HKCU is correct or call LoadUserProfile() */
1848  if (!CreateProcessAsUserW(pri_token, exe_path, cmdline, &ovpn_sa, NULL, TRUE,
1849  settings.priority | CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT,
1850  user_env, sud.directory, &startup_info, &proc_info))
1851  {
1852  ReturnLastError(pipe, L"CreateProcessAsUser");
1853  goto out;
1854  }
1855 
1856  if (!RevertToSelf())
1857  {
1858  TerminateProcess(proc_info.hProcess, 1);
1859  ReturnLastError(pipe, L"RevertToSelf");
1860  goto out;
1861  }
1862 
1863  ReturnProcessId(pipe, proc_info.dwProcessId, 1, &exit_event);
1864 
1865  CloseHandleEx(&stdout_write);
1866  CloseHandleEx(&stdin_read);
1867  CloseHandleEx(&svc_pipe);
1868 
1869  DWORD input_size = WideCharToMultiByte(CP_UTF8, 0, sud.std_input, -1, NULL, 0, NULL, NULL);
1870  LPSTR input = NULL;
1871  if (input_size && (input = malloc(input_size)))
1872  {
1873  DWORD written;
1874  WideCharToMultiByte(CP_UTF8, 0, sud.std_input, -1, input, input_size, NULL, NULL);
1875  WriteFile(stdin_write, input, (DWORD)strlen(input), &written, NULL);
1876  free(input);
1877  }
1878 
1879  while (TRUE)
1880  {
1881  DWORD bytes = PeekNamedPipeAsync(ovpn_pipe, 1, &exit_event);
1882  if (bytes == 0)
1883  {
1884  break;
1885  }
1886 
1887  HandleMessage(ovpn_pipe, proc_info.hProcess, &ring_buffer_handles, bytes, 1, &exit_event, &undo_lists);
1888  }
1889 
1890  WaitForSingleObject(proc_info.hProcess, IO_TIMEOUT);
1891  GetExitCodeProcess(proc_info.hProcess, &exit_code);
1892  if (exit_code == STILL_ACTIVE)
1893  {
1894  TerminateProcess(proc_info.hProcess, 1);
1895  }
1896  else if (exit_code != 0)
1897  {
1898  WCHAR buf[256];
1899  openvpn_swprintf(buf, _countof(buf),
1900  L"OpenVPN exited with error: exit code = %lu", exit_code);
1901  ReturnError(pipe, ERROR_OPENVPN_STARTUP, buf, 1, &exit_event);
1902  }
1903  Undo(&undo_lists);
1904 
1905 out:
1906  FlushFileBuffers(pipe);
1907  DisconnectNamedPipe(pipe);
1908 
1909  free(ovpn_user);
1910  free(svc_user);
1911  free(cmdline);
1912  DestroyEnvironmentBlock(user_env);
1913  FreeStartupData(&sud);
1914  CloseRingBufferHandles(&ring_buffer_handles);
1915  CloseHandleEx(&proc_info.hProcess);
1916  CloseHandleEx(&proc_info.hThread);
1917  CloseHandleEx(&stdin_read);
1918  CloseHandleEx(&stdin_write);
1919  CloseHandleEx(&stdout_write);
1920  CloseHandleEx(&svc_token);
1921  CloseHandleEx(&imp_token);
1922  CloseHandleEx(&pri_token);
1923  CloseHandleEx(&ovpn_pipe);
1924  CloseHandleEx(&svc_pipe);
1925  CloseHandleEx(&pipe);
1926 
1927  return 0;
1928 }
1929 
1930 
1931 static DWORD WINAPI
1932 ServiceCtrlInteractive(DWORD ctrl_code, DWORD event, LPVOID data, LPVOID ctx)
1933 {
1934  SERVICE_STATUS *status = ctx;
1935  switch (ctrl_code)
1936  {
1937  case SERVICE_CONTROL_STOP:
1938  status->dwCurrentState = SERVICE_STOP_PENDING;
1939  ReportStatusToSCMgr(service, status);
1940  if (exit_event)
1941  {
1942  SetEvent(exit_event);
1943  }
1944  return NO_ERROR;
1945 
1946  case SERVICE_CONTROL_INTERROGATE:
1947  return NO_ERROR;
1948 
1949  default:
1950  return ERROR_CALL_NOT_IMPLEMENTED;
1951  }
1952 }
1953 
1954 
1955 static HANDLE
1957 {
1958  TCHAR pipe_name[256]; /* The entire pipe name string can be up to 256 characters long according to MSDN. */
1959  HANDLE pipe = NULL;
1960  PACL old_dacl, new_dacl;
1961  PSECURITY_DESCRIPTOR sd;
1962  static EXPLICIT_ACCESS ea[2];
1963  static BOOL initialized = FALSE;
1964  DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED;
1965 
1966  if (!initialized)
1967  {
1968  PSID everyone, anonymous;
1969 
1970  ConvertStringSidToSid(TEXT("S-1-1-0"), &everyone);
1971  ConvertStringSidToSid(TEXT("S-1-5-7"), &anonymous);
1972 
1973  ea[0].grfAccessPermissions = FILE_GENERIC_WRITE;
1974  ea[0].grfAccessMode = GRANT_ACCESS;
1975  ea[0].grfInheritance = NO_INHERITANCE;
1976  ea[0].Trustee.pMultipleTrustee = NULL;
1977  ea[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
1978  ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
1979  ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
1980  ea[0].Trustee.ptstrName = (LPTSTR) everyone;
1981 
1982  ea[1].grfAccessPermissions = 0;
1983  ea[1].grfAccessMode = REVOKE_ACCESS;
1984  ea[1].grfInheritance = NO_INHERITANCE;
1985  ea[1].Trustee.pMultipleTrustee = NULL;
1986  ea[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
1987  ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
1988  ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
1989  ea[1].Trustee.ptstrName = (LPTSTR) anonymous;
1990 
1991  flags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
1992  initialized = TRUE;
1993  }
1994 
1995  openvpn_sntprintf(pipe_name, _countof(pipe_name), TEXT("\\\\.\\pipe\\" PACKAGE "%s\\service"), service_instance);
1996  pipe = CreateNamedPipe(pipe_name, flags,
1997  PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
1998  PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, NULL);
1999  if (pipe == INVALID_HANDLE_VALUE)
2000  {
2001  MsgToEventLog(M_SYSERR, TEXT("Could not create named pipe"));
2002  return INVALID_HANDLE_VALUE;
2003  }
2004 
2005  if (GetSecurityInfo(pipe, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
2006  NULL, NULL, &old_dacl, NULL, &sd) != ERROR_SUCCESS)
2007  {
2008  MsgToEventLog(M_SYSERR, TEXT("Could not get pipe security info"));
2009  return CloseHandleEx(&pipe);
2010  }
2011 
2012  if (SetEntriesInAcl(2, ea, old_dacl, &new_dacl) != ERROR_SUCCESS)
2013  {
2014  MsgToEventLog(M_SYSERR, TEXT("Could not set entries in new acl"));
2015  return CloseHandleEx(&pipe);
2016  }
2017 
2018  if (SetSecurityInfo(pipe, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
2019  NULL, NULL, new_dacl, NULL) != ERROR_SUCCESS)
2020  {
2021  MsgToEventLog(M_SYSERR, TEXT("Could not set pipe security info"));
2022  return CloseHandleEx(&pipe);
2023  }
2024 
2025  return pipe;
2026 }
2027 
2028 
2029 static DWORD
2030 UpdateWaitHandles(LPHANDLE *handles_ptr, LPDWORD count,
2031  HANDLE io_event, HANDLE exit_event, list_item_t *threads)
2032 {
2033  static DWORD size = 10;
2034  static LPHANDLE handles = NULL;
2035  DWORD pos = 0;
2036 
2037  if (handles == NULL)
2038  {
2039  handles = malloc(size * sizeof(HANDLE));
2040  *handles_ptr = handles;
2041  if (handles == NULL)
2042  {
2043  return ERROR_OUTOFMEMORY;
2044  }
2045  }
2046 
2047  handles[pos++] = io_event;
2048 
2049  if (!threads)
2050  {
2051  handles[pos++] = exit_event;
2052  }
2053 
2054  while (threads)
2055  {
2056  if (pos == size)
2057  {
2058  LPHANDLE tmp;
2059  size += 10;
2060  tmp = realloc(handles, size * sizeof(HANDLE));
2061  if (tmp == NULL)
2062  {
2063  size -= 10;
2064  *count = pos;
2065  return ERROR_OUTOFMEMORY;
2066  }
2067  handles = tmp;
2068  *handles_ptr = handles;
2069  }
2070  handles[pos++] = threads->data;
2071  threads = threads->next;
2072  }
2073 
2074  *count = pos;
2075  return NO_ERROR;
2076 }
2077 
2078 
2079 static VOID
2080 FreeWaitHandles(LPHANDLE h)
2081 {
2082  free(h);
2083 }
2084 
2085 static BOOL
2086 CmpHandle(LPVOID item, LPVOID hnd)
2087 {
2088  return item == hnd;
2089 }
2090 
2091 
2092 VOID WINAPI
2093 ServiceStartInteractiveOwn(DWORD dwArgc, LPTSTR *lpszArgv)
2094 {
2095  status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
2096  ServiceStartInteractive(dwArgc, lpszArgv);
2097 }
2098 
2099 
2100 VOID WINAPI
2101 ServiceStartInteractive(DWORD dwArgc, LPTSTR *lpszArgv)
2102 {
2103  HANDLE pipe, io_event = NULL;
2104  OVERLAPPED overlapped;
2105  DWORD error = NO_ERROR;
2106  list_item_t *threads = NULL;
2107  PHANDLE handles = NULL;
2108  DWORD handle_count;
2109 
2110  service = RegisterServiceCtrlHandlerEx(interactive_service.name, ServiceCtrlInteractive, &status);
2111  if (!service)
2112  {
2113  return;
2114  }
2115 
2116  status.dwCurrentState = SERVICE_START_PENDING;
2117  status.dwServiceSpecificExitCode = NO_ERROR;
2118  status.dwWin32ExitCode = NO_ERROR;
2119  status.dwWaitHint = 3000;
2121 
2122  /* Read info from registry in key HKLM\SOFTWARE\OpenVPN */
2123  error = GetOpenvpnSettings(&settings);
2124  if (error != ERROR_SUCCESS)
2125  {
2126  goto out;
2127  }
2128 
2129  io_event = InitOverlapped(&overlapped);
2130  exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
2131  if (!exit_event || !io_event)
2132  {
2133  error = MsgToEventLog(M_SYSERR, TEXT("Could not create event"));
2134  goto out;
2135  }
2136 
2137  rdns_semaphore = CreateSemaphoreW(NULL, 1, 1, NULL);
2138  if (!rdns_semaphore)
2139  {
2140  error = MsgToEventLog(M_SYSERR, TEXT("Could not create semaphore for register-dns"));
2141  goto out;
2142  }
2143 
2144  error = UpdateWaitHandles(&handles, &handle_count, io_event, exit_event, threads);
2145  if (error != NO_ERROR)
2146  {
2147  goto out;
2148  }
2149 
2150  pipe = CreateClientPipeInstance();
2151  if (pipe == INVALID_HANDLE_VALUE)
2152  {
2153  goto out;
2154  }
2155 
2156  status.dwCurrentState = SERVICE_RUNNING;
2157  status.dwWaitHint = 0;
2159 
2160  while (TRUE)
2161  {
2162  if (ConnectNamedPipe(pipe, &overlapped) == FALSE
2163  && GetLastError() != ERROR_PIPE_CONNECTED
2164  && GetLastError() != ERROR_IO_PENDING)
2165  {
2166  MsgToEventLog(M_SYSERR, TEXT("Could not connect pipe"));
2167  break;
2168  }
2169 
2170  error = WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
2171  if (error == WAIT_OBJECT_0)
2172  {
2173  /* Client connected, spawn a worker thread for it */
2174  HANDLE next_pipe = CreateClientPipeInstance();
2175  HANDLE thread = CreateThread(NULL, 0, RunOpenvpn, pipe, CREATE_SUSPENDED, NULL);
2176  if (thread)
2177  {
2178  error = AddListItem(&threads, thread);
2179  if (!error)
2180  {
2181  error = UpdateWaitHandles(&handles, &handle_count, io_event, exit_event, threads);
2182  }
2183  if (error)
2184  {
2185  ReturnError(pipe, error, L"Insufficient resources to service new clients", 1, &exit_event);
2186  /* Update wait handles again after removing the last worker thread */
2187  RemoveListItem(&threads, CmpHandle, thread);
2188  UpdateWaitHandles(&handles, &handle_count, io_event, exit_event, threads);
2189  TerminateThread(thread, 1);
2190  CloseHandleEx(&thread);
2191  CloseHandleEx(&pipe);
2192  }
2193  else
2194  {
2195  ResumeThread(thread);
2196  }
2197  }
2198  else
2199  {
2200  CloseHandleEx(&pipe);
2201  }
2202 
2203  ResetOverlapped(&overlapped);
2204  pipe = next_pipe;
2205  }
2206  else
2207  {
2208  CancelIo(pipe);
2209  if (error == WAIT_FAILED)
2210  {
2211  MsgToEventLog(M_SYSERR, TEXT("WaitForMultipleObjects failed"));
2212  SetEvent(exit_event);
2213  /* Give some time for worker threads to exit and then terminate */
2214  Sleep(1000);
2215  break;
2216  }
2217  if (!threads)
2218  {
2219  /* exit event signaled */
2220  CloseHandleEx(&pipe);
2221  ResetEvent(exit_event);
2222  error = NO_ERROR;
2223  break;
2224  }
2225 
2226  /* Worker thread ended */
2227  HANDLE thread = RemoveListItem(&threads, CmpHandle, handles[error]);
2228  UpdateWaitHandles(&handles, &handle_count, io_event, exit_event, threads);
2229  CloseHandleEx(&thread);
2230  }
2231  }
2232 
2233 out:
2234  FreeWaitHandles(handles);
2235  CloseHandleEx(&io_event);
2238 
2239  status.dwCurrentState = SERVICE_STOPPED;
2240  status.dwWin32ExitCode = error;
2242 }
BOOL openvpn_sntprintf(LPTSTR str, size_t size, LPCTSTR format,...)
Definition: common.c:47
DWORD MsgToEventLog(DWORD flags, LPCTSTR format,...)
Definition: common.c:258
undo_type_t
Definition: interactive.c:88
struct in6_addr ipv6
Definition: openvpn-msg.h:54
static BOOL CmpRoute(LPVOID item, LPVOID route)
Definition: interactive.c:665
#define ERROR_MESSAGE_DATA
Definition: interactive.c:52
static BOOL CmpAddress(LPVOID item, LPVOID address)
Definition: interactive.c:587
static BOOL CmpEngine(LPVOID item, LPVOID any)
Definition: interactive.c:789
LPCTSTR service_instance
Definition: common.c:27
#define M_INFO
Definition: errlevel.h:55
message_header_t header
Definition: openvpn-msg.h:81
inet_address_t addr[4]
Definition: openvpn-msg.h:86
static DWORD HandleRegisterRingBuffers(const register_ring_buffers_message_t *rrb, HANDLE ovpn_proc, ring_buffer_handles_t *ring_buffer_handles)
Definition: interactive.c:1371
#define MSG_FLAGS_ERROR
Definition: service.h:44
DWORD delete_block_dns_filters(HANDLE engine_handle)
Definition: block_dns.c:330
inet_address_t prefix
Definition: openvpn-msg.h:73
TCHAR exe_path[MAX_PATH]
Definition: service.h:66
static VOID HandleMessage(HANDLE pipe, HANDLE ovpn_proc, ring_buffer_handles_t *ring_buffer_handles, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists)
Definition: interactive.c:1444
static BOOL ResetOverlapped(LPOVERLAPPED overlapped)
Definition: interactive.c:199
static bool match(const WIN32_FIND_DATA *find, LPCTSTR ext)
Definition: automatic.c:112
DWORD priority
Definition: service.h:71
BOOL CheckOption(const WCHAR *workdir, int argc, WCHAR *argv[], const settings_t *s)
Definition: validate.c:329
static HANDLE rdns_semaphore
Definition: interactive.c:59
#define ERROR_OPENVPN_STARTUP
Definition: interactive.c:50
#define realloc
Definition: cmocka.c:1891
TCHAR * name
Definition: service.h:58
static DWORD AsyncPipeOp(async_op_t op, HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
Definition: interactive.c:219
static DWORD SetDNSDomain(const wchar_t *if_name, const char *domain, undo_lists_t *lists)
Set interface specific DNS domain suffix.
Definition: interactive.c:1157
static DWORD DuplicateAndMapRing(HANDLE ovpn_proc, HANDLE orig_handle, HANDLE *new_handle, struct tun_ring **ring)
Definition: interactive.c:1350
inet_address_t address
Definition: openvpn-msg.h:65
#define SERVICE_DEPENDENCIES
Definition: service.h:39
#define BLOCK_DNS_IFACE_METRIC
Definition: block_dns.h:30
static VOID Undo(undo_lists_t *lists)
Definition: interactive.c:1551
int add(int a, int b)
interface_t iface
Definition: openvpn-msg.h:133
list flags
static DWORD ConvertInterfaceNameToIndex(const wchar_t *ifname, NET_IFINDEX *index)
Definition: interactive.c:569
static DWORD AddListItem(list_item_t **pfirst, LPVOID data)
Definition: interactive.c:116
WCHAR * std_input
Definition: interactive.c:76
BOOL(* match_fn_t)(LPVOID item, LPVOID ctx)
Definition: interactive.c:131
message_header_t header
Definition: openvpn-msg.h:71
static DWORD DeleteAddress(PMIB_UNICASTIPADDRESS_ROW addr_row)
Definition: interactive.c:593
openvpn_service_t interactive_service
Definition: interactive.c:64
WCHAR * options
Definition: interactive.c:75
int get_interface_metric(const NET_IFINDEX index, const ADDRESS_FAMILY family, int *is_auto)
Return interface metric value for the specified interface index.
Definition: block_dns.c:355
static VOID FreeStartupData(STARTUP_DATA *sud)
Definition: interactive.c:527
static VOID ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events)
Definition: interactive.c:316
static HANDLE CreateClientPipeInstance(VOID)
Definition: interactive.c:1956
inet_address_t gateway
Definition: openvpn-msg.h:75
static DWORD DeleteRoute(PMIB_IPFORWARD_ROW2 fwd_row)
Definition: interactive.c:671
#define malloc
Definition: cmocka.c:1795
static bool register_ring_buffers(HANDLE device, struct tun_ring *send_ring, struct tun_ring *receive_ring, HANDLE send_tail_moved, HANDLE receive_tail_moved)
Registers ring buffers used to exchange data between userspace openvpn process and wintun kernel driv...
Definition: ring_buffer.h:98
static DWORD HandleDNSConfigMessage(const dns_cfg_message_t *msg, undo_lists_t *lists)
Definition: interactive.c:1197
static DWORD HandleRegisterDNSMessage(void)
Definition: interactive.c:994
static DWORD InterfaceLuid(const char *iface_name, PNET_LUID luid)
Definition: interactive.c:551
#define PACKAGE_NAME
Definition: config.h:730
static VOID ReturnLastError(HANDLE pipe, LPCWSTR func)
Definition: interactive.c:359
struct _list_item * next
Definition: interactive.c:82
wchar_t * utf8to16(const char *utf8)
Definition: common.c:295
VOID WINAPI ServiceStartInteractive(DWORD dwArgc, LPTSTR *lpszArgv)
Definition: interactive.c:2101
message_type_t type
Definition: openvpn-msg.h:47
static DWORD OvpnDuplicateHandle(HANDLE ovpn_proc, HANDLE orig_handle, HANDLE *new_handle)
Definition: interactive.c:1335
char domains[512]
Definition: openvpn-msg.h:83
static int pos(char c)
Definition: base64.c:107
static VOID ReturnProcessId(HANDLE pipe, DWORD pid, DWORD count, LPHANDLE events)
Definition: interactive.c:301
LPVOID data
Definition: interactive.c:83
static SOCKADDR_INET sockaddr_inet(short family, inet_address_t *addr)
Definition: interactive.c:534
static SERVICE_STATUS_HANDLE service
Definition: interactive.c:55
DWORD add_block_dns_filters(HANDLE *engine_handle, int index, const WCHAR *exe_path, block_dns_msg_handler_t msg_handler)
Definition: block_dns.c:179
DWORD GetOpenvpnSettings(settings_t *s)
Definition: common.c:101
#define msg
Definition: error.h:173
static DWORD WINAPI RunOpenvpn(LPVOID p)
Definition: interactive.c:1608
char * get_win_sys_path(void)
Definition: win32.c:1209
#define RDNS_TIMEOUT
Definition: interactive.c:60
struct _list_item list_item_t
static DWORD ReadPipeAsync(HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
Definition: interactive.c:289
static DWORD HandleRouteMessage(route_message_t *msg, undo_lists_t *lists)
Definition: interactive.c:677
static DWORD netsh_dns_cmd(const wchar_t *action, const wchar_t *proto, const wchar_t *if_name, const wchar_t *addr)
Run the command: netsh interface $proto $action dns $if_name $addr [validate=no]. ...
Definition: interactive.c:1029
TCHAR ovpn_admin_group[MAX_NAME]
Definition: service.h:70
#define ERROR_MESSAGE_TYPE
Definition: interactive.c:53
async_op_t
Definition: interactive.c:212
static DWORD AddDNS(short family, wchar_t *if_name, wchar_t *addr)
Definition: interactive.c:1136
SECURITY_DESCRIPTOR sd
Definition: win32.h:61
message_header_t header
Definition: openvpn-msg.h:108
static DWORD ExecCommand(const WCHAR *argv0, const WCHAR *cmdline, DWORD timeout)
Definition: interactive.c:888
static BOOL IsOption(const WCHAR *o)
Definition: validate.h:42
interface_t iface
Definition: openvpn-msg.h:76
struct in_addr ipv4
Definition: openvpn-msg.h:53
static DWORD HandleBlockDNSMessage(const block_dns_message_t *msg, undo_lists_t *lists)
Definition: interactive.c:795
#define M_ERR
Definition: error.h:110
static DWORD HandleMTUMessage(const set_mtu_message_t *mtu)
Definition: interactive.c:1421
static DWORD WINAPI ServiceCtrlInteractive(DWORD ctrl_code, DWORD event, LPVOID data, LPVOID ctx)
Definition: interactive.c:1932
static DWORD WINAPI RegisterDNS(LPVOID unused)
Definition: interactive.c:949
char name[256]
Definition: openvpn-msg.h:59
interface_t iface
Definition: openvpn-msg.h:82
message_header_t header
Definition: openvpn-msg.h:63
VOID WINAPI ServiceStartInteractiveOwn(DWORD dwArgc, LPTSTR *lpszArgv)
Definition: interactive.c:2093
Definition: dhcp.h:53
DWORD set_interface_metric(const NET_IFINDEX index, const ADDRESS_FAMILY family, const ULONG metric)
Sets interface metric value for specified interface index.
Definition: block_dns.c:394
Wrapper structure for dynamically allocated memory.
Definition: buffer.h:60
static HANDLE CloseHandleEx(LPHANDLE handle)
Definition: interactive.c:158
static settings_t settings
Definition: interactive.c:58
#define IO_TIMEOUT
Definition: interactive.c:48
static BOOL GetStartupData(HANDLE pipe, STARTUP_DATA *sud)
Definition: interactive.c:451
static void CloseRingBufferHandles(ring_buffer_handles_t *ring_buffer_handles)
Definition: interactive.c:180
#define ERROR_STARTUP_DATA
Definition: interactive.c:51
#define M_SYSERR
Definition: service.h:47
static DWORD HandleFlushNeighborsMessage(flush_neighbors_message_t *msg)
Definition: interactive.c:749
static DWORD HandleAddressMessage(address_message_t *msg, undo_lists_t *lists)
Definition: interactive.c:599
#define free
Definition: cmocka.c:1850
bool openvpn_swprintf(wchar_t *const str, const size_t size, const wchar_t *const format,...)
Definition: buffer.c:318
static DWORD HandleEnableDHCPMessage(const enable_dhcp_message_t *dhcp)
Definition: interactive.c:1296
static HANDLE InitOverlapped(LPOVERLAPPED overlapped)
Definition: interactive.c:190
static BOOL CmpWString(LPVOID item, LPVOID str)
Definition: interactive.c:1143
static void BlockDNSErrHandler(DWORD err, const char *msg)
Definition: interactive.c:760
static DWORD PeekNamedPipeAsync(HANDLE pipe, DWORD count, LPHANDLE events)
Definition: interactive.c:283
static DWORD DeleteDNS(short family, wchar_t *if_name)
Definition: interactive.c:1128
static DWORD wmic_nicconfig_cmd(const wchar_t *action, const NET_IFINDEX if_index, const wchar_t *data)
Run command: wmic nicconfig (InterfaceIndex=$if_index) call $action ($data)
Definition: interactive.c:1088
static DWORD UpdateWaitHandles(LPHANDLE *handles_ptr, LPDWORD count, HANDLE io_event, HANDLE exit_event, list_item_t *threads)
Definition: interactive.c:2030
static HANDLE exit_event
Definition: interactive.c:57
interface_t iface
Definition: openvpn-msg.h:67
static VOID FreeWaitHandles(LPHANDLE h)
Definition: interactive.c:2080
#define PACKAGE
Definition: config.h:724
message_header_t header
Definition: openvpn-msg.h:113
static LPVOID RemoveListItem(list_item_t **pfirst, match_fn_t match, LPVOID ctx)
Definition: interactive.c:134
WCHAR * directory
Definition: interactive.c:74
Wintun ring buffer See https://github.com/WireGuard/wintun#ring-layout.
Definition: ring_buffer.h:50
Definition: argv.h:35
static DWORD WritePipeAsync(HANDLE pipe, LPVOID data, DWORD size, DWORD count, LPHANDLE events)
Definition: interactive.c:295
static SERVICE_STATUS status
Definition: interactive.c:56
interface_t iface
Definition: openvpn-msg.h:114
list_item_t * undo_lists_t[_undo_type_max]
Definition: interactive.c:97
static BOOL ValidateOptions(HANDLE pipe, const WCHAR *workdir, const WCHAR *options, WCHAR *errmsg, DWORD capacity)
Definition: interactive.c:370
static BOOL CmpHandle(LPVOID item, LPVOID hnd)
Definition: interactive.c:2086
BOOL IsAuthorizedUser(PSID sid, const HANDLE token, const WCHAR *ovpn_admin_group)
Definition: validate.c:160
static HANDLE OvpnUnmapViewOfFile(LPHANDLE handle)
Definition: interactive.c:169
BOOL ReportStatusToSCMgr(SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status)
Definition: service.c:22