* This file shouldn't use any functions from the server core.
*/
-size_t fr_cond_sprint(char *buffer, size_t bufsize, fr_cond_t const *c)
+size_t fr_cond_sprint(char *buffer, size_t bufsize, fr_cond_t const *in)
{
size_t len;
char *p = buffer;
char *end = buffer + bufsize - 1;
+ fr_cond_t const *c = in;
next:
if (c->negate) {
#ifdef WITH_ASCEND_BINARY
case PW_TYPE_ABINARY:
#endif
- case PW_TYPE_COMBO_IP:
+ case PW_TYPE_IP_ADDR:
case PW_TYPE_TLV:
case PW_TYPE_EXTENDED:
case PW_TYPE_LONG_EXTENDED:
* @param[out] error the parse error (if any)
* @return length of the string skipped, or when negative, the offset to the offending error
*/
-static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, int brace, fr_cond_t **pcond, char const **error, int flags)
+static ssize_t condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, int brace,
+ fr_cond_t **pcond, char const **error, int flags)
{
ssize_t slen;
char const *p = start;
rad_assert(c->data.vpt->type != VPT_TYPE_REGEX);
} else { /* it's an operator */
- int regex;
+ bool regex;
+ bool i_flag = false;
/*
* The next thing should now be a comparison operator.
* Allow /foo/i
*/
if (p[slen] == 'i') {
- c->regex_i = true;
+ i_flag = true;
slen++;
}
REQUEST_CURRENT, PAIR_LIST_REQUEST,
REQUEST_CURRENT, PAIR_LIST_REQUEST);
if (!c->data.map) {
- if (*lhs == '&') {
- /*
- * FIXME: In the future,
- * have str2map above
- * know whether this is
- * pass1 or pass2. If
- * it's pass2, then an
- * unknown attribute is a
- * soft fail.
- */
+ /*
+ * FIXME: if strings are T_BARE_WORD and they start with '&',
+ * then they refer to attributes which have not yet been
+ * defined. Create the template(s) as literals, and
+ * fix them up in pass2.
+ */
+ if ((*lhs != '&') ||
+ (lhs_type != T_BARE_WORD)) {
+ return_0("Syntax error");
+ }
+ c->data.map = radius_str2map(c, lhs, lhs_type + 1, op, rhs, rhs_type,
+ REQUEST_CURRENT, PAIR_LIST_REQUEST,
+ REQUEST_CURRENT, PAIR_LIST_REQUEST);
+ if (!c->data.map) {
return_0("Unknown attribute");
}
- return_0("Syntax error");
+ rad_const_free(c->data.map->dst->name);
+ c->data.map->dst->name = talloc_strdup(c->data.map->dst, lhs);
+ c->pass2_fixup = PASS2_FIXUP_ATTR;
+ }
+
+ if (c->data.map->src->type == VPT_TYPE_REGEX) {
+ c->data.map->src->vpt_iflag = i_flag;
}
/*
*/
if (c->cast) {
if ((c->data.map->src->type == VPT_TYPE_ATTR) &&
- (c->cast->type != c->data.map->src->da->type)) {
+ (c->cast->type != c->data.map->src->vpt_da->type)) {
goto same_type;
}
*/
if ((c->data.map->dst->type == VPT_TYPE_DATA) &&
(c->data.map->src->type == VPT_TYPE_LITERAL) &&
- !radius_cast_tmpl(c->data.map->src, c->data.map->dst->da)) {
+ !radius_cast_tmpl(c->data.map->src, c->data.map->dst->vpt_da)) {
return_rhs("Failed to parse field");
}
/*
+ * We may be casting incompatible
+ * types. We check this based on
+ * their size.
+ */
+ if (c->data.map->dst->type == VPT_TYPE_ATTR) {
+ /*
+ * dst.min == src.min
+ * dst.max == src.max
+ */
+ if ((dict_attr_sizes[c->cast->type][0] == dict_attr_sizes[c->data.map->dst->vpt_da->type][0]) &&
+ (dict_attr_sizes[c->cast->type][1] == dict_attr_sizes[c->data.map->dst->vpt_da->type][1])) {
+ goto cast_ok;
+ }
+
+ /*
+ * Run-time parsing of strings.
+ * Run-time copying of octets.
+ */
+ if ((c->data.map->dst->vpt_da->type == PW_TYPE_STRING) ||
+ (c->data.map->dst->vpt_da->type == PW_TYPE_OCTETS)) {
+ goto cast_ok;
+ }
+
+ /*
+ * ipaddr to ipv4prefix is OK
+ */
+ if ((c->data.map->dst->vpt_da->type == PW_TYPE_IPV4_ADDR) &&
+ (c->cast->type == PW_TYPE_IPV4_PREFIX)) {
+ goto cast_ok;
+ }
+
+ /*
+ * ipv6addr to ipv6prefix is OK
+ */
+ if ((c->data.map->dst->vpt_da->type == PW_TYPE_IPV6_ADDR) &&
+ (c->cast->type == PW_TYPE_IPV6_PREFIX)) {
+ goto cast_ok;
+ }
+
+ /*
+ * integer64 to ethernet is OK.
+ */
+ if ((c->data.map->dst->vpt_da->type == PW_TYPE_INTEGER64) &&
+ (c->cast->type == PW_TYPE_ETHERNET)) {
+ goto cast_ok;
+ }
+
+ /*
+ * dst.max < src.min
+ * dst.min > src.max
+ */
+ if ((dict_attr_sizes[c->cast->type][1] < dict_attr_sizes[c->data.map->dst->vpt_da->type][0]) ||
+ (dict_attr_sizes[c->cast->type][0] > dict_attr_sizes[c->data.map->dst->vpt_da->type][1])) {
+ return_0("Cannot cast to attribute of incompatible size");
+ }
+ }
+
+ cast_ok:
+ /*
* Casting to a redundant type means we don't need the cast.
*
* Do this LAST, as the rest of the code above assumes c->cast
* is not NULL.
*/
if ((c->data.map->dst->type == VPT_TYPE_ATTR) &&
- (c->cast->type == c->data.map->dst->da->type)) {
+ (c->cast->type == c->data.map->dst->vpt_da->type)) {
c->cast = NULL;
}
*/
if ((c->data.map->src->type == VPT_TYPE_ATTR) &&
(c->data.map->dst->type == VPT_TYPE_ATTR) &&
- (c->data.map->dst->da->type != c->data.map->src->da->type)) {
+ (c->data.map->dst->vpt_da->type != c->data.map->src->vpt_da->type)) {
same_type:
return_0("Attribute comparisons must be of the same data type");
}
*/
if ((c->data.map->dst->type == VPT_TYPE_ATTR) &&
(c->data.map->src->type != VPT_TYPE_ATTR) &&
- (c->data.map->dst->da->type == PW_TYPE_STRING) &&
+ (c->data.map->dst->vpt_da->type == PW_TYPE_STRING) &&
(c->data.map->op != T_OP_CMP_TRUE) &&
(c->data.map->op != T_OP_CMP_FALSE) &&
(rhs_type == T_BARE_WORD)) {
*/
if ((c->data.map->dst->type == VPT_TYPE_ATTR) &&
(c->data.map->src->type != VPT_TYPE_ATTR) &&
- (c->data.map->dst->da->type != PW_TYPE_STRING) &&
- (c->data.map->dst->da->type != PW_TYPE_OCTETS) &&
- (c->data.map->dst->da->type != PW_TYPE_DATE) &&
+ (c->data.map->dst->vpt_da->type != PW_TYPE_STRING) &&
+ (c->data.map->dst->vpt_da->type != PW_TYPE_OCTETS) &&
+ (c->data.map->dst->vpt_da->type != PW_TYPE_DATE) &&
(rhs_type == T_SINGLE_QUOTED_STRING)) {
*error = "Value must be an unquoted string";
return_rhs:
*/
if ((c->data.map->dst->type == VPT_TYPE_ATTR) &&
(c->data.map->src->type == VPT_TYPE_LITERAL) &&
- !radius_cast_tmpl(c->data.map->src, c->data.map->dst->da)) {
- DICT_ATTR const *da = c->data.map->dst->da;
+ !radius_cast_tmpl(c->data.map->src, c->data.map->dst->vpt_da)) {
+ DICT_ATTR const *da = c->data.map->dst->vpt_da;
if ((da->vendor == 0) &&
((da->attr == PW_AUTH_TYPE) ||
rcode = radius_evaluate_map(NULL, 0, 0, c);
TALLOC_FREE(c->data.map);
c->cast = NULL;
- c->regex_i = false;
if (rcode) {
c->type = COND_TYPE_TRUE;
} else {
* doesn't need to be done at run time
*/
if ((c->data.map->src->type == VPT_TYPE_LITERAL) &&
- (c->data.map->dst->type == VPT_TYPE_LITERAL)) {
+ (c->data.map->dst->type == VPT_TYPE_LITERAL) &&
+ !c->pass2_fixup) {
int rcode;
rad_assert(c->cast == NULL);
- rad_assert(c->regex_i == false);
rcode = radius_evaluate_map(NULL, 0, 0, c);
if (rcode) {
c->type = COND_TYPE_TRUE;
} else {
+ DEBUG("OPTIMIZING %s %s --> FALSE",
+ c->data.map->dst->name,
+ c->data.map->src->name);
c->type = COND_TYPE_FALSE;
}
TALLOC_FREE(c->data.map);
break;
}
+
+ /*
+ * <ipaddr>"foo" CMP &Attribute-Name The cast is
+ * unnecessary, and we can re-write it so that
+ * the attribute reference is on the LHS.
+ */
+ if (c->cast &&
+ (c->data.map->src->type == VPT_TYPE_ATTR) &&
+ (c->data.map->dst->type != VPT_TYPE_ATTR)) {
+ value_pair_tmpl_t *tmp;
+
+ tmp = c->data.map->src;
+ c->data.map->src = c->data.map->dst;
+ c->data.map->dst = tmp;
+
+ c->cast = NULL;
+
+ switch (c->data.map->op) {
+ case T_OP_CMP_EQ:
+ /* do nothing */
+ break;
+
+ case T_OP_LE:
+ c->data.map->op = T_OP_GE;
+ break;
+
+ case T_OP_LT:
+ c->data.map->op = T_OP_GT;
+ break;
+
+ case T_OP_GE:
+ c->data.map->op = T_OP_LE;
+ break;
+
+ case T_OP_GT:
+ c->data.map->op = T_OP_LT;
+ break;
+
+ default:
+ return_0("Internal sanity check failed");
+ }
+
+ /*
+ * This must have been parsed into VPT_TYPE_DATA.
+ */
+ rad_assert(c->data.map->src->type != VPT_TYPE_LITERAL);
+ }
+
} while (0);
/*