Delete trailing whitespace.
[freeradius.git] / src / main / xlat.c
index dc85a5b..f2528ed 100644 (file)
  *
  *   You should have received a copy of the GNU General Public License
  *   along with this program; 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
  * Copyright 2000  Alan DeKok <aland@ox.org>
  */
 
-static const char rcsid[] =
-"$Id$";
+#include <freeradius-devel/ident.h>
+RCSID("$Id$")
 
-#include       "autoconf.h"
-#include       "libradius.h"
+#include       <freeradius-devel/radiusd.h>
+#include       <freeradius-devel/rad_assert.h>
 
-#include       <stdio.h>
-#include       <stdlib.h>
-#include       <string.h>
 #include       <ctype.h>
 
-#include       "radiusd.h"
-
-#include       "rad_assert.h"
-
 typedef struct xlat_t {
        char            module[MAX_STRING_LEN];
        int             length;
@@ -50,13 +43,17 @@ static rbtree_t *xlat_root = NULL;
 /*
  *     Define all xlat's in the structure.
  */
-static const char *internal_xlat[] = {"check",
-                                     "request",
-                                     "reply",
-                                     "proxy-request",
-                                     "proxy-reply",
-                                     NULL};
-static int xlat_inst[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };        /* up to 8 for regex */
+static const char * const internal_xlat[] = {"check",
+                                            "request",
+                                            "reply",
+                                            "proxy-request",
+                                            "proxy-reply",
+                                            NULL};
+
+#if REQUEST_MAX_REGEX > 8
+#error Please fix the following line
+#endif
+static const int xlat_inst[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };  /* up to 8 for regex */
 
 
 /*
@@ -68,25 +65,28 @@ static int valuepair2str(char * out,int outlen,VALUE_PAIR * pair,
        char buffer[MAX_STRING_LEN * 4];
 
        if (pair != NULL) {
-               vp_prints_value(buffer, sizeof(buffer), pair, 0);
+               vp_prints_value(buffer, sizeof(buffer), pair, -1);
                return func(out, outlen, buffer);
        }
 
        switch (type) {
        case PW_TYPE_STRING :
-               strNcpy(out,"_",outlen);
+               strlcpy(out,"_",outlen);
                break;
        case PW_TYPE_INTEGER :
-               strNcpy(out,"0",outlen);
+               strlcpy(out,"0",outlen);
                break;
        case PW_TYPE_IPADDR :
-               strNcpy(out,"?.?.?.?",outlen);
+               strlcpy(out,"?.?.?.?",outlen);
+               break;
+       case PW_TYPE_IPV6ADDR :
+               strlcpy(out,":?:",outlen);
                break;
        case PW_TYPE_DATE :
-               strNcpy(out,"0",outlen);
+               strlcpy(out,"0",outlen);
                break;
        default :
-               strNcpy(out,"unknown_type",outlen);
+               strlcpy(out,"unknown_type",outlen);
        }
        return strlen(out);
 }
@@ -137,7 +137,88 @@ static int xlat_packet(void *instance, REQUEST *request,
         *      The "format" string is the attribute name.
         */
        da = dict_attrbyname(fmt);
-       if (!da) return 0;
+       if (!da) {
+               int count;
+               const char *p = strchr(fmt, '[');
+               char buffer[256];
+
+               if (!p) return 0;
+               if (strlen(fmt) > sizeof(buffer)) return 0;
+
+               strlcpy(buffer, fmt, p - fmt + 1);
+
+               da = dict_attrbyname(buffer);
+               if (!da) return 0;
+
+               /*
+                *      %{Attribute-Name[#]} returns the count of
+                *      attributes of that name in the list.
+                */
+               if ((p[1] == '#') && (p[2] == ']')) {
+                       count = 0;
+
+                       for (vp = pairfind(vps, da->attr);
+                            vp != NULL;
+                            vp = pairfind(vp->next, da->attr)) {
+                               count++;
+                       }
+                       snprintf(out, outlen, "%d", count);
+                       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);
+                            vp != NULL;
+                            vp = pairfind(vp->next, da->attr)) {
+                               count = valuepair2str(out, outlen - 1, vp, da->type, func);
+                               rad_assert(count <= outlen);
+                               total += count + 1;
+                               outlen -= (count + 1);
+                               out += count;
+
+                               *(out++) = '\n';
+
+                               if (outlen == 0) break;
+                       }
+
+                       return total;
+               }
+
+               count = atoi(p + 1);
+
+               /*
+                *      Skip the numbers.
+                */
+               p += 1 + strspn(p + 1, "0123456789");
+               if (*p != ']') {
+                       DEBUG2("xlat: Invalid array reference in string at %s %s",
+                              fmt, p);
+                       return 0;
+               }
+
+               /*
+                *      Find the N'th value.
+                */
+               for (vp = pairfind(vps, da->attr);
+                    vp != NULL;
+                    vp = pairfind(vp->next, da->attr)) {
+                       if (count == 0) break;
+                       count--;
+               }
+
+               /*
+                *      Non-existent array reference.
+                */
+               if (!vp) return 0;
+
+               return valuepair2str(out, outlen, vp, da->type, func);
+       }
 
        vp = pairfind(vps, da->attr);
        if (!vp) {
@@ -145,14 +226,19 @@ static int xlat_packet(void *instance, REQUEST *request,
                 *      Some "magic" handlers, which are never in VP's, but
                 *      which are in the packet.
                 *
-                *      FIXME: Add SRC/DST IP address!
+                *      FIXME: We should really do this in a more
+                *      intelligent way...
                 */
                if (packet) {
+                       VALUE_PAIR localvp;
+
+                       localvp.vp_strvalue[0] = 0;
+
                        switch (da->attr) {
                        case PW_PACKET_TYPE:
                        {
                                DICT_VALUE *dval;
-                               
+
                                dval = dict_valbyattr(da->attr, packet->code);
                                if (dval) {
                                        snprintf(out, outlen, "%s", dval->name);
@@ -162,10 +248,87 @@ static int xlat_packet(void *instance, REQUEST *request,
                                return strlen(out);
                        }
                        break;
-                       
+
+                       case PW_CLIENT_IP_ADDRESS: /* the same as below */
+                       case PW_PACKET_SRC_IP_ADDRESS:
+                               if (packet->src_ipaddr.af != AF_INET) {
+                                       return 0;
+                               }
+                               localvp.attribute = da->attr;
+                               localvp.vp_ipaddr = packet->src_ipaddr.ipaddr.ip4addr.s_addr;
+                               break;
+
+                       case PW_PACKET_DST_IP_ADDRESS:
+                               if (packet->dst_ipaddr.af != AF_INET) {
+                                       return 0;
+                               }
+                               localvp.attribute = da->attr;
+                               localvp.vp_ipaddr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr;
+                               break;
+
+                       case PW_PACKET_SRC_PORT:
+                               localvp.attribute = da->attr;
+                               localvp.vp_integer = packet->src_port;
+                               break;
+
+                       case PW_PACKET_DST_PORT:
+                               localvp.attribute = da->attr;
+                               localvp.vp_integer = packet->dst_port;
+                               break;
+
+                       case PW_PACKET_AUTHENTICATION_VECTOR:
+                               localvp.attribute = da->attr;
+                               memcpy(localvp.vp_strvalue, packet->vector,
+                                      sizeof(packet->vector));
+                               localvp.length = sizeof(packet->vector);
+                               break;
+
+                               /*
+                                *      Authorization, accounting, etc.
+                                */
+                       case PW_REQUEST_PROCESSING_STAGE:
+                               if (request->component) {
+                                       strlcpy(out, request->component, outlen);
+                               } else {
+                                       strlcpy(out, "server_core", outlen);
+                               }
+                               return strlen(out);
+
+                       case PW_PACKET_SRC_IPV6_ADDRESS:
+                               if (packet->src_ipaddr.af != AF_INET6) {
+                                       return 0;
+                               }
+                               localvp.attribute = da->attr;
+                               memcpy(localvp.vp_strvalue,
+                                      &packet->src_ipaddr.ipaddr.ip6addr,
+                                      sizeof(packet->src_ipaddr.ipaddr.ip6addr));
+                               break;
+
+                       case PW_PACKET_DST_IPV6_ADDRESS:
+                               if (packet->dst_ipaddr.af != AF_INET6) {
+                                       return 0;
+                               }
+                               localvp.attribute = da->attr;
+                               memcpy(localvp.vp_strvalue,
+                                      &packet->dst_ipaddr.ipaddr.ip6addr,
+                                      sizeof(packet->dst_ipaddr.ipaddr.ip6addr));
+                               break;
+
+                       case PW_SERVER_IDENTITY:
+                               if (!request->listener || !request->listener->identity) return 0;
+
+                               snprintf(out, outlen, "%s", request->listener->identity);
+                               return strlen(out);
+                               break;
+
                        default:
+                               return 0; /* not found */
                                break;
                        }
+
+                       localvp.type = da->type;
+                       return valuepair2str(out, outlen, &localvp,
+                                            da->type, func);
                }
 
                /*
@@ -198,8 +361,8 @@ static int xlat_regex(void *instance, REQUEST *request,
         */
        fmt = fmt;              /* -Wunused */
        func = func;            /* -Wunused FIXME: do escaping? */
-       
-       regex = request_data_get(request, request,
+
+       regex = request_data_reference(request, request,
                                 REQUEST_DATA_REGEX | *(int *)instance);
        if (!regex) return 0;
 
@@ -207,12 +370,12 @@ static int xlat_regex(void *instance, REQUEST *request,
         *      Copy UP TO "freespace" bytes, including
         *      a zero byte.
         */
-       strNcpy(out, regex, outlen);
-       free(regex); /* was strdup'd */
+       strlcpy(out, regex, outlen);
        return strlen(out);
 }
 #endif                         /* HAVE_REGEX_H */
 
+
 /*
  *     Compare two xlat_t structs, based ONLY on the module name.
  */
@@ -231,20 +394,27 @@ static int xlat_cmp(const void *a, const void *b)
 /*
  *     find the appropriate registered xlat function.
  */
-static xlat_t *xlat_find(const char *module)
+static const xlat_t *xlat_find(const char *module)
 {
-       char *p;
        xlat_t my_xlat;
 
-       strNcpy(my_xlat.module, module, sizeof(my_xlat.module));
-
        /*
-        *      We get passed the WHOLE string, and all we want here
-        *      is the first piece.
+        *      Look for dictionary attributes first.
         */
-       p = strchr(my_xlat.module, ':');
-       if (p) *p = '\0';
+       if ((dict_attrbyname(module) != NULL) ||
+           (strchr(module, '[') != NULL)) {
+               static const xlat_t dict_xlat = {
+                       "request",
+                       7,
+                       &xlat_inst[1],
+                       xlat_packet,
+                       TRUE
+               };
+
+               return &dict_xlat;
+       }
 
+       strlcpy(my_xlat.module, module, sizeof(my_xlat.module));
        my_xlat.length = strlen(my_xlat.module);
 
        return rbtree_finddata(xlat_root, &my_xlat);
@@ -297,7 +467,7 @@ int xlat_register(const char *module, RAD_XLAT_FUNC func, void *instance)
                 *      Register xlat's for regexes.
                 */
                buffer[1] = '\0';
-               for (i = 0; i <= 8; i++) {
+               for (i = 0; i <= REQUEST_MAX_REGEX; i++) {
                        buffer[0] = '0' + i;
                        xlat_register(buffer, xlat_regex, &xlat_inst[i]);
                        c = xlat_find(buffer);
@@ -310,7 +480,7 @@ int xlat_register(const char *module, RAD_XLAT_FUNC func, void *instance)
        /*
         *      If it already exists, replace the instance.
         */
-       strNcpy(my_xlat.module, module, sizeof(my_xlat.module));
+       strlcpy(my_xlat.module, module, sizeof(my_xlat.module));
        my_xlat.length = strlen(my_xlat.module);
        c = rbtree_finddata(xlat_root, &my_xlat);
        if (c) {
@@ -331,7 +501,7 @@ int xlat_register(const char *module, RAD_XLAT_FUNC func, void *instance)
        memset(c, 0, sizeof(*c));
 
        c->do_xlat = func;
-       strNcpy(c->module, module, sizeof(c->module));
+       strlcpy(c->module, module, sizeof(c->module));
        c->length = strlen(c->module);
        c->instance = instance;
 
@@ -353,7 +523,9 @@ void xlat_unregister(const char *module, RAD_XLAT_FUNC func)
 
        func = func;            /* -Wunused */
 
-       strNcpy(my_xlat.module, module, sizeof(my_xlat.module));
+       if (!module) return;
+
+       strlcpy(my_xlat.module, module, sizeof(my_xlat.module));
        my_xlat.length = strlen(my_xlat.module);
 
        node = rbtree_find(xlat_root, &my_xlat);
@@ -362,24 +534,37 @@ void xlat_unregister(const char *module, RAD_XLAT_FUNC func)
        rbtree_delete(xlat_root, node);
 }
 
+/*
+ *     De-register all xlat functions,
+ *     used mainly for debugging.
+ */
+void xlat_free(void)
+{
+       rbtree_free(xlat_root);
+}
+
 
 /*
  *     Decode an attribute name into a string.
  */
 static void decode_attribute(const char **from, char **to, int freespace,
-                            int *open, REQUEST *request,
+                            int *open_p, REQUEST *request,
                             RADIUS_ESCAPE_STRING func)
 {
-       char attrname[256];
+       int     do_length = 0;
+       char    xlat_name[128];
+       char    *xlat_string = NULL; /* can be large */
+       int     free_xlat_string = FALSE;
        const char *p;
        char *q, *pa;
-       int stop=0, found=0, retlen=0;
-       int openbraces = *open;
-       xlat_t *c;
+       int found=0, retlen=0;
+       int openbraces = *open_p;
+       const xlat_t *c;
+       int spaces = FALSE;
 
        p = *from;
        q = *to;
-       pa = &attrname[0];
+       pa = &xlat_name[0];
 
        *q = '\0';
 
@@ -390,19 +575,99 @@ static void decode_attribute(const char **from, char **to, int freespace,
        p++;
        openbraces++;
 
+       if (*p == '#') {
+               p++;
+               do_length = 1;
+       }
+
        /*
-        *  Copy over the rest of the string.
+        *      First, copy the xlat key name to one buffer
         */
-       while ((*p) && (!stop)) {
-               switch(*p) {
+       while (*p && (*p != '}') && (*p != ':')) {
+               *pa++ = *p++;
+
+               if (pa >= (xlat_name + sizeof(xlat_name) - 1)) {
                        /*
-                        *  Allow braces inside things, too.
+                        *      Skip to the end of the input
                         */
+                       p += strlen(p);
+                       DEBUG("xlat: Module name is too long in string %%%s",
+                             *from);
+                       goto done;
+               }
+       }
+       *pa = '\0';
+
+       if (!*p) {
+               DEBUG("xlat: Invalid syntax in %s", *from);
+
+               /*
+                *      %{name} is a simple attribute reference,
+                *      or regex reference.
+                */
+       } else if (*p == '}') {
+               openbraces--;
+               rad_assert(openbraces == *open_p);
+
+               p++;
+               xlat_string = xlat_name;
+               goto do_xlat;
+
+       } else if (p[1] == '-') { /* handle ':- */
+               p += 2;
+               xlat_string = xlat_name;
+               goto do_xlat;
+
+       } else {      /* module name, followed by per-module string */
+               int stop = 0;
+               int delimitbrace = *open_p;
+
+               rad_assert(*p == ':');
+               p++;                    /* skip the ':' */
+
+               /*
+                *  If there's a brace immediately following the colon,
+                *  then we've chosen to delimite the per-module string,
+                *  so keep track of that.
+                */
+               if (*p == '{') {
+                       delimitbrace = openbraces;
+                       openbraces++;
+                       p++;
+               }
+
+               xlat_string = rad_malloc(strlen(p) + 1); /* always returns */
+               free_xlat_string = TRUE;
+               pa = xlat_string;
+
+               /*
+                *  Copy over the rest of the string, which is per-module
+                *  data.
+                */
+               while (*p && !stop) {
+                       switch(*p) {
+
+                               /*
+                                *      What the heck is this supposed
+                                *      to be doing?
+                                */
                        case '\\':
                                p++; /* skip it */
                                *pa++ = *p++;
                                break;
 
+                       case ':':
+                               if (!spaces && p[1] == '-') {
+                                       p += 2;
+                                       stop = 1;
+                                       break;
+                               }
+
+                               /*
+                                *      This is pretty hokey...  we
+                                *      should use the functions in
+                                *      util.c
+                                */
                        case '{':
                                openbraces++;
                                *pa++ = *p++;
@@ -410,7 +675,7 @@ static void decode_attribute(const char **from, char **to, int freespace,
 
                        case '}':
                                openbraces--;
-                               if (openbraces == *open) {
+                               if (openbraces == delimitbrace) {
                                        p++;
                                        stop=1;
                                } else {
@@ -418,64 +683,50 @@ static void decode_attribute(const char **from, char **to, int freespace,
                                }
                                break;
 
-                               /*
-                                *  Attr-Name1:-Attr-Name2
-                                *
-                                *  Use Attr-Name1, and if not found,
-                                *  use Attr-Name2.
-                                */
-                       case ':':
-                               if (p[1] == '-') {
-                                       p += 2;
-                                       stop = 1;
-                                       break;
-                               }
-                               /* else FALL-THROUGH */
+                       case ' ':
+                       case '\t':
+                               spaces = TRUE;
+                               /* FALL-THROUGH */
 
                        default:
                                *pa++ = *p++;
                                break;
+                       }
                }
-       }
-       *pa = '\0';
 
-       /*
-        *      Look up almost everything in the new tree of xlat
-        *      functions.  this makes it a little quicker...
-        */
-       if ((c = xlat_find(attrname)) != NULL) {
-               if (!c->internal) DEBUG("radius_xlat: Running registered xlat function of module %s for string \'%s\'",
-                                       c->module, attrname+ c->length + 1);
-               retlen = c->do_xlat(c->instance, request, attrname+(c->length+1), q, freespace, func);
-               /* If retlen is 0, treat it as not found */
-               if (retlen == 0) {
-                       found = 0;
-               } else {
-                       found = 1;
-                       q += retlen;
-               }
+               *pa = '\0';
 
                /*
-                *      Not in the default xlat database.  Must be
-                *      a bare attribute number.
+                *      Now check to see if we're at the end of the string
+                *      we were sent.  If we're not, check for :-
                 */
-       } else if ((retlen = xlat_packet(&xlat_inst[1], request, attrname,
-                                        q, freespace, func)) > 0) {
-               found = 1;
-               q += retlen;
+               if (openbraces == delimitbrace) {
+                       if (p[0] == ':' && p[1] == '-') {
+                               p += 2;
+                       }
+               }
 
                /*
-                *      Look up the name, in order to get the correct
-                *      debug message.
+                *      Look up almost everything in the new tree of xlat
+                *      functions.  This makes it a little quicker...
                 */
+       do_xlat:
+               if ((c = xlat_find(xlat_name)) != NULL) {
+                       if (!c->internal) DEBUG("radius_xlat: Running registered xlat function of module %s for string \'%s\'",
+                                               c->module, xlat_string);
+                       retlen = c->do_xlat(c->instance, request, xlat_string,
+                                           q, freespace, func);
+                       /* If retlen is 0, treat it as not found */
+                       if (retlen > 0) found = 1;
 #ifndef NDEBUG
-       } else if (dict_attrbyname(attrname) == NULL) {
-               /*
-                *      No attribute by that name, return an error.
-                */
-               DEBUG2("WARNING: Attempt to use unknown xlat function, or non-existent attribute in string %%{%s}", attrname);
+               } else {
+                       /*
+                        *      No attribute by that name, return an error.
+                        */
+                       DEBUG2("WARNING: Unknown module \"%s\" in string expansion \"%%%s\"", xlat_name, *from);
 #endif
-       } /* else the attribute is known, but not in the request */
+               }
+       }
 
        /*
         * Skip to last '}' if attr is found
@@ -483,7 +734,14 @@ static void decode_attribute(const char **from, char **to, int freespace,
         * useless if we found what we need
         */
        if (found) {
-               while((*p != '\0') && (openbraces > 0)) {
+               if (do_length) {
+                       snprintf(q, freespace, "%d", retlen);
+                       retlen = strlen(q);
+               }
+
+               q += retlen;
+
+               while((*p != '\0') && (openbraces > *open_p)) {
                        /*
                         *      Handle escapes outside of the loop.
                         */
@@ -513,7 +771,10 @@ static void decode_attribute(const char **from, char **to, int freespace,
                }
        }
 
-       *open = openbraces;
+       done:
+       if (free_xlat_string) free(xlat_string);
+
+       *open_p = openbraces;
        *from = p;
        *to = q;
 }
@@ -525,30 +786,23 @@ static void decode_attribute(const char **from, char **to, int freespace,
  */
 static int xlat_copy(char *out, int outlen, const char *in)
 {
-       int len = 0;
+       int freespace = outlen;
 
-       while (*in) {
-               /*
-                *  Truncate, if too much.
-                */
-               if (len >= outlen) {
-                       break;
-               }
+       rad_assert(outlen > 0);
 
+       while ((*in) && (freespace > 1)) {
                /*
                 *  Copy data.
                 *
                 *  FIXME: Do escaping of bad stuff!
                 */
-               *out = *in;
+               *(out++) = *(in++);
 
-               out++;
-               in++;
-               len++;
+               freespace--;
        }
-
        *out = '\0';
-       return len;
+
+       return (outlen - freespace); /* count does not include NUL */
 }
 
 /*
@@ -559,9 +813,10 @@ static int xlat_copy(char *out, int outlen, const char *in)
 int radius_xlat(char *out, int outlen, const char *fmt,
                REQUEST *request, RADIUS_ESCAPE_STRING func)
 {
-       int i, c,freespace;
+       int c, len, freespace;
        const char *p;
        char *q;
+       char *nl;
        VALUE_PAIR *tmp;
        struct tm *TM, s_TM;
        char tmpdt[40]; /* For temporary storing of dates */
@@ -579,7 +834,7 @@ int radius_xlat(char *out, int outlen, const char *fmt,
                func = xlat_copy;
        }
 
-       q = out;
+               q = out;
        p = fmt;
        while (*p) {
                /* Calculate freespace in output */
@@ -664,9 +919,11 @@ int radius_xlat(char *out, int outlen, const char *fmt,
                                break;
                        case 'd': /* request day */
                                TM = localtime_r(&request->timestamp, &s_TM);
-                               strftime(tmpdt,sizeof(tmpdt),"%d",TM);
-                               strNcpy(q,tmpdt,freespace);
-                               q += strlen(q);
+                               len = strftime(tmpdt, sizeof(tmpdt), "%d", TM);
+                               if (len > 0) {
+                                       strlcpy(q, tmpdt, freespace);
+                                       q += strlen(q);
+                               }
                                p++;
                                break;
                        case 'f': /* Framed IP address */
@@ -679,16 +936,18 @@ int radius_xlat(char *out, int outlen, const char *fmt,
                                break;
                        case 'l': /* request timestamp */
                                snprintf(tmpdt, sizeof(tmpdt), "%lu",
-                                        (unsigned long) request->timestamp);
-                               strNcpy(q,tmpdt,freespace);
+                                        (unsigned long) request->received.tv_sec);
+                               strlcpy(q,tmpdt,freespace);
                                q += strlen(q);
                                p++;
                                break;
                        case 'm': /* request month */
                                TM = localtime_r(&request->timestamp, &s_TM);
-                               strftime(tmpdt,sizeof(tmpdt),"%m",TM);
-                               strNcpy(q,tmpdt,freespace);
-                               q += strlen(q);
+                               len = strftime(tmpdt, sizeof(tmpdt), "%m", TM);
+                               if (len > 0) {
+                                       strlcpy(q, tmpdt, freespace);
+                                       q += strlen(q);
+                               }
                                p++;
                                break;
                        case 'n': /* NAS IP address */
@@ -704,7 +963,10 @@ int radius_xlat(char *out, int outlen, const char *fmt,
                                p++;
                                break;
                        case 't': /* request timestamp */
-                               CTIME_R(&request->timestamp, q, freespace);
+                               CTIME_R(&request->timestamp, tmpdt, sizeof(tmpdt));
+                               nl = strchr(tmpdt, '\n');
+                               if (nl) *nl = '\0';
+                               strlcpy(q, tmpdt, freespace);
                                q += strlen(q);
                                p++;
                                break;
@@ -713,31 +975,35 @@ int radius_xlat(char *out, int outlen, const char *fmt,
                                p++;
                                break;
                        case 'A': /* radacct_dir */
-                               strNcpy(q,radacct_dir,freespace-1);
+                               strlcpy(q,radacct_dir,freespace);
                                q += strlen(q);
                                p++;
                                break;
                        case 'C': /* ClientName */
-                               strNcpy(q,client_name(request->packet->src_ipaddr),freespace-1);
+                               strlcpy(q,client_name_old(&request->packet->src_ipaddr),freespace);
                                q += strlen(q);
                                p++;
                                break;
                        case 'D': /* request date */
                                TM = localtime_r(&request->timestamp, &s_TM);
-                               strftime(tmpdt,sizeof(tmpdt),"%Y%m%d",TM);
-                               strNcpy(q,tmpdt,freespace);
-                               q += strlen(q);
+                               len = strftime(tmpdt, sizeof(tmpdt), "%Y%m%d", TM);
+                               if (len > 0) {
+                                       strlcpy(q, tmpdt, freespace);
+                                       q += strlen(q);
+                               }
                                p++;
                                break;
                        case 'H': /* request hour */
                                TM = localtime_r(&request->timestamp, &s_TM);
-                               strftime(tmpdt,sizeof(tmpdt),"%H",TM);
-                               strNcpy(q,tmpdt,freespace);
-                               q += strlen(q);
+                               len = strftime(tmpdt, sizeof(tmpdt), "%H", TM);
+                               if (len > 0) {
+                                       strlcpy(q, tmpdt, freespace);
+                                       q += strlen(q);
+                               }
                                p++;
                                break;
                        case 'L': /* radlog_dir */
-                               strNcpy(q,radlog_dir,freespace-1);
+                               strlcpy(q,radlog_dir,freespace);
                                q += strlen(q);
                                p++;
                                break;
@@ -746,22 +1012,26 @@ int radius_xlat(char *out, int outlen, const char *fmt,
                                p++;
                                break;
                        case 'R': /* radius_dir */
-                               strNcpy(q,radius_dir,freespace-1);
+                               strlcpy(q,radius_dir,freespace);
                                q += strlen(q);
                                p++;
                                break;
                        case 'S': /* request timestamp in SQL format*/
                                TM = localtime_r(&request->timestamp, &s_TM);
-                               strftime(tmpdt,sizeof(tmpdt),"%Y-%m-%d %H:%M:%S",TM);
-                               strNcpy(q,tmpdt,freespace);
-                               q += strlen(q);
+                               len = strftime(tmpdt, sizeof(tmpdt), "%Y-%m-%d %H:%M:%S", TM);
+                               if (len > 0) {
+                                       strlcpy(q, tmpdt, freespace);
+                                       q += strlen(q);
+                               }
                                p++;
                                break;
                        case 'T': /* request timestamp */
                                TM = localtime_r(&request->timestamp, &s_TM);
-                               strftime(tmpdt,sizeof(tmpdt),"%Y-%m-%d-%H.%M.%S.000000",TM);
-                               strNcpy(q,tmpdt,freespace);
-                               q += strlen(q);
+                               len = strftime(tmpdt, sizeof(tmpdt), "%Y-%m-%d-%H.%M.%S.000000", TM);
+                               if (len > 0) {
+                                       strlcpy(q, tmpdt, freespace);
+                                       q += strlen(q);
+                               }
                                p++;
                                break;
                        case 'U': /* Stripped User name */
@@ -769,28 +1039,27 @@ int radius_xlat(char *out, int outlen, const char *fmt,
                                p++;
                                break;
                        case 'V': /* Request-Authenticator */
-                               if (request->packet->verified)
-                                       strNcpy(q,"Verified",freespace-1);
-                               else
-                                       strNcpy(q,"None",freespace-1);
+                               strlcpy(q,"Verified",freespace);
                                q += strlen(q);
                                p++;
                                break;
                        case 'Y': /* request year */
                                TM = localtime_r(&request->timestamp, &s_TM);
-                               strftime(tmpdt,sizeof(tmpdt),"%Y",TM);
-                               strNcpy(q,tmpdt,freespace);
-                               q += strlen(q);
+                               len = strftime(tmpdt, sizeof(tmpdt), "%Y", TM);
+                               if (len > 0) {
+                                       strlcpy(q, tmpdt, freespace);
+                                       q += strlen(q);
+                               }
                                p++;
                                break;
                        case 'Z': /* Full request pairs except password */
                                tmp = request->packet->vps;
                                while (tmp && (freespace > 3)) {
-                                       if (tmp->attribute != PW_PASSWORD) {
+                                       if (tmp->attribute != PW_USER_PASSWORD) {
                                                *q++ = '\t';
-                                               i = vp_prints(q,freespace-2,tmp);
-                                               q += i;
-                                               freespace -= (i+2);
+                                               len = vp_prints(q, freespace - 2, tmp);
+                                               q += len;
+                                               freespace -= (len + 2);
                                                *q++ = '\n';
                                        }
                                        tmp = tmp->next;