libclamav/stats_json.c
1bdaf813
 /*
  *  Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
  *
  *  Author: Shawn Webb
  *
  *  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.
  *
  *  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.
  *
  *  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.
  */
 
f2571e34
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
4a4b84da
 
 #if HAVE_UNISTD_H
f2571e34
 #include <unistd.h>
4a4b84da
 #endif
f2571e34
 
 #include <sys/types.h>
 #include <errno.h>
 
c7ad4bea
 #if defined(_WIN32)
 #include <WinSock2.h>
 #include <Windows.h>
 #endif
 
f2571e34
 #include "libclamav/others.h"
 #include "libclamav/clamav.h"
 
 #define JSON_BUFSZ 512
 #define SAMPLE_PREFIX "sample_"
 
cd94be7a
 char *hex_encode(char *buf, char *data, size_t len);
 char *ensure_bufsize(char *buf, size_t *oldsize, size_t used, size_t additional);
 char *export_stats_to_json(struct cl_engine *engine, cli_intel_t *intel);
 
f2571e34
 char *hex_encode(char *buf, char *data, size_t len)
 {
     size_t i;
     char *p;
b3c40dc6
     int t;
f2571e34
 
     p = (buf != NULL) ? buf : calloc(1, (len*2)+1);
     if (!(p))
         return NULL;
 
b3c40dc6
     for (i=0; i<len; i++) {
         t = data[i] & 0xff;
         sprintf(p+(i*2), "%02x", t);
     }
f2571e34
 
     return p;
 }
 
 char *ensure_bufsize(char *buf, size_t *oldsize, size_t used, size_t additional)
 {
     char *p=buf;
 
     if (*oldsize - used < additional) {
         p = realloc(buf, *oldsize + JSON_BUFSZ);
         if (!(p)) {
             cli_errmsg("ensure_bufsize: Could not allocate more memory: %s (errno: %d)\n", strerror(errno), errno);
             free(buf);
             return NULL;
         }
 
         *oldsize += JSON_BUFSZ;
     }
 
     return p;
 }
 
 char *export_stats_to_json(struct cl_engine *engine, cli_intel_t *intel)
 {
cd94be7a
     char *buf=NULL, *hostid, md5[33];
f2571e34
     cli_flagged_sample_t *sample;
c9dd1aaa
     size_t bufsz, curused, i, j;
f2571e34
 
     if (!(intel->hostid))
         if ((engine->cb_stats_get_hostid))
             intel->hostid = engine->cb_stats_get_hostid(engine->stats_data);
 
     hostid = (intel->hostid != NULL) ? intel->hostid : STATS_ANON_UUID;
 
     buf = calloc(1, JSON_BUFSZ);
     if (!(buf))
         return NULL;
 
     bufsz = JSON_BUFSZ;
     sprintf(buf, "{\n\t\"hostid\": \"%s\",\n", hostid);
dbc6d4b2
     if (intel->host_info)
         sprintf(buf+strlen(buf), "\t\"host_info\": \"%s\",\n", intel->host_info);
 
e256eaa9
     sprintf(buf+strlen(buf), "\t\"samples\": [\n");
f2571e34
     curused = strlen(buf);
 
     for (sample = intel->samples; sample != NULL; sample = sample->next) {
         if (sample->hits == 0)
             continue;
 
         memset(md5, 0x00, sizeof(md5));
         hex_encode(md5, sample->md5, sizeof(sample->md5));
 
         buf = ensure_bufsize(buf, &bufsz, curused, strlen(md5) + sizeof(SAMPLE_PREFIX) + 45);
         if (!(buf))
             return NULL;
 
e6786fef
         snprintf(buf+curused, bufsz-curused, "\t\t\t{\n");
e256eaa9
         curused += strlen(buf+curused);
 
         buf = ensure_bufsize(buf, &bufsz, curused, sizeof("\t\t\t\"hash\": \"\",\n") + strlen(md5) + 1);
         if (!(buf))
             return NULL;
 
         snprintf(buf+curused, bufsz-curused, "\t\t\t\"hash\": \"%s\",\n", md5);
f2571e34
         curused += strlen(buf+curused);
 
         /* Reuse the md5 variable for serializing the number of hits */
         snprintf(md5, sizeof(md5), "%u", sample->hits);
 
         buf = ensure_bufsize(buf, &bufsz, curused, strlen(md5) + 20);
         if (!(buf))
             return NULL;
 
7042d882
         snprintf(buf+curused, bufsz-curused, "\t\t\t\"hits\": %s,\n", md5);
30bdcf4e
         curused += strlen(buf+curused);
 
b3c40dc6
         snprintf(md5, sizeof(md5), "%u", sample->size);
30bdcf4e
 
         buf = ensure_bufsize(buf, &bufsz, curused, strlen(md5) + 20);
         if (!(buf))
             return NULL;
 
7042d882
         snprintf(buf+curused, bufsz-curused, "\t\t\t\"size\": %s,\n", md5);
f2571e34
         curused += strlen(buf+curused);
 
         buf = ensure_bufsize(buf, &bufsz, curused, 30);
         if (!(buf))
             return NULL;
 
c9dd1aaa
         if ((sample->sections) && (sample->sections->nsections)) {
             buf = ensure_bufsize(buf, &bufsz, curused, 30);
             if (!(buf))
                 return NULL;
 
             snprintf(buf+curused, bufsz-curused, "\t\t\t\"sections\": [\n");
             curused += strlen(buf+curused);
 
             for (i=0; i < sample->sections->nsections; i++) {
                 buf = ensure_bufsize(buf, &bufsz, curused, 30);
                 if (!(buf))
                     return NULL;
 
                 snprintf(buf+curused, bufsz-curused, "\t\t\t\t%s{\n", (i > 0) ? "," : "");
                 curused += strlen(buf+curused);
 
                 buf = ensure_bufsize(buf, &bufsz, curused, 65);
                 if (!(buf))
                     return NULL;
 
                 memset(md5, 0x00, sizeof(md5));
                 for (j=0; j < 16; j++)
                     sprintf(md5+(j*2), "%02x", sample->sections->sections[i].md5[j]);
 
                 snprintf(buf+curused, bufsz-curused, "\t\t\t\t\t\"hash\": \"%s\",\n", md5);
                 curused += strlen(buf+curused);
 
                 buf = ensure_bufsize(buf, &bufsz, curused, 65);
                 if (!(buf))
                     return NULL;
 
059ca614
                 snprintf(buf+curused, bufsz-curused, "\t\t\t\t\t\"size\": %llu\n", (long long unsigned)sample->sections->sections[i].len);
c9dd1aaa
                 curused += strlen(buf+curused);
 
                 buf = ensure_bufsize(buf, &bufsz, curused, 30);
                 if (!(buf))
                     return NULL;
 
                 snprintf(buf+curused, bufsz-curused, "\t\t\t\t}\n");
                 curused += strlen(buf+curused);
             }
 
             buf = ensure_bufsize(buf, &bufsz, curused, 20);
             if (!(buf))
                 return NULL;
 
             snprintf(buf+curused, bufsz-curused, "\t\t\t],\n");
             curused += strlen(buf+curused);
         }
 
f2571e34
         snprintf(buf+curused, bufsz-curused, "\t\t\t\"virus_names\": [ ");
         curused += strlen(buf+curused);
 
         for (i=0; sample->virus_name[i] != NULL; i++) {
             buf = ensure_bufsize(buf, &bufsz, curused, strlen(sample->virus_name[i]) + 5);
             if (!(buf))
                 return NULL;
 
             snprintf(buf+curused, bufsz-curused, "%s\"%s\"", (i > 0) ? ", " : "", sample->virus_name[i]);
             curused += strlen(buf+curused);
         }
 
         buf = ensure_bufsize(buf, &bufsz, curused, 10);
         if (!(buf))
             return NULL;
 
         snprintf(buf+curused, bufsz-curused, " ]\n\t\t}%s\n", (sample->next != NULL) ? "," : "");
         curused += strlen(buf+curused);
     }
 
     buf = ensure_bufsize(buf, &bufsz, curused, 15);
     if (!(buf))
         return NULL;
 
e256eaa9
     snprintf(buf+curused, bufsz-curused, "\t]\n}\n");
f2571e34
 
     return buf;
 }