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