Merge tag 'libradsec-0.0.5' into debian
authorSam Hartman <hartmans@painless-security.com>
Wed, 12 Feb 2014 02:17:19 +0000 (21:17 -0500)
committerSam Hartman <hartmans@painless-security.com>
Wed, 12 Feb 2014 02:17:19 +0000 (21:17 -0500)
libradsec-0.0.5

Conflicts:
lib/conf.c
lib/radius/Makefile.am

22 files changed:
README
lib/CHANGES [new file with mode: 0644]
lib/HACKING
lib/Makefile.am
lib/README
lib/conf.c
lib/configure.ac
lib/conn.c
lib/event.c
lib/examples/Makefile.am
lib/examples/client-blocking.c
lib/include/radsec/radsec.h
lib/radius/Makefile.am
lib/radsec.c
lib/radsecproxy/Makefile.am
lib/radsecproxy/tlscommon.c
lib/radsecproxy/tlscommon.h
lib/request.c
lib/tests/Makefile.am
lib/tls.c
lib/tls.h
lib/udp.c

diff --git a/README b/README
index 14df14e..729f3bb 100644 (file)
--- a/README
+++ b/README
@@ -1,6 +1,7 @@
-This is not radsecproxy, it's libradsec (see lib/) sharing the
-radsecproxy repository.
+This is libradsec, not radsecproxy, sharing repository with
+radsecproxy.
 
 For radsecproxy, see branch 'master'.
 
-The repository ca be found at http://git.nordu.net/?p=radsecproxy.git;a=summary .
+The source code can be found at
+http://git.nordu.net/?p=radsecproxy.git;a=summary .
diff --git a/lib/CHANGES b/lib/CHANGES
new file mode 100644 (file)
index 0000000..928dfbe
--- /dev/null
@@ -0,0 +1,17 @@
+Changes between 0.0.4 and 0.0.5
+
+  - When POSIX thread support is detected at configure and build time
+    libradsec will be more safe to use by programs that call it from
+    more than one thread simultaneously.
+
+  - The initialisation of the OpenSSL PRNG has been improved.
+
+User visible changes between 0.0.1 and 0.0.4
+
+  - TLS support is now enabled by default. Use --disable-tls to
+    disable it.
+
+  - Support for TLS-PSK has been added (--enable-tls-psk).
+
+  - The RADIUS dictionaries are now compiled into the library and are
+    no longer read from disk.
index a92f0f9..8278238 100644 (file)
@@ -1,10 +1,10 @@
 HACKING file for libradsec (in Emacs -*- org -*- mode).
 
-Status as of libradsec-0.0.4.dev (2013-05-06).
+Status as of libradsec-0.0.5 (2014-02-03).
 
 * Build instructions
 sh autogen.sh
-./configure #--enable-tls
+./configure
 make
 
 examples/client -r examples/client.conf blocking-tls; echo $?
@@ -37,7 +37,7 @@ examples/client -r examples/client.conf blocking-tls; echo $?
 
 - Application chooses allocation regime.
 
-Note that as of 0.0.2.dev libradsec suffers from way too much focus on
+Note that as of 0.0.4 libradsec suffers from way too much focus on
 the behaviour of a blocking client and is totally useless as a server.
 Not only does it lack most of the functions needed for writing a
 server but it also contains at least one architectural mishap which
index d5b2bff..251c5b9 100644 (file)
@@ -19,7 +19,7 @@ ACLOCAL_AMFLAGS = -I m4
 SUBDIRS = radius radsecproxy include . examples
 DIST_SUBDIRS = $(SUBDIRS) tests
 
-INCLUDES = -I$(srcdir)/include
+AM_CPPFLAGS = -I$(srcdir)/include
 AM_CFLAGS = -Wall -Werror -g
 
 lib_LTLIBRARIES = libradsec.la
@@ -62,7 +62,7 @@ libradsec_la_SOURCES += \
        udp.h \
        util.h
 
-EXTRA_DIST = HACKING LICENSE libradsec.spec radsec.sym
+EXTRA_DIST = CHANGES HACKING LICENSE libradsec.spec radsec.sym
 EXTRA_libradsec_la_DEPENDENCIES = radsec.sym
 AM_DISTCHECK_CONFIGURE_FLAGS = --enable-tls --enable-tls-psk
 
