From 234912c553f7808f25064b1a3980eb3651bb313e Mon Sep 17 00:00:00 2001
From: venaas <venaas>
Date: Tue, 16 Jan 2007 14:04:27 +0000
Subject: added code for reading main config and restructured tls init code

git-svn-id: https://svn.testnett.uninett.no/radsecproxy/trunk@39 e88ac4ed-0b26-0410-9574-a7f39faa03bf
---
 radsecproxy.c | 214 ++++++++++++++++++++++++++++++++++------------------------
 radsecproxy.h |   7 ++
 util.c        |  12 ++++
 3 files changed, 145 insertions(+), 88 deletions(-)

diff --git a/radsecproxy.c b/radsecproxy.c
index bcb4301..51202e4 100644
--- a/radsecproxy.c
+++ b/radsecproxy.c
@@ -58,6 +58,7 @@
 #include <openssl/hmac.h>
 #include "radsecproxy.h"
 
+static struct options options;
 static struct client clients[MAX_PEERS];
 static struct server servers[MAX_PEERS];
 
@@ -66,10 +67,9 @@ static int server_count = 0;
 
 static struct replyq udp_server_replyq;
 static int udp_server_sock = -1;
-static char *udp_server_port = DEFAULT_UDP_PORT;
 static pthread_mutex_t *ssl_locks;
 static long *ssl_lock_count;
-static SSL_CTX *ssl_ctx_cl;
+static SSL_CTX *ssl_ctx = NULL;
 extern int optind;
 extern char *optarg;
 
@@ -86,8 +86,14 @@ void ssl_locking_callback(int mode, int type, const char *file, int line) {
 	pthread_mutex_unlock(&ssl_locks[type]);
 }
 
-void ssl_locks_setup() {
+void ssl_init() {
     int i;
+    unsigned long error;
+    
+    if (!options.tlscertificatefile || !options.tlscertificatekeyfile) {
+	printf("TLSCertificateFile and TLSCertificateKeyFile must be specified for TLS\n");
+	exit(1);
+    }
 
     ssl_locks = malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
     ssl_lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));
@@ -95,10 +101,36 @@ void ssl_locks_setup() {
 	ssl_lock_count[i] = 0;
 	pthread_mutex_init(&ssl_locks[i], NULL);
     }
-
     CRYPTO_set_id_callback(ssl_thread_id);
     CRYPTO_set_locking_callback(ssl_locking_callback);
