libclamav/json_api.c
9fdbf2c7
 /*
  * JSON Object API
557c712c
  *
e1cbc270
  * Copyright (C) 2014-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
557c712c
  *
9fdbf2c7
  * Authors: Kevin Lin
557c712c
  *
9fdbf2c7
  * This program is free software; you can redistribute it and/or modify it under
  * the terms of the GNU General Public License version 2 as published by the
  * Free Software Foundation.
557c712c
  *
9fdbf2c7
  * This program is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
557c712c
  *
9fdbf2c7
  * You should have received a copy of the GNU General Public License along with
  * this program; if not, write to the Free Software Foundation, Inc., 51
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
 #if HAVE_CONFIG_H
 #include "clamav-config.h"
 #endif
 
60d8d2c3
 #include "clamav.h"
9fdbf2c7
 #include "others.h"
 #include "json_api.h"
 
 #ifdef HAVE_JSON
557c712c
 cl_error_t cli_json_timeout_cycle_check(cli_ctx *ctx, int *toval)
20b45621
 {
048a88e6
     if (SCAN_COLLECT_METADATA) {
8c338ea9
         if (*toval <= 0) {
             if (cli_checktimelimit(ctx) != CL_SUCCESS) {
                 cli_errmsg("cli_json_timeout_cycle_check: timeout!\n");
                 return CL_ETIMEOUT;
             }
             (*toval)++;
         }
         if (*toval > JSON_TIMEOUT_SKIP_CYCLES) {
             (*toval) = 0;
20b45621
         }
     }
     return CL_SUCCESS;
 }
 
557c712c
 cl_error_t cli_json_parse_error(json_object *root, const char *errstr)
4e2ae35b
 {
     json_object *perr;
 
     if (!root)
         return CL_SUCCESS; /* CL_ENULLARG? */
 
     perr = cli_jsonarray(root, "ParseErrors");
     if (perr == NULL) {
         return CL_EMEM;
     }
 
     return cli_jsonstr(perr, NULL, errstr);
 }
 
557c712c
 cl_error_t cli_jsonnull(json_object *obj, const char *key)
9fdbf2c7
 {
8f8c5555
     json_type objty;
9a7511a1
     json_object *fpobj = NULL;
849a2cef
     if (NULL == obj) {
5d93a537
         cli_dbgmsg("json: null 'obj' specified to cli_jsonnull\n");
849a2cef
         return CL_ENULLARG;
     }
8f8c5555
     objty = json_object_get_type(obj);
 
     if (objty == json_type_object) {
         if (NULL == key) {
             cli_dbgmsg("json: null string specified as key to cli_jsonnull\n");
             return CL_ENULLARG;
         }
 
         json_object_object_add(obj, key, fpobj);
288057e9
     } else if (objty == json_type_array) {
8f8c5555
         json_object_array_add(obj, fpobj);
a094a729
     }
 
9fdbf2c7
     return CL_SUCCESS;
 }
 
557c712c
 cl_error_t cli_jsonstr(json_object *obj, const char *key, const char *s)
9fdbf2c7
 {
8f8c5555
     json_type objty;
a094a729
     json_object *fpobj;
849a2cef
     if (NULL == obj) {
5d93a537
         cli_dbgmsg("json: null 'obj' specified to cli_jsonstr\n");
a094a729
         return CL_ENULLARG;
     }
8f8c5555
     objty = json_object_get_type(obj);
 
     if (objty == json_type_object) {
         if (NULL == key) {
             cli_dbgmsg("json: null string specified as 'key' to cli_jsonstr\n");
             return CL_ENULLARG;
         }
288057e9
     } else if (objty != json_type_array) {
8f8c5555
         return CL_EARG;
a094a729
     }
8f8c5555
 
a094a729
     if (NULL == s) {
5d93a537
         cli_dbgmsg("json: null string specified as 's' to  cli_jsonstr\n");
849a2cef
         return CL_ENULLARG;
     }
a094a729
 
     fpobj = json_object_new_string(s);
9fdbf2c7
     if (NULL == fpobj) {
a094a729
         cli_errmsg("json: no memory for json string object\n");
9fdbf2c7
         return CL_EMEM;
     }
8f8c5555
 
     if (objty == json_type_object)
         json_object_object_add(obj, key, fpobj);
     else if (objty == json_type_array)
         json_object_array_add(obj, fpobj);
 
9fdbf2c7
     return CL_SUCCESS;
 }
 
