Skip to content
Permalink
1.9.2-mpi
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
/* Copyright (c) 2019, SWITCH */
/* See LICENSE for licensing information. */
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <regex.h>
#include <arpa/inet.h>
#include "debug.h"
#include "gconfig.h"
#include "hash.h"
#include "list.h"
#include "radmsg.h"
#include "rewrite.h"
#include "util.h"
static struct hash *rewriteconfs;
/** Extract attributes from string NAMEVAL, create a struct tlv and
* return the tlv. If VENDOR_FLAG, NAMEVAL is on the form
* "<vendor>:<name>:<val>" and otherwise it's "<name>:<val>". Return
* NULL if fields are missing or if conversion fails.
*
* FIXME: Should accept both names and numeric values, only numeric
* right now */
struct tlv *extractattr(char *nameval, char vendor_flag) {
int len, name = 0;
int vendor = 0; /* Vendor 0 is reserved, see RFC 1700. */
uint32_t ival=0;
char *s, *s2;
struct tlv *a;
s = strchr(nameval, ':');
if (!s)
return NULL;
name = atoi(nameval);
if (vendor_flag) {
s2 = strchr(s + 1, ':');
if (!s2)
return NULL;
vendor = name;
name = atoi(s + 1);
s = s2;
}
s++;
if (isdigit(*s)) {
ival = atoi(s);
ival = htonl(ival);
len = 4;
s = (char *)&ival;
} else {
if (*s == '\'')
s++;
len = unhex(s,1);
if (len > 253)
return NULL;
}
if (name < 1 || name > 255)
return NULL;
a = malloc(sizeof(struct tlv));
if (!a)
return NULL;
a->v = (uint8_t *)stringcopy(s, len);
if (!a->v) {
free(a);
return NULL;
}
a->t = name;
a->l = len;
if (vendor_flag)
a = makevendortlv(vendor, a);
return a;
}
/* should accept both names and numeric values, only numeric right now */
struct modattr *extractmodattr(char *nameval) {
int name = 0;
char *s, *t;
struct modattr *m;
if (!strncasecmp(nameval, "User-Name:/", 11)) {
s = nameval + 11;
name = 1;
} else {
s = strchr(nameval, ':');
name = atoi(nameval);
if (!s || name < 1 || name > 255 || s[1] != '/')
return NULL;
s += 2;
}
/* regexp, remove optional trailing / if present */
if (s[strlen(s) - 1] == '/')
s[strlen(s) - 1] = '\0';
for (t = strchr(s, '/'); t; t = strchr(t+1, '/'))
if (t == s || t[-1] != '\\')
break;
if (!t)
return NULL;
*t = '\0';
t++;
m = malloc(sizeof(struct modattr));
if (!m) {
debug(DBG_ERR, "malloc failed");
return NULL;
}
m->t = name;
m->replacement = stringcopy(t, 0);
if (!m->replacement) {
free(m);
debug(DBG_ERR, "malloc failed");
return NULL;
}
m->regex = malloc(sizeof(regex_t));
if (!m->regex) {
free(m->replacement);
free(m);
debug(DBG_ERR, "malloc failed");
return NULL;
}
if (regcomp(m->regex, s, REG_ICASE | REG_EXTENDED)) {
free(m->regex);
free(m->replacement);
free(m);
debug(DBG_ERR, "failed to compile regular expression %s", s);
return NULL;
}
return m;
}
struct modattr *extractmodvattr(char *nameval) {
uint32_t vendor;
char *s;
struct modattr *modvattr;
s = strchr(nameval, ':');
vendor = atoi(nameval);
if (!s || !vendor || !strchr(s+1,':'))
return NULL;
modvattr = extractmodattr(s+1);
if (modvattr)
modvattr ->vendor = vendor;
return modvattr;
}
void addrewrite(char *value, uint8_t whitelist_mode, char **rmattrs, char **rmvattrs, char **addattrs,
char **addvattrs, char **modattrs, char **modvattrs, char **supattrs, char** supvattrs)
{
struct rewrite *rewrite = NULL;
int i, n;
uint8_t *rma = NULL;
uint32_t *p, *rmva = NULL;
struct list *adda = NULL, *moda = NULL, *modva = NULL, *supa = NULL;
struct tlv *a;
struct modattr *m;
if (rmattrs) {
for (n = 0; rmattrs[n]; n++);
rma = calloc(n + 1, sizeof(uint8_t));
if (!rma)
debugx(1, DBG_ERR, "malloc failed");
for (i = 0; i < n; i++)
if (!(rma[i] = attrname2val(rmattrs[i])))
debugx(1, DBG_ERR, "addrewrite: removing invalid attribute %s", rmattrs[i]);
freegconfmstr(rmattrs);
rma[i] = 0;
}
if (rmvattrs) {
for (n = 0; rmvattrs[n]; n++);
rmva = calloc(2 * n + 1, sizeof(uint32_t));
if (!rmva)
debugx(1, DBG_ERR, "malloc failed");
for (p = rmva, i = 0; i < n; i++, p += 2)
if (!vattrname2val(rmvattrs[i], p, p + 1))
debugx(1, DBG_ERR, "addrewrite: removing invalid vendor attribute %s", rmvattrs[i]);
freegconfmstr(rmvattrs);
*p = 0;
}
if (addattrs) {
adda = list_create();
if (!adda)
debugx(1, DBG_ERR, "malloc failed");
for (i = 0; addattrs[i]; i++) {
a = extractattr(addattrs[i], 0);
if (!a)
debugx(1, DBG_ERR, "addrewrite: adding invalid attribute %s", addattrs[i]);
if (!list_push(adda, a))
debugx(1, DBG_ERR, "malloc failed");
}
freegconfmstr(addattrs);
}
if (addvattrs) {
if (!adda)
adda = list_create();
if (!adda)
debugx(1, DBG_ERR, "malloc failed");
for (i = 0; addvattrs[i]; i++) {
a = extractattr(addvattrs[i], 1);
if (!a)
debugx(1, DBG_ERR, "addrewrite: adding invalid vendor attribute %s", addvattrs[i]);
if (!list_push(adda, a))
debugx(1, DBG_ERR, "malloc failed");
}
freegconfmstr(addvattrs);
}
if (modattrs) {
moda = list_create();
if (!moda)
debugx(1, DBG_ERR, "malloc failed");
for (i = 0; modattrs[i]; i++) {
m = extractmodattr(modattrs[i]);
if (!m)
debugx(1, DBG_ERR, "addrewrite: modifying invalid attribute %s", modattrs[i]);
if (!list_push(moda, m))
debugx(1, DBG_ERR, "malloc failed");
}
freegconfmstr(modattrs);
}
if (modvattrs) {
modva = list_create();
if (!modva)
debugx(1, DBG_ERR, "malloc failed");
for (i = 0; modvattrs[i]; i++) {
m = extractmodvattr(modvattrs[i]);
if (!m)
debugx(1, DBG_ERR, "addrewrite: modifying invalid vendor attribute %s", modvattrs[i]);
if (!list_push(modva, m))
debugx(1, DBG_ERR, "malloc failed");
}
freegconfmstr(modvattrs);
}
if (supattrs) {
supa = list_create();
if (!supa)
debugx(1, DBG_ERR, "malloc failed");
for (i = 0; supattrs[i]; i++) {
a = extractattr(supattrs[i], 0);
if (!a)
debugx(1, DBG_ERR, "addrewrite: adding invalid attribute %s", supattrs[i]);
if (!list_push(supa, a))
debugx(1, DBG_ERR, "malloc failed");
}
freegconfmstr(supattrs);
}
if (supvattrs) {
if (!supa)
supa = list_create();
if (!supa)
debugx(1, DBG_ERR, "malloc failed");
for (i = 0; supvattrs[i]; i++) {
a = extractattr(supvattrs[i], 1);
if (!a)
debugx(1, DBG_ERR, "addrewrite: adding invalid vendor attribute %s", supvattrs[i]);
if (!list_push(supa, a))
debugx(1, DBG_ERR, "malloc failed");
}
freegconfmstr(supvattrs);
}
if (rma || rmva || adda || moda || modva || supa) {
rewrite = malloc(sizeof(struct rewrite));
if (!rewrite)
debugx(1, DBG_ERR, "malloc failed");
rewrite->whitelist_mode = whitelist_mode;
rewrite->removeattrs = rma;
rewrite->removevendorattrs = rmva;
rewrite->addattrs = adda;
rewrite->modattrs = moda;
rewrite->modvattrs = modva;
rewrite->supattrs = supa;
}
if (!rewriteconfs)
rewriteconfs = hash_create();
if (!hash_insert(rewriteconfs, value, strlen(value), rewrite))
debugx(1, DBG_ERR, "malloc failed");
debug(DBG_DBG, "addrewrite: added rewrite block %s", value);
}
struct rewrite *getrewrite(char *alt1, char *alt2) {
struct rewrite *r;
if (alt1)
if ((r = hash_read(rewriteconfs, alt1, strlen(alt1))))
return r;
if (alt2)
if ((r = hash_read(rewriteconfs, alt2, strlen(alt2))))
return r;
return NULL;
}
int findvendorsubattr(uint32_t *attrs, uint32_t vendor, uint32_t subattr) {
if (!attrs)
return 0;
for (; attrs[0]; attrs += 2)
if (attrs[0] == vendor && attrs[1] == subattr)
return 1;
return 0;
}
/* returns 1 if entire element is to be removed, else 0 */
int dovendorrewriterm(struct tlv *attr, uint32_t *removevendorattrs, int inverted) {
uint8_t alen, sublen;
uint32_t vendor;
uint8_t *subattrs;
if (!removevendorattrs || attr->l <= 4)
return 0;
memcpy(&vendor, attr->v, 4);
vendor = ntohl(vendor);
while (*removevendorattrs && *removevendorattrs != vendor)
removevendorattrs += 2;
if (!*removevendorattrs)
return 0;
if (findvendorsubattr(removevendorattrs, vendor, 256))
return 1; /* remove entire vendor attribute */
sublen = attr->l - 4;
subattrs = attr->v + 4;
if (!attrvalidate(subattrs, sublen)) {
debug(DBG_INFO, "dovendorrewrite: vendor attribute validation failed, no rewrite");
return 0;
}
while (sublen > 1) {
alen = ATTRLEN(subattrs);
sublen -= alen;
if (!!findvendorsubattr(removevendorattrs, vendor, ATTRTYPE(subattrs)) != !!inverted) {
memmove(subattrs, subattrs + alen, sublen);
attr->l -= alen;
} else
subattrs += alen;
}
if ((attr->l <= 4) != !!inverted)
return 1;
return 0;
}
/*if inverted is true, remove all attributes except those listed */
void dorewriterm(struct radmsg *msg, uint8_t *rmattrs, uint32_t *rmvattrs, int inverted) {
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, inverted))) != !!inverted) {
list_removedata(msg->attrs, attr);
freetlv(attr);
n = p ? list_next(p) : list_first(msg->attrs);
} else {
p = n;
n = list_next(n);
}
}
}
int dorewritemodattr(struct tlv *attr, struct modattr *modattr) {
size_t nmatch = 10, reslen = 0, start = 0;
regmatch_t pmatch[10], *pfield;
int i;
char *in, *out;
in = stringcopy((char *)attr->v, attr->l);
if (!in)
return 0;
if (regexec(modattr->regex, in, nmatch, pmatch, 0)) {
free(in);
return 1;
}
out = modattr->replacement;
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) {
reslen += i - start + pfield->rm_eo - pfield->rm_so;
start = i + 2;
}
i++;
}
}
reslen += i - start;
if (!resizeattr(attr, reslen)) {
debug(DBG_INFO, "rewritten attribute to length %zu failed, discarding message", 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(attr->v + reslen, out + start, i - start);
reslen += i - start;
memcpy(attr->v + reslen, in + pfield->rm_so, pfield->rm_eo - pfield->rm_so);
reslen += pfield->rm_eo - pfield->rm_so;
start = i + 2;
}
i++;
}
}
free(in);
memcpy(attr->v + reslen, out + start, i - start);
return 1;
}
int replacesubtlv(struct tlv *vendortlv, uint8_t *p, struct tlv *newtlv) {
int size_diff;
uint8_t rem_size, *next_attr;
size_diff = newtlv->l - ATTRLEN(p);
next_attr = p+ATTRLEN(p);
rem_size = (vendortlv->v + vendortlv->l) - next_attr;
if (size_diff < 0)
memmove(next_attr + size_diff, next_attr, rem_size);
if (!resizeattr(vendortlv, vendortlv->l+size_diff))
return 0;
if (size_diff > 0)
memmove(next_attr + size_diff, next_attr, rem_size);
tlv2buf(p, newtlv);
return 1;
}
int dorewritemodvattr(struct tlv *vendortlv, struct modattr *modvattr) {
struct tlv *tmpattr;
int offset;
if (vendortlv->l <= 4 || !attrvalidate(vendortlv->v+4, vendortlv->l-4))
return 0;
for (offset = 4; offset < vendortlv->l; offset += ATTRLEN(vendortlv->v+offset)) {
if (ATTRTYPE(vendortlv->v+offset) == modvattr->t) {
tmpattr = maketlv(ATTRTYPE(vendortlv->v+offset), ATTRVALLEN(vendortlv->v+offset), ATTRVAL(vendortlv->v+offset));
if (!tmpattr)
return 0;
if (dorewritemodattr(tmpattr, modvattr)) {
int size_diff = tmpattr->l - ATTRVALLEN(vendortlv->v+offset);
int rem_size = vendortlv->l - offset - ATTRLEN(vendortlv->v+offset);
uint8_t *next;
if (size_diff > 0)
if (!resizeattr(vendortlv, vendortlv->l+size_diff)) {
freetlv(tmpattr);
return 0;
}
next = vendortlv->v + offset + ATTRLEN(vendortlv->v+offset);
memmove(next + size_diff, next, rem_size);
if (size_diff < 0)
if (!resizeattr(vendortlv, vendortlv->l+size_diff)) {
freetlv(tmpattr);
return 0;
}
tlv2buf(vendortlv->v+offset, tmpattr);
} else {
freetlv(tmpattr);
return 0;
}
freetlv(tmpattr);
}
}
return 1;
}
int dorewritemod(struct radmsg *msg, struct list *modattrs, struct list *modvattrs) {
struct list_node *n, *m;
uint32_t vendor;
for (n = list_first(msg->attrs); n; n = list_next(n)) {
struct tlv *attr = (struct tlv *)n->data;
if (attr->t == RAD_Attr_Vendor_Specific) {
memcpy(&vendor, attr->v, 4);
vendor = ntohl(vendor);
for (m = list_first(modvattrs); m; m = list_next(m)) {
if (vendor == ((struct modattr *)m->data)->vendor &&
!dorewritemodvattr(attr, (struct modattr*)m->data))
return 0;
}
} else {
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 dorewriteadd(struct radmsg *msg, struct list *addattrs) {
struct list_node *n;
struct tlv *a;
for (n = list_first(addattrs); n; n = list_next(n)) {
a = copytlv((struct tlv *)n->data);
if (!a)
return 0;
if (!radmsg_add(msg, a)) {
freetlv(a);
return 0;
}
}
return 1;
}
int dorewritesup(struct radmsg *msg, struct list *supattrs) {
struct list_node *n, *p;
struct tlv *attr, *supattr;
uint8_t exist, *vendortype, *v;;
for (n = list_first(supattrs); n; n = list_next(n)) {
supattr = (struct tlv *)n->data;
exist = 0;
for(p = list_first(msg->attrs); p; p = list_next(p)) {
attr = (struct tlv *)p->data;
if (attr->t == supattr->t && attr->t != RAD_Attr_Vendor_Specific) {
exist = 1;
break;
} else if (supattr->t == RAD_Attr_Vendor_Specific && attr->t == RAD_Attr_Vendor_Specific &&
memcmp (supattr->v, attr->v, 4)==0) {
if (!attrvalidate(attr->v+4, attr->l-4)) {
debug(DBG_INFO, "dorewritesup: vendor attribute validation failed, no rewrite");
return 0;
}
vendortype = (uint8_t *)supattr->v+4;
for (v=attr->v+4; v < attr->v + attr->l; v += *(v+1)){
if (*v == *vendortype) {
exist = 1;
break;
}
}
if (exist) break;
}
}
if (!exist) {
supattr = copytlv(supattr);
if (!supattr)
return 0;
if (!radmsg_add(msg, supattr)) {
freetlv(supattr);
return 0;
}
}
}
return 1;
}
int dorewrite(struct radmsg *msg, struct rewrite *rewrite) {
int rv = 1; /* Success. */
if (rewrite) {
if (rewrite->removeattrs || rewrite->removevendorattrs)
dorewriterm(msg, rewrite->removeattrs, rewrite->removevendorattrs, rewrite->whitelist_mode);
if (rewrite->modattrs || rewrite->modvattrs)
if (!dorewritemod(msg, rewrite->modattrs, rewrite->modvattrs))
rv = 0;
if (rewrite->supattrs)
if (!dorewritesup(msg, rewrite->supattrs))
rv = 0;
if (rewrite->addattrs)
if (!dorewriteadd(msg, rewrite->addattrs))
rv = 0;
}
return rv;
}
/** Ad vendor attribute with VENDOR + ATTR and push it on MSG. ATTR
* is consumed. */
int addvendorattr(struct radmsg *msg, uint32_t vendor, struct tlv *attr) {
struct tlv *vattr;
vattr = makevendortlv(vendor, attr);
if (!vattr) {
freetlv(attr);
return 0;
}
if (!radmsg_add(msg, vattr)) {
freetlv(vattr);
return 0;
}
return 1;
}
/* Local Variables: */
/* c-file-style: "stroustrup" */
/* End: */