ssize_t value_data_from_str(TALLOC_CTX *ctx, value_data_t *dst,
PW_TYPE *src_type, DICT_ATTR const *src_enumv,
- char const *src, ssize_t src_len);
+ char const *src, ssize_t src_len, char quote);
ssize_t value_data_cast(TALLOC_CTX *ctx, value_data_t *dst,
PW_TYPE dst_type, DICT_ATTR const *dst_enumv,
/* evaluate.c */
typedef struct fr_cond_t fr_cond_t;
-ssize_t radius_expand_tmpl(char **out, REQUEST *request, value_pair_tmpl_t const *vpt);
+ssize_t radius_expand_tmpl(value_data_t *vd, REQUEST *request, value_pair_tmpl_t const *vpt);
int radius_evaluate_tmpl(REQUEST *request, int modreturn, int depth,
value_pair_tmpl_t const *vpt);
int radius_evaluate_map(REQUEST *request, int modreturn, int depth,
/*
* Parses any type of string into a template
*/
-ssize_t tmpl_afrom_str(TALLOC_CTX *ctx, value_pair_tmpl_t **out, char const *name,
+ssize_t tmpl_afrom_str(TALLOC_CTX *ctx, value_pair_tmpl_t **out, char const *name, size_t inlen,
FR_TOKEN type, request_refs_t request_def, pair_lists_t list_def);
void tmpl_free(value_pair_tmpl_t **tmpl);
type = vp->da->type;
- ret = value_data_from_str(vp, &vp->data, &type, vp->da, value, inlen);
+ /*
+ * We presume that the input data is from a double quoted
+ * string, and needs escaping
+ */
+ ret = value_data_from_str(vp, &vp->data, &type, vp->da, value, inlen, '"');
if (ret < 0) return -1;
/*
*/
ssize_t value_data_from_str(TALLOC_CTX *ctx, value_data_t *dst,
PW_TYPE *src_type, DICT_ATTR const *src_enumv,
- char const *src, ssize_t src_len)
+ char const *src, ssize_t src_len, char quote)
{
DICT_VALUE *dval;
size_t len;
switch (*src_type) {
case PW_TYPE_STRING:
{
- size_t p_len;
- char const *cp;
char *p;
+ char const *q;
int x;
- /*
- * Do escaping here
- */
dst->strvalue = p = talloc_memdup(ctx, src, len + 1);
p[len] = '\0';
talloc_set_type(p, char);
- cp = src;
- p_len = 0;
- while (*cp) {
- char c = *cp++;
-
- if (c == '\\') switch (*cp) {
- case 'r':
- c = '\r';
- cp++;
- break;
-
- case 'n':
- c = '\n';
- cp++;
- break;
-
- case 't':
- c = '\t';
- cp++;
- break;
-
- case '"':
- c = '"';
- cp++;
- break;
-
- case '\'':
- c = '\'';
- cp++;
- break;
-
- case '\\':
- c = '\\';
- cp++;
- break;
-
- case '`':
- c = '`';
- cp++;
- break;
-
- case '\0':
- c = '\\'; /* no cp++ */
- break;
- default:
- if ((cp[0] >= '0') &&
- (cp[0] <= '9') &&
- (cp[1] >= '0') &&
- (cp[1] <= '9') &&
- (cp[2] >= '0') &&
- (cp[2] <= '9') &&
- (sscanf(cp, "%3o", &x) == 1)) {
- c = x;
- cp += 3;
+ /*
+ * No de-quoting. Just copy the string.
+ */
+ if (!quote) {
+ ret = len;
+ goto finish;
+ }
+
+ /*
+ * Do escaping for single quoted strings. Only
+ * single quotes get escaped. Everything else is
+ * left as-is.
+ */
+ if (quote == '\'') {
+ q = p;
+
+ /*
+ * Escape ONLY the quotation character.
+ * Everything else is left as-is.
+ */
+ while (q < (dst->strvalue + len)) {
+ if ((q[0] == '\\') &&
+ (q[1] == '\'')) {
+ *(p++) = '\'';
+ q += 2;
+ continue;
}
/*
- * Else It's not a recognised escape sequence DON'T
- * consume the backslash. This is identical
- * behaviour to bash and most other things that
- * use backslash escaping.
+ * Not escaped, just copy it over.
*/
+ *(p++) = *(q++);
+ }
+
+ *p = '\0';
+ ret = p - dst->strvalue;
+ dst->ptr = talloc_realloc(ctx, dst->ptr, char, ret + 1);
+ goto finish;
+ }
+
+ /*
+ * It's "string" or `string`, do all standard
+ * escaping.
+ */
+ q = p;
+ while (q < (dst->strvalue + len)) {
+ char c = *q++;
+
+ if ((c == '\\') && (q >= (dst->strvalue + len))) {
+ fr_strerror_printf("Invalid escape at end of string");
+ return -1;
}
+
+ /*
+ * Fix up \X -> ... the binary form of it.
+ */
+ if (c == '\\') {
+ switch (*q) {
+ case 'r':
+ c = '\r';
+ q++;
+ break;
+
+ case 'n':
+ c = '\n';
+ q++;
+ break;
+
+ case 't':
+ c = '\t';
+ q++;
+ break;
+
+ case '\\':
+ c = '\\';
+ q++;
+ break;
+
+ default:
+ /*
+ * \" --> ", but only inside of double quoted strings, etc.
+ */
+ if (*q == quote) {
+ c = quote;
+ q++;
+ break;
+ }
+
+ /*
+ * \000 --> binary zero character
+ */
+ if ((q[0] >= '0') &&
+ (q[0] <= '9') &&
+ (q[1] >= '0') &&
+ (q[1] <= '9') &&
+ (q[2] >= '0') &&
+ (q[2] <= '9') &&
+ (sscanf(q, "%3o", &x) == 1)) {
+ c = x;
+ q += 3;
+ }
+
+ /*
+ * Else It's not a recognised escape sequence DON'T
+ * consume the backslash. This is identical
+ * behaviour to bash and most other things that
+ * use backslash escaping.
+ */
+ }
+ }
+
*p++ = c;
- p_len++;
}
+
*p = '\0';
- ret = p_len;
+ ret = p - dst->strvalue;
+ dst->ptr = talloc_realloc(ctx, dst->ptr, char, ret + 1);
}
goto finish;
* Deserialise a value_data_t
*/
if (src_type == PW_TYPE_STRING) {
- return value_data_from_str(ctx, dst, &dst_type, dst_enumv, src->strvalue, src_len);
+ return value_data_from_str(ctx, dst, &dst_type, dst_enumv, src->strvalue, src_len, '\0');
}
/*
*
* @note Length of expanded string can be found with talloc_array_length(*out) - 1
*
- * @param out where to write a pointer to the newly allocated buffer.
+ * @param vd the output string
* @param request Current request.
* @param vpt to evaluate.
* @return -1 on error, else 0.
*/
-ssize_t radius_expand_tmpl(char **out, REQUEST *request, value_pair_tmpl_t const *vpt)
+ssize_t radius_expand_tmpl(value_data_t *vd, REQUEST *request, value_pair_tmpl_t const *vpt)
{
VALUE_PAIR *vp;
ssize_t slen;
- *out = NULL;
+ char *out = NULL;
rad_assert(vpt->type != TMPL_TYPE_LIST);
switch (vpt->type) {
case TMPL_TYPE_LITERAL:
EVAL_DEBUG("EXPAND TMPL LITERAL");
- *out = talloc_typed_strdup(request, vpt->name);
- slen = talloc_array_length(*out) - 1;
- break;
+ vd->strvalue = talloc_memdup(request, vpt->name, vpt->len);
+ return vpt->len;
case TMPL_TYPE_EXEC:
EVAL_DEBUG("EXPAND TMPL EXEC");
- *out = talloc_array(request, char, 1024);
- if (radius_exec_program(*out, 1024, NULL, request, vpt->name, NULL, true, false, EXEC_TIMEOUT) != 0) {
- TALLOC_FREE(*out);
+ out = talloc_array(request, char, 1024);
+ if (radius_exec_program(out, 1024, NULL, request, vpt->name, NULL, true, false, EXEC_TIMEOUT) != 0) {
+ TALLOC_FREE(out);
return -1;
}
- slen = strlen(*out);
+ slen = strlen(out);
break;
case TMPL_TYPE_XLAT:
EVAL_DEBUG("EXPAND TMPL XLAT");
/* Error in expansion, this is distinct from zero length expansion */
- slen = radius_axlat(out, request, vpt->name, NULL, NULL);
+ slen = radius_axlat(&out, request, vpt->name, NULL, NULL);
if (slen < 0) {
- rad_assert(!*out);
+ rad_assert(!out);
return slen;
}
- slen = strlen(*out);
+ slen = strlen(out);
break;
case TMPL_TYPE_XLAT_STRUCT:
EVAL_DEBUG("EXPAND TMPL XLAT STRUCT");
/* Error in expansion, this is distinct from zero length expansion */
- slen = radius_axlat_struct(out, request, vpt->tmpl_xlat, NULL, NULL);
+ slen = radius_axlat_struct(&out, request, vpt->tmpl_xlat, NULL, NULL);
if (slen < 0) {
- rad_assert(!*out);
+ rad_assert(!out);
return slen;
}
- slen = strlen(*out);
-
- RDEBUG2("EXPAND %s", vpt->name); /* xlat_struct doesn't do this */
- RDEBUG2(" --> %s", *out);
+ slen = strlen(out);
break;
case TMPL_TYPE_ATTR:
ret = tmpl_find_vp(&vp, request, vpt);
if (ret < 0) return -2;
- *out = vp_aprints_value(request, vp, '\0');
- if (!*out) return -1;
- slen = talloc_array_length(*out) - 1;
+ out = vp_aprints_value(request, vp, '"');
+ if (!out) return -1;
+ slen = talloc_array_length(out) - 1;
}
break;
/*
* We should never be expanding these.
*/
+ case TMPL_TYPE_UNKNOWN:
+ case TMPL_TYPE_NULL:
+ case TMPL_TYPE_LIST:
case TMPL_TYPE_DATA:
case TMPL_TYPE_REGEX:
+ case TMPL_TYPE_ATTR_UNDEFINED:
case TMPL_TYPE_REGEX_STRUCT:
rad_assert(0 == 1);
slen = -1;
- /* FALL-THROUGH */
-
- default:
- slen = 0;
break;
}
- EVAL_DEBUG(" --> %s", *out);
+ if (slen < 0) return slen;
+
+ vd->strvalue = out;
+
+ /*
+ * If we're doing correct escapes, we may have to re-parse the string.
+ * If the string is from another expansion, it needs re-parsing.
+ * Or, if it's from a "string" attribute, it needs re-parsing.
+ * Integers, IP addresses, etc. don't need re-parsing.
+ */
+ if (cf_new_escape &&
+ ((vpt->type != TMPL_TYPE_ATTR) ||
+ (vpt->tmpl_da->type == PW_TYPE_STRING))) {
+ PW_TYPE type = PW_TYPE_STRING;
+
+ slen = value_data_from_str(request, vd, &type, NULL, out, slen, '"');
+ out = vd->ptr;
+ }
+
+ if (vpt->type == TMPL_TYPE_XLAT_STRUCT) {
+ RDEBUG2("EXPAND %s", vpt->name); /* xlat_struct doesn't do this */
+ RDEBUG2(" --> %s", out);
+ } else {
+ EVAL_DEBUG(" --> %s", out);
+ }
+
return slen;
}
{
int rcode;
int modcode;
- char *buffer;
+ value_data_t data;
switch (vpt->type) {
case TMPL_TYPE_LITERAL:
case TMPL_TYPE_XLAT:
case TMPL_TYPE_EXEC:
if (!*vpt->name) return false;
- rcode = radius_expand_tmpl(&buffer, request, vpt);
+ rcode = radius_expand_tmpl(&data, request, vpt);
if (rcode < 0) {
EVAL_DEBUG("FAIL %d", __LINE__);
return -1;
}
- rcode = (buffer && (*buffer != '\0'));
- talloc_free(buffer);
+ rcode = (data.strvalue && (*data.strvalue != '\0'));
+ talloc_free(data.ptr);
break;
/*
value_data_t data;
if (map->rhs->type != TMPL_TYPE_LITERAL) {
- ret = radius_expand_tmpl((char **)&data.ptr, request, map->rhs);
+ ret = radius_expand_tmpl(&data, request, map->rhs);
if (ret < 0) {
EVAL_DEBUG("FAIL [%i]", __LINE__);
rcode = -1;
value_data_t data;
if (map->lhs->type != TMPL_TYPE_LITERAL) {
- ret = radius_expand_tmpl((char **)&data.ptr, request, map->lhs);
+ ret = radius_expand_tmpl(&data, request, map->lhs);
if (ret < 0) {
EVAL_DEBUG("FAIL [%i]", __LINE__);
return ret;
/* do nothing */
} else {
- slen = tmpl_afrom_str(map, &map->rhs, value, type, src_request_def, src_list_def);
+ slen = tmpl_afrom_str(map, &map->rhs, value, strlen(value), type, src_request_def, src_list_def);
if (slen < 0) {
char *spaces, *text;
map = talloc_zero(ctx, value_pair_map_t);
- slen = tmpl_afrom_str(map, &map->lhs, lhs, lhs_type, dst_request_def, dst_list_def);
+ slen = tmpl_afrom_str(map, &map->lhs, lhs, strlen(lhs), lhs_type, dst_request_def, dst_list_def);
if (slen < 0) {
error:
talloc_free(map);
return 0;
}
- slen = tmpl_afrom_str(map, &map->rhs, rhs, rhs_type, src_request_def, src_list_def);
+ slen = tmpl_afrom_str(map, &map->rhs, rhs, strlen(rhs), rhs_type, src_request_def, src_list_def);
if (slen < 0) goto error;
VERIFY_MAP(map);
fr_cond_t cond;
value_pair_map_t map;
value_pair_tmpl_t vpt;
- char *expanded = NULL;
-
MOD_LOG_OPEN_BRACE;
if ((g->vpt->type == TMPL_TYPE_XLAT_STRUCT) ||
(g->vpt->type == TMPL_TYPE_XLAT) ||
(g->vpt->type == TMPL_TYPE_EXEC)) {
- if (radius_expand_tmpl(&expanded, request, g->vpt) < 0) goto find_null_case;
- tmpl_init(&vpt, TMPL_TYPE_LITERAL, expanded, talloc_array_length(expanded) - 1);
+ value_data_t data;
+
+ if (radius_expand_tmpl(&data, request, g->vpt) < 0) goto find_null_case;
+ tmpl_init(&vpt, TMPL_TYPE_LITERAL, data.strvalue, talloc_array_length(data.strvalue) - 1);
+ talloc_free(data.ptr);
}
/*
break;
}
}
- talloc_free(expanded);
if (!found) found = null_case;
* will fix it up.
*/
type = cf_section_name2_type(cs);
- slen = tmpl_afrom_str(cs, &vpt, name2, type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
+ slen = tmpl_afrom_str(cs, &vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
if ((slen < 0) && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
char *spaces, *text;
type = cf_section_name2_type(cs);
- slen = tmpl_afrom_str(cs, &vpt, name2, type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
+ slen = tmpl_afrom_str(cs, &vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
if ((slen < 0) && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
char *spaces, *text;
* will fix it up.
*/
type = cf_section_name2_type(cs);
- slen = tmpl_afrom_str(cs, &vpt, name2, type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
+ slen = tmpl_afrom_str(cs, &vpt, name2, strlen(name2), type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
if ((slen < 0) && ((type != T_BARE_WORD) || (name2[0] != '&'))) {
char *spaces, *text;
value_pair_tmpl_t *vpt;
fmt = talloc_asprintf(map->lhs, "%%{%s}", map->lhs->name);
- slen = tmpl_afrom_str(map, &vpt, fmt, T_DOUBLE_QUOTED_STRING, REQUEST_CURRENT, PAIR_LIST_REQUEST);
+ slen = tmpl_afrom_str(map, &vpt, fmt, talloc_array_length(fmt) - 1,
+ T_DOUBLE_QUOTED_STRING, REQUEST_CURRENT, PAIR_LIST_REQUEST);
if (slen < 0) {
char *spaces, *text;
rad_assert(c->name[0] == '&');
rad_assert(cf_section_name2_type(g->cs) == T_BARE_WORD);
- slen = tmpl_afrom_str(g->cs, &g->vpt, c->name,
+ slen = tmpl_afrom_str(g->cs, &g->vpt, c->name, strlen(c->name),
cf_section_name2_type(g->cs),
REQUEST_CURRENT, PAIR_LIST_REQUEST);
if (slen < 0) {
if (g->vpt->type == TMPL_TYPE_LITERAL) {
value_pair_tmpl_t *vpt;
- slen = tmpl_afrom_str(g->cs, &vpt, c->name, cf_section_name2_type(g->cs),
+ slen = tmpl_afrom_str(g->cs, &vpt, c->name, strlen(c->name), cf_section_name2_type(g->cs),
REQUEST_CURRENT, PAIR_LIST_REQUEST);
if (slen < 0) goto parse_error;
if (vpt->type == TMPL_TYPE_ATTR) {
if (!g->vpt && c->name &&
(c->name[0] == '&') &&
(cf_section_name2_type(g->cs) == T_BARE_WORD)) {
- slen = tmpl_afrom_str(g->cs, &g->vpt, c->name,
+ slen = tmpl_afrom_str(g->cs, &g->vpt, c->name, strlen(c->name),
cf_section_name2_type(g->cs),
REQUEST_CURRENT, PAIR_LIST_REQUEST);
if (slen < 0) goto parse_error;
* all of the modules have been loaded.
* Check for that now.
*/
- slen = tmpl_afrom_str(g->cs, &g->vpt, c->name, cf_section_name2_type(g->cs),
+ slen = tmpl_afrom_str(g->cs, &g->vpt, c->name, strlen(c->name), cf_section_name2_type(g->cs),
REQUEST_CURRENT, PAIR_LIST_REQUEST);
if (slen < 0) goto parse_error;
}
-static ssize_t condition_tokenize_string(TALLOC_CTX *ctx, char **out, char const **error, char const *start,
+static ssize_t condition_tokenize_string(TALLOC_CTX *ctx, char **out, char const **error, char const *start,
FR_TOKEN *op)
{
char const *p = start;
while (*p) {
if (*p == *start) {
- *q = '\0';
+ /*
+ * Call the STANDARD parse function to figure out what the string is.
+ */
+ if (cf_new_escape) {
+ ssize_t slen;
+ value_data_t data;
+ PW_TYPE src_type = PW_TYPE_STRING;
+
+ slen = value_data_from_str(ctx, &data, &src_type, NULL, start + 1, p - (start + 1), *start);
+ if (slen < 0) {
+ *error = "error parsing string";
+ return slen - 1;
+ }
+
+ talloc_free(*out);
+ *out = talloc_steal(ctx, data.ptr);
+ data.strvalue = NULL;
+
+ } else {
+ *q = '\0'; /* terminate the output string */
+ }
+
p++;
return (p - start);
}
c->type = COND_TYPE_EXISTS;
c->ci = ci;
- tlen = tmpl_afrom_str(c, &c->data.vpt, lhs, lhs_type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
+ tlen = tmpl_afrom_str(c, &c->data.vpt, lhs, talloc_array_length(lhs) - 1, lhs_type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
if (tlen < 0) {
p = lhs_p - tlen;
return_P(fr_strerror());
*/
c->data.map = map = talloc_zero(c, value_pair_map_t);
- tlen = tmpl_afrom_str(map, &map->lhs, lhs, lhs_type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
+ tlen = tmpl_afrom_str(map, &map->lhs, lhs, talloc_array_length(lhs) - 1, lhs_type, REQUEST_CURRENT, PAIR_LIST_REQUEST);
if (tlen < 0) {
p = lhs_p - tlen;
return_P(fr_strerror());
map_cast_from_hex(map, rhs_type, rhs)) {
/* do nothing */
} else {
- tlen = tmpl_afrom_str(map, &map->rhs, rhs, rhs_type,
+ tlen = tmpl_afrom_str(map, &map->rhs, rhs, talloc_array_length(rhs) - 1, rhs_type,
REQUEST_CURRENT, PAIR_LIST_REQUEST);
if (tlen < 0) {
p = rhs_p - tlen;
* attributes, and instead set type to TMPL_TYPE_ATTR_UNDEFINED.
* @return <= 0 on error (offset as negative integer), > 0 on success (number of bytes parsed)
*/
-ssize_t tmpl_from_attr_str(value_pair_tmpl_t *vpt, char const *name, request_refs_t request_def,
- pair_lists_t list_def, bool allow_undefined)
+ssize_t tmpl_from_attr_str(value_pair_tmpl_t *vpt, char const *name,
+ request_refs_t request_def, pair_lists_t list_def, bool allow_undefined)
{
ssize_t slen;
* @param[in] list_def The default list to insert unqualified attributes into.
* @return < 0 on error (offset as negative integer), >= 0 on success (number of bytes parsed)
*/
-ssize_t tmpl_afrom_str(TALLOC_CTX *ctx, value_pair_tmpl_t **out, char const *name, FR_TOKEN type,
+ssize_t tmpl_afrom_str(TALLOC_CTX *ctx, value_pair_tmpl_t **out, char const *name, size_t inlen, FR_TOKEN type,
request_refs_t request_def, pair_lists_t list_def)
{
char const *p;
ssize_t slen;
+ PW_TYPE data_type = PW_TYPE_STRING;
value_pair_tmpl_t *vpt;
+ value_data_t data;
switch (type) {
case T_BARE_WORD:
/* FALL-THROUGH */
case T_SINGLE_QUOTED_STRING:
- vpt = tmpl_alloc(ctx, TMPL_TYPE_LITERAL, name, -1);
+ if (cf_new_escape) {
+ slen = value_data_from_str(ctx, &data, &data_type, NULL, name, inlen, '\'');
+ rad_assert(slen >= 0);
+
+ vpt = tmpl_alloc(ctx, TMPL_TYPE_LITERAL, data.strvalue, talloc_array_length(data.strvalue) - 1);
+ talloc_free(data.ptr);
+ } else {
+ vpt = tmpl_alloc(ctx, TMPL_TYPE_LITERAL, name, -1);
+ }
slen = vpt->len;
break;
* expansion. Otherwise, convert it to be a
* literal.
*/
- if (*p) {
- vpt = tmpl_alloc(ctx, TMPL_TYPE_XLAT, name, -1);
+ if (cf_new_escape) {
+ slen = value_data_from_str(ctx, &data, &data_type, NULL, name, inlen, '"');
+ rad_assert(slen >= 0);
+
+ if (*p) {
+ vpt = tmpl_alloc(ctx, TMPL_TYPE_XLAT, data.strvalue, talloc_array_length(data.strvalue) - 1);
+ } else {
+ vpt = tmpl_alloc(ctx, TMPL_TYPE_LITERAL, data.strvalue, talloc_array_length(data.strvalue) - 1);
+ }
+ talloc_free(data.ptr);
} else {
- vpt = tmpl_alloc(ctx, TMPL_TYPE_LITERAL, name, -1);
+ if (*p) {
+ vpt = tmpl_alloc(ctx, TMPL_TYPE_XLAT, name, -1);
+ } else {
+ vpt = tmpl_alloc(ctx, TMPL_TYPE_LITERAL, name, -1);
+ }
}
slen = vpt->len;
break;
case T_BACK_QUOTED_STRING:
- vpt = tmpl_alloc(ctx, TMPL_TYPE_EXEC, name, -1);
+ if (cf_new_escape) {
+ slen = value_data_from_str(ctx, &data, &data_type, NULL, name, inlen, '`');
+ rad_assert(slen >= 0);
+
+ vpt = tmpl_alloc(ctx, TMPL_TYPE_EXEC, data.strvalue, talloc_array_length(data.strvalue) - 1);
+ talloc_free(data.ptr);
+ } else {
+ vpt = tmpl_alloc(ctx, TMPL_TYPE_EXEC, name, -1);
+ }
slen = vpt->len;
break;
case T_OP_REG_EQ: /* hack */
- vpt = tmpl_alloc(ctx, TMPL_TYPE_REGEX, name, -1);
+ if (cf_new_escape) {
+ slen = value_data_from_str(ctx, &data, &data_type, NULL, name, inlen, '\0'); /* no unescaping */
+ rad_assert(slen >= 0);
+
+ vpt = tmpl_alloc(ctx, TMPL_TYPE_REGEX, data.strvalue, talloc_array_length(data.strvalue) - 1);
+ talloc_free(data.ptr);
+ } else {
+ vpt = tmpl_alloc(ctx, TMPL_TYPE_REGEX, name, -1);
+ }
slen = vpt->len;
break;
/** Convert a tmpl containing literal data, to the type specified by da.
*
* @param[in,out] vpt the template to modify
- * @param[in] type to case to.
+ * @param[in] type to cast to.
* @param[in] enumv Enumerated dictionary values.
* @return true for success, false for failure.
*/
/*
* Why do we pass a pointer to the tmpl type? Goddamn WiMAX.
*/
- ret = value_data_from_str(vpt, &vpt->tmpl_data_value, &vpt->tmpl_data_type, enumv, vpt->name, vpt->len);
+ ret = value_data_from_str(vpt, &vpt->tmpl_data_value, &vpt->tmpl_data_type, enumv, vpt->name, vpt->len, '\0');
if (ret < 0) return false;
vpt->type = TMPL_TYPE_DATA;
{
int rcode;
VALUE_PAIR *vp;
- char *str;
+ value_data_t data;
VERIFY_TMPL(vpt);
return 0;
}
- rcode = radius_expand_tmpl(&str, request, vpt);
+ rcode = radius_expand_tmpl(&data, request, vpt);
if (rcode < 0) {
pairfree(&vp);
return rcode;
}
- if (pairparsevalue(vp, str, -1) < 0) {
- talloc_free(str);
- pairfree(&vp);
- return rcode;
+ /*
+ * New escapes: strings are in binary form.
+ */
+ if (cf_new_escape && (vp->da->type == PW_TYPE_STRING)) {
+ vp->data.ptr = talloc_steal(vp, data.ptr);
+ vp->vp_length = rcode;
+
+ } else if (pairparsevalue(vp, data.strvalue, rcode) < 0) {
+ talloc_free(data.ptr);
+ pairfree(&vp);
+ return -1;
}
*out = vp;
switch (vp->da->type) {
case PW_TYPE_OCTETS:
- len = fr_print_string((char const *) p, vp->vp_length, out, outlen, '\0');
+ len = fr_print_string((char const *) p, vp->vp_length, out, outlen, '"');
break;
case PW_TYPE_STRING:
{
ssize_t rcode;
char *str = NULL, *child;
- char *q;
char const *p;
XLAT_DEBUG("%.*sxlat aprint %d", lvl, xlat_spaces, node->type);
*
* This is really the reverse of fr_print_string().
*/
- p = q = child;
- while (*p) {
- if (*p == '\\') switch (p[1]) {
- default:
- *(q++) = p[1];
- p += 2;
- continue;
-
- case 'n':
- *(q++) = '\n';
- p += 2;
- continue;
-
- case 't':
- *(q++) = '\t';
- p += 2;
- continue;
- }
+ if (cf_new_escape && *child) {
+ ssize_t slen;
+ PW_TYPE type;
+ value_data_t data;
+
+ type = PW_TYPE_STRING;
+ slen = value_data_from_str(request, &data, &type, NULL, child, talloc_array_length(child) - 1, '"');
+ rad_assert(slen > 0);
+
+ talloc_free(child);
+ child = data.ptr;
- *(q++) = *(p++);
+ } else {
+ char *q;
+
+ p = q = child;
+ while (*p) {
+ if (*p == '\\') switch (p[1]) {
+ default:
+ *(q++) = p[1];
+ p += 2;
+ continue;
+
+ case 'n':
+ *(q++) = '\n';
+ p += 2;
+ continue;
+
+ case 't':
+ *(q++) = '\t';
+ p += 2;
+ continue;
+ }
+
+ *(q++) = *(p++);
+ }
+ *q = '\0';
}
- *q = '\0';
str = talloc_array(ctx, char, 2048); /* FIXME: have the module call talloc_typed_asprintf */
*str = '\0'; /* Be sure the string is NULL terminated, we now only free on error */
}
}
-if (<string>"%{unescape:%{request:Tmp-String-3}}" != &Tmp-String-1) {
+if (<string>"%{unescape:%{request:Tmp-String-3}}" != "%{Tmp-String-1}") {
update reply {
Filter-Id += 'Fail 5'
}
Tmp-String-1 += '0x01\0010x07\0070x0A\n0x0D\r""0xb0\260°'
Tmp-String-2 := 'i have scary embedded things\000 inside me'
- Tmp-String-2 += '0x01\0010x07\0070x0A\n0x0D\r\'\'0xb0\260°'
+ Tmp-String-2 += "0x01\0010x07\0070x0A\n0x0D\r''0xb0\260°"
reply:Filter-Id := "filter"
}
-if ("%{string:Tmp-Octets-0}" != 'i have scary embedded things\000 inside me') {
+
+if ("%{length:&Tmp-String-0}" != 39) {
+ update reply {
+ Filter-Id += 'fail l-0'
+ }
+}
+
+if ("%{length:&Tmp-String-1}" != 42) {
+ update reply {
+ Filter-Id += 'fail l-1'
+ }
+}
+
+if ("%{string:Tmp-Octets-0}" != "i have scary embedded things\000 inside me") {
update reply {
Filter-Id += 'fail 1'
}
}
}
-if ("%{string:Tmp-Octets-1}" != '0x01\0010x07\0070x0A\n0x0D\r""0xb0\260°') {
+if ("%{string:Tmp-Octets-1}" != "0x01\0010x07\0070x0A\n0x0D\r\"\"0xb0\260°") {
update reply {
Filter-Id += 'fail 3'
}
}
-if ("%{Tmp-String-0[0]}" != 'i have scary embedded things\000 inside me') {
+if ("%{Tmp-String-0[0]}" != "i have scary embedded things\000 inside me") {
update reply {
Filter-Id += 'fail 4'
}
}
-if ("%{Tmp-String-0[1]}" != '0x01\0010x07\0070x0A\n0x0D\r\"\"0xb0\260°') {
+if ("%{Tmp-String-0[1]}" != "0x01\0010x07\0070x0A\n0x0D\r\"\"0xb0\260°") {
update reply {
Filter-Id += 'fail 5'
}
}
# And another slightly different codepath...
-if ("%{Tmp-String-0[*]}" != 'i have scary embedded things\000 inside me,0x01\0010x07\0070x0A\n0x0D\r\"\"0xb0\260°') {
+if ("%{Tmp-String-0[*]}" != "i have scary embedded things\000 inside me,0x01\0010x07\0070x0A\n0x0D\r\"\"0xb0\260°") {
update reply {
Filter-Id += 'fail 6'
}
# This seems weird... double escapes for most things, but single escapes
# for the quotation marks.
#
-if ("%{Tmp-String-2[1]}" != '0x01\0010x07\0070x0A\n0x0D\r\'\'0xb0\260°') {
+if ("%{Tmp-String-2[1]}" != "0x01\0010x07\0070x0A\n0x0D\r''0xb0\260°") {
update reply {
Filter-Id += 'fail 8'
}
#
# And again as an attribute reference
#
-if (&Tmp-String-2[1] != '0x01\0010x07\0070x0A\n0x0D\r\'\'0xb0\260°') {
+if (&Tmp-String-2[1] != "0x01\0010x07\0070x0A\n0x0D\r''0xb0\260°") {
update reply {
Filter-Id += 'fail 9'
}
# . is a valid dictionary name attribute, so we can't error out in pass1
condition ¬-a-packet.User-Name == ¬-a-packet.User-Name
data ¬-a-packet.User-Name == ¬-a-packet.User-Name
+
+#
+# The LHS is a string with ASCII 5C 30 30 30 inside of it.
+#
+condition ('i have scary embedded things\000 inside me' == "i have scary embedded things\000 inside me")
+data false