X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fprint.c;h=2c14c22ed05a09b8398f3a766fe0c311d544886e;hb=94dc4bb60ec649ce899c1d5e32b575d9523a48f2;hp=54959e1927c4a788526fd5149440d73c09c10040;hpb=bf888ac9d9620175e345105b073677112f132735;p=freeradius.git diff --git a/src/lib/print.c b/src/lib/print.c index 54959e1..2c14c22 100644 --- a/src/lib/print.c +++ b/src/lib/print.c @@ -17,44 +17,134 @@ * License along with this library; if not, write to the Free Software * 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 +RCSID("$Id$") -#include "autoconf.h" +#include -#include -#include -#include #include -#include -#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 '\\': @@ -69,25 +159,38 @@ void librad_safeprint(char *in, int inlen, char *out, int outlen) case '\t': sp = 't'; break; + 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; } @@ -97,112 +200,154 @@ void librad_safeprint(char *in, int inlen, char *out, int outlen) * 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]; - 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) { case PW_TYPE_STRING: - /* - * NAS-Port may have multiple integer values? - * This is an internal server extension... - */ - if (vp->attribute == PW_NAS_PORT) - a = (char *)vp->strvalue; - else { - if (delimitst && vp->flags.has_tag) { - /* Tagged attribute: print delimter and ignore tag */ - buf[0] = '"'; - librad_safeprint((char *)(vp->strvalue), - vp->length, buf + 1, sizeof(buf) - 2); - strcat(buf, "\""); - } else if (delimitst) { - /* Non-tagged attribute: print delimter */ - buf[0] = '"'; - librad_safeprint((char *)vp->strvalue, - vp->length, buf + 1, sizeof(buf) - 2); - strcat(buf, "\""); - } else { - /* Non-tagged attribute: no delimiter */ - librad_safeprint((char *)vp->strvalue, - vp->length, buf, sizeof(buf)); - } - a = buf; + if ((delimitst == 1) && vp->flags.has_tag) { + /* Tagged attribute: print delimter and ignore tag */ + buf[0] = '"'; + 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] = '"'; + fr_print_string(vp->vp_strvalue, + vp->length, buf + 1, sizeof(buf) - 2); + strcat(buf, "\""); + + } else if (delimitst < 0) { /* xlat.c */ + strlcpy(out, vp->vp_strvalue, outlen); + return strlen(out); + + } else { + /* Non-tagged attribute: no delimiter */ + fr_print_string(vp->vp_strvalue, + vp->length, buf, sizeof(buf)); } + a = buf; break; 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: - a = ip_ntoa(buf, vp->lvalue); + 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)); - break; + a = buf; + print_abinary(vp, buf, sizeof(buf)); + break; #else /* FALL THROUGH */ #endif case PW_TYPE_OCTETS: - strcpy(buf, "0x"); - a = buf + 2; - for (t = 0; t < vp->length; t++) { - sprintf(a, "%02x", vp->strvalue[t]); - a += 2; - } - a = buf; + 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->strvalue); + a = ifid_ntoa(buf, sizeof(buf), vp->vp_octets); break; case PW_TYPE_IPV6ADDR: - a = ipv6_ntoa(buf, sizeof(buf), vp->strvalue); + a = inet_ntop(AF_INET6, + (const struct in6_addr *) vp->vp_strvalue, + buf, sizeof(buf)); + break; + + case PW_TYPE_IPV6PREFIX: + { + struct in6_addr addr; + + /* + * Alignment issues. + */ + 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 = 0; + a = "UNKNOWN-TYPE"; break; } - strNcpy(out, a?a:"UNKNOWN-TYPE", outlen); + + if (a != NULL) strlcpy(out, a, outlen); return strlen(out); } @@ -211,7 +356,7 @@ int vp_prints_value(char * out, int outlen, VALUE_PAIR *vp, int delimitst) * This is a hack, and has to be kept in sync with tokens.h */ static const char *vp_tokens[] = { - "?", /* T_INVALID */ + "?", /* T_OP_INVALID */ "EOL", /* T_EOL */ "{", "}", @@ -240,23 +385,61 @@ static const char *vp_tokens[] = { "<`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_INVALID) && + if ((vp->operator > T_OP_INVALID) && (vp->operator < T_TOKEN_LAST)) { token = vp_tokens[vp->operator]; } else { @@ -264,22 +447,20 @@ int vp_prints(char *out, int outlen, VALUE_PAIR *vp) } 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); }