index 111c570..4c0d277 100644 (file)
@@ -14,7 +14,7 @@ LICENSE file.
 Libradsec depends on 
 - libconfuse
 - libevent2
-- openssl (if configured with --enable-tls)
+- openssl (unless configured with --disable-tls)
 
 
 To compile the library and the examples, do something like
@@ -26,8 +26,7 @@ There are a couple of options that can be used when configuring. See
 
   ./configure --help
 
-for the full list. Worth mentioning here is --enable-tls and
---enable-tls-psk.
+for the full list. Worth mentioning here is --enable-tls-psk.
 
 If the preprocessor has a hard time finding some of the header files
 are, try setting environment variable CPPFLAGS at configure
index 9dfc4c6..4e0df31 100644 (file)
@@ -31,7 +31,7 @@
       pskhexstr = STRING # Transport pre-shared key, ASCII hex form.
       pskid = STRING
       pskex = "PSK"|"DHE_PSK"|"RSA_PSK"
-      disable_hostname_check = yes|no
+      disable_hostname_check = "yes"|"no"
   }
 
   # client specific realm config options
index ab775e4..d99bab4 100644 (file)
@@ -1,7 +1,7 @@
 # -*- Autoconf -*- script for libradsec.
 
 AC_PREREQ([2.63])
-AC_INIT([libradsec], [0.0.4.dev], [linus+libradsec@nordu.net])
+AC_INIT([libradsec], [0.0.5], [linus+libradsec@nordu.net])
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_SRCDIR([radsec.c])
 AC_CONFIG_AUX_DIR([build-aux])
@@ -17,19 +17,25 @@ AC_CHECK_LIB([confuse], [cfg_init],,
     AC_MSG_ERROR([required library libconfuse not found]))
 AC_CHECK_LIB([event_core], [event_get_version],,
     AC_MSG_ERROR([required library libevent_core not found]))
+AH_TEMPLATE([HAVE_PTHREADS], [POSIX threads are available on this system])
+AC_SEARCH_LIBS([pthread_create], [pthread], AC_DEFINE([HAVE_PTHREADS]))
 
 # Enable-knobs.
-## Enable TLS (RadSec).
+## Enable TLS (RadSec), default on.
+want_tls=yes
 AH_TEMPLATE([RS_ENABLE_TLS], [TLS (RadSec) enabled])
-AH_TEMPLATE([RADPROT_TLS], [])  dnl Legacy.
-AC_ARG_ENABLE([tls], AS_HELP_STRING([--enable-tls], [enable TLS (RadSec)]),
-    [AC_CHECK_LIB([event_openssl], [bufferevent_openssl_socket_new],,
-         AC_MSG_ERROR([required library event_openssl not found]))
-     AC_DEFINE([RS_ENABLE_TLS])
-     AC_DEFINE([RADPROT_TLS])]) dnl Legacy.
-AM_CONDITIONAL([RS_ENABLE_TLS], [test "${enable_tls+set}" = set])
-### Define WITHOUT_OPENSSL for radius/client.h.
-if test -z "$enable_tls"; then
+AH_TEMPLATE([RADPROT_TLS], [])
+AC_ARG_ENABLE([tls],
+    AS_HELP_STRING([--disable-tls], [disable TLS (RadSec)]),
+    [want_tls=$enableval])
+AM_CONDITIONAL([RS_ENABLE_TLS], [test $want_tls = yes])
+if test $want_tls = yes; then
+    AC_CHECK_LIB([event_openssl], [bufferevent_openssl_socket_new],,
+        AC_MSG_ERROR([required library event_openssl not found]))
+    AC_DEFINE([RS_ENABLE_TLS])
+    AC_DEFINE([RADPROT_TLS])
+else
+    # Define WITHOUT_OPENSSL for radius/client.h.
     CPPFLAGS="$CPPFLAGS -DWITHOUT_OPENSSL"
 fi
 ## Enable TLS-PSK (preshared keys).
