From patchwork Mon Jan 25 01:56:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 1569 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director9.mail.ord1d.rsapps.net ([172.30.191.6]) by backend30.mail.ord1d.rsapps.net with LMTP id OJclEDTADmCRQgAAIUCqbw (envelope-from ) for ; Mon, 25 Jan 2021 07:57:24 -0500 Received: from proxy5.mail.ord1d.rsapps.net ([172.30.191.6]) by director9.mail.ord1d.rsapps.net with LMTP id kA0CEDTADmB+YgAAalYnBA (envelope-from ) for ; Mon, 25 Jan 2021 07:57:24 -0500 Received: from smtp2.gate.ord1c ([172.30.191.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy5.mail.ord1d.rsapps.net with LMTPS id mL6KDzTADmA+dgAA8Zzt7w (envelope-from ) for ; Mon, 25 Jan 2021 07:57:24 -0500 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: smtp2.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=none (p=nil; dis=none) header.from=rfc2549.org X-Suspicious-Flag: YES X-Classification-ID: ddd209ca-5f0c-11eb-bbbc-842b2b4e7063-1-1 Received: from [216.105.38.7] ([216.105.38.7:40758] helo=lists.sourceforge.net) by smtp2.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 68/38-04541-330CE006; Mon, 25 Jan 2021 07:57:23 -0500 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 1l41QD-0004rH-LE; Mon, 25 Jan 2021 12:56:45 +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 1l41QC-0004qR-3L for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:44 +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:To: From:Sender:Reply-To:Cc: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=pbSKN4R4pHmGXZWrSFy3cHnPIZDYJzcUyCWP7FsgAD8=; b=HxDoj9WZ3af5CwtNoRtKOnmmjJ fSHcKd5g5VjlotCDLGrKgW6qiOyKAs14lRUloBBd16DpOa4seF5BooAYsrfJAzTiimOeFo+sDL4ze Q/dLCBoYaTPB8jcBK4CT3ysiVs2heTMPECypTEK0ESGM4pkPgxjJ3nTDIPROmwqso8w4=; 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:To:From:Sender:Reply-To:Cc :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=pbSKN4R4pHmGXZWrSFy3cHnPIZDYJzcUyCWP7FsgAD8=; b=dr2K8S1vqguWwzitlBWTzMFD6e WsuGqLA2L+grD3PMsk9IVllTr3erQ8mO2lZ7470Lu01yREhdXVJBhM+3X9VX28zvjC9wkhpuEt5dM 3pJWFmewuoaZYUltFGZQiJg0b/pXVHJNJHvvReBBUK9SaQhFX9tcabpuajIGlf0dMM1Q=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.2) id 1l41Q3-002esn-WE for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:43 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.94 (FreeBSD)) (envelope-from ) id 1l41Pw-0007Wr-Ni for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 13:56:28 +0100 Received: (nullmailer pid 30411 invoked by uid 10006); Mon, 25 Jan 2021 12:56:28 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Mon, 25 Jan 2021 13:56:18 +0100 Message-Id: <20210125125628.30364-2-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210125125628.30364-1-arne@rfc2549.org> References: <20210125125628.30364-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 0.0 SPF_NONE SPF: sender does not publish an SPF Record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record X-Headers-End: 1l41Q3-002esn-WE Subject: [Openvpn-devel] [PATCH v2 01/11] Change pull request timeout use a timeout rather than a number 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 This commit changes the count n_sent_push_requests to time_t based push_request_timeout. This is more in line to our other timeouts which are also time based instead of number retries based. This does not change the behaviour but it prepares allowing to extend the pull request timeout during a pending authentication. As a user visible change we print the the time we waited for a timeout instead Also update the man page to actually document that hand-window controls this timeout. Patch V2: grammar fix in manual page Signed-off-by: Arne Schwabe Acked-by: Lev Stipakov --- doc/man-sections/tls-options.rst | 3 +++ src/openvpn/forward.c | 1 + src/openvpn/openvpn.h | 2 +- src/openvpn/push.c | 9 ++++++--- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/doc/man-sections/tls-options.rst b/doc/man-sections/tls-options.rst index 28cf6f1e..e13fb3c8 100644 --- a/doc/man-sections/tls-options.rst +++ b/doc/man-sections/tls-options.rst @@ -200,6 +200,9 @@ certificates and keys: https://github.com/OpenVPN/easy-rsa will still use our expiring key for up to ``--tran-window`` seconds to maintain continuity of transmission of tunnel data. + The ``--hand-window`` parameter also controls the amount of time that + the OpenVPN client repeats the pull request until it times out. + --key file Local peer's private key in .pem format. Use the private key which was generated when you built your peer's certificate (see ``--cert file`` diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 67615a6b..76f5a032 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -299,6 +299,7 @@ check_connection_established(struct context *c) } #endif /* fire up push request right away (already 1s delayed) */ + c->c2.push_request_timeout = now + c->options.handshake_window; event_timeout_init(&c->c2.push_request_interval, 0, now); reset_coarse_timers(c); } diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index 4ca89ba9..e9bc7dad 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -462,7 +462,7 @@ struct context_2 enum client_connect_status context_auth; struct event_timeout push_request_interval; - int n_sent_push_requests; + time_t push_request_timeout; bool did_pre_pull_restore; /* hash of pulled options, so we can compare when options change */ diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 26a6201f..fb6b9d17 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -369,14 +369,17 @@ cleanup: bool send_push_request(struct context *c) { - const int max_push_requests = c->options.handshake_window / PUSH_REQUEST_INTERVAL; - if (++c->c2.n_sent_push_requests <= max_push_requests) + struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE]; + struct key_state *ks = &session->key[KS_PRIMARY]; + + if (c->c2.push_request_timeout > now) { return send_control_channel_string(c, "PUSH_REQUEST", D_PUSH); } else { - msg(D_STREAM_ERRORS, "No reply from server after sending %d push requests", max_push_requests); + msg(D_STREAM_ERRORS, "No reply from server to push requests in %ds", + (int)(now - ks->established)); c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- server-pushed connection reset */ c->sig->signal_text = "no-push-reply"; return false; From patchwork Mon Jan 25 01:56:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 1575 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director14.mail.ord1d.rsapps.net ([172.28.255.1]) by backend30.mail.ord1d.rsapps.net with LMTP id WFJ7JUPADmCRQgAAIUCqbw (envelope-from ) for ; Mon, 25 Jan 2021 07:57:39 -0500 Received: from proxy2.mail.ord1c.rsapps.net ([172.28.255.1]) by director14.mail.ord1d.rsapps.net with LMTP id SOZHJUPADmD5NwAAeJ7fFg (envelope-from ) for ; Mon, 25 Jan 2021 07:57:39 -0500 Received: from smtp18.gate.ord1c ([172.28.255.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy2.mail.ord1c.rsapps.net with LMTPS id aPb+JEPADmCwYAAA311kuQ (envelope-from ) for ; Mon, 25 Jan 2021 07:57:39 -0500 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: smtp18.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=none (p=nil; dis=none) header.from=rfc2549.org X-Suspicious-Flag: YES X-Classification-ID: e72f3498-5f0c-11eb-aef7-bc305bf00c68-1-1 Received: from [216.105.38.7] ([216.105.38.7:54886] helo=lists.sourceforge.net) by smtp18.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 3C/64-12733-340CE006; Mon, 25 Jan 2021 07:57:39 -0500 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 1l41QP-0006Ga-T4; Mon, 25 Jan 2021 12:56:57 +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 1l41QF-0006FB-3q for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:47 +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:To: From:Sender:Reply-To:Cc: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=Z+cqvvlq3jV3x7l+iQlRxh/XdvEUkGvygA0VIN2hme8=; b=KA5rSw5nrTrkgAlkT60r/LkZ31 y4nrVVCBa3V/1oVxA4tVKgh8cG7ZjldX1z6LWrxgCMUGKwDDGgbTyv3vnkCGmIbRY3SqZlCK9w5mh ES24Bw78ph49ljv6FHpw7KrFNB1laqcoty08RrC4HM70OnWsTFQnJJhHvbeTcTf10iio=; 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:To:From:Sender:Reply-To:Cc :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=Z+cqvvlq3jV3x7l+iQlRxh/XdvEUkGvygA0VIN2hme8=; b=Lsz0YvMYieYld70r920N45halu 9HOvNCBfZ4hDHOYMTVZ14EpPZ3WqrMLWw1Qfj58O+UP4zDERJ72lWKhCJU1oh8yte65+SOMndyxJ1 eglmELCoXAGGbBTKOct4Ed/THEzUQtTnp5zUH15dTWY3aeZ+7muyKlvxQy2hCSwO3JhE=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.2) id 1l41QB-002etP-9w for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:47 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.94 (FreeBSD)) (envelope-from ) id 1l41Pw-0007Wu-QM for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 13:56:28 +0100 Received: (nullmailer pid 30414 invoked by uid 10006); Mon, 25 Jan 2021 12:56:28 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Mon, 25 Jan 2021 13:56:19 +0100 Message-Id: <20210125125628.30364-3-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210125125628.30364-1-arne@rfc2549.org> References: <20210125125628.30364-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 0.0 SPF_NONE SPF: sender does not publish an SPF Record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record X-Headers-End: 1l41QB-002etP-9w Subject: [Openvpn-devel] [PATCH v2 02/11] Implement client side handling of AUTH_PENDING message 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 This allows a client to extend the timeout of pull-request response while waiting for the user to complete a pending authentication. A timeout of 60s for a normal authentication might still works for a simple 2FA (but still challenging). With a sophisticated (or overly complicated) web based authentication 60s are quite short. To avoid not detecting network problem in this phase, we use the constant sending of PUSH_REQUEST/AUTH_PENDING as keepalive signal and still timeout the session after the handshake window time. patch v2: typo fixes, invert if for sscanf Signed-off-by: Arne Schwabe Acked-by: Lev Stipakov --- doc/man-sections/server-options.rst | 4 ++ doc/management-notes.txt | 39 +++++++++++++---- src/openvpn/forward.c | 11 ++++- src/openvpn/integer.h | 25 +++++++++++ src/openvpn/push.c | 68 ++++++++++++++++++++++++++++- src/openvpn/push.h | 9 ++++ src/openvpn/ssl.c | 3 ++ src/openvpn/ssl.h | 3 ++ src/openvpn/ssl_common.h | 1 + 9 files changed, 152 insertions(+), 11 deletions(-) diff --git a/doc/man-sections/server-options.rst b/doc/man-sections/server-options.rst index 5a689452..271c54d0 100644 --- a/doc/man-sections/server-options.rst +++ b/doc/man-sections/server-options.rst @@ -473,6 +473,10 @@ fast hardware. SSL/TLS authentication must be used in this mode. - bit 1: The peer supports peer-id floating mechanism - bit 2: The client expects a push-reply and the server may send this reply without waiting for a push-request first. + - bit 3: The client is capable of doing key derivation using + RFC5705 key material exporter. + - bit 4: The client is capable of accepting additional arguments + to the `AUTH_PENDING` message. :code:`IV_NCP=2` Negotiable ciphers, client supports ``--cipher`` pushed by diff --git a/doc/management-notes.txt b/doc/management-notes.txt index 50f0f567..3aff6eb6 100644 --- a/doc/management-notes.txt +++ b/doc/management-notes.txt @@ -610,14 +610,30 @@ to signal a pending authenticating to the client. A pending auth means that the connecting requires extra authentication like a one time password or doing a single sign one via web. - client-pending-auth {CID} {EXTRA} - -The server will send AUTH_PENDING and INFO_PRE,{EXTRA} to the client. -The client is expected to inform the user that authentication is pending and -display the extra information. For the format of EXTRA see below -For the OpenVPN server this is stateless operation and needs to be -followed by a client-deny/client-auth[-nt] command (that is the result of the -out of band authentication). + client-pending-auth {CID} {EXTRA} {TIMEOUT} + +The server will send AUTH_PENDING and INFO_PRE,{EXTRA} to the client. If the +client supports accepting keywords to AUTH_PENDING (announced via IV_PROTO), +TIMEOUT parameter will be also be announced to the client to allow it to modify +its own timeout. The client is expected to inform the user that authentication +is pending and display the extra information and also show the user the +remaining time to complete the auth if applicable. + +Receiving an AUTH_PENDING message will make the client change its timeout to +the timeout proposed by the server, even if the timeout is shorter. +If the client does not receive a packet from the server for hand-window the +connection times out regardless of the timeout. This ensures that the connection +still times out relatively quickly in case of network problems. The client will +continously send PULL_REQUEST messages to the server until the timeout is reached. +This message also triggers an ACK message from the server that resets the +hand-window based timeout. + +Both client and server limit the maximum timeout to the smaller value of half the +--tls-reneg minimum time and --hand-window time (defaults to 60s). + +For the format of EXTRA see below. For the OpenVPN server this is a stateless +operation and needs to be followed by a client-deny/client-auth[-nt] command +(that is the result of the out of band authentication). Before issuing a client-pending-auth to a client instead of a client-auth/client-deny, the server should check the IV_SSO @@ -630,7 +646,7 @@ set setenv IV_SSO openurl,crtext The variable name IV_SSO is historic as AUTH_PENDING was first used -to signal single sign on support. To keep compatiblity with existing +to signal single sign on support. To keep compatibility with existing implementations the name IV_SSO is kept in lieu of a better name. openurl @@ -646,6 +662,11 @@ The space in a control message is limited, so this url should be kept short to avoid issues. If a loger url is required a URL that redirects to the longer URL should be sent instead. +A complete documentation how URLs should be handled on the client is available +in the openvpn3 repository: + +https://github.com/OpenVPN/openvpn3/blob/master/doc/webauth.md + url_proxy ======== To avoid issues with OpenVPN connection persist-tun and not able diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 76f5a032..2e1e1490 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -240,6 +240,10 @@ check_incoming_control_channel(struct context *c) { receive_cr_response(c, &buf); } + else if (buf_string_match_head_str(&buf, "AUTH_PENDING")) + { + receive_auth_pending(c, &buf); + } else { msg(D_PUSH_ERRORS, "WARNING: Received unknown control message: %s", BSTR(&buf)); @@ -299,7 +303,12 @@ check_connection_established(struct context *c) } #endif /* fire up push request right away (already 1s delayed) */ - c->c2.push_request_timeout = now + c->options.handshake_window; + /* We might receive a AUTH_PENDING request before we armed this + * timer. In that case we don't change the value */ + if (c->c2.push_request_timeout < now) + { + c->c2.push_request_timeout = now + c->options.handshake_window; + } event_timeout_init(&c->c2.push_request_interval, 0, now); reset_coarse_timers(c); } diff --git a/src/openvpn/integer.h b/src/openvpn/integer.h index 3755f43f..0c3511e6 100644 --- a/src/openvpn/integer.h +++ b/src/openvpn/integer.h @@ -39,6 +39,31 @@ /* * min/max functions */ +static inline unsigned int +max_uint(unsigned int x, unsigned int y) +{ + if (x > y) + { + return x; + } + else + { + return y; + } +} + +static inline unsigned int +min_uint(unsigned int x, unsigned int y) +{ + if (x < y) + { + return x; + } + else + { + return y; + } +} static inline int max_int(int x, int y) diff --git a/src/openvpn/push.c b/src/openvpn/push.c index fb6b9d17..2ceee2c4 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -231,6 +231,62 @@ receive_cr_response(struct context *c, const struct buffer *buffer) msg(D_PUSH, "CR response was sent by client ('%s')", m); } +/** + * Parse the keyword for the AUTH_PENDING request + * @param buffer buffer containing the keywords, the buffer's + * content will be modified by this function + * @param server_timeout timeout pushed by the server or unchanged + * if the server does not push a timeout + */ +static void +parse_auth_pending_keywords(const struct buffer *buffer, + unsigned int *server_timeout) +{ + struct buffer buf = *buffer; + + /* does the buffer start with "AUTH_PENDING," ? */ + if (!buf_advance(&buf, strlen("AUTH_PENDING")) + || !(buf_read_u8(&buf) == ',') || !BLEN(&buf)) + { + return; + } + + /* parse the keywords in the same way that push options are parsed */ + char line[OPTION_LINE_SIZE]; + + while (buf_parse(&buf, ',', line, sizeof(line))) + { + if (sscanf(line, "timeout %u", server_timeout) != 1) + { + msg(D_PUSH, "ignoring AUTH_PENDING parameter: %s", line); + } + } +} + +void +receive_auth_pending(struct context *c, const struct buffer *buffer) +{ + if (!c->options.pull) + return; + + /* Cap the increase at the maximum time we are willing stay in the + * pending authentication state */ + unsigned int max_timeout = max_uint(c->options.renegotiate_seconds/2, + c->options.handshake_window); + + /* try to parse parameter keywords, default to hand-winow timeout if the + * server does not supply a timeout */ + unsigned int server_timeout = c->options.handshake_window; + parse_auth_pending_keywords(buffer, &server_timeout); + + msg(D_PUSH, "AUTH_PENDING received, extending handshake timeout from %us " + "to %us", c->options.handshake_window, + min_uint(max_timeout, server_timeout)); + + struct key_state *ks = &c->c2.tls_multi->session[TM_ACTIVE].key[KS_PRIMARY]; + c->c2.push_request_timeout = ks->established + min_uint(max_timeout, server_timeout); +} + /** * Add an option to the given push list by providing a format string. * @@ -372,7 +428,17 @@ send_push_request(struct context *c) struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE]; struct key_state *ks = &session->key[KS_PRIMARY]; - if (c->c2.push_request_timeout > now) + /* We timeout here under two conditions: + * a) we reached the hard limit of push_request_timeout + * b) we have not seen anything from the server in hand_window time + * + * for non auth-pending scenario, push_request_timeout is the same as + * hand_window timeout. For b) every PUSH_REQUEST is a acknowledged by + * the server by a P_ACK_V1 packet that reset the keepalive timer + */ + + if (c->c2.push_request_timeout > now + && (now - ks->peer_last_packet) < c->options.handshake_window) { return send_control_channel_string(c, "PUSH_REQUEST", D_PUSH); } diff --git a/src/openvpn/push.h b/src/openvpn/push.h index 2faf19a6..01847671 100644 --- a/src/openvpn/push.h +++ b/src/openvpn/push.h @@ -89,5 +89,14 @@ void send_restart(struct context *c, const char *kill_msg); */ void send_push_reply_auth_token(struct tls_multi *multi); +/** + * Parses an AUTH_PENDING message and if in pull mode extends the timeout + * + * @param c The context struct + * @param buffer Buffer containing the control message with AUTH_PENDING + */ +void +receive_auth_pending(struct context *c, const struct buffer *buffer); + #endif /* if P2MP */ #endif /* ifndef PUSH_H */ diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index efbf688f..5a231387 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -2268,6 +2268,7 @@ push_peer_info(struct buffer *buf, struct tls_session *session) if (session->opt->pull) { iv_proto |= IV_PROTO_REQUEST_PUSH; + iv_proto |= IV_PROTO_AUTH_PENDING_KW; } /* support for Negotiable Crypto Parameters */ @@ -3733,6 +3734,8 @@ tls_pre_decrypt(struct tls_multi *multi, } } } + /* Remember that we received a valid control channel packet */ + ks->peer_last_packet = now; done: buf->len = 0; diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index 56034540..8c8cbe02 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -119,6 +119,9 @@ /** Supports key derivation via TLS key material exporter [RFC5705] */ #define IV_PROTO_TLS_KEY_EXPORT (1<<3) +/** Supports signaling keywords with AUTH_PENDING, e.g. timeout=xy */ +#define IV_PROTO_AUTH_PENDING_KW (1<<4) + /* Default field in X509 to be username */ #define X509_USERNAME_FIELD_DEFAULT "CN" diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index a826e37f..bbb8135d 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -178,6 +178,7 @@ struct key_state time_t established; /* when our state went S_ACTIVE */ time_t must_negotiate; /* key negotiation times out if not finished before this time */ time_t must_die; /* this object is destroyed at this time */ + time_t peer_last_packet; /* Last time we received a packet in this control session */ int initial_opcode; /* our initial P_ opcode */ struct session_id session_id_remote; /* peer's random session ID */ From patchwork Mon Jan 25 01:56:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 1574 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director13.mail.ord1d.rsapps.net ([172.28.255.1]) by backend30.mail.ord1d.rsapps.net with LMTP id cOoNMz/ADmDZPAAAIUCqbw (envelope-from ) for ; Mon, 25 Jan 2021 07:57:35 -0500 Received: from proxy7.mail.ord1c.rsapps.net ([172.28.255.1]) by director13.mail.ord1d.rsapps.net with LMTP id kNrzMj/ADmBvXAAA91zNiA (envelope-from ) for ; Mon, 25 Jan 2021 07:57:35 -0500 Received: from smtp19.gate.ord1c ([172.28.255.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy7.mail.ord1c.rsapps.net with LMTPS id IJenMj/ADmBveAAAknS3pQ (envelope-from ) for ; Mon, 25 Jan 2021 07:57:35 -0500 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=none (p=nil; dis=none) header.from=rfc2549.org X-Suspicious-Flag: YES X-Classification-ID: e41a819a-5f0c-11eb-bf54-bc305bf036e4-1-1 Received: from [216.105.38.7] ([216.105.38.7:41144] helo=lists.sourceforge.net) by smtp19.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 7A/64-00839-E30CE006; Mon, 25 Jan 2021 07:57:34 -0500 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 1l41QD-0004r1-CV; Mon, 25 Jan 2021 12:56:45 +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 1l41QC-0004qM-1C for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:44 +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:To: From:Sender:Reply-To:Cc: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=uiVkwIM4SBRUBTXWK15lktOCtAA52/q7bCuxSxkZq+U=; b=cLckabINkdVIjPoEuo1LGACXi8 jGn38YOlna34o4WdHl8VwOF7r4ZOXmxzFyA1aCAlhWiSAgs/YxDZGWaS1yMJNl7cULNpTAvw2Yygr dCWMl3mU8LinGyy2GqWE/u0BptPgSdCnx1mbDY9j5TA0CcH/qcz4sE3e+BYUx8OlDP1c=; 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:To:From:Sender:Reply-To:Cc :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=uiVkwIM4SBRUBTXWK15lktOCtAA52/q7bCuxSxkZq+U=; b=m88thJK9UvTIK3d+4WnxqwMHG4 cPM/k62wdMhY5GrJk+vZ2iPr++KWnk3w2rCXOe4/jIAl/nnyfwqUXJJWIBRg/cXkVC8I+pl3DyRVZ EimM7Ixcgy5r5I07iJNI+/+CJ4csPOeUSZhMYFcPXcgt+zdLGNlkAHdiX5ZpbtvwlvkE=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-3.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.2) id 1l41Q9-006gWY-9d for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:43 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.94 (FreeBSD)) (envelope-from ) id 1l41Pw-0007Wx-Sq for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 13:56:28 +0100 Received: (nullmailer pid 30417 invoked by uid 10006); Mon, 25 Jan 2021 12:56:28 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Mon, 25 Jan 2021 13:56:20 +0100 Message-Id: <20210125125628.30364-4-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210125125628.30364-1-arne@rfc2549.org> References: <20210125125628.30364-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 0.0 SPF_NONE SPF: sender does not publish an SPF Record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record X-Headers-End: 1l41Q9-006gWY-9d Subject: [Openvpn-devel] [PATCH v2 03/11] Implement server side of AUTH_PENDING with extending timeout 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 Patch V2: eliminate parse_kid function, fix style Signed-off-by: Arne Schwabe --- src/openvpn/manage.c | 23 +++++++++-------- src/openvpn/manage.h | 3 ++- src/openvpn/multi.c | 27 +++----------------- src/openvpn/push.c | 55 +++++++++++++++++++++++++++++++++++++--- src/openvpn/push.h | 10 ++++++++ src/openvpn/ssl.c | 1 + src/openvpn/ssl_common.h | 1 + 7 files changed, 81 insertions(+), 39 deletions(-) diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index ed9dde1e..98a9a4cc 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -972,15 +972,15 @@ parse_cid(const char *str, unsigned long *cid) } static bool -parse_kid(const char *str, unsigned int *kid) +parse_uint(const char *str, const char* what, unsigned int *uint) { - if (sscanf(str, "%u", kid) == 1) + if (sscanf(str, "%u", uint) == 1) { return true; } else { - msg(M_CLIENT, "ERROR: cannot parse KID"); + msg(M_CLIENT, "ERROR: cannot parse %s", what); return false; } } @@ -995,15 +995,18 @@ parse_kid(const char *str, unsigned int *kid) * the information of the additional steps */ static void -man_client_pending_auth(struct management *man, const char *cid_str, const char *extra) +man_client_pending_auth(struct management *man, const char *cid_str, + const char *extra, const char *timeout_str) { unsigned long cid = 0; - if (parse_cid(cid_str, &cid)) + unsigned int timeout = 0; + if (parse_cid(cid_str, &cid) + && parse_uint(timeout_str, "TIMEOUT", &timeout)) { if (man->persist.callback.client_pending_auth) { bool ret = (*man->persist.callback.client_pending_auth) - (man->persist.callback.arg, cid, extra); + (man->persist.callback.arg, cid, extra, timeout); if (ret) { @@ -1029,7 +1032,7 @@ man_client_auth(struct management *man, const char *cid_str, const char *kid_str mc->in_extra_cid = 0; mc->in_extra_kid = 0; if (parse_cid(cid_str, &mc->in_extra_cid) - && parse_kid(kid_str, &mc->in_extra_kid)) + && parse_uint(kid_str, "KID", &mc->in_extra_kid)) { mc->in_extra_cmd = IEC_CLIENT_AUTH; in_extra_reset(mc, IER_NEW); @@ -1045,7 +1048,7 @@ man_client_deny(struct management *man, const char *cid_str, const char *kid_str { unsigned long cid = 0; unsigned int kid = 0; - if (parse_cid(cid_str, &cid) && parse_kid(kid_str, &kid)) + if (parse_cid(cid_str, &cid) && parse_uint(kid_str, "KID", &kid)) { if (man->persist.callback.client_auth) { @@ -1560,9 +1563,9 @@ man_dispatch_command(struct management *man, struct status_output *so, const cha } else if (streq(p[0], "client-pending-auth")) { - if (man_need(man, p, 2, 0)) + if (man_need(man, p, 3, 0)) { - man_client_pending_auth(man, p[1], p[2]); + man_client_pending_auth(man, p[1], p[2], p[3]); } } #ifdef MANAGEMENT_PF diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h index a3364644..aaa3b848 100644 --- a/src/openvpn/manage.h +++ b/src/openvpn/manage.h @@ -173,7 +173,8 @@ struct management_callback struct buffer_list *cc_config); /* ownership transferred */ bool (*client_pending_auth) (void *arg, const unsigned long cid, - const char *url); + const char *extra, + unsigned int timeout); char *(*get_peer_info) (void *arg, const unsigned long cid); #ifdef MANAGEMENT_PF bool (*client_pf)(void *arg, diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index dd713049..ac5d3f5b 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1768,28 +1768,6 @@ multi_client_connect_setenv(struct multi_context *m, gc_free(&gc); } -/** - * Extracts the IV_PROTO variable and returns its value or 0 - * if it cannot be extracted. - * - */ -static unsigned int -extract_iv_proto(const char *peer_info) -{ - - const char *optstr = peer_info ? strstr(peer_info, "IV_PROTO=") : NULL; - if (optstr) - { - int proto = 0; - int r = sscanf(optstr, "IV_PROTO=%d", &proto); - if (r == 1 && proto > 0) - { - return proto; - } - } - return 0; -} - /** * Calculates the options that depend on the client capabilities * based on local options and available peer info @@ -3918,14 +3896,15 @@ management_kill_by_cid(void *arg, const unsigned long cid, const char *kill_msg) static bool management_client_pending_auth(void *arg, const unsigned long cid, - const char *extra) + const char *extra, + unsigned int timeout) { struct multi_context *m = (struct multi_context *) arg; struct multi_instance *mi = lookup_by_cid(m, cid); if (mi) { /* sends INFO_PRE and AUTH_PENDING messages to client */ - bool ret = send_auth_pending_messages(&mi->context, extra); + bool ret = send_auth_pending_messages(&mi->context, extra, timeout); multi_schedule_context_wakeup(m, mi); return ret; } diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 2ceee2c4..e68fda9f 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -343,26 +343,57 @@ send_auth_failed(struct context *c, const char *client_reason) gc_free(&gc); } + bool -send_auth_pending_messages(struct context *c, const char *extra) +send_auth_pending_messages(struct context *c, const char *extra, + unsigned int timeout) { - send_control_channel_string(c, "AUTH_PENDING", D_PUSH); + struct key_state *ks = &tls_multi->session[TM_ACTIVE].key[KS_PRIMARY]; static const char info_pre[] = "INFO_PRE,"; + struct tls_multi *tls_multi = c->c2.tls_multi; + const char *const peer_info = tls_multi->peer_info; + unsigned int proto = extract_iv_proto(peer_info); + - size_t len = strlen(extra)+1 + sizeof(info_pre); + /* Calculate the maximum timeout and subtract the time we already waited */ + unsigned int max_timeout = max_uint(tls_multi->opt.renegotiate_seconds/2, + tls_multi->opt.handshake_window); + max_timeout = max_timeout - (now - ks->initial); + timeout = min_uint(max_timeout, timeout); + + struct gc_arena gc = gc_new(); + if ((proto & IV_PROTO_AUTH_PENDING_KW) == 0) + { + send_control_channel_string(c, "AUTH_PENDING", D_PUSH); + } + else + { + static const char auth_pre[] = "AUTH_PENDING,timeout "; + // Assume a worst case of 8 byte uint64 in decimal which + // needs 20 bytes + size_t len = 20 + 1 + sizeof(auth_pre); + struct buffer buf = alloc_buf_gc(len, &gc); + buf_printf(&buf, auth_pre); + buf_printf(&buf, "%u", timeout); + send_control_channel_string(c, BSTR(&buf), D_PUSH); + } + + size_t len = strlen(extra) + 1 + sizeof(info_pre); if (len > PUSH_BUNDLE_SIZE) { + gc_free(&gc); return false; } - struct gc_arena gc = gc_new(); struct buffer buf = alloc_buf_gc(len, &gc); buf_printf(&buf, info_pre); buf_printf(&buf, "%s", extra); send_control_channel_string(c, BSTR(&buf), D_PUSH); + ks->auth_deferred_expire = now + timeout; + gc_free(&gc); return true; } @@ -1010,4 +1041,20 @@ remove_iroutes_from_push_route_list(struct options *o) } } +unsigned int +extract_iv_proto(const char *peer_info) +{ + const char *optstr = peer_info ? strstr(peer_info, "IV_PROTO=") : NULL; + if (optstr) + { + int proto = 0; + int r = sscanf(optstr, "IV_PROTO=%d", &proto); + if (r == 1 && proto > 0) + { + return proto; + } + } + return 0; +} + #endif /* if P2MP */ diff --git a/src/openvpn/push.h b/src/openvpn/push.h index 01847671..a2192114 100644 --- a/src/openvpn/push.h +++ b/src/openvpn/push.h @@ -89,6 +89,16 @@ void send_restart(struct context *c, const char *kill_msg); */ void send_push_reply_auth_token(struct tls_multi *multi); + +/** + * Extracts the IV_PROTO variable and returns its value or 0 + * if it cannot be extracted. + * + * @param peer_info peer info string to search for IV_PROTO + */ +unsigned int +extract_iv_proto(const char *peer_info); + /** * Parses an AUTH_PENDING message and if in pull mode extends the timeout * diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 5a231387..14c8116f 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -2771,6 +2771,7 @@ tls_process(struct tls_multi *multi, buf = reliable_get_buf_output_sequenced(ks->send_reliable); if (buf) { + ks->initial = now; ks->must_negotiate = now + session->opt->handshake_window; ks->auth_deferred_expire = now + auth_deferred_expire_window(session->opt); diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index bbb8135d..bf7f9ba3 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -175,6 +175,7 @@ struct key_state struct key_state_ssl ks_ssl; /* contains SSL object and BIOs for the control channel */ + time_t initial; /* when we created this session */ time_t established; /* when our state went S_ACTIVE */ time_t must_negotiate; /* key negotiation times out if not finished before this time */ time_t must_die; /* this object is destroyed at this time */ From patchwork Mon Jan 25 01:56:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 1580 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director12.mail.ord1d.rsapps.net ([172.28.255.1]) by backend30.mail.ord1d.rsapps.net with LMTP id GPLnJkvADmBPRgAAIUCqbw (envelope-from ) for ; Mon, 25 Jan 2021 07:57:47 -0500 Received: from proxy8.mail.ord1c.rsapps.net ([172.28.255.1]) by director12.mail.ord1d.rsapps.net with LMTP id mPDIJkvADmCQawAAIasKDg (envelope-from ) for ; Mon, 25 Jan 2021 07:57:47 -0500 Received: from smtp33.gate.ord1c ([172.28.255.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy8.mail.ord1c.rsapps.net with LMTPS id WF2IJkvADmDMZgAAHz/atg (envelope-from ) for ; Mon, 25 Jan 2021 07:57:47 -0500 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: smtp33.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=none (p=nil; dis=none) header.from=rfc2549.org X-Suspicious-Flag: YES X-Classification-ID: ebf500de-5f0c-11eb-a3a7-54520067fec4-1-1 Received: from [216.105.38.7] ([216.105.38.7:41680] helo=lists.sourceforge.net) by smtp33.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 45/E6-06632-B40CE006; Mon, 25 Jan 2021 07:57:47 -0500 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 1l41QU-0004w6-Uc; Mon, 25 Jan 2021 12:57:02 +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 1l41QF-0004rs-2p for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:47 +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:To: From:Sender:Reply-To:Cc: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=hQPZhEw9ZBYGGz58+HLUBle/7D1Gs6EfMKIWcTN9Ito=; b=clN5zz86aiCXagdMYtOxmr4/tb j39V8jrwVHqXGj4ZL93EUBaiKvPtMKtFwiA8QQLf0JOHI9O9mSy1x8YNqAmpb7roAz+DrevMGhvst BzhdeFTHrsYJHRdz+mTPfNIjrObfe+JeiBuQBwapaNEB2nCxv/SFeOcRcJjZxdggpsws=; 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:To:From:Sender:Reply-To:Cc :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=hQPZhEw9ZBYGGz58+HLUBle/7D1Gs6EfMKIWcTN9Ito=; b=fMKqB7gaJRRF9+1n/fpZ9RhpUC 37caTHsPJeZKswPDR4+AjNpLgabI4myMXlyXq7rUWQxfwJAoIDb+2Bqr5qckrlLvEix3OiOOfx5JW ZagbJqEpl7zD0+wtz+S5R1NA8tBbxkbb/1iZNU2eqdgESpqteCwFsFVzsQA6gTSn+LZk=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-3.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.2) id 1l41QB-006gWt-9J for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:47 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.94 (FreeBSD)) (envelope-from ) id 1l41Pw-0007X0-VO for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 13:56:28 +0100 Received: (nullmailer pid 30420 invoked by uid 10006); Mon, 25 Jan 2021 12:56:28 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Mon, 25 Jan 2021 13:56:21 +0100 Message-Id: <20210125125628.30364-5-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210125125628.30364-1-arne@rfc2549.org> References: <20210125125628.30364-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 0.0 SPF_NONE SPF: sender does not publish an SPF Record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record X-Headers-End: 1l41QB-006gWt-9J Subject: [Openvpn-devel] [PATCH v2 04/11] Introduce management client state for AUTH_PENDING notifications 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 This allows a UI client to display the correct state. Technically the client is still waiting for PUSH_REPLY but for every practical concern this is a different state as we are waiting for the pending authentication to finish. Signed-off-by: Arne Schwabe Acked-by: Lev Stipakov --- src/openvpn/manage.c | 3 +++ src/openvpn/manage.h | 2 ++ src/openvpn/push.c | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index 98a9a4cc..df987f53 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -169,6 +169,9 @@ man_state_name(const int state) case OPENVPN_STATE_TCP_CONNECT: return "TCP_CONNECT"; + case OPENVPN_STATE_AUTH_PENDING: + return "AUTH_PENDING"; + default: return "?"; } diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h index aaa3b848..2f94b10c 100644 --- a/src/openvpn/manage.h +++ b/src/openvpn/manage.h @@ -493,6 +493,8 @@ management_enable_def_auth(const struct management *man) #define OPENVPN_STATE_GET_CONFIG 9 /* Downloading configuration from server */ #define OPENVPN_STATE_RESOLVE 10 /* DNS lookup */ #define OPENVPN_STATE_TCP_CONNECT 11 /* Connecting to TCP server */ +#define OPENVPN_STATE_AUTH_PENDING 12 /* Waiting in auth-pending mode + * techhnically variant of GET_CONFIG */ #define OPENVPN_STATE_CLIENT_BASE 7 /* Base index of client-only states */ diff --git a/src/openvpn/push.c b/src/openvpn/push.c index e68fda9f..7d3cf806 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -248,12 +248,30 @@ parse_auth_pending_keywords(const struct buffer *buffer, if (!buf_advance(&buf, strlen("AUTH_PENDING")) || !(buf_read_u8(&buf) == ',') || !BLEN(&buf)) { +#ifdef ENABLE_MANAGEMENT + if (management) + { + management_set_state(management, OPENVPN_STATE_AUTH_PENDING, + "", NULL, NULL, NULL, NULL); + } +#endif + return; } /* parse the keywords in the same way that push options are parsed */ char line[OPTION_LINE_SIZE]; +#ifdef ENABLE_MANAGEMENT + /* Need to do the management notification with the keywords before + * buf_parse is called, as it will insert \0 bytes into the buffer */ + if (management) + { + management_set_state(management, OPENVPN_STATE_AUTH_PENDING, + BSTR(&buf), NULL, NULL, NULL, NULL); + } +#endif + while (buf_parse(&buf, ',', line, sizeof(line))) { if (sscanf(line, "timeout %u", server_timeout) != 1) From patchwork Mon Jan 25 01:56:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 1578 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director8.mail.ord1d.rsapps.net ([172.27.255.51]) by backend30.mail.ord1d.rsapps.net with LMTP id SIxiI0jADmDzLgAAIUCqbw (envelope-from ) for ; Mon, 25 Jan 2021 07:57:44 -0500 Received: from proxy15.mail.iad3a.rsapps.net ([172.27.255.51]) by director8.mail.ord1d.rsapps.net with LMTP id WM8KI0jADmBTFgAAfY0hYg (envelope-from ) for ; Mon, 25 Jan 2021 07:57:44 -0500 Received: from smtp21.gate.iad3a ([172.27.255.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy15.mail.iad3a.rsapps.net with LMTPS id kBFgHEjADmCfNQAAHi9b9g (envelope-from ) for ; Mon, 25 Jan 2021 07:57:44 -0500 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: smtp21.gate.iad3a.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=none (p=nil; dis=none) header.from=rfc2549.org X-Suspicious-Flag: YES X-Classification-ID: ea0ab6d8-5f0c-11eb-a2be-525400e75841-1-1 Received: from [216.105.38.7] ([216.105.38.7:37138] helo=lists.sourceforge.net) by smtp21.gate.iad3a.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 74/E3-02556-840CE006; Mon, 25 Jan 2021 07:57:44 -0500 Received: from [127.0.0.1] (helo=sfs-ml-4.v29.lw.sourceforge.com) by sfs-ml-4.v29.lw.sourceforge.com with esmtp (Exim 4.90_1) (envelope-from ) id 1l41QR-0001nK-QE; Mon, 25 Jan 2021 12:56:59 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1l41QO-0001mW-C2 for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:56 +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:To: From:Sender:Reply-To:Cc: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=ia0ZN4jFn9HWvDt2sgfSlm/E3UJGiGY1BMoMk45rgjQ=; b=E4A/O/ZiLgtV2JKOaFTsPFUfj3 znt2/UK0JFpe2Sxzw5q7iwWIpI6S5fT2OCrb/hn4qS5/gO8c7UfdJv7qpXAR+Rd+uxr/p1bCcLS03 uZqyyy4FArd9hRmWI45y0BPyzyd5yGsEAJC9+yk8CQ2YmlftG1U7wr6q4jUKfWHxK53k=; 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:To:From:Sender:Reply-To:Cc :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=ia0ZN4jFn9HWvDt2sgfSlm/E3UJGiGY1BMoMk45rgjQ=; b=Ks9CCLriiwspd4iLJMzcSPPfE/ cl9cmwM/l1fuMqaz/DDtMA18ksoIOhAgQyR2K2JSueXSN0MD3Pi1B/0IrBfiprgMXs2jra4X1UZuD fziZzZWC0a8y8GKoXRk1Z0JY9V7Hiv/idaxkGtoQjdlHTeN5oh/yAxuVgmVO+DlRWDTA=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-3.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.2) id 1l41Q9-006gWZ-70 for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:53 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.94 (FreeBSD)) (envelope-from ) id 1l41Px-0007X3-0u for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 13:56:29 +0100 Received: (nullmailer pid 30423 invoked by uid 10006); Mon, 25 Jan 2021 12:56:28 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Mon, 25 Jan 2021 13:56:22 +0100 Message-Id: <20210125125628.30364-6-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210125125628.30364-1-arne@rfc2549.org> References: <20210125125628.30364-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 0.0 SPF_NONE SPF: sender does not publish an SPF Record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record X-Headers-End: 1l41Q9-006gWZ-70 Subject: [Openvpn-devel] [PATCH v2 05/11] Change parameter of send_auth_pending_messages from context to tls_multi 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 This prepares send_auth_pending_messages to be used a in context that does not have context c available but also does not need to schedule an immediate sending of the message (auth plugin/script) Patch V2: Adjust the comment of reschedule_multi_process to actually fit a function. Signed-off-by: Arne Schwabe --- src/openvpn/forward.c | 17 +++++++++-------- src/openvpn/forward.h | 9 +++++++++ src/openvpn/multi.c | 4 +++- src/openvpn/push.c | 9 ++++----- src/openvpn/push.h | 4 +++- 5 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 2e1e1490..fc28caf0 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -342,6 +342,14 @@ send_control_channel_string_dowork(struct tls_multi *multi, return stat; } +void reschedule_multi_process(struct context *c) +{ + + interval_action(&c->c2.tmp_int); + context_immediate_reschedule(c); /* ZERO-TIMEOUT */ +} + + bool send_control_channel_string(struct context *c, const char *str, int msglevel) { @@ -349,15 +357,8 @@ send_control_channel_string(struct context *c, const char *str, int msglevel) { bool ret = send_control_channel_string_dowork(c->c2.tls_multi, str, msglevel); - /* - * Reschedule tls_multi_process. - * NOTE: in multi-client mode, usually the below two statements are - * insufficient to reschedule the client instance object unless - * multi_schedule_context_wakeup(m, mi) is also called. - */ + reschedule_multi_process(c); - interval_action(&c->c2.tmp_int); - context_immediate_reschedule(c); /* ZERO-TIMEOUT */ return ret; } return true; diff --git a/src/openvpn/forward.h b/src/openvpn/forward.h index a8b19f69..9ce3bc1c 100644 --- a/src/openvpn/forward.h +++ b/src/openvpn/forward.h @@ -317,6 +317,15 @@ bool send_control_channel_string_dowork(struct tls_multi *multi, const char *str, int msglevel); + +/** + * Reschedule tls_multi_process. + * NOTE: in multi-client mode, usually calling the function is + * insufficient to reschedule the client instance object unless + * multi_schedule_context_wakeup(m, mi) is also called. + */ +void reschedule_multi_process(struct context *c); + #define PIPV4_PASSTOS (1<<0) #define PIP_MSSFIX (1<<1) /* v4 and v6 */ #define PIP_OUTGOING (1<<2) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index ac5d3f5b..d10f188c 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -3904,7 +3904,9 @@ management_client_pending_auth(void *arg, if (mi) { /* sends INFO_PRE and AUTH_PENDING messages to client */ - bool ret = send_auth_pending_messages(&mi->context, extra, timeout); + bool ret = send_auth_pending_messages(mi->context.c2.tls_multi, extra, + timeout); + reschedule_multi_process(&mi->context); multi_schedule_context_wakeup(m, mi); return ret; } diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 7d3cf806..320ad737 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -363,14 +363,13 @@ send_auth_failed(struct context *c, const char *client_reason) bool -send_auth_pending_messages(struct context *c, const char *extra, +send_auth_pending_messages(struct tls_multi *tls_multi, const char *extra, unsigned int timeout) { struct key_state *ks = &tls_multi->session[TM_ACTIVE].key[KS_PRIMARY]; static const char info_pre[] = "INFO_PRE,"; - struct tls_multi *tls_multi = c->c2.tls_multi; const char *const peer_info = tls_multi->peer_info; unsigned int proto = extract_iv_proto(peer_info); @@ -384,7 +383,7 @@ send_auth_pending_messages(struct context *c, const char *extra, struct gc_arena gc = gc_new(); if ((proto & IV_PROTO_AUTH_PENDING_KW) == 0) { - send_control_channel_string(c, "AUTH_PENDING", D_PUSH); + send_control_channel_string_dowork(tls_multi, "AUTH_PENDING", D_PUSH); } else { @@ -395,7 +394,7 @@ send_auth_pending_messages(struct context *c, const char *extra, struct buffer buf = alloc_buf_gc(len, &gc); buf_printf(&buf, auth_pre); buf_printf(&buf, "%u", timeout); - send_control_channel_string(c, BSTR(&buf), D_PUSH); + send_control_channel_string_dowork(tls_multi, BSTR(&buf), D_PUSH); } size_t len = strlen(extra) + 1 + sizeof(info_pre); @@ -408,7 +407,7 @@ send_auth_pending_messages(struct context *c, const char *extra, struct buffer buf = alloc_buf_gc(len, &gc); buf_printf(&buf, info_pre); buf_printf(&buf, "%s", extra); - send_control_channel_string(c, BSTR(&buf), D_PUSH); + send_control_channel_string_dowork(tls_multi, BSTR(&buf), D_PUSH); ks->auth_deferred_expire = now + timeout; diff --git a/src/openvpn/push.h b/src/openvpn/push.h index a2192114..377f94a6 100644 --- a/src/openvpn/push.h +++ b/src/openvpn/push.h @@ -77,7 +77,9 @@ void send_auth_failed(struct context *c, const char *client_reason); * doc/management-notes.txt under client-pending-auth for * more details on message format */ -bool send_auth_pending_messages(struct context *c, const char *extra); +bool +send_auth_pending_messages(struct tls_multi *tls_multi, const char *extra, + unsigned int timeout); void send_restart(struct context *c, const char *kill_msg); From patchwork Mon Jan 25 01:56:23 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 1570 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director14.mail.ord1d.rsapps.net ([172.27.255.1]) by backend30.mail.ord1d.rsapps.net with LMTP id SAlGEzTADmBPRgAAIUCqbw (envelope-from ) for ; Mon, 25 Jan 2021 07:57:24 -0500 Received: from proxy9.mail.iad3a.rsapps.net ([172.27.255.1]) by director14.mail.ord1d.rsapps.net with LMTP id GCsYEzTADmDDOAAAeJ7fFg (envelope-from ) for ; Mon, 25 Jan 2021 07:57:24 -0500 Received: from smtp7.gate.iad3a ([172.27.255.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy9.mail.iad3a.rsapps.net with LMTPS id KG5tCzTADmBUfAAAGuSQww (envelope-from ) for ; Mon, 25 Jan 2021 07:57:24 -0500 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: smtp7.gate.iad3a.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=none (p=nil; dis=none) header.from=rfc2549.org X-Suspicious-Flag: YES X-Classification-ID: ddd51a16-5f0c-11eb-8d4b-525400bbebb8-1-1 Received: from [216.105.38.7] ([216.105.38.7:36906] helo=lists.sourceforge.net) by smtp7.gate.iad3a.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 8A/46-07439-330CE006; Mon, 25 Jan 2021 07:57:23 -0500 Received: from [127.0.0.1] (helo=sfs-ml-4.v29.lw.sourceforge.com) by sfs-ml-4.v29.lw.sourceforge.com with esmtp (Exim 4.90_1) (envelope-from ) id 1l41QE-0001lv-5L; Mon, 25 Jan 2021 12:56:46 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1l41QC-0001li-2a for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:44 +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:To: From:Sender:Reply-To:Cc: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=ZqO1RGit4BRcaSI1bd1kzqk5uBPNI0zggKdfvfPJ4uc=; b=LAoS3b6/zZVIJoRv/eMfe6eezQ x19PygfAzOC77fmDbr7mOauo/Wuej2PAMdX8QbS+pY0XHWJPyy5FsHYNqHW6/eMIehXx4FJIbFc5f IUuyJvxb5SIMpBicWGn6pdFS1JIR/wT37KX0TksGXCwN4TYwF8FlaIo9jHpo/WSvfLqk=; 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:To:From:Sender:Reply-To:Cc :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=ZqO1RGit4BRcaSI1bd1kzqk5uBPNI0zggKdfvfPJ4uc=; b=ZcnaMi2R01w/OZPEYzg4NfQ5UE wacOSNf3nZD59oj5mn0ccljSej148yPP6xWG7Nw6bQpSDFGeUQWObhd3cQk3Tfa7XBQCOFk80NtoQ ln6rWryarfYSUHtumyP/L+6wLfPSiKRTQEJAdqe9099GssSMCLRQAmFv7Lhu48Wp4dPA=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.2) id 1l41Q4-002esp-0V for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:43 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.94 (FreeBSD)) (envelope-from ) id 1l41Px-0007X6-2Y for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 13:56:29 +0100 Received: (nullmailer pid 30426 invoked by uid 10006); Mon, 25 Jan 2021 12:56:29 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Mon, 25 Jan 2021 13:56:23 +0100 Message-Id: <20210125125628.30364-7-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210125125628.30364-1-arne@rfc2549.org> References: <20210125125628.30364-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 0.0 SPF_NONE SPF: sender does not publish an SPF Record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record X-Headers-End: 1l41Q4-002esp-0V Subject: [Openvpn-devel] [PATCH v2 06/11] Add S_EXITCODE flag for openvpn_run_script to report exit code 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 This allows to use script that have more than just fail/sucess but also deferred as status Patch v2: minor style fixes, improve doxygen comments Signed-off-by: Arne Schwabe Acked-by: Lev Stipakov --- src/openvpn/platform.c | 34 ++++++++++++++++++++++++++++++++++ src/openvpn/platform.h | 5 ++++- src/openvpn/run_command.c | 25 ++++++++++++++++--------- src/openvpn/run_command.h | 15 +++++++++++---- 4 files changed, 65 insertions(+), 14 deletions(-) diff --git a/src/openvpn/platform.c b/src/openvpn/platform.c index 53d07f9c..ef688c23 100644 --- a/src/openvpn/platform.c +++ b/src/openvpn/platform.c @@ -240,6 +240,40 @@ platform_system_ok(int stat) #endif } +#ifdef _WIN32 +int +platform_ret_code(int stat) +{ + if (stat >= 0 && stat < 255) + { + return stat; + } + else + { + return -1; + } +} +#else +int +platform_ret_code(int stat) +{ + if (!WIFEXITED(stat) || stat == -1) + { + return -1; + } + + int status = WEXITSTATUS(stat); + if (status >= 0 && status < 255) + { + return status; + } + else + { + return -1; + } +} +#endif + int platform_access(const char *path, int mode) { diff --git a/src/openvpn/platform.h b/src/openvpn/platform.h index 091fc9c4..01f3200c 100644 --- a/src/openvpn/platform.h +++ b/src/openvpn/platform.h @@ -119,9 +119,12 @@ void platform_mlockall(bool print_msg); /* Disable paging */ int platform_chdir(const char *dir); -/* interpret the status code returned by execve() */ +/** interpret the status code returned by execve() */ bool platform_system_ok(int stat); +/** Return an exit code if valid and between 0 and 255, -1 otherwise */ +int platform_ret_code(int stat); + int platform_access(const char *path, int mode); void platform_sleep_milliseconds(unsigned int n); diff --git a/src/openvpn/run_command.c b/src/openvpn/run_command.c index 4c4adf97..8f99ec88 100644 --- a/src/openvpn/run_command.c +++ b/src/openvpn/run_command.c @@ -191,27 +191,34 @@ openvpn_execve(const struct argv *a, const struct env_set *es, const unsigned in /* * Wrapper around openvpn_execve */ -bool +int openvpn_execve_check(const struct argv *a, const struct env_set *es, const unsigned int flags, const char *error_message) { struct gc_arena gc = gc_new(); const int stat = openvpn_execve(a, es, flags); int ret = false; - if (platform_system_ok(stat)) + if (flags & S_EXITCODE) + { + ret = platform_ret_code(stat); + if (ret != -1) { + goto done; + } + } + else if (platform_system_ok(stat)) { ret = true; + goto done; } - else + if (error_message) { - if (error_message) - { - msg(((flags & S_FATAL) ? M_FATAL : M_WARN), "%s: %s", - error_message, - system_error_message(stat, &gc)); - } + msg(((flags & S_FATAL) ? M_FATAL : M_WARN), "%s: %s", + error_message, + system_error_message(stat, &gc)); } +done: gc_free(&gc); + return ret; } diff --git a/src/openvpn/run_command.h b/src/openvpn/run_command.h index 7ccb13c6..da33d92b 100644 --- a/src/openvpn/run_command.h +++ b/src/openvpn/run_command.h @@ -42,18 +42,25 @@ int script_security(void); void script_security_set(int level); /* openvpn_execve flags */ -#define S_SCRIPT (1<<0) -#define S_FATAL (1<<1) +#define S_SCRIPT (1<<0) +#define S_FATAL (1<<1) +/** Instead of returning 1/0 for success/fail, + * return exit code when between 0 and 255 and -1 otherwise */ +#define S_EXITCODE (1<<2) /* wrapper around the execve() call */ int openvpn_popen(const struct argv *a, const struct env_set *es); bool openvpn_execve_allowed(const unsigned int flags); -bool openvpn_execve_check(const struct argv *a, const struct env_set *es, +int openvpn_execve_check(const struct argv *a, const struct env_set *es, const unsigned int flags, const char *error_message); -static inline bool +/** + * Will run a script and return the exit code of the script if between + * 0 and 255, -1 otherwise + */ +static inline int openvpn_run_script(const struct argv *a, const struct env_set *es, const unsigned int flags, const char *hook) { From patchwork Mon Jan 25 01:56:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 1579 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director12.mail.ord1d.rsapps.net ([172.28.255.1]) by backend30.mail.ord1d.rsapps.net with LMTP id 6KmsOUjADmDzLgAAIUCqbw (envelope-from ) for ; Mon, 25 Jan 2021 07:57:44 -0500 Received: from proxy1.mail.ord1c.rsapps.net ([172.28.255.1]) by director12.mail.ord1d.rsapps.net with LMTP id gKSNOUjADmC5ZwAAIasKDg (envelope-from ) for ; Mon, 25 Jan 2021 07:57:44 -0500 Received: from smtp40.gate.ord1c ([172.28.255.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy1.mail.ord1c.rsapps.net with LMTPS id QOxnOUjADmBfdQAA2VeTtA (envelope-from ) for ; Mon, 25 Jan 2021 07:57:44 -0500 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: smtp40.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=none (p=nil; dis=none) header.from=rfc2549.org X-Suspicious-Flag: YES X-Classification-ID: ea59c296-5f0c-11eb-ae77-525400b3abc9-1-1 Received: from [216.105.38.7] ([216.105.38.7:41568] helo=lists.sourceforge.net) by smtp40.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id DF/7B-17176-840CE006; Mon, 25 Jan 2021 07:57:44 -0500 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 1l41QV-0004wK-29; Mon, 25 Jan 2021 12:57:03 +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 1l41QF-0004rt-3D for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:47 +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:To: From:Sender:Reply-To:Cc: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=+7IoKGWNPS0oGst8IbmGhCnIukMULBNO/eHMhXYl24g=; b=OdXPpZkA6tFaS5c4VEjVYCBtr2 17M/F+N/a0eoIfmcnCaZeMoJwZF7OXMFjMFWCwUBmmIEz9jN0f9wJewALgRGCkFpR+XYNwsrq9scF pxxtmCtzPmrVux3oUOS0hPPi9Tn7fpcnF5AEAo20hmvUtI2GtF/HfHEOfYwvOpL3tlpw=; 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:To:From:Sender:Reply-To:Cc :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=+7IoKGWNPS0oGst8IbmGhCnIukMULBNO/eHMhXYl24g=; b=JtY+pI9ZrnbiTIpZcOCGRGyZik Bq0qOZ1fCiwcZiMU6VJMqUxI3A+600A/cVo8j6igqhgIA7RgB8L6j9n52RTfoJwP/RhvsY1xVGfYg bwgWGeYZ0EntyMx4a/N/AbXkLwfE7uibPD+ypM1smSa/C+CJgLGlc2nK25hcHQUt8wGs=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-3.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.2) id 1l41QB-006gWv-9t for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:47 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.94 (FreeBSD)) (envelope-from ) id 1l41Px-0007X9-4z for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 13:56:29 +0100 Received: (nullmailer pid 30429 invoked by uid 10006); Mon, 25 Jan 2021 12:56:29 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Mon, 25 Jan 2021 13:56:24 +0100 Message-Id: <20210125125628.30364-8-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210125125628.30364-1-arne@rfc2549.org> References: <20210125125628.30364-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 0.0 SPF_NONE SPF: sender does not publish an SPF Record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record X-Headers-End: 1l41QB-006gWv-9t Subject: [Openvpn-devel] [PATCH v2 07/11] Refactor extract_var_peer_info into standalone function and add ssl_util.c 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 Our "natural" place for this function would be ssl.c but ssl.c has a lot of dependencies on all kinds of other compilation units so including ssl.c into unit tests is near impossible currently. Instead create a new file ssl_util.c that holds small utility functions like this one. Patch v2: add newline add the end of sll_util.h and ssl_util.c Signed-off-by: Arne Schwabe Acked-by: Lev Stipakov --- src/openvpn/Makefile.am | 1 + src/openvpn/openvpn.vcxproj | 2 + src/openvpn/openvpn.vcxproj.filters | 6 +++ src/openvpn/ssl.c | 2 +- src/openvpn/ssl_ncp.c | 20 ++-------- src/openvpn/ssl_util.c | 59 ++++++++++++++++++++++++++++ src/openvpn/ssl_util.h | 49 +++++++++++++++++++++++ src/openvpn/ssl_verify.c | 1 + tests/unit_tests/openvpn/Makefile.am | 3 +- 9 files changed, 125 insertions(+), 18 deletions(-) create mode 100644 src/openvpn/ssl_util.c create mode 100644 src/openvpn/ssl_util.h diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index 37b002c6..ec84929b 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -119,6 +119,7 @@ openvpn_SOURCES = \ ssl_openssl.c ssl_openssl.h \ ssl_mbedtls.c ssl_mbedtls.h \ ssl_ncp.c ssl_ncp.h \ + ssl_util.c ssl_util.h \ ssl_common.h \ ssl_verify.c ssl_verify.h ssl_verify_backend.h \ ssl_verify_openssl.c ssl_verify_openssl.h \ diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj index 3863854b..cf31940c 100644 --- a/src/openvpn/openvpn.vcxproj +++ b/src/openvpn/openvpn.vcxproj @@ -212,6 +212,7 @@ + @@ -300,6 +301,7 @@ + diff --git a/src/openvpn/openvpn.vcxproj.filters b/src/openvpn/openvpn.vcxproj.filters index cf5748c7..e8aed2c5 100644 --- a/src/openvpn/openvpn.vcxproj.filters +++ b/src/openvpn/openvpn.vcxproj.filters @@ -243,6 +243,9 @@ Source Files + + Source Files + @@ -509,6 +512,9 @@ Header Files + + Header Files + diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 14c8116f..f59b409f 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -4201,4 +4201,4 @@ void ssl_clean_user_pass(void) { purge_user_pass(&auth_user_pass, false); -} +} \ No newline at end of file diff --git a/src/openvpn/ssl_ncp.c b/src/openvpn/ssl_ncp.c index 45bddbe0..f02a3103 100644 --- a/src/openvpn/ssl_ncp.c +++ b/src/openvpn/ssl_ncp.c @@ -48,6 +48,7 @@ #include "common.h" #include "ssl_ncp.h" +#include "ssl_util.h" #include "openvpn.h" /** @@ -195,23 +196,10 @@ const char * tls_peer_ncp_list(const char *peer_info, struct gc_arena *gc) { /* Check if the peer sends the IV_CIPHERS list */ - const char *ncp_ciphers_start; - if (peer_info && (ncp_ciphers_start = strstr(peer_info, "IV_CIPHERS="))) + const char *iv_ciphers = extract_var_peer_info(peer_info,"IV_CIPHERS=", gc); + if (iv_ciphers) { - ncp_ciphers_start += strlen("IV_CIPHERS="); - const char *ncp_ciphers_end = strstr(ncp_ciphers_start, "\n"); - if (!ncp_ciphers_end) - { - /* IV_CIPHERS is at end of the peer_info list and no '\n' - * follows */ - ncp_ciphers_end = ncp_ciphers_start + strlen(ncp_ciphers_start); - } - - char *ncp_ciphers_peer = string_alloc(ncp_ciphers_start, gc); - /* NULL terminate the copy at the right position */ - ncp_ciphers_peer[ncp_ciphers_end - ncp_ciphers_start] = '\0'; - return ncp_ciphers_peer; - + return iv_ciphers; } else if (tls_peer_info_ncp_ver(peer_info)>=2) { diff --git a/src/openvpn/ssl_util.c b/src/openvpn/ssl_util.c new file mode 100644 index 00000000..d6ead462 --- /dev/null +++ b/src/openvpn/ssl_util.c @@ -0,0 +1,59 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2020 OpenVPN Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" +#endif + +#include "syshead.h" + +#include "ssl_util.h" + +char * +extract_var_peer_info(const char *peer_info, const char *var, + struct gc_arena *gc) +{ + const char *var_start; + + if (peer_info && (var_start = strstr(peer_info, var))) + { + var_start += strlen(var); + const char *var_end = strstr(var_start, "\n"); + if (!var_end) + { + /* var is at end of the peer_info list and no '\n' + * follows */ + var_end = var_start + strlen(var_start); + } + + char *ncp_ciphers_peer = string_alloc(var_start, gc); + /* NULL terminate the copy at the right position */ + ncp_ciphers_peer[var_end - var_start] = '\0'; + return ncp_ciphers_peer; + } + else + { + return NULL; + } +} diff --git a/src/openvpn/ssl_util.h b/src/openvpn/ssl_util.h new file mode 100644 index 00000000..bc2ae30d --- /dev/null +++ b/src/openvpn/ssl_util.h @@ -0,0 +1,49 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2020 OpenVPN Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/** + * @file SSL utility function. This file (and its .c file) is designed to + * to be included in units/etc without pulling in a lot of dependencies + */ + +#ifndef SSL_UTIL_H_ +#define SSL_UTIL_H_ + +#include "buffer.h" + +/** + * Extracts a variable from peer info, the returned string will be allocated + * using the supplied gc_arena + * + * @param peer_info The peer's peer_info + * @param var The variable *including* =, e.g. IV_CIPHERS= + * + * @return The content of the variable as NULL terminated string or NULL if the + * variable cannot be found. + */ +char * +extract_var_peer_info(const char *peer_info, + const char *var, + struct gc_arena *gc); + +#endif diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index e04c5c35..e0ef399f 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -46,6 +46,7 @@ #endif #include "auth_token.h" #include "push.h" +#include "ssl_util.h" /** Maximum length of common name */ #define TLS_USERNAME_LEN 64 diff --git a/tests/unit_tests/openvpn/Makefile.am b/tests/unit_tests/openvpn/Makefile.am index f0880a6b..50f3a02e 100644 --- a/tests/unit_tests/openvpn/Makefile.am +++ b/tests/unit_tests/openvpn/Makefile.am @@ -125,4 +125,5 @@ ncp_testdriver_SOURCES = test_ncp.c mock_msg.c \ $(openvpn_srcdir)/crypto_openssl.c \ $(openvpn_srcdir)/otime.c \ $(openvpn_srcdir)/packet_id.c \ - $(openvpn_srcdir)/platform.c + $(openvpn_srcdir)/platform.c \ + $(openvpn_srcdir)/ssl_util.c From patchwork Mon Jan 25 01:56:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 1572 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director9.mail.ord1d.rsapps.net ([172.30.191.6]) by backend30.mail.ord1d.rsapps.net with LMTP id yG3aHDzADmCQLAAAIUCqbw (envelope-from ) for ; Mon, 25 Jan 2021 07:57:32 -0500 Received: from proxy19.mail.ord1d.rsapps.net ([172.30.191.6]) by director9.mail.ord1d.rsapps.net with LMTP id IMGnHDzADmCcYAAAalYnBA (envelope-from ) for ; Mon, 25 Jan 2021 07:57:32 -0500 Received: from smtp5.gate.ord1c ([172.30.191.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy19.mail.ord1d.rsapps.net with LMTPS id QL9hHDzADmDPaQAAyH2SIw (envelope-from ) for ; Mon, 25 Jan 2021 07:57:32 -0500 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: smtp5.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=none (p=nil; dis=none) header.from=rfc2549.org X-Suspicious-Flag: YES X-Classification-ID: e2a66e64-5f0c-11eb-ae2d-a4badb0b200d-1-1 Received: from [216.105.38.7] ([216.105.38.7:41038] helo=lists.sourceforge.net) by smtp5.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id F1/21-14465-B30CE006; Mon, 25 Jan 2021 07:57:31 -0500 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 1l41QD-0004qo-2j; Mon, 25 Jan 2021 12:56:45 +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 1l41QC-0004qN-1E for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:44 +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:To: From:Sender:Reply-To:Cc: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=JU5KSF1nl/Mzi+aalH2FbM4B8IA9ngx3r1lztOVqbyg=; b=BCKq2282697xhvTxKYUyq+83vO eIOIUlyGETxG10GBjOSGlOd8FoUdBdg+m+khbExwOV6cuZ2cVurLJS4caUsAxL0+fCiiMBzR9cZfX J7fN8cILWgoU/cFP0Oat7FL8MqtEPBG3y1fyxpEm2Kg7+29LK6L7srf7Bux9m8VtGEvA=; 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:To:From:Sender:Reply-To:Cc :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=JU5KSF1nl/Mzi+aalH2FbM4B8IA9ngx3r1lztOVqbyg=; b=QmZ8io4NwsTJ5T8QbzfboSD+8+ g4502KuIrh64RdScGOnCsxNCEVaU6uozRAkHvtsFLv7WpTZinSMcGoPmsPE7TZwbCgXMQv52M1nGN gOVGniykxty0Yi33q5VW32nULuSy+AJfU31E1qAsaWJqV7g3KROGzdZbNX1IM/daYlVc=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-3.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.2) id 1l41Q9-006gWa-9c for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:43 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.94 (FreeBSD)) (envelope-from ) id 1l41Px-0007XC-7x for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 13:56:29 +0100 Received: (nullmailer pid 30432 invoked by uid 10006); Mon, 25 Jan 2021 12:56:29 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Mon, 25 Jan 2021 13:56:25 +0100 Message-Id: <20210125125628.30364-9-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210125125628.30364-1-arne@rfc2549.org> References: <20210125125628.30364-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 0.0 SPF_NONE SPF: sender does not publish an SPF Record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record X-Headers-End: 1l41Q9-006gWa-9c Subject: [Openvpn-devel] [PATCH v2 08/11] Allow pending auth to be send from a auth plugin 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 Patch v2: removed change that slipped into this patch and belongs into the next Signed-off-by: Arne Schwabe Acked-By: David Sommerseth --- doc/man-sections/generic-options.rst | 3 +- include/openvpn-plugin.h.in | 8 ++ src/openvpn/ssl.c | 2 +- src/openvpn/ssl_common.h | 1 + src/openvpn/ssl_verify.c | 161 +++++++++++++++++++++++++-- src/openvpn/ssl_verify.h | 2 +- 6 files changed, 162 insertions(+), 15 deletions(-) diff --git a/doc/man-sections/generic-options.rst b/doc/man-sections/generic-options.rst index d5f08839..32eeda68 100644 --- a/doc/man-sections/generic-options.rst +++ b/doc/man-sections/generic-options.rst @@ -409,7 +409,8 @@ which mode OpenVPN is configured as. * :code:`OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY` plug-in hooks returns success/failure via :code:`auth_control_file` when using deferred auth - method + method and pending authentification via :code:`pending_auth_file`. + * :code:`OPENVPN_PLUGIN_ENABLE_PF` plugin hook to pass filtering rules via ``pf_file`` diff --git a/include/openvpn-plugin.h.in b/include/openvpn-plugin.h.in index 64b20886..bb561643 100644 --- a/include/openvpn-plugin.h.in +++ b/include/openvpn-plugin.h.in @@ -567,6 +567,14 @@ OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_op * auth_control_file/client_connect_deferred_file * in the environmental variable list (envp). * + * Additionally the auth_pending_file can be written, which causes the openvpn + * server to send a pending auth request to the client. See doc/management.txt + * for more details on this authentication mechanism. The format of the + * auth_pending_file is + * line 1: timeout in seconds + * line 2: Pending auth method the client needs to support (e.g. openurl) + * line 3: EXTRA (e.g. OPEN_URL:http://www.example.com) + * * In addition the OPENVPN_PLUGIN_CLIENT_CONNECT_DEFER and * OPENVPN_PLUGIN_CLIENT_CONNECT_DEFER_V2 are called when OpenVPN tries to * get the deferred result. For a V2 call implementing this function is diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index f59b409f..b8e77f0e 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -993,7 +993,7 @@ key_state_free(struct key_state *ks, bool clear) packet_id_free(&ks->crypto_options.packet_id); #ifdef PLUGIN_DEF_AUTH - key_state_rm_auth_control_file(ks); + key_state_rm_auth_control_files(ks); #endif if (clear) diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index bf7f9ba3..b493cbb7 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -215,6 +215,7 @@ struct key_state unsigned int auth_control_status; time_t acf_last_mod; char *auth_control_file; + char *auth_pending_file; }; /** Control channel wrapping (--tls-auth/--tls-crypt) context */ diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index e0ef399f..b9647c1a 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -865,13 +865,129 @@ man_def_auth_test(const struct key_state *ks) } #endif /* ifdef ENABLE_MANAGEMENT */ +/** + * Removes auth_pending file from the file system + * and key_state structure + */ +static void +key_state_rm_auth_pending_file(struct key_state *ks) +{ + if (ks && ks->auth_pending_file) + { + platform_unlink(ks->auth_pending_file); + free(ks->auth_pending_file); + ks->auth_pending_file = NULL; + } +} -/* - * auth_control_file functions +/** + * Check peer_info if the client supports the requested pending auth method + */ +static bool +check_auth_pending_method(const char *peer_info, const char *method) +{ + struct gc_arena gc = gc_new(); + + char *iv_sso = extract_var_peer_info(peer_info, "IV_SSO=", &gc); + if (!iv_sso) + { + gc_free(&gc); + return false; + } + + const char *client_method = strtok(iv_sso, ","); + bool supported = false; + + while (client_method) + { + if (0 == strcmp(client_method, method)) + { + supported = true; + break; + } + client_method = strtok(NULL, ":"); + } + + gc_free(&gc); + return supported; +} + +/** + * Checks if the deferred state should also send auth pending + * request to the client. Also removes the auth_pending control file + * + * @returns true if file was either processed sucessfully or did not + * exist at all + * @returns false The file had an invlaid format or another error occured */ +static bool +key_state_check_auth_pending_file(struct key_state *ks, + struct tls_multi *multi) +{ + bool ret = true; + if (ks && ks->auth_pending_file) + { + struct buffer_list *lines = buffer_list_file(ks->auth_pending_file, + 1024); + if (lines && lines->head) + { + /* Must have at least three lines. further lines are ignored for + * forward compatibility */ + if (!lines->head || !lines->head->next || !lines->head->next->next) + { + msg(M_WARN, "auth pending control file is not at least " + "three lines long."); + buffer_list_free(lines); + return false; + } + struct buffer *timeout_buf = &lines->head->buf; + struct buffer *iv_buf = &lines->head->next->buf; + struct buffer *extra_buf = &lines->head->next->next->buf; + + /* Remove newline chars at the end of the lines */ + buf_chomp(timeout_buf); + buf_chomp(iv_buf); + buf_chomp(extra_buf); + + long timeout = strtol(BSTR(timeout_buf), NULL, 10); + if (timeout == 0) + { + msg(M_WARN, "could not parse auth pending file timeout"); + buffer_list_free(lines); + return false; + } + + const char* pending_method = BSTR(iv_buf); + if (!check_auth_pending_method(multi->peer_info, pending_method)) + { + char buf[128]; + openvpn_snprintf(buf, sizeof(buf), + "Authentication failed, required pending auth " + "method '%s' not supported", pending_method); + auth_set_client_reason(multi, buf); + msg(M_INFO, "Client does not supported auth pending method " + "'%s'", pending_method); + ret = false; + } + else + { + send_auth_pending_messages(multi, BSTR(extra_buf), timeout); + } + } + + buffer_list_free(lines); + } + key_state_rm_auth_pending_file(ks); + return ret; +} + +/** + * Removes auth_pending and auth_control files from file system + * and key_state structure + */ void -key_state_rm_auth_control_file(struct key_state *ks) +key_state_rm_auth_control_files(struct key_state *ks) { if (ks && ks->auth_control_file) { @@ -879,23 +995,34 @@ key_state_rm_auth_control_file(struct key_state *ks) free(ks->auth_control_file); ks->auth_control_file = NULL; } + key_state_rm_auth_pending_file(ks); } +/** + * Generates and creates the control files used for deferred authentification + * in the temporary directory. + * + * @return true if file creation was successful + */ static bool -key_state_gen_auth_control_file(struct key_state *ks, const struct tls_options *opt) +key_state_gen_auth_control_files(struct key_state *ks, const struct tls_options *opt) { struct gc_arena gc = gc_new(); - key_state_rm_auth_control_file(ks); + key_state_rm_auth_control_files(ks); const char *acf = platform_create_temp_file(opt->tmp_dir, "acf", &gc); - if (acf) + const char *apf = platform_create_temp_file(opt->tmp_dir, "apf", &gc); + + if (acf && apf) { ks->auth_control_file = string_alloc(acf, NULL); + ks->auth_pending_file = string_alloc(apf, NULL); setenv_str(opt->es, "auth_control_file", ks->auth_control_file); + setenv_str(opt->es, "auth_pending_file", ks->auth_pending_file); } gc_free(&gc); - return acf; + return (acf && apf); } static unsigned int @@ -1140,7 +1267,7 @@ verify_user_pass_plugin(struct tls_session *session, struct tls_multi *multi, setenv_str(session->opt->es, "password", up->password); /* generate filename for deferred auth control file */ - if (!key_state_gen_auth_control_file(ks, session->opt)) + if (!key_state_gen_auth_control_files(ks, session->opt)) { msg(D_TLS_ERRORS, "TLS Auth Error (%s): " "could not create deferred auth control file", __func__); @@ -1150,10 +1277,20 @@ verify_user_pass_plugin(struct tls_session *session, struct tls_multi *multi, /* call command */ retval = plugin_call(session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL, session->opt->es); - /* purge auth control filename (and file itself) for non-deferred returns */ - if (retval != OPENVPN_PLUGIN_FUNC_DEFERRED) + if (retval == OPENVPN_PLUGIN_FUNC_DEFERRED) + { + /* Check if we the plugin has written the pending auth control + * file and send the pending auth to the client */ + if(!key_state_check_auth_pending_file(ks, multi)) + { + retval = OPENVPN_PLUGIN_FUNC_ERROR; + key_state_rm_auth_control_files(ks); + } + } + else { - key_state_rm_auth_control_file(ks); + /* purge auth control filename (and file itself) for non-deferred returns */ + key_state_rm_auth_control_files(ks); } setenv_del(session->opt->es, "password"); @@ -1224,7 +1361,7 @@ set_verify_user_pass_env(struct user_pass *up, struct tls_multi *multi, } } -/* +/** * Main username/password verification entry point * * Will set session->ks[KS_PRIMARY].authenticated according to diff --git a/src/openvpn/ssl_verify.h b/src/openvpn/ssl_verify.h index 7e8b9710..0221e81f 100644 --- a/src/openvpn/ssl_verify.h +++ b/src/openvpn/ssl_verify.h @@ -117,7 +117,7 @@ tls_authentication_status(struct tls_multi *multi, const int latency); * * @param ks The key state the remove the file for */ -void key_state_rm_auth_control_file(struct key_state *ks); +void key_state_rm_auth_control_files(struct key_state *ks); /** * Frees the given set of certificate hashes. From patchwork Mon Jan 25 01:56:26 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 1571 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director11.mail.ord1d.rsapps.net ([172.28.255.1]) by backend30.mail.ord1d.rsapps.net with LMTP id kLLYBzXADmCRQgAAIUCqbw (envelope-from ) for ; Mon, 25 Jan 2021 07:57:25 -0500 Received: from proxy7.mail.ord1c.rsapps.net ([172.28.255.1]) by director11.mail.ord1d.rsapps.net with LMTP id QK7NBzXADmA7fgAAvGGmqA (envelope-from ) for ; Mon, 25 Jan 2021 07:57:25 -0500 Received: from smtp1.gate.ord1c ([172.28.255.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy7.mail.ord1c.rsapps.net with LMTPS id KHtuBzXADmBDeAAAknS3pQ (envelope-from ) for ; Mon, 25 Jan 2021 07:57:25 -0500 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: smtp1.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=none (p=nil; dis=none) header.from=rfc2549.org X-Suspicious-Flag: YES X-Classification-ID: de5b6990-5f0c-11eb-8191-842b2b47c027-1-1 Received: from [216.105.38.7] ([216.105.38.7:54638] helo=lists.sourceforge.net) by smtp1.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id BA/D5-29904-430CE006; Mon, 25 Jan 2021 07:57:24 -0500 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 1l41QH-0006FO-C9; Mon, 25 Jan 2021 12:56:49 +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 1l41QC-0006Es-2e for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:44 +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:To: From:Sender:Reply-To:Cc: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=J01Vz4Iz0aO1zURP57e2Q9ulk24JBHOKRbahV7KWV8U=; b=ajXlWh036xchPZBFNo18S/J0EG dj9fTZhwVhiSqMjMTTjVCbbNqmiI4SO3EbrOv9AsAJF1A3JaOVGn+fZWqeb1mMWAUXNh33nX/fLBe pObYrkqCcWe1R93Kh0tG2T26Nai6y11KobUvSYiCXMsXzncmbEfbsGhTogroDYWPLevc=; 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:To:From:Sender:Reply-To:Cc :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=J01Vz4Iz0aO1zURP57e2Q9ulk24JBHOKRbahV7KWV8U=; b=KE5f2hXECSqEsiCpl8S8ZIhtv5 tC5wqIabDH8UqHLnGXsFq+mBjBtc+X/t69pi9hD5PwhdP6OfZjIIgPm2Lvl4CmiGu/hWiDevFpfpb SemR2M4UQW5bq5t5nzk2FxXLv/rv7AiCZjNOYkGusva7ibAKOPLUNs+xLYJjZgdRIyzc=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.2) id 1l41Q3-002esq-Vz for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:43 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.94 (FreeBSD)) (envelope-from ) id 1l41Px-0007XF-Ay for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 13:56:29 +0100 Received: (nullmailer pid 30435 invoked by uid 10006); Mon, 25 Jan 2021 12:56:29 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Mon, 25 Jan 2021 13:56:26 +0100 Message-Id: <20210125125628.30364-10-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210125125628.30364-1-arne@rfc2549.org> References: <20210125125628.30364-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 0.0 SPF_NONE SPF: sender does not publish an SPF Record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record X-Headers-End: 1l41Q3-002esq-Vz Subject: [Openvpn-devel] [PATCH v2 09/11] Implement deferred auth for scripts 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 This patch also refactors the if condition that checks the result of the authentication since that has become quite unreadable. It renames s1/s2 and extracts some parts of the condition into individual variables to make the condition better understandle Patch V2: add refactoring of the if condition Signed-off-by: Arne Schwabe --- Changes.rst | 12 ++++ doc/man-sections/script-options.rst | 14 ++++- src/openvpn/ssl.c | 2 - src/openvpn/ssl_verify.c | 86 +++++++++++++++++++++-------- 4 files changed, 89 insertions(+), 25 deletions(-) diff --git a/Changes.rst b/Changes.rst index 2a2829e7..188bd8ab 100644 --- a/Changes.rst +++ b/Changes.rst @@ -9,6 +9,18 @@ Keying Material Exporters (RFC 5705) based key generation the RFC5705 based key material generation to the current custom OpenVPN PRF. This feature requires OpenSSL or mbed TLS 2.18+. +Deferred auth support for scripts + The ``--auth-user-pass-verify`` script supports now deferred authentication. + +Pending auth support for plugins and scripts + Both auth plugin and script can now signal pending authentication to + the client when using deferred authentication. The new ``client-crresponse`` + script option and ``OPENVPN_PLUGIN_CLIENT_CRRESPONSE`` plugin function can + be used to parse a client response to a ``CR_TEXT`` two factor challenge. + + See ``sample/sample-scripts/totpauth.py`` for an example. + + Overview of changes in 2.5 ========================== diff --git a/doc/man-sections/script-options.rst b/doc/man-sections/script-options.rst index 03b3dd77..50edd986 100644 --- a/doc/man-sections/script-options.rst +++ b/doc/man-sections/script-options.rst @@ -90,7 +90,19 @@ SCRIPT HOOKS The script should examine the username and password, returning a success exit code (:code:`0`) if the client's authentication request is to be - accepted, or a failure code (:code:`1`) to reject the client. + accepted, a failure code (:code:`1`) to reject the client, or a that + the authentication is deferred (:code:`2`). If the authentication is + deferred, the script must fork/start a background or another non-blocking + operation to continue the authentication in the background. When finshing + the authentication, a :code:`1` or :code:`0` must be written to the + file specified by the :code:`auth_control_file`. + + When deferred authentication is in use, the script can also request + pending authentication by writing to the file specified by the + :code:`auth_pending_file`. The first line must be the timeout in + seconds and the second line the EXTRA as documented in the + ``client-pending-auth`` section of `doc/management.txt`. + This directive is designed to enable a plugin-style interface for extending OpenVPN's authentication capabilities. diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index b8e77f0e..699b7347 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -992,9 +992,7 @@ key_state_free(struct key_state *ks, bool clear) packet_id_free(&ks->crypto_options.packet_id); -#ifdef PLUGIN_DEF_AUTH key_state_rm_auth_control_files(ks); -#endif if (clear) { diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index b9647c1a..fc9f1d2e 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -1188,14 +1188,14 @@ tls_authenticate_key(struct tls_multi *multi, const unsigned int mda_key_id, con /* * Verify the user name and password using a script */ -static bool +static int verify_user_pass_script(struct tls_session *session, struct tls_multi *multi, const struct user_pass *up) { struct gc_arena gc = gc_new(); struct argv argv = argv_new(); const char *tmp_file = ""; - bool ret = false; + int retval = OPENVPN_PLUGIN_FUNC_ERROR; /* Set environmental variables prior to calling script */ setenv_str(session->opt->es, "script_type", "user-pass-verify"); @@ -1223,25 +1223,61 @@ verify_user_pass_script(struct tls_session *session, struct tls_multi *multi, /* pass temp file name to script */ argv_printf_cat(&argv, "%s", tmp_file); } - else - { - msg(D_TLS_ERRORS, "TLS Auth Error: could not create write " - "username/password to temp file"); - } } else { + setenv_str(session->opt->es, "username", up->username); setenv_str(session->opt->es, "password", up->password); } + /* generate filename for deferred auth control file */ + if (!key_state_gen_auth_control_files(&session->key[KS_PRIMARY], + session->opt)) + { + msg(D_TLS_ERRORS, "TLS Auth Error (%s): " + "could not create deferred auth control file", __func__); + return OPENVPN_PLUGIN_FUNC_ERROR; + } + /* call command */ - ret = openvpn_run_script(&argv, session->opt->es, 0, - "--auth-user-pass-verify"); + int script_ret = openvpn_run_script(&argv, session->opt->es, S_EXITCODE, + "--auth-user-pass-verify"); + switch (script_ret) + { + case 0: + retval = OPENVPN_PLUGIN_FUNC_SUCCESS; + break; + case 2: + retval = OPENVPN_PLUGIN_FUNC_DEFERRED; + break; + default: + retval = OPENVPN_PLUGIN_FUNC_ERROR; + break; + } +#ifdef ENABLE_DEF_AUTH + if (retval == OPENVPN_PLUGIN_FUNC_DEFERRED) + { + /* Check if we the plugin has written the pending auth control + * file and send the pending auth to the client */ + if(!key_state_check_auth_pending_file(&session->key[KS_PRIMARY], + multi)) + { + retval = OPENVPN_PLUGIN_FUNC_ERROR; + key_state_rm_auth_control_files(&session->key[KS_PRIMARY]); + } + } + else + { + /* purge auth control filename (and file itself) for non-deferred returns */ + key_state_rm_auth_control_files(&session->key[KS_PRIMARY]); + } +#endif if (!session->opt->auth_user_pass_verify_script_via_file) { setenv_del(session->opt->es, "password"); } + done: if (tmp_file && strlen(tmp_file) > 0) { @@ -1250,7 +1286,7 @@ done: argv_free(&argv); gc_free(&gc); - return ret; + return retval; } /* @@ -1371,8 +1407,6 @@ void verify_user_pass(struct user_pass *up, struct tls_multi *multi, struct tls_session *session) { - int s1 = OPENVPN_PLUGIN_FUNC_SUCCESS; - bool s2 = true; struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ #ifdef ENABLE_MANAGEMENT @@ -1432,30 +1466,32 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, } } + int plugin_status = OPENVPN_PLUGIN_FUNC_SUCCESS; + int script_status = OPENVPN_PLUGIN_FUNC_SUCCESS; /* Set the environment variables used by all auth variants */ if (!set_verify_user_pass_env(up, multi, session)) { skip_auth = true; - s1 = OPENVPN_PLUGIN_FUNC_ERROR; + plugin_status = OPENVPN_PLUGIN_FUNC_ERROR; } /* call plugin(s) and/or script */ if (!skip_auth) { #ifdef ENABLE_MANAGEMENT - if (man_def_auth==KMDA_DEF) + if (man_def_auth == KMDA_DEF) { man_def_auth = verify_user_pass_management(session, multi, up); } #endif if (plugin_defined(session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)) { - s1 = verify_user_pass_plugin(session, multi, up); + plugin_status = verify_user_pass_plugin(session, multi, up); } if (session->opt->auth_user_pass_verify_script) { - s2 = verify_user_pass_script(session, multi, up); + script_status = verify_user_pass_script(session, multi, up); } } @@ -1466,19 +1502,25 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, msg(D_TLS_ERRORS, "TLS Auth Error: --username-as-common name specified and username is longer than the maximum permitted Common Name length of %d characters", TLS_USERNAME_LEN); - s1 = OPENVPN_PLUGIN_FUNC_ERROR; + plugin_status = OPENVPN_PLUGIN_FUNC_ERROR; + script_status = OPENVPN_PLUGIN_FUNC_ERROR; } /* auth succeeded? */ - if ((s1 == OPENVPN_PLUGIN_FUNC_SUCCESS - || s1 == OPENVPN_PLUGIN_FUNC_DEFERRED - ) && s2 + bool plugin_ok = plugin_status == OPENVPN_PLUGIN_FUNC_SUCCESS + || plugin_status == OPENVPN_PLUGIN_FUNC_DEFERRED; + + bool script_ok = script_status == OPENVPN_PLUGIN_FUNC_SUCCESS + || script_status == OPENVPN_PLUGIN_FUNC_DEFERRED; + + if (script_ok && plugin_ok && tls_lock_username(multi, up->username) #ifdef ENABLE_MANAGEMENT && man_def_auth != KMDA_ERROR #endif - && tls_lock_username(multi, up->username)) + ) { ks->authenticated = KS_AUTH_TRUE; - if (s1 == OPENVPN_PLUGIN_FUNC_DEFERRED) + if (plugin_status == OPENVPN_PLUGIN_FUNC_DEFERRED + || script_status == OPENVPN_PLUGIN_FUNC_DEFERRED) { ks->authenticated = KS_AUTH_DEFERRED; } From patchwork Mon Jan 25 01:56:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 1577 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director7.mail.ord1d.rsapps.net ([172.30.191.6]) by backend30.mail.ord1d.rsapps.net with LMTP id sF5AEEfADmDzLgAAIUCqbw (envelope-from ) for ; Mon, 25 Jan 2021 07:57:43 -0500 Received: from proxy7.mail.ord1d.rsapps.net ([172.30.191.6]) by director7.mail.ord1d.rsapps.net with LMTP id COYuEEfADmDEOwAAovjBpQ (envelope-from ) for ; Mon, 25 Jan 2021 07:57:43 -0500 Received: from smtp8.gate.ord1c ([172.30.191.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy7.mail.ord1d.rsapps.net with LMTPS id CN/HD0fADmAKJAAAMe1Fpw (envelope-from ) for ; Mon, 25 Jan 2021 07:57:43 -0500 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: smtp8.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=none (p=nil; dis=none) header.from=rfc2549.org X-Suspicious-Flag: YES X-Classification-ID: e941b062-5f0c-11eb-b41d-782bcb03304b-1-1 Received: from [216.105.38.7] ([216.105.38.7:54942] helo=lists.sourceforge.net) by smtp8.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 91/A1-28123-640CE006; Mon, 25 Jan 2021 07:57:42 -0500 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 1l41QP-0006GN-Lr; Mon, 25 Jan 2021 12:56:57 +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 1l41QC-0006Er-1v for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:44 +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:To: From:Sender:Reply-To:Cc: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=byi/Gc1UKxk62HPmpc1gDTajj/BjHtAg6rC31OWtpL4=; b=cQsFFoUXghtjkYlz3aoboru7qv Bvtn6PR/um0enGLdqKm1W9KlcQ6icaErUTWC7EazOcGlN/wwCo1IHA3YwtfmGOQCQg2PmbXx3EqQW j8Gb3H+W/BKpY2wjGsTZFJLWp0MbDdxFrrmZxaHbBi2wSAhxadLxSkGWNS0sgNsG0kr0=; 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:To:From:Sender:Reply-To:Cc :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=byi/Gc1UKxk62HPmpc1gDTajj/BjHtAg6rC31OWtpL4=; b=YLB5txVVdflg1QP6J5NVXRL8nZ hVh9Lsj/yU8/UpdkpvnzWr4pHnhJhbTraUzz/dXcb+MWMCvvWgI7263KUzqTNdkLrdDplZrPp8whK fzaBzZ/0gqmxoF2yIyPgS3BCa0qdREiVbRrCDEB9Ge2lme8Ng0JYnbmHjrfNVNIfhoX4=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.2) id 1l41Q3-002esr-VU for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:43 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.94 (FreeBSD)) (envelope-from ) id 1l41Px-0007XI-DU for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 13:56:29 +0100 Received: (nullmailer pid 30438 invoked by uid 10006); Mon, 25 Jan 2021 12:56:29 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Mon, 25 Jan 2021 13:56:27 +0100 Message-Id: <20210125125628.30364-11-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210125125628.30364-1-arne@rfc2549.org> References: <20210125125628.30364-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 0.0 SPF_NONE SPF: sender does not publish an SPF Record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record X-Headers-End: 1l41Q3-002esr-VU Subject: [Openvpn-devel] [PATCH v2 10/11] Implement --client-crresponse script options and plugin interface 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 This is allows scripts and pluginsto parse/react to a CR_RESPONSE message Patch V2: doc fixes, do not put script under ENABLE_PLUGIN Signed-off-by: Arne Schwabe Acked-By: David Sommerseth --- doc/man-sections/script-options.rst | 28 ++++++++++++- include/openvpn-plugin.h.in | 7 +++- src/openvpn/init.c | 1 + src/openvpn/options.c | 15 +++++++ src/openvpn/options.h | 1 + src/openvpn/push.c | 4 ++ src/openvpn/ssl_common.h | 1 + src/openvpn/ssl_verify.c | 65 ++++++++++++++++++++++++++++- src/openvpn/ssl_verify.h | 23 ++++++++++ 9 files changed, 141 insertions(+), 4 deletions(-) diff --git a/doc/man-sections/script-options.rst b/doc/man-sections/script-options.rst index 50edd986..1d7118ae 100644 --- a/doc/man-sections/script-options.rst +++ b/doc/man-sections/script-options.rst @@ -52,6 +52,11 @@ Script Order of Execution Executed in ``--mode server`` mode on new client connections, when the client is still untrusted. +#. ``--client-crresponse`` + + Execute in ``--mode server`` whenever a client sends a + :code:`CR_RESPONSE` message + SCRIPT HOOKS ------------ @@ -72,7 +77,7 @@ SCRIPT HOOKS double-quoted and/or escaped using a backslash, and should be separated by one or more spaces. - If ``method`` is set to :code:`via-env`, OpenVPN will call ``script`` + If ``method`` is set to :code:`via-env`, OpenVPN will call ``cmd`` with the environmental variables :code:`username` and :code:`password` set to the username/password strings provided by the client. *Beware* that this method is insecure on some platforms which make the environment @@ -80,7 +85,7 @@ SCRIPT HOOKS If ``method`` is set to :code:`via-file`, OpenVPN will write the username and password to the first two lines of a temporary file. The filename - will be passed as an argument to ``script``, and the file will be + will be passed as an argument to ``cmd``, and the file will be automatically deleted by OpenVPN after the script returns. The location of the temporary file is controlled by the ``--tmp-dir`` option, and will default to the current directory if unspecified. For security, @@ -123,6 +128,25 @@ SCRIPT HOOKS For a sample script that performs PAM authentication, see :code:`sample-scripts/auth-pam.pl` in the OpenVPN source distribution. +--client-crresponse + Executed when the client sends a text based challenge response. + + Valid syntax: + :: + + client-crresponse cmd + + OpenVPN will write the response of the client into a temporary file. + The filename will be passed as an argument to ``cmd``, and the file will be + automatically deleted by OpenVPN after the script returns. + + The response is passed as is from the client. The script needs to check + itself if the input is valid, e.g. if the input is valid base64 encoding. + + The script can either directly write the result of the verification to + :code:`auth_control_file or further defer it. See ``--auth-user-pass-verify`` + for details. + --client-connect cmd Run command ``cmd`` on client connection. diff --git a/include/openvpn-plugin.h.in b/include/openvpn-plugin.h.in index bb561643..62e3c3b7 100644 --- a/include/openvpn-plugin.h.in +++ b/include/openvpn-plugin.h.in @@ -84,6 +84,10 @@ extern "C" { * FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_CLIENT_CONNECT_V2 * FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_LEARN_ADDRESS * + * The OPENVPN_PLUGIN_CLIENT_CRRESPONSE function is called when the client sends + * the CR_RESPONSE message, this is *typically* after OPENVPN_PLUGIN_TLS_FINAL + * but may also occur much later. + * * [Client session ensues] * * For each "TLS soft reset", according to reneg-sec option (or similar): @@ -131,7 +135,8 @@ extern "C" { #define OPENVPN_PLUGIN_ROUTE_PREDOWN 12 #define OPENVPN_PLUGIN_CLIENT_CONNECT_DEFER 13 #define OPENVPN_PLUGIN_CLIENT_CONNECT_DEFER_V2 14 -#define OPENVPN_PLUGIN_N 15 +#define OPENVPN_PLUGIN_CLIENT_CRRESPONSE 15 +#define OPENVPN_PLUGIN_N 16 /* * Build a mask out of a set of plug-in types. diff --git a/src/openvpn/init.c b/src/openvpn/init.c index c3493c42..4e753657 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2948,6 +2948,7 @@ do_init_crypto_tls(struct context *c, const unsigned int flags) to.auth_user_pass_verify_script = options->auth_user_pass_verify_script; to.auth_user_pass_verify_script_via_file = options->auth_user_pass_verify_script_via_file; + to.client_crresponse_script = options->client_crresponse_script; to.tmp_dir = options->tmp_dir; if (options->ccd_exclusive) { diff --git a/src/openvpn/options.c b/src/openvpn/options.c index b81137cf..2290bc12 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -1284,6 +1284,7 @@ show_p2mp_parms(const struct options *o) SHOW_STR(client_connect_script); SHOW_STR(learn_address_script); SHOW_STR(client_disconnect_script); + SHOW_STR(client_crresponse_script); SHOW_STR(client_config_dir); SHOW_BOOL(ccd_exclusive); SHOW_STR(tmp_dir); @@ -2465,6 +2466,10 @@ options_postprocess_verify_ce(const struct options *options, { msg(M_USAGE, "--client-connect requires --mode server"); } + if (options->client_crresponse_script) + { + msg(M_USAGE, "--client-crresponse requires --mode server"); + } if (options->client_disconnect_script) { msg(M_USAGE, "--client-disconnect requires --mode server"); @@ -7094,6 +7099,16 @@ add_option(struct options *options, set_user_script(options, &options->client_connect_script, p[1], "client-connect", true); } + else if (streq(p[0], "client-crresponse") && p[1]) + { + VERIFY_PERMISSION(OPT_P_SCRIPT); + if (!no_more_than_n_args(msglevel, p, 2, NM_QUOTE_HINT)) + { + goto err; + } + set_user_script(options, &options->client_crresponse_script, + p[1], "client-crresponse", true); + } else if (streq(p[0], "client-disconnect") && p[1]) { VERIFY_PERMISSION(OPT_P_SCRIPT); diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 5b6d9441..e79efe32 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -440,6 +440,7 @@ struct options const char *client_connect_script; const char *client_disconnect_script; const char *learn_address_script; + const char *client_crresponse_script; const char *client_config_dir; bool ccd_exclusive; bool disable; diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 320ad737..94a85ce3 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -228,6 +228,10 @@ receive_cr_response(struct context *c, const struct buffer *buffer) management_notify_client_cr_response(key_id, mda, es, m); #endif +#if ENABLE_PLUGIN + verify_crresponse_plugin(c->c2.tls_multi, m); +#endif + verify_crresponse_script(c->c2.tls_multi, m); msg(D_PUSH, "CR response was sent by client ('%s')", m); } diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index b493cbb7..1e43ed10 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -316,6 +316,7 @@ struct tls_options /* used for username/password authentication */ const char *auth_user_pass_verify_script; + const char *client_crresponse_script; bool auth_user_pass_verify_script_via_file; const char *tmp_dir; const char *auth_user_pass_file; diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index fc9f1d2e..ac4492ef 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -1232,7 +1232,7 @@ verify_user_pass_script(struct tls_session *session, struct tls_multi *multi, /* generate filename for deferred auth control file */ if (!key_state_gen_auth_control_files(&session->key[KS_PRIMARY], - session->opt)) + session->opt)) { msg(D_TLS_ERRORS, "TLS Auth Error (%s): " "could not create deferred auth control file", __func__); @@ -1289,6 +1289,69 @@ done: return retval; } +void +verify_crresponse_plugin(struct tls_multi *multi, const char *cr_response) +{ + struct tls_session *session = &multi->session[TM_ACTIVE]; + setenv_str(session->opt->es, "crresponse", cr_response); + + plugin_call(session->opt->plugins, OPENVPN_PLUGIN_CLIENT_CRRESPONSE, NULL, + NULL, session->opt->es); + + setenv_del(session->opt->es, "crresponse"); + +} +void +verify_crresponse_script(struct tls_multi *multi, const char *cr_response) +{ + + struct tls_session *session = &multi->session[TM_ACTIVE]; + + if (!session->opt->client_crresponse_script) + { + return; + } + struct argv argv = argv_new(); + struct gc_arena gc = gc_new(); + + setenv_str(session->opt->es, "script_type", "client-crresponse"); + + /* Since cr response might be sensitive, like a stupid way to query + * a password via 2FA, we pass it via file instead environment */ + const char *tmp_file = platform_create_temp_file(session->opt->tmp_dir, "cr", &gc); + if (tmp_file) + { + struct status_output *so = status_open(tmp_file, 0, -1, NULL, + STATUS_OUTPUT_WRITE); + status_printf(so, "%s", cr_response); + if (!status_close(so)) + { + msg(D_TLS_ERRORS, "TLS CR Response Error: could not write cr" + "responsed to file: %s", + tmp_file); + tls_deauthenticate(multi); + goto done; + } + } + else + { + msg(D_TLS_ERRORS, "TLS Auth Error: could not create write " + "username/password to temp file"); + } + + argv_parse_cmd(&argv, session->opt->client_crresponse_script); + argv_printf_cat(&argv, "%s", tmp_file); + + + if (!openvpn_run_script(&argv, session->opt->es, 0, "--client-crresponse")) + { + tls_deauthenticate(multi); + } +done: + argv_free(&argv); + gc_free(&gc); +} + /* * Verify the username and password using a plugin */ diff --git a/src/openvpn/ssl_verify.h b/src/openvpn/ssl_verify.h index 0221e81f..30ab8a1d 100644 --- a/src/openvpn/ssl_verify.h +++ b/src/openvpn/ssl_verify.h @@ -209,6 +209,29 @@ tls_common_name_hash(const struct tls_multi *multi, const char **cn, uint32_t *c void verify_user_pass(struct user_pass *up, struct tls_multi *multi, struct tls_session *session); + + +/** + * Runs the --client-crresponse script if one is defined. + * + * As with the management interface the script is stateless in the sense that + * it does not directly participate in the authentication but rather should set + * the files for the deferred auth like the management commands. + * + */ +void +verify_crresponse_script(struct tls_multi *multi, const char *cr_response); + +/** + * Call the plugin OPENVPN_PLUGIN_CLIENT_CRRESPONSE. + * + * As with the management interface calling the plugin is stateless in the sense + * that it does not directly participate in the authentication but rather + * should set the files for the deferred auth like the management commands. + */ +void +verify_crresponse_plugin(struct tls_multi *multi, const char *cr_response); + /** * Perform final authentication checks, including locking of the cn, the allowed * certificate hashes, and whether a client config entry exists in the From patchwork Mon Jan 25 01:56:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 1573 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director12.mail.ord1d.rsapps.net ([172.27.255.53]) by backend30.mail.ord1d.rsapps.net with LMTP id IAaaEj7ADmDzLgAAIUCqbw (envelope-from ) for ; Mon, 25 Jan 2021 07:57:34 -0500 Received: from proxy13.mail.iad3a.rsapps.net ([172.27.255.53]) by director12.mail.ord1d.rsapps.net with LMTP id YP12Ej7ADmAvbAAAIasKDg (envelope-from ) for ; Mon, 25 Jan 2021 07:57:34 -0500 Received: from smtp31.gate.iad3a ([172.27.255.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy13.mail.iad3a.rsapps.net with LMTPS id 0F7oCz7ADmCTDAAAwhxzoA (envelope-from ) for ; Mon, 25 Jan 2021 07:57:34 -0500 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: smtp31.gate.iad3a.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=none (p=nil; dis=none) header.from=rfc2549.org X-Suspicious-Flag: YES X-Classification-ID: e3c12208-5f0c-11eb-8147-5254003d9392-1-1 Received: from [216.105.38.7] ([216.105.38.7:37012] helo=lists.sourceforge.net) by smtp31.gate.iad3a.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 82/78-05487-D30CE006; Mon, 25 Jan 2021 07:57:33 -0500 Received: from [127.0.0.1] (helo=sfs-ml-4.v29.lw.sourceforge.com) by sfs-ml-4.v29.lw.sourceforge.com with esmtp (Exim 4.90_1) (envelope-from ) id 1l41QR-0001n3-Eb; Mon, 25 Jan 2021 12:56:59 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1l41QF-0001m7-2q for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:47 +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:To: From:Sender:Reply-To:Cc: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=AaLExEK5DruN9bLqioAKMTDMdwnBzMOjlLsbchqmC+U=; b=W+/Od0Gl028I7uR0XFjoHFXT2s /zQAalthbyW35VPgsLIWHqkeST/1189rt1vBeWKfqPOHb3b0x4iV/khIgn9WGqLCXYEHl8sk3raeo AOzy+xrkBDyiS0cE1b3ElJtqdS79xinB3REPTGhDqm0RP2G/HY7GpYQqI31SKYuQ1oz4=; 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:To:From:Sender:Reply-To:Cc :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=AaLExEK5DruN9bLqioAKMTDMdwnBzMOjlLsbchqmC+U=; b=Sm+TOyWo3vIvz3QenArjEc0Bwu l94Y2xzjzFhbCU5+Q/CP7G/kPiLqXJ+QLaZCPsmFdBe6Ml+Pp0cjzifjrm/LMvI5j8o0niSM/R4UW IYVRuPsc2eXMDxp0DrytsYWkjwSR58Gf4Uig+1Rgpj6rA2H55eKSuC4Ti78xwlFazKxk=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-3.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.2) id 1l41QB-006gWw-9K for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 12:56:47 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.94 (FreeBSD)) (envelope-from ) id 1l41Px-0007XL-Fg for openvpn-devel@lists.sourceforge.net; Mon, 25 Jan 2021 13:56:29 +0100 Received: (nullmailer pid 30441 invoked by uid 10006); Mon, 25 Jan 2021 12:56:29 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Mon, 25 Jan 2021 13:56:28 +0100 Message-Id: <20210125125628.30364-12-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210125125628.30364-1-arne@rfc2549.org> References: <20210125125628.30364-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 0.0 SPF_NONE SPF: sender does not publish an SPF Record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record X-Headers-End: 1l41QB-006gWw-9K Subject: [Openvpn-devel] [PATCH v2 11/11] Add example script demonstrating TOTP via auth-pending 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 Signed-off-by: Arne Schwabe --- Changes.rst | 9 +++ doc/man-sections/script-options.rst | 3 + sample/sample-scripts/totpauth.py | 107 ++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100755 sample/sample-scripts/totpauth.py diff --git a/Changes.rst b/Changes.rst index 188bd8ab..d64c6d83 100644 --- a/Changes.rst +++ b/Changes.rst @@ -19,6 +19,15 @@ Pending auth support for plugins and scripts be used to parse a client response to a ``CR_TEXT`` two factor challenge. See ``sample/sample-scripts/totpauth.py`` for an example. +<<<<<<< HEAD +======= + +Deprecated features +------------------- +``inetd`` has been removed + This was a very limited and not-well-tested way to run OpenVPN, on TCP + and TAP mode only. +>>>>>>> 239e8cfd (Add example script demonstrating TOTP via auth-pending) Overview of changes in 2.5 diff --git a/doc/man-sections/script-options.rst b/doc/man-sections/script-options.rst index 1d7118ae..05815020 100644 --- a/doc/man-sections/script-options.rst +++ b/doc/man-sections/script-options.rst @@ -147,6 +147,9 @@ SCRIPT HOOKS :code:`auth_control_file or further defer it. See ``--auth-user-pass-verify`` for details. + For a sample script that implement TOTP (RFC 6238) based two-factor + authentication, see :code:`sample-scripts/totp.py`. + --client-connect cmd Run command ``cmd`` on client connection. diff --git a/sample/sample-scripts/totpauth.py b/sample/sample-scripts/totpauth.py new file mode 100755 index 00000000..95ac3529 --- /dev/null +++ b/sample/sample-scripts/totpauth.py @@ -0,0 +1,107 @@ +#! /usr/bin/python3 +# Copyright (c) 2020 OpenVPN Inc +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import sys +import os +from base64 import standard_b64decode + +import pyotp + +import pprint + +# Example script demonstrating how to use the auth-pending API in +# OpenVPN. This script is provided under MIT license to allow easy +# modification for other purposes. +# +# To use this script add the following lines in the openvpn config + +# client-crresponse /path/to/totpauth.py +# auth-user-pass-verify /path/to/totpauth.py via-file +# auth-user-pass-optional +# auth-gen-token + +# Note that this script does NOT verify username/password +# It is only meant for querying additional 2FA when certificates are +# used to authenticate + +secrets = {"styx": "OS6JDNRK2BNUPQVX", + "apate": "IXWEMP7SK2QWSHTG"} + + +def main(): + # Get common name and script type from environment + script_type = os.environ['script_type'] + cn = os.environ['common_name'] + + if script_type == 'user-pass-verify': + # signal text based challenge response + + if cn in secrets: + extra = "CR_TEXT:E,R:Please enter your TOTP code!" + write_auth_pending(300, 'crtext', extra) + + # Signal authentication being deferred + sys.exit(2) + else: + # For unkown CN we report failure. Change to 0 + # to allow CNs without secret to auth without 2FA + sys.exit(1) + + elif script_type == 'client-crresponse': + response = None + + # Read the crresponse from the argument file + # and convert it into text. A failure because of bad user + # input (e.g. invalid base64) will make the script throw + # an error and make OpenVPN return AUTH_FAILED + with open(sys.argv[1], 'r') as crinput: + response = crinput.read() + response = standard_b64decode(response) + response = response.decode().strip() + + if cn not in secrets: + write_auth_control(1) + return + + totp = pyotp.TOTP(secrets[cn]) + + # Check if the code is valid (and also allow code +/-1) + if totp.verify(response, valid_window=1): + write_auth_control(1) + else: + write_auth_control(0) + else: + print(f"Unknown script type {script_type}") + sys.exit(1) + + +def write_auth_control(status): + with open(os.environ['auth_control_file'], 'w') as auth_control: + auth_control.write("%d" % status) + + +def write_auth_pending(timeout, method, extra): + with open(os.environ['auth_pending_file'], 'w') as auth_pending: + auth_pending.write("%d\n%s\n%s" % (timeout, method, extra)) + + +if __name__ == '__main__': + main()