]> source.dussan.org Git - rspamd.git/commitdiff
[Feature] Allow to save and show attachment name when inserting AV scan results
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Fri, 6 Aug 2021 11:42:06 +0000 (12:42 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Fri, 6 Aug 2021 11:42:06 +0000 (12:42 +0100)
13 files changed:
lualib/lua_scanners/avast.lua
lualib/lua_scanners/clamav.lua
lualib/lua_scanners/common.lua
lualib/lua_scanners/fprot.lua
lualib/lua_scanners/icap.lua
lualib/lua_scanners/kaspersky_av.lua
lualib/lua_scanners/kaspersky_se.lua
lualib/lua_scanners/oletools.lua
lualib/lua_scanners/sophos.lua
lualib/lua_scanners/vadesecure.lua
lualib/lua_scanners/virustotal.lua
src/plugins/lua/antivirus.lua
src/plugins/lua/mime_types.lua

index 16c838dbc2b3bcded92148e9f4d407f526cddf11..da8e6d7109dbdbece827736127c3c64b7af8961a 100644 (file)
@@ -81,7 +81,7 @@ local function avast_config(opts)
   return nil
 end
 
-local function avast_check(task, content, digest, rule)
+local function avast_check(task, content, digest, rule, maybe_part)
   local function avast_check_uncached ()
     local upstream = rule.upstreams:get_upstream_round_robin()
     local addr = upstream:get_addr()
@@ -148,7 +148,7 @@ local function avast_check(task, content, digest, rule)
             '%s [%s]: failed to scan, maximum retransmits exceed',
             rule['symbol'], rule['type'])
         common.yield_result(task, rule, 'failed to scan and retransmits exceed',
-            0.0, 'fail')
+            0.0, 'fail', maybe_part)
 
         return
       end
@@ -251,7 +251,7 @@ local function avast_check(task, content, digest, rule)
 
                 if vname then
                   vname = vname:gsub('\\ ', ' '):gsub('\\\\', '\\')
-                  common.yield_result(task, rule, vname)
+                  common.yield_result(task, rule, vname, 1.0, nil, maybe_part)
                   cached = vname
                 end
               end
@@ -263,12 +263,12 @@ local function avast_check(task, content, digest, rule)
               if ret then
                 rspamd_logger.errx(task, '%s: error: %s', rule.log_prefix, ret[1][2])
                 common.yield_result(task, rule, 'error:' .. ret[1][2],
-                    0.0, 'fail')
+                    0.0, 'fail', maybe_part)
               end
             end
 
             if cached then
-              common.save_cache(task, digest, rule, cached)
+              common.save_cache(task, digest, rule, cached, 1.0, maybe_part)
             else
               -- Unexpected reply
               rspamd_logger.errx(task, '%s: unexpected reply: %s', rule.log_prefix, mdata)
@@ -286,7 +286,8 @@ local function avast_check(task, content, digest, rule)
     maybe_retransmit()
   end
 
-  if common.condition_check_and_continue(task, content, rule, digest, avast_check_uncached) then
+  if common.condition_check_and_continue(task, content, rule, digest,
+      avast_check_uncached, maybe_part) then
     return
   else
     avast_check_uncached()
index 7c56f57982e3f5e09c0a0a933504bd4078919867..bc090036c3c16cd15b705e52ce27f3a18327c2d8 100644 (file)
@@ -79,7 +79,7 @@ local function clamav_config(opts)
   return nil
 end
 
-local function clamav_check(task, content, digest, rule)
+local function clamav_check(task, content, digest, rule, maybe_part)
   local function clamav_check_uncached ()
     local upstream = rule.upstreams:get_upstream_round_robin()
     local addr = upstream:get_addr()
@@ -117,7 +117,9 @@ local function clamav_check(task, content, digest, rule)
           })
         else
           rspamd_logger.errx(task, '%s: failed to scan, maximum retransmits exceed', rule.log_prefix)
-          common.yield_result(task, rule, 'failed to scan and retransmits exceed', 0.0, 'fail')
+          common.yield_result(task, rule,
+              'failed to scan and retransmits exceed', 0.0, 'fail',
+              maybe_part)
         end
 
       else
@@ -138,25 +140,28 @@ local function clamav_check(task, content, digest, rule)
           local vname = string.match(data, 'stream: (.+) FOUND')
           if string.find(vname, '^Heuristics%.Encrypted') then
             rspamd_logger.errx(task, '%s: File is encrypted', rule.log_prefix)
