]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
BEE Backport bacula/src/lib/authenticatebase.cc
authorAlain Spineux <alain@baculasystems.com>
Thu, 23 Apr 2020 14:39:27 +0000 (16:39 +0200)
committerEric Bollengier <eric@baculasystems.com>
Thu, 29 Apr 2021 08:44:17 +0000 (10:44 +0200)
This commit is the result of the squash of the following main commits:

Author: Eric Bollengier <eric@baculasystems.com>
Date:   Wed Mar 11 12:13:09 2020 +0100

    Fix TLS/PSK requierement checks

Author: Eric Bollengier <eric@baculasystems.com>
Date:   Mon Mar 9 17:09:00 2020 +0100

    Fix #6066 about TLS PSK issue with old client configured with TLS Keys

Author: Eric Bollengier <eric@baculasystems.com>
Date:   Wed Jan 29 14:54:04 2020 +0100

    Fix issue with TLS patch for the FileDaemon

Author: Alain Spineux <alain.spineux@baculasystems.com>
Date:   Wed Jan 29 09:06:18 2020 +0100

    Fix Client Initiated backup with TLS certificate connection

Author: Eric Bollengier <eric@baculasystems.com>
Date:   Tue Jan 14 15:09:05 2020 +0100

    Add specific checks when TLS PSK is not available in SSL library

Author: Alain Spineux <alain@baculasystems.com>
Date:   Tue Apr 9 11:13:50 2019 +0200

    PSK: Add PSK to QT's applications

    - add "TLS PSK Enable" to resources
    - update hello messages
    - rename authenticatebase.c to .cc and add the file to the QT tools
      because of a RTTI compilation problem.
      I use .cc because it works best with both bacula's CORE and QT
      to be compiled as C++ and not C
    - call init_crypto() and init_signals() in tray-monitor

bacula/src/lib/authenticatebase.cc [new file with mode: 0644]

