diff --git a/common/optparser.c b/common/optparser.c index 10398cb0f5..c13d56ed0e 100644 --- a/common/optparser.c +++ b/common/optparser.c @@ -118,7 +118,7 @@ const struct clam_option __clam_options[] = { {NULL, "verbose", 'v', CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_FRESHCLAM | OPT_CLAMSCAN | OPT_CLAMDSCAN | OPT_SIGTOOL | OPT_CLAMONACC, "", ""}, {NULL, "dumpcerts", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN, "Dump authenticode certificate chain.", ""}, {NULL, "quiet", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_FRESHCLAM | OPT_CLAMSCAN | OPT_CLAMDSCAN | OPT_SIGTOOL | OPT_CLAMONACC, "", ""}, - {NULL, "leave-temps", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN, "", ""}, + {NULL, "leave-temps", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN | OPT_SIGTOOL, "", ""}, {NULL, "no-warnings", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_FRESHCLAM, "", ""}, {NULL, "show-progress", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_FRESHCLAM, "", ""}, {NULL, "stdout", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_FRESHCLAM | OPT_CLAMSCAN | OPT_CLAMDSCAN | OPT_SIGTOOL | OPT_CLAMONACC, "", ""}, diff --git a/docs/man/sigtool.1.in b/docs/man/sigtool.1.in index 1bc5acdfc3..990349393d 100644 --- a/docs/man/sigtool.1.in +++ b/docs/man/sigtool.1.in @@ -114,6 +114,12 @@ Test all signatures from DATABASE against TARGET_FILE. This option will only giv .TP \fB\-\-print\-certs=FILE\fR Print Authenticode details from a PE file. +.TP +\fB\-\-tempdir=DIRECTORY\fR +Create temporary files in DIRECTORY. Directory must be writable for the user running sigtool. +.TP +\fB\-\-leave\-temps\fR +Do not remove temporary files. .SH "ENVIRONMENT VARIABLES" .LP diff --git a/libclamav/clamav.h b/libclamav/clamav.h index d0e707ed9f..a3b187ebbe 100644 --- a/libclamav/clamav.h +++ b/libclamav/clamav.h @@ -814,6 +814,27 @@ typedef int (*clcb_file_props)(const char *j_propstr, int rc, void *cbdata); */ extern void cl_engine_set_clcb_file_props(struct cl_engine *engine, clcb_file_props callback); +/** + * @brief generic data callback function. + * + * Callback handler prototype for callbacks passing back data and application context. + * + * @param data A pointer to some data. Should be treated as read-only and may be freed after callback. + * @param data_len The length of data. + * @param cbdata Opaque application provided data. + */ +typedef int (*clcb_generic_data)(const unsigned char *const data, const size_t data_len, void *cbdata); + +/** + * @brief Set a custom VBA macro callback function. + * + * Caution: changing options for an engine that is in-use is not thread-safe! + * + * @param engine The initialized scanning engine. + * @param callback The callback function pointer. + */ +extern void cl_engine_set_clcb_vba(struct cl_engine *engine, clcb_generic_data callback); + /* ---------------------------------------------------------------------------- * Statistics/telemetry gathering callbacks. * diff --git a/libclamav/libclamav.map b/libclamav/libclamav.map index e6d5b07d22..6fe8ce253c 100644 --- a/libclamav/libclamav.map +++ b/libclamav/libclamav.map @@ -74,6 +74,7 @@ CLAMAV_1.0.0 { CLAMAV_1.1.0 { global: cl_cvdgetage; + cl_engine_set_clcb_vba; } CLAMAV_1.0.0; CLAMAV_PRIVATE { global: diff --git a/libclamav/others.c b/libclamav/others.c index f14d633613..5eeba0a074 100644 --- a/libclamav/others.c +++ b/libclamav/others.c @@ -1927,6 +1927,11 @@ void cl_engine_set_clcb_file_props(struct cl_engine *engine, clcb_file_props cal engine->cb_file_props = callback; } +void cl_engine_set_clcb_vba(struct cl_engine *engine, clcb_generic_data callback) +{ + engine->cb_vba = callback; +} + uint8_t cli_get_debug_flag() { return cli_debug_flag; diff --git a/libclamav/others.h b/libclamav/others.h index d75e37dcd3..1dbe67329d 100644 --- a/libclamav/others.h +++ b/libclamav/others.h @@ -416,6 +416,7 @@ struct cl_engine { void *cb_sigload_ctx; clcb_hash cb_hash; clcb_meta cb_meta; + clcb_generic_data cb_vba; clcb_file_props cb_file_props; clcb_progress cb_sigload_progress; void *cb_sigload_progress_ctx; diff --git a/libclamav/vba_extract.c b/libclamav/vba_extract.c index 910d9a486b..5c35dd3090 100644 --- a/libclamav/vba_extract.c +++ b/libclamav/vba_extract.c @@ -1259,10 +1259,20 @@ cl_error_t cli_vba_readdir_new(cli_ctx *ctx, const char *dir, struct uniq *U, co module_data_utf8_size = vba_normalize(module_data_utf8, module_data_utf8_size); CLI_WRITEN(module_data_utf8, module_data_utf8_size); + + if (NULL != ctx->engine->cb_vba) { + ctx->engine->cb_vba(module_data_utf8, module_data_utf8_size, ctx->cb_ctx); + } + module_stream_found = 1; free(module_data_utf8); module_data_utf8 = NULL; } else { + /*If normalization didn't work, fall back to the pre-normalized data.*/ + if (NULL != ctx->engine->cb_vba) { + ctx->engine->cb_vba(module_data, module_data_size, ctx->cb_ctx); + } + CLI_WRITEN("\n\n", 30); cli_dbgmsg("cli_vba_readdir_new: Failed to decode VBA module content from codepage %" PRIu16 " to UTF8\n", codepage); } diff --git a/sigtool/sigtool.c b/sigtool/sigtool.c index 6f5ef8c1d1..1aa6400ae8 100644 --- a/sigtool/sigtool.c +++ b/sigtool/sigtool.c @@ -39,6 +39,10 @@ #include #include +#ifndef _WIN32 +#include +#endif + // libclamav #include "clamav.h" #include "matcher.h" @@ -433,7 +437,6 @@ static int fuzzy_img(const struct optstruct *opts) static int htmlnorm(const struct optstruct *opts) { int fd; - fmap_t *map; cli_ctx *ctx = NULL; if ((fd = open(optget(opts, "html-normalise")->strarg, O_RDONLY | O_BINARY)) == -1) { @@ -443,7 +446,7 @@ static int htmlnorm(const struct optstruct *opts) if (NULL != (ctx = convenience_ctx(fd))) { html_normalise_map(ctx, ctx->fmap, ".", NULL, NULL); - funmap(map); + funmap(ctx->fmap); } else mprintf(LOGG_ERROR, "fmap failed\n"); @@ -698,13 +701,21 @@ static int writeinfo(const char *dbname, const char *builder, const char *header } static int diffdirs(const char *old, const char *new, const char *patch); -static int verifydiff(const char *diff, const char *cvd, const char *incdir); +static int verifydiff(const struct optstruct *opts, const char *diff, const char *cvd, const char *incdir); static int qcompare(const void *a, const void *b) { return strcmp(*(char *const *)a, *(char *const *)b); } +char *createTempDir(const struct optstruct *opts); +void removeTempDir(const struct optstruct *opts, char *dir) +{ + if (!optget(opts, "leave-temps")->enabled) { + cli_rmdirs(dir); + } +} + static int build(const struct optstruct *opts) { int ret, bc = 0, hy = 0; @@ -1088,22 +1099,13 @@ static int build(const struct optstruct *opts) } /* generate patch */ - if (!(pt = cli_gentemp(NULL))) { - mprintf(LOGG_ERROR, "build: Can't generate temporary name\n"); - unlink(newcvd); - return -1; - } - - if (mkdir(pt, 0700)) { - mprintf(LOGG_ERROR, "build: Can't create temporary directory %s\n", pt); - free(pt); - unlink(newcvd); + if (!(pt = createTempDir(opts))) { return -1; } if (CL_SUCCESS != cl_cvdunpack(olddb, pt, true)) { mprintf(LOGG_ERROR, "build: Can't unpack CVD file %s\n", olddb); - cli_rmdirs(pt); + removeTempDir(opts, pt); free(pt); unlink(newcvd); return -1; @@ -1112,24 +1114,13 @@ static int build(const struct optstruct *opts) olddb[sizeof(olddb) - 1] = '\0'; free(pt); - if (!(pt = cli_gentemp(NULL))) { - mprintf(LOGG_ERROR, "build: Can't generate temporary name\n"); - cli_rmdirs(olddb); - unlink(newcvd); - return -1; - } - - if (mkdir(pt, 0700)) { - mprintf(LOGG_ERROR, "build: Can't create temporary directory %s\n", pt); - free(pt); - cli_rmdirs(olddb); - unlink(newcvd); + if (!(pt = createTempDir(opts))) { return -1; } if (CL_SUCCESS != cl_cvdunpack(newcvd, pt, true)) { mprintf(LOGG_ERROR, "build: Can't unpack CVD file %s\n", newcvd); - cli_rmdirs(pt); + removeTempDir(opts, pt); free(pt); cli_rmdirs(olddb); unlink(newcvd); @@ -1138,8 +1129,7 @@ static int build(const struct optstruct *opts) snprintf(patch, sizeof(patch), "%s-%u.script", dbname, version); ret = diffdirs(olddb, pt, patch); - - cli_rmdirs(pt); + removeTempDir(opts, pt); free(pt); if (ret == -1) { @@ -1148,7 +1138,7 @@ static int build(const struct optstruct *opts) return -1; } - ret = verifydiff(patch, NULL, olddb); + ret = verifydiff(opts, patch, NULL, olddb); cli_rmdirs(olddb); if (ret == -1) { @@ -1251,9 +1241,9 @@ static int cvdinfo(const struct optstruct *opts) return 0; } -static int listdb(const char *filename, const regex_t *regex); +static int listdb(const struct optstruct *opts, const char *filename, const regex_t *regex); -static int listdir(const char *dirname, const regex_t *regex) +static int listdir(const struct optstruct *opts, const char *dirname, const regex_t *regex) { DIR *dd; struct dirent *dent; @@ -1298,7 +1288,7 @@ static int listdir(const char *dirname, const regex_t *regex) } sprintf(dbfile, "%s" PATHSEP "%s", dirname, dent->d_name); - if (listdb(dbfile, regex) == -1) { + if (listdb(opts, dbfile, regex) == -1) { mprintf(LOGG_ERROR, "listdb: Error listing database %s\n", dbfile); free(dbfile); closedir(dd); @@ -1313,7 +1303,7 @@ static int listdir(const char *dirname, const regex_t *regex) return 0; } -static int listdb(const char *filename, const regex_t *regex) +static int listdb(const struct optstruct *opts, const char *filename, const regex_t *regex) { FILE *fh; char *buffer, *pt, *start, *dir; @@ -1344,33 +1334,26 @@ static int listdb(const char *filename, const regex_t *regex) free(buffer); fclose(fh); - if (!(dir = cli_gentemp(NULL))) { - mprintf(LOGG_ERROR, "listdb: Can't generate temporary name\n"); - return -1; - } - - if (mkdir(dir, 0700)) { - mprintf(LOGG_ERROR, "listdb: Can't create temporary directory %s\n", dir); - free(dir); + if (!(dir = createTempDir(opts))) { return -1; } if (CL_SUCCESS != cl_cvdunpack(filename, dir, true)) { mprintf(LOGG_ERROR, "listdb: Can't unpack CVD file %s\n", filename); - cli_rmdirs(dir); + removeTempDir(opts, dir); free(dir); return -1; } /* list extracted directory */ - if (listdir(dir, regex) == -1) { + if (listdir(opts, dir, regex) == -1) { mprintf(LOGG_ERROR, "listdb: Can't list directory %s\n", filename); - cli_rmdirs(dir); + removeTempDir(opts, dir); free(dir); return -1; } - cli_rmdirs(dir); + removeTempDir(opts, dir); free(dir); return 0; @@ -1542,13 +1525,13 @@ static int listsigs(const struct optstruct *opts, int mode) if (S_ISDIR(sb.st_mode)) { if (!strcmp(name, DATADIR)) { dbdir = freshdbdir(); - ret = listdir(localdbdir ? localdbdir : dbdir, NULL); + ret = listdir(opts, localdbdir ? localdbdir : dbdir, NULL); free(dbdir); } else { - ret = listdir(name, NULL); + ret = listdir(opts, name, NULL); } } else { - ret = listdb(name, NULL); + ret = listdb(opts, name, NULL); } } else { @@ -1558,7 +1541,7 @@ static int listsigs(const struct optstruct *opts, int mode) } mprintf_stdout = 1; dbdir = freshdbdir(); - ret = listdir(localdbdir ? localdbdir : dbdir, ®); + ret = listdir(opts, localdbdir ? localdbdir : dbdir, ®); free(dbdir); cli_regfree(®); } @@ -1566,62 +1549,199 @@ static int listsigs(const struct optstruct *opts, int mode) return ret; } -static int vbadump(const struct optstruct *opts) +char *createTempDir(const struct optstruct *opts) { - int fd, hex_output; - char *dir; - const char *pt; - struct uniq *files = NULL; - cli_ctx *ctx; - int has_vba = 0, has_xlm = 0; - - if (optget(opts, "vba-hex")->enabled) { - hex_output = 1; - pt = optget(opts, "vba-hex")->strarg; + const struct optstruct *opt; + const char *tempdir = NULL; + char *ret = NULL; + + if (opts && ((opt = optget(opts, "tempdir"))->enabled)) { + tempdir = opt->strarg; } else { - hex_output = 0; - pt = optget(opts, "vba")->strarg; + tempdir = cli_gettmpdir(); } - if ((fd = open(pt, O_RDONLY | O_BINARY)) == -1) { - mprintf(LOGG_ERROR, "vbadump: Can't open file %s\n", pt); - return -1; + ret = (char *)cli_gentemp_with_prefix(tempdir, "sigtool"); + if (NULL == ret) { + logg(LOGG_ERROR, "Can't create temporary directory name.\n"); + goto done; } - /* generate the temporary directory */ - if (!(dir = cli_gentemp(NULL))) { - mprintf(LOGG_ERROR, "vbadump: Can't generate temporary name\n"); - close(fd); - return -1; + if (mkdir(ret, 0700)) { + logg(LOGG_ERROR, "Can't create temporary directory for scan: %s.\n", tempdir); + free((char *)ret); + ret = NULL; } - if (mkdir(dir, 0700)) { - mprintf(LOGG_ERROR, "vbadump: Can't create temporary directory %s\n", dir); - free(dir); - close(fd); - return -1; +done: + + return ret; +} + +static bool setTempDir(struct cl_engine *engine, const struct optstruct *opts) +{ + bool bRet = false; + int ret = -1; + const char *tempdir = createTempDir(opts); + if (NULL == tempdir) { + goto done; } - if (!(ctx = convenience_ctx(fd))) { - close(fd); - free(dir); - return -1; + + if ((ret = cl_engine_set_str(engine, CL_ENGINE_TMPDIR, tempdir))) { + logg(LOGG_ERROR, "cli_engine_set_str(CL_ENGINE_TMPDIR) failed: %s\n", cl_strerror(ret)); + goto done; } - if (cli_ole2_extract(dir, ctx, &files, &has_vba, &has_xlm, NULL)) { - destroy_ctx(ctx); - cli_rmdirs(dir); - free(dir); - close(fd); + + bRet = true; +done: + if (tempdir) { + free((char *)tempdir); + } + return bRet; +} + +static void scanfile(const char *filename, struct cl_engine *engine, const struct optstruct *opts, struct cl_scan_options *options) +{ + cl_error_t ret = CL_SUCCESS; + int fd = -1; + const char *virname = NULL; + char *real_filename = NULL; + unsigned long int blocks = 0; + + if (NULL == filename || NULL == engine || NULL == opts || NULL == options) { + logg(LOGG_INFO, "scanfile: Invalid args.\n"); + ret = CL_EARG; + goto done; + } + + ret = cli_realpath((const char *)filename, &real_filename); + if (CL_SUCCESS != ret) { + logg(LOGG_DEBUG, "Failed to determine real filename of %s.\n", filename); + logg(LOGG_DEBUG, "Quarantine of the file may fail if file path contains symlinks.\n"); + } else { + filename = real_filename; + } + + if ((fd = safe_open(filename, O_RDONLY | O_BINARY)) == -1) { + logg(LOGG_WARNING, "Can't open file %s: %s\n", filename, strerror(errno)); + goto done; + } + + if (CL_CLEAN != cl_scandesc_callback(fd, filename, &virname, &blocks, engine, options, NULL)) { + logg(LOGG_ERROR, "Error parsing '%s'\n", filename); + goto done; + } + +done: + if (NULL != real_filename) { + free(real_filename); + } + return; +} + +static int vba_callback(const unsigned char *const metaString, const size_t metaStringLen, void *context) +{ + + size_t i = 0; + + UNUSEDPARAM(context); + + if (NULL == metaString) { return -1; } - destroy_ctx(ctx); - if (has_vba && files) - sigtool_vba_scandir(dir, hex_output, files); - cli_rmdirs(dir); - free(dir); - close(fd); + + for (i = 0; i < metaStringLen; i++) { +#ifndef _WIN32 + if ('\r' == metaString[i]) { + continue; + } +#endif + printf("%c", metaString[i]); + } + printf("\n"); + return 0; } +static int vbadump(const struct optstruct *opts) +{ + int ret = -1; + + struct cl_scan_options options; + struct cl_engine *engine = NULL; + +#ifndef _WIN32 + struct rlimit rlim; +#endif + + const char *filename = NULL; + + /* Initalize scan options struct */ + memset(&options, 0, sizeof(struct cl_scan_options)); + + if ((ret = cl_init(CL_INIT_DEFAULT))) { + logg(LOGG_ERROR, "Can't initialize libclamav: %s\n", cl_strerror(ret)); + ret = 2; + goto done; + } + + if (!(engine = cl_engine_new())) { + logg(LOGG_ERROR, "Can't initialize antivirus engine\n"); + ret = 2; + goto done; + } + + cl_engine_set_clcb_vba(engine, vba_callback); + + if (!setTempDir(engine, opts)) { + ret = 2; + goto done; + } + + if ((ret = cl_engine_compile(engine)) != 0) { + logg(LOGG_ERROR, "Database initialization error: %s\n", cl_strerror(ret)); + ret = 2; + goto done; + } + +#ifndef _WIN32 + if (getrlimit(RLIMIT_FSIZE, &rlim) == 0) { + if (rlim.rlim_cur < (rlim_t)cl_engine_get_num(engine, CL_ENGINE_MAX_FILESIZE, NULL)) + logg(LOGG_WARNING, "System limit for file size is lower than engine->maxfilesize\n"); + if (rlim.rlim_cur < (rlim_t)cl_engine_get_num(engine, CL_ENGINE_MAX_SCANSIZE, NULL)) + logg(LOGG_WARNING, "System limit for file size is lower than engine->maxscansize\n"); + } else { + logg(LOGG_WARNING, "Cannot obtain resource limits for file size\n"); + } +#endif + + options.general |= CL_SCAN_GENERAL_COLLECT_METADATA; + + /*Have the engine unpack everything so that we don't miss anything. We'll clean it up later.*/ + options.parse = ~0; + + /*Need to explicitly set this to always keep temps, since we are scanning extracted ooxml/ole2 files + * from our scan directory to print all the vba content. Remove it later if leave-temps was not + * specified */ + cl_engine_set_num(engine, CL_ENGINE_KEEPTMP, 1); + + filename = optget(opts, "vba")->strarg; + if (NULL == filename) { + filename = optget(opts, "vba-hex")->strarg; + } + scanfile(filename, engine, opts, &options); + + removeTempDir(opts, engine->tmpdir); + + ret = 0; +done: + + /* free the engine */ + cl_engine_free(engine); + + return ret; +} + static int comparesha(const char *diff) { char info[32], buff[FILEBUFF], *sha, *pt, *name; @@ -1960,7 +2080,7 @@ static int dircopy(const char *src, const char *dest) return 0; } -static int verifydiff(const char *diff, const char *cvd, const char *incdir) +static int verifydiff(const struct optstruct *opts, const char *diff, const char *cvd, const char *incdir) { char *tempdir, cwd[512]; int ret = 0, fd; @@ -1975,29 +2095,21 @@ static int verifydiff(const char *diff, const char *cvd, const char *incdir) return -1; } - tempdir = cli_gentemp(NULL); - if (!tempdir) { - mprintf(LOGG_ERROR, "verifydiff: Can't generate temporary name for tempdir\n"); - return -1; - } - - if (mkdir(tempdir, 0700) == -1) { - mprintf(LOGG_ERROR, "verifydiff: Can't create directory %s\n", tempdir); - free(tempdir); + if (!(tempdir = createTempDir(opts))) { return -1; } if (cvd) { if (CL_SUCCESS != cl_cvdunpack(cvd, tempdir, true)) { mprintf(LOGG_ERROR, "verifydiff: Can't unpack CVD file %s\n", cvd); - cli_rmdirs(tempdir); + removeTempDir(opts, tempdir); free(tempdir); return -1; } } else { if (dircopy(incdir, tempdir) == -1) { mprintf(LOGG_ERROR, "verifydiff: Can't copy dir %s to %s\n", incdir, tempdir); - cli_rmdirs(tempdir); + removeTempDir(opts, tempdir); free(tempdir); return -1; } @@ -2005,21 +2117,21 @@ static int verifydiff(const char *diff, const char *cvd, const char *incdir) if (!getcwd(cwd, sizeof(cwd))) { mprintf(LOGG_ERROR, "verifydiff: getcwd() failed\n"); - cli_rmdirs(tempdir); + removeTempDir(opts, tempdir); free(tempdir); return -1; } if ((fd = open(diff, O_RDONLY | O_BINARY)) == -1) { mprintf(LOGG_ERROR, "verifydiff: Can't open diff file %s\n", diff); - cli_rmdirs(tempdir); + removeTempDir(opts, tempdir); free(tempdir); return -1; } if (chdir(tempdir) == -1) { mprintf(LOGG_ERROR, "verifydiff: Can't chdir to %s\n", tempdir); - cli_rmdirs(tempdir); + removeTempDir(opts, tempdir); free(tempdir); close(fd); return -1; @@ -2029,7 +2141,7 @@ static int verifydiff(const char *diff, const char *cvd, const char *incdir) mprintf(LOGG_ERROR, "verifydiff: Can't apply %s\n", diff); if (chdir(cwd) == -1) mprintf(LOGG_WARNING, "verifydiff: Can't chdir to %s\n", cwd); - cli_rmdirs(tempdir); + removeTempDir(opts, tempdir); free(tempdir); close(fd); return -1; @@ -2040,7 +2152,7 @@ static int verifydiff(const char *diff, const char *cvd, const char *incdir) if (chdir(cwd) == -1) mprintf(LOGG_WARNING, "verifydiff: Can't chdir to %s\n", cwd); - cli_rmdirs(tempdir); + removeTempDir(opts, tempdir); free(tempdir); if (!ret) { @@ -3197,45 +3309,25 @@ static int makediff(const struct optstruct *opts) return -1; } - odir = cli_gentemp(NULL); - if (!odir) { - mprintf(LOGG_ERROR, "makediff: Can't generate temporary name for odir\n"); - return -1; - } - - if (mkdir(odir, 0700) == -1) { - mprintf(LOGG_ERROR, "makediff: Can't create directory %s\n", odir); - free(odir); + if (!(odir = createTempDir(opts))) { return -1; } if (CL_SUCCESS != cl_cvdunpack(optget(opts, "diff")->strarg, odir, true)) { mprintf(LOGG_ERROR, "makediff: Can't unpack CVD file %s\n", optget(opts, "diff")->strarg); - cli_rmdirs(odir); - free(odir); - return -1; - } - - ndir = cli_gentemp(NULL); - if (!ndir) { - mprintf(LOGG_ERROR, "makediff: Can't generate temporary name for ndir\n"); - cli_rmdirs(odir); + removeTempDir(opts, odir); free(odir); return -1; } - if (mkdir(ndir, 0700) == -1) { - mprintf(LOGG_ERROR, "makediff: Can't create directory %s\n", ndir); - free(ndir); - cli_rmdirs(odir); - free(odir); + if (!(ndir = createTempDir(opts))) { return -1; } if (CL_SUCCESS != cl_cvdunpack(opts->filename[0], ndir, true)) { mprintf(LOGG_ERROR, "makediff: Can't unpack CVD file %s\n", opts->filename[0]); - cli_rmdirs(odir); - cli_rmdirs(ndir); + removeTempDir(opts, odir); + removeTempDir(opts, ndir); free(odir); free(ndir); return -1; @@ -3244,15 +3336,15 @@ static int makediff(const struct optstruct *opts) snprintf(name, sizeof(name), "%s-%u.script", getdbname(opts->filename[0], dbname, sizeof(dbname)), newver); ret = diffdirs(odir, ndir, name); - cli_rmdirs(odir); - cli_rmdirs(ndir); + removeTempDir(opts, odir); + removeTempDir(opts, ndir); free(odir); free(ndir); if (ret == -1) return -1; - if (verifydiff(name, optget(opts, "diff")->strarg, NULL) == -1) { + if (verifydiff(opts, name, optget(opts, "diff")->strarg, NULL) == -1) { snprintf(broken, sizeof(broken), "%s.broken", name); if (rename(name, broken)) { unlink(name); @@ -3456,6 +3548,8 @@ static void help(void) mprintf(LOGG_INFO, " cdiff format\n"); mprintf(LOGG_INFO, " --run-cdiff=FILE -r FILE Execute update script FILE in cwd\n"); mprintf(LOGG_INFO, " --verify-cdiff=DIFF CVD/CLD Verify DIFF against CVD/CLD\n"); + mprintf(LOGG_INFO, " --tempdir=DIRECTORY Create temporary files in DIRECTORY\n"); + mprintf(LOGG_INFO, " --leave-temps[=yes/no(*)] Do not remove temporary files\n"); mprintf(LOGG_INFO, "\n"); return; @@ -3559,9 +3653,9 @@ int main(int argc, char **argv) ret = -1; } else { if (S_ISDIR(sb.st_mode)) - ret = verifydiff(optget(opts, "verify-cdiff")->strarg, NULL, opts->filename[0]); + ret = verifydiff(opts, optget(opts, "verify-cdiff")->strarg, NULL, opts->filename[0]); else - ret = verifydiff(optget(opts, "verify-cdiff")->strarg, opts->filename[0], NULL); + ret = verifydiff(opts, optget(opts, "verify-cdiff")->strarg, opts->filename[0], NULL); } } } else diff --git a/sigtool/vba.c b/sigtool/vba.c index e9852a7a5d..54304e9fe1 100644 --- a/sigtool/vba.c +++ b/sigtool/vba.c @@ -154,47 +154,7 @@ cli_ctx *convenience_ctx(int fd) return ctx; } -void destroy_ctx(cli_ctx *ctx) -{ - if (NULL != ctx) { - if (NULL != ctx->recursion_stack) { - /* Clean up any fmaps */ - while (ctx->recursion_level > 0) { - if (NULL != ctx->recursion_stack[ctx->recursion_level].fmap) { - funmap(ctx->recursion_stack[ctx->recursion_level].fmap); - ctx->recursion_stack[ctx->recursion_level].fmap = NULL; - } - ctx->recursion_level -= 1; - } - if (NULL != ctx->recursion_stack[0].fmap) { - funmap(ctx->recursion_stack[0].fmap); - ctx->recursion_stack[0].fmap = NULL; - } - - free(ctx->recursion_stack); - ctx->recursion_stack = NULL; - } - - if (NULL != ctx->engine) { - cl_engine_free((struct cl_engine *)ctx->engine); - ctx->engine = NULL; - } - - if (NULL != ctx->options) { - free(ctx->options); - ctx->options = NULL; - } - - if (NULL != ctx->evidence) { - evidence_free(ctx->evidence); - } - - free(ctx); - } -} - -int sigtool_vba_scandir(const char *dirname, int hex_output, struct uniq *U); - +/*only called by wm_decode_macro*/ static char *get_unicode_name(char *name, int size) { int i, j; @@ -224,6 +184,7 @@ static char *get_unicode_name(char *name, int size) return newname; } +/*only called by wm_decode_macro*/ static void output_token(unsigned char token) { int i; @@ -320,6 +281,7 @@ static void output_token(unsigned char token) return; } +/*only called by wm_decode_macro*/ static void output_token67(uint16_t token) { int i; @@ -670,6 +632,7 @@ static void output_token67(uint16_t token) return; } +/*only called by wm_decode_macro*/ static void output_token73(uint16_t token) { int i; @@ -921,6 +884,7 @@ static void output_token73(uint16_t token) return; } +/*only called by wm_decode_macro*/ static void print_hex_buff(unsigned char *start, unsigned char *end, int hex_output) { if (!hex_output) { @@ -1099,264 +1063,3 @@ static void wm_decode_macro(unsigned char *buff, uint32_t len, int hex_output) } print_hex_buff(line_start, buff + i, hex_output); } - -static int sigtool_scandir(const char *dirname, int hex_output) -{ - int status = -1; - DIR *dd = NULL; - struct dirent *dent; - STATBUF statbuf; - const char *tmpdir; - char *fname = NULL; - char *dir = NULL; - cl_error_t ret = CL_CLEAN; - int desc = -1; - cli_ctx *ctx = NULL; - int has_vba = 0, has_xlm = 0; - - if ((dd = opendir(dirname)) != NULL) { - while ((dent = readdir(dd))) { - if (dent->d_ino) { - if (strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) { - /* build the full name */ - fname = (char *)cli_calloc(strlen(dirname) + strlen(dent->d_name) + 2, sizeof(char)); - if (!fname) { - status = -1; - goto done; - } - - sprintf(fname, "%s" PATHSEP "%s", dirname, dent->d_name); - - /* stat the file */ - if (LSTAT(fname, &statbuf) != -1) { - if (S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) { - if (sigtool_scandir(fname, hex_output)) { - status = CL_VIRUS; - goto done; - } - } else { - if (S_ISREG(statbuf.st_mode)) { - struct uniq *files = NULL; - tmpdir = cli_gettmpdir(); - - /* generate the temporary directory */ - dir = cli_gentemp(tmpdir); - if (!dir) { - printf("cli_gentemp() failed\n"); - status = -1; - goto done; - } - - if (mkdir(dir, 0700)) { - printf("Can't create temporary directory %s\n", dir); - status = CL_ETMPDIR; - goto done; - } - - if ((desc = open(fname, O_RDONLY | O_BINARY)) == -1) { - printf("Can't open file %s\n", fname); - status = 1; - goto done; - } - - if (!(ctx = convenience_ctx(desc))) { - status = 1; - goto done; - } - if ((ret = cli_ole2_extract(dir, ctx, &files, &has_vba, &has_xlm, NULL))) { - printf("ERROR %s\n", cl_strerror(ret)); - - status = ret; - goto done; - } - - if (has_vba && files) - sigtool_vba_scandir(dir, hex_output, files); - - // Cleanup - if (desc >= 0) { - close(desc); - desc = -1; - } - - destroy_ctx(ctx); - ctx = NULL; - - cli_rmdirs(dir); - free(dir); - dir = NULL; - } - } - } - - // Cleanup - free(fname); - fname = NULL; - } - } - } - } else { - logg(LOGG_ERROR, "Can't open directory %s.\n", dirname); - return CL_EOPEN; - } - - status = 0; - -done: - if (desc >= 0) { - close(desc); - } - if (NULL != dd) { - closedir(dd); - } - if (NULL != ctx) { - destroy_ctx(ctx); - } - if (NULL != dir) { - cli_rmdirs(dir); - free(dir); - } - if (NULL != fname) { - free(fname); - } - - return status; -} - -int sigtool_vba_scandir(const char *dirname, int hex_output, struct uniq *U) -{ - cl_error_t status = CL_CLEAN; - cl_error_t ret; - int i, fd; - size_t data_len; - vba_project_t *vba_project = NULL; - DIR *dd; - struct dirent *dent; - STATBUF statbuf; - char *fullname, vbaname[1024], *hash; - unsigned char *data; - uint32_t hashcnt; - unsigned int j; - - if (CL_SUCCESS != (ret = uniq_get(U, "_vba_project", 12, NULL, &hashcnt))) { - logg(LOGG_ERROR, "ScanDir -> uniq_get('_vba_project') failed.\n"); - return ret; - } - - while (hashcnt) { - if (!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) { - hashcnt--; - continue; - } - - for (i = 0; i < vba_project->count; i++) { - for (j = 0; j < vba_project->colls[i]; j++) { - snprintf(vbaname, 1024, "%s" PATHSEP "%s_%u", vba_project->dir, vba_project->name[i], j); - vbaname[sizeof(vbaname) - 1] = '\0'; - - fd = open(vbaname, O_RDONLY | O_BINARY); - if (fd == -1) continue; - data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len); - close(fd); - - if (data) { - data = (unsigned char *)realloc(data, data_len + 1); - data[data_len] = '\0'; - printf("-------------- start of code ------------------\n%s\n-------------- end of code ------------------\n", data); - free(data); - } - } - } - - cli_free_vba_project(vba_project); - vba_project = NULL; - - hashcnt--; - } - - if (CL_SUCCESS != (ret = uniq_get(U, "powerpoint document", 19, &hash, &hashcnt))) { - logg(LOGG_ERROR, "ScanDir -> uniq_get('powerpoint document') failed.\n"); - return ret; - } - - while (hashcnt) { - snprintf(vbaname, 1024, "%s" PATHSEP "%s_%u", dirname, hash, hashcnt); - vbaname[sizeof(vbaname) - 1] = '\0'; - - fd = open(vbaname, O_RDONLY | O_BINARY); - if (fd == -1) { - hashcnt--; - continue; - } - if ((fullname = cli_ppt_vba_read(fd, NULL))) { - sigtool_scandir(fullname, hex_output); - cli_rmdirs(fullname); - free(fullname); - } - close(fd); - hashcnt--; - } - - if (CL_SUCCESS != (ret = uniq_get(U, "worddocument", 12, &hash, &hashcnt))) { - logg(LOGG_ERROR, "ScanDir -> uniq_get('worddocument') failed.\n"); - return ret; - } - - while (hashcnt) { - snprintf(vbaname, sizeof(vbaname), "%s" PATHSEP "%s_%u", dirname, hash, hashcnt); - vbaname[sizeof(vbaname) - 1] = '\0'; - - fd = open(vbaname, O_RDONLY | O_BINARY); - if (fd == -1) { - hashcnt--; - continue; - } - - if (!(vba_project = (vba_project_t *)cli_wm_readdir(fd))) { - close(fd); - hashcnt--; - continue; - } - - for (i = 0; i < vba_project->count; i++) { - data_len = vba_project->length[i]; - data = (unsigned char *)cli_wm_decrypt_macro(fd, vba_project->offset[i], (uint32_t)data_len, vba_project->key[i]); - if (data) { - data = (unsigned char *)realloc(data, data_len + 1); - data[data_len] = '\0'; - printf("-------------- start of code ------------------\n%s\n-------------- end of code ------------------\n", data); - free(data); - } - } - - close(fd); - cli_free_vba_project(vba_project); - vba_project = NULL; - hashcnt--; - } - - if ((dd = opendir(dirname)) != NULL) { - while ((dent = readdir(dd))) { - if (dent->d_ino) { - if (strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) { - /* build the full name */ - fullname = calloc(strlen(dirname) + strlen(dent->d_name) + 2, sizeof(char)); - sprintf(fullname, "%s" PATHSEP "%s", dirname, dent->d_name); - - /* stat the file */ - if (LSTAT(fullname, &statbuf) != -1) { - if (S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) - sigtool_vba_scandir(fullname, hex_output, U); - } - free(fullname); - } - } - } - } else { - logg(LOGG_ERROR, "ScanDir -> Can't open directory %s.\n", dirname); - return CL_EOPEN; - } - - closedir(dd); - return status; -} diff --git a/sigtool/vba.h b/sigtool/vba.h index 032e94cd72..410fd9cd87 100644 --- a/sigtool/vba.h +++ b/sigtool/vba.h @@ -24,7 +24,9 @@ #include "uniq.h" #include "others.h" -int sigtool_vba_scandir(const char *dirname, int hex_output, struct uniq *U); +struct optstruct; +int sigtool_vba_scandir(const struct optstruct *opts, const char *dirname, int hex_output, struct uniq *U); + cli_ctx *convenience_ctx(int fd); void destroy_ctx(cli_ctx *ctx);