@@ -43,7 +49,7 @@ AM_CONDITIONAL([RS_ENABLE_TLS_PSK], [test "${enable_tls_psk+set}" = set])
 # Checks for header files.
 AC_CHECK_HEADERS(
     [sys/time.h time.h netdb.h netinet/in.h stdint.h stdlib.h strings.h string.h \
-     sys/socket.h unistd.h syslog.h sys/select.h fcntl.h arpa/inet.h])
+     sys/socket.h unistd.h syslog.h sys/select.h fcntl.h arpa/inet.h pthread.h])
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_TYPE_SIZE_T
index 499c330..970a071 100644 (file)
@@ -307,20 +307,23 @@ rs_conn_receive_packet (struct rs_connection *conn,
                                evutil_gai_strerror (err));
   rs_debug (("%s: event loop done\n", __func__));
 
-  if ((pkt->flags & RS_PACKET_RECEIVED) == 0
-      || (req_msg
-         && packet_verify_response (pkt->conn, pkt, req_msg) != RSE_OK))
+  if ((pkt->flags & RS_PACKET_RECEIVED) != 0)
     {
-      if (rs_err_conn_peek_code (pkt->conn) == RSE_OK)
-        /* No packet and no error on the stack _should_ mean that the
-           server hung up on us.  */
-        rs_err_conn_push (pkt->conn, RSE_DISCO, "no response");
-      return rs_err_conn_peek_code (conn);
+      /* If the caller passed a request, check the response. */
+      if (req_msg)
+        err = packet_verify_response (pkt->conn, pkt, req_msg);
+
+      /* If the response was OK and the caller wants it, hand it
+         over, else free it. */
+      if (err == RSE_OK && pkt_out)
+        *pkt_out = pkt;
+      else
+        rs_packet_destroy (pkt);
     }
+  else
+    err = rs_err_conn_peek_code (pkt->conn);
 
-  if (pkt_out)
-    *pkt_out = pkt;
-  return RSE_OK;
+  return err;
 }
 
 void
index c625850..a532da9 100644 (file)
@@ -92,6 +92,21 @@ event_retransmit_timeout_cb (int fd, short event, void *data)
       rs_debug (("%s: retransmission timeout on %p (fd %d) sending to %p\n",
                 __func__, conn, conn->fd, conn->active_peer));
       rs_err_conn_push_fl (conn, RSE_TIMEOUT_IO, __FILE__, __LINE__, NULL);
+
+      /* Disable/delete read and write events. Timing out on reading
+         might f.ex. trigger resending of a message. It'd be
+         surprising to end up reading without having enabled/created a
+         read event in that case. */
+      if (conn->bev)            /* TCP. */
+        bufferevent_disable (conn->bev, EV_WRITE|EV_READ);
+      else                      /* UDP. */
+        {
+          if (conn->wev)
+            event_del (conn->wev);
+          if (conn->rev)
+            event_del (conn->rev);
+        }
+
       event_loopbreak (conn);
     }
 }
