]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/lib/tls.c
Check for job_canceled() in fd_plugin code
[bacula/bacula] / bacula / src / lib / tls.c
index 1e5d187e38fa60f433b55206802169e64f2e4ed8..f5f0623a3cd1bebbf598c3e068bc08d5ac00180c 100644 (file)
@@ -1,3 +1,30 @@
+/*
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2005-2008 Free Software Foundation Europe e.V.
+
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation and included
+   in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of Kern Sibbald.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+   Switzerland, email:ftf@fsfeurope.org.
+*/
 /*
  * tls.c TLS support functions
  *
@@ -5,8 +32,6 @@
  *
  * Version $Id$
  *
- * Copyright (C) 2005 Kern Sibbald
- *
  * This file was contributed to the Bacula project by Landon Fuller
  * and Three Rings Design, Inc.
  *
  * under an alternate open source license please contact
  * Landon Fuller <landonf@threerings.net>.
  */
-/*  
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-  
-   This library 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
-   Lesser General Public License for more details.
-  
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
-   MA 02111-1307, USA.
- */
 
 
 #include "bacula.h"
 #include <assert.h>
 
-extern time_t watchdog_time;
 
 #ifdef HAVE_TLS /* Is TLS enabled? */
 
@@ -51,42 +59,19 @@ extern time_t watchdog_time;
 /* No anonymous ciphers, no <128 bit ciphers, no export ciphers, no MD5 ciphers */
 #define TLS_DEFAULT_CIPHERS "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"
 
-/* Array of mutexes for use with OpenSSL static locking */
-static pthread_mutex_t *mutexes;
-
-/* OpenSSL dynamic locking structure */
-struct CRYPTO_dynlock_value {
-   pthread_mutex_t mutex;
-};
-
-/* Are we initialized? */
-static int tls_initialized = false;
-
 /* TLS Context Structure */
 struct TLS_Context {
    SSL_CTX *openssl;
-   TLS_PEM_PASSWD_CB *pem_callback;
+   CRYPTO_PEM_PASSWD_CB *pem_callback;
    const void *pem_userdata;
+   bool tls_enable;
+   bool tls_require;
 };
 
 struct TLS_Connection {
    SSL *openssl;
 };
 
-/* post all per-thread openssl errors */
-static void openssl_post_errors(int code, const char *errstring)
-{
-   char buf[512];
-   unsigned long sslerr;
-
-   /* Pop errors off of the per-thread queue */
-   while((sslerr = ERR_get_error()) != 0) {
-      /* Acquire the human readable string */
-      ERR_error_string_n(sslerr, (char *) &buf, sizeof(buf));
-      Emsg2(M_ERROR, 0, "%s: ERR=%s\n", errstring, buf);
-   }
-}
-
 /*
  * OpenSSL certificate verification callback.
  * OpenSSL has already performed internal certificate verification.
@@ -94,7 +79,6 @@ static void openssl_post_errors(int code, const char *errstring)
  */
 static int openssl_verify_peer(int ok, X509_STORE_CTX *store)
 {
-
    if (!ok) {
       X509 *cert = X509_STORE_CTX_get_current_cert(store);
       int depth = X509_STORE_CTX_get_error_depth(store);
@@ -105,29 +89,19 @@ static int openssl_verify_peer(int ok, X509_STORE_CTX *store)
       X509_NAME_oneline(X509_get_issuer_name(cert), issuer, 256);
       X509_NAME_oneline(X509_get_subject_name(cert), subject, 256);
 
-      Emsg5(M_ERROR, 0, _("Error with certificate at depth: %d, issuer = %s,"
-                         " subject = %s, ERR=%d:%s\n"), depth, issuer,
-                         subject, err, X509_verify_cert_error_string(err));
+      Jmsg5(NULL, M_ERROR, 0, _("Error with certificate at depth: %d, issuer = %s,"
+            " subject = %s, ERR=%d:%s\n"), depth, issuer,
+              subject, err, X509_verify_cert_error_string(err));
 
    }
 
    return ok;
 }
 
-/*
- * Default PEM encryption passphrase callback.
- * Returns an empty password.
- */
-static int tls_default_pem_callback(char *buf, int size, const void *userdata)
-{
-   bstrncpy(buf, "", size);
-   return (strlen(buf));
-}
-
 /* Dispatch user PEM encryption callbacks */
-static int openssl_pem_callback_dispatch (char *buf, int size, int rwflag, void *userdata)
+static int tls_pem_callback_dispatch (char *buf, int size, int rwflag, void *userdata)
 {
-   TLS_CONTEXT *ctx = (TLS_CONTEXT *) userdata;
+   TLS_CONTEXT *ctx = (TLS_CONTEXT *)userdata;
    return (ctx->pem_callback(buf, size, ctx->pem_userdata));
 }
 
