/src/clamav/libclamav/json_api.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * JSON Object API |
3 | | * |
4 | | * Copyright (C) 2014-2023 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
5 | | * |
6 | | * Authors: Kevin Lin |
7 | | * |
8 | | * This program is free software; you can redistribute it and/or modify it under |
9 | | * the terms of the GNU General Public License version 2 as published by the |
10 | | * Free Software Foundation. |
11 | | * |
12 | | * This program is distributed in the hope that it will be useful, but WITHOUT |
13 | | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 | | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
15 | | * more details. |
16 | | * |
17 | | * You should have received a copy of the GNU General Public License along with |
18 | | * this program; if not, write to the Free Software Foundation, Inc., 51 |
19 | | * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
20 | | */ |
21 | | |
22 | | #if HAVE_CONFIG_H |
23 | | #include "clamav-config.h" |
24 | | #endif |
25 | | |
26 | | #include "clamav.h" |
27 | | #include "others.h" |
28 | | #include "json_api.h" |
29 | | |
30 | | #ifdef HAVE_JSON |
31 | | cl_error_t cli_json_timeout_cycle_check(cli_ctx *ctx, int *toval) |
32 | 2.14M | { |
33 | 2.14M | if (SCAN_COLLECT_METADATA) { |
34 | 2.14M | if (*toval <= 0) { |
35 | 412k | if (cli_checktimelimit(ctx) != CL_SUCCESS) { |
36 | 0 | cli_dbgmsg("cli_json_timeout_cycle_check: timeout!\n"); |
37 | 0 | return CL_ETIMEOUT; |
38 | 0 | } |
39 | 412k | (*toval)++; |
40 | 412k | } |
41 | 2.14M | if (*toval > JSON_TIMEOUT_SKIP_CYCLES) { |
42 | 0 | (*toval) = 0; |
43 | 0 | } |
44 | 2.14M | } |
45 | 2.14M | return CL_SUCCESS; |
46 | 2.14M | } |
47 | | |
48 | | cl_error_t cli_json_parse_error(json_object *root, const char *errstr) |
49 | 19.6k | { |
50 | 19.6k | json_object *perr; |
51 | | |
52 | 19.6k | if (!root) |
53 | 0 | return CL_SUCCESS; /* CL_ENULLARG? */ |
54 | | |
55 | 19.6k | perr = cli_jsonarray(root, "ParseErrors"); |
56 | 19.6k | if (perr == NULL) { |
57 | 0 | return CL_EMEM; |
58 | 0 | } |
59 | | |
60 | 19.6k | return cli_jsonstr(perr, NULL, errstr); |
61 | 19.6k | } |
62 | | |
63 | | cl_error_t cli_jsonnull(json_object *obj, const char *key) |
64 | 233 | { |
65 | 233 | json_type objty; |
66 | 233 | json_object *fpobj = NULL; |
67 | 233 | if (NULL == obj) { |
68 | 0 | cli_dbgmsg("json: null 'obj' specified to cli_jsonnull\n"); |
69 | 0 | return CL_ENULLARG; |
70 | 0 | } |
71 | 233 | objty = json_object_get_type(obj); |
72 | | |
73 | 233 | if (objty == json_type_object) { |
74 | 233 | if (NULL == key) { |
75 | 0 | cli_dbgmsg("json: null string specified as key to cli_jsonnull\n"); |
76 | 0 | return CL_ENULLARG; |
77 | 0 | } |
78 | | |
79 | 233 | json_object_object_add(obj, key, fpobj); |
80 | 233 | } else if (objty == json_type_array) { |
81 | 0 | json_object_array_add(obj, fpobj); |
82 | 0 | } |
83 | | |
84 | 233 | return CL_SUCCESS; |
85 | 233 | } |
86 | | |
87 | | cl_error_t cli_jsonstr(json_object *obj, const char *key, const char *s) |
88 | 86.7M | { |
89 | 86.7M | json_type objty; |
90 | 86.7M | json_object *fpobj; |
91 | 86.7M | if (NULL == obj) { |
92 | 0 | cli_dbgmsg("json: null 'obj' specified to cli_jsonstr\n"); |
93 | 0 | return CL_ENULLARG; |
94 | 0 | } |
95 | 86.7M | objty = json_object_get_type(obj); |
96 | | |
97 | 86.7M | if (objty == json_type_object) { |
98 | 78.4M | if (NULL == key) { |
99 | 0 | cli_dbgmsg("json: null string specified as 'key' to cli_jsonstr\n"); |
100 | 0 | return CL_ENULLARG; |
101 | 0 | } |
102 | 78.4M | } else if (objty != json_type_array) { |
103 | 0 | return CL_EARG; |
104 | 0 | } |
105 | | |
106 | 86.7M | if (NULL == s) { |
107 | 169k | cli_dbgmsg("json: null string specified as 's' to cli_jsonstr\n"); |
108 | 169k | return CL_ENULLARG; |
109 | 169k | } |
110 | | |
111 | 86.6M | fpobj = json_object_new_string(s); |
112 | 86.6M | if (NULL == fpobj) { |
113 | 0 | cli_errmsg("json: no memory for json string object\n"); |
114 | 0 | return CL_EMEM; |
115 | 0 | } |
116 | | |
117 | 86.6M | if (objty == json_type_object) |
118 | 78.2M | json_object_object_add(obj, key, fpobj); |
119 | 8.35M | else if (objty == json_type_array) |
120 | 8.35M | json_object_array_add(obj, fpobj); |
121 | | |
122 | 86.6M | return CL_SUCCESS; |
123 | 86.6M | } |
124 | | |
125 | | cl_error_t cli_jsonstrlen(json_object *obj, const char *key, const char *s, int len) |
126 | 0 | { |
127 | 0 | json_type objty; |
128 | 0 | json_object *fpobj; |
129 | 0 | if (NULL == obj) { |
130 | 0 | cli_dbgmsg("json: null 'obj' specified to cli_jsonstr\n"); |
131 | 0 | return CL_ENULLARG; |
132 | 0 | } |
133 | 0 | objty = json_object_get_type(obj); |
134 | |
|
135 | 0 | if (objty == json_type_object) { |
136 | 0 | if (NULL == key) { |
137 | 0 | cli_dbgmsg("json: null string specified as 'key' to cli_jsonstr\n"); |
138 | 0 | return CL_ENULLARG; |
139 | 0 | } |
140 | 0 | } else if (objty != json_type_array) { |
141 | 0 | return CL_EARG; |
142 | 0 | } |
143 | | |
144 | 0 | if (NULL == s) { |
145 | 0 | cli_dbgmsg("json: null string specified as 's' to cli_jsonstr\n"); |
146 | 0 | return CL_ENULLARG; |
147 | 0 | } |
148 | | |
149 | 0 | fpobj = json_object_new_string_len(s, len); |
150 | 0 | if (NULL == fpobj) { |
151 | 0 | cli_errmsg("json: no memory for json string object\n"); |
152 | 0 | return CL_EMEM; |
153 | 0 | } |
154 | | |
155 | 0 | if (objty == json_type_object) |
156 | 0 | json_object_object_add(obj, key, fpobj); |
157 | 0 | else if (objty == json_type_array) |
158 | 0 | json_object_array_add(obj, fpobj); |
159 | |
|
160 | 0 | return CL_SUCCESS; |
161 | 0 | } |
162 | | |
163 | | cl_error_t cli_jsonint(json_object *obj, const char *key, int32_t i) |
164 | 15.5M | { |
165 | 15.5M | json_type objty; |
166 | 15.5M | json_object *fpobj; |
167 | 15.5M | if (NULL == obj) { |
168 | 0 | cli_dbgmsg("json: no parent object specified to cli_jsonint\n"); |
169 | 0 | return CL_ENULLARG; |
170 | 0 | } |
171 | 15.5M | objty = json_object_get_type(obj); |
172 | | |
173 | 15.5M | if (objty == json_type_object) { |
174 | 14.5M | if (NULL == key) { |
175 | 0 | cli_dbgmsg("json: null string specified as key to cli_jsonint\n"); |
176 | 0 | return CL_ENULLARG; |
177 | 0 | } |
178 | 14.5M | } else if (objty != json_type_array) { |
179 | 0 | return CL_EARG; |
180 | 0 | } |
181 | | |
182 | 15.5M | fpobj = json_object_new_int(i); |
183 | 15.5M | if (NULL == fpobj) { |
184 | 0 | cli_errmsg("json: no memory for json int object\n"); |
185 | 0 | return CL_EMEM; |
186 | 0 | } |
187 | | |
188 | 15.5M | if (objty == json_type_object) |
189 | 14.5M | json_object_object_add(obj, key, fpobj); |
190 | 1.09M | else if (objty == json_type_array) |
191 | 1.09M | json_object_array_add(obj, fpobj); |
192 | | |
193 | 15.5M | return CL_SUCCESS; |
194 | 15.5M | } |
195 | | |
196 | | cl_error_t cli_jsonint64(json_object *obj, const char *key, int64_t i) |
197 | 26.6M | { |
198 | 26.6M | json_type objty; |
199 | 26.6M | json_object *fpobj; |
200 | 26.6M | if (NULL == obj) { |
201 | 0 | cli_dbgmsg("json: no parent object specified to cli_jsonint64\n"); |
202 | 0 | return CL_ENULLARG; |
203 | 0 | } |
204 | 26.6M | objty = json_object_get_type(obj); |
205 | | |
206 | 26.6M | if (objty == json_type_object) { |
207 | 26.6M | if (NULL == key) { |
208 | 0 | cli_dbgmsg("json: null string specified as key to cli_jsonint64\n"); |
209 | 0 | return CL_ENULLARG; |
210 | 0 | } |
211 | 26.6M | } else if (objty != json_type_array) { |
212 | 0 | return CL_EARG; |
213 | 0 | } |
214 | | |
215 | 26.6M | fpobj = json_object_new_int64(i); |
216 | 26.6M | if (NULL == fpobj) { |
217 | 0 | cli_errmsg("json: no memory for json int object.\n"); |
218 | 0 | return CL_EMEM; |
219 | 0 | } |
220 | | |
221 | 26.6M | if (objty == json_type_object) |
222 | 26.6M | json_object_object_add(obj, key, fpobj); |
223 | 0 | else if (objty == json_type_array) |
224 | 0 | json_object_array_add(obj, fpobj); |
225 | | |
226 | 26.6M | return CL_SUCCESS; |
227 | 26.6M | } |
228 | | |
229 | | cl_error_t cli_jsonbool(json_object *obj, const char *key, int i) |
230 | 3.00M | { |
231 | 3.00M | json_type objty; |
232 | 3.00M | json_object *fpobj; |
233 | 3.00M | if (NULL == obj) { |
234 | 0 | cli_dbgmsg("json: no parent object specified to cli_jsonbool\n"); |
235 | 0 | return CL_ENULLARG; |
236 | 0 | } |
237 | 3.00M | objty = json_object_get_type(obj); |
238 | | |
239 | 3.00M | if (objty == json_type_object) { |
240 | 3.00M | if (NULL == key) { |
241 | 0 | cli_dbgmsg("json: null string specified as key to cli_jsonbool\n"); |
242 | 0 | return CL_ENULLARG; |
243 | 0 | } |
244 | 3.00M | } else if (objty != json_type_array) { |
245 | 0 | return CL_EARG; |
246 | 0 | } |
247 | | |
248 | 3.00M | fpobj = json_object_new_boolean(i); |
249 | 3.00M | if (NULL == fpobj) { |
250 | 0 | cli_errmsg("json: no memory for json boolean object.\n"); |
251 | 0 | return CL_EMEM; |
252 | 0 | } |
253 | | |
254 | 3.00M | if (objty == json_type_object) |
255 | 3.00M | json_object_object_add(obj, key, fpobj); |
256 | 0 | else if (objty == json_type_array) |
257 | 0 | json_object_array_add(obj, fpobj); |
258 | | |
259 | 3.00M | return CL_SUCCESS; |
260 | 3.00M | } |
261 | | |
262 | | cl_error_t cli_jsondouble(json_object *obj, const char *key, double d) |
263 | 94 | { |
264 | 94 | json_type objty; |
265 | 94 | json_object *fpobj; |
266 | 94 | if (NULL == obj) { |
267 | 0 | cli_dbgmsg("json: no parent object specified to cli_jsondouble\n"); |
268 | 0 | return CL_ENULLARG; |
269 | 0 | } |
270 | 94 | objty = json_object_get_type(obj); |
271 | | |
272 | 94 | if (objty == json_type_object) { |
273 | 94 | if (NULL == key) { |
274 | 0 | cli_dbgmsg("json: null string specified as key to cli_jsondouble\n"); |
275 | 0 | return CL_ENULLARG; |
276 | 0 | } |
277 | 94 | } else if (objty != json_type_array) { |
278 | 0 | return CL_EARG; |
279 | 0 | } |
280 | | |
281 | 94 | fpobj = json_object_new_double(d); |
282 | 94 | if (NULL == fpobj) { |
283 | 0 | cli_errmsg("json: no memory for json double object.\n"); |
284 | 0 | return CL_EMEM; |
285 | 0 | } |
286 | | |
287 | 94 | if (objty == json_type_object) |
288 | 94 | json_object_object_add(obj, key, fpobj); |
289 | 0 | else if (objty == json_type_array) |
290 | 0 | json_object_array_add(obj, fpobj); |
291 | | |
292 | 94 | return CL_SUCCESS; |
293 | 94 | } |
294 | | |
295 | | json_object *cli_jsonarray(json_object *obj, const char *key) |
296 | 1.62M | { |
297 | 1.62M | json_type objty; |
298 | 1.62M | json_object *newobj; |
299 | | |
300 | | /* First check to see if this key exists */ |
301 | 1.62M | if (obj && key && json_object_object_get_ex(obj, key, &newobj)) { |
302 | 725k | return json_object_is_type(newobj, json_type_array) ? newobj : NULL; |
303 | 725k | } |
304 | | |
305 | 903k | newobj = json_object_new_array(); |
306 | 903k | if (!(newobj)) |
307 | 0 | return NULL; |
308 | | |
309 | 903k | if (obj) { |
310 | 903k | objty = json_object_get_type(obj); |
311 | | |
312 | 903k | if (key && objty == json_type_object) { |
313 | 903k | json_object_object_add(obj, key, newobj); |
314 | 903k | if (!json_object_object_get_ex(obj, key, &newobj)) |
315 | 0 | return NULL; |
316 | 903k | } else if (objty == json_type_array) { |
317 | 0 | json_object_array_add(obj, newobj); |
318 | 0 | } |
319 | 903k | } |
320 | | |
321 | 903k | return newobj; |
322 | 903k | } |
323 | | |
324 | | cl_error_t cli_jsonint_array(json_object *obj, int32_t val) |
325 | 954k | { |
326 | 954k | return cli_jsonint(obj, NULL, val); |
327 | 954k | } |
328 | | |
329 | | json_object *cli_jsonobj(json_object *obj, const char *key) |
330 | 6.08M | { |
331 | 6.08M | json_type objty; |
332 | 6.08M | json_object *newobj; |
333 | | |
334 | 6.08M | if (obj && key && json_object_object_get_ex(obj, key, &newobj)) |
335 | 1.70M | return json_object_is_type(newobj, json_type_object) ? newobj : NULL; |
336 | | |
337 | 4.38M | newobj = json_object_new_object(); |
338 | 4.38M | if (!(newobj)) |
339 | 0 | return NULL; |
340 | | |
341 | 4.38M | if (obj) { |
342 | 4.13M | objty = json_object_get_type(obj); |
343 | | |
344 | 4.13M | if (key && objty == json_type_object) { |
345 | 3.94M | json_object_object_add(obj, key, newobj); |
346 | 3.94M | if (!json_object_object_get_ex(obj, key, &newobj)) |
347 | 0 | return NULL; |
348 | 3.94M | } else if (objty == json_type_array) { |
349 | 198k | json_object_array_add(obj, newobj); |
350 | 198k | } |
351 | 4.13M | } |
352 | | |
353 | 4.38M | return newobj; |
354 | 4.38M | } |
355 | | |
356 | | #if HAVE_DEPRECATED_JSON |
357 | | int json_object_object_get_ex(struct json_object *obj, const char *key, struct json_object **value) |
358 | | { |
359 | | struct json_object *res; |
360 | | |
361 | | if (value != NULL) |
362 | | *value = NULL; |
363 | | |
364 | | if (obj == NULL) |
365 | | return 0; |
366 | | |
367 | | if (json_object_get_type(obj) != json_type_object) |
368 | | return 0; |
369 | | |
370 | | res = json_object_object_get(obj, key); |
371 | | if (value != NULL) { |
372 | | *value = res; |
373 | | return (res != NULL); |
374 | | } |
375 | | |
376 | | return (res != NULL); |
377 | | } |
378 | | #endif |
379 | | |
380 | | /* adding an object does NOT increment reference count */ |
381 | | cl_error_t cli_json_addowner(json_object *owner, json_object *child, const char *key, int idx) |
382 | 241k | { |
383 | 241k | json_type objty; |
384 | 241k | if (NULL == owner) { |
385 | 0 | cli_dbgmsg("json: no owner object specified to cli_json_addowner\n"); |
386 | 0 | return CL_ENULLARG; |
387 | 0 | } |
388 | | |
389 | 241k | if (NULL == child) { |
390 | 0 | cli_dbgmsg("json: no child object specified to cli_json_addowner\n"); |
391 | 0 | return CL_ENULLARG; |
392 | 0 | } |
393 | 241k | objty = json_object_get_type(owner); |
394 | | |
395 | 241k | if (objty == json_type_object) { |
396 | 0 | if (NULL == key) { |
397 | 0 | cli_dbgmsg("json: null string specified as key to cli_addowner\n"); |
398 | 0 | return CL_ENULLARG; |
399 | 0 | } |
400 | 0 | json_object_object_add(owner, key, child); |
401 | 241k | } else if (objty == json_type_array) { |
402 | 241k | if (idx < 0 || NULL == json_object_array_get_idx(owner, idx)) |
403 | 241k | json_object_array_add(owner, child); |
404 | 0 | else if (0 != json_object_array_put_idx(owner, idx, child)) { |
405 | | /* this shouldn't be possible */ |
406 | 0 | cli_dbgmsg("json: cannot delete idx %d of owner array\n", idx); |
407 | 0 | return CL_BREAK; |
408 | 0 | } |
409 | 241k | } else { |
410 | 0 | cli_dbgmsg("json: no owner object cannot hold ownership\n"); |
411 | 0 | return CL_EARG; |
412 | 0 | } |
413 | | |
414 | | /* increment reference count */ |
415 | 241k | json_object_get(child); |
416 | 241k | return CL_SUCCESS; |
417 | 241k | } |
418 | | |
419 | | /* deleting an object DOES decrement reference count */ |
420 | | cl_error_t cli_json_delowner(json_object *owner, const char *key, int idx) |
421 | 0 | { |
422 | 0 | json_type objty; |
423 | 0 | json_object *obj; |
424 | 0 | if (NULL == owner) { |
425 | 0 | cli_dbgmsg("json: no owner object specified to cli_json_delowner\n"); |
426 | 0 | return CL_ENULLARG; |
427 | 0 | } |
428 | 0 | objty = json_object_get_type(owner); |
429 | |
|
430 | 0 | if (objty == json_type_object) { |
431 | 0 | if (NULL == key) { |
432 | 0 | cli_dbgmsg("json: null string specified as key to cli_delowner\n"); |
433 | 0 | return CL_ENULLARG; |
434 | 0 | } |
435 | | |
436 | 0 | if (!json_object_object_get_ex(owner, key, &obj)) { |
437 | 0 | cli_dbgmsg("json: owner array does not have content with key %s\n", key); |
438 | 0 | return CL_EARG; |
439 | 0 | } |
440 | | |
441 | 0 | json_object_object_del(owner, key); |
442 | 0 | } else if (objty == json_type_array) { |
443 | 0 | json_object *empty; |
444 | |
|
445 | 0 | if (NULL == json_object_array_get_idx(owner, idx)) { |
446 | 0 | cli_dbgmsg("json: owner array does not have content at idx %d\n", idx); |
447 | 0 | return CL_EARG; |
448 | 0 | } |
449 | | |
450 | | /* allocate the empty object to replace target object */ |
451 | 0 | empty = cli_jsonobj(NULL, NULL); |
452 | 0 | if (NULL == empty) |
453 | 0 | return CL_EMEM; |
454 | | |
455 | 0 | if (0 != json_object_array_put_idx(owner, idx, empty)) { |
456 | | /* this shouldn't be possible */ |
457 | 0 | cli_dbgmsg("json: cannot delete idx %d of owner array\n", idx); |
458 | 0 | return CL_BREAK; |
459 | 0 | } |
460 | 0 | } else { |
461 | 0 | cli_dbgmsg("json: no owner object cannot hold ownership\n"); |
462 | 0 | return CL_EARG; |
463 | 0 | } |
464 | | |
465 | 0 | return CL_SUCCESS; |
466 | 0 | } |
467 | | |
468 | | #else |
469 | | |
470 | | cl_error_t cli_json_nojson() |
471 | | { |
472 | | nojson_func("nojson: json needs to be enabled for this feature\n"); |
473 | | return CL_SUCCESS; |
474 | | } |
475 | | |
476 | | cl_error_t cli_jsonnull_nojson(const char* key) |
477 | | { |
478 | | nojson_func("nojson: %s: null\n", key); |
479 | | return CL_SUCCESS; |
480 | | } |
481 | | |
482 | | cl_error_t cli_jsonstr_nojson(const char* key, const char* s) |
483 | | { |
484 | | nojson_func("nojson: %s: %s\n", key, s); |
485 | | return CL_SUCCESS; |
486 | | } |
487 | | |
488 | | cl_error_t cli_jsonstrlen_nojson(const char* key, const char* s, int len) |
489 | | { |
490 | | char* sp = cli_malloc(len + 1); |
491 | | if (NULL == sp) { |
492 | | cli_errmsg("json: no memory for json strlen object.\n"); |
493 | | return CL_EMEM; |
494 | | } |
495 | | strncpy(sp, s, len); |
496 | | sp[len] = '\0'; |
497 | | |
498 | | nojson_func("nojson: %s: %s\n", key, sp); |
499 | | |
500 | | free(sp); |
501 | | return CL_SUCCESS; |
502 | | } |
503 | | |
504 | | cl_error_t cli_jsonint_nojson(const char* key, int32_t i) |
505 | | { |
506 | | nojson_func("nojson: %s: %d\n", key, i); |
507 | | return CL_SUCCESS; |
508 | | } |
509 | | |
510 | | cl_error_t cli_jsonint64_nojson(const char* key, int64_t i) |
511 | | { |
512 | | nojson_func("nojson: %s: %ld\n", key, (long int)i); |
513 | | return CL_SUCCESS; |
514 | | } |
515 | | |
516 | | cl_error_t cli_jsonbool_nojson(const char* key, int i) |
517 | | { |
518 | | nojson_func("nojson: %s: %s\n", key, i ? "true" : "false"); |
519 | | return CL_SUCCESS; |
520 | | } |
521 | | |
522 | | cl_error_t cli_jsondouble_nojson(const char* key, double d) |
523 | | { |
524 | | nojson_func("nojson: %s: %f\n", key, d); |
525 | | return CL_SUCCESS; |
526 | | } |
527 | | |
528 | | void* cli_jsonarray_nojson(const char* key) |
529 | | { |
530 | | nojson_func("nojson: %s\n", key); |
531 | | return NULL; |
532 | | } |
533 | | |
534 | | cl_error_t cli_jsonint_array_nojson(int32_t val) |
535 | | { |
536 | | nojson_func("nojson: %d\n", val); |
537 | | return CL_SUCCESS; |
538 | | } |
539 | | |
540 | | #endif |