38#include <versionhelpers.h>
45#define IO_TIMEOUT 2000
47#define ERROR_OPENVPN_STARTUP 0x20000000
48#define ERROR_STARTUP_DATA 0x20000001
49#define ERROR_MESSAGE_DATA 0x20000002
50#define ERROR_MESSAGE_TYPE 0x20000003
53static SERVICE_STATUS
status = { .dwServiceType = SERVICE_WIN32_SHARE_PROCESS };
57#define RDNS_TIMEOUT 600
59#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
63 TEXT(PACKAGE_NAME) TEXT(
"ServiceInteractive"),
64 TEXT(PACKAGE_NAME) TEXT(
" Interactive Service"),
127 if (new_item == NULL)
129 return ERROR_OUTOFMEMORY;
132 new_item->
next = *pfirst;
133 new_item->
data = data;
147 for (pnext = pfirst; *pnext; pnext = &(*pnext)->
next)
150 if (!match(item->
data, ctx))
168 if (handle && *handle && *handle != INVALID_HANDLE_VALUE)
170 CloseHandle(*handle);
171 *handle = INVALID_HANDLE_VALUE;
173 return INVALID_HANDLE_VALUE;
181 UnmapViewOfFile(*ring);
196 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
197 overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
198 return overlapped->hEvent;
205 HANDLE io_event = overlapped->hEvent;
206 if (!ResetEvent(io_event))
210 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
211 overlapped->hEvent = io_event;
228 DWORD res, bytes = 0;
229 OVERLAPPED overlapped;
230 LPHANDLE handles = NULL;
238 handles = malloc((count + 1) *
sizeof(HANDLE));
246 success = WriteFile(pipe,
buffer, size, NULL, &overlapped);
250 success = ReadFile(pipe,
buffer, size, NULL, &overlapped);
252 if (!success && GetLastError() != ERROR_IO_PENDING && GetLastError() != ERROR_MORE_DATA)
257 handles[0] = io_event;
258 for (i = 0; i < count; i++)
260 handles[i + 1] = events[i];
263 res = WaitForMultipleObjects(count + 1, handles, FALSE,
265 if (res != WAIT_OBJECT_0)
273 PeekNamedPipe(pipe, NULL, 0, NULL, &bytes, NULL);
277 GetOverlappedResult(pipe, &overlapped, &bytes, TRUE);
299WritePipeAsync(HANDLE pipe, LPVOID data, DWORD size, DWORD count, LPHANDLE events)
307 const WCHAR
msg[] = L
"Process ID";
308 WCHAR buf[22 + _countof(
msg)];
314 swprintf(buf, _countof(buf), L
"0x%08x\n0x%08x\n%ls", 0, pid,
msg);
316 WritePipeAsync(pipe, buf, (DWORD)(wcslen(buf) * 2), count, events);
320ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events)
323 LPWSTR result = L
"0xffffffff\nFormatMessage failed\nCould not return result";
332 FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM
333 |FORMAT_MESSAGE_ALLOCATE_BUFFER
334 |FORMAT_MESSAGE_IGNORE_INSERTS,
335 0, error, 0, (LPWSTR) &args[2], 0, NULL);
338 result_len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING
339 |FORMAT_MESSAGE_ALLOCATE_BUFFER
340 |FORMAT_MESSAGE_ARGUMENT_ARRAY,
341 L
"0x%1!08x!\n%2!s!\n%3!s!", 0, 0,
342 (LPWSTR) &result, 0, (va_list *) args);
344 WritePipeAsync(pipe, result, (DWORD)(wcslen(result) * 2), count, events);
349 LocalFree((LPVOID) args[2]);
376 const WCHAR *msg1 = L
"You have specified a config file location (%ls relative to %ls)"
377 L
" that requires admin approval. This error may be avoided"
378 L
" by adding your account to the \"%ls\" group";
380 const WCHAR *msg2 = L
"You have specified an option (%ls) that may be used"
381 L
" only with admin approval. This error may be avoided"
382 L
" by adding your account to the \"%ls\" group";
388 swprintf(errmsg, capacity,
389 L
"Cannot validate options: CommandLineToArgvW failed with error = 0x%08x",
406 WCHAR *argv_tmp[2] = { L
"--config",
argv[0] };
410 swprintf(errmsg, capacity, msg1,
argv[0], workdir,
416 for (i = 0; i < argc; ++i)
425 if (wcscmp(L
"--config",
argv[i]) == 0 && argc-i > 1)
427 swprintf(errmsg, capacity, msg1,
argv[i+1], workdir,
432 swprintf(errmsg, capacity, msg2,
argv[i],
465 size = bytes /
sizeof(*data);
473 data = malloc(bytes);
489 if (data[size - 1] != 0)
507 len = wcslen(sud->
options) + 1;
536 SOCKADDR_INET sa_inet;
537 ZeroMemory(&sa_inet,
sizeof(sa_inet));
538 sa_inet.si_family = family;
539 if (family == AF_INET)
541 sa_inet.Ipv4.sin_addr = addr->
ipv4;
543 else if (family == AF_INET6)
545 sa_inet.Ipv6.sin6_addr = addr->
ipv6;
554 LPWSTR wide_name =
utf8to16(iface_name);
558 status = ConvertInterfaceAliasToLuid(wide_name, luid);
563 status = ERROR_OUTOFMEMORY;
574 err = ConvertInterfaceAliasToLuid(ifname, &luid);
575 if (err == ERROR_SUCCESS)
577 err = ConvertInterfaceLuidToIndex(&luid, index);
579 if (err != ERROR_SUCCESS)
589 return memcmp(item,
address,
sizeof(MIB_UNICASTIPADDRESS_ROW)) == 0 ? TRUE : FALSE;
595 return DeleteUnicastIpAddressEntry(addr_row);
602 PMIB_UNICASTIPADDRESS_ROW addr_row;
605 addr_row = malloc(
sizeof(*addr_row));
606 if (addr_row == NULL)
608 return ERROR_OUTOFMEMORY;
611 InitializeUnicastIpAddressEntry(addr_row);
613 addr_row->OnLinkPrefixLength = (UINT8)
msg->prefix_len;
615 if (
msg->iface.index != -1)
617 addr_row->InterfaceIndex =
msg->iface.index;
627 addr_row->InterfaceLuid = luid;
632 err = CreateUnicastIpAddressEntry(addr_row);
667 return memcmp(item,
route,
sizeof(MIB_IPFORWARD_ROW2)) == 0 ? TRUE : FALSE;
673 return DeleteIpForwardEntry2(fwd_row);
680 PMIB_IPFORWARD_ROW2 fwd_row;
683 fwd_row = malloc(
sizeof(*fwd_row));
686 return ERROR_OUTOFMEMORY;
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;
695 fwd_row->DestinationPrefix.PrefixLength = (UINT8)
msg->prefix_len;
698 if (
msg->iface.index != -1)
700 fwd_row->InterfaceIndex =
msg->iface.index;
702 else if (strlen(
msg->iface.name))
710 fwd_row->InterfaceLuid = luid;
715 err = CreateIpForwardEntry2(fwd_row);
751 if (
msg->family == AF_INET)
753 return FlushIpNetTable(
msg->iface.index);
756 return FlushIpNetTable2(
msg->family,
msg->iface.index);
770 err_str = TEXT(
"Unknown Win32 Error");
772 if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM
773 | FORMAT_MESSAGE_ARGUMENT_ARRAY,
774 NULL, err, 0, buf,
sizeof(buf), NULL))
823 HANDLE engine = NULL;
836 err = ERROR_OUTOFMEMORY;
839 block_data->
engine = engine;
840 block_data->
index =
msg->iface.index;
908ExecCommand(
const WCHAR *argv0,
const WCHAR *cmdline, DWORD timeout)
912 PROCESS_INFORMATION pi;
913 DWORD proc_flags = CREATE_NO_WINDOW|CREATE_UNICODE_ENVIRONMENT;
914 WCHAR *cmdline_dup = NULL;
916 ZeroMemory(&si,
sizeof(si));
917 ZeroMemory(&pi,
sizeof(pi));
922 cmdline_dup = _wcsdup(cmdline);
923 if (cmdline_dup && CreateProcessW(argv0, cmdline_dup, NULL, NULL, FALSE,
924 proc_flags, NULL, NULL, &si, &pi) )
926 WaitForSingleObject(pi.hProcess, timeout ? timeout : INFINITE);
927 if (!GetExitCodeProcess(pi.hProcess, &exit_code))
930 exit_code = GetLastError();
932 else if (exit_code == STILL_ACTIVE)
934 exit_code = WAIT_TIMEOUT;
937 TerminateProcess(pi.hProcess, exit_code);
944 argv0, cmdline, exit_code);
951 CloseHandle(pi.hProcess);
952 CloseHandle(pi.hThread);
956 exit_code = GetLastError();
976 WCHAR ipcfg[MAX_PATH];
984 { ipcfg, L
"ipconfig /flushdns", timeout },
985 { ipcfg, L
"ipconfig /registerdns", timeout },
990 swprintf(ipcfg, MAX_PATH, L
"%ls\\%ls",
get_win_sys_path(), L
"ipconfig.exe");
992 if (WaitForMultipleObjects(2, wait_handles, FALSE, timeout) == WAIT_OBJECT_0)
995 for (i = 0; i < _countof(cmds); ++i)
997 ExecCommand(cmds[i].argv0, cmds[i].cmdline, cmds[i].timeout);
1008 err = ERROR_SEM_TIMEOUT;
1017 HANDLE thread = NULL;
1020 thread = CreateThread(NULL, 0,
RegisterDNS, NULL, 0, NULL);
1029 CloseHandle(thread);
1033 err = GetLastError();
1049netsh_dns_cmd(
const wchar_t *action,
const wchar_t *proto,
const wchar_t *if_name,
const wchar_t *addr)
1052 int timeout = 30000;
1053 wchar_t argv0[MAX_PATH];
1054 wchar_t *cmdline = NULL;
1058 if (wcscmp(action, L
"delete") == 0)
1069 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
1074 const wchar_t *fmt = L
"netsh interface %ls %ls dns \"%ls\" %ls";
1077 size_t ncmdline = wcslen(fmt) + wcslen(if_name) + wcslen(addr) + 32 + 1;
1078 cmdline = malloc(ncmdline*
sizeof(
wchar_t));
1081 err = ERROR_OUTOFMEMORY;
1085 swprintf(cmdline, ncmdline, fmt, proto, action, if_name, addr);
1087 if (IsWindows7OrGreater())
1089 wcscat_s(cmdline, ncmdline, L
" validate=no");
1111 int timeout = 30000;
1112 wchar_t argv0[MAX_PATH];
1113 wchar_t *cmdline = NULL;
1114 const wchar_t *addr_static = (wcscmp(action, L
"set") == 0) ? L
"static" : L
"";
1118 if (wcscmp(action, L
"delete") == 0)
1129 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
1134 const wchar_t *fmt = L
"netsh interface ip %ls wins \"%ls\" %ls %ls";
1137 size_t ncmdline = wcslen(fmt) + wcslen(if_name) + wcslen(action) + wcslen(addr)
1138 +wcslen(addr_static) + 32 + 1;
1139 cmdline = malloc(ncmdline *
sizeof(
wchar_t));
1142 err = ERROR_OUTOFMEMORY;
1146 swprintf(cmdline, ncmdline, fmt, action, if_name, addr_static, addr);
1165 const wchar_t *data)
1168 wchar_t argv0[MAX_PATH];
1169 wchar_t *cmdline = NULL;
1170 int timeout = 10000;
1172 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"wbem\\wmic.exe");
1176 if (data && wcschr(data, L
','))
1178 fmt = L
"wmic nicconfig where (InterfaceIndex=%ld) call %ls (%ls)";
1182 fmt = L
"wmic nicconfig where (InterfaceIndex=%ld) call %ls \"%ls\"";
1185 size_t ncmdline = wcslen(fmt) + 20 + wcslen(action)
1186 + (data ? wcslen(data) + 1 : 1);
1187 cmdline = malloc(ncmdline*
sizeof(
wchar_t));
1190 return ERROR_OUTOFMEMORY;
1193 swprintf(cmdline, ncmdline, fmt, if_index, action,
1205 wchar_t *proto = (family == AF_INET6) ? L
"ipv6" : L
"ip";
1211AddDNS(
short family,
wchar_t *if_name,
wchar_t *addr)
1213 wchar_t *proto = (family == AF_INET6) ? L
"ipv6" : L
"ip";
1220 return (wcscmp(item, str) == 0) ? TRUE : FALSE;
1234 NET_IFINDEX if_index;
1237 if (err != ERROR_SUCCESS)
1242 wchar_t *wdomain =
utf8to16(domain);
1245 return ERROR_OUTOFMEMORY;
1257 if (err == 0 && wdomain[0] && lists)
1259 wchar_t *tmp_name = _wcsdup(if_name);
1263 err = ERROR_OUTOFMEMORY;
1277 int addr_len =
msg->addr_len;
1280 if (addr_len > _countof(
msg->addr))
1282 addr_len = _countof(
msg->addr);
1285 if (!
msg->iface.name[0])
1293 msgptr->
iface.
name[_countof(
msg->iface.name)-1] =
'\0';
1294 msgptr->
domains[_countof(
msg->domains)-1] =
'\0';
1300 return ERROR_OUTOFMEMORY;
1318 if (
msg->domains[0])
1326 for (
int i = 0; i < addr_len; ++i)
1328 if (
msg->family == AF_INET6)
1330 RtlIpv6AddressToStringW(&
msg->addr[i].ipv6, addr);
1334 RtlIpv4AddressToStringW(&
msg->addr[i].ipv4, addr);
1336 err =
AddDNS(
msg->family, wide_name, addr);
1348 if (
msg->addr_len > 0)
1350 wchar_t *tmp_name = _wcsdup(wide_name);
1351 if (!tmp_name ||
AddListItem(&(*lists)[undo_type], tmp_name))
1355 err = ERROR_OUTOFMEMORY;
1360 if (
msg->domains[0])
1375 int addr_len =
msg->addr_len;
1378 if (addr_len > _countof(
msg->addr))
1380 addr_len = _countof(
msg->addr);
1383 if (!
msg->iface.name[0])
1391 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
1397 return ERROR_OUTOFMEMORY;
1418 for (
int i = 0; i < addr_len; ++i)
1420 RtlIpv4AddressToStringW(&
msg->addr[i].ipv4, addr);
1435 wchar_t *tmp_name = _wcsdup(wide_name);
1440 err = ERROR_OUTOFMEMORY;
1454 DWORD timeout = 5000;
1455 wchar_t argv0[MAX_PATH];
1458 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
1463 const wchar_t *fmt = L
"netsh interface ipv4 set address name=\"%d\" source=dhcp";
1468 size_t ncmdline = wcslen(fmt) + 10 + 1;
1469 wchar_t *cmdline = malloc(ncmdline*
sizeof(
wchar_t));
1472 err = ERROR_OUTOFMEMORY;
1476 swprintf(cmdline, ncmdline, fmt,
dhcp->iface.index);
1491 DWORD err = ERROR_SUCCESS;
1493 if (!DuplicateHandle(ovpn_proc, orig_handle, GetCurrentProcess(), new_handle, 0, FALSE, DUPLICATE_SAME_ACCESS))
1495 err = GetLastError();
1506 DWORD err = ERROR_SUCCESS;
1508 HANDLE dup_handle = NULL;
1511 if (err != ERROR_SUCCESS)
1515 *ring = (
struct tun_ring *)MapViewOfFile(dup_handle, FILE_MAP_ALL_ACCESS, 0, 0,
sizeof(
struct tun_ring));
1519 err = GetLastError();
1535 if (ring_buffer_maps)
1539 else if ((ring_buffer_maps = calloc(1,
sizeof(*ring_buffer_maps))) == NULL)
1541 return ERROR_OUTOFMEMORY;
1544 HANDLE device = NULL;
1545 HANDLE send_tail_moved = NULL;
1546 HANDLE receive_tail_moved = NULL;
1549 if (err != ERROR_SUCCESS)
1555 if (err != ERROR_SUCCESS)
1561 if (err != ERROR_SUCCESS)
1567 if (err != ERROR_SUCCESS)
1573 if (err != ERROR_SUCCESS)
1580 send_tail_moved, receive_tail_moved))
1582 err = GetLastError();
1590 if (err != ERROR_SUCCESS && ring_buffer_maps)
1593 free(ring_buffer_maps);
1605 MIB_IPINTERFACE_ROW ipiface;
1606 InitializeIpInterfaceEntry(&ipiface);
1607 ipiface.Family = mtu->
family;
1609 err = GetIpInterfaceEntry(&ipiface);
1610 if (err != NO_ERROR)
1614 if (mtu->
family == AF_INET)
1616 ipiface.SitePrefixLength = 0;
1618 ipiface.NlMtu = mtu->
mtu;
1620 err = SetIpInterfaceEntry(&ipiface);
1626 DWORD bytes, DWORD count, LPHANDLE events,
undo_lists_t *lists)
1632 .size =
sizeof(ack),
1646 switch (
msg.header.type)
1650 if (
msg.header.size ==
sizeof(
msg.address))
1658 if (
msg.header.size ==
sizeof(
msg.route))
1665 if (
msg.header.size ==
sizeof(
msg.flush_neighbors))
1673 if (
msg.header.size ==
sizeof(
msg.wfp_block))
1694 if (
msg.header.size ==
sizeof(
msg.dhcp))
1701 if (
msg.header.size ==
sizeof(
msg.rrb))
1708 if (
msg.header.size ==
sizeof(
msg.mtu))
1787 *pnext = item->
next;
1798 HANDLE ovpn_pipe = NULL, svc_pipe = NULL;
1799 PTOKEN_USER svc_user = NULL, ovpn_user = NULL;
1800 HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL;
1801 HANDLE stdin_read = NULL, stdin_write = NULL;
1802 HANDLE stdout_write = NULL;
1803 DWORD pipe_mode, len, exit_code = 0;
1805 STARTUPINFOW startup_info;
1806 PROCESS_INFORMATION proc_info;
1807 LPVOID user_env = NULL;
1808 TCHAR ovpn_pipe_name[256];
1810 WCHAR *cmdline = NULL;
1811 size_t cmdline_size;
1813 WCHAR errmsg[512] = L
"";
1815 SECURITY_ATTRIBUTES inheritable = {
1816 .nLength =
sizeof(inheritable),
1817 .lpSecurityDescriptor = NULL,
1818 .bInheritHandle = TRUE
1822 EXPLICIT_ACCESS ea[2];
1823 SECURITY_DESCRIPTOR ovpn_sd;
1824 SECURITY_ATTRIBUTES ovpn_sa = {
1825 .nLength =
sizeof(ovpn_sa),
1826 .lpSecurityDescriptor = &ovpn_sd,
1827 .bInheritHandle = FALSE
1830 ZeroMemory(&ea,
sizeof(ea));
1831 ZeroMemory(&startup_info,
sizeof(startup_info));
1832 ZeroMemory(&undo_lists,
sizeof(undo_lists));
1833 ZeroMemory(&proc_info,
sizeof(proc_info));
1840 if (!InitializeSecurityDescriptor(&ovpn_sd, SECURITY_DESCRIPTOR_REVISION))
1847 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &svc_token))
1853 while (!GetTokenInformation(svc_token, TokenUser, svc_user, len, &len))
1855 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1861 svc_user = malloc(len);
1862 if (svc_user == NULL)
1868 if (!IsValidSid(svc_user->User.Sid))
1874 if (!ImpersonateNamedPipeClient(pipe))
1879 if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &imp_token))
1885 while (!GetTokenInformation(imp_token, TokenUser, ovpn_user, len, &len))
1887 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1893 ovpn_user = malloc(len);
1894 if (ovpn_user == NULL)
1900 if (!IsValidSid(ovpn_user->User.Sid))
1921 ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
1922 ea[0].grfAccessMode = SET_ACCESS;
1923 ea[0].grfInheritance = NO_INHERITANCE;
1924 ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
1925 ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
1926 ea[0].Trustee.ptstrName = (LPTSTR) svc_user->User.Sid;
1927 ea[1].grfAccessPermissions = READ_CONTROL | SYNCHRONIZE | PROCESS_VM_READ
1928 |SYNCHRONIZE | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION;
1929 ea[1].grfAccessMode = SET_ACCESS;
1930 ea[1].grfInheritance = NO_INHERITANCE;
1931 ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
1932 ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
1933 ea[1].Trustee.ptstrName = (LPTSTR) ovpn_user->User.Sid;
1936 if (!SetSecurityDescriptorOwner(&ovpn_sd, svc_user->User.Sid, FALSE))
1941 if (SetEntriesInAcl(2, ea, NULL, &ovpn_dacl) != ERROR_SUCCESS)
1946 if (!SetSecurityDescriptorDacl(&ovpn_sd, TRUE, ovpn_dacl, FALSE))
1953 if (!DuplicateTokenEx(imp_token, TOKEN_ALL_ACCESS, NULL, 0, TokenPrimary, &pri_token))
1960 stdout_write = CreateFile(_T(
"NUL"), GENERIC_WRITE, FILE_SHARE_WRITE,
1961 &inheritable, OPEN_EXISTING, 0, NULL);
1962 if (stdout_write == INVALID_HANDLE_VALUE)
1968 if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0)
1969 || !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0))
1975 swprintf(ovpn_pipe_name, _countof(ovpn_pipe_name),
1976 TEXT(
"\\\\.\\pipe\\") TEXT(PACKAGE) TEXT(
"%ls\\service_%lu"),
service_instance, GetCurrentThreadId());
1977 ovpn_pipe = CreateNamedPipe(ovpn_pipe_name,
1978 PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
1979 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 128, 128, 0, NULL);
1980 if (ovpn_pipe == INVALID_HANDLE_VALUE)
1986 svc_pipe = CreateFile(ovpn_pipe_name, GENERIC_READ | GENERIC_WRITE, 0,
1987 &inheritable, OPEN_EXISTING, 0, NULL);
1988 if (svc_pipe == INVALID_HANDLE_VALUE)
1994 pipe_mode = PIPE_READMODE_MESSAGE;
1995 if (!SetNamedPipeHandleState(svc_pipe, &pipe_mode, NULL, NULL))
2001 cmdline_size = wcslen(sud.
options) + 128;
2002 cmdline = malloc(cmdline_size *
sizeof(*cmdline));
2003 if (cmdline == NULL)
2011 swprintf(cmdline, cmdline_size, L
"openvpn %ls --msg-channel %" PRIuPTR,
2012 sud.
options, (uintptr_t)svc_pipe);
2014 if (!CreateEnvironmentBlock(&user_env, imp_token, FALSE))
2020 startup_info.cb =
sizeof(startup_info);
2021 startup_info.dwFlags = STARTF_USESTDHANDLES;
2022 startup_info.hStdInput = stdin_read;
2023 startup_info.hStdOutput = stdout_write;
2024 startup_info.hStdError = stdout_write;
2029 if (!CreateProcessAsUserW(pri_token, exe_path, cmdline, &ovpn_sa, NULL, TRUE,
2031 user_env, sud.
directory, &startup_info, &proc_info))
2037 if (!RevertToSelf())
2039 TerminateProcess(proc_info.hProcess, 1);
2050 DWORD input_size = WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, NULL, 0, NULL, NULL);
2052 if (input_size && (input = malloc(input_size)))
2055 WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, input, input_size, NULL, NULL);
2056 WriteFile(stdin_write, input, (DWORD)strlen(input), &written, NULL);
2071 MsgToEventLog(
MSG_FLAGS_ERROR, TEXT(
"OpenVPN process sent too large payload length to the pipe (%lu bytes), it will be terminated"), bytes);
2078 WaitForSingleObject(proc_info.hProcess,
IO_TIMEOUT);
2079 GetExitCodeProcess(proc_info.hProcess, &exit_code);
2080 if (exit_code == STILL_ACTIVE)
2082 TerminateProcess(proc_info.hProcess, 1);
2084 else if (exit_code != 0)
2087 swprintf(buf, _countof(buf),
2088 L
"OpenVPN exited with error: exit code = %lu", exit_code);
2094 FlushFileBuffers(pipe);
2095 DisconnectNamedPipe(pipe);
2100 DestroyEnvironmentBlock(user_env);
2121 SERVICE_STATUS *
status = ctx;
2124 case SERVICE_CONTROL_STOP:
2125 status->dwCurrentState = SERVICE_STOP_PENDING;
2133 case SERVICE_CONTROL_INTERROGATE:
2137 return ERROR_CALL_NOT_IMPLEMENTED;
2151 const TCHAR *sddlString = TEXT(
"D:(A;OICI;GA;;;S-1-5-18)(D;OICI;0x4;;;S-1-1-0)(A;OICI;GRGW;;;S-1-5-11)(D;;GA;;;S-1-5-7)");
2153 PSECURITY_DESCRIPTOR sd = NULL;
2154 if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddlString, SDDL_REVISION_1, &sd, NULL))
2157 return INVALID_HANDLE_VALUE;
2161 SECURITY_ATTRIBUTES sa = {0};
2162 sa.nLength =
sizeof(SECURITY_ATTRIBUTES);
2163 sa.lpSecurityDescriptor = sd;
2164 sa.bInheritHandle = FALSE;
2166 DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED;
2168 static BOOL first = TRUE;
2171 flags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
2175 TCHAR pipe_name[256];
2176 swprintf(pipe_name, _countof(pipe_name), TEXT(
"\\\\.\\pipe\\") TEXT(PACKAGE) TEXT(
"%ls\\service"),
service_instance);
2177 HANDLE pipe = CreateNamedPipe(pipe_name, flags,
2178 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
2179 PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, &sa);
2183 if (pipe == INVALID_HANDLE_VALUE)
2186 return INVALID_HANDLE_VALUE;
2197 static DWORD size = 10;
2198 static LPHANDLE handles = NULL;
2201 if (handles == NULL)
2203 handles = malloc(size *
sizeof(HANDLE));
2204 *handles_ptr = handles;
2205 if (handles == NULL)
2207 return ERROR_OUTOFMEMORY;
2211 handles[
pos++] = io_event;
2224 tmp = realloc(handles, size *
sizeof(HANDLE));
2229 return ERROR_OUTOFMEMORY;
2232 *handles_ptr = handles;
2234 handles[
pos++] = threads->
data;
2235 threads = threads->
next;
2259 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
2267 HANDLE pipe, io_event = NULL;
2268 OVERLAPPED overlapped;
2269 DWORD error = NO_ERROR;
2271 PHANDLE handles = NULL;
2280 status.dwCurrentState = SERVICE_START_PENDING;
2281 status.dwServiceSpecificExitCode = NO_ERROR;
2282 status.dwWin32ExitCode = NO_ERROR;
2283 status.dwWaitHint = 3000;
2288 if (error != ERROR_SUCCESS)
2294 exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
2309 if (error != NO_ERROR)
2315 if (pipe == INVALID_HANDLE_VALUE)
2320 status.dwCurrentState = SERVICE_RUNNING;
2326 if (ConnectNamedPipe(pipe, &overlapped) == FALSE
2327 && GetLastError() != ERROR_PIPE_CONNECTED
2328 && GetLastError() != ERROR_IO_PENDING)
2334 error = WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
2335 if (error == WAIT_OBJECT_0)
2339 HANDLE thread = CreateThread(NULL, 0,
RunOpenvpn, pipe, CREATE_SUSPENDED, NULL);
2353 TerminateThread(thread, 1);
2359 ResumeThread(thread);
2373 if (error == WAIT_FAILED)
2403 status.dwCurrentState = SERVICE_STOPPED;
2404 status.dwWin32ExitCode = error;
DWORD MsgToEventLog(DWORD flags, LPCTSTR format,...)
DWORD GetOpenvpnSettings(settings_t *s)
static void OvpnUnmapViewOfFile(struct tun_ring **ring)
static VOID ReturnLastError(HANDLE pipe, LPCWSTR func)
static DWORD ReadPipeAsync(HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
static VOID ReturnProcessId(HANDLE pipe, DWORD pid, DWORD count, LPHANDLE events)
static DWORD HandleWINSConfigMessage(const wins_cfg_message_t *msg, undo_lists_t *lists)
static BOOL CmpAddress(LPVOID item, LPVOID address)
static DWORD PeekNamedPipeAsync(HANDLE pipe, DWORD count, LPHANDLE events)
static BOOL ResetOverlapped(LPOVERLAPPED overlapped)
static DWORD ExecCommand(const WCHAR *argv0, const WCHAR *cmdline, DWORD timeout)
static DWORD HandleEnableDHCPMessage(const enable_dhcp_message_t *dhcp)
static DWORD AddWfpBlock(const wfp_block_message_t *msg, undo_lists_t *lists)
static BOOL CmpWString(LPVOID item, LPVOID str)
static HANDLE CreateClientPipeInstance(VOID)
static DWORD SetDNSDomain(const wchar_t *if_name, const char *domain, undo_lists_t *lists)
Set interface specific DNS domain suffix.
static BOOL GetStartupData(HANDLE pipe, STARTUP_DATA *sud)
static DWORD DeleteWfpBlock(const wfp_block_message_t *msg, undo_lists_t *lists)
static VOID Undo(undo_lists_t *lists)
#define ERROR_STARTUP_DATA
static DWORD WINAPI RunOpenvpn(LPVOID p)
static settings_t settings
static DWORD DeleteRoute(PMIB_IPFORWARD_ROW2 fwd_row)
static DWORD ConvertInterfaceNameToIndex(const wchar_t *ifname, NET_IFINDEX *index)
static SERVICE_STATUS status
static DWORD DuplicateAndMapRing(HANDLE ovpn_proc, HANDLE orig_handle, struct tun_ring **ring)
#define ERROR_MESSAGE_TYPE
static VOID HandleMessage(HANDLE pipe, HANDLE ovpn_proc, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists)
static SOCKADDR_INET sockaddr_inet(short family, inet_address_t *addr)
static LPVOID RemoveListItem(list_item_t **pfirst, match_fn_t match, LPVOID ctx)
static BOOL CmpHandle(LPVOID item, LPVOID hnd)
static DWORD HandleAddressMessage(address_message_t *msg, undo_lists_t *lists)
static DWORD DeleteDNS(short family, wchar_t *if_name)
static VOID ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events)
static DWORD AddListItem(list_item_t **pfirst, LPVOID data)
static void BlockDNSErrHandler(DWORD err, const char *msg)
static DWORD OvpnDuplicateHandle(HANDLE ovpn_proc, HANDLE orig_handle, HANDLE *new_handle)
static DWORD HandleRouteMessage(route_message_t *msg, undo_lists_t *lists)
static DWORD WINAPI RegisterDNS(LPVOID unused)
static HANDLE InitOverlapped(LPOVERLAPPED overlapped)
BOOL(* match_fn_t)(LPVOID item, LPVOID ctx)
static HANDLE CloseHandleEx(LPHANDLE handle)
static DWORD WINAPI ServiceCtrlInteractive(DWORD ctrl_code, DWORD event, LPVOID data, LPVOID ctx)
struct _list_item list_item_t
static DWORD AddDNS(short family, wchar_t *if_name, wchar_t *addr)
static DWORD DeleteAddress(PMIB_UNICASTIPADDRESS_ROW addr_row)
#define ERROR_OPENVPN_STARTUP
static DWORD HandleRegisterRingBuffers(const register_ring_buffers_message_t *rrb, HANDLE ovpn_proc, undo_lists_t *lists)
static VOID FreeWaitHandles(LPHANDLE h)
openvpn_service_t interactive_service
static DWORD AsyncPipeOp(async_op_t op, HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
VOID WINAPI ServiceStartInteractiveOwn(DWORD dwArgc, LPTSTR *lpszArgv)
VOID WINAPI ServiceStartInteractive(DWORD dwArgc, LPTSTR *lpszArgv)
static DWORD HandleFlushNeighborsMessage(flush_neighbors_message_t *msg)
static DWORD HandleMTUMessage(const set_mtu_message_t *mtu)
list_item_t * undo_lists_t[_undo_type_max]
static DWORD wmic_nicconfig_cmd(const wchar_t *action, const NET_IFINDEX if_index, const wchar_t *data)
Run command: wmic nicconfig (InterfaceIndex=$if_index) call $action ($data)
static DWORD HandleRegisterDNSMessage(void)
#define ERROR_MESSAGE_DATA
static VOID FreeStartupData(STARTUP_DATA *sud)
static DWORD HandleWfpBlockMessage(const wfp_block_message_t *msg, undo_lists_t *lists)
static HANDLE rdns_semaphore
static DWORD netsh_dns_cmd(const wchar_t *action, const wchar_t *proto, const wchar_t *if_name, const wchar_t *addr)
Run the command: netsh interface $proto $action dns $if_name $addr [validate=no].
static DWORD InterfaceLuid(const char *iface_name, PNET_LUID luid)
static BOOL ValidateOptions(HANDLE pipe, const WCHAR *workdir, const WCHAR *options, WCHAR *errmsg, DWORD capacity)
static DWORD UpdateWaitHandles(LPHANDLE *handles_ptr, LPDWORD count, HANDLE io_event, HANDLE exit_event, list_item_t *threads)
static BOOL CmpRoute(LPVOID item, LPVOID route)
static DWORD HandleDNSConfigMessage(const dns_cfg_message_t *msg, undo_lists_t *lists)
static void UnmapRingBuffer(ring_buffer_maps_t *ring_buffer_maps)
static BOOL CmpAny(LPVOID item, LPVOID any)
static DWORD netsh_wins_cmd(const wchar_t *action, const wchar_t *if_name, const wchar_t *addr)
Run the command: netsh interface ip $action wins $if_name [static] $addr.
static SERVICE_STATUS_HANDLE service
static DWORD WritePipeAsync(HANDLE pipe, LPVOID data, DWORD size, DWORD count, LPHANDLE events)
@ msg_register_ring_buffers
static bool register_ring_buffers(HANDLE device, struct tun_ring *send_ring, struct tun_ring *receive_ring, HANDLE send_tail_moved, HANDLE receive_tail_moved)
Registers ring buffers used to exchange data between userspace openvpn process and wintun kernel driv...
BOOL ReportStatusToSCMgr(SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status)
#define SERVICE_DEPENDENCIES
static wchar_t * utf8to16(const char *utf8)
Convert a zero terminated UTF-8 string to UTF-16.
Wrapper structure for dynamically allocated memory.
HANDLE receive_tail_moved
HANDLE receive_ring_handle
struct tun_ring * receive_ring
struct tun_ring * send_ring
TCHAR ovpn_admin_group[MAX_NAME]
Wintun ring buffer See https://github.com/WireGuard/wintun#ring-layout.
UCHAR data[WINTUN_RING_CAPACITY+WINTUN_RING_TRAILING_BYTES]
address_message_t address
flush_neighbors_message_t flush_neighbors
wfp_block_message_t wfp_block
enable_dhcp_message_t dhcp
register_ring_buffers_message_t rrb
BOOL CheckOption(const WCHAR *workdir, int argc, WCHAR *argv[], const settings_t *s)
BOOL IsAuthorizedUser(PSID sid, const HANDLE token, const WCHAR *ovpn_admin_group)
static BOOL IsOption(const WCHAR *o)
int get_interface_metric(const NET_IFINDEX index, const ADDRESS_FAMILY family, int *is_auto)
Return interface metric value for the specified interface index.
DWORD set_interface_metric(const NET_IFINDEX index, const ADDRESS_FAMILY family, const ULONG metric)
Sets interface metric value for specified interface index.
DWORD delete_wfp_block_filters(HANDLE engine_handle)
DWORD add_wfp_block_filters(HANDLE *engine_handle, int index, const WCHAR *exe_path, wfp_block_msg_handler_t msg_handler, BOOL dns_only)
#define WFP_BLOCK_IFACE_METRIC
char * get_win_sys_path(void)