From 8b04726b7e73e294a39f818d9d2867b5718c8522 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Tue, 11 Dec 2007 22:04:34 +0000 Subject: [PATCH] Implement a security enhancement: TLS authentication but no encryption. Enabled by setting 'TLS Authentication = yes'. Note when this is on, TLS encryption is turned OFF git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@6040 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/console/authenticate.c | 28 ++++++--- bacula/src/console/console.c | 8 ++- bacula/src/console/console_conf.c | 10 ++-- bacula/src/console/console_conf.h | 10 ++-- bacula/src/dird/authenticate.c | 58 +++++++++++++++---- bacula/src/dird/dird.c | 36 +++++++----- bacula/src/dird/dird_conf.c | 4 ++ bacula/src/dird/dird_conf.h | 4 ++ bacula/src/filed/authenticate.c | 52 +++++++++++------ bacula/src/filed/filed.c | 15 +++-- bacula/src/filed/filed_conf.c | 2 + bacula/src/filed/filed_conf.h | 2 + bacula/src/lib/bnet.c | 3 +- bacula/src/lib/bsock.c | 6 ++ bacula/src/lib/bsock.h | 1 + bacula/src/lib/openssl.c | 2 +- bacula/src/lib/tls.c | 2 +- bacula/src/qt-console/bat_conf.cpp | 10 ++-- bacula/src/qt-console/bat_conf.h | 2 + .../src/qt-console/console/authenticate.cpp | 24 +++++--- bacula/src/qt-console/main.cpp | 7 ++- bacula/src/stored/authenticate.c | 44 ++++++++++---- bacula/src/stored/stored.c | 21 ++++--- bacula/src/stored/stored_conf.c | 26 +++++---- bacula/src/stored/stored_conf.h | 16 ++--- bacula/technotes-2.3 | 4 ++ 26 files changed, 274 insertions(+), 123 deletions(-) diff --git a/bacula/src/console/authenticate.c b/bacula/src/console/authenticate.c index 5887cbb3b4..abea3cff4a 100644 --- a/bacula/src/console/authenticate.c +++ b/bacula/src/console/authenticate.c @@ -62,6 +62,8 @@ int authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons) BSOCK *dir = jcr->dir_bsock; int tls_local_need = BNET_TLS_NONE; int tls_remote_need = BNET_TLS_NONE; + bool tls_needed; + bool tls_authenticate; int compatible = true; char bashed_name[MAX_NAME_LENGTH]; char *password; @@ -82,7 +84,11 @@ int authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons) tls_local_need = BNET_TLS_OK; } } - + if (cons->tls_authenticate) { + tls_local_need = BNET_TLS_REQUIRED; + } + tls_authenticate = cons->tls_authenticate; + tls_needed = cons->tls_enable || cons->tls_authenticate; tls_ctx = cons->tls_ctx; } else { bstrncpy(bashed_name, "*UserAgent*", sizeof(bashed_name)); @@ -96,6 +102,11 @@ int authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons) } } + if (director->tls_authenticate) { + tls_local_need = BNET_TLS_REQUIRED; + } + tls_authenticate = director->tls_authenticate; + tls_needed = director->tls_enable || director->tls_authenticate; tls_ctx = director->tls_ctx; } @@ -124,13 +135,14 @@ int authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons) } /* 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)) { - sendit(_("TLS negotiation failed\n")); - goto bail_out; - } + 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)) { + sendit(_("TLS negotiation failed\n")); + goto bail_out; + } + if (tls_authenticate) { /* Authenticate only? */ + dir->free_tls(); /* yes, shutdown tls */ } } diff --git a/bacula/src/console/console.c b/bacula/src/console/console.c index 0f57d173c4..9b88aa801e 100644 --- a/bacula/src/console/console.c +++ b/bacula/src/console/console.c @@ -822,6 +822,7 @@ static int check_resources() { bool OK = true; DIRRES *director; + bool tls_needed; LockRes(); @@ -839,8 +840,9 @@ static int check_resources() continue; } } + tls_needed = director->tls_enable || director->tls_authenticate; - if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && director->tls_enable) { + if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && tls_needed) { 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"), @@ -868,8 +870,8 @@ static int check_resources() continue; } } - - if ((!cons->tls_ca_certfile && !cons->tls_ca_certdir) && cons->tls_enable) { + tls_needed = cons->tls_enable || cons->tls_authenticate; + if ((!cons->tls_ca_certfile && !cons->tls_ca_certdir) && tls_needed) { 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); diff --git a/bacula/src/console/console_conf.c b/bacula/src/console/console_conf.c index 2ce66bbca8..1bdda9357e 100644 --- a/bacula/src/console/console_conf.c +++ b/bacula/src/console/console_conf.c @@ -88,8 +88,9 @@ static RES_ITEM cons_items[] = { {"rcfile", store_dir, ITEM(res_cons.rc_file), 0, 0, 0}, {"historyfile", store_dir, ITEM(res_cons.hist_file), 0, 0, 0}, {"password", store_password, ITEM(res_cons.password), 0, ITEM_REQUIRED, 0}, - {"tlsenable", store_bit, ITEM(res_cons.tls_enable), 1, 0, 0}, - {"tlsrequire", store_bit, ITEM(res_cons.tls_require), 1, 0, 0}, + {"tlsauthenticate",store_bool, ITEM(res_cons.tls_authenticate), 0, 0, 0}, + {"tlsenable", store_bool, ITEM(res_cons.tls_enable), 0, 0, 0}, + {"tlsrequire", store_bool, ITEM(res_cons.tls_require), 0, 0, 0}, {"tlscacertificatefile", store_dir, ITEM(res_cons.tls_ca_certfile), 0, 0, 0}, {"tlscacertificatedir", store_dir, ITEM(res_cons.tls_ca_certdir), 0, 0, 0}, {"tlscertificate", store_dir, ITEM(res_cons.tls_certfile), 0, 0, 0}, @@ -107,8 +108,9 @@ static RES_ITEM dir_items[] = { {"dirport", store_int, ITEM(res_dir.DIRport), 0, ITEM_DEFAULT, 9101}, {"address", store_str, ITEM(res_dir.address), 0, 0, 0}, {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0}, - {"tlsenable", store_bit, ITEM(res_dir.tls_enable), 1, 0, 0}, - {"tlsrequire", store_bit, ITEM(res_dir.tls_require), 1, 0, 0}, + {"tlsauthenticate",store_bool, ITEM(res_dir.tls_enable), 0, 0, 0}, + {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0}, + {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0}, {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0}, {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0}, {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0}, diff --git a/bacula/src/console/console_conf.h b/bacula/src/console/console_conf.h index b129cb27ae..3dda499599 100644 --- a/bacula/src/console/console_conf.h +++ b/bacula/src/console/console_conf.h @@ -64,8 +64,9 @@ struct CONRES { char *rc_file; /* startup file */ char *hist_file; /* command history file */ char *password; /* UA server password */ - int tls_enable; /* Enable TLS on all connections */ - int tls_require; /* Require TLS on all connections */ + bool tls_authenticate; /* Authenticate with TLS */ + bool tls_enable; /* Enable TLS on all connections */ + bool 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 */ @@ -82,8 +83,9 @@ struct DIRRES { 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 */ + bool tls_authenticate; /* Authenticate with TLS */ + bool tls_enable; /* Enable TLS */ + bool 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 */ diff --git a/bacula/src/dird/authenticate.c b/bacula/src/dird/authenticate.c index 1bbb84e3d2..61c9ccfe85 100644 --- a/bacula/src/dird/authenticate.c +++ b/bacula/src/dird/authenticate.c @@ -41,6 +41,8 @@ #include "bacula.h" #include "dird.h" +static const int dbglvl = 50; + extern DIRRES *director; /* Commands sent to Storage daemon and File daemon and received @@ -77,7 +79,7 @@ bool authenticate_storage_daemon(JCR *jcr, STORE *store) btimer_t *tid = start_bsock_timer(sd, AUTH_TIMEOUT); if (!sd->fsend(hello, dirname)) { stop_bsock_timer(tid); - Dmsg1(50, _("Error sending Hello to Storage daemon. ERR=%s\n"), bnet_strerror(sd)); + Dmsg1(dbglvl, _("Error sending Hello to Storage daemon. ERR=%s\n"), bnet_strerror(sd)); Jmsg(jcr, M_FATAL, 0, _("Error sending Hello to Storage daemon. ERR=%s\n"), bnet_strerror(sd)); return 0; } @@ -91,19 +93,23 @@ bool authenticate_storage_daemon(JCR *jcr, STORE *store) } } + if (store->tls_authenticate) { + tls_local_need = BNET_TLS_REQUIRED; + } + auth_success = cram_md5_respond(sd, store->password, &tls_remote_need, &compatible); if (auth_success) { auth_success = cram_md5_challenge(sd, store->password, tls_local_need, compatible); if (!auth_success) { - Dmsg1(50, "cram_challenge failed for %s\n", sd->who()); + Dmsg1(dbglvl, "cram_challenge failed for %s\n", sd->who()); } } else { - Dmsg1(50, "cram_respond failed for %s\n", sd->who()); + Dmsg1(dbglvl, "cram_respond failed for %s\n", sd->who()); } if (!auth_success) { stop_bsock_timer(tid); - Dmsg0(50, _("Director and Storage daemon passwords or names not the same.\n")); + Dmsg0(dbglvl, _("Director and Storage daemon passwords or names not the same.\n")); Jmsg2(jcr, M_FATAL, 0, _("Director unable to authenticate with Storage daemon at \"%s:%d\". Possible causes:\n" "Passwords or names not the same or\n" @@ -137,6 +143,9 @@ bool authenticate_storage_daemon(JCR *jcr, STORE *store) sd->host(), sd->port()); return 0; } + if (store->tls_authenticate) { /* authentication only? */ + sd->free_tls(); /* yes, stop tls */ + } } Dmsg1(116, ">stored: %s", sd->msg); @@ -149,7 +158,7 @@ bool authenticate_storage_daemon(JCR *jcr, STORE *store) Dmsg1(110, "msg); stop_bsock_timer(tid); if (strncmp(sd->msg, OKhello, sizeof(OKhello)) != 0) { - Dmsg0(50, _("Storage daemon rejected Hello command\n")); + Dmsg0(dbglvl, _("Storage daemon rejected Hello command\n")); Jmsg2(jcr, M_FATAL, 0, _("Storage daemon at \"%s:%d\" rejected Hello command\n"), sd->host(), sd->port()); return 0; @@ -183,7 +192,7 @@ int authenticate_file_daemon(JCR *jcr) fd->host(), fd->port(), fd->bstrerror()); return 0; } - Dmsg1(50, "Sent: %s", fd->msg); + Dmsg1(dbglvl, "Sent: %s", fd->msg); /* TLS Requirement */ if (client->tls_enable) { @@ -194,18 +203,22 @@ int authenticate_file_daemon(JCR *jcr) } } + if (client->tls_authenticate) { + tls_local_need = BNET_TLS_REQUIRED; + } + auth_success = cram_md5_respond(fd, client->password, &tls_remote_need, &compatible); if (auth_success) { auth_success = cram_md5_challenge(fd, client->password, tls_local_need, compatible); if (!auth_success) { - Dmsg1(50, "cram_auth failed for %s\n", fd->who()); + Dmsg1(dbglvl, "cram_auth failed for %s\n", fd->who()); } } else { - Dmsg1(50, "cram_get_auth failed for %s\n", fd->who()); + Dmsg1(dbglvl, "cram_get_auth failed for %s\n", fd->who()); } if (!auth_success) { stop_bsock_timer(tid); - Dmsg0(50, _("Director and File daemon passwords or names not the same.\n")); + Dmsg0(dbglvl, _("Director and File daemon passwords or names not the same.\n")); Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate with File daemon at \"%s:%d\". Possible causes:\n" "Passwords or names not the same or\n" @@ -242,12 +255,15 @@ int authenticate_file_daemon(JCR *jcr) fd->host(), fd->port()); return 0; } + if (client->tls_authenticate) { /* tls authentication only? */ + fd->free_tls(); /* yes, shutdown tls */ + } } Dmsg1(116, ">filed: %s", fd->msg); if (fd->recv() <= 0) { stop_bsock_timer(tid); - Dmsg1(50, _("Bad response from File daemon to Hello command: ERR=%s\n"), + Dmsg1(dbglvl, _("Bad response from File daemon to Hello command: ERR=%s\n"), bnet_strerror(fd)); Jmsg(jcr, M_FATAL, 0, _("Bad response from File daemon at \"%s:%d\" to Hello command: ERR=%s\n"), fd->host(), fd->port(), fd->bstrerror()); @@ -256,7 +272,7 @@ int authenticate_file_daemon(JCR *jcr) Dmsg1(110, "msg); stop_bsock_timer(tid); if (strncmp(fd->msg, FDOKhello, sizeof(FDOKhello)) != 0) { - Dmsg0(50, _("File daemon rejected Hello command\n")); + Dmsg0(dbglvl, _("File daemon rejected Hello command\n")); Jmsg(jcr, M_FATAL, 0, _("File daemon at \"%s:%d\" rejected Hello command\n"), fd->host(), fd->port()); return 0; @@ -272,6 +288,8 @@ int authenticate_user_agent(UAContext *uac) char name[MAX_NAME_LENGTH]; int tls_local_need = BNET_TLS_NONE; int tls_remote_need = BNET_TLS_NONE; + bool need_tls; + bool tls_authenticate; int compatible = true; CONRES *cons = NULL; BSOCK *ua = uac->UA_sock; @@ -303,6 +321,13 @@ int authenticate_user_agent(UAContext *uac) } } + tls_authenticate = director->tls_authenticate; + need_tls = director->tls_enable || tls_authenticate; + + if (tls_authenticate) { + tls_local_need = BNET_TLS_REQUIRED; + } + if (director->tls_verify_peer) { verify_list = director->tls_allowed_cns; } @@ -323,6 +348,13 @@ int authenticate_user_agent(UAContext *uac) } } + tls_authenticate = cons->tls_authenticate; + need_tls = cons->tls_enable || tls_authenticate; + + if (tls_authenticate) { + tls_local_need = BNET_TLS_REQUIRED; + } + if (cons->tls_verify_peer) { verify_list = cons->tls_allowed_cns; } @@ -340,6 +372,7 @@ int authenticate_user_agent(UAContext *uac) } } + /* Verify that the remote peer 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) { Emsg0(M_FATAL, 0, _("Authorization problem:" @@ -369,6 +402,9 @@ int authenticate_user_agent(UAContext *uac) auth_success = false; goto auth_done; } + if (tls_authenticate) { /* authentication only? */ + ua->free_tls(); /* stop tls */ + } } diff --git a/bacula/src/dird/dird.c b/bacula/src/dird/dird.c index c4dc63b69d..bccd480be1 100644 --- a/bacula/src/dird/dird.c +++ b/bacula/src/dird/dird.c @@ -539,6 +539,7 @@ static bool check_resources() { bool OK = true; JOB *job; + bool need_tls; LockRes(); @@ -572,19 +573,22 @@ static bool check_resources() } } - if (!director->tls_certfile && director->tls_enable) { + need_tls = director->tls_enable || director->tls_authenticate; + + if (!director->tls_certfile && need_tls) { Jmsg(NULL, M_FATAL, 0, _("\"TLS Certificate\" file not defined for Director \"%s\" in %s.\n"), director->name(), configfile); OK = false; } - if (!director->tls_keyfile && director->tls_enable) { + if (!director->tls_keyfile && need_tls) { Jmsg(NULL, M_FATAL, 0, _("\"TLS Key\" file not defined for Director \"%s\" in %s.\n"), director->name(), configfile); OK = false; } - if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && director->tls_enable && director->tls_verify_peer) { + if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && + need_tls && director->tls_verify_peer) { Jmsg(NULL, 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" @@ -594,7 +598,7 @@ static bool check_resources() } /* If everything is well, attempt to initialize our per-resource TLS context */ - if (OK && (director->tls_enable || director->tls_require)) { + if (OK && (need_tls || director->tls_require)) { /* Initialize TLS context: * Args: CA certfile, CA certdir, Certfile, Keyfile, * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */ @@ -774,19 +778,22 @@ static bool check_resources() } } - if (!cons->tls_certfile && cons->tls_enable) { + need_tls = cons->tls_enable || cons->tls_authenticate; + + if (!cons->tls_certfile && need_tls) { Jmsg(NULL, M_FATAL, 0, _("\"TLS Certificate\" file not defined for Console \"%s\" in %s.\n"), cons->name(), configfile); OK = false; } - if (!cons->tls_keyfile && cons->tls_enable) { + if (!cons->tls_keyfile && need_tls) { Jmsg(NULL, M_FATAL, 0, _("\"TLS Key\" file not defined for Console \"%s\" in %s.\n"), cons->name(), configfile); OK = false; } - if ((!cons->tls_ca_certfile && !cons->tls_ca_certdir) && cons->tls_enable && cons->tls_verify_peer) { + if ((!cons->tls_ca_certfile && !cons->tls_ca_certdir) + && need_tls && cons->tls_verify_peer) { Jmsg(NULL, M_FATAL, 0, _("Neither \"TLS CA Certificate\" or \"TLS CA" " Certificate Dir\" are defined for Console \"%s\" in %s." " At least one CA certificate store is required" @@ -795,7 +802,7 @@ static bool check_resources() OK = false; } /* If everything is well, attempt to initialize our per-resource TLS context */ - if (OK && (cons->tls_enable || cons->tls_require)) { + if (OK && (need_tls || cons->tls_require)) { /* Initialize TLS context: * Args: CA certfile, CA certdir, Certfile, Keyfile, * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */ @@ -825,8 +832,8 @@ static bool check_resources() continue; } } - - if ((!client->tls_ca_certfile && !client->tls_ca_certdir) && client->tls_enable) { + need_tls = client->tls_enable || client->tls_authenticate; + if ((!client->tls_ca_certfile && !client->tls_ca_certdir) && need_tls) { Jmsg(NULL, M_FATAL, 0, _("Neither \"TLS CA Certificate\"" " or \"TLS CA Certificate Dir\" are defined for File daemon \"%s\" in %s.\n"), client->name(), configfile); @@ -834,7 +841,7 @@ static bool check_resources() } /* If everything is well, attempt to initialize our per-resource TLS context */ - if (OK && (client->tls_enable || client->tls_require)) { + if (OK && (need_tls || client->tls_require)) { /* Initialize TLS context: * Args: CA certfile, CA certdir, Certfile, Keyfile, * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */ @@ -862,6 +869,7 @@ static bool check_resources() static bool check_catalog() { bool OK = true; + bool need_tls; /* Loop over databases */ CAT *catalog; @@ -929,7 +937,9 @@ static bool check_catalog() } } - if ((!store->tls_ca_certfile && !store->tls_ca_certdir) && store->tls_enable) { + need_tls = store->tls_enable || store->tls_authenticate; + + if ((!store->tls_ca_certfile && !store->tls_ca_certdir) && need_tls) { Jmsg(NULL, M_FATAL, 0, _("Neither \"TLS CA Certificate\"" " or \"TLS CA Certificate Dir\" are defined for Storage \"%s\" in %s.\n"), store->name(), configfile); @@ -937,7 +947,7 @@ static bool check_catalog() } /* If everything is well, attempt to initialize our per-resource TLS context */ - if (OK && (store->tls_enable || store->tls_require)) { + if (OK && (need_tls || store->tls_require)) { /* Initialize TLS context: * Args: CA certfile, CA certdir, Certfile, Keyfile, * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */ diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index eb04adaa00..04312c14cd 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -122,6 +122,7 @@ static RES_ITEM dir_items[] = { {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30}, {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30}, {"heartbeatinterval", store_time, ITEM(res_dir.heartbeat_interval), 0, ITEM_DEFAULT, 0}, + {"tlsauthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0}, {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0}, {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0}, {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true}, @@ -153,6 +154,7 @@ static RES_ITEM con_items[] = { {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0}, {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0}, {"whereacl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0}, + {"tlsauthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0}, {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0}, {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0}, {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true}, @@ -186,6 +188,7 @@ static RES_ITEM cli_items[] = { {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0}, {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true}, {"maximumconcurrentjobs", store_pint, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1}, + {"tlsauthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0}, {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0}, {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0}, {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0}, @@ -215,6 +218,7 @@ static RES_ITEM store_items[] = { {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0}, {"maximumconcurrentjobs", store_pint, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1}, {"sddport", store_pint, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */ + {"tlsauthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0}, {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0}, {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0}, {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0}, diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h index 61e4a32cdb..f8d91cacc8 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -124,6 +124,7 @@ public: char *tls_dhfile; /* TLS Diffie-Hellman Parameters */ alist *tls_allowed_cns; /* TLS Allowed Clients */ TLS_CONTEXT *tls_ctx; /* Shared TLS Context */ + bool tls_authenticate; /* Authenticated with TLS */ bool tls_enable; /* Enable TLS */ bool tls_require; /* Require TLS */ bool tls_verify_peer; /* TLS Verify Client Certificate */ @@ -201,6 +202,7 @@ public: char *tls_dhfile; /* TLS Diffie-Hellman Parameters */ alist *tls_allowed_cns; /* TLS Allowed Clients */ TLS_CONTEXT *tls_ctx; /* Shared TLS Context */ + bool tls_authenticate; /* Authenticated with TLS */ bool tls_enable; /* Enable TLS */ bool tls_require; /* Require TLS */ bool tls_verify_peer; /* TLS Verify Client Certificate */ @@ -258,6 +260,7 @@ public: char *tls_keyfile; /* TLS Client Key File */ alist *tls_allowed_cns; /* TLS Allowed Clients */ TLS_CONTEXT *tls_ctx; /* Shared TLS Context */ + bool tls_authenticate; /* Authenticated with TLS */ bool tls_enable; /* Enable TLS */ bool tls_require; /* Require TLS */ bool AutoPrune; /* Do automatic pruning? */ @@ -290,6 +293,7 @@ public: char *tls_certfile; /* TLS Client Certificate File */ char *tls_keyfile; /* TLS Client Key File */ TLS_CONTEXT *tls_ctx; /* Shared TLS Context */ + bool tls_authenticate; /* Authenticated with TLS */ bool tls_enable; /* Enable TLS */ bool tls_require; /* Require TLS */ bool enabled; /* Set if device is enabled */ diff --git a/bacula/src/filed/authenticate.c b/bacula/src/filed/authenticate.c index 12de1816ce..0f0e01081b 100644 --- a/bacula/src/filed/authenticate.c +++ b/bacula/src/filed/authenticate.c @@ -59,7 +59,7 @@ static bool authenticate(int rcode, BSOCK *bs, JCR* jcr) if (rcode != R_DIRECTOR) { Dmsg1(dbglvl, "I only authenticate directors, not %d\n", rcode); - Emsg1(M_FATAL, 0, _("I only authenticate directors, not %d\n"), rcode); + Jmsg1(jcr, M_FATAL, 0, _("I only authenticate directors, not %d\n"), rcode); goto auth_fatal; } if (bs->msglen < 25 || bs->msglen > 500) { @@ -67,7 +67,7 @@ static bool authenticate(int rcode, BSOCK *bs, JCR* jcr) bs->who(), bs->msglen); char addr[64]; char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr; - Emsg2(M_FATAL, 0, _("Bad Hello command from Director at %s. Len=%d.\n"), + Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s. Len=%d.\n"), who, bs->msglen); goto auth_fatal; } @@ -79,7 +79,7 @@ static bool authenticate(int rcode, BSOCK *bs, JCR* jcr) bs->msg[100] = 0; Dmsg2(dbglvl, "Bad Hello command from Director at %s: %s\n", bs->who(), bs->msg); - Emsg2(M_FATAL, 0, _("Bad Hello command from Director at %s: %s\n"), + Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s: %s\n"), who, bs->msg); goto auth_fatal; } @@ -89,9 +89,9 @@ static bool authenticate(int rcode, BSOCK *bs, JCR* jcr) break; } if (!director) { - char addr[64]; - char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr; - Emsg2(M_FATAL, 0, _("Connection from unknown Director %s at %s rejected.\n"), + char addr[64]; + char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr; + Jmsg2(jcr, M_FATAL, 0, _("Connection from unknown Director %s at %s rejected.\n"), dirname, who); goto auth_fatal; } @@ -106,6 +106,10 @@ static bool authenticate(int rcode, BSOCK *bs, JCR* jcr) } } + if (director->tls_authenticate) { + tls_local_need = BNET_TLS_REQUIRED; + } + if (director->tls_verify_peer) { verify_list = director->tls_allowed_cns; } @@ -138,27 +142,30 @@ static bool authenticate(int rcode, BSOCK *bs, JCR* jcr) /* 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) { - Emsg0(M_FATAL, 0, _("Authorization problem: Remote server did not" + Jmsg0(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not" " advertize required TLS support.\n")); + Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need); auth_success = false; goto auth_fatal; } /* Verify that we are willing to meet the remote host's requirements */ if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) { - Emsg0(M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n")); + Jmsg0(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n")); + Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need); auth_success = false; goto auth_fatal; } - if (have_tls) { - if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) { - /* Engage TLS! Full Speed Ahead! */ - if (!bnet_tls_server(director->tls_ctx, bs, verify_list)) { - Emsg0(M_FATAL, 0, _("TLS negotiation failed.\n")); - auth_success = false; - goto auth_fatal; - } + if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) { + /* Engage TLS! Full Speed Ahead! */ + if (!bnet_tls_server(director->tls_ctx, bs, verify_list)) { + Jmsg0(jcr, M_FATAL, 0, _("TLS negotiation failed.\n")); + auth_success = false; + goto auth_fatal; + } + if (director->tls_authenticate) { /* authentication only? */ + bs->free_tls(); /* shutodown tls */ } } @@ -221,6 +228,10 @@ int authenticate_storagedaemon(JCR *jcr) } } + if (me->tls_authenticate) { + tls_local_need = BNET_TLS_REQUIRED; + } + if (job_canceled(jcr)) { auth_success = false; /* force quick exit */ goto auth_fatal; @@ -251,7 +262,8 @@ int authenticate_storagedaemon(JCR *jcr) /* Verify that the remote host is willing to meet our TLS requirements */ if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) { Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not" - " advertise required TLS support.\n")); + " advertize required TLS support.\n")); + Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need); auth_success = false; goto auth_fatal; } @@ -259,17 +271,21 @@ int authenticate_storagedaemon(JCR *jcr) /* Verify that we are willing to meet the remote host's requirements */ if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) { Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n")); + Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need); auth_success = false; goto auth_fatal; } - if (have_tls && tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) { + if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) { /* Engage TLS! Full Speed Ahead! */ if (!bnet_tls_client(me->tls_ctx, sd, NULL)) { Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed.\n")); auth_success = false; goto auth_fatal; } + if (me->tls_authenticate) { /* tls authentication only? */ + sd->free_tls(); /* yes, shutdown tls */ + } } auth_fatal: diff --git a/bacula/src/filed/filed.c b/bacula/src/filed/filed.c index 5bbd1bb01a..9fad17c43b 100644 --- a/bacula/src/filed/filed.c +++ b/bacula/src/filed/filed.c @@ -274,6 +274,7 @@ static bool check_resources() { bool OK = true; DIRRES *director; + bool need_tls; LockRes(); @@ -305,8 +306,9 @@ static bool check_resources() me->tls_enable = true; #endif } + need_tls = me->tls_enable || me->tls_authenticate; - if ((!me->tls_ca_certfile && !me->tls_ca_certdir) && me->tls_enable) { + if ((!me->tls_ca_certfile && !me->tls_ca_certdir) && need_tls) { Emsg1(M_FATAL, 0, _("Neither \"TLS CA Certificate\"" " or \"TLS CA Certificate Dir\" are defined for File daemon in %s.\n"), configfile); @@ -314,7 +316,7 @@ static bool check_resources() } /* If everything is well, attempt to initialize our per-resource TLS context */ - if (OK && (me->tls_enable || me->tls_require)) { + if (OK && (need_tls || me->tls_require)) { /* Initialize TLS context: * Args: CA certfile, CA certdir, Certfile, Keyfile, * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */ @@ -464,20 +466,21 @@ static bool check_resources() director->tls_enable = true; #endif } + need_tls = director->tls_enable || director->tls_authenticate; - if (!director->tls_certfile && director->tls_enable) { + if (!director->tls_certfile && need_tls) { Emsg2(M_FATAL, 0, _("\"TLS Certificate\" file not defined for Director \"%s\" in %s.\n"), director->hdr.name, configfile); OK = false; } - if (!director->tls_keyfile && director->tls_enable) { + if (!director->tls_keyfile && need_tls) { Emsg2(M_FATAL, 0, _("\"TLS Key\" file not defined for Director \"%s\" in %s.\n"), director->hdr.name, configfile); OK = false; } - if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && director->tls_enable && director->tls_verify_peer) { + if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && need_tls && director->tls_verify_peer) { 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" @@ -487,7 +490,7 @@ static bool check_resources() } /* If everything is well, attempt to initialize our per-resource TLS context */ - if (OK && (director->tls_enable || director->tls_require)) { + if (OK && (need_tls || director->tls_require)) { /* Initialize TLS context: * Args: CA certfile, CA certdir, Certfile, Keyfile, * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */ diff --git a/bacula/src/filed/filed_conf.c b/bacula/src/filed/filed_conf.c index 427bc4bcfb..a7ce38b564 100644 --- a/bacula/src/filed/filed_conf.c +++ b/bacula/src/filed/filed_conf.c @@ -108,6 +108,7 @@ static RES_ITEM cli_items[] = { {"pkisigner", store_alist_str, ITEM(res_client.pki_signing_key_files), 0, 0, 0}, {"pkimasterkey", store_alist_str, ITEM(res_client.pki_master_key_files), 0, 0, 0}, #endif + {"tlsauthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0}, {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0}, {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0}, {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0}, @@ -124,6 +125,7 @@ static RES_ITEM dir_items[] = { {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0}, {"address", store_str, ITEM(res_dir.address), 0, 0, 0}, {"monitor", store_bool, ITEM(res_dir.monitor), 0, ITEM_DEFAULT, 0}, + {"tlsauthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0}, {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0}, {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0}, {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, 1}, diff --git a/bacula/src/filed/filed_conf.h b/bacula/src/filed/filed_conf.h index c64b35d17d..2efbb2a2b0 100644 --- a/bacula/src/filed/filed_conf.h +++ b/bacula/src/filed/filed_conf.h @@ -59,6 +59,7 @@ struct DIRRES { char *password; /* Director password */ char *address; /* Director address or zero */ bool monitor; /* Have only access to status and .status functions */ + bool tls_authenticate; /* Authenticate with TSL */ bool tls_enable; /* Enable TLS */ bool tls_require; /* Require TLS */ bool tls_verify_peer; /* TLS Verify Client Certificate */ @@ -89,6 +90,7 @@ struct CLIENT { char *pki_keypair_file; /* PKI Key Pair File */ alist *pki_signing_key_files; /* PKI Signing Key Files */ alist *pki_master_key_files; /* PKI Master Key Files */ + bool tls_authenticate; /* Authenticate with TLS */ bool tls_enable; /* Enable TLS */ bool tls_require; /* Require TLS */ char *tls_ca_certfile; /* TLS CA Certificate File */ diff --git a/bacula/src/lib/bnet.c b/bacula/src/lib/bnet.c index 08481133c0..1ed8e78bbf 100644 --- a/bacula/src/lib/bnet.c +++ b/bacula/src/lib/bnet.c @@ -261,6 +261,7 @@ bool bnet_tls_server(TLS_CONTEXT *ctx, BSOCK * bsock, alist *verify_list) goto err; } } + Dmsg0(50, "TLS server negotiation established.\n"); return true; err: @@ -307,7 +308,7 @@ bool bnet_tls_client(TLS_CONTEXT *ctx, BSOCK * bsock, alist *verify_list) goto err; } } - + Dmsg0(50, "TLS client negotiation established.\n"); return true; err: diff --git a/bacula/src/lib/bsock.c b/bacula/src/lib/bsock.c index 560d6233c3..c019f2ed91 100644 --- a/bacula/src/lib/bsock.c +++ b/bacula/src/lib/bsock.c @@ -85,6 +85,12 @@ void BSOCK::free_bsock() destroy(); } +void BSOCK::free_tls() +{ + free_tls_connection(this->tls); + this->tls = NULL; +} + /* * Try to connect to host for max_retry_time at retry_time intervals. * Note, you must have called the constructor prior to calling diff --git a/bacula/src/lib/bsock.h b/bacula/src/lib/bsock.h index f4a90085dc..118da0b209 100644 --- a/bacula/src/lib/bsock.h +++ b/bacula/src/lib/bsock.h @@ -91,6 +91,7 @@ public: /* methods -- in bsock.c */ void init(); void free_bsock(); + void free_tls(); bool connect(JCR * jcr, int retry_interval, utime_t max_retry_time, utime_t heart_beat, const char *name, char *host, char *service, int port, int verbose); diff --git a/bacula/src/lib/openssl.c b/bacula/src/lib/openssl.c index 014ed4026b..af4a46fb58 100644 --- a/bacula/src/lib/openssl.c +++ b/bacula/src/lib/openssl.c @@ -82,7 +82,7 @@ void openssl_post_errors(JCR *jcr, int code, const char *errstring) while((sslerr = ERR_get_error()) != 0) { /* Acquire the human readable string */ ERR_error_string_n(sslerr, buf, sizeof(buf)); - Dmsg3(100, "jcr=%p %s: ERR=%s\n", jcr, errstring, buf); + Dmsg3(50, "jcr=%p %s: ERR=%s\n", jcr, errstring, buf); Qmsg2(jcr, M_ERROR, 0, "%s: ERR=%s\n", errstring, buf); } } diff --git a/bacula/src/lib/tls.c b/bacula/src/lib/tls.c index f8062c073a..d70e4cb2d0 100644 --- a/bacula/src/lib/tls.c +++ b/bacula/src/lib/tls.c @@ -500,7 +500,7 @@ static inline bool openssl_bsock_session_start(BSOCK *bsock, bool server) select(fdmax, NULL, &fdset, NULL, &tv); break; default: - /* Socket Error Occured */ + /* Socket Error Occurred */ openssl_post_errors(M_ERROR, _("Connect failure")); stat = false; goto cleanup; diff --git a/bacula/src/qt-console/bat_conf.cpp b/bacula/src/qt-console/bat_conf.cpp index 1a08709592..d525ae181a 100644 --- a/bacula/src/qt-console/bat_conf.cpp +++ b/bacula/src/qt-console/bat_conf.cpp @@ -82,8 +82,9 @@ 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}, - {"tlsenable", store_bool, ITEM(dir_res.tls_enable), 1, 0, 0}, - {"tlsrequire", store_bool, ITEM(dir_res.tls_require), 1, 0, 0}, + {"tlsauthenticate",store_bool, ITEM(dir_res.tls_authenticate), 0, 0, 0}, + {"tlsenable", store_bool, ITEM(dir_res.tls_enable), 0, 0, 0}, + {"tlsrequire", store_bool, ITEM(dir_res.tls_require), 0, 0, 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}, @@ -96,8 +97,9 @@ 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}, - {"tlsenable", store_bool, ITEM(con_res.tls_enable), 1, 0, 0}, - {"tlsrequire", store_bool, ITEM(con_res.tls_require), 1, 0, 0}, + {"tlsauthenticate",store_bool, ITEM(con_res.tls_authenticate), 0, 0, 0}, + {"tlsenable", store_bool, ITEM(con_res.tls_enable), 0, 0, 0}, + {"tlsrequire", store_bool, ITEM(con_res.tls_require), 0, 0, 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}, diff --git a/bacula/src/qt-console/bat_conf.h b/bacula/src/qt-console/bat_conf.h index bcb6faa988..e09678c4a1 100644 --- a/bacula/src/qt-console/bat_conf.h +++ b/bacula/src/qt-console/bat_conf.h @@ -67,6 +67,7 @@ public: int DIRport; /* UA server port */ char *address; /* UA server address */ char *password; /* UA server password */ + bool tls_authenticate; /* Authenticate with tls */ bool tls_enable; /* Enable TLS */ bool tls_require; /* Require TLS */ char *tls_ca_certfile; /* TLS CA Certificate File */ @@ -93,6 +94,7 @@ class CONRES { public: RES hdr; char *password; /* UA server password */ + bool tls_authenticate; /* Authenticate with tls */ bool tls_enable; /* Enable TLS on all connections */ bool tls_require; /* Require TLS on all connections */ char *tls_ca_certfile; /* TLS CA Certificate File */ diff --git a/bacula/src/qt-console/console/authenticate.cpp b/bacula/src/qt-console/console/authenticate.cpp index 1ffd68bdef..dad53f44d2 100644 --- a/bacula/src/qt-console/console/authenticate.cpp +++ b/bacula/src/qt-console/console/authenticate.cpp @@ -58,6 +58,7 @@ bool Console::authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons, BSOCK *dir = jcr->dir_bsock; int tls_local_need = BNET_TLS_NONE; int tls_remote_need = BNET_TLS_NONE; + bool tls_authenticate; int compatible = true; char bashed_name[MAX_NAME_LENGTH]; char *password; @@ -79,6 +80,7 @@ bool Console::authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons, tls_local_need = BNET_TLS_OK; } } + tls_authenticate = cons->tls_authenticate; tls_ctx = cons->tls_ctx; } else { bstrncpy(bashed_name, "*UserAgent*", sizeof(bashed_name)); @@ -92,8 +94,13 @@ bool Console::authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons, } } + tls_authenticate = director->tls_authenticate; tls_ctx = director->tls_ctx; } + if (tls_authenticate) { + tls_local_need = BNET_TLS_REQUIRED; + } + /* Timeout Hello after 15 secs */ dir->start_timer(15); dir->fsend(hello, bashed_name); @@ -125,14 +132,15 @@ bool Console::authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons, } /* 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; - } + 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; + } + if (tls_authenticate) { /* authenticate only? */ + dir->free_tls(); /* Yes, shutdown tls */ } } diff --git a/bacula/src/qt-console/main.cpp b/bacula/src/qt-console/main.cpp index 1facbaa7bd..8aa2b39f39 100644 --- a/bacula/src/qt-console/main.cpp +++ b/bacula/src/qt-console/main.cpp @@ -195,6 +195,7 @@ static int check_resources() bool ok = true; DIRRES *director; int numdir; + bool tls_needed; LockRes(); @@ -211,8 +212,9 @@ static int check_resources() continue; } } + tls_needed = director->tls_enable || director->tls_authenticate; - if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && director->tls_enable) { + if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && tls_needed) { 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"), @@ -240,8 +242,9 @@ static int check_resources() continue; } } + tls_needed = cons->tls_enable || cons->tls_authenticate; - if ((!cons->tls_ca_certfile && !cons->tls_ca_certdir) && cons->tls_enable) { + if ((!cons->tls_ca_certfile && !cons->tls_ca_certdir) && tls_needed) { 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); diff --git a/bacula/src/stored/authenticate.c b/bacula/src/stored/authenticate.c index 49f6551fc5..bffb987e15 100644 --- a/bacula/src/stored/authenticate.c +++ b/bacula/src/stored/authenticate.c @@ -60,13 +60,13 @@ static int authenticate(int rcode, BSOCK *bs, JCR* jcr) if (rcode != R_DIRECTOR) { Dmsg1(dbglvl, "I only authenticate Directors, not %d\n", rcode); - Emsg1(M_FATAL, 0, _("I only authenticate Directors, not %d\n"), rcode); + Jmsg1(jcr, M_FATAL, 0, _("I only authenticate Directors, not %d\n"), rcode); return 0; } if (bs->msglen < 25 || bs->msglen > 500) { Dmsg2(dbglvl, "Bad Hello command from Director at %s. Len=%d.\n", bs->who(), bs->msglen); - Emsg2(M_FATAL, 0, _("Bad Hello command from Director at %s. Len=%d.\n"), + Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s. Len=%d.\n"), bs->who(), bs->msglen); return 0; } @@ -77,7 +77,7 @@ static int authenticate(int rcode, BSOCK *bs, JCR* jcr) bs->msg[100] = 0; Dmsg2(dbglvl, "Bad Hello command from Director at %s: %s\n", bs->who(), bs->msg); - Emsg2(M_FATAL, 0, _("Bad Hello command from Director at %s: %s\n"), + Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s: %s\n"), bs->who(), bs->msg); return 0; } @@ -90,7 +90,7 @@ static int authenticate(int rcode, BSOCK *bs, JCR* jcr) if (!director) { Dmsg2(dbglvl, "Connection from unknown Director %s at %s rejected.\n", dirname, bs->who()); - Emsg2(M_FATAL, 0, _("Connection from unknown Director %s at %s rejected.\n" + Jmsg2(jcr, M_FATAL, 0, _("Connection from unknown Director %s at %s rejected.\n" "Please see http://www.bacula.org/rel-manual/faq.html#AuthorizationErrors for help.\n"), dirname, bs->who()); free_pool_memory(dirname); @@ -106,6 +106,10 @@ static int authenticate(int rcode, BSOCK *bs, JCR* jcr) } } + if (director->tls_authenticate) { + tls_local_need = BNET_TLS_REQUIRED; + } + if (director->tls_verify_peer) { verify_list = director->tls_allowed_cns; } @@ -123,7 +127,7 @@ static int authenticate(int rcode, BSOCK *bs, JCR* jcr) } if (!auth_success) { - Emsg0(M_FATAL, 0, _("Incorrect password given by Director.\n" + Jmsg0(jcr, M_FATAL, 0, _("Incorrect password given by Director.\n" "Please see http://www.bacula.org/rel-manual/faq.html#AuthorizationErrors for help.\n")); auth_success = false; goto auth_fatal; @@ -131,15 +135,17 @@ static int authenticate(int rcode, BSOCK *bs, JCR* jcr) /* 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) { - Emsg0(M_FATAL, 0, _("Authorization problem: Remote server did not" - " advertise required TLS support.\n")); + Jmsg0(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not" + " advertize required TLS support.\n")); + Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need); auth_success = false; goto auth_fatal; } /* Verify that we are willing to meet the remote host's requirements */ if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) { - Emsg0(M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n")); + Jmsg0(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n")); + Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need); auth_success = false; goto auth_fatal; } @@ -147,10 +153,14 @@ static int authenticate(int rcode, BSOCK *bs, JCR* jcr) if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) { /* Engage TLS! Full Speed Ahead! */ if (!bnet_tls_server(director->tls_ctx, bs, verify_list)) { - Emsg0(M_FATAL, 0, _("TLS negotiation failed.\n")); + Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed with DIR at \"%s:%d\"\n"), + bs->host(), bs->port()); auth_success = false; goto auth_fatal; } + if (director->tls_authenticate) { /* authenticate with tls only? */ + bs->free_tls(); /* yes, shut it down */ + } } auth_fatal: @@ -179,7 +189,7 @@ int authenticate_director(JCR *jcr) if (!authenticate(R_DIRECTOR, dir, jcr)) { dir->fsend("%s", Dir_sorry); Dmsg1(dbglvl, "Unable to authenticate Director at %s.\n", dir->who()); - Emsg1(M_ERROR, 0, _("Unable to authenticate Director at %s.\n"), dir->who()); + Jmsg1(jcr, M_ERROR, 0, _("Unable to authenticate Director at %s.\n"), dir->who()); bmicrosleep(5, 0); return 0; } @@ -204,6 +214,10 @@ int authenticate_filed(JCR *jcr) } } + if (me->tls_authenticate) { + tls_local_need = BNET_TLS_REQUIRED; + } + if (me->tls_verify_peer) { verify_list = me->tls_allowed_cns; } @@ -233,7 +247,8 @@ int authenticate_filed(JCR *jcr) /* Verify that the remote host is willing to meet our TLS requirements */ if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) { Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not" - " advertise required TLS support.\n")); + " advertize required TLS support.\n")); + Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need); auth_success = false; goto auth_fatal; } @@ -241,6 +256,7 @@ int authenticate_filed(JCR *jcr) /* Verify that we are willing to meet the remote host's requirements */ if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) { Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n")); + Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need); auth_success = false; goto auth_fatal; } @@ -248,10 +264,14 @@ int authenticate_filed(JCR *jcr) if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) { /* Engage TLS! Full Speed Ahead! */ if (!bnet_tls_server(me->tls_ctx, fd, verify_list)) { - Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed.\n")); + Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed with FD at \"%s:%d\"\n"), + fd->host(), fd->port()); auth_success = false; goto auth_fatal; } + if (me->tls_authenticate) { /* tls authenticate only? */ + fd->free_tls(); /* yes, shut it down */ + } } auth_fatal: diff --git a/bacula/src/stored/stored.c b/bacula/src/stored/stored.c index f7d7605c1e..d878330cfb 100644 --- a/bacula/src/stored/stored.c +++ b/bacula/src/stored/stored.c @@ -287,6 +287,7 @@ uint32_t newVolSessionId() static int check_resources() { bool OK = true; + bool tls_needed; me = (STORES *)GetNextRes(R_STORAGE, NULL); @@ -341,19 +342,21 @@ static int check_resources() } } - if (!store->tls_certfile && store->tls_enable) { + tls_needed = store->tls_enable || store->tls_authenticate; + + if (!store->tls_certfile && tls_needed) { Jmsg(NULL, M_FATAL, 0, _("\"TLS Certificate\" file not defined for Storage \"%s\" in %s.\n"), store->hdr.name, configfile); OK = false; } - if (!store->tls_keyfile && store->tls_enable) { + if (!store->tls_keyfile && tls_needed) { Jmsg(NULL, M_FATAL, 0, _("\"TLS Key\" file not defined for Storage \"%s\" in %s.\n"), store->hdr.name, configfile); OK = false; } - if ((!store->tls_ca_certfile && !store->tls_ca_certdir) && store->tls_enable && store->tls_verify_peer) { + if ((!store->tls_ca_certfile && !store->tls_ca_certdir) && tls_needed && store->tls_verify_peer) { Jmsg(NULL, M_FATAL, 0, _("Neither \"TLS CA Certificate\"" " or \"TLS CA Certificate Dir\" are defined for Storage \"%s\" in %s." " At least one CA certificate store is required" @@ -363,7 +366,7 @@ static int check_resources() } /* If everything is well, attempt to initialize our per-resource TLS context */ - if (OK && (store->tls_enable || store->tls_require)) { + if (OK && (tls_needed || store->tls_require)) { /* Initialize TLS context: * Args: CA certfile, CA certdir, Certfile, Keyfile, * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */ @@ -386,19 +389,21 @@ static int check_resources() director->tls_enable = true; } - if (!director->tls_certfile && director->tls_enable) { + tls_needed = director->tls_enable || director->tls_authenticate; + + if (!director->tls_certfile && tls_needed) { Jmsg(NULL, M_FATAL, 0, _("\"TLS Certificate\" file not defined for Director \"%s\" in %s.\n"), director->hdr.name, configfile); OK = false; } - if (!director->tls_keyfile && director->tls_enable) { + if (!director->tls_keyfile && tls_needed) { Jmsg(NULL, M_FATAL, 0, _("\"TLS Key\" file not defined for Director \"%s\" in %s.\n"), director->hdr.name, configfile); OK = false; } - if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && director->tls_enable && director->tls_verify_peer) { + if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && tls_needed && director->tls_verify_peer) { Jmsg(NULL, 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" @@ -408,7 +413,7 @@ static int check_resources() } /* If everything is well, attempt to initialize our per-resource TLS context */ - if (OK && (director->tls_enable || director->tls_require)) { + if (OK && (tls_needed || director->tls_require)) { /* Initialize TLS context: * Args: CA certfile, CA certdir, Certfile, Keyfile, * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */ diff --git a/bacula/src/stored/stored_conf.c b/bacula/src/stored/stored_conf.c index caace4c970..0c96fd27c9 100644 --- a/bacula/src/stored/stored_conf.c +++ b/bacula/src/stored/stored_conf.c @@ -77,9 +77,10 @@ static RES_ITEM store_items[] = { {"scriptsdirectory", store_dir, ITEM(res_store.scripts_directory), 0, 0, 0}, {"maximumconcurrentjobs", store_pint, ITEM(res_store.max_concurrent_jobs), 0, ITEM_DEFAULT, 20}, {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0}, - {"tlsenable", store_bit, ITEM(res_store.tls_enable), 1, 0, 0}, - {"tlsrequire", store_bit, ITEM(res_store.tls_require), 1, 0, 0}, - {"tlsverifypeer", store_bit, ITEM(res_store.tls_verify_peer), 1, ITEM_DEFAULT, 1}, + {"tlsauthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0}, + {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0}, + {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0}, + {"tlsverifypeer", store_bool, ITEM(res_store.tls_verify_peer), 1, ITEM_DEFAULT, 1}, {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0}, {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0}, {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0}, @@ -96,10 +97,11 @@ static RES_ITEM dir_items[] = { {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0}, {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0}, {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0}, - {"monitor", store_bit, ITEM(res_dir.monitor), 1, ITEM_DEFAULT, 0}, - {"tlsenable", store_bit, ITEM(res_dir.tls_enable), 1, 0, 0}, - {"tlsrequire", store_bit, ITEM(res_dir.tls_require), 1, 0, 0}, - {"tlsverifypeer", store_bit, ITEM(res_dir.tls_verify_peer), 1, ITEM_DEFAULT, 1}, + {"monitor", store_bool, ITEM(res_dir.monitor), 0, 0, 0}, + {"tlsauthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0}, + {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0}, + {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0}, + {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 1, ITEM_DEFAULT, 1}, {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0}, {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0}, {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0}, @@ -111,11 +113,11 @@ static RES_ITEM dir_items[] = { /* Device definition */ static RES_ITEM dev_items[] = { - {"name", store_name, ITEM(res_dev.hdr.name), 0, ITEM_REQUIRED, 0}, - {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0}, - {"mediatype", store_strname,ITEM(res_dev.media_type), 0, ITEM_REQUIRED, 0}, - {"devicetype", store_devtype,ITEM(res_dev.dev_type), 0, 0, 0}, - {"archivedevice", store_strname,ITEM(res_dev.device_name), 0, ITEM_REQUIRED, 0}, + {"name", store_name, ITEM(res_dev.hdr.name), 0, ITEM_REQUIRED, 0}, + {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0}, + {"mediatype", store_strname,ITEM(res_dev.media_type), 0, ITEM_REQUIRED, 0}, + {"devicetype", store_devtype,ITEM(res_dev.dev_type), 0, 0, 0}, + {"archivedevice", store_strname,ITEM(res_dev.device_name), 0, ITEM_REQUIRED, 0}, {"hardwareendoffile", store_bit, ITEM(res_dev.cap_bits), CAP_EOF, ITEM_DEFAULT, 1}, {"hardwareendofmedium", store_bit, ITEM(res_dev.cap_bits), CAP_EOM, ITEM_DEFAULT, 1}, {"backwardspacerecord", store_bit, ITEM(res_dev.cap_bits), CAP_BSR, ITEM_DEFAULT, 1}, diff --git a/bacula/src/stored/stored_conf.h b/bacula/src/stored/stored_conf.h index f59986b01a..70b6126869 100644 --- a/bacula/src/stored/stored_conf.h +++ b/bacula/src/stored/stored_conf.h @@ -57,10 +57,11 @@ public: char *password; /* Director password */ char *address; /* Director IP address or zero */ - int monitor; /* Have only access to status and .status functions */ - int tls_enable; /* Enable TLS */ - int tls_require; /* Require TLS */ - int tls_verify_peer; /* TLS Verify Client Certificate */ + bool monitor; /* Have only access to status and .status functions */ + bool tls_authenticate; /* Authenticate with TLS */ + bool tls_enable; /* Enable TLS */ + bool tls_require; /* Require TLS */ + bool tls_verify_peer; /* TLS Verify Client Certificate */ char *tls_ca_certfile; /* TLS CA Certificate File */ char *tls_ca_certdir; /* TLS CA Certificate Directory */ char *tls_certfile; /* TLS Server Certificate File */ @@ -87,9 +88,10 @@ public: MSGS *messages; /* Daemon message handler */ utime_t heartbeat_interval; /* Interval to send hb to FD */ utime_t client_wait; /* Time to wait for FD to connect */ - int tls_enable; /* Enable TLS */ - int tls_require; /* Require TLS */ - int tls_verify_peer; /* TLS Verify Client Certificate */ + bool tls_authenticate; /* Authenticate with TLS */ + bool tls_enable; /* Enable TLS */ + bool tls_require; /* Require TLS */ + bool tls_verify_peer; /* TLS Verify Client Certificate */ char *tls_ca_certfile; /* TLS CA Certificate File */ char *tls_ca_certdir; /* TLS CA Certificate Directory */ char *tls_certfile; /* TLS Server Certificate File */ diff --git a/bacula/technotes-2.3 b/bacula/technotes-2.3 index 86a6c54da1..b12efcb1ec 100644 --- a/bacula/technotes-2.3 +++ b/bacula/technotes-2.3 @@ -1,6 +1,10 @@ Technical notes on version 2.3 General: +11Dec07 +kes Implement a security enhancement: TLS authentication but no + encryption. Enabled by setting 'TLS Authentication = yes'. + Note when this is on, TLS encryption is turned OFF! 10Dec07 kes This patch corrects a problem where the maximum concurrent storage jobs counter gets out of sync during restore jobs causing jobs to -- 2.39.5