-            common.yield_result(task, rule, 'File is encrypted: '.. vname, 0.0, 'encrypted')
+            common.yield_result(task, rule, 'File is encrypted: '.. vname,
+                0.0, 'encrypted', maybe_part)
             cached = 'ENCRYPTED'
           elseif string.find(vname, '^Heuristics%.OLE2%.ContainsMacros') then
             rspamd_logger.errx(task, '%s: ClamAV Found an OLE2 Office Macro', rule.log_prefix)
-            common.yield_result(task, rule, vname, 0.0, 'macro')
+            common.yield_result(task, rule, vname, 0.0, 'macro', maybe_part)
             cached = 'MACRO'
           elseif string.find(vname, '^Heuristics%.Limits%.Exceeded') then
             rspamd_logger.errx(task, '%s: ClamAV Limits Exceeded', rule.log_prefix)
-            common.yield_result(task, rule, 'Limits Exceeded: '.. vname, 0.0, 'fail')
+            common.yield_result(task, rule, 'Limits Exceeded: '.. vname, 0.0,
+                'fail', maybe_part)
           elseif vname then
-            common.yield_result(task, rule, vname)
+            common.yield_result(task, rule, vname, 1.0, nil, maybe_part)
             cached = vname
           else
             rspamd_logger.errx(task, '%s: unhandled response: %s', rule.log_prefix, data)
-            common.yield_result(task, rule, 'unhandled response:' .. vname, 0.0, 'fail')
+            common.yield_result(task, rule, 'unhandled response:' .. vname, 0.0,
+                'fail', maybe_part)
           end
         end
         if cached then
-          common.save_cache(task, digest, rule, cached)
+          common.save_cache(task, digest, rule, cached, 1.0, maybe_part)
         end
       end
     end
@@ -172,7 +177,8 @@ local function clamav_check(task, content, digest, rule)
     })
   end
 
-  if common.condition_check_and_continue(task, content, rule, digest, clamav_check_uncached) then
+  if common.condition_check_and_continue(task, content, rule, digest,
+      clamav_check_uncached, maybe_part) then
     return
   else
     clamav_check_uncached()
index 67952923d7ff89f4933fa896186d5a20e86a367e..bbad123f50116b293685d3f733ec10706e716f73 100644 (file)
@@ -62,14 +62,21 @@ local function match_patterns(default_sym, found, patterns, dyn_weight)
   end
 end
 
-local function yield_result(task, rule, vname, dyn_weight, is_fail)
+local function yield_result(task, rule, vname, dyn_weight, is_fail, maybe_part)
   local all_whitelisted = true
   local patterns
   local symbol
-  local threat_table = {}
+  local threat_table
   local threat_info
   local flags
 
+  if type(vname) == 'string' then
+    threat_table = {vname}
+  elseif type(vname) == 'table' then
+    threat_table = vname
+  end
+
+
   -- This should be more generic
   if not is_fail then
     patterns = rule.patterns
@@ -93,11 +100,6 @@ local function yield_result(task, rule, vname, dyn_weight, is_fail)
     dyn_weight = 1.0
   end
 
-  if type(vname) == 'string' then
-    table.insert(threat_table, vname)
-  elseif type(vname) == 'table' then
-    threat_table = vname
-  end
 
   for _, tm in ipairs(threat_table) do
     local symname, symscore = match_patterns(symbol, tm, patterns, dyn_weight)
@@ -107,7 +109,15 @@ local function yield_result(task, rule, vname, dyn_weight, is_fail)
       all_whitelisted = false
       rspamd_logger.infox(task, '%s: result - %s: "%s - score: %s"',
           rule.log_prefix, threat_info, tm, symscore)
-      task:insert_result(symname, symscore, tm)
+
+      if maybe_part and rule.show_attachments and maybe_part:get_filename() then
+        local fname = maybe_part:get_filename()
+        task:insert_result(symname, symscore, string.format("%s|%s",
+            tm, fname))
+      else
+        task:insert_result(symname, symscore, tm)
+      end
+
     end
   end
 
@@ -196,7 +206,7 @@ local function dynamic_scan(task, rule)
   end
 end
 
-local function need_check(task, content, rule, digest, fn)
+local function need_check(task, content, rule, digest, fn, maybe_part)
 
   local uncached = true
   local key = digest
@@ -207,15 +217,18 @@ local function need_check(task, content, rule, digest, fn)
       data = lua_util.str_split(data, '\t')
       local threat_string = lua_util.str_split(data[1], '\v')
       local score = data[2] or rule.default_score
