]> git.sur5r.net Git - bacula/bacula/commitdiff
Implement TLS in gnome console and wx-console.
authorKern Sibbald <kern@sibbald.com>
Sat, 9 Jul 2005 13:55:35 +0000 (13:55 +0000)
committerKern Sibbald <kern@sibbald.com>
Sat, 9 Jul 2005 13:55:35 +0000 (13:55 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@2183 91ce42f0-d328-0410-95d8-f526ca767f89

bacula/kernstodo
bacula/kes-1.37
bacula/src/console/console.c
bacula/src/gnome2-console/console.c
bacula/src/gnome2-console/console_conf.c
bacula/src/gnome2-console/console_conf.h
bacula/src/version.h
bacula/src/wx-console/console_conf.h
bacula/src/wx-console/console_thread.cpp

index b64e7e9d0217f4309c26a752fd8a8cc90ebca305..94a37d23b135af9f1be9ef58b51a35df78041b03 100644 (file)
@@ -24,13 +24,6 @@ Autochangers:
 
 For 1.37:
 - update volume=xxx --- add status=Full
-- After rename
-  04-Jul 13:01 MainSD: Rufus.2005-07-04_01.05.02 Warning: Director wanted Volume 
-     "DLT-13Feb04".
-  Current Volume "DLT-04Jul05" not acceptable because:
-  1997 Volume "DLT-13Feb04" not in catalog.
-  04-Jul 13:01 MainSD: Please mount Volume "DLT-04Jul05" on Storage Device 
-     "HP DLT 80" (/dev/nst0) for Job Rufus.2005-07-04_01.05.02
 - Remove old spool files on startup.
 - Exclude SD spool/working directory.
 - Finish TLS implementation.
@@ -1346,3 +1339,11 @@ Block Position: 0
 - Review all items in "restore".
 - Fix PostgreSQL GROUP BY problems in restore.
 - Fix PostgreSQL sql problems in bugs.
+- After rename
+  04-Jul 13:01 MainSD: Rufus.2005-07-04_01.05.02 Warning: Director wanted Volume 
+     "DLT-13Feb04".
+  Current Volume "DLT-04Jul05" not acceptable because:
+  1997 Volume "DLT-13Feb04" not in catalog.
+  04-Jul 13:01 MainSD: Please mount Volume "DLT-04Jul05" on Storage Device 
+     "HP DLT 80" (/dev/nst0) for Job Rufus.2005-07-04_01.05.02
+
index 4a821b655ff8152ead1ffafb4e5cd60b24aad57a..3c649f87ab413bd434df44d58644819550e1bd37 100644 (file)
@@ -4,6 +4,8 @@
 General:
 
 Changes to 1.37.28:
+09Jul05
+- Implement TLS in gnome console and wx-console.
 08Jul05
 - Correct a NULL pointer reference in the mount command.
 - Correct typo in Copyright
index 3d9b0b5b2b9814b50c3084ab9ad71a9a9a4060ba..af82ec5e7830643d457f16c24776ff3a35667a44 100644 (file)
@@ -306,7 +306,6 @@ static int tls_pem_callback(char *buf, int size, const void *userdata)
    buf[0] = 0;
    return 0;
 #endif
-
 }
 
 
index df4f4dfb65c6232b562a48fe50ceb884986e18b7..e2223c49a25f1f2b3159f8a3c9300a7e1d41fcdf 100644 (file)
@@ -6,23 +6,19 @@
  *
  *     Version $Id$
  */
