Skip to content

Commit

Permalink
Merge branch 'rewrite-attribute'
Browse files Browse the repository at this point in the history
  • Loading branch information
Fabian Mauchle committed May 27, 2019
2 parents c0e313d + 964038e commit 687c8cd
Show file tree
Hide file tree
Showing 23 changed files with 1,769 additions and 630 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ TAGS
radsecproxy
radsecproxy-conf
radsecproxy-hash
build-aux/*
tests/t_fticks
tests/t_rewrite
tests/t_rewrite_config
tests/t_resizeattr
tests/*.log
tests/*.trs
6 changes: 6 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
changes since 1.7.2
New features:
- Rewrite: supplement attribute (add attribute if not present) (#19)
- Rewrite: modify vendor attribute
- Rewrite whitelist mode
- Autodetect status-server capability of servers
- Minimalistic status-server

Expand All @@ -11,6 +14,9 @@ changes since 1.7.2
- Fix compile issues on bsd
- Fix server selection when udp were unreachable for long periods

Bug fixes:
- Handle %00 in config correctly (#31)

2018-09-03 1.7.2
Misc:
- Always copy proxy-state attributes in own responses
Expand Down
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ librsp_a_SOURCES = \
list.c list.h \
radmsg.c radmsg.h \
radsecproxy.c radsecproxy.h \
rewrite.c rewrite.h \
tcp.c tcp.h \
tls.c tls.h \
tlscommon.c tlscommon.h \
Expand Down
2 changes: 2 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ dnl See LICENSE for licensing information.

AC_INIT(radsecproxy, 1.7.2, https://radsecproxy.github.io)
AC_CANONICAL_TARGET
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE
AC_PROG_CC
AC_PROG_RANLIB
AC_CHECK_FUNCS([mallopt])
AC_REQUIRE_AUX_FILE([tap-driver.sh])

udp=yes
AC_ARG_ENABLE(udp,
Expand Down
20 changes: 12 additions & 8 deletions gconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -366,16 +366,20 @@ uint8_t hexdigit2int(char d) {
return 0;
}

void unhex(char *s) {
int unhex(char *s, uint8_t process_null) {
int len = 0;
char *t;
for (t = s; *t; s++) {
if (*t == '%' && isxdigit((int)t[1]) && isxdigit((int)t[2])) {
*s = 16 * hexdigit2int(t[1]) + hexdigit2int(t[2]);
t += 3;
} else
*s = *t++;
if (*t == '%' && isxdigit((int)t[1]) && isxdigit((int)t[2]) &&
(process_null || !(t[1]=='0' && t[2]=='0'))) {
*s = 16 * hexdigit2int(t[1]) + hexdigit2int(t[2]);
t += 3;
} else
*s = *t++;
len++;
}
*s = '\0';
return len;
}

typedef int (*t_fptr)(struct gconffile **, void *, char *, char *, char *);
Expand Down Expand Up @@ -466,7 +470,7 @@ int getgenericconfig(struct gconffile **cf, char *block, ...) {
debug(DBG_ERR, "configuration error, option %s already set to %s", opt, *str);
goto errexit;
}
unhex(val);
unhex(val,0);
*str = val;
break;
case CONF_MSTR:
Expand All @@ -479,7 +483,7 @@ int getgenericconfig(struct gconffile **cf, char *block, ...) {
debug(DBG_ERR, "malloc failed");
goto errexit;
}
unhex(val);
unhex(val,0);
newmstr[n] = val;
newmstr[n + 1] = NULL;
*mstr = newmstr;
Expand Down
1 change: 1 addition & 0 deletions gconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ int popgconf(struct gconffile **cf);
void freegconfmstr(char **mstr);
void freegconf(struct gconffile **cf);
struct gconffile *openconfigfile(const char *file);
int unhex(char *s, uint8_t process_null);

/* Local Variables: */
/* c-file-style: "stroustrup" */
Expand Down
1 change: 0 additions & 1 deletion hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "list.h"
#include "hash.h"

Expand Down
1 change: 1 addition & 0 deletions hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#ifndef SYS_SOLARIS9
#include <stdint.h>
#endif
#include <pthread.h>

