The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
json.c
Go to the documentation of this file.
1/*
2 * This program 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: a387075d5579320bef27b5d397e6927028033b59 $
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
82/*
83 * json-c >= 0.19 returns 0 for freed scalars and empty containers,
84 * so the return value can't identify leaks.
85 * Fix proposed upstream: https://github.com/json-c/json-c/pull/945
86 */
87#if JSON_C_VERSION_NUM >= 0x1300 /* 0.19.0 */
88#define json_object_put_assert(_obj) json_object_put(_obj)
89#else
90static inline CC_HINT(always_inline)
91void json_object_put_assert(json_object *obj)
92{
93 int ret;
94
95 ret = json_object_put(obj);
96 if (ret == 1) return;
97
98 fr_assert_fail("json_object_put did not free object (returned %d), likely leaking memory", ret);
99}
100#endif
101
102/** Convert json object to fr_value_box_t
103 *
104 * @param[in] ctx to allocate any value buffers in (should usually be the same as out).
105 * @param[in] out Where to write value. Must be initialised.
106 * @param[in] object to convert.
107 * @param[in] enumv Any string values are assumed to be in PRESENTATION format, meaning
108 * that if an enumv is specified, they'll be checked against the list
109 * of aliases for that enumeration, and possibly converted into one of
110 * the enumeration values (which may not be a string).
111 * @param[in] tainted Whether the data source is untrusted.
112 * @return
113 * - 0 on success.
114 * - -1 on failure.
115 */
116int fr_json_object_to_value_box(TALLOC_CTX *ctx, fr_value_box_t *out, json_object *object,
117 fr_dict_attr_t const *enumv, bool tainted)
118{
119 switch (json_object_get_type(object)) {
120 case json_type_string:
121 {
122 char const *value;
123 size_t len;
124 fr_dict_enum_value_t const *found;
125
126 value = json_object_get_string(object);
127 len = json_object_get_string_len(object);
128
129 if (!enumv) goto no_enumv;
130
131 if (fr_dict_valid_name(value, len) < 0) goto no_enumv;
132
133 /*
134 * If an alias exists, use that value instead
135 */
136 found = fr_dict_enum_by_name(enumv, value, len);
137 if (found) {
138 if (unlikely(fr_value_box_copy(ctx, out, found->value)) < 0) return -1;
139 return 0;
140 }
141
142 no_enumv:
143 /*
144 * Just copy the string to the box.
145 */
146 if (fr_value_box_bstrndup(out, out, NULL, value, len, tainted) < 0) return -1;
147 }
148 break;
149
150 case json_type_double:
151 fr_value_box(out, json_object_get_double(object), tainted);
152 break;
153
154 case json_type_int:
155 {
156#ifdef HAVE_JSON_OBJECT_GET_INT64
157 int64_t num;
158#else
159 int32_t num;
160#endif
161
162#ifndef HAVE_JSON_OBJECT_GET_INT64
163 num = json_object_get_int(object);
164#else
165 num = json_object_get_int64(object);
166 if (num < INT32_MIN) { /* 64bit signed*/
167 fr_value_box(out, (int64_t)num, tainted);
168 } else if (num > UINT32_MAX) { /* 64bit unsigned */
169 fr_value_box(out, (uint64_t)num, tainted);
170 } else
171#endif
172 if (num < INT16_MIN) { /* 32bit signed */
173 fr_value_box(out, (int32_t)num, tainted);
174 } else if (num < INT8_MIN) { /* 16bit signed */
175 fr_value_box(out, (int16_t)num, tainted);
176 } else if (num < 0) { /* 8bit signed */
177 fr_value_box(out, (int8_t)num, tainted);
178 } else if (num > UINT16_MAX) { /* 32bit unsigned */
179 fr_value_box(out, (uint32_t)num, tainted);
180 } else if (num > UINT8_MAX) { /* 16bit unsigned */
181 fr_value_box(out, (uint16_t)num, tainted);
182 } else { /* 8bit unsigned */
183 fr_value_box(out, (uint8_t)num, tainted);
184 }
185 }
186 break;
187
188 case json_type_boolean:
189 /* Must be cast to bool for correct generic case selection */
190 fr_value_box(out, ((bool)(json_object_get_boolean(object) > 0)), tainted);
191 break;
192
193 case json_type_null:
194 case json_type_array:
195 case json_type_object:
196 {
197 char const *value = json_object_to_json_string(object);
198
199 if (fr_value_box_bstrndup(out, out, NULL, value, strlen(value), tainted) < 0) return -1;
200 }
201 break;
202 }
203
204 out->tainted = tainted;
205
206 return 0;
207}
208
209/** Convert boxed value_box to a JSON object
210 *
211 * @param[in] data to convert.
212 */
214{
215 /*
216 * We're converting to PRESENTATION format
217 * so any attributes with enumeration values
218 * should be converted to string types.
219 */
220 if (data->enumv) {
221 fr_dict_enum_value_t const *enumv;
222
223 enumv = fr_dict_enum_by_value(data->enumv, data);
224 if (enumv) return json_object_new_string(enumv->name);
225 }
226
227 switch (data->type) {
228 default:
229 do_string:
230 {
231 char buffer[64];
232 fr_sbuff_t sbuff = FR_SBUFF_OUT(buffer, sizeof(buffer));
233
234 if (fr_value_box_print(&sbuff, data, NULL) <= 0) return NULL;
235
236 return json_object_new_string_len(buffer, fr_sbuff_used(&sbuff));
237 }
238
239 case FR_TYPE_STRING:
240 return json_object_new_string_len(data->vb_strvalue, data->vb_length);
241
242 case FR_TYPE_OCTETS:
243 return json_object_new_string_len((char const *)data->vb_octets, data->vb_length);
244
245 case FR_TYPE_BOOL:
246 return json_object_new_boolean(data->vb_bool);
247
248 case FR_TYPE_UINT8:
249 return json_object_new_int(data->vb_uint8);
250
251 case FR_TYPE_UINT16:
252 return json_object_new_int(data->vb_uint16);
253
254#ifdef HAVE_JSON_OBJECT_GET_INT64
255 case FR_TYPE_UINT32:
256 return json_object_new_int64((int64_t)data->vb_uint32); /* uint32_t (max) > int32_t (max) */
257
258 case FR_TYPE_UINT64:
259 if (data->vb_uint64 > INT64_MAX) goto do_string;
260 return json_object_new_int64(data->vb_uint64);
261#else
262 case FR_TYPE_UINT32:
263 if (data->vb_uint32 > INT32_MAX) goto do_string;
264 return json_object_new_int(data->vb_uint32);
265#endif
266
267 case FR_TYPE_INT8:
268 return json_object_new_int(data->vb_int8);
269
270 case FR_TYPE_INT16:
271 return json_object_new_int(data->vb_int16);
272
273 case FR_TYPE_INT32:
274 return json_object_new_int(data->vb_int32);
275
276#ifdef HAVE_JSON_OBJECT_GET_INT64
277 case FR_TYPE_INT64:
278 return json_object_new_int64(data->vb_int64);
279
280 case FR_TYPE_SIZE:
281 return json_object_new_int64(data->vb_size);
282#endif
283
285 fr_strerror_const("Can't convert structural type to JSON");
286 return NULL;
287 }
288}
289
290/** Print a value box as its equivalent JSON format without going via a struct json_object (in most cases)
291 *
292 * @param[out] out buffer to write to.
293 * @param[in] vb to print.
294 * @param[in] include_quotes whether we should wrap string values,
295 * or non-native types like IPv4 addresses in quotes.
296 * @return
297 * - <0 on error.
298 * - >= number of bytes written.
299 */
301{
302 fr_sbuff_t our_out = FR_SBUFF(out);
303
304 switch (vb->type) {
305 case FR_TYPE_NULL:
306 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "null");
307 break;
308
309 case FR_TYPE_BOOL:
310 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, vb->vb_bool ? "true" : "false");
311 break;
312
313 /*
314 * This is identical to JSON-C's escaping function
315 * but we avoid creating JSON objects just to be able
316 * to escape strings.
317 */
318 case FR_TYPE_STRING:
319 case FR_TYPE_OCTETS:
320 {
321 char const *last_app, *p, *end;
322
323 if (include_quotes) FR_SBUFF_IN_CHAR_RETURN(&our_out, '"');
324
325 last_app = p = vb->vb_strvalue;
326 end = p + vb->vb_length;
327
328 while (p < end) {
329 if ((*p < ' ') || (*p == '"') || (*p == '\\') || (*p == '/')) {
330 if (p > last_app) FR_SBUFF_IN_BSTRNCPY_RETURN(&our_out, last_app, p - last_app);
331
332 switch (*p) {
333 case '\b':
334 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "\\b");
335 break;
336
337 case '\n':
338 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "\\n");
339 break;
340
341 case '\r':
342 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "\\r");
343 break;
344
345 case '\t':
346 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "\\t");
347 break;
348
349 case '\f':
350 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "\\f");
351 break;
352
353 case '"':
354 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "\\\"");
355 break;
356
357 case '\\':
358 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "\\\\");
359 break;
360
361 case '/':
362 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "\\/");
363 break;
364
365 default:
366 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "\\u00");
367 fr_base16_encode(&our_out, &FR_DBUFF_TMP((uint8_t const *)p, 1));
368 }
369
370 last_app = p + 1;
371 }
372 p++;
373 }
374 if (end > last_app) FR_SBUFF_IN_BSTRNCPY_RETURN(&our_out, last_app, end - last_app);
375 if (include_quotes) FR_SBUFF_IN_CHAR_RETURN(&our_out, '"');
376 }
377 break;
378
379 case FR_TYPE_UINT8:
380 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", vb->vb_uint8);
381 break;
382
383 case FR_TYPE_UINT16:
384 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", vb->vb_uint16);
385 break;
386
387 case FR_TYPE_UINT32:
388 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%u", vb->vb_uint32);
389 break;
390
391 case FR_TYPE_UINT64:
392 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%" PRIu64, vb->vb_uint64);
393 break;
394
395 case FR_TYPE_INT8:
396 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%i", vb->vb_int8);
397 break;
398
399 case FR_TYPE_INT16:
400 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%i", vb->vb_int16);
401 break;
402
403 case FR_TYPE_INT32:
404 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%i", vb->vb_int32);
405 break;
406
407 case FR_TYPE_INT64:
408 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%" PRIi64, vb->vb_int64);
409 break;
410
411 case FR_TYPE_SIZE:
412 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%zu", vb->vb_size);
413 break;
414
415 /*
416 * It's too complex to replicate the float/double printing
417 * here, so pass it off to JSON-C's printing functions.
418 */
419 case FR_TYPE_FLOAT32:
420 {
421 struct json_object *obj;
422 fr_slen_t slen;
423
424 obj = json_object_new_double((double)vb->vb_float32);
425 if (unlikely(obj == NULL)) return -1;
426 slen = fr_sbuff_in_strcpy(&our_out, json_object_to_json_string(obj));
428
429 if (slen < 0) return slen;
430 break;
431 }
432
433 case FR_TYPE_FLOAT64:
434 {
435 struct json_object *obj;
436 fr_slen_t slen;
437
438 obj = json_object_new_double((double)vb->vb_float64);
439 if (unlikely(obj == NULL)) return -1;
440 slen = fr_sbuff_in_strcpy(&our_out, json_object_to_json_string(obj));
442
443 if (slen < 0) return slen;
444 break;
445 }
446
453 case FR_TYPE_IFID:
454 case FR_TYPE_ETHERNET:
455 case FR_TYPE_DATE:
457 case FR_TYPE_ATTR:
458 {
459 fr_slen_t slen;
460
461 if (include_quotes) FR_SBUFF_IN_CHAR_RETURN(&our_out, '"');
462 slen = fr_value_box_print(&our_out, vb, NULL);
463 if (include_quotes) FR_SBUFF_IN_CHAR_RETURN(&our_out, '"');
464 /* Intentionally after writing second dquote, so the buffer is always has a properly terminated string */
465 if (slen < 0) return slen;
466 }
467 break;
468
470 fr_strerror_const("Structural boxes not yet supported");
471 return -1;
472
473 case FR_TYPE_INTERNAL:
474 fr_strerror_printf("Box type %s cannot be converted to string", fr_type_to_str(vb->type));
475 return -1;
476 }
477
478 return fr_sbuff_set(out, &our_out);
479}
480
481/** Print JSON-C version
482 *
483 */
485{
486#ifdef HAVE_JSON_C_VERSION
487 INFO("libfreeradius-json: json-c version: %s", json_c_version());
488#else
489 INFO("libfreeradius-json: json-c version: Unknown (less than 0.10) - Please upgrade");
490#endif
491}
492
493
494/** Convert a value box into a JSON object
495 *
496 * If format.value.always_string is set then a numeric value
497 * will be returned as a JSON string object.
498 *
499 * @param[in] ctx Talloc context.
500 * @param[out] out returned json object.
501 * @param[in] vb to get the value of.
502 * @param[in] format format definition, or NULL.
503 * @return
504 * - 0 on success.
505 * - -1 on error.
506 */
507static inline CC_HINT(always_inline)
508int json_afrom_value_box(TALLOC_CTX *ctx, json_object **out,
509 fr_value_box_t const *vb, fr_json_format_t const *format)
510{
511 if (!format) {
513 return 0;
514 }
515
516 /*
517 * Evaluated before "always_string".
518 */
519 if (vb->type == FR_TYPE_OCTETS) {
520 switch (format->value.binary_format) {
523 {
524 fr_sbuff_t *encoded;
525 FR_SBUFF_TALLOC_THREAD_LOCAL(&encoded, 256, SIZE_MAX);
526
527 switch (format->value.binary_format) {
528 /*
529 * Hex encode octets values when requested.
530 */
532 fr_base16_encode(encoded, &FR_DBUFF_TMP(vb->vb_octets, vb->vb_length));
533 break;
534
535 /*
536 * Base64-encode octets values when requested.
537 */
539 fr_base64_encode(encoded, &FR_DBUFF_TMP(vb->vb_octets, vb->vb_length), true);
540 break;
541
542 default:
543 break;
544 }
545
546 MEM(*out = json_object_new_string_len(fr_sbuff_start(encoded), fr_sbuff_used(encoded)));
547 return 0;
548 }
549
551 break;
552 }
553 }
554
555 if (format->value.always_string) {
557
558 if (unlikely(fr_value_box_cast(ctx, &vb_str, FR_TYPE_STRING, NULL, vb) < 0)) return -1;
559
561 fr_value_box_clear(&vb_str);
562
563 return 0;
564 }
565
567 return 0;
568}
569
570/** Convert fr_pair_t into a JSON object
571 *
572 * If format.value.enum_as_int is set, and the given VP is an enum
573 * value, the integer value is returned as a json_object rather
574 * than the text representation.
575 *
576 * If format.value.always_string is set then a numeric value
577 * will be returned as a JSON string object.
578 *
579 * @param[in] ctx Talloc context.
580 * @param[out] out returned json object.
581 * @param[in] vp to get the value of.
582 * @param[in] format format definition, or NULL.
583 * @return
584 * - 0 on success.
585 * - -1 on error.
586 */
587static int json_afrom_pair(TALLOC_CTX *ctx, json_object **out,
588 fr_pair_t *vp, fr_json_format_t const *format)
589{
590 fr_value_box_t const *vb;
591
592 fr_assert(vp);
593
594 vb = &vp->data;
595
596 if (format->value.enum_as_int) {
597 (void)fr_pair_value_enum_box(&vb, vp);
598 }
599
600 return json_afrom_value_box(ctx, out, vb, format);
601}
602
603
604/** Get attribute name with optional prefix
605 *
606 * If the format "attr.prefix" string is set then prepend this
607 * to the given attribute name, otherwise just return name alone.
608 *
609 * @param[out] out sbuff to write the new name
610 * @param[in] da dictionary attribute to get name of
611 * @param[in] format json format structure
612 * @return length of attribute name
613 */
615{
616 fr_sbuff_t our_out;
617
618 if (!out) return 0;
619
620 our_out = FR_SBUFF(out);
621
622 if (format->attr.prefix) {
623 FR_SBUFF_IN_STRCPY_RETURN(&our_out, format->attr.prefix);
624 FR_SBUFF_IN_CHAR_RETURN(&our_out, ':');
625 }
626
627 FR_SBUFF_IN_BSTRNCPY_RETURN(&our_out, da->name, da->name_len);
628
629 FR_SBUFF_SET_RETURN(out, &our_out);
630}
631
632
633/** Verify that the options in fr_json_format_t are valid
634 *
635 * Warnings are optional, will fatal error if the format is corrupt.
636 *
637 * @param[in] format the format structure to check
638 * @param[in] verbose print out warnings if set
639 * @return true if format is good, otherwise false
640 */
641bool fr_json_format_verify(fr_json_format_t const *format, bool verbose)
642{
643 bool ret = true;
644
646
647 switch (format->output_mode) {
648 case JSON_MODE_OBJECT:
650 case JSON_MODE_ARRAY:
651 /* all options are valid */
652 return true;
654 if (format->attr.prefix) {
655 if (verbose) WARN("attribute name prefix not valid in output_mode 'array_of_values' and will be ignored");
656 ret = false;
657 }
658 if (format->value.value_is_always_array) {
659 if (verbose) WARN("'value_is_always_array' not valid in output_mode 'array_of_values' and will be ignored");
660 ret = false;
661 }
662 return ret;
664 if (format->value.value_is_always_array) {
665 if (verbose) WARN("'value_is_always_array' not valid in output_mode 'array_of_names' and will be ignored");
666 ret = false;
667 }
668 if (format->value.enum_as_int) {
669 if (verbose) WARN("'enum_as_int' not valid in output_mode 'array_of_names' and will be ignored");
670 ret = false;
671 }
672 if (format->value.always_string) {
673 if (verbose) WARN("'always_string' not valid in output_mode 'array_of_names' and will be ignored");
674 ret = false;
675 }
676 return ret;
677 default:
678 ERROR("JSON format output mode is invalid");
679 }
680
681 /* If we get here, something has gone wrong */
682 fr_assert(0);
683
684 return false;
685}
686
687#define INVALID_TYPE \
688do { \
689 fr_assert(0); \
690 fr_strerror_printf("Invalid type %s for attribute %s", fr_type_to_str(vp->vp_type), vp->da->name); \
691 goto error; \
692} while (0)
693
694/** Returns a JSON object representation of a list of value pairs
695 *
696 * The result is a struct json_object, which should be free'd with
697 * json_object_put() by the caller. Intended to only be called by
698 * fr_json_afrom_pair_list().
699 *
700 * This function generates the "object" format, JSON_MODE_OBJECT.
701 * @see fr_json_format_s
702 *
703@verbatim
704{
705 "<attribute0>":{
706 "type":"<type0>",
707 "value":[<value0>,<value1>,<valueN>] // if value_is_always_array is true
708 }, // or
709 "<attribute1>":{
710 "type":"<type1>",
711 "value":<value0> // if value_is_always_array is false
712 // and there is only one value
713 },
714 "<attributeN>":{
715 "type":"<typeN>",
716 "value":[...]
717 }
718}
719@endverbatim
720 *
721 * @param[in] ctx Talloc context.
722 * @param[in] vps a list of value pairs.
723 * @param[in] format Formatting control, must be set.
724 * @return JSON object with the generated representation.
725 */
726static CC_HINT(warn_unused_result)
727json_object *json_object_afrom_pair_list(TALLOC_CTX *ctx, fr_pair_list_t *vps, fr_json_format_t const *format)
728{
729 fr_pair_t *vp;
730 struct json_object *obj;
731 char buf[FR_DICT_ATTR_MAX_NAME_LEN + 32];
732
733 /* Check format and type */
735 fr_assert(format->output_mode == JSON_MODE_OBJECT);
736
737 MEM(obj = json_object_new_object());
738
739 for (vp = fr_pair_list_head(vps);
740 vp;
741 vp = fr_pair_list_next(vps, vp)) {
742 fr_sbuff_t attr_name;
743 struct json_object *vp_object, *values, *value, *type_name;
744
745 if (vp->vp_raw) continue;
746
747 /*
748 * Get attribute name and value.
749 */
750 fr_sbuff_init_in(&attr_name, buf, sizeof(buf) - 1);
751 if (attr_name_with_prefix(&attr_name, vp->da, format) < 0) {
752 error:
754 return NULL;
755 }
756
757 switch (vp->vp_type) {
758 case FR_TYPE_LEAF:
759 if (json_afrom_pair(ctx, &value, vp, format) < 0) {
760 fr_strerror_const("Failed to convert attribute value to JSON object");
761 goto error;
762 }
763 break;
764 /*
765 * For nested attributes we recurse. The nesting is represented
766 * as a table, either as the single value, or as an element in
767 * an array.
768 *
769 * ...
770 * "value" : { "nested_attr" : { "type" : "<nested_type>", "value" : "<nested_attr_value>" } }
771 * ...
772 *
773 * ...
774 * "value" : [ { "nested_attr" : { "type" : "<nested_type>", "value" : "<nested_attr_value>" } } ]
775 * ...
776 *
777 * The formatting of nested attributes and their structure is
778 * identical to top level attributes.
779 */
781 value = json_object_afrom_pair_list(ctx, &vp->vp_group, format);
782 if (unlikely(value == NULL)) goto error;
783 break;
784
785 default:
787 }
788
789 /*
790 * Look in the table to see if we already have a key for the attribute
791 * we're working on.
792 *
793 * If we don't we create a new object in either the form:
794 *
795 * "<attribute>": {
796 * "type": "<type>",
797 * "value": [<value>] // if value_is_always_array is true
798 * // or
799 * "value": <value> // if value_is_always_array is false
800 * // and there is only one value
801 * }
802 */
803 if (!json_object_object_get_ex(obj, fr_sbuff_start(&attr_name), &vp_object)) {
804 /*
805 * Wasn't there, so create a new object for this attribute.
806 */
807 MEM(vp_object = json_object_new_object());
808 json_object_object_add(obj, fr_sbuff_start(&attr_name), vp_object);
809
810 /*
811 * Add "type" to newly created keys.
812 */
813 MEM(type_name = json_object_new_string(fr_type_to_str(vp->vp_type)));
814 json_object_object_add_ex(vp_object, "type", type_name, JSON_C_OBJECT_KEY_IS_CONSTANT);
815
816 /*
817 * Create a "value" array to hold any attribute values for this attribute...
818 */
819 if (format->value.value_is_always_array) {
820 MEM(values = json_object_new_array());
821 json_object_object_add_ex(vp_object, "value", values, JSON_C_OBJECT_KEY_IS_CONSTANT);
822 json_object_array_add(values, value);
823 continue;
824 }
825
826 /*
827 * ...or just add the value directly.
828 */
829 json_object_object_add_ex(vp_object, "value", value, JSON_C_OBJECT_KEY_IS_CONSTANT);
830
831 continue; /* Next attribute! */
832 }
833
834 /*
835 * Find the 'values' array to add the current value to.
836 */
837 if (!fr_cond_assert(json_object_object_get_ex(vp_object, "value", &values))) {
838 fr_strerror_const("Inconsistent JSON tree");
839 goto error;
840 }
841
842 /*
843 * If value_is_always_array is no set then "values" may not be an array, so it will
844 * need converting to an array to add this extra attribute.
845 */
846 if (!format->value.value_is_always_array) {
847 json_type type;
848 struct json_object *convert_value = values;
849
850 /* Check "values" type */
851 type = json_object_get_type(values);
852
853 /* It wasn't an array, so turn it into one with the old value as the first entry */
854 if (type != json_type_array) {
855 MEM(values = json_object_new_array());
856 json_object_array_add(values, json_object_get(convert_value));
857 json_object_object_del(vp_object, "value");
858 json_object_object_add_ex(vp_object, "value", values,
859 JSON_C_OBJECT_KEY_IS_CONSTANT);
860 }
861 }
862 json_object_array_add(values, value);
863 }
864
865 return obj;
866}
867
868
869/** Returns a JSON object representation of a list of value pairs
870 *
871 * The result is a struct json_object, which should be free'd with
872 * json_object_put() by the caller. Intended to only be called by
873 * fr_json_afrom_pair_list().
874 *
875 * This function generates the "simple object" format, JSON_MODE_OBJECT_SIMPLE.
876 * @see fr_json_format_s
877 *
878@verbatim
879{
880 "<attribute0>":[<value0>,<value1>,<valueN>] // if value_is_always_array is true
881 // or
882 "<attribute1>":<value0> // if value_is_always_array is false,
883 // and there is only one value
884 "<attributeN>":[<value0>,<value1>,<valueN>]
885}
886@endverbatim
887 *
888 * @param[in] ctx Talloc context.
889 * @param[in] vps a list of value pairs.
890 * @param[in] format Formatting control, must be set.
891 * @return JSON object with the generated representation.
892 */
893static json_object *json_simple_obj_afrom_pair_list(TALLOC_CTX *ctx, fr_pair_list_t *vps,
894 fr_json_format_t const *format)
895{
896 fr_pair_t *vp;
897 struct json_object *obj;
898 char buf[FR_DICT_ATTR_MAX_NAME_LEN + 32];
899 json_type type;
900
901 /* Check format and type */
904
905 MEM(obj = json_object_new_object());
906
907 for (vp = fr_pair_list_head(vps);
908 vp;
909 vp = fr_pair_list_next(vps, vp)) {
910 fr_sbuff_t attr_name;
911 struct json_object *vp_object, *value;
912 struct json_object *values = NULL;
913 bool add_single = false;
914
915 if (vp->vp_raw) continue;
916
917 /*
918 * Get attribute name and value.
919 */
920 fr_sbuff_init_in(&attr_name, buf, sizeof(buf) - 1);
921 if (attr_name_with_prefix(&attr_name, vp->da, format) < 0) {
922 error:
924 return NULL;
925 }
926
927 switch (vp->vp_type) {
928 case FR_TYPE_LEAF:
929 if (json_afrom_pair(ctx, &value, vp, format) < 0) {
930 fr_strerror_const("Failed to convert attribute value to JSON object");
931 goto error;
932 }
933 break;
934 /*
935 * For nested attributes we recurse. The nesting is represented
936 * as a table, either as the single value, or as an element in
937 * an array.
938 *
939 * ...
940 * "<parent>" : { "<nested_attr>" : <nested_attr_value> }
941 * ...
942 *
943 * ...
944 * "<parent>" : [ { "<nested_attr>" : "<nested_attr_value>" } ]
945 * ...
946 *
947 * The formatting of nested attributes and their structure is
948 * identical to top level attributes.
949 */
952 if (unlikely(value == NULL)) goto error;
953 break;
954
955 default:
957 }
958
959 /*
960 * See if we already have a key in the table we're working on,
961 * if not then create a new one.
962 */
963 if (!json_object_object_get_ex(obj, fr_sbuff_start(&attr_name), &vp_object)) {
964 if (format->value.value_is_always_array) {
965 /*
966 * We have been asked to ensure /all/ values are lists,
967 * even if there's only one attribute.
968 */
969 MEM(values = json_object_new_array());
970 json_object_object_add(obj, fr_sbuff_start(&attr_name), values);
971 } else {
972 /*
973 * Deal with it later on.
974 */
975 add_single = true;
976 }
977 /*
978 * If we do have the key already, get its value array.
979 */
980 } else {
981 type = json_object_get_type(vp_object);
982
983 if (type == json_type_array) {
984 values = vp_object;
985 } else {
986 /*
987 * We've seen one of these before, but didn't add
988 * it as an array the first time. Sort that out.
989 */
990 MEM(values = json_object_new_array());
991 json_object_array_add(values, json_object_get(vp_object));
992
993 /*
994 * Existing key will have refcount decremented
995 * and will be freed if this drops to zero.
996 */
997 json_object_object_add(obj, fr_sbuff_start(&attr_name), values);
998 }
999 }
1000
1001 if (add_single) {
1002 /*
1003 * Only ever used the first time adding a new
1004 * attribute when "value_is_always_array" is not set.
1005 */
1006 json_object_object_add(obj, fr_sbuff_start(&attr_name), value);
1007 } else {
1008 /*
1009 * Otherwise we're always appending to a JSON array.
1010 */
1011 json_object_array_add(values, value);
1012 }
1013 }
1014
1015 return obj;
1016}
1017
1018
1019/** Returns a JSON array representation of a list of value pairs
1020 *
1021 * The result is a struct json_object, which should be free'd with
1022 * json_object_put() by the caller. Intended to only be called by
1023 * fr_json_afrom_pair_list().
1024 *
1025 * This function generates the "array" format, JSON_MODE_ARRAY.
1026 * @see fr_json_format_s
1027 *
1028 * @param[in] ctx Talloc context.
1029 * @param[in] vps a list of value pairs.
1030 * @param[in] format Formatting control, must be set.
1031 * @return JSON object with the generated representation.
1032 */
1033static struct json_object *json_array_afrom_pair_list(TALLOC_CTX *ctx, fr_pair_list_t *vps,
1034 fr_json_format_t const *format)
1035{
1036 fr_pair_t *vp;
1037 struct json_object *obj;
1038 struct json_object *seen_attributes = NULL;
1039 char buf[FR_DICT_ATTR_MAX_NAME_LEN + 32];
1040
1041 /* Check format and type */
1043 fr_assert(format->output_mode == JSON_MODE_ARRAY);
1044
1045 MEM(obj = json_object_new_array());
1046
1047 /*
1048 * If attribute values should be in a list format, then keep track
1049 * of the attributes we've previously seen in a JSON object.
1050 */
1051 if (format->value.value_is_always_array) {
1052 seen_attributes = json_object_new_object();
1053 }
1054
1055 for (vp = fr_pair_list_head(vps);
1056 vp;
1057 vp = fr_pair_list_next(vps, vp)) {
1058 fr_sbuff_t attr_name;
1059 struct json_object *name, *value, *type_name;
1060 struct json_object *values = NULL;
1061 struct json_object *attrobj = NULL;
1062 bool already_seen = false;
1063
1064 if (vp->vp_raw) continue;
1065
1066 /*
1067 * Get attribute name and value.
1068 */
1069 fr_sbuff_init_in(&attr_name, buf, sizeof(buf) - 1);
1070 if (attr_name_with_prefix(&attr_name, vp->da, format) < 0) {
1071 error:
1072 json_object_put_assert(seen_attributes);
1074 return NULL;
1075 }
1076
1077 switch (vp->vp_type) {
1078 case FR_TYPE_LEAF:
1079 if (json_afrom_pair(ctx, &value, vp, format) < 0) {
1080 fr_strerror_const("Failed to convert attribute value to JSON object");
1081 goto error;
1082 }
1083 break;
1084
1085 case FR_TYPE_STRUCTURAL:
1086 value = json_array_afrom_pair_list(ctx, &vp->vp_group, format);
1087 if (unlikely(value == NULL)) goto error;
1088 break;
1089
1090 default:
1092 }
1093
1094 if (format->value.value_is_always_array) {
1095 /*
1096 * Try and find this attribute in the "seen_attributes" object. If it is
1097 * there then get the "values" array to add this attribute value to.
1098 */
1099 already_seen = json_object_object_get_ex(seen_attributes, fr_sbuff_start(&attr_name), &values);
1100 }
1101
1102 /*
1103 * If we're adding all attributes to the toplevel array, or we're adding values
1104 * to an array of an existing attribute but haven't seen it before, then we need
1105 * to create a new JSON object for this attribute.
1106 */
1107 if (!format->value.value_is_always_array || !already_seen) {
1108 /*
1109 * Create object and add it to top-level array
1110 */
1111 MEM(attrobj = json_object_new_object());
1112 json_object_array_add(obj, attrobj);
1113
1114 /*
1115 * Add the attribute name in the "name" key and the type in the "type" key
1116 */
1117 MEM(name = json_object_new_string(fr_sbuff_start(&attr_name)));
1118 json_object_object_add_ex(attrobj, "name", name, JSON_C_OBJECT_KEY_IS_CONSTANT);
1119
1120 MEM(type_name = json_object_new_string(fr_type_to_str(vp->vp_type)));
1121 json_object_object_add_ex(attrobj, "type", type_name, JSON_C_OBJECT_KEY_IS_CONSTANT);
1122 }
1123
1124 if (format->value.value_is_always_array) {
1125 /*
1126 * We're adding values to an array for the first copy of this attribute
1127 * that we saw. First time around we need to create an array.
1128 */
1129 if (!already_seen) {
1130 MEM(values = json_object_new_array());
1131 /*
1132 * Add "value":[] key to the attribute object
1133 */
1134 json_object_object_add_ex(attrobj, "value", values, JSON_C_OBJECT_KEY_IS_CONSTANT);
1135
1136 /*
1137 * Also add to "seen_attributes" to check later
1138 */
1139 json_object_object_add(seen_attributes, fr_sbuff_start(&attr_name), json_object_get(values));
1140 }
1141
1142 /*
1143 * Always add the value to the respective "values" array.
1144 */
1145 json_object_array_add(values, value);
1146 } else {
1147 /*
1148 * This is simpler; just add a "value": key to the attribute object.
1149 */
1150 json_object_object_add_ex(attrobj, "value", value, JSON_C_OBJECT_KEY_IS_CONSTANT);
1151 }
1152
1153 }
1154
1155 /*
1156 * No longer need the "seen_attributes" object, it was just used for tracking.
1157 */
1158 if (format->value.value_is_always_array) {
1159 json_object_put_assert(seen_attributes);
1160 }
1161
1162 return obj;
1163}
1164
1165
1166/** Returns a JSON array of a list of value pairs
1167 *
1168 * The result is a struct json_object, which should be free'd with
1169 * json_object_put() by the caller. Intended to only be called by
1170 * fr_json_afrom_pair_list().
1171 *
1172 * This function generates the "array_of_values" format,
1173 * JSON_MODE_ARRAY_OF_VALUES, listing just the attribute values.
1174 * @see fr_json_format_s
1175 *
1176 * @param[in] ctx Talloc context.
1177 * @param[in] vps a list of value pairs.
1178 * @param[in] format Formatting control, must be set.
1179 * @return JSON object with the generated representation.
1180 */
1181static struct json_object *json_value_array_afrom_pair_list(TALLOC_CTX *ctx, fr_pair_list_t *vps,
1182 fr_json_format_t const *format)
1183{
1184 fr_pair_t *vp;
1185 struct json_object *obj;
1186
1187 /* Check format and type */
1190
1191 MEM(obj = json_object_new_array());
1192
1193 /*
1194 * This array format is very simple - just add all the
1195 * attribute values to the array in order.
1196 */
1197 for (vp = fr_pair_list_head(vps);
1198 vp;
1199 vp = fr_pair_list_next(vps, vp)) {
1200 struct json_object *value;
1201
1202 if (vp->vp_raw) continue;
1203
1204 switch (vp->vp_type) {
1205 case FR_TYPE_LEAF:
1206 if (json_afrom_pair(ctx, &value, vp, format) < 0) {
1207 fr_strerror_const("Failed to convert attribute value to JSON object");
1208 error:
1210 return NULL;
1211 }
1212 break;
1213
1214 case FR_TYPE_STRUCTURAL:
1215 value = json_value_array_afrom_pair_list(ctx, &vp->vp_group, format);
1216 if (value == NULL) goto error;
1217 break;
1218
1219 default:
1221 }
1222
1223 json_object_array_add(obj, value);
1224 }
1225
1226 return obj;
1227}
1228
1229
1230/** Returns a JSON array of a list of value pairs
1231 *
1232 * The result is a struct json_object, which should be free'd with
1233 * json_object_put() by the caller. Intended to only be called by
1234 * fr_json_afrom_pair_list().
1235 *
1236 * This function generates the "array_of_names" format,
1237 * JSON_MODE_ARRAY_OF_NAMES, listing just the attribute names.
1238 * @see fr_json_format_s
1239 *
1240 * @param[in] ctx Talloc context.
1241 * @param[in] vps a list of value pairs.
1242 * @param[in] format Formatting control, must be set.
1243 * @return JSON object with the generated representation.
1244 */
1245static struct json_object *json_attr_array_afrom_pair_list(TALLOC_CTX *ctx, fr_pair_list_t *vps,
1246 fr_json_format_t const *format)
1247{
1248 fr_pair_t *vp;
1249 struct json_object *obj;
1250 char buf[FR_DICT_ATTR_MAX_NAME_LEN + 32];
1251
1252 /* Check format and type */
1254 fr_assert(format->output_mode == JSON_MODE_ARRAY_OF_NAMES);
1255
1256 MEM(obj = json_object_new_array());
1257
1258 /*
1259 * Add all the attribute names to the array in order.
1260 */
1261 for (vp = fr_pair_list_head(vps);
1262 vp;
1263 vp = fr_pair_list_next(vps, vp)) {
1264 struct json_object *value;
1265 fr_sbuff_t attr_name;
1266
1267 if (vp->vp_raw) continue;
1268
1269 fr_sbuff_init_in(&attr_name, buf, sizeof(buf) - 1);
1270 if (attr_name_with_prefix(&attr_name, vp->da, format) < 0) {
1271 error:
1273 return NULL;
1274 }
1275 value = json_object_new_string(fr_sbuff_start(&attr_name));
1276
1277 switch (vp->vp_type) {
1278 case FR_TYPE_LEAF:
1279 break;
1280
1281 case FR_TYPE_STRUCTURAL:
1282 json_object_array_add(obj, value);
1283 value = json_attr_array_afrom_pair_list(ctx, &vp->vp_group, format);
1284 if (value == NULL) goto error;
1285 break;
1286
1287 default:
1289 }
1290
1291 json_object_array_add(obj, value);
1292 }
1293
1294 return obj;
1295}
1296
1297
1298/** Returns a JSON string of a list of value pairs
1299 *
1300 * The result is a talloc-ed string, freeing the string is
1301 * the responsibility of the caller.
1302 *
1303 * The 'format' struct contains settings to configure the output
1304 * JSON document format.
1305 * @see fr_json_format_s
1306 *
1307 * Default output, when format is NULL, is:
1308@verbatim
1309{
1310 "<attribute0>":{
1311 "type":"<type0>",
1312 "value":[<value0>,<value1>,<valueN>]
1313 },
1314 "<attribute1>":{
1315 "type":"<type1>",
1316 "value":[...]
1317 },
1318 "<attributeN>":{
1319 "type":"<typeN>",
1320 "value":[...]
1321 }
1322}
1323@endverbatim
1324 *
1325 * @param[in] ctx Talloc context.
1326 * @param[in] vps a list of value pairs.
1327 * @param[in] format Formatting control, can be NULL to use default format.
1328 * @return JSON string representation of the value pairs
1329 */
1330char *fr_json_afrom_pair_list(TALLOC_CTX *ctx, fr_pair_list_t *vps,
1331 fr_json_format_t const *format)
1332{
1333 struct json_object *obj = NULL;
1334 const char *p;
1335 char *out;
1336
1338
1339 switch (format->output_mode) {
1340 case JSON_MODE_OBJECT:
1341 MEM(obj = json_object_afrom_pair_list(ctx, vps, format));
1342 break;
1344 MEM(obj = json_simple_obj_afrom_pair_list(ctx, vps, format));
1345 break;
1346 case JSON_MODE_ARRAY:
1347 MEM(obj = json_array_afrom_pair_list(ctx, vps, format));
1348 break;
1351 break;
1353 MEM(obj = json_attr_array_afrom_pair_list(ctx, vps, format));
1354 break;
1355 default:
1356 /* This should never happen */
1357 fr_assert(0);
1358 }
1359
1360 /*
1361 * p is a buff inside obj, and will be freed
1362 * when it is freed.
1363 */
1364 MEM(p = json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN));
1365 MEM(out = talloc_strdup(ctx, p));
1366
1367 /*
1368 * Free the JSON structure, it's not needed any more
1369 */
1371
1372 return out;
1373}
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:228
#define unlikely(_x)
Definition build.h:407
#define NUM_ELEMENTS(_t)
Definition build.h:358
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:1724
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:669
cf_parse_t func
Override default parsing behaviour for the specified type with a custom parsing function.
Definition cf_parse.h:623
#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:606
#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:131
#define fr_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error.
Definition debug.h:208
#define MEM(x)
Definition debug.h:36
#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:3632
ssize_t fr_dict_valid_name(char const *name, ssize_t len)
Definition dict_util.c:4915
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:3678
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:91
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:1330
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:1181
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:213
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:687
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:300
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:587
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:508
void fr_json_version_print(void)
Print JSON-C version.
Definition json.c:484
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:1033
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:727
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:1245
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:116
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:641
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:614
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:893
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:3092
#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:1469
#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:149
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:6105
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:3946
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:4394
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition value.c:4377
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:4838
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