Coverage Report

Created: 2023-12-08 06:48

/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