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-2022 Heiko Hund <heiko.hund@sophos.com>
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License version 2
12  *  as published by the Free Software Foundation.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License along
20  *  with this program; if not, write to the Free Software Foundation, Inc.,
21  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23 
24 
25 #include "service.h"
26 
27 #include <ws2tcpip.h>
28 #include <iphlpapi.h>
29 #include <userenv.h>
30 #include <accctrl.h>
31 #include <aclapi.h>
32 #include <stdio.h>
33 #include <sddl.h>
34 #include <shellapi.h>
35 #include <mstcpip.h>
36 
37 #ifdef HAVE_VERSIONHELPERS_H
38 #include <versionhelpers.h>
39 #else
40 #include "compat-versionhelpers.h"
41 #endif
42 
43 #include "openvpn-msg.h"
44 #include "validate.h"
45 #include "block_dns.h"
46 #include "ring_buffer.h"
47 
48 #define IO_TIMEOUT  2000 /*ms*/
49 
50 #define ERROR_OPENVPN_STARTUP        0x20000000
51 #define ERROR_STARTUP_DATA           0x20000001
52 #define ERROR_MESSAGE_DATA           0x20000002
53 #define ERROR_MESSAGE_TYPE           0x20000003
54 
55 static SERVICE_STATUS_HANDLE service;
56 static SERVICE_STATUS status = { .dwServiceType = SERVICE_WIN32_SHARE_PROCESS };
57 static HANDLE exit_event = NULL;
58 static settings_t settings;
59 static HANDLE rdns_semaphore = NULL;
60 #define RDNS_TIMEOUT 600  /* seconds to wait for the semaphore */
61 
62 #define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
63 
64 openvpn_service_t interactive_service = {
65     interactive,
66     TEXT(PACKAGE_NAME "ServiceInteractive"),
67     TEXT(PACKAGE_NAME " Interactive Service"),
68     TEXT(SERVICE_DEPENDENCIES),
69     SERVICE_AUTO_START
70 };
71 
72 
73 typedef struct {
74     WCHAR *directory;
75     WCHAR *options;
76     WCHAR *std_input;
77 } STARTUP_DATA;
78 
79 
80 /* Datatype for linked lists */
81 typedef struct _list_item {
82     struct _list_item *next;
83     LPVOID data;
84 } list_item_t;
85 
86 
87 /* Datatypes for undo information */
88 typedef enum {
89     address,
90     route,
91     block_dns,
92     undo_dns4,
93     undo_dns6,
94     undo_domain,
95     _undo_type_max
96 } undo_type_t;
97 typedef list_item_t *undo_lists_t[_undo_type_max];
98 
99 typedef struct {
100     HANDLE engine;
101     int index;
102     int metric_v4;
103     int metric_v6;
104 } block_dns_data_t;
105 
106 typedef struct {
107     HANDLE send_ring_handle;
108     HANDLE receive_ring_handle;
109     HANDLE send_tail_moved;
110     HANDLE receive_tail_moved;
111     HANDLE device;
112 } ring_buffer_handles_t;
113 
114 
115 static DWORD
AddListItem(list_item_t ** pfirst,LPVOID data)116 AddListItem(list_item_t **pfirst, LPVOID data)
117 {
118     list_item_t *new_item = malloc(sizeof(list_item_t));
119     if (new_item == NULL)
120     {
121         return ERROR_OUTOFMEMORY;
122     }
123 
124     new_item->next = *pfirst;
125     new_item->data = data;
126 
127     *pfirst = new_item;
128     return NO_ERROR;
129 }
130 
131 typedef BOOL (*match_fn_t) (LPVOID item, LPVOID ctx);
132 
133 static LPVOID
RemoveListItem(list_item_t ** pfirst,match_fn_t match,LPVOID ctx)134 RemoveListItem(list_item_t **pfirst, match_fn_t match, LPVOID ctx)
135 {
136     LPVOID data = NULL;
137     list_item_t **pnext;
138 
139     for (pnext = pfirst; *pnext; pnext = &(*pnext)->next)
140     {
141         list_item_t *item = *pnext;
142         if (!match(item->data, ctx))
143         {
144             continue;
145         }
146 
147         /* Found item, remove from the list and free memory */
148         *pnext = item->next;
149         data = item->data;
150         free(item);
151         break;
152     }
153     return data;
154 }
155 
156 
157 static HANDLE
CloseHandleEx(LPHANDLE handle)158 CloseHandleEx(LPHANDLE handle)
159 {
160     if (handle && *handle && *handle != INVALID_HANDLE_VALUE)
161     {
162         CloseHandle(*handle);
163         *handle = INVALID_HANDLE_VALUE;
164     }
165     return INVALID_HANDLE_VALUE;
166 }
167 
168 static HANDLE
OvpnUnmapViewOfFile(LPHANDLE handle)169 OvpnUnmapViewOfFile(LPHANDLE handle)
170 {
171     if (handle && *handle && *handle != INVALID_HANDLE_VALUE)
172     {
173         UnmapViewOfFile(*handle);
174         *handle = INVALID_HANDLE_VALUE;
175     }
176     return INVALID_HANDLE_VALUE;
177 }
178 
179 static void
CloseRingBufferHandles(ring_buffer_handles_t * ring_buffer_handles)180 CloseRingBufferHandles(ring_buffer_handles_t *ring_buffer_handles)
181 {
182     CloseHandleEx(&ring_buffer_handles->device);
183     CloseHandleEx(&ring_buffer_handles->receive_tail_moved);
184     CloseHandleEx(&ring_buffer_handles->send_tail_moved);
185     OvpnUnmapViewOfFile(&ring_buffer_handles->send_ring_handle);
186     OvpnUnmapViewOfFile(&ring_buffer_handles->receive_ring_handle);
187 }
188 
189 static HANDLE
InitOverlapped(LPOVERLAPPED overlapped)190 InitOverlapped(LPOVERLAPPED overlapped)
191 {
192     ZeroMemory(overlapped, sizeof(OVERLAPPED));
193     overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
194     return overlapped->hEvent;
195 }
196 
197 
198 static BOOL
ResetOverlapped(LPOVERLAPPED overlapped)199 ResetOverlapped(LPOVERLAPPED overlapped)
200 {
201     HANDLE io_event = overlapped->hEvent;
202     if (!ResetEvent(io_event))
203     {
204         return FALSE;
205     }
206     ZeroMemory(overlapped, sizeof(OVERLAPPED));
207     overlapped->hEvent = io_event;
208     return TRUE;
209 }
210 
211 
212 typedef enum {
213     peek,
214     read,
215     write
216 } async_op_t;
217 
218 static DWORD
AsyncPipeOp(async_op_t op,HANDLE pipe,LPVOID buffer,DWORD size,DWORD count,LPHANDLE events)219 AsyncPipeOp(async_op_t op, HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
220 {
221     DWORD i;
222     BOOL success;
223     HANDLE io_event;
224     DWORD res, bytes = 0;
225     OVERLAPPED overlapped;
226     LPHANDLE handles = NULL;
227 
228     io_event = InitOverlapped(&overlapped);
229     if (!io_event)
230     {
231         goto out;
232     }
233 
234     handles = malloc((count + 1) * sizeof(HANDLE));
235     if (!handles)
236     {
237         goto out;
238     }
239 
240     if (op == write)
241     {
242         success = WriteFile(pipe, buffer, size, NULL, &overlapped);
243     }
244     else
245     {
246         success = ReadFile(pipe, buffer, size, NULL, &overlapped);
247     }
248     if (!success && GetLastError() != ERROR_IO_PENDING && GetLastError() != ERROR_MORE_DATA)
249     {
250         goto out;
251     }
252 
253     handles[0] = io_event;
254     for (i = 0; i < count; i++)
255     {
256         handles[i + 1] = events[i];
257     }
258 
259     res = WaitForMultipleObjects(count + 1, handles, FALSE,
260                                  op == peek ? INFINITE : IO_TIMEOUT);
261     if (res != WAIT_OBJECT_0)
262     {
263         CancelIo(pipe);
264         goto out;
265     }
266 
267     if (op == peek)
268     {
269         PeekNamedPipe(pipe, NULL, 0, NULL, &bytes, NULL);
270     }
271     else
272     {
273         GetOverlappedResult(pipe, &overlapped, &bytes, TRUE);
274     }
275 
276 out:
277     CloseHandleEx(&io_event);
278     free(handles);
279     return bytes;
280 }
281 
282 static DWORD
PeekNamedPipeAsync(HANDLE pipe,DWORD count,LPHANDLE events)283 PeekNamedPipeAsync(HANDLE pipe, DWORD count, LPHANDLE events)
284 {
285     return AsyncPipeOp(peek, pipe, NULL, 0, count, events);
286 }
287 
288 static DWORD
ReadPipeAsync(HANDLE pipe,LPVOID buffer,DWORD size,DWORD count,LPHANDLE events)289 ReadPipeAsync(HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
290 {
291     return AsyncPipeOp(read, pipe, buffer, size, count, events);
292 }
293 
294 static DWORD
WritePipeAsync(HANDLE pipe,LPVOID data,DWORD size,DWORD count,LPHANDLE events)295 WritePipeAsync(HANDLE pipe, LPVOID data, DWORD size, DWORD count, LPHANDLE events)
296 {
297     return AsyncPipeOp(write, pipe, data, size, count, events);
298 }
299 
300 static VOID
ReturnProcessId(HANDLE pipe,DWORD pid,DWORD count,LPHANDLE events)301 ReturnProcessId(HANDLE pipe, DWORD pid, DWORD count, LPHANDLE events)
302 {
303     const WCHAR msg[] = L"Process ID";
304     WCHAR buf[22 + _countof(msg)]; /* 10 chars each for error and PID and 2 for line breaks */
305 
306     /*
307      * Same format as error messages (3 line string) with error = 0 in
308      * 0x%08x format, PID on line 2 and a description "Process ID" on line 3
309      */
310     openvpn_swprintf(buf, _countof(buf), L"0x%08x\n0x%08x\n%s", 0, pid, msg);
311 
312     WritePipeAsync(pipe, buf, (DWORD)(wcslen(buf) * 2), count, events);
313 }
314 
315 static VOID
ReturnError(HANDLE pipe,DWORD error,LPCWSTR func,DWORD count,LPHANDLE events)316 ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events)
317 {
318     DWORD result_len;
319     LPWSTR result = L"0xffffffff\nFormatMessage failed\nCould not return result";
320     DWORD_PTR args[] = {
321         (DWORD_PTR) error,
322         (DWORD_PTR) func,
323         (DWORD_PTR) ""
324     };
325 
326     if (error != ERROR_OPENVPN_STARTUP)
327     {
328         FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM
329                        |FORMAT_MESSAGE_ALLOCATE_BUFFER
330                        |FORMAT_MESSAGE_IGNORE_INSERTS,
331                        0, error, 0, (LPWSTR) &args[2], 0, NULL);
332     }
333 
334     result_len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING
335                                 |FORMAT_MESSAGE_ALLOCATE_BUFFER
336                                 |FORMAT_MESSAGE_ARGUMENT_ARRAY,
337                                 L"0x%1!08x!\n%2!s!\n%3!s!", 0, 0,
338                                 (LPWSTR) &result, 0, (va_list *) args);
339 
340     WritePipeAsync(pipe, result, (DWORD)(wcslen(result) * 2), count, events);
341 #ifdef UNICODE
342     MsgToEventLog(MSG_FLAGS_ERROR, result);
343 #else
344     MsgToEventLog(MSG_FLAGS_ERROR, "%S", result);
345 #endif
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
ReturnLastError(HANDLE pipe,LPCWSTR func)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
ValidateOptions(HANDLE pipe,const WCHAR * workdir,const WCHAR * options,WCHAR * errmsg,DWORD capacity)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 (%s relative to %s)"
377                         L" that requires admin approval. This error may be avoided"
378                         L" by adding your account to the \"%s\" group";
379 
380     const WCHAR *msg2 = L"You have specified an option (%s) that may be used"
381                         L" only with admin approval. This error may be avoided"
382                         L" by adding your account to the \"%s\" group";
383 
384     argv = CommandLineToArgvW(options, &argc);
385 
386     if (!argv)
387     {
388         openvpn_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             openvpn_swprintf(errmsg, capacity, msg1, argv[0], workdir,
411                              settings.ovpn_admin_group);
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                 openvpn_swprintf(errmsg, capacity, msg1, argv[i+1], workdir,
428                                  settings.ovpn_admin_group);
429             }
430             else
431             {
432                 openvpn_swprintf(errmsg, capacity, msg2, argv[i],
433                                  settings.ovpn_admin_group);
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
GetStartupData(HANDLE pipe,STARTUP_DATA * sud)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
FreeStartupData(STARTUP_DATA * sud)527 FreeStartupData(STARTUP_DATA *sud)
528 {
529     free(sud->directory);
530 }
531 
532 
533 static SOCKADDR_INET
sockaddr_inet(short family,inet_address_t * addr)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
InterfaceLuid(const char * iface_name,PNET_LUID luid)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
ConvertInterfaceNameToIndex(const wchar_t * ifname,NET_IFINDEX * index)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 <%s>", ifname);
582    }
583    return err;
584 }
585 
586 static BOOL
CmpAddress(LPVOID item,LPVOID address)587 CmpAddress(LPVOID item, LPVOID address)
588 {
589     return memcmp(item, address, sizeof(MIB_UNICASTIPADDRESS_ROW)) == 0 ? TRUE : FALSE;
590 }
591 
592 static DWORD
DeleteAddress(PMIB_UNICASTIPADDRESS_ROW addr_row)593 DeleteAddress(PMIB_UNICASTIPADDRESS_ROW addr_row)
594 {
595     return DeleteUnicastIpAddressEntry(addr_row);
596 }
597 
598 static DWORD
HandleAddressMessage(address_message_t * msg,undo_lists_t * lists)599 HandleAddressMessage(address_message_t *msg, undo_lists_t *lists)
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
CmpRoute(LPVOID item,LPVOID route)665 CmpRoute(LPVOID item, LPVOID route)
666 {
667     return memcmp(item, route, sizeof(MIB_IPFORWARD_ROW2)) == 0 ? TRUE : FALSE;
668 }
669 
670 static DWORD
DeleteRoute(PMIB_IPFORWARD_ROW2 fwd_row)671 DeleteRoute(PMIB_IPFORWARD_ROW2 fwd_row)
672 {
673     return DeleteIpForwardEntry2(fwd_row);
674 }
675 
676 static DWORD
HandleRouteMessage(route_message_t * msg,undo_lists_t * lists)677 HandleRouteMessage(route_message_t *msg, undo_lists_t *lists)
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
HandleFlushNeighborsMessage(flush_neighbors_message_t * msg)749 HandleFlushNeighborsMessage(flush_neighbors_message_t *msg)
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
BlockDNSErrHandler(DWORD err,const char * msg)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 #ifdef UNICODE
780     MsgToEventLog(M_ERR, L"%S (status = %lu): %s", msg, err, err_str);
781 #else
782     MsgToEventLog(M_ERR, "%s (status = %lu): %s", msg, err, err_str);
783 #endif
784 
785 }
786 
787 /* Use an always-true match_fn to get the head of the list */
788 static BOOL
CmpEngine(LPVOID item,LPVOID any)789 CmpEngine(LPVOID item, LPVOID any)
790 {
791     return TRUE;
792 }
793 
794 static DWORD
HandleBlockDNSMessage(const block_dns_message_t * msg,undo_lists_t * lists)795 HandleBlockDNSMessage(const block_dns_message_t *msg, undo_lists_t *lists)
796 {
797     DWORD err = 0;
798     block_dns_data_t *interface_data;
799     HANDLE engine = NULL;
800     LPCWSTR exe_path;
801 
802 #ifdef UNICODE
803     exe_path = settings.exe_path;
804 #else
805     WCHAR wide_path[MAX_PATH];
806     MultiByteToWideChar(CP_UTF8, 0, settings.exe_path, MAX_PATH, wide_path, MAX_PATH);
807     exe_path = wide_path;
808 #endif
809 
810     if (msg->header.type == msg_add_block_dns)
811     {
812         err = add_block_dns_filters(&engine, msg->iface.index, exe_path, BlockDNSErrHandler);
813         if (!err)
814         {
815             interface_data = malloc(sizeof(block_dns_data_t));
816             if (!interface_data)
817             {
818                 return ERROR_OUTOFMEMORY;
819             }
820             interface_data->engine = engine;
821             interface_data->index = msg->iface.index;
822             int is_auto = 0;
823             interface_data->metric_v4 = get_interface_metric(msg->iface.index,
824                                                              AF_INET, &is_auto);
825             if (is_auto)
826             {
827                 interface_data->metric_v4 = 0;
828             }
829             interface_data->metric_v6 = get_interface_metric(msg->iface.index,
830                                                              AF_INET6, &is_auto);
831             if (is_auto)
832             {
833                 interface_data->metric_v6 = 0;
834             }
835             err = AddListItem(&(*lists)[block_dns], interface_data);
836             if (!err)
837             {
838                 err = set_interface_metric(msg->iface.index, AF_INET,
839                                            BLOCK_DNS_IFACE_METRIC);
840                 if (!err)
841                 {
842                     set_interface_metric(msg->iface.index, AF_INET6,
843                                          BLOCK_DNS_IFACE_METRIC);
844                 }
845             }
846         }
847     }
848     else
849     {
850         interface_data = RemoveListItem(&(*lists)[block_dns], CmpEngine, NULL);
851         if (interface_data)
852         {
853             engine = interface_data->engine;
854             err = delete_block_dns_filters(engine);
855             engine = NULL;
856             if (interface_data->metric_v4 >= 0)
857             {
858                 set_interface_metric(msg->iface.index, AF_INET,
859                                      interface_data->metric_v4);
860             }
861             if (interface_data->metric_v6 >= 0)
862             {
863                 set_interface_metric(msg->iface.index, AF_INET6,
864                                      interface_data->metric_v6);
865             }
866             free(interface_data);
867         }
868         else
869         {
870             MsgToEventLog(M_ERR, TEXT("No previous block DNS filters to delete"));
871         }
872     }
873 
874     if (err && engine)
875     {
876         delete_block_dns_filters(engine);
877     }
878 
879     return err;
880 }
881 
882 /*
883  * Execute a command and return its exit code. If timeout > 0, terminate
884  * the process if still running after timeout milliseconds. In that case
885  * the return value is the windows error code WAIT_TIMEOUT = 0x102
886  */
887 static DWORD
ExecCommand(const WCHAR * argv0,const WCHAR * cmdline,DWORD timeout)888 ExecCommand(const WCHAR *argv0, const WCHAR *cmdline, DWORD timeout)
889 {
890     DWORD exit_code;
891     STARTUPINFOW si;
892     PROCESS_INFORMATION pi;
893     DWORD proc_flags = CREATE_NO_WINDOW|CREATE_UNICODE_ENVIRONMENT;
894     WCHAR *cmdline_dup = NULL;
895 
896     ZeroMemory(&si, sizeof(si));
897     ZeroMemory(&pi, sizeof(pi));
898 
899     si.cb = sizeof(si);
900 
901     /* CreateProcess needs a modifiable cmdline: make a copy */
902     cmdline_dup = wcsdup(cmdline);
903     if (cmdline_dup && CreateProcessW(argv0, cmdline_dup, NULL, NULL, FALSE,
904                                       proc_flags, NULL, NULL, &si, &pi) )
905     {
906         WaitForSingleObject(pi.hProcess, timeout ? timeout : INFINITE);
907         if (!GetExitCodeProcess(pi.hProcess, &exit_code))
908         {
909             MsgToEventLog(M_SYSERR, TEXT("ExecCommand: Error getting exit_code:"));
910             exit_code = GetLastError();
911         }
912         else if (exit_code == STILL_ACTIVE)
913         {
914             exit_code = WAIT_TIMEOUT; /* Windows error code 0x102 */
915 
916             /* kill without impunity */
917             TerminateProcess(pi.hProcess, exit_code);
918             MsgToEventLog(M_ERR, TEXT("ExecCommand: \"%s %s\" killed after timeout"),
919                           argv0, cmdline);
920         }
921         else if (exit_code)
922         {
923             MsgToEventLog(M_ERR, TEXT("ExecCommand: \"%s %s\" exited with status = %lu"),
924                           argv0, cmdline, exit_code);
925         }
926         else
927         {
928             MsgToEventLog(M_INFO, TEXT("ExecCommand: \"%s %s\" completed"), argv0, cmdline);
929         }
930 
931         CloseHandle(pi.hProcess);
932         CloseHandle(pi.hThread);
933     }
934     else
935     {
936         exit_code = GetLastError();
937         MsgToEventLog(M_SYSERR, TEXT("ExecCommand: could not run \"%s %s\" :"),
938                       argv0, cmdline);
939     }
940 
941     free(cmdline_dup);
942     return exit_code;
943 }
944 
945 /*
946  * Entry point for register-dns thread.
947  */
948 static DWORD WINAPI
RegisterDNS(LPVOID unused)949 RegisterDNS(LPVOID unused)
950 {
951     DWORD err;
952     size_t i;
953     DWORD timeout = RDNS_TIMEOUT * 1000; /* in milliseconds */
954 
955     /* path of ipconfig command */
956     WCHAR ipcfg[MAX_PATH];
957 
958     struct
959     {
960         WCHAR *argv0;
961         WCHAR *cmdline;
962         DWORD timeout;
963     } cmds [] = {
964         { ipcfg, L"ipconfig /flushdns",    timeout },
965         { ipcfg, L"ipconfig /registerdns", timeout },
966     };
967 
968     HANDLE wait_handles[2] = {rdns_semaphore, exit_event};
969 
970     openvpn_swprintf(ipcfg, MAX_PATH, L"%s\\%s", get_win_sys_path(), L"ipconfig.exe");
971 
972     if (WaitForMultipleObjects(2, wait_handles, FALSE, timeout) == WAIT_OBJECT_0)
973     {
974         /* Semaphore locked */
975         for (i = 0; i < _countof(cmds); ++i)
976         {
977             ExecCommand(cmds[i].argv0, cmds[i].cmdline, cmds[i].timeout);
978         }
979         err = 0;
980         if (!ReleaseSemaphore(rdns_semaphore, 1, NULL) )
981         {
982             err = MsgToEventLog(M_SYSERR, TEXT("RegisterDNS: Failed to release regsiter-dns semaphore:"));
983         }
984     }
985     else
986     {
987         MsgToEventLog(M_ERR, TEXT("RegisterDNS: Failed to lock register-dns semaphore"));
988         err = ERROR_SEM_TIMEOUT; /* Windows error code 0x79 */
989     }
990     return err;
991 }
992 
993 static DWORD
HandleRegisterDNSMessage(void)994 HandleRegisterDNSMessage(void)
995 {
996     DWORD err;
997     HANDLE thread = NULL;
998 
999     /* Delegate this job to a sub-thread */
1000     thread = CreateThread(NULL, 0, RegisterDNS, NULL, 0, NULL);
1001 
1002     /*
1003      * We don't add these thread handles to the undo list -- the thread and
1004      * processes it spawns are all supposed to terminate or timeout by themselves.
1005      */
1006     if (thread)
1007     {
1008         err = 0;
1009         CloseHandle(thread);
1010     }
1011     else
1012     {
1013         err = GetLastError();
1014     }
1015 
1016     return err;
1017 }
1018 
1019 /**
1020  * Run the command: netsh interface $proto $action dns $if_name $addr [validate=no]
1021  * @param  action      "delete" or "add"
1022  * @param  proto       "ipv6" or "ip"
1023  * @param  if_name     "name_of_interface"
1024  * @param  addr         IPv4 (for proto = ip) or IPv6 address as a string
1025  *
1026  * If addr is null and action = "delete" all addresses are deleted.
1027  */
1028 static DWORD
netsh_dns_cmd(const wchar_t * action,const wchar_t * proto,const wchar_t * if_name,const wchar_t * addr)1029 netsh_dns_cmd(const wchar_t *action, const wchar_t *proto, const wchar_t *if_name, const wchar_t *addr)
1030 {
1031     DWORD err = 0;
1032     int timeout = 30000; /* in msec */
1033     wchar_t argv0[MAX_PATH];
1034     wchar_t *cmdline = NULL;
1035 
1036     if (!addr)
1037     {
1038         if (wcscmp(action, L"delete") == 0)
1039         {
1040             addr = L"all";
1041         }
1042         else /* nothing to do -- return success*/
1043         {
1044             goto out;
1045         }
1046     }
1047 
1048     /* Path of netsh */
1049     swprintf(argv0, _countof(argv0), L"%s\\%s", get_win_sys_path(), L"netsh.exe");
1050     argv0[_countof(argv0) - 1] = L'\0';
1051 
1052     /* cmd template:
1053      * netsh interface $proto $action dns $if_name $addr [validate=no]
1054      */
1055     const wchar_t *fmt = L"netsh interface %s %s dns \"%s\" %s";
1056 
1057     /* max cmdline length in wchars -- include room for worst case and some */
1058     size_t ncmdline = wcslen(fmt) + wcslen(if_name) + wcslen(addr) + 32 + 1;
1059     cmdline = malloc(ncmdline*sizeof(wchar_t));
1060     if (!cmdline)
1061     {
1062         err = ERROR_OUTOFMEMORY;
1063         goto out;
1064     }
1065 
1066     openvpn_sntprintf(cmdline, ncmdline, fmt, proto, action, if_name, addr);
1067 
1068     if (IsWindows7OrGreater())
1069     {
1070         wcsncat(cmdline, L" validate=no", ncmdline - wcslen(cmdline) - 1);
1071     }
1072     err = ExecCommand(argv0, cmdline, timeout);
1073 
1074 out:
1075     free(cmdline);
1076     return err;
1077 }
1078 
1079 /**
1080  * Run command: wmic nicconfig (InterfaceIndex=$if_index) call $action ($data)
1081  * @param  if_index    "index of interface"
1082  * @param  action      e.g., "SetDNSDomain"
1083  * @param  data        data if required for action
1084  *                     - a single word for SetDNSDomain, empty or NULL to delete
1085  *                     - comma separated values for a list
1086  */
1087 static DWORD
wmic_nicconfig_cmd(const wchar_t * action,const NET_IFINDEX if_index,const wchar_t * data)1088 wmic_nicconfig_cmd(const wchar_t *action, const NET_IFINDEX if_index,
1089                    const wchar_t *data)
1090 {
1091     DWORD err = 0;
1092     wchar_t argv0[MAX_PATH];
1093     wchar_t *cmdline = NULL;
1094     int timeout = 10000; /* in msec */
1095 
1096     swprintf(argv0, _countof(argv0), L"%s\\%s", get_win_sys_path(), L"wbem\\wmic.exe");
1097     argv0[_countof(argv0) - 1] = L'\0';
1098 
1099     const wchar_t *fmt;
1100     /* comma separated list must be enclosed in parenthesis */
1101     if (data && wcschr(data, L','))
1102     {
1103        fmt = L"wmic nicconfig where (InterfaceIndex=%ld) call %s (%s)";
1104     }
1105     else
1106     {
1107        fmt = L"wmic nicconfig where (InterfaceIndex=%ld) call %s \"%s\"";
1108     }
1109 
1110     size_t ncmdline = wcslen(fmt) + 20 + wcslen(action) /* max 20 for ifindex */
1111                     + (data ? wcslen(data) + 1 : 1);
1112     cmdline = malloc(ncmdline*sizeof(wchar_t));
1113     if (!cmdline)
1114     {
1115         return ERROR_OUTOFMEMORY;
1116     }
1117 
1118     openvpn_sntprintf(cmdline, ncmdline, fmt, if_index, action,
1119                       data? data : L"");
1120     err = ExecCommand(argv0, cmdline, timeout);
1121 
1122     free(cmdline);
1123     return err;
1124 }
1125 
1126 /* Delete all IPv4 or IPv6 dns servers for an interface */
1127 static DWORD
DeleteDNS(short family,wchar_t * if_name)1128 DeleteDNS(short family, wchar_t *if_name)
1129 {
1130     wchar_t *proto = (family == AF_INET6) ? L"ipv6" : L"ip";
1131     return netsh_dns_cmd(L"delete", proto, if_name, NULL);
1132 }
1133 
1134 /* Add an IPv4 or IPv6 dns server to an interface */
1135 static DWORD
AddDNS(short family,wchar_t * if_name,wchar_t * addr)1136 AddDNS(short family, wchar_t *if_name, wchar_t *addr)
1137 {
1138     wchar_t *proto = (family == AF_INET6) ? L"ipv6" : L"ip";
1139     return netsh_dns_cmd(L"add", proto, if_name, addr);
1140 }
1141 
1142 static BOOL
CmpWString(LPVOID item,LPVOID str)1143 CmpWString(LPVOID item, LPVOID str)
1144 {
1145     return (wcscmp(item, str) == 0) ? TRUE : FALSE;
1146 }
1147 
1148 /**
1149  * Set interface specific DNS domain suffix
1150  * @param  if_name    name of the the interface
1151  * @param  domain     a single domain name
1152  * @param  lists      pointer to the undo lists. If NULL
1153  *                    undo lists are not altered.
1154  * Will delete the currently set value if domain is empty.
1155  */
1156 static DWORD
SetDNSDomain(const wchar_t * if_name,const char * domain,undo_lists_t * lists)1157 SetDNSDomain(const wchar_t *if_name, const char *domain, undo_lists_t *lists)
1158 {
1159    NET_IFINDEX if_index;
1160 
1161    DWORD err  = ConvertInterfaceNameToIndex(if_name, &if_index);
1162    if (err != ERROR_SUCCESS)
1163    {
1164        return err;
1165    }
1166 
1167    wchar_t *wdomain = utf8to16(domain); /* utf8 to wide-char */
1168    if (!wdomain)
1169    {
1170        return ERROR_OUTOFMEMORY;
1171    }
1172 
1173    /* free undo list if previously set */
1174    if (lists)
1175    {
1176        free(RemoveListItem(&(*lists)[undo_domain], CmpWString, (void *)if_name));
1177    }
1178 
1179    err = wmic_nicconfig_cmd(L"SetDNSDomain", if_index, wdomain);
1180 
1181    /* Add to undo list if domain is non-empty */
1182    if (err == 0 && wdomain[0] && lists)
1183    {
1184         wchar_t *tmp_name = wcsdup(if_name);
1185         if (!tmp_name || AddListItem(&(*lists)[undo_domain], tmp_name))
1186         {
1187             free(tmp_name);
1188             err = ERROR_OUTOFMEMORY;
1189         }
1190    }
1191 
1192    free(wdomain);
1193    return err;
1194 }
1195 
1196 static DWORD
HandleDNSConfigMessage(const dns_cfg_message_t * msg,undo_lists_t * lists)1197 HandleDNSConfigMessage(const dns_cfg_message_t *msg, undo_lists_t *lists)
1198 {
1199     DWORD err = 0;
1200     wchar_t addr[46]; /* large enough to hold string representation of an ipv4 / ipv6 address */
1201     undo_type_t undo_type = (msg->family == AF_INET6) ? undo_dns4 : undo_dns6;
1202     int addr_len = msg->addr_len;
1203 
1204     /* sanity check */
1205     if (addr_len > _countof(msg->addr))
1206     {
1207         addr_len = _countof(msg->addr);
1208     }
1209 
1210     if (!msg->iface.name[0]) /* interface name is required */
1211     {
1212         return ERROR_MESSAGE_DATA;
1213     }
1214 
1215     /* use a non-const reference with limited scope to enforce null-termination of strings from client */
1216     {
1217         dns_cfg_message_t *msgptr = (dns_cfg_message_t *) msg;
1218         msgptr->iface.name[_countof(msg->iface.name)-1] = '\0';
1219         msgptr->domains[_countof(msg->domains)-1] = '\0';
1220     }
1221 
1222     wchar_t *wide_name = utf8to16(msg->iface.name); /* utf8 to wide-char */
1223     if (!wide_name)
1224     {
1225         return ERROR_OUTOFMEMORY;
1226     }
1227 
1228     /* We delete all current addresses before adding any
1229      * OR if the message type is del_dns_cfg
1230      */
1231     if (addr_len > 0 || msg->header.type == msg_del_dns_cfg)
1232     {
1233         err = DeleteDNS(msg->family, wide_name);
1234         if (err)
1235         {
1236             goto out;
1237         }
1238         free(RemoveListItem(&(*lists)[undo_type], CmpWString, wide_name));
1239     }
1240 
1241     if (msg->header.type == msg_del_dns_cfg)
1242     {
1243         if (msg->domains[0])
1244         {
1245             /* setting an empty domain removes any previous value */
1246             err = SetDNSDomain(wide_name, "", lists);
1247         }
1248         goto out;  /* job done */
1249     }
1250 
1251     for (int i = 0; i < addr_len; ++i)
1252     {
1253         if (msg->family == AF_INET6)
1254         {
1255             RtlIpv6AddressToStringW(&msg->addr[i].ipv6, addr);
1256         }
1257         else
1258         {
1259             RtlIpv4AddressToStringW(&msg->addr[i].ipv4, addr);
1260         }
1261         err = AddDNS(msg->family, wide_name, addr);
1262         if (i == 0 && err)
1263         {
1264             goto out;
1265         }
1266         /* We do not check for duplicate addresses, so any error in adding
1267          * additional addresses is ignored.
1268          */
1269     }
1270 
1271     err = 0;
1272 
1273     if (msg->addr_len > 0)
1274     {
1275         wchar_t *tmp_name = wcsdup(wide_name);
1276         if (!tmp_name || AddListItem(&(*lists)[undo_type], tmp_name))
1277         {
1278             free(tmp_name);
1279             DeleteDNS(msg->family, wide_name);
1280             err = ERROR_OUTOFMEMORY;
1281             goto out;
1282         }
1283     }
1284 
1285     if (msg->domains[0])
1286     {
1287         err = SetDNSDomain(wide_name, msg->domains, lists);
1288     }
1289 
1290 out:
1291     free(wide_name);
1292     return err;
1293 }
1294 
1295 static DWORD
HandleEnableDHCPMessage(const enable_dhcp_message_t * dhcp)1296 HandleEnableDHCPMessage(const enable_dhcp_message_t *dhcp)
1297 {
1298     DWORD err = 0;
1299     DWORD timeout = 5000; /* in milli seconds */
1300     wchar_t argv0[MAX_PATH];
1301 
1302     /* Path of netsh */
1303     swprintf(argv0, _countof(argv0), L"%s\\%s", get_win_sys_path(), L"netsh.exe");
1304     argv0[_countof(argv0) - 1] = L'\0';
1305 
1306     /* cmd template:
1307      * netsh interface ipv4 set address name=$if_index source=dhcp
1308      */
1309     const wchar_t *fmt = L"netsh interface ipv4 set address name=\"%d\" source=dhcp";
1310 
1311     /* max cmdline length in wchars -- include room for if index:
1312      * 10 chars for 32 bit int in decimal and +1 for NUL
1313      */
1314     size_t ncmdline = wcslen(fmt) + 10 + 1;
1315     wchar_t *cmdline = malloc(ncmdline*sizeof(wchar_t));
1316     if (!cmdline)
1317     {
1318         err = ERROR_OUTOFMEMORY;
1319         return err;
1320     }
1321 
1322     openvpn_sntprintf(cmdline, ncmdline, fmt, dhcp->iface.index);
1323 
1324     err = ExecCommand(argv0, cmdline, timeout);
1325 
1326     /* Note: This could fail if dhcp is already enabled, so the caller
1327      * may not want to treat errors as FATAL.
1328      */
1329 
1330     free(cmdline);
1331     return err;
1332 }
1333 
1334 static DWORD
OvpnDuplicateHandle(HANDLE ovpn_proc,HANDLE orig_handle,HANDLE * new_handle)1335 OvpnDuplicateHandle(HANDLE ovpn_proc, HANDLE orig_handle, HANDLE* new_handle)
1336 {
1337     DWORD err = ERROR_SUCCESS;
1338 
1339     if (!DuplicateHandle(ovpn_proc, orig_handle, GetCurrentProcess(), new_handle, 0, FALSE, DUPLICATE_SAME_ACCESS))
1340     {
1341         err = GetLastError();
1342         MsgToEventLog(M_SYSERR, TEXT("Could not duplicate handle"));
1343         return err;
1344     }
1345 
1346     return err;
1347 }
1348 
1349 static DWORD
DuplicateAndMapRing(HANDLE ovpn_proc,HANDLE orig_handle,HANDLE * new_handle,struct tun_ring ** ring)1350 DuplicateAndMapRing(HANDLE ovpn_proc, HANDLE orig_handle, HANDLE *new_handle, struct tun_ring **ring)
1351 {
1352     DWORD err = ERROR_SUCCESS;
1353 
1354     err = OvpnDuplicateHandle(ovpn_proc, orig_handle, new_handle);
1355     if (err != ERROR_SUCCESS)
1356     {
1357         return err;
1358     }
1359     *ring = (struct tun_ring *)MapViewOfFile(*new_handle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(struct tun_ring));
1360     if (*ring == NULL)
1361     {
1362         err = GetLastError();
1363         MsgToEventLog(M_SYSERR, TEXT("Could not map shared memory"));
1364         return err;
1365     }
1366 
1367     return err;
1368 }
1369 
1370 static DWORD
HandleRegisterRingBuffers(const register_ring_buffers_message_t * rrb,HANDLE ovpn_proc,ring_buffer_handles_t * ring_buffer_handles)1371 HandleRegisterRingBuffers(const register_ring_buffers_message_t *rrb, HANDLE ovpn_proc,
1372                           ring_buffer_handles_t *ring_buffer_handles)
1373 {
1374     DWORD err = 0;
1375     struct tun_ring *send_ring;
1376     struct tun_ring *receive_ring;
1377 
1378     CloseRingBufferHandles(ring_buffer_handles);
1379 
1380     err = OvpnDuplicateHandle(ovpn_proc, rrb->device, &ring_buffer_handles->device);
1381     if (err != ERROR_SUCCESS)
1382     {
1383         return err;
1384     }
1385 
1386     err = DuplicateAndMapRing(ovpn_proc, rrb->send_ring_handle, &ring_buffer_handles->send_ring_handle, &send_ring);
1387     if (err != ERROR_SUCCESS)
1388     {
1389         return err;
1390     }
1391 
1392     err = DuplicateAndMapRing(ovpn_proc, rrb->receive_ring_handle, &ring_buffer_handles->receive_ring_handle, &receive_ring);
1393     if (err != ERROR_SUCCESS)
1394     {
1395         return err;
1396     }
1397 
1398     err = OvpnDuplicateHandle(ovpn_proc, rrb->send_tail_moved, &ring_buffer_handles->send_tail_moved);
1399     if (err != ERROR_SUCCESS)
1400     {
1401         return err;
1402     }
1403 
1404     err = OvpnDuplicateHandle(ovpn_proc, rrb->receive_tail_moved, &ring_buffer_handles->receive_tail_moved);
1405     if (err != ERROR_SUCCESS)
1406     {
1407         return err;
1408     }
1409 
1410     if (!register_ring_buffers(ring_buffer_handles->device, send_ring, receive_ring,
1411                                ring_buffer_handles->send_tail_moved, ring_buffer_handles->receive_tail_moved))
1412     {
1413         err = GetLastError();
1414         MsgToEventLog(M_SYSERR, TEXT("Could not register ring buffers"));
1415     }
1416 
1417     return err;
1418 }
1419 
1420 static DWORD
HandleMTUMessage(const set_mtu_message_t * mtu)1421 HandleMTUMessage(const set_mtu_message_t *mtu)
1422 {
1423     DWORD err = 0;
1424     MIB_IPINTERFACE_ROW ipiface;
1425     InitializeIpInterfaceEntry(&ipiface);
1426     ipiface.Family = mtu->family;
1427     ipiface.InterfaceIndex = mtu->iface.index;
1428     err = GetIpInterfaceEntry(&ipiface);
1429     if (err != NO_ERROR)
1430     {
1431         return err;
1432     }
1433     if (mtu->family == AF_INET)
1434     {
1435         ipiface.SitePrefixLength = 0;
1436     }
1437     ipiface.NlMtu = mtu->mtu;
1438 
1439     err = SetIpInterfaceEntry(&ipiface);
1440     return err;
1441 }
1442 
1443 static VOID
HandleMessage(HANDLE pipe,HANDLE ovpn_proc,ring_buffer_handles_t * ring_buffer_handles,DWORD bytes,DWORD count,LPHANDLE events,undo_lists_t * lists)1444 HandleMessage(HANDLE pipe, HANDLE ovpn_proc, ring_buffer_handles_t *ring_buffer_handles,
1445               DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists)
1446 {
1447     DWORD read;
1448     union {
1449         message_header_t header;
1450         address_message_t address;
1451         route_message_t route;
1452         flush_neighbors_message_t flush_neighbors;
1453         block_dns_message_t block_dns;
1454         dns_cfg_message_t dns;
1455         enable_dhcp_message_t dhcp;
1456         register_ring_buffers_message_t rrb;
1457         set_mtu_message_t mtu;
1458     } msg;
1459     ack_message_t ack = {
1460         .header = {
1461             .type = msg_acknowledgement,
1462             .size = sizeof(ack),
1463             .message_id = -1
1464         },
1465         .error_number = ERROR_MESSAGE_DATA
1466     };
1467 
1468     read = ReadPipeAsync(pipe, &msg, bytes, count, events);
1469     if (read != bytes || read < sizeof(msg.header) || read != msg.header.size)
1470     {
1471         goto out;
1472     }
1473 
1474     ack.header.message_id = msg.header.message_id;
1475 
1476     switch (msg.header.type)
1477     {
1478         case msg_add_address:
1479         case msg_del_address:
1480             if (msg.header.size == sizeof(msg.address))
1481             {
1482                 ack.error_number = HandleAddressMessage(&msg.address, lists);
1483             }
1484             break;
1485 
1486         case msg_add_route:
1487         case msg_del_route:
1488             if (msg.header.size == sizeof(msg.route))
1489             {
1490                 ack.error_number = HandleRouteMessage(&msg.route, lists);
1491             }
1492             break;
1493 
1494         case msg_flush_neighbors:
1495             if (msg.header.size == sizeof(msg.flush_neighbors))
1496             {
1497                 ack.error_number = HandleFlushNeighborsMessage(&msg.flush_neighbors);
1498             }
1499             break;
1500 
1501         case msg_add_block_dns:
1502         case msg_del_block_dns:
1503             if (msg.header.size == sizeof(msg.block_dns))
1504             {
1505                 ack.error_number = HandleBlockDNSMessage(&msg.block_dns, lists);
1506             }
1507             break;
1508 
1509         case msg_register_dns:
1510             ack.error_number = HandleRegisterDNSMessage();
1511             break;
1512 
1513         case msg_add_dns_cfg:
1514         case msg_del_dns_cfg:
1515             ack.error_number = HandleDNSConfigMessage(&msg.dns, lists);
1516             break;
1517 
1518         case msg_enable_dhcp:
1519             if (msg.header.size == sizeof(msg.dhcp))
1520             {
1521                 ack.error_number = HandleEnableDHCPMessage(&msg.dhcp);
1522             }
1523             break;
1524 
1525         case msg_register_ring_buffers:
1526             if (msg.header.size == sizeof(msg.rrb))
1527             {
1528                 ack.error_number = HandleRegisterRingBuffers(&msg.rrb, ovpn_proc, ring_buffer_handles);
1529             }
1530             break;
1531 
1532         case msg_set_mtu:
1533             if (msg.header.size == sizeof(msg.mtu))
1534             {
1535                 ack.error_number = HandleMTUMessage(&msg.mtu);
1536             }
1537             break;
1538 
1539         default:
1540             ack.error_number = ERROR_MESSAGE_TYPE;
1541             MsgToEventLog(MSG_FLAGS_ERROR, TEXT("Unknown message type %d"), msg.header.type);
1542             break;
1543     }
1544 
1545 out:
1546     WritePipeAsync(pipe, &ack, sizeof(ack), count, events);
1547 }
1548 
1549 
1550 static VOID
Undo(undo_lists_t * lists)1551 Undo(undo_lists_t *lists)
1552 {
1553     undo_type_t type;
1554     block_dns_data_t *interface_data;
1555     for (type = 0; type < _undo_type_max; type++)
1556     {
1557         list_item_t **pnext = &(*lists)[type];
1558         while (*pnext)
1559         {
1560             list_item_t *item = *pnext;
1561             switch (type)
1562             {
1563                 case address:
1564                     DeleteAddress(item->data);
1565                     break;
1566 
1567                 case route:
1568                     DeleteRoute(item->data);
1569                     break;
1570 
1571                 case undo_dns4:
1572                     DeleteDNS(AF_INET, item->data);
1573                     break;
1574 
1575                 case undo_dns6:
1576                     DeleteDNS(AF_INET6, item->data);
1577                     break;
1578 
1579                 case undo_domain:
1580                     SetDNSDomain(item->data, "", NULL);
1581                     break;
1582 
1583                 case block_dns:
1584                     interface_data = (block_dns_data_t *)(item->data);
1585                     delete_block_dns_filters(interface_data->engine);
1586                     if (interface_data->metric_v4 >= 0)
1587                     {
1588                         set_interface_metric(interface_data->index, AF_INET,
1589                                              interface_data->metric_v4);
1590                     }
1591                     if (interface_data->metric_v6 >= 0)
1592                     {
1593                         set_interface_metric(interface_data->index, AF_INET6,
1594                                              interface_data->metric_v6);
1595                     }
1596                     break;
1597             }
1598 
1599             /* Remove from the list and free memory */
1600             *pnext = item->next;
1601             free(item->data);
1602             free(item);
1603         }
1604     }
1605 }
1606 
1607 static DWORD WINAPI
RunOpenvpn(LPVOID p)1608 RunOpenvpn(LPVOID p)
1609 {
1610     HANDLE pipe = p;
1611     HANDLE ovpn_pipe = NULL, svc_pipe = NULL;
1612     PTOKEN_USER svc_user = NULL, ovpn_user = NULL;
1613     HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL;
1614     HANDLE stdin_read = NULL, stdin_write = NULL;
1615     HANDLE stdout_write = NULL;
1616     DWORD pipe_mode, len, exit_code = 0;
1617     STARTUP_DATA sud = { 0, 0, 0 };
1618     STARTUPINFOW startup_info;
1619     PROCESS_INFORMATION proc_info;
1620     LPVOID user_env = NULL;
1621     TCHAR ovpn_pipe_name[256]; /* The entire pipe name string can be up to 256 characters long according to MSDN. */
1622     LPCWSTR exe_path;
1623     WCHAR *cmdline = NULL;
1624     size_t cmdline_size;
1625     undo_lists_t undo_lists;
1626     ring_buffer_handles_t ring_buffer_handles;
1627     WCHAR errmsg[512] = L"";
1628 
1629     SECURITY_ATTRIBUTES inheritable = {
1630         .nLength = sizeof(inheritable),
1631         .lpSecurityDescriptor = NULL,
1632         .bInheritHandle = TRUE
1633     };
1634 
1635     PACL ovpn_dacl;
1636     EXPLICIT_ACCESS ea[2];
1637     SECURITY_DESCRIPTOR ovpn_sd;
1638     SECURITY_ATTRIBUTES ovpn_sa = {
1639         .nLength = sizeof(ovpn_sa),
1640         .lpSecurityDescriptor = &ovpn_sd,
1641         .bInheritHandle = FALSE
1642     };
1643 
1644     ZeroMemory(&ea, sizeof(ea));
1645     ZeroMemory(&startup_info, sizeof(startup_info));
1646     ZeroMemory(&undo_lists, sizeof(undo_lists));
1647     ZeroMemory(&proc_info, sizeof(proc_info));
1648     ZeroMemory(&ring_buffer_handles, sizeof(ring_buffer_handles));
1649 
1650     if (!GetStartupData(pipe, &sud))
1651     {
1652         goto out;
1653     }
1654 
1655     if (!InitializeSecurityDescriptor(&ovpn_sd, SECURITY_DESCRIPTOR_REVISION))
1656     {
1657         ReturnLastError(pipe, L"InitializeSecurityDescriptor");
1658         goto out;
1659     }
1660 
1661     /* Get SID of user the service is running under */
1662     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &svc_token))
1663     {
1664         ReturnLastError(pipe, L"OpenProcessToken");
1665         goto out;
1666     }
1667     len = 0;
1668     while (!GetTokenInformation(svc_token, TokenUser, svc_user, len, &len))
1669     {
1670         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1671         {
1672             ReturnLastError(pipe, L"GetTokenInformation (service token)");
1673             goto out;
1674         }
1675         free(svc_user);
1676         svc_user = malloc(len);
1677         if (svc_user == NULL)
1678         {
1679             ReturnLastError(pipe, L"malloc (service token user)");
1680             goto out;
1681         }
1682     }
1683     if (!IsValidSid(svc_user->User.Sid))
1684     {
1685         ReturnLastError(pipe, L"IsValidSid (service token user)");
1686         goto out;
1687     }
1688 
1689     if (!ImpersonateNamedPipeClient(pipe))
1690     {
1691         ReturnLastError(pipe, L"ImpersonateNamedPipeClient");
1692         goto out;
1693     }
1694     if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &imp_token))
1695     {
1696         ReturnLastError(pipe, L"OpenThreadToken");
1697         goto out;
1698     }
1699     len = 0;
1700     while (!GetTokenInformation(imp_token, TokenUser, ovpn_user, len, &len))
1701     {
1702         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1703         {
1704             ReturnLastError(pipe, L"GetTokenInformation (impersonation token)");
1705             goto out;
1706         }
1707         free(ovpn_user);
1708         ovpn_user = malloc(len);
1709         if (ovpn_user == NULL)
1710         {
1711             ReturnLastError(pipe, L"malloc (impersonation token user)");
1712             goto out;
1713         }
1714     }
1715     if (!IsValidSid(ovpn_user->User.Sid))
1716     {
1717         ReturnLastError(pipe, L"IsValidSid (impersonation token user)");
1718         goto out;
1719     }
1720 
1721     /*
1722      * Only authorized users are allowed to use any command line options or
1723      * have the config file in locations other than the global config directory.
1724      *
1725      * Check options are white-listed and config is in the global directory
1726      * OR user is authorized to run any config.
1727      */
1728     if (!ValidateOptions(pipe, sud.directory, sud.options, errmsg, _countof(errmsg))
1729         && !IsAuthorizedUser(ovpn_user->User.Sid, imp_token, settings.ovpn_admin_group))
1730     {
1731         ReturnError(pipe, ERROR_STARTUP_DATA, errmsg, 1, &exit_event);
1732         goto out;
1733     }
1734 
1735     /* OpenVPN process DACL entry for access by service and user */
1736     ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
1737     ea[0].grfAccessMode = SET_ACCESS;
1738     ea[0].grfInheritance = NO_INHERITANCE;
1739     ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
1740     ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
1741     ea[0].Trustee.ptstrName = (LPTSTR) svc_user->User.Sid;
1742     ea[1].grfAccessPermissions = READ_CONTROL | SYNCHRONIZE | PROCESS_VM_READ
1743                                  |SYNCHRONIZE | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION;
1744     ea[1].grfAccessMode = SET_ACCESS;
1745     ea[1].grfInheritance = NO_INHERITANCE;
1746     ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
1747     ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
1748     ea[1].Trustee.ptstrName = (LPTSTR) ovpn_user->User.Sid;
1749 
1750     /* Set owner and DACL of OpenVPN security descriptor */
1751     if (!SetSecurityDescriptorOwner(&ovpn_sd, svc_user->User.Sid, FALSE))
1752     {
1753         ReturnLastError(pipe, L"SetSecurityDescriptorOwner");
1754         goto out;
1755     }
1756     if (SetEntriesInAcl(2, ea, NULL, &ovpn_dacl) != ERROR_SUCCESS)
1757     {
1758         ReturnLastError(pipe, L"SetEntriesInAcl");
1759         goto out;
1760     }
1761     if (!SetSecurityDescriptorDacl(&ovpn_sd, TRUE, ovpn_dacl, FALSE))
1762     {
1763         ReturnLastError(pipe, L"SetSecurityDescriptorDacl");
1764         goto out;
1765     }
1766 
1767     /* Create primary token from impersonation token */
1768     if (!DuplicateTokenEx(imp_token, TOKEN_ALL_ACCESS, NULL, 0, TokenPrimary, &pri_token))
1769     {
1770         ReturnLastError(pipe, L"DuplicateTokenEx");
1771         goto out;
1772     }
1773 
1774     /* use /dev/null for stdout of openvpn (client should use --log for output) */
1775     stdout_write = CreateFile(_T("NUL"), GENERIC_WRITE, FILE_SHARE_WRITE,
1776                               &inheritable, OPEN_EXISTING, 0, NULL);
1777     if (stdout_write == INVALID_HANDLE_VALUE)
1778     {
1779         ReturnLastError(pipe, L"CreateFile for stdout");
1780         goto out;
1781     }
1782 
1783     if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0)
1784         || !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0))
1785     {
1786         ReturnLastError(pipe, L"CreatePipe");
1787         goto out;
1788     }
1789 
1790     openvpn_sntprintf(ovpn_pipe_name, _countof(ovpn_pipe_name),
1791                       TEXT("\\\\.\\pipe\\" PACKAGE "%s\\service_%lu"), service_instance, GetCurrentThreadId());
1792     ovpn_pipe = CreateNamedPipe(ovpn_pipe_name,
1793                                 PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
1794                                 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 128, 128, 0, NULL);
1795     if (ovpn_pipe == INVALID_HANDLE_VALUE)
1796     {
1797         ReturnLastError(pipe, L"CreateNamedPipe");
1798         goto out;
1799     }
1800 
1801     svc_pipe = CreateFile(ovpn_pipe_name, GENERIC_READ | GENERIC_WRITE, 0,
1802                           &inheritable, OPEN_EXISTING, 0, NULL);
1803     if (svc_pipe == INVALID_HANDLE_VALUE)
1804     {
1805         ReturnLastError(pipe, L"CreateFile");
1806         goto out;
1807     }
1808 
1809     pipe_mode = PIPE_READMODE_MESSAGE;
1810     if (!SetNamedPipeHandleState(svc_pipe, &pipe_mode, NULL, NULL))
1811     {
1812         ReturnLastError(pipe, L"SetNamedPipeHandleState");
1813         goto out;
1814     }
1815 
1816     cmdline_size = wcslen(sud.options) + 128;
1817     cmdline = malloc(cmdline_size * sizeof(*cmdline));
1818     if (cmdline == NULL)
1819     {
1820         ReturnLastError(pipe, L"malloc");
1821         goto out;
1822     }
1823     openvpn_sntprintf(cmdline, cmdline_size, L"openvpn %s --msg-channel %lu",
1824                       sud.options, svc_pipe);
1825 
1826     if (!CreateEnvironmentBlock(&user_env, imp_token, FALSE))
1827     {
1828         ReturnLastError(pipe, L"CreateEnvironmentBlock");
1829         goto out;
1830     }
1831 
1832     startup_info.cb = sizeof(startup_info);
1833     startup_info.lpDesktop = L"winsta0\\default";
1834     startup_info.dwFlags = STARTF_USESTDHANDLES;
1835     startup_info.hStdInput = stdin_read;
1836     startup_info.hStdOutput = stdout_write;
1837     startup_info.hStdError = stdout_write;
1838 
1839 #ifdef UNICODE
1840     exe_path = settings.exe_path;
1841 #else
1842     WCHAR wide_path[MAX_PATH];
1843     MultiByteToWideChar(CP_UTF8, 0, settings.exe_path, MAX_PATH, wide_path, MAX_PATH);
1844     exe_path = wide_path;
1845 #endif
1846 
1847     /* TODO: make sure HKCU is correct or call LoadUserProfile() */
1848     if (!CreateProcessAsUserW(pri_token, exe_path, cmdline, &ovpn_sa, NULL, TRUE,
1849                               settings.priority | CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT,
1850                               user_env, sud.directory, &startup_info, &proc_info))
1851     {
1852         ReturnLastError(pipe, L"CreateProcessAsUser");
1853         goto out;
1854     }
1855 
1856     if (!RevertToSelf())
1857     {
1858         TerminateProcess(proc_info.hProcess, 1);
1859         ReturnLastError(pipe, L"RevertToSelf");
1860         goto out;
1861     }
1862 
1863     ReturnProcessId(pipe, proc_info.dwProcessId, 1, &exit_event);
1864 
1865     CloseHandleEx(&stdout_write);
1866     CloseHandleEx(&stdin_read);
1867     CloseHandleEx(&svc_pipe);
1868 
1869     DWORD input_size = WideCharToMultiByte(CP_UTF8, 0, sud.std_input, -1, NULL, 0, NULL, NULL);
1870     LPSTR input = NULL;
1871     if (input_size && (input = malloc(input_size)))
1872     {
1873         DWORD written;
1874         WideCharToMultiByte(CP_UTF8, 0, sud.std_input, -1, input, input_size, NULL, NULL);
1875         WriteFile(stdin_write, input, (DWORD)strlen(input), &written, NULL);
1876         free(input);
1877     }
1878 
1879     while (TRUE)
1880     {
1881         DWORD bytes = PeekNamedPipeAsync(ovpn_pipe, 1, &exit_event);
1882         if (bytes == 0)
1883         {
1884             break;
1885         }
1886 
1887         HandleMessage(ovpn_pipe, proc_info.hProcess, &ring_buffer_handles, bytes, 1, &exit_event, &undo_lists);
1888     }
1889 
1890     WaitForSingleObject(proc_info.hProcess, IO_TIMEOUT);
1891     GetExitCodeProcess(proc_info.hProcess, &exit_code);
1892     if (exit_code == STILL_ACTIVE)
1893     {
1894         TerminateProcess(proc_info.hProcess, 1);
1895     }
1896     else if (exit_code != 0)
1897     {
1898         WCHAR buf[256];
1899         openvpn_swprintf(buf, _countof(buf),
1900                          L"OpenVPN exited with error: exit code = %lu", exit_code);
1901         ReturnError(pipe, ERROR_OPENVPN_STARTUP, buf, 1, &exit_event);
1902     }
1903     Undo(&undo_lists);
1904 
1905 out:
1906     FlushFileBuffers(pipe);
1907     DisconnectNamedPipe(pipe);
1908 
1909     free(ovpn_user);
1910     free(svc_user);
1911     free(cmdline);
1912     DestroyEnvironmentBlock(user_env);
1913     FreeStartupData(&sud);
1914     CloseRingBufferHandles(&ring_buffer_handles);
1915     CloseHandleEx(&proc_info.hProcess);
1916     CloseHandleEx(&proc_info.hThread);
1917     CloseHandleEx(&stdin_read);
1918     CloseHandleEx(&stdin_write);
1919     CloseHandleEx(&stdout_write);
1920     CloseHandleEx(&svc_token);
1921     CloseHandleEx(&imp_token);
1922     CloseHandleEx(&pri_token);
1923     CloseHandleEx(&ovpn_pipe);
1924     CloseHandleEx(&svc_pipe);
1925     CloseHandleEx(&pipe);
1926 
1927     return 0;
1928 }
1929 
1930 
1931 static DWORD WINAPI
ServiceCtrlInteractive(DWORD ctrl_code,DWORD event,LPVOID data,LPVOID ctx)1932 ServiceCtrlInteractive(DWORD ctrl_code, DWORD event, LPVOID data, LPVOID ctx)
1933 {
1934     SERVICE_STATUS *status = ctx;
1935     switch (ctrl_code)
1936     {
1937         case SERVICE_CONTROL_STOP:
1938             status->dwCurrentState = SERVICE_STOP_PENDING;
1939             ReportStatusToSCMgr(service, status);
1940             if (exit_event)
1941             {
1942                 SetEvent(exit_event);
1943             }
1944             return NO_ERROR;
1945 
1946         case SERVICE_CONTROL_INTERROGATE:
1947             return NO_ERROR;
1948 
1949         default:
1950             return ERROR_CALL_NOT_IMPLEMENTED;
1951     }
1952 }
1953 
1954 
1955 static HANDLE
CreateClientPipeInstance(VOID)1956 CreateClientPipeInstance(VOID)
1957 {
1958     TCHAR pipe_name[256]; /* The entire pipe name string can be up to 256 characters long according to MSDN. */
1959     HANDLE pipe = NULL;
1960     PACL old_dacl, new_dacl;
1961     PSECURITY_DESCRIPTOR sd;
1962     static EXPLICIT_ACCESS ea[2];
1963     static BOOL initialized = FALSE;
1964     DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED;
1965 
1966     if (!initialized)
1967     {
1968         PSID everyone, anonymous;
1969 
1970         ConvertStringSidToSid(TEXT("S-1-1-0"), &everyone);
1971         ConvertStringSidToSid(TEXT("S-1-5-7"), &anonymous);
1972 
1973         ea[0].grfAccessPermissions = FILE_GENERIC_WRITE;
1974         ea[0].grfAccessMode = GRANT_ACCESS;
1975         ea[0].grfInheritance = NO_INHERITANCE;
1976         ea[0].Trustee.pMultipleTrustee = NULL;
1977         ea[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
1978         ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
1979         ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
1980         ea[0].Trustee.ptstrName = (LPTSTR) everyone;
1981 
1982         ea[1].grfAccessPermissions = 0;
1983         ea[1].grfAccessMode = REVOKE_ACCESS;
1984         ea[1].grfInheritance = NO_INHERITANCE;
1985         ea[1].Trustee.pMultipleTrustee = NULL;
1986         ea[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
1987         ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
1988         ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
1989         ea[1].Trustee.ptstrName = (LPTSTR) anonymous;
1990 
1991         flags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
1992         initialized = TRUE;
1993     }
1994 
1995     openvpn_sntprintf(pipe_name, _countof(pipe_name), TEXT("\\\\.\\pipe\\" PACKAGE "%s\\service"), service_instance);
1996     pipe = CreateNamedPipe(pipe_name, flags,
1997                            PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
1998                            PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, NULL);
1999     if (pipe == INVALID_HANDLE_VALUE)
2000     {
2001         MsgToEventLog(M_SYSERR, TEXT("Could not create named pipe"));
2002         return INVALID_HANDLE_VALUE;
2003     }
2004 
2005     if (GetSecurityInfo(pipe, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
2006                         NULL, NULL, &old_dacl, NULL, &sd) != ERROR_SUCCESS)
2007     {
2008         MsgToEventLog(M_SYSERR, TEXT("Could not get pipe security info"));
2009         return CloseHandleEx(&pipe);
2010     }
2011 
2012     if (SetEntriesInAcl(2, ea, old_dacl, &new_dacl) != ERROR_SUCCESS)
2013     {
2014         MsgToEventLog(M_SYSERR, TEXT("Could not set entries in new acl"));
2015         return CloseHandleEx(&pipe);
2016     }
2017 
2018     if (SetSecurityInfo(pipe, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
2019                         NULL, NULL, new_dacl, NULL) != ERROR_SUCCESS)
2020     {
2021         MsgToEventLog(M_SYSERR, TEXT("Could not set pipe security info"));
2022         return CloseHandleEx(&pipe);
2023     }
2024 
2025     return pipe;
2026 }
2027 
2028 
2029 static DWORD
UpdateWaitHandles(LPHANDLE * handles_ptr,LPDWORD count,HANDLE io_event,HANDLE exit_event,list_item_t * threads)2030 UpdateWaitHandles(LPHANDLE *handles_ptr, LPDWORD count,
2031                   HANDLE io_event, HANDLE exit_event, list_item_t *threads)
2032 {
2033     static DWORD size = 10;
2034     static LPHANDLE handles = NULL;
2035     DWORD pos = 0;
2036 
2037     if (handles == NULL)
2038     {
2039         handles = malloc(size * sizeof(HANDLE));
2040         *handles_ptr = handles;
2041         if (handles == NULL)
2042         {
2043             return ERROR_OUTOFMEMORY;
2044         }
2045     }
2046 
2047     handles[pos++] = io_event;
2048 
2049     if (!threads)
2050     {
2051         handles[pos++] = exit_event;
2052     }
2053 
2054     while (threads)
2055     {
2056         if (pos == size)
2057         {
2058             LPHANDLE tmp;
2059             size += 10;
2060             tmp = realloc(handles, size * sizeof(HANDLE));
2061             if (tmp == NULL)
2062             {
2063                 size -= 10;
2064                 *count = pos;
2065                 return ERROR_OUTOFMEMORY;
2066             }
2067             handles = tmp;
2068             *handles_ptr = handles;
2069         }
2070         handles[pos++] = threads->data;
2071         threads = threads->next;
2072     }
2073 
2074     *count = pos;
2075     return NO_ERROR;
2076 }
2077 
2078 
2079 static VOID
FreeWaitHandles(LPHANDLE h)2080 FreeWaitHandles(LPHANDLE h)
2081 {
2082     free(h);
2083 }
2084 
2085 static BOOL
CmpHandle(LPVOID item,LPVOID hnd)2086 CmpHandle(LPVOID item, LPVOID hnd)
2087 {
2088     return item == hnd;
2089 }
2090 
2091 
2092 VOID WINAPI
ServiceStartInteractiveOwn(DWORD dwArgc,LPTSTR * lpszArgv)2093 ServiceStartInteractiveOwn(DWORD dwArgc, LPTSTR *lpszArgv)
2094 {
2095     status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
2096     ServiceStartInteractive(dwArgc, lpszArgv);
2097 }
2098 
2099 
2100 VOID WINAPI
ServiceStartInteractive(DWORD dwArgc,LPTSTR * lpszArgv)2101 ServiceStartInteractive(DWORD dwArgc, LPTSTR *lpszArgv)
2102 {
2103     HANDLE pipe, io_event = NULL;
2104     OVERLAPPED overlapped;
2105     DWORD error = NO_ERROR;
2106     list_item_t *threads = NULL;
2107     PHANDLE handles = NULL;
2108     DWORD handle_count;
2109 
2110     service = RegisterServiceCtrlHandlerEx(interactive_service.name, ServiceCtrlInteractive, &status);
2111     if (!service)
2112     {
2113         return;
2114     }
2115 
2116     status.dwCurrentState = SERVICE_START_PENDING;
2117     status.dwServiceSpecificExitCode = NO_ERROR;
2118     status.dwWin32ExitCode = NO_ERROR;
2119     status.dwWaitHint = 3000;
2120     ReportStatusToSCMgr(service, &status);
2121 
2122     /* Read info from registry in key HKLM\SOFTWARE\OpenVPN */
2123     error = GetOpenvpnSettings(&settings);
2124     if (error != ERROR_SUCCESS)
2125     {
2126         goto out;
2127     }
2128 
2129     io_event = InitOverlapped(&overlapped);
2130     exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
2131     if (!exit_event || !io_event)
2132     {
2133         error = MsgToEventLog(M_SYSERR, TEXT("Could not create event"));
2134         goto out;
2135     }
2136 
2137     rdns_semaphore = CreateSemaphoreW(NULL, 1, 1, NULL);
2138     if (!rdns_semaphore)
2139     {
2140         error = MsgToEventLog(M_SYSERR, TEXT("Could not create semaphore for register-dns"));
2141         goto out;
2142     }
2143 
2144     error = UpdateWaitHandles(&handles, &handle_count, io_event, exit_event, threads);
2145     if (error != NO_ERROR)
2146     {
2147         goto out;
2148     }
2149 
2150     pipe = CreateClientPipeInstance();
2151     if (pipe == INVALID_HANDLE_VALUE)
2152     {
2153         goto out;
2154     }
2155 
2156     status.dwCurrentState = SERVICE_RUNNING;
2157     status.dwWaitHint = 0;
2158     ReportStatusToSCMgr(service, &status);
2159 
2160     while (TRUE)
2161     {
2162         if (ConnectNamedPipe(pipe, &overlapped) == FALSE
2163             && GetLastError() != ERROR_PIPE_CONNECTED
2164             && GetLastError() != ERROR_IO_PENDING)
2165         {
2166             MsgToEventLog(M_SYSERR, TEXT("Could not connect pipe"));
2167             break;
2168         }
2169 
2170         error = WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
2171         if (error == WAIT_OBJECT_0)
2172         {
2173             /* Client connected, spawn a worker thread for it */
2174             HANDLE next_pipe = CreateClientPipeInstance();
2175             HANDLE thread = CreateThread(NULL, 0, RunOpenvpn, pipe, CREATE_SUSPENDED, NULL);
2176             if (thread)
2177             {
2178                 error = AddListItem(&threads, thread);
2179                 if (!error)
2180                 {
2181                     error = UpdateWaitHandles(&handles, &handle_count, io_event, exit_event, threads);
2182                 }
2183                 if (error)
2184                 {
2185                     ReturnError(pipe, error, L"Insufficient resources to service new clients", 1, &exit_event);
2186                     /* Update wait handles again after removing the last worker thread */
2187                     RemoveListItem(&threads, CmpHandle, thread);
2188                     UpdateWaitHandles(&handles, &handle_count, io_event, exit_event, threads);
2189                     TerminateThread(thread, 1);
2190                     CloseHandleEx(&thread);
2191                     CloseHandleEx(&pipe);
2192                 }
2193                 else
2194                 {
2195                     ResumeThread(thread);
2196                 }
2197             }
2198             else
2199             {
2200                 CloseHandleEx(&pipe);
2201             }
2202 
2203             ResetOverlapped(&overlapped);
2204             pipe = next_pipe;
2205         }
2206         else
2207         {
2208             CancelIo(pipe);
2209             if (error == WAIT_FAILED)
2210             {
2211                 MsgToEventLog(M_SYSERR, TEXT("WaitForMultipleObjects failed"));
2212                 SetEvent(exit_event);
2213                 /* Give some time for worker threads to exit and then terminate */
2214                 Sleep(1000);
2215                 break;
2216             }
2217             if (!threads)
2218             {
2219                 /* exit event signaled */
2220                 CloseHandleEx(&pipe);
2221                 ResetEvent(exit_event);
2222                 error = NO_ERROR;
2223                 break;
2224             }
2225 
2226             /* Worker thread ended */
2227             HANDLE thread = RemoveListItem(&threads, CmpHandle, handles[error]);
2228             UpdateWaitHandles(&handles, &handle_count, io_event, exit_event, threads);
2229             CloseHandleEx(&thread);
2230         }
2231     }
2232 
2233 out:
2234     FreeWaitHandles(handles);
2235     CloseHandleEx(&io_event);
2236     CloseHandleEx(&exit_event);
2237     CloseHandleEx(&rdns_semaphore);
2238 
2239     status.dwCurrentState = SERVICE_STOPPED;
2240     status.dwWin32ExitCode = error;
2241     ReportStatusToSCMgr(service, &status);
2242 }
2243