]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
BEE Backport bacula/src/stored/authenticate.c
authorAlain Spineux <alain@baculasystems.com>
Tue, 12 May 2020 16:37:15 +0000 (18: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: Alain Spineux <alain@baculasystems.com>
Date:   Fri Apr 12 04:55:10 2019 +0200

    PSK: encrypt copy jobs (SD-SD )

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: Eric Bollengier <eric@baculasystems.com>
Date:   Thu Mar 12 10:01:54 2015 +0100

    Ensure that only one thread can use the auth code in the Storage

Author: Kern Sibbald <kern@sibbald.com>
Date:   Fri Jun 20 21:32:36 2014 +0200

    Refactor the SD Hello code to put it all in hello.c

bacula/src/stored/authenticate.c

index f2aace5ebd0d5907da8b60379abb0c9774e444a5..83eb1b41827bddae4b0129ba50d1399acc071f43 100644 (file)
@@ -20,6 +20,7 @@
  * Authenticate caller
  *
  *   Written by Kern Sibbald, October 2000
+ *
  */
 
 
@@ -32,194 +33,83 @@ const int dbglvl = 50;
 
 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 
-/* Version at end of Hello
- *   prior to 06Aug13 no version
- *   1 06Aug13 - added comm line compression
- *   2 13Dec13 - added api version to status command
- */
-#define SD_VERSION 2
-
+SDAuthenticateDIR::SDAuthenticateDIR(JCR *jcr):
+AuthenticateBase(jcr, jcr->dir_bsock, dtSrv, dcSD, dcDIR)
+{
+}
 
 /*
  * Authenticate the Director
  */
-bool authenticate_director(JCR* jcr)
+bool SDAuthenticateDIR::authenticate_director()
 {
-   DIRRES *director = jcr->director;
-   int tls_local_need = BNET_TLS_NONE;
-   int tls_remote_need = BNET_TLS_NONE;
-   int compatible = true;                  /* require md5 compatible DIR */
-   bool auth_success = false;
-   alist *verify_list = NULL;
    BSOCK *dir = jcr->dir_bsock;
+   DIRRES *director = jcr->director;
 
-   /* 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;
-   }
+   DecodeRemoteTLSPSKNeed(bsock->tlspsk_remote);
 
-   if (director->tls_verify_peer) {
-      verify_list = director->tls_allowed_cns;
-   }
+   /* TLS Requirement */
+   CalcLocalTLSNeedFromRes(director->tls_enable, director->tls_require,
+         director->tls_authenticate, director->tls_verify_peer,
+         director->tls_allowed_cns, director->tls_ctx,
+         director->tls_psk_enable, director->psk_ctx, director->password);
 
    /* Timeout authentication after 10 mins */
-   btimer_t *tid = start_bsock_timer(dir, AUTH_TIMEOUT);
-   auth_success = cram_md5_challenge(dir, director->password, tls_local_need, compatible);
-   if (auth_success) {
-      auth_success = cram_md5_respond(dir, director->password, &tls_remote_need, &compatible);
-      if (!auth_success) {
-         Dmsg1(dbglvl, "cram_get_auth respond failed with Director %s\n", dir->who());
-      }
-   } else {
-      Dmsg1(dbglvl, "cram_auth challenge failed with Director %s\n", dir->who());
-   }
-
-   if (!auth_success) {
-      Jmsg0(jcr, M_FATAL, 0, _("Incorrect password given by Director.\n"
-       "For help, please see: " MANUAL_AUTH_URL "\n"));
-      auth_success = false;
-      goto auth_fatal;
-   }
+   StartAuthTimeout();
 
-   /* 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) {
-      Jmsg0(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not"
-           " advertize required TLS support.\n"));
-      Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
-      auth_success = false;
-      goto auth_fatal;
-   }
-
-   /* 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) {
-      Jmsg0(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n"));
-      Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
-      auth_success = false;
+   /* Challenge the director */
+   if (!ServerCramMD5Authenticate(password)) {
       goto auth_fatal;
    }
 
-   if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
-      /* Engage TLS! Full Speed Ahead! */
-      if (!bnet_tls_server(director->tls_ctx, dir, verify_list)) {
-         Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed with DIR at \"%s:%d\"\n"),
-            dir->host(), dir->port());
-         auth_success = false;
-         goto auth_fatal;
-      }
-      if (director->tls_authenticate) {     /* authenticate with tls only? */
-         dir->free_tls();                   /* yes, shut it down */
-      }
-   }
+   this->auth_success = HandleTLS();
 
 auth_fatal:
-   stop_bsock_timer(tid);
-   jcr->director = director;
    if (auth_success) {
       return send_hello_ok(dir);
    }
    send_sorry(dir);
