summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvenaas <venaas>2008-09-23 15:21:50 +0000
committervenaas <venaas@e88ac4ed-0b26-0410-9574-a7f39faa03bf>2008-09-23 15:21:50 +0000
commite8d23e687d8e2c490ec0532505f31912696a21a5 (patch)
tree55112d55f18d8ea60e27f9018e5ebb3ffa593e7a
parent842497d6a8b72999e70613fa8d5ff1ee6acc1ecf (diff)
make clientwr not try to connect (left to reader), changed some timing stuff, issue with statusserver and connection down..., added optional cacheexpiry option for tls blocks
git-svn-id: https://svn.testnett.uninett.no/radsecproxy/branches/release-1.1@398 e88ac4ed-0b26-0410-9574-a7f39faa03bf
-rw-r--r--radsecproxy.c190
-rw-r--r--radsecproxy.h11
2 files changed, 117 insertions, 84 deletions
diff --git a/radsecproxy.c b/radsecproxy.c
index cc0dd03..af94af3 100644
--- a/radsecproxy.c
+++ b/radsecproxy.c
@@ -81,6 +81,8 @@ static long *ssl_lock_count;
extern int optind;
extern char *optarg;
+SSL_CTX *tlsgetctx(struct tls *t);
+
/* callbacks for making OpenSSL thread safe */
unsigned long ssl_thread_id() {
return (unsigned long)pthread_self();
@@ -783,6 +785,7 @@ void tlsconnect(struct server *server, struct timeval *when, char *text) {
struct timeval now;
time_t elapsed;
X509 *cert;
+ SSL_CTX *ctx = NULL;
debug(DBG_DBG, "tlsconnect called from %s", text);
pthread_mutex_lock(&server->lock);
@@ -793,7 +796,7 @@ void tlsconnect(struct server *server, struct timeval *when, char *text) {
return;
}
- debug(DBG_DBG, "tlsconnect %s", text);
+ debug(DBG_DBG, "tlsconnect(%s)", text);
for (;;) {
gettimeofday(&now, NULL);
@@ -820,7 +823,14 @@ void tlsconnect(struct server *server, struct timeval *when, char *text) {
}
SSL_free(server->ssl);
- server->ssl = SSL_new(server->conf->ssl_ctx);
+ server->ssl = NULL;
+ ctx = tlsgetctx(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)
continue;
@@ -834,6 +844,7 @@ void tlsconnect(struct server *server, struct timeval *when, char *text) {
X509_free(cert);
}
debug(DBG_WARN, "tlsconnect: TLS connection to %s port %s up", server->conf->host, server->conf->port);
+ server->connectionok = 1;
gettimeofday(&server->lastconnecttry, NULL);
pthread_mutex_unlock(&server->lock);
}
@@ -917,19 +928,17 @@ int clientradputtls(struct server *server, unsigned char *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));
- tlsconnect(server, &lastconnecttry, "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);
return 1;
}
@@ -2221,6 +2230,7 @@ void *clientwr(void *arg) {
int i;
uint8_t rnd;
struct timeval now, lastsend;
+ time_t secs;
struct timespec timeout;
struct request statsrvrq;
unsigned char statsrvbuf[38];
@@ -2254,8 +2264,9 @@ void *clientwr(void *arg) {
/* random 0-7 seconds */
RAND_bytes(&rnd, 1);
rnd /= 32;
- if (!timeout.tv_sec || timeout.tv_sec > lastsend.tv_sec + STATUS_SERVER_PERIOD + rnd)
- timeout.tv_sec = lastsend.tv_sec + STATUS_SERVER_PERIOD + rnd;
+ secs = now.tv_sec - lastsend.tv_sec < STATUS_SERVER_PERIOD ? lastsend.tv_sec : now.tv_sec;
+ if (!timeout.tv_sec || timeout.tv_sec > secs + STATUS_SERVER_PERIOD + rnd)
+ timeout.tv_sec = secs + STATUS_SERVER_PERIOD + rnd;
}
if (timeout.tv_sec) {
debug(DBG_DBG, "clientwr: waiting up to %ld secs for new request", timeout.tv_sec - now.tv_sec);
@@ -2334,7 +2345,7 @@ void *clientwr(void *arg) {
clientradput(server, server->requests[i].buf);
gettimeofday(&lastsend, NULL);
}
- if (server->conf->statusserver) {
+ if (server->conf->statusserver && server->connectionok) {
gettimeofday(&now, NULL);
if (now.tv_sec - lastsend.tv_sec >= STATUS_SERVER_PERIOD) {
if (!RAND_bytes(statsrvbuf + 4, 16)) {
@@ -2505,6 +2516,7 @@ void *tlsservernew(void *arg) {
struct list_node *cur = NULL;
SSL *ssl = NULL;
X509 *cert = NULL;
+ SSL_CTX *ctx = NULL;
unsigned long error;
struct client *client;
@@ -2517,7 +2529,12 @@ void *tlsservernew(void *arg) {
conf = find_conf('T', (struct sockaddr *)&from, clconfs, &cur);
if (conf) {
- ssl = SSL_new(conf->ssl_ctx);
+ ctx = tlsgetctx(conf->tlsconf);
+ if (!ctx)
+ goto exit;
+ ssl = SSL_new(ctx);
+ if (!ssl)
+ goto exit;
SSL_set_fd(ssl, s);
if (SSL_accept(ssl) <= 0) {
@@ -2593,20 +2610,13 @@ int tlslistener() {
return 0;
}
-void tlsadd(char *value, char *cacertfile, char *cacertpath, char *certfile, char *certkeyfile, char *certkeypwd, uint8_t crlcheck) {
- struct tls *new;
- SSL_CTX *ctx;
+SSL_CTX *tlscreatectx(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 = calloc(CRYPTO_num_locks(), sizeof(pthread_mutex_t));
ssl_lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));
@@ -2627,26 +2637,34 @@ void tlsadd(char *value, char *cacertfile, char *cacertpath, char *certfile, cha
RAND_seed((unsigned char *)&pid, sizeof(pid));
}
}
+
ctx = SSL_CTX_new(TLSv1_method());
- if (certkeypwd) {
- SSL_CTX_set_default_passwd_cb_userdata(ctx, certkeypwd);
+ 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;
}
@@ -2655,7 +2673,9 @@ void tlsadd(char *value, char *cacertfile, char *cacertpath, char *certfile, cha
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 initialising SSL/TLS 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);
@@ -2663,40 +2683,16 @@ void tlsadd(char *value, char *cacertfile, char *cacertpath, char *certfile, cha
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;
- new->count = 0;
- debug(DBG_DBG, "tlsadd: added TLS context %s", value);
+ debug(DBG_DBG, "tlscreatectx: created tls context %s", conf->name);
+ return ctx;
}
-void tlsfree() {
- struct list_node *entry;
- struct tls *t;
-
- for (entry = list_first(tlsconfs); entry; entry = list_next(entry)) {
- t = (struct tls *)entry->data;
- if (t->name)
- free(t->name);
- if (!t->count)
- SSL_CTX_free(t->ctx);
- }
- list_destroy(tlsconfs);
- tlsconfs = NULL;
-}
-
-SSL_CTX *tlsgetctx(char *alt1, char *alt2) {
+struct tls *tlsgettls(char *alt1, char *alt2) {
struct list_node *entry;
struct tls *t, *t1 = NULL, *t2 = NULL;
@@ -2710,10 +2706,27 @@ SSL_CTX *tlsgetctx(char *alt1, char *alt2) {
t2 = t;
}
- t = (t1 ? t1 : t2);
+ return t1 ? t1 : t2;
+}
+
+SSL_CTX *tlsgetctx(struct tls *t) {
+ struct timeval now;
+
if (!t)
return NULL;
- t->count++;
+ gettimeofday(&now, NULL);
+ if (t->expiry && t->ctx) {
+ if (t->expiry < now.tv_sec) {
+ t->expiry = now.tv_sec + t->cacheexpiry;
+ SSL_CTX_free(t->ctx);
+ return t->ctx = tlscreatectx(t);
+ }
+ }
+ if (!t->ctx) {
+ t->ctx = tlscreatectx(t);
+ if (t->cacheexpiry)
+ t->expiry = now.tv_sec + t->cacheexpiry;
+ }
return t->ctx;
}
@@ -3112,8 +3125,8 @@ void confclient_cb(struct gconffile **cf, char *block, char *opt, char *val) {
conf->type = 'U';
client_udp_count++;
} else if (type && !strcasecmp(type, "tls")) {
- conf->ssl_ctx = tls ? tlsgetctx(tls, NULL) : tlsgetctx("defaultclient", "default");
- if (!conf->ssl_ctx)
+ conf->tlsconf = tls ? tlsgettls(tls, NULL) : tlsgettls("defaultclient", "default");
+ if (!conf->tlsconf)
debugx(1, DBG_ERR, "error in block %s, no tls context defined", block);
if (matchcertattr && !addmatchcertattr(conf, matchcertattr))
debugx(1, DBG_ERR, "error in block %s, invalid MatchCertificateAttributeValue", block);
@@ -3194,8 +3207,8 @@ void confserver_cb(struct gconffile **cf, char *block, char *opt, char *val) {
if (!conf->port)
conf->port = stringcopy(DEFAULT_UDP_PORT, 0);
} else if (type && !strcasecmp(type, "tls")) {
- conf->ssl_ctx = tls ? tlsgetctx(tls, NULL) : tlsgetctx("defaultserver", "default");
- if (!conf->ssl_ctx)
+ conf->tlsconf = tls ? tlsgettls(tls, NULL) : tlsgettls("defaultserver", "default");
+ if (!conf->tlsconf)
debugx(1, DBG_ERR, "error in block %s, no tls context defined", block);
if (matchcertattr && !addmatchcertattr(conf, matchcertattr))
debugx(1, DBG_ERR, "error in block %s, invalid MatchCertificateAttributeValue", block);
@@ -3263,27 +3276,41 @@ void confrealm_cb(struct gconffile **cf, char *block, char *opt, char *val) {
}
void conftls_cb(struct gconffile **cf, char *block, char *opt, char *val) {
- char *cacertfile = NULL, *cacertpath = NULL, *certfile = NULL, *certkeyfile = NULL, *certkeypwd = NULL;
- uint8_t crlcheck = 0;
+ struct tls *conf;
+ long int expiry = LONG_MIN;
debug(DBG_DBG, "conftls_cb called for %s", block);
+
+ conf = malloc(sizeof(struct tls));
+ if (!conf)
+ debugx(1, DBG_ERR, "conftls_cb: malloc failed");
+ memset(conf, 0, sizeof(struct tls));
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,
+ "CacheExpiry", CONF_LINT, &expiry,
+ "CRLCheck", CONF_BLN, &conf->crlcheck,
NULL
);
- tlsadd(val, cacertfile, cacertpath, certfile, certkeyfile, certkeypwd, crlcheck);
- free(cacertfile);
- free(cacertpath);
- free(certfile);
- free(certkeyfile);
- free(certkeypwd);
+ if (!conf->certfile || !conf->certkeyfile)
+ debugx(1, DBG_ERR, "conftls_cb: TLSCertificateFile and TLSCertificateKeyFile must be specified in block %s", val);
+ if (!conf->cacertfile && !conf->cacertpath)
+ debugx(1, DBG_ERR, "CA Certificate file or path need to be specified in TLS context %s", val);
+ if (expiry != LONG_MIN) {
+ if (expiry < 0)
+ debugx(1, DBG_ERR, "error in block %s, value of option CacheExpiry is %ld, may not be negative", val, expiry);
+ conf->cacheexpiry = expiry;
+ }
+ conf->name = stringcopy(val, 0);
+ if (!conf->name || !list_push(tlsconfs, conf))
+ debugx(1, DBG_ERR, "conftls_cb: malloc failed");
+
+ debug(DBG_DBG, "conftls_cb: added TLS block %s", val);
}
void confrewrite_cb(struct gconffile **cf, char *block, char *opt, char *val) {
@@ -3344,7 +3371,6 @@ void getmainconfig(const char *configfile) {
"Rewrite", CONF_CBK, confrewrite_cb,
NULL
);
- tlsfree();
rewritefree();
if (loglevel != LONG_MIN) {
diff --git a/radsecproxy.h b/radsecproxy.h
index f4c468d..b239a3e 100644
--- a/radsecproxy.h
+++ b/radsecproxy.h
@@ -88,11 +88,11 @@ struct clsrvconf {
uint8_t retryinterval;
uint8_t retrycount;
uint8_t certnamecheck;
- SSL_CTX *ssl_ctx;
struct rewrite *rewritein;
struct rewrite *rewriteout;
struct addrinfo *addrinfo;
uint8_t prefixlen;
+ struct tls *tlsconf;
struct list *clients;
struct server *servers;
};
@@ -131,8 +131,15 @@ struct realm {
struct tls {
char *name;
+ char *cacertfile;
+ char *cacertpath;
+ char *certfile;
+ char *certkeyfile;
+ char *certkeypwd;
+ uint8_t crlcheck;
+ uint32_t cacheexpiry;
+ uint32_t expiry;
SSL_CTX *ctx;
- int count;
};
struct attribute {