557c712c
 cl_error_t cli_jsonstrlen(json_object *obj, const char *key, const char *s, int len)
0dab1f31
 {
     json_type objty;
     json_object *fpobj;
     if (NULL == obj) {
         cli_dbgmsg("json: null 'obj' specified to cli_jsonstr\n");
         return CL_ENULLARG;
     }
     objty = json_object_get_type(obj);
 
     if (objty == json_type_object) {
         if (NULL == key) {
             cli_dbgmsg("json: null string specified as 'key' to cli_jsonstr\n");
             return CL_ENULLARG;
         }
288057e9
     } else if (objty != json_type_array) {
0dab1f31
         return CL_EARG;
     }
 
     if (NULL == s) {
         cli_dbgmsg("json: null string specified as 's' to  cli_jsonstr\n");
         return CL_ENULLARG;
     }
 
     fpobj = json_object_new_string_len(s, len);
     if (NULL == fpobj) {
         cli_errmsg("json: no memory for json string object\n");
         return CL_EMEM;
     }
 
     if (objty == json_type_object)
         json_object_object_add(obj, key, fpobj);
     else if (objty == json_type_array)
         json_object_array_add(obj, fpobj);
 
     return CL_SUCCESS;
 }
 
557c712c
 cl_error_t cli_jsonint(json_object *obj, const char *key, int32_t i)
9fdbf2c7
 {
8f8c5555
     json_type objty;
a094a729
     json_object *fpobj;
849a2cef
     if (NULL == obj) {
5d93a537
         cli_dbgmsg("json: no parent object specified to cli_jsonint\n");
849a2cef
         return CL_ENULLARG;
     }
8f8c5555
     objty = json_object_get_type(obj);
 
288057e9
     if (objty == json_type_object) {
8f8c5555
         if (NULL == key) {
             cli_dbgmsg("json: null string specified as key to cli_jsonint\n");
             return CL_ENULLARG;
         }
288057e9
     } else if (objty != json_type_array) {
8f8c5555
         return CL_EARG;
a094a729
     }
 
     fpobj = json_object_new_int(i);
9fdbf2c7
     if (NULL == fpobj) {
a094a729
         cli_errmsg("json: no memory for json int object\n");
9fdbf2c7
         return CL_EMEM;
     }
8f8c5555
 
     if (objty == json_type_object)
         json_object_object_add(obj, key, fpobj);
     else if (objty == json_type_array)
         json_object_array_add(obj, fpobj);
 
9fdbf2c7
     return CL_SUCCESS;
 }
 
 #ifdef JSON10
557c712c
 cl_error_t cli_jsonint64(json_object *obj, const char *key, int64_t i)
9fdbf2c7
 {
8f8c5555
     json_type objty;
a094a729
     json_object *fpobj;
849a2cef
     if (NULL == obj) {
5d93a537
         cli_dbgmsg("json: no parent object specified to cli_jsonint64\n");
849a2cef
         return CL_ENULLARG;
     }
8f8c5555
     objty = json_object_get_type(obj);
 
     if (objty == json_type_object) {
         if (NULL == key) {
             cli_dbgmsg("json: null string specified as key to cli_jsonint64\n");
             return CL_ENULLARG;
         }
288057e9
     } else if (objty != json_type_array) {
8f8c5555
         return CL_EARG;
a094a729
     }
 
     fpobj = json_object_new_int64(i);
9fdbf2c7
     if (NULL == fpobj) {
         cli_errmsg("json: no memory for json int object.\n");
         return CL_EMEM;
     }
8f8c5555
 
     if (objty == json_type_object)
         json_object_object_add(obj, key, fpobj);
     else if (objty == json_type_array)
         json_object_array_add(obj, fpobj);
 
9fdbf2c7
     return CL_SUCCESS;
 }
 #else
557c712c
 cl_error_t cli_jsonint64(json_object *obj, const char *key, int64_t i)
