All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
value.c
Go to the documentation of this file.
1 /*
2  * value.c Functions to handle value_data_t
3  *
4  * Version: $Id: 68324d181f6c2b4a42e826063b1a25e3f92056ba $
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 2014 The FreeRADIUS server project
21  */
22 
23 RCSID("$Id: 68324d181f6c2b4a42e826063b1a25e3f92056ba $")
24 
25 #include <freeradius-devel/libradius.h>
26 #include <ctype.h>
27 
28 /** Compare two values
29  *
30  * @param[in] a_type of data to compare.
31  * @param[in] a Value to compare.
32  * @param[in] b_type of data to compare.
33  * @param[in] b Value to compare.
34  * @return
35  * - -1 if a is less than b.
36  * - 0 if both are equal.
37  * - 1 if a is more than b.
38  * - < -1 on failure.
39  */
40 int value_data_cmp(PW_TYPE a_type, value_data_t const *a,
41  PW_TYPE b_type, value_data_t const *b)
42 {
43  int compare = 0;
44 
45  if (a_type != b_type) {
46  fr_strerror_printf("Can't compare values of different types");
47  return -2;
48  }
49 
50  /*
51  * After doing the previous check for special comparisons,
52  * do the per-type comparison here.
53  */
54  switch (a_type) {
55  case PW_TYPE_ABINARY:
56  case PW_TYPE_OCTETS:
57  case PW_TYPE_STRING: /* We use memcmp to be \0 safe */
58  {
59  size_t length;
60 
61  if (a->length > b->length) {
62  length = a->length;
63  } else {
64  length = b->length;
65  }
66 
67  if (length) {
68  compare = memcmp(a->octets, b->octets, length);
69  if (compare != 0) break;
70  }
71 
72  /*
73  * Contents are the same. The return code
74  * is therefore the difference in lengths.
75  *
76  * i.e. "0x00" is smaller than "0x0000"
77  */
78  compare = a->length - b->length;
79  }
80  break;
81 
82  /*
83  * Short-hand for simplicity.
84  */
85 #define CHECK(_type) if (a->_type < b->_type) { compare = -1; \
86  } else if (a->_type > b->_type) { compare = +1; }
87 
88  case PW_TYPE_BOOLEAN: /* this isn't a RADIUS type, and shouldn't really ever be used */
89  case PW_TYPE_BYTE:
90  CHECK(byte);
91  break;
92 
93 
94  case PW_TYPE_SHORT:
95  CHECK(ushort);
96  break;
97 
98  case PW_TYPE_DATE:
99  CHECK(date);
100  break;
101 
102  case PW_TYPE_INTEGER:
103  CHECK(integer);
104  break;
105 
106  case PW_TYPE_SIGNED:
107  CHECK(sinteger);
108  break;
109 
110  case PW_TYPE_INTEGER64:
111  CHECK(integer64);
112  break;
113 
114  case PW_TYPE_DECIMAL:
115  CHECK(decimal);
116  break;
117 
118  case PW_TYPE_ETHERNET:
119  compare = memcmp(a->ether, b->ether, sizeof(a->ether));
120  break;
121 
122  case PW_TYPE_IPV4_ADDR:
123  {
124  uint32_t a_int, b_int;
125 
126  a_int = ntohl(a->ipaddr.s_addr);
127  b_int = ntohl(b->ipaddr.s_addr);
128  if (a_int < b_int) {
129  compare = -1;
130  } else if (a_int > b_int) {
131  compare = +1;
132  }
133  }
134  break;
135 
136  case PW_TYPE_IPV6_ADDR:
137  compare = memcmp(&a->ipv6addr, &b->ipv6addr, sizeof(a->ipv6addr));
138  break;
139 
140  case PW_TYPE_IPV6_PREFIX:
141  compare = memcmp(a->ipv6prefix, b->ipv6prefix, sizeof(a->ipv6prefix));
142  break;
143 
144  case PW_TYPE_IPV4_PREFIX:
145  compare = memcmp(a->ipv4prefix, b->ipv4prefix, sizeof(a->ipv4prefix));
146  break;
147 
148  case PW_TYPE_IFID:
149  compare = memcmp(a->ifid, b->ifid, sizeof(a->ifid));
150  break;
151 
152  /*
153  * These should be handled at some point
154  */
155  case PW_TYPE_TIMEVAL:
156  case PW_TYPE_COMBO_IP_ADDR: /* This should have been converted into IPADDR/IPV6ADDR */
157  case PW_TYPE_COMBO_IP_PREFIX: /* This should have been converted into IPADDR/IPV6ADDR */
158  case PW_TYPE_STRUCTURAL:
159  case PW_TYPE_BAD:
160  fr_assert(0); /* unknown type */
161  return -2;
162 
163  /*
164  * Do NOT add a default here, as new types are added
165  * static analysis will warn us they're not handled
166  */
167  }
168 
169  if (compare > 0) return 1;
170  if (compare < 0) return -1;
171  return 0;
172 }
173 
174 /*
175  * We leverage the fact that IPv4 and IPv6 prefixes both
176  * have the same format:
177  *
178  * reserved, prefix-len, data...
179  */
180 static int value_data_cidr_cmp_op(FR_TOKEN op, int bytes,
181  uint8_t a_net, uint8_t const *a,
182  uint8_t b_net, uint8_t const *b)
183 {
184  int i, common;
185  uint32_t mask;
186 
187  /*
188  * Handle the case of netmasks being identical.
189  */
190  if (a_net == b_net) {
191  int compare;
192 
193  compare = memcmp(a, b, bytes);
194 
195  /*
196  * If they're identical return true for
197  * identical.
198  */
199  if ((compare == 0) &&
200  ((op == T_OP_CMP_EQ) ||
201  (op == T_OP_LE) ||
202  (op == T_OP_GE))) {
203  return true;
204  }
205 
206  /*
207  * Everything else returns false.
208  *
209  * 10/8 == 24/8 --> false
210  * 10/8 <= 24/8 --> false
211  * 10/8 >= 24/8 --> false
212  */
213  return false;
214  }
215 
216  /*
217  * Netmasks are different. That limits the
218  * possible results, based on the operator.
219  */
220  switch (op) {
221  case T_OP_CMP_EQ:
222  return false;
223 
224  case T_OP_NE:
225  return true;
226 
227  case T_OP_LE:
228  case T_OP_LT: /* 192/8 < 192.168/16 --> false */
229  if (a_net < b_net) {
230  return false;
231  }
232  break;
233 
234  case T_OP_GE:
235  case T_OP_GT: /* 192/16 > 192.168/8 --> false */
236  if (a_net > b_net) {
237  return false;
238  }
239  break;
240 
241  default:
242  return false;
243  }
244 
245  if (a_net < b_net) {
246  common = a_net;
247  } else {
248  common = b_net;
249  }
250 
251  /*
252  * Do the check byte by byte. If the bytes are
253  * identical, it MAY be a match. If they're different,
254  * it is NOT a match.
255  */
256  i = 0;
257  while (i < bytes) {
258  /*
259  * All leading bytes are identical.
260  */
261  if (common == 0) return true;
262 
263  /*
264  * Doing bitmasks takes more work.
265  */
266  if (common < 8) break;
267 
268  if (a[i] != b[i]) return false;
269 
270  common -= 8;
271  i++;
272  continue;
273  }
274 
275  mask = 1;
276  mask <<= (8 - common);
277  mask--;
278  mask = ~mask;
279 
280  if ((a[i] & mask) == ((b[i] & mask))) {
281  return true;
282  }
283 
284  return false;
285 }
286 
287 /** Compare two attributes using an operator
288  *
289  * @param[in] op to use in comparison.
290  * @param[in] a_type of data to compare.
291  * @param[in] a Value to compare.
292  * @param[in] b_type of data to compare.
293  * @param[in] b Value to compare.
294  * @return
295  * - 1 if true
296  * - 0 if false
297  * - -1 on failure.
298  */
300  PW_TYPE a_type, value_data_t const *a,
301  PW_TYPE b_type, value_data_t const *b)
302 {
303  int compare = 0;
304 
305  if (!a || !b) return -1;
306 
307  switch (a_type) {
308  case PW_TYPE_IPV4_ADDR:
309  switch (b_type) {
310  case PW_TYPE_IPV4_ADDR: /* IPv4 and IPv4 */
311  goto cmp;
312 
313  case PW_TYPE_IPV4_PREFIX: /* IPv4 and IPv4 Prefix */
314  return value_data_cidr_cmp_op(op, 4, 32, (uint8_t const *) &a->ipaddr,
315  b->ipv4prefix[1], (uint8_t const *) &b->ipv4prefix[2]);
316 
317  default:
318  fr_strerror_printf("Cannot compare IPv4 with IPv6 address");
319  return -1;
320  }
321 
322  case PW_TYPE_IPV4_PREFIX: /* IPv4 and IPv4 Prefix */
323  switch (b_type) {
324  case PW_TYPE_IPV4_ADDR:
325  return value_data_cidr_cmp_op(op, 4, a->ipv4prefix[1],
326  (uint8_t const *) &a->ipv4prefix[2],
327  32, (uint8_t const *) &b->ipaddr);
328 
329  case PW_TYPE_IPV4_PREFIX: /* IPv4 Prefix and IPv4 Prefix */
330  return value_data_cidr_cmp_op(op, 4, a->ipv4prefix[1],
331  (uint8_t const *) &a->ipv4prefix[2],
332  b->ipv4prefix[1], (uint8_t const *) &b->ipv4prefix[2]);
333 
334  default:
335  fr_strerror_printf("Cannot compare IPv4 with IPv6 address");
336  return -1;
337  }
338 
339  case PW_TYPE_IPV6_ADDR:
340  switch (b_type) {
341  case PW_TYPE_IPV6_ADDR: /* IPv6 and IPv6 */
342  goto cmp;
343 
344  case PW_TYPE_IPV6_PREFIX: /* IPv6 and IPv6 Preifx */
345  return value_data_cidr_cmp_op(op, 16, 128, (uint8_t const *) &a->ipv6addr,
346  b->ipv6prefix[1], (uint8_t const *) &b->ipv6prefix[2]);
347 
348  default:
349  fr_strerror_printf("Cannot compare IPv6 with IPv4 address");
350  return -1;
351  }
352 
353  case PW_TYPE_IPV6_PREFIX:
354  switch (b_type) {
355  case PW_TYPE_IPV6_ADDR: /* IPv6 Prefix and IPv6 */
356  return value_data_cidr_cmp_op(op, 16, a->ipv6prefix[1],
357  (uint8_t const *) &a->ipv6prefix[2],
358  128, (uint8_t const *) &b->ipv6addr);
359 
360  case PW_TYPE_IPV6_PREFIX: /* IPv6 Prefix and IPv6 */
361  return value_data_cidr_cmp_op(op, 16, a->ipv6prefix[1],
362  (uint8_t const *) &a->ipv6prefix[2],
363  b->ipv6prefix[1], (uint8_t const *) &b->ipv6prefix[2]);
364 
365  default:
366  fr_strerror_printf("Cannot compare IPv6 with IPv4 address");
367  return -1;
368  }
369 
370  default:
371  cmp:
372  compare = value_data_cmp(a_type, a, b_type, b);
373  if (compare < -1) { /* comparison error */
374  return -1;
375  }
376  }
377 
378  /*
379  * Now do the operator comparison.
380  */
381  switch (op) {
382  case T_OP_CMP_EQ:
383  return (compare == 0);
384 
385  case T_OP_NE:
386  return (compare != 0);
387 
388  case T_OP_LT:
389  return (compare < 0);
390 
391  case T_OP_GT:
392  return (compare > 0);
393 
394  case T_OP_LE:
395  return (compare <= 0);
396 
397  case T_OP_GE:
398  return (compare >= 0);
399 
400  default:
401  return 0;
402  }
403 }
404 
405 /** Match all fixed length types in case statements
406  *
407  * @note This should be used for switch statements in printing and casting
408  * functions that need to deal with all types representing values
409  */
410 #define PW_TYPE_BOUNDED \
411  PW_TYPE_BYTE: \
412  case PW_TYPE_SHORT: \
413  case PW_TYPE_INTEGER: \
414  case PW_TYPE_INTEGER64: \
415  case PW_TYPE_DATE: \
416  case PW_TYPE_IFID: \
417  case PW_TYPE_ETHERNET: \
418  case PW_TYPE_COMBO_IP_ADDR: \
419  case PW_TYPE_COMBO_IP_PREFIX: \
420  case PW_TYPE_SIGNED: \
421  case PW_TYPE_TIMEVAL: \
422  case PW_TYPE_BOOLEAN: \
423  case PW_TYPE_DECIMAL
424 
425 /** Match all variable length types in case statements
426  *
427  * @note This should be used for switch statements in printing and casting
428  * functions that need to deal with all types representing values
429  */
430 #define PW_TYPE_UNBOUNDED \
431  PW_TYPE_STRING: \
432  case PW_TYPE_OCTETS: \
433  case PW_TYPE_ABINARY: \
434  case PW_TYPE_IPV4_ADDR: \
435  case PW_TYPE_IPV4_PREFIX: \
436  case PW_TYPE_IPV6_ADDR: \
437  case PW_TYPE_IPV6_PREFIX
438 
439 static char const hextab[] = "0123456789abcdef";
440 
441 /** Convert string value to a value_data_t type
442  *
443  * @param[in] ctx to alloc strings in.
444  * @param[out] dst where to write parsed value.
445  * @param[in,out] src_type of value data to create/type of value created.
446  * @param[in] src_enumv fr_dict_attr_t with string aliases for integer values.
447  * @param[in] src String to convert. Binary safe for variable length values if len is provided.
448  * @param[in] src_len may be < 0 in which case strlen(len) is used to determine length, else src_len
449  * should be the length of the string or sub string to parse.
450  * @param[in] quote quotation character used to drive de-escaping
451  * @return
452  * - 0 on success.
453  * - -1 on parse error.
454  */
455 int value_data_from_str(TALLOC_CTX *ctx, value_data_t *dst,
456  PW_TYPE *src_type, fr_dict_attr_t const *src_enumv,
457  char const *src, ssize_t src_len, char quote)
458 {
459  fr_dict_enum_t *dval;
460  size_t len;
461  ssize_t ret;
462  char buffer[256];
463 
464  if (!src) return -1;
465 
466  len = (src_len < 0) ? strlen(src) : (size_t)src_len;
467 
468  /*
469  * Set size for all fixed length attributes.
470  */
471  ret = dict_attr_sizes[*src_type][1]; /* Max length */
472 
473  /*
474  * It's a variable ret src_type so we just alloc a new buffer
475  * of size len and copy.
476  */
477  switch (*src_type) {
478  case PW_TYPE_STRING:
479  {
480  char *p, *buff;
481  char const *q;
482  int x;
483 
484  buff = p = talloc_bstrndup(ctx, src, len);
485 
486  /*
487  * No de-quoting. Just copy the string.
488  */
489  if (!quote) {
490  ret = len;
491  dst->strvalue = buff;
492  goto finish;
493  }
494 
495  /*
496  * Do escaping for single quoted strings. Only
497  * single quotes get escaped. Everything else is
498  * left as-is.
499  */
500  if (quote == '\'') {
501  q = p;
502 
503  while (q < (buff + len)) {
504  /*
505  * The quotation character is escaped.
506  */
507  if ((q[0] == '\\') &&
508  (q[1] == quote)) {
509  *(p++) = quote;
510  q += 2;
511  continue;
512  }
513 
514  /*
515  * Two backslashes get mangled to one.
516  */
517  if ((q[0] == '\\') &&
518  (q[1] == '\\')) {
519  *(p++) = '\\';
520  q += 2;
521  continue;
522  }
523 
524  /*
525  * Not escaped, just copy it over.
526  */
527  *(p++) = *(q++);
528  }
529 
530  *p = '\0';
531  ret = p - buff;
532 
533  /* Shrink the buffer to the correct size */
534  dst->strvalue = talloc_realloc(ctx, buff, char, ret + 1);
535  goto finish;
536  }
537 
538  /*
539  * It's "string" or `string`, do all standard
540  * escaping.
541  */
542  q = p;
543  while (q < (buff + len)) {
544  char c = *q++;
545 
546  if ((c == '\\') && (q >= (buff + len))) {
547  fr_strerror_printf("Invalid escape at end of string");
548  talloc_free(buff);
549  return -1;
550  }
551 
552  /*
553  * Fix up \X -> ... the binary form of it.
554  */
555  if (c == '\\') {
556  switch (*q) {
557  case 'r':
558  c = '\r';
559  q++;
560  break;
561 
562  case 'n':
563  c = '\n';
564  q++;
565  break;
566 
567  case 't':
568  c = '\t';
569  q++;
570  break;
571 
572  case '\\':
573  c = '\\';
574  q++;
575  break;
576 
577  default:
578  /*
579  * \" --> ", but only inside of double quoted strings, etc.
580  */
581  if (*q == quote) {
582  c = quote;
583  q++;
584  break;
585  }
586 
587  /*
588  * \000 --> binary zero character
589  */
590  if ((q[0] >= '0') &&
591  (q[0] <= '9') &&
592  (q[1] >= '0') &&
593  (q[1] <= '9') &&
594  (q[2] >= '0') &&
595  (q[2] <= '9') &&
596  (sscanf(q, "%3o", &x) == 1)) {
597  c = x;
598  q += 3;
599  }
600 
601  /*
602  * Else It's not a recognised escape sequence DON'T
603  * consume the backslash. This is identical
604  * behaviour to bash and most other things that
605  * use backslash escaping.
606  */
607  }
608  }
609 
610  *p++ = c;
611  }
612 
613  *p = '\0';
614  ret = p - buff;
615  dst->strvalue = talloc_realloc(ctx, buff, char, ret + 1);
616  }
617  goto finish;
618 
619  case PW_TYPE_VSA:
620  fr_strerror_printf("Must use 'Attr-26 = ...' instead of 'Vendor-Specific = ...'");
621  return -1;
622 
623  /* raw octets: 0x01020304... */
624  case PW_TYPE_OCTETS:
625  {
626  uint8_t *p;
627 
628  /*
629  * No 0x prefix, just copy verbatim.
630  */
631  if ((len < 2) || (strncasecmp(src, "0x", 2) != 0)) {
632  dst->octets = talloc_memdup(ctx, (uint8_t const *)src, len);
633  talloc_set_type(dst->octets, uint8_t);
634  ret = len;
635  goto finish;
636  }
637 
638  len -= 2;
639 
640  /*
641  * Invalid.
642  */
643  if ((len & 0x01) != 0) {
644  fr_strerror_printf("Length of Hex String is not even, got %zu bytes", len);
645  return -1;
646  }
647 
648  ret = len >> 1;
649  p = talloc_array(ctx, uint8_t, ret);
650  if (fr_hex2bin(p, ret, src + 2, len) != (size_t)ret) {
651  talloc_free(p);
652  fr_strerror_printf("Invalid hex data");
653  return -1;
654  }
655 
656  dst->octets = p;
657  }
658  goto finish;
659 
660  case PW_TYPE_ABINARY:
661 #ifdef WITH_ASCEND_BINARY
662  if ((len > 1) && (strncasecmp(src, "0x", 2) == 0)) {
663  ssize_t bin;
664 
665  if (len > ((sizeof(dst->filter) + 1) * 2)) {
666  fr_strerror_printf("Hex data is too large for ascend filter");
667  return -1;
668  }
669 
670  bin = fr_hex2bin((uint8_t *) &dst->filter, ret, src + 2, len);
671  if (bin < ret) {
672  memset(((uint8_t *) &dst->filter) + bin, 0, ret - bin);
673  }
674  } else {
675  if (ascend_parse_filter(dst, src, len) < 0 ) {
676  /* Allow ascend_parse_filter's strerror to bubble up */
677  return -1;
678  }
679  }
680 
681  ret = sizeof(dst->filter);
682  goto finish;
683 #else
684  /*
685  * If Ascend binary is NOT defined,
686  * then fall through to raw octets, so that
687  * the user can at least make them by hand...
688  */
689  goto do_octets;
690 #endif
691 
692  case PW_TYPE_IPV4_ADDR:
693  {
694  fr_ipaddr_t addr;
695 
696  if (fr_inet_pton4(&addr, src, src_len, fr_hostname_lookups, false, true) < 0) return -1;
697 
698  /*
699  * We allow v4 addresses to have a /32 suffix as some databases (PostgreSQL)
700  * print them this way.
701  */
702  if (addr.prefix != 32) {
703  fr_strerror_printf("Invalid IPv4 mask length \"/%i\". Only \"/32\" permitted "
704  "for non-prefix types", addr.prefix);
705  return -1;
706  }
707 
708  dst->ipaddr.s_addr = addr.ipaddr.ip4addr.s_addr;
709  }
710  goto finish;
711 
712  case PW_TYPE_IPV4_PREFIX:
713  {
714  fr_ipaddr_t addr;
715 
716  if (fr_inet_pton4(&addr, src, src_len, fr_hostname_lookups, false, true) < 0) return -1;
717 
718  dst->ipv4prefix[1] = addr.prefix;
719  memcpy(&dst->ipv4prefix[2], &addr.ipaddr.ip4addr.s_addr, sizeof(dst->ipv4prefix) - 2);
720  }
721  goto finish;
722 
723  case PW_TYPE_IPV6_ADDR:
724  {
725  fr_ipaddr_t addr;
726 
727  if (fr_inet_pton6(&addr, src, src_len, fr_hostname_lookups, false, true) < 0) return -1;
728 
729  /*
730  * We allow v6 addresses to have a /128 suffix as some databases (PostgreSQL)
731  * print them this way.
732  */
733  if (addr.prefix != 128) {
734  fr_strerror_printf("Invalid IPv6 mask length \"/%i\". Only \"/128\" permitted "
735  "for non-prefix types", addr.prefix);
736  return -1;
737  }
738 
739  memcpy(&dst->ipv6addr, addr.ipaddr.ip6addr.s6_addr, sizeof(dst->ipv6addr));
740  }
741  goto finish;
742 
743  case PW_TYPE_IPV6_PREFIX:
744  {
745  fr_ipaddr_t addr;
746 
747  if (fr_inet_pton6(&addr, src, src_len, fr_hostname_lookups, false, true) < 0) return -1;
748 
749  dst->ipv6prefix[1] = addr.prefix;
750  memcpy(&dst->ipv6prefix[2], addr.ipaddr.ip6addr.s6_addr, sizeof(dst->ipv6prefix) - 2);
751  }
752  goto finish;
753 
754  /*
755  * Dealt with below
756  */
757  case PW_TYPE_BOUNDED:
758  break;
759 
761  case PW_TYPE_VENDOR:
762  case PW_TYPE_BAD:
763  fr_strerror_printf("Invalid type %d", *src_type);
764  return -1;
765  }
766 
767  /*
768  * It's a fixed size src_type, copy to a temporary buffer and
769  * \0 terminate if insize >= 0.
770  */
771  if (src_len > 0) {
772  if (len >= sizeof(buffer)) {
773  fr_strerror_printf("Temporary buffer too small");
774  return -1;
775  }
776 
777  memcpy(buffer, src, src_len);
778  buffer[src_len] = '\0';
779  src = buffer;
780  }
781 
782  switch (*src_type) {
783  case PW_TYPE_BYTE:
784  {
785  char *p;
786  unsigned int i;
787 
788  /*
789  * Note that ALL integers are unsigned!
790  */
791  i = fr_strtoul(src, &p);
792 
793  /*
794  * Look for the named src for the given
795  * attribute.
796  */
797  if (src_enumv && *p && !is_whitespace(p)) {
798  if ((dval = fr_dict_enum_by_name(NULL, src_enumv, src)) == NULL) {
799  fr_strerror_printf("Unknown or invalid value \"%s\" for attribute %s",
800  src, src_enumv->name);
801  return -1;
802  }
803 
804  dst->byte = dval->value;
805  } else {
806  if (i > 255) {
807  fr_strerror_printf("Byte value \"%s\" is larger than 255", src);
808  return -1;
809  }
810 
811  dst->byte = i;
812  }
813  break;
814  }
815 
816  case PW_TYPE_SHORT:
817  {
818  char *p;
819  unsigned int i;
820 
821  /*
822  * Note that ALL integers are unsigned!
823  */
824  i = fr_strtoul(src, &p);
825 
826  /*
827  * Look for the named src for the given
828  * attribute.
829  */
830  if (src_enumv && *p && !is_whitespace(p)) {
831  if ((dval = fr_dict_enum_by_name(NULL, src_enumv, src)) == NULL) {
832  fr_strerror_printf("Unknown or invalid value \"%s\" for attribute %s",
833  src, src_enumv->name);
834  return -1;
835  }
836 
837  dst->ushort = dval->value;
838  } else {
839  if (i > 65535) {
840  fr_strerror_printf("Short value \"%s\" is larger than 65535", src);
841  return -1;
842  }
843 
844  dst->ushort = i;
845  }
846  break;
847  }
848 
849  case PW_TYPE_INTEGER:
850  {
851  char *p;
852  unsigned int i;
853 
854  /*
855  * Note that ALL integers are unsigned!
856  */
857  i = fr_strtoul(src, &p);
858 
859  /*
860  * Look for the named src for the given
861  * attribute.
862  */
863  if (src_enumv && *p && !is_whitespace(p)) {
864  if ((dval = fr_dict_enum_by_name(NULL, src_enumv, src)) == NULL) {
865  fr_strerror_printf("Unknown or invalid value \"%s\" for attribute %s",
866  src, src_enumv->name);
867  return -1;
868  }
869 
870  dst->integer = dval->value;
871  } else {
872  /*
873  * Value is always within the limits
874  */
875  dst->integer = i;
876  }
877  }
878  break;
879 
880  case PW_TYPE_INTEGER64:
881  {
882  uint64_t i;
883 
884  /*
885  * Note that ALL integers are unsigned!
886  */
887  if (sscanf(src, "%" PRIu64, &i) != 1) {
888  fr_strerror_printf("Failed parsing \"%s\" as unsigned 64bit integer", src);
889  return -1;
890  }
891  dst->integer64 = i;
892  }
893  break;
894 
895  case PW_TYPE_DATE:
896  {
897  /*
898  * time_t may be 64 bits, whule vp_date MUST be 32-bits. We need an
899  * intermediary variable to handle the conversions.
900  */
901  time_t date;
902 
903  if (fr_get_time(src, &date) < 0) {
904  fr_strerror_printf("failed to parse time string \"%s\"", src);
905  return -1;
906  }
907 
908  dst->date = date;
909  }
910 
911  break;
912 
913  case PW_TYPE_IFID:
914  if (fr_inet_ifid_pton((void *) dst->ifid, src) == NULL) {
915  fr_strerror_printf("Failed to parse interface-id string \"%s\"", src);
916  return -1;
917  }
918  break;
919 
920  case PW_TYPE_ETHERNET:
921  {
922  char const *c1, *c2, *cp;
923  size_t p_len = 0;
924 
925  /*
926  * Convert things which are obviously integers to Ethernet addresses
927  *
928  * We assume the number is the bigendian representation of the
929  * ethernet address.
930  */
931  if (is_integer(src)) {
932  uint64_t integer = htonll(atoll(src));
933 
934  memcpy(dst->ether, &integer, sizeof(dst->ether));
935  break;
936  }
937 
938  cp = src;
939  while (*cp) {
940  if (cp[1] == ':') {
941  c1 = hextab;
942  c2 = memchr(hextab, tolower((int) cp[0]), 16);
943  cp += 2;
944  } else if ((cp[1] != '\0') && ((cp[2] == ':') || (cp[2] == '\0'))) {
945  c1 = memchr(hextab, tolower((int) cp[0]), 16);
946  c2 = memchr(hextab, tolower((int) cp[1]), 16);
947  cp += 2;
948  if (*cp == ':') cp++;
949  } else {
950  c1 = c2 = NULL;
951  }
952  if (!c1 || !c2 || (p_len >= sizeof(dst->ether))) {
953  fr_strerror_printf("failed to parse Ethernet address \"%s\"", src);
954  return -1;
955  }
956  dst->ether[p_len] = ((c1-hextab)<<4) + (c2-hextab);
957  p_len++;
958  }
959  }
960  break;
961 
962  /*
963  * Crazy polymorphic (IPv4/IPv6) attribute src_type for WiMAX.
964  *
965  * We try and make is saner by replacing the original
966  * da, with either an IPv4 or IPv6 da src_type.
967  *
968  * These are not dynamic da, and will have the same vendor
969  * and attribute as the original.
970  */
972  {
973  if (inet_pton(AF_INET6, src, &dst->ipv6addr) > 0) {
974  *src_type = PW_TYPE_IPV6_ADDR;
975  ret = dict_attr_sizes[PW_TYPE_COMBO_IP_ADDR][1]; /* size of IPv6 address */
976  } else {
977  fr_ipaddr_t ipaddr;
978 
979  if (fr_inet_hton(&ipaddr, AF_INET, src, false) < 0) {
980  fr_strerror_printf("Failed to find IPv4 address for %s", src);
981  return -1;
982  }
983 
984  *src_type = PW_TYPE_IPV4_ADDR;
985  dst->ipaddr.s_addr = ipaddr.ipaddr.ip4addr.s_addr;
986  ret = dict_attr_sizes[PW_TYPE_COMBO_IP_ADDR][0]; /* size of IPv4 address */
987  }
988  }
989  break;
990 
991  case PW_TYPE_SIGNED:
992  /* Damned code for 1 WiMAX attribute */
993  dst->sinteger = (int32_t)strtol(src, NULL, 10);
994  break;
995 
996  case PW_TYPE_BOOLEAN:
998  case PW_TYPE_TIMEVAL:
999  break;
1000 
1001  case PW_TYPE_DECIMAL:
1002  {
1003  double i;
1004 
1005  if (sscanf(src, "%lf", &i) != 1) {
1006  fr_strerror_printf("Failed parsing \"%s\" as double", src);
1007  return -1;
1008  }
1009  dst->decimal = i;
1010  }
1011  break;
1012 
1013  case PW_TYPE_UNBOUNDED: /* Should have been dealt with above */
1014  case PW_TYPE_STRUCTURAL: /* Listed again to suppress compiler warnings */
1015  case PW_TYPE_BAD:
1016  fr_strerror_printf("Unknown attribute type %d", *src_type);
1017  return -1;
1018  }
1019 
1020 finish:
1021  dst->length = ret;
1022  return 0;
1023 }
1024 
1025 /** Performs byte order reversal for types that need it
1026  *
1027  */
1028 static void value_data_hton(value_data_t *dst, PW_TYPE type, void const *src, size_t src_len)
1029 {
1030  /* 8 byte integers */
1031  switch (type) {
1032  case PW_TYPE_INTEGER64:
1033  dst->integer64 = htonll(*(uint64_t const *)src);
1034  break;
1035 
1036  /* 4 byte integers */
1037  case PW_TYPE_INTEGER:
1038  case PW_TYPE_DATE:
1039  case PW_TYPE_SIGNED:
1040  dst->integer = htonl(*(uint32_t const *)src);
1041  break;
1042 
1043  /* 2 byte integers */
1044  case PW_TYPE_SHORT:
1045  dst->ushort = htons(*(uint16_t const *)src);
1046  break;
1047 
1048  case PW_TYPE_OCTETS:
1049  case PW_TYPE_STRING:
1050  fr_assert(0);
1051  return; /* shouldn't happen */
1052 
1053  default:
1054  memcpy(dst, src, src_len);
1055  }
1056 }
1057 
1058 /** Convert one type of value_data_t to another
1059  *
1060  * @note This should be the canonical function used to convert between data types.
1061  *
1062  * @param ctx to allocate buffers in (usually the same as dst)
1063  * @param dst Where to write result of casting.
1064  * @param dst_type to cast to.
1065  * @param dst_enumv Enumerated values used to converts strings to integers.
1066  * @param src_type to cast from.
1067  * @param src_enumv Enumerated values used to convert integers to strings.
1068  * @param src Input data.
1069  * @return
1070  * - 0 on success.
1071  * - -1 on failure.
1072  */
1073 int value_data_cast(TALLOC_CTX *ctx, value_data_t *dst,
1074  PW_TYPE dst_type, fr_dict_attr_t const *dst_enumv,
1075  PW_TYPE src_type, fr_dict_attr_t const *src_enumv,
1076  value_data_t const *src)
1077 {
1078  if (!fr_assert(dst_type != src_type)) return -1;
1079 
1080  /*
1081  * Deserialise a value_data_t
1082  */
1083  if (src_type == PW_TYPE_STRING) {
1084  return value_data_from_str(ctx, dst, &dst_type, dst_enumv, src->strvalue, src->length, '\0');
1085  }
1086 
1087  /*
1088  * Converts the src data to octets with no processing.
1089  */
1090  if (dst_type == PW_TYPE_OCTETS) {
1091  value_data_hton(dst, src_type, src, src->length);
1092  dst->octets = talloc_memdup(ctx, dst, src->length);
1093  dst->length = src->length;
1094  talloc_set_type(dst->octets, uint8_t);
1095  return 0;
1096  }
1097 
1098  /*
1099  * Serialise a value_data_t
1100  */
1101  if (dst_type == PW_TYPE_STRING) {
1102  dst->strvalue = value_data_asprint(ctx, src_type, src_enumv, src, '\0');
1103  dst->length = talloc_array_length(dst->strvalue) - 1;
1104  return 0;
1105  }
1106 
1107  if ((src_type == PW_TYPE_IFID) &&
1108  (dst_type == PW_TYPE_INTEGER64)) {
1109  memcpy(&dst->integer64, src->ifid, sizeof(src->ifid));
1110  dst->integer64 = htonll(dst->integer64);
1111  fixed_length:
1112  dst->length = dict_attr_sizes[dst_type][0];
1113  return 0;
1114  }
1115 
1116  if ((src_type == PW_TYPE_INTEGER64) &&
1117  (dst_type == PW_TYPE_ETHERNET)) {
1118  uint8_t array[8];
1119  uint64_t i;
1120 
1121  i = htonll(src->integer64);
1122  memcpy(array, &i, 8);
1123 
1124  /*
1125  * For OUIs in the DB.
1126  */
1127  if ((array[0] != 0) || (array[1] != 0)) return -1;
1128 
1129  memcpy(dst->ether, &array[2], 6);
1130  goto fixed_length;
1131  }
1132 
1133  /*
1134  * For integers, we allow the casting of a SMALL type to
1135  * a larger type, but not vice-versa.
1136  */
1137  if (dst_type == PW_TYPE_INTEGER64) {
1138  switch (src_type) {
1139  case PW_TYPE_BYTE:
1140  dst->integer64 = src->byte;
1141  break;
1142 
1143  case PW_TYPE_SHORT:
1144  dst->integer64 = src->ushort;
1145  break;
1146 
1147  case PW_TYPE_INTEGER:
1148  dst->integer64 = src->integer;
1149  break;
1150 
1151  case PW_TYPE_DATE:
1152  dst->integer64 = src->date;
1153  break;
1154 
1155  case PW_TYPE_OCTETS:
1156  goto do_octets;
1157 
1158  default:
1159  invalid_cast:
1160  fr_strerror_printf("Invalid cast from %s to %s",
1161  fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1162  fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1163  return -1;
1164 
1165  }
1166  goto fixed_length;
1167  }
1168 
1169  /*
1170  * We can cast LONG integers to SHORTER ones, so long
1171  * as the long one is on the LHS.
1172  */
1173  if (dst_type == PW_TYPE_INTEGER) {
1174  switch (src_type) {
1175  case PW_TYPE_BYTE:
1176  dst->integer = src->byte;
1177  break;
1178 
1179  case PW_TYPE_SHORT:
1180  dst->integer = src->ushort;
1181  break;
1182 
1183  case PW_TYPE_OCTETS:
1184  goto do_octets;
1185 
1186  default:
1187  goto invalid_cast;
1188  }
1189  goto fixed_length;
1190  }
1191 
1192  if (dst_type == PW_TYPE_SHORT) {
1193  switch (src_type) {
1194  case PW_TYPE_BYTE:
1195  dst->ushort = src->byte;
1196  break;
1197 
1198  case PW_TYPE_OCTETS:
1199  goto do_octets;
1200 
1201  default:
1202  goto invalid_cast;
1203  }
1204  goto fixed_length;
1205  }
1206 
1207  /*
1208  * We can cast integers less that < INT_MAX to signed
1209  */
1210  if (dst_type == PW_TYPE_SIGNED) {
1211  switch (src_type) {
1212  case PW_TYPE_BYTE:
1213  dst->sinteger = src->byte;
1214  break;
1215 
1216  case PW_TYPE_SHORT:
1217  dst->sinteger = src->ushort;
1218  break;
1219 
1220  case PW_TYPE_INTEGER:
1221  if (src->integer > INT_MAX) {
1222  fr_strerror_printf("Invalid cast: From integer to signed. integer value %u is larger "
1223  "than max signed int and would overflow", src->integer);
1224  return -1;
1225  }
1226  dst->sinteger = (int)src->integer;
1227  break;
1228 
1229  case PW_TYPE_INTEGER64:
1230  if (src->integer > INT_MAX) {
1231  fr_strerror_printf("Invalid cast: From integer64 to signed. integer64 value %" PRIu64
1232  " is larger than max signed int and would overflow", src->integer64);
1233  return -1;
1234  }
1235  dst->sinteger = (int)src->integer64;
1236  break;
1237 
1238  case PW_TYPE_OCTETS:
1239  goto do_octets;
1240 
1241  default:
1242  goto invalid_cast;
1243  }
1244  goto fixed_length;
1245  }
1246  /*
1247  * Conversions between IPv4 addresses, IPv6 addresses, IPv4 prefixes and IPv6 prefixes
1248  *
1249  * For prefix to ipaddress conversions, we assume that the host portion has already
1250  * been zeroed out.
1251  *
1252  * We allow casts from v6 to v4 if the v6 address has the correct mapping prefix.
1253  *
1254  * We only allow casts from prefixes to addresses if the prefix is the the length of
1255  * the address, e.g. 32 for ipv4 128 for ipv6.
1256  */
1257  {
1258  /*
1259  * 10 bytes of 0x00 2 bytes of 0xff
1260  */
1261  static uint8_t const v4_v6_map[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1262  0x00, 0x00, 0x00, 0x00, 0xff, 0xff };
1263 
1264  switch (dst_type) {
1265  case PW_TYPE_IPV4_ADDR:
1266  switch (src_type) {
1267  case PW_TYPE_IPV6_ADDR:
1268  if (memcmp(src->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
1269  bad_v6_prefix_map:
1270  fr_strerror_printf("Invalid cast from %s to %s. No IPv4-IPv6 mapping prefix",
1271  fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1272  fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1273  return -1;
1274  }
1275 
1276  memcpy(&dst->ipaddr, &src->ipv6addr.s6_addr[sizeof(v4_v6_map)],
1277  sizeof(dst->ipaddr));
1278  goto fixed_length;
1279 
1280  case PW_TYPE_IPV4_PREFIX:
1281  if (src->ipv4prefix[1] != 32) {
1282  bad_v4_prefix_len:
1283  fr_strerror_printf("Invalid cast from %s to %s. Only /32 prefixes may be "
1284  "cast to IP address types",
1285  fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1286  fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1287  return -1;
1288  }
1289 
1290  memcpy(&dst->ipaddr, &src->ipv4prefix[2], sizeof(dst->ipaddr));
1291  goto fixed_length;
1292 
1293  case PW_TYPE_IPV6_PREFIX:
1294  if (src->ipv6prefix[1] != 128) {
1295  bad_v6_prefix_len:
1296  fr_strerror_printf("Invalid cast from %s to %s. Only /128 prefixes may be "
1297  "cast to IP address types",
1298  fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1299  fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1300  return -1;
1301  }
1302  if (memcmp(&src->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map)) != 0) {
1303  goto bad_v6_prefix_map;
1304  }
1305  memcpy(&dst->ipaddr, &src->ipv6prefix[2 + sizeof(v4_v6_map)],
1306  sizeof(dst->ipaddr));
1307  goto fixed_length;
1308 
1309  default:
1310  break;
1311  }
1312  break;
1313 
1314  case PW_TYPE_IPV6_ADDR:
1315  switch (src_type) {
1316  case PW_TYPE_IPV4_ADDR:
1317  /* Add the v4/v6 mapping prefix */
1318  memcpy(dst->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map));
1319  memcpy(&dst->ipv6addr.s6_addr[sizeof(v4_v6_map)], &src->ipaddr,
1320  sizeof(dst->ipv6addr.s6_addr) - sizeof(v4_v6_map));
1321 
1322  goto fixed_length;
1323 
1324  case PW_TYPE_IPV4_PREFIX:
1325  if (src->ipv4prefix[1] != 32) goto bad_v4_prefix_len;
1326 
1327  /* Add the v4/v6 mapping prefix */
1328  memcpy(dst->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map));
1329  memcpy(&dst->ipv6addr.s6_addr[sizeof(v4_v6_map)], &src->ipv4prefix[2],
1330  sizeof(dst->ipv6addr.s6_addr) - sizeof(v4_v6_map));
1331  goto fixed_length;
1332 
1333  case PW_TYPE_IPV6_PREFIX:
1334  if (src->ipv4prefix[1] != 128) goto bad_v6_prefix_len;
1335 
1336  memcpy(dst->ipv6addr.s6_addr, &src->ipv6prefix[2], sizeof(dst->ipv6addr.s6_addr));
1337  goto fixed_length;
1338 
1339  default:
1340  break;
1341  }
1342  break;
1343 
1344  case PW_TYPE_IPV4_PREFIX:
1345  switch (src_type) {
1346  case PW_TYPE_IPV4_ADDR:
1347  memcpy(&dst->ipv4prefix[2], &src->ipaddr, sizeof(dst->ipv4prefix) - 2);
1348  dst->ipv4prefix[0] = 0;
1349  dst->ipv4prefix[1] = 32;
1350  goto fixed_length;
1351 
1352  case PW_TYPE_IPV6_ADDR:
1353  if (memcmp(src->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
1354  goto bad_v6_prefix_map;
1355  }
1356  memcpy(&dst->ipv4prefix[2], &src->ipv6addr.s6_addr[sizeof(v4_v6_map)],
1357  sizeof(dst->ipv4prefix) - 2);
1358  dst->ipv4prefix[0] = 0;
1359  dst->ipv4prefix[1] = 32;
1360  goto fixed_length;
1361 
1362  case PW_TYPE_IPV6_PREFIX:
1363  if (memcmp(&src->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map)) != 0) {
1364  goto bad_v6_prefix_map;
1365  }
1366 
1367  /*
1368  * Prefix must be >= 96 bits. If it's < 96 bytes and the
1369  * above check passed, the v6 address wasn't masked
1370  * correctly when it was packet into a value_data_t.
1371  */
1372  if (!fr_assert(src->ipv6prefix[1] >= (sizeof(v4_v6_map) * 8))) return -1;
1373 
1374  memcpy(&dst->ipv4prefix[2], &src->ipv6prefix[2 + sizeof(v4_v6_map)],
1375  sizeof(dst->ipv4prefix) - 2);
1376  dst->ipv4prefix[0] = 0;
1377  dst->ipv4prefix[1] = src->ipv6prefix[1] - (sizeof(v4_v6_map) * 8);
1378  goto fixed_length;
1379 
1380  default:
1381  break;
1382  }
1383  break;
1384 
1385  case PW_TYPE_IPV6_PREFIX:
1386  switch (src_type) {
1387  case PW_TYPE_IPV4_ADDR:
1388  /* Add the v4/v6 mapping prefix */
1389  memcpy(&dst->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map));
1390  memcpy(&dst->ipv6prefix[2 + sizeof(v4_v6_map)], &src->ipaddr,
1391  (sizeof(dst->ipv6prefix) - 2) - sizeof(v4_v6_map));
1392  dst->ipv6prefix[0] = 0;
1393  dst->ipv6prefix[1] = 128;
1394  goto fixed_length;
1395 
1396  case PW_TYPE_IPV4_PREFIX:
1397  /* Add the v4/v6 mapping prefix */
1398  memcpy(&dst->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map));
1399  memcpy(&dst->ipv6prefix[2 + sizeof(v4_v6_map)], &src->ipv4prefix[2],
1400  (sizeof(dst->ipv6prefix) - 2) - sizeof(v4_v6_map));
1401  dst->ipv6prefix[0] = 0;
1402  dst->ipv6prefix[1] = (sizeof(v4_v6_map) * 8) + src->ipv4prefix[1];
1403  goto fixed_length;
1404 
1405  case PW_TYPE_IPV6_ADDR:
1406  memcpy(&dst->ipv6prefix[2], &src->ipv6addr, sizeof(dst->ipv6prefix) - 2);
1407  dst->ipv6prefix[0] = 0;
1408  dst->ipv6prefix[1] = 128;
1409  goto fixed_length;
1410 
1411  default:
1412  break;
1413  }
1414 
1415  break;
1416 
1417  default:
1418  break;
1419  }
1420  }
1421 
1422  /*
1423  * The attribute we've found has to have a size which is
1424  * compatible with the type of the destination cast.
1425  */
1426  if ((src->length < dict_attr_sizes[dst_type][0]) ||
1427  (src->length > dict_attr_sizes[dst_type][1])) {
1428  char const *src_type_name;
1429 
1430  src_type_name = fr_int2str(dict_attr_types, src_type, "<INVALID>");
1431  fr_strerror_printf("Invalid cast from %s to %s. Length should be between %zu and %zu but is %zu",
1432  src_type_name,
1433  fr_int2str(dict_attr_types, dst_type, "<INVALID>"),
1434  dict_attr_sizes[dst_type][0], dict_attr_sizes[dst_type][1],
1435  src->length);
1436  return -1;
1437  }
1438 
1439  if (src_type == PW_TYPE_OCTETS) {
1440  do_octets:
1441  value_data_hton(dst, dst_type, src->octets, src->length);
1442  dst->length = src->length;
1443  return 0;
1444  }
1445 
1446  /*
1447  * Convert host order to network byte order.
1448  */
1449  if ((dst_type == PW_TYPE_IPV4_ADDR) &&
1450  ((src_type == PW_TYPE_INTEGER) ||
1451  (src_type == PW_TYPE_DATE) ||
1452  (src_type == PW_TYPE_SIGNED))) {
1453  dst->ipaddr.s_addr = htonl(src->integer);
1454 
1455  } else if ((src_type == PW_TYPE_IPV4_ADDR) &&
1456  ((dst_type == PW_TYPE_INTEGER) ||
1457  (dst_type == PW_TYPE_DATE) ||
1458  (dst_type == PW_TYPE_SIGNED))) {
1459  dst->integer = htonl(src->ipaddr.s_addr);
1460 
1461  } else { /* they're of the same byte order */
1462  memcpy(&dst, &src, src->length);
1463  }
1464  dst->length = src->length;
1465 
1466  return 0;
1467 }
1468 
1469 /** Copy value data verbatim duplicating any buffers
1470  *
1471  * @param ctx To allocate buffers in.
1472  * @param dst Where to copy value_data to.
1473  * @param src_type Type of src.
1474  * @param src Where to copy value_data from.
1475  * @return
1476  * - 0 on success.
1477  * - -1 on failure.
1478  */
1479 int value_data_copy(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE src_type, const value_data_t *src)
1480 {
1481  switch (src_type) {
1482  default:
1483  memcpy(dst, src, sizeof(*dst));
1484  break;
1485 
1486  case PW_TYPE_STRING:
1487  dst->strvalue = talloc_bstrndup(ctx, src->strvalue, src->length);
1488  if (!dst->strvalue) return -1;
1489  break;
1490 
1491  case PW_TYPE_OCTETS:
1492  dst->octets = talloc_memdup(ctx, src->octets, src->length);
1493  talloc_set_type(dst->strvalue, uint8_t);
1494  if (!dst->octets) return -1;
1495  break;
1496  }
1497  dst->length = src->length;
1498 
1499  return 0;
1500 }
1501 
1502 /** Copy value data verbatim moving any buffers to the specified context
1503  *
1504  * @param ctx To allocate buffers in.
1505  * @param dst Where to copy value_data to.
1506  * @param src_type Type of src.
1507  * @param src Where to copy value_data from.
1508  * @return
1509  * - 0 on success.
1510  * - -1 on failure.
1511  */
1512 int value_data_steal(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE src_type, const value_data_t *src)
1513 {
1514  switch (src_type) {
1515  default:
1516  memcpy(dst, src, sizeof(*src));
1517  break;
1518 
1519  case PW_TYPE_STRING:
1520  dst->strvalue = talloc_steal(ctx, src->strvalue);
1521  if (!dst->strvalue) {
1522  fr_strerror_printf("Failed stealing string buffer");
1523  return -1;
1524  }
1525  break;
1526 
1527  case PW_TYPE_OCTETS:
1528  dst->octets = talloc_steal(ctx, src->octets);
1529  if (!dst->octets) {
1530  fr_strerror_printf("Failed stealing octets buffer");
1531  return -1;
1532  }
1533  break;
1534  }
1535  dst->length = src->length;
1536 
1537  return 0;
1538 }
1539 
1540 /** Print one attribute value to a string
1541  *
1542  */
1543 char *value_data_asprint(TALLOC_CTX *ctx,
1544  PW_TYPE type, fr_dict_attr_t const *enumv, value_data_t const *data, char quote)
1545 {
1546  char *p = NULL;
1547  unsigned int i;
1548 
1549  switch (type) {
1550  case PW_TYPE_STRING:
1551  {
1552  size_t len, ret;
1553 
1554  if (!quote) {
1555  p = talloc_bstrndup(ctx, data->strvalue, data->length);
1556  if (!p) return NULL;
1557  talloc_set_type(p, char);
1558  return p;
1559  }
1560 
1561  /* Gets us the size of the buffer we need to alloc */
1562  len = fr_snprint_len(data->strvalue, data->length, quote);
1563  p = talloc_array(ctx, char, len);
1564  if (!p) return NULL;
1565 
1566  ret = fr_snprint(p, len, data->strvalue, data->length, quote);
1567  if (!fr_assert(ret == (len - 1))) {
1568  talloc_free(p);
1569  return NULL;
1570  }
1571  break;
1572  }
1573 
1574  case PW_TYPE_INTEGER:
1575  i = data->integer;
1576  goto print_int;
1577 
1578  case PW_TYPE_SHORT:
1579  i = data->ushort;
1580  goto print_int;
1581 
1582  case PW_TYPE_BYTE:
1583  i = data->byte;
1584 
1585  print_int:
1586  {
1587  fr_dict_enum_t const *dv;
1588 
1589  if (enumv && (dv = fr_dict_enum_by_da(NULL, enumv, i))) {
1590  p = talloc_typed_strdup(ctx, dv->name);
1591  } else {
1592  p = talloc_typed_asprintf(ctx, "%u", i);
1593  }
1594  }
1595  break;
1596 
1597  case PW_TYPE_SIGNED:
1598  p = talloc_typed_asprintf(ctx, "%d", data->sinteger);
1599  break;
1600 
1601  case PW_TYPE_INTEGER64:
1602  p = talloc_typed_asprintf(ctx, "%" PRIu64 , data->integer64);
1603  break;
1604 
1605  case PW_TYPE_ETHERNET:
1606  p = talloc_typed_asprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
1607  data->ether[0], data->ether[1],
1608  data->ether[2], data->ether[3],
1609  data->ether[4], data->ether[5]);
1610  break;
1611 
1612  case PW_TYPE_ABINARY:
1613 #ifdef WITH_ASCEND_BINARY
1614  p = talloc_array(ctx, char, 128);
1615  if (!p) return NULL;
1616  print_abinary(p, 128, (uint8_t const *) &data->filter, data->length, 0);
1617  break;
1618 #else
1619  /* FALL THROUGH */
1620 #endif
1621 
1622  case PW_TYPE_OCTETS:
1623  p = talloc_array(ctx, char, 2 + 1 + data->length * 2);
1624  if (!p) return NULL;
1625  p[0] = '0';
1626  p[1] = 'x';
1627 
1628  fr_bin2hex(p + 2, data->octets, data->length);
1629  break;
1630 
1631  case PW_TYPE_DATE:
1632  {
1633  time_t t;
1634  struct tm s_tm;
1635 
1636  t = data->date;
1637 
1638  p = talloc_array(ctx, char, 64);
1639  strftime(p, 64, "%b %e %Y %H:%M:%S %Z",
1640  localtime_r(&t, &s_tm));
1641  break;
1642  }
1643 
1644  /*
1645  * We need to use the proper inet_ntop functions for IP
1646  * addresses, else the output might not match output of
1647  * other functions, which makes testing difficult.
1648  *
1649  * An example is tunnelled ipv4 in ipv6 addresses.
1650  */
1651  case PW_TYPE_IPV4_ADDR:
1652  case PW_TYPE_IPV4_PREFIX:
1653  {
1654  char buff[INET_ADDRSTRLEN + 4]; // + /prefix
1655 
1656  buff[0] = '\0';
1657  value_data_snprint(buff, sizeof(buff), type, enumv, data, '\0');
1658 
1659  p = talloc_typed_strdup(ctx, buff);
1660  }
1661  break;
1662 
1663  case PW_TYPE_IPV6_ADDR:
1664  case PW_TYPE_IPV6_PREFIX:
1665  {
1666  char buff[INET6_ADDRSTRLEN + 4]; // + /prefix
1667 
1668  buff[0] = '\0';
1669  value_data_snprint(buff, sizeof(buff), type, enumv, data, '\0');
1670 
1671  p = talloc_typed_strdup(ctx, buff);
1672  }
1673  break;
1674 
1675  case PW_TYPE_IFID:
1676  p = talloc_typed_asprintf(ctx, "%x:%x:%x:%x",
1677  (data->ifid[0] << 8) | data->ifid[1],
1678  (data->ifid[2] << 8) | data->ifid[3],
1679  (data->ifid[4] << 8) | data->ifid[5],
1680  (data->ifid[6] << 8) | data->ifid[7]);
1681  break;
1682 
1683  case PW_TYPE_BOOLEAN:
1684  p = talloc_typed_strdup(ctx, data->byte ? "yes" : "no");
1685  break;
1686 
1687  case PW_TYPE_DECIMAL:
1688  p = talloc_typed_asprintf(ctx, "%g", data->decimal);
1689  break;
1690 
1691  /*
1692  * Don't add default here
1693  */
1694  case PW_TYPE_INVALID:
1695  case PW_TYPE_COMBO_IP_ADDR:
1697  case PW_TYPE_TLV:
1698  case PW_TYPE_EXTENDED:
1699  case PW_TYPE_LONG_EXTENDED:
1700  case PW_TYPE_EVS:
1701  case PW_TYPE_VSA:
1702  case PW_TYPE_VENDOR:
1703  case PW_TYPE_TIMEVAL:
1704  case PW_TYPE_MAX:
1705  fr_assert(0);
1706  return NULL;
1707  }
1708 
1709  return p;
1710 }
1711 
1712 /** Print the value of an attribute to a string
1713  *
1714  * @note return value should be checked with is_truncated.
1715  * @note Will always \0 terminate unless outlen == 0.
1716  *
1717  * @param out Where to write the printed version of the attribute value.
1718  * @param outlen Length of the output buffer.
1719  * @param type of data being printed.
1720  * @param enumv Enumerated string values for integer types.
1721  * @param data to print.
1722  * @param quote char to escape in string output.
1723  * @return
1724  * - The number of bytes written to the out buffer.
1725  * - A number >= outlen if truncation has occurred.
1726  */
1727 size_t value_data_snprint(char *out, size_t outlen,
1728  PW_TYPE type, fr_dict_attr_t const *enumv, value_data_t const *data, char quote)
1729 {
1730  fr_dict_enum_t *v;
1731  char buf[1024]; /* Interim buffer to use with poorly behaved printing functions */
1732  char const *a = NULL;
1733  char *p = out;
1734  time_t t;
1735  struct tm s_tm;
1736  unsigned int i;
1737 
1738  size_t len = 0, freespace = outlen;
1739 
1740  if (!data) return 0;
1741  if (outlen == 0) return data->length;
1742 
1743  *out = '\0';
1744 
1745  p = out;
1746 
1747  switch (type) {
1748  case PW_TYPE_STRING:
1749 
1750  /*
1751  * Ensure that WE add the quotation marks around the string.
1752  */
1753  if (quote) {
1754  if (freespace < 3) return data->length + 2;
1755 
1756  *p++ = quote;
1757  freespace--;
1758 
1759  len = fr_snprint(p, freespace, data->strvalue, data->length, quote);
1760  /* always terminate the quoted string with another quote */
1761  if (len >= (freespace - 1)) {
1762  /* Use out not p as we're operating on the entire buffer */
1763  out[outlen - 2] = (char) quote;
1764  out[outlen - 1] = '\0';
1765  return len + 2;
1766  }
1767  p += len;
1768  freespace -= len;
1769 
1770  *p++ = (char) quote;
1771  freespace--;
1772  *p = '\0';
1773 
1774  return len + 2;
1775  }
1776 
1777  return fr_snprint(out, outlen, data->strvalue, data->length, quote);
1778 
1779  case PW_TYPE_INTEGER:
1780  i = data->integer;
1781  goto print_int;
1782 
1783  case PW_TYPE_SHORT:
1784  i = data->ushort;
1785  goto print_int;
1786 
1787  case PW_TYPE_BYTE:
1788  i = data->byte;
1789 
1790 print_int:
1791  /* Normal, non-tagged attribute */
1792  if (enumv && (v = fr_dict_enum_by_da(NULL, enumv, i)) != NULL) {
1793  a = v->name;
1794  len = strlen(a);
1795  } else {
1796  /* should never be truncated */
1797  len = snprintf(buf, sizeof(buf), "%u", i);
1798  a = buf;
1799  }
1800  break;
1801 
1802  case PW_TYPE_INTEGER64:
1803  return snprintf(out, outlen, "%" PRIu64, data->integer64);
1804 
1805  case PW_TYPE_DATE:
1806  t = data->date;
1807  if (quote > 0) {
1808  len = strftime(buf, sizeof(buf) - 1, "%%%b %e %Y %H:%M:%S %Z%%", localtime_r(&t, &s_tm));
1809  buf[0] = (char) quote;
1810  buf[len - 1] = (char) quote;
1811  buf[len] = '\0';
1812  } else {
1813  len = strftime(buf, sizeof(buf), "%b %e %Y %H:%M:%S %Z", localtime_r(&t, &s_tm));
1814  }
1815  a = buf;
1816  break;
1817 
1818  case PW_TYPE_SIGNED: /* Damned code for 1 WiMAX attribute */
1819  len = snprintf(buf, sizeof(buf), "%d", data->sinteger);
1820  a = buf;
1821  break;
1822 
1823  case PW_TYPE_IPV4_ADDR:
1824  a = inet_ntop(AF_INET, &(data->ipaddr), buf, sizeof(buf));
1825  len = strlen(buf);
1826  break;
1827 
1828  case PW_TYPE_ABINARY:
1829 #ifdef WITH_ASCEND_BINARY
1830  print_abinary(buf, sizeof(buf), (uint8_t const *) data->filter, data->length, quote);
1831  a = buf;
1832  len = strlen(buf);
1833  break;
1834 #else
1835  /* FALL THROUGH */
1836 #endif
1837  case PW_TYPE_OCTETS:
1838  case PW_TYPE_TLV:
1839  {
1840  size_t max;
1841 
1842  /* Return the number of bytes we would have written */
1843  len = (data->length * 2) + 2;
1844  if (freespace <= 1) {
1845  return len;
1846  }
1847 
1848  *out++ = '0';
1849  freespace--;
1850 
1851  if (freespace <= 1) {
1852  *out = '\0';
1853  return len;
1854  }
1855  *out++ = 'x';
1856  freespace--;
1857 
1858  if (freespace <= 2) {
1859  *out = '\0';
1860  return len;
1861  }
1862 
1863  /* Get maximum number of bytes we can encode given freespace */
1864  max = ((freespace % 2) ? freespace - 1 : freespace - 2) / 2;
1865  fr_bin2hex(out, data->octets, ((size_t)data->length > max) ? max : (size_t)data->length);
1866  }
1867  return len;
1868 
1869  case PW_TYPE_IFID:
1870  a = fr_inet_ifid_ntop(buf, sizeof(buf), data->ifid);
1871  len = strlen(buf);
1872  break;
1873 
1874  case PW_TYPE_IPV6_ADDR:
1875  a = inet_ntop(AF_INET6, &data->ipv6addr, buf, sizeof(buf));
1876  len = strlen(buf);
1877  break;
1878 
1879  case PW_TYPE_IPV6_PREFIX:
1880  {
1881  struct in6_addr addr;
1882 
1883  /*
1884  * Alignment issues.
1885  */
1886  memcpy(&addr, &(data->ipv6prefix[2]), sizeof(addr));
1887 
1888  a = inet_ntop(AF_INET6, &addr, buf, sizeof(buf));
1889  if (a) {
1890  p = buf;
1891 
1892  len = strlen(buf);
1893  p += len;
1894  len += snprintf(p, sizeof(buf) - len, "/%u", (unsigned int) data->ipv6prefix[1]);
1895  }
1896  }
1897  break;
1898 
1899  case PW_TYPE_IPV4_PREFIX:
1900  {
1901  struct in_addr addr;
1902 
1903  /*
1904  * Alignment issues.
1905  */
1906  memcpy(&addr, &(data->ipv4prefix[2]), sizeof(addr));
1907 
1908  a = inet_ntop(AF_INET, &addr, buf, sizeof(buf));
1909  if (a) {
1910  p = buf;
1911 
1912  len = strlen(buf);
1913  p += len;
1914  len += snprintf(p, sizeof(buf) - len, "/%u", (unsigned int) (data->ipv4prefix[1] & 0x3f));
1915  }
1916  }
1917  break;
1918 
1919  case PW_TYPE_ETHERNET:
1920  return snprintf(out, outlen, "%02x:%02x:%02x:%02x:%02x:%02x",
1921  data->ether[0], data->ether[1],
1922  data->ether[2], data->ether[3],
1923  data->ether[4], data->ether[5]);
1924 
1925  case PW_TYPE_DECIMAL:
1926  return snprintf(out, outlen, "%g", data->decimal);
1927 
1928  /*
1929  * Don't add default here
1930  */
1931  case PW_TYPE_INVALID:
1932  case PW_TYPE_COMBO_IP_ADDR:
1934  case PW_TYPE_EXTENDED:
1935  case PW_TYPE_LONG_EXTENDED:
1936  case PW_TYPE_EVS:
1937  case PW_TYPE_VSA:
1938  case PW_TYPE_VENDOR:
1939  case PW_TYPE_TIMEVAL:
1940  case PW_TYPE_BOOLEAN:
1941  case PW_TYPE_MAX:
1942  fr_assert(0);
1943  *out = '\0';
1944  return 0;
1945  }
1946 
1947  if (a) strlcpy(out, a, outlen);
1948 
1949  return len; /* Return the number of bytes we would of written (for truncation detection) */
1950 }
1951 
128 Bit IPv6 Address.
Definition: radius.h:40
#define PW_TYPE_BOUNDED
Match all fixed length types in case statements.
Definition: value.c:410
Definition: token.h:47
Time value (struct timeval), only for config items.
Definition: radius.h:55
#define PW_TYPE_STRUCTURAL
Match all non value types in case statements.
Definition: radius.h:82
Dictionary attribute.
Definition: dict.h:77
int fr_inet_hton(fr_ipaddr_t *out, int af, char const *hostname, bool fallback)
Wrappers for IPv4/IPv6 host to IP address lookup.
Definition: inet.c:127
Ascend binary format a packed data structure.
Definition: radius.h:37
static struct cmp * cmp
Definition: pair.c:45
32 Bit signed integer.
Definition: radius.h:45
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
Definition: inet.h:47
WiMAX IPv4 or IPv6 address depending on length.
Definition: radius.h:46
const size_t dict_attr_sizes[PW_TYPE_MAX][2]
Map data types to min / max data sizes.
Definition: dict.c:119
static char const hextab[]
Definition: value.c:439
static int value_data_cidr_cmp_op(FR_TOKEN op, int bytes, uint8_t a_net, uint8_t const *a, uint8_t b_net, uint8_t const *b)
Definition: value.c:180
static void value_data_hton(value_data_t *dst, PW_TYPE type, void const *src, size_t src_len)
Performs byte order reversal for types that need it.
Definition: value.c:1028
IPv6 Prefix.
Definition: radius.h:41
char const * inet_ntop(int af, void const *src, char *dst, size_t cnt)
Definition: missing.c:538
#define PW_TYPE_BAD
Definition: radius.h:62
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:686
Number of defined data types.
Definition: radius.h:59
uint8_t length
Definition: proto_bfd.c:203
int value_data_copy(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE src_type, const value_data_t *src)
Copy value data verbatim duplicating any buffers.
Definition: value.c:1479
Long extended attribute space attribute.
Definition: radius.h:49
int fr_get_time(char const *date_str, time_t *date)
Convert string in various formats to a time_t.
Definition: misc.c:716
int value_data_cmp(PW_TYPE a_type, value_data_t const *a, PW_TYPE b_type, value_data_t const *b)
Compare two values.
Definition: value.c:40
fr_dict_enum_t * fr_dict_enum_by_name(fr_dict_t *dict, fr_dict_attr_t const *da, char const *val)
Definition: dict.c:3703
size_t fr_snprint(char *out, size_t outlen, char const *in, ssize_t inlen, char quote)
Escape any non printable or non-UTF8 characters in the input string.
Definition: print.c:179
WiMAX IPv4 or IPv6 address prefix depending on length.
Definition: radius.h:57
size_t fr_snprint_len(char const *in, ssize_t inlen, char quote)
Find the length of the buffer required to fully escape a string with fr_prints.
Definition: print.c:371
bool is_integer(char const *value)
Check whether the string is all numbers.
Definition: misc.c:350
char * fr_inet_ifid_ntop(char *out, size_t outlen, uint8_t const *ifid)
Print an interface-id in standard colon notation.
Definition: inet.c:788
#define CHECK(_type)
Definition: token.h:50
#define PW_TYPE_UNBOUNDED
Match all variable length types in case statements.
Definition: value.c:430
8 Bit unsigned integer.
Definition: radius.h:42
static uint32_t mask
Definition: rbmonkey.c:75
Interface ID.
Definition: radius.h:39
const FR_NAME_NUMBER dict_attr_types[]
Map data types to names representing those types.
Definition: dict.c:85
size_t fr_hex2bin(uint8_t *bin, size_t outlen, char const *hex, size_t inlen)
Convert hex strings to binary data.
Definition: misc.c:220
Double precision floating point.
Definition: radius.h:58
union fr_ipaddr_t::@1 ipaddr
#define fr_assert(_x)
Definition: libradius.h:505
Definition: token.h:49
48 Bit Mac-Address.
Definition: radius.h:44
Attribute that represents a vendor in the attribute tree.
Definition: radius.h:54
int value_data_steal(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE src_type, const value_data_t *src)
Copy value data verbatim moving any buffers to the specified context.
Definition: value.c:1512
char * talloc_typed_asprintf(void const *t, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition: missing.c:611
int fr_inet_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback, bool mask)
Parse an IPv4 address or IPv4 prefix in presentation format (and others)
Definition: inet.c:348
#define PW_TYPE_STRUCTURAL_EXCEPT_VSA
Stupid hack for things which produce special error messages for VSAs.
Definition: radius.h:71
Invalid (uninitialised) attribute type.
Definition: radius.h:32
bool is_whitespace(char const *value)
Check whether the string is all whitespace.
Definition: misc.c:311
size_t value_data_snprint(char *out, size_t outlen, PW_TYPE type, fr_dict_attr_t const *enumv, value_data_t const *data, char quote)
Print the value of an attribute to a string.
Definition: value.c:1727
A truth value.
Definition: radius.h:56
32 Bit unsigned integer.
Definition: radius.h:34
int inet_pton(int af, char const *src, void *dst)
Definition: missing.c:522
char name[1]
Enum name.
Definition: dict.h:97
64 Bit unsigned integer.
Definition: radius.h:51
Definition: token.h:48
Vendor-Specific, for RADIUS attribute 26.
Definition: radius.h:53
char * value_data_asprint(TALLOC_CTX *ctx, PW_TYPE type, fr_dict_attr_t const *enumv, value_data_t const *data, char quote)
Print one attribute value to a string.
Definition: value.c:1543
char name[1]
Attribute name.
Definition: dict.h:89
uint8_t data[]
Definition: eap_pwd.h:625
size_t length
Length of value data.
Definition: pair.h:87
char * talloc_bstrndup(void const *t, char const *in, size_t inlen)
Binary safe strndup function.
Definition: missing.c:632
32 Bit Unix timestamp.
Definition: radius.h:36
Extended attribute space attribute.
Definition: radius.h:48
bool fr_hostname_lookups
hostname -> IP lookups?
Definition: inet.c:29
uint32_t fr_strtoul(char const *value, char **end)
Consume the integer (or hex) portion of a value string.
Definition: misc.c:296
int strncasecmp(char *s1, char *s2, int n)
Definition: missing.c:43
PRIVATE void decimal(struct DATA *p, double d)
Definition: snprintf.c:254
uint8_t * fr_inet_ifid_pton(uint8_t out[8], char const *ifid_str)
Convert interface-id in colon notation to 8 byte binary form.
Definition: inet.c:802
fr_dict_enum_t * fr_dict_enum_by_da(fr_dict_t *dict, fr_dict_attr_t const *da, int value)
Lookup the structure representing an enum value in a fr_dict_attr_t.
Definition: dict.c:3654
int value
Enum value.
Definition: dict.h:96
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
IPv4 Prefix.
Definition: radius.h:52
enum fr_token FR_TOKEN
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:38
int value_data_cmp_op(FR_TOKEN op, PW_TYPE a_type, value_data_t const *a, PW_TYPE b_type, value_data_t const *b)
Compare two attributes using an operator.
Definition: value.c:299
IPv4/6 prefix.
Definition: inet.h:41
Definition: pair.c:37
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)
Definition: token.c:506
String of printable characters.
Definition: radius.h:33
Contains nested attributes.
Definition: radius.h:47
int fr_inet_pton6(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback, bool mask)
Parse an IPv6 address or IPv6 prefix in presentation format (and others)
Definition: inet.c:465
struct tm * localtime_r(time_t const *l_clock, struct tm *result)
Definition: missing.c:152
#define RCSID(id)
Definition: build.h:135
int value_data_cast(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE dst_type, fr_dict_attr_t const *dst_enumv, PW_TYPE src_type, fr_dict_attr_t const *src_enumv, value_data_t const *src)
Convert one type of value_data_t to another.
Definition: value.c:1073
Definition: token.h:51
char * talloc_typed_strdup(void const *t, char const *p)
Call talloc strdup, setting the type on the new chunk correctly.
Definition: missing.c:588
32 Bit IPv4 Address.
Definition: radius.h:35
size_t fr_bin2hex(char *hex, uint8_t const *bin, size_t inlen)
Convert binary data to a hex string.
Definition: misc.c:254
Value of an enumerated attribute.
Definition: dict.h:94
16 Bit unsigned integer.
Definition: radius.h:43
Raw octets.
Definition: radius.h:38
int value_data_from_str(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE *src_type, fr_dict_attr_t const *src_enumv, char const *src, ssize_t src_len, char quote)
Convert string value to a value_data_t type.
Definition: value.c:455
PW_TYPE
Internal data types used within libfreeradius.
Definition: radius.h:31
Extended attribute, vendor specific.
Definition: radius.h:50