-
 /*
-   Copyright (C) 2002-2004 Kern Sibbald and John Walker
+   Copyright (C) 2002-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
-   as published by the Free Software Foundation; either version 2
-   of the License, or (at your option) any later version.
+   version 2 as amended with additional clauses defined in the
+   file LICENSE in the main source directory.
 
    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.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
+   the file LICENSE for additional 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
 #include "bacula.h"
@@ -82,13 +78,14 @@ static bool at_prompt = false;
 static bool ready = false;
 static bool quit = false;
 static guint initial;
+static int numdir = 0;
 
 #define CONFIG_FILE "./gnome-console.conf"   /* default configuration file */
 
 static void usage()
 {
    fprintf(stderr, _(
-"Copyright (C) 2002-2004 Kern Sibbald and John Walker\n"
+"Copyright (C) 2002-2005 Kern Sibbald\n"
 "\nVersion: " VERSION " (" BDATE ") %s %s %s\n\n"
 "Usage: gnome-console [-s] [-c config_file] [-d debug_level] [config_file]\n"
 "       -c <file>   set configuration file to file\n"
@@ -101,6 +98,93 @@ static void usage()
    exit(1);
 }
 
+/*
+ * 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;
+   char *passwd;
+
+   passwd = getpass(prompt);
+   bstrncpy(buf, passwd, size);
+   return (strlen(buf));
+#else
+   buf[0] = 0;
+   return 0;
+#endif
+}
+
+
+/*
+ * Make a quick check to see that we have all the
+ * resources needed.
+ */
+static int check_resources()
+{
+   int xOK = true;
+   DIRRES *director;
+
+   LockRes();
+
+   numdir = 0;
+   foreach_res(director, R_DIRECTOR) {
+      numdir++;
+      /* tls_require implies tls_enable */
+      if (director->tls_require) {
+         if (have_tls) {
+            director->tls_enable = true;
+         } else {
+            Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured in Bacula.\n"));
+            xOK = false;
+            continue;
+         }
+      }
+
+      if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && director->tls_enable) {
+         Emsg2(M_FATAL, 0, _("Neither \"TLS CA Certificate\""
+                             " or \"TLS CA Certificate Dir\" are defined for Director \"%s\" in %s."
+                             " At least one CA certificate store is required.\n"),
+                             director->hdr.name, configfile);
+         xOK = false;
+      }
+   }
+   
+   if (numdir == 0) {
+      Emsg1(M_FATAL, 0, _("No Director resource defined in %s\n"
+                          "Without that I don't how to speak to the Director :-(\n"), configfile);
+      xOK = false;
+   }
+
+   CONRES *cons;
+   /* Loop over Consoles */
+   foreach_res(cons, R_CONSOLE) {
+      /* tls_require implies tls_enable */
+      if (cons->tls_require) {
+         if (have_tls) {
+            cons->tls_enable = true;
+         } else {
+            Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured in Bacula.\n"));
+            xOK = false;
+            continue;
+         }
+      }
+
+      if ((!cons->tls_ca_certfile && !cons->tls_ca_certdir) && cons->tls_enable) {
+         Emsg2(M_FATAL, 0, _("Neither \"TLS CA Certificate\""
+                             " or \"TLS CA Certificate Dir\" are defined for Console \"%s\" in %s.\n"),
+                             cons->hdr.name, configfile);
+         xOK = false;
+      }
+   }
+
+   UnlockRes();
+
+   return xOK;
+}
+
 
 /*********************************************************************
  *
@@ -179,18 +263,13 @@ int main(int argc, char *argv[])
 
    parse_config(configfile);
 
-   LockRes();
-   ndir = 0;
-   foreach_res(dir, R_DIRECTOR) {
-      ndir++;
+   if (init_tls() != 0) {
+      Emsg0(M_ERROR_TERM, 0, _("TLS library initialization failed.\n"));
    }
-   UnlockRes();
-   if (ndir == 0) {
-      Emsg1(M_ERROR_TERM, 0, _("No director resource defined in %s\n"
-"Without that I don't how to speak to the Director :-(\n"), configfile);
-   }
-
 
+   if (!check_resources()) {
+      Emsg1(M_ERROR_TERM, 0, _("Please correct configuration file: %s\n"), configfile);
+   }
 
    console = create_console();
    gtk_window_set_default_size(GTK_WINDOW(console), 800, 700);
@@ -402,6 +481,57 @@ int connect_to_director(gpointer data)
    while (gtk_events_pending()) {     /* fully paint screen */
       gtk_main_iteration();
    }