-   Dmsg1(dbglvl, "Unable to authenticate Director at %s.\n", dir->who());
-   Jmsg1(jcr, M_ERROR, 0, _("Unable to authenticate Director at %s.\n"), dir->who());
    bmicrosleep(5, 0);
    return false;
 }
 
-
-int authenticate_filed(JCR *jcr, BSOCK *fd, int FDVersion)
+class SDAuthenticateFD: public AuthenticateBase
 {
-   int tls_local_need = BNET_TLS_NONE;
-   int tls_remote_need = BNET_TLS_NONE;
-   int compatible = true;                 /* require md5 compatible FD */
-   bool auth_success = false;
-   alist *verify_list = NULL;
-
-   /* TLS Requirement */
-   if (me->tls_enable) {
-      if (me->tls_require) {
-         tls_local_need = BNET_TLS_REQUIRED;
-      } else {
-         tls_local_need = BNET_TLS_OK;
-      }
+public:
+   SDAuthenticateFD(JCR *jcr, BSOCK *bsock):
+   AuthenticateBase(jcr, bsock, dtSrv, dcSD, dcFD)
+   {
    }
+   virtual ~SDAuthenticateFD() {};
+   int authenticate_filed(int FDVersion);
+};
 
-   if (me->tls_authenticate) {
-      tls_local_need = BNET_TLS_REQUIRED;
-   }
-
-   if (me->tls_verify_peer) {
-      verify_list = me->tls_allowed_cns;
-   }
+int authenticate_filed(JCR *jcr, BSOCK *fd, int FDVersion)
+{
+   return SDAuthenticateFD(jcr, fd).authenticate_filed(FDVersion);
+}
 
-   /* Timeout authentication after 5 mins */
-   btimer_t *tid = start_bsock_timer(fd, AUTH_TIMEOUT);
-   /* Challenge FD */
-   Dmsg0(050, "Challenge FD\n");
-   auth_success = cram_md5_challenge(fd, jcr->sd_auth_key, tls_local_need, compatible);
-   if (auth_success) {
-       /* Respond to his challenge */
-       Dmsg0(050, "Respond to FD challenge\n");
-       auth_success = cram_md5_respond(fd, jcr->sd_auth_key, &tls_remote_need, &compatible);
-       if (!auth_success) {
-          Dmsg1(dbglvl, "Respond cram-get-auth respond failed with FD: %s\n", fd->who());
-       }
-   } else {
-      Dmsg1(dbglvl, "Challenge cram-auth failed with FD: %s\n", fd->who());
-   }
+int SDAuthenticateFD::authenticate_filed(int FDVersion)
+{
+   BSOCK *fd = bsock;
 
-   if (!auth_success) {
-      Jmsg(jcr, M_FATAL, 0, _("Incorrect authorization key from File daemon at %s rejected.\n"
-       "For help, please see: " MANUAL_AUTH_URL "\n"),
-           fd->who());
-      auth_success = false;
-      goto auth_fatal;
-   }
+   DecodeRemoteTLSPSKNeed(bsock->tlspsk_remote);
+   /* TLS Requirement */
+   CalcLocalTLSNeedFromRes(me->tls_enable, me->tls_require, me->tls_authenticate,
+         me->tls_verify_peer, me->tls_allowed_cns, me->tls_ctx,
+         me->tls_psk_enable, me->psk_ctx, jcr->sd_auth_key);
 
-   /* 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) {
-      Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not"
-           " advertize required TLS support.\n"));
-      Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
-      auth_success = false;
-      goto auth_fatal;
-   }
+   /* Timeout authentication after 10 mins */
+   StartAuthTimeout();
 
-   /* 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) {
-      Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n"));
-      Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
-      auth_success = false;
+   /* Challenge the FD */
+   if (!ServerCramMD5Authenticate(jcr->sd_auth_key)) {
       goto auth_fatal;
    }
 
-   if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
-      /* Engage TLS! Full Speed Ahead! */
-      if (!bnet_tls_server(me->tls_ctx, fd, verify_list)) {
-         Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed with FD at \"%s:%d\"\n"),
-            fd->host(), fd->port());
-         auth_success = false;
-         goto auth_fatal;
-      }
-      if (me->tls_authenticate) {          /* tls authenticate only? */
-         fd->free_tls();                   /* yes, shut it down */
-      }
-   }
+   this->auth_success = HandleTLS();
 
 auth_fatal:
