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