From 69b97b052c23cb5f566b1ef7ea888ec7b528f426 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Mon, 21 May 2007 10:54:24 +0000 Subject: [PATCH] Begin adding TLS support to bat. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@4864 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/console/authenticate.c | 6 +- .../src/qt-console/console/authenticate.cpp | 72 +++++++++++++++--- bacula/src/qt-console/console/console.cpp | 75 +++++++++++++++++++ bacula/src/version.h | 4 +- bacula/technotes-2.1 | 1 + 5 files changed, 143 insertions(+), 15 deletions(-) diff --git a/bacula/src/console/authenticate.c b/bacula/src/console/authenticate.c index 2cb65cbd62..f99331172c 100644 --- a/bacula/src/console/authenticate.c +++ b/bacula/src/console/authenticate.c @@ -102,7 +102,7 @@ int authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons) /* Timeout Hello after 5 mins */ btimer_t *tid = start_bsock_timer(dir, 60 * 5); - bnet_fsend(dir, hello, bashed_name); + dir->fsend(hello, bashed_name); if (!cram_md5_respond(dir, password, &tls_remote_need, &compatible) || !cram_md5_challenge(dir, password, tls_local_need, compatible)) { @@ -139,9 +139,9 @@ int authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons) * be dropped here if an invalid client certificate was presented */ Dmsg1(6, ">dird: %s", dir->msg); - if (bnet_recv(dir) <= 0) { + if (dir->recv() <= 0) { senditf(_("Bad response to Hello command: ERR=%s\n"), - bnet_strerror(dir)); + dir->bstrerror()); goto bail_out; } diff --git a/bacula/src/qt-console/console/authenticate.cpp b/bacula/src/qt-console/console/authenticate.cpp index dd5b3533a6..7ef47a1431 100644 --- a/bacula/src/qt-console/console/authenticate.cpp +++ b/bacula/src/qt-console/console/authenticate.cpp @@ -60,6 +60,7 @@ bool Console::authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons) int compatible = true; char bashed_name[MAX_NAME_LENGTH]; char *password; + TLS_CONTEXT *tls_ctx = NULL; /* * Send my name to the Director then do authentication @@ -68,36 +69,79 @@ bool Console::authenticate_director(JCR *jcr, DIRRES *director, CONRES *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; + } + } + + tls_ctx = cons->tls_ctx; } 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; + } + } + + tls_ctx = director->tls_ctx; } - /* Timeout Hello after 5 mins */ - btimer_t *tid = start_bsock_timer(dir, 60 * 5); - bnet_fsend(dir, hello, bashed_name); + /* Timeout Hello after 30 secs */ + btimer_t *tid = start_bsock_timer(dir, 30); + dir->fsend(hello, bashed_name); /* respond to Dir challenge */ if (!cram_md5_respond(dir, password, &tls_remote_need, &compatible) || /* Now challenge dir */ !cram_md5_challenge(dir, password, tls_local_need, compatible)) { - stop_bsock_timer(tid); printf(_("%s: Director authorization problem.\n"), my_name); display_text(_("Director authorization problem.\n")); - display_text(_( - "Please see http://www.bacula.org/rel-manual/faq.html#AuthorizationErrors for help.\n")); - return false; + goto bail_out; + } + + /* 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) { + display_text(_("Authorization problem:" + " Remote server did not advertise required TLS support.\n")); + 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) { + display_text(_("Authorization problem:" + " Remote server requires TLS.\n")); + goto bail_out; + } + + /* Is TLS Enabled? */ + if (have_tls) { + 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)) { + display_text(_("TLS negotiation failed\n")); + goto bail_out; + } + } } Dmsg1(6, ">dird: %s", dir->msg); - if (bnet_recv(dir) <= 0) { + if (dir->recv() <= 0) { stop_bsock_timer(tid); display_textf(_("Bad response to Hello command: ERR=%s\n"), - bnet_strerror(dir)); + dir->bstrerror()); printf(_("%s: Bad response to Hello command: ERR=%s\n"), - my_name, bnet_strerror(dir)); + my_name, dir->bstrerror()); display_text(_("The Director is probably not running.\n")); return false; } + stop_bsock_timer(tid); Dmsg1(10, "msg); if (strncmp(dir->msg, OKhello, sizeof(OKhello)-1) != 0) { @@ -107,4 +151,12 @@ bool Console::authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons) display_text(dir->msg); } return true; + +bail_out: + stop_bsock_timer(tid); + display_text(_("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" + "Please see http://www.bacula.org/rel-manual/faq.html#AuthorizationErrors for help.\n")); + return false; } diff --git a/bacula/src/qt-console/console/console.cpp b/bacula/src/qt-console/console/console.cpp index f1bec8d873..168ef97823 100644 --- a/bacula/src/qt-console/console/console.cpp +++ b/bacula/src/qt-console/console/console.cpp @@ -41,6 +41,9 @@ #include "select.h" #include "run/run.h" +static int tls_pem_callback(char *buf, int size, const void *userdata); + + Console::Console(QStackedWidget *parent) { QFont font; @@ -119,6 +122,48 @@ void Console::connect() CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL); UnlockRes(); + char buf[1024]; + /* Initialize Console TLS context */ + if (cons && (cons->tls_enable || cons->tls_require)) { + /* Generate passphrase prompt */ + bsnprintf(buf, sizeof(buf), "Passphrase for Console \"%s\" TLS private key: ", cons->hdr.name); + + /* Initialize TLS context: + * Args: CA certfile, CA certdir, Certfile, Keyfile, + * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer + */ + cons->tls_ctx = new_tls_context(cons->tls_ca_certfile, + cons->tls_ca_certdir, cons->tls_certfile, + cons->tls_keyfile, tls_pem_callback, &buf, NULL, true); + + if (!cons->tls_ctx) { + display_textf(_("Failed to initialize TLS context for Console \"%s\".\n"), + m_dir->hdr.name); + return; + } + } + + /* Initialize Director TLS context */ + if (m_dir->tls_enable || m_dir->tls_require) { + /* Generate passphrase prompt */ + bsnprintf(buf, sizeof(buf), "Passphrase for Director \"%s\" TLS private key: ", + m_dir->hdr.name); + + /* Initialize TLS context: + * Args: CA certfile, CA certdir, Certfile, Keyfile, + * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */ + m_dir->tls_ctx = new_tls_context(m_dir->tls_ca_certfile, + m_dir->tls_ca_certdir, m_dir->tls_certfile, + m_dir->tls_keyfile, tls_pem_callback, &buf, NULL, true); + + if (!m_dir->tls_ctx) { + display_textf(_("Failed to initialize TLS context for Director \"%s\".\n"), + m_dir->hdr.name); + mainWin->set_status("Connection failed"); + return; + } + } + if (m_dir->heartbeat_interval) { heart_beat = m_dir->heartbeat_interval; } else if (cons) { @@ -727,3 +772,33 @@ bool Console::preventInUseConnect() return true; } } + +/* + * Call-back for reading a passphrase for an encrypted PEM file + * This function uses getpass(), + * which uses a static buffer and is NOT thread-safe. + */ +static int tls_pem_callback(char *buf, int size, const void *userdata) +{ +#ifdef HAVE_TLS + const char *prompt = (const char *)userdata; +# if defined(HAVE_WIN32) + sendit(prompt); + if (win32_cgets(buf, size) == NULL) { + buf[0] = 0; + return 0; + } else { + return strlen(buf); + } +# else + char *passwd; + + passwd = getpass(prompt); + bstrncpy(buf, passwd, size); + return strlen(buf); +# endif +#else + buf[0] = 0; + return 0; +#endif +} diff --git a/bacula/src/version.h b/bacula/src/version.h index 6fafdc1755..3dd249fe89 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -4,8 +4,8 @@ #undef VERSION #define VERSION "2.1.11" -#define BDATE "20 May 2007" -#define LSMDATE "20May07" +#define BDATE "21 May 2007" +#define LSMDATE "21May07" #define PROG_COPYRIGHT "Copyright (C) %d-2007 Free Software Foundation Europe e.V.\n" #define BYEAR "2007" /* year for copyright messages in progs */ diff --git a/bacula/technotes-2.1 b/bacula/technotes-2.1 index a352b9161a..2fe5018630 100644 --- a/bacula/technotes-2.1 +++ b/bacula/technotes-2.1 @@ -2,6 +2,7 @@ General: 21May07 +kes Begin adding TLS support to bat. kes Apply UTF-8/16 patch from Yves Orton to clean up lex.c and make it more readable. 20May07 -- 2.39.5