From 20864ad07d5dbbaf6cdd242ff33b37a6b3f2e4cb Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Tue, 9 Apr 2019 11:54:21 +0100 Subject: [PATCH] [Feature] Dkim_signing: Add OpenDKIM like signing_table and key_table --- lualib/lua_dkim_tools.lua | 158 ++++++++++++++++++++++++++++++-------- 1 file changed, 124 insertions(+), 34 deletions(-) diff --git a/lualib/lua_dkim_tools.lua b/lualib/lua_dkim_tools.lua index fc891ba71..bdfd8abfc 100644 --- a/lualib/lua_dkim_tools.lua +++ b/lualib/lua_dkim_tools.lua @@ -202,47 +202,137 @@ local function prepare_dkim_signing(N, task, settings) tdom = tdom:lower() end - if settings.use_domain_sign_networks and is_sign_networks then - dkim_domain = get_dkim_domain('use_domain_sign_networks') - lua_util.debugm(N, task, 'sign_networks: use domain(%s) for signature: %s', - settings.use_domain_sign_networks, dkim_domain) - elseif settings.use_domain_sign_local and is_local then - dkim_domain = get_dkim_domain('use_domain_sign_local') - lua_util.debugm(N, task, 'local: use domain(%s) for signature: %s', - settings.use_domain_sign_local, dkim_domain) - elseif settings.use_domain_sign_inbound and not is_local and not auser then - dkim_domain = get_dkim_domain('use_domain_sign_inbound') - lua_util.debugm(N, task, 'inbound: use domain(%s) for signature: %s', - settings.use_domain_sign_inbound, dkim_domain) - elseif settings.use_domain_custom then - if type(settings.use_domain_custom) == 'string' then - -- Load custom function - local loadstring = loadstring or load - local ret, res_or_err = pcall(loadstring(settings.use_domain_custom)) - if ret then - if type(res_or_err) == 'function' then - settings.use_domain_custom = res_or_err - dkim_domain = settings.use_domain_custom(task) - lua_util.debugm(N, task, 'use custom domain for signing: %s', - dkim_domain) + if settings.signing_table and settings.key_table then + -- OpenDKIM style + if not hfrom or not hfrom[1] or not hfrom[1].addr then + lua_util.debugm(N, task, + 'signing_table: cannot get data when no header from is presented') + return false,{} + end + local sign_entry = settings.signing_table:get_key(hfrom[1].addr) + + if sign_entry then + lua_util.debugm(N, task, + 'signing_table: found entry for %s: %s', hfrom[1].addr, sign_entry) + if sign_entry == '%' then + sign_entry = hdom + end + + -- Now search in key table + local key_entry = settings.key_table:get_key(sign_entry) + + if key_entry then + local parts = lua_util.str_split(key_entry, ':') + + if #parts == 2 then + -- domain + key + local selector = settings.selector + + if not selector then + logger.errx(task, 'no selector defined for sign_entry %s, key_entry %s', + sign_entry, key_entry) + return false,{} + end + + local res = { + selector = selector, + domain = parts[1]:gsub('%%', hdom) + } + + local st = parts[2]:sub(1, 2) + + if st:sub(1, 1) == '/' or st == './' or st == '..' then + res.key = parts[2]:gsub('%%', hdom) + lua_util.debugm(N, task, 'perform dkim signing for %s, selector=%s, domain=%s, key file=%s', + hdom, selector, res.domain, res.key) + else + res.rawkey = parts[2] -- No sanity check here + lua_util.debugm(N, task, 'perform dkim signing for %s, selector=%s, domain=%s, raw key used', + hdom, selector, res.domain) + end + + return true,{res} + elseif #parts == 3 then + -- domain, selector, key + local selector = parts[2] + + local res = { + selector = selector, + domain = parts[1]:gsub('%%', hdom) + } + + local st = parts[3]:sub(1, 2) + + if st:sub(1, 1) == '/' or st == './' or st == '..' then + res.key = parts[3]:gsub('%%', hdom) + lua_util.debugm(N, task, 'perform dkim signing for %s, selector=%s, domain=%s, key file=%s', + hdom, selector, res.domain, res.key) + else + res.rawkey = parts[3] -- No sanity check here + lua_util.debugm(N, task, 'perform dkim signing for %s, selector=%s, domain=%s, raw key used', + hdom, selector, res.domain) + end + + return true,{res} else - logger.errx(task, 'cannot load dkim domain custom script: invalid type: %s, expected function', - type(res_or_err)) - settings.use_domain_custom = nil + logger.errx(task, 'invalid key entry for sign entry %s: %s; when signing %s domain', + sign_entry, key_entry, hdom) + return false,{} end else - logger.errx(task, 'cannot load dkim domain custom script: %s', res_or_err) - settings.use_domain_custom = nil + logger.errx(task, 'cannot get key entry for signing entry %s, when signing %s domain', + sign_entry, hdom) + return false,{} end else - dkim_domain = settings.use_domain_custom(task) - lua_util.debugm(N, task, 'use custom domain for signing: %s', - dkim_domain) + lua_util.debugm(N, task, + 'signing_table: no entry for %s', hfrom[1].addr) + return false,{} end else - dkim_domain = get_dkim_domain('use_domain') - lua_util.debugm(N, task, 'use domain(%s) for signature: %s', - settings.use_domain, dkim_domain) + if settings.use_domain_sign_networks and is_sign_networks then + dkim_domain = get_dkim_domain('use_domain_sign_networks') + lua_util.debugm(N, task, + 'sign_networks: use domain(%s) for signature: %s', + settings.use_domain_sign_networks, dkim_domain) + elseif settings.use_domain_sign_local and is_local then + dkim_domain = get_dkim_domain('use_domain_sign_local') + lua_util.debugm(N, task, 'local: use domain(%s) for signature: %s', + settings.use_domain_sign_local, dkim_domain) + elseif settings.use_domain_sign_inbound and not is_local and not auser then + dkim_domain = get_dkim_domain('use_domain_sign_inbound') + lua_util.debugm(N, task, 'inbound: use domain(%s) for signature: %s', + settings.use_domain_sign_inbound, dkim_domain) + elseif settings.use_domain_custom then + if type(settings.use_domain_custom) == 'string' then + -- Load custom function + local loadstring = loadstring or load + local ret, res_or_err = pcall(loadstring(settings.use_domain_custom)) + if ret then + if type(res_or_err) == 'function' then + settings.use_domain_custom = res_or_err + dkim_domain = settings.use_domain_custom(task) + lua_util.debugm(N, task, 'use custom domain for signing: %s', + dkim_domain) + else + logger.errx(task, 'cannot load dkim domain custom script: invalid type: %s, expected function', + type(res_or_err)) + settings.use_domain_custom = nil + end + else + logger.errx(task, 'cannot load dkim domain custom script: %s', res_or_err) + settings.use_domain_custom = nil + end + else + dkim_domain = settings.use_domain_custom(task) + lua_util.debugm(N, task, 'use custom domain for signing: %s', + dkim_domain) + end + else + dkim_domain = get_dkim_domain('use_domain') + lua_util.debugm(N, task, 'use domain(%s) for signature: %s', + settings.use_domain, dkim_domain) + end end if not dkim_domain then -- 2.39.5