@@ -138,15 +112,15 @@ static int openssl_pem_callback_dispatch (char *buf, int size, int rwflag, void
  */
 TLS_CONTEXT *new_tls_context(const char *ca_certfile, const char *ca_certdir,
                              const char *certfile, const char *keyfile,
-                            TLS_PEM_PASSWD_CB *pem_callback,
-                            const void *pem_userdata, const char *dhfile,
-                            bool verify_peer)
+                             CRYPTO_PEM_PASSWD_CB *pem_callback,
+                             const void *pem_userdata, const char *dhfile,
+                             bool verify_peer)
 {
    TLS_CONTEXT *ctx;
    BIO *bio;
    DH *dh;
 
-   ctx = (TLS_CONTEXT *) malloc(sizeof(TLS_CONTEXT));
+   ctx = (TLS_CONTEXT *)malloc(sizeof(TLS_CONTEXT));
 
    /* Allocate our OpenSSL TLSv1 Context */
    ctx->openssl = SSL_CTX_new(TLSv1_method());
@@ -161,10 +135,10 @@ TLS_CONTEXT *new_tls_context(const char *ca_certfile, const char *ca_certdir,
       ctx->pem_callback = pem_callback;
       ctx->pem_userdata = pem_userdata;
    } else {
-      ctx->pem_callback = tls_default_pem_callback;
+      ctx->pem_callback = crypto_default_pem_callback;
       ctx->pem_userdata = NULL;
    }
-   SSL_CTX_set_default_passwd_cb(ctx->openssl, openssl_pem_callback_dispatch);
+   SSL_CTX_set_default_passwd_cb(ctx->openssl, tls_pem_callback_dispatch);
    SSL_CTX_set_default_passwd_cb_userdata(ctx->openssl, (void *) ctx);
 
    /*
@@ -173,12 +147,12 @@ TLS_CONTEXT *new_tls_context(const char *ca_certfile, const char *ca_certdir,
     */
    if (ca_certfile || ca_certdir) {
       if (!SSL_CTX_load_verify_locations(ctx->openssl, ca_certfile, ca_certdir)) {
-        openssl_post_errors(M_ERROR, _("Error loading certificate verification stores"));
-        goto err;
+         openssl_post_errors(M_ERROR, _("Error loading certificate verification stores"));
+         goto err;
       }
    } else if (verify_peer) {
       /* At least one CA is required for peer verification */
-      Emsg0(M_ERROR, 0, _("Either a certificate file or a directory must be"
+      Jmsg0(NULL, M_ERROR, 0, _("Either a certificate file or a directory must be"
                          " specified as a verification store\n"));
       goto err;
    }
@@ -189,51 +163,52 @@ TLS_CONTEXT *new_tls_context(const char *ca_certfile, const char *ca_certdir,
     */
    if (certfile) {
       if (!SSL_CTX_use_certificate_chain_file(ctx->openssl, certfile)) {
-        openssl_post_errors(M_ERROR, _("Error loading certificate file"));
-        goto err;
+         openssl_post_errors(M_ERROR, _("Error loading certificate file"));
+         goto err;
       }
    }
 
    /* Load our private key. */
    if (keyfile) {
       if (!SSL_CTX_use_PrivateKey_file(ctx->openssl, keyfile, SSL_FILETYPE_PEM)) {
-        openssl_post_errors(M_ERROR, _("Error loading private key"));
-        goto err;
+         openssl_post_errors(M_ERROR, _("Error loading private key"));
+         goto err;
       }
    }
 
    /* Load Diffie-Hellman Parameters. */
    if (dhfile) {
       if (!(bio = BIO_new_file(dhfile, "r"))) {
-        openssl_post_errors(M_ERROR, _("Unable to open DH parameters file"));
-        goto err;
+         openssl_post_errors(M_ERROR, _("Unable to open DH parameters file"));
+         goto err;
       }
       dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
       BIO_free(bio);
       if (!dh) {
-        openssl_post_errors(M_ERROR, _("Unable to load DH parameters from specified file"));
-        goto err;
+         openssl_post_errors(M_ERROR, _("Unable to load DH parameters from specified file"));
+         goto err;
       }
       if (!SSL_CTX_set_tmp_dh(ctx->openssl, dh)) {
-        openssl_post_errors(M_ERROR, _("Failed to set TLS Diffie-Hellman parameters"));
-        DH_free(dh);
-        goto err;
+         openssl_post_errors(M_ERROR, _("Failed to set TLS Diffie-Hellman parameters"));
+         DH_free(dh);
+         goto err;
       }
       /* Enable Single-Use DH for Ephemeral Keying */
       SSL_CTX_set_options(ctx->openssl, SSL_OP_SINGLE_DH_USE);
    }
 
    if (SSL_CTX_set_cipher_list(ctx->openssl, TLS_DEFAULT_CIPHERS) != 1) {
-      Emsg0(M_ERROR, 0, _("Error setting cipher list, no valid ciphers available\n"));
+      Jmsg0(NULL, M_ERROR, 0,
+             _("Error setting cipher list, no valid ciphers available\n"));
       goto err;
    }
 
    /* Verify Peer Certificate */
    if (verify_peer) {
-          /* SSL_VERIFY_FAIL_IF_NO_PEER_CERT has no effect in client mode */
-          SSL_CTX_set_verify(ctx->openssl,
-                             SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
-                             openssl_verify_peer);
+      /* SSL_VERIFY_FAIL_IF_NO_PEER_CERT has no effect in client mode */
+      SSL_CTX_set_verify(ctx->openssl,
+                         SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+                         openssl_verify_peer);
    }
 
    return ctx;
@@ -256,38 +231,49 @@ void free_tls_context(TLS_CONTEXT *ctx)
    free(ctx);
 }
 
+bool get_tls_require(TLS_CONTEXT *ctx) 
+{
+   return ctx->tls_require;
+}
+
+bool get_tls_enable(TLS_CONTEXT *ctx) 
+{
+   return ctx->tls_enable;
+}
+
+
 /*
  * Verifies a list of common names against the certificate
  * commonName attribute.
  *  Returns: true on success
  *           false on failure
  */
-bool tls_postconnect_verify_cn(TLS_CONNECTION *tls, alist *verify_list)
+bool tls_postconnect_verify_cn(JCR *jcr, TLS_CONNECTION *tls, alist *verify_list)
 {
    SSL *ssl = tls->openssl;
    X509 *cert;
    X509_NAME *subject;
-   int auth_success = false;
+   bool auth_success = false;
    char data[256];
 
    /* Check if peer provided a certificate */
    if (!(cert = SSL_get_peer_certificate(ssl))) {
-      Emsg0(M_ERROR, 0, _("Peer failed to present a TLS certificate\n"));
+      Qmsg0(jcr, M_ERROR, 0, _("Peer failed to present a TLS certificate\n"));
       return false;
    }
 
    if ((subject = X509_get_subject_name(cert)) != NULL) {
       if (X509_NAME_get_text_by_NID(subject, NID_commonName, data, sizeof(data)) > 0) {
-        char *cn;
-        /* NULL terminate data */
-        data[255] = 0;
-
-        /* Try all the CNs in the list */
-        foreach_alist(cn, verify_list) {
-           if (strcasecmp(data, cn) == 0) {
-              auth_success = true;
-           }
-        }
+         char *cn;
+         /* NULL terminate data */
+         data[255] = 0;
+
+         /* Try all the CNs in the list */
+         foreach_alist(cn, verify_list) {
+            if (strcasecmp(data, cn) == 0) {
+               auth_success = true;
+            }
+         }
       }
    }
 
@@ -301,12 +287,12 @@ bool tls_postconnect_verify_cn(TLS_CONNECTION *tls, alist *verify_list)
  *  Returns: true on success
  *           false on failure
  */
-bool tls_postconnect_verify_host(TLS_CONNECTION *tls, const char *host)
+bool tls_postconnect_verify_host(JCR *jcr, TLS_CONNECTION *tls, const char *host)
 {
    SSL *ssl = tls->openssl;
    X509 *cert;
    X509_NAME *subject;
-   int auth_success = false;
+   bool auth_success = false;
    int extensions;
    char data[256];
    int i, j;
@@ -314,82 +300,86 @@ bool tls_postconnect_verify_host(TLS_CONNECTION *tls, const char *host)
 
    /* Check if peer provided a certificate */
    if (!(cert = SSL_get_peer_certificate(ssl))) {
-      Emsg1(M_ERROR, 0, _("Peer %s failed to present a TLS certificate\n"), host);
+      Qmsg1(jcr, M_ERROR, 0, 
+            _("Peer %s failed to present a TLS certificate\n"), host);
       return false;
    }
 
    /* Check subjectAltName extensions first */
    if ((extensions = X509_get_ext_count(cert)) > 0) {
       for (i = 0; i < extensions; i++) {
-        X509_EXTENSION *ext;
-        const char *extname;
-
-        ext = X509_get_ext(cert, i);
-        extname = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
-
-        if (strcmp(extname, "subjectAltName") == 0) {
-           X509V3_EXT_METHOD *method;
-           STACK_OF(CONF_VALUE) *val;
-           CONF_VALUE *nval;
-           unsigned char *data;
-           void *extstr = NULL;
+         X509_EXTENSION *ext;
+         const char *extname;
+
+         ext = X509_get_ext(cert, i);
+         extname = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
+
+         if (strcmp(extname, "subjectAltName") == 0) {
+            X509V3_EXT_METHOD *method;
+            STACK_OF(CONF_VALUE) *val;
+            CONF_VALUE *nval;
+            void *extstr = NULL;
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800FL)
+            const unsigned char *ext_value_data;
+#else
+            unsigned char *ext_value_data;
+#endif
 
             /* Get x509 extension method structure */
-           if (!(method = X509V3_EXT_get(ext))) {
-              break;
-           }
+            if (!(method = X509V3_EXT_get(ext))) {
+               break;
+            }
 
-           data = ext->value->data;
+            ext_value_data = ext->value->data;
 
 #if (OPENSSL_VERSION_NUMBER > 0x00907000L)
-           if (method->it) {
-              /* New style ASN1 */
+            if (method->it) {
+               /* New style ASN1 */
 
-              /* Decode ASN1 item in data */
-              extstr = ASN1_item_d2i(NULL, &data, ext->value->length,
-                                     ASN1_ITEM_ptr(method->it));
-           } else {
-              /* Old style ASN1 */
+               /* Decode ASN1 item in data */
+               extstr = ASN1_item_d2i(NULL, &ext_value_data, ext->value->length,
+                                      ASN1_ITEM_ptr(method->it));
+            } else {
+               /* Old style ASN1 */
 
-              /* Decode ASN1 item in data */
-              extstr = method->d2i(NULL, &data, ext->value->length);
-           }
+               /* Decode ASN1 item in data */
+               extstr = method->d2i(NULL, &ext_value_data, ext->value->length);
+            }
 
 #else
-           extstr = method->d2i(NULL, &data, ext->value->length);
+            extstr = method->d2i(NULL, &ext_value_data, ext->value->length);
 #endif
 
-           /* Iterate through to find the dNSName field(s) */
-           val = method->i2v(method, extstr, NULL);
-
-           /* dNSName shortname is "DNS" */
-           for (j = 0; j < sk_CONF_VALUE_num(val); j++) {
-              nval = sk_CONF_VALUE_value(val, j);
-              if (strcmp(nval->name, "DNS") == 0) {
-                 if (strcasecmp(nval->name, host) == 0) {
-                    auth_success = true;
-                    goto success;
-                 }
-              }
-           }
-        }
+            /* Iterate through to find the dNSName field(s) */
+            val = method->i2v(method, extstr, NULL);
+
+            /* dNSName shortname is "DNS" */
+            for (j = 0; j < sk_CONF_VALUE_num(val); j++) {
+               nval = sk_CONF_VALUE_value(val, j);
+               if (strcmp(nval->name, "DNS") == 0) {
+                  if (strcasecmp(nval->value, host) == 0) {
+                     auth_success = true;
+                     goto success;
+                  }
+               }
+            }
+         }
       }
    }
 
    /* Try verifying against the subject name */
    if (!auth_success) {
       if ((subject = X509_get_subject_name(cert)) != NULL) {
-        if (X509_NAME_get_text_by_NID(subject, NID_commonName, data, sizeof(data)) > 0) {
-           /* NULL terminate data */
-           data[255] = 0;
-           if (strcasecmp(data, host) == 0) {
-              auth_success = true;
-           }
-        }
+         if (X509_NAME_get_text_by_NID(subject, NID_commonName, data, sizeof(data)) > 0) {
+            /* NULL terminate data */
+            data[255] = 0;
+            if (strcasecmp(data, host) == 0) {
+               auth_success = true;
+            }
+         }
       }
    }
 
-
 success:
    X509_free(cert);
 
@@ -402,7 +392,7 @@ success:
  * Returns: Pointer to TLS_CONNECTION instance on success
  *          NULL on failure;
  */
-TLS_CONNECTION *new_tls_connection (TLS_CONTEXT *ctx, int fd)
+TLS_CONNECTION *new_tls_connection(TLS_CONTEXT *ctx, int fd)
 {
    BIO *bio;
 
@@ -413,18 +403,18 @@ TLS_CONNECTION *new_tls_connection (TLS_CONTEXT *ctx, int fd)
    bio = BIO_new(BIO_s_socket());
    if (!bio) {
       /* Not likely, but never say never */
-      openssl_post_errors(M_ERROR, "Error creating file descriptor-based BIO");
+      openssl_post_errors(M_ERROR, _("Error creating file descriptor-based BIO"));
       return NULL; /* Nothing allocated, nothing to clean up */
    }
    BIO_set_fd(bio, fd, BIO_NOCLOSE);
 
    /* Allocate our new tls connection */
-   TLS_CONNECTION *tls = (TLS_CONNECTION *) malloc(sizeof(TLS_CONNECTION));
+   TLS_CONNECTION *tls = (TLS_CONNECTION *)malloc(sizeof(TLS_CONNECTION));
 
    /* Create the SSL object and attach the socket BIO */
    if ((tls->openssl = SSL_new(ctx->openssl)) == NULL) {
       /* Not likely, but never say never */
-      openssl_post_errors(M_ERROR, "Error creating new SSL object");
+      openssl_post_errors(M_ERROR, _("Error creating new SSL object"));
       goto err;
    }
 
@@ -433,21 +423,20 @@ TLS_CONNECTION *new_tls_connection (TLS_CONTEXT *ctx, int fd)
    /* Non-blocking partial writes */
    SSL_set_mode(tls->openssl, SSL_MODE_ENABLE_PARTIAL_WRITE|SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
 
-   return (tls);
+   return tls;
 
 err:
    /* Clean up */
    BIO_free(bio);
    SSL_free(tls->openssl);
    free(tls);
-
    return NULL;
 }
 
 /*
  * Free TLS_CONNECTION instance
  */
-void free_tls_connection (TLS_CONNECTION *tls)
+void free_tls_connection(TLS_CONNECTION *tls)
 {
    SSL_free(tls->openssl);
    free(tls);
@@ -465,61 +454,65 @@ static inline bool openssl_bsock_session_start(BSOCK *bsock, bool server)
 
    /* Zero the fdset, we'll set our fd prior to each invocation of select() */
    FD_ZERO(&fdset);
-   tv.tv_sec = 10;
-   tv.tv_usec = 0;
-   fdmax = bsock->fd + 1;
+   fdmax = bsock->m_fd + 1;
 
    /* Ensure that socket is non-blocking */
-   flags = bnet_set_nonblocking(bsock);
+   flags = bsock->set_nonblocking();
 
    /* start timer */
    bsock->timer_start = watchdog_time;
-   bsock->timed_out = 0;
+   bsock->clear_timed_out();
 
    for (;;) { 
       if (server) {
-        err = SSL_accept(tls->openssl);
+         err = SSL_accept(tls->openssl);
       } else {
-        err = SSL_connect(tls->openssl);
+         err = SSL_connect(tls->openssl);
       }
 
       /* Handle errors */
       switch (SSL_get_error(tls->openssl, err)) {
-          case SSL_ERROR_NONE:
-             stat = true;
-             goto cleanup;
-          case SSL_ERROR_ZERO_RETURN:
-             /* TLS connection was cleanly shut down */
-             openssl_post_errors(M_ERROR, "Connect failure");
-             stat = false;
-             goto cleanup;
-          case SSL_ERROR_WANT_READ:
-             /* If we timeout of a select, this will be unset */
-             FD_SET((unsigned) bsock->fd, &fdset);
-             /* Block until we can read */
-             select(fdmax, &fdset, NULL, &fdset, &tv);
-             break;
-          case SSL_ERROR_WANT_WRITE:
-             /* If we timeout of a select, this will be unset */
-             FD_SET((unsigned) bsock->fd, &fdset);
-             /* Block until we can write */
-             select(fdmax, NULL, &fdset, &fdset, &tv);
-             break;
-          default:
-             /* Socket Error Occured */
-             openssl_post_errors(M_ERROR, "Connect failure");
-             stat = false;
-             goto cleanup;
+      case SSL_ERROR_NONE:
+         stat = true;
+         goto cleanup;
+      case SSL_ERROR_ZERO_RETURN:
+         /* TLS connection was cleanly shut down */
+         openssl_post_errors(M_ERROR, _("Connect failure"));
+         stat = false;
+         goto cleanup;
+      case SSL_ERROR_WANT_READ:
+         /* If we timeout of a select, this will be unset */
+         FD_SET((unsigned) bsock->m_fd, &fdset);
+         /* Set our timeout */
+         tv.tv_sec = 10;
+         tv.tv_usec = 0;
+         /* Block until we can read */
+         select(fdmax, &fdset, NULL, NULL, &tv);
+         break;
+      case SSL_ERROR_WANT_WRITE:
+         /* If we timeout of a select, this will be unset */
+         FD_SET((unsigned) bsock->m_fd, &fdset);
+         /* Set our timeout */
+         tv.tv_sec = 10;
+         tv.tv_usec = 0;
+         /* Block until we can write */
+         select(fdmax, NULL, &fdset, NULL, &tv);
+         break;
+      default:
+         /* Socket Error Occurred */
+         openssl_post_errors(M_ERROR, _("Connect failure"));
+         stat = false;
+         goto cleanup;
       }
 
-      if (bsock->timed_out) {
-        goto cleanup;
+      if (bsock->is_timed_out()) {
+         goto cleanup;
       }
    }
 
 cleanup:
    /* Restore saved flags */
-   bnet_restore_blocking(bsock, flags);
+   bsock->restore_blocking(flags);
    /* Clear timer */
    bsock->timer_start = 0;
 
@@ -534,7 +527,7 @@ cleanup:
 bool tls_bsock_connect(BSOCK *bsock)
 {
    /* SSL_connect(bsock->tls) */
-   return (openssl_bsock_session_start(bsock, false));
+   return openssl_bsock_session_start(bsock, false);
 }
 
 /*
@@ -545,55 +538,47 @@ bool tls_bsock_connect(BSOCK *bsock)
 bool tls_bsock_accept(BSOCK *bsock)
 {
    /* SSL_accept(bsock->tls) */
-   return (openssl_bsock_session_start(bsock, true));
+   return openssl_bsock_session_start(bsock, true);
 }
 
 /*
  * Shutdown TLS_CONNECTION instance
  */
-void tls_bsock_shutdown (BSOCK *bsock)
+void tls_bsock_shutdown(BSOCK *bsock)
 {
    /*
     * SSL_shutdown must be called twice to fully complete the process -
     * The first time to initiate the shutdown handshake, and the second to
     * receive the peer's reply.
     *
-    * However, it is valid to close the SSL connection after the initial
-    * shutdown notification is sent to the peer, without waiting for the
-    * peer's reply, as long as you do not plan to re-use that particular
-    * SSL connection object.
-    *
-    * Because we do not re-use SSL connection objects, I do not bother
-    * calling SSL_shutdown a second time.
-    *
     * In addition, if the underlying socket is blocking, SSL_shutdown()
     * will not return until the current stage of the shutdown process has
     * completed or an error has occured. By setting the socket blocking
     * we can avoid the ugly for()/switch()/select() loop.
     */
    int err;
-   int flags;
 
    /* Set socket blocking for shutdown */
-   flags = bnet_set_blocking(bsock);
+   bsock->set_blocking();
 
    err = SSL_shutdown(bsock->tls->openssl);
+   if (err == 0) {
+      /* Complete shutdown */
+      err = SSL_shutdown(bsock->tls->openssl);
+   }
 
    switch (SSL_get_error(bsock->tls->openssl, err)) {
-      case SSL_ERROR_NONE:
-        break;
-      case SSL_ERROR_ZERO_RETURN:
-        /* TLS connection was shut down on us via a TLS protocol-level closure */
-        openssl_post_errors(M_ERROR, _("TLS shutdown failure."));
-        break;
-      default:
-        /* Socket Error Occured */
-        openssl_post_errors(M_ERROR, _("TLS shutdown failure."));
-        break;
+   case SSL_ERROR_NONE:
+      break;
+   case SSL_ERROR_ZERO_RETURN:
+      /* TLS connection was shut down on us via a TLS protocol-level closure */
+      openssl_post_errors(M_ERROR, _("TLS shutdown failure."));
+      break;
+   default:
+      /* Socket Error Occurred */
+      openssl_post_errors(M_ERROR, _("TLS shutdown failure."));
+      break;
    }
-
-   /* Restore saved flags */
-   bnet_restore_blocking(bsock, flags);
 }
 
 /* Does all the manual labor for tls_bsock_readn() and tls_bsock_writen() */
@@ -608,319 +593,124 @@ static inline int openssl_bsock_readwrite(BSOCK *bsock, char *ptr, int nbytes, b
 
    /* Zero the fdset, we'll set our fd prior to each invocation of select() */
    FD_ZERO(&fdset);
-   tv.tv_sec = 10;
-   tv.tv_usec = 0;
-   fdmax = bsock->fd + 1;
+   fdmax = bsock->m_fd + 1;
 
    /* Ensure that socket is non-blocking */
-   flags = bnet_set_nonblocking(bsock);
+   flags = bsock->set_nonblocking();
 
    /* start timer */
    bsock->timer_start = watchdog_time;
-   bsock->timed_out = 0;
+   bsock->clear_timed_out();
 
    nleft = nbytes;
 
    while (nleft > 0) { 
-
       if (write) {
-        nwritten = SSL_write(tls->openssl, ptr, nleft);
+         nwritten = SSL_write(tls->openssl, ptr, nleft);
       } else {
-        nwritten = SSL_read(tls->openssl, ptr, nleft);
+         nwritten = SSL_read(tls->openssl, ptr, nleft);
       }
 
       /* Handle errors */
       switch (SSL_get_error(tls->openssl, nwritten)) {
-        case SSL_ERROR_NONE:
-           nleft -= nwritten;
-           if (nleft) {
-              ptr += nwritten;
-           }
-           break;
-        case SSL_ERROR_ZERO_RETURN:
-           /* TLS connection was cleanly shut down */
-           openssl_post_errors(M_ERROR, _("TLS read/write failure."));
-           goto cleanup;
-        case SSL_ERROR_WANT_READ:
-           /* If we timeout of a select, this will be unset */
-           FD_SET((unsigned) bsock->fd, &fdset);
-           /* Block until we can read */
-           select(fdmax, &fdset, NULL, &fdset, &tv);
-           break;
-        case SSL_ERROR_WANT_WRITE:
-           /* If we timeout of a select, this will be unset */
-           FD_SET((unsigned) bsock->fd, &fdset);
-           /* Block until we can write */
-           select(fdmax, NULL, &fdset, &fdset, &tv);
-           break;
-        default:
-           /* Socket Error Occured */
-           openssl_post_errors(M_ERROR, _("TLS read/write failure."));
-           goto cleanup;
+      case SSL_ERROR_NONE:
+         nleft -= nwritten;
+         if (nleft) {
+            ptr += nwritten;
+         }
+         break;
+
+      case SSL_ERROR_WANT_READ:
+         /* If we timeout on a select, this will be unset */
+         FD_SET((unsigned)bsock->m_fd, &fdset);
+         tv.tv_sec = 10;
+         tv.tv_usec = 0;
+         /* Block until we can read */
+         select(fdmax, &fdset, NULL, NULL, &tv);
+         break;
+
+      case SSL_ERROR_WANT_WRITE:
+         /* If we timeout on a select, this will be unset */
+         FD_SET((unsigned)bsock->m_fd, &fdset);
+         tv.tv_sec = 10;
+         tv.tv_usec = 0;
+         /* Block until we can write */
+         select(fdmax, NULL, &fdset, NULL, &tv);
+         break;
+
+      case SSL_ERROR_ZERO_RETURN:
+         /* TLS connection was cleanly shut down */
+         /* Fall through wanted */
+      default:
+         /* Socket Error Occured */
+         openssl_post_errors(M_ERROR, _("TLS read/write failure."));
+         goto cleanup;
       }
 
       /* Everything done? */
       if (nleft == 0) {
-        goto cleanup;
+         goto cleanup;
       }
 
       /* Timeout/Termination, let's take what we can get */
-      if (bsock->timed_out || bsock->terminated) {
-        goto cleanup;
+      if (bsock->is_timed_out() || bsock->is_terminated()) {
+         goto cleanup;
       }
    }
 
 cleanup:
    /* Restore saved flags */
-   bnet_restore_blocking(bsock, flags);
+   bsock->restore_blocking(flags);
 
    /* Clear timer */
    bsock->timer_start = 0;
-
    return nbytes - nleft;
 }
 
 
-int tls_bsock_writen(BSOCK *bsock, char *ptr, int32_t nbytes) {
-   /* SSL_write(bsock->tls->openssl, ptr, nbytes) */
-   return (openssl_bsock_readwrite(bsock, ptr, nbytes, true));
-}
-
-int tls_bsock_readn(BSOCK *bsock, char *ptr, int32_t nbytes) {
-   /* SSL_read(bsock->tls->openssl, ptr, nbytes) */
-   return (openssl_bsock_readwrite(bsock, ptr, nbytes, false));
-}
-
-/*
- * Return an OpenSSL thread ID
- *  Returns: thread ID
- *
- */
-static unsigned long get_openssl_thread_id (void)
-{
-   /* Comparison without use of pthread_equal() is mandated by the OpenSSL API */
-   return ((unsigned long) pthread_self());
-}
-
-/*
- * Allocate a dynamic OpenSSL mutex
- */
-static struct CRYPTO_dynlock_value *openssl_create_dynamic_mutex (const char *file, int line)
-{
-   struct CRYPTO_dynlock_value *dynlock;
-   int stat;
-
-   dynlock = (struct CRYPTO_dynlock_value *) malloc(sizeof(struct CRYPTO_dynlock_value));
-
-   if ((stat = pthread_mutex_init(&dynlock->mutex, NULL)) != 0) {
-      Emsg1(M_ABORT, 0, "Unable to init mutex: ERR=%s\n", strerror(stat));
-   }
-
-   return dynlock;
-}
-
-static void openssl_update_dynamic_mutex (int mode, struct CRYPTO_dynlock_value *dynlock, const char *file, int line)
-{
-   if (mode & CRYPTO_LOCK) {
-      P(dynlock->mutex);
-   } else {
-      V(dynlock->mutex);
-   }
-}
-
-static void openssl_destroy_dynamic_mutex (struct CRYPTO_dynlock_value *dynlock, const char *file, int line)
+int tls_bsock_writen(BSOCK *bsock, char *ptr, int32_t nbytes) 
 {
-   int stat;
-
-   if ((stat = pthread_mutex_destroy(&dynlock->mutex)) != 0) {
-      Emsg1(M_ABORT, 0, "Unable to destroy mutex: ERR=%s\n", strerror(stat));
-   }
-
-   free(dynlock);
+   /* SSL_write(bsock->tls->openssl, ptr, nbytes) */
+   return openssl_bsock_readwrite(bsock, ptr, nbytes, true);
 }
 
-/*
- * (Un)Lock a static OpenSSL mutex
- */
-static void openssl_update_static_mutex (int mode, int i, const char *file, int line)
+int tls_bsock_readn(BSOCK *bsock, char *ptr, int32_t nbytes) 
 {
-   if (mode & CRYPTO_LOCK) {
-      P(mutexes[i]);
-   } else {
-      V(mutexes[i]);
-   }
+   /* SSL_read(bsock->tls->openssl, ptr, nbytes) */
+   return openssl_bsock_readwrite(bsock, ptr, nbytes, false);
 }
 
-/*
- * Initialize OpenSSL thread support
- *  Returns: 0 on success
- *           errno on failure
- */
-static int openssl_init_threads (void)
-{
-   int i, numlocks;
-   int stat;
-
-
-   /* Set thread ID callback */
-   CRYPTO_set_id_callback(get_openssl_thread_id);
-
-   /* Initialize static locking */
-   numlocks = CRYPTO_num_locks();
-   mutexes = (pthread_mutex_t *) malloc(numlocks * sizeof(pthread_mutex_t));
-   for (i = 0; i < numlocks; i++) {
-      if ((stat = pthread_mutex_init(&mutexes[i], NULL)) != 0) {
-        Emsg1(M_ERROR, 0, "Unable to init mutex: ERR=%s\n", strerror(stat));
-        return stat;
-      }
-   }
+#else /* HAVE_OPENSSL */
+# error No TLS implementation available.
+#endif /* !HAVE_OPENSSL */
 
-   /* Set static locking callback */
-   CRYPTO_set_locking_callback(openssl_update_static_mutex);
 
-   /* Initialize dyanmic locking */
-   CRYPTO_set_dynlock_create_callback(openssl_create_dynamic_mutex);
-   CRYPTO_set_dynlock_lock_callback(openssl_update_dynamic_mutex);
-   CRYPTO_set_dynlock_destroy_callback(openssl_destroy_dynamic_mutex);
+#else     /* TLS NOT enabled, dummy routines substituted */
 
-   return 0;
-}
 
-/*
- * Clean up OpenSSL threading support
- */
-static void openssl_cleanup_threads (void)
+/* Dummy routines */
+TLS_CONTEXT *new_tls_context(const char *ca_certfile, const char *ca_certdir,
+                             const char *certfile, const char *keyfile,
+                             CRYPTO_PEM_PASSWD_CB *pem_callback,
+                             const void *pem_userdata, const char *dhfile,
+                             bool verify_peer)
 {
-   int i, numlocks;
-   int stat;
-
-   /* Unset thread ID callback */
-   CRYPTO_set_id_callback(NULL);
-  
-   /* Deallocate static lock mutexes */
-   numlocks = CRYPTO_num_locks();
-   for (i = 0; i < numlocks; i++) {
-      if ((stat = pthread_mutex_destroy(&mutexes[i])) != 0) {
-        /* We don't halt execution, reporting the error should be sufficient */
-        Emsg1(M_ERROR, 0, "Unable to destroy mutex: ERR=%s\n", strerror(stat));
-      }
-   }
-
-   /* Unset static locking callback */
-   CRYPTO_set_locking_callback(NULL);
-
-   /* Free static lock array */
-   free(mutexes);
-
-   /* Unset dynamic locking callbacks */
-   CRYPTO_set_dynlock_create_callback(NULL);
-   CRYPTO_set_dynlock_lock_callback(NULL);
-   CRYPTO_set_dynlock_destroy_callback(NULL);
+   return NULL;
 }
+void free_tls_context(TLS_CONTEXT *ctx) { }
 
+void tls_bsock_shutdown(BSOCK *bsock) { }
 
-/*
- * Seed TLS PRNG
- *  Returns: 1 on success
- *           0 on failure
- */
-static int seed_tls_prng (void)
-{
-   const char *names[]  = { "/dev/urandom", "/dev/random", NULL };
-   int i;
-
-   // ***FIXME***
-   // Win32 Support
-   // Read saved entropy?
-
-   for (i = 0; names[i]; i++) {
-      if (RAND_load_file(names[i], 1024) != -1) {
-        /* Success */
-        return 1;
-      }
-   }
-
-   /* Fail */
-   return 0;
-}
-
-/*
- * Save TLS Entropy
- *  Returns: 1 on success
- *           0 on failure
- */
-static int save_tls_prng (void)
-{
-   // ***FIXME***
-   // Implement PRNG state save
-   return 1;
-}
+void free_tls_connection(TLS_CONNECTION *tls) { }
 
-/*
- * Perform global initialization of TLS
- * This function is not thread safe.
- *  Returns: 0 on success
- *           errno on failure
- */
-int init_tls (void)
+bool get_tls_require(TLS_CONTEXT *ctx) 
 {
-   int stat;
-
-   if ((stat = openssl_init_threads()) != 0) {
-      Emsg1(M_ABORT, 0, "Unable to init OpenSSL threading: ERR=%s\n", strerror(stat));
-   }
-
-   /* Load libssl and libcrypto human-readable error strings */
-   SSL_load_error_strings();
-
-   /* Register OpenSSL ciphers */
-   SSL_library_init();
-
-   if (!seed_tls_prng()) {
-      Emsg0(M_ERROR_TERM, 0, _("Failed to seed OpenSSL PRNG\n"));
-   }
-
-   tls_initialized = true;
-
-   return stat;
+   return false;
 }
 
-/*
- * Perform global cleanup of TLS
- * All TLS connections must be closed before calling this function.
- * This function is not thread safe.
- *  Returns: 0 on success
- *           errno on failure
- */
-int cleanup_tls (void)
+bool get_tls_enable(TLS_CONTEXT *ctx) 
 {
-   /*
-    * Ensure that we've actually been initialized; Doing this here decreases the
-    * complexity of client's termination/cleanup code.
-    */
-   if (!tls_initialized) {
-      return 0;
-   }
-
-   if (!save_tls_prng()) {
-      Emsg0(M_ERROR, 0, _("Failed to save OpenSSL PRNG\n"));
-   }
-
-   openssl_cleanup_threads();
-
-   /* Free libssl and libcrypto error strings */
-   ERR_free_strings();
-
-   /* Free memory used by PRNG */
-   RAND_cleanup();
-
-   tls_initialized = false;
-
-   return 0;
+   return false;
 }
 
-#else /* HAVE_OPENSSL */
-# error No TLS implementation available.
-#endif /* !HAVE_OPENSSL */
-
 #endif /* HAVE_TLS */