diff options
author | venaas <venaas> | 2008-08-21 08:04:16 +0000 |
---|---|---|
committer | venaas <venaas@e88ac4ed-0b26-0410-9574-a7f39faa03bf> | 2008-08-21 08:04:16 +0000 |
commit | ea645ad6e5ec575e574960ccb079241c50b992fe (patch) | |
tree | 2ddf628ed8781120306060d3ac61128021bfbb41 | |
parent | 39692c605e2f1c37efd38f675abdd22ac503b382 (diff) |
separated tls
git-svn-id: https://svn.testnett.uninett.no/radsecproxy/trunk@349 e88ac4ed-0b26-0410-9574-a7f39faa03bf
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | radsecproxy.c | 376 | ||||
-rw-r--r-- | tls.c | 399 | ||||
-rw-r--r-- | tls.h | 12 |
5 files changed, 416 insertions, 375 deletions
@@ -1,6 +1,6 @@ CFLAGS = -g -Wall -pedantic -pthread LDFLAGS = -lssl -OBJ = util.o debug.o list.o gconfig.o tcp.o dtls.o radsecproxy.o +OBJ = util.o debug.o list.o gconfig.o tcp.o tls.o dtls.o radsecproxy.o all: radsecproxy diff --git a/Makefile.am b/Makefile.am index 6217aaf..0bf27aa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,6 +6,7 @@ radsecproxy_SOURCES = radsecproxy.c \ debug.c \ list.c \ tcp.c \ + tls.c \ dtls.c \ radsecproxy.h \ gconfig.h \ @@ -13,6 +14,7 @@ radsecproxy_SOURCES = radsecproxy.c \ util.h \ list.h \ tcp.h \ + tls.h \ dtls.h radsecproxy_CFLAGS = -g -Wall -pedantic -pthread @SSL_CFLAGS@ @TARGET_CFLAGS@ diff --git a/radsecproxy.c b/radsecproxy.c index 17d3685..1a9fc54 100644 --- a/radsecproxy.c +++ b/radsecproxy.c @@ -64,6 +64,8 @@ #include "util.h" #include "gconfig.h" #include "radsecproxy.h" +#include "tcp.h" +#include "tls.h" #include "dtls.h" static struct options options; @@ -91,16 +93,8 @@ void freerealm(struct realm *realm); void freeclsrvconf(struct clsrvconf *conf); void freerqdata(struct request *rq); void *udpserverrd(void *arg); -void *tlslistener(void *arg); -void *tcplistener(void *arg); -int tlsconnect(struct server *server, struct timeval *when, int timeout, char *text); -int tcpconnect(struct server *server, struct timeval *when, int timeout, char *text); void *udpclientrd(void *arg); -void *tlsclientrd(void *arg); -void *tcpclientrd(void *arg); int clientradputudp(struct server *server, unsigned char *rad); -int clientradputtls(struct server *server, unsigned char *rad); -int clientradputtcp(struct server *server, unsigned char *rad); X509 *verifytlscert(SSL *ssl); int radsrv(struct request *rq); @@ -999,156 +993,6 @@ int verifyconfcert(X509 *cert, struct clsrvconf *conf) { return 1; } -int tlsconnect(struct server *server, struct timeval *when, int timeout, char *text) { - struct timeval now; - time_t elapsed; - X509 *cert; - unsigned long error; - - debug(DBG_DBG, "tlsconnect: called from %s", text); - pthread_mutex_lock(&server->lock); - if (when && memcmp(&server->lastconnecttry, when, sizeof(struct timeval))) { - /* already reconnected, nothing to do */ - debug(DBG_DBG, "tlsconnect(%s): seems already reconnected", text); - pthread_mutex_unlock(&server->lock); - return 1; - } - - for (;;) { - gettimeofday(&now, NULL); - elapsed = now.tv_sec - server->lastconnecttry.tv_sec; - if (timeout && server->lastconnecttry.tv_sec && elapsed > timeout) { - debug(DBG_DBG, "tlsconnect: timeout"); - if (server->sock >= 0) - close(server->sock); - SSL_free(server->ssl); - server->ssl = NULL; - pthread_mutex_unlock(&server->lock); - return 0; - } - if (server->connectionok) { - server->connectionok = 0; - sleep(2); - } else if (elapsed < 1) - sleep(2); - else if (elapsed < 60) { - debug(DBG_INFO, "tlsconnect: sleeping %lds", elapsed); - sleep(elapsed); - } else if (elapsed < 100000) { - debug(DBG_INFO, "tlsconnect: sleeping %ds", 60); - sleep(60); - } else - server->lastconnecttry.tv_sec = now.tv_sec; /* no sleep at startup */ - debug(DBG_WARN, "tlsconnect: trying to open TLS connection to %s port %s", server->conf->host, server->conf->port); - if (server->sock >= 0) - close(server->sock); - if ((server->sock = connecttcp(server->conf->addrinfo, srcprotores[RAD_TLS])) < 0) { - debug(DBG_ERR, "tlsconnect: connecttcp failed"); - continue; - } - - SSL_free(server->ssl); - server->ssl = SSL_new(server->conf->ssl_ctx); - SSL_set_fd(server->ssl, server->sock); - if (SSL_connect(server->ssl) <= 0) { - while ((error = ERR_get_error())) - debug(DBG_ERR, "tlsconnect: TLS: %s", ERR_error_string(error, NULL)); - continue; - } - cert = verifytlscert(server->ssl); - if (!cert) - continue; - if (verifyconfcert(cert, server->conf)) { - X509_free(cert); - break; - } - X509_free(cert); - } - debug(DBG_WARN, "tlsconnect: TLS connection to %s port %s up", server->conf->host, server->conf->port); - gettimeofday(&server->lastconnecttry, NULL); - pthread_mutex_unlock(&server->lock); - return 1; -} - -/* timeout in seconds, 0 means no timeout (blocking), returns when num bytes have been read, or timeout */ -/* returns 0 on timeout, -1 on error and num if ok */ -int sslreadtimeout(SSL *ssl, unsigned char *buf, int num, int timeout) { - int s, ndesc, cnt, len; - fd_set readfds, writefds; - struct timeval timer; - - s = SSL_get_fd(ssl); - if (s < 0) - return -1; - /* make socket non-blocking? */ - for (len = 0; len < num; len += cnt) { - FD_ZERO(&readfds); - FD_SET(s, &readfds); - writefds = readfds; - if (timeout) { - timer.tv_sec = timeout; - timer.tv_usec = 0; - } - ndesc = select(s + 1, &readfds, &writefds, NULL, timeout ? &timer : NULL); - if (ndesc < 1) - return ndesc; - - cnt = SSL_read(ssl, buf + len, num - len); - if (cnt <= 0) - switch (SSL_get_error(ssl, cnt)) { - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - cnt = 0; - continue; - case SSL_ERROR_ZERO_RETURN: - /* remote end sent close_notify, send one back */ - SSL_shutdown(ssl); - return -1; - default: - return -1; - } - } - return num; -} - -/* timeout in seconds, 0 means no timeout (blocking) */ -unsigned char *radtlsget(SSL *ssl, int timeout) { - int cnt, len; - unsigned char buf[4], *rad; - - for (;;) { - cnt = sslreadtimeout(ssl, buf, 4, timeout); - if (cnt < 1) { - debug(DBG_DBG, cnt ? "radtlsget: connection lost" : "radtlsget: timeout"); - return NULL; - } - - len = RADLEN(buf); - rad = malloc(len); - if (!rad) { - debug(DBG_ERR, "radtlsget: malloc failed"); - continue; - } - memcpy(rad, buf, 4); - - cnt = sslreadtimeout(ssl, rad + 4, len - 4, timeout); - if (cnt < 1) { - debug(DBG_DBG, cnt ? "radtlsget: connection lost" : "radtlsget: timeout"); - free(rad); - return NULL; - } - - if (len >= 20) - break; - - free(rad); - debug(DBG_WARN, "radtlsget: packet smaller than minimum radius size"); - } - - debug(DBG_DBG, "radtlsget: got %d bytes", len); - return rad; -} - int clientradputudp(struct server *server, unsigned char *rad) { size_t len; struct sockaddr_storage sa; @@ -1187,29 +1031,6 @@ int clientradputudp(struct server *server, unsigned char *rad) { return 0; } -int clientradputtls(struct server *server, unsigned char *rad) { - int cnt; - size_t len; - unsigned long error; - struct timeval lastconnecttry; - struct clsrvconf *conf = server->conf; - - len = RADLEN(rad); - lastconnecttry = server->lastconnecttry; - while ((cnt = SSL_write(server->ssl, rad, len)) <= 0) { - while ((error = ERR_get_error())) - debug(DBG_ERR, "clientradputtls: TLS: %s", ERR_error_string(error, NULL)); - if (server->dynamiclookuparg) - return 0; - tlsconnect(server, &lastconnecttry, 0, "clientradputtls"); - lastconnecttry = server->lastconnecttry; - } - - server->connectionok = 1; - debug(DBG_DBG, "clientradputtls: Sent %d bytes, Radius packet of length %d to TLS peer %s", cnt, len, conf->host); - return 1; -} - int radsign(unsigned char *rad, unsigned char *sec) { static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; static unsigned char first = 1; @@ -2436,37 +2257,6 @@ void *udpclientrd(void *arg) { } } -void *tlsclientrd(void *arg) { - struct server *server = (struct server *)arg; - unsigned char *buf; - struct timeval now, lastconnecttry; - - for (;;) { - /* yes, lastconnecttry is really necessary */ - lastconnecttry = server->lastconnecttry; - buf = radtlsget(server->ssl, server->dynamiclookuparg ? IDLE_TIMEOUT : 0); - if (!buf) { - if (server->dynamiclookuparg) - break; - tlsconnect(server, &lastconnecttry, 0, "tlsclientrd"); - continue; - } - - if (!replyh(server, buf)) - free(buf); - if (server->dynamiclookuparg) { - gettimeofday(&now, NULL); - if (now.tv_sec - server->lastreply.tv_sec > IDLE_TIMEOUT) { - debug(DBG_INFO, "tlsclientrd: idle timeout for %s", server->conf->name); - break; - } - } - } - ERR_remove_state(0); - server->clientrdgone = 1; - return NULL; -} - /* code for removing state not finished */ void *clientwr(void *arg) { struct server *server = (struct server *)arg; @@ -2673,168 +2463,6 @@ void *udpserverrd(void *arg) { free(sp); } -void *tlsserverwr(void *arg) { - int cnt; - unsigned long error; - struct client *client = (struct client *)arg; - struct queue *replyq; - struct reply *reply; - - debug(DBG_DBG, "tlsserverwr: starting for %s", client->conf->host); - replyq = client->replyq; - for (;;) { - pthread_mutex_lock(&replyq->mutex); - while (!list_first(replyq->entries)) { - if (client->ssl) { - debug(DBG_DBG, "tlsserverwr: waiting for signal"); - pthread_cond_wait(&replyq->cond, &replyq->mutex); - debug(DBG_DBG, "tlsserverwr: got signal"); - } - if (!client->ssl) { - /* ssl might have changed while waiting */ - pthread_mutex_unlock(&replyq->mutex); - debug(DBG_DBG, "tlsserverwr: exiting as requested"); - ERR_remove_state(0); - pthread_exit(NULL); - } - } - reply = (struct reply *)list_shift(replyq->entries); - pthread_mutex_unlock(&replyq->mutex); - cnt = SSL_write(client->ssl, reply->buf, RADLEN(reply->buf)); - if (cnt > 0) - debug(DBG_DBG, "tlsserverwr: sent %d bytes, Radius packet of length %d", - cnt, RADLEN(reply->buf)); - else - while ((error = ERR_get_error())) - debug(DBG_ERR, "tlsserverwr: SSL: %s", ERR_error_string(error, NULL)); - free(reply->buf); - free(reply); - } -} - -void tlsserverrd(struct client *client) { - struct request rq; - pthread_t tlsserverwrth; - - debug(DBG_DBG, "tlsserverrd: starting for %s", client->conf->host); - - if (pthread_create(&tlsserverwrth, NULL, tlsserverwr, (void *)client)) { - debug(DBG_ERR, "tlsserverrd: pthread_create failed"); - return; - } - - for (;;) { - memset(&rq, 0, sizeof(struct request)); - rq.buf = radtlsget(client->ssl, 0); - if (!rq.buf) { - debug(DBG_ERR, "tlsserverrd: connection from %s lost", client->conf->host); - break; - } - debug(DBG_DBG, "tlsserverrd: got Radius message from %s", client->conf->host); - rq.from = client; - if (!radsrv(&rq)) { - debug(DBG_ERR, "tlsserverrd: message authentication/validation failed, closing connection from %s", client->conf->host); - break; - } - } - - /* stop writer by setting ssl to NULL and give signal in case waiting for data */ - client->ssl = NULL; - pthread_mutex_lock(&client->replyq->mutex); - pthread_cond_signal(&client->replyq->cond); - pthread_mutex_unlock(&client->replyq->mutex); - debug(DBG_DBG, "tlsserverrd: waiting for writer to end"); - pthread_join(tlsserverwrth, NULL); - removeclientrqs(client); - debug(DBG_DBG, "tlsserverrd: reader for %s exiting", client->conf->host); -} - -void *tlsservernew(void *arg) { - int s; - struct sockaddr_storage from; - size_t fromlen = sizeof(from); - struct clsrvconf *conf; - struct list_node *cur = NULL; - SSL *ssl = NULL; - X509 *cert = NULL; - unsigned long error; - struct client *client; - - s = *(int *)arg; - if (getpeername(s, (struct sockaddr *)&from, &fromlen)) { - debug(DBG_DBG, "tlsservernew: getpeername failed, exiting"); - goto exit; - } - debug(DBG_WARN, "tlsservernew: incoming TLS connection from %s", addr2string((struct sockaddr *)&from, fromlen)); - - conf = find_conf(RAD_TLS, (struct sockaddr *)&from, clconfs, &cur); - if (conf) { - ssl = SSL_new(conf->ssl_ctx); - SSL_set_fd(ssl, s); - - if (SSL_accept(ssl) <= 0) { - while ((error = ERR_get_error())) - debug(DBG_ERR, "tlsservernew: SSL: %s", ERR_error_string(error, NULL)); - debug(DBG_ERR, "tlsservernew: SSL_accept failed"); - goto exit; - } - cert = verifytlscert(ssl); - if (!cert) - goto exit; - } - - while (conf) { - if (verifyconfcert(cert, conf)) { - X509_free(cert); - client = addclient(conf); - if (client) { - client->ssl = ssl; - tlsserverrd(client); - removeclient(client); - } else - debug(DBG_WARN, "tlsservernew: failed to create new client instance"); - goto exit; - } - conf = find_conf(RAD_TLS, (struct sockaddr *)&from, clconfs, &cur); - } - debug(DBG_WARN, "tlsservernew: ignoring request, no matching TLS client"); - if (cert) - X509_free(cert); - - exit: - SSL_free(ssl); - ERR_remove_state(0); - shutdown(s, SHUT_RDWR); - close(s); - pthread_exit(NULL); -} - -void *tlslistener(void *arg) { - pthread_t tlsserverth; - int s, *sp = (int *)arg; - struct sockaddr_storage from; - size_t fromlen = sizeof(from); - - listen(*sp, 0); - - for (;;) { - s = accept(*sp, (struct sockaddr *)&from, &fromlen); - if (s < 0) { - debug(DBG_WARN, "accept failed"); - continue; - } - if (pthread_create(&tlsserverth, NULL, tlsservernew, (void *)&s)) { - debug(DBG_ERR, "tlslistener: pthread_create failed"); - shutdown(s, SHUT_RDWR); - close(s); - continue; - } - pthread_detach(tlsserverth); - } - free(sp); - return NULL; -} - void createlistener(uint8_t type, char *arg) { pthread_t th; struct clsrvconf *listenres; @@ -0,0 +1,399 @@ +/* + * Copyright (C) 2006-2008 Stig Venaas <venaas@uninett.no> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#include <signal.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <string.h> +#include <unistd.h> +#include <limits.h> +#ifdef SYS_SOLARIS9 +#include <fcntl.h> +#endif +#include <sys/time.h> +#include <sys/types.h> +#include <sys/select.h> +#include <ctype.h> +#include <sys/wait.h> +#include <arpa/inet.h> +#include <regex.h> +#include <pthread.h> +#include <openssl/ssl.h> +#include <openssl/err.h> +#include "debug.h" +#include "list.h" +#include "util.h" +#include "radsecproxy.h" +#include "tls.h" + +int tlsconnect(struct server *server, struct timeval *when, int timeout, char *text) { + struct timeval now; + time_t elapsed; + X509 *cert; + unsigned long error; + + debug(DBG_DBG, "tlsconnect: called from %s", text); + pthread_mutex_lock(&server->lock); + if (when && memcmp(&server->lastconnecttry, when, sizeof(struct timeval))) { + /* already reconnected, nothing to do */ + debug(DBG_DBG, "tlsconnect(%s): seems already reconnected", text); + pthread_mutex_unlock(&server->lock); + return 1; + } + + for (;;) { + gettimeofday(&now, NULL); + elapsed = now.tv_sec - server->lastconnecttry.tv_sec; + if (timeout && server->lastconnecttry.tv_sec && elapsed > timeout) { + debug(DBG_DBG, "tlsconnect: timeout"); + if (server->sock >= 0) + close(server->sock); + SSL_free(server->ssl); + server->ssl = NULL; + pthread_mutex_unlock(&server->lock); + return 0; + } + if (server->connectionok) { + server->connectionok = 0; + sleep(2); + } else if (elapsed < 1) + sleep(2); + else if (elapsed < 60) { + debug(DBG_INFO, "tlsconnect: sleeping %lds", elapsed); + sleep(elapsed); + } else if (elapsed < 100000) { + debug(DBG_INFO, "tlsconnect: sleeping %ds", 60); + sleep(60); + } else + server->lastconnecttry.tv_sec = now.tv_sec; /* no sleep at startup */ + debug(DBG_WARN, "tlsconnect: trying to open TLS connection to %s port %s", server->conf->host, server->conf->port); + if (server->sock >= 0) + close(server->sock); + if ((server->sock = connecttcp(server->conf->addrinfo, getsrcprotores(RAD_TLS))) < 0) { + debug(DBG_ERR, "tlsconnect: connecttcp failed"); + continue; + } + + SSL_free(server->ssl); + server->ssl = SSL_new(server->conf->ssl_ctx); + SSL_set_fd(server->ssl, server->sock); + if (SSL_connect(server->ssl) <= 0) { + while ((error = ERR_get_error())) + debug(DBG_ERR, "tlsconnect: TLS: %s", ERR_error_string(error, NULL)); + continue; + } + cert = verifytlscert(server->ssl); + if (!cert) + continue; + if (verifyconfcert(cert, server->conf)) { + X509_free(cert); + break; + } + X509_free(cert); + } + debug(DBG_WARN, "tlsconnect: TLS connection to %s port %s up", server->conf->host, server->conf->port); + gettimeofday(&server->lastconnecttry, NULL); + pthread_mutex_unlock(&server->lock); + return 1; +} + +/* timeout in seconds, 0 means no timeout (blocking), returns when num bytes have been read, or timeout */ +/* returns 0 on timeout, -1 on error and num if ok */ +int sslreadtimeout(SSL *ssl, unsigned char *buf, int num, int timeout) { + int s, ndesc, cnt, len; + fd_set readfds, writefds; + struct timeval timer; + + s = SSL_get_fd(ssl); + if (s < 0) + return -1; + /* make socket non-blocking? */ + for (len = 0; len < num; len += cnt) { + FD_ZERO(&readfds); + FD_SET(s, &readfds); + writefds = readfds; + if (timeout) { + timer.tv_sec = timeout; + timer.tv_usec = 0; + } + ndesc = select(s + 1, &readfds, &writefds, NULL, timeout ? &timer : NULL); + if (ndesc < 1) + return ndesc; + + cnt = SSL_read(ssl, buf + len, num - len); + if (cnt <= 0) + switch (SSL_get_error(ssl, cnt)) { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + cnt = 0; + continue; + case SSL_ERROR_ZERO_RETURN: + /* remote end sent close_notify, send one back */ + SSL_shutdown(ssl); + return -1; + default: + return -1; + } + } + return num; +} + +/* timeout in seconds, 0 means no timeout (blocking) */ +unsigned char *radtlsget(SSL *ssl, int timeout) { + int cnt, len; + unsigned char buf[4], *rad; + + for (;;) { + cnt = sslreadtimeout(ssl, buf, 4, timeout); + if (cnt < 1) { + debug(DBG_DBG, cnt ? "radtlsget: connection lost" : "radtlsget: timeout"); + return NULL; + } + + len = RADLEN(buf); + rad = malloc(len); + if (!rad) { + debug(DBG_ERR, "radtlsget: malloc failed"); + continue; + } + memcpy(rad, buf, 4); + + cnt = sslreadtimeout(ssl, rad + 4, len - 4, timeout); + if (cnt < 1) { + debug(DBG_DBG, cnt ? "radtlsget: connection lost" : "radtlsget: timeout"); + free(rad); + return NULL; + } + + if (len >= 20) + break; + + free(rad); + debug(DBG_WARN, "radtlsget: packet smaller than minimum radius size"); + } + + debug(DBG_DBG, "radtlsget: got %d bytes", len); + return rad; +} + +int clientradputtls(struct server *server, unsigned char *rad) { + int cnt; + size_t len; + unsigned long error; + struct timeval lastconnecttry; + struct clsrvconf *conf = server->conf; + + len = RADLEN(rad); + lastconnecttry = server->lastconnecttry; + while ((cnt = SSL_write(server->ssl, rad, len)) <= 0) { + while ((error = ERR_get_error())) + debug(DBG_ERR, "clientradputtls: TLS: %s", ERR_error_string(error, NULL)); + if (server->dynamiclookuparg) + return 0; + tlsconnect(server, &lastconnecttry, 0, "clientradputtls"); + lastconnecttry = server->lastconnecttry; + } + + server->connectionok = 1; + debug(DBG_DBG, "clientradputtls: Sent %d bytes, Radius packet of length %d to TLS peer %s", cnt, len, conf->host); + return 1; +} + +void *tlsclientrd(void *arg) { + struct server *server = (struct server *)arg; + unsigned char *buf; + struct timeval now, lastconnecttry; + + for (;;) { + /* yes, lastconnecttry is really necessary */ + lastconnecttry = server->lastconnecttry; + buf = radtlsget(server->ssl, server->dynamiclookuparg ? IDLE_TIMEOUT : 0); + if (!buf) { + if (server->dynamiclookuparg) + break; + tlsconnect(server, &lastconnecttry, 0, "tlsclientrd"); + continue; + } + + if (!replyh(server, buf)) + free(buf); + if (server->dynamiclookuparg) { + gettimeofday(&now, NULL); + if (now.tv_sec - server->lastreply.tv_sec > IDLE_TIMEOUT) { + debug(DBG_INFO, "tlsclientrd: idle timeout for %s", server->conf->name); + break; + } + } + } + ERR_remove_state(0); + server->clientrdgone = 1; + return NULL; +} + +void *tlsserverwr(void *arg) { + int cnt; + unsigned long error; + struct client *client = (struct client *)arg; + struct queue *replyq; + struct reply *reply; + + debug(DBG_DBG, "tlsserverwr: starting for %s", client->conf->host); + replyq = client->replyq; + for (;;) { + pthread_mutex_lock(&replyq->mutex); + while (!list_first(replyq->entries)) { + if (client->ssl) { + debug(DBG_DBG, "tlsserverwr: waiting for signal"); + pthread_cond_wait(&replyq->cond, &replyq->mutex); + debug(DBG_DBG, "tlsserverwr: got signal"); + } + if (!client->ssl) { + /* ssl might have changed while waiting */ + pthread_mutex_unlock(&replyq->mutex); + debug(DBG_DBG, "tlsserverwr: exiting as requested"); + ERR_remove_state(0); + pthread_exit(NULL); + } + } + reply = (struct reply *)list_shift(replyq->entries); + pthread_mutex_unlock(&replyq->mutex); + cnt = SSL_write(client->ssl, reply->buf, RADLEN(reply->buf)); + if (cnt > 0) + debug(DBG_DBG, "tlsserverwr: sent %d bytes, Radius packet of length %d", + cnt, RADLEN(reply->buf)); + else + while ((error = ERR_get_error())) + debug(DBG_ERR, "tlsserverwr: SSL: %s", ERR_error_string(error, NULL)); + free(reply->buf); + free(reply); + } +} + +void tlsserverrd(struct client *client) { + struct request rq; + pthread_t tlsserverwrth; + + debug(DBG_DBG, "tlsserverrd: starting for %s", client->conf->host); + + if (pthread_create(&tlsserverwrth, NULL, tlsserverwr, (void *)client)) { + debug(DBG_ERR, "tlsserverrd: pthread_create failed"); + return; + } + + for (;;) { + memset(&rq, 0, sizeof(struct request)); + rq.buf = radtlsget(client->ssl, 0); + if (!rq.buf) { + debug(DBG_ERR, "tlsserverrd: connection from %s lost", client->conf->host); + break; + } + debug(DBG_DBG, "tlsserverrd: got Radius message from %s", client->conf->host); + rq.from = client; + if (!radsrv(&rq)) { + debug(DBG_ERR, "tlsserverrd: message authentication/validation failed, closing connection from %s", client->conf->host); + break; + } + } + + /* stop writer by setting ssl to NULL and give signal in case waiting for data */ + client->ssl = NULL; + pthread_mutex_lock(&client->replyq->mutex); + pthread_cond_signal(&client->replyq->cond); + pthread_mutex_unlock(&client->replyq->mutex); + debug(DBG_DBG, "tlsserverrd: waiting for writer to end"); + pthread_join(tlsserverwrth, NULL); + removeclientrqs(client); + debug(DBG_DBG, "tlsserverrd: reader for %s exiting", client->conf->host); +} + +void *tlsservernew(void *arg) { + int s; + struct sockaddr_storage from; + size_t fromlen = sizeof(from); + struct clsrvconf *conf; + struct list_node *cur = NULL; + SSL *ssl = NULL; + X509 *cert = NULL; + unsigned long error; + struct client *client; + + s = *(int *)arg; + if (getpeername(s, (struct sockaddr *)&from, &fromlen)) { + debug(DBG_DBG, "tlsservernew: getpeername failed, exiting"); + goto exit; + } + debug(DBG_WARN, "tlsservernew: incoming TLS connection from %s", addr2string((struct sockaddr *)&from, fromlen)); + + conf = find_clconf(RAD_TLS, (struct sockaddr *)&from, &cur); + if (conf) { + ssl = SSL_new(conf->ssl_ctx); + SSL_set_fd(ssl, s); + + if (SSL_accept(ssl) <= 0) { + while ((error = ERR_get_error())) + debug(DBG_ERR, "tlsservernew: SSL: %s", ERR_error_string(error, NULL)); + debug(DBG_ERR, "tlsservernew: SSL_accept failed"); + goto exit; + } + cert = verifytlscert(ssl); + if (!cert) + goto exit; + } + + while (conf) { + if (verifyconfcert(cert, conf)) { + X509_free(cert); + client = addclient(conf); + if (client) { + client->ssl = ssl; + tlsserverrd(client); + removeclient(client); + } else + debug(DBG_WARN, "tlsservernew: failed to create new client instance"); + goto exit; + } + conf = find_clconf(RAD_TLS, (struct sockaddr *)&from, &cur); + } + debug(DBG_WARN, "tlsservernew: ignoring request, no matching TLS client"); + if (cert) + X509_free(cert); + + exit: + SSL_free(ssl); + ERR_remove_state(0); + shutdown(s, SHUT_RDWR); + close(s); + pthread_exit(NULL); +} + +void *tlslistener(void *arg) { + pthread_t tlsserverth; + int s, *sp = (int *)arg; + struct sockaddr_storage from; + size_t fromlen = sizeof(from); + + listen(*sp, 0); + + for (;;) { + s = accept(*sp, (struct sockaddr *)&from, &fromlen); + if (s < 0) { + debug(DBG_WARN, "accept failed"); + continue; + } + if (pthread_create(&tlsserverth, NULL, tlsservernew, (void *)&s)) { + debug(DBG_ERR, "tlslistener: pthread_create failed"); + shutdown(s, SHUT_RDWR); + close(s); + continue; + } + pthread_detach(tlsserverth); + } + free(sp); + return NULL; +} @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2006-2008 Stig Venaas <venaas@uninett.no> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +int tlsconnect(struct server *server, struct timeval *when, int timeout, char *text); +int clientradputtls(struct server *server, unsigned char *rad); +void *tlsclientrd(void *arg); +void *tlslistener(void *arg); |