*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
- * Copyright 2000 The FreeRADIUS server project
+ * Copyright 2000,2006 The FreeRADIUS server project
*/
-static const char rcsid[] = "$Id$";
+#include <freeradius-devel/ident.h>
+RCSID("$Id$")
-#include "autoconf.h"
+#include <freeradius-devel/libradius.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
#include <ctype.h>
-#include <string.h>
-#include "missing.h"
-#include "libradius.h"
+/*
+ * Checks for utf-8, taken from:
+ *
+ * http://www.w3.org/International/questions/qa-forms-utf-8
+ *
+ * Note that we don't care about the length of the input string,
+ * because '\0' is an invalid UTF-8 character.
+ */
+int fr_utf8_char(const uint8_t *str)
+{
+ if (*str < 0x20) return 0;
+
+ if (*str <= 0x7e) return 1; /* 1 */
+
+ if (*str <= 0xc1) return 0;
+
+ if ((str[0] >= 0xc2) && /* 2 */
+ (str[0] <= 0xdf) &&
+ (str[1] >= 0x80) &&
+ (str[1] <= 0xbf)) {
+ return 2;
+ }
+
+ if ((str[0] == 0xe0) && /* 3 */
+ (str[1] >= 0xa0) &&
+ (str[1] <= 0xbf) &&
+ (str[2] >= 0x80) &&
+ (str[2] <= 0xbf)) {
+ return 3;
+ }
+
+ if ((str[0] >= 0xe1) && /* 4a */
+ (str[0] <= 0xec) &&
+ (str[1] >= 0x80) &&
+ (str[1] <= 0xbf) &&
+ (str[2] >= 0x80) &&
+ (str[2] <= 0xbf)) {
+ return 3;
+ }
+
+ if ((str[0] >= 0xee) && /* 4b */
+ (str[0] <= 0xef) &&
+ (str[1] >= 0x80) &&
+ (str[1] <= 0xbf) &&
+ (str[2] >= 0x80) &&
+ (str[2] <= 0xbf)) {
+ return 3;
+ }
+
+ if ((str[0] == 0xed) && /* 5 */
+ (str[1] >= 0x80) &&
+ (str[1] <= 0x9f) &&
+ (str[2] >= 0x80) &&
+ (str[2] <= 0xbf)) {
+ return 3;
+ }
+
+ if ((str[0] == 0xf0) && /* 6 */
+ (str[1] >= 0x90) &&
+ (str[1] <= 0xbf) &&
+ (str[2] >= 0x80) &&
+ (str[2] <= 0xbf) &&
+ (str[3] >= 0x80) &&
+ (str[3] <= 0xbf)) {
+ return 4;
+ }
+
+ if ((str[0] >= 0xf1) && /* 6 */
+ (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) && /* 7 */
+ (str[1] >= 0x80) &&
+ (str[1] <= 0x8f) &&
+ (str[2] >= 0x80) &&
+ (str[2] <= 0xbf) &&
+ (str[3] >= 0x80) &&
+ (str[3] <= 0xbf)) {
+ return 4;
+ }
+
+ /*
+ * Invalid UTF-8 Character
+ */
+ return 0;
+}
/*
- * Convert a string to something printable.
- * The output string has to be _at least_ 4x the size
- * of the input string!
+ * Convert a string to something printable. The output string
+ * has to be larger than the input string by at least 5 bytes.
+ * If not, the output is silently truncated...
*/
-void librad_safeprint(char *in, int inlen, char *out, int outlen)
+void fr_print_string(const char *in, size_t inlen, char *out, size_t outlen)
{
- unsigned char *str = (unsigned char *)in;
- int done = 0;
+ const uint8_t *str = (const uint8_t *) in;
int sp = 0;
+ int utf8 = 0;
- if (inlen < 0) inlen = strlen(in);
+ if (inlen == 0) inlen = strlen(in);
- while (inlen-- > 0 && (done + 3) < outlen) {
+ /*
+ *
+ */
+ while ((inlen > 0) && (outlen > 4)) {
/*
* Hack: never print trailing zero.
* Some clients send strings with an off-by-one
* length (confused with strings in C).
*/
- if (inlen == 0 && *str == 0)
- break;
-
- sp = 0;
+ if ((inlen == 1) && (*str == 0)) break;
switch (*str) {
case '\\':
sp = '"';
break;
default:
- if (*str < 32 || (*str >= 128)){
- snprintf(out, outlen, "\\%03o", *str);
- done += 4;
- out += 4;
- outlen -= 4;
- } else {
- *out++ = *str;
- outlen--;
- done++;
- }
+ sp = 0;
+ break;
}
+
if (sp) {
*out++ = '\\';
*out++ = sp;
outlen -= 2;
- done += 2;
+ str++;
+ inlen--;
+ continue;
+ }
+
+ utf8 = fr_utf8_char(str);
+ if (!utf8) {
+ snprintf(out, outlen, "\\%03o", *str);
+ out += 4;
+ outlen -= 4;
+ str++;
+ inlen--;
+ continue;
}
- str++;
+
+ do {
+ *out++ = *str++;
+ outlen--;
+ inlen--;
+ } while (--utf8 > 0);
}
*out = 0;
}
* Print one value into a string.
* delimitst will define if strings and dates will be delimited by '"'
*/
-int vp_prints_value(char * out, int outlen, VALUE_PAIR *vp, int delimitst)
+int vp_prints_value(char * out, size_t outlen, VALUE_PAIR *vp, int delimitst)
{
DICT_VALUE *v;
char buf[1024];
- const char *a;
+ const char *a = NULL;
+ size_t len;
time_t t;
struct tm s_tm;
- out[0] = 0;
+ out[0] = '\0';
if (!vp) return 0;
switch (vp->type) {
if ((delimitst == 1) && vp->flags.has_tag) {
/* Tagged attribute: print delimter and ignore tag */
buf[0] = '"';
- librad_safeprint((char *)(vp->vp_strvalue),
+ fr_print_string(vp->vp_strvalue,
vp->length, buf + 1, sizeof(buf) - 2);
strcat(buf, "\"");
} else if (delimitst == 1) {
/* Non-tagged attribute: print delimter */
buf[0] = '"';
- librad_safeprint((char *)vp->vp_strvalue,
+ fr_print_string(vp->vp_strvalue,
vp->length, buf + 1, sizeof(buf) - 2);
strcat(buf, "\"");
- } else if (delimitst < 0) {
- strNcpy(out, vp->vp_strvalue, outlen);
+ } else if (delimitst < 0) { /* xlat.c */
+ strlcpy(out, vp->vp_strvalue, outlen);
return strlen(out);
} else {
/* Non-tagged attribute: no delimiter */
- librad_safeprint((char *)vp->vp_strvalue,
+ fr_print_string(vp->vp_strvalue,
vp->length, buf, sizeof(buf));
}
a = buf;
case PW_TYPE_INTEGER:
if ( vp->flags.has_tag ) {
/* Attribute value has a tag, need to ignore it */
- if ((v = dict_valbyattr(vp->attribute, (vp->lvalue & 0xffffff)))
+ if ((v = dict_valbyattr(vp->attribute, vp->vendor, (vp->vp_integer & 0xffffff)))
!= NULL)
a = v->name;
else {
- snprintf(buf, sizeof(buf), "%u", (vp->lvalue & 0xffffff));
+ snprintf(buf, sizeof(buf), "%u", (vp->vp_integer & 0xffffff));
a = buf;
}
} else {
+ case PW_TYPE_BYTE:
+ case PW_TYPE_SHORT:
/* Normal, non-tagged attribute */
- if ((v = dict_valbyattr(vp->attribute, vp->lvalue))
+ if ((v = dict_valbyattr(vp->attribute, vp->vendor, vp->vp_integer))
!= NULL)
a = v->name;
else {
- snprintf(buf, sizeof(buf), "%u", vp->lvalue);
+ snprintf(buf, sizeof(buf), "%u", vp->vp_integer);
a = buf;
}
}
break;
case PW_TYPE_DATE:
- t = vp->lvalue;
- if (delimitst) {
- strftime(buf, sizeof(buf), "\"%b %e %Y %H:%M:%S %Z\"",
- localtime_r(&t, &s_tm));
+ 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 {
- strftime(buf, sizeof(buf), "%b %e %Y %H:%M:%S %Z",
- localtime_r(&t, &s_tm));
+ 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: /* Damned code for 1 WiMAX attribute */
+ snprintf(buf, sizeof(buf), "%d", vp->vp_signed);
a = buf;
break;
case PW_TYPE_IPADDR:
- if (vp->vp_strvalue[0])
- a = (char *)vp->vp_strvalue;
- else
- a = inet_ntop(AF_INET, &(vp->lvalue),
- buf, sizeof(buf));
+ a = inet_ntop(AF_INET, &(vp->vp_ipaddr),
+ buf, sizeof(buf));
break;
case PW_TYPE_ABINARY:
#ifdef ASCEND_BINARY
a = buf;
- print_abinary(vp, (unsigned char *)buf, sizeof(buf));
+ print_abinary(vp, buf, sizeof(buf));
break;
#else
/* FALL THROUGH */
if (outlen <= (2 * (vp->length + 1))) return 0;
strcpy(buf, "0x");
-
- lrad_bin2hex(vp->vp_strvalue, buf + 2, vp->length);
+
+ fr_bin2hex(vp->vp_octets, buf + 2, vp->length);
a = buf;
break;
case PW_TYPE_IFID:
- a = ifid_ntoa(buf, sizeof(buf), vp->vp_strvalue);
+ a = ifid_ntoa(buf, sizeof(buf), vp->vp_octets);
break;
case PW_TYPE_IPV6ADDR:
a = inet_ntop(AF_INET6, &addr, buf, sizeof(buf));
if (a) {
char *p = buf + strlen(buf);
-
- sprintf(p, "/%u", (unsigned int) vp->vp_strvalue[1]);
+ 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 = 0;
+ a = "UNKNOWN-TYPE";
break;
}
- strNcpy(out, a?a:"UNKNOWN-TYPE", outlen);
+
+ if (a != NULL) strlcpy(out, a, outlen);
return strlen(out);
}
"<`STRING`>"
};
+const char *vp_print_name(char *buffer, size_t bufsize, int attr, int vendor)
+{
+ size_t len = 0;
+
+ if (!buffer) return NULL;
+
+ 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;
+}
+
/*
* Print one attribute and value into a string.
*/
-int vp_prints(char *out, int outlen, VALUE_PAIR *vp)
+int vp_prints(char *out, size_t outlen, VALUE_PAIR *vp)
{
- int len;
+ size_t len;
const char *token = NULL;
+ const char *name;
+ char namebuf[128];
out[0] = 0;
if (!vp) return 0;
- if (strlen(vp->name) + 3 > (size_t)outlen) {
- return 0;
+ name = vp->name;
+
+ if (!name || !*name) {
+ if (!vp_print_name(namebuf, sizeof(namebuf), vp->attribute, vp->attribute)) {
+ return 0;
+ }
+ name = namebuf;
}
if ((vp->operator > T_OP_INVALID) &&
}
if( vp->flags.has_tag ) {
-
- snprintf(out, outlen, "%s:%d %s ", vp->name, vp->flags.tag,
- token);
+ 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 ", vp->name, token);
+ snprintf(out, outlen, "%s %s ", name, token);
len = strlen(out);
vp_prints_value(out + len, outlen - len, vp, 1);
}
- return strlen(out);
+ return len + strlen(out + len);
}