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