123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- --[[
- Copyright (c) 2016, Andrew Lewis <nerf@judo.za.org>
- Copyright (c) 2022, Vsevolod Stakhov <vsevolod@rspamd.com>
-
- 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 or #selectors == 0 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" },
- flags = 'ignore_passthrough',
- 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')
|