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