This shows the archive member names (if known) when a virus is found.
When combined with -v it shows the archive member names while scanning too.
... | ... |
@@ -195,6 +195,7 @@ void help(void) |
195 | 195 |
mprintf(" --help -h Print this help screen\n"); |
196 | 196 |
mprintf(" --version -V Print version number\n"); |
197 | 197 |
mprintf(" --verbose -v Be verbose\n"); |
198 |
+ mprintf(" --archive-verbose -a Show filenames inside scanned archives\n"); |
|
198 | 199 |
mprintf(" --debug Enable libclamav's debug messages\n"); |
199 | 200 |
mprintf(" --quiet Only output error messages\n"); |
200 | 201 |
mprintf(" --stdout Write to stdout instead of stderr\n"); |
... | ... |
@@ -120,12 +120,104 @@ static int checkaccess(const char *path, const char *username, int mode) |
120 | 120 |
} |
121 | 121 |
#endif |
122 | 122 |
|
123 |
+struct metachain { |
|
124 |
+ char **chains; |
|
125 |
+ unsigned lastadd; |
|
126 |
+ unsigned lastvir; |
|
127 |
+ unsigned level; |
|
128 |
+ unsigned n; |
|
129 |
+}; |
|
130 |
+ |
|
131 |
+static cl_error_t pre(int fd, const char *type, void *context) |
|
132 |
+{ |
|
133 |
+ struct metachain *c = context; |
|
134 |
+ if (c) { |
|
135 |
+ c->level++; |
|
136 |
+ } |
|
137 |
+ return CL_CLEAN; |
|
138 |
+} |
|
139 |
+ |
|
140 |
+static int print_chain(struct metachain *c, char *str, unsigned len) |
|
141 |
+{ |
|
142 |
+ unsigned i; |
|
143 |
+ unsigned na = 0; |
|
144 |
+ for (i=0;i<c->n-1;i++) { |
|
145 |
+ unsigned int n = strlen(c->chains[i]); |
|
146 |
+ if (na) |
|
147 |
+ str[na++] = '!'; |
|
148 |
+ if (n + na + 2 > len) |
|
149 |
+ break; |
|
150 |
+ memcpy(str + na, c->chains[i], n); |
|
151 |
+ na += n; |
|
152 |
+ } |
|
153 |
+ str[na] = '\0'; |
|
154 |
+ str[len-1] = '\0'; |
|
155 |
+ return i == c->n-1 ? 0 : 1; |
|
156 |
+} |
|
157 |
+ |
|
158 |
+static cl_error_t post(int fd, int result, const char *virname, void *context) |
|
159 |
+{ |
|
160 |
+ struct metachain *c = context; |
|
161 |
+ if (c && c->n) { |
|
162 |
+ char str[128]; |
|
163 |
+ int toolong = print_chain(c, str, sizeof(str)); |
|
164 |
+ if (c->level == c->lastadd && !virname) |
|
165 |
+ free(c->chains[--c->n]); |
|
166 |
+ if (virname && !c->lastvir) |
|
167 |
+ c->lastvir = c->level; |
|
168 |
+ } |
|
169 |
+ if (c) |
|
170 |
+ c->level--; |
|
171 |
+ return CL_CLEAN; |
|
172 |
+} |
|
173 |
+ |
|
174 |
+static cl_error_t meta(const char* container_type, unsigned long fsize_container, const char *filename, |
|
175 |
+ unsigned long fsize_real, int is_encrypted, unsigned int filepos_container, void *context) |
|
176 |
+{ |
|
177 |
+ int na = 0; |
|
178 |
+ char prev[128]; |
|
179 |
+ struct metachain *c = context; |
|
180 |
+ const char *type = !strncmp(container_type,"CL_TYPE_",8) ? container_type + 8 : container_type; |
|
181 |
+ unsigned n = strlen(type) + 1 + strlen(filename) + 1; |
|
182 |
+ char *chain; |
|
183 |
+ char **chains; |
|
184 |
+ int toolong; |
|
185 |
+ |
|
186 |
+ if (!c) |
|
187 |
+ return CL_CLEAN; |
|
188 |
+ chain = malloc(n); |
|
189 |
+ if (!chain) |
|
190 |
+ return CL_CLEAN; |
|
191 |
+ if (!strcmp(type, "ANY")) |
|
192 |
+ snprintf(chain, n,"%s", filename); |
|
193 |
+ else |
|
194 |
+ snprintf(chain, n,"%s:%s", type, filename); |
|
195 |
+ if (c->lastadd != c->level) { |
|
196 |
+ n = c->n + 1; |
|
197 |
+ chains = realloc(c->chains, n * sizeof(*chains)); |
|
198 |
+ if (!chains) { |
|
199 |
+ free(chain); |
|
200 |
+ return CL_CLEAN; |
|
201 |
+ } |
|
202 |
+ c->chains = chains; |
|
203 |
+ c->n = n; |
|
204 |
+ c->lastadd = c->level; |
|
205 |
+ } else { |
|
206 |
+ free(c->chains[c->n-1]); |
|
207 |
+ } |
|
208 |
+ c->chains[c->n-1] = chain; |
|
209 |
+ toolong = print_chain(c, prev, sizeof(prev)); |
|
210 |
+ logg("*Scanning %s%s!%s\n", prev,toolong ? "..." : "", chain); |
|
211 |
+ return CL_CLEAN; |
|
212 |
+} |
|
213 |
+ |
|
123 | 214 |
static void scanfile(const char *filename, struct cl_engine *engine, const struct optstruct *opts, unsigned int options) |
124 | 215 |
{ |
125 |
- int ret = 0, fd, included, printclean = 1; |
|
216 |
+ int ret = 0, fd, included, printclean = 1, i; |
|
126 | 217 |
const struct optstruct *opt; |
127 | 218 |
const char *virname; |
128 | 219 |
struct stat sb; |
220 |
+ struct metachain chain; |
|
129 | 221 |
|
130 | 222 |
if((opt = optget(opts, "exclude"))->enabled) { |
131 | 223 |
while(opt) { |
... | ... |
@@ -181,6 +273,14 @@ static void scanfile(const char *filename, struct cl_engine *engine, const struc |
181 | 181 |
} |
182 | 182 |
#endif |
183 | 183 |
|
184 |
+ memset(&chain, 0, sizeof(chain)); |
|
185 |
+ if(optget(opts, "archive-verbose")->enabled) { |
|
186 |
+ chain.chains = malloc(sizeof(*chain.chains)); |
|
187 |
+ if (chain.chains) { |
|
188 |
+ chain.chains[0] = strdup(filename); |
|
189 |
+ chain.n = 1; |
|
190 |
+ } |
|
191 |
+ } |
|
184 | 192 |
logg("*Scanning %s\n", filename); |
185 | 193 |
|
186 | 194 |
if((fd = safe_open(filename, O_RDONLY|O_BINARY)) == -1) { |
... | ... |
@@ -189,7 +289,16 @@ static void scanfile(const char *filename, struct cl_engine *engine, const struc |
189 | 189 |
return; |
190 | 190 |
} |
191 | 191 |
|
192 |
- if((ret = cl_scandesc(fd, &virname, &info.blocks, engine, options)) == CL_VIRUS) { |
|
192 |
+ |
|
193 |
+ if((ret = cl_scandesc_callback(fd, &virname, &info.blocks, engine, options, &chain)) == CL_VIRUS) { |
|
194 |
+ if(optget(opts, "archive-verbose")->enabled) { |
|
195 |
+ if (chain.n > 1) { |
|
196 |
+ char str[128]; |
|
197 |
+ int toolong = print_chain(&chain, str, sizeof(str)); |
|
198 |
+ logg("~%s%s!(%d)%s: %s FOUND\n", str, toolong ? "..." : "", chain.lastvir-1, chain.chains[chain.n-1], virname); |
|
199 |
+ } else if (chain.lastvir) |
|
200 |
+ logg("~%s!(%d): %s FOUND\n", filename, chain.lastvir-1, virname); |
|
201 |
+ } |
|
193 | 202 |
logg("~%s: %s FOUND\n", filename, virname); |
194 | 203 |
info.files++; |
195 | 204 |
info.ifiles++; |
... | ... |
@@ -207,6 +316,9 @@ static void scanfile(const char *filename, struct cl_engine *engine, const struc |
207 | 207 |
info.errors++; |
208 | 208 |
} |
209 | 209 |
|
210 |
+ for (i=0;i<chain.n;i++) |
|
211 |
+ free(chain.chains[i]); |
|
212 |
+ free(chain.chains); |
|
210 | 213 |
close(fd); |
211 | 214 |
|
212 | 215 |
if(ret == CL_VIRUS && action) |
... | ... |
@@ -541,6 +653,12 @@ int scanmanager(const struct optstruct *opts) |
541 | 541 |
return 2; |
542 | 542 |
} |
543 | 543 |
|
544 |
+ if(optget(opts, "archive-verbose")->enabled) { |
|
545 |
+ cl_engine_set_clcb_meta(engine, meta); |
|
546 |
+ cl_engine_set_clcb_pre_scan(engine, pre); |
|
547 |
+ cl_engine_set_clcb_post_scan(engine, post); |
|
548 |
+ } |
|
549 |
+ |
|
544 | 550 |
/* set limits */ |
545 | 551 |
|
546 | 552 |
if((opt = optget(opts, "max-scansize"))->active) { |
... | ... |
@@ -343,6 +343,7 @@ int cli_scanishield(cli_ctx *ctx, off_t off, size_t sz) { |
343 | 343 |
off_t coff = off; |
344 | 344 |
struct IS_CABSTUFF c = { NULL, -1, 0, 0 }; |
345 | 345 |
fmap_t *map = *ctx->fmap; |
346 |
+ unsigned fc = 0; |
|
346 | 347 |
|
347 | 348 |
while(ret == CL_CLEAN) { |
348 | 349 |
fname = fmap_need_offstr(map, coff, 2048); |
... | ... |
@@ -371,6 +372,10 @@ int cli_scanishield(cli_ctx *ctx, off_t off, size_t sz) { |
371 | 371 |
) break; |
372 | 372 |
|
373 | 373 |
cli_dbgmsg("ishield: @%lx found file %s (%s) - version %s - size %lu\n", (unsigned long int) coff, fname, path, version, (unsigned long int) fsize); |
374 |
+ if(cli_matchmeta(ctx, fname, fsize, fsize, 0, fc++, 0, NULL) == CL_VIRUS) { |
|
375 |
+ ret = CL_VIRUS; |
|
376 |
+ break; |
|
377 |
+ } |
|
374 | 378 |
sz -= (data - fname) + fsize; |
375 | 379 |
|
376 | 380 |
if(!strncasecmp(fname, "data", 4)) { |
... | ... |
@@ -824,6 +824,7 @@ int cli_matchmeta(cli_ctx *ctx, const char *fname, size_t fsizec, size_t fsizer, |
824 | 824 |
if (ctx->engine && ctx->engine->cb_meta) |
825 | 825 |
if (ctx->engine->cb_meta(cli_ftname(ctx->container_type), fsizec, fname, fsizer, encrypted, filepos, ctx->cb_ctx) == CL_VIRUS) { |
826 | 826 |
cli_dbgmsg("inner file blacklisted by callback: %s\n", fname); |
827 |
+ *ctx->virname = "Detected.By.Callback"; |
|
827 | 828 |
return CL_VIRUS; |
828 | 829 |
} |
829 | 830 |
|
... | ... |
@@ -134,6 +134,8 @@ const struct clam_option __clam_options[] = { |
134 | 134 |
{ NULL, "trace", 't', TYPE_NUMBER, MATCH_NUMBER, 7, NULL, 0, OPT_CLAMBC, "bytecode trace level",""}, |
135 | 135 |
{ NULL, "no-trace-showsource", 's', TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMBC, "Don't show source line during tracing",""}, |
136 | 136 |
|
137 |
+ { NULL, "archive-verbose", 'a', TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN, "", ""}, |
|
138 |
+ |
|
137 | 139 |
/* cmdline only - deprecated */ |
138 | 140 |
{ NULL, "bytecode-trust-all", 't', TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN | OPT_DEPRECATED, "", ""}, |
139 | 141 |
{ NULL, "http-proxy", 0, TYPE_STRING, NULL, 0, NULL, 0, OPT_FRESHCLAM | OPT_DEPRECATED, "", "" }, |