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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
|
--[[
Copyright (c) 2016, Andrew Lewis <nerf@judo.za.org>
Copyright (c) 2016, 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.
]]--
local lua_util = require "lua_util"
local rspamd_logger = require "rspamd_logger"
local dkim_sign_tools = require "lua_dkim_tools"
local lua_redis = require "lua_redis"
local lua_mime = require "lua_mime"
if confighelp then
return
end
local settings = {
allow_envfrom_empty = true,
allow_hdrfrom_mismatch = false,
allow_hdrfrom_mismatch_local = false,
allow_hdrfrom_mismatch_sign_networks = false,
allow_hdrfrom_multiple = false,
allow_username_mismatch = false,
allow_pubkey_mismatch = true,
sign_authenticated = true,
allowed_ids = nil,
forbidden_ids = nil,
check_pubkey = false,
domain = {},
path = string.format('%s/%s/%s', rspamd_paths['DBDIR'], 'dkim', '$domain.$selector.key'),
sign_local = true,
selector = 'dkim',
symbol = 'DKIM_SIGNED',
try_fallback = true,
use_domain = 'header',
use_esld = true,
use_redis = false,
key_prefix = 'dkim_keys', -- default hash name
use_milter_headers = false, -- use milter headers instead of `dkim_signature`
}
local N = 'dkim_signing'
local redis_params
local sign_func = rspamd_plugins.dkim.sign
local function insert_sign_results(task, ret, hdr, dkim_params)
if settings.use_milter_headers then
lua_mime.modify_headers(task, {
add = {
['DKIM-Signature'] = {order = 1, value = hdr},
}
})
end
if ret then
task:insert_result(settings.symbol, 1.0, string.format('%s:s=%s',
dkim_params.domain, dkim_params.selector))
end
end
local function do_sign(task, p)
if settings.use_milter_headers then
p.no_cache = true -- Disable caching in rspamd_mempool
end
if settings.check_pubkey then
local resolve_name = p.selector .. "._domainkey." .. p.domain
task:get_resolver():resolve_txt({
task = task,
name = resolve_name,
callback = function(_, _, results, err)
if not err and results and results[1] then
p.pubkey = results[1]
p.strict_pubkey_check = not settings.allow_pubkey_mismatch
elseif not settings.allow_pubkey_mismatch then
rspamd_logger.infox(task, 'public key for domain %s/%s is not found: %s, skip signing',
p.domain, p.selector, err)
return
else
rspamd_logger.infox(task, 'public key for domain %s/%s is not found: %s',
p.domain, p.selector, err)
end
local sret, hdr = sign_func(task, p)
insert_sign_results(task, sret, hdr, p)
end,
forced = true
})
else
local sret, hdr = sign_func(task, p)
insert_sign_results(task, sret, hdr, p)
end
end
local function sign_error(task, msg)
rspamd_logger.errx(task, 'signing failure: %s', msg)
end
local function dkim_signing_cb(task)
local ret,selectors = dkim_sign_tools.prepare_dkim_signing(N, task, settings)
if not ret then
return
end
if settings.use_redis then
dkim_sign_tools.sign_using_redis(N, task, settings, selectors, do_sign, sign_error)
else
if selectors.vault then
dkim_sign_tools.sign_using_vault(N, task, settings, selectors, do_sign, sign_error)
else
if #selectors > 0 then
for _, k in ipairs(selectors) do
-- templates
if k.key then
k.key = lua_util.template(k.key, {
domain = k.domain,
selector = k.selector
})
lua_util.debugm(N, task, 'using key "%s", use selector "%s" for domain "%s"',
k.key, k.selector, k.domain)
end
do_sign(task, k)
end
else
rspamd_logger.infox(task, 'key path or dkim selector unconfigured; no signing')
return false
end
end
end
end
local opts = rspamd_config:get_all_opt('dkim_signing')
if not opts then return end
dkim_sign_tools.process_signing_settings(N, settings, opts)
if not dkim_sign_tools.validate_signing_settings(settings) then
rspamd_logger.infox(rspamd_config, 'mandatory parameters missing, disable dkim signing')
lua_util.disable_module(N, "config")
return
end
if settings.use_redis then
redis_params = lua_redis.parse_redis_server('dkim_signing')
if not redis_params then
rspamd_logger.errx(rspamd_config,
'no servers are specified, but module is configured to load keys from redis, disable dkim signing')
lua_util.disable_module(N, "redis")
return
end
settings.redis_params = redis_params
end
local sym_reg_tbl = {
name = settings['symbol'],
callback = dkim_signing_cb,
groups = {"policies", "dkim"},
score = 0.0,
}
if type(settings.allowed_ids) == 'table' then
sym_reg_tbl.allowed_ids = settings.allowed_ids
end
if type(settings.forbidden_ids) == 'table' then
sym_reg_tbl.forbidden_ids = settings.forbidden_ids
end
rspamd_config:register_symbol(sym_reg_tbl)
-- Add dependency on DKIM checks
rspamd_config:register_dependency(settings['symbol'], 'DKIM_CHECK')
|