Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699
  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. #include "task.h"
  17. #include "rspamd.h"
  18. #include "filter.h"
  19. #include "protocol.h"
  20. #include "message.h"
  21. #include "lua/lua_common.h"
  22. #include "email_addr.h"
  23. #include "composites.h"
  24. #include "stat_api.h"
  25. #include "unix-std.h"
  26. #include "utlist.h"
  27. #include "contrib/zstd/zstd.h"
  28. #include "libserver/mempool_vars_internal.h"
  29. #include "libserver/cfg_file_private.h"
  30. #include "libmime/lang_detection.h"
  31. #include "libmime/filter_private.h"
  32. #include <math.h>
  33. /*
  34. * Do not print more than this amount of elts
  35. */
  36. static const int max_log_elts = 7;
  37. static GQuark
  38. rspamd_task_quark (void)
  39. {
  40. return g_quark_from_static_string ("task-error");
  41. }
  42. static void
  43. rspamd_request_header_dtor (gpointer p)
  44. {
  45. GPtrArray *ar = p;
  46. guint i;
  47. rspamd_ftok_t *tok;
  48. if (ar) {
  49. for (i = 0; i < ar->len; i ++) {
  50. tok = g_ptr_array_index (ar, i);
  51. rspamd_fstring_mapped_ftok_free (tok);
  52. }
  53. g_ptr_array_free (ar, TRUE);
  54. }
  55. }
  56. /*
  57. * Create new task
  58. */
  59. struct rspamd_task *
  60. rspamd_task_new (struct rspamd_worker *worker, struct rspamd_config *cfg,
  61. rspamd_mempool_t *pool,
  62. struct rspamd_lang_detector *lang_det,
  63. struct event_base *ev_base)
  64. {
  65. struct rspamd_task *new_task;
  66. new_task = g_malloc0 (sizeof (struct rspamd_task));
  67. new_task->worker = worker;
  68. new_task->lang_det = lang_det;
  69. if (cfg) {
  70. new_task->cfg = cfg;
  71. REF_RETAIN (cfg);
  72. if (cfg->check_all_filters) {
  73. new_task->flags |= RSPAMD_TASK_FLAG_PASS_ALL;
  74. }
  75. if (cfg->re_cache) {
  76. new_task->re_rt = rspamd_re_cache_runtime_new (cfg->re_cache);
  77. }
  78. if (new_task->lang_det == NULL && cfg->lang_det != NULL) {
  79. new_task->lang_det = cfg->lang_det;
  80. }
  81. }
  82. new_task->ev_base = ev_base;
  83. #ifdef HAVE_EVENT_NO_CACHE_TIME_FUNC
  84. if (ev_base) {
  85. event_base_update_cache_time (ev_base);
  86. event_base_gettimeofday_cached (ev_base, &new_task->tv);
  87. new_task->time_real = tv_to_double (&new_task->tv);
  88. }
  89. else {
  90. gettimeofday (&new_task->tv, NULL);
  91. new_task->time_real = tv_to_double (&new_task->tv);
  92. }
  93. #else
  94. gettimeofday (&new_task->tv, NULL);
  95. new_task->time_real = tv_to_double (&new_task->tv);
  96. #endif
  97. new_task->time_virtual = rspamd_get_virtual_ticks ();
  98. new_task->time_real_finish = NAN;
  99. new_task->time_virtual_finish = NAN;
  100. if (pool == NULL) {
  101. new_task->task_pool =
  102. rspamd_mempool_new (rspamd_mempool_suggest_size (), "task");
  103. new_task->flags |= RSPAMD_TASK_FLAG_OWN_POOL;
  104. }
  105. else {
  106. new_task->task_pool = pool;
  107. }
  108. new_task->raw_headers = g_hash_table_new_full (rspamd_strcase_hash,
  109. rspamd_strcase_equal, NULL, rspamd_ptr_array_free_hard);
  110. new_task->headers_order = g_queue_new ();
  111. new_task->request_headers = g_hash_table_new_full (rspamd_ftok_icase_hash,
  112. rspamd_ftok_icase_equal, rspamd_fstring_mapped_ftok_free,
  113. rspamd_request_header_dtor);
  114. rspamd_mempool_add_destructor (new_task->task_pool,
  115. (rspamd_mempool_destruct_t) g_hash_table_unref,
  116. new_task->request_headers);
  117. new_task->reply_headers = g_hash_table_new_full (rspamd_ftok_icase_hash,
  118. rspamd_ftok_icase_equal, rspamd_fstring_mapped_ftok_free,
  119. rspamd_fstring_mapped_ftok_free);
  120. rspamd_mempool_add_destructor (new_task->task_pool,
  121. (rspamd_mempool_destruct_t) g_hash_table_unref,
  122. new_task->reply_headers);
  123. rspamd_mempool_add_destructor (new_task->task_pool,
  124. (rspamd_mempool_destruct_t) g_hash_table_unref,
  125. new_task->raw_headers);
  126. rspamd_mempool_add_destructor (new_task->task_pool,
  127. (rspamd_mempool_destruct_t) g_queue_free,
  128. new_task->headers_order);
  129. new_task->emails = g_hash_table_new (rspamd_email_hash, rspamd_emails_cmp);
  130. rspamd_mempool_add_destructor (new_task->task_pool,
  131. (rspamd_mempool_destruct_t) g_hash_table_unref,
  132. new_task->emails);
  133. new_task->urls = g_hash_table_new (rspamd_url_hash, rspamd_urls_cmp);
  134. rspamd_mempool_add_destructor (new_task->task_pool,
  135. (rspamd_mempool_destruct_t) g_hash_table_unref,
  136. new_task->urls);
  137. new_task->parts = g_ptr_array_sized_new (4);
  138. rspamd_mempool_add_destructor (new_task->task_pool,
  139. rspamd_ptr_array_free_hard, new_task->parts);
  140. new_task->text_parts = g_ptr_array_sized_new (2);
  141. rspamd_mempool_add_destructor (new_task->task_pool,
  142. rspamd_ptr_array_free_hard, new_task->text_parts);
  143. new_task->received = g_ptr_array_sized_new (8);
  144. rspamd_mempool_add_destructor (new_task->task_pool,
  145. rspamd_ptr_array_free_hard, new_task->received);
  146. new_task->sock = -1;
  147. new_task->flags |= (RSPAMD_TASK_FLAG_MIME|RSPAMD_TASK_FLAG_JSON);
  148. new_task->result = rspamd_create_metric_result (new_task);
  149. new_task->message_id = new_task->queue_id = "undef";
  150. new_task->messages = ucl_object_typed_new (UCL_OBJECT);
  151. new_task->lua_cache = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  152. return new_task;
  153. }
  154. static void
  155. rspamd_task_reply (struct rspamd_task *task)
  156. {
  157. if (task->fin_callback) {
  158. task->fin_callback (task, task->fin_arg);
  159. }
  160. else {
  161. rspamd_protocol_write_reply (task);
  162. }
  163. }
  164. /*
  165. * Called if all filters are processed
  166. * @return TRUE if session should be terminated
  167. */
  168. gboolean
  169. rspamd_task_fin (void *arg)
  170. {
  171. struct rspamd_task *task = (struct rspamd_task *) arg;
  172. /* Task is already finished or skipped */
  173. if (RSPAMD_TASK_IS_PROCESSED (task)) {
  174. rspamd_task_reply (task);
  175. return TRUE;
  176. }
  177. if (!rspamd_task_process (task, RSPAMD_TASK_PROCESS_ALL)) {
  178. rspamd_task_reply (task);
  179. return TRUE;
  180. }
  181. if (RSPAMD_TASK_IS_PROCESSED (task)) {
  182. rspamd_task_reply (task);
  183. return TRUE;
  184. }
  185. /* One more iteration */
  186. return FALSE;
  187. }
  188. /*
  189. * Called if session was restored inside fin callback
  190. */
  191. void
  192. rspamd_task_restore (void *arg)
  193. {
  194. /* XXX: not needed now ? */
  195. }
  196. /*
  197. * Free all structures of worker_task
  198. */
  199. void
  200. rspamd_task_free (struct rspamd_task *task)
  201. {
  202. struct rspamd_mime_part *p;
  203. struct rspamd_mime_text_part *tp;
  204. struct rspamd_email_address *addr;
  205. struct rspamd_lua_cached_entry *entry;
  206. GHashTableIter it;
  207. gpointer k, v;
  208. guint i;
  209. if (task) {
  210. debug_task ("free pointer %p", task);
  211. for (i = 0; i < task->parts->len; i ++) {
  212. p = g_ptr_array_index (task->parts, i);
  213. if (p->raw_headers) {
  214. g_hash_table_unref (p->raw_headers);
  215. }
  216. if (p->headers_order) {
  217. g_queue_free (p->headers_order);
  218. }
  219. if (IS_CT_MULTIPART (p->ct)) {
  220. if (p->specific.mp->children) {
  221. g_ptr_array_free (p->specific.mp->children, TRUE);
  222. }
  223. }
  224. }
  225. for (i = 0; i < task->text_parts->len; i ++) {
  226. tp = g_ptr_array_index (task->text_parts, i);
  227. if (tp->utf_words) {
  228. g_array_free (tp->utf_words, TRUE);
  229. }
  230. if (tp->normalized_hashes) {
  231. g_array_free (tp->normalized_hashes, TRUE);
  232. }
  233. if (tp->languages) {
  234. g_ptr_array_unref (tp->languages);
  235. }
  236. }
  237. if (task->rcpt_envelope) {
  238. for (i = 0; i < task->rcpt_envelope->len; i ++) {
  239. addr = g_ptr_array_index (task->rcpt_envelope, i);
  240. rspamd_email_address_free (addr);
  241. }
  242. g_ptr_array_free (task->rcpt_envelope, TRUE);
  243. }
  244. if (task->from_envelope) {
  245. rspamd_email_address_free (task->from_envelope);
  246. }
  247. if (task->meta_words) {
  248. g_array_free (task->meta_words, TRUE);
  249. }
  250. ucl_object_unref (task->messages);
  251. if (task->re_rt) {
  252. rspamd_re_cache_runtime_destroy (task->re_rt);
  253. }
  254. if (task->http_conn != NULL) {
  255. rspamd_http_connection_reset (task->http_conn);
  256. rspamd_http_connection_unref (task->http_conn);
  257. }
  258. if (task->settings != NULL) {
  259. ucl_object_unref (task->settings);
  260. }
  261. if (task->client_addr) {
  262. rspamd_inet_address_free (task->client_addr);
  263. }
  264. if (task->from_addr) {
  265. rspamd_inet_address_free (task->from_addr);
  266. }
  267. if (task->err) {
  268. g_error_free (task->err);
  269. }
  270. if (rspamd_event_pending (&task->timeout_ev, EV_TIMEOUT)) {
  271. event_del (&task->timeout_ev);
  272. }
  273. if (task->guard_ev) {
  274. event_del (task->guard_ev);
  275. }
  276. if (task->sock != -1) {
  277. close (task->sock);
  278. }
  279. if (task->cfg) {
  280. if (task->lua_cache) {
  281. g_hash_table_iter_init (&it, task->lua_cache);
  282. while (g_hash_table_iter_next (&it, &k, &v)) {
  283. entry = (struct rspamd_lua_cached_entry *)v;
  284. luaL_unref (task->cfg->lua_state,
  285. LUA_REGISTRYINDEX, entry->ref);
  286. }
  287. g_hash_table_unref (task->lua_cache);
  288. }
  289. REF_RELEASE (task->cfg);
  290. }
  291. if (task->flags & RSPAMD_TASK_FLAG_OWN_POOL) {
  292. rspamd_mempool_delete (task->task_pool);
  293. }
  294. g_free (task);
  295. }
  296. }
  297. struct rspamd_task_map {
  298. gpointer begin;
  299. gulong len;
  300. };
  301. static void
  302. rspamd_task_unmapper (gpointer ud)
  303. {
  304. struct rspamd_task_map *m = ud;
  305. munmap (m->begin, m->len);
  306. }
  307. gboolean
  308. rspamd_task_load_message (struct rspamd_task *task,
  309. struct rspamd_http_message *msg, const gchar *start, gsize len)
  310. {
  311. guint control_len, r;
  312. struct ucl_parser *parser;
  313. ucl_object_t *control_obj;
  314. gchar filepath[PATH_MAX], *fp;
  315. gint fd, flen;
  316. gulong offset = 0, shmem_size = 0;
  317. rspamd_ftok_t *tok;
  318. gpointer map;
  319. struct stat st;
  320. struct rspamd_task_map *m;
  321. const gchar *ft;
  322. #ifdef HAVE_SANE_SHMEM
  323. ft = "shm";
  324. #else
  325. ft = "file";
  326. #endif
  327. if (msg) {
  328. rspamd_protocol_handle_headers (task, msg);
  329. }
  330. tok = rspamd_task_get_request_header (task, "shm");
  331. if (tok) {
  332. /* Shared memory part */
  333. r = rspamd_strlcpy (filepath, tok->begin,
  334. MIN (sizeof (filepath), tok->len + 1));
  335. rspamd_url_decode (filepath, filepath, r + 1);
  336. flen = strlen (filepath);
  337. if (filepath[0] == '"' && flen > 2) {
  338. /* We need to unquote filepath */
  339. fp = &filepath[1];
  340. fp[flen - 2] = '\0';
  341. }
  342. else {
  343. fp = &filepath[0];
  344. }
  345. #ifdef HAVE_SANE_SHMEM
  346. fd = shm_open (fp, O_RDONLY, 00600);
  347. #else
  348. fd = open (fp, O_RDONLY, 00600);
  349. #endif
  350. if (fd == -1) {
  351. g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR,
  352. "Cannot open %s segment (%s): %s", ft, fp, strerror (errno));
  353. return FALSE;
  354. }
  355. if (fstat (fd, &st) == -1) {
  356. g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR,
  357. "Cannot stat %s segment (%s): %s", ft, fp, strerror (errno));
  358. close (fd);
  359. return FALSE;
  360. }
  361. map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
  362. if (map == MAP_FAILED) {
  363. close (fd);
  364. g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR,
  365. "Cannot mmap %s (%s): %s", ft, fp, strerror (errno));
  366. return FALSE;
  367. }
  368. close (fd);
  369. tok = rspamd_task_get_request_header (task, "shm-offset");
  370. if (tok) {
  371. rspamd_strtoul (tok->begin, tok->len, &offset);
  372. if (offset > (gulong)st.st_size) {
  373. msg_err_task ("invalid offset %ul (%ul available) for shm "
  374. "segment %s", offset, st.st_size, fp);
  375. munmap (map, st.st_size);
  376. return FALSE;
  377. }
  378. }
  379. tok = rspamd_task_get_request_header (task, "shm-length");
  380. shmem_size = st.st_size;
  381. if (tok) {
  382. rspamd_strtoul (tok->begin, tok->len, &shmem_size);
  383. if (shmem_size > (gulong)st.st_size) {
  384. msg_err_task ("invalid length %ul (%ul available) for %s "
  385. "segment %s", shmem_size, st.st_size, ft, fp);
  386. munmap (map, st.st_size);
  387. return FALSE;
  388. }
  389. }
  390. task->msg.begin = ((guchar *)map) + offset;
  391. task->msg.len = shmem_size;
  392. m = rspamd_mempool_alloc (task->task_pool, sizeof (*m));
  393. m->begin = map;
  394. m->len = st.st_size;
  395. msg_info_task ("loaded message from shared memory %s (%ul size, %ul offset)",
  396. fp, shmem_size, offset);
  397. rspamd_mempool_add_destructor (task->task_pool, rspamd_task_unmapper, m);
  398. return TRUE;
  399. }
  400. tok = rspamd_task_get_request_header (task, "file");
  401. if (tok == NULL) {
  402. tok = rspamd_task_get_request_header (task, "path");
  403. }
  404. if (tok) {
  405. debug_task ("want to scan file %T", tok);
  406. r = rspamd_strlcpy (filepath, tok->begin,
  407. MIN (sizeof (filepath), tok->len + 1));
  408. rspamd_url_decode (filepath, filepath, r + 1);
  409. flen = strlen (filepath);
  410. if (filepath[0] == '"' && flen > 2) {
  411. /* We need to unquote filepath */
  412. fp = &filepath[1];
  413. fp[flen - 2] = '\0';
  414. }
  415. else {
  416. fp = &filepath[0];
  417. }
  418. if (stat (fp, &st) == -1) {
  419. g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR,
  420. "Invalid file (%s): %s", fp, strerror (errno));
  421. return FALSE;
  422. }
  423. if (G_UNLIKELY (st.st_size == 0)) {
  424. /* Empty file */
  425. task->flags |= RSPAMD_TASK_FLAG_EMPTY;
  426. task->msg.begin = rspamd_mempool_strdup (task->task_pool, "");
  427. task->msg.len = 0;
  428. }
  429. else {
  430. fd = open (fp, O_RDONLY);
  431. if (fd == -1) {
  432. g_set_error (&task->err, rspamd_task_quark (),
  433. RSPAMD_PROTOCOL_ERROR,
  434. "Cannot open file (%s): %s", fp, strerror (errno));
  435. return FALSE;
  436. }
  437. map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
  438. if (map == MAP_FAILED) {
  439. close (fd);
  440. g_set_error (&task->err, rspamd_task_quark (),
  441. RSPAMD_PROTOCOL_ERROR,
  442. "Cannot mmap file (%s): %s", fp, strerror (errno));
  443. return FALSE;
  444. }
  445. close (fd);
  446. task->msg.begin = map;
  447. task->msg.len = st.st_size;
  448. m = rspamd_mempool_alloc (task->task_pool, sizeof (*m));
  449. m->begin = map;
  450. m->len = st.st_size;
  451. rspamd_mempool_add_destructor (task->task_pool, rspamd_task_unmapper, m);
  452. }
  453. task->msg.fpath = rspamd_mempool_strdup (task->task_pool, fp);
  454. task->flags |= RSPAMD_TASK_FLAG_FILE;
  455. msg_info_task ("loaded message from file %s", fp);
  456. return TRUE;
  457. }
  458. /* Plain data */
  459. debug_task ("got input of length %z", task->msg.len);
  460. /* Check compression */
  461. tok = rspamd_task_get_request_header (task, "compression");
  462. if (tok) {
  463. /* Need to uncompress */
  464. rspamd_ftok_t t;
  465. t.begin = "zstd";
  466. t.len = 4;
  467. if (rspamd_ftok_casecmp (tok, &t) == 0) {
  468. ZSTD_DStream *zstream;
  469. ZSTD_inBuffer zin;
  470. ZSTD_outBuffer zout;
  471. guchar *out;
  472. gsize outlen, r;
  473. gulong dict_id;
  474. if (!rspamd_libs_reset_decompression (task->cfg->libs_ctx)) {
  475. g_set_error (&task->err, rspamd_task_quark(),
  476. RSPAMD_PROTOCOL_ERROR,
  477. "Cannot decompress, decompressor init failed");
  478. return FALSE;
  479. }
  480. tok = rspamd_task_get_request_header (task, "dictionary");
  481. if (tok != NULL) {
  482. /* We need to use custom dictionary */
  483. if (!rspamd_strtoul (tok->begin, tok->len, &dict_id)) {
  484. g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR,
  485. "Non numeric dictionary");
  486. return FALSE;
  487. }
  488. if (!task->cfg->libs_ctx->in_dict) {
  489. g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR,
  490. "Unknown dictionary, undefined locally");
  491. return FALSE;
  492. }
  493. if (task->cfg->libs_ctx->in_dict->id != dict_id) {
  494. g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR,
  495. "Unknown dictionary, invalid dictionary id");
  496. return FALSE;
  497. }
  498. }
  499. zstream = task->cfg->libs_ctx->in_zstream;
  500. zin.pos = 0;
  501. zin.src = start;
  502. zin.size = len;
  503. if ((outlen = ZSTD_getDecompressedSize (start, len)) == 0) {
  504. outlen = ZSTD_DStreamOutSize ();
  505. }
  506. out = g_malloc (outlen);
  507. zout.dst = out;
  508. zout.pos = 0;
  509. zout.size = outlen;
  510. while (zin.pos < zin.size) {
  511. r = ZSTD_decompressStream (zstream, &zout, &zin);
  512. if (ZSTD_isError (r)) {
  513. g_set_error (&task->err, rspamd_task_quark(),
  514. RSPAMD_PROTOCOL_ERROR,
  515. "Decompression error: %s", ZSTD_getErrorName (r));
  516. return FALSE;
  517. }
  518. if (zout.pos == zout.size) {
  519. /* We need to extend output buffer */
  520. zout.size = zout.size * 1.5 + 1.0;
  521. zout.dst = g_realloc (zout.dst, zout.size);
  522. }
  523. }
  524. rspamd_mempool_add_destructor (task->task_pool, g_free, zout.dst);
  525. task->msg.begin = zout.dst;
  526. task->msg.len = zout.pos;
  527. task->flags |= RSPAMD_TASK_FLAG_COMPRESSED;
  528. msg_info_task ("loaded message from zstd compressed stream; "
  529. "compressed: %ul; uncompressed: %ul",
  530. (gulong)zin.size, (gulong)zout.pos);
  531. }
  532. else {
  533. g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR,
  534. "Invalid compression method");
  535. return FALSE;
  536. }
  537. }
  538. else {
  539. task->msg.begin = start;
  540. task->msg.len = len;
  541. }
  542. if (task->msg.len == 0) {
  543. task->flags |= RSPAMD_TASK_FLAG_EMPTY;
  544. }
  545. if (task->flags & RSPAMD_TASK_FLAG_HAS_CONTROL) {
  546. /* We have control chunk, so we need to process it separately */
  547. if (task->msg.len < task->message_len) {
  548. msg_warn_task ("message has invalid message length: %ul and total len: %ul",
  549. task->message_len, task->msg.len);
  550. g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR,
  551. "Invalid length");
  552. return FALSE;
  553. }
  554. control_len = task->msg.len - task->message_len;
  555. if (control_len > 0) {
  556. parser = ucl_parser_new (UCL_PARSER_KEY_LOWERCASE);
  557. if (!ucl_parser_add_chunk (parser, task->msg.begin, control_len)) {
  558. msg_warn_task ("processing of control chunk failed: %s",
  559. ucl_parser_get_error (parser));
  560. ucl_parser_free (parser);
  561. }
  562. else {
  563. control_obj = ucl_parser_get_object (parser);
  564. ucl_parser_free (parser);
  565. rspamd_protocol_handle_control (task, control_obj);
  566. ucl_object_unref (control_obj);
  567. }
  568. task->msg.begin += control_len;
  569. task->msg.len -= control_len;
  570. }
  571. }
  572. return TRUE;
  573. }
  574. static gint
  575. rspamd_task_select_processing_stage (struct rspamd_task *task, guint stages)
  576. {
  577. gint st, mask;
  578. mask = task->processed_stages;
  579. if (mask == 0) {
  580. st = 0;
  581. }
  582. else {
  583. for (st = 1; mask != 1; st ++) {
  584. mask = (unsigned int)mask >> 1;
  585. }
  586. }
  587. st = 1 << st;
  588. if (stages & st) {
  589. return st;
  590. }
  591. else if (st < RSPAMD_TASK_STAGE_DONE) {
  592. /* We assume that the stage that was not requested is done */
  593. task->processed_stages |= st;
  594. return rspamd_task_select_processing_stage (task, stages);
  595. }
  596. /* We are done */
  597. return RSPAMD_TASK_STAGE_DONE;
  598. }
  599. gboolean
  600. rspamd_task_process (struct rspamd_task *task, guint stages)
  601. {
  602. gint st;
  603. gboolean ret = TRUE;
  604. GError *stat_error = NULL;
  605. /* Avoid nested calls */
  606. if (task->flags & RSPAMD_TASK_FLAG_PROCESSING) {
  607. return TRUE;
  608. }
  609. if (RSPAMD_TASK_IS_PROCESSED (task)) {
  610. return TRUE;
  611. }
  612. task->flags |= RSPAMD_TASK_FLAG_PROCESSING;
  613. st = rspamd_task_select_processing_stage (task, stages);
  614. switch (st) {
  615. case RSPAMD_TASK_STAGE_READ_MESSAGE:
  616. if (!rspamd_message_parse (task)) {
  617. ret = FALSE;
  618. }
  619. break;
  620. case RSPAMD_TASK_STAGE_PRE_FILTERS:
  621. rspamd_symcache_process_symbols (task, task->cfg->cache,
  622. RSPAMD_TASK_STAGE_PRE_FILTERS);
  623. break;
  624. case RSPAMD_TASK_STAGE_PROCESS_MESSAGE:
  625. if (!(task->flags & RSPAMD_TASK_FLAG_SKIP_PROCESS)) {
  626. rspamd_message_process (task);
  627. }
  628. break;
  629. case RSPAMD_TASK_STAGE_FILTERS:
  630. rspamd_symcache_process_symbols (task, task->cfg->cache,
  631. RSPAMD_TASK_STAGE_FILTERS);
  632. break;
  633. case RSPAMD_TASK_STAGE_CLASSIFIERS:
  634. case RSPAMD_TASK_STAGE_CLASSIFIERS_PRE:
  635. case RSPAMD_TASK_STAGE_CLASSIFIERS_POST:
  636. if (!RSPAMD_TASK_IS_EMPTY (task)) {
  637. if (rspamd_stat_classify (task, task->cfg->lua_state, st, &stat_error) ==
  638. RSPAMD_STAT_PROCESS_ERROR) {
  639. msg_err_task ("classify error: %e", stat_error);
  640. g_error_free (stat_error);
  641. }
  642. }
  643. break;
  644. case RSPAMD_TASK_STAGE_COMPOSITES:
  645. rspamd_make_composites (task);
  646. break;
  647. case RSPAMD_TASK_STAGE_POST_FILTERS:
  648. rspamd_symcache_process_symbols (task, task->cfg->cache,
  649. RSPAMD_TASK_STAGE_POST_FILTERS);
  650. if ((task->flags & RSPAMD_TASK_FLAG_LEARN_AUTO) &&
  651. !RSPAMD_TASK_IS_EMPTY (task) &&
  652. !(task->flags & (RSPAMD_TASK_FLAG_LEARN_SPAM|RSPAMD_TASK_FLAG_LEARN_HAM))) {
  653. rspamd_stat_check_autolearn (task);
  654. }
  655. break;
  656. case RSPAMD_TASK_STAGE_LEARN:
  657. case RSPAMD_TASK_STAGE_LEARN_PRE:
  658. case RSPAMD_TASK_STAGE_LEARN_POST:
  659. if (task->flags & (RSPAMD_TASK_FLAG_LEARN_SPAM|RSPAMD_TASK_FLAG_LEARN_HAM)) {
  660. if (task->err == NULL) {
  661. if (!rspamd_stat_learn (task,
  662. task->flags & RSPAMD_TASK_FLAG_LEARN_SPAM,
  663. task->cfg->lua_state, task->classifier,
  664. st, &stat_error)) {
  665. if (stat_error == NULL) {
  666. g_set_error (&stat_error,
  667. g_quark_from_static_string ("stat"), 500,
  668. "Unknown statistics error");
  669. }
  670. msg_err_task ("learn error: %e", stat_error);
  671. if (!(task->flags & RSPAMD_TASK_FLAG_LEARN_AUTO)) {
  672. task->err = stat_error;
  673. task->processed_stages |= RSPAMD_TASK_STAGE_DONE;
  674. }
  675. else {
  676. /* Do not skip idempotent in case of learn error */
  677. if (stat_error) {
  678. g_error_free (stat_error);
  679. }
  680. task->processed_stages |= RSPAMD_TASK_STAGE_LEARN|
  681. RSPAMD_TASK_STAGE_LEARN_PRE|
  682. RSPAMD_TASK_STAGE_LEARN_POST;
  683. }
  684. }
  685. }
  686. }
  687. break;
  688. case RSPAMD_TASK_STAGE_COMPOSITES_POST:
  689. /* Second run of composites processing before idempotent filters */
  690. rspamd_make_composites (task);
  691. break;
  692. case RSPAMD_TASK_STAGE_IDEMPOTENT:
  693. rspamd_symcache_process_symbols (task, task->cfg->cache,
  694. RSPAMD_TASK_STAGE_IDEMPOTENT);
  695. break;
  696. case RSPAMD_TASK_STAGE_DONE:
  697. task->processed_stages |= RSPAMD_TASK_STAGE_DONE;
  698. break;
  699. default:
  700. /* TODO: not implemented stage */
  701. break;
  702. }
  703. if (RSPAMD_TASK_IS_SKIPPED (task)) {
  704. /* Set all bits except idempotent filters */
  705. task->processed_stages |= 0x7FFF;
  706. }
  707. task->flags &= ~RSPAMD_TASK_FLAG_PROCESSING;
  708. if (!ret || RSPAMD_TASK_IS_PROCESSED (task)) {
  709. if (!ret) {
  710. /* Set processed flags */
  711. task->processed_stages |= RSPAMD_TASK_STAGE_DONE;
  712. }
  713. msg_debug_task ("task is processed");
  714. return ret;
  715. }
  716. if (rspamd_session_events_pending (task->s) != 0) {
  717. /* We have events pending, so we consider this stage as incomplete */
  718. msg_debug_task ("need more work on stage %d", st);
  719. }
  720. else {
  721. /* Mark the current stage as done and go to the next stage */
  722. msg_debug_task ("completed stage %d", st);
  723. task->processed_stages |= st;
  724. /* Tail recursion */
  725. return rspamd_task_process (task, stages);
  726. }
  727. return ret;
  728. }
  729. struct rspamd_email_address*
  730. rspamd_task_get_sender (struct rspamd_task *task)
  731. {
  732. return task->from_envelope;
  733. }
  734. static const gchar *
  735. rspamd_task_cache_principal_recipient (struct rspamd_task *task,
  736. const gchar *rcpt, gsize len)
  737. {
  738. gchar *rcpt_lc;
  739. if (rcpt == NULL) {
  740. return NULL;
  741. }
  742. rcpt_lc = rspamd_mempool_alloc (task->task_pool, len + 1);
  743. rspamd_strlcpy (rcpt_lc, rcpt, len + 1);
  744. rspamd_str_lc (rcpt_lc, len);
  745. rspamd_mempool_set_variable (task->task_pool,
  746. RSPAMD_MEMPOOL_PRINCIPAL_RECIPIENT, rcpt_lc, NULL);
  747. return rcpt_lc;
  748. }
  749. const gchar *
  750. rspamd_task_get_principal_recipient (struct rspamd_task *task)
  751. {
  752. const gchar *val;
  753. struct rspamd_email_address *addr;
  754. val = rspamd_mempool_get_variable (task->task_pool,
  755. RSPAMD_MEMPOOL_PRINCIPAL_RECIPIENT);
  756. if (val) {
  757. return val;
  758. }
  759. if (task->deliver_to) {
  760. return rspamd_task_cache_principal_recipient (task, task->deliver_to,
  761. strlen (task->deliver_to));
  762. }
  763. if (task->rcpt_envelope != NULL) {
  764. addr = g_ptr_array_index (task->rcpt_envelope, 0);
  765. if (addr->addr) {
  766. return rspamd_task_cache_principal_recipient (task, addr->addr,
  767. addr->addr_len);
  768. }
  769. }
  770. if (task->rcpt_mime != NULL && task->rcpt_mime->len > 0) {
  771. addr = g_ptr_array_index (task->rcpt_mime, 0);
  772. if (addr->addr) {
  773. return rspamd_task_cache_principal_recipient (task, addr->addr,
  774. addr->addr_len);
  775. }
  776. }
  777. return NULL;
  778. }
  779. gboolean
  780. rspamd_learn_task_spam (struct rspamd_task *task,
  781. gboolean is_spam,
  782. const gchar *classifier,
  783. GError **err)
  784. {
  785. if (is_spam) {
  786. task->flags |= RSPAMD_TASK_FLAG_LEARN_SPAM;
  787. }
  788. else {
  789. task->flags |= RSPAMD_TASK_FLAG_LEARN_HAM;
  790. }
  791. task->classifier = classifier;
  792. return TRUE;
  793. }
  794. static gboolean
  795. rspamd_task_log_check_condition (struct rspamd_task *task,
  796. struct rspamd_log_format *lf)
  797. {
  798. gboolean ret = FALSE;
  799. switch (lf->type) {
  800. case RSPAMD_LOG_MID:
  801. if (task->message_id && strcmp (task->message_id, "undef") != 0) {
  802. ret = TRUE;
  803. }
  804. break;
  805. case RSPAMD_LOG_QID:
  806. if (task->queue_id && strcmp (task->queue_id, "undef") != 0) {
  807. ret = TRUE;
  808. }
  809. break;
  810. case RSPAMD_LOG_USER:
  811. if (task->user) {
  812. ret = TRUE;
  813. }
  814. break;
  815. case RSPAMD_LOG_IP:
  816. if (task->from_addr && rspamd_ip_is_valid (task->from_addr)) {
  817. ret = TRUE;
  818. }
  819. break;
  820. case RSPAMD_LOG_SMTP_RCPT:
  821. case RSPAMD_LOG_SMTP_RCPTS:
  822. if (task->rcpt_envelope && task->rcpt_envelope->len > 0) {
  823. ret = TRUE;
  824. }
  825. break;
  826. case RSPAMD_LOG_MIME_RCPT:
  827. case RSPAMD_LOG_MIME_RCPTS:
  828. if (task->rcpt_mime && task->rcpt_mime->len > 0) {
  829. ret = TRUE;
  830. }
  831. break;
  832. case RSPAMD_LOG_SMTP_FROM:
  833. if (task->from_envelope) {
  834. ret = TRUE;
  835. }
  836. break;
  837. case RSPAMD_LOG_MIME_FROM:
  838. if (task->from_mime && task->from_mime->len > 0) {
  839. ret = TRUE;
  840. }
  841. break;
  842. case RSPAMD_LOG_FILENAME:
  843. if (task->msg.fpath) {
  844. ret = TRUE;
  845. }
  846. break;
  847. case RSPAMD_LOG_FORCED_ACTION:
  848. if (task->result->passthrough_result) {
  849. ret = TRUE;
  850. }
  851. break;
  852. default:
  853. ret = TRUE;
  854. break;
  855. }
  856. return ret;
  857. }
  858. /*
  859. * Sort by symbol's score -> name
  860. */
  861. static gint
  862. rspamd_task_compare_log_sym (gconstpointer a, gconstpointer b)
  863. {
  864. const struct rspamd_symbol_result *s1 = *(const struct rspamd_symbol_result **)a,
  865. *s2 = *(const struct rspamd_symbol_result **)b;
  866. gdouble w1, w2;
  867. w1 = fabs (s1->score);
  868. w2 = fabs (s2->score);
  869. if (w1 == w2 && s1->name && s2->name) {
  870. return strcmp (s1->name, s2->name);
  871. }
  872. return (w2 - w1) * 1000.0;
  873. }
  874. static rspamd_ftok_t
  875. rspamd_task_log_metric_res (struct rspamd_task *task,
  876. struct rspamd_log_format *lf)
  877. {
  878. static gchar scorebuf[32];
  879. rspamd_ftok_t res = {.begin = NULL, .len = 0};
  880. struct rspamd_metric_result *mres;
  881. gboolean first = TRUE;
  882. rspamd_fstring_t *symbuf;
  883. struct rspamd_symbol_result *sym;
  884. GPtrArray *sorted_symbols;
  885. struct rspamd_action *act;
  886. guint i, j;
  887. mres = task->result;
  888. act = rspamd_check_action_metric (task);
  889. if (mres != NULL) {
  890. switch (lf->type) {
  891. case RSPAMD_LOG_ISSPAM:
  892. if (RSPAMD_TASK_IS_SKIPPED (task)) {
  893. res.begin = "S";
  894. }
  895. else if (!(act->flags & RSPAMD_ACTION_HAM)) {
  896. res.begin = "T";
  897. }
  898. else {
  899. res.begin = "F";
  900. }
  901. res.len = 1;
  902. break;
  903. case RSPAMD_LOG_ACTION:
  904. res.begin = act->name;
  905. res.len = strlen (res.begin);
  906. break;
  907. case RSPAMD_LOG_SCORES:
  908. res.len = rspamd_snprintf (scorebuf, sizeof (scorebuf), "%.2f/%.2f",
  909. mres->score, rspamd_task_get_required_score (task, mres));
  910. res.begin = scorebuf;
  911. break;
  912. case RSPAMD_LOG_SYMBOLS:
  913. symbuf = rspamd_fstring_sized_new (128);
  914. sorted_symbols = g_ptr_array_sized_new (kh_size (mres->symbols));
  915. kh_foreach_value_ptr (mres->symbols, sym, {
  916. if (!(sym->flags & RSPAMD_SYMBOL_RESULT_IGNORED)) {
  917. g_ptr_array_add (sorted_symbols, (gpointer)sym);
  918. }
  919. });
  920. g_ptr_array_sort (sorted_symbols, rspamd_task_compare_log_sym);
  921. for (i = 0; i < sorted_symbols->len; i ++) {
  922. sym = g_ptr_array_index (sorted_symbols, i);
  923. if (first) {
  924. rspamd_printf_fstring (&symbuf, "%s", sym->name);
  925. }
  926. else {
  927. rspamd_printf_fstring (&symbuf, ",%s", sym->name);
  928. }
  929. if (lf->flags & RSPAMD_LOG_FMT_FLAG_SYMBOLS_SCORES) {
  930. rspamd_printf_fstring (&symbuf, "(%.2f)", sym->score);
  931. }
  932. if (lf->flags & RSPAMD_LOG_FMT_FLAG_SYMBOLS_PARAMS) {
  933. rspamd_printf_fstring (&symbuf, "{");
  934. if (sym->options) {
  935. struct rspamd_symbol_option *opt;
  936. j = 0;
  937. DL_FOREACH (sym->opts_head, opt) {
  938. rspamd_printf_fstring (&symbuf, "%s;", opt->option);
  939. if (j >= max_log_elts) {
  940. rspamd_printf_fstring (&symbuf, "...;");
  941. break;
  942. }
  943. j ++;
  944. }
  945. }
  946. rspamd_printf_fstring (&symbuf, "}");
  947. }
  948. first = FALSE;
  949. }
  950. g_ptr_array_free (sorted_symbols, TRUE);
  951. rspamd_mempool_add_destructor (task->task_pool,
  952. (rspamd_mempool_destruct_t)rspamd_fstring_free,
  953. symbuf);
  954. res.begin = symbuf->str;
  955. res.len = symbuf->len;
  956. break;
  957. default:
  958. break;
  959. }
  960. }
  961. return res;
  962. }
  963. static rspamd_fstring_t *
  964. rspamd_task_log_write_var (struct rspamd_task *task, rspamd_fstring_t *logbuf,
  965. const rspamd_ftok_t *var, const rspamd_ftok_t *content)
  966. {
  967. rspamd_fstring_t *res = logbuf;
  968. const gchar *p, *c, *end;
  969. if (content == NULL) {
  970. /* Just output variable */
  971. res = rspamd_fstring_append (res, var->begin, var->len);
  972. }
  973. else {
  974. /* Replace $ with variable value */
  975. p = content->begin;
  976. c = p;
  977. end = p + content->len;
  978. while (p < end) {
  979. if (*p == '$') {
  980. if (p > c) {
  981. res = rspamd_fstring_append (res, c, p - c);
  982. }
  983. res = rspamd_fstring_append (res, var->begin, var->len);
  984. p ++;
  985. c = p;
  986. }
  987. else {
  988. p ++;
  989. }
  990. }
  991. if (p > c) {
  992. res = rspamd_fstring_append (res, c, p - c);
  993. }
  994. }
  995. return res;
  996. }
  997. static rspamd_fstring_t *
  998. rspamd_task_write_ialist (struct rspamd_task *task,
  999. GPtrArray *addrs, gint lim,
  1000. struct rspamd_log_format *lf,
  1001. rspamd_fstring_t *logbuf)
  1002. {
  1003. rspamd_fstring_t *res = logbuf, *varbuf;
  1004. rspamd_ftok_t var = {.begin = NULL, .len = 0};
  1005. struct rspamd_email_address *addr;
  1006. gint i, nchars = 0, cur_chars;
  1007. if (lim <= 0) {
  1008. lim = addrs->len;
  1009. }
  1010. varbuf = rspamd_fstring_new ();
  1011. PTR_ARRAY_FOREACH (addrs, i, addr) {
  1012. if (i >= lim) {
  1013. break;
  1014. }
  1015. cur_chars = addr->addr_len;
  1016. varbuf = rspamd_fstring_append (varbuf, addr->addr,
  1017. cur_chars);
  1018. nchars += cur_chars;
  1019. if (varbuf->len > 0) {
  1020. if (i != lim - 1) {
  1021. varbuf = rspamd_fstring_append (varbuf, ",", 1);
  1022. }
  1023. }
  1024. if (i >= max_log_elts || nchars >= max_log_elts * 10) {
  1025. varbuf = rspamd_fstring_append (varbuf, "...", 3);
  1026. break;
  1027. }
  1028. }
  1029. if (varbuf->len > 0) {
  1030. var.begin = varbuf->str;
  1031. var.len = varbuf->len;
  1032. res = rspamd_task_log_write_var (task, logbuf,
  1033. &var, (const rspamd_ftok_t *) lf->data);
  1034. }
  1035. rspamd_fstring_free (varbuf);
  1036. return res;
  1037. }
  1038. static rspamd_fstring_t *
  1039. rspamd_task_write_addr_list (struct rspamd_task *task,
  1040. GPtrArray *addrs, gint lim,
  1041. struct rspamd_log_format *lf,
  1042. rspamd_fstring_t *logbuf)
  1043. {
  1044. rspamd_fstring_t *res = logbuf, *varbuf;
  1045. rspamd_ftok_t var = {.begin = NULL, .len = 0};
  1046. struct rspamd_email_address *addr;
  1047. gint i;
  1048. if (lim <= 0) {
  1049. lim = addrs->len;
  1050. }
  1051. varbuf = rspamd_fstring_new ();
  1052. for (i = 0; i < lim; i++) {
  1053. addr = g_ptr_array_index (addrs, i);
  1054. if (addr->addr) {
  1055. varbuf = rspamd_fstring_append (varbuf, addr->addr, addr->addr_len);
  1056. }
  1057. if (varbuf->len > 0) {
  1058. if (i != lim - 1) {
  1059. varbuf = rspamd_fstring_append (varbuf, ",", 1);
  1060. }
  1061. }
  1062. if (i >= max_log_elts) {
  1063. varbuf = rspamd_fstring_append (varbuf, "...", 3);
  1064. break;
  1065. }
  1066. }
  1067. if (varbuf->len > 0) {
  1068. var.begin = varbuf->str;
  1069. var.len = varbuf->len;
  1070. res = rspamd_task_log_write_var (task, logbuf,
  1071. &var, (const rspamd_ftok_t *) lf->data);
  1072. }
  1073. rspamd_fstring_free (varbuf);
  1074. return res;
  1075. }
  1076. static rspamd_fstring_t *
  1077. rspamd_task_log_variable (struct rspamd_task *task,
  1078. struct rspamd_log_format *lf, rspamd_fstring_t *logbuf)
  1079. {
  1080. rspamd_fstring_t *res = logbuf;
  1081. rspamd_ftok_t var = {.begin = NULL, .len = 0};
  1082. static gchar numbuf[128];
  1083. static const gchar undef[] = "undef";
  1084. switch (lf->type) {
  1085. /* String vars */
  1086. case RSPAMD_LOG_MID:
  1087. if (task->message_id) {
  1088. var.begin = task->message_id;
  1089. var.len = strlen (var.begin);
  1090. }
  1091. else {
  1092. var.begin = undef;
  1093. var.len = sizeof (undef) - 1;
  1094. }
  1095. break;
  1096. case RSPAMD_LOG_QID:
  1097. if (task->queue_id) {
  1098. var.begin = task->queue_id;
  1099. var.len = strlen (var.begin);
  1100. }
  1101. else {
  1102. var.begin = undef;
  1103. var.len = sizeof (undef) - 1;
  1104. }
  1105. break;
  1106. case RSPAMD_LOG_USER:
  1107. if (task->user) {
  1108. var.begin = task->user;
  1109. var.len = strlen (var.begin);
  1110. }
  1111. else {
  1112. var.begin = undef;
  1113. var.len = sizeof (undef) - 1;
  1114. }
  1115. break;
  1116. case RSPAMD_LOG_IP:
  1117. if (task->from_addr && rspamd_ip_is_valid (task->from_addr)) {
  1118. var.begin = rspamd_inet_address_to_string (task->from_addr);
  1119. var.len = strlen (var.begin);
  1120. }
  1121. else {
  1122. var.begin = undef;
  1123. var.len = sizeof (undef) - 1;
  1124. }
  1125. break;
  1126. /* Numeric vars */
  1127. case RSPAMD_LOG_LEN:
  1128. var.len = rspamd_snprintf (numbuf, sizeof (numbuf), "%uz",
  1129. task->msg.len);
  1130. var.begin = numbuf;
  1131. break;
  1132. case RSPAMD_LOG_DNS_REQ:
  1133. var.len = rspamd_snprintf (numbuf, sizeof (numbuf), "%uD",
  1134. task->dns_requests);
  1135. var.begin = numbuf;
  1136. break;
  1137. case RSPAMD_LOG_TIME_REAL:
  1138. var.begin = rspamd_log_check_time (task->time_real,
  1139. task->time_real_finish,
  1140. task->cfg->clock_res);
  1141. var.len = strlen (var.begin);
  1142. break;
  1143. case RSPAMD_LOG_TIME_VIRTUAL:
  1144. var.begin = rspamd_log_check_time (task->time_virtual,
  1145. task->time_virtual_finish,
  1146. task->cfg->clock_res);
  1147. var.len = strlen (var.begin);
  1148. break;
  1149. /* InternetAddress vars */
  1150. case RSPAMD_LOG_SMTP_FROM:
  1151. if (task->from_envelope) {
  1152. var.begin = task->from_envelope->addr;
  1153. var.len = task->from_envelope->addr_len;
  1154. }
  1155. break;
  1156. case RSPAMD_LOG_MIME_FROM:
  1157. if (task->from_mime) {
  1158. return rspamd_task_write_ialist (task, task->from_mime, 1, lf,
  1159. logbuf);
  1160. }
  1161. break;
  1162. case RSPAMD_LOG_SMTP_RCPT:
  1163. if (task->rcpt_envelope) {
  1164. return rspamd_task_write_addr_list (task, task->rcpt_envelope, 1, lf,
  1165. logbuf);
  1166. }
  1167. break;
  1168. case RSPAMD_LOG_MIME_RCPT:
  1169. if (task->rcpt_mime) {
  1170. return rspamd_task_write_ialist (task, task->rcpt_mime, 1, lf,
  1171. logbuf);
  1172. }
  1173. break;
  1174. case RSPAMD_LOG_SMTP_RCPTS:
  1175. if (task->rcpt_envelope) {
  1176. return rspamd_task_write_addr_list (task, task->rcpt_envelope, -1, lf,
  1177. logbuf);
  1178. }
  1179. break;
  1180. case RSPAMD_LOG_MIME_RCPTS:
  1181. if (task->rcpt_mime) {
  1182. return rspamd_task_write_ialist (task, task->rcpt_mime, -1, lf,
  1183. logbuf);
  1184. }
  1185. break;
  1186. case RSPAMD_LOG_DIGEST:
  1187. var.len = rspamd_snprintf (numbuf, sizeof (numbuf), "%*xs",
  1188. (gint)sizeof (task->digest), task->digest);
  1189. var.begin = numbuf;
  1190. break;
  1191. case RSPAMD_LOG_FILENAME:
  1192. if (task->msg.fpath) {
  1193. var.len = strlen (task->msg.fpath);
  1194. var.begin = task->msg.fpath;
  1195. }
  1196. else {
  1197. var.begin = undef;
  1198. var.len = sizeof (undef) - 1;
  1199. }
  1200. break;
  1201. case RSPAMD_LOG_FORCED_ACTION:
  1202. if (task->result->passthrough_result) {
  1203. struct rspamd_passthrough_result *pr = task->result->passthrough_result;
  1204. if (!isnan (pr->target_score)) {
  1205. var.len = rspamd_snprintf (numbuf, sizeof (numbuf),
  1206. "%s \"%s\"; score=%.2f (set by %s)",
  1207. pr->action->name,
  1208. pr->message,
  1209. pr->target_score,
  1210. pr->module);
  1211. }
  1212. else {
  1213. var.len = rspamd_snprintf (numbuf, sizeof (numbuf),
  1214. "%s \"%s\"; score=nan (set by %s)",
  1215. pr->action->name,
  1216. pr->message,
  1217. pr->module);
  1218. }
  1219. var.begin = numbuf;
  1220. }
  1221. else {
  1222. var.begin = undef;
  1223. var.len = sizeof (undef) - 1;
  1224. }
  1225. break;
  1226. default:
  1227. var = rspamd_task_log_metric_res (task, lf);
  1228. break;
  1229. }
  1230. if (var.len > 0) {
  1231. res = rspamd_task_log_write_var (task, logbuf,
  1232. &var, (const rspamd_ftok_t *)lf->data);
  1233. }
  1234. return res;
  1235. }
  1236. void
  1237. rspamd_task_write_log (struct rspamd_task *task)
  1238. {
  1239. rspamd_fstring_t *logbuf;
  1240. struct rspamd_log_format *lf;
  1241. struct rspamd_task **ptask;
  1242. const gchar *lua_str;
  1243. gsize lua_str_len;
  1244. lua_State *L;
  1245. g_assert (task != NULL);
  1246. if (task->cfg->log_format == NULL ||
  1247. (task->flags & RSPAMD_TASK_FLAG_NO_LOG)) {
  1248. return;
  1249. }
  1250. logbuf = rspamd_fstring_sized_new (1000);
  1251. DL_FOREACH (task->cfg->log_format, lf) {
  1252. switch (lf->type) {
  1253. case RSPAMD_LOG_STRING:
  1254. logbuf = rspamd_fstring_append (logbuf, lf->data, lf->len);
  1255. break;
  1256. case RSPAMD_LOG_LUA:
  1257. L = task->cfg->lua_state;
  1258. lua_rawgeti (L, LUA_REGISTRYINDEX, GPOINTER_TO_INT (lf->data));
  1259. ptask = lua_newuserdata (L, sizeof (*ptask));
  1260. rspamd_lua_setclass (L, "rspamd{task}", -1);
  1261. *ptask = task;
  1262. if (lua_pcall (L, 1, 1, 0) != 0) {
  1263. msg_err_task ("call to log function failed: %s",
  1264. lua_tostring (L, -1));
  1265. lua_pop (L, 1);
  1266. }
  1267. else {
  1268. lua_str = lua_tolstring (L, -1, &lua_str_len);
  1269. if (lua_str != NULL) {
  1270. logbuf = rspamd_fstring_append (logbuf, lua_str, lua_str_len);
  1271. }
  1272. lua_pop (L, 1);
  1273. }
  1274. break;
  1275. default:
  1276. /* We have a variable in log format */
  1277. if (lf->flags & RSPAMD_LOG_FMT_FLAG_CONDITION) {
  1278. if (!rspamd_task_log_check_condition (task, lf)) {
  1279. continue;
  1280. }
  1281. }
  1282. logbuf = rspamd_task_log_variable (task, lf, logbuf);
  1283. break;
  1284. }
  1285. }
  1286. msg_notice_task ("%V", logbuf);
  1287. rspamd_fstring_free (logbuf);
  1288. }
  1289. gdouble
  1290. rspamd_task_get_required_score (struct rspamd_task *task, struct rspamd_metric_result *m)
  1291. {
  1292. gint i;
  1293. if (m == NULL) {
  1294. m = task->result;
  1295. if (m == NULL) {
  1296. return NAN;
  1297. }
  1298. }
  1299. for (i = m->nactions - 1; i >= 0; i --) {
  1300. struct rspamd_action_result *action_lim = &m->actions_limits[i];
  1301. if (!isnan (action_lim->cur_limit) &&
  1302. !(action_lim->action->flags & (RSPAMD_ACTION_NO_THRESHOLD|RSPAMD_ACTION_HAM))) {
  1303. return m->actions_limits[i].cur_limit;
  1304. }
  1305. }
  1306. return NAN;
  1307. }
  1308. rspamd_ftok_t *
  1309. rspamd_task_get_request_header (struct rspamd_task *task,
  1310. const gchar *name)
  1311. {
  1312. GPtrArray *ret;
  1313. rspamd_ftok_t srch;
  1314. srch.begin = (gchar *)name;
  1315. srch.len = strlen (name);
  1316. ret = g_hash_table_lookup (task->request_headers, &srch);
  1317. if (ret) {
  1318. return (rspamd_ftok_t *)g_ptr_array_index (ret, 0);
  1319. }
  1320. return NULL;
  1321. }
  1322. GPtrArray*
  1323. rspamd_task_get_request_header_multiple (struct rspamd_task *task,
  1324. const gchar *name)
  1325. {
  1326. GPtrArray *ret;
  1327. rspamd_ftok_t srch;
  1328. srch.begin = (gchar *)name;
  1329. srch.len = strlen (name);
  1330. ret = g_hash_table_lookup (task->request_headers, &srch);
  1331. return ret;
  1332. }
  1333. void
  1334. rspamd_task_add_request_header (struct rspamd_task *task,
  1335. rspamd_ftok_t *name, rspamd_ftok_t *value)
  1336. {
  1337. GPtrArray *ret;
  1338. ret = g_hash_table_lookup (task->request_headers, name);
  1339. if (ret) {
  1340. g_ptr_array_add (ret, value);
  1341. /* We need to free name token */
  1342. rspamd_fstring_mapped_ftok_free (name);
  1343. }
  1344. else {
  1345. ret = g_ptr_array_sized_new (2);
  1346. g_ptr_array_add (ret, value);
  1347. g_hash_table_replace (task->request_headers, name, ret);
  1348. }
  1349. }
  1350. void
  1351. rspamd_task_profile_set (struct rspamd_task *task, const gchar *key,
  1352. gdouble value)
  1353. {
  1354. GHashTable *tbl;
  1355. gdouble *pval;
  1356. if (key == NULL) {
  1357. return;
  1358. }
  1359. tbl = rspamd_mempool_get_variable (task->task_pool, RSPAMD_MEMPOOL_PROFILE);
  1360. if (tbl == NULL) {
  1361. tbl = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  1362. rspamd_mempool_set_variable (task->task_pool, RSPAMD_MEMPOOL_PROFILE,
  1363. tbl, (rspamd_mempool_destruct_t)g_hash_table_unref);
  1364. }
  1365. pval = g_hash_table_lookup (tbl, key);
  1366. if (pval == NULL) {
  1367. pval = rspamd_mempool_alloc (task->task_pool, sizeof (*pval));
  1368. *pval = value;
  1369. g_hash_table_insert (tbl, (void *)key, pval);
  1370. }
  1371. else {
  1372. *pval = value;
  1373. }
  1374. }
  1375. gdouble*
  1376. rspamd_task_profile_get (struct rspamd_task *task, const gchar *key)
  1377. {
  1378. GHashTable *tbl;
  1379. gdouble *pval = NULL;
  1380. tbl = rspamd_mempool_get_variable (task->task_pool, RSPAMD_MEMPOOL_PROFILE);
  1381. if (tbl != NULL) {
  1382. pval = g_hash_table_lookup (tbl, key);
  1383. }
  1384. return pval;
  1385. }
  1386. gboolean
  1387. rspamd_task_set_finish_time (struct rspamd_task *task)
  1388. {
  1389. struct timeval tv;
  1390. if (isnan (task->time_real_finish)) {
  1391. #ifdef HAVE_EVENT_NO_CACHE_TIME_FUNC
  1392. if (task->ev_base) {
  1393. event_base_update_cache_time (task->ev_base);
  1394. event_base_gettimeofday_cached (task->ev_base, &tv);
  1395. task->time_real_finish = tv_to_double (&tv);
  1396. }
  1397. else {
  1398. gettimeofday (&tv, NULL);
  1399. task->time_real_finish = tv_to_double (&tv);
  1400. }
  1401. #else
  1402. gettimeofday (&tv, NULL);
  1403. task->time_real_finish = tv_to_double (&tv);
  1404. #endif
  1405. task->time_virtual_finish = rspamd_get_virtual_ticks ();
  1406. return TRUE;
  1407. }
  1408. return FALSE;
  1409. }