9fdbf2c7
 {
8f8c5555
     json_type objty;
9fdbf2c7
     int32_t li, hi;
     json_object *fpobj0, *fpobj1;
a094a729
     json_object *fparr;
849a2cef
     if (NULL == obj) {
5d93a537
         cli_dbgmsg("json: no parent object specified to cli_jsonint64\n");
849a2cef
         return CL_ENULLARG;
     }
8f8c5555
     objty = json_object_get_type(obj);
 
     if (objty == json_type_object) {
         if (NULL == key) {
             cli_dbgmsg("json: null string specified as key to cli_jsonint64\n");
             return CL_ENULLARG;
         }
288057e9
     } else if (objty != json_type_array) {
8f8c5555
         return CL_EARG;
a094a729
     }
 
     fparr = json_object_new_array();
9fdbf2c7
     if (NULL == fparr) {
         cli_errmsg("json: no memory for json array object.\n");
         return CL_EMEM;
     }
 
     hi = (uint32_t)((i & 0xFFFFFFFF00000000) >> 32);
     li = (uint32_t)(i & 0xFFFFFFFF);
 
     fpobj0 = json_object_new_int(li);
     if (NULL == fpobj0) {
         cli_errmsg("json: no memory for json int object.\n");
849a2cef
         json_object_put(fparr);
9fdbf2c7
         return CL_EMEM;
     }
     fpobj1 = json_object_new_int(hi);
     if (NULL == fpobj1) {
         cli_errmsg("json: no memory for json int object.\n");
849a2cef
         json_object_put(fparr);
         json_object_put(fpobj0);
9fdbf2c7
         return CL_EMEM;
     }
 
     /* little-endian array */
     json_object_array_add(fparr, fpobj0);
     json_object_array_add(fparr, fpobj1);
8f8c5555
     if (objty == json_type_object)
         json_object_object_add(obj, key, fparr);
     else if (objty == json_type_array)
         json_object_array_add(obj, fparr);
 
849a2cef
     return CL_SUCCESS;
9fdbf2c7
 }
 //#define cli_jsonint64(o,n,i) cli_dbgmsg("%s: %lld [%llx]\n", n, i, i)
 #endif
 
557c712c
 cl_error_t cli_jsonbool(json_object *obj, const char *key, int i)
9fdbf2c7
 {
8f8c5555
     json_type objty;
a094a729
     json_object *fpobj;
849a2cef
     if (NULL == obj) {
5d93a537
         cli_dbgmsg("json: no parent object specified to cli_jsonbool\n");
849a2cef
         return CL_ENULLARG;
     }
8f8c5555
     objty = json_object_get_type(obj);
 
     if (objty == json_type_object) {
         if (NULL == key) {
             cli_dbgmsg("json: null string specified as key to cli_jsonbool\n");
             return CL_ENULLARG;
         }
288057e9
     } else if (objty != json_type_array) {
8f8c5555
         return CL_EARG;
a094a729
     }
 
     fpobj = json_object_new_boolean(i);
9fdbf2c7
     if (NULL == fpobj) {
         cli_errmsg("json: no memory for json boolean object.\n");
         return CL_EMEM;
     }
8f8c5555
 
     if (objty == json_type_object)
         json_object_object_add(obj, key, fpobj);
     else if (objty == json_type_array)
         json_object_array_add(obj, fpobj);
 
9fdbf2c7
     return CL_SUCCESS;
 }
 
557c712c
 cl_error_t cli_jsondouble(json_object *obj, const char *key, double d)
9fdbf2c7
 {
8f8c5555
     json_type objty;
a094a729
     json_object *fpobj;
849a2cef
     if (NULL == obj) {
5d93a537
         cli_dbgmsg("json: no parent object specified to cli_jsondouble\n");
849a2cef
         return CL_ENULLARG;
     }
8f8c5555
     objty = json_object_get_type(obj);
 
     if (objty == json_type_object) {
         if (NULL == key) {
             cli_dbgmsg("json: null string specified as key to cli_jsondouble\n");
             return CL_ENULLARG;
         }
288057e9
     } else if (objty != json_type_array) {
8f8c5555
         return CL_EARG;
a094a729
     }
 
     fpobj = json_object_new_double(d);
9fdbf2c7
     if (NULL == fpobj) {
849a2cef
         cli_errmsg("json: no memory for json double object.\n");
9fdbf2c7
         return CL_EMEM;
     }
8f8c5555
 
     if (objty == json_type_object)
         json_object_object_add(obj, key, fpobj);
     else if (objty == json_type_array)
         json_object_array_add(obj, fpobj);
 
9fdbf2c7
     return CL_SUCCESS;
 }
