--[[ Copyright (c) 2011-2015, Vsevolod Stakhov Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ]]-- -- Plugin for comparing smtp dialog recipients and sender with recipients and sender -- in mime headers if confighelp then return end local symbol_rcpt = 'FORGED_RECIPIENTS' local symbol_sender = 'FORGED_SENDER' local E = {} local function check_forged_headers(task) local auser = task:get_user() local delivered_to = task:get_header('Delivered-To') local smtp_rcpt = task:get_recipients(1) local smtp_from = task:get_from(1) local res local score = 1.0 if not smtp_rcpt then return end if #smtp_rcpt == 0 then return end local mime_rcpt = task:get_recipients(2) if not mime_rcpt then return elseif #mime_rcpt == 0 then return end -- Find pair for each smtp recipient in To or Cc headers for _,sr in ipairs(smtp_rcpt) do res = false for _,mr in ipairs(mime_rcpt) do if mr.addr and mr.addr ~= '' then if sr['addr'] and string.lower(mr['addr']) == string.lower(sr['addr']) then res = true break elseif delivered_to and delivered_to == mr['addr'] then -- allow alias expansion and forwarding (Postfix) res = true break elseif auser and auser == sr['addr'] then -- allow user to BCC themselves res = true break elseif ((smtp_from or E)[1] or E).addr and smtp_from[1]['addr'] == sr['addr'] then -- allow sender to BCC themselves res = true break elseif mr['user'] and sr['user'] and string.lower(mr['user']) == string.lower(sr['user']) then -- If we have the same username but for another domain, then -- lower the overall score score = score / 2 end else res = true end end if not res then local mra = mime_rcpt[1].addr .. (#mime_rcpt > 1 and ' ..' or '') local sra = smtp_rcpt[1].addr .. (#smtp_rcpt > 1 and ' ...' or '') task:insert_result(symbol_rcpt, score, mra, sra) break end end -- Check sender if smtp_from and smtp_from[1] and smtp_from[1]['addr'] ~= '' then local mime_from = task:get_from(2) if not mime_from or not mime_from[1] or not (string.lower(mime_from[1]['addr']) == string.lower(smtp_from[1]['addr'])) then task:insert_result(symbol_sender, 1, ((mime_from or E)[1] or E).addr or '', smtp_from[1].addr) end end end -- Configuration local opts = rspamd_config:get_all_opt('forged_recipients') if opts then if opts['symbol_rcpt'] or opts['symbol_sender'] then local id = rspamd_config:register_symbol({ name = 'FORGED_CALLBACK', callback = check_forged_headers, type = 'callback', group = 'headers', score = 0.0, }) if opts['symbol_rcpt'] then symbol_rcpt = opts['symbol_rcpt'] rspamd_config:register_symbol({ name = symbol_rcpt, type = 'virtual', parent = id, }) end if opts['symbol_sender'] then symbol_sender = opts['symbol_sender'] rspamd_config:register_symbol({ name = symbol_sender, type = 'virtual', parent = id, }) end end end