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.

cfg_utils.c 71KB

15 vuotta sitten
15 vuotta sitten
15 vuotta sitten
10 vuotta sitten
16 vuotta sitten
10 vuotta sitten
16 vuotta sitten
16 vuotta sitten
16 vuotta sitten
16 vuotta sitten
7 vuotta sitten
8 vuotta sitten
16 vuotta sitten
10 vuotta sitten
16 vuotta sitten
7 vuotta sitten
16 vuotta sitten
10 vuotta sitten
10 vuotta sitten
8 vuotta sitten
8 vuotta sitten
8 vuotta sitten
10 vuotta sitten
10 vuotta sitten
8 vuotta sitten
10 vuotta sitten
9 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
10 vuotta sitten
8 vuotta sitten
8 vuotta sitten
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008
  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 "config.h"
  17. #include "cfg_file.h"
  18. #include "rspamd.h"
  19. #include "cfg_file_private.h"
  20. #include "scan_result.h"
  21. #include "lua/lua_common.h"
  22. #include "lua/lua_thread_pool.h"
  23. #include "maps/map.h"
  24. #include "maps/map_helpers.h"
  25. #include "maps/map_private.h"
  26. #include "dynamic_cfg.h"
  27. #include "utlist.h"
  28. #include "stat_api.h"
  29. #include "unix-std.h"
  30. #include "libutil/multipattern.h"
  31. #include "monitored.h"
  32. #include "ref.h"
  33. #include "cryptobox.h"
  34. #include "ssl_util.h"
  35. #include "contrib/libottery/ottery.h"
  36. #include "contrib/fastutf8/fastutf8.h"
  37. #define ZSTD_STATIC_LINKING_ONLY
  38. #include "contrib/zstd/zstd.h"
  39. #include "contrib/zstd/zdict.h"
  40. #ifdef HAVE_OPENSSL
  41. #include <openssl/rand.h>
  42. #include <openssl/err.h>
  43. #include <openssl/evp.h>
  44. #include <openssl/ssl.h>
  45. #include <openssl/conf.h>
  46. #endif
  47. #ifdef HAVE_LOCALE_H
  48. #include <locale.h>
  49. #endif
  50. #ifdef HAVE_SYS_RESOURCE_H
  51. #include <sys/resource.h>
  52. #endif
  53. #include <math.h>
  54. #include "blas-config.h"
  55. #define DEFAULT_SCORE 10.0
  56. #define DEFAULT_RLIMIT_NOFILE 2048
  57. #define DEFAULT_RLIMIT_MAXCORE 0
  58. #define DEFAULT_MAP_TIMEOUT 60.0 * 5
  59. #define DEFAULT_MAP_FILE_WATCH_MULTIPLIER 1
  60. #define DEFAULT_MIN_WORD 0
  61. #define DEFAULT_MAX_WORD 40
  62. #define DEFAULT_WORDS_DECAY 600
  63. #define DEFAULT_MAX_MESSAGE (50 * 1024 * 1024)
  64. #define DEFAULT_MAX_PIC (1 * 1024 * 1024)
  65. #define DEFAULT_MAX_SHOTS 100
  66. #define DEFAULT_MAX_SESSIONS 100
  67. #define DEFAULT_MAX_WORKERS 4
  68. /* Timeout for task processing */
  69. #define DEFAULT_TASK_TIMEOUT 8.0
  70. #define DEFAULT_LUA_GC_STEP 200
  71. #define DEFAULT_LUA_GC_PAUSE 200
  72. #define DEFAULT_GC_MAXITERS 0
  73. struct rspamd_ucl_map_cbdata {
  74. struct rspamd_config *cfg;
  75. GString *buf;
  76. };
  77. static gchar * rspamd_ucl_read_cb (gchar * chunk,
  78. gint len,
  79. struct map_cb_data *data,
  80. gboolean final);
  81. static void rspamd_ucl_fin_cb (struct map_cb_data *data, void **target);
  82. static void rspamd_ucl_dtor_cb (struct map_cb_data *data);
  83. guint rspamd_config_log_id = (guint)-1;
  84. RSPAMD_CONSTRUCTOR(rspamd_config_log_init)
  85. {
  86. rspamd_config_log_id = rspamd_logger_add_debug_module("config");
  87. }
  88. gboolean
  89. rspamd_parse_bind_line (struct rspamd_config *cfg,
  90. struct rspamd_worker_conf *cf,
  91. const gchar *str)
  92. {
  93. struct rspamd_worker_bind_conf *cnf;
  94. const gchar *fdname;
  95. gboolean ret = TRUE;
  96. if (str == NULL) {
  97. return FALSE;
  98. }
  99. cnf = g_malloc0 (sizeof (struct rspamd_worker_bind_conf));
  100. cnf->cnt = 1024;
  101. cnf->bind_line = g_strdup (str);
  102. if (g_ascii_strncasecmp (str, "systemd:", sizeof ("systemd:") - 1) == 0) {
  103. /* The actual socket will be passed by systemd environment */
  104. fdname = str + sizeof ("systemd:") - 1;
  105. cnf->is_systemd = TRUE;
  106. cnf->addrs = g_ptr_array_new_full (1, g_free);
  107. if (fdname[0]) {
  108. g_ptr_array_add (cnf->addrs, g_strdup (fdname));
  109. cnf->cnt = cnf->addrs->len;
  110. cnf->name = g_strdup (str);
  111. LL_PREPEND (cf->bind_conf, cnf);
  112. }
  113. else {
  114. msg_err_config ("cannot parse bind line: %s", str);
  115. ret = FALSE;
  116. }
  117. }
  118. else {
  119. if (rspamd_parse_host_port_priority (str, &cnf->addrs,
  120. NULL, &cnf->name, DEFAULT_BIND_PORT, TRUE, NULL) == RSPAMD_PARSE_ADDR_FAIL) {
  121. msg_err_config ("cannot parse bind line: %s", str);
  122. ret = FALSE;
  123. }
  124. else {
  125. cnf->cnt = cnf->addrs->len;
  126. LL_PREPEND (cf->bind_conf, cnf);
  127. }
  128. }
  129. if (!ret) {
  130. if (cnf->addrs) {
  131. g_ptr_array_free (cnf->addrs, TRUE);
  132. }
  133. g_free (cnf->name);
  134. g_free (cnf);
  135. }
  136. return ret;
  137. }
  138. struct rspamd_config *
  139. rspamd_config_new (enum rspamd_config_init_flags flags)
  140. {
  141. struct rspamd_config *cfg;
  142. rspamd_mempool_t *pool;
  143. pool = rspamd_mempool_new (8 * 1024 * 1024, "cfg", 0);
  144. cfg = rspamd_mempool_alloc0 (pool, sizeof (*cfg));
  145. /* Allocate larger pool for cfg */
  146. cfg->cfg_pool = pool;
  147. cfg->dns_timeout = 1.0;
  148. cfg->dns_retransmits = 5;
  149. /* 16 sockets per DNS server */
  150. cfg->dns_io_per_server = 16;
  151. /* Add all internal actions to keep compatibility */
  152. for (int i = METRIC_ACTION_REJECT; i < METRIC_ACTION_MAX; i ++) {
  153. struct rspamd_action *action;
  154. action = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*action));
  155. action->threshold = NAN;
  156. action->name = rspamd_mempool_strdup (cfg->cfg_pool,
  157. rspamd_action_to_str (i));
  158. action->action_type = i;
  159. if (i == METRIC_ACTION_SOFT_REJECT) {
  160. action->flags |= RSPAMD_ACTION_NO_THRESHOLD|RSPAMD_ACTION_HAM;
  161. }
  162. else if (i == METRIC_ACTION_GREYLIST) {
  163. action->flags |= RSPAMD_ACTION_THRESHOLD_ONLY|RSPAMD_ACTION_HAM;
  164. }
  165. else if (i == METRIC_ACTION_NOACTION) {
  166. action->flags |= RSPAMD_ACTION_HAM;
  167. }
  168. HASH_ADD_KEYPTR (hh, cfg->actions,
  169. action->name, strlen (action->name), action);
  170. }
  171. /* Disable timeout */
  172. cfg->task_timeout = DEFAULT_TASK_TIMEOUT;
  173. rspamd_config_init_metric (cfg);
  174. cfg->composite_symbols =
  175. g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  176. cfg->classifiers_symbols = g_hash_table_new (rspamd_str_hash,
  177. rspamd_str_equal);
  178. cfg->cfg_params = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  179. cfg->debug_modules = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  180. cfg->explicit_modules = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  181. cfg->wrk_parsers = g_hash_table_new (g_int_hash, g_int_equal);
  182. cfg->trusted_keys = g_hash_table_new (rspamd_str_hash,
  183. rspamd_str_equal);
  184. cfg->map_timeout = DEFAULT_MAP_TIMEOUT;
  185. cfg->map_file_watch_multiplier = DEFAULT_MAP_FILE_WATCH_MULTIPLIER;
  186. cfg->log_level = G_LOG_LEVEL_WARNING;
  187. cfg->log_flags = RSPAMD_LOG_FLAG_DEFAULT;
  188. cfg->check_text_attachements = TRUE;
  189. cfg->dns_max_requests = 64;
  190. cfg->history_rows = 200;
  191. cfg->log_error_elts = 10;
  192. cfg->log_error_elt_maxlen = 1000;
  193. cfg->cache_reload_time = 30.0;
  194. cfg->max_lua_urls = 1024;
  195. cfg->max_urls = cfg->max_lua_urls * 10;
  196. cfg->max_recipients = 1024;
  197. cfg->max_blas_threads = 1;
  198. cfg->max_opts_len = 4096;
  199. /* Default log line */
  200. cfg->log_format_str = "id: <$mid>,$if_qid{ qid: <$>,}$if_ip{ ip: $,}"
  201. "$if_user{ user: $,}$if_smtp_from{ from: <$>,} (default: $is_spam "
  202. "($action): [$scores] [$symbols_scores_params]), len: $len, time: $time_real, "
  203. "dns req: $dns_req, digest: <$digest>"
  204. "$if_smtp_rcpts{ rcpts: <$>, }$if_mime_rcpt{ mime_rcpt: <$>, }";
  205. /* Allow non-mime input by default */
  206. cfg->allow_raw_input = TRUE;
  207. /* Default maximum words processed */
  208. cfg->words_decay = DEFAULT_WORDS_DECAY;
  209. cfg->min_word_len = DEFAULT_MIN_WORD;
  210. cfg->max_word_len = DEFAULT_MAX_WORD;
  211. /* GC limits */
  212. cfg->lua_gc_pause = DEFAULT_LUA_GC_PAUSE;
  213. cfg->lua_gc_step = DEFAULT_LUA_GC_STEP;
  214. cfg->full_gc_iters = DEFAULT_GC_MAXITERS;
  215. if (!(flags & RSPAMD_CONFIG_INIT_SKIP_LUA)) {
  216. cfg->lua_state = rspamd_lua_init (flags & RSPAMD_CONFIG_INIT_WIPE_LUA_MEM);
  217. cfg->own_lua_state = TRUE;
  218. cfg->lua_thread_pool = lua_thread_pool_new (cfg->lua_state);
  219. }
  220. cfg->cache = rspamd_symcache_new (cfg);
  221. cfg->ups_ctx = rspamd_upstreams_library_init ();
  222. cfg->re_cache = rspamd_re_cache_new ();
  223. cfg->doc_strings = ucl_object_typed_new (UCL_OBJECT);
  224. /*
  225. * Unless exim is fixed
  226. */
  227. cfg->enable_shutdown_workaround = TRUE;
  228. cfg->ssl_ciphers = "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4";
  229. cfg->max_message = DEFAULT_MAX_MESSAGE;
  230. cfg->max_pic_size = DEFAULT_MAX_PIC;
  231. cfg->images_cache_size = 256;
  232. cfg->monitored_ctx = rspamd_monitored_ctx_init ();
  233. cfg->neighbours = ucl_object_typed_new (UCL_OBJECT);
  234. #ifdef WITH_HIREDIS
  235. cfg->redis_pool = rspamd_redis_pool_init ();
  236. #endif
  237. cfg->default_max_shots = DEFAULT_MAX_SHOTS;
  238. cfg->max_sessions_cache = DEFAULT_MAX_SESSIONS;
  239. cfg->maps_cache_dir = rspamd_mempool_strdup (cfg->cfg_pool, RSPAMD_DBDIR);
  240. cfg->c_modules = g_ptr_array_new ();
  241. cfg->heartbeat_interval = 10.0;
  242. REF_INIT_RETAIN (cfg, rspamd_config_free);
  243. return cfg;
  244. }
  245. void
  246. rspamd_config_free (struct rspamd_config *cfg)
  247. {
  248. struct rspamd_config_cfg_lua_script *sc, *sctmp;
  249. struct rspamd_config_settings_elt *set, *stmp;
  250. struct rspamd_worker_log_pipe *lp, *ltmp;
  251. rspamd_lua_run_config_unload (cfg->lua_state, cfg);
  252. /* Scripts part */
  253. DL_FOREACH_SAFE (cfg->on_term_scripts, sc, sctmp) {
  254. luaL_unref (cfg->lua_state, LUA_REGISTRYINDEX, sc->cbref);
  255. }
  256. DL_FOREACH_SAFE (cfg->on_load_scripts, sc, sctmp) {
  257. luaL_unref (cfg->lua_state, LUA_REGISTRYINDEX, sc->cbref);
  258. }
  259. DL_FOREACH_SAFE (cfg->post_init_scripts, sc, sctmp) {
  260. luaL_unref (cfg->lua_state, LUA_REGISTRYINDEX, sc->cbref);
  261. }
  262. DL_FOREACH_SAFE (cfg->config_unload_scripts, sc, sctmp) {
  263. luaL_unref (cfg->lua_state, LUA_REGISTRYINDEX, sc->cbref);
  264. }
  265. DL_FOREACH_SAFE (cfg->setting_ids, set, stmp) {
  266. REF_RELEASE (set);
  267. }
  268. rspamd_map_remove_all (cfg);
  269. rspamd_mempool_destructors_enforce (cfg->cfg_pool);
  270. g_list_free (cfg->classifiers);
  271. g_list_free (cfg->workers);
  272. rspamd_symcache_destroy (cfg->cache);
  273. ucl_object_unref (cfg->rcl_obj);
  274. ucl_object_unref (cfg->config_comments);
  275. ucl_object_unref (cfg->doc_strings);
  276. ucl_object_unref (cfg->neighbours);
  277. g_hash_table_remove_all (cfg->composite_symbols);
  278. g_hash_table_unref (cfg->composite_symbols);
  279. g_hash_table_remove_all (cfg->cfg_params);
  280. g_hash_table_unref (cfg->cfg_params);
  281. g_hash_table_unref (cfg->classifiers_symbols);
  282. g_hash_table_unref (cfg->debug_modules);
  283. g_hash_table_unref (cfg->explicit_modules);
  284. g_hash_table_unref (cfg->wrk_parsers);
  285. g_hash_table_unref (cfg->trusted_keys);
  286. rspamd_re_cache_unref (cfg->re_cache);
  287. rspamd_upstreams_library_unref (cfg->ups_ctx);
  288. g_ptr_array_free (cfg->c_modules, TRUE);
  289. if (cfg->lua_state && cfg->own_lua_state) {
  290. lua_thread_pool_free (cfg->lua_thread_pool);
  291. lua_close (cfg->lua_state);
  292. }
  293. #ifdef WITH_HIREDIS
  294. if (cfg->redis_pool) {
  295. rspamd_redis_pool_destroy (cfg->redis_pool);
  296. }
  297. #endif
  298. if (cfg->monitored_ctx) {
  299. rspamd_monitored_ctx_destroy (cfg->monitored_ctx);
  300. }
  301. HASH_CLEAR (hh, cfg->actions);
  302. rspamd_mempool_destructors_enforce (cfg->cfg_pool);
  303. if (cfg->checksum) {
  304. g_free (cfg->checksum);
  305. }
  306. REF_RELEASE (cfg->libs_ctx);
  307. DL_FOREACH_SAFE (cfg->log_pipes, lp, ltmp) {
  308. close (lp->fd);
  309. g_free (lp);
  310. }
  311. rspamd_mempool_delete (cfg->cfg_pool);
  312. }
  313. const ucl_object_t *
  314. rspamd_config_get_module_opt (struct rspamd_config *cfg,
  315. const gchar *module_name,
  316. const gchar *opt_name)
  317. {
  318. const ucl_object_t *res = NULL, *sec;
  319. sec = ucl_obj_get_key (cfg->rcl_obj, module_name);
  320. if (sec != NULL) {
  321. res = ucl_obj_get_key (sec, opt_name);
  322. }
  323. return res;
  324. }
  325. gchar
  326. rspamd_config_parse_flag (const gchar *str, guint len)
  327. {
  328. gchar c;
  329. if (!str || !*str) {
  330. return -1;
  331. }
  332. if (len == 0) {
  333. len = strlen (str);
  334. }
  335. switch (len) {
  336. case 1:
  337. c = g_ascii_tolower (*str);
  338. if (c == 'y' || c == '1') {
  339. return 1;
  340. }
  341. else if (c == 'n' || c == '0') {
  342. return 0;
  343. }
  344. break;
  345. case 2:
  346. if (g_ascii_strncasecmp (str, "no", len) == 0) {
  347. return 0;
  348. }
  349. else if (g_ascii_strncasecmp (str, "on", len) == 0) {
  350. return 1;
  351. }
  352. break;
  353. case 3:
  354. if (g_ascii_strncasecmp (str, "yes", len) == 0) {
  355. return 1;
  356. }
  357. else if (g_ascii_strncasecmp (str, "off", len) == 0) {
  358. return 0;
  359. }
  360. break;
  361. case 4:
  362. if (g_ascii_strncasecmp (str, "true", len) == 0) {
  363. return 1;
  364. }
  365. break;
  366. case 5:
  367. if (g_ascii_strncasecmp (str, "false", len) == 0) {
  368. return 0;
  369. }
  370. break;
  371. }
  372. return -1;
  373. }
  374. static gboolean
  375. rspamd_config_process_var (struct rspamd_config *cfg, const rspamd_ftok_t *var,
  376. const rspamd_ftok_t *content)
  377. {
  378. guint flags = RSPAMD_LOG_FLAG_DEFAULT;
  379. struct rspamd_log_format *lf;
  380. enum rspamd_log_format_type type;
  381. rspamd_ftok_t tok;
  382. gint id;
  383. g_assert (var != NULL);
  384. if (var->len > 3 && rspamd_lc_cmp (var->begin, "if_", 3) == 0) {
  385. flags |= RSPAMD_LOG_FMT_FLAG_CONDITION;
  386. tok.begin = var->begin + 3;
  387. tok.len = var->len - 3;
  388. }
  389. else {
  390. tok.begin = var->begin;
  391. tok.len = var->len;
  392. }
  393. /* Now compare variable and check what we have */
  394. if (rspamd_ftok_cstr_equal (&tok, "mid", TRUE)) {
  395. type = RSPAMD_LOG_MID;
  396. }
  397. else if (rspamd_ftok_cstr_equal (&tok, "qid", TRUE)) {
  398. type = RSPAMD_LOG_QID;
  399. }
  400. else if (rspamd_ftok_cstr_equal (&tok, "user", TRUE)) {
  401. type = RSPAMD_LOG_USER;
  402. }
  403. else if (rspamd_ftok_cstr_equal (&tok, "is_spam", TRUE)) {
  404. type = RSPAMD_LOG_ISSPAM;
  405. }
  406. else if (rspamd_ftok_cstr_equal (&tok, "action", TRUE)) {
  407. type = RSPAMD_LOG_ACTION;
  408. }
  409. else if (rspamd_ftok_cstr_equal (&tok, "scores", TRUE)) {
  410. type = RSPAMD_LOG_SCORES;
  411. }
  412. else if (rspamd_ftok_cstr_equal (&tok, "symbols", TRUE)) {
  413. type = RSPAMD_LOG_SYMBOLS;
  414. }
  415. else if (rspamd_ftok_cstr_equal (&tok, "symbols_scores", TRUE)) {
  416. type = RSPAMD_LOG_SYMBOLS;
  417. flags |= RSPAMD_LOG_FMT_FLAG_SYMBOLS_SCORES;
  418. }
  419. else if (rspamd_ftok_cstr_equal (&tok, "symbols_params", TRUE)) {
  420. type = RSPAMD_LOG_SYMBOLS;
  421. flags |= RSPAMD_LOG_FMT_FLAG_SYMBOLS_PARAMS;
  422. }
  423. else if (rspamd_ftok_cstr_equal (&tok, "symbols_scores_params", TRUE)) {
  424. type = RSPAMD_LOG_SYMBOLS;
  425. flags |= RSPAMD_LOG_FMT_FLAG_SYMBOLS_PARAMS|RSPAMD_LOG_FMT_FLAG_SYMBOLS_SCORES;
  426. }
  427. else if (rspamd_ftok_cstr_equal (&tok, "groups", TRUE)) {
  428. type = RSPAMD_LOG_GROUPS;
  429. }
  430. else if (rspamd_ftok_cstr_equal (&tok, "public_groups", TRUE)) {
  431. type = RSPAMD_LOG_PUBLIC_GROUPS;
  432. }
  433. else if (rspamd_ftok_cstr_equal (&tok, "ip", TRUE)) {
  434. type = RSPAMD_LOG_IP;
  435. }
  436. else if (rspamd_ftok_cstr_equal (&tok, "len", TRUE)) {
  437. type = RSPAMD_LOG_LEN;
  438. }
  439. else if (rspamd_ftok_cstr_equal (&tok, "dns_req", TRUE)) {
  440. type = RSPAMD_LOG_DNS_REQ;
  441. }
  442. else if (rspamd_ftok_cstr_equal (&tok, "smtp_from", TRUE)) {
  443. type = RSPAMD_LOG_SMTP_FROM;
  444. }
  445. else if (rspamd_ftok_cstr_equal (&tok, "mime_from", TRUE)) {
  446. type = RSPAMD_LOG_MIME_FROM;
  447. }
  448. else if (rspamd_ftok_cstr_equal (&tok, "smtp_rcpt", TRUE)) {
  449. type = RSPAMD_LOG_SMTP_RCPT;
  450. }
  451. else if (rspamd_ftok_cstr_equal (&tok, "mime_rcpt", TRUE)) {
  452. type = RSPAMD_LOG_MIME_RCPT;
  453. }
  454. else if (rspamd_ftok_cstr_equal (&tok, "smtp_rcpts", TRUE)) {
  455. type = RSPAMD_LOG_SMTP_RCPTS;
  456. }
  457. else if (rspamd_ftok_cstr_equal (&tok, "mime_rcpts", TRUE)) {
  458. type = RSPAMD_LOG_MIME_RCPTS;
  459. }
  460. else if (rspamd_ftok_cstr_equal (&tok, "time_real", TRUE)) {
  461. type = RSPAMD_LOG_TIME_REAL;
  462. }
  463. else if (rspamd_ftok_cstr_equal (&tok, "time_virtual", TRUE)) {
  464. type = RSPAMD_LOG_TIME_VIRTUAL;
  465. }
  466. else if (rspamd_ftok_cstr_equal (&tok, "lua", TRUE)) {
  467. type = RSPAMD_LOG_LUA;
  468. }
  469. else if (rspamd_ftok_cstr_equal (&tok, "digest", TRUE) ||
  470. rspamd_ftok_cstr_equal (&tok, "checksum", TRUE)) {
  471. type = RSPAMD_LOG_DIGEST;
  472. }
  473. else if (rspamd_ftok_cstr_equal (&tok, "filename", TRUE)) {
  474. type = RSPAMD_LOG_FILENAME;
  475. }
  476. else if (rspamd_ftok_cstr_equal (&tok, "forced_action", TRUE)) {
  477. type = RSPAMD_LOG_FORCED_ACTION;
  478. }
  479. else if (rspamd_ftok_cstr_equal (&tok, "settings_id", TRUE)) {
  480. type = RSPAMD_LOG_SETTINGS_ID;
  481. }
  482. else if (rspamd_ftok_cstr_equal (&tok, "mempool_size", TRUE)) {
  483. type = RSPAMD_LOG_MEMPOOL_SIZE;
  484. }
  485. else if (rspamd_ftok_cstr_equal (&tok, "mempool_waste", TRUE)) {
  486. type = RSPAMD_LOG_MEMPOOL_WASTE;
  487. }
  488. else {
  489. msg_err_config ("unknown log variable: %T", &tok);
  490. return FALSE;
  491. }
  492. lf = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*lf));
  493. lf->type = type;
  494. lf->flags = flags;
  495. if (type != RSPAMD_LOG_LUA) {
  496. if (content && content->len > 0) {
  497. lf->data = rspamd_mempool_alloc0 (cfg->cfg_pool,
  498. sizeof (rspamd_ftok_t));
  499. memcpy (lf->data, content, sizeof (*content));
  500. lf->len = sizeof (*content);
  501. }
  502. }
  503. else {
  504. /* Load lua code and ensure that we have function ref returned */
  505. if (!content || content->len == 0) {
  506. msg_err_config ("lua variable needs content: %T", &tok);
  507. return FALSE;
  508. }
  509. if (luaL_loadbuffer (cfg->lua_state, content->begin, content->len,
  510. "lua log variable") != 0) {
  511. msg_err_config ("error loading lua code: '%T': %s", content,
  512. lua_tostring (cfg->lua_state, -1));
  513. return FALSE;
  514. }
  515. if (lua_pcall (cfg->lua_state, 0, 1, 0) != 0) {
  516. msg_err_config ("error executing lua code: '%T': %s", content,
  517. lua_tostring (cfg->lua_state, -1));
  518. lua_pop (cfg->lua_state, 1);
  519. return FALSE;
  520. }
  521. if (lua_type (cfg->lua_state, -1) != LUA_TFUNCTION) {
  522. msg_err_config ("lua variable should return function: %T", content);
  523. lua_pop (cfg->lua_state, 1);
  524. return FALSE;
  525. }
  526. id = luaL_ref (cfg->lua_state, LUA_REGISTRYINDEX);
  527. lf->data = GINT_TO_POINTER (id);
  528. lf->len = 0;
  529. }
  530. DL_APPEND (cfg->log_format, lf);
  531. return TRUE;
  532. }
  533. static gboolean
  534. rspamd_config_parse_log_format (struct rspamd_config *cfg)
  535. {
  536. const gchar *p, *c, *end, *s;
  537. gchar *d;
  538. struct rspamd_log_format *lf = NULL;
  539. rspamd_ftok_t var, var_content;
  540. enum {
  541. parse_str,
  542. parse_dollar,
  543. parse_var_name,
  544. parse_var_content,
  545. } state = parse_str;
  546. gint braces = 0;
  547. g_assert (cfg != NULL);
  548. c = cfg->log_format_str;
  549. if (c == NULL) {
  550. return FALSE;
  551. }
  552. p = c;
  553. end = p + strlen (p);
  554. while (p < end) {
  555. switch (state) {
  556. case parse_str:
  557. if (*p == '$') {
  558. state = parse_dollar;
  559. }
  560. else {
  561. p ++;
  562. }
  563. break;
  564. case parse_dollar:
  565. if (p > c) {
  566. /* We have string element that we need to store */
  567. lf = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*lf));
  568. lf->type = RSPAMD_LOG_STRING;
  569. lf->data = rspamd_mempool_alloc (cfg->cfg_pool, p - c + 1);
  570. /* Filter \r\n from the destination */
  571. s = c;
  572. d = lf->data;
  573. while (s < p) {
  574. if (*s != '\r' && *s != '\n') {
  575. *d++ = *s++;
  576. }
  577. else {
  578. *d ++ = ' ';
  579. s++;
  580. }
  581. }
  582. *d = '\0';
  583. lf->len = d - (char *) lf->data;
  584. DL_APPEND (cfg->log_format, lf);
  585. lf = NULL;
  586. }
  587. p++;
  588. c = p;
  589. state = parse_var_name;
  590. break;
  591. case parse_var_name:
  592. if (*p == '{') {
  593. var.begin = c;
  594. var.len = p - c;
  595. p ++;
  596. c = p;
  597. state = parse_var_content;
  598. braces = 1;
  599. }
  600. else if (*p != '_' && *p != '-' && !g_ascii_isalnum (*p)) {
  601. /* Variable with no content */
  602. var.begin = c;
  603. var.len = p - c;
  604. c = p;
  605. if (!rspamd_config_process_var (cfg, &var, NULL)) {
  606. return FALSE;
  607. }
  608. state = parse_str;
  609. }
  610. else {
  611. p++;
  612. }
  613. break;
  614. case parse_var_content:
  615. if (*p == '}' && --braces == 0) {
  616. var_content.begin = c;
  617. var_content.len = p - c;
  618. p ++;
  619. c = p;
  620. if (!rspamd_config_process_var (cfg, &var, &var_content)) {
  621. return FALSE;
  622. }
  623. state = parse_str;
  624. }
  625. else if (*p == '{') {
  626. braces ++;
  627. p ++;
  628. }
  629. else {
  630. p++;
  631. }
  632. break;
  633. }
  634. }
  635. /* Last state */
  636. switch (state) {
  637. case parse_str:
  638. if (p > c) {
  639. /* We have string element that we need to store */
  640. lf = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*lf));
  641. lf->type = RSPAMD_LOG_STRING;
  642. lf->data = rspamd_mempool_alloc (cfg->cfg_pool, p - c + 1);
  643. /* Filter \r\n from the destination */
  644. s = c;
  645. d = lf->data;
  646. while (s < p) {
  647. if (*s != '\r' && *s != '\n') {
  648. *d++ = *s++;
  649. }
  650. else {
  651. *d++ = ' ';
  652. s++;
  653. }
  654. }
  655. *d = '\0';
  656. lf->len = d - (char *)lf->data;
  657. DL_APPEND (cfg->log_format, lf);
  658. lf = NULL;
  659. }
  660. break;
  661. case parse_var_name:
  662. var.begin = c;
  663. var.len = p - c;
  664. if (!rspamd_config_process_var (cfg, &var, NULL)) {
  665. return FALSE;
  666. }
  667. break;
  668. case parse_dollar:
  669. case parse_var_content:
  670. msg_err_config ("cannot parse log format %s: incomplete string",
  671. cfg->log_format_str);
  672. return FALSE;
  673. break;
  674. }
  675. return TRUE;
  676. }
  677. static void
  678. rspamd_urls_config_dtor (gpointer _unused)
  679. {
  680. rspamd_url_deinit ();
  681. }
  682. /*
  683. * Perform post load actions
  684. */
  685. gboolean
  686. rspamd_config_post_load (struct rspamd_config *cfg,
  687. enum rspamd_post_load_options opts)
  688. {
  689. #ifdef HAVE_CLOCK_GETTIME
  690. struct timespec ts;
  691. #endif
  692. gboolean ret = TRUE;
  693. #ifdef HAVE_CLOCK_GETTIME
  694. #ifdef HAVE_CLOCK_PROCESS_CPUTIME_ID
  695. clock_getres (CLOCK_PROCESS_CPUTIME_ID, &ts);
  696. # elif defined(HAVE_CLOCK_VIRTUAL)
  697. clock_getres (CLOCK_VIRTUAL, &ts);
  698. # else
  699. clock_getres (CLOCK_REALTIME, &ts);
  700. # endif
  701. rspamd_logger_configure_modules (cfg->debug_modules);
  702. cfg->clock_res = log10 (1000000. / ts.tv_nsec);
  703. if (cfg->clock_res < 0) {
  704. cfg->clock_res = 0;
  705. }
  706. if (cfg->clock_res > 3) {
  707. cfg->clock_res = 3;
  708. }
  709. #else
  710. /* For gettimeofday */
  711. cfg->clock_res = 1;
  712. #endif
  713. if (cfg->one_shot_mode) {
  714. msg_info_config ("enabling one shot mode (was %d max shots)",
  715. cfg->default_max_shots);
  716. cfg->default_max_shots = 1;
  717. }
  718. rspamd_regexp_library_init (cfg);
  719. rspamd_multipattern_library_init (cfg->hs_cache_dir);
  720. #ifdef WITH_HYPERSCAN
  721. if (!cfg->disable_hyperscan) {
  722. if (!(cfg->libs_ctx->crypto_ctx->cpu_config & CPUID_SSSE3)) {
  723. msg_warn_config ("CPU doesn't have SSSE3 instructions set "
  724. "required for hyperscan, disable it");
  725. cfg->disable_hyperscan = TRUE;
  726. }
  727. }
  728. #endif
  729. if (opts & RSPAMD_CONFIG_INIT_URL) {
  730. if (cfg->tld_file == NULL) {
  731. /* Try to guess tld file */
  732. GString *fpath = g_string_new (NULL);
  733. rspamd_printf_gstring (fpath, "%s%c%s", RSPAMD_SHAREDIR,
  734. G_DIR_SEPARATOR, "effective_tld_names.dat");
  735. if (access (fpath->str, R_OK) != -1) {
  736. msg_debug_config ("url_tld option is not specified but %s is available,"
  737. " therefore this file is assumed as TLD file for URL"
  738. " extraction", fpath->str);
  739. cfg->tld_file = rspamd_mempool_strdup (cfg->cfg_pool, fpath->str);
  740. }
  741. else {
  742. if (opts & RSPAMD_CONFIG_INIT_VALIDATE) {
  743. msg_err_config ("no url_tld option has been specified");
  744. ret = FALSE;
  745. }
  746. }
  747. g_string_free (fpath, TRUE);
  748. }
  749. else {
  750. if (access (cfg->tld_file, R_OK) == -1) {
  751. if (opts & RSPAMD_CONFIG_INIT_VALIDATE) {
  752. ret = FALSE;
  753. msg_err_config ("cannot access tld file %s: %s", cfg->tld_file,
  754. strerror (errno));
  755. }
  756. else {
  757. msg_debug_config ("cannot access tld file %s: %s", cfg->tld_file,
  758. strerror (errno));
  759. cfg->tld_file = NULL;
  760. }
  761. }
  762. }
  763. if (opts & RSPAMD_CONFIG_INIT_NO_TLD) {
  764. rspamd_url_init (NULL);
  765. }
  766. else {
  767. rspamd_url_init (cfg->tld_file);
  768. }
  769. rspamd_mempool_add_destructor (cfg->cfg_pool, rspamd_urls_config_dtor,
  770. NULL);
  771. }
  772. init_dynamic_config (cfg);
  773. /* Insert classifiers symbols */
  774. rspamd_config_insert_classify_symbols (cfg);
  775. /* Parse format string that we have */
  776. if (!rspamd_config_parse_log_format (cfg)) {
  777. msg_err_config ("cannot parse log format, task logging will not be available");
  778. }
  779. if (opts & RSPAMD_CONFIG_INIT_SYMCACHE) {
  780. /* Init config cache */
  781. rspamd_symcache_init (cfg->cache);
  782. /* Init re cache */
  783. rspamd_re_cache_init (cfg->re_cache, cfg);
  784. /* Try load Hypersan */
  785. rspamd_re_cache_load_hyperscan (cfg->re_cache,
  786. cfg->hs_cache_dir ? cfg->hs_cache_dir : RSPAMD_DBDIR "/",
  787. true);
  788. }
  789. if (opts & RSPAMD_CONFIG_INIT_LIBS) {
  790. /* Config other libraries */
  791. rspamd_config_libs (cfg->libs_ctx, cfg);
  792. }
  793. /* Validate cache */
  794. if (opts & RSPAMD_CONFIG_INIT_VALIDATE) {
  795. /* Check for actions sanity */
  796. gboolean seen_controller = FALSE;
  797. GList *cur;
  798. struct rspamd_worker_conf *wcf;
  799. cur = cfg->workers;
  800. while (cur) {
  801. wcf = cur->data;
  802. if (wcf->type == g_quark_from_static_string ("controller")) {
  803. seen_controller = TRUE;
  804. break;
  805. }
  806. cur = g_list_next (cur);
  807. }
  808. if (!seen_controller) {
  809. msg_warn_config ("controller worker is unconfigured: learning,"
  810. " periodic scripts, maps watching and many other"
  811. " Rspamd features will be broken");
  812. ret = FALSE;
  813. }
  814. ret = rspamd_symcache_validate (cfg->cache, cfg, FALSE) && ret;
  815. }
  816. if (opts & RSPAMD_CONFIG_INIT_PRELOAD_MAPS) {
  817. rspamd_map_preload (cfg);
  818. }
  819. if (opts & RSPAMD_CONFIG_INIT_POST_LOAD_LUA) {
  820. rspamd_lua_run_config_post_init (cfg->lua_state, cfg);
  821. }
  822. return ret;
  823. }
  824. #if 0
  825. void
  826. parse_err (const gchar *fmt, ...)
  827. {
  828. va_list aq;
  829. gchar logbuf[BUFSIZ], readbuf[32];
  830. gint r;
  831. va_start (aq, fmt);
  832. rspamd_strlcpy (readbuf, yytext, sizeof (readbuf));
  833. r = snprintf (logbuf,
  834. sizeof (logbuf),
  835. "config file parse error! line: %d, text: %s, reason: ",
  836. yylineno,
  837. readbuf);
  838. r += vsnprintf (logbuf + r, sizeof (logbuf) - r, fmt, aq);
  839. va_end (aq);
  840. g_critical ("%s", logbuf);
  841. }
  842. void
  843. parse_warn (const gchar *fmt, ...)
  844. {
  845. va_list aq;
  846. gchar logbuf[BUFSIZ], readbuf[32];
  847. gint r;
  848. va_start (aq, fmt);
  849. rspamd_strlcpy (readbuf, yytext, sizeof (readbuf));
  850. r = snprintf (logbuf,
  851. sizeof (logbuf),
  852. "config file parse warning! line: %d, text: %s, reason: ",
  853. yylineno,
  854. readbuf);
  855. r += vsnprintf (logbuf + r, sizeof (logbuf) - r, fmt, aq);
  856. va_end (aq);
  857. g_warning ("%s", logbuf);
  858. }
  859. #endif
  860. void
  861. rspamd_config_unescape_quotes (gchar *line)
  862. {
  863. gchar *c = line, *t;
  864. while (*c) {
  865. if (*c == '\\' && *(c + 1) == '"') {
  866. t = c;
  867. while (*t) {
  868. *t = *(t + 1);
  869. t++;
  870. }
  871. }
  872. c++;
  873. }
  874. }
  875. GList *
  876. rspamd_config_parse_comma_list (rspamd_mempool_t * pool, const gchar *line)
  877. {
  878. GList *res = NULL;
  879. const gchar *c, *p;
  880. gchar *str;
  881. c = line;
  882. p = c;
  883. while (*p) {
  884. if (*p == ',' && *c != *p) {
  885. str = rspamd_mempool_alloc (pool, p - c + 1);
  886. rspamd_strlcpy (str, c, p - c + 1);
  887. res = g_list_prepend (res, str);
  888. /* Skip spaces */
  889. while (g_ascii_isspace (*(++p))) ;
  890. c = p;
  891. continue;
  892. }
  893. p++;
  894. }
  895. if (res != NULL) {
  896. rspamd_mempool_add_destructor (pool,
  897. (rspamd_mempool_destruct_t) g_list_free,
  898. res);
  899. }
  900. return res;
  901. }
  902. struct rspamd_classifier_config *
  903. rspamd_config_new_classifier (struct rspamd_config *cfg,
  904. struct rspamd_classifier_config *c)
  905. {
  906. if (c == NULL) {
  907. c =
  908. rspamd_mempool_alloc0 (cfg->cfg_pool,
  909. sizeof (struct rspamd_classifier_config));
  910. c->min_prob_strength = 0.05;
  911. c->min_token_hits = 2;
  912. }
  913. if (c->labels == NULL) {
  914. c->labels = g_hash_table_new_full (rspamd_str_hash,
  915. rspamd_str_equal,
  916. NULL,
  917. (GDestroyNotify)g_list_free);
  918. rspamd_mempool_add_destructor (cfg->cfg_pool,
  919. (rspamd_mempool_destruct_t) g_hash_table_destroy,
  920. c->labels);
  921. }
  922. return c;
  923. }
  924. struct rspamd_statfile_config *
  925. rspamd_config_new_statfile (struct rspamd_config *cfg,
  926. struct rspamd_statfile_config *c)
  927. {
  928. if (c == NULL) {
  929. c =
  930. rspamd_mempool_alloc0 (cfg->cfg_pool,
  931. sizeof (struct rspamd_statfile_config));
  932. }
  933. return c;
  934. }
  935. void
  936. rspamd_config_init_metric (struct rspamd_config *cfg)
  937. {
  938. cfg->grow_factor = 1.0;
  939. cfg->symbols = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  940. cfg->groups = g_hash_table_new (rspamd_strcase_hash, rspamd_strcase_equal);
  941. cfg->subject = SPAM_SUBJECT;
  942. rspamd_mempool_add_destructor (cfg->cfg_pool,
  943. (rspamd_mempool_destruct_t) g_hash_table_unref,
  944. cfg->symbols);
  945. rspamd_mempool_add_destructor (cfg->cfg_pool,
  946. (rspamd_mempool_destruct_t) g_hash_table_unref,
  947. cfg->groups);
  948. }
  949. struct rspamd_symbols_group *
  950. rspamd_config_new_group (struct rspamd_config *cfg, const gchar *name)
  951. {
  952. struct rspamd_symbols_group *gr;
  953. gr = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*gr));
  954. gr->symbols = g_hash_table_new (rspamd_strcase_hash,
  955. rspamd_strcase_equal);
  956. rspamd_mempool_add_destructor (cfg->cfg_pool,
  957. (rspamd_mempool_destruct_t)g_hash_table_unref, gr->symbols);
  958. gr->name = rspamd_mempool_strdup (cfg->cfg_pool, name);
  959. if (strcmp (gr->name, "ungrouped") == 0) {
  960. gr->flags |= RSPAMD_SYMBOL_GROUP_UNGROUPED;
  961. }
  962. g_hash_table_insert (cfg->groups, gr->name, gr);
  963. return gr;
  964. }
  965. static void
  966. rspamd_worker_conf_dtor (struct rspamd_worker_conf *wcf)
  967. {
  968. if (wcf) {
  969. struct rspamd_worker_bind_conf *cnf, *tmp;
  970. LL_FOREACH_SAFE (wcf->bind_conf, cnf, tmp) {
  971. g_free (cnf->name);
  972. g_free (cnf->bind_line);
  973. g_ptr_array_free (cnf->addrs, TRUE);
  974. g_free (cnf);
  975. }
  976. ucl_object_unref (wcf->options);
  977. g_queue_free (wcf->active_workers);
  978. g_hash_table_unref (wcf->params);
  979. g_free (wcf);
  980. }
  981. }
  982. static void
  983. rspamd_worker_conf_cfg_fin (gpointer d)
  984. {
  985. struct rspamd_worker_conf *wcf = d;
  986. REF_RELEASE (wcf);
  987. }
  988. struct rspamd_worker_conf *
  989. rspamd_config_new_worker (struct rspamd_config *cfg,
  990. struct rspamd_worker_conf *c)
  991. {
  992. if (c == NULL) {
  993. c = g_malloc0 (sizeof (struct rspamd_worker_conf));
  994. c->params = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  995. c->active_workers = g_queue_new ();
  996. #ifdef HAVE_SC_NPROCESSORS_ONLN
  997. c->count = MIN (DEFAULT_MAX_WORKERS,
  998. MAX (1, sysconf (_SC_NPROCESSORS_ONLN) - 2));
  999. #else
  1000. c->count = DEFAULT_MAX_WORKERS;
  1001. #endif
  1002. c->rlimit_nofile = 0;
  1003. c->rlimit_maxcore = 0;
  1004. c->enabled = TRUE;
  1005. REF_INIT_RETAIN (c, rspamd_worker_conf_dtor);
  1006. rspamd_mempool_add_destructor (cfg->cfg_pool,
  1007. rspamd_worker_conf_cfg_fin, c);
  1008. }
  1009. return c;
  1010. }
  1011. static bool
  1012. rspamd_include_map_handler (const guchar *data, gsize len,
  1013. const ucl_object_t *args, void * ud)
  1014. {
  1015. struct rspamd_config *cfg = (struct rspamd_config *)ud;
  1016. struct rspamd_ucl_map_cbdata *cbdata, **pcbdata;
  1017. gchar *map_line;
  1018. map_line = rspamd_mempool_alloc (cfg->cfg_pool, len + 1);
  1019. rspamd_strlcpy (map_line, data, len + 1);
  1020. cbdata = g_malloc (sizeof (struct rspamd_ucl_map_cbdata));
  1021. pcbdata = g_malloc (sizeof (struct rspamd_ucl_map_cbdata *));
  1022. cbdata->buf = NULL;
  1023. cbdata->cfg = cfg;
  1024. *pcbdata = cbdata;
  1025. return rspamd_map_add (cfg,
  1026. map_line,
  1027. "ucl include",
  1028. rspamd_ucl_read_cb,
  1029. rspamd_ucl_fin_cb,
  1030. rspamd_ucl_dtor_cb,
  1031. (void **)pcbdata,
  1032. NULL, RSPAMD_MAP_DEFAULT) != NULL;
  1033. }
  1034. /*
  1035. * Variables:
  1036. * $CONFDIR - configuration directory
  1037. * $LOCAL_CONFDIR - local configuration directory
  1038. * $RUNDIR - local states directory
  1039. * $DBDIR - databases dir
  1040. * $LOGDIR - logs dir
  1041. * $PLUGINSDIR - pluggins dir
  1042. * $PREFIX - installation prefix
  1043. * $VERSION - rspamd version
  1044. */
  1045. #define RSPAMD_CONFDIR_MACRO "CONFDIR"
  1046. #define RSPAMD_LOCAL_CONFDIR_MACRO "LOCAL_CONFDIR"
  1047. #define RSPAMD_RUNDIR_MACRO "RUNDIR"
  1048. #define RSPAMD_DBDIR_MACRO "DBDIR"
  1049. #define RSPAMD_LOGDIR_MACRO "LOGDIR"
  1050. #define RSPAMD_PLUGINSDIR_MACRO "PLUGINSDIR"
  1051. #define RSPAMD_SHAREDIR_MACRO "SHAREDIR"
  1052. #define RSPAMD_RULESDIR_MACRO "RULESDIR"
  1053. #define RSPAMD_WWWDIR_MACRO "WWWDIR"
  1054. #define RSPAMD_PREFIX_MACRO "PREFIX"
  1055. #define RSPAMD_VERSION_MACRO "VERSION"
  1056. #define RSPAMD_VERSION_MAJOR_MACRO "VERSION_MAJOR"
  1057. #define RSPAMD_VERSION_MINOR_MACRO "VERSION_MINOR"
  1058. #define RSPAMD_BRANCH_VERSION_MACRO "BRANCH_VERSION"
  1059. #define RSPAMD_HOSTNAME_MACRO "HOSTNAME"
  1060. void
  1061. rspamd_ucl_add_conf_variables (struct ucl_parser *parser, GHashTable *vars)
  1062. {
  1063. GHashTableIter it;
  1064. gpointer k, v;
  1065. gchar *hostbuf;
  1066. gsize hostlen;
  1067. ucl_parser_register_variable (parser,
  1068. RSPAMD_CONFDIR_MACRO,
  1069. RSPAMD_CONFDIR);
  1070. ucl_parser_register_variable (parser,
  1071. RSPAMD_LOCAL_CONFDIR_MACRO,
  1072. RSPAMD_LOCAL_CONFDIR);
  1073. ucl_parser_register_variable (parser, RSPAMD_RUNDIR_MACRO,
  1074. RSPAMD_RUNDIR);
  1075. ucl_parser_register_variable (parser, RSPAMD_DBDIR_MACRO,
  1076. RSPAMD_DBDIR);
  1077. ucl_parser_register_variable (parser, RSPAMD_LOGDIR_MACRO,
  1078. RSPAMD_LOGDIR);
  1079. ucl_parser_register_variable (parser,
  1080. RSPAMD_PLUGINSDIR_MACRO,
  1081. RSPAMD_PLUGINSDIR);
  1082. ucl_parser_register_variable (parser,
  1083. RSPAMD_SHAREDIR_MACRO,
  1084. RSPAMD_SHAREDIR);
  1085. ucl_parser_register_variable (parser,
  1086. RSPAMD_RULESDIR_MACRO,
  1087. RSPAMD_RULESDIR);
  1088. ucl_parser_register_variable (parser, RSPAMD_WWWDIR_MACRO,
  1089. RSPAMD_WWWDIR);
  1090. ucl_parser_register_variable (parser, RSPAMD_PREFIX_MACRO,
  1091. RSPAMD_PREFIX);
  1092. ucl_parser_register_variable (parser, RSPAMD_VERSION_MACRO, RVERSION);
  1093. ucl_parser_register_variable (parser, RSPAMD_VERSION_MAJOR_MACRO,
  1094. RSPAMD_VERSION_MAJOR);
  1095. ucl_parser_register_variable (parser, RSPAMD_VERSION_MINOR_MACRO,
  1096. RSPAMD_VERSION_MINOR);
  1097. ucl_parser_register_variable (parser, RSPAMD_BRANCH_VERSION_MACRO,
  1098. RSPAMD_VERSION_BRANCH);
  1099. hostlen = sysconf (_SC_HOST_NAME_MAX);
  1100. if (hostlen <= 0) {
  1101. hostlen = 256;
  1102. }
  1103. else {
  1104. hostlen ++;
  1105. }
  1106. hostbuf = g_alloca (hostlen);
  1107. memset (hostbuf, 0, hostlen);
  1108. gethostname (hostbuf, hostlen - 1);
  1109. /* UCL copies variables, so it is safe to pass an ephemeral buffer here */
  1110. ucl_parser_register_variable (parser, RSPAMD_HOSTNAME_MACRO,
  1111. hostbuf);
  1112. if (vars != NULL) {
  1113. g_hash_table_iter_init (&it, vars);
  1114. while (g_hash_table_iter_next (&it, &k, &v)) {
  1115. ucl_parser_register_variable (parser, k, v);
  1116. }
  1117. }
  1118. }
  1119. void
  1120. rspamd_ucl_add_conf_macros (struct ucl_parser *parser,
  1121. struct rspamd_config *cfg)
  1122. {
  1123. ucl_parser_register_macro (parser,
  1124. "include_map",
  1125. rspamd_include_map_handler,
  1126. cfg);
  1127. }
  1128. static void
  1129. symbols_classifiers_callback (gpointer key, gpointer value, gpointer ud)
  1130. {
  1131. struct rspamd_config *cfg = ud;
  1132. /* Actually, statistics should act like any ordinary symbol */
  1133. rspamd_symcache_add_symbol (cfg->cache, key, 0, NULL, NULL,
  1134. SYMBOL_TYPE_CLASSIFIER | SYMBOL_TYPE_NOSTAT, -1);
  1135. }
  1136. void
  1137. rspamd_config_insert_classify_symbols (struct rspamd_config *cfg)
  1138. {
  1139. g_hash_table_foreach (cfg->classifiers_symbols,
  1140. symbols_classifiers_callback,
  1141. cfg);
  1142. }
  1143. struct rspamd_classifier_config *
  1144. rspamd_config_find_classifier (struct rspamd_config *cfg, const gchar *name)
  1145. {
  1146. GList *cur;
  1147. struct rspamd_classifier_config *cf;
  1148. if (name == NULL) {
  1149. return NULL;
  1150. }
  1151. cur = cfg->classifiers;
  1152. while (cur) {
  1153. cf = cur->data;
  1154. if (g_ascii_strcasecmp (cf->name, name) == 0) {
  1155. return cf;
  1156. }
  1157. cur = g_list_next (cur);
  1158. }
  1159. return NULL;
  1160. }
  1161. gboolean
  1162. rspamd_config_check_statfiles (struct rspamd_classifier_config *cf)
  1163. {
  1164. struct rspamd_statfile_config *st;
  1165. gboolean has_other = FALSE, res = FALSE, cur_class = FALSE;
  1166. GList *cur;
  1167. /* First check classes directly */
  1168. cur = cf->statfiles;
  1169. while (cur) {
  1170. st = cur->data;
  1171. if (!has_other) {
  1172. cur_class = st->is_spam;
  1173. has_other = TRUE;
  1174. }
  1175. else {
  1176. if (cur_class != st->is_spam) {
  1177. return TRUE;
  1178. }
  1179. }
  1180. cur = g_list_next (cur);
  1181. }
  1182. if (!has_other) {
  1183. /* We have only one statfile */
  1184. return FALSE;
  1185. }
  1186. /* We have not detected any statfile that has different class, so turn on euristic based on symbol's name */
  1187. has_other = FALSE;
  1188. cur = cf->statfiles;
  1189. while (cur) {
  1190. st = cur->data;
  1191. if (rspamd_substring_search_caseless (st->symbol,
  1192. strlen (st->symbol),"spam", 4) != -1) {
  1193. st->is_spam = TRUE;
  1194. }
  1195. else if (rspamd_substring_search_caseless (st->symbol,
  1196. strlen (st->symbol),"ham", 3) != -1) {
  1197. st->is_spam = FALSE;
  1198. }
  1199. if (!has_other) {
  1200. cur_class = st->is_spam;
  1201. has_other = TRUE;
  1202. }
  1203. else {
  1204. if (cur_class != st->is_spam) {
  1205. res = TRUE;
  1206. }
  1207. }
  1208. cur = g_list_next (cur);
  1209. }
  1210. return res;
  1211. }
  1212. static gchar *
  1213. rspamd_ucl_read_cb (gchar * chunk,
  1214. gint len,
  1215. struct map_cb_data *data,
  1216. gboolean final)
  1217. {
  1218. struct rspamd_ucl_map_cbdata *cbdata = data->cur_data, *prev;
  1219. if (cbdata == NULL) {
  1220. cbdata = g_malloc (sizeof (struct rspamd_ucl_map_cbdata));
  1221. prev = data->prev_data;
  1222. cbdata->buf = g_string_sized_new (BUFSIZ);
  1223. cbdata->cfg = prev->cfg;
  1224. data->cur_data = cbdata;
  1225. }
  1226. g_string_append_len (cbdata->buf, chunk, len);
  1227. /* Say not to copy any part of this buffer */
  1228. return NULL;
  1229. }
  1230. static void
  1231. rspamd_ucl_fin_cb (struct map_cb_data *data, void **target)
  1232. {
  1233. struct rspamd_ucl_map_cbdata *cbdata = data->cur_data, *prev =
  1234. data->prev_data;
  1235. ucl_object_t *obj;
  1236. struct ucl_parser *parser;
  1237. ucl_object_iter_t it = NULL;
  1238. const ucl_object_t *cur;
  1239. struct rspamd_config *cfg = data->map->cfg;
  1240. if (cbdata == NULL) {
  1241. msg_err_config ("map fin error: new data is NULL");
  1242. return;
  1243. }
  1244. /* New data available */
  1245. parser = ucl_parser_new (0);
  1246. if (!ucl_parser_add_chunk (parser, cbdata->buf->str,
  1247. cbdata->buf->len)) {
  1248. msg_err_config ("cannot parse map %s: %s",
  1249. data->map->name,
  1250. ucl_parser_get_error (parser));
  1251. ucl_parser_free (parser);
  1252. }
  1253. else {
  1254. obj = ucl_parser_get_object (parser);
  1255. ucl_parser_free (parser);
  1256. it = NULL;
  1257. while ((cur = ucl_object_iterate (obj, &it, true))) {
  1258. ucl_object_replace_key (cbdata->cfg->rcl_obj, (ucl_object_t *)cur,
  1259. cur->key, cur->keylen, false);
  1260. }
  1261. ucl_object_unref (obj);
  1262. }
  1263. if (target) {
  1264. *target = data->cur_data;
  1265. }
  1266. if (prev != NULL) {
  1267. if (prev->buf != NULL) {
  1268. g_string_free (prev->buf, TRUE);
  1269. }
  1270. g_free (prev);
  1271. }
  1272. }
  1273. static void
  1274. rspamd_ucl_dtor_cb (struct map_cb_data *data)
  1275. {
  1276. struct rspamd_ucl_map_cbdata *cbdata = data->cur_data;
  1277. if (cbdata != NULL) {
  1278. if (cbdata->buf != NULL) {
  1279. g_string_free (cbdata->buf, TRUE);
  1280. }
  1281. g_free (cbdata);
  1282. }
  1283. }
  1284. gboolean
  1285. rspamd_check_module (struct rspamd_config *cfg, module_t *mod)
  1286. {
  1287. gboolean ret = TRUE;
  1288. if (mod != NULL) {
  1289. if (mod->module_version != RSPAMD_CUR_MODULE_VERSION) {
  1290. msg_err_config ("module %s has incorrect version %xd (%xd expected)",
  1291. mod->name, (gint)mod->module_version, RSPAMD_CUR_MODULE_VERSION);
  1292. ret = FALSE;
  1293. }
  1294. if (ret && mod->rspamd_version != RSPAMD_VERSION_NUM) {
  1295. msg_err_config ("module %s has incorrect rspamd version %xL (%xL expected)",
  1296. mod->name, mod->rspamd_version, RSPAMD_VERSION_NUM);
  1297. ret = FALSE;
  1298. }
  1299. if (ret && strcmp (mod->rspamd_features, RSPAMD_FEATURES) != 0) {
  1300. msg_err_config ("module %s has incorrect rspamd features '%s' ('%s' expected)",
  1301. mod->name, mod->rspamd_features, RSPAMD_FEATURES);
  1302. ret = FALSE;
  1303. }
  1304. }
  1305. else {
  1306. ret = FALSE;
  1307. }
  1308. return ret;
  1309. }
  1310. gboolean
  1311. rspamd_check_worker (struct rspamd_config *cfg, worker_t *wrk)
  1312. {
  1313. gboolean ret = TRUE;
  1314. if (wrk != NULL) {
  1315. if (wrk->worker_version != RSPAMD_CUR_WORKER_VERSION) {
  1316. msg_err_config ("worker %s has incorrect version %xd (%xd expected)",
  1317. wrk->name, wrk->worker_version, RSPAMD_CUR_WORKER_VERSION);
  1318. ret = FALSE;
  1319. }
  1320. if (ret && wrk->rspamd_version != RSPAMD_VERSION_NUM) {
  1321. msg_err_config ("worker %s has incorrect rspamd version %xL (%xL expected)",
  1322. wrk->name, wrk->rspamd_version, RSPAMD_VERSION_NUM);
  1323. ret = FALSE;
  1324. }
  1325. if (ret && strcmp (wrk->rspamd_features, RSPAMD_FEATURES) != 0) {
  1326. msg_err_config ("worker %s has incorrect rspamd features '%s' ('%s' expected)",
  1327. wrk->name, wrk->rspamd_features, RSPAMD_FEATURES);
  1328. ret = FALSE;
  1329. }
  1330. }
  1331. else {
  1332. ret = FALSE;
  1333. }
  1334. return ret;
  1335. }
  1336. gboolean
  1337. rspamd_init_filters (struct rspamd_config *cfg, bool reconfig, bool strict)
  1338. {
  1339. GList *cur;
  1340. module_t *mod, **pmod;
  1341. guint i = 0;
  1342. struct module_ctx *mod_ctx, *cur_ctx;
  1343. gboolean ret = TRUE;
  1344. /* Init all compiled modules */
  1345. for (pmod = cfg->compiled_modules; pmod != NULL && *pmod != NULL; pmod ++) {
  1346. mod = *pmod;
  1347. if (rspamd_check_module (cfg, mod)) {
  1348. if (mod->module_init_func (cfg, &mod_ctx) == 0) {
  1349. g_assert (mod_ctx != NULL);
  1350. g_ptr_array_add (cfg->c_modules, mod_ctx);
  1351. mod_ctx->mod = mod;
  1352. mod->ctx_offset = i ++;
  1353. }
  1354. }
  1355. }
  1356. /* Now check what's enabled */
  1357. cur = g_list_first (cfg->filters);
  1358. while (cur) {
  1359. /* Perform modules configuring */
  1360. mod_ctx = NULL;
  1361. PTR_ARRAY_FOREACH (cfg->c_modules, i, cur_ctx) {
  1362. if (g_ascii_strcasecmp (cur_ctx->mod->name,
  1363. (const gchar *)cur->data) == 0) {
  1364. mod_ctx = cur_ctx;
  1365. break;
  1366. }
  1367. }
  1368. if (mod_ctx) {
  1369. mod = mod_ctx->mod;
  1370. mod_ctx->enabled = rspamd_config_is_module_enabled (cfg, mod->name);
  1371. if (reconfig) {
  1372. if (!mod->module_reconfig_func (cfg)) {
  1373. msg_err_config ("reconfig of %s failed!", mod->name);
  1374. }
  1375. else {
  1376. msg_info_config ("reconfig of %s", mod->name);
  1377. }
  1378. }
  1379. else {
  1380. if (!mod->module_config_func (cfg)) {
  1381. msg_err_config ("config of %s failed", mod->name);
  1382. ret = FALSE;
  1383. if (strict) {
  1384. return FALSE;
  1385. }
  1386. }
  1387. }
  1388. }
  1389. if (mod_ctx == NULL) {
  1390. msg_warn_config ("requested unknown module %s", cur->data);
  1391. }
  1392. cur = g_list_next (cur);
  1393. }
  1394. ret = rspamd_init_lua_filters (cfg, 0, strict) && ret;
  1395. return ret;
  1396. }
  1397. static void
  1398. rspamd_config_new_symbol (struct rspamd_config *cfg, const gchar *symbol,
  1399. gdouble score, const gchar *description, const gchar *group,
  1400. guint flags, guint priority, gint nshots)
  1401. {
  1402. struct rspamd_symbols_group *sym_group;
  1403. struct rspamd_symbol *sym_def;
  1404. gdouble *score_ptr;
  1405. sym_def =
  1406. rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (struct rspamd_symbol));
  1407. score_ptr = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (gdouble));
  1408. if (isnan (score)) {
  1409. /* In fact, it could be defined later */
  1410. msg_debug_config ("score is not defined for symbol %s, set it to zero",
  1411. symbol);
  1412. score = 0.0;
  1413. /* Also set priority to 0 to allow override by anything */
  1414. sym_def->priority = 0;
  1415. flags |= RSPAMD_SYMBOL_FLAG_UNSCORED;
  1416. }
  1417. else {
  1418. sym_def->priority = priority;
  1419. }
  1420. *score_ptr = score;
  1421. sym_def->score = score;
  1422. sym_def->weight_ptr = score_ptr;
  1423. sym_def->name = rspamd_mempool_strdup (cfg->cfg_pool, symbol);
  1424. sym_def->flags = flags;
  1425. sym_def->nshots = nshots != 0 ? nshots : cfg->default_max_shots;
  1426. sym_def->groups = g_ptr_array_sized_new (1);
  1427. rspamd_mempool_add_destructor (cfg->cfg_pool, rspamd_ptr_array_free_hard,
  1428. sym_def->groups);
  1429. if (description) {
  1430. sym_def->description = rspamd_mempool_strdup (cfg->cfg_pool, description);
  1431. }
  1432. msg_debug_config ("registered symbol %s with weight %.2f in and group %s",
  1433. sym_def->name, score, group);
  1434. g_hash_table_insert (cfg->symbols, sym_def->name, sym_def);
  1435. /* Search for symbol group */
  1436. if (group == NULL) {
  1437. group = "ungrouped";
  1438. sym_def->flags |= RSPAMD_SYMBOL_FLAG_UNGROUPPED;
  1439. }
  1440. else {
  1441. if (strcmp (group, "ungrouped") == 0) {
  1442. sym_def->flags |= RSPAMD_SYMBOL_FLAG_UNGROUPPED;
  1443. }
  1444. }
  1445. sym_group = g_hash_table_lookup (cfg->groups, group);
  1446. if (sym_group == NULL) {
  1447. /* Create new group */
  1448. sym_group = rspamd_config_new_group (cfg, group);
  1449. }
  1450. sym_def->gr = sym_group;
  1451. g_hash_table_insert (sym_group->symbols, sym_def->name, sym_def);
  1452. if (!(sym_def->flags & RSPAMD_SYMBOL_FLAG_UNGROUPPED)) {
  1453. g_ptr_array_add (sym_def->groups, sym_group);
  1454. }
  1455. }
  1456. gboolean
  1457. rspamd_config_add_symbol (struct rspamd_config *cfg,
  1458. const gchar *symbol,
  1459. gdouble score,
  1460. const gchar *description,
  1461. const gchar *group,
  1462. guint flags,
  1463. guint priority,
  1464. gint nshots)
  1465. {
  1466. struct rspamd_symbol *sym_def;
  1467. struct rspamd_symbols_group *sym_group;
  1468. guint i;
  1469. g_assert (cfg != NULL);
  1470. g_assert (symbol != NULL);
  1471. sym_def = g_hash_table_lookup (cfg->symbols, symbol);
  1472. if (sym_def != NULL) {
  1473. if (group != NULL) {
  1474. gboolean has_group = FALSE;
  1475. PTR_ARRAY_FOREACH (sym_def->groups, i, sym_group) {
  1476. if (g_ascii_strcasecmp (sym_group->name, group) == 0) {
  1477. /* Group is already here */
  1478. has_group = TRUE;
  1479. break;
  1480. }
  1481. }
  1482. if (!has_group) {
  1483. /* Non-empty group has a priority over non-groupped one */
  1484. sym_group = g_hash_table_lookup (cfg->groups, group);
  1485. if (sym_group == NULL) {
  1486. /* Create new group */
  1487. sym_group = rspamd_config_new_group (cfg, group);
  1488. }
  1489. if (!sym_def->gr) {
  1490. sym_def->gr = sym_group;
  1491. }
  1492. g_hash_table_insert (sym_group->symbols, sym_def->name, sym_def);
  1493. sym_def->flags &= ~(RSPAMD_SYMBOL_FLAG_UNGROUPPED);
  1494. g_ptr_array_add (sym_def->groups, sym_group);
  1495. }
  1496. }
  1497. if (sym_def->priority > priority &&
  1498. (isnan(score) || !(sym_def->flags & RSPAMD_SYMBOL_FLAG_UNSCORED))) {
  1499. msg_debug_config ("symbol %s has been already registered with "
  1500. "priority %ud, do not override (new priority: %ud)",
  1501. symbol,
  1502. sym_def->priority,
  1503. priority);
  1504. /* But we can still add description */
  1505. if (!sym_def->description && description) {
  1506. sym_def->description = rspamd_mempool_strdup (cfg->cfg_pool,
  1507. description);
  1508. }
  1509. /* Or nshots in case of non-default setting */
  1510. if (nshots != 0 && sym_def->nshots == cfg->default_max_shots) {
  1511. sym_def->nshots = nshots;
  1512. }
  1513. return FALSE;
  1514. }
  1515. else {
  1516. if (!isnan (score)) {
  1517. msg_debug_config ("symbol %s has been already registered with "
  1518. "priority %ud, override it with new priority: %ud, "
  1519. "old score: %.2f, new score: %.2f",
  1520. symbol,
  1521. sym_def->priority,
  1522. priority,
  1523. sym_def->score,
  1524. score);
  1525. *sym_def->weight_ptr = score;
  1526. sym_def->score = score;
  1527. sym_def->priority = priority;
  1528. sym_def->flags &= ~RSPAMD_SYMBOL_FLAG_UNSCORED;
  1529. }
  1530. sym_def->flags = flags;
  1531. if (nshots != 0) {
  1532. sym_def->nshots = nshots;
  1533. }
  1534. else {
  1535. /* Do not reset unless we have exactly lower priority */
  1536. if (sym_def->priority < priority) {
  1537. sym_def->nshots = cfg->default_max_shots;
  1538. }
  1539. }
  1540. if (description) {
  1541. sym_def->description = rspamd_mempool_strdup (cfg->cfg_pool,
  1542. description);
  1543. }
  1544. /* We also check group information in this case */
  1545. if (group != NULL && sym_def->gr != NULL &&
  1546. strcmp (group, sym_def->gr->name) != 0) {
  1547. sym_group = g_hash_table_lookup (cfg->groups, group);
  1548. if (sym_group == NULL) {
  1549. /* Create new group */
  1550. sym_group = rspamd_config_new_group (cfg, group);
  1551. }
  1552. if (!(sym_group->flags & RSPAMD_SYMBOL_GROUP_UNGROUPED)) {
  1553. msg_debug_config ("move symbol %s from group %s to %s",
  1554. sym_def->name, sym_def->gr->name, group);
  1555. g_hash_table_remove (sym_def->gr->symbols, sym_def->name);
  1556. sym_def->gr = sym_group;
  1557. g_hash_table_insert (sym_group->symbols, sym_def->name, sym_def);
  1558. }
  1559. }
  1560. return TRUE;
  1561. }
  1562. }
  1563. /* This is called merely when we have an undefined symbol */
  1564. rspamd_config_new_symbol (cfg, symbol, score, description,
  1565. group, flags, priority, nshots);
  1566. return TRUE;
  1567. }
  1568. gboolean
  1569. rspamd_config_add_symbol_group (struct rspamd_config *cfg,
  1570. const gchar *symbol,
  1571. const gchar *group)
  1572. {
  1573. struct rspamd_symbol *sym_def;
  1574. struct rspamd_symbols_group *sym_group;
  1575. guint i;
  1576. g_assert (cfg != NULL);
  1577. g_assert (symbol != NULL);
  1578. g_assert (group != NULL);
  1579. sym_def = g_hash_table_lookup (cfg->symbols, symbol);
  1580. if (sym_def != NULL) {
  1581. gboolean has_group = FALSE;
  1582. PTR_ARRAY_FOREACH (sym_def->groups, i, sym_group) {
  1583. if (g_ascii_strcasecmp (sym_group->name, group) == 0) {
  1584. /* Group is already here */
  1585. has_group = TRUE;
  1586. break;
  1587. }
  1588. }
  1589. if (!has_group) {
  1590. /* Non-empty group has a priority over non-groupped one */
  1591. sym_group = g_hash_table_lookup (cfg->groups, group);
  1592. if (sym_group == NULL) {
  1593. /* Create new group */
  1594. sym_group = rspamd_config_new_group (cfg, group);
  1595. }
  1596. if (!sym_def->gr) {
  1597. sym_def->gr = sym_group;
  1598. }
  1599. g_hash_table_insert (sym_group->symbols, sym_def->name, sym_def);
  1600. sym_def->flags &= ~(RSPAMD_SYMBOL_FLAG_UNGROUPPED);
  1601. g_ptr_array_add (sym_def->groups, sym_group);
  1602. return TRUE;
  1603. }
  1604. }
  1605. return FALSE;
  1606. }
  1607. gboolean
  1608. rspamd_config_is_module_enabled (struct rspamd_config *cfg,
  1609. const gchar *module_name)
  1610. {
  1611. gboolean is_c = FALSE;
  1612. const ucl_object_t *conf, *enabled;
  1613. GList *cur;
  1614. struct rspamd_symbols_group *gr;
  1615. lua_State *L = cfg->lua_state;
  1616. struct module_ctx *cur_ctx;
  1617. guint i;
  1618. PTR_ARRAY_FOREACH (cfg->c_modules, i, cur_ctx) {
  1619. if (g_ascii_strcasecmp (cur_ctx->mod->name, module_name) == 0) {
  1620. is_c = TRUE;
  1621. break;
  1622. }
  1623. }
  1624. if (g_hash_table_lookup (cfg->explicit_modules, module_name) != NULL) {
  1625. /* Always load module */
  1626. rspamd_plugins_table_push_elt (L, "enabled", module_name);
  1627. return TRUE;
  1628. }
  1629. if (is_c) {
  1630. gboolean found = FALSE;
  1631. cur = g_list_first (cfg->filters);
  1632. while (cur) {
  1633. if (strcmp (cur->data, module_name) == 0) {
  1634. found = TRUE;
  1635. break;
  1636. }
  1637. cur = g_list_next (cur);
  1638. }
  1639. if (!found) {
  1640. msg_info_config ("internal module %s is disable in `filters` line",
  1641. module_name);
  1642. rspamd_plugins_table_push_elt (L,
  1643. "disabled_explicitly", module_name);
  1644. return FALSE;
  1645. }
  1646. }
  1647. conf = ucl_object_lookup (cfg->rcl_obj, module_name);
  1648. if (conf == NULL) {
  1649. rspamd_plugins_table_push_elt (L, "disabled_unconfigured", module_name);
  1650. msg_info_config ("%s module %s is enabled but has not been configured",
  1651. is_c ? "internal" : "lua", module_name);
  1652. if (!is_c) {
  1653. msg_info_config ("%s disabling unconfigured lua module", module_name);
  1654. return FALSE;
  1655. }
  1656. }
  1657. else {
  1658. enabled = ucl_object_lookup (conf, "enabled");
  1659. if (enabled) {
  1660. if (ucl_object_type (enabled) == UCL_BOOLEAN) {
  1661. if (!ucl_object_toboolean (enabled)) {
  1662. rspamd_plugins_table_push_elt (L,
  1663. "disabled_explicitly", module_name);
  1664. msg_info_config (
  1665. "%s module %s is disabled in the configuration",
  1666. is_c ? "internal" : "lua", module_name);
  1667. return FALSE;
  1668. }
  1669. }
  1670. else if (ucl_object_type (enabled) == UCL_STRING) {
  1671. gint ret;
  1672. ret = rspamd_config_parse_flag (ucl_object_tostring (enabled), 0);
  1673. if (ret == 0) {
  1674. rspamd_plugins_table_push_elt (L,
  1675. "disabled_explicitly", module_name);
  1676. msg_info_config (
  1677. "%s module %s is disabled in the configuration",
  1678. is_c ? "internal" : "lua", module_name);
  1679. return FALSE;
  1680. }
  1681. else if (ret == -1) {
  1682. rspamd_plugins_table_push_elt (L,
  1683. "disabled_failed", module_name);
  1684. msg_info_config (
  1685. "%s module %s has wrong enabled flag (%s) in the configuration",
  1686. is_c ? "internal" : "lua", module_name,
  1687. ucl_object_tostring (enabled));
  1688. return FALSE;
  1689. }
  1690. }
  1691. }
  1692. }
  1693. /* Now we check symbols group */
  1694. gr = g_hash_table_lookup (cfg->groups, module_name);
  1695. if (gr) {
  1696. if (gr->flags & RSPAMD_SYMBOL_GROUP_DISABLED) {
  1697. rspamd_plugins_table_push_elt (L,
  1698. "disabled_explicitly", module_name);
  1699. msg_info_config ("%s module %s is disabled in the configuration as "
  1700. "its group has been disabled",
  1701. is_c ? "internal" : "lua", module_name);
  1702. return FALSE;
  1703. }
  1704. }
  1705. rspamd_plugins_table_push_elt (L, "enabled", module_name);
  1706. return TRUE;
  1707. }
  1708. static gboolean
  1709. rspamd_config_action_from_ucl (struct rspamd_config *cfg,
  1710. struct rspamd_action *act,
  1711. const ucl_object_t *obj,
  1712. guint priority)
  1713. {
  1714. const ucl_object_t *elt;
  1715. gdouble threshold = NAN;
  1716. guint flags = 0, std_act, obj_type;
  1717. obj_type = ucl_object_type (obj);
  1718. if (obj_type == UCL_OBJECT) {
  1719. obj_type = ucl_object_type (obj);
  1720. elt = ucl_object_lookup_any (obj, "score", "threshold", NULL);
  1721. if (elt) {
  1722. threshold = ucl_object_todouble (elt);
  1723. }
  1724. elt = ucl_object_lookup (obj, "flags");
  1725. if (elt && ucl_object_type (elt) == UCL_ARRAY) {
  1726. const ucl_object_t *cur;
  1727. ucl_object_iter_t it = NULL;
  1728. while ((cur = ucl_object_iterate (elt, &it, true)) != NULL) {
  1729. if (ucl_object_type (cur) == UCL_STRING) {
  1730. const gchar *fl_str = ucl_object_tostring (cur);
  1731. if (g_ascii_strcasecmp (fl_str, "no_threshold") == 0) {
  1732. flags |= RSPAMD_ACTION_NO_THRESHOLD;
  1733. } else if (g_ascii_strcasecmp (fl_str, "threshold_only") == 0) {
  1734. flags |= RSPAMD_ACTION_THRESHOLD_ONLY;
  1735. } else if (g_ascii_strcasecmp (fl_str, "ham") == 0) {
  1736. flags |= RSPAMD_ACTION_HAM;
  1737. } else {
  1738. msg_warn_config ("unknown action flag: %s", fl_str);
  1739. }
  1740. }
  1741. }
  1742. }
  1743. elt = ucl_object_lookup (obj, "milter");
  1744. if (elt) {
  1745. const gchar *milter_action = ucl_object_tostring (elt);
  1746. if (strcmp (milter_action, "discard") == 0) {
  1747. flags |= RSPAMD_ACTION_MILTER;
  1748. act->action_type = METRIC_ACTION_DISCARD;
  1749. }
  1750. else if (strcmp (milter_action, "quarantine") == 0) {
  1751. flags |= RSPAMD_ACTION_MILTER;
  1752. act->action_type = METRIC_ACTION_QUARANTINE;
  1753. }
  1754. else {
  1755. msg_warn_config ("unknown milter action: %s", milter_action);
  1756. }
  1757. }
  1758. }
  1759. else if (obj_type == UCL_FLOAT || obj_type == UCL_INT) {
  1760. threshold = ucl_object_todouble (obj);
  1761. }
  1762. /* TODO: add lua references support */
  1763. if (isnan (threshold) && !(flags & RSPAMD_ACTION_NO_THRESHOLD)) {
  1764. msg_err_config ("action %s has no threshold being set and it is not"
  1765. " a no threshold action", act->name);
  1766. return FALSE;
  1767. }
  1768. act->threshold = threshold;
  1769. act->flags = flags;
  1770. if (!(flags & RSPAMD_ACTION_MILTER)) {
  1771. if (rspamd_action_from_str (act->name, &std_act)) {
  1772. act->action_type = std_act;
  1773. } else {
  1774. act->action_type = METRIC_ACTION_CUSTOM;
  1775. }
  1776. }
  1777. return TRUE;
  1778. }
  1779. gboolean
  1780. rspamd_config_set_action_score (struct rspamd_config *cfg,
  1781. const gchar *action_name,
  1782. const ucl_object_t *obj)
  1783. {
  1784. struct rspamd_action *act;
  1785. enum rspamd_action_type std_act;
  1786. const ucl_object_t *elt;
  1787. guint priority = ucl_object_get_priority (obj), obj_type;
  1788. g_assert (cfg != NULL);
  1789. g_assert (action_name != NULL);
  1790. obj_type = ucl_object_type (obj);
  1791. if (obj_type == UCL_OBJECT) {
  1792. elt = ucl_object_lookup (obj, "priority");
  1793. if (elt) {
  1794. priority = ucl_object_toint (elt);
  1795. }
  1796. }
  1797. /* Here are dragons:
  1798. * We have `canonical` name for actions, such as `soft reject` and
  1799. * configuration names for actions (used to be more convenient), such
  1800. * as `soft_reject`. Unfortunately, we must have heuristic for this
  1801. * variance of names.
  1802. */
  1803. if (rspamd_action_from_str (action_name, (gint *)&std_act)) {
  1804. action_name = rspamd_action_to_str (std_act);
  1805. }
  1806. HASH_FIND_STR (cfg->actions, action_name, act);
  1807. if (act) {
  1808. /* Existing element */
  1809. if (act->priority <= priority) {
  1810. /* We can replace data */
  1811. msg_info_config ("action %s has been already registered with "
  1812. "priority %ud, override it with new priority: %ud, "
  1813. "old score: %.2f",
  1814. action_name,
  1815. act->priority,
  1816. priority,
  1817. act->threshold);
  1818. if (rspamd_config_action_from_ucl (cfg, act, obj, priority)) {
  1819. rspamd_actions_sort (cfg);
  1820. }
  1821. else {
  1822. return FALSE;
  1823. }
  1824. }
  1825. else {
  1826. msg_info_config ("action %s has been already registered with "
  1827. "priority %ud, do not override (new priority: %ud)",
  1828. action_name,
  1829. act->priority,
  1830. priority);
  1831. }
  1832. }
  1833. else {
  1834. /* Add new element */
  1835. act = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*act));
  1836. act->name = rspamd_mempool_strdup (cfg->cfg_pool, action_name);
  1837. if (rspamd_config_action_from_ucl (cfg, act, obj, priority)) {
  1838. HASH_ADD_KEYPTR (hh, cfg->actions,
  1839. act->name, strlen (act->name), act);
  1840. rspamd_actions_sort (cfg);
  1841. }
  1842. else {
  1843. return FALSE;
  1844. }
  1845. }
  1846. return TRUE;
  1847. }
  1848. gboolean
  1849. rspamd_config_maybe_disable_action (struct rspamd_config *cfg,
  1850. const gchar *action_name,
  1851. guint priority)
  1852. {
  1853. struct rspamd_action *act;
  1854. HASH_FIND_STR (cfg->actions, action_name, act);
  1855. if (act) {
  1856. if (priority >= act->priority) {
  1857. msg_info_config ("disable action %s; old priority: %ud, new priority: %ud",
  1858. action_name,
  1859. act->priority,
  1860. priority);
  1861. act->threshold = NAN;
  1862. act->priority = priority;
  1863. act->flags |= RSPAMD_ACTION_NO_THRESHOLD;
  1864. return TRUE;
  1865. }
  1866. else {
  1867. msg_info_config ("action %s has been already registered with "
  1868. "priority %ud, cannot disable it with new priority: %ud",
  1869. action_name,
  1870. act->priority,
  1871. priority);
  1872. }
  1873. }
  1874. return FALSE;
  1875. }
  1876. struct rspamd_action *
  1877. rspamd_config_get_action (struct rspamd_config *cfg, const gchar *name)
  1878. {
  1879. struct rspamd_action *res = NULL;
  1880. HASH_FIND_STR (cfg->actions, name, res);
  1881. return res;
  1882. }
  1883. struct rspamd_action *
  1884. rspamd_config_get_action_by_type (struct rspamd_config *cfg,
  1885. enum rspamd_action_type type)
  1886. {
  1887. struct rspamd_action *cur, *tmp;
  1888. HASH_ITER (hh, cfg->actions, cur, tmp) {
  1889. if (cur->action_type == type) {
  1890. return cur;
  1891. }
  1892. }
  1893. return NULL;
  1894. }
  1895. gboolean
  1896. rspamd_config_radix_from_ucl (struct rspamd_config *cfg,
  1897. const ucl_object_t *obj,
  1898. const gchar *description,
  1899. struct rspamd_radix_map_helper **target,
  1900. GError **err,
  1901. struct rspamd_worker *worker)
  1902. {
  1903. ucl_type_t type;
  1904. ucl_object_iter_t it = NULL;
  1905. const ucl_object_t *cur, *cur_elt;
  1906. const gchar *str;
  1907. /* Cleanup */
  1908. *target = NULL;
  1909. LL_FOREACH (obj, cur_elt) {
  1910. type = ucl_object_type (cur_elt);
  1911. switch (type) {
  1912. case UCL_STRING:
  1913. /* Either map or a list of IPs */
  1914. str = ucl_object_tostring (cur_elt);
  1915. if (rspamd_map_is_map (str)) {
  1916. if (rspamd_map_add_from_ucl (cfg, cur_elt,
  1917. description,
  1918. rspamd_radix_read,
  1919. rspamd_radix_fin,
  1920. rspamd_radix_dtor,
  1921. (void **)target,
  1922. worker, RSPAMD_MAP_DEFAULT) == NULL) {
  1923. g_set_error (err,
  1924. g_quark_from_static_string ("rspamd-config"),
  1925. EINVAL, "bad map definition %s for %s", str,
  1926. ucl_object_key (obj));
  1927. return FALSE;
  1928. }
  1929. return TRUE;
  1930. }
  1931. else {
  1932. /* Just a list */
  1933. if (!*target) {
  1934. *target = rspamd_map_helper_new_radix (NULL);
  1935. }
  1936. rspamd_map_helper_insert_radix_resolve (*target, str, "");
  1937. }
  1938. break;
  1939. case UCL_OBJECT:
  1940. /* Should be a map description */
  1941. if (rspamd_map_add_from_ucl (cfg, cur_elt,
  1942. description,
  1943. rspamd_radix_read,
  1944. rspamd_radix_fin,
  1945. rspamd_radix_dtor,
  1946. (void **)target,
  1947. worker, RSPAMD_MAP_DEFAULT) == NULL) {
  1948. g_set_error (err,
  1949. g_quark_from_static_string ("rspamd-config"),
  1950. EINVAL, "bad map object for %s", ucl_object_key (obj));
  1951. return FALSE;
  1952. }
  1953. return TRUE;
  1954. break;
  1955. case UCL_ARRAY:
  1956. /* List of IP addresses */
  1957. it = ucl_object_iterate_new (cur_elt);
  1958. while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
  1959. str = ucl_object_tostring (cur);
  1960. if (!*target) {
  1961. *target = rspamd_map_helper_new_radix (NULL);
  1962. }
  1963. rspamd_map_helper_insert_radix_resolve (*target, str, "");
  1964. }
  1965. ucl_object_iterate_free (it);
  1966. break;
  1967. default:
  1968. g_set_error (err, g_quark_from_static_string ("rspamd-config"),
  1969. EINVAL, "bad map type %s for %s",
  1970. ucl_object_type_to_string (type),
  1971. ucl_object_key (obj));
  1972. return FALSE;
  1973. }
  1974. }
  1975. /* Destroy on cfg cleanup */
  1976. rspamd_mempool_add_destructor (cfg->cfg_pool,
  1977. (rspamd_mempool_destruct_t)rspamd_map_helper_destroy_radix,
  1978. *target);
  1979. return TRUE;
  1980. }
  1981. gboolean
  1982. rspamd_action_from_str (const gchar *data, gint *result)
  1983. {
  1984. guint64 h;
  1985. h = rspamd_cryptobox_fast_hash_specific (RSPAMD_CRYPTOBOX_XXHASH64,
  1986. data, strlen (data), 0xdeadbabe);
  1987. switch (h) {
  1988. case 0x9917BFDB46332B8CULL: /* reject */
  1989. *result = METRIC_ACTION_REJECT;
  1990. break;
  1991. case 0x7130EE37D07B3715ULL: /* greylist */
  1992. *result = METRIC_ACTION_GREYLIST;
  1993. break;
  1994. case 0xCA6087E05480C60CULL: /* add_header */
  1995. case 0x87A3D27783B16241ULL: /* add header */
  1996. *result = METRIC_ACTION_ADD_HEADER;
  1997. break;
  1998. case 0x4963374ED8B90449ULL: /* rewrite_subject */
  1999. case 0x5C9FC4679C025948ULL: /* rewrite subject */
  2000. *result = METRIC_ACTION_REWRITE_SUBJECT;
  2001. break;
  2002. case 0xFC7D6502EE71FDD9ULL: /* soft reject */
  2003. case 0x73576567C262A82DULL: /* soft_reject */
  2004. *result = METRIC_ACTION_SOFT_REJECT;
  2005. break;
  2006. case 0x207091B927D1EC0DULL: /* no action */
  2007. case 0xB7D92D002CD46325ULL: /* no_action */
  2008. case 0x167C0DF4BAA9BCECULL: /* accept */
  2009. *result = METRIC_ACTION_NOACTION;
  2010. break;
  2011. case 0x4E9666ECCD3FC314ULL: /* quarantine */
  2012. *result = METRIC_ACTION_QUARANTINE;
  2013. break;
  2014. case 0x93B346242F7F69B3ULL: /* discard */
  2015. *result = METRIC_ACTION_DISCARD;
  2016. break;
  2017. default:
  2018. return FALSE;
  2019. }
  2020. return TRUE;
  2021. }
  2022. const gchar *
  2023. rspamd_action_to_str (enum rspamd_action_type action)
  2024. {
  2025. switch (action) {
  2026. case METRIC_ACTION_REJECT:
  2027. return "reject";
  2028. case METRIC_ACTION_SOFT_REJECT:
  2029. return "soft reject";
  2030. case METRIC_ACTION_REWRITE_SUBJECT:
  2031. return "rewrite subject";
  2032. case METRIC_ACTION_ADD_HEADER:
  2033. return "add header";
  2034. case METRIC_ACTION_GREYLIST:
  2035. return "greylist";
  2036. case METRIC_ACTION_NOACTION:
  2037. return "no action";
  2038. case METRIC_ACTION_MAX:
  2039. return "invalid max action";
  2040. case METRIC_ACTION_CUSTOM:
  2041. return "custom";
  2042. case METRIC_ACTION_DISCARD:
  2043. return "discard";
  2044. case METRIC_ACTION_QUARANTINE:
  2045. return "quarantine";
  2046. }
  2047. return "unknown action";
  2048. }
  2049. const gchar *
  2050. rspamd_action_to_str_alt (enum rspamd_action_type action)
  2051. {
  2052. switch (action) {
  2053. case METRIC_ACTION_REJECT:
  2054. return "reject";
  2055. case METRIC_ACTION_SOFT_REJECT:
  2056. return "soft_reject";
  2057. case METRIC_ACTION_REWRITE_SUBJECT:
  2058. return "rewrite_subject";
  2059. case METRIC_ACTION_ADD_HEADER:
  2060. return "add_header";
  2061. case METRIC_ACTION_GREYLIST:
  2062. return "greylist";
  2063. case METRIC_ACTION_NOACTION:
  2064. return "no action";
  2065. case METRIC_ACTION_MAX:
  2066. return "invalid max action";
  2067. case METRIC_ACTION_CUSTOM:
  2068. return "custom";
  2069. case METRIC_ACTION_DISCARD:
  2070. return "discard";
  2071. case METRIC_ACTION_QUARANTINE:
  2072. return "quarantine";
  2073. }
  2074. return "unknown action";
  2075. }
  2076. static int
  2077. rspamd_actions_cmp (const struct rspamd_action *a1, const struct rspamd_action *a2)
  2078. {
  2079. if (!isnan (a1->threshold) && !isnan (a2->threshold)) {
  2080. if (a1->threshold < a2->threshold) {
  2081. return -1;
  2082. }
  2083. else if (a1->threshold > a2->threshold) {
  2084. return 1;
  2085. }
  2086. return 0;
  2087. }
  2088. if (isnan (a1->threshold) && isnan (a2->threshold)) {
  2089. return 0;
  2090. }
  2091. else if (isnan (a1->threshold)) {
  2092. return 1;
  2093. }
  2094. else {
  2095. return -1;
  2096. }
  2097. }
  2098. void
  2099. rspamd_actions_sort (struct rspamd_config *cfg)
  2100. {
  2101. HASH_SORT (cfg->actions, rspamd_actions_cmp);
  2102. }
  2103. static void
  2104. rspamd_config_settings_elt_dtor (struct rspamd_config_settings_elt *e)
  2105. {
  2106. if (e->symbols_enabled) {
  2107. ucl_object_unref (e->symbols_enabled);
  2108. }
  2109. if (e->symbols_disabled) {
  2110. ucl_object_unref (e->symbols_disabled);
  2111. }
  2112. }
  2113. guint32
  2114. rspamd_config_name_to_id (const gchar *name, gsize namelen)
  2115. {
  2116. guint64 h;
  2117. h = rspamd_cryptobox_fast_hash_specific (RSPAMD_CRYPTOBOX_XXHASH64,
  2118. name, namelen, 0x0);
  2119. /* Take the lower part of hash as LE number */
  2120. return ((guint32)GUINT64_TO_LE (h));
  2121. }
  2122. struct rspamd_config_settings_elt *
  2123. rspamd_config_find_settings_id_ref (struct rspamd_config *cfg,
  2124. guint32 id)
  2125. {
  2126. struct rspamd_config_settings_elt *cur;
  2127. DL_FOREACH (cfg->setting_ids, cur) {
  2128. if (cur->id == id) {
  2129. REF_RETAIN (cur);
  2130. return cur;
  2131. }
  2132. }
  2133. return NULL;
  2134. }
  2135. struct rspamd_config_settings_elt *rspamd_config_find_settings_name_ref (
  2136. struct rspamd_config *cfg,
  2137. const gchar *name, gsize namelen)
  2138. {
  2139. guint32 id;
  2140. id = rspamd_config_name_to_id (name, namelen);
  2141. return rspamd_config_find_settings_id_ref (cfg, id);
  2142. }
  2143. void
  2144. rspamd_config_register_settings_id (struct rspamd_config *cfg,
  2145. const gchar *name,
  2146. ucl_object_t *symbols_enabled,
  2147. ucl_object_t *symbols_disabled,
  2148. enum rspamd_config_settings_policy policy)
  2149. {
  2150. struct rspamd_config_settings_elt *elt;
  2151. guint32 id;
  2152. id = rspamd_config_name_to_id (name, strlen (name));
  2153. elt = rspamd_config_find_settings_id_ref (cfg, id);
  2154. if (elt) {
  2155. /* Need to replace */
  2156. struct rspamd_config_settings_elt *nelt;
  2157. DL_DELETE (cfg->setting_ids, elt);
  2158. nelt = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*nelt));
  2159. nelt->id = id;
  2160. nelt->name = rspamd_mempool_strdup (cfg->cfg_pool, name);
  2161. if (symbols_enabled) {
  2162. nelt->symbols_enabled = ucl_object_ref (symbols_enabled);
  2163. }
  2164. if (symbols_disabled) {
  2165. nelt->symbols_disabled = ucl_object_ref (symbols_disabled);
  2166. }
  2167. nelt->policy = policy;
  2168. REF_INIT_RETAIN (nelt, rspamd_config_settings_elt_dtor);
  2169. msg_warn_config ("replace settings id %ud (%s)", id, name);
  2170. rspamd_symcache_process_settings_elt (cfg->cache, elt);
  2171. DL_APPEND (cfg->setting_ids, nelt);
  2172. /*
  2173. * Need to unref old element twice as there are two reference holders:
  2174. * 1. Config structure as we call REF_INIT_RETAIN
  2175. * 2. rspamd_config_find_settings_id_ref also increases refcount
  2176. */
  2177. REF_RELEASE (elt);
  2178. REF_RELEASE (elt);
  2179. }
  2180. else {
  2181. elt = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*elt));
  2182. elt->id = id;
  2183. elt->name = rspamd_mempool_strdup (cfg->cfg_pool, name);
  2184. if (symbols_enabled) {
  2185. elt->symbols_enabled = ucl_object_ref (symbols_enabled);
  2186. }
  2187. if (symbols_disabled) {
  2188. elt->symbols_disabled = ucl_object_ref (symbols_disabled);
  2189. }
  2190. elt->policy = policy;
  2191. msg_info_config ("register new settings id %ud (%s)", id, name);
  2192. REF_INIT_RETAIN (elt, rspamd_config_settings_elt_dtor);
  2193. rspamd_symcache_process_settings_elt (cfg->cache, elt);
  2194. DL_APPEND (cfg->setting_ids, elt);
  2195. }
  2196. }
  2197. int
  2198. rspamd_config_ev_backend_get (struct rspamd_config *cfg)
  2199. {
  2200. #define AUTO_BACKEND (ev_supported_backends () & ~EVBACKEND_IOURING)
  2201. if (cfg == NULL || cfg->events_backend == NULL) {
  2202. return AUTO_BACKEND;
  2203. }
  2204. if (strcmp (cfg->events_backend, "auto") == 0) {
  2205. return AUTO_BACKEND;
  2206. }
  2207. else if (strcmp (cfg->events_backend, "epoll") == 0) {
  2208. if (ev_supported_backends () & EVBACKEND_EPOLL) {
  2209. return EVBACKEND_EPOLL;
  2210. }
  2211. else {
  2212. msg_warn_config ("unsupported events_backend: %s; defaulting to auto",
  2213. cfg->events_backend);
  2214. return AUTO_BACKEND;
  2215. }
  2216. }
  2217. else if (strcmp (cfg->events_backend, "iouring") == 0) {
  2218. if (ev_supported_backends () & EVBACKEND_IOURING) {
  2219. return EVBACKEND_IOURING;
  2220. }
  2221. else {
  2222. msg_warn_config ("unsupported events_backend: %s; defaulting to auto",
  2223. cfg->events_backend);
  2224. return AUTO_BACKEND;
  2225. }
  2226. }
  2227. else if (strcmp (cfg->events_backend, "kqueue") == 0) {
  2228. if (ev_supported_backends () & EVBACKEND_KQUEUE) {
  2229. return EVBACKEND_KQUEUE;
  2230. }
  2231. else {
  2232. msg_warn_config ("unsupported events_backend: %s; defaulting to auto",
  2233. cfg->events_backend);
  2234. return AUTO_BACKEND;
  2235. }
  2236. }
  2237. else if (strcmp (cfg->events_backend, "poll") == 0) {
  2238. return EVBACKEND_POLL;
  2239. }
  2240. else if (strcmp (cfg->events_backend, "select") == 0) {
  2241. return EVBACKEND_SELECT;
  2242. }
  2243. else {
  2244. msg_warn_config ("unknown events_backend: %s; defaulting to auto",
  2245. cfg->events_backend);
  2246. }
  2247. return AUTO_BACKEND;
  2248. }
  2249. const gchar *
  2250. rspamd_config_ev_backend_to_string (int ev_backend, gboolean *effective)
  2251. {
  2252. #define SET_EFFECTIVE(b) do { if ((effective) != NULL) *(effective) = b; } while(0)
  2253. if ((ev_backend & EVBACKEND_ALL) == EVBACKEND_ALL) {
  2254. SET_EFFECTIVE (TRUE);
  2255. return "auto";
  2256. }
  2257. if (ev_backend & EVBACKEND_IOURING) {
  2258. SET_EFFECTIVE (TRUE);
  2259. return "epoll+io_uring";
  2260. }
  2261. if (ev_backend & EVBACKEND_LINUXAIO) {
  2262. SET_EFFECTIVE (TRUE);
  2263. return "epoll+aio";
  2264. }if (ev_backend & EVBACKEND_IOURING) {
  2265. SET_EFFECTIVE (TRUE);
  2266. return "epoll+io_uring";
  2267. }
  2268. if (ev_backend & EVBACKEND_LINUXAIO) {
  2269. SET_EFFECTIVE (TRUE);
  2270. return "epoll+aio";
  2271. }
  2272. if (ev_backend & EVBACKEND_EPOLL) {
  2273. SET_EFFECTIVE (TRUE);
  2274. return "epoll";
  2275. }
  2276. if (ev_backend & EVBACKEND_KQUEUE) {
  2277. SET_EFFECTIVE (TRUE);
  2278. return "kqueue";
  2279. }
  2280. if (ev_backend & EVBACKEND_POLL) {
  2281. SET_EFFECTIVE (FALSE);
  2282. return "poll";
  2283. }
  2284. if (ev_backend & EVBACKEND_SELECT) {
  2285. SET_EFFECTIVE (FALSE);
  2286. return "select";
  2287. }
  2288. SET_EFFECTIVE (FALSE);
  2289. return "unknown";
  2290. #undef SET_EFFECTIVE
  2291. }
  2292. struct rspamd_external_libs_ctx *
  2293. rspamd_init_libs (void)
  2294. {
  2295. struct rlimit rlim;
  2296. struct rspamd_external_libs_ctx *ctx;
  2297. struct ottery_config *ottery_cfg;
  2298. ctx = g_malloc0 (sizeof (*ctx));
  2299. ctx->crypto_ctx = rspamd_cryptobox_init ();
  2300. ottery_cfg = g_malloc0 (ottery_get_sizeof_config ());
  2301. ottery_config_init (ottery_cfg);
  2302. ctx->ottery_cfg = ottery_cfg;
  2303. rspamd_openssl_maybe_init ();
  2304. /* Check if we have rdrand */
  2305. if ((ctx->crypto_ctx->cpu_config & CPUID_RDRAND) == 0) {
  2306. ottery_config_disable_entropy_sources (ottery_cfg,
  2307. OTTERY_ENTROPY_SRC_RDRAND);
  2308. #if OPENSSL_VERSION_NUMBER >= 0x1000104fL && !defined(LIBRESSL_VERSION_NUMBER)
  2309. RAND_set_rand_engine (NULL);
  2310. #endif
  2311. }
  2312. /* Configure utf8 library */
  2313. guint utf8_flags = 0;
  2314. if ((ctx->crypto_ctx->cpu_config & CPUID_SSE41)) {
  2315. utf8_flags |= RSPAMD_FAST_UTF8_FLAG_SSE41;
  2316. }
  2317. if ((ctx->crypto_ctx->cpu_config & CPUID_AVX2)) {
  2318. utf8_flags |= RSPAMD_FAST_UTF8_FLAG_AVX2;
  2319. }
  2320. rspamd_fast_utf8_library_init (utf8_flags);
  2321. g_assert (ottery_init (ottery_cfg) == 0);
  2322. #ifdef HAVE_LOCALE_H
  2323. if (getenv ("LANG") == NULL) {
  2324. setlocale (LC_ALL, "C");
  2325. setlocale (LC_CTYPE, "C");
  2326. setlocale (LC_MESSAGES, "C");
  2327. setlocale (LC_TIME, "C");
  2328. }
  2329. else {
  2330. /* Just set the default locale */
  2331. setlocale (LC_ALL, "");
  2332. /* But for some issues we still want C locale */
  2333. setlocale (LC_NUMERIC, "C");
  2334. }
  2335. #endif
  2336. ctx->ssl_ctx = rspamd_init_ssl_ctx ();
  2337. ctx->ssl_ctx_noverify = rspamd_init_ssl_ctx_noverify ();
  2338. rspamd_random_seed_fast ();
  2339. /* Set stack size for pcre */
  2340. getrlimit (RLIMIT_STACK, &rlim);
  2341. rlim.rlim_cur = 100 * 1024 * 1024;
  2342. rlim.rlim_max = rlim.rlim_cur;
  2343. setrlimit (RLIMIT_STACK, &rlim);
  2344. ctx->local_addrs = rspamd_inet_library_init ();
  2345. REF_INIT_RETAIN (ctx, rspamd_deinit_libs);
  2346. return ctx;
  2347. }
  2348. static struct zstd_dictionary *
  2349. rspamd_open_zstd_dictionary (const char *path)
  2350. {
  2351. struct zstd_dictionary *dict;
  2352. dict = g_malloc0 (sizeof (*dict));
  2353. dict->dict = rspamd_file_xmap (path, PROT_READ, &dict->size, TRUE);
  2354. if (dict->dict == NULL) {
  2355. g_free (dict);
  2356. return NULL;
  2357. }
  2358. dict->id = ZDICT_getDictID (dict->dict, dict->size);
  2359. if (dict->id == 0) {
  2360. g_free (dict);
  2361. return NULL;
  2362. }
  2363. return dict;
  2364. }
  2365. static void
  2366. rspamd_free_zstd_dictionary (struct zstd_dictionary *dict)
  2367. {
  2368. if (dict) {
  2369. munmap (dict->dict, dict->size);
  2370. g_free (dict);
  2371. }
  2372. }
  2373. #ifdef HAVE_OPENBLAS_SET_NUM_THREADS
  2374. extern void openblas_set_num_threads(int num_threads);
  2375. #endif
  2376. #ifdef HAVE_BLI_THREAD_SET_NUM_THREADS
  2377. extern void bli_thread_set_num_threads(int num_threads);
  2378. #endif
  2379. gboolean
  2380. rspamd_config_libs (struct rspamd_external_libs_ctx *ctx,
  2381. struct rspamd_config *cfg)
  2382. {
  2383. size_t r;
  2384. gboolean ret = TRUE;
  2385. g_assert (cfg != NULL);
  2386. if (ctx != NULL) {
  2387. if (cfg->local_addrs) {
  2388. rspamd_config_radix_from_ucl (cfg, cfg->local_addrs,
  2389. "Local addresses",
  2390. (struct rspamd_radix_map_helper **)ctx->local_addrs,
  2391. NULL,
  2392. NULL);
  2393. }
  2394. rspamd_free_zstd_dictionary (ctx->in_dict);
  2395. rspamd_free_zstd_dictionary (ctx->out_dict);
  2396. if (ctx->out_zstream) {
  2397. ZSTD_freeCStream (ctx->out_zstream);
  2398. ctx->out_zstream = NULL;
  2399. }
  2400. if (ctx->in_zstream) {
  2401. ZSTD_freeDStream (ctx->in_zstream);
  2402. ctx->in_zstream = NULL;
  2403. }
  2404. if (cfg->zstd_input_dictionary) {
  2405. ctx->in_dict = rspamd_open_zstd_dictionary (
  2406. cfg->zstd_input_dictionary);
  2407. if (ctx->in_dict == NULL) {
  2408. msg_err_config ("cannot open zstd dictionary in %s",
  2409. cfg->zstd_input_dictionary);
  2410. }
  2411. }
  2412. if (cfg->zstd_output_dictionary) {
  2413. ctx->out_dict = rspamd_open_zstd_dictionary (
  2414. cfg->zstd_output_dictionary);
  2415. if (ctx->out_dict == NULL) {
  2416. msg_err_config ("cannot open zstd dictionary in %s",
  2417. cfg->zstd_output_dictionary);
  2418. }
  2419. }
  2420. if (cfg->fips_mode) {
  2421. #ifdef HAVE_FIPS_MODE
  2422. int mode = FIPS_mode ();
  2423. unsigned long err = (unsigned long)-1;
  2424. /* Toggle FIPS mode */
  2425. if (mode == 0) {
  2426. if (FIPS_mode_set (1) != 1) {
  2427. err = ERR_get_error ();
  2428. }
  2429. }
  2430. else {
  2431. msg_info_config ("OpenSSL FIPS mode is already enabled");
  2432. }
  2433. if (err != (unsigned long)-1) {
  2434. msg_err_config ("FIPS_mode_set failed: %s",
  2435. ERR_error_string (err, NULL));
  2436. ret = FALSE;
  2437. }
  2438. else {
  2439. msg_info_config ("OpenSSL FIPS mode is enabled");
  2440. }
  2441. #else
  2442. msg_warn_config ("SSL FIPS mode is enabled but not supported by OpenSSL library!");
  2443. #endif
  2444. }
  2445. rspamd_ssl_ctx_config (cfg, ctx->ssl_ctx);
  2446. rspamd_ssl_ctx_config (cfg, ctx->ssl_ctx_noverify);
  2447. /* Init decompression */
  2448. ctx->in_zstream = ZSTD_createDStream ();
  2449. r = ZSTD_initDStream (ctx->in_zstream);
  2450. if (ZSTD_isError (r)) {
  2451. msg_err ("cannot init decompression stream: %s",
  2452. ZSTD_getErrorName (r));
  2453. ZSTD_freeDStream (ctx->in_zstream);
  2454. ctx->in_zstream = NULL;
  2455. }
  2456. /* Init compression */
  2457. ctx->out_zstream = ZSTD_createCStream ();
  2458. r = ZSTD_initCStream (ctx->out_zstream, 1);
  2459. if (ZSTD_isError (r)) {
  2460. msg_err ("cannot init compression stream: %s",
  2461. ZSTD_getErrorName (r));
  2462. ZSTD_freeCStream (ctx->out_zstream);
  2463. ctx->out_zstream = NULL;
  2464. }
  2465. #ifdef HAVE_OPENBLAS_SET_NUM_THREADS
  2466. openblas_set_num_threads (cfg->max_blas_threads);
  2467. #endif
  2468. #ifdef HAVE_BLI_THREAD_SET_NUM_THREADS
  2469. bli_thread_set_num_threads (cfg->max_blas_threads);
  2470. #endif
  2471. }
  2472. return ret;
  2473. }
  2474. gboolean
  2475. rspamd_libs_reset_decompression (struct rspamd_external_libs_ctx *ctx)
  2476. {
  2477. gsize r;
  2478. if (ctx->in_zstream == NULL) {
  2479. return FALSE;
  2480. }
  2481. else {
  2482. r = ZSTD_resetDStream (ctx->in_zstream);
  2483. if (ZSTD_isError (r)) {
  2484. msg_err ("cannot init decompression stream: %s",
  2485. ZSTD_getErrorName (r));
  2486. ZSTD_freeDStream (ctx->in_zstream);
  2487. ctx->in_zstream = NULL;
  2488. return FALSE;
  2489. }
  2490. }
  2491. return TRUE;
  2492. }
  2493. gboolean
  2494. rspamd_libs_reset_compression (struct rspamd_external_libs_ctx *ctx)
  2495. {
  2496. gsize r;
  2497. if (ctx->out_zstream == NULL) {
  2498. return FALSE;
  2499. }
  2500. else {
  2501. /* Dictionary will be reused automatically if specified */
  2502. r = ZSTD_resetCStream (ctx->out_zstream, 0);
  2503. if (ZSTD_isError (r)) {
  2504. msg_err ("cannot init compression stream: %s",
  2505. ZSTD_getErrorName (r));
  2506. ZSTD_freeCStream (ctx->out_zstream);
  2507. ctx->out_zstream = NULL;
  2508. return FALSE;
  2509. }
  2510. }
  2511. return TRUE;
  2512. }
  2513. void
  2514. rspamd_deinit_libs (struct rspamd_external_libs_ctx *ctx)
  2515. {
  2516. if (ctx != NULL) {
  2517. g_free (ctx->ottery_cfg);
  2518. #ifdef HAVE_OPENSSL
  2519. EVP_cleanup ();
  2520. ERR_free_strings ();
  2521. rspamd_ssl_ctx_free (ctx->ssl_ctx);
  2522. rspamd_ssl_ctx_free (ctx->ssl_ctx_noverify);
  2523. #endif
  2524. rspamd_inet_library_destroy ();
  2525. rspamd_free_zstd_dictionary (ctx->in_dict);
  2526. rspamd_free_zstd_dictionary (ctx->out_dict);
  2527. if (ctx->out_zstream) {
  2528. ZSTD_freeCStream (ctx->out_zstream);
  2529. }
  2530. if (ctx->in_zstream) {
  2531. ZSTD_freeDStream (ctx->in_zstream);
  2532. }
  2533. rspamd_cryptobox_deinit (ctx->crypto_ctx);
  2534. g_free (ctx);
  2535. }
  2536. }
  2537. gboolean
  2538. rspamd_ip_is_local_cfg (struct rspamd_config *cfg,
  2539. const rspamd_inet_addr_t *addr)
  2540. {
  2541. struct rspamd_radix_map_helper *local_addrs = NULL;
  2542. if (cfg && cfg->libs_ctx) {
  2543. local_addrs = *(struct rspamd_radix_map_helper**)cfg->libs_ctx->local_addrs;
  2544. }
  2545. if (rspamd_inet_address_is_local (addr)) {
  2546. return TRUE;
  2547. }
  2548. if (local_addrs) {
  2549. if (rspamd_match_radix_map_addr (local_addrs, addr) != NULL) {
  2550. return TRUE;
  2551. }
  2552. }
  2553. return FALSE;
  2554. }