You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

dkim_check.c 38KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603
  1. /*-
  2. * Copyright 2016 Vsevolod Stakhov
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /***MODULE:dkim
  17. * rspamd module that checks dkim records of incoming email
  18. *
  19. * Allowed options:
  20. * - symbol_allow (string): symbol to insert in case of allow (default: 'R_DKIM_ALLOW')
  21. * - symbol_reject (string): symbol to insert (default: 'R_DKIM_REJECT')
  22. * - symbol_tempfail (string): symbol to insert in case of temporary fail (default: 'R_DKIM_TEMPFAIL')
  23. * - symbol_permfail (string): symbol to insert in case of permanent failure (default: 'R_DKIM_PERMFAIL')
  24. * - symbol_na (string): symbol to insert in case of no signing (default: 'R_DKIM_NA')
  25. * - whitelist (map): map of whitelisted networks
  26. * - domains (map): map of domains to check
  27. * - strict_multiplier (number): multiplier for strict domains
  28. * - time_jitter (number): jitter in seconds to allow time diff while checking
  29. * - trusted_only (flag): check signatures only for domains in 'domains' map
  30. */
  31. #include "config.h"
  32. #include "libmime/message.h"
  33. #include "libserver/dkim.h"
  34. #include "libutil/hash.h"
  35. #include "libutil/map.h"
  36. #include "libutil/map_helpers.h"
  37. #include "rspamd.h"
  38. #include "utlist.h"
  39. #include "unix-std.h"
  40. #include "lua/lua_common.h"
  41. #include "libserver/mempool_vars_internal.h"
  42. #define DEFAULT_SYMBOL_REJECT "R_DKIM_REJECT"
  43. #define DEFAULT_SYMBOL_TEMPFAIL "R_DKIM_TEMPFAIL"
  44. #define DEFAULT_SYMBOL_ALLOW "R_DKIM_ALLOW"
  45. #define DEFAULT_SYMBOL_NA "R_DKIM_NA"
  46. #define DEFAULT_SYMBOL_PERMFAIL "R_DKIM_PERMFAIL"
  47. #define DEFAULT_CACHE_SIZE 2048
  48. #define DEFAULT_TIME_JITTER 60
  49. #define DEFAULT_MAX_SIGS 5
  50. static const gchar *M = "rspamd dkim plugin";
  51. static const gchar default_sign_headers[] = ""
  52. "(o)from:(x)sender:(o)reply-to:(o)subject:(x)date:(x)message-id:"
  53. "(o)to:(o)cc:(x)mime-version:(x)content-type:(x)content-transfer-encoding:"
  54. "resent-to:resent-cc:resent-from:resent-sender:resent-message-id:"
  55. "(x)in-reply-to:(x)references:list-id:list-help:list-owner:list-unsubscribe:"
  56. "list-subscribe:list-post:(x)openpgp:(x)autocrypt";
  57. static const gchar default_arc_sign_headers[] = ""
  58. "(o)from:(x)sender:(o)reply-to:(o)subject:(x)date:(x)message-id:"
  59. "(o)to:(o)cc:(x)mime-version:(x)content-type:(x)content-transfer-encoding:"
  60. "resent-to:resent-cc:resent-from:resent-sender:resent-message-id:"
  61. "(x)in-reply-to:(x)references:list-id:list-help:list-owner:list-unsubscribe:"
  62. "list-subscribe:list-post:dkim-signature:(x)openpgp:(x)autocrypt";
  63. struct dkim_ctx {
  64. struct module_ctx ctx;
  65. const gchar *symbol_reject;
  66. const gchar *symbol_tempfail;
  67. const gchar *symbol_allow;
  68. const gchar *symbol_na;
  69. const gchar *symbol_permfail;
  70. struct rspamd_radix_map_helper *whitelist_ip;
  71. struct rspamd_hash_map_helper *dkim_domains;
  72. guint strict_multiplier;
  73. guint time_jitter;
  74. rspamd_lru_hash_t *dkim_hash;
  75. rspamd_lru_hash_t *dkim_sign_hash;
  76. const gchar *sign_headers;
  77. const gchar *arc_sign_headers;
  78. guint max_sigs;
  79. gboolean trusted_only;
  80. gboolean check_local;
  81. gboolean check_authed;
  82. };
  83. struct dkim_check_result {
  84. rspamd_dkim_context_t *ctx;
  85. rspamd_dkim_key_t *key;
  86. struct rspamd_task *task;
  87. struct rspamd_dkim_check_result *res;
  88. gdouble mult_allow;
  89. gdouble mult_deny;
  90. struct rspamd_symcache_item *item;
  91. struct dkim_check_result *next, *prev, *first;
  92. };
  93. static void dkim_symbol_callback (struct rspamd_task *task,
  94. struct rspamd_symcache_item *item,
  95. void *unused);
  96. static void dkim_sign_callback (struct rspamd_task *task,
  97. struct rspamd_symcache_item *item,
  98. void *unused);
  99. static gint lua_dkim_sign_handler (lua_State *L);
  100. static gint lua_dkim_verify_handler (lua_State *L);
  101. static gint lua_dkim_canonicalize_handler (lua_State *L);
  102. /* Initialization */
  103. gint dkim_module_init (struct rspamd_config *cfg, struct module_ctx **ctx);
  104. gint dkim_module_config (struct rspamd_config *cfg);
  105. gint dkim_module_reconfig (struct rspamd_config *cfg);
  106. module_t dkim_module = {
  107. "dkim",
  108. dkim_module_init,
  109. dkim_module_config,
  110. dkim_module_reconfig,
  111. NULL,
  112. RSPAMD_MODULE_VER,
  113. (guint)-1,
  114. };
  115. static inline struct dkim_ctx *
  116. dkim_get_context (struct rspamd_config *cfg)
  117. {
  118. return (struct dkim_ctx *)g_ptr_array_index (cfg->c_modules,
  119. dkim_module.ctx_offset);
  120. }
  121. static void
  122. dkim_module_key_dtor (gpointer k)
  123. {
  124. rspamd_dkim_key_t *key = k;
  125. rspamd_dkim_key_unref (key);
  126. }
  127. static void
  128. dkim_module_free_list (gpointer k)
  129. {
  130. g_list_free_full ((GList *)k, rspamd_gstring_free_hard);
  131. }
  132. gint
  133. dkim_module_init (struct rspamd_config *cfg, struct module_ctx **ctx)
  134. {
  135. struct dkim_ctx *dkim_module_ctx;
  136. dkim_module_ctx = rspamd_mempool_alloc0 (cfg->cfg_pool,
  137. sizeof (*dkim_module_ctx));
  138. dkim_module_ctx->sign_headers = default_sign_headers;
  139. dkim_module_ctx->arc_sign_headers = default_arc_sign_headers;
  140. dkim_module_ctx->max_sigs = DEFAULT_MAX_SIGS;
  141. *ctx = (struct module_ctx *)dkim_module_ctx;
  142. rspamd_rcl_add_doc_by_path (cfg,
  143. NULL,
  144. "DKIM check plugin",
  145. "dkim",
  146. UCL_OBJECT,
  147. NULL,
  148. 0,
  149. NULL,
  150. 0);
  151. rspamd_rcl_add_doc_by_path (cfg,
  152. "dkim",
  153. "Map of IP addresses that should be excluded from DKIM checks",
  154. "whitelist",
  155. UCL_STRING,
  156. NULL,
  157. 0,
  158. NULL,
  159. 0);
  160. rspamd_rcl_add_doc_by_path (cfg,
  161. "dkim",
  162. "Symbol that is added if DKIM check is successful",
  163. "symbol_allow",
  164. UCL_STRING,
  165. NULL,
  166. 0,
  167. DEFAULT_SYMBOL_ALLOW,
  168. 0);
  169. rspamd_rcl_add_doc_by_path (cfg,
  170. "dkim",
  171. "Symbol that is added if DKIM check is unsuccessful",
  172. "symbol_reject",
  173. UCL_STRING,
  174. NULL,
  175. 0,
  176. DEFAULT_SYMBOL_REJECT,
  177. 0);
  178. rspamd_rcl_add_doc_by_path (cfg,
  179. "dkim",
  180. "Symbol that is added if DKIM check can't be completed (e.g. DNS failure)",
  181. "symbol_tempfail",
  182. UCL_STRING,
  183. NULL,
  184. 0,
  185. DEFAULT_SYMBOL_TEMPFAIL,
  186. 0);
  187. rspamd_rcl_add_doc_by_path (cfg,
  188. "dkim",
  189. "Symbol that is added if mail is not signed",
  190. "symbol_na",
  191. UCL_STRING,
  192. NULL,
  193. 0,
  194. DEFAULT_SYMBOL_NA,
  195. 0);
  196. rspamd_rcl_add_doc_by_path (cfg,
  197. "dkim",
  198. "Symbol that is added if permanent failure encountered",
  199. "symbol_permfail",
  200. UCL_STRING,
  201. NULL,
  202. 0,
  203. DEFAULT_SYMBOL_PERMFAIL,
  204. 0);
  205. rspamd_rcl_add_doc_by_path (cfg,
  206. "dkim",
  207. "Size of DKIM keys cache",
  208. "dkim_cache_size",
  209. UCL_INT,
  210. NULL,
  211. 0,
  212. G_STRINGIFY (DEFAULT_CACHE_SIZE),
  213. 0);
  214. rspamd_rcl_add_doc_by_path (cfg,
  215. "dkim",
  216. "Allow this time difference when checking DKIM signature time validity",
  217. "time_jitter",
  218. UCL_TIME,
  219. NULL,
  220. 0,
  221. G_STRINGIFY (DEFAULT_TIME_JITTER),
  222. 0);
  223. rspamd_rcl_add_doc_by_path (cfg,
  224. "dkim",
  225. "Domains to check DKIM for (check all domains if this option is empty)",
  226. "domains",
  227. UCL_STRING,
  228. NULL,
  229. 0,
  230. "empty",
  231. 0);
  232. rspamd_rcl_add_doc_by_path (cfg,
  233. "dkim",
  234. "Map of domains that are treated as 'trusted' meaning that DKIM policy failure has more significant score",
  235. "trusted_domains",
  236. UCL_STRING,
  237. NULL,
  238. 0,
  239. "empty",
  240. 0);
  241. rspamd_rcl_add_doc_by_path (cfg,
  242. "dkim",
  243. "Multiply dkim score by this factor for trusted domains",
  244. "strict_multiplier",
  245. UCL_FLOAT,
  246. NULL,
  247. 0,
  248. NULL,
  249. 0);
  250. rspamd_rcl_add_doc_by_path (cfg,
  251. "dkim",
  252. "Check DKIM policies merely for `trusted_domains`",
  253. "trusted_only",
  254. UCL_BOOLEAN,
  255. NULL,
  256. 0,
  257. "false",
  258. 0);
  259. rspamd_rcl_add_doc_by_path (cfg,
  260. "dkim",
  261. "Lua script that tells if a message should be signed and with what params (obsoleted)",
  262. "sign_condition",
  263. UCL_STRING,
  264. NULL,
  265. 0,
  266. "empty",
  267. 0);
  268. rspamd_rcl_add_doc_by_path (cfg,
  269. "dkim",
  270. "Obsoleted: maximum number of DKIM signatures to check",
  271. "max_sigs",
  272. UCL_INT,
  273. NULL,
  274. 0,
  275. "n/a",
  276. 0);
  277. rspamd_rcl_add_doc_by_path (cfg,
  278. "dkim",
  279. "Headers used in signing",
  280. "sign_headers",
  281. UCL_STRING,
  282. NULL,
  283. 0,
  284. default_sign_headers,
  285. 0);
  286. return 0;
  287. }
  288. gint
  289. dkim_module_config (struct rspamd_config *cfg)
  290. {
  291. const ucl_object_t *value;
  292. gint res = TRUE, cb_id = -1;
  293. guint cache_size, sign_cache_size;
  294. gboolean got_trusted = FALSE;
  295. struct dkim_ctx *dkim_module_ctx = dkim_get_context (cfg);
  296. /* Register global methods */
  297. lua_getglobal (cfg->lua_state, "rspamd_plugins");
  298. if (lua_type (cfg->lua_state, -1) == LUA_TTABLE) {
  299. lua_pushstring (cfg->lua_state, "dkim");
  300. lua_createtable (cfg->lua_state, 0, 1);
  301. /* Set methods */
  302. lua_pushstring (cfg->lua_state, "sign");
  303. lua_pushcfunction (cfg->lua_state, lua_dkim_sign_handler);
  304. lua_settable (cfg->lua_state, -3);
  305. lua_pushstring (cfg->lua_state, "verify");
  306. lua_pushcfunction (cfg->lua_state, lua_dkim_verify_handler);
  307. lua_settable (cfg->lua_state, -3);
  308. lua_pushstring (cfg->lua_state, "canon_header_relaxed");
  309. lua_pushcfunction (cfg->lua_state, lua_dkim_canonicalize_handler);
  310. lua_settable (cfg->lua_state, -3);
  311. /* Finish dkim key */
  312. lua_settable (cfg->lua_state, -3);
  313. }
  314. lua_pop (cfg->lua_state, 1); /* Remove global function */
  315. dkim_module_ctx->whitelist_ip = NULL;
  316. value = rspamd_config_get_module_opt (cfg, "dkim", "check_local");
  317. if (value == NULL) {
  318. rspamd_config_get_module_opt (cfg, "options", "check_local");
  319. }
  320. if (value != NULL) {
  321. dkim_module_ctx->check_local = ucl_object_toboolean (value);
  322. }
  323. else {
  324. dkim_module_ctx->check_local = FALSE;
  325. }
  326. value = rspamd_config_get_module_opt (cfg, "dkim", "check_authed");
  327. if (value == NULL) {
  328. rspamd_config_get_module_opt (cfg, "options", "check_authed");
  329. }
  330. if (value != NULL) {
  331. dkim_module_ctx->check_authed = ucl_object_toboolean (value);
  332. }
  333. else {
  334. dkim_module_ctx->check_authed = FALSE;
  335. }
  336. if ((value =
  337. rspamd_config_get_module_opt (cfg, "dkim", "symbol_reject")) != NULL) {
  338. dkim_module_ctx->symbol_reject = ucl_object_tostring (value);
  339. }
  340. else {
  341. dkim_module_ctx->symbol_reject = DEFAULT_SYMBOL_REJECT;
  342. }
  343. if ((value =
  344. rspamd_config_get_module_opt (cfg, "dkim",
  345. "symbol_tempfail")) != NULL) {
  346. dkim_module_ctx->symbol_tempfail = ucl_object_tostring (value);
  347. }
  348. else {
  349. dkim_module_ctx->symbol_tempfail = DEFAULT_SYMBOL_TEMPFAIL;
  350. }
  351. if ((value =
  352. rspamd_config_get_module_opt (cfg, "dkim", "symbol_allow")) != NULL) {
  353. dkim_module_ctx->symbol_allow = ucl_object_tostring (value);
  354. }
  355. else {
  356. dkim_module_ctx->symbol_allow = DEFAULT_SYMBOL_ALLOW;
  357. }
  358. if ((value =
  359. rspamd_config_get_module_opt (cfg, "dkim", "symbol_na")) != NULL) {
  360. dkim_module_ctx->symbol_na = ucl_object_tostring (value);
  361. }
  362. else {
  363. dkim_module_ctx->symbol_na = DEFAULT_SYMBOL_NA;
  364. }
  365. if ((value =
  366. rspamd_config_get_module_opt (cfg, "dkim", "symbol_permfail")) != NULL) {
  367. dkim_module_ctx->symbol_permfail = ucl_object_tostring (value);
  368. }
  369. else {
  370. dkim_module_ctx->symbol_permfail = DEFAULT_SYMBOL_PERMFAIL;
  371. }
  372. if ((value =
  373. rspamd_config_get_module_opt (cfg, "dkim",
  374. "dkim_cache_size")) != NULL) {
  375. cache_size = ucl_object_toint (value);
  376. }
  377. else {
  378. cache_size = DEFAULT_CACHE_SIZE;
  379. }
  380. if ((value =
  381. rspamd_config_get_module_opt (cfg, "dkim",
  382. "sign_cache_size")) != NULL) {
  383. sign_cache_size = ucl_object_toint (value);
  384. }
  385. else {
  386. sign_cache_size = 128;
  387. }
  388. if ((value =
  389. rspamd_config_get_module_opt (cfg, "dkim", "time_jitter")) != NULL) {
  390. dkim_module_ctx->time_jitter = ucl_object_todouble (value);
  391. }
  392. else {
  393. dkim_module_ctx->time_jitter = DEFAULT_TIME_JITTER;
  394. }
  395. if ((value =
  396. rspamd_config_get_module_opt (cfg, "dkim", "max_sigs")) != NULL) {
  397. dkim_module_ctx->max_sigs = ucl_object_toint (value);
  398. }
  399. if ((value =
  400. rspamd_config_get_module_opt (cfg, "dkim", "whitelist")) != NULL) {
  401. rspamd_config_radix_from_ucl (cfg, value, "DKIM whitelist",
  402. &dkim_module_ctx->whitelist_ip, NULL);
  403. }
  404. if ((value =
  405. rspamd_config_get_module_opt (cfg, "dkim", "domains")) != NULL) {
  406. if (!rspamd_map_add_from_ucl (cfg, value,
  407. "DKIM domains",
  408. rspamd_kv_list_read,
  409. rspamd_kv_list_fin,
  410. rspamd_kv_list_dtor,
  411. (void **)&dkim_module_ctx->dkim_domains)) {
  412. msg_warn_config ("cannot load dkim domains list from %s",
  413. ucl_object_tostring (value));
  414. }
  415. else {
  416. got_trusted = TRUE;
  417. }
  418. }
  419. if (!got_trusted && (value =
  420. rspamd_config_get_module_opt (cfg, "dkim", "trusted_domains")) != NULL) {
  421. if (!rspamd_map_add_from_ucl (cfg, value,
  422. "DKIM domains",
  423. rspamd_kv_list_read,
  424. rspamd_kv_list_fin,
  425. rspamd_kv_list_dtor,
  426. (void **)&dkim_module_ctx->dkim_domains)) {
  427. msg_warn_config ("cannot load dkim domains list from %s",
  428. ucl_object_tostring (value));
  429. }
  430. else {
  431. got_trusted = TRUE;
  432. }
  433. }
  434. if ((value =
  435. rspamd_config_get_module_opt (cfg, "dkim",
  436. "strict_multiplier")) != NULL) {
  437. dkim_module_ctx->strict_multiplier = ucl_object_toint (value);
  438. }
  439. else {
  440. dkim_module_ctx->strict_multiplier = 1;
  441. }
  442. if ((value =
  443. rspamd_config_get_module_opt (cfg, "dkim", "trusted_only")) != NULL) {
  444. dkim_module_ctx->trusted_only = ucl_object_toboolean (value);
  445. }
  446. else {
  447. dkim_module_ctx->trusted_only = FALSE;
  448. }
  449. if ((value =
  450. rspamd_config_get_module_opt (cfg, "dkim", "sign_headers")) != NULL) {
  451. dkim_module_ctx->sign_headers = ucl_object_tostring (value);
  452. }
  453. if ((value =
  454. rspamd_config_get_module_opt (cfg, "arc", "sign_headers")) != NULL) {
  455. dkim_module_ctx->arc_sign_headers = ucl_object_tostring (value);
  456. }
  457. if (cache_size > 0) {
  458. dkim_module_ctx->dkim_hash = rspamd_lru_hash_new (
  459. cache_size,
  460. g_free,
  461. dkim_module_key_dtor);
  462. rspamd_mempool_add_destructor (cfg->cfg_pool,
  463. (rspamd_mempool_destruct_t)rspamd_lru_hash_destroy,
  464. dkim_module_ctx->dkim_hash);
  465. }
  466. if (sign_cache_size > 0) {
  467. dkim_module_ctx->dkim_sign_hash = rspamd_lru_hash_new (
  468. sign_cache_size,
  469. g_free,
  470. (GDestroyNotify) rspamd_dkim_sign_key_unref);
  471. rspamd_mempool_add_destructor (cfg->cfg_pool,
  472. (rspamd_mempool_destruct_t)rspamd_lru_hash_destroy,
  473. dkim_module_ctx->dkim_sign_hash);
  474. }
  475. if (dkim_module_ctx->trusted_only && !got_trusted) {
  476. msg_err_config (
  477. "trusted_only option is set and no trusted domains are defined; disabling dkim module completely as it is useless in this case");
  478. }
  479. else {
  480. if (!rspamd_config_is_module_enabled (cfg, "dkim")) {
  481. return TRUE;
  482. }
  483. cb_id = rspamd_symcache_add_symbol (cfg->cache,
  484. "DKIM_CHECK",
  485. 0,
  486. dkim_symbol_callback,
  487. NULL,
  488. SYMBOL_TYPE_CALLBACK,
  489. -1);
  490. rspamd_config_add_symbol (cfg,
  491. "DKIM_CHECK",
  492. 0.0,
  493. "DKIM check callback",
  494. "policies",
  495. RSPAMD_SYMBOL_FLAG_IGNORE,
  496. 1,
  497. 1);
  498. rspamd_config_add_symbol_group (cfg, "DKIM_CHECK", "dkim");
  499. rspamd_symcache_add_symbol (cfg->cache,
  500. dkim_module_ctx->symbol_reject,
  501. 0,
  502. NULL,
  503. NULL,
  504. SYMBOL_TYPE_VIRTUAL | SYMBOL_TYPE_FINE,
  505. cb_id);
  506. rspamd_symcache_add_symbol (cfg->cache,
  507. dkim_module_ctx->symbol_na,
  508. 0,
  509. NULL, NULL,
  510. SYMBOL_TYPE_VIRTUAL | SYMBOL_TYPE_FINE,
  511. cb_id);
  512. rspamd_symcache_add_symbol (cfg->cache,
  513. dkim_module_ctx->symbol_permfail,
  514. 0,
  515. NULL, NULL,
  516. SYMBOL_TYPE_VIRTUAL | SYMBOL_TYPE_FINE,
  517. cb_id);
  518. rspamd_symcache_add_symbol (cfg->cache,
  519. dkim_module_ctx->symbol_tempfail,
  520. 0,
  521. NULL, NULL,
  522. SYMBOL_TYPE_VIRTUAL | SYMBOL_TYPE_FINE,
  523. cb_id);
  524. rspamd_symcache_add_symbol (cfg->cache,
  525. dkim_module_ctx->symbol_allow,
  526. 0,
  527. NULL, NULL,
  528. SYMBOL_TYPE_VIRTUAL | SYMBOL_TYPE_FINE,
  529. cb_id);
  530. rspamd_symcache_add_symbol (cfg->cache,
  531. "DKIM_TRACE",
  532. 0,
  533. NULL, NULL,
  534. SYMBOL_TYPE_VIRTUAL | SYMBOL_TYPE_NOSTAT,
  535. cb_id);
  536. rspamd_config_add_symbol (cfg,
  537. "DKIM_TRACE",
  538. 0.0,
  539. "DKIM trace symbol",
  540. "policies",
  541. RSPAMD_SYMBOL_FLAG_IGNORE,
  542. 1,
  543. 1);
  544. rspamd_config_add_symbol_group (cfg, "DKIM_TRACE", "dkim");
  545. msg_info_config ("init internal dkim module");
  546. #ifndef HAVE_OPENSSL
  547. msg_warn_config (
  548. "openssl is not found so dkim rsa check is disabled, only check body hash, it is NOT safe to trust these results");
  549. #endif
  550. }
  551. return res;
  552. }
  553. /**
  554. * Grab a private key from the cache
  555. * or from the key content provided
  556. */
  557. rspamd_dkim_sign_key_t *
  558. dkim_module_load_key_format (struct rspamd_task *task,
  559. struct dkim_ctx *dkim_module_ctx,
  560. const gchar *key, gsize keylen,
  561. enum rspamd_dkim_key_format key_format)
  562. {
  563. guchar h[rspamd_cryptobox_HASHBYTES],
  564. hex_hash[rspamd_cryptobox_HASHBYTES * 2 + 1];
  565. rspamd_dkim_sign_key_t *ret = NULL;
  566. GError *err = NULL;
  567. struct stat st;
  568. memset (hex_hash, 0, sizeof (hex_hash));
  569. rspamd_cryptobox_hash (h, key, keylen, NULL, 0);
  570. rspamd_encode_hex_buf (h, sizeof (h), hex_hash, sizeof (hex_hash));
  571. if (dkim_module_ctx->dkim_sign_hash) {
  572. ret = rspamd_lru_hash_lookup (dkim_module_ctx->dkim_sign_hash,
  573. hex_hash, time (NULL));
  574. }
  575. /*
  576. * This fails for paths that are also valid base64.
  577. * Maybe the caller should have specified a format.
  578. */
  579. if (key_format == RSPAMD_DKIM_KEY_UNKNOWN) {
  580. if (key[0] == '.' || key[0] == '/') {
  581. if (!rspamd_cryptobox_base64_is_valid (key, keylen)) {
  582. key_format = RSPAMD_DKIM_KEY_FILE;
  583. }
  584. }
  585. else if (rspamd_cryptobox_base64_is_valid (key, keylen)) {
  586. key_format = RSPAMD_DKIM_KEY_BASE64;
  587. }
  588. }
  589. if (ret != NULL && key_format == RSPAMD_DKIM_KEY_FILE) {
  590. msg_debug_task("checking for stale file key");
  591. if (stat (key, &st) != 0) {
  592. msg_err_task("cannot stat key file: %s", strerror (errno));
  593. return NULL;
  594. }
  595. if (rspamd_dkim_sign_key_maybe_invalidate (ret, st.st_mtime)) {
  596. msg_debug_task("removing stale file key");
  597. /*
  598. * Invalidate DKIM key
  599. * removal from lru cache also cleanup the key and value
  600. */
  601. if (dkim_module_ctx->dkim_sign_hash) {
  602. rspamd_lru_hash_remove (dkim_module_ctx->dkim_sign_hash,
  603. hex_hash);
  604. }
  605. ret = NULL;
  606. }
  607. }
  608. /* found key; done */
  609. if (ret != NULL) {
  610. return ret;
  611. }
  612. ret = rspamd_dkim_sign_key_load (key, keylen, key_format, &err);
  613. if (ret == NULL) {
  614. msg_err_task ("cannot load dkim key %s: %e",
  615. key, err);
  616. g_error_free (err);
  617. }
  618. else if (dkim_module_ctx->dkim_sign_hash) {
  619. rspamd_lru_hash_insert (dkim_module_ctx->dkim_sign_hash,
  620. g_strdup (hex_hash), ret, time (NULL), 0);
  621. }
  622. return ret;
  623. }
  624. static gint
  625. lua_dkim_sign_handler (lua_State *L)
  626. {
  627. struct rspamd_task *task = lua_check_task (L, 1);
  628. gint64 arc_idx = 0, expire = 0;
  629. enum rspamd_dkim_type sign_type = RSPAMD_DKIM_NORMAL;
  630. GError *err = NULL;
  631. GString *hdr;
  632. GList *sigs = NULL;
  633. const gchar *selector = NULL, *domain = NULL, *key = NULL, *rawkey = NULL,
  634. *headers = NULL, *sign_type_str = NULL, *arc_cv = NULL,
  635. *pubkey = NULL;
  636. rspamd_dkim_sign_context_t *ctx;
  637. rspamd_dkim_sign_key_t *dkim_key;
  638. gsize rawlen = 0, keylen = 0;
  639. gboolean no_cache = FALSE, strict_pubkey_check = FALSE;
  640. struct dkim_ctx *dkim_module_ctx;
  641. luaL_argcheck (L, lua_type (L, 2) == LUA_TTABLE, 2, "'table' expected");
  642. /*
  643. * Get the following elements:
  644. * - selector
  645. * - domain
  646. * - key
  647. */
  648. if (!rspamd_lua_parse_table_arguments (L, 2, &err,
  649. RSPAMD_LUA_PARSE_ARGUMENTS_DEFAULT,
  650. "key=V;rawkey=V;*domain=S;*selector=S;no_cache=B;headers=S;"
  651. "sign_type=S;arc_idx=I;arc_cv=S;expire=I;pubkey=S;"
  652. "strict_pubkey_check=B",
  653. &keylen, &key, &rawlen, &rawkey, &domain,
  654. &selector, &no_cache, &headers,
  655. &sign_type_str, &arc_idx, &arc_cv, &expire, &pubkey,
  656. &strict_pubkey_check)) {
  657. msg_err_task ("cannot parse table arguments: %e",
  658. err);
  659. g_error_free (err);
  660. lua_pushboolean (L, FALSE);
  661. return 1;
  662. }
  663. dkim_module_ctx = dkim_get_context (task->cfg);
  664. if (key) {
  665. dkim_key = dkim_module_load_key_format (task, dkim_module_ctx, key,
  666. keylen, RSPAMD_DKIM_KEY_UNKNOWN);
  667. }
  668. else if (rawkey) {
  669. dkim_key = dkim_module_load_key_format (task, dkim_module_ctx, rawkey,
  670. rawlen, RSPAMD_DKIM_KEY_UNKNOWN);
  671. }
  672. else {
  673. msg_err_task ("neither key nor rawkey are specified");
  674. lua_pushboolean (L, FALSE);
  675. return 1;
  676. }
  677. if (dkim_key == NULL) {
  678. lua_pushboolean (L, FALSE);
  679. return 1;
  680. }
  681. if (sign_type_str) {
  682. if (strcmp (sign_type_str, "dkim") == 0) {
  683. sign_type = RSPAMD_DKIM_NORMAL;
  684. if (headers == NULL) {
  685. headers = dkim_module_ctx->sign_headers;
  686. }
  687. }
  688. else if (strcmp (sign_type_str, "arc-sign") == 0) {
  689. sign_type = RSPAMD_DKIM_ARC_SIG;
  690. if (headers == NULL) {
  691. headers = dkim_module_ctx->arc_sign_headers;
  692. }
  693. if (arc_idx == 0) {
  694. lua_settop (L, 0);
  695. return luaL_error (L, "no arc idx specified");
  696. }
  697. }
  698. else if (strcmp (sign_type_str, "arc-seal") == 0) {
  699. sign_type = RSPAMD_DKIM_ARC_SEAL;
  700. if (arc_cv == NULL) {
  701. lua_settop (L, 0);
  702. return luaL_error (L, "no arc cv specified");
  703. }
  704. if (arc_idx == 0) {
  705. lua_settop (L, 0);
  706. return luaL_error (L, "no arc idx specified");
  707. }
  708. }
  709. else {
  710. lua_settop (L, 0);
  711. return luaL_error (L, "unknown sign type: %s",
  712. sign_type_str);
  713. }
  714. }
  715. else {
  716. /* Unspecified sign type, assume plain dkim */
  717. if (headers == NULL) {
  718. headers = dkim_module_ctx->sign_headers;
  719. }
  720. }
  721. if (pubkey != NULL) {
  722. /* Also check if private and public keys match */
  723. rspamd_dkim_key_t *pk;
  724. keylen = strlen (pubkey);
  725. pk = rspamd_dkim_parse_key (pubkey, &keylen, NULL);
  726. if (pk == NULL) {
  727. if (strict_pubkey_check) {
  728. msg_err_task ("cannot parse pubkey from string: %s, skip signing",
  729. pubkey);
  730. lua_pushboolean (L, FALSE);
  731. return 1;
  732. }
  733. else {
  734. msg_warn_task ("cannot parse pubkey from string: %s",
  735. pubkey);
  736. }
  737. }
  738. else {
  739. GError *te = NULL;
  740. /* We have parsed the key, so try to check keys */
  741. if (!rspamd_dkim_match_keys (pk, dkim_key, &te)) {
  742. if (strict_pubkey_check) {
  743. msg_err_task ("public key for %s/%s does not match private "
  744. "key: %e, skip signing",
  745. domain, selector, te);
  746. g_error_free (te);
  747. lua_pushboolean (L, FALSE);
  748. rspamd_dkim_key_unref (pk);
  749. return 1;
  750. }
  751. else {
  752. msg_warn_task ("public key for %s/%s does not match private "
  753. "key: %e",
  754. domain, selector, te);
  755. g_error_free (te);
  756. }
  757. }
  758. rspamd_dkim_key_unref (pk);
  759. }
  760. }
  761. ctx = rspamd_create_dkim_sign_context (task, dkim_key,
  762. DKIM_CANON_RELAXED, DKIM_CANON_RELAXED,
  763. headers, sign_type, &err);
  764. if (ctx == NULL) {
  765. msg_err_task ("cannot create sign context: %e",
  766. err);
  767. g_error_free (err);
  768. lua_pushboolean (L, FALSE);
  769. return 1;
  770. }
  771. hdr = rspamd_dkim_sign (task, selector, domain, 0,
  772. expire, arc_idx, arc_cv, ctx);
  773. if (hdr) {
  774. if (!no_cache) {
  775. sigs = rspamd_mempool_get_variable (task->task_pool, "dkim-signature");
  776. if (sigs == NULL) {
  777. sigs = g_list_append (sigs, hdr);
  778. rspamd_mempool_set_variable (task->task_pool, "dkim-signature",
  779. sigs, dkim_module_free_list);
  780. } else {
  781. (void) g_list_append (sigs, hdr);
  782. }
  783. }
  784. lua_pushboolean (L, TRUE);
  785. lua_pushlstring (L, hdr->str, hdr->len);
  786. if (no_cache) {
  787. g_string_free (hdr, TRUE);
  788. }
  789. return 2;
  790. }
  791. lua_pushboolean (L, FALSE);
  792. lua_pushnil (L);
  793. return 2;
  794. }
  795. gint
  796. dkim_module_reconfig (struct rspamd_config *cfg)
  797. {
  798. return dkim_module_config (cfg);
  799. }
  800. /*
  801. * Parse strict value for domain in format: 'reject_multiplier:deny_multiplier'
  802. */
  803. static gboolean
  804. dkim_module_parse_strict (const gchar *value, gdouble *allow, gdouble *deny)
  805. {
  806. const gchar *colon;
  807. gchar *err = NULL;
  808. gdouble val;
  809. gchar numbuf[64];
  810. colon = strchr (value, ':');
  811. if (colon) {
  812. rspamd_strlcpy (numbuf, value,
  813. MIN (sizeof (numbuf), (colon - value) + 1));
  814. val = strtod (numbuf, &err);
  815. if (err == NULL || *err == '\0') {
  816. *deny = val;
  817. colon++;
  818. rspamd_strlcpy (numbuf, colon, sizeof (numbuf));
  819. err = NULL;
  820. val = strtod (numbuf, &err);
  821. if (err == NULL || *err == '\0') {
  822. *allow = val;
  823. return TRUE;
  824. }
  825. }
  826. }
  827. return FALSE;
  828. }
  829. static void
  830. dkim_module_check (struct dkim_check_result *res)
  831. {
  832. gboolean all_done = TRUE;
  833. const gchar *strict_value;
  834. struct dkim_check_result *first, *cur = NULL;
  835. struct dkim_ctx *dkim_module_ctx = dkim_get_context (res->task->cfg);
  836. struct rspamd_task *task = res->task;
  837. first = res->first;
  838. DL_FOREACH (first, cur) {
  839. if (cur->ctx == NULL) {
  840. continue;
  841. }
  842. if (cur->key != NULL && cur->res == NULL) {
  843. cur->res = rspamd_dkim_check (cur->ctx, cur->key, task);
  844. if (dkim_module_ctx->dkim_domains != NULL) {
  845. /* Perform strict check */
  846. if ((strict_value =
  847. rspamd_match_hash_map (dkim_module_ctx->dkim_domains,
  848. rspamd_dkim_get_domain (cur->ctx))) != NULL) {
  849. if (!dkim_module_parse_strict (strict_value, &cur->mult_allow,
  850. &cur->mult_deny)) {
  851. cur->mult_allow = dkim_module_ctx->strict_multiplier;
  852. cur->mult_deny = dkim_module_ctx->strict_multiplier;
  853. }
  854. }
  855. }
  856. }
  857. }
  858. DL_FOREACH (first, cur) {
  859. if (cur->ctx == NULL) {
  860. continue;
  861. }
  862. if (cur->res == NULL) {
  863. /* Still need a key */
  864. all_done = FALSE;
  865. }
  866. }
  867. if (all_done) {
  868. /* Create zero terminated array of results */
  869. struct rspamd_dkim_check_result **pres;
  870. guint nres = 0, i = 0;
  871. DL_FOREACH (first, cur) {
  872. if (cur->ctx == NULL || cur->res == NULL) {
  873. continue;
  874. }
  875. nres ++;
  876. }
  877. pres = rspamd_mempool_alloc (task->task_pool, sizeof (*pres) * (nres + 1));
  878. pres[nres] = NULL;
  879. DL_FOREACH (first, cur) {
  880. const gchar *symbol = NULL, *trace = NULL;
  881. gdouble symbol_weight = 1.0;
  882. if (cur->ctx == NULL || cur->res == NULL) {
  883. continue;
  884. }
  885. pres[i++] = cur->res;
  886. if (cur->res->rcode == DKIM_REJECT) {
  887. symbol = dkim_module_ctx->symbol_reject;
  888. trace = "-";
  889. symbol_weight = cur->mult_deny * 1.0;
  890. }
  891. else if (cur->res->rcode == DKIM_CONTINUE) {
  892. symbol = dkim_module_ctx->symbol_allow;
  893. trace = "+";
  894. symbol_weight = cur->mult_allow * 1.0;
  895. }
  896. else if (cur->res->rcode == DKIM_PERM_ERROR) {
  897. trace = "~";
  898. symbol = dkim_module_ctx->symbol_permfail;
  899. }
  900. else if (cur->res->rcode == DKIM_TRYAGAIN) {
  901. trace = "?";
  902. symbol = dkim_module_ctx->symbol_tempfail;
  903. }
  904. if (symbol != NULL) {
  905. const gchar *domain = rspamd_dkim_get_domain (cur->ctx);
  906. const gchar *selector = rspamd_dkim_get_selector (cur->ctx);
  907. gsize tracelen;
  908. gchar *tracebuf;
  909. tracelen = strlen (domain) + strlen (selector) + 4;
  910. tracebuf = rspamd_mempool_alloc (task->task_pool,
  911. tracelen);
  912. rspamd_snprintf (tracebuf, tracelen, "%s:%s", domain, trace);
  913. rspamd_task_insert_result (cur->task,
  914. "DKIM_TRACE",
  915. 0.0,
  916. tracebuf);
  917. rspamd_snprintf (tracebuf, tracelen, "%s:s=%s", domain, selector);
  918. rspamd_task_insert_result (task,
  919. symbol,
  920. symbol_weight,
  921. tracebuf);
  922. }
  923. }
  924. rspamd_mempool_set_variable (task->task_pool,
  925. RSPAMD_MEMPOOL_DKIM_CHECK_RESULTS,
  926. pres, NULL);
  927. }
  928. }
  929. static void
  930. dkim_module_key_handler (rspamd_dkim_key_t *key,
  931. gsize keylen,
  932. rspamd_dkim_context_t *ctx,
  933. gpointer ud,
  934. GError *err)
  935. {
  936. struct dkim_check_result *res = ud;
  937. struct rspamd_task *task;
  938. struct dkim_ctx *dkim_module_ctx;
  939. task = res->task;
  940. dkim_module_ctx = dkim_get_context (task->cfg);
  941. if (key != NULL) {
  942. /* Another ref belongs to the check context */
  943. res->key = rspamd_dkim_key_ref (key);
  944. /*
  945. * We actually receive key with refcount = 1, so we just assume that
  946. * lru hash owns this object now
  947. */
  948. /* Release key when task is processed */
  949. rspamd_mempool_add_destructor (res->task->task_pool,
  950. dkim_module_key_dtor, res->key);
  951. if (dkim_module_ctx->dkim_hash) {
  952. rspamd_lru_hash_insert (dkim_module_ctx->dkim_hash,
  953. g_strdup (rspamd_dkim_get_dns_key (ctx)),
  954. key, res->task->task_timestamp, rspamd_dkim_key_get_ttl (key));
  955. msg_info_task ("stored DKIM key for %s in LRU cache for %d seconds, "
  956. "%d/%d elements in the cache",
  957. rspamd_dkim_get_dns_key (ctx),
  958. rspamd_dkim_key_get_ttl (key),
  959. rspamd_lru_hash_size (dkim_module_ctx->dkim_hash),
  960. rspamd_lru_hash_capacity (dkim_module_ctx->dkim_hash));
  961. }
  962. }
  963. else {
  964. /* Insert tempfail symbol */
  965. msg_info_task ("cannot get key for domain %s: %e",
  966. rspamd_dkim_get_dns_key (ctx), err);
  967. if (err != NULL) {
  968. if (err->code == DKIM_SIGERROR_NOKEY) {
  969. res->res = rspamd_dkim_create_result (ctx, DKIM_TRYAGAIN, task);
  970. res->res->fail_reason = "DNS error when getting key";
  971. }
  972. else {
  973. res->res = rspamd_dkim_create_result (ctx, DKIM_PERM_ERROR, task);
  974. res->res->fail_reason = "invalid DKIM record";
  975. }
  976. }
  977. }
  978. if (err) {
  979. g_error_free (err);
  980. }
  981. dkim_module_check (res);
  982. }
  983. static void
  984. dkim_symbol_callback (struct rspamd_task *task,
  985. struct rspamd_symcache_item *item,
  986. void *unused)
  987. {
  988. rspamd_dkim_context_t *ctx;
  989. rspamd_dkim_key_t *key;
  990. GError *err = NULL;
  991. struct rspamd_mime_header *rh, *rh_cur;
  992. struct dkim_check_result *res = NULL, *cur;
  993. guint checked = 0, *dmarc_checks;
  994. struct dkim_ctx *dkim_module_ctx = dkim_get_context (task->cfg);
  995. /* Allow dmarc */
  996. dmarc_checks = rspamd_mempool_get_variable (task->task_pool,
  997. RSPAMD_MEMPOOL_DMARC_CHECKS);
  998. if (dmarc_checks) {
  999. (*dmarc_checks) ++;
  1000. }
  1001. else {
  1002. dmarc_checks = rspamd_mempool_alloc (task->task_pool,
  1003. sizeof (*dmarc_checks));
  1004. *dmarc_checks = 1;
  1005. rspamd_mempool_set_variable (task->task_pool,
  1006. RSPAMD_MEMPOOL_DMARC_CHECKS,
  1007. dmarc_checks, NULL);
  1008. }
  1009. /* First check if plugin should be enabled */
  1010. if ((!dkim_module_ctx->check_authed && task->user != NULL)
  1011. || (!dkim_module_ctx->check_local &&
  1012. rspamd_inet_address_is_local (task->from_addr, TRUE))) {
  1013. msg_info_task ("skip DKIM checks for local networks and authorized users");
  1014. rspamd_symcache_finalize_item (task, item);
  1015. return;
  1016. }
  1017. /* Check whitelist */
  1018. if (rspamd_match_radix_map_addr (dkim_module_ctx->whitelist_ip,
  1019. task->from_addr) != NULL) {
  1020. msg_info_task ("skip DKIM checks for whitelisted address");
  1021. rspamd_symcache_finalize_item (task, item);
  1022. return;
  1023. }
  1024. rspamd_symcache_item_async_inc (task, item, M);
  1025. /* Now check if a message has its signature */
  1026. rh = rspamd_message_get_header_array (task, RSPAMD_DKIM_SIGNHEADER);
  1027. if (rh) {
  1028. msg_debug_task ("dkim signature found");
  1029. DL_FOREACH (rh, rh_cur) {
  1030. if (rh_cur->decoded == NULL || rh_cur->decoded[0] == '\0') {
  1031. msg_info_task ("cannot load empty DKIM signature");
  1032. continue;
  1033. }
  1034. cur = rspamd_mempool_alloc0 (task->task_pool, sizeof (*cur));
  1035. cur->first = res;
  1036. cur->res = NULL;
  1037. cur->task = task;
  1038. cur->mult_allow = 1.0;
  1039. cur->mult_deny = 1.0;
  1040. cur->item = item;
  1041. ctx = rspamd_create_dkim_context (rh_cur->decoded,
  1042. task->task_pool,
  1043. dkim_module_ctx->time_jitter,
  1044. RSPAMD_DKIM_NORMAL,
  1045. &err);
  1046. if (res == NULL) {
  1047. res = cur;
  1048. res->first = res;
  1049. res->prev = res;
  1050. }
  1051. else {
  1052. DL_APPEND (res, cur);
  1053. }
  1054. if (ctx == NULL) {
  1055. if (err != NULL) {
  1056. msg_info_task ("cannot parse DKIM signature: %e",
  1057. err);
  1058. g_error_free (err);
  1059. err = NULL;
  1060. }
  1061. else {
  1062. msg_info_task ("cannot parse DKIM signature: "
  1063. "unknown error");
  1064. }
  1065. continue;
  1066. }
  1067. else {
  1068. /* Get key */
  1069. cur->ctx = ctx;
  1070. if (dkim_module_ctx->trusted_only &&
  1071. (dkim_module_ctx->dkim_domains == NULL ||
  1072. rspamd_match_hash_map (dkim_module_ctx->dkim_domains,
  1073. rspamd_dkim_get_domain (ctx)) == NULL)) {
  1074. msg_debug_task ("skip dkim check for %s domain",
  1075. rspamd_dkim_get_domain (ctx));
  1076. continue;
  1077. }
  1078. if (dkim_module_ctx->dkim_hash) {
  1079. key = rspamd_lru_hash_lookup (dkim_module_ctx->dkim_hash,
  1080. rspamd_dkim_get_dns_key (ctx),
  1081. task->task_timestamp);
  1082. }
  1083. else {
  1084. key = NULL;
  1085. }
  1086. if (key != NULL) {
  1087. cur->key = rspamd_dkim_key_ref (key);
  1088. /* Release key when task is processed */
  1089. rspamd_mempool_add_destructor (task->task_pool,
  1090. dkim_module_key_dtor, cur->key);
  1091. }
  1092. else {
  1093. if (!rspamd_get_dkim_key (ctx,
  1094. task,
  1095. dkim_module_key_handler,
  1096. cur)) {
  1097. continue;
  1098. }
  1099. }
  1100. }
  1101. checked ++;
  1102. if (checked > dkim_module_ctx->max_sigs) {
  1103. msg_info_task ("message has multiple signatures but we"
  1104. " stopped after %d checked signatures as limit"
  1105. " is reached", checked);
  1106. break;
  1107. }
  1108. }
  1109. }
  1110. else {
  1111. rspamd_task_insert_result (task,
  1112. dkim_module_ctx->symbol_na,
  1113. 1.0,
  1114. NULL);
  1115. }
  1116. if (res != NULL) {
  1117. dkim_module_check (res);
  1118. }
  1119. rspamd_symcache_item_async_dec_check (task, item, M);
  1120. }
  1121. struct rspamd_dkim_lua_verify_cbdata {
  1122. rspamd_dkim_context_t *ctx;
  1123. struct rspamd_task *task;
  1124. lua_State *L;
  1125. rspamd_dkim_key_t *key;
  1126. gint cbref;
  1127. };
  1128. static void
  1129. dkim_module_lua_push_verify_result (struct rspamd_dkim_lua_verify_cbdata *cbd,
  1130. struct rspamd_dkim_check_result *res, GError *err)
  1131. {
  1132. struct rspamd_task **ptask, *task;
  1133. const gchar *error_str = "unknown error";
  1134. gboolean success = FALSE;
  1135. task = cbd->task;
  1136. switch (res->rcode) {
  1137. case DKIM_CONTINUE:
  1138. error_str = NULL;
  1139. success = TRUE;
  1140. break;
  1141. case DKIM_REJECT:
  1142. if (err) {
  1143. error_str = err->message;
  1144. }
  1145. else {
  1146. error_str = "reject";
  1147. }
  1148. break;
  1149. case DKIM_TRYAGAIN:
  1150. if (err) {
  1151. error_str = err->message;
  1152. }
  1153. else {
  1154. error_str = "tempfail";
  1155. }
  1156. break;
  1157. case DKIM_NOTFOUND:
  1158. if (err) {
  1159. error_str = err->message;
  1160. }
  1161. else {
  1162. error_str = "not found";
  1163. }
  1164. break;
  1165. case DKIM_RECORD_ERROR:
  1166. if (err) {
  1167. error_str = err->message;
  1168. }
  1169. else {
  1170. error_str = "bad record";
  1171. }
  1172. break;
  1173. case DKIM_PERM_ERROR:
  1174. if (err) {
  1175. error_str = err->message;
  1176. }
  1177. else {
  1178. error_str = "permanent error";
  1179. }
  1180. break;
  1181. default:
  1182. break;
  1183. }
  1184. lua_rawgeti (cbd->L, LUA_REGISTRYINDEX, cbd->cbref);
  1185. ptask = lua_newuserdata (cbd->L, sizeof (*ptask));
  1186. *ptask = task;
  1187. lua_pushboolean (cbd->L, success);
  1188. if (error_str) {
  1189. lua_pushstring (cbd->L, error_str);
  1190. }
  1191. else {
  1192. lua_pushnil (cbd->L);
  1193. }
  1194. if (cbd->ctx) {
  1195. if (res->domain) {
  1196. lua_pushstring (cbd->L, res->domain);
  1197. }
  1198. else {
  1199. lua_pushnil (cbd->L);
  1200. }
  1201. if (res->selector) {
  1202. lua_pushstring (cbd->L, res->selector);
  1203. }
  1204. else {
  1205. lua_pushnil (cbd->L);
  1206. }
  1207. if (res->short_b) {
  1208. lua_pushstring (cbd->L, res->short_b);
  1209. }
  1210. else {
  1211. lua_pushnil (cbd->L);
  1212. }
  1213. if (res->fail_reason) {
  1214. lua_pushstring (cbd->L, res->fail_reason);
  1215. }
  1216. else {
  1217. lua_pushnil (cbd->L);
  1218. }
  1219. }
  1220. else {
  1221. lua_pushnil (cbd->L);
  1222. lua_pushnil (cbd->L);
  1223. lua_pushnil (cbd->L);
  1224. lua_pushnil (cbd->L);
  1225. }
  1226. if (lua_pcall (cbd->L, 7, 0, 0) != 0) {
  1227. msg_err_task ("call to verify callback failed: %s",
  1228. lua_tostring (cbd->L, -1));
  1229. lua_pop (cbd->L, 1);
  1230. }
  1231. luaL_unref (cbd->L, LUA_REGISTRYINDEX, cbd->cbref);
  1232. }
  1233. static void
  1234. dkim_module_lua_on_key (rspamd_dkim_key_t *key,
  1235. gsize keylen,
  1236. rspamd_dkim_context_t *ctx,
  1237. gpointer ud,
  1238. GError *err)
  1239. {
  1240. struct rspamd_dkim_lua_verify_cbdata *cbd = ud;
  1241. struct rspamd_task *task;
  1242. struct rspamd_dkim_check_result *res;
  1243. struct dkim_ctx *dkim_module_ctx;
  1244. task = cbd->task;
  1245. dkim_module_ctx = dkim_get_context (task->cfg);
  1246. if (key != NULL) {
  1247. /* Another ref belongs to the check context */
  1248. cbd->key = rspamd_dkim_key_ref (key);
  1249. /*
  1250. * We actually receive key with refcount = 1, so we just assume that
  1251. * lru hash owns this object now
  1252. */
  1253. if (dkim_module_ctx->dkim_hash) {
  1254. rspamd_lru_hash_insert (dkim_module_ctx->dkim_hash,
  1255. g_strdup (rspamd_dkim_get_dns_key (ctx)),
  1256. key, cbd->task->task_timestamp, rspamd_dkim_key_get_ttl (key));
  1257. }
  1258. /* Release key when task is processed */
  1259. rspamd_mempool_add_destructor (cbd->task->task_pool,
  1260. dkim_module_key_dtor, cbd->key);
  1261. }
  1262. else {
  1263. /* Insert tempfail symbol */
  1264. msg_info_task ("cannot get key for domain %s: %e",
  1265. rspamd_dkim_get_dns_key (ctx), err);
  1266. if (err != NULL) {
  1267. if (err->code == DKIM_SIGERROR_NOKEY) {
  1268. res = rspamd_dkim_create_result (ctx, DKIM_TRYAGAIN, task);
  1269. res->fail_reason = "DNS error when getting key";
  1270. }
  1271. else {
  1272. res = rspamd_dkim_create_result (ctx, DKIM_PERM_ERROR, task);
  1273. res->fail_reason = "invalid DKIM record";
  1274. }
  1275. }
  1276. else {
  1277. res = rspamd_dkim_create_result (ctx, DKIM_TRYAGAIN, task);
  1278. res->fail_reason = "DNS error when getting key";
  1279. }
  1280. dkim_module_lua_push_verify_result (cbd, res, err);
  1281. if (err) {
  1282. g_error_free (err);
  1283. }
  1284. return;
  1285. }
  1286. res = rspamd_dkim_check (cbd->ctx, cbd->key, cbd->task);
  1287. dkim_module_lua_push_verify_result (cbd, res, NULL);
  1288. }
  1289. static gint
  1290. lua_dkim_verify_handler (lua_State *L)
  1291. {
  1292. struct rspamd_task *task = lua_check_task (L, 1);
  1293. const gchar *sig = luaL_checkstring (L, 2);
  1294. rspamd_dkim_context_t *ctx;
  1295. struct rspamd_dkim_lua_verify_cbdata *cbd;
  1296. rspamd_dkim_key_t *key;
  1297. struct rspamd_dkim_check_result *ret;
  1298. GError *err = NULL;
  1299. const gchar *type_str = NULL;
  1300. enum rspamd_dkim_type type = RSPAMD_DKIM_NORMAL;
  1301. struct dkim_ctx *dkim_module_ctx;
  1302. if (task && sig && lua_isfunction (L, 3)) {
  1303. if (lua_isstring (L, 4)) {
  1304. type_str = lua_tostring (L, 4);
  1305. if (type_str) {
  1306. if (strcmp (type_str, "dkim") == 0) {
  1307. type = RSPAMD_DKIM_NORMAL;
  1308. }
  1309. else if (strcmp (type_str, "arc-sign") == 0) {
  1310. type = RSPAMD_DKIM_ARC_SIG;
  1311. }
  1312. else if (strcmp (type_str, "arc-seal") == 0) {
  1313. type = RSPAMD_DKIM_ARC_SEAL;
  1314. }
  1315. else {
  1316. lua_settop (L, 0);
  1317. return luaL_error (L, "unknown sign type: %s",
  1318. type_str);
  1319. }
  1320. }
  1321. }
  1322. dkim_module_ctx = dkim_get_context (task->cfg);
  1323. ctx = rspamd_create_dkim_context (sig,
  1324. task->task_pool,
  1325. dkim_module_ctx->time_jitter,
  1326. type,
  1327. &err);
  1328. if (ctx == NULL) {
  1329. lua_pushboolean (L, false);
  1330. if (err) {
  1331. lua_pushstring (L, err->message);
  1332. g_error_free (err);
  1333. }
  1334. else {
  1335. lua_pushstring (L, "unknown error");
  1336. }
  1337. return 2;
  1338. }
  1339. cbd = rspamd_mempool_alloc (task->task_pool, sizeof (*cbd));
  1340. cbd->L = L;
  1341. cbd->task = task;
  1342. lua_pushvalue (L, 3);
  1343. cbd->cbref = luaL_ref (L, LUA_REGISTRYINDEX);
  1344. cbd->ctx = ctx;
  1345. cbd->key = NULL;
  1346. if (dkim_module_ctx->dkim_hash) {
  1347. key = rspamd_lru_hash_lookup (dkim_module_ctx->dkim_hash,
  1348. rspamd_dkim_get_dns_key (ctx),
  1349. task->task_timestamp);
  1350. }
  1351. else {
  1352. key = NULL;
  1353. }
  1354. if (key != NULL) {
  1355. cbd->key = rspamd_dkim_key_ref (key);
  1356. /* Release key when task is processed */
  1357. rspamd_mempool_add_destructor (task->task_pool,
  1358. dkim_module_key_dtor, cbd->key);
  1359. ret = rspamd_dkim_check (cbd->ctx, cbd->key, cbd->task);
  1360. dkim_module_lua_push_verify_result (cbd, ret, NULL);
  1361. }
  1362. else {
  1363. rspamd_get_dkim_key (ctx,
  1364. task,
  1365. dkim_module_lua_on_key,
  1366. cbd);
  1367. }
  1368. }
  1369. else {
  1370. return luaL_error (L, "invalid arguments");
  1371. }
  1372. lua_pushboolean (L, TRUE);
  1373. lua_pushnil (L);
  1374. return 2;
  1375. }
  1376. static gint
  1377. lua_dkim_canonicalize_handler (lua_State *L)
  1378. {
  1379. gsize nlen, vlen;
  1380. const gchar *hname = luaL_checklstring (L, 1, &nlen),
  1381. *hvalue = luaL_checklstring (L, 2, &vlen);
  1382. static gchar st_buf[8192];
  1383. gchar *buf;
  1384. guint inlen;
  1385. gboolean allocated = FALSE;
  1386. goffset r;
  1387. if (hname && hvalue && nlen > 0) {
  1388. inlen = nlen + vlen + sizeof (":" CRLF);
  1389. if (inlen > sizeof (st_buf)) {
  1390. buf = g_malloc (inlen);
  1391. allocated = TRUE;
  1392. }
  1393. else {
  1394. /* Faster */
  1395. buf = st_buf;
  1396. }
  1397. r = rspamd_dkim_canonize_header_relaxed_str (hname, hvalue, buf, inlen);
  1398. if (r == -1) {
  1399. lua_pushnil (L);
  1400. }
  1401. else {
  1402. lua_pushlstring (L, buf, r);
  1403. }
  1404. if (allocated) {
  1405. g_free (buf);
  1406. }
  1407. }
  1408. else {
  1409. return luaL_error (L, "invalid arguments");
  1410. }
  1411. return 1;
  1412. }