#include "util.h"
#include "gconfig.h"
#include "radsecproxy.h"
+#include "udp.h"
+#include "tcp.h"
+#include "tls.h"
+#include "dtls.h"
static struct options options;
-struct list *clconfs, *srvconfs, *realms, *tlsconfs, *rewriteconfs;
+static struct list *clconfs, *srvconfs;
+struct list *realms, *tlsconfs, *rewriteconfs;
-static struct addrinfo *srcprotores[3] = { NULL, NULL, NULL };
+static struct addrinfo *srcprotores[4] = { NULL, NULL, NULL, NULL };
-static struct replyq *udp_server_replyq = NULL;
+static struct queue *udp_server_replyq = NULL;
static int udp_client4_sock = -1;
static int udp_client6_sock = -1;
-static pthread_mutex_t *ssl_locks;
+static int dtls_client4_sock = -1;
+static int dtls_client6_sock = -1;
+static pthread_mutex_t tlsconfs_lock;
+static pthread_mutex_t *ssl_locks = NULL;
static long *ssl_lock_count;
extern int optind;
extern char *optarg;
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);
-
+
static const struct protodefs protodefs[] = {
{ "udp", /* UDP, assuming RAD_UDP defined as 0 */
NULL, /* secretdefault */
tcpclientrd, /* clientreader */
clientradputtcp /* clientradput */
},
+ { "dtls", /* DTLS, assuming RAD_DTLS defined as 3 */
+ "mysecret", /* secretdefault */
+ SOCK_DGRAM, /* socktype */
+ "2083", /* portdefault */
+ REQUEST_RETRY_COUNT, /* retrycountdefault */
+ 10, /* retrycountmax */
+ REQUEST_RETRY_INTERVAL, /* retryintervaldefault */
+ 60, /* retryintervalmax */
+ udpdtlsserverrd, /* listener */
+ &options.sourcedtls, /* srcaddrport */
+ dtlsconnect, /* connecter */
+ dtlsclientrd, /* clientreader */
+ clientradputdtls /* clientradput */
+ },
{ NULL
}
};
return ok;
}
+struct addrinfo *getsrcprotores(uint8_t type) {
+ return srcprotores[type];
+}
+
int resolvepeer(struct clsrvconf *conf, int ai_flags) {
struct addrinfo hints, *addrinfo, *res;
char *slash, *s;
return (((uint8_t *)a1)[l] & mask[r]) == (((uint8_t *)a2)[l] & mask[r]);
}
-/* check if conf has matching address */
-struct clsrvconf *checkconfaddr(uint8_t type, struct sockaddr *addr, struct clsrvconf *conf) {
- struct sockaddr_in6 *sa6 = NULL;
- struct in_addr *a4 = NULL;
- struct addrinfo *res;
-
- if (addr->sa_family == AF_INET6) {
- sa6 = (struct sockaddr_in6 *)addr;
- if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
- a4 = (struct in_addr *)&sa6->sin6_addr.s6_addr[12];
- sa6 = NULL;
- }
- } else
- a4 = &((struct sockaddr_in *)addr)->sin_addr;
-
- if (conf->type == type) {
- if (conf->prefixlen == 255) {
- for (res = conf->addrinfo; res; res = res->ai_next)
- if ((a4 && res->ai_family == AF_INET &&
- !memcmp(a4, &((struct sockaddr_in *)res->ai_addr)->sin_addr, 4)) ||
- (sa6 && res->ai_family == AF_INET6 &&
- !memcmp(&sa6->sin6_addr, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, 16)))
- return conf;
- } else {
- res = conf->addrinfo;
- if (res &&
- ((a4 && res->ai_family == AF_INET &&
- prefixmatch(a4, &((struct sockaddr_in *)res->ai_addr)->sin_addr, conf->prefixlen)) ||
- (sa6 && res->ai_family == AF_INET6 &&
- prefixmatch(&sa6->sin6_addr, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, conf->prefixlen))))
- return conf;
- }
- }
- return NULL;
-}
-
/* returns next config with matching address, or NULL */
struct clsrvconf *find_conf(uint8_t type, struct sockaddr *addr, struct list *confs, struct list_node **cur) {
struct sockaddr_in6 *sa6 = NULL;
return NULL;
}
+struct clsrvconf *find_clconf(uint8_t type, struct sockaddr *addr, struct list_node **cur) {
+ return find_conf(type, addr, clconfs, cur);
+}
+
+struct clsrvconf *find_srvconf(uint8_t type, struct sockaddr *addr, struct list_node **cur) {
+ return find_conf(type, addr, srvconfs, cur);
+}
+
/* returns next config of given type, or NULL */
struct clsrvconf *find_conf_type(uint8_t type, struct list *confs, struct list_node **cur) {
struct list_node *entry;
return NULL;
}
-struct replyq *newreplyq() {
- struct replyq *replyq;
+struct queue *newqueue() {
+ struct queue *q;
- replyq = malloc(sizeof(struct replyq));
- if (!replyq)
+ q = malloc(sizeof(struct queue));
+ if (!q)
debugx(1, DBG_ERR, "malloc failed");
- replyq->replies = list_create();
- if (!replyq->replies)
+ q->entries = list_create();
+ if (!q->entries)
debugx(1, DBG_ERR, "malloc failed");
- pthread_mutex_init(&replyq->mutex, NULL);
- pthread_cond_init(&replyq->cond, NULL);
- return replyq;
+ pthread_mutex_init(&q->mutex, NULL);
+ pthread_cond_init(&q->cond, NULL);
+ return q;
+}
+
+void removequeue(struct queue *q) {
+ struct list_node *entry;
+
+ pthread_mutex_lock(&q->mutex);
+ for (entry = list_first(q->entries); entry; entry = list_next(entry))
+ free(((struct reply *)entry)->buf);
+ list_destroy(q->entries);
+ pthread_cond_destroy(&q->cond);
+ pthread_mutex_unlock(&q->mutex);
+ pthread_mutex_destroy(&q->mutex);
+}
+
+void freebios(struct queue *q) {
+ BIO *bio;
+
+ pthread_mutex_lock(&q->mutex);
+ while ((bio = (BIO *)list_shift(q->entries)))
+ BIO_free(bio);
+ pthread_mutex_unlock(&q->mutex);
+ removequeue(q);
}
struct client *addclient(struct clsrvconf *conf) {
memset(new, 0, sizeof(struct client));
new->conf = conf;
- new->replyq = conf->type == RAD_UDP ? udp_server_replyq : newreplyq();
-
+ new->replyq = conf->type == RAD_UDP ? udp_server_replyq : newqueue();
+ if (conf->type == RAD_DTLS)
+ new->rbios = newqueue();
list_push(conf->clients, new);
return new;
}
void removeclient(struct client *client) {
- struct list_node *entry;
-
if (!client || !client->conf->clients)
return;
-
- pthread_mutex_lock(&client->replyq->mutex);
- for (entry = list_first(client->replyq->replies); entry; entry = list_next(entry))
- free(((struct reply *)entry)->buf);
- list_destroy(client->replyq->replies);
- pthread_cond_destroy(&client->replyq->cond);
- pthread_mutex_unlock(&client->replyq->mutex);
- pthread_mutex_destroy(&client->replyq->mutex);
+ removequeue(client->replyq);
+ if (client->rbios)
+ freebios(client->rbios);
list_removedata(client->conf->clients, client);
free(client);
}
if (!server)
return;
- if(server->requests) {
+ if (server->requests) {
rq = server->requests;
for (end = rq + MAX_REQUESTS; rq < end; rq++)
freerqdata(rq);
free(server->requests);
}
+ if (server->rbios)
+ freebios(server->rbios);
free(server->dynamiclookuparg);
if (destroymutex) {
pthread_mutex_destroy(&server->lock);
int addserver(struct clsrvconf *conf) {
struct clsrvconf *res;
+ uint8_t type;
if (conf->servers) {
debug(DBG_ERR, "addserver: currently works with just one server per conf");
memset(conf->servers, 0, sizeof(struct server));
conf->servers->conf = conf;
- if (!srcprotores[conf->type]) {
- res = resolve_hostport(conf->type, *conf->pdef->srcaddrport, NULL);
- srcprotores[conf->type] = res->addrinfo;
+ type = conf->type;
+ if (type == RAD_DTLS)
+ conf->servers->rbios = newqueue();
+
+ if (!srcprotores[type]) {
+ res = resolve_hostport(type, *conf->pdef->srcaddrport, NULL);
+ srcprotores[type] = res->addrinfo;
res->addrinfo = NULL;
freeclsrvres(res);
}
- if (conf->type == RAD_UDP) {
+ switch (type) {
+ case RAD_UDP:
switch (conf->addrinfo->ai_family) {
case AF_INET:
if (udp_client4_sock < 0) {
default:
debugx(1, DBG_ERR, "addserver: unsupported address family");
}
-
- } else
+ break;
+ case RAD_DTLS:
+ switch (conf->addrinfo->ai_family) {
+ case AF_INET:
+ if (dtls_client4_sock < 0) {
+ dtls_client4_sock = bindtoaddr(srcprotores[RAD_DTLS], AF_INET, 0, 1);
+ if (dtls_client4_sock < 0)
+ debugx(1, DBG_ERR, "addserver: failed to create client socket for server %s", conf->host);
+ }
+ conf->servers->sock = dtls_client4_sock;
+ break;
+ case AF_INET6:
+ if (dtls_client6_sock < 0) {
+ dtls_client6_sock = bindtoaddr(srcprotores[RAD_DTLS], AF_INET6, 0, 1);
+ if (dtls_client6_sock < 0)
+ debugx(1, DBG_ERR, "addserver: failed to create client socket for server %s", conf->host);
+ }
+ conf->servers->sock = dtls_client6_sock;
+ break;
+ default:
+ debugx(1, DBG_ERR, "addserver: unsupported address family");
+ }
+ break;
+ default:
conf->servers->sock = -1;
+ }
conf->servers->requests = calloc(MAX_REQUESTS, sizeof(struct request));
if (!conf->servers->requests) {
return 0;
}
-/* exactly one of client and server must be non-NULL */
-/* should probably take peer list (client(s) or server(s)) as argument instead */
-/* if *peer == NULL we return who we received from, else require it to be from peer */
-/* return from in sa if not NULL */
-unsigned char *radudpget(int s, struct client **client, struct server **server, struct sockaddr_storage *sa) {
- int cnt, len;
- unsigned char buf[4], *rad;
- struct sockaddr_storage from;
- socklen_t fromlen = sizeof(from);
- struct clsrvconf *p;
- struct list_node *node;
-
- for (;;) {
- cnt = recvfrom(s, buf, 4, MSG_PEEK, (struct sockaddr *)&from, &fromlen);
- if (cnt == -1) {
- debug(DBG_WARN, "radudpget: recv failed");
- continue;
- }
-
- if (client)
- if (*client)
- p = checkconfaddr(RAD_UDP, (struct sockaddr *)&from, (*client)->conf);
- else
- p = find_conf(RAD_UDP, (struct sockaddr *)&from, clconfs, NULL);
- else
- if (*server)
- p = checkconfaddr(RAD_UDP, (struct sockaddr *)&from, (*server)->conf);
- else
- p = find_conf(RAD_UDP, (struct sockaddr *)&from, srvconfs, NULL);
-
- if (!p) {
- debug(DBG_WARN, "radudpget: got packet from wrong or unknown UDP peer %s, ignoring", addr2string((struct sockaddr *)&from, fromlen));
- recv(s, buf, 4, 0);
- continue;
- }
-
- len = RADLEN(buf);
- if (len < 20) {
- debug(DBG_WARN, "radudpget: length too small");
- recv(s, buf, 4, 0);
- continue;
- }
-
- rad = malloc(len);
- if (!rad) {
- debug(DBG_ERR, "radudpget: malloc failed");
- recv(s, buf, 4, 0);
- continue;
- }
-
- cnt = recv(s, rad, len, MSG_TRUNC);
- debug(DBG_DBG, "radudpget: got %d bytes from %s", cnt, addr2string((struct sockaddr *)&from, fromlen));
-
- if (cnt < len) {
- debug(DBG_WARN, "radudpget: packet smaller than length field in radius header");
- free(rad);
- continue;
- }
-
- if (cnt > len)
- debug(DBG_DBG, "radudpget: packet was padded with %d bytes", cnt - len);
-
- if (client && !*client) {
- node = list_first(p->clients);
- *client = node ? (struct client *)node->data : addclient(p);
- if (!*client) {
- free(rad);
- continue;
- }
- } else if (server && !*server)
- *server = p->servers;
-
- break;
- }
- if (sa)
- *sa = from;
- return rad;
-}
-
int subjectaltnameaddr(X509 *cert, int family, struct in6_addr *addr) {
int loc, i, l, n, r = 0;
char *v;
return 1;
}
-int tlsconnect(struct server *server, struct timeval *when, int timeout, char *text) {
- struct timeval now;
- time_t elapsed;
- X509 *cert;
-
- 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)
- 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;
-}
-
-int tcpconnect(struct server *server, struct timeval *when, int timeout, char *text) {
- struct timeval now;
- time_t elapsed;
-
- debug(DBG_DBG, "tcpconnect: 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, "tcpconnect(%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, "tcpconnect: timeout");
- if (server->sock >= 0)
- close(server->sock);
- 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, "tcpconnect: sleeping %lds", elapsed);
- sleep(elapsed);
- } else if (elapsed < 100000) {
- debug(DBG_INFO, "tcpconnect: sleeping %ds", 60);
- sleep(60);
- } else
- server->lastconnecttry.tv_sec = now.tv_sec; /* no sleep at startup */
- debug(DBG_WARN, "tcpconnect: trying to open TCP 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_TCP])) >= 0)
- break;
- debug(DBG_ERR, "tcpconnect: connecttcp failed");
- }
- debug(DBG_WARN, "tcpconnect: TCP 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);
- /* fall through */
- 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;
-}
-
-/* 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 tcpreadtimeout(int s, unsigned char *buf, int num, int timeout) {
- int ndesc, cnt, len;
- fd_set readfds, writefds;
- struct timeval timer;
-
- 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 = read(s, buf + len, num - len);
- if (cnt <= 0)
- return -1;
- }
- return num;
-}
-
-/* timeout in seconds, 0 means no timeout (blocking) */
-unsigned char *radtcpget(int s, int timeout) {
- int cnt, len;
- unsigned char buf[4], *rad;
-
- for (;;) {
- cnt = tcpreadtimeout(s, buf, 4, timeout);
- if (cnt < 1) {
- debug(DBG_DBG, cnt ? "radtcpget: connection lost" : "radtcpget: timeout");
- return NULL;
- }
-
- len = RADLEN(buf);
- rad = malloc(len);
- if (!rad) {
- debug(DBG_ERR, "radtcpget: malloc failed");
- continue;
- }
- memcpy(rad, buf, 4);
-
- cnt = tcpreadtimeout(s, rad + 4, len - 4, timeout);
- if (cnt < 1) {
- debug(DBG_DBG, cnt ? "radtcpget: connection lost" : "radtcpget: timeout");
- free(rad);
- return NULL;
- }
-
- if (len >= 20)
- break;
-
- free(rad);
- debug(DBG_WARN, "radtcpget: packet smaller than minimum radius size");
- }
-
- debug(DBG_DBG, "radtcpget: got %d bytes", len);
- return rad;
-}
-
-int clientradputudp(struct server *server, unsigned char *rad) {
- size_t len;
- struct sockaddr_storage sa;
- struct sockaddr *sap;
- struct clsrvconf *conf = server->conf;
- in_port_t *port = NULL;
-
- len = RADLEN(rad);
-
- if (*rad == RAD_Accounting_Request) {
- sap = (struct sockaddr *)&sa;
- memcpy(sap, conf->addrinfo->ai_addr, conf->addrinfo->ai_addrlen);
- } else
- sap = conf->addrinfo->ai_addr;
-
- switch (sap->sa_family) {
- case AF_INET:
- port = &((struct sockaddr_in *)sap)->sin_port;
- break;
- case AF_INET6:
- port = &((struct sockaddr_in6 *)sap)->sin6_port;
- break;
- default:
- return 0;
- }
-
- if (*rad == RAD_Accounting_Request)
- *port = htons(ntohs(*port) + 1);
-
- if (sendto(server->sock, rad, len, 0, sap, conf->addrinfo->ai_addrlen) >= 0) {
- debug(DBG_DBG, "clienradputudp: sent UDP of length %d to %s port %d", len, conf->host, ntohs(*port));
- return 1;
- }
-
- debug(DBG_WARN, "clientradputudp: send failed");
- 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 clientradputtcp(struct server *server, unsigned char *rad) {
- int cnt;
- size_t len;
- struct timeval lastconnecttry;
- struct clsrvconf *conf = server->conf;
-
- len = RADLEN(rad);
- lastconnecttry = server->lastconnecttry;
- while ((cnt = write(server->sock, rad, len)) <= 0) {
- debug(DBG_ERR, "clientradputtcp: write error");
- tcpconnect(server, &lastconnecttry, 0, "clientradputtcp");
- lastconnecttry = server->lastconnecttry;
- }
-
- server->connectionok = 1;
- debug(DBG_DBG, "clientradputtcp: Sent %d bytes, Radius packet of length %d to TCP 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;
pthread_mutex_lock(&to->replyq->mutex);
- first = list_first(to->replyq->replies) == NULL;
+ first = list_first(to->replyq->entries) == NULL;
- if (!list_push(to->replyq->replies, reply)) {
+ if (!list_push(to->replyq->entries, reply)) {
pthread_mutex_unlock(&to->replyq->mutex);
free(reply);
free(buf);
return 1;
}
-void *udpclientrd(void *arg) {
- struct server *server;
- unsigned char *buf;
- int *s = (int *)arg;
-
- for (;;) {
- server = NULL;
- buf = radudpget(*s, NULL, &server, NULL);
- if (!replyh(server, buf))
- free(buf);
- }
-}
-
-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;
- }
- }
- }
- server->clientrdgone = 1;
- return NULL;
-}
-
-void *tcpclientrd(void *arg) {
- struct server *server = (struct server *)arg;
- unsigned char *buf;
- struct timeval lastconnecttry;
-
- for (;;) {
- /* yes, lastconnecttry is really necessary */
- lastconnecttry = server->lastconnecttry;
- buf = radtcpget(server->sock, 0);
- if (!buf) {
- tcpconnect(server, &lastconnecttry, 0, "tcpclientrd");
- continue;
- }
-
- if (!replyh(server, buf))
- free(buf);
- }
- server->clientrdgone = 1;
- return NULL;
-}
-
/* code for removing state not finished */
void *clientwr(void *arg) {
struct server *server = (struct server *)arg;
freeclsrvconf(conf);
}
freeserver(server, 1);
- return NULL;
-}
-
-void *udpserverwr(void *arg) {
- struct replyq *replyq = udp_server_replyq;
- struct reply *reply;
-
- for (;;) {
- pthread_mutex_lock(&replyq->mutex);
- while (!(reply = (struct reply *)list_shift(replyq->replies))) {
- debug(DBG_DBG, "udp server writer, waiting for signal");
- pthread_cond_wait(&replyq->cond, &replyq->mutex);
- debug(DBG_DBG, "udp server writer, got signal");
- }
- pthread_mutex_unlock(&replyq->mutex);
-
- if (sendto(reply->toudpsock, reply->buf, RADLEN(reply->buf), 0,
- (struct sockaddr *)&reply->tosa, SOCKADDR_SIZE(reply->tosa)) < 0)
- debug(DBG_WARN, "sendudp: send failed");
- free(reply->buf);
- free(reply);
- }
-}
-
-void *udpserverrd(void *arg) {
- struct request rq;
- int *sp = (int *)arg;
-
- for (;;) {
- memset(&rq, 0, sizeof(struct request));
- rq.buf = radudpget(*sp, &rq.from, NULL, &rq.fromsa);
- rq.fromudpsock = *sp;
- radsrv(&rq);
- }
- free(sp);
-}
-
-void *tlsserverwr(void *arg) {
- int cnt;
- unsigned long error;
- struct client *client = (struct client *)arg;
- struct replyq *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->replies)) {
- 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");
- pthread_exit(NULL);
- }
- }
- reply = (struct reply *)list_shift(replyq->replies);
- 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);
- 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 *tcpserverwr(void *arg) {
- int cnt;
- struct client *client = (struct client *)arg;
- struct replyq *replyq;
- struct reply *reply;
-
- debug(DBG_DBG, "tcpserverwr: starting for %s", client->conf->host);
- replyq = client->replyq;
- for (;;) {
- pthread_mutex_lock(&replyq->mutex);
- while (!list_first(replyq->replies)) {
- if (client->s >= 0) {
- debug(DBG_DBG, "tcpserverwr: waiting for signal");
- pthread_cond_wait(&replyq->cond, &replyq->mutex);
- debug(DBG_DBG, "tcpserverwr: got signal");
- }
- if (client->s < 0) {
- /* s might have changed while waiting */
- pthread_mutex_unlock(&replyq->mutex);
- debug(DBG_DBG, "tcpserverwr: exiting as requested");
- pthread_exit(NULL);
- }
- }
- reply = (struct reply *)list_shift(replyq->replies);
- pthread_mutex_unlock(&replyq->mutex);
- cnt = write(client->s, reply->buf, RADLEN(reply->buf));
- if (cnt > 0)
- debug(DBG_DBG, "tcpserverwr: sent %d bytes, Radius packet of length %d",
- cnt, RADLEN(reply->buf));
- else
- debug(DBG_ERR, "tcpserverwr: write error for %s", client->conf->host);
- free(reply->buf);
- free(reply);
- }
-}
-
-void tcpserverrd(struct client *client) {
- struct request rq;
- pthread_t tcpserverwrth;
-
- debug(DBG_DBG, "tcpserverrd: starting for %s", client->conf->host);
-
- if (pthread_create(&tcpserverwrth, NULL, tcpserverwr, (void *)client)) {
- debug(DBG_ERR, "tcpserverrd: pthread_create failed");
- return;
- }
-
- for (;;) {
- memset(&rq, 0, sizeof(struct request));
- rq.buf = radtcpget(client->s, 0);
- if (!rq.buf) {
- debug(DBG_ERR, "tcpserverrd: connection from %s lost", client->conf->host);
- break;
- }
- debug(DBG_DBG, "tcpserverrd: got Radius message from %s", client->conf->host);
- rq.from = client;
- if (!radsrv(&rq)) {
- debug(DBG_ERR, "tcpserverrd: message authentication/validation failed, closing connection from %s", client->conf->host);
- break;
- }
- }
-
- /* stop writer by setting s to -1 and give signal in case waiting for data */
- client->s = -1;
- pthread_mutex_lock(&client->replyq->mutex);
- pthread_cond_signal(&client->replyq->cond);
- pthread_mutex_unlock(&client->replyq->mutex);
- debug(DBG_DBG, "tcpserverrd: waiting for writer to end");
- pthread_join(tcpserverwrth, NULL);
- removeclientrqs(client);
- debug(DBG_DBG, "tcpserverrd: reader for %s exiting", client->conf->host);
-}
-
-void *tcpservernew(void *arg) {
- int s;
- struct sockaddr_storage from;
- size_t fromlen = sizeof(from);
- struct clsrvconf *conf;
- struct client *client;
-
- s = *(int *)arg;
- if (getpeername(s, (struct sockaddr *)&from, &fromlen)) {
- debug(DBG_DBG, "tcpservernew: getpeername failed, exiting");
- goto exit;
- }
- debug(DBG_WARN, "tcpservernew: incoming TCP connection from %s", addr2string((struct sockaddr *)&from, fromlen));
-
- conf = find_conf(RAD_TCP, (struct sockaddr *)&from, clconfs, NULL);
- if (conf) {
- client = addclient(conf);
- if (client) {
- client->s = s;
- tcpserverrd(client);
- removeclient(client);
- } else
- debug(DBG_WARN, "tcpservernew: failed to create new client instance");
- } else
- debug(DBG_WARN, "tcpservernew: ignoring request, no matching TCP client");
-
- exit:
- shutdown(s, SHUT_RDWR);
- close(s);
- pthread_exit(NULL);
-}
-
-void *tcplistener(void *arg) {
- pthread_t tcpserverth;
- 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(&tcpserverth, NULL, tcpservernew, (void *)&s)) {
- debug(DBG_ERR, "tcplistener: pthread_create failed");
- shutdown(s, SHUT_RDWR);
- close(s);
- continue;
- }
- pthread_detach(tcpserverth);
- }
- free(sp);
+ ERR_remove_state(0);
return NULL;
}
createlistener(type, NULL);
}
-void tlsadd(char *value, char *cacertfile, char *cacertpath, char *certfile, char *certkeyfile, char *certkeypwd, uint8_t crlcheck) {
- struct tls *new;
- SSL_CTX *ctx;
+#ifdef DEBUG
+void ssl_info_callback(const SSL *ssl, int where, int ret) {
+ const char *s;
+ int w;
+
+ w = where & ~SSL_ST_MASK;
+
+ if (w & SSL_ST_CONNECT)
+ s = "SSL_connect";
+ else if (w & SSL_ST_ACCEPT)
+ s = "SSL_accept";
+ else
+ s = "undefined";
+
+ if (where & SSL_CB_LOOP)
+ debug(DBG_DBG, "%s:%s\n", s, SSL_state_string_long(ssl));
+ else if (where & SSL_CB_ALERT) {
+ s = (where & SSL_CB_READ) ? "read" : "write";
+ debug(DBG_DBG, "SSL3 alert %s:%s:%s\n", s, SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret));
+ }
+ else if (where & SSL_CB_EXIT) {
+ if (ret == 0)
+ debug(DBG_DBG, "%s:failed in %s\n", s, SSL_state_string_long(ssl));
+ else if (ret < 0)
+ debug(DBG_DBG, "%s:error in %s\n", s, SSL_state_string_long(ssl));
+ }
+}
+#endif
+
+SSL_CTX *tlscreatectx(uint8_t type, struct tls *conf) {
+ SSL_CTX *ctx = NULL;
STACK_OF(X509_NAME) *calist;
X509_STORE *x509_s;
int i;
unsigned long error;
-
- if (!certfile || !certkeyfile)
- debugx(1, DBG_ERR, "TLSCertificateFile and TLSCertificateKeyFile must be specified in TLS context %s", value);
-
- if (!cacertfile && !cacertpath)
- debugx(1, DBG_ERR, "CA Certificate file or path need to be specified in TLS context %s", value);
if (!ssl_locks) {
ssl_locks = malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
RAND_seed((unsigned char *)&pid, sizeof(pid));
}
}
- ctx = SSL_CTX_new(TLSv1_method());
- if (certkeypwd) {
- SSL_CTX_set_default_passwd_cb_userdata(ctx, certkeypwd);
+
+ switch (type) {
+ case RAD_TLS:
+ ctx = SSL_CTX_new(TLSv1_method());
+#ifdef DEBUG
+ SSL_CTX_set_info_callback(ctx, ssl_info_callback);
+#endif
+ break;
+ case RAD_DTLS:
+ ctx = SSL_CTX_new(DTLSv1_method());
+#ifdef DEBUG
+ SSL_CTX_set_info_callback(ctx, ssl_info_callback);
+#endif
+ SSL_CTX_set_read_ahead(ctx, 1);
+ break;
+ }
+ if (!ctx) {
+ debug(DBG_ERR, "tlscreatectx: Error initialising SSL/TLS in TLS context %s", conf->name);
+ return NULL;
+ }
+
+ if (conf->certkeypwd) {
+ SSL_CTX_set_default_passwd_cb_userdata(ctx, conf->certkeypwd);
SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
}
- if (!SSL_CTX_use_certificate_chain_file(ctx, certfile) ||
- !SSL_CTX_use_PrivateKey_file(ctx, certkeyfile, SSL_FILETYPE_PEM) ||
+ if (!SSL_CTX_use_certificate_chain_file(ctx, conf->certfile) ||
+ !SSL_CTX_use_PrivateKey_file(ctx, conf->certkeyfile, SSL_FILETYPE_PEM) ||
!SSL_CTX_check_private_key(ctx) ||
- !SSL_CTX_load_verify_locations(ctx, cacertfile, cacertpath)) {
+ !SSL_CTX_load_verify_locations(ctx, conf->cacertfile, conf->cacertpath)) {
while ((error = ERR_get_error()))
debug(DBG_ERR, "SSL: %s", ERR_error_string(error, NULL));
- debugx(1, DBG_ERR, "Error initialising SSL/TLS in TLS context %s", value);
+ debug(DBG_ERR, "tlscreatectx: Error initialising SSL/TLS in TLS context %s", conf->name);
+ SSL_CTX_free(ctx);
+ return NULL;
}
- calist = cacertfile ? SSL_load_client_CA_file(cacertfile) : NULL;
- if (!cacertfile || calist) {
- if (cacertpath) {
+ calist = conf->cacertfile ? SSL_load_client_CA_file(conf->cacertfile) : NULL;
+ if (!conf->cacertfile || calist) {
+ if (conf->cacertpath) {
if (!calist)
calist = sk_X509_NAME_new_null();
- if (!SSL_add_dir_cert_subjects_to_stack(calist, cacertpath)) {
+ if (!SSL_add_dir_cert_subjects_to_stack(calist, conf->cacertpath)) {
sk_X509_NAME_free(calist);
calist = NULL;
}
if (!calist) {
while ((error = ERR_get_error()))
debug(DBG_ERR, "SSL: %s", ERR_error_string(error, NULL));
- debugx(1, DBG_ERR, "Error adding CA subjects in TLS context %s", value);
+ debug(DBG_ERR, "tlscreatectx: Error adding CA subjects in TLS context %s", conf->name);
+ SSL_CTX_free(ctx);
+ return NULL;
}
+ ERR_clear_error(); /* add_dir_cert_subj returns errors on success */
SSL_CTX_set_client_CA_list(ctx, calist);
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb);
SSL_CTX_set_verify_depth(ctx, MAX_CERT_DEPTH + 1);
- if (crlcheck) {
+ if (conf->crlcheck) {
x509_s = SSL_CTX_get_cert_store(ctx);
X509_STORE_set_flags(x509_s, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
}
- new = malloc(sizeof(struct tls));
- if (!new || !list_push(tlsconfs, new))
- debugx(1, DBG_ERR, "malloc failed");
-
- memset(new, 0, sizeof(struct tls));
- new->name = stringcopy(value, 0);
- if (!new->name)
- debugx(1, DBG_ERR, "malloc failed");
- new->ctx = ctx;
- debug(DBG_DBG, "tlsadd: added TLS context %s", value);
+ debug(DBG_DBG, "tlscreatectx: created TLS context %s", conf->name);
+ return ctx;
}
-SSL_CTX *tlsgetctx(char *alt1, char *alt2) {
+SSL_CTX *tlsgetctx(uint8_t type, char *alt1, char *alt2) {
struct list_node *entry;
struct tls *t, *t1 = NULL, *t2 = NULL;
+ SSL_CTX *ctx = NULL;
+
+ pthread_mutex_lock(&tlsconfs_lock);
for (entry = list_first(tlsconfs); entry; entry = list_next(entry)) {
t = (struct tls *)entry->data;
t = (t1 ? t1 : t2);
if (!t)
- return NULL;
- return t->ctx;
+ goto exit;
+
+ switch (type) {
+ case RAD_TLS:
+ if (!t->tlsctx)
+ t->tlsctx = tlscreatectx(RAD_TLS, t);
+ ctx = t->tlsctx;
+ break;
+ case RAD_DTLS:
+ if (!t->dtlsctx)
+ t->dtlsctx = tlscreatectx(RAD_DTLS, t);
+ ctx = t->dtlsctx;
+ break;
+ }
+
+ exit:
+ pthread_mutex_unlock(&tlsconfs_lock);
+ return ctx;
}
struct list *addsrvconfs(char *value, char **names) {
conf->name = stringcopy(val, 0);
if (!conf->host)
conf->host = stringcopy(val, 0);
-
+ if (!conf->name || !conf->host)
+ debugx(1, DBG_ERR, "malloc failed");
+
if (!conftype)
debugx(1, DBG_ERR, "error in block %s, option type missing", block);
conf->type = protoname2int(conftype);
debugx(1, DBG_ERR, "error in block %s, unknown transport %s", block, conftype);
free(conftype);
- if (conf->type == RAD_TLS) {
- conf->ssl_ctx = conf->tls ? tlsgetctx(conf->tls, NULL) : tlsgetctx("defaultclient", "default");
+ if (conf->type == RAD_TLS || conf->type == RAD_DTLS) {
+ conf->ssl_ctx = conf->tls ? tlsgetctx(conf->type, conf->tls, NULL) : tlsgetctx(conf->type, "defaultclient", "default");
if (!conf->ssl_ctx)
debugx(1, DBG_ERR, "error in block %s, no tls context defined", block);
if (conf->matchcertattr && !addmatchcertattr(conf))
}
int compileserverconfig(struct clsrvconf *conf, const char *block) {
- if (conf->type == RAD_TLS) {
- conf->ssl_ctx = conf->tls ? tlsgetctx(conf->tls, NULL) : tlsgetctx("defaultserver", "default");
+ if (conf->type == RAD_TLS || conf->type == RAD_DTLS) {
+ conf->ssl_ctx = conf->tls ? tlsgetctx(conf->type, conf->tls, NULL) : tlsgetctx(conf->type, "defaultserver", "default");
if (!conf->ssl_ctx) {
debug(DBG_ERR, "error in block %s, no tls context defined", block);
return 0;
}
int conftls_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val) {
- char *cacertfile = NULL, *cacertpath = NULL, *certfile = NULL, *certkeyfile = NULL, *certkeypwd = NULL;
- uint8_t crlcheck = 0;
+ struct tls *conf;
debug(DBG_DBG, "conftls_cb called for %s", block);
+ conf = malloc(sizeof(struct tls));
+ if (!conf) {
+ debug(DBG_ERR, "conftls_cb: malloc failed");
+ return 0;
+ }
+ memset(conf, 0, sizeof(struct tls));
+
if (!getgenericconfig(cf, block,
- "CACertificateFile", CONF_STR, &cacertfile,
- "CACertificatePath", CONF_STR, &cacertpath,
- "CertificateFile", CONF_STR, &certfile,
- "CertificateKeyFile", CONF_STR, &certkeyfile,
- "CertificateKeyPassword", CONF_STR, &certkeypwd,
- "CRLCheck", CONF_BLN, &crlcheck,
+ "CACertificateFile", CONF_STR, &conf->cacertfile,
+ "CACertificatePath", CONF_STR, &conf->cacertpath,
+ "CertificateFile", CONF_STR, &conf->certfile,
+ "CertificateKeyFile", CONF_STR, &conf->certkeyfile,
+ "CertificateKeyPassword", CONF_STR, &conf->certkeypwd,
+ "CRLCheck", CONF_BLN, &conf->crlcheck,
NULL
- ))
- debugx(1, DBG_ERR, "configuration error");
+ )) {
+ debug(DBG_ERR, "conftls_cb: configuration error in block %s", val);
+ goto errexit;
+ }
+ if (!conf->certfile || !conf->certkeyfile) {
+ debug(DBG_ERR, "conftls_cb: TLSCertificateFile and TLSCertificateKeyFile must be specified in block %s", val);
+ goto errexit;
+ }
+ if (!conf->cacertfile && !conf->cacertpath) {
+ debug(DBG_ERR, "conftls_cb: CA Certificate file or path need to be specified in block %s", val);
+ goto errexit;
+ }
+
+ conf->name = stringcopy(val, 0);
+ if (!conf->name) {
+ debug(DBG_ERR, "conftls_cb: malloc failed");
+ goto errexit;
+ }
- tlsadd(val, cacertfile, cacertpath, certfile, certkeyfile, certkeypwd, crlcheck);
- free(cacertfile);
- free(cacertpath);
- free(certfile);
- free(certkeyfile);
- free(certkeypwd);
+ pthread_mutex_lock(&tlsconfs_lock);
+ if (!list_push(tlsconfs, conf)) {
+ debug(DBG_ERR, "conftls_cb: malloc failed");
+ pthread_mutex_unlock(&tlsconfs_lock);
+ goto errexit;
+ }
+ pthread_mutex_unlock(&tlsconfs_lock);
+
+ debug(DBG_DBG, "conftls_cb: added TLS block %s", val);
return 1;
+
+ errexit:
+ free(conf->cacertfile);
+ free(conf->cacertpath);
+ free(conf->certfile);
+ free(conf->certkeyfile);
+ free(conf->certkeypwd);
+ free(conf);
+ return 0;
}
int confrewrite_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val) {
"ListenUDP", CONF_MSTR, &options.listenudp,
"ListenTCP", CONF_MSTR, &options.listentcp,
"ListenTLS", CONF_MSTR, &options.listentls,
+ "ListenDTLS", CONF_MSTR, &options.listendtls,
"ListenAccountingUDP", CONF_MSTR, &options.listenaccudp,
"SourceUDP", CONF_STR, &options.sourceudp,
"SourceTCP", CONF_STR, &options.sourcetcp,
"SourceTLS", CONF_STR, &options.sourcetls,
+ "SourceDTLS", CONF_STR, &options.sourcedtls,
"LogLevel", CONF_LINT, &loglevel,
"LogDestination", CONF_STR, &options.logdestination,
"LoopPrevention", CONF_BLN, &options.loopprevention,
}
int main(int argc, char **argv) {
- pthread_t sigth, udpclient4rdth, udpclient6rdth, udpserverwrth;
+ pthread_t sigth, udpclient4rdth, udpclient6rdth, udpserverwrth, dtlsclient4rdth, dtlsclient6rdth;
sigset_t sigset;
struct list_node *entry;
uint8_t foreground = 0, pretend = 0, loglevel = 0;
debug_init("radsecproxy");
debug_set_level(DEBUG_LEVEL);
+ pthread_mutex_init(&tlsconfs_lock, NULL);
+
getargs(argc, argv, &foreground, &pretend, &loglevel, &configfile);
if (loglevel)
debug_set_level(loglevel);
if (!list_first(clconfs))
debugx(1, DBG_ERR, "No clients configured, nothing to do, exiting");
- if (!list_first(srvconfs))
- debugx(1, DBG_ERR, "No servers configured, nothing to do, exiting");
if (!list_first(realms))
debugx(1, DBG_ERR, "No realms configured, nothing to do, exiting");
pthread_sigmask(SIG_BLOCK, &sigset, NULL);
pthread_create(&sigth, NULL, sighandler, NULL);
- if (find_conf_type(RAD_UDP, clconfs, NULL)) {
- udp_server_replyq = newreplyq();
- if (pthread_create(&udpserverwrth, NULL, udpserverwr, NULL))
- debugx(1, DBG_ERR, "pthread_create failed");
- createlisteners(RAD_UDP, options.listenudp);
- if (options.listenaccudp)
- createlisteners(RAD_UDP, options.listenaccudp);
- }
-
for (entry = list_first(srvconfs); entry; entry = list_next(entry)) {
srvconf = (struct clsrvconf *)entry->data;
if (srvconf->dynamiclookupcommand)
freeaddrinfo(srcprotores[RAD_UDP]);
srcprotores[RAD_UDP] = NULL;
}
+
if (udp_client4_sock >= 0)
if (pthread_create(&udpclient4rdth, NULL, protodefs[RAD_UDP].clientreader, (void *)&udp_client4_sock))
debugx(1, DBG_ERR, "pthread_create failed");
if (pthread_create(&udpclient6rdth, NULL, protodefs[RAD_UDP].clientreader, (void *)&udp_client6_sock))
debugx(1, DBG_ERR, "pthread_create failed");
+ if (dtls_client4_sock >= 0)
+ if (pthread_create(&dtlsclient4rdth, NULL, udpdtlsclientrd, (void *)&dtls_client4_sock))
+ debugx(1, DBG_ERR, "pthread_create failed");
+ if (dtls_client6_sock >= 0)
+ if (pthread_create(&dtlsclient6rdth, NULL, udpdtlsclientrd, (void *)&dtls_client6_sock))
+ debugx(1, DBG_ERR, "pthread_create failed");
+
if (find_conf_type(RAD_TCP, clconfs, NULL))
createlisteners(RAD_TCP, options.listentcp);
if (find_conf_type(RAD_TLS, clconfs, NULL))
createlisteners(RAD_TLS, options.listentls);
+ if (find_conf_type(RAD_DTLS, clconfs, NULL))
+ createlisteners(RAD_DTLS, options.listendtls);
+
+ if (find_conf_type(RAD_UDP, clconfs, NULL)) {
+ udp_server_replyq = newqueue();
+ if (pthread_create(&udpserverwrth, NULL, udpserverwr, (void *)udp_server_replyq))
+ debugx(1, DBG_ERR, "pthread_create failed");
+ createlisteners(RAD_UDP, options.listenudp);
+ if (options.listenaccudp)
+ createlisteners(RAD_UDP, options.listenaccudp);
+ }
+
/* just hang around doing nothing, anything to do here? */
for (;;)
sleep(1000);