add usec resolution to %S. Fixes #1917
[freeradius.git] / src / main / xlat.c
index 498f6b2..3198728 100644 (file)
@@ -623,6 +623,10 @@ static ssize_t xlat_string(UNUSED void *instance, REQUEST *request,
                len = fr_prints(out, outlen, (char const *) p, vp->vp_length, '"');
                break;
 
+               /*
+                *      Note that "%{string:...}" is NOT binary safe!
+                *      It is explicitly used to get rid of embedded zeros.
+                */
        case PW_TYPE_STRING:
                len = strlcpy(out, vp->vp_strvalue, outlen);
                break;
@@ -653,6 +657,8 @@ static ssize_t xlat_xlat(UNUSED void *instance, REQUEST *request,
 
        if ((radius_get_vp(&vp, request, fmt) < 0) || !vp) goto nothing;
 
+       if (vp->da->type != PW_TYPE_STRING) goto nothing;
+
        return radius_xlat(out, outlen, request, vp->vp_strvalue, NULL, NULL);
 }
 
@@ -1617,10 +1623,10 @@ static void xlat_tokenize_debug(xlat_exp_t const *node, int lvl)
 #endif
 
                case XLAT_ALTERNATE:
-                       DEBUG("%.*sif {", lvl, xlat_tabs);
+                       DEBUG("%.*sXLAT-IF {", lvl, xlat_tabs);
                        xlat_tokenize_debug(node->child, lvl + 1);
                        DEBUG("%.*s}", lvl, xlat_tabs);
-                       DEBUG("%.*selse {", lvl, xlat_tabs);
+                       DEBUG("%.*sXLAT-ELSE {", lvl, xlat_tabs);
                        xlat_tokenize_debug(node->alternate, lvl + 1);
                        DEBUG("%.*s}", lvl, xlat_tabs);
                        break;
@@ -2111,7 +2117,7 @@ static char *xlat_aprint(TALLOC_CTX *ctx, REQUEST *request, xlat_exp_t const * c
                 *      Don't escape this.
                 */
        case XLAT_LITERAL:
-               XLAT_DEBUG("xlat_aprint LITERAL");
+               XLAT_DEBUG("%.*sxlat_aprint LITERAL", lvl, xlat_spaces);
                return talloc_typed_strdup(ctx, node->fmt);
 
                /*
@@ -2123,15 +2129,18 @@ static char *xlat_aprint(TALLOC_CTX *ctx, REQUEST *request, xlat_exp_t const * c
                size_t freespace = 256;
                struct tm ts;
                time_t when;
+               int usec;
 
-               XLAT_DEBUG("xlat_aprint PERCENT");
+               XLAT_DEBUG("%.*sxlat_aprint PERCENT", lvl, xlat_spaces);
 
                str = talloc_array(ctx, char, freespace); /* @todo do better allocation */
                p = node->fmt;
 
                when = request->timestamp;
+               usec = 0;
                if (request->packet) {
                        when = request->packet->timestamp.tv_sec;
+                       usec = request->packet->timestamp.tv_usec;
                }
 
                switch (*p) {
@@ -2188,12 +2197,15 @@ static char *xlat_aprint(TALLOC_CTX *ctx, REQUEST *request, xlat_exp_t const * c
 
                case 'S': /* request timestamp in SQL format*/
                        if (!localtime_r(&when, &ts)) goto error;
-                       strftime(str, freespace, "%Y-%m-%d %H:%M:%S", &ts);
+                       nl = str + strftime(str, freespace, "%Y-%m-%d %H:%M:%S", &ts);
+                       rad_assert(((str + freespace) - nl) >= 8);
+                       snprintf(nl, (str + freespace) - nl, ".%06d",  usec);
                        break;
 
                case 'T': /* request timestamp */
                        if (!localtime_r(&when, &ts)) goto error;
-                       strftime(str, freespace, "%Y-%m-%d-%H.%M.%S.000000", &ts);
+                       strftime(str, freespace, "%Y-%m-%d-%H.%M.%S", &ts);
+                       
                        break;
 
                case 'Y': /* request year */
@@ -2219,15 +2231,15 @@ static char *xlat_aprint(TALLOC_CTX *ctx, REQUEST *request, xlat_exp_t const * c
                break;
 
        case XLAT_ATTRIBUTE:
-               XLAT_DEBUG("xlat_aprint ATTRIBUTE");
+               XLAT_DEBUG("%.*sxlat_aprint ATTRIBUTE", lvl, xlat_spaces);
 
                /*
                 *      Some attributes are virtual <sigh>
                 */
                str = xlat_getvp(ctx, request, &node->attr, escape ? false : true, true);
                if (str) {
-                       XLAT_DEBUG("EXPAND attr %s", node->attr.tmpl_da->name);
-                       XLAT_DEBUG("       ---> %s", str);
+                       XLAT_DEBUG("%.*sEXPAND attr %s", lvl, xlat_spaces, node->attr.tmpl_da->name);
+                       XLAT_DEBUG("%.*s       ---> %s", lvl ,xlat_spaces, str);
                }
                break;
 
@@ -2262,7 +2274,7 @@ static char *xlat_aprint(TALLOC_CTX *ctx, REQUEST *request, xlat_exp_t const * c
                /*
                 *      Smash \n --> CR.
                 *
-                *      The OUTPUT of xlat is a printable string.  The INPUT might not be...
+                *      The OUTPUT of xlat is a "raw" string.  The INPUT is a printable string.
                 *
                 *      This is really the reverse of fr_prints().
                 */
@@ -2321,27 +2333,42 @@ static char *xlat_aprint(TALLOC_CTX *ctx, REQUEST *request, xlat_exp_t const * c
 
 #ifdef HAVE_REGEX
        case XLAT_REGEX:
-               XLAT_DEBUG("xlat_aprint REGEX");
+               XLAT_DEBUG("%.*sxlat_aprint REGEX", lvl, xlat_spaces);
                if (regex_request_to_sub(ctx, &str, request, node->attr.tmpl_num) < 0) return NULL;
 
                break;
 #endif
 
        case XLAT_ALTERNATE:
-               XLAT_DEBUG("xlat_aprint ALTERNATE");
+               XLAT_DEBUG("%.*sxlat_aprint ALTERNATE", lvl, xlat_spaces);
                rad_assert(node->child != NULL);
                rad_assert(node->alternate != NULL);
 
-               str = xlat_aprint(ctx, request, node->child, escape, escape_ctx, lvl);
-               if (str) {
-                       XLAT_DEBUG("ALTERNATE got string: %s", str);
-                       break;
-               }
+               /*
+                *      If there are no "next" nodes, call ourselves
+                *      recursively, which is fast.
+                *
+                *      If there are "next" nodes, call xlat_process()
+                *      which does a ton more work.
+                */
+               if (!node->next) {
+                       str = xlat_aprint(ctx, request, node->child, escape, escape_ctx, lvl);
+                       if (str) {
+                               XLAT_DEBUG("%.*sALTERNATE got first string: %s", lvl, xlat_spaces, str);
+                       } else {
+                               str = xlat_aprint(ctx, request, node->alternate, escape, escape_ctx, lvl);
+                               XLAT_DEBUG("%.*sALTERNATE got alternate string %s", lvl, xlat_spaces, str);
+                       }
+               } else {
 
-               XLAT_DEBUG("ALTERNATE going to alternate");
-               str = xlat_aprint(ctx, request, node->alternate, escape, escape_ctx, lvl);
+                       if (xlat_process(&str, request, node->child, escape, escape_ctx) > 0) {
+                               XLAT_DEBUG("%.*sALTERNATE got first string: %s", lvl, xlat_spaces, str);
+                       } else {
+                               (void) xlat_process(&str, request, node->alternate, escape, escape_ctx);
+                               XLAT_DEBUG("%.*sALTERNATE got alternate string %s", lvl, xlat_spaces, str);
+                       }
+               }
                break;
-
        }
 
        /*
@@ -2356,10 +2383,13 @@ static char *xlat_aprint(TALLOC_CTX *ctx, REQUEST *request, xlat_exp_t const * c
         *      Escape the non-literals we found above.
         */
        if (str && escape) {
+               size_t len;
                char *escaped;
 
-               escaped = talloc_array(ctx, char, 2048); /* FIXME: do something intelligent */
-               escape(request, escaped, 2038, str, escape_ctx);
+               len = talloc_array_length(str) * 3;
+
+               escaped = talloc_array(ctx, char, len);
+               escape(request, escaped, len, str, escape_ctx);
                talloc_free(str);
                str = escaped;
        }
@@ -2604,10 +2634,12 @@ ssize_t radius_xlat_struct(char *out, size_t outlen, REQUEST *request, xlat_exp_
 
 ssize_t radius_axlat(char **out, REQUEST *request, char const *fmt, xlat_escape_t escape, void *ctx)
 {
+       *out = NULL;
        return xlat_expand(out, 0, request, fmt, escape, ctx);
 }
 
 ssize_t radius_axlat_struct(char **out, REQUEST *request, xlat_exp_t const *xlat, xlat_escape_t escape, void *ctx)
 {
+       *out = NULL;
        return xlat_expand_struct(out, 0, request, xlat, escape, ctx);
 }