a69adec1
 
d7ee9b81
 json_object *cli_jsonarray(json_object *obj, const char *key)
 {
b6549d30
     json_type objty;
d7ee9b81
     json_object *newobj;
 
8c338ea9
     /* First check to see if this key exists */
165cf21e
     if (obj && key && json_object_object_get_ex(obj, key, &newobj)) {
8c338ea9
         return json_object_is_type(newobj, json_type_array) ? newobj : NULL;
d7ee9b81
     }
 
     newobj = json_object_new_array();
     if (!(newobj))
         return NULL;
 
b6549d30
     if (obj) {
         objty = json_object_get_type(obj);
 
         if (key && objty == json_type_object) {
             json_object_object_add(obj, key, newobj);
             if (!json_object_object_get_ex(obj, key, &newobj))
                 return NULL;
         } else if (objty == json_type_array) {
             json_object_array_add(obj, newobj);
         }
d7ee9b81
     }
 
     return newobj;
 }
 
557c712c
 cl_error_t cli_jsonint_array(json_object *obj, int32_t val)
d7ee9b81
 {
8f8c5555
     return cli_jsonint(obj, NULL, val);
d7ee9b81
 }
 
 json_object *cli_jsonobj(json_object *obj, const char *key)
 {
b6549d30
     json_type objty;
d7ee9b81
     json_object *newobj;
 
8c338ea9
     if (obj && key && json_object_object_get_ex(obj, key, &newobj))
         return json_object_is_type(newobj, json_type_object) ? newobj : NULL;
d7ee9b81
 
     newobj = json_object_new_object();
     if (!(newobj))
         return NULL;
 
b6549d30
     if (obj) {
         objty = json_object_get_type(obj);
 
         if (key && objty == json_type_object) {
             json_object_object_add(obj, key, newobj);
             if (!json_object_object_get_ex(obj, key, &newobj))
                 return NULL;
         } else if (objty == json_type_array) {
             json_object_array_add(obj, newobj);
         }
8f94be58
     }
d7ee9b81
 
     return newobj;
 }
 
060a57d2
 #if HAVE_DEPRECATED_JSON
 int json_object_object_get_ex(struct json_object *obj, const char *key, struct json_object **value)
 {
     struct json_object *res;
 
     if (value != NULL)
         *value = NULL;
 
     if (obj == NULL)
         return 0;
 
     if (json_object_get_type(obj) != json_type_object)
         return 0;
 
     res = json_object_object_get(obj, key);
     if (value != NULL) {
         *value = res;
         return (res != NULL);
     }
 
     return (res != NULL);
 }
 #endif
 
8e586053
 /* adding an object does NOT increment reference count */
557c712c
 cl_error_t cli_json_addowner(json_object *owner, json_object *child, const char *key, int idx)
8e586053
 {
     json_type objty;
     if (NULL == owner) {
         cli_dbgmsg("json: no owner object specified to cli_json_addowner\n");
         return CL_ENULLARG;
     }
 
     if (NULL == child) {
         cli_dbgmsg("json: no child object specified to cli_json_addowner\n");
         return CL_ENULLARG;
     }
     objty = json_object_get_type(owner);
 
     if (objty == json_type_object) {
         if (NULL == key) {
             cli_dbgmsg("json: null string specified as key to cli_addowner\n");
             return CL_ENULLARG;
         }
         json_object_object_add(owner, key, child);
288057e9
     } else if (objty == json_type_array) {
8e586053
         if (idx < 0 || NULL == json_object_array_get_idx(owner, idx))
             json_object_array_add(owner, child);
         else if (0 != json_object_array_put_idx(owner, idx, child)) {
             /* this shouldn't be possible */
             cli_dbgmsg("json: cannot delete idx %d of owner array\n", idx);
             return CL_BREAK;
         }
288057e9
     } else {
8e586053
         cli_dbgmsg("json: no owner object cannot hold ownership\n");
         return CL_EARG;
     }
 
     /* increment reference count */
     json_object_get(child);
     return CL_SUCCESS;
 }
 
 /* deleting an object DOES decrement reference count */
