summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--Makefile.am4
-rw-r--r--radmsg.c238
-rw-r--r--radmsg.h41
-rw-r--r--radsecproxy.c654
-rw-r--r--radsecproxy.h25
-rw-r--r--tlv11.c118
-rw-r--r--tlv11.h23
-rw-r--r--udp.c2
9 files changed, 694 insertions, 413 deletions
diff --git a/Makefile b/Makefile
index 0bff710..102f5cc 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
CFLAGS = -g -Wall -pedantic -pthread
LDFLAGS = -lssl
-OBJ = util.o debug.o list.o hash.o gconfig.o udp.o tcp.o tls.o dtls.o radsecproxy.o
+OBJ = util.o debug.o list.o hash.o gconfig.o tlv11.o radmsg.o udp.o tcp.o tls.o dtls.o radsecproxy.o
all: radsecproxy
diff --git a/Makefile.am b/Makefile.am
index 11bf5c9..2e7d1cc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,6 +6,8 @@ radsecproxy_SOURCES = radsecproxy.c \
debug.c \
list.c \
hash.c \
+ tlv11.c \
+ radmsg.c \
udp.c \
tcp.c \
tls.c \
@@ -16,6 +18,8 @@ radsecproxy_SOURCES = radsecproxy.c \
util.h \
list.h \
hash.h \
+ tlv11.h \
+ radmsg.h \
udp.h \
tcp.h \
tls.h \
diff --git a/radmsg.c b/radmsg.c
new file mode 100644
index 0000000..26f8fbe
--- /dev/null
+++ b/radmsg.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2006-2008 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
+ * copyright notice and this permission notice appear in all copies.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include "list.h"
+#include "tlv11.h"
+#include "radmsg.h"
+#include "debug.h"
+#include <pthread.h>
+#include <openssl/hmac.h>
+
+#define RADLEN(x) ntohs(((uint16_t *)(x))[1])
+
+void radmsg_free(struct radmsg *msg) {
+ if (msg) {
+ freetlvlist(msg->attrs);
+ free(msg);
+ }
+}
+
+struct radmsg *radmsg_init(uint8_t code, uint8_t id, uint8_t *auth) {
+ struct radmsg *msg;
+
+ msg = malloc(sizeof(struct radmsg));
+ if (!msg)
+ return NULL;
+ msg->attrs = list_create();
+ if (!msg->attrs) {
+ free(msg);
+ return NULL;
+ }
+ msg->code = code;
+ msg->id = id;
+ memcpy(msg->auth, auth, 16);
+ return msg;
+}
+
+int radmsg_add(struct radmsg *msg, struct tlv *attr) {
+ if (!msg || !msg->attrs)
+ return 1;
+ if (!attr)
+ return 0;
+ return list_push(msg->attrs, attr);
+}
+
+/* returns first tlv of the given type */
+struct tlv *radmsg_gettype(struct radmsg *msg, uint8_t type) {
+ struct list_node *node;
+ struct tlv *tlv;
+
+ if (!msg)
+ return NULL;
+ for (node = list_first(msg->attrs); node; node = list_next(node)) {
+ tlv = (struct tlv *)node->data;
+ if (tlv->t == type)
+ return tlv;
+ }
+ 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) {
+ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+ static unsigned char first = 1;
+ static HMAC_CTX hmacctx;
+ unsigned int md_len;
+ uint8_t auth[16], hash[EVP_MAX_MD_SIZE];
+
+ pthread_mutex_lock(&lock);
+ if (first) {
+ HMAC_CTX_init(&hmacctx);
+ first = 0;
+ }
+
+ memcpy(auth, authattr, 16);
+ memset(authattr, 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, hash, &md_len);
+ memcpy(authattr, auth, 16);
+ if (md_len != 16) {
+ debug(DBG_WARN, "message auth computation failed");
+ pthread_mutex_unlock(&lock);
+ return 0;
+ }
+
+ if (memcmp(auth, hash, 16)) {
+ debug(DBG_WARN, "message authenticator, wrong value");
+ pthread_mutex_unlock(&lock);
+ return 0;
+ }
+
+ pthread_mutex_unlock(&lock);
+ return 1;
+}
+
+int _validauth(unsigned char *rad, unsigned char *reqauth, unsigned char *sec) {
+ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+ static unsigned char first = 1;
+ static EVP_MD_CTX mdctx;
+ unsigned char hash[EVP_MAX_MD_SIZE];
+ unsigned int len;
+ int result;
+
+ pthread_mutex_lock(&lock);
+ if (first) {
+ EVP_MD_CTX_init(&mdctx);
+ first = 0;
+ }
+
+ len = RADLEN(rad);
+
+ result = (EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL) &&
+ EVP_DigestUpdate(&mdctx, rad, 4) &&
+ EVP_DigestUpdate(&mdctx, reqauth, 16) &&
+ (len <= 20 || EVP_DigestUpdate(&mdctx, rad + 20, len - 20)) &&
+ EVP_DigestUpdate(&mdctx, sec, strlen((char *)sec)) &&
+ EVP_DigestFinal_ex(&mdctx, hash, &len) &&
+ len == 16 &&
+ !memcmp(hash, rad + 4, 16));
+ pthread_mutex_unlock(&lock);
+ return result;
+}
+
+/* if secret set we also validate message authenticator if present */
+struct radmsg *buf2radmsg(uint8_t *buf, uint8_t *secret, uint8_t *rqauth) {
+ struct radmsg *msg;
+ uint8_t t, l, *v, *p, auth[16];
+ uint16_t len;
+ struct tlv *attr;
+
+ len = RADLEN(buf);
+ if (len < 20)
+ return NULL;
+
+ if (secret && buf[0] == RAD_Accounting_Request) {
+ memset(auth, 0, 16);
+ if (!_validauth(buf, auth, secret)) {
+ debug(DBG_WARN, "buf2radmsg: Accounting-Request message authentication failed");
+ return NULL;
+ }
+ }
+
+ if (rqauth && !_validauth(buf, rqauth, secret)) {
+ debug(DBG_WARN, "buf2radmsg: Invalid auth, ignoring reply");
+ return NULL;
+ }
+
+ msg = radmsg_init(buf[0], buf[1], (uint8_t *)buf + 4);
+ if (!msg)
+ return NULL;
+
+ p = buf + 20;
+ while (p - buf + 2 <= len) {
+ t = *p++;
+ l = *p++;
+ if (l < 2) {
+ debug(DBG_WARN, "buf2radmsg: invalid attribute length %d", l);
+ radmsg_free(msg);
+ return NULL;
+ }
+ l -= 2;
+ if (l) {
+ if (p - buf + l > len) {
+ debug(DBG_WARN, "buf2radmsg: attribute length %d exceeds packet length", l + 2);
+ radmsg_free(msg);
+ return NULL;
+ }
+ v = p;
+ p += l;
+ }
+
+ if (t == RAD_Attr_Message_Authenticator && secret) {
+ if (rqauth)
+ memcpy(buf + 4, rqauth, 16);
+ if (l != 16 || !_checkmsgauth(buf, v, secret)) {
+ debug(DBG_WARN, "buf2radmsg: message authentication failed");
+ if (rqauth)
+ memcpy(buf + 4, msg->auth, 16);
+ radmsg_free(msg);
+ return NULL;
+ }
+ if (rqauth)
+ memcpy(buf + 4, msg->auth, 16);
+ debug(DBG_DBG, "buf2radmsg: message auth ok");
+ }
+
+ attr = maketlv(t, l, v);
+ if (!attr || !radmsg_add(msg, attr)) {
+ freetlv(attr);
+ radmsg_free(msg);
+ return NULL;
+ }
+ }
+ return msg;
+}
diff --git a/radmsg.h b/radmsg.h
new file mode 100644
index 0000000..d6df94f
--- /dev/null
+++ b/radmsg.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2006-2008 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
+ * copyright notice and this permission notice appear in all copies.
+ */
+
+#define RAD_Access_Request 1
+#define RAD_Access_Accept 2
+#define RAD_Access_Reject 3
+#define RAD_Accounting_Request 4
+#define RAD_Accounting_Response 5
+#define RAD_Access_Challenge 11
+#define RAD_Status_Server 12
+#define RAD_Status_Client 13
+
+#define RAD_Attr_User_Name 1
+#define RAD_Attr_User_Password 2
+#define RAD_Attr_Reply_Message 18
+#define RAD_Attr_Vendor_Specific 26
+#define RAD_Attr_Calling_Station_Id 31
+#define RAD_Attr_Tunnel_Password 69
+#define RAD_Attr_Message_Authenticator 80
+
+#define RAD_VS_ATTR_MS_MPPE_Send_Key 16
+#define RAD_VS_ATTR_MS_MPPE_Recv_Key 17
+
+struct radmsg {
+ uint8_t code;
+ uint8_t id;
+ uint8_t auth[20];
+ struct list *attrs;
+};
+
+void radmsg_free(struct radmsg *);
+struct radmsg *radmsg_init(uint8_t, uint8_t, uint8_t *);
+int radmsg_add(struct radmsg *, struct tlv *);
+struct tlv *radmsg_gettype(struct radmsg *, uint8_t);
+uint8_t *radmsg2buf(struct radmsg *msg);
+struct radmsg *buf2radmsg(uint8_t *, uint8_t *, uint8_t *);
diff --git a/radsecproxy.c b/radsecproxy.c
index 48543ef..ef27a11 100644
--- a/radsecproxy.c
+++ b/radsecproxy.c
@@ -62,6 +62,8 @@
#include "debug.h"
#include "list.h"
#include "hash.h"
+#include "tlv11.h"
+#include "radmsg.h"
#include "util.h"
#include "gconfig.h"
#include "radsecproxy.h"
@@ -900,70 +902,6 @@ int radsign(unsigned char *rad, unsigned char *sec) {
return result;
}
-int validauth(unsigned char *rad, unsigned char *reqauth, unsigned char *sec) {
- static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
- static unsigned char first = 1;
- static EVP_MD_CTX mdctx;
- unsigned char hash[EVP_MAX_MD_SIZE];
- unsigned int len;
- int result;
-
- pthread_mutex_lock(&lock);
- if (first) {
- EVP_MD_CTX_init(&mdctx);
- first = 0;
- }
-
- len = RADLEN(rad);
-
- result = (EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL) &&
- EVP_DigestUpdate(&mdctx, rad, 4) &&
- EVP_DigestUpdate(&mdctx, reqauth, 16) &&
- (len <= 20 || EVP_DigestUpdate(&mdctx, rad + 20, len - 20)) &&
- EVP_DigestUpdate(&mdctx, sec, strlen((char *)sec)) &&
- EVP_DigestFinal_ex(&mdctx, hash, &len) &&
- len == 16 &&
- !memcmp(hash, rad + 4, 16));
- pthread_mutex_unlock(&lock);
- return result;
-}
-
-int checkmessageauth(unsigned char *rad, uint8_t *authattr, char *secret) {
- static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
- static unsigned char first = 1;
- static HMAC_CTX hmacctx;
- unsigned int md_len;
- uint8_t auth[16], hash[EVP_MAX_MD_SIZE];
-
- pthread_mutex_lock(&lock);
- if (first) {
- HMAC_CTX_init(&hmacctx);
- first = 0;
- }
-
- memcpy(auth, authattr, 16);
- memset(authattr, 0, 16);
- md_len = 0;
- HMAC_Init_ex(&hmacctx, secret, strlen(secret), EVP_md5(), NULL);
- HMAC_Update(&hmacctx, rad, RADLEN(rad));
- HMAC_Final(&hmacctx, hash, &md_len);
- memcpy(authattr, auth, 16);
- if (md_len != 16) {
- debug(DBG_WARN, "message auth computation failed");
- pthread_mutex_unlock(&lock);
- return 0;
- }
-
- if (memcmp(auth, hash, 16)) {
- debug(DBG_WARN, "message authenticator, wrong value");
- pthread_mutex_unlock(&lock);
- return 0;
- }
-
- pthread_mutex_unlock(&lock);
- return 1;
-}
-
int createmessageauth(unsigned char *rad, unsigned char *authattrval, char *secret) {
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static unsigned char first = 1;
@@ -1458,136 +1396,100 @@ int findvendorsubattr(uint32_t *attrs, uint32_t vendor, uint8_t subattr) {
return 0;
}
-int dovendorrewriterm(uint8_t *attrs, uint16_t length, uint32_t *removevendorattrs) {
- uint8_t alen, sublen, rmlen = 0;
- uint32_t vendor = *(uint32_t *)ATTRVAL(attrs);
+/* returns 1 if entire element is to be removed, else 0 */
+int dovendorrewriterm(struct tlv *attr, uint32_t *removevendorattrs) {
+ uint8_t alen, sublen;
+ uint32_t vendor;
uint8_t *subattrs;
if (!removevendorattrs)
return 0;
+ memcpy(&vendor, attr->v, 4);
+ vendor = ntohl(vendor);
while (*removevendorattrs && *removevendorattrs != vendor)
removevendorattrs += 2;
if (!*removevendorattrs)
return 0;
- alen = ATTRLEN(attrs);
-
- if (findvendorsubattr(removevendorattrs, vendor, -1)) {
- /* remove entire vendor attribute */
- memmove(attrs, attrs + alen, length - alen);
- return alen;
- }
+ if (findvendorsubattr(removevendorattrs, vendor, -1))
+ return 1; /* remove entire vendor attribute */
- sublen = alen - 4;
- subattrs = ATTRVAL(attrs) + 4;
+ sublen = attr->l - 4;
+ subattrs = attr->v + 4;
if (!attrvalidate(subattrs, sublen)) {
debug(DBG_WARN, "dovendorrewrite: vendor attribute validation failed, no rewrite");
return 0;
}
- length -= 6;
while (sublen > 1) {
alen = ATTRLEN(subattrs);
sublen -= alen;
- length -= alen;
if (findvendorsubattr(removevendorattrs, vendor, ATTRTYPE(subattrs))) {
- memmove(subattrs, subattrs + alen, length);
- rmlen += alen;
+ memmove(subattrs, subattrs + alen, sublen);
+ attr->l -= alen;
} else
subattrs += alen;
}
-
- ATTRLEN(attrs) -= rmlen;
- return rmlen;
+ return 0;
}
-void dorewriterm(uint8_t *buf, uint8_t *rmattrs, uint32_t *rmvattrs) {
- uint8_t *attrs, alen;
- uint16_t len, rmlen = 0;
-
- len = RADLEN(buf) - 20;
- attrs = buf + 20;
- while (len > 1) {
- alen = ATTRLEN(attrs);
- len -= alen;
- if (rmattrs && strchr((char *)rmattrs, ATTRTYPE(attrs))) {
- memmove(attrs, attrs + alen, len);
- rmlen += alen;
- } else if (ATTRTYPE(attrs) == RAD_Attr_Vendor_Specific && rmvattrs)
- rmlen += dovendorrewriterm(attrs, len, rmvattrs);
- else
- attrs += alen;
+void dorewriterm(struct radmsg *msg, uint8_t *rmattrs, uint32_t *rmvattrs) {
+ struct list_node *n, *p;
+ struct tlv *attr;
+
+ p = NULL;
+ n = list_first(msg->attrs);
+ while (n) {
+ attr = (struct tlv *)n->data;
+ if ((rmattrs && strchr((char *)rmattrs, attr->t)) ||
+ (rmvattrs && attr->t == RAD_Attr_Vendor_Specific && dovendorrewriterm(attr, rmvattrs))) {
+ list_removedata(msg->attrs, attr);
+ freetlv(attr);
+ n = p ? list_next(p) : list_first(msg->attrs);
+ } else
+ p = n;
+ n = list_next(n);
}
- if (rmlen)
- ((uint16_t *)buf)[1] = htons(RADLEN(buf) - rmlen);
}
-int dorewriteadd(uint8_t **buf, struct list *addattrs) {
+int dorewriteadd(struct radmsg *msg, struct list *addattrs) {
struct list_node *n;
- struct attribute *a;
- uint16_t i, addlen = 0;
- uint8_t *newbuf;
+ struct tlv *a;
- for (n = list_first(addattrs); n; n = list_next(n))
- addlen += 2 + ((struct attribute *)n->data)->l;
- if (!addlen)
- return 1;
- newbuf = realloc(*buf, RADLEN(*buf) + addlen);
- if (!newbuf)
- return 0;
-
- i = RADLEN(newbuf);
for (n = list_first(addattrs); n; n = list_next(n)) {
- a = (struct attribute *)n->data;
- newbuf[i++] = a->t;
- newbuf[i++] = a->l + 2;
- memcpy(newbuf + i, a->v, a->l);
- i += a->l;
- }
- ((uint16_t *)newbuf)[1] = htons(RADLEN(newbuf) + addlen);
- *buf = newbuf;
+ a = copytlv((struct tlv *)n->data);
+ if (!a)
+ return 0;
+ if (!radmsg_add(msg, a)) {
+ freetlv(a);
+ return 0;
+ }
+ }
return 1;
}
-/* returns a pointer to the resized attribute value */
-uint8_t *resizeattr(uint8_t **buf, uint8_t **attr, uint8_t newvallen) {
- uint8_t vallen;
- uint16_t len;
- unsigned char *new;
-
- vallen = ATTRVALLEN(*attr);
- if (vallen == newvallen)
- return *attr + 2;
+int resizeattr2(struct tlv *attr, uint8_t newlen) {
+ uint8_t *newv;
- len = RADLEN(*buf) + newvallen - vallen;
-
- if (newvallen > vallen) {
- new = realloc(*buf, len);
- if (!new) {
- debug(DBG_ERR, "resizeattr: malloc failed");
- return NULL;
- }
- if (new != *buf) {
- *attr += new - *buf;
- *buf = new;
- }
+ if (newlen != attr->l) {
+ newv = realloc(attr->v, newlen);
+ if (!newv)
+ return 0;
+ attr->v = newv;
+ attr->l = newlen;
}
- memmove(*attr + 2 + newvallen, *attr + 2 + vallen, len - (*attr - *buf + newvallen));
- (*attr)[1] = newvallen + 2;
- ((uint16_t *)*buf)[1] = htons(len);
- return *attr + 2;
+ return 1;
}
-int dorewritemodattr(uint8_t **buf, uint8_t **attr, struct modattr *modattr) {
+int dorewritemodattr(struct tlv *attr, struct modattr *modattr) {
size_t nmatch = 10, reslen = 0, start = 0;
regmatch_t pmatch[10], *pfield;
int i;
- unsigned char *result;
char *in, *out;
- in = stringcopy((char *)ATTRVAL(*attr), ATTRVALLEN(*attr));
+ in = stringcopy((char *)attr->v, attr->l);
if (!in)
return 0;
@@ -1614,21 +1516,21 @@ int dorewritemodattr(uint8_t **buf, uint8_t **attr, struct modattr *modattr) {
free(in);
return 0;
}
- result = resizeattr(buf, attr, reslen);
- if (!result) {
+
+ if (!resizeattr2(attr, reslen)) {
free(in);
return 0;
}
-
+
start = 0;
reslen = 0;
for (i = start; out[i]; i++) {
if (out[i] == '\\' && out[i + 1] >= '1' && out[i + 1] <= '9') {
pfield = &pmatch[out[i + 1] - '0'];
if (pfield->rm_so >= 0) {
- memcpy(result + reslen, out + start, i - start);
+ memcpy(attr->v + reslen, out + start, i - start);
reslen += i - start;
- memcpy(result + reslen, in + pfield->rm_so, pfield->rm_eo - pfield->rm_so);
+ memcpy(attr->v + reslen, in + pfield->rm_so, pfield->rm_eo - pfield->rm_so);
reslen += pfield->rm_eo - pfield->rm_so;
start = i + 2;
}
@@ -1636,51 +1538,43 @@ int dorewritemodattr(uint8_t **buf, uint8_t **attr, struct modattr *modattr) {
}
}
- memcpy(result + reslen, out + start, i - start);
+ memcpy(attr->v + reslen, out + start, i - start);
return 1;
}
-
-int dorewritemod(uint8_t **buf, struct list *modattrs) {
- uint8_t *attr;
- uint16_t len = 0;
- struct list_node *n;
- attr = *buf + 20;
- while (RADLEN(*buf) - 22 >= len) {
- for (n = list_first(modattrs); n; n = list_next(n))
- if (ATTRTYPE(attr) == ((struct modattr *)n->data)->t)
- if (!dorewritemodattr(buf, &attr, (struct modattr *)n->data))
- return 0;
- len += ATTRLEN(attr);
- attr += ATTRLEN(attr);
- }
+int dorewritemod(struct radmsg *msg, struct list *modattrs) {
+ struct list_node *n, *m;
+
+ for (n = list_first(msg->attrs); n; n = list_next(n))
+ for (m = list_first(modattrs); m; m = list_next(m))
+ if (((struct tlv *)n->data)->t == ((struct modattr *)m->data)->t &&
+ !dorewritemodattr((struct tlv *)n->data, (struct modattr *)m->data))
+ return 0;
return 1;
}
-int dorewrite(uint8_t **buf, struct rewrite *rewrite) {
+int dorewrite(struct radmsg *msg, struct rewrite *rewrite) {
if (!rewrite)
return 1;
if (rewrite->removeattrs || rewrite->removevendorattrs)
- dorewriterm(*buf, rewrite->removeattrs, rewrite->removevendorattrs);
- if (rewrite->addattrs && !dorewriteadd(buf, rewrite->addattrs))
+ dorewriterm(msg, rewrite->removeattrs, rewrite->removevendorattrs);
+ if (rewrite->addattrs && !dorewriteadd(msg, rewrite->addattrs))
return 0;
- if (rewrite->modattrs && !dorewritemod(buf, rewrite->modattrs))
+ if (rewrite->modattrs && !dorewritemod(msg, rewrite->modattrs))
return 0;
return 1;
}
-
-int rewriteusername(struct request *rq, uint8_t *attr, char *in) {
- if (!dorewritemodattr(&rq->buf, &attr, rq->from->conf->rewriteusername))
- return 0;
- if (strlen(in) == ATTRVALLEN(attr) && !memcmp(in, ATTRVAL(attr), ATTRVALLEN(attr)))
- return 1;
- rq->origusername = stringcopy(in, 0);
- if (!rq->origusername)
+int rewriteusername(struct request *rq, struct tlv *attr) {
+ char *orig = (char *)tlv2str(attr);
+ if (!dorewritemodattr(attr, rq->from->conf->rewriteusername)) {
+ free(orig);
return 0;
-
- memcpy(in, ATTRVAL(attr), ATTRVALLEN(attr));
- in[ATTRVALLEN(attr)] = '\0';
+ }
+ if (strlen(orig) != attr->l || memcmp(orig, attr->v, attr->l))
+ rq->origusername = (char *)orig;
+ else
+ free(orig);
return 1;
}
@@ -1734,19 +1628,52 @@ char *radattr2ascii(char *ascii, size_t len, unsigned char *attr) {
return ascii;
}
-void acclog(unsigned char *attrs, int length, char *host) {
- unsigned char *attr;
- char username[760];
+uint8_t *radattr2ascii2(struct tlv *attr) {
+ int i, l;
+ uint8_t *a, *d;
+
+ if (!attr)
+ return NULL;
+
+ l = attr->l;
+ for (i = 0; i < attr->l; i++)
+ if (attr->v[i] < 32 || attr->v[i] > 126)
+ l += 2;
+ if (l == attr->l)
+ return (uint8_t *)stringcopy((char *)attr->v, attr->l);
+
+ a = malloc(l + 1);
+ if (!a)
+ return NULL;
+
+ d = a;
+ for (i = 0; i < attr->l; i++)
+ if (attr->v[i] < 32 || attr->v[i] > 126) {
+ *d++ = '%';
+ char2hex((char *)d, attr->v[i]);
+ d += 2;
+ } else
+ *d++ = attr->v[i];
+ *d = '\0';
+ return a;
+}
+
+void acclog(struct radmsg *msg, char *host) {
+ struct tlv *attr;
+ uint8_t *username;
- attr = attrget(attrs, length, RAD_Attr_User_Name);
+ attr = radmsg_gettype(msg, RAD_Attr_User_Name);
if (!attr) {
debug(DBG_INFO, "acclog: accounting-request from %s without username attribute", host);
return;
}
- radattr2ascii(username, sizeof(username), attr);
- debug(DBG_INFO, "acclog: accounting-request from %s with username: %s", host, username);
+ username = radattr2ascii2(attr);
+ if (username) {
+ debug(DBG_INFO, "acclog: accounting-request from %s with username: %s", host, username);
+ free(username);
+ }
}
-
+
void respondaccounting(struct request *rq) {
unsigned char *resp;
@@ -1826,115 +1753,92 @@ struct clsrvconf *choosesrvconf(struct list *srvconfs) {
return best ? best : first;
}
-struct server *findserver(struct realm **realm, char *id, uint8_t acc) {
+struct server *findserver(struct realm **realm, struct tlv *username, uint8_t acc) {
struct clsrvconf *srvconf;
+ char *id = (char *)tlv2str(username);
+ if (!id)
+ return NULL;
*realm = id2realm(realms, id);
- if (!*realm)
+ if (!*realm) {
+ free(id);
return NULL;
+ }
debug(DBG_DBG, "found matching realm: %s", (*realm)->name);
srvconf = choosesrvconf(acc ? (*realm)->accsrvconfs : (*realm)->srvconfs);
- if (!srvconf)
+ if (!srvconf) {
+ free(id);
return NULL;
+ }
if (!acc && !srvconf->servers)
adddynamicrealmserver(*realm, srvconf, id);
+ free(id);
return srvconf->servers;
}
/* returns 0 if validation/authentication fails, else 1 */
int radsrv(struct request *rq) {
- uint8_t code, id, *auth, *attrs, *attr;
- uint16_t len;
- struct server *to = NULL;
- char username[254], userascii[760];
+ struct radmsg *msg = NULL;
+ struct tlv *attr;
+ uint8_t *userascii = NULL;
unsigned char newauth[16];
struct realm *realm = NULL;
-
- code = *(uint8_t *)rq->buf;
- id = *(uint8_t *)(rq->buf + 1);
- len = RADLEN(rq->buf);
- auth = (uint8_t *)(rq->buf + 4);
+ struct server *to = NULL;
- debug(DBG_DBG, "radsrv: code %d, id %d, length %d", code, id, len);
+ msg = buf2radmsg(rq->buf, (uint8_t *)rq->from->conf->secret, NULL);
+ if (!msg) {
+ debug(DBG_WARN, "radsrv: message validation failed, ignoring packet");
+ freerqdata(rq);
+ return 0;
+ }
+ debug(DBG_DBG, "radsrv: code %d, id %d", msg->code, msg->id);
- if (code != RAD_Access_Request && code != RAD_Status_Server && code != RAD_Accounting_Request) {
+ if (msg->code != RAD_Access_Request && msg->code != RAD_Status_Server && msg->code != RAD_Accounting_Request) {
debug(DBG_INFO, "radsrv: server currently accepts only access-requests, accounting-requests and status-server, ignoring");
goto exit;
}
- len -= 20;
- attrs = rq->buf + 20;
-
- if (!attrvalidate(attrs, len)) {
- debug(DBG_WARN, "radsrv: attribute validation failed, ignoring packet");
- goto errvalauth;
- }
-
- attr = attrget(attrs, len, RAD_Attr_Message_Authenticator);
- if (attr && (ATTRVALLEN(attr) != 16 || !checkmessageauth(rq->buf, ATTRVAL(attr), rq->from->conf->secret))) {
- debug(DBG_WARN, "radsrv: message authentication failed");
- goto errvalauth;
- }
-
- if (code == RAD_Status_Server) {
+ if (msg->code == RAD_Status_Server) {
respondstatusserver(rq);
goto exit;
}
-
+
/* below: code == RAD_Access_Request || code == RAD_Accounting_Request */
- if (code == RAD_Accounting_Request) {
- memset(newauth, 0, 16);
- if (!validauth(rq->buf, newauth, (unsigned char *)rq->from->conf->secret)) {
- debug(DBG_WARN, "radsrv: Accounting-Request message authentication failed");
- goto errvalauth;
- }
- }
-
- if (rq->from->conf->rewritein) {
- if (!dorewrite(&rq->buf, rq->from->conf->rewritein))
- goto exit;
- len = RADLEN(rq->buf) - 20;
- auth = (uint8_t *)(rq->buf + 4);
- attrs = rq->buf + 20;
- }
-
- attr = attrget(attrs, len, RAD_Attr_User_Name);
+ if (rq->from->conf->rewritein && !dorewrite(msg, rq->from->conf->rewritein))
+ goto exit;
+
+ attr = radmsg_gettype(msg, RAD_Attr_User_Name);
if (!attr) {
- if (code == RAD_Accounting_Request) {
- acclog(attrs, len, rq->from->conf->host);
+ if (msg->code == RAD_Accounting_Request) {
+ acclog(msg, rq->from->conf->host);
respondaccounting(rq);
} else
debug(DBG_WARN, "radsrv: ignoring access request, no username attribute");
goto exit;
}
- memcpy(username, ATTRVAL(attr), ATTRVALLEN(attr));
- username[ATTRVALLEN(attr)] = '\0';
- radattr2ascii(userascii, sizeof(userascii), attr);
- if (rq->from->conf->rewriteusername) {
- if (!rewriteusername(rq, attr, username)) {
- debug(DBG_WARN, "radsrv: username malloc failed, ignoring request");
- goto exit;
- }
- len = RADLEN(rq->buf) - 20;
- auth = (uint8_t *)(rq->buf + 4);
- attrs = rq->buf + 20;
+ if (rq->from->conf->rewriteusername && !rewriteusername(rq, attr)) {
+ debug(DBG_WARN, "radsrv: username malloc failed, ignoring request");
+ goto exit;
}
-
- debug(DBG_DBG, "%s with username: %s", radmsgtype2string(code), userascii);
- to = findserver(&realm, username, code == RAD_Accounting_Request);
+ userascii = radattr2ascii2(attr);
+ if (!userascii)
+ goto exit;
+ debug(DBG_DBG, "%s with username: %s", radmsgtype2string(msg->code), userascii);
+
+ to = findserver(&realm, attr, msg->code == RAD_Accounting_Request);
if (!realm) {
debug(DBG_INFO, "radsrv: ignoring request, don't know where to send it");
goto exit;
}
if (!to) {
- if (realm->message && code == RAD_Access_Request) {
+ if (realm->message && msg->code == RAD_Access_Request) {
debug(DBG_INFO, "radsrv: sending reject to %s for %s", rq->from->conf->host, userascii);
respondreject(rq, realm->message);
- } else if (realm->accresp && code == RAD_Accounting_Request) {
- acclog(attrs, len, rq->from->conf->host);
+ } else if (realm->accresp && msg->code == RAD_Accounting_Request) {
+ acclog(msg, rq->from->conf->host);
respondaccounting(rq);
}
goto exit;
@@ -1946,13 +1850,13 @@ int radsrv(struct request *rq) {
goto exit;
}
- if (rqinqueue(to, rq->from, id, code)) {
+ if (rqinqueue(to, rq->from, msg->id, msg->code)) {
debug(DBG_INFO, "radsrv: already got %s from host %s with id %d, ignoring",
- radmsgtype2string(code), rq->from->conf->host, id);
+ radmsgtype2string(msg->code), rq->from->conf->host, msg->id);
goto exit;
}
- if (code != RAD_Accounting_Request) {
+ if (msg->code != RAD_Accounting_Request) {
if (!RAND_bytes(newauth, 16)) {
debug(DBG_WARN, "radsrv: failed to generate random auth");
goto exit;
@@ -1963,146 +1867,116 @@ int radsrv(struct request *rq) {
printfchars(NULL, "auth", "%02x ", auth, 16);
#endif
- attr = attrget(attrs, len, RAD_Attr_User_Password);
+ attr = radmsg_gettype(msg, RAD_Attr_User_Password);
if (attr) {
- debug(DBG_DBG, "radsrv: found userpwdattr with value length %d", ATTRVALLEN(attr));
- if (!pwdrecrypt(ATTRVAL(attr), ATTRVALLEN(attr), rq->from->conf->secret, to->conf->secret, auth, newauth))
+ debug(DBG_DBG, "radsrv: found userpwdattr with value length %d", attr->l);
+ if (!pwdrecrypt(attr->v, attr->l, rq->from->conf->secret, to->conf->secret, msg->auth, newauth))
goto exit;
}
-
- attr = attrget(attrs, len, RAD_Attr_Tunnel_Password);
+
+ attr = radmsg_gettype(msg, RAD_Attr_Tunnel_Password);
if (attr) {
- debug(DBG_DBG, "radsrv: found tunnelpwdattr with value length %d", ATTRVALLEN(attr));
- if (!pwdrecrypt(ATTRVAL(attr), ATTRVALLEN(attr), rq->from->conf->secret, to->conf->secret, auth, newauth))
+ debug(DBG_DBG, "radsrv: found tunnelpwdattr with value length %d", attr->l);
+ if (!pwdrecrypt(attr->v, attr->l, rq->from->conf->secret, to->conf->secret, msg->auth, newauth))
goto exit;
}
- rq->origid = id;
- memcpy(rq->origauth, auth, 16);
- memcpy(auth, newauth, 16);
+ rq->origid = msg->id;
+ memcpy(rq->origauth, msg->auth, 16);
+ memcpy(msg->auth, newauth, 16);
- if (to->conf->rewriteout)
- if (!dorewrite(&rq->buf, to->conf->rewriteout))
- goto exit;
+ if (to->conf->rewriteout && !dorewrite(msg, to->conf->rewriteout))
+ goto exit;
+ free(rq->buf);
+ rq->buf = radmsg2buf(msg);
+ if (!rq->buf)
+ goto exit;
+ free(userascii);
+ radmsg_free(msg);
+
sendrq(to, rq);
return 1;
exit:
+ free(userascii);
+ radmsg_free(msg);
freerqdata(rq);
return 1;
-
- errvalauth:
- freerqdata(rq);
- return 0;
}
int replyh(struct server *server, unsigned char *buf) {
struct client *from;
struct request *rq;
- int i, len, sublen;
- unsigned char *messageauth, *subattrs, *attrs, *attr, *username;
+ int sublen;
+ unsigned char *subattrs, *rqattr;
struct sockaddr_storage fromsa;
char tmp[760], stationid[760];
+ struct radmsg *msg = NULL;
+ struct tlv *attr, *messageauth;
+ struct list_node *node;
server->connectionok = 1;
server->lostrqs = 0;
-
- i = buf[1]; /* i is the id */
- if (*buf != RAD_Access_Accept && *buf != RAD_Access_Reject && *buf != RAD_Access_Challenge
- && *buf != RAD_Accounting_Response) {
- debug(DBG_INFO, "replyh: discarding message type %s, accepting only access accept, access reject, access challenge and accounting response messages", radmsgtype2string(*buf));
+ rq = server->requests + buf[1];
+ msg = buf2radmsg(buf, (uint8_t *)server->conf->secret, rq->buf + 4);
+ if (!msg) {
+ debug(DBG_WARN, "replyh: message validation failed, ignoring packet");
return 0;
}
- debug(DBG_DBG, "got %s message with id %d", radmsgtype2string(*buf), i);
-
- rq = server->requests + i;
+ if (msg->code != RAD_Access_Accept && msg->code != RAD_Access_Reject && msg->code != RAD_Access_Challenge
+ && 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));
+ radmsg_free(msg);
+ return 0;
+ }
+ debug(DBG_DBG, "got %s message with id %d", radmsgtype2string(msg->code), msg->id);
pthread_mutex_lock(&server->newrq_mutex);
if (!rq->buf || !rq->tries) {
- pthread_mutex_unlock(&server->newrq_mutex);
debug(DBG_INFO, "replyh: no matching request sent with this id, ignoring reply");
- return 0;
+ goto errunlock;
}
if (rq->received) {
- pthread_mutex_unlock(&server->newrq_mutex);
debug(DBG_INFO, "replyh: already received, ignoring reply");
- return 0;
- }
-
- if (!validauth(buf, rq->buf + 4, (unsigned char *)server->conf->secret)) {
- pthread_mutex_unlock(&server->newrq_mutex);
- debug(DBG_WARN, "replyh: invalid auth, ignoring reply");
- return 0;
- }
-
- len = RADLEN(buf) - 20;
- attrs = buf + 20;
-
- if (!attrvalidate(attrs, len)) {
- pthread_mutex_unlock(&server->newrq_mutex);
- debug(DBG_WARN, "replyh: attribute validation failed, ignoring reply");
- return 0;
+ goto errunlock;
}
- /* Message Authenticator */
- messageauth = attrget(attrs, len, RAD_Attr_Message_Authenticator);
- if (messageauth) {
- if (ATTRVALLEN(messageauth) != 16) {
- pthread_mutex_unlock(&server->newrq_mutex);
- debug(DBG_WARN, "replyh: illegal message auth attribute length, ignoring reply");
- return 0;
- }
- memcpy(tmp, buf + 4, 16);
- memcpy(buf + 4, rq->buf + 4, 16);
- if (!checkmessageauth(buf, ATTRVAL(messageauth), server->conf->secret)) {
- pthread_mutex_unlock(&server->newrq_mutex);
- debug(DBG_WARN, "replyh: message authentication failed, ignoring reply");
- return 0;
- }
- memcpy(buf + 4, tmp, 16);
- debug(DBG_DBG, "replyh: message auth ok");
- }
-
gettimeofday(&server->lastrcv, NULL);
if (*rq->buf == RAD_Status_Server) {
rq->received = 1;
- pthread_mutex_unlock(&server->newrq_mutex);
debug(DBG_DBG, "replyh: got status server response from %s", server->conf->host);
- return 0;
+ goto errunlock;
}
gettimeofday(&server->lastreply, NULL);
from = rq->from;
if (!from) {
- pthread_mutex_unlock(&server->newrq_mutex);
debug(DBG_INFO, "replyh: client gone, ignoring reply");
- return 0;
+ goto errunlock;
}
- if (server->conf->rewritein) {
- if (!dorewrite(&buf, server->conf->rewritein))
- return 0;
- len = RADLEN(buf) - 20;
- attrs = buf + 20;
- if (messageauth)
- messageauth = attrget(attrs, len, RAD_Attr_Message_Authenticator);
+ if (server->conf->rewritein && !dorewrite(msg, rq->from->conf->rewritein)) {
+ debug(DBG_WARN, "replyh: rewritein failed");
+ goto errunlock;
}
/* MS MPPE */
- for (attr = attrs; (attr = attrget(attr, len - (attr - attrs), RAD_Attr_Vendor_Specific)); attr += ATTRLEN(attr)) {
- if (ATTRVALLEN(attr) <= 4)
+ for (node = list_first(msg->attrs); node; node = list_next(node)) {
+ attr = (struct tlv *)node->data;
+ if (attr->t != RAD_Attr_Vendor_Specific)
+ continue;
+ if (attr->l <= 4)
break;
-
- if (attr[2] != 0 || attr[3] != 0 || attr[4] != 1 || attr[5] != 55) /* 311 == MS */
+ if (attr->v[0] != 0 || attr->v[1] != 0 || attr->v[2] != 1 || attr->v[3] != 55) /* 311 == MS */
continue;
- sublen = ATTRVALLEN(attr) - 4;
- subattrs = ATTRVAL(attr) + 4;
+ sublen = attr->l - 4;
+ subattrs = attr->v + 4;
if (!attrvalidate(subattrs, sublen) ||
!msmppe(subattrs, sublen, RAD_VS_ATTR_MS_MPPE_Send_Key, "MS MPPE Send Key",
rq, server->conf->secret, from->conf->secret) ||
@@ -2110,62 +1984,63 @@ int replyh(struct server *server, unsigned char *buf) {
rq, server->conf->secret, from->conf->secret))
break;
}
- if (attr) {
- pthread_mutex_unlock(&server->newrq_mutex);
+ if (node) {
debug(DBG_WARN, "replyh: MS attribute handling failed, ignoring reply");
- return 0;
+ goto errunlock;
}
-
- if (*buf == RAD_Access_Accept || *buf == RAD_Access_Reject || *buf == RAD_Accounting_Response) {
- attr = attrget(rq->buf + 20, RADLEN(rq->buf) - 20, RAD_Attr_User_Name);
- if (attr) {
- radattr2ascii(tmp, sizeof(tmp), attr);
- attr = attrget(rq->buf + 20, RADLEN(rq->buf) - 20, RAD_Attr_Calling_Station_Id);
- if (attr) {
- radattr2ascii(stationid, sizeof(stationid), attr);
+
+ 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);
+ if (rqattr) {
+ radattr2ascii(tmp, sizeof(tmp), rqattr);
+ rqattr = attrget(rq->buf + 20, RADLEN(rq->buf) - 20, RAD_Attr_Calling_Station_Id);
+ if (rqattr) {
+ radattr2ascii(stationid, sizeof(stationid), rqattr);
debug(DBG_INFO, "%s for user %s stationid %s from %s",
- radmsgtype2string(*buf), tmp, stationid, server->conf->host);
+ radmsgtype2string(msg->code), tmp, stationid, server->conf->host);
} else
- debug(DBG_INFO, "%s for user %s from %s", radmsgtype2string(*buf), tmp, server->conf->host);
+ debug(DBG_INFO, "%s for user %s from %s", radmsgtype2string(msg->code), tmp, server->conf->host);
}
}
-
- buf[1] = (char)rq->origid;
- memcpy(buf + 4, rq->origauth, 16);
+
+ msg->id = (char)rq->origid;
+ memcpy(msg->auth, rq->origauth, 16);
+
#ifdef DEBUG
printfchars(NULL, "origauth/buf+4", "%02x ", buf + 4, 16);
#endif
- if (rq->origusername && (attr = attrget(buf + 20, RADLEN(buf) - 20, RAD_Attr_User_Name))) {
- username = resizeattr(&buf, &attr, strlen(rq->origusername));
- if (!username) {
- pthread_mutex_unlock(&server->newrq_mutex);
+ if (rq->origusername && (attr = radmsg_gettype(msg, RAD_Attr_User_Name))) {
+ if (!resizeattr2(attr, strlen(rq->origusername))) {
debug(DBG_WARN, "replyh: malloc failed, ignoring reply");
- return 0;
+ goto errunlock;
}
- memcpy(username, rq->origusername, strlen(rq->origusername));
- len = RADLEN(buf) - 20;
- attrs = buf + 20;
- if (messageauth)
- messageauth = attrget(attrs, len, RAD_Attr_Message_Authenticator);
+ memcpy(attr->v, rq->origusername, strlen(rq->origusername));
}
-
- if (from->conf->rewriteout) {
- if (!dorewrite(&buf, from->conf->rewriteout))
- return 0;
- len = RADLEN(buf) - 20;
- attrs = buf + 20;
- if (messageauth)
- messageauth = attrget(attrs, len, RAD_Attr_Message_Authenticator);
+
+ if (from->conf->rewriteout && !dorewrite(msg, from->conf->rewriteout)) {
+ debug(DBG_WARN, "replyh: rewriteout failed");
+ goto errunlock;
}
-
+
+ free(buf);
+ buf = radmsg2buf(msg);
+ radmsg_free(msg);
+ msg = NULL;
+ if (!buf) {
+ debug(DBG_ERR, "replyh: malloc failed");
+ goto errunlock;
+ }
+
if (messageauth) {
- if (!createmessageauth(buf, ATTRVAL(messageauth), from->conf->secret)) {
- pthread_mutex_unlock(&server->newrq_mutex);
- debug(DBG_WARN, "replyh: failed to create authenticator, malloc failed?, ignoring reply");
- return 0;
+ rqattr = attrget(buf + 20, RADLEN(buf) - 20, RAD_Attr_Message_Authenticator);
+ if (rqattr) {
+ if (!createmessageauth(buf, ATTRVAL(rqattr), from->conf->secret)) {
+ debug(DBG_WARN, "replyh: failed to create authenticator, malloc failed?, ignoring reply");
+ goto errunlock;
+ }
+ debug(DBG_DBG, "replyh: computed messageauthattr");
}
- debug(DBG_DBG, "replyh: computed messageauthattr");
}
fromsa = rq->fromsa; /* only needed for UDP */
@@ -2176,6 +2051,11 @@ int replyh(struct server *server, unsigned char *buf) {
sendreply(from, buf, &fromsa, rq->fromudpsock);
pthread_mutex_unlock(&server->newrq_mutex);
return 1;
+
+ errunlock:
+ radmsg_free(msg);
+ pthread_mutex_unlock(&server->newrq_mutex);
+ return 0;
}
/* code for removing state not finished */
@@ -2915,10 +2795,10 @@ int vattrname2val(char *attrname, uint32_t *vendor, uint32_t *type) {
}
/* should accept both names and numeric values, only numeric right now */
-struct attribute *extractattr(char *nameval) {
+struct tlv *extractattr(char *nameval) {
int len, name = 0;
char *s;
- struct attribute *a;
+ struct tlv *a;
s = strchr(nameval, ':');
name = atoi(nameval);
@@ -2927,7 +2807,7 @@ struct attribute *extractattr(char *nameval) {
len = strlen(s + 1);
if (len > 253)
return NULL;
- a = malloc(sizeof(struct attribute));
+ a = malloc(sizeof(struct tlv));
if (!a)
return NULL;
a->v = (uint8_t *)stringcopy(s + 1, 0);
@@ -3015,7 +2895,7 @@ void addrewrite(char *value, char **rmattrs, char **rmvattrs, char **addattrs, c
uint8_t *rma = NULL;
uint32_t *p, *rmva = NULL;
struct list *adda = NULL, *moda = NULL;
- struct attribute *a;
+ struct tlv *a;
struct modattr *m;
if (rmattrs) {
diff --git a/radsecproxy.h b/radsecproxy.h
index f14e232..84780c4 100644
--- a/radsecproxy.h
+++ b/radsecproxy.h
@@ -17,31 +17,12 @@
#define MAX_CERT_DEPTH 5
#define STATUS_SERVER_PERIOD 25
#define IDLE_TIMEOUT 300
-#define RAD_Access_Request 1
-#define RAD_Access_Accept 2
-#define RAD_Access_Reject 3
-#define RAD_Accounting_Request 4
-#define RAD_Accounting_Response 5
-#define RAD_Access_Challenge 11
-#define RAD_Status_Server 12
-#define RAD_Status_Client 13
#define RAD_UDP 0
#define RAD_TLS 1
#define RAD_TCP 2
#define RAD_DTLS 3
-#define RAD_Attr_User_Name 1
-#define RAD_Attr_User_Password 2
-#define RAD_Attr_Reply_Message 18
-#define RAD_Attr_Vendor_Specific 26
-#define RAD_Attr_Calling_Station_Id 31
-#define RAD_Attr_Tunnel_Password 69
-#define RAD_Attr_Message_Authenticator 80
-
-#define RAD_VS_ATTR_MS_MPPE_Send_Key 16
-#define RAD_VS_ATTR_MS_MPPE_Recv_Key 17
-
struct options {
char **listenudp;
char **listentcp;
@@ -166,12 +147,6 @@ struct tls {
SSL_CTX *dtlsctx;
};
-struct attribute {
- uint8_t t;
- uint8_t l;
- uint8_t *v;
-};
-
struct modattr {
uint8_t t;
char *replacement;
diff --git a/tlv11.c b/tlv11.c
new file mode 100644
index 0000000..2593c15
--- /dev/null
+++ b/tlv11.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2008 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
+ * copyright notice and this permission notice appear in all copies.
+ */
+
+#include <stdint.h>
+#include "list.h"
+#include "tlv11.h"
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+struct tlv *maketlv(uint8_t t, uint8_t l, void *v) {
+ struct tlv *tlv;
+
+ tlv = malloc(sizeof(struct tlv));
+ if (!tlv)
+ return NULL;
+ tlv->t = t;
+ tlv->l = l;
+ if (l && v) {
+ tlv->v = malloc(l);
+ if (!tlv->v) {
+ free(tlv);
+ return NULL;
+ }
+ memcpy(tlv->v, v, l);
+ } else
+ tlv->v = NULL;
+ return tlv;
+}
+
+struct tlv *copytlv(struct tlv *in) {
+ return in ? maketlv(in->t, in->l, in->v) : NULL;
+}
+
+void freetlv(struct tlv *tlv) {
+ if (tlv) {
+ free(tlv->v);
+ free(tlv);
+ }
+}
+
+int eqtlv(struct tlv *t1, struct tlv *t2) {
+ if (!t1 || !t2)
+ return t1 == t2;
+ if (t1->t != t2->t || t1->l != t2->l)
+ return 0;
+ return memcmp(t1->v, t2->v, t1->l) == 0;
+}
+
+struct list *copytlvlist(struct list *tlvs) {
+ struct list *out;
+ struct list_node *node;
+
+ if (!tlvs)
+ return NULL;
+ out = list_create();
+ if (!out)
+ return NULL;
+ for (node = list_first(tlvs); node; node = list_next(node)) {
+ if (!list_push(out, copytlv((struct tlv *)node->data))) {
+ freetlvlist(out);
+ return NULL;
+ }
+ }
+ return out;
+}
+
+void freetlvlist(struct list *tlvs) {
+ struct tlv *tlv;
+ while ((tlv = (struct tlv *)list_shift(tlvs)))
+ freetlv(tlv);
+ list_destroy(tlvs);
+}
+
+void rmtlv(struct list *tlvs, uint8_t t) {
+ struct list_node *n, *p;
+ struct tlv *tlv;
+
+ p = NULL;
+ n = list_first(tlvs);
+ while (n) {
+ tlv = (struct tlv *)n->data;
+ if (tlv->t == t) {
+ list_removedata(tlvs, tlv);
+ freetlv(tlv);
+ n = p ? list_next(p) : list_first(tlvs);
+ } else {
+ p = n;
+ n = list_next(n);
+ }
+ }
+}
+
+uint8_t *tlv2str(struct tlv *tlv) {
+ uint8_t *s = malloc(tlv->l + 1);
+ if (s) {
+ memcpy(s, tlv->v, tlv->l);
+ s[tlv->l] = '\0';
+ }
+ return s;
+}
+
+uint8_t *tlv2buf(uint8_t *p, struct tlv *tlv) {
+ *p++ = tlv->t;
+ *p++ = tlv->l;
+ if (tlv->l) {
+ if (tlv->v)
+ memcpy(p, tlv->v, tlv->l);
+ else
+ memset(p, 0, tlv->l);
+ }
+ return p;
+}
diff --git a/tlv11.h b/tlv11.h
new file mode 100644
index 0000000..8a2c601
--- /dev/null
+++ b/tlv11.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2008 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
+ * copyright notice and this permission notice appear in all copies.
+ */
+
+struct tlv {
+ uint8_t t;
+ uint8_t l;
+ uint8_t *v;
+};
+
+struct tlv *maketlv(uint8_t, uint8_t, void *);
+struct tlv *copytlv(struct tlv *);
+void freetlv(struct tlv *);
+int eqtlv(struct tlv *, struct tlv *);
+struct list *copytlvlist(struct list *);
+void freetlvlist(struct list *);
+void rmtlv(struct list *, uint8_t);
+uint8_t *tlv2str(struct tlv *tlv);
+uint8_t *tlv2buf(uint8_t *, struct tlv *tlv);
diff --git a/udp.c b/udp.c
index db4dbfe..eff8a6e 100644
--- a/udp.c
+++ b/udp.c
@@ -27,6 +27,8 @@
#include <openssl/ssl.h>
#include "debug.h"
#include "list.h"
+#include "tlv11.h"
+#include "radmsg.h"
#include "util.h"
#include "radsecproxy.h"
#include "tls.h"