+
       if threat_string[1] ~= 'OK' then
         if threat_string[1] == 'MACRO' then
-          yield_result(task, rule, 'File contains macros', 0.0, 'macro')
+          yield_result(task, rule, 'File contains macros',
+              0.0, 'macro', maybe_part)
         elseif threat_string[1] == 'ENCRYPTED' then
-          yield_result(task, rule, 'File is encrypted', 0.0, 'encrypted')
+          yield_result(task, rule, 'File is encrypted',
+              0.0, 'encrypted', maybe_part)
         else
           lua_util.debugm(rule.name, task, '%s: got cached threat result for %s: %s - score: %s',
               rule.log_prefix, key, threat_string[1], score)
-          yield_result(task, rule, threat_string, score)
+          yield_result(task, rule, threat_string, score, false, maybe_part)
         end
 
       else
@@ -266,7 +279,7 @@ local function need_check(task, content, rule, digest, fn)
 
 end
 
-local function save_cache(task, digest, rule, to_save, dyn_weight)
+local function save_cache(task, digest, rule, to_save, dyn_weight, maybe_part)
   local key = digest
   if not dyn_weight then dyn_weight = 1.0 end
 
@@ -285,7 +298,12 @@ local function save_cache(task, digest, rule, to_save, dyn_weight)
     to_save = table.concat(to_save, '\v')
   end
 
-  local value = table.concat({to_save, dyn_weight}, '\t')
+  local value_tbl = {to_save, dyn_weight}
+  if maybe_part and rule.show_attachments and maybe_part:get_filename() then
+    local fname = maybe_part:get_filename()
+    table.insert(value_tbl, fname)
+  end
+  local value = table.concat(value_tbl, '\t')
 
   if rule.redis_params and rule.prefix then
     key = rule.prefix .. key
index 8baaeeddef07418db2975d3ebb77297c69cceaee..4c416524c0e68e01d4857e51813c79e85e2866f8 100644 (file)
@@ -78,7 +78,7 @@ local function fprot_config(opts)
   return nil
 end
 
-local function fprot_check(task, content, digest, rule)
+local function fprot_check(task, content, digest, rule, maybe_part)
   local function fprot_check_uncached ()
     local upstream = rule.upstreams:get_upstream_round_robin()
     local addr = upstream:get_addr()
@@ -119,7 +119,8 @@ local function fprot_check(task, content, digest, rule)
           rspamd_logger.errx(task,
               '%s [%s]: failed to scan, maximum retransmits exceed',
               rule['symbol'], rule['type'])
-          common.yield_result(task, rule, 'failed to scan and retransmits exceed', 0.0, 'fail')
+          common.yield_result(task, rule, 'failed to scan and retransmits exceed',
+              0.0, 'fail', maybe_part)
         end
       else
         upstream:ok()
@@ -140,12 +141,12 @@ local function fprot_check(task, content, digest, rule)
           if not vname then
             rspamd_logger.errx(task, 'Unhandled response: %s', data)
           else
-            common.yield_result(task, rule, vname)
+            common.yield_result(task, rule, vname, 1.0, nil, maybe_part)
             cached = vname
           end
         end
         if cached then
-          common.save_cache(task, digest, rule, cached)
+          common.save_cache(task, digest, rule, cached, 1.0, maybe_part)
         end
       end
     end
@@ -161,7 +162,8 @@ local function fprot_check(task, content, digest, rule)
     })
   end
 
-  if common.condition_check_and_continue(task, content, rule, digest, fprot_check_uncached) then
+  if common.condition_check_and_continue(task, content, rule, digest,
+      fprot_check_uncached, maybe_part) then
     return
   else
     fprot_check_uncached()
index af9d070dc73315f0506ecc0c1c203a53c5381b4a..86def8eddcc91ebf14308089e971a564bd10b09b 100644 (file)
@@ -98,7 +98,7 @@ local function icap_config(opts)
   return nil
 end
 
-local function icap_check(task, content, digest, rule)
+local function icap_check(task, content, digest, rule, maybe_part)
   local function icap_check_uncached ()
     local upstream = rule.upstreams:get_upstream_round_robin()
     local addr = upstream:get_addr()
@@ -162,7 +162,8 @@ local function icap_check(task, content, digest, rule)
         else
           rspamd_logger.errx(task, '%s: failed to scan, maximum retransmits '..
             'exceed - error: %s', rule.log_prefix, err_m or '')
