Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

8 роки тому
8 роки тому
8 роки тому
10 роки тому
9 роки тому
9 роки тому
9 роки тому
7 роки тому
9 роки тому
9 роки тому
9 роки тому
9 роки тому
9 роки тому
9 роки тому
9 роки тому
9 роки тому
11 роки тому
11 роки тому
10 роки тому
11 роки тому
8 роки тому
10 роки тому
11 роки тому
8 роки тому
11 роки тому
11 роки тому
11 роки тому
8 роки тому
10 роки тому
11 роки тому
11 роки тому
11 роки тому
11 роки тому
11 роки тому
11 роки тому
11 роки тому
11 роки тому
11 роки тому
11 роки тому
11 роки тому
11 роки тому
11 роки тому
11 роки тому
11 роки тому
11 роки тому
11 роки тому
11 роки тому
8 роки тому
11 роки тому
8 роки тому
10 роки тому
11 роки тому
11 роки тому
11 роки тому
11 роки тому
8 роки тому
10 роки тому
10 роки тому
6 роки тому
6 роки тому
10 роки тому
6 роки тому
6 роки тому
6 роки тому
10 роки тому
6 роки тому
6 роки тому
6 роки тому
10 роки тому
8 роки тому
8 роки тому
9 роки тому
6 роки тому
6 роки тому
9 роки тому
10 роки тому
9 роки тому
9 роки тому
6 роки тому
9 роки тому
9 роки тому
9 роки тому
9 роки тому
10 роки тому
10 роки тому
8 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
8 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
8 роки тому
9 роки тому
8 роки тому
9 роки тому
8 роки тому
8 роки тому
8 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
8 роки тому
5 роки тому
5 роки тому
5 роки тому
5 роки тому
10 роки тому
5 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
7 роки тому
7 роки тому
7 роки тому
10 роки тому
10 роки тому
8 роки тому
8 роки тому
8 роки тому
10 роки тому
8 роки тому
8 роки тому
8 роки тому
7 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
3 роки тому
10 роки тому
10 роки тому
11 роки тому
11 роки тому
11 роки тому
11 роки тому
7 роки тому
7 роки тому
7 роки тому
11 роки тому
10 роки тому
5 роки тому
5 роки тому
9 роки тому
8 роки тому
10 роки тому
8 роки тому
10 роки тому
8 роки тому
8 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
7 роки тому
10 роки тому
10 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
7 роки тому
7 роки тому
7 роки тому
5 роки тому
9 роки тому
9 роки тому
9 роки тому
9 роки тому
9 роки тому
9 роки тому
9 роки тому
9 роки тому
9 роки тому
9 роки тому
9 роки тому
9 роки тому
9 роки тому
6 роки тому
8 роки тому
9 роки тому
9 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277
  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 "cfg_file_private.h"
  19. #include "utlist.h"
  20. #include "cfg_file.h"
  21. #include "lua/lua_common.h"
  22. #include "expression.h"
  23. #include "src/libserver/composites/composites.h"
  24. #include "libserver/worker_util.h"
  25. #include "unix-std.h"
  26. #include "cryptobox.h"
  27. #include "libutil/multipattern.h"
  28. #include "libmime/email_addr.h"
  29. #include "libmime/lang_detection.h"
  30. #ifdef HAVE_SYSLOG_H
  31. #include <syslog.h>
  32. #endif
  33. #include <math.h>
  34. struct rspamd_rcl_default_handler_data {
  35. struct rspamd_rcl_struct_parser pd;
  36. gchar *key;
  37. rspamd_rcl_default_handler_t handler;
  38. UT_hash_handle hh;
  39. };
  40. struct rspamd_rcl_section {
  41. const gchar *name; /**< name of section */
  42. const gchar *key_attr;
  43. const gchar *default_key;
  44. rspamd_rcl_handler_t handler; /**< handler of section attributes */
  45. enum ucl_type type; /**< type of attribute */
  46. gboolean required; /**< whether this param is required */
  47. gboolean strict_type; /**< whether we need strict type */
  48. UT_hash_handle hh; /** hash handle */
  49. struct rspamd_rcl_section *subsections; /**< hash table of subsections */
  50. struct rspamd_rcl_default_handler_data *default_parser; /**< generic parsing fields */
  51. rspamd_rcl_section_fin_t fin; /** called at the end of section parsing */
  52. gpointer fin_ud;
  53. ucl_object_t *doc_ref; /**< reference to the section's documentation */
  54. };
  55. struct rspamd_worker_param_key {
  56. const gchar *name;
  57. gpointer ptr;
  58. };
  59. struct rspamd_worker_param_parser {
  60. rspamd_rcl_default_handler_t handler; /**< handler function */
  61. struct rspamd_rcl_struct_parser parser; /**< parser attributes */
  62. struct rspamd_worker_param_key key;
  63. };
  64. struct rspamd_worker_cfg_parser {
  65. GHashTable *parsers; /**< parsers hash */
  66. gint type; /**< workers quark */
  67. gboolean (*def_obj_parser)(ucl_object_t *obj, gpointer ud); /**<
  68. default object parser */
  69. gpointer def_ud;
  70. };
  71. static gboolean rspamd_rcl_process_section (struct rspamd_config *cfg,
  72. struct rspamd_rcl_section *sec,
  73. gpointer ptr, const ucl_object_t *obj, rspamd_mempool_t *pool,
  74. GError **err);
  75. /*
  76. * Common section handlers
  77. */
  78. static gboolean
  79. rspamd_rcl_logging_handler (rspamd_mempool_t *pool, const ucl_object_t *obj,
  80. const gchar *key, gpointer ud, struct rspamd_rcl_section *section,
  81. GError **err)
  82. {
  83. const ucl_object_t *val;
  84. const gchar *facility = NULL, *log_type = NULL, *log_level = NULL;
  85. struct rspamd_config *cfg = ud;
  86. val = ucl_object_lookup (obj, "type");
  87. if (val != NULL && ucl_object_tostring_safe (val, &log_type)) {
  88. if (g_ascii_strcasecmp (log_type, "file") == 0) {
  89. /* Need to get filename */
  90. val = ucl_object_lookup (obj, "filename");
  91. if (val == NULL || val->type != UCL_STRING) {
  92. g_set_error (err,
  93. CFG_RCL_ERROR,
  94. ENOENT,
  95. "filename attribute must be specified for file logging type");
  96. return FALSE;
  97. }
  98. cfg->log_type = RSPAMD_LOG_FILE;
  99. cfg->log_file = rspamd_mempool_strdup (cfg->cfg_pool,
  100. ucl_object_tostring (val));
  101. }
  102. else if (g_ascii_strcasecmp (log_type, "syslog") == 0) {
  103. /* Need to get facility */
  104. #ifdef HAVE_SYSLOG_H
  105. cfg->log_facility = LOG_DAEMON;
  106. cfg->log_type = RSPAMD_LOG_SYSLOG;
  107. val = ucl_object_lookup (obj, "facility");
  108. if (val != NULL && ucl_object_tostring_safe (val, &facility)) {
  109. if (g_ascii_strcasecmp (facility, "LOG_AUTH") == 0 ||
  110. g_ascii_strcasecmp (facility, "auth") == 0 ) {
  111. cfg->log_facility = LOG_AUTH;
  112. }
  113. else if (g_ascii_strcasecmp (facility, "LOG_CRON") == 0 ||
  114. g_ascii_strcasecmp (facility, "cron") == 0 ) {
  115. cfg->log_facility = LOG_CRON;
  116. }
  117. else if (g_ascii_strcasecmp (facility, "LOG_DAEMON") == 0 ||
  118. g_ascii_strcasecmp (facility, "daemon") == 0 ) {
  119. cfg->log_facility = LOG_DAEMON;
  120. }
  121. else if (g_ascii_strcasecmp (facility, "LOG_MAIL") == 0 ||
  122. g_ascii_strcasecmp (facility, "mail") == 0) {
  123. cfg->log_facility = LOG_MAIL;
  124. }
  125. else if (g_ascii_strcasecmp (facility, "LOG_USER") == 0 ||
  126. g_ascii_strcasecmp (facility, "user") == 0 ) {
  127. cfg->log_facility = LOG_USER;
  128. }
  129. else if (g_ascii_strcasecmp (facility, "LOG_LOCAL0") == 0 ||
  130. g_ascii_strcasecmp (facility, "local0") == 0) {
  131. cfg->log_facility = LOG_LOCAL0;
  132. }
  133. else if (g_ascii_strcasecmp (facility, "LOG_LOCAL1") == 0 ||
  134. g_ascii_strcasecmp (facility, "local1") == 0) {
  135. cfg->log_facility = LOG_LOCAL1;
  136. }
  137. else if (g_ascii_strcasecmp (facility, "LOG_LOCAL2") == 0 ||
  138. g_ascii_strcasecmp (facility, "local2") == 0) {
  139. cfg->log_facility = LOG_LOCAL2;
  140. }
  141. else if (g_ascii_strcasecmp (facility, "LOG_LOCAL3") == 0 ||
  142. g_ascii_strcasecmp (facility, "local3") == 0) {
  143. cfg->log_facility = LOG_LOCAL3;
  144. }
  145. else if (g_ascii_strcasecmp (facility, "LOG_LOCAL4") == 0 ||
  146. g_ascii_strcasecmp (facility, "local4") == 0) {
  147. cfg->log_facility = LOG_LOCAL4;
  148. }
  149. else if (g_ascii_strcasecmp (facility, "LOG_LOCAL5") == 0 ||
  150. g_ascii_strcasecmp (facility, "local5") == 0) {
  151. cfg->log_facility = LOG_LOCAL5;
  152. }
  153. else if (g_ascii_strcasecmp (facility, "LOG_LOCAL6") == 0 ||
  154. g_ascii_strcasecmp (facility, "local6") == 0) {
  155. cfg->log_facility = LOG_LOCAL6;
  156. }
  157. else if (g_ascii_strcasecmp (facility, "LOG_LOCAL7") == 0 ||
  158. g_ascii_strcasecmp (facility, "local7") == 0) {
  159. cfg->log_facility = LOG_LOCAL7;
  160. }
  161. else {
  162. g_set_error (err,
  163. CFG_RCL_ERROR,
  164. EINVAL,
  165. "invalid log facility: %s",
  166. facility);
  167. return FALSE;
  168. }
  169. }
  170. #endif
  171. }
  172. else if (g_ascii_strcasecmp (log_type,
  173. "stderr") == 0 || g_ascii_strcasecmp (log_type, "console") == 0) {
  174. cfg->log_type = RSPAMD_LOG_CONSOLE;
  175. }
  176. else {
  177. g_set_error (err,
  178. CFG_RCL_ERROR,
  179. EINVAL,
  180. "invalid log type: %s",
  181. log_type);
  182. return FALSE;
  183. }
  184. }
  185. else {
  186. /* No type specified */
  187. msg_warn_config (
  188. "logging type is not specified correctly, log output to the console");
  189. }
  190. /* Handle log level */
  191. val = ucl_object_lookup (obj, "level");
  192. if (val != NULL && ucl_object_tostring_safe (val, &log_level)) {
  193. if (g_ascii_strcasecmp (log_level, "error") == 0) {
  194. cfg->log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL;
  195. }
  196. else if (g_ascii_strcasecmp (log_level, "warning") == 0) {
  197. cfg->log_level = G_LOG_LEVEL_WARNING;
  198. }
  199. else if (g_ascii_strcasecmp (log_level, "info") == 0) {
  200. cfg->log_level = G_LOG_LEVEL_INFO | G_LOG_LEVEL_MESSAGE;
  201. }
  202. else if (g_ascii_strcasecmp (log_level, "message") == 0 ||
  203. g_ascii_strcasecmp (log_level, "notice") == 0) {
  204. cfg->log_level = G_LOG_LEVEL_MESSAGE;
  205. }
  206. else if (g_ascii_strcasecmp (log_level, "silent") == 0) {
  207. cfg->log_level = G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO;
  208. cfg->log_silent_workers = TRUE;
  209. }
  210. else if (g_ascii_strcasecmp (log_level, "debug") == 0) {
  211. cfg->log_level = G_LOG_LEVEL_DEBUG;
  212. }
  213. else {
  214. g_set_error (err,
  215. CFG_RCL_ERROR,
  216. EINVAL,
  217. "invalid log level: %s",
  218. log_level);
  219. return FALSE;
  220. }
  221. }
  222. /* Handle flags */
  223. val = ucl_object_lookup_any (obj, "color", "log_color", NULL);
  224. if (val && ucl_object_toboolean (val)) {
  225. cfg->log_flags |= RSPAMD_LOG_FLAG_COLOR;
  226. }
  227. val = ucl_object_lookup_any (obj, "severity", "log_severity", NULL);
  228. if (val && ucl_object_toboolean (val)) {
  229. cfg->log_flags |= RSPAMD_LOG_FLAG_SEVERITY;
  230. }
  231. val = ucl_object_lookup_any (obj, "systemd", "log_systemd", NULL);
  232. if (val && ucl_object_toboolean (val)) {
  233. cfg->log_flags |= RSPAMD_LOG_FLAG_SYSTEMD;
  234. }
  235. val = ucl_object_lookup (obj, "log_re_cache");
  236. if (val && ucl_object_toboolean (val)) {
  237. cfg->log_flags |= RSPAMD_LOG_FLAG_RE_CACHE;
  238. }
  239. val = ucl_object_lookup_any (obj, "usec", "log_usec", NULL);
  240. if (val && ucl_object_toboolean (val)) {
  241. cfg->log_flags |= RSPAMD_LOG_FLAG_USEC;
  242. }
  243. return rspamd_rcl_section_parse_defaults (cfg, section, cfg->cfg_pool, obj,
  244. cfg, err);
  245. }
  246. static gboolean
  247. rspamd_rcl_options_handler (rspamd_mempool_t *pool, const ucl_object_t *obj,
  248. const gchar *key, gpointer ud,
  249. struct rspamd_rcl_section *section, GError **err)
  250. {
  251. const ucl_object_t *dns, *upstream, *neighbours;
  252. struct rspamd_config *cfg = ud;
  253. struct rspamd_rcl_section *dns_section, *upstream_section, *neighbours_section;
  254. HASH_FIND_STR (section->subsections, "dns", dns_section);
  255. dns = ucl_object_lookup (obj, "dns");
  256. if (dns_section != NULL && dns != NULL) {
  257. if (!rspamd_rcl_section_parse_defaults (cfg,
  258. dns_section, cfg->cfg_pool, dns,
  259. cfg, err)) {
  260. return FALSE;
  261. }
  262. }
  263. HASH_FIND_STR (section->subsections, "upstream", upstream_section);
  264. upstream = ucl_object_lookup_any (obj, "upstream", "upstreams", NULL);
  265. if (upstream_section != NULL && upstream != NULL) {
  266. if (!rspamd_rcl_section_parse_defaults (cfg,
  267. upstream_section, cfg->cfg_pool,
  268. upstream, cfg, err)) {
  269. return FALSE;
  270. }
  271. }
  272. HASH_FIND_STR (section->subsections, "neighbours", neighbours_section);
  273. neighbours = ucl_object_lookup (obj, "neighbours");
  274. if (neighbours_section != NULL && neighbours != NULL) {
  275. const ucl_object_t *cur;
  276. LL_FOREACH (neighbours, cur) {
  277. if (!rspamd_rcl_process_section (cfg, neighbours_section, cfg, cur,
  278. pool, err)) {
  279. return FALSE;
  280. }
  281. }
  282. }
  283. if (rspamd_rcl_section_parse_defaults (cfg,
  284. section, cfg->cfg_pool, obj,
  285. cfg, err)) {
  286. /* We need to init this early */
  287. rspamd_multipattern_library_init (cfg->hs_cache_dir);
  288. return TRUE;
  289. }
  290. return FALSE;
  291. }
  292. struct rspamd_rcl_symbol_data {
  293. struct rspamd_symbols_group *gr;
  294. struct rspamd_config *cfg;
  295. };
  296. static gboolean
  297. rspamd_rcl_group_handler (rspamd_mempool_t *pool, const ucl_object_t *obj,
  298. const gchar *key, gpointer ud,
  299. struct rspamd_rcl_section *section, GError **err)
  300. {
  301. struct rspamd_config *cfg = ud;
  302. struct rspamd_symbols_group *gr;
  303. const ucl_object_t *val, *elt;
  304. struct rspamd_rcl_section *subsection;
  305. struct rspamd_rcl_symbol_data sd;
  306. const gchar *description = NULL;
  307. g_assert (key != NULL);
  308. gr = g_hash_table_lookup (cfg->groups, key);
  309. if (gr == NULL) {
  310. gr = rspamd_config_new_group (cfg, key);
  311. }
  312. if (!rspamd_rcl_section_parse_defaults (cfg, section, pool, obj,
  313. gr, err)) {
  314. return FALSE;
  315. }
  316. if ((elt = ucl_object_lookup (obj, "one_shot")) != NULL) {
  317. if (ucl_object_type (elt) != UCL_BOOLEAN) {
  318. g_set_error (err,
  319. CFG_RCL_ERROR,
  320. EINVAL,
  321. "one_shot attribute is not boolean for symbol: '%s'",
  322. key);
  323. return FALSE;
  324. }
  325. if (ucl_object_toboolean (elt)) {
  326. gr->flags |= RSPAMD_SYMBOL_GROUP_ONE_SHOT;
  327. }
  328. }
  329. if ((elt = ucl_object_lookup (obj, "disabled")) != NULL) {
  330. if (ucl_object_type (elt) != UCL_BOOLEAN) {
  331. g_set_error (err,
  332. CFG_RCL_ERROR,
  333. EINVAL,
  334. "disabled attribute is not boolean for symbol: '%s'",
  335. key);
  336. return FALSE;
  337. }
  338. if (ucl_object_toboolean (elt)) {
  339. gr->flags |= RSPAMD_SYMBOL_GROUP_DISABLED;
  340. }
  341. }
  342. if ((elt = ucl_object_lookup (obj, "enabled")) != NULL) {
  343. if (ucl_object_type (elt) != UCL_BOOLEAN) {
  344. g_set_error (err,
  345. CFG_RCL_ERROR,
  346. EINVAL,
  347. "enabled attribute is not boolean for symbol: '%s'",
  348. key);
  349. return FALSE;
  350. }
  351. if (!ucl_object_toboolean (elt)) {
  352. gr->flags |= RSPAMD_SYMBOL_GROUP_DISABLED;
  353. }
  354. }
  355. if ((elt = ucl_object_lookup (obj, "public")) != NULL) {
  356. if (ucl_object_type (elt) != UCL_BOOLEAN) {
  357. g_set_error (err,
  358. CFG_RCL_ERROR,
  359. EINVAL,
  360. "public attribute is not boolean for symbol: '%s'",
  361. key);
  362. return FALSE;
  363. }
  364. if (ucl_object_toboolean (elt)) {
  365. gr->flags |= RSPAMD_SYMBOL_GROUP_PUBLIC;
  366. }
  367. }
  368. if ((elt = ucl_object_lookup (obj, "private")) != NULL) {
  369. if (ucl_object_type (elt) != UCL_BOOLEAN) {
  370. g_set_error (err,
  371. CFG_RCL_ERROR,
  372. EINVAL,
  373. "private attribute is not boolean for symbol: '%s'",
  374. key);
  375. return FALSE;
  376. }
  377. if (!ucl_object_toboolean (elt)) {
  378. gr->flags |= RSPAMD_SYMBOL_GROUP_PUBLIC;
  379. }
  380. }
  381. elt = ucl_object_lookup (obj, "description");
  382. if (elt) {
  383. description = ucl_object_tostring (elt);
  384. gr->description = rspamd_mempool_strdup (cfg->cfg_pool,
  385. description);
  386. }
  387. sd.gr = gr;
  388. sd.cfg = cfg;
  389. /* Handle symbols */
  390. val = ucl_object_lookup (obj, "symbols");
  391. if (val != NULL && ucl_object_type (val) == UCL_OBJECT) {
  392. HASH_FIND_STR (section->subsections, "symbols", subsection);
  393. g_assert (subsection != NULL);
  394. if (!rspamd_rcl_process_section (cfg, subsection, &sd, val,
  395. pool, err)) {
  396. return FALSE;
  397. }
  398. }
  399. return TRUE;
  400. }
  401. static gboolean
  402. rspamd_rcl_symbol_handler (rspamd_mempool_t *pool, const ucl_object_t *obj,
  403. const gchar *key, gpointer ud,
  404. struct rspamd_rcl_section *section, GError **err)
  405. {
  406. struct rspamd_rcl_symbol_data *sd = ud;
  407. struct rspamd_config *cfg;
  408. const ucl_object_t *elt;
  409. const gchar *description = NULL;
  410. gdouble score = NAN;
  411. guint priority = 1, flags = 0;
  412. gint nshots = 0;
  413. g_assert (key != NULL);
  414. cfg = sd->cfg;
  415. if ((elt = ucl_object_lookup (obj, "one_shot")) != NULL) {
  416. if (ucl_object_type (elt) != UCL_BOOLEAN) {
  417. g_set_error (err,
  418. CFG_RCL_ERROR,
  419. EINVAL,
  420. "one_shot attribute is not boolean for symbol: '%s'",
  421. key);
  422. return FALSE;
  423. }
  424. if (ucl_object_toboolean (elt)) {
  425. nshots = 1;
  426. }
  427. }
  428. if ((elt = ucl_object_lookup (obj, "any_shot")) != NULL) {
  429. if (ucl_object_type (elt) != UCL_BOOLEAN) {
  430. g_set_error (err,
  431. CFG_RCL_ERROR,
  432. EINVAL,
  433. "any_shot attribute is not boolean for symbol: '%s'",
  434. key);
  435. return FALSE;
  436. }
  437. if (ucl_object_toboolean (elt)) {
  438. nshots = -1;
  439. }
  440. }
  441. if ((elt = ucl_object_lookup (obj, "one_param")) != NULL) {
  442. if (ucl_object_type (elt) != UCL_BOOLEAN) {
  443. g_set_error (err,
  444. CFG_RCL_ERROR,
  445. EINVAL,
  446. "one_param attribute is not boolean for symbol: '%s'",
  447. key);
  448. return FALSE;
  449. }
  450. if (ucl_object_toboolean (elt)) {
  451. flags |= RSPAMD_SYMBOL_FLAG_ONEPARAM;
  452. }
  453. }
  454. if ((elt = ucl_object_lookup (obj, "ignore")) != NULL) {
  455. if (ucl_object_type (elt) != UCL_BOOLEAN) {
  456. g_set_error (err,
  457. CFG_RCL_ERROR,
  458. EINVAL,
  459. "ignore attribute is not boolean for symbol: '%s'",
  460. key);
  461. return FALSE;
  462. }
  463. if (ucl_object_toboolean (elt)) {
  464. flags |= RSPAMD_SYMBOL_FLAG_IGNORE_METRIC;
  465. }
  466. }
  467. if ((elt = ucl_object_lookup (obj, "enabled")) != NULL) {
  468. if (ucl_object_type (elt) != UCL_BOOLEAN) {
  469. g_set_error (err,
  470. CFG_RCL_ERROR,
  471. EINVAL,
  472. "enabled attribute is not boolean for symbol: '%s'",
  473. key);
  474. return FALSE;
  475. }
  476. if (!ucl_object_toboolean (elt)) {
  477. flags |= RSPAMD_SYMBOL_FLAG_DISABLED;
  478. }
  479. }
  480. if ((elt = ucl_object_lookup (obj, "nshots")) != NULL) {
  481. if (ucl_object_type (elt) != UCL_FLOAT && ucl_object_type (elt) != UCL_INT) {
  482. g_set_error (err,
  483. CFG_RCL_ERROR,
  484. EINVAL,
  485. "nshots attribute is not numeric for symbol: '%s'",
  486. key);
  487. return FALSE;
  488. }
  489. nshots = ucl_object_toint (elt);
  490. }
  491. elt = ucl_object_lookup_any (obj, "score", "weight", NULL);
  492. if (elt) {
  493. if (ucl_object_type (elt) != UCL_FLOAT && ucl_object_type (elt) != UCL_INT) {
  494. g_set_error (err,
  495. CFG_RCL_ERROR,
  496. EINVAL,
  497. "score attribute is not numeric for symbol: '%s'",
  498. key);
  499. return FALSE;
  500. }
  501. score = ucl_object_todouble (elt);
  502. }
  503. elt = ucl_object_lookup (obj, "priority");
  504. if (elt) {
  505. if (ucl_object_type (elt) != UCL_FLOAT && ucl_object_type (elt) != UCL_INT) {
  506. g_set_error (err,
  507. CFG_RCL_ERROR,
  508. EINVAL,
  509. "priority attribute is not numeric for symbol: '%s'",
  510. key);
  511. return FALSE;
  512. }
  513. priority = ucl_object_toint (elt);
  514. }
  515. else {
  516. priority = ucl_object_get_priority (obj) + 1;
  517. }
  518. elt = ucl_object_lookup (obj, "description");
  519. if (elt) {
  520. description = ucl_object_tostring (elt);
  521. }
  522. if (sd->gr) {
  523. rspamd_config_add_symbol (cfg, key, score,
  524. description, sd->gr->name, flags, priority, nshots);
  525. }
  526. else {
  527. rspamd_config_add_symbol (cfg, key, score,
  528. description, NULL, flags, priority, nshots);
  529. }
  530. elt = ucl_object_lookup (obj, "groups");
  531. if (elt) {
  532. ucl_object_iter_t gr_it;
  533. const ucl_object_t *cur_gr;
  534. gr_it = ucl_object_iterate_new (elt);
  535. while ((cur_gr = ucl_object_iterate_safe (gr_it, true)) != NULL) {
  536. rspamd_config_add_symbol_group (cfg, key,
  537. ucl_object_tostring (cur_gr));
  538. }
  539. ucl_object_iterate_free (gr_it);
  540. }
  541. return TRUE;
  542. }
  543. static gboolean
  544. rspamd_rcl_actions_handler (rspamd_mempool_t *pool, const ucl_object_t *obj,
  545. const gchar *key, gpointer ud,
  546. struct rspamd_rcl_section *section, GError **err)
  547. {
  548. struct rspamd_config *cfg = ud;
  549. const ucl_object_t *cur;
  550. ucl_object_iter_t it;
  551. it = ucl_object_iterate_new (obj);
  552. while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
  553. gint type = ucl_object_type (cur);
  554. if (type == UCL_NULL) {
  555. rspamd_config_maybe_disable_action (cfg, ucl_object_key (cur),
  556. ucl_object_get_priority (cur));
  557. }
  558. else if (type == UCL_OBJECT || type == UCL_FLOAT || type == UCL_INT) {
  559. /* Exceptions */
  560. struct rspamd_rcl_default_handler_data *sec_cur, *sec_tmp;
  561. gboolean default_elt = FALSE;
  562. HASH_ITER (hh, section->default_parser, sec_cur, sec_tmp) {
  563. if (strcmp (ucl_object_key (cur), sec_cur->key) == 0) {
  564. default_elt = TRUE;
  565. }
  566. }
  567. if (default_elt) {
  568. continue;
  569. }
  570. /* Something non-default */
  571. if (!rspamd_config_set_action_score (cfg,
  572. ucl_object_key (cur),
  573. cur)) {
  574. g_set_error (err,
  575. CFG_RCL_ERROR,
  576. EINVAL,
  577. "invalid action definition for: '%s'",
  578. ucl_object_key (cur));
  579. ucl_object_iterate_free (it);
  580. return FALSE;
  581. }
  582. }
  583. }
  584. ucl_object_iterate_free (it);
  585. return rspamd_rcl_section_parse_defaults (cfg, section, pool, obj, cfg, err);
  586. }
  587. static gboolean
  588. rspamd_rcl_worker_handler (rspamd_mempool_t *pool, const ucl_object_t *obj,
  589. const gchar *key, gpointer ud,
  590. struct rspamd_rcl_section *section, GError **err)
  591. {
  592. const ucl_object_t *val, *cur, *cur_obj;
  593. ucl_object_t *robj;
  594. ucl_object_iter_t it = NULL;
  595. const gchar *worker_type, *worker_bind;
  596. struct rspamd_config *cfg = ud;
  597. GQuark qtype;
  598. struct rspamd_worker_conf *wrk;
  599. struct rspamd_worker_cfg_parser *wparser;
  600. struct rspamd_worker_param_parser *whandler;
  601. struct rspamd_worker_param_key srch;
  602. g_assert (key != NULL);
  603. worker_type = key;
  604. qtype = g_quark_try_string (worker_type);
  605. if (qtype != 0) {
  606. wrk = rspamd_config_new_worker (cfg, NULL);
  607. wrk->options = ucl_object_copy (obj);
  608. wrk->worker = rspamd_get_worker_by_type (cfg, qtype);
  609. if (wrk->worker == NULL) {
  610. g_set_error (err,
  611. CFG_RCL_ERROR,
  612. EINVAL,
  613. "unknown worker type: %s",
  614. worker_type);
  615. return FALSE;
  616. }
  617. wrk->type = qtype;
  618. if (wrk->worker->worker_init_func) {
  619. wrk->ctx = wrk->worker->worker_init_func (cfg);
  620. }
  621. }
  622. else {
  623. msg_err_config ("unknown worker type: %s", worker_type);
  624. return TRUE;
  625. }
  626. val = ucl_object_lookup_any (obj, "bind_socket", "listen", "bind", NULL);
  627. /* This name is more logical */
  628. if (val != NULL) {
  629. it = ucl_object_iterate_new (val);
  630. while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
  631. if (!ucl_object_tostring_safe (cur, &worker_bind)) {
  632. continue;
  633. }
  634. if (!rspamd_parse_bind_line (cfg, wrk, worker_bind)) {
  635. g_set_error (err,
  636. CFG_RCL_ERROR,
  637. EINVAL,
  638. "cannot parse bind line: %s",
  639. worker_bind);
  640. ucl_object_iterate_free (it);
  641. return FALSE;
  642. }
  643. }
  644. ucl_object_iterate_free (it);
  645. }
  646. if (!rspamd_rcl_section_parse_defaults (cfg, section, cfg->cfg_pool, obj,
  647. wrk, err)) {
  648. return FALSE;
  649. }
  650. /* Parse other attributes */
  651. wparser = g_hash_table_lookup (cfg->wrk_parsers, &qtype);
  652. if (wparser != NULL && obj->type == UCL_OBJECT) {
  653. it = ucl_object_iterate_new (obj);
  654. while ((cur = ucl_object_iterate_full (it, UCL_ITERATE_EXPLICIT)) != NULL) {
  655. srch.name = ucl_object_key (cur);
  656. srch.ptr = wrk->ctx; /* XXX: is it valid? */
  657. whandler = g_hash_table_lookup (wparser->parsers, &srch);
  658. if (whandler != NULL) {
  659. LL_FOREACH (cur, cur_obj) {
  660. if (!whandler->handler (cfg->cfg_pool,
  661. cur_obj,
  662. &whandler->parser,
  663. section,
  664. err)) {
  665. ucl_object_iterate_free (it);
  666. return FALSE;
  667. }
  668. if (!(whandler->parser.flags & RSPAMD_CL_FLAG_MULTIPLE)) {
  669. break;
  670. }
  671. }
  672. }
  673. }
  674. ucl_object_iterate_free (it);
  675. if (wparser->def_obj_parser != NULL) {
  676. robj = ucl_object_ref (obj);
  677. if (!wparser->def_obj_parser (robj, wparser->def_ud)) {
  678. ucl_object_unref (robj);
  679. return FALSE;
  680. }
  681. ucl_object_unref (robj);
  682. }
  683. }
  684. cfg->workers = g_list_prepend (cfg->workers, wrk);
  685. return TRUE;
  686. }
  687. static gboolean
  688. rspamd_rcl_lua_handler (rspamd_mempool_t *pool, const ucl_object_t *obj,
  689. const gchar *key, gpointer ud,
  690. struct rspamd_rcl_section *section, GError **err)
  691. {
  692. struct rspamd_config *cfg = ud;
  693. const gchar *lua_src = rspamd_mempool_strdup (pool,
  694. ucl_object_tostring (obj));
  695. gchar *cur_dir, *lua_dir, *lua_file, *tmp1, *tmp2;
  696. lua_State *L = cfg->lua_state;
  697. gint err_idx;
  698. tmp1 = g_strdup (lua_src);
  699. tmp2 = g_strdup (lua_src);
  700. lua_dir = dirname (tmp1);
  701. lua_file = basename (tmp2);
  702. if (lua_dir && lua_file) {
  703. cur_dir = g_malloc (PATH_MAX);
  704. if (getcwd (cur_dir, PATH_MAX) != NULL && chdir (lua_dir) != -1) {
  705. /* Push traceback function */
  706. lua_pushcfunction (L, &rspamd_lua_traceback);
  707. err_idx = lua_gettop (L);
  708. /* Load file */
  709. if (luaL_loadfile (L, lua_file) != 0) {
  710. g_set_error (err,
  711. CFG_RCL_ERROR,
  712. EINVAL,
  713. "cannot load lua file %s: %s",
  714. lua_src,
  715. lua_tostring (L, -1));
  716. if (chdir (cur_dir) == -1) {
  717. msg_err_config ("cannot chdir to %s: %s", cur_dir,
  718. strerror (errno));
  719. }
  720. g_free (cur_dir);
  721. g_free (tmp1);
  722. g_free (tmp2);
  723. return FALSE;
  724. }
  725. /* Now do it */
  726. if (lua_pcall (L, 0, 0, err_idx) != 0) {
  727. g_set_error (err,
  728. CFG_RCL_ERROR,
  729. EINVAL,
  730. "cannot init lua file %s: %s",
  731. lua_src,
  732. lua_tostring (L, -1));
  733. lua_settop (L, 0);
  734. if (chdir (cur_dir) == -1) {
  735. msg_err_config ("cannot chdir to %s: %s", cur_dir,
  736. strerror (errno));
  737. }
  738. g_free (cur_dir);
  739. g_free (tmp1);
  740. g_free (tmp2);
  741. return FALSE;
  742. }
  743. lua_pop (L, 1);
  744. }
  745. else {
  746. g_set_error (err, CFG_RCL_ERROR, ENOENT, "cannot chdir to %s: %s",
  747. lua_dir, strerror (errno));
  748. if (chdir (cur_dir) == -1) {
  749. msg_err_config ("cannot chdir to %s: %s", cur_dir, strerror (errno));
  750. }
  751. g_free (cur_dir);
  752. g_free (tmp1);
  753. g_free (tmp2);
  754. return FALSE;
  755. }
  756. if (chdir (cur_dir) == -1) {
  757. msg_err_config ("cannot chdir to %s: %s", cur_dir, strerror (errno));
  758. }
  759. g_free (cur_dir);
  760. g_free (tmp1);
  761. g_free (tmp2);
  762. }
  763. else {
  764. g_free (tmp1);
  765. g_free (tmp2);
  766. g_set_error (err, CFG_RCL_ERROR, ENOENT, "cannot find to %s: %s",
  767. lua_src, strerror (errno));
  768. return FALSE;
  769. }
  770. return TRUE;
  771. }
  772. gboolean
  773. rspamd_rcl_add_lua_plugins_path (struct rspamd_config *cfg,
  774. const gchar *path,
  775. gboolean main_path,
  776. GHashTable *modules_seen,
  777. GError **err)
  778. {
  779. struct stat st;
  780. struct script_module *cur_mod, *seen_mod;
  781. GPtrArray *paths;
  782. gchar *fname, *ext_pos;
  783. guint i;
  784. if (stat (path, &st) == -1) {
  785. if (errno != ENOENT || main_path) {
  786. g_set_error (err,
  787. CFG_RCL_ERROR,
  788. errno,
  789. "cannot stat path %s, %s",
  790. path,
  791. strerror (errno));
  792. return FALSE;
  793. }
  794. else {
  795. msg_debug_config ("optional plugins path %s is absent, skip it", path);
  796. return TRUE;
  797. }
  798. }
  799. /* Handle directory */
  800. if (S_ISDIR (st.st_mode)) {
  801. paths = rspamd_glob_path (path, "*.lua", TRUE, err);
  802. if (!paths) {
  803. return FALSE;
  804. }
  805. PTR_ARRAY_FOREACH (paths, i, fname) {
  806. cur_mod =
  807. rspamd_mempool_alloc (cfg->cfg_pool,
  808. sizeof (struct script_module));
  809. cur_mod->path = rspamd_mempool_strdup (cfg->cfg_pool, fname);
  810. cur_mod->name = g_path_get_basename (cur_mod->path);
  811. rspamd_mempool_add_destructor (cfg->cfg_pool, g_free,
  812. cur_mod->name);
  813. ext_pos = strstr (cur_mod->name, ".lua");
  814. if (ext_pos != NULL) {
  815. *ext_pos = '\0';
  816. }
  817. if (modules_seen) {
  818. seen_mod = g_hash_table_lookup (modules_seen, cur_mod->name);
  819. if (seen_mod != NULL) {
  820. msg_info_config ("already seen module %s at %s, skip %s",
  821. cur_mod->name, seen_mod->path, cur_mod->path);
  822. continue;
  823. }
  824. }
  825. if (cfg->script_modules == NULL) {
  826. cfg->script_modules = g_list_append (cfg->script_modules,
  827. cur_mod);
  828. rspamd_mempool_add_destructor (cfg->cfg_pool,
  829. (rspamd_mempool_destruct_t) g_list_free,
  830. cfg->script_modules);
  831. } else {
  832. cfg->script_modules = g_list_append (cfg->script_modules,
  833. cur_mod);
  834. }
  835. if (modules_seen) {
  836. g_hash_table_insert (modules_seen, cur_mod->name, cur_mod);
  837. }
  838. }
  839. g_ptr_array_free (paths, TRUE);
  840. }
  841. else {
  842. /* Handle single file */
  843. cur_mod =
  844. rspamd_mempool_alloc (cfg->cfg_pool, sizeof (struct script_module));
  845. cur_mod->path = rspamd_mempool_strdup (cfg->cfg_pool, path);
  846. cur_mod->name = g_path_get_basename (cur_mod->path);
  847. rspamd_mempool_add_destructor (cfg->cfg_pool, g_free,
  848. cur_mod->name);
  849. ext_pos = strstr (cur_mod->name, ".lua");
  850. if (ext_pos != NULL) {
  851. *ext_pos = '\0';
  852. }
  853. if (modules_seen) {
  854. seen_mod = g_hash_table_lookup (modules_seen, cur_mod->name);
  855. if (seen_mod != NULL) {
  856. msg_info_config ("already seen module %s at %s, skip %s",
  857. cur_mod->name, seen_mod->path, cur_mod->path);
  858. return TRUE;
  859. }
  860. }
  861. if (cfg->script_modules == NULL) {
  862. cfg->script_modules = g_list_append (cfg->script_modules,
  863. cur_mod);
  864. rspamd_mempool_add_destructor (cfg->cfg_pool,
  865. (rspamd_mempool_destruct_t)g_list_free,
  866. cfg->script_modules);
  867. }
  868. else {
  869. cfg->script_modules = g_list_append (cfg->script_modules,
  870. cur_mod);
  871. }
  872. if (modules_seen) {
  873. g_hash_table_insert (modules_seen, cur_mod->name, cur_mod);
  874. }
  875. }
  876. return TRUE;
  877. }
  878. static gboolean
  879. rspamd_rcl_modules_handler (rspamd_mempool_t *pool, const ucl_object_t *obj,
  880. const gchar *key, gpointer ud,
  881. struct rspamd_rcl_section *section, GError **err)
  882. {
  883. const ucl_object_t *val, *cur;
  884. struct rspamd_config *cfg = ud;
  885. const gchar *data;
  886. if (obj->type == UCL_OBJECT) {
  887. GHashTable *mods_seen = g_hash_table_new (rspamd_strcase_hash,
  888. rspamd_strcase_equal);
  889. val = ucl_object_lookup (obj, "path");
  890. if (val) {
  891. LL_FOREACH (val, cur) {
  892. if (ucl_object_tostring_safe (cur, &data)) {
  893. if (!rspamd_rcl_add_lua_plugins_path (cfg,
  894. rspamd_mempool_strdup (cfg->cfg_pool, data),
  895. TRUE,
  896. mods_seen,
  897. err)) {
  898. g_hash_table_unref (mods_seen);
  899. return FALSE;
  900. }
  901. }
  902. }
  903. }
  904. else {
  905. g_set_error (err,
  906. CFG_RCL_ERROR,
  907. EINVAL,
  908. "path attribute is missing");
  909. g_hash_table_unref (mods_seen);
  910. return FALSE;
  911. }
  912. val = ucl_object_lookup (obj, "fallback_path");
  913. if (val) {
  914. LL_FOREACH (val, cur) {
  915. if (ucl_object_tostring_safe (cur, &data)) {
  916. if (!rspamd_rcl_add_lua_plugins_path (cfg,
  917. rspamd_mempool_strdup (cfg->cfg_pool, data),
  918. FALSE,
  919. mods_seen,
  920. err)) {
  921. g_hash_table_unref (mods_seen);
  922. return FALSE;
  923. }
  924. }
  925. }
  926. }
  927. val = ucl_object_lookup (obj, "try_path");
  928. if (val) {
  929. LL_FOREACH (val, cur) {
  930. if (ucl_object_tostring_safe (cur, &data)) {
  931. if (!rspamd_rcl_add_lua_plugins_path (cfg,
  932. rspamd_mempool_strdup (cfg->cfg_pool, data),
  933. FALSE,
  934. mods_seen,
  935. err)) {
  936. g_hash_table_unref (mods_seen);
  937. return FALSE;
  938. }
  939. }
  940. }
  941. }
  942. g_hash_table_unref (mods_seen);
  943. }
  944. else if (ucl_object_tostring_safe (obj, &data)) {
  945. if (!rspamd_rcl_add_lua_plugins_path (cfg,
  946. rspamd_mempool_strdup (cfg->cfg_pool, data), TRUE, NULL, err)) {
  947. return FALSE;
  948. }
  949. }
  950. else {
  951. g_set_error (err,
  952. CFG_RCL_ERROR,
  953. EINVAL,
  954. "module parameter has wrong type (must be an object or a string)");
  955. return FALSE;
  956. }
  957. return TRUE;
  958. }
  959. struct statfile_parser_data {
  960. struct rspamd_config *cfg;
  961. struct rspamd_classifier_config *ccf;
  962. };
  963. static gboolean
  964. rspamd_rcl_statfile_handler (rspamd_mempool_t *pool, const ucl_object_t *obj,
  965. const gchar *key, gpointer ud,
  966. struct rspamd_rcl_section *section, GError **err)
  967. {
  968. struct statfile_parser_data *stud = ud;
  969. struct rspamd_classifier_config *ccf;
  970. struct rspamd_config *cfg;
  971. const ucl_object_t *val;
  972. struct rspamd_statfile_config *st;
  973. GList *labels;
  974. g_assert (key != NULL);
  975. cfg = stud->cfg;
  976. ccf = stud->ccf;
  977. st = rspamd_config_new_statfile (cfg, NULL);
  978. st->symbol = rspamd_mempool_strdup (cfg->cfg_pool, key);
  979. if (rspamd_rcl_section_parse_defaults (cfg, section, pool, obj, st, err)) {
  980. ccf->statfiles = rspamd_mempool_glist_prepend (pool, ccf->statfiles, st);
  981. if (st->label != NULL) {
  982. labels = g_hash_table_lookup (ccf->labels, st->label);
  983. if (labels != NULL) {
  984. labels = g_list_append (labels, st);
  985. }
  986. else {
  987. g_hash_table_insert (ccf->labels, st->label,
  988. g_list_prepend (NULL, st));
  989. }
  990. }
  991. if (st->symbol != NULL) {
  992. g_hash_table_insert (cfg->classifiers_symbols, st->symbol, st);
  993. }
  994. else {
  995. g_set_error (err,
  996. CFG_RCL_ERROR,
  997. EINVAL,
  998. "statfile must have a symbol defined");
  999. return FALSE;
  1000. }
  1001. st->opts = (ucl_object_t *)obj;
  1002. st->clcf = ccf;
  1003. val = ucl_object_lookup (obj, "spam");
  1004. if (val == NULL) {
  1005. msg_info_config (
  1006. "statfile %s has no explicit 'spam' setting, trying to guess by symbol",
  1007. st->symbol);
  1008. if (rspamd_substring_search_caseless (st->symbol,
  1009. strlen (st->symbol),"spam", 4) != -1) {
  1010. st->is_spam = TRUE;
  1011. }
  1012. else if (rspamd_substring_search_caseless (st->symbol,
  1013. strlen (st->symbol),"ham", 3) != -1) {
  1014. st->is_spam = FALSE;
  1015. }
  1016. else {
  1017. g_set_error (err,
  1018. CFG_RCL_ERROR,
  1019. EINVAL,
  1020. "cannot guess spam setting from %s",
  1021. st->symbol);
  1022. return FALSE;
  1023. }
  1024. msg_info_config ("guessed that statfile with symbol %s is %s",
  1025. st->symbol,
  1026. st->is_spam ?
  1027. "spam" : "ham");
  1028. }
  1029. return TRUE;
  1030. }
  1031. return FALSE;
  1032. }
  1033. static gboolean
  1034. rspamd_rcl_classifier_handler (rspamd_mempool_t *pool,
  1035. const ucl_object_t *obj,
  1036. const gchar *key,
  1037. gpointer ud,
  1038. struct rspamd_rcl_section *section,
  1039. GError **err)
  1040. {
  1041. const ucl_object_t *val, *cur;
  1042. ucl_object_iter_t it = NULL;
  1043. struct rspamd_config *cfg = ud;
  1044. struct statfile_parser_data stud;
  1045. const gchar *st_key;
  1046. struct rspamd_classifier_config *ccf;
  1047. gboolean res = TRUE;
  1048. struct rspamd_rcl_section *stat_section;
  1049. struct rspamd_tokenizer_config *tkcf = NULL;
  1050. lua_State *L = cfg->lua_state;
  1051. g_assert (key != NULL);
  1052. ccf = rspamd_config_new_classifier (cfg, NULL);
  1053. ccf->classifier = rspamd_mempool_strdup (cfg->cfg_pool, key);
  1054. if (rspamd_rcl_section_parse_defaults (cfg, section, cfg->cfg_pool, obj,
  1055. ccf, err)) {
  1056. HASH_FIND_STR (section->subsections, "statfile", stat_section);
  1057. if (ccf->classifier == NULL) {
  1058. ccf->classifier = "bayes";
  1059. }
  1060. if (ccf->name == NULL) {
  1061. ccf->name = ccf->classifier;
  1062. }
  1063. it = ucl_object_iterate_new (obj);
  1064. while ((val = ucl_object_iterate_safe (it, true)) != NULL && res) {
  1065. st_key = ucl_object_key (val);
  1066. if (st_key != NULL) {
  1067. if (g_ascii_strcasecmp (st_key, "statfile") == 0) {
  1068. LL_FOREACH (val, cur) {
  1069. stud.cfg = cfg;
  1070. stud.ccf = ccf;
  1071. res = rspamd_rcl_process_section (cfg, stat_section, &stud,
  1072. cur, cfg->cfg_pool, err);
  1073. if (!res) {
  1074. ucl_object_iterate_free (it);
  1075. return FALSE;
  1076. }
  1077. }
  1078. }
  1079. else if (g_ascii_strcasecmp (st_key, "tokenizer") == 0) {
  1080. tkcf = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*tkcf));
  1081. if (ucl_object_type (val) == UCL_STRING) {
  1082. tkcf->name = ucl_object_tostring (val);
  1083. }
  1084. else if (ucl_object_type (val) == UCL_OBJECT) {
  1085. cur = ucl_object_lookup (val, "name");
  1086. if (cur != NULL) {
  1087. tkcf->name = ucl_object_tostring (cur);
  1088. tkcf->opts = val;
  1089. }
  1090. else {
  1091. cur = ucl_object_lookup (val, "type");
  1092. if (cur != NULL) {
  1093. tkcf->name = ucl_object_tostring (cur);
  1094. tkcf->opts = val;
  1095. }
  1096. }
  1097. }
  1098. }
  1099. }
  1100. }
  1101. ucl_object_iterate_free (it);
  1102. }
  1103. else {
  1104. msg_err_config ("fatal configuration error, cannot parse statfile definition");
  1105. }
  1106. if (tkcf == NULL) {
  1107. tkcf = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*tkcf));
  1108. tkcf->name = NULL;
  1109. }
  1110. ccf->tokenizer = tkcf;
  1111. /* Handle lua conditions */
  1112. val = ucl_object_lookup_any (obj, "learn_condition", NULL);
  1113. if (val) {
  1114. LL_FOREACH (val, cur) {
  1115. if (ucl_object_type(cur) == UCL_STRING) {
  1116. const gchar *lua_script;
  1117. gsize slen;
  1118. gint ref_idx;
  1119. lua_script = ucl_object_tolstring(cur, &slen);
  1120. ref_idx = rspamd_lua_function_ref_from_str(L,
  1121. lua_script, slen, "learn_condition", err);
  1122. if (ref_idx == LUA_NOREF) {
  1123. return FALSE;
  1124. }
  1125. rspamd_lua_add_ref_dtor(L, cfg->cfg_pool, ref_idx);
  1126. ccf->learn_conditions = rspamd_mempool_glist_append(
  1127. cfg->cfg_pool,
  1128. ccf->learn_conditions,
  1129. GINT_TO_POINTER (ref_idx));
  1130. }
  1131. }
  1132. }
  1133. val = ucl_object_lookup_any (obj, "classify_condition", NULL);
  1134. if (val) {
  1135. LL_FOREACH (val, cur) {
  1136. if (ucl_object_type(cur) == UCL_STRING) {
  1137. const gchar *lua_script;
  1138. gsize slen;
  1139. gint ref_idx;
  1140. lua_script = ucl_object_tolstring(cur, &slen);
  1141. ref_idx = rspamd_lua_function_ref_from_str(L,
  1142. lua_script, slen, "classify_condition", err);
  1143. if (ref_idx == LUA_NOREF) {
  1144. return FALSE;
  1145. }
  1146. rspamd_lua_add_ref_dtor (L, cfg->cfg_pool, ref_idx);
  1147. ccf->classify_conditions = rspamd_mempool_glist_append(
  1148. cfg->cfg_pool,
  1149. ccf->classify_conditions,
  1150. GINT_TO_POINTER (ref_idx));
  1151. }
  1152. }
  1153. }
  1154. ccf->opts = (ucl_object_t *)obj;
  1155. cfg->classifiers = g_list_prepend (cfg->classifiers, ccf);
  1156. return res;
  1157. }
  1158. static gboolean
  1159. rspamd_rcl_composite_handler (rspamd_mempool_t *pool,
  1160. const ucl_object_t *obj,
  1161. const gchar *key,
  1162. gpointer ud,
  1163. struct rspamd_rcl_section *section,
  1164. GError **err)
  1165. {
  1166. struct rspamd_config *cfg = ud;
  1167. void *composite;
  1168. const gchar *composite_name;
  1169. g_assert (key != NULL);
  1170. composite_name = key;
  1171. if ((composite = rspamd_composites_manager_add_from_ucl(cfg->composites_manager,
  1172. composite_name, obj)) != NULL) {
  1173. rspamd_symcache_add_symbol (cfg->cache, composite_name, 0,
  1174. NULL, composite, SYMBOL_TYPE_COMPOSITE, -1);
  1175. }
  1176. return composite != NULL;
  1177. }
  1178. static gboolean
  1179. rspamd_rcl_composites_handler (rspamd_mempool_t *pool,
  1180. const ucl_object_t *obj,
  1181. const gchar *key,
  1182. gpointer ud,
  1183. struct rspamd_rcl_section *section,
  1184. GError **err)
  1185. {
  1186. ucl_object_iter_t it = NULL;
  1187. const ucl_object_t *cur;
  1188. gboolean success = TRUE;
  1189. it = ucl_object_iterate_new (obj);
  1190. while ((cur = ucl_object_iterate_safe (it, true))) {
  1191. success = rspamd_rcl_composite_handler(pool, cur,
  1192. ucl_object_key(cur), ud, section, err);
  1193. if (!success) {
  1194. break;
  1195. }
  1196. }
  1197. ucl_object_iterate_free (it);
  1198. return success;
  1199. }
  1200. static gboolean
  1201. rspamd_rcl_neighbours_handler (rspamd_mempool_t *pool,
  1202. const ucl_object_t *obj,
  1203. const gchar *key,
  1204. gpointer ud,
  1205. struct rspamd_rcl_section *section,
  1206. GError **err)
  1207. {
  1208. struct rspamd_config *cfg = ud;
  1209. const ucl_object_t *hostval, *pathval;
  1210. ucl_object_t *neigh;
  1211. gboolean has_port = FALSE, has_proto = FALSE;
  1212. GString *urlstr;
  1213. const gchar *p;
  1214. if (key == NULL) {
  1215. g_set_error (err,
  1216. CFG_RCL_ERROR,
  1217. EINVAL,
  1218. "missing name for neighbour");
  1219. return FALSE;
  1220. }
  1221. hostval = ucl_object_lookup (obj, "host");
  1222. if (hostval == NULL || ucl_object_type (hostval) != UCL_STRING) {
  1223. g_set_error (err,
  1224. CFG_RCL_ERROR,
  1225. EINVAL,
  1226. "missing host for neighbour: %s", ucl_object_key (obj));
  1227. return FALSE;
  1228. }
  1229. neigh = ucl_object_typed_new (UCL_OBJECT);
  1230. ucl_object_insert_key (neigh, ucl_object_copy (hostval), "host", 0, false);
  1231. if ((p = strrchr (ucl_object_tostring (hostval), ':')) != NULL) {
  1232. if (g_ascii_isdigit (p[1])) {
  1233. has_port = TRUE;
  1234. }
  1235. }
  1236. if (strstr (ucl_object_tostring (hostval), "://") != NULL) {
  1237. has_proto = TRUE;
  1238. }
  1239. /* Now make url */
  1240. urlstr = g_string_sized_new (63);
  1241. pathval = ucl_object_lookup (obj, "path");
  1242. if (!has_proto) {
  1243. g_string_append_len (urlstr, "http://", sizeof ("http://") - 1);
  1244. }
  1245. g_string_append (urlstr, ucl_object_tostring (hostval));
  1246. if (!has_port) {
  1247. g_string_append (urlstr, ":11334");
  1248. }
  1249. if (pathval == NULL) {
  1250. g_string_append (urlstr, "/");
  1251. }
  1252. else {
  1253. g_string_append (urlstr, ucl_object_tostring (pathval));
  1254. }
  1255. ucl_object_insert_key (neigh,
  1256. ucl_object_fromlstring (urlstr->str, urlstr->len),
  1257. "url", 0, false);
  1258. g_string_free (urlstr, TRUE);
  1259. ucl_object_insert_key (cfg->neighbours, neigh, key, 0, true);
  1260. return TRUE;
  1261. }
  1262. struct rspamd_rcl_section *
  1263. rspamd_rcl_add_section (struct rspamd_rcl_section **top,
  1264. const gchar *name, const gchar *key_attr, rspamd_rcl_handler_t handler,
  1265. enum ucl_type type, gboolean required, gboolean strict_type)
  1266. {
  1267. struct rspamd_rcl_section *new;
  1268. ucl_object_t *parent_doc;
  1269. new = g_malloc0 (sizeof (struct rspamd_rcl_section));
  1270. new->name = name;
  1271. new->key_attr = key_attr;
  1272. new->handler = handler;
  1273. new->type = type;
  1274. new->strict_type = strict_type;
  1275. if (*top == NULL) {
  1276. parent_doc = NULL;
  1277. new->doc_ref = NULL;
  1278. }
  1279. else {
  1280. parent_doc = (*top)->doc_ref;
  1281. new->doc_ref = ucl_object_ref (rspamd_rcl_add_doc_obj (parent_doc,
  1282. NULL,
  1283. name,
  1284. type,
  1285. NULL,
  1286. 0,
  1287. NULL,
  1288. 0));
  1289. }
  1290. HASH_ADD_KEYPTR (hh, *top, new->name, strlen (new->name), new);
  1291. return new;
  1292. }
  1293. struct rspamd_rcl_section *
  1294. rspamd_rcl_add_section_doc (struct rspamd_rcl_section **top,
  1295. const gchar *name, const gchar *key_attr, rspamd_rcl_handler_t handler,
  1296. enum ucl_type type, gboolean required, gboolean strict_type,
  1297. ucl_object_t *doc_target,
  1298. const gchar *doc_string)
  1299. {
  1300. struct rspamd_rcl_section *new_section;
  1301. new_section = g_malloc0 (sizeof (struct rspamd_rcl_section));
  1302. new_section->name = name;
  1303. new_section->key_attr = key_attr;
  1304. new_section->handler = handler;
  1305. new_section->type = type;
  1306. new_section->strict_type = strict_type;
  1307. new_section->doc_ref = ucl_object_ref (rspamd_rcl_add_doc_obj (doc_target,
  1308. doc_string,
  1309. name,
  1310. type,
  1311. NULL,
  1312. 0,
  1313. NULL,
  1314. 0));
  1315. HASH_ADD_KEYPTR (hh, *top, new_section->name, strlen (new_section->name), new_section);
  1316. return new_section;
  1317. }
  1318. struct rspamd_rcl_default_handler_data *
  1319. rspamd_rcl_add_default_handler (struct rspamd_rcl_section *section,
  1320. const gchar *name,
  1321. rspamd_rcl_default_handler_t handler,
  1322. goffset offset,
  1323. gint flags,
  1324. const gchar *doc_string)
  1325. {
  1326. struct rspamd_rcl_default_handler_data *nhandler;
  1327. nhandler = g_malloc0 (sizeof (struct rspamd_rcl_default_handler_data));
  1328. nhandler->key = g_strdup (name);
  1329. nhandler->handler = handler;
  1330. nhandler->pd.offset = offset;
  1331. nhandler->pd.flags = flags;
  1332. if (section->doc_ref != NULL) {
  1333. rspamd_rcl_add_doc_obj (section->doc_ref,
  1334. doc_string,
  1335. name,
  1336. UCL_NULL,
  1337. handler,
  1338. flags,
  1339. NULL,
  1340. 0);
  1341. }
  1342. HASH_ADD_KEYPTR (hh, section->default_parser, nhandler->key, strlen (
  1343. nhandler->key), nhandler);
  1344. return nhandler;
  1345. }
  1346. struct rspamd_rcl_section *
  1347. rspamd_rcl_config_init (struct rspamd_config *cfg, GHashTable *skip_sections)
  1348. {
  1349. struct rspamd_rcl_section *new = NULL, *sub, *ssub;
  1350. /*
  1351. * Important notice:
  1352. * the order of parsing is equal to order of this initialization, therefore
  1353. * it is possible to init some portions of config prior to others
  1354. */
  1355. /**
  1356. * Logging section
  1357. */
  1358. if (!(skip_sections && g_hash_table_lookup (skip_sections, "logging"))) {
  1359. sub = rspamd_rcl_add_section_doc (&new,
  1360. "logging", NULL,
  1361. rspamd_rcl_logging_handler,
  1362. UCL_OBJECT,
  1363. FALSE,
  1364. TRUE,
  1365. cfg->doc_strings,
  1366. "Configure rspamd logging");
  1367. /* Default handlers */
  1368. rspamd_rcl_add_default_handler (sub,
  1369. "log_buffer",
  1370. rspamd_rcl_parse_struct_integer,
  1371. G_STRUCT_OFFSET (struct rspamd_config, log_buf_size),
  1372. RSPAMD_CL_FLAG_INT_32,
  1373. "Size of log buffer in bytes (for file logging)");
  1374. rspamd_rcl_add_default_handler (sub,
  1375. "log_urls",
  1376. rspamd_rcl_parse_struct_boolean,
  1377. G_STRUCT_OFFSET (struct rspamd_config, log_urls),
  1378. 0,
  1379. "Write each URL found in a message to the log file");
  1380. rspamd_rcl_add_default_handler (sub,
  1381. "debug_ip",
  1382. rspamd_rcl_parse_struct_ucl,
  1383. G_STRUCT_OFFSET (struct rspamd_config, debug_ip_map),
  1384. 0,
  1385. "Enable debugging log for the specified IP addresses");
  1386. rspamd_rcl_add_default_handler (sub,
  1387. "debug_modules",
  1388. rspamd_rcl_parse_struct_string_list,
  1389. G_STRUCT_OFFSET (struct rspamd_config, debug_modules),
  1390. RSPAMD_CL_FLAG_STRING_LIST_HASH,
  1391. "Enable debugging for the specified modules");
  1392. rspamd_rcl_add_default_handler (sub,
  1393. "log_format",
  1394. rspamd_rcl_parse_struct_string,
  1395. G_STRUCT_OFFSET (struct rspamd_config, log_format_str),
  1396. 0,
  1397. "Specify format string for the task logging output "
  1398. "(https://rspamd.com/doc/configuration/logging.html "
  1399. "for details)");
  1400. rspamd_rcl_add_default_handler (sub,
  1401. "encryption_key",
  1402. rspamd_rcl_parse_struct_pubkey,
  1403. G_STRUCT_OFFSET (struct rspamd_config, log_encryption_key),
  1404. 0,
  1405. "Encrypt sensitive information in logs using this pubkey");
  1406. rspamd_rcl_add_default_handler (sub,
  1407. "error_elts",
  1408. rspamd_rcl_parse_struct_integer,
  1409. G_STRUCT_OFFSET (struct rspamd_config, log_error_elts),
  1410. RSPAMD_CL_FLAG_UINT,
  1411. "Size of circular buffer for last errors (10 by default)");
  1412. rspamd_rcl_add_default_handler (sub,
  1413. "error_maxlen",
  1414. rspamd_rcl_parse_struct_integer,
  1415. G_STRUCT_OFFSET (struct rspamd_config, log_error_elt_maxlen),
  1416. RSPAMD_CL_FLAG_UINT,
  1417. "Size of each element in error log buffer (1000 by default)");
  1418. /* Documentation only options, handled in log_handler to map flags */
  1419. rspamd_rcl_add_doc_by_path (cfg,
  1420. "logging",
  1421. "Enable colored output (for console logging)",
  1422. "log_color",
  1423. UCL_BOOLEAN,
  1424. NULL,
  1425. 0,
  1426. NULL,
  1427. 0);
  1428. rspamd_rcl_add_doc_by_path (cfg,
  1429. "logging",
  1430. "Enable severity logging output (e.g. [error] or [warning])",
  1431. "log_severity",
  1432. UCL_BOOLEAN,
  1433. NULL,
  1434. 0,
  1435. NULL,
  1436. 0);
  1437. rspamd_rcl_add_doc_by_path (cfg,
  1438. "logging",
  1439. "Enable systemd compatible logging",
  1440. "systemd",
  1441. UCL_BOOLEAN,
  1442. NULL,
  1443. 0,
  1444. NULL,
  1445. 0);
  1446. rspamd_rcl_add_doc_by_path (cfg,
  1447. "logging",
  1448. "Write statistics of regexp processing to log (useful for hyperscan)",
  1449. "log_re_cache",
  1450. UCL_BOOLEAN,
  1451. NULL,
  1452. 0,
  1453. NULL,
  1454. 0);
  1455. rspamd_rcl_add_doc_by_path (cfg,
  1456. "logging",
  1457. "Use microseconds resolution for timestamps",
  1458. "log_usec",
  1459. UCL_BOOLEAN,
  1460. NULL,
  1461. 0,
  1462. NULL,
  1463. 0);
  1464. }
  1465. if (!(skip_sections && g_hash_table_lookup (skip_sections, "options"))) {
  1466. /**
  1467. * Options section
  1468. */
  1469. sub = rspamd_rcl_add_section_doc (&new,
  1470. "options", NULL,
  1471. rspamd_rcl_options_handler,
  1472. UCL_OBJECT,
  1473. FALSE,
  1474. TRUE,
  1475. cfg->doc_strings,
  1476. "Global rspamd options");
  1477. rspamd_rcl_add_default_handler (sub,
  1478. "cache_file",
  1479. rspamd_rcl_parse_struct_string,
  1480. G_STRUCT_OFFSET (struct rspamd_config, cache_filename),
  1481. RSPAMD_CL_FLAG_STRING_PATH,
  1482. "Path to the cache file");
  1483. rspamd_rcl_add_default_handler (sub,
  1484. "cache_reload",
  1485. rspamd_rcl_parse_struct_time,
  1486. G_STRUCT_OFFSET (struct rspamd_config, cache_reload_time),
  1487. RSPAMD_CL_FLAG_TIME_FLOAT,
  1488. "How often cache reload should be performed");
  1489. /* Old DNS configuration */
  1490. rspamd_rcl_add_default_handler (sub,
  1491. "dns_nameserver",
  1492. rspamd_rcl_parse_struct_ucl,
  1493. G_STRUCT_OFFSET (struct rspamd_config, nameservers),
  1494. 0,
  1495. "Legacy option for DNS servers used");
  1496. rspamd_rcl_add_default_handler (sub,
  1497. "dns_timeout",
  1498. rspamd_rcl_parse_struct_time,
  1499. G_STRUCT_OFFSET (struct rspamd_config, dns_timeout),
  1500. RSPAMD_CL_FLAG_TIME_FLOAT,
  1501. "Legacy option for DNS request timeout");
  1502. rspamd_rcl_add_default_handler (sub,
  1503. "dns_retransmits",
  1504. rspamd_rcl_parse_struct_integer,
  1505. G_STRUCT_OFFSET (struct rspamd_config, dns_retransmits),
  1506. RSPAMD_CL_FLAG_INT_32,
  1507. "Legacy option for DNS retransmits count");
  1508. rspamd_rcl_add_default_handler (sub,
  1509. "dns_sockets",
  1510. rspamd_rcl_parse_struct_integer,
  1511. G_STRUCT_OFFSET (struct rspamd_config, dns_io_per_server),
  1512. RSPAMD_CL_FLAG_INT_32,
  1513. "Legacy option for DNS sockets per server count");
  1514. rspamd_rcl_add_default_handler (sub,
  1515. "dns_max_requests",
  1516. rspamd_rcl_parse_struct_integer,
  1517. G_STRUCT_OFFSET (struct rspamd_config, dns_max_requests),
  1518. RSPAMD_CL_FLAG_INT_32,
  1519. "Maximum DNS requests per task (default: 64)");
  1520. rspamd_rcl_add_default_handler (sub,
  1521. "control_socket",
  1522. rspamd_rcl_parse_struct_string,
  1523. G_STRUCT_OFFSET (struct rspamd_config, control_socket_path),
  1524. 0,
  1525. "Path to the control socket");
  1526. rspamd_rcl_add_default_handler (sub,
  1527. "explicit_modules",
  1528. rspamd_rcl_parse_struct_string_list,
  1529. G_STRUCT_OFFSET (struct rspamd_config, explicit_modules),
  1530. RSPAMD_CL_FLAG_STRING_LIST_HASH,
  1531. "Always load these modules even if they are not configured explicitly");
  1532. rspamd_rcl_add_default_handler (sub,
  1533. "allow_raw_input",
  1534. rspamd_rcl_parse_struct_boolean,
  1535. G_STRUCT_OFFSET (struct rspamd_config, allow_raw_input),
  1536. 0,
  1537. "Allow non MIME input for rspamd");
  1538. rspamd_rcl_add_default_handler (sub,
  1539. "one_shot",
  1540. rspamd_rcl_parse_struct_boolean,
  1541. G_STRUCT_OFFSET (struct rspamd_config, one_shot_mode),
  1542. 0,
  1543. "Add all symbols only once per message");
  1544. rspamd_rcl_add_default_handler (sub,
  1545. "check_attachements",
  1546. rspamd_rcl_parse_struct_boolean,
  1547. G_STRUCT_OFFSET (struct rspamd_config, check_text_attachements),
  1548. 0,
  1549. "Treat text attachments as normal text parts");
  1550. rspamd_rcl_add_default_handler (sub,
  1551. "tempdir",
  1552. rspamd_rcl_parse_struct_string,
  1553. G_STRUCT_OFFSET (struct rspamd_config, temp_dir),
  1554. RSPAMD_CL_FLAG_STRING_PATH,
  1555. "Directory for temporary files");
  1556. rspamd_rcl_add_default_handler (sub,
  1557. "pidfile",
  1558. rspamd_rcl_parse_struct_string,
  1559. G_STRUCT_OFFSET (struct rspamd_config, pid_file),
  1560. RSPAMD_CL_FLAG_STRING_PATH,
  1561. "Path to the pid file");
  1562. rspamd_rcl_add_default_handler (sub,
  1563. "filters",
  1564. rspamd_rcl_parse_struct_string_list,
  1565. G_STRUCT_OFFSET (struct rspamd_config, filters),
  1566. 0,
  1567. "List of internal filters enabled");
  1568. rspamd_rcl_add_default_handler (sub,
  1569. "map_watch_interval",
  1570. rspamd_rcl_parse_struct_time,
  1571. G_STRUCT_OFFSET (struct rspamd_config, map_timeout),
  1572. RSPAMD_CL_FLAG_TIME_FLOAT,
  1573. "Interval for checking maps");
  1574. rspamd_rcl_add_default_handler (sub,
  1575. "map_file_watch_multiplier",
  1576. rspamd_rcl_parse_struct_double,
  1577. G_STRUCT_OFFSET (struct rspamd_config, map_file_watch_multiplier),
  1578. 0,
  1579. "Multiplier for map watch interval when map is file");
  1580. rspamd_rcl_add_default_handler (sub,
  1581. "maps_cache_dir",
  1582. rspamd_rcl_parse_struct_string,
  1583. G_STRUCT_OFFSET (struct rspamd_config, maps_cache_dir),
  1584. 0,
  1585. "Directory to save maps cached data (default: $DBDIR)");
  1586. rspamd_rcl_add_default_handler (sub,
  1587. "monitoring_watch_interval",
  1588. rspamd_rcl_parse_struct_time,
  1589. G_STRUCT_OFFSET (struct rspamd_config, monitored_interval),
  1590. RSPAMD_CL_FLAG_TIME_FLOAT,
  1591. "Interval for checking monitored instances");
  1592. rspamd_rcl_add_default_handler (sub,
  1593. "disable_monitoring",
  1594. rspamd_rcl_parse_struct_boolean,
  1595. G_STRUCT_OFFSET (struct rspamd_config, disable_monitored),
  1596. 0,
  1597. "Disable monitoring completely");
  1598. rspamd_rcl_add_default_handler (sub,
  1599. "fips_mode",
  1600. rspamd_rcl_parse_struct_boolean,
  1601. G_STRUCT_OFFSET (struct rspamd_config, fips_mode),
  1602. 0,
  1603. "Enable FIPS 140-2 mode in OpenSSL");
  1604. rspamd_rcl_add_default_handler (sub,
  1605. "dynamic_conf",
  1606. rspamd_rcl_parse_struct_string,
  1607. G_STRUCT_OFFSET (struct rspamd_config, dynamic_conf),
  1608. 0,
  1609. "Path to the dynamic configuration");
  1610. rspamd_rcl_add_default_handler (sub,
  1611. "rrd",
  1612. rspamd_rcl_parse_struct_string,
  1613. G_STRUCT_OFFSET (struct rspamd_config, rrd_file),
  1614. RSPAMD_CL_FLAG_STRING_PATH,
  1615. "Path to RRD file");
  1616. rspamd_rcl_add_default_handler (sub,
  1617. "stats_file",
  1618. rspamd_rcl_parse_struct_string,
  1619. G_STRUCT_OFFSET (struct rspamd_config, stats_file),
  1620. RSPAMD_CL_FLAG_STRING_PATH,
  1621. "Path to stats file");
  1622. rspamd_rcl_add_default_handler (sub,
  1623. "history_file",
  1624. rspamd_rcl_parse_struct_string,
  1625. G_STRUCT_OFFSET (struct rspamd_config, history_file),
  1626. RSPAMD_CL_FLAG_STRING_PATH,
  1627. "Path to history file");
  1628. rspamd_rcl_add_default_handler (sub,
  1629. "check_all_filters",
  1630. rspamd_rcl_parse_struct_boolean,
  1631. G_STRUCT_OFFSET (struct rspamd_config, check_all_filters),
  1632. 0,
  1633. "Always check all filters");
  1634. rspamd_rcl_add_default_handler (sub,
  1635. "public_groups_only",
  1636. rspamd_rcl_parse_struct_boolean,
  1637. G_STRUCT_OFFSET (struct rspamd_config, public_groups_only),
  1638. 0,
  1639. "Output merely public groups everywhere");
  1640. rspamd_rcl_add_default_handler (sub,
  1641. "enable_test_patterns",
  1642. rspamd_rcl_parse_struct_boolean,
  1643. G_STRUCT_OFFSET (struct rspamd_config, enable_test_patterns),
  1644. 0,
  1645. "Enable test GTUBE like patterns (not for production!)");
  1646. rspamd_rcl_add_default_handler (sub,
  1647. "enable_css_parser",
  1648. rspamd_rcl_parse_struct_boolean,
  1649. G_STRUCT_OFFSET (struct rspamd_config, enable_css_parser),
  1650. 0,
  1651. "Enable CSS parser (experimental)");
  1652. rspamd_rcl_add_default_handler (sub,
  1653. "enable_experimental",
  1654. rspamd_rcl_parse_struct_boolean,
  1655. G_STRUCT_OFFSET (struct rspamd_config, enable_experimental),
  1656. 0,
  1657. "Enable experimental plugins");
  1658. rspamd_rcl_add_default_handler (sub,
  1659. "disable_pcre_jit",
  1660. rspamd_rcl_parse_struct_boolean,
  1661. G_STRUCT_OFFSET (struct rspamd_config, disable_pcre_jit),
  1662. 0,
  1663. "Disable PCRE JIT");
  1664. rspamd_rcl_add_default_handler (sub,
  1665. "min_word_len",
  1666. rspamd_rcl_parse_struct_integer,
  1667. G_STRUCT_OFFSET (struct rspamd_config, min_word_len),
  1668. RSPAMD_CL_FLAG_UINT,
  1669. "Minimum length of the word to be considered in statistics/fuzzy");
  1670. rspamd_rcl_add_default_handler (sub,
  1671. "max_word_len",
  1672. rspamd_rcl_parse_struct_integer,
  1673. G_STRUCT_OFFSET (struct rspamd_config, max_word_len),
  1674. RSPAMD_CL_FLAG_UINT,
  1675. "Maximum length of the word to be considered in statistics/fuzzy");
  1676. rspamd_rcl_add_default_handler (sub,
  1677. "words_decay",
  1678. rspamd_rcl_parse_struct_integer,
  1679. G_STRUCT_OFFSET (struct rspamd_config, words_decay),
  1680. RSPAMD_CL_FLAG_UINT,
  1681. "Start skipping words at this amount");
  1682. rspamd_rcl_add_default_handler (sub,
  1683. "url_tld",
  1684. rspamd_rcl_parse_struct_string,
  1685. G_STRUCT_OFFSET (struct rspamd_config, tld_file),
  1686. RSPAMD_CL_FLAG_STRING_PATH,
  1687. "Path to the TLD file for urls detector");
  1688. rspamd_rcl_add_default_handler (sub,
  1689. "tld",
  1690. rspamd_rcl_parse_struct_string,
  1691. G_STRUCT_OFFSET (struct rspamd_config, tld_file),
  1692. RSPAMD_CL_FLAG_STRING_PATH,
  1693. "Path to the TLD file for urls detector");
  1694. rspamd_rcl_add_default_handler (sub,
  1695. "hs_cache_dir",
  1696. rspamd_rcl_parse_struct_string,
  1697. G_STRUCT_OFFSET (struct rspamd_config, hs_cache_dir),
  1698. RSPAMD_CL_FLAG_STRING_PATH,
  1699. "Path directory where rspamd would save hyperscan cache");
  1700. rspamd_rcl_add_default_handler (sub,
  1701. "history_rows",
  1702. rspamd_rcl_parse_struct_integer,
  1703. G_STRUCT_OFFSET (struct rspamd_config, history_rows),
  1704. RSPAMD_CL_FLAG_UINT,
  1705. "Number of records in the history file");
  1706. rspamd_rcl_add_default_handler (sub,
  1707. "disable_hyperscan",
  1708. rspamd_rcl_parse_struct_boolean,
  1709. G_STRUCT_OFFSET (struct rspamd_config, disable_hyperscan),
  1710. 0,
  1711. "Disable hyperscan optimizations for regular expressions");
  1712. rspamd_rcl_add_default_handler (sub,
  1713. "vectorized_hyperscan",
  1714. rspamd_rcl_parse_struct_boolean,
  1715. G_STRUCT_OFFSET (struct rspamd_config, vectorized_hyperscan),
  1716. 0,
  1717. "Use hyperscan in vectorized mode (experimental)");
  1718. rspamd_rcl_add_default_handler (sub,
  1719. "cores_dir",
  1720. rspamd_rcl_parse_struct_string,
  1721. G_STRUCT_OFFSET (struct rspamd_config, cores_dir),
  1722. RSPAMD_CL_FLAG_STRING_PATH,
  1723. "Path to the directory where rspamd core files are intended to be dumped");
  1724. rspamd_rcl_add_default_handler (sub,
  1725. "max_cores_size",
  1726. rspamd_rcl_parse_struct_integer,
  1727. G_STRUCT_OFFSET (struct rspamd_config, max_cores_size),
  1728. RSPAMD_CL_FLAG_INT_SIZE,
  1729. "Limit of joint size of all files in `cores_dir`");
  1730. rspamd_rcl_add_default_handler (sub,
  1731. "max_cores_count",
  1732. rspamd_rcl_parse_struct_integer,
  1733. G_STRUCT_OFFSET (struct rspamd_config, max_cores_count),
  1734. RSPAMD_CL_FLAG_INT_SIZE,
  1735. "Limit of files count in `cores_dir`");
  1736. rspamd_rcl_add_default_handler (sub,
  1737. "local_addrs",
  1738. rspamd_rcl_parse_struct_ucl,
  1739. G_STRUCT_OFFSET (struct rspamd_config, local_addrs),
  1740. 0,
  1741. "Use the specified addresses as local ones");
  1742. rspamd_rcl_add_default_handler (sub,
  1743. "local_networks",
  1744. rspamd_rcl_parse_struct_ucl,
  1745. G_STRUCT_OFFSET (struct rspamd_config, local_addrs),
  1746. 0,
  1747. "Use the specified addresses as local ones (alias for `local_addrs`)");
  1748. rspamd_rcl_add_default_handler (sub,
  1749. "trusted_keys",
  1750. rspamd_rcl_parse_struct_string_list,
  1751. G_STRUCT_OFFSET (struct rspamd_config, trusted_keys),
  1752. RSPAMD_CL_FLAG_STRING_LIST_HASH,
  1753. "List of trusted public keys used for signatures in base32 encoding");
  1754. rspamd_rcl_add_default_handler (sub,
  1755. "enable_shutdown_workaround",
  1756. rspamd_rcl_parse_struct_boolean,
  1757. G_STRUCT_OFFSET (struct rspamd_config, enable_shutdown_workaround),
  1758. 0,
  1759. "Enable workaround for legacy clients");
  1760. rspamd_rcl_add_default_handler (sub,
  1761. "ignore_received",
  1762. rspamd_rcl_parse_struct_boolean,
  1763. G_STRUCT_OFFSET (struct rspamd_config, ignore_received),
  1764. 0,
  1765. "Ignore data from the first received header");
  1766. rspamd_rcl_add_default_handler (sub,
  1767. "ssl_ca_path",
  1768. rspamd_rcl_parse_struct_string,
  1769. G_STRUCT_OFFSET (struct rspamd_config, ssl_ca_path),
  1770. RSPAMD_CL_FLAG_STRING_PATH,
  1771. "Path to ssl CA file");
  1772. rspamd_rcl_add_default_handler (sub,
  1773. "ssl_ciphers",
  1774. rspamd_rcl_parse_struct_string,
  1775. G_STRUCT_OFFSET (struct rspamd_config, ssl_ciphers),
  1776. 0,
  1777. "List of ssl ciphers (e.g. HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4)");
  1778. rspamd_rcl_add_default_handler (sub,
  1779. "max_message",
  1780. rspamd_rcl_parse_struct_integer,
  1781. G_STRUCT_OFFSET (struct rspamd_config, max_message),
  1782. RSPAMD_CL_FLAG_INT_SIZE,
  1783. "Maximum size of the message to be scanned (50Mb by default)");
  1784. rspamd_rcl_add_default_handler (sub,
  1785. "max_pic",
  1786. rspamd_rcl_parse_struct_integer,
  1787. G_STRUCT_OFFSET (struct rspamd_config, max_pic_size),
  1788. RSPAMD_CL_FLAG_INT_SIZE,
  1789. "Maximum size of the picture to be normalized (1Mb by default)");
  1790. rspamd_rcl_add_default_handler (sub,
  1791. "images_cache",
  1792. rspamd_rcl_parse_struct_integer,
  1793. G_STRUCT_OFFSET (struct rspamd_config, max_pic_size),
  1794. RSPAMD_CL_FLAG_INT_SIZE,
  1795. "Size of DCT data cache for images (256 elements by default)");
  1796. rspamd_rcl_add_default_handler (sub,
  1797. "zstd_input_dictionary",
  1798. rspamd_rcl_parse_struct_string,
  1799. G_STRUCT_OFFSET (struct rspamd_config, zstd_input_dictionary),
  1800. RSPAMD_CL_FLAG_STRING_PATH,
  1801. "Dictionary for zstd inbound protocol compression");
  1802. rspamd_rcl_add_default_handler (sub,
  1803. "zstd_output_dictionary",
  1804. rspamd_rcl_parse_struct_string,
  1805. G_STRUCT_OFFSET (struct rspamd_config, zstd_output_dictionary),
  1806. RSPAMD_CL_FLAG_STRING_PATH,
  1807. "Dictionary for outbound zstd compression");
  1808. rspamd_rcl_add_default_handler (sub,
  1809. "compat_messages",
  1810. rspamd_rcl_parse_struct_boolean,
  1811. G_STRUCT_OFFSET (struct rspamd_config, compat_messages),
  1812. 0,
  1813. "Use pre 1.4 style of messages in the protocol");
  1814. rspamd_rcl_add_default_handler (sub,
  1815. "max_shots",
  1816. rspamd_rcl_parse_struct_integer,
  1817. G_STRUCT_OFFSET (struct rspamd_config, default_max_shots),
  1818. 0,
  1819. "Maximum number of hits per a single symbol (default: 100)");
  1820. rspamd_rcl_add_default_handler (sub,
  1821. "sessions_cache",
  1822. rspamd_rcl_parse_struct_boolean,
  1823. G_STRUCT_OFFSET (struct rspamd_config, enable_sessions_cache),
  1824. 0,
  1825. "Enable sessions cache to debug dangling sessions");
  1826. rspamd_rcl_add_default_handler (sub,
  1827. "max_sessions_cache",
  1828. rspamd_rcl_parse_struct_integer,
  1829. G_STRUCT_OFFSET (struct rspamd_config, max_sessions_cache),
  1830. 0,
  1831. "Maximum number of sessions in cache before warning (default: 100)");
  1832. rspamd_rcl_add_default_handler (sub,
  1833. "task_timeout",
  1834. rspamd_rcl_parse_struct_time,
  1835. G_STRUCT_OFFSET (struct rspamd_config, task_timeout),
  1836. RSPAMD_CL_FLAG_TIME_FLOAT,
  1837. "Maximum time for checking a message");
  1838. rspamd_rcl_add_default_handler (sub,
  1839. "soft_reject_on_timeout",
  1840. rspamd_rcl_parse_struct_boolean,
  1841. G_STRUCT_OFFSET (struct rspamd_config, soft_reject_on_timeout),
  1842. 0,
  1843. "Emit soft reject if task timeout takes place");
  1844. rspamd_rcl_add_default_handler (sub,
  1845. "check_timeout",
  1846. rspamd_rcl_parse_struct_time,
  1847. G_STRUCT_OFFSET (struct rspamd_config, task_timeout),
  1848. RSPAMD_CL_FLAG_TIME_FLOAT,
  1849. "Maximum time for checking a message (alias for task_timeout)");
  1850. rspamd_rcl_add_default_handler (sub,
  1851. "lua_gc_step",
  1852. rspamd_rcl_parse_struct_integer,
  1853. G_STRUCT_OFFSET (struct rspamd_config, lua_gc_step),
  1854. RSPAMD_CL_FLAG_UINT,
  1855. "Lua garbage-collector step (default: 200)");
  1856. rspamd_rcl_add_default_handler (sub,
  1857. "lua_gc_pause",
  1858. rspamd_rcl_parse_struct_integer,
  1859. G_STRUCT_OFFSET (struct rspamd_config, lua_gc_pause),
  1860. RSPAMD_CL_FLAG_UINT,
  1861. "Lua garbage-collector pause (default: 200)");
  1862. rspamd_rcl_add_default_handler (sub,
  1863. "full_gc_iters",
  1864. rspamd_rcl_parse_struct_integer,
  1865. G_STRUCT_OFFSET (struct rspamd_config, full_gc_iters),
  1866. RSPAMD_CL_FLAG_UINT,
  1867. "Task scanned before memory gc is performed (default: 0 - disabled)");
  1868. rspamd_rcl_add_default_handler (sub,
  1869. "heartbeat_interval",
  1870. rspamd_rcl_parse_struct_time,
  1871. G_STRUCT_OFFSET (struct rspamd_config, heartbeat_interval),
  1872. RSPAMD_CL_FLAG_TIME_FLOAT,
  1873. "Time between workers heartbeats");
  1874. rspamd_rcl_add_default_handler (sub,
  1875. "heartbeats_loss_max",
  1876. rspamd_rcl_parse_struct_integer,
  1877. G_STRUCT_OFFSET (struct rspamd_config, heartbeats_loss_max),
  1878. RSPAMD_CL_FLAG_INT_32,
  1879. "Maximum count of heartbeats to be lost before trying to "
  1880. "terminate a worker (default: 0 - disabled)");
  1881. rspamd_rcl_add_default_handler (sub,
  1882. "max_lua_urls",
  1883. rspamd_rcl_parse_struct_integer,
  1884. G_STRUCT_OFFSET (struct rspamd_config, max_lua_urls),
  1885. RSPAMD_CL_FLAG_INT_32,
  1886. "Maximum count of URLs to pass to Lua to avoid DoS (default: 1024)");
  1887. rspamd_rcl_add_default_handler (sub,
  1888. "max_urls",
  1889. rspamd_rcl_parse_struct_integer,
  1890. G_STRUCT_OFFSET (struct rspamd_config, max_urls),
  1891. RSPAMD_CL_FLAG_INT_32,
  1892. "Maximum count of URLs to process to avoid DoS (default: 10240)");
  1893. rspamd_rcl_add_default_handler (sub,
  1894. "max_recipients",
  1895. rspamd_rcl_parse_struct_integer,
  1896. G_STRUCT_OFFSET (struct rspamd_config, max_recipients),
  1897. RSPAMD_CL_FLAG_INT_32,
  1898. "Maximum count of recipients to process to avoid DoS (default: 1024)");
  1899. rspamd_rcl_add_default_handler (sub,
  1900. "max_blas_threads",
  1901. rspamd_rcl_parse_struct_integer,
  1902. G_STRUCT_OFFSET (struct rspamd_config, max_blas_threads),
  1903. RSPAMD_CL_FLAG_INT_32,
  1904. "Maximum number of Blas threads for learning neural networks (default: 1)");
  1905. rspamd_rcl_add_default_handler (sub,
  1906. "max_opts_len",
  1907. rspamd_rcl_parse_struct_integer,
  1908. G_STRUCT_OFFSET (struct rspamd_config, max_opts_len),
  1909. RSPAMD_CL_FLAG_INT_32,
  1910. "Maximum size of all options for a single symbol (default: 4096)");
  1911. rspamd_rcl_add_default_handler (sub,
  1912. "events_backend",
  1913. rspamd_rcl_parse_struct_string,
  1914. G_STRUCT_OFFSET (struct rspamd_config, events_backend),
  1915. 0,
  1916. "Events backend to use: kqueue, epoll, select, poll or auto (default: auto)");
  1917. /* Neighbours configuration */
  1918. rspamd_rcl_add_section_doc (&sub->subsections, "neighbours", "name",
  1919. rspamd_rcl_neighbours_handler,
  1920. UCL_OBJECT, FALSE, TRUE,
  1921. cfg->doc_strings,
  1922. "List of members of Rspamd cluster");
  1923. /* New DNS configuration */
  1924. ssub = rspamd_rcl_add_section_doc (&sub->subsections, "dns", NULL, NULL,
  1925. UCL_OBJECT, FALSE, TRUE,
  1926. cfg->doc_strings,
  1927. "Options for DNS resolver");
  1928. rspamd_rcl_add_default_handler (ssub,
  1929. "nameserver",
  1930. rspamd_rcl_parse_struct_ucl,
  1931. G_STRUCT_OFFSET (struct rspamd_config, nameservers),
  1932. 0,
  1933. "List of DNS servers");
  1934. rspamd_rcl_add_default_handler (ssub,
  1935. "server",
  1936. rspamd_rcl_parse_struct_ucl,
  1937. G_STRUCT_OFFSET (struct rspamd_config, nameservers),
  1938. 0,
  1939. "List of DNS servers");
  1940. rspamd_rcl_add_default_handler (ssub,
  1941. "timeout",
  1942. rspamd_rcl_parse_struct_time,
  1943. G_STRUCT_OFFSET (struct rspamd_config, dns_timeout),
  1944. RSPAMD_CL_FLAG_TIME_FLOAT,
  1945. "DNS request timeout");
  1946. rspamd_rcl_add_default_handler (ssub,
  1947. "retransmits",
  1948. rspamd_rcl_parse_struct_integer,
  1949. G_STRUCT_OFFSET (struct rspamd_config, dns_retransmits),
  1950. RSPAMD_CL_FLAG_INT_32,
  1951. "DNS request retransmits");
  1952. rspamd_rcl_add_default_handler (ssub,
  1953. "sockets",
  1954. rspamd_rcl_parse_struct_integer,
  1955. G_STRUCT_OFFSET (struct rspamd_config, dns_io_per_server),
  1956. RSPAMD_CL_FLAG_INT_32,
  1957. "Number of sockets per DNS server");
  1958. rspamd_rcl_add_default_handler (ssub,
  1959. "connections",
  1960. rspamd_rcl_parse_struct_integer,
  1961. G_STRUCT_OFFSET (struct rspamd_config, dns_io_per_server),
  1962. RSPAMD_CL_FLAG_INT_32,
  1963. "Number of sockets per DNS server");
  1964. rspamd_rcl_add_default_handler (ssub,
  1965. "enable_dnssec",
  1966. rspamd_rcl_parse_struct_boolean,
  1967. G_STRUCT_OFFSET (struct rspamd_config, enable_dnssec),
  1968. 0,
  1969. "Enable DNSSEC support in Rspamd");
  1970. /* New upstreams configuration */
  1971. ssub = rspamd_rcl_add_section_doc (&sub->subsections, "upstream", NULL, NULL,
  1972. UCL_OBJECT, FALSE, TRUE,
  1973. cfg->doc_strings,
  1974. "Upstreams configuration parameters");
  1975. rspamd_rcl_add_default_handler (ssub,
  1976. "max_errors",
  1977. rspamd_rcl_parse_struct_integer,
  1978. G_STRUCT_OFFSET (struct rspamd_config, upstream_max_errors),
  1979. RSPAMD_CL_FLAG_UINT,
  1980. "Maximum number of errors during `error_time` to consider upstream down");
  1981. rspamd_rcl_add_default_handler (ssub,
  1982. "error_time",
  1983. rspamd_rcl_parse_struct_time,
  1984. G_STRUCT_OFFSET (struct rspamd_config, upstream_error_time),
  1985. RSPAMD_CL_FLAG_TIME_FLOAT,
  1986. "Time frame to check errors");
  1987. rspamd_rcl_add_default_handler (ssub,
  1988. "revive_time",
  1989. rspamd_rcl_parse_struct_time,
  1990. G_STRUCT_OFFSET (struct rspamd_config, upstream_revive_time),
  1991. RSPAMD_CL_FLAG_TIME_FLOAT,
  1992. "Time before attempting to recover upstream after an error");
  1993. rspamd_rcl_add_default_handler (ssub,
  1994. "lazy_resolve_time",
  1995. rspamd_rcl_parse_struct_time,
  1996. G_STRUCT_OFFSET (struct rspamd_config, upstream_lazy_resolve_time),
  1997. RSPAMD_CL_FLAG_TIME_FLOAT,
  1998. "Time to resolve upstreams addresses in lazy mode");
  1999. }
  2000. if (!(skip_sections && g_hash_table_lookup (skip_sections, "actions"))) {
  2001. /**
  2002. * Symbols and actions sections
  2003. */
  2004. sub = rspamd_rcl_add_section_doc (&new,
  2005. "actions", NULL,
  2006. rspamd_rcl_actions_handler,
  2007. UCL_OBJECT,
  2008. FALSE,
  2009. TRUE,
  2010. cfg->doc_strings,
  2011. "Actions configuration");
  2012. rspamd_rcl_add_default_handler (sub,
  2013. "unknown_weight",
  2014. rspamd_rcl_parse_struct_double,
  2015. G_STRUCT_OFFSET (struct rspamd_config, unknown_weight),
  2016. 0,
  2017. "Accept unknown symbols with the specified weight");
  2018. rspamd_rcl_add_default_handler (sub,
  2019. "grow_factor",
  2020. rspamd_rcl_parse_struct_double,
  2021. G_STRUCT_OFFSET (struct rspamd_config, grow_factor),
  2022. 0,
  2023. "Multiply the subsequent symbols by this number "
  2024. "(does not affect symbols with score less or "
  2025. "equal to zero)");
  2026. rspamd_rcl_add_default_handler (sub,
  2027. "subject",
  2028. rspamd_rcl_parse_struct_string,
  2029. G_STRUCT_OFFSET (struct rspamd_config, subject),
  2030. 0,
  2031. "Rewrite subject with this value");
  2032. }
  2033. if (!(skip_sections && g_hash_table_lookup (skip_sections, "group"))) {
  2034. sub = rspamd_rcl_add_section_doc (&new,
  2035. "group", "name",
  2036. rspamd_rcl_group_handler,
  2037. UCL_OBJECT,
  2038. FALSE,
  2039. TRUE,
  2040. cfg->doc_strings,
  2041. "Symbol groups configuration");
  2042. ssub = rspamd_rcl_add_section_doc (&sub->subsections, "symbols", "name",
  2043. rspamd_rcl_symbol_handler,
  2044. UCL_OBJECT, FALSE, TRUE,
  2045. cfg->doc_strings,
  2046. "Symbols configuration");
  2047. /* Group part */
  2048. rspamd_rcl_add_default_handler (sub,
  2049. "max_score",
  2050. rspamd_rcl_parse_struct_double,
  2051. G_STRUCT_OFFSET (struct rspamd_symbols_group, max_score),
  2052. 0,
  2053. "Maximum score that could be reached by this symbols group");
  2054. }
  2055. if (!(skip_sections && g_hash_table_lookup (skip_sections, "worker"))) {
  2056. /**
  2057. * Worker section
  2058. */
  2059. sub = rspamd_rcl_add_section_doc (&new,
  2060. "worker", "type",
  2061. rspamd_rcl_worker_handler,
  2062. UCL_OBJECT,
  2063. FALSE,
  2064. TRUE,
  2065. cfg->doc_strings,
  2066. "Workers common options");
  2067. rspamd_rcl_add_default_handler (sub,
  2068. "count",
  2069. rspamd_rcl_parse_struct_integer,
  2070. G_STRUCT_OFFSET (struct rspamd_worker_conf, count),
  2071. RSPAMD_CL_FLAG_INT_16,
  2072. "Number of workers to spawn");
  2073. rspamd_rcl_add_default_handler (sub,
  2074. "max_files",
  2075. rspamd_rcl_parse_struct_integer,
  2076. G_STRUCT_OFFSET (struct rspamd_worker_conf, rlimit_nofile),
  2077. RSPAMD_CL_FLAG_INT_64,
  2078. "Maximum number of opened files per worker");
  2079. rspamd_rcl_add_default_handler (sub,
  2080. "max_core",
  2081. rspamd_rcl_parse_struct_integer,
  2082. G_STRUCT_OFFSET (struct rspamd_worker_conf, rlimit_maxcore),
  2083. RSPAMD_CL_FLAG_INT_64,
  2084. "Max size of core file in bytes");
  2085. rspamd_rcl_add_default_handler (sub,
  2086. "enabled",
  2087. rspamd_rcl_parse_struct_boolean,
  2088. G_STRUCT_OFFSET (struct rspamd_worker_conf, enabled),
  2089. 0,
  2090. "Enable or disable a worker (true by default)");
  2091. }
  2092. if (!(skip_sections && g_hash_table_lookup (skip_sections, "modules"))) {
  2093. /**
  2094. * Modules handler
  2095. */
  2096. sub = rspamd_rcl_add_section_doc (&new,
  2097. "modules", NULL,
  2098. rspamd_rcl_modules_handler,
  2099. UCL_OBJECT,
  2100. FALSE,
  2101. FALSE,
  2102. cfg->doc_strings,
  2103. "Lua plugins to load");
  2104. }
  2105. if (!(skip_sections && g_hash_table_lookup (skip_sections, "classifier"))) {
  2106. /**
  2107. * Classifiers handler
  2108. */
  2109. sub = rspamd_rcl_add_section_doc (&new,
  2110. "classifier", "type",
  2111. rspamd_rcl_classifier_handler,
  2112. UCL_OBJECT,
  2113. FALSE,
  2114. TRUE,
  2115. cfg->doc_strings,
  2116. "CLassifier options");
  2117. /* Default classifier is 'bayes' for now */
  2118. sub->default_key = "bayes";
  2119. rspamd_rcl_add_default_handler (sub,
  2120. "min_tokens",
  2121. rspamd_rcl_parse_struct_integer,
  2122. G_STRUCT_OFFSET (struct rspamd_classifier_config, min_tokens),
  2123. RSPAMD_CL_FLAG_INT_32,
  2124. "Minimum count of tokens (words) to be considered for statistics");
  2125. rspamd_rcl_add_default_handler (sub,
  2126. "min_token_hits",
  2127. rspamd_rcl_parse_struct_integer,
  2128. G_STRUCT_OFFSET (struct rspamd_classifier_config, min_token_hits),
  2129. RSPAMD_CL_FLAG_UINT,
  2130. "Minimum number of hits for a token to be considered");
  2131. rspamd_rcl_add_default_handler (sub,
  2132. "min_prob_strength",
  2133. rspamd_rcl_parse_struct_double,
  2134. G_STRUCT_OFFSET (struct rspamd_classifier_config, min_token_hits),
  2135. 0,
  2136. "Use only tokens with probability in [0.5 - MPS, 0.5 + MPS]");
  2137. rspamd_rcl_add_default_handler (sub,
  2138. "max_tokens",
  2139. rspamd_rcl_parse_struct_integer,
  2140. G_STRUCT_OFFSET (struct rspamd_classifier_config, max_tokens),
  2141. RSPAMD_CL_FLAG_INT_32,
  2142. "Maximum count of tokens (words) to be considered for statistics");
  2143. rspamd_rcl_add_default_handler (sub,
  2144. "min_learns",
  2145. rspamd_rcl_parse_struct_integer,
  2146. G_STRUCT_OFFSET (struct rspamd_classifier_config, min_learns),
  2147. RSPAMD_CL_FLAG_UINT,
  2148. "Minimum number of learns for each statfile to use this classifier");
  2149. rspamd_rcl_add_default_handler (sub,
  2150. "backend",
  2151. rspamd_rcl_parse_struct_string,
  2152. G_STRUCT_OFFSET (struct rspamd_classifier_config, backend),
  2153. 0,
  2154. "Statfiles engine");
  2155. rspamd_rcl_add_default_handler (sub,
  2156. "name",
  2157. rspamd_rcl_parse_struct_string,
  2158. G_STRUCT_OFFSET (struct rspamd_classifier_config, name),
  2159. 0,
  2160. "Name of classifier");
  2161. /*
  2162. * Statfile defaults
  2163. */
  2164. ssub = rspamd_rcl_add_section_doc (&sub->subsections,
  2165. "statfile", "symbol",
  2166. rspamd_rcl_statfile_handler,
  2167. UCL_OBJECT,
  2168. TRUE,
  2169. TRUE,
  2170. sub->doc_ref,
  2171. "Statfiles options");
  2172. rspamd_rcl_add_default_handler (ssub,
  2173. "label",
  2174. rspamd_rcl_parse_struct_string,
  2175. G_STRUCT_OFFSET (struct rspamd_statfile_config, label),
  2176. 0,
  2177. "Statfile unique label");
  2178. rspamd_rcl_add_default_handler (ssub,
  2179. "spam",
  2180. rspamd_rcl_parse_struct_boolean,
  2181. G_STRUCT_OFFSET (struct rspamd_statfile_config, is_spam),
  2182. 0,
  2183. "Sets if this statfile contains spam samples");
  2184. }
  2185. if (!(skip_sections && g_hash_table_lookup (skip_sections, "composite"))) {
  2186. /**
  2187. * Composites handlers
  2188. */
  2189. sub = rspamd_rcl_add_section_doc (&new,
  2190. "composite", "name",
  2191. rspamd_rcl_composite_handler,
  2192. UCL_OBJECT,
  2193. FALSE,
  2194. TRUE,
  2195. cfg->doc_strings,
  2196. "Rspamd composite symbols");
  2197. sub = rspamd_rcl_add_section_doc (&new,
  2198. "composites", NULL,
  2199. rspamd_rcl_composites_handler,
  2200. UCL_OBJECT,
  2201. FALSE,
  2202. TRUE,
  2203. cfg->doc_strings,
  2204. "Rspamd composite symbols");
  2205. }
  2206. if (!(skip_sections && g_hash_table_lookup (skip_sections, "lua"))) {
  2207. /**
  2208. * Lua handler
  2209. */
  2210. sub = rspamd_rcl_add_section_doc (&new,
  2211. "lua", NULL,
  2212. rspamd_rcl_lua_handler,
  2213. UCL_STRING,
  2214. FALSE,
  2215. TRUE,
  2216. cfg->doc_strings,
  2217. "Lua files to load");
  2218. }
  2219. return new;
  2220. }
  2221. struct rspamd_rcl_section *
  2222. rspamd_rcl_config_get_section (struct rspamd_rcl_section *top,
  2223. const char *path)
  2224. {
  2225. struct rspamd_rcl_section *cur, *found = NULL;
  2226. char **path_components;
  2227. gint ncomponents, i;
  2228. if (path == NULL) {
  2229. return top;
  2230. }
  2231. path_components = g_strsplit_set (path, "/", -1);
  2232. ncomponents = g_strv_length (path_components);
  2233. cur = top;
  2234. for (i = 0; i < ncomponents; i++) {
  2235. if (cur == NULL) {
  2236. g_strfreev (path_components);
  2237. return NULL;
  2238. }
  2239. HASH_FIND_STR (cur, path_components[i], found);
  2240. if (found == NULL) {
  2241. g_strfreev (path_components);
  2242. return NULL;
  2243. }
  2244. cur = found;
  2245. }
  2246. g_strfreev (path_components);
  2247. return found;
  2248. }
  2249. static gboolean
  2250. rspamd_rcl_process_section (struct rspamd_config *cfg,
  2251. struct rspamd_rcl_section *sec,
  2252. gpointer ptr, const ucl_object_t *obj, rspamd_mempool_t *pool,
  2253. GError **err)
  2254. {
  2255. ucl_object_iter_t it;
  2256. const ucl_object_t *cur;
  2257. gboolean is_nested = TRUE;
  2258. const gchar *key = NULL;
  2259. g_assert (obj != NULL);
  2260. g_assert (sec->handler != NULL);
  2261. if (sec->key_attr != NULL) {
  2262. it = ucl_object_iterate_new (obj);
  2263. while ((cur = ucl_object_iterate_full (it, UCL_ITERATE_EXPLICIT)) != NULL) {
  2264. if (ucl_object_type (cur) != UCL_OBJECT) {
  2265. is_nested = FALSE;
  2266. break;
  2267. }
  2268. }
  2269. ucl_object_iterate_free (it);
  2270. }
  2271. else {
  2272. is_nested = FALSE;
  2273. }
  2274. if (is_nested) {
  2275. /* Just reiterate on all subobjects */
  2276. it = ucl_object_iterate_new (obj);
  2277. while ((cur = ucl_object_iterate_full (it, UCL_ITERATE_EXPLICIT)) != NULL) {
  2278. if (!sec->handler (pool, cur, ucl_object_key (cur), ptr, sec, err)) {
  2279. ucl_object_iterate_free (it);
  2280. return FALSE;
  2281. }
  2282. }
  2283. ucl_object_iterate_free (it);
  2284. return TRUE;
  2285. }
  2286. else {
  2287. if (sec->key_attr != NULL) {
  2288. /* First of all search for required attribute and use it as a key */
  2289. cur = ucl_object_lookup (obj, sec->key_attr);
  2290. if (cur == NULL) {
  2291. if (sec->default_key == NULL) {
  2292. g_set_error (err, CFG_RCL_ERROR, EINVAL, "required attribute "
  2293. "'%s' is missing for section '%s', current key: %s",
  2294. sec->key_attr,
  2295. sec->name,
  2296. ucl_object_emit (obj, UCL_EMIT_CONFIG));
  2297. return FALSE;
  2298. }
  2299. else {
  2300. msg_info ("using default key '%s' for mandatory field '%s' "
  2301. "for section '%s'", sec->default_key, sec->key_attr,
  2302. sec->name);
  2303. key = sec->default_key;
  2304. }
  2305. }
  2306. else if (ucl_object_type (cur) != UCL_STRING) {
  2307. g_set_error (err, CFG_RCL_ERROR, EINVAL, "required attribute %s"
  2308. " is not a string for section %s",
  2309. sec->key_attr, sec->name);
  2310. return FALSE;
  2311. }
  2312. else {
  2313. key = ucl_object_tostring (cur);
  2314. }
  2315. }
  2316. }
  2317. return sec->handler (pool, obj, key, ptr, sec, err);
  2318. }
  2319. gboolean
  2320. rspamd_rcl_parse (struct rspamd_rcl_section *top,
  2321. struct rspamd_config *cfg,
  2322. gpointer ptr, rspamd_mempool_t *pool,
  2323. const ucl_object_t *obj, GError **err)
  2324. {
  2325. const ucl_object_t *found, *cur_obj;
  2326. struct rspamd_rcl_section *cur, *tmp, *found_sec;
  2327. if (obj->type != UCL_OBJECT) {
  2328. g_set_error (err,
  2329. CFG_RCL_ERROR,
  2330. EINVAL,
  2331. "top configuration must be an object");
  2332. return FALSE;
  2333. }
  2334. /* Iterate over known sections and ignore unknown ones */
  2335. HASH_ITER (hh, top, cur, tmp)
  2336. {
  2337. if (strcmp (cur->name, "*") == 0) {
  2338. /* Default section handler */
  2339. LL_FOREACH (obj, cur_obj) {
  2340. HASH_FIND_STR (top, ucl_object_key (cur_obj), found_sec);
  2341. if (found_sec == NULL) {
  2342. if (cur->handler != NULL) {
  2343. if (!rspamd_rcl_process_section (cfg, cur, ptr, cur_obj,
  2344. pool, err)) {
  2345. return FALSE;
  2346. }
  2347. }
  2348. else {
  2349. rspamd_rcl_section_parse_defaults (cfg,
  2350. cur,
  2351. pool,
  2352. cur_obj,
  2353. ptr,
  2354. err);
  2355. }
  2356. }
  2357. }
  2358. }
  2359. else {
  2360. found = ucl_object_lookup (obj, cur->name);
  2361. if (found == NULL) {
  2362. if (cur->required) {
  2363. g_set_error (err, CFG_RCL_ERROR, ENOENT,
  2364. "required section %s is missing", cur->name);
  2365. return FALSE;
  2366. }
  2367. }
  2368. else {
  2369. /* Check type */
  2370. if (cur->strict_type) {
  2371. if (cur->type != found->type) {
  2372. g_set_error (err, CFG_RCL_ERROR, EINVAL,
  2373. "object in section %s has invalid type", cur->name);
  2374. return FALSE;
  2375. }
  2376. }
  2377. LL_FOREACH (found, cur_obj) {
  2378. if (cur->handler != NULL) {
  2379. if (!rspamd_rcl_process_section (cfg, cur, ptr, cur_obj,
  2380. pool, err)) {
  2381. return FALSE;
  2382. }
  2383. }
  2384. else {
  2385. rspamd_rcl_section_parse_defaults (cfg, cur,
  2386. pool,
  2387. cur_obj,
  2388. ptr,
  2389. err);
  2390. }
  2391. }
  2392. }
  2393. }
  2394. if (cur->fin) {
  2395. cur->fin (pool, cur->fin_ud);
  2396. }
  2397. }
  2398. return TRUE;
  2399. }
  2400. gboolean
  2401. rspamd_rcl_section_parse_defaults (struct rspamd_config *cfg,
  2402. struct rspamd_rcl_section *section,
  2403. rspamd_mempool_t *pool, const ucl_object_t *obj, gpointer ptr,
  2404. GError **err)
  2405. {
  2406. const ucl_object_t *found, *cur_obj;
  2407. struct rspamd_rcl_default_handler_data *cur, *tmp;
  2408. if (obj->type != UCL_OBJECT) {
  2409. g_set_error (err,
  2410. CFG_RCL_ERROR,
  2411. EINVAL,
  2412. "default configuration must be an object for section %s "
  2413. "(actual type is %s)",
  2414. section->name, ucl_object_type_to_string (obj->type));
  2415. return FALSE;
  2416. }
  2417. HASH_ITER (hh, section->default_parser, cur, tmp)
  2418. {
  2419. found = ucl_object_lookup (obj, cur->key);
  2420. if (found != NULL) {
  2421. cur->pd.user_struct = ptr;
  2422. cur->pd.cfg = cfg;
  2423. LL_FOREACH (found, cur_obj) {
  2424. if (!cur->handler (pool, cur_obj, &cur->pd, section, err)) {
  2425. return FALSE;
  2426. }
  2427. if (!(cur->pd.flags & RSPAMD_CL_FLAG_MULTIPLE)) {
  2428. break;
  2429. }
  2430. }
  2431. }
  2432. }
  2433. return TRUE;
  2434. }
  2435. gboolean
  2436. rspamd_rcl_parse_struct_string (rspamd_mempool_t *pool,
  2437. const ucl_object_t *obj,
  2438. gpointer ud,
  2439. struct rspamd_rcl_section *section,
  2440. GError **err)
  2441. {
  2442. struct rspamd_rcl_struct_parser *pd = ud;
  2443. gchar **target;
  2444. const gsize num_str_len = 32;
  2445. target = (gchar **)(((gchar *)pd->user_struct) + pd->offset);
  2446. switch (obj->type) {
  2447. case UCL_STRING:
  2448. *target =
  2449. rspamd_mempool_strdup (pool, ucl_copy_value_trash (obj));
  2450. break;
  2451. case UCL_INT:
  2452. *target = rspamd_mempool_alloc (pool, num_str_len);
  2453. rspamd_snprintf (*target, num_str_len, "%L", obj->value.iv);
  2454. break;
  2455. case UCL_FLOAT:
  2456. *target = rspamd_mempool_alloc (pool, num_str_len);
  2457. rspamd_snprintf (*target, num_str_len, "%f", obj->value.dv);
  2458. break;
  2459. case UCL_BOOLEAN:
  2460. *target = rspamd_mempool_alloc (pool, num_str_len);
  2461. rspamd_snprintf (*target, num_str_len, "%s",
  2462. ((gboolean)obj->value.iv) ? "true" : "false");
  2463. break;
  2464. case UCL_NULL:
  2465. /* String is enforced to be null */
  2466. *target = NULL;
  2467. break;
  2468. default:
  2469. g_set_error (err,
  2470. CFG_RCL_ERROR,
  2471. EINVAL,
  2472. "cannot convert %s to string in option %s",
  2473. ucl_object_type_to_string (ucl_object_type (obj)),
  2474. ucl_object_key (obj));
  2475. return FALSE;
  2476. }
  2477. return TRUE;
  2478. }
  2479. gboolean
  2480. rspamd_rcl_parse_struct_integer (rspamd_mempool_t *pool,
  2481. const ucl_object_t *obj,
  2482. gpointer ud,
  2483. struct rspamd_rcl_section *section,
  2484. GError **err)
  2485. {
  2486. struct rspamd_rcl_struct_parser *pd = ud;
  2487. union {
  2488. gint *ip;
  2489. gint32 *i32p;
  2490. gint16 *i16p;
  2491. gint64 *i64p;
  2492. guint *up;
  2493. gsize *sp;
  2494. } target;
  2495. int64_t val;
  2496. if (pd->flags == RSPAMD_CL_FLAG_INT_32) {
  2497. target.i32p = (gint32 *)(((gchar *)pd->user_struct) + pd->offset);
  2498. if (!ucl_object_toint_safe (obj, &val)) {
  2499. g_set_error (err,
  2500. CFG_RCL_ERROR,
  2501. EINVAL,
  2502. "cannot convert %s to integer in option %s",
  2503. ucl_object_type_to_string (ucl_object_type (obj)),
  2504. ucl_object_key (obj));
  2505. return FALSE;
  2506. }
  2507. *target.i32p = val;
  2508. }
  2509. else if (pd->flags == RSPAMD_CL_FLAG_INT_64) {
  2510. target.i64p = (gint64 *)(((gchar *)pd->user_struct) + pd->offset);
  2511. if (!ucl_object_toint_safe (obj, &val)) {
  2512. g_set_error (err,
  2513. CFG_RCL_ERROR,
  2514. EINVAL,
  2515. "cannot convert %s to integer in option %s",
  2516. ucl_object_type_to_string (ucl_object_type (obj)),
  2517. ucl_object_key (obj));
  2518. return FALSE;
  2519. }
  2520. *target.i64p = val;
  2521. }
  2522. else if (pd->flags == RSPAMD_CL_FLAG_INT_SIZE) {
  2523. target.sp = (gsize *)(((gchar *)pd->user_struct) + pd->offset);
  2524. if (!ucl_object_toint_safe (obj, &val)) {
  2525. g_set_error (err,
  2526. CFG_RCL_ERROR,
  2527. EINVAL,
  2528. "cannot convert %s to integer in option %s",
  2529. ucl_object_type_to_string (ucl_object_type (obj)),
  2530. ucl_object_key (obj));
  2531. return FALSE;
  2532. }
  2533. *target.sp = val;
  2534. }
  2535. else if (pd->flags == RSPAMD_CL_FLAG_INT_16) {
  2536. target.i16p = (gint16 *)(((gchar *)pd->user_struct) + pd->offset);
  2537. if (!ucl_object_toint_safe (obj, &val)) {
  2538. g_set_error (err,
  2539. CFG_RCL_ERROR,
  2540. EINVAL,
  2541. "cannot convert %s to integer in option %s",
  2542. ucl_object_type_to_string (ucl_object_type (obj)),
  2543. ucl_object_key (obj));
  2544. return FALSE;
  2545. }
  2546. *target.i16p = val;
  2547. }
  2548. else if (pd->flags == RSPAMD_CL_FLAG_UINT) {
  2549. target.up = (guint *)(((gchar *)pd->user_struct) + pd->offset);
  2550. if (!ucl_object_toint_safe (obj, &val)) {
  2551. g_set_error (err,
  2552. CFG_RCL_ERROR,
  2553. EINVAL,
  2554. "cannot convert %s to integer in option %s",
  2555. ucl_object_type_to_string (ucl_object_type (obj)),
  2556. ucl_object_key (obj));
  2557. return FALSE;
  2558. }
  2559. *target.up = val;
  2560. }
  2561. else {
  2562. target.ip = (gint *)(((gchar *)pd->user_struct) + pd->offset);
  2563. if (!ucl_object_toint_safe (obj, &val)) {
  2564. g_set_error (err,
  2565. CFG_RCL_ERROR,
  2566. EINVAL,
  2567. "cannot convert %s to integer in option %s",
  2568. ucl_object_type_to_string (ucl_object_type (obj)),
  2569. ucl_object_key (obj));
  2570. return FALSE;
  2571. }
  2572. *target.ip = val;
  2573. }
  2574. return TRUE;
  2575. }
  2576. gboolean
  2577. rspamd_rcl_parse_struct_double (rspamd_mempool_t *pool,
  2578. const ucl_object_t *obj,
  2579. gpointer ud,
  2580. struct rspamd_rcl_section *section,
  2581. GError **err)
  2582. {
  2583. struct rspamd_rcl_struct_parser *pd = ud;
  2584. gdouble *target;
  2585. target = (gdouble *)(((gchar *)pd->user_struct) + pd->offset);
  2586. if (!ucl_object_todouble_safe (obj, target)) {
  2587. g_set_error (err,
  2588. CFG_RCL_ERROR,
  2589. EINVAL,
  2590. "cannot convert %s to double in option %s",
  2591. ucl_object_type_to_string (ucl_object_type (obj)),
  2592. ucl_object_key (obj));
  2593. return FALSE;
  2594. }
  2595. return TRUE;
  2596. }
  2597. gboolean
  2598. rspamd_rcl_parse_struct_time (rspamd_mempool_t *pool,
  2599. const ucl_object_t *obj,
  2600. gpointer ud,
  2601. struct rspamd_rcl_section *section,
  2602. GError **err)
  2603. {
  2604. struct rspamd_rcl_struct_parser *pd = ud;
  2605. union {
  2606. gint *psec;
  2607. guint32 *pu32;
  2608. gdouble *pdv;
  2609. struct timeval *ptv;
  2610. struct timespec *pts;
  2611. } target;
  2612. gdouble val;
  2613. if (!ucl_object_todouble_safe (obj, &val)) {
  2614. g_set_error (err,
  2615. CFG_RCL_ERROR,
  2616. EINVAL,
  2617. "cannot convert %s to double in option %s",
  2618. ucl_object_type_to_string (ucl_object_type (obj)),
  2619. ucl_object_key (obj));
  2620. return FALSE;
  2621. }
  2622. if (pd->flags == RSPAMD_CL_FLAG_TIME_TIMEVAL) {
  2623. target.ptv =
  2624. (struct timeval *)(((gchar *)pd->user_struct) + pd->offset);
  2625. target.ptv->tv_sec = (glong)val;
  2626. target.ptv->tv_usec = (val - (glong)val) * 1000000;
  2627. }
  2628. else if (pd->flags == RSPAMD_CL_FLAG_TIME_TIMESPEC) {
  2629. target.pts =
  2630. (struct timespec *)(((gchar *)pd->user_struct) + pd->offset);
  2631. target.pts->tv_sec = (glong)val;
  2632. target.pts->tv_nsec = (val - (glong)val) * 1000000000000LL;
  2633. }
  2634. else if (pd->flags == RSPAMD_CL_FLAG_TIME_FLOAT) {
  2635. target.pdv = (double *)(((gchar *)pd->user_struct) + pd->offset);
  2636. *target.pdv = val;
  2637. }
  2638. else if (pd->flags == RSPAMD_CL_FLAG_TIME_INTEGER) {
  2639. target.psec = (gint *)(((gchar *)pd->user_struct) + pd->offset);
  2640. *target.psec = val * 1000;
  2641. }
  2642. else if (pd->flags == RSPAMD_CL_FLAG_TIME_UINT_32) {
  2643. target.pu32 = (guint32 *)(((gchar *)pd->user_struct) + pd->offset);
  2644. *target.pu32 = val * 1000;
  2645. }
  2646. else {
  2647. g_set_error (err,
  2648. CFG_RCL_ERROR,
  2649. EINVAL,
  2650. "cannot convert %s to time in option %s",
  2651. ucl_object_type_to_string (ucl_object_type (obj)),
  2652. ucl_object_key (obj));
  2653. return FALSE;
  2654. }
  2655. return TRUE;
  2656. }
  2657. gboolean
  2658. rspamd_rcl_parse_struct_keypair (rspamd_mempool_t *pool,
  2659. const ucl_object_t *obj,
  2660. gpointer ud,
  2661. struct rspamd_rcl_section *section,
  2662. GError **err)
  2663. {
  2664. struct rspamd_rcl_struct_parser *pd = ud;
  2665. struct rspamd_cryptobox_keypair **target, *kp;
  2666. target = (struct rspamd_cryptobox_keypair **)(((gchar *)pd->user_struct) +
  2667. pd->offset);
  2668. if (obj->type == UCL_OBJECT) {
  2669. kp = rspamd_keypair_from_ucl (obj);
  2670. if (kp != NULL) {
  2671. rspamd_mempool_add_destructor (pool,
  2672. (rspamd_mempool_destruct_t)rspamd_keypair_unref, kp);
  2673. *target = kp;
  2674. }
  2675. else {
  2676. gchar *dump = ucl_object_emit (obj, UCL_EMIT_JSON_COMPACT);
  2677. g_set_error (err,
  2678. CFG_RCL_ERROR,
  2679. EINVAL,
  2680. "cannot load the keypair specified: %s; section: %s; value: %s",
  2681. ucl_object_key (obj), section->name, dump);
  2682. free (dump);
  2683. return FALSE;
  2684. }
  2685. }
  2686. else {
  2687. g_set_error (err,
  2688. CFG_RCL_ERROR,
  2689. EINVAL,
  2690. "no sane pubkey or privkey found in the keypair: %s",
  2691. ucl_object_key (obj));
  2692. return FALSE;
  2693. }
  2694. return TRUE;
  2695. }
  2696. gboolean
  2697. rspamd_rcl_parse_struct_pubkey (rspamd_mempool_t *pool,
  2698. const ucl_object_t *obj,
  2699. gpointer ud,
  2700. struct rspamd_rcl_section *section,
  2701. GError **err)
  2702. {
  2703. struct rspamd_rcl_struct_parser *pd = ud;
  2704. struct rspamd_cryptobox_pubkey **target, *pk;
  2705. gsize len;
  2706. const gchar *str;
  2707. gint keypair_type = RSPAMD_KEYPAIR_KEX,
  2708. keypair_mode = RSPAMD_CRYPTOBOX_MODE_25519;
  2709. if (pd->flags & RSPAMD_CL_FLAG_SIGNKEY) {
  2710. keypair_type = RSPAMD_KEYPAIR_SIGN;
  2711. }
  2712. if (pd->flags & RSPAMD_CL_FLAG_NISTKEY) {
  2713. keypair_mode = RSPAMD_CRYPTOBOX_MODE_NIST;
  2714. }
  2715. target = (struct rspamd_cryptobox_pubkey **)(((gchar *)pd->user_struct) +
  2716. pd->offset);
  2717. if (obj->type == UCL_STRING) {
  2718. str = ucl_object_tolstring (obj, &len);
  2719. pk = rspamd_pubkey_from_base32 (str, len, keypair_type,
  2720. keypair_mode);
  2721. if (pk != NULL) {
  2722. *target = pk;
  2723. }
  2724. else {
  2725. g_set_error (err,
  2726. CFG_RCL_ERROR,
  2727. EINVAL,
  2728. "cannot load the pubkey specified: %s",
  2729. ucl_object_key (obj));
  2730. return FALSE;
  2731. }
  2732. }
  2733. else {
  2734. g_set_error (err,
  2735. CFG_RCL_ERROR,
  2736. EINVAL,
  2737. "no sane pubkey found in the element: %s",
  2738. ucl_object_key (obj));
  2739. return FALSE;
  2740. }
  2741. rspamd_mempool_add_destructor (pool,
  2742. (rspamd_mempool_destruct_t)rspamd_pubkey_unref, pk);
  2743. return TRUE;
  2744. }
  2745. static void
  2746. rspamd_rcl_insert_string_list_item (gpointer *target, rspamd_mempool_t *pool,
  2747. const gchar *src, gboolean is_hash)
  2748. {
  2749. union {
  2750. GHashTable *hv;
  2751. GList *lv;
  2752. gpointer p;
  2753. } d;
  2754. gchar *val;
  2755. d.p = *target;
  2756. if (is_hash) {
  2757. if (d.hv == NULL) {
  2758. d.hv = g_hash_table_new (rspamd_str_hash, rspamd_str_equal);
  2759. rspamd_mempool_add_destructor (pool,
  2760. (rspamd_mempool_destruct_t)g_hash_table_unref, d.hv);
  2761. }
  2762. val = rspamd_mempool_strdup (pool, src);
  2763. g_hash_table_insert (d.hv, val, val);
  2764. }
  2765. else {
  2766. val = rspamd_mempool_strdup (pool, src);
  2767. d.lv = g_list_prepend (d.lv, val);
  2768. }
  2769. *target = d.p;
  2770. }
  2771. gboolean
  2772. rspamd_rcl_parse_struct_string_list (rspamd_mempool_t *pool,
  2773. const ucl_object_t *obj,
  2774. gpointer ud,
  2775. struct rspamd_rcl_section *section,
  2776. GError **err)
  2777. {
  2778. struct rspamd_rcl_struct_parser *pd = ud;
  2779. gpointer *target;
  2780. gchar *val, **strvec, **cvec;
  2781. const ucl_object_t *cur;
  2782. const gsize num_str_len = 32;
  2783. ucl_object_iter_t iter = NULL;
  2784. gboolean is_hash, need_destructor = TRUE;
  2785. is_hash = pd->flags & RSPAMD_CL_FLAG_STRING_LIST_HASH;
  2786. target = (gpointer *)(((gchar *)pd->user_struct) + pd->offset);
  2787. if (!is_hash && *target != NULL) {
  2788. need_destructor = FALSE;
  2789. }
  2790. iter = ucl_object_iterate_new (obj);
  2791. while ((cur = ucl_object_iterate_safe (iter, true)) != NULL) {
  2792. switch (cur->type) {
  2793. case UCL_STRING:
  2794. strvec = g_strsplit_set (ucl_object_tostring (cur), ",", -1);
  2795. cvec = strvec;
  2796. while (*cvec) {
  2797. rspamd_rcl_insert_string_list_item (target, pool, *cvec, is_hash);
  2798. cvec ++;
  2799. }
  2800. g_strfreev (strvec);
  2801. /* Go to the next object */
  2802. continue;
  2803. case UCL_INT:
  2804. val = rspamd_mempool_alloc (pool, num_str_len);
  2805. rspamd_snprintf (val, num_str_len, "%L", cur->value.iv);
  2806. break;
  2807. case UCL_FLOAT:
  2808. val = rspamd_mempool_alloc (pool, num_str_len);
  2809. rspamd_snprintf (val, num_str_len, "%f", cur->value.dv);
  2810. break;
  2811. case UCL_BOOLEAN:
  2812. val = rspamd_mempool_alloc (pool, num_str_len);
  2813. rspamd_snprintf (val, num_str_len, "%s",
  2814. ((gboolean)cur->value.iv) ? "true" : "false");
  2815. break;
  2816. default:
  2817. g_set_error (err,
  2818. CFG_RCL_ERROR,
  2819. EINVAL,
  2820. "cannot convert %s to a string list in option %s",
  2821. ucl_object_type_to_string (ucl_object_type (obj)),
  2822. ucl_object_key (obj));
  2823. ucl_object_iterate_free (iter);
  2824. return FALSE;
  2825. }
  2826. rspamd_rcl_insert_string_list_item (target, pool, val, is_hash);
  2827. }
  2828. ucl_object_iterate_free (iter);
  2829. #if 0
  2830. /* WTF: why don't we allow empty list here?? */
  2831. if (*target == NULL) {
  2832. g_set_error (err,
  2833. CFG_RCL_ERROR,
  2834. EINVAL,
  2835. "non-empty array of strings is expected: %s, "
  2836. "got: %s, of length: %d",
  2837. ucl_object_key (obj), ucl_object_type_to_string (obj->type),
  2838. obj->len);
  2839. return FALSE;
  2840. }
  2841. #endif
  2842. if (!is_hash && *target != NULL) {
  2843. *target = g_list_reverse (*target);
  2844. if (need_destructor) {
  2845. rspamd_mempool_add_destructor (pool,
  2846. (rspamd_mempool_destruct_t) g_list_free,
  2847. *target);
  2848. }
  2849. }
  2850. return TRUE;
  2851. }
  2852. gboolean
  2853. rspamd_rcl_parse_struct_ucl (rspamd_mempool_t *pool,
  2854. const ucl_object_t *obj,
  2855. gpointer ud,
  2856. struct rspamd_rcl_section *section,
  2857. GError **err)
  2858. {
  2859. struct rspamd_rcl_struct_parser *pd = ud;
  2860. const ucl_object_t **target;
  2861. target = (const ucl_object_t **)(((gchar *)pd->user_struct) + pd->offset);
  2862. *target = obj;
  2863. return TRUE;
  2864. }
  2865. gboolean
  2866. rspamd_rcl_parse_struct_boolean (rspamd_mempool_t *pool,
  2867. const ucl_object_t *obj,
  2868. gpointer ud,
  2869. struct rspamd_rcl_section *section,
  2870. GError **err)
  2871. {
  2872. struct rspamd_rcl_struct_parser *pd = ud;
  2873. gboolean *target;
  2874. target = (gboolean *)(((gchar *)pd->user_struct) + pd->offset);
  2875. if (obj->type == UCL_BOOLEAN) {
  2876. *target = obj->value.iv;
  2877. }
  2878. else if (obj->type == UCL_INT) {
  2879. *target = obj->value.iv;
  2880. }
  2881. else {
  2882. g_set_error (err,
  2883. CFG_RCL_ERROR,
  2884. EINVAL,
  2885. "cannot convert %s to boolean in option %s",
  2886. ucl_object_type_to_string (ucl_object_type (obj)),
  2887. ucl_object_key (obj));
  2888. return FALSE;
  2889. }
  2890. if (pd->flags & RSPAMD_CL_FLAG_BOOLEAN_INVERSE) {
  2891. *target = !*target;
  2892. }
  2893. return TRUE;
  2894. }
  2895. gboolean
  2896. rspamd_rcl_parse_struct_addr (rspamd_mempool_t *pool,
  2897. const ucl_object_t *obj,
  2898. gpointer ud,
  2899. struct rspamd_rcl_section *section,
  2900. GError **err)
  2901. {
  2902. struct rspamd_rcl_struct_parser *pd = ud;
  2903. rspamd_inet_addr_t **target;
  2904. const gchar *val;
  2905. gsize size;
  2906. target = (rspamd_inet_addr_t **)(((gchar *)pd->user_struct) + pd->offset);
  2907. if (ucl_object_type (obj) == UCL_STRING) {
  2908. val = ucl_object_tolstring (obj, &size);
  2909. if (!rspamd_parse_inet_address (target, val, size,
  2910. RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) {
  2911. g_set_error (err,
  2912. CFG_RCL_ERROR,
  2913. EINVAL,
  2914. "cannot parse inet address: %s", val);
  2915. return FALSE;
  2916. }
  2917. }
  2918. else {
  2919. g_set_error (err,
  2920. CFG_RCL_ERROR,
  2921. EINVAL,
  2922. "cannot convert %s to inet address in option %s",
  2923. ucl_object_type_to_string (ucl_object_type (obj)),
  2924. ucl_object_key (obj));
  2925. return FALSE;
  2926. }
  2927. return TRUE;
  2928. }
  2929. gboolean
  2930. rspamd_rcl_parse_struct_mime_addr (rspamd_mempool_t *pool,
  2931. const ucl_object_t *obj,
  2932. gpointer ud,
  2933. struct rspamd_rcl_section *section,
  2934. GError **err)
  2935. {
  2936. struct rspamd_rcl_struct_parser *pd = ud;
  2937. GPtrArray **target, *tmp_addr = NULL;
  2938. const gchar *val;
  2939. ucl_object_iter_t it;
  2940. const ucl_object_t *cur;
  2941. target = (GPtrArray **)(((gchar *)pd->user_struct) + pd->offset);
  2942. it = ucl_object_iterate_new (obj);
  2943. while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
  2944. if (ucl_object_type (cur) == UCL_STRING) {
  2945. val = ucl_object_tostring (obj);
  2946. tmp_addr = rspamd_email_address_from_mime (pool, val,
  2947. strlen (val), tmp_addr, -1);
  2948. }
  2949. else {
  2950. g_set_error (err,
  2951. CFG_RCL_ERROR,
  2952. EINVAL,
  2953. "cannot get inet address from ucl object in %s",
  2954. ucl_object_key (obj));
  2955. ucl_object_iterate_free (it);
  2956. return FALSE;
  2957. }
  2958. }
  2959. ucl_object_iterate_free (it);
  2960. *target = tmp_addr;
  2961. return TRUE;
  2962. }
  2963. static guint
  2964. rspamd_worker_param_key_hash (gconstpointer p)
  2965. {
  2966. const struct rspamd_worker_param_key *k = p;
  2967. rspamd_cryptobox_fast_hash_state_t st;
  2968. rspamd_cryptobox_fast_hash_init (&st, rspamd_hash_seed ());
  2969. rspamd_cryptobox_fast_hash_update (&st, k->name, strlen (k->name));
  2970. rspamd_cryptobox_fast_hash_update (&st, &k->ptr, sizeof (gpointer));
  2971. return rspamd_cryptobox_fast_hash_final (&st);
  2972. }
  2973. static gboolean
  2974. rspamd_worker_param_key_equal (gconstpointer p1, gconstpointer p2)
  2975. {
  2976. const struct rspamd_worker_param_key *k1 = p1, *k2 = p2;
  2977. if (k1->ptr == k2->ptr) {
  2978. return strcmp (k1->name, k2->name) == 0;
  2979. }
  2980. return FALSE;
  2981. }
  2982. void
  2983. rspamd_rcl_register_worker_option (struct rspamd_config *cfg,
  2984. GQuark type,
  2985. const gchar *name,
  2986. rspamd_rcl_default_handler_t handler,
  2987. gpointer target,
  2988. glong offset,
  2989. gint flags,
  2990. const gchar *doc_string)
  2991. {
  2992. struct rspamd_worker_param_parser *nhandler;
  2993. struct rspamd_worker_cfg_parser *nparser;
  2994. struct rspamd_worker_param_key srch;
  2995. const ucl_object_t *doc_workers, *doc_target;
  2996. ucl_object_t *doc_obj;
  2997. nparser = g_hash_table_lookup (cfg->wrk_parsers, &type);
  2998. if (nparser == NULL) {
  2999. rspamd_rcl_register_worker_parser (cfg, type, NULL, NULL);
  3000. nparser = g_hash_table_lookup (cfg->wrk_parsers, &type);
  3001. g_assert (nparser != NULL);
  3002. }
  3003. srch.name = name;
  3004. srch.ptr = target;
  3005. nhandler = g_hash_table_lookup (nparser->parsers, &srch);
  3006. if (nhandler != NULL) {
  3007. msg_warn_config (
  3008. "handler for parameter %s is already registered for worker type %s",
  3009. name,
  3010. g_quark_to_string (type));
  3011. return;
  3012. }
  3013. nhandler =
  3014. rspamd_mempool_alloc0 (cfg->cfg_pool,
  3015. sizeof (struct rspamd_worker_param_parser));
  3016. nhandler->key.name = name;
  3017. nhandler->key.ptr = target;
  3018. nhandler->parser.flags = flags;
  3019. nhandler->parser.offset = offset;
  3020. nhandler->parser.user_struct = target;
  3021. nhandler->handler = handler;
  3022. g_hash_table_insert (nparser->parsers, &nhandler->key, nhandler);
  3023. doc_workers = ucl_object_lookup (cfg->doc_strings, "workers");
  3024. if (doc_workers == NULL) {
  3025. doc_obj = ucl_object_typed_new (UCL_OBJECT);
  3026. ucl_object_insert_key (cfg->doc_strings, doc_obj, "workers", 0, false);
  3027. doc_workers = doc_obj;
  3028. }
  3029. doc_target = ucl_object_lookup (doc_workers, g_quark_to_string (type));
  3030. if (doc_target == NULL) {
  3031. doc_obj = ucl_object_typed_new (UCL_OBJECT);
  3032. ucl_object_insert_key ((ucl_object_t *)doc_workers, doc_obj,
  3033. g_quark_to_string (type), 0, true);
  3034. doc_target = doc_obj;
  3035. }
  3036. rspamd_rcl_add_doc_obj ((ucl_object_t *) doc_target,
  3037. doc_string,
  3038. name,
  3039. UCL_NULL,
  3040. handler,
  3041. flags,
  3042. NULL,
  3043. 0);
  3044. }
  3045. void
  3046. rspamd_rcl_register_worker_parser (struct rspamd_config *cfg, gint type,
  3047. gboolean (*func)(ucl_object_t *, gpointer), gpointer ud)
  3048. {
  3049. struct rspamd_worker_cfg_parser *nparser;
  3050. nparser = g_hash_table_lookup (cfg->wrk_parsers, &type);
  3051. if (nparser == NULL) {
  3052. /* Allocate new parser for this worker */
  3053. nparser =
  3054. rspamd_mempool_alloc0 (cfg->cfg_pool,
  3055. sizeof (struct rspamd_worker_cfg_parser));
  3056. nparser->type = type;
  3057. nparser->parsers = g_hash_table_new (rspamd_worker_param_key_hash,
  3058. rspamd_worker_param_key_equal);
  3059. rspamd_mempool_add_destructor (cfg->cfg_pool,
  3060. (rspamd_mempool_destruct_t)g_hash_table_unref, nparser->parsers);
  3061. g_hash_table_insert (cfg->wrk_parsers, &nparser->type, nparser);
  3062. }
  3063. nparser->def_obj_parser = func;
  3064. nparser->def_ud = ud;
  3065. }
  3066. /* Checksum functions */
  3067. static int
  3068. rspamd_rcl_emitter_append_c (unsigned char c, size_t nchars, void *ud)
  3069. {
  3070. rspamd_cryptobox_hash_state_t *hs = ud;
  3071. guint64 d[2];
  3072. d[0] = nchars;
  3073. d[1] = c;
  3074. rspamd_cryptobox_hash_update (hs, (const guchar *)d, sizeof (d));
  3075. return 0;
  3076. }
  3077. static int
  3078. rspamd_rcl_emitter_append_len (unsigned const char *str, size_t len, void *ud)
  3079. {
  3080. rspamd_cryptobox_hash_state_t *hs = ud;
  3081. rspamd_cryptobox_hash_update (hs, str, len);
  3082. return 0;
  3083. }
  3084. static int
  3085. rspamd_rcl_emitter_append_int (int64_t elt, void *ud)
  3086. {
  3087. rspamd_cryptobox_hash_state_t *hs = ud;
  3088. rspamd_cryptobox_hash_update (hs, (const guchar *)&elt, sizeof (elt));
  3089. return 0;
  3090. }
  3091. static int
  3092. rspamd_rcl_emitter_append_double (double elt, void *ud)
  3093. {
  3094. rspamd_cryptobox_hash_state_t *hs = ud;
  3095. rspamd_cryptobox_hash_update (hs, (const guchar *)&elt, sizeof (elt));
  3096. return 0;
  3097. }
  3098. void
  3099. rspamd_rcl_section_free (gpointer p)
  3100. {
  3101. struct rspamd_rcl_section *top = p, *cur, *tmp;
  3102. struct rspamd_rcl_default_handler_data *dh, *dhtmp;
  3103. HASH_ITER (hh, top, cur, tmp) {
  3104. HASH_DEL (top, cur);
  3105. if (cur->subsections) {
  3106. rspamd_rcl_section_free (cur->subsections);
  3107. }
  3108. HASH_ITER (hh, cur->default_parser, dh, dhtmp) {
  3109. HASH_DEL (cur->default_parser, dh);
  3110. g_free (dh->key);
  3111. g_free (dh);
  3112. }
  3113. ucl_object_unref (cur->doc_ref);
  3114. g_free (cur);
  3115. }
  3116. }
  3117. /**
  3118. * Calls for an external lua function to apply potential config transformations
  3119. * if needed. This function can change the cfg->rcl_obj.
  3120. *
  3121. * Example of transformation function:
  3122. *
  3123. * function(obj)
  3124. * if obj.something == 'foo' then
  3125. * obj.something = "bla"
  3126. * return true, obj
  3127. * end
  3128. *
  3129. * return false, nil
  3130. * end
  3131. *
  3132. * If function returns 'false' then rcl_obj is not touched. Otherwise,
  3133. * it is changed, then rcl_obj is imported from lua. Old config is dereferenced.
  3134. * @param cfg
  3135. */
  3136. void
  3137. rspamd_rcl_maybe_apply_lua_transform (struct rspamd_config *cfg)
  3138. {
  3139. lua_State *L = cfg->lua_state;
  3140. gint err_idx, ret;
  3141. gchar str[PATH_MAX];
  3142. static const char *transform_script = "lua_cfg_transform";
  3143. g_assert (L != NULL);
  3144. rspamd_snprintf (str, sizeof (str), "return require \"%s\"",
  3145. transform_script);
  3146. if (luaL_dostring (L, str) != 0) {
  3147. msg_warn_config ("cannot execute lua script %s: %s",
  3148. str, lua_tostring (L, -1));
  3149. return;
  3150. }
  3151. else {
  3152. #if LUA_VERSION_NUM >= 504
  3153. lua_settop(L, -2);
  3154. #endif
  3155. if (lua_type (L, -1) != LUA_TFUNCTION) {
  3156. msg_warn_config ("lua script must return "
  3157. "function and not %s",
  3158. lua_typename (L, lua_type (L, -1)));
  3159. return;
  3160. }
  3161. }
  3162. lua_pushcfunction (L, &rspamd_lua_traceback);
  3163. err_idx = lua_gettop (L);
  3164. /* Push function */
  3165. lua_pushvalue (L, -2);
  3166. /* Push the existing config */
  3167. ucl_object_push_lua (L, cfg->rcl_obj, true);
  3168. if ((ret = lua_pcall (L, 1, 2, err_idx)) != 0) {
  3169. msg_err ("call to rspamadm lua script failed (%d): %s", ret,
  3170. lua_tostring (L, -1));
  3171. lua_settop (L, 0);
  3172. return;
  3173. }
  3174. if (lua_toboolean (L, -2) && lua_type (L, -1) == LUA_TTABLE) {
  3175. ucl_object_t *old_cfg = cfg->rcl_obj;
  3176. msg_info_config ("configuration has been transformed in Lua");
  3177. cfg->rcl_obj = ucl_object_lua_import (L, -1);
  3178. ucl_object_unref (old_cfg);
  3179. }
  3180. /* error function */
  3181. lua_settop (L, 0);
  3182. }
  3183. static bool
  3184. rspamd_rcl_decrypt_handler (struct ucl_parser *parser,
  3185. const unsigned char *source, size_t source_len,
  3186. unsigned char **destination, size_t *dest_len,
  3187. void *user_data)
  3188. {
  3189. GError *err = NULL;
  3190. struct rspamd_cryptobox_keypair *kp = (struct rspamd_cryptobox_keypair *)user_data;
  3191. if (!rspamd_keypair_decrypt (kp, source, source_len,
  3192. destination, dest_len, &err)) {
  3193. msg_err ("cannot decrypt file: %e", err);
  3194. g_error_free (err);
  3195. return false;
  3196. }
  3197. return true;
  3198. }
  3199. static bool
  3200. rspamd_rcl_jinja_handler (struct ucl_parser *parser,
  3201. const unsigned char *source, size_t source_len,
  3202. unsigned char **destination, size_t *dest_len,
  3203. void *user_data)
  3204. {
  3205. struct rspamd_config *cfg = (struct rspamd_config *)user_data;
  3206. lua_State *L = cfg->lua_state;
  3207. gint err_idx;
  3208. lua_pushcfunction (L, &rspamd_lua_traceback);
  3209. err_idx = lua_gettop (L);
  3210. /* Obtain function */
  3211. if (!rspamd_lua_require_function (L, "lua_util", "jinja_template")) {
  3212. msg_err_config ("cannot require lua_util.jinja_template");
  3213. lua_settop (L, err_idx - 1);
  3214. return false;
  3215. }
  3216. lua_pushlstring (L, source, source_len);
  3217. lua_getglobal (L, "rspamd_env");
  3218. lua_pushboolean (L, false);
  3219. if (lua_pcall (L, 3, 1, err_idx) != 0) {
  3220. msg_err_config ("cannot call lua jinja_template script: %s",
  3221. lua_tostring (L, -1));
  3222. lua_settop (L, err_idx - 1);
  3223. return false;
  3224. }
  3225. if (lua_type (L, -1) == LUA_TSTRING) {
  3226. const char *ndata;
  3227. gsize nsize;
  3228. ndata = lua_tolstring (L, -1, &nsize);
  3229. *destination = UCL_ALLOC (nsize);
  3230. memcpy (*destination, ndata, nsize);
  3231. *dest_len = nsize;
  3232. }
  3233. else {
  3234. msg_err_config ("invalid return type when templating jinja %s",
  3235. lua_typename (L, lua_type (L, -1)));
  3236. lua_settop (L, err_idx - 1);
  3237. return false;
  3238. }
  3239. lua_settop (L, err_idx - 1);
  3240. return true;
  3241. }
  3242. static void
  3243. rspamd_rcl_decrypt_free (unsigned char *data, size_t len, void *user_data)
  3244. {
  3245. g_free (data);
  3246. }
  3247. void
  3248. rspamd_config_calculate_cksum (struct rspamd_config *cfg)
  3249. {
  3250. rspamd_cryptobox_hash_state_t hs;
  3251. unsigned char cksumbuf[rspamd_cryptobox_HASHBYTES];
  3252. struct ucl_emitter_functions f;
  3253. /* Calculate checksum */
  3254. rspamd_cryptobox_hash_init (&hs, NULL, 0);
  3255. f.ucl_emitter_append_character = rspamd_rcl_emitter_append_c;
  3256. f.ucl_emitter_append_double = rspamd_rcl_emitter_append_double;
  3257. f.ucl_emitter_append_int = rspamd_rcl_emitter_append_int;
  3258. f.ucl_emitter_append_len = rspamd_rcl_emitter_append_len;
  3259. f.ucl_emitter_free_func = NULL;
  3260. f.ud = &hs;
  3261. ucl_object_emit_full (cfg->rcl_obj, UCL_EMIT_MSGPACK,
  3262. &f, cfg->config_comments);
  3263. rspamd_cryptobox_hash_final (&hs, cksumbuf);
  3264. cfg->checksum = rspamd_encode_base32 (cksumbuf, sizeof (cksumbuf), RSPAMD_BASE32_DEFAULT);
  3265. /* Also change the tag of cfg pool to be equal to the checksum */
  3266. rspamd_strlcpy (cfg->cfg_pool->tag.uid, cfg->checksum,
  3267. MIN (sizeof (cfg->cfg_pool->tag.uid), strlen (cfg->checksum)));
  3268. }
  3269. gboolean
  3270. rspamd_config_parse_ucl (struct rspamd_config *cfg,
  3271. const gchar *filename,
  3272. GHashTable *vars,
  3273. ucl_include_trace_func_t inc_trace,
  3274. void *trace_data,
  3275. gboolean skip_jinja,
  3276. GError **err)
  3277. {
  3278. struct stat st;
  3279. gint fd;
  3280. struct ucl_parser *parser;
  3281. gchar keypair_path[PATH_MAX];
  3282. struct rspamd_cryptobox_keypair *decrypt_keypair = NULL;
  3283. gchar *data;
  3284. if ((fd = open (filename, O_RDONLY)) == -1) {
  3285. g_set_error (err, cfg_rcl_error_quark (), errno,
  3286. "cannot open %s: %s", filename, strerror (errno));
  3287. return FALSE;
  3288. }
  3289. if (fstat (fd, &st) == -1) {
  3290. g_set_error (err, cfg_rcl_error_quark (), errno,
  3291. "cannot stat %s: %s", filename, strerror (errno));
  3292. close (fd);
  3293. return FALSE;
  3294. }
  3295. /* Now mmap this file to simplify reading process */
  3296. if ((data = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
  3297. g_set_error (err, cfg_rcl_error_quark (), errno,
  3298. "cannot mmap %s: %s", filename, strerror (errno));
  3299. close (fd);
  3300. return FALSE;
  3301. }
  3302. close (fd);
  3303. /* Try to load keyfile if available */
  3304. rspamd_snprintf (keypair_path, sizeof (keypair_path), "%s.key",
  3305. filename);
  3306. if ((fd = open (keypair_path, O_RDONLY)) != -1) {
  3307. struct ucl_parser *kp_parser;
  3308. kp_parser = ucl_parser_new (0);
  3309. if (ucl_parser_add_fd (kp_parser, fd)) {
  3310. ucl_object_t *kp_obj;
  3311. kp_obj = ucl_parser_get_object (kp_parser);
  3312. g_assert (kp_obj != NULL);
  3313. decrypt_keypair = rspamd_keypair_from_ucl (kp_obj);
  3314. if (decrypt_keypair == NULL) {
  3315. msg_err_config_forced ("cannot load keypair from %s: invalid keypair",
  3316. keypair_path);
  3317. }
  3318. else {
  3319. /* Add decryption support to UCL */
  3320. rspamd_mempool_add_destructor (cfg->cfg_pool,
  3321. (rspamd_mempool_destruct_t)rspamd_keypair_unref,
  3322. decrypt_keypair);
  3323. }
  3324. ucl_object_unref (kp_obj);
  3325. }
  3326. else {
  3327. msg_err_config_forced ("cannot load keypair from %s: %s",
  3328. keypair_path, ucl_parser_get_error (kp_parser));
  3329. }
  3330. ucl_parser_free (kp_parser);
  3331. close (fd);
  3332. }
  3333. parser = ucl_parser_new (UCL_PARSER_SAVE_COMMENTS);
  3334. rspamd_ucl_add_conf_variables (parser, vars);
  3335. rspamd_ucl_add_conf_macros (parser, cfg);
  3336. ucl_parser_set_filevars (parser, filename, true);
  3337. if (inc_trace) {
  3338. ucl_parser_set_include_tracer (parser, inc_trace, trace_data);
  3339. }
  3340. if (decrypt_keypair) {
  3341. struct ucl_parser_special_handler *decrypt_handler;
  3342. decrypt_handler = rspamd_mempool_alloc0 (cfg->cfg_pool,
  3343. sizeof (*decrypt_handler));
  3344. decrypt_handler->user_data = decrypt_keypair;
  3345. decrypt_handler->magic = encrypted_magic;
  3346. decrypt_handler->magic_len = sizeof (encrypted_magic);
  3347. decrypt_handler->handler = rspamd_rcl_decrypt_handler;
  3348. decrypt_handler->free_function = rspamd_rcl_decrypt_free;
  3349. ucl_parser_add_special_handler (parser, decrypt_handler);
  3350. }
  3351. if (!skip_jinja) {
  3352. struct ucl_parser_special_handler *jinja_handler;
  3353. jinja_handler = rspamd_mempool_alloc0 (cfg->cfg_pool,
  3354. sizeof (*jinja_handler));
  3355. jinja_handler->user_data = cfg;
  3356. jinja_handler->flags = UCL_SPECIAL_HANDLER_PREPROCESS_ALL;
  3357. jinja_handler->handler = rspamd_rcl_jinja_handler;
  3358. ucl_parser_add_special_handler (parser, jinja_handler);
  3359. }
  3360. if (!ucl_parser_add_chunk (parser, data, st.st_size)) {
  3361. g_set_error (err, cfg_rcl_error_quark (), errno,
  3362. "ucl parser error: %s", ucl_parser_get_error (parser));
  3363. ucl_parser_free (parser);
  3364. munmap (data, st.st_size);
  3365. return FALSE;
  3366. }
  3367. munmap (data, st.st_size);
  3368. cfg->rcl_obj = ucl_parser_get_object (parser);
  3369. cfg->config_comments = ucl_object_ref (ucl_parser_get_comments (parser));
  3370. ucl_parser_free (parser);
  3371. return TRUE;
  3372. }
  3373. gboolean
  3374. rspamd_config_read (struct rspamd_config *cfg,
  3375. const gchar *filename,
  3376. rspamd_rcl_section_fin_t logger_fin,
  3377. gpointer logger_ud,
  3378. GHashTable *vars,
  3379. gboolean skip_jinja,
  3380. gchar **lua_env)
  3381. {
  3382. GError *err = NULL;
  3383. struct rspamd_rcl_section *top, *logger_section;
  3384. const ucl_object_t *logger_obj;
  3385. rspamd_lua_set_path (cfg->lua_state, NULL, vars);
  3386. if (!rspamd_lua_set_env (cfg->lua_state, vars, lua_env, &err)) {
  3387. msg_err_config_forced ("failed to set up environment: %e", err);
  3388. g_error_free (err);
  3389. return FALSE;
  3390. }
  3391. if (!rspamd_config_parse_ucl (cfg, filename, vars, NULL, NULL, skip_jinja, &err)) {
  3392. msg_err_config_forced ("failed to load config: %e", err);
  3393. g_error_free (err);
  3394. return FALSE;
  3395. }
  3396. top = rspamd_rcl_config_init (cfg, NULL);
  3397. /* Add new paths if defined in options */
  3398. rspamd_lua_set_path (cfg->lua_state, cfg->rcl_obj, vars);
  3399. rspamd_lua_set_globals (cfg, cfg->lua_state);
  3400. rspamd_mempool_add_destructor (cfg->cfg_pool, rspamd_rcl_section_free, top);
  3401. err = NULL;
  3402. if (logger_fin != NULL) {
  3403. HASH_FIND_STR (top, "logging", logger_section);
  3404. if (logger_section != NULL) {
  3405. logger_obj = ucl_object_lookup_any (cfg->rcl_obj, "logging",
  3406. "logger", NULL);
  3407. if (logger_obj == NULL) {
  3408. logger_fin (cfg->cfg_pool, logger_ud);
  3409. }
  3410. else {
  3411. if (!rspamd_rcl_process_section (cfg, logger_section, cfg,
  3412. logger_obj, cfg->cfg_pool, &err)) {
  3413. msg_err_config_forced ("cannot init logger: %e", err);
  3414. g_error_free (err);
  3415. return FALSE;
  3416. } else {
  3417. logger_fin (cfg->cfg_pool, logger_ud);
  3418. }
  3419. /* Init lua logging */
  3420. lua_State *L = cfg->lua_state;
  3421. gint err_idx;
  3422. struct rspamd_config **pcfg;
  3423. lua_pushcfunction (L, &rspamd_lua_traceback);
  3424. err_idx = lua_gettop (L);
  3425. /* Obtain function */
  3426. if (!rspamd_lua_require_function (L, "lua_util",
  3427. "init_debug_logging")) {
  3428. msg_err_config ("cannot require lua_util.init_debug_logging");
  3429. lua_settop (L, err_idx - 1);
  3430. return FALSE;
  3431. }
  3432. pcfg = lua_newuserdata (L, sizeof (*pcfg));
  3433. *pcfg = cfg;
  3434. rspamd_lua_setclass (L, "rspamd{config}", -1);
  3435. if (lua_pcall (L, 1, 0, err_idx) != 0) {
  3436. msg_err_config ("cannot call lua init_debug_logging script: %s",
  3437. lua_tostring (L, -1));
  3438. lua_settop (L, err_idx - 1);
  3439. return FALSE;
  3440. }
  3441. lua_settop (L, err_idx - 1);
  3442. }
  3443. HASH_DEL (top, logger_section);
  3444. }
  3445. }
  3446. /* Transform config if needed */
  3447. rspamd_rcl_maybe_apply_lua_transform (cfg);
  3448. rspamd_config_calculate_cksum (cfg);
  3449. if (!rspamd_rcl_parse (top, cfg, cfg, cfg->cfg_pool, cfg->rcl_obj, &err)) {
  3450. msg_err_config ("rcl parse error: %e", err);
  3451. if (err) {
  3452. g_error_free (err);
  3453. }
  3454. return FALSE;
  3455. }
  3456. cfg->lang_det = rspamd_language_detector_init (cfg);
  3457. rspamd_mempool_add_destructor (cfg->cfg_pool,
  3458. (rspamd_mempool_destruct_t)rspamd_language_detector_unref,
  3459. cfg->lang_det);
  3460. return TRUE;
  3461. }
  3462. static void
  3463. rspamd_rcl_doc_obj_from_handler (ucl_object_t *doc_obj,
  3464. rspamd_rcl_default_handler_t handler,
  3465. gint flags)
  3466. {
  3467. gboolean has_example = FALSE, has_type = FALSE;
  3468. const gchar *type = NULL;
  3469. if (ucl_object_lookup (doc_obj, "example") != NULL) {
  3470. has_example = TRUE;
  3471. }
  3472. if (ucl_object_lookup (doc_obj, "type") != NULL) {
  3473. has_type = TRUE;
  3474. }
  3475. if (handler == rspamd_rcl_parse_struct_string) {
  3476. if (!has_type) {
  3477. ucl_object_insert_key (doc_obj, ucl_object_fromstring ("string"),
  3478. "type", 0, false);
  3479. }
  3480. }
  3481. else if (handler == rspamd_rcl_parse_struct_integer) {
  3482. type = "int";
  3483. if (flags & RSPAMD_CL_FLAG_INT_16) {
  3484. type = "int16";
  3485. }
  3486. else if (flags & RSPAMD_CL_FLAG_INT_32) {
  3487. type = "int32";
  3488. }
  3489. else if (flags & RSPAMD_CL_FLAG_INT_64) {
  3490. type = "int64";
  3491. }
  3492. else if (flags & RSPAMD_CL_FLAG_INT_SIZE) {
  3493. type = "size";
  3494. }
  3495. else if (flags & RSPAMD_CL_FLAG_UINT) {
  3496. type = "uint";
  3497. }
  3498. if (!has_type) {
  3499. ucl_object_insert_key (doc_obj, ucl_object_fromstring (type),
  3500. "type", 0, false);
  3501. }
  3502. }
  3503. else if (handler == rspamd_rcl_parse_struct_double) {
  3504. if (!has_type) {
  3505. ucl_object_insert_key (doc_obj, ucl_object_fromstring ("double"),
  3506. "type", 0, false);
  3507. }
  3508. }
  3509. else if (handler == rspamd_rcl_parse_struct_time) {
  3510. type = "time";
  3511. if (!has_type) {
  3512. ucl_object_insert_key (doc_obj, ucl_object_fromstring (type),
  3513. "type", 0, false);
  3514. }
  3515. }
  3516. else if (handler == rspamd_rcl_parse_struct_string_list) {
  3517. if (!has_type) {
  3518. ucl_object_insert_key (doc_obj, ucl_object_fromstring ("string list"),
  3519. "type", 0, false);
  3520. }
  3521. if (!has_example) {
  3522. ucl_object_insert_key (doc_obj,
  3523. ucl_object_fromstring_common ("param = \"str1, str2, str3\" OR "
  3524. "param = [\"str1\", \"str2\", \"str3\"]", 0, 0),
  3525. "example",
  3526. 0,
  3527. false);
  3528. }
  3529. }
  3530. else if (handler == rspamd_rcl_parse_struct_boolean) {
  3531. if (!has_type) {
  3532. ucl_object_insert_key (doc_obj,
  3533. ucl_object_fromstring ("bool"),
  3534. "type",
  3535. 0,
  3536. false);
  3537. }
  3538. }
  3539. else if (handler == rspamd_rcl_parse_struct_keypair) {
  3540. if (!has_type) {
  3541. ucl_object_insert_key (doc_obj,
  3542. ucl_object_fromstring ("keypair"),
  3543. "type",
  3544. 0,
  3545. false);
  3546. }
  3547. if (!has_example) {
  3548. ucl_object_insert_key (doc_obj,
  3549. ucl_object_fromstring ("keypair { "
  3550. "pubkey = <base32_string>;"
  3551. " privkey = <base32_string>; "
  3552. "}"),
  3553. "example",
  3554. 0,
  3555. false);
  3556. }
  3557. }
  3558. else if (handler == rspamd_rcl_parse_struct_addr) {
  3559. if (!has_type) {
  3560. ucl_object_insert_key (doc_obj,
  3561. ucl_object_fromstring ("socket address"),
  3562. "type",
  3563. 0,
  3564. false);
  3565. }
  3566. }
  3567. else if (handler == rspamd_rcl_parse_struct_mime_addr) {
  3568. if (!has_type) {
  3569. ucl_object_insert_key (doc_obj,
  3570. ucl_object_fromstring ("email address"),
  3571. "type",
  3572. 0,
  3573. false);
  3574. }
  3575. }
  3576. }
  3577. ucl_object_t *
  3578. rspamd_rcl_add_doc_obj (ucl_object_t *doc_target,
  3579. const char *doc_string,
  3580. const char *doc_name,
  3581. ucl_type_t type,
  3582. rspamd_rcl_default_handler_t handler,
  3583. gint flags,
  3584. const char *default_value,
  3585. gboolean required)
  3586. {
  3587. ucl_object_t *doc_obj;
  3588. if (doc_target == NULL || doc_name == NULL) {
  3589. return NULL;
  3590. }
  3591. doc_obj = ucl_object_typed_new (UCL_OBJECT);
  3592. /* Insert doc string itself */
  3593. if (doc_string) {
  3594. ucl_object_insert_key (doc_obj,
  3595. ucl_object_fromstring_common (doc_string, 0, 0),
  3596. "data", 0, false);
  3597. }
  3598. else {
  3599. ucl_object_insert_key (doc_obj, ucl_object_fromstring ("undocumented"),
  3600. "data", 0, false);
  3601. }
  3602. if (type != UCL_NULL) {
  3603. ucl_object_insert_key (doc_obj,
  3604. ucl_object_fromstring (ucl_object_type_to_string (type)),
  3605. "type", 0, false);
  3606. }
  3607. rspamd_rcl_doc_obj_from_handler (doc_obj, handler, flags);
  3608. ucl_object_insert_key (doc_obj,
  3609. ucl_object_frombool (required),
  3610. "required", 0, false);
  3611. if (default_value) {
  3612. ucl_object_insert_key (doc_obj,
  3613. ucl_object_fromstring_common (default_value, 0, 0),
  3614. "default", 0, false);
  3615. }
  3616. ucl_object_insert_key (doc_target, doc_obj, doc_name, 0, true);
  3617. return doc_obj;
  3618. }
  3619. ucl_object_t *
  3620. rspamd_rcl_add_doc_by_path (struct rspamd_config *cfg,
  3621. const gchar *doc_path,
  3622. const char *doc_string,
  3623. const char *doc_name,
  3624. ucl_type_t type,
  3625. rspamd_rcl_default_handler_t handler,
  3626. gint flags,
  3627. const char *default_value,
  3628. gboolean required)
  3629. {
  3630. const ucl_object_t *found, *cur;
  3631. ucl_object_t *obj;
  3632. gchar **path_components, **comp;
  3633. if (doc_path == NULL) {
  3634. /* Assume top object */
  3635. return rspamd_rcl_add_doc_obj (cfg->doc_strings,
  3636. doc_string,
  3637. doc_name,
  3638. type,
  3639. handler,
  3640. flags,
  3641. default_value,
  3642. required);
  3643. }
  3644. else {
  3645. found = ucl_object_lookup_path (cfg->doc_strings, doc_path);
  3646. if (found != NULL) {
  3647. return rspamd_rcl_add_doc_obj ((ucl_object_t *) found,
  3648. doc_string,
  3649. doc_name,
  3650. type,
  3651. handler,
  3652. flags,
  3653. default_value,
  3654. required);
  3655. }
  3656. /* Otherwise we need to insert all components of the path */
  3657. path_components = g_strsplit_set (doc_path, ".", -1);
  3658. cur = cfg->doc_strings;
  3659. for (comp = path_components; *comp != NULL; comp++) {
  3660. if (ucl_object_type (cur) != UCL_OBJECT) {
  3661. msg_err_config ("Bad path while lookup for '%s' at %s",
  3662. doc_path, *comp);
  3663. g_strfreev (path_components);
  3664. return NULL;
  3665. }
  3666. found = ucl_object_lookup (cur, *comp);
  3667. if (found == NULL) {
  3668. obj = ucl_object_typed_new (UCL_OBJECT);
  3669. ucl_object_insert_key ((ucl_object_t *) cur,
  3670. obj,
  3671. *comp,
  3672. 0,
  3673. true);
  3674. cur = obj;
  3675. }
  3676. else {
  3677. cur = found;
  3678. }
  3679. }
  3680. g_strfreev (path_components);
  3681. }
  3682. return rspamd_rcl_add_doc_obj (ucl_object_ref (cur),
  3683. doc_string,
  3684. doc_name,
  3685. type,
  3686. handler,
  3687. flags,
  3688. default_value,
  3689. required);
  3690. }
  3691. static void
  3692. rspamd_rcl_add_doc_from_comments (struct rspamd_config *cfg,
  3693. ucl_object_t *top_doc, const ucl_object_t *obj,
  3694. const ucl_object_t *comments, gboolean is_top)
  3695. {
  3696. ucl_object_iter_t it = NULL;
  3697. const ucl_object_t *cur, *cmt;
  3698. ucl_object_t *cur_doc;
  3699. if (ucl_object_type (obj) == UCL_OBJECT) {
  3700. while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) {
  3701. cur_doc = NULL;
  3702. if ((cmt = ucl_comments_find (comments, cur)) != NULL) {
  3703. cur_doc = rspamd_rcl_add_doc_obj (top_doc,
  3704. ucl_object_tostring (cmt), ucl_object_key (cur),
  3705. ucl_object_type (cur), NULL, 0, NULL, FALSE);
  3706. }
  3707. if (ucl_object_type (cur) == UCL_OBJECT) {
  3708. if (cur_doc) {
  3709. rspamd_rcl_add_doc_from_comments (cfg, cur_doc, cur,
  3710. comments,
  3711. FALSE);
  3712. }
  3713. else {
  3714. rspamd_rcl_add_doc_from_comments (cfg, top_doc, cur,
  3715. comments,
  3716. FALSE);
  3717. }
  3718. }
  3719. }
  3720. }
  3721. else if (!is_top) {
  3722. if ((cmt = ucl_comments_find (comments, obj)) != NULL) {
  3723. rspamd_rcl_add_doc_obj (top_doc,
  3724. ucl_object_tostring (cmt), ucl_object_key (obj),
  3725. ucl_object_type (obj), NULL, 0, NULL, FALSE);
  3726. }
  3727. }
  3728. }
  3729. ucl_object_t *
  3730. rspamd_rcl_add_doc_by_example (struct rspamd_config *cfg,
  3731. const gchar *root_path,
  3732. const gchar *doc_string,
  3733. const gchar *doc_name,
  3734. const gchar *example_data, gsize example_len)
  3735. {
  3736. struct ucl_parser *parser;
  3737. ucl_object_t *top, *top_doc;
  3738. const ucl_object_t *comments;
  3739. parser = ucl_parser_new (UCL_PARSER_NO_FILEVARS|UCL_PARSER_SAVE_COMMENTS);
  3740. if (!ucl_parser_add_chunk (parser, example_data, example_len)) {
  3741. msg_err_config ("cannot parse example: %s",
  3742. ucl_parser_get_error (parser));
  3743. ucl_parser_free (parser);
  3744. return NULL;
  3745. }
  3746. top = ucl_parser_get_object (parser);
  3747. comments = ucl_parser_get_comments (parser);
  3748. /* Add top object */
  3749. top_doc = rspamd_rcl_add_doc_by_path (cfg, root_path, doc_string,
  3750. doc_name, ucl_object_type (top), NULL, 0, NULL, FALSE);
  3751. ucl_object_insert_key (top_doc,
  3752. ucl_object_fromstring_common (example_data, example_len, 0),
  3753. "example", 0, false);
  3754. rspamd_rcl_add_doc_from_comments (cfg, top_doc, top, comments, TRUE);
  3755. return top_doc;
  3756. }