summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--radsecproxy.c162
1 files changed, 107 insertions, 55 deletions
diff --git a/radsecproxy.c b/radsecproxy.c
index 4413927..2bb47f2 100644
--- a/radsecproxy.c
+++ b/radsecproxy.c
@@ -1256,11 +1256,44 @@ int msmppe(unsigned char *attrs, int length, uint8_t type, char *attrtxt, struct
return 1;
}
-int rewriteattr(struct request *rq, char *in) {
+int resizeattr(unsigned char **buf, uint8_t newvallen, uint8_t type) {
+ uint8_t *attrs, *attr, vallen;
+ uint16_t len;
+ unsigned char *new;
+
+ len = RADLEN(*buf) - 20;
+ attrs = *buf + 20;
+
+ attr = attrget(attrs, len, type);
+ if (!attr)
+ return 0;
+
+ vallen = ATTRVALLEN(attr);
+ if (vallen == newvallen)
+ return 1;
+
+ len += newvallen - vallen;
+ new = realloc(*buf, len);
+ if (!new) {
+ debug(DBG_ERR, "resizeattr: malloc failed");
+ return 0;
+ }
+ if (new != *buf) {
+ attr += new - *buf;
+ attrs = new + 20;
+ *buf = new;
+ }
+ memmove(attr + 2 + newvallen, attr + 2 + vallen, len - (attr - attrs + newvallen));
+ attr[1] = newvallen + 2;
+ ((uint16_t *)new)[1] = htons(len);
+ return 1;
+}
+
+int rewriteusername(struct request *rq, char *in) {
size_t nmatch = 10, reslen = 0, start = 0;
regmatch_t pmatch[10], *pfield;
int i;
- char result[1024];
+ unsigned char *result;
char *out = rq->from->conf->rewriteattrreplacement;
if (regexec(rq->from->conf->rewriteattrregex, in, nmatch, pmatch, 0)) {
@@ -1276,6 +1309,23 @@ int rewriteattr(struct request *rq, char *in) {
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(&rq->buf, reslen, RAD_Attr_User_Name))
+ return 0;
+ result = ATTRVAL(attrget(rq->buf + 20, RADLEN(rq->buf) - 20, RAD_Attr_User_Name));
+
+ 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);
reslen += i - start;
memcpy(result + reslen, in + pfield->rm_so, pfield->rm_eo - pfield->rm_so);
@@ -1285,9 +1335,11 @@ int rewriteattr(struct request *rq, char *in) {
i++;
}
}
-
- memcpy(result + reslen, out + start, i + 1 - start);
- debug(DBG_DBG, "rewriteattr: username matching, %s would have rewritten to %s", in, result);
+
+ memcpy(result + reslen, out + start, i - start);
+ reslen += i - start;
+ memcpy(in, result, reslen);
+ in[reslen] = '\0';
return 1;
}
@@ -1385,14 +1437,13 @@ void radsrv(struct request *rq) {
uint16_t len;
struct server *to = NULL;
char username[256];
- unsigned char *buf, newauth[16];
+ unsigned char newauth[16];
struct realm *realm = NULL;
- buf = rq->buf;
- code = *(uint8_t *)buf;
- id = *(uint8_t *)(buf + 1);
- len = RADLEN(buf);
- auth = (uint8_t *)(buf + 4);
+ code = *(uint8_t *)rq->buf;
+ id = *(uint8_t *)(rq->buf + 1);
+ len = RADLEN(rq->buf);
+ auth = (uint8_t *)(rq->buf + 4);
debug(DBG_DBG, "radsrv: code %d, id %d, length %d", code, id, len);
@@ -1403,7 +1454,7 @@ void radsrv(struct request *rq) {
}
len -= 20;
- attrs = buf + 20;
+ attrs = rq->buf + 20;
if (!attrvalidate(attrs, len)) {
debug(DBG_WARN, "radsrv: attribute validation failed, ignoring packet");
@@ -1411,59 +1462,60 @@ void radsrv(struct request *rq) {
return;
}
- if (code == RAD_Access_Request) {
- attr = attrget(attrs, len, RAD_Attr_User_Name);
- if (!attr) {
- debug(DBG_WARN, "radsrv: ignoring request, no username attribute");
- freerqdata(rq);
- return;
+ 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");
+ freerqdata(rq);
+ return;
+ }
+
+ if (code != RAD_Access_Request) {
+ switch (code) {
+ case RAD_Accounting_Request:
+ acclog(attrs, len, rq->from->conf->host);
+ respondaccounting(rq);
+ break;
+ case RAD_Status_Server:
+ respondstatusserver(rq);
+ break;
}
- memcpy(username, ATTRVAL(attr), ATTRVALLEN(attr));
- username[ATTRVALLEN(attr)] = '\0';
+ freerqdata(rq);
+ return;
+ }
- if (rq->from->conf->rewriteattrregex)
- if (!rewriteattr(rq, username)) {
- debug(DBG_WARN, "radsrv: username malloc failed, ignoring request");
- freerqdata(rq);
- return;
- }
+ /* code == RAD_Access_Request */
+ attr = attrget(attrs, len, RAD_Attr_User_Name);
+ if (!attr) {
+ debug(DBG_WARN, "radsrv: ignoring request, no username attribute");
+ freerqdata(rq);
+ return;
+ }
+ memcpy(username, ATTRVAL(attr), ATTRVALLEN(attr));
+ username[ATTRVALLEN(attr)] = '\0';
- if (rq->origusername)
- debug(DBG_DBG, "Access Request with username: %s (originally %s)", username, rq->origusername);
- else
- debug(DBG_DBG, "Access Request with username: %s", username);
-
- realm = id2realm(username, strlen(username));
- if (!realm) {
- debug(DBG_INFO, "radsrv: ignoring request, don't know where to send it");
+ if (rq->from->conf->rewriteattrregex) {
+ if (!rewriteusername(rq, username)) {
+ debug(DBG_WARN, "radsrv: username malloc failed, ignoring request");
freerqdata(rq);
return;
}
+ len = RADLEN(rq->buf) - 20;
+ auth = (uint8_t *)(rq->buf + 4);
+ attrs = rq->buf + 20;
+ debug(DBG_DBG, "Access Request with username: %s (originally %s)", username, rq->origusername);
+ } else
+ debug(DBG_DBG, "Access Request with username: %s", username);
- to = realm2server(realm);
- if (to && rqinqueue(to, rq->from, id)) {
- debug(DBG_INFO, "radsrv: already got request from host %s with id %d, ignoring", rq->from->conf->host, id);
- freerqdata(rq);
- return;
- }
- }
-
- attr = attrget(attrs, len, RAD_Attr_Message_Authenticator);
- if (attr && (ATTRVALLEN(attr) != 16 || !checkmessageauth(buf, ATTRVAL(attr), rq->from->conf->secret))) {
- debug(DBG_WARN, "radsrv: message authentication failed");
- freerqdata(rq);
- return;
- }
-
- if (code == RAD_Accounting_Request) {
- acclog(attrs, len, rq->from->conf->host);
- respondaccounting(rq);
+ realm = id2realm(username, strlen(username));
+ if (!realm) {
+ debug(DBG_INFO, "radsrv: ignoring request, don't know where to send it");
freerqdata(rq);
return;
}
-
- if (code == RAD_Status_Server) {
- respondstatusserver(rq);
+
+ to = realm2server(realm);
+ if (to && rqinqueue(to, rq->from, id)) {
+ debug(DBG_INFO, "radsrv: already got request from host %s with id %d, ignoring", rq->from->conf->host, id);
freerqdata(rq);
return;
}