]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
BEE Backport bacula/src/console/authenticate.c
authorAlain Spineux <alain@baculasystems.com>
Tue, 12 May 2020 20:37:14 +0000 (22:37 +0200)
committerEric Bollengier <eric@baculasystems.com>
Thu, 29 Apr 2021 08:44:18 +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: Alain Spineux <alain@baculasystems.com>
Date:   Tue Apr 23 16:46:55 2019 +0200

    PSK: make AuthenticateBase::CheckTLSRequirement() virtual

    - move the CheckTLSRequirement() aka "error handling" to the sub-class
    - cleanup a bit the not needed anymore "helper"

Author: Alain Spineux <alain@baculasystems.com>
Date:   Mon Apr 8 14:56:45 2019 +0200

    PSK: Modify authentication in each daemon to support PSK

    - use AuthenticateBase class

Author: Alain Spineux <alain@baculasystems.com>
Date:   Thu Apr 19 17:33:55 2018 +0200

    fix #3694 bconsole show message when MaximumConsoleConnections limit is reached

    - When the director reach the MaximumConsoleConnections limit, it queues
      the new bconsole connections until one bconsole disconnect.
    - Now, when bconsole timeout, it display an appropriate message
    - The time out entries in the queues look to be cleaned up in < 30s

Author: Kern Sibbald <kern@sibbald.com>
Date:   Wed May 17 13:57:59 2017 +0200

    Add community daemon versions

Author: Eric Bollengier <eric@baculasystems.com>
Date:   Mon Feb 29 16:12:21 2016 +0100

    Allow bconsole to connect to FD

Author: Kern Sibbald <kern@sibbald.com>
Date:   Mon Oct 21 15:41:49 2013 +0200

    Add code to turn off comm line compression

bacula/src/console/authenticate.c

index 5405220191f454a6bebd6a5cd17f553b13b637e6..9331cd2de38e4d1a845845a85c0347904801a91b 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula(R) - The Network Backup Solution
 
-   Copyright (C) 2000-2017 Kern Sibbald
+   Copyright (C) 2000-2020 Kern Sibbald
 
    The original author of Bacula is Kern Sibbald, with contributions
    from many others, a complete list can be found in the file AUTHORS.
@@ -11,7 +11,7 @@
    Public License, v3.0 ("AGPLv3") and some additional permissions and
    terms pursuant to its AGPLv3 Section 7.
 
-   This notice must be preserved when any source code is 
+   This notice must be preserved when any source code is
    conveyed and/or propagated.
 
    Bacula(R) is a registered trademark of Kern Sibbald.
  *   prior to 06Aug13 no version
  *   100  14Feb17 - added comm line compression
  */
-#define UA_VERSION 100
+#ifndef COMMUNITY
+#define UA_VERSION 1   /* Enterprise */
+#else
+#define UA_VERSION 100 /* Community */
+#endif
 
 void senditf(const char *fmt, ...);
 void sendit(const char *buf);
 
 /* Commands sent to Director */
-static char hello[]    = "Hello %s calling %d\n";
+static char hello[]    = "Hello %s calling %d tlspsk=%d\n";
 
 /* Response from Director */
 static char oldOKhello[]   = "1000 OK:";
 static char newOKhello[]   = "1000 OK: %d";
-static char FDOKhello[]    = "2000 OK Hello %d";
+static char FDOKhello[]   = "2000 OK Hello %d";
 
-/* Forward referenced functions */
+class ConsoleAuthenticate: public AuthenticateBase
+{
+public:
+   ConsoleAuthenticate(BSOCK *dir):
+   AuthenticateBase(NULL, dir, dtCli, dcCON, dcDIR)
+   {
+   }
+   virtual ~ConsoleAuthenticate() {};
+   virtual void TLSFailure() { sendit(_("TLS negotiation failed\n")); }
+   virtual bool CheckTLSRequirement();
+
+   int authenticate_director(DIRRES *director, CONRES *cons);
+};
+
+
+int authenticate_director(BSOCK *dir, DIRRES *director, CONRES *cons)
+{
+   ConsoleAuthenticate auth(dir);
+   return auth.authenticate_director(director, cons);
+}
+
+bool ConsoleAuthenticate::CheckTLSRequirement()
+{
+   /* Verify that the connection is willing to meet our TLS requirements */
+   switch (TestTLSRequirement()) {
+   case TLS_REQ_ERR_LOCAL:
+     sendit(_("Authorization problem:"
+             " Remote server requires TLS.\n"));
+      return false;
+
+   case TLS_REQ_ERR_REMOTE:
+      sendit(_("Authorization problem:"
+             " Remote server did not advertise required TLS support.\n"));
+      return false;
+   case TLS_REQ_OK:
+      break;
+   }
+   return true;
+}
 
 /*
  * Authenticate Director
  */
