From patchwork Wed Apr 4 07:28:41 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Janito Vaqueiro Ferreira Filho X-Patchwork-Id: 293 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director11.mail.ord1d.rsapps.net ([172.30.191.6]) by backend30.mail.ord1d.rsapps.net (Dovecot) with LMTP id ZLCKEm0QxVrQZAAAIUCqbw for ; Wed, 04 Apr 2018 13:50:37 -0400 Received: from proxy9.mail.ord1d.rsapps.net ([172.30.191.6]) by director11.mail.ord1d.rsapps.net (Dovecot) with LMTP id K1guJG0QxVqvEQAAvGGmqA ; Wed, 04 Apr 2018 13:50:37 -0400 Received: from smtp32.gate.ord1d ([172.30.191.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy9.mail.ord1d.rsapps.net with LMTP id IPudI20QxVrHCwAA7h+8OQ ; Wed, 04 Apr 2018 13:50:37 -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: smtp32.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; dkim=fail (signature verification failed) header.d=mullvad-net.20150623.gappssmtp.com; dmarc=none (p=nil; dis=none) header.from=mullvad.net X-Suspicious-Flag: YES X-Classification-ID: adfe44ee-3830-11e8-8bc9-52540099eaf5-1-1 Received: from [216.105.38.7] ([216.105.38.7:13723] helo=lists.sourceforge.net) by smtp32.gate.ord1d.rsapps.net (envelope-from ) (ecelerity 4.2.1.56364 r(Core:4.2.1.14)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 94/E5-11623-C6015CA5; Wed, 04 Apr 2018 13:50:37 -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.90_1) (envelope-from ) id 1f3mXV-0007L9-VS; Wed, 04 Apr 2018 17:49:41 +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 1f3mXU-0007Kk-HO for openvpn-devel@lists.sourceforge.net; Wed, 04 Apr 2018 17:49:40 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=References:In-Reply-To:Message-Id:Date:Subject:Cc: To:From:Sender:Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=szJz3pmh0FHKvDCQXKZ0PkVhyoTVRFluCiLGtGaebD0=; b=mWIYCVlv2mAPYwk4ta3mDK/SuZ 9rXK61mRoH+uf6xMQODgtv7Aa/Vb0IGx5o0RzXlTbFMitSWJfZvPcdp3VItWhXbKjWKvC/IqnLQZ1 70+UF4VEVwiOJ4gKc9HQxbp45k++D5VGWYhuNs54zx08wRECWUEBDWAV5eIOaObi36dw=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To :MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=szJz3pmh0FHKvDCQXKZ0PkVhyoTVRFluCiLGtGaebD0=; b=CEQSNaoORKEg71+Atbum1AD5cc jmmkQcfu+Nyb5z+4iHnZkNu9oC87xWyduYU67lF9FiEFLUj/d5L4A8sZYHqp35zcNf35ixlbdBn4p B6WMwr/22RZ3rLpkFEvQlsE0oAk718q+uAzq5Kh9+DFbVqSOJ9kHN+IcBOpPxFmZi1nA=; Received: from mail-qk0-f182.google.com ([209.85.220.182]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.90_1) id 1f3mXS-0030wv-KJ for openvpn-devel@lists.sourceforge.net; Wed, 04 Apr 2018 17:49:40 +0000 Received: by mail-qk0-f182.google.com with SMTP id 132so23402178qkd.5 for ; Wed, 04 Apr 2018 10:49:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mullvad-net.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=szJz3pmh0FHKvDCQXKZ0PkVhyoTVRFluCiLGtGaebD0=; b=cOAeoBefJd7v8uvXZfN6zF4UrKG0z3gIo2iqUzkJlL6rBvSHYTdXd4/pVK2gcOachU VOGCE9ZMoMxB4FzHAwFDSZvmL+DCnUNMIEYrTdskmOapkyE5s11rWcgJTDxqmlAOz6D0 6FKEbGG23xafKIQ2OGtAg+JdPeOEgae0Vw0S9IAI7pfZtKLS8NFdwjrGA2m1A96E5tn/ QMTc2UsRuK1L7tgbD70Z14uS41K6sOXkmLSVJi4Rgeqrx946vPxhcScNX86zkEStTVGL O49i3hbP3ouHlqiMJPTLiGvPwzq0fv32Y/dpQjTWMKw2f5Zy+xxQhRFXOOjrNLSE++bm TxPg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=szJz3pmh0FHKvDCQXKZ0PkVhyoTVRFluCiLGtGaebD0=; b=IZvFkjyk3cJAVPR0JAug/KyeK5SZR9Z4Fv9QbQmDP3Sx+CQvf+DBmOXO8Wc/GyUL8K wCWq53erZdIxrZPuDASdIvBeTzTrshOVKrQRUBZs3YNlLKoNpnXPk2fRWkBrH//f1p68 guT3HqEdoSANYWZ5KX4J/P5lZXrR+C/xcfZCHNjYdv4haIXSrsNEg7EknqGYgyGrXDqA OksqS1qHPTAmkz6E513PKL6u/qmWJyrxDeHYwzMtQ3xGxwEMsPBxgZ0IawZ+7ckBK5gu yfKPP/CaphjF/2YgwKKLQ/DJS+3aMYuL+mB9Kjl5p5MX2b9bbWNFrPOsDF0Rawb70w+x 3rcA== X-Gm-Message-State: ALQs6tASfe+/jx/VlWZYPJSrjkb+/cyl3pIy7srE9lXSuyKX6zEDLtzH 04bMW6W52co3khrBXyn+ufCPU30Dt40= X-Google-Smtp-Source: AIpwx482LYfNbsRazXHI5eVI50KA7NNBr7kTmnyZkoqP6G4YPHPujmhSN1AgJtVENyPaMfbz92ErbQ== X-Received: by 10.55.43.234 with SMTP id r103mr25131027qkr.37.1522862954329; Wed, 04 Apr 2018 10:29:14 -0700 (PDT) Received: from localhost.localdomain ([189.61.196.150]) by smtp.gmail.com with ESMTPSA id w18sm4360877qkw.35.2018.04.04.10.29.12 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 04 Apr 2018 10:29:13 -0700 (PDT) From: Janito Vaqueiro Ferreira Filho To: openvpn-devel@lists.sourceforge.net Date: Wed, 4 Apr 2018 14:28:41 -0300 Message-Id: <20180404172841.13134-1-janito@mullvad.net> X-Mailer: git-send-email 2.13.6 In-Reply-To: References: X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [209.85.220.182 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H3 RBL: Good reputation (+3) [209.85.220.182 listed in wl.mailspike.net] 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.0 RCVD_IN_MSPIKE_WL Mailspike good senders X-Headers-End: 1f3mXS-0030wv-KJ Subject: [Openvpn-devel] [PATCH] Send authentication failure reason between plugins 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 implements support for sending an authentication failure reason from a server plugin to a client plugin. Currently this can only be done using the management interface. To allow this to be done through the use of plugins, two changes were made. The first change is to allow a plugin to set the failure reason through an approach similar to how deferred authentication is done. The reason should be written as a single line to an external file whose path is specified in the plugin environment variable "auth_failure_reason_file". The second change introduces a new plugin event: "AUTH_FAILED". Plugins running in the client that register to receive this event are notified when an authentication failure is reported from the server. The authentication failure reason, if one was received, is set to the "auth_failed_reason" environment variable. --- include/openvpn-plugin.h.in | 3 +- src/openvpn/plugin.c | 3 ++ src/openvpn/push.c | 24 ++++++++++++++ src/openvpn/ssl.c | 5 +-- src/openvpn/ssl_common.h | 1 + src/openvpn/ssl_verify.c | 79 ++++++++++++++++++++++++++++++++++++++++++--- src/openvpn/ssl_verify.h | 12 +++++-- 7 files changed, 118 insertions(+), 9 deletions(-) diff --git a/include/openvpn-plugin.h.in b/include/openvpn-plugin.h.in index a90a998e..c3b8c476 100644 --- a/include/openvpn-plugin.h.in +++ b/include/openvpn-plugin.h.in @@ -129,7 +129,8 @@ extern "C" { #define OPENVPN_PLUGIN_TLS_FINAL 10 #define OPENVPN_PLUGIN_ENABLE_PF 11 #define OPENVPN_PLUGIN_ROUTE_PREDOWN 12 -#define OPENVPN_PLUGIN_N 13 +#define OPENVPN_PLUGIN_AUTH_FAILED 13 +#define OPENVPN_PLUGIN_N 14 /* * Build a mask out of a set of plug-in types. diff --git a/src/openvpn/plugin.c b/src/openvpn/plugin.c index 0f091ef5..3310c69d 100644 --- a/src/openvpn/plugin.c +++ b/src/openvpn/plugin.c @@ -118,6 +118,9 @@ plugin_type_name(const int type) case OPENVPN_PLUGIN_ROUTE_PREDOWN: return "PLUGIN_ROUTE_PREDOWN"; + case OPENVPN_PLUGIN_AUTH_FAILED: + return "PLUGIN_AUTH_FAILED"; + default: return "PLUGIN_???"; } diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 6a30e479..3fbaa035 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -34,6 +34,7 @@ #include "ssl.h" #include "ssl_verify.h" #include "manage.h" +#include "plugin.h" #include "memdbg.h" @@ -72,6 +73,29 @@ receive_auth_failed(struct context *c, const struct buffer *buffer) ASSERT(0); } c->sig->signal_text = "auth-failure"; + + if (plugin_defined(c->plugins, OPENVPN_PLUGIN_AUTH_FAILED)) + { + struct argv argv = argv_new(); + const char *reason = NULL; + struct buffer buf = *buffer; + if (buf_string_compare_advance(&buf, "AUTH_FAILED,") && BLEN(&buf)) + { + reason = BSTR(&buf); + setenv_str(c->c2.es, "auth_failed_reason", reason); + } + + if (plugin_call(c->plugins, OPENVPN_PLUGIN_AUTH_FAILED, &argv, NULL, c->c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) + { + msg(M_WARN, "WARNING: authfailed plugin call failed"); + } + + if (reason) + { + setenv_del(c->c2.es, "auth_failed_reason"); + } + } + #ifdef ENABLE_MANAGEMENT if (management) { diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 669f941b..b416aa3c 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1015,6 +1015,7 @@ key_state_free(struct key_state *ks, bool clear) #ifdef PLUGIN_DEF_AUTH key_state_rm_auth_control_file(ks); + key_state_rm_auth_failure_reason_file(ks); #endif if (clear) @@ -1347,8 +1348,8 @@ tls_multi_free(struct tls_multi *multi, bool clear) ASSERT(multi); -#ifdef MANAGEMENT_DEF_AUTH - man_def_auth_set_client_reason(multi, NULL); +#ifdef ENABLE_DEF_AUTH + tls_def_auth_set_client_reason(multi, NULL); #endif #if P2MP_SERVER diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index 08ef6ffa..f47609b4 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -199,6 +199,7 @@ struct key_state unsigned int auth_control_status; time_t acf_last_mod; char *auth_control_file; + char *auth_failure_reason_file; #endif #endif }; diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index 25395b27..031bee21 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -837,9 +837,9 @@ cleanup: #define ACF_FAILED 3 #endif -#ifdef MANAGEMENT_DEF_AUTH +#ifdef ENABLE_DEF_AUTH void -man_def_auth_set_client_reason(struct tls_multi *multi, const char *client_reason) +tls_def_auth_set_client_reason(struct tls_multi *multi, const char *client_reason) { if (multi->client_reason) { @@ -852,7 +852,9 @@ man_def_auth_set_client_reason(struct tls_multi *multi, const char *client_reaso multi->client_reason = string_alloc(client_reason, NULL); } } +#endif /* ifdef ENABLE_DEF_AUTH */ +#ifdef MANAGEMENT_DEF_AUTH static inline unsigned int man_def_auth_test(const struct key_state *ks) { @@ -930,6 +932,58 @@ key_state_test_auth_control_file(struct key_state *ks) return ACF_DISABLED; } +/* + * auth_failure_reason_file functions + */ + +void +key_state_rm_auth_failure_reason_file(struct key_state *ks) +{ + if (ks && ks->auth_failure_reason_file) + { + platform_unlink(ks->auth_failure_reason_file); + free(ks->auth_failure_reason_file); + ks->auth_failure_reason_file = NULL; + } +} + +static bool +key_state_gen_auth_failure_reason_file(struct key_state *ks, const struct tls_options *opt) +{ + struct gc_arena gc = gc_new(); + + key_state_rm_auth_failure_reason_file(ks); + const char *acf = create_temp_file(opt->tmp_dir, "afrf", &gc); + if (acf) + { + ks->auth_failure_reason_file = string_alloc(acf, NULL); + setenv_str(opt->es, "auth_failure_reason_file", ks->auth_failure_reason_file); + } + + gc_free(&gc); + return acf; +} + +static char * +key_state_read_auth_failure_reason_file(struct key_state *ks) +{ + char *line = NULL; + size_t line_len = 0; + if (ks && ks->auth_failure_reason_file) + { + FILE *fp = fopen(ks->auth_failure_reason_file, "r"); + if (fp) + { + if (getline(&line, &line_len, fp) < 0) + { + line = NULL; + } + fclose(fp); + } + } + return line; +} + #endif /* ifdef PLUGIN_DEF_AUTH */ /* @@ -987,6 +1041,7 @@ tls_authentication_status(struct tls_multi *multi, const int latency) if (ks->authenticated) { #ifdef ENABLE_DEF_AUTH + char *reason = NULL; unsigned int s1 = ACF_DISABLED; unsigned int s2 = ACF_DISABLED; #ifdef PLUGIN_DEF_AUTH @@ -1012,6 +1067,12 @@ tls_authentication_status(struct tls_multi *multi, const int latency) break; case ACF_FAILED: +#ifdef PLUGIN_DEF_AUTH + reason = key_state_read_auth_failure_reason_file(ks); + tls_def_auth_set_client_reason(multi, reason); + free(reason); + reason = NULL; +#endif /* PLUGIN_DEF_AUTH */ ks->authenticated = false; break; @@ -1056,7 +1117,7 @@ tls_authenticate_key(struct tls_multi *multi, const unsigned int mda_key_id, con if (multi) { int i; - man_def_auth_set_client_reason(multi, client_reason); + tls_def_auth_set_client_reason(multi, client_reason); for (i = 0; i < KEY_SCAN_SIZE; ++i) { struct key_state *ks = multi->key_scan[i]; @@ -1195,16 +1256,26 @@ verify_user_pass_plugin(struct tls_session *session, const struct user_pass *up, "could not create deferred auth control file", __func__); goto cleanup; } + + /* generate filename for deferred auth failure reason file */ + if (!key_state_gen_auth_failure_reason_file(ks, session->opt)) + { + key_state_rm_auth_failure_reason_file(ks); + msg (D_TLS_ERRORS, "TLS Auth Error (%s): " + "could not create deferred auth failure reason file", __func__); + goto cleanup; + } #endif /* call command */ retval = plugin_call(session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL, session->opt->es); #ifdef PLUGIN_DEF_AUTH - /* purge auth control filename (and file itself) for non-deferred returns */ + /* purge auth control filenames (and files themselves) for non-deferred returns */ if (retval != OPENVPN_PLUGIN_FUNC_DEFERRED) { key_state_rm_auth_control_file(ks); + key_state_rm_auth_failure_reason_file(ks); } #endif diff --git a/src/openvpn/ssl_verify.h b/src/openvpn/ssl_verify.h index 64f27efb..88b790ff 100644 --- a/src/openvpn/ssl_verify.h +++ b/src/openvpn/ssl_verify.h @@ -96,6 +96,13 @@ int tls_authentication_status(struct tls_multi *multi, const int latency); void key_state_rm_auth_control_file(struct key_state *ks); /** + * Remove the given key state's auth failure reason file, if it exists. + * + * @param ks The key state the remove the file for + */ +void key_state_rm_auth_failure_reason_file(struct key_state *ks); + +/** * Frees the given set of certificate hashes. * * @param chs The certificate hash set to free. @@ -223,9 +230,10 @@ struct x509_track */ #ifdef MANAGEMENT_DEF_AUTH bool tls_authenticate_key(struct tls_multi *multi, const unsigned int mda_key_id, const bool auth, const char *client_reason); +#endif -void man_def_auth_set_client_reason(struct tls_multi *multi, const char *client_reason); - +#ifdef ENABLE_DEF_AUTH +void tls_def_auth_set_client_reason(struct tls_multi *multi, const char *client_reason); #endif static inline const char *