@@ -143,7 +158,7 @@ event_init_bufferevent (struct rs_connection *conn, struct rs_peer *peer)
 #if defined (RS_ENABLE_TLS)
   else if (conn->realm->type == RS_CONN_TYPE_TLS)
     {
-      if (rs_tls_init (conn))
+      if (tls_init_conn (conn))
        return -1;
       /* Would be convenient to pass BEV_OPT_CLOSE_ON_FREE but things
         seem to break when be_openssl_ctrl() (in libevent) calls
index f300627..fa1c835 100644 (file)
@@ -1,5 +1,5 @@
 AUTOMAKE_OPTIONS = foreign
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)
 AM_CFLAGS = -Wall -Werror -g
 
 noinst_PROGRAMS = client
index cce00bf..a50ee8a 100644 (file)
@@ -26,8 +26,7 @@ blocking_client (const char *config_fn, const char *configuration,
   r = rs_context_create (&h);
   if (r)
     {
-      assert(r == RSE_NOMEM);
-      assert (!"out of RAM -- unable to create libradsec context");
+      assert (!"unable to create libradsec context");
     }
 
 #if !defined (USE_CONFIG_FILE)
index bc061e0..1d718a0 100644 (file)
@@ -168,10 +168,15 @@ typedef const struct value_pair rs_const_avp;
     that the context must not be freed before all other libradsec
     objects have been freed.
 
+    If support for POSIX threads was detected at configure and build
+    time \a rs_context_create will use mutexes to protect multiple
+    threads from stomping on each other in OpenSSL.
+
     \a ctx Address of pointer to a struct rs_context.  This is the
     output of this function.
 
-    \return RSE_OK (0) on success or RSE_NOMEM on out of memory.  */
+    \return RSE_OK (0) on success, RSE_SSLERR on TLS library
+    initialisation error and RSE_NOMEM on out of memory.  */
 int rs_context_create(struct rs_context **ctx);
 
 /** Free a context.  Note that the context must not be freed before
index 9aafed7..ba09db0 100644 (file)
@@ -2,8 +2,7 @@ AUTOMAKE_OPTIONS = foreign
 ACLOCAL_AMFLAGS = -I m4
 
 BUILT_SOURCES = dictionaries.c
-
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)
 AM_CFLAGS = -Wall -g
 
 noinst_LTLIBRARIES = libradsec-radius.la
index efd2dc3..83ce6c5 100644 (file)
@@ -21,6 +21,7 @@
 #include "debug.h"
 #include "radsecproxy/debug.h"
 #if defined (RS_ENABLE_TLS)
+#include "tls.h"
 #include <regex.h>
 #include "radsecproxy/list.h"
 #include "radsecproxy/radsecproxy.h"
@@ -32,14 +33,15 @@ rs_context_create (struct rs_context **ctx)
 {
   struct rs_context *h;
 
+#if defined (RS_ENABLE_TLS)
+  if (tls_init ())
+    return RSE_SSLERR;
+#endif
+
   h = calloc (1, sizeof(*h));
   if (h == NULL)
     return RSE_NOMEM;
 
-#if defined (RS_ENABLE_TLS)
-  ssl_init ();
-#endif
-
   debug_init ("libradsec");    /* radsecproxy compat, FIXME: remove */
 
   if (ctx != NULL)
index 962f367..dc5ffc4 100644 (file)
@@ -1,7 +1,7 @@
 AUTOMAKE_OPTIONS = foreign
 ACLOCAL_AMFLAGS = -I m4
 
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)
 AM_CFLAGS = -Wall -Werror -g
 
 noinst_LTLIBRARIES = libradsec-radsecproxy.la
index 002788d..a31fa32 100644 (file)
 #include "hostport_types.h"
 #include "radsecproxy.h"
 