-          common.yield_result(task, rule, 'failed - error: ' .. err_m or '', 0.0, 'fail')
+          common.yield_result(task, rule, 'failed - error: ' .. err_m or '',
+              0.0, 'fail', maybe_part)
         end
       end
 
@@ -248,7 +249,8 @@ local function icap_check(task, content, digest, rule)
             -- error returned
             lua_util.debugm(rule.name, task,
                 '%s: icap error X-Infection-Found: %s', rule.log_prefix, icap_threat)
-            common.yield_result(task, rule, icap_threat, 0, 'fail')
+            common.yield_result(task, rule, icap_threat, 0,
+                'fail', maybe_part)
           else
             lua_util.debugm(rule.name, task,
                 '%s: icap X-Infection-Found: %s', rule.log_prefix, icap_threat)
@@ -295,10 +297,10 @@ local function icap_check(task, content, digest, rule)
           end
         end
         if #threat_string > 0 then
-          common.yield_result(task, rule, threat_string, rule.default_score)
-          common.save_cache(task, digest, rule, threat_string, rule.default_score)
+          common.yield_result(task, rule, threat_string, rule.default_score, nil, maybe_part)
+          common.save_cache(task, digest, rule, threat_string, rule.default_score, maybe_part)
         else
-          common.save_cache(task, digest, rule, 'OK', 0)
+          common.save_cache(task, digest, rule, 'OK', 0, maybe_part)
           common.log_clean(task, rule)
         end
       end
@@ -323,12 +325,15 @@ local function icap_check(task, content, digest, rule)
               ICAP/1.0 500 Server error
             ]]--
             rspamd_logger.errx(task, '%s: ICAP ERROR: %s', rule.log_prefix, icap_headers.icap)
-            common.yield_result(task, rule, icap_headers.icap, 0.0, 'fail')
+            common.yield_result(task, rule, icap_headers.icap, 0.0,
+                'fail', maybe_part)
             return false
           else
             rspamd_logger.errx(task, '%s: unhandled response |%s|',
               rule.log_prefix, string.gsub(result, "\r\n", ", "))
-            common.yield_result(task, rule, 'unhandled icap response: ' .. icap_headers.icap or "-", 0.0, 'fail')
+            common.yield_result(task, rule,
+                'unhandled icap response: ' .. icap_headers.icap or "-",
+                0.0, 'fail', maybe_part)
           end
         end
       end
@@ -371,12 +376,14 @@ local function icap_check(task, content, digest, rule)
             else
               rspamd_logger.errx(task, '%s: RESPMOD method not advertised: Methods: %s',
                 rule.log_prefix, icap_headers['Methods'])
-              common.yield_result(task, rule, 'NO RESPMOD', 0.0, 'fail')
+              common.yield_result(task, rule, 'NO RESPMOD', 0.0,
+                  'fail', maybe_part)
             end
           else
             rspamd_logger.errx(task, '%s: OPTIONS query failed: %s',
               rule.log_prefix, icap_headers.icap or "-")
-            common.yield_result(task, rule, 'OPTIONS query failed', 0.0, 'fail')
+            common.yield_result(task, rule, 'OPTIONS query failed', 0.0,
+                'fail', maybe_part)
           end
         end
       end
@@ -402,7 +409,8 @@ local function icap_check(task, content, digest, rule)
     })
   end
 
-  if common.condition_check_and_continue(task, content, rule, digest, icap_check_uncached) then
+  if common.condition_check_and_continue(task, content, rule, digest,
+      icap_check_uncached, maybe_part) then
     return
   else
     icap_check_uncached()
index 4bdbdbbfdd49ef2224214d048f1fd29ad61c306d..c07a910cdba91fc25855d1dcb5679e278b49e515 100644 (file)
@@ -79,7 +79,7 @@ local function kaspersky_config(opts)
   return nil
 end
 
-local function kaspersky_check(task, content, digest, rule)
+local function kaspersky_check(task, content, digest, rule, maybe_part)
   local function kaspersky_check_uncached ()
     local upstream = rule.upstreams:get_upstream_round_robin()
     local addr = upstream:get_addr()
@@ -138,7 +138,9 @@ local function kaspersky_check(task, content, digest, rule)
           rspamd_logger.errx(task,
               '%s [%s]: failed to scan, maximum retransmits exceed',
               rule['symbol'], rule['type'])
