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.

пре 8 година
пре 8 година
пре 8 година
пре 10 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 10 година
пре 9 година
пре 10 година
пре 10 година
пре 10 година
пре 9 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 8 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 9 година
пре 10 година
пре 10 година
пре 9 година
пре 10 година
пре 9 година
пре 9 година
пре 9 година
пре 10 година
пре 9 година
пре 10 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 10 година
пре 8 година
пре 10 година
пре 8 година
пре 10 година
пре 8 година
пре 10 година
пре 8 година
пре 9 година
пре 9 година
пре 8 година
пре 8 година
пре 10 година
пре 8 година
пре 10 година
пре 8 година
пре 8 година
пре 10 година
пре 8 година
пре 10 година
пре 8 година
пре 10 година
пре 8 година
пре 10 година
пре 8 година
пре 8 година
пре 8 година
пре 10 година
пре 9 година
пре 8 година
пре 9 година
пре 8 година
пре 9 година
пре 8 година
пре 9 година
пре 8 година
пре 9 година
пре 8 година
пре 9 година
пре 10 година
пре 9 година
пре 10 година
пре 9 година
пре 10 година
пре 8 година
пре 10 година
пре 8 година
пре 10 година
пре 10 година
пре 8 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 8 година
пре 10 година
пре 10 година
пре 8 година
пре 10 година
пре 8 година
пре 8 година
пре 9 година
пре 10 година
пре 9 година
пре 10 година
пре 10 година
пре 9 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 9 година
пре 10 година
пре 8 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 9 година
пре 9 година
пре 9 година
пре 8 година
пре 9 година
пре 8 година
пре 9 година
пре 8 година
пре 8 година
пре 9 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 9 година
пре 10 година
пре 10 година
пре 10 година
пре 9 година
пре 10 година
пре 9 година
пре 10 година
пре 10 година
пре 9 година
пре 9 година
пре 9 година
пре 10 година
пре 10 година
пре 9 година
пре 10 година
пре 9 година
пре 10 година
пре 10 година
пре 8 година
пре 8 година
пре 9 година
пре 10 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 8 година
пре 9 година
пре 9 година
пре 10 година
пре 9 година
пре 10 година
пре 10 година
пре 9 година
пре 9 година
пре 10 година
пре 10 година
пре 10 година
пре 8 година
пре 10 година
пре 10 година
пре 9 година
пре 9 година
пре 8 година
пре 9 година
пре 8 година
пре 9 година
пре 10 година
пре 10 година
пре 8 година
пре 9 година
пре 10 година
пре 10 година
пре 9 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 8 година
пре 10 година
пре 9 година
пре 10 година
пре 8 година
пре 10 година
пре 10 година
пре 9 година
пре 8 година
пре 10 година
пре 9 година
пре 8 година
пре 8 година
пре 9 година
пре 8 година
пре 10 година
пре 8 година
пре 8 година
пре 8 година
пре 8 година
пре 8 година
пре 8 година
пре 8 година
пре 8 година
пре 8 година
пре 8 година
пре 8 година
пре 8 година
пре 8 година
пре 8 година
пре 8 година
пре 8 година
пре 8 година
пре 8 година
пре 10 година
пре 10 година
пре 9 година
пре 9 година
пре 9 година
пре 10 година
пре 10 година
пре 9 година
пре 8 година
пре 8 година
пре 8 година
пре 8 година
пре 9 година
пре 10 година
пре 9 година
пре 10 година
пре 9 година
пре 10 година
пре 9 година
пре 9 година
пре 10 година
пре 8 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 10 година
пре 9 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 9 година
пре 10 година
пре 10 година
пре 10 година
пре 9 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 9 година
пре 8 година
пре 10 година
пре 9 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 9 година
пре 9 година
пре 9 година
пре 10 година
пре 8 година
пре 10 година
пре 9 година
пре 8 година
пре 8 година
пре 8 година
пре 8 година
пре 9 година
пре 8 година
пре 9 година
пре 8 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 9 година
пре 9 година
пре 9 година
пре 8 година
пре 9 година
пре 8 година
пре 9 година
пре 8 година
пре 9 година
пре 8 година
пре 9 година
пре 9 година
пре 9 година
пре 8 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 9 година
пре 8 година
пре 9 година
пре 8 година
пре 8 година
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185
  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 "cfg_rcl.h"
  17. #include "rspamd.h"
  18. #include "uthash_strcase.h"
  19. #include "utlist.h"
  20. #include "cfg_file.h"
  21. #include "lua/lua_common.h"
  22. #include "expression.h"
  23. #include "composites.h"
  24. #include "libserver/worker_util.h"
  25. #include "unix-std.h"
  26. #include "cryptobox.h"
  27. #ifdef HAVE_SYSLOG_H
  28. #include <syslog.h>
  29. #endif
  30. #ifdef HAVE_GLOB_H
  31. #include <glob.h>
  32. #endif
  33. struct rspamd_rcl_default_handler_data {
  34. struct rspamd_rcl_struct_parser pd;
  35. const gchar *key;
  36. rspamd_rcl_default_handler_t handler;
  37. UT_hash_handle hh;
  38. };
  39. struct rspamd_rcl_section {
  40. const gchar *name; /**< name of section */
  41. const gchar *key_attr;
  42. const gchar *default_key;
  43. rspamd_rcl_handler_t handler; /**< handler of section attributes */
  44. enum ucl_type type; /**< type of attribute */
  45. gboolean required; /**< whether this param is required */
  46. gboolean strict_type; /**< whether we need strict type */
  47. UT_hash_handle hh; /** hash handle */
  48. struct rspamd_rcl_section *subsections; /**< hash table of subsections */
  49. struct rspamd_rcl_default_handler_data *default_parser; /**< generic parsing fields */
  50. rspamd_rcl_section_fin_t fin; /** called at the end of section parsing */
  51. gpointer fin_ud;
  52. ucl_object_t *doc_ref; /**< reference to the section's documentation */
  53. };
  54. struct rspamd_worker_param_key {
  55. const gchar *name;
  56. gpointer ptr;
  57. };
  58. struct rspamd_worker_param_parser {
  59. rspamd_rcl_default_handler_t handler; /**< handler function */
  60. struct rspamd_rcl_struct_parser parser; /**< parser attributes */
  61. struct rspamd_worker_param_key key;
  62. };
  63. struct rspamd_worker_cfg_parser {
  64. GHashTable *parsers; /**< parsers hash */
  65. gint type; /**< workers quark */
  66. gboolean (*def_obj_parser)(ucl_object_t *obj, gpointer ud); /**<
  67. default object parser */
  68. gpointer def_ud;
  69. };
  70. static gboolean rspamd_rcl_process_section (struct rspamd_rcl_section *sec,
  71. gpointer ptr, const ucl_object_t *obj, rspamd_mempool_t *pool,
  72. GError **err);
  73. /*
  74. * Common section handlers
  75. */
  76. static gboolean
  77. rspamd_rcl_logging_handler (rspamd_mempool_t *pool, const ucl_object_t *obj,
  78. const gchar *key, gpointer ud, struct rspamd_rcl_section *section,
  79. GError **err)
  80. {
  81. const ucl_object_t *val;
  82. const gchar *facility, *log_type, *log_level;
  83. struct rspamd_config *cfg = ud;
  84. val = ucl_object_find_key (obj, "type");
  85. if (val != NULL && ucl_object_tostring_safe (val, &log_type)) {
  86. if (g_ascii_strcasecmp (log_type, "file") == 0) {
  87. /* Need to get filename */
  88. val = ucl_object_find_key (obj, "filename");
  89. if (val == NULL || val->type != UCL_STRING) {
  90. g_set_error (err,
  91. CFG_RCL_ERROR,
  92. ENOENT,
  93. "filename attribute must be specified for file logging type");
  94. return FALSE;
  95. }
  96. cfg->log_type = RSPAMD_LOG_FILE;
  97. cfg->log_file = rspamd_mempool_strdup (cfg->cfg_pool,
  98. ucl_object_tostring (val));
  99. }
  100. else if (g_ascii_strcasecmp (log_type, "syslog") == 0) {
  101. /* Need to get facility */
  102. #ifdef HAVE_SYSLOG_H
  103. cfg->log_facility = LOG_DAEMON;
  104. cfg->log_type = RSPAMD_LOG_SYSLOG;
  105. val = ucl_object_find_key (obj, "facility");
  106. if (val != NULL && ucl_object_tostring_safe (val, &facility)) {
  107. if (g_ascii_strcasecmp (facility, "LOG_AUTH") == 0 ||
  108. g_ascii_strcasecmp (facility, "auth") == 0 ) {
  109. cfg->log_facility = LOG_AUTH;
  110. }
  111. else if (g_ascii_strcasecmp (facility, "LOG_CRON") == 0 ||
  112. g_ascii_strcasecmp (facility, "cron") == 0 ) {
  113. cfg->log_facility = LOG_CRON;
  114. }
  115. else if (g_ascii_strcasecmp (facility, "LOG_DAEMON") == 0 ||
  116. g_ascii_strcasecmp (facility, "daemon") == 0 ) {
  117. cfg->log_facility = LOG_DAEMON;
  118. }
  119. else if (g_ascii_strcasecmp (facility, "LOG_MAIL") == 0 ||
  120. g_ascii_strcasecmp (facility, "mail") == 0) {
  121. cfg->log_facility = LOG_MAIL;
  122. }
  123. else if (g_ascii_strcasecmp (facility, "LOG_USER") == 0 ||
  124. g_ascii_strcasecmp (facility, "user") == 0 ) {
  125. cfg->log_facility = LOG_USER;
  126. }
  127. else if (g_ascii_strcasecmp (facility, "LOG_LOCAL0") == 0 ||
  128. g_ascii_strcasecmp (facility, "local0") == 0) {
  129. cfg->log_facility = LOG_LOCAL0;
  130. }
  131. else if (g_ascii_strcasecmp (facility, "LOG_LOCAL1") == 0 ||
  132. g_ascii_strcasecmp (facility, "local1") == 0) {
  133. cfg->log_facility = LOG_LOCAL1;
  134. }
  135. else if (g_ascii_strcasecmp (facility, "LOG_LOCAL2") == 0 ||
  136. g_ascii_strcasecmp (facility, "local2") == 0) {
  137. cfg->log_facility = LOG_LOCAL2;
  138. }
  139. else if (g_ascii_strcasecmp (facility, "LOG_LOCAL3") == 0 ||
  140. g_ascii_strcasecmp (facility, "local3") == 0) {
  141. cfg->log_facility = LOG_LOCAL3;
  142. }
  143. else if (g_ascii_strcasecmp (facility, "LOG_LOCAL4") == 0 ||
  144. g_ascii_strcasecmp (facility, "local4") == 0) {
  145. cfg->log_facility = LOG_LOCAL4;
  146. }
  147. else if (g_ascii_strcasecmp (facility, "LOG_LOCAL5") == 0 ||
  148. g_ascii_strcasecmp (facility, "local5") == 0) {
  149. cfg->log_facility = LOG_LOCAL5;
  150. }
  151. else if (g_ascii_strcasecmp (facility, "LOG_LOCAL6") == 0 ||
  152. g_ascii_strcasecmp (facility, "local6") == 0) {
  153. cfg->log_facility = LOG_LOCAL6;
  154. }
  155. else if (g_ascii_strcasecmp (facility, "LOG_LOCAL7") == 0 ||
  156. g_ascii_strcasecmp (facility, "local7") == 0) {
  157. cfg->log_facility = LOG_LOCAL7;
  158. }
  159. else {
  160. g_set_error (err,
  161. CFG_RCL_ERROR,
  162. EINVAL,
  163. "invalid log facility: %s",
  164. facility);
  165. return FALSE;
  166. }
  167. }
  168. #endif
  169. }
  170. else if (g_ascii_strcasecmp (log_type,
  171. "stderr") == 0 || g_ascii_strcasecmp (log_type, "console") == 0) {
  172. cfg->log_type = RSPAMD_LOG_CONSOLE;
  173. }
  174. else {
  175. g_set_error (err,
  176. CFG_RCL_ERROR,
  177. EINVAL,
  178. "invalid log type: %s",
  179. log_type);
  180. return FALSE;
  181. }
  182. }
  183. else {
  184. /* No type specified */
  185. msg_warn_config (
  186. "logging type is not specified correctly, log output to the console");
  187. }
  188. /* Handle log level */
  189. val = ucl_object_find_key (obj, "level");
  190. if (val != NULL && ucl_object_tostring_safe (val, &log_level)) {
  191. if (g_ascii_strcasecmp (log_level, "error") == 0) {
  192. cfg->log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL;
  193. }
  194. else if (g_ascii_strcasecmp (log_level, "warning") == 0) {
  195. cfg->log_level = G_LOG_LEVEL_WARNING;
  196. }
  197. else if (g_ascii_strcasecmp (log_level, "info") == 0) {
  198. cfg->log_level = G_LOG_LEVEL_INFO | G_LOG_LEVEL_MESSAGE;
  199. }
  200. else if (g_ascii_strcasecmp (log_level, "debug") == 0) {
  201. cfg->log_level = G_LOG_LEVEL_DEBUG;
  202. }
  203. else {
  204. g_set_error (err,
  205. CFG_RCL_ERROR,
  206. EINVAL,
  207. "invalid log level: %s",
  208. log_level);
  209. return FALSE;
  210. }
  211. }
  212. return rspamd_rcl_section_parse_defaults (section, cfg->cfg_pool, obj,
  213. cfg, err);
  214. }
  215. static gboolean
  216. rspamd_rcl_options_handler (rspamd_mempool_t *pool, const ucl_object_t *obj,
  217. const gchar *key, gpointer ud,
  218. struct rspamd_rcl_section *section, GError **err)
  219. {
  220. const ucl_object_t *dns, *upstream;
  221. struct rspamd_config *cfg = ud;
  222. struct rspamd_rcl_section *dns_section, *upstream_section;
  223. HASH_FIND_STR (section->subsections, "dns", dns_section);
  224. dns = ucl_object_find_key (obj, "dns");
  225. if (dns_section != NULL && dns != NULL) {
  226. if (!rspamd_rcl_section_parse_defaults (dns_section, cfg->cfg_pool, dns,
  227. cfg, err)) {
  228. return FALSE;
  229. }
  230. }
  231. HASH_FIND_STR (section->subsections, "upstream", upstream_section);
  232. upstream = ucl_object_find_key (obj, "upstream");
  233. if (upstream_section != NULL && upstream != NULL) {
  234. if (!rspamd_rcl_section_parse_defaults (upstream_section, cfg->cfg_pool,
  235. upstream, cfg, err)) {
  236. return FALSE;
  237. }
  238. }
  239. return rspamd_rcl_section_parse_defaults (section, cfg->cfg_pool, obj,
  240. cfg, err);
  241. }
  242. struct rspamd_rcl_symbol_data {
  243. struct metric *metric;
  244. struct rspamd_symbols_group *gr;
  245. struct rspamd_config *cfg;
  246. };
  247. static gboolean
  248. rspamd_rcl_group_handler (rspamd_mempool_t *pool, const ucl_object_t *obj,
  249. const gchar *key, gpointer ud,
  250. struct rspamd_rcl_section *section, GError **err)
  251. {
  252. struct rspamd_rcl_symbol_data *sd = ud;
  253. struct metric *metric;
  254. struct rspamd_symbols_group *gr;
  255. const ucl_object_t *val, *cur;
  256. struct rspamd_rcl_section *subsection;
  257. g_assert (key != NULL);
  258. metric = sd->metric;
  259. gr = g_hash_table_lookup (metric->groups, key);
  260. if (gr == NULL) {
  261. gr = rspamd_config_new_group (sd->cfg, metric, key);
  262. }
  263. if (!rspamd_rcl_section_parse_defaults (section, pool, obj,
  264. gr, err)) {
  265. return FALSE;
  266. }
  267. sd->gr = gr;
  268. /* Handle symbols */
  269. val = ucl_object_find_key (obj, "symbol");
  270. if (val != NULL && ucl_object_type (val) == UCL_OBJECT) {
  271. HASH_FIND_STR (section->subsections, "symbol", subsection);
  272. g_assert (subsection != NULL);
  273. LL_FOREACH (val, cur) {
  274. if (!rspamd_rcl_process_section (subsection, sd, cur,
  275. pool, err)) {
  276. return FALSE;
  277. }
  278. }
  279. }
  280. return TRUE;
  281. }
  282. static gboolean
  283. rspamd_rcl_symbol_handler (rspamd_mempool_t *pool, const ucl_object_t *obj,
  284. const gchar *key, gpointer ud,
  285. struct rspamd_rcl_section *section, GError **err)
  286. {
  287. struct rspamd_rcl_symbol_data *sd = ud;
  288. struct rspamd_symbol_def *sym_def;
  289. struct metric *metric;
  290. struct rspamd_config *cfg;
  291. const ucl_object_t *elt;
  292. GList *metric_list;
  293. g_assert (key != NULL);
  294. metric = sd->metric;
  295. g_assert (metric != NULL);
  296. cfg = sd->cfg;
  297. sym_def = g_hash_table_lookup (metric->symbols, key);
  298. if (sym_def == NULL) {
  299. sym_def = rspamd_mempool_alloc0 (pool, sizeof (*sym_def));
  300. sym_def->name = rspamd_mempool_strdup (pool, key);
  301. sym_def->gr = sd->gr;
  302. sym_def->weight_ptr = rspamd_mempool_alloc (pool, sizeof (gdouble));
  303. g_hash_table_insert (metric->symbols, sym_def->name, sym_def);
  304. if (sd->gr) {
  305. g_hash_table_insert (sd->gr->symbols, sym_def->name, sym_def);
  306. }
  307. if ((metric_list =
  308. g_hash_table_lookup (cfg->metrics_symbols, sym_def->name)) == NULL) {
  309. metric_list = g_list_prepend (NULL, metric);
  310. rspamd_mempool_add_destructor (cfg->cfg_pool,
  311. (rspamd_mempool_destruct_t)g_list_free,
  312. metric_list);
  313. g_hash_table_insert (cfg->metrics_symbols, sym_def->name, metric_list);
  314. }
  315. else {
  316. if (!g_list_find (metric_list, metric)) {
  317. metric_list = g_list_append (metric_list, metric);
  318. }
  319. }
  320. }
  321. else {
  322. msg_warn_config ("redefining symbol '%s' in metric '%s'", key, metric->name);
  323. }
  324. if ((elt = ucl_object_find_key (obj, "one_shot")) != NULL) {
  325. if (ucl_object_toboolean (elt)) {
  326. sym_def->flags |= RSPAMD_SYMBOL_FLAG_ONESHOT;
  327. }
  328. }
  329. if ((elt = ucl_object_find_key (obj, "ignore")) != NULL) {
  330. if (ucl_object_toboolean (elt)) {
  331. sym_def->flags |= RSPAMD_SYMBOL_FLAG_IGNORE;
  332. }
  333. }
  334. if (!rspamd_rcl_section_parse_defaults (section, pool, obj,
  335. sym_def, err)) {
  336. return FALSE;
  337. }
  338. if (ucl_object_find_any_key (obj, "score", "weight", NULL) != NULL) {
  339. *sym_def->weight_ptr = sym_def->score;
  340. }
  341. return TRUE;
  342. }
  343. static gboolean
  344. rspamd_rcl_actions_handler (rspamd_mempool_t *pool, const ucl_object_t *obj,
  345. const gchar *key, gpointer ud,
  346. struct rspamd_rcl_section *section, GError **err)
  347. {
  348. gdouble action_score;
  349. struct metric_action *action;
  350. struct metric *metric = ud;
  351. gint action_value;
  352. const ucl_object_t *cur;
  353. ucl_object_iter_t it = NULL;
  354. while ((cur = ucl_iterate_object (obj, &it, true)) != NULL) {
  355. if (!rspamd_action_from_str (ucl_object_key (cur), &action_value) ||
  356. !ucl_object_todouble_safe (cur, &action_score)) {
  357. g_set_error (err,
  358. CFG_RCL_ERROR,
  359. EINVAL,
  360. "invalid action definition: '%s'",
  361. ucl_object_key (cur));
  362. return FALSE;
  363. }
  364. else {
  365. action = &metric->actions[action_value];
  366. action->action = action_value;
  367. action->score = action_score;
  368. }
  369. }
  370. return TRUE;
  371. }
  372. static gboolean
  373. rspamd_rcl_metric_handler (rspamd_mempool_t *pool, const ucl_object_t *obj,
  374. const gchar *key, gpointer ud,
  375. struct rspamd_rcl_section *section, GError **err)
  376. {
  377. const ucl_object_t *val, *cur, *elt;
  378. ucl_object_iter_t it;
  379. struct rspamd_config *cfg = ud;
  380. struct metric *metric;
  381. struct rspamd_rcl_section *subsection;
  382. struct rspamd_rcl_symbol_data sd;
  383. struct rspamd_symbol_def *sym_def;
  384. g_assert (key != NULL);
  385. metric = g_hash_table_lookup (cfg->metrics, key);
  386. if (metric == NULL) {
  387. metric = rspamd_config_new_metric (cfg, metric, key);
  388. }
  389. if (!rspamd_rcl_section_parse_defaults (section, cfg->cfg_pool, obj,
  390. metric, err)) {
  391. return FALSE;
  392. }
  393. if (metric->unknown_weight > 0) {
  394. metric->accept_unknown_symbols = TRUE;
  395. }
  396. /* Handle actions */
  397. val = ucl_object_find_key (obj, "actions");
  398. if (val != NULL) {
  399. if (val->type != UCL_OBJECT) {
  400. g_set_error (err, CFG_RCL_ERROR, EINVAL,
  401. "actions must be an object");
  402. return FALSE;
  403. }
  404. HASH_FIND_STR (section->subsections, "actions", subsection);
  405. g_assert (subsection != NULL);
  406. if (!rspamd_rcl_process_section (subsection, metric, val,
  407. cfg->cfg_pool, err)) {
  408. return FALSE;
  409. }
  410. }
  411. /* No more legacy mode */
  412. /* Handle grouped symbols */
  413. val = ucl_object_find_key (obj, "group");
  414. if (val != NULL && ucl_object_type (val) == UCL_OBJECT) {
  415. HASH_FIND_STR (section->subsections, "group", subsection);
  416. g_assert (subsection != NULL);
  417. sd.gr = NULL;
  418. sd.cfg = cfg;
  419. sd.metric = metric;
  420. LL_FOREACH (val, cur) {
  421. if (!rspamd_rcl_process_section (subsection, &sd, cur,
  422. cfg->cfg_pool, err)) {
  423. return FALSE;
  424. }
  425. }
  426. }
  427. /* Handle symbols */
  428. val = ucl_object_find_key (obj, "symbol");
  429. if (val != NULL && ucl_object_type (val) == UCL_OBJECT) {
  430. HASH_FIND_STR (section->subsections, "symbol", subsection);
  431. g_assert (subsection != NULL);
  432. sd.gr = NULL;
  433. sd.cfg = cfg;
  434. sd.metric = metric;
  435. LL_FOREACH (val, cur) {
  436. if (!rspamd_rcl_process_section (subsection, &sd, cur,
  437. cfg->cfg_pool, err)) {
  438. return FALSE;
  439. }
  440. }
  441. }
  442. /* Handle ignored symbols */
  443. val = ucl_object_find_key (obj, "ignore");
  444. if (val != NULL && ucl_object_type (val) == UCL_ARRAY) {
  445. LL_FOREACH (val, cur) {
  446. it = NULL;
  447. while ((elt = ucl_iterate_object (cur, &it, true)) != NULL) {
  448. if (ucl_object_type (elt) == UCL_STRING) {
  449. sym_def = g_hash_table_lookup (metric->symbols,
  450. ucl_object_tostring (elt));
  451. if (sym_def != NULL) {
  452. sym_def->flags |= RSPAMD_SYMBOL_FLAG_IGNORE;
  453. }
  454. else {
  455. msg_warn ("cannot find symbol %s to set ignore flag",
  456. ucl_object_tostring (elt));
  457. }
  458. }
  459. }
  460. }
  461. }
  462. return TRUE;
  463. }
  464. static gboolean
  465. rspamd_rcl_worker_handler (rspamd_mempool_t *pool, const ucl_object_t *obj,
  466. const gchar *key, gpointer ud,
  467. struct rspamd_rcl_section *section, GError **err)
  468. {
  469. const ucl_object_t *val, *cur, *cur_obj;
  470. ucl_object_t *robj;
  471. ucl_object_iter_t it = NULL;
  472. const gchar *worker_type, *worker_bind;
  473. struct rspamd_config *cfg = ud;
  474. GQuark qtype;
  475. struct rspamd_worker_conf *wrk;
  476. struct rspamd_worker_cfg_parser *wparser;
  477. struct rspamd_worker_param_parser *whandler;
  478. struct rspamd_worker_param_key srch;
  479. g_assert (key != NULL);
  480. worker_type = key;
  481. qtype = g_quark_try_string (worker_type);
  482. if (qtype != 0) {
  483. wrk = rspamd_config_new_worker (cfg, NULL);
  484. wrk->worker = rspamd_get_worker_by_type (cfg, qtype);
  485. if (wrk->worker == NULL) {
  486. g_set_error (err,
  487. CFG_RCL_ERROR,
  488. EINVAL,
  489. "unknown worker type: %s",
  490. worker_type);
  491. return FALSE;
  492. }
  493. wrk->type = qtype;
  494. if (wrk->worker->worker_init_func) {
  495. wrk->ctx = wrk->worker->worker_init_func (cfg);
  496. }
  497. }
  498. else {
  499. msg_err_config ("unknown worker type: %s", worker_type);
  500. return TRUE;
  501. }
  502. val = ucl_object_find_key (obj, "bind_socket");
  503. /* This name is more logical */
  504. if (val == NULL) {
  505. val = ucl_object_find_key (obj, "listen");
  506. }
  507. if (val != NULL) {
  508. it = ucl_object_iterate_new (val);
  509. while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
  510. if (!ucl_object_tostring_safe (cur, &worker_bind)) {
  511. continue;
  512. }
  513. if (!rspamd_parse_bind_line (cfg, wrk, worker_bind)) {
  514. g_set_error (err,
  515. CFG_RCL_ERROR,
  516. EINVAL,
  517. "cannot parse bind line: %s",
  518. worker_bind);
  519. ucl_object_iterate_free (it);
  520. return FALSE;
  521. }
  522. }
  523. ucl_object_iterate_free (it);
  524. }
  525. wrk->options = (ucl_object_t *)obj;
  526. if (!rspamd_rcl_section_parse_defaults (section, cfg->cfg_pool, obj,
  527. wrk, err)) {
  528. return FALSE;
  529. }
  530. /* Parse other attributes */
  531. wparser = g_hash_table_lookup (cfg->wrk_parsers, &qtype);
  532. if (wparser != NULL && obj->type == UCL_OBJECT) {
  533. it = NULL;
  534. while ((cur = ucl_iterate_object (obj, &it, true)) != NULL) {
  535. srch.name = ucl_object_key (cur);
  536. srch.ptr = wrk->ctx; /* XXX: is it valid? */
  537. whandler = g_hash_table_lookup (wparser->parsers, &srch);
  538. if (whandler != NULL) {
  539. LL_FOREACH (cur, cur_obj) {
  540. if (!whandler->handler (cfg->cfg_pool,
  541. cur_obj,
  542. &whandler->parser,
  543. section,
  544. err)) {
  545. return FALSE;
  546. }
  547. if (!(whandler->parser.flags & RSPAMD_CL_FLAG_MULTIPLE)) {
  548. break;
  549. }
  550. }
  551. }
  552. }
  553. if (wparser->def_obj_parser != NULL) {
  554. robj = ucl_object_ref (obj);
  555. if (!wparser->def_obj_parser (robj, wparser->def_ud)) {
  556. ucl_object_unref (robj);
  557. return FALSE;
  558. }
  559. ucl_object_unref (robj);
  560. }
  561. }
  562. cfg->workers = g_list_prepend (cfg->workers, wrk);
  563. return TRUE;
  564. }
  565. #define RSPAMD_CONFDIR_INDEX "CONFDIR"
  566. #define RSPAMD_RUNDIR_INDEX "RUNDIR"
  567. #define RSPAMD_DBDIR_INDEX "DBDIR"
  568. #define RSPAMD_LOGDIR_INDEX "LOGDIR"
  569. #define RSPAMD_PLUGINSDIR_INDEX "PLUGINSDIR"
  570. #define RSPAMD_RULESDIR_INDEX "RULESDIR"
  571. #define RSPAMD_WWWDIR_INDEX "WWWDIR"
  572. #define RSPAMD_PREFIX_INDEX "PREFIX"
  573. #define RSPAMD_VERSION_INDEX "VERSION"
  574. static void
  575. rspamd_rcl_set_lua_globals (struct rspamd_config *cfg, lua_State *L,
  576. GHashTable *vars)
  577. {
  578. struct rspamd_config **pcfg;
  579. GHashTableIter it;
  580. gpointer k, v;
  581. /* First check for global variable 'config' */
  582. lua_getglobal (L, "config");
  583. if (lua_isnil (L, -1)) {
  584. /* Assign global table to set up attributes */
  585. lua_newtable (L);
  586. lua_setglobal (L, "config");
  587. }
  588. lua_getglobal (L, "metrics");
  589. if (lua_isnil (L, -1)) {
  590. lua_newtable (L);
  591. lua_setglobal (L, "metrics");
  592. }
  593. lua_getglobal (L, "composites");
  594. if (lua_isnil (L, -1)) {
  595. lua_newtable (L);
  596. lua_setglobal (L, "composites");
  597. }
  598. lua_getglobal (L, "classifiers");
  599. if (lua_isnil (L, -1)) {
  600. lua_newtable (L);
  601. lua_setglobal (L, "classifiers");
  602. }
  603. pcfg = lua_newuserdata (L, sizeof (struct rspamd_config *));
  604. rspamd_lua_setclass (L, "rspamd{config}", -1);
  605. *pcfg = cfg;
  606. lua_setglobal (L, "rspamd_config");
  607. /* Clear stack from globals */
  608. lua_pop (L, 4);
  609. rspamd_lua_set_path (L, cfg);
  610. /* Set known paths as rspamd_paths global */
  611. lua_getglobal (L, "rspamd_paths");
  612. if (lua_isnil (L, -1)) {
  613. lua_newtable (L);
  614. rspamd_lua_table_set (L, RSPAMD_CONFDIR_INDEX, RSPAMD_CONFDIR);
  615. rspamd_lua_table_set (L, RSPAMD_RUNDIR_INDEX, RSPAMD_RUNDIR);
  616. rspamd_lua_table_set (L, RSPAMD_DBDIR_INDEX, RSPAMD_DBDIR);
  617. rspamd_lua_table_set (L, RSPAMD_LOGDIR_INDEX, RSPAMD_LOGDIR);
  618. rspamd_lua_table_set (L, RSPAMD_WWWDIR_INDEX, RSPAMD_WWWDIR);
  619. rspamd_lua_table_set (L, RSPAMD_PLUGINSDIR_INDEX, RSPAMD_PLUGINSDIR);
  620. rspamd_lua_table_set (L, RSPAMD_RULESDIR_INDEX, RSPAMD_RULESDIR);
  621. rspamd_lua_table_set (L, RSPAMD_PREFIX_INDEX, RSPAMD_PREFIX);
  622. /* Override from vars if needed */
  623. if (vars != NULL) {
  624. g_hash_table_iter_init (&it, vars);
  625. while (g_hash_table_iter_next (&it, &k, &v)) {
  626. rspamd_lua_table_set (L, k, v);
  627. }
  628. }
  629. lua_setglobal (L, "rspamd_paths");
  630. }
  631. }
  632. static gboolean
  633. rspamd_rcl_lua_handler (rspamd_mempool_t *pool, const ucl_object_t *obj,
  634. const gchar *key, gpointer ud,
  635. struct rspamd_rcl_section *section, GError **err)
  636. {
  637. struct rspamd_config *cfg = ud;
  638. const gchar *lua_src = rspamd_mempool_strdup (pool,
  639. ucl_object_tostring (obj));
  640. gchar *cur_dir, *lua_dir, *lua_file, *tmp1, *tmp2;
  641. lua_State *L = cfg->lua_state;
  642. tmp1 = g_strdup (lua_src);
  643. tmp2 = g_strdup (lua_src);
  644. lua_dir = dirname (tmp1);
  645. lua_file = basename (tmp2);
  646. if (lua_dir && lua_file) {
  647. cur_dir = g_malloc (PATH_MAX);
  648. if (getcwd (cur_dir, PATH_MAX) != NULL && chdir (lua_dir) != -1) {
  649. /* Load file */
  650. if (luaL_loadfile (L, lua_file) != 0) {
  651. g_set_error (err,
  652. CFG_RCL_ERROR,
  653. EINVAL,
  654. "cannot load lua file %s: %s",
  655. lua_src,
  656. lua_tostring (L, -1));
  657. if (chdir (cur_dir) == -1) {
  658. msg_err_config ("cannot chdir to %s: %s", cur_dir,
  659. strerror (errno));
  660. }
  661. g_free (cur_dir);
  662. g_free (tmp1);
  663. g_free (tmp2);
  664. return FALSE;
  665. }
  666. /* Now do it */
  667. if (lua_pcall (L, 0, LUA_MULTRET, 0) != 0) {
  668. g_set_error (err,
  669. CFG_RCL_ERROR,
  670. EINVAL,
  671. "cannot init lua file %s: %s",
  672. lua_src,
  673. lua_tostring (L, -1));
  674. if (chdir (cur_dir) == -1) {
  675. msg_err_config ("cannot chdir to %s: %s", cur_dir,
  676. strerror (errno));
  677. }
  678. g_free (cur_dir);
  679. g_free (tmp1);
  680. g_free (tmp2);
  681. return FALSE;
  682. }
  683. }
  684. else {
  685. g_set_error (err, CFG_RCL_ERROR, ENOENT, "cannot chdir to %s: %s",
  686. lua_src, strerror (errno));
  687. if (chdir (cur_dir) == -1) {
  688. msg_err_config ("cannot chdir to %s: %s", cur_dir, strerror (errno));
  689. }
  690. g_free (cur_dir);
  691. g_free (tmp1);
  692. g_free (tmp2);
  693. return FALSE;
  694. }
  695. if (chdir (cur_dir) == -1) {
  696. msg_err_config ("cannot chdir to %s: %s", cur_dir, strerror (errno));
  697. }
  698. g_free (cur_dir);
  699. g_free (tmp1);
  700. g_free (tmp2);
  701. }
  702. else {
  703. g_free (tmp1);
  704. g_free (tmp2);
  705. g_set_error (err, CFG_RCL_ERROR, ENOENT, "cannot find to %s: %s",
  706. lua_src, strerror (errno));
  707. return FALSE;
  708. }
  709. return TRUE;
  710. }
  711. static gboolean
  712. rspamd_rcl_add_module_path (struct rspamd_config *cfg,
  713. const gchar *path,
  714. GError **err)
  715. {
  716. struct stat st;
  717. struct script_module *cur_mod;
  718. glob_t globbuf;
  719. gchar *pattern, *ext_pos;
  720. size_t len;
  721. guint i;
  722. if (stat (path, &st) == -1) {
  723. g_set_error (err,
  724. CFG_RCL_ERROR,
  725. errno,
  726. "cannot stat path %s, %s",
  727. path,
  728. strerror (errno));
  729. return FALSE;
  730. }
  731. /* Handle directory */
  732. if (S_ISDIR (st.st_mode)) {
  733. globbuf.gl_offs = 0;
  734. len = strlen (path) + sizeof ("*.lua");
  735. pattern = g_malloc (len);
  736. rspamd_snprintf (pattern, len, "%s%s", path, "*.lua");
  737. if (glob (pattern, GLOB_DOOFFS, NULL, &globbuf) == 0) {
  738. for (i = 0; i < globbuf.gl_pathc; i++) {
  739. cur_mod =
  740. rspamd_mempool_alloc (cfg->cfg_pool,
  741. sizeof (struct script_module));
  742. cur_mod->path = rspamd_mempool_strdup (cfg->cfg_pool,
  743. globbuf.gl_pathv[i]);
  744. cur_mod->name = g_path_get_basename (cur_mod->path);
  745. rspamd_mempool_add_destructor (cfg->cfg_pool, g_free,
  746. cur_mod->name);
  747. ext_pos = strstr (cur_mod->name, ".lua");
  748. if (ext_pos != NULL) {
  749. *ext_pos = '\0';
  750. }
  751. cfg->script_modules = g_list_prepend (cfg->script_modules,
  752. cur_mod);
  753. }
  754. globfree (&globbuf);
  755. g_free (pattern);
  756. }
  757. else {
  758. g_set_error (err,
  759. CFG_RCL_ERROR,
  760. errno,
  761. "glob failed for %s, %s",
  762. pattern,
  763. strerror (errno));
  764. g_free (pattern);
  765. return FALSE;
  766. }
  767. }
  768. else {
  769. /* Handle single file */
  770. cur_mod =
  771. rspamd_mempool_alloc (cfg->cfg_pool, sizeof (struct script_module));
  772. cur_mod->path = rspamd_mempool_strdup (cfg->cfg_pool, path);
  773. cur_mod->name = g_path_get_basename (cur_mod->path);
  774. rspamd_mempool_add_destructor (cfg->cfg_pool, g_free,
  775. cur_mod->name);
  776. ext_pos = strstr (cur_mod->name, ".lua");
  777. if (ext_pos != NULL) {
  778. *ext_pos = '\0';
  779. }
  780. cfg->script_modules = g_list_prepend (cfg->script_modules, cur_mod);
  781. }
  782. return TRUE;
  783. }
  784. static gboolean
  785. rspamd_rcl_modules_handler (rspamd_mempool_t *pool, const ucl_object_t *obj,
  786. const gchar *key, gpointer ud,
  787. struct rspamd_rcl_section *section, GError **err)
  788. {
  789. const ucl_object_t *val, *cur;
  790. struct rspamd_config *cfg = ud;
  791. const gchar *data;
  792. if (obj->type == UCL_OBJECT) {
  793. val = ucl_object_find_key (obj, "path");
  794. LL_FOREACH (val, cur)
  795. {
  796. if (ucl_object_tostring_safe (cur, &data)) {
  797. if (!rspamd_rcl_add_module_path (cfg,
  798. rspamd_mempool_strdup (cfg->cfg_pool, data), err)) {
  799. return FALSE;
  800. }
  801. }
  802. }
  803. }
  804. else if (ucl_object_tostring_safe (obj, &data)) {
  805. if (!rspamd_rcl_add_module_path (cfg,
  806. rspamd_mempool_strdup (cfg->cfg_pool, data), err)) {
  807. return FALSE;
  808. }
  809. }
  810. else {
  811. g_set_error (err,
  812. CFG_RCL_ERROR,
  813. EINVAL,
  814. "module parameter has wrong type (must be an object or a string)");
  815. return FALSE;
  816. }
  817. return TRUE;
  818. }
  819. struct statfile_parser_data {
  820. struct rspamd_config *cfg;
  821. struct rspamd_classifier_config *ccf;
  822. };
  823. static gboolean
  824. rspamd_rcl_statfile_handler (rspamd_mempool_t *pool, const ucl_object_t *obj,
  825. const gchar *key, gpointer ud,
  826. struct rspamd_rcl_section *section, GError **err)
  827. {
  828. struct statfile_parser_data *stud = ud;
  829. struct rspamd_classifier_config *ccf;
  830. struct rspamd_config *cfg;
  831. const ucl_object_t *val;
  832. struct rspamd_statfile_config *st;
  833. GList *labels;
  834. g_assert (key != NULL);
  835. cfg = stud->cfg;
  836. ccf = stud->ccf;
  837. st = rspamd_config_new_statfile (cfg, NULL);
  838. st->symbol = rspamd_mempool_strdup (cfg->cfg_pool, key);
  839. if (rspamd_rcl_section_parse_defaults (section, pool, obj, st, err)) {
  840. ccf->statfiles = g_list_prepend (ccf->statfiles, st);
  841. if (st->label != NULL) {
  842. labels = g_hash_table_lookup (ccf->labels, st->label);
  843. if (labels != NULL) {
  844. labels = g_list_append (labels, st);
  845. }
  846. else {
  847. g_hash_table_insert (ccf->labels, st->label,
  848. g_list_prepend (NULL, st));
  849. }
  850. }
  851. if (st->symbol != NULL) {
  852. g_hash_table_insert (cfg->classifiers_symbols, st->symbol, st);
  853. }
  854. else {
  855. g_set_error (err,
  856. CFG_RCL_ERROR,
  857. EINVAL,
  858. "statfile must have a symbol defined");
  859. return FALSE;
  860. }
  861. st->opts = (ucl_object_t *)obj;
  862. st->clcf = ccf;
  863. val = ucl_object_find_key (obj, "spam");
  864. if (val == NULL) {
  865. msg_info_config (
  866. "statfile %s has no explicit 'spam' setting, trying to guess by symbol",
  867. st->symbol);
  868. if (rspamd_strncasestr (st->symbol, "spam",
  869. strlen (st->symbol)) != NULL) {
  870. st->is_spam = TRUE;
  871. }
  872. else if (rspamd_strncasestr (st->symbol, "ham",
  873. strlen (st->symbol)) != NULL) {
  874. st->is_spam = FALSE;
  875. }
  876. else {
  877. g_set_error (err,
  878. CFG_RCL_ERROR,
  879. EINVAL,
  880. "cannot guess spam setting from %s",
  881. st->symbol);
  882. return FALSE;
  883. }
  884. msg_info_config ("guessed that statfile with symbol %s is %s",
  885. st->symbol,
  886. st->is_spam ?
  887. "spam" : "ham");
  888. }
  889. return TRUE;
  890. }
  891. return FALSE;
  892. }
  893. static gboolean
  894. rspamd_rcl_classifier_handler (rspamd_mempool_t *pool,
  895. const ucl_object_t *obj,
  896. const gchar *key,
  897. gpointer ud,
  898. struct rspamd_rcl_section *section,
  899. GError **err)
  900. {
  901. const ucl_object_t *val, *cur;
  902. ucl_object_iter_t it = NULL;
  903. struct rspamd_config *cfg = ud;
  904. struct statfile_parser_data stud;
  905. const gchar *st_key;
  906. struct rspamd_classifier_config *ccf;
  907. gboolean res = TRUE;
  908. struct rspamd_rcl_section *stat_section;
  909. struct rspamd_tokenizer_config *tkcf = NULL;
  910. g_assert (key != NULL);
  911. ccf = rspamd_config_new_classifier (cfg, NULL);
  912. ccf->classifier = rspamd_mempool_strdup (cfg->cfg_pool, key);
  913. if (rspamd_rcl_section_parse_defaults (section, cfg->cfg_pool, obj,
  914. ccf, err)) {
  915. HASH_FIND_STR (section->subsections, "statfile", stat_section);
  916. if (ccf->classifier == NULL) {
  917. ccf->classifier = "bayes";
  918. }
  919. if (ccf->name == NULL) {
  920. ccf->name = ccf->classifier;
  921. }
  922. while ((val = ucl_iterate_object (obj, &it, true)) != NULL && res) {
  923. st_key = ucl_object_key (val);
  924. if (st_key != NULL) {
  925. if (g_ascii_strcasecmp (st_key, "statfile") == 0) {
  926. LL_FOREACH (val, cur) {
  927. stud.cfg = cfg;
  928. stud.ccf = ccf;
  929. res = rspamd_rcl_process_section (stat_section, &stud,
  930. cur, cfg->cfg_pool, err);
  931. if (!res) {
  932. return FALSE;
  933. }
  934. }
  935. }
  936. else if (g_ascii_strcasecmp (st_key, "tokenizer") == 0) {
  937. tkcf = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*tkcf));
  938. if (ucl_object_type (val) == UCL_STRING) {
  939. tkcf->name = ucl_object_tostring (val);
  940. }
  941. else if (ucl_object_type (val) == UCL_OBJECT) {
  942. cur = ucl_object_find_key (val, "name");
  943. if (cur != NULL) {
  944. tkcf->name = ucl_object_tostring (cur);
  945. tkcf->opts = val;
  946. }
  947. else {
  948. cur = ucl_object_find_key (val, "type");
  949. if (cur != NULL) {
  950. tkcf->name = ucl_object_tostring (cur);
  951. tkcf->opts = val;
  952. }
  953. }
  954. }
  955. }
  956. }
  957. }
  958. }
  959. else {
  960. msg_err_config ("fatal configuration error, cannot parse statfile definition");
  961. }
  962. if (tkcf == NULL) {
  963. tkcf = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*tkcf));
  964. tkcf->name = NULL;
  965. }
  966. ccf->tokenizer = tkcf;
  967. ccf->opts = (ucl_object_t *)obj;
  968. cfg->classifiers = g_list_prepend (cfg->classifiers, ccf);
  969. return res;
  970. }
  971. static gboolean
  972. rspamd_rcl_composite_handler (rspamd_mempool_t *pool,
  973. const ucl_object_t *obj,
  974. const gchar *key,
  975. gpointer ud,
  976. struct rspamd_rcl_section *section,
  977. GError **err)
  978. {
  979. const ucl_object_t *val;
  980. struct rspamd_expression *expr;
  981. struct rspamd_config *cfg = ud;
  982. struct rspamd_composite *composite;
  983. const gchar *composite_name, *composite_expression, *group, *metric,
  984. *description;
  985. gdouble score;
  986. gboolean new = TRUE;
  987. g_assert (key != NULL);
  988. composite_name = key;
  989. if (g_hash_table_lookup (cfg->composite_symbols, composite_name) != NULL) {
  990. msg_warn_config ("composite %s is redefined", composite_name);
  991. new = FALSE;
  992. }
  993. val = ucl_object_find_key (obj, "expression");
  994. if (val == NULL || !ucl_object_tostring_safe (val, &composite_expression)) {
  995. g_set_error (err,
  996. CFG_RCL_ERROR,
  997. EINVAL,
  998. "composite must have an expression defined");
  999. return FALSE;
  1000. }
  1001. if (!rspamd_parse_expression (composite_expression, 0, &composite_expr_subr,
  1002. NULL, cfg->cfg_pool, err, &expr)) {
  1003. if (err && *err) {
  1004. msg_err_config ("cannot parse composite expression for %s: %e",
  1005. composite_name, *err);
  1006. }
  1007. else {
  1008. msg_err_config ("cannot parse composite expression for %s: unknown error",
  1009. composite_name);
  1010. }
  1011. return FALSE;
  1012. }
  1013. composite =
  1014. rspamd_mempool_alloc (cfg->cfg_pool, sizeof (struct rspamd_composite));
  1015. composite->expr = expr;
  1016. composite->id = g_hash_table_size (cfg->composite_symbols);
  1017. g_hash_table_insert (cfg->composite_symbols,
  1018. (gpointer)composite_name,
  1019. composite);
  1020. if (new) {
  1021. rspamd_symbols_cache_add_symbol (cfg->cache, composite_name, 0,
  1022. NULL, NULL, SYMBOL_TYPE_COMPOSITE, -1);
  1023. }
  1024. val = ucl_object_find_key (obj, "score");
  1025. if (val != NULL && ucl_object_todouble_safe (val, &score)) {
  1026. /* Also set score in the metric */
  1027. val = ucl_object_find_key (obj, "group");
  1028. if (val != NULL) {
  1029. group = ucl_object_tostring (val);
  1030. }
  1031. else {
  1032. group = "composite";
  1033. }
  1034. val = ucl_object_find_key (obj, "metric");
  1035. if (val != NULL) {
  1036. metric = ucl_object_tostring (val);
  1037. }
  1038. else {
  1039. metric = DEFAULT_METRIC;
  1040. }
  1041. val = ucl_object_find_key (obj, "description");
  1042. if (val != NULL) {
  1043. description = ucl_object_tostring (val);
  1044. }
  1045. else {
  1046. description = composite_expression;
  1047. }
  1048. rspamd_config_add_metric_symbol (cfg, metric, composite_name, score,
  1049. description, group, FALSE, FALSE);
  1050. }
  1051. return TRUE;
  1052. }
  1053. struct rspamd_rcl_section *
  1054. rspamd_rcl_add_section (struct rspamd_rcl_section **top,
  1055. const gchar *name, const gchar *key_attr, rspamd_rcl_handler_t handler,
  1056. enum ucl_type type, gboolean required, gboolean strict_type)
  1057. {
  1058. struct rspamd_rcl_section *new;
  1059. ucl_object_t *parent_doc;
  1060. new = g_slice_alloc0 (sizeof (struct rspamd_rcl_section));
  1061. new->name = name;
  1062. new->key_attr = key_attr;
  1063. new->handler = handler;
  1064. new->type = type;
  1065. new->strict_type = strict_type;
  1066. if (*top == NULL) {
  1067. parent_doc = NULL;
  1068. new->doc_ref = NULL;
  1069. }
  1070. else {
  1071. parent_doc = (*top)->doc_ref;
  1072. new->doc_ref = rspamd_rcl_add_doc_obj (parent_doc,
  1073. NULL,
  1074. name,
  1075. type,
  1076. NULL,
  1077. 0,
  1078. NULL,
  1079. 0);
  1080. }
  1081. HASH_ADD_KEYPTR (hh, *top, new->name, strlen (new->name), new);
  1082. return new;
  1083. }
  1084. struct rspamd_rcl_section *
  1085. rspamd_rcl_add_section_doc (struct rspamd_rcl_section **top,
  1086. const gchar *name, const gchar *key_attr, rspamd_rcl_handler_t handler,
  1087. enum ucl_type type, gboolean required, gboolean strict_type,
  1088. ucl_object_t *doc_target,
  1089. const gchar *doc_string)
  1090. {
  1091. struct rspamd_rcl_section *new;
  1092. new = g_slice_alloc0 (sizeof (struct rspamd_rcl_section));
  1093. new->name = name;
  1094. new->key_attr = key_attr;
  1095. new->handler = handler;
  1096. new->type = type;
  1097. new->strict_type = strict_type;
  1098. new->doc_ref = rspamd_rcl_add_doc_obj (doc_target,
  1099. doc_string,
  1100. name,
  1101. type,
  1102. NULL,
  1103. 0,
  1104. NULL,
  1105. 0);
  1106. HASH_ADD_KEYPTR (hh, *top, new->name, strlen (new->name), new);
  1107. return new;
  1108. }
  1109. struct rspamd_rcl_default_handler_data *
  1110. rspamd_rcl_add_default_handler (struct rspamd_rcl_section *section,
  1111. const gchar *name,
  1112. rspamd_rcl_default_handler_t handler,
  1113. goffset offset,
  1114. gint flags,
  1115. const gchar *doc_string)
  1116. {
  1117. struct rspamd_rcl_default_handler_data *new;
  1118. new = g_slice_alloc0 (sizeof (struct rspamd_rcl_default_handler_data));
  1119. new->key = name;
  1120. new->handler = handler;
  1121. new->pd.offset = offset;
  1122. new->pd.flags = flags;
  1123. if (section->doc_ref != NULL) {
  1124. rspamd_rcl_add_doc_obj (section->doc_ref,
  1125. doc_string,
  1126. name,
  1127. UCL_NULL,
  1128. handler,
  1129. flags,
  1130. NULL,
  1131. 0);
  1132. }
  1133. HASH_ADD_KEYPTR (hh, section->default_parser, new->key, strlen (
  1134. new->key), new);
  1135. return new;
  1136. }
  1137. struct rspamd_rcl_section *
  1138. rspamd_rcl_config_init (struct rspamd_config *cfg)
  1139. {
  1140. struct rspamd_rcl_section *new = NULL, *sub, *ssub, *sssub;
  1141. /*
  1142. * Important notice:
  1143. * the order of parsing is equal to order of this initialization, therefore
  1144. * it is possible to init some portions of config prior to others
  1145. */
  1146. /**
  1147. * Logging section
  1148. */
  1149. sub = rspamd_rcl_add_section_doc (&new,
  1150. "logging", NULL,
  1151. rspamd_rcl_logging_handler,
  1152. UCL_OBJECT,
  1153. FALSE,
  1154. TRUE,
  1155. cfg->doc_strings,
  1156. "Configure rspamd logging");
  1157. /* Default handlers */
  1158. rspamd_rcl_add_default_handler (sub,
  1159. "log_buffer",
  1160. rspamd_rcl_parse_struct_integer,
  1161. G_STRUCT_OFFSET (struct rspamd_config, log_buf_size),
  1162. 0,
  1163. "Size of log buffer in bytes (for file logging)");
  1164. rspamd_rcl_add_default_handler (sub,
  1165. "log_urls",
  1166. rspamd_rcl_parse_struct_boolean,
  1167. G_STRUCT_OFFSET (struct rspamd_config, log_urls),
  1168. 0,
  1169. "Write each URL found in a message to the log file");
  1170. rspamd_rcl_add_default_handler (sub,
  1171. "log_re_cache",
  1172. rspamd_rcl_parse_struct_boolean,
  1173. G_STRUCT_OFFSET (struct rspamd_config, log_re_cache),
  1174. 0,
  1175. "Write statistics of regexp processing to log (useful for hyperscan)");
  1176. rspamd_rcl_add_default_handler (sub,
  1177. "debug_ip",
  1178. rspamd_rcl_parse_struct_string,
  1179. G_STRUCT_OFFSET (struct rspamd_config, debug_ip_map),
  1180. 0,
  1181. "Enable debugging log for the specified IP addresses");
  1182. rspamd_rcl_add_default_handler (sub,
  1183. "debug_symbols",
  1184. rspamd_rcl_parse_struct_string_list,
  1185. G_STRUCT_OFFSET (struct rspamd_config, debug_symbols),
  1186. 0,
  1187. "Enable debug for the specified symbols");
  1188. rspamd_rcl_add_default_handler (sub,
  1189. "log_color",
  1190. rspamd_rcl_parse_struct_boolean,
  1191. G_STRUCT_OFFSET (struct rspamd_config, log_color),
  1192. 0,
  1193. "Enable colored output (for console logging)");
  1194. rspamd_rcl_add_default_handler (sub,
  1195. "color",
  1196. rspamd_rcl_parse_struct_boolean,
  1197. G_STRUCT_OFFSET (struct rspamd_config, log_color),
  1198. 0,
  1199. "Enable colored output (for console logging)");
  1200. rspamd_rcl_add_default_handler (sub,
  1201. "log_systemd",
  1202. rspamd_rcl_parse_struct_boolean,
  1203. G_STRUCT_OFFSET (struct rspamd_config, log_systemd),
  1204. 0,
  1205. "Enable systemd compatible logging");
  1206. rspamd_rcl_add_default_handler (sub,
  1207. "systemd",
  1208. rspamd_rcl_parse_struct_boolean,
  1209. G_STRUCT_OFFSET (struct rspamd_config, log_systemd),
  1210. 0,
  1211. "Enable systemd compatible logging");
  1212. rspamd_rcl_add_default_handler (sub,
  1213. "debug_modules",
  1214. rspamd_rcl_parse_struct_string_list,
  1215. G_STRUCT_OFFSET (struct rspamd_config, debug_modules),
  1216. RSPAMD_CL_FLAG_STRING_LIST_HASH,
  1217. "Enable debugging for the specified modules");
  1218. rspamd_rcl_add_default_handler (sub,
  1219. "log_format",
  1220. rspamd_rcl_parse_struct_string,
  1221. G_STRUCT_OFFSET (struct rspamd_config, log_format_str),
  1222. 0,
  1223. "Specify format string for the task logging output "
  1224. "(https://rspamd.com/doc/configuration/logging.html "
  1225. "for details)");
  1226. /**
  1227. * Options section
  1228. */
  1229. sub = rspamd_rcl_add_section_doc (&new,
  1230. "options", NULL,
  1231. rspamd_rcl_options_handler,
  1232. UCL_OBJECT,
  1233. FALSE,
  1234. TRUE,
  1235. cfg->doc_strings,
  1236. "Global rspamd options");
  1237. rspamd_rcl_add_default_handler (sub,
  1238. "cache_file",
  1239. rspamd_rcl_parse_struct_string,
  1240. G_STRUCT_OFFSET (struct rspamd_config, cache_filename),
  1241. RSPAMD_CL_FLAG_STRING_PATH,
  1242. "Path to the cache file");
  1243. /* Old DNS configuration */
  1244. rspamd_rcl_add_default_handler (sub,
  1245. "dns_nameserver",
  1246. rspamd_rcl_parse_struct_string_list,
  1247. G_STRUCT_OFFSET (struct rspamd_config, nameservers),
  1248. 0,
  1249. "Legacy option for DNS servers used");
  1250. rspamd_rcl_add_default_handler (sub,
  1251. "dns_timeout",
  1252. rspamd_rcl_parse_struct_time,
  1253. G_STRUCT_OFFSET (struct rspamd_config, dns_timeout),
  1254. RSPAMD_CL_FLAG_TIME_FLOAT,
  1255. "Legacy option for DNS request timeout");
  1256. rspamd_rcl_add_default_handler (sub,
  1257. "dns_retransmits",
  1258. rspamd_rcl_parse_struct_integer,
  1259. G_STRUCT_OFFSET (struct rspamd_config, dns_retransmits),
  1260. RSPAMD_CL_FLAG_INT_32,
  1261. "Legacy option for DNS retransmits count");
  1262. rspamd_rcl_add_default_handler (sub,
  1263. "dns_sockets",
  1264. rspamd_rcl_parse_struct_integer,
  1265. G_STRUCT_OFFSET (struct rspamd_config, dns_io_per_server),
  1266. RSPAMD_CL_FLAG_INT_32,
  1267. "Legacy option for DNS sockets per server count");
  1268. rspamd_rcl_add_default_handler (sub,
  1269. "dns_max_requests",
  1270. rspamd_rcl_parse_struct_integer,
  1271. G_STRUCT_OFFSET (struct rspamd_config, dns_max_requests),
  1272. RSPAMD_CL_FLAG_INT_32,
  1273. "Legacy option for DNS maximum requests per task count");
  1274. rspamd_rcl_add_default_handler (sub,
  1275. "classify_headers",
  1276. rspamd_rcl_parse_struct_string_list,
  1277. G_STRUCT_OFFSET (struct rspamd_config, classify_headers),
  1278. 0,
  1279. "List of headers used for classifiers");
  1280. rspamd_rcl_add_default_handler (sub,
  1281. "control_socket",
  1282. rspamd_rcl_parse_struct_string,
  1283. G_STRUCT_OFFSET (struct rspamd_config, control_socket_path),
  1284. 0,
  1285. "Path to the control socket");
  1286. rspamd_rcl_add_default_handler (sub,
  1287. "explicit_modules",
  1288. rspamd_rcl_parse_struct_string_list,
  1289. G_STRUCT_OFFSET (struct rspamd_config, explicit_modules),
  1290. RSPAMD_CL_FLAG_STRING_LIST_HASH,
  1291. "Always load these modules even if they are not configured explicitly");
  1292. rspamd_rcl_add_default_handler (sub,
  1293. "allow_raw_input",
  1294. rspamd_rcl_parse_struct_boolean,
  1295. G_STRUCT_OFFSET (struct rspamd_config, allow_raw_input),
  1296. 0,
  1297. "Allow non MIME input for rspamd");
  1298. rspamd_rcl_add_default_handler (sub,
  1299. "raw_mode",
  1300. rspamd_rcl_parse_struct_boolean,
  1301. G_STRUCT_OFFSET (struct rspamd_config, raw_mode),
  1302. 0,
  1303. "Don't try to convert all messages to utf8");
  1304. rspamd_rcl_add_default_handler (sub,
  1305. "one_shot",
  1306. rspamd_rcl_parse_struct_boolean,
  1307. G_STRUCT_OFFSET (struct rspamd_config, one_shot_mode),
  1308. 0,
  1309. "Add all symbols only once per message");
  1310. rspamd_rcl_add_default_handler (sub,
  1311. "check_attachements",
  1312. rspamd_rcl_parse_struct_boolean,
  1313. G_STRUCT_OFFSET (struct rspamd_config, check_text_attachements),
  1314. 0,
  1315. "Treat text attachements as normal text parts");
  1316. rspamd_rcl_add_default_handler (sub,
  1317. "tempdir",
  1318. rspamd_rcl_parse_struct_string,
  1319. G_STRUCT_OFFSET (struct rspamd_config, temp_dir),
  1320. RSPAMD_CL_FLAG_STRING_PATH,
  1321. "Directory for temporary files");
  1322. rspamd_rcl_add_default_handler (sub,
  1323. "pidfile",
  1324. rspamd_rcl_parse_struct_string,
  1325. G_STRUCT_OFFSET (struct rspamd_config, pid_file),
  1326. RSPAMD_CL_FLAG_STRING_PATH,
  1327. "Path to the pid file");
  1328. rspamd_rcl_add_default_handler (sub,
  1329. "filters",
  1330. rspamd_rcl_parse_struct_string_list,
  1331. G_STRUCT_OFFSET (struct rspamd_config, filters),
  1332. 0,
  1333. "List of internal filters enabled");
  1334. rspamd_rcl_add_default_handler (sub,
  1335. "max_diff",
  1336. rspamd_rcl_parse_struct_integer,
  1337. G_STRUCT_OFFSET (struct rspamd_config, max_diff),
  1338. RSPAMD_CL_FLAG_INT_SIZE,
  1339. "Legacy option, do not use");
  1340. rspamd_rcl_add_default_handler (sub,
  1341. "map_watch_interval",
  1342. rspamd_rcl_parse_struct_time,
  1343. G_STRUCT_OFFSET (struct rspamd_config, map_timeout),
  1344. RSPAMD_CL_FLAG_TIME_FLOAT,
  1345. "Interval for checking maps");
  1346. rspamd_rcl_add_default_handler (sub,
  1347. "dynamic_conf",
  1348. rspamd_rcl_parse_struct_string,
  1349. G_STRUCT_OFFSET (struct rspamd_config, dynamic_conf),
  1350. 0,
  1351. "Path to the dynamic configuration");
  1352. rspamd_rcl_add_default_handler (sub,
  1353. "rrd",
  1354. rspamd_rcl_parse_struct_string,
  1355. G_STRUCT_OFFSET (struct rspamd_config, rrd_file),
  1356. RSPAMD_CL_FLAG_STRING_PATH,
  1357. "Path to RRD file");
  1358. rspamd_rcl_add_default_handler (sub,
  1359. "history_file",
  1360. rspamd_rcl_parse_struct_string,
  1361. G_STRUCT_OFFSET (struct rspamd_config, history_file),
  1362. RSPAMD_CL_FLAG_STRING_PATH,
  1363. "Path to history file");
  1364. rspamd_rcl_add_default_handler (sub,
  1365. "use_mlock",
  1366. rspamd_rcl_parse_struct_boolean,
  1367. G_STRUCT_OFFSET (struct rspamd_config, mlock_statfile_pool),
  1368. 0,
  1369. "Use mlock call for statistics to ensure that all files are in RAM");
  1370. rspamd_rcl_add_default_handler (sub,
  1371. "strict_protocol_headers",
  1372. rspamd_rcl_parse_struct_boolean,
  1373. G_STRUCT_OFFSET (struct rspamd_config, strict_protocol_headers),
  1374. 0,
  1375. "Emit errors if there are unknown HTTP headers in a request");
  1376. rspamd_rcl_add_default_handler (sub,
  1377. "check_all_filters",
  1378. rspamd_rcl_parse_struct_boolean,
  1379. G_STRUCT_OFFSET (struct rspamd_config, check_all_filters),
  1380. 0,
  1381. "Always check all filters");
  1382. rspamd_rcl_add_default_handler (sub,
  1383. "all_filters",
  1384. rspamd_rcl_parse_struct_boolean,
  1385. G_STRUCT_OFFSET (struct rspamd_config, check_all_filters),
  1386. 0,
  1387. "Always check all filters");
  1388. rspamd_rcl_add_default_handler (sub,
  1389. "min_word_len",
  1390. rspamd_rcl_parse_struct_integer,
  1391. G_STRUCT_OFFSET (struct rspamd_config, min_word_len),
  1392. RSPAMD_CL_FLAG_UINT,
  1393. "Minimum length of the word to be considered in statistics/fuzzy");
  1394. rspamd_rcl_add_default_handler (sub,
  1395. "max_word_len",
  1396. rspamd_rcl_parse_struct_integer,
  1397. G_STRUCT_OFFSET (struct rspamd_config, max_word_len),
  1398. RSPAMD_CL_FLAG_UINT,
  1399. "Maximum length of the word to be considered in statistics/fuzzy");
  1400. rspamd_rcl_add_default_handler (sub,
  1401. "words_decay",
  1402. rspamd_rcl_parse_struct_integer,
  1403. G_STRUCT_OFFSET (struct rspamd_config, words_decay),
  1404. RSPAMD_CL_FLAG_UINT,
  1405. "Start skipping words at this amount");
  1406. rspamd_rcl_add_default_handler (sub,
  1407. "url_tld",
  1408. rspamd_rcl_parse_struct_string,
  1409. G_STRUCT_OFFSET (struct rspamd_config, tld_file),
  1410. RSPAMD_CL_FLAG_STRING_PATH,
  1411. "Path to the TLD file for urls detector");
  1412. rspamd_rcl_add_default_handler (sub,
  1413. "tld",
  1414. rspamd_rcl_parse_struct_string,
  1415. G_STRUCT_OFFSET (struct rspamd_config, tld_file),
  1416. RSPAMD_CL_FLAG_STRING_PATH,
  1417. "Path to the TLD file for urls detector");
  1418. rspamd_rcl_add_default_handler (sub,
  1419. "history_rows",
  1420. rspamd_rcl_parse_struct_integer,
  1421. G_STRUCT_OFFSET (struct rspamd_config, history_rows),
  1422. RSPAMD_CL_FLAG_UINT,
  1423. "Number of records in the history file");
  1424. rspamd_rcl_add_default_handler (sub,
  1425. "disable_hyperscan",
  1426. rspamd_rcl_parse_struct_boolean,
  1427. G_STRUCT_OFFSET (struct rspamd_config, disable_hyperscan),
  1428. 0,
  1429. "Disable hyperscan optimizations for regular expressions");
  1430. rspamd_rcl_add_default_handler (sub,
  1431. "cores_dir",
  1432. rspamd_rcl_parse_struct_string,
  1433. G_STRUCT_OFFSET (struct rspamd_config, cores_dir),
  1434. RSPAMD_CL_FLAG_STRING_PATH,
  1435. "Path to the directory where rspamd core files are intended to be dumped");
  1436. rspamd_rcl_add_default_handler (sub,
  1437. "max_cores_size",
  1438. rspamd_rcl_parse_struct_integer,
  1439. G_STRUCT_OFFSET (struct rspamd_config, max_cores_size),
  1440. RSPAMD_CL_FLAG_INT_SIZE,
  1441. "Limit of joint size of all files in `cores_dir`");
  1442. rspamd_rcl_add_default_handler (sub,
  1443. "max_cores_count",
  1444. rspamd_rcl_parse_struct_integer,
  1445. G_STRUCT_OFFSET (struct rspamd_config, max_cores_count),
  1446. RSPAMD_CL_FLAG_INT_SIZE,
  1447. "Limit of files count in `cores_dir`");
  1448. rspamd_rcl_add_default_handler (sub,
  1449. "local_addrs",
  1450. rspamd_rcl_parse_struct_string,
  1451. G_STRUCT_OFFSET (struct rspamd_config, local_addrs),
  1452. 0,
  1453. "Use the specified addresses as local ones");
  1454. rspamd_rcl_add_default_handler (sub,
  1455. "local_networks",
  1456. rspamd_rcl_parse_struct_string,
  1457. G_STRUCT_OFFSET (struct rspamd_config, local_addrs),
  1458. 0,
  1459. "Use the specified addresses as local ones (alias for `local_addrs`)");
  1460. /* New DNS configuration */
  1461. ssub = rspamd_rcl_add_section_doc (&sub->subsections, "dns", NULL, NULL,
  1462. UCL_OBJECT, FALSE, TRUE,
  1463. cfg->doc_strings,
  1464. "Options for DNS resolver");
  1465. rspamd_rcl_add_default_handler (ssub,
  1466. "nameserver",
  1467. rspamd_rcl_parse_struct_string_list,
  1468. G_STRUCT_OFFSET (struct rspamd_config, nameservers),
  1469. 0,
  1470. "List of DNS servers");
  1471. rspamd_rcl_add_default_handler (ssub,
  1472. "server",
  1473. rspamd_rcl_parse_struct_string_list,
  1474. G_STRUCT_OFFSET (struct rspamd_config, nameservers),
  1475. 0,
  1476. "List of DNS servers");
  1477. rspamd_rcl_add_default_handler (ssub,
  1478. "timeout",
  1479. rspamd_rcl_parse_struct_time,
  1480. G_STRUCT_OFFSET (struct rspamd_config, dns_timeout),
  1481. RSPAMD_CL_FLAG_TIME_FLOAT,
  1482. "DNS request timeout");
  1483. rspamd_rcl_add_default_handler (ssub,
  1484. "retransmits",
  1485. rspamd_rcl_parse_struct_integer,
  1486. G_STRUCT_OFFSET (struct rspamd_config, dns_retransmits),
  1487. RSPAMD_CL_FLAG_INT_32,
  1488. "DNS request retransmits");
  1489. rspamd_rcl_add_default_handler (ssub,
  1490. "sockets",
  1491. rspamd_rcl_parse_struct_integer,
  1492. G_STRUCT_OFFSET (struct rspamd_config, dns_io_per_server),
  1493. RSPAMD_CL_FLAG_INT_32,
  1494. "Number of sockets per DNS server");
  1495. rspamd_rcl_add_default_handler (ssub,
  1496. "connections",
  1497. rspamd_rcl_parse_struct_integer,
  1498. G_STRUCT_OFFSET (struct rspamd_config, dns_io_per_server),
  1499. RSPAMD_CL_FLAG_INT_32,
  1500. "Number of sockets per DNS server");
  1501. /* New upstreams configuration */
  1502. ssub = rspamd_rcl_add_section_doc (&sub->subsections, "upstream", NULL, NULL,
  1503. UCL_OBJECT, FALSE, TRUE,
  1504. cfg->doc_strings,
  1505. "Upstreams configuration parameters");
  1506. rspamd_rcl_add_default_handler (ssub,
  1507. "max_errors",
  1508. rspamd_rcl_parse_struct_integer,
  1509. G_STRUCT_OFFSET (struct rspamd_config, upstream_max_errors),
  1510. RSPAMD_CL_FLAG_UINT,
  1511. "Maximum number of errors during `error_time` to consider upstream down");
  1512. rspamd_rcl_add_default_handler (ssub,
  1513. "error_time",
  1514. rspamd_rcl_parse_struct_time,
  1515. G_STRUCT_OFFSET (struct rspamd_config, upstream_error_time),
  1516. RSPAMD_CL_FLAG_TIME_FLOAT,
  1517. "Time frame to check errors");
  1518. rspamd_rcl_add_default_handler (ssub,
  1519. "revive_time",
  1520. rspamd_rcl_parse_struct_time,
  1521. G_STRUCT_OFFSET (struct rspamd_config, upstream_revive_time),
  1522. RSPAMD_CL_FLAG_TIME_FLOAT,
  1523. "Time before attempting to recover upstream after an error");
  1524. /**
  1525. * Metric section
  1526. */
  1527. sub = rspamd_rcl_add_section_doc (&new,
  1528. "metric", "name",
  1529. rspamd_rcl_metric_handler,
  1530. UCL_OBJECT,
  1531. FALSE,
  1532. TRUE,
  1533. cfg->doc_strings,
  1534. "Metrics configuration");
  1535. sub->default_key = DEFAULT_METRIC;
  1536. rspamd_rcl_add_default_handler (sub,
  1537. "unknown_weight",
  1538. rspamd_rcl_parse_struct_double,
  1539. G_STRUCT_OFFSET (struct metric, unknown_weight),
  1540. 0,
  1541. "Accept unknown symbols with the specified weight");
  1542. rspamd_rcl_add_default_handler (sub,
  1543. "grow_factor",
  1544. rspamd_rcl_parse_struct_double,
  1545. G_STRUCT_OFFSET (struct metric, grow_factor),
  1546. 0,
  1547. "Multiply the subsequent symbols by this number "
  1548. "(does not affect symbols with score less or "
  1549. "equal to zero)");
  1550. rspamd_rcl_add_default_handler (sub,
  1551. "subject",
  1552. rspamd_rcl_parse_struct_string,
  1553. G_STRUCT_OFFSET (struct metric, subject),
  1554. 0,
  1555. "Rewrite subject with this value");
  1556. /* Ungrouped symbols */
  1557. ssub = rspamd_rcl_add_section_doc (&sub->subsections,
  1558. "symbol", "name",
  1559. rspamd_rcl_symbol_handler,
  1560. UCL_OBJECT,
  1561. TRUE,
  1562. TRUE,
  1563. sub->doc_ref,
  1564. "Symbols settings");
  1565. rspamd_rcl_add_default_handler (ssub,
  1566. "description",
  1567. rspamd_rcl_parse_struct_string,
  1568. G_STRUCT_OFFSET (struct rspamd_symbol_def, description),
  1569. 0,
  1570. "Symbol's description");
  1571. rspamd_rcl_add_default_handler (ssub,
  1572. "score",
  1573. rspamd_rcl_parse_struct_double,
  1574. G_STRUCT_OFFSET (struct rspamd_symbol_def, score),
  1575. 0,
  1576. "Symbol's score");
  1577. rspamd_rcl_add_default_handler (ssub,
  1578. "weight",
  1579. rspamd_rcl_parse_struct_double,
  1580. G_STRUCT_OFFSET (struct rspamd_symbol_def, score),
  1581. 0,
  1582. "Symbol's score");
  1583. /* Actions part */
  1584. ssub = rspamd_rcl_add_section_doc (&sub->subsections,
  1585. "actions", NULL,
  1586. rspamd_rcl_actions_handler,
  1587. UCL_OBJECT,
  1588. TRUE,
  1589. TRUE,
  1590. sub->doc_ref,
  1591. "Actions settings");
  1592. /* Group part */
  1593. ssub = rspamd_rcl_add_section_doc (&sub->subsections,
  1594. "group", "name",
  1595. rspamd_rcl_group_handler,
  1596. UCL_OBJECT,
  1597. TRUE,
  1598. TRUE,
  1599. sub->doc_ref,
  1600. "Symbol groups settings");
  1601. rspamd_rcl_add_default_handler (ssub,
  1602. "disabled",
  1603. rspamd_rcl_parse_struct_boolean,
  1604. G_STRUCT_OFFSET (struct rspamd_symbols_group, disabled),
  1605. 0,
  1606. "Disable symbols group");
  1607. rspamd_rcl_add_default_handler (ssub,
  1608. "enabled",
  1609. rspamd_rcl_parse_struct_boolean,
  1610. G_STRUCT_OFFSET (struct rspamd_symbols_group, disabled),
  1611. RSPAMD_CL_FLAG_BOOLEAN_INVERSE,
  1612. "Enable or disable symbols group");
  1613. rspamd_rcl_add_default_handler (ssub,
  1614. "max_score",
  1615. rspamd_rcl_parse_struct_double,
  1616. G_STRUCT_OFFSET (struct rspamd_symbols_group, max_score),
  1617. 0,
  1618. "Maximum score that could be reached by this symbols group");
  1619. /* Grouped symbols */
  1620. sssub = rspamd_rcl_add_section_doc (&ssub->subsections,
  1621. "symbol", "name",
  1622. rspamd_rcl_symbol_handler,
  1623. UCL_OBJECT,
  1624. TRUE,
  1625. TRUE,
  1626. ssub->doc_ref,
  1627. "Symbols settings");
  1628. rspamd_rcl_add_default_handler (sssub,
  1629. "description",
  1630. rspamd_rcl_parse_struct_string,
  1631. G_STRUCT_OFFSET (struct rspamd_symbol_def, description),
  1632. 0,
  1633. "Description of a symbol");
  1634. rspamd_rcl_add_default_handler (sssub,
  1635. "score",
  1636. rspamd_rcl_parse_struct_double,
  1637. G_STRUCT_OFFSET (struct rspamd_symbol_def, score),
  1638. 0,
  1639. "Symbol's score");
  1640. rspamd_rcl_add_default_handler (sssub,
  1641. "weight",
  1642. rspamd_rcl_parse_struct_double,
  1643. G_STRUCT_OFFSET (struct rspamd_symbol_def, score),
  1644. 0,
  1645. "Symbol's score");
  1646. /**
  1647. * Worker section
  1648. */
  1649. sub = rspamd_rcl_add_section_doc (&new,
  1650. "worker", "type",
  1651. rspamd_rcl_worker_handler,
  1652. UCL_OBJECT,
  1653. FALSE,
  1654. TRUE,
  1655. cfg->doc_strings,
  1656. "Workers common options");
  1657. rspamd_rcl_add_default_handler (sub,
  1658. "count",
  1659. rspamd_rcl_parse_struct_integer,
  1660. G_STRUCT_OFFSET (struct rspamd_worker_conf, count),
  1661. RSPAMD_CL_FLAG_INT_16,
  1662. "Number of workers to spawn");
  1663. rspamd_rcl_add_default_handler (sub,
  1664. "max_files",
  1665. rspamd_rcl_parse_struct_integer,
  1666. G_STRUCT_OFFSET (struct rspamd_worker_conf, rlimit_nofile),
  1667. RSPAMD_CL_FLAG_INT_32,
  1668. "Maximum number of opened files per worker");
  1669. rspamd_rcl_add_default_handler (sub,
  1670. "max_core",
  1671. rspamd_rcl_parse_struct_integer,
  1672. G_STRUCT_OFFSET (struct rspamd_worker_conf, rlimit_maxcore),
  1673. RSPAMD_CL_FLAG_INT_32,
  1674. "Max size of core file in bytes");
  1675. /**
  1676. * Modules handler
  1677. */
  1678. sub = rspamd_rcl_add_section_doc (&new,
  1679. "modules", NULL,
  1680. rspamd_rcl_modules_handler,
  1681. UCL_OBJECT,
  1682. FALSE,
  1683. FALSE,
  1684. cfg->doc_strings,
  1685. "Lua plugins to load");
  1686. /**
  1687. * Classifiers handler
  1688. */
  1689. sub = rspamd_rcl_add_section_doc (&new,
  1690. "classifier", "type",
  1691. rspamd_rcl_classifier_handler,
  1692. UCL_OBJECT,
  1693. FALSE,
  1694. TRUE,
  1695. cfg->doc_strings,
  1696. "CLassifier options");
  1697. /* Default classifier is 'bayes' for now */
  1698. sub->default_key = "bayes";
  1699. rspamd_rcl_add_default_handler (sub,
  1700. "min_tokens",
  1701. rspamd_rcl_parse_struct_integer,
  1702. G_STRUCT_OFFSET (struct rspamd_classifier_config, min_tokens),
  1703. RSPAMD_CL_FLAG_INT_32,
  1704. "Minumum count of tokens (words) to be considered for statistics");
  1705. rspamd_rcl_add_default_handler (sub,
  1706. "max_tokens",
  1707. rspamd_rcl_parse_struct_integer,
  1708. G_STRUCT_OFFSET (struct rspamd_classifier_config, max_tokens),
  1709. RSPAMD_CL_FLAG_INT_32,
  1710. "Maximum count of tokens (words) to be considered for statistics");
  1711. rspamd_rcl_add_default_handler (sub,
  1712. "backend",
  1713. rspamd_rcl_parse_struct_string,
  1714. G_STRUCT_OFFSET (struct rspamd_classifier_config, backend),
  1715. 0,
  1716. "Statfiles engine");
  1717. rspamd_rcl_add_default_handler (sub,
  1718. "name",
  1719. rspamd_rcl_parse_struct_string,
  1720. G_STRUCT_OFFSET (struct rspamd_classifier_config, name),
  1721. 0,
  1722. "Name of classifier");
  1723. /*
  1724. * Statfile defaults
  1725. */
  1726. ssub = rspamd_rcl_add_section_doc (&sub->subsections,
  1727. "statfile", "symbol",
  1728. rspamd_rcl_statfile_handler,
  1729. UCL_OBJECT,
  1730. TRUE,
  1731. TRUE,
  1732. sub->doc_ref,
  1733. "Statfiles options");
  1734. rspamd_rcl_add_default_handler (ssub,
  1735. "label",
  1736. rspamd_rcl_parse_struct_string,
  1737. G_STRUCT_OFFSET (struct rspamd_statfile_config, label),
  1738. 0,
  1739. "Statfile unique label");
  1740. rspamd_rcl_add_default_handler (ssub,
  1741. "spam",
  1742. rspamd_rcl_parse_struct_boolean,
  1743. G_STRUCT_OFFSET (struct rspamd_statfile_config, is_spam),
  1744. 0,
  1745. "Sets if this statfile contains spam samples");
  1746. /**
  1747. * Composites handler
  1748. */
  1749. sub = rspamd_rcl_add_section_doc (&new,
  1750. "composite", "name",
  1751. rspamd_rcl_composite_handler,
  1752. UCL_OBJECT,
  1753. FALSE,
  1754. TRUE,
  1755. cfg->doc_strings,
  1756. "Rspamd composite symbols");
  1757. /**
  1758. * Lua handler
  1759. */
  1760. sub = rspamd_rcl_add_section_doc (&new,
  1761. "lua", NULL,
  1762. rspamd_rcl_lua_handler,
  1763. UCL_STRING,
  1764. FALSE,
  1765. TRUE,
  1766. cfg->doc_strings,
  1767. "Lua files to load");
  1768. return new;
  1769. }
  1770. struct rspamd_rcl_section *
  1771. rspamd_rcl_config_get_section (struct rspamd_rcl_section *top,
  1772. const char *path)
  1773. {
  1774. struct rspamd_rcl_section *cur, *found = NULL;
  1775. char **path_components;
  1776. gint ncomponents, i;
  1777. if (path == NULL) {
  1778. return top;
  1779. }
  1780. path_components = g_strsplit_set (path, "/", -1);
  1781. ncomponents = g_strv_length (path_components);
  1782. cur = top;
  1783. for (i = 0; i < ncomponents; i++) {
  1784. if (cur == NULL) {
  1785. g_strfreev (path_components);
  1786. return NULL;
  1787. }
  1788. HASH_FIND_STR (cur, path_components[i], found);
  1789. if (found == NULL) {
  1790. g_strfreev (path_components);
  1791. return NULL;
  1792. }
  1793. cur = found;
  1794. }
  1795. g_strfreev (path_components);
  1796. return found;
  1797. }
  1798. static gboolean
  1799. rspamd_rcl_process_section (struct rspamd_rcl_section *sec,
  1800. gpointer ptr, const ucl_object_t *obj, rspamd_mempool_t *pool,
  1801. GError **err)
  1802. {
  1803. ucl_object_iter_t it;
  1804. const ucl_object_t *cur;
  1805. gboolean is_nested = TRUE;
  1806. const gchar *key = NULL;
  1807. g_assert (obj != NULL);
  1808. g_assert (sec->handler != NULL);
  1809. it = NULL;
  1810. if (sec->key_attr != NULL) {
  1811. while ((cur = ucl_iterate_object (obj, &it, true)) != NULL) {
  1812. if (ucl_object_type (cur) != UCL_OBJECT) {
  1813. is_nested = FALSE;
  1814. break;
  1815. }
  1816. }
  1817. }
  1818. else {
  1819. is_nested = FALSE;
  1820. }
  1821. if (is_nested) {
  1822. /* Just reiterate on all subobjects */
  1823. it = NULL;
  1824. while ((cur = ucl_iterate_object (obj, &it, true)) != NULL) {
  1825. if (!sec->handler (pool, cur, ucl_object_key (cur), ptr, sec, err)) {
  1826. return FALSE;
  1827. }
  1828. }
  1829. return TRUE;
  1830. }
  1831. else {
  1832. if (sec->key_attr != NULL) {
  1833. /* First of all search for required attribute and use it as a key */
  1834. cur = ucl_object_find_key (obj, sec->key_attr);
  1835. if (cur == NULL) {
  1836. if (sec->default_key == NULL) {
  1837. g_set_error (err, CFG_RCL_ERROR, EINVAL, "required attribute "
  1838. "'%s' is missing for section '%s'", sec->key_attr,
  1839. sec->name);
  1840. return FALSE;
  1841. }
  1842. else {
  1843. msg_info ("using default key '%s' for mandatory field '%s' "
  1844. "for section '%s'", sec->default_key, sec->key_attr,
  1845. sec->name);
  1846. key = sec->default_key;
  1847. }
  1848. }
  1849. else if (ucl_object_type (cur) != UCL_STRING) {
  1850. g_set_error (err, CFG_RCL_ERROR, EINVAL, "required attribute %s"
  1851. " is not a string for section %s",
  1852. sec->key_attr, sec->name);
  1853. return FALSE;
  1854. }
  1855. else {
  1856. key = ucl_object_tostring (cur);
  1857. }
  1858. }
  1859. }
  1860. return sec->handler (pool, obj, key, ptr, sec, err);
  1861. }
  1862. gboolean
  1863. rspamd_rcl_parse (struct rspamd_rcl_section *top,
  1864. gpointer ptr, rspamd_mempool_t *pool,
  1865. const ucl_object_t *obj, GError **err)
  1866. {
  1867. const ucl_object_t *found, *cur_obj;
  1868. struct rspamd_rcl_section *cur, *tmp, *found_sec;
  1869. if (obj->type != UCL_OBJECT) {
  1870. g_set_error (err,
  1871. CFG_RCL_ERROR,
  1872. EINVAL,
  1873. "top configuration must be an object");
  1874. return FALSE;
  1875. }
  1876. /* Iterate over known sections and ignore unknown ones */
  1877. HASH_ITER (hh, top, cur, tmp)
  1878. {
  1879. if (strcmp (cur->name, "*") == 0) {
  1880. /* Default section handler */
  1881. LL_FOREACH (obj, cur_obj) {
  1882. HASH_FIND_STR (top, ucl_object_key (cur_obj), found_sec);
  1883. if (found_sec == NULL) {
  1884. if (cur->handler != NULL) {
  1885. if (!rspamd_rcl_process_section (cur, ptr, cur_obj,
  1886. pool, err)) {
  1887. return FALSE;
  1888. }
  1889. }
  1890. else {
  1891. rspamd_rcl_section_parse_defaults (cur,
  1892. pool,
  1893. cur_obj,
  1894. ptr,
  1895. err);
  1896. }
  1897. }
  1898. }
  1899. }
  1900. else {
  1901. found = ucl_object_find_key (obj, cur->name);
  1902. if (found == NULL) {
  1903. if (cur->required) {
  1904. g_set_error (err, CFG_RCL_ERROR, ENOENT,
  1905. "required section %s is missing", cur->name);
  1906. return FALSE;
  1907. }
  1908. }
  1909. else {
  1910. /* Check type */
  1911. if (cur->strict_type) {
  1912. if (cur->type != found->type) {
  1913. g_set_error (err, CFG_RCL_ERROR, EINVAL,
  1914. "object in section %s has invalid type", cur->name);
  1915. return FALSE;
  1916. }
  1917. }
  1918. LL_FOREACH (found, cur_obj) {
  1919. if (cur->handler != NULL) {
  1920. if (!rspamd_rcl_process_section (cur, ptr, cur_obj,
  1921. pool, err)) {
  1922. return FALSE;
  1923. }
  1924. }
  1925. else {
  1926. rspamd_rcl_section_parse_defaults (cur,
  1927. pool,
  1928. cur_obj,
  1929. ptr,
  1930. err);
  1931. }
  1932. }
  1933. }
  1934. }
  1935. if (cur->fin) {
  1936. cur->fin (pool, cur->fin_ud);
  1937. }
  1938. }
  1939. return TRUE;
  1940. }
  1941. gboolean
  1942. rspamd_rcl_section_parse_defaults (struct rspamd_rcl_section *section,
  1943. rspamd_mempool_t *pool, const ucl_object_t *obj, gpointer ptr,
  1944. GError **err)
  1945. {
  1946. const ucl_object_t *found, *cur_obj;
  1947. struct rspamd_rcl_default_handler_data *cur, *tmp;
  1948. if (obj->type != UCL_OBJECT) {
  1949. g_set_error (err,
  1950. CFG_RCL_ERROR,
  1951. EINVAL,
  1952. "default configuration must be an object");
  1953. return FALSE;
  1954. }
  1955. HASH_ITER (hh, section->default_parser, cur, tmp)
  1956. {
  1957. found = ucl_object_find_key (obj, cur->key);
  1958. if (found != NULL) {
  1959. cur->pd.user_struct = ptr;
  1960. LL_FOREACH (found, cur_obj) {
  1961. if (!cur->handler (pool, cur_obj, &cur->pd, section, err)) {
  1962. return FALSE;
  1963. }
  1964. if (!(cur->pd.flags & RSPAMD_CL_FLAG_MULTIPLE)) {
  1965. break;
  1966. }
  1967. }
  1968. }
  1969. }
  1970. return TRUE;
  1971. }
  1972. gboolean
  1973. rspamd_rcl_parse_struct_string (rspamd_mempool_t *pool,
  1974. const ucl_object_t *obj,
  1975. gpointer ud,
  1976. struct rspamd_rcl_section *section,
  1977. GError **err)
  1978. {
  1979. struct rspamd_rcl_struct_parser *pd = ud;
  1980. gchar **target;
  1981. const gsize num_str_len = 32;
  1982. target = (gchar **)(((gchar *)pd->user_struct) + pd->offset);
  1983. switch (obj->type) {
  1984. case UCL_STRING:
  1985. *target =
  1986. rspamd_mempool_strdup (pool, ucl_copy_value_trash (obj));
  1987. break;
  1988. case UCL_INT:
  1989. *target = rspamd_mempool_alloc (pool, num_str_len);
  1990. rspamd_snprintf (*target, num_str_len, "%L", obj->value.iv);
  1991. break;
  1992. case UCL_FLOAT:
  1993. *target = rspamd_mempool_alloc (pool, num_str_len);
  1994. rspamd_snprintf (*target, num_str_len, "%f", obj->value.dv);
  1995. break;
  1996. case UCL_BOOLEAN:
  1997. *target = rspamd_mempool_alloc (pool, num_str_len);
  1998. rspamd_snprintf (*target, num_str_len, "%B", (gboolean)obj->value.iv);
  1999. break;
  2000. default:
  2001. g_set_error (err,
  2002. CFG_RCL_ERROR,
  2003. EINVAL,
  2004. "cannot convert object or array to string");
  2005. return FALSE;
  2006. }
  2007. return TRUE;
  2008. }
  2009. gboolean
  2010. rspamd_rcl_parse_struct_integer (rspamd_mempool_t *pool,
  2011. const ucl_object_t *obj,
  2012. gpointer ud,
  2013. struct rspamd_rcl_section *section,
  2014. GError **err)
  2015. {
  2016. struct rspamd_rcl_struct_parser *pd = ud;
  2017. union {
  2018. gint *ip;
  2019. gint32 *i32p;
  2020. gint16 *i16p;
  2021. gint64 *i64p;
  2022. guint *up;
  2023. gsize *sp;
  2024. } target;
  2025. int64_t val;
  2026. if (pd->flags == RSPAMD_CL_FLAG_INT_32) {
  2027. target.i32p = (gint32 *)(((gchar *)pd->user_struct) + pd->offset);
  2028. if (!ucl_object_toint_safe (obj, &val)) {
  2029. g_set_error (err,
  2030. CFG_RCL_ERROR,
  2031. EINVAL,
  2032. "cannot convert param to integer");
  2033. return FALSE;
  2034. }
  2035. *target.i32p = val;
  2036. }
  2037. else if (pd->flags == RSPAMD_CL_FLAG_INT_64) {
  2038. target.i64p = (gint64 *)(((gchar *)pd->user_struct) + pd->offset);
  2039. if (!ucl_object_toint_safe (obj, &val)) {
  2040. g_set_error (err,
  2041. CFG_RCL_ERROR,
  2042. EINVAL,
  2043. "cannot convert param to integer");
  2044. return FALSE;
  2045. }
  2046. *target.i64p = val;
  2047. }
  2048. else if (pd->flags == RSPAMD_CL_FLAG_INT_SIZE) {
  2049. target.sp = (gsize *)(((gchar *)pd->user_struct) + pd->offset);
  2050. if (!ucl_object_toint_safe (obj, &val)) {
  2051. g_set_error (err,
  2052. CFG_RCL_ERROR,
  2053. EINVAL,
  2054. "cannot convert param to integer");
  2055. return FALSE;
  2056. }
  2057. *target.sp = val;
  2058. }
  2059. else if (pd->flags == RSPAMD_CL_FLAG_INT_16) {
  2060. target.i16p = (gint16 *)(((gchar *)pd->user_struct) + pd->offset);
  2061. if (!ucl_object_toint_safe (obj, &val)) {
  2062. g_set_error (err,
  2063. CFG_RCL_ERROR,
  2064. EINVAL,
  2065. "cannot convert param to integer");
  2066. return FALSE;
  2067. }
  2068. *target.i16p = val;
  2069. }
  2070. else if (pd->flags == RSPAMD_CL_FLAG_UINT) {
  2071. target.up = (guint *)(((gchar *)pd->user_struct) + pd->offset);
  2072. if (!ucl_object_toint_safe (obj, &val)) {
  2073. g_set_error (err,
  2074. CFG_RCL_ERROR,
  2075. EINVAL,
  2076. "cannot convert param to integer");
  2077. return FALSE;
  2078. }
  2079. *target.up = val;
  2080. }
  2081. else {
  2082. target.ip = (gint *)(((gchar *)pd->user_struct) + pd->offset);
  2083. if (!ucl_object_toint_safe (obj, &val)) {
  2084. g_set_error (err,
  2085. CFG_RCL_ERROR,
  2086. EINVAL,
  2087. "cannot convert param to integer");
  2088. return FALSE;
  2089. }
  2090. *target.ip = val;
  2091. }
  2092. return TRUE;
  2093. }
  2094. gboolean
  2095. rspamd_rcl_parse_struct_double (rspamd_mempool_t *pool,
  2096. const ucl_object_t *obj,
  2097. gpointer ud,
  2098. struct rspamd_rcl_section *section,
  2099. GError **err)
  2100. {
  2101. struct rspamd_rcl_struct_parser *pd = ud;
  2102. gdouble *target;
  2103. target = (gdouble *)(((gchar *)pd->user_struct) + pd->offset);
  2104. if (!ucl_object_todouble_safe (obj, target)) {
  2105. g_set_error (err,
  2106. CFG_RCL_ERROR,
  2107. EINVAL,
  2108. "cannot convert param %s to double", ucl_object_key (obj));
  2109. return FALSE;
  2110. }
  2111. return TRUE;
  2112. }
  2113. gboolean
  2114. rspamd_rcl_parse_struct_time (rspamd_mempool_t *pool,
  2115. const ucl_object_t *obj,
  2116. gpointer ud,
  2117. struct rspamd_rcl_section *section,
  2118. GError **err)
  2119. {
  2120. struct rspamd_rcl_struct_parser *pd = ud;
  2121. union {
  2122. gint *psec;
  2123. guint32 *pu32;
  2124. gdouble *pdv;
  2125. struct timeval *ptv;
  2126. struct timespec *pts;
  2127. } target;
  2128. gdouble val;
  2129. if (!ucl_object_todouble_safe (obj, &val)) {
  2130. g_set_error (err,
  2131. CFG_RCL_ERROR,
  2132. EINVAL,
  2133. "cannot convert param %s to double", ucl_object_key (obj));
  2134. return FALSE;
  2135. }
  2136. if (pd->flags == RSPAMD_CL_FLAG_TIME_TIMEVAL) {
  2137. target.ptv =
  2138. (struct timeval *)(((gchar *)pd->user_struct) + pd->offset);
  2139. target.ptv->tv_sec = (glong)val;
  2140. target.ptv->tv_usec = (val - (glong)val) * 1000000;
  2141. }
  2142. else if (pd->flags == RSPAMD_CL_FLAG_TIME_TIMESPEC) {
  2143. target.pts =
  2144. (struct timespec *)(((gchar *)pd->user_struct) + pd->offset);
  2145. target.pts->tv_sec = (glong)val;
  2146. target.pts->tv_nsec = (val - (glong)val) * 1000000000000LL;
  2147. }
  2148. else if (pd->flags == RSPAMD_CL_FLAG_TIME_FLOAT) {
  2149. target.pdv = (double *)(((gchar *)pd->user_struct) + pd->offset);
  2150. *target.pdv = val;
  2151. }
  2152. else if (pd->flags == RSPAMD_CL_FLAG_TIME_INTEGER) {
  2153. target.psec = (gint *)(((gchar *)pd->user_struct) + pd->offset);
  2154. *target.psec = val * 1000;
  2155. }
  2156. else if (pd->flags == RSPAMD_CL_FLAG_TIME_UINT_32) {
  2157. target.pu32 = (guint32 *)(((gchar *)pd->user_struct) + pd->offset);
  2158. *target.pu32 = val * 1000;
  2159. }
  2160. else {
  2161. g_set_error (err,
  2162. CFG_RCL_ERROR,
  2163. EINVAL,
  2164. "invalid flags to parse time value in %s", ucl_object_key (obj));
  2165. return FALSE;
  2166. }
  2167. return TRUE;
  2168. }
  2169. gboolean
  2170. rspamd_rcl_parse_struct_keypair (rspamd_mempool_t *pool,
  2171. const ucl_object_t *obj,
  2172. gpointer ud,
  2173. struct rspamd_rcl_section *section,
  2174. GError **err)
  2175. {
  2176. struct rspamd_rcl_struct_parser *pd = ud;
  2177. gpointer *target;
  2178. gpointer key;
  2179. const gchar *val, *sem = NULL, *pk = NULL, *sk = NULL;
  2180. gchar keybuf[256];
  2181. const ucl_object_t *elt;
  2182. target = (gpointer *)(((gchar *)pd->user_struct) + pd->offset);
  2183. if (obj->type == UCL_STRING) {
  2184. /* Pk and Sk are just linked all together */
  2185. val = ucl_object_tostring (obj);
  2186. if ((sem = strchr (val, ':')) != NULL) {
  2187. sk = val;
  2188. pk = sem + 1;
  2189. }
  2190. else {
  2191. /* Try to parse the key as is */
  2192. key = rspamd_http_connection_make_key ((gchar *)val, strlen (val));
  2193. if (key != NULL) {
  2194. *target = key;
  2195. return TRUE;
  2196. }
  2197. g_set_error (err,
  2198. CFG_RCL_ERROR,
  2199. EINVAL,
  2200. "invalid string with keypair content for %s",
  2201. ucl_object_key (obj));
  2202. return FALSE;
  2203. }
  2204. }
  2205. else if (obj->type == UCL_OBJECT) {
  2206. elt = ucl_object_find_key (obj, "pubkey");
  2207. if (elt == NULL || !ucl_object_tostring_safe (elt, &pk)) {
  2208. g_set_error (err,
  2209. CFG_RCL_ERROR,
  2210. EINVAL,
  2211. "no sane pubkey found in the keypair: %s",
  2212. ucl_object_key (obj));
  2213. return FALSE;
  2214. }
  2215. elt = ucl_object_find_key (obj, "privkey");
  2216. if (elt == NULL || !ucl_object_tostring_safe (elt, &sk)) {
  2217. g_set_error (err,
  2218. CFG_RCL_ERROR,
  2219. EINVAL,
  2220. "no sane privkey found in the keypair: %s",
  2221. ucl_object_key (obj));
  2222. return FALSE;
  2223. }
  2224. }
  2225. if (sk == NULL || pk == NULL) {
  2226. g_set_error (err,
  2227. CFG_RCL_ERROR,
  2228. EINVAL,
  2229. "no sane pubkey or privkey found in the keypair: %s",
  2230. ucl_object_key (obj));
  2231. return FALSE;
  2232. }
  2233. if (!sem) {
  2234. rspamd_snprintf (keybuf, sizeof (keybuf), "%s%s", sk, pk);
  2235. }
  2236. else {
  2237. rspamd_snprintf (keybuf, sizeof (keybuf), "%*s%s", (gint)(sem - sk),
  2238. sk, pk);
  2239. }
  2240. key = rspamd_http_connection_make_key (keybuf, strlen (keybuf));
  2241. if (key != NULL) {
  2242. /* XXX: clean buffer after usage */
  2243. *target = key;
  2244. return TRUE;
  2245. }
  2246. g_set_error (err,
  2247. CFG_RCL_ERROR,
  2248. EINVAL,
  2249. "cannot load the keypair specified: %s",
  2250. ucl_object_key (obj));
  2251. return FALSE;
  2252. }
  2253. static void
  2254. rspamd_rcl_insert_string_list_item (gpointer *target, rspamd_mempool_t *pool,
  2255. const gchar *src, gboolean is_hash)
  2256. {
  2257. union {
  2258. GHashTable *hv;
  2259. GList *lv;
  2260. gpointer p;
  2261. } d;
  2262. gchar *val;
  2263. d.p = *target;
  2264. if (is_hash) {
  2265. if (d.hv == NULL) {
  2266. d.hv = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  2267. rspamd_mempool_add_destructor (pool,
  2268. (rspamd_mempool_destruct_t)g_hash_table_unref, d.hv);
  2269. }
  2270. val = rspamd_mempool_strdup (pool, src);
  2271. g_hash_table_insert (d.hv, val, val);
  2272. }
  2273. else {
  2274. val = rspamd_mempool_strdup (pool, src);
  2275. d.lv = g_list_prepend (d.lv, val);
  2276. }
  2277. *target = d.p;
  2278. }
  2279. gboolean
  2280. rspamd_rcl_parse_struct_string_list (rspamd_mempool_t *pool,
  2281. const ucl_object_t *obj,
  2282. gpointer ud,
  2283. struct rspamd_rcl_section *section,
  2284. GError **err)
  2285. {
  2286. struct rspamd_rcl_struct_parser *pd = ud;
  2287. gpointer *target;
  2288. gchar *val, **strvec, **cvec;
  2289. const ucl_object_t *cur;
  2290. const gsize num_str_len = 32;
  2291. ucl_object_iter_t iter = NULL;
  2292. gboolean is_hash, need_destructor = TRUE;
  2293. is_hash = pd->flags & RSPAMD_CL_FLAG_STRING_LIST_HASH;
  2294. target = (gpointer *)(((gchar *)pd->user_struct) + pd->offset);
  2295. if (!is_hash && *target != NULL) {
  2296. need_destructor = FALSE;
  2297. }
  2298. iter = ucl_object_iterate_new (obj);
  2299. while ((cur = ucl_object_iterate_safe (iter, true)) != NULL) {
  2300. switch (cur->type) {
  2301. case UCL_STRING:
  2302. strvec = g_strsplit_set (ucl_object_tostring (cur), ",", -1);
  2303. cvec = strvec;
  2304. while (*cvec) {
  2305. rspamd_rcl_insert_string_list_item (target, pool, *cvec, is_hash);
  2306. cvec ++;
  2307. }
  2308. g_strfreev (strvec);
  2309. /* Go to the next object */
  2310. continue;
  2311. case UCL_INT:
  2312. val = rspamd_mempool_alloc (pool, num_str_len);
  2313. rspamd_snprintf (val, num_str_len, "%L", cur->value.iv);
  2314. break;
  2315. case UCL_FLOAT:
  2316. val = rspamd_mempool_alloc (pool, num_str_len);
  2317. rspamd_snprintf (val, num_str_len, "%f", cur->value.dv);
  2318. break;
  2319. case UCL_BOOLEAN:
  2320. val = rspamd_mempool_alloc (pool, num_str_len);
  2321. rspamd_snprintf (val, num_str_len, "%B", (gboolean)cur->value.iv);
  2322. break;
  2323. default:
  2324. g_set_error (err,
  2325. CFG_RCL_ERROR,
  2326. EINVAL,
  2327. "cannot convert an object or array to string: %s",
  2328. ucl_object_key (obj));
  2329. return FALSE;
  2330. }
  2331. rspamd_rcl_insert_string_list_item (target, pool, val, is_hash);
  2332. }
  2333. if (*target == NULL) {
  2334. g_set_error (err,
  2335. CFG_RCL_ERROR,
  2336. EINVAL,
  2337. "an array of strings is expected: %s",
  2338. ucl_object_key (obj));
  2339. return FALSE;
  2340. }
  2341. if (!is_hash && *target != NULL) {
  2342. *target = g_list_reverse (*target);
  2343. if (need_destructor) {
  2344. rspamd_mempool_add_destructor (pool,
  2345. (rspamd_mempool_destruct_t) g_list_free,
  2346. *target);
  2347. }
  2348. }
  2349. return TRUE;
  2350. }
  2351. gboolean
  2352. rspamd_rcl_parse_struct_boolean (rspamd_mempool_t *pool,
  2353. const ucl_object_t *obj,
  2354. gpointer ud,
  2355. struct rspamd_rcl_section *section,
  2356. GError **err)
  2357. {
  2358. struct rspamd_rcl_struct_parser *pd = ud;
  2359. gboolean *target;
  2360. target = (gboolean *)(((gchar *)pd->user_struct) + pd->offset);
  2361. if (obj->type == UCL_BOOLEAN) {
  2362. *target = obj->value.iv;
  2363. }
  2364. else if (obj->type == UCL_INT) {
  2365. *target = obj->value.iv;
  2366. }
  2367. else {
  2368. g_set_error (err,
  2369. CFG_RCL_ERROR,
  2370. EINVAL,
  2371. "cannot convert an object to boolean: %s",
  2372. ucl_object_key (obj));
  2373. return FALSE;
  2374. }
  2375. if (pd->flags & RSPAMD_CL_FLAG_BOOLEAN_INVERSE) {
  2376. *target = !*target;
  2377. }
  2378. return TRUE;
  2379. }
  2380. gboolean
  2381. rspamd_rcl_parse_struct_addr (rspamd_mempool_t *pool,
  2382. const ucl_object_t *obj,
  2383. gpointer ud,
  2384. struct rspamd_rcl_section *section,
  2385. GError **err)
  2386. {
  2387. struct rspamd_rcl_struct_parser *pd = ud;
  2388. rspamd_inet_addr_t **target;
  2389. const gchar *val;
  2390. target = (rspamd_inet_addr_t **)(((gchar *)pd->user_struct) + pd->offset);
  2391. if (ucl_object_type (obj) == UCL_STRING) {
  2392. val = ucl_object_tostring (obj);
  2393. if (!rspamd_parse_inet_address (target, val, 0)) {
  2394. g_set_error (err,
  2395. CFG_RCL_ERROR,
  2396. EINVAL,
  2397. "cannot parse inet address: %s", val);
  2398. return FALSE;
  2399. }
  2400. }
  2401. else {
  2402. g_set_error (err,
  2403. CFG_RCL_ERROR,
  2404. EINVAL,
  2405. "cannot convert an object to inet address: %s",
  2406. ucl_object_key (obj));
  2407. return FALSE;
  2408. }
  2409. return TRUE;
  2410. }
  2411. gboolean
  2412. rspamd_rcl_parse_struct_mime_addr (rspamd_mempool_t *pool,
  2413. const ucl_object_t *obj,
  2414. gpointer ud,
  2415. struct rspamd_rcl_section *section,
  2416. GError **err)
  2417. {
  2418. struct rspamd_rcl_struct_parser *pd = ud;
  2419. InternetAddressList **target, *tmp_addr;
  2420. const gchar *val;
  2421. ucl_object_iter_t it;
  2422. const ucl_object_t *cur;
  2423. target = (InternetAddressList **)(((gchar *)pd->user_struct) + pd->offset);
  2424. if (*target == NULL) {
  2425. *target = internet_address_list_new ();
  2426. #ifdef GMIME24
  2427. rspamd_mempool_add_destructor (pool,
  2428. (rspamd_mempool_destruct_t) g_object_unref,
  2429. *target);
  2430. #else
  2431. rspamd_mempool_add_destructor (pool,
  2432. (rspamd_mempool_destruct_t) internet_address_list_destroy,
  2433. *target);
  2434. #endif
  2435. }
  2436. it = ucl_object_iterate_new (obj);
  2437. while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
  2438. if (ucl_object_type (cur) == UCL_STRING) {
  2439. val = ucl_object_tostring (obj);
  2440. tmp_addr = internet_address_list_parse_string (val);
  2441. if (tmp_addr) {
  2442. internet_address_list_append (*target, tmp_addr);
  2443. #ifdef GMIME24
  2444. g_object_unref (tmp_addr);
  2445. #else
  2446. internet_address_list_destroy (tmp_addr);
  2447. #endif
  2448. }
  2449. else {
  2450. g_set_error (err,
  2451. CFG_RCL_ERROR,
  2452. EINVAL,
  2453. "cannot parse inet address: %s in %s", val,
  2454. ucl_object_key (obj));
  2455. ucl_object_iterate_free (it);
  2456. return FALSE;
  2457. }
  2458. }
  2459. else {
  2460. g_set_error (err,
  2461. CFG_RCL_ERROR,
  2462. EINVAL,
  2463. "cannot get inet address from ucl object in %s",
  2464. ucl_object_key (obj));
  2465. ucl_object_iterate_free (it);
  2466. return FALSE;
  2467. }
  2468. }
  2469. ucl_object_iterate_free (it);
  2470. return TRUE;
  2471. }
  2472. static guint
  2473. rspamd_worker_param_key_hash (gconstpointer p)
  2474. {
  2475. const struct rspamd_worker_param_key *k = p;
  2476. XXH64_state_t st;
  2477. XXH64_reset (&st, rspamd_hash_seed ());
  2478. XXH64_update (&st, k->name, strlen (k->name));
  2479. XXH64_update (&st, &k->ptr, sizeof (gpointer));
  2480. return XXH64_digest (&st);
  2481. }
  2482. static gboolean
  2483. rspamd_worker_param_key_equal (gconstpointer p1, gconstpointer p2)
  2484. {
  2485. const struct rspamd_worker_param_key *k1 = p1, *k2 = p2;
  2486. if (k1->ptr == k2->ptr) {
  2487. return strcmp (k1->name, k2->name) == 0;
  2488. }
  2489. return FALSE;
  2490. }
  2491. void
  2492. rspamd_rcl_register_worker_option (struct rspamd_config *cfg,
  2493. GQuark type,
  2494. const gchar *name,
  2495. rspamd_rcl_default_handler_t handler,
  2496. gpointer target,
  2497. glong offset,
  2498. gint flags,
  2499. const gchar *doc_string)
  2500. {
  2501. struct rspamd_worker_param_parser *nhandler;
  2502. struct rspamd_worker_cfg_parser *nparser;
  2503. struct rspamd_worker_param_key srch;
  2504. const ucl_object_t *doc_workers, *doc_target;
  2505. ucl_object_t *doc_obj;
  2506. nparser = g_hash_table_lookup (cfg->wrk_parsers, &type);
  2507. if (nparser == NULL) {
  2508. rspamd_rcl_register_worker_parser (cfg, type, NULL, NULL);
  2509. nparser = g_hash_table_lookup (cfg->wrk_parsers, &type);
  2510. g_assert (nparser != NULL);
  2511. }
  2512. srch.name = name;
  2513. srch.ptr = target;
  2514. nhandler = g_hash_table_lookup (nparser->parsers, &srch);
  2515. if (nhandler != NULL) {
  2516. msg_warn_config (
  2517. "handler for parameter %s is already registered for worker type %s",
  2518. name,
  2519. g_quark_to_string (type));
  2520. return;
  2521. }
  2522. nhandler =
  2523. rspamd_mempool_alloc0 (cfg->cfg_pool,
  2524. sizeof (struct rspamd_worker_param_parser));
  2525. nhandler->key.name = name;
  2526. nhandler->key.ptr = target;
  2527. nhandler->parser.flags = flags;
  2528. nhandler->parser.offset = offset;
  2529. nhandler->parser.user_struct = target;
  2530. nhandler->handler = handler;
  2531. g_hash_table_insert (nparser->parsers, &nhandler->key, nhandler);
  2532. doc_workers = ucl_object_find_key (cfg->doc_strings, "workers");
  2533. if (doc_workers == NULL) {
  2534. doc_obj = ucl_object_typed_new (UCL_OBJECT);
  2535. ucl_object_insert_key (cfg->doc_strings, doc_obj, "workers", 0, false);
  2536. doc_workers = doc_obj;
  2537. }
  2538. doc_target = ucl_object_find_key (doc_workers, g_quark_to_string (type));
  2539. if (doc_target == NULL) {
  2540. doc_obj = ucl_object_typed_new (UCL_OBJECT);
  2541. ucl_object_insert_key ((ucl_object_t *)doc_workers, doc_obj,
  2542. g_quark_to_string (type), 0, true);
  2543. doc_target = doc_obj;
  2544. }
  2545. rspamd_rcl_add_doc_obj ((ucl_object_t *) doc_target,
  2546. doc_string,
  2547. name,
  2548. UCL_NULL,
  2549. handler,
  2550. flags,
  2551. NULL,
  2552. 0);
  2553. }
  2554. void
  2555. rspamd_rcl_register_worker_parser (struct rspamd_config *cfg, gint type,
  2556. gboolean (*func)(ucl_object_t *, gpointer), gpointer ud)
  2557. {
  2558. struct rspamd_worker_cfg_parser *nparser;
  2559. nparser = g_hash_table_lookup (cfg->wrk_parsers, &type);
  2560. if (nparser == NULL) {
  2561. /* Allocate new parser for this worker */
  2562. nparser =
  2563. rspamd_mempool_alloc0 (cfg->cfg_pool,
  2564. sizeof (struct rspamd_worker_cfg_parser));
  2565. nparser->type = type;
  2566. nparser->parsers = g_hash_table_new (rspamd_worker_param_key_hash,
  2567. rspamd_worker_param_key_equal);
  2568. rspamd_mempool_add_destructor (cfg->cfg_pool,
  2569. (rspamd_mempool_destruct_t)g_hash_table_unref, nparser->parsers);
  2570. g_hash_table_insert (cfg->wrk_parsers, &nparser->type, nparser);
  2571. }
  2572. nparser->def_obj_parser = func;
  2573. nparser->def_ud = ud;
  2574. }
  2575. gboolean
  2576. rspamd_config_read (struct rspamd_config *cfg, const gchar *filename,
  2577. const gchar *convert_to, rspamd_rcl_section_fin_t logger_fin,
  2578. gpointer logger_ud, GHashTable *vars)
  2579. {
  2580. struct stat st;
  2581. gint fd;
  2582. gchar *data;
  2583. GError *err = NULL;
  2584. struct rspamd_rcl_section *top, *logger;
  2585. struct ucl_parser *parser;
  2586. unsigned char cksumbuf[rspamd_cryptobox_HASHBYTES];
  2587. if (stat (filename, &st) == -1) {
  2588. msg_err_config ("cannot stat %s: %s", filename, strerror (errno));
  2589. return FALSE;
  2590. }
  2591. if ((fd = open (filename, O_RDONLY)) == -1) {
  2592. msg_err_config ("cannot open %s: %s", filename, strerror (errno));
  2593. return FALSE;
  2594. }
  2595. /* Now mmap this file to simplify reading process */
  2596. if ((data =
  2597. mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
  2598. msg_err_config ("cannot mmap %s: %s", filename, strerror (errno));
  2599. close (fd);
  2600. return FALSE;
  2601. }
  2602. close (fd);
  2603. rspamd_cryptobox_hash (cksumbuf, data, st.st_size, NULL, 0);
  2604. cfg->checksum = rspamd_encode_base32 (cksumbuf, sizeof (cksumbuf));
  2605. /* Also change the tag of cfg pool to be equal to the checksum */
  2606. rspamd_strlcpy (cfg->cfg_pool->tag.uid, cfg->checksum,
  2607. MIN (sizeof (cfg->cfg_pool->tag.uid), strlen (cfg->checksum)));
  2608. parser = ucl_parser_new (0);
  2609. rspamd_ucl_add_conf_variables (parser, vars);
  2610. rspamd_ucl_add_conf_macros (parser, cfg);
  2611. if (!ucl_parser_add_chunk (parser, data, st.st_size)) {
  2612. msg_err_config ("ucl parser error: %s", ucl_parser_get_error (parser));
  2613. ucl_parser_free (parser);
  2614. munmap (data, st.st_size);
  2615. return FALSE;
  2616. }
  2617. munmap (data, st.st_size);
  2618. cfg->rcl_obj = ucl_parser_get_object (parser);
  2619. ucl_parser_free (parser);
  2620. top = rspamd_rcl_config_init (cfg);
  2621. rspamd_rcl_set_lua_globals (cfg, cfg->lua_state, vars);
  2622. err = NULL;
  2623. if (logger_fin != NULL) {
  2624. HASH_FIND_STR (top, "logging", logger);
  2625. if (logger != NULL) {
  2626. logger->fin = logger_fin;
  2627. logger->fin_ud = logger_ud;
  2628. }
  2629. }
  2630. if (!rspamd_rcl_parse (top, cfg, cfg->cfg_pool, cfg->rcl_obj, &err)) {
  2631. msg_err_config ("rcl parse error: %e", err);
  2632. g_error_free (err);
  2633. return FALSE;
  2634. }
  2635. return TRUE;
  2636. }
  2637. static void
  2638. rspamd_rcl_doc_obj_from_handler (ucl_object_t *doc_obj,
  2639. rspamd_rcl_default_handler_t handler,
  2640. gint flags)
  2641. {
  2642. gboolean has_example = FALSE, has_type = FALSE;
  2643. const gchar *type = NULL;
  2644. if (ucl_object_find_key (doc_obj, "example") != NULL) {
  2645. has_example = TRUE;
  2646. }
  2647. if (ucl_object_find_key (doc_obj, "type") != NULL) {
  2648. has_type = TRUE;
  2649. }
  2650. if (handler == rspamd_rcl_parse_struct_string) {
  2651. if (!has_type) {
  2652. ucl_object_insert_key (doc_obj, ucl_object_fromstring ("string"),
  2653. "type", 0, false);
  2654. }
  2655. }
  2656. else if (handler == rspamd_rcl_parse_struct_integer) {
  2657. type = "int";
  2658. if (flags & RSPAMD_CL_FLAG_INT_16) {
  2659. type = "int16";
  2660. }
  2661. else if (flags & RSPAMD_CL_FLAG_INT_32) {
  2662. type = "int32";
  2663. }
  2664. else if (flags & RSPAMD_CL_FLAG_INT_64) {
  2665. type = "int64";
  2666. }
  2667. else if (flags & RSPAMD_CL_FLAG_INT_SIZE) {
  2668. type = "size";
  2669. }
  2670. else if (flags & RSPAMD_CL_FLAG_UINT) {
  2671. type = "uint";
  2672. }
  2673. if (!has_type) {
  2674. ucl_object_insert_key (doc_obj, ucl_object_fromstring (type),
  2675. "type", 0, false);
  2676. }
  2677. }
  2678. else if (handler == rspamd_rcl_parse_struct_double) {
  2679. if (!has_type) {
  2680. ucl_object_insert_key (doc_obj, ucl_object_fromstring ("double"),
  2681. "type", 0, false);
  2682. }
  2683. }
  2684. else if (handler == rspamd_rcl_parse_struct_time) {
  2685. type = "time";
  2686. if (!has_type) {
  2687. ucl_object_insert_key (doc_obj, ucl_object_fromstring (type),
  2688. "type", 0, false);
  2689. }
  2690. }
  2691. else if (handler == rspamd_rcl_parse_struct_string_list) {
  2692. if (!has_type) {
  2693. ucl_object_insert_key (doc_obj, ucl_object_fromstring ("string list"),
  2694. "type", 0, false);
  2695. }
  2696. if (!has_example) {
  2697. ucl_object_insert_key (doc_obj,
  2698. ucl_object_fromstring_common ("param = \"str1, str2, str3\" OR "
  2699. "param = [\"str1\", \"str2\", \"str3\"]", 0, 0),
  2700. "example",
  2701. 0,
  2702. false);
  2703. }
  2704. }
  2705. else if (handler == rspamd_rcl_parse_struct_boolean) {
  2706. if (!has_type) {
  2707. ucl_object_insert_key (doc_obj,
  2708. ucl_object_fromstring ("bool"),
  2709. "type",
  2710. 0,
  2711. false);
  2712. }
  2713. }
  2714. else if (handler == rspamd_rcl_parse_struct_keypair) {
  2715. if (!has_type) {
  2716. ucl_object_insert_key (doc_obj,
  2717. ucl_object_fromstring ("keypair"),
  2718. "type",
  2719. 0,
  2720. false);
  2721. }
  2722. if (!has_example) {
  2723. ucl_object_insert_key (doc_obj,
  2724. ucl_object_fromstring ("keypair { "
  2725. "pubkey = <base32_string>;"
  2726. " privkey = <base32_string>; "
  2727. "}"),
  2728. "example",
  2729. 0,
  2730. false);
  2731. }
  2732. }
  2733. else if (handler == rspamd_rcl_parse_struct_addr) {
  2734. if (!has_type) {
  2735. ucl_object_insert_key (doc_obj,
  2736. ucl_object_fromstring ("socket address"),
  2737. "type",
  2738. 0,
  2739. false);
  2740. }
  2741. }
  2742. else if (handler == rspamd_rcl_parse_struct_mime_addr) {
  2743. if (!has_type) {
  2744. ucl_object_insert_key (doc_obj,
  2745. ucl_object_fromstring ("email address"),
  2746. "type",
  2747. 0,
  2748. false);
  2749. }
  2750. }
  2751. }
  2752. ucl_object_t *
  2753. rspamd_rcl_add_doc_obj (ucl_object_t *doc_target,
  2754. const char *doc_string,
  2755. const char *doc_name,
  2756. ucl_type_t type,
  2757. rspamd_rcl_default_handler_t handler,
  2758. gint flags,
  2759. const char *default_value,
  2760. gboolean required)
  2761. {
  2762. ucl_object_t *doc_obj;
  2763. if (doc_target == NULL || doc_name == NULL) {
  2764. return NULL;
  2765. }
  2766. doc_obj = ucl_object_typed_new (UCL_OBJECT);
  2767. /* Insert doc string itself */
  2768. if (doc_string) {
  2769. ucl_object_insert_key (doc_obj,
  2770. ucl_object_fromstring_common (doc_string, 0, 0),
  2771. "data", 0, false);
  2772. }
  2773. else {
  2774. ucl_object_insert_key (doc_obj, ucl_object_fromstring ("undocumented"),
  2775. "data", 0, false);
  2776. }
  2777. if (type != UCL_NULL) {
  2778. ucl_object_insert_key (doc_obj,
  2779. ucl_object_fromstring (ucl_object_type_to_string (type)),
  2780. "type", 0, false);
  2781. }
  2782. rspamd_rcl_doc_obj_from_handler (doc_obj, handler, flags);
  2783. ucl_object_insert_key (doc_obj,
  2784. ucl_object_frombool (required),
  2785. "required", 0, false);
  2786. if (default_value) {
  2787. ucl_object_insert_key (doc_obj,
  2788. ucl_object_fromstring_common (default_value, 0, 0),
  2789. "default", 0, false);
  2790. }
  2791. ucl_object_insert_key (doc_target, doc_obj, doc_name, 0, true);
  2792. return doc_obj;
  2793. }
  2794. ucl_object_t *
  2795. rspamd_rcl_add_doc_by_path (struct rspamd_config *cfg,
  2796. const gchar *doc_path,
  2797. const char *doc_string,
  2798. const char *doc_name,
  2799. ucl_type_t type,
  2800. rspamd_rcl_default_handler_t handler,
  2801. gint flags,
  2802. const char *default_value,
  2803. gboolean required)
  2804. {
  2805. const ucl_object_t *found, *cur;
  2806. ucl_object_t *obj;
  2807. gchar **path_components, **comp;
  2808. if (doc_path == NULL) {
  2809. /* Assume top object */
  2810. return rspamd_rcl_add_doc_obj (cfg->doc_strings,
  2811. doc_string,
  2812. doc_name,
  2813. type,
  2814. handler,
  2815. flags,
  2816. default_value,
  2817. required);
  2818. }
  2819. else {
  2820. found = ucl_lookup_path (cfg->doc_strings, doc_path);
  2821. if (found != NULL) {
  2822. return rspamd_rcl_add_doc_obj ((ucl_object_t *) found,
  2823. doc_string,
  2824. doc_name,
  2825. type,
  2826. handler,
  2827. flags,
  2828. default_value,
  2829. required);
  2830. }
  2831. /* Otherwise we need to insert all components of the path */
  2832. path_components = g_strsplit_set (doc_path, ".", -1);
  2833. cur = cfg->doc_strings;
  2834. for (comp = path_components; *comp != NULL; comp++) {
  2835. if (ucl_object_type (cur) != UCL_OBJECT) {
  2836. msg_err_config ("Bad path while lookup for '%s' at %s",
  2837. doc_path, *comp);
  2838. return NULL;
  2839. }
  2840. found = ucl_object_find_key (cur, *comp);
  2841. if (found == NULL) {
  2842. obj = ucl_object_typed_new (UCL_OBJECT);
  2843. ucl_object_insert_key ((ucl_object_t *) cur,
  2844. obj,
  2845. *comp,
  2846. 0,
  2847. true);
  2848. cur = obj;
  2849. }
  2850. else {
  2851. cur = found;
  2852. }
  2853. }
  2854. }
  2855. return rspamd_rcl_add_doc_obj ((ucl_object_t *) cur,
  2856. doc_string,
  2857. doc_name,
  2858. type,
  2859. handler,
  2860. flags,
  2861. default_value,
  2862. required);
  2863. }