#include <freeradius-devel/ident.h>
RCSID("$Id$")
#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/modules.h>
#include <freeradius-devel/rad_assert.h>
#include <ctype.h>
#ifdef HAVE_REGEX_H
#include <regex.h>
#ifndef REG_EXTENDED
#define REG_EXTENDED (0)
#endif
#ifndef REG_NOSUB
#define REG_NOSUB (0)
#endif
#endif
#ifdef WITH_UNLANG
static int all_digits(const char *string)
{
const char *p = string;
if (*p == '-') p++;
while (isdigit((int) *p)) p++;
return (*p == '\0');
}
static const char *filler = "????????????????????????????????????????????????????????????????";
static const char *expand_string(char *buffer, size_t sizeof_buffer,
REQUEST *request,
FR_TOKEN value_type, const char *value)
{
int result;
char *p;
switch (value_type) {
default:
case T_BARE_WORD:
case T_SINGLE_QUOTED_STRING:
return value;
case T_BACK_QUOTED_STRING:
result = radius_exec_program(value, request, 1,
buffer, sizeof_buffer, NULL,
NULL, 0);
if (result != 0) {
return NULL;
}
for (p = buffer; *p != '\0'; p++) {
if (*p < ' ' ) {
*p = '\0';
return buffer;
}
}
return buffer;
case T_DOUBLE_QUOTED_STRING:
if (!strchr(value, '%')) return value;
radius_xlat(buffer, sizeof_buffer, value, request, NULL);
return buffer;
}
return NULL;
}
#ifdef HAVE_REGEX_H
static FR_TOKEN getregex(const char **ptr, char *buffer, size_t buflen,
int *pcflags)
{
const char *p = *ptr;
char *q = buffer;
if (*p != '/') return T_OP_INVALID;
*pcflags = REG_EXTENDED;
p++;
while (*p) {
if (buflen <= 1) break;
if (*p == '/') {
p++;
if (*p == 'i') {
p++;
*pcflags |= REG_ICASE;
}
break;
}
if (*p == '\\') {
int x;
switch (p[1]) {
case 'r':
*q++ = '\r';
break;
case 'n':
*q++ = '\n';
break;
case 't':
*q++ = '\t';
break;
case '"':
*q++ = '"';
break;
case '\'':
*q++ = '\'';
break;
case '`':
*q++ = '`';
break;
default:
if ((p[1] >= '0') && (p[1] <= '9') &&
(sscanf(p + 1, "%3o", &x) == 1)) {
*q++ = x;
p += 2;
} else {
*q++ = p[1];
}
break;
}
p += 2;
buflen--;
continue;
}
*(q++) = *(p++);
buflen--;
}
*q = '\0';
*ptr = p;
return T_DOUBLE_QUOTED_STRING;
}
#endif
static const FR_NAME_NUMBER modreturn_table[] = {
{ "reject", RLM_MODULE_REJECT },
{ "fail", RLM_MODULE_FAIL },
{ "ok", RLM_MODULE_OK },
{ "handled", RLM_MODULE_HANDLED },
{ "invalid", RLM_MODULE_INVALID },
{ "userlock", RLM_MODULE_USERLOCK },
{ "notfound", RLM_MODULE_NOTFOUND },
{ "noop", RLM_MODULE_NOOP },
{ "updated", RLM_MODULE_UPDATED },
{ NULL, 0 }
};
int radius_get_vp(REQUEST *request, const char *name, VALUE_PAIR **vp_p)
{
const char *vp_name = name;
REQUEST *myrequest = request;
DICT_ATTR *da;
VALUE_PAIR *vps = NULL;
*vp_p = NULL;
if (strncmp(vp_name, "outer.", 6) == 0) {
if (!myrequest->parent) return TRUE;
vp_name += 6;
myrequest = myrequest->parent;
}
if (strncmp(vp_name, "request:", 8) == 0) {
vp_name += 8;
vps = myrequest->packet->vps;
} else if (strncmp(vp_name, "reply:", 6) == 0) {
vp_name += 6;
vps = myrequest->reply->vps;
#ifdef WITH_PROXY
} else if (strncmp(vp_name, "proxy-request:", 14) == 0) {
vp_name += 14;
if (request->proxy) vps = myrequest->proxy->vps;
} else if (strncmp(vp_name, "proxy-reply:", 12) == 0) {
vp_name += 12;
if (request->proxy_reply) vps = myrequest->proxy_reply->vps;
#endif
} else if (strncmp(vp_name, "config:", 7) == 0) {
vp_name += 7;
vps = myrequest->config_items;
} else if (strncmp(vp_name, "control:", 8) == 0) {
vp_name += 8;
vps = myrequest->config_items;
#ifdef WITH_COA
} else if (strncmp(vp_name, "coa:", 4) == 0) {
vp_name += 4;
if (myrequest->coa &&
(myrequest->coa->proxy->code == PW_COA_REQUEST)) {
vps = myrequest->coa->proxy->vps;
}
} else if (strncmp(vp_name, "coa-reply:", 10) == 0) {
vp_name += 10;
if (myrequest->coa &&
(myrequest->coa->proxy->code == PW_COA_REQUEST) &&
(myrequest->coa->proxy_reply)) {
vps = myrequest->coa->proxy_reply->vps;
}
} else if (strncmp(vp_name, "disconnect:", 11) == 0) {
vp_name += 11;
if (myrequest->coa &&
(myrequest->coa->proxy->code == PW_DISCONNECT_REQUEST)) {
vps = myrequest->coa->proxy->vps;
}
} else if (strncmp(vp_name, "disconnect-reply:", 17) == 0) {
vp_name += 17;
if (myrequest->coa &&
(myrequest->coa->proxy->code == PW_DISCONNECT_REQUEST) &&
(myrequest->coa->proxy_reply)) {
vps = myrequest->coa->proxy_reply->vps;
}
#endif
} else {
vps = myrequest->packet->vps;
}
da = dict_attrbyname(vp_name);
if (!da) return FALSE;
*vp_p = pairfind(vps, da->attr);
return TRUE;
}
static int radius_do_cmp(REQUEST *request, int *presult,
FR_TOKEN lt, const char *pleft, FR_TOKEN token,
FR_TOKEN rt, const char *pright,
int cflags, int modreturn)
{
int result;
uint32_t lint, rint;
VALUE_PAIR *vp = NULL;
#ifdef HAVE_REGEX_H
char buffer[8192];
#else
cflags = cflags;
#endif
rt = rt;
if (lt == T_BARE_WORD) {
if (token == T_OP_CMP_TRUE) {
int isreturn;
isreturn = fr_str2int(modreturn_table, pleft, -1);
if (isreturn != -1) {
*presult = (modreturn == isreturn);
return TRUE;
}
}
if (radius_get_vp(request, pleft, &vp)) {
VALUE_PAIR myvp;
if (token == T_OP_CMP_TRUE) {
*presult = (vp != NULL);
return TRUE;
}
if (!vp) {
DICT_ATTR *da;
da = dict_attrbyname(pleft);
if (da && radius_find_compare(da->attr)) {
VALUE_PAIR *check = pairmake(pleft, pright, token);
*presult = (radius_callback_compare(request, NULL, check, NULL, NULL) == 0);
RDEBUG3(" Callback returns %d",
*presult);
pairfree(&check);
return TRUE;
}
RDEBUG2(" (Attribute %s was not found)",
pleft);
*presult = 0;
return TRUE;
}
#ifdef HAVE_REGEX_H
if ((token == T_OP_REG_EQ) ||
(token == T_OP_REG_NE)) {
vp_prints_value(buffer, sizeof(buffer), vp, 0);
pleft = buffer;
goto do_checks;
}
#endif
memcpy(&myvp, vp, sizeof(myvp));
if (!pairparsevalue(&myvp, pright)) {
RDEBUG2("Failed parsing \"%s\": %s",
pright, fr_strerror());
return FALSE;
}
myvp.operator = token;
*presult = paircmp(&myvp, vp);
RDEBUG3(" paircmp -> %d", *presult);
return TRUE;
}
}
#ifdef HAVE_REGEX_H
do_checks:
#endif
switch (token) {
case T_OP_GE:
case T_OP_GT:
case T_OP_LE:
case T_OP_LT:
if (!all_digits(pright)) {
RDEBUG2(" (Right field is not a number at: %s)", pright);
return FALSE;
}
rint = strtoul(pright, NULL, 0);
if (!all_digits(pleft)) {
RDEBUG2(" (Left field is not a number at: %s)", pleft);
return FALSE;
}
lint = strtoul(pleft, NULL, 0);
break;
default:
lint = rint = 0;
break;
}
switch (token) {
case T_OP_CMP_TRUE:
if (all_digits(pleft)) {
lint = strtoul(pleft, NULL, 0);
result = (lint != 0);
} else {
result = (*pleft != '\0');
}
break;
case T_OP_CMP_EQ:
result = (strcmp(pleft, pright) == 0);
break;
case T_OP_NE:
result = (strcmp(pleft, pright) != 0);
break;
case T_OP_GE:
result = (lint >= rint);
break;
case T_OP_GT:
result = (lint > rint);
break;
case T_OP_LE:
result = (lint <= rint);
break;
case T_OP_LT:
result = (lint < rint);
break;
#ifdef HAVE_REGEX_H
case T_OP_REG_EQ: {
int i, compare;
regex_t reg;
regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];
compare = regcomp(®, pright, cflags);
if (compare != 0) {
if (debug_flag) {
char errbuf[128];
regerror(compare, ®, errbuf, sizeof(errbuf));
DEBUG("ERROR: Failed compiling regular expression: %s", errbuf);
}
return FALSE;
}
compare = regexec(®, pleft,
REQUEST_MAX_REGEX + 1,
rxmatch, 0);
regfree(®);
if (compare == 0) for (i = 0; i <= REQUEST_MAX_REGEX; i++) {
char *r;
free(request_data_get(request, request,
REQUEST_DATA_REGEX | i));
if (rxmatch[i].rm_so == -1) continue;
r = rad_malloc(rxmatch[i].rm_eo -rxmatch[i].rm_so + 1);
memcpy(r, pleft + rxmatch[i].rm_so,
rxmatch[i].rm_eo - rxmatch[i].rm_so);
r[rxmatch[i].rm_eo - rxmatch[i].rm_so] = '\0';
request_data_add(request, request,
REQUEST_DATA_REGEX | i,
r, free);
}
result = (compare == 0);
}
break;
case T_OP_REG_NE: {
int compare;
regex_t reg;
regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];
compare = regcomp(®, pright, cflags);
if (compare != 0) {
if (debug_flag) {
char errbuf[128];
regerror(compare, ®, errbuf, sizeof(errbuf));
DEBUG("ERROR: Failed compiling regular expression: %s", errbuf);
}
return FALSE;
}
compare = regexec(®, pleft,
REQUEST_MAX_REGEX + 1,
rxmatch, 0);
regfree(®);
result = (compare != 0);
}
break;
#endif
default:
DEBUG("ERROR: Comparison operator %s is not supported",
fr_token_name(token));
result = FALSE;
break;
}
*presult = result;
return TRUE;
}
int radius_evaluate_condition(REQUEST *request, int modreturn, int depth,
const char **ptr, int evaluate_it, int *presult)
{
int found_condition = FALSE;
int result = TRUE;
int invert = FALSE;
int evaluate_next_condition = evaluate_it;
const char *p;
const char *q, *start;
FR_TOKEN token, lt, rt;
char left[1024], right[1024], comp[4];
const char *pleft, *pright;
char xleft[1024], xright[1024];
int cflags = 0;
if (!ptr || !*ptr || (depth >= 64)) {
radlog(L_ERR, "Internal sanity check failed in evaluate condition");
return FALSE;
}
p = *ptr;
while (*p) {
while ((*p == ' ') || (*p == '\t')) p++;
if (!found_condition && (*p == '!')) {
if (evaluate_next_condition) {
RDEBUG4(">>> INVERT");
invert = TRUE;
}
p++;
while ((*p == ' ') || (*p == '\t')) p++;
}
if (!found_condition && (*p == '(')) {
const char *end = p + 1;
RDEBUG4(">>> RECURSING WITH ... %s", end);
if (!radius_evaluate_condition(request, modreturn,
depth + 1, &end,
evaluate_next_condition,
&result)) {
return FALSE;
}
if (invert) {
if (evaluate_next_condition) {
RDEBUG2("%.*s Converting !%s -> %s",
depth, filler,
(result != FALSE) ? "TRUE" : "FALSE",
(result == FALSE) ? "TRUE" : "FALSE");
result = (result == FALSE);
}
invert = FALSE;
}
p = end;
RDEBUG4(">>> AFTER RECURSION ... %s", end);
while ((*p == ' ') || (*p == '\t')) p++;
if (!*p) {
radlog(L_ERR, "No closing brace");
return FALSE;
}
if (*p == ')') p++;
found_condition = TRUE;
while ((*p == ' ') || (*p == '\t')) p++;
}
if (found_condition && (!*p || (*p == ')'))) break;
if (found_condition) {
if ((p[0] == '&') && (p[1] == '&')) {
if (!result) evaluate_next_condition = FALSE;
p += 2;
found_condition = FALSE;
continue;
}
if ((p[0] == '|') && (p[1] == '|')) {
if (result) evaluate_next_condition = FALSE;
p += 2;
found_condition = FALSE;
continue;
}
}
if (found_condition) {
radlog(L_ERR, "Consecutive conditions at %s", p);
return FALSE;
}
RDEBUG4(">>> LOOKING AT %s", p);
start = p;
if ((p[0] == '%') && (p[1] == '{')) {
radlog(L_ERR, "Bare %%{...} is invalid in condition at: %s", p);
return FALSE;
}
lt = gettoken(&p, left, sizeof(left));
if ((lt != T_BARE_WORD) &&
(lt != T_DOUBLE_QUOTED_STRING) &&
(lt != T_SINGLE_QUOTED_STRING) &&
(lt != T_BACK_QUOTED_STRING)) {
radlog(L_ERR, "Expected string or numbers at: %s", p);
return FALSE;
}
pleft = left;
if (evaluate_next_condition) {
pleft = expand_string(xleft, sizeof(xleft), request,
lt, left);
if (!pleft) {
radlog(L_ERR, "Failed expanding string at: %s",
left);
return FALSE;
}
}
q = p;
while ((*q == ' ') || (*q == '\t')) q++;
if (!*q || (*q == ')') ||
((q[0] == '&') && (q[1] == '&')) ||
((q[0] == '|') && (q[1] == '|'))) {
token = T_OP_CMP_TRUE;
rt = T_OP_INVALID;
pright = NULL;
goto do_cmp;
}
token = gettoken(&p, comp, sizeof(comp));
if ((token < T_OP_NE) || (token > T_OP_CMP_EQ) ||
(token == T_OP_CMP_TRUE)) {
radlog(L_ERR, "Expected comparison at: %s", comp);
return FALSE;
}
if ((p[0] == '%') && (p[1] == '{')) {
radlog(L_ERR, "Bare %%{...} is invalid in condition at: %s", p);
return FALSE;
}
#ifdef HAVE_REGEX_H
if ((token == T_OP_REG_EQ) ||
(token == T_OP_REG_NE)) {
rt = getregex(&p, right, sizeof(right), &cflags);
if (rt != T_DOUBLE_QUOTED_STRING) {
radlog(L_ERR, "Expected regular expression at: %s", p);
return FALSE;
}
} else
#endif
rt = gettoken(&p, right, sizeof(right));
if ((rt != T_BARE_WORD) &&
(rt != T_DOUBLE_QUOTED_STRING) &&
(rt != T_SINGLE_QUOTED_STRING) &&
(rt != T_BACK_QUOTED_STRING)) {
radlog(L_ERR, "Expected string or numbers at: %s", p);
return FALSE;
}
pright = right;
if (evaluate_next_condition) {
pright = expand_string(xright, sizeof(xright), request,
rt, right);
if (!pright) {
radlog(L_ERR, "Failed expanding string at: %s",
right);
return FALSE;
}
}
RDEBUG4(">>> %d:%s %d %d:%s",
lt, pleft, token, rt, pright);
do_cmp:
if (evaluate_next_condition) {
if (!radius_do_cmp(request, &result, lt, pleft, token,
rt, pright, cflags, modreturn)) {
return FALSE;
}
RDEBUG4(">>> Comparison returned %d", result);
if (invert) {
RDEBUG4(">>> INVERTING result");
result = (result == FALSE);
}
RDEBUG2("%.*s Evaluating %s(%.*s) -> %s",
depth, filler,
invert ? "!" : "", p - start, start,
(result != FALSE) ? "TRUE" : "FALSE");
invert = FALSE;
RDEBUG4(">>> GOT result %d", result);
} else if (request) {
RDEBUG2("%.*s Skipping %s(%.*s)",
depth, filler,
invert ? "!" : "", p - start, start);
}
found_condition = TRUE;
}
if (!found_condition) {
radlog(L_ERR, "Syntax error. Expected condition at %s", p);
return FALSE;
}
RDEBUG4(">>> AT EOL -> %d", result);
*ptr = p;
if (evaluate_it) *presult = result;
return TRUE;
}
#endif
static void fix_up(REQUEST *request)
{
VALUE_PAIR *vp;
request->username = NULL;
request->password = NULL;
for (vp = request->packet->vps; vp != NULL; vp = vp->next) {
if ((vp->attribute == PW_USER_NAME) &&
!request->username) {
request->username = vp;
} else if (vp->attribute == PW_STRIPPED_USER_NAME) {
request->username = vp;
} else if (vp->attribute == PW_USER_PASSWORD) {
request->password = vp;
}
}
}
void radius_pairmove(REQUEST *request, VALUE_PAIR **to, VALUE_PAIR *from)
{
int i, j, count, from_count, to_count, tailto;
VALUE_PAIR *vp, *next, **last;
VALUE_PAIR **from_list, **to_list;
int *edited = NULL;
count = 0;
for (vp = from; vp != NULL; vp = vp->next) count++;
from_list = rad_malloc(sizeof(*from_list) * count);
for (vp = *to; vp != NULL; vp = vp->next) count++;
to_list = rad_malloc(sizeof(*to_list) * count);
from_count = 0;
for (vp = from; vp != NULL; vp = next) {
next = vp->next;
from_list[from_count++] = vp;
vp->next = NULL;
}
to_count = 0;
for (vp = *to; vp != NULL; vp = next) {
next = vp->next;
to_list[to_count++] = vp;
vp->next = NULL;
}
tailto = to_count;
edited = rad_malloc(sizeof(*edited) * to_count);
memset(edited, 0, sizeof(*edited) * to_count);
RDEBUG4("::: FROM %d TO %d MAX %d", from_count, to_count, count);
for (i = 0; i < from_count; i++) {
int found;
RDEBUG4("::: Examining %s", from_list[i]->name);
if (from_list[i]->operator == T_OP_ADD) goto append;
found = FALSE;
for (j = 0; j < to_count; j++) {
if (edited[j] || !to_list[j] || !from_list[i]) continue;
if (from_list[i]->attribute != to_list[j]->attribute) {
continue;
}
if (from_list[i]->operator == T_OP_SET) {
RDEBUG4("::: OVERWRITING %s FROM %d TO %d",
to_list[j]->name, i, j);
pairfree(&to_list[j]);
to_list[j] = from_list[i];
from_list[i] = NULL;
edited[j] = TRUE;
break;
}
if (from_list[i]->operator == T_OP_EQ) {
found = TRUE;
break;
}
if (from_list[i]->operator == T_OP_CMP_FALSE) {
goto delete;
}
if ((from_list[i]->operator == T_OP_SUB) ||
(from_list[i]->operator == T_OP_CMP_EQ) ||
(from_list[i]->operator == T_OP_LE) ||
(from_list[i]->operator == T_OP_GE)) {
int rcode;
int old_op = from_list[i]->operator;
from_list[i]->operator = T_OP_CMP_EQ;
rcode = radius_compare_vps(NULL, from_list[i],
to_list[j]);
from_list[i]->operator = old_op;
switch (old_op) {
case T_OP_CMP_EQ:
if (rcode != 0) goto delete;
break;
case T_OP_SUB:
if (rcode == 0) {
delete:
RDEBUG4("::: DELETING %s FROM %d TO %d",
from_list[i]->name, i, j);
pairfree(&to_list[j]);
to_list[j] = NULL;
}
break;
case T_OP_LE:
if (rcode > 0) {
RDEBUG4("::: REPLACING %s FROM %d TO %d",
from_list[i]->name, i, j);
pairfree(&to_list[j]);
to_list[j] = from_list[i];
from_list[i] = NULL;
edited[j] = TRUE;
}
break;
case T_OP_GE:
if (rcode < 0) {
RDEBUG4("::: REPLACING %s FROM %d TO %d",
from_list[i]->name, i, j);
pairfree(&to_list[j]);
to_list[j] = from_list[i];
from_list[i] = NULL;
edited[j] = TRUE;
}
break;
}
continue;
}
rad_assert(0 == 1);
}
if (!found && from_list[i]) {
if ((from_list[i]->operator == T_OP_EQ) ||
(from_list[i]->operator == T_OP_LE) ||
(from_list[i]->operator == T_OP_GE) ||
(from_list[i]->operator == T_OP_SET)) {
append:
RDEBUG4("::: APPENDING %s FROM %d TO %d",
from_list[i]->name, i, tailto);
to_list[tailto++] = from_list[i];
from_list[i] = NULL;
}
}
}
for (i = 0; i < from_count; i++) {
if (!from_list[i]) continue;
pairfree(&from_list[i]);
}
free(from_list);
RDEBUG4("::: TO in %d out %d", to_count, tailto);
*to = NULL;
last = to;
for (i = 0; i < tailto; i++) {
if (!to_list[i]) continue;
RDEBUG4("::: to[%d] = %s", i, to_list[i]->name);
to_list[i]->operator = T_OP_EQ;
*last = to_list[i];
last = &(*last)->next;
}
rad_assert(request != NULL);
rad_assert(request->packet != NULL);
if (to == &request->packet->vps) {
fix_up(request);
} else if (request->parent && (to == &request->parent->packet->vps)) {
fix_up(request->parent);
}
free(to_list);
free(edited);
}
#ifdef WITH_UNLANG
typedef enum conf_type {
CONF_ITEM_INVALID = 0,
CONF_ITEM_PAIR,
CONF_ITEM_SECTION,
CONF_ITEM_DATA
} CONF_ITEM_TYPE;
struct conf_item {
struct conf_item *next;
struct conf_part *parent;
int lineno;
const char *filename;
CONF_ITEM_TYPE type;
};
struct conf_pair {
CONF_ITEM item;
char *attr;
char *value;
FR_TOKEN operator;
FR_TOKEN value_type;
};
int radius_update_attrlist(REQUEST *request, CONF_SECTION *cs,
VALUE_PAIR *input_vps, const char *name)
{
CONF_ITEM *ci;
VALUE_PAIR *newlist, *vp;
VALUE_PAIR **output_vps = NULL;
REQUEST *myrequest = request;
if (!request || !cs) return RLM_MODULE_INVALID;
if (strncmp(name, "outer.", 6) == 0) {
if (!request->parent) return RLM_MODULE_NOOP;
myrequest = request->parent;
name += 6;
}
if (strcmp(name, "request") == 0) {
output_vps = &myrequest->packet->vps;
} else if (strcmp(name, "reply") == 0) {
output_vps = &myrequest->reply->vps;
#ifdef WITH_PROXY
} else if (strcmp(name, "proxy-request") == 0) {
if (request->proxy) output_vps = &myrequest->proxy->vps;
} else if (strcmp(name, "proxy-reply") == 0) {
if (request->proxy_reply) output_vps = &request->proxy_reply->vps;
#endif
} else if (strcmp(name, "config") == 0) {
output_vps = &myrequest->config_items;
} else if (strcmp(name, "control") == 0) {
output_vps = &myrequest->config_items;
#ifdef WITH_COA
} else if (strcmp(name, "coa") == 0) {
if (!myrequest->coa) {
request_alloc_coa(myrequest);
myrequest->coa->proxy->code = PW_COA_REQUEST;
}
if (myrequest->coa &&
(myrequest->coa->proxy->code == PW_COA_REQUEST)) {
output_vps = &myrequest->coa->proxy->vps;
}
} else if (strcmp(name, "coa-reply") == 0) {
if (myrequest->coa &&
(myrequest->coa->proxy->code == PW_COA_REQUEST) &&
(myrequest->coa->proxy_reply)) {
output_vps = &myrequest->coa->proxy_reply->vps;
}
} else if (strcmp(name, "disconnect") == 0) {
if (!myrequest->coa) {
request_alloc_coa(myrequest);
if (myrequest->coa) myrequest->coa->proxy->code = PW_DISCONNECT_REQUEST;
}
if (myrequest->coa &&
(myrequest->coa->proxy->code == PW_DISCONNECT_REQUEST)) {
output_vps = &myrequest->coa->proxy->vps;
}
} else if (strcmp(name, "disconnect-reply") == 0) {
if (myrequest->coa &&
(myrequest->coa->proxy->code == PW_DISCONNECT_REQUEST) &&
(myrequest->coa->proxy_reply)) {
output_vps = &myrequest->coa->proxy_reply->vps;
}
#endif
} else {
return RLM_MODULE_INVALID;
}
if (!output_vps) return RLM_MODULE_NOOP;
newlist = paircopy(input_vps);
if (!newlist) {
RDEBUG2("Out of memory");
return RLM_MODULE_FAIL;
}
vp = newlist;
for (ci=cf_item_find_next(cs, NULL);
ci != NULL;
ci=cf_item_find_next(cs, ci)) {
CONF_PAIR *cp;
if (cf_item_is_section(ci)) {
pairfree(&newlist);
return RLM_MODULE_INVALID;
}
cp = cf_itemtopair(ci);
#ifndef NDEBUG
if (debug_flag && radius_find_compare(vp->attribute)) {
DEBUG("WARNING: You are modifying the value of virtual attribute %s. This is not supported.", vp->name);
}
#endif
if (vp->flags.do_xlat) {
const char *value;
char buffer[2048];
value = expand_string(buffer, sizeof(buffer), request,
cp->value_type, cp->value);
if (!value) {
pairfree(&newlist);
return RLM_MODULE_INVALID;
}
if (!pairparsevalue(vp, value)) {
RDEBUG2("ERROR: Failed parsing value \"%s\" for attribute %s: %s",
value, vp->name, fr_strerror());
pairfree(&newlist);
return RLM_MODULE_FAIL;
}
vp->flags.do_xlat = 0;
}
vp = vp->next;
}
radius_pairmove(request, output_vps, newlist);
return RLM_MODULE_UPDATED;
}
#endif