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