-   stop_bsock_timer(tid);
-   if (!auth_success) {
-      Jmsg(jcr, M_FATAL, 0, _("Incorrect authorization key from File daemon at %s rejected.\n"
-       "For help, please see: " MANUAL_AUTH_URL "\n"),
-           fd->who());
-   }
-
    /* Version 5 of the protocol is a bit special, it is used by both 6.0.0
     * Enterprise version and 7.0.x Community version, but do not support the
     * same level of features. As nobody is using the 6.0.0 release, we can
@@ -231,93 +121,54 @@ auth_fatal:
    return auth_success;
 }
 
+class SDAuthenticateSD: public AuthenticateBase
+{
+public:
+   SDAuthenticateSD(JCR *jcr):
+   AuthenticateBase(jcr, jcr->store_bsock, dtCli, dcSD, dcSD) {
+      /* TLS Requirement */
+      CalcLocalTLSNeedFromRes(me->tls_enable, me->tls_require, me->tls_authenticate,
+            me->tls_verify_peer, me->tls_allowed_cns, me->tls_ctx,
+            me->tls_psk_enable, me->psk_ctx, jcr->sd_auth_key);
+   }
+   virtual ~SDAuthenticateSD() {};
+   bool authenticate_storagedaemon();
+};
+
+
+bool send_hello_and_authenticate_sd(JCR *jcr, char *Job)
+{
+   SDAuthenticateSD auth(jcr);
+   /* TODO disable PSK/TLS when the SD talk to itself */
+   if (!send_hello_sd(jcr, Job, auth.GetTLSPSKLocalNeed())) {
+      return false;
+   }
+   return auth.authenticate_storagedaemon();
+}
+
 /*
  * First prove our identity to the Storage daemon, then
  * make him prove his identity.
  */
-bool authenticate_storagedaemon(JCR *jcr)
+bool SDAuthenticateSD::authenticate_storagedaemon()
 {
    BSOCK *sd = jcr->store_bsock;
-   int tls_local_need = BNET_TLS_NONE;
-   int tls_remote_need = BNET_TLS_NONE;
-   int compatible = true;
-   bool auth_success = false;
    int sd_version = 0;
 
-   btimer_t *tid = start_bsock_timer(sd, AUTH_TIMEOUT);
-
-   /* TLS Requirement */
-   if (have_tls && me->tls_enable) {
-      if (me->tls_require) {
-         tls_local_need = BNET_TLS_REQUIRED;
-      } else {
-         tls_local_need = BNET_TLS_OK;
-      }
-   }
-
-   if (me->tls_authenticate) {
-      tls_local_need = BNET_TLS_REQUIRED;
-   }
+   /* Timeout authentication after 10 mins */
+   StartAuthTimeout();
 
-   if (job_canceled(jcr)) {
-      auth_success = false;     /* force quick exit */
+   /* Challenge the FD */
+   if (!ClientCramMD5Authenticate(jcr->sd_auth_key)) {
       goto auth_fatal;
    }
 
-   /* Respond to SD challenge */
-   Dmsg0(050, "Respond to SD challenge\n");
-   auth_success = cram_md5_respond(sd, jcr->sd_auth_key, &tls_remote_need, &compatible);
-   if (job_canceled(jcr)) {
-      auth_success = false;     /* force quick exit */
-      goto auth_fatal;
-   }
-   if (!auth_success) {
-      Dmsg1(dbglvl, "cram_respond failed for SD: %s\n", sd->who());
-   } else {
-      /* Now challenge him */
-      Dmsg0(050, "Challenge SD\n");
-      auth_success = cram_md5_challenge(sd, jcr->sd_auth_key, tls_local_need, compatible);
-      if (!auth_success) {
-         Dmsg1(dbglvl, "cram_challenge failed for SD: %s\n", sd->who());
-      }
-   }
+   this->auth_success = HandleTLS();
 
    if (!auth_success) {
-      Jmsg(jcr, M_FATAL, 0, _("Authorization key rejected by Storage daemon.\n"
-       "Please see " MANUAL_AUTH_URL " for help.\n"));
-      goto auth_fatal;
-   } else {
-      Dmsg0(050, "Authorization with SD is OK\n");
-   }
-
-   /* 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) {
-      Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not"
-           " advertize required TLS support.\n"));
-      Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
-      auth_success = false;
       goto auth_fatal;
    }
 
-   /* 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) {
-      Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n"));
-      Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
-      auth_success = false;
-      goto auth_fatal;
-   }
-
-   if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
-      /* Engage TLS! Full Speed Ahead! */
-      if (!bnet_tls_client(me->tls_ctx, sd, NULL)) {
-         Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed.\n"));
-         auth_success = false;
-         goto auth_fatal;
-      }
-      if (me->tls_authenticate) {           /* tls authentication only? */
-         sd->free_tls();                    /* yes, shutdown tls */
-      }
-   }
    if (sd->recv() <= 0) {
       auth_success = false;
       goto auth_fatal;
@@ -335,7 +186,6 @@ bool authenticate_storagedaemon(JCR *jcr)
 auth_fatal:
    /* Destroy session key */
    memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
-   stop_bsock_timer(tid);
    /* Single thread all failures to avoid DOS */
    if (!auth_success) {
       P(mutex);