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