From patchwork Thu Apr 12 09:39:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Rozman X-Patchwork-Id: 295 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director9.mail.ord1d.rsapps.net ([172.28.255.1]) by backend30.mail.ord1d.rsapps.net (Dovecot) with LMTP id W6a7GES2z1pDVwAAIUCqbw for ; Thu, 12 Apr 2018 15:40:52 -0400 Received: from director3.mail.ord1c.rsapps.net ([172.28.255.1]) by director9.mail.ord1d.rsapps.net (Dovecot) with LMTP id w1CBGES2z1qjQAAAalYnBA ; Thu, 12 Apr 2018 15:40:52 -0400 Received: from smtp19.gate.ord1c ([172.28.255.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by director3.mail.ord1c.rsapps.net with LMTP id UCTDGES2z1pVEQAAdSFV8w ; Thu, 12 Apr 2018 15:40:52 -0400 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO X-Virus-Scanned: OK X-Orig-To: openvpnslackdevel@openvpn.net X-Originating-Ip: [216.105.38.7] Authentication-Results: smtp19.gate.ord1c.rsapps.net; iprev=pass policy.iprev="216.105.38.7"; spf=pass smtp.mailfrom="openvpn-devel-bounces@lists.sourceforge.net" smtp.helo="lists.sourceforge.net"; dkim=fail (signature verification failed) header.d=sourceforge.net; dkim=fail (signature verification failed) header.d=sf.net; dmarc=fail (p=none; dis=none) header.from=rozman.si X-Suspicious-Flag: YES X-Classification-ID: 6722cc0c-3e89-11e8-8468-bc305bf036e4-1-1 Received: from [216.105.38.7] ([216.105.38.7:7447] helo=lists.sourceforge.net) by smtp19.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.1.56364 r(Core:4.2.1.14)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 04/62-14282-246BFCA5; Thu, 12 Apr 2018 15:40:50 -0400 Received: from [127.0.0.1] (helo=sfs-ml-1.v29.lw.sourceforge.com) by sfs-ml-1.v29.lw.sourceforge.com with esmtp (Exim 4.90_1) (envelope-from ) id 1f6i4k-00039E-Pn; Thu, 12 Apr 2018 19:40:06 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-1.v29.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1f6i4i-000395-NU for openvpn-devel@lists.sourceforge.net; Thu, 12 Apr 2018 19:40:04 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=References:In-Reply-To:Message-Id:Date:Subject:Cc: To:From:Sender:Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=QhAp9qHS1pUgdsgH/wF+HN1V9WPOd7r4FNqrCFO9A4U=; b=SkJEdoJn1bFvjgGEoO4qaOsXUJ jWz91nV/vhuvDW1pPvHnkeu0lEzmNGjsvDXkipgzfrdKz3PqCH3s0Dv54u4sGimrEfxQ9DMVluDHy ADQXHRMFcJp0Rf1jw7wcyHKT4uivhx3ONX7eqEojGMAWjlbdg7LVnyjwI3kgXdDAoTyY=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To :MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=QhAp9qHS1pUgdsgH/wF+HN1V9WPOd7r4FNqrCFO9A4U=; b=Tv7cKj+BlhN2ZX/U/fytGqIyy2 qCm5bzbcCiEkUK022x12H8fkFcRo5aBIAw3GYqao03zbVyhVabeTkjc6J8BdrNb2ZBas3HAavMMB0 zCAkH88QtGzSo+FhX7XvhbLzqkIVkxTjnD0pf7p4wTdBq5VBjYwHCyvNrBVd/uxYzJ6I=; Received: from [213.250.22.160] (helo=iMac.selo.doma) by sfi-mx-3.v28.lw.sourceforge.com with esmtp (Exim 4.90_1) id 1f6i4f-008d3v-W4 for openvpn-devel@lists.sourceforge.net; Thu, 12 Apr 2018 19:40:04 +0000 Received: by iMac.selo.doma (Postfix, from userid 698428175) id 13043519F10; Thu, 12 Apr 2018 21:39:53 +0200 (CEST) From: Simon Rozman To: openvpn-devel@lists.sourceforge.net Date: Thu, 12 Apr 2018 21:39:51 +0200 Message-Id: <20180412193951.1447-1-simon@rozman.si> X-Mailer: git-send-email 2.15.1 (Apple Git-101) In-Reply-To: <20180412184845.1175-1-simon@rozman.si> References: <20180412184845.1175-1-simon@rozman.si> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.4 NO_DNS_FOR_FROM DNS: Envelope sender has no MX or A DNS records 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 1.0 RDNS_NONE Delivered to internal network by a host with no rDNS X-Headers-End: 1f6i4f-008d3v-W4 Subject: [Openvpn-devel] [PATCH v2] Add Interactive Service developer documentation X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox The OpenVPN Interactive Service documentation from https://community.openvpn.net/openvpn/wiki/OpenVPNInteractiveService was upgraded with a description of the client-service communication flow, service registry configuration, and non-default instance installation. --- doc/Makefile.am | 2 +- doc/interactive-service-notes.txt | 316 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 317 insertions(+), 1 deletion(-) create mode 100644 doc/interactive-service-notes.txt -- 2.15.1 (Apple Git-101) Hi, I forgot to update the doc/Makefile.am in the original version of this patch. Perhaps this is not relevant anyway. So, feel free to discard the v2 version of this patch if the update to doc/Makefile.am is not required or desired. Best regards, Simon ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot diff --git a/doc/Makefile.am b/doc/Makefile.am index cd1bcfdf..4e307c4b 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -17,6 +17,7 @@ CLEANFILES = openvpn.8.html SUBDIRS = doxygen dist_doc_DATA = \ + interactive-service-notes.txt \ management-notes.txt dist_noinst_DATA = \ @@ -30,4 +31,3 @@ openvpn.8.html: $(srcdir)/openvpn.8 else dist_man_MANS = openvpn.8 endif - diff --git a/doc/interactive-service-notes.txt b/doc/interactive-service-notes.txt new file mode 100644 index 00000000..9b3b8f6c --- /dev/null +++ b/doc/interactive-service-notes.txt @@ -0,0 +1,316 @@ +================================= +OpenVPN Interactive Service Notes +================================= + + +Introduction +============ + +OpenVPN Interactive Service, also known as "iservice" or +"OpenVPNServiceInteractive", is a Windows system service which allows +unprivileged users to do certain privileged operations required by OpenVPN, such +as adding routes. This removes the need to always run OpenVPN as administrator, +which was the case for a long time, and continues to be the case for OpenVPN +2.3.x. + +The 2.4.x release and git "master" versions of OpenVPN contain the Interactive +Service code and OpenVPN-GUI is setup to use it by default. Starting from +version 2.4.0, OpenVPN-GUI is expected to be started as user (do not right-click +and "run as administrator" or do not set the shortcut to run as administrator). +This ensures that OpenVPN and the GUI run with limited privileges. + + +How It Works +============ + +Here is a brief explanation of how the Interactive Service works, based on +`Gert's email`_ to openvpn-devel mailing list. The example user, *joe*, is not +an administrator, and does not have any other extra privileges. + +- OpenVPN-GUI runs as a *joe* +- Interactive Service runs as a local Windows service with maximum privileges +- OpenVPN-GUI connects to the Interactive Service and asks it "run openvpn.exe + with the following arguments, using the *joe*'s credentials" - Windows can do + this - pass credentials across a pipe, which you can't fake +- Interactive Service forks openvpn.exe, and runs this as the user *joe*, and + keeps a "service pipe" between Interactive Service and openvpn.exe +- If openvpn.exe wants to do ipconfig/route/dns stuff, it sends these as + requests over the service pipe to the Interactive Service, which will then + execute them (and clean up should openvpn.exe crash) +- ``--up`` scripts are run by openvpn.exe itself, which is already running as + *joe*, all privileges are nicely in place +- Scripts run by the GUI will run as user *joe*, so that automated tasks like + mapping of drives work as expected + +This also avoids the use of scripts for privilege escalation to admin (as was +possible by running an ``--up`` script from openvpn.exe which is run as admin). + + +Client-Service Communication +============================ + +Connecting +---------- + +The client (OpenVPN GUI) and the Interactive Service communicate using a named +message pipe. By default, the service provides the ``\\.\pipe\openvpn\service`` +named pipe. + +The client connects to the pipe for read/write and sets the pipe state to the +``PIPE_READMODE_MESSAGE``:: + + HANDLE pipe = CreateFile(_T("\\\\.\\pipe\\openvpn\\service"), + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL); + + if (pipe == INVALID_HANDLE_VALUE) + { + // Error + } + + DWORD dwMode = PIPE_READMODE_MESSAGE; + if (!SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL) + { + // Error + } + + +openvpn.exe Startup +------------------- + +After the client is connected to the service, the client must send a startup +message to have the service start the openvpn.exe process. The startup message +is comprised of three UTF-16 strings delimited by U0000 zero characters:: + + startupmsg = workingdir WZERO openvpnoptions WZERO stdin WZERO + + workingdir = WSTRING + openvpnoptions = WSTRING + stdin = WSTRING + + WSTRING = *WCHAR + WCHAR = %x0001-FFFF + WZERO = %x0000 + +``workingdir`` + Represents the folder openvpn.exe process should be started in. + +``openvpnoptions`` + String contains ``--config`` and other OpenVPN command line options, without + the ``argv[0]`` executable name ("openvpn" or "openvpn.exe"). When there is + only one option specified, the ``--config`` option is assumed and the option + is the configuration filename. + + Please, note that the interactive service validates the options (e.g. OpenVPN + config file must reside in one of the approved folders, or the invoking user + must be a member of local Administrators group, or a member of the + "OpenVPN Administrators" group). + +``stdin`` + The content of the ``stdin`` string is sent to the openvpn.exe process to its + stdin stream after it starts. + + When a ``--management ... stdin`` option is present, the openvpn.exe process + will prompt for the management interface password on start. In this case, the + ``stdin`` must contain the password appended with an LF (U000A) to simulate + the [Enter] key after the password is "typed" in. + + The openvpn.exe's stdout is redirected to ``NUL``. Should the client require + openvpn.exe's stdout, one should specify ``--log`` option. + +The message must be written in a single ``WriteFile()`` call. + +Example:: + + // Prepare the message. + size_t msg_len = + wcslen(workingdir) + 1 + + wcslen(options ) + 1 + + wcslen(manage_pwd) + 1; + wchar_t *msg_data = (wchar_t*)malloc(msg_len*sizeof(wchar_t)); + _snwprintf(msg_data, msg_len, L"%s%c%s%c%s", + workingdir, L'\0', + options, L'\0', + manage_pwd) + + // Send the message. + DWORD dwBytesWritten; + if (!WriteFile(pipe, + msg_data, + msg_len*sizeof(wchar_t), + &dwBytesWritten, + NULL)) + { + // Error + } + + // Sanitize memory, since the stdin component of the message + // contains the management interface password. + SecureZeroMemory(msg_data, msg_len*sizeof(wchar_t)); + free(msg_data); + + +openvpn.exe Process ID +---------------------- + +After receiving the startup message, the Interactive Service validates the user +and specified options before launching the openvpn.exe process. + +The Interactive Service replies with a process ID message. The process ID +message is comprised of three UTF-16 strings delimited by LFs (U000A):: + + pidmsg = L"0x00000000" WLF L"0x" pid WLF L"Process ID" + + pid = 8*8WHEXDIG + + WHEXDIG = WDIGIT / L"A" / L"B" / L"C" / L"D" / L"E" / L"F" + WDIGIT = %x0030-0039 + WLF = %x000a + +``pid`` + An UTF-16 eight-character hexadecimal process ID of the openvpn.exe process + the Interactive Service launched on client's behalf. + + +openvpn.exe Termination +----------------------- + +The pipe between the client and the service is kept open until the openvpn.exe +process terminates. + +Should the openvpn.exe process terminate with an error, the Interactive Service +sends an error message to the client before disconnecting the pipe. + + +Error Messages +-------------- + +In case of an error, the Interactive Service sends an error message to the +client. Error messages are comprised of three UTF-16 strings delimited by LFs +(U000A):: + + errmsg = L"0x" errnum WLF func WLF msg + + errnum = 8*8WHEXDIG + func = WSTRING + msg = WSTRING + +``errnum`` + + An UTF-16 eight-character hexadecimal error code. Typically, it is one of the + Win32 error codes returned by ``GetLastError()``. + + However, it can be one of the Interactive Service specific error codes: + + ===================== ========== + Error Code + ===================== ========== + ERROR_OPENVPN_STARTUP 0x20000000 + ERROR_STARTUP_DATA 0x20000001 + ERROR_MESSAGE_DATA 0x20000002 + ERROR_MESSAGE_TYPE 0x20000003 + ===================== ========== + +``func`` + The name of the function call that failed or an error description. + +``msg`` + The error description returned by a + ``FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, 0, errnum, ...)`` call. + + +Interactive Service Configuration +================================= + +The Interactive Service settings are read from the +``HKEY_LOCAL_MACHINE\SOFTWARE\OpenVPN`` registry key by default. + +All the following registry values are of the ``REG_SZ`` type: + +*Default* + Installation folder (required) + +``exe_path`` + The absolute path to the openvpn.exe binary; defaults to + ``install_dir "\bin\openvpn.exe"``. + +``config_dir`` + The path to the configuration folder; defaults to ``install_dir "\config"``. + +``priority`` + openvpn.exe process priority; one of the following strings: + + - ``"IDLE_PRIORITY_CLASS"`` + - ``"BELOW_NORMAL_PRIORITY_CLASS"`` + - ``"NORMAL_PRIORITY_CLASS"`` (default) + - ``"ABOVE_NORMAL_PRIORITY_CLASS"`` + - ``"HIGH_PRIORITY_CLASS"`` + +``ovpn_admin_group`` + The name of the local group, whose members are authorized to use the + Interactive Service unrestricted; defaults to ``"OpenVPN Administrators"`` + + +Multiple Interactive Service Instances +====================================== + +OpenVPN 2.4.5 extended the Interactive Service to support multiple side-by-side +running instances. This allows clients to use different Interactive Service +versions with different settings and/or openvpn.exe binary version on the same +computer. + +OpenVPN installs the default Interactive Service instance only. The default +instance is used by OpenVPN GUI client and also provides backward compatibility. + + +Installing a Non-default Interactive Service Instance +----------------------------------------------------- + +1. Choose a unique instance name. For example: "$v2.5-test". The instance name + is appended to the default registry path and service name. We choose to start + it with a dollar "$" sign analogous to Microsoft SQL Server instance naming + scheme. However, this is not imperative. + + Appending the name to the registry path and service name also implies the + name cannot contain characters not allowed in Windows paths: "<", ">", double + quote etc. + +2. Create an ``HKEY_LOCAL_MACHINE\SOFTWARE\OpenVPN$v2.5-test`` registry key and + configure the Interactive Service instance configuration appropriately. + + This allows using slightly or completely different settings from the default + instance. + + See the `Interactive Service Configuration`_ chapter for the list of registry + values. + +3. Create and start the instance's Windows service from an elevated command + prompt:: + + sc create "OpenVPNServiceInteractive$v2.5-test" \ + start= auto \ + binPath= " -instance interactive $v2.5-test" \ + depend= tap0901/Dhcp \ + DisplayName= "OpenVPN Interactive Service (v2.5-test)" + + sc start "OpenVPNServiceInteractive$v2.5-test" + + This allows using the same or a different version of openvpnserv.exe than the + default instance. + + Please, mind the spacing around "=" character in ``sc`` command line options. + +4. Set your OpenVPN client to connect to the + ``\\.\pipe\openvpn$v2.5-test\service``. + + This allows the client to select different installed Interactive Service + instance at run-time, thus allowing different OpenVPN settings and versions. + + At the time writing, the OpenVPN GUI client supports connecting to the + default Interactive Service instance only. + +.. _`Gert's email`: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg00097.html