557c712c
 cl_error_t cli_json_delowner(json_object *owner, const char *key, int idx)
8e586053
 {
     json_type objty;
     json_object *obj;
     if (NULL == owner) {
         cli_dbgmsg("json: no owner object specified to cli_json_delowner\n");
         return CL_ENULLARG;
     }
     objty = json_object_get_type(owner);
 
     if (objty == json_type_object) {
         if (NULL == key) {
             cli_dbgmsg("json: null string specified as key to cli_delowner\n");
             return CL_ENULLARG;
         }
 
         if (!json_object_object_get_ex(owner, key, &obj)) {
             cli_dbgmsg("json: owner array does not have content with key %s\n", key);
             return CL_EARG;
         }
 
         json_object_object_del(owner, key);
288057e9
     } else if (objty == json_type_array) {
8e586053
         json_object *empty;
 
         if (NULL == json_object_array_get_idx(owner, idx)) {
             cli_dbgmsg("json: owner array does not have content at idx %d\n", idx);
             return CL_EARG;
         }
 
         /* allocate the empty object to replace target object */
         empty = cli_jsonobj(NULL, NULL);
         if (NULL == empty)
             return CL_EMEM;
 
         if (0 != json_object_array_put_idx(owner, idx, empty)) {
             /* this shouldn't be possible */
             cli_dbgmsg("json: cannot delete idx %d of owner array\n", idx);
             return CL_BREAK;
         }
288057e9
     } else {
8e586053
         cli_dbgmsg("json: no owner object cannot hold ownership\n");
         return CL_EARG;
     }
 
     return CL_SUCCESS;
 }
 
9fdbf2c7
 #else
a69adec1
 
557c712c
 cl_error_t cli_json_nojson()
a69adec1
 {
     nojson_func("nojson: json needs to be enabled for this feature\n");
     return CL_SUCCESS;
 }
 
557c712c
 cl_error_t cli_jsonnull_nojson(const char* key)
a69adec1
 {
     nojson_func("nojson: %s: null\n", key);
     return CL_SUCCESS;
 }
 
557c712c
 cl_error_t cli_jsonstr_nojson(const char* key, const char* s)
a69adec1
 {
     nojson_func("nojson: %s: %s\n", key, s);
     return CL_SUCCESS;
 }
 
557c712c
 cl_error_t cli_jsonstrlen_nojson(const char* key, const char* s, int len)
b2743d5d
 {
288057e9
     char* sp = cli_malloc(len + 1);
32ad1c56
     if (NULL == sp) {
288057e9
         cli_errmsg("json: no memory for json strlen object.\n");
         return CL_EMEM;
32ad1c56
     }
b2743d5d
     strncpy(sp, s, len);
     sp[len] = '\0';
 
     nojson_func("nojson: %s: %s\n", key, sp);
 
     free(sp);
     return CL_SUCCESS;
 }
 
557c712c
 cl_error_t cli_jsonint_nojson(const char* key, int32_t i)
a69adec1
 {
     nojson_func("nojson: %s: %d\n", key, i);
     return CL_SUCCESS;
 }
 
557c712c
 cl_error_t cli_jsonint64_nojson(const char* key, int64_t i)
a69adec1
 {
     nojson_func("nojson: %s: %ld\n", key, (long int)i);
     return CL_SUCCESS;
 }
 
557c712c
 cl_error_t cli_jsonbool_nojson(const char* key, int i)
a69adec1
 {
288057e9
     nojson_func("nojson: %s: %s\n", key, i ? "true" : "false");
dec128ce
     return CL_SUCCESS;
a69adec1
 }
 
557c712c
 cl_error_t cli_jsondouble_nojson(const char* key, double d)
a69adec1
 {
     nojson_func("nojson: %s: %f\n", key, d);
dec128ce
     return CL_SUCCESS;
a69adec1
 }
 
288057e9
 void* cli_jsonarray_nojson(const char* key)
d7ee9b81
 {
     nojson_func("nojson: %s\n", key);
     return NULL;
 }
 
557c712c
 cl_error_t cli_jsonint_array_nojson(int32_t val)
d7ee9b81
 {
     nojson_func("nojson: %d\n", val);
5899095f
     return CL_SUCCESS;
d7ee9b81
 }
 
9fdbf2c7
 #endif