Allow UTF-8 in SQL log
authorAlan T. DeKok <aland@freeradius.org>
Fri, 3 Jul 2009 06:57:38 +0000 (08:57 +0200)
committerAlan T. DeKok <aland@freeradius.org>
Fri, 3 Jul 2009 06:57:38 +0000 (08:57 +0200)
Based on patch from http://github.com/stjaeger/freeradius-server/commit/769d35691ef3adbf4de84602a63a72df00712b2c

raddb/modules/sql_log
src/include/libradius.h
src/lib/print.c
src/modules/rlm_sql_log/rlm_sql_log.c

index 6060d9a..aad8c55 100644 (file)
@@ -24,6 +24,13 @@ sql_log {
        postauth_table = "radpostauth"
        sql_user_name = "%{%{User-Name}:-DEFAULT}"
 
+       #
+       #  Setting this to "yes" will allow UTF-8 characters to be
+       #  written to the log file.  Otherwise, they are escaped
+       #  as being potentially invalid.
+       #
+       utf8 = no
+
        Start = "INSERT INTO ${acct_table} (AcctSessionId, UserName, \
         NASIPAddress, FramedIPAddress, AcctStartTime, AcctStopTime, \
         AcctSessionTime, AcctTerminateCause) VALUES                 \
index 01712ed..1d13e85 100644 (file)
@@ -225,6 +225,7 @@ typedef struct radius_packet {
 /*
  *     Printing functions.
  */
+int            fr_utf8_char(uint8_t *str);
 void           fr_print_string(const char *in, size_t inlen,
                                 char *out, size_t outlen);
 int            vp_prints_value(char *out, size_t outlen,
index 86757bb..871fcb7 100644 (file)
@@ -35,7 +35,7 @@ RCSID("$Id$")
  *     Note that we don't care about the length of the input string,
  *     because '\0' is an invalid UTF-8 character.
  */
-static int utf8_char(uint8_t *str)
+int fr_utf8_char(uint8_t *str)
 {
        if (*str < 0x20) return 0;
 
index 2cabe90..a4ab2b8 100644 (file)
@@ -48,6 +48,7 @@ typedef struct rlm_sql_log_t {
        char            *path;
        char            *postauth_query;
        char            *sql_user_name;
+       int             utf8;   
        char            *allowed_chars;
        CONF_SECTION    *conf_section;
 } rlm_sql_log_t;
@@ -62,6 +63,8 @@ static const CONF_PARSER module_config[] = {
         offsetof(rlm_sql_log_t,postauth_query), NULL, ""},
        {"sql_user_name", PW_TYPE_STRING_PTR,
         offsetof(rlm_sql_log_t,sql_user_name), NULL, ""},
+       {"utf8", PW_TYPE_BOOLEAN,
+         offsetof(rlm_sql_log_t,utf8), NULL, "no"},
        {"safe-characters", PW_TYPE_STRING_PTR,
         offsetof(rlm_sql_log_t,allowed_chars), NULL,
        "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /"},
@@ -194,6 +197,71 @@ static size_t sql_escape_func(char *out, size_t outlen, const char *in)
        return len;
 }
 
+static size_t sql_utf8_escape_func(char *out, size_t outlen, const char *in)
+{
+       int len = 0;
+       int utf8 = 0;
+
+       while (in[0]) {
+               /* 
+                * Skip over UTF8 characters
+                */
+               utf8 = fr_utf8_char((uint8_t *)in);
+               if (utf8) {
+                       if (outlen <= utf8) {
+                               break;
+                       }
+                       while (utf8-- > 0) {
+                               *out = *in;
+                               out++;
+                               in++;
+                               outlen--;
+                               len++;
+                       }
+                       continue;
+               }
+
+               /*
+                *      Non-printable characters get replaced with their
+                *      mime-encoded equivalents.
+                */
+               if ((in[0] < 32) ||
+                   strchr(allowed_chars, *in) == NULL) {
+                       /*
+                        *      Only 3 or less bytes available.
+                        */
+                       if (outlen <= 3) {
+                               break;
+                       }
+
+                       snprintf(out, outlen, "=%02X", (unsigned char) in[0]);
+                       in++;
+                       out += 3;
+                       outlen -= 3;
+                       len += 3;
+                       continue;
+               }
+
+               /*
+                *      Only one byte left.
+                */
+               if (outlen <= 1) {
+                       break;
+               }
+
+               /*
+                *      Allowed character.
+                */
+               *out = *in;
+               out++;
+               in++;
+               outlen--;
+               len++;
+       }
+       *out = '\0';
+       return len;
+}
+
 /*
  *     Add the 'SQL-User-Name' attribute to the packet.
  */
@@ -255,7 +323,8 @@ static int sql_xlat_query(rlm_sql_log_t *inst, REQUEST *request, const char *que
 
        /* Expand variables in the query */
        xlat_query[0] = '\0';
-       radius_xlat(xlat_query, len, query, request, sql_escape_func);
+       radius_xlat(xlat_query, len, query, request,
+                   inst->utf8 ? sql_utf8_escape_func : sql_escape_func);
        if (xlat_query[0] == '\0') {
                radlog_request(L_ERR, 0, request, "Couldn't xlat the query %s",
                       query);