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