24 RCSID(
"$Id: 5720955d826a3683aaf722c79b492c120bf71ba6 $")
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/modules.h>
28 #include <freeradius-devel/parser.h>
29 #include <freeradius-devel/rad_assert.h>
34 #ifdef WITH_EVAL_DEBUG
35 # define EVAL_DEBUG(fmt, ...) printf("EVAL: ");printf(fmt, ## __VA_ARGS__);printf("\n");fflush(stdout)
37 # define EVAL_DEBUG(...)
56 char const *p = string;
60 if (*p ==
'\0')
return false;
64 while (isdigit((
int) *p)) p++;
92 rcode = (modcode == modreturn);
105 rcode = (vpt->
name !=
'\0');
123 if (!*vpt->
name)
return false;
124 rcode =
tmpl_aexpand(request, &p, request, vpt, NULL, NULL);
130 rcode = (data.strvalue && (*data.strvalue !=
'\0'));
131 talloc_free(data.ptr);
169 regex_t *preg, *rreg = NULL;
170 regmatch_t rxmatch[REQUEST_MAX_REGEX + 1];
171 size_t nmatch =
sizeof(rxmatch) /
sizeof(regmatch_t);
177 map->
rhs->tmpl_iflag ?
"CASE INSENSITIVE" :
"CASE SENSITIVE",
178 map->
rhs->tmpl_mflag ?
"MULTILINE" :
"SINGLELINE");
182 preg = map->
rhs->tmpl_preg;
188 slen = regex_compile(request, &rreg, rhs->strvalue, rhs->
length,
189 map->
rhs->tmpl_iflag, map->
rhs->tmpl_mflag,
true,
true);
200 ret = regex_exec(preg, lhs->strvalue, lhs->
length, rxmatch, &nmatch);
204 regex_sub_to_request(request, NULL, NULL, 0, NULL, 0);
209 regex_sub_to_request(request, &preg, lhs->strvalue, lhs->
length, rxmatch, nmatch);
221 if (preg) talloc_free(rreg);
227 #ifdef WITH_EVAL_DEBUG
228 static void cond_print_operands(
REQUEST *request,
238 lhs_hex = talloc_array(request,
char, (lhs->
length * 2) + 1);
248 talloc_free(lhs_hex);
260 rhs_hex = talloc_array(request,
char, (rhs->
length * 2) + 1);
270 talloc_free(rhs_hex);
295 #ifdef WITH_EVAL_DEBUG
297 cond_print_operands(request, lhs_type, lhs, rhs_type, rhs);
305 rcode = cond_do_regex(request, c, lhs_type, lhs, rhs_type, rhs);
324 rcode = (rcode == 0) ? 1 : 0;
383 void *lhs_cast_buff = NULL, *rhs_cast_buff = NULL;
395 if ((cast_type != PW_TYPE_INVALID) && (_s ## _type != PW_TYPE_INVALID) && (cast_type != _s ## _type)) {\
396 EVAL_DEBUG("CASTING " #_s " FROM %s TO %s",\
397 fr_int2str(dict_attr_types, _s ## _type, "<INVALID>"),\
398 fr_int2str(dict_attr_types, cast_type, "<INVALID>"));\
399 if (value_data_cast(request, &_s ## _cast, cast_type, cast, _s ## _type, _s ## _enumv, _s) < 0) {\
400 REDEBUG("Failed casting " #_s " operand: %s", fr_strerror());\
404 if (cast && cast->flags.is_pointer) _s ## _cast_buff = _s ## _cast.ptr;\
405 _s ## _type = cast_type;\
410 #define CHECK_INT_CAST(_l, _r) \
412 if ((cast_type == PW_TYPE_INVALID) &&\
413 _l && (_l ## _type == PW_TYPE_STRING) &&\
414 _r && (_r ## _type == PW_TYPE_STRING) &&\
415 all_digits(lhs->strvalue) && all_digits(rhs->strvalue)) {\
416 cast_type = PW_TYPE_INTEGER64;\
417 EVAL_DEBUG("OPERANDS ARE NUMBER STRINGS, SETTING CAST TO integer64");\
441 cast = map->
lhs->tmpl_da;
442 cast_type = cast->
type;
444 EVAL_DEBUG(
"NORMALISATION TYPE %s (PAIRCMP TYPE)",
452 }
else if (c->
cast) {
454 EVAL_DEBUG(
"NORMALISATION TYPE %s (EXPLICIT CAST)",
457 cast = map->
lhs->tmpl_da;
458 EVAL_DEBUG(
"NORMALISATION TYPE %s (IMPLICIT FROM LHS REF)",
461 cast = map->
rhs->tmpl_da;
462 EVAL_DEBUG(
"NORMALISATION TYPE %s (IMPLICIT FROM RHS REF)",
465 cast_type = map->
lhs->tmpl_data_type;
466 EVAL_DEBUG(
"NORMALISATION TYPE %s (IMPLICIT FROM LHS DATA)",
469 cast_type = map->
rhs->tmpl_data_type;
470 EVAL_DEBUG(
"NORMALISATION TYPE %s (IMPLICIT FROM RHS DATA)",
474 if (cast) cast_type = cast->
type;
494 if (rcode != 0)
break;
496 TALLOC_FREE(rhs_cast_buff);
502 rhs_type = map->
rhs->tmpl_data_type;
503 rhs = &map->
rhs->tmpl_data_value;
537 data.strvalue = map->
rhs->
name;
576 talloc_free(lhs_cast_buff);
577 talloc_free(rhs_cast_buff);
632 if (rcode != 0)
break;
639 map->
lhs->tmpl_data_type, NULL, &map->
lhs->tmpl_data_value);
659 data.
length = (size_t)ret;
661 data.strvalue = map->
lhs->
name;
704 #ifdef WITH_EVAL_DEBUG
716 if (rcode < 0) rcode = 0;
739 if (rcode < 0)
return rcode;
741 if (c->
negate) rcode = !rcode;
776 int i, j, count, from_count, to_count, tailto;
809 from_list = talloc_array(request,
VALUE_PAIR *, count);
812 to_list = talloc_array(request,
VALUE_PAIR *, count);
815 append_tail = &append;
822 for (vp = from; vp != NULL; vp = next) {
824 from_list[from_count++] = vp;
829 ctx = talloc_parent(*to);
831 for (vp = to_copy; vp != NULL; vp = next) {
833 to_list[to_count++] = vp;
837 edited = talloc_zero_array(request,
bool, to_count);
839 RDEBUG4(
"::: FROM %d TO %d MAX %d", from_count, to_count, count);
845 for (i = 0; i < from_count; i++) {
848 RDEBUG4(
"::: Examining %s", from_list[i]->da->name);
857 if (from_list[i]->op ==
T_OP_ADD)
goto do_append;
860 for (j = 0; j < to_count; j++) {
861 if (edited[j] || !to_list[j] || !from_list[i])
continue;
866 if (from_list[i]->da != to_list[j]->da) {
883 RDEBUG4(
"::: OVERWRITING %s FROM %d TO %d",
884 to_list[j]->da->name, i, j);
886 to_list[j] = from_list[i];
897 if (from_list[i]->op ==
T_OP_EQ) {
914 if ((from_list[i]->op ==
T_OP_SUB) ||
916 (from_list[i]->op ==
T_OP_LE) ||
917 (from_list[i]->op ==
T_OP_GE)) {
919 int old_op = from_list[i]->
op;
938 from_list[i]->
op = old_op;
942 if (rcode != 0)
goto delete;
948 RDEBUG4(
"::: DELETING %s FROM %d TO %d",
949 from_list[i]->da->name, i, j);
961 RDEBUG4(
"::: REPLACING %s FROM %d TO %d",
962 from_list[i]->da->name, i, j);
964 to_list[j] = from_list[i];
972 RDEBUG4(
"::: REPLACING %s FROM %d TO %d",
973 from_list[i]->da->name, i, j);
975 to_list[j] = from_list[i];
994 if (!found && from_list[i]) {
995 if ((from_list[i]->op ==
T_OP_EQ) ||
996 (from_list[i]->op ==
T_OP_LE) ||
997 (from_list[i]->op ==
T_OP_GE) ||
1000 RDEBUG4(
"::: APPENDING %s FROM %d TO %d",
1001 from_list[i]->da->name, i, tailto);
1002 *append_tail = from_list[i];
1004 from_list[i] = NULL;
1005 append_tail = &(*append_tail)->
next;
1013 for (i = 0; i < from_count; i++) {
1014 if (!from_list[i])
continue;
1018 talloc_free(from_list);
1020 RDEBUG4(
"::: TO in %d out %d", to_count, tailto);
1034 for (i = 0; i < tailto; i++) {
1035 if (!to_list[i])
continue;
1050 last = &(*last)->
next;
1072 }
else if (vp->
da->
attr == PW_STRIPPED_USER_NAME) {
1075 }
else if (vp->
da->
attr == PW_USER_PASSWORD) {
1083 talloc_free(to_list);
1084 talloc_free(edited);
void fr_pair_list_free(VALUE_PAIR **)
Free memory used by a valuepair list.
int radius_evaluate_tmpl(REQUEST *request, int modreturn, UNUSED int depth, vp_tmpl_t const *vpt)
Evaluate a template.
FR_NAME_NUMBER const modreturn_table[]
The module is OK, continue.
char const * name
Raw string used to create the template.
vp_tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
int paircompare(REQUEST *request, VALUE_PAIR *req_list, VALUE_PAIR *check, VALUE_PAIR **rep_list)
Compare two pair lists except for the password information.
vp_tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
Pre-parsed XLAT expansion.
VALUE_PAIR * username
Cached username VALUE_PAIR from request RADIUS_PACKET.
#define REMARKER(_m, _i, _e)
Output string with error marker, showing where format error occurred.
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Error resolving rcode (should not be returned by modules).
VALUE_PAIR * fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR *const *node)
Setup a cursor to iterate over attribute pairs.
void radius_pairmove(REQUEST *request, VALUE_PAIR **to, VALUE_PAIR *from, bool do_xlat)
fr_dict_attr_t const * cast
VALUE_PAIR * password
Cached password VALUE_PAIR from request RADIUS_PACKET.
The module considers the request invalid.
int radius_find_compare(fr_dict_attr_t const *attribute)
Find a comparison function for two attributes.
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
Attribute not found in the global dictionary.
static int cond_cmp_values(REQUEST *request, fr_cond_t const *c, PW_TYPE lhs_type, value_data_t const *lhs, PW_TYPE rhs_type, value_data_t const *rhs)
Call the correct data comparison function for the condition.
Reject the request (user is locked out).
Pre-parsed regular expression.
int fr_str2int(FR_NAME_NUMBER const *table, char const *name, int def)
VALUE_PAIR * tmpl_cursor_init(int *err, vp_cursor_t *cursor, REQUEST *request, vp_tmpl_t const *vpt)
Initialise a vp_cursor_t to the VALUE_PAIR specified by a vp_tmpl_t.
VALUE_PAIR * fr_pair_list_copy(TALLOC_CTX *ctx, VALUE_PAIR *from)
Copy a pairlist.
int tmpl_find_vp(VALUE_PAIR **out, REQUEST *request, vp_tmpl_t const *vpt)
Returns the first VP matching a vp_tmpl_t.
int radius_evaluate_map(REQUEST *request, UNUSED int modreturn, UNUSED int depth, fr_cond_t const *c)
Evaluate a map.
int radius_evaluate_cond(REQUEST *request, int modreturn, int depth, fr_cond_t const *c)
Evaluate a fr_cond_t;.
const FR_NAME_NUMBER dict_attr_types[]
Map data types to names representing those types.
unsigned int attr
Attribute number.
Immediately reject the request.
unsigned int vendor
Vendor that defines this attribute.
Stores an attribute, a value and various bits of other data.
ssize_t tmpl_aexpand(TALLOC_CTX *ctx, char **out, REQUEST *request, vp_tmpl_t const *vpt, xlat_escape_t escape, void *escape_ctx)
Expand a template to a string, allocing a new buffer to hold the string.
Invalid (uninitialised) attribute type.
FR_TOKEN op
Operator to use when moving or inserting valuepair into a list.
int radius_xlat_do(REQUEST *request, VALUE_PAIR *vp)
Expands an attribute marked with fr_pair_mark_xlat.
tmpl_type_t type
What type of value tmpl refers to.
char const * fr_strerror(void)
Get the last library error.
size_t len
Length of the raw string used to create the template.
int value_data_copy(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE type, const value_data_t *src)
Copy value data verbatim duplicating any buffers.
Module succeeded without doing anything.
Callout to an external script or program.
char name[1]
Attribute name.
size_t length
Length of value data.
Module failed, don't reply.
FR_TOKEN op
The operator that controls insertion of the dst attribute.
size_t fr_cond_snprint(char *buffer, size_t bufsize, fr_cond_t const *c)
VALUE_PAIR * fr_cursor_next(vp_cursor_t *cursor)
Advanced the cursor to the next VALUE_PAIR.
static int cond_normalise_and_cmp(REQUEST *request, fr_cond_t const *c, PW_TYPE lhs_type, fr_dict_attr_t const *lhs_enumv, value_data_t const *lhs)
Convert both operands to the same type.
static bool all_digits(char const *string)
fr_cond_pass2_t pass2_fixup
RADIUS_PACKET * packet
Incoming request.
VALUE_PAIR * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute.
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)
int value_data_cmp_op(FR_TOKEN op, PW_TYPE a_type, value_data_t const *a, PW_TYPE b_type, value_data_t const *b)
Compare two attributes using an operator.
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
String of printable characters.
VALUE_PAIR * tmpl_cursor_next(vp_cursor_t *cursor, vp_tmpl_t const *vpt)
Returns the next VALUE_PAIR specified by vpt.
The module handled the request, so stop.
int radius_compare_vps(REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *vp)
#define CHECK_INT_CAST(_l, _r)
A source or sink of value data.
size_t fr_bin2hex(char *hex, uint8_t const *bin, size_t inlen)
Convert binary data to a hex string.
const FR_NAME_NUMBER tmpl_names[]
Map tmpl_type_t values to descriptive strings.
PW_TYPE
Internal data types used within libfreeradius.