37#include <versionhelpers.h>
43#define IO_TIMEOUT 2000
45#define ERROR_OPENVPN_STARTUP 0x20000000
46#define ERROR_STARTUP_DATA 0x20000001
47#define ERROR_MESSAGE_DATA 0x20000002
48#define ERROR_MESSAGE_TYPE 0x20000003
51static SERVICE_STATUS
status = { .dwServiceType = SERVICE_WIN32_SHARE_PROCESS };
55#define RDNS_TIMEOUT 600
57#define TUN_IOCTL_REGISTER_RINGS \
58 CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
61 _L(PACKAGE_NAME) L
" Interactive Service",
137 if (new_item == NULL)
139 return ERROR_OUTOFMEMORY;
142 new_item->
next = *pfirst;
157 for (pnext = pfirst; *pnext; pnext = &(*pnext)->
next)
160 if (!match(item->
data, ctx))
178 if (handle && *handle && *handle != INVALID_HANDLE_VALUE)
180 CloseHandle(*handle);
181 *handle = INVALID_HANDLE_VALUE;
183 return INVALID_HANDLE_VALUE;
189 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
190 overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
191 return overlapped->hEvent;
197 HANDLE io_event = overlapped->hEvent;
198 if (!ResetEvent(io_event))
202 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
203 overlapped->hEvent = io_event;
222 DWORD res, bytes = 0;
223 OVERLAPPED overlapped;
224 LPHANDLE handles = NULL;
232 handles = malloc((count + 1) *
sizeof(HANDLE));
240 success = WriteFile(pipe,
buffer, size, NULL, &overlapped);
244 success = ReadFile(pipe,
buffer, size, NULL, &overlapped);
246 if (!success && GetLastError() != ERROR_IO_PENDING && GetLastError() != ERROR_MORE_DATA)
251 handles[0] = io_event;
252 for (i = 0; i < count; i++)
254 handles[i + 1] = events[i];
257 res = WaitForMultipleObjects(count + 1, handles, FALSE, op ==
peek ? INFINITE :
IO_TIMEOUT);
258 if (res != WAIT_OBJECT_0)
266 PeekNamedPipe(pipe, NULL, 0, NULL, &bytes, NULL);
270 GetOverlappedResult(pipe, &overlapped, &bytes, TRUE);
306 const WCHAR
msg[] = L
"Process ID";
307 WCHAR buf[22 + _countof(
msg)];
313 swprintf(buf, _countof(buf), L
"0x%08x\n0x%08x\n%ls", 0, pid,
msg);
315 WritePipeAsync(pipe, buf, (DWORD)(wcslen(buf) * 2), count, events);
319ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events)
322 LPWSTR result = L
"0xffffffff\nFormatMessage failed\nCould not return result";
323 DWORD_PTR args[] = { (DWORD_PTR)error, (DWORD_PTR)func, (DWORD_PTR)
"" };
327 FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER
328 | FORMAT_MESSAGE_IGNORE_INSERTS,
329 0, error, 0, (LPWSTR)&args[2], 0, NULL);
332 result_len = FormatMessageW(
333 FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
334 L
"0x%1!08x!\n%2!s!\n%3!s!", 0, 0, (LPWSTR)&result, 0, (va_list *)args);
336 WritePipeAsync(pipe, result, (DWORD)(wcslen(result) * 2), count, events);
341 LocalFree((LPVOID)args[2]);
369 const WCHAR *
msg1 = L
"You have specified a config file location (%ls relative to %ls)"
370 L
" that requires admin approval. This error may be avoided"
371 L
" by adding your account to the \"%ls\" group";
373 const WCHAR *
msg2 = L
"You have specified an option (%ls) that may be used"
374 L
" only with admin approval. This error may be avoided"
375 L
" by adding your account to the \"%ls\" group";
381 swprintf(errmsg, capacity,
382 L
"Cannot validate options: CommandLineToArgvW failed with error = 0x%08x",
399 WCHAR *argv_tmp[2] = { L
"--config",
argv[0] };
408 for (i = 0; i < argc; ++i)
417 if (wcscmp(L
"--config",
argv[i]) == 0 && argc - i > 1)
455 size = bytes /
sizeof(*data);
456 if ((size == 0) || (size > 4096))
463 data = malloc(bytes);
479 if (
data[size - 1] != 0)
497 len = wcslen(sud->
options) + 1;
526 SOCKADDR_INET sa_inet;
527 ZeroMemory(&sa_inet,
sizeof(sa_inet));
528 sa_inet.si_family = family;
529 if (family == AF_INET)
531 sa_inet.Ipv4.sin_addr = addr->
ipv4;
533 else if (family == AF_INET6)
535 sa_inet.Ipv6.sin6_addr = addr->
ipv6;
544 LPWSTR wide_name =
utf8to16(iface_name);
548 status = ConvertInterfaceAliasToLuid(wide_name, luid);
553 status = ERROR_OUTOFMEMORY;
561 return memcmp(item,
address,
sizeof(MIB_UNICASTIPADDRESS_ROW)) == 0 ? TRUE : FALSE;
567 return DeleteUnicastIpAddressEntry(addr_row);
574 PMIB_UNICASTIPADDRESS_ROW addr_row;
577 addr_row = malloc(
sizeof(*addr_row));
578 if (addr_row == NULL)
580 return ERROR_OUTOFMEMORY;
583 InitializeUnicastIpAddressEntry(addr_row);
585 addr_row->OnLinkPrefixLength = (UINT8)
msg->prefix_len;
589 addr_row->InterfaceIndex =
msg->iface.index;
599 addr_row->InterfaceLuid = luid;
604 err = CreateUnicastIpAddressEntry(addr_row);
639 return memcmp(item,
route,
sizeof(MIB_IPFORWARD_ROW2)) == 0 ? TRUE : FALSE;
645 return DeleteIpForwardEntry2(fwd_row);
652 PMIB_IPFORWARD_ROW2 fwd_row;
655 fwd_row = malloc(
sizeof(*fwd_row));
658 return ERROR_OUTOFMEMORY;
661 ZeroMemory(fwd_row,
sizeof(*fwd_row));
662 fwd_row->ValidLifetime = 0xffffffff;
663 fwd_row->PreferredLifetime = 0xffffffff;
664 fwd_row->Protocol = MIB_IPPROTO_NETMGMT;
665 fwd_row->Metric =
msg->metric;
667 fwd_row->DestinationPrefix.PrefixLength = (UINT8)
msg->prefix_len;
672 fwd_row->InterfaceIndex =
msg->iface.index;
674 else if (strlen(
msg->iface.name))
682 fwd_row->InterfaceLuid = luid;
687 err = CreateIpForwardEntry2(fwd_row);
723 if (
msg->family == AF_INET)
725 return FlushIpNetTable(
msg->iface.index);
728 return FlushIpNetTable2(
msg->family,
msg->iface.index);
742 err_str = L
"Unknown Win32 Error";
744 if (FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
745 NULL, err, 0, buf, _countof(buf), NULL))
792 HANDLE engine = NULL;
805 err = ERROR_OUTOFMEMORY;
808 block_data->
engine = engine;
809 block_data->
index =
msg->iface.index;
873ExecCommand(
const WCHAR *argv0,
const WCHAR *cmdline, DWORD timeout)
877 PROCESS_INFORMATION pi;
878 DWORD proc_flags = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
879 WCHAR *cmdline_dup = NULL;
881 ZeroMemory(&si,
sizeof(si));
882 ZeroMemory(&pi,
sizeof(pi));
887 cmdline_dup = _wcsdup(cmdline);
889 && CreateProcessW(argv0, cmdline_dup, NULL, NULL, FALSE, proc_flags, NULL, NULL, &si, &pi))
891 WaitForSingleObject(pi.hProcess, timeout ? timeout : INFINITE);
892 if (!GetExitCodeProcess(pi.hProcess, &exit_code))
895 exit_code = GetLastError();
897 else if (exit_code == STILL_ACTIVE)
899 exit_code = WAIT_TIMEOUT;
902 TerminateProcess(pi.hProcess, exit_code);
903 MsgToEventLog(
M_ERR, L
"ExecCommand: \"%ls %ls\" killed after timeout", argv0, cmdline);
915 CloseHandle(pi.hProcess);
916 CloseHandle(pi.hThread);
920 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 (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());
1186 if (ControlService(dnssvc, SERVICE_CONTROL_PARAMCHANGE, &
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;
1229 err = ConvertInterfaceLuidToGuid(&luid, &guid);
1236 if (StringFromIID(&guid, &iid_str) != S_OK)
1239 err = ERROR_OUTOFMEMORY;
1242 if (wcslen(iid_str) + 1 > len)
1244 err = ERROR_INVALID_PARAMETER;
1248 wcsncpy(str, iid_str, len);
1253 CoTaskMemFree(iid_str);
1275 DWORD size =
sizeof(
data);
1276 LSTATUS err = RegGetValueA(
key, NULL,
"SearchList", RRF_RT_REG_SZ, NULL, (PBYTE)
data, &size);
1277 if (!err || err == ERROR_MORE_DATA)
1280 for (
size_t i = 0; i < strlen(
data); ++i)
1282 if (isalnum(
data[i]) ||
data[i] ==
'-' ||
data[i] ==
'.')
1316 err = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient",
1317 0, KEY_ALL_ACCESS,
key);
1330 RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"System\\CurrentControlSet\\Services\\TCPIP\\Parameters",
1331 0, KEY_ALL_ACCESS,
key);
1350 RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1351 "System\\CurrentControlSet\\Services\\TCPIP\\Parameters\\Interfaces",
1352 0, KEY_ALL_ACCESS, &itfs);
1355 err = RegOpenKeyExW(itfs, iid, 0, KEY_ALL_ACCESS,
key);
1365 *
key = INVALID_HANDLE_VALUE;
1381 err = RegGetValueA(
key, NULL,
"InitialSearchList", RRF_RT_REG_SZ, NULL, NULL, NULL);
1384 if (err == ERROR_FILE_NOT_FOUND)
1401 size_t length = (wcslen(
string) + 1) *
sizeof(
wchar_t);
1402 if (length > UINT_MAX)
1406 return (DWORD)length;
1422 if (!list || wcslen(list) == 0)
1435 LSTATUS err = RegSetValueExW(
key, L
"InitialSearchList", 0, REG_SZ, (PBYTE)list, size);
1438 MsgToEventLog(
M_ERR, L
"%S: failed to set InitialSearchList value (%lu)", __func__, err);
1458 WCHAR list[2048] = { 0 };
1459 DWORD size =
sizeof(list);
1463 err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1476 size_t listlen = (size /
sizeof(list[0])) - 1;
1477 size_t domlen = wcslen(domains);
1478 if (listlen + domlen + 2 > _countof(list))
1486 PWSTR
pos = list + listlen;
1488 wcsncpy(
pos + 1, domains, domlen + 1);
1492 wcsncpy(list, domains, wcslen(domains) + 1);
1496 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1523 DWORD size =
sizeof(list);
1525 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, list, &size);
1528 if (err != ERROR_FILE_NOT_FOUND)
1537 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1544 RegDeleteValueA(
key,
"InitialSearchList");
1562 DWORD size =
sizeof(list);
1564 err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1571 PWSTR dst = wcsstr(list, domains);
1579 size_t domlen = wcslen(domains);
1580 PCWSTR src = dst + domlen;
1582 dst = dst > list ? dst - 1 : dst;
1583 wmemmove(dst, src, domlen);
1585 size_t list_len = wcslen(list);
1589 WCHAR initial[2048];
1590 size =
sizeof(initial);
1591 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, initial, &size);
1600 if (wcsncmp(list, initial, list_len) == 0)
1608 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1624 HKEY dns_searchlist_key;
1626 if (dns_searchlist_key != INVALID_HANDLE_VALUE)
1629 RegCloseKey(dns_searchlist_key);
1661 DWORD err = ERROR_OUTOFMEMORY;
1665 if (list_key == INVALID_HANDLE_VALUE)
1668 return ERROR_FILE_NOT_FOUND;
1682 if (domains && *domains)
1684 wchar_t *wide_domains =
utf8to16(domains);
1690 undo_data = malloc(
sizeof(*undo_data));
1694 wide_domains = NULL;
1698 undo_data->
domains = wide_domains;
1714 RegCloseKey(list_key);
1728 PCSTR itfs_key = family == AF_INET6
1729 ?
"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces"
1730 :
"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
1732 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, itfs_key, 0, KEY_ALL_ACCESS,
key);
1735 *
key = INVALID_HANDLE_VALUE;
1737 __func__, family, err);
1740 return err ? FALSE : TRUE;
1760 return ERROR_FILE_NOT_FOUND;
1763 HKEY itf = INVALID_HANDLE_VALUE;
1764 err = RegOpenKeyExW(itfs, itf_id, 0, KEY_ALL_ACCESS, &itf);
1768 __func__, itf_id, family, err);
1772 err = RegSetValueExA(itf,
"NameServer", 0, REG_SZ, (PBYTE)value, (DWORD)strlen(value) + 1);
1776 __func__, value, itf_id, family, err);
1780 if (itf != INVALID_HANDLE_VALUE)
1784 if (itfs != INVALID_HANDLE_VALUE)
1825 unsigned int addr_len =
msg->addr_len;
1828 const unsigned int max_addrs = _countof(
msg->addr);
1829 if (addr_len > max_addrs)
1831 addr_len = max_addrs;
1834 if (!
msg->iface.name[0])
1843 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
1844 msgptr->
domains[_countof(
msg->domains) - 1] =
'\0';
1870 if (
msg->domains[0])
1884 CHAR addrs[_countof(
msg->addr) * 64];
1886 for (
unsigned int i = 0; i < addr_len; ++i)
1890 addrs[offset++] =
',';
1892 if (
msg->family == AF_INET6)
1894 RtlIpv6AddressToStringA(&
msg->addr[i].ipv6, addrs + offset);
1898 RtlIpv4AddressToStringA(&
msg->addr[i].ipv4, addrs + offset);
1900 offset = strlen(addrs);
1909 wchar_t *tmp_iid = _wcsdup(iid);
1910 if (!tmp_iid ||
AddListItem(&(*lists)[undo_type], tmp_iid))
1914 return ERROR_OUTOFMEMORY;
1919 if (
msg->domains[0])
1940 DWORD size =
sizeof(
dhcp);
1943 err = RegGetValueA(
key, NULL,
"EnableDHCP", RRF_RT_REG_DWORD, NULL, (PBYTE)&
dhcp, &size);
1944 if (err != NO_ERROR)
1950 return dhcp ? TRUE : FALSE;
1964 const short families[] = { AF_INET, AF_INET6 };
1965 for (
size_t i = 0; i < _countof(families); i++)
1967 short family = families[i];
1974 if ((family == AF_INET6 && strchr(addresses[j],
':') == NULL)
1975 || (family == AF_INET && strchr(addresses[j],
':') != NULL))
1982 addr_list[offset++] =
',';
1984 strcpy(addr_list + offset, addresses[j]);
1985 offset += strlen(addresses[j]);
2017 addrs[*size - 1] =
'\0';
2021 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2022 if (err && err != ERROR_FILE_NOT_FOUND)
2032 RegGetValueA(itf_key, NULL,
"DhcpNameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2040 if (strchr(addrs,
'.'))
2047 return ERROR_FILE_NOT_FOUND;
2062 addrs[*size - 1] =
'\0';
2066 err = RegGetValueA(itf_key, NULL,
"NameServer", RRF_RT_REG_SZ, NULL, (PBYTE)addrs, &s);
2067 if (err && err != ERROR_FILE_NOT_FOUND)
2076 IN6_ADDR in_addrs[8];
2077 DWORD in_addrs_size =
sizeof(in_addrs);
2078 err = RegGetValueA(itf_key, NULL,
"Dhcpv6DNSServers", RRF_RT_REG_BINARY, NULL,
2079 (PBYTE)in_addrs, &in_addrs_size);
2088 size_t in_addrs_read = in_addrs_size /
sizeof(IN6_ADDR);
2089 for (
size_t i = 0; i < in_addrs_read; ++i)
2098 if (inet_ntop(AF_INET6, &in_addrs[i],
pos, s) != NULL)
2101 return ERROR_MORE_DATA;
2104 size_t addr_len = strlen(
pos);
2106 s -= (DWORD)addr_len;
2108 s = (DWORD)strlen(addrs) + 1;
2111 if (strchr(addrs,
':'))
2118 return ERROR_FILE_NOT_FOUND;
2133 PCWSTR match = list;
2136 match = wcsstr(match, domain);
2142 if ((match == list || *(match - 1) ==
',')
2143 && (*(match + len) ==
',' || *(match + len) ==
'\0'))
2177 const DWORD glyph_size =
sizeof(*domains);
2178 const DWORD
buf_len = buf_size / glyph_size;
2185 PWCHAR
pos = domains;
2189 PWCHAR comma = wcschr(
pos,
',');
2195 DWORD domain_len = (DWORD)wcslen(
pos);
2196 DWORD domain_size = domain_len * glyph_size;
2197 DWORD converted_size = (DWORD)(
pos - domains) * glyph_size;
2205 memmove(
pos, comma + 1, buf_size - converted_size);
2206 *size -= domain_size + glyph_size;
2213 *size -= domain_size;
2214 return wcslen(domains) ? NO_ERROR : ERROR_FILE_NOT_FOUND;
2220 domain_size += glyph_size;
2223 const DWORD extra_size = 2 * glyph_size;
2226 if (converted_size + domain_size + extra_size > buf_size)
2230 *size = converted_size == 0 ? 0 : converted_size + glyph_size;
2231 return ERROR_MORE_DATA;
2235 memmove(
pos + 1,
pos, buf_size - converted_size - glyph_size);
2238 *size += glyph_size;
2243 *(
pos + domain_len) =
'\0';
2244 *size += glyph_size;
2277 if (domains == NULL || size == NULL || *size == 0)
2279 return ERROR_INVALID_PARAMETER;
2282 LSTATUS err = ERROR_FILE_NOT_FOUND;
2283 const DWORD buf_size = *size;
2284 const DWORD glyph_size =
sizeof(*domains);
2285 PWSTR values[] = { L
"SearchList", L
"Domain", L
"DhcpDomainSearchList", L
"DhcpDomain", NULL };
2287 for (
int i = 0; values[i]; i++)
2290 err = RegGetValueW(itf, NULL, values[i], RRF_RT_REG_SZ, NULL, (PBYTE)domains, size);
2291 if (!err && *size > glyph_size && domains[(*size / glyph_size) - 1] ==
'\0' && wcschr(domains,
'.'))
2314 MIB_IF_ROW2 itf_row;
2317 if (IIDFromString(iid_str, &iid) != S_OK)
2325 if (ConvertInterfaceGuidToLuid(&iid, &itf_row.InterfaceLuid) != NO_ERROR)
2331 if (GetIfEntry2(&itf_row) != NO_ERROR)
2337 if (itf_row.MediaConnectState == MediaConnectStateConnected
2338 && itf_row.OperStatus == IfOperStatusUp)
2359 HKEY v4_itfs = INVALID_HANDLE_VALUE;
2360 HKEY v6_itfs = INVALID_HANDLE_VALUE;
2368 DWORD enum_index = 0;
2369 while (i < data_size)
2371 WCHAR itf_guid[MAX_PATH];
2372 DWORD itf_guid_len = _countof(itf_guid);
2374 RegEnumKeyExW(v4_itfs, enum_index++, itf_guid, &itf_guid_len, NULL, NULL, NULL, NULL);
2377 if (err != ERROR_NO_MORE_ITEMS)
2391 if (RegOpenKeyExW(v4_itfs, itf_guid, 0, KEY_READ, &v4_itf) != NO_ERROR)
2399 data[i].domains_size =
sizeof(
data[0].domains);
2400 memset(
data[i].domains, 0,
data[i].domains_size);
2404 if (err != ERROR_FILE_NOT_FOUND)
2413 DWORD v4_addrs_size =
sizeof(
data[0].addresses);
2415 if (err && err != ERROR_FILE_NOT_FOUND)
2418 __func__, itf_guid, err);
2423 PSTR v6_addrs =
data[i].addresses + v4_addrs_size;
2424 DWORD v6_addrs_size =
sizeof(
data[0].addresses) - v4_addrs_size;
2428 if (RegOpenKeyExW(v6_itfs, itf_guid, 0, KEY_READ, &v6_itf) != NO_ERROR)
2431 __func__, itf_guid);
2435 RegCloseKey(v6_itf);
2436 if (err && err != ERROR_FILE_NOT_FOUND)
2439 __func__, itf_guid, err);
2444 if (v4_addrs_size || v6_addrs_size)
2447 for (
size_t j = 0; j <
sizeof(
data[0].addresses) &&
data[i].addresses[j]; j++)
2449 if (
data[i].addresses[j] ==
',' ||
data[i].addresses[j] ==
' ')
2451 data[i].addresses[j] =
';';
2458 RegCloseKey(v4_itf);
2462 RegCloseKey(v6_itfs);
2463 RegCloseKey(v4_itfs);
2483 DWORD err = NO_ERROR;
2485 err = RegCreateKeyExW(nrpt_key, subkey, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &rule_key, NULL);
2492 err = RegSetValueExW(rule_key, L
"Name", 0, REG_MULTI_SZ, (PBYTE)domains, dom_size);
2499 err = RegSetValueExA(rule_key,
"GenericDNSServers", 0, REG_SZ, (PBYTE)
address,
2511 err = RegSetValueExA(rule_key,
"DNSSECValidationRequired", 0, REG_DWORD, (PBYTE)®_val,
2519 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECRequired", 0, REG_DWORD, (PBYTE)®_val,
2527 err = RegSetValueExA(rule_key,
"DNSSECQueryIPSECEncryption", 0, REG_DWORD, (PBYTE)®_val,
2536 reg_val = dnssec ? 0x0000000A : 0x00000008;
2537 err = RegSetValueExA(rule_key,
"ConfigOptions", 0, REG_DWORD, (
const PBYTE)®_val,
2546 err = RegSetValueExA(rule_key,
"Version", 0, REG_DWORD, (
const PBYTE)®_val,
sizeof(reg_val));
2555 RegDeleteKeyW(nrpt_key, subkey);
2557 RegCloseKey(rule_key);
2578 for (
size_t i = 0; i < _countof(
data); ++i)
2588 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRoutingX-%02x-%lu", ++n, ovpn_pid);
2611 const char *search_domains, BOOL dnssec, DWORD ovpn_pid)
2613 DWORD err = NO_ERROR;
2614 PWSTR wide_domains = L
".\0";
2620 size_t domains_len = strlen(domains);
2621 dom_size = (DWORD)domains_len + 2;
2624 dom_size *=
sizeof(*wide_domains);
2627 return ERROR_OUTOFMEMORY;
2630 for (
size_t i = 0; i < domains_len; ++i)
2632 if (wide_domains[i] ==
',')
2634 wide_domains[i] = 0;
2640 PWSTR wide_search_domains;
2641 wide_search_domains =
utf8to16(search_domains);
2642 if (!wide_search_domains)
2644 return ERROR_OUTOFMEMORY;
2647 free(wide_search_domains);
2650 if (addresses[0][0])
2654 PSTR
pos = addr_list;
2661 strcpy(
pos, addresses[i]);
2665 WCHAR subkey[MAX_PATH];
2666 swprintf(subkey, _countof(subkey), L
"OpenVPNDNSRouting-%lu", ovpn_pid);
2667 err =
SetNrptRule(nrpt_key, subkey, addr_list, wide_domains, dom_size, dnssec);
2698 static PCSTR gpol_key =
"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient\\DnsPolicyConfig";
2699 static PCSTR sys_key =
2700 "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig";
2704 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, gpol_key, 0, KEY_ALL_ACCESS, &nrpt);
2705 if (err == ERROR_FILE_NOT_FOUND)
2708 err = RegCreateKeyExA(HKEY_LOCAL_MACHINE, sys_key, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &nrpt,
2712 nrpt = INVALID_HANDLE_VALUE;
2746 swprintf(pid_str, _countof(pid_str), L
"-%lu", pid);
2747 pidlen = wcslen(pid_str);
2751 DWORD enum_index = 0;
2754 WCHAR name[MAX_PATH];
2755 DWORD namelen = _countof(name);
2756 err = RegEnumKeyExW(
key, enum_index++, name, &namelen, NULL, NULL, NULL, NULL);
2759 if (err != ERROR_NO_MORE_ITEMS)
2767 if (wcsncmp(name, L
"OpenVPNDNSRouting", 17) != 0
2768 || (pid && wcsncmp(name + namelen - pidlen, pid_str, pidlen) != 0))
2773 if (RegDeleteKeyW(
key, name) == NO_ERROR)
2781 return deleted ? TRUE : FALSE;
2819 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
2824 msgptr->
addresses[i][_countof(
msg->addresses[0]) - 1] =
'\0';
2829 if (
msg->iface.name[0] == 0)
2838 if (
msg->addresses[0][0] == 0)
2843 const char *rdom =
msg->resolve_domains;
2844 size_t rdom_size =
sizeof(
msg->resolve_domains);
2845 size_t rdom_len = strlen(rdom);
2846 if (rdom_len && (rdom_len + 1 >= rdom_size || rdom[rdom_len + 2] != 0))
2852 BOOL gpol_nrpt = FALSE;
2853 BOOL gpol_list = FALSE;
2866 if (*undo_pid != ovpn_pid)
2869 L
"%S: PID stored for undo doesn't match: %lu vs %lu. "
2870 "This is likely an error. Cleaning up anyway.",
2871 __func__, *undo_pid, ovpn_pid);
2895 PDWORD pid = malloc(
sizeof(ovpn_pid));
2898 err = ERROR_OUTOFMEMORY;
2904 err = ERROR_OUTOFMEMORY;
2924 if (
msg->search_domains[0] || !
msg->resolve_domains[0])
2934 if (
msg->search_domains[0])
2948 DWORD err = NO_ERROR;
2950 unsigned int addr_len =
msg->addr_len;
2953 if (addr_len > _countof(
msg->addr))
2955 addr_len = _countof(
msg->addr);
2958 if (!
msg->iface.index)
2981 for (
unsigned int i = 0; i < addr_len; ++i)
2983 RtlIpv4AddressToStringW(&
msg->addr[i].ipv4, addr);
2994 PDWORD if_index = malloc(
sizeof(
msg->iface.index));
2997 *if_index =
msg->iface.index;
3004 err = ERROR_OUTOFMEMORY;
3018 DWORD timeout = 5000;
3019 wchar_t argv0[MAX_PATH];
3022 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
3027 const wchar_t *fmt = L
"netsh interface ipv4 set address name=\"%lu\" source=dhcp";
3032 size_t ncmdline = wcslen(fmt) + 10 + 1;
3033 wchar_t *cmdline = malloc(ncmdline *
sizeof(
wchar_t));
3036 err = ERROR_OUTOFMEMORY;
3040 swprintf(cmdline, ncmdline, fmt,
dhcp->iface.index);
3056 MIB_IPINTERFACE_ROW ipiface;
3057 InitializeIpInterfaceEntry(&ipiface);
3058 ipiface.Family = mtu->
family;
3060 err = GetIpInterfaceEntry(&ipiface);
3061 if (err != NO_ERROR)
3065 if (mtu->
family == AF_INET)
3067 ipiface.SitePrefixLength = 0;
3069 ipiface.NlMtu = mtu->
mtu;
3071 err = SetIpInterfaceEntry(&ipiface);
3087 switch (
msg->adapter_type)
3094 hwid = L
"root\\tap0901";
3098 return ERROR_INVALID_PARAMETER;
3101 WCHAR cmd[MAX_PATH];
3102 WCHAR args[MAX_PATH];
3104 if (swprintf_s(cmd, _countof(cmd), L
"%s\\tapctl.exe",
settings.
bin_dir) < 0)
3106 return ERROR_BUFFER_OVERFLOW;
3109 if (swprintf_s(args, _countof(args), L
"tapctl create --hwid %s", hwid) < 0)
3111 return ERROR_BUFFER_OVERFLOW;
3118HandleMessage(HANDLE pipe, PPROCESS_INFORMATION proc_info, DWORD bytes, DWORD count,
3135 switch (
msg.header.type)
3139 if (
msg.header.size ==
sizeof(
msg.address))
3147 if (
msg.header.size ==
sizeof(
msg.route))
3154 if (
msg.header.size ==
sizeof(
msg.flush_neighbors))
3162 if (
msg.header.size ==
sizeof(
msg.wfp_block))
3180 DWORD ovpn_pid = proc_info->dwProcessId;
3191 if (
msg.header.size ==
sizeof(
msg.dhcp))
3198 if (
msg.header.size ==
sizeof(
msg.mtu))
3205 if (
msg.header.size ==
sizeof(
msg.create_adapter))
3284 *pnext = item->
next;
3295 HANDLE ovpn_pipe = NULL, svc_pipe = NULL;
3296 PTOKEN_USER svc_user = NULL, ovpn_user = NULL;
3297 HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL;
3298 HANDLE stdin_read = NULL, stdin_write = NULL;
3299 HANDLE stdout_write = NULL;
3300 DWORD pipe_mode, len, exit_code = 0;
3302 STARTUPINFOW startup_info;
3303 PROCESS_INFORMATION proc_info;
3304 LPVOID user_env = NULL;
3305 WCHAR ovpn_pipe_name[256];
3308 WCHAR *cmdline = NULL;
3309 size_t cmdline_size;
3311 WCHAR errmsg[512] = L
"";
3312 BOOL flush_pipe = TRUE;
3314 SECURITY_ATTRIBUTES inheritable = { .nLength =
sizeof(inheritable),
3315 .lpSecurityDescriptor = NULL,
3316 .bInheritHandle = TRUE };
3319 EXPLICIT_ACCESS ea[2];
3320 SECURITY_DESCRIPTOR ovpn_sd;
3321 SECURITY_ATTRIBUTES ovpn_sa = { .nLength =
sizeof(ovpn_sa),
3322 .lpSecurityDescriptor = &ovpn_sd,
3323 .bInheritHandle = FALSE };
3325 ZeroMemory(&ea,
sizeof(ea));
3326 ZeroMemory(&startup_info,
sizeof(startup_info));
3327 ZeroMemory(&undo_lists,
sizeof(undo_lists));
3328 ZeroMemory(&proc_info,
sizeof(proc_info));
3336 if (!InitializeSecurityDescriptor(&ovpn_sd, SECURITY_DESCRIPTOR_REVISION))
3343 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &svc_token))
3349 while (!GetTokenInformation(svc_token, TokenUser, svc_user, len, &len))
3351 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3357 svc_user = malloc(len);
3358 if (svc_user == NULL)
3364 if (!IsValidSid(svc_user->User.Sid))
3370 if (!ImpersonateNamedPipeClient(pipe))
3375 if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &imp_token))
3381 while (!GetTokenInformation(imp_token, TokenUser, ovpn_user, len, &len))
3383 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
3389 ovpn_user = malloc(len);
3390 if (ovpn_user == NULL)
3396 if (!IsValidSid(ovpn_user->User.Sid))
3418 ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
3419 ea[0].grfAccessMode = SET_ACCESS;
3420 ea[0].grfInheritance = NO_INHERITANCE;
3421 ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3422 ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3423 ea[0].Trustee.ptstrName = (LPWSTR)svc_user->User.Sid;
3424 ea[1].grfAccessPermissions = READ_CONTROL | PROCESS_VM_READ | SYNCHRONIZE
3425 | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION;
3426 ea[1].grfAccessMode = SET_ACCESS;
3427 ea[1].grfInheritance = NO_INHERITANCE;
3428 ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
3429 ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
3430 ea[1].Trustee.ptstrName = (LPWSTR)ovpn_user->User.Sid;
3433 if (!SetSecurityDescriptorOwner(&ovpn_sd, svc_user->User.Sid, FALSE))
3438 if (SetEntriesInAcl(2, ea, NULL, &ovpn_dacl) != ERROR_SUCCESS)
3443 if (!SetSecurityDescriptorDacl(&ovpn_sd, TRUE, ovpn_dacl, FALSE))
3450 if (!DuplicateTokenEx(imp_token, TOKEN_ALL_ACCESS, NULL, 0, TokenPrimary, &pri_token))
3457 stdout_write = CreateFile(
_L(
"NUL"), GENERIC_WRITE, FILE_SHARE_WRITE, &inheritable,
3458 OPEN_EXISTING, 0, NULL);
3459 if (stdout_write == INVALID_HANDLE_VALUE)
3465 if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0)
3466 || !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0))
3473 RPC_STATUS rpc_stat = UuidCreate(&pipe_uuid);
3474 if (rpc_stat != RPC_S_OK)
3480 RPC_WSTR pipe_uuid_str = NULL;
3481 rpc_stat = UuidToStringW(&pipe_uuid, &pipe_uuid_str);
3482 if (rpc_stat != RPC_S_OK)
3487 swprintf(ovpn_pipe_name, _countof(ovpn_pipe_name),
3489 GetCurrentThreadId(), pipe_uuid_str);
3490 RpcStringFreeW(&pipe_uuid_str);
3496 SECURITY_ATTRIBUTES sa;
3497 PSECURITY_DESCRIPTOR pSD = NULL;
3498 LPCWSTR szSDDL = L
"D:(A;;GA;;;SY)(A;;GA;;;OW)";
3499 if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(
3500 szSDDL, SDDL_REVISION_1, &pSD, NULL))
3505 sa.nLength =
sizeof(sa);
3506 sa.lpSecurityDescriptor = pSD;
3507 sa.bInheritHandle = FALSE;
3509 ovpn_pipe = CreateNamedPipe(
3510 ovpn_pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
3511 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, 1, 128, 128, 0, &sa);
3512 if (ovpn_pipe == INVALID_HANDLE_VALUE)
3518 svc_pipe = CreateFile(ovpn_pipe_name, GENERIC_READ | GENERIC_WRITE, 0, &inheritable,
3519 OPEN_EXISTING, 0, NULL);
3520 if (svc_pipe == INVALID_HANDLE_VALUE)
3526 pipe_mode = PIPE_READMODE_MESSAGE;
3527 if (!SetNamedPipeHandleState(svc_pipe, &pipe_mode, NULL, NULL))
3533 cmdline_size = wcslen(sud.
options) + 128;
3534 cmdline = malloc(cmdline_size *
sizeof(*cmdline));
3535 if (cmdline == NULL)
3543 swprintf(cmdline, cmdline_size, L
"openvpn %ls --msg-channel %" PRIuPTR, sud.
options,
3544 (uintptr_t)svc_pipe);
3546 if (!CreateEnvironmentBlock(&user_env, imp_token, FALSE))
3552 startup_info.cb =
sizeof(startup_info);
3553 startup_info.dwFlags = STARTF_USESTDHANDLES;
3554 startup_info.hStdInput = stdin_read;
3555 startup_info.hStdOutput = stdout_write;
3556 startup_info.hStdError = stdout_write;
3561 if (!CreateProcessAsUserW(pri_token, exe_path, cmdline, &ovpn_sa, NULL, TRUE,
3563 user_env, sud.
directory, &startup_info, &proc_info))
3569 if (!RevertToSelf())
3571 TerminateProcess(proc_info.hProcess, 1);
3582 DWORD input_size = WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, NULL, 0, NULL, NULL);
3584 if (input_size && (input = malloc(input_size)))
3587 WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, input, input_size, NULL, NULL);
3588 WriteFile(stdin_write, input, (DWORD)strlen(input), &written, NULL);
3605 L
"OpenVPN process sent too large payload length to the pipe (%lu bytes), it will be terminated",
3613 WaitForSingleObject(proc_info.hProcess,
IO_TIMEOUT);
3614 GetExitCodeProcess(proc_info.hProcess, &exit_code);
3615 if (exit_code == STILL_ACTIVE)
3617 TerminateProcess(proc_info.hProcess, 1);
3619 else if (exit_code != 0)
3622 swprintf(buf, _countof(buf), L
"OpenVPN exited with error: exit code = %lu", exit_code);
3630 FlushFileBuffers(pipe);
3632 DisconnectNamedPipe(pipe);
3637 DestroyEnvironmentBlock(user_env);
3658 SERVICE_STATUS *
status = ctx;
3661 case SERVICE_CONTROL_STOP:
3662 status->dwCurrentState = SERVICE_STOP_PENDING;
3670 case SERVICE_CONTROL_INTERROGATE:
3674 return ERROR_CALL_NOT_IMPLEMENTED;
3688 const WCHAR *sddlString =
3689 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)";
3691 PSECURITY_DESCRIPTOR sd = NULL;
3692 if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddlString, SDDL_REVISION_1, &sd,
3696 return INVALID_HANDLE_VALUE;
3700 SECURITY_ATTRIBUTES sa = { 0 };
3701 sa.nLength =
sizeof(SECURITY_ATTRIBUTES);
3702 sa.lpSecurityDescriptor = sd;
3703 sa.bInheritHandle = FALSE;
3705 DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED;
3707 static BOOL first = TRUE;
3710 flags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
3714 WCHAR pipe_name[256];
3716 swprintf(pipe_name, _countof(pipe_name), L
"\\\\.\\pipe\\" _L(PACKAGE) L
"%ls\\service",
3718 HANDLE pipe = CreateNamedPipe(
3719 pipe_name, flags, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
3720 PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, &sa);
3724 if (pipe == INVALID_HANDLE_VALUE)
3727 return INVALID_HANDLE_VALUE;
3738 static DWORD size = 10;
3739 static LPHANDLE handles = NULL;
3742 if (handles == NULL)
3744 handles = malloc(size *
sizeof(HANDLE));
3745 *handles_ptr = handles;
3746 if (handles == NULL)
3748 return ERROR_OUTOFMEMORY;
3752 handles[
pos++] = io_event;
3765 tmp = realloc(handles, size *
sizeof(HANDLE));
3770 return ERROR_OUTOFMEMORY;
3773 *handles_ptr = handles;
3775 handles[
pos++] = threads->
data;
3776 threads = threads->
next;
3800 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
3812 BOOL changed = FALSE;
3822 if (
key != INVALID_HANDLE_VALUE)
3840 HANDLE pipe, io_event = NULL;
3841 OVERLAPPED overlapped;
3842 DWORD error = NO_ERROR;
3844 PHANDLE handles = NULL;
3854 status.dwCurrentState = SERVICE_START_PENDING;
3855 status.dwServiceSpecificExitCode = NO_ERROR;
3856 status.dwWin32ExitCode = NO_ERROR;
3857 status.dwWaitHint = 3000;
3865 if (error != ERROR_SUCCESS)
3871 exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
3886 if (error != NO_ERROR)
3892 if (pipe == INVALID_HANDLE_VALUE)
3897 status.dwCurrentState = SERVICE_RUNNING;
3903 if (!ConnectNamedPipe(pipe, &overlapped))
3905 DWORD connect_error = GetLastError();
3906 if (connect_error == ERROR_NO_DATA)
3913 DisconnectNamedPipe(pipe);
3917 else if (connect_error == ERROR_PIPE_CONNECTED)
3920 SetEvent(overlapped.hEvent);
3922 else if (connect_error != ERROR_IO_PENDING)
3929 error = WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
3930 if (error == WAIT_OBJECT_0)
3936 if (handle_count + 1 > MAXIMUM_WAIT_OBJECTS)
3945 HANDLE thread = CreateThread(NULL, 0,
RunOpenvpn, pipe, CREATE_SUSPENDED, NULL);
3956 ReturnError(pipe, error, L
"Insufficient resources to service new clients", 1,
3961 TerminateThread(thread, 1);
3967 ResumeThread(thread);
3981 if (error == WAIT_FAILED)
4011 status.dwCurrentState = SERVICE_STOPPED;
4012 status.dwWin32ExitCode = error;
static int buf_len(const struct buffer *buf)
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 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 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 LSTATUS ConvertItfDnsDomains(PCWSTR search_domains, PWSTR domains, PDWORD size, const DWORD buf_size)
Convert interface specific domain suffix(es) from comma-separated string to MULTI_SZ string.
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 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 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]
WCHAR ovpn_admin_group[MAX_NAME]
WCHAR ovpn_service_user[MAX_NAME]
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)