char name[MAX_STRING_LEN]; //!< Name of the xlat expansion.
int length; //!< Length of name.
void *instance; //!< Module instance passed to xlat and escape functions.
- RAD_XLAT_FUNC func; //!< xlat function.
- RADIUS_ESCAPE_STRING escape; //!< Escape function to apply to dynamic input to func.
+ xlat_func_t func; //!< xlat function.
+ xlat_escape_t escape; //!< Escape function to apply to dynamic input to func.
bool internal; //!< If true, cannot be redefined.
} xlat_t;
xlat_exp_t *child; //!< Nested expansion.
xlat_exp_t *alternate; //!< Alternative expansion if this one expanded to a zero length string.
- value_pair_tmpl_t attr; //!< An attribute template.
+ vp_tmpl_t attr; //!< An attribute template.
xlat_t const *xlat; //!< The xlat expansion to expand format with.
};
static int xlat_inst[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; /* up to 10 for foreach */
-static char const *radiusd_short_version = RADIUSD_VERSION_STRING;
-
/** Print length of its RHS.
*
*/
return snprintf(out, outlen, "%u", htonl((*(uint32_t *)(vp->vp_ipv4prefix + 2))));
case PW_TYPE_INTEGER:
- case PW_TYPE_DATE:
return snprintf(out, outlen, "%u", vp->vp_integer);
+
+ case PW_TYPE_DATE:
+ return snprintf(out, outlen, "%u", vp->vp_date);
+
case PW_TYPE_BYTE:
return snprintf(out, outlen, "%u", (unsigned int) vp->vp_byte);
+
case PW_TYPE_SHORT:
return snprintf(out, outlen, "%u", (unsigned int) vp->vp_short);
return snprintf(out, outlen, "%u", vp->tag);
}
+/** Return the vendor of an attribute reference
+ *
+ */
+static ssize_t xlat_vendor(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ VALUE_PAIR *vp;
+ DICT_VENDOR *vendor;
+
+ while (isspace((int) *fmt)) fmt++;
+
+ if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
+ *out = '\0';
+ return 0;
+ }
+
+ vendor = dict_vendorbyvalue(vp->da->vendor);
+ if (!vendor) {
+ *out = '\0';
+ return 0;
+ }
+ strlcpy(out, vendor->name, outlen);
+
+ return vendor->length;
+}
+
+/** Return the vendor number of an attribute reference
+ *
+ */
+static ssize_t xlat_vendor_num(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ VALUE_PAIR *vp;
+
+ while (isspace((int) *fmt)) fmt++;
+
+ if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
+ *out = '\0';
+ return 0;
+ }
+
+ return snprintf(out, outlen, "%u", vp->da->vendor);
+}
+
+/** Return the attribute name of an attribute reference
+ *
+ */
+static ssize_t xlat_attr(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ VALUE_PAIR *vp;
+
+ while (isspace((int) *fmt)) fmt++;
+
+ if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
+ *out = '\0';
+ return 0;
+ }
+ strlcpy(out, vp->da->name, outlen);
+
+ return strlen(vp->da->name);
+}
+
+/** Return the attribute number of an attribute reference
+ *
+ */
+static ssize_t xlat_attr_num(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ VALUE_PAIR *vp;
+
+ while (isspace((int) *fmt)) fmt++;
+
+ if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) {
+ *out = '\0';
+ return 0;
+ }
+
+ return snprintf(out, outlen, "%u", vp->da->attr);
+}
+
/** Print out attribute info
*
* Prints out all instances of a current attribute, or all attributes in a list.
* value. This is helpful to determine types for unknown attributes of long
* passed vendors, or just crazy/broken NAS.
*
- * It's also useful for exposing issues in the packet decoding functions, as in
- * some cases they get fed random garbage data.
- *
* This expands to a zero length string.
*/
static ssize_t xlat_debug_attr(UNUSED void *instance, REQUEST *request, char const *fmt,
VALUE_PAIR *vp;
vp_cursor_t cursor;
- value_pair_tmpl_t vpt;
+ vp_tmpl_t vpt;
if (!RDEBUG_ENABLED2) {
*out = '\0';
while (isspace((int) *fmt)) fmt++;
- if (tmpl_from_attr_str(&vpt, fmt, REQUEST_CURRENT, PAIR_LIST_REQUEST, false) <= 0) {
+ if (tmpl_from_attr_str(&vpt, fmt, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false) <= 0) {
RDEBUG("%s", fr_strerror());
return -1;
}
case PW_TYPE_COMBO_IP_ADDR: /* Covered by IPv4 address IPv6 address */
case PW_TYPE_COMBO_IP_PREFIX: /* Covered by IPv4 address IPv6 address */
case PW_TYPE_TIMEVAL: /* Not a VALUE_PAIR type */
-
goto next_type;
default:
&vp->data, vp->vp_length);
if (ret < 0) goto next_type; /* We expect some to fail */
- value = vp_data_aprints_value(dst, type->number, NULL, dst, (size_t)ret, '\'');
+ value = value_data_aprints(dst, type->number, NULL, dst, (size_t)ret, '\'');
if (!value) goto next_type;
if ((pad = (11 - strlen(type->name))) < 0) {
return 0;
}
+/** Processes fmt as a map string and applies it to the current request
+ *
+ * e.g. "%{map:&User-Name := 'foo'}"
+ *
+ * Allows sets of modifications to be cached and then applied.
+ * Useful for processing generic attributes from LDAP.
+ */
+static ssize_t xlat_map(UNUSED void *instance, REQUEST *request,
+ char const *fmt, char *out, size_t outlen)
+{
+ vp_map_t *map = NULL;
+ int ret;
+
+ if (map_afrom_attr_str(request, &map, fmt,
+ REQUEST_CURRENT, PAIR_LIST_REQUEST,
+ REQUEST_CURRENT, PAIR_LIST_REQUEST) < 0) {
+ REDEBUG("Failed parsing \"%s\" as map: %s", fmt, fr_strerror());
+ return -1;
+ }
+
+ RINDENT();
+ ret = map_to_request(request, map, map_to_vp, NULL);
+ REXDENT();
+ talloc_free(map);
+ if (ret < 0) return strlcpy(out, "0", outlen);
+
+ return strlcpy(out, "1", outlen);
+}
+
/** Prints the current module processing the request
*
*/
len = fr_prints(out, outlen, (char const *) p, vp->vp_length, '"');
break;
+ /*
+ * Note that "%{string:...}" is NOT binary safe!
+ * It is explicitly used to get rid of embedded zeros.
+ */
case PW_TYPE_STRING:
len = strlcpy(out, vp->vp_strvalue, outlen);
break;
if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) goto nothing;
+ if (vp->da->type != PW_TYPE_STRING) goto nothing;
+
return radius_xlat(out, outlen, request, vp->vp_strvalue, NULL, NULL);
}
/*
* Expand to previous (or current) level
*/
- snprintf(out, outlen, "%d", request->log.lvl & RAD_REQUEST_OPTION_DEBUG4);
+ snprintf(out, outlen, "%d", request->log.lvl);
/*
* Assume we just want to get the current value and NOT set it to 0
level = atoi(fmt);
if (level == 0) {
- request->log.lvl = RAD_REQUEST_OPTION_NONE;
+ request->log.lvl = RAD_REQUEST_LVL_NONE;
request->log.func = NULL;
} else {
if (level > 4) level = 4;
* @param[in] instance of module that's registering the xlat function.
* @return 0 on success, -1 on failure
*/
-int xlat_register(char const *name, RAD_XLAT_FUNC func, RADIUS_ESCAPE_STRING escape, void *instance)
+int xlat_register(char const *name, xlat_func_t func, xlat_escape_t escape, void *instance)
{
xlat_t *c;
xlat_t my_xlat;
XLAT_REGISTER(length);
XLAT_REGISTER(hex);
XLAT_REGISTER(tag);
+ XLAT_REGISTER(vendor);
+ XLAT_REGISTER(vendor_num);
+ XLAT_REGISTER(attr);
+ XLAT_REGISTER(attr_num);
XLAT_REGISTER(string);
XLAT_REGISTER(xlat);
+ XLAT_REGISTER(map);
XLAT_REGISTER(module);
XLAT_REGISTER(debug_attr);
#if defined(HAVE_REGEX) && defined(HAVE_PCRE)
* @param[in] func unused.
* @param[in] instance data.
*/
-void xlat_unregister(char const *name, UNUSED RAD_XLAT_FUNC func, void *instance)
+void xlat_unregister(char const *name, UNUSED xlat_func_t func, void *instance)
{
xlat_t *c;
xlat_t my_xlat;
- if (!name) return;
+ if (!name || !xlat_root) return;
strlcpy(my_xlat.name, name, sizeof(my_xlat.name));
my_xlat.length = strlen(my_xlat.name);
if (!cf_item_is_pair(ci)) continue;
- name = cf_pair_attr(cf_itemtopair(ci));
+ name = cf_pair_attr(cf_item_to_pair(ci));
rad_assert(name != NULL);
xlat = xlat_find(name);
* Plain load balancing: do one child, and only one child.
*/
if (xr->type == XLAT_LOAD_BALANCE) {
- name = cf_pair_attr(cf_itemtopair(found));
+ name = cf_pair_attr(cf_item_to_pair(found));
rad_assert(name != NULL);
xlat = xlat_find(name);
*/
ci = found;
do {
- name = cf_pair_attr(cf_itemtopair(ci));
+ name = cf_pair_attr(cf_item_to_pair(ci));
rad_assert(name != NULL);
xlat = xlat_find(name);
ci = cf_item_find_next(cs, ci)) {
if (!cf_item_is_pair(ci)) continue;
- if (!xlat_find(cf_pair_attr(cf_itemtopair(ci)))) {
+ if (!xlat_find(cf_pair_attr(cf_item_to_pair(ci)))) {
talloc_free(xr);
return false;
}
static ssize_t xlat_tokenize_literal(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
bool brace, char const **error);
static size_t xlat_process(char **out, REQUEST *request, xlat_exp_t const * const head,
- RADIUS_ESCAPE_STRING escape, void *escape_ctx);
+ xlat_escape_t escape, void *escape_ctx);
static ssize_t xlat_tokenize_alternation(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head,
char const **error)
* Check for empty expressions %{}
*/
if ((*q == '}') && (q == p)) {
+ talloc_free(node);
*error = "Empty expression is invalid";
return -(p - fmt);
}
XLAT_DEBUG("MOD <-- %s ... %s", node->fmt, p);
slen = xlat_tokenize_literal(node, p, &node->child, true, error);
- if (slen <= 0) {
+ if (slen < 0) {
talloc_free(node);
return slen - (p - fmt);
}
* - '[' - Which is an attribute index, so it must be an attribute.
* - '}' - The end of the expansion, which means it was a bareword.
*/
- slen = tmpl_from_attr_substr(&node->attr, p, REQUEST_CURRENT, PAIR_LIST_REQUEST, true);
+ slen = tmpl_from_attr_substr(&node->attr, p, REQUEST_CURRENT, PAIR_LIST_REQUEST, true, true);
if (slen <= 0) {
/*
* If the parse error occurred before the ':'
} else {
*error = fr_strerror();
}
+
+ talloc_free(node);
return slen - (p - fmt);
}
*/
if (node->attr.type == TMPL_TYPE_ATTR_UNDEFINED) {
node->xlat = xlat_find(node->attr.tmpl_unknown_name);
+ if (node->xlat && node->xlat->instance && !node->xlat->internal) {
+ talloc_free(node);
+ *error = "Missing content in expansion";
+ return -(p - fmt) - slen;
+ }
+
if (node->xlat) {
node->type = XLAT_VIRTUAL;
node->fmt = node->attr.tmpl_unknown_name;
*error = "No matching closing brace";
return -1; /* second character of format string */
}
- p++;
+ *p++ = '\0';
*head = node;
rad_assert(node->next == NULL);
*error = "Invalid escape at end of string";
return -(p - fmt);
}
+
p += 2;
+ node->len += 2;
continue;
}
ssize_t slen;
xlat_exp_t *next;
- if (!p[1] || !strchr("%dlmntDGHISTYv", p[1])) {
- talloc_free(node);
- *error = "Invalid variable expansion";
- p++;
- return - (p - fmt);
+ if (!p[1] || !strchr("%}dlmntDGHISTYv", p[1])) {
+ talloc_free(node);
+ *error = "Invalid variable expansion";
+ p++;
+ return - (p - fmt);
}
next = talloc_zero(node, xlat_exp_t);
next->len = 1;
- if (p[1] == '%') {
- next->fmt = talloc_typed_strdup(next, "%");
+ switch (p[1]) {
+ case '%':
+ case '}':
+ next->fmt = talloc_strndup(next, p + 1, 1);
- XLAT_DEBUG("LITERAL-PERCENT <-- %s", next->fmt);
+ XLAT_DEBUG("LITERAL-ESCAPED <-- %s", next->fmt);
next->type = XLAT_LITERAL;
+ break;
- } else {
+ default:
next->fmt = p + 1;
XLAT_DEBUG("PERCENT <-- %c", *next->fmt);
next->type = XLAT_PERCENT;
+ break;
}
node->next = next;
#endif
case XLAT_ALTERNATE:
- DEBUG("%.*sif {", lvl, xlat_tabs);
+ DEBUG("%.*sXLAT-IF {", lvl, xlat_tabs);
xlat_tokenize_debug(node->child, lvl + 1);
DEBUG("%.*s}", lvl, xlat_tabs);
- DEBUG("%.*selse {", lvl, xlat_tabs);
+ DEBUG("%.*sXLAT-ELSE {", lvl, xlat_tabs);
xlat_tokenize_debug(node->alternate, lvl + 1);
DEBUG("%.*s}", lvl, xlat_tabs);
break;
return slen;
}
- if (*head && (debug_flag > 2)) {
+ if (*head && (rad_debug_lvl > 2)) {
DEBUG("%s", fmt);
DEBUG("Parsed xlat tree:");
xlat_tokenize_debug(*head, 0);
}
-static char *xlat_getvp(TALLOC_CTX *ctx, REQUEST *request, value_pair_tmpl_t const *vpt,
+static char *xlat_getvp(TALLOC_CTX *ctx, REQUEST *request, vp_tmpl_t const *vpt,
bool escape, bool return_null)
{
VALUE_PAIR *vp = NULL, *virtual = NULL;
RADIUS_PACKET *packet = NULL;
DICT_VALUE *dv;
char *ret = NULL;
- int err;
+ vp_cursor_t cursor;
char quote = escape ? '"' : '\0';
- vp_cursor_t cursor;
+ rad_assert((vpt->type == TMPL_TYPE_ATTR) || (vpt->type == TMPL_TYPE_LIST));
+
+ /*
+ * We only support count and concatenate operations on lists.
+ */
+ if (vpt->type == TMPL_TYPE_LIST) {
+ vp = tmpl_cursor_init(NULL, &cursor, request, vpt);
+ goto do_print;
+ }
/*
* See if we're dealing with an attribute in the request
* This allows users to manipulate virtual attributes as if
* they were real ones.
*/
- vp = tmpl_cursor_init(&err, &cursor, request, vpt);
+ vp = tmpl_cursor_init(NULL, &cursor, request, vpt);
if (vp) goto do_print;
/*
* various VP functions.
*/
case PW_PACKET_AUTHENTICATION_VECTOR:
- virtual = pairalloc(ctx, vpt->tmpl_da);
- pairmemcpy(virtual, packet->vector, sizeof(packet->vector));
+ virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
+ fr_pair_value_memcpy(virtual, packet->vector, sizeof(packet->vector));
vp = virtual;
break;
case PW_CLIENT_IP_ADDRESS:
case PW_PACKET_SRC_IP_ADDRESS:
if (packet->src_ipaddr.af == AF_INET) {
- virtual = pairalloc(ctx, vpt->tmpl_da);
+ virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
virtual->vp_ipaddr = packet->src_ipaddr.ipaddr.ip4addr.s_addr;
vp = virtual;
}
case PW_PACKET_DST_IP_ADDRESS:
if (packet->dst_ipaddr.af == AF_INET) {
- virtual = pairalloc(ctx, vpt->tmpl_da);
+ virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
virtual->vp_ipaddr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr;
vp = virtual;
}
case PW_PACKET_SRC_IPV6_ADDRESS:
if (packet->src_ipaddr.af == AF_INET6) {
- virtual = pairalloc(ctx, vpt->tmpl_da);
+ virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
memcpy(&virtual->vp_ipv6addr,
&packet->src_ipaddr.ipaddr.ip6addr,
sizeof(packet->src_ipaddr.ipaddr.ip6addr));
case PW_PACKET_DST_IPV6_ADDRESS:
if (packet->dst_ipaddr.af == AF_INET6) {
- virtual = pairalloc(ctx, vpt->tmpl_da);
+ virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
memcpy(&virtual->vp_ipv6addr,
&packet->dst_ipaddr.ipaddr.ip6addr,
sizeof(packet->dst_ipaddr.ipaddr.ip6addr));
break;
case PW_PACKET_SRC_PORT:
- virtual = pairalloc(ctx, vpt->tmpl_da);
+ virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
virtual->vp_integer = packet->src_port;
vp = virtual;
break;
case PW_PACKET_DST_PORT:
- virtual = pairalloc(ctx, vpt->tmpl_da);
+ virtual = fr_pair_afrom_da(ctx, vpt->tmpl_da);
virtual->vp_integer = packet->dst_port;
vp = virtual;
break;
{
int count = 0;
- fr_cursor_first(&cursor);
- while (fr_cursor_next_by_da(&cursor, vpt->tmpl_da, vpt->tmpl_tag)) count++;
+ for (vp = tmpl_cursor_init(NULL, &cursor, request, vpt);
+ vp;
+ vp = tmpl_cursor_next(&cursor, vpt)) count++;
return talloc_typed_asprintf(ctx, "%d", count);
}
#endif
static char *xlat_aprint(TALLOC_CTX *ctx, REQUEST *request, xlat_exp_t const * const node,
- RADIUS_ESCAPE_STRING escape, void *escape_ctx, int lvl)
+ xlat_escape_t escape, void *escape_ctx, int lvl)
{
ssize_t rcode;
char *str = NULL, *child;
char const *p;
- XLAT_DEBUG("%.*sxlat aprint %d", lvl, xlat_spaces, node->type);
+ XLAT_DEBUG("%.*sxlat aprint %d %s", lvl, xlat_spaces, node->type, node->fmt);
switch (node->type) {
/*
* Don't escape this.
*/
case XLAT_LITERAL:
- XLAT_DEBUG("xlat_aprint LITERAL");
+ XLAT_DEBUG("%.*sxlat_aprint LITERAL", lvl, xlat_spaces);
return talloc_typed_strdup(ctx, node->fmt);
/*
size_t freespace = 256;
struct tm ts;
time_t when;
+ int usec;
- XLAT_DEBUG("xlat_aprint PERCENT");
+ XLAT_DEBUG("%.*sxlat_aprint PERCENT", lvl, xlat_spaces);
str = talloc_array(ctx, char, freespace); /* @todo do better allocation */
p = node->fmt;
when = request->timestamp;
+ usec = 0;
if (request->packet) {
when = request->packet->timestamp.tv_sec;
+ usec = request->packet->timestamp.tv_usec;
}
switch (*p) {
case 'S': /* request timestamp in SQL format*/
if (!localtime_r(&when, &ts)) goto error;
- strftime(str, freespace, "%Y-%m-%d %H:%M:%S", &ts);
+ nl = str + strftime(str, freespace, "%Y-%m-%d %H:%M:%S", &ts);
+ rad_assert(((str + freespace) - nl) >= 8);
+ snprintf(nl, (str + freespace) - nl, ".%06d", usec);
break;
case 'T': /* request timestamp */
if (!localtime_r(&when, &ts)) goto error;
- strftime(str, freespace, "%Y-%m-%d-%H.%M.%S.000000", &ts);
+ strftime(str, freespace, "%Y-%m-%d-%H.%M.%S", &ts);
+
break;
case 'Y': /* request year */
break;
case 'v': /* Version of code */
- snprintf(str, freespace, "%s", radiusd_short_version);
+ RWDEBUG("%%v is deprecated and will be removed. Use ${version.freeradius-server}");
+ snprintf(str, freespace, "%s", radiusd_version_short);
break;
default:
break;
case XLAT_ATTRIBUTE:
- XLAT_DEBUG("xlat_aprint ATTRIBUTE");
+ XLAT_DEBUG("%.*sxlat_aprint ATTRIBUTE", lvl, xlat_spaces);
/*
* Some attributes are virtual <sigh>
*/
str = xlat_getvp(ctx, request, &node->attr, escape ? false : true, true);
if (str) {
- XLAT_DEBUG("EXPAND attr %s", node->attr.tmpl_da->name);
- XLAT_DEBUG(" ---> %s", str);
+ XLAT_DEBUG("%.*sEXPAND attr %s", lvl, xlat_spaces, node->attr.tmpl_da->name);
+ XLAT_DEBUG("%.*s ---> %s", lvl ,xlat_spaces, str);
}
break;
case XLAT_MODULE:
XLAT_DEBUG("xlat_aprint MODULE");
- if (xlat_process(&child, request, node->child, node->xlat->escape, node->xlat->instance) == 0) {
- return NULL;
+
+ if (node->child) {
+ if (xlat_process(&child, request, node->child, node->xlat->escape, node->xlat->instance) == 0) {
+ return NULL;
+ }
+
+ XLAT_DEBUG("%.*sEXPAND mod %s %s", lvl, xlat_spaces, node->fmt, node->child->fmt);
+ } else {
+ XLAT_DEBUG("%.*sEXPAND mod %s", lvl, xlat_spaces, node->fmt);
+ child = talloc_typed_strdup(ctx, "");
}
- XLAT_DEBUG("%.*sEXPAND mod %s %s", lvl, xlat_spaces, node->fmt, node->child->fmt);
XLAT_DEBUG("%.*s ---> %s", lvl, xlat_spaces, child);
/*
* Smash \n --> CR.
*
- * The OUTPUT of xlat is a printable string. The INPUT might not be...
+ * The OUTPUT of xlat is a "raw" string. The INPUT is a printable string.
*
* This is really the reverse of fr_prints().
*/
type = PW_TYPE_STRING;
slen = value_data_from_str(request, &data, &type, NULL, child, talloc_array_length(child) - 1, '"');
- rad_assert(slen > 0);
+ if (slen <= 0) {
+ talloc_free(child);
+ return NULL;
+ }
talloc_free(child);
child = data.ptr;
#ifdef HAVE_REGEX
case XLAT_REGEX:
- XLAT_DEBUG("xlat_aprint REGEX");
+ XLAT_DEBUG("%.*sxlat_aprint REGEX", lvl, xlat_spaces);
if (regex_request_to_sub(ctx, &str, request, node->attr.tmpl_num) < 0) return NULL;
break;
#endif
case XLAT_ALTERNATE:
- XLAT_DEBUG("xlat_aprint ALTERNATE");
+ XLAT_DEBUG("%.*sxlat_aprint ALTERNATE", lvl, xlat_spaces);
rad_assert(node->child != NULL);
rad_assert(node->alternate != NULL);
- str = xlat_aprint(ctx, request, node->child, escape, escape_ctx, lvl);
- if (str) break;
+ /*
+ * If there are no "next" nodes, call ourselves
+ * recursively, which is fast.
+ *
+ * If there are "next" nodes, call xlat_process()
+ * which does a ton more work.
+ */
+ if (!node->next) {
+ str = xlat_aprint(ctx, request, node->child, escape, escape_ctx, lvl);
+ if (str) {
+ XLAT_DEBUG("%.*sALTERNATE got first string: %s", lvl, xlat_spaces, str);
+ } else {
+ str = xlat_aprint(ctx, request, node->alternate, escape, escape_ctx, lvl);
+ XLAT_DEBUG("%.*sALTERNATE got alternate string %s", lvl, xlat_spaces, str);
+ }
+ } else {
- str = xlat_aprint(ctx, request, node->alternate, escape, escape_ctx, lvl);
+ if (xlat_process(&str, request, node->child, escape, escape_ctx) > 0) {
+ XLAT_DEBUG("%.*sALTERNATE got first string: %s", lvl, xlat_spaces, str);
+ } else {
+ (void) xlat_process(&str, request, node->alternate, escape, escape_ctx);
+ XLAT_DEBUG("%.*sALTERNATE got alternate string %s", lvl, xlat_spaces, str);
+ }
+ }
break;
+ }
+ /*
+ * If there's no data, return that, instead of an empty string.
+ */
+ if (str && !str[0]) {
+ talloc_free(str);
+ return NULL;
}
/*
* Escape the non-literals we found above.
*/
if (str && escape) {
+ size_t len;
char *escaped;
- escaped = talloc_array(ctx, char, 2048); /* FIXME: do something intelligent */
- escape(request, escaped, 2038, str, escape_ctx);
+ len = talloc_array_length(str) * 3;
+
+ escaped = talloc_array(ctx, char, len);
+ escape(request, escaped, len, str, escape_ctx);
talloc_free(str);
str = escaped;
}
static size_t xlat_process(char **out, REQUEST *request, xlat_exp_t const * const head,
- RADIUS_ESCAPE_STRING escape, void *escape_ctx)
+ xlat_escape_t escape, void *escape_ctx)
{
int i, list;
size_t total;
/** Replace %whatever in a string.
*
- * See 'doc/variables.txt' for more information.
+ * See 'doc/configuration/variables.rst' for more information.
*
* @param[out] out Where to write pointer to output buffer.
* @param[in] outlen Size of out.
* @return length of string written @bug should really have -1 for failure
*/
static ssize_t xlat_expand_struct(char **out, size_t outlen, REQUEST *request, xlat_exp_t const *node,
- RADIUS_ESCAPE_STRING escape, void *escape_ctx)
+ xlat_escape_t escape, void *escape_ctx)
{
char *buff;
ssize_t len;
return len;
}
+ len = strlen(buff);
+
+ /*
+ * If out doesn't point to an existing buffer
+ * copy the pointer to our buffer over.
+ */
if (!*out) {
*out = buff;
- } else {
- strlcpy(*out, buff, outlen);
- talloc_free(buff);
+ return len;
}
- return strlen(*out);
+ /*
+ * Otherwise copy the malloced buffer to the fixed one.
+ */
+ strlcpy(*out, buff, outlen);
+ talloc_free(buff);
+ return len;
}
static ssize_t xlat_expand(char **out, size_t outlen, REQUEST *request, char const *fmt,
- RADIUS_ESCAPE_STRING escape, void *escape_ctx) CC_HINT(nonnull (1, 3, 4));
+ xlat_escape_t escape, void *escape_ctx) CC_HINT(nonnull (1, 3, 4));
/** Replace %whatever in a string.
*
- * See 'doc/variables.txt' for more information.
+ * See 'doc/configuration/variables.rst' for more information.
*
* @param[out] out Where to write pointer to output buffer.
* @param[in] outlen Size of out.
* @return length of string written @bug should really have -1 for failure
*/
static ssize_t xlat_expand(char **out, size_t outlen, REQUEST *request, char const *fmt,
- RADIUS_ESCAPE_STRING escape, void *escape_ctx)
+ xlat_escape_t escape, void *escape_ctx)
{
ssize_t len;
xlat_exp_t *node;
/** Try to convert an xlat to a tmpl for efficiency
*
- * @param ctx to allocate new value_pair_tmpl_t in.
+ * @param ctx to allocate new vp_tmpl_t in.
* @param node to convert.
- * @return NULL if unable to convert (not necessarily error), or a new value_pair_tmpl_t.
+ * @return NULL if unable to convert (not necessarily error), or a new vp_tmpl_t.
*/
-value_pair_tmpl_t *xlat_to_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_t *node)
+vp_tmpl_t *xlat_to_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_t *node)
{
- value_pair_tmpl_t *vpt;
+ vp_tmpl_t *vpt;
- if (node->next || (node->type != XLAT_ATTRIBUTE)) return NULL;
+ if (node->next || (node->type != XLAT_ATTRIBUTE) || (node->attr.type != TMPL_TYPE_ATTR)) return NULL;
/*
* Concat means something completely different as an attribute reference
*
* @param ctx to allocate new xlat_expt_t in.
* @param vpt to convert.
- * @return NULL if unable to convert (not necessarily error), or a new value_pair_tmpl_t.
+ * @return NULL if unable to convert (not necessarily error), or a new vp_tmpl_t.
*/
-xlat_exp_t *xlat_from_tmpl_attr(TALLOC_CTX *ctx, value_pair_tmpl_t *vpt)
+xlat_exp_t *xlat_from_tmpl_attr(TALLOC_CTX *ctx, vp_tmpl_t *vpt)
{
xlat_exp_t *node;
if (vpt->type != TMPL_TYPE_ATTR) return NULL;
node = talloc_zero(ctx, xlat_exp_t);
- node->fmt = talloc_memdup(node, vpt->name, vpt->len);
+ node->type = XLAT_ATTRIBUTE;
+ node->fmt = talloc_bstrndup(node, vpt->name, vpt->len);
tmpl_init(&node->attr, TMPL_TYPE_ATTR, node->fmt, talloc_array_length(node->fmt) - 1);
memcpy(&node->attr.data, &vpt->data, sizeof(vpt->data));
return node;
}
-ssize_t radius_xlat(char *out, size_t outlen, REQUEST *request, char const *fmt, RADIUS_ESCAPE_STRING escape, void *ctx)
+ssize_t radius_xlat(char *out, size_t outlen, REQUEST *request, char const *fmt, xlat_escape_t escape, void *ctx)
{
return xlat_expand(&out, outlen, request, fmt, escape, ctx);
}
-ssize_t radius_axlat(char **out, REQUEST *request, char const *fmt, RADIUS_ESCAPE_STRING escape, void *ctx)
+ssize_t radius_xlat_struct(char *out, size_t outlen, REQUEST *request, xlat_exp_t const *xlat, xlat_escape_t escape, void *ctx)
{
+ return xlat_expand_struct(&out, outlen, request, xlat, escape, ctx);
+}
+
+ssize_t radius_axlat(char **out, REQUEST *request, char const *fmt, xlat_escape_t escape, void *ctx)
+{
+ *out = NULL;
return xlat_expand(out, 0, request, fmt, escape, ctx);
}
-ssize_t radius_axlat_struct(char **out, REQUEST *request, xlat_exp_t const *xlat, RADIUS_ESCAPE_STRING escape, void *ctx)
+ssize_t radius_axlat_struct(char **out, REQUEST *request, xlat_exp_t const *xlat, xlat_escape_t escape, void *ctx)
{
+ *out = NULL;
return xlat_expand_struct(out, 0, request, xlat, escape, ctx);
}