return strlen(out);
}
+static VALUE_PAIR *pairfind_tag(VALUE_PAIR *vps, int attr, int tag)
+{
+ VALUE_PAIR *vp = vps;
+
+redo:
+ if (!vp) return NULL;
+
+ vp = pairfind(vp, attr);
+ if (!tag) return vp;
+
+ if (!vp->flags.has_tag) return NULL;
+
+ if (vp->flags.tag == tag) return vp;
+
+ vp = vp->next;
+ goto redo;
+}
/*
* Dynamically translate for check:, request:, reply:, etc.
da = dict_attrbyname(fmt);
if (!da) {
int do_number = FALSE;
- size_t count;
- const char *p;
+ int do_array = FALSE;
+ int do_count = FALSE;
+ int do_all = FALSE;
+ int tag = 0;
+ size_t count, total;
+ char *p;
char buffer[256];
if (strlen(fmt) > sizeof(buffer)) return 0;
- p = strchr(fmt, '[');
- if (!p) {
- p = strchr(fmt, '#');
- if (!p) return 0;
+ strlcpy(buffer, fmt, sizeof(buffer));
+
+ /*
+ * %{Attribute-name#} - print integer version of it.
+ */
+ p = buffer + strlen(buffer) - 1;
+ if (*p == '#') {
+ *p = '\0';
do_number = TRUE;
}
- strlcpy(buffer, fmt, p - fmt + 1);
+ /*
+ * %{Attribute-Name:tag} - get the name with the specified
+ * value of the tag.
+ */
+ p = strchr(buffer, ':');
+ if (p) {
+ tag = atoi(p + 1);
+ *p = '\0';
+ p++;
- da = dict_attrbyname(buffer);
- if (!da) return 0;
+ } else {
+ /*
+ * Allow %{Attribute-Name:tag[...]}
+ */
+ p = buffer;
+ }
- if (do_number) {
- vp = pairfind(vps, da->attr);
- if (!vp) return 0;
+ /*
+ * %{Attribute-Name[...] does more stuff
+ */
+ p = strchr(p, '[');
+ if (p) {
+ do_array = TRUE;
+ if (p[1] == '#') {
+ do_count = TRUE;
+ } else if (p[1] == '*') {
+ do_all = TRUE;
+ } else {
+ count = atoi(p + 1);
+ p += 1 + strspn(p + 1, "0123456789");
+ if (*p != ']') {
+ RDEBUG2("xlat: Invalid array reference in string at %s %s",
+ fmt, p);
+ return 0;
+ }
+ }
+ *p = '\0';
+ }
- switch (da->type) {
- default:
- break;
+ /*
+ * We COULD argue about %{Attribute-Name[#]#} etc.
+ * But that looks like more work than it's worth.
+ */
- case PW_TYPE_INTEGER:
- case PW_TYPE_DATE:
- case PW_TYPE_SHORT:
- case PW_TYPE_BYTE:
- snprintf(out, outlen, "%u", vp->lvalue);
- return strlen(out);
- }
+ da = dict_attrbyname(buffer);
+ if (!da) return 0;
+ /*
+ * No array, print the tagged attribute.
+ */
+ if (!do_array) {
+ vp = pairfind_tag(vps, da->attr, tag);
goto just_print;
}
+ total = 0;
+
/*
- * %{Attribute-Name[#]} returns the count of
- * attributes of that name in the list.
+ * Array[#] - return the total
*/
- if ((p[1] == '#') && (p[2] == ']')) {
- count = 0;
-
- for (vp = pairfind(vps, da->attr);
+ if (do_count) {
+ for (vp = pairfind_tag(vps, da->attr, tag);
vp != NULL;
- vp = pairfind(vp->next, da->attr)) {
- count++;
+ vp = pairfind_tag(vp->next, da->attr, tag)) {
+ total++;
}
- snprintf(out, outlen, "%d", (int) count);
+
+ snprintf(out, outlen, "%d", (int) total);
return strlen(out);
}
* %{Attribute-Name[*]} returns ALL of the
* the attributes, separated by a newline.
*/
- if ((p[1] == '*') && (p[2] == ']')) {
- int total = 0;
-
- for (vp = pairfind(vps, da->attr);
+ if (do_all) {
+ for (vp = pairfind_tag(vps, da->attr, tag);
vp != NULL;
- vp = pairfind(vp->next, da->attr)) {
+ vp = pairfind_tag(vp->next, da->attr, tag)) {
count = valuepair2str(out, outlen - 1, vp, da->type, func);
rad_assert(count <= outlen);
total += count + 1;
return total;
}
- count = atoi(p + 1);
-
- /*
- * Skip the numbers.
- */
- p += 1 + strspn(p + 1, "0123456789");
- if (*p != ']') {
- RDEBUG2("xlat: Invalid array reference in string at %s %s",
- fmt, p);
- return 0;
- }
-
/*
* Find the N'th value.
*/
- for (vp = pairfind(vps, da->attr);
+ for (vp = pairfind_tag(vps, da->attr, tag);
vp != NULL;
- vp = pairfind(vp->next, da->attr)) {
- if (count == 0) break;
- count--;
+ vp = pairfind_tag(vp->next, da->attr, tag)) {
+ if (total == count) break;
+ total++;
+ if (total > count) {
+ vp = NULL;
+ break;
+ }
}
/*
* Non-existent array reference.
*/
- if (!vp) return 0;
just_print:
+ if (do_number) {
+ if ((vp->type != PW_TYPE_IPADDR) &&
+ (vp->type != PW_TYPE_INTEGER) &&
+ (vp->type != PW_TYPE_SHORT) &&
+ (vp->type != PW_TYPE_BYTE) &&
+ (vp->type != PW_TYPE_DATE)) {
+ *out = '\0';
+ return 0;
+ }
+
+ return snprintf(out, outlen, "%u", vp->vp_integer);
+ }
+
+ if (!vp) return 0;
return valuepair2str(out, outlen, vp, da->type, func);
}
((const xlat_t *)a)->length);
}
+
/*
* find the appropriate registered xlat function.
*/
{
xlat_t my_xlat;
- /*
- * Look for dictionary attributes first.
- */
- if ((dict_attrbyname(module) != NULL) ||
- (strchr(module, '[') != NULL) ||
- (strchr(module, '#') != NULL)) {
- module = "request";
- }
-
strlcpy(my_xlat.module, module, sizeof(my_xlat.module));
my_xlat.length = strlen(my_xlat.module);
RADIUS_ESCAPE_STRING func)
{
int do_length = 0;
- char *xlat_name, *xlat_str;
+ char *module_name, *xlat_str;
char *p, *q, *l, *next = NULL;
int retlen=0;
const xlat_t *c;
/*
* See if we're supposed to expand a module name.
*/
- xlat_name = NULL;
+ module_name = NULL;
for (l = p; *l != '\0'; l++) {
if (*l == '\\') {
l++;
}
if (*l == ':') {
- xlat_name = p; /* start of name */
+ if (isdigit(l[1])) break;
+
+ module_name = p; /* start of name */
*l = '\0';
p = l + 1;
break;
* %{name} is a simple attribute reference,
* or regex reference.
*/
- if (!xlat_name) {
- xlat_name = xlat_str = p;
+ if (!module_name) {
+ if (isdigit(*p)) {
+ module_name = xlat_str = p;
+ } else {
+ module_name = internal_xlat[1];
+ xlat_str = p;
+ }
goto do_xlat;
}
RDEBUG2("WARNING: Deprecated conditional expansion \":-\". See \"man unlang\" for details");
p++;
- xlat_str = xlat_name;
+ xlat_str = module_name;
next = p;
goto do_xlat;
}
xlat_str = p;
do_xlat:
- if ((c = xlat_find(xlat_name)) != NULL) {
- if (!c->internal) RDEBUG3("radius_xlat: Running registered xlat function of module %s for string \'%s\'",
- c->module, xlat_str);
- retlen = c->do_xlat(c->instance, request, xlat_str,
- q, freespace, func);
- if (retlen > 0) {
- if (do_length) {
- snprintf(q, freespace, "%d", retlen);
- retlen = strlen(q);
- }
-
- } else if (next) {
- /*
- * Expand the second bit.
- */
- RDEBUG2("\t... expanding second conditional");
- retlen = radius_xlat(q, freespace, next, request, func);
+ c = xlat_find(module_name);
+ if (!c) {
+ if (module_name == internal_xlat[1]) {
+ RDEBUG2("WARNING: Unknown Attribute \"%s\" in string expansion \"%%%s\"", module_name, *from);
+ } else {
+ RDEBUG2("WARNING: Unknown module \"%s\" in string expansion \"%%%s\"", module_name, *from);
}
- q += retlen;
+ return -1;
+ }
- } else {
+ if (!c->internal) RDEBUG3("radius_xlat: Running registered xlat function of module %s for string \'%s\'",
+ c->module, xlat_str);
+ retlen = c->do_xlat(c->instance, request, xlat_str,
+ q, freespace, func);
+ if (retlen > 0) {
+ if (do_length) {
+ snprintf(q, freespace, "%d", retlen);
+ retlen = strlen(q);
+ }
+
+ } else if (next) {
/*
- * No attribute by that name, return an error.
+ * Expand the second bit.
*/
- RDEBUG2("WARNING: Unknown module \"%s\" in string expansion \"%%%s\"", xlat_name, *from);
- return -1;
+ RDEBUG2("\t... expanding second conditional");
+ retlen = radius_xlat(q, freespace, next, request, func);
}
+ q += retlen;
done:
*to = q;