-          common.yield_result(task, rule, 'failed to scan and retransmits exceed', 0.0, 'fail')
+          common.yield_result(task, rule,
+              'failed to scan and retransmits exceed', 0.0, 'fail',
+              maybe_part)
         end
 
       else
@@ -154,15 +156,16 @@ local function kaspersky_check(task, content, digest, rule)
         else
           local vname = string.match(data, ': (.+) FOUND')
           if vname then
-            common.yield_result(task, rule, vname)
+            common.yield_result(task, rule, vname, 1.0, nil, maybe_part)
             cached = vname
           else
             rspamd_logger.errx(task, 'unhandled response: %s', data)
-            common.yield_result(task, rule, 'unhandled response', 0.0, 'fail')
+            common.yield_result(task, rule, 'unhandled response',
+                0.0, 'fail', maybe_part)
           end
         end
         if cached then
-          common.save_cache(task, digest, rule, cached)
+          common.save_cache(task, digest, rule, cached, 1.0, maybe_part)
         end
       end
     end
@@ -178,7 +181,8 @@ local function kaspersky_check(task, content, digest, rule)
     })
   end
 
-  if common.condition_check_and_continue(task, content, rule, digest, kaspersky_check_uncached) then
+  if common.condition_check_and_continue(task, content, rule, digest,
+      kaspersky_check_uncached, maybe_part) then
     return
   else
     kaspersky_check_uncached()
index cac604016b3102a2a610ae8d9fb40548f5eb749c..bf1fb956836d102f22990e7f0d3696fc44011396 100644 (file)
@@ -88,7 +88,7 @@ local function kaspersky_se_config(opts)
   return nil
 end
 
-local function kaspersky_se_check(task, content, digest, rule)
+local function kaspersky_se_check(task, content, digest, rule, maybe_part)
   local function kaspersky_se_check_uncached()
     local function make_url(addr)
       local url
@@ -220,19 +220,21 @@ local function kaspersky_se_check(task, content, digest, rule)
                   rule.log_prefix)
             end
           elseif data == 'CLEAN AND CONTAINS OFFICE MACRO' then
-            common.yield_result(task, rule, 'File contains macros', 0.0, 'macro')
+            common.yield_result(task, rule, 'File contains macros',
+                0.0, 'macro', maybe_part)
             cached = 'MACRO'
           else
             rspamd_logger.errx(task, '%s: unhandled clean response: %s', rule.log_prefix, data)
-            common.yield_result(task, rule, 'unhandled response:' .. data, 0.0, 'fail')
+            common.yield_result(task, rule, 'unhandled response:' .. data,
+                0.0, 'fail', maybe_part)
           end
         elseif data == 'SERVER_ERROR' then
           rspamd_logger.errx(task, '%s: error: %s', rule.log_prefix, data)
           common.yield_result(task, rule, 'error:' .. data,
-              0.0, 'fail')
+              0.0, 'fail', maybe_part)
         elseif string.match(data, 'DETECT (.+)') then
           local vname = string.match(data, 'DETECT (.+)')
-          common.yield_result(task, rule, vname)
+          common.yield_result(task, rule, vname, 1.0, nil, maybe_part)
           cached = vname
         elseif string.match(data, 'NON_SCANNED %((.+)%)') then
           local why = string.match(data, 'NON_SCANNED %((.+)%)')
@@ -240,18 +242,20 @@ local function kaspersky_se_check(task, content, digest, rule)
           if why == 'PASSWORD PROTECTED' then
             rspamd_logger.errx(task, '%s: File is encrypted', rule.log_prefix)
             common.yield_result(task, rule, 'File is encrypted: '.. why,
-                0.0, 'encrypted')
+                0.0, 'encrypted', maybe_part)
             cached = 'ENCRYPTED'
           else
-            common.yield_result(task, rule, 'unhandled response:' .. data, 0.0, 'fail')
+            common.yield_result(task, rule, 'unhandled response:' .. data,
+                0.0, 'fail', maybe_part)
           end
         else
           rspamd_logger.errx(task, '%s: unhandled response: %s', rule.log_prefix, data)
-          common.yield_result(task, rule, 'unhandled response:' .. data, 0.0, 'fail')
+          common.yield_result(task, rule, 'unhandled response:' .. data,
+              0.0, 'fail', maybe_part)
         end
 
         if cached then
-          common.save_cache(task, digest, rule, cached)
+          common.save_cache(task, digest, rule, cached, 1.0, maybe_part)
         end
 
       end
