#include <freeradius-devel/ident.h>
RCSID("$Id$")
#include <freeradius-devel/libradius.h>
#include <ctype.h>
int fr_utf8_char(const uint8_t *str)
{
if (*str < 0x20) return 0;
if (*str <= 0x7e) return 1;
if (*str <= 0xc1) return 0;
if ((str[0] >= 0xc2) &&
(str[0] <= 0xdf) &&
(str[1] >= 0x80) &&
(str[1] <= 0xbf)) {
return 2;
}
if ((str[0] == 0xe0) &&
(str[1] >= 0xa0) &&
(str[1] <= 0xbf) &&
(str[2] >= 0x80) &&
(str[2] <= 0xbf)) {
return 3;
}
if ((str[0] >= 0xe1) &&
(str[0] <= 0xec) &&
(str[1] >= 0x80) &&
(str[1] <= 0xbf) &&
(str[2] >= 0x80) &&
(str[2] <= 0xbf)) {
return 3;
}
if ((str[0] >= 0xee) &&
(str[0] <= 0xef) &&
(str[1] >= 0x80) &&
(str[1] <= 0xbf) &&
(str[2] >= 0x80) &&
(str[2] <= 0xbf)) {
return 3;
}
if ((str[0] == 0xed) &&
(str[1] >= 0x80) &&
(str[1] <= 0x9f) &&
(str[2] >= 0x80) &&
(str[2] <= 0xbf)) {
return 3;
}
if ((str[0] == 0xf0) &&
(str[1] >= 0x90) &&
(str[1] <= 0xbf) &&
(str[2] >= 0x80) &&
(str[2] <= 0xbf) &&
(str[3] >= 0x80) &&
(str[3] <= 0xbf)) {
return 4;
}
if ((str[0] >= 0xf1) &&
(str[1] <= 0xf3) &&
(str[1] >= 0x80) &&
(str[1] <= 0xbf) &&
(str[2] >= 0x80) &&
(str[2] <= 0xbf) &&
(str[3] >= 0x80) &&
(str[3] <= 0xbf)) {
return 4;
}
if ((str[0] == 0xf4) &&
(str[1] >= 0x80) &&
(str[1] <= 0x8f) &&
(str[2] >= 0x80) &&
(str[2] <= 0xbf) &&
(str[3] >= 0x80) &&
(str[3] <= 0xbf)) {
return 4;
}
return 0;
}
void fr_print_string(const char *in, size_t inlen, char *out, size_t outlen)
{
const uint8_t *str = (const uint8_t *) in;
int sp = 0;
int utf8 = 0;
if (inlen == 0) inlen = strlen(in);
while ((inlen > 0) && (outlen > 4)) {
if ((inlen == 1) && (*str == 0)) break;
switch (*str) {
case '\\':
sp = '\\';
break;
case '\r':
sp = 'r';
break;
case '\n':
sp = 'n';
break;
case '\t':
sp = 't';
break;
case '"':
sp = '"';
break;
default:
sp = 0;
break;
}
if (sp) {
*out++ = '\\';
*out++ = sp;
outlen -= 2;
str++;
inlen--;
continue;
}
utf8 = fr_utf8_char(str);
if (!utf8) {
snprintf(out, outlen, "\\%03o", *str);
out += 4;
outlen -= 4;
str++;
inlen--;
continue;
}
do {
*out++ = *str++;
outlen--;
inlen--;
} while (--utf8 > 0);
}
*out = 0;
}
int vp_prints_value(char * out, size_t outlen, VALUE_PAIR *vp, int delimitst)
{
DICT_VALUE *v;
char buf[1024];
const char *a = NULL;
size_t len;
time_t t;
struct tm s_tm;
out[0] = '\0';
if (!vp) return 0;
switch (vp->type) {
case PW_TYPE_STRING:
if ((delimitst == 1) && vp->flags.has_tag) {
buf[0] = '"';
fr_print_string(vp->vp_strvalue,
vp->length, buf + 1, sizeof(buf) - 2);
strcat(buf, "\"");
} else if (delimitst == 1) {
buf[0] = '"';
fr_print_string(vp->vp_strvalue,
vp->length, buf + 1, sizeof(buf) - 2);
strcat(buf, "\"");
} else if (delimitst < 0) {
strlcpy(out, vp->vp_strvalue, outlen);
return strlen(out);
} else {
fr_print_string(vp->vp_strvalue,
vp->length, buf, sizeof(buf));
}
a = buf;
break;
case PW_TYPE_INTEGER:
if ( vp->flags.has_tag ) {
if ((v = dict_valbyattr(vp->attribute, (vp->vp_integer & 0xffffff)))
!= NULL)
a = v->name;
else {
snprintf(buf, sizeof(buf), "%u", (vp->vp_integer & 0xffffff));
a = buf;
}
} else {
case PW_TYPE_BYTE:
case PW_TYPE_SHORT:
if ((v = dict_valbyattr(vp->attribute, vp->vp_integer))
!= NULL)
a = v->name;
else {
snprintf(buf, sizeof(buf), "%u", vp->vp_integer);
a = buf;
}
}
break;
case PW_TYPE_DATE:
t = vp->vp_date;
if (delimitst == 1) {
len = strftime(buf, sizeof(buf), "\"%b %e %Y %H:%M:%S %Z\"",
localtime_r(&t, &s_tm));
} else {
len = strftime(buf, sizeof(buf), "%b %e %Y %H:%M:%S %Z",
localtime_r(&t, &s_tm));
}
if (len > 0) a = buf;
break;
case PW_TYPE_SIGNED:
snprintf(buf, sizeof(buf), "%d", vp->vp_signed);
a = buf;
break;
case PW_TYPE_IPADDR:
a = inet_ntop(AF_INET, &(vp->vp_ipaddr),
buf, sizeof(buf));
break;
case PW_TYPE_ABINARY:
#ifdef ASCEND_BINARY
a = buf;
print_abinary(vp, buf, sizeof(buf));
break;
#else
#endif
case PW_TYPE_OCTETS:
if (outlen <= (2 * (vp->length + 1))) return 0;
strcpy(buf, "0x");
fr_bin2hex(vp->vp_octets, buf + 2, vp->length);
a = buf;
break;
case PW_TYPE_IFID:
a = ifid_ntoa(buf, sizeof(buf), vp->vp_octets);
break;
case PW_TYPE_IPV6ADDR:
a = inet_ntop(AF_INET6,
(const struct in6_addr *) vp->vp_strvalue,
buf, sizeof(buf));
break;
case PW_TYPE_IPV6PREFIX:
{
struct in6_addr addr;
memcpy(&addr, vp->vp_strvalue + 2, sizeof(addr));
a = inet_ntop(AF_INET6, &addr, buf, sizeof(buf));
if (a) {
char *p = buf + strlen(buf);
snprintf(p, buf + sizeof(buf) - p - 1, "/%u",
(unsigned int) vp->vp_octets[1]);
}
}
break;
case PW_TYPE_ETHERNET:
snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
vp->vp_ether[0], vp->vp_ether[1],
vp->vp_ether[2], vp->vp_ether[3],
vp->vp_ether[4], vp->vp_ether[5]);
a = buf;
break;
case PW_TYPE_TLV:
if (outlen <= (2 * (vp->length + 1))) return 0;
strcpy(buf, "0x");
fr_bin2hex(vp->vp_tlv, buf + 2, vp->length);
a = buf;
break;
default:
a = "UNKNOWN-TYPE";
break;
}
if (a != NULL) strlcpy(out, a, outlen);
return strlen(out);
}
static const char *vp_tokens[] = {
"?",
"EOL",
"{",
"}",
"(",
")",
",",
";",
"+=",
"-=",
":=",
"=",
"!=",
">=",
">",
"<=",
"<",
"=~",
"!~",
"=*",
"!*",
"==",
"#",
"<BARE-WORD>",
"<\"STRING\">",
"<'STRING'>",
"<`STRING`>"
};
const char *vp_print_name(char *buffer, size_t bufsize, int attr)
{
int vendor;
size_t len = 0;
if (!buffer) return NULL;
vendor = VENDOR(attr);
if (vendor) {
DICT_VENDOR *v;
v = dict_vendorbyvalue(vendor);
if (v) {
snprintf(buffer, bufsize, "%s-", v->name);
} else {
snprintf(buffer, bufsize, "Vendor-%u-", vendor);
}
len = strlen(buffer);
if (len == bufsize) {
return NULL;
}
}
snprintf(buffer + len, bufsize - len, "Attr-%u", attr & 0xffff);
len += strlen(buffer + len);
if (len == bufsize) {
return NULL;
}
return buffer;
}
int vp_prints(char *out, size_t outlen, VALUE_PAIR *vp)
{
size_t len;
const char *token = NULL;
const char *name;
char namebuf[128];
out[0] = 0;
if (!vp) return 0;
name = vp->name;
len = 0;
if (!name || !*name) {
if (!vp_print_name(namebuf, sizeof(namebuf), vp->attribute)) {
return 0;
}
name = namebuf;
}
if ((vp->operator > T_OP_INVALID) &&
(vp->operator < T_TOKEN_LAST)) {
token = vp_tokens[vp->operator];
} else {
token = "<INVALID-TOKEN>";
}
if( vp->flags.has_tag ) {
snprintf(out, outlen, "%s:%d %s ",
name, vp->flags.tag, token);
len = strlen(out);
vp_prints_value(out + len, outlen - len, vp, 1);
} else {
snprintf(out, outlen, "%s %s ", name, token);
len = strlen(out);
vp_prints_value(out + len, outlen - len, vp, 1);
}
return len + strlen(out + len);
}
void vp_print(FILE *fp, VALUE_PAIR *vp)
{
char buf[1024];
vp_prints(buf, sizeof(buf), vp);
fputs(buf, fp);
}
void vp_printlist(FILE *fp, VALUE_PAIR *vp)
{
for (; vp; vp = vp->next) {
fprintf(fp, "\t");
vp_print(fp, vp);
fprintf(fp, "\n");
}
}