/*
- * Copyright (C) 2006-2008 Stig Venaas <venaas@uninett.no>
+ * Copyright (C) 2006-2009 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
#include <pthread.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
+#include "radsecproxy.h"
+#include "hostport.h"
+
+#ifdef RADPROT_TLS
#include "debug.h"
-#include "list.h"
#include "util.h"
-#include "radsecproxy.h"
-#include "tls.h"
+
+static void setprotoopts(struct commonprotoopts *opts);
+static char **getlistenerargs();
+void *tlslistener(void *arg);
+int tlsconnect(struct server *server, struct timeval *when, int timeout, char *text);
+void *tlsclientrd(void *arg);
+int clientradputtls(struct server *server, unsigned char *rad);
+void tlssetsrcres();
+
+static const struct protodefs protodefs = {
+ "tls",
+ "radsec", /* secretdefault */
+ SOCK_STREAM, /* socktype */
+ "2083", /* portdefault */
+ 0, /* retrycountdefault */
+ 0, /* retrycountmax */
+ REQUEST_RETRY_INTERVAL * REQUEST_RETRY_COUNT, /* retryintervaldefault */
+ 60, /* retryintervalmax */
+ DUPLICATE_INTERVAL, /* duplicateintervaldefault */
+ setprotoopts, /* setprotoopts */
+ getlistenerargs, /* getlistenerargs */
+ tlslistener, /* listener */
+ tlsconnect, /* connecter */
+ tlsclientrd, /* clientconnreader */
+ clientradputtls, /* clientradput */
+ NULL, /* addclient */
+ NULL, /* addserverextra */
+ tlssetsrcres, /* setsrcres */
+ NULL /* initextra */
+};
+
+static struct addrinfo *srcres = NULL;
+static uint8_t handle;
+static struct commonprotoopts *protoopts = NULL;
+
+const struct protodefs *tlsinit(uint8_t h) {
+ handle = h;
+ return &protodefs;
+}
+
+static void setprotoopts(struct commonprotoopts *opts) {
+ protoopts = opts;
+}
+
+static char **getlistenerargs() {
+ return protoopts ? protoopts->listenargs : NULL;
+}
+
+void tlssetsrcres() {
+ if (!srcres)
+ srcres =
+ resolvepassiveaddrinfo(protoopts ? protoopts->sourcearg : NULL,
+ AF_UNSPEC, NULL, protodefs.socktype);
+}
int tlsconnect(struct server *server, struct timeval *when, int timeout, char *text) {
struct timeval now;
time_t elapsed;
X509 *cert;
+ SSL_CTX *ctx = NULL;
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))) {
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");
+ if ((server->sock = connecttcphostlist(server->conf->hostports, srcres)) < 0)
continue;
- }
-
+
SSL_free(server->ssl);
- server->ssl = SSL_new(server->conf->ssl_ctx);
+ server->ssl = NULL;
+ ctx = tlsgetctx(handle, server->conf->tlsconf);
+ if (!ctx)
+ continue;
+ server->ssl = SSL_new(ctx);
+ if (!server->ssl)
+ continue;
+
SSL_set_fd(server->ssl, server->sock);
if (SSL_connect(server->ssl) <= 0) {
while ((error = ERR_get_error()))
}
X509_free(cert);
}
- debug(DBG_WARN, "tlsconnect: TLS connection to %s port %s up", server->conf->host, server->conf->port);
+ debug(DBG_WARN, "tlsconnect: TLS connection to %s up", server->conf->name);
+ server->connectionok = 1;
gettimeofday(&server->lastconnecttry, NULL);
pthread_mutex_unlock(&server->lock);
return 1;
int s, ndesc, cnt, len;
fd_set readfds, writefds;
struct timeval timer;
-
+
s = SSL_get_fd(ssl);
if (s < 0)
return -1;
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 cnt;
size_t len;
unsigned long error;
- struct timeval lastconnecttry;
struct clsrvconf *conf = server->conf;
-
+
+ if (!server->connectionok)
+ return 0;
len = RADLEN(rad);
- lastconnecttry = server->lastconnecttry;
- while ((cnt = SSL_write(server->ssl, rad, len)) <= 0) {
+ if ((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;
+ return 0;
}
- server->connectionok = 1;
- debug(DBG_DBG, "clientradputtls: Sent %d bytes, Radius packet of length %d to TLS peer %s", cnt, len, conf->host);
+ debug(DBG_DBG, "clientradputtls: Sent %d bytes, Radius packet of length %d to TLS peer %s", cnt, len, conf->name);
return 1;
}
struct server *server = (struct server *)arg;
unsigned char *buf;
struct timeval now, lastconnecttry;
-
+
for (;;) {
/* yes, lastconnecttry is really necessary */
lastconnecttry = server->lastconnecttry;
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);
+ struct gqueue *replyq;
+ struct request *reply;
+
+ debug(DBG_DBG, "tlsserverwr: starting for %s", addr2string(client->addr));
replyq = client->replyq;
for (;;) {
pthread_mutex_lock(&replyq->mutex);
while (!list_first(replyq->entries)) {
- if (client->ssl) {
+ if (client->ssl) {
debug(DBG_DBG, "tlsserverwr: waiting for signal");
pthread_cond_wait(&replyq->cond, &replyq->mutex);
debug(DBG_DBG, "tlsserverwr: got signal");
pthread_exit(NULL);
}
}
- reply = (struct reply *)list_shift(replyq->entries);
+ reply = (struct request *)list_shift(replyq->entries);
pthread_mutex_unlock(&replyq->mutex);
- cnt = SSL_write(client->ssl, reply->buf, RADLEN(reply->buf));
+ cnt = SSL_write(client->ssl, reply->replybuf, RADLEN(reply->replybuf));
if (cnt > 0)
- debug(DBG_DBG, "tlsserverwr: sent %d bytes, Radius packet of length %d",
- cnt, RADLEN(reply->buf));
+ debug(DBG_DBG, "tlsserverwr: sent %d bytes, Radius packet of length %d to %s",
+ cnt, RADLEN(reply->replybuf), addr2string(client->addr));
else
while ((error = ERR_get_error()))
debug(DBG_ERR, "tlsserverwr: SSL: %s", ERR_error_string(error, NULL));
- free(reply->buf);
- free(reply);
+ freerq(reply);
}
}
struct request *rq;
uint8_t *buf;
pthread_t tlsserverwrth;
-
- debug(DBG_DBG, "tlsserverrd: starting for %s", client->conf->host);
-
+
+ debug(DBG_DBG, "tlsserverrd: starting for %s", addr2string(client->addr));
+
if (pthread_create(&tlsserverwrth, NULL, tlsserverwr, (void *)client)) {
debug(DBG_ERR, "tlsserverrd: pthread_create failed");
return;
for (;;) {
buf = radtlsget(client->ssl, 0);
if (!buf) {
- debug(DBG_ERR, "tlsserverrd: connection from %s lost", client->conf->host);
+ debug(DBG_ERR, "tlsserverrd: connection from %s lost", addr2string(client->addr));
break;
}
- debug(DBG_DBG, "tlsserverrd: got Radius message from %s", client->conf->host);
+ debug(DBG_DBG, "tlsserverrd: got Radius message from %s", addr2string(client->addr));
rq = newrequest();
if (!rq) {
free(buf);
rq->buf = buf;
rq->from = client;
if (!radsrv(rq)) {
- debug(DBG_ERR, "tlsserverrd: message authentication/validation failed, closing connection from %s", client->conf->host);
+ debug(DBG_ERR, "tlsserverrd: message authentication/validation failed, closing connection from %s", addr2string(client->addr));
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_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);
+ debug(DBG_DBG, "tlsserverrd: reader for %s exiting", addr2string(client->addr));
}
void *tlsservernew(void *arg) {
int s;
struct sockaddr_storage from;
- size_t fromlen = sizeof(from);
+ socklen_t fromlen = sizeof(from);
struct clsrvconf *conf;
struct list_node *cur = NULL;
SSL *ssl = NULL;
X509 *cert = NULL;
+ SSL_CTX *ctx = NULL;
unsigned long error;
struct client *client;
debug(DBG_DBG, "tlsservernew: getpeername failed, exiting");
goto exit;
}
- debug(DBG_WARN, "tlsservernew: incoming TLS connection from %s", addr2string((struct sockaddr *)&from, fromlen));
+ debug(DBG_WARN, "tlsservernew: incoming TLS connection from %s", addr2string((struct sockaddr *)&from));
- conf = find_clconf(RAD_TLS, (struct sockaddr *)&from, &cur);
+ conf = find_clconf(handle, (struct sockaddr *)&from, &cur);
if (conf) {
- ssl = SSL_new(conf->ssl_ctx);
+ ctx = tlsgetctx(handle, conf->tlsconf);
+ if (!ctx)
+ goto exit;
+ ssl = SSL_new(ctx);
+ if (!ssl)
+ goto exit;
SSL_set_fd(ssl, s);
if (SSL_accept(ssl) <= 0) {
if (!cert)
goto exit;
}
-
+
while (conf) {
if (verifyconfcert(cert, conf)) {
X509_free(cert);
client = addclient(conf, 1);
if (client) {
client->ssl = ssl;
+ client->addr = addr_copy((struct sockaddr *)&from);
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);
+ conf = find_clconf(handle, (struct sockaddr *)&from, &cur);
}
debug(DBG_WARN, "tlsservernew: ignoring request, no matching TLS client");
if (cert)
X509_free(cert);
- exit:
+exit:
if (ssl) {
SSL_shutdown(ssl);
SSL_free(ssl);
pthread_t tlsserverth;
int s, *sp = (int *)arg;
struct sockaddr_storage from;
- size_t fromlen = sizeof(from);
+ socklen_t fromlen = sizeof(from);
listen(*sp, 0);
free(sp);
return NULL;
}
+#else
+const struct protodefs *tlsinit(uint8_t h) {
+ return NULL;
+}
+#endif
+
+/* Local Variables: */
+/* c-file-style: "stroustrup" */
+/* End: */