Print out TAG_ANY attributes correctly
[freeradius.git] / src / lib / print.c
1 /*
2  * print.c      Routines to print stuff.
3  *
4  * Version:     $Id$
5  *
6  *   This library is free software; you can redistribute it and/or
7  *   modify it under the terms of the GNU Lesser General Public
8  *   License as published by the Free Software Foundation; either
9  *   version 2.1 of the License, or (at your option) any later version.
10  *
11  *   This library is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  *   Lesser General Public License for more details.
15  *
16  *   You should have received a copy of the GNU Lesser General Public
17  *   License along with this library; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000,2006  The FreeRADIUS server project
21  */
22
23 RCSID("$Id$")
24
25 #include        <freeradius-devel/libradius.h>
26
27 #include        <ctype.h>
28
29 /*
30  *      Checks for utf-8, taken from:
31  *
32  *  http://www.w3.org/International/questions/qa-forms-utf-8
33  *
34  *      Note that we don't care about the length of the input string,
35  *      because '\0' is an invalid UTF-8 character.
36  */
37 int fr_utf8_char(uint8_t const *str)
38 {
39         if (*str < 0x20) return 0;
40
41         if (*str <= 0x7e) return 1; /* 1 */
42
43         if (*str <= 0xc1) return 0;
44
45         if ((str[0] >= 0xc2) && /* 2 */
46             (str[0] <= 0xdf) &&
47             (str[1] >= 0x80) &&
48             (str[1] <= 0xbf)) {
49                 return 2;
50         }
51
52         if ((str[0] == 0xe0) && /* 3 */
53             (str[1] >= 0xa0) &&
54             (str[1] <= 0xbf) &&
55             (str[2] >= 0x80) &&
56             (str[2] <= 0xbf)) {
57                 return 3;
58         }
59
60         if ((str[0] >= 0xe1) && /* 4a */
61             (str[0] <= 0xec) &&
62             (str[1] >= 0x80) &&
63             (str[1] <= 0xbf) &&
64             (str[2] >= 0x80) &&
65             (str[2] <= 0xbf)) {
66                 return 3;
67         }
68
69         if ((str[0] >= 0xee) && /* 4b */
70             (str[0] <= 0xef) &&
71             (str[1] >= 0x80) &&
72             (str[1] <= 0xbf) &&
73             (str[2] >= 0x80) &&
74             (str[2] <= 0xbf)) {
75                 return 3;
76         }
77
78         if ((str[0] == 0xed) && /* 5 */
79             (str[1] >= 0x80) &&
80             (str[1] <= 0x9f) &&
81             (str[2] >= 0x80) &&
82             (str[2] <= 0xbf)) {
83                 return 3;
84         }
85
86         if ((str[0] == 0xf0) && /* 6 */
87             (str[1] >= 0x90) &&
88             (str[1] <= 0xbf) &&
89             (str[2] >= 0x80) &&
90             (str[2] <= 0xbf) &&
91             (str[3] >= 0x80) &&
92             (str[3] <= 0xbf)) {
93                 return 4;
94         }
95
96         if ((str[0] >= 0xf1) && /* 6 */
97             (str[1] <= 0xf3) &&
98             (str[1] >= 0x80) &&
99             (str[1] <= 0xbf) &&
100             (str[2] >= 0x80) &&
101             (str[2] <= 0xbf) &&
102             (str[3] >= 0x80) &&
103             (str[3] <= 0xbf)) {
104                 return 4;
105         }
106
107
108         if ((str[0] == 0xf4) && /* 7 */
109             (str[1] >= 0x80) &&
110             (str[1] <= 0x8f) &&
111             (str[2] >= 0x80) &&
112             (str[2] <= 0xbf) &&
113             (str[3] >= 0x80) &&
114             (str[3] <= 0xbf)) {
115                 return 4;
116         }
117
118         /*
119          *      Invalid UTF-8 Character
120          */
121         return 0;
122 }
123
124 /** Escape any non printable or non-UTF8 characters in the input string
125  *
126  * @param[in] in string to escape.
127  * @param[in] inlen length of string to escape (lets us deal with embedded NULLs)
128  * @param[out] out where to write the escaped string.
129  * @param[out] outlen the length of the buffer pointed to by out.
130  * @return the number of bytes written to the out buffer, or a number > outlen if truncation has occurred.
131  */
132 size_t fr_print_string(char const *in, size_t inlen, char *out, size_t outlen)
133 {
134         uint8_t const   *p = (uint8_t const *) in;
135         int             sp = 0;
136         int             utf8 = 0;
137         size_t          freespace = outlen;
138
139         /* Can't '\0' terminate */
140         if (freespace == 0) {
141                 return inlen;
142         }
143
144         /* No input, so no output... */
145         if (!in) {
146         no_input:
147                 *out = '\0';
148                 return 0;
149         }
150
151         /* Figure out the length of the input string */
152         if (inlen == 0) inlen = strlen(in);
153
154         /* Not enough space to hold one char */
155         if (freespace < 2) {
156                 /* And there's input data... */
157                 if (inlen > 0) {
158                         *out = '\0';
159                         return inlen;
160                 }
161
162                 goto no_input;
163         }
164
165         while (inlen > 0) {
166                 /*
167                  *      Hack: never print trailing zero.
168                  *      Some clients send pings with an off-by-one
169                  *      length (confused with strings in C).
170                  */
171                 if ((inlen == 1) && (*p == '\0')) {
172                         inlen--;
173                         break;
174                 }
175                 switch (*p) {
176                 case '\\':
177                         sp = '\\';
178                         break;
179                 case '\r':
180                         sp = 'r';
181                         break;
182                 case '\n':
183                         sp = 'n';
184                         break;
185                 case '\t':
186                         sp = 't';
187                         break;
188                 case '"':
189                         sp = '"';
190                         break;
191                 default:
192                         sp = '\0';
193                         break;
194                 }
195
196                 if (sp) {
197                         if (freespace < 3) break; /* \ + <c> + \0 */
198                         *out++ = '\\';
199                         *out++ = sp;
200                         freespace -= 2;
201                         p++;
202                         inlen--;
203                         continue;
204                 }
205
206                 utf8 = fr_utf8_char(p);
207                 if (utf8 == 0) {
208                         if (freespace < 5) break; /* \ + <o><o><o> + \0 */
209                         snprintf(out, freespace, "\\%03o", *p);
210                         out += 4;
211                         freespace -= 4;
212                         p++;
213                         inlen--;
214                         continue;
215                 }
216
217                 do {
218                         if (freespace < 2) goto finish; /* <c> + \0 */
219                         *out++ = *p++;
220                         freespace--;
221                         inlen--;
222                 } while (--utf8 > 0);
223         }
224
225 finish:
226         *out = '\0';
227
228         /* Indicate truncation occurred */
229         if (inlen > 0) return outlen + inlen;
230
231         return outlen - freespace;
232 }
233
234 /** Find the length of the buffer required to fully escape a string with fr_print_string
235  *
236  * Were assuming here that's it's cheaper to figure out the length and do one
237  * alloc than repeatedly expand the buffer when we find extra chars which need
238  * to be added.
239  *
240  * @param in string to calculate the escaped length for.
241  * @param inlen length of the input string, if 0 strlen will be used to check the length.
242  * @return the size of buffer required to hold the escaped string excluding the NULL byte.
243  */
244 size_t fr_print_string_len(char const *in, size_t inlen)
245 {
246         uint8_t const   *p = (uint8_t const *) in;
247         size_t          outlen = 0;
248         int             utf8 = 0;
249
250         if (!in) {
251                 return 0;
252         }
253
254         if (inlen == 0) {
255                 inlen = strlen(in);
256         }
257
258         while (inlen > 0) {
259                 /*
260                  *      Hack: never print trailing zero. Some clients send pings
261                  *      with an off-by-one length (confused with strings in C).
262                  */
263                 if ((inlen == 1) && (*p == '\0')) {
264                         inlen--;
265                         break;
266                 }
267
268                 switch (*p) {
269                 case '\\':
270                 case '\r':
271                 case '\n':
272                 case '\t':
273                 case '"':
274                         outlen += 2;
275                         p++;
276                         inlen--;
277                         continue;
278
279                 default:
280                         break;
281                 }
282
283                 utf8 = fr_utf8_char(p);
284                 if (utf8 == 0) {
285                         outlen += 4;
286                         p++;
287                         inlen--;
288                         continue;
289                 }
290
291                 do {
292                         outlen++;
293                         p++;
294                         inlen--;
295                 } while (--utf8 > 0);
296         }
297
298         return outlen;
299 }
300
301 /** Print the value of an attribute to a string
302  *
303  */
304 size_t vp_data_prints_value(char *out, size_t outlen,
305                             DICT_ATTR const *da, value_data_t const *data, size_t data_len, int8_t quote)
306 {
307         DICT_VALUE      *v;
308         char            buf[1024];      /* Interim buffer to use with poorly behaved printing functions */
309         char const      *a = NULL;
310         time_t          t;
311         struct tm       s_tm;
312
313         size_t          len = 0, freespace = outlen;
314
315         if (!data) return 0;
316         if (outlen == 0) return data_len;
317
318         *out = '\0';
319
320         switch (da->type) {
321         case PW_TYPE_STRING:
322                 /* need to copy the escaped value, but quoted */
323                 if (quote > 0) {
324                         if (freespace < 3) {
325                                 return data_len + 2;
326                         }
327
328                         *out++ = (char) quote;
329                         freespace--;
330
331                         len = fr_print_string(data->strvalue, data_len, out, freespace);
332                         /* always terminate the quoted string with another quote */
333                         if (len >= (freespace - 1)) {
334                                 out[outlen - 2] = (char) quote;
335                                 out[outlen - 1] = '\0';
336                                 return len + 2;
337                         }
338                         out += len;
339                         freespace -= len;
340
341                         *out++ = (char) quote;
342                         freespace--;
343                         *out = '\0';
344
345                         return len + 2;
346                 }
347
348                 /* xlat.c - need to copy raw value verbatim */
349                 else if (quote < 0) {
350                         if (outlen > data_len) {
351                                 memcpy(out, data->strvalue, data_len + 1);
352                                 return data_len;
353                         }
354
355                         memcpy(out, data->strvalue, outlen);
356                         out[outlen - 1] = '\0';
357                         return data_len;        /* not a typo */
358                 }
359
360                 return fr_print_string(data->strvalue, data_len, out, outlen);
361
362         case PW_TYPE_INTEGER:
363         case PW_TYPE_BYTE:
364         case PW_TYPE_SHORT:
365                 /* Normal, non-tagged attribute */
366                 if ((v = dict_valbyattr(da->attr, da->vendor, data->integer)) != NULL) {
367                         a = v->name;
368                         len = strlen(a);
369                 } else {
370                         /* should never be truncated */
371                         len = snprintf(buf, sizeof(buf), "%u", data->integer);
372                         a = buf;
373                 }
374                 break;
375
376         case PW_TYPE_INTEGER64:
377                 return snprintf(out, outlen, "%" PRIu64, data->integer64);
378
379         case PW_TYPE_DATE:
380                 t = data->date;
381                 if (quote > 0) {
382                         len = strftime(buf, sizeof(buf) - 1, "%%%b %e %Y %H:%M:%S %Z%%", localtime_r(&t, &s_tm));
383                         buf[0] = (char) quote;
384                         buf[len - 1] = (char) quote;
385                         buf[len] = '\0';
386                 } else {
387                         len = strftime(buf, sizeof(buf), "%b %e %Y %H:%M:%S %Z", localtime_r(&t, &s_tm));
388                 }
389                 a = buf;
390                 break;
391
392         case PW_TYPE_SIGNED: /* Damned code for 1 WiMAX attribute */
393                 len = snprintf(buf, sizeof(buf), "%d", data->sinteger);
394                 a = buf;
395                 break;
396
397         case PW_TYPE_IPV4_ADDR:
398                 a = inet_ntop(AF_INET, &(data->ipaddr), buf, sizeof(buf));
399                 len = strlen(buf);
400                 break;
401
402         case PW_TYPE_ABINARY:
403 #ifdef WITH_ASCEND_BINARY
404                 print_abinary(buf, sizeof(buf), (uint8_t const *) data->filter, len, quote);
405                 a = buf;
406                 len = strlen(buf);
407                 break;
408 #else
409         /* FALL THROUGH */
410 #endif
411         case PW_TYPE_OCTETS:
412         case PW_TYPE_TLV:
413         {
414                 size_t max;
415
416                 /* Return the number of bytes we would have written */
417                 len = (data_len * 2) + 2;
418                 if (freespace <= 1) {
419                         return len;
420                 }
421
422                 *out++ = '0';
423                 freespace--;
424
425                 if (freespace <= 1) {
426                         *out = '\0';
427                         return len;
428                 }
429                 *out++ = 'x';
430                 freespace--;
431
432                 if (freespace <= 2) {
433                         *out = '\0';
434                         return len;
435                 }
436
437                 /* Get maximum number of bytes we can encode given freespace */
438                 max = ((freespace % 2) ? freespace - 1 : freespace - 2) / 2;
439                 fr_bin2hex(out, data->octets, (data_len > max) ? max : data_len);
440         }
441                 return len;
442
443         case PW_TYPE_IFID:
444                 a = ifid_ntoa(buf, sizeof(buf), data->ifid);
445                 len = strlen(buf);
446                 break;
447
448         case PW_TYPE_IPV6_ADDR:
449                 a = inet_ntop(AF_INET6, &data->ipv6addr, buf, sizeof(buf));
450                 len = strlen(buf);
451                 break;
452
453         case PW_TYPE_IPV6_PREFIX:
454         {
455                 struct in6_addr addr;
456
457                 /*
458                  *      Alignment issues.
459                  */
460                 memcpy(&addr, &(data->ipv6prefix[2]), sizeof(addr));
461
462                 a = inet_ntop(AF_INET6, &addr, buf, sizeof(buf));
463                 if (a) {
464                         char *p = buf;
465
466                         len = strlen(buf);
467                         p += len;
468                         len += snprintf(p, sizeof(buf) - len, "/%u", (unsigned int) data->ipv6prefix[1]);
469                 }
470         }
471                 break;
472
473         case PW_TYPE_IPV4_PREFIX:
474         {
475                 struct in_addr addr;
476
477                 /*
478                  *      Alignment issues.
479                  */
480                 memcpy(&addr, &(data->ipv4prefix[2]), sizeof(addr));
481
482                 a = inet_ntop(AF_INET, &addr, buf, sizeof(buf));
483                 if (a) {
484                         char *p = buf;
485
486                         len = strlen(buf);
487                         p += len;
488                         len += snprintf(p, sizeof(buf) - len, "/%u", (unsigned int) (data->ipv4prefix[1] & 0x3f));
489                 }
490         }
491                 break;
492
493         case PW_TYPE_ETHERNET:
494                 return snprintf(out, outlen, "%02x:%02x:%02x:%02x:%02x:%02x",
495                                 data->ether[0], data->ether[1],
496                                 data->ether[2], data->ether[3],
497                                 data->ether[4], data->ether[5]);
498
499         default:
500                 a = "UNKNOWN-TYPE";
501                 len = strlen(a);
502                 break;
503         }
504
505         if (a) strlcpy(out, a, outlen);
506
507         return len;     /* Return the number of bytes we would of written (for truncation detection) */
508 }
509
510 /** Print the value of an attribute to a string
511  *
512  * @param[out] out Where to write the string.
513  * @param[in] outlen Size of outlen (must be at least 3 bytes).
514  * @param[in] vp to print.
515  * @param[in] quote Char to add before and after printed value, if 0 no char will be added, if < 0 raw string will be
516  *      added.
517  * @return the length of data written to out, or a value >= outlen on truncation.
518  */
519 size_t vp_prints_value(char *out, size_t outlen, VALUE_PAIR const *vp, int8_t quote)
520 {
521         return vp_data_prints_value(out, outlen, vp->da, &vp->data, vp->length, quote);
522 }
523
524 char *vp_aprint_type(TALLOC_CTX *ctx, PW_TYPE type)
525 {
526         switch (type) {
527         case PW_TYPE_STRING :
528                 return talloc_typed_strdup(ctx, "_");
529
530         case PW_TYPE_INTEGER64:
531         case PW_TYPE_SIGNED:
532         case PW_TYPE_BYTE:
533         case PW_TYPE_SHORT:
534         case PW_TYPE_INTEGER:
535         case PW_TYPE_DATE :
536                 return talloc_typed_strdup(ctx, "0");
537
538         case PW_TYPE_IPV4_ADDR :
539                 return talloc_typed_strdup(ctx, "?.?.?.?");
540
541         case PW_TYPE_IPV4_PREFIX:
542                 return talloc_typed_strdup(ctx, "?.?.?.?/?");
543
544         case PW_TYPE_IPV6_ADDR:
545                 return talloc_typed_strdup(ctx, "[:?:]");
546
547         case PW_TYPE_IPV6_PREFIX:
548                 return talloc_typed_strdup(ctx, "[:?:]/?");
549
550         case PW_TYPE_OCTETS:
551                 return talloc_typed_strdup(ctx, "??");
552
553         case PW_TYPE_ETHERNET:
554                 return talloc_typed_strdup(ctx, "??:??:??:??:??:??:??:??");
555
556 #ifdef WITH_ASCEND_BINARY
557         case PW_TYPE_ABINARY:
558                 return talloc_typed_strdup(ctx, "??");
559 #endif
560
561         default :
562                 break;
563         }
564
565         return talloc_typed_strdup(ctx, "<UNKNOWN-TYPE>");
566 }
567
568 /**  Prints attribute values escaped suitably for use as JSON values
569  *
570  *  Returns < 0 if the buffer may be (or have been) too small to write the encoded
571  *  JSON value to.
572  *
573  * @param out Where to write the string.
574  * @param outlen Lenth of output buffer.
575  * @param vp to print.
576  * @return the length of data written to out, or a value >= outlen on truncation.
577  */
578 size_t vp_prints_value_json(char *out, size_t outlen, VALUE_PAIR const *vp)
579 {
580         char const      *q;
581         size_t          len, freespace = outlen;
582
583         if (!vp->da->flags.has_tag) {
584                 switch (vp->da->type) {
585                         case PW_TYPE_INTEGER:
586                         case PW_TYPE_BYTE:
587                         case PW_TYPE_SHORT:
588                                 if (vp->da->flags.has_value) break;
589
590                                 return snprintf(out, freespace, "%u", vp->vp_integer);
591
592                         case PW_TYPE_SIGNED:
593                                 return snprintf(out, freespace, "%d", vp->vp_signed);
594
595                         default:
596                                 break;
597                 }
598         }
599
600         /* Indicate truncation */
601         if (freespace < 2) return outlen + 1;
602         *out++ = '"';
603         freespace--;
604
605         switch (vp->da->type) {
606                 case PW_TYPE_STRING:
607                         for (q = vp->vp_strvalue; q < vp->vp_strvalue + vp->length; q++) {
608                                 /* Indicate truncation */
609                                 if (freespace < 3) return outlen + 1;
610
611                                 if (*q == '"') {
612                                         *out++ = '\\';
613                                         *out++ = '"';
614                                         freespace -= 2;
615                                 } else if (*q == '\\') {
616                                         *out++ = '\\';
617                                         *out++ = '\\';
618                                         freespace -= 2;
619                                 } else if (*q == '/') {
620                                         *out++ = '\\';
621                                         *out++ = '/';
622                                         freespace -= 2;
623                                 } else if (*q >= ' ') {
624                                         *out++ = *q;
625                                         freespace--;
626                                 } else {
627                                         *out++ = '\\';
628                                         freespace--;
629
630                                         switch (*q) {
631                                         case '\b':
632                                                 *out++ = 'b';
633                                                 freespace--;
634                                                 break;
635
636                                         case '\f':
637                                                 *out++ = 'f';
638                                                 freespace--;
639                                                 break;
640
641                                         case '\n':
642                                                 *out++ = 'b';
643                                                 freespace--;
644                                                 break;
645
646                                         case '\r':
647                                                 *out++ = 'r';
648                                                 freespace--;
649                                                 break;
650
651                                         case '\t':
652                                                 *out++ = 't';
653                                                 freespace--;
654                                                 break;
655                                         default:
656                                                 len = snprintf(out, freespace, "u%04X", *q);
657                                                 if (is_truncated(len, freespace)) return (outlen - freespace) + len;
658                                                 out += len;
659                                                 freespace -= len;
660                                         }
661                                 }
662                         }
663                         break;
664
665                 default:
666                         len = vp_prints_value(out, freespace, vp, 0);
667                         if (is_truncated(len, freespace)) return (outlen - freespace) + len;
668                         out += len;
669                         freespace -= len;
670                         break;
671         }
672
673         /* Indicate truncation */
674         if (freespace < 2) return outlen + 1;
675         *out++ = '"';
676         freespace--;
677         *out = '\0'; // We don't increment out, because the nul byte should not be included in the length
678
679         return outlen - freespace;
680 }
681
682 /*
683  *  This is a hack, and has to be kept in sync with tokens.h
684  */
685 static char const *vp_tokens[] = {
686   "?",                          /* T_OP_INVALID */
687   "EOL",                        /* T_EOL */
688   "{",
689   "}",
690   "(",
691   ")",
692   ",",
693   ";",
694   "++",
695   "+=",
696   "-=",
697   ":=",
698   "=",
699   "!=",
700   ">=",
701   ">",
702   "<=",
703   "<",
704   "=~",
705   "!~",
706   "=*",
707   "!*",
708   "==",
709   "#",
710   "<BARE-WORD>",
711   "<\"STRING\">",
712   "<'STRING'>",
713   "<`STRING`>"
714 };
715
716 extern int fr_attr_max_tlv;
717 extern int fr_attr_shift[];
718 extern int fr_attr_mask[];
719
720
721 /** Print one attribute and value to a string
722  *
723  * Print a VALUE_PAIR in the format:
724 @verbatim
725         <attribute_name>[:tag] <op> <value>
726 @endverbatim
727  * to a string.
728  *
729  * @param out Where to write the string.
730  * @param outlen Lenth of output buffer.
731  * @param vp to print.
732  * @return the length of data written to out, or a value >= outlen on truncation.
733  */
734 size_t vp_prints(char *out, size_t outlen, VALUE_PAIR const *vp)
735 {
736         char const      *token = NULL;
737         size_t          len, freespace = outlen;
738
739         if (!out) return 0;
740
741         *out = '\0';
742         if (!vp || !vp->da) return 0;
743
744         VERIFY_VP(vp);
745
746         if ((vp->op > T_OP_INVALID) && (vp->op < T_TOKEN_LAST)) {
747                 token = vp_tokens[vp->op];
748         } else {
749                 token = "<INVALID-TOKEN>";
750         }
751
752         if (vp->da->flags.has_tag && (vp->tag != TAG_ANY)) {
753                 len = snprintf(out, freespace, "%s:%d %s ", vp->da->name, vp->tag, token);
754         } else {
755                 len = snprintf(out, freespace, "%s %s ", vp->da->name, token);
756         }
757
758         if (is_truncated(len, freespace)) return len;
759         out += len;
760         freespace -= len;
761
762         len = vp_prints_value(out, freespace, vp, '\'');
763         if (is_truncated(len, freespace)) return (outlen - freespace) + len;
764         freespace -= len;
765
766         return (outlen - freespace);
767 }
768
769 /** Print one attribute and value to FP
770  *
771  * Complete string with '\\t' and '\\n' is written to buffer before printing to
772  * avoid issues when running with multiple threads.
773  *
774  * @param fp to output to.
775  * @param vp to print.
776  */
777 void vp_print(FILE *fp, VALUE_PAIR const *vp)
778 {
779         char    buf[1024];
780         char    *p = buf;
781         size_t  len;
782
783         VERIFY_VP(vp);
784
785         *p++ = '\t';
786         len = vp_prints(p, sizeof(buf) - 1, vp);
787         if (!len) {
788                 return;
789         }
790         p += len;
791
792         /*
793          *      Deal with truncation gracefully
794          */
795         if (((size_t) (p - buf)) >= (sizeof(buf) - 2)) {
796                 p = buf + (sizeof(buf) - 2);
797         }
798
799         *p++ = '\n';
800         *p = '\0';
801
802         fputs(buf, fp);
803 }
804
805
806 /** Print a list of attributes and values
807  *
808  * @param fp to output to.
809  * @param vp to print.
810  */
811 void vp_printlist(FILE *fp, VALUE_PAIR const *vp)
812 {
813         vp_cursor_t cursor;
814         for (vp = fr_cursor_init(&cursor, &vp); vp; vp = fr_cursor_next(&cursor)) {
815                 vp_print(fp, vp);
816         }
817 }
818
819
820 /*
821  *      vp_prints_value for talloc
822  */
823 char *vp_aprint_value(TALLOC_CTX *ctx, VALUE_PAIR const *vp)
824 {
825         char *p;
826
827         switch (vp->da->type) {
828         case PW_TYPE_STRING:
829         {
830                 size_t len, ret;
831
832                 /* Gets us the size of the buffer we need to alloc */
833                 len = fr_print_string_len(vp->vp_strvalue, vp->length);
834                 p = talloc_array(ctx, char, len + 1);   /* +1 for '\0' */
835                 if (!p) return NULL;
836
837                 ret = fr_print_string(vp->vp_strvalue, vp->length, p, len + 1);
838                 if (!fr_assert(ret == len)) {
839                         talloc_free(p);
840                         return NULL;
841                 }
842                 break;
843         }
844
845         case PW_TYPE_BYTE:
846         case PW_TYPE_SHORT:
847         case PW_TYPE_INTEGER:
848                 {
849                         DICT_VALUE *dv;
850
851                         dv = dict_valbyattr(vp->da->attr, vp->da->vendor,
852                                             vp->vp_integer);
853                         if (dv) {
854                                 p = talloc_typed_strdup(ctx, dv->name);
855                         } else {
856                                 p = talloc_typed_asprintf(ctx, "%u", vp->vp_integer);
857                         }
858                 }
859                 break;
860
861         case PW_TYPE_SIGNED:
862                 p = talloc_typed_asprintf(ctx, "%d", vp->vp_signed);
863                 break;
864
865         case PW_TYPE_INTEGER64:
866                 p = talloc_typed_asprintf(ctx, "%" PRIu64 , vp->vp_integer64);
867                 break;
868
869         case PW_TYPE_ETHERNET:
870                 p = talloc_typed_asprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
871                                     vp->vp_ether[0], vp->vp_ether[1],
872                                     vp->vp_ether[2], vp->vp_ether[3],
873                                     vp->vp_ether[4], vp->vp_ether[5]);
874                 break;
875
876         case PW_TYPE_ABINARY:
877 #ifdef WITH_ASCEND_BINARY
878                 p = talloc_array(ctx, char, 128);
879                 if (!p) return NULL;
880                 print_abinary(p, 128, (uint8_t *) &vp->vp_filter, vp->length, 0);
881                 break;
882 #else
883                   /* FALL THROUGH */
884 #endif
885
886         case PW_TYPE_OCTETS:
887                 p = talloc_array(ctx, char, 1 + vp->length * 2);
888                 if (!p) return NULL;
889                 fr_bin2hex(p, vp->vp_octets, vp->length);
890                 break;
891
892         case PW_TYPE_DATE:
893         {
894                 time_t t;
895                 struct tm s_tm;
896
897                 t = vp->vp_date;
898
899                 p = talloc_array(ctx, char, 64);
900                 strftime(p, 64, "%b %e %Y %H:%M:%S %Z",
901                          localtime_r(&t, &s_tm));
902                 break;
903         }
904
905         /*
906          *      We need to use the proper inet_ntop functions for IP
907          *      addresses, else the output might not match output of
908          *      other functions, which makes testing difficult.
909          *
910          *      An example is tunnelled ipv4 in ipv6 addresses.
911          */
912         case PW_TYPE_IPV4_ADDR:
913         case PW_TYPE_IPV4_PREFIX:
914                 {
915                         char buff[INET_ADDRSTRLEN  + 4]; // + /prefix
916
917                         buff[0] = '\0';
918                         vp_prints_value(buff, sizeof(buff), vp, 0);
919
920                         p = talloc_typed_strdup(ctx, buff);
921                 }
922                 break;
923
924         case PW_TYPE_IPV6_ADDR:
925         case PW_TYPE_IPV6_PREFIX:
926                 {
927                         char buff[INET6_ADDRSTRLEN + 4]; // + /prefix
928
929                         buff[0] = '\0';
930                         vp_prints_value(buff, sizeof(buff), vp, 0);
931
932                         p = talloc_typed_strdup(ctx, buff);
933                 }
934                 break;
935
936         case PW_TYPE_IFID:
937                 p = talloc_typed_asprintf(ctx, "%x:%x:%x:%x",
938                                     (vp->vp_ifid[0] << 8) | vp->vp_ifid[1],
939                                     (vp->vp_ifid[2] << 8) | vp->vp_ifid[3],
940                                     (vp->vp_ifid[4] << 8) | vp->vp_ifid[5],
941                                     (vp->vp_ifid[6] << 8) | vp->vp_ifid[7]);
942                 break;
943
944         default:
945                 p = NULL;
946                 break;
947         }
948
949         return p;
950 }
951
952 /** Print one attribute and value to a string
953  *
954  * Print a VALUE_PAIR in the format:
955 @verbatim
956         <attribute_name>[:tag] <op> <value>
957 @endverbatim
958  * to a string.
959  *
960  * @param ctx to allocate string in.
961  * @param vp to print.
962  * @return a talloced buffer with the attribute operator and value.
963  */
964 char *vp_aprint(TALLOC_CTX *ctx, VALUE_PAIR const *vp)
965 {
966         char const      *token = NULL;
967         char            *pair, *value;
968
969         if (!vp || !vp->da) return 0;
970
971         VERIFY_VP(vp);
972
973         if ((vp->op > T_OP_INVALID) && (vp->op < T_TOKEN_LAST)) {
974                 token = vp_tokens[vp->op];
975         } else {
976                 token = "<INVALID-TOKEN>";
977         }
978
979         value = vp_aprint_value(ctx, vp);
980         pair = vp->da->flags.has_tag ?
981                talloc_asprintf(ctx, "%s:%d %s %s", vp->da->name, vp->tag, token, value) :
982                talloc_asprintf(ctx, "%s %s %s", vp->da->name, token, value);
983         talloc_free(value);
984
985         return pair;
986 }
987
988