38#include <versionhelpers.h>
44#define IO_TIMEOUT 2000
46#define ERROR_OPENVPN_STARTUP 0x20000000
47#define ERROR_STARTUP_DATA 0x20000001
48#define ERROR_MESSAGE_DATA 0x20000002
49#define ERROR_MESSAGE_TYPE 0x20000003
52static SERVICE_STATUS
status = { .dwServiceType = SERVICE_WIN32_SHARE_PROCESS };
56#define RDNS_TIMEOUT 600
58#define TUN_IOCTL_REGISTER_RINGS \
59 CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
62 _L(PACKAGE_NAME) L
" Interactive Service",
138 if (new_item == NULL)
140 return ERROR_OUTOFMEMORY;
143 new_item->
next = *pfirst;
158 for (pnext = pfirst; *pnext; pnext = &(*pnext)->
next)
161 if (!match(item->
data, ctx))
179 if (handle && *handle && *handle != INVALID_HANDLE_VALUE)
181 CloseHandle(*handle);
182 *handle = INVALID_HANDLE_VALUE;
184 return INVALID_HANDLE_VALUE;
190 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
191 overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
192 return overlapped->hEvent;
198 HANDLE io_event = overlapped->hEvent;
199 if (!ResetEvent(io_event))
203 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
204 overlapped->hEvent = io_event;
223 DWORD res, bytes = 0;
224 OVERLAPPED overlapped;
225 LPHANDLE handles = NULL;
233 handles = malloc((count + 1) *
sizeof(HANDLE));
241 success = WriteFile(pipe,
buffer, size, NULL, &overlapped);
245 success = ReadFile(pipe,
buffer, size, NULL, &overlapped);
247 if (!success && GetLastError() != ERROR_IO_PENDING && GetLastError() != ERROR_MORE_DATA)
252 handles[0] = io_event;
253 for (i = 0; i < count; i++)
255 handles[i + 1] = events[i];
258 res = WaitForMultipleObjects(count + 1, handles, FALSE, op ==
peek ? INFINITE :
IO_TIMEOUT);
259 if (res != WAIT_OBJECT_0)
267 PeekNamedPipe(pipe, NULL, 0, NULL, &bytes, NULL);
271 GetOverlappedResult(pipe, &overlapped, &bytes, TRUE);
307 const WCHAR
msg[] = L
"Process ID";
308 WCHAR buf[22 + _countof(
msg)];
314 swprintf(buf, _countof(buf), L
"0x%08x\n0x%08lx\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";
324 DWORD_PTR args[] = { (DWORD_PTR)error, (DWORD_PTR)func, (DWORD_PTR)
"" };
328 FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER
329 | FORMAT_MESSAGE_IGNORE_INSERTS,
330 0, error, 0, (LPWSTR)&args[2], 0, NULL);
333 result_len = FormatMessageW(
334 FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
335 L
"0x%1!08x!\n%2!s!\n%3!s!", 0, 0, (LPWSTR)&result, 0, (va_list *)args);
337 WritePipeAsync(pipe, result, (DWORD)(wcslen(result) * 2), count, events);
342 LocalFree((LPVOID)args[2]);
370 const WCHAR *
msg1 = L
"You have specified a config file location (%ls relative to %ls)"
371 L
" that requires admin approval. This error may be avoided"
372 L
" by adding your account to the \"%ls\" group";
374 const WCHAR *
msg2 = L
"You have specified an option (%ls) that may be used"
375 L
" only with admin approval. This error may be avoided"
376 L
" by adding your account to the \"%ls\" group";
382 swprintf(errmsg, capacity,
383 L
"Cannot validate options: CommandLineToArgvW failed with error = 0x%08lx",
400 WCHAR *argv_tmp[2] = { L
"--config",
argv[0] };
404 swprintf(errmsg, capacity,
msg1,
argv[0], workdir,
settings.ovpn_admin_group);
409 for (i = 0; i < argc; ++i)
418 if (wcscmp(L
"--config",
argv[i]) == 0 && argc - i > 1)
420 swprintf(errmsg, capacity,
msg1,
argv[i + 1], workdir,
settings.ovpn_admin_group);
456 size = bytes /
sizeof(*data);
457 if ((size == 0) || (size > 4096))
464 data = malloc(bytes);
480 if (
data[size - 1] != 0)
498 len = wcslen(sud->
options) + 1;
527 SOCKADDR_INET sa_inet;
528 ZeroMemory(&sa_inet,
sizeof(sa_inet));
529 sa_inet.si_family = family;
530 if (family == AF_INET)
532 sa_inet.Ipv4.sin_addr = addr->
ipv4;
534 else if (family == AF_INET6)
536 sa_inet.Ipv6.sin6_addr = addr->
ipv6;
544 NETIO_STATUS convert_status;
545 LPWSTR wide_name =
utf8to16(iface_name);
549 convert_status = ConvertInterfaceAliasToLuid(wide_name, luid);
554 convert_status = ERROR_OUTOFMEMORY;
556 return convert_status;
562 return memcmp(item,
address,
sizeof(MIB_UNICASTIPADDRESS_ROW)) == 0 ? TRUE : FALSE;
568 return DeleteUnicastIpAddressEntry(addr_row);
575 PMIB_UNICASTIPADDRESS_ROW addr_row;
578 addr_row = malloc(
sizeof(*addr_row));
579 if (addr_row == NULL)
581 return ERROR_OUTOFMEMORY;
584 InitializeUnicastIpAddressEntry(addr_row);
586 addr_row->OnLinkPrefixLength = (UINT8)
msg->prefix_len;
590 addr_row->InterfaceIndex =
msg->iface.index;
600 addr_row->InterfaceLuid = luid;
605 err = CreateUnicastIpAddressEntry(addr_row);
640 return memcmp(item,
route,
sizeof(MIB_IPFORWARD_ROW2)) == 0 ? TRUE : FALSE;
646 return DeleteIpForwardEntry2(fwd_row);
653 PMIB_IPFORWARD_ROW2 fwd_row;
656 fwd_row = malloc(
sizeof(*fwd_row));
659 return ERROR_OUTOFMEMORY;
662 ZeroMemory(fwd_row,
sizeof(*fwd_row));
663 fwd_row->ValidLifetime = 0xffffffff;
664 fwd_row->PreferredLifetime = 0xffffffff;
665 fwd_row->Protocol = MIB_IPPROTO_NETMGMT;
666 fwd_row->Metric =
msg->metric;
668 fwd_row->DestinationPrefix.PrefixLength = (UINT8)
msg->prefix_len;
673 fwd_row->InterfaceIndex =
msg->iface.index;
675 else if (strlen(
msg->iface.name))
683 fwd_row->InterfaceLuid = luid;
688 err = CreateIpForwardEntry2(fwd_row);
724 if (
msg->family == AF_INET)
726 return FlushIpNetTable(
msg->iface.index);
729 return FlushIpNetTable2(
msg->family,
msg->iface.index);
743 err_str = L
"Unknown Win32 Error";
745 if (FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
746 NULL, err, 0, buf, _countof(buf), NULL))
793 HANDLE engine = NULL;
806 err = ERROR_OUTOFMEMORY;
809 block_data->
engine = engine;
810 block_data->
index =
msg->iface.index;
874ExecCommand(
const WCHAR *argv0,
const WCHAR *cmdline, DWORD timeout)
878 PROCESS_INFORMATION pi;
879 DWORD proc_flags = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
880 WCHAR *cmdline_dup = NULL;
882 ZeroMemory(&si,
sizeof(si));
883 ZeroMemory(&pi,
sizeof(pi));
888 cmdline_dup = _wcsdup(cmdline);
890 && CreateProcessW(argv0, cmdline_dup, NULL, NULL, FALSE, proc_flags, NULL, NULL, &si, &pi))
892 WaitForSingleObject(pi.hProcess, timeout ? timeout : INFINITE);
893 if (!GetExitCodeProcess(pi.hProcess, &exit_code))
896 exit_code = GetLastError();
898 else if (exit_code == STILL_ACTIVE)
900 exit_code = WAIT_TIMEOUT;
903 TerminateProcess(pi.hProcess, exit_code);
904 MsgToEventLog(
M_ERR, L
"ExecCommand: \"%ls %ls\" killed after timeout", argv0, cmdline);
916 CloseHandle(pi.hProcess);
917 CloseHandle(pi.hThread);
921 exit_code = GetLastError();
939 WCHAR ipcfg[MAX_PATH];
947 { ipcfg, L
"ipconfig /flushdns", timeout },
948 { ipcfg, L
"ipconfig /registerdns", timeout },
953 swprintf(ipcfg, MAX_PATH, L
"%ls\\%ls",
get_win_sys_path(), L
"ipconfig.exe");
955 if (WaitForMultipleObjects(2, wait_handles, FALSE, timeout) == WAIT_OBJECT_0)
958 for (
size_t i = 0; i < _countof(cmds); ++i)
960 ExecCommand(cmds[i].argv0, cmds[i].cmdline, cmds[i].timeout);
972 err = ERROR_SEM_TIMEOUT;
981 HANDLE thread = NULL;
984 thread = CreateThread(NULL, 0,
RegisterDNS, NULL, 0, NULL);
997 err = GetLastError();
1016 int timeout = 30000;
1017 wchar_t argv0[MAX_PATH];
1018 wchar_t *cmdline = NULL;
1019 const wchar_t *addr_static = (wcscmp(action, L
"set") == 0) ? L
"static" : L
"";
1023 if (wcscmp(action, L
"delete") == 0)
1034 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
1039 const wchar_t *fmt = L
"netsh interface ip %ls wins %lu %ls %ls";
1042 size_t ncmdline = wcslen(fmt) + 11 + wcslen(action) + wcslen(addr)
1043 + wcslen(addr_static) + 32 + 1;
1044 cmdline = malloc(ncmdline *
sizeof(
wchar_t));
1047 err = ERROR_OUTOFMEMORY;
1051 swprintf(cmdline, ncmdline, fmt, action, if_index, addr_static, addr);
1069 typedef NTSTATUS(__stdcall * publish_fn_t)(DWORD StateNameLo, DWORD StateNameHi, DWORD TypeId,
1070 DWORD Buffer, DWORD Length, DWORD ExplicitScope);
1071 publish_fn_t RtlPublishWnfStateData;
1072 const DWORD WNF_GPOL_SYSTEM_CHANGES_HI = 0x0D891E2A;
1073 const DWORD WNF_GPOL_SYSTEM_CHANGES_LO = 0xA3BC0875;
1076 HMODULE ntdll = LoadLibraryA(
"ntdll.dll");
1082 RtlPublishWnfStateData = (publish_fn_t)GetProcAddress(ntdll,
"RtlPublishWnfStateData");
1083 if (RtlPublishWnfStateData == NULL)
1088 if (RtlPublishWnfStateData(WNF_GPOL_SYSTEM_CHANGES_LO, WNF_GPOL_SYSTEM_CHANGES_HI, 0, 0, 0, 0)
1109 typedef NTSTATUS (*publish_fn_t)(INT64 StateName, INT64 TypeId, INT64 Buffer,
1110 unsigned int Length, INT64 ExplicitScope);
1111 publish_fn_t RtlPublishWnfStateData;
1112 const INT64 WNF_GPOL_SYSTEM_CHANGES = 0x0D891E2AA3BC0875;
1115 HMODULE ntdll = LoadLibraryA(
"ntdll.dll");
1121 RtlPublishWnfStateData = (publish_fn_t)GetProcAddress(ntdll,
"RtlPublishWnfStateData");
1122 if (RtlPublishWnfStateData == NULL)
1127 if (RtlPublishWnfStateData(WNF_GPOL_SYSTEM_CHANGES, 0, 0, 0, 0) != ERROR_SUCCESS)
1148 const BOOL win_32bit = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL;
1163 SC_HANDLE scm = NULL;
1164 SC_HANDLE dnssvc = NULL;
1171 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1174 MsgToEventLog(
M_ERR, L
"%S: OpenSCManager call failed (%lu)", __func__, GetLastError());
1178 dnssvc = OpenServiceA(scm,
"Dnscache", SERVICE_PAUSE_CONTINUE);
1181 MsgToEventLog(
M_ERR, L
"%S: OpenService call failed (%lu)", __func__, GetLastError());
1185 SERVICE_STATUS control_status;
1186 if (ControlService(dnssvc, SERVICE_CONTROL_PARAMCHANGE, &control_status) == 0)
1188 MsgToEventLog(
M_ERR, L
"%S: ControlService call failed (%lu)", __func__, GetLastError());
1197 CloseServiceHandle(dnssvc);
1201 CloseServiceHandle(scm);
1221 PWSTR iid_str = NULL;
1226 PWSTR wide_name =
utf8to16(itf_name);
1231 err = ConvertInterfaceLuidToGuid(&luid, &guid);
1234 PWSTR wide_name =
utf8to16(itf_name);
1240 if (StringFromIID(&guid, &iid_str) != S_OK)
1242 PWSTR wide_name =
utf8to16(itf_name);
1245 err = ERROR_OUTOFMEMORY;
1248 if (wcslen(iid_str) + 1 > len)
1250 err = ERROR_INVALID_PARAMETER;
1254 wcsncpy(str, iid_str, len);
1259 CoTaskMemFree(iid_str);
1281 DWORD size =
sizeof(
data);
1282 LSTATUS err = RegGetValueA(
key, NULL,
"SearchList", RRF_RT_REG_SZ, NULL, (PBYTE)
data, &size);
1283 if (!err || err == ERROR_MORE_DATA)
1286 for (
size_t i = 0; i < strlen(
data); ++i)
1288 if (isalnum(
data[i]) ||
data[i] ==
'-' ||
data[i] ==
'.')
1322 err = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient",
1323 0, KEY_ALL_ACCESS,
key);
1336 RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"System\\CurrentControlSet\\Services\\TCPIP\\Parameters",
1337 0, KEY_ALL_ACCESS,
key);
1356 RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1357 "System\\CurrentControlSet\\Services\\TCPIP\\Parameters\\Interfaces",
1358 0, KEY_ALL_ACCESS, &itfs);
1361 err = RegOpenKeyExW(itfs, iid, 0, KEY_ALL_ACCESS,
key);
1371 *
key = INVALID_HANDLE_VALUE;
1387 err = RegGetValueA(
key, NULL,
"InitialSearchList", RRF_RT_REG_SZ, NULL, NULL, NULL);
1390 if (err == ERROR_FILE_NOT_FOUND)
1407 size_t length = (wcslen(
string) + 1) *
sizeof(
wchar_t);
1408 if (length > UINT_MAX)
1412 return (DWORD)length;
1428 if (!list || wcslen(list) == 0)
1441 LSTATUS err = RegSetValueExW(
key, L
"InitialSearchList", 0, REG_SZ, (PBYTE)list, size);
1444 MsgToEventLog(
M_ERR, L
"%S: failed to set InitialSearchList value (%lu)", __func__, err);
1468 size_t list_len = wcslen(list);
1469 size_t add_len = wcslen(add);
1475 size_t sep_len = (list_len > 0) ? 1 : 0;
1476 if (list_len + sep_len + add_len + 1 > list_cap)
1483 list[list_len++] = L
',';
1485 wmemcpy(list + list_len, add, add_len + 1);
1516 PCWSTR domain = remove;
1519 PCWSTR comma = wcschr(domain, L
',');
1520 size_t domain_len = comma ? (size_t)(comma - domain) : wcslen(domain);
1525 PWSTR match_end = NULL;
1526 for (PWSTR p = list; *p;)
1528 PWSTR tok_end = wcschr(p, L
',');
1529 size_t tok_len = tok_end ? (size_t)(tok_end - p) : wcslen(p);
1530 if (tok_len == domain_len && wcsncmp(p, domain, domain_len) == 0)
1533 match_end = tok_end;
1545 PWSTR cut_start, cut_end;
1549 cut_end = match_end ? match_end + 1 : match + domain_len;
1553 cut_start = match - 1;
1554 cut_end = match + domain_len;
1556 wmemmove(cut_start, cut_end, wcslen(cut_end) + 1);
1588 WCHAR list[2048] = { 0 };
1592 DWORD size =
sizeof(list);
1594 RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1615 LSTATUS err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1642 DWORD size =
sizeof(list);
1644 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, list, &size);
1647 if (err != ERROR_FILE_NOT_FOUND)
1656 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1663 RegDeleteValueA(
key,
"InitialSearchList");
1688 DWORD size =
sizeof(list);
1689 LSTATUS err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1702 if (list[0] != L
'\0')
1707 WCHAR initial[2048];
1708 size =
sizeof(initial);
1709 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, initial, &size);
1710 if (!err && wcscmp(list, initial) == 0)
1715 if (err && err != ERROR_FILE_NOT_FOUND)
1724 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1740 HKEY dns_searchlist_key;
1742 if (dns_searchlist_key != INVALID_HANDLE_VALUE)
1745 RegCloseKey(dns_searchlist_key);
1777 DWORD err = ERROR_OUTOFMEMORY;
1781 if (list_key == INVALID_HANDLE_VALUE)
1784 return ERROR_FILE_NOT_FOUND;
1798 if (domains && *domains)
1800 wchar_t *wide_domains =
utf8to16(domains);
1806 undo_data = malloc(
sizeof(*undo_data));
1810 wide_domains = NULL;
1814 undo_data->
domains = wide_domains;
1830 RegCloseKey(list_key);
1844 PCSTR itfs_key = family == AF_INET6
1845 ?
"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces"
1846 :
"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
1848 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, itfs_key, 0, KEY_ALL_ACCESS,
key);
1851 *
key = INVALID_HANDLE_VALUE;
1853 __func__, family, err);
1856 return err ? FALSE : TRUE;
1876 return ERROR_FILE_NOT_FOUND;
1879 HKEY itf = INVALID_HANDLE_VALUE;
1880 err = RegOpenKeyExW(itfs, itf_id, 0, KEY_ALL_ACCESS, &itf);
1884 __func__, itf_id, family, err);
1888 err = RegSetValueExA(itf,
"NameServer", 0, REG_SZ, (PBYTE)value, (DWORD)strlen(value) + 1);
1892 __func__, value, itf_id, family, err);
1896 if (itf != INVALID_HANDLE_VALUE)
1900 if (itfs != INVALID_HANDLE_VALUE)
1941 unsigned int addr_len =
msg->addr_len;
1944 const unsigned int max_addrs = _countof(
msg->addr);
1945 if (addr_len > max_addrs)
1947 addr_len = max_addrs;
1950 if (!
msg->iface.name[0])
1959 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
1960 msgptr->
domains[_countof(
msg->domains) - 1] =
'\0';
1986 if (
msg->domains[0])
2000 CHAR addrs[_countof(
msg->addr) * 64];
2002 for (
unsigned int i = 0; i < addr_len; ++i)
2006 addrs[offset++] =
',';
2008 if (
msg->family == AF_INET6)
2010 RtlIpv6AddressToStringA(&
msg->addr[i].ipv6, addrs + offset);
2014 RtlIpv4AddressToStringA(&
msg->addr[i].ipv4, addrs + offset);
2016 offset = strlen(addrs);
2025 wchar_t *tmp_iid = _wcsdup(iid);
2026 if (!tmp_iid ||
AddListItem(&(*lists)[undo_type], tmp_iid))
2030 return ERROR_OUTOFMEMORY;
2035 if (
msg->domains[0])
2056 DWORD size =
sizeof(
dhcp);
2059 err = RegGetValueA(
key, NULL,
"EnableDHCP", RRF_RT_REG_DWORD, NULL, (PBYTE)&
dhcp, &size);
2060 if (err != NO_ERROR)
2066 return dhcp ? TRUE : FALSE;
2080 const short families[] = { AF_INET, AF_INET6 };
2081 for (
size_t i = 0; i < _countof(families); i++)
2083 short family = families[i];
2090 if ((family == AF_INET6 && strchr(addresses[j],
':') == NULL)
2091 || (family == AF_INET && strchr(addresses[j],
':') != NULL))
2098 addr_list[offset++] =
',';
2100 strcpy(addr_list + offset, addresses[j]);
2101 offset += strlen(addresses[j]);
2133 addrs[*size - 1] =
'\0';
2137 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2138 if (err && err != ERROR_FILE_NOT_FOUND)
2148 RegGetValueA(itf_key, NULL,
"DhcpNameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2156 if (strchr(addrs,
'.'))
2163 return ERROR_FILE_NOT_FOUND;
2178 addrs[*size - 1] =
'\0';
2182 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2183 if (err && err != ERROR_FILE_NOT_FOUND)
2192 IN6_ADDR in_addrs[8];
2193 DWORD in_addrs_size =
sizeof(in_addrs);
2194 err = RegGetValueA(itf_key, NULL,
"Dhcpv6DNSServers", RRF_RT_REG_BINARY, NULL,
2195 (PBYTE)in_addrs, &in_addrs_size);
2204 size_t in_addrs_read = in_addrs_size /
sizeof(IN6_ADDR);
2205 for (
size_t i = 0; i < in_addrs_read; ++i)
2214 if (inet_ntop(AF_INET6, &in_addrs[i],
pos, s) != NULL)
2217 return ERROR_MORE_DATA;
2220 size_t addr_len = strlen(
pos);
2222 s -= (DWORD)addr_len;
2224 s = (DWORD)strlen(addrs) + 1;
2227 if (strchr(addrs,
':'))
2234 return ERROR_FILE_NOT_FOUND;
2249 PCWSTR entry = list;
2250 while (entry && *entry)
2252 PCWSTR comma = wcschr(entry, L
',');
2253 size_t entry_len = comma ? (size_t)(comma - entry) : wcslen(entry);
2254 if (entry_len == len && wcsncmp(entry, domain, len) == 0)
2292 const size_t glyph_size =
sizeof(*domains);
2293 const size_t max_len = (size_t)capacity / glyph_size;
2296 const size_t dot_len = 1;
2297 const size_t term_len = 2;
2299 LSTATUS ret = NO_ERROR;
2301 WCHAR *tmp = malloc(capacity);
2304 ret = ERROR_OUTOFMEMORY;
2308 PWCHAR tmp_pos = tmp;
2309 PCWCHAR domain = domains;
2311 while (domain && *domain)
2313 PWCHAR comma = wcschr(domain, L
',');
2314 size_t domain_len = comma ? (size_t)(comma - domain) : wcslen(domain);
2319 domain = comma ? comma + 1 : domain + domain_len;
2324 if (tmp_len + dot_len + domain_len + term_len > max_len)
2332 ret = ERROR_MORE_DATA;
2338 wcsncpy(tmp_pos, domain, domain_len);
2339 tmp_pos += domain_len;
2341 tmp_len += dot_len + domain_len + 1;
2343 domain = comma ? comma + 1 : domain + domain_len;
2348 ret = ERROR_FILE_NOT_FOUND;
2359 wmemcpy(domains, tmp, tmp_len);
2362 *size = (DWORD)(tmp_len * glyph_size);
2390 if (domains == NULL || size == NULL || *size == 0)
2392 return ERROR_INVALID_PARAMETER;
2395 LSTATUS err = ERROR_FILE_NOT_FOUND;
2396 const DWORD buf_size = *size;
2397 const DWORD glyph_size =
sizeof(*domains);
2398 PWSTR values[] = { L
"SearchList", L
"Domain", L
"DhcpDomainSearchList", L
"DhcpDomain", NULL };
2400 for (
int i = 0; values[i]; i++)
2403 err = RegGetValueW(itf, NULL, values[i], RRF_RT_REG_SZ, NULL, (PBYTE)domains, size);
2404 if (!err && *size > glyph_size && domains[(*size / glyph_size) - 1] ==
'\0' && wcschr(domains,
'.'))
2427 MIB_IF_ROW2 itf_row;
2430 if (IIDFromString(iid_str, &iid) != S_OK)
2438 if (ConvertInterfaceGuidToLuid(&iid, &itf_row.InterfaceLuid) != NO_ERROR)
2444 if (GetIfEntry2(&itf_row) != NO_ERROR)
2450 if (itf_row.MediaConnectState == MediaConnectStateConnected
2451 && itf_row.OperStatus == IfOperStatusUp)
2472 HKEY v4_itfs = INVALID_HANDLE_VALUE;
2473 HKEY v6_itfs = INVALID_HANDLE_VALUE;
2481 DWORD enum_index = 0;
2482 while (i < data_size)
2484 WCHAR itf_guid[MAX_PATH];
2485 DWORD itf_guid_len = _countof(itf_guid);
2487 RegEnumKeyExW(v4_itfs, enum_index++, itf_guid, &itf_guid_len, NULL, NULL, NULL, NULL);
2490 if (err != ERROR_NO_MORE_ITEMS)
2504 if (RegOpenKeyExW(v4_itfs, itf_guid, 0, KEY_READ, &v4_itf) != NO_ERROR)
2512 data[i].domains_size =
sizeof(
data[0].domains);
2513 memset(
data[i].domains, 0,
data[i].domains_size);
2517 if (err != ERROR_FILE_NOT_FOUND)
2526 DWORD v4_addrs_size =
sizeof(
data[0].addresses);
2528 if (err && err != ERROR_FILE_NOT_FOUND)
2531 __func__, itf_guid, err);
2536 PSTR v6_addrs =
data[i].addresses + v4_addrs_size;
2537 DWORD v6_addrs_size =
sizeof(
data[0].addresses) - v4_addrs_size;
2541 if (RegOpenKeyExW(v6_itfs, itf_guid, 0, KEY_READ, &v6_itf) != NO_ERROR)
2544 __func__, itf_guid);
2548 RegCloseKey(v6_itf);
2549 if (err && err != ERROR_FILE_NOT_FOUND)
2552 __func__, itf_guid, err);
2557 if (v4_addrs_size || v6_addrs_size)
2560 for (
size_t j = 0; j <
sizeof(
data[0].addresses) &&
data[i].addresses[j]; j++)
2562 if (
data[i].addresses[j] ==
',' ||
data[i].addresses[j] ==
' ')
2564 data[i].addresses[j] =
';';
2571 RegCloseKey(v4_itf);
2575 RegCloseKey(v6_itfs);
2576 RegCloseKey(v4_itfs);
2596 DWORD err = NO_ERROR;
2598 err = RegCreateKeyExW(nrpt_key, subkey, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &rule_key, NULL);
2605 err = RegSetValueExW(rule_key, L
"Name", 0, REG_MULTI_SZ, (PBYTE)domains, dom_size);
2612 err = RegSetValueExA(rule_key,
"GenericDNSServers", 0, REG_SZ, (PBYTE)
address,
2624 err = RegSetValueExA(rule_key,
"DNSSECValidationRequired", 0, REG_DWORD, (PBYTE)®_val,
2632 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECRequired", 0, REG_DWORD, (PBYTE)®_val,
2640 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECEncryption", 0, REG_DWORD, (PBYTE)®_val,
2649 reg_val = dnssec ? 0x0000000A : 0x00000008;
2650 err = RegSetValueExA(rule_key,
"ConfigOptions", 0, REG_DWORD, (
const PBYTE)®_val,
2659 err = RegSetValueExA(rule_key,
"Version", 0, REG_DWORD, (
const PBYTE)®_val,
sizeof(reg_val));
2668 RegDeleteKeyW(nrpt_key, subkey);
2670 RegCloseKey(rule_key);
2691 for (
size_t i = 0; i < _countof(
data); ++i)
2701 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRoutingX-%02x-%lu", ++n, ovpn_pid);
2724 const char *search_domains, BOOL dnssec, DWORD ovpn_pid)
2726 DWORD err = NO_ERROR;
2727 PWSTR wide_domains = L
".\0";
2733 size_t domains_len = strlen(domains);
2734 dom_size = (DWORD)domains_len + 2;
2739 return ERROR_OUTOFMEMORY;
2741 domains_len = wcslen(wide_domains);
2742 dom_size = (DWORD)(domains_len + 2) *
sizeof(*wide_domains);
2745 for (
size_t i = 0; i < domains_len; ++i)
2747 if (wide_domains[i] ==
',')
2749 wide_domains[i] = 0;
2755 PWSTR wide_search_domains;
2756 wide_search_domains =
utf8to16(search_domains);
2757 if (!wide_search_domains)
2759 return ERROR_OUTOFMEMORY;
2762 free(wide_search_domains);
2765 if (addresses[0][0])
2769 PSTR
pos = addr_list;
2776 strcpy(
pos, addresses[i]);
2780 WCHAR subkey[MAX_PATH];
2781 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRouting-%lu", ovpn_pid);
2782 err =
SetNrptRule(nrpt_key, subkey, addr_list, wide_domains, dom_size, dnssec);
2813 static PCSTR gpol_key =
"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient\\DnsPolicyConfig";
2814 static PCSTR sys_key =
2815 "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig";
2819 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, gpol_key, 0, KEY_ALL_ACCESS, &nrpt);
2820 if (err == ERROR_FILE_NOT_FOUND)
2823 err = RegCreateKeyExA(HKEY_LOCAL_MACHINE, sys_key, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &nrpt,
2827 nrpt = INVALID_HANDLE_VALUE;
2861 swprintf(pid_str, _countof(pid_str), L
"-%lu", pid);
2862 pidlen = wcslen(pid_str);
2866 DWORD enum_index = 0;
2869 WCHAR name[MAX_PATH];
2870 DWORD namelen = _countof(name);
2871 err = RegEnumKeyExW(
key, enum_index++, name, &namelen, NULL, NULL, NULL, NULL);
2874 if (err != ERROR_NO_MORE_ITEMS)
2882 if (wcsncmp(name, L
"OpenVPNDNSRouting", 17) != 0
2883 || (pid && wcsncmp(name + namelen - pidlen, pid_str, pidlen) != 0))
2888 if (RegDeleteKeyW(
key, name) == NO_ERROR)
2896 return deleted ? TRUE : FALSE;
2934 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
2939 msgptr->
addresses[i][_countof(
msg->addresses[0]) - 1] =
'\0';
2944 if (
msg->iface.name[0] == 0)
2953 if (
msg->addresses[0][0] == 0)
2958 const char *rdom =
msg->resolve_domains;
2959 size_t rdom_size =
sizeof(
msg->resolve_domains);
2960 size_t rdom_len = strlen(rdom);
2961 if (rdom_len && (rdom_len + 1 >= rdom_size || rdom[rdom_len + 1] != 0))
2967 BOOL gpol_nrpt = FALSE;
2968 BOOL gpol_list = FALSE;
2981 if (*undo_pid != ovpn_pid)
2984 L
"%S: PID stored for undo doesn't match: %lu vs %lu. "
2985 "This is likely an error. Cleaning up anyway.",
2986 __func__, *undo_pid, ovpn_pid);
3010 PDWORD pid = malloc(
sizeof(ovpn_pid));
3013 err = ERROR_OUTOFMEMORY;
3019 err = ERROR_OUTOFMEMORY;
3039 if (
msg->search_domains[0] || !
msg->resolve_domains[0])
3049 if (
msg->search_domains[0])
3063 DWORD err = NO_ERROR;
3065 unsigned int addr_len =
msg->addr_len;
3068 if (addr_len > _countof(
msg->addr))
3070 addr_len = _countof(
msg->addr);
3073 if (!
msg->iface.index)
3096 for (
unsigned int i = 0; i < addr_len; ++i)
3098 RtlIpv4AddressToStringW(&
msg->addr[i].ipv4, addr);
3109 PDWORD if_index = malloc(
sizeof(
msg->iface.index));
3112 *if_index =
msg->iface.index;
3119 err = ERROR_OUTOFMEMORY;
3133 DWORD timeout = 5000;
3134 wchar_t argv0[MAX_PATH];
3137 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
3142 const wchar_t *fmt = L
"netsh interface ipv4 set address name=\"%lu\" source=dhcp";
3147 size_t ncmdline = wcslen(fmt) + 10 + 1;
3148 wchar_t *cmdline = malloc(ncmdline *
sizeof(
wchar_t));
3151 err = ERROR_OUTOFMEMORY;
3155 swprintf(cmdline, ncmdline, fmt,
dhcp->iface.index);
3171 MIB_IPINTERFACE_ROW ipiface;
3172 InitializeIpInterfaceEntry(&ipiface);
3173 ipiface.Family = mtu->
family;
3175 err = GetIpInterfaceEntry(&ipiface);
3176 if (err != NO_ERROR)
3180 if (mtu->
family == AF_INET)
3182 ipiface.SitePrefixLength = 0;
3184 ipiface.NlMtu = mtu->
mtu;
3186 err = SetIpInterfaceEntry(&ipiface);
3202 switch (
msg->adapter_type)
3209 hwid = L
"root\\tap0901";
3213 return ERROR_INVALID_PARAMETER;
3216 WCHAR cmd[MAX_PATH];
3217 WCHAR args[MAX_PATH];
3219 if (swprintf_s(cmd, _countof(cmd), L
"%s\\tapctl.exe",
settings.bin_dir) < 0)
3221 return ERROR_BUFFER_OVERFLOW;
3224 if (swprintf_s(args, _countof(args), L
"tapctl create --hwid %s", hwid) < 0)
3226 return ERROR_BUFFER_OVERFLOW;
3233HandleMessage(HANDLE pipe, PPROCESS_INFORMATION proc_info, DWORD bytes, DWORD count,
3250 switch (
msg.header.type)
3254 if (
msg.header.size ==
sizeof(
msg.address))
3262 if (
msg.header.size ==
sizeof(
msg.route))
3269 if (
msg.header.size ==
sizeof(
msg.flush_neighbors))
3277 if (
msg.header.size ==
sizeof(
msg.wfp_block))
3295 DWORD ovpn_pid = proc_info->dwProcessId;
3306 if (
msg.header.size ==
sizeof(
msg.dhcp))
3313 if (
msg.header.size ==
sizeof(
msg.mtu))
3320 if (
msg.header.size ==
sizeof(
msg.create_adapter))
3399 *pnext = item->
next;
3410 HANDLE ovpn_pipe = NULL, svc_pipe = NULL;
3411 PTOKEN_USER svc_user = NULL, ovpn_user = NULL;
3412 HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL;
3413 HANDLE stdin_read = NULL, stdin_write = NULL;
3414 HANDLE stdout_write = NULL;
3415 DWORD pipe_mode, len, exit_code = 0;
3417 STARTUPINFOW startup_info;
3418 PROCESS_INFORMATION proc_info;
3419 LPVOID user_env = NULL;
3420 WCHAR ovpn_pipe_name[256];
3423 WCHAR *cmdline = NULL;
3424 size_t cmdline_size;
3426 WCHAR errmsg[512] = L
"";
3427 BOOL flush_pipe = TRUE;
3429 SECURITY_ATTRIBUTES inheritable = { .nLength =
sizeof(inheritable),
3430 .lpSecurityDescriptor = NULL,
3431 .bInheritHandle = TRUE };
3434 EXPLICIT_ACCESS ea[2];
3435 SECURITY_DESCRIPTOR ovpn_sd;
3436 SECURITY_ATTRIBUTES ovpn_sa = { .nLength =
sizeof(ovpn_sa),
3437 .lpSecurityDescriptor = &ovpn_sd,
3438 .bInheritHandle = FALSE };
3440 ZeroMemory(&ea,
sizeof(ea));
3441 ZeroMemory(&startup_info,
sizeof(startup_info));
3442 ZeroMemory(&undo_lists,
sizeof(undo_lists));
3443 ZeroMemory(&proc_info,
sizeof(proc_info));
3451 if (!InitializeSecurityDescriptor(&ovpn_sd, SECURITY_DESCRIPTOR_REVISION))
3458 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &svc_token))
3464 while (!GetTokenInformation(svc_token, TokenUser, svc_user, len, &len))
3466 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3472 svc_user = malloc(len);
3473 if (svc_user == NULL)
3479 if (!IsValidSid(svc_user->User.Sid))
3485 if (!ImpersonateNamedPipeClient(pipe))
3490 if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &imp_token))
3496 while (!GetTokenInformation(imp_token, TokenUser, ovpn_user, len, &len))
3498 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3504 ovpn_user = malloc(len);
3505 if (ovpn_user == NULL)
3511 if (!IsValidSid(ovpn_user->User.Sid))
3533 ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
3534 ea[0].grfAccessMode = SET_ACCESS;
3535 ea[0].grfInheritance = NO_INHERITANCE;
3536 ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3537 ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3538 ea[0].Trustee.ptstrName = (LPWSTR)svc_user->User.Sid;
3539 ea[1].grfAccessPermissions = READ_CONTROL | PROCESS_VM_READ | SYNCHRONIZE
3540 | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION;
3541 ea[1].grfAccessMode = SET_ACCESS;
3542 ea[1].grfInheritance = NO_INHERITANCE;
3543 ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3544 ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3545 ea[1].Trustee.ptstrName = (LPWSTR)ovpn_user->User.Sid;
3548 if (!SetSecurityDescriptorOwner(&ovpn_sd, svc_user->User.Sid, FALSE))
3553 if (SetEntriesInAcl(2, ea, NULL, &ovpn_dacl) != ERROR_SUCCESS)
3558 if (!SetSecurityDescriptorDacl(&ovpn_sd, TRUE, ovpn_dacl, FALSE))
3565 if (!DuplicateTokenEx(imp_token, TOKEN_ALL_ACCESS, NULL, 0, TokenPrimary, &pri_token))
3572 stdout_write = CreateFile(
_L(
"NUL"), GENERIC_WRITE, FILE_SHARE_WRITE, &inheritable,
3573 OPEN_EXISTING, 0, NULL);
3574 if (stdout_write == INVALID_HANDLE_VALUE)
3580 if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0)
3581 || !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0))
3588 RPC_STATUS rpc_stat = UuidCreate(&pipe_uuid);
3589 if (rpc_stat != RPC_S_OK)
3595 RPC_WSTR pipe_uuid_str = NULL;
3596 rpc_stat = UuidToStringW(&pipe_uuid, &pipe_uuid_str);
3597 if (rpc_stat != RPC_S_OK)
3602 swprintf(ovpn_pipe_name, _countof(ovpn_pipe_name),
3605 GetCurrentThreadId(), pipe_uuid_str);
3606 RpcStringFreeW(&pipe_uuid_str);
3612 SECURITY_ATTRIBUTES sa;
3613 PSECURITY_DESCRIPTOR pSD = NULL;
3614 LPCWSTR szSDDL = L
"D:(A;;GA;;;SY)(A;;GA;;;OW)";
3615 if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(
3616 szSDDL, SDDL_REVISION_1, &pSD, NULL))
3621 sa.nLength =
sizeof(sa);
3622 sa.lpSecurityDescriptor = pSD;
3623 sa.bInheritHandle = FALSE;
3625 ovpn_pipe = CreateNamedPipe(
3626 ovpn_pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
3627 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, 1, 128, 128, 0, &sa);
3628 if (ovpn_pipe == INVALID_HANDLE_VALUE)
3634 svc_pipe = CreateFile(ovpn_pipe_name, GENERIC_READ | GENERIC_WRITE, 0, &inheritable,
3635 OPEN_EXISTING, 0, NULL);
3636 if (svc_pipe == INVALID_HANDLE_VALUE)
3642 pipe_mode = PIPE_READMODE_MESSAGE;
3643 if (!SetNamedPipeHandleState(svc_pipe, &pipe_mode, NULL, NULL))
3649 cmdline_size = wcslen(sud.
options) + 128;
3650 cmdline = malloc(cmdline_size *
sizeof(*cmdline));
3651 if (cmdline == NULL)
3659 swprintf(cmdline, cmdline_size, L
"openvpn %ls --msg-channel %" PRIuPTR, sud.
options,
3660 (uintptr_t)svc_pipe);
3662 if (!CreateEnvironmentBlock(&user_env, imp_token, FALSE))
3668 startup_info.cb =
sizeof(startup_info);
3669 startup_info.dwFlags = STARTF_USESTDHANDLES;
3670 startup_info.hStdInput = stdin_read;
3671 startup_info.hStdOutput = stdout_write;
3672 startup_info.hStdError = stdout_write;
3677 if (!CreateProcessAsUserW(pri_token, exe_path, cmdline, &ovpn_sa, NULL, TRUE,
3678 settings.priority | CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT,
3679 user_env, sud.
directory, &startup_info, &proc_info))
3685 if (!RevertToSelf())
3687 TerminateProcess(proc_info.hProcess, 1);
3698 DWORD input_size = WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, NULL, 0, NULL, NULL);
3700 if (input_size && (input = malloc(input_size)))
3703 WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, input, input_size, NULL, NULL);
3704 WriteFile(stdin_write, input, (DWORD)strlen(input), &written, NULL);
3721 L
"OpenVPN process sent too large payload length to the pipe (%lu bytes), it will be terminated",
3729 WaitForSingleObject(proc_info.hProcess,
IO_TIMEOUT);
3730 GetExitCodeProcess(proc_info.hProcess, &exit_code);
3731 if (exit_code == STILL_ACTIVE)
3733 TerminateProcess(proc_info.hProcess, 1);
3735 else if (exit_code != 0)
3738 swprintf(buf, _countof(buf), L
"OpenVPN exited with error: exit code = %lu", exit_code);
3746 FlushFileBuffers(pipe);
3748 DisconnectNamedPipe(pipe);
3753 DestroyEnvironmentBlock(user_env);
3774 SERVICE_STATUS *svc_status = ctx;
3777 case SERVICE_CONTROL_STOP:
3778 svc_status->dwCurrentState = SERVICE_STOP_PENDING;
3786 case SERVICE_CONTROL_INTERROGATE:
3790 return ERROR_CALL_NOT_IMPLEMENTED;
3804 const WCHAR *sddlString =
3805 L
"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)";
3807 PSECURITY_DESCRIPTOR sd = NULL;
3808 if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddlString, SDDL_REVISION_1, &sd,
3812 return INVALID_HANDLE_VALUE;
3816 SECURITY_ATTRIBUTES sa = { 0 };
3817 sa.nLength =
sizeof(SECURITY_ATTRIBUTES);
3818 sa.lpSecurityDescriptor = sd;
3819 sa.bInheritHandle = FALSE;
3821 DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED;
3823 static BOOL first = TRUE;
3826 flags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
3830 WCHAR pipe_name[256];
3832 swprintf(pipe_name, _countof(pipe_name), L
"\\\\.\\pipe\\" _L(PACKAGE) L
"%ls\\service",
3834 HANDLE pipe = CreateNamedPipe(
3835 pipe_name, flags, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
3836 PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, &sa);
3840 if (pipe == INVALID_HANDLE_VALUE)
3843 return INVALID_HANDLE_VALUE;
3854 static DWORD size = 10;
3855 static LPHANDLE handles = NULL;
3858 if (handles == NULL)
3860 handles = malloc(size *
sizeof(HANDLE));
3861 *handles_ptr = handles;
3862 if (handles == NULL)
3864 return ERROR_OUTOFMEMORY;
3868 handles[
pos++] = io_event;
3881 tmp = realloc(handles, size *
sizeof(HANDLE));
3886 return ERROR_OUTOFMEMORY;
3889 *handles_ptr = handles;
3891 handles[
pos++] = threads->
data;
3892 threads = threads->
next;
3916 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
3928 BOOL changed = FALSE;
3938 if (
key != INVALID_HANDLE_VALUE)
3956 HANDLE pipe, io_event = NULL;
3957 OVERLAPPED overlapped;
3958 DWORD error = NO_ERROR;
3960 PHANDLE handles = NULL;
3970 status.dwCurrentState = SERVICE_START_PENDING;
3971 status.dwServiceSpecificExitCode = NO_ERROR;
3972 status.dwWin32ExitCode = NO_ERROR;
3973 status.dwWaitHint = 3000;
3981 if (error != ERROR_SUCCESS)
3987 exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
4002 if (error != NO_ERROR)
4008 if (pipe == INVALID_HANDLE_VALUE)
4013 status.dwCurrentState = SERVICE_RUNNING;
4019 if (!ConnectNamedPipe(pipe, &overlapped))
4021 DWORD connect_error = GetLastError();
4022 if (connect_error == ERROR_NO_DATA)
4029 DisconnectNamedPipe(pipe);
4033 else if (connect_error == ERROR_PIPE_CONNECTED)
4036 SetEvent(overlapped.hEvent);
4038 else if (connect_error != ERROR_IO_PENDING)
4045 error = WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
4046 if (error == WAIT_OBJECT_0)
4052 if (handle_count + 1 > MAXIMUM_WAIT_OBJECTS)
4061 HANDLE thread = CreateThread(NULL, 0,
RunOpenvpn, pipe, CREATE_SUSPENDED, NULL);
4072 ReturnError(pipe, error, L
"Insufficient resources to service new clients", 1,
4077 TerminateThread(thread, 1);
4083 ResumeThread(thread);
4097 if (error == WAIT_FAILED)
4127 status.dwCurrentState = SERVICE_STOPPED;
4128 status.dwWin32ExitCode = error;
wchar_t * utf8to16_size(const char *utf8, int size)
Convert a UTF-8 string to UTF-16.
DWORD MsgToEventLog(DWORD flags, LPCWSTR format,...)
DWORD GetOpenvpnSettings(settings_t *s)
static LSTATUS GetItfDnsServersV4(HKEY itf_key, PSTR addrs, PDWORD size)
Get DNS server IPv4 addresses of an interface.
static LSTATUS SetNameServerAddresses(PWSTR itf_id, const nrpt_address_t *addresses)
Set name servers from a NRPT address list.
static VOID ReturnLastError(HANDLE pipe, LPCWSTR func)
static BOOL GetInterfacesKey(short family, PHKEY key)
Return the interfaces registry key for the specified address family.
static DWORD ReadPipeAsync(HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
static void UndoNrptRules(DWORD ovpn_pid)
Delete a process' NRPT rules and apply the reduced set of rules.
static BOOL ApplyGpolSettings(void)
Signal the DNS resolver (and others potentially) to reload the group policy (DNS) settings.
static VOID ReturnProcessId(HANDLE pipe, DWORD pid, DWORD count, LPHANDLE events)
static BOOL GetDnsSearchListKey(PCSTR itf_name, PBOOL gpol, PHKEY key)
Find the registry key for storing the DNS domains for the VPN interface.
static DWORD HandleWINSConfigMessage(const wins_cfg_message_t *msg, undo_lists_t *lists)
static BOOL CmpAddress(LPVOID item, LPVOID address)
static LSTATUS GetItfDnsDomains(HKEY itf, PCWSTR search_domains, PWSTR domains, PDWORD size)
Return interface specific domain suffix(es).
static DWORD PeekNamedPipeAsyncTimed(HANDLE pipe, DWORD count, LPHANDLE events)
static DWORD PeekNamedPipeAsync(HANDLE pipe, DWORD count, LPHANDLE events)
static BOOL ResetOverlapped(LPOVERLAPPED overlapped)
static DWORD SetNameServers(PCWSTR itf_id, short family, PCSTR addrs)
Set the DNS name servers in a registry interface configuration.
static void SetNrptExcludeRules(HKEY nrpt_key, DWORD ovpn_pid, PCWSTR search_domains)
Set NRPT exclude rules to accompany a catch all rule.
static DWORD ExecCommand(const WCHAR *argv0, const WCHAR *cmdline, DWORD timeout)
static DWORD HandleEnableDHCPMessage(const enable_dhcp_message_t *dhcp)
static BOOL ResetDnsSearchDomains(HKEY key)
Reset the DNS search list to its original value.
static DWORD AddWfpBlock(const wfp_block_message_t *msg, undo_lists_t *lists)
static HANDLE CreateClientPipeInstance(VOID)
static DWORD DeleteWfpBlock(undo_lists_t *lists)
static void GetNrptExcludeData(PCWSTR search_domains, nrpt_exclude_data_t *data, size_t data_size)
Collect interface DNS settings to be used in excluding NRPT rules.
static DWORD SetNameServersValue(PCWSTR itf_id, short family, PCSTR value)
Set the DNS name servers in a registry interface configuration.
static BOOL GetStartupData(HANDLE pipe, STARTUP_DATA *sud)
static BOOL DeleteNrptRules(DWORD pid, PBOOL gpol)
Delete OpenVPN NRPT rules from the registry.
static VOID Undo(undo_lists_t *lists)
static BOOL ApplyDnsSettings(BOOL apply_gpol)
Signal the DNS resolver to reload its settings.
#define ERROR_STARTUP_DATA
static DWORD WINAPI RunOpenvpn(LPVOID p)
static settings_t settings
VOID WINAPI ServiceStartInteractive(DWORD dwArgc, LPWSTR *lpszArgv)
static DWORD DeleteRoute(PMIB_IPFORWARD_ROW2 fwd_row)
static SERVICE_STATUS status
static DWORD HandleDNSConfigNrptMessage(const nrpt_dns_cfg_message_t *msg, DWORD ovpn_pid, undo_lists_t *lists)
Add Name Resolution Policy Table (NRPT) rules as documented in https://msdn.microsoft....
static DWORD SetDnsSearchDomains(PCSTR itf_name, PCSTR domains, PBOOL gpol, undo_lists_t *lists)
Add or remove DNS search domains.
static void CleanupRegistry(void)
Clean up remains of previous sessions in registry.
static DWORD netsh_wins_cmd(const wchar_t *action, DWORD if_index, const wchar_t *addr)
Run the command: netsh interface ip $action wins $if_index [static] $addr.
#define ERROR_MESSAGE_TYPE
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 BOOL ApplyGpolSettings64(void)
Signal the DNS resolver (and others potentially) to reload the group policy (DNS) settings on 64 bit ...
static DWORD HandleAddressMessage(address_message_t *msg, undo_lists_t *lists)
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 ResetNameServers(PCWSTR itf_id, short family)
Delete all DNS name servers from a registry interface configuration.
static LSTATUS OpenNrptBaseKey(PHKEY key, PBOOL gpol)
Return the registry key where NRPT rules are stored.
static BOOL HasValidSearchList(HKEY key)
Check for a valid search list in a certain key of the registry.
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)
static BOOL StoreInitialDnsSearchList(HKEY key, PCWSTR list)
Prepare DNS domain "SearchList" registry value, so additional VPN domains can be added and its origin...
struct _list_item list_item_t
static DWORD RegWStringSize(PCWSTR string)
Return correct size for registry value to set for string.
static DWORD DeleteAddress(PMIB_UNICASTIPADDRESS_ROW addr_row)
static BOOL IsInterfaceConnected(PWSTR iid_str)
Check if an interface is connected and up.
#define ERROR_OPENVPN_STARTUP
static DWORD SetNrptRules(HKEY nrpt_key, const nrpt_address_t *addresses, const char *domains, const char *search_domains, BOOL dnssec, DWORD ovpn_pid)
Set NRPT rules for a openvpn process.
static LSTATUS GetItfDnsServersV6(HKEY itf_key, PSTR addrs, PDWORD size)
Get DNS server IPv6 addresses of an interface.
static BOOL AppendSearchList(PWSTR list, size_t list_cap, PCWSTR add)
Append a comma-separated list of domains to another comma-separated list, in place.
static DWORD SetNrptRule(HKEY nrpt_key, PCWSTR subkey, PCSTR address, PCWSTR domains, DWORD dom_size, BOOL dnssec)
Set a NRPT rule (subkey) and its values in the registry.
static BOOL AddDnsSearchDomains(HKEY key, BOOL have_list, PCWSTR domains)
Append domain suffixes to an existing search list.
static VOID FreeWaitHandles(LPHANDLE h)
openvpn_service_t interactive_service
VOID WINAPI ServiceStartInteractiveOwn(DWORD dwArgc, LPWSTR *lpszArgv)
static size_t RemoveSearchListTokens(PWSTR list, PCWSTR remove)
Remove tokens from a comma-separated search list with multiset semantics: for each comma-separated to...
static DWORD AsyncPipeOp(async_op_t op, HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
static BOOL ListContainsDomain(PCWSTR list, PCWSTR domain, size_t len)
Check if a domain is contained in a comma separated list of domains.
static BOOL IsDhcpEnabled(HKEY key)
Checks if DHCP is enabled for an interface.
static DWORD HandleFlushNeighborsMessage(flush_neighbors_message_t *msg)
static BOOL ApplyGpolSettings32(void)
Signal the DNS resolver (and others potentially) to reload the group policy (DNS) settings on 32 bit ...
static DWORD HandleMTUMessage(const set_mtu_message_t *mtu)
list_item_t * undo_lists_t[_undo_type_max]
static VOID HandleMessage(HANDLE pipe, PPROCESS_INFORMATION proc_info, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists)
static DWORD HandleRegisterDNSMessage(void)
static void RemoveDnsSearchDomains(HKEY key, PCWSTR domains)
Remove domain suffixes from an existing search list.
static BOOL InitialSearchListExists(HKEY key)
Check if a initial list had already been created.
#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 UpdateWaitHandles(LPHANDLE *handles_ptr, LPDWORD count, HANDLE io_event, const list_item_t *threads)
static DWORD InterfaceLuid(const char *iface_name, PNET_LUID luid)
static LSTATUS ConvertItfDnsDomains(PCWSTR search_domains, PWSTR domains, PDWORD size, const DWORD capacity)
Convert interface specific domain suffix(es) from comma-separated string to MULTI_SZ string.
static BOOL ValidateOptions(HANDLE pipe, const WCHAR *workdir, const WCHAR *options, WCHAR *errmsg, DWORD capacity)
static BOOL CmpRoute(LPVOID item, LPVOID route)
static DWORD HandleDNSConfigMessage(const dns_cfg_message_t *msg, undo_lists_t *lists)
static BOOL CmpAny(LPVOID item, LPVOID any)
static DWORD HandleCreateAdapterMessage(const create_adapter_message_t *msg)
Creates a VPN adapter of the specified type by invoking tapctl.exe.
static DWORD InterfaceIdString(PCSTR itf_name, PWSTR str, size_t len)
Get the string interface UUID (with braces) for an interface alias name.
static SERVICE_STATUS_HANDLE service
static DWORD WritePipeAsync(HANDLE pipe, LPVOID data, DWORD size, DWORD count, LPHANDLE events)
static void UndoDnsSearchDomains(dns_domains_undo_data_t *undo_data)
Removes DNS domains from a search list they were previously added to.
#define TUN_ADAPTER_INDEX_INVALID
char nrpt_address_t[NRPT_ADDR_SIZE]
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.
Container for unidirectional cipher and HMAC key material.
char resolve_domains[512]
nrpt_address_t addresses[NRPT_ADDR_NUM]
CHAR addresses[NRPT_ADDR_NUM *NRPT_ADDR_SIZE]
static int cleanup(void **state)
address_message_t address
flush_neighbors_message_t flush_neighbors
wfp_block_message_t wfp_block
enable_dhcp_message_t dhcp
nrpt_dns_cfg_message_t nrpt_dns
create_adapter_message_t create_adapter
BOOL IsAuthorizedUser(PSID sid, const HANDLE token, const WCHAR *ovpn_admin_group, const WCHAR *ovpn_service_user)
BOOL CheckOption(const WCHAR *workdir, int argc, WCHAR *argv[], const settings_t *s)
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)