All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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: 0451c64e51a15ffdaa9cdf251833255de0eee70c $
19  * @file json.c
20  * @brief Common functions for working with json-c
21  *
22  * @author Arran Cudbard-Bell
23  *
24  * @copyright 2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
25  * @copyright 2015 Network RADIUS SARL <info@networkradius.com>
26  * @copyright 2015 The FreeRADIUS Server Project
27  */
28 #include <freeradius-devel/rad_assert.h>
29 #include "json.h"
30 
31 /** Convert json object to value_data_t
32  *
33  * @param ctx to allocate any value buffers in (should usually be the same as out).
34  * @param out Where to write value_data.
35  * @param object to convert.
36  * @param dst_type FreeRADIUS type to convert to.
37  * @param dst_enumv Enumeration values to allow string to integer conversions.
38  * @return
39  * - 0 on success.
40  * - -1 on failure.
41  */
42 int fr_json_object_to_value_data(TALLOC_CTX *ctx, value_data_t *out, json_object *object,
43  PW_TYPE dst_type, fr_dict_attr_t const *dst_enumv)
44 {
45  PW_TYPE src_type = PW_TYPE_INVALID;
46  value_data_t in;
47 
48  memset(&in, 0, sizeof(in));
49 
50  switch (fr_json_object_get_type(object)) {
51  case json_type_string:
52  src_type = PW_TYPE_STRING;
53  in.strvalue = json_object_get_string(object);
55  break;
56 
57  case json_type_double:
58  src_type = PW_TYPE_DECIMAL;
59  in.decimal = json_object_get_double(object);
60  in.length = sizeof(in.decimal);
61  break;
62 
63  case json_type_int:
64  {
65 #ifdef HAVE_JSON_OBJECT_GET_INT64
66  int64_t num;
67 #else
68  int32_t num;
69 #endif
70 #ifndef HAVE_JSON_OBJECT_GET_INT64
71  if (dst_type == PW_TYPE_INTEGER64) {
72  fr_strerror_printf("64bit integers are not supported by linked json-c. "
73  "Upgrade to json-c > 0.10 to use this feature");
74  return -1;
75  }
76 #endif
77 
78 #ifndef HAVE_JSON_OBJECT_GET_INT64
79  num = json_object_get_int(object);
80 #else
81  num = json_object_get_int64(object);
82  if (num < INT32_MIN) { /* 64bit signed (not supported)*/
83  fr_strerror_printf("Signed 64bit integers are not supported");
84  return -1;
85  }
86  if (num > UINT32_MAX) { /* 64bit unsigned (supported) */
87  src_type = PW_TYPE_INTEGER64;
88  in.integer64 = (uint64_t) num;
89  in.length = sizeof(in.integer64);
90  } else
91 #endif
92  if (num < 0) { /* 32bit signed (supported) */
93  src_type = PW_TYPE_SIGNED;
94  in.sinteger = num;
95  in.length = sizeof(in.sinteger);
96  } else if (num > UINT16_MAX) { /* 32bit unsigned (supported) */
97  src_type = PW_TYPE_INTEGER;
98  in.integer = (uint32_t) num;
99  in.length = sizeof(in.integer);
100  } else if (num > UINT8_MAX) { /* 16bit unsigned (supported) */
101  src_type = PW_TYPE_SHORT;
102  in.ushort = (uint16_t) num;
103  in.length = sizeof(in.ushort);
104  } else if (num >= 0) { /* 8bit unsigned (supported) */
105  src_type = PW_TYPE_BYTE;
106  in.byte = (uint8_t) num;
107  in.length = sizeof(in.byte);
108  } else {
109  rad_assert(0);
110  return -1;
111  }
112  }
113  break;
114 
115  case json_type_boolean:
116  src_type = PW_TYPE_BOOLEAN;
117  in.boolean = json_object_get_boolean(object);
118  in.length = sizeof(in.boolean);
119  break;
120 
121  case json_type_null:
122  case json_type_array:
123  case json_type_object:
124  src_type = PW_TYPE_STRING;
125  in.strvalue = json_object_to_json_string(object);
126  in.length = strlen(in.strvalue);
127  break;
128  }
129 
130  if (src_type == dst_type) {
131  if (value_data_copy(ctx, out, src_type, &in) < 0) return -1;
132  } else {
133  if (value_data_cast(ctx, out, dst_type, dst_enumv, src_type, NULL, &in) < 0) return -1;
134  }
135  return 0;
136 }
137 
138 /** Prints attribute as string, escaped suitably for use as JSON string
139  *
140  * Returns < 0 if the buffer may be (or have been) too small to write the encoded
141  * JSON value to.
142  *
143  * @param out Where to write the string.
144  * @param outlen Lenth of output buffer.
145  * @param vp to print.
146  * @return
147  * - Length of data written to out.
148  * - value >= outlen on truncation.
149  */
150 size_t fr_json_from_pair(char *out, size_t outlen, VALUE_PAIR const *vp)
151 {
152  char const *q;
153  size_t len, freespace = outlen;
154 
155  if (!vp->da->flags.has_tag) {
156  switch (vp->da->type) {
157  case PW_TYPE_INTEGER:
158  if (vp->da->flags.has_value) break;
159 
160  return snprintf(out, freespace, "%u", vp->vp_integer);
161 
162  case PW_TYPE_SHORT:
163  if (vp->da->flags.has_value) break;
164 
165  return snprintf(out, freespace, "%u", (unsigned int) vp->vp_short);
166 
167  case PW_TYPE_BYTE:
168  if (vp->da->flags.has_value) break;
169 
170  return snprintf(out, freespace, "%u", (unsigned int) vp->vp_byte);
171 
172  case PW_TYPE_SIGNED:
173  return snprintf(out, freespace, "%d", vp->vp_signed);
174 
175  default:
176  break;
177  }
178  }
179 
180  /* Indicate truncation */
181  if (freespace < 2) return outlen + 1;
182  *out++ = '"';
183  freespace--;
184 
185  switch (vp->da->type) {
186  case PW_TYPE_STRING:
187  for (q = vp->vp_strvalue; q < vp->vp_strvalue + vp->vp_length; q++) {
188  /* Indicate truncation */
189  if (freespace < 3) return outlen + 1;
190 
191  if (*q == '"') {
192  *out++ = '\\';
193  *out++ = '"';
194  freespace -= 2;
195  } else if (*q == '\\') {
196  *out++ = '\\';
197  *out++ = '\\';
198  freespace -= 2;
199  } else if (*q == '/') {
200  *out++ = '\\';
201  *out++ = '/';
202  freespace -= 2;
203  } else if (*q >= ' ') {
204  *out++ = *q;
205  freespace--;
206  } else {
207  *out++ = '\\';
208  freespace--;
209 
210  switch (*q) {
211  case '\b':
212  *out++ = 'b';
213  freespace--;
214  break;
215 
216  case '\f':
217  *out++ = 'f';
218  freespace--;
219  break;
220 
221  case '\n':
222  *out++ = 'b';
223  freespace--;
224  break;
225 
226  case '\r':
227  *out++ = 'r';
228  freespace--;
229  break;
230 
231  case '\t':
232  *out++ = 't';
233  freespace--;
234  break;
235  default:
236  len = snprintf(out, freespace, "u%04X", *q);
237  if (is_truncated(len, freespace)) return (outlen - freespace) + len;
238  out += len;
239  freespace -= len;
240  }
241  }
242  }
243  break;
244 
245  default:
246  len = fr_pair_value_snprint(out, freespace, vp, 0);
247  if (is_truncated(len, freespace)) return (outlen - freespace) + len;
248  out += len;
249  freespace -= len;
250  break;
251  }
252 
253  /* Indicate truncation */
254  if (freespace < 2) return outlen + 1;
255  *out++ = '"';
256  freespace--;
257  *out = '\0'; // We don't increment out, because the nul byte should not be included in the length
258 
259  return outlen - freespace;
260 }
261 
262 /** Print JSON-C version
263  *
264  */
266 {
267  static bool done_version;
268 
269  if (!done_version) {
270  done_version = true;
271 
272 #ifdef HAVE_JSON_C_VERSION
273  INFO("libfreeradius-json: json-c version: %s", json_c_version());
274 #else
275  INFO("libfreeradius-json: json-c version: Unknown (less than 0.10) - Please upgrade");
276 #endif
277  }
278 }
279 
#define fr_json_object_get_type(_obj)
Definition: json_missing.h:56
int fr_json_object_to_value_data(TALLOC_CTX *ctx, value_data_t *out, json_object *object, PW_TYPE dst_type, fr_dict_attr_t const *dst_enumv)
Convert json object to value_data_t.
Definition: json.c:42
Dictionary attribute.
Definition: dict.h:77
32 Bit signed integer.
Definition: radius.h:45
#define INFO(fmt,...)
Definition: log.h:143
void size_t fr_pair_value_snprint(char *out, size_t outlen, VALUE_PAIR const *vp, char quote)
Print the value of an attribute to a string.
Definition: pair.c:2107
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:686
fr_dict_attr_flags_t flags
Flags.
Definition: dict.h:88
#define is_truncated(_ret, _max)
Definition: libradius.h:204
#define rad_assert(expr)
Definition: rad_assert.h:38
8 Bit unsigned integer.
Definition: radius.h:42
int value_data_cast(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE dst_type, fr_dict_attr_t const *dst_enumv, PW_TYPE src_type, fr_dict_attr_t const *src_enumv, value_data_t const *src)
Convert one type of value_data_t to another.
Definition: value.c:1073
Double precision floating point.
Definition: radius.h:58
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
Invalid (uninitialised) attribute type.
Definition: radius.h:32
A truth value.
Definition: radius.h:56
int json_object_get_string_len(json_object *obj)
Definition: json_missing.c:32
32 Bit unsigned integer.
Definition: radius.h:34
int value_data_copy(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE type, const value_data_t *src)
Copy value data verbatim duplicating any buffers.
Definition: value.c:1479
void fr_json_version_print(void)
Print JSON-C version.
Definition: json.c:265
64 Bit unsigned integer.
Definition: radius.h:51
size_t length
Length of value data.
Definition: pair.h:87
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
unsigned int has_tag
Tagged attribute.
Definition: dict.h:46
#define vp_strvalue
Definition: pair.h:165
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
Definition: pair.h:113
String of printable characters.
Definition: radius.h:33
size_t fr_json_from_pair(char *out, size_t outlen, VALUE_PAIR const *vp)
Prints attribute as string, escaped suitably for use as JSON string.
Definition: json.c:150
PW_TYPE type
Value type.
Definition: dict.h:80
16 Bit unsigned integer.
Definition: radius.h:43
PW_TYPE
Internal data types used within libfreeradius.
Definition: radius.h:31
unsigned int has_value
Has a value.
Definition: dict.h:48