@@ -262,7 +266,7 @@ local function kaspersky_se_check(task, content, digest, rule)
   end
 
   if common.condition_check_and_continue(task, content, rule, digest,
-      kaspersky_se_check_uncached) then
+      kaspersky_se_check_uncached, maybe_part) then
     return
   else
 
index 1121b322649abf1fdf5a4cad934ab546402ff7a6..e76a25911c751cbb67bcd35af21b88868cd0c7b4 100644 (file)
@@ -87,7 +87,7 @@ local function oletools_config(opts)
   return nil
 end
 
-local function oletools_check(task, content, digest, rule)
+local function oletools_check(task, content, digest, rule, maybe_part)
   local function oletools_check_uncached ()
     local upstream = rule.upstreams:get_upstream_round_robin()
     local addr = upstream:get_addr()
@@ -125,7 +125,9 @@ local function oletools_check(task, content, digest, rule)
         else
           rspamd_logger.errx(task, '%s: failed to scan, maximum retransmits '..
               'exceed - err: %s', rule.log_prefix, error)
-          common.yield_result(task, rule, 'failed to scan, maximum retransmits exceed - err: ' .. error, 0.0, 'fail')
+          common.yield_result(task, rule,
+              'failed to scan, maximum retransmits exceed - err: ' .. error,
+              0.0, 'fail', maybe_part)
         end
       end
 
@@ -191,7 +193,7 @@ local function oletools_check(task, content, digest, rule)
               rspamd_logger.errx(task, '%s: ERROR found: %s', rule.log_prefix,
                   v.error)
               if v.error == 'File too small' then
-                common.save_cache(task, digest, rule, 'OK')
+                common.save_cache(task, digest, rule, 'OK', 1.0, maybe_part)
                 common.log_clean(task, rule, 'File too small to be scanned for macros')
                 return
               else
@@ -210,20 +212,26 @@ local function oletools_check(task, content, digest, rule)
               local oletools_rc_code = tonumber(v.return_code)
               if oletools_rc_code == 9 then
                 rspamd_logger.warnx(task, '%s: File is encrypted.', rule.log_prefix)
-                common.yield_result(task, rule, 'failed - err: ' .. oletools_rc[oletools_rc_code], 0.0, 'encrypted')
-                common.save_cache(task, digest, rule, 'encrypted')
+                common.yield_result(task, rule,
+                    'failed - err: ' .. oletools_rc[oletools_rc_code],
+                    0.0, 'encrypted', maybe_part)
+                common.save_cache(task, digest, rule, 'encrypted', 1.0, maybe_part)
                 return
               elseif oletools_rc_code == 5 then
                 rspamd_logger.warnx(task, '%s: olefy could not open the file - error: %s', rule.log_prefix,
                     result[2]['message'])
-                common.yield_result(task, rule, 'failed - err: ' .. oletools_rc[oletools_rc_code], 0.0, 'fail')
+                common.yield_result(task, rule,
+                    'failed - err: ' .. oletools_rc[oletools_rc_code],
+                    0.0, 'fail', maybe_part)
                 return
               elseif oletools_rc_code > 6 then
                 rspamd_logger.errx(task, '%s: MetaInfo section error code: %s',
                     rule.log_prefix, oletools_rc[oletools_rc_code])
                 rspamd_logger.errx(task, '%s: MetaInfo section message: %s',
                     rule.log_prefix, result[2]['message'])
