License:
For the most part, Bacula is licensed under the GPL version 2
this code is listed under Copyright Free Software Foundation
-Europe e.V. A small part of the code (less than 20 files) is
-copyrighted under the GPL by other people (FSF, Sun, ...).
+Europe e.V. A small part of the code (less than 10 files) is
+copyrighted under the GPL by FSF, or under BSD licenses by various
+authors (see below).
What follows is information from the authors of the code:
Bacula may be linked with any libraries permitted under the GPL.
However, if configured with encryption Bacula does use the
OpenSSL libraries which are, unfortunately, not compatible with
-GPL v2. To the best of our knowledge these libaries are not
+GPL v2. To the best of our knowledge these libraries are not
distributed with Bacula code because they are shared objects, and
as such there is no conflict with the GPL according what I (Kern)
understand in talking to FSFE, and in any case, for the code that
and may contain Microsoft intellectual property (examples:
Microsoft VC++, the source to the VSS libraries, the Microsoft C
runtime libraries). As such we cannot and do not distribute that
-software. We are permitted however to distribut Bacula with the
+software. We are permitted however to distribute Bacula with the
necessary Microsoft libraries in binary form.
You may obtain the parts that we cannot distribute as follows. The
Source practices while maintaining full respect for proprietary and
copyrighted code.
+BSD code used in the Windows version only:
+Code falling under the BSD license has the following license:
+
+ Copyright (c)2002-2003 Mark K. Kim
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ * Neither the original author of this software nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
+
+
=====================================
The entire GPL is reproduced below, in the manuals distributed with the
Other Licenses:
Certain parts of the Bacula software are licensed by their
-copyright holder(s) under the GPL. These software files are
-clearly marked as such.
+copyright holder(s) under the GPL or under the BSD license.
+These software files are clearly marked as such.
Bacula can be enabled with data encryption and/or communications
encryption. If this is the case, you will be including OpenSSL code that
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+=====================================
+
+
============== Text of GPL version 2 license ========
GNU GENERAL PUBLIC LICENSE
--- /dev/null
+/*
+ Bacula® - The Network Backup Solution
+
+ Copyright (C) 2007-2007 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 two of the GNU General Public
+ License as published by the Free Software Foundation and included
+ in the file LICENSE.
+
+ 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 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.
+
+ Bacula® is a registered trademark of John Walker.
+ The licensor of Bacula is the Free Software Foundation Europe
+ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+ Switzerland, email:ftf@fsfeurope.org.
+*/
+/*
+ * Version $Id$
+ *
+ * Bacula Communications class that is at a higher level than BSOCK
+ *
+ * Kern Sibbald, May MMVII
+ *
+ */
+
+#include "bat.h"
+#include "console.h"
+#include "restore.h"
+#include "select.h"
+#include "run/run.h"
+#include "dircomm.h"
+
+static int tls_pem_callback(char *buf, int size, const void *userdata);
+
+
+DirComm::DirComm(Console *console)
+{
+ m_console = console;
+ m_sock = NULL;
+ m_at_prompt = false;
+ m_at_main_prompt = false;
+ m_timer = NULL;
+}
+
+DirComm::~DirComm()
+{
+ if (m_timer) {
+ stopTimer();
+ }
+}
+
+void DirComm::startTimer()
+{
+ m_timer = new QTimer(m_console);
+ QWidget::connect(m_timer, SIGNAL(timeout()), this, SLOT(poll_messages()));
+ m_timer->start(mainWin->m_checkMessagesInterval*1000);
+}
+
+void DirComm::stopTimer()
+{
+ if (m_timer) {
+ QWidget::disconnect(m_timer, SIGNAL(timeout()), this, SLOT(poll_messages()));
+ m_timer->stop();
+ delete m_timer;
+ m_timer = NULL;
+ }
+}
+
+void DirComm::poll_messages()
+{
+ m_messages_pending = true;
+ if ((m_at_main_prompt) && (mainWin->m_checkMessages)){
+ write(".messages");
+ displayToPrompt();
+ }
+}
+
+/* Terminate any open socket */
+void DirComm::terminate()
+{
+ if (m_sock) {
+ stopTimer();
+ m_sock->close();
+ m_sock = NULL;
+ }
+}
+
+/*
+ * Connect to Director.
+ */
+void DirComm::connect_dir(DIRRES *dir, CONRES *cons)
+{
+ JCR jcr;
+ utime_t heart_beat;
+ char buf[1024];
+
+ m_dir = dir;
+ if (!m_dir) {
+ mainWin->set_status("No Director found.");
+ return;
+ }
+ if (m_sock) {
+ mainWin->set_status("Already connected.");
+ return;
+ }
+
+ memset(&jcr, 0, sizeof(jcr));
+
+ mainWin->set_statusf(_("Connecting to Director %s:%d"), m_dir->address, m_dir->DIRport);
+ m_console->display_textf(_("Connecting to Director %s:%d\n\n"), m_dir->address, m_dir->DIRport);
+
+ /* Give GUI a chance */
+ app->processEvents();
+
+ /* Initialize Console TLS context once */
+ if (cons && !cons->tls_ctx && (cons->tls_enable || cons->tls_require)) {
+ /* Generate passphrase prompt */
+ bsnprintf(buf, sizeof(buf), "Passphrase for Console \"%s\" TLS private key: ",
+ cons->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) {
+ m_console->display_textf(_("Failed to initialize TLS context for Console \"%s\".\n"),
+ m_dir->name());
+ return;
+ }
+ }
+
+ /* Initialize Director TLS context once */
+ if (!m_dir->tls_ctx && (m_dir->tls_enable || m_dir->tls_require)) {
+ /* Generate passphrase prompt */
+ bsnprintf(buf, sizeof(buf), "Passphrase for Director \"%s\" TLS private key: ",
+ m_dir->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) {
+ m_console->display_textf(_("Failed to initialize TLS context for Director \"%s\".\n"),
+ m_dir->name());
+ mainWin->set_status("Connection failed");
+ return;
+ }
+ }
+
+ if (m_dir->heartbeat_interval) {
+ heart_beat = m_dir->heartbeat_interval;
+ } else if (cons) {
+ heart_beat = cons->heartbeat_interval;
+ } else {
+ heart_beat = 0;
+ }
+
+ m_sock = bnet_connect(NULL, 5, 15, heart_beat,
+ _("Director daemon"), m_dir->address,
+ NULL, m_dir->DIRport, 0);
+ if (m_sock == NULL) {
+ mainWin->set_status("Connection failed");
+ return;
+ } else {
+ /* Update page selector to green to indicate that Console is connected */
+ mainWin->actionConnect->setIcon(QIcon(":images/connected.png"));
+ QBrush greenBrush(Qt::green);
+ QTreeWidgetItem *item = mainWin->getFromHash(this);
+ item->setForeground(0, greenBrush);
+ }
+
+ jcr.dir_bsock = m_sock;
+
+ if (!authenticate_director(&jcr, m_dir, cons, buf, sizeof(buf))) {
+ m_console->display_text(buf);
+ return;
+ }
+ if (buf[0]) {
+ m_console->display_text(buf);
+ }
+
+ /* Give GUI a chance */
+ app->processEvents();
+
+ mainWin->set_status(_("Initializing ..."));
+
+ /* Set up input notifier */
+ m_notifier = new QSocketNotifier(m_sock->m_fd, QSocketNotifier::Read, 0);
+ QObject::connect(m_notifier, SIGNAL(activated(int)), this, SLOT(read_dir(int)));
+
+ mainWin->set_status(_("Connected"));
+ startTimer(); /* start message timer */
+ return;
+}
+
+bool DirComm::dir_cmd(QString &cmd, QStringList &results)
+{
+ return dir_cmd(cmd.toUtf8().data(), results);
+}
+
+/*
+ * Send a command to the Director, and return the
+ * results in a QStringList.
+ */
+bool DirComm::dir_cmd(const char *cmd, QStringList &results)
+{
+ int stat;
+
+ notify(false);
+ write(cmd);
+ while ((stat = read()) > 0) {
+ if (mainWin->m_displayAll) m_console->display_text(msg());
+ strip_trailing_junk(msg());
+ results << msg();
+ }
+ notify(true);
+ discardToPrompt();
+ return true; /* ***FIXME*** return any command error */
+}
+
+bool DirComm::sql_cmd(QString &query, QStringList &results)
+{
+ return sql_cmd(query.toUtf8().data(), results);
+}
+
+/*
+ * Send an sql query to the Director, and return the
+ * results in a QStringList.
+ */
+bool DirComm::sql_cmd(const char *query, QStringList &results)
+{
+ int stat;
+ POOL_MEM cmd(PM_MESSAGE);
+
+ if (!is_connectedGui()) {
+ return false;
+ }
+
+ notify(false);
+
+ pm_strcpy(cmd, ".sql query=\"");
+ pm_strcat(cmd, query);
+ pm_strcat(cmd, "\"");
+ write(cmd.c_str());
+ while ((stat = read()) > 0) {
+ if (mainWin->m_displayAll) m_console->display_text(msg());
+ strip_trailing_junk(msg());
+ results << msg();
+ }
+ notify(true);
+ discardToPrompt();
+ return true; /* ***FIXME*** return any command error */
+}
+
+/*
+ * This should be moved into a bSocket class
+ */
+char *DirComm::msg()
+{
+ if (m_sock) {
+ return m_sock->msg;
+ }
+ return NULL;
+}
+
+/* Send a command to the Director */
+void DirComm::write_dir(const char *msg)
+{
+ if (m_sock) {
+ mainWin->set_status(_("Processing command ..."));
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+ write(msg);
+ } else {
+ mainWin->set_status(" Director not connected. Click on connect button.");
+ mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
+ QBrush redBrush(Qt::red);
+ QTreeWidgetItem *item = mainWin->getFromHash(this);
+ item->setForeground(0, redBrush);
+ m_at_prompt = false;
+ m_at_main_prompt = false;
+ }
+}
+
+int DirComm::write(const QString msg)
+{
+ return write(msg.toUtf8().data());
+}
+
+int DirComm::write(const char *msg)
+{
+ if (!m_sock) {
+ return -1;
+ }
+ m_sock->msglen = pm_strcpy(m_sock->msg, msg);
+ m_at_prompt = false;
+ m_at_main_prompt = false;
+ if (mainWin->m_commDebug) Pmsg1(000, "send: %s\n", msg);
+ return m_sock->send();
+
+}
+
+/*
+ * Get to main command prompt -- i.e. abort any suDirCommand
+ */
+void DirComm::beginNewCommand()
+{
+ for (int i=0; i < 3; i++) {
+ write(".\n");
+ while (read() > 0) {
+ if (mainWin->m_displayAll) m_console->display_text(msg());
+ }
+ if (m_at_main_prompt) {
+ break;
+ }
+ }
+ m_console->display_text("\n");
+}
+
+void DirComm::displayToPrompt()
+{
+ int stat = 0;
+ if (mainWin->m_commDebug) Pmsg0(000, "DisplaytoPrompt\n");
+ while (!m_at_prompt) {
+ if ((stat=read()) > 0) {
+ m_console->display_text(msg());
+ }
+ }
+ if (mainWin->m_commDebug) Pmsg1(000, "endDisplaytoPrompt=%d\n", stat);
+}
+
+void DirComm::discardToPrompt()
+{
+ int stat = 0;
+ if (mainWin->m_commDebug) Pmsg0(000, "discardToPrompt\n");
+ while (!m_at_prompt) {
+ if ((stat=read()) > 0) {
+ if (mainWin->m_displayAll) m_console->display_text(msg());
+ }
+ }
+ if (mainWin->m_commDebug) Pmsg1(000, "endDisplayToPrompt=%d\n", stat);
+}
+
+
+/*
+ * Blocking read from director
+ */
+int DirComm::read()
+{
+ int stat = 0;
+ while (m_sock) {
+ for (;;) {
+ stat = bnet_wait_data_intr(m_sock, 1);
+ if (stat > 0) {
+ break;
+ }
+ app->processEvents();
+ if (m_api_set && m_messages_pending) {
+ write_dir(".messages");
+ m_messages_pending = false;
+ }
+ }
+ m_sock->msg[0] = 0;
+ stat = m_sock->recv();
+ if (stat >= 0) {
+ if (mainWin->m_commDebug) Pmsg1(000, "got: %s\n", m_sock->msg);
+ if (m_at_prompt) {
+ m_console->display_text("\n");
+ m_at_prompt = false;
+ m_at_main_prompt = false;
+ }
+ }
+ switch (m_sock->msglen) {
+ case BNET_MSGS_PENDING :
+ if (m_notifier->isEnabled()) {
+ if (mainWin->m_commDebug) Pmsg0(000, "MSGS PENDING\n");
+ write_dir(".messages");
+ displayToPrompt();
+ m_messages_pending = false;
+ }
+ m_messages_pending = true;
+ continue;
+ case BNET_CMD_OK:
+ if (mainWin->m_commDebug) Pmsg0(000, "CMD OK\n");
+ m_at_prompt = false;
+ m_at_main_prompt = false;
+ mainWin->set_status(_("Command completed ..."));
+ continue;
+ case BNET_CMD_BEGIN:
+ if (mainWin->m_commDebug) Pmsg0(000, "CMD BEGIN\n");
+ m_at_prompt = false;
+ m_at_main_prompt = false;
+ mainWin->set_status(_("Processing command ..."));
+ continue;
+ case BNET_MAIN_PROMPT:
+ if (mainWin->m_commDebug) Pmsg0(000, "MAIN PROMPT\n");
+ m_at_prompt = true;
+ m_at_main_prompt = true;
+ mainWin->set_status(_("At main prompt waiting for input ..."));
+ QApplication::restoreOverrideCursor();
+ break;
+ case BNET_PROMPT:
+ if (mainWin->m_commDebug) Pmsg0(000, "PROMPT\n");
+ m_at_prompt = true;
+ m_at_main_prompt = false;
+ mainWin->set_status(_("At prompt waiting for input ..."));
+ QApplication::restoreOverrideCursor();
+ break;
+ case BNET_CMD_FAILED:
+ if (mainWin->m_commDebug) Pmsg0(000, "CMD FAILED\n");
+ mainWin->set_status(_("Command failed."));
+ QApplication::restoreOverrideCursor();
+ break;
+ /* We should not get this one */
+ case BNET_EOD:
+ if (mainWin->m_commDebug) Pmsg0(000, "EOD\n");
+ mainWin->set_status_ready();
+ QApplication::restoreOverrideCursor();
+ if (!m_api_set) {
+ break;
+ }
+ continue;
+ case BNET_START_SELECT:
+ if (mainWin->m_commDebug) Pmsg0(000, "START SELECT\n");
+ new selectDialog(m_console);
+ break;
+ case BNET_YESNO:
+ if (mainWin->m_commDebug) Pmsg0(000, "YESNO\n");
+ new yesnoPopUp(m_console);
+ break;
+ case BNET_RUN_CMD:
+ if (mainWin->m_commDebug) Pmsg0(000, "RUN CMD\n");
+ new runCmdPage();
+ break;
+ case BNET_ERROR_MSG:
+ if (mainWin->m_commDebug) Pmsg0(000, "ERROR MSG\n");
+ m_sock->recv(); /* get the message */
+ m_console->display_text(msg());
+ QMessageBox::critical(this, "Error", msg(), QMessageBox::Ok);
+ break;
+ case BNET_WARNING_MSG:
+ if (mainWin->m_commDebug) Pmsg0(000, "WARNING MSG\n");
+ m_sock->recv(); /* get the message */
+ m_console->display_text(msg());
+ QMessageBox::critical(this, "Warning", msg(), QMessageBox::Ok);
+ break;
+ case BNET_INFO_MSG:
+ if (mainWin->m_commDebug) Pmsg0(000, "INFO MSG\n");
+ m_sock->recv(); /* get the message */
+ m_console->display_text(msg());
+ mainWin->set_status(msg());
+ break;
+ }
+ if (is_bnet_stop(m_sock)) { /* error or term request */
+ if (mainWin->m_commDebug) Pmsg0(000, "BNET STOP\n");
+ stopTimer();
+ m_sock->close();
+ m_sock = NULL;
+ mainWin->actionConnect->setIcon(QIcon(":images/disconnected.png"));
+ QBrush redBrush(Qt::red);
+ QTreeWidgetItem *item = mainWin->getFromHash(this);
+ item->setForeground(0, redBrush);
+ m_notifier->setEnabled(false);
+ delete m_notifier;
+ m_notifier = NULL;
+ mainWin->set_status(_("Director disconnected."));
+ QApplication::restoreOverrideCursor();
+ stat = BNET_HARDEOF;
+ }
+ break;
+ }
+ return stat;
+}
+
+/* Called by signal when the Director has output for us */
+void DirComm::read_dir(int /* fd */)
+{
+ if (mainWin->m_commDebug) Pmsg0(000, "read_dir\n");
+ while (read() >= 0) {
+ m_console->display_text(msg());
+ }
+}
+
+/*
+ * When the notifier is enabled, read_dir() will automatically be
+ * called by the Qt event loop when ever there is any output
+ * from the Directory, and read_dir() will then display it on
+ * the console.
+ *
+ * When we are in a bat dialog, we want to control *all* output
+ * from the Directory, so we set notify to off.
+ * m_console->notifiy(false);
+ */
+void DirComm::notify(bool enable)
+{
+ m_notifier->setEnabled(enable);
+}
+
+bool DirComm::is_connectedGui()
+{
+ if (is_connected()) {
+ return true;
+ } else {
+ QString message("Director ");
+ message += " is curerntly disconnected\n Please reconnect!!";
+ QMessageBox::warning(this, tr("Bat"),
+ tr(message.toUtf8().data()), QMessageBox::Ok );
+ return false;
+ }
+}
+
+/*
+ * 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)
+{
+ (void)size;
+ (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
+}
--- /dev/null
+#ifndef _DIRCOMM_H_
+#define _DIRCOMM_H_
+/*
+ Bacula® - The Network Backup Solution
+
+ Copyright (C) 2007-2007 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 two of the GNU General Public
+ License as published by the Free Software Foundation and included
+ in the file LICENSE.
+
+ 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 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.
+
+ Bacula® is a registered trademark of John Walker.
+ The licensor of Bacula is the Free Software Foundation Europe
+ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+ Switzerland, email:ftf@fsfeurope.org.
+*/
+/*
+ * Version $Id$
+ *
+ * This is an attempt to move the higher level read/write type
+ * functionality to the Director out of the Console class into
+ * a Bacula Communications class. This class builds on the
+ * BSOCK class.
+ *
+ *
+ * Kern Sibbald, May 2007
+ */
+
+#include "bat.h"
+#include "pages.h"
+
+class DIRRES;
+class BSOCK;
+class CONRES;
+
+class DirComm : public Pages
+{
+ Q_OBJECT
+
+public:
+ DirComm(Console *console);
+ ~DirComm();
+ void display_text(const char *buf);
+ void display_text(const QString buf);
+ void display_textf(const char *fmt, ...);
+ void display_html(const QString buf);
+ void update_cursor(void);
+ void write_dir(const char *buf);
+ bool dir_cmd(const char *cmd, QStringList &results);
+ bool dir_cmd(QString &cmd, QStringList &results);
+ bool sql_cmd(const char *cmd, QStringList &results);
+ bool sql_cmd(QString &cmd, QStringList &results);
+ bool authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons,
+ char *buf, int buflen);
+ bool is_connected() { return m_sock != NULL; };
+ bool is_connectedGui();
+ char *msg();
+ void notify(bool enable);
+ void terminate();
+ void beginNewCommand();
+ void displayToPrompt();
+ void discardToPrompt();
+ void setDirectorTreeItem(QTreeWidgetItem *);
+ void setDirRes(DIRRES *dir);
+ void getDirResName(QString &);
+ void startTimer();
+ void stopTimer();
+
+public slots:
+ void connect_dir(DIRRES *dir, CONRES *cons);
+ void read_dir(int fd);
+ int read(void);
+ int write(const char *msg);
+ int write(QString msg);
+ void poll_messages(void);
+
+public:
+
+private:
+ DIRRES *m_dir;
+ BSOCK *m_sock;
+ bool m_at_prompt;
+ bool m_at_main_prompt;
+ QSocketNotifier *m_notifier;
+ Console *m_console;
+ bool m_api_set;
+ bool m_messages_pending;
+ QTimer *m_timer;
+};
+
+#endif /* _DIRCOMM_H_ */
--- /dev/null
+/*
+ Bacula® - The Network Backup Solution
+
+ Copyright (C) 2001-2007 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 two of the GNU General Public
+ License as published by the Free Software Foundation and included
+ in the file LICENSE.
+
+ 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 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.
+
+ Bacula® is a registered trademark of John Walker.
+ The licensor of Bacula is the Free Software Foundation Europe
+ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+ Switzerland, email:ftf@fsfeurope.org.
+*/
+
+/*
+ *
+ * Bacula UA authentication. Provides authentication with
+ * the Director.
+ *
+ * Kern Sibbald, June MMI adapted to bat, Jan MMVI
+ *
+ * Version $Id$
+ *
+ */
+
+
+#include "bat.h"
+#include "dircomm.h"
+
+
+/* Commands sent to Director */
+static char hello[] = "Hello %s calling\n";
+
+/* Response from Director */
+static char OKhello[] = "1000 OK:";
+
+/* Forward referenced functions */
+
+/*
+ * Authenticate Director
+ */
+bool DirComm::authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons,
+ char *errmsg, int errmsg_len)
+{
+ BSOCK *dir = jcr->dir_bsock;
+ int tls_local_need = BNET_TLS_NONE;
+ int tls_remote_need = BNET_TLS_NONE;
+ int compatible = true;
+ char bashed_name[MAX_NAME_LENGTH];
+ char *password;
+ TLS_CONTEXT *tls_ctx = NULL;
+
+ errmsg[0] = 0;
+ /*
+ * 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;
+ }
+ }
+ 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 15 secs */
+ dir->start_timer(15);
+ 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)) {
+ bsnprintf(errmsg, errmsg_len, _("Director authorization problem at \"%s:%d\"\n"),
+ dir->host(), dir->port());
+ 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) {
+ bsnprintf(errmsg, errmsg_len, _("Authorization problem:"
+ " Remote server at \"%s:%d\" did not advertise required TLS support.\n"),
+ dir->host(), dir->port());
+ 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) {
+ bsnprintf(errmsg, errmsg_len, _("Authorization problem with Director at \"%s:%d\":"
+ " Remote server requires TLS.\n"),
+ dir->host(), dir->port());
+
+ 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)) {
+ bsnprintf(errmsg, errmsg_len, _("TLS negotiation failed with Director at \"%s:%d\"\n"),
+ dir->host(), dir->port());
+ goto bail_out;
+ }
+ }
+ }
+
+ Dmsg1(6, ">dird: %s", dir->msg);
+ if (dir->recv() <= 0) {
+ dir->stop_timer();
+ bsnprintf(errmsg, errmsg_len, _("Bad response to Hello command: ERR=%s\n"
+ "The Director at \"%s:%d\" is probably not running.\n"),
+ dir->bstrerror(), dir->host(), dir->port());
+ return false;
+ }
+
+ dir->stop_timer();
+ Dmsg1(10, "<dird: %s", dir->msg);
+ if (strncmp(dir->msg, OKhello, sizeof(OKhello)-1) != 0) {
+ bsnprintf(errmsg, errmsg_len, _("Director at \"%s:%d\" rejected Hello command\n"),
+ dir->host(), dir->port());
+ return false;
+ } else {
+ bsnprintf(errmsg, errmsg_len, "%s", dir->msg);
+ }
+ return true;
+
+bail_out:
+ dir->stop_timer();
+ bsnprintf(errmsg, errmsg_len, _("Authorization problem with Director at \"%s:%d\"\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"),
+ dir->host(), dir->port());
+ return false;
+}