1 /*
2  *  ClamAV bytecode internal API
3  *
4  *  Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
5  *  Copyright (C) 2009-2013 Sourcefire, Inc.
6  *
7  *  Authors: Török Edvin
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License version 2 as
11  *  published by the Free Software Foundation.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21  *  MA 02110-1301, USA.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include "clamav-config.h"
26 #endif
27 
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #include <stdlib.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <string.h>
35 #include <math.h>
36 #include <ctype.h>
37 
38 #if HAVE_JSON
39 #include <json.h>
40 #endif
41 #if HAVE_BZLIB_H
42 #include <bzlib.h>
43 #endif
44 
45 #include "clamav.h"
46 #include "clambc.h"
47 #include "bytecode.h"
48 #include "bytecode_priv.h"
49 #include "type_desc.h"
50 #include "bytecode_api.h"
51 #include "bytecode_api_impl.h"
52 #include "others.h"
53 #include "pe.h"
54 #include "pdf.h"
55 #include "disasm.h"
56 #include "scanners.h"
57 #include "jsparse/js-norm.h"
58 #include "hashtab.h"
59 #include "str.h"
60 #include "filetypes.h"
61 #include "lzma_iface.h"
62 
63 #define EV ctx->bc_events
64 
65 #define STRINGIFY(x) #x
66 #define TOSTRING(x) STRINGIFY(x)
67 #define API_MISUSE() cli_event_error_str(EV, "API misuse @" TOSTRING(__LINE__))
68 
69 struct bc_lzma {
70     struct CLI_LZMA stream;
71     int32_t from;
72     int32_t to;
73 };
74 
75 #if HAVE_BZLIB_H
76 struct bc_bzip2 {
77     bz_stream stream;
78     int32_t from;
79     int32_t to;
80 };
81 #endif
82 
cli_bcapi_test1(struct cli_bc_ctx * ctx,uint32_t a,uint32_t b)83 uint32_t cli_bcapi_test1(struct cli_bc_ctx *ctx, uint32_t a, uint32_t b)
84 {
85     UNUSEDPARAM(ctx);
86     return (a == 0xf00dbeef && b == 0xbeeff00d) ? 0x12345678 : 0x55;
87 }
88 
cli_bcapi_test2(struct cli_bc_ctx * ctx,uint32_t a)89 uint32_t cli_bcapi_test2(struct cli_bc_ctx *ctx, uint32_t a)
90 {
91     UNUSEDPARAM(ctx);
92     return a == 0xf00d ? 0xd00f : 0x5555;
93 }
94 
cli_bcapi_read(struct cli_bc_ctx * ctx,uint8_t * data,int32_t size)95 int32_t cli_bcapi_read(struct cli_bc_ctx *ctx, uint8_t *data, int32_t size)
96 {
97     size_t n;
98     if (!ctx->fmap) {
99         API_MISUSE();
100         return -1;
101     }
102     if (size < 0 || size > CLI_MAX_ALLOCATION) {
103         cli_warnmsg("bytecode: negative read size: %d\n", size);
104         API_MISUSE();
105         return -1;
106     }
107     n = fmap_readn(ctx->fmap, data, ctx->off, size);
108     if ((n == 0) || (n == (size_t)-1)) {
109         cli_dbgmsg("bcapi_read: fmap_readn failed (requested %d)\n", size);
110         cli_event_count(EV, BCEV_READ_ERR);
111         return (int32_t)n;
112     }
113     cli_event_int(EV, BCEV_OFFSET, ctx->off);
114     cli_event_fastdata(EV, BCEV_READ, data, size);
115     //cli_event_data(EV, BCEV_READ, data, n);
116     ctx->off += n;
117     return (int32_t)n;
118 }
119 
cli_bcapi_seek(struct cli_bc_ctx * ctx,int32_t pos,uint32_t whence)120 int32_t cli_bcapi_seek(struct cli_bc_ctx *ctx, int32_t pos, uint32_t whence)
121 {
122     off_t off;
123     if (!ctx->fmap) {
124         cli_dbgmsg("bcapi_seek: no fmap\n");
125         API_MISUSE();
126         return -1;
127     }
128     switch (whence) {
129         case 0:
130             off = pos;
131             break;
132         case 1:
133             off = ctx->off + pos;
134             break;
135         case 2:
136             off = ctx->file_size + pos;
137             break;
138         default:
139             API_MISUSE();
140             cli_dbgmsg("bcapi_seek: invalid whence value\n");
141             return -1;
142     }
143     if (off < 0 || off > ctx->file_size) {
144         cli_dbgmsg("bcapi_seek: out of file: %lld (max %d)\n",
145                    (long long)off, ctx->file_size);
146         return -1;
147     }
148     cli_event_int(EV, BCEV_OFFSET, off);
149     ctx->off = off;
150     return off;
151 }
152 
cli_bcapi_debug_print_str(struct cli_bc_ctx * ctx,const uint8_t * str,uint32_t len)153 uint32_t cli_bcapi_debug_print_str(struct cli_bc_ctx *ctx, const uint8_t *str, uint32_t len)
154 {
155     UNUSEDPARAM(len);
156     cli_event_fastdata(EV, BCEV_DBG_STR, str, strlen((const char *)str));
157     cli_dbgmsg("bytecode debug: %s\n", str);
158     return 0;
159 }
160 
cli_bcapi_debug_print_uint(struct cli_bc_ctx * ctx,uint32_t a)161 uint32_t cli_bcapi_debug_print_uint(struct cli_bc_ctx *ctx, uint32_t a)
162 {
163     cli_event_int(EV, BCEV_DBG_INT, a);
164     //cli_dbgmsg("bytecode debug: %d\n", a);
165     //return 0;
166     if (!cli_debug_flag)
167         return 0;
168     return fprintf(stderr, "%d", a);
169 }
170 
171 /*TODO: compiler should make sure that only constants are passed here, and not
172  * pointers to arbitrary locations that may not be valid when bytecode finishes
173  * executing */
cli_bcapi_setvirusname(struct cli_bc_ctx * ctx,const uint8_t * name,uint32_t len)174 uint32_t cli_bcapi_setvirusname(struct cli_bc_ctx *ctx, const uint8_t *name, uint32_t len)
175 {
176     UNUSEDPARAM(len);
177     ctx->virname = (const char *)name;
178     return 0;
179 }
180 
cli_bcapi_disasm_x86(struct cli_bc_ctx * ctx,struct DISASM_RESULT * res,uint32_t len)181 uint32_t cli_bcapi_disasm_x86(struct cli_bc_ctx *ctx, struct DISASM_RESULT *res, uint32_t len)
182 {
183     int n;
184     const unsigned char *buf;
185     const unsigned char *next;
186     UNUSEDPARAM(len);
187     if (!res || !ctx->fmap || (size_t)(ctx->off) >= ctx->fmap->len) {
188         API_MISUSE();
189         return -1;
190     }
191     /* 32 should be longest instr we support decoding.
192      * When we'll support mmx/sse instructions this should be updated! */
193     n   = MIN(32, ctx->fmap->len - ctx->off);
194     buf = fmap_need_off_once(ctx->fmap, ctx->off, n);
195     if (buf)
196         next = cli_disasm_one(buf, n, res, 0);
197     else
198         next = NULL;
199     if (!next) {
200         cli_dbgmsg("bcapi_disasm: failed\n");
201         cli_event_count(EV, BCEV_DISASM_FAIL);
202         return -1;
203     }
204     return ctx->off + next - buf;
205 }
206 
207 /* TODO: field in ctx, id of last bytecode that called magicscandesc, reset
208  * after hooks/other bytecodes are run. TODO: need a more generic solution
209  * to avoid uselessly recursing on bytecode-unpacked files, but also a way to
210  * override the limit if we need it in a special situation */
cli_bcapi_write(struct cli_bc_ctx * ctx,uint8_t * data,int32_t len)211 int32_t cli_bcapi_write(struct cli_bc_ctx *ctx, uint8_t *data, int32_t len)
212 {
213     char err[128];
214     size_t res;
215 
216     cli_ctx *cctx = (cli_ctx *)ctx->ctx;
217     if (len < 0) {
218         cli_warnmsg("Bytecode API: called with negative length!\n");
219         API_MISUSE();
220         return -1;
221     }
222     if (!ctx->outfd) {
223         ctx->tempfile = cli_gentemp(cctx ? cctx->engine->tmpdir : NULL);
224         if (!ctx->tempfile) {
225             cli_dbgmsg("Bytecode API: Unable to allocate memory for tempfile\n");
226             cli_event_error_oom(EV, 0);
227             return -1;
228         }
229         ctx->outfd = open(ctx->tempfile, O_RDWR | O_CREAT | O_EXCL | O_TRUNC | O_BINARY, 0600);
230         if (ctx->outfd == -1) {
231             ctx->outfd = 0;
232             cli_warnmsg("Bytecode API: Can't create file %s: %s\n", ctx->tempfile, cli_strerror(errno, err, sizeof(err)));
233             cli_event_error_str(EV, "cli_bcapi_write: Can't create temporary file");
234             free(ctx->tempfile);
235             return -1;
236         }
237         cli_dbgmsg("bytecode opened new tempfile: %s\n", ctx->tempfile);
238     }
239 
240     cli_event_fastdata(ctx->bc_events, BCEV_WRITE, data, len);
241     if (cli_checklimits("bytecode api", cctx, ctx->written + len, 0, 0))
242         return -1;
243     res = cli_writen(ctx->outfd, data, (size_t)len);
244     if (res > 0) ctx->written += res;
245     if (res == (size_t)-1) {
246         cli_warnmsg("Bytecode API: write failed: %s\n", cli_strerror(errno, err, sizeof(err)));
247         cli_event_error_str(EV, "cli_bcapi_write: write failed");
248     }
249     return (int32_t)res;
250 }
251 
cli_bytecode_context_set_trace(struct cli_bc_ctx * ctx,unsigned level,bc_dbg_callback_trace trace,bc_dbg_callback_trace_op trace_op,bc_dbg_callback_trace_val trace_val,bc_dbg_callback_trace_ptr trace_ptr)252 void cli_bytecode_context_set_trace(struct cli_bc_ctx *ctx, unsigned level,
253                                     bc_dbg_callback_trace trace,
254                                     bc_dbg_callback_trace_op trace_op,
255                                     bc_dbg_callback_trace_val trace_val,
256                                     bc_dbg_callback_trace_ptr trace_ptr)
257 {
258     ctx->trace       = trace;
259     ctx->trace_op    = trace_op;
260     ctx->trace_val   = trace_val;
261     ctx->trace_ptr   = trace_ptr;
262     ctx->trace_level = level;
263 }
264 
cli_bcapi_trace_scope(struct cli_bc_ctx * ctx,const uint8_t * scope,uint32_t scopeid)265 uint32_t cli_bcapi_trace_scope(struct cli_bc_ctx *ctx, const uint8_t *scope, uint32_t scopeid)
266 {
267     if (LIKELY(!ctx->trace_level))
268         return 0;
269     if (ctx->scope != (const char *)scope) {
270         ctx->scope   = (const char *)scope ? (const char *)scope : "?";
271         ctx->scopeid = scopeid;
272         ctx->trace_level |= 0x80; /* temporarily increase level to print params */
273     } else if ((ctx->trace_level >= trace_scope) && ctx->scopeid != scopeid) {
274         ctx->scopeid = scopeid;
275         ctx->trace_level |= 0x40; /* temporarily increase level to print location */
276     }
277     return 0;
278 }
279 
cli_bcapi_trace_directory(struct cli_bc_ctx * ctx,const uint8_t * dir,uint32_t dummy)280 uint32_t cli_bcapi_trace_directory(struct cli_bc_ctx *ctx, const uint8_t *dir, uint32_t dummy)
281 {
282     UNUSEDPARAM(dummy);
283     if (LIKELY(!ctx->trace_level))
284         return 0;
285     ctx->directory = (const char *)dir ? (const char *)dir : "";
286     return 0;
287 }
288 
cli_bcapi_trace_source(struct cli_bc_ctx * ctx,const uint8_t * file,uint32_t line)289 uint32_t cli_bcapi_trace_source(struct cli_bc_ctx *ctx, const uint8_t *file, uint32_t line)
290 {
291     if (LIKELY(ctx->trace_level < trace_line))
292         return 0;
293     if (ctx->file != (const char *)file || ctx->line != line) {
294         ctx->col  = 0;
295         ctx->file = (const char *)file ? (const char *)file : "??";
296         ctx->line = line;
297     }
298     return 0;
299 }
300 
cli_bcapi_trace_op(struct cli_bc_ctx * ctx,const uint8_t * op,uint32_t col)301 uint32_t cli_bcapi_trace_op(struct cli_bc_ctx *ctx, const uint8_t *op, uint32_t col)
302 {
303     if (LIKELY(ctx->trace_level < trace_col))
304         return 0;
305     if (ctx->trace_level & 0xc0) {
306         ctx->col = col;
307         /* func/scope changed and they needed param/location event */
308         ctx->trace(ctx, (ctx->trace_level & 0x80) ? trace_func : trace_scope);
309         ctx->trace_level &= ~0xc0;
310     }
311     if (LIKELY(ctx->trace_level < trace_col))
312         return 0;
313     if (ctx->col != col) {
314         ctx->col = col;
315         ctx->trace(ctx, trace_col);
316     } else {
317         ctx->trace(ctx, trace_line);
318     }
319     if (LIKELY(ctx->trace_level < trace_op))
320         return 0;
321     if (ctx->trace_op && op)
322         ctx->trace_op(ctx, (const char *)op);
323     return 0;
324 }
325 
cli_bcapi_trace_value(struct cli_bc_ctx * ctx,const uint8_t * name,uint32_t value)326 uint32_t cli_bcapi_trace_value(struct cli_bc_ctx *ctx, const uint8_t *name, uint32_t value)
327 {
328     if (LIKELY(ctx->trace_level < trace_val))
329         return 0;
330     if (ctx->trace_level & 0x80) {
331         if ((ctx->trace_level & 0x7f) < trace_param)
332             return 0;
333         ctx->trace(ctx, trace_param);
334     }
335     if (ctx->trace_val && name)
336         ctx->trace_val(ctx, (const char *)name, value);
337     return 0;
338 }
339 
cli_bcapi_trace_ptr(struct cli_bc_ctx * ctx,const uint8_t * ptr,uint32_t dummy)340 uint32_t cli_bcapi_trace_ptr(struct cli_bc_ctx *ctx, const uint8_t *ptr, uint32_t dummy)
341 {
342     UNUSEDPARAM(dummy);
343     if (LIKELY(ctx->trace_level < trace_val))
344         return 0;
345     if (ctx->trace_level & 0x80) {
346         if ((ctx->trace_level & 0x7f) < trace_param)
347             return 0;
348         ctx->trace(ctx, trace_param);
349     }
350     if (ctx->trace_ptr)
351         ctx->trace_ptr(ctx, ptr);
352     return 0;
353 }
354 
cli_bcapi_pe_rawaddr(struct cli_bc_ctx * ctx,uint32_t rva)355 uint32_t cli_bcapi_pe_rawaddr(struct cli_bc_ctx *ctx, uint32_t rva)
356 {
357     uint32_t ret;
358     unsigned err                      = 0;
359     const struct cli_pe_hook_data *pe = ctx->hooks.pedata;
360     ret                               = cli_rawaddr(rva, ctx->sections, pe->nsections, &err,
361                       ctx->file_size, pe->hdr_size);
362     if (err) {
363         cli_dbgmsg("bcapi_pe_rawaddr invalid rva: %u\n", rva);
364         return PE_INVALID_RVA;
365     }
366     return ret;
367 }
368 
cli_memmem(const char * haystack,unsigned hlen,const unsigned char * needle,unsigned nlen)369 static inline const char *cli_memmem(const char *haystack, unsigned hlen,
370                                      const unsigned char *needle, unsigned nlen)
371 {
372     const char *p;
373     unsigned char c;
374     if (!needle || !haystack) {
375         return NULL;
376     }
377     c = *needle++;
378     if (nlen == 1)
379         return memchr(haystack, c, hlen);
380 
381     while (hlen >= nlen) {
382         p        = haystack;
383         haystack = memchr(haystack, c, hlen - nlen + 1);
384         if (!haystack)
385             return NULL;
386         hlen -= haystack + 1 - p;
387         p = haystack + 1;
388         if (!memcmp(p, needle, nlen - 1))
389             return haystack;
390         haystack = p;
391     }
392     return NULL;
393 }
394 
cli_bcapi_file_find(struct cli_bc_ctx * ctx,const uint8_t * data,uint32_t len)395 int32_t cli_bcapi_file_find(struct cli_bc_ctx *ctx, const uint8_t *data, uint32_t len)
396 {
397     fmap_t *map = ctx->fmap;
398     if (!map || len <= 0) {
399         cli_dbgmsg("bcapi_file_find preconditions not met\n");
400         API_MISUSE();
401         return -1;
402     }
403     return cli_bcapi_file_find_limit(ctx, data, len, map->len);
404 }
405 
cli_bcapi_file_find_limit(struct cli_bc_ctx * ctx,const uint8_t * data,uint32_t len,int32_t limit)406 int32_t cli_bcapi_file_find_limit(struct cli_bc_ctx *ctx, const uint8_t *data, uint32_t len, int32_t limit)
407 {
408     char buf[4096];
409     fmap_t *map  = ctx->fmap;
410     uint32_t off = ctx->off;
411     size_t n;
412     size_t limit_sz;
413 
414     if (!map || (len > sizeof(buf) / 4) || (len <= 0) || (limit <= 0)) {
415         cli_dbgmsg("bcapi_file_find_limit preconditions not met\n");
416         API_MISUSE();
417         return -1;
418     }
419 
420     limit_sz = (size_t)limit;
421 
422     cli_event_int(EV, BCEV_OFFSET, off);
423     cli_event_fastdata(EV, BCEV_FIND, data, len);
424     for (;;) {
425         const char *p;
426         size_t readlen = sizeof(buf);
427         if (off + readlen > limit_sz) {
428             if (off > limit_sz) {
429                 return -1;
430             } else {
431                 readlen = limit_sz - off;
432             }
433         }
434         n = fmap_readn(map, buf, off, readlen);
435         if ((n < len) || (n == (size_t)-1))
436             return -1;
437         p = cli_memmem(buf, n, data, len);
438         if (p)
439             return off + (p - buf);
440         off += n;
441     }
442     return -1;
443 }
444 
cli_bcapi_file_byteat(struct cli_bc_ctx * ctx,uint32_t off)445 int32_t cli_bcapi_file_byteat(struct cli_bc_ctx *ctx, uint32_t off)
446 {
447     unsigned char c;
448     if (!ctx->fmap) {
449         cli_dbgmsg("bcapi_file_byteat: no fmap\n");
450         return -1;
451     }
452     cli_event_int(EV, BCEV_OFFSET, off);
453     if (fmap_readn(ctx->fmap, &c, off, 1) != 1) {
454         cli_dbgmsg("bcapi_file_byteat: fmap_readn failed at %u\n", off);
455         return -1;
456     }
457     return c;
458 }
459 
cli_bcapi_malloc(struct cli_bc_ctx * ctx,uint32_t size)460 uint8_t *cli_bcapi_malloc(struct cli_bc_ctx *ctx, uint32_t size)
461 {
462     void *v;
463 #if USE_MPOOL
464     if (!ctx->mpool) {
465         ctx->mpool = mpool_create();
466         if (!ctx->mpool) {
467             cli_dbgmsg("bytecode: mpool_create failed!\n");
468             cli_event_error_oom(EV, 0);
469             return NULL;
470         }
471     }
472     v = MPOOL_MALLOC(ctx->mpool, size);
473 #else
474     /* TODO: implement using a list of pointers we allocated! */
475     cli_errmsg("cli_bcapi_malloc not implemented for systems without mmap yet!\n");
476     v = cli_malloc(size);
477 #endif
478     if (!v)
479         cli_event_error_oom(EV, size);
480     return v;
481 }
482 
cli_bcapi_get_pe_section(struct cli_bc_ctx * ctx,struct cli_exe_section * section,uint32_t num)483 int32_t cli_bcapi_get_pe_section(struct cli_bc_ctx *ctx, struct cli_exe_section *section, uint32_t num)
484 {
485     if (num < ctx->hooks.pedata->nsections) {
486         memcpy(section, &ctx->sections[num], sizeof(struct cli_exe_section));
487         return 0;
488     }
489     return -1;
490 }
491 
cli_bcapi_fill_buffer(struct cli_bc_ctx * ctx,uint8_t * buf,uint32_t buflen,uint32_t filled,uint32_t pos,uint32_t fill)492 int32_t cli_bcapi_fill_buffer(struct cli_bc_ctx *ctx, uint8_t *buf,
493                               uint32_t buflen, uint32_t filled,
494                               uint32_t pos, uint32_t fill)
495 {
496     int32_t res, remaining, tofill;
497     UNUSEDPARAM(fill);
498     if (!buf || !buflen || buflen > CLI_MAX_ALLOCATION || filled > buflen) {
499         cli_dbgmsg("fill_buffer1\n");
500         API_MISUSE();
501         return -1;
502     }
503     if (ctx->off >= ctx->file_size) {
504         cli_dbgmsg("fill_buffer2\n");
505         API_MISUSE();
506         return 0;
507     }
508     remaining = filled - pos;
509     if (remaining) {
510         if (!CLI_ISCONTAINED(buf, buflen, buf + pos, remaining)) {
511             cli_dbgmsg("fill_buffer3\n");
512             API_MISUSE();
513             return -1;
514         }
515         memmove(buf, buf + pos, remaining);
516     }
517     tofill = buflen - remaining;
518     if (!CLI_ISCONTAINED(buf, buflen, buf + remaining, tofill)) {
519         cli_dbgmsg("fill_buffer4\n");
520         API_MISUSE();
521         return -1;
522     }
523     res = cli_bcapi_read(ctx, buf + remaining, tofill);
524     if (res <= 0) {
525         cli_dbgmsg("fill_buffer5\n");
526         API_MISUSE();
527         return res;
528     }
529     return remaining + res;
530 }
531 
cli_bcapi_extract_new(struct cli_bc_ctx * ctx,int32_t id)532 int32_t cli_bcapi_extract_new(struct cli_bc_ctx *ctx, int32_t id)
533 {
534     cli_ctx *cctx;
535     int res = -1;
536 
537     cli_event_count(EV, BCEV_EXTRACTED);
538     cli_dbgmsg("previous tempfile had %u bytes\n", ctx->written);
539     if (!ctx->written)
540         return 0;
541     if (ctx->ctx && cli_updatelimits(ctx->ctx, ctx->written))
542         return -1;
543     ctx->written = 0;
544     if (lseek(ctx->outfd, 0, SEEK_SET) == -1) {
545         cli_dbgmsg("bytecode: call to lseek() has failed\n");
546         return CL_ESEEK;
547     }
548     cli_dbgmsg("bytecode: scanning extracted file %s\n", ctx->tempfile);
549     cctx = (cli_ctx *)ctx->ctx;
550     if (cctx) {
551         res = cli_magic_scan_desc_type(ctx->outfd, ctx->tempfile, cctx, ctx->containertype, NULL);
552         if (res == CL_VIRUS) {
553             ctx->virname = cli_get_last_virus(cctx);
554             ctx->found   = 1;
555         }
556     }
557     if ((cctx && cctx->engine->keeptmp) ||
558         (ftruncate(ctx->outfd, 0) == -1)) {
559 
560         close(ctx->outfd);
561         if (!(cctx && cctx->engine->keeptmp) && ctx->tempfile)
562             cli_unlink(ctx->tempfile);
563         free(ctx->tempfile);
564         ctx->tempfile = NULL;
565         ctx->outfd    = 0;
566     }
567     cli_dbgmsg("bytecode: extracting new file with id %u\n", id);
568     return res;
569 }
570 
571 #define BUF 16
cli_bcapi_read_number(struct cli_bc_ctx * ctx,uint32_t radix)572 int32_t cli_bcapi_read_number(struct cli_bc_ctx *ctx, uint32_t radix)
573 {
574     unsigned i;
575     const char *p;
576     int32_t result;
577 
578     if ((radix != 10 && radix != 16) || !ctx->fmap)
579         return -1;
580     cli_event_int(EV, BCEV_OFFSET, ctx->off);
581     while ((p = fmap_need_off_once(ctx->fmap, ctx->off, BUF))) {
582         for (i = 0; i < BUF; i++) {
583             if ((p[i] >= '0' && p[i] <= '9') || (radix == 16 && ((p[i] >= 'a' && p[i] <= 'f') || (p[i] >= 'A' && p[i] <= 'F')))) {
584                 char *endptr;
585                 p = fmap_need_ptr_once(ctx->fmap, p + i, 16);
586                 if (!p)
587                     return -1;
588                 result = strtoul(p, &endptr, radix);
589                 ctx->off += i + (endptr - p);
590                 return result;
591             }
592         }
593         ctx->off += BUF;
594     }
595     return -1;
596 }
597 
cli_bcapi_hashset_new(struct cli_bc_ctx * ctx)598 int32_t cli_bcapi_hashset_new(struct cli_bc_ctx *ctx)
599 {
600     unsigned n            = ctx->nhashsets + 1;
601     struct cli_hashset *s = cli_realloc(ctx->hashsets, sizeof(*ctx->hashsets) * n);
602     if (!s) {
603         cli_event_error_oom(EV, 0);
604         return -1;
605     }
606     ctx->hashsets  = s;
607     ctx->nhashsets = n;
608     s              = &s[n - 1];
609     cli_hashset_init(s, 16, 80);
610     return n - 1;
611 }
612 
get_hashset(struct cli_bc_ctx * ctx,int32_t id)613 static struct cli_hashset *get_hashset(struct cli_bc_ctx *ctx, int32_t id)
614 {
615     if (id < 0 || (unsigned int)id >= ctx->nhashsets || !ctx->hashsets) {
616         API_MISUSE();
617         return NULL;
618     }
619     return &ctx->hashsets[id];
620 }
621 
cli_bcapi_hashset_add(struct cli_bc_ctx * ctx,int32_t id,uint32_t key)622 int32_t cli_bcapi_hashset_add(struct cli_bc_ctx *ctx, int32_t id, uint32_t key)
623 {
624     struct cli_hashset *s = get_hashset(ctx, id);
625     if (!s)
626         return -1;
627     return cli_hashset_addkey(s, key);
628 }
629 
cli_bcapi_hashset_remove(struct cli_bc_ctx * ctx,int32_t id,uint32_t key)630 int32_t cli_bcapi_hashset_remove(struct cli_bc_ctx *ctx, int32_t id, uint32_t key)
631 {
632     struct cli_hashset *s = get_hashset(ctx, id);
633     if (!s)
634         return -1;
635     return cli_hashset_removekey(s, key);
636 }
637 
cli_bcapi_hashset_contains(struct cli_bc_ctx * ctx,int32_t id,uint32_t key)638 int32_t cli_bcapi_hashset_contains(struct cli_bc_ctx *ctx, int32_t id, uint32_t key)
639 {
640     struct cli_hashset *s = get_hashset(ctx, id);
641     if (!s)
642         return -1;
643     return cli_hashset_contains(s, key);
644 }
645 
cli_bcapi_hashset_empty(struct cli_bc_ctx * ctx,int32_t id)646 int32_t cli_bcapi_hashset_empty(struct cli_bc_ctx *ctx, int32_t id)
647 {
648     struct cli_hashset *s = get_hashset(ctx, id);
649     return s ? !s->count : 1;
650 }
651 
cli_bcapi_hashset_done(struct cli_bc_ctx * ctx,int32_t id)652 int32_t cli_bcapi_hashset_done(struct cli_bc_ctx *ctx, int32_t id)
653 {
654     struct cli_hashset *s = get_hashset(ctx, id);
655     if (!s)
656         return -1;
657     cli_hashset_destroy(s);
658     if ((unsigned int)id == ctx->nhashsets - 1) {
659         ctx->nhashsets--;
660         if (!ctx->nhashsets) {
661             free(ctx->hashsets);
662             ctx->hashsets = NULL;
663         } else {
664             s = cli_realloc(ctx->hashsets, ctx->nhashsets * sizeof(*s));
665             if (s)
666                 ctx->hashsets = s;
667         }
668     }
669     return 0;
670 }
671 
cli_bcapi_buffer_pipe_new(struct cli_bc_ctx * ctx,uint32_t size)672 int32_t cli_bcapi_buffer_pipe_new(struct cli_bc_ctx *ctx, uint32_t size)
673 {
674     unsigned char *data;
675     struct bc_buffer *b;
676     unsigned n = ctx->nbuffers + 1;
677 
678     data = cli_calloc(1, size);
679     if (!data)
680         return -1;
681     b = cli_realloc(ctx->buffers, sizeof(*ctx->buffers) * n);
682     if (!b) {
683         free(data);
684         return -1;
685     }
686     ctx->buffers  = b;
687     ctx->nbuffers = n;
688     b             = &b[n - 1];
689 
690     b->data         = data;
691     b->size         = size;
692     b->write_cursor = b->read_cursor = 0;
693     return n - 1;
694 }
695 
cli_bcapi_buffer_pipe_new_fromfile(struct cli_bc_ctx * ctx,uint32_t at)696 int32_t cli_bcapi_buffer_pipe_new_fromfile(struct cli_bc_ctx *ctx, uint32_t at)
697 {
698     struct bc_buffer *b;
699     unsigned n = ctx->nbuffers + 1;
700 
701     if (at >= ctx->file_size)
702         return -1;
703 
704     b = cli_realloc(ctx->buffers, sizeof(*ctx->buffers) * n);
705     if (!b) {
706         return -1;
707     }
708     ctx->buffers  = b;
709     ctx->nbuffers = n;
710     b             = &b[n - 1];
711 
712     /* NULL data means read from file at pos read_cursor */
713     b->data         = NULL;
714     b->size         = 0;
715     b->read_cursor  = at;
716     b->write_cursor = 0;
717     return n - 1;
718 }
719 
get_buffer(struct cli_bc_ctx * ctx,int32_t id)720 static struct bc_buffer *get_buffer(struct cli_bc_ctx *ctx, int32_t id)
721 {
722     if (!ctx->buffers || id < 0 || (unsigned int)id >= ctx->nbuffers) {
723         cli_dbgmsg("bytecode api: invalid buffer id %u\n", id);
724         return NULL;
725     }
726     return &ctx->buffers[id];
727 }
728 
cli_bcapi_buffer_pipe_read_avail(struct cli_bc_ctx * ctx,int32_t id)729 uint32_t cli_bcapi_buffer_pipe_read_avail(struct cli_bc_ctx *ctx, int32_t id)
730 {
731     struct bc_buffer *b = get_buffer(ctx, id);
732     if (!b)
733         return 0;
734     if (b->data) {
735         if (b->write_cursor <= b->read_cursor)
736             return 0;
737         return b->write_cursor - b->read_cursor;
738     }
739     if (!ctx->fmap || b->read_cursor >= ctx->file_size)
740         return 0;
741     if (b->read_cursor + BUFSIZ <= ctx->file_size)
742         return BUFSIZ;
743     return ctx->file_size - b->read_cursor;
744 }
745 
cli_bcapi_buffer_pipe_read_get(struct cli_bc_ctx * ctx,int32_t id,uint32_t size)746 const uint8_t *cli_bcapi_buffer_pipe_read_get(struct cli_bc_ctx *ctx, int32_t id, uint32_t size)
747 {
748     struct bc_buffer *b = get_buffer(ctx, id);
749     if (!b || size > cli_bcapi_buffer_pipe_read_avail(ctx, id) || !size)
750         return NULL;
751     if (b->data)
752         return b->data + b->read_cursor;
753     return fmap_need_off(ctx->fmap, b->read_cursor, size);
754 }
755 
cli_bcapi_buffer_pipe_read_stopped(struct cli_bc_ctx * ctx,int32_t id,uint32_t amount)756 int32_t cli_bcapi_buffer_pipe_read_stopped(struct cli_bc_ctx *ctx, int32_t id, uint32_t amount)
757 {
758     struct bc_buffer *b = get_buffer(ctx, id);
759     if (!b)
760         return -1;
761     if (b->data) {
762         if (b->write_cursor <= b->read_cursor)
763             return -1;
764         if (b->read_cursor + amount > b->write_cursor)
765             b->read_cursor = b->write_cursor;
766         else
767             b->read_cursor += amount;
768         if (b->read_cursor >= b->size &&
769             b->write_cursor >= b->size)
770             b->read_cursor = b->write_cursor = 0;
771         return 0;
772     }
773     b->read_cursor += amount;
774     return 0;
775 }
776 
cli_bcapi_buffer_pipe_write_avail(struct cli_bc_ctx * ctx,int32_t id)777 uint32_t cli_bcapi_buffer_pipe_write_avail(struct cli_bc_ctx *ctx, int32_t id)
778 {
779     struct bc_buffer *b = get_buffer(ctx, id);
780     if (!b)
781         return 0;
782     if (!b->data)
783         return 0;
784     if (b->write_cursor >= b->size)
785         return 0;
786     return b->size - b->write_cursor;
787 }
788 
cli_bcapi_buffer_pipe_write_get(struct cli_bc_ctx * ctx,int32_t id,uint32_t size)789 uint8_t *cli_bcapi_buffer_pipe_write_get(struct cli_bc_ctx *ctx, int32_t id, uint32_t size)
790 {
791     struct bc_buffer *b = get_buffer(ctx, id);
792     if (!b || size > cli_bcapi_buffer_pipe_write_avail(ctx, id) || !size)
793         return NULL;
794     if (!b->data)
795         return NULL;
796     return b->data + b->write_cursor;
797 }
798 
cli_bcapi_buffer_pipe_write_stopped(struct cli_bc_ctx * ctx,int32_t id,uint32_t size)799 int32_t cli_bcapi_buffer_pipe_write_stopped(struct cli_bc_ctx *ctx, int32_t id, uint32_t size)
800 {
801     struct bc_buffer *b = get_buffer(ctx, id);
802     if (!b || !b->data)
803         return -1;
804     if (b->write_cursor + size >= b->size)
805         b->write_cursor = b->size;
806     else
807         b->write_cursor += size;
808     return 0;
809 }
810 
cli_bcapi_buffer_pipe_done(struct cli_bc_ctx * ctx,int32_t id)811 int32_t cli_bcapi_buffer_pipe_done(struct cli_bc_ctx *ctx, int32_t id)
812 {
813     struct bc_buffer *b = get_buffer(ctx, id);
814     if (!b)
815         return -1;
816     free(b->data);
817     b->data = NULL;
818     return -0;
819 }
820 
cli_bcapi_inflate_init(struct cli_bc_ctx * ctx,int32_t from,int32_t to,int32_t windowBits)821 int32_t cli_bcapi_inflate_init(struct cli_bc_ctx *ctx, int32_t from, int32_t to, int32_t windowBits)
822 {
823     int ret;
824     z_stream stream;
825     struct bc_inflate *b;
826     unsigned n = ctx->ninflates + 1;
827     if (!get_buffer(ctx, from) || !get_buffer(ctx, to)) {
828         cli_dbgmsg("bytecode api: inflate_init: invalid buffers!\n");
829         return -1;
830     }
831     b = cli_realloc(ctx->inflates, sizeof(*ctx->inflates) * n);
832     if (!b) {
833         return -1;
834     }
835     ctx->inflates  = b;
836     ctx->ninflates = n;
837     b              = &b[n - 1];
838 
839     b->from     = from;
840     b->to       = to;
841     b->needSync = 0;
842     memset(&b->stream, 0, sizeof(stream));
843     ret = inflateInit2(&b->stream, windowBits);
844     switch (ret) {
845         case Z_MEM_ERROR:
846             cli_dbgmsg("bytecode api: inflateInit2: out of memory!\n");
847             return -1;
848         case Z_VERSION_ERROR:
849             cli_dbgmsg("bytecode api: inflateinit2: zlib version error!\n");
850             return -1;
851         case Z_STREAM_ERROR:
852             cli_dbgmsg("bytecode api: inflateinit2: zlib stream error!\n");
853             return -1;
854         case Z_OK:
855             break;
856         default:
857             cli_dbgmsg("bytecode api: inflateInit2: unknown error %d\n", ret);
858             return -1;
859     }
860 
861     return n - 1;
862 }
863 
get_inflate(struct cli_bc_ctx * ctx,int32_t id)864 static struct bc_inflate *get_inflate(struct cli_bc_ctx *ctx, int32_t id)
865 {
866     if (id < 0 || (unsigned int)id >= ctx->ninflates || !ctx->inflates)
867         return NULL;
868     return &ctx->inflates[id];
869 }
870 
cli_bcapi_inflate_process(struct cli_bc_ctx * ctx,int32_t id)871 int32_t cli_bcapi_inflate_process(struct cli_bc_ctx *ctx, int32_t id)
872 {
873     int ret;
874     unsigned avail_in_orig, avail_out_orig;
875     struct bc_inflate *b = get_inflate(ctx, id);
876     if (!b || b->from == -1 || b->to == -1)
877         return -1;
878 
879     b->stream.avail_in = avail_in_orig =
880         cli_bcapi_buffer_pipe_read_avail(ctx, b->from);
881 
882     b->stream.next_in = (void *)cli_bcapi_buffer_pipe_read_get(ctx, b->from,
883                                                                b->stream.avail_in);
884 
885     b->stream.avail_out = avail_out_orig =
886         cli_bcapi_buffer_pipe_write_avail(ctx, b->to);
887 
888     b->stream.next_out = cli_bcapi_buffer_pipe_write_get(ctx, b->to,
889                                                          b->stream.avail_out);
890 
891     if (!b->stream.avail_in || !b->stream.avail_out || !b->stream.next_in || !b->stream.next_out)
892         return -1;
893     /* try hard to extract data, skipping over corrupted data */
894     do {
895         if (!b->needSync) {
896             ret = inflate(&b->stream, Z_NO_FLUSH);
897             if (ret == Z_DATA_ERROR) {
898                 cli_dbgmsg("bytecode api: inflate at %lu: %s, trying to recover\n", b->stream.total_in,
899                            b->stream.msg);
900                 b->needSync = 1;
901             }
902         }
903         if (b->needSync) {
904             ret = inflateSync(&b->stream);
905             if (ret == Z_OK) {
906                 cli_dbgmsg("bytecode api: successfully recovered inflate stream\n");
907                 b->needSync = 0;
908                 continue;
909             }
910         }
911         break;
912     } while (1);
913     cli_bcapi_buffer_pipe_read_stopped(ctx, b->from, avail_in_orig - b->stream.avail_in);
914     cli_bcapi_buffer_pipe_write_stopped(ctx, b->to, avail_out_orig - b->stream.avail_out);
915 
916     if (ret == Z_MEM_ERROR) {
917         cli_dbgmsg("bytecode api: out of memory!\n");
918         cli_bcapi_inflate_done(ctx, id);
919         return ret;
920     }
921     if (ret == Z_STREAM_END) {
922         cli_bcapi_inflate_done(ctx, id);
923     }
924     if (ret == Z_BUF_ERROR) {
925         cli_dbgmsg("bytecode api: buffer error!\n");
926     }
927 
928     return ret;
929 }
930 
cli_bcapi_inflate_done(struct cli_bc_ctx * ctx,int32_t id)931 int32_t cli_bcapi_inflate_done(struct cli_bc_ctx *ctx, int32_t id)
932 {
933     int ret;
934     struct bc_inflate *b = get_inflate(ctx, id);
935     if (!b || b->from == -1 || b->to == -1)
936         return -1;
937     ret = inflateEnd(&b->stream);
938     if (ret == Z_STREAM_ERROR)
939         cli_dbgmsg("bytecode api: inflateEnd: %s\n", b->stream.msg);
940     b->from = b->to = -1;
941     return ret;
942 }
943 
cli_bcapi_lzma_init(struct cli_bc_ctx * ctx,int32_t from,int32_t to)944 int32_t cli_bcapi_lzma_init(struct cli_bc_ctx *ctx, int32_t from, int32_t to)
945 {
946     int ret;
947     struct bc_lzma *b;
948     unsigned n = ctx->nlzmas + 1;
949     unsigned avail_in_orig;
950 
951     if (!get_buffer(ctx, from) || !get_buffer(ctx, to)) {
952         cli_dbgmsg("bytecode api: lzma_init: invalid buffers!\n");
953         return -1;
954     }
955 
956     avail_in_orig = cli_bcapi_buffer_pipe_read_avail(ctx, from);
957     if (avail_in_orig < LZMA_PROPS_SIZE + 8) {
958         cli_dbgmsg("bytecode api: lzma_init: not enough bytes in pipe to read LZMA header!\n");
959         return -1;
960     }
961 
962     b = cli_realloc(ctx->lzmas, sizeof(*ctx->lzmas) * n);
963     if (!b) {
964         return -1;
965     }
966     ctx->lzmas  = b;
967     ctx->nlzmas = n;
968     b           = &b[n - 1];
969 
970     b->from = from;
971     b->to   = to;
972     memset(&b->stream, 0, sizeof(b->stream));
973 
974     b->stream.avail_in = avail_in_orig;
975     b->stream.next_in  = (void *)cli_bcapi_buffer_pipe_read_get(ctx, b->from,
976                                                                b->stream.avail_in);
977 
978     if ((ret = cli_LzmaInit(&b->stream, 0)) != LZMA_RESULT_OK) {
979         cli_dbgmsg("bytecode api: LzmaInit: Failed to initialize LZMA decompressor: %d!\n", ret);
980         cli_bcapi_buffer_pipe_read_stopped(ctx, b->from, avail_in_orig - b->stream.avail_in);
981         return ret;
982     }
983 
984     cli_bcapi_buffer_pipe_read_stopped(ctx, b->from, avail_in_orig - b->stream.avail_in);
985     return n - 1;
986 }
987 
get_lzma(struct cli_bc_ctx * ctx,int32_t id)988 static struct bc_lzma *get_lzma(struct cli_bc_ctx *ctx, int32_t id)
989 {
990     if (id < 0 || (unsigned int)id >= ctx->nlzmas || !ctx->lzmas)
991         return NULL;
992     return &ctx->lzmas[id];
993 }
994 
cli_bcapi_lzma_process(struct cli_bc_ctx * ctx,int32_t id)995 int32_t cli_bcapi_lzma_process(struct cli_bc_ctx *ctx, int32_t id)
996 {
997     int ret;
998     unsigned avail_in_orig, avail_out_orig;
999     struct bc_lzma *b = get_lzma(ctx, id);
1000     if (!b || b->from == -1 || b->to == -1)
1001         return -1;
1002 
1003     b->stream.avail_in = avail_in_orig =
1004         cli_bcapi_buffer_pipe_read_avail(ctx, b->from);
1005 
1006     b->stream.next_in = (void *)cli_bcapi_buffer_pipe_read_get(ctx, b->from,
1007                                                                b->stream.avail_in);
1008 
1009     b->stream.avail_out = avail_out_orig =
1010         cli_bcapi_buffer_pipe_write_avail(ctx, b->to);
1011     b->stream.next_out = (uint8_t *)cli_bcapi_buffer_pipe_write_get(ctx, b->to,
1012                                                                     b->stream.avail_out);
1013 
1014     if (!b->stream.avail_in || !b->stream.avail_out || !b->stream.next_in || !b->stream.next_out)
1015         return -1;
1016 
1017     ret = cli_LzmaDecode(&b->stream);
1018     cli_bcapi_buffer_pipe_read_stopped(ctx, b->from, avail_in_orig - b->stream.avail_in);
1019     cli_bcapi_buffer_pipe_write_stopped(ctx, b->to, avail_out_orig - b->stream.avail_out);
1020 
1021     if (ret != LZMA_RESULT_OK && ret != LZMA_STREAM_END) {
1022         cli_dbgmsg("bytecode api: LzmaDecode: Error %d while decoding\n", ret);
1023         cli_bcapi_lzma_done(ctx, id);
1024     }
1025 
1026     return ret;
1027 }
1028 
cli_bcapi_lzma_done(struct cli_bc_ctx * ctx,int32_t id)1029 int32_t cli_bcapi_lzma_done(struct cli_bc_ctx *ctx, int32_t id)
1030 {
1031     struct bc_lzma *b = get_lzma(ctx, id);
1032     if (!b || b->from == -1 || b->to == -1)
1033         return -1;
1034     cli_LzmaShutdown(&b->stream);
1035     b->from = b->to = -1;
1036     return 0;
1037 }
1038 
cli_bcapi_bzip2_init(struct cli_bc_ctx * ctx,int32_t from,int32_t to)1039 int32_t cli_bcapi_bzip2_init(struct cli_bc_ctx *ctx, int32_t from, int32_t to)
1040 {
1041 #if HAVE_BZLIB_H
1042     int ret;
1043     struct bc_bzip2 *b;
1044     unsigned n = ctx->nbzip2s + 1;
1045     if (!get_buffer(ctx, from) || !get_buffer(ctx, to)) {
1046         cli_dbgmsg("bytecode api: bzip2_init: invalid buffers!\n");
1047         return -1;
1048     }
1049     b = cli_realloc(ctx->bzip2s, sizeof(*ctx->bzip2s) * n);
1050     if (!b) {
1051         return -1;
1052     }
1053     ctx->bzip2s  = b;
1054     ctx->nbzip2s = n;
1055     b            = &b[n - 1];
1056 
1057     b->from = from;
1058     b->to   = to;
1059     memset(&b->stream, 0, sizeof(b->stream));
1060     ret = BZ2_bzDecompressInit(&b->stream, 0, 0);
1061     switch (ret) {
1062         case BZ_CONFIG_ERROR:
1063             cli_dbgmsg("bytecode api: BZ2_bzDecompressInit: Library has been mis-compiled!\n");
1064             return -1;
1065         case BZ_PARAM_ERROR:
1066             cli_dbgmsg("bytecode api: BZ2_bzDecompressInit: Invalid arguments!\n");
1067             return -1;
1068         case BZ_MEM_ERROR:
1069             cli_dbgmsg("bytecode api: BZ2_bzDecompressInit: Insufficient memory available!\n");
1070             return -1;
1071         case BZ_OK:
1072             break;
1073         default:
1074             cli_dbgmsg("bytecode api: BZ2_bzDecompressInit: unknown error %d\n", ret);
1075             return -1;
1076     }
1077 
1078     return n - 1;
1079 #else
1080     return -1;
1081 #endif
1082 }
1083 
1084 #if HAVE_BZLIB_H
get_bzip2(struct cli_bc_ctx * ctx,int32_t id)1085 static struct bc_bzip2 *get_bzip2(struct cli_bc_ctx *ctx, int32_t id)
1086 {
1087     if (id < 0 || (unsigned int)id >= ctx->nbzip2s || !ctx->bzip2s)
1088         return NULL;
1089     return &ctx->bzip2s[id];
1090 }
1091 #endif
1092 
cli_bcapi_bzip2_process(struct cli_bc_ctx * ctx,int32_t id)1093 int32_t cli_bcapi_bzip2_process(struct cli_bc_ctx *ctx, int32_t id)
1094 {
1095 #if HAVE_BZLIB_H
1096     int ret;
1097     unsigned avail_in_orig, avail_out_orig;
1098     struct bc_bzip2 *b = get_bzip2(ctx, id);
1099     if (!b || b->from == -1 || b->to == -1)
1100         return -1;
1101 
1102     b->stream.avail_in = avail_in_orig =
1103         cli_bcapi_buffer_pipe_read_avail(ctx, b->from);
1104 
1105     b->stream.next_in = (void *)cli_bcapi_buffer_pipe_read_get(ctx, b->from,
1106                                                                b->stream.avail_in);
1107 
1108     b->stream.avail_out = avail_out_orig =
1109         cli_bcapi_buffer_pipe_write_avail(ctx, b->to);
1110 
1111     b->stream.next_out = (char *)cli_bcapi_buffer_pipe_write_get(ctx, b->to,
1112                                                                  b->stream.avail_out);
1113 
1114     if (!b->stream.avail_in || !b->stream.avail_out || !b->stream.next_in || !b->stream.next_out)
1115         return -1;
1116     /* try hard to extract data, skipping over corrupted data */
1117     ret = BZ2_bzDecompress(&b->stream);
1118     cli_bcapi_buffer_pipe_read_stopped(ctx, b->from, avail_in_orig - b->stream.avail_in);
1119     cli_bcapi_buffer_pipe_write_stopped(ctx, b->to, avail_out_orig - b->stream.avail_out);
1120 
1121     /* check if nothing written whatsoever */
1122     if ((ret != BZ_OK) && (b->stream.avail_out == avail_out_orig)) {
1123         /* Inflation failed */
1124         cli_errmsg("cli_bcapi_bzip2_process: failed to decompress data\n");
1125     }
1126 
1127     return ret;
1128 #else
1129     return -1;
1130 #endif
1131 }
1132 
cli_bcapi_bzip2_done(struct cli_bc_ctx * ctx,int32_t id)1133 int32_t cli_bcapi_bzip2_done(struct cli_bc_ctx *ctx, int32_t id)
1134 {
1135 #if HAVE_BZLIB_H
1136     struct bc_bzip2 *b = get_bzip2(ctx, id);
1137     if (!b || b->from == -1 || b->to == -1)
1138         return -1;
1139     BZ2_bzDecompressEnd(&b->stream);
1140     b->from = b->to = -1;
1141     return 0;
1142 #else
1143     return -1;
1144 #endif
1145 }
1146 
cli_bcapi_bytecode_rt_error(struct cli_bc_ctx * ctx,int32_t id)1147 int32_t cli_bcapi_bytecode_rt_error(struct cli_bc_ctx *ctx, int32_t id)
1148 {
1149     int32_t line = id >> 8;
1150     int32_t col  = id & 0xff;
1151     UNUSEDPARAM(ctx);
1152     cli_warnmsg("Bytecode runtime error at line %u, col %u\n", line, col);
1153     return 0;
1154 }
1155 
cli_bcapi_jsnorm_init(struct cli_bc_ctx * ctx,int32_t from)1156 int32_t cli_bcapi_jsnorm_init(struct cli_bc_ctx *ctx, int32_t from)
1157 {
1158     struct parser_state *state;
1159     struct bc_jsnorm *b;
1160     unsigned n = ctx->njsnorms + 1;
1161     if (!get_buffer(ctx, from)) {
1162         cli_dbgmsg("bytecode api: jsnorm_init: invalid buffers!\n");
1163         return -1;
1164     }
1165     state = cli_js_init();
1166     if (!state)
1167         return -1;
1168     b = cli_realloc(ctx->jsnorms, sizeof(*ctx->jsnorms) * n);
1169     if (!b) {
1170         cli_js_destroy(state);
1171         return -1;
1172     }
1173     ctx->jsnorms  = b;
1174     ctx->njsnorms = n;
1175     b             = &b[n - 1];
1176     b->from       = from;
1177     b->state      = state;
1178     if (!ctx->jsnormdir) {
1179         cli_ctx *cctx  = (cli_ctx *)ctx->ctx;
1180         ctx->jsnormdir = cli_gentemp_with_prefix(cctx ? cctx->engine->tmpdir : NULL, "normalized-js");
1181         if (ctx->jsnormdir) {
1182             if (mkdir(ctx->jsnormdir, 0700)) {
1183                 cli_dbgmsg("js: can't create temp dir %s\n", ctx->jsnormdir);
1184                 free(ctx->jsnormdir);
1185                 return CL_ETMPDIR;
1186             }
1187         }
1188     }
1189     return n - 1;
1190 }
1191 
get_jsnorm(struct cli_bc_ctx * ctx,int32_t id)1192 static struct bc_jsnorm *get_jsnorm(struct cli_bc_ctx *ctx, int32_t id)
1193 {
1194     if (id < 0 || (unsigned int)id >= ctx->njsnorms || !ctx->jsnorms)
1195         return NULL;
1196     return &ctx->jsnorms[id];
1197 }
1198 
cli_bcapi_jsnorm_process(struct cli_bc_ctx * ctx,int32_t id)1199 int32_t cli_bcapi_jsnorm_process(struct cli_bc_ctx *ctx, int32_t id)
1200 {
1201     unsigned avail;
1202     const unsigned char *in;
1203     cli_ctx *cctx       = ctx->ctx;
1204     struct bc_jsnorm *b = get_jsnorm(ctx, id);
1205     if (!b || b->from == -1 || !b->state)
1206         return -1;
1207 
1208     avail = cli_bcapi_buffer_pipe_read_avail(ctx, b->from);
1209     in    = cli_bcapi_buffer_pipe_read_get(ctx, b->from, avail);
1210     if (!avail || !in)
1211         return -1;
1212     if (cctx && cli_checklimits("bytecode js api", cctx, ctx->jsnormwritten + avail, 0, 0))
1213         return -1;
1214     cli_bcapi_buffer_pipe_read_stopped(ctx, b->from, avail);
1215     cli_js_process_buffer(b->state, (char *)in, avail);
1216     return 0;
1217 }
1218 
cli_bcapi_jsnorm_done(struct cli_bc_ctx * ctx,int32_t id)1219 int32_t cli_bcapi_jsnorm_done(struct cli_bc_ctx *ctx, int32_t id)
1220 {
1221     struct bc_jsnorm *b = get_jsnorm(ctx, id);
1222     if (!b || b->from == -1)
1223         return -1;
1224     if (ctx->ctx && cli_updatelimits(ctx->ctx, ctx->jsnormwritten))
1225         return -1;
1226     ctx->jsnormwritten = 0;
1227     cli_js_parse_done(b->state);
1228     cli_js_output(b->state, ctx->jsnormdir);
1229     cli_js_destroy(b->state);
1230     b->from = -1;
1231     return 0;
1232 }
1233 
myround(double a)1234 static inline double myround(double a)
1235 {
1236     if (a < 0)
1237         return a - 0.5;
1238     return a + 0.5;
1239 }
1240 
cli_bcapi_ilog2(struct cli_bc_ctx * ctx,uint32_t a,uint32_t b)1241 int32_t cli_bcapi_ilog2(struct cli_bc_ctx *ctx, uint32_t a, uint32_t b)
1242 {
1243     double f;
1244     UNUSEDPARAM(ctx);
1245     if (!b)
1246         return 0x7fffffff;
1247     /* log(a/b) is -32..32, so 2^26*32=2^31 covers the entire range of int32 */
1248     f = (1 << 26) * log((double)a / b) / log(2);
1249     return (int32_t)myround(f);
1250 }
1251 
cli_bcapi_ipow(struct cli_bc_ctx * ctx,int32_t a,int32_t b,int32_t c)1252 int32_t cli_bcapi_ipow(struct cli_bc_ctx *ctx, int32_t a, int32_t b, int32_t c)
1253 {
1254     UNUSEDPARAM(ctx);
1255     if (!a && b < 0)
1256         return 0x7fffffff;
1257     return (int32_t)myround(c * pow(a, b));
1258 }
1259 
cli_bcapi_iexp(struct cli_bc_ctx * ctx,int32_t a,int32_t b,int32_t c)1260 uint32_t cli_bcapi_iexp(struct cli_bc_ctx *ctx, int32_t a, int32_t b, int32_t c)
1261 {
1262     double f;
1263     UNUSEDPARAM(ctx);
1264     if (!b)
1265         return 0x7fffffff;
1266     f = c * exp((double)a / b);
1267     return (uint32_t)myround(f);
1268 }
1269 
cli_bcapi_isin(struct cli_bc_ctx * ctx,int32_t a,int32_t b,int32_t c)1270 int32_t cli_bcapi_isin(struct cli_bc_ctx *ctx, int32_t a, int32_t b, int32_t c)
1271 {
1272     double f;
1273     UNUSEDPARAM(ctx);
1274     if (!b)
1275         return 0x7fffffff;
1276     f = c * sin((double)a / b);
1277     return (int32_t)myround(f);
1278 }
1279 
cli_bcapi_icos(struct cli_bc_ctx * ctx,int32_t a,int32_t b,int32_t c)1280 int32_t cli_bcapi_icos(struct cli_bc_ctx *ctx, int32_t a, int32_t b, int32_t c)
1281 {
1282     double f;
1283     UNUSEDPARAM(ctx);
1284     if (!b)
1285         return 0x7fffffff;
1286     f = c * cos((double)a / b);
1287     return (int32_t)myround(f);
1288 }
1289 
cli_bcapi_memstr(struct cli_bc_ctx * ctx,const uint8_t * h,int32_t hs,const uint8_t * n,int32_t ns)1290 int32_t cli_bcapi_memstr(struct cli_bc_ctx *ctx, const uint8_t *h, int32_t hs,
1291                          const uint8_t *n, int32_t ns)
1292 {
1293     const uint8_t *s;
1294     if (!h || !n || hs < 0 || ns < 0) {
1295         API_MISUSE();
1296         return -1;
1297     }
1298     cli_event_fastdata(EV, BCEV_MEM_1, h, hs);
1299     cli_event_fastdata(EV, BCEV_MEM_2, n, ns);
1300     s = (const uint8_t *)cli_memstr((const char *)h, hs, (const char *)n, ns);
1301     if (!s)
1302         return -1;
1303     return s - h;
1304 }
1305 
cli_bcapi_hex2ui(struct cli_bc_ctx * ctx,uint32_t ah,uint32_t bh)1306 int32_t cli_bcapi_hex2ui(struct cli_bc_ctx *ctx, uint32_t ah, uint32_t bh)
1307 {
1308     char result = 0;
1309     unsigned char in[2];
1310     UNUSEDPARAM(ctx);
1311 
1312     in[0] = ah;
1313     in[1] = bh;
1314 
1315     if (cli_hex2str_to((const char *)in, &result, 2) == -1)
1316         return -1;
1317     return result;
1318 }
1319 
cli_bcapi_atoi(struct cli_bc_ctx * ctx,const uint8_t * str,int32_t len)1320 int32_t cli_bcapi_atoi(struct cli_bc_ctx *ctx, const uint8_t *str, int32_t len)
1321 {
1322     int32_t number     = 0;
1323     const uint8_t *end = str + len;
1324     UNUSEDPARAM(ctx);
1325 
1326     while (isspace(*str) && str < end) str++;
1327     if (str == end)
1328         return -1; /* all spaces */
1329     if (*str == '+') str++;
1330     if (str == end)
1331         return -1; /* all spaces and +*/
1332     if (*str == '-')
1333         return -1; /* only positive numbers */
1334     if (!isdigit(*str))
1335         return -1;
1336     while (isdigit(*str) && str < end) {
1337         number = number * 10 + (*str - '0');
1338     }
1339     return number;
1340 }
1341 
cli_bcapi_debug_print_str_start(struct cli_bc_ctx * ctx,const uint8_t * s,uint32_t len)1342 uint32_t cli_bcapi_debug_print_str_start(struct cli_bc_ctx *ctx, const uint8_t *s, uint32_t len)
1343 {
1344     UNUSEDPARAM(ctx);
1345 
1346     if (!s || len <= 0)
1347         return -1;
1348     cli_event_fastdata(EV, BCEV_DBG_STR, s, len);
1349     cli_dbgmsg("bytecode debug: %.*s", len, s);
1350     return 0;
1351 }
1352 
cli_bcapi_debug_print_str_nonl(struct cli_bc_ctx * ctx,const uint8_t * s,uint32_t len)1353 uint32_t cli_bcapi_debug_print_str_nonl(struct cli_bc_ctx *ctx, const uint8_t *s, uint32_t len)
1354 {
1355     UNUSEDPARAM(ctx);
1356 
1357     if (!s || len <= 0)
1358         return -1;
1359     if (!cli_debug_flag)
1360         return 0;
1361     return fwrite(s, 1, len, stderr);
1362 }
1363 
cli_bcapi_entropy_buffer(struct cli_bc_ctx * ctx,uint8_t * s,int32_t len)1364 uint32_t cli_bcapi_entropy_buffer(struct cli_bc_ctx *ctx, uint8_t *s, int32_t len)
1365 {
1366     uint32_t probTable[256];
1367     unsigned int i;
1368     double entropy = 0;
1369     double log2    = log(2);
1370 
1371     UNUSEDPARAM(ctx);
1372 
1373     if (!s || len <= 0)
1374         return -1;
1375     memset(probTable, 0, sizeof(probTable));
1376     for (i = 0; i < (unsigned int)len; i++) {
1377         probTable[s[i]]++;
1378     }
1379     for (i = 0; i < 256; i++) {
1380         double p;
1381         if (!probTable[i])
1382             continue;
1383         p = (double)probTable[i] / len;
1384         entropy += -p * log(p) / log2;
1385     }
1386     entropy *= 1 << 26;
1387     return (uint32_t)entropy;
1388 }
1389 
cli_bcapi_map_new(struct cli_bc_ctx * ctx,int32_t keysize,int32_t valuesize)1390 int32_t cli_bcapi_map_new(struct cli_bc_ctx *ctx, int32_t keysize, int32_t valuesize)
1391 {
1392     unsigned n = ctx->nmaps + 1;
1393     struct cli_map *s;
1394     if (!keysize)
1395         return -1;
1396     s = cli_realloc(ctx->maps, sizeof(*ctx->maps) * n);
1397     if (!s)
1398         return -1;
1399     ctx->maps  = s;
1400     ctx->nmaps = n;
1401     s          = &s[n - 1];
1402     cli_map_init(s, keysize, valuesize, 16);
1403     return n - 1;
1404 }
1405 
get_hashtab(struct cli_bc_ctx * ctx,int32_t id)1406 static struct cli_map *get_hashtab(struct cli_bc_ctx *ctx, int32_t id)
1407 {
1408     if (id < 0 || (unsigned int)id >= ctx->nmaps || !ctx->maps)
1409         return NULL;
1410     return &ctx->maps[id];
1411 }
1412 
cli_bcapi_map_addkey(struct cli_bc_ctx * ctx,const uint8_t * key,int32_t keysize,int32_t id)1413 int32_t cli_bcapi_map_addkey(struct cli_bc_ctx *ctx, const uint8_t *key, int32_t keysize, int32_t id)
1414 {
1415     struct cli_map *s = get_hashtab(ctx, id);
1416     if (!s)
1417         return -1;
1418     return cli_map_addkey(s, key, keysize);
1419 }
1420 
cli_bcapi_map_setvalue(struct cli_bc_ctx * ctx,const uint8_t * value,int32_t valuesize,int32_t id)1421 int32_t cli_bcapi_map_setvalue(struct cli_bc_ctx *ctx, const uint8_t *value, int32_t valuesize, int32_t id)
1422 {
1423     struct cli_map *s = get_hashtab(ctx, id);
1424     if (!s)
1425         return -1;
1426     return cli_map_setvalue(s, value, valuesize);
1427 }
1428 
cli_bcapi_map_remove(struct cli_bc_ctx * ctx,const uint8_t * key,int32_t keysize,int32_t id)1429 int32_t cli_bcapi_map_remove(struct cli_bc_ctx *ctx, const uint8_t *key, int32_t keysize, int32_t id)
1430 {
1431     struct cli_map *s = get_hashtab(ctx, id);
1432     if (!s)
1433         return -1;
1434     return cli_map_removekey(s, key, keysize);
1435 }
1436 
cli_bcapi_map_find(struct cli_bc_ctx * ctx,const uint8_t * key,int32_t keysize,int32_t id)1437 int32_t cli_bcapi_map_find(struct cli_bc_ctx *ctx, const uint8_t *key, int32_t keysize, int32_t id)
1438 {
1439     struct cli_map *s = get_hashtab(ctx, id);
1440     if (!s)
1441         return -1;
1442     return cli_map_find(s, key, keysize);
1443 }
1444 
cli_bcapi_map_getvaluesize(struct cli_bc_ctx * ctx,int32_t id)1445 int32_t cli_bcapi_map_getvaluesize(struct cli_bc_ctx *ctx, int32_t id)
1446 {
1447     struct cli_map *s = get_hashtab(ctx, id);
1448     if (!s)
1449         return -1;
1450     return cli_map_getvalue_size(s);
1451 }
1452 
cli_bcapi_map_getvalue(struct cli_bc_ctx * ctx,int32_t id,int32_t valuesize)1453 uint8_t *cli_bcapi_map_getvalue(struct cli_bc_ctx *ctx, int32_t id, int32_t valuesize)
1454 {
1455     struct cli_map *s = get_hashtab(ctx, id);
1456     if (!s)
1457         return NULL;
1458     if (cli_map_getvalue_size(s) != valuesize)
1459         return NULL;
1460     return cli_map_getvalue(s);
1461 }
1462 
cli_bcapi_map_done(struct cli_bc_ctx * ctx,int32_t id)1463 int32_t cli_bcapi_map_done(struct cli_bc_ctx *ctx, int32_t id)
1464 {
1465     struct cli_map *s = get_hashtab(ctx, id);
1466     if (!s)
1467         return -1;
1468     cli_map_delete(s);
1469     if ((unsigned int)id == ctx->nmaps - 1) {
1470         ctx->nmaps--;
1471         if (!ctx->nmaps) {
1472             free(ctx->maps);
1473             ctx->maps = NULL;
1474         } else {
1475             s = cli_realloc(ctx->maps, ctx->nmaps * (sizeof(*s)));
1476             if (s)
1477                 ctx->maps = s;
1478         }
1479     }
1480     return 0;
1481 }
1482 
cli_bcapi_engine_functionality_level(struct cli_bc_ctx * ctx)1483 uint32_t cli_bcapi_engine_functionality_level(struct cli_bc_ctx *ctx)
1484 {
1485     UNUSEDPARAM(ctx);
1486     return cl_retflevel();
1487 }
1488 
cli_bcapi_engine_dconf_level(struct cli_bc_ctx * ctx)1489 uint32_t cli_bcapi_engine_dconf_level(struct cli_bc_ctx *ctx)
1490 {
1491     UNUSEDPARAM(ctx);
1492     return CL_FLEVEL_DCONF;
1493 }
1494 
cli_bcapi_engine_scan_options(struct cli_bc_ctx * ctx)1495 uint32_t cli_bcapi_engine_scan_options(struct cli_bc_ctx *ctx)
1496 {
1497     cli_ctx *cctx    = (cli_ctx *)ctx->ctx;
1498     uint32_t options = CL_SCAN_RAW;
1499 
1500     if (cctx->options->general & CL_SCAN_GENERAL_ALLMATCHES)
1501         options |= CL_SCAN_ALLMATCHES;
1502     if (cctx->options->general & CL_SCAN_GENERAL_HEURISTICS)
1503         options |= CL_SCAN_ALGORITHMIC;
1504     if (cctx->options->general & CL_SCAN_GENERAL_COLLECT_METADATA)
1505         options |= CL_SCAN_FILE_PROPERTIES;
1506     if (cctx->options->general & CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE)
1507         options |= CL_SCAN_HEURISTIC_PRECEDENCE;
1508 
1509     if (cctx->options->parse & CL_SCAN_PARSE_ARCHIVE)
1510         options |= CL_SCAN_ARCHIVE;
1511     if (cctx->options->parse & CL_SCAN_PARSE_ELF)
1512         options |= CL_SCAN_ELF;
1513     if (cctx->options->parse & CL_SCAN_PARSE_PDF)
1514         options |= CL_SCAN_PDF;
1515     if (cctx->options->parse & CL_SCAN_PARSE_SWF)
1516         options |= CL_SCAN_SWF;
1517     if (cctx->options->parse & CL_SCAN_PARSE_HWP3)
1518         options |= CL_SCAN_HWP3;
1519     if (cctx->options->parse & CL_SCAN_PARSE_XMLDOCS)
1520         options |= CL_SCAN_XMLDOCS;
1521     if (cctx->options->parse & CL_SCAN_PARSE_MAIL)
1522         options |= CL_SCAN_MAIL;
1523     if (cctx->options->parse & CL_SCAN_PARSE_OLE2)
1524         options |= CL_SCAN_OLE2;
1525     if (cctx->options->parse & CL_SCAN_PARSE_HTML)
1526         options |= CL_SCAN_HTML;
1527     if (cctx->options->parse & CL_SCAN_PARSE_PE)
1528         options |= CL_SCAN_PE;
1529     // if (cctx->options->parse & CL_SCAN_MAIL_URL)
1530     //    options |= CL_SCAN_MAILURL; /* deprecated circa 2009 */
1531 
1532     if (cctx->options->heuristic & CL_SCAN_HEURISTIC_BROKEN)
1533         options |= CL_SCAN_BLOCKBROKEN;
1534     if (cctx->options->heuristic & CL_SCAN_HEURISTIC_EXCEEDS_MAX)
1535         options |= CL_SCAN_BLOCKMAX;
1536     if (cctx->options->heuristic & CL_SCAN_HEURISTIC_PHISHING_SSL_MISMATCH)
1537         options |= CL_SCAN_PHISHING_BLOCKSSL;
1538     if (cctx->options->heuristic & CL_SCAN_HEURISTIC_PHISHING_CLOAK)
1539         options |= CL_SCAN_PHISHING_BLOCKCLOAK;
1540     if (cctx->options->heuristic & CL_SCAN_HEURISTIC_MACROS)
1541         options |= CL_SCAN_BLOCKMACROS;
1542     if ((cctx->options->heuristic & CL_SCAN_HEURISTIC_ENCRYPTED_ARCHIVE) ||
1543         (cctx->options->heuristic & CL_SCAN_HEURISTIC_ENCRYPTED_DOC))
1544         options |= CL_SCAN_BLOCKENCRYPTED;
1545     if (cctx->options->heuristic & CL_SCAN_HEURISTIC_PARTITION_INTXN)
1546         options |= CL_SCAN_PARTITION_INTXN;
1547     if (cctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED)
1548         options |= CL_SCAN_STRUCTURED;
1549     if (cctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL)
1550         options |= CL_SCAN_STRUCTURED_SSN_NORMAL;
1551     if (cctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED)
1552         options |= CL_SCAN_STRUCTURED_SSN_STRIPPED;
1553 
1554     if (cctx->options->mail & CL_SCAN_MAIL_PARTIAL_MESSAGE)
1555         options |= CL_SCAN_PARTIAL_MESSAGE;
1556 
1557     if (cctx->options->dev & CL_SCAN_DEV_COLLECT_SHA)
1558         options |= CL_SCAN_INTERNAL_COLLECT_SHA;
1559     if (cctx->options->dev & CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO)
1560         options |= CL_SCAN_PERFORMANCE_INFO;
1561 
1562     return options;
1563 }
1564 
cli_bcapi_engine_scan_options_ex(struct cli_bc_ctx * ctx,const uint8_t * option_name,uint32_t name_len)1565 uint32_t cli_bcapi_engine_scan_options_ex(struct cli_bc_ctx *ctx, const uint8_t *option_name, uint32_t name_len)
1566 {
1567     uint32_t i          = 0;
1568     uint32_t result     = 0;
1569     char *option_name_l = NULL;
1570 
1571     if (ctx == NULL || option_name == NULL || name_len == 0) {
1572         cli_warnmsg("engine_scan_options_ex: Invalid arguments!\n");
1573         goto done;
1574     }
1575 
1576     cli_ctx *cctx = (cli_ctx *)ctx->ctx;
1577     if (cctx == NULL || cctx->options == NULL) {
1578         cli_warnmsg("engine_scan_options_ex: Invalid arguments!\n");
1579         goto done;
1580     }
1581 
1582     option_name_l = malloc(name_len + 1);
1583     if (NULL == option_name_l) {
1584         cli_warnmsg("Failed to allocate memory for option name.\n");
1585         goto done;
1586     }
1587 
1588     for (i = 0; i < name_len; i++) {
1589         option_name_l[0] = tolower(option_name[i]);
1590     }
1591     option_name_l[name_len] = '\0';
1592 
1593     if (strncmp(option_name_l, "general", MIN(name_len, sizeof("general")))) {
1594         if (cli_memstr(option_name_l, name_len, "allmatch", sizeof("allmatch"))) {
1595             result = (cctx->options->general & CL_SCAN_GENERAL_ALLMATCHES) ? 1 : 0;
1596         } else if (cli_memstr(option_name_l, name_len, "collect metadata", sizeof("collect metadata"))) {
1597             result = (cctx->options->general & CL_SCAN_GENERAL_COLLECT_METADATA) ? 1 : 0;
1598         } else if (cli_memstr(option_name_l, name_len, "heuristics", sizeof("heuristics"))) {
1599             result = (cctx->options->general & CL_SCAN_GENERAL_HEURISTICS) ? 1 : 0;
1600         } else if (cli_memstr(option_name_l, name_len, "precedence", sizeof("precedence"))) {
1601             result = (cctx->options->general & CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE) ? 1 : 0;
1602         }
1603         /* else unknown option */
1604     } else if (strncmp(option_name_l, "parse", MIN(name_len, sizeof("parse")))) {
1605         if (cli_memstr(option_name_l, name_len, "archive", sizeof("archive"))) {
1606             result = (cctx->options->parse & CL_SCAN_PARSE_ARCHIVE) ? 1 : 0;
1607         } else if (cli_memstr(option_name_l, name_len, "elf", sizeof("elf"))) {
1608             result = (cctx->options->parse & CL_SCAN_PARSE_ELF) ? 1 : 0;
1609         } else if (cli_memstr(option_name_l, name_len, "pdf", sizeof("pdf"))) {
1610             result = (cctx->options->parse & CL_SCAN_PARSE_PDF) ? 1 : 0;
1611         } else if (cli_memstr(option_name_l, name_len, "swf", sizeof("swf"))) {
1612             result = (cctx->options->parse & CL_SCAN_PARSE_SWF) ? 1 : 0;
1613         } else if (cli_memstr(option_name_l, name_len, "hwp3", sizeof("hwp3"))) {
1614             result = (cctx->options->parse & CL_SCAN_PARSE_HWP3) ? 1 : 0;
1615         } else if (cli_memstr(option_name_l, name_len, "xmldocs", sizeof("xmldocs"))) {
1616             result = (cctx->options->parse & CL_SCAN_PARSE_XMLDOCS) ? 1 : 0;
1617         } else if (cli_memstr(option_name_l, name_len, "mail", sizeof("mail"))) {
1618             result = (cctx->options->parse & CL_SCAN_PARSE_MAIL) ? 1 : 0;
1619         } else if (cli_memstr(option_name_l, name_len, "ole2", sizeof("ole2"))) {
1620             result = (cctx->options->parse & CL_SCAN_PARSE_OLE2) ? 1 : 0;
1621         } else if (cli_memstr(option_name_l, name_len, "html", sizeof("html"))) {
1622             result = (cctx->options->parse & CL_SCAN_PARSE_HTML) ? 1 : 0;
1623         } else if (cli_memstr(option_name_l, name_len, "pe", sizeof("pe"))) {
1624             result = (cctx->options->parse & CL_SCAN_PARSE_PE) ? 1 : 0;
1625         }
1626         /* else unknown option */
1627     } else if (strncmp(option_name_l, "heuristic", MIN(name_len, sizeof("heuristic")))) {
1628         if (cli_memstr(option_name_l, name_len, "broken", sizeof("broken"))) {
1629             result = (cctx->options->heuristic & CL_SCAN_HEURISTIC_BROKEN) ? 1 : 0;
1630         } else if (cli_memstr(option_name_l, name_len, "exceeds max", sizeof("exceeds max"))) {
1631             result = (cctx->options->heuristic & CL_SCAN_HEURISTIC_EXCEEDS_MAX) ? 1 : 0;
1632         } else if (cli_memstr(option_name_l, name_len, "phishing ssl mismatch", sizeof("phishing ssl mismatch"))) {
1633             result = (cctx->options->heuristic & CL_SCAN_HEURISTIC_PHISHING_SSL_MISMATCH) ? 1 : 0;
1634         } else if (cli_memstr(option_name_l, name_len, "phishing cloak", sizeof("phishing cloak"))) {
1635             result = (cctx->options->heuristic & CL_SCAN_HEURISTIC_PHISHING_CLOAK) ? 1 : 0;
1636         } else if (cli_memstr(option_name_l, name_len, "macros", sizeof("macros"))) {
1637             result = (cctx->options->heuristic & CL_SCAN_HEURISTIC_MACROS) ? 1 : 0;
1638         } else if (cli_memstr(option_name_l, name_len, "encrypted archive", sizeof("encrypted archive"))) {
1639             result = (cctx->options->heuristic & CL_SCAN_HEURISTIC_ENCRYPTED_ARCHIVE) ? 1 : 0;
1640         } else if (cli_memstr(option_name_l, name_len, "encrypted doc", sizeof("encrypted doc"))) {
1641             result = (cctx->options->heuristic & CL_SCAN_HEURISTIC_ENCRYPTED_DOC) ? 1 : 0;
1642         } else if (cli_memstr(option_name_l, name_len, "partition intersection", sizeof("partition intersection"))) {
1643             result = (cctx->options->heuristic & CL_SCAN_HEURISTIC_PARTITION_INTXN) ? 1 : 0;
1644         } else if (cli_memstr(option_name_l, name_len, "structured", sizeof("structured"))) {
1645             result = (cctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED) ? 1 : 0;
1646         } else if (cli_memstr(option_name_l, name_len, "structured ssn normal", sizeof("structured ssn normal"))) {
1647             result = (cctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED_SSN_NORMAL) ? 1 : 0;
1648         } else if (cli_memstr(option_name_l, name_len, "structured ssn stripped", sizeof("structured ssn stripped"))) {
1649             result = (cctx->options->heuristic & CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED) ? 1 : 0;
1650         }
1651         /* else unknown option */
1652     } else if (strncmp(option_name_l, "mail", MIN(name_len, sizeof("mail")))) {
1653         if (cli_memstr(option_name_l, name_len, "partial message", sizeof("partial message"))) {
1654             result = (cctx->options->mail & CL_SCAN_MAIL_PARTIAL_MESSAGE) ? 1 : 0;
1655         }
1656         /* else unknown option */
1657     } else if (strncmp(option_name_l, "dev", MIN(name_len, sizeof("dev")))) {
1658         if (cli_memstr(option_name_l, name_len, "collect sha", sizeof("collect sha"))) {
1659             result = (cctx->options->dev & CL_SCAN_DEV_COLLECT_SHA) ? 1 : 0;
1660         } else if (cli_memstr(option_name_l, name_len, "collect performance info", sizeof("collect performance info"))) {
1661             result = (cctx->options->dev & CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO) ? 1 : 0;
1662         }
1663         /* else unknown option */
1664     }
1665     /* else unknown option */
1666 
1667 done:
1668 
1669     if (NULL != option_name_l)
1670         free(option_name_l);
1671 
1672     return result;
1673 }
1674 
cli_bcapi_engine_db_options(struct cli_bc_ctx * ctx)1675 uint32_t cli_bcapi_engine_db_options(struct cli_bc_ctx *ctx)
1676 {
1677     cli_ctx *cctx = (cli_ctx *)ctx->ctx;
1678     return cctx->engine->dboptions;
1679 }
1680 
cli_bcapi_extract_set_container(struct cli_bc_ctx * ctx,uint32_t ftype)1681 int32_t cli_bcapi_extract_set_container(struct cli_bc_ctx *ctx, uint32_t ftype)
1682 {
1683     if (ftype > CL_TYPE_IGNORED)
1684         return -1;
1685     ctx->containertype = ftype;
1686     return 0;
1687 }
1688 
cli_bcapi_input_switch(struct cli_bc_ctx * ctx,int32_t extracted_file)1689 int32_t cli_bcapi_input_switch(struct cli_bc_ctx *ctx, int32_t extracted_file)
1690 {
1691     fmap_t *map;
1692     if (0 == extracted_file) {
1693         /*
1694          * Set input back to original fmap.
1695          */
1696         if (0 == ctx->extracted_file_input) {
1697             /* Input already set to original fmap, nothing to do. */
1698             return 0;
1699         }
1700 
1701         /* Free the fmap used for the extracted file */
1702         funmap(ctx->fmap);
1703 
1704         /* Restore pointer to original fmap */
1705         cli_bytecode_context_setfile(ctx, ctx->save_map);
1706         ctx->save_map = NULL;
1707 
1708         ctx->extracted_file_input = 0;
1709         cli_dbgmsg("bytecode api: input switched back to main file\n");
1710         return 0;
1711     } else {
1712         /*
1713          * Set input to extracted file.
1714          */
1715         if (1 == ctx->extracted_file_input) {
1716             /* Input already set to extracted file, nothing to do. */
1717             return 0;
1718         }
1719 
1720         if (ctx->outfd < 0) {
1721             /* no valid fd to switch to use for fmap */
1722             return -1;
1723         }
1724 
1725         /* Create fmap for the extracted file */
1726         map = fmap(ctx->outfd, 0, 0, NULL);
1727         if (!map) {
1728             cli_warnmsg("can't mmap() extracted temporary file %s\n", ctx->tempfile);
1729             return -1;
1730         }
1731 
1732         /* Save off pointer to original fmap */
1733         ctx->save_map = ctx->fmap;
1734         cli_bytecode_context_setfile(ctx, map);
1735 
1736         ctx->extracted_file_input = 1;
1737         cli_dbgmsg("bytecode api: input switched to extracted file\n");
1738         return 0;
1739     }
1740 }
1741 
cli_bcapi_get_environment(struct cli_bc_ctx * ctx,struct cli_environment * env,uint32_t len)1742 uint32_t cli_bcapi_get_environment(struct cli_bc_ctx *ctx, struct cli_environment *env, uint32_t len)
1743 {
1744     if (len > sizeof(*env)) {
1745         cli_dbgmsg("cli_bcapi_get_environment len %u > %lu\n", len, (unsigned long)sizeof(*env));
1746         return -1;
1747     }
1748     memcpy(env, ctx->env, len);
1749     return 0;
1750 }
1751 
cli_bcapi_disable_bytecode_if(struct cli_bc_ctx * ctx,const int8_t * reason,uint32_t len,uint32_t cond)1752 uint32_t cli_bcapi_disable_bytecode_if(struct cli_bc_ctx *ctx, const int8_t *reason, uint32_t len, uint32_t cond)
1753 {
1754     UNUSEDPARAM(len);
1755     if (ctx->bc->kind != BC_STARTUP) {
1756         cli_dbgmsg("Bytecode must be BC_STARTUP to call disable_bytecode_if\n");
1757         return -1;
1758     }
1759     if (!cond)
1760         return ctx->bytecode_disable_status;
1761     if (*reason == '^')
1762         cli_warnmsg("Bytecode: disabling completely because %s\n", reason + 1);
1763     else
1764         cli_dbgmsg("Bytecode: disabling completely because %s\n", reason);
1765     ctx->bytecode_disable_status = 2;
1766     return ctx->bytecode_disable_status;
1767 }
1768 
cli_bcapi_disable_jit_if(struct cli_bc_ctx * ctx,const int8_t * reason,uint32_t len,uint32_t cond)1769 uint32_t cli_bcapi_disable_jit_if(struct cli_bc_ctx *ctx, const int8_t *reason, uint32_t len, uint32_t cond)
1770 {
1771     UNUSEDPARAM(len);
1772     if (ctx->bc->kind != BC_STARTUP) {
1773         cli_dbgmsg("Bytecode must be BC_STARTUP to call disable_jit_if\n");
1774         return -1;
1775     }
1776     if (!cond)
1777         return ctx->bytecode_disable_status;
1778     if (*reason == '^')
1779         cli_warnmsg("Bytecode: disabling JIT because %s\n", reason + 1);
1780     else
1781         cli_dbgmsg("Bytecode: disabling JIT because %s\n", reason);
1782     if (ctx->bytecode_disable_status != 2) /* no reenabling */
1783         ctx->bytecode_disable_status = 1;
1784     return ctx->bytecode_disable_status;
1785 }
1786 
cli_bcapi_version_compare(struct cli_bc_ctx * ctx,const uint8_t * lhs,uint32_t lhs_len,const uint8_t * rhs,uint32_t rhs_len)1787 int32_t cli_bcapi_version_compare(struct cli_bc_ctx *ctx, const uint8_t *lhs, uint32_t lhs_len,
1788                                   const uint8_t *rhs, uint32_t rhs_len)
1789 {
1790     unsigned i = 0, j = 0;
1791     unsigned long li = 0, ri = 0;
1792     UNUSEDPARAM(ctx);
1793     do {
1794         while (i < lhs_len && j < rhs_len && lhs[i] == rhs[j] &&
1795                !isdigit(lhs[i]) && !isdigit(rhs[j])) {
1796             i++;
1797             j++;
1798         }
1799         if (i == lhs_len && j == rhs_len)
1800             return 0;
1801         if (i == lhs_len)
1802             return -1;
1803         if (j == rhs_len)
1804             return 1;
1805         if (!isdigit(lhs[i]) || !isdigit(rhs[j]))
1806             return lhs[i] < rhs[j] ? -1 : 1;
1807         while (isdigit(lhs[i]) && i < lhs_len)
1808             li = 10 * li + (lhs[i++] - '0');
1809         while (isdigit(rhs[j]) && j < rhs_len)
1810             ri = 10 * ri + (rhs[j++] - '0');
1811         if (li < ri)
1812             return -1;
1813         if (li > ri)
1814             return 1;
1815     } while (1);
1816 }
1817 
check_bits(uint32_t query,uint32_t value,uint8_t shift,uint8_t mask)1818 static int check_bits(uint32_t query, uint32_t value, uint8_t shift, uint8_t mask)
1819 {
1820     uint8_t q = (query >> shift) & mask;
1821     uint8_t v = (value >> shift) & mask;
1822     /* q == mask -> ANY */
1823     if (q == v || q == mask)
1824         return 1;
1825     return 0;
1826 }
1827 
cli_bcapi_check_platform(struct cli_bc_ctx * ctx,uint32_t a,uint32_t b,uint32_t c)1828 uint32_t cli_bcapi_check_platform(struct cli_bc_ctx *ctx, uint32_t a, uint32_t b, uint32_t c)
1829 {
1830     unsigned ret =
1831         check_bits(a, ctx->env->platform_id_a, 24, 0xff) &&
1832         check_bits(a, ctx->env->platform_id_a, 20, 0xf) &&
1833         check_bits(a, ctx->env->platform_id_a, 16, 0xf) &&
1834         check_bits(a, ctx->env->platform_id_a, 8, 0xff) &&
1835         check_bits(a, ctx->env->platform_id_a, 0, 0xff) &&
1836         check_bits(b, ctx->env->platform_id_b, 28, 0xf) &&
1837         check_bits(b, ctx->env->platform_id_b, 24, 0xf) &&
1838         check_bits(b, ctx->env->platform_id_b, 16, 0xff) &&
1839         check_bits(b, ctx->env->platform_id_b, 8, 0xff) &&
1840         check_bits(b, ctx->env->platform_id_b, 0, 0xff) &&
1841         check_bits(c, ctx->env->platform_id_c, 24, 0xff) &&
1842         check_bits(c, ctx->env->platform_id_c, 16, 0xff) &&
1843         check_bits(c, ctx->env->platform_id_c, 8, 0xff) &&
1844         check_bits(c, ctx->env->platform_id_c, 0, 0xff);
1845     if (ret) {
1846         cli_dbgmsg("check_platform(0x%08x,0x%08x,0x%08x) = match\n", a, b, c);
1847     }
1848     return ret;
1849 }
1850 
cli_bytecode_context_setpdf(struct cli_bc_ctx * ctx,unsigned phase,unsigned nobjs,struct pdf_obj ** objs,uint32_t * pdf_flags,uint32_t pdfsize,uint32_t pdfstartoff)1851 int cli_bytecode_context_setpdf(struct cli_bc_ctx *ctx, unsigned phase,
1852                                 unsigned nobjs,
1853                                 struct pdf_obj **objs, uint32_t *pdf_flags,
1854                                 uint32_t pdfsize, uint32_t pdfstartoff)
1855 {
1856     ctx->pdf_nobjs    = nobjs;
1857     ctx->pdf_objs     = objs;
1858     ctx->pdf_flags    = pdf_flags;
1859     ctx->pdf_size     = pdfsize;
1860     ctx->pdf_startoff = pdfstartoff;
1861     ctx->pdf_phase    = phase;
1862     return 0;
1863 }
1864 
cli_bcapi_pdf_get_obj_num(struct cli_bc_ctx * ctx)1865 int32_t cli_bcapi_pdf_get_obj_num(struct cli_bc_ctx *ctx)
1866 {
1867     if (!ctx->pdf_phase)
1868         return -1;
1869     return ctx->pdf_nobjs;
1870 }
1871 
cli_bcapi_pdf_get_flags(struct cli_bc_ctx * ctx)1872 int32_t cli_bcapi_pdf_get_flags(struct cli_bc_ctx *ctx)
1873 {
1874     if (!ctx->pdf_phase)
1875         return -1;
1876     return *ctx->pdf_flags;
1877 }
1878 
cli_bcapi_pdf_set_flags(struct cli_bc_ctx * ctx,int32_t flags)1879 int32_t cli_bcapi_pdf_set_flags(struct cli_bc_ctx *ctx, int32_t flags)
1880 {
1881     if (!ctx->pdf_phase)
1882         return -1;
1883     cli_dbgmsg("cli_pdf: bytecode set_flags %08x -> %08x\n",
1884                *ctx->pdf_flags,
1885                flags);
1886     *ctx->pdf_flags = flags;
1887     return 0;
1888 }
1889 
cli_bcapi_pdf_lookupobj(struct cli_bc_ctx * ctx,uint32_t objid)1890 int32_t cli_bcapi_pdf_lookupobj(struct cli_bc_ctx *ctx, uint32_t objid)
1891 {
1892     unsigned i;
1893     if (!ctx->pdf_phase)
1894         return -1;
1895     for (i = 0; i < ctx->pdf_nobjs; i++) {
1896         if (ctx->pdf_objs[i]->id == objid)
1897             return i;
1898     }
1899     return -1;
1900 }
1901 
cli_bcapi_pdf_getobjsize(struct cli_bc_ctx * ctx,int32_t objidx)1902 uint32_t cli_bcapi_pdf_getobjsize(struct cli_bc_ctx *ctx, int32_t objidx)
1903 {
1904     if (!ctx->pdf_phase ||
1905         (uint32_t)objidx >= ctx->pdf_nobjs ||
1906         ctx->pdf_phase == PDF_PHASE_POSTDUMP /* map is obj itself, no access to pdf anymore */
1907     )
1908         return 0;
1909     if ((uint32_t)(objidx + 1) == ctx->pdf_nobjs)
1910         return ctx->pdf_size - ctx->pdf_objs[objidx]->start;
1911     return ctx->pdf_objs[objidx + 1]->start - ctx->pdf_objs[objidx]->start - 4;
1912 }
1913 
cli_bcapi_pdf_getobj(struct cli_bc_ctx * ctx,int32_t objidx,uint32_t amount)1914 const uint8_t *cli_bcapi_pdf_getobj(struct cli_bc_ctx *ctx, int32_t objidx, uint32_t amount)
1915 {
1916     uint32_t size = cli_bcapi_pdf_getobjsize(ctx, objidx);
1917     if (amount > size)
1918         return NULL;
1919     return fmap_need_off(ctx->fmap, ctx->pdf_objs[objidx]->start, amount);
1920 }
1921 
cli_bcapi_pdf_getobjid(struct cli_bc_ctx * ctx,int32_t objidx)1922 int32_t cli_bcapi_pdf_getobjid(struct cli_bc_ctx *ctx, int32_t objidx)
1923 {
1924     if (!ctx->pdf_phase ||
1925         (uint32_t)objidx >= ctx->pdf_nobjs)
1926         return -1;
1927     return ctx->pdf_objs[objidx]->id;
1928 }
1929 
cli_bcapi_pdf_getobjflags(struct cli_bc_ctx * ctx,int32_t objidx)1930 int32_t cli_bcapi_pdf_getobjflags(struct cli_bc_ctx *ctx, int32_t objidx)
1931 {
1932     if (!ctx->pdf_phase ||
1933         (uint32_t)objidx >= ctx->pdf_nobjs)
1934         return -1;
1935     return ctx->pdf_objs[objidx]->flags;
1936 }
1937 
cli_bcapi_pdf_setobjflags(struct cli_bc_ctx * ctx,int32_t objidx,int32_t flags)1938 int32_t cli_bcapi_pdf_setobjflags(struct cli_bc_ctx *ctx, int32_t objidx, int32_t flags)
1939 {
1940     if (!ctx->pdf_phase ||
1941         (uint32_t)objidx >= ctx->pdf_nobjs)
1942         return -1;
1943     cli_dbgmsg("cli_pdf: bytecode setobjflags %08x -> %08x\n",
1944                ctx->pdf_objs[objidx]->flags,
1945                flags);
1946     ctx->pdf_objs[objidx]->flags = flags;
1947     return 0;
1948 }
1949 
cli_bcapi_pdf_get_offset(struct cli_bc_ctx * ctx,int32_t objidx)1950 int32_t cli_bcapi_pdf_get_offset(struct cli_bc_ctx *ctx, int32_t objidx)
1951 {
1952     if (!ctx->pdf_phase ||
1953         (uint32_t)objidx >= ctx->pdf_nobjs)
1954         return -1;
1955     return ctx->pdf_startoff + ctx->pdf_objs[objidx]->start;
1956 }
1957 
cli_bcapi_pdf_get_phase(struct cli_bc_ctx * ctx)1958 int32_t cli_bcapi_pdf_get_phase(struct cli_bc_ctx *ctx)
1959 {
1960     return ctx->pdf_phase;
1961 }
1962 
cli_bcapi_pdf_get_dumpedobjid(struct cli_bc_ctx * ctx)1963 int32_t cli_bcapi_pdf_get_dumpedobjid(struct cli_bc_ctx *ctx)
1964 {
1965     if (ctx->pdf_phase != PDF_PHASE_POSTDUMP)
1966         return -1;
1967     return ctx->pdf_dumpedid;
1968 }
1969 
cli_bcapi_running_on_jit(struct cli_bc_ctx * ctx)1970 int32_t cli_bcapi_running_on_jit(struct cli_bc_ctx *ctx)
1971 {
1972     ctx->no_diff = 1;
1973     return ctx->on_jit;
1974 }
1975 
cli_bcapi_get_file_reliability(struct cli_bc_ctx * ctx)1976 int32_t cli_bcapi_get_file_reliability(struct cli_bc_ctx *ctx)
1977 {
1978     cli_ctx *cctx = (cli_ctx *)ctx->ctx;
1979     return cctx ? cctx->corrupted_input : 3;
1980 }
1981 
cli_bcapi_json_is_active(struct cli_bc_ctx * ctx)1982 int32_t cli_bcapi_json_is_active(struct cli_bc_ctx *ctx)
1983 {
1984 #if HAVE_JSON
1985     cli_ctx *cctx = (cli_ctx *)ctx->ctx;
1986     if (cctx->properties != NULL) {
1987         return 1;
1988     }
1989 #else
1990     UNUSEDPARAM(ctx);
1991     cli_dbgmsg("bytecode api: libjson is not enabled!\n");
1992 #endif
1993     return 0;
1994 }
1995 
cli_bcapi_json_objs_init(struct cli_bc_ctx * ctx)1996 static int32_t cli_bcapi_json_objs_init(struct cli_bc_ctx *ctx)
1997 {
1998 #if HAVE_JSON
1999     unsigned n = ctx->njsonobjs + 1;
2000     json_object **j, **jobjs = (json_object **)(ctx->jsonobjs);
2001     cli_ctx *cctx = (cli_ctx *)ctx->ctx;
2002 
2003     j = cli_realloc(jobjs, sizeof(json_object *) * n);
2004     if (!j) { /* memory allocation failure */
2005         cli_event_error_oom(EV, 0);
2006         return -1;
2007     }
2008     ctx->jsonobjs  = (void **)j;
2009     ctx->njsonobjs = n;
2010     j[n - 1]       = cctx->properties;
2011 
2012     return 0;
2013 #else
2014     UNUSEDPARAM(ctx);
2015     return -1;
2016 #endif
2017 }
2018 
2019 #define INIT_JSON_OBJS(ctx)                  \
2020     if (!cli_bcapi_json_is_active(ctx))      \
2021         return -1;                           \
2022     if (ctx->njsonobjs == 0) {               \
2023         if (cli_bcapi_json_objs_init(ctx)) { \
2024             return -1;                       \
2025         }                                    \
2026     }
2027 
cli_bcapi_json_get_object(struct cli_bc_ctx * ctx,const int8_t * name,int32_t name_len,int32_t objid)2028 int32_t cli_bcapi_json_get_object(struct cli_bc_ctx *ctx, const int8_t *name, int32_t name_len, int32_t objid)
2029 {
2030 #if HAVE_JSON
2031     unsigned n;
2032     json_object **j, *jobj, **jobjs;
2033     char *namep;
2034 
2035     INIT_JSON_OBJS(ctx);
2036     jobjs = ((json_object **)(ctx->jsonobjs));
2037     if (objid < 0 || (unsigned int)objid >= ctx->njsonobjs) {
2038         cli_dbgmsg("bytecode api[json_get_object]: invalid json objid requested\n");
2039         return -1;
2040     }
2041 
2042     if (!name || name_len < 0) {
2043         cli_dbgmsg("bytecode api[json_get_object]: unnamed object queried\n");
2044         return -1;
2045     }
2046 
2047     n    = ctx->njsonobjs + 1;
2048     jobj = jobjs[objid];
2049     if (!jobj) /* shouldn't be possible */
2050         return -1;
2051     namep = (char *)cli_malloc(sizeof(char) * (name_len + 1));
2052     if (!namep)
2053         return -1;
2054     strncpy(namep, (char *)name, name_len);
2055     namep[name_len] = '\0';
2056 
2057     if (!json_object_object_get_ex(jobj, namep, &jobj)) { /* object not found */
2058         free(namep);
2059         return 0;
2060     }
2061 
2062     j = cli_realloc(jobjs, sizeof(json_object *) * n);
2063     if (!j) { /* memory allocation failure */
2064         free(namep);
2065         cli_event_error_oom(EV, 0);
2066         return -1;
2067     }
2068     ctx->jsonobjs  = (void **)j;
2069     ctx->njsonobjs = n;
2070     j[n - 1]       = jobj;
2071 
2072     cli_dbgmsg("bytecode api[json_get_object]: assigned %s => ID %d\n", namep, n - 1);
2073     free(namep);
2074     return n - 1;
2075 #else
2076     UNUSEDPARAM(ctx);
2077     UNUSEDPARAM(name);
2078     UNUSEDPARAM(name_len);
2079     UNUSEDPARAM(objid);
2080     cli_dbgmsg("bytecode api: libjson is not enabled!\n");
2081     return -1;
2082 #endif
2083 }
2084 
cli_bcapi_json_get_type(struct cli_bc_ctx * ctx,int32_t objid)2085 int32_t cli_bcapi_json_get_type(struct cli_bc_ctx *ctx, int32_t objid)
2086 {
2087 #if HAVE_JSON
2088     enum json_type type;
2089     json_object **jobjs;
2090 
2091     INIT_JSON_OBJS(ctx);
2092     jobjs = ((json_object **)(ctx->jsonobjs));
2093     if (objid < 0 || (unsigned int)objid >= ctx->njsonobjs) {
2094         cli_dbgmsg("bytecode api[json_get_type]: invalid json objid requested\n");
2095         return -1;
2096     }
2097 
2098     type = json_object_get_type(jobjs[objid]);
2099     switch (type) {
2100         case json_type_null:
2101             return JSON_TYPE_NULL;
2102         case json_type_boolean:
2103             return JSON_TYPE_BOOLEAN;
2104         case json_type_double:
2105             return JSON_TYPE_DOUBLE;
2106         case json_type_int:
2107             return JSON_TYPE_INT;
2108         case json_type_object:
2109             return JSON_TYPE_OBJECT;
2110         case json_type_array:
2111             return JSON_TYPE_ARRAY;
2112         case json_type_string:
2113             return JSON_TYPE_STRING;
2114         default:
2115             cli_dbgmsg("bytecode api[json_get_type]: unrecognized json type %d\n", type);
2116     }
2117 
2118 #else
2119     UNUSEDPARAM(ctx);
2120     UNUSEDPARAM(objid);
2121     cli_dbgmsg("bytecode api: libjson is not enabled!\n");
2122 #endif
2123     return -1;
2124 }
2125 
cli_bcapi_json_get_array_length(struct cli_bc_ctx * ctx,int32_t objid)2126 int32_t cli_bcapi_json_get_array_length(struct cli_bc_ctx *ctx, int32_t objid)
2127 {
2128 #if HAVE_JSON
2129     enum json_type type;
2130     json_object **jobjs;
2131 
2132     INIT_JSON_OBJS(ctx);
2133     jobjs = (json_object **)(ctx->jsonobjs);
2134     if (objid < 0 || (unsigned int)objid >= ctx->njsonobjs) {
2135         cli_dbgmsg("bytecode api[json_array_get_length]: invalid json objid requested\n");
2136         return -1;
2137     }
2138 
2139     type = json_object_get_type(jobjs[objid]);
2140     if (type != json_type_array) {
2141         return -2; /* error code for not an array */
2142     }
2143 
2144     return json_object_array_length(jobjs[objid]);
2145 #else
2146     UNUSEDPARAM(ctx);
2147     UNUSEDPARAM(objid);
2148     cli_dbgmsg("bytecode api: libjson is not enabled!\n");
2149     return -1;
2150 #endif
2151 }
2152 
cli_bcapi_json_get_array_idx(struct cli_bc_ctx * ctx,int32_t idx,int32_t objid)2153 int32_t cli_bcapi_json_get_array_idx(struct cli_bc_ctx *ctx, int32_t idx, int32_t objid)
2154 {
2155 #if HAVE_JSON
2156     enum json_type type;
2157     unsigned n;
2158     int length;
2159     json_object **j, *jarr = NULL, *jobj = NULL, **jobjs;
2160 
2161     INIT_JSON_OBJS(ctx);
2162     jobjs = (json_object **)(ctx->jsonobjs);
2163     if (objid < 0 || (unsigned int)objid >= ctx->njsonobjs) {
2164         cli_dbgmsg("bytecode api[json_array_get_idx]: invalid json objid requested\n");
2165         return -1;
2166     }
2167 
2168     jarr = jobjs[objid];
2169     if (!jarr) /* shouldn't be possible */
2170         return -1;
2171 
2172     type = json_object_get_type(jarr);
2173     if (type != json_type_array) {
2174         return -2; /* error code for not an array */
2175     }
2176 
2177     length = json_object_array_length(jarr);
2178     if (idx >= 0 && idx < length) {
2179         n = ctx->njsonobjs + 1;
2180 
2181         jobj = json_object_array_get_idx(jarr, idx);
2182         if (!jobj) { /* object not found */
2183             return 0;
2184         }
2185 
2186         j = cli_realloc(jobjs, sizeof(json_object *) * n);
2187         if (!j) { /* memory allocation failure */
2188             cli_event_error_oom(EV, 0);
2189             return -1;
2190         }
2191         ctx->jsonobjs  = (void **)j;
2192         ctx->njsonobjs = n;
2193         j[n - 1]       = jobj;
2194 
2195         cli_dbgmsg("bytecode api[json_array_get_idx]: assigned array @ %d => ID %d\n", idx, n - 1);
2196         return n - 1;
2197     }
2198 
2199     return 0;
2200 #else
2201     UNUSEDPARAM(ctx);
2202     UNUSEDPARAM(idx);
2203     UNUSEDPARAM(objid);
2204     cli_dbgmsg("bytecode api: libjson is not enabled!\n");
2205     return -1;
2206 #endif
2207 }
2208 
cli_bcapi_json_get_string_length(struct cli_bc_ctx * ctx,int32_t objid)2209 int32_t cli_bcapi_json_get_string_length(struct cli_bc_ctx *ctx, int32_t objid)
2210 {
2211 #if HAVE_JSON
2212     enum json_type type;
2213     json_object *jobj, **jobjs;
2214     int32_t len;
2215     const char *jstr;
2216 
2217     INIT_JSON_OBJS(ctx);
2218     jobjs = (json_object **)(ctx->jsonobjs);
2219     if (objid < 0 || (unsigned int)objid >= ctx->njsonobjs) {
2220         cli_dbgmsg("bytecode api[json_get_string_length]: invalid json objid requested\n");
2221         return -1;
2222     }
2223 
2224     jobj = jobjs[objid];
2225     if (!jobj) /* shouldn't be possible */
2226         return -1;
2227 
2228     type = json_object_get_type(jobj);
2229     if (type != json_type_string) {
2230         return -2; /* error code for not an array */
2231     }
2232 
2233     //len = json_object_get_string_len(jobj); /* not in JSON <0.10 */
2234     jstr = json_object_get_string(jobj);
2235     len  = strlen(jstr);
2236 
2237     return len;
2238 #else
2239     UNUSEDPARAM(ctx);
2240     UNUSEDPARAM(objid);
2241     cli_dbgmsg("bytecode api: libjson is not enabled!\n");
2242     return -1;
2243 #endif
2244 }
2245 
cli_bcapi_json_get_string(struct cli_bc_ctx * ctx,int8_t * str,int32_t str_len,int32_t objid)2246 int32_t cli_bcapi_json_get_string(struct cli_bc_ctx *ctx, int8_t *str, int32_t str_len, int32_t objid)
2247 {
2248 #if HAVE_JSON
2249     enum json_type type;
2250     json_object *jobj, **jobjs;
2251     int32_t len;
2252     const char *jstr;
2253 
2254     INIT_JSON_OBJS(ctx);
2255     jobjs = (json_object **)(ctx->jsonobjs);
2256     if (objid < 0 || (unsigned int)objid >= ctx->njsonobjs) {
2257         cli_dbgmsg("bytecode api[json_get_string]: invalid json objid requested\n");
2258         return -1;
2259     }
2260 
2261     jobj = jobjs[objid];
2262     if (!jobj) /* shouldn't be possible */
2263         return -1;
2264 
2265     type = json_object_get_type(jobj);
2266     if (type != json_type_string) {
2267         return -2; /* error code for not an array */
2268     }
2269 
2270     //len = json_object_get_string_len(jobj); /* not in JSON <0.10 */
2271     jstr = json_object_get_string(jobj);
2272     len  = strlen(jstr);
2273 
2274     if (len + 1 > str_len) {
2275         /* limit on str-len */
2276         strncpy((char *)str, jstr, str_len - 1);
2277         str[str_len - 1] = '\0';
2278         return str_len;
2279     } else {
2280         /* limit on len+1 */
2281         strncpy((char *)str, jstr, len);
2282         str[len] = '\0';
2283         return len + 1;
2284     }
2285 #else
2286     UNUSEDPARAM(ctx);
2287     UNUSEDPARAM(str);
2288     UNUSEDPARAM(str_len);
2289     UNUSEDPARAM(objid);
2290     cli_dbgmsg("bytecode api: libjson is not enabled!\n");
2291     return -1;
2292 #endif
2293 }
2294 
cli_bcapi_json_get_boolean(struct cli_bc_ctx * ctx,int32_t objid)2295 int32_t cli_bcapi_json_get_boolean(struct cli_bc_ctx *ctx, int32_t objid)
2296 {
2297 #if HAVE_JSON
2298     json_object *jobj, **jobjs;
2299 
2300     INIT_JSON_OBJS(ctx);
2301     jobjs = (json_object **)(ctx->jsonobjs);
2302     if (objid < 0 || (unsigned int)objid >= ctx->njsonobjs) {
2303         cli_dbgmsg("bytecode api[json_get_boolean]: invalid json objid requested\n");
2304         return -1;
2305     }
2306 
2307     jobj = jobjs[objid];
2308     return json_object_get_boolean(jobj);
2309 #else
2310     UNUSEDPARAM(ctx);
2311     UNUSEDPARAM(objid);
2312     cli_dbgmsg("bytecode api: libjson is not enabled!\n");
2313     return 0;
2314 #endif
2315 }
2316 
cli_bcapi_json_get_int(struct cli_bc_ctx * ctx,int32_t objid)2317 int32_t cli_bcapi_json_get_int(struct cli_bc_ctx *ctx, int32_t objid)
2318 {
2319 #if HAVE_JSON
2320     json_object *jobj, **jobjs;
2321 
2322     INIT_JSON_OBJS(ctx);
2323     jobjs = (json_object **)(ctx->jsonobjs);
2324     if (objid < 0 || (unsigned int)objid >= ctx->njsonobjs) {
2325         cli_dbgmsg("bytecode api[json_get_int]: invalid json objid requested\n");
2326         return -1;
2327     }
2328 
2329     jobj = jobjs[objid];
2330     return json_object_get_int(jobj);
2331 #else
2332     UNUSEDPARAM(ctx);
2333     UNUSEDPARAM(objid);
2334     cli_dbgmsg("bytecode api: libjson is not enabled!\n");
2335     return 0;
2336 #endif
2337 }
2338 
2339 //int64_t cli_bcapi_json_get_int64(struct cli_bc_ctx *ctx, int32_t objid);
2340 //double cli_bcapi_json_get_double(struct cli_bc_ctx *ctx, int32_t objid);
2341