diff --git a/bacula/src/lib/authenticatebase.cc b/bacula/src/lib/authenticatebase.cc
new file mode 100644 (file)
index 0000000..31f2b37
--- /dev/null
@@ -0,0 +1,570 @@
+/*
+   Bacula(R) - The Network Backup Solution
+
+   Copyright (C) 2000-2020 Bacula Systems SA
+   All rights reserved.
+
+   The main author of Bacula is Kern Sibbald, with contributions from many
+   others, a complete list can be found in the file AUTHORS.
+
+   Licensees holding a valid Bacula Systems SA license may use this file
+   and others of this release in accordance with the proprietary license
+   agreement provided in the LICENSE file.  Redistribution of any part of
+   this release is not permitted.
+
+   Bacula(R) is a registered trademark of Kern Sibbald.
+*/
+/*
+ * authenticateb.c
+ *
+ * AuthenticateBase is the base class to handles authentication for all daemons
+ *
+ */
+
+#include "bacula.h"
+#include "jcr.h"
+
+static const int authdl = 50;
+
+const char *AuthenticateBase::dc_short_name[6]={ "UNK", "CON", "FD", "SD", "DIR", "GUI" };
+const char *AuthenticateBase::dc_long_name[6]={
+      "Unknown", "Console", "File Daemon", "Storage Daemon", "Director", "Gui"
+};
+
+AuthenticateBase::AuthenticateBase(JCR *jcr, BSOCK *bsock, int loc_typ, int loc_cls, int rm_cls):
+jcr(jcr),
+bsock(bsock),
+local_type(loc_typ),
+local_class(loc_cls),
+remote_class(rm_cls),
+tls_local_need(BNET_TLS_NONE),
+tls_remote_need(BNET_TLS_NONE),
+tls_authenticate(false),
+tls_verify_peer(false),
+tls_verify_list(NULL),
+verify_list(NULL),
+tls_ctx(NULL),
+psk_ctx(NULL),
+ctx(NULL),
+password(NULL),
+psk_local_need(BNET_TLS_NONE),
+psk_remote_need(BNET_TLS_NONE),
+tlspsk_local_need(0),
+tid(NULL),
+auth_success(false),
+check_early_tls(false),
+tls_started(false)
+{
+   local_name[0]='\0';
+   remote_name[0]='\0';
+}
+
+AuthenticateBase::~AuthenticateBase()
+{
+   StopAuthTimeout();
+}
+
+/*
+ * 
+ * LOCAL                    REMOTE
+ * {TLS,PSK}                {TLS,PSK}
+ * --------------------------------------------------
+ * {OK,OK}                 {OK,OK}               => t   TLS
+ * {OK,OK}                 {OK,NONE}             => t   TLS
+ * {OK,OK}                 {OK,REQUIRED}         => t   TLS
+ * {OK,OK}                 {NONE,OK}             => t   PSK
+ * {OK,OK}                 {NONE,NONE}           => t   NONE
+ * {OK,OK}                 {NONE,REQUIRED}       => t   PSK
+ * {OK,OK}                 {REQUIRED,OK}         => t   TLS
+ * {OK,OK}                 {REQUIRED,NONE}       => t   TLS
+ * {OK,OK}                 {REQUIRED,REQUIRED}   => t   TLS
+ *
+ * {OK,NONE}               {OK,OK}               => t
+ * {OK,NONE}               {OK,NONE}             => t
+ * {OK,NONE}               {OK,REQUIRED}         => t
+ * {OK,NONE}               {NONE,OK}             => t
+ * {OK,NONE}               {NONE,NONE}           => t
+ * {OK,NONE}               {NONE,REQUIRED}       => F   -- Remote
+ * {OK,NONE}               {REQUIRED,OK}         => t
+ * {OK,NONE}               {REQUIRED,NONE}       => t
+ * {OK,NONE}               {REQUIRED,REQUIRED}   => t
+ *
+ * Not possible, it means TLS keys is defined + TLS Requires = yes
+ * {OK,REQUIRED}           {OK,OK}               => t
+ * {OK,REQUIRED}           {OK,NONE}             => t
+ * {OK,REQUIRED}           {OK,REQUIRED}         => t
+ * {OK,REQUIRED}           {NONE,OK}             => t
+ * {OK,REQUIRED}           {NONE,NONE}           => F  -- Local
+ * {OK,REQUIRED}           {NONE,REQUIRED}       => t
+ * {OK,REQUIRED}           {REQUIRED,OK}         => t
+ * {OK,REQUIRED}           {REQUIRED,NONE}       => t
+ * {OK,REQUIRED}           {REQUIRED,REQUIRED}   => t
+ *
+ * {NONE,OK}               {OK,OK}               => t
+ * {NONE,OK}               {OK,NONE}             => t
+ * {NONE,OK}               {OK,REQUIRED}         => t
+ * {NONE,OK}               {NONE,OK}             => t
+ * {NONE,OK}               {NONE,NONE}           => t
+ * {NONE,OK}               {NONE,REQUIRED}       => t
+ * {NONE,OK}               {REQUIRED,OK}         => t
+ * {NONE,OK}               {REQUIRED,NONE}       => F  -- Remote
+ * {NONE,OK}               {REQUIRED,REQUIRED}   => t
+ *
+ * {NONE,NONE}             {OK,OK}               => t
+ * {NONE,NONE}             {OK,NONE}             => t
+ * {NONE,NONE}             {OK,REQUIRED}         => F
+ * {NONE,NONE}             {NONE,OK}             => t
+ * {NONE,NONE}             {NONE,NONE}           => t
+ * {NONE,NONE}             {NONE,REQUIRED}       => F  -- Remote
+ * {NONE,NONE}             {REQUIRED,OK}         => F  -- Remote
+ * {NONE,NONE}             {REQUIRED,NONE}       => F  -- Remote
+ * {NONE,NONE}             {REQUIRED,REQUIRED}   => F
+ *
+ * {NONE,REQUIRED}         {OK,OK}               => t
+ * {NONE,REQUIRED}         {OK,NONE}             => F  -- Local
+ * {NONE,REQUIRED}         {OK,REQUIRED}         => t
+ * {NONE,REQUIRED}         {NONE,OK}             => t
+ * {NONE,REQUIRED}         {NONE,NONE}           => F  -- Local
+ * {NONE,REQUIRED}         {NONE,REQUIRED}       => t
+ * {NONE,REQUIRED}         {REQUIRED,OK}         => t
+ * {NONE,REQUIRED}         {REQUIRED,NONE}       => F  -- Local
+ * {NONE,REQUIRED}         {REQUIRED,REQUIRED}   => t
+ *
+ * {REQUIRED,OK}           {OK,OK}               => t
+ * {REQUIRED,OK}           {OK,NONE}             => t
+ * {REQUIRED,OK}           {OK,REQUIRED}         => t
+ * {REQUIRED,OK}           {NONE,OK}             => t
+ * {REQUIRED,OK}           {NONE,NONE}           => F  -- Local
+ * {REQUIRED,OK}           {NONE,REQUIRED}       => t
+ * {REQUIRED,OK}           {REQUIRED,OK}         => t
+ * {REQUIRED,OK}           {REQUIRED,NONE}       => t
+ * {REQUIRED,OK}           {REQUIRED,REQUIRED}   => t
+ *
+ * {REQUIRED,NONE}         {OK,OK}               => t
+ * {REQUIRED,NONE}         {OK,NONE}             => t
+ * {REQUIRED,NONE}         {OK,REQUIRED}         => t
+ * {REQUIRED,NONE}         {NONE,OK}             => F  -- Local
+ * {REQUIRED,NONE}         {NONE,NONE}           => F  -- Local
+ * {REQUIRED,NONE}         {NONE,REQUIRED}       => F  -- Local
+ * {REQUIRED,NONE}         {REQUIRED,OK}         => t
+ * {REQUIRED,NONE}         {REQUIRED,NONE}       => t
+ * {REQUIRED,NONE}         {REQUIRED,REQUIRED}   => t
+ *
+ * {REQUIRED,REQUIRED}     {OK,OK}               => t
+ * {REQUIRED,REQUIRED}     {OK,NONE}             => t
+ * {REQUIRED,REQUIRED}     {OK,REQUIRED}         => t
+ * {REQUIRED,REQUIRED}     {NONE,OK}             => t
+ * {REQUIRED,REQUIRED}     {NONE,NONE}           => F  -- Local
+ * {REQUIRED,REQUIRED}     {NONE,REQUIRED}       => t
+ * {REQUIRED,REQUIRED}     {REQUIRED,OK}         => t
+ * {REQUIRED,REQUIRED}     {REQUIRED,NONE}       => t
+ * {REQUIRED,REQUIRED}     {REQUIRED,REQUIRED}   => t
+ * 
+ */
+
+/* OK
+ * Remote requirement not ok
+ * Local requirement not ok
+ */
+int AuthenticateBase::TestTLSRequirement()
+{
+   /* {OK,NONE}               {NONE,REQUIRED}       => F   -- Remote */
+   if (tls_local_need == BNET_TLS_OK && psk_local_need == BNET_TLS_NONE
+       &&
+       tls_remote_need == BNET_TLS_NONE && psk_remote_need == BNET_TLS_REQUIRED)
+   {
+      return TLS_REQ_ERR_REMOTE;
+   }
+
+   /* {OK,REQUIRED}           {NONE,NONE}           => F  -- Local */
+   if (tls_local_need == BNET_TLS_OK && psk_local_need == BNET_TLS_REQUIRED
+       &&
+       tls_remote_need == BNET_TLS_NONE && psk_remote_need == BNET_TLS_NONE)
+   {
+      return TLS_REQ_ERR_LOCAL;
+   }
+
+   /* {NONE,OK}               {REQUIRED,NONE}       => F  -- Remote */
+   if (tls_local_need == BNET_TLS_NONE && psk_local_need == BNET_TLS_OK
+       &&
+       tls_remote_need == BNET_TLS_REQUIRED && psk_remote_need == BNET_TLS_NONE)
+   {
+      return TLS_REQ_ERR_REMOTE;
+   }
+
+   /* {NONE,NONE}             {OK,REQUIRED}         => F
+    * {NONE,NONE}             {NONE,REQUIRED}       => F  -- Remote
+    * {NONE,NONE}             {REQUIRED,OK}         => F  -- Remote
+    * {NONE,NONE}             {REQUIRED,NONE}       => F  -- Remote
+    * {NONE,NONE}             {REQUIRED,REQUIRED}   => F  
+    */
+   if (tls_local_need == BNET_TLS_NONE && psk_local_need == BNET_TLS_NONE
+       &&
+      (tls_remote_need == BNET_TLS_REQUIRED || psk_remote_need == BNET_TLS_REQUIRED))
+    {
+       return TLS_REQ_ERR_REMOTE;
+    }
+
+   /* {NONE,REQUIRED}         {OK,NONE}             => F  -- Local
+    * {NONE,REQUIRED}         {NONE,NONE}           => F  -- Local
+    * {NONE,REQUIRED}         {REQUIRED,NONE}       => F  -- Local
+    */
+   if (tls_local_need == BNET_TLS_NONE && psk_local_need == BNET_TLS_REQUIRED
+       &&
+       psk_remote_need == BNET_TLS_NONE)
+   {
+      return TLS_REQ_ERR_LOCAL;
+   }
+
+   /* {REQUIRED,OK}           {NONE,NONE}           => F  -- Local */
+   if (tls_local_need == BNET_TLS_REQUIRED && psk_local_need == BNET_TLS_OK
+       &&
+       tls_local_need == BNET_TLS_NONE && psk_remote_need == BNET_TLS_NONE)
+   {
+      return TLS_REQ_ERR_LOCAL;
+   }
+
+   /* {REQUIRED,NONE}         {NONE,OK}             => F  -- Local
+    * {REQUIRED,NONE}         {NONE,NONE}           => F  -- Local
+    * {REQUIRED,NONE}         {NONE,REQUIRED}       => F  -- Local
+    */
+   if (tls_local_need == BNET_TLS_REQUIRED && psk_local_need == BNET_TLS_NONE
+       &&
+       tls_local_need == BNET_TLS_NONE)
+   {
+      return TLS_REQ_ERR_LOCAL;
+   }
+
+   /* {REQUIRED,REQUIRED}     {NONE,NONE}           => F  -- Local */
+   if (tls_local_need == BNET_TLS_REQUIRED && psk_local_need == BNET_TLS_REQUIRED
+       &&
+       tls_local_need == BNET_TLS_NONE && psk_local_need == BNET_TLS_NONE)
+   {
+      return TLS_REQ_ERR_LOCAL;
+   }
+   return TLS_REQ_OK;
+}
+
+const char *AuthenticateBase::GetLocalClassShortName()
+{
+   return dc_short_name[local_class];
+};
+
+const char *AuthenticateBase::GetLocalClassLongName()
+{
+   return dc_long_name[local_class];
+};
+
+const char *AuthenticateBase::GetRemoteClassShortName()
+{
+   return dc_short_name[remote_class];
+};
+
+const char *AuthenticateBase::GetRemoteClassLongName()
+{
+   return dc_long_name[local_class];
+};
+
+int AuthenticateBase::GetTLSPSKLocalNeed()
+{
+   return tlspsk_local_need;
+};
+
+void AuthenticateBase::StartAuthTimeout(int auth_timeout)
+{
+   tid = start_bsock_timer(bsock, auth_timeout);
+}
+
+void AuthenticateBase::StopAuthTimeout()
+{
+   if (tid != NULL) {
+      stop_bsock_timer(tid);
+      tid = NULL;
+   }
+}
+
+/* calculate this->tls_local_need from RES->tls_enable and tls_require */
+/*
+ * psk_local_need
+ *   TLS  |   TLS    |  TLS PSK  |
+ * Enable | Required |  Enable   |
+ * ------------------------------+
+ *    n        n           n          Clear Text
+ *    n        n           y          PSK is welcome
+ *    n        y           n          --
+ *    n        y           y          PSK is REQUIRED
+ *    y        n           n          TLS is welcome
+ *    y        n           y          TLS and PSK are welcome
+ *    y        y           n          TLS is REQUIRED
+ *    y        y           y          TLS or PSK are required
+ */
+void AuthenticateBase::CalcLocalTLSNeedFromRes(bool tls_enable, bool tls_require,
+      bool atls_authenticate, bool atls_verify_peer, alist *atls_verify_list,
+      TLS_CONTEXT *atls_ctx, bool tls_psk_enable, TLS_CONTEXT *apsk_ctx,
+      const char *apassword)
+{
+   tls_authenticate=atls_authenticate;
+   if (tls_enable) {
+      if (tls_require) {
+         tls_local_need = BNET_TLS_REQUIRED;
+      } else {
+         tls_local_need = BNET_TLS_OK;
+      }
+   }
+   if (tls_psk_enable) {
+      if (tls_require) {
+         psk_local_need = BNET_TLS_REQUIRED;
+      } else if (apsk_ctx != NULL) {
+         psk_local_need = BNET_TLS_OK;
+      } else {
+         psk_local_need = BNET_TLS_NONE; /* TLS PSK not available */
+      }
+   }
+   tls_verify_peer = atls_verify_peer;
+   if (tls_verify_peer) {
+      tls_verify_list = atls_verify_list;
+   } else {
+      tls_verify_list = NULL;
+   }
+   tls_ctx = atls_ctx;
+   psk_ctx = apsk_ctx;
+   password = apassword;
+   tlspsk_local_need = tls_local_need+psk_local_need*100; // Encode TLS-PSK need
+   Dmsg1(10, "TLSPSK Local need %d\n", tlspsk_local_need);
+   bsock->tlspsk_local = tlspsk_local_need;
+}
+
+bool AuthenticateBase::CheckTLSRequirement()
+{
+   int msg_type = (local_class == dcDIR && remote_class == dcCON)?M_SECURITY:M_FATAL;
+
+   /* Verify that the connection is willing to meet our TLS requirements */
+   switch (TestTLSRequirement()) {
+   case TLS_REQ_ERR_LOCAL:
+      Jmsg(jcr, msg_type, 0, _("Authorization problem: %s \"%s:%s\" did not advertise required TLS support.\n"),
+           GetRemoteClassShortName(), bsock->who(), bsock->host());
+      return false;
+
+   case TLS_REQ_ERR_REMOTE:
+      Jmsg(jcr, msg_type, 0, _("Authorization problem: %s \"%s:%s\" did not advertise required TLS support.\n"),
+           GetRemoteClassShortName(), bsock->who(), bsock->host());
+      return false;
+   case TLS_REQ_OK:
+      break;
+   }
+   return true;
+}
+
+/* Convert single "remote_need" from remote hello message into PSK and TLS need */
+void AuthenticateBase::DecodeRemoteTLSPSKNeed(int remote_need)
+{
+   tls_remote_need=remote_need%100;
+   psk_remote_need=remote_need/100;
+   Dmsg1(10, "TLSPSK Remote need %d\n", remote_need);
+}
+
+bool AuthenticateBase::ClientEarlyTLS()
+{
+   int tlspsk_remote=0;
+
+   check_early_tls=true;
+   if (bsock->recv() <= 0) {
+      bmicrosleep(5, 0); // original cram_md5_respond() wait for 5s here
+      return false;
+   }
+   if (scan_string(bsock->msg, "starttls tlspsk=%d\n", &tlspsk_remote) != EOF) {
+      DecodeRemoteTLSPSKNeed(tlspsk_remote);
+      if (!HandleTLS()) {
+         return false;
+      }
+      check_early_tls = false; // "tell" cram_md5_respond to do a recv()
+   }
+   return true;
+}
+
+/* DIR is calling, DIR is the client */
+bool AuthenticateBase::ClientCramMD5Authenticate(const char *password)
+{
+   int compatible = true;
+
+   if (!ClientEarlyTLS()) {
+      return false;
+   }
+
+   if (((local_class == dcSD && remote_class == dcSD) ||
+        (local_class == dcFD && remote_class == dcSD))) {
+      if (jcr && job_canceled(jcr)) {
+         auth_success = false;
+         return false;                   /* quick exit */
+      }
+   }
+
+   auth_success = cram_md5_respond(bsock, password, &tls_remote_need, &compatible, check_early_tls);
+
+   if (local_class == dcSD && remote_class == dcSD) {
+      if (jcr && job_canceled(jcr)) {
+         auth_success = false;
+         return false;                   /* quick exit */
+      }
+   }
+
+   if (auth_success) {
+      auth_success = cram_md5_challenge(bsock, password, tls_local_need, compatible);
+      if (!auth_success) {
+         Dmsg2(authdl, "cram_challenge failed for %s: %s\n",
+               GetRemoteClassShortName(), bsock->who());
+      }
+   } else {
+      Dmsg2(authdl, "cram_respond failed for %s: %s\n",
+            GetRemoteClassShortName(), bsock->who());
+   }
+
+   if (!auth_success) {
+      if ((local_class == dcFD && remote_class == dcSD) ||
+          (local_class == dcSD && remote_class == dcFD) ) {
+         Dmsg2(authdl, "Authorization key rejected by %s at %s.\n",
+            GetRemoteClassShortName(), bsock->who());
+         Jmsg(jcr, M_FATAL, 0, _("Authorization key rejected by %s at %s rejected.\n"
+           "For help, please see: " MANUAL_AUTH_URL "\n"),
+            GetRemoteClassLongName(), bsock->who());
+      } else if ((local_class == dcDIR && (remote_class == dcSD || remote_class == dcFD))) {
+         Dmsg2(authdl, _("%s and %s passwords or names not the same.\n"),
+               GetLocalClassLongName(), GetRemoteClassLongName());
+         Jmsg6(jcr, M_FATAL, 0,
+               _("%s unable to authenticate with %s at \"%s:%d\". Possible causes:\n"
+               "Passwords or names not the same or\n"
+               "Maximum Concurrent Jobs exceeded on the %s or\n"
+               "%s networking messed up (restart daemon).\n"
+               "For help, please see: " MANUAL_AUTH_URL "\n"),
+               GetLocalClassLongName(), GetRemoteClassLongName(),
+               bsock->host(), bsock->port(),
+               GetRemoteClassShortName(), GetRemoteClassShortName());
+      } else {
+         // Silent
+      }
+   }
+// TODO check that free_tls() is done at the right place
+   if (tls_authenticate) {       /* authentication only? */
+      bsock->free_tls();         /* yes, stop tls */
+   }
+
+   return auth_success;
+}
+
+bool AuthenticateBase::ServerEarlyTLS()
+{
+   if ((tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) ||
+       (psk_local_need >= BNET_TLS_OK && psk_remote_need >= BNET_TLS_OK)) {
+      /* If both can speak TLS or PSK then send the "starttls" even if the
+       * local requirement is not full filled. The client need to
+       * know the server requirements too. Both will terminate the connection
+       * in HandleTLS if the requirement are not full filled 
+       */
+      if (!bsock->fsend("starttls tlspsk=%d\n", tlspsk_local_need)) {
+// TODO tweak the error message
+         Qmsg3(NULL, M_SECURITY, 0, _("Connection with %s:%s starttls comm error. ERR=%s\n"), bsock->who(),
+               bsock->host(), bsock->bstrerror());
+         sleep(5);
+         return false;
+      }
+      if (!HandleTLS()) {
+         return false;
+      }
+   }
+   return true;
+}
+
+bool AuthenticateBase::ServerCramMD5Authenticate(const char *password)
+{
+   int compatible = true;
+
+   if (!ServerEarlyTLS()) {
+      return false;
+   }
+
+   /* Challenge the director */
+   auth_success = cram_md5_challenge(bsock, password, tls_local_need, compatible);
+   if (local_type == dtSrv && local_class == dcFD && remote_class == dcDIR) {
+      if (jcr && job_canceled(jcr)) {
+         auth_success = false;
+         return false;                   /* quick exit */
+      }
+   }
+   if (auth_success) {
+      auth_success = cram_md5_respond(bsock, password, &tls_remote_need, &compatible);
+      if (!auth_success) {
+         char addr[64];
+         char *who = bsock->get_peer(addr, sizeof(addr)) ? bsock->who() : addr;
+         Dmsg2(authdl, "cram_get_auth respond failed for %s: %s\n",
+               GetRemoteClassShortName(), who);
+      }
+   } else {
+      char addr[64];
+      char *who = bsock->get_peer(addr, sizeof(addr)) ? bsock->who() : addr;
+      Dmsg2(authdl, "cram_auth challenge failed for %s %s\n",
+            GetRemoteClassShortName(), who);
+   }
+
+   if (!auth_success) {
+      if (local_type == dtSrv && local_class == dcDIR && remote_class == dcCON) {
+         // let the authenticate_xxxx() react
+      } else if (local_class == dcGUI) {
+         // let the authenticate_xxxx() react
+      } else if (local_type == dtSrv && local_class == dcFD && remote_class == dcDIR) {
+         Emsg1(M_FATAL, 0, _("Incorrect password given by Director at %s.\n"),
+             bsock->who());
+      } else if ((local_class == dcFD && remote_class == dcSD) ||
+                 (local_class == dcSD && remote_class == dcFD) ) {
+         Jmsg(jcr, M_FATAL, 0, _("Incorrect authorization key from %s at %s rejected.\n"
+              "For help, please see: " MANUAL_AUTH_URL "\n"),
+               GetRemoteClassLongName(), bsock->who());
+      } else {
+         Jmsg1(jcr, M_FATAL, 0, _("Incorrect password given by %s.\n"
+          "For help, please see: " MANUAL_AUTH_URL "\n"), GetRemoteClassLongName());
+      }
+   }
+   if (tls_authenticate) {       /* authentication only? */
+      bsock->free_tls();         /* yes, stop tls */
+   }
+
+   return auth_success;
+}
+
+void AuthenticateBase::TLSFailure()
+{
+   Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed with %s at \"%s:%d\"\n"),
+         GetRemoteClassShortName(), bsock->host(), bsock->port());
+}
+
+bool AuthenticateBase::HandleTLS()
+{
+   if (tls_started) {
+      return true;
+   }
+   if (!CheckTLSRequirement()) {
+      return false;
+   }
+
+   /* Is TLS Enabled? */
+   if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
+      /* Engage TLS! Full Speed Ahead! */
+      ctx = tls_ctx;
+      Dmsg0(10, "TLSPSK Start TLS\n");
+   } else if (psk_local_need >= BNET_TLS_OK && psk_remote_need >= BNET_TLS_OK) {
+      ctx = psk_ctx;
+      Dmsg0(10, "TLSPSK Start PSK\n");
+   } else {
+      ctx = NULL;
+      Dmsg0(DT_NETWORK, "TLSPSK Start CLEAR\n");
+      // Qmsg0(jcr, M_INFO, 0, _("Start connection in CLEAR-TEXT\n"));
+   }
+   if (ctx != NULL) {
+      if ((local_type==dtCli && !bnet_tls_client(ctx, bsock, verify_list, password)) ||
+          (local_type==dtSrv && !bnet_tls_server(ctx, bsock, verify_list, password))) {
+         TLSFailure();
+         return false;
+      }
+      tls_started = true;
+   }
+   return true;
+}