diff --git a/openvpn/win/npinfo.hpp b/openvpn/win/npinfo.hpp
new file mode 100644
index 00000000..e151fbaa
--- /dev/null
+++ b/openvpn/win/npinfo.hpp
@@ -0,0 +1,165 @@
+// OpenVPN -- An application to securely tunnel IP networks
+// over a single port, with support for SSL/TLS-based
+// session authentication and key exchange,
+// packet encryption, packet authentication, and
+// packet compression.
+//
+// Copyright (C) 2012-2015 OpenVPN Technologies, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License Version 3
+// as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program in the COPYING file.
+// If not, see .
+
+// Get info about named pipe peer
+
+#ifndef OPENVPN_WIN_NPINFO_H
+#define OPENVPN_WIN_NPINFO_H
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+namespace openvpn {
+ namespace Win {
+ struct NamedPipePeerInfo
+ {
+ OPENVPN_EXCEPTION(npinfo_error);
+
+ // Servers must call this method to modify their process
+ // access rights to grant clients the
+ // PROCESS_QUERY_LIMITED_INFORMATION right, so that clients
+ // can validate the server's exe path via get_exe_path().
+ static void allow_client_query()
+ {
+ SecurityAttributes sa(
+ "D:" // discretionary ACL
+ "(A;OICI;0x1000;;;S-1-1-0)" // allow PROCESS_QUERY_LIMITED_INFORMATION access to Everyone
+ ,
+ false,
+ "client query");
+
+ ACL* dacl;
+ BOOL bDaclPresent, bDaclDefaulted;
+ if (!::GetSecurityDescriptorDacl(sa.sa.lpSecurityDescriptor,
+ &bDaclPresent,
+ &dacl,
+ &bDaclDefaulted))
+ {
+ const Win::LastError err;
+ OPENVPN_THROW(npinfo_error, "allow_client_query: GetSecurityDescriptorDacl failed: " << err.message());
+ }
+ if (!bDaclPresent)
+ OPENVPN_THROW(npinfo_error, "allow_client_query: missing DACL");
+ const DWORD ssi_status = ::SetSecurityInfo(
+ GetCurrentProcess(),
+ SE_KERNEL_OBJECT,
+ DACL_SECURITY_INFORMATION,
+ NULL,
+ NULL,
+ dacl,
+ NULL);
+ if (ssi_status != ERROR_SUCCESS)
+ {
+ const Win::Error err(ssi_status);
+ OPENVPN_THROW(npinfo_error, "allow_client_query: SetSecurityInfo failed: " << err.message());
+ }
+ }
+
+ // Get PID of process at other end of named pipe
+ static ULONG get_pid(const HANDLE np_handle, const bool client)
+ {
+ ULONG pid = 0;
+ if (client)
+ {
+ if (!::GetNamedPipeClientProcessId(np_handle, &pid))
+ {
+ const Win::LastError err;
+ OPENVPN_THROW(npinfo_error, "GetNamedPipeClientProcessId failed: " << err.message());
+ }
+ }
+ else
+ {
+ if (!::GetNamedPipeServerProcessId(np_handle, &pid))
+ {
+ const Win::LastError err;
+ OPENVPN_THROW(npinfo_error, "GetNamedPipeServerProcessId failed: " << err.message());
+ }
+ }
+ return pid;
+ }
+
+ // Get process handle given PID.
+ static Win::ScopedHANDLE get_process(const ULONG pid, const bool limited)
+ {
+ // open process
+ Win::ScopedHANDLE proc(::OpenProcess(
+ limited ? PROCESS_QUERY_LIMITED_INFORMATION : PROCESS_ALL_ACCESS,
+ FALSE,
+ pid));
+ if (!proc.defined())
+ {
+ const Win::LastError err;
+ OPENVPN_THROW(npinfo_error, "OpenProcess failed: " << err.message());
+ }
+ return proc;
+ }
+
+ // Get exe path given process handle.
+ static std::wstring get_exe_path(const HANDLE proc)
+ {
+ // get exe path
+ const size_t exe_cap = 256;
+ wchar_t exe[exe_cap];
+ DWORD exe_size = exe_cap;
+ if (!::QueryFullProcessImageNameW(proc, 0, exe, &exe_size))
+ {
+ const Win::LastError err;
+ OPENVPN_THROW(npinfo_error, "QueryFullProcessImageName failed: " << err.message());
+ }
+ return std::wstring(exe, exe_size);
+ }
+ };
+
+ // Used by server to get info about clients
+ struct NamedPipePeerInfoClient : public NamedPipePeerInfo
+ {
+ NamedPipePeerInfoClient(const HANDLE handle)
+ {
+ const ULONG pid = get_pid(handle, true);
+ Win::ScopedHANDLE proc = get_process(pid, false);
+ exe_path = get_exe_path(proc());
+ }
+
+ std::wstring exe_path;
+ };
+
+ // Used by clients to get info about the server
+ struct NamedPipePeerInfoServer : public NamedPipePeerInfo
+ {
+ NamedPipePeerInfoServer(const HANDLE handle)
+ {
+ const ULONG pid = get_pid(handle, false);
+ Win::ScopedHANDLE proc = get_process(pid, true);
+ exe_path = get_exe_path(proc());
+ }
+
+ std::wstring exe_path;
+ };
+ }
+}
+
+#endif