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