-}
+
+    SSL_load_error_strings();
+    SSL_library_init();
+
+    while (!RAND_status()) {
+	time_t t = time(NULL);
+	pid_t pid = getpid();
+	RAND_seed((unsigned char *)&t, sizeof(time_t));
+        RAND_seed((unsigned char *)&pid, sizeof(pid));
+    }
+
+    ssl_ctx = SSL_CTX_new(TLSv1_method());
+    if (!ssl_ctx) {
+	printf("failed to initialise ssl");
+	exit(1);
+    }
+
+    if (!SSL_CTX_use_certificate_file(ssl_ctx, options.tlscertificatefile, SSL_FILETYPE_PEM)) {
+        while ((error = ERR_get_error()))
+            err("SSL: %s", ERR_error_string(error, NULL));
+        errx("Failed to load certificate");
+    }
+    if (!SSL_CTX_use_PrivateKey_file(ssl_ctx, options.tlscertificatekeyfile, SSL_FILETYPE_PEM)) {
+	while ((error = ERR_get_error()))
+	    err("SSL: %s", ERR_error_string(error, NULL));
+	errx("Failed to load private key");
+    }
+}    
 
 void printauth(char *s, unsigned char *t) {
     int i;
@@ -299,7 +331,7 @@ void tlsconnect(struct server *server, struct timeval *when, char *text) {
 	if ((server->sock = connecttoserver(server->peer.addrinfo)) < 0)
 	    continue;
 	SSL_free(server->peer.ssl);
-	server->peer.ssl = SSL_new(ssl_ctx_cl);
+	server->peer.ssl = SSL_new(ssl_ctx);
 	SSL_set_fd(server->peer.ssl, server->sock);
 	if (SSL_connect(server->peer.ssl) > 0)
 	    break;
@@ -1217,11 +1249,11 @@ void *udpserverrd(void *arg) {
     struct client *fr;
     pthread_t udpserverwrth;
     
-    if ((udp_server_sock = bindport(SOCK_DGRAM, udp_server_port)) < 0) {
+    if ((udp_server_sock = bindport(SOCK_DGRAM, options.udpserverport)) < 0) {
         printf("udpserverrd: socket/bind failed\n");
 	exit(1);
     }
-    printf("udpserverrd: listening on UDP port %s\n", udp_server_port);
+    printf("udpserverrd: listening on UDP port %s\n", options.udpserverport);
 
     if (pthread_create(&udpserverwrth, NULL, udpserverwr, NULL))
 	errx("pthread_create failed");
@@ -1328,7 +1360,7 @@ void *tlsserverrd(void *arg) {
     pthread_exit(NULL);
 }
 
-int tlslistener(SSL_CTX *ssl_ctx) {
+int tlslistener() {
     pthread_t tlsserverth;
     int s, snew;
     struct sockaddr_storage from;
@@ -1395,11 +1427,7 @@ char *parsehostport(char *s, struct peer *peer) {
 	printf("missing host/address\n");
 	exit(1);
     }
-    peer->host = malloc(p - field + 1);
-    if (!peer->host)
-	errx("malloc failed");
-    memcpy(peer->host, field, p - field);
-    peer->host[p - field] = '\0';
+    peer->host = stringcopy(field, p - field);
     if (ipv6) {
 	p++;
 	if (*p && *p != ':' && *p != ' ' && *p != '\t' && *p != '\n') {
@@ -1415,13 +1443,9 @@ char *parsehostport(char *s, struct peer *peer) {
 		printf("syntax error, : but no following port\n");
 		exit(1);
 	    }
-	    peer->port = malloc(p - field + 1);
-	    if (!peer->port)
-		errx("malloc failed");
-	    memcpy(peer->port, field, p - field);
-	    peer->port[p - field] = '\0';
+	    peer->port = stringcopy(field, p - field);
     } else
-        peer->port = NULL;
+	peer->port = stringcopy(peer->type == 'U' ? DEFAULT_UDP_PORT : DEFAULT_TLS_PORT, 0);
     return p;
 }
 
@@ -1435,14 +1459,10 @@ char *parserealmlist(char *s, struct server *server) {
 	    n++;
     l = p - s;
     if (!l) {
-	server->realms = NULL;
-	return p;
+	printf("realm list must be specified\n");
+	exit(1);
     }
-    server->realmdata = malloc(l + 1);
-    if (!server->realmdata)
-	errx("malloc failed");
-    memcpy(server->realmdata, s, l);
-    server->realmdata[l] = '\0';
+    server->realmdata = stringcopy(s, l);
     server->realms = malloc((1+n) * sizeof(char *));
     if (!server->realms)
 	errx("malloc failed");
@@ -1508,15 +1528,9 @@ void getconfig(const char *serverfile, const char *clientfile) {
 	peer->type = *p;
 	for (p++; *p == ' ' || *p == '\t'; p++);
 	p = parsehostport(p, peer);
-	if (!peer->port)
-	    peer->port = (peer->type == 'U' ? DEFAULT_UDP_PORT : DEFAULT_TLS_PORT);
 	for (; *p == ' ' || *p == '\t'; p++);
 	if (serverfile) {
 	    p = parserealmlist(p, server);
-	    if (!server->realms) {
-		printf("realm list must be specified\n");
-		exit(1);
-	    }
 	    for (; *p == ' ' || *p == '\t'; p++);
 	}
 	field = p;
@@ -1527,13 +1541,9 @@ void getconfig(const char *serverfile, const char *clientfile) {
 		printf("secret must be specified for UDP\n");
 		exit(1);
 	    }
-	    peer->secret = DEFAULT_TLS_SECRET;
+	    peer->secret = stringcopy(DEFAULT_TLS_SECRET, 0);
 	} else {
-	    peer->secret = malloc(p - field + 1);
-	    if (!peer->secret)
-		errx("malloc failed");
-	    memcpy(peer->secret, field, p - field);
-	    peer->secret[p - field] = '\0';
+	    peer->secret = stringcopy(field, p - field);
 	    /* check that rest of line only white space */
 	    for (; *p == ' ' || *p == '\t'; p++);
 	    if (*p && *p != '\n') {
@@ -1586,6 +1596,62 @@ void getconfig(const char *serverfile, const char *clientfile) {
     fclose(f);
 }
 
+void getmainconfig(const char *configfile) {
+    FILE *f;
+    char line[1024];
+    char *p, *opt, *endopt, *val, *endval;
+    
+    printf("opening file %s for reading\n", configfile);
+    f = fopen(configfile, "r");
+    if (!f)
+	errx("getmainconfig failed to open %s for reading", configfile);
+
+    memset(&options, 0, sizeof(options));
+
+    while (fgets(line, 1024, f)) {
+	for (p = line; *p == ' ' || *p == '\t'; p++);
+	if (!*p || *p == '#' || *p == '\n')
+	    continue;
+	opt = p++;
+	for (; *p && *p != ' ' && *p != '\t' && *p != '\n'; p++);
+	endopt = p - 1;
+	for (; *p == ' ' || *p == '\t'; p++);
+	if (!*p || *p == '\n') {
+	    endopt[1] = '\0';
+	    printf("error in %s, option %s has no value\n", configfile, opt);
+	    exit(1);
+	}
+	val = p;
+	for (; *p && *p != '\n'; p++)
+	    if (*p != ' ' && *p != '\t')
+		endval = p;
+	endopt[1] = '\0';
+	endval[1] = '\0';
+	printf("getmainconfig: %s = %s\n", opt, val);
+	
+	if (!strcasecmp(opt, "TLSCertificateFile")) {
+	    options.tlscertificatefile = stringcopy(val, 0);
+	    continue;
+	}
+	if (!strcasecmp(opt, "TLSCertificateKeyFile")) {
+	    options.tlscertificatekeyfile = stringcopy(val, 0);
+	    continue;
+	}
+	if (!strcasecmp(opt, "UDPServerPort")) {
+	    options.udpserverport = stringcopy(val, 0);
+	    continue;
+	}
+
+	printf("error in %s, unknown option %s\n", configfile, opt);
+	exit(1);
+    }
+    fclose(f);
+
+    if (!options.udpserverport)
+	options.udpserverport = stringcopy(DEFAULT_UDP_PORT, 0);
+}
+
+#if 0
 void parseargs(int argc, char **argv) {
     int c;
 
@@ -1605,20 +1671,18 @@ void parseargs(int argc, char **argv) {
     printf("radsecproxy [ -p UDP-port ]\n");
     exit(1);
 }
-	       
+#endif
+
 int main(int argc, char **argv) {
-    SSL_CTX *ssl_ctx_srv;
-    unsigned long error;
     pthread_t udpserverth;
     //    pthread_attr_t joinable;
     int i;
     
-    parseargs(argc, argv);
+    //    parseargs(argc, argv);
+    getmainconfig("radsecproxy.conf");
     getconfig("servers.conf", NULL);
     getconfig(NULL, "clients.conf");
     
-    ssl_locks_setup();
-
     //    pthread_attr_init(&joinable);
     //    pthread_attr_setdetachstate(&joinable, PTHREAD_CREATE_JOINABLE);
    
@@ -1630,53 +1694,27 @@ int main(int argc, char **argv) {
 		errx("pthread_create failed");
 	    break;
 	}
-    
-    /* SSL setup */
-    SSL_load_error_strings();
-    SSL_library_init();
 
-    while (!RAND_status()) {
-	time_t t = time(NULL);
-	pid_t pid = getpid();
-	RAND_seed((unsigned char *)&t, sizeof(time_t));
-        RAND_seed((unsigned char *)&pid, sizeof(pid));
-    }
-    
-    /* initialise client part and start clients */
-    ssl_ctx_cl = SSL_CTX_new(TLSv1_client_method());
-    if (!ssl_ctx_cl)
-	errx("no ssl ctx");
-    
-    for (i = 0; i < server_count; i++) {
+    /* only initialise ssl here if at least one TLS server defined */
+    for (i = 0; i < server_count; i++)
+	if (servers[i].peer.type == 'T') {
+	    ssl_init();
+	    break;
+	}
+
+    for (i = 0; i < server_count; i++)
 	if (pthread_create(&servers[i].clientth, NULL, clientwr, (void *)&servers[i]))
 	    errx("pthread_create failed");
-    }
 
+    /* start listener if at least one TLS client defined */
     for (i = 0; i < client_count; i++)
-	if (clients[i].peer.type == 'T')
-	    break;
-
-    if (i == client_count) {
-	printf("No TLS clients defined, not starting TLS listener\n");
-	/* just hang around doing nothing, anything to do here? */
-	for (;;)
-	    sleep(1000);
-    }
-    
-    /* setting up server/daemon part */
-    ssl_ctx_srv = SSL_CTX_new(TLSv1_server_method());
-    if (!ssl_ctx_srv)
-	errx("no ssl ctx");
-    if (!SSL_CTX_use_certificate_file(ssl_ctx_srv, "/tmp/server.pem", SSL_FILETYPE_PEM)) {
-        while ((error = ERR_get_error()))
-            err("SSL: %s", ERR_error_string(error, NULL));
-        errx("Failed to load certificate");
-    }
-    if (!SSL_CTX_use_PrivateKey_file(ssl_ctx_srv, "/tmp/server.key", SSL_FILETYPE_PEM)) {
-	while ((error = ERR_get_error()))
-	    err("SSL: %s", ERR_error_string(error, NULL));
-	errx("Failed to load private key");
-    }
+	if (clients[i].peer.type == 'T') {
+	    if (!ssl_ctx)
+		ssl_init();
+	    return tlslistener();
+	}
 
-    return tlslistener(ssl_ctx_srv);
+    /* just hang around doing nothing, anything to do here? */
+    for (;;)
+	sleep(1000);
 }
diff --git a/radsecproxy.h b/radsecproxy.h
index b4393d4..e6dca52 100644
--- a/radsecproxy.h
+++ b/radsecproxy.h
@@ -42,6 +42,12 @@
 #define RAD_Attr_Length 1
 #define RAD_Attr_Value 2
 
+struct options {
+    char *tlscertificatefile;
+    char *tlscertificatekeyfile;
+    char *udpserverport;
+};
+    
 /* requests that a client will send */
 struct request {
     unsigned char *buf;
@@ -101,6 +107,7 @@ struct server {
 
 void errx(char *format, ...);
 void err(char *format, ...);
+char *stringcopy(char *s, int len);
 char *addr2string(struct sockaddr *addr, socklen_t len);
 int bindport(int type, char *port);
 int connectport(int type, char *host, char *port);
diff --git a/util.c b/util.c
index 7ca29c7..e4372a3 100644
--- a/util.c
+++ b/util.c
@@ -45,6 +45,18 @@ void err(char *format, ...) {
         fprintf(stderr, "\n");
 }
 
+char *stringcopy(char *s, int len) {
+    char *r;
+    if (!len)
+	len = strlen(s);
+    r = malloc(len + 1);
+    if (!r)
+	errx("stringcopy: malloc failed");
+    memcpy(r, s, len);
+    r[len] = '\0';
+    return r;
+}
+		
 char *addr2string(struct sockaddr *addr, socklen_t len) {
     struct sockaddr_in6 *sa6;
     struct sockaddr_in sa4;
-- 
cgit v1.1