Commit a1ea5fc1 authored by venaas's avatar venaas Committed by venaas

various code improvements

git-svn-id: https://svn.testnett.uninett.no/radsecproxy/trunk@375 e88ac4ed-0b26-0410-9574-a7f39faa03bf
parent faf8717d
...@@ -585,8 +585,7 @@ void *dtlsclientrd(void *arg) { ...@@ -585,8 +585,7 @@ void *dtlsclientrd(void *arg) {
dtlsconnect(server, &lastconnecttry, 0, "dtlsclientrd"); dtlsconnect(server, &lastconnecttry, 0, "dtlsclientrd");
continue; continue;
} }
if (!replyh(server, buf)) replyh(server, buf);
free(buf);
} }
ERR_remove_state(0); ERR_remove_state(0);
server->clientrdgone = 1; server->clientrdgone = 1;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <limits.h> #include <limits.h>
#include <glob.h> #include <glob.h>
#include <sys/types.h> #include <sys/types.h>
#include <ctype.h>
#include <libgen.h> #include <libgen.h>
#include <errno.h> #include <errno.h>
#include "debug.h" #include "debug.h"
...@@ -350,6 +351,28 @@ int getconfigline(struct gconffile **cf, char *block, char **opt, char **val, in ...@@ -350,6 +351,28 @@ int getconfigline(struct gconffile **cf, char *block, char **opt, char **val, in
return 0; return 0;
} }
uint8_t hexdigit2int(char d) {
if (d >= '0' && d <= '9')
return d - '0';
if (d >= 'a' && d <= 'f')
return 10 + d - 'a';
if (d >= 'A' && d <= 'F')
return 10 + d - 'A';
return 0;
}
void unhex(char *s) {
char *t;
for (t = s; *t; s++) {
if (*t == '%' && isxdigit(t[1]) && isxdigit(t[2])) {
*s = 16 * hexdigit2int(t[1]) + hexdigit2int(t[2]);
t += 3;
} else
*s = *t++;
}
*s = '\0';
}
/* returns 1 if ok, 0 on error */ /* returns 1 if ok, 0 on error */
/* caller must free returned values also on error */ /* caller must free returned values also on error */
int getgenericconfig(struct gconffile **cf, char *block, ...) { int getgenericconfig(struct gconffile **cf, char *block, ...) {
...@@ -436,6 +459,7 @@ int getgenericconfig(struct gconffile **cf, char *block, ...) { ...@@ -436,6 +459,7 @@ int getgenericconfig(struct gconffile **cf, char *block, ...) {
debug(DBG_ERR, "configuration error, option %s already set to %s", opt, *str); debug(DBG_ERR, "configuration error, option %s already set to %s", opt, *str);
goto errexit; goto errexit;
} }
unhex(val);
*str = val; *str = val;
break; break;
case CONF_MSTR: case CONF_MSTR:
...@@ -448,6 +472,7 @@ int getgenericconfig(struct gconffile **cf, char *block, ...) { ...@@ -448,6 +472,7 @@ int getgenericconfig(struct gconffile **cf, char *block, ...) {
debug(DBG_ERR, "malloc failed"); debug(DBG_ERR, "malloc failed");
goto errexit; goto errexit;
} }
unhex(val);
newmstr[n] = val; newmstr[n] = val;
newmstr[n + 1] = NULL; newmstr[n + 1] = NULL;
*mstr = newmstr; *mstr = newmstr;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "debug.h" #include "debug.h"
#include <pthread.h> #include <pthread.h>
#include <openssl/hmac.h> #include <openssl/hmac.h>
#include <openssl/rand.h>
#define RADLEN(x) ntohs(((uint16_t *)(x))[1]) #define RADLEN(x) ntohs(((uint16_t *)(x))[1])
...@@ -32,6 +33,7 @@ struct radmsg *radmsg_init(uint8_t code, uint8_t id, uint8_t *auth) { ...@@ -32,6 +33,7 @@ struct radmsg *radmsg_init(uint8_t code, uint8_t id, uint8_t *auth) {
msg = malloc(sizeof(struct radmsg)); msg = malloc(sizeof(struct radmsg));
if (!msg) if (!msg)
return NULL; return NULL;
memset(msg, 0, sizeof(struct radmsg));
msg->attrs = list_create(); msg->attrs = list_create();
if (!msg->attrs) { if (!msg->attrs) {
free(msg); free(msg);
...@@ -39,7 +41,12 @@ struct radmsg *radmsg_init(uint8_t code, uint8_t id, uint8_t *auth) { ...@@ -39,7 +41,12 @@ struct radmsg *radmsg_init(uint8_t code, uint8_t id, uint8_t *auth) {
} }
msg->code = code; msg->code = code;
msg->id = id; msg->id = id;
memcpy(msg->auth, auth, 16); if (auth)
memcpy(msg->auth, auth, 16);
else if (!RAND_bytes(msg->auth, 16)) {
free(msg);
return NULL;
}
return msg; return msg;
} }
...@@ -66,40 +73,6 @@ struct tlv *radmsg_gettype(struct radmsg *msg, uint8_t type) { ...@@ -66,40 +73,6 @@ struct tlv *radmsg_gettype(struct radmsg *msg, uint8_t type) {
return NULL; return NULL;
} }
uint8_t *radmsg2buf(struct radmsg *msg) {
struct list_node *node;
struct tlv *tlv;
int size;
uint8_t *buf, *p;
if (!msg || !msg->attrs)
return NULL;
size = 20;
for (node = list_first(msg->attrs); node; node = list_next(node))
size += 2 + ((struct tlv *)node->data)->l;
if (size > 65535)
return NULL;
buf = malloc(size);
if (!buf)
return NULL;
p = buf;
*p++ = msg->code;
*p++ = msg->id;
*(uint16_t *)p = htons(size);
p += 2;
memcpy(p, msg->auth, 16);
p += 16;
for (node = list_first(msg->attrs); node; node = list_next(node)) {
tlv = (struct tlv *)node->data;
p = tlv2buf(p, tlv);
p[-1] += 2;
p += tlv->l;
}
return buf;
}
int _checkmsgauth(unsigned char *rad, uint8_t *authattr, uint8_t *secret) { int _checkmsgauth(unsigned char *rad, uint8_t *authattr, uint8_t *secret) {
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static unsigned char first = 1; static unsigned char first = 1;
...@@ -163,7 +136,76 @@ int _validauth(unsigned char *rad, unsigned char *reqauth, unsigned char *sec) { ...@@ -163,7 +136,76 @@ int _validauth(unsigned char *rad, unsigned char *reqauth, unsigned char *sec) {
pthread_mutex_unlock(&lock); pthread_mutex_unlock(&lock);
return result; return result;
} }
int _createmessageauth(unsigned char *rad, unsigned char *authattrval, uint8_t *secret) {
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static unsigned char first = 1;
static HMAC_CTX hmacctx;
unsigned int md_len;
if (!authattrval)
return 1;
pthread_mutex_lock(&lock);
if (first) {
HMAC_CTX_init(&hmacctx);
first = 0;
}
memset(authattrval, 0, 16);
md_len = 0;
HMAC_Init_ex(&hmacctx, secret, strlen((char *)secret), EVP_md5(), NULL);
HMAC_Update(&hmacctx, rad, RADLEN(rad));
HMAC_Final(&hmacctx, authattrval, &md_len);
if (md_len != 16) {
debug(DBG_WARN, "message auth computation failed");
pthread_mutex_unlock(&lock);
return 0;
}
pthread_mutex_unlock(&lock);
return 1;
}
uint8_t *radmsg2buf(struct radmsg *msg, uint8_t *secret) {
struct list_node *node;
struct tlv *tlv;
int size;
uint8_t *buf, *p, *msgauth = NULL;
if (!msg || !msg->attrs)
return NULL;
size = 20;
for (node = list_first(msg->attrs); node; node = list_next(node))
size += 2 + ((struct tlv *)node->data)->l;
if (size > 65535)
return NULL;
buf = malloc(size);
if (!buf)
return NULL;
p = buf;
*p++ = msg->code;
*p++ = msg->id;
*(uint16_t *)p = htons(size);
p += 2;
memcpy(p, msg->auth, 16);
p += 16;
for (node = list_first(msg->attrs); node; node = list_next(node)) {
tlv = (struct tlv *)node->data;
p = tlv2buf(p, tlv);
p[-1] += 2;
if (tlv->t == RAD_Attr_Message_Authenticator && secret)
msgauth = p;
p += tlv->l;
}
if (msgauth && !_createmessageauth(buf, msgauth, secret)) {
free(buf);
return NULL;
}
return buf;
}
/* if secret set we also validate message authenticator if present */ /* if secret set we also validate message authenticator if present */
struct radmsg *buf2radmsg(uint8_t *buf, uint8_t *secret, uint8_t *rqauth) { struct radmsg *buf2radmsg(uint8_t *buf, uint8_t *secret, uint8_t *rqauth) {
struct radmsg *msg; struct radmsg *msg;
......
...@@ -37,5 +37,5 @@ void radmsg_free(struct radmsg *); ...@@ -37,5 +37,5 @@ void radmsg_free(struct radmsg *);
struct radmsg *radmsg_init(uint8_t, uint8_t, uint8_t *); struct radmsg *radmsg_init(uint8_t, uint8_t, uint8_t *);
int radmsg_add(struct radmsg *, struct tlv *); int radmsg_add(struct radmsg *, struct tlv *);
struct tlv *radmsg_gettype(struct radmsg *, uint8_t); struct tlv *radmsg_gettype(struct radmsg *, uint8_t);
uint8_t *radmsg2buf(struct radmsg *msg); uint8_t *radmsg2buf(struct radmsg *msg, uint8_t *);
struct radmsg *buf2radmsg(uint8_t *, uint8_t *, uint8_t *); struct radmsg *buf2radmsg(uint8_t *, uint8_t *, uint8_t *);
...@@ -62,8 +62,6 @@ ...@@ -62,8 +62,6 @@
#include "debug.h" #include "debug.h"
#include "list.h" #include "list.h"
#include "hash.h" #include "hash.h"
#include "tlv11.h"
#include "radmsg.h"
#include "util.h" #include "util.h"
#include "gconfig.h" #include "gconfig.h"
#include "radsecproxy.h" #include "radsecproxy.h"
...@@ -902,36 +900,6 @@ int radsign(unsigned char *rad, unsigned char *sec) { ...@@ -902,36 +900,6 @@ int radsign(unsigned char *rad, unsigned char *sec) {
return result; return result;
} }
int createmessageauth(unsigned char *rad, unsigned char *authattrval, char *secret) {
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static unsigned char first = 1;
static HMAC_CTX hmacctx;
unsigned int md_len;
if (!authattrval)
return 1;
pthread_mutex_lock(&lock);
if (first) {
HMAC_CTX_init(&hmacctx);
first = 0;
}
memset(authattrval, 0, 16);
md_len = 0;
HMAC_Init_ex(&hmacctx, secret, strlen(secret), EVP_md5(), NULL);
HMAC_Update(&hmacctx, rad, RADLEN(rad));
HMAC_Final(&hmacctx, authattrval, &md_len);
if (md_len != 16) {
debug(DBG_WARN, "message auth computation failed");
pthread_mutex_unlock(&lock);
return 0;
}
pthread_mutex_unlock(&lock);
return 1;
}
unsigned char *attrget(unsigned char *attrs, int length, uint8_t type) { unsigned char *attrget(unsigned char *attrs, int length, uint8_t type) {
while (length > 1) { while (length > 1) {
if (ATTRTYPE(attrs) == type) if (ATTRTYPE(attrs) == type)
...@@ -945,13 +913,14 @@ unsigned char *attrget(unsigned char *attrs, int length, uint8_t type) { ...@@ -945,13 +913,14 @@ unsigned char *attrget(unsigned char *attrs, int length, uint8_t type) {
void freerqdata(struct request *rq) { void freerqdata(struct request *rq) {
if (rq->origusername) if (rq->origusername)
free(rq->origusername); free(rq->origusername);
if (rq->msg)
radmsg_free(rq->msg);
if (rq->buf) if (rq->buf)
free(rq->buf); free(rq->buf);
} }
void sendrq(struct server *to, struct request *rq) { void sendrq(struct server *to, struct request *rq) {
int i; int i;
uint8_t *attr;
pthread_mutex_lock(&to->newrq_mutex); pthread_mutex_lock(&to->newrq_mutex);
/* might simplify if only try nextid, might be ok */ /* might simplify if only try nextid, might be ok */
...@@ -968,11 +937,10 @@ void sendrq(struct server *to, struct request *rq) { ...@@ -968,11 +937,10 @@ void sendrq(struct server *to, struct request *rq) {
goto exit; goto exit;
} }
} }
rq->buf[1] = (char)i;
attr = attrget(rq->buf + 20, RADLEN(rq->buf) - 20, RAD_Attr_Message_Authenticator); rq->msg->id = (uint8_t)i;
if (attr && !createmessageauth(rq->buf, ATTRVAL(attr), to->conf->secret)) { rq->buf = radmsg2buf(rq->msg, (uint8_t *)to->conf->secret);
if (!rq->buf) {
freerqdata(rq); freerqdata(rq);
goto exit; goto exit;
} }
...@@ -994,6 +962,7 @@ void sendrq(struct server *to, struct request *rq) { ...@@ -994,6 +962,7 @@ void sendrq(struct server *to, struct request *rq) {
debug(DBG_DBG, "sendrq: signalling client writer"); debug(DBG_DBG, "sendrq: signalling client writer");
pthread_cond_signal(&to->newrq_cond); pthread_cond_signal(&to->newrq_cond);
} }
exit: exit:
pthread_mutex_unlock(&to->newrq_mutex); pthread_mutex_unlock(&to->newrq_mutex);
} }
...@@ -1470,7 +1439,7 @@ int dorewriteadd(struct radmsg *msg, struct list *addattrs) { ...@@ -1470,7 +1439,7 @@ int dorewriteadd(struct radmsg *msg, struct list *addattrs) {
return 1; return 1;
} }
int resizeattr2(struct tlv *attr, uint8_t newlen) { int resizeattr(struct tlv *attr, uint8_t newlen) {
uint8_t *newv; uint8_t *newv;
if (newlen != attr->l) { if (newlen != attr->l) {
...@@ -1517,7 +1486,7 @@ int dorewritemodattr(struct tlv *attr, struct modattr *modattr) { ...@@ -1517,7 +1486,7 @@ int dorewritemodattr(struct tlv *attr, struct modattr *modattr) {
return 0; return 0;
} }
if (!resizeattr2(attr, reslen)) { if (!resizeattr(attr, reslen)) {
free(in); free(in);
return 0; return 0;
} }
...@@ -1596,39 +1565,7 @@ void char2hex(char *h, unsigned char c) { ...@@ -1596,39 +1565,7 @@ void char2hex(char *h, unsigned char c) {
return; return;
} }
char *radattr2ascii(char *ascii, size_t len, unsigned char *attr) { uint8_t *radattr2ascii(struct tlv *attr) {
int i, l;
char *s, *d;
if (!attr || len == 1) {
*ascii = '\0';
return ascii;
}
l = ATTRVALLEN(attr);
s = (char *)ATTRVAL(attr);
d = ascii;
for (i = 0; i < l; i++) {
if (s[i] > 31 && s[i] < 127) {
*d++ = s[i];
if (d - ascii == len - 1)
break;
} else {
if (d - ascii > len - 4)
break;
*d++ = '%';
char2hex(d, s[i]);
d += 2;
if (d - ascii == len - 1)
break;
}
}
*d = '\0';
return ascii;
}
uint8_t *radattr2ascii2(struct tlv *attr) {
int i, l; int i, l;
uint8_t *a, *d; uint8_t *a, *d;
...@@ -1667,7 +1604,7 @@ void acclog(struct radmsg *msg, char *host) { ...@@ -1667,7 +1604,7 @@ void acclog(struct radmsg *msg, char *host) {
debug(DBG_INFO, "acclog: accounting-request from %s without username attribute", host); debug(DBG_INFO, "acclog: accounting-request from %s without username attribute", host);
return; return;
} }
username = radattr2ascii2(attr); username = radattr2ascii(attr);
if (username) { if (username) {
debug(DBG_INFO, "acclog: accounting-request from %s with username: %s", host, username); debug(DBG_INFO, "acclog: accounting-request from %s with username: %s", host, username);
free(username); free(username);
...@@ -1817,13 +1754,13 @@ int radsrv(struct request *rq) { ...@@ -1817,13 +1754,13 @@ int radsrv(struct request *rq) {
debug(DBG_WARN, "radsrv: ignoring access request, no username attribute"); debug(DBG_WARN, "radsrv: ignoring access request, no username attribute");
goto exit; goto exit;
} }
if (rq->from->conf->rewriteusername && !rewriteusername(rq, attr)) { if (rq->from->conf->rewriteusername && !rewriteusername(rq, attr)) {
debug(DBG_WARN, "radsrv: username malloc failed, ignoring request"); debug(DBG_WARN, "radsrv: username malloc failed, ignoring request");
goto exit; goto exit;
} }
userascii = radattr2ascii2(attr); userascii = radattr2ascii(attr);
if (!userascii) if (!userascii)
goto exit; goto exit;
debug(DBG_DBG, "%s with username: %s", radmsgtype2string(msg->code), userascii); debug(DBG_DBG, "%s with username: %s", radmsgtype2string(msg->code), userascii);
...@@ -1844,6 +1781,9 @@ int radsrv(struct request *rq) { ...@@ -1844,6 +1781,9 @@ int radsrv(struct request *rq) {
goto exit; goto exit;
} }
free(rq->buf);
rq->buf = NULL;
if (options.loopprevention && !strcmp(rq->from->conf->name, to->conf->name)) { if (options.loopprevention && !strcmp(rq->from->conf->name, to->conf->name)) {
debug(DBG_INFO, "radsrv: Loop prevented, not forwarding request from client %s to server %s, discarding", debug(DBG_INFO, "radsrv: Loop prevented, not forwarding request from client %s to server %s, discarding",
rq->from->conf->name, to->conf->name); rq->from->conf->name, to->conf->name);
...@@ -1888,13 +1828,8 @@ int radsrv(struct request *rq) { ...@@ -1888,13 +1828,8 @@ int radsrv(struct request *rq) {
if (to->conf->rewriteout && !dorewrite(msg, to->conf->rewriteout)) if (to->conf->rewriteout && !dorewrite(msg, to->conf->rewriteout))
goto exit; goto exit;
free(rq->buf);
rq->buf = radmsg2buf(msg);
if (!rq->buf)
goto exit;
free(userascii); free(userascii);
radmsg_free(msg); rq->msg = msg;
sendrq(to, rq); sendrq(to, rq);
return 1; return 1;
...@@ -1905,31 +1840,33 @@ int radsrv(struct request *rq) { ...@@ -1905,31 +1840,33 @@ int radsrv(struct request *rq) {
return 1; return 1;
} }
int replyh(struct server *server, unsigned char *buf) { void replyh(struct server *server, unsigned char *buf) {
struct client *from; struct client *from;
struct request *rq; struct request *rq;
int sublen; int sublen;
unsigned char *subattrs, *rqattr; unsigned char *subattrs;
struct sockaddr_storage fromsa; struct sockaddr_storage fromsa;
char tmp[760], stationid[760]; uint8_t *username, *stationid;
struct radmsg *msg = NULL; struct radmsg *msg = NULL;
struct tlv *attr, *messageauth; struct tlv *attr;
struct list_node *node; struct list_node *node;
server->connectionok = 1; server->connectionok = 1;
server->lostrqs = 0; server->lostrqs = 0;
rq = server->requests + buf[1]; rq = server->requests + buf[1];
msg = buf2radmsg(buf, (uint8_t *)server->conf->secret, rq->buf + 4); msg = buf2radmsg(buf, (uint8_t *)server->conf->secret, rq->msg->auth);
free(buf);
buf = NULL;
if (!msg) { if (!msg) {
debug(DBG_WARN, "replyh: message validation failed, ignoring packet"); debug(DBG_WARN, "replyh: message validation failed, ignoring packet");
return 0; return;
} }
if (msg->code != RAD_Access_Accept && msg->code != RAD_Access_Reject && msg->code != RAD_Access_Challenge if (msg->code != RAD_Access_Accept && msg->code != RAD_Access_Reject && msg->code != RAD_Access_Challenge
&& msg->code != RAD_Accounting_Response) { && msg->code != RAD_Accounting_Response) {
debug(DBG_INFO, "replyh: discarding message type %s, accepting only access accept, access reject, access challenge and accounting response messages", radmsgtype2string(msg->code)); debug(DBG_INFO, "replyh: discarding message type %s, accepting only access accept, access reject, access challenge and accounting response messages", radmsgtype2string(msg->code));
radmsg_free(msg); radmsg_free(msg);
return 0; return;
} }
debug(DBG_DBG, "got %s message with id %d", radmsgtype2string(msg->code), msg->id); debug(DBG_DBG, "got %s message with id %d", radmsgtype2string(msg->code), msg->id);
...@@ -1946,7 +1883,7 @@ int replyh(struct server *server, unsigned char *buf) { ...@@ -1946,7 +1883,7 @@ int replyh(struct server *server, unsigned char *buf) {
gettimeofday(&server->lastrcv, NULL); gettimeofday(&server->lastrcv, NULL);
if (*rq->buf == RAD_Status_Server) { if (rq->msg->code == RAD_Status_Server) {
rq->received = 1; rq->received = 1;
debug(DBG_DBG, "replyh: got status server response from %s", server->conf->host); debug(DBG_DBG, "replyh: got status server response from %s", server->conf->host);
goto errunlock; goto errunlock;
...@@ -1990,16 +1927,16 @@ int replyh(struct server *server, unsigned char *buf) { ...@@ -1990,16 +1927,16 @@ int replyh(struct server *server, unsigned char *buf) {
} }
if (msg->code == RAD_Access_Accept || msg->code == RAD_Access_Reject || msg->code == RAD_Accounting_Response) { if (msg->code == RAD_Access_Accept || msg->code == RAD_Access_Reject || msg->code == RAD_Accounting_Response) {
rqattr = attrget(rq->buf + 20, RADLEN(rq->buf) - 20, RAD_Attr_User_Name); username = radattr2ascii(radmsg_gettype(rq->msg, RAD_Attr_User_Name));
if (rqattr) { if (username) {
radattr2ascii(tmp, sizeof(tmp), rqattr); stationid = radattr2ascii(radmsg_gettype(rq->msg, RAD_Attr_Calling_Station_Id));
rqattr = attrget(rq->buf + 20, RADLEN(rq->buf) - 20, RAD_Attr_Calling_Station_Id); if (stationid) {
if (rqattr) {
radattr2ascii(stationid, sizeof(stationid), rqattr);
debug(DBG_INFO, "%s for user %s stationid %s from %s", debug(DBG_INFO, "%s for user %s stationid %s from %s",
radmsgtype2string(msg->code), tmp, stationid, server->conf->host); radmsgtype2string(msg->code), username, stationid, server->conf->host);
free(stationid);
} else } else
debug(DBG_INFO, "%s for user %s from %s", radmsgtype2string(msg->code), tmp, server->conf->host); debug(DBG_INFO, "%s for user %s from %s", radmsgtype2string(msg->code), username, server->conf->host);
free(username);
} }
}