From patchwork Fri May 20 11:32:47 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 2488 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director13.mail.ord1d.rsapps.net ([172.28.255.1]) by backend41.mail.ord1d.rsapps.net with LMTP id 8KrKF10JiGLMSQAAqwncew (envelope-from ) for ; Fri, 20 May 2022 17:34:21 -0400 Received: from proxy8.mail.ord1c.rsapps.net ([172.28.255.1]) by director13.mail.ord1d.rsapps.net with LMTP id OBuXOF0JiGLWDgAA91zNiA (envelope-from ) for ; Fri, 20 May 2022 17:34:21 -0400 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 yH8vOF0JiGIOQQAAHz/atg (envelope-from ) for ; Fri, 20 May 2022 17:34:21 -0400 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO X-Virus-Scanned: OK X-Orig-To: openvpnslackdevel@openvpn.net X-Originating-Ip: [216.105.38.7] Authentication-Results: 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: 9c03d2ec-d884-11ec-9058-54520067fec4-1-1 Received: from [216.105.38.7] ([216.105.38.7:41384] 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 E4/B4-00371-D5908826; Fri, 20 May 2022 17:34:21 -0400 Received: from [127.0.0.1] (helo=sfs-ml-1.v29.lw.sourceforge.com) by sfs-ml-1.v29.lw.sourceforge.com with esmtp (Exim 4.94.2) (envelope-from ) id 1nsAFD-0008Kl-Ko; Fri, 20 May 2022 21:33:12 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-1.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1nsAFA-0008KS-IE for openvpn-devel@lists.sourceforge.net; Fri, 20 May 2022 21:33:09 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type: 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=OLoChQtJiA0S9ua3Yx+nGScVL8ITIr8CXuPMd6mmGIE=; b=aZzCVgrI6J7uoIEQxcq1Hte2mr bMnNtagtZqNwqsQlhXy6SpCEuVPiFLqE+ZrCKEDfcVkTWe0o0DwtH6npUSiIKAgH5S7OrjsPPo0Sp a/Hmsms/JzKsUPLQ0FWZju9RD/bkknIweGAyYy7bDssTb9Rb9IpfNHbZGRQSISUcLWAc=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id: Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type: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=OLoChQtJiA0S9ua3Yx+nGScVL8ITIr8CXuPMd6mmGIE=; b=h6k/q5hWgN7apt+tXK+7PjVKWz QhVCuQPhHngzav9cEJvEP8R8ZHwnriycC66ItMQKrNmAa2Oam6O6Mgc1/diljJgo7O/+C8CWqAkfn jkcoJ/AY2jCuQ2OQ+K0/NyGvU43RDFSzEoEgcB4aI+G2HmJXbbbXJPDB7a8WwDuxruyQ=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.94.2) id 1nsAF9-0005EO-Jx for openvpn-devel@lists.sourceforge.net; Fri, 20 May 2022 21:33:08 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.95 (FreeBSD)) (envelope-from ) id 1nsAEt-0005Sf-En for openvpn-devel@lists.sourceforge.net; Fri, 20 May 2022 23:32:51 +0200 Received: (nullmailer pid 3126423 invoked by uid 10006); Fri, 20 May 2022 21:32:51 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Fri, 20 May 2022 23:32:47 +0200 Message-Id: <20220520213250.3126372-2-arne@rfc2549.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220520213250.3126372-1-arne@rfc2549.org> References: <20220520213250.3126372-1-arne@rfc2549.org> MIME-Version: 1.0 X-Spam-Report: Spam detection software, running on the system "util-spamd-1.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Current exit notification relies on data channel messages with specific prefix. Adding these to new data channel modules (DCO) adds unncessary complexity for the data for messages that from their idea [...] Content analysis details: (0.3 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 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 X-Headers-End: 1nsAF9-0005EO-Jx Subject: [Openvpn-devel] [PATCH v2 1/4] Implement exit notification via control channel 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: , Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox Current exit notification relies on data channel messages with specific prefix. Adding these to new data channel modules (DCO) adds unncessary complexity for the data for messages that from their idea belong to the control channel anyway. This patch adds announcing support for control channel and sending/receving it. We use the simple EXIT message for this. Patch V2: add comment about protocol-flags to be not a user visible option, fix various grammar mistakes, remove unused argument to receive_exit_message --- doc/man-sections/client-options.rst | 7 ++++++- src/openvpn/crypto.h | 5 +++++ src/openvpn/forward.c | 4 ++++ src/openvpn/multi.c | 5 +++++ src/openvpn/options.c | 20 ++++++++++++++++++++ src/openvpn/push.c | 19 +++++++++++++++++++ src/openvpn/push.h | 2 ++ src/openvpn/sig.c | 27 +++++++++++++++++++++++++-- src/openvpn/ssl.c | 3 +++ src/openvpn/ssl.h | 3 +++ src/openvpn/ssl_ncp.c | 5 +++++ 11 files changed, 97 insertions(+), 3 deletions(-) diff --git a/doc/man-sections/client-options.rst b/doc/man-sections/client-options.rst index 8e0e4f18a..5a906895b 100644 --- a/doc/man-sections/client-options.rst +++ b/doc/man-sections/client-options.rst @@ -220,9 +220,14 @@ configuration. immediately close its client instance object rather than waiting for a timeout. + If both server and client support sending this message using the control + channel, the message will be sent as control-channel message. Otherwise + the message is sent as data-channel message, which will be ignored by + data-channel offloaded peers. + The **n** parameter (default :code:`1` if not present) controls the maximum number of attempts that the client will try to resend the exit - notification message. + notification message if messages are sent in data-channel mode. In UDP server mode, send :code:`RESTART` control channel command to connected clients. The ``n`` parameter (default :code:`1` if not present) diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index 98e2c7664..5ea889081 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -264,6 +264,11 @@ struct crypto_options /**< Bit-flag indicating that we do not allow clients that do * not support resending the wrapped client key (WKc) with the * third packet of the three-way handshake */ +#define CO_USE_CC_EXIT_NOTIFY (1<<6) + /**< Bit-flag indicating that explicit exit notifies should be + * sent via the control channel instead of using an OCC message + */ + unsigned int flags; /**< Bit-flags determining behavior of * security operation functions. */ }; diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 6afe152b4..4fb3a20d7 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -241,6 +241,10 @@ check_incoming_control_channel(struct context *c) { receive_auth_pending(c, &buf); } + else if (buf_string_match_head_str(&buf, "EXIT")) + { + receive_exit_message(c); + } else { msg(D_PUSH_ERRORS, "WARNING: Received unknown control message: %s", BSTR(&buf)); diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index ba2f6d581..e7c99f813 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1777,6 +1777,11 @@ multi_client_set_protocol_options(struct context *c) } #endif + if (proto & IV_PROTO_CC_EXIT_NOTIFY) + { + o->data_channel_crypto_flags |= CO_USE_CC_EXIT_NOTIFY; + } + /* Select cipher if client supports Negotiable Crypto Parameters */ /* if we have already created our key, we cannot *change* our own diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 9ff384d09..427d58392 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -8326,6 +8326,8 @@ add_option(struct options *options, } else if (streq(p[0], "key-derivation") && p[1]) { + /* NCP only option that is pushed by the server to enable EKM, + * should not be used by normal users in config files*/ VERIFY_PERMISSION(OPT_P_NCP) #ifdef HAVE_EXPORT_KEYING_MATERIAL if (streq(p[1], "tls-ekm")) @@ -8338,6 +8340,24 @@ add_option(struct options *options, msg(msglevel, "Unknown key-derivation method %s", p[1]); } } + else if (streq(p[0], "protocol-flags") && p[1]) + { + /* NCP only option that is pushed by the server to enable protocol + * features that are negotiated, should not be used by normal users + * in config files */ + VERIFY_PERMISSION(OPT_P_NCP) + for (size_t j = 1; j < MAX_PARMS && p[j] != NULL; j++) + { + if (streq(p[j], "cc-exit")) + { + options->data_channel_crypto_flags |= CO_USE_CC_EXIT_NOTIFY; + } + else + { + msg(msglevel, "Unknown protocol-flags flag: %s", p[j]); + } + } + } else if (streq(p[0], "prng") && p[1] && !p[3]) { msg(M_WARN, "NOTICE: --prng option ignored (SSL library PRNG is used)"); diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 70fd1c3ce..fa0def7f8 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -176,6 +176,21 @@ server_pushed_signal(struct context *c, const struct buffer *buffer, const bool } } +void +receive_exit_message(struct context *c) +{ + dmsg(D_STREAM_ERRORS, "Exit message received by peer"); + c->sig->signal_received = SIGTERM; + c->sig->signal_text = "remote-exit"; +#ifdef ENABLE_MANAGEMENT + if (management) + { + management_notify(management, "info", c->sig->signal_text, "EXIT"); + } +#endif +} + + void server_pushed_info(struct context *c, const struct buffer *buffer, const int adv) @@ -604,6 +619,10 @@ prepare_push_reply(struct context *c, struct gc_arena *gc, { push_option_fmt(gc, push_list, M_USAGE, "key-derivation tls-ekm"); } + if (o->data_channel_crypto_flags & CO_USE_CC_EXIT_NOTIFY) + { + push_option_fmt(gc, push_list, M_USAGE, "protocol-flags cc-exit"); + } return true; } diff --git a/src/openvpn/push.h b/src/openvpn/push.h index 62fad4a14..7138055a7 100644 --- a/src/openvpn/push.h +++ b/src/openvpn/push.h @@ -48,6 +48,8 @@ void receive_auth_failed(struct context *c, const struct buffer *buffer); void server_pushed_signal(struct context *c, const struct buffer *buffer, const bool restart, const int adv); +void receive_exit_message(struct context *c); + void server_pushed_info(struct context *c, const struct buffer *buffer, const int adv); diff --git a/src/openvpn/sig.c b/src/openvpn/sig.c index e06edd216..d6683d2d1 100644 --- a/src/openvpn/sig.c +++ b/src/openvpn/sig.c @@ -321,20 +321,43 @@ print_status(const struct context *c, struct status_output *so) gc_free(&gc); } + +/* Small helper function to determine if we should send the exit notification + * via control channel */ +static inline bool +cc_exit_notify_enabled(struct context *c) +{ + /* Check if we have TLS active at all */ + if (!c->c2.tls_multi) + { + return false; + } + + const struct key_state *ks = get_primary_key(c->c2.tls_multi); + return (ks->crypto_options.flags & CO_USE_CC_EXIT_NOTIFY); +} + /* * Handle the triggering and time-wait of explicit * exit notification. */ - static void process_explicit_exit_notification_init(struct context *c) { msg(M_INFO, "SIGTERM received, sending exit notification to peer"); event_timeout_init(&c->c2.explicit_exit_notification_interval, 1, 0); reset_coarse_timers(c); + signal_reset(c->sig); halt_non_edge_triggered_signals(); c->c2.explicit_exit_notification_time_wait = now; + + /* Check if we are in TLS mode and should send the notification via data + * channel */ + if (cc_exit_notify_enabled(c)) + { + send_control_channel_string(c, "EXIT", D_PUSH); + } } void @@ -351,7 +374,7 @@ process_explicit_exit_notification_timer_wakeup(struct context *c) c->sig->signal_received = SIGTERM; c->sig->signal_text = "exit-with-notification"; } - else + else if (!cc_exit_notify_enabled(c)) { c->c2.occ_op = OCC_EXIT; } diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 61dea996d..4506b7504 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1940,6 +1940,9 @@ push_peer_info(struct buffer *buf, struct tls_session *session) /* support for P_DATA_V2 */ int iv_proto = IV_PROTO_DATA_V2; + /* support for exit notify via control channel */ + iv_proto |= IV_PROTO_CC_EXIT_NOTIFY; + /* support for receiving push_reply before sending * push request, also signal that the client wants * to get push-reply messages without without requiring a round diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index 0ba86d3e6..1b8b736b9 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -93,6 +93,9 @@ * result. */ #define IV_PROTO_NCP_P2P (1<<5) +/** Support for explicit exit notify via control channel */ +#define IV_PROTO_CC_EXIT_NOTIFY (1<<7) + /* Default field in X509 to be username */ #define X509_USERNAME_FIELD_DEFAULT "CN" diff --git a/src/openvpn/ssl_ncp.c b/src/openvpn/ssl_ncp.c index 5d7e6dd38..4a083e247 100644 --- a/src/openvpn/ssl_ncp.c +++ b/src/openvpn/ssl_ncp.c @@ -419,6 +419,11 @@ p2p_ncp_set_options(struct tls_multi *multi, struct tls_session *session) multi->peer_id = 0x76706e; /* 'v' 'p' 'n' */ } + if (iv_proto_peer & IV_PROTO_CC_EXIT_NOTIFY) + { + session->opt->crypto_flags |= CO_USE_CC_EXIT_NOTIFY; + } + #if defined(HAVE_EXPORT_KEYING_MATERIAL) if (iv_proto_peer & IV_PROTO_TLS_KEY_EXPORT) { From patchwork Fri May 20 11:32:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 2484 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director7.mail.ord1d.rsapps.net ([172.30.191.6]) by backend41.mail.ord1d.rsapps.net with LMTP id kDJAFlQJiGKdSQAAqwncew (envelope-from ) for ; Fri, 20 May 2022 17:34:12 -0400 Received: from proxy10.mail.ord1d.rsapps.net ([172.30.191.6]) by director7.mail.ord1d.rsapps.net with LMTP id uIvuNlQJiGJYEgAAovjBpQ (envelope-from ) for ; Fri, 20 May 2022 17:34:12 -0400 Received: from smtp37.gate.ord1c ([172.30.191.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy10.mail.ord1d.rsapps.net with LMTPS id ADeSNlQJiGK5TAAAfSg8FQ (envelope-from ) for ; Fri, 20 May 2022 17:34:12 -0400 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO X-Virus-Scanned: OK X-Orig-To: openvpnslackdevel@openvpn.net X-Originating-Ip: [216.105.38.7] Authentication-Results: smtp37.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: 96ae3bac-d884-11ec-b19c-525400e8d833-1-1 Received: from [216.105.38.7] ([216.105.38.7:41344] helo=lists.sourceforge.net) by smtp37.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id D4/4F-25020-45908826; Fri, 20 May 2022 17:34:12 -0400 Received: from [127.0.0.1] (helo=sfs-ml-1.v29.lw.sourceforge.com) by sfs-ml-1.v29.lw.sourceforge.com with esmtp (Exim 4.94.2) (envelope-from ) id 1nsAFD-0008Ke-IN; Fri, 20 May 2022 21:33:12 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-1.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1nsAFA-0008KM-2s for openvpn-devel@lists.sourceforge.net; Fri, 20 May 2022 21:33:08 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type: 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=ONmnP87/lvB/vAq7Sb9HdK9w48vMJuXO3GscrwUFAEY=; b=gakKd5ZmRKu5/Ijgiw8R4973cd KBbymViuBb6+kcfPO1m3fEoIPLzb4qSlicl9ObRMAAxtvBPIkJZbSwrXfIueeaahkc2c8jawBMt3q rCiuUnvkntk4ZZ2EGc8TNqEkFInms8uw6wlY6TUTh4vO075KF6b6qK0VfdnYE2zFkCN4=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id: Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type: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=ONmnP87/lvB/vAq7Sb9HdK9w48vMJuXO3GscrwUFAEY=; b=iF+xTyL74NJY2QtgG0NwJw+CTz e9LbwVgLw1wORP/XE/X+vyvedvoCECM16djLH+hEYWo0hBDqTD1xopFOQTuaiS2XgMjxFNZVcL3nS bKqK5pHJcrXP6KONZ1Mpo6ulOe1O9cbKJaIUkYLXds33Z/J9hDTSevGOufFtKaz/dZ9I=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.94.2) id 1nsAF9-0005EQ-Ob for openvpn-devel@lists.sourceforge.net; Fri, 20 May 2022 21:33:08 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.95 (FreeBSD)) (envelope-from ) id 1nsAEt-0005Sj-Ih for openvpn-devel@lists.sourceforge.net; Fri, 20 May 2022 23:32:51 +0200 Received: (nullmailer pid 3126428 invoked by uid 10006); Fri, 20 May 2022 21:32:51 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Fri, 20 May 2022 23:32:48 +0200 Message-Id: <20220520213250.3126372-3-arne@rfc2549.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220520213250.3126372-1-arne@rfc2549.org> References: <20220520213250.3126372-1-arne@rfc2549.org> MIME-Version: 1.0 X-Spam-Report: Spam detection software, running on the system "util-spamd-2.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: This simplifies the buffer handling in the method and adds a quick return instead of wrapping the whole method in a if (pull) block Patch V2: remove uncessary ifdef/endif and unnecassary block --- src/openvpn/push.c | 99 ++++++++++++++++++++++++ 1 file changed, 51 insertions(+), 48 deletions(-) Content analysis details: (0.2 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 SPF_NONE SPF: sender does not publish an SPF Record -0.0 T_SCC_BODY_TEXT_LINE No description available. X-Headers-End: 1nsAF9-0005EQ-Ob Subject: [Openvpn-devel] [PATCH v2 2/4] Cleanup receive_auth_failed and simplify method 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: , Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox This simplifies the buffer handling in the method and adds a quick return instead of wrapping the whole method in a if (pull) block Patch V2: remove uncessary ifdef/endif and unnecassary block Acked-By: Frank Lichtenheld Acked-by: Heiko Hund --- src/openvpn/push.c | 99 ++++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/src/openvpn/push.c b/src/openvpn/push.c index fa0def7f8..1c4e637e4 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -53,64 +53,67 @@ receive_auth_failed(struct context *c, const struct buffer *buffer) msg(M_VERB0, "AUTH: Received control message: %s", BSTR(buffer)); c->options.no_advance = true; - if (c->options.pull) + if (!c->options.pull) { - /* Before checking how to react on AUTH_FAILED, first check if the - * failed auth might be the result of an expired auth-token. - * Note that a server restart will trigger a generic AUTH_FAILED - * instead an AUTH_FAILED,SESSION so handle all AUTH_FAILED message - * identical for this scenario */ - if (ssl_clean_auth_token()) - { - c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Auth failure error */ - c->sig->signal_text = "auth-failure (auth-token)"; - } - else + return; + } + + struct buffer buf = *buffer; + + /* If the AUTH_FAIL message ends with a , it is an extended message that + * contains further flags */ + bool authfail_extended = buf_string_compare_advance(&buf, "AUTH_FAILED,"); + + /* Before checking how to react on AUTH_FAILED, first check if the + * failed auth might be the result of an expired auth-token. + * Note that a server restart will trigger a generic AUTH_FAILED + * instead an AUTH_FAILED,SESSION so handle all AUTH_FAILED message + * identical for this scenario */ + if (ssl_clean_auth_token()) + { + c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Auth failure error */ + c->sig->signal_text = "auth-failure (auth-token)"; + } + else + { + switch (auth_retry_get()) { - switch (auth_retry_get()) - { - case AR_NONE: - c->sig->signal_received = SIGTERM; /* SOFT-SIGTERM -- Auth failure error */ - break; + case AR_NONE: + c->sig->signal_received = SIGTERM; /* SOFT-SIGTERM -- Auth failure error */ + break; - case AR_INTERACT: - ssl_purge_auth(false); + case AR_INTERACT: + ssl_purge_auth(false); - case AR_NOINTERACT: - c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Auth failure error */ - break; + case AR_NOINTERACT: + c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Auth failure error */ + break; - default: - ASSERT(0); - } - c->sig->signal_text = "auth-failure"; + default: + ASSERT(0); } + c->sig->signal_text = "auth-failure"; + } #ifdef ENABLE_MANAGEMENT - if (management) - { - const char *reason = NULL; - struct buffer buf = *buffer; - if (buf_string_compare_advance(&buf, "AUTH_FAILED,") && BLEN(&buf)) - { - reason = BSTR(&buf); - } - management_auth_failure(management, UP_TYPE_AUTH, reason); - } -#endif - /* - * Save the dynamic-challenge text even when management is defined - */ + if (management) + { + const char *reason = NULL; + if (authfail_extended && BLEN(&buf)) { -#ifdef ENABLE_MANAGEMENT - struct buffer buf = *buffer; - if (buf_string_match_head_str(&buf, "AUTH_FAILED,CRV1:") && BLEN(&buf)) - { - buf_advance(&buf, 12); /* Length of "AUTH_FAILED," substring */ - ssl_put_auth_challenge(BSTR(&buf)); - } -#endif + reason = BSTR(&buf); } + management_auth_failure(management, UP_TYPE_AUTH, reason); + } + /* + * Save the dynamic-challenge text even when management is defined + */ + if (authfail_extended + && buf_string_match_head_str(&buf, "CRV1:") && BLEN(&buf)) + { + ssl_put_auth_challenge(BSTR(&buf)); } +#endif + } /* From patchwork Fri May 20 11:32:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 2487 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director15.mail.ord1d.rsapps.net ([172.30.191.6]) by backend41.mail.ord1d.rsapps.net with LMTP id CDenGVsJiGLISQAAqwncew (envelope-from ) for ; Fri, 20 May 2022 17:34:19 -0400 Received: from proxy14.mail.ord1d.rsapps.net ([172.30.191.6]) by director15.mail.ord1d.rsapps.net with LMTP id QOBjOlsJiGKoAQAAIcMcQg (envelope-from ) for ; Fri, 20 May 2022 17:34:19 -0400 Received: from smtp1.gate.ord1d ([172.30.191.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy14.mail.ord1d.rsapps.net with LMTPS id iITvF14JiGJfagAAtEH5vw (envelope-from ) for ; Fri, 20 May 2022 17:34:22 -0400 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO X-Virus-Scanned: OK X-Orig-To: openvpnslackdevel@openvpn.net X-Originating-Ip: [216.105.38.7] Authentication-Results: smtp1.gate.ord1d.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: 9ac3728e-d884-11ec-b483-5254002d775b-1-1 Received: from [216.105.38.7] ([216.105.38.7:44586] helo=lists.sourceforge.net) by smtp1.gate.ord1d.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 99/0C-09579-A5908826; Fri, 20 May 2022 17:34:19 -0400 Received: from [127.0.0.1] (helo=sfs-ml-2.v29.lw.sourceforge.com) by sfs-ml-2.v29.lw.sourceforge.com with esmtp (Exim 4.94.2) (envelope-from ) id 1nsAFC-0006ao-CH; Fri, 20 May 2022 21:33:09 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-2.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1nsAFB-0006ai-D9 for openvpn-devel@lists.sourceforge.net; Fri, 20 May 2022 21:33:08 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type: 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=/GKJfTjJXUATPpLKT7mu0p4oCSAHhy3M5JMj4/60mhc=; b=F5TsvLiXaTeroGF5u61dUvsVzq LBNTlF178XrCnTpeNS21DvByU1Eb3ijnN6CEnqw5OHWMGapXjr60eFzxJCRV6CF6GiYiO+GMnxqa7 oHefescgQLHodszdWaZTfZ09Eg+KVNe5DnyHOCM6/2MVMuQds87/EK3daTfX0p7DLkCk=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id: Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type: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=/GKJfTjJXUATPpLKT7mu0p4oCSAHhy3M5JMj4/60mhc=; b=J5UmBMCDkUDh+at4FAZ8YU1cwa 0p2HcmbHHlDOUtaFv/VRgabo9tfaVZyGXHEWpWL0kSbvs0d5wsCinBKCWspsA/be6KiTZAE9eH/o3 goemUADXyvs2g70RWcRt5hJnuFTAA7eAp4dC961kUjN8RD5ozp24ZhtRQHkebo89VYZQ=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.94.2) id 1nsAF5-00Dyy6-C4 for openvpn-devel@lists.sourceforge.net; Fri, 20 May 2022 21:33:08 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.95 (FreeBSD)) (envelope-from ) id 1nsAEt-0005Sm-LX for openvpn-devel@lists.sourceforge.net; Fri, 20 May 2022 23:32:51 +0200 Received: (nullmailer pid 3126431 invoked by uid 10006); Fri, 20 May 2022 21:32:51 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Fri, 20 May 2022 23:32:49 +0200 Message-Id: <20220520213250.3126372-4-arne@rfc2549.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220520213250.3126372-1-arne@rfc2549.org> References: <20220520213250.3126372-1-arne@rfc2549.org> MIME-Version: 1.0 X-Spam-Report: Spam detection software, running on the system "util-spamd-1.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: This allows a server to indicate a temporary problem on the server and allows the server to indicate how to proceed (i.e. move to the next server, retry the same server, wait a certain time, ...) This adds options_utils.c/h to be able to unit test the new function. Content analysis details: (0.3 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 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 X-Headers-End: 1nsAF5-00Dyy6-C4 Subject: [Openvpn-devel] [PATCH v2 3/4] Implement AUTH_FAIL, TEMP message support 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: , Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox This allows a server to indicate a temporary problem on the server and allows the server to indicate how to proceed (i.e. move to the next server, retry the same server, wait a certain time,...) This adds options_utils.c/h to be able to unit test the new function. Patch v2: Improve documentation, format man page better, comment that protocol-flags is not a user usable option. --- doc/man-sections/script-options.rst | 36 ++++++++++ src/openvpn/Makefile.am | 1 + src/openvpn/init.c | 9 ++- src/openvpn/openvpn.vcxproj | 2 + src/openvpn/openvpn.vcxproj.filters | 3 + src/openvpn/options.h | 9 ++- src/openvpn/options_util.c | 104 +++++++++++++++++++++++++++ src/openvpn/options_util.h | 33 +++++++++ src/openvpn/push.c | 11 ++- src/openvpn/ssl.c | 13 ++-- src/openvpn/ssl.h | 3 + tests/unit_tests/openvpn/Makefile.am | 1 + tests/unit_tests/openvpn/test_misc.c | 49 +++++++++++++ 13 files changed, 266 insertions(+), 8 deletions(-) create mode 100644 src/openvpn/options_util.c create mode 100644 src/openvpn/options_util.h diff --git a/doc/man-sections/script-options.rst b/doc/man-sections/script-options.rst index 6be0686d7..8a58eaad0 100644 --- a/doc/man-sections/script-options.rst +++ b/doc/man-sections/script-options.rst @@ -97,6 +97,42 @@ SCRIPT HOOKS the authentication, a :code:`1` or :code:`0` must be written to the file specified by the :code:`auth_control_file`. + If the file specified by :code:`auth_failed_reason` exists and has non-empty + content, the content of this file will be used as AUTH_FAILED message. To + avoid race conditions, this file should be written before + :code:`auth_control_file`. + + This auth fail reason can be something simple like "User has been permanently + disabled" but there are also some special auth failed messages. + + The ``TEMP`` message indicates that the authentication + temporarily failed and that the client should continue to retry to connect. + The server can optionally give a user readable message and hint the client a + behavior how to proceed. The keywords of the ``AUTH_FAILED,TEMP`` message + are comma separated keys/values and provide a hint to the client how to + proceed. Currently defined keywords are: + + ``backoff`` :code:`s` + instructs the client to wait at least :code:`s` seconds before the next + connection attempt. If the client already uses a higher delay for + reconnection attempt, the delay will not be shortened. + + ``advance addr`` + Instructs the client to reconnect to the next (IP) address of the + current server. + + ``advance remote`` + Instructs the client to skip the remaining IP addresses of the current + server and instead connect to the next server specified in the + configuration file. + + ``advance no`` + Instructs the client to retry connecting to the same server again. + + For example, the message ``TEMP[backoff 42,advance no]: No free IP addresses`` + indicates that the VPN connection can currently not succeed and instructs + the client to retry in 42 seconds again. + 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 diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index 577294804..a619aac38 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -95,6 +95,7 @@ openvpn_SOURCES = \ pkcs11_mbedtls.c \ openvpn.c openvpn.h \ options.c options.h \ + options_util.c options_util.h \ otime.c otime.h \ packet_id.c packet_id.h \ perf.c perf.h \ diff --git a/src/openvpn/init.c b/src/openvpn/init.c index b0c62a859..b2a1e92a5 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -483,13 +483,15 @@ next_connection_entry(struct context *c) /* Check if there is another resolved address to try for * the current connection */ if (c->c1.link_socket_addr.current_remote - && c->c1.link_socket_addr.current_remote->ai_next) + && c->c1.link_socket_addr.current_remote->ai_next + && !c->options.advance_next_remote) { c->c1.link_socket_addr.current_remote = c->c1.link_socket_addr.current_remote->ai_next; } else { + c->options.advance_next_remote = false; /* FIXME (schwabe) fix the persist-remote-ip option for real, * this is broken probably ever since connection lists and multiple * remote existed @@ -2357,6 +2359,11 @@ socket_restart_pause(struct context *c) /* sec is less than 2^16; we can left shift it by up to 15 bits without overflow */ sec = max_int(sec, 1) << min_int(backoff, 15); } + if (c->options.server_backoff_time) + { + sec = max_int(sec, c->options.server_backoff_time); + c->options.server_backoff_time = 0; + } if (sec > c->options.ce.connect_retry_seconds_max) { diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj index 860ef8926..e82be2698 100644 --- a/src/openvpn/openvpn.vcxproj +++ b/src/openvpn/openvpn.vcxproj @@ -306,6 +306,7 @@ + @@ -395,6 +396,7 @@ + diff --git a/src/openvpn/openvpn.vcxproj.filters b/src/openvpn/openvpn.vcxproj.filters index f76e59235..616b71ab2 100644 --- a/src/openvpn/openvpn.vcxproj.filters +++ b/src/openvpn/openvpn.vcxproj.filters @@ -395,6 +395,9 @@ Header Files + + Header Files + Header Files diff --git a/src/openvpn/options.h b/src/openvpn/options.h index c2937dc37..0c1a31389 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -272,10 +272,17 @@ struct options struct connection_list *connection_list; struct remote_list *remote_list; - /* Do not advanced the connection or remote addr list*/ + /* Do not advance the connection or remote addr list*/ bool no_advance; + /* Advance directly to the next remote, skipping remaining addresses of the + * current remote */ + bool advance_next_remote; /* Counts the number of unsuccessful connection attempts */ unsigned int unsuccessful_attempts; + /* the server can suggest a backoff time to the client, it + * will still be capped by the max timeout between connections + * (300s by default) */ + int server_backoff_time; #if ENABLE_MANAGEMENT struct http_proxy_options *http_proxy_override; diff --git a/src/openvpn/options_util.c b/src/openvpn/options_util.c new file mode 100644 index 000000000..d8a7e2343 --- /dev/null +++ b/src/openvpn/options_util.c @@ -0,0 +1,104 @@ +/* + * 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-2022 OpenVPN Inc + * Copyright (C) 2010-2021 Fox Crypto B.V. + * + * 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 "options_util.h" + +const char * +parse_auth_failed_temp(struct options *o, const struct buffer *buf) +{ + struct gc_arena gc = gc_new(); + char *m = string_alloc(BSTR(buf), &gc); + /* skip TEMP */ + m += strlen("TEMP"); + const char *message = BSTR(buf) + 4; + + + /* Check if the message uses the TEMP[flags]: message format*/ + char *endofflags = strstr(m, "]"); + + /* Temporary failure from the server */ + if (m[0] == '[' && endofflags) + { + message = strstr(BSTR(buf), "]") + 1; + /* null terminate the substring to only looks for flags between [ and ] */ + *endofflags = '\x00'; + const char *token = strtok(m, "[,"); + while (token) + { + if (!strncmp(token, "backoff ", strlen("backoff "))) + { + if (sscanf(token, "backoff %d", &o->server_backoff_time) != 1) + { + msg(D_PUSH, "invalid AUTH_FAIL,TEMP flag: %s", token); + o->server_backoff_time = 0; + } + } + else if (!strncmp(token, "advance ", strlen("advance "))) + { + token += strlen("advance "); + if (!strcmp(token, "no")) + { + o->no_advance = true; + } + else if (!strcmp(token, "remote")) + { + o->advance_next_remote = true; + o->no_advance = false; + } + else if (!strcmp(token, "addr")) + { + /* Go on to the next remote */ + o->no_advance = false; + } + } + else + { + msg(D_PUSH_ERRORS, "WARNING: unknown AUTH_FAIL,TEMP flag: %s", token); + } + token = strtok(NULL, "[,"); + } + } + + /* Look for the message in the original buffer to safely be + * able to return it */ + if (!message || message[0] != ':') + { + message = ""; + } + else + { + /* Skip the : at the beginning */ + message += 1; + } + gc_free(&gc); + return message; +} \ No newline at end of file diff --git a/src/openvpn/options_util.h b/src/openvpn/options_util.h new file mode 100644 index 000000000..9785bb239 --- /dev/null +++ b/src/openvpn/options_util.h @@ -0,0 +1,33 @@ +/* + * 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-2022 OpenVPN Inc + * Copyright (C) 2010-2021 Fox Crypto B.V. + * + * 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. + */ + +#ifndef OPTIONS_UTIL_H_ +#define OPTIONS_UTIL_H_ + +#include "options.h" + +const char * +parse_auth_failed_temp(struct options *o, const struct buffer *buf); + +#endif \ No newline at end of file diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 1c4e637e4..3b3dce642 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -38,6 +38,7 @@ #include "memdbg.h" #include "ssl_util.h" +#include "options_util.h" static char push_reply_cmd[] = "PUSH_REPLY"; @@ -51,7 +52,6 @@ void receive_auth_failed(struct context *c, const struct buffer *buffer) { msg(M_VERB0, "AUTH: Received control message: %s", BSTR(buffer)); - c->options.no_advance = true; if (!c->options.pull) { @@ -64,15 +64,22 @@ receive_auth_failed(struct context *c, const struct buffer *buffer) * contains further flags */ bool authfail_extended = buf_string_compare_advance(&buf, "AUTH_FAILED,"); + if (authfail_extended && buf_string_match_head_str(&buf, "TEMP")) + { + parse_auth_failed_temp(&c->options, &buf); + c->sig->signal_received = SIGUSR1; + c->sig->signal_text = "auth-temp-failure (server temporary reject)"; + } /* Before checking how to react on AUTH_FAILED, first check if the * failed auth might be the result of an expired auth-token. * Note that a server restart will trigger a generic AUTH_FAILED * instead an AUTH_FAILED,SESSION so handle all AUTH_FAILED message * identical for this scenario */ - if (ssl_clean_auth_token()) + else if (ssl_clean_auth_token()) { c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Auth failure error */ c->sig->signal_text = "auth-failure (auth-token)"; + c->options.no_advance = true; } else { diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 4506b7504..f11b3afb3 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1943,14 +1943,19 @@ push_peer_info(struct buffer *buf, struct tls_session *session) /* support for exit notify via control channel */ iv_proto |= IV_PROTO_CC_EXIT_NOTIFY; - /* support for receiving push_reply before sending - * push request, also signal that the client wants - * to get push-reply messages without without requiring a round - * trip for a push request message*/ if (session->opt->pull) { + /* support for receiving push_reply before sending + * push request, also signal that the client wants + * to get push-reply messages without requiring a round + * trip for a push request message*/ iv_proto |= IV_PROTO_REQUEST_PUSH; + + /* Support keywords in the AUTH_PENDING control message */ iv_proto |= IV_PROTO_AUTH_PENDING_KW; + + /* support for AUTH_FAIL,TEMP control message */ + iv_proto |= IV_PROTO_AUTH_FAIL_TEMP; } /* support for Negotiable Crypto Parameters */ diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index 1b8b736b9..981bb3403 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -93,6 +93,9 @@ * result. */ #define IV_PROTO_NCP_P2P (1<<5) +/** Support for AUTH_FAIL,TEMP messages */ +#define IV_PROTO_AUTH_FAIL_TEMP (1<<6) + /** Support for explicit exit notify via control channel */ #define IV_PROTO_CC_EXIT_NOTIFY (1<<7) diff --git a/tests/unit_tests/openvpn/Makefile.am b/tests/unit_tests/openvpn/Makefile.am index 63b53a6ac..65cf9549c 100644 --- a/tests/unit_tests/openvpn/Makefile.am +++ b/tests/unit_tests/openvpn/Makefile.am @@ -176,5 +176,6 @@ misc_testdriver_LDFLAGS = @TEST_LDFLAGS@ misc_testdriver_SOURCES = test_misc.c mock_msg.c \ mock_get_random.c \ $(openvpn_srcdir)/buffer.c \ + $(openvpn_srcdir)/options_util.c \ $(openvpn_srcdir)/ssl_util.c \ $(openvpn_srcdir)/platform.c diff --git a/tests/unit_tests/openvpn/test_misc.c b/tests/unit_tests/openvpn/test_misc.c index 636fc45d6..802307fb7 100644 --- a/tests/unit_tests/openvpn/test_misc.c +++ b/tests/unit_tests/openvpn/test_misc.c @@ -37,6 +37,7 @@ #include #include "ssl_util.h" +#include "options_util.h" static void test_compat_lzo_string(void **state) @@ -72,8 +73,56 @@ test_compat_lzo_string(void **state) gc_free(&gc); } +static void +test_auth_fail_temp_no_flags(void **state) +{ + struct options o; + + struct buffer buf; + const char *teststr = "TEMP:There are no flags here [really not]"; + + buf_set_read(&buf, (uint8_t *)teststr,strlen(teststr)); + + const char *msg = parse_auth_failed_temp(&o, &buf); + assert_string_equal(msg, "There are no flags here [really not]"); +} + +static void +test_auth_fail_temp_flags(void **state) +{ + struct options o; + + struct buffer buf; + const char *teststr = "TEMP[backoff 42,advance no]"; + + buf_set_read(&buf, (uint8_t *)teststr,strlen(teststr)); + + const char *msg = parse_auth_failed_temp(&o, &buf); + assert_string_equal(msg, ""); + assert_int_equal(o.server_backoff_time, 42); + assert_int_equal(o.no_advance, true); +} + +static void +test_auth_fail_temp_flags_msg(void **state) +{ + struct options o; + + struct buffer buf; + const char *teststr = "TEMP[advance remote,backoff 77]:go round and round"; + + buf_set_read(&buf, (uint8_t *)teststr,strlen(teststr)); + + const char *msg = parse_auth_failed_temp(&o, &buf); + assert_string_equal(msg, "go round and round"); + assert_int_equal(o.server_backoff_time, 77); +} + const struct CMUnitTest misc_tests[] = { cmocka_unit_test(test_compat_lzo_string), + cmocka_unit_test(test_auth_fail_temp_no_flags), + cmocka_unit_test(test_auth_fail_temp_flags), + cmocka_unit_test(test_auth_fail_temp_flags_msg), }; int From patchwork Fri May 20 11:32:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 2486 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director8.mail.ord1d.rsapps.net ([172.28.255.1]) by backend41.mail.ord1d.rsapps.net with LMTP id gHz/NVcJiGKPSQAAqwncew (envelope-from ) for ; Fri, 20 May 2022 17:34:15 -0400 Received: from proxy6.mail.ord1c.rsapps.net ([172.28.255.1]) by director8.mail.ord1d.rsapps.net with LMTP id +IcKG1gJiGI2SgAAfY0hYg (envelope-from ) for ; Fri, 20 May 2022 17:34:16 -0400 Received: from smtp18.gate.ord1c ([172.28.255.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy6.mail.ord1c.rsapps.net with LMTPS id iF6QGlgJiGKhFgAA9sKXow (envelope-from ) for ; Fri, 20 May 2022 17:34:16 -0400 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO X-Virus-Scanned: OK X-Orig-To: openvpnslackdevel@openvpn.net X-Originating-Ip: [216.105.38.7] Authentication-Results: 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: 98d75800-d884-11ec-aa5f-bc305bf00c68-1-1 Received: from [216.105.38.7] ([216.105.38.7:46910] 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 A4/6D-02782-75908826; Fri, 20 May 2022 17:34:15 -0400 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.94.2) (envelope-from ) id 1nsAFD-0004AT-Md; Fri, 20 May 2022 21:33:10 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1nsAFC-0004AI-0N for openvpn-devel@lists.sourceforge.net; Fri, 20 May 2022 21:33:08 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type: 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=787G4S/jcpCeLiSY0CHzktHs6RJoFozAnf2xmEkX1ak=; b=PgvU1mBqpdbDtTD3gHryaM4iSa Pkcu/HjXW9fq+MDK8lD475bIRZ+xD9IN7ktzJ2SHi5zvwsRp6jKvTtcT1G6J0Vm9NB7FNkOnbwGA/ /VDZoGfgPeK0W13yYa0C4UdagJkY26h7WI1ByAzWO5EpdnGd3Gq8Y5YM0zgRy/7lbipc=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id: Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type: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=787G4S/jcpCeLiSY0CHzktHs6RJoFozAnf2xmEkX1ak=; b=YXGcOashcSxeO7lxc1fIUFr2Cu 7D2bx072VK8Immc5cSlI/5dgDjUBMhaxHz/QTFPgJwtiHC2VG/1UJSM5/RXilnhNi7CTxV2+iUCYr +ETv5jN9zHgyXrbCzVGtK5sC+JXq3Og5RUPZO3Dx5zxf8t+33JK038Oo/uSjmII6dFOU=; Received: from mail.blinkt.de ([192.26.174.232]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.94.2) id 1nsAF9-0005EU-PA for openvpn-devel@lists.sourceforge.net; Fri, 20 May 2022 21:33:08 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.95 (FreeBSD)) (envelope-from ) id 1nsAEt-0005Sp-O6 for openvpn-devel@lists.sourceforge.net; Fri, 20 May 2022 23:32:51 +0200 Received: (nullmailer pid 3126434 invoked by uid 10006); Fri, 20 May 2022 21:32:51 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Fri, 20 May 2022 23:32:50 +0200 Message-Id: <20220520213250.3126372-5-arne@rfc2549.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220520213250.3126372-1-arne@rfc2549.org> References: <20220520213250.3126372-1-arne@rfc2549.org> MIME-Version: 1.0 X-Spam-Report: Spam detection software, running on the system "util-spamd-2.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: This is currently only possible when using the management interface and the client-deny functionality. --- src/openvpn/ssl_common.h | 1 + src/openvpn/ssl_verify.c | 74 ++++++++++++++++++++++++++++++++ [...] Content analysis details: (0.2 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 SPF_NONE SPF: sender does not publish an SPF Record -0.0 T_SCC_BODY_TEXT_LINE No description available. X-Headers-End: 1nsAF9-0005EU-PA Subject: [Openvpn-devel] [PATCH v2 4/4] Allow scripts and plugins to set a custom AUTH_FAILED 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: , Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox This is currently only possible when using the management interface and the client-deny functionality. --- src/openvpn/ssl_common.h | 1 + src/openvpn/ssl_verify.c | 74 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index cef2611b9..433563068 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -155,6 +155,7 @@ struct auth_deferred_status { char *auth_control_file; char *auth_pending_file; + char *auth_failed_reason_file; unsigned int auth_control_status; }; diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index c01841fa9..4cf772fef 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -989,6 +989,12 @@ key_state_rm_auth_control_files(struct auth_deferred_status *ads) free(ads->auth_control_file); ads->auth_control_file = NULL; } + if (ads->auth_failed_reason_file) + { + platform_unlink(ads->auth_failed_reason_file); + free(ads->auth_failed_reason_file); + ads->auth_failed_reason_file = NULL; + } key_state_rm_auth_pending_file(ads); } @@ -1007,19 +1013,47 @@ key_state_gen_auth_control_files(struct auth_deferred_status *ads, key_state_rm_auth_control_files(ads); const char *acf = platform_create_temp_file(opt->tmp_dir, "acf", &gc); const char *apf = platform_create_temp_file(opt->tmp_dir, "apf", &gc); + const char *afr = platform_create_temp_file(opt->tmp_dir, "afr", &gc); if (acf && apf) { ads->auth_control_file = string_alloc(acf, NULL); ads->auth_pending_file = string_alloc(apf, NULL); + ads->auth_failed_reason_file = string_alloc(afr, NULL); + setenv_str(opt->es, "auth_control_file", ads->auth_control_file); setenv_str(opt->es, "auth_pending_file", ads->auth_pending_file); + setenv_str(opt->es, "auth_failed_reason_file", ads->auth_failed_reason_file); } gc_free(&gc); return (acf && apf); } +/** + * Checks if the auth failed reason file has any content and if yes it will + * be returned as string allocated in gc to the caller. + */ +static char * +key_state_check_auth_failed_message_file(const struct auth_deferred_status *ads, + struct tls_multi *multi, + struct gc_arena *gc) +{ + char *ret = NULL; + if (ads->auth_failed_reason_file) + { + struct buffer reason = buffer_read_from_file(ads->auth_failed_reason_file, gc); + + if (BLEN(&reason)) + { + ret = BSTR(&reason); + } + + } + return ret; +} + + /** * Checks the auth control status from a file. The function will try * to read and update the cached status if the status is still pending @@ -1184,6 +1218,20 @@ tls_authentication_status(struct tls_multi *multi) #endif if (failed_auth) { + struct gc_arena gc = gc_new(); + const struct key_state *ks = get_primary_key(multi); + const char *plugin_message = key_state_check_auth_failed_message_file(&ks->plugin_auth, multi, &gc); + const char *script_message = key_state_check_auth_failed_message_file(&ks->script_auth, multi, &gc); + + if (plugin_message) + { + auth_set_client_reason(multi, plugin_message); + } + if (script_message) + { + auth_set_client_reason(multi, script_message); + } + /* We have at least one session that failed authentication. There * might be still another session with valid keys. * Although our protocol allows keeping the VPN session alive @@ -1248,6 +1296,21 @@ tls_authenticate_key(struct tls_multi *multi, const unsigned int mda_key_id, con * this is the place to start. *************************************************************************** */ +/** + * Check if the script/plugin left a message in the auth failed message + * file and rely it to the user */ +static void +check_for_client_reason(struct tls_multi *multi, + struct auth_deferred_status *status) +{ + struct gc_arena gc = gc_new(); + const char *msg = key_state_check_auth_failed_message_file(status, multi, &gc); + if (msg) + { + auth_set_client_reason(multi, msg); + } + gc_free(&gc); +} /* * Verify the user name and password using a script */ @@ -1316,6 +1379,7 @@ verify_user_pass_script(struct tls_session *session, struct tls_multi *multi, break; default: + check_for_client_reason(multi, &ks->script_auth); retval = OPENVPN_PLUGIN_FUNC_ERROR; break; } @@ -1376,6 +1440,7 @@ 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); + if (retval == OPENVPN_PLUGIN_FUNC_DEFERRED) { /* Check if the plugin has written the pending auth control @@ -1383,10 +1448,15 @@ verify_user_pass_plugin(struct tls_session *session, struct tls_multi *multi, if (!key_state_check_auth_pending_file(&ks->plugin_auth, multi)) { retval = OPENVPN_PLUGIN_FUNC_ERROR; - key_state_rm_auth_control_files(&ks->plugin_auth); } } - else + + if (retval == OPENVPN_PLUGIN_FUNC_ERROR) + { + check_for_client_reason(multi, &ks->plugin_auth); + } + + if (retval != OPENVPN_PLUGIN_FUNC_DEFERRED) { /* purge auth control filename (and file itself) for non-deferred returns */ key_state_rm_auth_control_files(&ks->plugin_auth);