+
+   LockRes();
+   /* If cons==NULL, default console will be used */
+   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) {
+         bsnprintf(buf, sizeof(buf), _("Failed to initialize TLS context for Console \"%s\".\n"),
+            dir->hdr.name);
+         set_text(buf, strlen(buf));
+         terminate_console(0);
+         return 1;
+      }
+
+   }
+
+   /* Initialize Director TLS context */
+   if (dir->tls_enable || dir->tls_require) {
+      /* Generate passphrase prompt */
+      bsnprintf(buf, sizeof(buf), "Passphrase for Director \"%s\" TLS private key: ", dir->hdr.name);
+
+      /* Initialize TLS context:
+       * Args: CA certfile, CA certdir, Certfile, Keyfile,
+       * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
+      dir->tls_ctx = new_tls_context(dir->tls_ca_certfile,
+         dir->tls_ca_certdir, dir->tls_certfile,
+         dir->tls_keyfile, tls_pem_callback, &buf, NULL, true);
+
+      if (!dir->tls_ctx) {
+         bsnprintf(buf, sizeof(buf), _("Failed to initialize TLS context for Director \"%s\".\n"),
+            dir->hdr.name);
+         set_text(buf, strlen(buf));
+         terminate_console(0);
+         return 1;
+      }
+   }
+
+
    UA_sock = bnet_connect(NULL, 5, 15, "Director daemon", dir->address,
                           NULL, dir->DIRport, 0);
    if (UA_sock == NULL) {
@@ -409,10 +539,6 @@ int connect_to_director(gpointer data)
    }
 
    jcr.dir_bsock = UA_sock;
-   LockRes();
-   /* If cons==NULL, default console will be used */
-   CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
-   UnlockRes();
    if (!authenticate_director(&jcr, dir, cons)) {
       set_text(UA_sock->msg, UA_sock->msglen);
       return 0;
@@ -541,11 +667,12 @@ void stop_director_reader(gpointer data)
 /* Cleanup and then exit */
 void terminate_console(int sig)
 {
-   static int already_here = FALSE;
+   static bool already_here = false;
 
    if (already_here)                  /* avoid recursive temination problems */
       exit(1);
-   already_here = TRUE;
+   already_here = true;
+   cleanup_tls();
    disconnect_from_director((gpointer)NULL);
    gtk_main_quit();
    exit(0);
index a64d448c5d93fff73b5da5e12abdb2f3727e13f9..e0601dcc8588875e5dac76215fb9f6459090ead4 100644 (file)
@@ -8,36 +8,32 @@
  *   1. The generic lexical scanner in lib/lex.c and lib/lex.h
  *
  *   2. The generic config  scanner in lib/parse_config.c and
- *     lib/parse_config.h.
- *     These files contain the parser code, some utility
- *     routines, and the common store routines (name, int,
- *     string).
+ *      lib/parse_config.h.
+ *      These files contain the parser code, some utility
+ *      routines, and the common store routines (name, int,
+ *      string).
  *
  *   3. The daemon specific file, which contains the Resource
- *     definitions as well as any specific store routines
- *     for the resource records.
+ *      definitions as well as any specific store routines
+ *      for the resource records.
  *
  *     Kern Sibbald, January MM, September MM
  *
  *     Version $Id$
  */
-
 /*
-   Copyright (C) 2000, 2001 Kern Sibbald and John Walker
+   Copyright (C) 2000-2005 Kern Sibbald
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
-   as published by the Free Software Foundation; either version 2
-   of the License, or (at your option) any later version.
+   version 2 as amended with additional clauses defined in the
+   file LICENSE in the main source directory.
 
    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.
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
+   the file LICENSE for additional 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
 #include "bacula.h"
@@ -73,7 +69,12 @@ static RES_ITEM dir_items[] = {
    {"dirport",     store_int,      ITEM(dir_res.DIRport),  0, ITEM_DEFAULT, 9101},
    {"address",     store_str,      ITEM(dir_res.address),  0, ITEM_REQUIRED, 0},
    {"password",    store_password, ITEM(dir_res.password), 0, 0, 0},
-   {"enablessl", store_yesno,      ITEM(dir_res.enable_ssl), 1, ITEM_DEFAULT, 0},
+   {"tlsenable",      store_yesno,     ITEM(dir_res.tls_enable), 1, ITEM_DEFAULT, 0},
+   {"tlsrequire",     store_yesno,     ITEM(dir_res.tls_require), 1, ITEM_DEFAULT, 0},
+   {"tlscacertificatefile", store_dir, ITEM(dir_res.tls_ca_certfile), 0, 0, 0},
+   {"tlscacertificatedir", store_dir,  ITEM(dir_res.tls_ca_certdir), 0, 0, 0},
+   {"tlscertificate", store_dir,       ITEM(dir_res.tls_certfile), 0, 0, 0},
+   {"tlskey",         store_dir,       ITEM(dir_res.tls_keyfile), 0, 0, 0},
    {NULL, NULL, NULL, 0, 0, 0}
 };
 
@@ -81,7 +82,12 @@ static RES_ITEM con_items[] = {
    {"name",        store_name,     ITEM(con_res.hdr.name), 0, ITEM_REQUIRED, 0},
    {"description", store_str,      ITEM(con_res.hdr.desc), 0, 0, 0},
    {"password",    store_password, ITEM(con_res.password), 0, ITEM_REQUIRED, 0},
-   {"requiressl",  store_yesno,    ITEM(con_res.require_ssl), 1, ITEM_DEFAULT, 0},
+   {"tlsenable",      store_yesno,     ITEM(con_res.tls_enable), 1, ITEM_DEFAULT, 0},
+   {"tlsrequire",     store_yesno,     ITEM(con_res.tls_require), 1, ITEM_DEFAULT, 0},
+   {"tlscacertificatefile", store_dir, ITEM(con_res.tls_ca_certfile), 0, 0, 0},
+   {"tlscacertificatedir", store_dir,  ITEM(con_res.tls_ca_certdir), 0, 0, 0},
+   {"tlscertificate", store_dir,       ITEM(con_res.tls_certfile), 0, 0, 0},
+   {"tlskey",         store_dir,       ITEM(con_res.tls_keyfile), 0, 0, 0},
    {NULL, NULL, NULL, 0, 0, 0}
 };
 
@@ -102,7 +108,7 @@ RES_TABLE resources[] = {
    {"director",      dir_items,   R_DIRECTOR},
    {"console",       con_items,   R_CONSOLE},
    {"consolefont",   con_font_items, R_CONSOLE_FONT},
-   {NULL,           NULL,        0}
+   {NULL,            NULL,        0}
 };
 
 
@@ -116,21 +122,21 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm
       printf("No record for %d %s\n", type, res_to_str(type));
       return;
    }
-   if (type < 0) {                   /* no recursion */
+   if (type < 0) {                    /* no recursion */
       type = - type;
       recurse = false;
    }
    switch (type) {
    case R_DIRECTOR:
       printf("Director: name=%s address=%s DIRport=%d\n", reshdr->name,
-             res->dir_res.address, res->dir_res.DIRport);
+              res->dir_res.address, res->dir_res.DIRport);
       break;
    case R_CONSOLE:
       printf("Console: name=%s\n", reshdr->name);
       break;
    case R_CONSOLE_FONT:
       printf("ConsoleFont: name=%s font face=%s\n",
-            reshdr->name, NPRT(res->con_font.fontface));
+             reshdr->name, NPRT(res->con_font.fontface));
       break;
    default:
       printf("Unknown resource type %d\n", type);
@@ -167,17 +173,47 @@ void free_resource(RES *sres, int type)
    switch (type) {
    case R_DIRECTOR:
       if (res->dir_res.address) {
-        free(res->dir_res.address);
+         free(res->dir_res.address);
+      }
+      if (res->dir_res.tls_ctx) { 
+         free_tls_context(res->dir_res.tls_ctx);
+      }
+      if (res->dir_res.tls_ca_certfile) {
+         free(res->dir_res.tls_ca_certfile);
+      }
+      if (res->dir_res.tls_ca_certdir) {
+         free(res->dir_res.tls_ca_certdir);
+      }
+      if (res->dir_res.tls_certfile) {
+         free(res->dir_res.tls_certfile);
+      }
+      if (res->dir_res.tls_keyfile) {
+         free(res->dir_res.tls_keyfile);
       }
       break;
    case R_CONSOLE:
       if (res->con_res.password) {
-        free(res->con_res.password);
+         free(res->con_res.password);
+      }
+      if (res->con_res.tls_ctx) { 
+         free_tls_context(res->con_res.tls_ctx);
+      }
+      if (res->con_res.tls_ca_certfile) {
+         free(res->con_res.tls_ca_certfile);
+      }
+      if (res->con_res.tls_ca_certdir) {
+         free(res->con_res.tls_ca_certdir);
+      }
+      if (res->con_res.tls_certfile) {
+         free(res->con_res.tls_certfile);
+      }
+      if (res->con_res.tls_keyfile) {
+         free(res->con_res.tls_keyfile);
       }
       break;
    case R_CONSOLE_FONT:
       if (res->con_font.fontface) {
-        free(res->con_font.fontface);
+         free(res->con_font.fontface);
       }
       break;
    default:
@@ -206,10 +242,10 @@ void save_resource(int type, RES_ITEM *items, int pass)
     */
    for (i=0; items[i].name; i++) {
       if (items[i].flags & ITEM_REQUIRED) {
-           if (!bit_is_set(i, res_all.dir_res.hdr.item_present)) {
-              Emsg2(M_ABORT, 0, "%s item is required in %s resource, but not found.\n",
-                items[i].name, resources[rindex]);
-            }
+            if (!bit_is_set(i, res_all.dir_res.hdr.item_present)) {
+               Emsg2(M_ABORT, 0, "%s item is required in %s resource, but not found.\n",
+                 items[i].name, resources[rindex]);
+             }
       }
    }
 
@@ -222,27 +258,27 @@ void save_resource(int type, RES_ITEM *items, int pass)
       switch (type) {
       /* Resources not containing a resource */
       case R_DIRECTOR:
-        break;
+         break;
 
       case R_CONSOLE:
       case R_CONSOLE_FONT:
-        break;
+         break;
 
       default:
-        Emsg1(M_ERROR, 0, "Unknown resource type %d\n", type);
-        error = 1;
-        break;
+         Emsg1(M_ERROR, 0, "Unknown resource type %d\n", type);
+         error = 1;
+         break;
       }
       /* Note, the resoure name was already saved during pass 1,
        * so here, we can just release it.
        */
       if (res_all.dir_res.hdr.name) {
-        free(res_all.dir_res.hdr.name);
-        res_all.dir_res.hdr.name = NULL;
+         free(res_all.dir_res.hdr.name);
+         res_all.dir_res.hdr.name = NULL;
       }
       if (res_all.dir_res.hdr.desc) {
-        free(res_all.dir_res.hdr.desc);
-        res_all.dir_res.hdr.desc = NULL;
+         free(res_all.dir_res.hdr.desc);
+         res_all.dir_res.hdr.desc = NULL;
       }
       return;
    }
@@ -268,20 +304,20 @@ void save_resource(int type, RES_ITEM *items, int pass)
       res = (URES *)malloc(size);
       memcpy(res, &res_all, size);
       if (!res_head[rindex]) {
-        res_head[rindex] = (RES *)res; /* store first entry */
+         res_head[rindex] = (RES *)res; /* store first entry */
       } else {
-        RES *next;
-        /* Add new res to end of chain */
-        for (next=res_head[rindex]; next->next; next=next->next) {
-           if (strcmp(next->name, res->dir_res.hdr.name) == 0) {
-              Emsg2(M_ERROR_TERM, 0,
-                 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
-                 resources[rindex].name, res->dir_res.hdr.name);
-           }
-        }
-        next->next = (RES *)res;
-        Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
-              res->dir_res.hdr.name);
+         RES *next;
+         /* Add new res to end of chain */
+         for (next=res_head[rindex]; next->next; next=next->next) {
+            if (strcmp(next->name, res->dir_res.hdr.name) == 0) {
+               Emsg2(M_ERROR_TERM, 0,
+                  _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
+                  resources[rindex].name, res->dir_res.hdr.name);
+            }
+         }
+         next->next = (RES *)res;
+         Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
+               res->dir_res.hdr.name);
       }
    }
 }
