... | ... |
@@ -174,6 +174,52 @@ extern int cl_engine_addref(struct cl_engine *engine); |
174 | 174 |
extern int cl_engine_free(struct cl_engine *engine); |
175 | 175 |
|
176 | 176 |
|
177 |
+/* CALLBACKS - WARNING: unstable API - WIP */ |
|
178 |
+ |
|
179 |
+ |
|
180 |
+typedef cl_error_t (*clcb_pre_scan)(int fd, void *context); |
|
181 |
+/* PRE-SCAN |
|
182 |
+Input: |
|
183 |
+fd = File descriptor which is about to be scanned |
|
184 |
+context = Opaque application provided data |
|
185 |
+ |
|
186 |
+Output: |
|
187 |
+CL_CLEAN = File is scanned |
|
188 |
+CL_BREAK = Whitelisted by callback - file is skipped and marked as clean |
|
189 |
+CL_VIRUS = Blacklisted by callback - file is skipped and marked as infected |
|
190 |
+*/ |
|
191 |
+extern void cl_engine_set_clcb_pre_scan(struct cl_engine *engine, clcb_pre_scan callback, void *context); |
|
192 |
+ |
|
193 |
+ |
|
194 |
+typedef cl_error_t (*clcb_post_scan)(int fd, int result, void *context); |
|
195 |
+/* POST-SCAN |
|
196 |
+Input: |
|
197 |
+fd = File descriptor which is was scanned |
|
198 |
+result = The scan result for the file |
|
199 |
+context = Opaque application provided data |
|
200 |
+ |
|
201 |
+Output: |
|
202 |
+CL_CLEAN = Scan result is not overridden |
|
203 |
+CL_BREAK = Whitelisted by callback - scan result is set to CL_CLEAN |
|
204 |
+CL_VIRUS = Blacklisted by callback - scan result is set to CL_VIRUS |
|
205 |
+*/ |
|
206 |
+extern void cl_engine_set_clcb_post_scan(struct cl_engine *engine, clcb_post_scan callback, void *context); |
|
207 |
+ |
|
208 |
+ |
|
209 |
+typedef int (*clcb_sigload)(const char *type, const char *name, void *context); |
|
210 |
+/* SIGNATURE LOAD |
|
211 |
+Input: |
|
212 |
+type = The signature type (e.g. "db", "ndb", "mdb", etc.) |
|
213 |
+name = The virus name |
|
214 |
+context = Opaque application provided data |
|
215 |
+ |
|
216 |
+Output: |
|
217 |
+0 = Load the current signature |
|
218 |
+Non 0 = Skip the current signature |
|
219 |
+*/ |
|
220 |
+extern void cl_engine_set_clcb_sigload(struct cl_engine *engine, clcb_sigload callback, void *context); |
|
221 |
+ |
|
222 |
+ |
|
177 | 223 |
struct cl_stat { |
178 | 224 |
char *dir; |
179 | 225 |
struct stat *stattab; |
... | ... |
@@ -11,6 +11,9 @@ CLAMAV_PUBLIC { |
11 | 11 |
cl_engine_get_num; |
12 | 12 |
cl_engine_set_str; |
13 | 13 |
cl_engine_get_str; |
14 |
+ cl_engine_set_clcb_pre_scan; |
|
15 |
+ cl_engine_set_clcb_post_scan; |
|
16 |
+ cl_engine_set_clcb_sigload; |
|
14 | 17 |
cl_engine_settings_copy; |
15 | 18 |
cl_engine_settings_apply; |
16 | 19 |
cl_engine_settings_free; |
... | ... |
@@ -1008,3 +1008,18 @@ int cli_bitset_test(bitset_t *bs, unsigned long bit_offset) |
1008 | 1008 |
} |
1009 | 1009 |
return (bs->bitset[char_offset] & ((unsigned char)1 << bit_offset)); |
1010 | 1010 |
} |
1011 |
+ |
|
1012 |
+void cl_engine_set_clcb_pre_scan(struct cl_engine *engine, clcb_pre_scan callback, void *context) { |
|
1013 |
+ engine->cb_pre_scan = callback; |
|
1014 |
+ engine->cb_pre_scan_ctx = callback ? context : NULL; |
|
1015 |
+} |
|
1016 |
+ |
|
1017 |
+void cl_engine_set_clcb_post_scan(struct cl_engine *engine, clcb_post_scan callback, void *context) { |
|
1018 |
+ engine->cb_post_scan = callback; |
|
1019 |
+ engine->cb_post_scan_ctx = callback ? context : NULL; |
|
1020 |
+} |
|
1021 |
+ |
|
1022 |
+void cl_engine_set_clcb_sigload(struct cl_engine *engine, clcb_sigload callback, void *context) { |
|
1023 |
+ engine->cb_sigload = callback; |
|
1024 |
+ engine->cb_sigload_ctx = callback ? context : NULL; |
|
1025 |
+} |
... | ... |
@@ -247,6 +247,14 @@ struct cl_engine { |
247 | 247 |
/* Used for memory pools */ |
248 | 248 |
mpool_t *mempool; |
249 | 249 |
|
250 |
+ /* Callback(s) */ |
|
251 |
+ clcb_pre_scan cb_pre_scan; |
|
252 |
+ void *cb_pre_scan_ctx; |
|
253 |
+ clcb_post_scan cb_post_scan; |
|
254 |
+ void *cb_post_scan_ctx; |
|
255 |
+ clcb_sigload cb_sigload; |
|
256 |
+ void *cb_sigload_ctx; |
|
257 |
+ |
|
250 | 258 |
/* Used for bytecode */ |
251 | 259 |
struct cli_all_bc bcs; |
252 | 260 |
unsigned *hooks[_BC_LAST_HOOK - _BC_START_HOOKS]; |
... | ... |
@@ -549,6 +549,11 @@ static int cli_loaddb(FILE *fs, struct cl_engine *engine, unsigned int *signo, u |
549 | 549 |
if(engine->ignored && cli_chkign(engine->ignored, start, buffer_cpy)) |
550 | 550 |
continue; |
551 | 551 |
|
552 |
+ if(engine->cb_sigload && engine->cb_sigload("db", start, engine->cb_sigload_ctx)) { |
|
553 |
+ cli_dbgmsg("cli_loaddb: skipping %s due to callback\n", start); |
|
554 |
+ continue; |
|
555 |
+ } |
|
556 |
+ |
|
552 | 557 |
if(*pt == '=') continue; |
553 | 558 |
|
554 | 559 |
if((ret = cli_parse_add(root, start, pt, 0, 0, "*", 0, NULL, options))) { |
... | ... |
@@ -623,6 +628,11 @@ static int cli_loadidb(FILE *fs, struct cl_engine *engine, unsigned int *signo, |
623 | 623 |
if(engine->ignored && cli_chkign(engine->ignored, tokens[0], buffer_cpy)) |
624 | 624 |
continue; |
625 | 625 |
|
626 |
+ if(engine->cb_sigload && engine->cb_sigload("idb", tokens[0], engine->cb_sigload_ctx)) { |
|
627 |
+ cli_dbgmsg("cli_loadidb: skipping %s due to callback\n", tokens[0]); |
|
628 |
+ continue; |
|
629 |
+ } |
|
630 |
+ |
|
626 | 631 |
hash = (uint8_t *)tokens[3]; |
627 | 632 |
if(cli_hexnibbles((char *)hash, 124)) { |
628 | 633 |
cli_errmsg("cli_loadidb: Malformed hash at line %u (bad chars)\n", line); |
... | ... |
@@ -892,6 +902,11 @@ static int cli_loadndb(FILE *fs, struct cl_engine *engine, unsigned int *signo, |
892 | 892 |
if(engine->ignored && cli_chkign(engine->ignored, virname, buffer_cpy)) |
893 | 893 |
continue; |
894 | 894 |
|
895 |
+ if(engine->cb_sigload && engine->cb_sigload("ndb", virname, engine->cb_sigload_ctx)) { |
|
896 |
+ cli_dbgmsg("cli_loadndb: skipping %s due to callback\n", virname); |
|
897 |
+ continue; |
|
898 |
+ } |
|
899 |
+ |
|
895 | 900 |
if(tokens_count > 4) { /* min version */ |
896 | 901 |
pt = tokens[4]; |
897 | 902 |
|
... | ... |
@@ -1195,6 +1210,11 @@ static int load_oneldb(char *buffer, int chkpua, int chkign, struct cl_engine *e |
1195 | 1195 |
if (chkign && cli_chkign(engine->ignored, virname, buffer_cpy)) |
1196 | 1196 |
return CL_SUCCESS; |
1197 | 1197 |
|
1198 |
+ if(engine->cb_sigload && engine->cb_sigload("ldb", virname, engine->cb_sigload_ctx)) { |
|
1199 |
+ cli_dbgmsg("cli_loadldb: skipping %s due to callback\n", virname); |
|
1200 |
+ return CL_SUCCESS; |
|
1201 |
+ } |
|
1202 |
+ |
|
1198 | 1203 |
subsigs = cli_ac_chklsig(logic, logic + strlen(logic), NULL, NULL, NULL, 1); |
1199 | 1204 |
if(subsigs == -1) { |
1200 | 1205 |
return CL_EMALFDB; |
... | ... |
@@ -1894,6 +1914,11 @@ static int cli_loadmd5(FILE *fs, struct cl_engine *engine, unsigned int *signo, |
1894 | 1894 |
if(engine->ignored && cli_chkign(engine->ignored, pt, buffer_cpy)) |
1895 | 1895 |
continue; |
1896 | 1896 |
|
1897 |
+ if(engine->cb_sigload && engine->cb_sigload("md5", pt, engine->cb_sigload_ctx)) { |
|
1898 |
+ cli_dbgmsg("cli_loadmd5: skipping %s due to callback\n", pt); |
|
1899 |
+ continue; |
|
1900 |
+ } |
|
1901 |
+ |
|
1897 | 1902 |
new = (struct cli_bm_patt *) mpool_calloc(engine->mempool, 1, sizeof(struct cli_bm_patt)); |
1898 | 1903 |
if(!new) { |
1899 | 1904 |
ret = CL_EMEM; |
... | ... |
@@ -2045,6 +2070,13 @@ static int cli_loadmd(FILE *fs, struct cl_engine *engine, unsigned int *signo, i |
2045 | 2045 |
continue; |
2046 | 2046 |
} |
2047 | 2047 |
|
2048 |
+ if(engine->cb_sigload && engine->cb_sigload("md", new->virname, engine->cb_sigload_ctx)) { |
|
2049 |
+ cli_dbgmsg("cli_loadmd: skipping %s due to callback\n", new->virname); |
|
2050 |
+ mpool_free(engine->mempool, new->virname); |
|
2051 |
+ mpool_free(engine->mempool, new); |
|
2052 |
+ continue; |
|
2053 |
+ } |
|
2054 |
+ |
|
2048 | 2055 |
new->encrypted = strcmp(tokens[1], "*") ? atoi(tokens[1]) : 2; |
2049 | 2056 |
|
2050 | 2057 |
if(strcmp(tokens[2], "*") && cli_regcomp(&new->name, tokens[2], REG_EXTENDED | REG_NOSUB)) { |
... | ... |
@@ -2178,6 +2210,13 @@ static int cli_loadcdb(FILE *fs, struct cl_engine *engine, unsigned int *signo, |
2178 | 2178 |
continue; |
2179 | 2179 |
} |
2180 | 2180 |
|
2181 |
+ if(engine->cb_sigload && engine->cb_sigload("cdb", new->virname, engine->cb_sigload_ctx)) { |
|
2182 |
+ cli_dbgmsg("cli_loadcdb: skipping %s due to callback\n", new->virname); |
|
2183 |
+ mpool_free(engine->mempool, new->virname); |
|
2184 |
+ mpool_free(engine->mempool, new); |
|
2185 |
+ continue; |
|
2186 |
+ } |
|
2187 |
+ |
|
2181 | 2188 |
if(!strcmp(tokens[1], "*")) { |
2182 | 2189 |
new->ctype = CL_TYPE_ANY; |
2183 | 2190 |
} else if((new->ctype = cli_ftcode(tokens[1])) == CL_TYPE_ERROR) { |
... | ... |
@@ -1894,9 +1894,25 @@ static void emax_reached(cli_ctx *ctx) { |
1894 | 1894 |
#define LINESTR(x) #x |
1895 | 1895 |
#define LINESTR2(x) LINESTR(x) |
1896 | 1896 |
#define __AT__ " at line "LINESTR2(__LINE__) |
1897 |
-#define ret_from_magicscan(retcode) do { \ |
|
1898 |
- cli_dbgmsg("cli_magic_scandesc: returning %d %s\n", retcode, __AT__); \ |
|
1899 |
- return retcode; \ |
|
1897 |
+#define ret_from_magicscan(retcode) do { \ |
|
1898 |
+ cli_dbgmsg("cli_magic_scandesc: returning %d %s\n", retcode, __AT__); \ |
|
1899 |
+ if(ctx->engine->cb_post_scan) { \ |
|
1900 |
+ switch(ctx->engine->cb_post_scan(desc, retcode, ctx->engine->cb_post_scan_ctx)) { \ |
|
1901 |
+ case CL_BREAK: \ |
|
1902 |
+ cli_dbgmsg("cli_magic_scandesc: file whitelisted by callback\n"); \ |
|
1903 |
+ return CL_CLEAN; \ |
|
1904 |
+ case CL_VIRUS: \ |
|
1905 |
+ cli_dbgmsg("cli_magic_scandesc: file blacklisted by callback\n"); \ |
|
1906 |
+ if(ctx->virname) \ |
|
1907 |
+ *ctx->virname = "Detected.By.Callback"; \ |
|
1908 |
+ return CL_VIRUS; \ |
|
1909 |
+ case CL_CLEAN: \ |
|
1910 |
+ break; \ |
|
1911 |
+ default: \ |
|
1912 |
+ cli_warnmsg("cli_magic_scandesc: ignoring bad return code from callback\n"); \ |
|
1913 |
+ } \ |
|
1914 |
+ } \ |
|
1915 |
+ return retcode; \ |
|
1900 | 1916 |
} while(0) |
1901 | 1917 |
|
1902 | 1918 |
int cli_magic_scandesc(int desc, cli_ctx *ctx) |
... | ... |
@@ -1953,6 +1969,27 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx) |
1953 | 1953 |
ret_from_magicscan(CL_EMEM); |
1954 | 1954 |
} |
1955 | 1955 |
|
1956 |
+ if(ctx->engine->cb_pre_scan) { |
|
1957 |
+ switch(ctx->engine->cb_pre_scan(desc, ctx->engine->cb_pre_scan_ctx)) { |
|
1958 |
+ case CL_BREAK: |
|
1959 |
+ cli_dbgmsg("cli_magic_scandesc: file whitelisted by callback\n"); |
|
1960 |
+ funmap(*ctx->fmap); |
|
1961 |
+ ctx->fmap--; |
|
1962 |
+ ret_from_magicscan(CL_CLEAN); |
|
1963 |
+ case CL_VIRUS: |
|
1964 |
+ cli_dbgmsg("cli_magic_scandesc: file blacklisted by callback\n"); |
|
1965 |
+ if(ctx->virname) |
|
1966 |
+ *ctx->virname = "Detected.By.Callback"; |
|
1967 |
+ funmap(*ctx->fmap); |
|
1968 |
+ ctx->fmap--; |
|
1969 |
+ ret_from_magicscan(CL_VIRUS); |
|
1970 |
+ case CL_CLEAN: |
|
1971 |
+ break; |
|
1972 |
+ default: |
|
1973 |
+ cli_warnmsg("cli_magic_scandesc: ignoring bad return code from callback\n"); |
|
1974 |
+ } |
|
1975 |
+ } |
|
1976 |
+ |
|
1956 | 1977 |
if(cache_check(hash, ctx) == CL_CLEAN) { |
1957 | 1978 |
funmap(*ctx->fmap); |
1958 | 1979 |
ctx->fmap--; |