diff options
author | Sam Hartman <hartmans@painless-security.com> | 2014-02-11 21:17:19 -0500 |
---|---|---|
committer | Sam Hartman <hartmans@painless-security.com> | 2014-02-11 21:17:19 -0500 |
commit | d78a0c6725823419bf54d4f9d45ddd402caaa7a0 (patch) | |
tree | 4e8a86ad5d9a4658e1350ecb2aff19a5786452ed /lib | |
parent | 7b065194a99aa15b10ff1e69547eb1b44d5399a8 (diff) | |
parent | f18e7f2ab31160c00a7b363542fc4cea57d0fa14 (diff) |
Merge tag 'libradsec-0.0.5' into debian
libradsec-0.0.5
Conflicts:
lib/conf.c
lib/radius/Makefile.am
Diffstat (limited to 'lib')
-rw-r--r-- | lib/CHANGES | 17 | ||||
-rw-r--r-- | lib/HACKING | 6 | ||||
-rw-r--r-- | lib/Makefile.am | 4 | ||||
-rw-r--r-- | lib/README | 5 | ||||
-rw-r--r-- | lib/conf.c | 2 | ||||
-rw-r--r-- | lib/configure.ac | 30 | ||||
-rw-r--r-- | lib/conn.c | 25 | ||||
-rw-r--r-- | lib/event.c | 17 | ||||
-rw-r--r-- | lib/examples/Makefile.am | 2 | ||||
-rw-r--r-- | lib/examples/client-blocking.c | 3 | ||||
-rw-r--r-- | lib/include/radsec/radsec.h | 7 | ||||
-rw-r--r-- | lib/radius/Makefile.am | 3 | ||||
-rw-r--r-- | lib/radsec.c | 10 | ||||
-rw-r--r-- | lib/radsecproxy/Makefile.am | 2 | ||||
-rw-r--r-- | lib/radsecproxy/tlscommon.c | 90 | ||||
-rw-r--r-- | lib/radsecproxy/tlscommon.h | 3 | ||||
-rw-r--r-- | lib/request.c | 12 | ||||
-rw-r--r-- | lib/tests/Makefile.am | 2 | ||||
-rw-r--r-- | lib/tls.c | 136 | ||||
-rw-r--r-- | lib/tls.h | 12 | ||||
-rw-r--r-- | lib/udp.c | 4 |
21 files changed, 246 insertions, 146 deletions
diff --git a/lib/CHANGES b/lib/CHANGES new file mode 100644 index 0000000..928dfbe --- /dev/null +++ b/lib/CHANGES @@ -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. diff --git a/lib/HACKING b/lib/HACKING index a92f0f9..8278238 100644 --- a/lib/HACKING +++ b/lib/HACKING @@ -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 diff --git a/lib/Makefile.am b/lib/Makefile.am index d5b2bff..251c5b9 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -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 @@ -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 @@ -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 diff --git a/lib/configure.ac b/lib/configure.ac index ab775e4..d99bab4 100644 --- a/lib/configure.ac +++ b/lib/configure.ac @@ -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 @@ -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 diff --git a/lib/event.c b/lib/event.c index c625850..a532da9 100644 --- a/lib/event.c +++ b/lib/event.c @@ -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 diff --git a/lib/examples/Makefile.am b/lib/examples/Makefile.am index f300627..fa1c835 100644 --- a/lib/examples/Makefile.am +++ b/lib/examples/Makefile.am @@ -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 diff --git a/lib/examples/client-blocking.c b/lib/examples/client-blocking.c index cce00bf..a50ee8a 100644 --- a/lib/examples/client-blocking.c +++ b/lib/examples/client-blocking.c @@ -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) diff --git a/lib/include/radsec/radsec.h b/lib/include/radsec/radsec.h index bc061e0..1d718a0 100644 --- a/lib/include/radsec/radsec.h +++ b/lib/include/radsec/radsec.h @@ -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 diff --git a/lib/radius/Makefile.am b/lib/radius/Makefile.am index 9aafed7..ba09db0 100644 --- a/lib/radius/Makefile.am +++ b/lib/radius/Makefile.am @@ -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 diff --git a/lib/radsec.c b/lib/radsec.c index efd2dc3..83ce6c5 100644 --- a/lib/radsec.c +++ b/lib/radsec.c @@ -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) diff --git a/lib/radsecproxy/Makefile.am b/lib/radsecproxy/Makefile.am index 962f367..dc5ffc4 100644 --- a/lib/radsecproxy/Makefile.am +++ b/lib/radsecproxy/Makefile.am @@ -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 diff --git a/lib/radsecproxy/tlscommon.c b/lib/radsecproxy/tlscommon.c index 002788d..a31fa32 100644 --- a/lib/radsecproxy/tlscommon.c +++ b/lib/radsecproxy/tlscommon.c @@ -37,23 +37,6 @@ #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: */ diff --git a/lib/radsecproxy/tlscommon.h b/lib/radsecproxy/tlscommon.h index da2092e..5a6d262 100644 --- a/lib/radsecproxy/tlscommon.h +++ b/lib/radsecproxy/tlscommon.h @@ -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) diff --git a/lib/request.c b/lib/request.c index 3a8b6dd..40ac56d 100644 --- a/lib/request.c +++ b/lib/request.c @@ -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. */ } diff --git a/lib/tests/Makefile.am b/lib/tests/Makefile.am index dc15264..09f9d28 100644 --- a/lib/tests/Makefile.am +++ b/lib/tests/Makefile.am @@ -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 @@ -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; @@ -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 @@ -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) { |