Call VERIFY_VP from vp_prints_value
[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
180                 case '\r':
181                         sp = 'r';
182                         break;
183
184                 case '\n':
185                         sp = 'n';
186                         break;
187
188                 case '\t':
189                         sp = 't';
190                         break;
191
192                 case '"':
193                         sp = '"';
194                         break;
195
196                 default:
197                         sp = '\0';
198                         break;
199                 }
200
201                 if (sp) {
202                         if (freespace < 3) break; /* \ + <c> + \0 */
203                         *out++ = '\\';
204                         *out++ = sp;
205                         freespace -= 2;
206                         p++;
207                         inlen--;
208                         continue;
209                 }
210
211                 utf8 = fr_utf8_char(p);
212                 if (utf8 == 0) {
213                         if (freespace < 5) break; /* \ + <o><o><o> + \0 */
214                         snprintf(out, freespace, "\\%03o", *p);
215                         out += 4;
216                         freespace -= 4;
217                         p++;
218                         inlen--;
219                         continue;
220                 }
221
222                 do {
223                         if (freespace < 2) goto finish; /* <c> + \0 */
224                         *out++ = *p++;
225                         freespace--;
226                         inlen--;
227                 } while (--utf8 > 0);
228         }
229
230 finish:
231         *out = '\0';
232
233         /* Indicate truncation occurred */
234         if (inlen > 0) return outlen + inlen;
235
236         return outlen - freespace;
237 }
238
239 /** Find the length of the buffer required to fully escape a string with fr_print_string
240  *
241  * Were assuming here that's it's cheaper to figure out the length and do one
242  * alloc than repeatedly expand the buffer when we find extra chars which need
243  * to be added.
244  *
245  * @param in string to calculate the escaped length for.
246  * @param inlen length of the input string, if 0 strlen will be used to check the length.
247  * @return the size of buffer required to hold the escaped string excluding the NULL byte.
248  */
249 size_t fr_print_string_len(char const *in, size_t inlen)
250 {
251         uint8_t const   *p = (uint8_t const *) in;
252         size_t          outlen = 0;
253         int             utf8 = 0;
254
255         if (!in) {
256                 return 0;
257         }
258
259         if (inlen == 0) {
260                 inlen = strlen(in);
261         }
262
263         while (inlen > 0) {
264                 /*
265                  *      Hack: never print trailing zero. Some clients send pings
266                  *      with an off-by-one length (confused with strings in C).
267                  */
268                 if ((inlen == 1) && (*p == '\0')) {
269                         inlen--;
270                         break;
271                 }
272
273                 switch (*p) {
274                 case '\\':
275                 case '\r':
276                 case '\n':
277                 case '\t':
278                 case '"':
279                         outlen += 2;
280                         p++;
281                         inlen--;
282                         continue;
283
284                 default:
285                         break;
286                 }
287
288                 utf8 = fr_utf8_char(p);
289                 if (utf8 == 0) {
290                         outlen += 4;
291                         p++;
292                         inlen--;
293                         continue;
294                 }
295
296                 do {
297                         outlen++;
298                         p++;
299                         inlen--;
300                 } while (--utf8 > 0);
301         }
302
303         return outlen;
304 }
305
306 /** Print the value of an attribute to a string
307  *
308  */
309 size_t vp_data_prints_value(char *out, size_t outlen,
310                             DICT_ATTR const *da, value_data_t const *data, size_t data_len, int8_t quote)
311 {
312         DICT_VALUE      *v;
313         char            buf[1024];      /* Interim buffer to use with poorly behaved printing functions */
314         char const      *a = NULL;
315         time_t          t;
316         struct tm       s_tm;
317
318         size_t          len = 0, freespace = outlen;
319
320         if (!data) return 0;
321         if (outlen == 0) return data_len;
322
323         *out = '\0';
324
325         switch (da->type) {
326         case PW_TYPE_STRING:
327                 /* need to copy the escaped value, but quoted */
328                 if (quote > 0) {
329                         if (freespace < 3) {
330                                 return data_len + 2;
331                         }
332
333                         *out++ = (char) quote;
334                         freespace--;
335
336                         len = fr_print_string(data->strvalue, data_len, out, freespace);
337                         /* always terminate the quoted string with another quote */
338                         if (len >= (freespace - 1)) {
339                                 out[outlen - 2] = (char) quote;
340                                 out[outlen - 1] = '\0';
341                                 return len + 2;
342                         }
343                         out += len;
344                         freespace -= len;
345
346                         *out++ = (char) quote;
347                         freespace--;
348                         *out = '\0';
349
350                         return len + 2;
351                 }
352
353                 /* xlat.c - need to copy raw value verbatim */
354                 else if (quote < 0) {
355                         if (outlen > data_len) {
356                                 memcpy(out, data->strvalue, data_len + 1);
357                                 return data_len;
358                         }
359
360                         memcpy(out, data->strvalue, outlen);
361                         out[outlen - 1] = '\0';
362                         return data_len;        /* not a typo */
363                 }
364
365                 return fr_print_string(data->strvalue, data_len, out, outlen);
366
367         case PW_TYPE_INTEGER:
368         case PW_TYPE_BYTE:
369         case PW_TYPE_SHORT:
370                 /* Normal, non-tagged attribute */
371                 if ((v = dict_valbyattr(da->attr, da->vendor, data->integer)) != NULL) {
372                         a = v->name;
373                         len = strlen(a);
374                 } else {
375                         /* should never be truncated */
376                         len = snprintf(buf, sizeof(buf), "%u", data->integer);
377                         a = buf;
378                 }
379                 break;
380
381         case PW_TYPE_INTEGER64:
382                 return snprintf(out, outlen, "%" PRIu64, data->integer64);
383
384         case PW_TYPE_DATE:
385                 t = data->date;
386                 if (quote > 0) {
387                         len = strftime(buf, sizeof(buf) - 1, "%%%b %e %Y %H:%M:%S %Z%%", localtime_r(&t, &s_tm));
388                         buf[0] = (char) quote;
389                         buf[len - 1] = (char) quote;
390                         buf[len] = '\0';
391                 } else {
392                         len = strftime(buf, sizeof(buf), "%b %e %Y %H:%M:%S %Z", localtime_r(&t, &s_tm));
393                 }
394                 a = buf;
395                 break;
396
397         case PW_TYPE_SIGNED: /* Damned code for 1 WiMAX attribute */
398                 len = snprintf(buf, sizeof(buf), "%d", data->sinteger);
399                 a = buf;
400                 break;
401
402         case PW_TYPE_IPV4_ADDR:
403                 a = inet_ntop(AF_INET, &(data->ipaddr), buf, sizeof(buf));
404                 len = strlen(buf);
405                 break;
406
407         case PW_TYPE_ABINARY:
408 #ifdef WITH_ASCEND_BINARY
409                 print_abinary(buf, sizeof(buf), (uint8_t const *) data->filter, len, quote);
410                 a = buf;
411                 len = strlen(buf);
412                 break;
413 #else
414         /* FALL THROUGH */
415 #endif
416         case PW_TYPE_OCTETS:
417         case PW_TYPE_TLV:
418         {
419                 size_t max;
420
421                 /* Return the number of bytes we would have written */
422                 len = (data_len * 2) + 2;
423                 if (freespace <= 1) {
424                         return len;
425                 }
426
427                 *out++ = '0';
428                 freespace--;
429
430                 if (freespace <= 1) {
431                         *out = '\0';
432                         return len;
433                 }
434                 *out++ = 'x';
435                 freespace--;
436
437                 if (freespace <= 2) {
438                         *out = '\0';
439                         return len;
440                 }
441
442                 /* Get maximum number of bytes we can encode given freespace */
443                 max = ((freespace % 2) ? freespace - 1 : freespace - 2) / 2;
444                 fr_bin2hex(out, data->octets, (data_len > max) ? max : data_len);
445         }
446                 return len;
447
448         case PW_TYPE_IFID:
449                 a = ifid_ntoa(buf, sizeof(buf), data->ifid);
450                 len = strlen(buf);
451                 break;
452
453         case PW_TYPE_IPV6_ADDR:
454                 a = inet_ntop(AF_INET6, &data->ipv6addr, buf, sizeof(buf));
455                 len = strlen(buf);
456                 break;
457
458         case PW_TYPE_IPV6_PREFIX:
459         {
460                 struct in6_addr addr;
461
462                 /*
463                  *      Alignment issues.
464                  */
465                 memcpy(&addr, &(data->ipv6prefix[2]), sizeof(addr));
466
467                 a = inet_ntop(AF_INET6, &addr, buf, sizeof(buf));
468                 if (a) {
469                         char *p = buf;
470
471                         len = strlen(buf);
472                         p += len;
473                         len += snprintf(p, sizeof(buf) - len, "/%u", (unsigned int) data->ipv6prefix[1]);
474                 }
475         }
476                 break;
477
478         case PW_TYPE_IPV4_PREFIX:
479         {
480                 struct in_addr addr;
481
482                 /*
483                  *      Alignment issues.
484                  */
485                 memcpy(&addr, &(data->ipv4prefix[2]), sizeof(addr));
486
487                 a = inet_ntop(AF_INET, &addr, buf, sizeof(buf));
488                 if (a) {
489                         char *p = buf;
490
491                         len = strlen(buf);
492                         p += len;
493                         len += snprintf(p, sizeof(buf) - len, "/%u", (unsigned int) (data->ipv4prefix[1] & 0x3f));
494                 }
495         }
496                 break;
497
498         case PW_TYPE_ETHERNET:
499                 return snprintf(out, outlen, "%02x:%02x:%02x:%02x:%02x:%02x",
500                                 data->ether[0], data->ether[1],
501                                 data->ether[2], data->ether[3],
502                                 data->ether[4], data->ether[5]);
503
504         default:
505                 a = "UNKNOWN-TYPE";
506                 len = strlen(a);
507                 break;
508         }
509
510         if (a) strlcpy(out, a, outlen);
511
512         return len;     /* Return the number of bytes we would of written (for truncation detection) */
513 }
514
515 /** Print the value of an attribute to a string
516  *
517  * @param[out] out Where to write the string.
518  * @param[in] outlen Size of outlen (must be at least 3 bytes).
519  * @param[in] vp to print.
520  * @param[in] quote Char to add before and after printed value, if 0 no char will be added, if < 0 raw string will be
521  *      added.
522  * @return the length of data written to out, or a value >= outlen on truncation.
523  */
524 size_t vp_prints_value(char *out, size_t outlen, VALUE_PAIR const *vp, int8_t quote)
525 {
526         VERIFY_VP(vp);
527
528         return vp_data_prints_value(out, outlen, vp->da, &vp->data, vp->length, quote);
529 }
530
531 char *vp_aprint_type(TALLOC_CTX *ctx, PW_TYPE type)
532 {
533         switch (type) {
534         case PW_TYPE_STRING :
535                 return talloc_typed_strdup(ctx, "_");
536
537         case PW_TYPE_INTEGER64:
538         case PW_TYPE_SIGNED:
539         case PW_TYPE_BYTE:
540         case PW_TYPE_SHORT:
541         case PW_TYPE_INTEGER:
542         case PW_TYPE_DATE :
543                 return talloc_typed_strdup(ctx, "0");
544
545         case PW_TYPE_IPV4_ADDR :
546                 return talloc_typed_strdup(ctx, "?.?.?.?");
547
548         case PW_TYPE_IPV4_PREFIX:
549                 return talloc_typed_strdup(ctx, "?.?.?.?/?");
550
551         case PW_TYPE_IPV6_ADDR:
552                 return talloc_typed_strdup(ctx, "[:?:]");
553
554         case PW_TYPE_IPV6_PREFIX:
555                 return talloc_typed_strdup(ctx, "[:?:]/?");
556
557         case PW_TYPE_OCTETS:
558                 return talloc_typed_strdup(ctx, "??");
559
560         case PW_TYPE_ETHERNET:
561                 return talloc_typed_strdup(ctx, "??:??:??:??:??:??:??:??");
562
563 #ifdef WITH_ASCEND_BINARY
564         case PW_TYPE_ABINARY:
565                 return talloc_typed_strdup(ctx, "??");
566 #endif
567
568         default :
569                 break;
570         }
571
572         return talloc_typed_strdup(ctx, "<UNKNOWN-TYPE>");
573 }
574
575 /**  Prints attribute values escaped suitably for use as JSON values
576  *
577  *  Returns < 0 if the buffer may be (or have been) too small to write the encoded
578  *  JSON value to.
579  *
580  * @param out Where to write the string.
581  * @param outlen Lenth of output buffer.
582  * @param vp to print.
583  * @return the length of data written to out, or a value >= outlen on truncation.
584  */
585 size_t vp_prints_value_json(char *out, size_t outlen, VALUE_PAIR const *vp)
586 {
587         char const      *q;
588         size_t          len, freespace = outlen;
589
590         if (!vp->da->flags.has_tag) {
591                 switch (vp->da->type) {
592                 case PW_TYPE_INTEGER:
593                 case PW_TYPE_BYTE:
594                 case PW_TYPE_SHORT:
595                         if (vp->da->flags.has_value) break;
596
597                         return snprintf(out, freespace, "%u", vp->vp_integer);
598
599                 case PW_TYPE_SIGNED:
600                         return snprintf(out, freespace, "%d", vp->vp_signed);
601
602                 default:
603                         break;
604                 }
605         }
606
607         /* Indicate truncation */
608         if (freespace < 2) return outlen + 1;
609         *out++ = '"';
610         freespace--;
611
612         switch (vp->da->type) {
613         case PW_TYPE_STRING:
614                 for (q = vp->vp_strvalue; q < vp->vp_strvalue + vp->length; q++) {
615                         /* Indicate truncation */
616                         if (freespace < 3) return outlen + 1;
617
618                         if (*q == '"') {
619                                 *out++ = '\\';
620                                 *out++ = '"';
621                                 freespace -= 2;
622                         } else if (*q == '\\') {
623                                 *out++ = '\\';
624                                 *out++ = '\\';
625                                 freespace -= 2;
626                         } else if (*q == '/') {
627                                 *out++ = '\\';
628                                 *out++ = '/';
629                                 freespace -= 2;
630                         } else if (*q >= ' ') {
631                                 *out++ = *q;
632                                 freespace--;
633                         } else {
634                                 *out++ = '\\';
635                                 freespace--;
636
637                                 switch (*q) {
638                                 case '\b':
639                                         *out++ = 'b';
640                                         freespace--;
641                                         break;
642
643                                 case '\f':
644                                         *out++ = 'f';
645                                         freespace--;
646                                         break;
647
648                                 case '\n':
649                                         *out++ = 'b';
650                                         freespace--;
651                                         break;
652
653                                 case '\r':
654                                         *out++ = 'r';
655                                         freespace--;
656                                         break;
657
658                                 case '\t':
659                                         *out++ = 't';
660                                         freespace--;
661                                         break;
662                                 default:
663                                         len = snprintf(out, freespace, "u%04X", *q);
664                                         if (is_truncated(len, freespace)) return (outlen - freespace) + len;
665                                         out += len;
666                                         freespace -= len;
667                                 }
668                         }
669                 }
670                 break;
671
672         default:
673                 len = vp_prints_value(out, freespace, vp, 0);
674                 if (is_truncated(len, freespace)) return (outlen - freespace) + len;
675                 out += len;
676                 freespace -= len;
677                 break;
678         }
679
680         /* Indicate truncation */
681         if (freespace < 2) return outlen + 1;
682         *out++ = '"';
683         freespace--;
684         *out = '\0'; // We don't increment out, because the nul byte should not be included in the length
685
686         return outlen - freespace;
687 }
688
689 /*
690  *  This is a hack, and has to be kept in sync with tokens.h
691  */
692 static char const *vp_tokens[] = {
693   "?",                          /* T_OP_INVALID */
694   "EOL",                        /* T_EOL */
695   "{",
696   "}",
697   "(",
698   ")",
699   ",",
700   ";",
701   "++",
702   "+=",
703   "-=",
704   ":=",
705   "=",
706   "!=",
707   ">=",
708   ">",
709   "<=",
710   "<",
711   "=~",
712   "!~",
713   "=*",
714   "!*",
715   "==",
716   "#",
717   "<BARE-WORD>",
718   "<\"STRING\">",
719   "<'STRING'>",
720   "<`STRING`>"
721 };
722
723 extern int const fr_attr_max_tlv;
724 extern int const fr_attr_shift[];
725 extern int const fr_attr_mask[];
726
727
728 /** Print one attribute and value to a string
729  *
730  * Print a VALUE_PAIR in the format:
731 @verbatim
732         <attribute_name>[:tag] <op> <value>
733 @endverbatim
734  * to a string.
735  *
736  * @param out Where to write the string.
737  * @param outlen Lenth of output buffer.
738  * @param vp to print.
739  * @return the length of data written to out, or a value >= outlen on truncation.
740  */
741 size_t vp_prints(char *out, size_t outlen, VALUE_PAIR const *vp)
742 {
743         char const      *token = NULL;
744         size_t          len, freespace = outlen;
745
746         if (!out) return 0;
747
748         *out = '\0';
749         if (!vp || !vp->da) return 0;
750
751         VERIFY_VP(vp);
752
753         if ((vp->op > T_OP_INVALID) && (vp->op < T_TOKEN_LAST)) {
754                 token = vp_tokens[vp->op];
755         } else {
756                 token = "<INVALID-TOKEN>";
757         }
758
759         if (vp->da->flags.has_tag && (vp->tag != TAG_ANY)) {
760                 len = snprintf(out, freespace, "%s:%d %s ", vp->da->name, vp->tag, token);
761         } else {
762                 len = snprintf(out, freespace, "%s %s ", vp->da->name, token);
763         }
764
765         if (is_truncated(len, freespace)) return len;
766         out += len;
767         freespace -= len;
768
769         len = vp_prints_value(out, freespace, vp, '\'');
770         if (is_truncated(len, freespace)) return (outlen - freespace) + len;
771         freespace -= len;
772
773         return (outlen - freespace);
774 }
775
776 /** Print one attribute and value to FP
777  *
778  * Complete string with '\\t' and '\\n' is written to buffer before printing to
779  * avoid issues when running with multiple threads.
780  *
781  * @param fp to output to.
782  * @param vp to print.
783  */
784 void vp_print(FILE *fp, VALUE_PAIR const *vp)
785 {
786         char    buf[1024];
787         char    *p = buf;
788         size_t  len;
789
790         VERIFY_VP(vp);
791
792         *p++ = '\t';
793         len = vp_prints(p, sizeof(buf) - 1, vp);
794         if (!len) {
795                 return;
796         }
797         p += len;
798
799         /*
800          *      Deal with truncation gracefully
801          */
802         if (((size_t) (p - buf)) >= (sizeof(buf) - 2)) {
803                 p = buf + (sizeof(buf) - 2);
804         }
805
806         *p++ = '\n';
807         *p = '\0';
808
809         fputs(buf, fp);
810 }
811
812
813 /** Print a list of attributes and values
814  *
815  * @param fp to output to.
816  * @param vp to print.
817  */
818 void vp_printlist(FILE *fp, VALUE_PAIR const *vp)
819 {
820         vp_cursor_t cursor;
821         for (vp = fr_cursor_init(&cursor, &vp); vp; vp = fr_cursor_next(&cursor)) {
822                 vp_print(fp, vp);
823         }
824 }
825
826
827 /*
828  *      vp_prints_value for talloc
829  */
830 char *vp_aprint_value(TALLOC_CTX *ctx, VALUE_PAIR const *vp)
831 {
832         char *p;
833
834         switch (vp->da->type) {
835         case PW_TYPE_STRING:
836         {
837                 size_t len, ret;
838
839                 /* Gets us the size of the buffer we need to alloc */
840                 len = fr_print_string_len(vp->vp_strvalue, vp->length);
841                 p = talloc_array(ctx, char, len + 1);   /* +1 for '\0' */
842                 if (!p) return NULL;
843
844                 ret = fr_print_string(vp->vp_strvalue, vp->length, p, len + 1);
845                 if (!fr_assert(ret == len)) {
846                         talloc_free(p);
847                         return NULL;
848                 }
849                 break;
850         }
851
852         case PW_TYPE_BYTE:
853         case PW_TYPE_SHORT:
854         case PW_TYPE_INTEGER:
855                 {
856                         DICT_VALUE *dv;
857
858                         dv = dict_valbyattr(vp->da->attr, vp->da->vendor,
859                                             vp->vp_integer);
860                         if (dv) {
861                                 p = talloc_typed_strdup(ctx, dv->name);
862                         } else {
863                                 p = talloc_typed_asprintf(ctx, "%u", vp->vp_integer);
864                         }
865                 }
866                 break;
867
868         case PW_TYPE_SIGNED:
869                 p = talloc_typed_asprintf(ctx, "%d", vp->vp_signed);
870                 break;
871
872         case PW_TYPE_INTEGER64:
873                 p = talloc_typed_asprintf(ctx, "%" PRIu64 , vp->vp_integer64);
874                 break;
875
876         case PW_TYPE_ETHERNET:
877                 p = talloc_typed_asprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
878                                     vp->vp_ether[0], vp->vp_ether[1],
879                                     vp->vp_ether[2], vp->vp_ether[3],
880                                     vp->vp_ether[4], vp->vp_ether[5]);
881                 break;
882
883         case PW_TYPE_ABINARY:
884 #ifdef WITH_ASCEND_BINARY
885                 p = talloc_array(ctx, char, 128);
886                 if (!p) return NULL;
887                 print_abinary(p, 128, (uint8_t *) &vp->vp_filter, vp->length, 0);
888                 break;
889 #else
890                   /* FALL THROUGH */
891 #endif
892
893         case PW_TYPE_OCTETS:
894                 p = talloc_array(ctx, char, 1 + vp->length * 2);
895                 if (!p) return NULL;
896                 fr_bin2hex(p, vp->vp_octets, vp->length);
897                 break;
898
899         case PW_TYPE_DATE:
900         {
901                 time_t t;
902                 struct tm s_tm;
903
904                 t = vp->vp_date;
905
906                 p = talloc_array(ctx, char, 64);
907                 strftime(p, 64, "%b %e %Y %H:%M:%S %Z",
908                          localtime_r(&t, &s_tm));
909                 break;
910         }
911
912         /*
913          *      We need to use the proper inet_ntop functions for IP
914          *      addresses, else the output might not match output of
915          *      other functions, which makes testing difficult.
916          *
917          *      An example is tunnelled ipv4 in ipv6 addresses.
918          */
919         case PW_TYPE_IPV4_ADDR:
920         case PW_TYPE_IPV4_PREFIX:
921                 {
922                         char buff[INET_ADDRSTRLEN  + 4]; // + /prefix
923
924                         buff[0] = '\0';
925                         vp_prints_value(buff, sizeof(buff), vp, 0);
926
927                         p = talloc_typed_strdup(ctx, buff);
928                 }
929                 break;
930
931         case PW_TYPE_IPV6_ADDR:
932         case PW_TYPE_IPV6_PREFIX:
933                 {
934                         char buff[INET6_ADDRSTRLEN + 4]; // + /prefix
935
936                         buff[0] = '\0';
937                         vp_prints_value(buff, sizeof(buff), vp, 0);
938
939                         p = talloc_typed_strdup(ctx, buff);
940                 }
941                 break;
942
943         case PW_TYPE_IFID:
944                 p = talloc_typed_asprintf(ctx, "%x:%x:%x:%x",
945                                     (vp->vp_ifid[0] << 8) | vp->vp_ifid[1],
946                                     (vp->vp_ifid[2] << 8) | vp->vp_ifid[3],
947                                     (vp->vp_ifid[4] << 8) | vp->vp_ifid[5],
948                                     (vp->vp_ifid[6] << 8) | vp->vp_ifid[7]);
949                 break;
950
951         default:
952                 p = NULL;
953                 break;
954         }
955
956         return p;
957 }
958
959 /** Print one attribute and value to a string
960  *
961  * Print a VALUE_PAIR in the format:
962 @verbatim
963         <attribute_name>[:tag] <op> <value>
964 @endverbatim
965  * to a string.
966  *
967  * @param ctx to allocate string in.
968  * @param vp to print.
969  * @return a talloced buffer with the attribute operator and value.
970  */
971 char *vp_aprint(TALLOC_CTX *ctx, VALUE_PAIR const *vp)
972 {
973         char const      *token = NULL;
974         char            *pair, *value;
975
976         if (!vp || !vp->da) return 0;
977
978         VERIFY_VP(vp);
979
980         if ((vp->op > T_OP_INVALID) && (vp->op < T_TOKEN_LAST)) {
981                 token = vp_tokens[vp->op];
982         } else {
983                 token = "<INVALID-TOKEN>";
984         }
985
986         value = vp_aprint_value(ctx, vp);
987         pair = vp->da->flags.has_tag ?
988                talloc_asprintf(ctx, "%s:%d %s %s", vp->da->name, vp->tag, token, value) :
989                talloc_asprintf(ctx, "%s %s %s", vp->da->name, token, value);
990         talloc_free(value);
991
992         return pair;
993 }
994
995