struct hash {
struct list *hashlist;
Expand Down
5 changes: 5 additions & 0 deletions list.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/* Copyright (c) 2007,2009, UNINETT AS */
/* See LICENSE for licensing information. */

#ifndef _LIST_H
#define _LIST_H

#ifdef SYS_SOLARIS9
#include <sys/inttypes.h>
#else
Expand Down Expand Up @@ -44,6 +47,8 @@ struct list_node *list_next(struct list_node *node);
/* returns number of nodes */
uint32_t list_count(struct list *list);

#endif /*_LIST_H*/

/* Local Variables: */
/* c-file-style: "stroustrup" */
/* End: */
129 changes: 108 additions & 21 deletions radmsg.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#include <string.h>
#include <arpa/inet.h>
#include "list.h"
#include "tlv11.h"
#include "radmsg.h"
#include "debug.h"
#include <pthread.h>
Expand Down Expand Up @@ -52,7 +51,7 @@ struct radmsg *radmsg_init(uint8_t code, uint8_t id, uint8_t *auth) {
int radmsg_add(struct radmsg *msg, struct tlv *attr) {
if (!msg || !msg->attrs)
return 1;
if (!attr)
if (!attr || attr->l > RAD_Max_Attr_Value_Length)
return 0;
return list_push(msg->attrs, attr);
}
Expand Down Expand Up @@ -121,7 +120,7 @@ int radmsg_copy_attrs(struct radmsg *dst,
return n;
}

int _checkmsgauth(unsigned char *rad, uint8_t *authattr, uint8_t *secret) {
int _checkmsgauth(unsigned char *rad, uint8_t *authattr, uint8_t *secret, int secret_len) {
int result = 0; /* Fail. */
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
struct hmac_md5_ctx hmacctx;
Expand All @@ -133,7 +132,7 @@ int _checkmsgauth(unsigned char *rad, uint8_t *authattr, uint8_t *secret) {
memcpy(auth, authattr, 16);
memset(authattr, 0, 16);

hmac_md5_set_key(&hmacctx, strlen((char *) secret), secret);
hmac_md5_set_key(&hmacctx, secret_len, secret);
hmac_md5_update(&hmacctx, RADLEN(rad), rad);
hmac_md5_digest(&hmacctx, sizeof(hash), hash);

Expand All @@ -150,7 +149,7 @@ int _checkmsgauth(unsigned char *rad, uint8_t *authattr, uint8_t *secret) {
return result;
}

int _validauth(unsigned char *rad, unsigned char *reqauth, unsigned char *sec) {
int _validauth(unsigned char *rad, unsigned char *reqauth, unsigned char *sec, int sec_len) {
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
struct md5_ctx mdctx;
unsigned char hash[MD5_DIGEST_SIZE];
Expand All @@ -164,7 +163,7 @@ int _validauth(unsigned char *rad, unsigned char *reqauth, unsigned char *sec) {
md5_update(&mdctx, 16, reqauth);
if (len > 20)
md5_update(&mdctx, len - 20, rad + 20);
md5_update(&mdctx, strlen((char *) sec), sec);
md5_update(&mdctx, sec_len, sec);
md5_digest(&mdctx, sizeof(hash), hash);

result = !memcmp(hash, rad + 4, 16);
Expand All @@ -173,7 +172,7 @@ int _validauth(unsigned char *rad, unsigned char *reqauth, unsigned char *sec) {
return result;
}

int _createmessageauth(unsigned char *rad, unsigned char *authattrval, uint8_t *secret) {
int _createmessageauth(unsigned char *rad, unsigned char *authattrval, uint8_t *secret, int secret_len) {
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
struct hmac_md5_ctx hmacctx;

Expand All @@ -183,30 +182,42 @@ int _createmessageauth(unsigned char *rad, unsigned char *authattrval, uint8_t *
pthread_mutex_lock(&lock);

memset(authattrval, 0, 16);
hmac_md5_set_key(&hmacctx, strlen((char *) secret), secret);
hmac_md5_set_key(&hmacctx, secret_len, secret);
hmac_md5_update(&hmacctx, RADLEN(rad), rad);
hmac_md5_digest(&hmacctx, MD5_DIGEST_SIZE, authattrval);

pthread_mutex_unlock(&lock);
return 1;
}

int _radsign(unsigned char *rad, unsigned char *sec) {
int _radsign(unsigned char *rad, unsigned char *sec, int sec_len) {
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
struct md5_ctx mdctx;

pthread_mutex_lock(&lock);

md5_init(&mdctx);
md5_update(&mdctx, RADLEN(rad), rad);
md5_update(&mdctx, strlen((char *) sec), sec);
md5_update(&mdctx, sec_len, sec);
md5_digest(&mdctx, MD5_DIGEST_SIZE, rad + 4);

pthread_mutex_unlock(&lock);
return 1;
}

uint8_t *radmsg2buf(struct radmsg *msg, uint8_t *secret) {
uint8_t *tlv2buf(uint8_t *p, const struct tlv *tlv) {
p[0] = tlv->t;
p[1] = tlv->l+2;
if (tlv->l) {
if (tlv->v)
memcpy(p+2, tlv->v, tlv->l);
else
memset(p+2, 0, tlv->l);
}
return p;
}

uint8_t *radmsg2buf(struct radmsg *msg, uint8_t *secret, int secret_len) {
struct list_node *node;
struct tlv *tlv;
int size;
Expand Down Expand Up @@ -234,17 +245,16 @@ uint8_t *radmsg2buf(struct radmsg *msg, uint8_t *secret) {
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 (tlv->t == RAD_Attr_Message_Authenticator && secret)
msgauth = ATTRVAL(p);
p += tlv->l + 2;
}
if (msgauth && !_createmessageauth(buf, msgauth, secret)) {
if (msgauth && !_createmessageauth(buf, msgauth, secret, secret_len)) {
free(buf);
return NULL;
}
if (secret) {
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_Request) && !_radsign(buf, secret)) {
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_Request) && !_radsign(buf, secret, secret_len)) {
free(buf);
return NULL;
}
Expand All @@ -255,7 +265,7 @@ uint8_t *radmsg2buf(struct radmsg *msg, uint8_t *secret) {
}

/* 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, int secret_len, uint8_t *rqauth) {
struct radmsg *msg;
uint8_t t, l, *v = NULL, *p, auth[16];
uint16_t len;
Expand All @@ -267,13 +277,13 @@ struct radmsg *buf2radmsg(uint8_t *buf, uint8_t *secret, uint8_t *rqauth) {

if (secret && buf[0] == RAD_Accounting_Request) {
memset(auth, 0, 16);
if (!_validauth(buf, auth, secret)) {
if (!_validauth(buf, auth, secret, secret_len)) {
debug(DBG_WARN, "buf2radmsg: Accounting-Request message authentication failed");
return NULL;
}
}

if (rqauth && secret && !_validauth(buf, rqauth, secret)) {
if (rqauth && secret && !_validauth(buf, rqauth, secret, secret_len)) {
debug(DBG_WARN, "buf2radmsg: Invalid auth, ignoring reply");
return NULL;
}
Expand Down Expand Up @@ -305,7 +315,7 @@ struct radmsg *buf2radmsg(uint8_t *buf, uint8_t *secret, uint8_t *rqauth) {
if (t == RAD_Attr_Message_Authenticator && secret) {
if (rqauth)
memcpy(buf + 4, rqauth, 16);
if (l != 16 || !_checkmsgauth(buf, v, secret)) {
if (l != 16 || !_checkmsgauth(buf, v, secret, secret_len)) {
debug(DBG_WARN, "buf2radmsg: message authentication failed");
if (rqauth)
memcpy(buf + 4, msg->auth, 16);
Expand All @@ -327,6 +337,83 @@ struct radmsg *buf2radmsg(uint8_t *buf, uint8_t *secret, uint8_t *rqauth) {
return msg;
}

/* should accept both names and numeric values, only numeric right now */
uint8_t attrname2val(char *attrname) {
int val = 0;

val = atoi(attrname);
return val > 0 && val < 256 ? val : 0;
}

/* ATTRNAME is on the form vendor[:type].
If only vendor is found, TYPE is set to 256 and 1 is returned.
If type is >= 256, 1 is returned.
Otherwise, 0 is returned.
*/
/* should accept both names and numeric values, only numeric right now */
int vattrname2val(char *attrname, uint32_t *vendor, uint32_t *type) {
char *s;

*vendor = atoi(attrname);
s = strchr(attrname, ':');
if (!s) { /* Only vendor was found. */
*type = 256;
return 1;
}
*type = atoi(s + 1);
return *type < 256;
}

int attrvalidate(unsigned char *attrs, int length) {
while (length > 1) {
if (ATTRLEN(attrs) < 2) {
debug(DBG_INFO, "attrvalidate: invalid attribute length %d", ATTRLEN(attrs));
return 0;
}
length -= ATTRLEN(attrs);
if (length < 0) {
debug(DBG_INFO, "attrvalidate: attribute length %d exceeds packet length", ATTRLEN(attrs));
return 0;
}
attrs += ATTRLEN(attrs);
}
if (length)
debug(DBG_INFO, "attrvalidate: malformed packet? remaining byte after last attribute");
return 1;
}

/** Create vendor specific tlv with ATTR. ATTR is consumed (freed) if
* all is well with the new tlv, i.e. if the function returns
* !NULL. */
struct tlv *makevendortlv(uint32_t vendor, struct tlv *attr){
struct tlv *newtlv = NULL;
uint8_t l, *v;

if (!attr || attr->l > (RAD_Max_Attr_Value_Length - 6))
return NULL;
l = attr->l + 2 + 4;
v = malloc(l);
if (v) {
vendor = htonl(vendor & 0x00ffffff); /* MSB=0 according to RFC 2865. */
memcpy(v, &vendor, 4);
tlv2buf(v + 4, attr);
newtlv = maketlv(RAD_Attr_Vendor_Specific, l, v);
free(v);
if (newtlv)
freetlv(attr);
}
return newtlv;
}

int resizeattr(struct tlv *attr, uint8_t newlen) {
if (newlen > RAD_Max_Attr_Value_Length)
return 0;

if (resizetlv(attr, newlen))
return 1;
return 0;
}

/* Local Variables: */
/* c-file-style: "stroustrup" */
/* End: */
Loading

0 comments on commit 687c8cd

Please sign in to comment.