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
53 static 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)
132 if (new_item == NULL)
134 return ERROR_OUTOFMEMORY;
137 new_item->
next = *pfirst;
138 new_item->
data = data;
152 for (pnext = pfirst; *pnext; pnext = &(*pnext)->
next)
155 if (!match(item->
data, ctx))
173 if (handle && *handle && *handle != INVALID_HANDLE_VALUE)
175 CloseHandle(*handle);
176 *handle = INVALID_HANDLE_VALUE;
178 return INVALID_HANDLE_VALUE;
186 UnmapViewOfFile(*ring);
201 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
202 overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
203 return overlapped->hEvent;
210 HANDLE io_event = overlapped->hEvent;
211 if (!ResetEvent(io_event))
215 ZeroMemory(overlapped,
sizeof(OVERLAPPED));
216 overlapped->hEvent = io_event;
233 DWORD res, bytes = 0;
234 OVERLAPPED overlapped;
235 LPHANDLE handles = NULL;
243 handles = malloc((count + 1) *
sizeof(HANDLE));
251 success = WriteFile(pipe,
buffer, size, NULL, &overlapped);
255 success = ReadFile(pipe,
buffer, size, NULL, &overlapped);
257 if (!success && GetLastError() != ERROR_IO_PENDING && GetLastError() != ERROR_MORE_DATA)
262 handles[0] = io_event;
263 for (i = 0; i < count; i++)
265 handles[i + 1] = events[i];
268 res = WaitForMultipleObjects(count + 1, handles, FALSE,
270 if (res != WAIT_OBJECT_0)
278 PeekNamedPipe(pipe, NULL, 0, NULL, &bytes, NULL);
282 GetOverlappedResult(pipe, &overlapped, &bytes, TRUE);
304 WritePipeAsync(HANDLE pipe, LPVOID data, DWORD size, DWORD count, LPHANDLE events)
312 const WCHAR
msg[] = L
"Process ID";
313 WCHAR buf[22 + _countof(
msg)];
319 swprintf(buf, _countof(buf), L
"0x%08x\n0x%08x\n%ls", 0, pid,
msg);
321 WritePipeAsync(pipe, buf, (DWORD)(wcslen(buf) * 2), count, events);
325 ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events)
328 LPWSTR result = L
"0xffffffff\nFormatMessage failed\nCould not return result";
337 FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM
338 |FORMAT_MESSAGE_ALLOCATE_BUFFER
339 |FORMAT_MESSAGE_IGNORE_INSERTS,
340 0, error, 0, (LPWSTR) &args[2], 0, NULL);
343 result_len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING
344 |FORMAT_MESSAGE_ALLOCATE_BUFFER
345 |FORMAT_MESSAGE_ARGUMENT_ARRAY,
346 L
"0x%1!08x!\n%2!s!\n%3!s!", 0, 0,
347 (LPWSTR) &result, 0, (va_list *) args);
349 WritePipeAsync(pipe, result, (DWORD)(wcslen(result) * 2), count, events);
354 LocalFree((LPVOID) args[2]);
381 const WCHAR *msg1 = L
"You have specified a config file location (%ls relative to %ls)"
382 L
" that requires admin approval. This error may be avoided"
383 L
" by adding your account to the \"%ls\" group";
385 const WCHAR *msg2 = L
"You have specified an option (%ls) that may be used"
386 L
" only with admin approval. This error may be avoided"
387 L
" by adding your account to the \"%ls\" group";
393 swprintf(errmsg, capacity,
394 L
"Cannot validate options: CommandLineToArgvW failed with error = 0x%08x",
411 WCHAR *argv_tmp[2] = { L
"--config",
argv[0] };
415 swprintf(errmsg, capacity, msg1,
argv[0], workdir,
421 for (i = 0; i < argc; ++i)
430 if (wcscmp(L
"--config",
argv[i]) == 0 && argc-i > 1)
432 swprintf(errmsg, capacity, msg1,
argv[i+1], workdir,
437 swprintf(errmsg, capacity, msg2,
argv[i],
470 size = bytes /
sizeof(*data);
478 data = malloc(bytes);
494 if (data[size - 1] != 0)
512 len = wcslen(sud->
options) + 1;
541 SOCKADDR_INET sa_inet;
542 ZeroMemory(&sa_inet,
sizeof(sa_inet));
543 sa_inet.si_family = family;
544 if (family == AF_INET)
546 sa_inet.Ipv4.sin_addr = addr->
ipv4;
548 else if (family == AF_INET6)
550 sa_inet.Ipv6.sin6_addr = addr->
ipv6;
559 LPWSTR wide_name =
utf8to16(iface_name);
563 status = ConvertInterfaceAliasToLuid(wide_name, luid);
568 status = ERROR_OUTOFMEMORY;
576 return memcmp(item,
address,
sizeof(MIB_UNICASTIPADDRESS_ROW)) == 0 ? TRUE : FALSE;
582 return DeleteUnicastIpAddressEntry(addr_row);
589 PMIB_UNICASTIPADDRESS_ROW addr_row;
592 addr_row = malloc(
sizeof(*addr_row));
593 if (addr_row == NULL)
595 return ERROR_OUTOFMEMORY;
598 InitializeUnicastIpAddressEntry(addr_row);
600 addr_row->OnLinkPrefixLength = (UINT8)
msg->prefix_len;
602 if (
msg->iface.index != -1)
604 addr_row->InterfaceIndex =
msg->iface.index;
614 addr_row->InterfaceLuid = luid;
619 err = CreateUnicastIpAddressEntry(addr_row);
654 return memcmp(item,
route,
sizeof(MIB_IPFORWARD_ROW2)) == 0 ? TRUE : FALSE;
660 return DeleteIpForwardEntry2(fwd_row);
667 PMIB_IPFORWARD_ROW2 fwd_row;
670 fwd_row = malloc(
sizeof(*fwd_row));
673 return ERROR_OUTOFMEMORY;
676 ZeroMemory(fwd_row,
sizeof(*fwd_row));
677 fwd_row->ValidLifetime = 0xffffffff;
678 fwd_row->PreferredLifetime = 0xffffffff;
679 fwd_row->Protocol = MIB_IPPROTO_NETMGMT;
680 fwd_row->Metric =
msg->metric;
682 fwd_row->DestinationPrefix.PrefixLength = (UINT8)
msg->prefix_len;
685 if (
msg->iface.index != -1)
687 fwd_row->InterfaceIndex =
msg->iface.index;
689 else if (strlen(
msg->iface.name))
697 fwd_row->InterfaceLuid = luid;
702 err = CreateIpForwardEntry2(fwd_row);
738 if (
msg->family == AF_INET)
740 return FlushIpNetTable(
msg->iface.index);
743 return FlushIpNetTable2(
msg->family,
msg->iface.index);
757 err_str = L
"Unknown Win32 Error";
759 if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM
760 | FORMAT_MESSAGE_ARGUMENT_ARRAY,
761 NULL, err, 0, buf,
sizeof(buf), NULL))
810 HANDLE engine = NULL;
823 err = ERROR_OUTOFMEMORY;
826 block_data->
engine = engine;
827 block_data->
index =
msg->iface.index;
895 ExecCommand(
const WCHAR *argv0,
const WCHAR *cmdline, DWORD timeout)
899 PROCESS_INFORMATION pi;
900 DWORD proc_flags = CREATE_NO_WINDOW|CREATE_UNICODE_ENVIRONMENT;
901 WCHAR *cmdline_dup = NULL;
903 ZeroMemory(&si,
sizeof(si));
904 ZeroMemory(&pi,
sizeof(pi));
909 cmdline_dup = _wcsdup(cmdline);
910 if (cmdline_dup && CreateProcessW(argv0, cmdline_dup, NULL, NULL, FALSE,
911 proc_flags, NULL, NULL, &si, &pi) )
913 WaitForSingleObject(pi.hProcess, timeout ? timeout : INFINITE);
914 if (!GetExitCodeProcess(pi.hProcess, &exit_code))
917 exit_code = GetLastError();
919 else if (exit_code == STILL_ACTIVE)
921 exit_code = WAIT_TIMEOUT;
924 TerminateProcess(pi.hProcess, exit_code);
931 argv0, cmdline, exit_code);
938 CloseHandle(pi.hProcess);
939 CloseHandle(pi.hThread);
943 exit_code = GetLastError();
963 WCHAR ipcfg[MAX_PATH];
971 { ipcfg, L
"ipconfig /flushdns", timeout },
972 { ipcfg, L
"ipconfig /registerdns", timeout },
977 swprintf(ipcfg, MAX_PATH, L
"%ls\\%ls",
get_win_sys_path(), L
"ipconfig.exe");
979 if (WaitForMultipleObjects(2, wait_handles, FALSE, timeout) == WAIT_OBJECT_0)
982 for (i = 0; i < _countof(cmds); ++i)
984 ExecCommand(cmds[i].argv0, cmds[i].cmdline, cmds[i].timeout);
995 err = ERROR_SEM_TIMEOUT;
1004 HANDLE thread = NULL;
1007 thread = CreateThread(NULL, 0,
RegisterDNS, NULL, 0, NULL);
1016 CloseHandle(thread);
1020 err = GetLastError();
1039 int timeout = 30000;
1040 wchar_t argv0[MAX_PATH];
1041 wchar_t *cmdline = NULL;
1042 const wchar_t *addr_static = (wcscmp(action, L
"set") == 0) ? L
"static" : L
"";
1046 if (wcscmp(action, L
"delete") == 0)
1057 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
1062 const wchar_t *fmt = L
"netsh interface ip %ls wins \"%ls\" %ls %ls";
1065 size_t ncmdline = wcslen(fmt) + wcslen(if_name) + wcslen(action) + wcslen(addr)
1066 +wcslen(addr_static) + 32 + 1;
1067 cmdline = malloc(ncmdline *
sizeof(
wchar_t));
1070 err = ERROR_OUTOFMEMORY;
1074 swprintf(cmdline, ncmdline, fmt, action, if_name, addr_static, addr);
1086 return (wcscmp(item, str) == 0) ? TRUE : FALSE;
1098 typedef NTSTATUS (__stdcall *publish_fn_t)(
1104 DWORD ExplicitScope);
1105 publish_fn_t RtlPublishWnfStateData;
1106 const DWORD WNF_GPOL_SYSTEM_CHANGES_HI = 0x0D891E2A;
1107 const DWORD WNF_GPOL_SYSTEM_CHANGES_LO = 0xA3BC0875;
1109 HMODULE ntdll = LoadLibraryA(
"ntdll.dll");
1115 RtlPublishWnfStateData = (publish_fn_t) GetProcAddress(ntdll,
"RtlPublishWnfStateData");
1116 if (RtlPublishWnfStateData == NULL)
1121 if (RtlPublishWnfStateData(WNF_GPOL_SYSTEM_CHANGES_LO, WNF_GPOL_SYSTEM_CHANGES_HI, 0, 0, 0, 0) != ERROR_SUCCESS)
1138 typedef NTSTATUS (*publish_fn_t)(
1142 unsigned int Length,
1143 INT64 ExplicitScope);
1144 publish_fn_t RtlPublishWnfStateData;
1145 const INT64 WNF_GPOL_SYSTEM_CHANGES = 0x0D891E2AA3BC0875;
1147 HMODULE ntdll = LoadLibraryA(
"ntdll.dll");
1153 RtlPublishWnfStateData = (publish_fn_t) GetProcAddress(ntdll,
"RtlPublishWnfStateData");
1154 if (RtlPublishWnfStateData == NULL)
1159 if (RtlPublishWnfStateData(WNF_GPOL_SYSTEM_CHANGES, 0, 0, 0, 0) != ERROR_SUCCESS)
1177 const BOOL win_32bit = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL;
1192 SC_HANDLE scm = NULL;
1193 SC_HANDLE dnssvc = NULL;
1200 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1204 __func__, GetLastError());
1208 dnssvc = OpenServiceA(scm,
"Dnscache", SERVICE_PAUSE_CONTINUE);
1212 __func__, GetLastError());
1217 if (ControlService(dnssvc, SERVICE_CONTROL_PARAMCHANGE, &
status) == 0)
1220 __func__, GetLastError());
1229 CloseServiceHandle(dnssvc);
1233 CloseServiceHandle(scm);
1253 PWSTR iid_str = NULL;
1261 err = ConvertInterfaceLuidToGuid(&luid, &guid);
1268 if (StringFromIID(&guid, &iid_str) != S_OK)
1271 err = ERROR_OUTOFMEMORY;
1274 if (wcslen(iid_str) + 1 > len)
1276 err = ERROR_INVALID_PARAMETER;
1280 wcsncpy(str, iid_str, len);
1285 CoTaskMemFree(iid_str);
1307 DWORD size =
sizeof(data);
1308 LSTATUS err = RegGetValueA(
key, NULL,
"SearchList", RRF_RT_REG_SZ, NULL, (PBYTE)data, &size);
1309 if (!err || err == ERROR_MORE_DATA)
1311 data[
sizeof(data) - 1] =
'\0';
1312 for (
int i = 0; i < strlen(data); ++i)
1314 if (isalnum(data[i]) || data[i] ==
'-' || data[i] ==
'.')
1348 err = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1349 "SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient",
1350 0, KEY_ALL_ACCESS,
key);
1362 err = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1363 "System\\CurrentControlSet\\Services\\TCPIP\\Parameters",
1364 0, KEY_ALL_ACCESS,
key);
1382 err = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
1383 "System\\CurrentControlSet\\Services\\TCPIP\\Parameters\\Interfaces",
1384 0, KEY_ALL_ACCESS, &itfs);
1387 err = RegOpenKeyExW(itfs, iid, 0, KEY_ALL_ACCESS,
key);
1397 *
key = INVALID_HANDLE_VALUE;
1413 err = RegGetValueA(
key, NULL,
"InitialSearchList", RRF_RT_REG_SZ, NULL, NULL, NULL);
1416 if (err == ERROR_FILE_NOT_FOUND)
1440 if (!list || wcslen(list) == 0)
1452 DWORD size = (wcslen(list) + 1) *
sizeof(*list);
1453 LSTATUS err = RegSetValueExW(
key, L
"InitialSearchList", 0, REG_SZ, (PBYTE)list, size);
1477 WCHAR list[2048] = {0};
1478 DWORD size =
sizeof(list);
1482 err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1495 size_t listlen = (size /
sizeof(list[0])) - 1;
1496 size_t domlen = wcslen(domains);
1497 if (listlen + domlen + 2 > _countof(list))
1505 PWSTR
pos = list + listlen;
1507 wcsncpy(
pos + 1, domains, domlen + 1);
1511 wcsncpy(list, domains, wcslen(domains) + 1);
1514 size = (wcslen(list) + 1) *
sizeof(list[0]);
1515 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1543 DWORD size =
sizeof(list);
1545 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, list, &size);
1548 if (err != ERROR_FILE_NOT_FOUND)
1556 size = (wcslen(list) + 1) *
sizeof(list[0]);
1557 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1565 RegDeleteValueA(
key,
"InitialSearchList");
1583 DWORD size =
sizeof(list);
1585 err = RegGetValueW(
key, NULL, L
"SearchList", RRF_RT_REG_SZ, NULL, list, &size);
1593 PWSTR dst = wcsstr(list, domains);
1601 size_t domlen = wcslen(domains);
1602 PCWSTR src = dst + domlen;
1604 dst = dst > list ? dst - 1 : dst;
1605 wmemmove(dst, src, domlen);
1607 size_t list_len = wcslen(list);
1611 WCHAR initial[2048];
1612 size =
sizeof(initial);
1613 err = RegGetValueW(
key, NULL, L
"InitialSearchList", RRF_RT_REG_SZ, NULL, initial, &size);
1622 if (wcsncmp(list, initial, wcslen(list)) == 0)
1629 size = (list_len + 1) *
sizeof(list[0]);
1630 err = RegSetValueExW(
key, L
"SearchList", 0, REG_SZ, (PBYTE)list, size);
1647 HKEY dns_searchlist_key;
1649 if (dns_searchlist_key != INVALID_HANDLE_VALUE)
1652 RegCloseKey(dns_searchlist_key);
1684 DWORD err = ERROR_OUTOFMEMORY;
1688 if (list_key == INVALID_HANDLE_VALUE)
1691 return ERROR_FILE_NOT_FOUND;
1705 if (domains && *domains)
1707 wchar_t *wide_domains =
utf8to16(domains);
1713 undo_data = malloc(
sizeof(*undo_data));
1717 wide_domains = NULL;
1721 undo_data->
domains = wide_domains;
1737 RegCloseKey(list_key);
1751 PCSTR itfs_key = family == AF_INET6
1752 ?
"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces"
1753 :
"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
1755 LSTATUS err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, itfs_key, 0, KEY_ALL_ACCESS,
key);
1758 *
key = INVALID_HANDLE_VALUE;
1760 __func__, family, err);
1763 return err ? FALSE : TRUE;
1783 return ERROR_FILE_NOT_FOUND;
1786 HKEY itf = INVALID_HANDLE_VALUE;
1787 err = RegOpenKeyExW(itfs, itf_id, 0, KEY_ALL_ACCESS, &itf);
1791 __func__, itf_id, family, err);
1795 err = RegSetValueExA(itf,
"NameServer", 0, REG_SZ, (PBYTE)value, strlen(value) + 1);
1799 __func__, value, itf_id, family, err);
1803 if (itf != INVALID_HANDLE_VALUE)
1807 if (itfs != INVALID_HANDLE_VALUE)
1848 int addr_len =
msg->addr_len;
1851 const size_t max_addrs = _countof(
msg->addr);
1852 if (addr_len > max_addrs)
1854 addr_len = max_addrs;
1857 if (!
msg->iface.name[0])
1865 msgptr->
iface.
name[_countof(
msg->iface.name)-1] =
'\0';
1866 msgptr->
domains[_countof(
msg->domains)-1] =
'\0';
1892 if (
msg->domains[0])
1901 if (
msg->addr_len > 0)
1906 CHAR addrs[_countof(
msg->addr) * 64];
1908 for (
int i = 0; i < addr_len; ++i)
1912 addrs[offset++] =
',';
1914 if (
msg->family == AF_INET6)
1916 RtlIpv6AddressToStringA(&
msg->addr[i].ipv6, addrs + offset);
1920 RtlIpv4AddressToStringA(&
msg->addr[i].ipv4, addrs + offset);
1922 offset += strlen(addrs);
1931 wchar_t *tmp_iid = _wcsdup(iid);
1932 if (!tmp_iid ||
AddListItem(&(*lists)[undo_type], tmp_iid))
1936 return ERROR_OUTOFMEMORY;
1941 if (
msg->domains[0])
1955 int addr_len =
msg->addr_len;
1958 if (addr_len > _countof(
msg->addr))
1960 addr_len = _countof(
msg->addr);
1963 if (!
msg->iface.name[0])
1971 msgptr->
iface.
name[_countof(
msg->iface.name) - 1] =
'\0';
1977 return ERROR_OUTOFMEMORY;
1998 for (
int i = 0; i < addr_len; ++i)
2000 RtlIpv4AddressToStringW(&
msg->addr[i].ipv4, addr);
2015 wchar_t *tmp_name = _wcsdup(wide_name);
2020 err = ERROR_OUTOFMEMORY;
2034 DWORD timeout = 5000;
2035 wchar_t argv0[MAX_PATH];
2038 swprintf(argv0, _countof(argv0), L
"%ls\\%ls",
get_win_sys_path(), L
"netsh.exe");
2043 const wchar_t *fmt = L
"netsh interface ipv4 set address name=\"%d\" source=dhcp";
2048 size_t ncmdline = wcslen(fmt) + 10 + 1;
2049 wchar_t *cmdline = malloc(ncmdline*
sizeof(
wchar_t));
2052 err = ERROR_OUTOFMEMORY;
2056 swprintf(cmdline, ncmdline, fmt,
dhcp->iface.index);
2071 DWORD err = ERROR_SUCCESS;
2073 if (!DuplicateHandle(ovpn_proc, orig_handle, GetCurrentProcess(), new_handle, 0, FALSE, DUPLICATE_SAME_ACCESS))
2075 err = GetLastError();
2086 DWORD err = ERROR_SUCCESS;
2088 HANDLE dup_handle = NULL;
2091 if (err != ERROR_SUCCESS)
2095 *ring = (
struct tun_ring *)MapViewOfFile(dup_handle, FILE_MAP_ALL_ACCESS, 0, 0,
sizeof(
struct tun_ring));
2099 err = GetLastError();
2115 if (ring_buffer_maps)
2119 else if ((ring_buffer_maps = calloc(1,
sizeof(*ring_buffer_maps))) == NULL)
2121 return ERROR_OUTOFMEMORY;
2124 HANDLE device = NULL;
2125 HANDLE send_tail_moved = NULL;
2126 HANDLE receive_tail_moved = NULL;
2129 if (err != ERROR_SUCCESS)
2135 if (err != ERROR_SUCCESS)
2141 if (err != ERROR_SUCCESS)
2147 if (err != ERROR_SUCCESS)
2153 if (err != ERROR_SUCCESS)
2160 send_tail_moved, receive_tail_moved))
2162 err = GetLastError();
2170 if (err != ERROR_SUCCESS && ring_buffer_maps)
2173 free(ring_buffer_maps);
2185 MIB_IPINTERFACE_ROW ipiface;
2186 InitializeIpInterfaceEntry(&ipiface);
2187 ipiface.Family = mtu->
family;
2189 err = GetIpInterfaceEntry(&ipiface);
2190 if (err != NO_ERROR)
2194 if (mtu->
family == AF_INET)
2196 ipiface.SitePrefixLength = 0;
2198 ipiface.NlMtu = mtu->
mtu;
2200 err = SetIpInterfaceEntry(&ipiface);
2206 DWORD bytes, DWORD count, LPHANDLE events,
undo_lists_t *lists)
2212 .size =
sizeof(ack),
2226 switch (
msg.header.type)
2230 if (
msg.header.size ==
sizeof(
msg.address))
2238 if (
msg.header.size ==
sizeof(
msg.route))
2245 if (
msg.header.size ==
sizeof(
msg.flush_neighbors))
2253 if (
msg.header.size ==
sizeof(
msg.wfp_block))
2274 if (
msg.header.size ==
sizeof(
msg.dhcp))
2281 if (
msg.header.size ==
sizeof(
msg.rrb))
2288 if (
msg.header.size ==
sizeof(
msg.mtu))
2367 *pnext = item->
next;
2378 HANDLE ovpn_pipe = NULL, svc_pipe = NULL;
2379 PTOKEN_USER svc_user = NULL, ovpn_user = NULL;
2380 HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL;
2381 HANDLE stdin_read = NULL, stdin_write = NULL;
2382 HANDLE stdout_write = NULL;
2383 DWORD pipe_mode, len, exit_code = 0;
2385 STARTUPINFOW startup_info;
2386 PROCESS_INFORMATION proc_info;
2387 LPVOID user_env = NULL;
2388 WCHAR ovpn_pipe_name[256];
2390 WCHAR *cmdline = NULL;
2391 size_t cmdline_size;
2393 WCHAR errmsg[512] = L
"";
2395 SECURITY_ATTRIBUTES inheritable = {
2396 .nLength =
sizeof(inheritable),
2397 .lpSecurityDescriptor = NULL,
2398 .bInheritHandle = TRUE
2402 EXPLICIT_ACCESS ea[2];
2403 SECURITY_DESCRIPTOR ovpn_sd;
2404 SECURITY_ATTRIBUTES ovpn_sa = {
2405 .nLength =
sizeof(ovpn_sa),
2406 .lpSecurityDescriptor = &ovpn_sd,
2407 .bInheritHandle = FALSE
2410 ZeroMemory(&ea,
sizeof(ea));
2411 ZeroMemory(&startup_info,
sizeof(startup_info));
2412 ZeroMemory(&undo_lists,
sizeof(undo_lists));
2413 ZeroMemory(&proc_info,
sizeof(proc_info));
2420 if (!InitializeSecurityDescriptor(&ovpn_sd, SECURITY_DESCRIPTOR_REVISION))
2427 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &svc_token))
2433 while (!GetTokenInformation(svc_token, TokenUser, svc_user, len, &len))
2435 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2441 svc_user = malloc(len);
2442 if (svc_user == NULL)
2448 if (!IsValidSid(svc_user->User.Sid))
2454 if (!ImpersonateNamedPipeClient(pipe))
2459 if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &imp_token))
2465 while (!GetTokenInformation(imp_token, TokenUser, ovpn_user, len, &len))
2467 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2473 ovpn_user = malloc(len);
2474 if (ovpn_user == NULL)
2480 if (!IsValidSid(ovpn_user->User.Sid))
2501 ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
2502 ea[0].grfAccessMode = SET_ACCESS;
2503 ea[0].grfInheritance = NO_INHERITANCE;
2504 ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
2505 ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
2506 ea[0].Trustee.ptstrName = (LPWSTR) svc_user->User.Sid;
2507 ea[1].grfAccessPermissions = READ_CONTROL | SYNCHRONIZE | PROCESS_VM_READ
2508 |SYNCHRONIZE | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION;
2509 ea[1].grfAccessMode = SET_ACCESS;
2510 ea[1].grfInheritance = NO_INHERITANCE;
2511 ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
2512 ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
2513 ea[1].Trustee.ptstrName = (LPWSTR) ovpn_user->User.Sid;
2516 if (!SetSecurityDescriptorOwner(&ovpn_sd, svc_user->User.Sid, FALSE))
2521 if (SetEntriesInAcl(2, ea, NULL, &ovpn_dacl) != ERROR_SUCCESS)
2526 if (!SetSecurityDescriptorDacl(&ovpn_sd, TRUE, ovpn_dacl, FALSE))
2533 if (!DuplicateTokenEx(imp_token, TOKEN_ALL_ACCESS, NULL, 0, TokenPrimary, &pri_token))
2540 stdout_write = CreateFile(
_L(
"NUL"), GENERIC_WRITE, FILE_SHARE_WRITE,
2541 &inheritable, OPEN_EXISTING, 0, NULL);
2542 if (stdout_write == INVALID_HANDLE_VALUE)
2548 if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0)
2549 || !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0))
2555 swprintf(ovpn_pipe_name, _countof(ovpn_pipe_name),
2557 ovpn_pipe = CreateNamedPipe(ovpn_pipe_name,
2558 PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
2559 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 128, 128, 0, NULL);
2560 if (ovpn_pipe == INVALID_HANDLE_VALUE)
2566 svc_pipe = CreateFile(ovpn_pipe_name, GENERIC_READ | GENERIC_WRITE, 0,
2567 &inheritable, OPEN_EXISTING, 0, NULL);
2568 if (svc_pipe == INVALID_HANDLE_VALUE)
2574 pipe_mode = PIPE_READMODE_MESSAGE;
2575 if (!SetNamedPipeHandleState(svc_pipe, &pipe_mode, NULL, NULL))
2581 cmdline_size = wcslen(sud.
options) + 128;
2582 cmdline = malloc(cmdline_size *
sizeof(*cmdline));
2583 if (cmdline == NULL)
2591 swprintf(cmdline, cmdline_size, L
"openvpn %ls --msg-channel %" PRIuPTR,
2592 sud.
options, (uintptr_t)svc_pipe);
2594 if (!CreateEnvironmentBlock(&user_env, imp_token, FALSE))
2600 startup_info.cb =
sizeof(startup_info);
2601 startup_info.dwFlags = STARTF_USESTDHANDLES;
2602 startup_info.hStdInput = stdin_read;
2603 startup_info.hStdOutput = stdout_write;
2604 startup_info.hStdError = stdout_write;
2609 if (!CreateProcessAsUserW(pri_token, exe_path, cmdline, &ovpn_sa, NULL, TRUE,
2611 user_env, sud.
directory, &startup_info, &proc_info))
2617 if (!RevertToSelf())
2619 TerminateProcess(proc_info.hProcess, 1);
2630 DWORD input_size = WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, NULL, 0, NULL, NULL);
2632 if (input_size && (input = malloc(input_size)))
2635 WideCharToMultiByte(CP_UTF8, 0, sud.
std_input, -1, input, input_size, NULL, NULL);
2636 WriteFile(stdin_write, input, (DWORD)strlen(input), &written, NULL);
2651 MsgToEventLog(
MSG_FLAGS_ERROR, L
"OpenVPN process sent too large payload length to the pipe (%lu bytes), it will be terminated", bytes);
2658 WaitForSingleObject(proc_info.hProcess,
IO_TIMEOUT);
2659 GetExitCodeProcess(proc_info.hProcess, &exit_code);
2660 if (exit_code == STILL_ACTIVE)
2662 TerminateProcess(proc_info.hProcess, 1);
2664 else if (exit_code != 0)
2667 swprintf(buf, _countof(buf),
2668 L
"OpenVPN exited with error: exit code = %lu", exit_code);
2674 FlushFileBuffers(pipe);
2675 DisconnectNamedPipe(pipe);
2680 DestroyEnvironmentBlock(user_env);
2701 SERVICE_STATUS *
status = ctx;
2704 case SERVICE_CONTROL_STOP:
2705 status->dwCurrentState = SERVICE_STOP_PENDING;
2713 case SERVICE_CONTROL_INTERROGATE:
2717 return ERROR_CALL_NOT_IMPLEMENTED;
2731 const WCHAR *sddlString = 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)";
2733 PSECURITY_DESCRIPTOR sd = NULL;
2734 if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddlString, SDDL_REVISION_1, &sd, NULL))
2737 return INVALID_HANDLE_VALUE;
2741 SECURITY_ATTRIBUTES sa = {0};
2742 sa.nLength =
sizeof(SECURITY_ATTRIBUTES);
2743 sa.lpSecurityDescriptor = sd;
2744 sa.bInheritHandle = FALSE;
2746 DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED;
2748 static BOOL first = TRUE;
2751 flags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
2755 WCHAR pipe_name[256];
2757 HANDLE pipe = CreateNamedPipe(pipe_name, flags,
2758 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
2759 PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, &sa);
2763 if (pipe == INVALID_HANDLE_VALUE)
2766 return INVALID_HANDLE_VALUE;
2777 static DWORD size = 10;
2778 static LPHANDLE handles = NULL;
2781 if (handles == NULL)
2783 handles = malloc(size *
sizeof(HANDLE));
2784 *handles_ptr = handles;
2785 if (handles == NULL)
2787 return ERROR_OUTOFMEMORY;
2791 handles[
pos++] = io_event;
2804 tmp = realloc(handles, size *
sizeof(HANDLE));
2809 return ERROR_OUTOFMEMORY;
2812 *handles_ptr = handles;
2814 handles[
pos++] = threads->
data;
2815 threads = threads->
next;
2839 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
2857 if (
key != INVALID_HANDLE_VALUE)
2875 HANDLE pipe, io_event = NULL;
2876 OVERLAPPED overlapped;
2877 DWORD error = NO_ERROR;
2879 PHANDLE handles = NULL;
2888 status.dwCurrentState = SERVICE_START_PENDING;
2889 status.dwServiceSpecificExitCode = NO_ERROR;
2890 status.dwWin32ExitCode = NO_ERROR;
2891 status.dwWaitHint = 3000;
2899 if (error != ERROR_SUCCESS)
2905 exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
2920 if (error != NO_ERROR)
2926 if (pipe == INVALID_HANDLE_VALUE)
2931 status.dwCurrentState = SERVICE_RUNNING;
2937 if (ConnectNamedPipe(pipe, &overlapped) == FALSE
2938 && GetLastError() != ERROR_PIPE_CONNECTED
2939 && GetLastError() != ERROR_IO_PENDING)
2945 error = WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
2946 if (error == WAIT_OBJECT_0)
2950 HANDLE thread = CreateThread(NULL, 0,
RunOpenvpn, pipe, CREATE_SUSPENDED, NULL);
2964 TerminateThread(thread, 1);
2970 ResumeThread(thread);
2984 if (error == WAIT_FAILED)
3014 status.dwCurrentState = SERVICE_STOPPED;
3015 status.dwWin32ExitCode = error;