The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
json.c
Go to the documentation of this file.
1/*
2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 6dce13eeb977662a2fae15d213ce0e4c02b5af84 $
19 * @file json.c
20 * @brief Common functions for working with json-c
21 *
22 * @author Arran Cudbard-Bell
23 * @author Matthew Newton
24 *
25 * @copyright 2015 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
26 * @copyright 2015,2020 Network RADIUS SAS (legal@networkradius.com)
27 * @copyright 2015 The FreeRADIUS Server Project
28 */
29#include <freeradius-devel/util/debug.h>
30#include <freeradius-devel/util/base16.h>
31#include <freeradius-devel/util/base64.h>
32#include <freeradius-devel/util/types.h>
33#include <freeradius-devel/util/value.h>
34#include "base.h"
35#include "lib/util/strerror.h"
36
38 { L("array"), JSON_MODE_ARRAY },
39 { L("array_of_names"), JSON_MODE_ARRAY_OF_NAMES },
40 { L("array_of_values"), JSON_MODE_ARRAY_OF_VALUES },
41 { L("object"), JSON_MODE_OBJECT },
42 { L("object_simple"), JSON_MODE_OBJECT_SIMPLE },
43};
45
52
54 .attr = { .prefix = NULL },
55 .value = { .value_is_always_array = true },
56 .output_mode = JSON_MODE_OBJECT
57};
58
63
65 { FR_CONF_OFFSET("single_value_as_array", fr_json_format_value_t, value_is_always_array), .dflt = "no" },
66 { FR_CONF_OFFSET("enum_as_integer", fr_json_format_value_t, enum_as_int), .dflt = "no" },
67 { FR_CONF_OFFSET("always_string", fr_json_format_value_t, always_string), .dflt = "no" },
68 { FR_CONF_OFFSET("binary_format", fr_json_format_value_t, binary_format), .dflt = "raw",
72};
73
75 { FR_CONF_OFFSET("output_mode", fr_json_format_t, output_mode_str), .dflt = "object" },
78
80};
81
82static inline CC_HINT(always_inline)
83void json_object_put_assert(json_object *obj)
84{
85 int ret;
86
87 ret = json_object_put(obj);
88 if (ret == 1) return;
89
90 fr_assert_fail("json_object_put did not free object (returned %d), likely leaking memory", ret);
91}
92
93/** Convert json object to fr_value_box_t
94 *
95 * @param[in] ctx to allocate any value buffers in (should usually be the same as out).
96 * @param[in] out Where to write value. Must be initialised.
97 * @param[in] object to convert.
98 * @param[in] enumv Any string values are assumed to be in PRESENTATION format, meaning
99 * that if an enumv is specified, they'll be checked against the list
100 * of aliases for that enumeration, and possibly converted into one of
101 * the enumeration values (which may not be a string).
102 * @param[in] tainted Whether the data source is untrusted.
103 * @return
104 * - 0 on success.
105 * - -1 on failure.
106 */
107int fr_json_object_to_value_box(TALLOC_CTX *ctx, fr_value_box_t *out, json_object *object,
108 fr_dict_attr_t const *enumv, bool tainted)
109{
110 switch (json_object_get_type(object)) {
111 case json_type_string:
112 {
113 char const *value;
114 size_t len;
115 fr_dict_enum_value_t const *found;
116
117 value = json_object_get_string(object);
118 len = json_object_get_string_len(object);
119
120 if (!enumv) goto no_enumv;
121
122 if (fr_dict_valid_name(value, len) < 0) goto no_enumv;
123
124 /*
125 * If an alias exists, use that value instead
126 */
127 found = fr_dict_enum_by_name(enumv, value, len);
128 if (found) {
129 if (unlikely(fr_value_box_copy(ctx, out, found->value)) < 0) return -1;
130 return 0;
131 }
132
133 no_enumv:
134 /*
135 * Just copy the string to the box.
136 */
137 fr_value_box_bstrndup(out, out, NULL, value, len, tainted);
138 }
139 break;
140
141 case json_type_double:
142 fr_value_box(out, json_object_get_double(object), tainted);
143 break;
144
145 case json_type_int:
146 {
147#ifdef HAVE_JSON_OBJECT_GET_INT64
148 int64_t num;
149#else
150 int32_t num;
151#endif
152
153#ifndef HAVE_JSON_OBJECT_GET_INT64
154 num = json_object_get_int(object);
155#else
156 num = json_object_get_int64(object);
157 if (num < INT32_MIN) { /* 64bit signed*/
158 fr_value_box(out, (int64_t)num, tainted);
159 } else if (num > UINT32_MAX) { /* 64bit unsigned */
160 fr_value_box(out, (uint64_t)num, tainted);
161 } else
162#endif
163 if (num < INT16_MIN) { /* 32bit signed */
164 fr_value_box(out, (int32_t)num, tainted);
165 } else if (num < INT8_MIN) { /* 16bit signed */
166 fr_value_box(out, (int16_t)num, tainted);
167 } else if (num < 0) { /* 8bit signed */
168 fr_value_box(out, (int8_t)num, tainted);
169 } else if (num > UINT16_MAX) { /* 32bit unsigned */
170 fr_value_box(out, (uint32_t)num, tainted);
171 } else if (num > UINT8_MAX) { /* 16bit unsigned */
172 fr_value_box(out, (uint16_t)num, tainted);
173 } else { /* 8bit unsigned */
174 fr_value_box(out, (uint8_t)num, tainted);
175 }
176 }
177 break;
178
179 case json_type_boolean:
180 /* Must be cast to bool for correct generic case selection */
181 fr_value_box(out, ((bool)(json_object_get_boolean(object) > 0)), tainted);
182 break;
183
184 case json_type_null:
185 case json_type_array:
186 case json_type_object:
187 {
188 char const *value = json_object_to_json_string(object);
189
190 fr_value_box_bstrndup(out, out, NULL, value, strlen(value), tainted);
191 }
192 break;
193 }
194
195 out->tainted = tainted;
196
197 return 0;
198}
199
200/** Convert boxed value_box to a JSON object
201 *
202 * @param[in] data to convert.
203 */
205{
206 /*
207 * We're converting to PRESENTATION format
208 * so any attributes with enumeration values
209 * should be converted to string types.
210 */
211 if (data->enumv) {
212 fr_dict_enum_value_t const *enumv;
213
214 enumv = fr_dict_enum_by_value(data->enumv, data);
215 if (enumv) return json_object_new_string(enumv->name);
216 }
217
218 switch (data->type) {
219 default:
220 do_string:
221 {
222 char buffer[64];
223 fr_sbuff_t sbuff = FR_SBUFF_OUT(buffer, sizeof(buffer));
224
225 if (fr_value_box_print(&sbuff, data, NULL) <= 0) return NULL;
226
227 return json_object_new_string_len(buffer, fr_sbuff_used(&sbuff));
228 }
229
230 case FR_TYPE_STRING:
231 return json_object_new_string_len(data->vb_strvalue, data->vb_length);
232
233 case FR_TYPE_OCTETS:
234 return json_object_new_string_len((char const *)data->vb_octets, data->vb_length);
235
236 case FR_TYPE_BOOL:
237 return json_object_new_boolean(data->vb_bool);
238
239 case FR_TYPE_UINT8:
240 return json_object_new_int(data->vb_uint8);
241
242 case FR_TYPE_UINT16:
243 return json_object_new_int(data->vb_uint16);
244
245#ifdef HAVE_JSON_OBJECT_GET_INT64
246 case FR_TYPE_UINT32:
247 return json_object_new_int64((int64_t)data->vb_uint32); /* uint32_t (max) > int32_t (max) */
248
249 case FR_TYPE_UINT64:
250 if (data->vb_uint64 > INT64_MAX) goto do_string;
251 return json_object_new_int64(data->vb_uint64);
252#else
253 case FR_TYPE_UINT32:
254 if (data->vb_uint32 > INT32_MAX) goto do_string;
255 return json_object_new_int(data->vb_uint32);
256#endif
257
258 case FR_TYPE_INT8:
259 return json_object_new_int(data->vb_int8);
260
261 case FR_TYPE_INT16:
262 return json_object_new_int(data->vb_int16);
263
264 case FR_TYPE_INT32:
265 return json_object_new_int(data->vb_int32);
266
267#ifdef HAVE_JSON_OBJECT_GET_INT64
268 case FR_TYPE_INT64:
269 return json_object_new_int64(data->vb_int64);
270
271 case FR_TYPE_SIZE:
272 return json_object_new_int64(data->vb_size);
273#endif
274
276 fr_strerror_const("Can't convert structural type to JSON");
277 return NULL;
278 }
279}
280
281/** Print a value box as its equivalent JSON format without going via a struct json_object (in most cases)
282 *
283 * @param[out] out buffer to write to.
284 * @param[in] vb to print.
285 * @param[in] include_quotes whether we should wrap string values,
286 * or non-native types like IPv4 addresses in quotes.
287 * @return
288 * - <0 on error.
289 * - >= number of bytes written.
290 */
292{
293 fr_sbuff_t our_out = FR_SBUFF(out);
294
295 switch (vb->type) {
296 case FR_TYPE_NULL:
297 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "null");
298 break;
299
300 case FR_TYPE_BOOL:
301 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, vb->vb_bool ? "true" : "false");
302 break;
303
304 /*
305 * This is identical to JSON-C's escaping function
306 * but we avoid creating JSON objects just to be able
307 * to escape strings.
308 */
309 case FR_TYPE_STRING:
310 case FR_TYPE_OCTETS:
311 {
312 char const *last_app, *p, *end;
313
314 if (include_quotes) FR_SBUFF_IN_CHAR_RETURN(&our_out, '"');
315
316 last_app = p = vb->vb_strvalue;
317 end = p + vb->vb_length;
318
319 while (p < end) {
320 if ((*p < ' ') || (*p == '"') || (*p == '\\') || (*p == '/')) {
321 if (p > last_app) FR_SBUFF_IN_BSTRNCPY_RETURN(&our_out, last_app, p - last_app);
322
323 switch (*p) {
324 case '\b':
325 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "\\b");
326 break;
327
328 case '\n':
329 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "\\n");
330 break;
331
332 case '\r':
333 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "\\r");
334 break;
335
336 case '\t':
337 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "\\t");
338 break;
339
340 case '\f':
341 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "\\f");
342 break;
343
344 case '"':
345 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "\\\"");
346 break;
347
348 case '\\':
349 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "\\\\");
350 break;
351
352 case '/':
353 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "\\/");
354 break;
355
356 default:
357 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "\\u00");
358 fr_base16_encode(&our_out, &FR_DBUFF_TMP((uint8_t const *)p, 1));
359 }
360
361 last_app = p + 1;
362 }
363 p++;
364 }
365 if (end > last_app) FR_SBUFF_IN_BSTRNCPY_RETURN(&our_out, last_app, end - last_app);
366 if (include_quotes) FR_SBUFF_IN_CHAR_RETURN(&our_out, '"');
367 }
368 break;
369
370 case FR_TYPE_UINT8:
371 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", vb->vb_uint8);
372 break;
373
374 case FR_TYPE_UINT16:
375 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", vb->vb_uint16);
376 break;
377
378 case FR_TYPE_UINT32:
379 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", vb->vb_uint32);
380 break;
381
382 case FR_TYPE_UINT64:
383 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%" PRIu64, vb->vb_uint64);
384 break;
385
386 case FR_TYPE_INT8:
387 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%i", vb->vb_int8);
388 break;
389
390 case FR_TYPE_INT16:
391 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%i", vb->vb_int16);
392 break;
393
394 case FR_TYPE_INT32:
395 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%i", vb->vb_int32);
396 break;
397
398 case FR_TYPE_INT64:
399 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%" PRIi64, vb->vb_int64);
400 break;
401
402 case FR_TYPE_SIZE:
403 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%zu", vb->vb_size);
404 break;
405
406 /*
407 * It's too complex to replicate the float/double printing
408 * here, so pass it off to JSON-C's printing functions.
409 */
410 case FR_TYPE_FLOAT32:
411 {
412 struct json_object *obj;
413 fr_slen_t slen;
414
415 obj = json_object_new_double((double)vb->vb_float32);
416 if (unlikely(obj == NULL)) return -1;
417 slen = fr_sbuff_in_strcpy(&our_out, json_object_to_json_string(obj));
419
420 if (slen < 0) return slen;
421 break;
422 }
423
424 case FR_TYPE_FLOAT64:
425 {
426 struct json_object *obj;
427 fr_slen_t slen;
428
429 obj = json_object_new_double((double)vb->vb_float64);
430 if (unlikely(obj == NULL)) return -1;
431 slen = fr_sbuff_in_strcpy(&our_out, json_object_to_json_string(obj));
433
434 if (slen < 0) return slen;
435 break;
436 }
437
444 case FR_TYPE_IFID:
445 case FR_TYPE_ETHERNET:
446 case FR_TYPE_DATE:
448 case FR_TYPE_ATTR:
449 {
450 fr_slen_t slen;
451
452 if (include_quotes) FR_SBUFF_IN_CHAR_RETURN(&our_out, '"');
453 slen = fr_value_box_print(&our_out, vb, NULL);
454 if (include_quotes) FR_SBUFF_IN_CHAR_RETURN(&our_out, '"');
455 /* Intentionally after writing second dquote, so the buffer is always has a properly terminated string */
456 if (slen < 0) return slen;
457 }
458 break;
459
461 fr_strerror_const("Structural boxes not yet supported");
462 return -1;
463
464 case FR_TYPE_INTERNAL:
465 fr_strerror_printf("Box type %s cannot be converted to string", fr_type_to_str(vb->type));
466 return -1;
467 }
468
469 return fr_sbuff_set(out, &our_out);
470}
471
472/** Print JSON-C version
473 *
474 */
476{
477#ifdef HAVE_JSON_C_VERSION
478 INFO("libfreeradius-json: json-c version: %s", json_c_version());
479#else
480 INFO("libfreeradius-json: json-c version: Unknown (less than 0.10) - Please upgrade");
481#endif
482}
483
484
485/** Convert a value box into a JSON object
486 *
487 * If format.value.always_string is set then a numeric value
488 * will be returned as a JSON string object.
489 *
490 * @param[in] ctx Talloc context.
491 * @param[out] out returned json object.
492 * @param[in] vb to get the value of.
493 * @param[in] format format definition, or NULL.
494 * @return
495 * - 0 on success.
496 * - -1 on error.
497 */
498static inline CC_HINT(always_inline)
499int json_afrom_value_box(TALLOC_CTX *ctx, json_object **out,
500 fr_value_box_t const *vb, fr_json_format_t const *format)
501{
502 if (!format) {
504 return 0;
505 }
506
507 /*
508 * Evaluated before "always_string".
509 */
510 if (vb->type == FR_TYPE_OCTETS) {
511 switch (format->value.binary_format) {
514 {
515 fr_sbuff_t *encoded;
516 FR_SBUFF_TALLOC_THREAD_LOCAL(&encoded, 256, SIZE_MAX);
517
518 switch (format->value.binary_format) {
519 /*
520 * Hex encode octets values when requested.
521 */
523 fr_base16_encode(encoded, &FR_DBUFF_TMP(vb->vb_octets, vb->vb_length));
524 break;
525
526 /*
527 * Base64-encode octets values when requested.
528 */
530 fr_base64_encode(encoded, &FR_DBUFF_TMP(vb->vb_octets, vb->vb_length), true);
531 break;
532
533 default:
534 break;
535 }
536
537 MEM(*out = json_object_new_string_len(fr_sbuff_start(encoded), fr_sbuff_used(encoded)));
538 return 0;
539 }
540
542 break;
543 }
544 }
545
546 if (format->value.always_string) {
548
549 if (unlikely(fr_value_box_cast(ctx, &vb_str, FR_TYPE_STRING, NULL, vb) < 0)) return -1;
550
552 fr_value_box_clear(&vb_str);
553
554 return 0;
555 }
556
558 return 0;
559}
560
561/** Convert fr_pair_t into a JSON object
562 *
563 * If format.value.enum_as_int is set, and the given VP is an enum
564 * value, the integer value is returned as a json_object rather
565 * than the text representation.
566 *
567 * If format.value.always_string is set then a numeric value
568 * will be returned as a JSON string object.
569 *
570 * @param[in] ctx Talloc context.
571 * @param[out] out returned json object.
572 * @param[in] vp to get the value of.
573 * @param[in] format format definition, or NULL.
574 * @return
575 * - 0 on success.
576 * - -1 on error.
577 */
578static int json_afrom_pair(TALLOC_CTX *ctx, json_object **out,
579 fr_pair_t *vp, fr_json_format_t const *format)
580{
581 fr_value_box_t const *vb;
582
583 fr_assert(vp);
584
585 vb = &vp->data;
586
587 if (format->value.enum_as_int) {
588 (void)fr_pair_value_enum_box(&vb, vp);
589 }
590
591 return json_afrom_value_box(ctx, out, vb, format);
592}
593
594
595/** Get attribute name with optional prefix
596 *
597 * If the format "attr.prefix" string is set then prepend this
598 * to the given attribute name, otherwise just return name alone.
599 *
600 * @param[out] out sbuff to write the new name
601 * @param[in] da dictionary attribute to get name of
602 * @param[in] format json format structure
603 * @return length of attribute name
604 */
606{
607 fr_sbuff_t our_out;
608
609 if (!out) return 0;
610
611 our_out = FR_SBUFF(out);
612
613 if (format->attr.prefix) {
614 FR_SBUFF_IN_STRCPY_RETURN(&our_out, format->attr.prefix);
615 FR_SBUFF_IN_CHAR_RETURN(&our_out, ':');
616 }
617
618 FR_SBUFF_IN_BSTRNCPY_RETURN(&our_out, da->name, da->name_len);
619
620 FR_SBUFF_SET_RETURN(out, &our_out);
621}
622
623
624/** Verify that the options in fr_json_format_t are valid
625 *
626 * Warnings are optional, will fatal error if the format is corrupt.
627 *
628 * @param[in] format the format structure to check
629 * @param[in] verbose print out warnings if set
630 * @return true if format is good, otherwise false
631 */
632bool fr_json_format_verify(fr_json_format_t const *format, bool verbose)
633{
634 bool ret = true;
635
637
638 switch (format->output_mode) {
639 case JSON_MODE_OBJECT:
641 case JSON_MODE_ARRAY:
642 /* all options are valid */
643 return true;
645 if (format->attr.prefix) {
646 if (verbose) WARN("attribute name prefix not valid in output_mode 'array_of_values' and will be ignored");
647 ret = false;
648 }
649 if (format->value.value_is_always_array) {
650 if (verbose) WARN("'value_is_always_array' not valid in output_mode 'array_of_values' and will be ignored");
651 ret = false;
652 }
653 return ret;
655 if (format->value.value_is_always_array) {
656 if (verbose) WARN("'value_is_always_array' not valid in output_mode 'array_of_names' and will be ignored");
657 ret = false;
658 }
659 if (format->value.enum_as_int) {
660 if (verbose) WARN("'enum_as_int' not valid in output_mode 'array_of_names' and will be ignored");
661 ret = false;
662 }
663 if (format->value.always_string) {
664 if (verbose) WARN("'always_string' not valid in output_mode 'array_of_names' and will be ignored");
665 ret = false;
666 }
667 return ret;
668 default:
669 ERROR("JSON format output mode is invalid");
670 }
671
672 /* If we get here, something has gone wrong */
673 fr_assert(0);
674
675 return false;
676}
677
678#define INVALID_TYPE \
679do { \
680 fr_assert(0); \
681 fr_strerror_printf("Invalid type %s for attribute %s", fr_type_to_str(vp->vp_type), vp->da->name); \
682 goto error; \
683} while (0)
684
685/** Returns a JSON object representation of a list of value pairs
686 *
687 * The result is a struct json_object, which should be free'd with
688 * json_object_put() by the caller. Intended to only be called by
689 * fr_json_afrom_pair_list().
690 *
691 * This function generates the "object" format, JSON_MODE_OBJECT.
692 * @see fr_json_format_s
693 *
694@verbatim
695{
696 "<attribute0>":{
697 "type":"<type0>",
698 "value":[<value0>,<value1>,<valueN>] // if value_is_always_array is true
699 }, // or
700 "<attribute1>":{
701 "type":"<type1>",
702 "value":<value0> // if value_is_always_array is false
703 // and there is only one value
704 },
705 "<attributeN>":{
706 "type":"<typeN>",
707 "value":[...]
708 }
709}
710@endverbatim
711 *
712 * @param[in] ctx Talloc context.
713 * @param[in] vps a list of value pairs.
714 * @param[in] format Formatting control, must be set.
715 * @return JSON object with the generated representation.
716 */
717static CC_HINT(warn_unused_result)
718json_object *json_object_afrom_pair_list(TALLOC_CTX *ctx, fr_pair_list_t *vps, fr_json_format_t const *format)
719{
720 fr_pair_t *vp;
721 struct json_object *obj;
722 char buf[FR_DICT_ATTR_MAX_NAME_LEN + 32];
723
724 /* Check format and type */
726 fr_assert(format->output_mode == JSON_MODE_OBJECT);
727
728 MEM(obj = json_object_new_object());
729
730 for (vp = fr_pair_list_head(vps);
731 vp;
732 vp = fr_pair_list_next(vps, vp)) {
733 fr_sbuff_t attr_name;
734 struct json_object *vp_object, *values, *value, *type_name;
735
736 if (vp->vp_raw) continue;
737
738 /*
739 * Get attribute name and value.
740 */
741 fr_sbuff_init_in(&attr_name, buf, sizeof(buf) - 1);
742 if (attr_name_with_prefix(&attr_name, vp->da, format) < 0) {
743 error:
745 return NULL;
746 }
747
748 switch (vp->vp_type) {
749 case FR_TYPE_LEAF:
750 if (json_afrom_pair(ctx, &value, vp, format) < 0) {
751 fr_strerror_const("Failed to convert attribute value to JSON object");
752 goto error;
753 }
754 break;
755 /*
756 * For nested attributes we recurse. The nesting is represented
757 * as a table, either as the single value, or as an element in
758 * an array.
759 *
760 * ...
761 * "value" : { "nested_attr" : { "type" : "<nested_type>", "value" : "<nested_attr_value>" } }
762 * ...
763 *
764 * ...
765 * "value" : [ { "nested_attr" : { "type" : "<nested_type>", "value" : "<nested_attr_value>" } } ]
766 * ...
767 *
768 * The formatting of nested attributes and their structure is
769 * identical to top level attributes.
770 */
772 value = json_object_afrom_pair_list(ctx, &vp->vp_group, format);
773 if (unlikely(value == NULL)) goto error;
774 break;
775
776 default:
778 }
779
780 /*
781 * Look in the table to see if we already have a key for the attribute
782 * we're working on.
783 *
784 * If we don't we create a new object in either the form:
785 *
786 * "<attribute>": {
787 * "type": "<type>",
788 * "value": [<value>] // if value_is_always_array is true
789 * // or
790 * "value": <value> // if value_is_always_array is false
791 * // and there is only one value
792 * }
793 */
794 if (!json_object_object_get_ex(obj, fr_sbuff_start(&attr_name), &vp_object)) {
795 /*
796 * Wasn't there, so create a new object for this attribute.
797 */
798 MEM(vp_object = json_object_new_object());
799 json_object_object_add(obj, fr_sbuff_start(&attr_name), vp_object);
800
801 /*
802 * Add "type" to newly created keys.
803 */
804 MEM(type_name = json_object_new_string(fr_type_to_str(vp->vp_type)));
805 json_object_object_add_ex(vp_object, "type", type_name, JSON_C_OBJECT_KEY_IS_CONSTANT);
806
807 /*
808 * Create a "value" array to hold any attribute values for this attribute...
809 */
810 if (format->value.value_is_always_array) {
811 MEM(values = json_object_new_array());
812 json_object_object_add_ex(vp_object, "value", values, JSON_C_OBJECT_KEY_IS_CONSTANT);
813 json_object_array_add(values, value);
814 continue;
815 }
816
817 /*
818 * ...or just add the value directly.
819 */
820 json_object_object_add_ex(vp_object, "value", value, JSON_C_OBJECT_KEY_IS_CONSTANT);
821
822 continue; /* Next attribute! */
823 }
824
825 /*
826 * Find the 'values' array to add the current value to.
827 */
828 if (!fr_cond_assert(json_object_object_get_ex(vp_object, "value", &values))) {
829 fr_strerror_const("Inconsistent JSON tree");
830 goto error;
831 }
832
833 /*
834 * If value_is_always_array is no set then "values" may not be an array, so it will
835 * need converting to an array to add this extra attribute.
836 */
837 if (!format->value.value_is_always_array) {
838 json_type type;
839 struct json_object *convert_value = values;
840
841 /* Check "values" type */
842 type = json_object_get_type(values);
843
844 /* It wasn't an array, so turn it into one with the old value as the first entry */
845 if (type != json_type_array) {
846 MEM(values = json_object_new_array());
847 json_object_array_add(values, json_object_get(convert_value));
848 json_object_object_del(vp_object, "value");
849 json_object_object_add_ex(vp_object, "value", values,
850 JSON_C_OBJECT_KEY_IS_CONSTANT);
851 }
852 }
853 json_object_array_add(values, value);
854 }
855
856 return obj;
857}
858
859
860/** Returns a JSON object representation of a list of value pairs
861 *
862 * The result is a struct json_object, which should be free'd with
863 * json_object_put() by the caller. Intended to only be called by
864 * fr_json_afrom_pair_list().
865 *
866 * This function generates the "simple object" format, JSON_MODE_OBJECT_SIMPLE.
867 * @see fr_json_format_s
868 *
869@verbatim
870{
871 "<attribute0>":[<value0>,<value1>,<valueN>] // if value_is_always_array is true
872 // or
873 "<attribute1>":<value0> // if value_is_always_array is false,
874 // and there is only one value
875 "<attributeN>":[<value0>,<value1>,<valueN>]
876}
877@endverbatim
878 *
879 * @param[in] ctx Talloc context.
880 * @param[in] vps a list of value pairs.
881 * @param[in] format Formatting control, must be set.
882 * @return JSON object with the generated representation.
883 */
884static json_object *json_simple_obj_afrom_pair_list(TALLOC_CTX *ctx, fr_pair_list_t *vps,
885 fr_json_format_t const *format)
886{
887 fr_pair_t *vp;
888 struct json_object *obj;
889 char buf[FR_DICT_ATTR_MAX_NAME_LEN + 32];
890 json_type type;
891
892 /* Check format and type */
895
896 MEM(obj = json_object_new_object());
897
898 for (vp = fr_pair_list_head(vps);
899 vp;
900 vp = fr_pair_list_next(vps, vp)) {
901 fr_sbuff_t attr_name;
902 struct json_object *vp_object, *value;
903 struct json_object *values = NULL;
904 bool add_single = false;
905
906 if (vp->vp_raw) continue;
907
908 /*
909 * Get attribute name and value.
910 */
911 fr_sbuff_init_in(&attr_name, buf, sizeof(buf) - 1);
912 if (attr_name_with_prefix(&attr_name, vp->da, format) < 0) {
913 error:
915 return NULL;
916 }
917
918 switch (vp->vp_type) {
919 case FR_TYPE_LEAF:
920 if (json_afrom_pair(ctx, &value, vp, format) < 0) {
921 fr_strerror_const("Failed to convert attribute value to JSON object");
922 goto error;
923 }
924 break;
925 /*
926 * For nested attributes we recurse. The nesting is represented
927 * as a table, either as the single value, or as an element in
928 * an array.
929 *
930 * ...
931 * "<parent>" : { "<nested_attr>" : <nested_attr_value> }
932 * ...
933 *
934 * ...
935 * "<parent>" : [ { "<nested_attr>" : "<nested_attr_value>" } ]
936 * ...
937 *
938 * The formatting of nested attributes and their structure is
939 * identical to top level attributes.
940 */
943 if (unlikely(value == NULL)) goto error;
944 break;
945
946 default:
948 }
949
950 /*
951 * See if we already have a key in the table we're working on,
952 * if not then create a new one.
953 */
954 if (!json_object_object_get_ex(obj, fr_sbuff_start(&attr_name), &vp_object)) {
955 if (format->value.value_is_always_array) {
956 /*
957 * We have been asked to ensure /all/ values are lists,
958 * even if there's only one attribute.
959 */
960 MEM(values = json_object_new_array());
961 json_object_object_add(obj, fr_sbuff_start(&attr_name), values);
962 } else {
963 /*
964 * Deal with it later on.
965 */
966 add_single = true;
967 }
968 /*
969 * If we do have the key already, get its value array.
970 */
971 } else {
972 type = json_object_get_type(vp_object);
973
974 if (type == json_type_array) {
975 values = vp_object;
976 } else {
977 /*
978 * We've seen one of these before, but didn't add
979 * it as an array the first time. Sort that out.
980 */
981 MEM(values = json_object_new_array());
982 json_object_array_add(values, json_object_get(vp_object));
983
984 /*
985 * Existing key will have refcount decremented
986 * and will be freed if this drops to zero.
987 */
988 json_object_object_add(obj, fr_sbuff_start(&attr_name), values);
989 }
990 }
991
992 if (add_single) {
993 /*
994 * Only ever used the first time adding a new
995 * attribute when "value_is_always_array" is not set.
996 */
997 json_object_object_add(obj, fr_sbuff_start(&attr_name), value);
998 } else {
999 /*
1000 * Otherwise we're always appending to a JSON array.
1001 */
1002 json_object_array_add(values, value);
1003 }
1004 }
1005
1006 return obj;
1007}
1008
1009
1010/** Returns a JSON array representation of a list of value pairs
1011 *
1012 * The result is a struct json_object, which should be free'd with
1013 * json_object_put() by the caller. Intended to only be called by
1014 * fr_json_afrom_pair_list().
1015 *
1016 * This function generates the "array" format, JSON_MODE_ARRAY.
1017 * @see fr_json_format_s
1018 *
1019 * @param[in] ctx Talloc context.
1020 * @param[in] vps a list of value pairs.
1021 * @param[in] format Formatting control, must be set.
1022 * @return JSON object with the generated representation.
1023 */
1024static struct json_object *json_array_afrom_pair_list(TALLOC_CTX *ctx, fr_pair_list_t *vps,
1025 fr_json_format_t const *format)
1026{
1027 fr_pair_t *vp;
1028 struct json_object *obj;
1029 struct json_object *seen_attributes = NULL;
1030 char buf[FR_DICT_ATTR_MAX_NAME_LEN + 32];
1031
1032 /* Check format and type */
1034 fr_assert(format->output_mode == JSON_MODE_ARRAY);
1035
1036 MEM(obj = json_object_new_array());
1037
1038 /*
1039 * If attribute values should be in a list format, then keep track
1040 * of the attributes we've previously seen in a JSON object.
1041 */
1042 if (format->value.value_is_always_array) {
1043 seen_attributes = json_object_new_object();
1044 }
1045
1046 for (vp = fr_pair_list_head(vps);
1047 vp;
1048 vp = fr_pair_list_next(vps, vp)) {
1049 fr_sbuff_t attr_name;
1050 struct json_object *name, *value, *type_name;
1051 struct json_object *values = NULL;
1052 struct json_object *attrobj = NULL;
1053 bool already_seen = false;
1054
1055 if (vp->vp_raw) continue;
1056
1057 /*
1058 * Get attribute name and value.
1059 */
1060 fr_sbuff_init_in(&attr_name, buf, sizeof(buf) - 1);
1061 if (attr_name_with_prefix(&attr_name, vp->da, format) < 0) {
1062 error:
1063 json_object_put_assert(seen_attributes);
1065 return NULL;
1066 }
1067
1068 switch (vp->vp_type) {
1069 case FR_TYPE_LEAF:
1070 if (json_afrom_pair(ctx, &value, vp, format) < 0) {
1071 fr_strerror_const("Failed to convert attribute value to JSON object");
1072 goto error;
1073 }
1074 break;
1075
1076 case FR_TYPE_STRUCTURAL:
1077 value = json_array_afrom_pair_list(ctx, &vp->vp_group, format);
1078 if (unlikely(value == NULL)) goto error;
1079 break;
1080
1081 default:
1083 }
1084
1085 if (format->value.value_is_always_array) {
1086 /*
1087 * Try and find this attribute in the "seen_attributes" object. If it is
1088 * there then get the "values" array to add this attribute value to.
1089 */
1090 already_seen = json_object_object_get_ex(seen_attributes, fr_sbuff_start(&attr_name), &values);
1091 }
1092
1093 /*
1094 * If we're adding all attributes to the toplevel array, or we're adding values
1095 * to an array of an existing attribute but haven't seen it before, then we need
1096 * to create a new JSON object for this attribute.
1097 */
1098 if (!format->value.value_is_always_array || !already_seen) {
1099 /*
1100 * Create object and add it to top-level array
1101 */
1102 MEM(attrobj = json_object_new_object());
1103 json_object_array_add(obj, attrobj);
1104
1105 /*
1106 * Add the attribute name in the "name" key and the type in the "type" key
1107 */
1108 MEM(name = json_object_new_string(fr_sbuff_start(&attr_name)));
1109 json_object_object_add_ex(attrobj, "name", name, JSON_C_OBJECT_KEY_IS_CONSTANT);
1110
1111 MEM(type_name = json_object_new_string(fr_type_to_str(vp->vp_type)));
1112 json_object_object_add_ex(attrobj, "type", type_name, JSON_C_OBJECT_KEY_IS_CONSTANT);
1113 }
1114
1115 if (format->value.value_is_always_array) {
1116 /*
1117 * We're adding values to an array for the first copy of this attribute
1118 * that we saw. First time around we need to create an array.
1119 */
1120 if (!already_seen) {
1121 MEM(values = json_object_new_array());
1122 /*
1123 * Add "value":[] key to the attribute object
1124 */
1125 json_object_object_add_ex(attrobj, "value", values, JSON_C_OBJECT_KEY_IS_CONSTANT);
1126
1127 /*
1128 * Also add to "seen_attributes" to check later
1129 */
1130 json_object_object_add(seen_attributes, fr_sbuff_start(&attr_name), json_object_get(values));
1131 }
1132
1133 /*
1134 * Always add the value to the respective "values" array.
1135 */
1136 json_object_array_add(values, value);
1137 } else {
1138 /*
1139 * This is simpler; just add a "value": key to the attribute object.
1140 */
1141 json_object_object_add_ex(attrobj, "value", value, JSON_C_OBJECT_KEY_IS_CONSTANT);
1142 }
1143
1144 }
1145
1146 /*
1147 * No longer need the "seen_attributes" object, it was just used for tracking.
1148 */
1149 if (format->value.value_is_always_array) {
1150 json_object_put_assert(seen_attributes);
1151 }
1152
1153 return obj;
1154}
1155
1156
1157/** Returns a JSON array of a list of value pairs
1158 *
1159 * The result is a struct json_object, which should be free'd with
1160 * json_object_put() by the caller. Intended to only be called by
1161 * fr_json_afrom_pair_list().
1162 *
1163 * This function generates the "array_of_values" format,
1164 * JSON_MODE_ARRAY_OF_VALUES, listing just the attribute values.
1165 * @see fr_json_format_s
1166 *
1167 * @param[in] ctx Talloc context.
1168 * @param[in] vps a list of value pairs.
1169 * @param[in] format Formatting control, must be set.
1170 * @return JSON object with the generated representation.
1171 */
1172static struct json_object *json_value_array_afrom_pair_list(TALLOC_CTX *ctx, fr_pair_list_t *vps,
1173 fr_json_format_t const *format)
1174{
1175 fr_pair_t *vp;
1176 struct json_object *obj;
1177
1178 /* Check format and type */
1181
1182 MEM(obj = json_object_new_array());
1183
1184 /*
1185 * This array format is very simple - just add all the
1186 * attribute values to the array in order.
1187 */
1188 for (vp = fr_pair_list_head(vps);
1189 vp;
1190 vp = fr_pair_list_next(vps, vp)) {
1191 struct json_object *value;
1192
1193 if (vp->vp_raw) continue;
1194
1195 switch (vp->vp_type) {
1196 case FR_TYPE_LEAF:
1197 if (json_afrom_pair(ctx, &value, vp, format) < 0) {
1198 fr_strerror_const("Failed to convert attribute value to JSON object");
1199 error:
1201 return NULL;
1202 }
1203 break;
1204
1205 case FR_TYPE_STRUCTURAL:
1206 value = json_value_array_afrom_pair_list(ctx, &vp->vp_group, format);
1207 if (value == NULL) goto error;
1208 break;
1209
1210 default:
1212 }
1213
1214 json_object_array_add(obj, value);
1215 }
1216
1217 return obj;
1218}
1219
1220
1221/** Returns a JSON array of a list of value pairs
1222 *
1223 * The result is a struct json_object, which should be free'd with
1224 * json_object_put() by the caller. Intended to only be called by
1225 * fr_json_afrom_pair_list().
1226 *
1227 * This function generates the "array_of_names" format,
1228 * JSON_MODE_ARRAY_OF_NAMES, listing just the attribute names.
1229 * @see fr_json_format_s
1230 *
1231 * @param[in] ctx Talloc context.
1232 * @param[in] vps a list of value pairs.
1233 * @param[in] format Formatting control, must be set.
1234 * @return JSON object with the generated representation.
1235 */
1236static struct json_object *json_attr_array_afrom_pair_list(TALLOC_CTX *ctx, fr_pair_list_t *vps,
1237 fr_json_format_t const *format)
1238{
1239 fr_pair_t *vp;
1240 struct json_object *obj;
1241 char buf[FR_DICT_ATTR_MAX_NAME_LEN + 32];
1242
1243 /* Check format and type */
1245 fr_assert(format->output_mode == JSON_MODE_ARRAY_OF_NAMES);
1246
1247 MEM(obj = json_object_new_array());
1248
1249 /*
1250 * Add all the attribute names to the array in order.
1251 */
1252 for (vp = fr_pair_list_head(vps);
1253 vp;
1254 vp = fr_pair_list_next(vps, vp)) {
1255 struct json_object *value;
1256 fr_sbuff_t attr_name;
1257
1258 if (vp->vp_raw) continue;
1259
1260 fr_sbuff_init_in(&attr_name, buf, sizeof(buf) - 1);
1261 if (attr_name_with_prefix(&attr_name, vp->da, format) < 0) {
1262 error:
1264 return NULL;
1265 }
1266 value = json_object_new_string(fr_sbuff_start(&attr_name));
1267
1268 switch (vp->vp_type) {
1269 case FR_TYPE_LEAF:
1270 break;
1271
1272 case FR_TYPE_STRUCTURAL:
1273 json_object_array_add(obj, value);
1274 value = json_attr_array_afrom_pair_list(ctx, &vp->vp_group, format);
1275 if (value == NULL) goto error;
1276 break;
1277
1278 default:
1280 }
1281
1282 json_object_array_add(obj, value);
1283 }
1284
1285 return obj;
1286}
1287
1288
1289/** Returns a JSON string of a list of value pairs
1290 *
1291 * The result is a talloc-ed string, freeing the string is
1292 * the responsibility of the caller.
1293 *
1294 * The 'format' struct contains settings to configure the output
1295 * JSON document format.
1296 * @see fr_json_format_s
1297 *
1298 * Default output, when format is NULL, is:
1299@verbatim
1300{
1301 "<attribute0>":{
1302 "type":"<type0>",
1303 "value":[<value0>,<value1>,<valueN>]
1304 },
1305 "<attribute1>":{
1306 "type":"<type1>",
1307 "value":[...]
1308 },
1309 "<attributeN>":{
1310 "type":"<typeN>",
1311 "value":[...]
1312 }
1313}
1314@endverbatim
1315 *
1316 * @param[in] ctx Talloc context.
1317 * @param[in] vps a list of value pairs.
1318 * @param[in] format Formatting control, can be NULL to use default format.
1319 * @return JSON string representation of the value pairs
1320 */
1321char *fr_json_afrom_pair_list(TALLOC_CTX *ctx, fr_pair_list_t *vps,
1322 fr_json_format_t const *format)
1323{
1324 struct json_object *obj = NULL;
1325 const char *p;
1326 char *out;
1327
1329
1330 switch (format->output_mode) {
1331 case JSON_MODE_OBJECT:
1332 MEM(obj = json_object_afrom_pair_list(ctx, vps, format));
1333 break;
1335 MEM(obj = json_simple_obj_afrom_pair_list(ctx, vps, format));
1336 break;
1337 case JSON_MODE_ARRAY:
1338 MEM(obj = json_array_afrom_pair_list(ctx, vps, format));
1339 break;
1342 break;
1344 MEM(obj = json_attr_array_afrom_pair_list(ctx, vps, format));
1345 break;
1346 default:
1347 /* This should never happen */
1348 fr_assert(0);
1349 }
1350
1351 /*
1352 * p is a buff inside obj, and will be freed
1353 * when it is freed.
1354 */
1355 MEM(p = json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN));
1356 MEM(out = talloc_strdup(ctx, p));
1357
1358 /*
1359 * Free the JSON structure, it's not needed any more
1360 */
1362
1363 return out;
1364}
static int const char char buffer[256]
Definition acutest.h:576
#define fr_base16_encode(_out, _in)
Definition base16.h:54
#define fr_base64_encode(_out, _in, _add_padding)
Definition base64.h:71
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:210
#define unlikely(_x)
Definition build.h:384
#define NUM_ELEMENTS(_t)
Definition build.h:340
int cf_table_parse_int(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Generic function for parsing conf pair values as int.
Definition cf_parse.c:1635
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:657
cf_parse_t func
Override default parsing behaviour for the specified type with a custom parsing function.
Definition cf_parse.h:611
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:280
#define FR_CONF_OFFSET_SUBSECTION(_name, _flags, _struct, _field, _subcs)
conf_parser_t which populates a sub-struct using a CONF_SECTION
Definition cf_parse.h:309
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:594
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:522
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:141
#define fr_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error.
Definition debug.h:218
#define MEM(x)
Definition debug.h:46
#define ERROR(fmt,...)
Definition dhcpclient.c:40
fr_value_box_t const * value
Enum value (what name maps to).
Definition dict.h:257
fr_dict_enum_value_t const * fr_dict_enum_by_value(fr_dict_attr_t const *da, fr_value_box_t const *value)
Lookup the structure representing an enum value in a fr_dict_attr_t.
Definition dict_util.c:3655
ssize_t fr_dict_valid_name(char const *name, ssize_t len)
Definition dict_util.c:4938
fr_dict_enum_value_t const * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
Definition dict_util.c:3701
char const * name
Enum name.
Definition dict.h:254
#define FR_DICT_ATTR_MAX_NAME_LEN
Maximum length of a attribute name.
Definition dict.h:501
Value of an enumerated attribute.
Definition dict.h:253
Test enumeration values.
Definition dict_test.h:92
@ JSON_MODE_ARRAY
Definition base.h:72
@ JSON_MODE_OBJECT
Definition base.h:70
@ JSON_MODE_ARRAY_OF_NAMES
Definition base.h:74
@ JSON_MODE_OBJECT_SIMPLE
Definition base.h:71
@ JSON_MODE_ARRAY_OF_VALUES
Definition base.h:73
fr_json_format_attr_t attr
Formatting options for attribute names.
Definition base.h:237
@ JSON_BINARY_FORMAT_BASE64
Base64-encode octets values.
Definition base.h:58
@ JSON_BINARY_FORMAT_RAW
Current behaviour - raw bytes as JSON string.
Definition base.h:56
@ JSON_BINARY_FORMAT_BASE16
Base16-encode octets values.
Definition base.h:57
char const * prefix
Prefix to add to all attribute names.
Definition base.h:100
Attribute formatting options for fr_json_afrom_pair_list()
Definition base.h:99
JSON document formatting options.
Definition base.h:231
Value formatting options for fr_json_afrom_pair_list()
Definition base.h:158
fr_table_num_sorted_t const fr_json_binary_format_table[]
Definition json.c:46
static fr_json_format_t const default_json_format
Definition json.c:53
static void json_object_put_assert(json_object *obj)
Definition json.c:83
char * fr_json_afrom_pair_list(TALLOC_CTX *ctx, fr_pair_list_t *vps, fr_json_format_t const *format)
Returns a JSON string of a list of value pairs.
Definition json.c:1321
size_t fr_json_format_table_len
Definition json.c:44
static struct json_object * json_value_array_afrom_pair_list(TALLOC_CTX *ctx, fr_pair_list_t *vps, fr_json_format_t const *format)
Returns a JSON array of a list of value pairs.
Definition json.c:1172
static conf_parser_t const json_format_value_config[]
Definition json.c:64
json_object * json_object_from_value_box(fr_value_box_t const *data)
Convert boxed value_box to a JSON object.
Definition json.c:204
static conf_parser_t const json_format_attr_config[]
Definition json.c:59
size_t fr_json_binary_format_table_len
Definition json.c:51
#define INVALID_TYPE
Definition json.c:678
fr_slen_t fr_json_str_from_value(fr_sbuff_t *out, fr_value_box_t const *vb, bool include_quotes)
Print a value box as its equivalent JSON format without going via a struct json_object (in most cases...
Definition json.c:291
conf_parser_t const fr_json_format_config[]
Definition json.c:74
static int json_afrom_pair(TALLOC_CTX *ctx, json_object **out, fr_pair_t *vp, fr_json_format_t const *format)
Convert fr_pair_t into a JSON object.
Definition json.c:578
static int json_afrom_value_box(TALLOC_CTX *ctx, json_object **out, fr_value_box_t const *vb, fr_json_format_t const *format)
Convert a value box into a JSON object.
Definition json.c:499
void fr_json_version_print(void)
Print JSON-C version.
Definition json.c:475
fr_table_num_sorted_t const fr_json_format_table[]
Definition json.c:37
static struct json_object * json_array_afrom_pair_list(TALLOC_CTX *ctx, fr_pair_list_t *vps, fr_json_format_t const *format)
Returns a JSON array representation of a list of value pairs.
Definition json.c:1024
static json_object * json_object_afrom_pair_list(TALLOC_CTX *ctx, fr_pair_list_t *vps, fr_json_format_t const *format)
Returns a JSON object representation of a list of value pairs.
Definition json.c:718
static struct json_object * json_attr_array_afrom_pair_list(TALLOC_CTX *ctx, fr_pair_list_t *vps, fr_json_format_t const *format)
Returns a JSON array of a list of value pairs.
Definition json.c:1236
int fr_json_object_to_value_box(TALLOC_CTX *ctx, fr_value_box_t *out, json_object *object, fr_dict_attr_t const *enumv, bool tainted)
Convert json object to fr_value_box_t.
Definition json.c:107
bool fr_json_format_verify(fr_json_format_t const *format, bool verbose)
Verify that the options in fr_json_format_t are valid.
Definition json.c:632
static ssize_t attr_name_with_prefix(fr_sbuff_t *out, fr_dict_attr_t const *da, fr_json_format_t const *format)
Get attribute name with optional prefix.
Definition json.c:605
static json_object * json_simple_obj_afrom_pair_list(TALLOC_CTX *ctx, fr_pair_list_t *vps, fr_json_format_t const *format)
Returns a JSON object representation of a list of value pairs.
Definition json.c:884
unsigned short uint16_t
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_FLOAT32
Single precision floating point.
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_INT8
8 Bit signed integer.
@ FR_TYPE_ETHERNET
48 Bit Mac-Address.
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_INT64
64 Bit signed integer.
@ FR_TYPE_INT16
16 Bit signed integer.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_COMBO_IP_PREFIX
IPv4 or IPv6 address prefix depending on length.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_SIZE
Unsigned integer capable of representing any memory address on the local system.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
@ FR_TYPE_IFID
Interface ID.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_FLOAT64
Double precision floating point.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
ssize_t fr_slen_t
#define UINT8_MAX
int fr_pair_value_enum_box(fr_value_box_t const **out, fr_pair_t *vp)
Get value box of a VP, optionally prefer enum value.
Definition pair.c:3096
#define fr_assert(_expr)
Definition rad_assert.h:37
#define WARN(fmt,...)
#define INFO(fmt,...)
Definition radict.c:63
static char const * name
ssize_t fr_sbuff_in_strcpy(fr_sbuff_t *sbuff, char const *str)
Copy bytes into the sbuff up to the first \0.
Definition sbuff.c:1472
#define fr_sbuff_start(_sbuff_or_marker)
#define FR_SBUFF_IN_CHAR_RETURN(_sbuff,...)
#define fr_sbuff_set(_dst, _src)
#define FR_SBUFF_IN_STRCPY_LITERAL_RETURN(_sbuff, _str)
#define FR_SBUFF_SET_RETURN(_dst, _src)
#define FR_SBUFF_IN_SPRINTF_RETURN(...)
#define FR_SBUFF(_sbuff_or_marker)
#define FR_SBUFF_IN_BSTRNCPY_RETURN(...)
#define fr_sbuff_init_in(_out, _start, _len_or_end)
#define FR_SBUFF_OUT(_start, _len_or_end)
#define fr_sbuff_used(_sbuff_or_marker)
#define FR_SBUFF_IN_STRCPY_RETURN(...)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
fr_aka_sim_id_type_t type
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
#define talloc_strdup(_ctx, _str)
Definition talloc.h:142
Master include file to access all functions and structures in the library.
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
Definition pair_inline.c:69
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
Definition pair_inline.c:42
Support functions to allow libraries to provide errors to their callers.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
@ FR_TYPE_ATTR
A contains an attribute reference.
Definition types.h:83
#define FR_TYPE_INTERNAL
Definition types.h:319
#define FR_TYPE_STRUCTURAL
Definition types.h:316
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:454
#define FR_TYPE_LEAF
Definition types.h:317
ssize_t fr_value_box_print(fr_sbuff_t *out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules)
Print one boxed value to a string.
Definition value.c:6115
int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert one type of fr_value_box_t to another.
Definition value.c:3960
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
Definition value.c:4408
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition value.c:4391
int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Copy a string to to a fr_value_box_t.
Definition value.c:4852
static fr_slen_t data
Definition value.h:1340
#define FR_VALUE_BOX_INITIALISER_NULL(_vb)
A static initialiser for stack/globally allocated boxes.
Definition value.h:511
#define fr_value_box(_box, _var, _tainted)
Automagically fill in a box, determining the value type from the type of the C variable.
Definition value.h:904
int format(printf, 5, 0))
static size_t char ** out
Definition value.h:1030