-                common.yield_result(task, rule, 'failed - err: ' .. oletools_rc[oletools_rc_code], 0.0, 'fail')
+                common.yield_result(task, rule,
+                    'failed - err: ' .. oletools_rc[oletools_rc_code],
+                    0.0, 'fail', maybe_part)
                 return
               elseif oletools_rc_code > 1 then
                 rspamd_logger.errx(task, '%s: Error message: %s',
@@ -296,8 +304,8 @@ local function oletools_check(task, content, digest, rule)
             -- use single string as virus name
             local threat = 'AutoExec + Suspicious (' .. table.concat(analysis_keyword_table, ',') .. ')'
             lua_util.debugm(rule.name, task, '%s: threat result: %s', rule.log_prefix, threat)
-            common.yield_result(task, rule, threat, rule.default_score)
-            common.save_cache(task, digest, rule, threat, rule.default_score)
+            common.yield_result(task, rule, threat, rule.default_score, nil, maybe_part)
+            common.save_cache(task, digest, rule, threat, rule.default_score, maybe_part)
 
           elseif rule.extended == true and #analysis_keyword_table > 0 then
             -- report any flags (types) and any most keywords as individual virus name
@@ -317,15 +325,17 @@ local function oletools_check(task, content, digest, rule)
             lua_util.debugm(rule.name, task, '%s: extended threat result: %s',
                 rule.log_prefix, table.concat(analysis_keyword_table, ','))
 
-            common.yield_result(task, rule, analysis_keyword_table, rule.default_score)
-            common.save_cache(task, digest, rule, analysis_keyword_table, rule.default_score)
+            common.yield_result(task, rule, analysis_keyword_table,
+                rule.default_score, nil, maybe_part)
+            common.save_cache(task, digest, rule, analysis_keyword_table,
+                rule.default_score, maybe_part)
 
           elseif analysis_cat_table.macro_exist == '-' and #analysis_keyword_table == 0 then
-            common.save_cache(task, digest, rule, 'OK')
+            common.save_cache(task, digest, rule, 'OK', 1.0, maybe_part)
             common.log_clean(task, rule, 'No macro found')
 
           else
-            common.save_cache(task, digest, rule, 'OK')
+            common.save_cache(task, digest, rule, 'OK', 1.0, maybe_part)
             common.log_clean(task, rule, 'Scanned Macro is OK')
           end
         end
@@ -344,7 +354,8 @@ local function oletools_check(task, content, digest, rule)
 
   end
 
-  if common.condition_check_and_continue(task, content, rule, digest, oletools_check_uncached) then
+  if common.condition_check_and_continue(task, content, rule, digest,
+      oletools_check_uncached, maybe_part) then
     return
   else
     oletools_check_uncached()
index bfc1644ac92c14ffd4baecbde3dd151c7dd16f60..36ebe417715be8a55cd882ab855bc1035f5f6d30 100644 (file)
@@ -78,7 +78,7 @@ local function sophos_config(opts)
   return nil
 end
 
-local function sophos_check(task, content, digest, rule)
+local function sophos_check(task, content, digest, rule, maybe_part)
   local function sophos_check_uncached ()
     local upstream = rule.upstreams:get_upstream_round_robin()
     local addr = upstream:get_addr()
@@ -115,7 +115,8 @@ local function sophos_check(task, content, digest, rule)
           })
         else
           rspamd_logger.errx(task, '%s [%s]: failed to scan, maximum retransmits exceed', rule['symbol'], rule['type'])
-          common.yield_result(task, rule, 'failed to scan and retransmits exceed', 0.0, 'fail')
+          common.yield_result(task, rule, 'failed to scan and retransmits exceed',
+              0.0, 'fail', maybe_part)
         end
       else
         upstream:ok()
@@ -125,8 +126,8 @@ local function sophos_check(task, content, digest, rule)
         local vname = string.match(data, 'VIRUS (%S+) ')
         local cached
         if vname then
-          common.yield_result(task, rule, vname)
-          common.save_cache(task, digest, rule, vname)
+          common.yield_result(task, rule, vname, 1.0, nil, maybe_part)
+          common.save_cache(task, digest, rule, vname, 1.0, maybe_part)
         else
           if string.find(data, 'DONE OK') then
             if rule['log_clean'] then
@@ -141,21 +142,25 @@ local function sophos_check(task, content, digest, rule)
             conn:add_read(sophos_callback)
           elseif string.find(data, 'FAIL 0212') then
             rspamd_logger.warnx(task, 'Message is encrypted (FAIL 0212): %s', data)
-            common.yield_result(task, rule, 'SAVDI: Message is encrypted (FAIL 0212)', 0.0, 'encrypted')
+            common.yield_result(task, rule, 'SAVDI: Message is encrypted (FAIL 0212)',
+                0.0, 'encrypted', maybe_part)
             cached = 'ENCRYPTED'
           elseif string.find(data, 'REJ 4') then
             rspamd_logger.warnx(task, 'Message is oversized (REJ 4): %s', data)
-            common.yield_result(task, rule, 'SAVDI: Message oversized (REJ 4)', 0.0, 'fail')
+            common.yield_result(task, rule, 'SAVDI: Message oversized (REJ 4)',
+                0.0, 'fail', maybe_part)
             -- excplicitly set REJ1 message when SAVDIreports a protocol error
           elseif string.find(data, 'REJ 1') then
             rspamd_logger.errx(task, 'SAVDI (Protocol error (REJ 1)): %s', data)
