From patchwork Thu Apr 12 08:48:45 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Rozman X-Patchwork-Id: 296 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director12.mail.ord1d.rsapps.net ([172.30.191.6]) by backend30.mail.ord1d.rsapps.net (Dovecot) with LMTP id 22UzDIy2z1rSPQAAIUCqbw for ; Thu, 12 Apr 2018 15:42:04 -0400 Received: from proxy9.mail.ord1d.rsapps.net ([172.30.191.6]) by director12.mail.ord1d.rsapps.net (Dovecot) with LMTP id 47bLC4y2z1rUGQAAIasKDg ; Thu, 12 Apr 2018 15:42:04 -0400 Received: from smtp3.gate.ord1c ([172.30.191.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy9.mail.ord1d.rsapps.net with LMTP id iE7DC4y2z1q+QgAA7h+8OQ ; Thu, 12 Apr 2018 15:42:04 -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: smtp3.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: 92a1ec8c-3e89-11e8-a85a-842b2b47481a-1-1 Received: from [216.105.38.7] ([216.105.38.7:31557] helo=lists.sourceforge.net) by smtp3.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 63/4B-30045-B86BFCA5; Thu, 12 Apr 2018 15:42:03 -0400 Received: from [127.0.0.1] (helo=sfs-ml-2.v29.lw.sourceforge.com) by sfs-ml-2.v29.lw.sourceforge.com with esmtp (Exim 4.90_1) (envelope-from ) id 1f6i4k-00036S-6u; Thu, 12 Apr 2018 19:40:06 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-2.v29.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1f6i4i-000361-QZ 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=g5e1SCSZn/+lDtWW6olr5uj74sua+eNAdW1QAmoGidQ=; b=ijxmAGgM3tQfDJU0TvzbMOw3+Z 7/8NFJptOVHPV1lvTbPuT5k0/Rw0RCsUzWLunDzWLYad544FOWx3DlLlzp06oR0mUU+EHGiZ3aR23 4t0rRQf8WHVgoGMiFXbAmgPVxrZCbO8wUJEj/a/1lixEb/sTGaqRoMd1EQA7+6s8tn2I=; 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=g5e1SCSZn/+lDtWW6olr5uj74sua+eNAdW1QAmoGidQ=; b=jG6MSDPoHE7Ef+Y7FxFs8kk+o4 ktMKpxknFNQBOEELdfWS+1+W/Ly0BtS6nskVDbo4+QyijFuwdXBNZZeMtiScLG6ZksNFtiBCA/69N McPS+D23D7m/wx7wcB1R1o280XA7JON08BZQna4Vhyj1WaXfJ/5wmUCLooki8tszssKE=; 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-008d3s-UT for openvpn-devel@lists.sourceforge.net; Thu, 12 Apr 2018 19:40:04 +0000 Received: by iMac.selo.doma (Postfix, from userid 698428175) id 15C23519077; Thu, 12 Apr 2018 20:49:19 +0200 (CEST) From: Simon Rozman To: openvpn-devel@lists.sourceforge.net Date: Thu, 12 Apr 2018 20:48:45 +0200 Message-Id: <20180412184845.1175-1-simon@rozman.si> X-Mailer: git-send-email 2.15.1 (Apple Git-101) In-Reply-To: References: 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-008d3s-UT Subject: [Openvpn-devel] [PATCH] 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/interactive-service-notes.txt | 316 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 316 insertions(+) create mode 100644 doc/interactive-service-notes.txt -- 2.15.1 (Apple Git-101) Hi, I'm back. :) I took the short Interactive Service introduction found at https://community.openvpn.net/openvpn/wiki/OpenVPNInteractiveService and extended it with my experience while developing the eduVPN client. This document is not up to the RFC standards nor it intends to be. It's written using reStructuredText markup as suggested by Iliya, but keeping the filename and ".txt" extension as suggested by Samuli. I suggest replacing the https://community.openvpn.net/openvpn/wiki/OpenVPNInteractiveService wiki page with this document analogous to the Management Interface Notes document published online at https://openvpn.net/index.php/open-source/documentation/miscellaneous/79-management-interface.html. Your comments are welcome. 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/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