index 0f621c6cff1eaca7e30365039b5d11f3ea57ee59..530ce1870f2f92f551a24eca47534aeb09b4db63 100644 (file)
 enum {
    R_DIRECTOR = 1001,
    R_CONSOLE,
-   R_CONSOLE_FONT
+   R_CONSOLE_FONT,
+   R_FIRST = R_DIRECTOR,
+   R_LAST = R_CONSOLE_FONT            /* Keep this updated */
 };
 
-#define R_FIRST     R_DIRECTOR
-#define R_LAST     R_CONSOLE_FONT
-
 /*
  * Some resource attributes
  */
-#define R_NAME                       1020
-#define R_ADDRESS                    1021
-#define R_PASSWORD                   1022
-#define R_TYPE                       1023
-#define R_BACKUP                     1024
+enum {
+   R_NAME = 1020,
+   R_ADDRESS,
+   R_PASSWORD,
+   R_TYPE,
+   R_BACKUP
+};
 
 
 /* Definition of the contents of each Resource */
-struct s_res_dir {
-   RES  hdr;
-   int  DIRport;                     /* UA server port */
-   char *address;                    /* UA server address */
-   char *password;                   /* UA server password */
-   int enable_ssl;                   /* Use SSL */
+struct DIRRES {
+   RES   hdr;
+   int   DIRport;                     /* UA server port */
+   char *address;                     /* UA server address */
+   char *password;                    /* UA server password */
+   int tls_enable;                    /* Enable TLS */
+   int tls_require;                   /* Require TLS */
+   char *tls_ca_certfile;             /* TLS CA Certificate File */
+   char *tls_ca_certdir;              /* TLS CA Certificate Directory */
+   char *tls_certfile;                /* TLS Client Certificate File */
+   char *tls_keyfile;                 /* TLS Client Key File */
+
+   TLS_CONTEXT *tls_ctx;              /* Shared TLS Context */
 };
-typedef struct s_res_dir DIRRES;
 
-struct s_con_font {
-   RES  hdr;
-   char *fontface;                   /* Console Font specification */
-   int require_ssl;                  /* Require SSL on all connections */
+struct CONFONTRES {
+   RES   hdr;
+   char *fontface;                    /* Console Font specification */
+   int require_ssl;                   /* Require SSL on all connections */
 };
-typedef struct s_con_font CONFONTRES;
 
-struct s_con_res {
-   RES  hdr;
-   char *password;                   /* UA server password */
-   int require_ssl;                  /* Require SSL on all connections */
+struct CONRES {
+   RES   hdr;
+   char *password;                    /* UA server password */
+   int tls_enable;                    /* Enable TLS on all connections */
+   int tls_require;                   /* Require TLS on all connections */
+   char *tls_ca_certfile;             /* TLS CA Certificate File */
+   char *tls_ca_certdir;              /* TLS CA Certificate Directory */
+   char *tls_certfile;                /* TLS Client Certificate File */
+   char *tls_keyfile;                 /* TLS Client Key File */
+
+   TLS_CONTEXT *tls_ctx;              /* Shared TLS Context */
 };
-typedef struct s_con_res CONRES;
 
 
 /* Define the Union of all the above
  * resource structure definitions.
  */
 union u_res {
-   struct s_res_dir    dir_res;
-   struct s_con_font   con_font;
-   struct s_con_res    con_res;
+   DIRRES dir_res;
+   CONRES con_res;
+   CONFONTRES con_font;
    RES hdr;
 };
 
index 4ca58bef97a95b0c38757903bf668bfaed60dcd0..1c9d61a0e47b4195d49877b6234ee7903556f2d2 100644 (file)
@@ -1,8 +1,8 @@
 /* */
 #undef  VERSION
 #define VERSION "1.37.28"
-#define BDATE   "08 July 2005"
-#define LSMDATE "08Jul05"
+#define BDATE   "09 July 2005"
+#define LSMDATE "09Jul05"
 
 /* Debug flags */
 #undef  DEBUG
index a468dc9c44935c69d2e79edd17aedb639073e754..5ef1fc3c7f8355fe01ef02f311ab45613a7e4a1f 100644 (file)
@@ -45,7 +45,7 @@
 /* Definition of the contents of each Resource */
 
 /* Console "globals" */
-struct s_res_con {
+struct CONRES {
    RES   hdr;
    char *rc_file;                     /* startup file */
    char *hist_file;                   /* command history file */
@@ -59,10 +59,9 @@ struct s_res_con {
 
    TLS_CONTEXT *tls_ctx;              /* Shared TLS Context */
 };
-typedef struct s_res_con CONRES;
 
 /* Director */
-struct s_res_dir {
+struct DIRRES {
    RES   hdr;
    int   DIRport;                     /* UA server port */
    char *address;                     /* UA server address */
@@ -76,15 +75,14 @@ struct s_res_dir {
 
    TLS_CONTEXT *tls_ctx;              /* Shared TLS Context */
 };
-typedef struct s_res_dir DIRRES;
 
 
 /* Define the Union of all the above
  * resource structure definitions.
  */
 union u_res {
-   struct s_res_dir     res_dir;
-   struct s_res_con     res_cons;
+   DIRRES res_dir;
+   CONRES res_cons;
    RES hdr;
 };
 
index f54a178e0f1bec12668a89edd1bc05b13898ef8d..1d1fc76f08f6b1d0253382acba225fb5e7e67e22 100644 (file)
@@ -49,6 +49,94 @@ bool console_thread::inited = false;
 bool console_thread::configloaded = false;
 wxString console_thread::working_dir = wxT(".");
 
+int numdir = 0;
+
+/*
+ * 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;
+   char *passwd;
+
+   passwd = getpass(prompt);
+   bstrncpy(buf, passwd, size);
+   return (strlen(buf));
+#else
+   buf[0] = 0;
+   return 0;
+#endif
+}
+
+
+/*
+ * Make a quick check to see that we have all the
+ * resources needed.
+ */
+static int check_resources()
+{
+   int xOK = true;
+   DIRRES *director;
+
+   LockRes();
+
+   numdir = 0;
+   foreach_res(director, R_DIRECTOR) {
+      numdir++;
+      /* tls_require implies tls_enable */
+      if (director->tls_require) {
+         if (have_tls) {
+            director->tls_enable = true;
+         } else {
+            Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured in Bacula.\n"));
+            xOK = false;
+            continue;
+         }
+      }
+
+      if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && director->tls_enable) {
+         Jmsg(NULL, M_FATAL, 0, _("Neither \"TLS CA Certificate\""
+                             " or \"TLS CA Certificate Dir\" are defined for Director \"%s\" in config file.\n"
+                             " At least one CA certificate store is required.\n"),
+                             director->hdr.name);
+         xOK = false;
+      }
+   }
+   
+   if (numdir == 0) {
+      Jmsg(NULL, M_FATAL, 0, _("No Director resource defined in config file.\n"
+                          "Without that I don't how to speak to the Director :-(\n"));
+      xOK = false;
+   }
+
+   CONRES *cons;
+   /* Loop over Consoles */
+   foreach_res(cons, R_CONSOLE) {
+      /* tls_require implies tls_enable */
+      if (cons->tls_require) {
+         if (have_tls) {
+            cons->tls_enable = true;
+         } else {
+            Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured in Bacula.\n"));
+            xOK = false;
+            continue;
+         }
+      }
+
+      if ((!cons->tls_ca_certfile && !cons->tls_ca_certdir) && cons->tls_enable) {
+         Jmsg(NULL, M_FATAL, 0, _("Neither \"TLS CA Certificate\""
+                             " or \"TLS CA Certificate Dir\" are defined for Console \"%s\" in config file.\n"),
+                             cons->hdr.name);
+         xOK = false;
+      }
+   }
+   UnlockRes();
+   return xOK;
+}
+
+
 void console_thread::SetWorkingDirectory(wxString w_dir) {
    if ((w_dir.Last() == '/') || (w_dir.Last() == '\\')) {
       console_thread::working_dir = w_dir.Mid(0, w_dir.Length()-1);
@@ -139,6 +227,14 @@ wxString console_thread::LoadConfig(wxString configfile) {
       return errmsg;
    }
    
+   if (init_tls() != 0) {
+      Jmsg(NULL, M_ERROR_TERM, 0, _("TLS library initialization failed.\n"));
+   }
+
+   if (!check_resources()) {
+      Jmsg(NULL, M_ERROR_TERM, 0, _("Please correct configuration file.\n"));
+   }
+
    term_msg();
    wxRemoveFile(console_thread::working_dir + wxT("/wx-console.conmsg"));
    init_msg(NULL, NULL);
@@ -167,6 +263,7 @@ console_thread::~console_thread() {
  * Thread entry point
  */
 void* console_thread::Entry() {
+   DIRRES* dir;
    if (!inited) {
       csprint("Error : Library not initialized\n");
       csprint(NULL, CS_END);
@@ -195,7 +292,6 @@ void* console_thread::Entry() {
    DIRRES* res[16]; /* Maximum 16 directors */
    
    LockRes();
-   DIRRES* dir;
    foreach_res(dir, R_DIRECTOR) {
       res[count] = dir;
       count++;
@@ -214,11 +310,9 @@ void* console_thread::Entry() {
          Exit();
       #endif
       return NULL;
-   }
-   else if (count == 1) {
+   } else if (count == 1) {
       directorchoosen = 1;
-   }
-   else {
+   } else {
       while (true) {
          csprint("Multiple directors found in your config file.\n");
          for (int i = 0; i < count; i++) {
@@ -243,13 +337,62 @@ void* console_thread::Entry() {
          }
       }
    }
+   dir = res[directorchoosen-1];
 
    memset(&jcr, 0, sizeof(jcr));
    
    jcr.dequeuing = 1; /* TODO: catch messages */
 
+   LockRes();
+   /* If cons==NULL, default console will be used */
+   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) {
+         bsnprintf(buf, sizeof(buf), _("Failed to initialize TLS context for Console \"%s\".\n"),
+            dir->hdr.name);
+         csprint(buf);
+         return NULL;
+      }
+
+   }
+
+   /* Initialize Director TLS context */
+   if (dir->tls_enable || dir->tls_require) {
+      /* Generate passphrase prompt */
+      bsnprintf(buf, sizeof(buf), "Passphrase for Director \"%s\" TLS private key: ", dir->hdr.name);
+
+      /* Initialize TLS context:
+       * Args: CA certfile, CA certdir, Certfile, Keyfile,
+       * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
+      dir->tls_ctx = new_tls_context(dir->tls_ca_certfile,
+         dir->tls_ca_certdir, dir->tls_certfile,
+         dir->tls_keyfile, tls_pem_callback, &buf, NULL, true);
+
+      if (!dir->tls_ctx) {
+         bsnprintf(buf, sizeof(buf), _("Failed to initialize TLS context for Director \"%s\".\n"),
+            dir->hdr.name);
+         csprint(buf);
+         return NULL;
+      }
+   }
+
+
    UA_sock = bnet_connect(&jcr, 3, 3, "Director daemon",
-      res[directorchoosen-1]->address, NULL, res[directorchoosen-1]->DIRport, 0);
+      dir->address, NULL, dir->DIRport, 0);
       
    if (UA_sock == NULL) {
       csprint("Failed to connect to the director\n");
@@ -265,11 +408,7 @@ void* console_thread::Entry() {
    csprint("Connected\n");
 
    jcr.dir_bsock = UA_sock;
-   LockRes();
-   /* If cons==NULL, default console will be used */
-   CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
-   UnlockRes();
-   if (!authenticate_director(&jcr, res[directorchoosen-1], cons)) {
+   if (!authenticate_director(&jcr, dir, cons)) {
       csprint("ERR=");
       csprint(UA_sock->msg);
       csprint(NULL, CS_END);