-static struct hash *tlsconfs = NULL;
-
-void ssl_init(void) {
-    time_t t;
-    pid_t pid;
-
-    SSL_load_error_strings();
-    SSL_library_init();
-
-    while (!RAND_status()) {
-       t = time(NULL);
-       pid = getpid();
-       RAND_seed((unsigned char *)&t, sizeof(time_t));
-       RAND_seed((unsigned char *)&pid, sizeof(pid));
-    }
-}
-
 static int pem_passwd_cb(char *buf, int size, int rwflag, void *userdata) {
     int pwdlen = strlen(userdata);
     if (rwflag != 0 || pwdlen > size) /* not for decryption or too large */
@@ -280,15 +263,6 @@ static SSL_CTX *tlscreatectx(uint8_t type, struct tls *conf) {
     return ctx;
 }
 
-struct tls *tlsgettls(char *alt1, char *alt2) {
-    struct tls *t;
-
-    t = hash_read(tlsconfs, alt1, strlen(alt1));
-    if (!t)
-       t = hash_read(tlsconfs, alt2, strlen(alt2));
-    return t;
-}
-
 SSL_CTX *tlsgetctx(uint8_t type, struct tls *t) {
     struct timeval now;
 
@@ -476,70 +450,6 @@ int cnregexp(X509 *cert, const char *exact, const regex_t *regex) {
     return 0;
 }
 
-/* this is a bit sloppy, should not always accept match to any */
-int certnamecheck(X509 *cert, struct list *hostports) {
-    struct list_node *entry;
-    struct hostportres *hp;
-    int r;
-    uint8_t type = 0; /* 0 for DNS, AF_INET for IPv4, AF_INET6 for IPv6 */
-    struct in6_addr addr;
-
-    for (entry = list_first(hostports); entry; entry = list_next(entry)) {
-       hp = (struct hostportres *)entry->data;
-       if (hp->prefixlen != 255) {
-           /* we disable the check for prefixes */
-           return 1;
-       }
-       if (inet_pton(AF_INET, hp->host, &addr))
-           type = AF_INET;
-       else if (inet_pton(AF_INET6, hp->host, &addr))
-           type = AF_INET6;
-       else
-           type = 0;
-
-       r = type ? subjectaltnameaddr(cert, type, &addr) : subjectaltnameregexp(cert, GEN_DNS, hp->host, NULL);
-       if (r) {
-           if (r > 0) {
-               debug(DBG_DBG, "certnamecheck: Found subjectaltname matching %s %s", type ? "address" : "host", hp->host);
-               return 1;
-           }
-           debug(DBG_WARN, "certnamecheck: No subjectaltname matching %s %s", type ? "address" : "host", hp->host);
-       } else {
-           if (cnregexp(cert, hp->host, NULL)) {
-               debug(DBG_DBG, "certnamecheck: Found cn matching host %s", hp->host);
-               return 1;
-           }
-           debug(DBG_WARN, "certnamecheck: cn not matching host %s", hp->host);
-       }
-    }
-    return 0;
-}
-
-int verifyconfcert(X509 *cert, struct clsrvconf *conf) {
-    if (conf->certnamecheck) {
-       if (!certnamecheck(cert, conf->hostports)) {
-           debug(DBG_WARN, "verifyconfcert: certificate name check failed");
-           return 0;
-       }
-       debug(DBG_WARN, "verifyconfcert: certificate name check ok");
-    }
-    if (conf->certcnregex) {
-       if (cnregexp(cert, NULL, conf->certcnregex) < 1) {
-           debug(DBG_WARN, "verifyconfcert: CN not matching regex");
-           return 0;
-       }
-       debug(DBG_DBG, "verifyconfcert: CN matching regex");
-    }
-    if (conf->certuriregex) {
-       if (subjectaltnameregexp(cert, GEN_URI, NULL, conf->certuriregex) < 1) {
-           debug(DBG_WARN, "verifyconfcert: subjectaltname URI not matching regex");
-           return 0;
-       }
-       debug(DBG_DBG, "verifyconfcert: subjectaltname URI matching regex");
-    }
-    return 1;
-}
-
 /* Local Variables: */
 /* c-file-style: "stroustrup" */
 /* End: */
index da2092e..5a6d262 100644 (file)
@@ -26,14 +26,11 @@ struct tls {
 };
 
 #if defined(RADPROT_TLS) || defined(RADPROT_DTLS)
-void ssl_init();
-struct tls *tlsgettls(char *alt1, char *alt2);
 SSL_CTX *tlsgetctx(uint8_t type, struct tls *t);
 X509 *verifytlscert(SSL *ssl);
 int subjectaltnameaddr(X509 *cert, int family, const struct in6_addr *addr);
 int subjectaltnameregexp(X509 *cert, int type, const char *exact,  const regex_t *regex);
 int cnregexp(X509 *cert, const char *exact, const regex_t *regex);
-int verifyconfcert(X509 *cert, struct clsrvconf *conf);
 #endif
 
 #if defined (__cplusplus)
index 3a8b6dd..40ac56d 100644 (file)
@@ -119,17 +119,19 @@ rs_request_send (struct rs_request *request, struct rs_packet **resp_msg)
                                      resp_msg);
          if (r == RSE_OK)
            break;              /* Success.  */
-
-         if (r != RSE_TIMEOUT_CONN && r != RSE_TIMEOUT_IO)
-           break;              /* Error.  */
        }
-      else if (r != RSE_TIMEOUT_CONN && r != RSE_TIMEOUT_IO)
+      if (r != RSE_TIMEOUT_CONN && r != RSE_TIMEOUT_IO)
        break;                  /* Error.  */
 
