1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
--[[
Copyright (c) 2011-2015, Vsevolod Stakhov <vsevolod@highsecure.ru>
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
|