-            common.yield_result(task, rule, 'SAVDI: Protocol error (REJ 1)', 0.0, 'fail')
+            common.yield_result(task, rule, 'SAVDI: Protocol error (REJ 1)',
+                0.0, 'fail', maybe_part)
           else
             rspamd_logger.errx(task, 'unhandled response: %s', data)
-            common.yield_result(task, rule, 'unhandled response: ' .. data, 0.0, 'fail')
+            common.yield_result(task, rule, 'unhandled response: ' .. data,
+                0.0, 'fail', maybe_part)
           end
           if cached then
-            common.save_cache(task, digest, rule, cached)
+            common.save_cache(task, digest, rule, cached, 1.0, maybe_part)
           end
         end
       end
@@ -171,7 +176,8 @@ local function sophos_check(task, content, digest, rule)
     })
   end
 
-  if common.condition_check_and_continue(task, content, rule, digest, sophos_check_uncached) then
+  if common.condition_check_and_continue(task, content, rule, digest,
+      sophos_check_uncached, maybe_part) then
     return
   else
     sophos_check_uncached()
index cbad42d4fe4e420147a825f2d8fc21e130e3abf9..158eedb1a806cbd235bd3e8111ae9142076bcbce 100644 (file)
@@ -152,7 +152,7 @@ local function vade_config(opts)
   return nil
 end
 
-local function vade_check(task, content, digest, rule)
+local function vade_check(task, content, digest, rule, maybe_part)
   local function vade_check_uncached()
     local function vade_url(addr)
       local url
@@ -331,7 +331,8 @@ local function vade_check(task, content, digest, rule)
     http.request(request_data)
   end
 
-  if common.condition_check_and_continue(task, content, rule, digest, vade_check_uncached) then
+  if common.condition_check_and_continue(task, content, rule, digest,
+      vade_check_uncached, maybe_part) then
     return
   else
     vade_check_uncached()
index 6bbdf94fd1767927ead499777b9b3751dc7c5154..8c5d71dbbc07aeaeea79ac57051756fdc09db9fb 100644 (file)
@@ -74,7 +74,7 @@ local function virustotal_config(opts)
   return default_conf
 end
 
-local function virustotal_check(task, content, digest, rule)
+local function virustotal_check(task, content, digest, rule, maybe_part)
   local function virustotal_check_uncached()
     local function make_url(hash)
       return string.format('%s/report?apikey=%s&resource=%s',
@@ -172,7 +172,7 @@ local function virustotal_check(task, content, digest, rule)
                 end
                 local sopt = string.format("%s:%s/%s",
                     hash, obj.positives, obj.total)
-                common.yield_result(task, rule, sopt, dyn_score)
+                common.yield_result(task, rule, sopt, dyn_score, nil, maybe_part)
                 cached = sopt
               end
             end
@@ -186,7 +186,7 @@ local function virustotal_check(task, content, digest, rule)
         end
 
         if cached then
-          common.save_cache(task, digest, rule, cached, dyn_score)
+          common.save_cache(task, digest, rule, cached, dyn_score, maybe_part)
         end
       end
     end
index 18d41dbb602c5f0fc489d1480ef56f5039d9f237..56bd4b5205814a4fd53a75245e0b4f14f02c58c2 100644 (file)
@@ -136,7 +136,7 @@ local function add_antivirus_rule(sym, opts)
       fun.each(function(p)
         local content = p:get_content()
         if content and #content > 0 then
-          cfg.check(task, content, p:get_digest(), rule)
+          cfg.check(task, content, p:get_digest(), rule, p)
         end
       end, common.check_parts_match(task, rule))
 
@@ -266,7 +266,7 @@ if opts and type(opts) == 'table' then
               })
             end
           end
-        end        
+        end
         if m['score'] then
           -- Register metric symbol
           local description = 'antivirus symbol'
index 627c27f596c3b31edd1a485914fc7535e0a9917d..edfc6d0024b9d8f18955f5bc2f2a7fa43c2f4d24 100644 (file)
@@ -222,7 +222,8 @@ local function check_mime_type(task)
     end
 
     -- Decode hex encoded characters
-    fname = string.gsub(fname, '%%(%x%x)', function (hex) return string.char(tonumber(hex,16)) end )
+    fname = string.gsub(fname, '%%(%x%x)',
+        function (hex) return string.char(tonumber(hex,16)) end )
 
     -- Replace potentially bad characters with '?'
     fname = fname:gsub('[^%s%g]', '?')