From: Kern Sibbald Date: Sat, 9 Jul 2005 13:55:35 +0000 (+0000) Subject: Implement TLS in gnome console and wx-console. X-Git-Tag: Release-1.38.0~321 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=ae5d2b860379151a2f17bc9e1788956f8f82fb99;p=bacula%2Fbacula Implement TLS in gnome console and wx-console. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@2183 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/kernstodo b/bacula/kernstodo index b64e7e9d02..94a37d23b1 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -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 + diff --git a/bacula/kes-1.37 b/bacula/kes-1.37 index 4a821b655f..3c649f87ab 100644 --- a/bacula/kes-1.37 +++ b/bacula/kes-1.37 @@ -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 diff --git a/bacula/src/console/console.c b/bacula/src/console/console.c index 3d9b0b5b2b..af82ec5e78 100644 --- a/bacula/src/console/console.c +++ b/bacula/src/console/console.c @@ -306,7 +306,6 @@ static int tls_pem_callback(char *buf, int size, const void *userdata) buf[0] = 0; return 0; #endif - } diff --git a/bacula/src/gnome2-console/console.c b/bacula/src/gnome2-console/console.c index df4f4dfb65..e2223c49a2 100644 --- a/bacula/src/gnome2-console/console.c +++ b/bacula/src/gnome2-console/console.c @@ -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 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); diff --git a/bacula/src/gnome2-console/console_conf.c b/bacula/src/gnome2-console/console_conf.c index a64d448c5d..e0601dcc85 100644 --- a/bacula/src/gnome2-console/console_conf.c +++ b/bacula/src/gnome2-console/console_conf.c @@ -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); } } } diff --git a/bacula/src/gnome2-console/console_conf.h b/bacula/src/gnome2-console/console_conf.h index 0f621c6cff..530ce1870f 100644 --- a/bacula/src/gnome2-console/console_conf.h +++ b/bacula/src/gnome2-console/console_conf.h @@ -16,54 +16,66 @@ 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; }; diff --git a/bacula/src/version.h b/bacula/src/version.h index 4ca58bef97..1c9d61a0e4 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -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 diff --git a/bacula/src/wx-console/console_conf.h b/bacula/src/wx-console/console_conf.h index a468dc9c44..5ef1fc3c7f 100644 --- a/bacula/src/wx-console/console_conf.h +++ b/bacula/src/wx-console/console_conf.h @@ -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; }; diff --git a/bacula/src/wx-console/console_thread.cpp b/bacula/src/wx-console/console_thread.cpp index f54a178e0f..1d1fc76f08 100644 --- a/bacula/src/wx-console/console_thread.cpp +++ b/bacula/src/wx-console/console_thread.cpp @@ -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);