+      /* Timing out reading or writing. Pop the timeout error from the
+         stack and continue the loop. */
+      rs_err_conn_pop (request->conn);
+
       gettimeofday (&now, NULL);
       if (++count > MRC || timercmp (&now, &end, >))
        {
-         r = RSE_TIMEOUT;
+         r = rs_err_conn_push_fl (request->conn, RSE_TIMEOUT,
+                                   __FILE__, __LINE__, NULL);
          break;                /* Timeout.  */
        }
 
index dc15264..09f9d28 100644 (file)
@@ -1,5 +1,5 @@
 AUTOMAKE_OPTIONS = foreign
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)
 AM_CFLAGS = -Wall -Werror -g
 
 TESTS = test-udp
index 62b281f..ba3cab5 100644 (file)
--- a/lib/tls.c
+++ b/lib/tls.c
@@ -6,11 +6,19 @@
 #endif
 
 #include <stdlib.h>
+#include <unistd.h>
 #include <assert.h>
+#include <fcntl.h>
+#include <limits.h>
+#if defined HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
 #include <openssl/ssl.h>
 #include <openssl/err.h>
 #include <openssl/bn.h>
 #include <openssl/x509v3.h>
+#include <openssl/rand.h>
+#include <openssl/crypto.h>
 #include <radsec/radsec.h>
 #include <radsec/radsec-impl.h>
 
@@ -18,6 +26,8 @@
 #include "radsecproxy/list.h"
 #include "radsecproxy/radsecproxy.h"
 