-int authenticate_director(BSOCK *dir, DIRRES *director, CONRES *cons)
+int ConsoleAuthenticate::authenticate_director(DIRRES *director, CONRES *cons)
 {
-   int tls_local_need = BNET_TLS_NONE;
-   int tls_remote_need = BNET_TLS_NONE;
-   bool tls_authenticate;
-   int compatible = true;
+   BSOCK *dir = bsock;
    int dir_version = 0;
-   int fd_version = 0;
    char bashed_name[MAX_NAME_LENGTH];
-   char *password;
-   TLS_CONTEXT *tls_ctx = NULL;
-            
+   bool skip_msg = false;
    /*
     * Send my name to the Director then do authentication
     */
    if (cons) {
       bstrncpy(bashed_name, cons->hdr.name, sizeof(bashed_name));
       bash_spaces(bashed_name);
-      password = cons->password;
-      /* TLS Requirement */
-      if (cons->tls_enable) {
-         if (cons->tls_require) {
-            tls_local_need = BNET_TLS_REQUIRED;
-         } else {
-            tls_local_need = BNET_TLS_OK;
-         }
-      }
-      if (cons->tls_authenticate) {
-         tls_local_need = BNET_TLS_REQUIRED;
-      }
-      tls_authenticate = cons->tls_authenticate;
-      tls_ctx = cons->tls_ctx;
+      CalcLocalTLSNeedFromRes(cons->tls_enable, cons->tls_require,
+            cons->tls_authenticate, false, NULL, cons->tls_ctx,
+            cons->tls_psk_enable, cons->psk_ctx, cons->password);
+
    } else {
       bstrncpy(bashed_name, "*UserAgent*", sizeof(bashed_name));
-      password = director->password;
-      /* TLS Requirement */
-      if (director->tls_enable) {
-         if (director->tls_require) {
-            tls_local_need = BNET_TLS_REQUIRED;
-         } else {
-            tls_local_need = BNET_TLS_OK;
-         }
-      }
-
-      if (director->tls_authenticate) {
-         tls_local_need = BNET_TLS_REQUIRED;
-      }
-      tls_authenticate = director->tls_authenticate;
-      tls_ctx = director->tls_ctx;
+      CalcLocalTLSNeedFromRes(director->tls_enable, director->tls_require,
+            director->tls_authenticate, false, NULL, director->tls_ctx,
+            director->tls_psk_enable, director->psk_ctx, director->password);
    }
 
-
    /* Timeout Hello after 15 secs */
-   btimer_t *tid = start_bsock_timer(dir, 15);
-   dir->fsend(hello, bashed_name, UA_VERSION);
+   StartAuthTimeout(15);
 
-   if (!cram_md5_respond(dir, password, &tls_remote_need, &compatible) ||
-       !cram_md5_challenge(dir, password, tls_local_need, compatible)) {
-      goto bail_out;
-   }
+   dir->fsend(hello, bashed_name, UA_VERSION, tlspsk_local_need);
 
-   /* Verify that the remote host is willing to meet our TLS requirements */
-   if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
-      sendit(_("Authorization problem:"
-             " Remote server did not advertise required TLS support.\n"));
+   if (!ClientCramMD5Authenticate(password)) {
+      if (dir->is_timed_out()) {
+         sendit(_("The Director is busy or the MaximumConsoleConnections limit is reached.\n"));
+         skip_msg = true;
+      }
       goto bail_out;
    }
 
-   /* Verify that we are willing to meet the remote host's requirements */
-   if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
-      sendit(_("Authorization problem:"
-             " Remote server requires TLS.\n"));
+   if (!HandleTLS()) {
       goto bail_out;
    }
 
-   /* Is TLS Enabled? */
-   if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
-      /* Engage TLS! Full Speed Ahead! */
-      if (!bnet_tls_client(tls_ctx, dir, NULL)) {
-         sendit(_("TLS negotiation failed\n"));
-         goto bail_out;
-      }
-      if (tls_authenticate) {           /* Authenticate only? */
-         dir->free_tls();               /* yes, shutdown tls */
-      }
-   }
-
    /*
     * It's possible that the TLS connection will
     * be dropped here if an invalid client certificate was presented
@@ -161,28 +156,30 @@ int authenticate_director(BSOCK *dir, DIRRES *director, CONRES *cons)
       /* If Dir version exists, get it */
       sscanf(dir->msg, newOKhello, &dir_version);
       sendit(dir->msg);
-   /* Check for hello from FD */
-   } else if (sscanf(dir->msg, FDOKhello, &fd_version) == 1) {
+
+      /* We do not check the last %d */
+   } else if (strncmp(dir->msg, FDOKhello, sizeof(FDOKhello)-3) == 0) {
+      sscanf(dir->msg, FDOKhello, &dir_version);
       sendit(dir->msg);
+
    } else {
       sendit(_("Director rejected Hello command\n"));
       goto bail_out;
    }
    /* Turn on compression for newer Directors */
-   if (dir_version >= 103 && (!cons || cons->comm_compression)) {
+   if (dir_version >= 1 && (!cons || cons->comm_compression)) {
       dir->set_compress();
    } else {
       dir->clear_compress();
    }
-   /* ***FIXME*** should turn on compression for FD if possible */
-   stop_bsock_timer(tid);
    return 1;
 
 bail_out:
-   stop_bsock_timer(tid);
-   sendit( _("Director authorization problem.\n"
+   if (!skip_msg) {
+      sendit( _("Director authorization problem.\n"
              "Most likely the passwords do not agree.\n"
              "If you are using TLS, there may have been a certificate validation error during the TLS handshake.\n"
              "For help, please see " MANUAL_AUTH_URL "\n"));
+   }
    return 0;
 }