/*
Bacula® - The Network Backup Solution
- Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
+ Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
- The main author of Bacula is Kern Sibbald, with contributions from
- many others, a complete list can be found in the file AUTHORS.
- This program is Free Software; you can redistribute it and/or
- modify it under the terms of version three of the GNU Affero General Public
- License as published by the Free Software Foundation and included
- in the file LICENSE.
+ The main author of Bacula is Kern Sibbald, with contributions from many
+ others, a complete list can be found in the file AUTHORS.
- 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 Affero 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.
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
Bacula® is a registered trademark of Kern Sibbald.
- The licensor of Bacula is the Free Software Foundation Europe
- (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
- Switzerland, email:ftf@fsfeurope.org.
*/
/*
* Authenticate caller
*
- * Kern Sibbald, October 2000
+ * Written by Kern Sibbald, October 2000
*
*/
#include "bacula.h"
#include "stored.h"
+extern STORES *me; /* our Global resource */
+
+
const int dbglvl = 50;
+/* Version at end of Hello
+ * prior to 06Aug13 no version
+ * 1 06Aug13 - added comm line compression
+ * 2 13Dec13 - added api version to status command
+ * 3 22Feb14 - Added SD->SD with SD_Calls_Client
+ */
+#define SD_VERSION 3
+#define FD_VERSION 10
+static char hello_sd[] = "Hello Bacula SD: Start Job %s %d %d\n";
+
+
static char Dir_sorry[] = "3999 No go\n";
-static char OK_hello[] = "3000 OK Hello\n";
+static char OK_hello[] = "3000 OK Hello %d\n";
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
/*********************************************************************
*
int compatible = true; /* require md5 compatible DIR */
bool auth_success = false;
alist *verify_list = NULL;
+ int dir_version = 0;
if (rcode != R_DIRECTOR) {
Dmsg1(dbglvl, "I only authenticate Directors, not %d\n", rcode);
dirname = get_pool_memory(PM_MESSAGE);
dirname = check_pool_memory_size(dirname, bs->msglen);
- if (sscanf(bs->msg, "Hello Director %127s calling", dirname) != 1) {
+ if (sscanf(bs->msg, "Hello SD: Bacula Director %127s calling %d",
+ dirname, &dir_version) != 2 &&
+ sscanf(bs->msg, "Hello SD: Bacula Director %127s calling",
+ dirname) != 1) {
bs->msg[100] = 0;
Dmsg2(dbglvl, "Bad Hello command from Director at %s: %s\n",
bs->who(), bs->msg);
Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s: %s\n"),
bs->who(), bs->msg);
+ free_pool_memory(dirname);
return 0;
}
director = NULL;
unbash_spaces(dirname);
foreach_res(director, rcode) {
- if (strcmp(director->hdr.name, dirname) == 0) {
+ if (strcasecmp(director->hdr.name, dirname) == 0) {
break;
}
}
if (auth_success) {
auth_success = cram_md5_respond(bs, director->password, &tls_remote_need, &compatible);
if (!auth_success) {
- Dmsg1(dbglvl, "cram_get_auth failed with %s\n", bs->who());
+ Dmsg1(dbglvl, "cram_get_auth respond failed with Director %s\n", bs->who());
}
} else {
- Dmsg1(dbglvl, "cram_auth failed with %s\n", bs->who());
+ Dmsg1(dbglvl, "cram_auth challenge failed with Director %s\n", bs->who());
}
if (!auth_success) {
/* 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"
+ 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;
BSOCK *dir = jcr->dir_bsock;
if (!authenticate(R_DIRECTOR, dir, jcr)) {
- dir->fsend("%s", Dir_sorry);
+ dir->fsend(Dir_sorry);
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 0;
}
- return dir->fsend("%s", OK_hello);
+ return dir->fsend(OK_hello, SD_VERSION);
}
int authenticate_filed(JCR *jcr)
/* Timeout Hello 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 failed with %s\n", fd->who());
+ Dmsg1(dbglvl, "Respond cram-get-auth respond failed with FD: %s\n", fd->who());
}
} else {
- Dmsg1(dbglvl, "Challenge cram-auth failed with %s\n", fd->who());
+ Dmsg1(dbglvl, "Challenge cram-auth failed with FD: %s\n", fd->who());
}
if (!auth_success) {
/* 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"
+ 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;
fd->who());
}
jcr->authenticated = auth_success;
+ if (auth_success && jcr->FDVersion >= 5) {
+ /* Send hello and our version to FD */
+ fd->fsend(OK_hello, SD_VERSION);
+ }
+ return auth_success;
+}
+
+/*
+ * First prove our identity to the Storage daemon, then
+ * make him prove his identity.
+ */
+bool authenticate_storagedaemon(JCR *jcr, char *Job)
+{
+ 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;
+ }
+
+ if (job_canceled(jcr)) {
+ auth_success = false; /* force quick exit */
+ goto auth_fatal;
+ }
+
+
+ bash_spaces(Job);
+ sd->fsend(hello_sd, Job, FD_VERSION, SD_VERSION);
+ Dmsg1(100, "Send to SD: %s\n", sd->msg);
+
+ /* 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());
+ }
+ }
+
+ 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;
+ }
+ sscanf(sd->msg, "3000 OK Hello %d", &sd_version);
+
+ /* At this point, we have successfully connected */
+
+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);
+ bmicrosleep(6, 0);
+ V(mutex);
+ }
return auth_success;
}