+#include "tls.h"
+
 static struct tls *
 _get_tlsconf (struct rs_connection *conn, const struct rs_realm *realm)
 {
@@ -112,8 +122,132 @@ psk_client_cb (SSL *ssl,
 }
 #endif  /* RS_ENABLE_TLS_PSK */
 
+/** Read \a buf_len bytes from one of the random devices into \a
+    buf. Return 0 on success and -1 on failure. */
+static int
+load_rand_ (uint8_t *buf, size_t buf_len)
+{
+  static const char *fns[] = {"/dev/urandom", "/dev/random", NULL};
+  int i;
+
+  if (buf_len > SSIZE_MAX)
+    return -1;
+
+  for (i = 0; fns[i] != NULL; i++)
+    {
+      size_t nread = 0;
+      int fd = open (fns[i], O_RDONLY);
+      if (fd < 0)
+        continue;
+      while (nread != buf_len)
+        {
+          ssize_t r = read (fd, buf + nread, buf_len - nread);
+          if (r < 0)
+            return -1;
+          if (r == 0)
+            break;
+          nread += r;
+        }
+      close (fd);
+      if (nread != buf_len)
+        return -1;
+      return 0;
+    }
+  return -1;
+}
+
+/** Initialise OpenSSL's PRNG by possibly invoking RAND_poll() and by
+    feeding RAND_seed() data from one of the random devices. If either
+    succeeds, we're happy and return 0. */
+static int
+init_openssl_rand_ (void)
+{
+  long openssl_version = 0;
+  int openssl_random_init_flag = 0;
+  int our_random_init_flag = 0;
+  uint8_t buf[32];
+
+  /* Older OpenSSL has a crash bug in RAND_poll (when a file it opens
+     gets a file descriptor with a number higher than FD_SETSIZE) so
+     use it only for newer versions. */
+  openssl_version = SSLeay ();
+  if (openssl_version >= OPENSSL_V (0,9,8,'c'))
+    openssl_random_init_flag = RAND_poll ();
+
+  our_random_init_flag = !load_rand_ (buf, sizeof(buf));
+  if (our_random_init_flag)
+    RAND_seed (buf, sizeof(buf));
+  memset (buf, 0, sizeof(buf)); /* FIXME: What if memset() is optimised out? */
+
+  if (!openssl_random_init_flag && !our_random_init_flag)
+    return -1;
+  if (!RAND_bytes (buf, sizeof(buf)))
+    return -1;
+  return 0;
+}
+
+#if defined HAVE_PTHREADS
+/** Array of pthread_mutex_t for OpenSSL. Allocated and initialised in
+    \a init_locking_ and never freed. */
+static pthread_mutex_t *s_openssl_mutexes = NULL;
+/** Number of pthread_mutex_t's allocated at s_openssl_mutexes. */
+static int s_openssl_mutexes_count = 0;
+
+/** Callback for OpenSSL when a lock is to be held or released. */
+static void
+openssl_locking_cb_ (int mode, int i, const char *file, int line)
+{
+  if (s_openssl_mutexes == NULL || i >= s_openssl_mutexes_count)
+    return;
+  if (mode & CRYPTO_LOCK)
+    pthread_mutex_lock (&s_openssl_mutexes[i]);
+  else
+    pthread_mutex_unlock (&s_openssl_mutexes[i]);
+}
+
+/** Initialise any locking needed for being thread safe. Libradsec has
+    all its own state in one or more struct rs_context and doesn't
+    need locks but libraries used by libradsec may need protection. */
+static int
+init_locking_ ()
+{
+  int i, n;
+  n = CRYPTO_num_locks ();
+
+  s_openssl_mutexes = calloc (n, sizeof(pthread_mutex_t));
+  if (s_openssl_mutexes == NULL)
+    return -RSE_NOMEM;
+  for (i = 0; i < n; i++)
+    pthread_mutex_init (&s_openssl_mutexes[i], NULL);
+  s_openssl_mutexes_count = n;
+
+  return 0;
+}
+#endif  /* HAVE_PTHREADS */
+
+/** Initialise the TLS library. Return 0 on success, -1 on failure. */
+int
+tls_init ()
+{
+  SSL_load_error_strings ();
+#if defined HAVE_PTHREADS
+  if (CRYPTO_get_locking_callback () == NULL)
+    {
+      assert (s_openssl_mutexes_count == 0);
+      /* Allocate and initialise mutexes. We will never free
+         these. FIXME: Is there a portable way of having a function
+         invoked when a solib is unloaded? -ln */
+      if (init_locking_ ())
+        return -1;
+      CRYPTO_set_locking_callback (openssl_locking_cb_);
+    }
+#endif  /* HAVE_PTHREADS */
+  SSL_library_init ();
+  return init_openssl_rand_ ();
+}
+
 int
-rs_tls_init (struct rs_connection *conn)
+tls_init_conn (struct rs_connection *conn)
 {
   struct rs_context *ctx = NULL;
   struct tls *tlsconf = NULL;
index 4707b93..51f2a64 100644 (file)
--- a/lib/tls.h
+++ b/lib/tls.h
@@ -5,9 +5,19 @@
 extern "C" {
 #endif
 
-int rs_tls_init (struct rs_connection *conn);
+int tls_init (void);
+int tls_init_conn (struct rs_connection *conn);
 int tls_verify_cert (struct rs_connection *conn);
 
+#define OPENSSL_VER(a,b,c,d,e) \
+  (((a)<<28) |                 \
+   ((b)<<20) |                 \
+   ((c)<<12) |                 \
+   ((d)<< 4) |                 \
+    (e))
+#define OPENSSL_V(a,b,c,d) \
+  OPENSSL_VER((a),(b),(c),(d)-'a'+1,0xf)
+
 #if defined (__cplusplus)
 }
 #endif
index 36af084..c00f215 100644 (file)
--- a/lib/udp.c
+++ b/lib/udp.c
@@ -91,7 +91,7 @@ _evcb (evutil_socket_t fd, short what, void *user_data)
            {
              /* FIXME: Really shouldn't happen since we've been told
                 that fd is readable!  */
-             rs_debug (("%s: EAGAIN reading UDP packet -- wot?"));
+             rs_debug (("%s: EAGAIN reading UDP packet -- wot?\n"));
               goto err_out;
            }
 
@@ -121,6 +121,8 @@ _evcb (evutil_socket_t fd, short what, void *user_data)
         Don't touch it afterwards -- it might have been freed.  */
       if (pkt->conn->callbacks.received_cb)
        pkt->conn->callbacks.received_cb (pkt, pkt->conn->user_data);
+      else
+        rs_debug (("%s: no received-callback -- dropping packet\n", __func__));
     }
   else if (what & EV_WRITE)
     {